summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/pdbox/PDa/CHANGELOG.PDa118
-rw-r--r--apps/plugins/pdbox/PDa/LICENSE.txt60
-rw-r--r--apps/plugins/pdbox/PDa/README.PDa106
-rw-r--r--apps/plugins/pdbox/PDa/README.txt88
-rw-r--r--apps/plugins/pdbox/PDa/extra/OSC-client.h376
-rw-r--r--apps/plugins/pdbox/PDa/extra/OSC.pd26
-rw-r--r--apps/plugins/pdbox/PDa/extra/OSCroute.c1204
-rw-r--r--apps/plugins/pdbox/PDa/extra/README24
-rw-r--r--apps/plugins/pdbox/PDa/extra/bandpass-help.pd34
-rw-r--r--apps/plugins/pdbox/PDa/extra/bandpass.c172
-rw-r--r--apps/plugins/pdbox/PDa/extra/dumpOSC.c1998
-rw-r--r--apps/plugins/pdbox/PDa/extra/equalizer.c178
-rw-r--r--apps/plugins/pdbox/PDa/extra/fatom.h970
-rw-r--r--apps/plugins/pdbox/PDa/extra/filters.h148
-rw-r--r--apps/plugins/pdbox/PDa/extra/g_canvas.h1204
-rw-r--r--apps/plugins/pdbox/PDa/extra/gcanvas-help.pd16
-rw-r--r--apps/plugins/pdbox/PDa/extra/gcanvas.c758
-rw-r--r--apps/plugins/pdbox/PDa/extra/highpass.c174
-rw-r--r--apps/plugins/pdbox/PDa/extra/highshelf.c180
-rw-r--r--apps/plugins/pdbox/PDa/extra/hlshelf.c452
-rw-r--r--apps/plugins/pdbox/PDa/extra/image.c434
-rw-r--r--apps/plugins/pdbox/PDa/extra/lowpass.c178
-rw-r--r--apps/plugins/pdbox/PDa/extra/lowshelf.c182
-rw-r--r--apps/plugins/pdbox/PDa/extra/m_pd.h1300
-rw-r--r--apps/plugins/pdbox/PDa/extra/makefile66
-rw-r--r--apps/plugins/pdbox/PDa/extra/moog~.c366
-rw-r--r--apps/plugins/pdbox/PDa/extra/notch.c178
-rw-r--r--apps/plugins/pdbox/PDa/extra/s_stuff.h430
-rw-r--r--apps/plugins/pdbox/PDa/extra/sendOSC.c2922
-rw-r--r--apps/plugins/pdbox/PDa/extra/sformat.h110
-rw-r--r--apps/plugins/pdbox/PDa/extra/shell.c624
-rw-r--r--apps/plugins/pdbox/PDa/extra/slider.c106
-rw-r--r--apps/plugins/pdbox/PDa/extra/sliderh.c126
-rw-r--r--apps/plugins/pdbox/PDa/extra/test-clip.pd26
-rw-r--r--apps/plugins/pdbox/PDa/extra/test-vcf.pd36
-rw-r--r--apps/plugins/pdbox/PDa/extra/zerox~.c114
-rw-r--r--apps/plugins/pdbox/PDa/intern/biquad~.c252
-rw-r--r--apps/plugins/pdbox/PDa/intern/bp~.c276
-rw-r--r--apps/plugins/pdbox/PDa/intern/clip~.c116
-rw-r--r--apps/plugins/pdbox/PDa/intern/cos_table.h6
-rw-r--r--apps/plugins/pdbox/PDa/intern/cos~.c122
-rw-r--r--apps/plugins/pdbox/PDa/intern/dbtopow~.c104
-rw-r--r--apps/plugins/pdbox/PDa/intern/dbtorms~.c106
-rw-r--r--apps/plugins/pdbox/PDa/intern/delay.h84
-rw-r--r--apps/plugins/pdbox/PDa/intern/delread~.c200
-rw-r--r--apps/plugins/pdbox/PDa/intern/delwrite~.c168
-rw-r--r--apps/plugins/pdbox/PDa/intern/env~.c254
-rw-r--r--apps/plugins/pdbox/PDa/intern/ftom~.c88
-rw-r--r--apps/plugins/pdbox/PDa/intern/hip~.c184
-rw-r--r--apps/plugins/pdbox/PDa/intern/intern_setup.c94
-rw-r--r--apps/plugins/pdbox/PDa/intern/line~.c202
-rw-r--r--apps/plugins/pdbox/PDa/intern/lop~.c180
-rw-r--r--apps/plugins/pdbox/PDa/intern/makefile48
-rw-r--r--apps/plugins/pdbox/PDa/intern/mtof~.c98
-rw-r--r--apps/plugins/pdbox/PDa/intern/noise~.c110
-rw-r--r--apps/plugins/pdbox/PDa/intern/osc~.c174
-rw-r--r--apps/plugins/pdbox/PDa/intern/phasor~.c138
-rw-r--r--apps/plugins/pdbox/PDa/intern/powtodb~.c106
-rw-r--r--apps/plugins/pdbox/PDa/intern/print~.c156
-rw-r--r--apps/plugins/pdbox/PDa/intern/rmstodb~.c104
-rw-r--r--apps/plugins/pdbox/PDa/intern/rsqrt~.c210
-rw-r--r--apps/plugins/pdbox/PDa/intern/samphold~.c150
-rw-r--r--apps/plugins/pdbox/PDa/intern/sformat.h110
-rw-r--r--apps/plugins/pdbox/PDa/intern/sfread~.c576
-rw-r--r--apps/plugins/pdbox/PDa/intern/sfwrite~.c480
-rw-r--r--apps/plugins/pdbox/PDa/intern/sig~.c134
-rw-r--r--apps/plugins/pdbox/PDa/intern/snapshot~.c114
-rw-r--r--apps/plugins/pdbox/PDa/intern/sqrt~.c154
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabosc4~.c264
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabplay~.c264
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabread.c104
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabread4~.c210
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabread~.c194
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabreceive~.c122
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabsend~.c196
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabwrite.c168
-rw-r--r--apps/plugins/pdbox/PDa/intern/tabwrite~.c264
-rw-r--r--apps/plugins/pdbox/PDa/intern/threshold~.c270
-rw-r--r--apps/plugins/pdbox/PDa/intern/vcf~.c238
-rw-r--r--apps/plugins/pdbox/PDa/intern/vd~.c184
-rw-r--r--apps/plugins/pdbox/PDa/intern/vline~.c368
-rw-r--r--apps/plugins/pdbox/PDa/intern/vsnapshot~.c176
-rw-r--r--apps/plugins/pdbox/PDa/intern/wrap~.c104
-rw-r--r--apps/plugins/pdbox/PDa/src/build.ipod10
-rw-r--r--apps/plugins/pdbox/PDa/src/d_arithmetic.c1684
-rw-r--r--apps/plugins/pdbox/PDa/src/d_array.c2148
-rw-r--r--apps/plugins/pdbox/PDa/src/d_ctl.c1568
-rw-r--r--apps/plugins/pdbox/PDa/src/d_dac.c368
-rw-r--r--apps/plugins/pdbox/PDa/src/d_delay.c638
-rw-r--r--apps/plugins/pdbox/PDa/src/d_fft.c688
-rw-r--r--apps/plugins/pdbox/PDa/src/d_fftroutine.c2002
-rw-r--r--apps/plugins/pdbox/PDa/src/d_filter.c1094
-rw-r--r--apps/plugins/pdbox/PDa/src/d_global.c616
-rw-r--r--apps/plugins/pdbox/PDa/src/d_imayer_fft.c1032
-rw-r--r--apps/plugins/pdbox/PDa/src/d_imayer_tables.h100
-rw-r--r--apps/plugins/pdbox/PDa/src/d_math.c1146
-rw-r--r--apps/plugins/pdbox/PDa/src/d_mayer_fft.c838
-rw-r--r--apps/plugins/pdbox/PDa/src/d_misc.c524
-rw-r--r--apps/plugins/pdbox/PDa/src/d_osc.c1070
-rw-r--r--apps/plugins/pdbox/PDa/src/d_resample.c450
-rw-r--r--apps/plugins/pdbox/PDa/src/d_soundfile.c4734
-rw-r--r--apps/plugins/pdbox/PDa/src/d_ugen.c2252
-rw-r--r--apps/plugins/pdbox/PDa/src/delme.pd16
-rw-r--r--apps/plugins/pdbox/PDa/src/g_all_guis.c1324
-rw-r--r--apps/plugins/pdbox/PDa/src/g_all_guis.h658
-rw-r--r--apps/plugins/pdbox/PDa/src/g_array.c2734
-rw-r--r--apps/plugins/pdbox/PDa/src/g_bang.c1108
-rw-r--r--apps/plugins/pdbox/PDa/src/g_canvas.c2952
-rw-r--r--apps/plugins/pdbox/PDa/src/g_canvas.h1204
-rw-r--r--apps/plugins/pdbox/PDa/src/g_editor.c4548
-rw-r--r--apps/plugins/pdbox/PDa/src/g_graph.c2224
-rw-r--r--apps/plugins/pdbox/PDa/src/g_guiconnect.c188
-rw-r--r--apps/plugins/pdbox/PDa/src/g_hdial.c1470
-rw-r--r--apps/plugins/pdbox/PDa/src/g_hslider.c1308
-rw-r--r--apps/plugins/pdbox/PDa/src/g_io.c1224
-rw-r--r--apps/plugins/pdbox/PDa/src/g_mycanvas.c770
-rw-r--r--apps/plugins/pdbox/PDa/src/g_numbox.c1814
-rw-r--r--apps/plugins/pdbox/PDa/src/g_readwrite.c1446
-rw-r--r--apps/plugins/pdbox/PDa/src/g_rtext.c972
-rw-r--r--apps/plugins/pdbox/PDa/src/g_scalar.c802
-rw-r--r--apps/plugins/pdbox/PDa/src/g_template.c3358
-rw-r--r--apps/plugins/pdbox/PDa/src/g_text.c2632
-rw-r--r--apps/plugins/pdbox/PDa/src/g_toggle.c948
-rw-r--r--apps/plugins/pdbox/PDa/src/g_traversal.c2168
-rw-r--r--apps/plugins/pdbox/PDa/src/g_vdial.c1432
-rw-r--r--apps/plugins/pdbox/PDa/src/g_vslider.c1254
-rw-r--r--apps/plugins/pdbox/PDa/src/g_vumeter.c1426
-rw-r--r--apps/plugins/pdbox/PDa/src/m_atom.c258
-rw-r--r--apps/plugins/pdbox/PDa/src/m_binbuf.c2438
-rw-r--r--apps/plugins/pdbox/PDa/src/m_class.c1648
-rw-r--r--apps/plugins/pdbox/PDa/src/m_conf.c202
-rw-r--r--apps/plugins/pdbox/PDa/src/m_fixed.c252
-rw-r--r--apps/plugins/pdbox/PDa/src/m_fixed.h110
-rw-r--r--apps/plugins/pdbox/PDa/src/m_glob.c210
-rw-r--r--apps/plugins/pdbox/PDa/src/m_imp.h156
-rw-r--r--apps/plugins/pdbox/PDa/src/m_memory.c178
-rw-r--r--apps/plugins/pdbox/PDa/src/m_obj.c1394
-rw-r--r--apps/plugins/pdbox/PDa/src/m_pd.c612
-rw-r--r--apps/plugins/pdbox/PDa/src/m_pd.h1300
-rw-r--r--apps/plugins/pdbox/PDa/src/m_sched.c1162
-rw-r--r--apps/plugins/pdbox/PDa/src/makecostab.c50
-rw-r--r--apps/plugins/pdbox/PDa/src/makefile354
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio.c1746
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_alsa.c1890
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_mmio.c1588
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_oss.c1688
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_pa.c584
-rw-r--r--apps/plugins/pdbox/PDa/src/s_entry.c102
-rw-r--r--apps/plugins/pdbox/PDa/src/s_file.c110
-rw-r--r--apps/plugins/pdbox/PDa/src/s_inter.c2000
-rw-r--r--apps/plugins/pdbox/PDa/src/s_loader.c338
-rw-r--r--apps/plugins/pdbox/PDa/src/s_main.c1676
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi.c1282
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi_oss.c718
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi_pm.c332
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi_sgi.c376
-rw-r--r--apps/plugins/pdbox/PDa/src/s_path.c820
-rw-r--r--apps/plugins/pdbox/PDa/src/s_print.c300
-rw-r--r--apps/plugins/pdbox/PDa/src/s_stuff.h430
-rw-r--r--apps/plugins/pdbox/PDa/src/s_watchdog.c94
-rw-r--r--apps/plugins/pdbox/PDa/src/t_main.c240
-rw-r--r--apps/plugins/pdbox/PDa/src/t_tk.h20
-rw-r--r--apps/plugins/pdbox/PDa/src/t_tkcmd.c796
-rw-r--r--apps/plugins/pdbox/PDa/src/u_main.tk6734
-rw-r--r--apps/plugins/pdbox/PDa/src/u_pdreceive.c650
-rw-r--r--apps/plugins/pdbox/PDa/src/u_pdsend.c314
-rw-r--r--apps/plugins/pdbox/PDa/src/x_acoustics.c386
-rw-r--r--apps/plugins/pdbox/PDa/src/x_arithmetic.c1792
-rw-r--r--apps/plugins/pdbox/PDa/src/x_connective.c2904
-rw-r--r--apps/plugins/pdbox/PDa/src/x_gui.c754
-rw-r--r--apps/plugins/pdbox/PDa/src/x_interface.c156
-rw-r--r--apps/plugins/pdbox/PDa/src/x_midi.c2626
-rw-r--r--apps/plugins/pdbox/PDa/src/x_misc.c642
-rw-r--r--apps/plugins/pdbox/PDa/src/x_net.c726
-rw-r--r--apps/plugins/pdbox/PDa/src/x_qlist.c690
-rw-r--r--apps/plugins/pdbox/PDa/src/x_time.c1040
-rw-r--r--apps/plugins/pdbox/README.rockbox16
-rw-r--r--apps/plugins/pdbox/SOURCES330
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/CHANGES24
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/FILES30
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/Makefile76
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/Malloc.c402
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/README44
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/bmalloc.c740
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/bmalloc.h12
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/bysize.c848
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/bysize.h8
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/dmalloc.c1380
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/dmalloc.h16
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/dmytest.c276
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/malloc.man190
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/mytest.c140
-rw-r--r--apps/plugins/pdbox/dbestfit-3.3/thoughts340
-rw-r--r--apps/plugins/pdbox/pdbox-net.c238
-rw-r--r--apps/plugins/pdbox/pdbox.c314
-rw-r--r--apps/plugins/pdbox/pdbox.h142
-rw-r--r--apps/plugins/pdbox/pdbox.make62
-rw-r--r--apps/plugins/viewers.config3
199 files changed, 139349 insertions, 1 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 4b759b080f..8e4bb7d7c4 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -54,6 +54,7 @@ mpegplayer,viewers
54nim,games 54nim,games
55oscilloscope,demos 55oscilloscope,demos
56pacbox,games 56pacbox,games
57pdbox,apps
57pegbox,games 58pegbox,games
58pictureflow,demos 59pictureflow,demos
59plasma,demos 60plasma,demos
diff --git a/apps/plugins/pdbox/PDa/CHANGELOG.PDa b/apps/plugins/pdbox/PDa/CHANGELOG.PDa
new file mode 100644
index 0000000000..f8afc2bd89
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/CHANGELOG.PDa
@@ -0,0 +1,118 @@
10.6:
2 - added compilation for blackfin architecture (blackfin.uclinux.org)
3 - added third outlet for mouseup to gcanvas.
4 - debian package support (for maemo)
5 - don't ask quit question
6
70.5:
8 - fixed a crasher bug in sfread~.c
9
100.4:
11 - added ipod gui communication in m_pd.c (pd_bind) and m_fixed.c
12 - moved the pd internal objects in a folder called interns
13 - restructuring of the makefile, you can build a static binary
14 now with "make static", needed for the iPod part mainly.
15 - the oscillator tables are precalculated now (faster startup).
16 see src/makecostable.c for that
17 - the scheduler is simplified (added an additional scheduler called
18 m_scheduler_pda(), this is a lot faster now
19 - changed the "look" of PDa
20 - The menubar in the patcher window is now optional, its off by default.
21 - stdin interface added. It is now possible to communicate with pd via the
22 keyboard even in -nogui mode
23 - fixed loading and saving of arrays (g_array.c)
24 - corrected rounding when calculation phase update osc~ and phasor~
25 (there are better methods to do this, but they are slower)
26 - fixed tabosc4~
27 - enabled array drawing
28 - fixed array saving in subpatch
29
30
310.3test2:
32 - added the O_CREAT flag to sfwrite
33 - removed the OSC stuff (now in PDa-externals)
34
350.3test1:
36 - moved all objects into the extra dir
37
38
39 d_arithmetic: t_float -> t_sample .. exchanged * with mult / with divide
40 d_fft: t_float -> t_sample
41 d_global: t_float -> t_sample
42 d_misc: put print~ into extra folder
43 d_resample: t_float -> t_sample
44 g_array: disable editing
45 fixtof()
46 t_float -> t_sample (check out the savefn thingy)
47
48 g_graph: 1 t_float -> t_sample
49 g_io: t_float -> t_sample
50 m_conf: remove calls to setup routines
51 m_obj.c ftofix
52 m_pd.h definition of t_sample
53 double -> t_time
54 ... and more
55 m_sched.c
56 double t_time
57 s_inter: check !!!
58 s_main: check !!!
59
600.6:
61 - added compilation for blackfin architecture (blackfin.uclinux.org)
62 - added third outlet for mouseup to gcanvas.
63 - debian package support (for maemo)
64 - don't ask quit question
65
660.5:
67 - fixed a crasher bug in sfread~.c
68
690.4:
70 - added ipod gui communication in m_pd.c (pd_bind) and m_fixed.c
71 - moved the pd internal objects in a folder called interns
72 - restructuring of the makefile, you can build a static binary
73 now with "make static", needed for the iPod part mainly.
74 - the oscillator tables are precalculated now (faster startup).
75 see src/makecostable.c for that
76 - the scheduler is simplified (added an additional scheduler called
77 m_scheduler_pda(), this is a lot faster now
78 - changed the "look" of PDa
79 - The menubar in the patcher window is now optional, its off by default.
80 - stdin interface added. It is now possible to communicate with pd via the
81 keyboard even in -nogui mode
82 - fixed loading and saving of arrays (g_array.c)
83 - corrected rounding when calculation phase update osc~ and phasor~
84 (there are better methods to do this, but they are slower)
85 - fixed tabosc4~
86 - enabled array drawing
87 - fixed array saving in subpatch
88
89
900.3test2:
91 - added the O_CREAT flag to sfwrite
92 - removed the OSC stuff (now in PDa-externals)
93
940.3test1:
95 - moved all objects into the extra dir
96
97
98 d_arithmetic: t_float -> t_sample .. exchanged * with mult / with divide
99 d_fft: t_float -> t_sample
100 d_global: t_float -> t_sample
101 d_misc: put print~ into extra folder
102 d_resample: t_float -> t_sample
103 g_array: disable editing
104 fixtof()
105 t_float -> t_sample (check out the savefn thingy)
106
107 g_graph: 1 t_float -> t_sample
108 g_io: t_float -> t_sample
109 m_conf: remove calls to setup routines
110 m_obj.c ftofix
111 m_pd.h definition of t_sample
112 double -> t_time
113 ... and more
114 m_sched.c
115 double t_time
116 s_inter: check !!!
117 s_main: check !!!
118
diff --git a/apps/plugins/pdbox/PDa/LICENSE.txt b/apps/plugins/pdbox/PDa/LICENSE.txt
new file mode 100644
index 0000000000..3e104c77a2
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/LICENSE.txt
@@ -0,0 +1,60 @@
1This software is copyrighted by Miller Puckette and others. The following
2terms (the "Standard Improved BSD License") apply to all files associated with
3the software unless explicitly disclaimed in individual files:
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
91. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
112. Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
153. The name of the author may not be used to endorse or promote
16 products derived from this software without specific prior
17 written permission.
18
19THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
20EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30THE POSSIBILITY OF SUCH DAMAGE.
31This software is copyrighted by Miller Puckette and others. The following
32terms (the "Standard Improved BSD License") apply to all files associated with
33the software unless explicitly disclaimed in individual files:
34
35Redistribution and use in source and binary forms, with or without
36modification, are permitted provided that the following conditions are
37met:
38
391. Redistributions of source code must retain the above copyright
40 notice, this list of conditions and the following disclaimer.
412. Redistributions in binary form must reproduce the above
42 copyright notice, this list of conditions and the following
43 disclaimer in the documentation and/or other materials provided
44 with the distribution.
453. The name of the author may not be used to endorse or promote
46 products derived from this software without specific prior
47 written permission.
48
49THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
50EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
51THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
52PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
53BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
54EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
55TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
57ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
59IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
60THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/apps/plugins/pdbox/PDa/README.PDa b/apps/plugins/pdbox/PDa/README.PDa
new file mode 100644
index 0000000000..7c567d70c2
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/README.PDa
@@ -0,0 +1,106 @@
1PDa - Pure Data for Personal Digital Assistants
2===============================================
3
4Based on pd-0.37-4.
5
6This version of Pure Data is based on the original sources by
7Miller Puckette, but several part have been changed in order
8to run on embedded systems. Most of the changed objects are in
9the folder "intern".
10
11This means, that all the signal processing is done with fixed-point
12math. The control processing is still in floating point, therefor this
13might be a bit slow.
14
15The package is compilable under Linux. I would be glad if someone would
16make a version for windows or OSX, but I unfortunately don't have the
17time or resource to do so.
18
19In order to compile:
20cd src/
21make
22
23The default compilation flags are very conservative, you can add
24optimization flags through the CFLAGS variable.
25e.g
26
27make CFLAGS="-O6"
28
29Will turn on maximum optimization (almost).
30
31If you have tcl/tk installed in the right place this should work out,
32if you have problems with that, either adapt the makefile or ask me.
33On Debian you just have to install tk8.4-dev to get it going.
34
35Have fun !
36
37Guenter
38
39
40Additional information:
41---------------------------
42
43Instructions for compiling for iPods, using arm-elf-tools-20030314:
44
45cd src
46./build.ipod
47
48The tcl/tk interface will not be built for iPods, you can interface with
49Pd from the podzilla console or with this GUI for PDa on iPod:
50
51http://ipodlinux.org/Pdpod
52
53
54PDa - Pure Data for Personal Digital Assistants
55===============================================
56
57Based on pd-0.37-4.
58
59This version of Pure Data is based on the original sources by
60Miller Puckette, but several part have been changed in order
61to run on embedded systems. Most of the changed objects are in
62the folder "intern".
63
64This means, that all the signal processing is done with fixed-point
65math. The control processing is still in floating point, therefor this
66might be a bit slow.
67
68The package is compilable under Linux. I would be glad if someone would
69make a version for windows or OSX, but I unfortunately don't have the
70time or resource to do so.
71
72In order to compile:
73cd src/
74make
75
76The default compilation flags are very conservative, you can add
77optimization flags through the CFLAGS variable.
78e.g
79
80make CFLAGS="-O6"
81
82Will turn on maximum optimization (almost).
83
84If you have tcl/tk installed in the right place this should work out,
85if you have problems with that, either adapt the makefile or ask me.
86On Debian you just have to install tk8.4-dev to get it going.
87
88Have fun !
89
90Guenter
91
92
93Additional information:
94---------------------------
95
96Instructions for compiling for iPods, using arm-elf-tools-20030314:
97
98cd src
99./build.ipod
100
101The tcl/tk interface will not be built for iPods, you can interface with
102Pd from the podzilla console or with this GUI for PDa on iPod:
103
104http://ipodlinux.org/Pdpod
105
106
diff --git a/apps/plugins/pdbox/PDa/README.txt b/apps/plugins/pdbox/PDa/README.txt
new file mode 100644
index 0000000000..856ccaad62
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/README.txt
@@ -0,0 +1,88 @@
1This is the README file for Pd, a free real-time computer music software
2package resembling Max. You can get Pd for Linux, Windows, Mac OSX, or IRIX
3from http://www.crca.ucsd.edu/~msp/software.html or ftp://felix.ucsd.edu.
4Installation instructions are in the HTML DOCUMENTATION at:
5
6 http://www.crca.ucsd.edu/~msp/Pd_documentation/index.htm
7
8If you download and unpack Pd, you will also find the html documentation
9locally in the file, .../pd-whatever/doc/1.manual/index.htm. To unpack Pd:
10
11LINUX (or freeBSD). Download Pd, which will be a ".tar.gz" file; to unpack it,
12type "zcat [name].tar.gz | tar xf -" to a shell. This creates a directory with
13a name like "pd-0.35". There are also RPMs available.
14
15Microsoft Windows. Pd is distributed as a "zip" file. Unzip this,
16creating a directory such as \pd.
17
18IRIX. Download Pd, which will be a "tar.Z" file. You can unpack this by
19typing "zcat [name].tar.Z | tar xf -" to a shell.
20
21Macintosh. The web browser will automatically unpack the distributions
22into a folder such as "pd-0.35" on your desktop.
23
24If you have qustions about Pd, or if you wish to be notified of releases,
25check the Pd mailing list: http://iem.mhsg.ac.at/mailinglists/pd-list/
26
27Many extensions to Pd are available, notably for handling video and 3D
28graphics; see the html documentation for pointers.
29
30COPYRIGHT. Except as otherwise noted, all files in the Pd distribution are
31
32 Copyright (c) 1997-2001 Miller Puckette and others.
33
34For information on usage and redistribution, and for a DISCLAIMER OF ALL
35WARRANTIES, see the file, "LICENSE.txt," included in the Pd distribution.
36(Note that tcl/tk, expr, and some other files are copyrighted separately).
37
38ACKNOWLEDGEMENTS. Thanks to Harry Castle, Krzysztof Czaja, Mark Danks,
39Christian Feldbauer, Guenter Geiger, Kerry Hagan, Trevor Johnson, Fernando
40Lopez-Lezcano, Adam Lindsay, Karl MacMillan, Thomas Musil, Toshinori Ohkouchi,
41Winfried Ritsch, Vibeke Sorensen, Rand Steiger, Shahrokh Yadegari, David
42Zicarelli, Iohannes Zmoelnig, and probably many others for contributions of
43code, documentation, ideas, and expertise. This work has received generous
44support from the Intel Research Council.
45This is the README file for Pd, a free real-time computer music software
46package resembling Max. You can get Pd for Linux, Windows, Mac OSX, or IRIX
47from http://www.crca.ucsd.edu/~msp/software.html or ftp://felix.ucsd.edu.
48Installation instructions are in the HTML DOCUMENTATION at:
49
50 http://www.crca.ucsd.edu/~msp/Pd_documentation/index.htm
51
52If you download and unpack Pd, you will also find the html documentation
53locally in the file, .../pd-whatever/doc/1.manual/index.htm. To unpack Pd:
54
55LINUX (or freeBSD). Download Pd, which will be a ".tar.gz" file; to unpack it,
56type "zcat [name].tar.gz | tar xf -" to a shell. This creates a directory with
57a name like "pd-0.35". There are also RPMs available.
58
59Microsoft Windows. Pd is distributed as a "zip" file. Unzip this,
60creating a directory such as \pd.
61
62IRIX. Download Pd, which will be a "tar.Z" file. You can unpack this by
63typing "zcat [name].tar.Z | tar xf -" to a shell.
64
65Macintosh. The web browser will automatically unpack the distributions
66into a folder such as "pd-0.35" on your desktop.
67
68If you have qustions about Pd, or if you wish to be notified of releases,
69check the Pd mailing list: http://iem.mhsg.ac.at/mailinglists/pd-list/
70
71Many extensions to Pd are available, notably for handling video and 3D
72graphics; see the html documentation for pointers.
73
74COPYRIGHT. Except as otherwise noted, all files in the Pd distribution are
75
76 Copyright (c) 1997-2001 Miller Puckette and others.
77
78For information on usage and redistribution, and for a DISCLAIMER OF ALL
79WARRANTIES, see the file, "LICENSE.txt," included in the Pd distribution.
80(Note that tcl/tk, expr, and some other files are copyrighted separately).
81
82ACKNOWLEDGEMENTS. Thanks to Harry Castle, Krzysztof Czaja, Mark Danks,
83Christian Feldbauer, Guenter Geiger, Kerry Hagan, Trevor Johnson, Fernando
84Lopez-Lezcano, Adam Lindsay, Karl MacMillan, Thomas Musil, Toshinori Ohkouchi,
85Winfried Ritsch, Vibeke Sorensen, Rand Steiger, Shahrokh Yadegari, David
86Zicarelli, Iohannes Zmoelnig, and probably many others for contributions of
87code, documentation, ideas, and expertise. This work has received generous
88support from the Intel Research Council.
diff --git a/apps/plugins/pdbox/PDa/extra/OSC-client.h b/apps/plugins/pdbox/PDa/extra/OSC-client.h
new file mode 100644
index 0000000000..196143f8e7
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/OSC-client.h
@@ -0,0 +1,376 @@
1/*
2Written by Matt Wright, The Center for New Music and Audio Technologies,
3University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
4The Regents of the University of California (Regents).
5
6Permission to use, copy, modify, distribute, and distribute modified versions
7of this software and its documentation without fee and without a signed
8licensing agreement, is hereby granted, provided that the above copyright
9notice, this paragraph and the following two paragraphs appear in all copies,
10modifications, and distributions.
11
12IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
13SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
14OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
15BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
17REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
20HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
21MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
22*/
23
24/*
25
26 OSC-client.h: library for constructing OpenSoundControl messages.
27 Derived from SynthControl.h
28 Author: Matt Wright
29 Version 0.1: 6/13/97
30 Version 0.2: 7/21/2000: Support for type-tagged messages
31
32
33 General notes:
34
35 This library abstracts away the data format for the OpenSoundControl
36 protocol. Users of this library can construct OpenSoundControl packets
37 with a function call interface instead of knowing how to lay out the bits.
38
39 All issues of memory allocation are deferred to the user of this library.
40 There are two data structures that the user must allocate. The first
41 is the actual buffer that the message will be written into. This buffer
42 can be any size, but if it's too small there's a possibility that it
43 will become overfull. The other data structure is called an OSCbuf,
44 and it holds all the state used by the library as it's constructing
45 a buffer.
46
47 All procedures that have the possibility of an error condition return int,
48 with 0 indicating no error and nonzero indicating an error. The variable
49 OSC_errorMessage will be set to point to a string containing an error
50 message explaining what the problem is.
51
52*/
53
54
55
56/* The int4byte type has to be a 4-byte integer. You may have to
57 change this to long or something else on your system. */
58#ifdef __MWERKS__
59 /* In Metrowerks you can set ints to be 2 or 4 bytes on 68K, but long is
60 always 4 bytes */
61 typedef long int4byte;
62#else
63 typedef int int4byte;
64#endif
65
66/* OSC_timetag.h */
67
68 typedef struct {
69 int seconds;
70 int fraction;
71 } OSCTimeTag;
72
73OSCTimeTag OSCTT_Immediately(void);
74OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset);
75OSCTimeTag OSCTT_CurrentTime(void);
76
77
78
79/* The maximum depth of bundles within bundles within bundles within...
80 This is the size of a static array. If you exceed this limit you'll
81 get an error message. */
82#define MAX_BUNDLE_NESTING 32
83
84
85/* Don't ever manipulate the data in the OSCbuf struct directly. (It's
86 declared here in the header file only so your program will be able to
87 declare variables of type OSCbuf and have the right amount of memory
88 be allocated.) */
89
90typedef struct OSCbuf_struct {
91 char *buffer; /* The buffer to hold the OSC packet */
92 int size; /* Size of the buffer */
93 char *bufptr; /* Current position as we fill the buffer */
94 int state; /* State of partially-constructed message */
95 int4byte *thisMsgSize; /* Pointer to count field before
96 currently-being-written message */
97 int4byte *prevCounts[MAX_BUNDLE_NESTING];
98 /* Pointers to count field before each currently
99 open bundle */
100 int bundleDepth; /* How many sub-sub-bundles are we in now? */
101 char *typeStringPtr; /* This pointer advances through the type
102 tag string as you add arguments. */
103 int gettingFirstUntypedArg; /* nonzero if this message doesn't have
104 a type tag and we're waiting for the 1st arg */
105} OSCbuf;
106
107
108
109/* Initialize the given OSCbuf. The user of this module must pass in the
110 block of memory that this OSCbuf will use for a buffer, and the number of
111 bytes in that block. (It's the user's job to allocate the memory because
112 you do it differently in different systems.) */
113void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray);
114
115
116/* Reset the given OSCbuf. Do this after you send out the contents of
117 the buffer and want to start writing new data into it. */
118void OSC_resetBuffer(OSCbuf *buf);
119
120
121/* Is the buffer empty? (I.e., would it be stupid to send the buffer
122 contents to the synth?) */
123int OSC_isBufferEmpty(OSCbuf *buf);
124
125
126/* How much space is left in the buffer? */
127int OSC_freeSpaceInBuffer(OSCbuf *buf);
128
129/* Does the buffer contain a valid OSC packet? (Returns nonzero if yes.) */
130int OSC_isBufferDone(OSCbuf *buf);
131
132/* When you're ready to send out the buffer (i.e., when OSC_isBufferDone()
133 returns true), call these two procedures to get the OSC packet that's been
134 assembled and its size in bytes. (And then call OSC_resetBuffer() if you
135 want to re-use this OSCbuf for the next packet.) */
136char *OSC_getPacket(OSCbuf *buf);
137int OSC_packetSize(OSCbuf *buf);
138
139
140
141/* Here's the basic model for building up OSC messages in an OSCbuf:
142
143 - Make sure the OSCbuf has been initialized with OSC_initBuffer().
144
145 - To open a bundle, call OSC_openBundle(). You can then write
146 messages or open new bundles within the bundle you opened.
147 Call OSC_closeBundle() to close the bundle. Note that a packet
148 does not have to have a bundle; it can instead consist of just a
149 single message.
150
151
152 - For each message you want to send:
153
154 - Call OSC_writeAddress() with the name of your message. (In
155 addition to writing your message name into the buffer, this
156 procedure will also leave space for the size count of this message.)
157
158 - Alternately, call OSC_writeAddressAndTypes() with the name of
159 your message and with a type string listing the types of all the
160 arguments you will be putting in this message.
161
162 - Now write each of the arguments into the buffer, by calling one of:
163 OSC_writeFloatArg()
164 OSC_writeFloatArgs()
165 OSC_writeIntArg()
166 OSC_writeStringArg()
167
168 - Now your message is complete; you can send out the buffer or you can
169 add another message to it.
170*/
171
172int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt);
173int OSC_closeBundle(OSCbuf *buf);
174int OSC_closeAllBundles(OSCbuf *buf);
175
176int OSC_writeAddress(OSCbuf *buf, char *name);
177int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types);
178int OSC_writeFloatArg(OSCbuf *buf, float arg);
179int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args);
180int OSC_writeIntArg(OSCbuf *buf, int4byte arg);
181int OSC_writeStringArg(OSCbuf *buf, char *arg);
182
183extern char *OSC_errorMessage;
184
185/* How many bytes will be needed in the OSC format to hold the given
186 string? The length of the string, plus the null char, plus any padding
187 needed for 4-byte alignment. */
188int OSC_effectiveStringLength(char *string);
189/*
190Written by Matt Wright, The Center for New Music and Audio Technologies,
191University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
192The Regents of the University of California (Regents).
193
194Permission to use, copy, modify, distribute, and distribute modified versions
195of this software and its documentation without fee and without a signed
196licensing agreement, is hereby granted, provided that the above copyright
197notice, this paragraph and the following two paragraphs appear in all copies,
198modifications, and distributions.
199
200IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
201SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
202OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
203BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
204
205REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
206THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
207PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
208HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
209MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
210*/
211
212/*
213
214 OSC-client.h: library for constructing OpenSoundControl messages.
215 Derived from SynthControl.h
216 Author: Matt Wright
217 Version 0.1: 6/13/97
218 Version 0.2: 7/21/2000: Support for type-tagged messages
219
220
221 General notes:
222
223 This library abstracts away the data format for the OpenSoundControl
224 protocol. Users of this library can construct OpenSoundControl packets
225 with a function call interface instead of knowing how to lay out the bits.
226
227 All issues of memory allocation are deferred to the user of this library.
228 There are two data structures that the user must allocate. The first
229 is the actual buffer that the message will be written into. This buffer
230 can be any size, but if it's too small there's a possibility that it
231 will become overfull. The other data structure is called an OSCbuf,
232 and it holds all the state used by the library as it's constructing
233 a buffer.
234
235 All procedures that have the possibility of an error condition return int,
236 with 0 indicating no error and nonzero indicating an error. The variable
237 OSC_errorMessage will be set to point to a string containing an error
238 message explaining what the problem is.
239
240*/
241
242
243
244/* The int4byte type has to be a 4-byte integer. You may have to
245 change this to long or something else on your system. */
246#ifdef __MWERKS__
247 /* In Metrowerks you can set ints to be 2 or 4 bytes on 68K, but long is
248 always 4 bytes */
249 typedef long int4byte;
250#else
251 typedef int int4byte;
252#endif
253
254/* OSC_timetag.h */
255
256 typedef struct {
257 int seconds;
258 int fraction;
259 } OSCTimeTag;
260
261OSCTimeTag OSCTT_Immediately(void);
262OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset);
263OSCTimeTag OSCTT_CurrentTime(void);
264
265
266
267/* The maximum depth of bundles within bundles within bundles within...
268 This is the size of a static array. If you exceed this limit you'll
269 get an error message. */
270#define MAX_BUNDLE_NESTING 32
271
272
273/* Don't ever manipulate the data in the OSCbuf struct directly. (It's
274 declared here in the header file only so your program will be able to
275 declare variables of type OSCbuf and have the right amount of memory
276 be allocated.) */
277
278typedef struct OSCbuf_struct {
279 char *buffer; /* The buffer to hold the OSC packet */
280 int size; /* Size of the buffer */
281 char *bufptr; /* Current position as we fill the buffer */
282 int state; /* State of partially-constructed message */
283 int4byte *thisMsgSize; /* Pointer to count field before
284 currently-being-written message */
285 int4byte *prevCounts[MAX_BUNDLE_NESTING];
286 /* Pointers to count field before each currently
287 open bundle */
288 int bundleDepth; /* How many sub-sub-bundles are we in now? */
289 char *typeStringPtr; /* This pointer advances through the type
290 tag string as you add arguments. */
291 int gettingFirstUntypedArg; /* nonzero if this message doesn't have
292 a type tag and we're waiting for the 1st arg */
293} OSCbuf;
294
295
296
297/* Initialize the given OSCbuf. The user of this module must pass in the
298 block of memory that this OSCbuf will use for a buffer, and the number of
299 bytes in that block. (It's the user's job to allocate the memory because
300 you do it differently in different systems.) */
301void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray);
302
303
304/* Reset the given OSCbuf. Do this after you send out the contents of
305 the buffer and want to start writing new data into it. */
306void OSC_resetBuffer(OSCbuf *buf);
307
308
309/* Is the buffer empty? (I.e., would it be stupid to send the buffer
310 contents to the synth?) */
311int OSC_isBufferEmpty(OSCbuf *buf);
312
313
314/* How much space is left in the buffer? */
315int OSC_freeSpaceInBuffer(OSCbuf *buf);
316
317/* Does the buffer contain a valid OSC packet? (Returns nonzero if yes.) */
318int OSC_isBufferDone(OSCbuf *buf);
319
320/* When you're ready to send out the buffer (i.e., when OSC_isBufferDone()
321 returns true), call these two procedures to get the OSC packet that's been
322 assembled and its size in bytes. (And then call OSC_resetBuffer() if you
323 want to re-use this OSCbuf for the next packet.) */
324char *OSC_getPacket(OSCbuf *buf);
325int OSC_packetSize(OSCbuf *buf);
326
327
328
329/* Here's the basic model for building up OSC messages in an OSCbuf:
330
331 - Make sure the OSCbuf has been initialized with OSC_initBuffer().
332
333 - To open a bundle, call OSC_openBundle(). You can then write
334 messages or open new bundles within the bundle you opened.
335 Call OSC_closeBundle() to close the bundle. Note that a packet
336 does not have to have a bundle; it can instead consist of just a
337 single message.
338
339
340 - For each message you want to send:
341
342 - Call OSC_writeAddress() with the name of your message. (In
343 addition to writing your message name into the buffer, this
344 procedure will also leave space for the size count of this message.)
345
346 - Alternately, call OSC_writeAddressAndTypes() with the name of
347 your message and with a type string listing the types of all the
348 arguments you will be putting in this message.
349
350 - Now write each of the arguments into the buffer, by calling one of:
351 OSC_writeFloatArg()
352 OSC_writeFloatArgs()
353 OSC_writeIntArg()
354 OSC_writeStringArg()
355
356 - Now your message is complete; you can send out the buffer or you can
357 add another message to it.
358*/
359
360int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt);
361int OSC_closeBundle(OSCbuf *buf);
362int OSC_closeAllBundles(OSCbuf *buf);
363
364int OSC_writeAddress(OSCbuf *buf, char *name);
365int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types);
366int OSC_writeFloatArg(OSCbuf *buf, float arg);
367int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args);
368int OSC_writeIntArg(OSCbuf *buf, int4byte arg);
369int OSC_writeStringArg(OSCbuf *buf, char *arg);
370
371extern char *OSC_errorMessage;
372
373/* How many bytes will be needed in the OSC format to hold the given
374 string? The length of the string, plus the null char, plus any padding
375 needed for 4-byte alignment. */
376int OSC_effectiveStringLength(char *string);
diff --git a/apps/plugins/pdbox/PDa/extra/OSC.pd b/apps/plugins/pdbox/PDa/extra/OSC.pd
new file mode 100644
index 0000000000..8873f308da
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/OSC.pd
@@ -0,0 +1,26 @@
1#N canvas 0 0 240 300 10;
2#X obj 32 185 dumpOSC 5550;
3#X obj 32 217 OSCroute /hello;
4#X obj 32 239 print;
5#X obj 133 238 print;
6#X obj 26 87 sendOSC;
7#X msg 50 43 connect localhost 5550;
8#X msg 21 13 send /hello PDa;
9#X connect 0 0 1 0;
10#X connect 1 0 2 0;
11#X connect 1 1 3 0;
12#X connect 5 0 4 0;
13#X connect 6 0 4 0;
14#N canvas 0 0 240 300 10;
15#X obj 32 185 dumpOSC 5550;
16#X obj 32 217 OSCroute /hello;
17#X obj 32 239 print;
18#X obj 133 238 print;
19#X obj 26 87 sendOSC;
20#X msg 50 43 connect localhost 5550;
21#X msg 21 13 send /hello PDa;
22#X connect 0 0 1 0;
23#X connect 1 0 2 0;
24#X connect 1 1 3 0;
25#X connect 5 0 4 0;
26#X connect 6 0 4 0;
diff --git a/apps/plugins/pdbox/PDa/extra/OSCroute.c b/apps/plugins/pdbox/PDa/extra/OSCroute.c
new file mode 100644
index 0000000000..437d34dc68
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/OSCroute.c
@@ -0,0 +1,1204 @@
1/*
2Written by Adrian Freed, The Center for New Music and Audio Technologies,
3University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04
4The Regents of the University of California (Regents).
5
6Permission to use, copy, modify, distribute, and distribute modified versions
7of this software and its documentation without fee and without a signed
8licensing agreement, is hereby granted, provided that the above copyright
9notice, this paragraph and the following two paragraphs appear in all copies,
10modifications, and distributions.
11
12IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
13SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
14OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
15BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
17REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
20HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
21MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
22
23
24The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
25*/
26
27 /* OSC-route.c
28 Max object for OSC-style dispatching
29
30 To-do:
31
32 Match a pattern against a pattern?
33 Declare outlet types / distinguish leaf nodes from other children
34 More sophisticated (2-pass?) allmessages scheme
35 set message?
36
37
38 pd
39 -------------
40 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
41
42
43 */
44
45#ifdef WIN32
46 #include <stdlib.h>
47 #include <string.h>
48#endif
49#ifdef __APPLE__
50 #include <stdio.h>
51#endif
52#ifdef UNIX
53 #include <stdio.h>
54#endif
55
56/* structure definition of your object */
57
58#define MAX_NUM 20
59#define OSC_ROUTE_VERSION "1.05"
60#define OSCWarning(x...) post(x)
61
62/* the required include files */
63#include "m_pd.h"
64
65
66#ifndef TRUE
67typedef int Boolean;
68#define TRUE 1
69#define FALSE 0
70#endif
71
72
73/* Fixed byte width types */
74typedef int int4; /* 4 byte int */
75
76Boolean PatternMatch (const char *pattern, const char *test);
77
78
79
80/* Version 1.04: Allows #1 thru #9 as typed-in arguments
81 Version 1.05: Allows "list" messages as well as "message" messages.
82*/
83
84static t_class *OSCroute_class;
85
86typedef struct _OSCroute
87{
88 t_object x_obj; // required header
89 t_int x_num; // Number of address prefixes we store
90 t_int x_complainmode; // Do we print a message if no match?
91 t_int x_sendmode; // use pd internal sends instead of outlets
92 char *x_prefixes[MAX_NUM];
93 void *x_outlets[MAX_NUM+1];
94} t_OSCroute;
95
96t_symbol *ps_list, *ps_complain, *ps_emptySymbol;
97
98/* prototypes */
99
100void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
101void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
102void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
103/* //void *OSCroute_new(t_symbol *s, int argc, atom *argv); */
104void *OSCroute_new(t_symbol *s, int argc, t_atom *argv);
105void OSCroute_version (t_OSCroute *x);
106/* void OSCroute_assist (OSCroute *x, void *box, long msg, long arg, */
107/* char *dstString); */
108void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
109
110static char *NextSlashOrNull(char *p);
111static void StrCopyUntilSlash(char *target, const char *source);
112
113
114// free
115static void OSCroute_free(t_OSCroute *x)
116{
117 // freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
118}
119
120/* initialization routine */
121
122// setup
123#ifdef WIN32
124 OSC_API void OSCroute_setup(void) {
125#else
126void OSCroute_setup(void) {
127#endif
128 OSCroute_class = class_new(gensym("OSCroute"), (t_newmethod)OSCroute_new,
129 (t_method)OSCroute_free,sizeof(t_OSCroute), 0, A_GIMME, 0);
130 class_addlist(OSCroute_class, OSCroute_list);
131 class_addanything(OSCroute_class, OSCroute_anything);
132 class_addmethod(OSCroute_class, (t_method)OSCroute_version, gensym("version"), A_NULL, 0, 0);
133 class_sethelpsymbol(OSCroute_class, gensym("OSCroute-help.pd"));
134
135 /*
136 class_addmethod(OSCroute_class, (t_method)OSCroute_connect,
137 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
138 class_addmethod(OSCroute_class, (t_method)OSCroute_disconnect,
139 gensym("disconnect"), 0);
140 class_addmethod(OSCroute_class, (t_method)OSCroute_send, gensym("send"),
141 A_GIMME, 0);
142 */
143/* ps_list = gensym("list"); */
144/* ps_complain = gensym("complain"); */
145 ps_emptySymbol = gensym("");
146
147 post("OSCroute object version " OSC_ROUTE_VERSION " by Matt Wright. pd: jdl Win32 raf.");
148 post("OSCroute Copyright © 1999 Regents of the University of California. All Rights Reserved.");
149}
150
151
152
153/* instance creation routine */
154
155void *OSCroute_new(t_symbol *s, int argc, t_atom *argv)
156{
157
158 t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class); // get memory for a new object & initialize
159
160 int i; //{{raf}} n not used
161
162 // EnterCallback();
163
164 if (argc > MAX_NUM) {
165 post("* OSC-route: too many arguments: %ld (max %ld)", argc, MAX_NUM);
166 // ExitCallback();
167 return 0;
168 }
169
170 x->x_complainmode = 0;
171 x->x_num = 0;
172 for (i = 0; i < argc; ++i) {
173 if (argv[i].a_type == A_SYMBOL) {
174 if (argv[i].a_w.w_symbol->s_name[0] == '/') {
175 /* Now that's a nice prefix */
176 x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
177 ++(x->x_num);
178 } else if (argv[i].a_w.w_symbol->s_name[0] == '#' &&
179 argv[i].a_w.w_symbol->s_name[1] >= '1' &&
180 argv[i].a_w.w_symbol->s_name[1] <= '9') {
181 /* The Max programmer is trying to make a patch that will be
182 a subpatch with arguments. We have to make an outlet for this
183 argument. */
184 x->x_prefixes[i] = "dummy";
185 ++(x->x_num);
186 } else {
187 /* Maybe this is an option we support */
188
189/* if (argv[i].a_w.w_sym == ps_complain) { */
190/* x->x_complainmode = 1; */
191/* } else { */
192/* post("* OSC-route: Unrecognized argument %s", argv[i].a_w.w_sym->s_name); */
193/* } */
194
195 }
196
197 // no LONG
198
199/* } else if (argv[i].a_type == A_FLOAD) { */
200/* // Convert to a numeral. Max ints are -2147483648 to 2147483647 */
201/* char *string = getbytes(12); */
202/* // I can't be bothered to plug this 12 byte memory leak */
203/* if (string == 0) { */
204/* post("* OSC-route: out of memory!"); */
205/* // ExitCallback(); */
206/* return 0; */
207/* } */
208/* sprintf(string, "%d", argv[i].a_w.w_long); */
209/* x->x_prefixes[i] = string; */
210/* ++(x->x_num); */
211
212 } else if (argv[i].a_type == A_FLOAT) {
213 post("* OSC-route: float arguments are not OK.");
214 // ExitCallback();
215 return 0;
216 } else {
217 post("* OSC-route: unrecognized argument type!");
218 // ExitCallback();
219 return 0;
220 }
221 }
222
223
224 /* Have to create the outlets in reverse order */
225 /* well, not in pd ? */
226 // for (i = x->x_num-1; i >= 0; --i) {
227 // for (i = 0; i <= x->x_num-1; i++) {
228 for (i = 0; i <= x->x_num; i++) {
229 // x->x_outlets[i] = listout(x);
230 x->x_outlets[i] = outlet_new(&x->x_obj, &s_list);
231 }
232
233 // ExitCallback();
234 return (x);
235}
236
237
238void OSCroute_version (t_OSCroute *x) {
239 // EnterCallback();
240 post("OSCroute Version " OSC_ROUTE_VERSION
241 ", by Matt Wright. pd jdl, win32: raf.\nOSCroute Compiled " __TIME__ " " __DATE__);
242 // ExitCallback();
243}
244
245/* I don't know why these aren't defined in some Max #include file. */
246#define ASSIST_INLET 1
247#define ASSIST_OUTLET 2
248
249void OSCroute_assist (t_OSCroute *x, void *box, long msg, long arg,
250 char *dstString) {
251 // EnterCallback();
252
253 if (msg==ASSIST_INLET) {
254 sprintf(dstString, "Incoming OSC messages");
255 } else if (msg==ASSIST_OUTLET) {
256 if (arg < 0 || arg >= x->x_num) {
257 post("* OSCroute_assist: No outlet corresponds to arg %ld!", arg);
258 } else {
259 sprintf(dstString, "subaddress + args for prefix %s", x->x_prefixes[arg]);
260 }
261 } else {
262 post("* OSCroute_assist: unrecognized message %ld", msg);
263 }
264
265 // ExitCallback();
266}
267
268void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
269 // EnterCallback();
270 if (argc > 0 && argv[0].a_type == A_SYMBOL) {
271 /* Ignore the fact that this is a "list" */
272 OSCroute_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1);
273 } else {
274 // post("* OSC-route: invalid list beginning with a number");
275 // output on unmatched outlet jdl 20020908
276 if (argv[0].a_type == A_FLOAT) {
277 outlet_float(x->x_outlets[x->x_num], argv[0].a_w.w_float);
278 } else {
279 post("* OSC-route: unrecognized atom type!");
280 }
281 }
282 // ExitCallback();
283}
284
285
286void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
287 // EnterCallback();
288 OSCroute_doanything(x, s, argc, argv);
289 // ExitCallback();
290}
291
292
293
294
295void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
296 char *pattern, *nextSlash;
297 int i;
298 int matchedAnything;
299 // post("*** OSCroute_anything(s %s, argc %ld)", s->s_name, (long) argc);
300
301 pattern = s->s_name;
302 if (pattern[0] != '/') {
303 post("* OSC-route: invalid message pattern %s does not begin with /", s->s_name);
304 outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
305 return;
306 }
307
308 matchedAnything = 0;
309
310 nextSlash = NextSlashOrNull(pattern+1);
311 if (*nextSlash == '\0') {
312 /* last level of the address, so we'll output the argument list */
313
314
315#ifdef NULL_IS_DIFFERENT_FROM_BANG
316 if (argc==0) {
317 post("* OSC-route: why are you matching one level pattern %s with no args?",
318 pattern);
319 return;
320 }
321#endif
322
323 for (i = 0; i < x->x_num; ++i) {
324 if (PatternMatch(pattern+1, x->x_prefixes[i]+1)) {
325 ++matchedAnything;
326
327 // I hate stupid Max lists with a special first element
328 if (argc == 0) {
329 outlet_bang(x->x_outlets[i]);
330 } else if (argv[0].a_type == A_SYMBOL) {
331 // Promote the symbol that was argv[0] to the special symbol
332 outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
333 } else if (argc > 1) {
334 // Multiple arguments starting with a number, so naturally we have
335 // to use a special function to output this "list", since it's what
336 // Max originally meant by "list".
337 outlet_list(x->x_outlets[i], 0L, argc, argv);
338 } else {
339 // There was only one argument, and it was a number, so we output it
340 // not as a list
341/* if (argv[0].a_type == A_LONG) { */
342
343/* outlet_int(x->x_outlets[i], argv[0].a_w.w_long); */
344 // } else
345 if (argv[0].a_type == A_FLOAT) {
346
347 outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
348 } else {
349 post("* OSC-route: unrecognized atom type!");
350 }
351 }
352 }
353 }
354 } else {
355 /* There's more address after this part, so our output list will begin with
356 the next slash. */
357 t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */
358 char patternBegin[1000];
359
360
361 /* Get the first level of the incoming pattern to match against all our prefixes */
362 StrCopyUntilSlash(patternBegin, pattern+1);
363
364 for (i = 0; i < x->x_num; ++i) {
365 if (PatternMatch(patternBegin, x->x_prefixes[i]+1)) {
366 ++matchedAnything;
367 if (restOfPattern == 0) {
368 restOfPattern = gensym(nextSlash);
369 }
370 outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
371 }
372 }
373 }
374
375 if (x->x_complainmode) {
376 if (!matchedAnything) {
377 post("* OSC-route: pattern %s did not match any prefixes", pattern);
378 }
379 }
380
381 // output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908
382 if (!matchedAnything) {
383 outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
384 }
385
386
387}
388
389static char *NextSlashOrNull(char *p) {
390 while (*p != '/' && *p != '\0') {
391 p++;
392 }
393 return p;
394}
395
396static void StrCopyUntilSlash(char *target, const char *source) {
397 while (*source != '/' && *source != '\0') {
398 *target = *source;
399 ++target;
400 ++source;
401 }
402 *target = 0;
403}
404
405static int MyStrCopy(char *target, const char *source) {
406 int i = 0;
407 while (*source != '\0') {
408 *target = *source;
409 ++target;
410 ++source;
411 ++i;
412 }
413 *target = 0;
414 return i;
415}
416
417
418
419void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
420 int i;
421 t_symbol *prefixSymbol = 0;
422 char prefixBuf[1000];
423 char *endOfPrefix;
424 t_atom a[1];
425
426 if (argc >= 1 && argv[0].a_type == A_SYMBOL) {
427 prefixSymbol = argv[0].a_w.w_symbol;
428 endOfPrefix = prefixBuf + MyStrCopy(prefixBuf,
429 prefixSymbol->s_name);
430 } else {
431 prefixSymbol = ps_emptySymbol;
432 prefixBuf[0] = '\0';
433 endOfPrefix = prefixBuf;
434 }
435
436
437 for (i = 0; i < x->x_num; ++i) {
438 post("OSC: %s%s", prefixSymbol->s_name, x->x_prefixes[i]);
439 MyStrCopy(endOfPrefix, x->x_prefixes[i]);
440 SETSYMBOL(a, gensym(prefixBuf));
441 outlet_anything(x->x_outlets[i], s, 1, a);
442 }
443}
444
445
446/* --------------------------------------------------- */
447
448
449
450static const char *theWholePattern; /* Just for warning messages */
451
452static Boolean MatchBrackets (const char *pattern, const char *test);
453static Boolean MatchList (const char *pattern, const char *test);
454
455Boolean PatternMatch (const char * pattern, const char * test) {
456 theWholePattern = pattern;
457
458 if (pattern == 0 || pattern[0] == 0) {
459 return test[0] == 0;
460 }
461
462 if (test[0] == 0) {
463 if (pattern[0] == '*')
464 return PatternMatch (pattern+1,test);
465 else
466 return FALSE;
467 }
468
469 switch (pattern[0]) {
470 case 0 : return test[0] == 0;
471 case '?' : return PatternMatch (pattern + 1, test + 1);
472 case '*' :
473 if (PatternMatch (pattern+1, test)) {
474 return TRUE;
475 } else {
476 return PatternMatch (pattern, test+1);
477 }
478 case ']' :
479 case '}' :
480 OSCWarning("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
481 return FALSE;
482 case '[' :
483 return MatchBrackets (pattern,test);
484 case '{' :
485 return MatchList (pattern,test);
486 case '\\' :
487 if (pattern[1] == 0) {
488 return test[0] == 0;
489 } else if (pattern[1] == test[0]) {
490 return PatternMatch (pattern+2,test+1);
491 } else {
492 return FALSE;
493 }
494 default :
495 if (pattern[0] == test[0]) {
496 return PatternMatch (pattern+1,test+1);
497 } else {
498 return FALSE;
499 }
500 }
501}
502
503
504/* we know that pattern[0] == '[' and test[0] != 0 */
505
506static Boolean MatchBrackets (const char *pattern, const char *test) {
507 Boolean result;
508 Boolean negated = FALSE;
509 const char *p = pattern;
510
511 if (pattern[1] == 0) {
512 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
513 return FALSE;
514 }
515
516 if (pattern[1] == '!') {
517 negated = TRUE;
518 p++;
519 }
520
521 while (*p != ']') {
522 if (*p == 0) {
523 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
524 return FALSE;
525 }
526 if (p[1] == '-' && p[2] != 0) {
527 if (test[0] >= p[0] && test[0] <= p[2]) {
528 result = !negated;
529 goto advance;
530 }
531 }
532 if (p[0] == test[0]) {
533 result = !negated;
534 goto advance;
535 }
536 p++;
537 }
538
539 result = negated;
540
541advance:
542
543 if (!result)
544 return FALSE;
545
546 while (*p != ']') {
547 if (*p == 0) {
548 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
549 return FALSE;
550 }
551 p++;
552 }
553
554 return PatternMatch (p+1,test+1);
555}
556
557static Boolean MatchList (const char *pattern, const char *test) {
558
559 const char *restOfPattern, *tp = test;
560
561
562 for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
563 if (*restOfPattern == 0) {
564 OSCWarning("Unterminated { in pattern \".../%s/...\"", theWholePattern);
565 return FALSE;
566 }
567 }
568
569 restOfPattern++; /* skip close curly brace */
570
571
572 pattern++; /* skip open curly brace */
573
574 while (1) {
575
576 if (*pattern == ',') {
577 if (PatternMatch (restOfPattern, tp)) {
578 return TRUE;
579 } else {
580 tp = test;
581 ++pattern;
582 }
583 } else if (*pattern == '}') {
584 return PatternMatch (restOfPattern, tp);
585 } else if (*pattern == *tp) {
586 ++pattern;
587 ++tp;
588 } else {
589 tp = test;
590 while (*pattern != ',' && *pattern != '}') {
591 pattern++;
592 }
593 if (*pattern == ',') {
594 pattern++;
595 }
596 }
597 }
598
599}
600
601
602
603/*
604Written by Adrian Freed, The Center for New Music and Audio Technologies,
605University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04
606The Regents of the University of California (Regents).
607
608Permission to use, copy, modify, distribute, and distribute modified versions
609of this software and its documentation without fee and without a signed
610licensing agreement, is hereby granted, provided that the above copyright
611notice, this paragraph and the following two paragraphs appear in all copies,
612modifications, and distributions.
613
614IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
615SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
616OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
617BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
618
619REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
620THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
621PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
622HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
623MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
624
625
626The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
627*/
628
629 /* OSC-route.c
630 Max object for OSC-style dispatching
631
632 To-do:
633
634 Match a pattern against a pattern?
635 Declare outlet types / distinguish leaf nodes from other children
636 More sophisticated (2-pass?) allmessages scheme
637 set message?
638
639
640 pd
641 -------------
642 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
643
644
645 */
646
647#ifdef WIN32
648 #include <stdlib.h>
649 #include <string.h>
650#endif
651#ifdef __APPLE__
652 #include <stdio.h>
653#endif
654#ifdef UNIX
655 #include <stdio.h>
656#endif
657
658/* structure definition of your object */
659
660#define MAX_NUM 20
661#define OSC_ROUTE_VERSION "1.05"
662#define OSCWarning(x...) post(x)
663
664/* the required include files */
665#include "m_pd.h"
666
667
668#ifndef TRUE
669typedef int Boolean;
670#define TRUE 1
671#define FALSE 0
672#endif
673
674
675/* Fixed byte width types */
676typedef int int4; /* 4 byte int */
677
678Boolean PatternMatch (const char *pattern, const char *test);
679
680
681
682/* Version 1.04: Allows #1 thru #9 as typed-in arguments
683 Version 1.05: Allows "list" messages as well as "message" messages.
684*/
685
686static t_class *OSCroute_class;
687
688typedef struct _OSCroute
689{
690 t_object x_obj; // required header
691 t_int x_num; // Number of address prefixes we store
692 t_int x_complainmode; // Do we print a message if no match?
693 t_int x_sendmode; // use pd internal sends instead of outlets
694 char *x_prefixes[MAX_NUM];
695 void *x_outlets[MAX_NUM+1];
696} t_OSCroute;
697
698t_symbol *ps_list, *ps_complain, *ps_emptySymbol;
699
700/* prototypes */
701
702void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
703void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
704void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
705/* //void *OSCroute_new(t_symbol *s, int argc, atom *argv); */
706void *OSCroute_new(t_symbol *s, int argc, t_atom *argv);
707void OSCroute_version (t_OSCroute *x);
708/* void OSCroute_assist (OSCroute *x, void *box, long msg, long arg, */
709/* char *dstString); */
710void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
711
712static char *NextSlashOrNull(char *p);
713static void StrCopyUntilSlash(char *target, const char *source);
714
715
716// free
717static void OSCroute_free(t_OSCroute *x)
718{
719 // freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
720}
721
722/* initialization routine */
723
724// setup
725#ifdef WIN32
726 OSC_API void OSCroute_setup(void) {
727#else
728void OSCroute_setup(void) {
729#endif
730 OSCroute_class = class_new(gensym("OSCroute"), (t_newmethod)OSCroute_new,
731 (t_method)OSCroute_free,sizeof(t_OSCroute), 0, A_GIMME, 0);
732 class_addlist(OSCroute_class, OSCroute_list);
733 class_addanything(OSCroute_class, OSCroute_anything);
734 class_addmethod(OSCroute_class, (t_method)OSCroute_version, gensym("version"), A_NULL, 0, 0);
735 class_sethelpsymbol(OSCroute_class, gensym("OSCroute-help.pd"));
736
737 /*
738 class_addmethod(OSCroute_class, (t_method)OSCroute_connect,
739 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
740 class_addmethod(OSCroute_class, (t_method)OSCroute_disconnect,
741 gensym("disconnect"), 0);
742 class_addmethod(OSCroute_class, (t_method)OSCroute_send, gensym("send"),
743 A_GIMME, 0);
744 */
745/* ps_list = gensym("list"); */
746/* ps_complain = gensym("complain"); */
747 ps_emptySymbol = gensym("");
748
749 post("OSCroute object version " OSC_ROUTE_VERSION " by Matt Wright. pd: jdl Win32 raf.");
750 post("OSCroute Copyright © 1999 Regents of the University of California. All Rights Reserved.");
751}
752
753
754
755/* instance creation routine */
756
757void *OSCroute_new(t_symbol *s, int argc, t_atom *argv)
758{
759
760 t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class); // get memory for a new object & initialize
761
762 int i; //{{raf}} n not used
763
764 // EnterCallback();
765
766 if (argc > MAX_NUM) {
767 post("* OSC-route: too many arguments: %ld (max %ld)", argc, MAX_NUM);
768 // ExitCallback();
769 return 0;
770 }
771
772 x->x_complainmode = 0;
773 x->x_num = 0;
774 for (i = 0; i < argc; ++i) {
775 if (argv[i].a_type == A_SYMBOL) {
776 if (argv[i].a_w.w_symbol->s_name[0] == '/') {
777 /* Now that's a nice prefix */
778 x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
779 ++(x->x_num);
780 } else if (argv[i].a_w.w_symbol->s_name[0] == '#' &&
781 argv[i].a_w.w_symbol->s_name[1] >= '1' &&
782 argv[i].a_w.w_symbol->s_name[1] <= '9') {
783 /* The Max programmer is trying to make a patch that will be
784 a subpatch with arguments. We have to make an outlet for this
785 argument. */
786 x->x_prefixes[i] = "dummy";
787 ++(x->x_num);
788 } else {
789 /* Maybe this is an option we support */
790
791/* if (argv[i].a_w.w_sym == ps_complain) { */
792/* x->x_complainmode = 1; */
793/* } else { */
794/* post("* OSC-route: Unrecognized argument %s", argv[i].a_w.w_sym->s_name); */
795/* } */
796
797 }
798
799 // no LONG
800
801/* } else if (argv[i].a_type == A_FLOAD) { */
802/* // Convert to a numeral. Max ints are -2147483648 to 2147483647 */
803/* char *string = getbytes(12); */
804/* // I can't be bothered to plug this 12 byte memory leak */
805/* if (string == 0) { */
806/* post("* OSC-route: out of memory!"); */
807/* // ExitCallback(); */
808/* return 0; */
809/* } */
810/* sprintf(string, "%d", argv[i].a_w.w_long); */
811/* x->x_prefixes[i] = string; */
812/* ++(x->x_num); */
813
814 } else if (argv[i].a_type == A_FLOAT) {
815 post("* OSC-route: float arguments are not OK.");
816 // ExitCallback();
817 return 0;
818 } else {
819 post("* OSC-route: unrecognized argument type!");
820 // ExitCallback();
821 return 0;
822 }
823 }
824
825
826 /* Have to create the outlets in reverse order */
827 /* well, not in pd ? */
828 // for (i = x->x_num-1; i >= 0; --i) {
829 // for (i = 0; i <= x->x_num-1; i++) {
830 for (i = 0; i <= x->x_num; i++) {
831 // x->x_outlets[i] = listout(x);
832 x->x_outlets[i] = outlet_new(&x->x_obj, &s_list);
833 }
834
835 // ExitCallback();
836 return (x);
837}
838
839
840void OSCroute_version (t_OSCroute *x) {
841 // EnterCallback();
842 post("OSCroute Version " OSC_ROUTE_VERSION
843 ", by Matt Wright. pd jdl, win32: raf.\nOSCroute Compiled " __TIME__ " " __DATE__);
844 // ExitCallback();
845}
846
847/* I don't know why these aren't defined in some Max #include file. */
848#define ASSIST_INLET 1
849#define ASSIST_OUTLET 2
850
851void OSCroute_assist (t_OSCroute *x, void *box, long msg, long arg,
852 char *dstString) {
853 // EnterCallback();
854
855 if (msg==ASSIST_INLET) {
856 sprintf(dstString, "Incoming OSC messages");
857 } else if (msg==ASSIST_OUTLET) {
858 if (arg < 0 || arg >= x->x_num) {
859 post("* OSCroute_assist: No outlet corresponds to arg %ld!", arg);
860 } else {
861 sprintf(dstString, "subaddress + args for prefix %s", x->x_prefixes[arg]);
862 }
863 } else {
864 post("* OSCroute_assist: unrecognized message %ld", msg);
865 }
866
867 // ExitCallback();
868}
869
870void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
871 // EnterCallback();
872 if (argc > 0 && argv[0].a_type == A_SYMBOL) {
873 /* Ignore the fact that this is a "list" */
874 OSCroute_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1);
875 } else {
876 // post("* OSC-route: invalid list beginning with a number");
877 // output on unmatched outlet jdl 20020908
878 if (argv[0].a_type == A_FLOAT) {
879 outlet_float(x->x_outlets[x->x_num], argv[0].a_w.w_float);
880 } else {
881 post("* OSC-route: unrecognized atom type!");
882 }
883 }
884 // ExitCallback();
885}
886
887
888void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
889 // EnterCallback();
890 OSCroute_doanything(x, s, argc, argv);
891 // ExitCallback();
892}
893
894
895
896
897void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
898 char *pattern, *nextSlash;
899 int i;
900 int matchedAnything;
901 // post("*** OSCroute_anything(s %s, argc %ld)", s->s_name, (long) argc);
902
903 pattern = s->s_name;
904 if (pattern[0] != '/') {
905 post("* OSC-route: invalid message pattern %s does not begin with /", s->s_name);
906 outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
907 return;
908 }
909
910 matchedAnything = 0;
911
912 nextSlash = NextSlashOrNull(pattern+1);
913 if (*nextSlash == '\0') {
914 /* last level of the address, so we'll output the argument list */
915
916
917#ifdef NULL_IS_DIFFERENT_FROM_BANG
918 if (argc==0) {
919 post("* OSC-route: why are you matching one level pattern %s with no args?",
920 pattern);
921 return;
922 }
923#endif
924
925 for (i = 0; i < x->x_num; ++i) {
926 if (PatternMatch(pattern+1, x->x_prefixes[i]+1)) {
927 ++matchedAnything;
928
929 // I hate stupid Max lists with a special first element
930 if (argc == 0) {
931 outlet_bang(x->x_outlets[i]);
932 } else if (argv[0].a_type == A_SYMBOL) {
933 // Promote the symbol that was argv[0] to the special symbol
934 outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
935 } else if (argc > 1) {
936 // Multiple arguments starting with a number, so naturally we have
937 // to use a special function to output this "list", since it's what
938 // Max originally meant by "list".
939 outlet_list(x->x_outlets[i], 0L, argc, argv);
940 } else {
941 // There was only one argument, and it was a number, so we output it
942 // not as a list
943/* if (argv[0].a_type == A_LONG) { */
944
945/* outlet_int(x->x_outlets[i], argv[0].a_w.w_long); */
946 // } else
947 if (argv[0].a_type == A_FLOAT) {
948
949 outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
950 } else {
951 post("* OSC-route: unrecognized atom type!");
952 }
953 }
954 }
955 }
956 } else {
957 /* There's more address after this part, so our output list will begin with
958 the next slash. */
959 t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */
960 char patternBegin[1000];
961
962
963 /* Get the first level of the incoming pattern to match against all our prefixes */
964 StrCopyUntilSlash(patternBegin, pattern+1);
965
966 for (i = 0; i < x->x_num; ++i) {
967 if (PatternMatch(patternBegin, x->x_prefixes[i]+1)) {
968 ++matchedAnything;
969 if (restOfPattern == 0) {
970 restOfPattern = gensym(nextSlash);
971 }
972 outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
973 }
974 }
975 }
976
977 if (x->x_complainmode) {
978 if (!matchedAnything) {
979 post("* OSC-route: pattern %s did not match any prefixes", pattern);
980 }
981 }
982
983 // output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908
984 if (!matchedAnything) {
985 outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
986 }
987
988
989}
990
991static char *NextSlashOrNull(char *p) {
992 while (*p != '/' && *p != '\0') {
993 p++;
994 }
995 return p;
996}
997
998static void StrCopyUntilSlash(char *target, const char *source) {
999 while (*source != '/' && *source != '\0') {
1000 *target = *source;
1001 ++target;
1002 ++source;
1003 }
1004 *target = 0;
1005}
1006
1007static int MyStrCopy(char *target, const char *source) {
1008 int i = 0;
1009 while (*source != '\0') {
1010 *target = *source;
1011 ++target;
1012 ++source;
1013 ++i;
1014 }
1015 *target = 0;
1016 return i;
1017}
1018
1019
1020
1021void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
1022 int i;
1023 t_symbol *prefixSymbol = 0;
1024 char prefixBuf[1000];
1025 char *endOfPrefix;
1026 t_atom a[1];
1027
1028 if (argc >= 1 && argv[0].a_type == A_SYMBOL) {
1029 prefixSymbol = argv[0].a_w.w_symbol;
1030 endOfPrefix = prefixBuf + MyStrCopy(prefixBuf,
1031 prefixSymbol->s_name);
1032 } else {
1033 prefixSymbol = ps_emptySymbol;
1034 prefixBuf[0] = '\0';
1035 endOfPrefix = prefixBuf;
1036 }
1037
1038
1039 for (i = 0; i < x->x_num; ++i) {
1040 post("OSC: %s%s", prefixSymbol->s_name, x->x_prefixes[i]);
1041 MyStrCopy(endOfPrefix, x->x_prefixes[i]);
1042 SETSYMBOL(a, gensym(prefixBuf));
1043 outlet_anything(x->x_outlets[i], s, 1, a);
1044 }
1045}
1046
1047
1048/* --------------------------------------------------- */
1049
1050
1051
1052static const char *theWholePattern; /* Just for warning messages */
1053
1054static Boolean MatchBrackets (const char *pattern, const char *test);
1055static Boolean MatchList (const char *pattern, const char *test);
1056
1057Boolean PatternMatch (const char * pattern, const char * test) {
1058 theWholePattern = pattern;
1059
1060 if (pattern == 0 || pattern[0] == 0) {
1061 return test[0] == 0;
1062 }
1063
1064 if (test[0] == 0) {
1065 if (pattern[0] == '*')
1066 return PatternMatch (pattern+1,test);
1067 else
1068 return FALSE;
1069 }
1070
1071 switch (pattern[0]) {
1072 case 0 : return test[0] == 0;
1073 case '?' : return PatternMatch (pattern + 1, test + 1);
1074 case '*' :
1075 if (PatternMatch (pattern+1, test)) {
1076 return TRUE;
1077 } else {
1078 return PatternMatch (pattern, test+1);
1079 }
1080 case ']' :
1081 case '}' :
1082 OSCWarning("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
1083 return FALSE;
1084 case '[' :
1085 return MatchBrackets (pattern,test);
1086 case '{' :
1087 return MatchList (pattern,test);
1088 case '\\' :
1089 if (pattern[1] == 0) {
1090 return test[0] == 0;
1091 } else if (pattern[1] == test[0]) {
1092 return PatternMatch (pattern+2,test+1);
1093 } else {
1094 return FALSE;
1095 }
1096 default :
1097 if (pattern[0] == test[0]) {
1098 return PatternMatch (pattern+1,test+1);
1099 } else {
1100 return FALSE;
1101 }
1102 }
1103}
1104
1105
1106/* we know that pattern[0] == '[' and test[0] != 0 */
1107
1108static Boolean MatchBrackets (const char *pattern, const char *test) {
1109 Boolean result;
1110 Boolean negated = FALSE;
1111 const char *p = pattern;
1112
1113 if (pattern[1] == 0) {
1114 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
1115 return FALSE;
1116 }
1117
1118 if (pattern[1] == '!') {
1119 negated = TRUE;
1120 p++;
1121 }
1122
1123 while (*p != ']') {
1124 if (*p == 0) {
1125 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
1126 return FALSE;
1127 }
1128 if (p[1] == '-' && p[2] != 0) {
1129 if (test[0] >= p[0] && test[0] <= p[2]) {
1130 result = !negated;
1131 goto advance;
1132 }
1133 }
1134 if (p[0] == test[0]) {
1135 result = !negated;
1136 goto advance;
1137 }
1138 p++;
1139 }
1140
1141 result = negated;
1142
1143advance:
1144
1145 if (!result)
1146 return FALSE;
1147
1148 while (*p != ']') {
1149 if (*p == 0) {
1150 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
1151 return FALSE;
1152 }
1153 p++;
1154 }
1155
1156 return PatternMatch (p+1,test+1);
1157}
1158
1159static Boolean MatchList (const char *pattern, const char *test) {
1160
1161 const char *restOfPattern, *tp = test;
1162
1163
1164 for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
1165 if (*restOfPattern == 0) {
1166 OSCWarning("Unterminated { in pattern \".../%s/...\"", theWholePattern);
1167 return FALSE;
1168 }
1169 }
1170
1171 restOfPattern++; /* skip close curly brace */
1172
1173
1174 pattern++; /* skip open curly brace */
1175
1176 while (1) {
1177
1178 if (*pattern == ',') {
1179 if (PatternMatch (restOfPattern, tp)) {
1180 return TRUE;
1181 } else {
1182 tp = test;
1183 ++pattern;
1184 }
1185 } else if (*pattern == '}') {
1186 return PatternMatch (restOfPattern, tp);
1187 } else if (*pattern == *tp) {
1188 ++pattern;
1189 ++tp;
1190 } else {
1191 tp = test;
1192 while (*pattern != ',' && *pattern != '}') {
1193 pattern++;
1194 }
1195 if (*pattern == ',') {
1196 pattern++;
1197 }
1198 }
1199 }
1200
1201}
1202
1203
1204
diff --git a/apps/plugins/pdbox/PDa/extra/README b/apps/plugins/pdbox/PDa/extra/README
new file mode 100644
index 0000000000..6e0b4a1e67
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/README
@@ -0,0 +1,24 @@
1PDa - externals
2===============
3
4This is a collection of selected externals for PDa. The externals are
5all copyright by their authors, check out the copyright notice in
6each of the files.
7
8I have changed some of the files a bit, so the bugs are most likely my
9fault. Send feedback and wishes to
10
11geiger <AT> xdv dot org
12
13PDa - externals
14===============
15
16This is a collection of selected externals for PDa. The externals are
17all copyright by their authors, check out the copyright notice in
18each of the files.
19
20I have changed some of the files a bit, so the bugs are most likely my
21fault. Send feedback and wishes to
22
23geiger <AT> xdv dot org
24
diff --git a/apps/plugins/pdbox/PDa/extra/bandpass-help.pd b/apps/plugins/pdbox/PDa/extra/bandpass-help.pd
new file mode 100644
index 0000000000..65d41eafad
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/bandpass-help.pd
@@ -0,0 +1,34 @@
1#N canvas 428 285 240 300 8;
2#X obj 24 78 noise~;
3#X obj 15 215 dac~;
4#X obj 24 167 biquad~;
5#X floatatom 67 76 5 0 0 0 - - -;
6#X floatatom 83 111 5 0 0 0 - - -;
7#X obj 67 138 bandpass 600 10;
8#X text 77 97 bandwidth: 100 = 1 octave;
9#X text 67 58 frequency;
10#X text 8 11 Calculation of biquad coefficients;
11#X text 7 21 ==================================;
12#X connect 0 0 2 0;
13#X connect 2 0 1 0;
14#X connect 2 0 1 1;
15#X connect 3 0 5 0;
16#X connect 4 0 5 1;
17#X connect 5 0 2 0;
18#N canvas 428 285 240 300 8;
19#X obj 24 78 noise~;
20#X obj 15 215 dac~;
21#X obj 24 167 biquad~;
22#X floatatom 67 76 5 0 0 0 - - -;
23#X floatatom 83 111 5 0 0 0 - - -;
24#X obj 67 138 bandpass 600 10;
25#X text 77 97 bandwidth: 100 = 1 octave;
26#X text 67 58 frequency;
27#X text 8 11 Calculation of biquad coefficients;
28#X text 7 21 ==================================;
29#X connect 0 0 2 0;
30#X connect 2 0 1 0;
31#X connect 2 0 1 1;
32#X connect 3 0 5 0;
33#X connect 4 0 5 1;
34#X connect 5 0 2 0;
diff --git a/apps/plugins/pdbox/PDa/extra/bandpass.c b/apps/plugins/pdbox/PDa/extra/bandpass.c
new file mode 100644
index 0000000000..6de56d6174
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/bandpass.c
@@ -0,0 +1,172 @@
1
2/* (C) Guenter Geiger <geiger@epy.co.at> */
3
4
5/*
6
7 These filter coefficients computations are taken from
8 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
9
10 written by Robert Bristow-Johnson
11
12*/
13
14#include "m_pd.h"
15#ifdef NT
16#pragma warning( disable : 4244 )
17#pragma warning( disable : 4305 )
18#endif
19#include <math.h>
20#include "filters.h"
21
22/* ------------------- bandpass ----------------------------*/
23
24static t_class *bandpass_class;
25
26void bandpass_bang(t_rbjfilter *x)
27{
28 t_atom at[5];
29 t_float omega = e_omega(x->x_freq,x->x_rate);
30 t_float alpha = e_alpha(x->x_bw* 0.01,omega);
31 t_float b1 = 0.;
32 t_float b0 = alpha;
33 t_float b2 = -alpha;
34 t_float a0 = 1 + alpha;
35 t_float a1 = -2.*cos(omega);
36 t_float a2 = 1 - alpha;
37
38/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
39
40 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
41 post("bandpass: filter unstable -> resetting");
42 a0=1.;a1=0.;a2=0.;
43 b0=1.;b1=0.;b2=0.;
44 }
45
46 SETFLOAT(at,-a1/a0);
47 SETFLOAT(at+1,-a2/a0);
48 SETFLOAT(at+2,b0/a0);
49 SETFLOAT(at+3,b1/a0);
50 SETFLOAT(at+4,b2/a0);
51
52 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
53}
54
55
56void bandpass_float(t_rbjfilter *x,t_floatarg f)
57{
58 x->x_freq = f;
59 bandpass_bang(x);
60}
61
62
63static void *bandpass_new(t_floatarg f,t_floatarg bw)
64{
65 t_rbjfilter *x = (t_rbjfilter *)pd_new(bandpass_class);
66
67 x->x_rate = 44100.0;
68 outlet_new(&x->x_obj,&s_float);
69/* floatinlet_new(&x->x_obj, &x->x_gain); */
70 floatinlet_new(&x->x_obj, &x->x_bw);
71 if (f > 0.) x->x_freq = f;
72 if (bw > 0.) x->x_bw = bw;
73 return (x);
74}
75
76
77void bandpass_setup(void)
78{
79 bandpass_class = class_new(gensym("bandpass"), (t_newmethod)bandpass_new, 0,
80 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,0);
81 class_addbang(bandpass_class,bandpass_bang);
82 class_addfloat(bandpass_class,bandpass_float);
83}
84
85
86
87
88/* (C) Guenter Geiger <geiger@epy.co.at> */
89
90
91/*
92
93 These filter coefficients computations are taken from
94 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
95
96 written by Robert Bristow-Johnson
97
98*/
99
100#include "m_pd.h"
101#ifdef NT
102#pragma warning( disable : 4244 )
103#pragma warning( disable : 4305 )
104#endif
105#include <math.h>
106#include "filters.h"
107
108/* ------------------- bandpass ----------------------------*/
109
110static t_class *bandpass_class;
111
112void bandpass_bang(t_rbjfilter *x)
113{
114 t_atom at[5];
115 t_float omega = e_omega(x->x_freq,x->x_rate);
116 t_float alpha = e_alpha(x->x_bw* 0.01,omega);
117 t_float b1 = 0.;
118 t_float b0 = alpha;
119 t_float b2 = -alpha;
120 t_float a0 = 1 + alpha;
121 t_float a1 = -2.*cos(omega);
122 t_float a2 = 1 - alpha;
123
124/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
125
126 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
127 post("bandpass: filter unstable -> resetting");
128 a0=1.;a1=0.;a2=0.;
129 b0=1.;b1=0.;b2=0.;
130 }
131
132 SETFLOAT(at,-a1/a0);
133 SETFLOAT(at+1,-a2/a0);
134 SETFLOAT(at+2,b0/a0);
135 SETFLOAT(at+3,b1/a0);
136 SETFLOAT(at+4,b2/a0);
137
138 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
139}
140
141
142void bandpass_float(t_rbjfilter *x,t_floatarg f)
143{
144 x->x_freq = f;
145 bandpass_bang(x);
146}
147
148
149static void *bandpass_new(t_floatarg f,t_floatarg bw)
150{
151 t_rbjfilter *x = (t_rbjfilter *)pd_new(bandpass_class);
152
153 x->x_rate = 44100.0;
154 outlet_new(&x->x_obj,&s_float);
155/* floatinlet_new(&x->x_obj, &x->x_gain); */
156 floatinlet_new(&x->x_obj, &x->x_bw);
157 if (f > 0.) x->x_freq = f;
158 if (bw > 0.) x->x_bw = bw;
159 return (x);
160}
161
162
163void bandpass_setup(void)
164{
165 bandpass_class = class_new(gensym("bandpass"), (t_newmethod)bandpass_new, 0,
166 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,0);
167 class_addbang(bandpass_class,bandpass_bang);
168 class_addfloat(bandpass_class,bandpass_float);
169}
170
171
172
diff --git a/apps/plugins/pdbox/PDa/extra/dumpOSC.c b/apps/plugins/pdbox/PDa/extra/dumpOSC.c
new file mode 100644
index 0000000000..37767c2b03
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/dumpOSC.c
@@ -0,0 +1,1998 @@
1/*
2Written by Matt Wright and Adrian Freed, The Center for New Music and
3Audio Technologies, University of California, Berkeley. Copyright (c)
41992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of
5California (Regents).
6
7Permission to use, copy, modify, distribute, and distribute modified versions
8of this software and its documentation without fee and without a signed
9licensing agreement, is hereby granted, provided that the above copyright
10notice, this paragraph and the following two paragraphs appear in all copies,
11modifications, and distributions.
12
13IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
14SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
15OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
16BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17
18REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
21HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
22MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
24
25The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
26*/
27
28
29 /*
30
31 dumpOSC.c
32 server that displays OpenSoundControl messages sent to it
33 for debugging client udp and UNIX protocol
34
35 by Matt Wright, 6/3/97
36 modified from dumpSC.c, by Matt Wright and Adrian Freed
37
38 version 0.2: Added "-silent" option a.k.a. "-quiet"
39
40 version 0.3: Incorporated patches from Nicola Bernardini to make
41 things Linux-friendly. Also added ntohl() in the right places
42 to support little-endian architectures.
43
44
45
46 compile:
47 cc -o dumpOSC dumpOSC.c
48
49 to-do:
50
51 More robustness in saying exactly what's wrong with ill-formed
52 messages. (If they don't make sense, show exactly what was
53 received.)
54
55 Time-based features: print time-received for each packet
56
57 Clean up to separate OSC parsing code from socket/select stuff
58
59 pd: branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/dumpOSC/dumpOSC.c
60 -------------
61 -- added pd functions
62 -- socket is made differently than original via pd mechanisms
63 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
64 -- the OSX changes from cnmat didnt make it here yet but this compiles
65 on OSX anyway.
66
67*/
68
69#if HAVE_CONFIG_H
70#include <config.h>
71#endif
72
73#include "m_pd.h"
74//#include "m_imp.h"
75#include "s_stuff.h"
76
77/* declarations */
78
79// typedef void (*t_fdpollfn)(void *ptr, int fd);
80void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
81
82
83#if defined(__sgi) || defined(__linux) || defined(WIN32) || defined(__APPLE__)
84
85#ifdef WIN32
86 #include "OSC-common.h"
87 #include <winsock2.h>
88 #include <string.h>
89 #include <stdlib.h>
90 #include <fcntl.h>
91 #include <sys/types.h>
92 #include <sys/stat.h>
93 #include <ctype.h>
94 #include <signal.h>
95#else
96 #include <stdio.h>
97 #include <string.h>
98 #include <stdlib.h>
99 #include <unistd.h>
100 #include <fcntl.h>
101 #include <sys/types.h>
102 #include <sys/stat.h>
103 #include <netinet/in.h>
104 #include <rpc/rpc.h>
105 #include <sys/socket.h>
106 #include <sys/un.h>
107 #include <sys/times.h>
108 #include <sys/param.h>
109 #include <sys/time.h>
110 #include <sys/ioctl.h>
111 #include <ctype.h>
112 #include <arpa/inet.h>
113 #include <netdb.h>
114 #include <pwd.h>
115 #include <signal.h>
116 #include <grp.h>
117 #include <sys/file.h>
118 //#include <sys/prctl.h>
119
120 #ifdef NEED_SCHEDCTL_AND_LOCK
121 #include <sys/schedctl.h>
122 #include <sys/lock.h>
123 #endif
124#endif
125
126
127char *htm_error_string;
128typedef int Boolean;
129typedef void *OBJ;
130
131typedef struct ClientAddressStruct {
132 struct sockaddr_in cl_addr;
133 int clilen;
134 int sockfd;
135} *ClientAddr;
136
137typedef unsigned long long osc_time_t;
138
139Boolean ShowBytes = FALSE;
140Boolean Silent = FALSE;
141
142/* Declarations */
143#ifndef WIN32
144static int unixinitudp(int chan);
145#endif
146
147static int initudp(int chan);
148static void closeudp(int sockfd);
149Boolean ClientReply(int packetsize, void *packet, int socketfd,
150 void *clientaddresspointer, int clientaddressbufferlength);
151void sgi_CleanExit(void);
152Boolean sgi_HaveToQuit(void);
153int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy);
154static void catch_sigint();
155static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ;
156char *DataAfterAlignedString(char *string, char *boundary) ;
157Boolean IsNiceString(char *string, char *boundary) ;
158void complain(char *s, ...);
159
160#define MAXMESG 32768
161static char mbuf[MAXMESG];
162
163/* ----------------------------- dumpOSC ------------------------- */
164
165#define MAXOUTAT 50
166
167static t_class *dumpOSC_class;
168
169typedef struct _dumpOSC
170{
171 t_object x_obj;
172 t_outlet *x_msgout;
173 t_outlet *x_connectout;
174 t_atom x_outat[MAXOUTAT];
175 int x_outatc;
176 t_binbuf *x_b;
177 int x_connectsocket;
178 int x_nconnections;
179 int x_udp;
180 struct sockaddr_in x_server;
181 int x_clilen;
182} t_dumpOSC;
183
184void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr);
185Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd);
186static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr);
187static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n);
188static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma);
189
190static void dumpOSC_read(t_dumpOSC *x, int sockfd) {
191 int clilen = x->x_clilen;
192 int n;
193 struct ClientAddressStruct ras;
194 ClientAddr ra = &ras;
195
196 //catchupflag= FALSE;
197
198/* if (ShowBytes) { */
199/* int i; */
200/* printf("%d byte message:\n", n); */
201/* for (i = 0; i < n; ++i) { */
202/* printf(" %x (%c)\t", m[i], m[i]); */
203/* if (i%4 == 3) printf("\n"); */
204/* } */
205/* printf("\n"); */
206/* } */
207
208 // return catchupflag;
209 //struct sockaddr_in x->x_server;
210 //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
211 // while((
212
213 #ifdef WIN32
214 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (SOCKADDR*)&x->x_server, &clilen)) >0)
215 #else
216 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (struct sockaddr *)&x->x_server, &clilen)) >0)
217 #endif
218 {
219 //int r;
220 ras.cl_addr = *((struct sockaddr_in *) &x->x_server);
221 ras.clilen = x->x_clilen;
222 ras.sockfd = x->x_connectsocket;
223
224 #ifdef DEBUG
225 printf("dumpOSC_read: received UDP packet of length %d\n", n);
226 #endif
227
228 if(!dumpOSC_SendReply(mbuf, n, &x->x_server, clilen, sockfd))
229 {
230 dumpOSC_ParsePacket(x, mbuf, n, ra);
231 }
232 //r = Synthmessage(mbuf, n, &x->x_server, clilen, sockfd);
233 //post ("%d", r);
234 //outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
235 // emsg-msg-1, at + msg + 1);
236 // outlet_list(x->x_msgout, 0, n, mbuf);
237 //if( sgi_HaveToQuit()) goto out;
238 //if(r>0) goto back;
239 //clilen = maxclilen;
240 }
241}
242
243static void *dumpOSC_new(t_symbol *compatflag,
244 t_floatarg fportno) {
245 t_dumpOSC *x;
246 struct sockaddr_in server;
247 int clilen=sizeof(server);
248 int sockfd;
249 int portno=fportno;
250 int udp = 1;
251
252 //x->x_b = binbuf_new();
253 //x->x_outat = binbuf_getvec(x->x_b);
254
255 //{{raf}} pointer not valid yet...moving this down
256 //x->x_outatc = 0; {{raf}}
257
258 /* create a socket */
259 if ((sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0)) == -1)
260 {
261 sys_sockerror("socket");
262 return (0);
263 }
264
265 server.sin_family = AF_INET;
266 server.sin_addr.s_addr = INADDR_ANY;
267 /* assign server port number */
268 server.sin_port = htons((u_short)portno);
269 /* name the socket */
270 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
271 {
272 sys_sockerror("bind");
273 sys_closesocket(sockfd);
274 return (0);
275 }
276
277 x = (t_dumpOSC *)pd_new(dumpOSC_class);
278 x->x_outatc = 0; // {{raf}} now pointer is valid (less invalid)
279
280 x->x_msgout = outlet_new(&x->x_obj, &s_anything);
281
282 // if (udp) /* datagram protocol */
283 {
284
285 sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_read, x);
286 x->x_connectout = 0;
287 }
288 // else /* streaming protocol */
289 /* { */
290 /* if (listen(sockfd, 5) < 0) */
291 /* { */
292 /* sys_sockerror("listen"); */
293 /* sys_closesocket(sockfd); */
294 /* sockfd = -1; */
295 /* } */
296 /* else */
297 /* { */
298 /* sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
299 /* x->x_connectout = outlet_new(&x->x_obj, &s_float); */
300 /* } */
301 /* } */
302
303 x->x_connectsocket = sockfd;
304 x->x_server = server;
305 x->x_clilen = clilen;
306 x->x_nconnections = 0;
307 x->x_udp = udp;
308
309 return (x);
310}
311
312static void dumpOSC_free(t_dumpOSC *x)
313{
314 /* LATER make me clean up open connections */
315 if (x->x_connectsocket >= 0)
316 {
317 sys_rmpollfn(x->x_connectsocket);
318 sys_closesocket(x->x_connectsocket);
319 }
320}
321
322#ifdef WIN32
323OSC_API void dumpOSC_setup(void)
324#else
325void dumpOSC_setup(void)
326#endif
327{
328 dumpOSC_class = class_new(gensym("dumpOSC"),
329 (t_newmethod)dumpOSC_new, (t_method)dumpOSC_free,
330 sizeof(t_dumpOSC), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
331 A_DEFSYM, 0);
332 class_sethelpsymbol(dumpOSC_class, gensym("dumpOSC-help.pd"));
333}
334
335
336#ifndef WIN32
337 #define UNIXDG_PATH "/tmp/htm"
338 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
339 static int unixinitudp(int chan)
340 {
341 struct sockaddr_un serv_addr;
342 int sockfd;
343
344 if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
345 return sockfd;
346
347 bzero((char *)&serv_addr, sizeof(serv_addr));
348 serv_addr.sun_family = AF_UNIX;
349 strcpy(serv_addr.sun_path, UNIXDG_PATH);
350 sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan);
351 unlink(serv_addr.sun_path);
352 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0)
353 {
354 perror("unable to bind\n");
355 return -1;
356 }
357
358 fcntl(sockfd, F_SETFL, FNDELAY);
359 return sockfd;
360 }
361#endif // #ifndef WIN32
362
363
364
365static int initudp(int chan)
366{
367
368#ifdef WIN32
369 struct sockaddr_in serv_addr;
370 unsigned int sockfd;
371 ULONG nonBlocking = (ULONG) TRUE;
372
373 if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET ) {
374 ZeroMemory((char *)&serv_addr, sizeof(serv_addr));
375 serv_addr.sin_family = AF_INET;
376 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
377 serv_addr.sin_port = htons(chan);
378 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) {
379 // set for non-blocking mode
380 if(ioctlsocket(sockfd, FIONBIO, &nonBlocking) == SOCKET_ERROR) {
381 perror("unable to set non-blocking\n");
382 return -1;
383 }
384 }
385 else { perror("unable to bind\n"); return -1; }
386 }
387 return (sockfd == INVALID_SOCKET ? -1 : (int)sockfd);
388#else
389 struct sockaddr_in serv_addr;
390 int sockfd;
391
392 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
393 return sockfd;
394
395 bzero((char *)&serv_addr, sizeof(serv_addr));
396 serv_addr.sin_family = AF_INET;
397 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
398 serv_addr.sin_port = htons(chan);
399
400 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
401 {
402 perror("unable to bind\n");
403 return -1;
404 }
405
406 fcntl(sockfd, F_SETFL, FNDELAY);
407 return sockfd;
408#endif
409}
410
411
412
413
414
415
416
417
418static void closeudp(int sockfd) {
419 #ifdef WIN32
420 closesocket(sockfd);
421 #else
422 close(sockfd);
423 #endif
424}
425
426static Boolean catchupflag=FALSE;
427Boolean ClientReply(int packetsize, void *packet, int socketfd,
428 void *clientaddresspointer, int clientaddressbufferlength)
429{
430 if(!clientaddresspointer) return FALSE;
431 catchupflag= TRUE;
432 return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength);
433}
434
435static Boolean exitflag= FALSE;
436void sgi_CleanExit(void) {
437 exitflag = TRUE;
438}
439
440Boolean sgi_HaveToQuit(void) {
441 return exitflag;
442}
443
444
445/* file descriptor poll table */
446static int npolldevs =0;
447typedef struct polldev
448{
449 int fd;
450 void (*callbackfunction)(int , void *);
451 void *dummy;
452} polldev;
453#define TABMAX 8
454static polldev polldevs[TABMAX];
455
456
457/* Register a device (referred to by a file descriptor that the caller
458 should have already successfully obtained from a system call) to be
459 polled as real-time constraints allowed.
460
461 When a select(2) call indicates activity on the file descriptor, the
462 callback function is called with the file descripter as first
463 argument and the given dummy argument (presumably a pointer to the
464 instance variables associated with the device).
465*/
466int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy)
467{
468 if(npolldevs<TABMAX)
469 {
470 polldevs[npolldevs].fd = fd;
471 polldevs[npolldevs].callbackfunction = callbackfunction;
472 polldevs[npolldevs].dummy = dummy;
473 }
474 else return -1;
475 return npolldevs++;
476}
477
478static int caught_sigint;
479
480static void catch_sigint() {
481 caught_sigint = 1;
482}
483static int sockfd, usockfd;
484
485
486void PrintClientAddr(ClientAddr CA) {
487 unsigned long addr = CA->cl_addr.sin_addr.s_addr;
488 printf("Client address %p:\n", CA);
489 printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
490 printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
491 CA->cl_addr.sin_port);
492 printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
493
494 printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
495 CA->cl_addr.sin_zero[0],
496 CA->cl_addr.sin_zero[1],
497 CA->cl_addr.sin_zero[2],
498 CA->cl_addr.sin_zero[3],
499 CA->cl_addr.sin_zero[4],
500 CA->cl_addr.sin_zero[5],
501 CA->cl_addr.sin_zero[6],
502 CA->cl_addr.sin_zero[7]);
503
504 printf("\n");
505}
506
507//*******************
508
509void WriteTime(char* dst, osc_time_t osctime)
510{
511 *(int32_t*)dst = htonl((int32_t)(osctime >> 32));
512 *(int32_t*)(dst+4) = htonl((int32_t)osctime);
513}
514
515void WriteMode(char* dst)
516{
517 *(int32_t*)dst = htonl(0);
518}
519
520osc_time_t ReadTime(const char* src)
521{
522 osc_time_t osctime = ntohl(*(int32_t*)src);
523 return (osctime << 32) + ntohl(*(int32_t*)(src+4));
524}
525
526double TimeToSeconds(osc_time_t osctime)
527{
528 return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */;
529}
530
531int timeRound(double x)
532{
533 return x >= 0.0 ? x+0.5 : x-0.5;
534}
535/*
536void WriteLogicalTime(char* dst)
537{
538 static double startTime = -1.0;
539 double sTime;
540
541 // Initialisierung der Startzeit.
542 // Knnte effizienter (ohne 'if') auch irgendwo vorher passieren.
543 // Knnte wahrscheinlich auch 0.0 sein.
544 if (startTime < 0.0) {
545 startTime = clock_getlogicaltime();
546 }
547
548 sTime = clock_gettimesince(startTime) * 0.001;
549 *(int32_t*)dst = hton'K l((int32_t)sTime);
550 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296.0 * sTime));
551}
552*/
553
554void WriteLogicalTime(char* dst)
555{
556 double sTime = clock_gettimesince(19230720) / 1000.0;
557 double tau = sTime - timeRound(sTime);
558
559 //fprintf(stderr, "sSec = %f tau = %f\n", sTime, tau);
560
561 *(int32_t*)dst = htonl((int32_t)(sTime));
562 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296 * tau));
563}
564
565Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd)
566{
567 if((n == 24) && (strcmp(buf, "#time") == 0))
568 {
569 osc_time_t t0, t1, t2;
570 double dt0, dt1, dt2;
571
572 WriteMode(buf+6);
573
574 t0 = ReadTime(buf+8);
575
576 WriteLogicalTime(buf+16);
577 t1 = ReadTime(buf+16); // reverse
578 dt0 = TimeToSeconds(t0); // client time
579 dt1 = TimeToSeconds(t1); // server time
580
581 // fprintf(stderr, "%f\t%f\t%f\n", dt0, dt1, dt0 - dt1);
582
583 sendto(fd, buf, n, 0, (struct sockaddr *)clientDesc, clientDescLenght);
584 return TRUE;
585 }
586 else
587 {
588 return FALSE;
589 }
590}
591
592//**********************
593
594void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr) {
595 // t_dumpOSC *x;
596 int size, messageLen, i;
597 char *messageName;
598 char *args;
599
600 //#ifdef PRINTADDRS
601 #ifdef DEBUG
602 //PrintClientAddr(returnAddr);
603 #endif
604
605
606 if ((n%4) != 0) {
607 complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", n);
608 return;
609 }
610
611 if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
612 /* This is a bundle message. */
613 #ifdef DEBUG
614 printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
615 #endif
616
617 if (n < 16) {
618 complain("Bundle message too small (%d bytes) for time tag", n);
619 return;
620 }
621
622 /* Print the time tag */
623 #ifdef DEBUG
624 printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), ntohl(*((unsigned long *)(buf+12))));
625 #endif
626
627 /* Note: if we wanted to actually use the time tag as a little-endian
628 64-bit int, we'd have to word-swap the two 32-bit halves of it */
629
630 i = 16; /* Skip "#group\0" and time tag */
631
632 while(i<n) {
633 size = ntohl(*((int *) (buf + i)));
634 if ((size % 4) != 0) {
635 complain("Bad size count %d in bundle (not a multiple of 4)", size);
636 return;
637 }
638 if ((size + i + 4) > n) {
639 complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
640 size, n-i-4);
641 return;
642 }
643
644 /* Recursively handle element of bundle */
645 dumpOSC_ParsePacket(x, buf+i+4, size, returnAddr);
646 i += 4 + size;
647 }
648
649 if (i != n) {
650 complain("This can't happen");
651 }
652 #ifdef DEBUG
653 printf("]\n");
654 #endif
655
656 }
657 else if ((n == 24) && (strcmp(buf, "#time") == 0))
658 {
659 complain("Time message: %s\n :).\n", htm_error_string);
660 return;
661
662 }
663 else
664 {
665 /* This is not a bundle message */
666
667 messageName = buf;
668 args = DataAfterAlignedString(messageName, buf+n);
669 if (args == 0) {
670 complain("Bad message name string: %s\nDropping entire message.\n",
671 htm_error_string);
672 return;
673 }
674 messageLen = args-messageName;
675 dumpOSC_Smessage(x, messageName, (void *)args, n-messageLen, returnAddr);
676 }
677}
678
679#define SMALLEST_POSITIVE_FLOAT 0.000001f
680
681static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr) {
682 char *chars = v;
683 t_atom at;
684 //t_atom myargv[50];
685
686 int myargc = x->x_outatc;
687 t_atom* mya = x->x_outat;
688 int myi;
689
690#ifdef DEBUG
691 printf("%s ", address);
692#endif
693
694 // ztoln+cvt from envgen.c, ggee-0.18 ..
695 // outlet_anything's 'symbol' gets set to address
696 // so we dont need to append address to the atomlist
697 /*
698 SETSYMBOL(mya,gensym(address));myargc++;
699 x->x_outatc = myargc;
700 */
701
702 if (n != 0) {
703 if (chars[0] == ',') {
704 if (chars[1] != ',') {
705 /* This message begins with a type-tag string */
706 dumpOSC_PrintTypeTaggedArgs(x, v, n);
707 } else {
708 /* Double comma means an escaped real comma, not a type string */
709 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 1);
710 }
711 } else {
712 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
713 }
714 }
715
716 outlet_anything(x->x_msgout,gensym(address),x->x_outatc,(t_atom*)&x->x_outat);
717 x->x_outatc = 0;
718#ifdef DEBUG
719 printf("\n");
720#endif
721 fflush(stdout); /* Added for Sami 5/21/98 */
722}
723
724static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n) {
725 char *typeTags, *thisType;
726 char *p;
727
728 int myargc = x->x_outatc;
729 t_atom* mya = x->x_outat;
730 int myi;
731
732 typeTags = v;
733
734 if (!IsNiceString(typeTags, typeTags+n)) {
735 /* No null-termination, so maybe it wasn't a type tag
736 string after all */
737 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
738 return;
739 }
740
741 p = DataAfterAlignedString(typeTags, typeTags+n);
742
743
744 for (thisType = typeTags + 1; *thisType != 0; ++thisType) {
745 switch (*thisType) {
746 case 'i': case 'r': case 'm': case 'c':
747#ifdef DEBUG
748 //post("integer: %d", ntohl(*((int *) p)));
749#endif
750 /* Martin Peach fix for negative floats:
751 * was: SETFLOAT(mya+myargc,ntohl(*((int *) p)));
752 * now is:
753 */
754 SETFLOAT(mya+myargc,(signed)ntohl(*((int *) p)));
755 myargc++;
756
757 p += 4;
758 break;
759
760 case 'f': {
761 int i = ntohl(*((int *) p));
762 float *floatp = ((float *) (&i));
763#ifdef DEBUG
764 post("float: %f", *floatp);
765#endif
766 SETFLOAT(mya+myargc,*floatp);
767 myargc++;
768
769 p += 4;
770 }
771 break;
772
773 case 'h': case 't':
774#ifdef DEBUG
775 printf("[A 64-bit int] ");
776#endif
777 post("[A 64-bit int] not implemented");
778
779 p += 8;
780 break;
781
782 case 'd':
783#ifdef DEBUG
784 printf("[A 64-bit float] ");
785#endif
786 post("[A 64-bit float] not implemented");
787
788 p += 8;
789 break;
790
791 case 's': case 'S':
792 if (!IsNiceString(p, typeTags+n)) {
793 post("Type tag said this arg is a string but it's not!\n");
794 return;
795 } else {
796#ifdef DEBUG
797 post("string: \"%s\"", p);
798#endif
799 SETSYMBOL(mya+myargc,gensym(p));
800 myargc++;
801 //outlet_list(x->x_msgout, 0,sizeof(p), p);
802 //outlet_anything(x->x_msgout, 0, sizeof(p), p);
803 p = DataAfterAlignedString(p, typeTags+n);
804 // append to output vector ..
805 }
806 break;
807
808 case 'T':
809#ifdef DEBUG
810 printf("[True] ");
811#endif
812 SETFLOAT(mya+myargc,1.);
813 myargc++;
814 break;
815 case 'F':
816#ifdef DEBUG
817 printf("[False] ");
818#endif
819 SETFLOAT(mya+myargc,0.);
820 myargc++;
821 break;
822 case 'N':
823#ifdef DEBUG
824 printf("[Nil]");
825#endif
826 post("sendOSC: [Nil] not implemented");
827 break;
828 case 'I':
829#ifdef DEBUG
830 printf("[Infinitum]");
831#endif
832 post("sendOSC: [Infinitum] not implemented");
833 break;
834
835 default:
836 post("sendOSC: [Unrecognized type tag %c]", *thisType);
837 // return;
838 }
839 }
840 x->x_outatc = myargc;
841}
842
843static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma) {
844 int i, thisi;
845 float thisf;
846 int *ints;
847 char *chars;
848 char *string, *nextString;
849
850 int myargc= x->x_outatc;
851 t_atom* mya = x->x_outat;
852 int myi;
853
854
855 /* Go through the arguments 32 bits at a time */
856 ints = v;
857 chars = v;
858
859 for (i = 0; i<n/4; ) {
860 string = &chars[i*4];
861 thisi = ntohl(ints[i]);
862 /* Reinterpret the (potentially byte-reversed) thisi as a float */
863 thisf = *(((float *) (&thisi)));
864
865 if (thisi >= -1000 && thisi <= 1000000) {
866#ifdef DEBUG
867 printf("%d ", thisi);
868#endif
869 // append to output vector ..
870 SETFLOAT(mya+myargc,(t_float) (thisi));
871 myargc++;
872 // outlet_float(x->x_msgout, thisi);
873 i++;
874 } else if (thisf >= -1000.f && thisf <= 1000000.f &&
875 (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
876#ifdef DEBUG
877 printf("%f ", thisf);
878#endif
879 // append to output vector ..
880 SETFLOAT(mya+myargc,thisf);
881 myargc++;
882 //outlet_float(x->x_msgout, thisf);
883 i++;
884 } else if (IsNiceString(string, chars+n)) {
885 nextString = DataAfterAlignedString(string, chars+n);
886#ifdef DEBUG
887 printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
888#endif
889 // append to output vector ..
890 SETSYMBOL(mya+myargc,gensym(string));
891 myargc++;
892 //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
893 i += (nextString-string) / 4;
894 } else {
895 // unhandled .. ;)
896#ifdef DEBUG
897 printf("0x%x xx", ints[i]);
898#endif
899 i++;
900 }
901 x->x_outatc = myargc;
902 }
903}
904
905
906#define STRING_ALIGN_PAD 4
907
908char *DataAfterAlignedString(char *string, char *boundary)
909{
910 /* The argument is a block of data beginning with a string. The
911 string has (presumably) been padded with extra null characters
912 so that the overall length is a multiple of STRING_ALIGN_PAD
913 bytes. Return a pointer to the next byte after the null
914 byte(s). The boundary argument points to the character after
915 the last valid character in the buffer---if the string hasn't
916 ended by there, something's wrong.
917
918 If the data looks wrong, return 0, and set htm_error_string */
919
920 int i;
921
922 if ((boundary - string) %4 != 0) {
923 fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n");
924 return 0;
925 }
926
927 for (i = 0; string[i] != '\0'; i++) {
928 if (string + i >= boundary) {
929 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
930 return 0;
931 }
932 }
933
934 /* Now string[i] is the first null character */
935 i++;
936
937 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
938 if (string + i >= boundary) {
939 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
940 return 0;
941 }
942 if (string[i] != '\0') {
943 htm_error_string = "DataAfterAlignedString: Incorrectly padded string.";
944 return 0;
945 }
946 }
947
948 return string+i;
949}
950
951Boolean IsNiceString(char *string, char *boundary)
952{
953 /* Arguments same as DataAfterAlignedString(). Is the given "string"
954 really a string? I.e., is it a sequence of isprint() characters
955 terminated with 1-4 null characters to align on a 4-byte boundary? */
956
957 int i;
958
959 if ((boundary - string) %4 != 0) {
960 fprintf(stderr, "Internal error: IsNiceString: bad boundary\n");
961 return 0;
962 }
963
964 for (i = 0; string[i] != '\0'; i++) {
965 if (!isprint(string[i])) return FALSE;
966 if (string + i >= boundary) return FALSE;
967 }
968
969 /* If we made it this far, it's a null-terminated sequence of printing characters
970 in the given boundary. Now we just make sure it's null padded... */
971
972 /* Now string[i] is the first null character */
973 i++;
974 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
975 if (string[i] != '\0') return FALSE;
976 }
977
978 return TRUE;
979}
980
981
982
983
984
985
986
987
988
989#include <stdarg.h>
990void complain(char *s, ...) {
991 va_list ap;
992 va_start(ap, s);
993 fprintf(stderr, "*** ERROR: ");
994 vfprintf(stderr, s, ap);
995 fprintf(stderr, "\n");
996 va_end(ap);
997}
998
999#endif /* __sgi or LINUX or WIN32 */
1000/*
1001Written by Matt Wright and Adrian Freed, The Center for New Music and
1002Audio Technologies, University of California, Berkeley. Copyright (c)
10031992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of
1004California (Regents).
1005
1006Permission to use, copy, modify, distribute, and distribute modified versions
1007of this software and its documentation without fee and without a signed
1008licensing agreement, is hereby granted, provided that the above copyright
1009notice, this paragraph and the following two paragraphs appear in all copies,
1010modifications, and distributions.
1011
1012IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
1013SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
1014OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
1015BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1016
1017REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1018THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1019PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
1020HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
1021MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1022
1023
1024The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
1025*/
1026
1027
1028 /*
1029
1030 dumpOSC.c
1031 server that displays OpenSoundControl messages sent to it
1032 for debugging client udp and UNIX protocol
1033
1034 by Matt Wright, 6/3/97
1035 modified from dumpSC.c, by Matt Wright and Adrian Freed
1036
1037 version 0.2: Added "-silent" option a.k.a. "-quiet"
1038
1039 version 0.3: Incorporated patches from Nicola Bernardini to make
1040 things Linux-friendly. Also added ntohl() in the right places
1041 to support little-endian architectures.
1042
1043
1044
1045 compile:
1046 cc -o dumpOSC dumpOSC.c
1047
1048 to-do:
1049
1050 More robustness in saying exactly what's wrong with ill-formed
1051 messages. (If they don't make sense, show exactly what was
1052 received.)
1053
1054 Time-based features: print time-received for each packet
1055
1056 Clean up to separate OSC parsing code from socket/select stuff
1057
1058 pd: branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/dumpOSC/dumpOSC.c
1059 -------------
1060 -- added pd functions
1061 -- socket is made differently than original via pd mechanisms
1062 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
1063 -- the OSX changes from cnmat didnt make it here yet but this compiles
1064 on OSX anyway.
1065
1066*/
1067
1068#if HAVE_CONFIG_H
1069#include <config.h>
1070#endif
1071
1072#include "m_pd.h"
1073//#include "m_imp.h"
1074#include "s_stuff.h"
1075
1076/* declarations */
1077
1078// typedef void (*t_fdpollfn)(void *ptr, int fd);
1079void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
1080
1081
1082#if defined(__sgi) || defined(__linux) || defined(WIN32) || defined(__APPLE__)
1083
1084#ifdef WIN32
1085 #include "OSC-common.h"
1086 #include <winsock2.h>
1087 #include <string.h>
1088 #include <stdlib.h>
1089 #include <fcntl.h>
1090 #include <sys/types.h>
1091 #include <sys/stat.h>
1092 #include <ctype.h>
1093 #include <signal.h>
1094#else
1095 #include <stdio.h>
1096 #include <string.h>
1097 #include <stdlib.h>
1098 #include <unistd.h>
1099 #include <fcntl.h>
1100 #include <sys/types.h>
1101 #include <sys/stat.h>
1102 #include <netinet/in.h>
1103 #include <rpc/rpc.h>
1104 #include <sys/socket.h>
1105 #include <sys/un.h>
1106 #include <sys/times.h>
1107 #include <sys/param.h>
1108 #include <sys/time.h>
1109 #include <sys/ioctl.h>
1110 #include <ctype.h>
1111 #include <arpa/inet.h>
1112 #include <netdb.h>
1113 #include <pwd.h>
1114 #include <signal.h>
1115 #include <grp.h>
1116 #include <sys/file.h>
1117 //#include <sys/prctl.h>
1118
1119 #ifdef NEED_SCHEDCTL_AND_LOCK
1120 #include <sys/schedctl.h>
1121 #include <sys/lock.h>
1122 #endif
1123#endif
1124
1125
1126char *htm_error_string;
1127typedef int Boolean;
1128typedef void *OBJ;
1129
1130typedef struct ClientAddressStruct {
1131 struct sockaddr_in cl_addr;
1132 int clilen;
1133 int sockfd;
1134} *ClientAddr;
1135
1136typedef unsigned long long osc_time_t;
1137
1138Boolean ShowBytes = FALSE;
1139Boolean Silent = FALSE;
1140
1141/* Declarations */
1142#ifndef WIN32
1143static int unixinitudp(int chan);
1144#endif
1145
1146static int initudp(int chan);
1147static void closeudp(int sockfd);
1148Boolean ClientReply(int packetsize, void *packet, int socketfd,
1149 void *clientaddresspointer, int clientaddressbufferlength);
1150void sgi_CleanExit(void);
1151Boolean sgi_HaveToQuit(void);
1152int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy);
1153static void catch_sigint();
1154static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ;
1155char *DataAfterAlignedString(char *string, char *boundary) ;
1156Boolean IsNiceString(char *string, char *boundary) ;
1157void complain(char *s, ...);
1158
1159#define MAXMESG 32768
1160static char mbuf[MAXMESG];
1161
1162/* ----------------------------- dumpOSC ------------------------- */
1163
1164#define MAXOUTAT 50
1165
1166static t_class *dumpOSC_class;
1167
1168typedef struct _dumpOSC
1169{
1170 t_object x_obj;
1171 t_outlet *x_msgout;
1172 t_outlet *x_connectout;
1173 t_atom x_outat[MAXOUTAT];
1174 int x_outatc;
1175 t_binbuf *x_b;
1176 int x_connectsocket;
1177 int x_nconnections;
1178 int x_udp;
1179 struct sockaddr_in x_server;
1180 int x_clilen;
1181} t_dumpOSC;
1182
1183void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr);
1184Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd);
1185static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr);
1186static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n);
1187static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma);
1188
1189static void dumpOSC_read(t_dumpOSC *x, int sockfd) {
1190 int clilen = x->x_clilen;
1191 int n;
1192 struct ClientAddressStruct ras;
1193 ClientAddr ra = &ras;
1194
1195 //catchupflag= FALSE;
1196
1197/* if (ShowBytes) { */
1198/* int i; */
1199/* printf("%d byte message:\n", n); */
1200/* for (i = 0; i < n; ++i) { */
1201/* printf(" %x (%c)\t", m[i], m[i]); */
1202/* if (i%4 == 3) printf("\n"); */
1203/* } */
1204/* printf("\n"); */
1205/* } */
1206
1207 // return catchupflag;
1208 //struct sockaddr_in x->x_server;
1209 //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
1210 // while((
1211
1212 #ifdef WIN32
1213 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (SOCKADDR*)&x->x_server, &clilen)) >0)
1214 #else
1215 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (struct sockaddr *)&x->x_server, &clilen)) >0)
1216 #endif
1217 {
1218 //int r;
1219 ras.cl_addr = *((struct sockaddr_in *) &x->x_server);
1220 ras.clilen = x->x_clilen;
1221 ras.sockfd = x->x_connectsocket;
1222
1223 #ifdef DEBUG
1224 printf("dumpOSC_read: received UDP packet of length %d\n", n);
1225 #endif
1226
1227 if(!dumpOSC_SendReply(mbuf, n, &x->x_server, clilen, sockfd))
1228 {
1229 dumpOSC_ParsePacket(x, mbuf, n, ra);
1230 }
1231 //r = Synthmessage(mbuf, n, &x->x_server, clilen, sockfd);
1232 //post ("%d", r);
1233 //outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
1234 // emsg-msg-1, at + msg + 1);
1235 // outlet_list(x->x_msgout, 0, n, mbuf);
1236 //if( sgi_HaveToQuit()) goto out;
1237 //if(r>0) goto back;
1238 //clilen = maxclilen;
1239 }
1240}
1241
1242static void *dumpOSC_new(t_symbol *compatflag,
1243 t_floatarg fportno) {
1244 t_dumpOSC *x;
1245 struct sockaddr_in server;
1246 int clilen=sizeof(server);
1247 int sockfd;
1248 int portno=fportno;
1249 int udp = 1;
1250
1251 //x->x_b = binbuf_new();
1252 //x->x_outat = binbuf_getvec(x->x_b);
1253
1254 //{{raf}} pointer not valid yet...moving this down
1255 //x->x_outatc = 0; {{raf}}
1256
1257 /* create a socket */
1258 if ((sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0)) == -1)
1259 {
1260 sys_sockerror("socket");
1261 return (0);
1262 }
1263
1264 server.sin_family = AF_INET;
1265 server.sin_addr.s_addr = INADDR_ANY;
1266 /* assign server port number */
1267 server.sin_port = htons((u_short)portno);
1268 /* name the socket */
1269 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
1270 {
1271 sys_sockerror("bind");
1272 sys_closesocket(sockfd);
1273 return (0);
1274 }
1275
1276 x = (t_dumpOSC *)pd_new(dumpOSC_class);
1277 x->x_outatc = 0; // {{raf}} now pointer is valid (less invalid)
1278
1279 x->x_msgout = outlet_new(&x->x_obj, &s_anything);
1280
1281 // if (udp) /* datagram protocol */
1282 {
1283
1284 sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_read, x);
1285 x->x_connectout = 0;
1286 }
1287 // else /* streaming protocol */
1288 /* { */
1289 /* if (listen(sockfd, 5) < 0) */
1290 /* { */
1291 /* sys_sockerror("listen"); */
1292 /* sys_closesocket(sockfd); */
1293 /* sockfd = -1; */
1294 /* } */
1295 /* else */
1296 /* { */
1297 /* sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
1298 /* x->x_connectout = outlet_new(&x->x_obj, &s_float); */
1299 /* } */
1300 /* } */
1301
1302 x->x_connectsocket = sockfd;
1303 x->x_server = server;
1304 x->x_clilen = clilen;
1305 x->x_nconnections = 0;
1306 x->x_udp = udp;
1307
1308 return (x);
1309}
1310
1311static void dumpOSC_free(t_dumpOSC *x)
1312{
1313 /* LATER make me clean up open connections */
1314 if (x->x_connectsocket >= 0)
1315 {
1316 sys_rmpollfn(x->x_connectsocket);
1317 sys_closesocket(x->x_connectsocket);
1318 }
1319}
1320
1321#ifdef WIN32
1322OSC_API void dumpOSC_setup(void)
1323#else
1324void dumpOSC_setup(void)
1325#endif
1326{
1327 dumpOSC_class = class_new(gensym("dumpOSC"),
1328 (t_newmethod)dumpOSC_new, (t_method)dumpOSC_free,
1329 sizeof(t_dumpOSC), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
1330 A_DEFSYM, 0);
1331 class_sethelpsymbol(dumpOSC_class, gensym("dumpOSC-help.pd"));
1332}
1333
1334
1335#ifndef WIN32
1336 #define UNIXDG_PATH "/tmp/htm"
1337 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
1338 static int unixinitudp(int chan)
1339 {
1340 struct sockaddr_un serv_addr;
1341 int sockfd;
1342
1343 if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
1344 return sockfd;
1345
1346 bzero((char *)&serv_addr, sizeof(serv_addr));
1347 serv_addr.sun_family = AF_UNIX;
1348 strcpy(serv_addr.sun_path, UNIXDG_PATH);
1349 sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan);
1350 unlink(serv_addr.sun_path);
1351 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0)
1352 {
1353 perror("unable to bind\n");
1354 return -1;
1355 }
1356
1357 fcntl(sockfd, F_SETFL, FNDELAY);
1358 return sockfd;
1359 }
1360#endif // #ifndef WIN32
1361
1362
1363
1364static int initudp(int chan)
1365{
1366
1367#ifdef WIN32
1368 struct sockaddr_in serv_addr;
1369 unsigned int sockfd;
1370 ULONG nonBlocking = (ULONG) TRUE;
1371
1372 if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET ) {
1373 ZeroMemory((char *)&serv_addr, sizeof(serv_addr));
1374 serv_addr.sin_family = AF_INET;
1375 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1376 serv_addr.sin_port = htons(chan);
1377 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) {
1378 // set for non-blocking mode
1379 if(ioctlsocket(sockfd, FIONBIO, &nonBlocking) == SOCKET_ERROR) {
1380 perror("unable to set non-blocking\n");
1381 return -1;
1382 }
1383 }
1384 else { perror("unable to bind\n"); return -1; }
1385 }
1386 return (sockfd == INVALID_SOCKET ? -1 : (int)sockfd);
1387#else
1388 struct sockaddr_in serv_addr;
1389 int sockfd;
1390
1391 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1392 return sockfd;
1393
1394 bzero((char *)&serv_addr, sizeof(serv_addr));
1395 serv_addr.sin_family = AF_INET;
1396 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1397 serv_addr.sin_port = htons(chan);
1398
1399 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
1400 {
1401 perror("unable to bind\n");
1402 return -1;
1403 }
1404
1405 fcntl(sockfd, F_SETFL, FNDELAY);
1406 return sockfd;
1407#endif
1408}
1409
1410
1411
1412
1413
1414
1415
1416
1417static void closeudp(int sockfd) {
1418 #ifdef WIN32
1419 closesocket(sockfd);
1420 #else
1421 close(sockfd);
1422 #endif
1423}
1424
1425static Boolean catchupflag=FALSE;
1426Boolean ClientReply(int packetsize, void *packet, int socketfd,
1427 void *clientaddresspointer, int clientaddressbufferlength)
1428{
1429 if(!clientaddresspointer) return FALSE;
1430 catchupflag= TRUE;
1431 return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength);
1432}
1433
1434static Boolean exitflag= FALSE;
1435void sgi_CleanExit(void) {
1436 exitflag = TRUE;
1437}
1438
1439Boolean sgi_HaveToQuit(void) {
1440 return exitflag;
1441}
1442
1443
1444/* file descriptor poll table */
1445static int npolldevs =0;
1446typedef struct polldev
1447{
1448 int fd;
1449 void (*callbackfunction)(int , void *);
1450 void *dummy;
1451} polldev;
1452#define TABMAX 8
1453static polldev polldevs[TABMAX];
1454
1455
1456/* Register a device (referred to by a file descriptor that the caller
1457 should have already successfully obtained from a system call) to be
1458 polled as real-time constraints allowed.
1459
1460 When a select(2) call indicates activity on the file descriptor, the
1461 callback function is called with the file descripter as first
1462 argument and the given dummy argument (presumably a pointer to the
1463 instance variables associated with the device).
1464*/
1465int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy)
1466{
1467 if(npolldevs<TABMAX)
1468 {
1469 polldevs[npolldevs].fd = fd;
1470 polldevs[npolldevs].callbackfunction = callbackfunction;
1471 polldevs[npolldevs].dummy = dummy;
1472 }
1473 else return -1;
1474 return npolldevs++;
1475}
1476
1477static int caught_sigint;
1478
1479static void catch_sigint() {
1480 caught_sigint = 1;
1481}
1482static int sockfd, usockfd;
1483
1484
1485void PrintClientAddr(ClientAddr CA) {
1486 unsigned long addr = CA->cl_addr.sin_addr.s_addr;
1487 printf("Client address %p:\n", CA);
1488 printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
1489 printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
1490 CA->cl_addr.sin_port);
1491 printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
1492
1493 printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
1494 CA->cl_addr.sin_zero[0],
1495 CA->cl_addr.sin_zero[1],
1496 CA->cl_addr.sin_zero[2],
1497 CA->cl_addr.sin_zero[3],
1498 CA->cl_addr.sin_zero[4],
1499 CA->cl_addr.sin_zero[5],
1500 CA->cl_addr.sin_zero[6],
1501 CA->cl_addr.sin_zero[7]);
1502
1503 printf("\n");
1504}
1505
1506//*******************
1507
1508void WriteTime(char* dst, osc_time_t osctime)
1509{
1510 *(int32_t*)dst = htonl((int32_t)(osctime >> 32));
1511 *(int32_t*)(dst+4) = htonl((int32_t)osctime);
1512}
1513
1514void WriteMode(char* dst)
1515{
1516 *(int32_t*)dst = htonl(0);
1517}
1518
1519osc_time_t ReadTime(const char* src)
1520{
1521 osc_time_t osctime = ntohl(*(int32_t*)src);
1522 return (osctime << 32) + ntohl(*(int32_t*)(src+4));
1523}
1524
1525double TimeToSeconds(osc_time_t osctime)
1526{
1527 return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */;
1528}
1529
1530int timeRound(double x)
1531{
1532 return x >= 0.0 ? x+0.5 : x-0.5;
1533}
1534/*
1535void WriteLogicalTime(char* dst)
1536{
1537 static double startTime = -1.0;
1538 double sTime;
1539
1540 // Initialisierung der Startzeit.
1541 // Knnte effizienter (ohne 'if') auch irgendwo vorher passieren.
1542 // Knnte wahrscheinlich auch 0.0 sein.
1543 if (startTime < 0.0) {
1544 startTime = clock_getlogicaltime();
1545 }
1546
1547 sTime = clock_gettimesince(startTime) * 0.001;
1548 *(int32_t*)dst = hton'K l((int32_t)sTime);
1549 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296.0 * sTime));
1550}
1551*/
1552
1553void WriteLogicalTime(char* dst)
1554{
1555 double sTime = clock_gettimesince(19230720) / 1000.0;
1556 double tau = sTime - timeRound(sTime);
1557
1558 //fprintf(stderr, "sSec = %f tau = %f\n", sTime, tau);
1559
1560 *(int32_t*)dst = htonl((int32_t)(sTime));
1561 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296 * tau));
1562}
1563
1564Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd)
1565{
1566 if((n == 24) && (strcmp(buf, "#time") == 0))
1567 {
1568 osc_time_t t0, t1, t2;
1569 double dt0, dt1, dt2;
1570
1571 WriteMode(buf+6);
1572
1573 t0 = ReadTime(buf+8);
1574
1575 WriteLogicalTime(buf+16);
1576 t1 = ReadTime(buf+16); // reverse
1577 dt0 = TimeToSeconds(t0); // client time
1578 dt1 = TimeToSeconds(t1); // server time
1579
1580 // fprintf(stderr, "%f\t%f\t%f\n", dt0, dt1, dt0 - dt1);
1581
1582 sendto(fd, buf, n, 0, (struct sockaddr *)clientDesc, clientDescLenght);
1583 return TRUE;
1584 }
1585 else
1586 {
1587 return FALSE;
1588 }
1589}
1590
1591//**********************
1592
1593void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr) {
1594 // t_dumpOSC *x;
1595 int size, messageLen, i;
1596 char *messageName;
1597 char *args;
1598
1599 //#ifdef PRINTADDRS
1600 #ifdef DEBUG
1601 //PrintClientAddr(returnAddr);
1602 #endif
1603
1604
1605 if ((n%4) != 0) {
1606 complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", n);
1607 return;
1608 }
1609
1610 if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
1611 /* This is a bundle message. */
1612 #ifdef DEBUG
1613 printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
1614 #endif
1615
1616 if (n < 16) {
1617 complain("Bundle message too small (%d bytes) for time tag", n);
1618 return;
1619 }
1620
1621 /* Print the time tag */
1622 #ifdef DEBUG
1623 printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), ntohl(*((unsigned long *)(buf+12))));
1624 #endif
1625
1626 /* Note: if we wanted to actually use the time tag as a little-endian
1627 64-bit int, we'd have to word-swap the two 32-bit halves of it */
1628
1629 i = 16; /* Skip "#group\0" and time tag */
1630
1631 while(i<n) {
1632 size = ntohl(*((int *) (buf + i)));
1633 if ((size % 4) != 0) {
1634 complain("Bad size count %d in bundle (not a multiple of 4)", size);
1635 return;
1636 }
1637 if ((size + i + 4) > n) {
1638 complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
1639 size, n-i-4);
1640 return;
1641 }
1642
1643 /* Recursively handle element of bundle */
1644 dumpOSC_ParsePacket(x, buf+i+4, size, returnAddr);
1645 i += 4 + size;
1646 }
1647
1648 if (i != n) {
1649 complain("This can't happen");
1650 }
1651 #ifdef DEBUG
1652 printf("]\n");
1653 #endif
1654
1655 }
1656 else if ((n == 24) && (strcmp(buf, "#time") == 0))
1657 {
1658 complain("Time message: %s\n :).\n", htm_error_string);
1659 return;
1660
1661 }
1662 else
1663 {
1664 /* This is not a bundle message */
1665
1666 messageName = buf;
1667 args = DataAfterAlignedString(messageName, buf+n);
1668 if (args == 0) {
1669 complain("Bad message name string: %s\nDropping entire message.\n",
1670 htm_error_string);
1671 return;
1672 }
1673 messageLen = args-messageName;
1674 dumpOSC_Smessage(x, messageName, (void *)args, n-messageLen, returnAddr);
1675 }
1676}
1677
1678#define SMALLEST_POSITIVE_FLOAT 0.000001f
1679
1680static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr) {
1681 char *chars = v;
1682 t_atom at;
1683 //t_atom myargv[50];
1684
1685 int myargc = x->x_outatc;
1686 t_atom* mya = x->x_outat;
1687 int myi;
1688
1689#ifdef DEBUG
1690 printf("%s ", address);
1691#endif
1692
1693 // ztoln+cvt from envgen.c, ggee-0.18 ..
1694 // outlet_anything's 'symbol' gets set to address
1695 // so we dont need to append address to the atomlist
1696 /*
1697 SETSYMBOL(mya,gensym(address));myargc++;
1698 x->x_outatc = myargc;
1699 */
1700
1701 if (n != 0) {
1702 if (chars[0] == ',') {
1703 if (chars[1] != ',') {
1704 /* This message begins with a type-tag string */
1705 dumpOSC_PrintTypeTaggedArgs(x, v, n);
1706 } else {
1707 /* Double comma means an escaped real comma, not a type string */
1708 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 1);
1709 }
1710 } else {
1711 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
1712 }
1713 }
1714
1715 outlet_anything(x->x_msgout,gensym(address),x->x_outatc,(t_atom*)&x->x_outat);
1716 x->x_outatc = 0;
1717#ifdef DEBUG
1718 printf("\n");
1719#endif
1720 fflush(stdout); /* Added for Sami 5/21/98 */
1721}
1722
1723static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n) {
1724 char *typeTags, *thisType;
1725 char *p;
1726
1727 int myargc = x->x_outatc;
1728 t_atom* mya = x->x_outat;
1729 int myi;
1730
1731 typeTags = v;
1732
1733 if (!IsNiceString(typeTags, typeTags+n)) {
1734 /* No null-termination, so maybe it wasn't a type tag
1735 string after all */
1736 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
1737 return;
1738 }
1739
1740 p = DataAfterAlignedString(typeTags, typeTags+n);
1741
1742
1743 for (thisType = typeTags + 1; *thisType != 0; ++thisType) {
1744 switch (*thisType) {
1745 case 'i': case 'r': case 'm': case 'c':
1746#ifdef DEBUG
1747 //post("integer: %d", ntohl(*((int *) p)));
1748#endif
1749 /* Martin Peach fix for negative floats:
1750 * was: SETFLOAT(mya+myargc,ntohl(*((int *) p)));
1751 * now is:
1752 */
1753 SETFLOAT(mya+myargc,(signed)ntohl(*((int *) p)));
1754 myargc++;
1755
1756 p += 4;
1757 break;
1758
1759 case 'f': {
1760 int i = ntohl(*((int *) p));
1761 float *floatp = ((float *) (&i));
1762#ifdef DEBUG
1763 post("float: %f", *floatp);
1764#endif
1765 SETFLOAT(mya+myargc,*floatp);
1766 myargc++;
1767
1768 p += 4;
1769 }
1770 break;
1771
1772 case 'h': case 't':
1773#ifdef DEBUG
1774 printf("[A 64-bit int] ");
1775#endif
1776 post("[A 64-bit int] not implemented");
1777
1778 p += 8;
1779 break;
1780
1781 case 'd':
1782#ifdef DEBUG
1783 printf("[A 64-bit float] ");
1784#endif
1785 post("[A 64-bit float] not implemented");
1786
1787 p += 8;
1788 break;
1789
1790 case 's': case 'S':
1791 if (!IsNiceString(p, typeTags+n)) {
1792 post("Type tag said this arg is a string but it's not!\n");
1793 return;
1794 } else {
1795#ifdef DEBUG
1796 post("string: \"%s\"", p);
1797#endif
1798 SETSYMBOL(mya+myargc,gensym(p));
1799 myargc++;
1800 //outlet_list(x->x_msgout, 0,sizeof(p), p);
1801 //outlet_anything(x->x_msgout, 0, sizeof(p), p);
1802 p = DataAfterAlignedString(p, typeTags+n);
1803 // append to output vector ..
1804 }
1805 break;
1806
1807 case 'T':
1808#ifdef DEBUG
1809 printf("[True] ");
1810#endif
1811 SETFLOAT(mya+myargc,1.);
1812 myargc++;
1813 break;
1814 case 'F':
1815#ifdef DEBUG
1816 printf("[False] ");
1817#endif
1818 SETFLOAT(mya+myargc,0.);
1819 myargc++;
1820 break;
1821 case 'N':
1822#ifdef DEBUG
1823 printf("[Nil]");
1824#endif
1825 post("sendOSC: [Nil] not implemented");
1826 break;
1827 case 'I':
1828#ifdef DEBUG
1829 printf("[Infinitum]");
1830#endif
1831 post("sendOSC: [Infinitum] not implemented");
1832 break;
1833
1834 default:
1835 post("sendOSC: [Unrecognized type tag %c]", *thisType);
1836 // return;
1837 }
1838 }
1839 x->x_outatc = myargc;
1840}
1841
1842static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma) {
1843 int i, thisi;
1844 float thisf;
1845 int *ints;
1846 char *chars;
1847 char *string, *nextString;
1848
1849 int myargc= x->x_outatc;
1850 t_atom* mya = x->x_outat;
1851 int myi;
1852
1853
1854 /* Go through the arguments 32 bits at a time */
1855 ints = v;
1856 chars = v;
1857
1858 for (i = 0; i<n/4; ) {
1859 string = &chars[i*4];
1860 thisi = ntohl(ints[i]);
1861 /* Reinterpret the (potentially byte-reversed) thisi as a float */
1862 thisf = *(((float *) (&thisi)));
1863
1864 if (thisi >= -1000 && thisi <= 1000000) {
1865#ifdef DEBUG
1866 printf("%d ", thisi);
1867#endif
1868 // append to output vector ..
1869 SETFLOAT(mya+myargc,(t_float) (thisi));
1870 myargc++;
1871 // outlet_float(x->x_msgout, thisi);
1872 i++;
1873 } else if (thisf >= -1000.f && thisf <= 1000000.f &&
1874 (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
1875#ifdef DEBUG
1876 printf("%f ", thisf);
1877#endif
1878 // append to output vector ..
1879 SETFLOAT(mya+myargc,thisf);
1880 myargc++;
1881 //outlet_float(x->x_msgout, thisf);
1882 i++;
1883 } else if (IsNiceString(string, chars+n)) {
1884 nextString = DataAfterAlignedString(string, chars+n);
1885#ifdef DEBUG
1886 printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
1887#endif
1888 // append to output vector ..
1889 SETSYMBOL(mya+myargc,gensym(string));
1890 myargc++;
1891 //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
1892 i += (nextString-string) / 4;
1893 } else {
1894 // unhandled .. ;)
1895#ifdef DEBUG
1896 printf("0x%x xx", ints[i]);
1897#endif
1898 i++;
1899 }
1900 x->x_outatc = myargc;
1901 }
1902}
1903
1904
1905#define STRING_ALIGN_PAD 4
1906
1907char *DataAfterAlignedString(char *string, char *boundary)
1908{
1909 /* The argument is a block of data beginning with a string. The
1910 string has (presumably) been padded with extra null characters
1911 so that the overall length is a multiple of STRING_ALIGN_PAD
1912 bytes. Return a pointer to the next byte after the null
1913 byte(s). The boundary argument points to the character after
1914 the last valid character in the buffer---if the string hasn't
1915 ended by there, something's wrong.
1916
1917 If the data looks wrong, return 0, and set htm_error_string */
1918
1919 int i;
1920
1921 if ((boundary - string) %4 != 0) {
1922 fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n");
1923 return 0;
1924 }
1925
1926 for (i = 0; string[i] != '\0'; i++) {
1927 if (string + i >= boundary) {
1928 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
1929 return 0;
1930 }
1931 }
1932
1933 /* Now string[i] is the first null character */
1934 i++;
1935
1936 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
1937 if (string + i >= boundary) {
1938 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
1939 return 0;
1940 }
1941 if (string[i] != '\0') {
1942 htm_error_string = "DataAfterAlignedString: Incorrectly padded string.";
1943 return 0;
1944 }
1945 }
1946
1947 return string+i;
1948}
1949
1950Boolean IsNiceString(char *string, char *boundary)
1951{
1952 /* Arguments same as DataAfterAlignedString(). Is the given "string"
1953 really a string? I.e., is it a sequence of isprint() characters
1954 terminated with 1-4 null characters to align on a 4-byte boundary? */
1955
1956 int i;
1957
1958 if ((boundary - string) %4 != 0) {
1959 fprintf(stderr, "Internal error: IsNiceString: bad boundary\n");
1960 return 0;
1961 }
1962
1963 for (i = 0; string[i] != '\0'; i++) {
1964 if (!isprint(string[i])) return FALSE;
1965 if (string + i >= boundary) return FALSE;
1966 }
1967
1968 /* If we made it this far, it's a null-terminated sequence of printing characters
1969 in the given boundary. Now we just make sure it's null padded... */
1970
1971 /* Now string[i] is the first null character */
1972 i++;
1973 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
1974 if (string[i] != '\0') return FALSE;
1975 }
1976
1977 return TRUE;
1978}
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988#include <stdarg.h>
1989void complain(char *s, ...) {
1990 va_list ap;
1991 va_start(ap, s);
1992 fprintf(stderr, "*** ERROR: ");
1993 vfprintf(stderr, s, ap);
1994 fprintf(stderr, "\n");
1995 va_end(ap);
1996}
1997
1998#endif /* __sgi or LINUX or WIN32 */
diff --git a/apps/plugins/pdbox/PDa/extra/equalizer.c b/apps/plugins/pdbox/PDa/extra/equalizer.c
new file mode 100644
index 0000000000..1d21c4087c
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/equalizer.c
@@ -0,0 +1,178 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3
4/*
5
6 These filter coefficients computations are taken from
7 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
8
9 written by Robert Bristow-Johnson
10
11*/
12
13#include "m_pd.h"
14#ifdef NT
15#pragma warning( disable : 4244 )
16#pragma warning( disable : 4305 )
17#endif
18#include <math.h>
19#include "filters.h"
20
21
22
23/* ------------------- equ ----------------------------*/
24static t_class *equ_class;
25
26void equ_bang(t_rbjfilter *x)
27{
28 t_atom at[5];
29 t_float omega = e_omega(x->x_freq,x->x_rate);
30 t_float alpha = e_alpha(x->x_bw*0.01,omega);
31 t_float b0 = 1 + alpha*e_A(x->x_gain);
32 t_float b1 = -2.*cos(omega);
33 t_float b2 = 1 - alpha*e_A(x->x_gain);
34 t_float a0 = 1 + alpha/e_A(x->x_gain);
35 t_float a1 = -2.*cos(omega);
36 t_float a2 = 1 - alpha/e_A(x->x_gain);
37
38/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw);*/
39
40 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
41 post("equ: filter unstable -> resetting");
42 a0=1.;a1=0.;a2=0.;
43 b0=1.;b1=0.;b2=0.;
44 }
45
46 SETFLOAT(at,-a1/a0);
47 SETFLOAT(at+1,-a2/a0);
48 SETFLOAT(at+2,b0/a0);
49 SETFLOAT(at+3,b1/a0);
50 SETFLOAT(at+4,b2/a0);
51
52 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
53}
54
55
56void equ_float(t_rbjfilter *x,t_floatarg f)
57{
58 x->x_freq = f;
59 equ_bang(x);
60}
61
62
63static void *equ_new(t_floatarg f,t_floatarg g,t_floatarg bw)
64{
65 t_rbjfilter *x = (t_rbjfilter *)pd_new(equ_class);
66
67 x->x_rate = 44100.0;
68 outlet_new(&x->x_obj,&s_float);
69 floatinlet_new(&x->x_obj, &x->x_gain);
70 floatinlet_new(&x->x_obj, &x->x_bw);
71 if (f > 0.) x->x_freq = f;
72 if (bw > 0.) x->x_bw = bw;
73 if (g != 0.) x->x_gain = g;
74 return (x);
75}
76
77
78void equalizer_setup(void)
79{
80 equ_class = class_new(gensym("equalizer"), (t_newmethod)equ_new, 0,
81 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
82 class_addbang(equ_class,equ_bang);
83 class_addfloat(equ_class,equ_float);
84}
85
86
87
88
89
90/* (C) Guenter Geiger <geiger@epy.co.at> */
91
92
93/*
94
95 These filter coefficients computations are taken from
96 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
97
98 written by Robert Bristow-Johnson
99
100*/
101
102#include "m_pd.h"
103#ifdef NT
104#pragma warning( disable : 4244 )
105#pragma warning( disable : 4305 )
106#endif
107#include <math.h>
108#include "filters.h"
109
110
111
112/* ------------------- equ ----------------------------*/
113static t_class *equ_class;
114
115void equ_bang(t_rbjfilter *x)
116{
117 t_atom at[5];
118 t_float omega = e_omega(x->x_freq,x->x_rate);
119 t_float alpha = e_alpha(x->x_bw*0.01,omega);
120 t_float b0 = 1 + alpha*e_A(x->x_gain);
121 t_float b1 = -2.*cos(omega);
122 t_float b2 = 1 - alpha*e_A(x->x_gain);
123 t_float a0 = 1 + alpha/e_A(x->x_gain);
124 t_float a1 = -2.*cos(omega);
125 t_float a2 = 1 - alpha/e_A(x->x_gain);
126
127/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw);*/
128
129 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
130 post("equ: filter unstable -> resetting");
131 a0=1.;a1=0.;a2=0.;
132 b0=1.;b1=0.;b2=0.;
133 }
134
135 SETFLOAT(at,-a1/a0);
136 SETFLOAT(at+1,-a2/a0);
137 SETFLOAT(at+2,b0/a0);
138 SETFLOAT(at+3,b1/a0);
139 SETFLOAT(at+4,b2/a0);
140
141 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
142}
143
144
145void equ_float(t_rbjfilter *x,t_floatarg f)
146{
147 x->x_freq = f;
148 equ_bang(x);
149}
150
151
152static void *equ_new(t_floatarg f,t_floatarg g,t_floatarg bw)
153{
154 t_rbjfilter *x = (t_rbjfilter *)pd_new(equ_class);
155
156 x->x_rate = 44100.0;
157 outlet_new(&x->x_obj,&s_float);
158 floatinlet_new(&x->x_obj, &x->x_gain);
159 floatinlet_new(&x->x_obj, &x->x_bw);
160 if (f > 0.) x->x_freq = f;
161 if (bw > 0.) x->x_bw = bw;
162 if (g != 0.) x->x_gain = g;
163 return (x);
164}
165
166
167void equalizer_setup(void)
168{
169 equ_class = class_new(gensym("equalizer"), (t_newmethod)equ_new, 0,
170 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
171 class_addbang(equ_class,equ_bang);
172 class_addfloat(equ_class,equ_float);
173}
174
175
176
177
178
diff --git a/apps/plugins/pdbox/PDa/extra/fatom.h b/apps/plugins/pdbox/PDa/extra/fatom.h
new file mode 100644
index 0000000000..abaf9b91c1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/fatom.h
@@ -0,0 +1,970 @@
1/* ------------------------ fatom ----------------------------- */
2
3#define x_val a_pos.a_w.w_float
4#define DEBUG(x)
5
6#include <string.h>
7#include <stdio.h>
8
9typedef struct _fatom
10{
11 t_object x_obj;
12 t_atom a_pos; /* the value of the fatom */
13
14 t_symbol* x_send;
15 t_symbol* x_receive;
16 t_glist * x_glist; /* value of the current canvas, intialized in _new */
17 int x_rect_width; /* width of the widget */
18 int x_rect_height; /* height of the widget */
19 t_symbol* x_sym; /* symbol for receiving callbacks from GUI */
20 t_symbol* x_type; /* type of fatom (vslider, hslider, checkbutton) */
21
22 t_symbol* x_text; /* associated widget text */
23 int x_max; /* maximum value of a_pos (x_val) */
24 int x_min; /* minimum value of a_pos (x_val) */
25 int x_width; /* width of widget (e.g x_rect_height + 15 for hslider, x_rect_width + 15 for slider) */
26 t_symbol* x_color;
27 t_symbol* x_bgcolor;
28} t_fatom;
29
30/* widget helper functions */
31
32
33
34
35static void draw_inlets(t_fatom *x, t_glist *glist, int firsttime, int nin, int nout)
36{
37 int n = nin;
38 int nplus, i;
39 nplus = (n == 1 ? 1 : n-1);
40 DEBUG(post("draw inlet");)
41 for (i = 0; i < n; i++)
42 {
43 int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH) * i / nplus;
44 if (firsttime)
45 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xo%d\n",
46 glist_getcanvas(glist),
47 onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 1,
48 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height,
49 x, i);
50 else
51 sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n",
52 glist_getcanvas(glist), x, i,
53 onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 1,
54 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height);
55 }
56 n = nout;
57 nplus = (n == 1 ? 1 : n-1);
58 for (i = 0; i < n; i++)
59 {
60 int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH) * i / nplus;
61 if (firsttime)
62 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xi%d\n",
63 glist_getcanvas(glist),
64 onset, text_ypix(&x->x_obj, glist),
65 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + 1,
66 x, i);
67 else
68 sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n",
69 glist_getcanvas(glist), x, i,
70 onset, text_ypix(&x->x_obj, glist),
71 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + 1);
72
73 }
74 DEBUG(post("draw inlet end");)
75}
76
77
78static void draw_handle(t_fatom *x, t_glist *glist, int firsttime) {
79 int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH+2);
80
81 if (firsttime)
82 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xhandle\n",
83 glist_getcanvas(glist),
84 onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 12,
85 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height-4,
86 x);
87 else
88 sys_vgui(".x%x.c coords %xhandle %d %d %d %d\n",
89 glist_getcanvas(glist), x,
90 onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 12,
91 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height-4);
92}
93
94static void create_widget(t_fatom *x, t_glist *glist)
95{
96 t_canvas *canvas=glist_getcanvas(glist);
97
98 if (!strcmp(x->x_type->s_name,"vslider")) {
99 x->x_rect_width = x->x_width+15;
100 x->x_rect_height = x->x_max-x->x_min+26;
101
102 sys_vgui("scale .x%x.c.s%x \
103 -sliderlength 10 \
104 -showvalue 0 \
105 -length %d \
106 -resolution 0.01 \
107 -repeatinterval 20 \
108 -from %d -to %d \
109 -width %d \
110 -bg %s \
111 -activebackground %s \
112 -troughcolor %s \
113 -command fatom_cb%x\n",canvas,x,
114 x->x_max-x->x_min+14,
115 x->x_max,
116 x->x_min,
117 x->x_width,
118 x->x_color->s_name,
119 x->x_color->s_name,
120 x->x_bgcolor->s_name,
121 x);
122 } else if (!strcmp(x->x_type->s_name,"hslider")) {
123 x->x_rect_width = x->x_max-x->x_min + 24;
124 x->x_rect_height = x->x_width + 15;
125 sys_vgui("scale .x%x.c.s%x \
126 -sliderlength 10 \
127 -showvalue 0 \
128 -length %d \
129 -resolution 0.01 \
130 -orient horizontal \
131 -repeatinterval 20 \
132 -from %d -to %d \
133 -width %d \
134 -bg %s \
135 -activebackground %s \
136 -troughcolor %s \
137 -command fatom_cb%x\n",canvas,x,
138 x->x_max-x->x_min+14,
139 x->x_min,
140 x->x_max,
141 x->x_width,
142 x->x_color->s_name,
143 x->x_color->s_name,
144 x->x_bgcolor->s_name,
145 x);
146 } else if (!strcmp(x->x_type->s_name,"checkbutton")) {
147 x->x_rect_width = 32;
148 x->x_rect_height = 28;
149 sys_vgui("checkbutton .x%x.c.s%x \
150 -command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -text \"%s\" \
151 -bg %s \
152 -activebackground %s \
153 \n",canvas,x,x,x,x,
154 x->x_text->s_name,
155 x->x_color->s_name,
156 x->x_bgcolor->s_name);
157 } else if (!strcmp(x->x_type->s_name,"hradio")) {
158 int i;
159 x->x_rect_width = 8*20;
160 x->x_rect_height = 25;
161 for (i=0;i<8;i++) {
162 sys_vgui("radiobutton .x%x.c.s%x%d \
163 -command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -value %d\n",canvas,x,i,x,x,x,i);
164 }
165 /* TODO pack them */
166 } else if (!strcmp(x->x_type->s_name,"vradio")) {
167 int i;
168 x->x_rect_width = 30;
169 x->x_rect_height = 20*8+5;
170 for (i=0;i<8;i++) {
171 sys_vgui("radiobutton .x%x.c.s%x%d \
172 -command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -value %d\n",canvas,x,i,x,x,x,i);
173 }
174 /* TODO pack them */
175 } else {
176 x->x_rect_width = 32;
177 x->x_rect_height = 140;
178 sys_vgui("scale .x%x.c.s%x \
179 -sliderlength 10 \
180 -showvalue 0 \
181 -length 131 \
182 -from 127 -to 0 \
183 -command fatom_cb%x\n",canvas,x,x);
184 }
185
186 /* set the start value */
187 if (!strcmp(x->x_type->s_name,"checkbutton")) {
188 if (x->x_val)
189 sys_vgui(".x%x.c.s%x select\n",canvas,x,x->x_val);
190 else
191 sys_vgui(".x%x.c.s%x deselect\n",canvas,x,x->x_val);
192 } else
193 sys_vgui(".x%x.c.s%x set %f\n",canvas,x,x->x_val);
194
195}
196
197
198
199
200
201static void fatom_drawme(t_fatom *x, t_glist *glist, int firsttime)
202{
203 t_canvas *canvas=glist_getcanvas(glist);// x->x_glist;//glist_getcanvas(glist);
204 DEBUG(post("drawme %d",firsttime);)
205 if (firsttime) {
206 DEBUG(post("glist %x canvas %x",x->x_glist,canvas));
207 create_widget(x,glist);
208 x->x_glist = canvas;
209 sys_vgui(".x%x.c create window %d %d -anchor nw -window .x%x.c.s%x -tags %xS\n",
210 canvas,text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)+2,x->x_glist,x,x);
211
212 }
213 else {
214 sys_vgui(".x%x.c coords %xS \
215%d %d\n",
216 canvas, x,
217 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)+2);
218 }
219 draw_inlets(x, glist, firsttime, 1,1);
220 // draw_handle(x, glist, firsttime);
221
222}
223
224
225static void fatom_erase(t_fatom* x,t_glist* glist)
226{
227 int n;
228
229 DEBUG(post("erase");)
230 sys_vgui("destroy .x%x.c.s%x\n",glist_getcanvas(glist),x);
231
232 sys_vgui(".x%x.c delete %xS\n",glist_getcanvas(glist), x);
233
234 /* inlets and outlets */
235
236 sys_vgui(".x%x.c delete %xi%d\n",glist_getcanvas(glist),x,0);
237 sys_vgui(".x%x.c delete %xo%d\n",glist_getcanvas(glist),x,0);
238 sys_vgui(".x%x.c delete %xhandle\n",glist_getcanvas(glist),x,0);
239}
240
241
242
243/* ------------------------ fatom widgetbehaviour----------------------------- */
244
245
246static void fatom_getrect(t_gobj *z, t_glist *owner,
247 int *xp1, int *yp1, int *xp2, int *yp2)
248{
249 int width, height;
250 t_fatom* s = (t_fatom*)z;
251
252 width = s->x_rect_width;
253 height = s->x_rect_height;
254 *xp1 = text_xpix(&s->x_obj, owner);
255 *yp1 = text_ypix(&s->x_obj, owner);
256 *xp2 = text_xpix(&s->x_obj, owner) + width;
257 *yp2 = text_ypix(&s->x_obj, owner) + height;
258}
259
260static void fatom_displace(t_gobj *z, t_glist *glist,
261 int dx, int dy)
262{
263 t_fatom *x = (t_fatom *)z;
264 DEBUG(post("displace");)
265 x->x_obj.te_xpix += dx;
266 x->x_obj.te_ypix += dy;
267 if (glist_isvisible(glist))
268 {
269 sys_vgui(".x%x.c coords %xSEL %d %d %d %d\n",
270 glist_getcanvas(glist), x,
271 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
272 text_xpix(&x->x_obj, glist) + x->x_rect_width, text_ypix(&x->x_obj, glist) + x->x_rect_height);
273
274 fatom_drawme(x, glist, 0);
275 canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
276 }
277 DEBUG(post("displace end");)
278}
279
280static void fatom_select(t_gobj *z, t_glist *glist, int state)
281{
282 t_fatom *x = (t_fatom *)z;
283 if (state) {
284 sys_vgui(".x%x.c create rectangle \
285%d %d %d %d -tags %xSEL -outline blue\n",
286 glist_getcanvas(glist),
287 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
288 text_xpix(&x->x_obj, glist) + x->x_rect_width, text_ypix(&x->x_obj, glist) + x->x_rect_height,
289 x);
290 }
291 else {
292 sys_vgui(".x%x.c delete %xSEL\n",
293 glist_getcanvas(glist), x);
294 }
295
296
297
298}
299
300
301static void fatom_activate(t_gobj *z, t_glist *glist, int state)
302{
303/* t_text *x = (t_text *)z;
304 t_rtext *y = glist_findrtext(glist, x);
305 if (z->g_pd != gatom_class) rtext_activate(y, state);*/
306}
307
308static void fatom_delete(t_gobj *z, t_glist *glist)
309{
310 t_text *x = (t_text *)z;
311 canvas_deletelinesfor(glist_getcanvas(glist), x);
312}
313
314
315static void fatom_vis(t_gobj *z, t_glist *glist, int vis)
316{
317 t_fatom* s = (t_fatom*)z;
318 t_rtext *y;
319 DEBUG(post("vis: %d",vis);)
320 if (vis) {
321#ifdef PD_MINOR_VERSION
322 y = (t_rtext *) rtext_new(glist, (t_text *)z);
323#else
324 y = (t_rtext *) rtext_new(glist, (t_text *)z,0,0);
325#endif
326 fatom_drawme(s, glist, 1);
327 }
328 else {
329 y = glist_findrtext(glist, (t_text *)z);
330 fatom_erase(s,glist);
331 rtext_free(y);
332 }
333}
334
335static void fatom_save(t_gobj *z, t_binbuf *b);
336
337t_widgetbehavior fatom_widgetbehavior;
338
339
340
341
342static void fatom_size(t_fatom* x,t_floatarg w,t_floatarg h) {
343 x->x_rect_width = w;
344 x->x_rect_height = h;
345}
346
347static void fatom_color(t_fatom* x,t_symbol* col)
348{
349
350}
351
352
353static void fatom_f(t_fatom* x,t_floatarg f)
354{
355 x->x_val = f;
356 if (x->x_send == &s_)
357 outlet_float(x->x_obj.ob_outlet,f);
358 else
359 if (x->x_send->s_thing) pd_float(x->x_send->s_thing,f);
360}
361
362
363static void fatom_float(t_fatom* x,t_floatarg f)
364{
365 if (glist_isvisible(x->x_glist)) {
366 if (!strcmp(x->x_type->s_name,"checkbutton")) {
367 if (x->x_val)
368 sys_vgui(".x%x.c.s%x select\n",x->x_glist,x,f);
369 else
370 sys_vgui(".x%x.c.s%x deselect\n",x->x_glist,x,f);
371 } else
372 sys_vgui(".x%x.c.s%x set %f\n",x->x_glist,x,f);
373 }
374 fatom_f(x,f);
375}
376
377
378static void fatom_bang(t_fatom* x,t_floatarg f)
379{
380 outlet_float(x->x_obj.ob_outlet,x->x_val);
381}
382
383
384static void fatom_properties(t_gobj *z, t_glist *owner)
385{
386 post("N/I");
387}
388
389
390static void fatom_save(t_gobj *z, t_binbuf *b)
391{
392
393 t_fatom *x = (t_fatom *)z;
394
395 binbuf_addv(b, "ssiiss", gensym("#X"),gensym("obj"),
396 x->x_obj.te_xpix, x->x_obj.te_ypix ,
397 gensym("fatom"),x->x_type);
398 binbuf_addv(b, ";");
399}
400
401
402static void *fatom_new(t_fatom* x,int argc,t_atom* argv)
403{
404 char buf[256];
405 int n = 0;
406 x->x_glist = canvas_getcurrent();
407
408 x->x_text = gensym("");
409 x->x_max = 127;
410 x->x_min = 0;
411 x->x_width = 15;
412 x->x_color = gensym("grey");
413 x->x_bgcolor = gensym("grey");
414 x->x_send = &s_;
415
416 while (argc) {
417 if (argv->a_type == A_FLOAT) {
418 if (n==0) x->x_max = atom_getfloat(argv);
419 if (n==1) x->x_min = atom_getfloat(argv);
420 if (n==2) x->x_width = atom_getfloat(argv);
421 }
422
423 if (argv->a_type == A_SYMBOL) {
424 post("%d: symbol value %s",n,atom_getsymbol(argv)->s_name);
425 if (n==3) x->x_send = atom_getsymbol(argv);
426 if (n==4) x->x_color = atom_getsymbol(argv);
427 if (n==5) x->x_bgcolor = atom_getsymbol(argv);
428 }
429 argv++;
430 argc--;
431 n++;
432 }
433
434 /* bind to a symbol for slider callback (later make this based on the
435 filepath ??) */
436
437 sprintf(buf,"fatom%x",(t_int)x);
438 x->x_sym = gensym(buf);
439 pd_bind(&x->x_obj.ob_pd, x->x_sym);
440
441 /* pipe startup code to tk */
442
443 sys_vgui("proc fatom_cb%x {v} {\n pd [concat fatom%x f $v \\;]\n }\n",x,x);
444
445 outlet_new(&x->x_obj, &s_float);
446 return (x);
447}
448
449static void fatom_setup_common(t_class* class)
450{
451
452 fatom_widgetbehavior.w_getrectfn = fatom_getrect;
453 fatom_widgetbehavior.w_displacefn = fatom_displace;
454 fatom_widgetbehavior.w_selectfn = fatom_select;
455 fatom_widgetbehavior.w_activatefn = fatom_activate;
456 fatom_widgetbehavior.w_deletefn = fatom_delete;
457 fatom_widgetbehavior.w_visfn = fatom_vis;
458#if PD_MINOR_VERSION < 37
459 fatom_widgetbehavior.w_savefn = fatom_save;
460 fatom_widgetbehavior.w_propertiesfn = NULL;
461#endif
462 fatom_widgetbehavior.w_clickfn = NULL;
463
464 class_addfloat(class, (t_method)fatom_float);
465 class_addbang(class, (t_method)fatom_bang);
466 class_addmethod(class, (t_method)fatom_f, gensym("f"),
467 A_FLOAT, 0);
468
469/*
470 class_addmethod(class, (t_method)fatom_size, gensym("size"),
471 A_FLOAT, A_FLOAT, 0);
472
473 class_addmethod(class, (t_method)fatom_color, gensym("color"),
474 A_SYMBOL, 0);
475*/
476/*
477 class_addmethod(class, (t_method)fatom_open, gensym("open"),
478 A_SYMBOL, 0);
479*/
480
481 class_setwidget(class,&fatom_widgetbehavior);
482#if PD_MINOR_VERSION >= 37
483 class_setsavefn(class,&fatom_save);
484#endif
485}
486/* ------------------------ fatom ----------------------------- */
487
488#define x_val a_pos.a_w.w_float
489#define DEBUG(x)
490
491#include <string.h>
492#include <stdio.h>
493
494typedef struct _fatom
495{
496 t_object x_obj;
497 t_atom a_pos; /* the value of the fatom */
498
499 t_symbol* x_send;
500 t_symbol* x_receive;
501 t_glist * x_glist; /* value of the current canvas, intialized in _new */
502 int x_rect_width; /* width of the widget */
503 int x_rect_height; /* height of the widget */
504 t_symbol* x_sym; /* symbol for receiving callbacks from GUI */
505 t_symbol* x_type; /* type of fatom (vslider, hslider, checkbutton) */
506
507 t_symbol* x_text; /* associated widget text */
508 int x_max; /* maximum value of a_pos (x_val) */
509 int x_min; /* minimum value of a_pos (x_val) */
510 int x_width; /* width of widget (e.g x_rect_height + 15 for hslider, x_rect_width + 15 for slider) */
511 t_symbol* x_color;
512 t_symbol* x_bgcolor;
513} t_fatom;
514
515/* widget helper functions */
516
517
518
519
520static void draw_inlets(t_fatom *x, t_glist *glist, int firsttime, int nin, int nout)
521{
522 int n = nin;
523 int nplus, i;
524 nplus = (n == 1 ? 1 : n-1);
525 DEBUG(post("draw inlet");)
526 for (i = 0; i < n; i++)
527 {
528 int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH) * i / nplus;
529 if (firsttime)
530 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xo%d\n",
531 glist_getcanvas(glist),
532 onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 1,
533 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height,
534 x, i);
535 else
536 sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n",
537 glist_getcanvas(glist), x, i,
538 onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 1,
539 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height);
540 }
541 n = nout;
542 nplus = (n == 1 ? 1 : n-1);
543 for (i = 0; i < n; i++)
544 {
545 int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH) * i / nplus;
546 if (firsttime)
547 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xi%d\n",
548 glist_getcanvas(glist),
549 onset, text_ypix(&x->x_obj, glist),
550 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + 1,
551 x, i);
552 else
553 sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n",
554 glist_getcanvas(glist), x, i,
555 onset, text_ypix(&x->x_obj, glist),
556 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + 1);
557
558 }
559 DEBUG(post("draw inlet end");)
560}
561
562
563static void draw_handle(t_fatom *x, t_glist *glist, int firsttime) {
564 int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH+2);
565
566 if (firsttime)
567 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xhandle\n",
568 glist_getcanvas(glist),
569 onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 12,
570 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height-4,
571 x);
572 else
573 sys_vgui(".x%x.c coords %xhandle %d %d %d %d\n",
574 glist_getcanvas(glist), x,
575 onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 12,
576 onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height-4);
577}
578
579static void create_widget(t_fatom *x, t_glist *glist)
580{
581 t_canvas *canvas=glist_getcanvas(glist);
582
583 if (!strcmp(x->x_type->s_name,"vslider")) {
584 x->x_rect_width = x->x_width+15;
585 x->x_rect_height = x->x_max-x->x_min+26;
586
587 sys_vgui("scale .x%x.c.s%x \
588 -sliderlength 10 \
589 -showvalue 0 \
590 -length %d \
591 -resolution 0.01 \
592 -repeatinterval 20 \
593 -from %d -to %d \
594 -width %d \
595 -bg %s \
596 -activebackground %s \
597 -troughcolor %s \
598 -command fatom_cb%x\n",canvas,x,
599 x->x_max-x->x_min+14,
600 x->x_max,
601 x->x_min,
602 x->x_width,
603 x->x_color->s_name,
604 x->x_color->s_name,
605 x->x_bgcolor->s_name,
606 x);
607 } else if (!strcmp(x->x_type->s_name,"hslider")) {
608 x->x_rect_width = x->x_max-x->x_min + 24;
609 x->x_rect_height = x->x_width + 15;
610 sys_vgui("scale .x%x.c.s%x \
611 -sliderlength 10 \
612 -showvalue 0 \
613 -length %d \
614 -resolution 0.01 \
615 -orient horizontal \
616 -repeatinterval 20 \
617 -from %d -to %d \
618 -width %d \
619 -bg %s \
620 -activebackground %s \
621 -troughcolor %s \
622 -command fatom_cb%x\n",canvas,x,
623 x->x_max-x->x_min+14,
624 x->x_min,
625 x->x_max,
626 x->x_width,
627 x->x_color->s_name,
628 x->x_color->s_name,
629 x->x_bgcolor->s_name,
630 x);
631 } else if (!strcmp(x->x_type->s_name,"checkbutton")) {
632 x->x_rect_width = 32;
633 x->x_rect_height = 28;
634 sys_vgui("checkbutton .x%x.c.s%x \
635 -command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -text \"%s\" \
636 -bg %s \
637 -activebackground %s \
638 \n",canvas,x,x,x,x,
639 x->x_text->s_name,
640 x->x_color->s_name,
641 x->x_bgcolor->s_name);
642 } else if (!strcmp(x->x_type->s_name,"hradio")) {
643 int i;
644 x->x_rect_width = 8*20;
645 x->x_rect_height = 25;
646 for (i=0;i<8;i++) {
647 sys_vgui("radiobutton .x%x.c.s%x%d \
648 -command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -value %d\n",canvas,x,i,x,x,x,i);
649 }
650 /* TODO pack them */
651 } else if (!strcmp(x->x_type->s_name,"vradio")) {
652 int i;
653 x->x_rect_width = 30;
654 x->x_rect_height = 20*8+5;
655 for (i=0;i<8;i++) {
656 sys_vgui("radiobutton .x%x.c.s%x%d \
657 -command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -value %d\n",canvas,x,i,x,x,x,i);
658 }
659 /* TODO pack them */
660 } else {
661 x->x_rect_width = 32;
662 x->x_rect_height = 140;
663 sys_vgui("scale .x%x.c.s%x \
664 -sliderlength 10 \
665 -showvalue 0 \
666 -length 131 \
667 -from 127 -to 0 \
668 -command fatom_cb%x\n",canvas,x,x);
669 }
670
671 /* set the start value */
672 if (!strcmp(x->x_type->s_name,"checkbutton")) {
673 if (x->x_val)
674 sys_vgui(".x%x.c.s%x select\n",canvas,x,x->x_val);
675 else
676 sys_vgui(".x%x.c.s%x deselect\n",canvas,x,x->x_val);
677 } else
678 sys_vgui(".x%x.c.s%x set %f\n",canvas,x,x->x_val);
679
680}
681
682
683
684
685
686static void fatom_drawme(t_fatom *x, t_glist *glist, int firsttime)
687{
688 t_canvas *canvas=glist_getcanvas(glist);// x->x_glist;//glist_getcanvas(glist);
689 DEBUG(post("drawme %d",firsttime);)
690 if (firsttime) {
691 DEBUG(post("glist %x canvas %x",x->x_glist,canvas));
692 create_widget(x,glist);
693 x->x_glist = canvas;
694 sys_vgui(".x%x.c create window %d %d -anchor nw -window .x%x.c.s%x -tags %xS\n",
695 canvas,text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)+2,x->x_glist,x,x);
696
697 }
698 else {
699 sys_vgui(".x%x.c coords %xS \
700%d %d\n",
701 canvas, x,
702 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)+2);
703 }
704 draw_inlets(x, glist, firsttime, 1,1);
705 // draw_handle(x, glist, firsttime);
706
707}
708
709
710static void fatom_erase(t_fatom* x,t_glist* glist)
711{
712 int n;
713
714 DEBUG(post("erase");)
715 sys_vgui("destroy .x%x.c.s%x\n",glist_getcanvas(glist),x);
716
717 sys_vgui(".x%x.c delete %xS\n",glist_getcanvas(glist), x);
718
719 /* inlets and outlets */
720
721 sys_vgui(".x%x.c delete %xi%d\n",glist_getcanvas(glist),x,0);
722 sys_vgui(".x%x.c delete %xo%d\n",glist_getcanvas(glist),x,0);
723 sys_vgui(".x%x.c delete %xhandle\n",glist_getcanvas(glist),x,0);
724}
725
726
727
728/* ------------------------ fatom widgetbehaviour----------------------------- */
729
730
731static void fatom_getrect(t_gobj *z, t_glist *owner,
732 int *xp1, int *yp1, int *xp2, int *yp2)
733{
734 int width, height;
735 t_fatom* s = (t_fatom*)z;
736
737 width = s->x_rect_width;
738 height = s->x_rect_height;
739 *xp1 = text_xpix(&s->x_obj, owner);
740 *yp1 = text_ypix(&s->x_obj, owner);
741 *xp2 = text_xpix(&s->x_obj, owner) + width;
742 *yp2 = text_ypix(&s->x_obj, owner) + height;
743}
744
745static void fatom_displace(t_gobj *z, t_glist *glist,
746 int dx, int dy)
747{
748 t_fatom *x = (t_fatom *)z;
749 DEBUG(post("displace");)
750 x->x_obj.te_xpix += dx;
751 x->x_obj.te_ypix += dy;
752 if (glist_isvisible(glist))
753 {
754 sys_vgui(".x%x.c coords %xSEL %d %d %d %d\n",
755 glist_getcanvas(glist), x,
756 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
757 text_xpix(&x->x_obj, glist) + x->x_rect_width, text_ypix(&x->x_obj, glist) + x->x_rect_height);
758
759 fatom_drawme(x, glist, 0);
760 canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
761 }
762 DEBUG(post("displace end");)
763}
764
765static void fatom_select(t_gobj *z, t_glist *glist, int state)
766{
767 t_fatom *x = (t_fatom *)z;
768 if (state) {
769 sys_vgui(".x%x.c create rectangle \
770%d %d %d %d -tags %xSEL -outline blue\n",
771 glist_getcanvas(glist),
772 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
773 text_xpix(&x->x_obj, glist) + x->x_rect_width, text_ypix(&x->x_obj, glist) + x->x_rect_height,
774 x);
775 }
776 else {
777 sys_vgui(".x%x.c delete %xSEL\n",
778 glist_getcanvas(glist), x);
779 }
780
781
782
783}
784
785
786static void fatom_activate(t_gobj *z, t_glist *glist, int state)
787{
788/* t_text *x = (t_text *)z;
789 t_rtext *y = glist_findrtext(glist, x);
790 if (z->g_pd != gatom_class) rtext_activate(y, state);*/
791}
792
793static void fatom_delete(t_gobj *z, t_glist *glist)
794{
795 t_text *x = (t_text *)z;
796 canvas_deletelinesfor(glist_getcanvas(glist), x);
797}
798
799
800static void fatom_vis(t_gobj *z, t_glist *glist, int vis)
801{
802 t_fatom* s = (t_fatom*)z;
803 t_rtext *y;
804 DEBUG(post("vis: %d",vis);)
805 if (vis) {
806#ifdef PD_MINOR_VERSION
807 y = (t_rtext *) rtext_new(glist, (t_text *)z);
808#else
809 y = (t_rtext *) rtext_new(glist, (t_text *)z,0,0);
810#endif
811 fatom_drawme(s, glist, 1);
812 }
813 else {
814 y = glist_findrtext(glist, (t_text *)z);
815 fatom_erase(s,glist);
816 rtext_free(y);
817 }
818}
819
820static void fatom_save(t_gobj *z, t_binbuf *b);
821
822t_widgetbehavior fatom_widgetbehavior;
823
824
825
826
827static void fatom_size(t_fatom* x,t_floatarg w,t_floatarg h) {
828 x->x_rect_width = w;
829 x->x_rect_height = h;
830}
831
832static void fatom_color(t_fatom* x,t_symbol* col)
833{
834
835}
836
837
838static void fatom_f(t_fatom* x,t_floatarg f)
839{
840 x->x_val = f;
841 if (x->x_send == &s_)
842 outlet_float(x->x_obj.ob_outlet,f);
843 else
844 if (x->x_send->s_thing) pd_float(x->x_send->s_thing,f);
845}
846
847
848static void fatom_float(t_fatom* x,t_floatarg f)
849{
850 if (glist_isvisible(x->x_glist)) {
851 if (!strcmp(x->x_type->s_name,"checkbutton")) {
852 if (x->x_val)
853 sys_vgui(".x%x.c.s%x select\n",x->x_glist,x,f);
854 else
855 sys_vgui(".x%x.c.s%x deselect\n",x->x_glist,x,f);
856 } else
857 sys_vgui(".x%x.c.s%x set %f\n",x->x_glist,x,f);
858 }
859 fatom_f(x,f);
860}
861
862
863static void fatom_bang(t_fatom* x,t_floatarg f)
864{
865 outlet_float(x->x_obj.ob_outlet,x->x_val);
866}
867
868
869static void fatom_properties(t_gobj *z, t_glist *owner)
870{
871 post("N/I");
872}
873
874
875static void fatom_save(t_gobj *z, t_binbuf *b)
876{
877
878 t_fatom *x = (t_fatom *)z;
879
880 binbuf_addv(b, "ssiiss", gensym("#X"),gensym("obj"),
881 x->x_obj.te_xpix, x->x_obj.te_ypix ,
882 gensym("fatom"),x->x_type);
883 binbuf_addv(b, ";");
884}
885
886
887static void *fatom_new(t_fatom* x,int argc,t_atom* argv)
888{
889 char buf[256];
890 int n = 0;
891 x->x_glist = canvas_getcurrent();
892
893 x->x_text = gensym("");
894 x->x_max = 127;
895 x->x_min = 0;
896 x->x_width = 15;
897 x->x_color = gensym("grey");
898 x->x_bgcolor = gensym("grey");
899 x->x_send = &s_;
900
901 while (argc) {
902 if (argv->a_type == A_FLOAT) {
903 if (n==0) x->x_max = atom_getfloat(argv);
904 if (n==1) x->x_min = atom_getfloat(argv);
905 if (n==2) x->x_width = atom_getfloat(argv);
906 }
907
908 if (argv->a_type == A_SYMBOL) {
909 post("%d: symbol value %s",n,atom_getsymbol(argv)->s_name);
910 if (n==3) x->x_send = atom_getsymbol(argv);
911 if (n==4) x->x_color = atom_getsymbol(argv);
912 if (n==5) x->x_bgcolor = atom_getsymbol(argv);
913 }
914 argv++;
915 argc--;
916 n++;
917 }
918
919 /* bind to a symbol for slider callback (later make this based on the
920 filepath ??) */
921
922 sprintf(buf,"fatom%x",(t_int)x);
923 x->x_sym = gensym(buf);
924 pd_bind(&x->x_obj.ob_pd, x->x_sym);
925
926 /* pipe startup code to tk */
927
928 sys_vgui("proc fatom_cb%x {v} {\n pd [concat fatom%x f $v \\;]\n }\n",x,x);
929
930 outlet_new(&x->x_obj, &s_float);
931 return (x);
932}
933
934static void fatom_setup_common(t_class* class)
935{
936
937 fatom_widgetbehavior.w_getrectfn = fatom_getrect;
938 fatom_widgetbehavior.w_displacefn = fatom_displace;
939 fatom_widgetbehavior.w_selectfn = fatom_select;
940 fatom_widgetbehavior.w_activatefn = fatom_activate;
941 fatom_widgetbehavior.w_deletefn = fatom_delete;
942 fatom_widgetbehavior.w_visfn = fatom_vis;
943#if PD_MINOR_VERSION < 37
944 fatom_widgetbehavior.w_savefn = fatom_save;
945 fatom_widgetbehavior.w_propertiesfn = NULL;
946#endif
947 fatom_widgetbehavior.w_clickfn = NULL;
948
949 class_addfloat(class, (t_method)fatom_float);
950 class_addbang(class, (t_method)fatom_bang);
951 class_addmethod(class, (t_method)fatom_f, gensym("f"),
952 A_FLOAT, 0);
953
954/*
955 class_addmethod(class, (t_method)fatom_size, gensym("size"),
956 A_FLOAT, A_FLOAT, 0);
957
958 class_addmethod(class, (t_method)fatom_color, gensym("color"),
959 A_SYMBOL, 0);
960*/
961/*
962 class_addmethod(class, (t_method)fatom_open, gensym("open"),
963 A_SYMBOL, 0);
964*/
965
966 class_setwidget(class,&fatom_widgetbehavior);
967#if PD_MINOR_VERSION >= 37
968 class_setsavefn(class,&fatom_save);
969#endif
970}
diff --git a/apps/plugins/pdbox/PDa/extra/filters.h b/apps/plugins/pdbox/PDa/extra/filters.h
new file mode 100644
index 0000000000..72d997e425
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/filters.h
@@ -0,0 +1,148 @@
1/*
2
3 These filter coefficients computations are taken from
4 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
5
6 written by Robert Bristow-Johnson
7
8*/
9
10
11#ifndef __GGEE_FILTERS_H__
12#define __GGEE_FILTERS_H__
13
14
15
16#ifndef M_PI
17#define M_PI 3.141593f
18#endif
19
20
21#include <math.h>
22#define LN2 0.69314718
23#define e_A(g) (pow(10,(g/40.)))
24#define e_omega(f,r) (2.0*M_PI*f/r)
25#define e_alpha(bw,omega) (sin(omega)*sinh(LN2/2. * bw * omega/sin(omega)))
26#define e_beta(a,S) (sqrt((a*a + 1)/(S) - (a-1)*(a-1)))
27
28
29
30
31typedef struct _rbjfilter
32{
33 t_object x_obj;
34 t_float x_rate;
35 t_float x_freq;
36 t_float x_gain;
37 t_float x_bw;
38} t_rbjfilter;
39
40
41static int check_stability(t_float fb1,
42 t_float fb2,
43 t_float ff1,
44 t_float ff2,
45 t_float ff3)
46{
47 float discriminant = fb1 * fb1 + 4 * fb2;
48
49 if (discriminant < 0) /* imaginary roots -- resonant filter */
50 {
51 /* they're conjugates so we just check that the product
52 is less than one */
53 if (fb2 >= -1.0f) goto stable;
54 }
55 else /* real roots */
56 {
57 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
58 vertex between -1 and 1, and that it's nonnegative
59 at both ends, which implies both roots are in [1-,1]. */
60 if (fb1 <= 2.0f && fb1 >= -2.0f &&
61 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
62 goto stable;
63 }
64 return 0;
65stable:
66 return 1;
67}
68
69
70
71
72
73
74#endif
75/*
76
77 These filter coefficients computations are taken from
78 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
79
80 written by Robert Bristow-Johnson
81
82*/
83
84
85#ifndef __GGEE_FILTERS_H__
86#define __GGEE_FILTERS_H__
87
88
89
90#ifndef M_PI
91#define M_PI 3.141593f
92#endif
93
94
95#include <math.h>
96#define LN2 0.69314718
97#define e_A(g) (pow(10,(g/40.)))
98#define e_omega(f,r) (2.0*M_PI*f/r)
99#define e_alpha(bw,omega) (sin(omega)*sinh(LN2/2. * bw * omega/sin(omega)))
100#define e_beta(a,S) (sqrt((a*a + 1)/(S) - (a-1)*(a-1)))
101
102
103
104
105typedef struct _rbjfilter
106{
107 t_object x_obj;
108 t_float x_rate;
109 t_float x_freq;
110 t_float x_gain;
111 t_float x_bw;
112} t_rbjfilter;
113
114
115static int check_stability(t_float fb1,
116 t_float fb2,
117 t_float ff1,
118 t_float ff2,
119 t_float ff3)
120{
121 float discriminant = fb1 * fb1 + 4 * fb2;
122
123 if (discriminant < 0) /* imaginary roots -- resonant filter */
124 {
125 /* they're conjugates so we just check that the product
126 is less than one */
127 if (fb2 >= -1.0f) goto stable;
128 }
129 else /* real roots */
130 {
131 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
132 vertex between -1 and 1, and that it's nonnegative
133 at both ends, which implies both roots are in [1-,1]. */
134 if (fb1 <= 2.0f && fb1 >= -2.0f &&
135 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
136 goto stable;
137 }
138 return 0;
139stable:
140 return 1;
141}
142
143
144
145
146
147
148#endif
diff --git a/apps/plugins/pdbox/PDa/extra/g_canvas.h b/apps/plugins/pdbox/PDa/extra/g_canvas.h
new file mode 100644
index 0000000000..54ab985feb
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/g_canvas.h
@@ -0,0 +1,1204 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* this file defines the structure for "glists" and related structures and
6functions. "Glists" and "canvases" and "graphs" used to be different
7structures until being unified in version 0.35.
8
9A glist occupies its own window if the "gl_havewindow" flag is set. Its
10appearance on its "parent" or "owner" (if it has one) is as a graph if
11"gl_isgraph" is set, and otherwise as a text box.
12
13A glist is "root" if it has no owner, i.e., a document window. In this
14case "gl_havewindow" is always set.
15
16We maintain a list of root windows, so that we can traverse the whole
17collection of everything in a Pd process.
18
19If a glist has a window it may still not be "mapped." Miniaturized
20windows aren't mapped, for example, but a window is also not mapped
21immediately upon creation. In either case gl_havewindow is true but
22gl_mapped is false.
23
24Closing a non-root window makes it invisible; closing a root destroys it.
25
26A glist that's just a text object on its parent is always "toplevel." An
27embedded glist can switch back and forth to appear as a toplevel by double-
28clicking on it. Single-clicking a text box makes the toplevel become visible
29and raises the window it's in.
30
31If a glist shows up as a graph on its parent, the graph is blanked while the
32glist has its own window, even if miniaturized.
33
34*/
35
36/* NOTE: this file describes Pd implementation details which may change
37in future releases. The public (stable) API is in m_pd.h. */
38
39#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
40extern "C" {
41#endif
42
43/* --------------------- geometry ---------------------------- */
44#define IOWIDTH 7 /* width of an inlet/outlet in pixels */
45#define IOMIDDLE ((IOWIDTH-1)/2)
46#define GLIST_DEFGRAPHWIDTH 200
47#define GLIST_DEFGRAPHHEIGHT 140
48/* ----------------------- data ------------------------------- */
49
50typedef struct _updateheader
51{
52 struct _updateheader *upd_next;
53 unsigned int upd_array:1; /* true if array, false if glist */
54 unsigned int upd_queued:1; /* true if we're queued */
55} t_updateheader;
56
57 /* types to support glists grabbing mouse motion or keys from parent */
58typedef void (*t_glistmotionfn)(void *z, t_floatarg dx, t_floatarg dy);
59typedef void (*t_glistkeyfn)(void *z, t_floatarg key);
60
61EXTERN_STRUCT _rtext;
62#define t_rtext struct _rtext
63
64EXTERN_STRUCT _gtemplate;
65#define t_gtemplate struct _gtemplate
66
67EXTERN_STRUCT _guiconnect;
68#define t_guiconnect struct _guiconnect
69
70EXTERN_STRUCT _tscalar;
71#define t_tscalar struct _tscalar
72
73EXTERN_STRUCT _canvasenvironment;
74#define t_canvasenvironment struct _canvasenvironment
75
76typedef struct _selection
77{
78 t_gobj *sel_what;
79 struct _selection *sel_next;
80} t_selection;
81
82 /* this structure is instantiated whenever a glist becomes visible. */
83typedef struct _editor
84{
85 t_updateheader e_upd; /* update header structure */
86 t_selection *e_updlist; /* list of objects to update */
87 t_rtext *e_rtext; /* text responder linked list */
88 t_selection *e_selection; /* head of the selection list */
89 t_rtext *e_textedfor; /* the rtext if any that we are editing */
90 t_gobj *e_grab; /* object being "dragged" */
91 t_glistmotionfn e_motionfn; /* ... motion callback */
92 t_glistkeyfn e_keyfn; /* ... keypress callback */
93 t_binbuf *e_connectbuf; /* connections to deleted objects */
94 t_binbuf *e_deleted; /* last stuff we deleted */
95 t_guiconnect *e_guiconnect; /* GUI connection for filtering messages */
96 struct _glist *e_glist; /* glist which owns this */
97 int e_xwas; /* xpos on last mousedown or motion event */
98 int e_ywas; /* ypos, similarly */
99 int e_selectline_index1; /* indices for the selected line if any */
100 int e_selectline_outno; /* (only valid if e_selectedline is set) */
101 int e_selectline_index2;
102 int e_selectline_inno;
103 t_outconnect *e_selectline_tag;
104 unsigned int e_onmotion: 3; /* action to take on motion */
105 unsigned int e_lastmoved: 1; /* one if mouse has moved since click */
106 unsigned int e_textdirty: 1; /* one if e_textedfor has changed */
107 unsigned int e_selectedline: 1; /* one if a line is selected */
108} t_editor;
109
110#define MA_NONE 0 /* e_onmotion: do nothing on mouse motion */
111#define MA_MOVE 1 /* drag the selection around */
112#define MA_CONNECT 2 /* make a connection */
113#define MA_REGION 3 /* selection region */
114#define MA_PASSOUT 4 /* send on to e_grab */
115#define MA_DRAGTEXT 5 /* drag in text editor to alter selection */
116
117/* editor structure for "garrays". We don't bother to delete and regenerate
118this structure when the "garray" becomes invisible or visible, although we
119could do so if the structure gets big (like the "editor" above.) */
120
121typedef struct _arrayvis
122{
123 t_updateheader av_upd; /* update header structure */
124 t_garray *av_garray; /* owning structure */
125} t_arrayvis;
126
127/* the t_tick structure describes where to draw x and y "ticks" for a glist */
128
129typedef struct _tick /* where to put ticks on x or y axes */
130{
131 float k_point; /* one point to draw a big tick at */
132 float k_inc; /* x or y increment per little tick */
133 int k_lperb; /* little ticks per big; 0 if no ticks to draw */
134} t_tick;
135
136/* the t_glist structure, which describes a list of elements that live on an
137area of a window.
138
139*/
140
141struct _glist
142{
143 t_object gl_obj; /* header in case we're a glist */
144 t_gobj *gl_list; /* the actual data */
145 struct _gstub *gl_stub; /* safe pointer handler */
146 int gl_valid; /* incremented when pointers might be stale */
147 struct _glist *gl_owner; /* parent glist, supercanvas, or 0 if none */
148 int gl_pixwidth; /* width in pixels (on parent, if a graph) */
149 int gl_pixheight;
150 float gl_x1; /* bounding rectangle in our own coordinates */
151 float gl_y1;
152 float gl_x2;
153 float gl_y2;
154 int gl_screenx1; /* screen coordinates when toplevel */
155 int gl_screeny1;
156 int gl_screenx2;
157 int gl_screeny2;
158 t_tick gl_xtick; /* ticks marking X values */
159 int gl_nxlabels; /* number of X coordinate labels */
160 t_symbol **gl_xlabel; /* ... an array to hold them */
161 float gl_xlabely; /* ... and their Y coordinates */
162 t_tick gl_ytick; /* same as above for Y ticks and labels */
163 int gl_nylabels;
164 t_symbol **gl_ylabel;
165 float gl_ylabelx;
166 t_editor *gl_editor; /* editor structure when visible */
167 t_symbol *gl_name; /* symbol bound here */
168 int gl_font; /* nominal font size in points, e.g., 10 */
169 struct _glist *gl_next; /* link in list of toplevels */
170 t_canvasenvironment *gl_env; /* root canvases and abstractions only */
171 unsigned int gl_havewindow:1; /* true if we own a window */
172 unsigned int gl_mapped:1; /* true if, moreover, it's "mapped" */
173 unsigned int gl_dirty:1; /* (root canvas only:) patch has changed */
174 unsigned int gl_loading:1; /* am now loading from file */
175 unsigned int gl_willvis:1; /* make me visible after loading */
176 unsigned int gl_edit:1; /* edit mode */
177 unsigned int gl_isdeleting:1; /* we're inside glist_delete -- hack! */
178 unsigned int gl_stretch:1; /* stretch contents on resize */
179 unsigned int gl_isgraph:1; /* show as graph on parent */
180};
181
182#define gl_gobj gl_obj.te_g
183#define gl_pd gl_gobj.g_pd
184
185/* a data structure to describe a field in a pure datum */
186
187#define DT_FLOAT 0
188#define DT_SYMBOL 1
189#define DT_LIST 2
190#define DT_ARRAY 3
191
192typedef struct _dataslot
193{
194 int ds_type;
195 t_symbol *ds_name;
196 t_symbol *ds_arraytemplate; /* filled in for arrays only */
197} t_dataslot;
198
199
200/* T.Grill - changed t_pd member to t_pdobj to avoid name clashed */
201typedef struct _template
202{
203 t_pd t_pdobj; /* header */
204 struct _gtemplate *t_list; /* list of "struct"/gtemplate objects */
205 t_symbol *t_sym; /* name */
206 int t_n; /* number of dataslots (fields) */
207 t_dataslot *t_vec; /* array of dataslots */
208} t_template;
209
210struct _array
211{
212 int a_n; /* number of elements */
213 int a_elemsize; /* size in bytes; LATER get this from template */
214 char *a_vec; /* array of elements */
215 t_symbol *a_templatesym; /* template for elements */
216 int a_valid; /* protection against stale pointers into array */
217 t_gpointer a_gp; /* pointer to scalar or array element we're in */
218 t_gstub *a_stub;
219};
220
221 /* structure for traversing all the connections in a glist */
222typedef struct _linetraverser
223{
224 t_canvas *tr_x;
225 t_object *tr_ob;
226 int tr_nout;
227 int tr_outno;
228 t_object *tr_ob2;
229 t_outlet *tr_outlet;
230 t_inlet *tr_inlet;
231 int tr_nin;
232 int tr_inno;
233 int tr_x11, tr_y11, tr_x12, tr_y12;
234 int tr_x21, tr_y21, tr_x22, tr_y22;
235 int tr_lx1, tr_ly1, tr_lx2, tr_ly2;
236 t_outconnect *tr_nextoc;
237 int tr_nextoutno;
238} t_linetraverser;
239
240/* function types used to define graphical behavior for gobjs, a bit like X
241widgets. We don't use Pd methods because Pd's typechecking can't specify the
242types of pointer arguments. Also it's more convenient this way, since
243every "patchable" object can just get the "text" behaviors. */
244
245 /* Call this to get a gobj's bounding rectangle in pixels */
246typedef void (*t_getrectfn)(t_gobj *x, struct _glist *glist,
247 int *x1, int *y1, int *x2, int *y2);
248 /* and this to displace a gobj: */
249typedef void (*t_displacefn)(t_gobj *x, struct _glist *glist, int dx, int dy);
250 /* change color to show selection: */
251typedef void (*t_selectfn)(t_gobj *x, struct _glist *glist, int state);
252 /* change appearance to show activation/deactivation: */
253typedef void (*t_activatefn)(t_gobj *x, struct _glist *glist, int state);
254 /* warn a gobj it's about to be deleted */
255typedef void (*t_deletefn)(t_gobj *x, struct _glist *glist);
256 /* making visible or invisible */
257typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag);
258 /* field a mouse click (when not in "edit" mode) */
259typedef int (*t_clickfn)(t_gobj *x, struct _glist *glist,
260 int xpix, int ypix, int shift, int alt, int dbl, int doit);
261 /* ... and later, resizing; getting/setting font or color... */
262
263struct _widgetbehavior
264{
265 t_getrectfn w_getrectfn;
266 t_displacefn w_displacefn;
267 t_selectfn w_selectfn;
268 t_activatefn w_activatefn;
269 t_deletefn w_deletefn;
270 t_visfn w_visfn;
271 t_clickfn w_clickfn;
272};
273
274/* -------- behaviors for scalars defined by objects in template --------- */
275/* these are set by "drawing commands" in g_template.c which add appearance to
276scalars, which live in some other window. If the scalar is just included
277in a canvas the "parent" is a misnomer. There is also a text scalar object
278which really does draw the scalar on the parent window; see g_scalar.c. */
279
280/* note how the click function wants the whole scalar, not the "data", so
281doesn't work on array elements... LATER reconsider this */
282
283 /* bounding rectangle: */
284typedef void (*t_parentgetrectfn)(t_gobj *x, struct _glist *glist,
285 t_word *data, t_template *tmpl, float basex, float basey,
286 int *x1, int *y1, int *x2, int *y2);
287 /* displace it */
288typedef void (*t_parentdisplacefn)(t_gobj *x, struct _glist *glist,
289 t_word *data, t_template *tmpl, float basex, float basey,
290 int dx, int dy);
291 /* change color to show selection */
292typedef void (*t_parentselectfn)(t_gobj *x, struct _glist *glist,
293 t_word *data, t_template *tmpl, float basex, float basey,
294 int state);
295 /* change appearance to show activation/deactivation: */
296typedef void (*t_parentactivatefn)(t_gobj *x, struct _glist *glist,
297 t_word *data, t_template *tmpl, float basex, float basey,
298 int state);
299 /* making visible or invisible */
300typedef void (*t_parentvisfn)(t_gobj *x, struct _glist *glist,
301 t_word *data, t_template *tmpl, float basex, float basey,
302 int flag);
303 /* field a mouse click */
304typedef int (*t_parentclickfn)(t_gobj *x, struct _glist *glist,
305 t_scalar *sc, t_template *tmpl, float basex, float basey,
306 int xpix, int ypix, int shift, int alt, int dbl, int doit);
307
308struct _parentwidgetbehavior
309{
310 t_parentgetrectfn w_parentgetrectfn;
311 t_parentdisplacefn w_parentdisplacefn;
312 t_parentselectfn w_parentselectfn;
313 t_parentactivatefn w_parentactivatefn;
314 t_parentvisfn w_parentvisfn;
315 t_parentclickfn w_parentclickfn;
316};
317
318 /* cursor definitions; used as return value for t_parentclickfn */
319#define CURSOR_RUNMODE_NOTHING 0
320#define CURSOR_RUNMODE_CLICKME 1
321#define CURSOR_RUNMODE_THICKEN 2
322#define CURSOR_RUNMODE_ADDPOINT 3
323#define CURSOR_EDITMODE_NOTHING 4
324#define CURSOR_EDITMODE_CONNECT 5
325#define CURSOR_EDITMODE_DISCONNECT 6
326EXTERN void canvas_setcursor(t_glist *x, unsigned int cursornum);
327
328extern t_canvas *canvas_editing; /* last canvas to start text edting */
329extern t_canvas *canvas_whichfind; /* last canvas we did a find in */
330extern t_canvas *canvas_list; /* list of all root canvases */
331extern t_class *vinlet_class, *voutlet_class;
332extern int glist_valid; /* incremented when pointers might be stale */
333
334/* ------------------- functions on any gobj ----------------------------- */
335EXTERN void gobj_getrect(t_gobj *x, t_glist *owner, int *x1, int *y1,
336 int *x2, int *y2);
337EXTERN void gobj_displace(t_gobj *x, t_glist *owner, int dx, int dy);
338EXTERN void gobj_select(t_gobj *x, t_glist *owner, int state);
339EXTERN void gobj_activate(t_gobj *x, t_glist *owner, int state);
340EXTERN void gobj_delete(t_gobj *x, t_glist *owner);
341EXTERN void gobj_vis(t_gobj *x, t_glist *glist, int flag);
342EXTERN int gobj_click(t_gobj *x, struct _glist *glist,
343 int xpix, int ypix, int shift, int alt, int dbl, int doit);
344EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
345EXTERN void gobj_properties(t_gobj *x, struct _glist *glist);
346EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
347
348/* -------------------- functions on glists --------------------- */
349EXTERN t_glist *glist_new( void);
350EXTERN void glist_init(t_glist *x);
351EXTERN void glist_add(t_glist *x, t_gobj *g);
352EXTERN void glist_cleanup(t_glist *x);
353EXTERN void glist_free(t_glist *x);
354
355EXTERN void glist_clear(t_glist *x);
356EXTERN t_canvas *glist_getcanvas(t_glist *x);
357EXTERN int glist_isselected(t_glist *x, t_gobj *y);
358EXTERN void glist_select(t_glist *x, t_gobj *y);
359EXTERN void glist_deselect(t_glist *x, t_gobj *y);
360EXTERN void glist_noselect(t_glist *x);
361EXTERN void glist_selectall(t_glist *x);
362EXTERN void glist_delete(t_glist *x, t_gobj *y);
363EXTERN void glist_retext(t_glist *x, t_text *y);
364EXTERN void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
365 t_glistkeyfn keyfn, int xpos, int ypos);
366EXTERN int glist_isvisible(t_glist *x);
367EXTERN int glist_istoplevel(t_glist *x);
368EXTERN t_glist *glist_findgraph(t_glist *x);
369EXTERN int glist_getfont(t_glist *x);
370EXTERN void glist_sort(t_glist *canvas);
371EXTERN void glist_read(t_glist *x, t_symbol *filename, t_symbol *format);
372EXTERN void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format);
373
374EXTERN float glist_pixelstox(t_glist *x, float xpix);
375EXTERN float glist_pixelstoy(t_glist *x, float ypix);
376EXTERN float glist_xtopixels(t_glist *x, float xval);
377EXTERN float glist_ytopixels(t_glist *x, float yval);
378EXTERN float glist_dpixtodx(t_glist *x, float dxpix);
379EXTERN float glist_dpixtody(t_glist *x, float dypix);
380
381EXTERN void glist_redrawitem(t_glist *owner, t_gobj *gobj);
382EXTERN void glist_getnextxy(t_glist *gl, int *xval, int *yval);
383EXTERN void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv);
384EXTERN t_glist *glist_addglist(t_glist *g, t_symbol *sym,
385 float x1, float y1, float x2, float y2,
386 float px1, float py1, float px2, float py2);
387EXTERN void glist_arraydialog(t_glist *parent, t_symbol *name,
388 t_floatarg size, t_floatarg saveit, t_floatarg newgraph);
389EXTERN t_binbuf *glist_writetobinbuf(t_glist *x, int wholething);
390EXTERN int glist_isgraph(t_glist *x);
391EXTERN void glist_redraw(t_glist *x);
392EXTERN void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
393 char *tag, int x1, int y1, int x2, int y2);
394EXTERN void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag);
395EXTERN void canvas_create_editor(t_glist *x, int createit);
396void canvas_deletelinesforio(t_canvas *x, t_text *text,
397 t_inlet *inp, t_outlet *outp);
398
399
400/* -------------------- functions on texts ------------------------- */
401EXTERN void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize);
402EXTERN void text_drawborder(t_text *x, t_glist *glist, char *tag,
403 int width, int height, int firsttime);
404EXTERN void text_eraseborder(t_text *x, t_glist *glist, char *tag);
405EXTERN int text_xcoord(t_text *x, t_glist *glist);
406EXTERN int text_ycoord(t_text *x, t_glist *glist);
407EXTERN int text_xpix(t_text *x, t_glist *glist);
408EXTERN int text_ypix(t_text *x, t_glist *glist);
409EXTERN int text_shouldvis(t_text *x, t_glist *glist);
410
411/* -------------------- functions on rtexts ------------------------- */
412#define RTEXT_DOWN 1
413#define RTEXT_DRAG 2
414#define RTEXT_DBL 3
415#define RTEXT_SHIFT 4
416
417EXTERN t_rtext *rtext_new(t_glist *glist, t_text *who);
418EXTERN t_rtext *glist_findrtext(t_glist *gl, t_text *who);
419EXTERN void rtext_draw(t_rtext *x);
420EXTERN void rtext_erase(t_rtext *x);
421EXTERN t_rtext *rtext_remove(t_rtext *first, t_rtext *x);
422EXTERN int rtext_height(t_rtext *x);
423EXTERN void rtext_displace(t_rtext *x, int dx, int dy);
424EXTERN void rtext_select(t_rtext *x, int state);
425EXTERN void rtext_activate(t_rtext *x, int state);
426EXTERN void rtext_free(t_rtext *x);
427EXTERN void rtext_key(t_rtext *x, int n, t_symbol *s);
428EXTERN void rtext_mouse(t_rtext *x, int xval, int yval, int flag);
429EXTERN void rtext_retext(t_rtext *x);
430EXTERN int rtext_width(t_rtext *x);
431EXTERN int rtext_height(t_rtext *x);
432EXTERN char *rtext_gettag(t_rtext *x);
433EXTERN void rtext_gettext(t_rtext *x, char **buf, int *bufsize);
434
435/* -------------------- functions on canvases ------------------------ */
436EXTERN t_class *canvas_class;
437
438EXTERN t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv);
439EXTERN t_symbol *canvas_makebindsym(t_symbol *s);
440EXTERN void canvas_vistext(t_canvas *x, t_text *y);
441EXTERN void canvas_fixlinesfor(t_canvas *x, t_text *text);
442EXTERN void canvas_deletelinesfor(t_canvas *x, t_text *text);
443EXTERN void canvas_stowconnections(t_canvas *x);
444EXTERN void canvas_restoreconnections(t_canvas *x);
445EXTERN void canvas_redraw(t_canvas *x);
446
447EXTERN t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *sym);
448EXTERN void canvas_rminlet(t_canvas *x, t_inlet *ip);
449EXTERN t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *sym);
450EXTERN void canvas_rmoutlet(t_canvas *x, t_outlet *op);
451EXTERN void canvas_redrawallfortemplate(t_canvas *tmpl);
452EXTERN void canvas_zapallfortemplate(t_canvas *tmpl);
453EXTERN void canvas_setusedastemplate(t_canvas *x);
454EXTERN t_canvas *canvas_getcurrent(void);
455EXTERN void canvas_setcurrent(t_canvas *x);
456EXTERN void canvas_unsetcurrent(t_canvas *x);
457EXTERN t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s);
458EXTERN t_canvas *canvas_getrootfor(t_canvas *x);
459EXTERN void canvas_dirty(t_canvas *x, t_int n);
460EXTERN int canvas_getfont(t_canvas *x);
461typedef int (*t_canvasapply)(t_canvas *x, t_int x1, t_int x2, t_int x3);
462
463EXTERN t_int *canvas_recurapply(t_canvas *x, t_canvasapply *fn,
464 t_int x1, t_int x2, t_int x3);
465
466EXTERN void canvas_resortinlets(t_canvas *x);
467EXTERN void canvas_resortoutlets(t_canvas *x);
468EXTERN void canvas_free(t_canvas *x);
469EXTERN void canvas_updatewindowlist( void);
470EXTERN void canvas_editmode(t_canvas *x, t_floatarg yesplease);
471EXTERN int canvas_isabstraction(t_canvas *x);
472EXTERN int canvas_istable(t_canvas *x);
473EXTERN int canvas_showtext(t_canvas *x);
474EXTERN void canvas_vis(t_canvas *x, t_floatarg f);
475EXTERN t_canvasenvironment *canvas_getenv(t_canvas *x);
476EXTERN void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir);
477EXTERN void canvas_loadbang(t_canvas *x);
478EXTERN int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos,
479 int *x1p, int *y1p, int *x2p, int *y2p);
480EXTERN int canvas_setdeleting(t_canvas *x, int flag);
481
482typedef void (*t_undofn)(t_canvas *canvas, void *buf,
483 int action); /* a function that does UNDO/REDO */
484#define UNDO_FREE 0 /* free current undo/redo buffer */
485#define UNDO_UNDO 1 /* undo */
486#define UNDO_REDO 2 /* redo */
487EXTERN void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
488 const char *name);
489EXTERN void canvas_noundo(t_canvas *x);
490EXTERN int canvas_getindex(t_canvas *x, t_gobj *y);
491
492/* T.Grill - made public for dynamic object creation */
493/* in g_editor.c */
494EXTERN void canvas_connect(t_canvas *x,
495 t_floatarg fwhoout, t_floatarg foutno,t_floatarg fwhoin, t_floatarg finno);
496EXTERN void canvas_disconnect(t_canvas *x,
497 float index1, float outno, float index2, float inno);
498EXTERN int canvas_isconnected (t_canvas *x,
499 t_text *ob1, int n1, t_text *ob2, int n2);
500EXTERN void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy);
501
502
503/* ---- functions on canvasses as objects --------------------- */
504
505EXTERN void canvas_fattenforscalars(t_canvas *x,
506 int *x1, int *y1, int *x2, int *y2);
507EXTERN void canvas_visforscalars(t_canvas *x, t_glist *glist, int vis);
508EXTERN int canvas_clicksub(t_canvas *x, int xpix, int ypix, int shift,
509 int alt, int dbl, int doit);
510EXTERN t_glist *canvas_getglistonsuper(void);
511
512EXTERN void linetraverser_start(t_linetraverser *t, t_canvas *x);
513EXTERN t_outconnect *linetraverser_next(t_linetraverser *t);
514EXTERN void linetraverser_skipobject(t_linetraverser *t);
515
516/* --------------------- functions on tscalars --------------------- */
517
518EXTERN void tscalar_getrect(t_tscalar *x, t_glist *owner,
519 int *xp1, int *yp1, int *xp2, int *yp2);
520EXTERN void tscalar_vis(t_tscalar *x, t_glist *owner, int flag);
521EXTERN int tscalar_click(t_tscalar *x, int xpix, int ypix, int shift,
522 int alt, int dbl, int doit);
523
524/* --------- functions on garrays (graphical arrays) -------------------- */
525
526EXTERN t_template *garray_template(t_garray *x);
527
528/* -------------------- arrays --------------------- */
529EXTERN t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *tmpl,
530 t_floatarg f, t_floatarg saveit);
531EXTERN t_array *array_new(t_symbol *templatesym, t_gpointer *parent);
532EXTERN void array_resize(t_array *x, t_template *tmpl, int n);
533EXTERN void array_free(t_array *x);
534
535/* --------------------- gpointers and stubs ---------------- */
536EXTERN t_gstub *gstub_new(t_glist *gl, t_array *a);
537EXTERN void gstub_cutoff(t_gstub *gs);
538EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x);
539
540/* --------------------- scalars ------------------------- */
541EXTERN void word_init(t_word *wp, t_template *tmpl, t_gpointer *gp);
542EXTERN void word_restore(t_word *wp, t_template *tmpl,
543 int argc, t_atom *argv);
544EXTERN t_scalar *scalar_new(t_glist *owner,
545 t_symbol *templatesym);
546EXTERN void scalar_getbasexy(t_scalar *x, float *basex, float *basey);
547
548/* ------helper routines for "garrays" and "plots" -------------- */
549EXTERN int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
550 t_symbol *elemtemplatesym,
551 float linewidth, float xloc, float xinc, float yloc,
552 int xpix, int ypix, int shift, int alt, int dbl, int doit);
553
554EXTERN void array_getcoordinate(t_glist *glist,
555 char *elem, int xonset, int yonset, int wonset, int indx,
556 float basex, float basey, float xinc,
557 float *xp, float *yp, float *wp);
558
559EXTERN int array_getfields(t_symbol *elemtemplatesym,
560 t_canvas **elemtemplatecanvasp,
561 t_template **elemtemplatep, int *elemsizep,
562 int *xonsetp, int *yonsetp, int *wonsetp);
563
564/* --------------------- templates ------------------------- */
565EXTERN t_template *template_new(t_symbol *sym, int argc, t_atom *argv);
566EXTERN void template_free(t_template *x);
567EXTERN int template_match(t_template *x1, t_template *x2);
568EXTERN int template_find_field(t_template *x, t_symbol *name, int *p_onset,
569 int *p_type, t_symbol **p_arraytype);
570EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
571 int loud);
572EXTERN void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
573 t_float f, int loud);
574EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
575 t_word *wp, int loud);
576EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
577 t_word *wp, t_symbol *s, int loud);
578
579EXTERN t_template *gtemplate_get(t_gtemplate *x);
580EXTERN t_template *template_findbyname(t_symbol *s);
581EXTERN t_canvas *template_findcanvas(t_template *tmpl);
582
583EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname,
584 t_word *wp, int loud);
585EXTERN void template_setfloat(t_template *x, t_symbol *fieldname,
586 t_word *wp, t_float f, int loud);
587EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
588 t_word *wp, int loud);
589EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
590 t_word *wp, t_symbol *s, int loud);
591
592/* ----------------------- guiconnects, g_guiconnect.c --------- */
593EXTERN t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym);
594EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay);
595
596/* ------------- IEMGUI routines used in other g_ files ---------------- */
597EXTERN t_symbol *iemgui_raute2dollar(t_symbol *s);
598EXTERN t_symbol *iemgui_dollar2raute(t_symbol *s);
599
600#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
601}
602#endif
603/* Copyright (c) 1997-1999 Miller Puckette.
604* For information on usage and redistribution, and for a DISCLAIMER OF ALL
605* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
606
607/* this file defines the structure for "glists" and related structures and
608functions. "Glists" and "canvases" and "graphs" used to be different
609structures until being unified in version 0.35.
610
611A glist occupies its own window if the "gl_havewindow" flag is set. Its
612appearance on its "parent" or "owner" (if it has one) is as a graph if
613"gl_isgraph" is set, and otherwise as a text box.
614
615A glist is "root" if it has no owner, i.e., a document window. In this
616case "gl_havewindow" is always set.
617
618We maintain a list of root windows, so that we can traverse the whole
619collection of everything in a Pd process.
620
621If a glist has a window it may still not be "mapped." Miniaturized
622windows aren't mapped, for example, but a window is also not mapped
623immediately upon creation. In either case gl_havewindow is true but
624gl_mapped is false.
625
626Closing a non-root window makes it invisible; closing a root destroys it.
627
628A glist that's just a text object on its parent is always "toplevel." An
629embedded glist can switch back and forth to appear as a toplevel by double-
630clicking on it. Single-clicking a text box makes the toplevel become visible
631and raises the window it's in.
632
633If a glist shows up as a graph on its parent, the graph is blanked while the
634glist has its own window, even if miniaturized.
635
636*/
637
638/* NOTE: this file describes Pd implementation details which may change
639in future releases. The public (stable) API is in m_pd.h. */
640
641#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
642extern "C" {
643#endif
644
645/* --------------------- geometry ---------------------------- */
646#define IOWIDTH 7 /* width of an inlet/outlet in pixels */
647#define IOMIDDLE ((IOWIDTH-1)/2)
648#define GLIST_DEFGRAPHWIDTH 200
649#define GLIST_DEFGRAPHHEIGHT 140
650/* ----------------------- data ------------------------------- */
651
652typedef struct _updateheader
653{
654 struct _updateheader *upd_next;
655 unsigned int upd_array:1; /* true if array, false if glist */
656 unsigned int upd_queued:1; /* true if we're queued */
657} t_updateheader;
658
659 /* types to support glists grabbing mouse motion or keys from parent */
660typedef void (*t_glistmotionfn)(void *z, t_floatarg dx, t_floatarg dy);
661typedef void (*t_glistkeyfn)(void *z, t_floatarg key);
662
663EXTERN_STRUCT _rtext;
664#define t_rtext struct _rtext
665
666EXTERN_STRUCT _gtemplate;
667#define t_gtemplate struct _gtemplate
668
669EXTERN_STRUCT _guiconnect;
670#define t_guiconnect struct _guiconnect
671
672EXTERN_STRUCT _tscalar;
673#define t_tscalar struct _tscalar
674
675EXTERN_STRUCT _canvasenvironment;
676#define t_canvasenvironment struct _canvasenvironment
677
678typedef struct _selection
679{
680 t_gobj *sel_what;
681 struct _selection *sel_next;
682} t_selection;
683
684 /* this structure is instantiated whenever a glist becomes visible. */
685typedef struct _editor
686{
687 t_updateheader e_upd; /* update header structure */
688 t_selection *e_updlist; /* list of objects to update */
689 t_rtext *e_rtext; /* text responder linked list */
690 t_selection *e_selection; /* head of the selection list */
691 t_rtext *e_textedfor; /* the rtext if any that we are editing */
692 t_gobj *e_grab; /* object being "dragged" */
693 t_glistmotionfn e_motionfn; /* ... motion callback */
694 t_glistkeyfn e_keyfn; /* ... keypress callback */
695 t_binbuf *e_connectbuf; /* connections to deleted objects */
696 t_binbuf *e_deleted; /* last stuff we deleted */
697 t_guiconnect *e_guiconnect; /* GUI connection for filtering messages */
698 struct _glist *e_glist; /* glist which owns this */
699 int e_xwas; /* xpos on last mousedown or motion event */
700 int e_ywas; /* ypos, similarly */
701 int e_selectline_index1; /* indices for the selected line if any */
702 int e_selectline_outno; /* (only valid if e_selectedline is set) */
703 int e_selectline_index2;
704 int e_selectline_inno;
705 t_outconnect *e_selectline_tag;
706 unsigned int e_onmotion: 3; /* action to take on motion */
707 unsigned int e_lastmoved: 1; /* one if mouse has moved since click */
708 unsigned int e_textdirty: 1; /* one if e_textedfor has changed */
709 unsigned int e_selectedline: 1; /* one if a line is selected */
710} t_editor;
711
712#define MA_NONE 0 /* e_onmotion: do nothing on mouse motion */
713#define MA_MOVE 1 /* drag the selection around */
714#define MA_CONNECT 2 /* make a connection */
715#define MA_REGION 3 /* selection region */
716#define MA_PASSOUT 4 /* send on to e_grab */
717#define MA_DRAGTEXT 5 /* drag in text editor to alter selection */
718
719/* editor structure for "garrays". We don't bother to delete and regenerate
720this structure when the "garray" becomes invisible or visible, although we
721could do so if the structure gets big (like the "editor" above.) */
722
723typedef struct _arrayvis
724{
725 t_updateheader av_upd; /* update header structure */
726 t_garray *av_garray; /* owning structure */
727} t_arrayvis;
728
729/* the t_tick structure describes where to draw x and y "ticks" for a glist */
730
731typedef struct _tick /* where to put ticks on x or y axes */
732{
733 float k_point; /* one point to draw a big tick at */
734 float k_inc; /* x or y increment per little tick */
735 int k_lperb; /* little ticks per big; 0 if no ticks to draw */
736} t_tick;
737
738/* the t_glist structure, which describes a list of elements that live on an
739area of a window.
740
741*/
742
743struct _glist
744{
745 t_object gl_obj; /* header in case we're a glist */
746 t_gobj *gl_list; /* the actual data */
747 struct _gstub *gl_stub; /* safe pointer handler */
748 int gl_valid; /* incremented when pointers might be stale */
749 struct _glist *gl_owner; /* parent glist, supercanvas, or 0 if none */
750 int gl_pixwidth; /* width in pixels (on parent, if a graph) */
751 int gl_pixheight;
752 float gl_x1; /* bounding rectangle in our own coordinates */
753 float gl_y1;
754 float gl_x2;
755 float gl_y2;
756 int gl_screenx1; /* screen coordinates when toplevel */
757 int gl_screeny1;
758 int gl_screenx2;
759 int gl_screeny2;
760 t_tick gl_xtick; /* ticks marking X values */
761 int gl_nxlabels; /* number of X coordinate labels */
762 t_symbol **gl_xlabel; /* ... an array to hold them */
763 float gl_xlabely; /* ... and their Y coordinates */
764 t_tick gl_ytick; /* same as above for Y ticks and labels */
765 int gl_nylabels;
766 t_symbol **gl_ylabel;
767 float gl_ylabelx;
768 t_editor *gl_editor; /* editor structure when visible */
769 t_symbol *gl_name; /* symbol bound here */
770 int gl_font; /* nominal font size in points, e.g., 10 */
771 struct _glist *gl_next; /* link in list of toplevels */
772 t_canvasenvironment *gl_env; /* root canvases and abstractions only */
773 unsigned int gl_havewindow:1; /* true if we own a window */
774 unsigned int gl_mapped:1; /* true if, moreover, it's "mapped" */
775 unsigned int gl_dirty:1; /* (root canvas only:) patch has changed */
776 unsigned int gl_loading:1; /* am now loading from file */
777 unsigned int gl_willvis:1; /* make me visible after loading */
778 unsigned int gl_edit:1; /* edit mode */
779 unsigned int gl_isdeleting:1; /* we're inside glist_delete -- hack! */
780 unsigned int gl_stretch:1; /* stretch contents on resize */
781 unsigned int gl_isgraph:1; /* show as graph on parent */
782};
783
784#define gl_gobj gl_obj.te_g
785#define gl_pd gl_gobj.g_pd
786
787/* a data structure to describe a field in a pure datum */
788
789#define DT_FLOAT 0
790#define DT_SYMBOL 1
791#define DT_LIST 2
792#define DT_ARRAY 3
793
794typedef struct _dataslot
795{
796 int ds_type;
797 t_symbol *ds_name;
798 t_symbol *ds_arraytemplate; /* filled in for arrays only */
799} t_dataslot;
800
801
802/* T.Grill - changed t_pd member to t_pdobj to avoid name clashed */
803typedef struct _template
804{
805 t_pd t_pdobj; /* header */
806 struct _gtemplate *t_list; /* list of "struct"/gtemplate objects */
807 t_symbol *t_sym; /* name */
808 int t_n; /* number of dataslots (fields) */
809 t_dataslot *t_vec; /* array of dataslots */
810} t_template;
811
812struct _array
813{
814 int a_n; /* number of elements */
815 int a_elemsize; /* size in bytes; LATER get this from template */
816 char *a_vec; /* array of elements */
817 t_symbol *a_templatesym; /* template for elements */
818 int a_valid; /* protection against stale pointers into array */
819 t_gpointer a_gp; /* pointer to scalar or array element we're in */
820 t_gstub *a_stub;
821};
822
823 /* structure for traversing all the connections in a glist */
824typedef struct _linetraverser
825{
826 t_canvas *tr_x;
827 t_object *tr_ob;
828 int tr_nout;
829 int tr_outno;
830 t_object *tr_ob2;
831 t_outlet *tr_outlet;
832 t_inlet *tr_inlet;
833 int tr_nin;
834 int tr_inno;
835 int tr_x11, tr_y11, tr_x12, tr_y12;
836 int tr_x21, tr_y21, tr_x22, tr_y22;
837 int tr_lx1, tr_ly1, tr_lx2, tr_ly2;
838 t_outconnect *tr_nextoc;
839 int tr_nextoutno;
840} t_linetraverser;
841
842/* function types used to define graphical behavior for gobjs, a bit like X
843widgets. We don't use Pd methods because Pd's typechecking can't specify the
844types of pointer arguments. Also it's more convenient this way, since
845every "patchable" object can just get the "text" behaviors. */
846
847 /* Call this to get a gobj's bounding rectangle in pixels */
848typedef void (*t_getrectfn)(t_gobj *x, struct _glist *glist,
849 int *x1, int *y1, int *x2, int *y2);
850 /* and this to displace a gobj: */
851typedef void (*t_displacefn)(t_gobj *x, struct _glist *glist, int dx, int dy);
852 /* change color to show selection: */
853typedef void (*t_selectfn)(t_gobj *x, struct _glist *glist, int state);
854 /* change appearance to show activation/deactivation: */
855typedef void (*t_activatefn)(t_gobj *x, struct _glist *glist, int state);
856 /* warn a gobj it's about to be deleted */
857typedef void (*t_deletefn)(t_gobj *x, struct _glist *glist);
858 /* making visible or invisible */
859typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag);
860 /* field a mouse click (when not in "edit" mode) */
861typedef int (*t_clickfn)(t_gobj *x, struct _glist *glist,
862 int xpix, int ypix, int shift, int alt, int dbl, int doit);
863 /* ... and later, resizing; getting/setting font or color... */
864
865struct _widgetbehavior
866{
867 t_getrectfn w_getrectfn;
868 t_displacefn w_displacefn;
869 t_selectfn w_selectfn;
870 t_activatefn w_activatefn;
871 t_deletefn w_deletefn;
872 t_visfn w_visfn;
873 t_clickfn w_clickfn;
874};
875
876/* -------- behaviors for scalars defined by objects in template --------- */
877/* these are set by "drawing commands" in g_template.c which add appearance to
878scalars, which live in some other window. If the scalar is just included
879in a canvas the "parent" is a misnomer. There is also a text scalar object
880which really does draw the scalar on the parent window; see g_scalar.c. */
881
882/* note how the click function wants the whole scalar, not the "data", so
883doesn't work on array elements... LATER reconsider this */
884
885 /* bounding rectangle: */
886typedef void (*t_parentgetrectfn)(t_gobj *x, struct _glist *glist,
887 t_word *data, t_template *tmpl, float basex, float basey,
888 int *x1, int *y1, int *x2, int *y2);
889 /* displace it */
890typedef void (*t_parentdisplacefn)(t_gobj *x, struct _glist *glist,
891 t_word *data, t_template *tmpl, float basex, float basey,
892 int dx, int dy);
893 /* change color to show selection */
894typedef void (*t_parentselectfn)(t_gobj *x, struct _glist *glist,
895 t_word *data, t_template *tmpl, float basex, float basey,
896 int state);
897 /* change appearance to show activation/deactivation: */
898typedef void (*t_parentactivatefn)(t_gobj *x, struct _glist *glist,
899 t_word *data, t_template *tmpl, float basex, float basey,
900 int state);
901 /* making visible or invisible */
902typedef void (*t_parentvisfn)(t_gobj *x, struct _glist *glist,
903 t_word *data, t_template *tmpl, float basex, float basey,
904 int flag);
905 /* field a mouse click */
906typedef int (*t_parentclickfn)(t_gobj *x, struct _glist *glist,
907 t_scalar *sc, t_template *tmpl, float basex, float basey,
908 int xpix, int ypix, int shift, int alt, int dbl, int doit);
909
910struct _parentwidgetbehavior
911{
912 t_parentgetrectfn w_parentgetrectfn;
913 t_parentdisplacefn w_parentdisplacefn;
914 t_parentselectfn w_parentselectfn;
915 t_parentactivatefn w_parentactivatefn;
916 t_parentvisfn w_parentvisfn;
917 t_parentclickfn w_parentclickfn;
918};
919
920 /* cursor definitions; used as return value for t_parentclickfn */
921#define CURSOR_RUNMODE_NOTHING 0
922#define CURSOR_RUNMODE_CLICKME 1
923#define CURSOR_RUNMODE_THICKEN 2
924#define CURSOR_RUNMODE_ADDPOINT 3
925#define CURSOR_EDITMODE_NOTHING 4
926#define CURSOR_EDITMODE_CONNECT 5
927#define CURSOR_EDITMODE_DISCONNECT 6
928EXTERN void canvas_setcursor(t_glist *x, unsigned int cursornum);
929
930extern t_canvas *canvas_editing; /* last canvas to start text edting */
931extern t_canvas *canvas_whichfind; /* last canvas we did a find in */
932extern t_canvas *canvas_list; /* list of all root canvases */
933extern t_class *vinlet_class, *voutlet_class;
934extern int glist_valid; /* incremented when pointers might be stale */
935
936/* ------------------- functions on any gobj ----------------------------- */
937EXTERN void gobj_getrect(t_gobj *x, t_glist *owner, int *x1, int *y1,
938 int *x2, int *y2);
939EXTERN void gobj_displace(t_gobj *x, t_glist *owner, int dx, int dy);
940EXTERN void gobj_select(t_gobj *x, t_glist *owner, int state);
941EXTERN void gobj_activate(t_gobj *x, t_glist *owner, int state);
942EXTERN void gobj_delete(t_gobj *x, t_glist *owner);
943EXTERN void gobj_vis(t_gobj *x, t_glist *glist, int flag);
944EXTERN int gobj_click(t_gobj *x, struct _glist *glist,
945 int xpix, int ypix, int shift, int alt, int dbl, int doit);
946EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
947EXTERN void gobj_properties(t_gobj *x, struct _glist *glist);
948EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
949
950/* -------------------- functions on glists --------------------- */
951EXTERN t_glist *glist_new( void);
952EXTERN void glist_init(t_glist *x);
953EXTERN void glist_add(t_glist *x, t_gobj *g);
954EXTERN void glist_cleanup(t_glist *x);
955EXTERN void glist_free(t_glist *x);
956
957EXTERN void glist_clear(t_glist *x);
958EXTERN t_canvas *glist_getcanvas(t_glist *x);
959EXTERN int glist_isselected(t_glist *x, t_gobj *y);
960EXTERN void glist_select(t_glist *x, t_gobj *y);
961EXTERN void glist_deselect(t_glist *x, t_gobj *y);
962EXTERN void glist_noselect(t_glist *x);
963EXTERN void glist_selectall(t_glist *x);
964EXTERN void glist_delete(t_glist *x, t_gobj *y);
965EXTERN void glist_retext(t_glist *x, t_text *y);
966EXTERN void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
967 t_glistkeyfn keyfn, int xpos, int ypos);
968EXTERN int glist_isvisible(t_glist *x);
969EXTERN int glist_istoplevel(t_glist *x);
970EXTERN t_glist *glist_findgraph(t_glist *x);
971EXTERN int glist_getfont(t_glist *x);
972EXTERN void glist_sort(t_glist *canvas);
973EXTERN void glist_read(t_glist *x, t_symbol *filename, t_symbol *format);
974EXTERN void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format);
975
976EXTERN float glist_pixelstox(t_glist *x, float xpix);
977EXTERN float glist_pixelstoy(t_glist *x, float ypix);
978EXTERN float glist_xtopixels(t_glist *x, float xval);
979EXTERN float glist_ytopixels(t_glist *x, float yval);
980EXTERN float glist_dpixtodx(t_glist *x, float dxpix);
981EXTERN float glist_dpixtody(t_glist *x, float dypix);
982
983EXTERN void glist_redrawitem(t_glist *owner, t_gobj *gobj);
984EXTERN void glist_getnextxy(t_glist *gl, int *xval, int *yval);
985EXTERN void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv);
986EXTERN t_glist *glist_addglist(t_glist *g, t_symbol *sym,
987 float x1, float y1, float x2, float y2,
988 float px1, float py1, float px2, float py2);
989EXTERN void glist_arraydialog(t_glist *parent, t_symbol *name,
990 t_floatarg size, t_floatarg saveit, t_floatarg newgraph);
991EXTERN t_binbuf *glist_writetobinbuf(t_glist *x, int wholething);
992EXTERN int glist_isgraph(t_glist *x);
993EXTERN void glist_redraw(t_glist *x);
994EXTERN void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
995 char *tag, int x1, int y1, int x2, int y2);
996EXTERN void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag);
997EXTERN void canvas_create_editor(t_glist *x, int createit);
998void canvas_deletelinesforio(t_canvas *x, t_text *text,
999 t_inlet *inp, t_outlet *outp);
1000
1001
1002/* -------------------- functions on texts ------------------------- */
1003EXTERN void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize);
1004EXTERN void text_drawborder(t_text *x, t_glist *glist, char *tag,
1005 int width, int height, int firsttime);
1006EXTERN void text_eraseborder(t_text *x, t_glist *glist, char *tag);
1007EXTERN int text_xcoord(t_text *x, t_glist *glist);
1008EXTERN int text_ycoord(t_text *x, t_glist *glist);
1009EXTERN int text_xpix(t_text *x, t_glist *glist);
1010EXTERN int text_ypix(t_text *x, t_glist *glist);
1011EXTERN int text_shouldvis(t_text *x, t_glist *glist);
1012
1013/* -------------------- functions on rtexts ------------------------- */
1014#define RTEXT_DOWN 1
1015#define RTEXT_DRAG 2
1016#define RTEXT_DBL 3
1017#define RTEXT_SHIFT 4
1018
1019EXTERN t_rtext *rtext_new(t_glist *glist, t_text *who);
1020EXTERN t_rtext *glist_findrtext(t_glist *gl, t_text *who);
1021EXTERN void rtext_draw(t_rtext *x);
1022EXTERN void rtext_erase(t_rtext *x);
1023EXTERN t_rtext *rtext_remove(t_rtext *first, t_rtext *x);
1024EXTERN int rtext_height(t_rtext *x);
1025EXTERN void rtext_displace(t_rtext *x, int dx, int dy);
1026EXTERN void rtext_select(t_rtext *x, int state);
1027EXTERN void rtext_activate(t_rtext *x, int state);
1028EXTERN void rtext_free(t_rtext *x);
1029EXTERN void rtext_key(t_rtext *x, int n, t_symbol *s);
1030EXTERN void rtext_mouse(t_rtext *x, int xval, int yval, int flag);
1031EXTERN void rtext_retext(t_rtext *x);
1032EXTERN int rtext_width(t_rtext *x);
1033EXTERN int rtext_height(t_rtext *x);
1034EXTERN char *rtext_gettag(t_rtext *x);
1035EXTERN void rtext_gettext(t_rtext *x, char **buf, int *bufsize);
1036
1037/* -------------------- functions on canvases ------------------------ */
1038EXTERN t_class *canvas_class;
1039
1040EXTERN t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv);
1041EXTERN t_symbol *canvas_makebindsym(t_symbol *s);
1042EXTERN void canvas_vistext(t_canvas *x, t_text *y);
1043EXTERN void canvas_fixlinesfor(t_canvas *x, t_text *text);
1044EXTERN void canvas_deletelinesfor(t_canvas *x, t_text *text);
1045EXTERN void canvas_stowconnections(t_canvas *x);
1046EXTERN void canvas_restoreconnections(t_canvas *x);
1047EXTERN void canvas_redraw(t_canvas *x);
1048
1049EXTERN t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *sym);
1050EXTERN void canvas_rminlet(t_canvas *x, t_inlet *ip);
1051EXTERN t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *sym);
1052EXTERN void canvas_rmoutlet(t_canvas *x, t_outlet *op);
1053EXTERN void canvas_redrawallfortemplate(t_canvas *tmpl);
1054EXTERN void canvas_zapallfortemplate(t_canvas *tmpl);
1055EXTERN void canvas_setusedastemplate(t_canvas *x);
1056EXTERN t_canvas *canvas_getcurrent(void);
1057EXTERN void canvas_setcurrent(t_canvas *x);
1058EXTERN void canvas_unsetcurrent(t_canvas *x);
1059EXTERN t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s);
1060EXTERN t_canvas *canvas_getrootfor(t_canvas *x);
1061EXTERN void canvas_dirty(t_canvas *x, t_int n);
1062EXTERN int canvas_getfont(t_canvas *x);
1063typedef int (*t_canvasapply)(t_canvas *x, t_int x1, t_int x2, t_int x3);
1064
1065EXTERN t_int *canvas_recurapply(t_canvas *x, t_canvasapply *fn,
1066 t_int x1, t_int x2, t_int x3);
1067
1068EXTERN void canvas_resortinlets(t_canvas *x);
1069EXTERN void canvas_resortoutlets(t_canvas *x);
1070EXTERN void canvas_free(t_canvas *x);
1071EXTERN void canvas_updatewindowlist( void);
1072EXTERN void canvas_editmode(t_canvas *x, t_floatarg yesplease);
1073EXTERN int canvas_isabstraction(t_canvas *x);
1074EXTERN int canvas_istable(t_canvas *x);
1075EXTERN int canvas_showtext(t_canvas *x);
1076EXTERN void canvas_vis(t_canvas *x, t_floatarg f);
1077EXTERN t_canvasenvironment *canvas_getenv(t_canvas *x);
1078EXTERN void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir);
1079EXTERN void canvas_loadbang(t_canvas *x);
1080EXTERN int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos,
1081 int *x1p, int *y1p, int *x2p, int *y2p);
1082EXTERN int canvas_setdeleting(t_canvas *x, int flag);
1083
1084typedef void (*t_undofn)(t_canvas *canvas, void *buf,
1085 int action); /* a function that does UNDO/REDO */
1086#define UNDO_FREE 0 /* free current undo/redo buffer */
1087#define UNDO_UNDO 1 /* undo */
1088#define UNDO_REDO 2 /* redo */
1089EXTERN void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
1090 const char *name);
1091EXTERN void canvas_noundo(t_canvas *x);
1092EXTERN int canvas_getindex(t_canvas *x, t_gobj *y);
1093
1094/* T.Grill - made public for dynamic object creation */
1095/* in g_editor.c */
1096EXTERN void canvas_connect(t_canvas *x,
1097 t_floatarg fwhoout, t_floatarg foutno,t_floatarg fwhoin, t_floatarg finno);
1098EXTERN void canvas_disconnect(t_canvas *x,
1099 float index1, float outno, float index2, float inno);
1100EXTERN int canvas_isconnected (t_canvas *x,
1101 t_text *ob1, int n1, t_text *ob2, int n2);
1102EXTERN void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy);
1103
1104
1105/* ---- functions on canvasses as objects --------------------- */
1106
1107EXTERN void canvas_fattenforscalars(t_canvas *x,
1108 int *x1, int *y1, int *x2, int *y2);
1109EXTERN void canvas_visforscalars(t_canvas *x, t_glist *glist, int vis);
1110EXTERN int canvas_clicksub(t_canvas *x, int xpix, int ypix, int shift,
1111 int alt, int dbl, int doit);
1112EXTERN t_glist *canvas_getglistonsuper(void);
1113
1114EXTERN void linetraverser_start(t_linetraverser *t, t_canvas *x);
1115EXTERN t_outconnect *linetraverser_next(t_linetraverser *t);
1116EXTERN void linetraverser_skipobject(t_linetraverser *t);
1117
1118/* --------------------- functions on tscalars --------------------- */
1119
1120EXTERN void tscalar_getrect(t_tscalar *x, t_glist *owner,
1121 int *xp1, int *yp1, int *xp2, int *yp2);
1122EXTERN void tscalar_vis(t_tscalar *x, t_glist *owner, int flag);
1123EXTERN int tscalar_click(t_tscalar *x, int xpix, int ypix, int shift,
1124 int alt, int dbl, int doit);
1125
1126/* --------- functions on garrays (graphical arrays) -------------------- */
1127
1128EXTERN t_template *garray_template(t_garray *x);
1129
1130/* -------------------- arrays --------------------- */
1131EXTERN t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *tmpl,
1132 t_floatarg f, t_floatarg saveit);
1133EXTERN t_array *array_new(t_symbol *templatesym, t_gpointer *parent);
1134EXTERN void array_resize(t_array *x, t_template *tmpl, int n);
1135EXTERN void array_free(t_array *x);
1136
1137/* --------------------- gpointers and stubs ---------------- */
1138EXTERN t_gstub *gstub_new(t_glist *gl, t_array *a);
1139EXTERN void gstub_cutoff(t_gstub *gs);
1140EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x);
1141
1142/* --------------------- scalars ------------------------- */
1143EXTERN void word_init(t_word *wp, t_template *tmpl, t_gpointer *gp);
1144EXTERN void word_restore(t_word *wp, t_template *tmpl,
1145 int argc, t_atom *argv);
1146EXTERN t_scalar *scalar_new(t_glist *owner,
1147 t_symbol *templatesym);
1148EXTERN void scalar_getbasexy(t_scalar *x, float *basex, float *basey);
1149
1150/* ------helper routines for "garrays" and "plots" -------------- */
1151EXTERN int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
1152 t_symbol *elemtemplatesym,
1153 float linewidth, float xloc, float xinc, float yloc,
1154 int xpix, int ypix, int shift, int alt, int dbl, int doit);
1155
1156EXTERN void array_getcoordinate(t_glist *glist,
1157 char *elem, int xonset, int yonset, int wonset, int indx,
1158 float basex, float basey, float xinc,
1159 float *xp, float *yp, float *wp);
1160
1161EXTERN int array_getfields(t_symbol *elemtemplatesym,
1162 t_canvas **elemtemplatecanvasp,
1163 t_template **elemtemplatep, int *elemsizep,
1164 int *xonsetp, int *yonsetp, int *wonsetp);
1165
1166/* --------------------- templates ------------------------- */
1167EXTERN t_template *template_new(t_symbol *sym, int argc, t_atom *argv);
1168EXTERN void template_free(t_template *x);
1169EXTERN int template_match(t_template *x1, t_template *x2);
1170EXTERN int template_find_field(t_template *x, t_symbol *name, int *p_onset,
1171 int *p_type, t_symbol **p_arraytype);
1172EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
1173 int loud);
1174EXTERN void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
1175 t_float f, int loud);
1176EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
1177 t_word *wp, int loud);
1178EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
1179 t_word *wp, t_symbol *s, int loud);
1180
1181EXTERN t_template *gtemplate_get(t_gtemplate *x);
1182EXTERN t_template *template_findbyname(t_symbol *s);
1183EXTERN t_canvas *template_findcanvas(t_template *tmpl);
1184
1185EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname,
1186 t_word *wp, int loud);
1187EXTERN void template_setfloat(t_template *x, t_symbol *fieldname,
1188 t_word *wp, t_float f, int loud);
1189EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
1190 t_word *wp, int loud);
1191EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
1192 t_word *wp, t_symbol *s, int loud);
1193
1194/* ----------------------- guiconnects, g_guiconnect.c --------- */
1195EXTERN t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym);
1196EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay);
1197
1198/* ------------- IEMGUI routines used in other g_ files ---------------- */
1199EXTERN t_symbol *iemgui_raute2dollar(t_symbol *s);
1200EXTERN t_symbol *iemgui_dollar2raute(t_symbol *s);
1201
1202#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
1203}
1204#endif
diff --git a/apps/plugins/pdbox/PDa/extra/gcanvas-help.pd b/apps/plugins/pdbox/PDa/extra/gcanvas-help.pd
new file mode 100644
index 0000000000..e0e3fd6f4d
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/gcanvas-help.pd
@@ -0,0 +1,16 @@
1#N canvas 0 0 240 300 8;
2#X obj 21 61 gcanvas 80 80;
3#X text 14 9 gcanvas .. mouse coordinate enabled canvas;
4#X text 13 22 ==========================================;
5#X floatatom 21 148 5 0 0 0 - - -;
6#X floatatom 94 147 5 0 0 0 - - -;
7#X connect 0 0 3 0;
8#X connect 0 1 4 0;
9#N canvas 0 0 240 300 8;
10#X obj 21 61 gcanvas 80 80;
11#X text 14 9 gcanvas .. mouse coordinate enabled canvas;
12#X text 13 22 ==========================================;
13#X floatatom 21 148 5 0 0 0 - - -;
14#X floatatom 94 147 5 0 0 0 - - -;
15#X connect 0 0 3 0;
16#X connect 0 1 4 0;
diff --git a/apps/plugins/pdbox/PDa/extra/gcanvas.c b/apps/plugins/pdbox/PDa/extra/gcanvas.c
new file mode 100644
index 0000000000..aed5c96cec
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/gcanvas.c
@@ -0,0 +1,758 @@
1/* (C) Guenter Geiger <geiger@xdv.org> */
2
3
4#include "m_pd.h"
5#include "g_canvas.h"
6
7/* ------------------------ gcanvas ----------------------------- */
8
9
10#define BACKGROUNDCOLOR "grey"
11
12#define DEFAULTSIZE 80
13
14static t_class *gcanvas_class;
15
16typedef struct _gcanvas
17{
18 t_object x_obj;
19 t_glist * x_glist;
20 t_outlet* out2;
21 t_outlet* out3;
22 int x_width;
23 int x_height;
24 int x;
25 int y;
26 int x_xgrid;
27 int x_ygrid;
28} t_gcanvas;
29
30
31static void rectangle(void* cv,void* o,char c,int x, int y,int w,int h,char* color) {
32 sys_vgui(".x%x.c create rectangle \
33 %d %d %d %d -tags %x%c -fill %s\n",cv,x,y,x+w,y+h,o,c,color);
34}
35
36static void move_object(void* cv,void* o,char c,int x, int y,int w,int h) {
37 sys_vgui(".x%x.c coords %x%c %d %d %d %d\n",
38 cv,o,c,x,y,x+w,y+h);
39
40}
41
42static void color_object(void* cv,void* o,char c,char* color) {
43 sys_vgui(".x%x.c itemconfigure %x%c -fill %s\n", cv,
44 o, c,color);
45}
46
47static void delete_object(void* cv,void* o,char c) {
48 sys_vgui(".x%x.c delete %x%c\n",
49 cv, o,c);
50}
51
52static void line(void* cv,void* o,char c,int x,int y,int w,int h,char* color) {
53 sys_vgui(".x%x.c create line \
54 %d %d %d %d -tags %x%c -fill %s\n",cv,x,y,x+w,y+h,o,c,color);
55}
56
57
58/* widget helper functions */
59
60void gcanvas_drawme(t_gcanvas *x, t_glist *glist, int firsttime)
61{
62 int i;
63 if (firsttime) {
64 rectangle(glist_getcanvas(glist),x,'a',
65 x->x_obj.te_xpix, x->x_obj.te_ypix,
66 x->x_width, x->x_height,BACKGROUNDCOLOR);
67 for (i=1;i<x->x_xgrid;i++)
68 line(glist_getcanvas(glist),x,'b'+ i,
69 x->x_obj.te_xpix + x->x_width*i/x->x_xgrid,
70 x->x_obj.te_ypix,
71 0, x->x_height,"red");
72 for (i=1;i<x->x_ygrid;i++)
73 line(glist_getcanvas(glist),x,'B'+ i,
74 x->x_obj.te_xpix,
75 x->x_obj.te_ypix + x->x_height*i/x->x_ygrid,
76 x->x_width, 0,"blue");
77 }
78 else {
79 move_object(
80 glist_getcanvas(glist),x,'a',
81 x->x_obj.te_xpix, x->x_obj.te_ypix,
82 x->x_width, x->x_height);
83 for (i=1;i<x->x_xgrid;i++)
84 move_object(glist_getcanvas(glist),x,'b'+ i,
85 x->x_obj.te_xpix + x->x_width*i/x->x_xgrid,
86 x->x_obj.te_ypix,
87 0, x->x_height);
88 for (i=1;i<x->x_ygrid;i++)
89 move_object(glist_getcanvas(glist),x,'B'+ i,
90 x->x_obj.te_xpix,
91 x->x_obj.te_ypix + x->x_height*i/x->x_ygrid,
92 x->x_width, 0);
93 }
94
95 {
96 /* outlets */
97 int n = 3;
98 int nplus, i;
99 nplus = (n == 1 ? 1 : n-1);
100 for (i = 0; i < n; i++)
101 {
102 int onset = x->x_obj.te_xpix + (x->x_width - IOWIDTH) * i / nplus;
103 if (firsttime)
104 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xo%d\n",
105 glist_getcanvas(glist),
106 onset, x->x_obj.te_ypix + x->x_height - 1,
107 onset + IOWIDTH, x->x_obj.te_ypix + x->x_height,
108 x, i);
109 else
110 sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n",
111 glist_getcanvas(glist), x, i,
112 onset, x->x_obj.te_ypix + x->x_height - 1,
113 onset + IOWIDTH, x->x_obj.te_ypix + x->x_height);
114 }
115 /* inlets */
116 n = 0;
117 nplus = (n == 1 ? 1 : n-1);
118 for (i = 0; i < n; i++)
119 {
120 int onset = x->x_obj.te_xpix + (x->x_width - IOWIDTH) * i / nplus;
121 if (firsttime)
122 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xi%d\n",
123 glist_getcanvas(glist),
124 onset, x->x_obj.te_ypix,
125 onset + IOWIDTH, x->x_obj.te_ypix + 1,
126 x, i);
127 else
128 sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n",
129 glist_getcanvas(glist), x, i,
130 onset, x->x_obj.te_ypix,
131 onset + IOWIDTH, x->x_obj.te_ypix + 1);
132
133 }
134 }
135
136}
137
138
139
140
141void gcanvas_erase(t_gcanvas* x,t_glist* glist)
142{
143 int n,i;
144 delete_object(glist_getcanvas(glist),x,'a');
145 for (i=1;i<x->x_xgrid;i++)
146 delete_object(glist_getcanvas(glist),x,'b'+ i);
147 for (i=1;i<x->x_ygrid;i++)
148 delete_object(glist_getcanvas(glist),x,'B'+ i);
149
150 n = 2;
151 while (n--) {
152 sys_vgui(".x%x.c delete %xo%d\n",glist_getcanvas(glist),x,n);
153 }
154}
155
156
157
158/* ------------------------ gcanvas widgetbehaviour----------------------------- */
159
160
161static void gcanvas_getrect(t_gobj *z, t_glist *owner,
162 int *xp1, int *yp1, int *xp2, int *yp2)
163{
164 int width, height;
165 t_gcanvas* s = (t_gcanvas*)z;
166
167
168 width = s->x_width;
169 height = s->x_height;
170 *xp1 = s->x_obj.te_xpix;
171 *yp1 = s->x_obj.te_ypix;
172 *xp2 = s->x_obj.te_xpix + width;
173 *yp2 = s->x_obj.te_ypix + height;
174}
175
176static void gcanvas_displace(t_gobj *z, t_glist *glist,
177 int dx, int dy)
178{
179 t_gcanvas *x = (t_gcanvas *)z;
180 x->x_obj.te_xpix += dx;
181 x->x_obj.te_ypix += dy;
182 gcanvas_drawme(x, glist, 0);
183 canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
184}
185
186static void gcanvas_select(t_gobj *z, t_glist *glist, int state)
187{
188 t_gcanvas *x = (t_gcanvas *)z;
189 color_object(glist,x,'a',state ? "blue" : BACKGROUNDCOLOR);
190}
191
192
193static void gcanvas_activate(t_gobj *z, t_glist *glist, int state)
194{
195/* t_text *x = (t_text *)z;
196 t_rtext *y = glist_findrtext(glist, x);
197 if (z->g_pd != gatom_class) rtext_activate(y, state);*/
198}
199
200static void gcanvas_delete(t_gobj *z, t_glist *glist)
201{
202 t_text *x = (t_text *)z;
203 canvas_deletelinesfor(glist_getcanvas(glist), x);
204}
205
206
207static void gcanvas_vis(t_gobj *z, t_glist *glist, int vis)
208{
209 t_gcanvas* s = (t_gcanvas*)z;
210 if (vis)
211 gcanvas_drawme(s, glist, 1);
212 else
213 gcanvas_erase(s,glist);
214}
215
216/* can we use the normal text save function ?? */
217
218static void gcanvas_save(t_gobj *z, t_binbuf *b)
219{
220 t_gcanvas *x = (t_gcanvas *)z;
221 binbuf_addv(b, "ssiisiiii", gensym("#X"),gensym("obj"),
222 (t_int)x->x_obj.te_xpix, (t_int)x->x_obj.te_ypix,
223 gensym("gcanvas"),x->x_width,x->x_height,
224 x->x_xgrid,
225 x->x_ygrid);
226 binbuf_addv(b, ";");
227}
228
229
230t_widgetbehavior gcanvas_widgetbehavior;
231
232static void gcanvas_motion(t_gcanvas *x, t_floatarg dx, t_floatarg dy)
233{
234 x->x += dx;
235 x->y += dy;
236 outlet_float(x->out2,x->y);
237 outlet_float(x->x_obj.ob_outlet,x->x);
238}
239
240void gcanvas_key(t_gcanvas *x, t_floatarg f)
241{
242 post("key");
243}
244
245
246static void gcanvas_click(t_gcanvas *x,
247 t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl,
248 t_floatarg doit,int up)
249{
250 glist_grab(x->x_glist, &x->x_obj.te_g, (t_glistmotionfn) gcanvas_motion,
251 (t_glistkeyfn) NULL, xpos, ypos);
252
253 x->x = xpos - x->x_obj.te_xpix;
254 x->y = ypos - x->x_obj.te_ypix;
255 outlet_float(x->out2,x->y);
256 outlet_float(x->x_obj.ob_outlet,x->x);
257 outlet_float(x->out3,0);
258}
259
260static int gcanvas_newclick(t_gobj *z, struct _glist *glist,
261 int xpix, int ypix, int shift, int alt, int dbl, int doit)
262{
263 if (doit)
264 gcanvas_click((t_gcanvas *)z, (t_floatarg)xpix, (t_floatarg)ypix,
265 (t_floatarg)shift, 0, (t_floatarg)alt,dbl);
266
267 if (dbl) outlet_float(((t_gcanvas*)z)->out3,1);
268 return (1);
269}
270
271void gcanvas_size(t_gcanvas* x,t_floatarg w,t_floatarg h) {
272 x->x_width = w;
273 x->x_height = h;
274 gcanvas_drawme(x, x->x_glist, 0);
275}
276
277static void gcanvas_setwidget(void)
278{
279 gcanvas_widgetbehavior.w_getrectfn = gcanvas_getrect;
280 gcanvas_widgetbehavior.w_displacefn = gcanvas_displace;
281 gcanvas_widgetbehavior.w_selectfn = gcanvas_select;
282 gcanvas_widgetbehavior.w_activatefn = gcanvas_activate;
283 gcanvas_widgetbehavior.w_deletefn = gcanvas_delete;
284 gcanvas_widgetbehavior.w_visfn = gcanvas_vis;
285 gcanvas_widgetbehavior.w_clickfn = gcanvas_newclick;
286 class_setsavefn(gcanvas_class,gcanvas_save);
287}
288
289
290static void *gcanvas_new(t_symbol* s,t_int ac,t_atom* at)
291{
292 t_gcanvas *x = (t_gcanvas *)pd_new(gcanvas_class);
293
294 x->x_glist = (t_glist*) canvas_getcurrent();
295
296
297 /* Fetch the width */
298
299 x->x_width = DEFAULTSIZE;
300 if (ac-- > 0) {
301 if (at->a_type != A_FLOAT)
302 error("gcanvas: wrong argument type");
303 else
304 x->x_width = atom_getfloat(at++);
305
306 if (x->x_width < 0 || x->x_width > 2000) {
307 error("gcanvas: unallowed width %f",x->x_width);
308 x->x_width = DEFAULTSIZE;
309 }
310 }
311
312 /* Fetch the height */
313
314 x->x_height = DEFAULTSIZE;
315 if (ac-- > 0) {
316 if (at->a_type != A_FLOAT)
317 error("gcanvas: wrong argument type");
318 else
319 x->x_height = atom_getfloat(at++);
320
321 if (x->x_height < 0 || x->x_height > 2000) {
322 error("gcanvas: unallowed height %f",x->x_height);
323 x->x_width = DEFAULTSIZE;
324 }
325 }
326
327 /* Fetch the xgrid */
328
329 x->x_xgrid = 0;
330 if (ac-- > 0) {
331 if (at->a_type != A_FLOAT)
332 error("gcanvas: wrong argument type");
333 else
334 x->x_xgrid = atom_getfloat(at++);
335
336 if (x->x_xgrid < 0 || x->x_xgrid > x->x_width/2) {
337 error("gcanvas: unallowed xgrid %f",x->x_xgrid);
338 x->x_xgrid = 0;
339 }
340 }
341
342 /* Fetch the ygrid */
343
344 x->x_ygrid = 0;
345 if (ac-- > 0) {
346 if (at->a_type != A_FLOAT)
347 error("gcanvas: wrong argument type");
348 else
349 x->x_ygrid = atom_getfloat(at++);
350
351 if (x->x_ygrid < 0 || x->x_ygrid > x->x_height/2) {
352 error("gcanvas: unallowed xgrid %f",x->x_ygrid);
353 x->x_ygrid = 0;
354 }
355 }
356
357 outlet_new(&x->x_obj, &s_float);
358 x->out2 = outlet_new(&x->x_obj, &s_float);
359 x->out3 = outlet_new(&x->x_obj, &s_float);
360 return (x);
361}
362
363
364
365void gcanvas_setup(void)
366{
367 gcanvas_class = class_new(gensym("gcanvas"), (t_newmethod)gcanvas_new, 0,
368 sizeof(t_gcanvas),0, A_GIMME,0);
369
370 class_addmethod(gcanvas_class, (t_method)gcanvas_click, gensym("click"),
371 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
372 class_addmethod(gcanvas_class, (t_method)gcanvas_size, gensym("size"),
373 A_FLOAT, A_FLOAT, 0);
374
375 gcanvas_setwidget();
376 class_setwidget(gcanvas_class,&gcanvas_widgetbehavior);
377}
378
379
380/* (C) Guenter Geiger <geiger@xdv.org> */
381
382
383#include "m_pd.h"
384#include "g_canvas.h"
385
386/* ------------------------ gcanvas ----------------------------- */
387
388
389#define BACKGROUNDCOLOR "grey"
390
391#define DEFAULTSIZE 80
392
393static t_class *gcanvas_class;
394
395typedef struct _gcanvas
396{
397 t_object x_obj;
398 t_glist * x_glist;
399 t_outlet* out2;
400 t_outlet* out3;
401 int x_width;
402 int x_height;
403 int x;
404 int y;
405 int x_xgrid;
406 int x_ygrid;
407} t_gcanvas;
408
409
410static void rectangle(void* cv,void* o,char c,int x, int y,int w,int h,char* color) {
411 sys_vgui(".x%x.c create rectangle \
412 %d %d %d %d -tags %x%c -fill %s\n",cv,x,y,x+w,y+h,o,c,color);
413}
414
415static void move_object(void* cv,void* o,char c,int x, int y,int w,int h) {
416 sys_vgui(".x%x.c coords %x%c %d %d %d %d\n",
417 cv,o,c,x,y,x+w,y+h);
418
419}
420
421static void color_object(void* cv,void* o,char c,char* color) {
422 sys_vgui(".x%x.c itemconfigure %x%c -fill %s\n", cv,
423 o, c,color);
424}
425
426static void delete_object(void* cv,void* o,char c) {
427 sys_vgui(".x%x.c delete %x%c\n",
428 cv, o,c);
429}
430
431static void line(void* cv,void* o,char c,int x,int y,int w,int h,char* color) {
432 sys_vgui(".x%x.c create line \
433 %d %d %d %d -tags %x%c -fill %s\n",cv,x,y,x+w,y+h,o,c,color);
434}
435
436
437/* widget helper functions */
438
439void gcanvas_drawme(t_gcanvas *x, t_glist *glist, int firsttime)
440{
441 int i;
442 if (firsttime) {
443 rectangle(glist_getcanvas(glist),x,'a',
444 x->x_obj.te_xpix, x->x_obj.te_ypix,
445 x->x_width, x->x_height,BACKGROUNDCOLOR);
446 for (i=1;i<x->x_xgrid;i++)
447 line(glist_getcanvas(glist),x,'b'+ i,
448 x->x_obj.te_xpix + x->x_width*i/x->x_xgrid,
449 x->x_obj.te_ypix,
450 0, x->x_height,"red");
451 for (i=1;i<x->x_ygrid;i++)
452 line(glist_getcanvas(glist),x,'B'+ i,
453 x->x_obj.te_xpix,
454 x->x_obj.te_ypix + x->x_height*i/x->x_ygrid,
455 x->x_width, 0,"blue");
456 }
457 else {
458 move_object(
459 glist_getcanvas(glist),x,'a',
460 x->x_obj.te_xpix, x->x_obj.te_ypix,
461 x->x_width, x->x_height);
462 for (i=1;i<x->x_xgrid;i++)
463 move_object(glist_getcanvas(glist),x,'b'+ i,
464 x->x_obj.te_xpix + x->x_width*i/x->x_xgrid,
465 x->x_obj.te_ypix,
466 0, x->x_height);
467 for (i=1;i<x->x_ygrid;i++)
468 move_object(glist_getcanvas(glist),x,'B'+ i,
469 x->x_obj.te_xpix,
470 x->x_obj.te_ypix + x->x_height*i/x->x_ygrid,
471 x->x_width, 0);
472 }
473
474 {
475 /* outlets */
476 int n = 3;
477 int nplus, i;
478 nplus = (n == 1 ? 1 : n-1);
479 for (i = 0; i < n; i++)
480 {
481 int onset = x->x_obj.te_xpix + (x->x_width - IOWIDTH) * i / nplus;
482 if (firsttime)
483 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xo%d\n",
484 glist_getcanvas(glist),
485 onset, x->x_obj.te_ypix + x->x_height - 1,
486 onset + IOWIDTH, x->x_obj.te_ypix + x->x_height,
487 x, i);
488 else
489 sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n",
490 glist_getcanvas(glist), x, i,
491 onset, x->x_obj.te_ypix + x->x_height - 1,
492 onset + IOWIDTH, x->x_obj.te_ypix + x->x_height);
493 }
494 /* inlets */
495 n = 0;
496 nplus = (n == 1 ? 1 : n-1);
497 for (i = 0; i < n; i++)
498 {
499 int onset = x->x_obj.te_xpix + (x->x_width - IOWIDTH) * i / nplus;
500 if (firsttime)
501 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xi%d\n",
502 glist_getcanvas(glist),
503 onset, x->x_obj.te_ypix,
504 onset + IOWIDTH, x->x_obj.te_ypix + 1,
505 x, i);
506 else
507 sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n",
508 glist_getcanvas(glist), x, i,
509 onset, x->x_obj.te_ypix,
510 onset + IOWIDTH, x->x_obj.te_ypix + 1);
511
512 }
513 }
514
515}
516
517
518
519
520void gcanvas_erase(t_gcanvas* x,t_glist* glist)
521{
522 int n,i;
523 delete_object(glist_getcanvas(glist),x,'a');
524 for (i=1;i<x->x_xgrid;i++)
525 delete_object(glist_getcanvas(glist),x,'b'+ i);
526 for (i=1;i<x->x_ygrid;i++)
527 delete_object(glist_getcanvas(glist),x,'B'+ i);
528
529 n = 2;
530 while (n--) {
531 sys_vgui(".x%x.c delete %xo%d\n",glist_getcanvas(glist),x,n);
532 }
533}
534
535
536
537/* ------------------------ gcanvas widgetbehaviour----------------------------- */
538
539
540static void gcanvas_getrect(t_gobj *z, t_glist *owner,
541 int *xp1, int *yp1, int *xp2, int *yp2)
542{
543 int width, height;
544 t_gcanvas* s = (t_gcanvas*)z;
545
546
547 width = s->x_width;
548 height = s->x_height;
549 *xp1 = s->x_obj.te_xpix;
550 *yp1 = s->x_obj.te_ypix;
551 *xp2 = s->x_obj.te_xpix + width;
552 *yp2 = s->x_obj.te_ypix + height;
553}
554
555static void gcanvas_displace(t_gobj *z, t_glist *glist,
556 int dx, int dy)
557{
558 t_gcanvas *x = (t_gcanvas *)z;
559 x->x_obj.te_xpix += dx;
560 x->x_obj.te_ypix += dy;
561 gcanvas_drawme(x, glist, 0);
562 canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
563}
564
565static void gcanvas_select(t_gobj *z, t_glist *glist, int state)
566{
567 t_gcanvas *x = (t_gcanvas *)z;
568 color_object(glist,x,'a',state ? "blue" : BACKGROUNDCOLOR);
569}
570
571
572static void gcanvas_activate(t_gobj *z, t_glist *glist, int state)
573{
574/* t_text *x = (t_text *)z;
575 t_rtext *y = glist_findrtext(glist, x);
576 if (z->g_pd != gatom_class) rtext_activate(y, state);*/
577}
578
579static void gcanvas_delete(t_gobj *z, t_glist *glist)
580{
581 t_text *x = (t_text *)z;
582 canvas_deletelinesfor(glist_getcanvas(glist), x);
583}
584
585
586static void gcanvas_vis(t_gobj *z, t_glist *glist, int vis)
587{
588 t_gcanvas* s = (t_gcanvas*)z;
589 if (vis)
590 gcanvas_drawme(s, glist, 1);
591 else
592 gcanvas_erase(s,glist);
593}
594
595/* can we use the normal text save function ?? */
596
597static void gcanvas_save(t_gobj *z, t_binbuf *b)
598{
599 t_gcanvas *x = (t_gcanvas *)z;
600 binbuf_addv(b, "ssiisiiii", gensym("#X"),gensym("obj"),
601 (t_int)x->x_obj.te_xpix, (t_int)x->x_obj.te_ypix,
602 gensym("gcanvas"),x->x_width,x->x_height,
603 x->x_xgrid,
604 x->x_ygrid);
605 binbuf_addv(b, ";");
606}
607
608
609t_widgetbehavior gcanvas_widgetbehavior;
610
611static void gcanvas_motion(t_gcanvas *x, t_floatarg dx, t_floatarg dy)
612{
613 x->x += dx;
614 x->y += dy;
615 outlet_float(x->out2,x->y);
616 outlet_float(x->x_obj.ob_outlet,x->x);
617}
618
619void gcanvas_key(t_gcanvas *x, t_floatarg f)
620{
621 post("key");
622}
623
624
625static void gcanvas_click(t_gcanvas *x,
626 t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl,
627 t_floatarg doit,int up)
628{
629 glist_grab(x->x_glist, &x->x_obj.te_g, (t_glistmotionfn) gcanvas_motion,
630 (t_glistkeyfn) NULL, xpos, ypos);
631
632 x->x = xpos - x->x_obj.te_xpix;
633 x->y = ypos - x->x_obj.te_ypix;
634 outlet_float(x->out2,x->y);
635 outlet_float(x->x_obj.ob_outlet,x->x);
636 outlet_float(x->out3,0);
637}
638
639static int gcanvas_newclick(t_gobj *z, struct _glist *glist,
640 int xpix, int ypix, int shift, int alt, int dbl, int doit)
641{
642 if (doit)
643 gcanvas_click((t_gcanvas *)z, (t_floatarg)xpix, (t_floatarg)ypix,
644 (t_floatarg)shift, 0, (t_floatarg)alt,dbl);
645
646 if (dbl) outlet_float(((t_gcanvas*)z)->out3,1);
647 return (1);
648}
649
650void gcanvas_size(t_gcanvas* x,t_floatarg w,t_floatarg h) {
651 x->x_width = w;
652 x->x_height = h;
653 gcanvas_drawme(x, x->x_glist, 0);
654}
655
656static void gcanvas_setwidget(void)
657{
658 gcanvas_widgetbehavior.w_getrectfn = gcanvas_getrect;
659 gcanvas_widgetbehavior.w_displacefn = gcanvas_displace;
660 gcanvas_widgetbehavior.w_selectfn = gcanvas_select;
661 gcanvas_widgetbehavior.w_activatefn = gcanvas_activate;
662 gcanvas_widgetbehavior.w_deletefn = gcanvas_delete;
663 gcanvas_widgetbehavior.w_visfn = gcanvas_vis;
664 gcanvas_widgetbehavior.w_clickfn = gcanvas_newclick;
665 class_setsavefn(gcanvas_class,gcanvas_save);
666}
667
668
669static void *gcanvas_new(t_symbol* s,t_int ac,t_atom* at)
670{
671 t_gcanvas *x = (t_gcanvas *)pd_new(gcanvas_class);
672
673 x->x_glist = (t_glist*) canvas_getcurrent();
674
675
676 /* Fetch the width */
677
678 x->x_width = DEFAULTSIZE;
679 if (ac-- > 0) {
680 if (at->a_type != A_FLOAT)
681 error("gcanvas: wrong argument type");
682 else
683 x->x_width = atom_getfloat(at++);
684
685 if (x->x_width < 0 || x->x_width > 2000) {
686 error("gcanvas: unallowed width %f",x->x_width);
687 x->x_width = DEFAULTSIZE;
688 }
689 }
690
691 /* Fetch the height */
692
693 x->x_height = DEFAULTSIZE;
694 if (ac-- > 0) {
695 if (at->a_type != A_FLOAT)
696 error("gcanvas: wrong argument type");
697 else
698 x->x_height = atom_getfloat(at++);
699
700 if (x->x_height < 0 || x->x_height > 2000) {
701 error("gcanvas: unallowed height %f",x->x_height);
702 x->x_width = DEFAULTSIZE;
703 }
704 }
705
706 /* Fetch the xgrid */
707
708 x->x_xgrid = 0;
709 if (ac-- > 0) {
710 if (at->a_type != A_FLOAT)
711 error("gcanvas: wrong argument type");
712 else
713 x->x_xgrid = atom_getfloat(at++);
714
715 if (x->x_xgrid < 0 || x->x_xgrid > x->x_width/2) {
716 error("gcanvas: unallowed xgrid %f",x->x_xgrid);
717 x->x_xgrid = 0;
718 }
719 }
720
721 /* Fetch the ygrid */
722
723 x->x_ygrid = 0;
724 if (ac-- > 0) {
725 if (at->a_type != A_FLOAT)
726 error("gcanvas: wrong argument type");
727 else
728 x->x_ygrid = atom_getfloat(at++);
729
730 if (x->x_ygrid < 0 || x->x_ygrid > x->x_height/2) {
731 error("gcanvas: unallowed xgrid %f",x->x_ygrid);
732 x->x_ygrid = 0;
733 }
734 }
735
736 outlet_new(&x->x_obj, &s_float);
737 x->out2 = outlet_new(&x->x_obj, &s_float);
738 x->out3 = outlet_new(&x->x_obj, &s_float);
739 return (x);
740}
741
742
743
744void gcanvas_setup(void)
745{
746 gcanvas_class = class_new(gensym("gcanvas"), (t_newmethod)gcanvas_new, 0,
747 sizeof(t_gcanvas),0, A_GIMME,0);
748
749 class_addmethod(gcanvas_class, (t_method)gcanvas_click, gensym("click"),
750 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
751 class_addmethod(gcanvas_class, (t_method)gcanvas_size, gensym("size"),
752 A_FLOAT, A_FLOAT, 0);
753
754 gcanvas_setwidget();
755 class_setwidget(gcanvas_class,&gcanvas_widgetbehavior);
756}
757
758
diff --git a/apps/plugins/pdbox/PDa/extra/highpass.c b/apps/plugins/pdbox/PDa/extra/highpass.c
new file mode 100644
index 0000000000..88ba4564e6
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/highpass.c
@@ -0,0 +1,174 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3
4/*
5
6 These filter coefficients computations are taken from
7 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
8
9 written by Robert Bristow-Johnson
10
11*/
12
13#include "m_pd.h"
14#ifdef NT
15#pragma warning( disable : 4244 )
16#pragma warning( disable : 4305 )
17#endif
18#include <math.h>
19#include "filters.h"
20
21
22/* ------------------- highpass ----------------------------*/
23
24static t_class *highpass_class;
25
26void highpass_bang(t_rbjfilter *x)
27{
28 t_atom at[5];
29 t_float omega = e_omega(x->x_freq,x->x_rate);
30 t_float alpha = e_alpha(x->x_bw* 0.01,omega);
31 t_float b1 = -(1 + cos(omega));
32 t_float b0 = -b1/2.;
33 t_float b2 = b0;
34 t_float a0 = 1 + alpha;
35 t_float a1 = -2.*cos(omega);
36 t_float a2 = 1 - alpha;
37
38/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
39
40 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
41 post("highpass: filter unstable -> resetting");
42 a0=1.;a1=0.;a2=0.;
43 b0=1.;b1=0.;b2=0.;
44 }
45
46 SETFLOAT(at,-a1/a0);
47 SETFLOAT(at+1,-a2/a0);
48 SETFLOAT(at+2,b0/a0);
49 SETFLOAT(at+3,b1/a0);
50 SETFLOAT(at+4,b2/a0);
51
52 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
53}
54
55
56void highpass_float(t_rbjfilter *x,t_floatarg f)
57{
58 x->x_freq = f;
59 highpass_bang(x);
60}
61
62
63static void *highpass_new(t_floatarg f,t_floatarg bw)
64{
65 t_rbjfilter *x = (t_rbjfilter *)pd_new(highpass_class);
66
67 x->x_rate = 44100.0;
68 outlet_new(&x->x_obj,&s_float);
69/* floatinlet_new(&x->x_obj, &x->x_gain); */
70 floatinlet_new(&x->x_obj, &x->x_bw);
71 if (f > 0.) x->x_freq = f;
72 if (bw > 0.) x->x_bw = bw;
73 return (x);
74}
75
76
77void highpass_setup(void)
78{
79 highpass_class = class_new(gensym("highpass"), (t_newmethod)highpass_new, 0,
80 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,0);
81 class_addbang(highpass_class,highpass_bang);
82 class_addfloat(highpass_class,highpass_float);
83}
84
85
86
87
88/* (C) Guenter Geiger <geiger@epy.co.at> */
89
90
91/*
92
93 These filter coefficients computations are taken from
94 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
95
96 written by Robert Bristow-Johnson
97
98*/
99
100#include "m_pd.h"
101#ifdef NT
102#pragma warning( disable : 4244 )
103#pragma warning( disable : 4305 )
104#endif
105#include <math.h>
106#include "filters.h"
107
108
109/* ------------------- highpass ----------------------------*/
110
111static t_class *highpass_class;
112
113void highpass_bang(t_rbjfilter *x)
114{
115 t_atom at[5];
116 t_float omega = e_omega(x->x_freq,x->x_rate);
117 t_float alpha = e_alpha(x->x_bw* 0.01,omega);
118 t_float b1 = -(1 + cos(omega));
119 t_float b0 = -b1/2.;
120 t_float b2 = b0;
121 t_float a0 = 1 + alpha;
122 t_float a1 = -2.*cos(omega);
123 t_float a2 = 1 - alpha;
124
125/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
126
127 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
128 post("highpass: filter unstable -> resetting");
129 a0=1.;a1=0.;a2=0.;
130 b0=1.;b1=0.;b2=0.;
131 }
132
133 SETFLOAT(at,-a1/a0);
134 SETFLOAT(at+1,-a2/a0);
135 SETFLOAT(at+2,b0/a0);
136 SETFLOAT(at+3,b1/a0);
137 SETFLOAT(at+4,b2/a0);
138
139 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
140}
141
142
143void highpass_float(t_rbjfilter *x,t_floatarg f)
144{
145 x->x_freq = f;
146 highpass_bang(x);
147}
148
149
150static void *highpass_new(t_floatarg f,t_floatarg bw)
151{
152 t_rbjfilter *x = (t_rbjfilter *)pd_new(highpass_class);
153
154 x->x_rate = 44100.0;
155 outlet_new(&x->x_obj,&s_float);
156/* floatinlet_new(&x->x_obj, &x->x_gain); */
157 floatinlet_new(&x->x_obj, &x->x_bw);
158 if (f > 0.) x->x_freq = f;
159 if (bw > 0.) x->x_bw = bw;
160 return (x);
161}
162
163
164void highpass_setup(void)
165{
166 highpass_class = class_new(gensym("highpass"), (t_newmethod)highpass_new, 0,
167 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,0);
168 class_addbang(highpass_class,highpass_bang);
169 class_addfloat(highpass_class,highpass_float);
170}
171
172
173
174
diff --git a/apps/plugins/pdbox/PDa/extra/highshelf.c b/apps/plugins/pdbox/PDa/extra/highshelf.c
new file mode 100644
index 0000000000..0060d896c2
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/highshelf.c
@@ -0,0 +1,180 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3
4/*
5
6 These filter coefficients computations are taken from
7 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
8
9 written by Robert Bristow-Johnson
10
11*/
12
13#include "m_pd.h"
14#ifdef NT
15#pragma warning( disable : 4244 )
16#pragma warning( disable : 4305 )
17#endif
18#include <math.h>
19#include "filters.h"
20
21
22/* ------------------- highshelf ----------------------------*/
23
24static t_class *highshelf_class;
25
26void highshelf_bang(t_rbjfilter *x)
27{
28 t_atom at[5];
29 t_float omega = e_omega(x->x_freq,x->x_rate);
30 t_float A = e_A(x->x_gain);
31 t_float cs = cos(omega);
32 t_float sn = sin(omega);
33 t_float beta = e_beta(A,x->x_bw* 0.01);
34
35 t_float b0 = A*((A+1) + (A-1)*cs + beta*sn);
36 t_float b1 =-2.*A*((A-1) + (A+1)*cs);
37 t_float b2 = A*((A+1) + (A-1)*cs - beta*sn);
38 t_float a0 = ((A+1) - (A-1)*cs + beta*sn);
39 t_float a1 = 2.*((A-1) - (A+1)*cs);
40 t_float a2 = ((A+1) - (A-1)*cs - beta*sn);
41
42/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw);*/
43
44 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
45 post("highshelf: filter unstable -> resetting");
46 a0=1.;a1=0.;a2=0.;
47 b0=1.;b1=0.;b2=0.;
48 }
49
50 SETFLOAT(at,-a1/a0);
51 SETFLOAT(at+1,-a2/a0);
52 SETFLOAT(at+2,b0/a0);
53 SETFLOAT(at+3,b1/a0);
54 SETFLOAT(at+4,b2/a0);
55
56 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
57}
58
59
60void highshelf_float(t_rbjfilter *x,t_floatarg f)
61{
62 x->x_freq = f;
63 highshelf_bang(x);
64}
65
66
67static void *highshelf_new(t_floatarg f,t_floatarg g,t_floatarg bw)
68{
69 t_rbjfilter *x = (t_rbjfilter *)pd_new(highshelf_class);
70
71 x->x_rate = 44100.0;
72 outlet_new(&x->x_obj,&s_float);
73 floatinlet_new(&x->x_obj, &x->x_gain);
74 floatinlet_new(&x->x_obj, &x->x_bw);
75 if (f > 0.) x->x_freq = f;
76 if (bw > 0.) x->x_bw = bw;
77 if (g != 0.) x->x_gain = g;
78 return (x);
79}
80
81
82void highshelf_setup(void)
83{
84 highshelf_class = class_new(gensym("highshelf"), (t_newmethod)highshelf_new, 0,
85 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
86 class_addbang(highshelf_class,highshelf_bang);
87 class_addfloat(highshelf_class,highshelf_float);
88}
89
90
91/* (C) Guenter Geiger <geiger@epy.co.at> */
92
93
94/*
95
96 These filter coefficients computations are taken from
97 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
98
99 written by Robert Bristow-Johnson
100
101*/
102
103#include "m_pd.h"
104#ifdef NT
105#pragma warning( disable : 4244 )
106#pragma warning( disable : 4305 )
107#endif
108#include <math.h>
109#include "filters.h"
110
111
112/* ------------------- highshelf ----------------------------*/
113
114static t_class *highshelf_class;
115
116void highshelf_bang(t_rbjfilter *x)
117{
118 t_atom at[5];
119 t_float omega = e_omega(x->x_freq,x->x_rate);
120 t_float A = e_A(x->x_gain);
121 t_float cs = cos(omega);
122 t_float sn = sin(omega);
123 t_float beta = e_beta(A,x->x_bw* 0.01);
124
125 t_float b0 = A*((A+1) + (A-1)*cs + beta*sn);
126 t_float b1 =-2.*A*((A-1) + (A+1)*cs);
127 t_float b2 = A*((A+1) + (A-1)*cs - beta*sn);
128 t_float a0 = ((A+1) - (A-1)*cs + beta*sn);
129 t_float a1 = 2.*((A-1) - (A+1)*cs);
130 t_float a2 = ((A+1) - (A-1)*cs - beta*sn);
131
132/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw);*/
133
134 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
135 post("highshelf: filter unstable -> resetting");
136 a0=1.;a1=0.;a2=0.;
137 b0=1.;b1=0.;b2=0.;
138 }
139
140 SETFLOAT(at,-a1/a0);
141 SETFLOAT(at+1,-a2/a0);
142 SETFLOAT(at+2,b0/a0);
143 SETFLOAT(at+3,b1/a0);
144 SETFLOAT(at+4,b2/a0);
145
146 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
147}
148
149
150void highshelf_float(t_rbjfilter *x,t_floatarg f)
151{
152 x->x_freq = f;
153 highshelf_bang(x);
154}
155
156
157static void *highshelf_new(t_floatarg f,t_floatarg g,t_floatarg bw)
158{
159 t_rbjfilter *x = (t_rbjfilter *)pd_new(highshelf_class);
160
161 x->x_rate = 44100.0;
162 outlet_new(&x->x_obj,&s_float);
163 floatinlet_new(&x->x_obj, &x->x_gain);
164 floatinlet_new(&x->x_obj, &x->x_bw);
165 if (f > 0.) x->x_freq = f;
166 if (bw > 0.) x->x_bw = bw;
167 if (g != 0.) x->x_gain = g;
168 return (x);
169}
170
171
172void highshelf_setup(void)
173{
174 highshelf_class = class_new(gensym("highshelf"), (t_newmethod)highshelf_new, 0,
175 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
176 class_addbang(highshelf_class,highshelf_bang);
177 class_addfloat(highshelf_class,highshelf_float);
178}
179
180
diff --git a/apps/plugins/pdbox/PDa/extra/hlshelf.c b/apps/plugins/pdbox/PDa/extra/hlshelf.c
new file mode 100644
index 0000000000..46190c9b7c
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/hlshelf.c
@@ -0,0 +1,452 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3
4#include <m_pd.h>
5#include <math.h>
6
7#ifdef NT
8#pragma warning( disable : 4244 )
9#pragma warning( disable : 4305 )
10#endif
11
12/* ------------------------ hlshelf ----------------------------- */
13
14
15#ifndef M_PI
16#define M_PI 3.141593f
17#endif
18
19#define SRATE 44100.0
20#define MAX_GAIN 120.0f
21
22static t_class *hlshelf_class;
23
24
25typedef struct _hlshelf
26{
27 t_object x_obj;
28 float s_rate;
29 float s_gain0;
30 float s_gain1;
31 float s_gain2;
32 float s_ltransfq;
33 float s_htransfq;
34 float s_lradians;
35 float s_hradians;
36} t_hlshelf;
37
38
39int hlshelf_check_stability(t_float fb1,
40 t_float fb2,
41 t_float ff1,
42 t_float ff2,
43 t_float ff3)
44{
45 float discriminant = fb1 * fb1 + 4 * fb2;
46
47 if (discriminant < 0) /* imaginary roots -- resonant filter */
48 {
49 /* they're conjugates so we just check that the product
50 is less than one */
51 if (fb2 >= -1.0f) goto stable;
52 }
53 else /* real roots */
54 {
55 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
56 vertex between -1 and 1, and that it's nonnegative
57 at both ends, which implies both roots are in [1-,1]. */
58 if (fb1 <= 2.0f && fb1 >= -2.0f &&
59 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
60 goto stable;
61 }
62 return 0;
63stable:
64 return 1;
65}
66
67
68void hlshelf_check(t_hlshelf *x)
69{
70
71 if(x->s_gain0 - x->s_gain1 > MAX_GAIN) {
72 x->s_gain0 = x->s_gain1 + MAX_GAIN;
73 post("setting gain0 to %f",x->s_gain0);
74 }
75
76
77 if(x->s_gain1 > MAX_GAIN) {
78 x->s_gain1 = MAX_GAIN;
79 post("setting gain1 to %f",x->s_gain1);
80 }
81
82 if(x->s_gain2 - x->s_gain1 > MAX_GAIN) {
83 x->s_gain2 = x->s_gain1 + MAX_GAIN;
84 post("setting gain2 to %f",x->s_gain2);
85 }
86
87 /* constrain: 0 <= x->s_ltransfq < x->s_htransfq. */
88 x->s_ltransfq = (x->s_ltransfq < x->s_htransfq) ? x->s_ltransfq : x->s_htransfq - 0.5f;
89
90 if (x->s_ltransfq < 0) x->s_ltransfq = 0.0f;
91
92 x->s_lradians = M_PI * x->s_ltransfq / x->s_rate;
93 x->s_hradians= M_PI * (0.5f - (x->s_htransfq / x->s_rate));
94
95}
96
97
98void hlshelf_bang(t_hlshelf *x)
99{
100 t_atom at[6];
101 float c0, c1, c2, d0, d1, d2; /* output coefs */
102 float a1, a2, b1, b2, g1, g2; /* temp coefs */
103 double xf;
104
105 hlshelf_check(x);
106
107 /* low shelf */
108 xf = 0.5 * 0.115129255 * (double)(x->s_gain0 - x->s_gain1); /* ln(10) / 20 = 0.115129255 */
109 if(xf < -200.) /* exp(x) -> 0 */
110 {
111 a1 = 1.0f;
112 b1 = -1.0f;
113 g1 = 0.0f;
114 }
115 else
116 {
117 double t = tan(x->s_lradians);
118 double e = exp(xf);
119 double r = t / e;
120 double kr = t * e;
121
122 a1 = (r - 1) / (r + 1);
123 b1 = (kr - 1) / (kr + 1);
124 g1 = (kr + 1) / (r + 1);
125 }
126
127 /* high shelf */
128 xf = 0.5 * 0.115129255 * (double)(x->s_gain2 - x->s_gain1); /* ln(10) / 20 = 0.115129255 */
129 if(xf < -200.) /* exp(x) -> 0 */
130 {
131 a2 = -1.0f;
132 b2 = 1.0f;
133 g2 = 0.0f;
134 }
135 else
136 {
137 double t = tan(x->s_hradians);
138 double e = exp(xf);
139 double r = t / e;
140 double kr = t * e;
141
142 a2 = (1 - r) / (1 + r);
143 b2 = (1 - kr) / (1 + kr);
144 g2 = (1 + kr) / (1 + r);
145 }
146
147 /* form product */
148 c0 = g1 * g2 * (float)(exp((double)(x->s_gain1) * 0.05f * 2.302585093f)); ;
149 c1 = a1 + a2;
150 c2 = a1 * a2;
151 d0 = 1.0f;
152 d1 = b1 + b2;
153 d2 = b1 * b2;
154
155 if (!hlshelf_check_stability(-c1/d0,-c2/d0,d0/d0,d1/d0,d2/d0)) {
156 post("hlshelf: filter unstable -> resetting");
157 c0=1.;c1=0.;c2=0.;
158 d0=1.;d1=0.;d2=0.;
159 }
160
161 SETFLOAT(at,-c1/d0);
162 SETFLOAT(at+1,-c2/d0);
163 SETFLOAT(at+2,d0/d0);
164 SETFLOAT(at+3,d1/d0);
165 SETFLOAT(at+4,d2/d0);
166
167 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
168}
169
170void hlshelf_float(t_hlshelf *x,t_floatarg f)
171{
172 x->s_gain0 = f;
173 hlshelf_bang(x);
174}
175
176
177static void *hlshelf_new(t_symbol* s,t_int argc, t_atom* at)
178{
179 t_hlshelf *x = (t_hlshelf *)pd_new(hlshelf_class);
180 t_float k0 = atom_getfloat(at);
181 t_float k1 = atom_getfloat(at+1);
182 t_float k2 = atom_getfloat(at+2);
183 t_float f1 = atom_getfloat(at+3);
184 t_float f2 = atom_getfloat(at+4);
185
186
187 f1 = atom_getfloat(at);
188 f2 = atom_getfloat(at);
189
190 if ((f1 == 0.0f && f2 == 0.0f) || f1 > f2){ /* all gains = 0db */
191 f1 = 150.0f;
192 f2 = 5000.0f;
193 }
194
195 if (f1 < 0) f1 = 0.0f;
196 if (f2 > SRATE) f2 = .5f*SRATE;
197
198 x->s_rate = SRATE; /* srate default */
199 x->s_gain0 = k0;
200 x->s_gain1 = k1;
201 x->s_gain2 = k2;
202
203 x->s_ltransfq = 0.0f;
204 x->s_htransfq = SRATE/2;
205
206 x->s_lradians = M_PI * x->s_ltransfq / x->s_rate;
207 x->s_hradians= M_PI * (0.5f - (x->s_htransfq / x->s_rate));
208
209 floatinlet_new(&x->x_obj, &x->s_gain1);
210 floatinlet_new(&x->x_obj, &x->s_gain2);
211 floatinlet_new(&x->x_obj, &x->s_ltransfq);
212 floatinlet_new(&x->x_obj, &x->s_htransfq);
213 outlet_new(&x->x_obj, &s_list);
214
215 return (x);
216}
217
218void hlshelf_setup(void)
219{
220 hlshelf_class = class_new(gensym("hlshelf"), (t_newmethod)hlshelf_new, 0,
221 sizeof(t_hlshelf), 0, A_GIMME, 0);
222 class_addbang(hlshelf_class,hlshelf_bang);
223 class_addfloat(hlshelf_class,hlshelf_float);
224}
225
226
227/* (C) Guenter Geiger <geiger@epy.co.at> */
228
229
230#include <m_pd.h>
231#include <math.h>
232
233#ifdef NT
234#pragma warning( disable : 4244 )
235#pragma warning( disable : 4305 )
236#endif
237
238/* ------------------------ hlshelf ----------------------------- */
239
240
241#ifndef M_PI
242#define M_PI 3.141593f
243#endif
244
245#define SRATE 44100.0
246#define MAX_GAIN 120.0f
247
248static t_class *hlshelf_class;
249
250
251typedef struct _hlshelf
252{
253 t_object x_obj;
254 float s_rate;
255 float s_gain0;
256 float s_gain1;
257 float s_gain2;
258 float s_ltransfq;
259 float s_htransfq;
260 float s_lradians;
261 float s_hradians;
262} t_hlshelf;
263
264
265int hlshelf_check_stability(t_float fb1,
266 t_float fb2,
267 t_float ff1,
268 t_float ff2,
269 t_float ff3)
270{
271 float discriminant = fb1 * fb1 + 4 * fb2;
272
273 if (discriminant < 0) /* imaginary roots -- resonant filter */
274 {
275 /* they're conjugates so we just check that the product
276 is less than one */
277 if (fb2 >= -1.0f) goto stable;
278 }
279 else /* real roots */
280 {
281 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
282 vertex between -1 and 1, and that it's nonnegative
283 at both ends, which implies both roots are in [1-,1]. */
284 if (fb1 <= 2.0f && fb1 >= -2.0f &&
285 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
286 goto stable;
287 }
288 return 0;
289stable:
290 return 1;
291}
292
293
294void hlshelf_check(t_hlshelf *x)
295{
296
297 if(x->s_gain0 - x->s_gain1 > MAX_GAIN) {
298 x->s_gain0 = x->s_gain1 + MAX_GAIN;
299 post("setting gain0 to %f",x->s_gain0);
300 }
301
302
303 if(x->s_gain1 > MAX_GAIN) {
304 x->s_gain1 = MAX_GAIN;
305 post("setting gain1 to %f",x->s_gain1);
306 }
307
308 if(x->s_gain2 - x->s_gain1 > MAX_GAIN) {
309 x->s_gain2 = x->s_gain1 + MAX_GAIN;
310 post("setting gain2 to %f",x->s_gain2);
311 }
312
313 /* constrain: 0 <= x->s_ltransfq < x->s_htransfq. */
314 x->s_ltransfq = (x->s_ltransfq < x->s_htransfq) ? x->s_ltransfq : x->s_htransfq - 0.5f;
315
316 if (x->s_ltransfq < 0) x->s_ltransfq = 0.0f;
317
318 x->s_lradians = M_PI * x->s_ltransfq / x->s_rate;
319 x->s_hradians= M_PI * (0.5f - (x->s_htransfq / x->s_rate));
320
321}
322
323
324void hlshelf_bang(t_hlshelf *x)
325{
326 t_atom at[6];
327 float c0, c1, c2, d0, d1, d2; /* output coefs */
328 float a1, a2, b1, b2, g1, g2; /* temp coefs */
329 double xf;
330
331 hlshelf_check(x);
332
333 /* low shelf */
334 xf = 0.5 * 0.115129255 * (double)(x->s_gain0 - x->s_gain1); /* ln(10) / 20 = 0.115129255 */
335 if(xf < -200.) /* exp(x) -> 0 */
336 {
337 a1 = 1.0f;
338 b1 = -1.0f;
339 g1 = 0.0f;
340 }
341 else
342 {
343 double t = tan(x->s_lradians);
344 double e = exp(xf);
345 double r = t / e;
346 double kr = t * e;
347
348 a1 = (r - 1) / (r + 1);
349 b1 = (kr - 1) / (kr + 1);
350 g1 = (kr + 1) / (r + 1);
351 }
352
353 /* high shelf */
354 xf = 0.5 * 0.115129255 * (double)(x->s_gain2 - x->s_gain1); /* ln(10) / 20 = 0.115129255 */
355 if(xf < -200.) /* exp(x) -> 0 */
356 {
357 a2 = -1.0f;
358 b2 = 1.0f;
359 g2 = 0.0f;
360 }
361 else
362 {
363 double t = tan(x->s_hradians);
364 double e = exp(xf);
365 double r = t / e;
366 double kr = t * e;
367
368 a2 = (1 - r) / (1 + r);
369 b2 = (1 - kr) / (1 + kr);
370 g2 = (1 + kr) / (1 + r);
371 }
372
373 /* form product */
374 c0 = g1 * g2 * (float)(exp((double)(x->s_gain1) * 0.05f * 2.302585093f)); ;
375 c1 = a1 + a2;
376 c2 = a1 * a2;
377 d0 = 1.0f;
378 d1 = b1 + b2;
379 d2 = b1 * b2;
380
381 if (!hlshelf_check_stability(-c1/d0,-c2/d0,d0/d0,d1/d0,d2/d0)) {
382 post("hlshelf: filter unstable -> resetting");
383 c0=1.;c1=0.;c2=0.;
384 d0=1.;d1=0.;d2=0.;
385 }
386
387 SETFLOAT(at,-c1/d0);
388 SETFLOAT(at+1,-c2/d0);
389 SETFLOAT(at+2,d0/d0);
390 SETFLOAT(at+3,d1/d0);
391 SETFLOAT(at+4,d2/d0);
392
393 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
394}
395
396void hlshelf_float(t_hlshelf *x,t_floatarg f)
397{
398 x->s_gain0 = f;
399 hlshelf_bang(x);
400}
401
402
403static void *hlshelf_new(t_symbol* s,t_int argc, t_atom* at)
404{
405 t_hlshelf *x = (t_hlshelf *)pd_new(hlshelf_class);
406 t_float k0 = atom_getfloat(at);
407 t_float k1 = atom_getfloat(at+1);
408 t_float k2 = atom_getfloat(at+2);
409 t_float f1 = atom_getfloat(at+3);
410 t_float f2 = atom_getfloat(at+4);
411
412
413 f1 = atom_getfloat(at);
414 f2 = atom_getfloat(at);
415
416 if ((f1 == 0.0f && f2 == 0.0f) || f1 > f2){ /* all gains = 0db */
417 f1 = 150.0f;
418 f2 = 5000.0f;
419 }
420
421 if (f1 < 0) f1 = 0.0f;
422 if (f2 > SRATE) f2 = .5f*SRATE;
423
424 x->s_rate = SRATE; /* srate default */
425 x->s_gain0 = k0;
426 x->s_gain1 = k1;
427 x->s_gain2 = k2;
428
429 x->s_ltransfq = 0.0f;
430 x->s_htransfq = SRATE/2;
431
432 x->s_lradians = M_PI * x->s_ltransfq / x->s_rate;
433 x->s_hradians= M_PI * (0.5f - (x->s_htransfq / x->s_rate));
434
435 floatinlet_new(&x->x_obj, &x->s_gain1);
436 floatinlet_new(&x->x_obj, &x->s_gain2);
437 floatinlet_new(&x->x_obj, &x->s_ltransfq);
438 floatinlet_new(&x->x_obj, &x->s_htransfq);
439 outlet_new(&x->x_obj, &s_list);
440
441 return (x);
442}
443
444void hlshelf_setup(void)
445{
446 hlshelf_class = class_new(gensym("hlshelf"), (t_newmethod)hlshelf_new, 0,
447 sizeof(t_hlshelf), 0, A_GIMME, 0);
448 class_addbang(hlshelf_class,hlshelf_bang);
449 class_addfloat(hlshelf_class,hlshelf_float);
450}
451
452
diff --git a/apps/plugins/pdbox/PDa/extra/image.c b/apps/plugins/pdbox/PDa/extra/image.c
new file mode 100644
index 0000000000..6de48ef8fb
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/image.c
@@ -0,0 +1,434 @@
1#include "m_pd.h"
2#include "g_canvas.h"
3
4#ifdef NT
5#pragma warning( disable : 4244 )
6#pragma warning( disable : 4305 )
7#endif
8
9/* ------------------------ image ----------------------------- */
10
11static t_class *image_class;
12
13typedef struct _image
14{
15 t_object x_obj;
16 t_glist * x_glist;
17 int x_width;
18 int x_height;
19 t_symbol* x_fname;
20} t_image;
21
22/* widget helper functions */
23
24void image_drawme(t_image *x, t_glist *glist, int firsttime)
25{
26 if (firsttime) {
27 char fname[MAXPDSTRING];
28 canvas_makefilename(glist_getcanvas(x->x_glist), x->x_fname->s_name,
29 fname, MAXPDSTRING);
30
31 sys_vgui("image create photo img%x -file %s\n",x,fname);
32 sys_vgui(".x%x.c create image %d %d -image img%x -tags %xS\n",
33 glist_getcanvas(glist),text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x,x);
34
35 /* TODO callback from gui
36 sys_vgui("image_size logo");
37 */
38 }
39 else {
40 sys_vgui(".x%x.c coords %xS \
41%d %d\n",
42 glist_getcanvas(glist), x,
43 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist));
44 }
45
46}
47
48
49void image_erase(t_image* x,t_glist* glist)
50{
51 int n;
52 sys_vgui(".x%x.c delete %xS\n",
53 glist_getcanvas(glist), x);
54
55}
56
57
58
59/* ------------------------ image widgetbehaviour----------------------------- */
60
61
62static void image_getrect(t_gobj *z, t_glist *glist,
63 int *xp1, int *yp1, int *xp2, int *yp2)
64{
65 int width, height;
66 t_image* x = (t_image*)z;
67
68
69 width = x->x_width;
70 height = x->x_height;
71 *xp1 = text_xpix(&x->x_obj, glist);
72 *yp1 = text_ypix(&x->x_obj, glist);
73 *xp2 = text_xpix(&x->x_obj, glist) + width;
74 *yp2 = text_ypix(&x->x_obj, glist) + height;
75}
76
77static void image_displace(t_gobj *z, t_glist *glist,
78 int dx, int dy)
79{
80 t_image *x = (t_image *)z;
81 x->x_obj.te_xpix += dx;
82 x->x_obj.te_ypix += dy;
83 sys_vgui(".x%x.c coords %xSEL %d %d %d %d\n",
84 glist_getcanvas(glist), x,
85 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
86 text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height);
87
88 image_drawme(x, glist, 0);
89 canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
90}
91
92static void image_select(t_gobj *z, t_glist *glist, int state)
93{
94 t_image *x = (t_image *)z;
95 if (state) {
96 sys_vgui(".x%x.c create rectangle \
97%d %d %d %d -tags %xSEL -outline blue\n",
98 glist_getcanvas(glist),
99 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
100 text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height,
101 x);
102 }
103 else {
104 sys_vgui(".x%x.c delete %xSEL\n",
105 glist_getcanvas(glist), x);
106 }
107
108
109
110}
111
112
113static void image_activate(t_gobj *z, t_glist *glist, int state)
114{
115/* t_text *x = (t_text *)z;
116 t_rtext *y = glist_findrtext(glist, x);
117 if (z->g_pd != gatom_class) rtext_activate(y, state);*/
118}
119
120static void image_delete(t_gobj *z, t_glist *glist)
121{
122 t_text *x = (t_text *)z;
123 canvas_deletelinesfor(glist_getcanvas(glist), x);
124}
125
126
127static void image_vis(t_gobj *z, t_glist *glist, int vis)
128{
129 t_image* s = (t_image*)z;
130 if (vis)
131 image_drawme(s, glist, 1);
132 else
133 image_erase(s,glist);
134}
135
136/* can we use the normal text save function ?? */
137
138static void image_save(t_gobj *z, t_binbuf *b)
139{
140 t_image *x = (t_image *)z;
141 binbuf_addv(b, "ssiiss", gensym("#X"),gensym("obj"),
142 x->x_obj.te_xpix, x->x_obj.te_ypix,
143 gensym("image"),x->x_fname);
144 binbuf_addv(b, ";");
145}
146
147
148t_widgetbehavior image_widgetbehavior;
149
150void image_size(t_image* x,t_floatarg w,t_floatarg h) {
151 x->x_width = w;
152 x->x_height = h;
153}
154
155void image_color(t_image* x,t_symbol* col)
156{
157/* outlet_bang(x->x_obj.ob_outlet); only bang if there was a bang ..
158 so color black does the same as bang, but doesn't forward the bang
159*/
160}
161
162static void image_setwidget(void)
163{
164 image_widgetbehavior.w_getrectfn = image_getrect;
165 image_widgetbehavior.w_displacefn = image_displace;
166 image_widgetbehavior.w_selectfn = image_select;
167 image_widgetbehavior.w_activatefn = image_activate;
168 image_widgetbehavior.w_deletefn = image_delete;
169 image_widgetbehavior.w_visfn = image_vis;
170#if (PD_VERSION_MINOR > 31)
171 image_widgetbehavior.w_clickfn = NULL;
172 image_widgetbehavior.w_propertiesfn = NULL;
173#endif
174#if PD_MINOR_VERSION < 37
175 image_widgetbehavior.w_savefn = image_save;
176#endif
177}
178
179
180static void *image_new(t_symbol* fname)
181{
182 t_image *x = (t_image *)pd_new(image_class);
183
184 x->x_glist = (t_glist*) canvas_getcurrent();
185
186 x->x_width = 15;
187 x->x_height = 15;
188
189 x->x_fname = fname;
190 outlet_new(&x->x_obj, &s_float);
191 return (x);
192}
193
194void image_setup(void)
195{
196 image_class = class_new(gensym("image"), (t_newmethod)image_new, 0,
197 sizeof(t_image),0, A_DEFSYM,0);
198
199/*
200 class_addmethod(image_class, (t_method)image_size, gensym("size"),
201 A_FLOAT, A_FLOAT, 0);
202
203 class_addmethod(image_class, (t_method)image_color, gensym("color"),
204 A_SYMBOL, 0);
205*/
206/*
207 class_addmethod(image_class, (t_method)image_open, gensym("open"),
208 A_SYMBOL, 0);
209*/
210 image_setwidget();
211 class_setwidget(image_class,&image_widgetbehavior);
212#if PD_MINOR_VERSION >= 37
213 class_setsavefn(image_class,&image_save);
214#endif
215}
216
217
218#include "m_pd.h"
219#include "g_canvas.h"
220
221#ifdef NT
222#pragma warning( disable : 4244 )
223#pragma warning( disable : 4305 )
224#endif
225
226/* ------------------------ image ----------------------------- */
227
228static t_class *image_class;
229
230typedef struct _image
231{
232 t_object x_obj;
233 t_glist * x_glist;
234 int x_width;
235 int x_height;
236 t_symbol* x_fname;
237} t_image;
238
239/* widget helper functions */
240
241void image_drawme(t_image *x, t_glist *glist, int firsttime)
242{
243 if (firsttime) {
244 char fname[MAXPDSTRING];
245 canvas_makefilename(glist_getcanvas(x->x_glist), x->x_fname->s_name,
246 fname, MAXPDSTRING);
247
248 sys_vgui("image create photo img%x -file %s\n",x,fname);
249 sys_vgui(".x%x.c create image %d %d -image img%x -tags %xS\n",
250 glist_getcanvas(glist),text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x,x);
251
252 /* TODO callback from gui
253 sys_vgui("image_size logo");
254 */
255 }
256 else {
257 sys_vgui(".x%x.c coords %xS \
258%d %d\n",
259 glist_getcanvas(glist), x,
260 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist));
261 }
262
263}
264
265
266void image_erase(t_image* x,t_glist* glist)
267{
268 int n;
269 sys_vgui(".x%x.c delete %xS\n",
270 glist_getcanvas(glist), x);
271
272}
273
274
275
276/* ------------------------ image widgetbehaviour----------------------------- */
277
278
279static void image_getrect(t_gobj *z, t_glist *glist,
280 int *xp1, int *yp1, int *xp2, int *yp2)
281{
282 int width, height;
283 t_image* x = (t_image*)z;
284
285
286 width = x->x_width;
287 height = x->x_height;
288 *xp1 = text_xpix(&x->x_obj, glist);
289 *yp1 = text_ypix(&x->x_obj, glist);
290 *xp2 = text_xpix(&x->x_obj, glist) + width;
291 *yp2 = text_ypix(&x->x_obj, glist) + height;
292}
293
294static void image_displace(t_gobj *z, t_glist *glist,
295 int dx, int dy)
296{
297 t_image *x = (t_image *)z;
298 x->x_obj.te_xpix += dx;
299 x->x_obj.te_ypix += dy;
300 sys_vgui(".x%x.c coords %xSEL %d %d %d %d\n",
301 glist_getcanvas(glist), x,
302 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
303 text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height);
304
305 image_drawme(x, glist, 0);
306 canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
307}
308
309static void image_select(t_gobj *z, t_glist *glist, int state)
310{
311 t_image *x = (t_image *)z;
312 if (state) {
313 sys_vgui(".x%x.c create rectangle \
314%d %d %d %d -tags %xSEL -outline blue\n",
315 glist_getcanvas(glist),
316 text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
317 text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height,
318 x);
319 }
320 else {
321 sys_vgui(".x%x.c delete %xSEL\n",
322 glist_getcanvas(glist), x);
323 }
324
325
326
327}
328
329
330static void image_activate(t_gobj *z, t_glist *glist, int state)
331{
332/* t_text *x = (t_text *)z;
333 t_rtext *y = glist_findrtext(glist, x);
334 if (z->g_pd != gatom_class) rtext_activate(y, state);*/
335}
336
337static void image_delete(t_gobj *z, t_glist *glist)
338{
339 t_text *x = (t_text *)z;
340 canvas_deletelinesfor(glist_getcanvas(glist), x);
341}
342
343
344static void image_vis(t_gobj *z, t_glist *glist, int vis)
345{
346 t_image* s = (t_image*)z;
347 if (vis)
348 image_drawme(s, glist, 1);
349 else
350 image_erase(s,glist);
351}
352
353/* can we use the normal text save function ?? */
354
355static void image_save(t_gobj *z, t_binbuf *b)
356{
357 t_image *x = (t_image *)z;
358 binbuf_addv(b, "ssiiss", gensym("#X"),gensym("obj"),
359 x->x_obj.te_xpix, x->x_obj.te_ypix,
360 gensym("image"),x->x_fname);
361 binbuf_addv(b, ";");
362}
363
364
365t_widgetbehavior image_widgetbehavior;
366
367void image_size(t_image* x,t_floatarg w,t_floatarg h) {
368 x->x_width = w;
369 x->x_height = h;
370}
371
372void image_color(t_image* x,t_symbol* col)
373{
374/* outlet_bang(x->x_obj.ob_outlet); only bang if there was a bang ..
375 so color black does the same as bang, but doesn't forward the bang
376*/
377}
378
379static void image_setwidget(void)
380{
381 image_widgetbehavior.w_getrectfn = image_getrect;
382 image_widgetbehavior.w_displacefn = image_displace;
383 image_widgetbehavior.w_selectfn = image_select;
384 image_widgetbehavior.w_activatefn = image_activate;
385 image_widgetbehavior.w_deletefn = image_delete;
386 image_widgetbehavior.w_visfn = image_vis;
387#if (PD_VERSION_MINOR > 31)
388 image_widgetbehavior.w_clickfn = NULL;
389 image_widgetbehavior.w_propertiesfn = NULL;
390#endif
391#if PD_MINOR_VERSION < 37
392 image_widgetbehavior.w_savefn = image_save;
393#endif
394}
395
396
397static void *image_new(t_symbol* fname)
398{
399 t_image *x = (t_image *)pd_new(image_class);
400
401 x->x_glist = (t_glist*) canvas_getcurrent();
402
403 x->x_width = 15;
404 x->x_height = 15;
405
406 x->x_fname = fname;
407 outlet_new(&x->x_obj, &s_float);
408 return (x);
409}
410
411void image_setup(void)
412{
413 image_class = class_new(gensym("image"), (t_newmethod)image_new, 0,
414 sizeof(t_image),0, A_DEFSYM,0);
415
416/*
417 class_addmethod(image_class, (t_method)image_size, gensym("size"),
418 A_FLOAT, A_FLOAT, 0);
419
420 class_addmethod(image_class, (t_method)image_color, gensym("color"),
421 A_SYMBOL, 0);
422*/
423/*
424 class_addmethod(image_class, (t_method)image_open, gensym("open"),
425 A_SYMBOL, 0);
426*/
427 image_setwidget();
428 class_setwidget(image_class,&image_widgetbehavior);
429#if PD_MINOR_VERSION >= 37
430 class_setsavefn(image_class,&image_save);
431#endif
432}
433
434
diff --git a/apps/plugins/pdbox/PDa/extra/lowpass.c b/apps/plugins/pdbox/PDa/extra/lowpass.c
new file mode 100644
index 0000000000..c242aff0a8
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/lowpass.c
@@ -0,0 +1,178 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3
4/*
5
6 These filter coefficients computations are taken from
7 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
8
9 written by Robert Bristow-Johnson
10
11*/
12
13#include "m_pd.h"
14#ifdef NT
15#pragma warning( disable : 4244 )
16#pragma warning( disable : 4305 )
17#endif
18#include <math.h>
19#include "filters.h"
20
21
22
23/* ------------------- lowpass ----------------------------*/
24
25static t_class *lowpass_class;
26
27void lowpass_bang(t_rbjfilter *x)
28{
29 t_atom at[5];
30 t_float omega = e_omega(x->x_freq,x->x_rate);
31 t_float alpha = e_alpha(x->x_bw*0.01,omega);
32 t_float b1 = 1 - cos(omega);
33 t_float b0 = b1/2.;
34 t_float b2 = b0;
35 t_float a0 = 1 + alpha;
36 t_float a1 = -2.*cos(omega);
37 t_float a2 = 1 - alpha;
38
39/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
40
41 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
42 post("lowpass: filter unstable -> resetting");
43 a0=1.;a1=0.;a2=0.;
44 b0=1.;b1=0.;b2=0.;
45 }
46
47 SETFLOAT(at,-a1/a0);
48 SETFLOAT(at+1,-a2/a0);
49 SETFLOAT(at+2,b0/a0);
50 SETFLOAT(at+3,b1/a0);
51 SETFLOAT(at+4,b2/a0);
52
53 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
54}
55
56
57void lowpass_float(t_rbjfilter *x,t_floatarg f)
58{
59 x->x_freq = f;
60 lowpass_bang(x);
61}
62
63
64static void *lowpass_new(t_floatarg f,t_floatarg bw)
65{
66 t_rbjfilter *x = (t_rbjfilter *)pd_new(lowpass_class);
67
68 x->x_rate = 44100.0;
69 outlet_new(&x->x_obj,&s_float);
70/* floatinlet_new(&x->x_obj, &x->x_gain); */
71 floatinlet_new(&x->x_obj, &x->x_bw);
72
73 if (f > 0.) x->x_freq = f;
74 if (bw > 0.) x->x_bw = bw;
75 return (x);
76}
77
78
79void lowpass_setup(void)
80{
81 lowpass_class = class_new(gensym("lowpass"), (t_newmethod)lowpass_new, 0,
82 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,0);
83 class_addbang(lowpass_class,lowpass_bang);
84 class_addfloat(lowpass_class,lowpass_float);
85}
86
87
88
89
90/* (C) Guenter Geiger <geiger@epy.co.at> */
91
92
93/*
94
95 These filter coefficients computations are taken from
96 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
97
98 written by Robert Bristow-Johnson
99
100*/
101
102#include "m_pd.h"
103#ifdef NT
104#pragma warning( disable : 4244 )
105#pragma warning( disable : 4305 )
106#endif
107#include <math.h>
108#include "filters.h"
109
110
111
112/* ------------------- lowpass ----------------------------*/
113
114static t_class *lowpass_class;
115
116void lowpass_bang(t_rbjfilter *x)
117{
118 t_atom at[5];
119 t_float omega = e_omega(x->x_freq,x->x_rate);
120 t_float alpha = e_alpha(x->x_bw*0.01,omega);
121 t_float b1 = 1 - cos(omega);
122 t_float b0 = b1/2.;
123 t_float b2 = b0;
124 t_float a0 = 1 + alpha;
125 t_float a1 = -2.*cos(omega);
126 t_float a2 = 1 - alpha;
127
128/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
129
130 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
131 post("lowpass: filter unstable -> resetting");
132 a0=1.;a1=0.;a2=0.;
133 b0=1.;b1=0.;b2=0.;
134 }
135
136 SETFLOAT(at,-a1/a0);
137 SETFLOAT(at+1,-a2/a0);
138 SETFLOAT(at+2,b0/a0);
139 SETFLOAT(at+3,b1/a0);
140 SETFLOAT(at+4,b2/a0);
141
142 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
143}
144
145
146void lowpass_float(t_rbjfilter *x,t_floatarg f)
147{
148 x->x_freq = f;
149 lowpass_bang(x);
150}
151
152
153static void *lowpass_new(t_floatarg f,t_floatarg bw)
154{
155 t_rbjfilter *x = (t_rbjfilter *)pd_new(lowpass_class);
156
157 x->x_rate = 44100.0;
158 outlet_new(&x->x_obj,&s_float);
159/* floatinlet_new(&x->x_obj, &x->x_gain); */
160 floatinlet_new(&x->x_obj, &x->x_bw);
161
162 if (f > 0.) x->x_freq = f;
163 if (bw > 0.) x->x_bw = bw;
164 return (x);
165}
166
167
168void lowpass_setup(void)
169{
170 lowpass_class = class_new(gensym("lowpass"), (t_newmethod)lowpass_new, 0,
171 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,0);
172 class_addbang(lowpass_class,lowpass_bang);
173 class_addfloat(lowpass_class,lowpass_float);
174}
175
176
177
178
diff --git a/apps/plugins/pdbox/PDa/extra/lowshelf.c b/apps/plugins/pdbox/PDa/extra/lowshelf.c
new file mode 100644
index 0000000000..52c30d839d
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/lowshelf.c
@@ -0,0 +1,182 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3
4/*
5
6 These filter coefficients computations are taken from
7 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
8
9 written by Robert Bristow-Johnson
10
11*/
12
13#include "m_pd.h"
14#ifdef NT
15#pragma warning( disable : 4244 )
16#pragma warning( disable : 4305 )
17#endif
18#include <math.h>
19#include "filters.h"
20
21
22
23/* ------------------- lowshelf ----------------------------*/
24
25static t_class *lowshelf_class;
26
27void lowshelf_bang(t_rbjfilter *x)
28{
29 t_atom at[5];
30 t_float omega = e_omega(x->x_freq,x->x_rate);
31 t_float A = e_A(x->x_gain);
32 t_float cs = cos(omega);
33 t_float sn = sin(omega);
34 t_float beta = e_beta(A,x->x_bw*0.01);
35
36 t_float b0 = A*((A+1) - (A-1)*cs + beta*sn);
37 t_float b1 = 2.*A*((A-1) - (A+1)*cs);
38 t_float b2 = A*((A+1) - (A-1)*cs - beta*sn);
39 t_float a0 = ((A+1) + (A-1)*cs + beta*sn);
40 t_float a1 = -2.*((A-1) + (A+1)*cs);
41 t_float a2 = ((A+1) + (A-1)*cs - beta*sn);
42
43/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
44
45 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
46 post("lowshelf: filter unstable -> resetting");
47 a0=1.;a1=0.;a2=0.;
48 b0=1.;b1=0.;b2=0.;
49 }
50
51 SETFLOAT(at,-a1/a0);
52 SETFLOAT(at+1,-a2/a0);
53 SETFLOAT(at+2,b0/a0);
54 SETFLOAT(at+3,b1/a0);
55 SETFLOAT(at+4,b2/a0);
56
57 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
58}
59
60
61void lowshelf_float(t_rbjfilter *x,t_floatarg f)
62{
63 x->x_freq = f;
64 lowshelf_bang(x);
65}
66
67
68static void *lowshelf_new(t_floatarg f,t_floatarg g,t_floatarg bw)
69{
70 t_rbjfilter *x = (t_rbjfilter *)pd_new(lowshelf_class);
71
72 x->x_rate = 44100.0;
73 outlet_new(&x->x_obj,&s_float);
74 floatinlet_new(&x->x_obj, &x->x_gain);
75 floatinlet_new(&x->x_obj, &x->x_bw);
76 if (f > 0.) x->x_freq = f;
77 if (bw > 0.) x->x_bw = bw;
78 if (g != 0.) x->x_gain = g;
79 return (x);
80}
81
82
83void lowshelf_setup(void)
84{
85 lowshelf_class = class_new(gensym("lowshelf"), (t_newmethod)lowshelf_new, 0,
86 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
87 class_addbang(lowshelf_class,lowshelf_bang);
88 class_addfloat(lowshelf_class,lowshelf_float);
89}
90
91
92/* (C) Guenter Geiger <geiger@epy.co.at> */
93
94
95/*
96
97 These filter coefficients computations are taken from
98 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
99
100 written by Robert Bristow-Johnson
101
102*/
103
104#include "m_pd.h"
105#ifdef NT
106#pragma warning( disable : 4244 )
107#pragma warning( disable : 4305 )
108#endif
109#include <math.h>
110#include "filters.h"
111
112
113
114/* ------------------- lowshelf ----------------------------*/
115
116static t_class *lowshelf_class;
117
118void lowshelf_bang(t_rbjfilter *x)
119{
120 t_atom at[5];
121 t_float omega = e_omega(x->x_freq,x->x_rate);
122 t_float A = e_A(x->x_gain);
123 t_float cs = cos(omega);
124 t_float sn = sin(omega);
125 t_float beta = e_beta(A,x->x_bw*0.01);
126
127 t_float b0 = A*((A+1) - (A-1)*cs + beta*sn);
128 t_float b1 = 2.*A*((A-1) - (A+1)*cs);
129 t_float b2 = A*((A+1) - (A-1)*cs - beta*sn);
130 t_float a0 = ((A+1) + (A-1)*cs + beta*sn);
131 t_float a1 = -2.*((A-1) + (A+1)*cs);
132 t_float a2 = ((A+1) + (A-1)*cs - beta*sn);
133
134/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
135
136 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
137 post("lowshelf: filter unstable -> resetting");
138 a0=1.;a1=0.;a2=0.;
139 b0=1.;b1=0.;b2=0.;
140 }
141
142 SETFLOAT(at,-a1/a0);
143 SETFLOAT(at+1,-a2/a0);
144 SETFLOAT(at+2,b0/a0);
145 SETFLOAT(at+3,b1/a0);
146 SETFLOAT(at+4,b2/a0);
147
148 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
149}
150
151
152void lowshelf_float(t_rbjfilter *x,t_floatarg f)
153{
154 x->x_freq = f;
155 lowshelf_bang(x);
156}
157
158
159static void *lowshelf_new(t_floatarg f,t_floatarg g,t_floatarg bw)
160{
161 t_rbjfilter *x = (t_rbjfilter *)pd_new(lowshelf_class);
162
163 x->x_rate = 44100.0;
164 outlet_new(&x->x_obj,&s_float);
165 floatinlet_new(&x->x_obj, &x->x_gain);
166 floatinlet_new(&x->x_obj, &x->x_bw);
167 if (f > 0.) x->x_freq = f;
168 if (bw > 0.) x->x_bw = bw;
169 if (g != 0.) x->x_gain = g;
170 return (x);
171}
172
173
174void lowshelf_setup(void)
175{
176 lowshelf_class = class_new(gensym("lowshelf"), (t_newmethod)lowshelf_new, 0,
177 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
178 class_addbang(lowshelf_class,lowshelf_bang);
179 class_addfloat(lowshelf_class,lowshelf_float);
180}
181
182
diff --git a/apps/plugins/pdbox/PDa/extra/m_pd.h b/apps/plugins/pdbox/PDa/extra/m_pd.h
new file mode 100644
index 0000000000..403c5b382b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/m_pd.h
@@ -0,0 +1,1300 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#ifndef __m_pd_h_
6
7#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
8extern "C" {
9#endif
10
11#define PD_VERSION 0.37 /* oops, don't use this... */ */
12#define PD_MAJOR_VERSION 0 /* ... use these two instead. */
13#define PD_MINOR_VERSION 37
14
15/* old name for "MSW" flag -- we have to take it for the sake of many old
16"nmakefiles" for externs, which will define NT and not MSW */
17#if defined(NT) && !defined(MSW)
18#define MSW
19#endif
20
21#ifdef MSW
22// #pragma warning( disable : 4091 )
23#pragma warning( disable : 4305 ) /* uncast const double to float */
24#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */
25#pragma warning( disable : 4101 ) /* unused automatic variables */
26#endif /* MSW */
27
28 /* the external storage class is "extern" in UNIX; in MSW it's ugly. */
29#ifdef MSW
30#ifdef PD_INTERNAL
31#define EXTERN __declspec(dllexport) extern
32#else
33#define EXTERN __declspec(dllimport) extern
34#endif /* PD_INTERNAL */
35#else
36#define EXTERN extern
37#endif /* MSW */
38
39 /* and depending on the compiler, hidden data structures are
40 declared differently: */
41#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ )
42#define EXTERN_STRUCT struct
43#else
44#define EXTERN_STRUCT extern struct
45#endif
46
47
48#if !defined(_SIZE_T) && !defined(_SIZE_T_)
49#include <stddef.h> /* just for size_t -- how lame! */
50#endif
51
52#define MAXPDSTRING 1000 /* use this for anything you want */
53#define MAXPDARG 5 /* max number of args we can typecheck today */
54
55 /* signed and unsigned integer types the size of a pointer: */
56#ifdef __alpha__
57typedef long t_int;
58#else
59typedef int t_int;
60#endif
61
62typedef float t_float; /* a floating-point number at most the same size */
63typedef float t_floatarg; /* floating-point type for function calls */
64
65typedef struct _symbol
66{
67 char *s_name;
68 struct _class **s_thing;
69 struct _symbol *s_next;
70} t_symbol;
71
72EXTERN_STRUCT _array;
73#define t_array struct _array /* g_canvas.h */
74
75/* pointers to glist and array elements go through a "stub" which sticks
76around after the glist or array is freed. The stub itself is deleted when
77both the glist/array is gone and the refcount is zero, ensuring that no
78gpointers are pointing here. */
79
80#define GP_NONE 0 /* the stub points nowhere (has been cut off) */
81#define GP_GLIST 1 /* the stub points to a glist element */
82#define GP_ARRAY 2 /* ... or array */
83
84typedef struct _gstub
85{
86 union
87 {
88 struct _glist *gs_glist; /* glist we're in */
89 struct _array *gs_array; /* array we're in */
90 } gs_un;
91 int gs_which; /* GP_GLIST/GP_ARRAY */
92 int gs_refcount; /* number of gpointers pointing here */
93} t_gstub;
94
95typedef struct _gpointer /* pointer to a gobj in a glist */
96{
97 union
98 {
99 struct _scalar *gp_scalar; /* scalar we're in (if glist) */
100 union word *gp_w; /* raw data (if array) */
101 } gp_un;
102 int gp_valid; /* number which must match gpointee */
103 t_gstub *gp_stub; /* stub which points to glist/array */
104} t_gpointer;
105
106typedef union word
107{
108 t_float w_float;
109 t_symbol *w_symbol;
110 t_gpointer *w_gpointer;
111 t_array *w_array;
112 struct _glist *w_list;
113 int w_index;
114} t_word;
115
116typedef enum
117{
118 A_NULL,
119 A_FLOAT,
120 A_SYMBOL,
121 A_POINTER,
122 A_SEMI,
123 A_COMMA,
124 A_DEFFLOAT,
125 A_DEFSYM,
126 A_DOLLAR,
127 A_DOLLSYM,
128 A_GIMME,
129 A_CANT
130} t_atomtype;
131
132#define A_DEFSYMBOL A_DEFSYM /* better name for this */
133
134typedef struct _atom
135{
136 t_atomtype a_type;
137 union word a_w;
138} t_atom;
139
140EXTERN_STRUCT _class;
141#define t_class struct _class
142
143EXTERN_STRUCT _outlet;
144#define t_outlet struct _outlet
145
146EXTERN_STRUCT _inlet;
147#define t_inlet struct _inlet
148
149EXTERN_STRUCT _binbuf;
150#define t_binbuf struct _binbuf
151
152EXTERN_STRUCT _clock;
153#define t_clock struct _clock
154
155EXTERN_STRUCT _outconnect;
156#define t_outconnect struct _outconnect
157
158EXTERN_STRUCT _glist;
159#define t_glist struct _glist
160#define t_canvas struct _glist /* LATER lose this */
161
162typedef t_class *t_pd; /* pure datum: nothing but a class pointer */
163
164typedef struct _gobj /* a graphical object */
165{
166 t_pd g_pd; /* pure datum header (class) */
167 struct _gobj *g_next; /* next in list */
168} t_gobj;
169
170typedef struct _scalar /* a graphical object holding data */
171{
172 t_gobj sc_gobj; /* header for graphical object */
173 t_symbol *sc_template; /* template name (LATER replace with pointer) */
174 t_word sc_vec[1]; /* indeterminate-length array of words */
175} t_scalar;
176
177typedef struct _text /* patchable object - graphical, with text */
178{
179 t_gobj te_g; /* header for graphical object */
180 t_binbuf *te_binbuf; /* holder for the text */
181 t_outlet *te_outlet; /* linked list of outlets */
182 t_inlet *te_inlet; /* linked list of inlets */
183 short te_xpix; /* x&y location (within the toplevel) */
184 short te_ypix;
185 short te_width; /* requested width in chars, 0 if auto */
186 unsigned int te_type:2; /* from defs below */
187} t_text;
188
189#define T_TEXT 0 /* just a textual comment */
190#define T_OBJECT 1 /* a MAX style patchable object */
191#define T_MESSAGE 2 /* a MAX stype message */
192#define T_ATOM 3 /* a cell to display a number or symbol */
193
194#define te_pd te_g.g_pd
195
196 /* t_object is synonym for t_text (LATER unify them) */
197
198typedef struct _text t_object;
199
200#define ob_outlet te_outlet
201#define ob_inlet te_inlet
202#define ob_binbuf te_binbuf
203#define ob_pd te_g.g_pd
204#define ob_g te_g
205
206typedef void (*t_method)(void);
207typedef void *(*t_newmethod)( void);
208typedef void (*t_gotfn)(void *x, ...);
209
210/* ---------------- pre-defined objects and symbols --------------*/
211EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */
212EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */
213EXTERN t_symbol s_pointer;
214EXTERN t_symbol s_float;
215EXTERN t_symbol s_symbol;
216EXTERN t_symbol s_bang;
217EXTERN t_symbol s_list;
218EXTERN t_symbol s_anything;
219EXTERN t_symbol s_signal;
220EXTERN t_symbol s__N;
221EXTERN t_symbol s__X;
222EXTERN t_symbol s_x;
223EXTERN t_symbol s_y;
224EXTERN t_symbol s_;
225
226/* --------- prototypes from the central message system ----------- */
227EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
228EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
229EXTERN t_symbol *gensym(char *s);
230EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
231EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
232EXTERN void nullfn(void);
233EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
234#define mess0(x, s) ((*getfn((x), (s)))((x)))
235#define mess1(x, s, a) ((*getfn((x), (s)))((x), (a)))
236#define mess2(x, s, a,b) ((*getfn((x), (s)))((x), (a),(b)))
237#define mess3(x, s, a,b,c) ((*getfn((x), (s)))((x), (a),(b),(c)))
238#define mess4(x, s, a,b,c,d) ((*getfn((x), (s)))((x), (a),(b),(c),(d)))
239#define mess5(x, s, a,b,c,d,e) ((*getfn((x), (s)))((x), (a),(b),(c),(d),(e)))
240EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
241EXTERN t_pd *pd_newest(void);
242
243/* --------------- memory management -------------------- */
244EXTERN void *getbytes(size_t nbytes);
245EXTERN void *getzbytes(size_t nbytes);
246EXTERN void *copybytes(void *src, size_t nbytes);
247EXTERN void freebytes(void *x, size_t nbytes);
248EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize);
249
250/* -------------------- atoms ----------------------------- */
251
252#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0)
253#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0)
254#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \
255 (atom)->a_w.w_gpointer = (gp))
256#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f))
257#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \
258 (atom)->a_w.w_symbol = (s))
259#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \
260 (atom)->a_w.w_index = (n))
261#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \
262 (atom)->a_w.w_symbol= (s))
263
264EXTERN t_float atom_getfloat(t_atom *a);
265EXTERN t_int atom_getint(t_atom *a);
266EXTERN t_symbol *atom_getsymbol(t_atom *a);
267EXTERN t_symbol *atom_gensym(t_atom *a);
268EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv);
269EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv);
270EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
271
272EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
273
274/* ------------------ binbufs --------------- */
275
276EXTERN t_binbuf *binbuf_new(void);
277EXTERN void binbuf_free(t_binbuf *x);
278EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y);
279
280EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
281EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
282EXTERN void binbuf_clear(t_binbuf *x);
283EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
284EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
285EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
286EXTERN void binbuf_addsemi(t_binbuf *x);
287EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
288EXTERN void binbuf_print(t_binbuf *x);
289EXTERN int binbuf_getnatom(t_binbuf *x);
290EXTERN t_atom *binbuf_getvec(t_binbuf *x);
291EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
292EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname,
293 int crflag);
294EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
295 int crflag);
296EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir,
297 int crflag);
298EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
299EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av,
300 int tonew);
301
302/* ------------------ clocks --------------- */
303
304typedef long long t_time;
305EXTERN t_clock *clock_new(void *owner, t_method fn);
306EXTERN void clock_set(t_clock *x, t_time systime);
307EXTERN void clock_delay(t_clock *x, t_time delaytime);
308EXTERN void clock_unset(t_clock *x);
309EXTERN t_time clock_getlogicaltime(void);
310EXTERN t_time clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
311EXTERN t_time clock_gettimesince(t_time prevsystime);
312EXTERN t_time clock_getsystimeafter(t_time delaytime);
313EXTERN void clock_free(t_clock *x);
314
315/* ----------------- pure data ---------------- */
316EXTERN t_pd *pd_new(t_class *cls);
317EXTERN void pd_free(t_pd *x);
318EXTERN void pd_bind(t_pd *x, t_symbol *s);
319EXTERN void pd_unbind(t_pd *x, t_symbol *s);
320EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
321EXTERN void pd_pushsym(t_pd *x);
322EXTERN void pd_popsym(t_pd *x);
323EXTERN t_symbol *pd_getfilename(void);
324EXTERN t_symbol *pd_getdirname(void);
325EXTERN void pd_bang(t_pd *x);
326EXTERN void pd_pointer(t_pd *x, t_gpointer *gp);
327EXTERN void pd_float(t_pd *x, t_float f);
328EXTERN void pd_symbol(t_pd *x, t_symbol *s);
329EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv);
330EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv);
331#define pd_class(x) (*(x))
332
333/* ----------------- pointers ---------------- */
334EXTERN void gpointer_init(t_gpointer *gp);
335EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
336EXTERN void gpointer_unset(t_gpointer *gp);
337EXTERN int gpointer_check(const t_gpointer *gp, int headok);
338
339/* ----------------- patchable "objects" -------------- */
340EXTERN_STRUCT _inlet;
341#define t_inlet struct _inlet
342EXTERN_STRUCT _outlet;
343#define t_outlet struct _outlet
344
345EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1,
346 t_symbol *s2);
347EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
348EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
349EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
350EXTERN void inlet_free(t_inlet *x);
351
352EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
353EXTERN void outlet_bang(t_outlet *x);
354EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp);
355EXTERN void outlet_float(t_outlet *x, t_float f);
356EXTERN void outlet_symbol(t_outlet *x, t_symbol *s);
357EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
358EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
359EXTERN t_symbol *outlet_getsymbol(t_outlet *x);
360EXTERN void outlet_free(t_outlet *x);
361EXTERN t_object *pd_checkobject(t_pd *x);
362
363
364/* -------------------- canvases -------------- */
365
366EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
367
368EXTERN void canvas_setargs(int argc, t_atom *argv);
369EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
370EXTERN t_symbol *canvas_getcurrentdir(void);
371EXTERN t_glist *canvas_getcurrent(void);
372EXTERN void canvas_makefilename(t_glist *c, char *file,
373 char *result,int resultsize);
374EXTERN t_symbol *canvas_getdir(t_glist *x);
375EXTERN int sys_fontwidth(int fontsize);
376EXTERN int sys_fontheight(int fontsize);
377EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
378
379/* ---------------- widget behaviors ---------------------- */
380
381EXTERN_STRUCT _widgetbehavior;
382#define t_widgetbehavior struct _widgetbehavior
383
384EXTERN_STRUCT _parentwidgetbehavior;
385#define t_parentwidgetbehavior struct _parentwidgetbehavior
386EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x);
387
388/* -------------------- classes -------------- */
389
390#define CLASS_DEFAULT 0 /* flags for new classes below */
391#define CLASS_PD 1
392#define CLASS_GOBJ 2
393#define CLASS_PATCHABLE 3
394#define CLASS_NOINLET 8
395
396#define CLASS_TYPEMASK 3
397
398
399EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod,
400 t_method freemethod, size_t size, int flags, t_atomtype arg1, ...);
401EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s,
402 t_atomtype type1, ...);
403EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
404 t_atomtype arg1, ...);
405EXTERN void class_addbang(t_class *c, t_method fn);
406EXTERN void class_addpointer(t_class *c, t_method fn);
407EXTERN void class_doaddfloat(t_class *c, t_method fn);
408EXTERN void class_addsymbol(t_class *c, t_method fn);
409EXTERN void class_addlist(t_class *c, t_method fn);
410EXTERN void class_addanything(t_class *c, t_method fn);
411EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
412EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w);
413EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w);
414EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c);
415EXTERN char *class_getname(t_class *c);
416EXTERN char *class_gethelpname(t_class *c);
417EXTERN void class_setdrawcommand(t_class *c);
418EXTERN int class_isdrawcommand(t_class *c);
419EXTERN void class_domainsignalin(t_class *c, int onset);
420#define CLASS_MAINSIGNALIN(c, type, field) \
421 class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
422
423 /* prototype for functions to save Pd's to a binbuf */
424typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
425EXTERN void class_setsavefn(t_class *c, t_savefn f);
426EXTERN t_savefn class_getsavefn(t_class *c);
427 /* prototype for functions to open properties dialogs */
428typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist);
429EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f);
430EXTERN t_propertiesfn class_getpropertiesfn(t_class *c);
431
432#ifndef PD_CLASS_DEF
433#define class_addbang(x, y) class_addbang((x), (t_method)(y))
434#define class_addpointer(x, y) class_addpointer((x), (t_method)(y))
435#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y))
436#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y))
437#define class_addlist(x, y) class_addlist((x), (t_method)(y))
438#define class_addanything(x, y) class_addanything((x), (t_method)(y))
439#endif
440
441/* ------------ printing --------------------------------- */
442EXTERN void post(char *fmt, ...);
443EXTERN void startpost(char *fmt, ...);
444EXTERN void poststring(char *s);
445EXTERN void postfloat(float f);
446EXTERN void postatom(int argc, t_atom *argv);
447EXTERN void endpost(void);
448EXTERN void error(char *fmt, ...);
449EXTERN void bug(char *fmt, ...);
450EXTERN void pd_error(void *object, char *fmt, ...);
451EXTERN void sys_logerror(char *object, char *s);
452EXTERN void sys_unixerror(char *object);
453EXTERN void sys_ouch(void);
454
455#ifdef __linux__
456EXTERN char* sys_get_path( void);
457#endif
458EXTERN void sys_addpath(const char* p);
459
460
461/* ------------ system interface routines ------------------- */
462EXTERN int sys_isreadablefile(const char *name);
463EXTERN void sys_bashfilename(const char *from, char *to);
464EXTERN void sys_unbashfilename(const char *from, char *to);
465EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
466 char *dirresult, char **nameresult, unsigned int size, int bin);
467EXTERN int sched_geteventno(void);
468EXTERN double sys_getrealtime(void);
469
470
471/* ------------ threading ------------------- */
472/* T.Grill - see m_sched.c */
473
474EXTERN void sys_lock(void);
475EXTERN void sys_unlock(void);
476EXTERN int sys_trylock(void);
477
478
479/* --------------- signals ----------------------------------- */
480
481#define MAXLOGSIG 32
482#define MAXSIGSIZE (1 << MAXLOGSIG)
483#ifndef FIXEDPOINT
484typedef float t_sample;
485#else
486#include "m_fixed.h"
487#endif
488
489
490typedef struct _signal
491{
492 int s_n; /* number of points in the array */
493 t_sample *s_vec; /* the array */
494 float s_sr; /* sample rate */
495 int s_refcount; /* number of times used */
496 int s_isborrowed; /* whether we're going to borrow our array */
497 struct _signal *s_borrowedfrom; /* signal to borrow it from */
498 struct _signal *s_nextfree; /* next in freelist */
499 struct _signal *s_nextused; /* next in used list */
500} t_signal;
501
502
503typedef t_int *(*t_perfroutine)(t_int *args);
504
505EXTERN t_int *plus_perform(t_int *args);
506EXTERN t_int *zero_perform(t_int *args);
507EXTERN t_int *copy_perform(t_int *args);
508
509EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
510EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
511EXTERN void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n);
512EXTERN void dsp_add_zero(t_sample *out, int n);
513
514EXTERN int sys_getblksize(void);
515EXTERN float sys_getsr(void);
516EXTERN int sys_get_inchannels(void);
517EXTERN int sys_get_outchannels(void);
518
519EXTERN void dsp_add(t_perfroutine f, int n, ...);
520EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
521EXTERN void pd_fft(float *buf, int npoints, int inverse);
522EXTERN int ilog2(int n);
523
524EXTERN void mayer_fht(t_sample *fz, int n);
525EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag);
526EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag);
527EXTERN void mayer_realfft(int n, t_sample *real);
528EXTERN void mayer_realifft(int n, t_sample *real);
529
530EXTERN t_sample *cos_table;
531
532#define LOGCOSTABSIZE 9
533#define COSTABSIZE (1<<LOGCOSTABSIZE)
534
535EXTERN int canvas_suspend_dsp(void);
536EXTERN void canvas_resume_dsp(int oldstate);
537EXTERN void canvas_update_dsp(void);
538
539/* IOhannes { (up/downsampling) */
540typedef struct _resample
541{
542 int method; /* up/downsampling method ID */
543
544 t_int downsample; /* downsampling factor */
545 t_int upsample; /* upsampling factor */
546
547 t_sample *s_vec; /* here we hold the resampled data */
548 int s_n;
549
550 t_sample *coeffs; /* coefficients for filtering... */
551 int coefsize;
552
553 t_sample *buffer; /* buffer for filtering */
554 int bufsize;
555} t_resample;
556
557EXTERN void resample_init(t_resample *x);
558EXTERN void resample_free(t_resample *x);
559
560EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
561EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
562EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
563/* } IOhannes */
564
565/* ----------------------- utility functions for signals -------------- */
566EXTERN float mtof(float);
567EXTERN float ftom(float);
568EXTERN float rmstodb(float);
569EXTERN float powtodb(float);
570EXTERN float dbtorms(float);
571EXTERN float dbtopow(float);
572
573EXTERN float q8_sqrt(float);
574EXTERN float q8_rsqrt(float);
575#ifndef N32
576EXTERN float qsqrt(float); /* old names kept for extern compatibility */
577EXTERN float qrsqrt(float);
578#endif
579/* --------------------- data --------------------------------- */
580
581 /* graphical arrays */
582EXTERN_STRUCT _garray;
583#define t_garray struct _garray
584
585EXTERN t_class *garray_class;
586EXTERN int garray_getfloatarray(t_garray *x, int *size, t_sample **vec);
587EXTERN float garray_get(t_garray *x, t_symbol *s, t_int indx);
588EXTERN void garray_redraw(t_garray *x);
589EXTERN int garray_npoints(t_garray *x);
590EXTERN char *garray_vec(t_garray *x);
591EXTERN void garray_resize(t_garray *x, t_floatarg f);
592EXTERN void garray_usedindsp(t_garray *x);
593EXTERN void garray_setsaveit(t_garray *x, int saveit);
594EXTERN t_class *scalar_class;
595
596EXTERN t_float *value_get(t_symbol *s);
597EXTERN void value_release(t_symbol *s);
598EXTERN int value_getfloat(t_symbol *s, t_float *f);
599EXTERN int value_setfloat(t_symbol *s, t_float f);
600
601/* ------- GUI interface - functions to send strings to TK --------- */
602EXTERN void sys_vgui(char *fmt, ...);
603EXTERN void sys_gui(char *s);
604
605 /* dialog window creation and destruction */
606EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd);
607EXTERN void gfxstub_deleteforkey(void *key);
608
609extern t_class *glob_pdobject; /* object to send "pd" messages */
610
611/*------------- Max 0.26 compatibility --------------------*/
612
613/* the following reflects the new way classes are laid out, with the class
614 pointing to the messlist and not vice versa. Externs shouldn't feel it. */
615typedef t_class *t_externclass;
616
617EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine,
618 t_method freeroutine, t_symbol *name, size_t size, int tiny, \
619 t_atomtype arg1, ...);
620EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...);
621
622#define t_getbytes getbytes
623#define t_freebytes freebytes
624#define t_resizebytes resizebytes
625#define typedmess pd_typedmess
626#define vmess pd_vmess
627
628/* A definition to help gui objects straddle 0.34-0.35 changes. If this is
629defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
630
631#define PD_USE_TE_XPIX
632
633#if 0
634/* a test for NANs and denormals. Should only be necessary on i386. */
635#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
636 (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
637/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
638#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
639 (((*(unsigned int*)&(f))&0x60000000)==0x60000000))
640#else
641#define PD_BADFLOAT(f) 0
642#define PD_BIGORSMALL(f) 0
643#endif
644
645#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
646}
647#endif
648
649#define __m_pd_h_
650#endif /* __m_pd_h_ */
651/* Copyright (c) 1997-1999 Miller Puckette.
652* For information on usage and redistribution, and for a DISCLAIMER OF ALL
653* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
654
655#ifndef __m_pd_h_
656
657#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
658extern "C" {
659#endif
660
661#define PD_VERSION 0.37 /* oops, don't use this... */ */
662#define PD_MAJOR_VERSION 0 /* ... use these two instead. */
663#define PD_MINOR_VERSION 37
664
665/* old name for "MSW" flag -- we have to take it for the sake of many old
666"nmakefiles" for externs, which will define NT and not MSW */
667#if defined(NT) && !defined(MSW)
668#define MSW
669#endif
670
671#ifdef MSW
672// #pragma warning( disable : 4091 )
673#pragma warning( disable : 4305 ) /* uncast const double to float */
674#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */
675#pragma warning( disable : 4101 ) /* unused automatic variables */
676#endif /* MSW */
677
678 /* the external storage class is "extern" in UNIX; in MSW it's ugly. */
679#ifdef MSW
680#ifdef PD_INTERNAL
681#define EXTERN __declspec(dllexport) extern
682#else
683#define EXTERN __declspec(dllimport) extern
684#endif /* PD_INTERNAL */
685#else
686#define EXTERN extern
687#endif /* MSW */
688
689 /* and depending on the compiler, hidden data structures are
690 declared differently: */
691#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ )
692#define EXTERN_STRUCT struct
693#else
694#define EXTERN_STRUCT extern struct
695#endif
696
697
698#if !defined(_SIZE_T) && !defined(_SIZE_T_)
699#include <stddef.h> /* just for size_t -- how lame! */
700#endif
701
702#define MAXPDSTRING 1000 /* use this for anything you want */
703#define MAXPDARG 5 /* max number of args we can typecheck today */
704
705 /* signed and unsigned integer types the size of a pointer: */
706#ifdef __alpha__
707typedef long t_int;
708#else
709typedef int t_int;
710#endif
711
712typedef float t_float; /* a floating-point number at most the same size */
713typedef float t_floatarg; /* floating-point type for function calls */
714
715typedef struct _symbol
716{
717 char *s_name;
718 struct _class **s_thing;
719 struct _symbol *s_next;
720} t_symbol;
721
722EXTERN_STRUCT _array;
723#define t_array struct _array /* g_canvas.h */
724
725/* pointers to glist and array elements go through a "stub" which sticks
726around after the glist or array is freed. The stub itself is deleted when
727both the glist/array is gone and the refcount is zero, ensuring that no
728gpointers are pointing here. */
729
730#define GP_NONE 0 /* the stub points nowhere (has been cut off) */
731#define GP_GLIST 1 /* the stub points to a glist element */
732#define GP_ARRAY 2 /* ... or array */
733
734typedef struct _gstub
735{
736 union
737 {
738 struct _glist *gs_glist; /* glist we're in */
739 struct _array *gs_array; /* array we're in */
740 } gs_un;
741 int gs_which; /* GP_GLIST/GP_ARRAY */
742 int gs_refcount; /* number of gpointers pointing here */
743} t_gstub;
744
745typedef struct _gpointer /* pointer to a gobj in a glist */
746{
747 union
748 {
749 struct _scalar *gp_scalar; /* scalar we're in (if glist) */
750 union word *gp_w; /* raw data (if array) */
751 } gp_un;
752 int gp_valid; /* number which must match gpointee */
753 t_gstub *gp_stub; /* stub which points to glist/array */
754} t_gpointer;
755
756typedef union word
757{
758 t_float w_float;
759 t_symbol *w_symbol;
760 t_gpointer *w_gpointer;
761 t_array *w_array;
762 struct _glist *w_list;
763 int w_index;
764} t_word;
765
766typedef enum
767{
768 A_NULL,
769 A_FLOAT,
770 A_SYMBOL,
771 A_POINTER,
772 A_SEMI,
773 A_COMMA,
774 A_DEFFLOAT,
775 A_DEFSYM,
776 A_DOLLAR,
777 A_DOLLSYM,
778 A_GIMME,
779 A_CANT
780} t_atomtype;
781
782#define A_DEFSYMBOL A_DEFSYM /* better name for this */
783
784typedef struct _atom
785{
786 t_atomtype a_type;
787 union word a_w;
788} t_atom;
789
790EXTERN_STRUCT _class;
791#define t_class struct _class
792
793EXTERN_STRUCT _outlet;
794#define t_outlet struct _outlet
795
796EXTERN_STRUCT _inlet;
797#define t_inlet struct _inlet
798
799EXTERN_STRUCT _binbuf;
800#define t_binbuf struct _binbuf
801
802EXTERN_STRUCT _clock;
803#define t_clock struct _clock
804
805EXTERN_STRUCT _outconnect;
806#define t_outconnect struct _outconnect
807
808EXTERN_STRUCT _glist;
809#define t_glist struct _glist
810#define t_canvas struct _glist /* LATER lose this */
811
812typedef t_class *t_pd; /* pure datum: nothing but a class pointer */
813
814typedef struct _gobj /* a graphical object */
815{
816 t_pd g_pd; /* pure datum header (class) */
817 struct _gobj *g_next; /* next in list */
818} t_gobj;
819
820typedef struct _scalar /* a graphical object holding data */
821{
822 t_gobj sc_gobj; /* header for graphical object */
823 t_symbol *sc_template; /* template name (LATER replace with pointer) */
824 t_word sc_vec[1]; /* indeterminate-length array of words */
825} t_scalar;
826
827typedef struct _text /* patchable object - graphical, with text */
828{
829 t_gobj te_g; /* header for graphical object */
830 t_binbuf *te_binbuf; /* holder for the text */
831 t_outlet *te_outlet; /* linked list of outlets */
832 t_inlet *te_inlet; /* linked list of inlets */
833 short te_xpix; /* x&y location (within the toplevel) */
834 short te_ypix;
835 short te_width; /* requested width in chars, 0 if auto */
836 unsigned int te_type:2; /* from defs below */
837} t_text;
838
839#define T_TEXT 0 /* just a textual comment */
840#define T_OBJECT 1 /* a MAX style patchable object */
841#define T_MESSAGE 2 /* a MAX stype message */
842#define T_ATOM 3 /* a cell to display a number or symbol */
843
844#define te_pd te_g.g_pd
845
846 /* t_object is synonym for t_text (LATER unify them) */
847
848typedef struct _text t_object;
849
850#define ob_outlet te_outlet
851#define ob_inlet te_inlet
852#define ob_binbuf te_binbuf
853#define ob_pd te_g.g_pd
854#define ob_g te_g
855
856typedef void (*t_method)(void);
857typedef void *(*t_newmethod)( void);
858typedef void (*t_gotfn)(void *x, ...);
859
860/* ---------------- pre-defined objects and symbols --------------*/
861EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */
862EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */
863EXTERN t_symbol s_pointer;
864EXTERN t_symbol s_float;
865EXTERN t_symbol s_symbol;
866EXTERN t_symbol s_bang;
867EXTERN t_symbol s_list;
868EXTERN t_symbol s_anything;
869EXTERN t_symbol s_signal;
870EXTERN t_symbol s__N;
871EXTERN t_symbol s__X;
872EXTERN t_symbol s_x;
873EXTERN t_symbol s_y;
874EXTERN t_symbol s_;
875
876/* --------- prototypes from the central message system ----------- */
877EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
878EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
879EXTERN t_symbol *gensym(char *s);
880EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
881EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
882EXTERN void nullfn(void);
883EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
884#define mess0(x, s) ((*getfn((x), (s)))((x)))
885#define mess1(x, s, a) ((*getfn((x), (s)))((x), (a)))
886#define mess2(x, s, a,b) ((*getfn((x), (s)))((x), (a),(b)))
887#define mess3(x, s, a,b,c) ((*getfn((x), (s)))((x), (a),(b),(c)))
888#define mess4(x, s, a,b,c,d) ((*getfn((x), (s)))((x), (a),(b),(c),(d)))
889#define mess5(x, s, a,b,c,d,e) ((*getfn((x), (s)))((x), (a),(b),(c),(d),(e)))
890EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
891EXTERN t_pd *pd_newest(void);
892
893/* --------------- memory management -------------------- */
894EXTERN void *getbytes(size_t nbytes);
895EXTERN void *getzbytes(size_t nbytes);
896EXTERN void *copybytes(void *src, size_t nbytes);
897EXTERN void freebytes(void *x, size_t nbytes);
898EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize);
899
900/* -------------------- atoms ----------------------------- */
901
902#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0)
903#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0)
904#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \
905 (atom)->a_w.w_gpointer = (gp))
906#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f))
907#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \
908 (atom)->a_w.w_symbol = (s))
909#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \
910 (atom)->a_w.w_index = (n))
911#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \
912 (atom)->a_w.w_symbol= (s))
913
914EXTERN t_float atom_getfloat(t_atom *a);
915EXTERN t_int atom_getint(t_atom *a);
916EXTERN t_symbol *atom_getsymbol(t_atom *a);
917EXTERN t_symbol *atom_gensym(t_atom *a);
918EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv);
919EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv);
920EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
921
922EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
923
924/* ------------------ binbufs --------------- */
925
926EXTERN t_binbuf *binbuf_new(void);
927EXTERN void binbuf_free(t_binbuf *x);
928EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y);
929
930EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
931EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
932EXTERN void binbuf_clear(t_binbuf *x);
933EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
934EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
935EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
936EXTERN void binbuf_addsemi(t_binbuf *x);
937EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
938EXTERN void binbuf_print(t_binbuf *x);
939EXTERN int binbuf_getnatom(t_binbuf *x);
940EXTERN t_atom *binbuf_getvec(t_binbuf *x);
941EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
942EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname,
943 int crflag);
944EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
945 int crflag);
946EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir,
947 int crflag);
948EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
949EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av,
950 int tonew);
951
952/* ------------------ clocks --------------- */
953
954typedef long long t_time;
955EXTERN t_clock *clock_new(void *owner, t_method fn);
956EXTERN void clock_set(t_clock *x, t_time systime);
957EXTERN void clock_delay(t_clock *x, t_time delaytime);
958EXTERN void clock_unset(t_clock *x);
959EXTERN t_time clock_getlogicaltime(void);
960EXTERN t_time clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
961EXTERN t_time clock_gettimesince(t_time prevsystime);
962EXTERN t_time clock_getsystimeafter(t_time delaytime);
963EXTERN void clock_free(t_clock *x);
964
965/* ----------------- pure data ---------------- */
966EXTERN t_pd *pd_new(t_class *cls);
967EXTERN void pd_free(t_pd *x);
968EXTERN void pd_bind(t_pd *x, t_symbol *s);
969EXTERN void pd_unbind(t_pd *x, t_symbol *s);
970EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
971EXTERN void pd_pushsym(t_pd *x);
972EXTERN void pd_popsym(t_pd *x);
973EXTERN t_symbol *pd_getfilename(void);
974EXTERN t_symbol *pd_getdirname(void);
975EXTERN void pd_bang(t_pd *x);
976EXTERN void pd_pointer(t_pd *x, t_gpointer *gp);
977EXTERN void pd_float(t_pd *x, t_float f);
978EXTERN void pd_symbol(t_pd *x, t_symbol *s);
979EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv);
980EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv);
981#define pd_class(x) (*(x))
982
983/* ----------------- pointers ---------------- */
984EXTERN void gpointer_init(t_gpointer *gp);
985EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
986EXTERN void gpointer_unset(t_gpointer *gp);
987EXTERN int gpointer_check(const t_gpointer *gp, int headok);
988
989/* ----------------- patchable "objects" -------------- */
990EXTERN_STRUCT _inlet;
991#define t_inlet struct _inlet
992EXTERN_STRUCT _outlet;
993#define t_outlet struct _outlet
994
995EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1,
996 t_symbol *s2);
997EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
998EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
999EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
1000EXTERN void inlet_free(t_inlet *x);
1001
1002EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
1003EXTERN void outlet_bang(t_outlet *x);
1004EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp);
1005EXTERN void outlet_float(t_outlet *x, t_float f);
1006EXTERN void outlet_symbol(t_outlet *x, t_symbol *s);
1007EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
1008EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
1009EXTERN t_symbol *outlet_getsymbol(t_outlet *x);
1010EXTERN void outlet_free(t_outlet *x);
1011EXTERN t_object *pd_checkobject(t_pd *x);
1012
1013
1014/* -------------------- canvases -------------- */
1015
1016EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
1017
1018EXTERN void canvas_setargs(int argc, t_atom *argv);
1019EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
1020EXTERN t_symbol *canvas_getcurrentdir(void);
1021EXTERN t_glist *canvas_getcurrent(void);
1022EXTERN void canvas_makefilename(t_glist *c, char *file,
1023 char *result,int resultsize);
1024EXTERN t_symbol *canvas_getdir(t_glist *x);
1025EXTERN int sys_fontwidth(int fontsize);
1026EXTERN int sys_fontheight(int fontsize);
1027EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
1028
1029/* ---------------- widget behaviors ---------------------- */
1030
1031EXTERN_STRUCT _widgetbehavior;
1032#define t_widgetbehavior struct _widgetbehavior
1033
1034EXTERN_STRUCT _parentwidgetbehavior;
1035#define t_parentwidgetbehavior struct _parentwidgetbehavior
1036EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x);
1037
1038/* -------------------- classes -------------- */
1039
1040#define CLASS_DEFAULT 0 /* flags for new classes below */
1041#define CLASS_PD 1
1042#define CLASS_GOBJ 2
1043#define CLASS_PATCHABLE 3
1044#define CLASS_NOINLET 8
1045
1046#define CLASS_TYPEMASK 3
1047
1048
1049EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod,
1050 t_method freemethod, size_t size, int flags, t_atomtype arg1, ...);
1051EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s,
1052 t_atomtype type1, ...);
1053EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
1054 t_atomtype arg1, ...);
1055EXTERN void class_addbang(t_class *c, t_method fn);
1056EXTERN void class_addpointer(t_class *c, t_method fn);
1057EXTERN void class_doaddfloat(t_class *c, t_method fn);
1058EXTERN void class_addsymbol(t_class *c, t_method fn);
1059EXTERN void class_addlist(t_class *c, t_method fn);
1060EXTERN void class_addanything(t_class *c, t_method fn);
1061EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
1062EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w);
1063EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w);
1064EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c);
1065EXTERN char *class_getname(t_class *c);
1066EXTERN char *class_gethelpname(t_class *c);
1067EXTERN void class_setdrawcommand(t_class *c);
1068EXTERN int class_isdrawcommand(t_class *c);
1069EXTERN void class_domainsignalin(t_class *c, int onset);
1070#define CLASS_MAINSIGNALIN(c, type, field) \
1071 class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
1072
1073 /* prototype for functions to save Pd's to a binbuf */
1074typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
1075EXTERN void class_setsavefn(t_class *c, t_savefn f);
1076EXTERN t_savefn class_getsavefn(t_class *c);
1077 /* prototype for functions to open properties dialogs */
1078typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist);
1079EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f);
1080EXTERN t_propertiesfn class_getpropertiesfn(t_class *c);
1081
1082#ifndef PD_CLASS_DEF
1083#define class_addbang(x, y) class_addbang((x), (t_method)(y))
1084#define class_addpointer(x, y) class_addpointer((x), (t_method)(y))
1085#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y))
1086#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y))
1087#define class_addlist(x, y) class_addlist((x), (t_method)(y))
1088#define class_addanything(x, y) class_addanything((x), (t_method)(y))
1089#endif
1090
1091/* ------------ printing --------------------------------- */
1092EXTERN void post(char *fmt, ...);
1093EXTERN void startpost(char *fmt, ...);
1094EXTERN void poststring(char *s);
1095EXTERN void postfloat(float f);
1096EXTERN void postatom(int argc, t_atom *argv);
1097EXTERN void endpost(void);
1098EXTERN void error(char *fmt, ...);
1099EXTERN void bug(char *fmt, ...);
1100EXTERN void pd_error(void *object, char *fmt, ...);
1101EXTERN void sys_logerror(char *object, char *s);
1102EXTERN void sys_unixerror(char *object);
1103EXTERN void sys_ouch(void);
1104
1105#ifdef __linux__
1106EXTERN char* sys_get_path( void);
1107#endif
1108EXTERN void sys_addpath(const char* p);
1109
1110
1111/* ------------ system interface routines ------------------- */
1112EXTERN int sys_isreadablefile(const char *name);
1113EXTERN void sys_bashfilename(const char *from, char *to);
1114EXTERN void sys_unbashfilename(const char *from, char *to);
1115EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
1116 char *dirresult, char **nameresult, unsigned int size, int bin);
1117EXTERN int sched_geteventno(void);
1118EXTERN double sys_getrealtime(void);
1119
1120
1121/* ------------ threading ------------------- */
1122/* T.Grill - see m_sched.c */
1123
1124EXTERN void sys_lock(void);
1125EXTERN void sys_unlock(void);
1126EXTERN int sys_trylock(void);
1127
1128
1129/* --------------- signals ----------------------------------- */
1130
1131#define MAXLOGSIG 32
1132#define MAXSIGSIZE (1 << MAXLOGSIG)
1133#ifndef FIXEDPOINT
1134typedef float t_sample;
1135#else
1136#include "m_fixed.h"
1137#endif
1138
1139
1140typedef struct _signal
1141{
1142 int s_n; /* number of points in the array */
1143 t_sample *s_vec; /* the array */
1144 float s_sr; /* sample rate */
1145 int s_refcount; /* number of times used */
1146 int s_isborrowed; /* whether we're going to borrow our array */
1147 struct _signal *s_borrowedfrom; /* signal to borrow it from */
1148 struct _signal *s_nextfree; /* next in freelist */
1149 struct _signal *s_nextused; /* next in used list */
1150} t_signal;
1151
1152
1153typedef t_int *(*t_perfroutine)(t_int *args);
1154
1155EXTERN t_int *plus_perform(t_int *args);
1156EXTERN t_int *zero_perform(t_int *args);
1157EXTERN t_int *copy_perform(t_int *args);
1158
1159EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
1160EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
1161EXTERN void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n);
1162EXTERN void dsp_add_zero(t_sample *out, int n);
1163
1164EXTERN int sys_getblksize(void);
1165EXTERN float sys_getsr(void);
1166EXTERN int sys_get_inchannels(void);
1167EXTERN int sys_get_outchannels(void);
1168
1169EXTERN void dsp_add(t_perfroutine f, int n, ...);
1170EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
1171EXTERN void pd_fft(float *buf, int npoints, int inverse);
1172EXTERN int ilog2(int n);
1173
1174EXTERN void mayer_fht(t_sample *fz, int n);
1175EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag);
1176EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag);
1177EXTERN void mayer_realfft(int n, t_sample *real);
1178EXTERN void mayer_realifft(int n, t_sample *real);
1179
1180EXTERN t_sample *cos_table;
1181
1182#define LOGCOSTABSIZE 9
1183#define COSTABSIZE (1<<LOGCOSTABSIZE)
1184
1185EXTERN int canvas_suspend_dsp(void);
1186EXTERN void canvas_resume_dsp(int oldstate);
1187EXTERN void canvas_update_dsp(void);
1188
1189/* IOhannes { (up/downsampling) */
1190typedef struct _resample
1191{
1192 int method; /* up/downsampling method ID */
1193
1194 t_int downsample; /* downsampling factor */
1195 t_int upsample; /* upsampling factor */
1196
1197 t_sample *s_vec; /* here we hold the resampled data */
1198 int s_n;
1199
1200 t_sample *coeffs; /* coefficients for filtering... */
1201 int coefsize;
1202
1203 t_sample *buffer; /* buffer for filtering */
1204 int bufsize;
1205} t_resample;
1206
1207EXTERN void resample_init(t_resample *x);
1208EXTERN void resample_free(t_resample *x);
1209
1210EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
1211EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
1212EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
1213/* } IOhannes */
1214
1215/* ----------------------- utility functions for signals -------------- */
1216EXTERN float mtof(float);
1217EXTERN float ftom(float);
1218EXTERN float rmstodb(float);
1219EXTERN float powtodb(float);
1220EXTERN float dbtorms(float);
1221EXTERN float dbtopow(float);
1222
1223EXTERN float q8_sqrt(float);
1224EXTERN float q8_rsqrt(float);
1225#ifndef N32
1226EXTERN float qsqrt(float); /* old names kept for extern compatibility */
1227EXTERN float qrsqrt(float);
1228#endif
1229/* --------------------- data --------------------------------- */
1230
1231 /* graphical arrays */
1232EXTERN_STRUCT _garray;
1233#define t_garray struct _garray
1234
1235EXTERN t_class *garray_class;
1236EXTERN int garray_getfloatarray(t_garray *x, int *size, t_sample **vec);
1237EXTERN float garray_get(t_garray *x, t_symbol *s, t_int indx);
1238EXTERN void garray_redraw(t_garray *x);
1239EXTERN int garray_npoints(t_garray *x);
1240EXTERN char *garray_vec(t_garray *x);
1241EXTERN void garray_resize(t_garray *x, t_floatarg f);
1242EXTERN void garray_usedindsp(t_garray *x);
1243EXTERN void garray_setsaveit(t_garray *x, int saveit);
1244EXTERN t_class *scalar_class;
1245
1246EXTERN t_float *value_get(t_symbol *s);
1247EXTERN void value_release(t_symbol *s);
1248EXTERN int value_getfloat(t_symbol *s, t_float *f);
1249EXTERN int value_setfloat(t_symbol *s, t_float f);
1250
1251/* ------- GUI interface - functions to send strings to TK --------- */
1252EXTERN void sys_vgui(char *fmt, ...);
1253EXTERN void sys_gui(char *s);
1254
1255 /* dialog window creation and destruction */
1256EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd);
1257EXTERN void gfxstub_deleteforkey(void *key);
1258
1259extern t_class *glob_pdobject; /* object to send "pd" messages */
1260
1261/*------------- Max 0.26 compatibility --------------------*/
1262
1263/* the following reflects the new way classes are laid out, with the class
1264 pointing to the messlist and not vice versa. Externs shouldn't feel it. */
1265typedef t_class *t_externclass;
1266
1267EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine,
1268 t_method freeroutine, t_symbol *name, size_t size, int tiny, \
1269 t_atomtype arg1, ...);
1270EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...);
1271
1272#define t_getbytes getbytes
1273#define t_freebytes freebytes
1274#define t_resizebytes resizebytes
1275#define typedmess pd_typedmess
1276#define vmess pd_vmess
1277
1278/* A definition to help gui objects straddle 0.34-0.35 changes. If this is
1279defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
1280
1281#define PD_USE_TE_XPIX
1282
1283#if 0
1284/* a test for NANs and denormals. Should only be necessary on i386. */
1285#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
1286 (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
1287/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
1288#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
1289 (((*(unsigned int*)&(f))&0x60000000)==0x60000000))
1290#else
1291#define PD_BADFLOAT(f) 0
1292#define PD_BIGORSMALL(f) 0
1293#endif
1294
1295#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
1296}
1297#endif
1298
1299#define __m_pd_h_
1300#endif /* __m_pd_h_ */
diff --git a/apps/plugins/pdbox/PDa/extra/makefile b/apps/plugins/pdbox/PDa/extra/makefile
new file mode 100644
index 0000000000..270491de63
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/makefile
@@ -0,0 +1,66 @@
1
2VERSION = 0.2
3SOURCE = $(shell ls *.c)
4TARGETS = $(SOURCE:.c=.pd_linux)
5
6EXT= pd_linux
7
8AFLAGS = -g -O2 -I./ -DFIXEDPOINT
9EFLAGS = -shared -Wl,-export-dynamic
10PREFIX = /usr
11
12
13all: $(TARGETS)
14
15clean:
16 -rm $(TARGETS)
17 -rm *.o *~
18
19tar: clean
20 cd ..;tar czvf PDa-externals-$(VERSION).tgz PDa-externals
21
22upload: tar
23 scp ../PDa-externals-$(VERSION).tgz gige@xdv.org:~/www/pda/release
24
25install:
26 install -d $(DESTDIR)/$(PREFIX)/lib/pd/extra
27 cp $(TARGETS) $(DESTDIR)/$(PREFIX)/lib/pd/extra
28
29%.$(EXT) : %.o
30 $(CC) -o $@ $(EFLAGS) $+
31
32%.o : %.c
33 $(CC) -c $(AFLAGS) $(CFLAGS) $+
34
35VERSION = 0.2
36SOURCE = $(shell ls *.c)
37TARGETS = $(SOURCE:.c=.pd_linux)
38
39EXT= pd_linux
40
41AFLAGS = -g -O2 -I./ -DFIXEDPOINT
42EFLAGS = -shared -Wl,-export-dynamic
43PREFIX = /usr
44
45
46all: $(TARGETS)
47
48clean:
49 -rm $(TARGETS)
50 -rm *.o *~
51
52tar: clean
53 cd ..;tar czvf PDa-externals-$(VERSION).tgz PDa-externals
54
55upload: tar
56 scp ../PDa-externals-$(VERSION).tgz gige@xdv.org:~/www/pda/release
57
58install:
59 install -d $(DESTDIR)/$(PREFIX)/lib/pd/extra
60 cp $(TARGETS) $(DESTDIR)/$(PREFIX)/lib/pd/extra
61
62%.$(EXT) : %.o
63 $(CC) -o $@ $(EFLAGS) $+
64
65%.o : %.c
66 $(CC) -c $(AFLAGS) $(CFLAGS) $+ \ No newline at end of file
diff --git a/apps/plugins/pdbox/PDa/extra/moog~.c b/apps/plugins/pdbox/PDa/extra/moog~.c
new file mode 100644
index 0000000000..ee7acc99aa
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/moog~.c
@@ -0,0 +1,366 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3
4#include "math.h"
5#include <m_pd.h>
6
7/* ----------------------------- moog ----------------------------- */
8static t_class *moog_class;
9
10
11typedef struct _moog
12{
13 t_object x_obj;
14 t_pd in2;
15 t_sample x_1,x_2,x_3,x_4;
16 t_sample y_1,y_2,y_3,y_4;
17} t_moog;
18
19static void moog_reset(t_moog *x)
20{
21 x->x_1 = x->x_2 = x->x_3 = x->x_4 = 0;
22 x->y_1 = x->y_2 = x->y_3 = x->y_4 = 0;
23
24}
25
26
27
28static void *moog_new(t_symbol *s, int argc, t_atom *argv)
29{
30 if (argc > 1) post("moog~: extra arguments ignored");
31 {
32 t_moog *x = (t_moog *)pd_new(moog_class);
33 outlet_new(&x->x_obj, &s_signal);
34 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
35 inlet_new(&x->x_obj, &x->in2, &s_signal, &s_signal);
36 moog_reset(x);
37 return (x);
38 }
39
40
41}
42
43
44
45static t_sample calc_k(t_sample f,t_sample k) {
46 if (k>itofix(4)) k = itofix(4);
47 if (k < 0) k = 0;
48 if (f <= itofix(3800)) return k;
49 k = k - mult(0.5,(f-idiv(itofix(3800),itofix(4300))));
50 return k;
51}
52
53t_int *moog_perform(t_int *w)
54{
55 t_moog* x = (t_moog*) (w[1]);
56 t_sample *in1 = (t_sample *)(w[2]);
57 t_sample *p = (t_sample *)(w[3]);
58 t_sample *k = (t_sample *)(w[4]);
59
60 t_sample *out = (t_sample *)(w[5]);
61 int n = (int)(w[6]);
62 t_sample in;
63 t_sample pt,pt1;
64
65 t_sample x1 = x->x_1;
66 t_sample x2 = x->x_2;
67 t_sample x3 = x->x_3;
68 t_sample x4 = x->x_4;
69 t_sample ys1 = x->y_1;
70 t_sample ys2 = x->y_2;
71 t_sample ys3 = x->y_3;
72 t_sample ys4 = x->y_4;
73
74
75 while (n--) {
76 if (*p > itofix(8140)) *p = itofix(8140);
77 *k = calc_k(*p,*k);
78 pt =*p;
79 pt1=mult((pt+1),ftofix(0.76923077));
80 in = *in1++ - mult(*k,ys4);
81 ys1 = mult(pt1,in) + mult(0.3,x1) - mult(pt,ys1);
82 x1 = in;
83 ys2 = mult(pt1,ys1) + mult(0.3,x2) - mult(pt,ys2);
84 x2 = ys1;
85 ys3 = mult(pt1,ys2) + mult(0.3,x3) - mult(pt,ys3);
86 x3 = ys2;
87 ys4 = mult(pt1,ys3) + mult(0.3,x4) - mult(pt,ys4);
88 x4 = ys3;
89 *out++ = ys4;
90 }
91
92
93 x->y_1 = ys1;
94 x->y_2 = ys2;
95 x->y_3 = ys3;
96 x->y_4 = ys4;
97 x->x_1 = x1;
98 x->x_2 = x2;
99 x->x_3 = x3;
100 x->x_4 = x4;
101
102 return (w+7);
103}
104
105
106#define CLIP(x) x = ((x) > 1.0 ? (1.0) : (x))
107
108t_int *moog_perf8(t_int *w)
109{
110 t_moog* x = (t_moog*) (w[1]);
111 t_sample *in1 = (t_sample *)(w[2]);
112 t_sample *p = (t_sample *)(w[3]);
113 t_sample *k = (t_sample *)(w[4]);
114 t_sample *out = (t_sample *)(w[5]);
115 int n = (int)(w[6]);
116
117 t_sample x1 = x->x_1;
118 t_sample x2 = x->x_2;
119 t_sample x3 = x->x_3;
120 t_sample x4 = x->x_4;
121 t_sample ys1 = x->y_1;
122 t_sample ys2 = x->y_2;
123 t_sample ys3 = x->y_3;
124 t_sample ys4 = x->y_4;
125
126 t_sample temp,temp2;
127 t_sample pt,pt1;
128 t_sample in;
129
130 while (n--) {
131 if (*p > itofix(8140)) *p = itofix(8140);
132 *k = calc_k(*p,*k);
133
134 pt =mult(*p, ftofix(0.01*0.0140845)) - ftofix(0.9999999f);
135 pt1=mult((pt+itofix(1)),ftofix(0.76923077));
136 in = *in1++ - mult(*k,ys4);
137 ys1 = mult(pt1,(in + mult(ftofix(0.3),x1))) - mult(pt,ys1);
138 x1 = in;
139 ys2 = mult(pt1,(ys1 + mult(0.3,x2))) - mult(pt,ys2);
140 x2 = ys1;
141 ys3 = mult(pt1,(ys2 + mult(0.3,x3))) - mult(pt,ys3);
142 x3 = ys2;
143 ys4 = mult(pt1,(ys3 + mult(0.3,x4))) - mult(pt,ys4);
144 x4 = ys3;
145 *out++ = ys4;
146
147 p++;k++;
148 }
149
150 x->y_1 = ys1;
151 x->y_2 = ys2;
152 x->y_3 = ys3;
153 x->y_4 = ys4;
154 x->x_1 = x1;
155 x->x_2 = x2;
156 x->x_3 = x3;
157 x->x_4 = x4;
158
159 return (w+7);
160}
161
162void dsp_add_moog(t_moog *x, t_sample *in1, t_sample *in2, t_sample *in3, t_sample *out, int n)
163{
164 if (n&7)
165 dsp_add(moog_perform, 6,(t_int)x, in1,in2,in3, out, n);
166 else
167 dsp_add(moog_perf8, 6,(t_int) x, in1, in2, in3, out, n);
168}
169
170static void moog_dsp(t_moog *x, t_signal **sp)
171{
172 dsp_add_moog(x,sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,sp[0]->s_n);
173}
174
175
176void moog_tilde_setup(void)
177{
178 moog_class = class_new(gensym("moog~"), (t_newmethod)moog_new, 0,
179 sizeof(t_moog), 0, A_GIMME, 0);
180 class_addmethod(moog_class, nullfn, gensym("signal"), 0);
181 class_addmethod(moog_class, (t_method)moog_reset, gensym("reset"), 0);
182 class_addmethod(moog_class, (t_method)moog_dsp, gensym("dsp"), A_NULL);
183}
184/* (C) Guenter Geiger <geiger@epy.co.at> */
185
186
187#include "math.h"
188#include <m_pd.h>
189
190/* ----------------------------- moog ----------------------------- */
191static t_class *moog_class;
192
193
194typedef struct _moog
195{
196 t_object x_obj;
197 t_pd in2;
198 t_sample x_1,x_2,x_3,x_4;
199 t_sample y_1,y_2,y_3,y_4;
200} t_moog;
201
202static void moog_reset(t_moog *x)
203{
204 x->x_1 = x->x_2 = x->x_3 = x->x_4 = 0;
205 x->y_1 = x->y_2 = x->y_3 = x->y_4 = 0;
206
207}
208
209
210
211static void *moog_new(t_symbol *s, int argc, t_atom *argv)
212{
213 if (argc > 1) post("moog~: extra arguments ignored");
214 {
215 t_moog *x = (t_moog *)pd_new(moog_class);
216 outlet_new(&x->x_obj, &s_signal);
217 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
218 inlet_new(&x->x_obj, &x->in2, &s_signal, &s_signal);
219 moog_reset(x);
220 return (x);
221 }
222
223
224}
225
226
227
228static t_sample calc_k(t_sample f,t_sample k) {
229 if (k>itofix(4)) k = itofix(4);
230 if (k < 0) k = 0;
231 if (f <= itofix(3800)) return k;
232 k = k - mult(0.5,(f-idiv(itofix(3800),itofix(4300))));
233 return k;
234}
235
236t_int *moog_perform(t_int *w)
237{
238 t_moog* x = (t_moog*) (w[1]);
239 t_sample *in1 = (t_sample *)(w[2]);
240 t_sample *p = (t_sample *)(w[3]);
241 t_sample *k = (t_sample *)(w[4]);
242
243 t_sample *out = (t_sample *)(w[5]);
244 int n = (int)(w[6]);
245 t_sample in;
246 t_sample pt,pt1;
247
248 t_sample x1 = x->x_1;
249 t_sample x2 = x->x_2;
250 t_sample x3 = x->x_3;
251 t_sample x4 = x->x_4;
252 t_sample ys1 = x->y_1;
253 t_sample ys2 = x->y_2;
254 t_sample ys3 = x->y_3;
255 t_sample ys4 = x->y_4;
256
257
258 while (n--) {
259 if (*p > itofix(8140)) *p = itofix(8140);
260 *k = calc_k(*p,*k);
261 pt =*p;
262 pt1=mult((pt+1),ftofix(0.76923077));
263 in = *in1++ - mult(*k,ys4);
264 ys1 = mult(pt1,in) + mult(0.3,x1) - mult(pt,ys1);
265 x1 = in;
266 ys2 = mult(pt1,ys1) + mult(0.3,x2) - mult(pt,ys2);
267 x2 = ys1;
268 ys3 = mult(pt1,ys2) + mult(0.3,x3) - mult(pt,ys3);
269 x3 = ys2;
270 ys4 = mult(pt1,ys3) + mult(0.3,x4) - mult(pt,ys4);
271 x4 = ys3;
272 *out++ = ys4;
273 }
274
275
276 x->y_1 = ys1;
277 x->y_2 = ys2;
278 x->y_3 = ys3;
279 x->y_4 = ys4;
280 x->x_1 = x1;
281 x->x_2 = x2;
282 x->x_3 = x3;
283 x->x_4 = x4;
284
285 return (w+7);
286}
287
288
289#define CLIP(x) x = ((x) > 1.0 ? (1.0) : (x))
290
291t_int *moog_perf8(t_int *w)
292{
293 t_moog* x = (t_moog*) (w[1]);
294 t_sample *in1 = (t_sample *)(w[2]);
295 t_sample *p = (t_sample *)(w[3]);
296 t_sample *k = (t_sample *)(w[4]);
297 t_sample *out = (t_sample *)(w[5]);
298 int n = (int)(w[6]);
299
300 t_sample x1 = x->x_1;
301 t_sample x2 = x->x_2;
302 t_sample x3 = x->x_3;
303 t_sample x4 = x->x_4;
304 t_sample ys1 = x->y_1;
305 t_sample ys2 = x->y_2;
306 t_sample ys3 = x->y_3;
307 t_sample ys4 = x->y_4;
308
309 t_sample temp,temp2;
310 t_sample pt,pt1;
311 t_sample in;
312
313 while (n--) {
314 if (*p > itofix(8140)) *p = itofix(8140);
315 *k = calc_k(*p,*k);
316
317 pt =mult(*p, ftofix(0.01*0.0140845)) - ftofix(0.9999999f);
318 pt1=mult((pt+itofix(1)),ftofix(0.76923077));
319 in = *in1++ - mult(*k,ys4);
320 ys1 = mult(pt1,(in + mult(ftofix(0.3),x1))) - mult(pt,ys1);
321 x1 = in;
322 ys2 = mult(pt1,(ys1 + mult(0.3,x2))) - mult(pt,ys2);
323 x2 = ys1;
324 ys3 = mult(pt1,(ys2 + mult(0.3,x3))) - mult(pt,ys3);
325 x3 = ys2;
326 ys4 = mult(pt1,(ys3 + mult(0.3,x4))) - mult(pt,ys4);
327 x4 = ys3;
328 *out++ = ys4;
329
330 p++;k++;
331 }
332
333 x->y_1 = ys1;
334 x->y_2 = ys2;
335 x->y_3 = ys3;
336 x->y_4 = ys4;
337 x->x_1 = x1;
338 x->x_2 = x2;
339 x->x_3 = x3;
340 x->x_4 = x4;
341
342 return (w+7);
343}
344
345void dsp_add_moog(t_moog *x, t_sample *in1, t_sample *in2, t_sample *in3, t_sample *out, int n)
346{
347 if (n&7)
348 dsp_add(moog_perform, 6,(t_int)x, in1,in2,in3, out, n);
349 else
350 dsp_add(moog_perf8, 6,(t_int) x, in1, in2, in3, out, n);
351}
352
353static void moog_dsp(t_moog *x, t_signal **sp)
354{
355 dsp_add_moog(x,sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,sp[0]->s_n);
356}
357
358
359void moog_tilde_setup(void)
360{
361 moog_class = class_new(gensym("moog~"), (t_newmethod)moog_new, 0,
362 sizeof(t_moog), 0, A_GIMME, 0);
363 class_addmethod(moog_class, nullfn, gensym("signal"), 0);
364 class_addmethod(moog_class, (t_method)moog_reset, gensym("reset"), 0);
365 class_addmethod(moog_class, (t_method)moog_dsp, gensym("dsp"), A_NULL);
366}
diff --git a/apps/plugins/pdbox/PDa/extra/notch.c b/apps/plugins/pdbox/PDa/extra/notch.c
new file mode 100644
index 0000000000..49be753ff2
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/notch.c
@@ -0,0 +1,178 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3
4/*
5
6 These filter coefficients computations are taken from
7 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
8
9 written by Robert Bristow-Johnson
10
11*/
12
13#include "m_pd.h"
14#ifdef NT
15#pragma warning( disable : 4244 )
16#pragma warning( disable : 4305 )
17#endif
18#include <math.h>
19#include "filters.h"
20
21
22
23/* ------------------- notch ----------------------------*/
24
25static t_class *notch_class;
26
27void notch_bang(t_rbjfilter *x)
28{
29 t_atom at[5];
30 t_float omega = e_omega(x->x_freq,x->x_rate);
31 t_float alpha = e_alpha(x->x_bw* 0.01,omega);
32 t_float b1 = -2.*cos(omega);
33 t_float b0 = 1;
34 t_float b2 = b0;
35 t_float a0 = 1 + alpha;
36 t_float a1 = -2.*cos(omega);
37 t_float a2 = 1 - alpha;
38
39/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
40
41 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
42 post("notch: filter unstable -> resetting");
43 a0=1.;a1=0.;a2=0.;
44 b0=1.;b1=0.;b2=0.;
45 }
46
47 SETFLOAT(at,-a1/a0);
48 SETFLOAT(at+1,-a2/a0);
49 SETFLOAT(at+2,b0/a0);
50 SETFLOAT(at+3,b1/a0);
51 SETFLOAT(at+4,b2/a0);
52
53 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
54}
55
56
57void notch_float(t_rbjfilter *x,t_floatarg f)
58{
59 x->x_freq = f;
60 notch_bang(x);
61}
62
63
64static void *notch_new(t_floatarg f,t_floatarg bw)
65{
66 t_rbjfilter *x = (t_rbjfilter *)pd_new(notch_class);
67
68 x->x_rate = 44100.0;
69 outlet_new(&x->x_obj,&s_float);
70/* floatinlet_new(&x->x_obj, &x->x_gain); */
71 floatinlet_new(&x->x_obj, &x->x_bw);
72 if (f > 0.) x->x_freq = f;
73 if (bw > 0.) x->x_bw = bw;
74 return (x);
75}
76
77
78void notch_setup(void)
79{
80 notch_class = class_new(gensym("notch"), (t_newmethod)notch_new, 0,
81 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,0);
82 class_addbang(notch_class,notch_bang);
83 class_addfloat(notch_class,notch_float);
84}
85
86
87
88
89
90/* (C) Guenter Geiger <geiger@epy.co.at> */
91
92
93/*
94
95 These filter coefficients computations are taken from
96 http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
97
98 written by Robert Bristow-Johnson
99
100*/
101
102#include "m_pd.h"
103#ifdef NT
104#pragma warning( disable : 4244 )
105#pragma warning( disable : 4305 )
106#endif
107#include <math.h>
108#include "filters.h"
109
110
111
112/* ------------------- notch ----------------------------*/
113
114static t_class *notch_class;
115
116void notch_bang(t_rbjfilter *x)
117{
118 t_atom at[5];
119 t_float omega = e_omega(x->x_freq,x->x_rate);
120 t_float alpha = e_alpha(x->x_bw* 0.01,omega);
121 t_float b1 = -2.*cos(omega);
122 t_float b0 = 1;
123 t_float b2 = b0;
124 t_float a0 = 1 + alpha;
125 t_float a1 = -2.*cos(omega);
126 t_float a2 = 1 - alpha;
127
128/* post("bang %f %f %f",x->x_freq, x->x_gain, x->x_bw); */
129
130 if (!check_stability(-a1/a0,-a2/a0,b0/a0,b1/a0,b2/a0)) {
131 post("notch: filter unstable -> resetting");
132 a0=1.;a1=0.;a2=0.;
133 b0=1.;b1=0.;b2=0.;
134 }
135
136 SETFLOAT(at,-a1/a0);
137 SETFLOAT(at+1,-a2/a0);
138 SETFLOAT(at+2,b0/a0);
139 SETFLOAT(at+3,b1/a0);
140 SETFLOAT(at+4,b2/a0);
141
142 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
143}
144
145
146void notch_float(t_rbjfilter *x,t_floatarg f)
147{
148 x->x_freq = f;
149 notch_bang(x);
150}
151
152
153static void *notch_new(t_floatarg f,t_floatarg bw)
154{
155 t_rbjfilter *x = (t_rbjfilter *)pd_new(notch_class);
156
157 x->x_rate = 44100.0;
158 outlet_new(&x->x_obj,&s_float);
159/* floatinlet_new(&x->x_obj, &x->x_gain); */
160 floatinlet_new(&x->x_obj, &x->x_bw);
161 if (f > 0.) x->x_freq = f;
162 if (bw > 0.) x->x_bw = bw;
163 return (x);
164}
165
166
167void notch_setup(void)
168{
169 notch_class = class_new(gensym("notch"), (t_newmethod)notch_new, 0,
170 sizeof(t_rbjfilter), 0,A_DEFFLOAT,A_DEFFLOAT,0);
171 class_addbang(notch_class,notch_bang);
172 class_addfloat(notch_class,notch_float);
173}
174
175
176
177
178
diff --git a/apps/plugins/pdbox/PDa/extra/s_stuff.h b/apps/plugins/pdbox/PDa/extra/s_stuff.h
new file mode 100644
index 0000000000..6dc9a88c4b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/s_stuff.h
@@ -0,0 +1,430 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* Audio and MIDI I/O, and other scheduling and system stuff. */
6
7/* NOTE: this file describes Pd implementation details which may change
8in future releases. The public (stable) API is in m_pd.h. */
9
10/* in s_file.c */
11typedef struct _namelist
12{
13 struct _namelist *nl_next;
14 char *nl_string;
15} t_namelist;
16
17t_namelist *namelist_append(t_namelist *listwas, const char *s);
18void namelist_free(t_namelist *listwas);
19
20/* s_main.c */
21extern int sys_debuglevel;
22extern int sys_verbose;
23extern int sys_noloadbang;
24extern int sys_nogui;
25extern char *sys_guicmd;
26
27EXTERN int sys_nearestfontsize(int fontsize);
28EXTERN int sys_hostfontsize(int fontsize);
29
30extern int sys_defaultfont;
31extern t_symbol *sys_libdir; /* library directory for auxilliary files */
32
33/* s_loader.c */
34int sys_load_lib(char *dirname, char *filename);
35
36/* s_audio.c */
37
38#define SENDDACS_NO 0 /* return values for sys_send_dacs() */
39#define SENDDACS_YES 1
40#define SENDDACS_SLEPT 2
41
42#define DEFDACBLKSIZE 64
43extern int sys_schedblocksize; /* audio block size for scheduler */
44extern int sys_hipriority; /* real-time flag, true if priority boosted */
45extern t_sample *sys_soundout;
46extern t_sample *sys_soundin;
47extern int sys_inchannels;
48extern int sys_outchannels;
49extern int sys_advance_samples; /* scheduler advance in samples */
50extern int sys_blocksize; /* audio I/O block size in sample frames */
51extern float sys_dacsr;
52extern int sys_schedadvance;
53extern int sys_sleepgrain;
54void sys_open_audio(int naudioindev, int *audioindev,
55 int nchindev, int *chindev,
56 int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
57 int srate, int advance, int enable);
58void sys_close_audio(void);
59
60 /* s_midi.c */
61void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec);
62
63 /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */
64void sys_do_open_midi(int nmidiin, int *midiinvec,
65 int nmidiout, int *midioutvec);
66void sys_close_midi(void);
67void midi_getdevs(char *indevlist, int *nindevs,
68 char *outdevlist, int *noutdevs, int maxndev, int devdescsize);
69
70int sys_send_dacs(void);
71void sys_reportidle(void);
72void sys_set_priority(int higher);
73void sys_audiobuf(int nbufs);
74void sys_getmeters(float *inmax, float *outmax);
75void sys_listdevs(void);
76void sys_setblocksize(int n);
77
78/* s_midi.c */
79#define MAXMIDIINDEV 16 /* max. number of input ports */
80#define MAXMIDIOUTDEV 16 /* max. number of output ports */
81extern int sys_nmidiin;
82extern int sys_nmidiout;
83extern int sys_midiindevlist[];
84extern int sys_midioutdevlist[];
85
86EXTERN void sys_putmidimess(int portno, int a, int b, int c);
87EXTERN void sys_putmidibyte(int portno, int a);
88EXTERN void sys_poll_midi(void);
89EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
90EXTERN void sys_midibytein(int portno, int byte);
91
92/* m_sched.c */
93EXTERN void sys_log_error(int type);
94#define ERR_NOTHING 0
95#define ERR_ADCSLEPT 1
96#define ERR_DACSLEPT 2
97#define ERR_RESYNC 3
98#define ERR_DATALATE 4
99void sched_set_using_dacs(int flag);
100
101/* s_inter.c */
102
103EXTERN void sys_microsleep(int microsec);
104
105EXTERN void sys_bail(int exitcode);
106EXTERN int sys_pollgui(void);
107
108EXTERN_STRUCT _socketreceiver;
109#define t_socketreceiver struct _socketreceiver
110
111typedef void (*t_socketnotifier)(void *x);
112typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
113
114EXTERN t_socketreceiver *socketreceiver_new(void *owner,
115 t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp);
116EXTERN void socketreceiver_read(t_socketreceiver *x, int fd);
117EXTERN void sys_sockerror(char *s);
118EXTERN void sys_closesocket(int fd);
119
120typedef void (*t_fdpollfn)(void *ptr, int fd);
121EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
122EXTERN void sys_rmpollfn(int fd);
123#ifdef UNIX
124void sys_setalarm(int microsec);
125void sys_setvirtualalarm( void);
126#endif
127
128#define API_ALSA 1
129#define API_OSS 2
130#define API_MMIO 3
131#define API_PORTAUDIO 4
132#define API_JACK 5
133
134#ifdef __linux__
135#define API_DEFAULT API_OSS
136#define API_DEFSTRING "OSS"
137#endif
138#ifdef MSW
139#define API_DEFAULT API_MMIO
140#define API_DEFSTRING "MMIO"
141#endif
142#ifdef MACOSX
143#define API_DEFAULT API_PORTAUDIO
144#define API_DEFSTRING "portaudio"
145#endif
146#define DEFAULTAUDIODEV 0
147
148#define MAXAUDIOINDEV 4
149#define MAXAUDIOOUTDEV 4
150
151#define DEFMIDIDEV 0
152
153#define DEFAULTSRATE 44100
154#ifdef MSW
155#define DEFAULTADVANCE 70
156#else
157#define DEFAULTADVANCE 50
158#endif
159
160int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
161 t_sample *soundout, int framesperbuf, int nbuffers,
162 int indeviceno, int outdeviceno);
163void pa_close_audio(void);
164int pa_send_dacs(void);
165void sys_reportidle(void);
166void pa_listdevs(void);
167void pa_getdevs(char *indevlist, int *nindevs,
168 char *outdevlist, int *noutdevs, int *canmulti,
169 int maxndev, int devdescsize);
170
171int oss_open_audio(int naudioindev, int *audioindev, int nchindev,
172 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
173 int *choutdev, int rate); /* IOhannes */
174void oss_close_audio(void);
175int oss_send_dacs(void);
176void oss_reportidle(void);
177void oss_getdevs(char *indevlist, int *nindevs,
178 char *outdevlist, int *noutdevs, int *canmulti,
179 int maxndev, int devdescsize);
180
181int alsa_open_audio(int naudioindev, int *audioindev, int nchindev,
182 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
183 int *choutdev, int rate);
184void alsa_close_audio(void);
185int alsa_send_dacs(void);
186void alsa_reportidle(void);
187void alsa_getdevs(char *indevlist, int *nindevs,
188 char *outdevlist, int *noutdevs, int *canmulti,
189 int maxndev, int devdescsize);
190
191int jack_open_audio(int wantinchans, int wantoutchans, int srate);
192void jack_close_audio(void);
193int jack_send_dacs(void);
194void jack_reportidle(void);
195void jack_listdevs(void);
196
197void mmio_open_audio(int naudioindev, int *audioindev,
198 int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
199 int nchoutdev, int *choutdev, int rate);
200void mmio_close_audio( void);
201void mmio_reportidle(void);
202int mmio_send_dacs(void);
203void mmio_getdevs(char *indevlist, int *nindevs,
204 char *outdevlist, int *noutdevs, int *canmulti,
205 int maxndev, int devdescsize);
206
207void sys_listmididevs(void);
208void sys_set_audio_api(int whichapi);
209void sys_get_audio_apis(char *buf);
210extern int sys_audioapi;
211void sys_set_audio_state(int onoff);
212
213/* API dependent audio flags and settings */
214void oss_set32bit( void);
215void linux_alsa_devname(char *devname);
216/* Copyright (c) 1997-1999 Miller Puckette.
217* For information on usage and redistribution, and for a DISCLAIMER OF ALL
218* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
219
220/* Audio and MIDI I/O, and other scheduling and system stuff. */
221
222/* NOTE: this file describes Pd implementation details which may change
223in future releases. The public (stable) API is in m_pd.h. */
224
225/* in s_file.c */
226typedef struct _namelist
227{
228 struct _namelist *nl_next;
229 char *nl_string;
230} t_namelist;
231
232t_namelist *namelist_append(t_namelist *listwas, const char *s);
233void namelist_free(t_namelist *listwas);
234
235/* s_main.c */
236extern int sys_debuglevel;
237extern int sys_verbose;
238extern int sys_noloadbang;
239extern int sys_nogui;
240extern char *sys_guicmd;
241
242EXTERN int sys_nearestfontsize(int fontsize);
243EXTERN int sys_hostfontsize(int fontsize);
244
245extern int sys_defaultfont;
246extern t_symbol *sys_libdir; /* library directory for auxilliary files */
247
248/* s_loader.c */
249int sys_load_lib(char *dirname, char *filename);
250
251/* s_audio.c */
252
253#define SENDDACS_NO 0 /* return values for sys_send_dacs() */
254#define SENDDACS_YES 1
255#define SENDDACS_SLEPT 2
256
257#define DEFDACBLKSIZE 64
258extern int sys_schedblocksize; /* audio block size for scheduler */
259extern int sys_hipriority; /* real-time flag, true if priority boosted */
260extern t_sample *sys_soundout;
261extern t_sample *sys_soundin;
262extern int sys_inchannels;
263extern int sys_outchannels;
264extern int sys_advance_samples; /* scheduler advance in samples */
265extern int sys_blocksize; /* audio I/O block size in sample frames */
266extern float sys_dacsr;
267extern int sys_schedadvance;
268extern int sys_sleepgrain;
269void sys_open_audio(int naudioindev, int *audioindev,
270 int nchindev, int *chindev,
271 int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
272 int srate, int advance, int enable);
273void sys_close_audio(void);
274
275 /* s_midi.c */
276void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec);
277
278 /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */
279void sys_do_open_midi(int nmidiin, int *midiinvec,
280 int nmidiout, int *midioutvec);
281void sys_close_midi(void);
282void midi_getdevs(char *indevlist, int *nindevs,
283 char *outdevlist, int *noutdevs, int maxndev, int devdescsize);
284
285int sys_send_dacs(void);
286void sys_reportidle(void);
287void sys_set_priority(int higher);
288void sys_audiobuf(int nbufs);
289void sys_getmeters(float *inmax, float *outmax);
290void sys_listdevs(void);
291void sys_setblocksize(int n);
292
293/* s_midi.c */
294#define MAXMIDIINDEV 16 /* max. number of input ports */
295#define MAXMIDIOUTDEV 16 /* max. number of output ports */
296extern int sys_nmidiin;
297extern int sys_nmidiout;
298extern int sys_midiindevlist[];
299extern int sys_midioutdevlist[];
300
301EXTERN void sys_putmidimess(int portno, int a, int b, int c);
302EXTERN void sys_putmidibyte(int portno, int a);
303EXTERN void sys_poll_midi(void);
304EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
305EXTERN void sys_midibytein(int portno, int byte);
306
307/* m_sched.c */
308EXTERN void sys_log_error(int type);
309#define ERR_NOTHING 0
310#define ERR_ADCSLEPT 1
311#define ERR_DACSLEPT 2
312#define ERR_RESYNC 3
313#define ERR_DATALATE 4
314void sched_set_using_dacs(int flag);
315
316/* s_inter.c */
317
318EXTERN void sys_microsleep(int microsec);
319
320EXTERN void sys_bail(int exitcode);
321EXTERN int sys_pollgui(void);
322
323EXTERN_STRUCT _socketreceiver;
324#define t_socketreceiver struct _socketreceiver
325
326typedef void (*t_socketnotifier)(void *x);
327typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
328
329EXTERN t_socketreceiver *socketreceiver_new(void *owner,
330 t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp);
331EXTERN void socketreceiver_read(t_socketreceiver *x, int fd);
332EXTERN void sys_sockerror(char *s);
333EXTERN void sys_closesocket(int fd);
334
335typedef void (*t_fdpollfn)(void *ptr, int fd);
336EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
337EXTERN void sys_rmpollfn(int fd);
338#ifdef UNIX
339void sys_setalarm(int microsec);
340void sys_setvirtualalarm( void);
341#endif
342
343#define API_ALSA 1
344#define API_OSS 2
345#define API_MMIO 3
346#define API_PORTAUDIO 4
347#define API_JACK 5
348
349#ifdef __linux__
350#define API_DEFAULT API_OSS
351#define API_DEFSTRING "OSS"
352#endif
353#ifdef MSW
354#define API_DEFAULT API_MMIO
355#define API_DEFSTRING "MMIO"
356#endif
357#ifdef MACOSX
358#define API_DEFAULT API_PORTAUDIO
359#define API_DEFSTRING "portaudio"
360#endif
361#define DEFAULTAUDIODEV 0
362
363#define MAXAUDIOINDEV 4
364#define MAXAUDIOOUTDEV 4
365
366#define DEFMIDIDEV 0
367
368#define DEFAULTSRATE 44100
369#ifdef MSW
370#define DEFAULTADVANCE 70
371#else
372#define DEFAULTADVANCE 50
373#endif
374
375int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
376 t_sample *soundout, int framesperbuf, int nbuffers,
377 int indeviceno, int outdeviceno);
378void pa_close_audio(void);
379int pa_send_dacs(void);
380void sys_reportidle(void);
381void pa_listdevs(void);
382void pa_getdevs(char *indevlist, int *nindevs,
383 char *outdevlist, int *noutdevs, int *canmulti,
384 int maxndev, int devdescsize);
385
386int oss_open_audio(int naudioindev, int *audioindev, int nchindev,
387 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
388 int *choutdev, int rate); /* IOhannes */
389void oss_close_audio(void);
390int oss_send_dacs(void);
391void oss_reportidle(void);
392void oss_getdevs(char *indevlist, int *nindevs,
393 char *outdevlist, int *noutdevs, int *canmulti,
394 int maxndev, int devdescsize);
395
396int alsa_open_audio(int naudioindev, int *audioindev, int nchindev,
397 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
398 int *choutdev, int rate);
399void alsa_close_audio(void);
400int alsa_send_dacs(void);
401void alsa_reportidle(void);
402void alsa_getdevs(char *indevlist, int *nindevs,
403 char *outdevlist, int *noutdevs, int *canmulti,
404 int maxndev, int devdescsize);
405
406int jack_open_audio(int wantinchans, int wantoutchans, int srate);
407void jack_close_audio(void);
408int jack_send_dacs(void);
409void jack_reportidle(void);
410void jack_listdevs(void);
411
412void mmio_open_audio(int naudioindev, int *audioindev,
413 int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
414 int nchoutdev, int *choutdev, int rate);
415void mmio_close_audio( void);
416void mmio_reportidle(void);
417int mmio_send_dacs(void);
418void mmio_getdevs(char *indevlist, int *nindevs,
419 char *outdevlist, int *noutdevs, int *canmulti,
420 int maxndev, int devdescsize);
421
422void sys_listmididevs(void);
423void sys_set_audio_api(int whichapi);
424void sys_get_audio_apis(char *buf);
425extern int sys_audioapi;
426void sys_set_audio_state(int onoff);
427
428/* API dependent audio flags and settings */
429void oss_set32bit( void);
430void linux_alsa_devname(char *devname);
diff --git a/apps/plugins/pdbox/PDa/extra/sendOSC.c b/apps/plugins/pdbox/PDa/extra/sendOSC.c
new file mode 100644
index 0000000000..c00f693280
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/sendOSC.c
@@ -0,0 +1,2922 @@
1/*
2Written by Matt Wright, The Center for New Music and Audio Technologies,
3University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
4The Regents of the University of California (Regents).
5
6Permission to use, copy, modify, distribute, and distribute modified versions
7of this software and its documentation without fee and without a signed
8licensing agreement, is hereby granted, provided that the above copyright
9notice, this paragraph and the following two paragraphs appear in all copies,
10modifications, and distributions.
11
12IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
13SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
14OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
15BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
17REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
20HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
21MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
22
23
24The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
25*/
26
27
28/* sendOSC.c
29
30 Matt Wright, 6/3/97
31 based on sendOSC.c, which was based on a version by Adrian Freed
32
33 Text-based OpenSoundControl client. User can enter messages via command
34 line arguments or standard input.
35
36 Version 0.1: "play" feature
37 Version 0.2: Message type tags.
38
39 pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c
40 -------------
41 -- added bundle stuff to send. jdl 20020416
42 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
43 -- ost_at_test.at + i22_at_test.at, 2000-2002
44 modified to compile as pd externel
45*/
46
47#define MAX_ARGS 2000
48#define SC_BUFFER_SIZE 64000
49
50#include "m_pd.h"
51#include "OSC-client.h"
52
53#include <string.h>
54#include <sys/types.h>
55#include <stdlib.h>
56#include <stdio.h>
57#include <sys/stat.h>
58#include <sys/types.h>
59
60#ifdef WIN32
61#include <winsock2.h>
62#include <io.h>
63#include <errno.h>
64#include <fcntl.h>
65#include <winsock2.h>
66#include <ctype.h>
67#include <signal.h>
68#else
69#include <sys/socket.h>
70#include <netinet/in.h>
71#include <rpc/rpc.h>
72#include <sys/times.h>
73#include <sys/param.h>
74#include <sys/time.h>
75#include <sys/ioctl.h>
76#include <netdb.h>
77#endif
78
79#ifdef __APPLE__
80 #include <string.h>
81#endif
82
83#define UNIXDG_PATH "/tmp/htm"
84#define UNIXDG_TMP "/tmp/htm.XXXXXX"
85
86
87
88OSCTimeTag OSCTT_Immediately(void) {
89 OSCTimeTag result;
90 result.seconds = 0;
91 result.fraction = 1;
92 return result;
93}
94
95
96OSCTimeTag OSCTT_CurrentTime(void) {
97 OSCTimeTag result;
98 result.seconds = 0;
99 result.fraction = 1;
100 return result;
101}
102
103OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
104 OSCTimeTag result;
105 result.seconds = 0;
106 result.fraction = 1;
107 return result;
108}
109
110
111typedef int bool;
112
113typedef struct
114{
115 float srate;
116
117 struct sockaddr_in serv_addr; /* udp socket */
118 #ifndef WIN32
119 struct sockaddr_un userv_addr; /* UNIX socket */
120 #endif
121 int sockfd; /* socket file descriptor */
122 int index, len,uservlen;
123 void *addr;
124 int id;
125} desc;
126
127
128/* open a socket for HTM communication to given host on given portnumber */
129/* if host is 0 then UNIX protocol is used (i.e. local communication */
130void *OpenHTMSocket(char *host, int portnumber)
131{
132 struct sockaddr_in cl_addr;
133 #ifndef WIN32
134 int sockfd;
135 struct sockaddr_un ucl_addr;
136 #else
137 unsigned int sockfd;
138 #endif
139
140 desc *o;
141 int oval = 1;
142 o = malloc(sizeof(*o));
143 if(!o) return 0;
144
145 #ifndef WIN32
146
147 if(!host)
148 {
149 char *mktemp(char *);
150 int clilen;
151 o->len = sizeof(ucl_addr);
152 /*
153 * Fill in the structure "userv_addr" with the address of the
154 * server that we want to send to.
155 */
156
157 bzero((char *) &o->userv_addr, sizeof(o->userv_addr));
158 o->userv_addr.sun_family = AF_UNIX;
159 strcpy(o->userv_addr.sun_path, UNIXDG_PATH);
160 sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber);
161 o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path);
162 o->addr = &(o->userv_addr);
163 /*
164 * Open a socket (a UNIX domain datagram socket).
165 */
166
167 if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
168 {
169 /*
170 * Bind a local address for us.
171 * In the UNIX domain we have to choose our own name (that
172 * should be unique). We'll use mktemp() to create a unique
173 * pathname, based on our process id.
174 */
175
176 bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */
177 ucl_addr.sun_family = AF_UNIX;
178 strcpy(ucl_addr.sun_path, UNIXDG_TMP);
179
180 mktemp(ucl_addr.sun_path);
181 clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path);
182
183 if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0)
184 {
185 perror("client: can't bind local address");
186 close(sockfd);
187 sockfd = -1;
188 }
189 }
190 else
191 perror("unable to make socket\n");
192
193 }else
194
195 #endif
196
197 {
198 /*
199 * Fill in the structure "serv_addr" with the address of the
200 * server that we want to send to.
201 */
202 o->len = sizeof(cl_addr);
203
204 #ifdef WIN32
205 ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr));
206 #else
207 bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
208 #endif
209
210 o->serv_addr.sin_family = AF_INET;
211
212 /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
213 so that host can be either an Internet host name (e.g.,
214 "les") or an Internet address in standard dot notation
215 (e.g., "128.32.122.13") */
216 {
217 struct hostent *hostsEntry;
218 unsigned long address;
219
220 hostsEntry = gethostbyname(host);
221 if (hostsEntry == NULL) {
222 fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host);
223 #ifndef WIN32
224 herror(NULL);
225 #endif
226 return 0;
227 }
228 address = *((unsigned long *) hostsEntry->h_addr_list[0]);
229 o->serv_addr.sin_addr.s_addr = address;
230 }
231
232 /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
233
234 /* End MW changes */
235
236 /*
237 * Open a socket (a UDP domain datagram socket).
238 */
239
240
241 #ifdef WIN32
242 o->serv_addr.sin_port = htons((USHORT)portnumber);
243 o->addr = &(o->serv_addr);
244 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
245 ZeroMemory((char *)&cl_addr, sizeof(cl_addr));
246 cl_addr.sin_family = AF_INET;
247 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
248 cl_addr.sin_port = htons(0);
249
250 // enable broadcast: jdl ~2003
251 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
252 perror("setsockopt");
253 }
254
255 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
256 perror("could not bind\n");
257 closesocket(sockfd);
258 sockfd = -1;
259 }
260 }
261 else { perror("unable to make socket\n");}
262 #else
263 o->serv_addr.sin_port = htons(portnumber);
264 o->addr = &(o->serv_addr);
265 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
266 bzero((char *)&cl_addr, sizeof(cl_addr));
267 cl_addr.sin_family = AF_INET;
268 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
269 cl_addr.sin_port = htons(0);
270
271 // enable broadcast: jdl ~2003
272 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
273 perror("setsockopt");
274 }
275
276 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
277 perror("could not bind\n");
278 close(sockfd);
279 sockfd = -1;
280 }
281 }
282 else { perror("unable to make socket\n");}
283 #endif
284 }
285 #ifdef WIN32
286 if(sockfd == INVALID_SOCKET) {
287 #else
288 if(sockfd < 0) {
289 #endif
290 free(o);
291 o = 0;
292 }
293 else
294 o->sockfd = sockfd;
295 return o;
296}
297
298static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b)
299{
300 int rcount;
301 if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count)
302 {
303 printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length);
304 return FALSE;
305 }
306 return TRUE;
307}
308
309bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer)
310{
311 desc *o = (desc *)htmsendhandle;
312 return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer);
313}
314void CloseHTMSocket(void *htmsendhandle)
315{
316 desc *o = (desc *)htmsendhandle;
317 #ifdef WIN32
318 if(SOCKET_ERROR == closesocket(o->sockfd)) {
319 perror("CloseHTMSocket::closesocket failed\n");
320 return;
321 }
322 #else
323 if(close(o->sockfd) == -1)
324 {
325 perror("CloseHTMSocket::closesocket failed");
326 return;
327 }
328 #endif
329
330 free(o);
331}
332
333
334///////////////////////
335// from sendOSC
336
337typedef struct {
338 //enum {INT, FLOAT, STRING} type;
339 enum {INT_osc, FLOAT_osc, STRING_osc} type;
340 union {
341 int i;
342 float f;
343 char *s;
344 } datum;
345} typedArg;
346
347void CommandLineMode(int argc, char *argv[], void *htmsocket);
348OSCTimeTag ParseTimeTag(char *s);
349void ParseInteractiveLine(OSCbuf *buf, char *mesg);
350typedArg ParseToken(char *token);
351int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args);
352void SendBuffer(void *htmsocket, OSCbuf *buf);
353void SendData(void *htmsocket, int size, char *data);
354/* defined in OSC-system-dependent.c now */
355
356//static void *htmsocket;
357static int exitStatus = 0;
358static int useTypeTags = 0;
359
360static char bufferForOSCbuf[SC_BUFFER_SIZE];
361
362
363/////////
364// end from sendOSC
365
366static t_class *sendOSC_class;
367
368typedef struct _sendOSC
369{
370 t_object x_obj;
371 int x_protocol; // UDP/TCP (udp only atm)
372 t_int x_typetags; // typetag flag
373 void *x_htmsocket; // sending socket
374 int x_bundle; // bundle open flag
375 OSCbuf x_oscbuf[1]; // OSCbuffer
376 t_outlet *x_bdpthout;// bundle-depth floatoutlet
377} t_sendOSC;
378
379static void *sendOSC_new(t_floatarg udpflag)
380{
381 t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class);
382 outlet_new(&x->x_obj, &s_float);
383 x->x_htmsocket = 0; // {{raf}}
384 // set udp
385 x->x_protocol = SOCK_STREAM;
386 // set typetags to 1 by default
387 x->x_typetags = 1;
388 // bunlde is closed
389 x->x_bundle = 0;
390 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
391 x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float();
392 //x->x_oscbuf =
393 return (x);
394}
395
396
397void sendOSC_openbundle(t_sendOSC *x)
398{
399 if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING ||
400 OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()))
401 {
402 post("Problem opening bundle: %s\n", OSC_errorMessage);
403 return;
404 }
405 x->x_bundle = 1;
406 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
407}
408
409static void sendOSC_closebundle(t_sendOSC *x)
410{
411 if (OSC_closeBundle(x->x_oscbuf)) {
412 post("Problem closing bundle: %s\n", OSC_errorMessage);
413 return;
414 }
415 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
416 // in bundle mode we send when bundle is closed?
417 if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) {
418 // post("x_oscbuf: something inside me?");
419 if (x->x_htmsocket) {
420 SendBuffer(x->x_htmsocket, x->x_oscbuf);
421 } else {
422 post("sendOSC: not connected");
423 }
424 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
425 x->x_bundle = 0;
426 return;
427 }
428 // post("x_oscbuf: something went wrong");
429}
430
431static void sendOSC_settypetags(t_sendOSC *x, t_float *f)
432 {
433 x->x_typetags = (int)f;
434 post("sendOSC.c: setting typetags %d",x->x_typetags);
435 }
436
437
438static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname,
439 t_floatarg fportno)
440{
441 int portno = fportno;
442 /* create a socket */
443
444 // make sure handle is available
445 if(x->x_htmsocket == 0) {
446 //
447 x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno);
448 if (!x->x_htmsocket)
449 post("Couldn't open socket: ");
450 else {
451 post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket);
452 outlet_float(x->x_obj.ob_outlet, 1);
453 }
454 }
455 else
456 perror("call to sendOSC_connect() against UNavailable socket handle");
457}
458
459void sendOSC_disconnect(t_sendOSC *x)
460{
461 if (x->x_htmsocket)
462 {
463 post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket);
464 CloseHTMSocket(x->x_htmsocket);
465 x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this
466 outlet_float(x->x_obj.ob_outlet, 0);
467 }
468 else {
469 perror("call to sendOSC_disconnect() against unused socket handle");
470 }
471}
472
473void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
474{
475 char* targv[MAXPDARG];
476 char tmparg[MAXPDSTRING];
477 char* tmp = tmparg;
478 //char testarg[MAXPDSTRING];
479 int c;
480
481 post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged...");
482 return;
483
484 //atom_string(argv,testarg, MAXPDSTRING);
485 for (c=0;c<argc;c++) {
486 atom_string(argv+c,tmp, 80);
487 targv[c] = tmp;
488 tmp += strlen(tmp)+1;
489 }
490
491 // this sock needs to be larger than 0, not >= ..
492 if (x->x_htmsocket)
493 {
494 CommandLineMode(argc, targv, x->x_htmsocket);
495 // post("test %d", c);
496 }
497 else {
498 post("sendOSC: not connected");
499 }
500}
501
502//////////////////////////////////////////////////////////////////////
503// this is the real and only sending routine now, for both typed and
504// undtyped mode.
505
506static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
507{
508 char* targv[MAX_ARGS];
509 char tmparg[MAXPDSTRING];
510 char* tmp = tmparg;
511 int c;
512
513 char *messageName;
514 char *token;
515 typedArg args[MAX_ARGS];
516 int i,j;
517 int numArgs = 0;
518
519 messageName = "";
520#ifdef DEBUG
521 post ("sendOSC: messageName: %s", messageName);
522#endif
523
524
525
526 for (c=0;c<argc;c++) {
527 atom_string(argv+c,tmp, 80);
528
529#ifdef DEBUG
530 // post ("sendOSC: %d, %s",c, tmp);
531#endif
532
533 targv[c] = tmp;
534 tmp += strlen(tmp)+1;
535
536#ifdef DEBUG
537 // post ("sendOSC: %d, %s",c, targv[c]);
538#endif
539 }
540
541 // this sock needs to be larger than 0, not >= ..
542 if (x->x_htmsocket > 0)
543 {
544#ifdef DEBUG
545 post ("sendOSC: type tags? %d", useTypeTags);
546#endif
547
548 messageName = strtok(targv[0], ",");
549 j = 1;
550 for (i = j; i < argc; i++) {
551 token = strtok(targv[i],",");
552 args[i-j] = ParseToken(token);
553#ifdef DEBUG
554 printf("cell-cont: %s\n", targv[i]);
555 printf(" type-id: %d\n", args[i-j]);
556#endif
557 numArgs = i;
558 }
559
560
561 if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) {
562 post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage);
563 return;
564 }
565
566 if(!x->x_bundle) {
567 SendBuffer(x->x_htmsocket, x->x_oscbuf);
568 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
569 }
570
571 //CommandLineMode(argc, targv, x->x_htmsocket);
572 //useTypeTags = 0;
573 }
574 else {
575 post("sendOSC: not connected");
576 }
577}
578
579void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
580{
581 if(!argc) {
582 post("not sending empty message.");
583 return;
584 }
585 if(x->x_typetags) {
586 useTypeTags = 1;
587 sendOSC_sendtyped(x,s,argc,argv);
588 useTypeTags = 0;
589 } else {
590 sendOSC_sendtyped(x,s,argc,argv);
591 }
592}
593
594static void sendOSC_free(t_sendOSC *x)
595{
596 sendOSC_disconnect(x);
597}
598
599#ifdef WIN32
600 OSC_API void sendOSC_setup(void) {
601#else
602 void sendOSC_setup(void) {
603#endif
604 sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new,
605 (t_method)sendOSC_free,
606 sizeof(t_sendOSC), 0, A_DEFFLOAT, 0);
607 class_addmethod(sendOSC_class, (t_method)sendOSC_connect,
608 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
609 class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect,
610 gensym("disconnect"), 0);
611 class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags,
612 gensym("typetags"),
613 A_FLOAT, 0);
614 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
615 gensym("send"),
616 A_GIMME, 0);
617 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
618 gensym("senduntyped"),
619 A_GIMME, 0);
620 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
621 gensym("sendtyped"),
622 A_GIMME, 0);
623 class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle,
624 gensym("["),
625 0, 0);
626 class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle,
627 gensym("]"),
628 0, 0);
629 class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd"));
630}
631
632
633
634
635
636/* Exit status codes:
637 0: successful
638 2: Message(s) dropped because of buffer overflow
639 3: Socket error
640 4: Usage error
641 5: Internal error
642*/
643
644void CommandLineMode(int argc, char *argv[], void *htmsocket) {
645 char *messageName;
646 char *token;
647 typedArg args[MAX_ARGS];
648 int i,j, numArgs;
649 OSCbuf buf[1];
650
651 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
652
653 if (argc > 1) {
654 post("argc (%d) > 1", argc);
655 }
656
657 // ParseInteractiveLine(buf, argv);
658 messageName = strtok(argv[0], ",");
659
660 j = 1;
661 for (i = j; i < argc; i++) {
662 token = strtok(argv[i],",");
663 args[i-j] = ParseToken(token);
664#ifdef DEBUG
665 printf("cell-cont: %s\n", argv[i]);
666 printf(" type-id: %d\n", args[i-j]);
667#endif
668 numArgs = i;
669 }
670
671 if(WriteMessage(buf, messageName, numArgs, args)) {
672 post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage);
673 return;
674 }
675
676 SendBuffer(htmsocket, buf);
677}
678
679#define MAXMESG 2048
680
681void InteractiveMode(void *htmsocket) {
682 char mesg[MAXMESG];
683 OSCbuf buf[1];
684 int bundleDepth = 0; /* At first, we haven't seen "[". */
685
686 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
687
688 while (fgets(mesg, MAXMESG, stdin) != NULL) {
689 if (mesg[0] == '\n') {
690 if (bundleDepth > 0) {
691 /* Ignore blank lines inside a group. */
692 } else {
693 /* blank line => repeat previous send */
694 SendBuffer(htmsocket, buf);
695 }
696 continue;
697 }
698
699 if (bundleDepth == 0) {
700 OSC_resetBuffer(buf);
701 }
702
703 if (mesg[0] == '[') {
704 OSCTimeTag tt = ParseTimeTag(mesg+1);
705 if (OSC_openBundle(buf, tt)) {
706 post("Problem opening bundle: %s\n", OSC_errorMessage);
707 OSC_resetBuffer(buf);
708 bundleDepth = 0;
709 continue;
710 }
711 bundleDepth++;
712 } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') {
713 if (bundleDepth == 0) {
714 post("Unexpected ']': not currently in a bundle.\n");
715 } else {
716 if (OSC_closeBundle(buf)) {
717 post("Problem closing bundle: %s\n", OSC_errorMessage);
718 OSC_resetBuffer(buf);
719 bundleDepth = 0;
720 continue;
721 }
722
723 bundleDepth--;
724 if (bundleDepth == 0) {
725 SendBuffer(htmsocket, buf);
726 }
727 }
728 } else {
729 ParseInteractiveLine(buf, mesg);
730 if (bundleDepth != 0) {
731 /* Don't send anything until we close all bundles */
732 } else {
733 SendBuffer(htmsocket, buf);
734 }
735 }
736 }
737}
738
739OSCTimeTag ParseTimeTag(char *s) {
740 char *p, *newline;
741 typedArg arg;
742
743 p = s;
744 while (isspace(*p)) p++;
745 if (*p == '\0') return OSCTT_Immediately();
746
747 if (*p == '+') {
748 /* Time tag is for some time in the future. It should be a
749 number of seconds as an int or float */
750
751 newline = strchr(s, '\n');
752 if (newline != NULL) *newline = '\0';
753
754 p++; /* Skip '+' */
755 while (isspace(*p)) p++;
756
757 arg = ParseToken(p);
758 if (arg.type == STRING_osc) {
759 post("warning: inscrutable time tag request: %s\n", s);
760 return OSCTT_Immediately();
761 } else if (arg.type == INT_osc) {
762 return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
763 (float) arg.datum.i);
764 } else if (arg.type == FLOAT_osc) {
765 return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f);
766 } else {
767 error("This can't happen!");
768 }
769 }
770
771 if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) {
772 /* They specified the 8-byte tag in hex */
773 OSCTimeTag tt;
774 if (sscanf(p, "%llx", &tt) != 1) {
775 post("warning: couldn't parse time tag %s\n", s);
776 return OSCTT_Immediately();
777 }
778#ifndef HAS8BYTEINT
779 if (ntohl(1) != 1) {
780 /* tt is a struct of seconds and fractional part,
781 and this machine is little-endian, so sscanf
782 wrote each half of the time tag in the wrong half
783 of the struct. */
784 int temp;
785 temp = tt.seconds;
786 tt.seconds = tt.fraction ;
787 tt.fraction = temp;
788 }
789#endif
790 return tt;
791 }
792
793 post("warning: invalid time tag: %s\n", s);
794 return OSCTT_Immediately();
795}
796
797
798void ParseInteractiveLine(OSCbuf *buf, char *mesg) {
799 char *messageName, *token, *p;
800 typedArg args[MAX_ARGS];
801 int thisArg;
802
803 p = mesg;
804 while (isspace(*p)) p++;
805 if (*p == '\0') return;
806
807 messageName = p;
808
809 if (strcmp(messageName, "play\n") == 0) {
810 /* Special kludge feature to save typing */
811 typedArg arg;
812
813 if (OSC_openBundle(buf, OSCTT_Immediately())) {
814 post("Problem opening bundle: %s\n", OSC_errorMessage);
815 return;
816 }
817
818 arg.type = INT_osc;
819 arg.datum.i = 0;
820 WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);
821
822 arg.type = FLOAT_osc;
823 arg.datum.i = 0.0f;
824 WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);
825
826 if (OSC_closeBundle(buf)) {
827 post("Problem closing bundle: %s\n", OSC_errorMessage);
828 }
829
830 return;
831 }
832
833 while (!isspace(*p) && *p != '\0') p++;
834 if (isspace(*p)) {
835 *p = '\0';
836 p++;
837 }
838
839 thisArg = 0;
840 while (*p != '\0') {
841 /* flush leading whitespace */
842 while (isspace(*p)) p++;
843 if (*p == '\0') break;
844
845 if (*p == '"') {
846 /* A string argument: scan for close quotes */
847 p++;
848 args[thisArg].type = STRING_osc;
849 args[thisArg].datum.s = p;
850
851 while (*p != '"') {
852 if (*p == '\0') {
853 post("Unterminated quote mark: ignoring line\n");
854 return;
855 }
856 p++;
857 }
858 *p = '\0';
859 p++;
860 } else {
861 token = p;
862 while (!isspace(*p) && (*p != '\0')) p++;
863 if (isspace(*p)) {
864 *p = '\0';
865 p++;
866 }
867 args[thisArg] = ParseToken(token);
868 }
869 thisArg++;
870 if (thisArg >= MAX_ARGS) {
871 post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
872 MAX_ARGS);
873 break;
874 }
875 }
876
877 if (WriteMessage(buf, messageName, thisArg, args) != 0) {
878 post("Problem sending message: %s\n", OSC_errorMessage);
879 }
880}
881
882typedArg ParseToken(char *token) {
883 char *p = token;
884 typedArg returnVal;
885
886 /* It might be an int, a float, or a string */
887
888 if (*p == '-') p++;
889
890 if (isdigit(*p) || *p == '.') {
891 while (isdigit(*p)) p++;
892 if (*p == '\0') {
893 returnVal.type = INT_osc;
894 returnVal.datum.i = atoi(token);
895 return returnVal;
896 }
897 if (*p == '.') {
898 p++;
899 while (isdigit(*p)) p++;
900 if (*p == '\0') {
901 returnVal.type = FLOAT_osc;
902 returnVal.datum.f = atof(token);
903 return returnVal;
904 }
905 }
906 }
907
908 returnVal.type = STRING_osc;
909 returnVal.datum.s = token;
910 return returnVal;
911}
912
913int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
914 int j, returnVal;
915 const int wmERROR = -1;
916
917 returnVal = 0;
918
919#ifdef DEBUG
920 printf("WriteMessage: %s ", messageName);
921
922 for (j = 0; j < numArgs; j++) {
923 switch (args[j].type) {
924 case INT_osc:
925 printf("%d ", args[j].datum.i);
926 break;
927
928 case FLOAT_osc:
929 printf("%f ", args[j].datum.f);
930 break;
931
932 case STRING_osc:
933 printf("%s ", args[j].datum.s);
934 break;
935
936 default:
937 error("Unrecognized arg type, (not exiting)");
938 return(wmERROR);
939 }
940 }
941 printf("\n");
942#endif
943
944 if (!useTypeTags) {
945 returnVal = OSC_writeAddress(buf, messageName);
946 if (returnVal) {
947 post("Problem writing address: %s\n", OSC_errorMessage);
948 }
949 } else {
950 /* First figure out the type tags */
951 char typeTags[MAX_ARGS+2];
952 int i;
953
954 typeTags[0] = ',';
955
956 for (i = 0; i < numArgs; ++i) {
957 switch (args[i].type) {
958 case INT_osc:
959 typeTags[i+1] = 'i';
960 break;
961
962 case FLOAT_osc:
963 typeTags[i+1] = 'f';
964 break;
965
966 case STRING_osc:
967 typeTags[i+1] = 's';
968 break;
969
970 default:
971 error("Unrecognized arg type (not exiting)");
972 return(wmERROR);
973 }
974 }
975 typeTags[i+1] = '\0';
976
977 returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
978 if (returnVal) {
979 post("Problem writing address: %s\n", OSC_errorMessage);
980 }
981 }
982
983 for (j = 0; j < numArgs; j++) {
984 switch (args[j].type) {
985 case INT_osc:
986 if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
987 return returnVal;
988 }
989 break;
990
991 case FLOAT_osc:
992 if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
993 return returnVal;
994 }
995 break;
996
997 case STRING_osc:
998 if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
999 return returnVal;
1000 }
1001 break;
1002
1003 default:
1004 error("Unrecognized arg type (not exiting)");
1005 returnVal = wmERROR;
1006 }
1007 }
1008 return returnVal;
1009}
1010
1011void SendBuffer(void *htmsocket, OSCbuf *buf) {
1012#ifdef DEBUG
1013 printf("Sending buffer...\n");
1014#endif
1015 if (OSC_isBufferEmpty(buf)) {
1016 post("SendBuffer() called but buffer empty");
1017 return;
1018 }
1019 if (!OSC_isBufferDone(buf)) {
1020 error("SendBuffer() called but buffer not ready!, not exiting");
1021 return; //{{raf}}
1022 }
1023 SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
1024}
1025
1026void SendData(void *htmsocket, int size, char *data) {
1027 if (!SendHTMSocket(htmsocket, size, data)) {
1028 post("SendData::SendHTMSocket()failure -- not connected");
1029 CloseHTMSocket(htmsocket);
1030 }
1031}
1032
1033
1034
1035/* ----------------------
1036 OSC-client code
1037
1038 */
1039
1040/* Here are the possible values of the state field: */
1041
1042#define EMPTY 0 /* Nothing written to packet yet */
1043#define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
1044#define NEED_COUNT 2 /* Just opened a bundle; must write message name or
1045 open another bundle */
1046#define GET_ARGS 3 /* Getting arguments to a message. If we see a message
1047 name or a bundle open/close then the current message
1048 will end. */
1049#define DONE 4 /* All open bundles have been closed, so can't write
1050 anything else */
1051
1052#ifdef WIN32
1053 #include <winsock2.h>
1054 #include <io.h>
1055 #include <stdio.h>
1056 #include <errno.h>
1057 #include <fcntl.h>
1058 #include <sys/types.h>
1059 #include <sys/stat.h>
1060#endif
1061
1062#ifdef __APPLE__
1063 #include <sys/types.h>
1064#endif
1065
1066#ifdef unix
1067 #include <netinet/in.h>
1068 #include <stdio.h>
1069#endif
1070
1071
1072char *OSC_errorMessage;
1073
1074static int OSC_padString(char *dest, char *str);
1075static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str);
1076static int OSC_WritePadding(char *dest, int i);
1077static int CheckTypeTag(OSCbuf *buf, char expectedType);
1078
1079void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) {
1080 buf->buffer = byteArray;
1081 buf->size = size;
1082 OSC_resetBuffer(buf);
1083}
1084
1085void OSC_resetBuffer(OSCbuf *buf) {
1086 buf->bufptr = buf->buffer;
1087 buf->state = EMPTY;
1088 buf->bundleDepth = 0;
1089 buf->prevCounts[0] = 0;
1090 buf->gettingFirstUntypedArg = 0;
1091 buf->typeStringPtr = 0;
1092}
1093
1094int OSC_isBufferEmpty(OSCbuf *buf) {
1095 return buf->bufptr == buf->buffer;
1096}
1097
1098int OSC_freeSpaceInBuffer(OSCbuf *buf) {
1099 return buf->size - (buf->bufptr - buf->buffer);
1100}
1101
1102int OSC_isBufferDone(OSCbuf *buf) {
1103 return (buf->state == DONE || buf->state == ONE_MSG_ARGS);
1104}
1105
1106char *OSC_getPacket(OSCbuf *buf) {
1107#ifdef ERROR_CHECK_GETPACKET
1108 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
1109 return buf->buffer;
1110 } else {
1111 OSC_errorMessage = "Packet has unterminated bundles";
1112 return 0;
1113 }
1114#else
1115 return buf->buffer;
1116#endif
1117}
1118
1119int OSC_packetSize(OSCbuf *buf) {
1120#ifdef ERROR_CHECK_PACKETSIZE
1121 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
1122 return (buf->bufptr - buf->buffer);
1123 } else {
1124 OSC_errorMessage = "Packet has unterminated bundles";
1125 return 0;
1126 }
1127#else
1128 return (buf->bufptr - buf->buffer);
1129#endif
1130}
1131
1132#define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}}
1133
1134static void PatchMessageSize(OSCbuf *buf) {
1135 int4byte size;
1136 size = buf->bufptr - ((char *) buf->thisMsgSize) - 4;
1137 *(buf->thisMsgSize) = htonl(size);
1138}
1139
1140int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) {
1141 if (buf->state == ONE_MSG_ARGS) {
1142 OSC_errorMessage = "Can't open a bundle in a one-message packet";
1143 return 3;
1144 }
1145
1146 if (buf->state == DONE) {
1147 OSC_errorMessage = "This packet is finished; can't open a new bundle";
1148 return 4;
1149 }
1150
1151 if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) {
1152 OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
1153 return 2;
1154 }
1155
1156 if (CheckTypeTag(buf, '\0')) return 9;
1157
1158 if (buf->state == GET_ARGS) {
1159 PatchMessageSize(buf);
1160 }
1161
1162 if (buf->state == EMPTY) {
1163 /* Need 16 bytes for "#bundle" and time tag */
1164 CheckOverflow(buf, 16);
1165 } else {
1166 /* This bundle is inside another bundle, so we need to leave
1167 a blank size count for the size of this current bundle. */
1168 CheckOverflow(buf, 20);
1169 *((int4byte *)buf->bufptr) = 0xaaaaaaaa;
1170 buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr;
1171
1172 buf->bufptr += 4;
1173 }
1174
1175 buf->bufptr += OSC_padString(buf->bufptr, "#bundle");
1176
1177
1178 *((OSCTimeTag *) buf->bufptr) = tt;
1179
1180 if (htonl(1) != 1) {
1181 /* Byte swap the 8-byte integer time tag */
1182 int4byte *intp = (int4byte *)buf->bufptr;
1183 intp[0] = htonl(intp[0]);
1184 intp[1] = htonl(intp[1]);
1185
1186#ifdef HAS8BYTEINT
1187 { /* tt is a 64-bit int so we have to swap the two 32-bit words.
1188 (Otherwise tt is a struct of two 32-bit words, and even though
1189 each word was wrong-endian, they were in the right order
1190 in the struct.) */
1191 int4byte temp = intp[0];
1192 intp[0] = intp[1];
1193 intp[1] = temp;
1194 }
1195#endif
1196 }
1197
1198 buf->bufptr += sizeof(OSCTimeTag);
1199
1200 buf->state = NEED_COUNT;
1201
1202 buf->gettingFirstUntypedArg = 0;
1203 buf->typeStringPtr = 0;
1204 return 0;
1205}
1206
1207
1208int OSC_closeBundle(OSCbuf *buf) {
1209 if (buf->bundleDepth == 0) {
1210 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
1211 OSC_errorMessage = "Can't close bundle; no bundle is open!";
1212 return 5;
1213 }
1214
1215 if (CheckTypeTag(buf, '\0')) return 9;
1216
1217 if (buf->state == GET_ARGS) {
1218 PatchMessageSize(buf);
1219 }
1220
1221 if (buf->bundleDepth == 1) {
1222 /* Closing the last bundle: No bundle size to patch */
1223 buf->state = DONE;
1224 } else {
1225 /* Closing a sub-bundle: patch bundle size */
1226 int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4;
1227 *(buf->prevCounts[buf->bundleDepth]) = htonl(size);
1228 buf->state = NEED_COUNT;
1229 }
1230
1231 --buf->bundleDepth;
1232 buf->gettingFirstUntypedArg = 0;
1233 buf->typeStringPtr = 0;
1234 return 0;
1235}
1236
1237
1238int OSC_closeAllBundles(OSCbuf *buf) {
1239 if (buf->bundleDepth == 0) {
1240 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
1241 OSC_errorMessage = "Can't close all bundles; no bundle is open!";
1242 return 6;
1243 }
1244
1245 if (CheckTypeTag(buf, '\0')) return 9;
1246
1247 while (buf->bundleDepth > 0) {
1248 OSC_closeBundle(buf);
1249 }
1250 buf->typeStringPtr = 0;
1251 return 0;
1252}
1253
1254int OSC_writeAddress(OSCbuf *buf, char *name) {
1255 int4byte paddedLength;
1256
1257 if (buf->state == ONE_MSG_ARGS) {
1258 OSC_errorMessage = "This packet is not a bundle, so you can't write another address";
1259 return 7;
1260 }
1261
1262 if (buf->state == DONE) {
1263 OSC_errorMessage = "This packet is finished; can't write another address";
1264 return 8;
1265 }
1266
1267 if (CheckTypeTag(buf, '\0')) return 9;
1268
1269 paddedLength = OSC_effectiveStringLength(name);
1270
1271 if (buf->state == EMPTY) {
1272 /* This will be a one-message packet, so no sizes to worry about */
1273 CheckOverflow(buf, paddedLength);
1274 buf->state = ONE_MSG_ARGS;
1275 } else {
1276 /* GET_ARGS or NEED_COUNT */
1277 CheckOverflow(buf, 4+paddedLength);
1278 if (buf->state == GET_ARGS) {
1279 /* Close the old message */
1280 PatchMessageSize(buf);
1281 }
1282 buf->thisMsgSize = (int4byte *)buf->bufptr;
1283 *(buf->thisMsgSize) = 0xbbbbbbbb;
1284 buf->bufptr += 4;
1285 buf->state = GET_ARGS;
1286 }
1287
1288 /* Now write the name */
1289 buf->bufptr += OSC_padString(buf->bufptr, name);
1290 buf->typeStringPtr = 0;
1291 buf->gettingFirstUntypedArg = 1;
1292
1293 return 0;
1294}
1295
1296int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) {
1297 int result;
1298 int4byte paddedLength;
1299
1300 if (CheckTypeTag(buf, '\0')) return 9;
1301
1302 result = OSC_writeAddress(buf, name);
1303
1304 if (result) return result;
1305
1306 paddedLength = OSC_effectiveStringLength(types);
1307
1308 CheckOverflow(buf, paddedLength);
1309
1310 buf->typeStringPtr = buf->bufptr + 1; /* skip comma */
1311 buf->bufptr += OSC_padString(buf->bufptr, types);
1312
1313 buf->gettingFirstUntypedArg = 0;
1314 return 0;
1315}
1316
1317static int CheckTypeTag(OSCbuf *buf, char expectedType) {
1318 if (buf->typeStringPtr) {
1319 if (*(buf->typeStringPtr) != expectedType) {
1320 if (expectedType == '\0') {
1321 OSC_errorMessage =
1322 "According to the type tag I expected more arguments.";
1323 } else if (*(buf->typeStringPtr) == '\0') {
1324 OSC_errorMessage =
1325 "According to the type tag I didn't expect any more arguments.";
1326 } else {
1327 OSC_errorMessage =
1328 "According to the type tag I expected an argument of a different type.";
1329 printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr);
1330 }
1331 return 9;
1332 }
1333 ++(buf->typeStringPtr);
1334 }
1335 return 0;
1336}
1337
1338
1339int OSC_writeFloatArg(OSCbuf *buf, float arg) {
1340 int4byte *intp;
1341 //int result;
1342
1343 CheckOverflow(buf, 4);
1344
1345 if (CheckTypeTag(buf, 'f')) return 9;
1346
1347 /* Pretend arg is a long int so we can use htonl() */
1348 intp = ((int4byte *) &arg);
1349 *((int4byte *) buf->bufptr) = htonl(*intp);
1350
1351 buf->bufptr += 4;
1352
1353 buf->gettingFirstUntypedArg = 0;
1354 return 0;
1355}
1356
1357
1358
1359int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) {
1360 int i;
1361 int4byte *intp;
1362
1363 CheckOverflow(buf, 4 * numFloats);
1364
1365 /* Pretend args are long ints so we can use htonl() */
1366 intp = ((int4byte *) args);
1367
1368 for (i = 0; i < numFloats; i++) {
1369 if (CheckTypeTag(buf, 'f')) return 9;
1370 *((int4byte *) buf->bufptr) = htonl(intp[i]);
1371 buf->bufptr += 4;
1372 }
1373
1374 buf->gettingFirstUntypedArg = 0;
1375 return 0;
1376}
1377
1378int OSC_writeIntArg(OSCbuf *buf, int4byte arg) {
1379 CheckOverflow(buf, 4);
1380 if (CheckTypeTag(buf, 'i')) return 9;
1381
1382 *((int4byte *) buf->bufptr) = htonl(arg);
1383 buf->bufptr += 4;
1384
1385 buf->gettingFirstUntypedArg = 0;
1386 return 0;
1387}
1388
1389int OSC_writeStringArg(OSCbuf *buf, char *arg) {
1390 int len;
1391
1392 if (CheckTypeTag(buf, 's')) return 9;
1393
1394 len = OSC_effectiveStringLength(arg);
1395
1396 if (buf->gettingFirstUntypedArg && arg[0] == ',') {
1397 /* This un-type-tagged message starts with a string
1398 that starts with a comma, so we have to escape it
1399 (with a double comma) so it won't look like a type
1400 tag string. */
1401
1402 CheckOverflow(buf, len+4); /* Too conservative */
1403 buf->bufptr +=
1404 OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg);
1405
1406 } else {
1407 CheckOverflow(buf, len);
1408 buf->bufptr += OSC_padString(buf->bufptr, arg);
1409 }
1410
1411 buf->gettingFirstUntypedArg = 0;
1412 return 0;
1413
1414}
1415
1416/* String utilities */
1417
1418#define STRING_ALIGN_PAD 4
1419int OSC_effectiveStringLength(char *string) {
1420 int len = strlen(string) + 1; /* We need space for the null char. */
1421
1422 /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
1423 if ((len % STRING_ALIGN_PAD) != 0) {
1424 len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD);
1425 }
1426 return len;
1427}
1428
1429static int OSC_padString(char *dest, char *str) {
1430 int i;
1431
1432 for (i = 0; str[i] != '\0'; i++) {
1433 dest[i] = str[i];
1434 }
1435
1436 return OSC_WritePadding(dest, i);
1437}
1438
1439static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) {
1440 int i;
1441
1442 dest[0] = ',';
1443 for (i = 0; str[i] != '\0'; i++) {
1444 dest[i+1] = str[i];
1445 }
1446
1447 return OSC_WritePadding(dest, i+1);
1448}
1449
1450static int OSC_WritePadding(char *dest, int i) {
1451 dest[i] = '\0';
1452 i++;
1453
1454 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
1455 dest[i] = '\0';
1456 }
1457
1458 return i;
1459}
1460
1461
1462/*
1463Written by Matt Wright, The Center for New Music and Audio Technologies,
1464University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
1465The Regents of the University of California (Regents).
1466
1467Permission to use, copy, modify, distribute, and distribute modified versions
1468of this software and its documentation without fee and without a signed
1469licensing agreement, is hereby granted, provided that the above copyright
1470notice, this paragraph and the following two paragraphs appear in all copies,
1471modifications, and distributions.
1472
1473IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
1474SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
1475OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
1476BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1477
1478REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1479THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1480PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
1481HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
1482MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1483
1484
1485The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
1486*/
1487
1488
1489/* sendOSC.c
1490
1491 Matt Wright, 6/3/97
1492 based on sendOSC.c, which was based on a version by Adrian Freed
1493
1494 Text-based OpenSoundControl client. User can enter messages via command
1495 line arguments or standard input.
1496
1497 Version 0.1: "play" feature
1498 Version 0.2: Message type tags.
1499
1500 pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c
1501 -------------
1502 -- added bundle stuff to send. jdl 20020416
1503 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
1504 -- ost_at_test.at + i22_at_test.at, 2000-2002
1505 modified to compile as pd externel
1506*/
1507
1508#define MAX_ARGS 2000
1509#define SC_BUFFER_SIZE 64000
1510
1511#include "m_pd.h"
1512#include "OSC-client.h"
1513
1514#include <string.h>
1515#include <sys/types.h>
1516#include <stdlib.h>
1517#include <stdio.h>
1518#include <sys/stat.h>
1519#include <sys/types.h>
1520
1521#ifdef WIN32
1522#include <winsock2.h>
1523#include <io.h>
1524#include <errno.h>
1525#include <fcntl.h>
1526#include <winsock2.h>
1527#include <ctype.h>
1528#include <signal.h>
1529#else
1530#include <sys/socket.h>
1531#include <netinet/in.h>
1532#include <rpc/rpc.h>
1533#include <sys/times.h>
1534#include <sys/param.h>
1535#include <sys/time.h>
1536#include <sys/ioctl.h>
1537#include <netdb.h>
1538#endif
1539
1540#ifdef __APPLE__
1541 #include <string.h>
1542#endif
1543
1544#define UNIXDG_PATH "/tmp/htm"
1545#define UNIXDG_TMP "/tmp/htm.XXXXXX"
1546
1547
1548
1549OSCTimeTag OSCTT_Immediately(void) {
1550 OSCTimeTag result;
1551 result.seconds = 0;
1552 result.fraction = 1;
1553 return result;
1554}
1555
1556
1557OSCTimeTag OSCTT_CurrentTime(void) {
1558 OSCTimeTag result;
1559 result.seconds = 0;
1560 result.fraction = 1;
1561 return result;
1562}
1563
1564OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
1565 OSCTimeTag result;
1566 result.seconds = 0;
1567 result.fraction = 1;
1568 return result;
1569}
1570
1571
1572typedef int bool;
1573
1574typedef struct
1575{
1576 float srate;
1577
1578 struct sockaddr_in serv_addr; /* udp socket */
1579 #ifndef WIN32
1580 struct sockaddr_un userv_addr; /* UNIX socket */
1581 #endif
1582 int sockfd; /* socket file descriptor */
1583 int index, len,uservlen;
1584 void *addr;
1585 int id;
1586} desc;
1587
1588
1589/* open a socket for HTM communication to given host on given portnumber */
1590/* if host is 0 then UNIX protocol is used (i.e. local communication */
1591void *OpenHTMSocket(char *host, int portnumber)
1592{
1593 struct sockaddr_in cl_addr;
1594 #ifndef WIN32
1595 int sockfd;
1596 struct sockaddr_un ucl_addr;
1597 #else
1598 unsigned int sockfd;
1599 #endif
1600
1601 desc *o;
1602 int oval = 1;
1603 o = malloc(sizeof(*o));
1604 if(!o) return 0;
1605
1606 #ifndef WIN32
1607
1608 if(!host)
1609 {
1610 char *mktemp(char *);
1611 int clilen;
1612 o->len = sizeof(ucl_addr);
1613 /*
1614 * Fill in the structure "userv_addr" with the address of the
1615 * server that we want to send to.
1616 */
1617
1618 bzero((char *) &o->userv_addr, sizeof(o->userv_addr));
1619 o->userv_addr.sun_family = AF_UNIX;
1620 strcpy(o->userv_addr.sun_path, UNIXDG_PATH);
1621 sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber);
1622 o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path);
1623 o->addr = &(o->userv_addr);
1624 /*
1625 * Open a socket (a UNIX domain datagram socket).
1626 */
1627
1628 if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
1629 {
1630 /*
1631 * Bind a local address for us.
1632 * In the UNIX domain we have to choose our own name (that
1633 * should be unique). We'll use mktemp() to create a unique
1634 * pathname, based on our process id.
1635 */
1636
1637 bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */
1638 ucl_addr.sun_family = AF_UNIX;
1639 strcpy(ucl_addr.sun_path, UNIXDG_TMP);
1640
1641 mktemp(ucl_addr.sun_path);
1642 clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path);
1643
1644 if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0)
1645 {
1646 perror("client: can't bind local address");
1647 close(sockfd);
1648 sockfd = -1;
1649 }
1650 }
1651 else
1652 perror("unable to make socket\n");
1653
1654 }else
1655
1656 #endif
1657
1658 {
1659 /*
1660 * Fill in the structure "serv_addr" with the address of the
1661 * server that we want to send to.
1662 */
1663 o->len = sizeof(cl_addr);
1664
1665 #ifdef WIN32
1666 ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr));
1667 #else
1668 bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
1669 #endif
1670
1671 o->serv_addr.sin_family = AF_INET;
1672
1673 /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
1674 so that host can be either an Internet host name (e.g.,
1675 "les") or an Internet address in standard dot notation
1676 (e.g., "128.32.122.13") */
1677 {
1678 struct hostent *hostsEntry;
1679 unsigned long address;
1680
1681 hostsEntry = gethostbyname(host);
1682 if (hostsEntry == NULL) {
1683 fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host);
1684 #ifndef WIN32
1685 herror(NULL);
1686 #endif
1687 return 0;
1688 }
1689 address = *((unsigned long *) hostsEntry->h_addr_list[0]);
1690 o->serv_addr.sin_addr.s_addr = address;
1691 }
1692
1693 /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
1694
1695 /* End MW changes */
1696
1697 /*
1698 * Open a socket (a UDP domain datagram socket).
1699 */
1700
1701
1702 #ifdef WIN32
1703 o->serv_addr.sin_port = htons((USHORT)portnumber);
1704 o->addr = &(o->serv_addr);
1705 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
1706 ZeroMemory((char *)&cl_addr, sizeof(cl_addr));
1707 cl_addr.sin_family = AF_INET;
1708 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1709 cl_addr.sin_port = htons(0);
1710
1711 // enable broadcast: jdl ~2003
1712 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
1713 perror("setsockopt");
1714 }
1715
1716 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
1717 perror("could not bind\n");
1718 closesocket(sockfd);
1719 sockfd = -1;
1720 }
1721 }
1722 else { perror("unable to make socket\n");}
1723 #else
1724 o->serv_addr.sin_port = htons(portnumber);
1725 o->addr = &(o->serv_addr);
1726 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
1727 bzero((char *)&cl_addr, sizeof(cl_addr));
1728 cl_addr.sin_family = AF_INET;
1729 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1730 cl_addr.sin_port = htons(0);
1731
1732 // enable broadcast: jdl ~2003
1733 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
1734 perror("setsockopt");
1735 }
1736
1737 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
1738 perror("could not bind\n");
1739 close(sockfd);
1740 sockfd = -1;
1741 }
1742 }
1743 else { perror("unable to make socket\n");}
1744 #endif
1745 }
1746 #ifdef WIN32
1747 if(sockfd == INVALID_SOCKET) {
1748 #else
1749 if(sockfd < 0) {
1750 #endif
1751 free(o);
1752 o = 0;
1753 }
1754 else
1755 o->sockfd = sockfd;
1756 return o;
1757}
1758
1759static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b)
1760{
1761 int rcount;
1762 if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count)
1763 {
1764 printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length);
1765 return FALSE;
1766 }
1767 return TRUE;
1768}
1769
1770bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer)
1771{
1772 desc *o = (desc *)htmsendhandle;
1773 return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer);
1774}
1775void CloseHTMSocket(void *htmsendhandle)
1776{
1777 desc *o = (desc *)htmsendhandle;
1778 #ifdef WIN32
1779 if(SOCKET_ERROR == closesocket(o->sockfd)) {
1780 perror("CloseHTMSocket::closesocket failed\n");
1781 return;
1782 }
1783 #else
1784 if(close(o->sockfd) == -1)
1785 {
1786 perror("CloseHTMSocket::closesocket failed");
1787 return;
1788 }
1789 #endif
1790
1791 free(o);
1792}
1793
1794
1795///////////////////////
1796// from sendOSC
1797
1798typedef struct {
1799 //enum {INT, FLOAT, STRING} type;
1800 enum {INT_osc, FLOAT_osc, STRING_osc} type;
1801 union {
1802 int i;
1803 float f;
1804 char *s;
1805 } datum;
1806} typedArg;
1807
1808void CommandLineMode(int argc, char *argv[], void *htmsocket);
1809OSCTimeTag ParseTimeTag(char *s);
1810void ParseInteractiveLine(OSCbuf *buf, char *mesg);
1811typedArg ParseToken(char *token);
1812int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args);
1813void SendBuffer(void *htmsocket, OSCbuf *buf);
1814void SendData(void *htmsocket, int size, char *data);
1815/* defined in OSC-system-dependent.c now */
1816
1817//static void *htmsocket;
1818static int exitStatus = 0;
1819static int useTypeTags = 0;
1820
1821static char bufferForOSCbuf[SC_BUFFER_SIZE];
1822
1823
1824/////////
1825// end from sendOSC
1826
1827static t_class *sendOSC_class;
1828
1829typedef struct _sendOSC
1830{
1831 t_object x_obj;
1832 int x_protocol; // UDP/TCP (udp only atm)
1833 t_int x_typetags; // typetag flag
1834 void *x_htmsocket; // sending socket
1835 int x_bundle; // bundle open flag
1836 OSCbuf x_oscbuf[1]; // OSCbuffer
1837 t_outlet *x_bdpthout;// bundle-depth floatoutlet
1838} t_sendOSC;
1839
1840static void *sendOSC_new(t_floatarg udpflag)
1841{
1842 t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class);
1843 outlet_new(&x->x_obj, &s_float);
1844 x->x_htmsocket = 0; // {{raf}}
1845 // set udp
1846 x->x_protocol = SOCK_STREAM;
1847 // set typetags to 1 by default
1848 x->x_typetags = 1;
1849 // bunlde is closed
1850 x->x_bundle = 0;
1851 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
1852 x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float();
1853 //x->x_oscbuf =
1854 return (x);
1855}
1856
1857
1858void sendOSC_openbundle(t_sendOSC *x)
1859{
1860 if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING ||
1861 OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()))
1862 {
1863 post("Problem opening bundle: %s\n", OSC_errorMessage);
1864 return;
1865 }
1866 x->x_bundle = 1;
1867 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
1868}
1869
1870static void sendOSC_closebundle(t_sendOSC *x)
1871{
1872 if (OSC_closeBundle(x->x_oscbuf)) {
1873 post("Problem closing bundle: %s\n", OSC_errorMessage);
1874 return;
1875 }
1876 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
1877 // in bundle mode we send when bundle is closed?
1878 if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) {
1879 // post("x_oscbuf: something inside me?");
1880 if (x->x_htmsocket) {
1881 SendBuffer(x->x_htmsocket, x->x_oscbuf);
1882 } else {
1883 post("sendOSC: not connected");
1884 }
1885 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
1886 x->x_bundle = 0;
1887 return;
1888 }
1889 // post("x_oscbuf: something went wrong");
1890}
1891
1892static void sendOSC_settypetags(t_sendOSC *x, t_float *f)
1893 {
1894 x->x_typetags = (int)f;
1895 post("sendOSC.c: setting typetags %d",x->x_typetags);
1896 }
1897
1898
1899static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname,
1900 t_floatarg fportno)
1901{
1902 int portno = fportno;
1903 /* create a socket */
1904
1905 // make sure handle is available
1906 if(x->x_htmsocket == 0) {
1907 //
1908 x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno);
1909 if (!x->x_htmsocket)
1910 post("Couldn't open socket: ");
1911 else {
1912 post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket);
1913 outlet_float(x->x_obj.ob_outlet, 1);
1914 }
1915 }
1916 else
1917 perror("call to sendOSC_connect() against UNavailable socket handle");
1918}
1919
1920void sendOSC_disconnect(t_sendOSC *x)
1921{
1922 if (x->x_htmsocket)
1923 {
1924 post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket);
1925 CloseHTMSocket(x->x_htmsocket);
1926 x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this
1927 outlet_float(x->x_obj.ob_outlet, 0);
1928 }
1929 else {
1930 perror("call to sendOSC_disconnect() against unused socket handle");
1931 }
1932}
1933
1934void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
1935{
1936 char* targv[MAXPDARG];
1937 char tmparg[MAXPDSTRING];
1938 char* tmp = tmparg;
1939 //char testarg[MAXPDSTRING];
1940 int c;
1941
1942 post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged...");
1943 return;
1944
1945 //atom_string(argv,testarg, MAXPDSTRING);
1946 for (c=0;c<argc;c++) {
1947 atom_string(argv+c,tmp, 80);
1948 targv[c] = tmp;
1949 tmp += strlen(tmp)+1;
1950 }
1951
1952 // this sock needs to be larger than 0, not >= ..
1953 if (x->x_htmsocket)
1954 {
1955 CommandLineMode(argc, targv, x->x_htmsocket);
1956 // post("test %d", c);
1957 }
1958 else {
1959 post("sendOSC: not connected");
1960 }
1961}
1962
1963//////////////////////////////////////////////////////////////////////
1964// this is the real and only sending routine now, for both typed and
1965// undtyped mode.
1966
1967static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
1968{
1969 char* targv[MAX_ARGS];
1970 char tmparg[MAXPDSTRING];
1971 char* tmp = tmparg;
1972 int c;
1973
1974 char *messageName;
1975 char *token;
1976 typedArg args[MAX_ARGS];
1977 int i,j;
1978 int numArgs = 0;
1979
1980 messageName = "";
1981#ifdef DEBUG
1982 post ("sendOSC: messageName: %s", messageName);
1983#endif
1984
1985
1986
1987 for (c=0;c<argc;c++) {
1988 atom_string(argv+c,tmp, 80);
1989
1990#ifdef DEBUG
1991 // post ("sendOSC: %d, %s",c, tmp);
1992#endif
1993
1994 targv[c] = tmp;
1995 tmp += strlen(tmp)+1;
1996
1997#ifdef DEBUG
1998 // post ("sendOSC: %d, %s",c, targv[c]);
1999#endif
2000 }
2001
2002 // this sock needs to be larger than 0, not >= ..
2003 if (x->x_htmsocket > 0)
2004 {
2005#ifdef DEBUG
2006 post ("sendOSC: type tags? %d", useTypeTags);
2007#endif
2008
2009 messageName = strtok(targv[0], ",");
2010 j = 1;
2011 for (i = j; i < argc; i++) {
2012 token = strtok(targv[i],",");
2013 args[i-j] = ParseToken(token);
2014#ifdef DEBUG
2015 printf("cell-cont: %s\n", targv[i]);
2016 printf(" type-id: %d\n", args[i-j]);
2017#endif
2018 numArgs = i;
2019 }
2020
2021
2022 if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) {
2023 post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage);
2024 return;
2025 }
2026
2027 if(!x->x_bundle) {
2028 SendBuffer(x->x_htmsocket, x->x_oscbuf);
2029 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
2030 }
2031
2032 //CommandLineMode(argc, targv, x->x_htmsocket);
2033 //useTypeTags = 0;
2034 }
2035 else {
2036 post("sendOSC: not connected");
2037 }
2038}
2039
2040void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
2041{
2042 if(!argc) {
2043 post("not sending empty message.");
2044 return;
2045 }
2046 if(x->x_typetags) {
2047 useTypeTags = 1;
2048 sendOSC_sendtyped(x,s,argc,argv);
2049 useTypeTags = 0;
2050 } else {
2051 sendOSC_sendtyped(x,s,argc,argv);
2052 }
2053}
2054
2055static void sendOSC_free(t_sendOSC *x)
2056{
2057 sendOSC_disconnect(x);
2058}
2059
2060#ifdef WIN32
2061 OSC_API void sendOSC_setup(void) {
2062#else
2063 void sendOSC_setup(void) {
2064#endif
2065 sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new,
2066 (t_method)sendOSC_free,
2067 sizeof(t_sendOSC), 0, A_DEFFLOAT, 0);
2068 class_addmethod(sendOSC_class, (t_method)sendOSC_connect,
2069 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
2070 class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect,
2071 gensym("disconnect"), 0);
2072 class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags,
2073 gensym("typetags"),
2074 A_FLOAT, 0);
2075 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2076 gensym("send"),
2077 A_GIMME, 0);
2078 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2079 gensym("senduntyped"),
2080 A_GIMME, 0);
2081 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2082 gensym("sendtyped"),
2083 A_GIMME, 0);
2084 class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle,
2085 gensym("["),
2086 0, 0);
2087 class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle,
2088 gensym("]"),
2089 0, 0);
2090 class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd"));
2091}
2092
2093
2094
2095
2096
2097/* Exit status codes:
2098 0: successful
2099 2: Message(s) dropped because of buffer overflow
2100 3: Socket error
2101 4: Usage error
2102 5: Internal error
2103*/
2104
2105void CommandLineMode(int argc, char *argv[], void *htmsocket) {
2106 char *messageName;
2107 char *token;
2108 typedArg args[MAX_ARGS];
2109 int i,j, numArgs;
2110 OSCbuf buf[1];
2111
2112 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
2113
2114 if (argc > 1) {
2115 post("argc (%d) > 1", argc);
2116 }
2117
2118 // ParseInteractiveLine(buf, argv);
2119 messageName = strtok(argv[0], ",");
2120
2121 j = 1;
2122 for (i = j; i < argc; i++) {
2123 token = strtok(argv[i],",");
2124 args[i-j] = ParseToken(token);
2125#ifdef DEBUG
2126 printf("cell-cont: %s\n", argv[i]);
2127 printf(" type-id: %d\n", args[i-j]);
2128#endif
2129 numArgs = i;
2130 }
2131
2132 if(WriteMessage(buf, messageName, numArgs, args)) {
2133 post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage);
2134 return;
2135 }
2136
2137 SendBuffer(htmsocket, buf);
2138}
2139
2140#define MAXMESG 2048
2141
2142void InteractiveMode(void *htmsocket) {
2143 char mesg[MAXMESG];
2144 OSCbuf buf[1];
2145 int bundleDepth = 0; /* At first, we haven't seen "[". */
2146
2147 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
2148
2149 while (fgets(mesg, MAXMESG, stdin) != NULL) {
2150 if (mesg[0] == '\n') {
2151 if (bundleDepth > 0) {
2152 /* Ignore blank lines inside a group. */
2153 } else {
2154 /* blank line => repeat previous send */
2155 SendBuffer(htmsocket, buf);
2156 }
2157 continue;
2158 }
2159
2160 if (bundleDepth == 0) {
2161 OSC_resetBuffer(buf);
2162 }
2163
2164 if (mesg[0] == '[') {
2165 OSCTimeTag tt = ParseTimeTag(mesg+1);
2166 if (OSC_openBundle(buf, tt)) {
2167 post("Problem opening bundle: %s\n", OSC_errorMessage);
2168 OSC_resetBuffer(buf);
2169 bundleDepth = 0;
2170 continue;
2171 }
2172 bundleDepth++;
2173 } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') {
2174 if (bundleDepth == 0) {
2175 post("Unexpected ']': not currently in a bundle.\n");
2176 } else {
2177 if (OSC_closeBundle(buf)) {
2178 post("Problem closing bundle: %s\n", OSC_errorMessage);
2179 OSC_resetBuffer(buf);
2180 bundleDepth = 0;
2181 continue;
2182 }
2183
2184 bundleDepth--;
2185 if (bundleDepth == 0) {
2186 SendBuffer(htmsocket, buf);
2187 }
2188 }
2189 } else {
2190 ParseInteractiveLine(buf, mesg);
2191 if (bundleDepth != 0) {
2192 /* Don't send anything until we close all bundles */
2193 } else {
2194 SendBuffer(htmsocket, buf);
2195 }
2196 }
2197 }
2198}
2199
2200OSCTimeTag ParseTimeTag(char *s) {
2201 char *p, *newline;
2202 typedArg arg;
2203
2204 p = s;
2205 while (isspace(*p)) p++;
2206 if (*p == '\0') return OSCTT_Immediately();
2207
2208 if (*p == '+') {
2209 /* Time tag is for some time in the future. It should be a
2210 number of seconds as an int or float */
2211
2212 newline = strchr(s, '\n');
2213 if (newline != NULL) *newline = '\0';
2214
2215 p++; /* Skip '+' */
2216 while (isspace(*p)) p++;
2217
2218 arg = ParseToken(p);
2219 if (arg.type == STRING_osc) {
2220 post("warning: inscrutable time tag request: %s\n", s);
2221 return OSCTT_Immediately();
2222 } else if (arg.type == INT_osc) {
2223 return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
2224 (float) arg.datum.i);
2225 } else if (arg.type == FLOAT_osc) {
2226 return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f);
2227 } else {
2228 error("This can't happen!");
2229 }
2230 }
2231
2232 if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) {
2233 /* They specified the 8-byte tag in hex */
2234 OSCTimeTag tt;
2235 if (sscanf(p, "%llx", &tt) != 1) {
2236 post("warning: couldn't parse time tag %s\n", s);
2237 return OSCTT_Immediately();
2238 }
2239#ifndef HAS8BYTEINT
2240 if (ntohl(1) != 1) {
2241 /* tt is a struct of seconds and fractional part,
2242 and this machine is little-endian, so sscanf
2243 wrote each half of the time tag in the wrong half
2244 of the struct. */
2245 int temp;
2246 temp = tt.seconds;
2247 tt.seconds = tt.fraction ;
2248 tt.fraction = temp;
2249 }
2250#endif
2251 return tt;
2252 }
2253
2254 post("warning: invalid time tag: %s\n", s);
2255 return OSCTT_Immediately();
2256}
2257
2258
2259void ParseInteractiveLine(OSCbuf *buf, char *mesg) {
2260 char *messageName, *token, *p;
2261 typedArg args[MAX_ARGS];
2262 int thisArg;
2263
2264 p = mesg;
2265 while (isspace(*p)) p++;
2266 if (*p == '\0') return;
2267
2268 messageName = p;
2269
2270 if (strcmp(messageName, "play\n") == 0) {
2271 /* Special kludge feature to save typing */
2272 typedArg arg;
2273
2274 if (OSC_openBundle(buf, OSCTT_Immediately())) {
2275 post("Problem opening bundle: %s\n", OSC_errorMessage);
2276 return;
2277 }
2278
2279 arg.type = INT_osc;
2280 arg.datum.i = 0;
2281 WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);
2282
2283 arg.type = FLOAT_osc;
2284 arg.datum.i = 0.0f;
2285 WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);
2286
2287 if (OSC_closeBundle(buf)) {
2288 post("Problem closing bundle: %s\n", OSC_errorMessage);
2289 }
2290
2291 return;
2292 }
2293
2294 while (!isspace(*p) && *p != '\0') p++;
2295 if (isspace(*p)) {
2296 *p = '\0';
2297 p++;
2298 }
2299
2300 thisArg = 0;
2301 while (*p != '\0') {
2302 /* flush leading whitespace */
2303 while (isspace(*p)) p++;
2304 if (*p == '\0') break;
2305
2306 if (*p == '"') {
2307 /* A string argument: scan for close quotes */
2308 p++;
2309 args[thisArg].type = STRING_osc;
2310 args[thisArg].datum.s = p;
2311
2312 while (*p != '"') {
2313 if (*p == '\0') {
2314 post("Unterminated quote mark: ignoring line\n");
2315 return;
2316 }
2317 p++;
2318 }
2319 *p = '\0';
2320 p++;
2321 } else {
2322 token = p;
2323 while (!isspace(*p) && (*p != '\0')) p++;
2324 if (isspace(*p)) {
2325 *p = '\0';
2326 p++;
2327 }
2328 args[thisArg] = ParseToken(token);
2329 }
2330 thisArg++;
2331 if (thisArg >= MAX_ARGS) {
2332 post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
2333 MAX_ARGS);
2334 break;
2335 }
2336 }
2337
2338 if (WriteMessage(buf, messageName, thisArg, args) != 0) {
2339 post("Problem sending message: %s\n", OSC_errorMessage);
2340 }
2341}
2342
2343typedArg ParseToken(char *token) {
2344 char *p = token;
2345 typedArg returnVal;
2346
2347 /* It might be an int, a float, or a string */
2348
2349 if (*p == '-') p++;
2350
2351 if (isdigit(*p) || *p == '.') {
2352 while (isdigit(*p)) p++;
2353 if (*p == '\0') {
2354 returnVal.type = INT_osc;
2355 returnVal.datum.i = atoi(token);
2356 return returnVal;
2357 }
2358 if (*p == '.') {
2359 p++;
2360 while (isdigit(*p)) p++;
2361 if (*p == '\0') {
2362 returnVal.type = FLOAT_osc;
2363 returnVal.datum.f = atof(token);
2364 return returnVal;
2365 }
2366 }
2367 }
2368
2369 returnVal.type = STRING_osc;
2370 returnVal.datum.s = token;
2371 return returnVal;
2372}
2373
2374int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
2375 int j, returnVal;
2376 const int wmERROR = -1;
2377
2378 returnVal = 0;
2379
2380#ifdef DEBUG
2381 printf("WriteMessage: %s ", messageName);
2382
2383 for (j = 0; j < numArgs; j++) {
2384 switch (args[j].type) {
2385 case INT_osc:
2386 printf("%d ", args[j].datum.i);
2387 break;
2388
2389 case FLOAT_osc:
2390 printf("%f ", args[j].datum.f);
2391 break;
2392
2393 case STRING_osc:
2394 printf("%s ", args[j].datum.s);
2395 break;
2396
2397 default:
2398 error("Unrecognized arg type, (not exiting)");
2399 return(wmERROR);
2400 }
2401 }
2402 printf("\n");
2403#endif
2404
2405 if (!useTypeTags) {
2406 returnVal = OSC_writeAddress(buf, messageName);
2407 if (returnVal) {
2408 post("Problem writing address: %s\n", OSC_errorMessage);
2409 }
2410 } else {
2411 /* First figure out the type tags */
2412 char typeTags[MAX_ARGS+2];
2413 int i;
2414
2415 typeTags[0] = ',';
2416
2417 for (i = 0; i < numArgs; ++i) {
2418 switch (args[i].type) {
2419 case INT_osc:
2420 typeTags[i+1] = 'i';
2421 break;
2422
2423 case FLOAT_osc:
2424 typeTags[i+1] = 'f';
2425 break;
2426
2427 case STRING_osc:
2428 typeTags[i+1] = 's';
2429 break;
2430
2431 default:
2432 error("Unrecognized arg type (not exiting)");
2433 return(wmERROR);
2434 }
2435 }
2436 typeTags[i+1] = '\0';
2437
2438 returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
2439 if (returnVal) {
2440 post("Problem writing address: %s\n", OSC_errorMessage);
2441 }
2442 }
2443
2444 for (j = 0; j < numArgs; j++) {
2445 switch (args[j].type) {
2446 case INT_osc:
2447 if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
2448 return returnVal;
2449 }
2450 break;
2451
2452 case FLOAT_osc:
2453 if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
2454 return returnVal;
2455 }
2456 break;
2457
2458 case STRING_osc:
2459 if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
2460 return returnVal;
2461 }
2462 break;
2463
2464 default:
2465 error("Unrecognized arg type (not exiting)");
2466 returnVal = wmERROR;
2467 }
2468 }
2469 return returnVal;
2470}
2471
2472void SendBuffer(void *htmsocket, OSCbuf *buf) {
2473#ifdef DEBUG
2474 printf("Sending buffer...\n");
2475#endif
2476 if (OSC_isBufferEmpty(buf)) {
2477 post("SendBuffer() called but buffer empty");
2478 return;
2479 }
2480 if (!OSC_isBufferDone(buf)) {
2481 error("SendBuffer() called but buffer not ready!, not exiting");
2482 return; //{{raf}}
2483 }
2484 SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
2485}
2486
2487void SendData(void *htmsocket, int size, char *data) {
2488 if (!SendHTMSocket(htmsocket, size, data)) {
2489 post("SendData::SendHTMSocket()failure -- not connected");
2490 CloseHTMSocket(htmsocket);
2491 }
2492}
2493
2494
2495
2496/* ----------------------
2497 OSC-client code
2498
2499 */
2500
2501/* Here are the possible values of the state field: */
2502
2503#define EMPTY 0 /* Nothing written to packet yet */
2504#define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
2505#define NEED_COUNT 2 /* Just opened a bundle; must write message name or
2506 open another bundle */
2507#define GET_ARGS 3 /* Getting arguments to a message. If we see a message
2508 name or a bundle open/close then the current message
2509 will end. */
2510#define DONE 4 /* All open bundles have been closed, so can't write
2511 anything else */
2512
2513#ifdef WIN32
2514 #include <winsock2.h>
2515 #include <io.h>
2516 #include <stdio.h>
2517 #include <errno.h>
2518 #include <fcntl.h>
2519 #include <sys/types.h>
2520 #include <sys/stat.h>
2521#endif
2522
2523#ifdef __APPLE__
2524 #include <sys/types.h>
2525#endif
2526
2527#ifdef unix
2528 #include <netinet/in.h>
2529 #include <stdio.h>
2530#endif
2531
2532
2533char *OSC_errorMessage;
2534
2535static int OSC_padString(char *dest, char *str);
2536static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str);
2537static int OSC_WritePadding(char *dest, int i);
2538static int CheckTypeTag(OSCbuf *buf, char expectedType);
2539
2540void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) {
2541 buf->buffer = byteArray;
2542 buf->size = size;
2543 OSC_resetBuffer(buf);
2544}
2545
2546void OSC_resetBuffer(OSCbuf *buf) {
2547 buf->bufptr = buf->buffer;
2548 buf->state = EMPTY;
2549 buf->bundleDepth = 0;
2550 buf->prevCounts[0] = 0;
2551 buf->gettingFirstUntypedArg = 0;
2552 buf->typeStringPtr = 0;
2553}
2554
2555int OSC_isBufferEmpty(OSCbuf *buf) {
2556 return buf->bufptr == buf->buffer;
2557}
2558
2559int OSC_freeSpaceInBuffer(OSCbuf *buf) {
2560 return buf->size - (buf->bufptr - buf->buffer);
2561}
2562
2563int OSC_isBufferDone(OSCbuf *buf) {
2564 return (buf->state == DONE || buf->state == ONE_MSG_ARGS);
2565}
2566
2567char *OSC_getPacket(OSCbuf *buf) {
2568#ifdef ERROR_CHECK_GETPACKET
2569 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
2570 return buf->buffer;
2571 } else {
2572 OSC_errorMessage = "Packet has unterminated bundles";
2573 return 0;
2574 }
2575#else
2576 return buf->buffer;
2577#endif
2578}
2579
2580int OSC_packetSize(OSCbuf *buf) {
2581#ifdef ERROR_CHECK_PACKETSIZE
2582 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
2583 return (buf->bufptr - buf->buffer);
2584 } else {
2585 OSC_errorMessage = "Packet has unterminated bundles";
2586 return 0;
2587 }
2588#else
2589 return (buf->bufptr - buf->buffer);
2590#endif
2591}
2592
2593#define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}}
2594
2595static void PatchMessageSize(OSCbuf *buf) {
2596 int4byte size;
2597 size = buf->bufptr - ((char *) buf->thisMsgSize) - 4;
2598 *(buf->thisMsgSize) = htonl(size);
2599}
2600
2601int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) {
2602 if (buf->state == ONE_MSG_ARGS) {
2603 OSC_errorMessage = "Can't open a bundle in a one-message packet";
2604 return 3;
2605 }
2606
2607 if (buf->state == DONE) {
2608 OSC_errorMessage = "This packet is finished; can't open a new bundle";
2609 return 4;
2610 }
2611
2612 if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) {
2613 OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
2614 return 2;
2615 }
2616
2617 if (CheckTypeTag(buf, '\0')) return 9;
2618
2619 if (buf->state == GET_ARGS) {
2620 PatchMessageSize(buf);
2621 }
2622
2623 if (buf->state == EMPTY) {
2624 /* Need 16 bytes for "#bundle" and time tag */
2625 CheckOverflow(buf, 16);
2626 } else {
2627 /* This bundle is inside another bundle, so we need to leave
2628 a blank size count for the size of this current bundle. */
2629 CheckOverflow(buf, 20);
2630 *((int4byte *)buf->bufptr) = 0xaaaaaaaa;
2631 buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr;
2632
2633 buf->bufptr += 4;
2634 }
2635
2636 buf->bufptr += OSC_padString(buf->bufptr, "#bundle");
2637
2638
2639 *((OSCTimeTag *) buf->bufptr) = tt;
2640
2641 if (htonl(1) != 1) {
2642 /* Byte swap the 8-byte integer time tag */
2643 int4byte *intp = (int4byte *)buf->bufptr;
2644 intp[0] = htonl(intp[0]);
2645 intp[1] = htonl(intp[1]);
2646
2647#ifdef HAS8BYTEINT
2648 { /* tt is a 64-bit int so we have to swap the two 32-bit words.
2649 (Otherwise tt is a struct of two 32-bit words, and even though
2650 each word was wrong-endian, they were in the right order
2651 in the struct.) */
2652 int4byte temp = intp[0];
2653 intp[0] = intp[1];
2654 intp[1] = temp;
2655 }
2656#endif
2657 }
2658
2659 buf->bufptr += sizeof(OSCTimeTag);
2660
2661 buf->state = NEED_COUNT;
2662
2663 buf->gettingFirstUntypedArg = 0;
2664 buf->typeStringPtr = 0;
2665 return 0;
2666}
2667
2668
2669int OSC_closeBundle(OSCbuf *buf) {
2670 if (buf->bundleDepth == 0) {
2671 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
2672 OSC_errorMessage = "Can't close bundle; no bundle is open!";
2673 return 5;
2674 }
2675
2676 if (CheckTypeTag(buf, '\0')) return 9;
2677
2678 if (buf->state == GET_ARGS) {
2679 PatchMessageSize(buf);
2680 }
2681
2682 if (buf->bundleDepth == 1) {
2683 /* Closing the last bundle: No bundle size to patch */
2684 buf->state = DONE;
2685 } else {
2686 /* Closing a sub-bundle: patch bundle size */
2687 int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4;
2688 *(buf->prevCounts[buf->bundleDepth]) = htonl(size);
2689 buf->state = NEED_COUNT;
2690 }
2691
2692 --buf->bundleDepth;
2693 buf->gettingFirstUntypedArg = 0;
2694 buf->typeStringPtr = 0;
2695 return 0;
2696}
2697
2698
2699int OSC_closeAllBundles(OSCbuf *buf) {
2700 if (buf->bundleDepth == 0) {
2701 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
2702 OSC_errorMessage = "Can't close all bundles; no bundle is open!";
2703 return 6;
2704 }
2705
2706 if (CheckTypeTag(buf, '\0')) return 9;
2707
2708 while (buf->bundleDepth > 0) {
2709 OSC_closeBundle(buf);
2710 }
2711 buf->typeStringPtr = 0;
2712 return 0;
2713}
2714
2715int OSC_writeAddress(OSCbuf *buf, char *name) {
2716 int4byte paddedLength;
2717
2718 if (buf->state == ONE_MSG_ARGS) {
2719 OSC_errorMessage = "This packet is not a bundle, so you can't write another address";
2720 return 7;
2721 }
2722
2723 if (buf->state == DONE) {
2724 OSC_errorMessage = "This packet is finished; can't write another address";
2725 return 8;
2726 }
2727
2728 if (CheckTypeTag(buf, '\0')) return 9;
2729
2730 paddedLength = OSC_effectiveStringLength(name);
2731
2732 if (buf->state == EMPTY) {
2733 /* This will be a one-message packet, so no sizes to worry about */
2734 CheckOverflow(buf, paddedLength);
2735 buf->state = ONE_MSG_ARGS;
2736 } else {
2737 /* GET_ARGS or NEED_COUNT */
2738 CheckOverflow(buf, 4+paddedLength);
2739 if (buf->state == GET_ARGS) {
2740 /* Close the old message */
2741 PatchMessageSize(buf);
2742 }
2743 buf->thisMsgSize = (int4byte *)buf->bufptr;
2744 *(buf->thisMsgSize) = 0xbbbbbbbb;
2745 buf->bufptr += 4;
2746 buf->state = GET_ARGS;
2747 }
2748
2749 /* Now write the name */
2750 buf->bufptr += OSC_padString(buf->bufptr, name);
2751 buf->typeStringPtr = 0;
2752 buf->gettingFirstUntypedArg = 1;
2753
2754 return 0;
2755}
2756
2757int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) {
2758 int result;
2759 int4byte paddedLength;
2760
2761 if (CheckTypeTag(buf, '\0')) return 9;
2762
2763 result = OSC_writeAddress(buf, name);
2764
2765 if (result) return result;
2766
2767 paddedLength = OSC_effectiveStringLength(types);
2768
2769 CheckOverflow(buf, paddedLength);
2770
2771 buf->typeStringPtr = buf->bufptr + 1; /* skip comma */
2772 buf->bufptr += OSC_padString(buf->bufptr, types);
2773
2774 buf->gettingFirstUntypedArg = 0;
2775 return 0;
2776}
2777
2778static int CheckTypeTag(OSCbuf *buf, char expectedType) {
2779 if (buf->typeStringPtr) {
2780 if (*(buf->typeStringPtr) != expectedType) {
2781 if (expectedType == '\0') {
2782 OSC_errorMessage =
2783 "According to the type tag I expected more arguments.";
2784 } else if (*(buf->typeStringPtr) == '\0') {
2785 OSC_errorMessage =
2786 "According to the type tag I didn't expect any more arguments.";
2787 } else {
2788 OSC_errorMessage =
2789 "According to the type tag I expected an argument of a different type.";
2790 printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr);
2791 }
2792 return 9;
2793 }
2794 ++(buf->typeStringPtr);
2795 }
2796 return 0;
2797}
2798
2799
2800int OSC_writeFloatArg(OSCbuf *buf, float arg) {
2801 int4byte *intp;
2802 //int result;
2803
2804 CheckOverflow(buf, 4);
2805
2806 if (CheckTypeTag(buf, 'f')) return 9;
2807
2808 /* Pretend arg is a long int so we can use htonl() */
2809 intp = ((int4byte *) &arg);
2810 *((int4byte *) buf->bufptr) = htonl(*intp);
2811
2812 buf->bufptr += 4;
2813
2814 buf->gettingFirstUntypedArg = 0;
2815 return 0;
2816}
2817
2818
2819
2820int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) {
2821 int i;
2822 int4byte *intp;
2823
2824 CheckOverflow(buf, 4 * numFloats);
2825
2826 /* Pretend args are long ints so we can use htonl() */
2827 intp = ((int4byte *) args);
2828
2829 for (i = 0; i < numFloats; i++) {
2830 if (CheckTypeTag(buf, 'f')) return 9;
2831 *((int4byte *) buf->bufptr) = htonl(intp[i]);
2832 buf->bufptr += 4;
2833 }
2834
2835 buf->gettingFirstUntypedArg = 0;
2836 return 0;
2837}
2838
2839int OSC_writeIntArg(OSCbuf *buf, int4byte arg) {
2840 CheckOverflow(buf, 4);
2841 if (CheckTypeTag(buf, 'i')) return 9;
2842
2843 *((int4byte *) buf->bufptr) = htonl(arg);
2844 buf->bufptr += 4;
2845
2846 buf->gettingFirstUntypedArg = 0;
2847 return 0;
2848}
2849
2850int OSC_writeStringArg(OSCbuf *buf, char *arg) {
2851 int len;
2852
2853 if (CheckTypeTag(buf, 's')) return 9;
2854
2855 len = OSC_effectiveStringLength(arg);
2856
2857 if (buf->gettingFirstUntypedArg && arg[0] == ',') {
2858 /* This un-type-tagged message starts with a string
2859 that starts with a comma, so we have to escape it
2860 (with a double comma) so it won't look like a type
2861 tag string. */
2862
2863 CheckOverflow(buf, len+4); /* Too conservative */
2864 buf->bufptr +=
2865 OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg);
2866
2867 } else {
2868 CheckOverflow(buf, len);
2869 buf->bufptr += OSC_padString(buf->bufptr, arg);
2870 }
2871
2872 buf->gettingFirstUntypedArg = 0;
2873 return 0;
2874
2875}
2876
2877/* String utilities */
2878
2879#define STRING_ALIGN_PAD 4
2880int OSC_effectiveStringLength(char *string) {
2881 int len = strlen(string) + 1; /* We need space for the null char. */
2882
2883 /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
2884 if ((len % STRING_ALIGN_PAD) != 0) {
2885 len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD);
2886 }
2887 return len;
2888}
2889
2890static int OSC_padString(char *dest, char *str) {
2891 int i;
2892
2893 for (i = 0; str[i] != '\0'; i++) {
2894 dest[i] = str[i];
2895 }
2896
2897 return OSC_WritePadding(dest, i);
2898}
2899
2900static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) {
2901 int i;
2902
2903 dest[0] = ',';
2904 for (i = 0; str[i] != '\0'; i++) {
2905 dest[i+1] = str[i];
2906 }
2907
2908 return OSC_WritePadding(dest, i+1);
2909}
2910
2911static int OSC_WritePadding(char *dest, int i) {
2912 dest[i] = '\0';
2913 i++;
2914
2915 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
2916 dest[i] = '\0';
2917 }
2918
2919 return i;
2920}
2921
2922
diff --git a/apps/plugins/pdbox/PDa/extra/sformat.h b/apps/plugins/pdbox/PDa/extra/sformat.h
new file mode 100644
index 0000000000..b75ef98c9a
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/sformat.h
@@ -0,0 +1,110 @@
1
2#ifndef SFORMAT_H__
3#define SFORMAT_H__
4
5typedef unsigned short uint16;
6typedef unsigned long uint32;
7
8#define FORMAT_WAVE 0
9#define FORMAT_AIFF 1
10#define FORMAT_NEXT 2
11
12/* the NeXTStep sound header structure; can be big or little endian */
13
14typedef struct _nextstep
15{
16 char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
17 uint32 ns_onset; /* byte offset of first sample */
18 uint32 ns_length; /* length of sound in bytes */
19 uint32 ns_format; /* format; see below */
20 uint32 ns_sr; /* sample rate */
21 uint32 ns_nchans; /* number of channels */
22 char ns_info[4]; /* comment */
23} t_nextstep;
24
25#define NS_FORMAT_LINEAR_16 3
26#define NS_FORMAT_LINEAR_24 4
27#define NS_FORMAT_FLOAT 6
28#define SCALE (1./(1024. * 1024. * 1024. * 2.))
29
30/* the WAVE header. All Wave files are little endian. We assume
31 the "fmt" chunk comes first which is usually the case but perhaps not
32 always; same for AIFF and the "COMM" chunk. */
33
34typedef unsigned word;
35typedef unsigned long dword;
36
37typedef struct _wave
38{
39 char w_fileid[4]; /* chunk id 'RIFF' */
40 uint32 w_chunksize; /* chunk size */
41 char w_waveid[4]; /* wave chunk id 'WAVE' */
42 char w_fmtid[4]; /* format chunk id 'fmt ' */
43 uint32 w_fmtchunksize; /* format chunk size */
44 uint16 w_fmttag; /* format tag, 1 for PCM */
45 uint16 w_nchannels; /* number of channels */
46 uint32 w_samplespersec; /* sample rate in hz */
47 uint32 w_navgbytespersec; /* average bytes per second */
48 uint16 w_nblockalign; /* number of bytes per sample */
49 uint16 w_nbitspersample; /* number of bits in a sample */
50 char w_datachunkid[4]; /* data chunk id 'data' */
51 uint32 w_datachunksize; /* length of data chunk */
52} t_wave;
53
54
55#endif
56
57#ifndef SFORMAT_H__
58#define SFORMAT_H__
59
60typedef unsigned short uint16;
61typedef unsigned long uint32;
62
63#define FORMAT_WAVE 0
64#define FORMAT_AIFF 1
65#define FORMAT_NEXT 2
66
67/* the NeXTStep sound header structure; can be big or little endian */
68
69typedef struct _nextstep
70{
71 char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
72 uint32 ns_onset; /* byte offset of first sample */
73 uint32 ns_length; /* length of sound in bytes */
74 uint32 ns_format; /* format; see below */
75 uint32 ns_sr; /* sample rate */
76 uint32 ns_nchans; /* number of channels */
77 char ns_info[4]; /* comment */
78} t_nextstep;
79
80#define NS_FORMAT_LINEAR_16 3
81#define NS_FORMAT_LINEAR_24 4
82#define NS_FORMAT_FLOAT 6
83#define SCALE (1./(1024. * 1024. * 1024. * 2.))
84
85/* the WAVE header. All Wave files are little endian. We assume
86 the "fmt" chunk comes first which is usually the case but perhaps not
87 always; same for AIFF and the "COMM" chunk. */
88
89typedef unsigned word;
90typedef unsigned long dword;
91
92typedef struct _wave
93{
94 char w_fileid[4]; /* chunk id 'RIFF' */
95 uint32 w_chunksize; /* chunk size */
96 char w_waveid[4]; /* wave chunk id 'WAVE' */
97 char w_fmtid[4]; /* format chunk id 'fmt ' */
98 uint32 w_fmtchunksize; /* format chunk size */
99 uint16 w_fmttag; /* format tag, 1 for PCM */
100 uint16 w_nchannels; /* number of channels */
101 uint32 w_samplespersec; /* sample rate in hz */
102 uint32 w_navgbytespersec; /* average bytes per second */
103 uint16 w_nblockalign; /* number of bytes per sample */
104 uint16 w_nbitspersample; /* number of bits in a sample */
105 char w_datachunkid[4]; /* data chunk id 'data' */
106 uint32 w_datachunksize; /* length of data chunk */
107} t_wave;
108
109
110#endif
diff --git a/apps/plugins/pdbox/PDa/extra/shell.c b/apps/plugins/pdbox/PDa/extra/shell.c
new file mode 100644
index 0000000000..a0b6cef5b5
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/shell.c
@@ -0,0 +1,624 @@
1/* (C) Guenter Geiger <geiger@epy.co.at> */
2
3#include "m_pd.h"
4#ifdef NT
5#pragma warning( disable : 4244 )
6#pragma warning( disable : 4305 )
7#endif
8
9#include <unistd.h>
10#include <stdlib.h>
11#include <string.h>
12#include <stdio.h>
13#include <sys/types.h>
14#include <sys/wait.h>
15#include <signal.h>
16#include <sched.h>
17
18void sys_rmpollfn(int fd);
19void sys_addpollfn(int fd, void* fn, void *ptr);
20
21/* ------------------------ shell ----------------------------- */
22
23#define INBUFSIZE 1024
24
25static t_class *shell_class;
26
27
28static void drop_priority(void)
29{
30#ifdef _POSIX_PRIORITY_SCHEDULING
31 struct sched_param par;
32 int p1 ,p2, p3;
33 par.sched_priority = 0;
34 sched_setscheduler(0,SCHED_OTHER,&par);
35#endif
36}
37
38
39typedef struct _shell
40{
41 t_object x_obj;
42 int x_echo;
43 char *sr_inbuf;
44 int sr_inhead;
45 int sr_intail;
46 void* x_binbuf;
47 int fdpipe[2];
48 int fdinpipe[2];
49 int pid;
50 int x_del;
51 t_outlet* x_done;
52 t_clock* x_clock;
53} t_shell;
54
55static int shell_pid;
56
57
58void shell_cleanup(t_shell* x)
59{
60 sys_rmpollfn(x->fdpipe[0]);
61
62 if (x->fdpipe[0]>0) close(x->fdpipe[0]);
63 if (x->fdpipe[1]>0) close(x->fdpipe[1]);
64 if (x->fdinpipe[0]>0) close(x->fdinpipe[0]);
65 if (x->fdinpipe[1]>0) close(x->fdinpipe[1]);
66
67 x->fdpipe[0] = -1;
68 x->fdpipe[1] = -1;
69 x->fdinpipe[0] = -1;
70 x->fdinpipe[1] = -1;
71 clock_unset(x->x_clock);
72}
73
74void shell_check(t_shell* x)
75{
76 int ret;
77 int status;
78 ret = waitpid(x->pid,&status,WNOHANG);
79 if (ret == x->pid) {
80 shell_cleanup(x);
81 if (WIFEXITED(status)) {
82 outlet_float(x->x_done,WEXITSTATUS(status));
83 }
84 else outlet_float(x->x_done,0);
85 }
86 else {
87 if (x->x_del < 100) x->x_del+=2; /* increment poll times */
88 clock_delay(x->x_clock,x->x_del);
89 }
90}
91
92
93void shell_bang(t_shell *x)
94{
95 post("bang");
96}
97
98/* snippet from pd's code */
99static void shell_doit(void *z, t_binbuf *b)
100{
101 t_shell *x = (t_shell *)z;
102 int msg, natom = binbuf_getnatom(b);
103 t_atom *at = binbuf_getvec(b);
104
105 for (msg = 0; msg < natom;)
106 {
107 int emsg;
108 for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
109 && at[emsg].a_type != A_SEMI; emsg++)
110 ;
111 if (emsg > msg)
112 {
113 int i;
114 for (i = msg; i < emsg; i++)
115 if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
116 {
117 pd_error(x, "netreceive: got dollar sign in message");
118 goto nodice;
119 }
120 if (at[msg].a_type == A_FLOAT)
121 {
122 if (emsg > msg + 1)
123 outlet_list(x->x_obj.ob_outlet, 0, emsg-msg, at + msg);
124 else outlet_float(x->x_obj.ob_outlet, at[msg].a_w.w_float);
125 }
126 else if (at[msg].a_type == A_SYMBOL)
127 outlet_anything(x->x_obj.ob_outlet, at[msg].a_w.w_symbol,
128 emsg-msg-1, at + msg + 1);
129 }
130 nodice:
131 msg = emsg + 1;
132 }
133}
134
135
136void shell_read(t_shell *x, int fd)
137{
138 char buf[INBUFSIZE];
139 t_binbuf* bbuf = binbuf_new();
140 int i;
141 int readto =
142 (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
143 int ret;
144
145 ret = read(fd, buf,INBUFSIZE-1);
146 buf[ret] = '\0';
147
148 for (i=0;i<ret;i++)
149 if (buf[i] == '\n') buf[i] = ';';
150 if (ret < 0)
151 {
152 error("shell: pipe read error");
153 sys_rmpollfn(fd);
154 x->fdpipe[0] = -1;
155 close(fd);
156 return;
157 }
158 else if (ret == 0)
159 {
160 post("EOF on socket %d\n", fd);
161 sys_rmpollfn(fd);
162 x->fdpipe[0] = -1;
163 close(fd);
164 return;
165 }
166 else
167 {
168 int natom;
169 t_atom *at;
170 binbuf_text(bbuf, buf, strlen(buf));
171
172 natom = binbuf_getnatom(bbuf);
173 at = binbuf_getvec(bbuf);
174 shell_doit(x,bbuf);
175 }
176 binbuf_free(bbuf);
177}
178
179
180static void shell_send(t_shell *x, t_symbol *s,int ac, t_atom *at)
181{
182 int i;
183 char tmp[MAXPDSTRING];
184 int size = 0;
185
186 if (x->fdinpipe[0] == -1) return; /* nothing to send to */
187
188 for (i=0;i<ac;i++) {
189 atom_string(at,tmp+size,MAXPDSTRING - size);
190 at++;
191 size=strlen(tmp);
192 tmp[size++] = ' ';
193 }
194 tmp[size-1] = '\0';
195 post("sending %s",tmp);
196 write(x->fdinpipe[0],tmp,strlen(tmp));
197}
198
199static void shell_anything(t_shell *x, t_symbol *s, int ac, t_atom *at)
200{
201 int i;
202 char* argv[20];
203 t_symbol* sym;
204
205 if (!strcmp(s->s_name,"send")) {
206 post("send");
207 shell_send(x,s,ac,at);
208 return;
209 }
210
211 argv[0] = s->s_name;
212
213 if (x->fdpipe[0] != -1) {
214 post("shell: old process still running");
215 kill(x->pid,SIGKILL);
216 shell_cleanup(x);
217 }
218
219
220 if (pipe(x->fdpipe) < 0) {
221 error("unable to create pipe");
222 return;
223 }
224
225 if (pipe(x->fdinpipe) < 0) {
226 error("unable to create input pipe");
227 return;
228 }
229
230
231 sys_addpollfn(x->fdpipe[0],shell_read,x);
232
233 if (!(x->pid = fork())) {
234 int status;
235 char* cmd = getbytes(1024);
236 char* tcmd = getbytes(1024);
237 strcpy(cmd,s->s_name);
238
239#if 0
240 for (i=1;i<=ac;i++) {
241 argv[i] = getbytes(255);
242 atom_string(at,argv[i],255);
243/* post("argument %s",argv[i]); */
244 at++;
245 }
246 argv[i] = 0;
247#endif
248 for (i=1;i<=ac;i++) {
249 atom_string(at,tcmd,255);
250 strcat(cmd," ");
251 strcat(cmd,tcmd);
252 at++;
253 }
254
255
256 /* reassign stdout */
257 dup2(x->fdpipe[1],1);
258 dup2(x->fdinpipe[1],0);
259
260 /* drop privileges */
261 drop_priority();
262 seteuid(getuid()); /* lose setuid priveliges */
263
264 post("executing %s",cmd);
265 system(cmd);
266// execvp(s->s_name,argv);
267 exit(0);
268 }
269 x->x_del = 4;
270 clock_delay(x->x_clock,x->x_del);
271
272 if (x->x_echo)
273 outlet_anything(x->x_obj.ob_outlet, s, ac, at);
274}
275
276
277
278void shell_free(t_shell* x)
279{
280 binbuf_free(x->x_binbuf);
281}
282
283static void *shell_new(void)
284{
285 t_shell *x = (t_shell *)pd_new(shell_class);
286
287 x->x_echo = 0;
288 x->fdpipe[0] = -1;
289 x->fdpipe[1] = -1;
290 x->fdinpipe[0] = -1;
291 x->fdinpipe[1] = -1;
292
293 x->sr_inhead = x->sr_intail = 0;
294 if (!(x->sr_inbuf = (char*) malloc(INBUFSIZE))) bug("t_shell");;
295
296 x->x_binbuf = binbuf_new();
297
298 outlet_new(&x->x_obj, &s_list);
299 x->x_done = outlet_new(&x->x_obj, &s_bang);
300 x->x_clock = clock_new(x, (t_method) shell_check);
301 return (x);
302}
303
304void shell_setup(void)
305{
306 shell_class = class_new(gensym("shell"), (t_newmethod)shell_new,
307 (t_method)shell_free,sizeof(t_shell), 0,0);
308 class_addbang(shell_class,shell_bang);
309 class_addanything(shell_class, shell_anything);
310}
311
312
313/* (C) Guenter Geiger <geiger@epy.co.at> */
314
315#include "m_pd.h"
316#ifdef NT
317#pragma warning( disable : 4244 )
318#pragma warning( disable : 4305 )
319#endif
320
321#include <unistd.h>
322#include <stdlib.h>
323#include <string.h>
324#include <stdio.h>
325#include <sys/types.h>
326#include <sys/wait.h>
327#include <signal.h>
328#include <sched.h>
329
330void sys_rmpollfn(int fd);
331void sys_addpollfn(int fd, void* fn, void *ptr);
332
333/* ------------------------ shell ----------------------------- */
334
335#define INBUFSIZE 1024
336
337static t_class *shell_class;
338
339
340static void drop_priority(void)
341{
342#ifdef _POSIX_PRIORITY_SCHEDULING
343 struct sched_param par;
344 int p1 ,p2, p3;
345 par.sched_priority = 0;
346 sched_setscheduler(0,SCHED_OTHER,&par);
347#endif
348}
349
350
351typedef struct _shell
352{
353 t_object x_obj;
354 int x_echo;
355 char *sr_inbuf;
356 int sr_inhead;
357 int sr_intail;
358 void* x_binbuf;
359 int fdpipe[2];
360 int fdinpipe[2];
361 int pid;
362 int x_del;
363 t_outlet* x_done;
364 t_clock* x_clock;
365} t_shell;
366
367static int shell_pid;
368
369
370void shell_cleanup(t_shell* x)
371{
372 sys_rmpollfn(x->fdpipe[0]);
373
374 if (x->fdpipe[0]>0) close(x->fdpipe[0]);
375 if (x->fdpipe[1]>0) close(x->fdpipe[1]);
376 if (x->fdinpipe[0]>0) close(x->fdinpipe[0]);
377 if (x->fdinpipe[1]>0) close(x->fdinpipe[1]);
378
379 x->fdpipe[0] = -1;
380 x->fdpipe[1] = -1;
381 x->fdinpipe[0] = -1;
382 x->fdinpipe[1] = -1;
383 clock_unset(x->x_clock);
384}
385
386void shell_check(t_shell* x)
387{
388 int ret;
389 int status;
390 ret = waitpid(x->pid,&status,WNOHANG);
391 if (ret == x->pid) {
392 shell_cleanup(x);
393 if (WIFEXITED(status)) {
394 outlet_float(x->x_done,WEXITSTATUS(status));
395 }
396 else outlet_float(x->x_done,0);
397 }
398 else {
399 if (x->x_del < 100) x->x_del+=2; /* increment poll times */
400 clock_delay(x->x_clock,x->x_del);
401 }
402}
403
404
405void shell_bang(t_shell *x)
406{
407 post("bang");
408}
409
410/* snippet from pd's code */
411static void shell_doit(void *z, t_binbuf *b)
412{
413 t_shell *x = (t_shell *)z;
414 int msg, natom = binbuf_getnatom(b);
415 t_atom *at = binbuf_getvec(b);
416
417 for (msg = 0; msg < natom;)
418 {
419 int emsg;
420 for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
421 && at[emsg].a_type != A_SEMI; emsg++)
422 ;
423 if (emsg > msg)
424 {
425 int i;
426 for (i = msg; i < emsg; i++)
427 if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
428 {
429 pd_error(x, "netreceive: got dollar sign in message");
430 goto nodice;
431 }
432 if (at[msg].a_type == A_FLOAT)
433 {
434 if (emsg > msg + 1)
435 outlet_list(x->x_obj.ob_outlet, 0, emsg-msg, at + msg);
436 else outlet_float(x->x_obj.ob_outlet, at[msg].a_w.w_float);
437 }
438 else if (at[msg].a_type == A_SYMBOL)
439 outlet_anything(x->x_obj.ob_outlet, at[msg].a_w.w_symbol,
440 emsg-msg-1, at + msg + 1);
441 }
442 nodice:
443 msg = emsg + 1;
444 }
445}
446
447
448void shell_read(t_shell *x, int fd)
449{
450 char buf[INBUFSIZE];
451 t_binbuf* bbuf = binbuf_new();
452 int i;
453 int readto =
454 (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
455 int ret;
456
457 ret = read(fd, buf,INBUFSIZE-1);
458 buf[ret] = '\0';
459
460 for (i=0;i<ret;i++)
461 if (buf[i] == '\n') buf[i] = ';';
462 if (ret < 0)
463 {
464 error("shell: pipe read error");
465 sys_rmpollfn(fd);
466 x->fdpipe[0] = -1;
467 close(fd);
468 return;
469 }
470 else if (ret == 0)
471 {
472 post("EOF on socket %d\n", fd);
473 sys_rmpollfn(fd);
474 x->fdpipe[0] = -1;
475 close(fd);
476 return;
477 }
478 else
479 {
480 int natom;
481 t_atom *at;
482 binbuf_text(bbuf, buf, strlen(buf));
483
484 natom = binbuf_getnatom(bbuf);
485 at = binbuf_getvec(bbuf);
486 shell_doit(x,bbuf);
487 }
488 binbuf_free(bbuf);
489}
490
491
492static void shell_send(t_shell *x, t_symbol *s,int ac, t_atom *at)
493{
494 int i;
495 char tmp[MAXPDSTRING];
496 int size = 0;
497
498 if (x->fdinpipe[0] == -1) return; /* nothing to send to */
499
500 for (i=0;i<ac;i++) {
501 atom_string(at,tmp+size,MAXPDSTRING - size);
502 at++;
503 size=strlen(tmp);
504 tmp[size++] = ' ';
505 }
506 tmp[size-1] = '\0';
507 post("sending %s",tmp);
508 write(x->fdinpipe[0],tmp,strlen(tmp));
509}
510
511static void shell_anything(t_shell *x, t_symbol *s, int ac, t_atom *at)
512{
513 int i;
514 char* argv[20];
515 t_symbol* sym;
516
517 if (!strcmp(s->s_name,"send")) {
518 post("send");
519 shell_send(x,s,ac,at);
520 return;
521 }
522
523 argv[0] = s->s_name;
524
525 if (x->fdpipe[0] != -1) {
526 post("shell: old process still running");
527 kill(x->pid,SIGKILL);
528 shell_cleanup(x);
529 }
530
531
532 if (pipe(x->fdpipe) < 0) {
533 error("unable to create pipe");
534 return;
535 }
536
537 if (pipe(x->fdinpipe) < 0) {
538 error("unable to create input pipe");
539 return;
540 }
541
542
543 sys_addpollfn(x->fdpipe[0],shell_read,x);
544
545 if (!(x->pid = fork())) {
546 int status;
547 char* cmd = getbytes(1024);
548 char* tcmd = getbytes(1024);
549 strcpy(cmd,s->s_name);
550
551#if 0
552 for (i=1;i<=ac;i++) {
553 argv[i] = getbytes(255);
554 atom_string(at,argv[i],255);
555/* post("argument %s",argv[i]); */
556 at++;
557 }
558 argv[i] = 0;
559#endif
560 for (i=1;i<=ac;i++) {
561 atom_string(at,tcmd,255);
562 strcat(cmd," ");
563 strcat(cmd,tcmd);
564 at++;
565 }
566
567
568 /* reassign stdout */
569 dup2(x->fdpipe[1],1);
570 dup2(x->fdinpipe[1],0);
571
572 /* drop privileges */
573 drop_priority();
574 seteuid(getuid()); /* lose setuid priveliges */
575
576 post("executing %s",cmd);
577 system(cmd);
578// execvp(s->s_name,argv);
579 exit(0);
580 }
581 x->x_del = 4;
582 clock_delay(x->x_clock,x->x_del);
583
584 if (x->x_echo)
585 outlet_anything(x->x_obj.ob_outlet, s, ac, at);
586}
587
588
589
590void shell_free(t_shell* x)
591{
592 binbuf_free(x->x_binbuf);
593}
594
595static void *shell_new(void)
596{
597 t_shell *x = (t_shell *)pd_new(shell_class);
598
599 x->x_echo = 0;
600 x->fdpipe[0] = -1;
601 x->fdpipe[1] = -1;
602 x->fdinpipe[0] = -1;
603 x->fdinpipe[1] = -1;
604
605 x->sr_inhead = x->sr_intail = 0;
606 if (!(x->sr_inbuf = (char*) malloc(INBUFSIZE))) bug("t_shell");;
607
608 x->x_binbuf = binbuf_new();
609
610 outlet_new(&x->x_obj, &s_list);
611 x->x_done = outlet_new(&x->x_obj, &s_bang);
612 x->x_clock = clock_new(x, (t_method) shell_check);
613 return (x);
614}
615
616void shell_setup(void)
617{
618 shell_class = class_new(gensym("shell"), (t_newmethod)shell_new,
619 (t_method)shell_free,sizeof(t_shell), 0,0);
620 class_addbang(shell_class,shell_bang);
621 class_addanything(shell_class, shell_anything);
622}
623
624
diff --git a/apps/plugins/pdbox/PDa/extra/slider.c b/apps/plugins/pdbox/PDa/extra/slider.c
new file mode 100644
index 0000000000..4650050006
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/slider.c
@@ -0,0 +1,106 @@
1#include <stdio.h>
2#include "m_pd.h"
3#include "g_canvas.h" /* for widgetbehaviour */
4#include "fatom.h"
5
6static t_class *slider_class;
7
8static void slider_save(t_gobj *z, t_binbuf *b)
9{
10 t_fatom *x = (t_fatom *)z;
11
12 binbuf_addv(b, "ssiisiiisss", gensym("#X"),gensym("obj"),
13 x->x_obj.te_xpix, x->x_obj.te_ypix ,
14 gensym("slider"),x->x_max,x->x_min,x->x_width,x->x_send,x->x_color,x->x_bgcolor);
15 binbuf_addv(b, ";");
16}
17
18
19static void *slider_new(t_symbol* s,t_int argc, t_atom* argv)
20{
21 t_fatom *x = (t_fatom *)pd_new(slider_class);
22 x->x_type = gensym("vslider");
23 return fatom_new(x,argc,argv);
24}
25
26
27t_widgetbehavior slider_widgetbehavior;
28
29
30void slider_setup(void) {
31 slider_class = class_new(gensym("slider"), (t_newmethod)slider_new, 0,
32 sizeof(t_fatom),0,A_GIMME,0);
33
34 slider_widgetbehavior.w_getrectfn = fatom_getrect;
35 slider_widgetbehavior.w_displacefn = fatom_displace;
36 slider_widgetbehavior.w_selectfn = fatom_select;
37 slider_widgetbehavior.w_activatefn = fatom_activate;
38 slider_widgetbehavior.w_deletefn = fatom_delete;
39 slider_widgetbehavior.w_visfn= fatom_vis;
40 slider_widgetbehavior.w_clickfn = NULL;
41
42 fatom_setup_common(slider_class);
43 class_setwidget(slider_class,&slider_widgetbehavior);
44
45#if PD_MINOR_VERSION < 37
46 slider_widgetbehavior.w_savefn = slider_save;
47 slider_widgetbehavior.w_propertiesfn = NULL;
48#else
49 class_setsavefn(slider_class,&slider_save);
50 class_setpropertiesfn(slider_class,&fatom_properties);
51#endif
52
53}
54#include <stdio.h>
55#include "m_pd.h"
56#include "g_canvas.h" /* for widgetbehaviour */
57#include "fatom.h"
58
59static t_class *slider_class;
60
61static void slider_save(t_gobj *z, t_binbuf *b)
62{
63 t_fatom *x = (t_fatom *)z;
64
65 binbuf_addv(b, "ssiisiiisss", gensym("#X"),gensym("obj"),
66 x->x_obj.te_xpix, x->x_obj.te_ypix ,
67 gensym("slider"),x->x_max,x->x_min,x->x_width,x->x_send,x->x_color,x->x_bgcolor);
68 binbuf_addv(b, ";");
69}
70
71
72static void *slider_new(t_symbol* s,t_int argc, t_atom* argv)
73{
74 t_fatom *x = (t_fatom *)pd_new(slider_class);
75 x->x_type = gensym("vslider");
76 return fatom_new(x,argc,argv);
77}
78
79
80t_widgetbehavior slider_widgetbehavior;
81
82
83void slider_setup(void) {
84 slider_class = class_new(gensym("slider"), (t_newmethod)slider_new, 0,
85 sizeof(t_fatom),0,A_GIMME,0);
86
87 slider_widgetbehavior.w_getrectfn = fatom_getrect;
88 slider_widgetbehavior.w_displacefn = fatom_displace;
89 slider_widgetbehavior.w_selectfn = fatom_select;
90 slider_widgetbehavior.w_activatefn = fatom_activate;
91 slider_widgetbehavior.w_deletefn = fatom_delete;
92 slider_widgetbehavior.w_visfn= fatom_vis;
93 slider_widgetbehavior.w_clickfn = NULL;
94
95 fatom_setup_common(slider_class);
96 class_setwidget(slider_class,&slider_widgetbehavior);
97
98#if PD_MINOR_VERSION < 37
99 slider_widgetbehavior.w_savefn = slider_save;
100 slider_widgetbehavior.w_propertiesfn = NULL;
101#else
102 class_setsavefn(slider_class,&slider_save);
103 class_setpropertiesfn(slider_class,&fatom_properties);
104#endif
105
106}
diff --git a/apps/plugins/pdbox/PDa/extra/sliderh.c b/apps/plugins/pdbox/PDa/extra/sliderh.c
new file mode 100644
index 0000000000..23a6d256e0
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/sliderh.c
@@ -0,0 +1,126 @@
1#include "m_pd.h"
2#include "g_canvas.h"
3
4
5#ifdef NT
6#pragma warning( disable : 4244 )
7#pragma warning( disable : 4305 )
8#endif
9
10#include "fatom.h"
11
12/* can we use the normal text save function ?? */
13
14static t_class *sliderh_class;
15
16static void sliderh_save(t_gobj *z, t_binbuf *b)
17{
18
19 t_fatom *x = (t_fatom *)z;
20
21 binbuf_addv(b, "ssiisiiisss", gensym("#X"),gensym("obj"),
22 x->x_obj.te_xpix, x->x_obj.te_ypix ,
23 gensym("sliderh"),x->x_max,x->x_min,x->x_width,x->x_send,x->x_color,x->x_bgcolor);
24 binbuf_addv(b, ";");
25}
26
27
28static void *sliderh_new(t_symbol* s, int argc, t_atom* argv)
29{
30 t_fatom *x = (t_fatom *)pd_new(sliderh_class);
31 x->x_type = gensym("hslider");
32 return fatom_new(x,argc,argv);
33}
34
35
36t_widgetbehavior sliderh_widgetbehavior;
37
38
39
40
41void sliderh_setup(void) {
42 sliderh_class = class_new(gensym("sliderh"), (t_newmethod)sliderh_new, 0,
43 sizeof(t_fatom),0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
44
45 fatom_setup_common(sliderh_class);
46
47 sliderh_widgetbehavior.w_getrectfn = fatom_getrect;
48 sliderh_widgetbehavior.w_displacefn= fatom_displace;
49 sliderh_widgetbehavior.w_selectfn= fatom_select;
50 sliderh_widgetbehavior.w_activatefn=fatom_activate;
51 sliderh_widgetbehavior.w_deletefn= fatom_delete;
52 sliderh_widgetbehavior.w_visfn= fatom_vis;
53#if PD_MINOR_VERSION < 37
54 sliderh_widgetbehavior.w_savefn= sliderh_save;
55 sliderh_widgetbehavior.w_propertiesfn= NULL;
56#endif
57 sliderh_widgetbehavior.w_clickfn= NULL;
58
59 class_setwidget(sliderh_class,&sliderh_widgetbehavior);
60#if PD_MINOR_VERSION >= 37
61 class_setsavefn(sliderh_class,&sliderh_save);
62#endif
63}
64#include "m_pd.h"
65#include "g_canvas.h"
66
67
68#ifdef NT
69#pragma warning( disable : 4244 )
70#pragma warning( disable : 4305 )
71#endif
72
73#include "fatom.h"
74
75/* can we use the normal text save function ?? */
76
77static t_class *sliderh_class;
78
79static void sliderh_save(t_gobj *z, t_binbuf *b)
80{
81
82 t_fatom *x = (t_fatom *)z;
83
84 binbuf_addv(b, "ssiisiiisss", gensym("#X"),gensym("obj"),
85 x->x_obj.te_xpix, x->x_obj.te_ypix ,
86 gensym("sliderh"),x->x_max,x->x_min,x->x_width,x->x_send,x->x_color,x->x_bgcolor);
87 binbuf_addv(b, ";");
88}
89
90
91static void *sliderh_new(t_symbol* s, int argc, t_atom* argv)
92{
93 t_fatom *x = (t_fatom *)pd_new(sliderh_class);
94 x->x_type = gensym("hslider");
95 return fatom_new(x,argc,argv);
96}
97
98
99t_widgetbehavior sliderh_widgetbehavior;
100
101
102
103
104void sliderh_setup(void) {
105 sliderh_class = class_new(gensym("sliderh"), (t_newmethod)sliderh_new, 0,
106 sizeof(t_fatom),0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
107
108 fatom_setup_common(sliderh_class);
109
110 sliderh_widgetbehavior.w_getrectfn = fatom_getrect;
111 sliderh_widgetbehavior.w_displacefn= fatom_displace;
112 sliderh_widgetbehavior.w_selectfn= fatom_select;
113 sliderh_widgetbehavior.w_activatefn=fatom_activate;
114 sliderh_widgetbehavior.w_deletefn= fatom_delete;
115 sliderh_widgetbehavior.w_visfn= fatom_vis;
116#if PD_MINOR_VERSION < 37
117 sliderh_widgetbehavior.w_savefn= sliderh_save;
118 sliderh_widgetbehavior.w_propertiesfn= NULL;
119#endif
120 sliderh_widgetbehavior.w_clickfn= NULL;
121
122 class_setwidget(sliderh_class,&sliderh_widgetbehavior);
123#if PD_MINOR_VERSION >= 37
124 class_setsavefn(sliderh_class,&sliderh_save);
125#endif
126}
diff --git a/apps/plugins/pdbox/PDa/extra/test-clip.pd b/apps/plugins/pdbox/PDa/extra/test-clip.pd
new file mode 100644
index 0000000000..c682e31845
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/test-clip.pd
@@ -0,0 +1,26 @@
1#N canvas 0 0 240 300 10;
2#X obj 57 84 clip~ -0.1 0.1;
3#X obj 58 61 sig~;
4#X obj 57 111 snapshot~;
5#X floatatom 58 19 5 0 0 0 - - -;
6#X floatatom 57 144 5 0 0 0 - - -;
7#X obj 58 37 t f b;
8#X connect 0 0 2 0;
9#X connect 1 0 0 0;
10#X connect 2 0 4 0;
11#X connect 3 0 5 0;
12#X connect 5 0 1 0;
13#X connect 5 1 2 0;
14#N canvas 0 0 240 300 10;
15#X obj 57 84 clip~ -0.1 0.1;
16#X obj 58 61 sig~;
17#X obj 57 111 snapshot~;
18#X floatatom 58 19 5 0 0 0 - - -;
19#X floatatom 57 144 5 0 0 0 - - -;
20#X obj 58 37 t f b;
21#X connect 0 0 2 0;
22#X connect 1 0 0 0;
23#X connect 2 0 4 0;
24#X connect 3 0 5 0;
25#X connect 5 0 1 0;
26#X connect 5 1 2 0;
diff --git a/apps/plugins/pdbox/PDa/extra/test-vcf.pd b/apps/plugins/pdbox/PDa/extra/test-vcf.pd
new file mode 100644
index 0000000000..099d3d7958
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/test-vcf.pd
@@ -0,0 +1,36 @@
1#N canvas 0 0 240 300 10;
2#X obj 38 93 noise~;
3#X obj 44 161 vcf~;
4#X obj 48 191 dac~;
5#X floatatom 138 33 5 0 0 0 - - -;
6#X obj 44 18 osc~ 1;
7#X obj 46 75 *~ 800;
8#X obj 48 48 +~ 2;
9#X obj 106 125 sig~;
10#X floatatom 132 77 5 0 0 0 - - -;
11#X connect 0 0 1 0;
12#X connect 1 0 2 0;
13#X connect 1 0 2 1;
14#X connect 3 0 1 2;
15#X connect 4 0 6 0;
16#X connect 6 0 5 0;
17#X connect 7 0 1 1;
18#X connect 8 0 7 0;
19#N canvas 0 0 240 300 10;
20#X obj 38 93 noise~;
21#X obj 44 161 vcf~;
22#X obj 48 191 dac~;
23#X floatatom 138 33 5 0 0 0 - - -;
24#X obj 44 18 osc~ 1;
25#X obj 46 75 *~ 800;
26#X obj 48 48 +~ 2;
27#X obj 106 125 sig~;
28#X floatatom 132 77 5 0 0 0 - - -;
29#X connect 0 0 1 0;
30#X connect 1 0 2 0;
31#X connect 1 0 2 1;
32#X connect 3 0 1 2;
33#X connect 4 0 6 0;
34#X connect 6 0 5 0;
35#X connect 7 0 1 1;
36#X connect 8 0 7 0;
diff --git a/apps/plugins/pdbox/PDa/extra/zerox~.c b/apps/plugins/pdbox/PDa/extra/zerox~.c
new file mode 100644
index 0000000000..f97f412308
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/extra/zerox~.c
@@ -0,0 +1,114 @@
1#include "m_pd.h"
2
3static t_class *zerox_class;
4
5typedef struct _zerox
6{
7 t_object x_obj;
8 t_sample x_f;
9 t_int x_zeros;
10} t_zerox;
11
12
13static t_int *zerox_perform(t_int *w)
14{
15 t_zerox* x = (t_zerox*)w[1];
16 t_sample *in = (t_sample *)(w[2]);
17 int n = (int)(w[3]) ;
18
19 if (*in * x->x_f < 0) x->x_zeros++;
20 n--;
21 while (n--)
22 {
23 float f = *(in++);
24 x->x_zeros += f * *in < 0;
25 }
26 return (w+4);
27}
28
29static void zerox_dsp(t_zerox *x, t_signal **sp)
30{
31 dsp_add(zerox_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
32}
33
34
35static void zerox_bang(t_zerox* x)
36{
37 outlet_float(x->x_obj.ob_outlet,x->x_zeros);
38 x->x_zeros=0;
39}
40
41static void *zerox_new(void)
42{
43 t_zerox *x = (t_zerox *)pd_new(zerox_class);
44 outlet_new(&x->x_obj, gensym("float"));
45 x->x_f = 0;
46 x->x_zeros=0;
47 return (x);
48}
49
50void zerox_tilde_setup(void)
51{
52 zerox_class = class_new(gensym("zerox~"), (t_newmethod)zerox_new, 0,
53 sizeof(t_zerox), 0, A_DEFFLOAT, 0);
54 CLASS_MAINSIGNALIN(zerox_class, t_zerox, x_f);
55 class_addmethod(zerox_class, (t_method)zerox_dsp, gensym("dsp"), 0);
56 class_addbang(zerox_class, (t_method)zerox_bang);
57}
58#include "m_pd.h"
59
60static t_class *zerox_class;
61
62typedef struct _zerox
63{
64 t_object x_obj;
65 t_sample x_f;
66 t_int x_zeros;
67} t_zerox;
68
69
70static t_int *zerox_perform(t_int *w)
71{
72 t_zerox* x = (t_zerox*)w[1];
73 t_sample *in = (t_sample *)(w[2]);
74 int n = (int)(w[3]) ;
75
76 if (*in * x->x_f < 0) x->x_zeros++;
77 n--;
78 while (n--)
79 {
80 float f = *(in++);
81 x->x_zeros += f * *in < 0;
82 }
83 return (w+4);
84}
85
86static void zerox_dsp(t_zerox *x, t_signal **sp)
87{
88 dsp_add(zerox_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
89}
90
91
92static void zerox_bang(t_zerox* x)
93{
94 outlet_float(x->x_obj.ob_outlet,x->x_zeros);
95 x->x_zeros=0;
96}
97
98static void *zerox_new(void)
99{
100 t_zerox *x = (t_zerox *)pd_new(zerox_class);
101 outlet_new(&x->x_obj, gensym("float"));
102 x->x_f = 0;
103 x->x_zeros=0;
104 return (x);
105}
106
107void zerox_tilde_setup(void)
108{
109 zerox_class = class_new(gensym("zerox~"), (t_newmethod)zerox_new, 0,
110 sizeof(t_zerox), 0, A_DEFFLOAT, 0);
111 CLASS_MAINSIGNALIN(zerox_class, t_zerox, x_f);
112 class_addmethod(zerox_class, (t_method)zerox_dsp, gensym("dsp"), 0);
113 class_addbang(zerox_class, (t_method)zerox_bang);
114}
diff --git a/apps/plugins/pdbox/PDa/intern/biquad~.c b/apps/plugins/pdbox/PDa/intern/biquad~.c
new file mode 100644
index 0000000000..c37182a911
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/biquad~.c
@@ -0,0 +1,252 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4typedef struct biquadctl
5{
6 t_sample c_x1;
7 t_sample c_x2;
8 t_sample c_fb1;
9 t_sample c_fb2;
10 t_sample c_ff1;
11 t_sample c_ff2;
12 t_sample c_ff3;
13} t_biquadctl;
14
15typedef struct sigbiquad
16{
17 t_object x_obj;
18 float x_f;
19 t_biquadctl x_cspace;
20 t_biquadctl *x_ctl;
21} t_sigbiquad;
22
23t_class *sigbiquad_class;
24
25static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
26
27static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv)
28{
29 t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
30 outlet_new(&x->x_obj, gensym("signal"));
31 x->x_ctl = &x->x_cspace;
32 x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0;
33 sigbiquad_list(x, s, argc, argv);
34 x->x_f = 0;
35 return (x);
36}
37
38static t_int *sigbiquad_perform(t_int *w)
39{
40 t_sample *in = (t_sample *)(w[1]);
41 t_sample *out = (t_sample *)(w[2]);
42 t_biquadctl *c = (t_biquadctl *)(w[3]);
43 int n = (t_int)(w[4]);
44 int i;
45 t_sample last = c->c_x1;
46 t_sample prev = c->c_x2;
47 t_sample fb1 = c->c_fb1;
48 t_sample fb2 = c->c_fb2;
49 t_sample ff1 = c->c_ff1;
50 t_sample ff2 = c->c_ff2;
51 t_sample ff3 = c->c_ff3;
52 for (i = 0; i < n; i++)
53 {
54 t_sample output = *in++ + mult(fb1,last) + mult(fb2,prev);
55 if (PD_BADFLOAT(output))
56 output = 0;
57 *out++ = mult(ff1,output) + mult(ff2,last) + mult(ff3,prev);
58 prev = last;
59 last = output;
60 }
61 c->c_x1 = last;
62 c->c_x2 = prev;
63 return (w+5);
64}
65
66static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
67{
68 float fb1 = atom_getfloatarg(0, argc, argv);
69 float fb2 = atom_getfloatarg(1, argc, argv);
70 float ff1 = atom_getfloatarg(2, argc, argv);
71 float ff2 = atom_getfloatarg(3, argc, argv);
72 float ff3 = atom_getfloatarg(4, argc, argv);
73 float discriminant = fb1 * fb1 + 4 * fb2;
74 t_biquadctl *c = x->x_ctl;
75 if (discriminant < 0) /* imaginary roots -- resonant filter */
76 {
77 /* they're conjugates so we just check that the product
78 is less than one */
79 if (fb2 >= -1.0f) goto stable;
80 }
81 else /* real roots */
82 {
83 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
84 vertex between -1 and 1, and that it's nonnegative
85 at both ends, which implies both roots are in [1-,1]. */
86 if (fb1 <= 2.0f && fb1 >= -2.0f &&
87 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
88 goto stable;
89 }
90 /* if unstable, just bash to zero */
91 fb1 = fb2 = ff1 = ff2 = ff3 = 0;
92stable:
93 c->c_fb1 = ftofix(fb1);
94 c->c_fb2 = ftofix(fb2);
95 c->c_ff1 = ftofix(ff1);
96 c->c_ff2 = ftofix(ff2);
97 c->c_ff3 = ftofix(ff3);
98}
99
100static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
101{
102 t_biquadctl *c = x->x_ctl;
103 c->c_x1 = atom_getfloatarg(0, argc, argv);
104 c->c_x2 = atom_getfloatarg(1, argc, argv);
105}
106
107static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp)
108{
109 dsp_add(sigbiquad_perform, 4,
110 sp[0]->s_vec, sp[1]->s_vec,
111 x->x_ctl, sp[0]->s_n);
112
113}
114
115void biquad_tilde_setup(void)
116{
117 sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new,
118 0, sizeof(t_sigbiquad), 0, A_GIMME, 0);
119 CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f);
120 class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0);
121 class_addlist(sigbiquad_class, sigbiquad_list);
122 class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"),
123 A_GIMME, 0);
124 class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"),
125 A_GIMME, 0);
126}
127#include <m_pd.h>
128#include <m_fixed.h>
129
130typedef struct biquadctl
131{
132 t_sample c_x1;
133 t_sample c_x2;
134 t_sample c_fb1;
135 t_sample c_fb2;
136 t_sample c_ff1;
137 t_sample c_ff2;
138 t_sample c_ff3;
139} t_biquadctl;
140
141typedef struct sigbiquad
142{
143 t_object x_obj;
144 float x_f;
145 t_biquadctl x_cspace;
146 t_biquadctl *x_ctl;
147} t_sigbiquad;
148
149t_class *sigbiquad_class;
150
151static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
152
153static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv)
154{
155 t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
156 outlet_new(&x->x_obj, gensym("signal"));
157 x->x_ctl = &x->x_cspace;
158 x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0;
159 sigbiquad_list(x, s, argc, argv);
160 x->x_f = 0;
161 return (x);
162}
163
164static t_int *sigbiquad_perform(t_int *w)
165{
166 t_sample *in = (t_sample *)(w[1]);
167 t_sample *out = (t_sample *)(w[2]);
168 t_biquadctl *c = (t_biquadctl *)(w[3]);
169 int n = (t_int)(w[4]);
170 int i;
171 t_sample last = c->c_x1;
172 t_sample prev = c->c_x2;
173 t_sample fb1 = c->c_fb1;
174 t_sample fb2 = c->c_fb2;
175 t_sample ff1 = c->c_ff1;
176 t_sample ff2 = c->c_ff2;
177 t_sample ff3 = c->c_ff3;
178 for (i = 0; i < n; i++)
179 {
180 t_sample output = *in++ + mult(fb1,last) + mult(fb2,prev);
181 if (PD_BADFLOAT(output))
182 output = 0;
183 *out++ = mult(ff1,output) + mult(ff2,last) + mult(ff3,prev);
184 prev = last;
185 last = output;
186 }
187 c->c_x1 = last;
188 c->c_x2 = prev;
189 return (w+5);
190}
191
192static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
193{
194 float fb1 = atom_getfloatarg(0, argc, argv);
195 float fb2 = atom_getfloatarg(1, argc, argv);
196 float ff1 = atom_getfloatarg(2, argc, argv);
197 float ff2 = atom_getfloatarg(3, argc, argv);
198 float ff3 = atom_getfloatarg(4, argc, argv);
199 float discriminant = fb1 * fb1 + 4 * fb2;
200 t_biquadctl *c = x->x_ctl;
201 if (discriminant < 0) /* imaginary roots -- resonant filter */
202 {
203 /* they're conjugates so we just check that the product
204 is less than one */
205 if (fb2 >= -1.0f) goto stable;
206 }
207 else /* real roots */
208 {
209 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
210 vertex between -1 and 1, and that it's nonnegative
211 at both ends, which implies both roots are in [1-,1]. */
212 if (fb1 <= 2.0f && fb1 >= -2.0f &&
213 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
214 goto stable;
215 }
216 /* if unstable, just bash to zero */
217 fb1 = fb2 = ff1 = ff2 = ff3 = 0;
218stable:
219 c->c_fb1 = ftofix(fb1);
220 c->c_fb2 = ftofix(fb2);
221 c->c_ff1 = ftofix(ff1);
222 c->c_ff2 = ftofix(ff2);
223 c->c_ff3 = ftofix(ff3);
224}
225
226static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
227{
228 t_biquadctl *c = x->x_ctl;
229 c->c_x1 = atom_getfloatarg(0, argc, argv);
230 c->c_x2 = atom_getfloatarg(1, argc, argv);
231}
232
233static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp)
234{
235 dsp_add(sigbiquad_perform, 4,
236 sp[0]->s_vec, sp[1]->s_vec,
237 x->x_ctl, sp[0]->s_n);
238
239}
240
241void biquad_tilde_setup(void)
242{
243 sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new,
244 0, sizeof(t_sigbiquad), 0, A_GIMME, 0);
245 CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f);
246 class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0);
247 class_addlist(sigbiquad_class, sigbiquad_list);
248 class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"),
249 A_GIMME, 0);
250 class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"),
251 A_GIMME, 0);
252}
diff --git a/apps/plugins/pdbox/PDa/intern/bp~.c b/apps/plugins/pdbox/PDa/intern/bp~.c
new file mode 100644
index 0000000000..f247c1d66b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/bp~.c
@@ -0,0 +1,276 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4typedef struct bpctl
5{
6 t_sample c_x1;
7 t_sample c_x2;
8 t_sample c_coef1;
9 t_sample c_coef2;
10 t_sample c_gain;
11} t_bpctl;
12
13typedef struct sigbp
14{
15 t_object x_obj;
16 float x_sr;
17 float x_freq;
18 float x_q;
19 t_bpctl x_cspace;
20 t_bpctl *x_ctl;
21 float x_f;
22} t_sigbp;
23
24t_class *sigbp_class;
25
26static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
27
28static void *sigbp_new(t_floatarg f, t_floatarg q)
29{
30 t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
31 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
32 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2"));
33 outlet_new(&x->x_obj, gensym("signal"));
34 x->x_sr = 44100;
35 x->x_ctl = &x->x_cspace;
36 x->x_cspace.c_x1 = 0;
37 x->x_cspace.c_x2 = 0;
38 sigbp_docoef(x, f, q);
39 x->x_f = 0;
40 return (x);
41}
42
43static float sigbp_qcos(float f)
44{
45 if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f)
46 {
47 float g = f*f;
48 return (((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1);
49 }
50 else return (0);
51}
52
53static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q)
54{
55 float r, oneminusr, omega;
56 if (f < 0.001) f = 10;
57 if (q < 0) q = 0;
58 x->x_freq = f;
59 x->x_q = q;
60 omega = f * (2.0f * 3.14159f) / x->x_sr;
61 if (q < 0.001) oneminusr = 1.0f;
62 else oneminusr = omega/q;
63 if (oneminusr > 1.0f) oneminusr = 1.0f;
64 r = 1.0f - oneminusr;
65 x->x_ctl->c_coef1 = ftofix(2.0f * sigbp_qcos(omega) * r);
66 x->x_ctl->c_coef2 = ftofix(- r * r);
67 x->x_ctl->c_gain = ftofix(2 * oneminusr * (oneminusr + r * omega));
68 /* post("r %f, omega %f, coef1 %f, coef2 %f",
69 r, omega, x->x_ctl->c_coef1, x->x_ctl->c_coef2); */
70}
71
72static void sigbp_ft1(t_sigbp *x, t_floatarg f)
73{
74 sigbp_docoef(x, f, x->x_q);
75}
76
77static void sigbp_ft2(t_sigbp *x, t_floatarg q)
78{
79 sigbp_docoef(x, x->x_freq, q);
80}
81
82static void sigbp_clear(t_sigbp *x, t_floatarg q)
83{
84 x->x_ctl->c_x1 = x->x_ctl->c_x2 = 0;
85}
86
87static t_int *sigbp_perform(t_int *w)
88{
89 t_sample *in = (t_sample *)(w[1]);
90 t_sample *out = (t_sample *)(w[2]);
91 t_bpctl *c = (t_bpctl *)(w[3]);
92 int n = (t_int)(w[4]);
93 int i;
94 t_sample last = c->c_x1;
95 t_sample prev = c->c_x2;
96 t_sample coef1 = c->c_coef1;
97 t_sample coef2 = c->c_coef2;
98 t_sample gain = c->c_gain;
99 for (i = 0; i < n; i++)
100 {
101 t_sample output = *in++ + mult(coef1,last) + mult(coef2,prev);
102 *out++ = mult(gain,output);
103 prev = last;
104 last = output;
105 }
106 if (PD_BADFLOAT(last))
107 last = 0;
108 if (PD_BADFLOAT(prev))
109 prev = 0;
110 c->c_x1 = last;
111 c->c_x2 = prev;
112 return (w+5);
113}
114
115static void sigbp_dsp(t_sigbp *x, t_signal **sp)
116{
117 x->x_sr = sp[0]->s_sr;
118 sigbp_docoef(x, x->x_freq, x->x_q);
119 dsp_add(sigbp_perform, 4,
120 sp[0]->s_vec, sp[1]->s_vec,
121 x->x_ctl, sp[0]->s_n);
122
123}
124
125void bp_tilde_setup(void)
126{
127 sigbp_class = class_new(gensym("bp~"), (t_newmethod)sigbp_new, 0,
128 sizeof(t_sigbp), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
129 CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, x_f);
130 class_addmethod(sigbp_class, (t_method)sigbp_dsp, gensym("dsp"), 0);
131 class_addmethod(sigbp_class, (t_method)sigbp_ft1,
132 gensym("ft1"), A_FLOAT, 0);
133 class_addmethod(sigbp_class, (t_method)sigbp_ft2,
134 gensym("ft2"), A_FLOAT, 0);
135 class_addmethod(sigbp_class, (t_method)sigbp_clear, gensym("clear"), 0);
136 class_sethelpsymbol(sigbp_class, gensym("lop~-help.pd"));
137}
138
139#include <m_pd.h>
140#include <m_fixed.h>
141
142typedef struct bpctl
143{
144 t_sample c_x1;
145 t_sample c_x2;
146 t_sample c_coef1;
147 t_sample c_coef2;
148 t_sample c_gain;
149} t_bpctl;
150
151typedef struct sigbp
152{
153 t_object x_obj;
154 float x_sr;
155 float x_freq;
156 float x_q;
157 t_bpctl x_cspace;
158 t_bpctl *x_ctl;
159 float x_f;
160} t_sigbp;
161
162t_class *sigbp_class;
163
164static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
165
166static void *sigbp_new(t_floatarg f, t_floatarg q)
167{
168 t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
169 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
170 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2"));
171 outlet_new(&x->x_obj, gensym("signal"));
172 x->x_sr = 44100;
173 x->x_ctl = &x->x_cspace;
174 x->x_cspace.c_x1 = 0;
175 x->x_cspace.c_x2 = 0;
176 sigbp_docoef(x, f, q);
177 x->x_f = 0;
178 return (x);
179}
180
181static float sigbp_qcos(float f)
182{
183 if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f)
184 {
185 float g = f*f;
186 return (((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1);
187 }
188 else return (0);
189}
190
191static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q)
192{
193 float r, oneminusr, omega;
194 if (f < 0.001) f = 10;
195 if (q < 0) q = 0;
196 x->x_freq = f;
197 x->x_q = q;
198 omega = f * (2.0f * 3.14159f) / x->x_sr;
199 if (q < 0.001) oneminusr = 1.0f;
200 else oneminusr = omega/q;
201 if (oneminusr > 1.0f) oneminusr = 1.0f;
202 r = 1.0f - oneminusr;
203 x->x_ctl->c_coef1 = ftofix(2.0f * sigbp_qcos(omega) * r);
204 x->x_ctl->c_coef2 = ftofix(- r * r);
205 x->x_ctl->c_gain = ftofix(2 * oneminusr * (oneminusr + r * omega));
206 /* post("r %f, omega %f, coef1 %f, coef2 %f",
207 r, omega, x->x_ctl->c_coef1, x->x_ctl->c_coef2); */
208}
209
210static void sigbp_ft1(t_sigbp *x, t_floatarg f)
211{
212 sigbp_docoef(x, f, x->x_q);
213}
214
215static void sigbp_ft2(t_sigbp *x, t_floatarg q)
216{
217 sigbp_docoef(x, x->x_freq, q);
218}
219
220static void sigbp_clear(t_sigbp *x, t_floatarg q)
221{
222 x->x_ctl->c_x1 = x->x_ctl->c_x2 = 0;
223}
224
225static t_int *sigbp_perform(t_int *w)
226{
227 t_sample *in = (t_sample *)(w[1]);
228 t_sample *out = (t_sample *)(w[2]);
229 t_bpctl *c = (t_bpctl *)(w[3]);
230 int n = (t_int)(w[4]);
231 int i;
232 t_sample last = c->c_x1;
233 t_sample prev = c->c_x2;
234 t_sample coef1 = c->c_coef1;
235 t_sample coef2 = c->c_coef2;
236 t_sample gain = c->c_gain;
237 for (i = 0; i < n; i++)
238 {
239 t_sample output = *in++ + mult(coef1,last) + mult(coef2,prev);
240 *out++ = mult(gain,output);
241 prev = last;
242 last = output;
243 }
244 if (PD_BADFLOAT(last))
245 last = 0;
246 if (PD_BADFLOAT(prev))
247 prev = 0;
248 c->c_x1 = last;
249 c->c_x2 = prev;
250 return (w+5);
251}
252
253static void sigbp_dsp(t_sigbp *x, t_signal **sp)
254{
255 x->x_sr = sp[0]->s_sr;
256 sigbp_docoef(x, x->x_freq, x->x_q);
257 dsp_add(sigbp_perform, 4,
258 sp[0]->s_vec, sp[1]->s_vec,
259 x->x_ctl, sp[0]->s_n);
260
261}
262
263void bp_tilde_setup(void)
264{
265 sigbp_class = class_new(gensym("bp~"), (t_newmethod)sigbp_new, 0,
266 sizeof(t_sigbp), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
267 CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, x_f);
268 class_addmethod(sigbp_class, (t_method)sigbp_dsp, gensym("dsp"), 0);
269 class_addmethod(sigbp_class, (t_method)sigbp_ft1,
270 gensym("ft1"), A_FLOAT, 0);
271 class_addmethod(sigbp_class, (t_method)sigbp_ft2,
272 gensym("ft2"), A_FLOAT, 0);
273 class_addmethod(sigbp_class, (t_method)sigbp_clear, gensym("clear"), 0);
274 class_sethelpsymbol(sigbp_class, gensym("lop~-help.pd"));
275}
276
diff --git a/apps/plugins/pdbox/PDa/intern/clip~.c b/apps/plugins/pdbox/PDa/intern/clip~.c
new file mode 100644
index 0000000000..e2c697d1d8
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/clip~.c
@@ -0,0 +1,116 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4static t_class *clip_class;
5
6typedef struct _clip
7{
8 t_object x_obj;
9 float x_f;
10 t_float x_lo;
11 t_float x_hi;
12} t_clip;
13
14static void *clip_new(t_floatarg lo, t_floatarg hi)
15{
16 t_clip *x = (t_clip *)pd_new(clip_class);
17 x->x_lo = lo;
18 x->x_hi = hi;
19 outlet_new(&x->x_obj, gensym("signal"));
20 floatinlet_new(&x->x_obj, &x->x_lo);
21 floatinlet_new(&x->x_obj, &x->x_hi);
22 x->x_f = 0;
23 return (x);
24}
25
26static t_int *clip_perform(t_int *w)
27{
28 t_clip *x = (t_clip *)(w[1]);
29 t_sample *in = (t_sample *)(w[2]);
30 t_sample *out = (t_sample *)(w[3]);
31 int n = (int)(w[4]);
32 t_sample lo;
33 t_sample hi;
34 lo = ftofix(x->x_lo);
35 hi = ftofix(x->x_hi);
36
37 while (n--)
38 {
39 t_sample f = *in++;
40 if (f < lo) f = lo;
41 if (f > hi) f = hi;
42 *out++ = f;
43 }
44 return (w+5);
45}
46
47static void clip_dsp(t_clip *x, t_signal **sp)
48{
49 dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
50}
51
52void clip_tilde_setup(void)
53{
54 clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0,
55 sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
56 CLASS_MAINSIGNALIN(clip_class, t_clip, x_f);
57 class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), 0);
58}
59#include <m_pd.h>
60#include <m_fixed.h>
61
62static t_class *clip_class;
63
64typedef struct _clip
65{
66 t_object x_obj;
67 float x_f;
68 t_float x_lo;
69 t_float x_hi;
70} t_clip;
71
72static void *clip_new(t_floatarg lo, t_floatarg hi)
73{
74 t_clip *x = (t_clip *)pd_new(clip_class);
75 x->x_lo = lo;
76 x->x_hi = hi;
77 outlet_new(&x->x_obj, gensym("signal"));
78 floatinlet_new(&x->x_obj, &x->x_lo);
79 floatinlet_new(&x->x_obj, &x->x_hi);
80 x->x_f = 0;
81 return (x);
82}
83
84static t_int *clip_perform(t_int *w)
85{
86 t_clip *x = (t_clip *)(w[1]);
87 t_sample *in = (t_sample *)(w[2]);
88 t_sample *out = (t_sample *)(w[3]);
89 int n = (int)(w[4]);
90 t_sample lo;
91 t_sample hi;
92 lo = ftofix(x->x_lo);
93 hi = ftofix(x->x_hi);
94
95 while (n--)
96 {
97 t_sample f = *in++;
98 if (f < lo) f = lo;
99 if (f > hi) f = hi;
100 *out++ = f;
101 }
102 return (w+5);
103}
104
105static void clip_dsp(t_clip *x, t_signal **sp)
106{
107 dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
108}
109
110void clip_tilde_setup(void)
111{
112 clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0,
113 sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
114 CLASS_MAINSIGNALIN(clip_class, t_clip, x_f);
115 class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), 0);
116}
diff --git a/apps/plugins/pdbox/PDa/intern/cos_table.h b/apps/plugins/pdbox/PDa/intern/cos_table.h
new file mode 100644
index 0000000000..b30bb4245b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/cos_table.h
@@ -0,0 +1,6 @@
1#define ILOGCOSTABSIZE 15
2#define ICOSTABSIZE (1<<ILOGCOSTABSIZE)
3static t_sample cos_table[] = {262144,262144,262144,262144,262144,262144,262144,262144,262144,262144,262144,262143,262143,262143,262143,262143,262143,262143,262142,262142,262142,262142,262142,262141,262141,262141,262141,262140,262140,262140,262140,262139,262139,262139,262138,262138,262138,262137,262137,262137,262136,262136,262135,262135,262135,262134,262134,262133,262133,262132,262132,262131,262131,262130,262130,262129,262129,262128,262128,262127,262127,262126,262125,262125,262124,262124,262123,262122,262122,262121,262120,262120,262119,262118,262118,262117,262116,262115,262115,262114,262113,262112,262112,262111,262110,262109,262108,262108,262107,262106,262105,262104,262103,262102,262101,262101,262100,262099,262098,262097,262096,262095,262094,262093,262092,262091,262090,262089,262088,262087,262086,262085,262084,262082,262081,262080,262079,262078,262077,262076,262075,262073,262072,262071,262070,262069,262067,262066,262065,262064,262063,262061,262060,262059,262057,262056,262055,262054,262052,262051,262050,262048,262047,262045,262044,262043,262041,262040,262038,262037,262036,262034,262033,262031,262030,262028,262027,262025,262024,262022,262021,262019,262018,262016,262014,262013,262011,262010,262008,262006,262005,262003,262001,262000,261998,261996,261995,261993,261991,261990,261988,261986,261984,261983,261981,261979,261977,261975,261974,261972,261970,261968,261966,261965,261963,261961,261959,261957,261955,261953,261951,261949,261947,261945,261943,261942,261940,261938,261936,261934,261932,261929,261927,261925,261923,261921,261919,261917,261915,261913,261911,261909,261907,261904,261902,261900,261898,261896,261894,261891,261889,261887,261885,261882,261880,261878,261876,261873,261871,261869,261866,261864,261862,261859,261857,261855,261852,261850,261848,261845,261843,261840,261838,261836,261833,261831,261828,261826,261823,261821,261818,261816,261813,261811,261808,261806,261803,261801,261798,261795,261793,261790,261788,261785,261782,261780,261777,261774,261772,261769,261766,261764,261761,261758,261755,261753,261750,261747,261744,261742,261739,261736,261733,261730,261728,261725,261722,261719,261716,261713,261710,261708,261705,261702,261699,261696,261693,261690,261687,261684,261681,261678,261675,261672,261669,261666,261663,261660,261657,261654,261651,261648,261644,261641,261638,261635,261632,261629,261626,261623,261619,261616,261613,261610,261607,261603,261600,261597,261594,261590,261587,261584,261581,261577,261574,261571,261567,261564,261561,261557,261554,261551,261547,261544,261540,261537,261533,261530,261527,261523,261520,261516,261513,261509,261506,261502,261499,261495,261492,261488,261485,261481,261477,261474,261470,261467,261463,261459,261456,261452,261448,261445,261441,261437,261434,261430,261426,261423,261419,261415,261411,261408,261404,261400,261396,261392,261389,261385,261381,261377,261373,261369,261366,261362,261358,261354,261350,261346,261342,261338,261334,261330,261326,261322,261318,261314,261310,261306,261302,261298,261294,261290,261286,261282,261278,261274,261270,261266,261262,261258,261253,261249,261245,261241,261237,261233,261228,261224,261220,261216,261212,261207,261203,261199,261195,261190,261186,261182,261177,261173,261169,261164,261160,261156,261151,261147,261143,261138,261134,261129,261125,261120,261116,261112,261107,261103,261098,261094,261089,261085,261080,261076,261071,261067,261062,261057,261053,261048,261044,261039,261034,261030,261025,261021,261016,261011,261007,261002,260997,260992,260988,260983,260978,260974,260969,260964,260959,260955,260950,260945,260940,260935,260930,260926,260921,260916,260911,260906,260901,260896,260892,260887,260882,260877,260872,260867,260862,260857,260852,260847,260842,260837,260832,260827,260822,260817,260812,260807,260802,260797,260791,260786,260781,260776,260771,260766,260761,260756,260750,260745,260740,260735,260730,260724,260719,260714,260709,260703,260698,260693,260688,260682,260677,260672,260666,260661,260656,260650,260645,260640,260634,260629,260623,260618,260613,260607,260602,260596,260591,260585,260580,260574,260569,260563,260558,260552,260547,260541,260536,260530,260525,260519,260513,260508,260502,260496,260491,260485,260480,260474,260468,260463,260457,260451,260445,260440,260434,260428,260423,260417,260411,260405,260399,260394,260388,260382,260376,260370,260365,260359,260353,260347,260341,260335,260329,260323,260317,260312,260306,260300,260294,260288,260282,260276,260270,260264,260258,260252,260246,260240,260234,260228,260221,260215,260209,260203,260197,260191,260185,260179,260173,260166,260160,260154,260148,260142,260135,260129,260123,260117,260111,260104,260098,260092,260085,260079,260073,260067,260060,260054,260048,260041,260035,260029,260022,260016,260009,260003,259997,259990,259984,259977,259971,259964,259958,259951,259945,259938,259932,259925,259919,259912,259906,259899,259893,259886,259879,259873,259866,259860,259853,259846,259840,259833,259826,259820,259813,259806,259800,259793,259786,259779,259773,259766,259759,259752,259746,259739,259732,259725,259718,259712,259705,259698,259691,259684,259677,259670,259664,259657,259650,259643,259636,259629,259622,259615,259608,259601,259594,259587,259580,259573,259566,259559,259552,259545,259538,259531,259524,259517,259509,259502,259495,259488,259481,259474,259467,259459,259452,259445,259438,259431,259423,259416,259409,259402,259395,259387,259380,259373,259365,259358,259351,259343,259336,259329,259321,259314,259307,259299,259292,259285,259277,259270,259262,259255,259247,259240,259232,259225,259217,259210,259202,259195,259187,259180,259172,259165,259157,259150,259142,259135,259127,259119,259112,259104,259096,259089,259081,259073,259066,259058,259050,259043,259035,259027,259020,259012,259004,258996,258989,258981,258973,258965,258957,258950,258942,258934,258926,258918,258910,258902,258895,258887,258879,258871,258863,258855,258847,258839,258831,258823,258815,258807,258799,258791,258783,258775,258767,258759,258751,258743,258735,258727,258719,258711,258702,258694,258686,258678,258670,258662,258654,258645,258637,258629,258621,258613,258604,258596,258588,258580,258571,258563,258555,258546,258538,258530,258522,258513,258505,258496,258488,258480,258471,258463,258455,258446,258438,258429,258421,258412,258404,258396,258387,258379,258370,258362,258353,258345,258336,258327,258319,258310,258302,258293,258285,258276,258267,258259,258250,258242,258233,258224,258216,258207,258198,258190,258181,258172,258163,258155,258146,258137,258128,258120,258111,258102,258093,258084,258076,258067,258058,258049,258040,258031,258023,258014,258005,257996,257987,257978,257969,257960,257951,257942,257933,257924,257915,257906,257897,257888,257879,257870,257861,257852,257843,257834,257825,257816,257807,257798,257789,257779,257770,257761,257752,257743,257734,257724,257715,257706,257697,257688,257678,257669,257660,257651,257641,257632,257623,257613,257604,257595,257585,257576,257567,257557,257548,257539,257529,257520,257510,257501,257492,257482,257473,257463,257454,257444,257435,257425,257416,257406,257397,257387,257378,257368,257359,257349,257340,257330,257320,257311,257301,257292,257282,257272,257263,257253,257243,257234,257224,257214,257205,257195,257185,257175,257166,257156,257146,257136,257127,257117,257107,257097,257087,257078,257068,257058,257048,257038,257028,257018,257008,256999,256989,256979,256969,256959,256949,256939,256929,256919,256909,256899,256889,256879,256869,256859,256849,256839,256829,256819,256809,256798,256788,256778,256768,256758,256748,256738,256728,256717,256707,256697,256687,256677,256666,256656,256646,256636,256625,256615,256605,256595,256584,256574,256564,256553,256543,256533,256522,256512,256502,256491,256481,256470,256460,256450,256439,256429,256418,256408,256397,256387,256376,256366,256355,256345,256334,256324,256313,256303,256292,256282,256271,256261,256250,256239,256229,256218,256207,256197,256186,256176,256165,256154,256143,256133,256122,256111,256101,256090,256079,256068,256058,256047,256036,256025,256014,256004,255993,255982,255971,255960,255949,255939,255928,255917,255906,255895,255884,255873,255862,255851,255840,255829,255818,255807,255796,255785,255774,255763,255752,255741,255730,255719,255708,255697,255686,255675,255664,255653,255642,255630,255619,255608,255597,255586,255575,255564,255552,255541,255530,255519,255507,255496,255485,255474,255462,255451,255440,255429,255417,255406,255395,255383,255372,255361,255349,255338,255326,255315,255304,255292,255281,255269,255258,255246,255235,255224,255212,255201,255189,255178,255166,255155,255143,255131,255120,255108,255097,255085,255074,255062,255050,255039,255027,255015,255004,254992,254981,254969,254957,254945,254934,254922,254910,254899,254887,254875,254863,254852,254840,254828,254816,254804,254793,254781,254769,254757,254745,254733,254721,254710,254698,254686,254674,254662,254650,254638,254626,254614,254602,254590,254578,254566,254554,254542,254530,254518,254506,254494,254482,254470,254458,254446,254434,254422,254410,254397,254385,254373,254361,254349,254337,254324,254312,254300,254288,254276,254263,254251,254239,254227,254214,254202,254190,254178,254165,254153,254141,254128,254116,254104,254091,254079,254067,254054,254042,254029,254017,254004,253992,253980,253967,253955,253942,253930,253917,253905,253892,253880,253867,253855,253842,253830,253817,253804,253792,253779,253767,253754,253741,253729,253716,253704,253691,253678,253666,253653,253640,253627,253615,253602,253589,253577,253564,253551,253538,253525,253513,253500,253487,253474,253461,253449,253436,253423,253410,253397,253384,253371,253359,253346,253333,253320,253307,253294,253281,253268,253255,253242,253229,253216,253203,253190,253177,253164,253151,253138,253125,253112,253099,253085,253072,253059,253046,253033,253020,253007,252994,252980,252967,252954,252941,252928,252914,252901,252888,252875,252861,252848,252835,252822,252808,252795,252782,252768,252755,252742,252728,252715,252702,252688,252675,252662,252648,252635,252621,252608,252594,252581,252568,252554,252541,252527,252514,252500,252487,252473,252460,252446,252432,252419,252405,252392,252378,252365,252351,252337,252324,252310,252296,252283,252269,252255,252242,252228,252214,252201,252187,252173,252159,252146,252132,252118,252104,252091,252077,252063,252049,252035,252022,252008,251994,251980,251966,251952,251938,251925,251911,251897,251883,251869,251855,251841,251827,251813,251799,251785,251771,251757,251743,251729,251715,251701,251687,251673,251659,251645,251631,251617,251602,251588,251574,251560,251546,251532,251518,251503,251489,251475,251461,251447,251432,251418,251404,251390,251375,251361,251347,251333,251318,251304,251290,251275,251261,251247,251232,251218,251204,251189,251175,251161,251146,251132,251117,251103,251088,251074,251060,251045,251031,251016,251002,250987,250973,250958,250944,250929,250914,250900,250885,250871,250856,250842,250827,250812,250798,250783,250768,250754,250739,250724,250710,250695,250680,250666,250651,250636,250622,250607,250592,250577,250562,250548,250533,250518,250503,250489,250474,250459,250444,250429,250414,250399,250385,250370,250355,250340,250325,250310,250295,250280,250265,250250,250235,250220,250205,250190,250175,250160,250145,250130,250115,250100,250085,250070,250055,250040,250025,250009,249994,249979,249964,249949,249934,249919,249903,249888,249873,249858,249843,249827,249812,249797,249782,249766,249751,249736,249721,249705,249690,249675,249659,249644,249629,249613,249598,249583,249567,249552,249536,249521,249506,249490,249475,249459,249444,249428,249413,249398,249382,249367,249351,249335,249320,249304,249289,249273,249258,249242,249227,249211,249195,249180,249164,249149,249133,249117,249102,249086,249070,249055,249039,249023,249008,248992,248976,248960,248945,248929,248913,248897,248882,248866,248850,248834,248818,248803,248787,248771,248755,248739,248723,248707,248691,248676,248660,248644,248628,248612,248596,248580,248564,248548,248532,248516,248500,248484,248468,248452,248436,248420,248404,248388,248372,248356,248340,248323,248307,248291,248275,248259,248243,248227,248211,248194,248178,248162,248146,248130,248113,248097,248081,248065,248048,248032,248016,248000,247983,247967,247951,247934,247918,247902,247885,247869,247853,247836,247820,247803,247787,247771,247754,247738,247721,247705,247688,247672,247655,247639,247622,247606,247589,247573,247556,247540,247523,247507,247490,247474,247457,247440,247424,247407,247391,247374,247357,247341,247324,247307,247291,247274,247257,247241,247224,247207,247190,247174,247157,247140,247123,247107,247090,247073,247056,247040,247023,247006,246989,246972,246955,246938,246922,246905,246888,246871,246854,246837,246820,246803,246786,246769,246752,246735,246718,246701,246684,246667,246650,246633,246616,246599,246582,246565,246548,246531,246514,246497,246480,246463,246445,246428,246411,246394,246377,246360,246342,246325,246308,246291,246274,246256,246239,246222,246205,246187,246170,246153,246136,246118,246101,246084,246066,246049,246032,246014,245997,245979,245962,245945,245927,245910,245892,245875,245858,245840,245823,245805,245788,245770,245753,245735,245718,245700,245683,245665,245648,245630,245613,245595,245577,245560,245542,245525,245507,245489,245472,245454,245436,245419,245401,245383,245366,245348,245330,245313,245295,245277,245259,245242,245224,245206,245188,245171,245153,245135,245117,245099,245081,245064,245046,245028,245010,244992,244974,244956,244938,244921,244903,244885,244867,244849,244831,244813,244795,244777,244759,244741,244723,244705,244687,244669,244651,244633,244615,244597,244578,244560,244542,244524,244506,244488,244470,244452,244433,244415,244397,244379,244361,244343,244324,244306,244288,244270,244251,244233,244215,244197,244178,244160,244142,244123,244105,244087,244068,244050,244032,244013,243995,243977,243958,243940,243921,243903,243885,243866,243848,243829,243811,243792,243774,243755,243737,243718,243700,243681,243663,243644,243626,243607,243588,243570,243551,243533,243514,243496,243477,243458,243440,243421,243402,243384,243365,243346,243328,243309,243290,243271,243253,243234,243215,243196,243178,243159,243140,243121,243103,243084,243065,243046,243027,243008,242990,242971,242952,242933,242914,242895,242876,242857,242838,242819,242800,242782,242763,242744,242725,242706,242687,242668,242649,242630,242611,242591,242572,242553,242534,242515,242496,242477,242458,242439,242420,242401,242381,242362,242343,242324,242305,242286,242266,242247,242228,242209,242189,242170,242151,242132,242112,242093,242074,242055,242035,242016,241997,241977,241958,241939,241919,241900,241881,241861,241842,241822,241803,241784,241764,241745,241725,241706,241686,241667,241647,241628,241608,241589,241569,241550,241530,241511,241491,241472,241452,241433,241413,241393,241374,241354,241334,241315,241295,241276,241256,241236,241217,241197,241177,241157,241138,241118,241098,241079,241059,241039,241019,241000,240980,240960,240940,240920,240901,240881,240861,240841,240821,240801,240781,240762,240742,240722,240702,240682,240662,240642,240622,240602,240582,240562,240542,240522,240502,240482,240462,240442,240422,240402,240382,240362,240342,240322,240302,240282,240262,240242,240221,240201,240181,240161,240141,240121,240101,240080,240060,240040,240020,240000,239979,239959,239939,239919,239898,239878,239858,239838,239817,239797,239777,239756,239736,239716,239695,239675,239655,239634,239614,239593,239573,239553,239532,239512,239491,239471,239450,239430,239410,239389,239369,239348,239328,239307,239287,239266,239245,239225,239204,239184,239163,239143,239122,239101,239081,239060,239040,239019,238998,238978,238957,238936,238916,238895,238874,238853,238833,238812,238791,238771,238750,238729,238708,238688,238667,238646,238625,238604,238583,238563,238542,238521,238500,238479,238458,238437,238417,238396,238375,238354,238333,238312,238291,238270,238249,238228,238207,238186,238165,238144,238123,238102,238081,238060,238039,238018,237997,237976,237955,237934,237913,237891,237870,237849,237828,237807,237786,237765,237743,237722,237701,237680,237659,237637,237616,237595,237574,237552,237531,237510,237489,237467,237446,237425,237403,237382,237361,237339,237318,237297,237275,237254,237233,237211,237190,237168,237147,237126,237104,237083,237061,237040,237018,236997,236975,236954,236932,236911,236889,236868,236846,236825,236803,236782,236760,236738,236717,236695,236674,236652,236630,236609,236587,236565,236544,236522,236500,236479,236457,236435,236414,236392,236370,236348,236327,236305,236283,236261,236240,236218,236196,236174,236152,236131,236109,236087,236065,236043,236021,235999,235978,235956,235934,235912,235890,235868,235846,235824,235802,235780,235758,235736,235714,235692,235670,235648,235626,235604,235582,235560,235538,235516,235494,235472,235450,235428,235405,235383,235361,235339,235317,235295,235273,235250,235228,235206,235184,235162,235139,235117,235095,235073,235050,235028,235006,234984,234961,234939,234917,234894,234872,234850,234828,234805,234783,234760,234738,234716,234693,234671,234649,234626,234604,234581,234559,234536,234514,234491,234469,234446,234424,234401,234379,234356,234334,234311,234289,234266,234244,234221,234199,234176,234153,234131,234108,234086,234063,234040,234018,233995,233972,233950,233927,233904,233882,233859,233836,233813,233791,233768,233745,233722,233700,233677,233654,233631,233609,233586,233563,233540,233517,233494,233472,233449,233426,233403,233380,233357,233334,233311,233288,233265,233243,233220,233197,233174,233151,233128,233105,233082,233059,233036,233013,232990,232967,232944,232920,232897,232874,232851,232828,232805,232782,232759,232736,232713,232689,232666,232643,232620,232597,232574,232550,232527,232504,232481,232457,232434,232411,232388,232364,232341,232318,232295,232271,232248,232225,232201,232178,232155,232131,232108,232085,232061,232038,232014,231991,231968,231944,231921,231897,231874,231850,231827,231804,231780,231757,231733,231710,231686,231663,231639,231615,231592,231568,231545,231521,231498,231474,231450,231427,231403,231380,231356,231332,231309,231285,231261,231238,231214,231190,231167,231143,231119,231096,231072,231048,231024,231001,230977,230953,230929,230905,230882,230858,230834,230810,230786,230762,230739,230715,230691,230667,230643,230619,230595,230571,230548,230524,230500,230476,230452,230428,230404,230380,230356,230332,230308,230284,230260,230236,230212,230188,230164,230140,230116,230091,230067,230043,230019,229995,229971,229947,229923,229898,229874,229850,229826,229802,229778,229753,229729,229705,229681,229657,229632,229608,229584,229560,229535,229511,229487,229462,229438,229414,229389,229365,229341,229316,229292,229268,229243,229219,229194,229170,229146,229121,229097,229072,229048,229024,228999,228975,228950,228926,228901,228877,228852,228828,228803,228779,228754,228729,228705,228680,228656,228631,228607,228582,228557,228533,228508,228483,228459,228434,228409,228385,228360,228335,228311,228286,228261,228237,228212,228187,228162,228138,228113,228088,228063,228039,228014,227989,227964,227939,227914,227890,227865,227840,227815,227790,227765,227740,227716,227691,227666,227641,227616,227591,227566,227541,227516,227491,227466,227441,227416,227391,227366,227341,227316,227291,227266,227241,227216,227191,227166,227141,227115,227090,227065,227040,227015,226990,226965,226940,226914,226889,226864,226839,226814,226788,226763,226738,226713,226688,226662,226637,226612,226586,226561,226536,226511,226485,226460,226435,226409,226384,226359,226333,226308,226283,226257,226232,226206,226181,226156,226130,226105,226079,226054,226028,226003,225977,225952,225926,225901,225875,225850,225824,225799,225773,225748,225722,225697,225671,225646,225620,225594,225569,225543,225517,225492,225466,225441,225415,225389,225364,225338,225312,225287,225261,225235,225209,225184,225158,225132,225106,225081,225055,225029,225003,224978,224952,224926,224900,224874,224848,224823,224797,224771,224745,224719,224693,224667,224641,224615,224590,224564,224538,224512,224486,224460,224434,224408,224382,224356,224330,224304,224278,224252,224226,224200,224174,224148,224122,224096,224069,224043,224017,223991,223965,223939,223913,223887,223860,223834,223808,223782,223756,223730,223703,223677,223651,223625,223599,223572,223546,223520,223493,223467,223441,223415,223388,223362,223336,223309,223283,223257,223230,223204,223178,223151,223125,223099,223072,223046,223019,222993,222966,222940,222914,222887,222861,222834,222808,222781,222755,222728,222702,222675,222649,222622,222596,222569,222542,222516,222489,222463,222436,222410,222383,222356,222330,222303,222276,222250,222223,222196,222170,222143,222116,222090,222063,222036,222010,221983,221956,221929,221903,221876,221849,221822,221795,221769,221742,221715,221688,221661,221634,221608,221581,221554,221527,221500,221473,221446,221419,221393,221366,221339,221312,221285,221258,221231,221204,221177,221150,221123,221096,221069,221042,221015,220988,220961,220934,220907,220880,220853,220826,220798,220771,220744,220717,220690,220663,220636,220609,220581,220554,220527,220500,220473,220446,220418,220391,220364,220337,220309,220282,220255,220228,220200,220173,220146,220119,220091,220064,220037,220009,219982,219955,219927,219900,219873,219845,219818,219790,219763,219736,219708,219681,219653,219626,219598,219571,219544,219516,219489,219461,219434,219406,219379,219351,219324,219296,219268,219241,219213,219186,219158,219131,219103,219075,219048,219020,218993,218965,218937,218910,218882,218854,218827,218799,218771,218744,218716,218688,218660,218633,218605,218577,218549,218522,218494,218466,218438,218411,218383,218355,218327,218299,218271,218244,218216,218188,218160,218132,218104,218076,218049,218021,217993,217965,217937,217909,217881,217853,217825,217797,217769,217741,217713,217685,217657,217629,217601,217573,217545,217517,217489,217461,217433,217405,217377,217348,217320,217292,217264,217236,217208,217180,217152,217123,217095,217067,217039,217011,216982,216954,216926,216898,216870,216841,216813,216785,216757,216728,216700,216672,216643,216615,216587,216558,216530,216502,216473,216445,216417,216388,216360,216332,216303,216275,216246,216218,216190,216161,216133,216104,216076,216047,216019,215990,215962,215933,215905,215876,215848,215819,215791,215762,215734,215705,215677,215648,215619,215591,215562,215534,215505,215476,215448,215419,215390,215362,215333,215304,215276,215247,215218,215190,215161,215132,215104,215075,215046,215017,214989,214960,214931,214902,214873,214845,214816,214787,214758,214729,214701,214672,214643,214614,214585,214556,214527,214498,214470,214441,214412,214383,214354,214325,214296,214267,214238,214209,214180,214151,214122,214093,214064,214035,214006,213977,213948,213919,213890,213861,213832,213803,213774,213745,213715,213686,213657,213628,213599,213570,213541,213511,213482,213453,213424,213395,213366,213336,213307,213278,213249,213219,213190,213161,213132,213102,213073,213044,213015,212985,212956,212927,212897,212868,212839,212809,212780,212751,212721,212692,212662,212633,212604,212574,212545,212515,212486,212456,212427,212398,212368,212339,212309,212280,212250,212221,212191,212162,212132,212103,212073,212043,212014,211984,211955,211925,211896,211866,211836,211807,211777,211748,211718,211688,211659,211629,211599,211570,211540,211510,211481,211451,211421,211391,211362,211332,211302,211272,211243,211213,211183,211153,211124,211094,211064,211034,211004,210974,210945,210915,210885,210855,210825,210795,210765,210736,210706,210676,210646,210616,210586,210556,210526,210496,210466,210436,210406,210376,210346,210316,210286,210256,210226,210196,210166,210136,210106,210076,210046,210016,209986,209956,209926,209895,209865,209835,209805,209775,209745,209715,209684,209654,209624,209594,209564,209534,209503,209473,209443,209413,209382,209352,209322,209292,209261,209231,209201,209170,209140,209110,209080,209049,209019,208989,208958,208928,208897,208867,208837,208806,208776,208746,208715,208685,208654,208624,208593,208563,208533,208502,208472,208441,208411,208380,208350,208319,208289,208258,208228,208197,208166,208136,208105,208075,208044,208014,207983,207952,207922,207891,207861,207830,207799,207769,207738,207707,207677,207646,207615,207585,207554,207523,207492,207462,207431,207400,207370,207339,207308,207277,207246,207216,207185,207154,207123,207092,207062,207031,207000,206969,206938,206907,206877,206846,206815,206784,206753,206722,206691,206660,206629,206598,206567,206537,206506,206475,206444,206413,206382,206351,206320,206289,206258,206227,206196,206165,206133,206102,206071,206040,206009,205978,205947,205916,205885,205854,205823,205791,205760,205729,205698,205667,205636,205604,205573,205542,205511,205480,205448,205417,205386,205355,205324,205292,205261,205230,205198,205167,205136,205105,205073,205042,205011,204979,204948,204917,204885,204854,204823,204791,204760,204728,204697,204666,204634,204603,204571,204540,204508,204477,204446,204414,204383,204351,204320,204288,204257,204225,204194,204162,204131,204099,204067,204036,204004,203973,203941,203910,203878,203846,203815,203783,203752,203720,203688,203657,203625,203593,203562,203530,203498,203467,203435,203403,203372,203340,203308,203276,203245,203213,203181,203149,203118,203086,203054,203022,202990,202959,202927,202895,202863,202831,202799,202768,202736,202704,202672,202640,202608,202576,202544,202512,202481,202449,202417,202385,202353,202321,202289,202257,202225,202193,202161,202129,202097,202065,202033,202001,201969,201937,201905,201873,201841,201808,201776,201744,201712,201680,201648,201616,201584,201552,201519,201487,201455,201423,201391,201359,201326,201294,201262,201230,201198,201165,201133,201101,201069,201036,201004,200972,200940,200907,200875,200843,200810,200778,200746,200713,200681,200649,200616,200584,200552,200519,200487,200454,200422,200390,200357,200325,200292,200260,200228,200195,200163,200130,200098,200065,200033,200000,199968,199935,199903,199870,199838,199805,199773,199740,199708,199675,199642,199610,199577,199545,199512,199479,199447,199414,199382,199349,199316,199284,199251,199218,199186,199153,199120,199088,199055,199022,198989,198957,198924,198891,198858,198826,198793,198760,198727,198695,198662,198629,198596,198563,198531,198498,198465,198432,198399,198366,198334,198301,198268,198235,198202,198169,198136,198103,198070,198037,198004,197972,197939,197906,197873,197840,197807,197774,197741,197708,197675,197642,197609,197576,197543,197510,197476,197443,197410,197377,197344,197311,197278,197245,197212,197179,197146,197112,197079,197046,197013,196980,196947,196913,196880,196847,196814,196781,196747,196714,196681,196648,196615,196581,196548,196515,196481,196448,196415,196382,196348,196315,196282,196248,196215,196182,196148,196115,196082,196048,196015,195982,195948,195915,195881,195848,195815,195781,195748,195714,195681,195647,195614,195580,195547,195513,195480,195446,195413,195379,195346,195312,195279,195245,195212,195178,195145,195111,195078,195044,195010,194977,194943,194910,194876,194842,194809,194775,194741,194708,194674,194640,194607,194573,194539,194506,194472,194438,194405,194371,194337,194303,194270,194236,194202,194168,194135,194101,194067,194033,193999,193966,193932,193898,193864,193830,193796,193763,193729,193695,193661,193627,193593,193559,193525,193492,193458,193424,193390,193356,193322,193288,193254,193220,193186,193152,193118,193084,193050,193016,192982,192948,192914,192880,192846,192812,192778,192744,192710,192676,192641,192607,192573,192539,192505,192471,192437,192403,192369,192334,192300,192266,192232,192198,192164,192129,192095,192061,192027,191992,191958,191924,191890,191856,191821,191787,191753,191718,191684,191650,191616,191581,191547,191513,191478,191444,191410,191375,191341,191307,191272,191238,191203,191169,191135,191100,191066,191031,190997,190963,190928,190894,190859,190825,190790,190756,190721,190687,190652,190618,190583,190549,190514,190480,190445,190411,190376,190342,190307,190272,190238,190203,190169,190134,190099,190065,190030,189996,189961,189926,189892,189857,189822,189788,189753,189718,189684,189649,189614,189580,189545,189510,189475,189441,189406,189371,189336,189302,189267,189232,189197,189162,189128,189093,189058,189023,188988,188954,188919,188884,188849,188814,188779,188744,188709,188675,188640,188605,188570,188535,188500,188465,188430,188395,188360,188325,188290,188255,188220,188185,188150,188115,188080,188045,188010,187975,187940,187905,187870,187835,187800,187765,187730,187695,187660,187625,187589,187554,187519,187484,187449,187414,187379,187343,187308,187273,187238,187203,187168,187132,187097,187062,187027,186992,186956,186921,186886,186851,186815,186780,186745,186710,186674,186639,186604,186568,186533,186498,186462,186427,186392,186356,186321,186286,186250,186215,186179,186144,186109,186073,186038,186002,185967,185932,185896,185861,185825,185790,185754,185719,185683,185648,185612,185577,185541,185506,185470,185435,185399,185364,185328,185293,185257,185222,185186,185150,185115,185079,185044,185008,184972,184937,184901,184866,184830,184794,184759,184723,184687,184652,184616,184580,184545,184509,184473,184437,184402,184366,184330,184294,184259,184223,184187,184151,184116,184080,184044,184008,183972,183937,183901,183865,183829,183793,183757,183722,183686,183650,183614,183578,183542,183506,183470,183435,183399,183363,183327,183291,183255,183219,183183,183147,183111,183075,183039,183003,182967,182931,182895,182859,182823,182787,182751,182715,182679,182643,182607,182571,182535,182499,182463,182426,182390,182354,182318,182282,182246,182210,182174,182137,182101,182065,182029,181993,181957,181920,181884,181848,181812,181776,181739,181703,181667,181631,181594,181558,181522,181486,181449,181413,181377,181341,181304,181268,181232,181195,181159,181123,181086,181050,181014,180977,180941,180904,180868,180832,180795,180759,180723,180686,180650,180613,180577,180540,180504,180467,180431,180395,180358,180322,180285,180249,180212,180176,180139,180103,180066,180029,179993,179956,179920,179883,179847,179810,179774,179737,179700,179664,179627,179591,179554,179517,179481,179444,179407,179371,179334,179297,179261,179224,179187,179151,179114,179077,179041,179004,178967,178930,178894,178857,178820,178783,178747,178710,178673,178636,178600,178563,178526,178489,178452,178415,178379,178342,178305,178268,178231,178194,178158,178121,178084,178047,178010,177973,177936,177899,177862,177825,177788,177752,177715,177678,177641,177604,177567,177530,177493,177456,177419,177382,177345,177308,177271,177234,177197,177160,177123,177085,177048,177011,176974,176937,176900,176863,176826,176789,176752,176714,176677,176640,176603,176566,176529,176492,176454,176417,176380,176343,176306,176268,176231,176194,176157,176120,176082,176045,176008,175971,175933,175896,175859,175822,175784,175747,175710,175672,175635,175598,175560,175523,175486,175448,175411,175374,175336,175299,175262,175224,175187,175149,175112,175075,175037,175000,174962,174925,174887,174850,174813,174775,174738,174700,174663,174625,174588,174550,174513,174475,174438,174400,174363,174325,174288,174250,174212,174175,174137,174100,174062,174025,173987,173949,173912,173874,173837,173799,173761,173724,173686,173648,173611,173573,173535,173498,173460,173422,173385,173347,173309,173271,173234,173196,173158,173121,173083,173045,173007,172969,172932,172894,172856,172818,172781,172743,172705,172667,172629,172591,172554,172516,172478,172440,172402,172364,172326,172289,172251,172213,172175,172137,172099,172061,172023,171985,171947,171909,171871,171834,171796,171758,171720,171682,171644,171606,171568,171530,171492,171454,171416,171378,171339,171301,171263,171225,171187,171149,171111,171073,171035,170997,170959,170921,170883,170844,170806,170768,170730,170692,170654,170616,170577,170539,170501,170463,170425,170386,170348,170310,170272,170234,170195,170157,170119,170081,170042,170004,169966,169928,169889,169851,169813,169774,169736,169698,169660,169621,169583,169545,169506,169468,169430,169391,169353,169314,169276,169238,169199,169161,169122,169084,169046,169007,168969,168930,168892,168853,168815,168777,168738,168700,168661,168623,168584,168546,168507,168469,168430,168392,168353,168315,168276,168238,168199,168160,168122,168083,168045,168006,167968,167929,167890,167852,167813,167774,167736,167697,167659,167620,167581,167543,167504,167465,167427,167388,167349,167311,167272,167233,167194,167156,167117,167078,167040,167001,166962,166923,166885,166846,166807,166768,166729,166691,166652,166613,166574,166535,166497,166458,166419,166380,166341,166302,166264,166225,166186,166147,166108,166069,166030,165991,165952,165914,165875,165836,165797,165758,165719,165680,165641,165602,165563,165524,165485,165446,165407,165368,165329,165290,165251,165212,165173,165134,165095,165056,165017,164978,164939,164900,164861,164821,164782,164743,164704,164665,164626,164587,164548,164509,164469,164430,164391,164352,164313,164274,164234,164195,164156,164117,164078,164039,163999,163960,163921,163882,163842,163803,163764,163725,163685,163646,163607,163568,163528,163489,163450,163410,163371,163332,163292,163253,163214,163174,163135,163096,163056,163017,162978,162938,162899,162860,162820,162781,162741,162702,162663,162623,162584,162544,162505,162465,162426,162386,162347,162308,162268,162229,162189,162150,162110,162071,162031,161992,161952,161913,161873,161833,161794,161754,161715,161675,161636,161596,161557,161517,161477,161438,161398,161359,161319,161279,161240,161200,161160,161121,161081,161041,161002,160962,160922,160883,160843,160803,160764,160724,160684,160644,160605,160565,160525,160486,160446,160406,160366,160327,160287,160247,160207,160167,160128,160088,160048,160008,159968,159929,159889,159849,159809,159769,159729,159689,159650,159610,159570,159530,159490,159450,159410,159370,159330,159291,159251,159211,159171,159131,159091,159051,159011,158971,158931,158891,158851,158811,158771,158731,158691,158651,158611,158571,158531,158491,158451,158411,158371,158331,158291,158251,158211,158170,158130,158090,158050,158010,157970,157930,157890,157850,157809,157769,157729,157689,157649,157609,157569,157528,157488,157448,157408,157368,157327,157287,157247,157207,157167,157126,157086,157046,157006,156965,156925,156885,156845,156804,156764,156724,156683,156643,156603,156562,156522,156482,156441,156401,156361,156320,156280,156240,156199,156159,156119,156078,156038,155997,155957,155917,155876,155836,155795,155755,155715,155674,155634,155593,155553,155512,155472,155431,155391,155350,155310,155269,155229,155188,155148,155107,155067,155026,154986,154945,154905,154864,154824,154783,154742,154702,154661,154621,154580,154539,154499,154458,154418,154377,154336,154296,154255,154214,154174,154133,154093,154052,154011,153970,153930,153889,153848,153808,153767,153726,153686,153645,153604,153563,153523,153482,153441,153400,153360,153319,153278,153237,153197,153156,153115,153074,153033,152993,152952,152911,152870,152829,152788,152748,152707,152666,152625,152584,152543,152502,152461,152421,152380,152339,152298,152257,152216,152175,152134,152093,152052,152011,151970,151929,151888,151847,151806,151765,151724,151683,151642,151601,151560,151519,151478,151437,151396,151355,151314,151273,151232,151191,151150,151109,151068,151027,150986,150945,150904,150862,150821,150780,150739,150698,150657,150616,150575,150533,150492,150451,150410,150369,150328,150286,150245,150204,150163,150122,150080,150039,149998,149957,149916,149874,149833,149792,149751,149709,149668,149627,149585,149544,149503,149462,149420,149379,149338,149296,149255,149214,149172,149131,149090,149048,149007,148966,148924,148883,148842,148800,148759,148717,148676,148635,148593,148552,148510,148469,148428,148386,148345,148303,148262,148220,148179,148137,148096,148054,148013,147971,147930,147888,147847,147805,147764,147722,147681,147639,147598,147556,147515,147473,147432,147390,147348,147307,147265,147224,147182,147141,147099,147057,147016,146974,146932,146891,146849,146808,146766,146724,146683,146641,146599,146558,146516,146474,146433,146391,146349,146307,146266,146224,146182,146141,146099,146057,146015,145974,145932,145890,145848,145807,145765,145723,145681,145639,145598,145556,145514,145472,145430,145389,145347,145305,145263,145221,145179,145137,145096,145054,145012,144970,144928,144886,144844,144802,144761,144719,144677,144635,144593,144551,144509,144467,144425,144383,144341,144299,144257,144215,144173,144131,144089,144047,144005,143963,143921,143879,143837,143795,143753,143711,143669,143627,143585,143543,143501,143459,143417,143375,143333,143291,143248,143206,143164,143122,143080,143038,142996,142954,142912,142869,142827,142785,142743,142701,142659,142616,142574,142532,142490,142448,142405,142363,142321,142279,142237,142194,142152,142110,142068,142025,141983,141941,141899,141856,141814,141772,141730,141687,141645,141603,141560,141518,141476,141433,141391,141349,141306,141264,141222,141179,141137,141095,141052,141010,140968,140925,140883,140840,140798,140756,140713,140671,140628,140586,140544,140501,140459,140416,140374,140331,140289,140246,140204,140161,140119,140077,140034,139992,139949,139907,139864,139821,139779,139736,139694,139651,139609,139566,139524,139481,139439,139396,139353,139311,139268,139226,139183,139141,139098,139055,139013,138970,138927,138885,138842,138800,138757,138714,138672,138629,138586,138544,138501,138458,138416,138373,138330,138288,138245,138202,138159,138117,138074,138031,137988,137946,137903,137860,137817,137775,137732,137689,137646,137604,137561,137518,137475,137432,137390,137347,137304,137261,137218,137176,137133,137090,137047,137004,136961,136918,136876,136833,136790,136747,136704,136661,136618,136575,136532,136490,136447,136404,136361,136318,136275,136232,136189,136146,136103,136060,136017,135974,135931,135888,135845,135802,135759,135716,135673,135630,135587,135544,135501,135458,135415,135372,135329,135286,135243,135200,135157,135114,135071,135028,134984,134941,134898,134855,134812,134769,134726,134683,134640,134596,134553,134510,134467,134424,134381,134338,134294,134251,134208,134165,134122,134078,134035,133992,133949,133906,133862,133819,133776,133733,133690,133646,133603,133560,133517,133473,133430,133387,133343,133300,133257,133214,133170,133127,133084,133040,132997,132954,132910,132867,132824,132780,132737,132694,132650,132607,132564,132520,132477,132434,132390,132347,132303,132260,132217,132173,132130,132086,132043,132000,131956,131913,131869,131826,131782,131739,131695,131652,131609,131565,131522,131478,131435,131391,131348,131304,131261,131217,131174,131130,131087,131043,130999,130956,130912,130869,130825,130782,130738,130695,130651,130607,130564,130520,130477,130433,130389,130346,130302,130259,130215,130171,130128,130084,130040,129997,129953,129909,129866,129822,129778,129735,129691,129647,129604,129560,129516,129473,129429,129385,129341,129298,129254,129210,129167,129123,129079,129035,128992,128948,128904,128860,128816,128773,128729,128685,128641,128598,128554,128510,128466,128422,128378,128335,128291,128247,128203,128159,128115,128072,128028,127984,127940,127896,127852,127808,127764,127721,127677,127633,127589,127545,127501,127457,127413,127369,127325,127281,127237,127193,127150,127106,127062,127018,126974,126930,126886,126842,126798,126754,126710,126666,126622,126578,126534,126490,126446,126402,126358,126314,126269,126225,126181,126137,126093,126049,126005,125961,125917,125873,125829,125785,125741,125696,125652,125608,125564,125520,125476,125432,125388,125343,125299,125255,125211,125167,125123,125078,125034,124990,124946,124902,124857,124813,124769,124725,124681,124636,124592,124548,124504,124460,124415,124371,124327,124283,124238,124194,124150,124105,124061,124017,123973,123928,123884,123840,123795,123751,123707,123662,123618,123574,123529,123485,123441,123396,123352,123308,123263,123219,123175,123130,123086,123042,122997,122953,122908,122864,122820,122775,122731,122686,122642,122597,122553,122509,122464,122420,122375,122331,122286,122242,122197,122153,122108,122064,122019,121975,121931,121886,121842,121797,121752,121708,121663,121619,121574,121530,121485,121441,121396,121352,121307,121263,121218,121173,121129,121084,121040,120995,120950,120906,120861,120817,120772,120727,120683,120638,120594,120549,120504,120460,120415,120370,120326,120281,120236,120192,120147,120102,120058,120013,119968,119924,119879,119834,119790,119745,119700,119655,119611,119566,119521,119476,119432,119387,119342,119297,119253,119208,119163,119118,119074,119029,118984,118939,118894,118850,118805,118760,118715,118670,118626,118581,118536,118491,118446,118401,118357,118312,118267,118222,118177,118132,118087,118042,117998,117953,117908,117863,117818,117773,117728,117683,117638,117593,117549,117504,117459,117414,117369,117324,117279,117234,117189,117144,117099,117054,117009,116964,116919,116874,116829,116784,116739,116694,116649,116604,116559,116514,116469,116424,116379,116334,116289,116244,116199,116154,116109,116064,116018,115973,115928,115883,115838,115793,115748,115703,115658,115613,115567,115522,115477,115432,115387,115342,115297,115252,115206,115161,115116,115071,115026,114981,114935,114890,114845,114800,114755,114710,114664,114619,114574,114529,114483,114438,114393,114348,114303,114257,114212,114167,114122,114076,114031,113986,113941,113895,113850,113805,113759,113714,113669,113624,113578,113533,113488,113442,113397,113352,113306,113261,113216,113170,113125,113080,113034,112989,112944,112898,112853,112808,112762,112717,112671,112626,112581,112535,112490,112444,112399,112354,112308,112263,112217,112172,112126,112081,112036,111990,111945,111899,111854,111808,111763,111717,111672,111626,111581,111535,111490,111444,111399,111353,111308,111262,111217,111171,111126,111080,111035,110989,110944,110898,110853,110807,110762,110716,110670,110625,110579,110534,110488,110443,110397,110351,110306,110260,110215,110169,110123,110078,110032,109986,109941,109895,109850,109804,109758,109713,109667,109621,109576,109530,109484,109439,109393,109347,109302,109256,109210,109165,109119,109073,109027,108982,108936,108890,108845,108799,108753,108707,108662,108616,108570,108524,108479,108433,108387,108341,108295,108250,108204,108158,108112,108067,108021,107975,107929,107883,107838,107792,107746,107700,107654,107608,107563,107517,107471,107425,107379,107333,107287,107242,107196,107150,107104,107058,107012,106966,106920,106875,106829,106783,106737,106691,106645,106599,106553,106507,106461,106415,106369,106323,106278,106232,106186,106140,106094,106048,106002,105956,105910,105864,105818,105772,105726,105680,105634,105588,105542,105496,105450,105404,105358,105312,105266,105220,105174,105128,105082,105035,104989,104943,104897,104851,104805,104759,104713,104667,104621,104575,104529,104483,104436,104390,104344,104298,104252,104206,104160,104114,104067,104021,103975,103929,103883,103837,103791,103744,103698,103652,103606,103560,103514,103467,103421,103375,103329,103283,103236,103190,103144,103098,103052,103005,102959,102913,102867,102820,102774,102728,102682,102635,102589,102543,102497,102450,102404,102358,102312,102265,102219,102173,102126,102080,102034,101988,101941,101895,101849,101802,101756,101710,101663,101617,101571,101524,101478,101432,101385,101339,101293,101246,101200,101153,101107,101061,101014,100968,100922,100875,100829,100782,100736,100690,100643,100597,100550,100504,100457,100411,100365,100318,100272,100225,100179,100132,100086,100039,99993,99947,99900,99854,99807,99761,99714,99668,99621,99575,99528,99482,99435,99389,99342,99296,99249,99203,99156,99110,99063,99016,98970,98923,98877,98830,98784,98737,98691,98644,98597,98551,98504,98458,98411,98364,98318,98271,98225,98178,98131,98085,98038,97992,97945,97898,97852,97805,97758,97712,97665,97619,97572,97525,97479,97432,97385,97339,97292,97245,97199,97152,97105,97058,97012,96965,96918,96872,96825,96778,96732,96685,96638,96591,96545,96498,96451,96404,96358,96311,96264,96217,96171,96124,96077,96030,95984,95937,95890,95843,95796,95750,95703,95656,95609,95562,95516,95469,95422,95375,95328,95282,95235,95188,95141,95094,95047,95001,94954,94907,94860,94813,94766,94719,94673,94626,94579,94532,94485,94438,94391,94344,94297,94251,94204,94157,94110,94063,94016,93969,93922,93875,93828,93781,93734,93687,93640,93594,93547,93500,93453,93406,93359,93312,93265,93218,93171,93124,93077,93030,92983,92936,92889,92842,92795,92748,92701,92654,92607,92560,92513,92466,92419,92372,92325,92278,92230,92183,92136,92089,92042,91995,91948,91901,91854,91807,91760,91713,91666,91619,91571,91524,91477,91430,91383,91336,91289,91242,91195,91147,91100,91053,91006,90959,90912,90865,90817,90770,90723,90676,90629,90582,90534,90487,90440,90393,90346,90299,90251,90204,90157,90110,90063,90015,89968,89921,89874,89826,89779,89732,89685,89638,89590,89543,89496,89449,89401,89354,89307,89260,89212,89165,89118,89070,89023,88976,88929,88881,88834,88787,88739,88692,88645,88598,88550,88503,88456,88408,88361,88314,88266,88219,88172,88124,88077,88030,87982,87935,87888,87840,87793,87745,87698,87651,87603,87556,87509,87461,87414,87366,87319,87272,87224,87177,87129,87082,87035,86987,86940,86892,86845,86798,86750,86703,86655,86608,86560,86513,86465,86418,86371,86323,86276,86228,86181,86133,86086,86038,85991,85943,85896,85848,85801,85753,85706,85658,85611,85563,85516,85468,85421,85373,85326,85278,85231,85183,85136,85088,85040,84993,84945,84898,84850,84803,84755,84708,84660,84612,84565,84517,84470,84422,84374,84327,84279,84232,84184,84136,84089,84041,83994,83946,83898,83851,83803,83756,83708,83660,83613,83565,83517,83470,83422,83374,83327,83279,83231,83184,83136,83088,83041,82993,82945,82898,82850,82802,82755,82707,82659,82612,82564,82516,82468,82421,82373,82325,82278,82230,82182,82134,82087,82039,81991,81943,81896,81848,81800,81752,81705,81657,81609,81561,81514,81466,81418,81370,81322,81275,81227,81179,81131,81083,81036,80988,80940,80892,80844,80797,80749,80701,80653,80605,80557,80510,80462,80414,80366,80318,80270,80223,80175,80127,80079,80031,79983,79935,79887,79840,79792,79744,79696,79648,79600,79552,79504,79457,79409,79361,79313,79265,79217,79169,79121,79073,79025,78977,78929,78881,78834,78786,78738,78690,78642,78594,78546,78498,78450,78402,78354,78306,78258,78210,78162,78114,78066,78018,77970,77922,77874,77826,77778,77730,77682,77634,77586,77538,77490,77442,77394,77346,77298,77250,77202,77154,77106,77058,77010,76962,76914,76866,76818,76770,76721,76673,76625,76577,76529,76481,76433,76385,76337,76289,76241,76193,76144,76096,76048,76000,75952,75904,75856,75808,75760,75711,75663,75615,75567,75519,75471,75423,75375,75326,75278,75230,75182,75134,75086,75037,74989,74941,74893,74845,74797,74748,74700,74652,74604,74556,74508,74459,74411,74363,74315,74267,74218,74170,74122,74074,74025,73977,73929,73881,73833,73784,73736,73688,73640,73591,73543,73495,73447,73398,73350,73302,73254,73205,73157,73109,73061,73012,72964,72916,72867,72819,72771,72723,72674,72626,72578,72529,72481,72433,72384,72336,72288,72239,72191,72143,72095,72046,71998,71950,71901,71853,71805,71756,71708,71659,71611,71563,71514,71466,71418,71369,71321,71273,71224,71176,71127,71079,71031,70982,70934,70886,70837,70789,70740,70692,70644,70595,70547,70498,70450,70401,70353,70305,70256,70208,70159,70111,70062,70014,69966,69917,69869,69820,69772,69723,69675,69626,69578,69530,69481,69433,69384,69336,69287,69239,69190,69142,69093,69045,68996,68948,68899,68851,68802,68754,68705,68657,68608,68560,68511,68463,68414,68366,68317,68269,68220,68171,68123,68074,68026,67977,67929,67880,67832,67783,67735,67686,67637,67589,67540,67492,67443,67395,67346,67297,67249,67200,67152,67103,67055,67006,66957,66909,66860,66812,66763,66714,66666,66617,66568,66520,66471,66423,66374,66325,66277,66228,66179,66131,66082,66034,65985,65936,65888,65839,65790,65742,65693,65644,65596,65547,65498,65450,65401,65352,65304,65255,65206,65158,65109,65060,65011,64963,64914,64865,64817,64768,64719,64671,64622,64573,64524,64476,64427,64378,64329,64281,64232,64183,64135,64086,64037,63988,63940,63891,63842,63793,63745,63696,63647,63598,63550,63501,63452,63403,63354,63306,63257,63208,63159,63111,63062,63013,62964,62915,62867,62818,62769,62720,62671,62623,62574,62525,62476,62427,62378,62330,62281,62232,62183,62134,62085,62037,61988,61939,61890,61841,61792,61744,61695,61646,61597,61548,61499,61450,61402,61353,61304,61255,61206,61157,61108,61059,61011,60962,60913,60864,60815,60766,60717,60668,60619,60570,60522,60473,60424,60375,60326,60277,60228,60179,60130,60081,60032,59983,59935,59886,59837,59788,59739,59690,59641,59592,59543,59494,59445,59396,59347,59298,59249,59200,59151,59102,59053,59004,58955,58906,58857,58808,58759,58711,58662,58613,58564,58515,58466,58417,58368,58319,58270,58221,58171,58122,58073,58024,57975,57926,57877,57828,57779,57730,57681,57632,57583,57534,57485,57436,57387,57338,57289,57240,57191,57142,57093,57044,56995,56946,56896,56847,56798,56749,56700,56651,56602,56553,56504,56455,56406,56357,56308,56258,56209,56160,56111,56062,56013,55964,55915,55866,55816,55767,55718,55669,55620,55571,55522,55473,55424,55374,55325,55276,55227,55178,55129,55080,55030,54981,54932,54883,54834,54785,54736,54686,54637,54588,54539,54490,54441,54391,54342,54293,54244,54195,54145,54096,54047,53998,53949,53900,53850,53801,53752,53703,53654,53604,53555,53506,53457,53408,53358,53309,53260,53211,53161,53112,53063,53014,52965,52915,52866,52817,52768,52718,52669,52620,52571,52521,52472,52423,52374,52324,52275,52226,52177,52127,52078,52029,51980,51930,51881,51832,51782,51733,51684,51635,51585,51536,51487,51438,51388,51339,51290,51240,51191,51142,51092,51043,50994,50945,50895,50846,50797,50747,50698,50649,50599,50550,50501,50451,50402,50353,50303,50254,50205,50155,50106,50057,50007,49958,49909,49859,49810,49761,49711,49662,49613,49563,49514,49464,49415,49366,49316,49267,49218,49168,49119,49070,49020,48971,48921,48872,48823,48773,48724,48674,48625,48576,48526,48477,48427,48378,48329,48279,48230,48180,48131,48082,48032,47983,47933,47884,47835,47785,47736,47686,47637,47587,47538,47489,47439,47390,47340,47291,47241,47192,47142,47093,47044,46994,46945,46895,46846,46796,46747,46697,46648,46598,46549,46500,46450,46401,46351,46302,46252,46203,46153,46104,46054,46005,45955,45906,45856,45807,45757,45708,45658,45609,45559,45510,45460,45411,45361,45312,45262,45213,45163,45114,45064,45015,44965,44916,44866,44817,44767,44718,44668,44619,44569,44519,44470,44420,44371,44321,44272,44222,44173,44123,44074,44024,43974,43925,43875,43826,43776,43727,43677,43628,43578,43528,43479,43429,43380,43330,43281,43231,43181,43132,43082,43033,42983,42933,42884,42834,42785,42735,42686,42636,42586,42537,42487,42438,42388,42338,42289,42239,42190,42140,42090,42041,41991,41941,41892,41842,41793,41743,41693,41644,41594,41544,41495,41445,41396,41346,41296,41247,41197,41147,41098,41048,40998,40949,40899,40849,40800,40750,40701,40651,40601,40552,40502,40452,40403,40353,40303,40254,40204,40154,40105,40055,40005,39956,39906,39856,39806,39757,39707,39657,39608,39558,39508,39459,39409,39359,39310,39260,39210,39160,39111,39061,39011,38962,38912,38862,38813,38763,38713,38663,38614,38564,38514,38465,38415,38365,38315,38266,38216,38166,38116,38067,38017,37967,37917,37868,37818,37768,37719,37669,37619,37569,37520,37470,37420,37370,37321,37271,37221,37171,37122,37072,37022,36972,36922,36873,36823,36773,36723,36674,36624,36574,36524,36475,36425,36375,36325,36275,36226,36176,36126,36076,36027,35977,35927,35877,35827,35778,35728,35678,35628,35578,35529,35479,35429,35379,35329,35280,35230,35180,35130,35080,35030,34981,34931,34881,34831,34781,34732,34682,34632,34582,34532,34482,34433,34383,34333,34283,34233,34183,34134,34084,34034,33984,33934,33884,33835,33785,33735,33685,33635,33585,33535,33486,33436,33386,33336,33286,33236,33186,33137,33087,33037,32987,32937,32887,32837,32788,32738,32688,32638,32588,32538,32488,32438,32389,32339,32289,32239,32189,32139,32089,32039,31989,31940,31890,31840,31790,31740,31690,31640,31590,31540,31490,31441,31391,31341,31291,31241,31191,31141,31091,31041,30991,30942,30892,30842,30792,30742,30692,30642,30592,30542,30492,30442,30392,30342,30293,30243,30193,30143,30093,30043,29993,29943,29893,29843,29793,29743,29693,29643,29593,29543,29494,29444,29394,29344,29294,29244,29194,29144,29094,29044,28994,28944,28894,28844,28794,28744,28694,28644,28594,28544,28494,28444,28394,28344,28295,28245,28195,28145,28095,28045,27995,27945,27895,27845,27795,27745,27695,27645,27595,27545,27495,27445,27395,27345,27295,27245,27195,27145,27095,27045,26995,26945,26895,26845,26795,26745,26695,26645,26595,26545,26495,26445,26395,26345,26295,26245,26195,26145,26095,26045,25995,25945,25895,25845,25795,25745,25695,25645,25595,25545,25495,25444,25394,25344,25294,25244,25194,25144,25094,25044,24994,24944,24894,24844,24794,24744,24694,24644,24594,24544,24494,24444,24394,24344,24294,24244,24193,24143,24093,24043,23993,23943,23893,23843,23793,23743,23693,23643,23593,23543,23493,23443,23393,23342,23292,23242,23192,23142,23092,23042,22992,22942,22892,22842,22792,22742,22692,22641,22591,22541,22491,22441,22391,22341,22291,22241,22191,22141,22091,22040,21990,21940,21890,21840,21790,21740,21690,21640,21590,21540,21489,21439,21389,21339,21289,21239,21189,21139,21089,21039,20988,20938,20888,20838,20788,20738,20688,20638,20588,20538,20487,20437,20387,20337,20287,20237,20187,20137,20086,20036,19986,19936,19886,19836,19786,19736,19686,19635,19585,19535,19485,19435,19385,19335,19285,19234,19184,19134,19084,19034,18984,18934,18883,18833,18783,18733,18683,18633,18583,18532,18482,18432,18382,18332,18282,18232,18181,18131,18081,18031,17981,17931,17881,17830,17780,17730,17680,17630,17580,17530,17479,17429,17379,17329,17279,17229,17178,17128,17078,17028,16978,16928,16878,16827,16777,16727,16677,16627,16577,16526,16476,16426,16376,16326,16276,16225,16175,16125,16075,16025,15975,15924,15874,15824,15774,15724,15673,15623,15573,15523,15473,15423,15372,15322,15272,15222,15172,15122,15071,15021,14971,14921,14871,14820,14770,14720,14670,14620,14569,14519,14469,14419,14369,14319,14268,14218,14168,14118,14068,14017,13967,13917,13867,13817,13766,13716,13666,13616,13566,13515,13465,13415,13365,13315,13264,13214,13164,13114,13064,13013,12963,12913,12863,12813,12762,12712,12662,12612,12562,12511,12461,12411,12361,12311,12260,12210,12160,12110,12059,12009,11959,11909,11859,11808,11758,11708,11658,11608,11557,11507,11457,11407,11356,11306,11256,11206,11156,11105,11055,11005,10955,10904,10854,10804,10754,10704,10653,10603,10553,10503,10452,10402,10352,10302,10252,10201,10151,10101,10051,10000,9950,9900,9850,9799,9749,9699,9649,9599,9548,9498,9448,9398,9347,9297,9247,9197,9146,9096,9046,8996,8946,8895,8845,8795,8745,8694,8644,8594,8544,8493,8443,8393,8343,8292,8242,8192,8142,8091,8041,7991,7941,7890,7840,7790,7740,7690,7639,7589,7539,7489,7438,7388,7338,7288,7237,7187,7137,7087,7036,6986,6936,6886,6835,6785,6735,6685,6634,6584,6534,6484,6433,6383,6333,6283,6232,6182,6132,6082,6031,5981,5931,5881,5830,5780,5730,5680,5629,5579,5529,5479,5428,5378,5328,5278,5227,5177,5127,5076,5026,4976,4926,4875,4825,4775,4725,4674,4624,4574,4524,4473,4423,4373,4323,4272,4222,4172,4122,4071,4021,3971,3921,3870,3820,3770,3720,3669,3619,3569,3518,3468,3418,3368,3317,3267,3217,3167,3116,3066,3016,2966,2915,2865,2815,2765,2714,2664,2614,2563,2513,2463,2413,2362,2312,2262,2212,2161,2111,2061,2011,1960,1910,1860,1810,1759,1709,1659,1608,1558,1508,1458,1407,1357,1307,1257,1206,1156,1106,1056,1005,955,905,855,804,754,704,653,603,553,503,452,402,352,302,251,201,151,101,50,0,-49,-100,-150,-200,-250,-301,-351,-401,-451,-502,-552,-602,-652,-703,-753,-803,-854,-904,-954,-1004,-1055,-1105,-1155,-1205,-1256,-1306,-1356,-1406,-1457,-1507,-1557,-1607,-1658,-1708,-1758,-1809,-1859,-1909,-1959,-2010,-2060,-2110,-2160,-2211,-2261,-2311,-2361,-2412,-2462,-2512,-2562,-2613,-2663,-2713,-2764,-2814,-2864,-2914,-2965,-3015,-3065,-3115,-3166,-3216,-3266,-3316,-3367,-3417,-3467,-3517,-3568,-3618,-3668,-3719,-3769,-3819,-3869,-3920,-3970,-4020,-4070,-4121,-4171,-4221,-4271,-4322,-4372,-4422,-4472,-4523,-4573,-4623,-4673,-4724,-4774,-4824,-4874,-4925,-4975,-5025,-5075,-5126,-5176,-5226,-5277,-5327,-5377,-5427,-5478,-5528,-5578,-5628,-5679,-5729,-5779,-5829,-5880,-5930,-5980,-6030,-6081,-6131,-6181,-6231,-6282,-6332,-6382,-6432,-6483,-6533,-6583,-6633,-6684,-6734,-6784,-6834,-6885,-6935,-6985,-7035,-7086,-7136,-7186,-7236,-7287,-7337,-7387,-7437,-7488,-7538,-7588,-7638,-7689,-7739,-7789,-7839,-7889,-7940,-7990,-8040,-8090,-8141,-8191,-8241,-8291,-8342,-8392,-8442,-8492,-8543,-8593,-8643,-8693,-8744,-8794,-8844,-8894,-8945,-8995,-9045,-9095,-9145,-9196,-9246,-9296,-9346,-9397,-9447,-9497,-9547,-9598,-9648,-9698,-9748,-9798,-9849,-9899,-9949,-9999,-10050,-10100,-10150,-10200,-10251,-10301,-10351,-10401,-10451,-10502,-10552,-10602,-10652,-10703,-10753,-10803,-10853,-10903,-10954,-11004,-11054,-11104,-11155,-11205,-11255,-11305,-11355,-11406,-11456,-11506,-11556,-11607,-11657,-11707,-11757,-11807,-11858,-11908,-11958,-12008,-12058,-12109,-12159,-12209,-12259,-12310,-12360,-12410,-12460,-12510,-12561,-12611,-12661,-12711,-12761,-12812,-12862,-12912,-12962,-13012,-13063,-13113,-13163,-13213,-13263,-13314,-13364,-13414,-13464,-13514,-13565,-13615,-13665,-13715,-13765,-13816,-13866,-13916,-13966,-14016,-14067,-14117,-14167,-14217,-14267,-14318,-14368,-14418,-14468,-14518,-14568,-14619,-14669,-14719,-14769,-14819,-14870,-14920,-14970,-15020,-15070,-15121,-15171,-15221,-15271,-15321,-15371,-15422,-15472,-15522,-15572,-15622,-15672,-15723,-15773,-15823,-15873,-15923,-15974,-16024,-16074,-16124,-16174,-16224,-16275,-16325,-16375,-16425,-16475,-16525,-16576,-16626,-16676,-16726,-16776,-16826,-16877,-16927,-16977,-17027,-17077,-17127,-17177,-17228,-17278,-17328,-17378,-17428,-17478,-17529,-17579,-17629,-17679,-17729,-17779,-17829,-17880,-17930,-17980,-18030,-18080,-18130,-18180,-18231,-18281,-18331,-18381,-18431,-18481,-18531,-18582,-18632,-18682,-18732,-18782,-18832,-18882,-18933,-18983,-19033,-19083,-19133,-19183,-19233,-19284,-19334,-19384,-19434,-19484,-19534,-19584,-19634,-19685,-19735,-19785,-19835,-19885,-19935,-19985,-20035,-20085,-20136,-20186,-20236,-20286,-20336,-20386,-20436,-20486,-20537,-20587,-20637,-20687,-20737,-20787,-20837,-20887,-20937,-20987,-21038,-21088,-21138,-21188,-21238,-21288,-21338,-21388,-21438,-21488,-21539,-21589,-21639,-21689,-21739,-21789,-21839,-21889,-21939,-21989,-22039,-22090,-22140,-22190,-22240,-22290,-22340,-22390,-22440,-22490,-22540,-22590,-22640,-22691,-22741,-22791,-22841,-22891,-22941,-22991,-23041,-23091,-23141,-23191,-23241,-23291,-23341,-23392,-23442,-23492,-23542,-23592,-23642,-23692,-23742,-23792,-23842,-23892,-23942,-23992,-24042,-24092,-24142,-24192,-24243,-24293,-24343,-24393,-24443,-24493,-24543,-24593,-24643,-24693,-24743,-24793,-24843,-24893,-24943,-24993,-25043,-25093,-25143,-25193,-25243,-25293,-25343,-25393,-25443,-25494,-25544,-25594,-25644,-25694,-25744,-25794,-25844,-25894,-25944,-25994,-26044,-26094,-26144,-26194,-26244,-26294,-26344,-26394,-26444,-26494,-26544,-26594,-26644,-26694,-26744,-26794,-26844,-26894,-26944,-26994,-27044,-27094,-27144,-27194,-27244,-27294,-27344,-27394,-27444,-27494,-27544,-27594,-27644,-27694,-27744,-27794,-27844,-27894,-27944,-27994,-28044,-28094,-28144,-28194,-28244,-28294,-28343,-28393,-28443,-28493,-28543,-28593,-28643,-28693,-28743,-28793,-28843,-28893,-28943,-28993,-29043,-29093,-29143,-29193,-29243,-29293,-29343,-29393,-29443,-29493,-29542,-29592,-29642,-29692,-29742,-29792,-29842,-29892,-29942,-29992,-30042,-30092,-30142,-30192,-30242,-30292,-30341,-30391,-30441,-30491,-30541,-30591,-30641,-30691,-30741,-30791,-30841,-30891,-30941,-30990,-31040,-31090,-31140,-31190,-31240,-31290,-31340,-31390,-31440,-31489,-31539,-31589,-31639,-31689,-31739,-31789,-31839,-31889,-31939,-31988,-32038,-32088,-32138,-32188,-32238,-32288,-32338,-32388,-32437,-32487,-32537,-32587,-32637,-32687,-32737,-32787,-32836,-32886,-32936,-32986,-33036,-33086,-33136,-33185,-33235,-33285,-33335,-33385,-33435,-33485,-33534,-33584,-33634,-33684,-33734,-33784,-33834,-33883,-33933,-33983,-34033,-34083,-34133,-34182,-34232,-34282,-34332,-34382,-34432,-34481,-34531,-34581,-34631,-34681,-34731,-34780,-34830,-34880,-34930,-34980,-35029,-35079,-35129,-35179,-35229,-35279,-35328,-35378,-35428,-35478,-35528,-35577,-35627,-35677,-35727,-35777,-35826,-35876,-35926,-35976,-36026,-36075,-36125,-36175,-36225,-36274,-36324,-36374,-36424,-36474,-36523,-36573,-36623,-36673,-36722,-36772,-36822,-36872,-36921,-36971,-37021,-37071,-37121,-37170,-37220,-37270,-37320,-37369,-37419,-37469,-37519,-37568,-37618,-37668,-37718,-37767,-37817,-37867,-37916,-37966,-38016,-38066,-38115,-38165,-38215,-38265,-38314,-38364,-38414,-38464,-38513,-38563,-38613,-38662,-38712,-38762,-38812,-38861,-38911,-38961,-39010,-39060,-39110,-39159,-39209,-39259,-39309,-39358,-39408,-39458,-39507,-39557,-39607,-39656,-39706,-39756,-39805,-39855,-39905,-39955,-40004,-40054,-40104,-40153,-40203,-40253,-40302,-40352,-40402,-40451,-40501,-40551,-40600,-40650,-40700,-40749,-40799,-40848,-40898,-40948,-40997,-41047,-41097,-41146,-41196,-41246,-41295,-41345,-41395,-41444,-41494,-41543,-41593,-41643,-41692,-41742,-41792,-41841,-41891,-41940,-41990,-42040,-42089,-42139,-42189,-42238,-42288,-42337,-42387,-42437,-42486,-42536,-42585,-42635,-42685,-42734,-42784,-42833,-42883,-42932,-42982,-43032,-43081,-43131,-43180,-43230,-43280,-43329,-43379,-43428,-43478,-43527,-43577,-43627,-43676,-43726,-43775,-43825,-43874,-43924,-43973,-44023,-44073,-44122,-44172,-44221,-44271,-44320,-44370,-44419,-44469,-44518,-44568,-44618,-44667,-44717,-44766,-44816,-44865,-44915,-44964,-45014,-45063,-45113,-45162,-45212,-45261,-45311,-45360,-45410,-45459,-45509,-45558,-45608,-45657,-45707,-45756,-45806,-45855,-45905,-45954,-46004,-46053,-46103,-46152,-46202,-46251,-46301,-46350,-46400,-46449,-46499,-46548,-46597,-46647,-46696,-46746,-46795,-46845,-46894,-46944,-46993,-47043,-47092,-47141,-47191,-47240,-47290,-47339,-47389,-47438,-47488,-47537,-47586,-47636,-47685,-47735,-47784,-47834,-47883,-47932,-47982,-48031,-48081,-48130,-48179,-48229,-48278,-48328,-48377,-48426,-48476,-48525,-48575,-48624,-48673,-48723,-48772,-48822,-48871,-48920,-48970,-49019,-49069,-49118,-49167,-49217,-49266,-49315,-49365,-49414,-49463,-49513,-49562,-49612,-49661,-49710,-49760,-49809,-49858,-49908,-49957,-50006,-50056,-50105,-50154,-50204,-50253,-50302,-50352,-50401,-50450,-50500,-50549,-50598,-50648,-50697,-50746,-50796,-50845,-50894,-50944,-50993,-51042,-51091,-51141,-51190,-51239,-51289,-51338,-51387,-51437,-51486,-51535,-51584,-51634,-51683,-51732,-51781,-51831,-51880,-51929,-51979,-52028,-52077,-52126,-52176,-52225,-52274,-52323,-52373,-52422,-52471,-52520,-52570,-52619,-52668,-52717,-52767,-52816,-52865,-52914,-52964,-53013,-53062,-53111,-53160,-53210,-53259,-53308,-53357,-53407,-53456,-53505,-53554,-53603,-53653,-53702,-53751,-53800,-53849,-53899,-53948,-53997,-54046,-54095,-54144,-54194,-54243,-54292,-54341,-54390,-54440,-54489,-54538,-54587,-54636,-54685,-54735,-54784,-54833,-54882,-54931,-54980,-55029,-55079,-55128,-55177,-55226,-55275,-55324,-55373,-55423,-55472,-55521,-55570,-55619,-55668,-55717,-55766,-55815,-55865,-55914,-55963,-56012,-56061,-56110,-56159,-56208,-56257,-56307,-56356,-56405,-56454,-56503,-56552,-56601,-56650,-56699,-56748,-56797,-56846,-56895,-56945,-56994,-57043,-57092,-57141,-57190,-57239,-57288,-57337,-57386,-57435,-57484,-57533,-57582,-57631,-57680,-57729,-57778,-57827,-57876,-57925,-57974,-58023,-58072,-58121,-58170,-58220,-58269,-58318,-58367,-58416,-58465,-58514,-58563,-58612,-58661,-58710,-58758,-58807,-58856,-58905,-58954,-59003,-59052,-59101,-59150,-59199,-59248,-59297,-59346,-59395,-59444,-59493,-59542,-59591,-59640,-59689,-59738,-59787,-59836,-59885,-59934,-59982,-60031,-60080,-60129,-60178,-60227,-60276,-60325,-60374,-60423,-60472,-60521,-60569,-60618,-60667,-60716,-60765,-60814,-60863,-60912,-60961,-61010,-61058,-61107,-61156,-61205,-61254,-61303,-61352,-61401,-61449,-61498,-61547,-61596,-61645,-61694,-61743,-61791,-61840,-61889,-61938,-61987,-62036,-62084,-62133,-62182,-62231,-62280,-62329,-62377,-62426,-62475,-62524,-62573,-62622,-62670,-62719,-62768,-62817,-62866,-62914,-62963,-63012,-63061,-63110,-63158,-63207,-63256,-63305,-63353,-63402,-63451,-63500,-63549,-63597,-63646,-63695,-63744,-63792,-63841,-63890,-63939,-63987,-64036,-64085,-64134,-64182,-64231,-64280,-64328,-64377,-64426,-64475,-64523,-64572,-64621,-64670,-64718,-64767,-64816,-64864,-64913,-64962,-65010,-65059,-65108,-65157,-65205,-65254,-65303,-65351,-65400,-65449,-65497,-65546,-65595,-65643,-65692,-65741,-65789,-65838,-65887,-65935,-65984,-66033,-66081,-66130,-66178,-66227,-66276,-66324,-66373,-66422,-66470,-66519,-66567,-66616,-66665,-66713,-66762,-66811,-66859,-66908,-66956,-67005,-67054,-67102,-67151,-67199,-67248,-67296,-67345,-67394,-67442,-67491,-67539,-67588,-67636,-67685,-67734,-67782,-67831,-67879,-67928,-67976,-68025,-68073,-68122,-68170,-68219,-68268,-68316,-68365,-68413,-68462,-68510,-68559,-68607,-68656,-68704,-68753,-68801,-68850,-68898,-68947,-68995,-69044,-69092,-69141,-69189,-69238,-69286,-69335,-69383,-69432,-69480,-69529,-69577,-69625,-69674,-69722,-69771,-69819,-69868,-69916,-69965,-70013,-70061,-70110,-70158,-70207,-70255,-70304,-70352,-70400,-70449,-70497,-70546,-70594,-70643,-70691,-70739,-70788,-70836,-70885,-70933,-70981,-71030,-71078,-71126,-71175,-71223,-71272,-71320,-71368,-71417,-71465,-71513,-71562,-71610,-71658,-71707,-71755,-71804,-71852,-71900,-71949,-71997,-72045,-72094,-72142,-72190,-72238,-72287,-72335,-72383,-72432,-72480,-72528,-72577,-72625,-72673,-72722,-72770,-72818,-72866,-72915,-72963,-73011,-73060,-73108,-73156,-73204,-73253,-73301,-73349,-73397,-73446,-73494,-73542,-73590,-73639,-73687,-73735,-73783,-73832,-73880,-73928,-73976,-74024,-74073,-74121,-74169,-74217,-74266,-74314,-74362,-74410,-74458,-74507,-74555,-74603,-74651,-74699,-74747,-74796,-74844,-74892,-74940,-74988,-75036,-75085,-75133,-75181,-75229,-75277,-75325,-75374,-75422,-75470,-75518,-75566,-75614,-75662,-75710,-75759,-75807,-75855,-75903,-75951,-75999,-76047,-76095,-76143,-76192,-76240,-76288,-76336,-76384,-76432,-76480,-76528,-76576,-76624,-76672,-76720,-76769,-76817,-76865,-76913,-76961,-77009,-77057,-77105,-77153,-77201,-77249,-77297,-77345,-77393,-77441,-77489,-77537,-77585,-77633,-77681,-77729,-77777,-77825,-77873,-77921,-77969,-78017,-78065,-78113,-78161,-78209,-78257,-78305,-78353,-78401,-78449,-78497,-78545,-78593,-78641,-78689,-78737,-78785,-78833,-78880,-78928,-78976,-79024,-79072,-79120,-79168,-79216,-79264,-79312,-79360,-79408,-79456,-79503,-79551,-79599,-79647,-79695,-79743,-79791,-79839,-79886,-79934,-79982,-80030,-80078,-80126,-80174,-80222,-80269,-80317,-80365,-80413,-80461,-80509,-80556,-80604,-80652,-80700,-80748,-80796,-80843,-80891,-80939,-80987,-81035,-81082,-81130,-81178,-81226,-81274,-81321,-81369,-81417,-81465,-81513,-81560,-81608,-81656,-81704,-81751,-81799,-81847,-81895,-81942,-81990,-82038,-82086,-82133,-82181,-82229,-82277,-82324,-82372,-82420,-82467,-82515,-82563,-82611,-82658,-82706,-82754,-82801,-82849,-82897,-82944,-82992,-83040,-83087,-83135,-83183,-83230,-83278,-83326,-83373,-83421,-83469,-83516,-83564,-83612,-83659,-83707,-83755,-83802,-83850,-83897,-83945,-83993,-84040,-84088,-84135,-84183,-84231,-84278,-84326,-84373,-84421,-84469,-84516,-84564,-84611,-84659,-84707,-84754,-84802,-84849,-84897,-84944,-84992,-85039,-85087,-85135,-85182,-85230,-85277,-85325,-85372,-85420,-85467,-85515,-85562,-85610,-85657,-85705,-85752,-85800,-85847,-85895,-85942,-85990,-86037,-86085,-86132,-86180,-86227,-86275,-86322,-86370,-86417,-86464,-86512,-86559,-86607,-86654,-86702,-86749,-86797,-86844,-86891,-86939,-86986,-87034,-87081,-87128,-87176,-87223,-87271,-87318,-87365,-87413,-87460,-87508,-87555,-87602,-87650,-87697,-87744,-87792,-87839,-87887,-87934,-87981,-88029,-88076,-88123,-88171,-88218,-88265,-88313,-88360,-88407,-88455,-88502,-88549,-88597,-88644,-88691,-88738,-88786,-88833,-88880,-88928,-88975,-89022,-89069,-89117,-89164,-89211,-89259,-89306,-89353,-89400,-89448,-89495,-89542,-89589,-89637,-89684,-89731,-89778,-89825,-89873,-89920,-89967,-90014,-90062,-90109,-90156,-90203,-90250,-90298,-90345,-90392,-90439,-90486,-90533,-90581,-90628,-90675,-90722,-90769,-90816,-90864,-90911,-90958,-91005,-91052,-91099,-91146,-91194,-91241,-91288,-91335,-91382,-91429,-91476,-91523,-91570,-91618,-91665,-91712,-91759,-91806,-91853,-91900,-91947,-91994,-92041,-92088,-92135,-92182,-92229,-92277,-92324,-92371,-92418,-92465,-92512,-92559,-92606,-92653,-92700,-92747,-92794,-92841,-92888,-92935,-92982,-93029,-93076,-93123,-93170,-93217,-93264,-93311,-93358,-93405,-93452,-93499,-93546,-93593,-93639,-93686,-93733,-93780,-93827,-93874,-93921,-93968,-94015,-94062,-94109,-94156,-94203,-94250,-94296,-94343,-94390,-94437,-94484,-94531,-94578,-94625,-94672,-94718,-94765,-94812,-94859,-94906,-94953,-95000,-95046,-95093,-95140,-95187,-95234,-95281,-95327,-95374,-95421,-95468,-95515,-95561,-95608,-95655,-95702,-95749,-95795,-95842,-95889,-95936,-95983,-96029,-96076,-96123,-96170,-96216,-96263,-96310,-96357,-96403,-96450,-96497,-96544,-96590,-96637,-96684,-96731,-96777,-96824,-96871,-96917,-96964,-97011,-97057,-97104,-97151,-97198,-97244,-97291,-97338,-97384,-97431,-97478,-97524,-97571,-97618,-97664,-97711,-97757,-97804,-97851,-97897,-97944,-97991,-98037,-98084,-98130,-98177,-98224,-98270,-98317,-98363,-98410,-98457,-98503,-98550,-98596,-98643,-98690,-98736,-98783,-98829,-98876,-98922,-98969,-99015,-99062,-99109,-99155,-99202,-99248,-99295,-99341,-99388,-99434,-99481,-99527,-99574,-99620,-99667,-99713,-99760,-99806,-99853,-99899,-99946,-99992,-100038,-100085,-100131,-100178,-100224,-100271,-100317,-100364,-100410,-100456,-100503,-100549,-100596,-100642,-100689,-100735,-100781,-100828,-100874,-100921,-100967,-101013,-101060,-101106,-101152,-101199,-101245,-101292,-101338,-101384,-101431,-101477,-101523,-101570,-101616,-101662,-101709,-101755,-101801,-101848,-101894,-101940,-101987,-102033,-102079,-102125,-102172,-102218,-102264,-102311,-102357,-102403,-102449,-102496,-102542,-102588,-102634,-102681,-102727,-102773,-102819,-102866,-102912,-102958,-103004,-103051,-103097,-103143,-103189,-103235,-103282,-103328,-103374,-103420,-103466,-103513,-103559,-103605,-103651,-103697,-103743,-103790,-103836,-103882,-103928,-103974,-104020,-104066,-104113,-104159,-104205,-104251,-104297,-104343,-104389,-104435,-104482,-104528,-104574,-104620,-104666,-104712,-104758,-104804,-104850,-104896,-104942,-104988,-105034,-105081,-105127,-105173,-105219,-105265,-105311,-105357,-105403,-105449,-105495,-105541,-105587,-105633,-105679,-105725,-105771,-105817,-105863,-105909,-105955,-106001,-106047,-106093,-106139,-106185,-106231,-106277,-106322,-106368,-106414,-106460,-106506,-106552,-106598,-106644,-106690,-106736,-106782,-106828,-106874,-106919,-106965,-107011,-107057,-107103,-107149,-107195,-107241,-107286,-107332,-107378,-107424,-107470,-107516,-107562,-107607,-107653,-107699,-107745,-107791,-107837,-107882,-107928,-107974,-108020,-108066,-108111,-108157,-108203,-108249,-108294,-108340,-108386,-108432,-108478,-108523,-108569,-108615,-108661,-108706,-108752,-108798,-108844,-108889,-108935,-108981,-109026,-109072,-109118,-109164,-109209,-109255,-109301,-109346,-109392,-109438,-109483,-109529,-109575,-109620,-109666,-109712,-109757,-109803,-109849,-109894,-109940,-109985,-110031,-110077,-110122,-110168,-110214,-110259,-110305,-110350,-110396,-110442,-110487,-110533,-110578,-110624,-110669,-110715,-110761,-110806,-110852,-110897,-110943,-110988,-111034,-111079,-111125,-111170,-111216,-111261,-111307,-111352,-111398,-111443,-111489,-111534,-111580,-111625,-111671,-111716,-111762,-111807,-111853,-111898,-111944,-111989,-112035,-112080,-112125,-112171,-112216,-112262,-112307,-112353,-112398,-112443,-112489,-112534,-112580,-112625,-112670,-112716,-112761,-112807,-112852,-112897,-112943,-112988,-113033,-113079,-113124,-113169,-113215,-113260,-113305,-113351,-113396,-113441,-113487,-113532,-113577,-113623,-113668,-113713,-113758,-113804,-113849,-113894,-113940,-113985,-114030,-114075,-114121,-114166,-114211,-114256,-114302,-114347,-114392,-114437,-114482,-114528,-114573,-114618,-114663,-114709,-114754,-114799,-114844,-114889,-114934,-114980,-115025,-115070,-115115,-115160,-115205,-115251,-115296,-115341,-115386,-115431,-115476,-115521,-115566,-115612,-115657,-115702,-115747,-115792,-115837,-115882,-115927,-115972,-116017,-116063,-116108,-116153,-116198,-116243,-116288,-116333,-116378,-116423,-116468,-116513,-116558,-116603,-116648,-116693,-116738,-116783,-116828,-116873,-116918,-116963,-117008,-117053,-117098,-117143,-117188,-117233,-117278,-117323,-117368,-117413,-117458,-117503,-117548,-117592,-117637,-117682,-117727,-117772,-117817,-117862,-117907,-117952,-117997,-118041,-118086,-118131,-118176,-118221,-118266,-118311,-118356,-118400,-118445,-118490,-118535,-118580,-118625,-118669,-118714,-118759,-118804,-118849,-118893,-118938,-118983,-119028,-119073,-119117,-119162,-119207,-119252,-119296,-119341,-119386,-119431,-119475,-119520,-119565,-119610,-119654,-119699,-119744,-119789,-119833,-119878,-119923,-119967,-120012,-120057,-120101,-120146,-120191,-120235,-120280,-120325,-120369,-120414,-120459,-120503,-120548,-120593,-120637,-120682,-120726,-120771,-120816,-120860,-120905,-120949,-120994,-121039,-121083,-121128,-121172,-121217,-121262,-121306,-121351,-121395,-121440,-121484,-121529,-121573,-121618,-121662,-121707,-121751,-121796,-121841,-121885,-121930,-121974,-122018,-122063,-122107,-122152,-122196,-122241,-122285,-122330,-122374,-122419,-122463,-122508,-122552,-122596,-122641,-122685,-122730,-122774,-122819,-122863,-122907,-122952,-122996,-123041,-123085,-123129,-123174,-123218,-123262,-123307,-123351,-123395,-123440,-123484,-123528,-123573,-123617,-123661,-123706,-123750,-123794,-123839,-123883,-123927,-123972,-124016,-124060,-124104,-124149,-124193,-124237,-124282,-124326,-124370,-124414,-124459,-124503,-124547,-124591,-124635,-124680,-124724,-124768,-124812,-124856,-124901,-124945,-124989,-125033,-125077,-125122,-125166,-125210,-125254,-125298,-125342,-125387,-125431,-125475,-125519,-125563,-125607,-125651,-125695,-125740,-125784,-125828,-125872,-125916,-125960,-126004,-126048,-126092,-126136,-126180,-126224,-126268,-126313,-126357,-126401,-126445,-126489,-126533,-126577,-126621,-126665,-126709,-126753,-126797,-126841,-126885,-126929,-126973,-127017,-127061,-127105,-127149,-127192,-127236,-127280,-127324,-127368,-127412,-127456,-127500,-127544,-127588,-127632,-127676,-127720,-127763,-127807,-127851,-127895,-127939,-127983,-128027,-128071,-128114,-128158,-128202,-128246,-128290,-128334,-128377,-128421,-128465,-128509,-128553,-128597,-128640,-128684,-128728,-128772,-128815,-128859,-128903,-128947,-128991,-129034,-129078,-129122,-129166,-129209,-129253,-129297,-129340,-129384,-129428,-129472,-129515,-129559,-129603,-129646,-129690,-129734,-129777,-129821,-129865,-129908,-129952,-129996,-130039,-130083,-130127,-130170,-130214,-130258,-130301,-130345,-130388,-130432,-130476,-130519,-130563,-130606,-130650,-130694,-130737,-130781,-130824,-130868,-130911,-130955,-130998,-131042,-131086,-131129,-131173,-131216,-131260,-131303,-131347,-131390,-131434,-131477,-131521,-131564,-131608,-131651,-131694,-131738,-131781,-131825,-131868,-131912,-131955,-131999,-132042,-132085,-132129,-132172,-132216,-132259,-132302,-132346,-132389,-132433,-132476,-132519,-132563,-132606,-132649,-132693,-132736,-132779,-132823,-132866,-132909,-132953,-132996,-133039,-133083,-133126,-133169,-133213,-133256,-133299,-133342,-133386,-133429,-133472,-133516,-133559,-133602,-133645,-133689,-133732,-133775,-133818,-133861,-133905,-133948,-133991,-134034,-134077,-134121,-134164,-134207,-134250,-134293,-134337,-134380,-134423,-134466,-134509,-134552,-134595,-134639,-134682,-134725,-134768,-134811,-134854,-134897,-134940,-134983,-135027,-135070,-135113,-135156,-135199,-135242,-135285,-135328,-135371,-135414,-135457,-135500,-135543,-135586,-135629,-135672,-135715,-135758,-135801,-135844,-135887,-135930,-135973,-136016,-136059,-136102,-136145,-136188,-136231,-136274,-136317,-136360,-136403,-136446,-136489,-136531,-136574,-136617,-136660,-136703,-136746,-136789,-136832,-136875,-136917,-136960,-137003,-137046,-137089,-137132,-137175,-137217,-137260,-137303,-137346,-137389,-137431,-137474,-137517,-137560,-137603,-137645,-137688,-137731,-137774,-137816,-137859,-137902,-137945,-137987,-138030,-138073,-138116,-138158,-138201,-138244,-138287,-138329,-138372,-138415,-138457,-138500,-138543,-138585,-138628,-138671,-138713,-138756,-138799,-138841,-138884,-138926,-138969,-139012,-139054,-139097,-139140,-139182,-139225,-139267,-139310,-139352,-139395,-139438,-139480,-139523,-139565,-139608,-139650,-139693,-139735,-139778,-139820,-139863,-139906,-139948,-139991,-140033,-140076,-140118,-140160,-140203,-140245,-140288,-140330,-140373,-140415,-140458,-140500,-140543,-140585,-140627,-140670,-140712,-140755,-140797,-140839,-140882,-140924,-140967,-141009,-141051,-141094,-141136,-141178,-141221,-141263,-141305,-141348,-141390,-141432,-141475,-141517,-141559,-141602,-141644,-141686,-141729,-141771,-141813,-141855,-141898,-141940,-141982,-142024,-142067,-142109,-142151,-142193,-142236,-142278,-142320,-142362,-142404,-142447,-142489,-142531,-142573,-142615,-142658,-142700,-142742,-142784,-142826,-142868,-142911,-142953,-142995,-143037,-143079,-143121,-143163,-143205,-143247,-143290,-143332,-143374,-143416,-143458,-143500,-143542,-143584,-143626,-143668,-143710,-143752,-143794,-143836,-143878,-143920,-143962,-144004,-144046,-144088,-144130,-144172,-144214,-144256,-144298,-144340,-144382,-144424,-144466,-144508,-144550,-144592,-144634,-144676,-144718,-144760,-144801,-144843,-144885,-144927,-144969,-145011,-145053,-145095,-145136,-145178,-145220,-145262,-145304,-145346,-145388,-145429,-145471,-145513,-145555,-145597,-145638,-145680,-145722,-145764,-145806,-145847,-145889,-145931,-145973,-146014,-146056,-146098,-146140,-146181,-146223,-146265,-146306,-146348,-146390,-146432,-146473,-146515,-146557,-146598,-146640,-146682,-146723,-146765,-146807,-146848,-146890,-146931,-146973,-147015,-147056,-147098,-147140,-147181,-147223,-147264,-147306,-147347,-147389,-147431,-147472,-147514,-147555,-147597,-147638,-147680,-147721,-147763,-147804,-147846,-147887,-147929,-147970,-148012,-148053,-148095,-148136,-148178,-148219,-148261,-148302,-148344,-148385,-148427,-148468,-148509,-148551,-148592,-148634,-148675,-148716,-148758,-148799,-148841,-148882,-148923,-148965,-149006,-149047,-149089,-149130,-149171,-149213,-149254,-149295,-149337,-149378,-149419,-149461,-149502,-149543,-149584,-149626,-149667,-149708,-149750,-149791,-149832,-149873,-149915,-149956,-149997,-150038,-150079,-150121,-150162,-150203,-150244,-150285,-150327,-150368,-150409,-150450,-150491,-150532,-150574,-150615,-150656,-150697,-150738,-150779,-150820,-150861,-150903,-150944,-150985,-151026,-151067,-151108,-151149,-151190,-151231,-151272,-151313,-151354,-151395,-151436,-151477,-151518,-151559,-151600,-151641,-151682,-151723,-151764,-151805,-151846,-151887,-151928,-151969,-152010,-152051,-152092,-152133,-152174,-152215,-152256,-152297,-152338,-152379,-152420,-152460,-152501,-152542,-152583,-152624,-152665,-152706,-152747,-152787,-152828,-152869,-152910,-152951,-152992,-153032,-153073,-153114,-153155,-153196,-153236,-153277,-153318,-153359,-153399,-153440,-153481,-153522,-153562,-153603,-153644,-153685,-153725,-153766,-153807,-153847,-153888,-153929,-153969,-154010,-154051,-154092,-154132,-154173,-154213,-154254,-154295,-154335,-154376,-154417,-154457,-154498,-154538,-154579,-154620,-154660,-154701,-154741,-154782,-154823,-154863,-154904,-154944,-154985,-155025,-155066,-155106,-155147,-155187,-155228,-155268,-155309,-155349,-155390,-155430,-155471,-155511,-155552,-155592,-155633,-155673,-155714,-155754,-155794,-155835,-155875,-155916,-155956,-155996,-156037,-156077,-156118,-156158,-156198,-156239,-156279,-156319,-156360,-156400,-156440,-156481,-156521,-156561,-156602,-156642,-156682,-156723,-156763,-156803,-156844,-156884,-156924,-156964,-157005,-157045,-157085,-157125,-157166,-157206,-157246,-157286,-157326,-157367,-157407,-157447,-157487,-157527,-157568,-157608,-157648,-157688,-157728,-157768,-157808,-157849,-157889,-157929,-157969,-158009,-158049,-158089,-158129,-158169,-158210,-158250,-158290,-158330,-158370,-158410,-158450,-158490,-158530,-158570,-158610,-158650,-158690,-158730,-158770,-158810,-158850,-158890,-158930,-158970,-159010,-159050,-159090,-159130,-159170,-159210,-159250,-159290,-159329,-159369,-159409,-159449,-159489,-159529,-159569,-159609,-159649,-159688,-159728,-159768,-159808,-159848,-159888,-159928,-159967,-160007,-160047,-160087,-160127,-160166,-160206,-160246,-160286,-160326,-160365,-160405,-160445,-160485,-160524,-160564,-160604,-160643,-160683,-160723,-160763,-160802,-160842,-160882,-160921,-160961,-161001,-161040,-161080,-161120,-161159,-161199,-161239,-161278,-161318,-161358,-161397,-161437,-161476,-161516,-161556,-161595,-161635,-161674,-161714,-161753,-161793,-161832,-161872,-161912,-161951,-161991,-162030,-162070,-162109,-162149,-162188,-162228,-162267,-162307,-162346,-162385,-162425,-162464,-162504,-162543,-162583,-162622,-162662,-162701,-162740,-162780,-162819,-162859,-162898,-162937,-162977,-163016,-163055,-163095,-163134,-163173,-163213,-163252,-163291,-163331,-163370,-163409,-163449,-163488,-163527,-163567,-163606,-163645,-163684,-163724,-163763,-163802,-163841,-163881,-163920,-163959,-163998,-164038,-164077,-164116,-164155,-164194,-164233,-164273,-164312,-164351,-164390,-164429,-164468,-164508,-164547,-164586,-164625,-164664,-164703,-164742,-164781,-164820,-164860,-164899,-164938,-164977,-165016,-165055,-165094,-165133,-165172,-165211,-165250,-165289,-165328,-165367,-165406,-165445,-165484,-165523,-165562,-165601,-165640,-165679,-165718,-165757,-165796,-165835,-165874,-165913,-165951,-165990,-166029,-166068,-166107,-166146,-166185,-166224,-166263,-166301,-166340,-166379,-166418,-166457,-166496,-166534,-166573,-166612,-166651,-166690,-166728,-166767,-166806,-166845,-166884,-166922,-166961,-167000,-167039,-167077,-167116,-167155,-167193,-167232,-167271,-167310,-167348,-167387,-167426,-167464,-167503,-167542,-167580,-167619,-167658,-167696,-167735,-167773,-167812,-167851,-167889,-167928,-167967,-168005,-168044,-168082,-168121,-168159,-168198,-168237,-168275,-168314,-168352,-168391,-168429,-168468,-168506,-168545,-168583,-168622,-168660,-168699,-168737,-168776,-168814,-168852,-168891,-168929,-168968,-169006,-169045,-169083,-169121,-169160,-169198,-169237,-169275,-169313,-169352,-169390,-169429,-169467,-169505,-169544,-169582,-169620,-169659,-169697,-169735,-169773,-169812,-169850,-169888,-169927,-169965,-170003,-170041,-170080,-170118,-170156,-170194,-170233,-170271,-170309,-170347,-170385,-170424,-170462,-170500,-170538,-170576,-170615,-170653,-170691,-170729,-170767,-170805,-170843,-170882,-170920,-170958,-170996,-171034,-171072,-171110,-171148,-171186,-171224,-171262,-171300,-171338,-171377,-171415,-171453,-171491,-171529,-171567,-171605,-171643,-171681,-171719,-171757,-171795,-171833,-171870,-171908,-171946,-171984,-172022,-172060,-172098,-172136,-172174,-172212,-172250,-172288,-172325,-172363,-172401,-172439,-172477,-172515,-172553,-172590,-172628,-172666,-172704,-172742,-172780,-172817,-172855,-172893,-172931,-172968,-173006,-173044,-173082,-173120,-173157,-173195,-173233,-173270,-173308,-173346,-173384,-173421,-173459,-173497,-173534,-173572,-173610,-173647,-173685,-173723,-173760,-173798,-173836,-173873,-173911,-173948,-173986,-174024,-174061,-174099,-174136,-174174,-174211,-174249,-174287,-174324,-174362,-174399,-174437,-174474,-174512,-174549,-174587,-174624,-174662,-174699,-174737,-174774,-174812,-174849,-174886,-174924,-174961,-174999,-175036,-175074,-175111,-175148,-175186,-175223,-175261,-175298,-175335,-175373,-175410,-175447,-175485,-175522,-175559,-175597,-175634,-175671,-175709,-175746,-175783,-175821,-175858,-175895,-175932,-175970,-176007,-176044,-176081,-176119,-176156,-176193,-176230,-176267,-176305,-176342,-176379,-176416,-176453,-176491,-176528,-176565,-176602,-176639,-176676,-176713,-176751,-176788,-176825,-176862,-176899,-176936,-176973,-177010,-177047,-177084,-177122,-177159,-177196,-177233,-177270,-177307,-177344,-177381,-177418,-177455,-177492,-177529,-177566,-177603,-177640,-177677,-177714,-177751,-177787,-177824,-177861,-177898,-177935,-177972,-178009,-178046,-178083,-178120,-178157,-178193,-178230,-178267,-178304,-178341,-178378,-178414,-178451,-178488,-178525,-178562,-178599,-178635,-178672,-178709,-178746,-178782,-178819,-178856,-178893,-178929,-178966,-179003,-179040,-179076,-179113,-179150,-179186,-179223,-179260,-179296,-179333,-179370,-179406,-179443,-179480,-179516,-179553,-179590,-179626,-179663,-179699,-179736,-179773,-179809,-179846,-179882,-179919,-179955,-179992,-180028,-180065,-180102,-180138,-180175,-180211,-180248,-180284,-180321,-180357,-180394,-180430,-180466,-180503,-180539,-180576,-180612,-180649,-180685,-180722,-180758,-180794,-180831,-180867,-180903,-180940,-180976,-181013,-181049,-181085,-181122,-181158,-181194,-181231,-181267,-181303,-181340,-181376,-181412,-181448,-181485,-181521,-181557,-181593,-181630,-181666,-181702,-181738,-181775,-181811,-181847,-181883,-181919,-181956,-181992,-182028,-182064,-182100,-182136,-182173,-182209,-182245,-182281,-182317,-182353,-182389,-182425,-182462,-182498,-182534,-182570,-182606,-182642,-182678,-182714,-182750,-182786,-182822,-182858,-182894,-182930,-182966,-183002,-183038,-183074,-183110,-183146,-183182,-183218,-183254,-183290,-183326,-183362,-183398,-183434,-183469,-183505,-183541,-183577,-183613,-183649,-183685,-183721,-183756,-183792,-183828,-183864,-183900,-183936,-183971,-184007,-184043,-184079,-184115,-184150,-184186,-184222,-184258,-184293,-184329,-184365,-184401,-184436,-184472,-184508,-184544,-184579,-184615,-184651,-184686,-184722,-184758,-184793,-184829,-184865,-184900,-184936,-184971,-185007,-185043,-185078,-185114,-185149,-185185,-185221,-185256,-185292,-185327,-185363,-185398,-185434,-185469,-185505,-185540,-185576,-185611,-185647,-185682,-185718,-185753,-185789,-185824,-185860,-185895,-185931,-185966,-186001,-186037,-186072,-186108,-186143,-186178,-186214,-186249,-186285,-186320,-186355,-186391,-186426,-186461,-186497,-186532,-186567,-186603,-186638,-186673,-186709,-186744,-186779,-186814,-186850,-186885,-186920,-186955,-186991,-187026,-187061,-187096,-187131,-187167,-187202,-187237,-187272,-187307,-187342,-187378,-187413,-187448,-187483,-187518,-187553,-187588,-187624,-187659,-187694,-187729,-187764,-187799,-187834,-187869,-187904,-187939,-187974,-188009,-188044,-188079,-188114,-188149,-188184,-188219,-188254,-188289,-188324,-188359,-188394,-188429,-188464,-188499,-188534,-188569,-188604,-188639,-188674,-188708,-188743,-188778,-188813,-188848,-188883,-188918,-188953,-188987,-189022,-189057,-189092,-189127,-189161,-189196,-189231,-189266,-189301,-189335,-189370,-189405,-189440,-189474,-189509,-189544,-189579,-189613,-189648,-189683,-189717,-189752,-189787,-189821,-189856,-189891,-189925,-189960,-189995,-190029,-190064,-190098,-190133,-190168,-190202,-190237,-190271,-190306,-190341,-190375,-190410,-190444,-190479,-190513,-190548,-190582,-190617,-190651,-190686,-190720,-190755,-190789,-190824,-190858,-190893,-190927,-190962,-190996,-191030,-191065,-191099,-191134,-191168,-191202,-191237,-191271,-191306,-191340,-191374,-191409,-191443,-191477,-191512,-191546,-191580,-191615,-191649,-191683,-191717,-191752,-191786,-191820,-191855,-191889,-191923,-191957,-191991,-192026,-192060,-192094,-192128,-192163,-192197,-192231,-192265,-192299,-192333,-192368,-192402,-192436,-192470,-192504,-192538,-192572,-192606,-192640,-192675,-192709,-192743,-192777,-192811,-192845,-192879,-192913,-192947,-192981,-193015,-193049,-193083,-193117,-193151,-193185,-193219,-193253,-193287,-193321,-193355,-193389,-193423,-193457,-193491,-193524,-193558,-193592,-193626,-193660,-193694,-193728,-193762,-193795,-193829,-193863,-193897,-193931,-193965,-193998,-194032,-194066,-194100,-194134,-194167,-194201,-194235,-194269,-194302,-194336,-194370,-194404,-194437,-194471,-194505,-194538,-194572,-194606,-194639,-194673,-194707,-194740,-194774,-194808,-194841,-194875,-194909,-194942,-194976,-195009,-195043,-195077,-195110,-195144,-195177,-195211,-195244,-195278,-195311,-195345,-195378,-195412,-195445,-195479,-195512,-195546,-195579,-195613,-195646,-195680,-195713,-195747,-195780,-195814,-195847,-195880,-195914,-195947,-195981,-196014,-196047,-196081,-196114,-196147,-196181,-196214,-196247,-196281,-196314,-196347,-196381,-196414,-196447,-196480,-196514,-196547,-196580,-196614,-196647,-196680,-196713,-196746,-196780,-196813,-196846,-196879,-196912,-196946,-196979,-197012,-197045,-197078,-197111,-197145,-197178,-197211,-197244,-197277,-197310,-197343,-197376,-197409,-197442,-197475,-197509,-197542,-197575,-197608,-197641,-197674,-197707,-197740,-197773,-197806,-197839,-197872,-197905,-197938,-197971,-198003,-198036,-198069,-198102,-198135,-198168,-198201,-198234,-198267,-198300,-198333,-198365,-198398,-198431,-198464,-198497,-198530,-198562,-198595,-198628,-198661,-198694,-198726,-198759,-198792,-198825,-198857,-198890,-198923,-198956,-198988,-199021,-199054,-199087,-199119,-199152,-199185,-199217,-199250,-199283,-199315,-199348,-199381,-199413,-199446,-199478,-199511,-199544,-199576,-199609,-199641,-199674,-199707,-199739,-199772,-199804,-199837,-199869,-199902,-199934,-199967,-199999,-200032,-200064,-200097,-200129,-200162,-200194,-200227,-200259,-200291,-200324,-200356,-200389,-200421,-200453,-200486,-200518,-200551,-200583,-200615,-200648,-200680,-200712,-200745,-200777,-200809,-200842,-200874,-200906,-200939,-200971,-201003,-201035,-201068,-201100,-201132,-201164,-201197,-201229,-201261,-201293,-201325,-201358,-201390,-201422,-201454,-201486,-201518,-201551,-201583,-201615,-201647,-201679,-201711,-201743,-201775,-201807,-201840,-201872,-201904,-201936,-201968,-202000,-202032,-202064,-202096,-202128,-202160,-202192,-202224,-202256,-202288,-202320,-202352,-202384,-202416,-202448,-202480,-202511,-202543,-202575,-202607,-202639,-202671,-202703,-202735,-202767,-202798,-202830,-202862,-202894,-202926,-202958,-202989,-203021,-203053,-203085,-203117,-203148,-203180,-203212,-203244,-203275,-203307,-203339,-203371,-203402,-203434,-203466,-203497,-203529,-203561,-203592,-203624,-203656,-203687,-203719,-203751,-203782,-203814,-203845,-203877,-203909,-203940,-203972,-204003,-204035,-204066,-204098,-204130,-204161,-204193,-204224,-204256,-204287,-204319,-204350,-204382,-204413,-204445,-204476,-204507,-204539,-204570,-204602,-204633,-204665,-204696,-204727,-204759,-204790,-204822,-204853,-204884,-204916,-204947,-204978,-205010,-205041,-205072,-205104,-205135,-205166,-205197,-205229,-205260,-205291,-205323,-205354,-205385,-205416,-205447,-205479,-205510,-205541,-205572,-205603,-205635,-205666,-205697,-205728,-205759,-205790,-205822,-205853,-205884,-205915,-205946,-205977,-206008,-206039,-206070,-206101,-206132,-206164,-206195,-206226,-206257,-206288,-206319,-206350,-206381,-206412,-206443,-206474,-206505,-206536,-206566,-206597,-206628,-206659,-206690,-206721,-206752,-206783,-206814,-206845,-206876,-206906,-206937,-206968,-206999,-207030,-207061,-207091,-207122,-207153,-207184,-207215,-207245,-207276,-207307,-207338,-207369,-207399,-207430,-207461,-207491,-207522,-207553,-207584,-207614,-207645,-207676,-207706,-207737,-207768,-207798,-207829,-207860,-207890,-207921,-207951,-207982,-208013,-208043,-208074,-208104,-208135,-208165,-208196,-208227,-208257,-208288,-208318,-208349,-208379,-208410,-208440,-208471,-208501,-208532,-208562,-208592,-208623,-208653,-208684,-208714,-208745,-208775,-208805,-208836,-208866,-208896,-208927,-208957,-208988,-209018,-209048,-209079,-209109,-209139,-209169,-209200,-209230,-209260,-209291,-209321,-209351,-209381,-209412,-209442,-209472,-209502,-209533,-209563,-209593,-209623,-209653,-209683,-209714,-209744,-209774,-209804,-209834,-209864,-209894,-209925,-209955,-209985,-210015,-210045,-210075,-210105,-210135,-210165,-210195,-210225,-210255,-210285,-210315,-210345,-210375,-210405,-210435,-210465,-210495,-210525,-210555,-210585,-210615,-210645,-210675,-210705,-210735,-210764,-210794,-210824,-210854,-210884,-210914,-210944,-210973,-211003,-211033,-211063,-211093,-211123,-211152,-211182,-211212,-211242,-211271,-211301,-211331,-211361,-211390,-211420,-211450,-211480,-211509,-211539,-211569,-211598,-211628,-211658,-211687,-211717,-211747,-211776,-211806,-211835,-211865,-211895,-211924,-211954,-211983,-212013,-212042,-212072,-212102,-212131,-212161,-212190,-212220,-212249,-212279,-212308,-212338,-212367,-212397,-212426,-212455,-212485,-212514,-212544,-212573,-212603,-212632,-212661,-212691,-212720,-212750,-212779,-212808,-212838,-212867,-212896,-212926,-212955,-212984,-213014,-213043,-213072,-213101,-213131,-213160,-213189,-213218,-213248,-213277,-213306,-213335,-213365,-213394,-213423,-213452,-213481,-213510,-213540,-213569,-213598,-213627,-213656,-213685,-213714,-213744,-213773,-213802,-213831,-213860,-213889,-213918,-213947,-213976,-214005,-214034,-214063,-214092,-214121,-214150,-214179,-214208,-214237,-214266,-214295,-214324,-214353,-214382,-214411,-214440,-214469,-214497,-214526,-214555,-214584,-214613,-214642,-214671,-214700,-214728,-214757,-214786,-214815,-214844,-214872,-214901,-214930,-214959,-214988,-215016,-215045,-215074,-215103,-215131,-215160,-215189,-215217,-215246,-215275,-215303,-215332,-215361,-215389,-215418,-215447,-215475,-215504,-215533,-215561,-215590,-215618,-215647,-215676,-215704,-215733,-215761,-215790,-215818,-215847,-215875,-215904,-215932,-215961,-215989,-216018,-216046,-216075,-216103,-216132,-216160,-216189,-216217,-216245,-216274,-216302,-216331,-216359,-216387,-216416,-216444,-216472,-216501,-216529,-216557,-216586,-216614,-216642,-216671,-216699,-216727,-216756,-216784,-216812,-216840,-216869,-216897,-216925,-216953,-216981,-217010,-217038,-217066,-217094,-217122,-217151,-217179,-217207,-217235,-217263,-217291,-217319,-217347,-217376,-217404,-217432,-217460,-217488,-217516,-217544,-217572,-217600,-217628,-217656,-217684,-217712,-217740,-217768,-217796,-217824,-217852,-217880,-217908,-217936,-217964,-217992,-218020,-218048,-218075,-218103,-218131,-218159,-218187,-218215,-218243,-218270,-218298,-218326,-218354,-218382,-218410,-218437,-218465,-218493,-218521,-218548,-218576,-218604,-218632,-218659,-218687,-218715,-218743,-218770,-218798,-218826,-218853,-218881,-218909,-218936,-218964,-218992,-219019,-219047,-219074,-219102,-219130,-219157,-219185,-219212,-219240,-219267,-219295,-219323,-219350,-219378,-219405,-219433,-219460,-219488,-219515,-219543,-219570,-219597,-219625,-219652,-219680,-219707,-219735,-219762,-219789,-219817,-219844,-219872,-219899,-219926,-219954,-219981,-220008,-220036,-220063,-220090,-220118,-220145,-220172,-220199,-220227,-220254,-220281,-220308,-220336,-220363,-220390,-220417,-220445,-220472,-220499,-220526,-220553,-220580,-220608,-220635,-220662,-220689,-220716,-220743,-220770,-220797,-220825,-220852,-220879,-220906,-220933,-220960,-220987,-221014,-221041,-221068,-221095,-221122,-221149,-221176,-221203,-221230,-221257,-221284,-221311,-221338,-221365,-221392,-221418,-221445,-221472,-221499,-221526,-221553,-221580,-221607,-221633,-221660,-221687,-221714,-221741,-221768,-221794,-221821,-221848,-221875,-221902,-221928,-221955,-221982,-222009,-222035,-222062,-222089,-222115,-222142,-222169,-222195,-222222,-222249,-222275,-222302,-222329,-222355,-222382,-222409,-222435,-222462,-222488,-222515,-222541,-222568,-222595,-222621,-222648,-222674,-222701,-222727,-222754,-222780,-222807,-222833,-222860,-222886,-222913,-222939,-222965,-222992,-223018,-223045,-223071,-223098,-223124,-223150,-223177,-223203,-223229,-223256,-223282,-223308,-223335,-223361,-223387,-223414,-223440,-223466,-223492,-223519,-223545,-223571,-223598,-223624,-223650,-223676,-223702,-223729,-223755,-223781,-223807,-223833,-223859,-223886,-223912,-223938,-223964,-223990,-224016,-224042,-224068,-224095,-224121,-224147,-224173,-224199,-224225,-224251,-224277,-224303,-224329,-224355,-224381,-224407,-224433,-224459,-224485,-224511,-224537,-224563,-224589,-224614,-224640,-224666,-224692,-224718,-224744,-224770,-224796,-224822,-224847,-224873,-224899,-224925,-224951,-224977,-225002,-225028,-225054,-225080,-225105,-225131,-225157,-225183,-225208,-225234,-225260,-225286,-225311,-225337,-225363,-225388,-225414,-225440,-225465,-225491,-225516,-225542,-225568,-225593,-225619,-225645,-225670,-225696,-225721,-225747,-225772,-225798,-225823,-225849,-225874,-225900,-225925,-225951,-225976,-226002,-226027,-226053,-226078,-226104,-226129,-226155,-226180,-226205,-226231,-226256,-226282,-226307,-226332,-226358,-226383,-226408,-226434,-226459,-226484,-226510,-226535,-226560,-226585,-226611,-226636,-226661,-226687,-226712,-226737,-226762,-226787,-226813,-226838,-226863,-226888,-226913,-226939,-226964,-226989,-227014,-227039,-227064,-227089,-227114,-227140,-227165,-227190,-227215,-227240,-227265,-227290,-227315,-227340,-227365,-227390,-227415,-227440,-227465,-227490,-227515,-227540,-227565,-227590,-227615,-227640,-227665,-227690,-227715,-227739,-227764,-227789,-227814,-227839,-227864,-227889,-227913,-227938,-227963,-227988,-228013,-228038,-228062,-228087,-228112,-228137,-228161,-228186,-228211,-228236,-228260,-228285,-228310,-228334,-228359,-228384,-228408,-228433,-228458,-228482,-228507,-228532,-228556,-228581,-228606,-228630,-228655,-228679,-228704,-228728,-228753,-228778,-228802,-228827,-228851,-228876,-228900,-228925,-228949,-228974,-228998,-229023,-229047,-229071,-229096,-229120,-229145,-229169,-229193,-229218,-229242,-229267,-229291,-229315,-229340,-229364,-229388,-229413,-229437,-229461,-229486,-229510,-229534,-229559,-229583,-229607,-229631,-229656,-229680,-229704,-229728,-229752,-229777,-229801,-229825,-229849,-229873,-229897,-229922,-229946,-229970,-229994,-230018,-230042,-230066,-230090,-230115,-230139,-230163,-230187,-230211,-230235,-230259,-230283,-230307,-230331,-230355,-230379,-230403,-230427,-230451,-230475,-230499,-230523,-230547,-230570,-230594,-230618,-230642,-230666,-230690,-230714,-230738,-230761,-230785,-230809,-230833,-230857,-230881,-230904,-230928,-230952,-230976,-231000,-231023,-231047,-231071,-231095,-231118,-231142,-231166,-231189,-231213,-231237,-231260,-231284,-231308,-231331,-231355,-231379,-231402,-231426,-231449,-231473,-231497,-231520,-231544,-231567,-231591,-231614,-231638,-231662,-231685,-231709,-231732,-231756,-231779,-231803,-231826,-231849,-231873,-231896,-231920,-231943,-231967,-231990,-232013,-232037,-232060,-232084,-232107,-232130,-232154,-232177,-232200,-232224,-232247,-232270,-232294,-232317,-232340,-232363,-232387,-232410,-232433,-232456,-232480,-232503,-232526,-232549,-232573,-232596,-232619,-232642,-232665,-232688,-232712,-232735,-232758,-232781,-232804,-232827,-232850,-232873,-232896,-232919,-232943,-232966,-232989,-233012,-233035,-233058,-233081,-233104,-233127,-233150,-233173,-233196,-233219,-233242,-233264,-233287,-233310,-233333,-233356,-233379,-233402,-233425,-233448,-233471,-233493,-233516,-233539,-233562,-233585,-233608,-233630,-233653,-233676,-233699,-233721,-233744,-233767,-233790,-233812,-233835,-233858,-233881,-233903,-233926,-233949,-233971,-233994,-234017,-234039,-234062,-234085,-234107,-234130,-234152,-234175,-234198,-234220,-234243,-234265,-234288,-234310,-234333,-234355,-234378,-234400,-234423,-234445,-234468,-234490,-234513,-234535,-234558,-234580,-234603,-234625,-234648,-234670,-234692,-234715,-234737,-234759,-234782,-234804,-234827,-234849,-234871,-234893,-234916,-234938,-234960,-234983,-235005,-235027,-235049,-235072,-235094,-235116,-235138,-235161,-235183,-235205,-235227,-235249,-235272,-235294,-235316,-235338,-235360,-235382,-235404,-235427,-235449,-235471,-235493,-235515,-235537,-235559,-235581,-235603,-235625,-235647,-235669,-235691,-235713,-235735,-235757,-235779,-235801,-235823,-235845,-235867,-235889,-235911,-235933,-235955,-235977,-235998,-236020,-236042,-236064,-236086,-236108,-236130,-236151,-236173,-236195,-236217,-236239,-236260,-236282,-236304,-236326,-236347,-236369,-236391,-236413,-236434,-236456,-236478,-236499,-236521,-236543,-236564,-236586,-236608,-236629,-236651,-236673,-236694,-236716,-236737,-236759,-236781,-236802,-236824,-236845,-236867,-236888,-236910,-236931,-236953,-236974,-236996,-237017,-237039,-237060,-237082,-237103,-237125,-237146,-237167,-237189,-237210,-237232,-237253,-237274,-237296,-237317,-237338,-237360,-237381,-237402,-237424,-237445,-237466,-237488,-237509,-237530,-237551,-237573,-237594,-237615,-237636,-237658,-237679,-237700,-237721,-237742,-237764,-237785,-237806,-237827,-237848,-237869,-237890,-237912,-237933,-237954,-237975,-237996,-238017,-238038,-238059,-238080,-238101,-238122,-238143,-238164,-238185,-238206,-238227,-238248,-238269,-238290,-238311,-238332,-238353,-238374,-238395,-238416,-238436,-238457,-238478,-238499,-238520,-238541,-238562,-238582,-238603,-238624,-238645,-238666,-238687,-238707,-238728,-238749,-238770,-238790,-238811,-238832,-238852,-238873,-238894,-238915,-238935,-238956,-238977,-238997,-239018,-239039,-239059,-239080,-239100,-239121,-239142,-239162,-239183,-239203,-239224,-239244,-239265,-239286,-239306,-239327,-239347,-239368,-239388,-239409,-239429,-239449,-239470,-239490,-239511,-239531,-239552,-239572,-239592,-239613,-239633,-239654,-239674,-239694,-239715,-239735,-239755,-239776,-239796,-239816,-239837,-239857,-239877,-239897,-239918,-239938,-239958,-239978,-239999,-240019,-240039,-240059,-240079,-240100,-240120,-240140,-240160,-240180,-240200,-240220,-240241,-240261,-240281,-240301,-240321,-240341,-240361,-240381,-240401,-240421,-240441,-240461,-240481,-240501,-240521,-240541,-240561,-240581,-240601,-240621,-240641,-240661,-240681,-240701,-240721,-240741,-240761,-240780,-240800,-240820,-240840,-240860,-240880,-240900,-240919,-240939,-240959,-240979,-240999,-241018,-241038,-241058,-241078,-241097,-241117,-241137,-241156,-241176,-241196,-241216,-241235,-241255,-241275,-241294,-241314,-241333,-241353,-241373,-241392,-241412,-241432,-241451,-241471,-241490,-241510,-241529,-241549,-241568,-241588,-241607,-241627,-241646,-241666,-241685,-241705,-241724,-241744,-241763,-241783,-241802,-241821,-241841,-241860,-241880,-241899,-241918,-241938,-241957,-241976,-241996,-242015,-242034,-242054,-242073,-242092,-242111,-242131,-242150,-242169,-242188,-242208,-242227,-242246,-242265,-242285,-242304,-242323,-242342,-242361,-242380,-242400,-242419,-242438,-242457,-242476,-242495,-242514,-242533,-242552,-242571,-242590,-242610,-242629,-242648,-242667,-242686,-242705,-242724,-242743,-242762,-242781,-242799,-242818,-242837,-242856,-242875,-242894,-242913,-242932,-242951,-242970,-242989,-243007,-243026,-243045,-243064,-243083,-243102,-243120,-243139,-243158,-243177,-243195,-243214,-243233,-243252,-243270,-243289,-243308,-243327,-243345,-243364,-243383,-243401,-243420,-243439,-243457,-243476,-243495,-243513,-243532,-243550,-243569,-243587,-243606,-243625,-243643,-243662,-243680,-243699,-243717,-243736,-243754,-243773,-243791,-243810,-243828,-243847,-243865,-243884,-243902,-243920,-243939,-243957,-243976,-243994,-244012,-244031,-244049,-244067,-244086,-244104,-244122,-244141,-244159,-244177,-244196,-244214,-244232,-244250,-244269,-244287,-244305,-244323,-244342,-244360,-244378,-244396,-244414,-244432,-244451,-244469,-244487,-244505,-244523,-244541,-244559,-244577,-244596,-244614,-244632,-244650,-244668,-244686,-244704,-244722,-244740,-244758,-244776,-244794,-244812,-244830,-244848,-244866,-244884,-244902,-244920,-244937,-244955,-244973,-244991,-245009,-245027,-245045,-245063,-245080,-245098,-245116,-245134,-245152,-245170,-245187,-245205,-245223,-245241,-245258,-245276,-245294,-245312,-245329,-245347,-245365,-245382,-245400,-245418,-245435,-245453,-245471,-245488,-245506,-245524,-245541,-245559,-245576,-245594,-245612,-245629,-245647,-245664,-245682,-245699,-245717,-245734,-245752,-245769,-245787,-245804,-245822,-245839,-245857,-245874,-245891,-245909,-245926,-245944,-245961,-245978,-245996,-246013,-246031,-246048,-246065,-246083,-246100,-246117,-246135,-246152,-246169,-246186,-246204,-246221,-246238,-246255,-246273,-246290,-246307,-246324,-246341,-246359,-246376,-246393,-246410,-246427,-246444,-246462,-246479,-246496,-246513,-246530,-246547,-246564,-246581,-246598,-246615,-246632,-246649,-246666,-246683,-246700,-246717,-246734,-246751,-246768,-246785,-246802,-246819,-246836,-246853,-246870,-246887,-246904,-246921,-246937,-246954,-246971,-246988,-247005,-247022,-247039,-247055,-247072,-247089,-247106,-247122,-247139,-247156,-247173,-247189,-247206,-247223,-247240,-247256,-247273,-247290,-247306,-247323,-247340,-247356,-247373,-247390,-247406,-247423,-247439,-247456,-247473,-247489,-247506,-247522,-247539,-247555,-247572,-247588,-247605,-247621,-247638,-247654,-247671,-247687,-247704,-247720,-247737,-247753,-247770,-247786,-247802,-247819,-247835,-247852,-247868,-247884,-247901,-247917,-247933,-247950,-247966,-247982,-247999,-248015,-248031,-248047,-248064,-248080,-248096,-248112,-248129,-248145,-248161,-248177,-248193,-248210,-248226,-248242,-248258,-248274,-248290,-248306,-248322,-248339,-248355,-248371,-248387,-248403,-248419,-248435,-248451,-248467,-248483,-248499,-248515,-248531,-248547,-248563,-248579,-248595,-248611,-248627,-248643,-248659,-248675,-248690,-248706,-248722,-248738,-248754,-248770,-248786,-248802,-248817,-248833,-248849,-248865,-248881,-248896,-248912,-248928,-248944,-248959,-248975,-248991,-249007,-249022,-249038,-249054,-249069,-249085,-249101,-249116,-249132,-249148,-249163,-249179,-249194,-249210,-249226,-249241,-249257,-249272,-249288,-249303,-249319,-249334,-249350,-249366,-249381,-249397,-249412,-249427,-249443,-249458,-249474,-249489,-249505,-249520,-249535,-249551,-249566,-249582,-249597,-249612,-249628,-249643,-249658,-249674,-249689,-249704,-249720,-249735,-249750,-249765,-249781,-249796,-249811,-249826,-249842,-249857,-249872,-249887,-249902,-249918,-249933,-249948,-249963,-249978,-249993,-250008,-250024,-250039,-250054,-250069,-250084,-250099,-250114,-250129,-250144,-250159,-250174,-250189,-250204,-250219,-250234,-250249,-250264,-250279,-250294,-250309,-250324,-250339,-250354,-250369,-250384,-250398,-250413,-250428,-250443,-250458,-250473,-250488,-250502,-250517,-250532,-250547,-250561,-250576,-250591,-250606,-250621,-250635,-250650,-250665,-250679,-250694,-250709,-250723,-250738,-250753,-250767,-250782,-250797,-250811,-250826,-250841,-250855,-250870,-250884,-250899,-250913,-250928,-250943,-250957,-250972,-250986,-251001,-251015,-251030,-251044,-251059,-251073,-251087,-251102,-251116,-251131,-251145,-251160,-251174,-251188,-251203,-251217,-251231,-251246,-251260,-251274,-251289,-251303,-251317,-251332,-251346,-251360,-251374,-251389,-251403,-251417,-251431,-251446,-251460,-251474,-251488,-251502,-251517,-251531,-251545,-251559,-251573,-251587,-251601,-251616,-251630,-251644,-251658,-251672,-251686,-251700,-251714,-251728,-251742,-251756,-251770,-251784,-251798,-251812,-251826,-251840,-251854,-251868,-251882,-251896,-251910,-251924,-251937,-251951,-251965,-251979,-251993,-252007,-252021,-252034,-252048,-252062,-252076,-252090,-252103,-252117,-252131,-252145,-252158,-252172,-252186,-252200,-252213,-252227,-252241,-252254,-252268,-252282,-252295,-252309,-252323,-252336,-252350,-252364,-252377,-252391,-252404,-252418,-252431,-252445,-252459,-252472,-252486,-252499,-252513,-252526,-252540,-252553,-252567,-252580,-252593,-252607,-252620,-252634,-252647,-252661,-252674,-252687,-252701,-252714,-252727,-252741,-252754,-252767,-252781,-252794,-252807,-252821,-252834,-252847,-252860,-252874,-252887,-252900,-252913,-252927,-252940,-252953,-252966,-252979,-252993,-253006,-253019,-253032,-253045,-253058,-253071,-253084,-253098,-253111,-253124,-253137,-253150,-253163,-253176,-253189,-253202,-253215,-253228,-253241,-253254,-253267,-253280,-253293,-253306,-253319,-253332,-253345,-253358,-253370,-253383,-253396,-253409,-253422,-253435,-253448,-253460,-253473,-253486,-253499,-253512,-253524,-253537,-253550,-253563,-253576,-253588,-253601,-253614,-253626,-253639,-253652,-253665,-253677,-253690,-253703,-253715,-253728,-253740,-253753,-253766,-253778,-253791,-253803,-253816,-253829,-253841,-253854,-253866,-253879,-253891,-253904,-253916,-253929,-253941,-253954,-253966,-253979,-253991,-254003,-254016,-254028,-254041,-254053,-254066,-254078,-254090,-254103,-254115,-254127,-254140,-254152,-254164,-254177,-254189,-254201,-254213,-254226,-254238,-254250,-254262,-254275,-254287,-254299,-254311,-254323,-254336,-254348,-254360,-254372,-254384,-254396,-254409,-254421,-254433,-254445,-254457,-254469,-254481,-254493,-254505,-254517,-254529,-254541,-254553,-254565,-254577,-254589,-254601,-254613,-254625,-254637,-254649,-254661,-254673,-254685,-254697,-254709,-254720,-254732,-254744,-254756,-254768,-254780,-254792,-254803,-254815,-254827,-254839,-254851,-254862,-254874,-254886,-254898,-254909,-254921,-254933,-254944,-254956,-254968,-254980,-254991,-255003,-255014,-255026,-255038,-255049,-255061,-255073,-255084,-255096,-255107,-255119,-255130,-255142,-255154,-255165,-255177,-255188,-255200,-255211,-255223,-255234,-255245,-255257,-255268,-255280,-255291,-255303,-255314,-255325,-255337,-255348,-255360,-255371,-255382,-255394,-255405,-255416,-255428,-255439,-255450,-255461,-255473,-255484,-255495,-255506,-255518,-255529,-255540,-255551,-255563,-255574,-255585,-255596,-255607,-255618,-255629,-255641,-255652,-255663,-255674,-255685,-255696,-255707,-255718,-255729,-255740,-255751,-255762,-255773,-255784,-255795,-255806,-255817,-255828,-255839,-255850,-255861,-255872,-255883,-255894,-255905,-255916,-255927,-255938,-255948,-255959,-255970,-255981,-255992,-256003,-256013,-256024,-256035,-256046,-256057,-256067,-256078,-256089,-256100,-256110,-256121,-256132,-256142,-256153,-256164,-256175,-256185,-256196,-256206,-256217,-256228,-256238,-256249,-256260,-256270,-256281,-256291,-256302,-256312,-256323,-256333,-256344,-256354,-256365,-256375,-256386,-256396,-256407,-256417,-256428,-256438,-256449,-256459,-256469,-256480,-256490,-256501,-256511,-256521,-256532,-256542,-256552,-256563,-256573,-256583,-256594,-256604,-256614,-256624,-256635,-256645,-256655,-256665,-256676,-256686,-256696,-256706,-256716,-256727,-256737,-256747,-256757,-256767,-256777,-256787,-256797,-256808,-256818,-256828,-256838,-256848,-256858,-256868,-256878,-256888,-256898,-256908,-256918,-256928,-256938,-256948,-256958,-256968,-256978,-256988,-256998,-257007,-257017,-257027,-257037,-257047,-257057,-257067,-257077,-257086,-257096,-257106,-257116,-257126,-257135,-257145,-257155,-257165,-257174,-257184,-257194,-257204,-257213,-257223,-257233,-257242,-257252,-257262,-257271,-257281,-257291,-257300,-257310,-257319,-257329,-257339,-257348,-257358,-257367,-257377,-257386,-257396,-257405,-257415,-257424,-257434,-257443,-257453,-257462,-257472,-257481,-257491,-257500,-257509,-257519,-257528,-257538,-257547,-257556,-257566,-257575,-257584,-257594,-257603,-257612,-257622,-257631,-257640,-257650,-257659,-257668,-257677,-257687,-257696,-257705,-257714,-257723,-257733,-257742,-257751,-257760,-257769,-257778,-257788,-257797,-257806,-257815,-257824,-257833,-257842,-257851,-257860,-257869,-257878,-257887,-257896,-257905,-257914,-257923,-257932,-257941,-257950,-257959,-257968,-257977,-257986,-257995,-258004,-258013,-258022,-258030,-258039,-258048,-258057,-258066,-258075,-258083,-258092,-258101,-258110,-258119,-258127,-258136,-258145,-258154,-258162,-258171,-258180,-258189,-258197,-258206,-258215,-258223,-258232,-258241,-258249,-258258,-258266,-258275,-258284,-258292,-258301,-258309,-258318,-258326,-258335,-258344,-258352,-258361,-258369,-258378,-258386,-258395,-258403,-258411,-258420,-258428,-258437,-258445,-258454,-258462,-258470,-258479,-258487,-258495,-258504,-258512,-258521,-258529,-258537,-258545,-258554,-258562,-258570,-258579,-258587,-258595,-258603,-258612,-258620,-258628,-258636,-258644,-258653,-258661,-258669,-258677,-258685,-258693,-258701,-258710,-258718,-258726,-258734,-258742,-258750,-258758,-258766,-258774,-258782,-258790,-258798,-258806,-258814,-258822,-258830,-258838,-258846,-258854,-258862,-258870,-258878,-258886,-258894,-258901,-258909,-258917,-258925,-258933,-258941,-258949,-258956,-258964,-258972,-258980,-258988,-258995,-259003,-259011,-259019,-259026,-259034,-259042,-259049,-259057,-259065,-259072,-259080,-259088,-259095,-259103,-259111,-259118,-259126,-259134,-259141,-259149,-259156,-259164,-259171,-259179,-259186,-259194,-259201,-259209,-259216,-259224,-259231,-259239,-259246,-259254,-259261,-259269,-259276,-259284,-259291,-259298,-259306,-259313,-259320,-259328,-259335,-259342,-259350,-259357,-259364,-259372,-259379,-259386,-259394,-259401,-259408,-259415,-259422,-259430,-259437,-259444,-259451,-259458,-259466,-259473,-259480,-259487,-259494,-259501,-259508,-259516,-259523,-259530,-259537,-259544,-259551,-259558,-259565,-259572,-259579,-259586,-259593,-259600,-259607,-259614,-259621,-259628,-259635,-259642,-259649,-259656,-259663,-259669,-259676,-259683,-259690,-259697,-259704,-259711,-259717,-259724,-259731,-259738,-259745,-259751,-259758,-259765,-259772,-259778,-259785,-259792,-259799,-259805,-259812,-259819,-259825,-259832,-259839,-259845,-259852,-259859,-259865,-259872,-259878,-259885,-259892,-259898,-259905,-259911,-259918,-259924,-259931,-259937,-259944,-259950,-259957,-259963,-259970,-259976,-259983,-259989,-259996,-260002,-260008,-260015,-260021,-260028,-260034,-260040,-260047,-260053,-260059,-260066,-260072,-260078,-260084,-260091,-260097,-260103,-260110,-260116,-260122,-260128,-260134,-260141,-260147,-260153,-260159,-260165,-260172,-260178,-260184,-260190,-260196,-260202,-260208,-260214,-260220,-260227,-260233,-260239,-260245,-260251,-260257,-260263,-260269,-260275,-260281,-260287,-260293,-260299,-260305,-260311,-260316,-260322,-260328,-260334,-260340,-260346,-260352,-260358,-260364,-260369,-260375,-260381,-260387,-260393,-260398,-260404,-260410,-260416,-260422,-260427,-260433,-260439,-260444,-260450,-260456,-260462,-260467,-260473,-260479,-260484,-260490,-260495,-260501,-260507,-260512,-260518,-260524,-260529,-260535,-260540,-260546,-260551,-260557,-260562,-260568,-260573,-260579,-260584,-260590,-260595,-260601,-260606,-260612,-260617,-260622,-260628,-260633,-260639,-260644,-260649,-260655,-260660,-260665,-260671,-260676,-260681,-260687,-260692,-260697,-260702,-260708,-260713,-260718,-260723,-260729,-260734,-260739,-260744,-260749,-260755,-260760,-260765,-260770,-260775,-260780,-260785,-260790,-260796,-260801,-260806,-260811,-260816,-260821,-260826,-260831,-260836,-260841,-260846,-260851,-260856,-260861,-260866,-260871,-260876,-260881,-260886,-260891,-260895,-260900,-260905,-260910,-260915,-260920,-260925,-260929,-260934,-260939,-260944,-260949,-260954,-260958,-260963,-260968,-260973,-260977,-260982,-260987,-260991,-260996,-261001,-261006,-261010,-261015,-261020,-261024,-261029,-261033,-261038,-261043,-261047,-261052,-261056,-261061,-261066,-261070,-261075,-261079,-261084,-261088,-261093,-261097,-261102,-261106,-261111,-261115,-261119,-261124,-261128,-261133,-261137,-261142,-261146,-261150,-261155,-261159,-261163,-261168,-261172,-261176,-261181,-261185,-261189,-261194,-261198,-261202,-261206,-261211,-261215,-261219,-261223,-261227,-261232,-261236,-261240,-261244,-261248,-261252,-261257,-261261,-261265,-261269,-261273,-261277,-261281,-261285,-261289,-261293,-261297,-261301,-261305,-261309,-261313,-261317,-261321,-261325,-261329,-261333,-261337,-261341,-261345,-261349,-261353,-261357,-261361,-261365,-261368,-261372,-261376,-261380,-261384,-261388,-261391,-261395,-261399,-261403,-261407,-261410,-261414,-261418,-261422,-261425,-261429,-261433,-261436,-261440,-261444,-261447,-261451,-261455,-261458,-261462,-261466,-261469,-261473,-261476,-261480,-261484,-261487,-261491,-261494,-261498,-261501,-261505,-261508,-261512,-261515,-261519,-261522,-261526,-261529,-261532,-261536,-261539,-261543,-261546,-261550,-261553,-261556,-261560,-261563,-261566,-261570,-261573,-261576,-261580,-261583,-261586,-261589,-261593,-261596,-261599,-261602,-261606,-261609,-261612,-261615,-261618,-261622,-261625,-261628,-261631,-261634,-261637,-261640,-261643,-261647,-261650,-261653,-261656,-261659,-261662,-261665,-261668,-261671,-261674,-261677,-261680,-261683,-261686,-261689,-261692,-261695,-261698,-261701,-261704,-261707,-261709,-261712,-261715,-261718,-261721,-261724,-261727,-261729,-261732,-261735,-261738,-261741,-261743,-261746,-261749,-261752,-261754,-261757,-261760,-261763,-261765,-261768,-261771,-261773,-261776,-261779,-261781,-261784,-261787,-261789,-261792,-261794,-261797,-261800,-261802,-261805,-261807,-261810,-261812,-261815,-261817,-261820,-261822,-261825,-261827,-261830,-261832,-261835,-261837,-261839,-261842,-261844,-261847,-261849,-261851,-261854,-261856,-261858,-261861,-261863,-261865,-261868,-261870,-261872,-261875,-261877,-261879,-261881,-261884,-261886,-261888,-261890,-261893,-261895,-261897,-261899,-261901,-261903,-261906,-261908,-261910,-261912,-261914,-261916,-261918,-261920,-261922,-261924,-261926,-261928,-261931,-261933,-261935,-261937,-261939,-261941,-261942,-261944,-261946,-261948,-261950,-261952,-261954,-261956,-261958,-261960,-261962,-261964,-261965,-261967,-261969,-261971,-261973,-261974,-261976,-261978,-261980,-261982,-261983,-261985,-261987,-261989,-261990,-261992,-261994,-261995,-261997,-261999,-262000,-262002,-262004,-262005,-262007,-262009,-262010,-262012,-262013,-262015,-262017,-262018,-262020,-262021,-262023,-262024,-262026,-262027,-262029,-262030,-262032,-262033,-262035,-262036,-262037,-262039,-262040,-262042,-262043,-262044,-262046,-262047,-262049,-262050,-262051,-262053,-262054,-262055,-262056,-262058,-262059,-262060,-262062,-262063,-262064,-262065,-262066,-262068,-262069,-262070,-262071,-262072,-262074,-262075,-262076,-262077,-262078,-262079,-262080,-262081,-262083,-262084,-262085,-262086,-262087,-262088,-262089,-262090,-262091,-262092,-262093,-262094,-262095,-262096,-262097,-262098,-262099,-262100,-262100,-262101,-262102,-262103,-262104,-262105,-262106,-262107,-262107,-262108,-262109,-262110,-262111,-262111,-262112,-262113,-262114,-262114,-262115,-262116,-262117,-262117,-262118,-262119,-262119,-262120,-262121,-262121,-262122,-262123,-262123,-262124,-262124,-262125,-262126,-262126,-262127,-262127,-262128,-262128,-262129,-262129,-262130,-262130,-262131,-262131,-262132,-262132,-262133,-262133,-262134,-262134,-262134,-262135,-262135,-262136,-262136,-262136,-262137,-262137,-262137,-262138,-262138,-262138,-262139,-262139,-262139,-262139,-262140,-262140,-262140,-262140,-262141,-262141,-262141,-262141,-262141,-262142,-262142,-262142,-262142,-262142,-262142,-262142,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262142,-262142,-262142,-262142,-262142,-262142,-262142,-262141,-262141,-262141,-262141,-262141,-262140,-262140,-262140,-262140,-262139,-262139,-262139,-262139,-262138,-262138,-262138,-262137,-262137,-262137,-262136,-262136,-262136,-262135,-262135,-262134,-262134,-262134,-262133,-262133,-262132,-262132,-262131,-262131,-262130,-262130,-262129,-262129,-262128,-262128,-262127,-262127,-262126,-262126,-262125,-262124,-262124,-262123,-262123,-262122,-262121,-262121,-262120,-262119,-262119,-262118,-262117,-262117,-262116,-262115,-262114,-262114,-262113,-262112,-262111,-262111,-262110,-262109,-262108,-262107,-262107,-262106,-262105,-262104,-262103,-262102,-262101,-262100,-262100,-262099,-262098,-262097,-262096,-262095,-262094,-262093,-262092,-262091,-262090,-262089,-262088,-262087,-262086,-262085,-262084,-262083,-262081,-262080,-262079,-262078,-262077,-262076,-262075,-262074,-262072,-262071,-262070,-262069,-262068,-262066,-262065,-262064,-262063,-262062,-262060,-262059,-262058,-262056,-262055,-262054,-262053,-262051,-262050,-262049,-262047,-262046,-262044,-262043,-262042,-262040,-262039,-262037,-262036,-262035,-262033,-262032,-262030,-262029,-262027,-262026,-262024,-262023,-262021,-262020,-262018,-262017,-262015,-262013,-262012,-262010,-262009,-262007,-262005,-262004,-262002,-262000,-261999,-261997,-261995,-261994,-261992,-261990,-261989,-261987,-261985,-261983,-261982,-261980,-261978,-261976,-261974,-261973,-261971,-261969,-261967,-261965,-261964,-261962,-261960,-261958,-261956,-261954,-261952,-261950,-261948,-261946,-261944,-261942,-261941,-261939,-261937,-261935,-261933,-261931,-261928,-261926,-261924,-261922,-261920,-261918,-261916,-261914,-261912,-261910,-261908,-261906,-261903,-261901,-261899,-261897,-261895,-261893,-261890,-261888,-261886,-261884,-261881,-261879,-261877,-261875,-261872,-261870,-261868,-261865,-261863,-261861,-261858,-261856,-261854,-261851,-261849,-261847,-261844,-261842,-261839,-261837,-261835,-261832,-261830,-261827,-261825,-261822,-261820,-261817,-261815,-261812,-261810,-261807,-261805,-261802,-261800,-261797,-261794,-261792,-261789,-261787,-261784,-261781,-261779,-261776,-261773,-261771,-261768,-261765,-261763,-261760,-261757,-261754,-261752,-261749,-261746,-261743,-261741,-261738,-261735,-261732,-261729,-261727,-261724,-261721,-261718,-261715,-261712,-261709,-261707,-261704,-261701,-261698,-261695,-261692,-261689,-261686,-261683,-261680,-261677,-261674,-261671,-261668,-261665,-261662,-261659,-261656,-261653,-261650,-261647,-261643,-261640,-261637,-261634,-261631,-261628,-261625,-261622,-261618,-261615,-261612,-261609,-261606,-261602,-261599,-261596,-261593,-261589,-261586,-261583,-261580,-261576,-261573,-261570,-261566,-261563,-261560,-261556,-261553,-261550,-261546,-261543,-261539,-261536,-261532,-261529,-261526,-261522,-261519,-261515,-261512,-261508,-261505,-261501,-261498,-261494,-261491,-261487,-261484,-261480,-261476,-261473,-261469,-261466,-261462,-261458,-261455,-261451,-261447,-261444,-261440,-261436,-261433,-261429,-261425,-261422,-261418,-261414,-261410,-261407,-261403,-261399,-261395,-261391,-261388,-261384,-261380,-261376,-261372,-261368,-261365,-261361,-261357,-261353,-261349,-261345,-261341,-261337,-261333,-261329,-261325,-261321,-261317,-261313,-261309,-261305,-261301,-261297,-261293,-261289,-261285,-261281,-261277,-261273,-261269,-261265,-261261,-261257,-261252,-261248,-261244,-261240,-261236,-261232,-261227,-261223,-261219,-261215,-261211,-261206,-261202,-261198,-261194,-261189,-261185,-261181,-261176,-261172,-261168,-261163,-261159,-261155,-261150,-261146,-261142,-261137,-261133,-261128,-261124,-261119,-261115,-261111,-261106,-261102,-261097,-261093,-261088,-261084,-261079,-261075,-261070,-261066,-261061,-261056,-261052,-261047,-261043,-261038,-261033,-261029,-261024,-261020,-261015,-261010,-261006,-261001,-260996,-260991,-260987,-260982,-260977,-260973,-260968,-260963,-260958,-260954,-260949,-260944,-260939,-260934,-260929,-260925,-260920,-260915,-260910,-260905,-260900,-260895,-260891,-260886,-260881,-260876,-260871,-260866,-260861,-260856,-260851,-260846,-260841,-260836,-260831,-260826,-260821,-260816,-260811,-260806,-260801,-260796,-260790,-260785,-260780,-260775,-260770,-260765,-260760,-260755,-260749,-260744,-260739,-260734,-260729,-260723,-260718,-260713,-260708,-260702,-260697,-260692,-260687,-260681,-260676,-260671,-260665,-260660,-260655,-260649,-260644,-260639,-260633,-260628,-260622,-260617,-260612,-260606,-260601,-260595,-260590,-260584,-260579,-260573,-260568,-260562,-260557,-260551,-260546,-260540,-260535,-260529,-260524,-260518,-260512,-260507,-260501,-260495,-260490,-260484,-260479,-260473,-260467,-260462,-260456,-260450,-260444,-260439,-260433,-260427,-260422,-260416,-260410,-260404,-260398,-260393,-260387,-260381,-260375,-260369,-260364,-260358,-260352,-260346,-260340,-260334,-260328,-260322,-260316,-260311,-260305,-260299,-260293,-260287,-260281,-260275,-260269,-260263,-260257,-260251,-260245,-260239,-260233,-260227,-260220,-260214,-260208,-260202,-260196,-260190,-260184,-260178,-260172,-260165,-260159,-260153,-260147,-260141,-260134,-260128,-260122,-260116,-260110,-260103,-260097,-260091,-260084,-260078,-260072,-260066,-260059,-260053,-260047,-260040,-260034,-260028,-260021,-260015,-260008,-260002,-259996,-259989,-259983,-259976,-259970,-259963,-259957,-259950,-259944,-259937,-259931,-259924,-259918,-259911,-259905,-259898,-259892,-259885,-259878,-259872,-259865,-259859,-259852,-259845,-259839,-259832,-259825,-259819,-259812,-259805,-259799,-259792,-259785,-259778,-259772,-259765,-259758,-259751,-259745,-259738,-259731,-259724,-259717,-259711,-259704,-259697,-259690,-259683,-259676,-259669,-259663,-259656,-259649,-259642,-259635,-259628,-259621,-259614,-259607,-259600,-259593,-259586,-259579,-259572,-259565,-259558,-259551,-259544,-259537,-259530,-259523,-259516,-259508,-259501,-259494,-259487,-259480,-259473,-259466,-259458,-259451,-259444,-259437,-259430,-259422,-259415,-259408,-259401,-259394,-259386,-259379,-259372,-259364,-259357,-259350,-259342,-259335,-259328,-259320,-259313,-259306,-259298,-259291,-259284,-259276,-259269,-259261,-259254,-259246,-259239,-259231,-259224,-259216,-259209,-259201,-259194,-259186,-259179,-259171,-259164,-259156,-259149,-259141,-259134,-259126,-259118,-259111,-259103,-259095,-259088,-259080,-259072,-259065,-259057,-259049,-259042,-259034,-259026,-259019,-259011,-259003,-258995,-258988,-258980,-258972,-258964,-258956,-258949,-258941,-258933,-258925,-258917,-258909,-258901,-258894,-258886,-258878,-258870,-258862,-258854,-258846,-258838,-258830,-258822,-258814,-258806,-258798,-258790,-258782,-258774,-258766,-258758,-258750,-258742,-258734,-258726,-258718,-258710,-258701,-258693,-258685,-258677,-258669,-258661,-258653,-258644,-258636,-258628,-258620,-258612,-258603,-258595,-258587,-258579,-258570,-258562,-258554,-258545,-258537,-258529,-258521,-258512,-258504,-258495,-258487,-258479,-258470,-258462,-258454,-258445,-258437,-258428,-258420,-258411,-258403,-258395,-258386,-258378,-258369,-258361,-258352,-258344,-258335,-258326,-258318,-258309,-258301,-258292,-258284,-258275,-258266,-258258,-258249,-258241,-258232,-258223,-258215,-258206,-258197,-258189,-258180,-258171,-258162,-258154,-258145,-258136,-258127,-258119,-258110,-258101,-258092,-258083,-258075,-258066,-258057,-258048,-258039,-258030,-258022,-258013,-258004,-257995,-257986,-257977,-257968,-257959,-257950,-257941,-257932,-257923,-257914,-257905,-257896,-257887,-257878,-257869,-257860,-257851,-257842,-257833,-257824,-257815,-257806,-257797,-257788,-257778,-257769,-257760,-257751,-257742,-257733,-257723,-257714,-257705,-257696,-257687,-257677,-257668,-257659,-257650,-257640,-257631,-257622,-257612,-257603,-257594,-257584,-257575,-257566,-257556,-257547,-257538,-257528,-257519,-257509,-257500,-257491,-257481,-257472,-257462,-257453,-257443,-257434,-257424,-257415,-257405,-257396,-257386,-257377,-257367,-257358,-257348,-257339,-257329,-257319,-257310,-257300,-257291,-257281,-257271,-257262,-257252,-257242,-257233,-257223,-257213,-257204,-257194,-257184,-257174,-257165,-257155,-257145,-257135,-257126,-257116,-257106,-257096,-257086,-257077,-257067,-257057,-257047,-257037,-257027,-257017,-257007,-256998,-256988,-256978,-256968,-256958,-256948,-256938,-256928,-256918,-256908,-256898,-256888,-256878,-256868,-256858,-256848,-256838,-256828,-256818,-256808,-256797,-256787,-256777,-256767,-256757,-256747,-256737,-256727,-256716,-256706,-256696,-256686,-256676,-256665,-256655,-256645,-256635,-256624,-256614,-256604,-256594,-256583,-256573,-256563,-256552,-256542,-256532,-256521,-256511,-256501,-256490,-256480,-256469,-256459,-256449,-256438,-256428,-256417,-256407,-256396,-256386,-256375,-256365,-256354,-256344,-256333,-256323,-256312,-256302,-256291,-256281,-256270,-256260,-256249,-256238,-256228,-256217,-256206,-256196,-256185,-256175,-256164,-256153,-256142,-256132,-256121,-256110,-256100,-256089,-256078,-256067,-256057,-256046,-256035,-256024,-256013,-256003,-255992,-255981,-255970,-255959,-255948,-255938,-255927,-255916,-255905,-255894,-255883,-255872,-255861,-255850,-255839,-255828,-255817,-255806,-255795,-255784,-255773,-255762,-255751,-255740,-255729,-255718,-255707,-255696,-255685,-255674,-255663,-255652,-255641,-255629,-255618,-255607,-255596,-255585,-255574,-255563,-255551,-255540,-255529,-255518,-255506,-255495,-255484,-255473,-255461,-255450,-255439,-255428,-255416,-255405,-255394,-255382,-255371,-255360,-255348,-255337,-255325,-255314,-255303,-255291,-255280,-255268,-255257,-255245,-255234,-255223,-255211,-255200,-255188,-255177,-255165,-255154,-255142,-255130,-255119,-255107,-255096,-255084,-255073,-255061,-255049,-255038,-255026,-255014,-255003,-254991,-254980,-254968,-254956,-254944,-254933,-254921,-254909,-254898,-254886,-254874,-254862,-254851,-254839,-254827,-254815,-254803,-254792,-254780,-254768,-254756,-254744,-254732,-254720,-254709,-254697,-254685,-254673,-254661,-254649,-254637,-254625,-254613,-254601,-254589,-254577,-254565,-254553,-254541,-254529,-254517,-254505,-254493,-254481,-254469,-254457,-254445,-254433,-254421,-254409,-254396,-254384,-254372,-254360,-254348,-254336,-254323,-254311,-254299,-254287,-254275,-254262,-254250,-254238,-254226,-254213,-254201,-254189,-254177,-254164,-254152,-254140,-254127,-254115,-254103,-254090,-254078,-254066,-254053,-254041,-254028,-254016,-254003,-253991,-253979,-253966,-253954,-253941,-253929,-253916,-253904,-253891,-253879,-253866,-253854,-253841,-253829,-253816,-253803,-253791,-253778,-253766,-253753,-253740,-253728,-253715,-253703,-253690,-253677,-253665,-253652,-253639,-253626,-253614,-253601,-253588,-253576,-253563,-253550,-253537,-253524,-253512,-253499,-253486,-253473,-253460,-253448,-253435,-253422,-253409,-253396,-253383,-253370,-253358,-253345,-253332,-253319,-253306,-253293,-253280,-253267,-253254,-253241,-253228,-253215,-253202,-253189,-253176,-253163,-253150,-253137,-253124,-253111,-253098,-253084,-253071,-253058,-253045,-253032,-253019,-253006,-252993,-252979,-252966,-252953,-252940,-252927,-252913,-252900,-252887,-252874,-252860,-252847,-252834,-252821,-252807,-252794,-252781,-252767,-252754,-252741,-252727,-252714,-252701,-252687,-252674,-252661,-252647,-252634,-252620,-252607,-252593,-252580,-252567,-252553,-252540,-252526,-252513,-252499,-252486,-252472,-252459,-252445,-252431,-252418,-252404,-252391,-252377,-252364,-252350,-252336,-252323,-252309,-252295,-252282,-252268,-252254,-252241,-252227,-252213,-252200,-252186,-252172,-252158,-252145,-252131,-252117,-252103,-252090,-252076,-252062,-252048,-252034,-252021,-252007,-251993,-251979,-251965,-251951,-251937,-251924,-251910,-251896,-251882,-251868,-251854,-251840,-251826,-251812,-251798,-251784,-251770,-251756,-251742,-251728,-251714,-251700,-251686,-251672,-251658,-251644,-251630,-251616,-251601,-251587,-251573,-251559,-251545,-251531,-251517,-251502,-251488,-251474,-251460,-251446,-251431,-251417,-251403,-251389,-251374,-251360,-251346,-251332,-251317,-251303,-251289,-251274,-251260,-251246,-251231,-251217,-251203,-251188,-251174,-251160,-251145,-251131,-251116,-251102,-251087,-251073,-251059,-251044,-251030,-251015,-251001,-250986,-250972,-250957,-250943,-250928,-250913,-250899,-250884,-250870,-250855,-250841,-250826,-250811,-250797,-250782,-250767,-250753,-250738,-250723,-250709,-250694,-250679,-250665,-250650,-250635,-250621,-250606,-250591,-250576,-250561,-250547,-250532,-250517,-250502,-250488,-250473,-250458,-250443,-250428,-250413,-250398,-250384,-250369,-250354,-250339,-250324,-250309,-250294,-250279,-250264,-250249,-250234,-250219,-250204,-250189,-250174,-250159,-250144,-250129,-250114,-250099,-250084,-250069,-250054,-250039,-250024,-250008,-249993,-249978,-249963,-249948,-249933,-249918,-249902,-249887,-249872,-249857,-249842,-249826,-249811,-249796,-249781,-249765,-249750,-249735,-249720,-249704,-249689,-249674,-249658,-249643,-249628,-249612,-249597,-249582,-249566,-249551,-249535,-249520,-249505,-249489,-249474,-249458,-249443,-249427,-249412,-249397,-249381,-249366,-249350,-249334,-249319,-249303,-249288,-249272,-249257,-249241,-249226,-249210,-249194,-249179,-249163,-249148,-249132,-249116,-249101,-249085,-249069,-249054,-249038,-249022,-249007,-248991,-248975,-248959,-248944,-248928,-248912,-248896,-248881,-248865,-248849,-248833,-248817,-248802,-248786,-248770,-248754,-248738,-248722,-248706,-248690,-248675,-248659,-248643,-248627,-248611,-248595,-248579,-248563,-248547,-248531,-248515,-248499,-248483,-248467,-248451,-248435,-248419,-248403,-248387,-248371,-248355,-248339,-248322,-248306,-248290,-248274,-248258,-248242,-248226,-248210,-248193,-248177,-248161,-248145,-248129,-248112,-248096,-248080,-248064,-248047,-248031,-248015,-247999,-247982,-247966,-247950,-247933,-247917,-247901,-247884,-247868,-247852,-247835,-247819,-247802,-247786,-247770,-247753,-247737,-247720,-247704,-247687,-247671,-247654,-247638,-247621,-247605,-247588,-247572,-247555,-247539,-247522,-247506,-247489,-247473,-247456,-247439,-247423,-247406,-247390,-247373,-247356,-247340,-247323,-247306,-247290,-247273,-247256,-247240,-247223,-247206,-247189,-247173,-247156,-247139,-247122,-247106,-247089,-247072,-247055,-247039,-247022,-247005,-246988,-246971,-246954,-246937,-246921,-246904,-246887,-246870,-246853,-246836,-246819,-246802,-246785,-246768,-246751,-246734,-246717,-246700,-246683,-246666,-246649,-246632,-246615,-246598,-246581,-246564,-246547,-246530,-246513,-246496,-246479,-246462,-246444,-246427,-246410,-246393,-246376,-246359,-246341,-246324,-246307,-246290,-246273,-246255,-246238,-246221,-246204,-246186,-246169,-246152,-246135,-246117,-246100,-246083,-246065,-246048,-246031,-246013,-245996,-245978,-245961,-245944,-245926,-245909,-245891,-245874,-245857,-245839,-245822,-245804,-245787,-245769,-245752,-245734,-245717,-245699,-245682,-245664,-245647,-245629,-245612,-245594,-245576,-245559,-245541,-245524,-245506,-245488,-245471,-245453,-245435,-245418,-245400,-245382,-245365,-245347,-245329,-245312,-245294,-245276,-245258,-245241,-245223,-245205,-245187,-245170,-245152,-245134,-245116,-245098,-245080,-245063,-245045,-245027,-245009,-244991,-244973,-244955,-244937,-244920,-244902,-244884,-244866,-244848,-244830,-244812,-244794,-244776,-244758,-244740,-244722,-244704,-244686,-244668,-244650,-244632,-244614,-244596,-244577,-244559,-244541,-244523,-244505,-244487,-244469,-244451,-244432,-244414,-244396,-244378,-244360,-244342,-244323,-244305,-244287,-244269,-244250,-244232,-244214,-244196,-244177,-244159,-244141,-244122,-244104,-244086,-244067,-244049,-244031,-244012,-243994,-243976,-243957,-243939,-243920,-243902,-243884,-243865,-243847,-243828,-243810,-243791,-243773,-243754,-243736,-243717,-243699,-243680,-243662,-243643,-243625,-243606,-243587,-243569,-243550,-243532,-243513,-243495,-243476,-243457,-243439,-243420,-243401,-243383,-243364,-243345,-243327,-243308,-243289,-243270,-243252,-243233,-243214,-243195,-243177,-243158,-243139,-243120,-243102,-243083,-243064,-243045,-243026,-243007,-242989,-242970,-242951,-242932,-242913,-242894,-242875,-242856,-242837,-242818,-242799,-242781,-242762,-242743,-242724,-242705,-242686,-242667,-242648,-242629,-242610,-242590,-242571,-242552,-242533,-242514,-242495,-242476,-242457,-242438,-242419,-242400,-242380,-242361,-242342,-242323,-242304,-242285,-242265,-242246,-242227,-242208,-242188,-242169,-242150,-242131,-242111,-242092,-242073,-242054,-242034,-242015,-241996,-241976,-241957,-241938,-241918,-241899,-241880,-241860,-241841,-241821,-241802,-241783,-241763,-241744,-241724,-241705,-241685,-241666,-241646,-241627,-241607,-241588,-241568,-241549,-241529,-241510,-241490,-241471,-241451,-241432,-241412,-241392,-241373,-241353,-241333,-241314,-241294,-241275,-241255,-241235,-241216,-241196,-241176,-241156,-241137,-241117,-241097,-241078,-241058,-241038,-241018,-240999,-240979,-240959,-240939,-240919,-240900,-240880,-240860,-240840,-240820,-240800,-240780,-240761,-240741,-240721,-240701,-240681,-240661,-240641,-240621,-240601,-240581,-240561,-240541,-240521,-240501,-240481,-240461,-240441,-240421,-240401,-240381,-240361,-240341,-240321,-240301,-240281,-240261,-240241,-240220,-240200,-240180,-240160,-240140,-240120,-240100,-240079,-240059,-240039,-240019,-239999,-239978,-239958,-239938,-239918,-239897,-239877,-239857,-239837,-239816,-239796,-239776,-239755,-239735,-239715,-239694,-239674,-239654,-239633,-239613,-239592,-239572,-239552,-239531,-239511,-239490,-239470,-239449,-239429,-239409,-239388,-239368,-239347,-239327,-239306,-239286,-239265,-239244,-239224,-239203,-239183,-239162,-239142,-239121,-239100,-239080,-239059,-239039,-239018,-238997,-238977,-238956,-238935,-238915,-238894,-238873,-238852,-238832,-238811,-238790,-238770,-238749,-238728,-238707,-238687,-238666,-238645,-238624,-238603,-238582,-238562,-238541,-238520,-238499,-238478,-238457,-238436,-238416,-238395,-238374,-238353,-238332,-238311,-238290,-238269,-238248,-238227,-238206,-238185,-238164,-238143,-238122,-238101,-238080,-238059,-238038,-238017,-237996,-237975,-237954,-237933,-237912,-237890,-237869,-237848,-237827,-237806,-237785,-237764,-237742,-237721,-237700,-237679,-237658,-237636,-237615,-237594,-237573,-237551,-237530,-237509,-237488,-237466,-237445,-237424,-237402,-237381,-237360,-237338,-237317,-237296,-237274,-237253,-237232,-237210,-237189,-237167,-237146,-237125,-237103,-237082,-237060,-237039,-237017,-236996,-236974,-236953,-236931,-236910,-236888,-236867,-236845,-236824,-236802,-236781,-236759,-236737,-236716,-236694,-236673,-236651,-236629,-236608,-236586,-236564,-236543,-236521,-236499,-236478,-236456,-236434,-236413,-236391,-236369,-236347,-236326,-236304,-236282,-236260,-236239,-236217,-236195,-236173,-236151,-236130,-236108,-236086,-236064,-236042,-236020,-235998,-235977,-235955,-235933,-235911,-235889,-235867,-235845,-235823,-235801,-235779,-235757,-235735,-235713,-235691,-235669,-235647,-235625,-235603,-235581,-235559,-235537,-235515,-235493,-235471,-235449,-235427,-235404,-235382,-235360,-235338,-235316,-235294,-235272,-235249,-235227,-235205,-235183,-235161,-235138,-235116,-235094,-235072,-235049,-235027,-235005,-234983,-234960,-234938,-234916,-234893,-234871,-234849,-234827,-234804,-234782,-234759,-234737,-234715,-234692,-234670,-234648,-234625,-234603,-234580,-234558,-234535,-234513,-234490,-234468,-234445,-234423,-234400,-234378,-234355,-234333,-234310,-234288,-234265,-234243,-234220,-234198,-234175,-234152,-234130,-234107,-234085,-234062,-234039,-234017,-233994,-233971,-233949,-233926,-233903,-233881,-233858,-233835,-233812,-233790,-233767,-233744,-233721,-233699,-233676,-233653,-233630,-233608,-233585,-233562,-233539,-233516,-233493,-233471,-233448,-233425,-233402,-233379,-233356,-233333,-233310,-233287,-233264,-233242,-233219,-233196,-233173,-233150,-233127,-233104,-233081,-233058,-233035,-233012,-232989,-232966,-232943,-232919,-232896,-232873,-232850,-232827,-232804,-232781,-232758,-232735,-232712,-232688,-232665,-232642,-232619,-232596,-232573,-232549,-232526,-232503,-232480,-232456,-232433,-232410,-232387,-232363,-232340,-232317,-232294,-232270,-232247,-232224,-232200,-232177,-232154,-232130,-232107,-232084,-232060,-232037,-232013,-231990,-231967,-231943,-231920,-231896,-231873,-231849,-231826,-231803,-231779,-231756,-231732,-231709,-231685,-231662,-231638,-231614,-231591,-231567,-231544,-231520,-231497,-231473,-231449,-231426,-231402,-231379,-231355,-231331,-231308,-231284,-231260,-231237,-231213,-231189,-231166,-231142,-231118,-231095,-231071,-231047,-231023,-231000,-230976,-230952,-230928,-230904,-230881,-230857,-230833,-230809,-230785,-230761,-230738,-230714,-230690,-230666,-230642,-230618,-230594,-230570,-230547,-230523,-230499,-230475,-230451,-230427,-230403,-230379,-230355,-230331,-230307,-230283,-230259,-230235,-230211,-230187,-230163,-230139,-230115,-230090,-230066,-230042,-230018,-229994,-229970,-229946,-229922,-229897,-229873,-229849,-229825,-229801,-229777,-229752,-229728,-229704,-229680,-229656,-229631,-229607,-229583,-229559,-229534,-229510,-229486,-229461,-229437,-229413,-229388,-229364,-229340,-229315,-229291,-229267,-229242,-229218,-229193,-229169,-229145,-229120,-229096,-229071,-229047,-229023,-228998,-228974,-228949,-228925,-228900,-228876,-228851,-228827,-228802,-228778,-228753,-228728,-228704,-228679,-228655,-228630,-228606,-228581,-228556,-228532,-228507,-228482,-228458,-228433,-228408,-228384,-228359,-228334,-228310,-228285,-228260,-228236,-228211,-228186,-228161,-228137,-228112,-228087,-228062,-228038,-228013,-227988,-227963,-227938,-227913,-227889,-227864,-227839,-227814,-227789,-227764,-227739,-227715,-227690,-227665,-227640,-227615,-227590,-227565,-227540,-227515,-227490,-227465,-227440,-227415,-227390,-227365,-227340,-227315,-227290,-227265,-227240,-227215,-227190,-227165,-227140,-227114,-227089,-227064,-227039,-227014,-226989,-226964,-226939,-226913,-226888,-226863,-226838,-226813,-226787,-226762,-226737,-226712,-226687,-226661,-226636,-226611,-226585,-226560,-226535,-226510,-226484,-226459,-226434,-226408,-226383,-226358,-226332,-226307,-226282,-226256,-226231,-226205,-226180,-226155,-226129,-226104,-226078,-226053,-226027,-226002,-225976,-225951,-225925,-225900,-225874,-225849,-225823,-225798,-225772,-225747,-225721,-225696,-225670,-225645,-225619,-225593,-225568,-225542,-225516,-225491,-225465,-225440,-225414,-225388,-225363,-225337,-225311,-225286,-225260,-225234,-225208,-225183,-225157,-225131,-225105,-225080,-225054,-225028,-225002,-224977,-224951,-224925,-224899,-224873,-224847,-224822,-224796,-224770,-224744,-224718,-224692,-224666,-224640,-224614,-224589,-224563,-224537,-224511,-224485,-224459,-224433,-224407,-224381,-224355,-224329,-224303,-224277,-224251,-224225,-224199,-224173,-224147,-224121,-224095,-224068,-224042,-224016,-223990,-223964,-223938,-223912,-223886,-223859,-223833,-223807,-223781,-223755,-223729,-223702,-223676,-223650,-223624,-223598,-223571,-223545,-223519,-223492,-223466,-223440,-223414,-223387,-223361,-223335,-223308,-223282,-223256,-223229,-223203,-223177,-223150,-223124,-223098,-223071,-223045,-223018,-222992,-222965,-222939,-222913,-222886,-222860,-222833,-222807,-222780,-222754,-222727,-222701,-222674,-222648,-222621,-222595,-222568,-222541,-222515,-222488,-222462,-222435,-222409,-222382,-222355,-222329,-222302,-222275,-222249,-222222,-222195,-222169,-222142,-222115,-222089,-222062,-222035,-222009,-221982,-221955,-221928,-221902,-221875,-221848,-221821,-221794,-221768,-221741,-221714,-221687,-221660,-221633,-221607,-221580,-221553,-221526,-221499,-221472,-221445,-221418,-221392,-221365,-221338,-221311,-221284,-221257,-221230,-221203,-221176,-221149,-221122,-221095,-221068,-221041,-221014,-220987,-220960,-220933,-220906,-220879,-220852,-220825,-220797,-220770,-220743,-220716,-220689,-220662,-220635,-220608,-220580,-220553,-220526,-220499,-220472,-220445,-220417,-220390,-220363,-220336,-220308,-220281,-220254,-220227,-220199,-220172,-220145,-220118,-220090,-220063,-220036,-220008,-219981,-219954,-219926,-219899,-219872,-219844,-219817,-219789,-219762,-219735,-219707,-219680,-219652,-219625,-219597,-219570,-219543,-219515,-219488,-219460,-219433,-219405,-219378,-219350,-219323,-219295,-219267,-219240,-219212,-219185,-219157,-219130,-219102,-219074,-219047,-219019,-218992,-218964,-218936,-218909,-218881,-218853,-218826,-218798,-218770,-218743,-218715,-218687,-218659,-218632,-218604,-218576,-218548,-218521,-218493,-218465,-218437,-218410,-218382,-218354,-218326,-218298,-218270,-218243,-218215,-218187,-218159,-218131,-218103,-218075,-218048,-218020,-217992,-217964,-217936,-217908,-217880,-217852,-217824,-217796,-217768,-217740,-217712,-217684,-217656,-217628,-217600,-217572,-217544,-217516,-217488,-217460,-217432,-217404,-217376,-217347,-217319,-217291,-217263,-217235,-217207,-217179,-217151,-217122,-217094,-217066,-217038,-217010,-216981,-216953,-216925,-216897,-216869,-216840,-216812,-216784,-216756,-216727,-216699,-216671,-216642,-216614,-216586,-216557,-216529,-216501,-216472,-216444,-216416,-216387,-216359,-216331,-216302,-216274,-216245,-216217,-216189,-216160,-216132,-216103,-216075,-216046,-216018,-215989,-215961,-215932,-215904,-215875,-215847,-215818,-215790,-215761,-215733,-215704,-215676,-215647,-215618,-215590,-215561,-215533,-215504,-215475,-215447,-215418,-215389,-215361,-215332,-215303,-215275,-215246,-215217,-215189,-215160,-215131,-215103,-215074,-215045,-215016,-214988,-214959,-214930,-214901,-214872,-214844,-214815,-214786,-214757,-214728,-214700,-214671,-214642,-214613,-214584,-214555,-214526,-214497,-214469,-214440,-214411,-214382,-214353,-214324,-214295,-214266,-214237,-214208,-214179,-214150,-214121,-214092,-214063,-214034,-214005,-213976,-213947,-213918,-213889,-213860,-213831,-213802,-213773,-213744,-213714,-213685,-213656,-213627,-213598,-213569,-213540,-213510,-213481,-213452,-213423,-213394,-213365,-213335,-213306,-213277,-213248,-213218,-213189,-213160,-213131,-213101,-213072,-213043,-213014,-212984,-212955,-212926,-212896,-212867,-212838,-212808,-212779,-212750,-212720,-212691,-212661,-212632,-212603,-212573,-212544,-212514,-212485,-212455,-212426,-212397,-212367,-212338,-212308,-212279,-212249,-212220,-212190,-212161,-212131,-212102,-212072,-212042,-212013,-211983,-211954,-211924,-211895,-211865,-211835,-211806,-211776,-211747,-211717,-211687,-211658,-211628,-211598,-211569,-211539,-211509,-211480,-211450,-211420,-211390,-211361,-211331,-211301,-211271,-211242,-211212,-211182,-211152,-211123,-211093,-211063,-211033,-211003,-210973,-210944,-210914,-210884,-210854,-210824,-210794,-210764,-210735,-210705,-210675,-210645,-210615,-210585,-210555,-210525,-210495,-210465,-210435,-210405,-210375,-210345,-210315,-210285,-210255,-210225,-210195,-210165,-210135,-210105,-210075,-210045,-210015,-209985,-209955,-209925,-209894,-209864,-209834,-209804,-209774,-209744,-209714,-209683,-209653,-209623,-209593,-209563,-209533,-209502,-209472,-209442,-209412,-209381,-209351,-209321,-209291,-209260,-209230,-209200,-209169,-209139,-209109,-209079,-209048,-209018,-208988,-208957,-208927,-208896,-208866,-208836,-208805,-208775,-208745,-208714,-208684,-208653,-208623,-208592,-208562,-208532,-208501,-208471,-208440,-208410,-208379,-208349,-208318,-208288,-208257,-208227,-208196,-208165,-208135,-208104,-208074,-208043,-208013,-207982,-207951,-207921,-207890,-207860,-207829,-207798,-207768,-207737,-207706,-207676,-207645,-207614,-207584,-207553,-207522,-207491,-207461,-207430,-207399,-207369,-207338,-207307,-207276,-207245,-207215,-207184,-207153,-207122,-207091,-207061,-207030,-206999,-206968,-206937,-206906,-206876,-206845,-206814,-206783,-206752,-206721,-206690,-206659,-206628,-206597,-206566,-206536,-206505,-206474,-206443,-206412,-206381,-206350,-206319,-206288,-206257,-206226,-206195,-206164,-206132,-206101,-206070,-206039,-206008,-205977,-205946,-205915,-205884,-205853,-205822,-205790,-205759,-205728,-205697,-205666,-205635,-205603,-205572,-205541,-205510,-205479,-205447,-205416,-205385,-205354,-205323,-205291,-205260,-205229,-205197,-205166,-205135,-205104,-205072,-205041,-205010,-204978,-204947,-204916,-204884,-204853,-204822,-204790,-204759,-204727,-204696,-204665,-204633,-204602,-204570,-204539,-204507,-204476,-204445,-204413,-204382,-204350,-204319,-204287,-204256,-204224,-204193,-204161,-204130,-204098,-204066,-204035,-204003,-203972,-203940,-203909,-203877,-203845,-203814,-203782,-203751,-203719,-203687,-203656,-203624,-203592,-203561,-203529,-203497,-203466,-203434,-203402,-203371,-203339,-203307,-203275,-203244,-203212,-203180,-203148,-203117,-203085,-203053,-203021,-202989,-202958,-202926,-202894,-202862,-202830,-202798,-202767,-202735,-202703,-202671,-202639,-202607,-202575,-202543,-202511,-202480,-202448,-202416,-202384,-202352,-202320,-202288,-202256,-202224,-202192,-202160,-202128,-202096,-202064,-202032,-202000,-201968,-201936,-201904,-201872,-201840,-201807,-201775,-201743,-201711,-201679,-201647,-201615,-201583,-201551,-201518,-201486,-201454,-201422,-201390,-201358,-201325,-201293,-201261,-201229,-201197,-201164,-201132,-201100,-201068,-201035,-201003,-200971,-200939,-200906,-200874,-200842,-200809,-200777,-200745,-200712,-200680,-200648,-200615,-200583,-200551,-200518,-200486,-200453,-200421,-200389,-200356,-200324,-200291,-200259,-200227,-200194,-200162,-200129,-200097,-200064,-200032,-199999,-199967,-199934,-199902,-199869,-199837,-199804,-199772,-199739,-199707,-199674,-199641,-199609,-199576,-199544,-199511,-199478,-199446,-199413,-199381,-199348,-199315,-199283,-199250,-199217,-199185,-199152,-199119,-199087,-199054,-199021,-198988,-198956,-198923,-198890,-198857,-198825,-198792,-198759,-198726,-198694,-198661,-198628,-198595,-198562,-198530,-198497,-198464,-198431,-198398,-198365,-198333,-198300,-198267,-198234,-198201,-198168,-198135,-198102,-198069,-198036,-198003,-197971,-197938,-197905,-197872,-197839,-197806,-197773,-197740,-197707,-197674,-197641,-197608,-197575,-197542,-197509,-197475,-197442,-197409,-197376,-197343,-197310,-197277,-197244,-197211,-197178,-197145,-197111,-197078,-197045,-197012,-196979,-196946,-196912,-196879,-196846,-196813,-196780,-196746,-196713,-196680,-196647,-196614,-196580,-196547,-196514,-196480,-196447,-196414,-196381,-196347,-196314,-196281,-196247,-196214,-196181,-196147,-196114,-196081,-196047,-196014,-195981,-195947,-195914,-195880,-195847,-195814,-195780,-195747,-195713,-195680,-195646,-195613,-195579,-195546,-195512,-195479,-195445,-195412,-195378,-195345,-195311,-195278,-195244,-195211,-195177,-195144,-195110,-195077,-195043,-195009,-194976,-194942,-194909,-194875,-194841,-194808,-194774,-194740,-194707,-194673,-194639,-194606,-194572,-194538,-194505,-194471,-194437,-194404,-194370,-194336,-194302,-194269,-194235,-194201,-194167,-194134,-194100,-194066,-194032,-193998,-193965,-193931,-193897,-193863,-193829,-193795,-193762,-193728,-193694,-193660,-193626,-193592,-193558,-193524,-193491,-193457,-193423,-193389,-193355,-193321,-193287,-193253,-193219,-193185,-193151,-193117,-193083,-193049,-193015,-192981,-192947,-192913,-192879,-192845,-192811,-192777,-192743,-192709,-192675,-192640,-192606,-192572,-192538,-192504,-192470,-192436,-192402,-192368,-192333,-192299,-192265,-192231,-192197,-192163,-192128,-192094,-192060,-192026,-191991,-191957,-191923,-191889,-191855,-191820,-191786,-191752,-191717,-191683,-191649,-191615,-191580,-191546,-191512,-191477,-191443,-191409,-191374,-191340,-191306,-191271,-191237,-191202,-191168,-191134,-191099,-191065,-191030,-190996,-190962,-190927,-190893,-190858,-190824,-190789,-190755,-190720,-190686,-190651,-190617,-190582,-190548,-190513,-190479,-190444,-190410,-190375,-190341,-190306,-190271,-190237,-190202,-190168,-190133,-190098,-190064,-190029,-189995,-189960,-189925,-189891,-189856,-189821,-189787,-189752,-189717,-189683,-189648,-189613,-189579,-189544,-189509,-189474,-189440,-189405,-189370,-189335,-189301,-189266,-189231,-189196,-189161,-189127,-189092,-189057,-189022,-188987,-188953,-188918,-188883,-188848,-188813,-188778,-188743,-188708,-188674,-188639,-188604,-188569,-188534,-188499,-188464,-188429,-188394,-188359,-188324,-188289,-188254,-188219,-188184,-188149,-188114,-188079,-188044,-188009,-187974,-187939,-187904,-187869,-187834,-187799,-187764,-187729,-187694,-187659,-187624,-187588,-187553,-187518,-187483,-187448,-187413,-187378,-187342,-187307,-187272,-187237,-187202,-187167,-187131,-187096,-187061,-187026,-186991,-186955,-186920,-186885,-186850,-186814,-186779,-186744,-186709,-186673,-186638,-186603,-186567,-186532,-186497,-186461,-186426,-186391,-186355,-186320,-186285,-186249,-186214,-186178,-186143,-186108,-186072,-186037,-186001,-185966,-185931,-185895,-185860,-185824,-185789,-185753,-185718,-185682,-185647,-185611,-185576,-185540,-185505,-185469,-185434,-185398,-185363,-185327,-185292,-185256,-185221,-185185,-185149,-185114,-185078,-185043,-185007,-184971,-184936,-184900,-184865,-184829,-184793,-184758,-184722,-184686,-184651,-184615,-184579,-184544,-184508,-184472,-184436,-184401,-184365,-184329,-184293,-184258,-184222,-184186,-184150,-184115,-184079,-184043,-184007,-183971,-183936,-183900,-183864,-183828,-183792,-183756,-183721,-183685,-183649,-183613,-183577,-183541,-183505,-183469,-183434,-183398,-183362,-183326,-183290,-183254,-183218,-183182,-183146,-183110,-183074,-183038,-183002,-182966,-182930,-182894,-182858,-182822,-182786,-182750,-182714,-182678,-182642,-182606,-182570,-182534,-182498,-182462,-182425,-182389,-182353,-182317,-182281,-182245,-182209,-182173,-182136,-182100,-182064,-182028,-181992,-181956,-181919,-181883,-181847,-181811,-181775,-181738,-181702,-181666,-181630,-181593,-181557,-181521,-181485,-181448,-181412,-181376,-181340,-181303,-181267,-181231,-181194,-181158,-181122,-181085,-181049,-181013,-180976,-180940,-180903,-180867,-180831,-180794,-180758,-180722,-180685,-180649,-180612,-180576,-180539,-180503,-180466,-180430,-180394,-180357,-180321,-180284,-180248,-180211,-180175,-180138,-180102,-180065,-180028,-179992,-179955,-179919,-179882,-179846,-179809,-179773,-179736,-179699,-179663,-179626,-179590,-179553,-179516,-179480,-179443,-179406,-179370,-179333,-179296,-179260,-179223,-179186,-179150,-179113,-179076,-179040,-179003,-178966,-178929,-178893,-178856,-178819,-178782,-178746,-178709,-178672,-178635,-178599,-178562,-178525,-178488,-178451,-178414,-178378,-178341,-178304,-178267,-178230,-178193,-178157,-178120,-178083,-178046,-178009,-177972,-177935,-177898,-177861,-177824,-177787,-177751,-177714,-177677,-177640,-177603,-177566,-177529,-177492,-177455,-177418,-177381,-177344,-177307,-177270,-177233,-177196,-177159,-177122,-177084,-177047,-177010,-176973,-176936,-176899,-176862,-176825,-176788,-176751,-176713,-176676,-176639,-176602,-176565,-176528,-176491,-176453,-176416,-176379,-176342,-176305,-176267,-176230,-176193,-176156,-176119,-176081,-176044,-176007,-175970,-175932,-175895,-175858,-175821,-175783,-175746,-175709,-175671,-175634,-175597,-175559,-175522,-175485,-175447,-175410,-175373,-175335,-175298,-175261,-175223,-175186,-175148,-175111,-175074,-175036,-174999,-174961,-174924,-174886,-174849,-174812,-174774,-174737,-174699,-174662,-174624,-174587,-174549,-174512,-174474,-174437,-174399,-174362,-174324,-174287,-174249,-174211,-174174,-174136,-174099,-174061,-174024,-173986,-173948,-173911,-173873,-173836,-173798,-173760,-173723,-173685,-173647,-173610,-173572,-173534,-173497,-173459,-173421,-173384,-173346,-173308,-173270,-173233,-173195,-173157,-173120,-173082,-173044,-173006,-172968,-172931,-172893,-172855,-172817,-172780,-172742,-172704,-172666,-172628,-172590,-172553,-172515,-172477,-172439,-172401,-172363,-172325,-172288,-172250,-172212,-172174,-172136,-172098,-172060,-172022,-171984,-171946,-171908,-171870,-171833,-171795,-171757,-171719,-171681,-171643,-171605,-171567,-171529,-171491,-171453,-171415,-171377,-171338,-171300,-171262,-171224,-171186,-171148,-171110,-171072,-171034,-170996,-170958,-170920,-170882,-170843,-170805,-170767,-170729,-170691,-170653,-170615,-170576,-170538,-170500,-170462,-170424,-170385,-170347,-170309,-170271,-170233,-170194,-170156,-170118,-170080,-170041,-170003,-169965,-169927,-169888,-169850,-169812,-169773,-169735,-169697,-169659,-169620,-169582,-169544,-169505,-169467,-169429,-169390,-169352,-169313,-169275,-169237,-169198,-169160,-169121,-169083,-169045,-169006,-168968,-168929,-168891,-168852,-168814,-168776,-168737,-168699,-168660,-168622,-168583,-168545,-168506,-168468,-168429,-168391,-168352,-168314,-168275,-168237,-168198,-168159,-168121,-168082,-168044,-168005,-167967,-167928,-167889,-167851,-167812,-167773,-167735,-167696,-167658,-167619,-167580,-167542,-167503,-167464,-167426,-167387,-167348,-167310,-167271,-167232,-167193,-167155,-167116,-167077,-167039,-167000,-166961,-166922,-166884,-166845,-166806,-166767,-166728,-166690,-166651,-166612,-166573,-166534,-166496,-166457,-166418,-166379,-166340,-166301,-166263,-166224,-166185,-166146,-166107,-166068,-166029,-165990,-165951,-165913,-165874,-165835,-165796,-165757,-165718,-165679,-165640,-165601,-165562,-165523,-165484,-165445,-165406,-165367,-165328,-165289,-165250,-165211,-165172,-165133,-165094,-165055,-165016,-164977,-164938,-164899,-164860,-164820,-164781,-164742,-164703,-164664,-164625,-164586,-164547,-164508,-164468,-164429,-164390,-164351,-164312,-164273,-164233,-164194,-164155,-164116,-164077,-164038,-163998,-163959,-163920,-163881,-163841,-163802,-163763,-163724,-163684,-163645,-163606,-163567,-163527,-163488,-163449,-163409,-163370,-163331,-163291,-163252,-163213,-163173,-163134,-163095,-163055,-163016,-162977,-162937,-162898,-162859,-162819,-162780,-162740,-162701,-162662,-162622,-162583,-162543,-162504,-162464,-162425,-162385,-162346,-162307,-162267,-162228,-162188,-162149,-162109,-162070,-162030,-161991,-161951,-161912,-161872,-161832,-161793,-161753,-161714,-161674,-161635,-161595,-161556,-161516,-161476,-161437,-161397,-161358,-161318,-161278,-161239,-161199,-161159,-161120,-161080,-161040,-161001,-160961,-160921,-160882,-160842,-160802,-160763,-160723,-160683,-160643,-160604,-160564,-160524,-160485,-160445,-160405,-160365,-160326,-160286,-160246,-160206,-160166,-160127,-160087,-160047,-160007,-159967,-159928,-159888,-159848,-159808,-159768,-159728,-159688,-159649,-159609,-159569,-159529,-159489,-159449,-159409,-159369,-159329,-159290,-159250,-159210,-159170,-159130,-159090,-159050,-159010,-158970,-158930,-158890,-158850,-158810,-158770,-158730,-158690,-158650,-158610,-158570,-158530,-158490,-158450,-158410,-158370,-158330,-158290,-158250,-158210,-158169,-158129,-158089,-158049,-158009,-157969,-157929,-157889,-157849,-157808,-157768,-157728,-157688,-157648,-157608,-157568,-157527,-157487,-157447,-157407,-157367,-157326,-157286,-157246,-157206,-157166,-157125,-157085,-157045,-157005,-156964,-156924,-156884,-156844,-156803,-156763,-156723,-156682,-156642,-156602,-156561,-156521,-156481,-156440,-156400,-156360,-156319,-156279,-156239,-156198,-156158,-156118,-156077,-156037,-155996,-155956,-155916,-155875,-155835,-155794,-155754,-155714,-155673,-155633,-155592,-155552,-155511,-155471,-155430,-155390,-155349,-155309,-155268,-155228,-155187,-155147,-155106,-155066,-155025,-154985,-154944,-154904,-154863,-154823,-154782,-154741,-154701,-154660,-154620,-154579,-154538,-154498,-154457,-154417,-154376,-154335,-154295,-154254,-154213,-154173,-154132,-154092,-154051,-154010,-153969,-153929,-153888,-153847,-153807,-153766,-153725,-153685,-153644,-153603,-153562,-153522,-153481,-153440,-153399,-153359,-153318,-153277,-153236,-153196,-153155,-153114,-153073,-153032,-152992,-152951,-152910,-152869,-152828,-152787,-152747,-152706,-152665,-152624,-152583,-152542,-152501,-152460,-152420,-152379,-152338,-152297,-152256,-152215,-152174,-152133,-152092,-152051,-152010,-151969,-151928,-151887,-151846,-151805,-151764,-151723,-151682,-151641,-151600,-151559,-151518,-151477,-151436,-151395,-151354,-151313,-151272,-151231,-151190,-151149,-151108,-151067,-151026,-150985,-150944,-150903,-150861,-150820,-150779,-150738,-150697,-150656,-150615,-150574,-150532,-150491,-150450,-150409,-150368,-150327,-150285,-150244,-150203,-150162,-150121,-150079,-150038,-149997,-149956,-149915,-149873,-149832,-149791,-149750,-149708,-149667,-149626,-149584,-149543,-149502,-149461,-149419,-149378,-149337,-149295,-149254,-149213,-149171,-149130,-149089,-149047,-149006,-148965,-148923,-148882,-148841,-148799,-148758,-148716,-148675,-148634,-148592,-148551,-148509,-148468,-148427,-148385,-148344,-148302,-148261,-148219,-148178,-148136,-148095,-148053,-148012,-147970,-147929,-147887,-147846,-147804,-147763,-147721,-147680,-147638,-147597,-147555,-147514,-147472,-147431,-147389,-147347,-147306,-147264,-147223,-147181,-147140,-147098,-147056,-147015,-146973,-146931,-146890,-146848,-146807,-146765,-146723,-146682,-146640,-146598,-146557,-146515,-146473,-146432,-146390,-146348,-146306,-146265,-146223,-146181,-146140,-146098,-146056,-146014,-145973,-145931,-145889,-145847,-145806,-145764,-145722,-145680,-145638,-145597,-145555,-145513,-145471,-145429,-145388,-145346,-145304,-145262,-145220,-145178,-145136,-145095,-145053,-145011,-144969,-144927,-144885,-144843,-144801,-144760,-144718,-144676,-144634,-144592,-144550,-144508,-144466,-144424,-144382,-144340,-144298,-144256,-144214,-144172,-144130,-144088,-144046,-144004,-143962,-143920,-143878,-143836,-143794,-143752,-143710,-143668,-143626,-143584,-143542,-143500,-143458,-143416,-143374,-143332,-143290,-143247,-143205,-143163,-143121,-143079,-143037,-142995,-142953,-142911,-142868,-142826,-142784,-142742,-142700,-142658,-142615,-142573,-142531,-142489,-142447,-142404,-142362,-142320,-142278,-142236,-142193,-142151,-142109,-142067,-142024,-141982,-141940,-141898,-141855,-141813,-141771,-141729,-141686,-141644,-141602,-141559,-141517,-141475,-141432,-141390,-141348,-141305,-141263,-141221,-141178,-141136,-141094,-141051,-141009,-140967,-140924,-140882,-140839,-140797,-140755,-140712,-140670,-140627,-140585,-140543,-140500,-140458,-140415,-140373,-140330,-140288,-140245,-140203,-140160,-140118,-140076,-140033,-139991,-139948,-139906,-139863,-139820,-139778,-139735,-139693,-139650,-139608,-139565,-139523,-139480,-139438,-139395,-139352,-139310,-139267,-139225,-139182,-139140,-139097,-139054,-139012,-138969,-138926,-138884,-138841,-138799,-138756,-138713,-138671,-138628,-138585,-138543,-138500,-138457,-138415,-138372,-138329,-138287,-138244,-138201,-138158,-138116,-138073,-138030,-137987,-137945,-137902,-137859,-137816,-137774,-137731,-137688,-137645,-137603,-137560,-137517,-137474,-137431,-137389,-137346,-137303,-137260,-137217,-137175,-137132,-137089,-137046,-137003,-136960,-136917,-136875,-136832,-136789,-136746,-136703,-136660,-136617,-136574,-136531,-136489,-136446,-136403,-136360,-136317,-136274,-136231,-136188,-136145,-136102,-136059,-136016,-135973,-135930,-135887,-135844,-135801,-135758,-135715,-135672,-135629,-135586,-135543,-135500,-135457,-135414,-135371,-135328,-135285,-135242,-135199,-135156,-135113,-135070,-135027,-134983,-134940,-134897,-134854,-134811,-134768,-134725,-134682,-134639,-134595,-134552,-134509,-134466,-134423,-134380,-134337,-134293,-134250,-134207,-134164,-134121,-134077,-134034,-133991,-133948,-133905,-133861,-133818,-133775,-133732,-133689,-133645,-133602,-133559,-133516,-133472,-133429,-133386,-133342,-133299,-133256,-133213,-133169,-133126,-133083,-133039,-132996,-132953,-132909,-132866,-132823,-132779,-132736,-132693,-132649,-132606,-132563,-132519,-132476,-132433,-132389,-132346,-132302,-132259,-132216,-132172,-132129,-132085,-132042,-131999,-131955,-131912,-131868,-131825,-131781,-131738,-131694,-131651,-131608,-131564,-131521,-131477,-131434,-131390,-131347,-131303,-131260,-131216,-131173,-131129,-131086,-131042,-130998,-130955,-130911,-130868,-130824,-130781,-130737,-130694,-130650,-130606,-130563,-130519,-130476,-130432,-130388,-130345,-130301,-130258,-130214,-130170,-130127,-130083,-130039,-129996,-129952,-129908,-129865,-129821,-129777,-129734,-129690,-129646,-129603,-129559,-129515,-129472,-129428,-129384,-129340,-129297,-129253,-129209,-129166,-129122,-129078,-129034,-128991,-128947,-128903,-128859,-128815,-128772,-128728,-128684,-128640,-128597,-128553,-128509,-128465,-128421,-128377,-128334,-128290,-128246,-128202,-128158,-128114,-128071,-128027,-127983,-127939,-127895,-127851,-127807,-127763,-127720,-127676,-127632,-127588,-127544,-127500,-127456,-127412,-127368,-127324,-127280,-127236,-127192,-127149,-127105,-127061,-127017,-126973,-126929,-126885,-126841,-126797,-126753,-126709,-126665,-126621,-126577,-126533,-126489,-126445,-126401,-126357,-126313,-126268,-126224,-126180,-126136,-126092,-126048,-126004,-125960,-125916,-125872,-125828,-125784,-125740,-125695,-125651,-125607,-125563,-125519,-125475,-125431,-125387,-125342,-125298,-125254,-125210,-125166,-125122,-125077,-125033,-124989,-124945,-124901,-124856,-124812,-124768,-124724,-124680,-124635,-124591,-124547,-124503,-124459,-124414,-124370,-124326,-124282,-124237,-124193,-124149,-124104,-124060,-124016,-123972,-123927,-123883,-123839,-123794,-123750,-123706,-123661,-123617,-123573,-123528,-123484,-123440,-123395,-123351,-123307,-123262,-123218,-123174,-123129,-123085,-123041,-122996,-122952,-122907,-122863,-122819,-122774,-122730,-122685,-122641,-122596,-122552,-122508,-122463,-122419,-122374,-122330,-122285,-122241,-122196,-122152,-122107,-122063,-122018,-121974,-121930,-121885,-121841,-121796,-121751,-121707,-121662,-121618,-121573,-121529,-121484,-121440,-121395,-121351,-121306,-121262,-121217,-121172,-121128,-121083,-121039,-120994,-120949,-120905,-120860,-120816,-120771,-120726,-120682,-120637,-120593,-120548,-120503,-120459,-120414,-120369,-120325,-120280,-120235,-120191,-120146,-120101,-120057,-120012,-119967,-119923,-119878,-119833,-119789,-119744,-119699,-119654,-119610,-119565,-119520,-119475,-119431,-119386,-119341,-119296,-119252,-119207,-119162,-119117,-119073,-119028,-118983,-118938,-118893,-118849,-118804,-118759,-118714,-118669,-118625,-118580,-118535,-118490,-118445,-118400,-118356,-118311,-118266,-118221,-118176,-118131,-118086,-118041,-117997,-117952,-117907,-117862,-117817,-117772,-117727,-117682,-117637,-117592,-117548,-117503,-117458,-117413,-117368,-117323,-117278,-117233,-117188,-117143,-117098,-117053,-117008,-116963,-116918,-116873,-116828,-116783,-116738,-116693,-116648,-116603,-116558,-116513,-116468,-116423,-116378,-116333,-116288,-116243,-116198,-116153,-116108,-116063,-116017,-115972,-115927,-115882,-115837,-115792,-115747,-115702,-115657,-115612,-115566,-115521,-115476,-115431,-115386,-115341,-115296,-115251,-115205,-115160,-115115,-115070,-115025,-114980,-114934,-114889,-114844,-114799,-114754,-114709,-114663,-114618,-114573,-114528,-114482,-114437,-114392,-114347,-114302,-114256,-114211,-114166,-114121,-114075,-114030,-113985,-113940,-113894,-113849,-113804,-113758,-113713,-113668,-113623,-113577,-113532,-113487,-113441,-113396,-113351,-113305,-113260,-113215,-113169,-113124,-113079,-113033,-112988,-112943,-112897,-112852,-112807,-112761,-112716,-112670,-112625,-112580,-112534,-112489,-112443,-112398,-112353,-112307,-112262,-112216,-112171,-112125,-112080,-112035,-111989,-111944,-111898,-111853,-111807,-111762,-111716,-111671,-111625,-111580,-111534,-111489,-111443,-111398,-111352,-111307,-111261,-111216,-111170,-111125,-111079,-111034,-110988,-110943,-110897,-110852,-110806,-110761,-110715,-110669,-110624,-110578,-110533,-110487,-110442,-110396,-110350,-110305,-110259,-110214,-110168,-110122,-110077,-110031,-109985,-109940,-109894,-109849,-109803,-109757,-109712,-109666,-109620,-109575,-109529,-109483,-109438,-109392,-109346,-109301,-109255,-109209,-109164,-109118,-109072,-109026,-108981,-108935,-108889,-108844,-108798,-108752,-108706,-108661,-108615,-108569,-108523,-108478,-108432,-108386,-108340,-108294,-108249,-108203,-108157,-108111,-108066,-108020,-107974,-107928,-107882,-107837,-107791,-107745,-107699,-107653,-107607,-107562,-107516,-107470,-107424,-107378,-107332,-107286,-107241,-107195,-107149,-107103,-107057,-107011,-106965,-106919,-106874,-106828,-106782,-106736,-106690,-106644,-106598,-106552,-106506,-106460,-106414,-106368,-106322,-106277,-106231,-106185,-106139,-106093,-106047,-106001,-105955,-105909,-105863,-105817,-105771,-105725,-105679,-105633,-105587,-105541,-105495,-105449,-105403,-105357,-105311,-105265,-105219,-105173,-105127,-105081,-105034,-104988,-104942,-104896,-104850,-104804,-104758,-104712,-104666,-104620,-104574,-104528,-104482,-104435,-104389,-104343,-104297,-104251,-104205,-104159,-104113,-104066,-104020,-103974,-103928,-103882,-103836,-103790,-103743,-103697,-103651,-103605,-103559,-103513,-103466,-103420,-103374,-103328,-103282,-103235,-103189,-103143,-103097,-103051,-103004,-102958,-102912,-102866,-102819,-102773,-102727,-102681,-102634,-102588,-102542,-102496,-102449,-102403,-102357,-102311,-102264,-102218,-102172,-102125,-102079,-102033,-101987,-101940,-101894,-101848,-101801,-101755,-101709,-101662,-101616,-101570,-101523,-101477,-101431,-101384,-101338,-101292,-101245,-101199,-101152,-101106,-101060,-101013,-100967,-100921,-100874,-100828,-100781,-100735,-100689,-100642,-100596,-100549,-100503,-100456,-100410,-100364,-100317,-100271,-100224,-100178,-100131,-100085,-100038,-99992,-99946,-99899,-99853,-99806,-99760,-99713,-99667,-99620,-99574,-99527,-99481,-99434,-99388,-99341,-99295,-99248,-99202,-99155,-99109,-99062,-99015,-98969,-98922,-98876,-98829,-98783,-98736,-98690,-98643,-98596,-98550,-98503,-98457,-98410,-98363,-98317,-98270,-98224,-98177,-98130,-98084,-98037,-97991,-97944,-97897,-97851,-97804,-97757,-97711,-97664,-97618,-97571,-97524,-97478,-97431,-97384,-97338,-97291,-97244,-97198,-97151,-97104,-97057,-97011,-96964,-96917,-96871,-96824,-96777,-96731,-96684,-96637,-96590,-96544,-96497,-96450,-96403,-96357,-96310,-96263,-96216,-96170,-96123,-96076,-96029,-95983,-95936,-95889,-95842,-95795,-95749,-95702,-95655,-95608,-95561,-95515,-95468,-95421,-95374,-95327,-95281,-95234,-95187,-95140,-95093,-95046,-95000,-94953,-94906,-94859,-94812,-94765,-94718,-94672,-94625,-94578,-94531,-94484,-94437,-94390,-94343,-94296,-94250,-94203,-94156,-94109,-94062,-94015,-93968,-93921,-93874,-93827,-93780,-93733,-93686,-93639,-93593,-93546,-93499,-93452,-93405,-93358,-93311,-93264,-93217,-93170,-93123,-93076,-93029,-92982,-92935,-92888,-92841,-92794,-92747,-92700,-92653,-92606,-92559,-92512,-92465,-92418,-92371,-92324,-92277,-92229,-92182,-92135,-92088,-92041,-91994,-91947,-91900,-91853,-91806,-91759,-91712,-91665,-91618,-91570,-91523,-91476,-91429,-91382,-91335,-91288,-91241,-91194,-91146,-91099,-91052,-91005,-90958,-90911,-90864,-90816,-90769,-90722,-90675,-90628,-90581,-90533,-90486,-90439,-90392,-90345,-90298,-90250,-90203,-90156,-90109,-90062,-90014,-89967,-89920,-89873,-89825,-89778,-89731,-89684,-89637,-89589,-89542,-89495,-89448,-89400,-89353,-89306,-89259,-89211,-89164,-89117,-89069,-89022,-88975,-88928,-88880,-88833,-88786,-88738,-88691,-88644,-88597,-88549,-88502,-88455,-88407,-88360,-88313,-88265,-88218,-88171,-88123,-88076,-88029,-87981,-87934,-87887,-87839,-87792,-87744,-87697,-87650,-87602,-87555,-87508,-87460,-87413,-87365,-87318,-87271,-87223,-87176,-87128,-87081,-87034,-86986,-86939,-86891,-86844,-86797,-86749,-86702,-86654,-86607,-86559,-86512,-86464,-86417,-86370,-86322,-86275,-86227,-86180,-86132,-86085,-86037,-85990,-85942,-85895,-85847,-85800,-85752,-85705,-85657,-85610,-85562,-85515,-85467,-85420,-85372,-85325,-85277,-85230,-85182,-85135,-85087,-85039,-84992,-84944,-84897,-84849,-84802,-84754,-84707,-84659,-84611,-84564,-84516,-84469,-84421,-84373,-84326,-84278,-84231,-84183,-84135,-84088,-84040,-83993,-83945,-83897,-83850,-83802,-83755,-83707,-83659,-83612,-83564,-83516,-83469,-83421,-83373,-83326,-83278,-83230,-83183,-83135,-83087,-83040,-82992,-82944,-82897,-82849,-82801,-82754,-82706,-82658,-82611,-82563,-82515,-82467,-82420,-82372,-82324,-82277,-82229,-82181,-82133,-82086,-82038,-81990,-81942,-81895,-81847,-81799,-81751,-81704,-81656,-81608,-81560,-81513,-81465,-81417,-81369,-81321,-81274,-81226,-81178,-81130,-81082,-81035,-80987,-80939,-80891,-80843,-80796,-80748,-80700,-80652,-80604,-80556,-80509,-80461,-80413,-80365,-80317,-80269,-80222,-80174,-80126,-80078,-80030,-79982,-79934,-79886,-79839,-79791,-79743,-79695,-79647,-79599,-79551,-79503,-79456,-79408,-79360,-79312,-79264,-79216,-79168,-79120,-79072,-79024,-78976,-78928,-78880,-78833,-78785,-78737,-78689,-78641,-78593,-78545,-78497,-78449,-78401,-78353,-78305,-78257,-78209,-78161,-78113,-78065,-78017,-77969,-77921,-77873,-77825,-77777,-77729,-77681,-77633,-77585,-77537,-77489,-77441,-77393,-77345,-77297,-77249,-77201,-77153,-77105,-77057,-77009,-76961,-76913,-76865,-76817,-76769,-76720,-76672,-76624,-76576,-76528,-76480,-76432,-76384,-76336,-76288,-76240,-76192,-76143,-76095,-76047,-75999,-75951,-75903,-75855,-75807,-75759,-75710,-75662,-75614,-75566,-75518,-75470,-75422,-75374,-75325,-75277,-75229,-75181,-75133,-75085,-75036,-74988,-74940,-74892,-74844,-74796,-74747,-74699,-74651,-74603,-74555,-74507,-74458,-74410,-74362,-74314,-74266,-74217,-74169,-74121,-74073,-74024,-73976,-73928,-73880,-73832,-73783,-73735,-73687,-73639,-73590,-73542,-73494,-73446,-73397,-73349,-73301,-73253,-73204,-73156,-73108,-73060,-73011,-72963,-72915,-72866,-72818,-72770,-72722,-72673,-72625,-72577,-72528,-72480,-72432,-72383,-72335,-72287,-72238,-72190,-72142,-72094,-72045,-71997,-71949,-71900,-71852,-71804,-71755,-71707,-71658,-71610,-71562,-71513,-71465,-71417,-71368,-71320,-71272,-71223,-71175,-71126,-71078,-71030,-70981,-70933,-70885,-70836,-70788,-70739,-70691,-70643,-70594,-70546,-70497,-70449,-70400,-70352,-70304,-70255,-70207,-70158,-70110,-70061,-70013,-69965,-69916,-69868,-69819,-69771,-69722,-69674,-69625,-69577,-69529,-69480,-69432,-69383,-69335,-69286,-69238,-69189,-69141,-69092,-69044,-68995,-68947,-68898,-68850,-68801,-68753,-68704,-68656,-68607,-68559,-68510,-68462,-68413,-68365,-68316,-68268,-68219,-68170,-68122,-68073,-68025,-67976,-67928,-67879,-67831,-67782,-67734,-67685,-67636,-67588,-67539,-67491,-67442,-67394,-67345,-67296,-67248,-67199,-67151,-67102,-67054,-67005,-66956,-66908,-66859,-66811,-66762,-66713,-66665,-66616,-66567,-66519,-66470,-66422,-66373,-66324,-66276,-66227,-66178,-66130,-66081,-66033,-65984,-65935,-65887,-65838,-65789,-65741,-65692,-65643,-65595,-65546,-65497,-65449,-65400,-65351,-65303,-65254,-65205,-65157,-65108,-65059,-65010,-64962,-64913,-64864,-64816,-64767,-64718,-64670,-64621,-64572,-64523,-64475,-64426,-64377,-64328,-64280,-64231,-64182,-64134,-64085,-64036,-63987,-63939,-63890,-63841,-63792,-63744,-63695,-63646,-63597,-63549,-63500,-63451,-63402,-63353,-63305,-63256,-63207,-63158,-63110,-63061,-63012,-62963,-62914,-62866,-62817,-62768,-62719,-62670,-62622,-62573,-62524,-62475,-62426,-62377,-62329,-62280,-62231,-62182,-62133,-62084,-62036,-61987,-61938,-61889,-61840,-61791,-61743,-61694,-61645,-61596,-61547,-61498,-61449,-61401,-61352,-61303,-61254,-61205,-61156,-61107,-61058,-61010,-60961,-60912,-60863,-60814,-60765,-60716,-60667,-60618,-60569,-60521,-60472,-60423,-60374,-60325,-60276,-60227,-60178,-60129,-60080,-60031,-59982,-59934,-59885,-59836,-59787,-59738,-59689,-59640,-59591,-59542,-59493,-59444,-59395,-59346,-59297,-59248,-59199,-59150,-59101,-59052,-59003,-58954,-58905,-58856,-58807,-58758,-58710,-58661,-58612,-58563,-58514,-58465,-58416,-58367,-58318,-58269,-58220,-58170,-58121,-58072,-58023,-57974,-57925,-57876,-57827,-57778,-57729,-57680,-57631,-57582,-57533,-57484,-57435,-57386,-57337,-57288,-57239,-57190,-57141,-57092,-57043,-56994,-56945,-56895,-56846,-56797,-56748,-56699,-56650,-56601,-56552,-56503,-56454,-56405,-56356,-56307,-56257,-56208,-56159,-56110,-56061,-56012,-55963,-55914,-55865,-55815,-55766,-55717,-55668,-55619,-55570,-55521,-55472,-55423,-55373,-55324,-55275,-55226,-55177,-55128,-55079,-55029,-54980,-54931,-54882,-54833,-54784,-54735,-54685,-54636,-54587,-54538,-54489,-54440,-54390,-54341,-54292,-54243,-54194,-54144,-54095,-54046,-53997,-53948,-53899,-53849,-53800,-53751,-53702,-53653,-53603,-53554,-53505,-53456,-53407,-53357,-53308,-53259,-53210,-53160,-53111,-53062,-53013,-52964,-52914,-52865,-52816,-52767,-52717,-52668,-52619,-52570,-52520,-52471,-52422,-52373,-52323,-52274,-52225,-52176,-52126,-52077,-52028,-51979,-51929,-51880,-51831,-51781,-51732,-51683,-51634,-51584,-51535,-51486,-51437,-51387,-51338,-51289,-51239,-51190,-51141,-51091,-51042,-50993,-50944,-50894,-50845,-50796,-50746,-50697,-50648,-50598,-50549,-50500,-50450,-50401,-50352,-50302,-50253,-50204,-50154,-50105,-50056,-50006,-49957,-49908,-49858,-49809,-49760,-49710,-49661,-49612,-49562,-49513,-49463,-49414,-49365,-49315,-49266,-49217,-49167,-49118,-49069,-49019,-48970,-48920,-48871,-48822,-48772,-48723,-48673,-48624,-48575,-48525,-48476,-48426,-48377,-48328,-48278,-48229,-48179,-48130,-48081,-48031,-47982,-47932,-47883,-47834,-47784,-47735,-47685,-47636,-47586,-47537,-47488,-47438,-47389,-47339,-47290,-47240,-47191,-47141,-47092,-47043,-46993,-46944,-46894,-46845,-46795,-46746,-46696,-46647,-46597,-46548,-46499,-46449,-46400,-46350,-46301,-46251,-46202,-46152,-46103,-46053,-46004,-45954,-45905,-45855,-45806,-45756,-45707,-45657,-45608,-45558,-45509,-45459,-45410,-45360,-45311,-45261,-45212,-45162,-45113,-45063,-45014,-44964,-44915,-44865,-44816,-44766,-44717,-44667,-44618,-44568,-44518,-44469,-44419,-44370,-44320,-44271,-44221,-44172,-44122,-44073,-44023,-43973,-43924,-43874,-43825,-43775,-43726,-43676,-43627,-43577,-43527,-43478,-43428,-43379,-43329,-43280,-43230,-43180,-43131,-43081,-43032,-42982,-42932,-42883,-42833,-42784,-42734,-42685,-42635,-42585,-42536,-42486,-42437,-42387,-42337,-42288,-42238,-42189,-42139,-42089,-42040,-41990,-41940,-41891,-41841,-41792,-41742,-41692,-41643,-41593,-41543,-41494,-41444,-41395,-41345,-41295,-41246,-41196,-41146,-41097,-41047,-40997,-40948,-40898,-40848,-40799,-40749,-40700,-40650,-40600,-40551,-40501,-40451,-40402,-40352,-40302,-40253,-40203,-40153,-40104,-40054,-40004,-39955,-39905,-39855,-39805,-39756,-39706,-39656,-39607,-39557,-39507,-39458,-39408,-39358,-39309,-39259,-39209,-39159,-39110,-39060,-39010,-38961,-38911,-38861,-38812,-38762,-38712,-38662,-38613,-38563,-38513,-38464,-38414,-38364,-38314,-38265,-38215,-38165,-38115,-38066,-38016,-37966,-37916,-37867,-37817,-37767,-37718,-37668,-37618,-37568,-37519,-37469,-37419,-37369,-37320,-37270,-37220,-37170,-37121,-37071,-37021,-36971,-36921,-36872,-36822,-36772,-36722,-36673,-36623,-36573,-36523,-36474,-36424,-36374,-36324,-36274,-36225,-36175,-36125,-36075,-36026,-35976,-35926,-35876,-35826,-35777,-35727,-35677,-35627,-35577,-35528,-35478,-35428,-35378,-35328,-35279,-35229,-35179,-35129,-35079,-35029,-34980,-34930,-34880,-34830,-34780,-34731,-34681,-34631,-34581,-34531,-34481,-34432,-34382,-34332,-34282,-34232,-34182,-34133,-34083,-34033,-33983,-33933,-33883,-33834,-33784,-33734,-33684,-33634,-33584,-33534,-33485,-33435,-33385,-33335,-33285,-33235,-33185,-33136,-33086,-33036,-32986,-32936,-32886,-32836,-32787,-32737,-32687,-32637,-32587,-32537,-32487,-32437,-32388,-32338,-32288,-32238,-32188,-32138,-32088,-32038,-31988,-31939,-31889,-31839,-31789,-31739,-31689,-31639,-31589,-31539,-31489,-31440,-31390,-31340,-31290,-31240,-31190,-31140,-31090,-31040,-30990,-30941,-30891,-30841,-30791,-30741,-30691,-30641,-30591,-30541,-30491,-30441,-30391,-30341,-30292,-30242,-30192,-30142,-30092,-30042,-29992,-29942,-29892,-29842,-29792,-29742,-29692,-29642,-29592,-29542,-29493,-29443,-29393,-29343,-29293,-29243,-29193,-29143,-29093,-29043,-28993,-28943,-28893,-28843,-28793,-28743,-28693,-28643,-28593,-28543,-28493,-28443,-28393,-28343,-28294,-28244,-28194,-28144,-28094,-28044,-27994,-27944,-27894,-27844,-27794,-27744,-27694,-27644,-27594,-27544,-27494,-27444,-27394,-27344,-27294,-27244,-27194,-27144,-27094,-27044,-26994,-26944,-26894,-26844,-26794,-26744,-26694,-26644,-26594,-26544,-26494,-26444,-26394,-26344,-26294,-26244,-26194,-26144,-26094,-26044,-25994,-25944,-25894,-25844,-25794,-25744,-25694,-25644,-25594,-25544,-25494,-25443,-25393,-25343,-25293,-25243,-25193,-25143,-25093,-25043,-24993,-24943,-24893,-24843,-24793,-24743,-24693,-24643,-24593,-24543,-24493,-24443,-24393,-24343,-24293,-24243,-24192,-24142,-24092,-24042,-23992,-23942,-23892,-23842,-23792,-23742,-23692,-23642,-23592,-23542,-23492,-23442,-23392,-23341,-23291,-23241,-23191,-23141,-23091,-23041,-22991,-22941,-22891,-22841,-22791,-22741,-22691,-22640,-22590,-22540,-22490,-22440,-22390,-22340,-22290,-22240,-22190,-22140,-22090,-22039,-21989,-21939,-21889,-21839,-21789,-21739,-21689,-21639,-21589,-21539,-21488,-21438,-21388,-21338,-21288,-21238,-21188,-21138,-21088,-21038,-20987,-20937,-20887,-20837,-20787,-20737,-20687,-20637,-20587,-20537,-20486,-20436,-20386,-20336,-20286,-20236,-20186,-20136,-20085,-20035,-19985,-19935,-19885,-19835,-19785,-19735,-19685,-19634,-19584,-19534,-19484,-19434,-19384,-19334,-19284,-19233,-19183,-19133,-19083,-19033,-18983,-18933,-18882,-18832,-18782,-18732,-18682,-18632,-18582,-18531,-18481,-18431,-18381,-18331,-18281,-18231,-18180,-18130,-18080,-18030,-17980,-17930,-17880,-17829,-17779,-17729,-17679,-17629,-17579,-17529,-17478,-17428,-17378,-17328,-17278,-17228,-17177,-17127,-17077,-17027,-16977,-16927,-16877,-16826,-16776,-16726,-16676,-16626,-16576,-16525,-16475,-16425,-16375,-16325,-16275,-16224,-16174,-16124,-16074,-16024,-15974,-15923,-15873,-15823,-15773,-15723,-15672,-15622,-15572,-15522,-15472,-15422,-15371,-15321,-15271,-15221,-15171,-15121,-15070,-15020,-14970,-14920,-14870,-14819,-14769,-14719,-14669,-14619,-14568,-14518,-14468,-14418,-14368,-14318,-14267,-14217,-14167,-14117,-14067,-14016,-13966,-13916,-13866,-13816,-13765,-13715,-13665,-13615,-13565,-13514,-13464,-13414,-13364,-13314,-13263,-13213,-13163,-13113,-13063,-13012,-12962,-12912,-12862,-12812,-12761,-12711,-12661,-12611,-12561,-12510,-12460,-12410,-12360,-12310,-12259,-12209,-12159,-12109,-12058,-12008,-11958,-11908,-11858,-11807,-11757,-11707,-11657,-11607,-11556,-11506,-11456,-11406,-11355,-11305,-11255,-11205,-11155,-11104,-11054,-11004,-10954,-10903,-10853,-10803,-10753,-10703,-10652,-10602,-10552,-10502,-10451,-10401,-10351,-10301,-10251,-10200,-10150,-10100,-10050,-9999,-9949,-9899,-9849,-9798,-9748,-9698,-9648,-9598,-9547,-9497,-9447,-9397,-9346,-9296,-9246,-9196,-9145,-9095,-9045,-8995,-8945,-8894,-8844,-8794,-8744,-8693,-8643,-8593,-8543,-8492,-8442,-8392,-8342,-8291,-8241,-8191,-8141,-8090,-8040,-7990,-7940,-7889,-7839,-7789,-7739,-7689,-7638,-7588,-7538,-7488,-7437,-7387,-7337,-7287,-7236,-7186,-7136,-7086,-7035,-6985,-6935,-6885,-6834,-6784,-6734,-6684,-6633,-6583,-6533,-6483,-6432,-6382,-6332,-6282,-6231,-6181,-6131,-6081,-6030,-5980,-5930,-5880,-5829,-5779,-5729,-5679,-5628,-5578,-5528,-5478,-5427,-5377,-5327,-5277,-5226,-5176,-5126,-5075,-5025,-4975,-4925,-4874,-4824,-4774,-4724,-4673,-4623,-4573,-4523,-4472,-4422,-4372,-4322,-4271,-4221,-4171,-4121,-4070,-4020,-3970,-3920,-3869,-3819,-3769,-3719,-3668,-3618,-3568,-3517,-3467,-3417,-3367,-3316,-3266,-3216,-3166,-3115,-3065,-3015,-2965,-2914,-2864,-2814,-2764,-2713,-2663,-2613,-2562,-2512,-2462,-2412,-2361,-2311,-2261,-2211,-2160,-2110,-2060,-2010,-1959,-1909,-1859,-1809,-1758,-1708,-1658,-1607,-1557,-1507,-1457,-1406,-1356,-1306,-1256,-1205,-1155,-1105,-1055,-1004,-954,-904,-854,-803,-753,-703,-652,-602,-552,-502,-451,-401,-351,-301,-250,-200,-150,-100,-49,0,50,101,151,201,251,302,352,402,452,503,553,603,653,704,754,804,855,905,955,1005,1056,1106,1156,1206,1257,1307,1357,1407,1458,1508,1558,1608,1659,1709,1759,1810,1860,1910,1960,2011,2061,2111,2161,2212,2262,2312,2362,2413,2463,2513,2563,2614,2664,2714,2765,2815,2865,2915,2966,3016,3066,3116,3167,3217,3267,3317,3368,3418,3468,3518,3569,3619,3669,3720,3770,3820,3870,3921,3971,4021,4071,4122,4172,4222,4272,4323,4373,4423,4473,4524,4574,4624,4674,4725,4775,4825,4875,4926,4976,5026,5076,5127,5177,5227,5278,5328,5378,5428,5479,5529,5579,5629,5680,5730,5780,5830,5881,5931,5981,6031,6082,6132,6182,6232,6283,6333,6383,6433,6484,6534,6584,6634,6685,6735,6785,6835,6886,6936,6986,7036,7087,7137,7187,7237,7288,7338,7388,7438,7489,7539,7589,7639,7690,7740,7790,7840,7890,7941,7991,8041,8091,8142,8192,8242,8292,8343,8393,8443,8493,8544,8594,8644,8694,8745,8795,8845,8895,8946,8996,9046,9096,9146,9197,9247,9297,9347,9398,9448,9498,9548,9599,9649,9699,9749,9799,9850,9900,9950,10000,10051,10101,10151,10201,10252,10302,10352,10402,10452,10503,10553,10603,10653,10704,10754,10804,10854,10904,10955,11005,11055,11105,11156,11206,11256,11306,11356,11407,11457,11507,11557,11608,11658,11708,11758,11808,11859,11909,11959,12009,12059,12110,12160,12210,12260,12311,12361,12411,12461,12511,12562,12612,12662,12712,12762,12813,12863,12913,12963,13013,13064,13114,13164,13214,13264,13315,13365,13415,13465,13515,13566,13616,13666,13716,13766,13817,13867,13917,13967,14017,14068,14118,14168,14218,14268,14319,14369,14419,14469,14519,14569,14620,14670,14720,14770,14820,14871,14921,14971,15021,15071,15122,15172,15222,15272,15322,15372,15423,15473,15523,15573,15623,15673,15724,15774,15824,15874,15924,15975,16025,16075,16125,16175,16225,16276,16326,16376,16426,16476,16526,16577,16627,16677,16727,16777,16827,16878,16928,16978,17028,17078,17128,17178,17229,17279,17329,17379,17429,17479,17530,17580,17630,17680,17730,17780,17830,17881,17931,17981,18031,18081,18131,18181,18232,18282,18332,18382,18432,18482,18532,18583,18633,18683,18733,18783,18833,18883,18934,18984,19034,19084,19134,19184,19234,19285,19335,19385,19435,19485,19535,19585,19635,19686,19736,19786,19836,19886,19936,19986,20036,20086,20137,20187,20237,20287,20337,20387,20437,20487,20538,20588,20638,20688,20738,20788,20838,20888,20938,20988,21039,21089,21139,21189,21239,21289,21339,21389,21439,21489,21540,21590,21640,21690,21740,21790,21840,21890,21940,21990,22040,22091,22141,22191,22241,22291,22341,22391,22441,22491,22541,22591,22641,22692,22742,22792,22842,22892,22942,22992,23042,23092,23142,23192,23242,23292,23342,23393,23443,23493,23543,23593,23643,23693,23743,23793,23843,23893,23943,23993,24043,24093,24143,24193,24244,24294,24344,24394,24444,24494,24544,24594,24644,24694,24744,24794,24844,24894,24944,24994,25044,25094,25144,25194,25244,25294,25344,25394,25444,25495,25545,25595,25645,25695,25745,25795,25845,25895,25945,25995,26045,26095,26145,26195,26245,26295,26345,26395,26445,26495,26545,26595,26645,26695,26745,26795,26845,26895,26945,26995,27045,27095,27145,27195,27245,27295,27345,27395,27445,27495,27545,27595,27645,27695,27745,27795,27845,27895,27945,27995,28045,28095,28145,28195,28245,28295,28344,28394,28444,28494,28544,28594,28644,28694,28744,28794,28844,28894,28944,28994,29044,29094,29144,29194,29244,29294,29344,29394,29444,29494,29543,29593,29643,29693,29743,29793,29843,29893,29943,29993,30043,30093,30143,30193,30243,30293,30342,30392,30442,30492,30542,30592,30642,30692,30742,30792,30842,30892,30942,30991,31041,31091,31141,31191,31241,31291,31341,31391,31441,31490,31540,31590,31640,31690,31740,31790,31840,31890,31940,31989,32039,32089,32139,32189,32239,32289,32339,32389,32438,32488,32538,32588,32638,32688,32738,32788,32837,32887,32937,32987,33037,33087,33137,33186,33236,33286,33336,33386,33436,33486,33535,33585,33635,33685,33735,33785,33835,33884,33934,33984,34034,34084,34134,34183,34233,34283,34333,34383,34433,34482,34532,34582,34632,34682,34732,34781,34831,34881,34931,34981,35030,35080,35130,35180,35230,35280,35329,35379,35429,35479,35529,35578,35628,35678,35728,35778,35827,35877,35927,35977,36027,36076,36126,36176,36226,36275,36325,36375,36425,36475,36524,36574,36624,36674,36723,36773,36823,36873,36922,36972,37022,37072,37122,37171,37221,37271,37321,37370,37420,37470,37520,37569,37619,37669,37719,37768,37818,37868,37917,37967,38017,38067,38116,38166,38216,38266,38315,38365,38415,38465,38514,38564,38614,38663,38713,38763,38813,38862,38912,38962,39011,39061,39111,39160,39210,39260,39310,39359,39409,39459,39508,39558,39608,39657,39707,39757,39806,39856,39906,39956,40005,40055,40105,40154,40204,40254,40303,40353,40403,40452,40502,40552,40601,40651,40701,40750,40800,40849,40899,40949,40998,41048,41098,41147,41197,41247,41296,41346,41396,41445,41495,41544,41594,41644,41693,41743,41793,41842,41892,41941,41991,42041,42090,42140,42190,42239,42289,42338,42388,42438,42487,42537,42586,42636,42686,42735,42785,42834,42884,42933,42983,43033,43082,43132,43181,43231,43281,43330,43380,43429,43479,43528,43578,43628,43677,43727,43776,43826,43875,43925,43974,44024,44074,44123,44173,44222,44272,44321,44371,44420,44470,44519,44569,44619,44668,44718,44767,44817,44866,44916,44965,45015,45064,45114,45163,45213,45262,45312,45361,45411,45460,45510,45559,45609,45658,45708,45757,45807,45856,45906,45955,46005,46054,46104,46153,46203,46252,46302,46351,46401,46450,46500,46549,46598,46648,46697,46747,46796,46846,46895,46945,46994,47044,47093,47142,47192,47241,47291,47340,47390,47439,47489,47538,47587,47637,47686,47736,47785,47835,47884,47933,47983,48032,48082,48131,48180,48230,48279,48329,48378,48427,48477,48526,48576,48625,48674,48724,48773,48823,48872,48921,48971,49020,49070,49119,49168,49218,49267,49316,49366,49415,49464,49514,49563,49613,49662,49711,49761,49810,49859,49909,49958,50007,50057,50106,50155,50205,50254,50303,50353,50402,50451,50501,50550,50599,50649,50698,50747,50797,50846,50895,50945,50994,51043,51092,51142,51191,51240,51290,51339,51388,51438,51487,51536,51585,51635,51684,51733,51782,51832,51881,51930,51980,52029,52078,52127,52177,52226,52275,52324,52374,52423,52472,52521,52571,52620,52669,52718,52768,52817,52866,52915,52965,53014,53063,53112,53161,53211,53260,53309,53358,53408,53457,53506,53555,53604,53654,53703,53752,53801,53850,53900,53949,53998,54047,54096,54145,54195,54244,54293,54342,54391,54441,54490,54539,54588,54637,54686,54736,54785,54834,54883,54932,54981,55030,55080,55129,55178,55227,55276,55325,55374,55424,55473,55522,55571,55620,55669,55718,55767,55816,55866,55915,55964,56013,56062,56111,56160,56209,56258,56308,56357,56406,56455,56504,56553,56602,56651,56700,56749,56798,56847,56896,56946,56995,57044,57093,57142,57191,57240,57289,57338,57387,57436,57485,57534,57583,57632,57681,57730,57779,57828,57877,57926,57975,58024,58073,58122,58171,58221,58270,58319,58368,58417,58466,58515,58564,58613,58662,58711,58759,58808,58857,58906,58955,59004,59053,59102,59151,59200,59249,59298,59347,59396,59445,59494,59543,59592,59641,59690,59739,59788,59837,59886,59935,59983,60032,60081,60130,60179,60228,60277,60326,60375,60424,60473,60522,60570,60619,60668,60717,60766,60815,60864,60913,60962,61011,61059,61108,61157,61206,61255,61304,61353,61402,61450,61499,61548,61597,61646,61695,61744,61792,61841,61890,61939,61988,62037,62085,62134,62183,62232,62281,62330,62378,62427,62476,62525,62574,62623,62671,62720,62769,62818,62867,62915,62964,63013,63062,63111,63159,63208,63257,63306,63354,63403,63452,63501,63550,63598,63647,63696,63745,63793,63842,63891,63940,63988,64037,64086,64135,64183,64232,64281,64329,64378,64427,64476,64524,64573,64622,64671,64719,64768,64817,64865,64914,64963,65011,65060,65109,65158,65206,65255,65304,65352,65401,65450,65498,65547,65596,65644,65693,65742,65790,65839,65888,65936,65985,66034,66082,66131,66179,66228,66277,66325,66374,66423,66471,66520,66568,66617,66666,66714,66763,66812,66860,66909,66957,67006,67055,67103,67152,67200,67249,67297,67346,67395,67443,67492,67540,67589,67637,67686,67735,67783,67832,67880,67929,67977,68026,68074,68123,68171,68220,68269,68317,68366,68414,68463,68511,68560,68608,68657,68705,68754,68802,68851,68899,68948,68996,69045,69093,69142,69190,69239,69287,69336,69384,69433,69481,69530,69578,69626,69675,69723,69772,69820,69869,69917,69966,70014,70062,70111,70159,70208,70256,70305,70353,70401,70450,70498,70547,70595,70644,70692,70740,70789,70837,70886,70934,70982,71031,71079,71127,71176,71224,71273,71321,71369,71418,71466,71514,71563,71611,71659,71708,71756,71805,71853,71901,71950,71998,72046,72095,72143,72191,72239,72288,72336,72384,72433,72481,72529,72578,72626,72674,72723,72771,72819,72867,72916,72964,73012,73061,73109,73157,73205,73254,73302,73350,73398,73447,73495,73543,73591,73640,73688,73736,73784,73833,73881,73929,73977,74025,74074,74122,74170,74218,74267,74315,74363,74411,74459,74508,74556,74604,74652,74700,74748,74797,74845,74893,74941,74989,75037,75086,75134,75182,75230,75278,75326,75375,75423,75471,75519,75567,75615,75663,75711,75760,75808,75856,75904,75952,76000,76048,76096,76144,76193,76241,76289,76337,76385,76433,76481,76529,76577,76625,76673,76721,76770,76818,76866,76914,76962,77010,77058,77106,77154,77202,77250,77298,77346,77394,77442,77490,77538,77586,77634,77682,77730,77778,77826,77874,77922,77970,78018,78066,78114,78162,78210,78258,78306,78354,78402,78450,78498,78546,78594,78642,78690,78738,78786,78834,78881,78929,78977,79025,79073,79121,79169,79217,79265,79313,79361,79409,79457,79504,79552,79600,79648,79696,79744,79792,79840,79887,79935,79983,80031,80079,80127,80175,80223,80270,80318,80366,80414,80462,80510,80557,80605,80653,80701,80749,80797,80844,80892,80940,80988,81036,81083,81131,81179,81227,81275,81322,81370,81418,81466,81514,81561,81609,81657,81705,81752,81800,81848,81896,81943,81991,82039,82087,82134,82182,82230,82278,82325,82373,82421,82468,82516,82564,82612,82659,82707,82755,82802,82850,82898,82945,82993,83041,83088,83136,83184,83231,83279,83327,83374,83422,83470,83517,83565,83613,83660,83708,83756,83803,83851,83898,83946,83994,84041,84089,84136,84184,84232,84279,84327,84374,84422,84470,84517,84565,84612,84660,84708,84755,84803,84850,84898,84945,84993,85040,85088,85136,85183,85231,85278,85326,85373,85421,85468,85516,85563,85611,85658,85706,85753,85801,85848,85896,85943,85991,86038,86086,86133,86181,86228,86276,86323,86371,86418,86465,86513,86560,86608,86655,86703,86750,86798,86845,86892,86940,86987,87035,87082,87129,87177,87224,87272,87319,87366,87414,87461,87509,87556,87603,87651,87698,87745,87793,87840,87888,87935,87982,88030,88077,88124,88172,88219,88266,88314,88361,88408,88456,88503,88550,88598,88645,88692,88739,88787,88834,88881,88929,88976,89023,89070,89118,89165,89212,89260,89307,89354,89401,89449,89496,89543,89590,89638,89685,89732,89779,89826,89874,89921,89968,90015,90063,90110,90157,90204,90251,90299,90346,90393,90440,90487,90534,90582,90629,90676,90723,90770,90817,90865,90912,90959,91006,91053,91100,91147,91195,91242,91289,91336,91383,91430,91477,91524,91571,91619,91666,91713,91760,91807,91854,91901,91948,91995,92042,92089,92136,92183,92230,92278,92325,92372,92419,92466,92513,92560,92607,92654,92701,92748,92795,92842,92889,92936,92983,93030,93077,93124,93171,93218,93265,93312,93359,93406,93453,93500,93547,93594,93640,93687,93734,93781,93828,93875,93922,93969,94016,94063,94110,94157,94204,94251,94297,94344,94391,94438,94485,94532,94579,94626,94673,94719,94766,94813,94860,94907,94954,95001,95047,95094,95141,95188,95235,95282,95328,95375,95422,95469,95516,95562,95609,95656,95703,95750,95796,95843,95890,95937,95984,96030,96077,96124,96171,96217,96264,96311,96358,96404,96451,96498,96545,96591,96638,96685,96732,96778,96825,96872,96918,96965,97012,97058,97105,97152,97199,97245,97292,97339,97385,97432,97479,97525,97572,97619,97665,97712,97758,97805,97852,97898,97945,97992,98038,98085,98131,98178,98225,98271,98318,98364,98411,98458,98504,98551,98597,98644,98691,98737,98784,98830,98877,98923,98970,99016,99063,99110,99156,99203,99249,99296,99342,99389,99435,99482,99528,99575,99621,99668,99714,99761,99807,99854,99900,99947,99993,100039,100086,100132,100179,100225,100272,100318,100365,100411,100457,100504,100550,100597,100643,100690,100736,100782,100829,100875,100922,100968,101014,101061,101107,101153,101200,101246,101293,101339,101385,101432,101478,101524,101571,101617,101663,101710,101756,101802,101849,101895,101941,101988,102034,102080,102126,102173,102219,102265,102312,102358,102404,102450,102497,102543,102589,102635,102682,102728,102774,102820,102867,102913,102959,103005,103052,103098,103144,103190,103236,103283,103329,103375,103421,103467,103514,103560,103606,103652,103698,103744,103791,103837,103883,103929,103975,104021,104067,104114,104160,104206,104252,104298,104344,104390,104436,104483,104529,104575,104621,104667,104713,104759,104805,104851,104897,104943,104989,105035,105082,105128,105174,105220,105266,105312,105358,105404,105450,105496,105542,105588,105634,105680,105726,105772,105818,105864,105910,105956,106002,106048,106094,106140,106186,106232,106278,106323,106369,106415,106461,106507,106553,106599,106645,106691,106737,106783,106829,106875,106920,106966,107012,107058,107104,107150,107196,107242,107287,107333,107379,107425,107471,107517,107563,107608,107654,107700,107746,107792,107838,107883,107929,107975,108021,108067,108112,108158,108204,108250,108295,108341,108387,108433,108479,108524,108570,108616,108662,108707,108753,108799,108845,108890,108936,108982,109027,109073,109119,109165,109210,109256,109302,109347,109393,109439,109484,109530,109576,109621,109667,109713,109758,109804,109850,109895,109941,109986,110032,110078,110123,110169,110215,110260,110306,110351,110397,110443,110488,110534,110579,110625,110670,110716,110762,110807,110853,110898,110944,110989,111035,111080,111126,111171,111217,111262,111308,111353,111399,111444,111490,111535,111581,111626,111672,111717,111763,111808,111854,111899,111945,111990,112036,112081,112126,112172,112217,112263,112308,112354,112399,112444,112490,112535,112581,112626,112671,112717,112762,112808,112853,112898,112944,112989,113034,113080,113125,113170,113216,113261,113306,113352,113397,113442,113488,113533,113578,113624,113669,113714,113759,113805,113850,113895,113941,113986,114031,114076,114122,114167,114212,114257,114303,114348,114393,114438,114483,114529,114574,114619,114664,114710,114755,114800,114845,114890,114935,114981,115026,115071,115116,115161,115206,115252,115297,115342,115387,115432,115477,115522,115567,115613,115658,115703,115748,115793,115838,115883,115928,115973,116018,116064,116109,116154,116199,116244,116289,116334,116379,116424,116469,116514,116559,116604,116649,116694,116739,116784,116829,116874,116919,116964,117009,117054,117099,117144,117189,117234,117279,117324,117369,117414,117459,117504,117549,117593,117638,117683,117728,117773,117818,117863,117908,117953,117998,118042,118087,118132,118177,118222,118267,118312,118357,118401,118446,118491,118536,118581,118626,118670,118715,118760,118805,118850,118894,118939,118984,119029,119074,119118,119163,119208,119253,119297,119342,119387,119432,119476,119521,119566,119611,119655,119700,119745,119790,119834,119879,119924,119968,120013,120058,120102,120147,120192,120236,120281,120326,120370,120415,120460,120504,120549,120594,120638,120683,120727,120772,120817,120861,120906,120950,120995,121040,121084,121129,121173,121218,121263,121307,121352,121396,121441,121485,121530,121574,121619,121663,121708,121752,121797,121842,121886,121931,121975,122019,122064,122108,122153,122197,122242,122286,122331,122375,122420,122464,122509,122553,122597,122642,122686,122731,122775,122820,122864,122908,122953,122997,123042,123086,123130,123175,123219,123263,123308,123352,123396,123441,123485,123529,123574,123618,123662,123707,123751,123795,123840,123884,123928,123973,124017,124061,124105,124150,124194,124238,124283,124327,124371,124415,124460,124504,124548,124592,124636,124681,124725,124769,124813,124857,124902,124946,124990,125034,125078,125123,125167,125211,125255,125299,125343,125388,125432,125476,125520,125564,125608,125652,125696,125741,125785,125829,125873,125917,125961,126005,126049,126093,126137,126181,126225,126269,126314,126358,126402,126446,126490,126534,126578,126622,126666,126710,126754,126798,126842,126886,126930,126974,127018,127062,127106,127150,127193,127237,127281,127325,127369,127413,127457,127501,127545,127589,127633,127677,127721,127764,127808,127852,127896,127940,127984,128028,128072,128115,128159,128203,128247,128291,128335,128378,128422,128466,128510,128554,128598,128641,128685,128729,128773,128816,128860,128904,128948,128992,129035,129079,129123,129167,129210,129254,129298,129341,129385,129429,129473,129516,129560,129604,129647,129691,129735,129778,129822,129866,129909,129953,129997,130040,130084,130128,130171,130215,130259,130302,130346,130389,130433,130477,130520,130564,130607,130651,130695,130738,130782,130825,130869,130912,130956,130999,131043,131087,131130,131174,131217,131261,131304,131348,131391,131435,131478,131522,131565,131609,131652,131695,131739,131782,131826,131869,131913,131956,132000,132043,132086,132130,132173,132217,132260,132303,132347,132390,132434,132477,132520,132564,132607,132650,132694,132737,132780,132824,132867,132910,132954,132997,133040,133084,133127,133170,133214,133257,133300,133343,133387,133430,133473,133517,133560,133603,133646,133690,133733,133776,133819,133862,133906,133949,133992,134035,134078,134122,134165,134208,134251,134294,134338,134381,134424,134467,134510,134553,134596,134640,134683,134726,134769,134812,134855,134898,134941,134984,135028,135071,135114,135157,135200,135243,135286,135329,135372,135415,135458,135501,135544,135587,135630,135673,135716,135759,135802,135845,135888,135931,135974,136017,136060,136103,136146,136189,136232,136275,136318,136361,136404,136447,136490,136532,136575,136618,136661,136704,136747,136790,136833,136876,136918,136961,137004,137047,137090,137133,137176,137218,137261,137304,137347,137390,137432,137475,137518,137561,137604,137646,137689,137732,137775,137817,137860,137903,137946,137988,138031,138074,138117,138159,138202,138245,138288,138330,138373,138416,138458,138501,138544,138586,138629,138672,138714,138757,138800,138842,138885,138927,138970,139013,139055,139098,139141,139183,139226,139268,139311,139353,139396,139439,139481,139524,139566,139609,139651,139694,139736,139779,139821,139864,139907,139949,139992,140034,140077,140119,140161,140204,140246,140289,140331,140374,140416,140459,140501,140544,140586,140628,140671,140713,140756,140798,140840,140883,140925,140968,141010,141052,141095,141137,141179,141222,141264,141306,141349,141391,141433,141476,141518,141560,141603,141645,141687,141730,141772,141814,141856,141899,141941,141983,142025,142068,142110,142152,142194,142237,142279,142321,142363,142405,142448,142490,142532,142574,142616,142659,142701,142743,142785,142827,142869,142912,142954,142996,143038,143080,143122,143164,143206,143248,143291,143333,143375,143417,143459,143501,143543,143585,143627,143669,143711,143753,143795,143837,143879,143921,143963,144005,144047,144089,144131,144173,144215,144257,144299,144341,144383,144425,144467,144509,144551,144593,144635,144677,144719,144761,144802,144844,144886,144928,144970,145012,145054,145096,145137,145179,145221,145263,145305,145347,145389,145430,145472,145514,145556,145598,145639,145681,145723,145765,145807,145848,145890,145932,145974,146015,146057,146099,146141,146182,146224,146266,146307,146349,146391,146433,146474,146516,146558,146599,146641,146683,146724,146766,146808,146849,146891,146932,146974,147016,147057,147099,147141,147182,147224,147265,147307,147348,147390,147432,147473,147515,147556,147598,147639,147681,147722,147764,147805,147847,147888,147930,147971,148013,148054,148096,148137,148179,148220,148262,148303,148345,148386,148428,148469,148510,148552,148593,148635,148676,148717,148759,148800,148842,148883,148924,148966,149007,149048,149090,149131,149172,149214,149255,149296,149338,149379,149420,149462,149503,149544,149585,149627,149668,149709,149751,149792,149833,149874,149916,149957,149998,150039,150080,150122,150163,150204,150245,150286,150328,150369,150410,150451,150492,150533,150575,150616,150657,150698,150739,150780,150821,150862,150904,150945,150986,151027,151068,151109,151150,151191,151232,151273,151314,151355,151396,151437,151478,151519,151560,151601,151642,151683,151724,151765,151806,151847,151888,151929,151970,152011,152052,152093,152134,152175,152216,152257,152298,152339,152380,152421,152461,152502,152543,152584,152625,152666,152707,152748,152788,152829,152870,152911,152952,152993,153033,153074,153115,153156,153197,153237,153278,153319,153360,153400,153441,153482,153523,153563,153604,153645,153686,153726,153767,153808,153848,153889,153930,153970,154011,154052,154093,154133,154174,154214,154255,154296,154336,154377,154418,154458,154499,154539,154580,154621,154661,154702,154742,154783,154824,154864,154905,154945,154986,155026,155067,155107,155148,155188,155229,155269,155310,155350,155391,155431,155472,155512,155553,155593,155634,155674,155715,155755,155795,155836,155876,155917,155957,155997,156038,156078,156119,156159,156199,156240,156280,156320,156361,156401,156441,156482,156522,156562,156603,156643,156683,156724,156764,156804,156845,156885,156925,156965,157006,157046,157086,157126,157167,157207,157247,157287,157327,157368,157408,157448,157488,157528,157569,157609,157649,157689,157729,157769,157809,157850,157890,157930,157970,158010,158050,158090,158130,158170,158211,158251,158291,158331,158371,158411,158451,158491,158531,158571,158611,158651,158691,158731,158771,158811,158851,158891,158931,158971,159011,159051,159091,159131,159171,159211,159251,159291,159330,159370,159410,159450,159490,159530,159570,159610,159650,159689,159729,159769,159809,159849,159889,159929,159968,160008,160048,160088,160128,160167,160207,160247,160287,160327,160366,160406,160446,160486,160525,160565,160605,160644,160684,160724,160764,160803,160843,160883,160922,160962,161002,161041,161081,161121,161160,161200,161240,161279,161319,161359,161398,161438,161477,161517,161557,161596,161636,161675,161715,161754,161794,161833,161873,161913,161952,161992,162031,162071,162110,162150,162189,162229,162268,162308,162347,162386,162426,162465,162505,162544,162584,162623,162663,162702,162741,162781,162820,162860,162899,162938,162978,163017,163056,163096,163135,163174,163214,163253,163292,163332,163371,163410,163450,163489,163528,163568,163607,163646,163685,163725,163764,163803,163842,163882,163921,163960,163999,164039,164078,164117,164156,164195,164234,164274,164313,164352,164391,164430,164469,164509,164548,164587,164626,164665,164704,164743,164782,164821,164861,164900,164939,164978,165017,165056,165095,165134,165173,165212,165251,165290,165329,165368,165407,165446,165485,165524,165563,165602,165641,165680,165719,165758,165797,165836,165875,165914,165952,165991,166030,166069,166108,166147,166186,166225,166264,166302,166341,166380,166419,166458,166497,166535,166574,166613,166652,166691,166729,166768,166807,166846,166885,166923,166962,167001,167040,167078,167117,167156,167194,167233,167272,167311,167349,167388,167427,167465,167504,167543,167581,167620,167659,167697,167736,167774,167813,167852,167890,167929,167968,168006,168045,168083,168122,168160,168199,168238,168276,168315,168353,168392,168430,168469,168507,168546,168584,168623,168661,168700,168738,168777,168815,168853,168892,168930,168969,169007,169046,169084,169122,169161,169199,169238,169276,169314,169353,169391,169430,169468,169506,169545,169583,169621,169660,169698,169736,169774,169813,169851,169889,169928,169966,170004,170042,170081,170119,170157,170195,170234,170272,170310,170348,170386,170425,170463,170501,170539,170577,170616,170654,170692,170730,170768,170806,170844,170883,170921,170959,170997,171035,171073,171111,171149,171187,171225,171263,171301,171339,171378,171416,171454,171492,171530,171568,171606,171644,171682,171720,171758,171796,171834,171871,171909,171947,171985,172023,172061,172099,172137,172175,172213,172251,172289,172326,172364,172402,172440,172478,172516,172554,172591,172629,172667,172705,172743,172781,172818,172856,172894,172932,172969,173007,173045,173083,173121,173158,173196,173234,173271,173309,173347,173385,173422,173460,173498,173535,173573,173611,173648,173686,173724,173761,173799,173837,173874,173912,173949,173987,174025,174062,174100,174137,174175,174212,174250,174288,174325,174363,174400,174438,174475,174513,174550,174588,174625,174663,174700,174738,174775,174813,174850,174887,174925,174962,175000,175037,175075,175112,175149,175187,175224,175262,175299,175336,175374,175411,175448,175486,175523,175560,175598,175635,175672,175710,175747,175784,175822,175859,175896,175933,175971,176008,176045,176082,176120,176157,176194,176231,176268,176306,176343,176380,176417,176454,176492,176529,176566,176603,176640,176677,176714,176752,176789,176826,176863,176900,176937,176974,177011,177048,177085,177123,177160,177197,177234,177271,177308,177345,177382,177419,177456,177493,177530,177567,177604,177641,177678,177715,177752,177788,177825,177862,177899,177936,177973,178010,178047,178084,178121,178158,178194,178231,178268,178305,178342,178379,178415,178452,178489,178526,178563,178600,178636,178673,178710,178747,178783,178820,178857,178894,178930,178967,179004,179041,179077,179114,179151,179187,179224,179261,179297,179334,179371,179407,179444,179481,179517,179554,179591,179627,179664,179700,179737,179774,179810,179847,179883,179920,179956,179993,180029,180066,180103,180139,180176,180212,180249,180285,180322,180358,180395,180431,180467,180504,180540,180577,180613,180650,180686,180723,180759,180795,180832,180868,180904,180941,180977,181014,181050,181086,181123,181159,181195,181232,181268,181304,181341,181377,181413,181449,181486,181522,181558,181594,181631,181667,181703,181739,181776,181812,181848,181884,181920,181957,181993,182029,182065,182101,182137,182174,182210,182246,182282,182318,182354,182390,182426,182463,182499,182535,182571,182607,182643,182679,182715,182751,182787,182823,182859,182895,182931,182967,183003,183039,183075,183111,183147,183183,183219,183255,183291,183327,183363,183399,183435,183470,183506,183542,183578,183614,183650,183686,183722,183757,183793,183829,183865,183901,183937,183972,184008,184044,184080,184116,184151,184187,184223,184259,184294,184330,184366,184402,184437,184473,184509,184545,184580,184616,184652,184687,184723,184759,184794,184830,184866,184901,184937,184972,185008,185044,185079,185115,185150,185186,185222,185257,185293,185328,185364,185399,185435,185470,185506,185541,185577,185612,185648,185683,185719,185754,185790,185825,185861,185896,185932,185967,186002,186038,186073,186109,186144,186179,186215,186250,186286,186321,186356,186392,186427,186462,186498,186533,186568,186604,186639,186674,186710,186745,186780,186815,186851,186886,186921,186956,186992,187027,187062,187097,187132,187168,187203,187238,187273,187308,187343,187379,187414,187449,187484,187519,187554,187589,187625,187660,187695,187730,187765,187800,187835,187870,187905,187940,187975,188010,188045,188080,188115,188150,188185,188220,188255,188290,188325,188360,188395,188430,188465,188500,188535,188570,188605,188640,188675,188709,188744,188779,188814,188849,188884,188919,188954,188988,189023,189058,189093,189128,189162,189197,189232,189267,189302,189336,189371,189406,189441,189475,189510,189545,189580,189614,189649,189684,189718,189753,189788,189822,189857,189892,189926,189961,189996,190030,190065,190099,190134,190169,190203,190238,190272,190307,190342,190376,190411,190445,190480,190514,190549,190583,190618,190652,190687,190721,190756,190790,190825,190859,190894,190928,190963,190997,191031,191066,191100,191135,191169,191203,191238,191272,191307,191341,191375,191410,191444,191478,191513,191547,191581,191616,191650,191684,191718,191753,191787,191821,191856,191890,191924,191958,191992,192027,192061,192095,192129,192164,192198,192232,192266,192300,192334,192369,192403,192437,192471,192505,192539,192573,192607,192641,192676,192710,192744,192778,192812,192846,192880,192914,192948,192982,193016,193050,193084,193118,193152,193186,193220,193254,193288,193322,193356,193390,193424,193458,193492,193525,193559,193593,193627,193661,193695,193729,193763,193796,193830,193864,193898,193932,193966,193999,194033,194067,194101,194135,194168,194202,194236,194270,194303,194337,194371,194405,194438,194472,194506,194539,194573,194607,194640,194674,194708,194741,194775,194809,194842,194876,194910,194943,194977,195010,195044,195078,195111,195145,195178,195212,195245,195279,195312,195346,195379,195413,195446,195480,195513,195547,195580,195614,195647,195681,195714,195748,195781,195815,195848,195881,195915,195948,195982,196015,196048,196082,196115,196148,196182,196215,196248,196282,196315,196348,196382,196415,196448,196481,196515,196548,196581,196615,196648,196681,196714,196747,196781,196814,196847,196880,196913,196947,196980,197013,197046,197079,197112,197146,197179,197212,197245,197278,197311,197344,197377,197410,197443,197476,197510,197543,197576,197609,197642,197675,197708,197741,197774,197807,197840,197873,197906,197939,197972,198004,198037,198070,198103,198136,198169,198202,198235,198268,198301,198334,198366,198399,198432,198465,198498,198531,198563,198596,198629,198662,198695,198727,198760,198793,198826,198858,198891,198924,198957,198989,199022,199055,199088,199120,199153,199186,199218,199251,199284,199316,199349,199382,199414,199447,199479,199512,199545,199577,199610,199642,199675,199708,199740,199773,199805,199838,199870,199903,199935,199968,200000,200033,200065,200098,200130,200163,200195,200228,200260,200292,200325,200357,200390,200422,200454,200487,200519,200552,200584,200616,200649,200681,200713,200746,200778,200810,200843,200875,200907,200940,200972,201004,201036,201069,201101,201133,201165,201198,201230,201262,201294,201326,201359,201391,201423,201455,201487,201519,201552,201584,201616,201648,201680,201712,201744,201776,201808,201841,201873,201905,201937,201969,202001,202033,202065,202097,202129,202161,202193,202225,202257,202289,202321,202353,202385,202417,202449,202481,202512,202544,202576,202608,202640,202672,202704,202736,202768,202799,202831,202863,202895,202927,202959,202990,203022,203054,203086,203118,203149,203181,203213,203245,203276,203308,203340,203372,203403,203435,203467,203498,203530,203562,203593,203625,203657,203688,203720,203752,203783,203815,203846,203878,203910,203941,203973,204004,204036,204067,204099,204131,204162,204194,204225,204257,204288,204320,204351,204383,204414,204446,204477,204508,204540,204571,204603,204634,204666,204697,204728,204760,204791,204823,204854,204885,204917,204948,204979,205011,205042,205073,205105,205136,205167,205198,205230,205261,205292,205324,205355,205386,205417,205448,205480,205511,205542,205573,205604,205636,205667,205698,205729,205760,205791,205823,205854,205885,205916,205947,205978,206009,206040,206071,206102,206133,206165,206196,206227,206258,206289,206320,206351,206382,206413,206444,206475,206506,206537,206567,206598,206629,206660,206691,206722,206753,206784,206815,206846,206877,206907,206938,206969,207000,207031,207062,207092,207123,207154,207185,207216,207246,207277,207308,207339,207370,207400,207431,207462,207492,207523,207554,207585,207615,207646,207677,207707,207738,207769,207799,207830,207861,207891,207922,207952,207983,208014,208044,208075,208105,208136,208166,208197,208228,208258,208289,208319,208350,208380,208411,208441,208472,208502,208533,208563,208593,208624,208654,208685,208715,208746,208776,208806,208837,208867,208897,208928,208958,208989,209019,209049,209080,209110,209140,209170,209201,209231,209261,209292,209322,209352,209382,209413,209443,209473,209503,209534,209564,209594,209624,209654,209684,209715,209745,209775,209805,209835,209865,209895,209926,209956,209986,210016,210046,210076,210106,210136,210166,210196,210226,210256,210286,210316,210346,210376,210406,210436,210466,210496,210526,210556,210586,210616,210646,210676,210706,210736,210765,210795,210825,210855,210885,210915,210945,210974,211004,211034,211064,211094,211124,211153,211183,211213,211243,211272,211302,211332,211362,211391,211421,211451,211481,211510,211540,211570,211599,211629,211659,211688,211718,211748,211777,211807,211836,211866,211896,211925,211955,211984,212014,212043,212073,212103,212132,212162,212191,212221,212250,212280,212309,212339,212368,212398,212427,212456,212486,212515,212545,212574,212604,212633,212662,212692,212721,212751,212780,212809,212839,212868,212897,212927,212956,212985,213015,213044,213073,213102,213132,213161,213190,213219,213249,213278,213307,213336,213366,213395,213424,213453,213482,213511,213541,213570,213599,213628,213657,213686,213715,213745,213774,213803,213832,213861,213890,213919,213948,213977,214006,214035,214064,214093,214122,214151,214180,214209,214238,214267,214296,214325,214354,214383,214412,214441,214470,214498,214527,214556,214585,214614,214643,214672,214701,214729,214758,214787,214816,214845,214873,214902,214931,214960,214989,215017,215046,215075,215104,215132,215161,215190,215218,215247,215276,215304,215333,215362,215390,215419,215448,215476,215505,215534,215562,215591,215619,215648,215677,215705,215734,215762,215791,215819,215848,215876,215905,215933,215962,215990,216019,216047,216076,216104,216133,216161,216190,216218,216246,216275,216303,216332,216360,216388,216417,216445,216473,216502,216530,216558,216587,216615,216643,216672,216700,216728,216757,216785,216813,216841,216870,216898,216926,216954,216982,217011,217039,217067,217095,217123,217152,217180,217208,217236,217264,217292,217320,217348,217377,217405,217433,217461,217489,217517,217545,217573,217601,217629,217657,217685,217713,217741,217769,217797,217825,217853,217881,217909,217937,217965,217993,218021,218049,218076,218104,218132,218160,218188,218216,218244,218271,218299,218327,218355,218383,218411,218438,218466,218494,218522,218549,218577,218605,218633,218660,218688,218716,218744,218771,218799,218827,218854,218882,218910,218937,218965,218993,219020,219048,219075,219103,219131,219158,219186,219213,219241,219268,219296,219324,219351,219379,219406,219434,219461,219489,219516,219544,219571,219598,219626,219653,219681,219708,219736,219763,219790,219818,219845,219873,219900,219927,219955,219982,220009,220037,220064,220091,220119,220146,220173,220200,220228,220255,220282,220309,220337,220364,220391,220418,220446,220473,220500,220527,220554,220581,220609,220636,220663,220690,220717,220744,220771,220798,220826,220853,220880,220907,220934,220961,220988,221015,221042,221069,221096,221123,221150,221177,221204,221231,221258,221285,221312,221339,221366,221393,221419,221446,221473,221500,221527,221554,221581,221608,221634,221661,221688,221715,221742,221769,221795,221822,221849,221876,221903,221929,221956,221983,222010,222036,222063,222090,222116,222143,222170,222196,222223,222250,222276,222303,222330,222356,222383,222410,222436,222463,222489,222516,222542,222569,222596,222622,222649,222675,222702,222728,222755,222781,222808,222834,222861,222887,222914,222940,222966,222993,223019,223046,223072,223099,223125,223151,223178,223204,223230,223257,223283,223309,223336,223362,223388,223415,223441,223467,223493,223520,223546,223572,223599,223625,223651,223677,223703,223730,223756,223782,223808,223834,223860,223887,223913,223939,223965,223991,224017,224043,224069,224096,224122,224148,224174,224200,224226,224252,224278,224304,224330,224356,224382,224408,224434,224460,224486,224512,224538,224564,224590,224615,224641,224667,224693,224719,224745,224771,224797,224823,224848,224874,224900,224926,224952,224978,225003,225029,225055,225081,225106,225132,225158,225184,225209,225235,225261,225287,225312,225338,225364,225389,225415,225441,225466,225492,225517,225543,225569,225594,225620,225646,225671,225697,225722,225748,225773,225799,225824,225850,225875,225901,225926,225952,225977,226003,226028,226054,226079,226105,226130,226156,226181,226206,226232,226257,226283,226308,226333,226359,226384,226409,226435,226460,226485,226511,226536,226561,226586,226612,226637,226662,226688,226713,226738,226763,226788,226814,226839,226864,226889,226914,226940,226965,226990,227015,227040,227065,227090,227115,227141,227166,227191,227216,227241,227266,227291,227316,227341,227366,227391,227416,227441,227466,227491,227516,227541,227566,227591,227616,227641,227666,227691,227716,227740,227765,227790,227815,227840,227865,227890,227914,227939,227964,227989,228014,228039,228063,228088,228113,228138,228162,228187,228212,228237,228261,228286,228311,228335,228360,228385,228409,228434,228459,228483,228508,228533,228557,228582,228607,228631,228656,228680,228705,228729,228754,228779,228803,228828,228852,228877,228901,228926,228950,228975,228999,229024,229048,229072,229097,229121,229146,229170,229194,229219,229243,229268,229292,229316,229341,229365,229389,229414,229438,229462,229487,229511,229535,229560,229584,229608,229632,229657,229681,229705,229729,229753,229778,229802,229826,229850,229874,229898,229923,229947,229971,229995,230019,230043,230067,230091,230116,230140,230164,230188,230212,230236,230260,230284,230308,230332,230356,230380,230404,230428,230452,230476,230500,230524,230548,230571,230595,230619,230643,230667,230691,230715,230739,230762,230786,230810,230834,230858,230882,230905,230929,230953,230977,231001,231024,231048,231072,231096,231119,231143,231167,231190,231214,231238,231261,231285,231309,231332,231356,231380,231403,231427,231450,231474,231498,231521,231545,231568,231592,231615,231639,231663,231686,231710,231733,231757,231780,231804,231827,231850,231874,231897,231921,231944,231968,231991,232014,232038,232061,232085,232108,232131,232155,232178,232201,232225,232248,232271,232295,232318,232341,232364,232388,232411,232434,232457,232481,232504,232527,232550,232574,232597,232620,232643,232666,232689,232713,232736,232759,232782,232805,232828,232851,232874,232897,232920,232944,232967,232990,233013,233036,233059,233082,233105,233128,233151,233174,233197,233220,233243,233265,233288,233311,233334,233357,233380,233403,233426,233449,233472,233494,233517,233540,233563,233586,233609,233631,233654,233677,233700,233722,233745,233768,233791,233813,233836,233859,233882,233904,233927,233950,233972,233995,234018,234040,234063,234086,234108,234131,234153,234176,234199,234221,234244,234266,234289,234311,234334,234356,234379,234401,234424,234446,234469,234491,234514,234536,234559,234581,234604,234626,234649,234671,234693,234716,234738,234760,234783,234805,234828,234850,234872,234894,234917,234939,234961,234984,235006,235028,235050,235073,235095,235117,235139,235162,235184,235206,235228,235250,235273,235295,235317,235339,235361,235383,235405,235428,235450,235472,235494,235516,235538,235560,235582,235604,235626,235648,235670,235692,235714,235736,235758,235780,235802,235824,235846,235868,235890,235912,235934,235956,235978,235999,236021,236043,236065,236087,236109,236131,236152,236174,236196,236218,236240,236261,236283,236305,236327,236348,236370,236392,236414,236435,236457,236479,236500,236522,236544,236565,236587,236609,236630,236652,236674,236695,236717,236738,236760,236782,236803,236825,236846,236868,236889,236911,236932,236954,236975,236997,237018,237040,237061,237083,237104,237126,237147,237168,237190,237211,237233,237254,237275,237297,237318,237339,237361,237382,237403,237425,237446,237467,237489,237510,237531,237552,237574,237595,237616,237637,237659,237680,237701,237722,237743,237765,237786,237807,237828,237849,237870,237891,237913,237934,237955,237976,237997,238018,238039,238060,238081,238102,238123,238144,238165,238186,238207,238228,238249,238270,238291,238312,238333,238354,238375,238396,238417,238437,238458,238479,238500,238521,238542,238563,238583,238604,238625,238646,238667,238688,238708,238729,238750,238771,238791,238812,238833,238853,238874,238895,238916,238936,238957,238978,238998,239019,239040,239060,239081,239101,239122,239143,239163,239184,239204,239225,239245,239266,239287,239307,239328,239348,239369,239389,239410,239430,239450,239471,239491,239512,239532,239553,239573,239593,239614,239634,239655,239675,239695,239716,239736,239756,239777,239797,239817,239838,239858,239878,239898,239919,239939,239959,239979,240000,240020,240040,240060,240080,240101,240121,240141,240161,240181,240201,240221,240242,240262,240282,240302,240322,240342,240362,240382,240402,240422,240442,240462,240482,240502,240522,240542,240562,240582,240602,240622,240642,240662,240682,240702,240722,240742,240762,240781,240801,240821,240841,240861,240881,240901,240920,240940,240960,240980,241000,241019,241039,241059,241079,241098,241118,241138,241157,241177,241197,241217,241236,241256,241276,241295,241315,241334,241354,241374,241393,241413,241433,241452,241472,241491,241511,241530,241550,241569,241589,241608,241628,241647,241667,241686,241706,241725,241745,241764,241784,241803,241822,241842,241861,241881,241900,241919,241939,241958,241977,241997,242016,242035,242055,242074,242093,242112,242132,242151,242170,242189,242209,242228,242247,242266,242286,242305,242324,242343,242362,242381,242401,242420,242439,242458,242477,242496,242515,242534,242553,242572,242591,242611,242630,242649,242668,242687,242706,242725,242744,242763,242782,242800,242819,242838,242857,242876,242895,242914,242933,242952,242971,242990,243008,243027,243046,243065,243084,243103,243121,243140,243159,243178,243196,243215,243234,243253,243271,243290,243309,243328,243346,243365,243384,243402,243421,243440,243458,243477,243496,243514,243533,243551,243570,243588,243607,243626,243644,243663,243681,243700,243718,243737,243755,243774,243792,243811,243829,243848,243866,243885,243903,243921,243940,243958,243977,243995,244013,244032,244050,244068,244087,244105,244123,244142,244160,244178,244197,244215,244233,244251,244270,244288,244306,244324,244343,244361,244379,244397,244415,244433,244452,244470,244488,244506,244524,244542,244560,244578,244597,244615,244633,244651,244669,244687,244705,244723,244741,244759,244777,244795,244813,244831,244849,244867,244885,244903,244921,244938,244956,244974,244992,245010,245028,245046,245064,245081,245099,245117,245135,245153,245171,245188,245206,245224,245242,245259,245277,245295,245313,245330,245348,245366,245383,245401,245419,245436,245454,245472,245489,245507,245525,245542,245560,245577,245595,245613,245630,245648,245665,245683,245700,245718,245735,245753,245770,245788,245805,245823,245840,245858,245875,245892,245910,245927,245945,245962,245979,245997,246014,246032,246049,246066,246084,246101,246118,246136,246153,246170,246187,246205,246222,246239,246256,246274,246291,246308,246325,246342,246360,246377,246394,246411,246428,246445,246463,246480,246497,246514,246531,246548,246565,246582,246599,246616,246633,246650,246667,246684,246701,246718,246735,246752,246769,246786,246803,246820,246837,246854,246871,246888,246905,246922,246938,246955,246972,246989,247006,247023,247040,247056,247073,247090,247107,247123,247140,247157,247174,247190,247207,247224,247241,247257,247274,247291,247307,247324,247341,247357,247374,247391,247407,247424,247440,247457,247474,247490,247507,247523,247540,247556,247573,247589,247606,247622,247639,247655,247672,247688,247705,247721,247738,247754,247771,247787,247803,247820,247836,247853,247869,247885,247902,247918,247934,247951,247967,247983,248000,248016,248032,248048,248065,248081,248097,248113,248130,248146,248162,248178,248194,248211,248227,248243,248259,248275,248291,248307,248323,248340,248356,248372,248388,248404,248420,248436,248452,248468,248484,248500,248516,248532,248548,248564,248580,248596,248612,248628,248644,248660,248676,248691,248707,248723,248739,248755,248771,248787,248803,248818,248834,248850,248866,248882,248897,248913,248929,248945,248960,248976,248992,249008,249023,249039,249055,249070,249086,249102,249117,249133,249149,249164,249180,249195,249211,249227,249242,249258,249273,249289,249304,249320,249335,249351,249367,249382,249398,249413,249428,249444,249459,249475,249490,249506,249521,249536,249552,249567,249583,249598,249613,249629,249644,249659,249675,249690,249705,249721,249736,249751,249766,249782,249797,249812,249827,249843,249858,249873,249888,249903,249919,249934,249949,249964,249979,249994,250009,250025,250040,250055,250070,250085,250100,250115,250130,250145,250160,250175,250190,250205,250220,250235,250250,250265,250280,250295,250310,250325,250340,250355,250370,250385,250399,250414,250429,250444,250459,250474,250489,250503,250518,250533,250548,250562,250577,250592,250607,250622,250636,250651,250666,250680,250695,250710,250724,250739,250754,250768,250783,250798,250812,250827,250842,250856,250871,250885,250900,250914,250929,250944,250958,250973,250987,251002,251016,251031,251045,251060,251074,251088,251103,251117,251132,251146,251161,251175,251189,251204,251218,251232,251247,251261,251275,251290,251304,251318,251333,251347,251361,251375,251390,251404,251418,251432,251447,251461,251475,251489,251503,251518,251532,251546,251560,251574,251588,251602,251617,251631,251645,251659,251673,251687,251701,251715,251729,251743,251757,251771,251785,251799,251813,251827,251841,251855,251869,251883,251897,251911,251925,251938,251952,251966,251980,251994,252008,252022,252035,252049,252063,252077,252091,252104,252118,252132,252146,252159,252173,252187,252201,252214,252228,252242,252255,252269,252283,252296,252310,252324,252337,252351,252365,252378,252392,252405,252419,252432,252446,252460,252473,252487,252500,252514,252527,252541,252554,252568,252581,252594,252608,252621,252635,252648,252662,252675,252688,252702,252715,252728,252742,252755,252768,252782,252795,252808,252822,252835,252848,252861,252875,252888,252901,252914,252928,252941,252954,252967,252980,252994,253007,253020,253033,253046,253059,253072,253085,253099,253112,253125,253138,253151,253164,253177,253190,253203,253216,253229,253242,253255,253268,253281,253294,253307,253320,253333,253346,253359,253371,253384,253397,253410,253423,253436,253449,253461,253474,253487,253500,253513,253525,253538,253551,253564,253577,253589,253602,253615,253627,253640,253653,253666,253678,253691,253704,253716,253729,253741,253754,253767,253779,253792,253804,253817,253830,253842,253855,253867,253880,253892,253905,253917,253930,253942,253955,253967,253980,253992,254004,254017,254029,254042,254054,254067,254079,254091,254104,254116,254128,254141,254153,254165,254178,254190,254202,254214,254227,254239,254251,254263,254276,254288,254300,254312,254324,254337,254349,254361,254373,254385,254397,254410,254422,254434,254446,254458,254470,254482,254494,254506,254518,254530,254542,254554,254566,254578,254590,254602,254614,254626,254638,254650,254662,254674,254686,254698,254710,254721,254733,254745,254757,254769,254781,254793,254804,254816,254828,254840,254852,254863,254875,254887,254899,254910,254922,254934,254945,254957,254969,254981,254992,255004,255015,255027,255039,255050,255062,255074,255085,255097,255108,255120,255131,255143,255155,255166,255178,255189,255201,255212,255224,255235,255246,255258,255269,255281,255292,255304,255315,255326,255338,255349,255361,255372,255383,255395,255406,255417,255429,255440,255451,255462,255474,255485,255496,255507,255519,255530,255541,255552,255564,255575,255586,255597,255608,255619,255630,255642,255653,255664,255675,255686,255697,255708,255719,255730,255741,255752,255763,255774,255785,255796,255807,255818,255829,255840,255851,255862,255873,255884,255895,255906,255917,255928,255939,255949,255960,255971,255982,255993,256004,256014,256025,256036,256047,256058,256068,256079,256090,256101,256111,256122,256133,256143,256154,256165,256176,256186,256197,256207,256218,256229,256239,256250,256261,256271,256282,256292,256303,256313,256324,256334,256345,256355,256366,256376,256387,256397,256408,256418,256429,256439,256450,256460,256470,256481,256491,256502,256512,256522,256533,256543,256553,256564,256574,256584,256595,256605,256615,256625,256636,256646,256656,256666,256677,256687,256697,256707,256717,256728,256738,256748,256758,256768,256778,256788,256798,256809,256819,256829,256839,256849,256859,256869,256879,256889,256899,256909,256919,256929,256939,256949,256959,256969,256979,256989,256999,257008,257018,257028,257038,257048,257058,257068,257078,257087,257097,257107,257117,257127,257136,257146,257156,257166,257175,257185,257195,257205,257214,257224,257234,257243,257253,257263,257272,257282,257292,257301,257311,257320,257330,257340,257349,257359,257368,257378,257387,257397,257406,257416,257425,257435,257444,257454,257463,257473,257482,257492,257501,257510,257520,257529,257539,257548,257557,257567,257576,257585,257595,257604,257613,257623,257632,257641,257651,257660,257669,257678,257688,257697,257706,257715,257724,257734,257743,257752,257761,257770,257779,257789,257798,257807,257816,257825,257834,257843,257852,257861,257870,257879,257888,257897,257906,257915,257924,257933,257942,257951,257960,257969,257978,257987,257996,258005,258014,258023,258031,258040,258049,258058,258067,258076,258084,258093,258102,258111,258120,258128,258137,258146,258155,258163,258172,258181,258190,258198,258207,258216,258224,258233,258242,258250,258259,258267,258276,258285,258293,258302,258310,258319,258327,258336,258345,258353,258362,258370,258379,258387,258396,258404,258412,258421,258429,258438,258446,258455,258463,258471,258480,258488,258496,258505,258513,258522,258530,258538,258546,258555,258563,258571,258580,258588,258596,258604,258613,258621,258629,258637,258645,258654,258662,258670,258678,258686,258694,258702,258711,258719,258727,258735,258743,258751,258759,258767,258775,258783,258791,258799,258807,258815,258823,258831,258839,258847,258855,258863,258871,258879,258887,258895,258902,258910,258918,258926,258934,258942,258950,258957,258965,258973,258981,258989,258996,259004,259012,259020,259027,259035,259043,259050,259058,259066,259073,259081,259089,259096,259104,259112,259119,259127,259135,259142,259150,259157,259165,259172,259180,259187,259195,259202,259210,259217,259225,259232,259240,259247,259255,259262,259270,259277,259285,259292,259299,259307,259314,259321,259329,259336,259343,259351,259358,259365,259373,259380,259387,259395,259402,259409,259416,259423,259431,259438,259445,259452,259459,259467,259474,259481,259488,259495,259502,259509,259517,259524,259531,259538,259545,259552,259559,259566,259573,259580,259587,259594,259601,259608,259615,259622,259629,259636,259643,259650,259657,259664,259670,259677,259684,259691,259698,259705,259712,259718,259725,259732,259739,259746,259752,259759,259766,259773,259779,259786,259793,259800,259806,259813,259820,259826,259833,259840,259846,259853,259860,259866,259873,259879,259886,259893,259899,259906,259912,259919,259925,259932,259938,259945,259951,259958,259964,259971,259977,259984,259990,259997,260003,260009,260016,260022,260029,260035,260041,260048,260054,260060,260067,260073,260079,260085,260092,260098,260104,260111,260117,260123,260129,260135,260142,260148,260154,260160,260166,260173,260179,260185,260191,260197,260203,260209,260215,260221,260228,260234,260240,260246,260252,260258,260264,260270,260276,260282,260288,260294,260300,260306,260312,260317,260323,260329,260335,260341,260347,260353,260359,260365,260370,260376,260382,260388,260394,260399,260405,260411,260417,260423,260428,260434,260440,260445,260451,260457,260463,260468,260474,260480,260485,260491,260496,260502,260508,260513,260519,260525,260530,260536,260541,260547,260552,260558,260563,260569,260574,260580,260585,260591,260596,260602,260607,260613,260618,260623,260629,260634,260640,260645,260650,260656,260661,260666,260672,260677,260682,260688,260693,260698,260703,260709,260714,260719,260724,260730,260735,260740,260745,260750,260756,260761,260766,260771,260776,260781,260786,260791,260797,260802,260807,260812,260817,260822,260827,260832,260837,260842,260847,260852,260857,260862,260867,260872,260877,260882,260887,260892,260896,260901,260906,260911,260916,260921,260926,260930,260935,260940,260945,260950,260955,260959,260964,260969,260974,260978,260983,260988,260992,260997,261002,261007,261011,261016,261021,261025,261030,261034,261039,261044,261048,261053,261057,261062,261067,261071,261076,261080,261085,261089,261094,261098,261103,261107,261112,261116,261120,261125,261129,261134,261138,261143,261147,261151,261156,261160,261164,261169,261173,261177,261182,261186,261190,261195,261199,261203,261207,261212,261216,261220,261224,261228,261233,261237,261241,261245,261249,261253,261258,261262,261266,261270,261274,261278,261282,261286,261290,261294,261298,261302,261306,261310,261314,261318,261322,261326,261330,261334,261338,261342,261346,261350,261354,261358,261362,261366,261369,261373,261377,261381,261385,261389,261392,261396,261400,261404,261408,261411,261415,261419,261423,261426,261430,261434,261437,261441,261445,261448,261452,261456,261459,261463,261467,261470,261474,261477,261481,261485,261488,261492,261495,261499,261502,261506,261509,261513,261516,261520,261523,261527,261530,261533,261537,261540,261544,261547,261551,261554,261557,261561,261564,261567,261571,261574,261577,261581,261584,261587,261590,261594,261597,261600,261603,261607,261610,261613,261616,261619,261623,261626,261629,261632,261635,261638,261641,261644,261648,261651,261654,261657,261660,261663,261666,261669,261672,261675,261678,261681,261684,261687,261690,261693,261696,261699,261702,261705,261708,261710,261713,261716,261719,261722,261725,261728,261730,261733,261736,261739,261742,261744,261747,261750,261753,261755,261758,261761,261764,261766,261769,261772,261774,261777,261780,261782,261785,261788,261790,261793,261795,261798,261801,261803,261806,261808,261811,261813,261816,261818,261821,261823,261826,261828,261831,261833,261836,261838,261840,261843,261845,261848,261850,261852,261855,261857,261859,261862,261864,261866,261869,261871,261873,261876,261878,261880,261882,261885,261887,261889,261891,261894,261896,261898,261900,261902,261904,261907,261909,261911,261913,261915,261917,261919,261921,261923,261925,261927,261929,261932,261934,261936,261938,261940,261942,261943,261945,261947,261949,261951,261953,261955,261957,261959,261961,261963,261965,261966,261968,261970,261972,261974,261975,261977,261979,261981,261983,261984,261986,261988,261990,261991,261993,261995,261996,261998,262000,262001,262003,262005,262006,262008,262010,262011,262013,262014,262016,262018,262019,262021,262022,262024,262025,262027,262028,262030,262031,262033,262034,262036,262037,262038,262040,262041,262043,262044,262045,262047,262048,262050,262051,262052,262054,262055,262056,262057,262059,262060,262061,262063,262064,262065,262066,262067,262069,262070,262071,262072,262073,262075,262076,262077,262078,262079,262080,262081,262082,262084,262085,262086,262087,262088,262089,262090,262091,262092,262093,262094,262095,262096,262097,262098,262099,262100,262101,262101,262102,262103,262104,262105,262106,262107,262108,262108,262109,262110,262111,262112,262112,262113,262114,262115,262115,262116,262117,262118,262118,262119,262120,262120,262121,262122,262122,262123,262124,262124,262125,262125,262126,262127,262127,262128,262128,262129,262129,262130,262130,262131,262131,262132,262132,262133,262133,262134,262134,262135,262135,262135,262136,262136,262137,262137,262137,262138,262138,262138,262139,262139,262139,262140,262140,262140,262140,262141,262141,262141,262141,262142,262142,262142,262142,262142,262143,262143,262143,262143,262143,262143,262143,262144,262144,262144,262144,262144,262144,262144,262144,262144,262144,262144,0};
4#define ILOGCOSTABSIZE 15
5#define ICOSTABSIZE (1<<ILOGCOSTABSIZE)
6static t_sample cos_table[] = {262144,262144,262144,262144,262144,262144,262144,262144,262144,262144,262144,262143,262143,262143,262143,262143,262143,262143,262142,262142,262142,262142,262142,262141,262141,262141,262141,262140,262140,262140,262140,262139,262139,262139,262138,262138,262138,262137,262137,262137,262136,262136,262135,262135,262135,262134,262134,262133,262133,262132,262132,262131,262131,262130,262130,262129,262129,262128,262128,262127,262127,262126,262125,262125,262124,262124,262123,262122,262122,262121,262120,262120,262119,262118,262118,262117,262116,262115,262115,262114,262113,262112,262112,262111,262110,262109,262108,262108,262107,262106,262105,262104,262103,262102,262101,262101,262100,262099,262098,262097,262096,262095,262094,262093,262092,262091,262090,262089,262088,262087,262086,262085,262084,262082,262081,262080,262079,262078,262077,262076,262075,262073,262072,262071,262070,262069,262067,262066,262065,262064,262063,262061,262060,262059,262057,262056,262055,262054,262052,262051,262050,262048,262047,262045,262044,262043,262041,262040,262038,262037,262036,262034,262033,262031,262030,262028,262027,262025,262024,262022,262021,262019,262018,262016,262014,262013,262011,262010,262008,262006,262005,262003,262001,262000,261998,261996,261995,261993,261991,261990,261988,261986,261984,261983,261981,261979,261977,261975,261974,261972,261970,261968,261966,261965,261963,261961,261959,261957,261955,261953,261951,261949,261947,261945,261943,261942,261940,261938,261936,261934,261932,261929,261927,261925,261923,261921,261919,261917,261915,261913,261911,261909,261907,261904,261902,261900,261898,261896,261894,261891,261889,261887,261885,261882,261880,261878,261876,261873,261871,261869,261866,261864,261862,261859,261857,261855,261852,261850,261848,261845,261843,261840,261838,261836,261833,261831,261828,261826,261823,261821,261818,261816,261813,261811,261808,261806,261803,261801,261798,261795,261793,261790,261788,261785,261782,261780,261777,261774,261772,261769,261766,261764,261761,261758,261755,261753,261750,261747,261744,261742,261739,261736,261733,261730,261728,261725,261722,261719,261716,261713,261710,261708,261705,261702,261699,261696,261693,261690,261687,261684,261681,261678,261675,261672,261669,261666,261663,261660,261657,261654,261651,261648,261644,261641,261638,261635,261632,261629,261626,261623,261619,261616,261613,261610,261607,261603,261600,261597,261594,261590,261587,261584,261581,261577,261574,261571,261567,261564,261561,261557,261554,261551,261547,261544,261540,261537,261533,261530,261527,261523,261520,261516,261513,261509,261506,261502,261499,261495,261492,261488,261485,261481,261477,261474,261470,261467,261463,261459,261456,261452,261448,261445,261441,261437,261434,261430,261426,261423,261419,261415,261411,261408,261404,261400,261396,261392,261389,261385,261381,261377,261373,261369,261366,261362,261358,261354,261350,261346,261342,261338,261334,261330,261326,261322,261318,261314,261310,261306,261302,261298,261294,261290,261286,261282,261278,261274,261270,261266,261262,261258,261253,261249,261245,261241,261237,261233,261228,261224,261220,261216,261212,261207,261203,261199,261195,261190,261186,261182,261177,261173,261169,261164,261160,261156,261151,261147,261143,261138,261134,261129,261125,261120,261116,261112,261107,261103,261098,261094,261089,261085,261080,261076,261071,261067,261062,261057,261053,261048,261044,261039,261034,261030,261025,261021,261016,261011,261007,261002,260997,260992,260988,260983,260978,260974,260969,260964,260959,260955,260950,260945,260940,260935,260930,260926,260921,260916,260911,260906,260901,260896,260892,260887,260882,260877,260872,260867,260862,260857,260852,260847,260842,260837,260832,260827,260822,260817,260812,260807,260802,260797,260791,260786,260781,260776,260771,260766,260761,260756,260750,260745,260740,260735,260730,260724,260719,260714,260709,260703,260698,260693,260688,260682,260677,260672,260666,260661,260656,260650,260645,260640,260634,260629,260623,260618,260613,260607,260602,260596,260591,260585,260580,260574,260569,260563,260558,260552,260547,260541,260536,260530,260525,260519,260513,260508,260502,260496,260491,260485,260480,260474,260468,260463,260457,260451,260445,260440,260434,260428,260423,260417,260411,260405,260399,260394,260388,260382,260376,260370,260365,260359,260353,260347,260341,260335,260329,260323,260317,260312,260306,260300,260294,260288,260282,260276,260270,260264,260258,260252,260246,260240,260234,260228,260221,260215,260209,260203,260197,260191,260185,260179,260173,260166,260160,260154,260148,260142,260135,260129,260123,260117,260111,260104,260098,260092,260085,260079,260073,260067,260060,260054,260048,260041,260035,260029,260022,260016,260009,260003,259997,259990,259984,259977,259971,259964,259958,259951,259945,259938,259932,259925,259919,259912,259906,259899,259893,259886,259879,259873,259866,259860,259853,259846,259840,259833,259826,259820,259813,259806,259800,259793,259786,259779,259773,259766,259759,259752,259746,259739,259732,259725,259718,259712,259705,259698,259691,259684,259677,259670,259664,259657,259650,259643,259636,259629,259622,259615,259608,259601,259594,259587,259580,259573,259566,259559,259552,259545,259538,259531,259524,259517,259509,259502,259495,259488,259481,259474,259467,259459,259452,259445,259438,259431,259423,259416,259409,259402,259395,259387,259380,259373,259365,259358,259351,259343,259336,259329,259321,259314,259307,259299,259292,259285,259277,259270,259262,259255,259247,259240,259232,259225,259217,259210,259202,259195,259187,259180,259172,259165,259157,259150,259142,259135,259127,259119,259112,259104,259096,259089,259081,259073,259066,259058,259050,259043,259035,259027,259020,259012,259004,258996,258989,258981,258973,258965,258957,258950,258942,258934,258926,258918,258910,258902,258895,258887,258879,258871,258863,258855,258847,258839,258831,258823,258815,258807,258799,258791,258783,258775,258767,258759,258751,258743,258735,258727,258719,258711,258702,258694,258686,258678,258670,258662,258654,258645,258637,258629,258621,258613,258604,258596,258588,258580,258571,258563,258555,258546,258538,258530,258522,258513,258505,258496,258488,258480,258471,258463,258455,258446,258438,258429,258421,258412,258404,258396,258387,258379,258370,258362,258353,258345,258336,258327,258319,258310,258302,258293,258285,258276,258267,258259,258250,258242,258233,258224,258216,258207,258198,258190,258181,258172,258163,258155,258146,258137,258128,258120,258111,258102,258093,258084,258076,258067,258058,258049,258040,258031,258023,258014,258005,257996,257987,257978,257969,257960,257951,257942,257933,257924,257915,257906,257897,257888,257879,257870,257861,257852,257843,257834,257825,257816,257807,257798,257789,257779,257770,257761,257752,257743,257734,257724,257715,257706,257697,257688,257678,257669,257660,257651,257641,257632,257623,257613,257604,257595,257585,257576,257567,257557,257548,257539,257529,257520,257510,257501,257492,257482,257473,257463,257454,257444,257435,257425,257416,257406,257397,257387,257378,257368,257359,257349,257340,257330,257320,257311,257301,257292,257282,257272,257263,257253,257243,257234,257224,257214,257205,257195,257185,257175,257166,257156,257146,257136,257127,257117,257107,257097,257087,257078,257068,257058,257048,257038,257028,257018,257008,256999,256989,256979,256969,256959,256949,256939,256929,256919,256909,256899,256889,256879,256869,256859,256849,256839,256829,256819,256809,256798,256788,256778,256768,256758,256748,256738,256728,256717,256707,256697,256687,256677,256666,256656,256646,256636,256625,256615,256605,256595,256584,256574,256564,256553,256543,256533,256522,256512,256502,256491,256481,256470,256460,256450,256439,256429,256418,256408,256397,256387,256376,256366,256355,256345,256334,256324,256313,256303,256292,256282,256271,256261,256250,256239,256229,256218,256207,256197,256186,256176,256165,256154,256143,256133,256122,256111,256101,256090,256079,256068,256058,256047,256036,256025,256014,256004,255993,255982,255971,255960,255949,255939,255928,255917,255906,255895,255884,255873,255862,255851,255840,255829,255818,255807,255796,255785,255774,255763,255752,255741,255730,255719,255708,255697,255686,255675,255664,255653,255642,255630,255619,255608,255597,255586,255575,255564,255552,255541,255530,255519,255507,255496,255485,255474,255462,255451,255440,255429,255417,255406,255395,255383,255372,255361,255349,255338,255326,255315,255304,255292,255281,255269,255258,255246,255235,255224,255212,255201,255189,255178,255166,255155,255143,255131,255120,255108,255097,255085,255074,255062,255050,255039,255027,255015,255004,254992,254981,254969,254957,254945,254934,254922,254910,254899,254887,254875,254863,254852,254840,254828,254816,254804,254793,254781,254769,254757,254745,254733,254721,254710,254698,254686,254674,254662,254650,254638,254626,254614,254602,254590,254578,254566,254554,254542,254530,254518,254506,254494,254482,254470,254458,254446,254434,254422,254410,254397,254385,254373,254361,254349,254337,254324,254312,254300,254288,254276,254263,254251,254239,254227,254214,254202,254190,254178,254165,254153,254141,254128,254116,254104,254091,254079,254067,254054,254042,254029,254017,254004,253992,253980,253967,253955,253942,253930,253917,253905,253892,253880,253867,253855,253842,253830,253817,253804,253792,253779,253767,253754,253741,253729,253716,253704,253691,253678,253666,253653,253640,253627,253615,253602,253589,253577,253564,253551,253538,253525,253513,253500,253487,253474,253461,253449,253436,253423,253410,253397,253384,253371,253359,253346,253333,253320,253307,253294,253281,253268,253255,253242,253229,253216,253203,253190,253177,253164,253151,253138,253125,253112,253099,253085,253072,253059,253046,253033,253020,253007,252994,252980,252967,252954,252941,252928,252914,252901,252888,252875,252861,252848,252835,252822,252808,252795,252782,252768,252755,252742,252728,252715,252702,252688,252675,252662,252648,252635,252621,252608,252594,252581,252568,252554,252541,252527,252514,252500,252487,252473,252460,252446,252432,252419,252405,252392,252378,252365,252351,252337,252324,252310,252296,252283,252269,252255,252242,252228,252214,252201,252187,252173,252159,252146,252132,252118,252104,252091,252077,252063,252049,252035,252022,252008,251994,251980,251966,251952,251938,251925,251911,251897,251883,251869,251855,251841,251827,251813,251799,251785,251771,251757,251743,251729,251715,251701,251687,251673,251659,251645,251631,251617,251602,251588,251574,251560,251546,251532,251518,251503,251489,251475,251461,251447,251432,251418,251404,251390,251375,251361,251347,251333,251318,251304,251290,251275,251261,251247,251232,251218,251204,251189,251175,251161,251146,251132,251117,251103,251088,251074,251060,251045,251031,251016,251002,250987,250973,250958,250944,250929,250914,250900,250885,250871,250856,250842,250827,250812,250798,250783,250768,250754,250739,250724,250710,250695,250680,250666,250651,250636,250622,250607,250592,250577,250562,250548,250533,250518,250503,250489,250474,250459,250444,250429,250414,250399,250385,250370,250355,250340,250325,250310,250295,250280,250265,250250,250235,250220,250205,250190,250175,250160,250145,250130,250115,250100,250085,250070,250055,250040,250025,250009,249994,249979,249964,249949,249934,249919,249903,249888,249873,249858,249843,249827,249812,249797,249782,249766,249751,249736,249721,249705,249690,249675,249659,249644,249629,249613,249598,249583,249567,249552,249536,249521,249506,249490,249475,249459,249444,249428,249413,249398,249382,249367,249351,249335,249320,249304,249289,249273,249258,249242,249227,249211,249195,249180,249164,249149,249133,249117,249102,249086,249070,249055,249039,249023,249008,248992,248976,248960,248945,248929,248913,248897,248882,248866,248850,248834,248818,248803,248787,248771,248755,248739,248723,248707,248691,248676,248660,248644,248628,248612,248596,248580,248564,248548,248532,248516,248500,248484,248468,248452,248436,248420,248404,248388,248372,248356,248340,248323,248307,248291,248275,248259,248243,248227,248211,248194,248178,248162,248146,248130,248113,248097,248081,248065,248048,248032,248016,248000,247983,247967,247951,247934,247918,247902,247885,247869,247853,247836,247820,247803,247787,247771,247754,247738,247721,247705,247688,247672,247655,247639,247622,247606,247589,247573,247556,247540,247523,247507,247490,247474,247457,247440,247424,247407,247391,247374,247357,247341,247324,247307,247291,247274,247257,247241,247224,247207,247190,247174,247157,247140,247123,247107,247090,247073,247056,247040,247023,247006,246989,246972,246955,246938,246922,246905,246888,246871,246854,246837,246820,246803,246786,246769,246752,246735,246718,246701,246684,246667,246650,246633,246616,246599,246582,246565,246548,246531,246514,246497,246480,246463,246445,246428,246411,246394,246377,246360,246342,246325,246308,246291,246274,246256,246239,246222,246205,246187,246170,246153,246136,246118,246101,246084,246066,246049,246032,246014,245997,245979,245962,245945,245927,245910,245892,245875,245858,245840,245823,245805,245788,245770,245753,245735,245718,245700,245683,245665,245648,245630,245613,245595,245577,245560,245542,245525,245507,245489,245472,245454,245436,245419,245401,245383,245366,245348,245330,245313,245295,245277,245259,245242,245224,245206,245188,245171,245153,245135,245117,245099,245081,245064,245046,245028,245010,244992,244974,244956,244938,244921,244903,244885,244867,244849,244831,244813,244795,244777,244759,244741,244723,244705,244687,244669,244651,244633,244615,244597,244578,244560,244542,244524,244506,244488,244470,244452,244433,244415,244397,244379,244361,244343,244324,244306,244288,244270,244251,244233,244215,244197,244178,244160,244142,244123,244105,244087,244068,244050,244032,244013,243995,243977,243958,243940,243921,243903,243885,243866,243848,243829,243811,243792,243774,243755,243737,243718,243700,243681,243663,243644,243626,243607,243588,243570,243551,243533,243514,243496,243477,243458,243440,243421,243402,243384,243365,243346,243328,243309,243290,243271,243253,243234,243215,243196,243178,243159,243140,243121,243103,243084,243065,243046,243027,243008,242990,242971,242952,242933,242914,242895,242876,242857,242838,242819,242800,242782,242763,242744,242725,242706,242687,242668,242649,242630,242611,242591,242572,242553,242534,242515,242496,242477,242458,242439,242420,242401,242381,242362,242343,242324,242305,242286,242266,242247,242228,242209,242189,242170,242151,242132,242112,242093,242074,242055,242035,242016,241997,241977,241958,241939,241919,241900,241881,241861,241842,241822,241803,241784,241764,241745,241725,241706,241686,241667,241647,241628,241608,241589,241569,241550,241530,241511,241491,241472,241452,241433,241413,241393,241374,241354,241334,241315,241295,241276,241256,241236,241217,241197,241177,241157,241138,241118,241098,241079,241059,241039,241019,241000,240980,240960,240940,240920,240901,240881,240861,240841,240821,240801,240781,240762,240742,240722,240702,240682,240662,240642,240622,240602,240582,240562,240542,240522,240502,240482,240462,240442,240422,240402,240382,240362,240342,240322,240302,240282,240262,240242,240221,240201,240181,240161,240141,240121,240101,240080,240060,240040,240020,240000,239979,239959,239939,239919,239898,239878,239858,239838,239817,239797,239777,239756,239736,239716,239695,239675,239655,239634,239614,239593,239573,239553,239532,239512,239491,239471,239450,239430,239410,239389,239369,239348,239328,239307,239287,239266,239245,239225,239204,239184,239163,239143,239122,239101,239081,239060,239040,239019,238998,238978,238957,238936,238916,238895,238874,238853,238833,238812,238791,238771,238750,238729,238708,238688,238667,238646,238625,238604,238583,238563,238542,238521,238500,238479,238458,238437,238417,238396,238375,238354,238333,238312,238291,238270,238249,238228,238207,238186,238165,238144,238123,238102,238081,238060,238039,238018,237997,237976,237955,237934,237913,237891,237870,237849,237828,237807,237786,237765,237743,237722,237701,237680,237659,237637,237616,237595,237574,237552,237531,237510,237489,237467,237446,237425,237403,237382,237361,237339,237318,237297,237275,237254,237233,237211,237190,237168,237147,237126,237104,237083,237061,237040,237018,236997,236975,236954,236932,236911,236889,236868,236846,236825,236803,236782,236760,236738,236717,236695,236674,236652,236630,236609,236587,236565,236544,236522,236500,236479,236457,236435,236414,236392,236370,236348,236327,236305,236283,236261,236240,236218,236196,236174,236152,236131,236109,236087,236065,236043,236021,235999,235978,235956,235934,235912,235890,235868,235846,235824,235802,235780,235758,235736,235714,235692,235670,235648,235626,235604,235582,235560,235538,235516,235494,235472,235450,235428,235405,235383,235361,235339,235317,235295,235273,235250,235228,235206,235184,235162,235139,235117,235095,235073,235050,235028,235006,234984,234961,234939,234917,234894,234872,234850,234828,234805,234783,234760,234738,234716,234693,234671,234649,234626,234604,234581,234559,234536,234514,234491,234469,234446,234424,234401,234379,234356,234334,234311,234289,234266,234244,234221,234199,234176,234153,234131,234108,234086,234063,234040,234018,233995,233972,233950,233927,233904,233882,233859,233836,233813,233791,233768,233745,233722,233700,233677,233654,233631,233609,233586,233563,233540,233517,233494,233472,233449,233426,233403,233380,233357,233334,233311,233288,233265,233243,233220,233197,233174,233151,233128,233105,233082,233059,233036,233013,232990,232967,232944,232920,232897,232874,232851,232828,232805,232782,232759,232736,232713,232689,232666,232643,232620,232597,232574,232550,232527,232504,232481,232457,232434,232411,232388,232364,232341,232318,232295,232271,232248,232225,232201,232178,232155,232131,232108,232085,232061,232038,232014,231991,231968,231944,231921,231897,231874,231850,231827,231804,231780,231757,231733,231710,231686,231663,231639,231615,231592,231568,231545,231521,231498,231474,231450,231427,231403,231380,231356,231332,231309,231285,231261,231238,231214,231190,231167,231143,231119,231096,231072,231048,231024,231001,230977,230953,230929,230905,230882,230858,230834,230810,230786,230762,230739,230715,230691,230667,230643,230619,230595,230571,230548,230524,230500,230476,230452,230428,230404,230380,230356,230332,230308,230284,230260,230236,230212,230188,230164,230140,230116,230091,230067,230043,230019,229995,229971,229947,229923,229898,229874,229850,229826,229802,229778,229753,229729,229705,229681,229657,229632,229608,229584,229560,229535,229511,229487,229462,229438,229414,229389,229365,229341,229316,229292,229268,229243,229219,229194,229170,229146,229121,229097,229072,229048,229024,228999,228975,228950,228926,228901,228877,228852,228828,228803,228779,228754,228729,228705,228680,228656,228631,228607,228582,228557,228533,228508,228483,228459,228434,228409,228385,228360,228335,228311,228286,228261,228237,228212,228187,228162,228138,228113,228088,228063,228039,228014,227989,227964,227939,227914,227890,227865,227840,227815,227790,227765,227740,227716,227691,227666,227641,227616,227591,227566,227541,227516,227491,227466,227441,227416,227391,227366,227341,227316,227291,227266,227241,227216,227191,227166,227141,227115,227090,227065,227040,227015,226990,226965,226940,226914,226889,226864,226839,226814,226788,226763,226738,226713,226688,226662,226637,226612,226586,226561,226536,226511,226485,226460,226435,226409,226384,226359,226333,226308,226283,226257,226232,226206,226181,226156,226130,226105,226079,226054,226028,226003,225977,225952,225926,225901,225875,225850,225824,225799,225773,225748,225722,225697,225671,225646,225620,225594,225569,225543,225517,225492,225466,225441,225415,225389,225364,225338,225312,225287,225261,225235,225209,225184,225158,225132,225106,225081,225055,225029,225003,224978,224952,224926,224900,224874,224848,224823,224797,224771,224745,224719,224693,224667,224641,224615,224590,224564,224538,224512,224486,224460,224434,224408,224382,224356,224330,224304,224278,224252,224226,224200,224174,224148,224122,224096,224069,224043,224017,223991,223965,223939,223913,223887,223860,223834,223808,223782,223756,223730,223703,223677,223651,223625,223599,223572,223546,223520,223493,223467,223441,223415,223388,223362,223336,223309,223283,223257,223230,223204,223178,223151,223125,223099,223072,223046,223019,222993,222966,222940,222914,222887,222861,222834,222808,222781,222755,222728,222702,222675,222649,222622,222596,222569,222542,222516,222489,222463,222436,222410,222383,222356,222330,222303,222276,222250,222223,222196,222170,222143,222116,222090,222063,222036,222010,221983,221956,221929,221903,221876,221849,221822,221795,221769,221742,221715,221688,221661,221634,221608,221581,221554,221527,221500,221473,221446,221419,221393,221366,221339,221312,221285,221258,221231,221204,221177,221150,221123,221096,221069,221042,221015,220988,220961,220934,220907,220880,220853,220826,220798,220771,220744,220717,220690,220663,220636,220609,220581,220554,220527,220500,220473,220446,220418,220391,220364,220337,220309,220282,220255,220228,220200,220173,220146,220119,220091,220064,220037,220009,219982,219955,219927,219900,219873,219845,219818,219790,219763,219736,219708,219681,219653,219626,219598,219571,219544,219516,219489,219461,219434,219406,219379,219351,219324,219296,219268,219241,219213,219186,219158,219131,219103,219075,219048,219020,218993,218965,218937,218910,218882,218854,218827,218799,218771,218744,218716,218688,218660,218633,218605,218577,218549,218522,218494,218466,218438,218411,218383,218355,218327,218299,218271,218244,218216,218188,218160,218132,218104,218076,218049,218021,217993,217965,217937,217909,217881,217853,217825,217797,217769,217741,217713,217685,217657,217629,217601,217573,217545,217517,217489,217461,217433,217405,217377,217348,217320,217292,217264,217236,217208,217180,217152,217123,217095,217067,217039,217011,216982,216954,216926,216898,216870,216841,216813,216785,216757,216728,216700,216672,216643,216615,216587,216558,216530,216502,216473,216445,216417,216388,216360,216332,216303,216275,216246,216218,216190,216161,216133,216104,216076,216047,216019,215990,215962,215933,215905,215876,215848,215819,215791,215762,215734,215705,215677,215648,215619,215591,215562,215534,215505,215476,215448,215419,215390,215362,215333,215304,215276,215247,215218,215190,215161,215132,215104,215075,215046,215017,214989,214960,214931,214902,214873,214845,214816,214787,214758,214729,214701,214672,214643,214614,214585,214556,214527,214498,214470,214441,214412,214383,214354,214325,214296,214267,214238,214209,214180,214151,214122,214093,214064,214035,214006,213977,213948,213919,213890,213861,213832,213803,213774,213745,213715,213686,213657,213628,213599,213570,213541,213511,213482,213453,213424,213395,213366,213336,213307,213278,213249,213219,213190,213161,213132,213102,213073,213044,213015,212985,212956,212927,212897,212868,212839,212809,212780,212751,212721,212692,212662,212633,212604,212574,212545,212515,212486,212456,212427,212398,212368,212339,212309,212280,212250,212221,212191,212162,212132,212103,212073,212043,212014,211984,211955,211925,211896,211866,211836,211807,211777,211748,211718,211688,211659,211629,211599,211570,211540,211510,211481,211451,211421,211391,211362,211332,211302,211272,211243,211213,211183,211153,211124,211094,211064,211034,211004,210974,210945,210915,210885,210855,210825,210795,210765,210736,210706,210676,210646,210616,210586,210556,210526,210496,210466,210436,210406,210376,210346,210316,210286,210256,210226,210196,210166,210136,210106,210076,210046,210016,209986,209956,209926,209895,209865,209835,209805,209775,209745,209715,209684,209654,209624,209594,209564,209534,209503,209473,209443,209413,209382,209352,209322,209292,209261,209231,209201,209170,209140,209110,209080,209049,209019,208989,208958,208928,208897,208867,208837,208806,208776,208746,208715,208685,208654,208624,208593,208563,208533,208502,208472,208441,208411,208380,208350,208319,208289,208258,208228,208197,208166,208136,208105,208075,208044,208014,207983,207952,207922,207891,207861,207830,207799,207769,207738,207707,207677,207646,207615,207585,207554,207523,207492,207462,207431,207400,207370,207339,207308,207277,207246,207216,207185,207154,207123,207092,207062,207031,207000,206969,206938,206907,206877,206846,206815,206784,206753,206722,206691,206660,206629,206598,206567,206537,206506,206475,206444,206413,206382,206351,206320,206289,206258,206227,206196,206165,206133,206102,206071,206040,206009,205978,205947,205916,205885,205854,205823,205791,205760,205729,205698,205667,205636,205604,205573,205542,205511,205480,205448,205417,205386,205355,205324,205292,205261,205230,205198,205167,205136,205105,205073,205042,205011,204979,204948,204917,204885,204854,204823,204791,204760,204728,204697,204666,204634,204603,204571,204540,204508,204477,204446,204414,204383,204351,204320,204288,204257,204225,204194,204162,204131,204099,204067,204036,204004,203973,203941,203910,203878,203846,203815,203783,203752,203720,203688,203657,203625,203593,203562,203530,203498,203467,203435,203403,203372,203340,203308,203276,203245,203213,203181,203149,203118,203086,203054,203022,202990,202959,202927,202895,202863,202831,202799,202768,202736,202704,202672,202640,202608,202576,202544,202512,202481,202449,202417,202385,202353,202321,202289,202257,202225,202193,202161,202129,202097,202065,202033,202001,201969,201937,201905,201873,201841,201808,201776,201744,201712,201680,201648,201616,201584,201552,201519,201487,201455,201423,201391,201359,201326,201294,201262,201230,201198,201165,201133,201101,201069,201036,201004,200972,200940,200907,200875,200843,200810,200778,200746,200713,200681,200649,200616,200584,200552,200519,200487,200454,200422,200390,200357,200325,200292,200260,200228,200195,200163,200130,200098,200065,200033,200000,199968,199935,199903,199870,199838,199805,199773,199740,199708,199675,199642,199610,199577,199545,199512,199479,199447,199414,199382,199349,199316,199284,199251,199218,199186,199153,199120,199088,199055,199022,198989,198957,198924,198891,198858,198826,198793,198760,198727,198695,198662,198629,198596,198563,198531,198498,198465,198432,198399,198366,198334,198301,198268,198235,198202,198169,198136,198103,198070,198037,198004,197972,197939,197906,197873,197840,197807,197774,197741,197708,197675,197642,197609,197576,197543,197510,197476,197443,197410,197377,197344,197311,197278,197245,197212,197179,197146,197112,197079,197046,197013,196980,196947,196913,196880,196847,196814,196781,196747,196714,196681,196648,196615,196581,196548,196515,196481,196448,196415,196382,196348,196315,196282,196248,196215,196182,196148,196115,196082,196048,196015,195982,195948,195915,195881,195848,195815,195781,195748,195714,195681,195647,195614,195580,195547,195513,195480,195446,195413,195379,195346,195312,195279,195245,195212,195178,195145,195111,195078,195044,195010,194977,194943,194910,194876,194842,194809,194775,194741,194708,194674,194640,194607,194573,194539,194506,194472,194438,194405,194371,194337,194303,194270,194236,194202,194168,194135,194101,194067,194033,193999,193966,193932,193898,193864,193830,193796,193763,193729,193695,193661,193627,193593,193559,193525,193492,193458,193424,193390,193356,193322,193288,193254,193220,193186,193152,193118,193084,193050,193016,192982,192948,192914,192880,192846,192812,192778,192744,192710,192676,192641,192607,192573,192539,192505,192471,192437,192403,192369,192334,192300,192266,192232,192198,192164,192129,192095,192061,192027,191992,191958,191924,191890,191856,191821,191787,191753,191718,191684,191650,191616,191581,191547,191513,191478,191444,191410,191375,191341,191307,191272,191238,191203,191169,191135,191100,191066,191031,190997,190963,190928,190894,190859,190825,190790,190756,190721,190687,190652,190618,190583,190549,190514,190480,190445,190411,190376,190342,190307,190272,190238,190203,190169,190134,190099,190065,190030,189996,189961,189926,189892,189857,189822,189788,189753,189718,189684,189649,189614,189580,189545,189510,189475,189441,189406,189371,189336,189302,189267,189232,189197,189162,189128,189093,189058,189023,188988,188954,188919,188884,188849,188814,188779,188744,188709,188675,188640,188605,188570,188535,188500,188465,188430,188395,188360,188325,188290,188255,188220,188185,188150,188115,188080,188045,188010,187975,187940,187905,187870,187835,187800,187765,187730,187695,187660,187625,187589,187554,187519,187484,187449,187414,187379,187343,187308,187273,187238,187203,187168,187132,187097,187062,187027,186992,186956,186921,186886,186851,186815,186780,186745,186710,186674,186639,186604,186568,186533,186498,186462,186427,186392,186356,186321,186286,186250,186215,186179,186144,186109,186073,186038,186002,185967,185932,185896,185861,185825,185790,185754,185719,185683,185648,185612,185577,185541,185506,185470,185435,185399,185364,185328,185293,185257,185222,185186,185150,185115,185079,185044,185008,184972,184937,184901,184866,184830,184794,184759,184723,184687,184652,184616,184580,184545,184509,184473,184437,184402,184366,184330,184294,184259,184223,184187,184151,184116,184080,184044,184008,183972,183937,183901,183865,183829,183793,183757,183722,183686,183650,183614,183578,183542,183506,183470,183435,183399,183363,183327,183291,183255,183219,183183,183147,183111,183075,183039,183003,182967,182931,182895,182859,182823,182787,182751,182715,182679,182643,182607,182571,182535,182499,182463,182426,182390,182354,182318,182282,182246,182210,182174,182137,182101,182065,182029,181993,181957,181920,181884,181848,181812,181776,181739,181703,181667,181631,181594,181558,181522,181486,181449,181413,181377,181341,181304,181268,181232,181195,181159,181123,181086,181050,181014,180977,180941,180904,180868,180832,180795,180759,180723,180686,180650,180613,180577,180540,180504,180467,180431,180395,180358,180322,180285,180249,180212,180176,180139,180103,180066,180029,179993,179956,179920,179883,179847,179810,179774,179737,179700,179664,179627,179591,179554,179517,179481,179444,179407,179371,179334,179297,179261,179224,179187,179151,179114,179077,179041,179004,178967,178930,178894,178857,178820,178783,178747,178710,178673,178636,178600,178563,178526,178489,178452,178415,178379,178342,178305,178268,178231,178194,178158,178121,178084,178047,178010,177973,177936,177899,177862,177825,177788,177752,177715,177678,177641,177604,177567,177530,177493,177456,177419,177382,177345,177308,177271,177234,177197,177160,177123,177085,177048,177011,176974,176937,176900,176863,176826,176789,176752,176714,176677,176640,176603,176566,176529,176492,176454,176417,176380,176343,176306,176268,176231,176194,176157,176120,176082,176045,176008,175971,175933,175896,175859,175822,175784,175747,175710,175672,175635,175598,175560,175523,175486,175448,175411,175374,175336,175299,175262,175224,175187,175149,175112,175075,175037,175000,174962,174925,174887,174850,174813,174775,174738,174700,174663,174625,174588,174550,174513,174475,174438,174400,174363,174325,174288,174250,174212,174175,174137,174100,174062,174025,173987,173949,173912,173874,173837,173799,173761,173724,173686,173648,173611,173573,173535,173498,173460,173422,173385,173347,173309,173271,173234,173196,173158,173121,173083,173045,173007,172969,172932,172894,172856,172818,172781,172743,172705,172667,172629,172591,172554,172516,172478,172440,172402,172364,172326,172289,172251,172213,172175,172137,172099,172061,172023,171985,171947,171909,171871,171834,171796,171758,171720,171682,171644,171606,171568,171530,171492,171454,171416,171378,171339,171301,171263,171225,171187,171149,171111,171073,171035,170997,170959,170921,170883,170844,170806,170768,170730,170692,170654,170616,170577,170539,170501,170463,170425,170386,170348,170310,170272,170234,170195,170157,170119,170081,170042,170004,169966,169928,169889,169851,169813,169774,169736,169698,169660,169621,169583,169545,169506,169468,169430,169391,169353,169314,169276,169238,169199,169161,169122,169084,169046,169007,168969,168930,168892,168853,168815,168777,168738,168700,168661,168623,168584,168546,168507,168469,168430,168392,168353,168315,168276,168238,168199,168160,168122,168083,168045,168006,167968,167929,167890,167852,167813,167774,167736,167697,167659,167620,167581,167543,167504,167465,167427,167388,167349,167311,167272,167233,167194,167156,167117,167078,167040,167001,166962,166923,166885,166846,166807,166768,166729,166691,166652,166613,166574,166535,166497,166458,166419,166380,166341,166302,166264,166225,166186,166147,166108,166069,166030,165991,165952,165914,165875,165836,165797,165758,165719,165680,165641,165602,165563,165524,165485,165446,165407,165368,165329,165290,165251,165212,165173,165134,165095,165056,165017,164978,164939,164900,164861,164821,164782,164743,164704,164665,164626,164587,164548,164509,164469,164430,164391,164352,164313,164274,164234,164195,164156,164117,164078,164039,163999,163960,163921,163882,163842,163803,163764,163725,163685,163646,163607,163568,163528,163489,163450,163410,163371,163332,163292,163253,163214,163174,163135,163096,163056,163017,162978,162938,162899,162860,162820,162781,162741,162702,162663,162623,162584,162544,162505,162465,162426,162386,162347,162308,162268,162229,162189,162150,162110,162071,162031,161992,161952,161913,161873,161833,161794,161754,161715,161675,161636,161596,161557,161517,161477,161438,161398,161359,161319,161279,161240,161200,161160,161121,161081,161041,161002,160962,160922,160883,160843,160803,160764,160724,160684,160644,160605,160565,160525,160486,160446,160406,160366,160327,160287,160247,160207,160167,160128,160088,160048,160008,159968,159929,159889,159849,159809,159769,159729,159689,159650,159610,159570,159530,159490,159450,159410,159370,159330,159291,159251,159211,159171,159131,159091,159051,159011,158971,158931,158891,158851,158811,158771,158731,158691,158651,158611,158571,158531,158491,158451,158411,158371,158331,158291,158251,158211,158170,158130,158090,158050,158010,157970,157930,157890,157850,157809,157769,157729,157689,157649,157609,157569,157528,157488,157448,157408,157368,157327,157287,157247,157207,157167,157126,157086,157046,157006,156965,156925,156885,156845,156804,156764,156724,156683,156643,156603,156562,156522,156482,156441,156401,156361,156320,156280,156240,156199,156159,156119,156078,156038,155997,155957,155917,155876,155836,155795,155755,155715,155674,155634,155593,155553,155512,155472,155431,155391,155350,155310,155269,155229,155188,155148,155107,155067,155026,154986,154945,154905,154864,154824,154783,154742,154702,154661,154621,154580,154539,154499,154458,154418,154377,154336,154296,154255,154214,154174,154133,154093,154052,154011,153970,153930,153889,153848,153808,153767,153726,153686,153645,153604,153563,153523,153482,153441,153400,153360,153319,153278,153237,153197,153156,153115,153074,153033,152993,152952,152911,152870,152829,152788,152748,152707,152666,152625,152584,152543,152502,152461,152421,152380,152339,152298,152257,152216,152175,152134,152093,152052,152011,151970,151929,151888,151847,151806,151765,151724,151683,151642,151601,151560,151519,151478,151437,151396,151355,151314,151273,151232,151191,151150,151109,151068,151027,150986,150945,150904,150862,150821,150780,150739,150698,150657,150616,150575,150533,150492,150451,150410,150369,150328,150286,150245,150204,150163,150122,150080,150039,149998,149957,149916,149874,149833,149792,149751,149709,149668,149627,149585,149544,149503,149462,149420,149379,149338,149296,149255,149214,149172,149131,149090,149048,149007,148966,148924,148883,148842,148800,148759,148717,148676,148635,148593,148552,148510,148469,148428,148386,148345,148303,148262,148220,148179,148137,148096,148054,148013,147971,147930,147888,147847,147805,147764,147722,147681,147639,147598,147556,147515,147473,147432,147390,147348,147307,147265,147224,147182,147141,147099,147057,147016,146974,146932,146891,146849,146808,146766,146724,146683,146641,146599,146558,146516,146474,146433,146391,146349,146307,146266,146224,146182,146141,146099,146057,146015,145974,145932,145890,145848,145807,145765,145723,145681,145639,145598,145556,145514,145472,145430,145389,145347,145305,145263,145221,145179,145137,145096,145054,145012,144970,144928,144886,144844,144802,144761,144719,144677,144635,144593,144551,144509,144467,144425,144383,144341,144299,144257,144215,144173,144131,144089,144047,144005,143963,143921,143879,143837,143795,143753,143711,143669,143627,143585,143543,143501,143459,143417,143375,143333,143291,143248,143206,143164,143122,143080,143038,142996,142954,142912,142869,142827,142785,142743,142701,142659,142616,142574,142532,142490,142448,142405,142363,142321,142279,142237,142194,142152,142110,142068,142025,141983,141941,141899,141856,141814,141772,141730,141687,141645,141603,141560,141518,141476,141433,141391,141349,141306,141264,141222,141179,141137,141095,141052,141010,140968,140925,140883,140840,140798,140756,140713,140671,140628,140586,140544,140501,140459,140416,140374,140331,140289,140246,140204,140161,140119,140077,140034,139992,139949,139907,139864,139821,139779,139736,139694,139651,139609,139566,139524,139481,139439,139396,139353,139311,139268,139226,139183,139141,139098,139055,139013,138970,138927,138885,138842,138800,138757,138714,138672,138629,138586,138544,138501,138458,138416,138373,138330,138288,138245,138202,138159,138117,138074,138031,137988,137946,137903,137860,137817,137775,137732,137689,137646,137604,137561,137518,137475,137432,137390,137347,137304,137261,137218,137176,137133,137090,137047,137004,136961,136918,136876,136833,136790,136747,136704,136661,136618,136575,136532,136490,136447,136404,136361,136318,136275,136232,136189,136146,136103,136060,136017,135974,135931,135888,135845,135802,135759,135716,135673,135630,135587,135544,135501,135458,135415,135372,135329,135286,135243,135200,135157,135114,135071,135028,134984,134941,134898,134855,134812,134769,134726,134683,134640,134596,134553,134510,134467,134424,134381,134338,134294,134251,134208,134165,134122,134078,134035,133992,133949,133906,133862,133819,133776,133733,133690,133646,133603,133560,133517,133473,133430,133387,133343,133300,133257,133214,133170,133127,133084,133040,132997,132954,132910,132867,132824,132780,132737,132694,132650,132607,132564,132520,132477,132434,132390,132347,132303,132260,132217,132173,132130,132086,132043,132000,131956,131913,131869,131826,131782,131739,131695,131652,131609,131565,131522,131478,131435,131391,131348,131304,131261,131217,131174,131130,131087,131043,130999,130956,130912,130869,130825,130782,130738,130695,130651,130607,130564,130520,130477,130433,130389,130346,130302,130259,130215,130171,130128,130084,130040,129997,129953,129909,129866,129822,129778,129735,129691,129647,129604,129560,129516,129473,129429,129385,129341,129298,129254,129210,129167,129123,129079,129035,128992,128948,128904,128860,128816,128773,128729,128685,128641,128598,128554,128510,128466,128422,128378,128335,128291,128247,128203,128159,128115,128072,128028,127984,127940,127896,127852,127808,127764,127721,127677,127633,127589,127545,127501,127457,127413,127369,127325,127281,127237,127193,127150,127106,127062,127018,126974,126930,126886,126842,126798,126754,126710,126666,126622,126578,126534,126490,126446,126402,126358,126314,126269,126225,126181,126137,126093,126049,126005,125961,125917,125873,125829,125785,125741,125696,125652,125608,125564,125520,125476,125432,125388,125343,125299,125255,125211,125167,125123,125078,125034,124990,124946,124902,124857,124813,124769,124725,124681,124636,124592,124548,124504,124460,124415,124371,124327,124283,124238,124194,124150,124105,124061,124017,123973,123928,123884,123840,123795,123751,123707,123662,123618,123574,123529,123485,123441,123396,123352,123308,123263,123219,123175,123130,123086,123042,122997,122953,122908,122864,122820,122775,122731,122686,122642,122597,122553,122509,122464,122420,122375,122331,122286,122242,122197,122153,122108,122064,122019,121975,121931,121886,121842,121797,121752,121708,121663,121619,121574,121530,121485,121441,121396,121352,121307,121263,121218,121173,121129,121084,121040,120995,120950,120906,120861,120817,120772,120727,120683,120638,120594,120549,120504,120460,120415,120370,120326,120281,120236,120192,120147,120102,120058,120013,119968,119924,119879,119834,119790,119745,119700,119655,119611,119566,119521,119476,119432,119387,119342,119297,119253,119208,119163,119118,119074,119029,118984,118939,118894,118850,118805,118760,118715,118670,118626,118581,118536,118491,118446,118401,118357,118312,118267,118222,118177,118132,118087,118042,117998,117953,117908,117863,117818,117773,117728,117683,117638,117593,117549,117504,117459,117414,117369,117324,117279,117234,117189,117144,117099,117054,117009,116964,116919,116874,116829,116784,116739,116694,116649,116604,116559,116514,116469,116424,116379,116334,116289,116244,116199,116154,116109,116064,116018,115973,115928,115883,115838,115793,115748,115703,115658,115613,115567,115522,115477,115432,115387,115342,115297,115252,115206,115161,115116,115071,115026,114981,114935,114890,114845,114800,114755,114710,114664,114619,114574,114529,114483,114438,114393,114348,114303,114257,114212,114167,114122,114076,114031,113986,113941,113895,113850,113805,113759,113714,113669,113624,113578,113533,113488,113442,113397,113352,113306,113261,113216,113170,113125,113080,113034,112989,112944,112898,112853,112808,112762,112717,112671,112626,112581,112535,112490,112444,112399,112354,112308,112263,112217,112172,112126,112081,112036,111990,111945,111899,111854,111808,111763,111717,111672,111626,111581,111535,111490,111444,111399,111353,111308,111262,111217,111171,111126,111080,111035,110989,110944,110898,110853,110807,110762,110716,110670,110625,110579,110534,110488,110443,110397,110351,110306,110260,110215,110169,110123,110078,110032,109986,109941,109895,109850,109804,109758,109713,109667,109621,109576,109530,109484,109439,109393,109347,109302,109256,109210,109165,109119,109073,109027,108982,108936,108890,108845,108799,108753,108707,108662,108616,108570,108524,108479,108433,108387,108341,108295,108250,108204,108158,108112,108067,108021,107975,107929,107883,107838,107792,107746,107700,107654,107608,107563,107517,107471,107425,107379,107333,107287,107242,107196,107150,107104,107058,107012,106966,106920,106875,106829,106783,106737,106691,106645,106599,106553,106507,106461,106415,106369,106323,106278,106232,106186,106140,106094,106048,106002,105956,105910,105864,105818,105772,105726,105680,105634,105588,105542,105496,105450,105404,105358,105312,105266,105220,105174,105128,105082,105035,104989,104943,104897,104851,104805,104759,104713,104667,104621,104575,104529,104483,104436,104390,104344,104298,104252,104206,104160,104114,104067,104021,103975,103929,103883,103837,103791,103744,103698,103652,103606,103560,103514,103467,103421,103375,103329,103283,103236,103190,103144,103098,103052,103005,102959,102913,102867,102820,102774,102728,102682,102635,102589,102543,102497,102450,102404,102358,102312,102265,102219,102173,102126,102080,102034,101988,101941,101895,101849,101802,101756,101710,101663,101617,101571,101524,101478,101432,101385,101339,101293,101246,101200,101153,101107,101061,101014,100968,100922,100875,100829,100782,100736,100690,100643,100597,100550,100504,100457,100411,100365,100318,100272,100225,100179,100132,100086,100039,99993,99947,99900,99854,99807,99761,99714,99668,99621,99575,99528,99482,99435,99389,99342,99296,99249,99203,99156,99110,99063,99016,98970,98923,98877,98830,98784,98737,98691,98644,98597,98551,98504,98458,98411,98364,98318,98271,98225,98178,98131,98085,98038,97992,97945,97898,97852,97805,97758,97712,97665,97619,97572,97525,97479,97432,97385,97339,97292,97245,97199,97152,97105,97058,97012,96965,96918,96872,96825,96778,96732,96685,96638,96591,96545,96498,96451,96404,96358,96311,96264,96217,96171,96124,96077,96030,95984,95937,95890,95843,95796,95750,95703,95656,95609,95562,95516,95469,95422,95375,95328,95282,95235,95188,95141,95094,95047,95001,94954,94907,94860,94813,94766,94719,94673,94626,94579,94532,94485,94438,94391,94344,94297,94251,94204,94157,94110,94063,94016,93969,93922,93875,93828,93781,93734,93687,93640,93594,93547,93500,93453,93406,93359,93312,93265,93218,93171,93124,93077,93030,92983,92936,92889,92842,92795,92748,92701,92654,92607,92560,92513,92466,92419,92372,92325,92278,92230,92183,92136,92089,92042,91995,91948,91901,91854,91807,91760,91713,91666,91619,91571,91524,91477,91430,91383,91336,91289,91242,91195,91147,91100,91053,91006,90959,90912,90865,90817,90770,90723,90676,90629,90582,90534,90487,90440,90393,90346,90299,90251,90204,90157,90110,90063,90015,89968,89921,89874,89826,89779,89732,89685,89638,89590,89543,89496,89449,89401,89354,89307,89260,89212,89165,89118,89070,89023,88976,88929,88881,88834,88787,88739,88692,88645,88598,88550,88503,88456,88408,88361,88314,88266,88219,88172,88124,88077,88030,87982,87935,87888,87840,87793,87745,87698,87651,87603,87556,87509,87461,87414,87366,87319,87272,87224,87177,87129,87082,87035,86987,86940,86892,86845,86798,86750,86703,86655,86608,86560,86513,86465,86418,86371,86323,86276,86228,86181,86133,86086,86038,85991,85943,85896,85848,85801,85753,85706,85658,85611,85563,85516,85468,85421,85373,85326,85278,85231,85183,85136,85088,85040,84993,84945,84898,84850,84803,84755,84708,84660,84612,84565,84517,84470,84422,84374,84327,84279,84232,84184,84136,84089,84041,83994,83946,83898,83851,83803,83756,83708,83660,83613,83565,83517,83470,83422,83374,83327,83279,83231,83184,83136,83088,83041,82993,82945,82898,82850,82802,82755,82707,82659,82612,82564,82516,82468,82421,82373,82325,82278,82230,82182,82134,82087,82039,81991,81943,81896,81848,81800,81752,81705,81657,81609,81561,81514,81466,81418,81370,81322,81275,81227,81179,81131,81083,81036,80988,80940,80892,80844,80797,80749,80701,80653,80605,80557,80510,80462,80414,80366,80318,80270,80223,80175,80127,80079,80031,79983,79935,79887,79840,79792,79744,79696,79648,79600,79552,79504,79457,79409,79361,79313,79265,79217,79169,79121,79073,79025,78977,78929,78881,78834,78786,78738,78690,78642,78594,78546,78498,78450,78402,78354,78306,78258,78210,78162,78114,78066,78018,77970,77922,77874,77826,77778,77730,77682,77634,77586,77538,77490,77442,77394,77346,77298,77250,77202,77154,77106,77058,77010,76962,76914,76866,76818,76770,76721,76673,76625,76577,76529,76481,76433,76385,76337,76289,76241,76193,76144,76096,76048,76000,75952,75904,75856,75808,75760,75711,75663,75615,75567,75519,75471,75423,75375,75326,75278,75230,75182,75134,75086,75037,74989,74941,74893,74845,74797,74748,74700,74652,74604,74556,74508,74459,74411,74363,74315,74267,74218,74170,74122,74074,74025,73977,73929,73881,73833,73784,73736,73688,73640,73591,73543,73495,73447,73398,73350,73302,73254,73205,73157,73109,73061,73012,72964,72916,72867,72819,72771,72723,72674,72626,72578,72529,72481,72433,72384,72336,72288,72239,72191,72143,72095,72046,71998,71950,71901,71853,71805,71756,71708,71659,71611,71563,71514,71466,71418,71369,71321,71273,71224,71176,71127,71079,71031,70982,70934,70886,70837,70789,70740,70692,70644,70595,70547,70498,70450,70401,70353,70305,70256,70208,70159,70111,70062,70014,69966,69917,69869,69820,69772,69723,69675,69626,69578,69530,69481,69433,69384,69336,69287,69239,69190,69142,69093,69045,68996,68948,68899,68851,68802,68754,68705,68657,68608,68560,68511,68463,68414,68366,68317,68269,68220,68171,68123,68074,68026,67977,67929,67880,67832,67783,67735,67686,67637,67589,67540,67492,67443,67395,67346,67297,67249,67200,67152,67103,67055,67006,66957,66909,66860,66812,66763,66714,66666,66617,66568,66520,66471,66423,66374,66325,66277,66228,66179,66131,66082,66034,65985,65936,65888,65839,65790,65742,65693,65644,65596,65547,65498,65450,65401,65352,65304,65255,65206,65158,65109,65060,65011,64963,64914,64865,64817,64768,64719,64671,64622,64573,64524,64476,64427,64378,64329,64281,64232,64183,64135,64086,64037,63988,63940,63891,63842,63793,63745,63696,63647,63598,63550,63501,63452,63403,63354,63306,63257,63208,63159,63111,63062,63013,62964,62915,62867,62818,62769,62720,62671,62623,62574,62525,62476,62427,62378,62330,62281,62232,62183,62134,62085,62037,61988,61939,61890,61841,61792,61744,61695,61646,61597,61548,61499,61450,61402,61353,61304,61255,61206,61157,61108,61059,61011,60962,60913,60864,60815,60766,60717,60668,60619,60570,60522,60473,60424,60375,60326,60277,60228,60179,60130,60081,60032,59983,59935,59886,59837,59788,59739,59690,59641,59592,59543,59494,59445,59396,59347,59298,59249,59200,59151,59102,59053,59004,58955,58906,58857,58808,58759,58711,58662,58613,58564,58515,58466,58417,58368,58319,58270,58221,58171,58122,58073,58024,57975,57926,57877,57828,57779,57730,57681,57632,57583,57534,57485,57436,57387,57338,57289,57240,57191,57142,57093,57044,56995,56946,56896,56847,56798,56749,56700,56651,56602,56553,56504,56455,56406,56357,56308,56258,56209,56160,56111,56062,56013,55964,55915,55866,55816,55767,55718,55669,55620,55571,55522,55473,55424,55374,55325,55276,55227,55178,55129,55080,55030,54981,54932,54883,54834,54785,54736,54686,54637,54588,54539,54490,54441,54391,54342,54293,54244,54195,54145,54096,54047,53998,53949,53900,53850,53801,53752,53703,53654,53604,53555,53506,53457,53408,53358,53309,53260,53211,53161,53112,53063,53014,52965,52915,52866,52817,52768,52718,52669,52620,52571,52521,52472,52423,52374,52324,52275,52226,52177,52127,52078,52029,51980,51930,51881,51832,51782,51733,51684,51635,51585,51536,51487,51438,51388,51339,51290,51240,51191,51142,51092,51043,50994,50945,50895,50846,50797,50747,50698,50649,50599,50550,50501,50451,50402,50353,50303,50254,50205,50155,50106,50057,50007,49958,49909,49859,49810,49761,49711,49662,49613,49563,49514,49464,49415,49366,49316,49267,49218,49168,49119,49070,49020,48971,48921,48872,48823,48773,48724,48674,48625,48576,48526,48477,48427,48378,48329,48279,48230,48180,48131,48082,48032,47983,47933,47884,47835,47785,47736,47686,47637,47587,47538,47489,47439,47390,47340,47291,47241,47192,47142,47093,47044,46994,46945,46895,46846,46796,46747,46697,46648,46598,46549,46500,46450,46401,46351,46302,46252,46203,46153,46104,46054,46005,45955,45906,45856,45807,45757,45708,45658,45609,45559,45510,45460,45411,45361,45312,45262,45213,45163,45114,45064,45015,44965,44916,44866,44817,44767,44718,44668,44619,44569,44519,44470,44420,44371,44321,44272,44222,44173,44123,44074,44024,43974,43925,43875,43826,43776,43727,43677,43628,43578,43528,43479,43429,43380,43330,43281,43231,43181,43132,43082,43033,42983,42933,42884,42834,42785,42735,42686,42636,42586,42537,42487,42438,42388,42338,42289,42239,42190,42140,42090,42041,41991,41941,41892,41842,41793,41743,41693,41644,41594,41544,41495,41445,41396,41346,41296,41247,41197,41147,41098,41048,40998,40949,40899,40849,40800,40750,40701,40651,40601,40552,40502,40452,40403,40353,40303,40254,40204,40154,40105,40055,40005,39956,39906,39856,39806,39757,39707,39657,39608,39558,39508,39459,39409,39359,39310,39260,39210,39160,39111,39061,39011,38962,38912,38862,38813,38763,38713,38663,38614,38564,38514,38465,38415,38365,38315,38266,38216,38166,38116,38067,38017,37967,37917,37868,37818,37768,37719,37669,37619,37569,37520,37470,37420,37370,37321,37271,37221,37171,37122,37072,37022,36972,36922,36873,36823,36773,36723,36674,36624,36574,36524,36475,36425,36375,36325,36275,36226,36176,36126,36076,36027,35977,35927,35877,35827,35778,35728,35678,35628,35578,35529,35479,35429,35379,35329,35280,35230,35180,35130,35080,35030,34981,34931,34881,34831,34781,34732,34682,34632,34582,34532,34482,34433,34383,34333,34283,34233,34183,34134,34084,34034,33984,33934,33884,33835,33785,33735,33685,33635,33585,33535,33486,33436,33386,33336,33286,33236,33186,33137,33087,33037,32987,32937,32887,32837,32788,32738,32688,32638,32588,32538,32488,32438,32389,32339,32289,32239,32189,32139,32089,32039,31989,31940,31890,31840,31790,31740,31690,31640,31590,31540,31490,31441,31391,31341,31291,31241,31191,31141,31091,31041,30991,30942,30892,30842,30792,30742,30692,30642,30592,30542,30492,30442,30392,30342,30293,30243,30193,30143,30093,30043,29993,29943,29893,29843,29793,29743,29693,29643,29593,29543,29494,29444,29394,29344,29294,29244,29194,29144,29094,29044,28994,28944,28894,28844,28794,28744,28694,28644,28594,28544,28494,28444,28394,28344,28295,28245,28195,28145,28095,28045,27995,27945,27895,27845,27795,27745,27695,27645,27595,27545,27495,27445,27395,27345,27295,27245,27195,27145,27095,27045,26995,26945,26895,26845,26795,26745,26695,26645,26595,26545,26495,26445,26395,26345,26295,26245,26195,26145,26095,26045,25995,25945,25895,25845,25795,25745,25695,25645,25595,25545,25495,25444,25394,25344,25294,25244,25194,25144,25094,25044,24994,24944,24894,24844,24794,24744,24694,24644,24594,24544,24494,24444,24394,24344,24294,24244,24193,24143,24093,24043,23993,23943,23893,23843,23793,23743,23693,23643,23593,23543,23493,23443,23393,23342,23292,23242,23192,23142,23092,23042,22992,22942,22892,22842,22792,22742,22692,22641,22591,22541,22491,22441,22391,22341,22291,22241,22191,22141,22091,22040,21990,21940,21890,21840,21790,21740,21690,21640,21590,21540,21489,21439,21389,21339,21289,21239,21189,21139,21089,21039,20988,20938,20888,20838,20788,20738,20688,20638,20588,20538,20487,20437,20387,20337,20287,20237,20187,20137,20086,20036,19986,19936,19886,19836,19786,19736,19686,19635,19585,19535,19485,19435,19385,19335,19285,19234,19184,19134,19084,19034,18984,18934,18883,18833,18783,18733,18683,18633,18583,18532,18482,18432,18382,18332,18282,18232,18181,18131,18081,18031,17981,17931,17881,17830,17780,17730,17680,17630,17580,17530,17479,17429,17379,17329,17279,17229,17178,17128,17078,17028,16978,16928,16878,16827,16777,16727,16677,16627,16577,16526,16476,16426,16376,16326,16276,16225,16175,16125,16075,16025,15975,15924,15874,15824,15774,15724,15673,15623,15573,15523,15473,15423,15372,15322,15272,15222,15172,15122,15071,15021,14971,14921,14871,14820,14770,14720,14670,14620,14569,14519,14469,14419,14369,14319,14268,14218,14168,14118,14068,14017,13967,13917,13867,13817,13766,13716,13666,13616,13566,13515,13465,13415,13365,13315,13264,13214,13164,13114,13064,13013,12963,12913,12863,12813,12762,12712,12662,12612,12562,12511,12461,12411,12361,12311,12260,12210,12160,12110,12059,12009,11959,11909,11859,11808,11758,11708,11658,11608,11557,11507,11457,11407,11356,11306,11256,11206,11156,11105,11055,11005,10955,10904,10854,10804,10754,10704,10653,10603,10553,10503,10452,10402,10352,10302,10252,10201,10151,10101,10051,10000,9950,9900,9850,9799,9749,9699,9649,9599,9548,9498,9448,9398,9347,9297,9247,9197,9146,9096,9046,8996,8946,8895,8845,8795,8745,8694,8644,8594,8544,8493,8443,8393,8343,8292,8242,8192,8142,8091,8041,7991,7941,7890,7840,7790,7740,7690,7639,7589,7539,7489,7438,7388,7338,7288,7237,7187,7137,7087,7036,6986,6936,6886,6835,6785,6735,6685,6634,6584,6534,6484,6433,6383,6333,6283,6232,6182,6132,6082,6031,5981,5931,5881,5830,5780,5730,5680,5629,5579,5529,5479,5428,5378,5328,5278,5227,5177,5127,5076,5026,4976,4926,4875,4825,4775,4725,4674,4624,4574,4524,4473,4423,4373,4323,4272,4222,4172,4122,4071,4021,3971,3921,3870,3820,3770,3720,3669,3619,3569,3518,3468,3418,3368,3317,3267,3217,3167,3116,3066,3016,2966,2915,2865,2815,2765,2714,2664,2614,2563,2513,2463,2413,2362,2312,2262,2212,2161,2111,2061,2011,1960,1910,1860,1810,1759,1709,1659,1608,1558,1508,1458,1407,1357,1307,1257,1206,1156,1106,1056,1005,955,905,855,804,754,704,653,603,553,503,452,402,352,302,251,201,151,101,50,0,-49,-100,-150,-200,-250,-301,-351,-401,-451,-502,-552,-602,-652,-703,-753,-803,-854,-904,-954,-1004,-1055,-1105,-1155,-1205,-1256,-1306,-1356,-1406,-1457,-1507,-1557,-1607,-1658,-1708,-1758,-1809,-1859,-1909,-1959,-2010,-2060,-2110,-2160,-2211,-2261,-2311,-2361,-2412,-2462,-2512,-2562,-2613,-2663,-2713,-2764,-2814,-2864,-2914,-2965,-3015,-3065,-3115,-3166,-3216,-3266,-3316,-3367,-3417,-3467,-3517,-3568,-3618,-3668,-3719,-3769,-3819,-3869,-3920,-3970,-4020,-4070,-4121,-4171,-4221,-4271,-4322,-4372,-4422,-4472,-4523,-4573,-4623,-4673,-4724,-4774,-4824,-4874,-4925,-4975,-5025,-5075,-5126,-5176,-5226,-5277,-5327,-5377,-5427,-5478,-5528,-5578,-5628,-5679,-5729,-5779,-5829,-5880,-5930,-5980,-6030,-6081,-6131,-6181,-6231,-6282,-6332,-6382,-6432,-6483,-6533,-6583,-6633,-6684,-6734,-6784,-6834,-6885,-6935,-6985,-7035,-7086,-7136,-7186,-7236,-7287,-7337,-7387,-7437,-7488,-7538,-7588,-7638,-7689,-7739,-7789,-7839,-7889,-7940,-7990,-8040,-8090,-8141,-8191,-8241,-8291,-8342,-8392,-8442,-8492,-8543,-8593,-8643,-8693,-8744,-8794,-8844,-8894,-8945,-8995,-9045,-9095,-9145,-9196,-9246,-9296,-9346,-9397,-9447,-9497,-9547,-9598,-9648,-9698,-9748,-9798,-9849,-9899,-9949,-9999,-10050,-10100,-10150,-10200,-10251,-10301,-10351,-10401,-10451,-10502,-10552,-10602,-10652,-10703,-10753,-10803,-10853,-10903,-10954,-11004,-11054,-11104,-11155,-11205,-11255,-11305,-11355,-11406,-11456,-11506,-11556,-11607,-11657,-11707,-11757,-11807,-11858,-11908,-11958,-12008,-12058,-12109,-12159,-12209,-12259,-12310,-12360,-12410,-12460,-12510,-12561,-12611,-12661,-12711,-12761,-12812,-12862,-12912,-12962,-13012,-13063,-13113,-13163,-13213,-13263,-13314,-13364,-13414,-13464,-13514,-13565,-13615,-13665,-13715,-13765,-13816,-13866,-13916,-13966,-14016,-14067,-14117,-14167,-14217,-14267,-14318,-14368,-14418,-14468,-14518,-14568,-14619,-14669,-14719,-14769,-14819,-14870,-14920,-14970,-15020,-15070,-15121,-15171,-15221,-15271,-15321,-15371,-15422,-15472,-15522,-15572,-15622,-15672,-15723,-15773,-15823,-15873,-15923,-15974,-16024,-16074,-16124,-16174,-16224,-16275,-16325,-16375,-16425,-16475,-16525,-16576,-16626,-16676,-16726,-16776,-16826,-16877,-16927,-16977,-17027,-17077,-17127,-17177,-17228,-17278,-17328,-17378,-17428,-17478,-17529,-17579,-17629,-17679,-17729,-17779,-17829,-17880,-17930,-17980,-18030,-18080,-18130,-18180,-18231,-18281,-18331,-18381,-18431,-18481,-18531,-18582,-18632,-18682,-18732,-18782,-18832,-18882,-18933,-18983,-19033,-19083,-19133,-19183,-19233,-19284,-19334,-19384,-19434,-19484,-19534,-19584,-19634,-19685,-19735,-19785,-19835,-19885,-19935,-19985,-20035,-20085,-20136,-20186,-20236,-20286,-20336,-20386,-20436,-20486,-20537,-20587,-20637,-20687,-20737,-20787,-20837,-20887,-20937,-20987,-21038,-21088,-21138,-21188,-21238,-21288,-21338,-21388,-21438,-21488,-21539,-21589,-21639,-21689,-21739,-21789,-21839,-21889,-21939,-21989,-22039,-22090,-22140,-22190,-22240,-22290,-22340,-22390,-22440,-22490,-22540,-22590,-22640,-22691,-22741,-22791,-22841,-22891,-22941,-22991,-23041,-23091,-23141,-23191,-23241,-23291,-23341,-23392,-23442,-23492,-23542,-23592,-23642,-23692,-23742,-23792,-23842,-23892,-23942,-23992,-24042,-24092,-24142,-24192,-24243,-24293,-24343,-24393,-24443,-24493,-24543,-24593,-24643,-24693,-24743,-24793,-24843,-24893,-24943,-24993,-25043,-25093,-25143,-25193,-25243,-25293,-25343,-25393,-25443,-25494,-25544,-25594,-25644,-25694,-25744,-25794,-25844,-25894,-25944,-25994,-26044,-26094,-26144,-26194,-26244,-26294,-26344,-26394,-26444,-26494,-26544,-26594,-26644,-26694,-26744,-26794,-26844,-26894,-26944,-26994,-27044,-27094,-27144,-27194,-27244,-27294,-27344,-27394,-27444,-27494,-27544,-27594,-27644,-27694,-27744,-27794,-27844,-27894,-27944,-27994,-28044,-28094,-28144,-28194,-28244,-28294,-28343,-28393,-28443,-28493,-28543,-28593,-28643,-28693,-28743,-28793,-28843,-28893,-28943,-28993,-29043,-29093,-29143,-29193,-29243,-29293,-29343,-29393,-29443,-29493,-29542,-29592,-29642,-29692,-29742,-29792,-29842,-29892,-29942,-29992,-30042,-30092,-30142,-30192,-30242,-30292,-30341,-30391,-30441,-30491,-30541,-30591,-30641,-30691,-30741,-30791,-30841,-30891,-30941,-30990,-31040,-31090,-31140,-31190,-31240,-31290,-31340,-31390,-31440,-31489,-31539,-31589,-31639,-31689,-31739,-31789,-31839,-31889,-31939,-31988,-32038,-32088,-32138,-32188,-32238,-32288,-32338,-32388,-32437,-32487,-32537,-32587,-32637,-32687,-32737,-32787,-32836,-32886,-32936,-32986,-33036,-33086,-33136,-33185,-33235,-33285,-33335,-33385,-33435,-33485,-33534,-33584,-33634,-33684,-33734,-33784,-33834,-33883,-33933,-33983,-34033,-34083,-34133,-34182,-34232,-34282,-34332,-34382,-34432,-34481,-34531,-34581,-34631,-34681,-34731,-34780,-34830,-34880,-34930,-34980,-35029,-35079,-35129,-35179,-35229,-35279,-35328,-35378,-35428,-35478,-35528,-35577,-35627,-35677,-35727,-35777,-35826,-35876,-35926,-35976,-36026,-36075,-36125,-36175,-36225,-36274,-36324,-36374,-36424,-36474,-36523,-36573,-36623,-36673,-36722,-36772,-36822,-36872,-36921,-36971,-37021,-37071,-37121,-37170,-37220,-37270,-37320,-37369,-37419,-37469,-37519,-37568,-37618,-37668,-37718,-37767,-37817,-37867,-37916,-37966,-38016,-38066,-38115,-38165,-38215,-38265,-38314,-38364,-38414,-38464,-38513,-38563,-38613,-38662,-38712,-38762,-38812,-38861,-38911,-38961,-39010,-39060,-39110,-39159,-39209,-39259,-39309,-39358,-39408,-39458,-39507,-39557,-39607,-39656,-39706,-39756,-39805,-39855,-39905,-39955,-40004,-40054,-40104,-40153,-40203,-40253,-40302,-40352,-40402,-40451,-40501,-40551,-40600,-40650,-40700,-40749,-40799,-40848,-40898,-40948,-40997,-41047,-41097,-41146,-41196,-41246,-41295,-41345,-41395,-41444,-41494,-41543,-41593,-41643,-41692,-41742,-41792,-41841,-41891,-41940,-41990,-42040,-42089,-42139,-42189,-42238,-42288,-42337,-42387,-42437,-42486,-42536,-42585,-42635,-42685,-42734,-42784,-42833,-42883,-42932,-42982,-43032,-43081,-43131,-43180,-43230,-43280,-43329,-43379,-43428,-43478,-43527,-43577,-43627,-43676,-43726,-43775,-43825,-43874,-43924,-43973,-44023,-44073,-44122,-44172,-44221,-44271,-44320,-44370,-44419,-44469,-44518,-44568,-44618,-44667,-44717,-44766,-44816,-44865,-44915,-44964,-45014,-45063,-45113,-45162,-45212,-45261,-45311,-45360,-45410,-45459,-45509,-45558,-45608,-45657,-45707,-45756,-45806,-45855,-45905,-45954,-46004,-46053,-46103,-46152,-46202,-46251,-46301,-46350,-46400,-46449,-46499,-46548,-46597,-46647,-46696,-46746,-46795,-46845,-46894,-46944,-46993,-47043,-47092,-47141,-47191,-47240,-47290,-47339,-47389,-47438,-47488,-47537,-47586,-47636,-47685,-47735,-47784,-47834,-47883,-47932,-47982,-48031,-48081,-48130,-48179,-48229,-48278,-48328,-48377,-48426,-48476,-48525,-48575,-48624,-48673,-48723,-48772,-48822,-48871,-48920,-48970,-49019,-49069,-49118,-49167,-49217,-49266,-49315,-49365,-49414,-49463,-49513,-49562,-49612,-49661,-49710,-49760,-49809,-49858,-49908,-49957,-50006,-50056,-50105,-50154,-50204,-50253,-50302,-50352,-50401,-50450,-50500,-50549,-50598,-50648,-50697,-50746,-50796,-50845,-50894,-50944,-50993,-51042,-51091,-51141,-51190,-51239,-51289,-51338,-51387,-51437,-51486,-51535,-51584,-51634,-51683,-51732,-51781,-51831,-51880,-51929,-51979,-52028,-52077,-52126,-52176,-52225,-52274,-52323,-52373,-52422,-52471,-52520,-52570,-52619,-52668,-52717,-52767,-52816,-52865,-52914,-52964,-53013,-53062,-53111,-53160,-53210,-53259,-53308,-53357,-53407,-53456,-53505,-53554,-53603,-53653,-53702,-53751,-53800,-53849,-53899,-53948,-53997,-54046,-54095,-54144,-54194,-54243,-54292,-54341,-54390,-54440,-54489,-54538,-54587,-54636,-54685,-54735,-54784,-54833,-54882,-54931,-54980,-55029,-55079,-55128,-55177,-55226,-55275,-55324,-55373,-55423,-55472,-55521,-55570,-55619,-55668,-55717,-55766,-55815,-55865,-55914,-55963,-56012,-56061,-56110,-56159,-56208,-56257,-56307,-56356,-56405,-56454,-56503,-56552,-56601,-56650,-56699,-56748,-56797,-56846,-56895,-56945,-56994,-57043,-57092,-57141,-57190,-57239,-57288,-57337,-57386,-57435,-57484,-57533,-57582,-57631,-57680,-57729,-57778,-57827,-57876,-57925,-57974,-58023,-58072,-58121,-58170,-58220,-58269,-58318,-58367,-58416,-58465,-58514,-58563,-58612,-58661,-58710,-58758,-58807,-58856,-58905,-58954,-59003,-59052,-59101,-59150,-59199,-59248,-59297,-59346,-59395,-59444,-59493,-59542,-59591,-59640,-59689,-59738,-59787,-59836,-59885,-59934,-59982,-60031,-60080,-60129,-60178,-60227,-60276,-60325,-60374,-60423,-60472,-60521,-60569,-60618,-60667,-60716,-60765,-60814,-60863,-60912,-60961,-61010,-61058,-61107,-61156,-61205,-61254,-61303,-61352,-61401,-61449,-61498,-61547,-61596,-61645,-61694,-61743,-61791,-61840,-61889,-61938,-61987,-62036,-62084,-62133,-62182,-62231,-62280,-62329,-62377,-62426,-62475,-62524,-62573,-62622,-62670,-62719,-62768,-62817,-62866,-62914,-62963,-63012,-63061,-63110,-63158,-63207,-63256,-63305,-63353,-63402,-63451,-63500,-63549,-63597,-63646,-63695,-63744,-63792,-63841,-63890,-63939,-63987,-64036,-64085,-64134,-64182,-64231,-64280,-64328,-64377,-64426,-64475,-64523,-64572,-64621,-64670,-64718,-64767,-64816,-64864,-64913,-64962,-65010,-65059,-65108,-65157,-65205,-65254,-65303,-65351,-65400,-65449,-65497,-65546,-65595,-65643,-65692,-65741,-65789,-65838,-65887,-65935,-65984,-66033,-66081,-66130,-66178,-66227,-66276,-66324,-66373,-66422,-66470,-66519,-66567,-66616,-66665,-66713,-66762,-66811,-66859,-66908,-66956,-67005,-67054,-67102,-67151,-67199,-67248,-67296,-67345,-67394,-67442,-67491,-67539,-67588,-67636,-67685,-67734,-67782,-67831,-67879,-67928,-67976,-68025,-68073,-68122,-68170,-68219,-68268,-68316,-68365,-68413,-68462,-68510,-68559,-68607,-68656,-68704,-68753,-68801,-68850,-68898,-68947,-68995,-69044,-69092,-69141,-69189,-69238,-69286,-69335,-69383,-69432,-69480,-69529,-69577,-69625,-69674,-69722,-69771,-69819,-69868,-69916,-69965,-70013,-70061,-70110,-70158,-70207,-70255,-70304,-70352,-70400,-70449,-70497,-70546,-70594,-70643,-70691,-70739,-70788,-70836,-70885,-70933,-70981,-71030,-71078,-71126,-71175,-71223,-71272,-71320,-71368,-71417,-71465,-71513,-71562,-71610,-71658,-71707,-71755,-71804,-71852,-71900,-71949,-71997,-72045,-72094,-72142,-72190,-72238,-72287,-72335,-72383,-72432,-72480,-72528,-72577,-72625,-72673,-72722,-72770,-72818,-72866,-72915,-72963,-73011,-73060,-73108,-73156,-73204,-73253,-73301,-73349,-73397,-73446,-73494,-73542,-73590,-73639,-73687,-73735,-73783,-73832,-73880,-73928,-73976,-74024,-74073,-74121,-74169,-74217,-74266,-74314,-74362,-74410,-74458,-74507,-74555,-74603,-74651,-74699,-74747,-74796,-74844,-74892,-74940,-74988,-75036,-75085,-75133,-75181,-75229,-75277,-75325,-75374,-75422,-75470,-75518,-75566,-75614,-75662,-75710,-75759,-75807,-75855,-75903,-75951,-75999,-76047,-76095,-76143,-76192,-76240,-76288,-76336,-76384,-76432,-76480,-76528,-76576,-76624,-76672,-76720,-76769,-76817,-76865,-76913,-76961,-77009,-77057,-77105,-77153,-77201,-77249,-77297,-77345,-77393,-77441,-77489,-77537,-77585,-77633,-77681,-77729,-77777,-77825,-77873,-77921,-77969,-78017,-78065,-78113,-78161,-78209,-78257,-78305,-78353,-78401,-78449,-78497,-78545,-78593,-78641,-78689,-78737,-78785,-78833,-78880,-78928,-78976,-79024,-79072,-79120,-79168,-79216,-79264,-79312,-79360,-79408,-79456,-79503,-79551,-79599,-79647,-79695,-79743,-79791,-79839,-79886,-79934,-79982,-80030,-80078,-80126,-80174,-80222,-80269,-80317,-80365,-80413,-80461,-80509,-80556,-80604,-80652,-80700,-80748,-80796,-80843,-80891,-80939,-80987,-81035,-81082,-81130,-81178,-81226,-81274,-81321,-81369,-81417,-81465,-81513,-81560,-81608,-81656,-81704,-81751,-81799,-81847,-81895,-81942,-81990,-82038,-82086,-82133,-82181,-82229,-82277,-82324,-82372,-82420,-82467,-82515,-82563,-82611,-82658,-82706,-82754,-82801,-82849,-82897,-82944,-82992,-83040,-83087,-83135,-83183,-83230,-83278,-83326,-83373,-83421,-83469,-83516,-83564,-83612,-83659,-83707,-83755,-83802,-83850,-83897,-83945,-83993,-84040,-84088,-84135,-84183,-84231,-84278,-84326,-84373,-84421,-84469,-84516,-84564,-84611,-84659,-84707,-84754,-84802,-84849,-84897,-84944,-84992,-85039,-85087,-85135,-85182,-85230,-85277,-85325,-85372,-85420,-85467,-85515,-85562,-85610,-85657,-85705,-85752,-85800,-85847,-85895,-85942,-85990,-86037,-86085,-86132,-86180,-86227,-86275,-86322,-86370,-86417,-86464,-86512,-86559,-86607,-86654,-86702,-86749,-86797,-86844,-86891,-86939,-86986,-87034,-87081,-87128,-87176,-87223,-87271,-87318,-87365,-87413,-87460,-87508,-87555,-87602,-87650,-87697,-87744,-87792,-87839,-87887,-87934,-87981,-88029,-88076,-88123,-88171,-88218,-88265,-88313,-88360,-88407,-88455,-88502,-88549,-88597,-88644,-88691,-88738,-88786,-88833,-88880,-88928,-88975,-89022,-89069,-89117,-89164,-89211,-89259,-89306,-89353,-89400,-89448,-89495,-89542,-89589,-89637,-89684,-89731,-89778,-89825,-89873,-89920,-89967,-90014,-90062,-90109,-90156,-90203,-90250,-90298,-90345,-90392,-90439,-90486,-90533,-90581,-90628,-90675,-90722,-90769,-90816,-90864,-90911,-90958,-91005,-91052,-91099,-91146,-91194,-91241,-91288,-91335,-91382,-91429,-91476,-91523,-91570,-91618,-91665,-91712,-91759,-91806,-91853,-91900,-91947,-91994,-92041,-92088,-92135,-92182,-92229,-92277,-92324,-92371,-92418,-92465,-92512,-92559,-92606,-92653,-92700,-92747,-92794,-92841,-92888,-92935,-92982,-93029,-93076,-93123,-93170,-93217,-93264,-93311,-93358,-93405,-93452,-93499,-93546,-93593,-93639,-93686,-93733,-93780,-93827,-93874,-93921,-93968,-94015,-94062,-94109,-94156,-94203,-94250,-94296,-94343,-94390,-94437,-94484,-94531,-94578,-94625,-94672,-94718,-94765,-94812,-94859,-94906,-94953,-95000,-95046,-95093,-95140,-95187,-95234,-95281,-95327,-95374,-95421,-95468,-95515,-95561,-95608,-95655,-95702,-95749,-95795,-95842,-95889,-95936,-95983,-96029,-96076,-96123,-96170,-96216,-96263,-96310,-96357,-96403,-96450,-96497,-96544,-96590,-96637,-96684,-96731,-96777,-96824,-96871,-96917,-96964,-97011,-97057,-97104,-97151,-97198,-97244,-97291,-97338,-97384,-97431,-97478,-97524,-97571,-97618,-97664,-97711,-97757,-97804,-97851,-97897,-97944,-97991,-98037,-98084,-98130,-98177,-98224,-98270,-98317,-98363,-98410,-98457,-98503,-98550,-98596,-98643,-98690,-98736,-98783,-98829,-98876,-98922,-98969,-99015,-99062,-99109,-99155,-99202,-99248,-99295,-99341,-99388,-99434,-99481,-99527,-99574,-99620,-99667,-99713,-99760,-99806,-99853,-99899,-99946,-99992,-100038,-100085,-100131,-100178,-100224,-100271,-100317,-100364,-100410,-100456,-100503,-100549,-100596,-100642,-100689,-100735,-100781,-100828,-100874,-100921,-100967,-101013,-101060,-101106,-101152,-101199,-101245,-101292,-101338,-101384,-101431,-101477,-101523,-101570,-101616,-101662,-101709,-101755,-101801,-101848,-101894,-101940,-101987,-102033,-102079,-102125,-102172,-102218,-102264,-102311,-102357,-102403,-102449,-102496,-102542,-102588,-102634,-102681,-102727,-102773,-102819,-102866,-102912,-102958,-103004,-103051,-103097,-103143,-103189,-103235,-103282,-103328,-103374,-103420,-103466,-103513,-103559,-103605,-103651,-103697,-103743,-103790,-103836,-103882,-103928,-103974,-104020,-104066,-104113,-104159,-104205,-104251,-104297,-104343,-104389,-104435,-104482,-104528,-104574,-104620,-104666,-104712,-104758,-104804,-104850,-104896,-104942,-104988,-105034,-105081,-105127,-105173,-105219,-105265,-105311,-105357,-105403,-105449,-105495,-105541,-105587,-105633,-105679,-105725,-105771,-105817,-105863,-105909,-105955,-106001,-106047,-106093,-106139,-106185,-106231,-106277,-106322,-106368,-106414,-106460,-106506,-106552,-106598,-106644,-106690,-106736,-106782,-106828,-106874,-106919,-106965,-107011,-107057,-107103,-107149,-107195,-107241,-107286,-107332,-107378,-107424,-107470,-107516,-107562,-107607,-107653,-107699,-107745,-107791,-107837,-107882,-107928,-107974,-108020,-108066,-108111,-108157,-108203,-108249,-108294,-108340,-108386,-108432,-108478,-108523,-108569,-108615,-108661,-108706,-108752,-108798,-108844,-108889,-108935,-108981,-109026,-109072,-109118,-109164,-109209,-109255,-109301,-109346,-109392,-109438,-109483,-109529,-109575,-109620,-109666,-109712,-109757,-109803,-109849,-109894,-109940,-109985,-110031,-110077,-110122,-110168,-110214,-110259,-110305,-110350,-110396,-110442,-110487,-110533,-110578,-110624,-110669,-110715,-110761,-110806,-110852,-110897,-110943,-110988,-111034,-111079,-111125,-111170,-111216,-111261,-111307,-111352,-111398,-111443,-111489,-111534,-111580,-111625,-111671,-111716,-111762,-111807,-111853,-111898,-111944,-111989,-112035,-112080,-112125,-112171,-112216,-112262,-112307,-112353,-112398,-112443,-112489,-112534,-112580,-112625,-112670,-112716,-112761,-112807,-112852,-112897,-112943,-112988,-113033,-113079,-113124,-113169,-113215,-113260,-113305,-113351,-113396,-113441,-113487,-113532,-113577,-113623,-113668,-113713,-113758,-113804,-113849,-113894,-113940,-113985,-114030,-114075,-114121,-114166,-114211,-114256,-114302,-114347,-114392,-114437,-114482,-114528,-114573,-114618,-114663,-114709,-114754,-114799,-114844,-114889,-114934,-114980,-115025,-115070,-115115,-115160,-115205,-115251,-115296,-115341,-115386,-115431,-115476,-115521,-115566,-115612,-115657,-115702,-115747,-115792,-115837,-115882,-115927,-115972,-116017,-116063,-116108,-116153,-116198,-116243,-116288,-116333,-116378,-116423,-116468,-116513,-116558,-116603,-116648,-116693,-116738,-116783,-116828,-116873,-116918,-116963,-117008,-117053,-117098,-117143,-117188,-117233,-117278,-117323,-117368,-117413,-117458,-117503,-117548,-117592,-117637,-117682,-117727,-117772,-117817,-117862,-117907,-117952,-117997,-118041,-118086,-118131,-118176,-118221,-118266,-118311,-118356,-118400,-118445,-118490,-118535,-118580,-118625,-118669,-118714,-118759,-118804,-118849,-118893,-118938,-118983,-119028,-119073,-119117,-119162,-119207,-119252,-119296,-119341,-119386,-119431,-119475,-119520,-119565,-119610,-119654,-119699,-119744,-119789,-119833,-119878,-119923,-119967,-120012,-120057,-120101,-120146,-120191,-120235,-120280,-120325,-120369,-120414,-120459,-120503,-120548,-120593,-120637,-120682,-120726,-120771,-120816,-120860,-120905,-120949,-120994,-121039,-121083,-121128,-121172,-121217,-121262,-121306,-121351,-121395,-121440,-121484,-121529,-121573,-121618,-121662,-121707,-121751,-121796,-121841,-121885,-121930,-121974,-122018,-122063,-122107,-122152,-122196,-122241,-122285,-122330,-122374,-122419,-122463,-122508,-122552,-122596,-122641,-122685,-122730,-122774,-122819,-122863,-122907,-122952,-122996,-123041,-123085,-123129,-123174,-123218,-123262,-123307,-123351,-123395,-123440,-123484,-123528,-123573,-123617,-123661,-123706,-123750,-123794,-123839,-123883,-123927,-123972,-124016,-124060,-124104,-124149,-124193,-124237,-124282,-124326,-124370,-124414,-124459,-124503,-124547,-124591,-124635,-124680,-124724,-124768,-124812,-124856,-124901,-124945,-124989,-125033,-125077,-125122,-125166,-125210,-125254,-125298,-125342,-125387,-125431,-125475,-125519,-125563,-125607,-125651,-125695,-125740,-125784,-125828,-125872,-125916,-125960,-126004,-126048,-126092,-126136,-126180,-126224,-126268,-126313,-126357,-126401,-126445,-126489,-126533,-126577,-126621,-126665,-126709,-126753,-126797,-126841,-126885,-126929,-126973,-127017,-127061,-127105,-127149,-127192,-127236,-127280,-127324,-127368,-127412,-127456,-127500,-127544,-127588,-127632,-127676,-127720,-127763,-127807,-127851,-127895,-127939,-127983,-128027,-128071,-128114,-128158,-128202,-128246,-128290,-128334,-128377,-128421,-128465,-128509,-128553,-128597,-128640,-128684,-128728,-128772,-128815,-128859,-128903,-128947,-128991,-129034,-129078,-129122,-129166,-129209,-129253,-129297,-129340,-129384,-129428,-129472,-129515,-129559,-129603,-129646,-129690,-129734,-129777,-129821,-129865,-129908,-129952,-129996,-130039,-130083,-130127,-130170,-130214,-130258,-130301,-130345,-130388,-130432,-130476,-130519,-130563,-130606,-130650,-130694,-130737,-130781,-130824,-130868,-130911,-130955,-130998,-131042,-131086,-131129,-131173,-131216,-131260,-131303,-131347,-131390,-131434,-131477,-131521,-131564,-131608,-131651,-131694,-131738,-131781,-131825,-131868,-131912,-131955,-131999,-132042,-132085,-132129,-132172,-132216,-132259,-132302,-132346,-132389,-132433,-132476,-132519,-132563,-132606,-132649,-132693,-132736,-132779,-132823,-132866,-132909,-132953,-132996,-133039,-133083,-133126,-133169,-133213,-133256,-133299,-133342,-133386,-133429,-133472,-133516,-133559,-133602,-133645,-133689,-133732,-133775,-133818,-133861,-133905,-133948,-133991,-134034,-134077,-134121,-134164,-134207,-134250,-134293,-134337,-134380,-134423,-134466,-134509,-134552,-134595,-134639,-134682,-134725,-134768,-134811,-134854,-134897,-134940,-134983,-135027,-135070,-135113,-135156,-135199,-135242,-135285,-135328,-135371,-135414,-135457,-135500,-135543,-135586,-135629,-135672,-135715,-135758,-135801,-135844,-135887,-135930,-135973,-136016,-136059,-136102,-136145,-136188,-136231,-136274,-136317,-136360,-136403,-136446,-136489,-136531,-136574,-136617,-136660,-136703,-136746,-136789,-136832,-136875,-136917,-136960,-137003,-137046,-137089,-137132,-137175,-137217,-137260,-137303,-137346,-137389,-137431,-137474,-137517,-137560,-137603,-137645,-137688,-137731,-137774,-137816,-137859,-137902,-137945,-137987,-138030,-138073,-138116,-138158,-138201,-138244,-138287,-138329,-138372,-138415,-138457,-138500,-138543,-138585,-138628,-138671,-138713,-138756,-138799,-138841,-138884,-138926,-138969,-139012,-139054,-139097,-139140,-139182,-139225,-139267,-139310,-139352,-139395,-139438,-139480,-139523,-139565,-139608,-139650,-139693,-139735,-139778,-139820,-139863,-139906,-139948,-139991,-140033,-140076,-140118,-140160,-140203,-140245,-140288,-140330,-140373,-140415,-140458,-140500,-140543,-140585,-140627,-140670,-140712,-140755,-140797,-140839,-140882,-140924,-140967,-141009,-141051,-141094,-141136,-141178,-141221,-141263,-141305,-141348,-141390,-141432,-141475,-141517,-141559,-141602,-141644,-141686,-141729,-141771,-141813,-141855,-141898,-141940,-141982,-142024,-142067,-142109,-142151,-142193,-142236,-142278,-142320,-142362,-142404,-142447,-142489,-142531,-142573,-142615,-142658,-142700,-142742,-142784,-142826,-142868,-142911,-142953,-142995,-143037,-143079,-143121,-143163,-143205,-143247,-143290,-143332,-143374,-143416,-143458,-143500,-143542,-143584,-143626,-143668,-143710,-143752,-143794,-143836,-143878,-143920,-143962,-144004,-144046,-144088,-144130,-144172,-144214,-144256,-144298,-144340,-144382,-144424,-144466,-144508,-144550,-144592,-144634,-144676,-144718,-144760,-144801,-144843,-144885,-144927,-144969,-145011,-145053,-145095,-145136,-145178,-145220,-145262,-145304,-145346,-145388,-145429,-145471,-145513,-145555,-145597,-145638,-145680,-145722,-145764,-145806,-145847,-145889,-145931,-145973,-146014,-146056,-146098,-146140,-146181,-146223,-146265,-146306,-146348,-146390,-146432,-146473,-146515,-146557,-146598,-146640,-146682,-146723,-146765,-146807,-146848,-146890,-146931,-146973,-147015,-147056,-147098,-147140,-147181,-147223,-147264,-147306,-147347,-147389,-147431,-147472,-147514,-147555,-147597,-147638,-147680,-147721,-147763,-147804,-147846,-147887,-147929,-147970,-148012,-148053,-148095,-148136,-148178,-148219,-148261,-148302,-148344,-148385,-148427,-148468,-148509,-148551,-148592,-148634,-148675,-148716,-148758,-148799,-148841,-148882,-148923,-148965,-149006,-149047,-149089,-149130,-149171,-149213,-149254,-149295,-149337,-149378,-149419,-149461,-149502,-149543,-149584,-149626,-149667,-149708,-149750,-149791,-149832,-149873,-149915,-149956,-149997,-150038,-150079,-150121,-150162,-150203,-150244,-150285,-150327,-150368,-150409,-150450,-150491,-150532,-150574,-150615,-150656,-150697,-150738,-150779,-150820,-150861,-150903,-150944,-150985,-151026,-151067,-151108,-151149,-151190,-151231,-151272,-151313,-151354,-151395,-151436,-151477,-151518,-151559,-151600,-151641,-151682,-151723,-151764,-151805,-151846,-151887,-151928,-151969,-152010,-152051,-152092,-152133,-152174,-152215,-152256,-152297,-152338,-152379,-152420,-152460,-152501,-152542,-152583,-152624,-152665,-152706,-152747,-152787,-152828,-152869,-152910,-152951,-152992,-153032,-153073,-153114,-153155,-153196,-153236,-153277,-153318,-153359,-153399,-153440,-153481,-153522,-153562,-153603,-153644,-153685,-153725,-153766,-153807,-153847,-153888,-153929,-153969,-154010,-154051,-154092,-154132,-154173,-154213,-154254,-154295,-154335,-154376,-154417,-154457,-154498,-154538,-154579,-154620,-154660,-154701,-154741,-154782,-154823,-154863,-154904,-154944,-154985,-155025,-155066,-155106,-155147,-155187,-155228,-155268,-155309,-155349,-155390,-155430,-155471,-155511,-155552,-155592,-155633,-155673,-155714,-155754,-155794,-155835,-155875,-155916,-155956,-155996,-156037,-156077,-156118,-156158,-156198,-156239,-156279,-156319,-156360,-156400,-156440,-156481,-156521,-156561,-156602,-156642,-156682,-156723,-156763,-156803,-156844,-156884,-156924,-156964,-157005,-157045,-157085,-157125,-157166,-157206,-157246,-157286,-157326,-157367,-157407,-157447,-157487,-157527,-157568,-157608,-157648,-157688,-157728,-157768,-157808,-157849,-157889,-157929,-157969,-158009,-158049,-158089,-158129,-158169,-158210,-158250,-158290,-158330,-158370,-158410,-158450,-158490,-158530,-158570,-158610,-158650,-158690,-158730,-158770,-158810,-158850,-158890,-158930,-158970,-159010,-159050,-159090,-159130,-159170,-159210,-159250,-159290,-159329,-159369,-159409,-159449,-159489,-159529,-159569,-159609,-159649,-159688,-159728,-159768,-159808,-159848,-159888,-159928,-159967,-160007,-160047,-160087,-160127,-160166,-160206,-160246,-160286,-160326,-160365,-160405,-160445,-160485,-160524,-160564,-160604,-160643,-160683,-160723,-160763,-160802,-160842,-160882,-160921,-160961,-161001,-161040,-161080,-161120,-161159,-161199,-161239,-161278,-161318,-161358,-161397,-161437,-161476,-161516,-161556,-161595,-161635,-161674,-161714,-161753,-161793,-161832,-161872,-161912,-161951,-161991,-162030,-162070,-162109,-162149,-162188,-162228,-162267,-162307,-162346,-162385,-162425,-162464,-162504,-162543,-162583,-162622,-162662,-162701,-162740,-162780,-162819,-162859,-162898,-162937,-162977,-163016,-163055,-163095,-163134,-163173,-163213,-163252,-163291,-163331,-163370,-163409,-163449,-163488,-163527,-163567,-163606,-163645,-163684,-163724,-163763,-163802,-163841,-163881,-163920,-163959,-163998,-164038,-164077,-164116,-164155,-164194,-164233,-164273,-164312,-164351,-164390,-164429,-164468,-164508,-164547,-164586,-164625,-164664,-164703,-164742,-164781,-164820,-164860,-164899,-164938,-164977,-165016,-165055,-165094,-165133,-165172,-165211,-165250,-165289,-165328,-165367,-165406,-165445,-165484,-165523,-165562,-165601,-165640,-165679,-165718,-165757,-165796,-165835,-165874,-165913,-165951,-165990,-166029,-166068,-166107,-166146,-166185,-166224,-166263,-166301,-166340,-166379,-166418,-166457,-166496,-166534,-166573,-166612,-166651,-166690,-166728,-166767,-166806,-166845,-166884,-166922,-166961,-167000,-167039,-167077,-167116,-167155,-167193,-167232,-167271,-167310,-167348,-167387,-167426,-167464,-167503,-167542,-167580,-167619,-167658,-167696,-167735,-167773,-167812,-167851,-167889,-167928,-167967,-168005,-168044,-168082,-168121,-168159,-168198,-168237,-168275,-168314,-168352,-168391,-168429,-168468,-168506,-168545,-168583,-168622,-168660,-168699,-168737,-168776,-168814,-168852,-168891,-168929,-168968,-169006,-169045,-169083,-169121,-169160,-169198,-169237,-169275,-169313,-169352,-169390,-169429,-169467,-169505,-169544,-169582,-169620,-169659,-169697,-169735,-169773,-169812,-169850,-169888,-169927,-169965,-170003,-170041,-170080,-170118,-170156,-170194,-170233,-170271,-170309,-170347,-170385,-170424,-170462,-170500,-170538,-170576,-170615,-170653,-170691,-170729,-170767,-170805,-170843,-170882,-170920,-170958,-170996,-171034,-171072,-171110,-171148,-171186,-171224,-171262,-171300,-171338,-171377,-171415,-171453,-171491,-171529,-171567,-171605,-171643,-171681,-171719,-171757,-171795,-171833,-171870,-171908,-171946,-171984,-172022,-172060,-172098,-172136,-172174,-172212,-172250,-172288,-172325,-172363,-172401,-172439,-172477,-172515,-172553,-172590,-172628,-172666,-172704,-172742,-172780,-172817,-172855,-172893,-172931,-172968,-173006,-173044,-173082,-173120,-173157,-173195,-173233,-173270,-173308,-173346,-173384,-173421,-173459,-173497,-173534,-173572,-173610,-173647,-173685,-173723,-173760,-173798,-173836,-173873,-173911,-173948,-173986,-174024,-174061,-174099,-174136,-174174,-174211,-174249,-174287,-174324,-174362,-174399,-174437,-174474,-174512,-174549,-174587,-174624,-174662,-174699,-174737,-174774,-174812,-174849,-174886,-174924,-174961,-174999,-175036,-175074,-175111,-175148,-175186,-175223,-175261,-175298,-175335,-175373,-175410,-175447,-175485,-175522,-175559,-175597,-175634,-175671,-175709,-175746,-175783,-175821,-175858,-175895,-175932,-175970,-176007,-176044,-176081,-176119,-176156,-176193,-176230,-176267,-176305,-176342,-176379,-176416,-176453,-176491,-176528,-176565,-176602,-176639,-176676,-176713,-176751,-176788,-176825,-176862,-176899,-176936,-176973,-177010,-177047,-177084,-177122,-177159,-177196,-177233,-177270,-177307,-177344,-177381,-177418,-177455,-177492,-177529,-177566,-177603,-177640,-177677,-177714,-177751,-177787,-177824,-177861,-177898,-177935,-177972,-178009,-178046,-178083,-178120,-178157,-178193,-178230,-178267,-178304,-178341,-178378,-178414,-178451,-178488,-178525,-178562,-178599,-178635,-178672,-178709,-178746,-178782,-178819,-178856,-178893,-178929,-178966,-179003,-179040,-179076,-179113,-179150,-179186,-179223,-179260,-179296,-179333,-179370,-179406,-179443,-179480,-179516,-179553,-179590,-179626,-179663,-179699,-179736,-179773,-179809,-179846,-179882,-179919,-179955,-179992,-180028,-180065,-180102,-180138,-180175,-180211,-180248,-180284,-180321,-180357,-180394,-180430,-180466,-180503,-180539,-180576,-180612,-180649,-180685,-180722,-180758,-180794,-180831,-180867,-180903,-180940,-180976,-181013,-181049,-181085,-181122,-181158,-181194,-181231,-181267,-181303,-181340,-181376,-181412,-181448,-181485,-181521,-181557,-181593,-181630,-181666,-181702,-181738,-181775,-181811,-181847,-181883,-181919,-181956,-181992,-182028,-182064,-182100,-182136,-182173,-182209,-182245,-182281,-182317,-182353,-182389,-182425,-182462,-182498,-182534,-182570,-182606,-182642,-182678,-182714,-182750,-182786,-182822,-182858,-182894,-182930,-182966,-183002,-183038,-183074,-183110,-183146,-183182,-183218,-183254,-183290,-183326,-183362,-183398,-183434,-183469,-183505,-183541,-183577,-183613,-183649,-183685,-183721,-183756,-183792,-183828,-183864,-183900,-183936,-183971,-184007,-184043,-184079,-184115,-184150,-184186,-184222,-184258,-184293,-184329,-184365,-184401,-184436,-184472,-184508,-184544,-184579,-184615,-184651,-184686,-184722,-184758,-184793,-184829,-184865,-184900,-184936,-184971,-185007,-185043,-185078,-185114,-185149,-185185,-185221,-185256,-185292,-185327,-185363,-185398,-185434,-185469,-185505,-185540,-185576,-185611,-185647,-185682,-185718,-185753,-185789,-185824,-185860,-185895,-185931,-185966,-186001,-186037,-186072,-186108,-186143,-186178,-186214,-186249,-186285,-186320,-186355,-186391,-186426,-186461,-186497,-186532,-186567,-186603,-186638,-186673,-186709,-186744,-186779,-186814,-186850,-186885,-186920,-186955,-186991,-187026,-187061,-187096,-187131,-187167,-187202,-187237,-187272,-187307,-187342,-187378,-187413,-187448,-187483,-187518,-187553,-187588,-187624,-187659,-187694,-187729,-187764,-187799,-187834,-187869,-187904,-187939,-187974,-188009,-188044,-188079,-188114,-188149,-188184,-188219,-188254,-188289,-188324,-188359,-188394,-188429,-188464,-188499,-188534,-188569,-188604,-188639,-188674,-188708,-188743,-188778,-188813,-188848,-188883,-188918,-188953,-188987,-189022,-189057,-189092,-189127,-189161,-189196,-189231,-189266,-189301,-189335,-189370,-189405,-189440,-189474,-189509,-189544,-189579,-189613,-189648,-189683,-189717,-189752,-189787,-189821,-189856,-189891,-189925,-189960,-189995,-190029,-190064,-190098,-190133,-190168,-190202,-190237,-190271,-190306,-190341,-190375,-190410,-190444,-190479,-190513,-190548,-190582,-190617,-190651,-190686,-190720,-190755,-190789,-190824,-190858,-190893,-190927,-190962,-190996,-191030,-191065,-191099,-191134,-191168,-191202,-191237,-191271,-191306,-191340,-191374,-191409,-191443,-191477,-191512,-191546,-191580,-191615,-191649,-191683,-191717,-191752,-191786,-191820,-191855,-191889,-191923,-191957,-191991,-192026,-192060,-192094,-192128,-192163,-192197,-192231,-192265,-192299,-192333,-192368,-192402,-192436,-192470,-192504,-192538,-192572,-192606,-192640,-192675,-192709,-192743,-192777,-192811,-192845,-192879,-192913,-192947,-192981,-193015,-193049,-193083,-193117,-193151,-193185,-193219,-193253,-193287,-193321,-193355,-193389,-193423,-193457,-193491,-193524,-193558,-193592,-193626,-193660,-193694,-193728,-193762,-193795,-193829,-193863,-193897,-193931,-193965,-193998,-194032,-194066,-194100,-194134,-194167,-194201,-194235,-194269,-194302,-194336,-194370,-194404,-194437,-194471,-194505,-194538,-194572,-194606,-194639,-194673,-194707,-194740,-194774,-194808,-194841,-194875,-194909,-194942,-194976,-195009,-195043,-195077,-195110,-195144,-195177,-195211,-195244,-195278,-195311,-195345,-195378,-195412,-195445,-195479,-195512,-195546,-195579,-195613,-195646,-195680,-195713,-195747,-195780,-195814,-195847,-195880,-195914,-195947,-195981,-196014,-196047,-196081,-196114,-196147,-196181,-196214,-196247,-196281,-196314,-196347,-196381,-196414,-196447,-196480,-196514,-196547,-196580,-196614,-196647,-196680,-196713,-196746,-196780,-196813,-196846,-196879,-196912,-196946,-196979,-197012,-197045,-197078,-197111,-197145,-197178,-197211,-197244,-197277,-197310,-197343,-197376,-197409,-197442,-197475,-197509,-197542,-197575,-197608,-197641,-197674,-197707,-197740,-197773,-197806,-197839,-197872,-197905,-197938,-197971,-198003,-198036,-198069,-198102,-198135,-198168,-198201,-198234,-198267,-198300,-198333,-198365,-198398,-198431,-198464,-198497,-198530,-198562,-198595,-198628,-198661,-198694,-198726,-198759,-198792,-198825,-198857,-198890,-198923,-198956,-198988,-199021,-199054,-199087,-199119,-199152,-199185,-199217,-199250,-199283,-199315,-199348,-199381,-199413,-199446,-199478,-199511,-199544,-199576,-199609,-199641,-199674,-199707,-199739,-199772,-199804,-199837,-199869,-199902,-199934,-199967,-199999,-200032,-200064,-200097,-200129,-200162,-200194,-200227,-200259,-200291,-200324,-200356,-200389,-200421,-200453,-200486,-200518,-200551,-200583,-200615,-200648,-200680,-200712,-200745,-200777,-200809,-200842,-200874,-200906,-200939,-200971,-201003,-201035,-201068,-201100,-201132,-201164,-201197,-201229,-201261,-201293,-201325,-201358,-201390,-201422,-201454,-201486,-201518,-201551,-201583,-201615,-201647,-201679,-201711,-201743,-201775,-201807,-201840,-201872,-201904,-201936,-201968,-202000,-202032,-202064,-202096,-202128,-202160,-202192,-202224,-202256,-202288,-202320,-202352,-202384,-202416,-202448,-202480,-202511,-202543,-202575,-202607,-202639,-202671,-202703,-202735,-202767,-202798,-202830,-202862,-202894,-202926,-202958,-202989,-203021,-203053,-203085,-203117,-203148,-203180,-203212,-203244,-203275,-203307,-203339,-203371,-203402,-203434,-203466,-203497,-203529,-203561,-203592,-203624,-203656,-203687,-203719,-203751,-203782,-203814,-203845,-203877,-203909,-203940,-203972,-204003,-204035,-204066,-204098,-204130,-204161,-204193,-204224,-204256,-204287,-204319,-204350,-204382,-204413,-204445,-204476,-204507,-204539,-204570,-204602,-204633,-204665,-204696,-204727,-204759,-204790,-204822,-204853,-204884,-204916,-204947,-204978,-205010,-205041,-205072,-205104,-205135,-205166,-205197,-205229,-205260,-205291,-205323,-205354,-205385,-205416,-205447,-205479,-205510,-205541,-205572,-205603,-205635,-205666,-205697,-205728,-205759,-205790,-205822,-205853,-205884,-205915,-205946,-205977,-206008,-206039,-206070,-206101,-206132,-206164,-206195,-206226,-206257,-206288,-206319,-206350,-206381,-206412,-206443,-206474,-206505,-206536,-206566,-206597,-206628,-206659,-206690,-206721,-206752,-206783,-206814,-206845,-206876,-206906,-206937,-206968,-206999,-207030,-207061,-207091,-207122,-207153,-207184,-207215,-207245,-207276,-207307,-207338,-207369,-207399,-207430,-207461,-207491,-207522,-207553,-207584,-207614,-207645,-207676,-207706,-207737,-207768,-207798,-207829,-207860,-207890,-207921,-207951,-207982,-208013,-208043,-208074,-208104,-208135,-208165,-208196,-208227,-208257,-208288,-208318,-208349,-208379,-208410,-208440,-208471,-208501,-208532,-208562,-208592,-208623,-208653,-208684,-208714,-208745,-208775,-208805,-208836,-208866,-208896,-208927,-208957,-208988,-209018,-209048,-209079,-209109,-209139,-209169,-209200,-209230,-209260,-209291,-209321,-209351,-209381,-209412,-209442,-209472,-209502,-209533,-209563,-209593,-209623,-209653,-209683,-209714,-209744,-209774,-209804,-209834,-209864,-209894,-209925,-209955,-209985,-210015,-210045,-210075,-210105,-210135,-210165,-210195,-210225,-210255,-210285,-210315,-210345,-210375,-210405,-210435,-210465,-210495,-210525,-210555,-210585,-210615,-210645,-210675,-210705,-210735,-210764,-210794,-210824,-210854,-210884,-210914,-210944,-210973,-211003,-211033,-211063,-211093,-211123,-211152,-211182,-211212,-211242,-211271,-211301,-211331,-211361,-211390,-211420,-211450,-211480,-211509,-211539,-211569,-211598,-211628,-211658,-211687,-211717,-211747,-211776,-211806,-211835,-211865,-211895,-211924,-211954,-211983,-212013,-212042,-212072,-212102,-212131,-212161,-212190,-212220,-212249,-212279,-212308,-212338,-212367,-212397,-212426,-212455,-212485,-212514,-212544,-212573,-212603,-212632,-212661,-212691,-212720,-212750,-212779,-212808,-212838,-212867,-212896,-212926,-212955,-212984,-213014,-213043,-213072,-213101,-213131,-213160,-213189,-213218,-213248,-213277,-213306,-213335,-213365,-213394,-213423,-213452,-213481,-213510,-213540,-213569,-213598,-213627,-213656,-213685,-213714,-213744,-213773,-213802,-213831,-213860,-213889,-213918,-213947,-213976,-214005,-214034,-214063,-214092,-214121,-214150,-214179,-214208,-214237,-214266,-214295,-214324,-214353,-214382,-214411,-214440,-214469,-214497,-214526,-214555,-214584,-214613,-214642,-214671,-214700,-214728,-214757,-214786,-214815,-214844,-214872,-214901,-214930,-214959,-214988,-215016,-215045,-215074,-215103,-215131,-215160,-215189,-215217,-215246,-215275,-215303,-215332,-215361,-215389,-215418,-215447,-215475,-215504,-215533,-215561,-215590,-215618,-215647,-215676,-215704,-215733,-215761,-215790,-215818,-215847,-215875,-215904,-215932,-215961,-215989,-216018,-216046,-216075,-216103,-216132,-216160,-216189,-216217,-216245,-216274,-216302,-216331,-216359,-216387,-216416,-216444,-216472,-216501,-216529,-216557,-216586,-216614,-216642,-216671,-216699,-216727,-216756,-216784,-216812,-216840,-216869,-216897,-216925,-216953,-216981,-217010,-217038,-217066,-217094,-217122,-217151,-217179,-217207,-217235,-217263,-217291,-217319,-217347,-217376,-217404,-217432,-217460,-217488,-217516,-217544,-217572,-217600,-217628,-217656,-217684,-217712,-217740,-217768,-217796,-217824,-217852,-217880,-217908,-217936,-217964,-217992,-218020,-218048,-218075,-218103,-218131,-218159,-218187,-218215,-218243,-218270,-218298,-218326,-218354,-218382,-218410,-218437,-218465,-218493,-218521,-218548,-218576,-218604,-218632,-218659,-218687,-218715,-218743,-218770,-218798,-218826,-218853,-218881,-218909,-218936,-218964,-218992,-219019,-219047,-219074,-219102,-219130,-219157,-219185,-219212,-219240,-219267,-219295,-219323,-219350,-219378,-219405,-219433,-219460,-219488,-219515,-219543,-219570,-219597,-219625,-219652,-219680,-219707,-219735,-219762,-219789,-219817,-219844,-219872,-219899,-219926,-219954,-219981,-220008,-220036,-220063,-220090,-220118,-220145,-220172,-220199,-220227,-220254,-220281,-220308,-220336,-220363,-220390,-220417,-220445,-220472,-220499,-220526,-220553,-220580,-220608,-220635,-220662,-220689,-220716,-220743,-220770,-220797,-220825,-220852,-220879,-220906,-220933,-220960,-220987,-221014,-221041,-221068,-221095,-221122,-221149,-221176,-221203,-221230,-221257,-221284,-221311,-221338,-221365,-221392,-221418,-221445,-221472,-221499,-221526,-221553,-221580,-221607,-221633,-221660,-221687,-221714,-221741,-221768,-221794,-221821,-221848,-221875,-221902,-221928,-221955,-221982,-222009,-222035,-222062,-222089,-222115,-222142,-222169,-222195,-222222,-222249,-222275,-222302,-222329,-222355,-222382,-222409,-222435,-222462,-222488,-222515,-222541,-222568,-222595,-222621,-222648,-222674,-222701,-222727,-222754,-222780,-222807,-222833,-222860,-222886,-222913,-222939,-222965,-222992,-223018,-223045,-223071,-223098,-223124,-223150,-223177,-223203,-223229,-223256,-223282,-223308,-223335,-223361,-223387,-223414,-223440,-223466,-223492,-223519,-223545,-223571,-223598,-223624,-223650,-223676,-223702,-223729,-223755,-223781,-223807,-223833,-223859,-223886,-223912,-223938,-223964,-223990,-224016,-224042,-224068,-224095,-224121,-224147,-224173,-224199,-224225,-224251,-224277,-224303,-224329,-224355,-224381,-224407,-224433,-224459,-224485,-224511,-224537,-224563,-224589,-224614,-224640,-224666,-224692,-224718,-224744,-224770,-224796,-224822,-224847,-224873,-224899,-224925,-224951,-224977,-225002,-225028,-225054,-225080,-225105,-225131,-225157,-225183,-225208,-225234,-225260,-225286,-225311,-225337,-225363,-225388,-225414,-225440,-225465,-225491,-225516,-225542,-225568,-225593,-225619,-225645,-225670,-225696,-225721,-225747,-225772,-225798,-225823,-225849,-225874,-225900,-225925,-225951,-225976,-226002,-226027,-226053,-226078,-226104,-226129,-226155,-226180,-226205,-226231,-226256,-226282,-226307,-226332,-226358,-226383,-226408,-226434,-226459,-226484,-226510,-226535,-226560,-226585,-226611,-226636,-226661,-226687,-226712,-226737,-226762,-226787,-226813,-226838,-226863,-226888,-226913,-226939,-226964,-226989,-227014,-227039,-227064,-227089,-227114,-227140,-227165,-227190,-227215,-227240,-227265,-227290,-227315,-227340,-227365,-227390,-227415,-227440,-227465,-227490,-227515,-227540,-227565,-227590,-227615,-227640,-227665,-227690,-227715,-227739,-227764,-227789,-227814,-227839,-227864,-227889,-227913,-227938,-227963,-227988,-228013,-228038,-228062,-228087,-228112,-228137,-228161,-228186,-228211,-228236,-228260,-228285,-228310,-228334,-228359,-228384,-228408,-228433,-228458,-228482,-228507,-228532,-228556,-228581,-228606,-228630,-228655,-228679,-228704,-228728,-228753,-228778,-228802,-228827,-228851,-228876,-228900,-228925,-228949,-228974,-228998,-229023,-229047,-229071,-229096,-229120,-229145,-229169,-229193,-229218,-229242,-229267,-229291,-229315,-229340,-229364,-229388,-229413,-229437,-229461,-229486,-229510,-229534,-229559,-229583,-229607,-229631,-229656,-229680,-229704,-229728,-229752,-229777,-229801,-229825,-229849,-229873,-229897,-229922,-229946,-229970,-229994,-230018,-230042,-230066,-230090,-230115,-230139,-230163,-230187,-230211,-230235,-230259,-230283,-230307,-230331,-230355,-230379,-230403,-230427,-230451,-230475,-230499,-230523,-230547,-230570,-230594,-230618,-230642,-230666,-230690,-230714,-230738,-230761,-230785,-230809,-230833,-230857,-230881,-230904,-230928,-230952,-230976,-231000,-231023,-231047,-231071,-231095,-231118,-231142,-231166,-231189,-231213,-231237,-231260,-231284,-231308,-231331,-231355,-231379,-231402,-231426,-231449,-231473,-231497,-231520,-231544,-231567,-231591,-231614,-231638,-231662,-231685,-231709,-231732,-231756,-231779,-231803,-231826,-231849,-231873,-231896,-231920,-231943,-231967,-231990,-232013,-232037,-232060,-232084,-232107,-232130,-232154,-232177,-232200,-232224,-232247,-232270,-232294,-232317,-232340,-232363,-232387,-232410,-232433,-232456,-232480,-232503,-232526,-232549,-232573,-232596,-232619,-232642,-232665,-232688,-232712,-232735,-232758,-232781,-232804,-232827,-232850,-232873,-232896,-232919,-232943,-232966,-232989,-233012,-233035,-233058,-233081,-233104,-233127,-233150,-233173,-233196,-233219,-233242,-233264,-233287,-233310,-233333,-233356,-233379,-233402,-233425,-233448,-233471,-233493,-233516,-233539,-233562,-233585,-233608,-233630,-233653,-233676,-233699,-233721,-233744,-233767,-233790,-233812,-233835,-233858,-233881,-233903,-233926,-233949,-233971,-233994,-234017,-234039,-234062,-234085,-234107,-234130,-234152,-234175,-234198,-234220,-234243,-234265,-234288,-234310,-234333,-234355,-234378,-234400,-234423,-234445,-234468,-234490,-234513,-234535,-234558,-234580,-234603,-234625,-234648,-234670,-234692,-234715,-234737,-234759,-234782,-234804,-234827,-234849,-234871,-234893,-234916,-234938,-234960,-234983,-235005,-235027,-235049,-235072,-235094,-235116,-235138,-235161,-235183,-235205,-235227,-235249,-235272,-235294,-235316,-235338,-235360,-235382,-235404,-235427,-235449,-235471,-235493,-235515,-235537,-235559,-235581,-235603,-235625,-235647,-235669,-235691,-235713,-235735,-235757,-235779,-235801,-235823,-235845,-235867,-235889,-235911,-235933,-235955,-235977,-235998,-236020,-236042,-236064,-236086,-236108,-236130,-236151,-236173,-236195,-236217,-236239,-236260,-236282,-236304,-236326,-236347,-236369,-236391,-236413,-236434,-236456,-236478,-236499,-236521,-236543,-236564,-236586,-236608,-236629,-236651,-236673,-236694,-236716,-236737,-236759,-236781,-236802,-236824,-236845,-236867,-236888,-236910,-236931,-236953,-236974,-236996,-237017,-237039,-237060,-237082,-237103,-237125,-237146,-237167,-237189,-237210,-237232,-237253,-237274,-237296,-237317,-237338,-237360,-237381,-237402,-237424,-237445,-237466,-237488,-237509,-237530,-237551,-237573,-237594,-237615,-237636,-237658,-237679,-237700,-237721,-237742,-237764,-237785,-237806,-237827,-237848,-237869,-237890,-237912,-237933,-237954,-237975,-237996,-238017,-238038,-238059,-238080,-238101,-238122,-238143,-238164,-238185,-238206,-238227,-238248,-238269,-238290,-238311,-238332,-238353,-238374,-238395,-238416,-238436,-238457,-238478,-238499,-238520,-238541,-238562,-238582,-238603,-238624,-238645,-238666,-238687,-238707,-238728,-238749,-238770,-238790,-238811,-238832,-238852,-238873,-238894,-238915,-238935,-238956,-238977,-238997,-239018,-239039,-239059,-239080,-239100,-239121,-239142,-239162,-239183,-239203,-239224,-239244,-239265,-239286,-239306,-239327,-239347,-239368,-239388,-239409,-239429,-239449,-239470,-239490,-239511,-239531,-239552,-239572,-239592,-239613,-239633,-239654,-239674,-239694,-239715,-239735,-239755,-239776,-239796,-239816,-239837,-239857,-239877,-239897,-239918,-239938,-239958,-239978,-239999,-240019,-240039,-240059,-240079,-240100,-240120,-240140,-240160,-240180,-240200,-240220,-240241,-240261,-240281,-240301,-240321,-240341,-240361,-240381,-240401,-240421,-240441,-240461,-240481,-240501,-240521,-240541,-240561,-240581,-240601,-240621,-240641,-240661,-240681,-240701,-240721,-240741,-240761,-240780,-240800,-240820,-240840,-240860,-240880,-240900,-240919,-240939,-240959,-240979,-240999,-241018,-241038,-241058,-241078,-241097,-241117,-241137,-241156,-241176,-241196,-241216,-241235,-241255,-241275,-241294,-241314,-241333,-241353,-241373,-241392,-241412,-241432,-241451,-241471,-241490,-241510,-241529,-241549,-241568,-241588,-241607,-241627,-241646,-241666,-241685,-241705,-241724,-241744,-241763,-241783,-241802,-241821,-241841,-241860,-241880,-241899,-241918,-241938,-241957,-241976,-241996,-242015,-242034,-242054,-242073,-242092,-242111,-242131,-242150,-242169,-242188,-242208,-242227,-242246,-242265,-242285,-242304,-242323,-242342,-242361,-242380,-242400,-242419,-242438,-242457,-242476,-242495,-242514,-242533,-242552,-242571,-242590,-242610,-242629,-242648,-242667,-242686,-242705,-242724,-242743,-242762,-242781,-242799,-242818,-242837,-242856,-242875,-242894,-242913,-242932,-242951,-242970,-242989,-243007,-243026,-243045,-243064,-243083,-243102,-243120,-243139,-243158,-243177,-243195,-243214,-243233,-243252,-243270,-243289,-243308,-243327,-243345,-243364,-243383,-243401,-243420,-243439,-243457,-243476,-243495,-243513,-243532,-243550,-243569,-243587,-243606,-243625,-243643,-243662,-243680,-243699,-243717,-243736,-243754,-243773,-243791,-243810,-243828,-243847,-243865,-243884,-243902,-243920,-243939,-243957,-243976,-243994,-244012,-244031,-244049,-244067,-244086,-244104,-244122,-244141,-244159,-244177,-244196,-244214,-244232,-244250,-244269,-244287,-244305,-244323,-244342,-244360,-244378,-244396,-244414,-244432,-244451,-244469,-244487,-244505,-244523,-244541,-244559,-244577,-244596,-244614,-244632,-244650,-244668,-244686,-244704,-244722,-244740,-244758,-244776,-244794,-244812,-244830,-244848,-244866,-244884,-244902,-244920,-244937,-244955,-244973,-244991,-245009,-245027,-245045,-245063,-245080,-245098,-245116,-245134,-245152,-245170,-245187,-245205,-245223,-245241,-245258,-245276,-245294,-245312,-245329,-245347,-245365,-245382,-245400,-245418,-245435,-245453,-245471,-245488,-245506,-245524,-245541,-245559,-245576,-245594,-245612,-245629,-245647,-245664,-245682,-245699,-245717,-245734,-245752,-245769,-245787,-245804,-245822,-245839,-245857,-245874,-245891,-245909,-245926,-245944,-245961,-245978,-245996,-246013,-246031,-246048,-246065,-246083,-246100,-246117,-246135,-246152,-246169,-246186,-246204,-246221,-246238,-246255,-246273,-246290,-246307,-246324,-246341,-246359,-246376,-246393,-246410,-246427,-246444,-246462,-246479,-246496,-246513,-246530,-246547,-246564,-246581,-246598,-246615,-246632,-246649,-246666,-246683,-246700,-246717,-246734,-246751,-246768,-246785,-246802,-246819,-246836,-246853,-246870,-246887,-246904,-246921,-246937,-246954,-246971,-246988,-247005,-247022,-247039,-247055,-247072,-247089,-247106,-247122,-247139,-247156,-247173,-247189,-247206,-247223,-247240,-247256,-247273,-247290,-247306,-247323,-247340,-247356,-247373,-247390,-247406,-247423,-247439,-247456,-247473,-247489,-247506,-247522,-247539,-247555,-247572,-247588,-247605,-247621,-247638,-247654,-247671,-247687,-247704,-247720,-247737,-247753,-247770,-247786,-247802,-247819,-247835,-247852,-247868,-247884,-247901,-247917,-247933,-247950,-247966,-247982,-247999,-248015,-248031,-248047,-248064,-248080,-248096,-248112,-248129,-248145,-248161,-248177,-248193,-248210,-248226,-248242,-248258,-248274,-248290,-248306,-248322,-248339,-248355,-248371,-248387,-248403,-248419,-248435,-248451,-248467,-248483,-248499,-248515,-248531,-248547,-248563,-248579,-248595,-248611,-248627,-248643,-248659,-248675,-248690,-248706,-248722,-248738,-248754,-248770,-248786,-248802,-248817,-248833,-248849,-248865,-248881,-248896,-248912,-248928,-248944,-248959,-248975,-248991,-249007,-249022,-249038,-249054,-249069,-249085,-249101,-249116,-249132,-249148,-249163,-249179,-249194,-249210,-249226,-249241,-249257,-249272,-249288,-249303,-249319,-249334,-249350,-249366,-249381,-249397,-249412,-249427,-249443,-249458,-249474,-249489,-249505,-249520,-249535,-249551,-249566,-249582,-249597,-249612,-249628,-249643,-249658,-249674,-249689,-249704,-249720,-249735,-249750,-249765,-249781,-249796,-249811,-249826,-249842,-249857,-249872,-249887,-249902,-249918,-249933,-249948,-249963,-249978,-249993,-250008,-250024,-250039,-250054,-250069,-250084,-250099,-250114,-250129,-250144,-250159,-250174,-250189,-250204,-250219,-250234,-250249,-250264,-250279,-250294,-250309,-250324,-250339,-250354,-250369,-250384,-250398,-250413,-250428,-250443,-250458,-250473,-250488,-250502,-250517,-250532,-250547,-250561,-250576,-250591,-250606,-250621,-250635,-250650,-250665,-250679,-250694,-250709,-250723,-250738,-250753,-250767,-250782,-250797,-250811,-250826,-250841,-250855,-250870,-250884,-250899,-250913,-250928,-250943,-250957,-250972,-250986,-251001,-251015,-251030,-251044,-251059,-251073,-251087,-251102,-251116,-251131,-251145,-251160,-251174,-251188,-251203,-251217,-251231,-251246,-251260,-251274,-251289,-251303,-251317,-251332,-251346,-251360,-251374,-251389,-251403,-251417,-251431,-251446,-251460,-251474,-251488,-251502,-251517,-251531,-251545,-251559,-251573,-251587,-251601,-251616,-251630,-251644,-251658,-251672,-251686,-251700,-251714,-251728,-251742,-251756,-251770,-251784,-251798,-251812,-251826,-251840,-251854,-251868,-251882,-251896,-251910,-251924,-251937,-251951,-251965,-251979,-251993,-252007,-252021,-252034,-252048,-252062,-252076,-252090,-252103,-252117,-252131,-252145,-252158,-252172,-252186,-252200,-252213,-252227,-252241,-252254,-252268,-252282,-252295,-252309,-252323,-252336,-252350,-252364,-252377,-252391,-252404,-252418,-252431,-252445,-252459,-252472,-252486,-252499,-252513,-252526,-252540,-252553,-252567,-252580,-252593,-252607,-252620,-252634,-252647,-252661,-252674,-252687,-252701,-252714,-252727,-252741,-252754,-252767,-252781,-252794,-252807,-252821,-252834,-252847,-252860,-252874,-252887,-252900,-252913,-252927,-252940,-252953,-252966,-252979,-252993,-253006,-253019,-253032,-253045,-253058,-253071,-253084,-253098,-253111,-253124,-253137,-253150,-253163,-253176,-253189,-253202,-253215,-253228,-253241,-253254,-253267,-253280,-253293,-253306,-253319,-253332,-253345,-253358,-253370,-253383,-253396,-253409,-253422,-253435,-253448,-253460,-253473,-253486,-253499,-253512,-253524,-253537,-253550,-253563,-253576,-253588,-253601,-253614,-253626,-253639,-253652,-253665,-253677,-253690,-253703,-253715,-253728,-253740,-253753,-253766,-253778,-253791,-253803,-253816,-253829,-253841,-253854,-253866,-253879,-253891,-253904,-253916,-253929,-253941,-253954,-253966,-253979,-253991,-254003,-254016,-254028,-254041,-254053,-254066,-254078,-254090,-254103,-254115,-254127,-254140,-254152,-254164,-254177,-254189,-254201,-254213,-254226,-254238,-254250,-254262,-254275,-254287,-254299,-254311,-254323,-254336,-254348,-254360,-254372,-254384,-254396,-254409,-254421,-254433,-254445,-254457,-254469,-254481,-254493,-254505,-254517,-254529,-254541,-254553,-254565,-254577,-254589,-254601,-254613,-254625,-254637,-254649,-254661,-254673,-254685,-254697,-254709,-254720,-254732,-254744,-254756,-254768,-254780,-254792,-254803,-254815,-254827,-254839,-254851,-254862,-254874,-254886,-254898,-254909,-254921,-254933,-254944,-254956,-254968,-254980,-254991,-255003,-255014,-255026,-255038,-255049,-255061,-255073,-255084,-255096,-255107,-255119,-255130,-255142,-255154,-255165,-255177,-255188,-255200,-255211,-255223,-255234,-255245,-255257,-255268,-255280,-255291,-255303,-255314,-255325,-255337,-255348,-255360,-255371,-255382,-255394,-255405,-255416,-255428,-255439,-255450,-255461,-255473,-255484,-255495,-255506,-255518,-255529,-255540,-255551,-255563,-255574,-255585,-255596,-255607,-255618,-255629,-255641,-255652,-255663,-255674,-255685,-255696,-255707,-255718,-255729,-255740,-255751,-255762,-255773,-255784,-255795,-255806,-255817,-255828,-255839,-255850,-255861,-255872,-255883,-255894,-255905,-255916,-255927,-255938,-255948,-255959,-255970,-255981,-255992,-256003,-256013,-256024,-256035,-256046,-256057,-256067,-256078,-256089,-256100,-256110,-256121,-256132,-256142,-256153,-256164,-256175,-256185,-256196,-256206,-256217,-256228,-256238,-256249,-256260,-256270,-256281,-256291,-256302,-256312,-256323,-256333,-256344,-256354,-256365,-256375,-256386,-256396,-256407,-256417,-256428,-256438,-256449,-256459,-256469,-256480,-256490,-256501,-256511,-256521,-256532,-256542,-256552,-256563,-256573,-256583,-256594,-256604,-256614,-256624,-256635,-256645,-256655,-256665,-256676,-256686,-256696,-256706,-256716,-256727,-256737,-256747,-256757,-256767,-256777,-256787,-256797,-256808,-256818,-256828,-256838,-256848,-256858,-256868,-256878,-256888,-256898,-256908,-256918,-256928,-256938,-256948,-256958,-256968,-256978,-256988,-256998,-257007,-257017,-257027,-257037,-257047,-257057,-257067,-257077,-257086,-257096,-257106,-257116,-257126,-257135,-257145,-257155,-257165,-257174,-257184,-257194,-257204,-257213,-257223,-257233,-257242,-257252,-257262,-257271,-257281,-257291,-257300,-257310,-257319,-257329,-257339,-257348,-257358,-257367,-257377,-257386,-257396,-257405,-257415,-257424,-257434,-257443,-257453,-257462,-257472,-257481,-257491,-257500,-257509,-257519,-257528,-257538,-257547,-257556,-257566,-257575,-257584,-257594,-257603,-257612,-257622,-257631,-257640,-257650,-257659,-257668,-257677,-257687,-257696,-257705,-257714,-257723,-257733,-257742,-257751,-257760,-257769,-257778,-257788,-257797,-257806,-257815,-257824,-257833,-257842,-257851,-257860,-257869,-257878,-257887,-257896,-257905,-257914,-257923,-257932,-257941,-257950,-257959,-257968,-257977,-257986,-257995,-258004,-258013,-258022,-258030,-258039,-258048,-258057,-258066,-258075,-258083,-258092,-258101,-258110,-258119,-258127,-258136,-258145,-258154,-258162,-258171,-258180,-258189,-258197,-258206,-258215,-258223,-258232,-258241,-258249,-258258,-258266,-258275,-258284,-258292,-258301,-258309,-258318,-258326,-258335,-258344,-258352,-258361,-258369,-258378,-258386,-258395,-258403,-258411,-258420,-258428,-258437,-258445,-258454,-258462,-258470,-258479,-258487,-258495,-258504,-258512,-258521,-258529,-258537,-258545,-258554,-258562,-258570,-258579,-258587,-258595,-258603,-258612,-258620,-258628,-258636,-258644,-258653,-258661,-258669,-258677,-258685,-258693,-258701,-258710,-258718,-258726,-258734,-258742,-258750,-258758,-258766,-258774,-258782,-258790,-258798,-258806,-258814,-258822,-258830,-258838,-258846,-258854,-258862,-258870,-258878,-258886,-258894,-258901,-258909,-258917,-258925,-258933,-258941,-258949,-258956,-258964,-258972,-258980,-258988,-258995,-259003,-259011,-259019,-259026,-259034,-259042,-259049,-259057,-259065,-259072,-259080,-259088,-259095,-259103,-259111,-259118,-259126,-259134,-259141,-259149,-259156,-259164,-259171,-259179,-259186,-259194,-259201,-259209,-259216,-259224,-259231,-259239,-259246,-259254,-259261,-259269,-259276,-259284,-259291,-259298,-259306,-259313,-259320,-259328,-259335,-259342,-259350,-259357,-259364,-259372,-259379,-259386,-259394,-259401,-259408,-259415,-259422,-259430,-259437,-259444,-259451,-259458,-259466,-259473,-259480,-259487,-259494,-259501,-259508,-259516,-259523,-259530,-259537,-259544,-259551,-259558,-259565,-259572,-259579,-259586,-259593,-259600,-259607,-259614,-259621,-259628,-259635,-259642,-259649,-259656,-259663,-259669,-259676,-259683,-259690,-259697,-259704,-259711,-259717,-259724,-259731,-259738,-259745,-259751,-259758,-259765,-259772,-259778,-259785,-259792,-259799,-259805,-259812,-259819,-259825,-259832,-259839,-259845,-259852,-259859,-259865,-259872,-259878,-259885,-259892,-259898,-259905,-259911,-259918,-259924,-259931,-259937,-259944,-259950,-259957,-259963,-259970,-259976,-259983,-259989,-259996,-260002,-260008,-260015,-260021,-260028,-260034,-260040,-260047,-260053,-260059,-260066,-260072,-260078,-260084,-260091,-260097,-260103,-260110,-260116,-260122,-260128,-260134,-260141,-260147,-260153,-260159,-260165,-260172,-260178,-260184,-260190,-260196,-260202,-260208,-260214,-260220,-260227,-260233,-260239,-260245,-260251,-260257,-260263,-260269,-260275,-260281,-260287,-260293,-260299,-260305,-260311,-260316,-260322,-260328,-260334,-260340,-260346,-260352,-260358,-260364,-260369,-260375,-260381,-260387,-260393,-260398,-260404,-260410,-260416,-260422,-260427,-260433,-260439,-260444,-260450,-260456,-260462,-260467,-260473,-260479,-260484,-260490,-260495,-260501,-260507,-260512,-260518,-260524,-260529,-260535,-260540,-260546,-260551,-260557,-260562,-260568,-260573,-260579,-260584,-260590,-260595,-260601,-260606,-260612,-260617,-260622,-260628,-260633,-260639,-260644,-260649,-260655,-260660,-260665,-260671,-260676,-260681,-260687,-260692,-260697,-260702,-260708,-260713,-260718,-260723,-260729,-260734,-260739,-260744,-260749,-260755,-260760,-260765,-260770,-260775,-260780,-260785,-260790,-260796,-260801,-260806,-260811,-260816,-260821,-260826,-260831,-260836,-260841,-260846,-260851,-260856,-260861,-260866,-260871,-260876,-260881,-260886,-260891,-260895,-260900,-260905,-260910,-260915,-260920,-260925,-260929,-260934,-260939,-260944,-260949,-260954,-260958,-260963,-260968,-260973,-260977,-260982,-260987,-260991,-260996,-261001,-261006,-261010,-261015,-261020,-261024,-261029,-261033,-261038,-261043,-261047,-261052,-261056,-261061,-261066,-261070,-261075,-261079,-261084,-261088,-261093,-261097,-261102,-261106,-261111,-261115,-261119,-261124,-261128,-261133,-261137,-261142,-261146,-261150,-261155,-261159,-261163,-261168,-261172,-261176,-261181,-261185,-261189,-261194,-261198,-261202,-261206,-261211,-261215,-261219,-261223,-261227,-261232,-261236,-261240,-261244,-261248,-261252,-261257,-261261,-261265,-261269,-261273,-261277,-261281,-261285,-261289,-261293,-261297,-261301,-261305,-261309,-261313,-261317,-261321,-261325,-261329,-261333,-261337,-261341,-261345,-261349,-261353,-261357,-261361,-261365,-261368,-261372,-261376,-261380,-261384,-261388,-261391,-261395,-261399,-261403,-261407,-261410,-261414,-261418,-261422,-261425,-261429,-261433,-261436,-261440,-261444,-261447,-261451,-261455,-261458,-261462,-261466,-261469,-261473,-261476,-261480,-261484,-261487,-261491,-261494,-261498,-261501,-261505,-261508,-261512,-261515,-261519,-261522,-261526,-261529,-261532,-261536,-261539,-261543,-261546,-261550,-261553,-261556,-261560,-261563,-261566,-261570,-261573,-261576,-261580,-261583,-261586,-261589,-261593,-261596,-261599,-261602,-261606,-261609,-261612,-261615,-261618,-261622,-261625,-261628,-261631,-261634,-261637,-261640,-261643,-261647,-261650,-261653,-261656,-261659,-261662,-261665,-261668,-261671,-261674,-261677,-261680,-261683,-261686,-261689,-261692,-261695,-261698,-261701,-261704,-261707,-261709,-261712,-261715,-261718,-261721,-261724,-261727,-261729,-261732,-261735,-261738,-261741,-261743,-261746,-261749,-261752,-261754,-261757,-261760,-261763,-261765,-261768,-261771,-261773,-261776,-261779,-261781,-261784,-261787,-261789,-261792,-261794,-261797,-261800,-261802,-261805,-261807,-261810,-261812,-261815,-261817,-261820,-261822,-261825,-261827,-261830,-261832,-261835,-261837,-261839,-261842,-261844,-261847,-261849,-261851,-261854,-261856,-261858,-261861,-261863,-261865,-261868,-261870,-261872,-261875,-261877,-261879,-261881,-261884,-261886,-261888,-261890,-261893,-261895,-261897,-261899,-261901,-261903,-261906,-261908,-261910,-261912,-261914,-261916,-261918,-261920,-261922,-261924,-261926,-261928,-261931,-261933,-261935,-261937,-261939,-261941,-261942,-261944,-261946,-261948,-261950,-261952,-261954,-261956,-261958,-261960,-261962,-261964,-261965,-261967,-261969,-261971,-261973,-261974,-261976,-261978,-261980,-261982,-261983,-261985,-261987,-261989,-261990,-261992,-261994,-261995,-261997,-261999,-262000,-262002,-262004,-262005,-262007,-262009,-262010,-262012,-262013,-262015,-262017,-262018,-262020,-262021,-262023,-262024,-262026,-262027,-262029,-262030,-262032,-262033,-262035,-262036,-262037,-262039,-262040,-262042,-262043,-262044,-262046,-262047,-262049,-262050,-262051,-262053,-262054,-262055,-262056,-262058,-262059,-262060,-262062,-262063,-262064,-262065,-262066,-262068,-262069,-262070,-262071,-262072,-262074,-262075,-262076,-262077,-262078,-262079,-262080,-262081,-262083,-262084,-262085,-262086,-262087,-262088,-262089,-262090,-262091,-262092,-262093,-262094,-262095,-262096,-262097,-262098,-262099,-262100,-262100,-262101,-262102,-262103,-262104,-262105,-262106,-262107,-262107,-262108,-262109,-262110,-262111,-262111,-262112,-262113,-262114,-262114,-262115,-262116,-262117,-262117,-262118,-262119,-262119,-262120,-262121,-262121,-262122,-262123,-262123,-262124,-262124,-262125,-262126,-262126,-262127,-262127,-262128,-262128,-262129,-262129,-262130,-262130,-262131,-262131,-262132,-262132,-262133,-262133,-262134,-262134,-262134,-262135,-262135,-262136,-262136,-262136,-262137,-262137,-262137,-262138,-262138,-262138,-262139,-262139,-262139,-262139,-262140,-262140,-262140,-262140,-262141,-262141,-262141,-262141,-262141,-262142,-262142,-262142,-262142,-262142,-262142,-262142,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262143,-262142,-262142,-262142,-262142,-262142,-262142,-262142,-262141,-262141,-262141,-262141,-262141,-262140,-262140,-262140,-262140,-262139,-262139,-262139,-262139,-262138,-262138,-262138,-262137,-262137,-262137,-262136,-262136,-262136,-262135,-262135,-262134,-262134,-262134,-262133,-262133,-262132,-262132,-262131,-262131,-262130,-262130,-262129,-262129,-262128,-262128,-262127,-262127,-262126,-262126,-262125,-262124,-262124,-262123,-262123,-262122,-262121,-262121,-262120,-262119,-262119,-262118,-262117,-262117,-262116,-262115,-262114,-262114,-262113,-262112,-262111,-262111,-262110,-262109,-262108,-262107,-262107,-262106,-262105,-262104,-262103,-262102,-262101,-262100,-262100,-262099,-262098,-262097,-262096,-262095,-262094,-262093,-262092,-262091,-262090,-262089,-262088,-262087,-262086,-262085,-262084,-262083,-262081,-262080,-262079,-262078,-262077,-262076,-262075,-262074,-262072,-262071,-262070,-262069,-262068,-262066,-262065,-262064,-262063,-262062,-262060,-262059,-262058,-262056,-262055,-262054,-262053,-262051,-262050,-262049,-262047,-262046,-262044,-262043,-262042,-262040,-262039,-262037,-262036,-262035,-262033,-262032,-262030,-262029,-262027,-262026,-262024,-262023,-262021,-262020,-262018,-262017,-262015,-262013,-262012,-262010,-262009,-262007,-262005,-262004,-262002,-262000,-261999,-261997,-261995,-261994,-261992,-261990,-261989,-261987,-261985,-261983,-261982,-261980,-261978,-261976,-261974,-261973,-261971,-261969,-261967,-261965,-261964,-261962,-261960,-261958,-261956,-261954,-261952,-261950,-261948,-261946,-261944,-261942,-261941,-261939,-261937,-261935,-261933,-261931,-261928,-261926,-261924,-261922,-261920,-261918,-261916,-261914,-261912,-261910,-261908,-261906,-261903,-261901,-261899,-261897,-261895,-261893,-261890,-261888,-261886,-261884,-261881,-261879,-261877,-261875,-261872,-261870,-261868,-261865,-261863,-261861,-261858,-261856,-261854,-261851,-261849,-261847,-261844,-261842,-261839,-261837,-261835,-261832,-261830,-261827,-261825,-261822,-261820,-261817,-261815,-261812,-261810,-261807,-261805,-261802,-261800,-261797,-261794,-261792,-261789,-261787,-261784,-261781,-261779,-261776,-261773,-261771,-261768,-261765,-261763,-261760,-261757,-261754,-261752,-261749,-261746,-261743,-261741,-261738,-261735,-261732,-261729,-261727,-261724,-261721,-261718,-261715,-261712,-261709,-261707,-261704,-261701,-261698,-261695,-261692,-261689,-261686,-261683,-261680,-261677,-261674,-261671,-261668,-261665,-261662,-261659,-261656,-261653,-261650,-261647,-261643,-261640,-261637,-261634,-261631,-261628,-261625,-261622,-261618,-261615,-261612,-261609,-261606,-261602,-261599,-261596,-261593,-261589,-261586,-261583,-261580,-261576,-261573,-261570,-261566,-261563,-261560,-261556,-261553,-261550,-261546,-261543,-261539,-261536,-261532,-261529,-261526,-261522,-261519,-261515,-261512,-261508,-261505,-261501,-261498,-261494,-261491,-261487,-261484,-261480,-261476,-261473,-261469,-261466,-261462,-261458,-261455,-261451,-261447,-261444,-261440,-261436,-261433,-261429,-261425,-261422,-261418,-261414,-261410,-261407,-261403,-261399,-261395,-261391,-261388,-261384,-261380,-261376,-261372,-261368,-261365,-261361,-261357,-261353,-261349,-261345,-261341,-261337,-261333,-261329,-261325,-261321,-261317,-261313,-261309,-261305,-261301,-261297,-261293,-261289,-261285,-261281,-261277,-261273,-261269,-261265,-261261,-261257,-261252,-261248,-261244,-261240,-261236,-261232,-261227,-261223,-261219,-261215,-261211,-261206,-261202,-261198,-261194,-261189,-261185,-261181,-261176,-261172,-261168,-261163,-261159,-261155,-261150,-261146,-261142,-261137,-261133,-261128,-261124,-261119,-261115,-261111,-261106,-261102,-261097,-261093,-261088,-261084,-261079,-261075,-261070,-261066,-261061,-261056,-261052,-261047,-261043,-261038,-261033,-261029,-261024,-261020,-261015,-261010,-261006,-261001,-260996,-260991,-260987,-260982,-260977,-260973,-260968,-260963,-260958,-260954,-260949,-260944,-260939,-260934,-260929,-260925,-260920,-260915,-260910,-260905,-260900,-260895,-260891,-260886,-260881,-260876,-260871,-260866,-260861,-260856,-260851,-260846,-260841,-260836,-260831,-260826,-260821,-260816,-260811,-260806,-260801,-260796,-260790,-260785,-260780,-260775,-260770,-260765,-260760,-260755,-260749,-260744,-260739,-260734,-260729,-260723,-260718,-260713,-260708,-260702,-260697,-260692,-260687,-260681,-260676,-260671,-260665,-260660,-260655,-260649,-260644,-260639,-260633,-260628,-260622,-260617,-260612,-260606,-260601,-260595,-260590,-260584,-260579,-260573,-260568,-260562,-260557,-260551,-260546,-260540,-260535,-260529,-260524,-260518,-260512,-260507,-260501,-260495,-260490,-260484,-260479,-260473,-260467,-260462,-260456,-260450,-260444,-260439,-260433,-260427,-260422,-260416,-260410,-260404,-260398,-260393,-260387,-260381,-260375,-260369,-260364,-260358,-260352,-260346,-260340,-260334,-260328,-260322,-260316,-260311,-260305,-260299,-260293,-260287,-260281,-260275,-260269,-260263,-260257,-260251,-260245,-260239,-260233,-260227,-260220,-260214,-260208,-260202,-260196,-260190,-260184,-260178,-260172,-260165,-260159,-260153,-260147,-260141,-260134,-260128,-260122,-260116,-260110,-260103,-260097,-260091,-260084,-260078,-260072,-260066,-260059,-260053,-260047,-260040,-260034,-260028,-260021,-260015,-260008,-260002,-259996,-259989,-259983,-259976,-259970,-259963,-259957,-259950,-259944,-259937,-259931,-259924,-259918,-259911,-259905,-259898,-259892,-259885,-259878,-259872,-259865,-259859,-259852,-259845,-259839,-259832,-259825,-259819,-259812,-259805,-259799,-259792,-259785,-259778,-259772,-259765,-259758,-259751,-259745,-259738,-259731,-259724,-259717,-259711,-259704,-259697,-259690,-259683,-259676,-259669,-259663,-259656,-259649,-259642,-259635,-259628,-259621,-259614,-259607,-259600,-259593,-259586,-259579,-259572,-259565,-259558,-259551,-259544,-259537,-259530,-259523,-259516,-259508,-259501,-259494,-259487,-259480,-259473,-259466,-259458,-259451,-259444,-259437,-259430,-259422,-259415,-259408,-259401,-259394,-259386,-259379,-259372,-259364,-259357,-259350,-259342,-259335,-259328,-259320,-259313,-259306,-259298,-259291,-259284,-259276,-259269,-259261,-259254,-259246,-259239,-259231,-259224,-259216,-259209,-259201,-259194,-259186,-259179,-259171,-259164,-259156,-259149,-259141,-259134,-259126,-259118,-259111,-259103,-259095,-259088,-259080,-259072,-259065,-259057,-259049,-259042,-259034,-259026,-259019,-259011,-259003,-258995,-258988,-258980,-258972,-258964,-258956,-258949,-258941,-258933,-258925,-258917,-258909,-258901,-258894,-258886,-258878,-258870,-258862,-258854,-258846,-258838,-258830,-258822,-258814,-258806,-258798,-258790,-258782,-258774,-258766,-258758,-258750,-258742,-258734,-258726,-258718,-258710,-258701,-258693,-258685,-258677,-258669,-258661,-258653,-258644,-258636,-258628,-258620,-258612,-258603,-258595,-258587,-258579,-258570,-258562,-258554,-258545,-258537,-258529,-258521,-258512,-258504,-258495,-258487,-258479,-258470,-258462,-258454,-258445,-258437,-258428,-258420,-258411,-258403,-258395,-258386,-258378,-258369,-258361,-258352,-258344,-258335,-258326,-258318,-258309,-258301,-258292,-258284,-258275,-258266,-258258,-258249,-258241,-258232,-258223,-258215,-258206,-258197,-258189,-258180,-258171,-258162,-258154,-258145,-258136,-258127,-258119,-258110,-258101,-258092,-258083,-258075,-258066,-258057,-258048,-258039,-258030,-258022,-258013,-258004,-257995,-257986,-257977,-257968,-257959,-257950,-257941,-257932,-257923,-257914,-257905,-257896,-257887,-257878,-257869,-257860,-257851,-257842,-257833,-257824,-257815,-257806,-257797,-257788,-257778,-257769,-257760,-257751,-257742,-257733,-257723,-257714,-257705,-257696,-257687,-257677,-257668,-257659,-257650,-257640,-257631,-257622,-257612,-257603,-257594,-257584,-257575,-257566,-257556,-257547,-257538,-257528,-257519,-257509,-257500,-257491,-257481,-257472,-257462,-257453,-257443,-257434,-257424,-257415,-257405,-257396,-257386,-257377,-257367,-257358,-257348,-257339,-257329,-257319,-257310,-257300,-257291,-257281,-257271,-257262,-257252,-257242,-257233,-257223,-257213,-257204,-257194,-257184,-257174,-257165,-257155,-257145,-257135,-257126,-257116,-257106,-257096,-257086,-257077,-257067,-257057,-257047,-257037,-257027,-257017,-257007,-256998,-256988,-256978,-256968,-256958,-256948,-256938,-256928,-256918,-256908,-256898,-256888,-256878,-256868,-256858,-256848,-256838,-256828,-256818,-256808,-256797,-256787,-256777,-256767,-256757,-256747,-256737,-256727,-256716,-256706,-256696,-256686,-256676,-256665,-256655,-256645,-256635,-256624,-256614,-256604,-256594,-256583,-256573,-256563,-256552,-256542,-256532,-256521,-256511,-256501,-256490,-256480,-256469,-256459,-256449,-256438,-256428,-256417,-256407,-256396,-256386,-256375,-256365,-256354,-256344,-256333,-256323,-256312,-256302,-256291,-256281,-256270,-256260,-256249,-256238,-256228,-256217,-256206,-256196,-256185,-256175,-256164,-256153,-256142,-256132,-256121,-256110,-256100,-256089,-256078,-256067,-256057,-256046,-256035,-256024,-256013,-256003,-255992,-255981,-255970,-255959,-255948,-255938,-255927,-255916,-255905,-255894,-255883,-255872,-255861,-255850,-255839,-255828,-255817,-255806,-255795,-255784,-255773,-255762,-255751,-255740,-255729,-255718,-255707,-255696,-255685,-255674,-255663,-255652,-255641,-255629,-255618,-255607,-255596,-255585,-255574,-255563,-255551,-255540,-255529,-255518,-255506,-255495,-255484,-255473,-255461,-255450,-255439,-255428,-255416,-255405,-255394,-255382,-255371,-255360,-255348,-255337,-255325,-255314,-255303,-255291,-255280,-255268,-255257,-255245,-255234,-255223,-255211,-255200,-255188,-255177,-255165,-255154,-255142,-255130,-255119,-255107,-255096,-255084,-255073,-255061,-255049,-255038,-255026,-255014,-255003,-254991,-254980,-254968,-254956,-254944,-254933,-254921,-254909,-254898,-254886,-254874,-254862,-254851,-254839,-254827,-254815,-254803,-254792,-254780,-254768,-254756,-254744,-254732,-254720,-254709,-254697,-254685,-254673,-254661,-254649,-254637,-254625,-254613,-254601,-254589,-254577,-254565,-254553,-254541,-254529,-254517,-254505,-254493,-254481,-254469,-254457,-254445,-254433,-254421,-254409,-254396,-254384,-254372,-254360,-254348,-254336,-254323,-254311,-254299,-254287,-254275,-254262,-254250,-254238,-254226,-254213,-254201,-254189,-254177,-254164,-254152,-254140,-254127,-254115,-254103,-254090,-254078,-254066,-254053,-254041,-254028,-254016,-254003,-253991,-253979,-253966,-253954,-253941,-253929,-253916,-253904,-253891,-253879,-253866,-253854,-253841,-253829,-253816,-253803,-253791,-253778,-253766,-253753,-253740,-253728,-253715,-253703,-253690,-253677,-253665,-253652,-253639,-253626,-253614,-253601,-253588,-253576,-253563,-253550,-253537,-253524,-253512,-253499,-253486,-253473,-253460,-253448,-253435,-253422,-253409,-253396,-253383,-253370,-253358,-253345,-253332,-253319,-253306,-253293,-253280,-253267,-253254,-253241,-253228,-253215,-253202,-253189,-253176,-253163,-253150,-253137,-253124,-253111,-253098,-253084,-253071,-253058,-253045,-253032,-253019,-253006,-252993,-252979,-252966,-252953,-252940,-252927,-252913,-252900,-252887,-252874,-252860,-252847,-252834,-252821,-252807,-252794,-252781,-252767,-252754,-252741,-252727,-252714,-252701,-252687,-252674,-252661,-252647,-252634,-252620,-252607,-252593,-252580,-252567,-252553,-252540,-252526,-252513,-252499,-252486,-252472,-252459,-252445,-252431,-252418,-252404,-252391,-252377,-252364,-252350,-252336,-252323,-252309,-252295,-252282,-252268,-252254,-252241,-252227,-252213,-252200,-252186,-252172,-252158,-252145,-252131,-252117,-252103,-252090,-252076,-252062,-252048,-252034,-252021,-252007,-251993,-251979,-251965,-251951,-251937,-251924,-251910,-251896,-251882,-251868,-251854,-251840,-251826,-251812,-251798,-251784,-251770,-251756,-251742,-251728,-251714,-251700,-251686,-251672,-251658,-251644,-251630,-251616,-251601,-251587,-251573,-251559,-251545,-251531,-251517,-251502,-251488,-251474,-251460,-251446,-251431,-251417,-251403,-251389,-251374,-251360,-251346,-251332,-251317,-251303,-251289,-251274,-251260,-251246,-251231,-251217,-251203,-251188,-251174,-251160,-251145,-251131,-251116,-251102,-251087,-251073,-251059,-251044,-251030,-251015,-251001,-250986,-250972,-250957,-250943,-250928,-250913,-250899,-250884,-250870,-250855,-250841,-250826,-250811,-250797,-250782,-250767,-250753,-250738,-250723,-250709,-250694,-250679,-250665,-250650,-250635,-250621,-250606,-250591,-250576,-250561,-250547,-250532,-250517,-250502,-250488,-250473,-250458,-250443,-250428,-250413,-250398,-250384,-250369,-250354,-250339,-250324,-250309,-250294,-250279,-250264,-250249,-250234,-250219,-250204,-250189,-250174,-250159,-250144,-250129,-250114,-250099,-250084,-250069,-250054,-250039,-250024,-250008,-249993,-249978,-249963,-249948,-249933,-249918,-249902,-249887,-249872,-249857,-249842,-249826,-249811,-249796,-249781,-249765,-249750,-249735,-249720,-249704,-249689,-249674,-249658,-249643,-249628,-249612,-249597,-249582,-249566,-249551,-249535,-249520,-249505,-249489,-249474,-249458,-249443,-249427,-249412,-249397,-249381,-249366,-249350,-249334,-249319,-249303,-249288,-249272,-249257,-249241,-249226,-249210,-249194,-249179,-249163,-249148,-249132,-249116,-249101,-249085,-249069,-249054,-249038,-249022,-249007,-248991,-248975,-248959,-248944,-248928,-248912,-248896,-248881,-248865,-248849,-248833,-248817,-248802,-248786,-248770,-248754,-248738,-248722,-248706,-248690,-248675,-248659,-248643,-248627,-248611,-248595,-248579,-248563,-248547,-248531,-248515,-248499,-248483,-248467,-248451,-248435,-248419,-248403,-248387,-248371,-248355,-248339,-248322,-248306,-248290,-248274,-248258,-248242,-248226,-248210,-248193,-248177,-248161,-248145,-248129,-248112,-248096,-248080,-248064,-248047,-248031,-248015,-247999,-247982,-247966,-247950,-247933,-247917,-247901,-247884,-247868,-247852,-247835,-247819,-247802,-247786,-247770,-247753,-247737,-247720,-247704,-247687,-247671,-247654,-247638,-247621,-247605,-247588,-247572,-247555,-247539,-247522,-247506,-247489,-247473,-247456,-247439,-247423,-247406,-247390,-247373,-247356,-247340,-247323,-247306,-247290,-247273,-247256,-247240,-247223,-247206,-247189,-247173,-247156,-247139,-247122,-247106,-247089,-247072,-247055,-247039,-247022,-247005,-246988,-246971,-246954,-246937,-246921,-246904,-246887,-246870,-246853,-246836,-246819,-246802,-246785,-246768,-246751,-246734,-246717,-246700,-246683,-246666,-246649,-246632,-246615,-246598,-246581,-246564,-246547,-246530,-246513,-246496,-246479,-246462,-246444,-246427,-246410,-246393,-246376,-246359,-246341,-246324,-246307,-246290,-246273,-246255,-246238,-246221,-246204,-246186,-246169,-246152,-246135,-246117,-246100,-246083,-246065,-246048,-246031,-246013,-245996,-245978,-245961,-245944,-245926,-245909,-245891,-245874,-245857,-245839,-245822,-245804,-245787,-245769,-245752,-245734,-245717,-245699,-245682,-245664,-245647,-245629,-245612,-245594,-245576,-245559,-245541,-245524,-245506,-245488,-245471,-245453,-245435,-245418,-245400,-245382,-245365,-245347,-245329,-245312,-245294,-245276,-245258,-245241,-245223,-245205,-245187,-245170,-245152,-245134,-245116,-245098,-245080,-245063,-245045,-245027,-245009,-244991,-244973,-244955,-244937,-244920,-244902,-244884,-244866,-244848,-244830,-244812,-244794,-244776,-244758,-244740,-244722,-244704,-244686,-244668,-244650,-244632,-244614,-244596,-244577,-244559,-244541,-244523,-244505,-244487,-244469,-244451,-244432,-244414,-244396,-244378,-244360,-244342,-244323,-244305,-244287,-244269,-244250,-244232,-244214,-244196,-244177,-244159,-244141,-244122,-244104,-244086,-244067,-244049,-244031,-244012,-243994,-243976,-243957,-243939,-243920,-243902,-243884,-243865,-243847,-243828,-243810,-243791,-243773,-243754,-243736,-243717,-243699,-243680,-243662,-243643,-243625,-243606,-243587,-243569,-243550,-243532,-243513,-243495,-243476,-243457,-243439,-243420,-243401,-243383,-243364,-243345,-243327,-243308,-243289,-243270,-243252,-243233,-243214,-243195,-243177,-243158,-243139,-243120,-243102,-243083,-243064,-243045,-243026,-243007,-242989,-242970,-242951,-242932,-242913,-242894,-242875,-242856,-242837,-242818,-242799,-242781,-242762,-242743,-242724,-242705,-242686,-242667,-242648,-242629,-242610,-242590,-242571,-242552,-242533,-242514,-242495,-242476,-242457,-242438,-242419,-242400,-242380,-242361,-242342,-242323,-242304,-242285,-242265,-242246,-242227,-242208,-242188,-242169,-242150,-242131,-242111,-242092,-242073,-242054,-242034,-242015,-241996,-241976,-241957,-241938,-241918,-241899,-241880,-241860,-241841,-241821,-241802,-241783,-241763,-241744,-241724,-241705,-241685,-241666,-241646,-241627,-241607,-241588,-241568,-241549,-241529,-241510,-241490,-241471,-241451,-241432,-241412,-241392,-241373,-241353,-241333,-241314,-241294,-241275,-241255,-241235,-241216,-241196,-241176,-241156,-241137,-241117,-241097,-241078,-241058,-241038,-241018,-240999,-240979,-240959,-240939,-240919,-240900,-240880,-240860,-240840,-240820,-240800,-240780,-240761,-240741,-240721,-240701,-240681,-240661,-240641,-240621,-240601,-240581,-240561,-240541,-240521,-240501,-240481,-240461,-240441,-240421,-240401,-240381,-240361,-240341,-240321,-240301,-240281,-240261,-240241,-240220,-240200,-240180,-240160,-240140,-240120,-240100,-240079,-240059,-240039,-240019,-239999,-239978,-239958,-239938,-239918,-239897,-239877,-239857,-239837,-239816,-239796,-239776,-239755,-239735,-239715,-239694,-239674,-239654,-239633,-239613,-239592,-239572,-239552,-239531,-239511,-239490,-239470,-239449,-239429,-239409,-239388,-239368,-239347,-239327,-239306,-239286,-239265,-239244,-239224,-239203,-239183,-239162,-239142,-239121,-239100,-239080,-239059,-239039,-239018,-238997,-238977,-238956,-238935,-238915,-238894,-238873,-238852,-238832,-238811,-238790,-238770,-238749,-238728,-238707,-238687,-238666,-238645,-238624,-238603,-238582,-238562,-238541,-238520,-238499,-238478,-238457,-238436,-238416,-238395,-238374,-238353,-238332,-238311,-238290,-238269,-238248,-238227,-238206,-238185,-238164,-238143,-238122,-238101,-238080,-238059,-238038,-238017,-237996,-237975,-237954,-237933,-237912,-237890,-237869,-237848,-237827,-237806,-237785,-237764,-237742,-237721,-237700,-237679,-237658,-237636,-237615,-237594,-237573,-237551,-237530,-237509,-237488,-237466,-237445,-237424,-237402,-237381,-237360,-237338,-237317,-237296,-237274,-237253,-237232,-237210,-237189,-237167,-237146,-237125,-237103,-237082,-237060,-237039,-237017,-236996,-236974,-236953,-236931,-236910,-236888,-236867,-236845,-236824,-236802,-236781,-236759,-236737,-236716,-236694,-236673,-236651,-236629,-236608,-236586,-236564,-236543,-236521,-236499,-236478,-236456,-236434,-236413,-236391,-236369,-236347,-236326,-236304,-236282,-236260,-236239,-236217,-236195,-236173,-236151,-236130,-236108,-236086,-236064,-236042,-236020,-235998,-235977,-235955,-235933,-235911,-235889,-235867,-235845,-235823,-235801,-235779,-235757,-235735,-235713,-235691,-235669,-235647,-235625,-235603,-235581,-235559,-235537,-235515,-235493,-235471,-235449,-235427,-235404,-235382,-235360,-235338,-235316,-235294,-235272,-235249,-235227,-235205,-235183,-235161,-235138,-235116,-235094,-235072,-235049,-235027,-235005,-234983,-234960,-234938,-234916,-234893,-234871,-234849,-234827,-234804,-234782,-234759,-234737,-234715,-234692,-234670,-234648,-234625,-234603,-234580,-234558,-234535,-234513,-234490,-234468,-234445,-234423,-234400,-234378,-234355,-234333,-234310,-234288,-234265,-234243,-234220,-234198,-234175,-234152,-234130,-234107,-234085,-234062,-234039,-234017,-233994,-233971,-233949,-233926,-233903,-233881,-233858,-233835,-233812,-233790,-233767,-233744,-233721,-233699,-233676,-233653,-233630,-233608,-233585,-233562,-233539,-233516,-233493,-233471,-233448,-233425,-233402,-233379,-233356,-233333,-233310,-233287,-233264,-233242,-233219,-233196,-233173,-233150,-233127,-233104,-233081,-233058,-233035,-233012,-232989,-232966,-232943,-232919,-232896,-232873,-232850,-232827,-232804,-232781,-232758,-232735,-232712,-232688,-232665,-232642,-232619,-232596,-232573,-232549,-232526,-232503,-232480,-232456,-232433,-232410,-232387,-232363,-232340,-232317,-232294,-232270,-232247,-232224,-232200,-232177,-232154,-232130,-232107,-232084,-232060,-232037,-232013,-231990,-231967,-231943,-231920,-231896,-231873,-231849,-231826,-231803,-231779,-231756,-231732,-231709,-231685,-231662,-231638,-231614,-231591,-231567,-231544,-231520,-231497,-231473,-231449,-231426,-231402,-231379,-231355,-231331,-231308,-231284,-231260,-231237,-231213,-231189,-231166,-231142,-231118,-231095,-231071,-231047,-231023,-231000,-230976,-230952,-230928,-230904,-230881,-230857,-230833,-230809,-230785,-230761,-230738,-230714,-230690,-230666,-230642,-230618,-230594,-230570,-230547,-230523,-230499,-230475,-230451,-230427,-230403,-230379,-230355,-230331,-230307,-230283,-230259,-230235,-230211,-230187,-230163,-230139,-230115,-230090,-230066,-230042,-230018,-229994,-229970,-229946,-229922,-229897,-229873,-229849,-229825,-229801,-229777,-229752,-229728,-229704,-229680,-229656,-229631,-229607,-229583,-229559,-229534,-229510,-229486,-229461,-229437,-229413,-229388,-229364,-229340,-229315,-229291,-229267,-229242,-229218,-229193,-229169,-229145,-229120,-229096,-229071,-229047,-229023,-228998,-228974,-228949,-228925,-228900,-228876,-228851,-228827,-228802,-228778,-228753,-228728,-228704,-228679,-228655,-228630,-228606,-228581,-228556,-228532,-228507,-228482,-228458,-228433,-228408,-228384,-228359,-228334,-228310,-228285,-228260,-228236,-228211,-228186,-228161,-228137,-228112,-228087,-228062,-228038,-228013,-227988,-227963,-227938,-227913,-227889,-227864,-227839,-227814,-227789,-227764,-227739,-227715,-227690,-227665,-227640,-227615,-227590,-227565,-227540,-227515,-227490,-227465,-227440,-227415,-227390,-227365,-227340,-227315,-227290,-227265,-227240,-227215,-227190,-227165,-227140,-227114,-227089,-227064,-227039,-227014,-226989,-226964,-226939,-226913,-226888,-226863,-226838,-226813,-226787,-226762,-226737,-226712,-226687,-226661,-226636,-226611,-226585,-226560,-226535,-226510,-226484,-226459,-226434,-226408,-226383,-226358,-226332,-226307,-226282,-226256,-226231,-226205,-226180,-226155,-226129,-226104,-226078,-226053,-226027,-226002,-225976,-225951,-225925,-225900,-225874,-225849,-225823,-225798,-225772,-225747,-225721,-225696,-225670,-225645,-225619,-225593,-225568,-225542,-225516,-225491,-225465,-225440,-225414,-225388,-225363,-225337,-225311,-225286,-225260,-225234,-225208,-225183,-225157,-225131,-225105,-225080,-225054,-225028,-225002,-224977,-224951,-224925,-224899,-224873,-224847,-224822,-224796,-224770,-224744,-224718,-224692,-224666,-224640,-224614,-224589,-224563,-224537,-224511,-224485,-224459,-224433,-224407,-224381,-224355,-224329,-224303,-224277,-224251,-224225,-224199,-224173,-224147,-224121,-224095,-224068,-224042,-224016,-223990,-223964,-223938,-223912,-223886,-223859,-223833,-223807,-223781,-223755,-223729,-223702,-223676,-223650,-223624,-223598,-223571,-223545,-223519,-223492,-223466,-223440,-223414,-223387,-223361,-223335,-223308,-223282,-223256,-223229,-223203,-223177,-223150,-223124,-223098,-223071,-223045,-223018,-222992,-222965,-222939,-222913,-222886,-222860,-222833,-222807,-222780,-222754,-222727,-222701,-222674,-222648,-222621,-222595,-222568,-222541,-222515,-222488,-222462,-222435,-222409,-222382,-222355,-222329,-222302,-222275,-222249,-222222,-222195,-222169,-222142,-222115,-222089,-222062,-222035,-222009,-221982,-221955,-221928,-221902,-221875,-221848,-221821,-221794,-221768,-221741,-221714,-221687,-221660,-221633,-221607,-221580,-221553,-221526,-221499,-221472,-221445,-221418,-221392,-221365,-221338,-221311,-221284,-221257,-221230,-221203,-221176,-221149,-221122,-221095,-221068,-221041,-221014,-220987,-220960,-220933,-220906,-220879,-220852,-220825,-220797,-220770,-220743,-220716,-220689,-220662,-220635,-220608,-220580,-220553,-220526,-220499,-220472,-220445,-220417,-220390,-220363,-220336,-220308,-220281,-220254,-220227,-220199,-220172,-220145,-220118,-220090,-220063,-220036,-220008,-219981,-219954,-219926,-219899,-219872,-219844,-219817,-219789,-219762,-219735,-219707,-219680,-219652,-219625,-219597,-219570,-219543,-219515,-219488,-219460,-219433,-219405,-219378,-219350,-219323,-219295,-219267,-219240,-219212,-219185,-219157,-219130,-219102,-219074,-219047,-219019,-218992,-218964,-218936,-218909,-218881,-218853,-218826,-218798,-218770,-218743,-218715,-218687,-218659,-218632,-218604,-218576,-218548,-218521,-218493,-218465,-218437,-218410,-218382,-218354,-218326,-218298,-218270,-218243,-218215,-218187,-218159,-218131,-218103,-218075,-218048,-218020,-217992,-217964,-217936,-217908,-217880,-217852,-217824,-217796,-217768,-217740,-217712,-217684,-217656,-217628,-217600,-217572,-217544,-217516,-217488,-217460,-217432,-217404,-217376,-217347,-217319,-217291,-217263,-217235,-217207,-217179,-217151,-217122,-217094,-217066,-217038,-217010,-216981,-216953,-216925,-216897,-216869,-216840,-216812,-216784,-216756,-216727,-216699,-216671,-216642,-216614,-216586,-216557,-216529,-216501,-216472,-216444,-216416,-216387,-216359,-216331,-216302,-216274,-216245,-216217,-216189,-216160,-216132,-216103,-216075,-216046,-216018,-215989,-215961,-215932,-215904,-215875,-215847,-215818,-215790,-215761,-215733,-215704,-215676,-215647,-215618,-215590,-215561,-215533,-215504,-215475,-215447,-215418,-215389,-215361,-215332,-215303,-215275,-215246,-215217,-215189,-215160,-215131,-215103,-215074,-215045,-215016,-214988,-214959,-214930,-214901,-214872,-214844,-214815,-214786,-214757,-214728,-214700,-214671,-214642,-214613,-214584,-214555,-214526,-214497,-214469,-214440,-214411,-214382,-214353,-214324,-214295,-214266,-214237,-214208,-214179,-214150,-214121,-214092,-214063,-214034,-214005,-213976,-213947,-213918,-213889,-213860,-213831,-213802,-213773,-213744,-213714,-213685,-213656,-213627,-213598,-213569,-213540,-213510,-213481,-213452,-213423,-213394,-213365,-213335,-213306,-213277,-213248,-213218,-213189,-213160,-213131,-213101,-213072,-213043,-213014,-212984,-212955,-212926,-212896,-212867,-212838,-212808,-212779,-212750,-212720,-212691,-212661,-212632,-212603,-212573,-212544,-212514,-212485,-212455,-212426,-212397,-212367,-212338,-212308,-212279,-212249,-212220,-212190,-212161,-212131,-212102,-212072,-212042,-212013,-211983,-211954,-211924,-211895,-211865,-211835,-211806,-211776,-211747,-211717,-211687,-211658,-211628,-211598,-211569,-211539,-211509,-211480,-211450,-211420,-211390,-211361,-211331,-211301,-211271,-211242,-211212,-211182,-211152,-211123,-211093,-211063,-211033,-211003,-210973,-210944,-210914,-210884,-210854,-210824,-210794,-210764,-210735,-210705,-210675,-210645,-210615,-210585,-210555,-210525,-210495,-210465,-210435,-210405,-210375,-210345,-210315,-210285,-210255,-210225,-210195,-210165,-210135,-210105,-210075,-210045,-210015,-209985,-209955,-209925,-209894,-209864,-209834,-209804,-209774,-209744,-209714,-209683,-209653,-209623,-209593,-209563,-209533,-209502,-209472,-209442,-209412,-209381,-209351,-209321,-209291,-209260,-209230,-209200,-209169,-209139,-209109,-209079,-209048,-209018,-208988,-208957,-208927,-208896,-208866,-208836,-208805,-208775,-208745,-208714,-208684,-208653,-208623,-208592,-208562,-208532,-208501,-208471,-208440,-208410,-208379,-208349,-208318,-208288,-208257,-208227,-208196,-208165,-208135,-208104,-208074,-208043,-208013,-207982,-207951,-207921,-207890,-207860,-207829,-207798,-207768,-207737,-207706,-207676,-207645,-207614,-207584,-207553,-207522,-207491,-207461,-207430,-207399,-207369,-207338,-207307,-207276,-207245,-207215,-207184,-207153,-207122,-207091,-207061,-207030,-206999,-206968,-206937,-206906,-206876,-206845,-206814,-206783,-206752,-206721,-206690,-206659,-206628,-206597,-206566,-206536,-206505,-206474,-206443,-206412,-206381,-206350,-206319,-206288,-206257,-206226,-206195,-206164,-206132,-206101,-206070,-206039,-206008,-205977,-205946,-205915,-205884,-205853,-205822,-205790,-205759,-205728,-205697,-205666,-205635,-205603,-205572,-205541,-205510,-205479,-205447,-205416,-205385,-205354,-205323,-205291,-205260,-205229,-205197,-205166,-205135,-205104,-205072,-205041,-205010,-204978,-204947,-204916,-204884,-204853,-204822,-204790,-204759,-204727,-204696,-204665,-204633,-204602,-204570,-204539,-204507,-204476,-204445,-204413,-204382,-204350,-204319,-204287,-204256,-204224,-204193,-204161,-204130,-204098,-204066,-204035,-204003,-203972,-203940,-203909,-203877,-203845,-203814,-203782,-203751,-203719,-203687,-203656,-203624,-203592,-203561,-203529,-203497,-203466,-203434,-203402,-203371,-203339,-203307,-203275,-203244,-203212,-203180,-203148,-203117,-203085,-203053,-203021,-202989,-202958,-202926,-202894,-202862,-202830,-202798,-202767,-202735,-202703,-202671,-202639,-202607,-202575,-202543,-202511,-202480,-202448,-202416,-202384,-202352,-202320,-202288,-202256,-202224,-202192,-202160,-202128,-202096,-202064,-202032,-202000,-201968,-201936,-201904,-201872,-201840,-201807,-201775,-201743,-201711,-201679,-201647,-201615,-201583,-201551,-201518,-201486,-201454,-201422,-201390,-201358,-201325,-201293,-201261,-201229,-201197,-201164,-201132,-201100,-201068,-201035,-201003,-200971,-200939,-200906,-200874,-200842,-200809,-200777,-200745,-200712,-200680,-200648,-200615,-200583,-200551,-200518,-200486,-200453,-200421,-200389,-200356,-200324,-200291,-200259,-200227,-200194,-200162,-200129,-200097,-200064,-200032,-199999,-199967,-199934,-199902,-199869,-199837,-199804,-199772,-199739,-199707,-199674,-199641,-199609,-199576,-199544,-199511,-199478,-199446,-199413,-199381,-199348,-199315,-199283,-199250,-199217,-199185,-199152,-199119,-199087,-199054,-199021,-198988,-198956,-198923,-198890,-198857,-198825,-198792,-198759,-198726,-198694,-198661,-198628,-198595,-198562,-198530,-198497,-198464,-198431,-198398,-198365,-198333,-198300,-198267,-198234,-198201,-198168,-198135,-198102,-198069,-198036,-198003,-197971,-197938,-197905,-197872,-197839,-197806,-197773,-197740,-197707,-197674,-197641,-197608,-197575,-197542,-197509,-197475,-197442,-197409,-197376,-197343,-197310,-197277,-197244,-197211,-197178,-197145,-197111,-197078,-197045,-197012,-196979,-196946,-196912,-196879,-196846,-196813,-196780,-196746,-196713,-196680,-196647,-196614,-196580,-196547,-196514,-196480,-196447,-196414,-196381,-196347,-196314,-196281,-196247,-196214,-196181,-196147,-196114,-196081,-196047,-196014,-195981,-195947,-195914,-195880,-195847,-195814,-195780,-195747,-195713,-195680,-195646,-195613,-195579,-195546,-195512,-195479,-195445,-195412,-195378,-195345,-195311,-195278,-195244,-195211,-195177,-195144,-195110,-195077,-195043,-195009,-194976,-194942,-194909,-194875,-194841,-194808,-194774,-194740,-194707,-194673,-194639,-194606,-194572,-194538,-194505,-194471,-194437,-194404,-194370,-194336,-194302,-194269,-194235,-194201,-194167,-194134,-194100,-194066,-194032,-193998,-193965,-193931,-193897,-193863,-193829,-193795,-193762,-193728,-193694,-193660,-193626,-193592,-193558,-193524,-193491,-193457,-193423,-193389,-193355,-193321,-193287,-193253,-193219,-193185,-193151,-193117,-193083,-193049,-193015,-192981,-192947,-192913,-192879,-192845,-192811,-192777,-192743,-192709,-192675,-192640,-192606,-192572,-192538,-192504,-192470,-192436,-192402,-192368,-192333,-192299,-192265,-192231,-192197,-192163,-192128,-192094,-192060,-192026,-191991,-191957,-191923,-191889,-191855,-191820,-191786,-191752,-191717,-191683,-191649,-191615,-191580,-191546,-191512,-191477,-191443,-191409,-191374,-191340,-191306,-191271,-191237,-191202,-191168,-191134,-191099,-191065,-191030,-190996,-190962,-190927,-190893,-190858,-190824,-190789,-190755,-190720,-190686,-190651,-190617,-190582,-190548,-190513,-190479,-190444,-190410,-190375,-190341,-190306,-190271,-190237,-190202,-190168,-190133,-190098,-190064,-190029,-189995,-189960,-189925,-189891,-189856,-189821,-189787,-189752,-189717,-189683,-189648,-189613,-189579,-189544,-189509,-189474,-189440,-189405,-189370,-189335,-189301,-189266,-189231,-189196,-189161,-189127,-189092,-189057,-189022,-188987,-188953,-188918,-188883,-188848,-188813,-188778,-188743,-188708,-188674,-188639,-188604,-188569,-188534,-188499,-188464,-188429,-188394,-188359,-188324,-188289,-188254,-188219,-188184,-188149,-188114,-188079,-188044,-188009,-187974,-187939,-187904,-187869,-187834,-187799,-187764,-187729,-187694,-187659,-187624,-187588,-187553,-187518,-187483,-187448,-187413,-187378,-187342,-187307,-187272,-187237,-187202,-187167,-187131,-187096,-187061,-187026,-186991,-186955,-186920,-186885,-186850,-186814,-186779,-186744,-186709,-186673,-186638,-186603,-186567,-186532,-186497,-186461,-186426,-186391,-186355,-186320,-186285,-186249,-186214,-186178,-186143,-186108,-186072,-186037,-186001,-185966,-185931,-185895,-185860,-185824,-185789,-185753,-185718,-185682,-185647,-185611,-185576,-185540,-185505,-185469,-185434,-185398,-185363,-185327,-185292,-185256,-185221,-185185,-185149,-185114,-185078,-185043,-185007,-184971,-184936,-184900,-184865,-184829,-184793,-184758,-184722,-184686,-184651,-184615,-184579,-184544,-184508,-184472,-184436,-184401,-184365,-184329,-184293,-184258,-184222,-184186,-184150,-184115,-184079,-184043,-184007,-183971,-183936,-183900,-183864,-183828,-183792,-183756,-183721,-183685,-183649,-183613,-183577,-183541,-183505,-183469,-183434,-183398,-183362,-183326,-183290,-183254,-183218,-183182,-183146,-183110,-183074,-183038,-183002,-182966,-182930,-182894,-182858,-182822,-182786,-182750,-182714,-182678,-182642,-182606,-182570,-182534,-182498,-182462,-182425,-182389,-182353,-182317,-182281,-182245,-182209,-182173,-182136,-182100,-182064,-182028,-181992,-181956,-181919,-181883,-181847,-181811,-181775,-181738,-181702,-181666,-181630,-181593,-181557,-181521,-181485,-181448,-181412,-181376,-181340,-181303,-181267,-181231,-181194,-181158,-181122,-181085,-181049,-181013,-180976,-180940,-180903,-180867,-180831,-180794,-180758,-180722,-180685,-180649,-180612,-180576,-180539,-180503,-180466,-180430,-180394,-180357,-180321,-180284,-180248,-180211,-180175,-180138,-180102,-180065,-180028,-179992,-179955,-179919,-179882,-179846,-179809,-179773,-179736,-179699,-179663,-179626,-179590,-179553,-179516,-179480,-179443,-179406,-179370,-179333,-179296,-179260,-179223,-179186,-179150,-179113,-179076,-179040,-179003,-178966,-178929,-178893,-178856,-178819,-178782,-178746,-178709,-178672,-178635,-178599,-178562,-178525,-178488,-178451,-178414,-178378,-178341,-178304,-178267,-178230,-178193,-178157,-178120,-178083,-178046,-178009,-177972,-177935,-177898,-177861,-177824,-177787,-177751,-177714,-177677,-177640,-177603,-177566,-177529,-177492,-177455,-177418,-177381,-177344,-177307,-177270,-177233,-177196,-177159,-177122,-177084,-177047,-177010,-176973,-176936,-176899,-176862,-176825,-176788,-176751,-176713,-176676,-176639,-176602,-176565,-176528,-176491,-176453,-176416,-176379,-176342,-176305,-176267,-176230,-176193,-176156,-176119,-176081,-176044,-176007,-175970,-175932,-175895,-175858,-175821,-175783,-175746,-175709,-175671,-175634,-175597,-175559,-175522,-175485,-175447,-175410,-175373,-175335,-175298,-175261,-175223,-175186,-175148,-175111,-175074,-175036,-174999,-174961,-174924,-174886,-174849,-174812,-174774,-174737,-174699,-174662,-174624,-174587,-174549,-174512,-174474,-174437,-174399,-174362,-174324,-174287,-174249,-174211,-174174,-174136,-174099,-174061,-174024,-173986,-173948,-173911,-173873,-173836,-173798,-173760,-173723,-173685,-173647,-173610,-173572,-173534,-173497,-173459,-173421,-173384,-173346,-173308,-173270,-173233,-173195,-173157,-173120,-173082,-173044,-173006,-172968,-172931,-172893,-172855,-172817,-172780,-172742,-172704,-172666,-172628,-172590,-172553,-172515,-172477,-172439,-172401,-172363,-172325,-172288,-172250,-172212,-172174,-172136,-172098,-172060,-172022,-171984,-171946,-171908,-171870,-171833,-171795,-171757,-171719,-171681,-171643,-171605,-171567,-171529,-171491,-171453,-171415,-171377,-171338,-171300,-171262,-171224,-171186,-171148,-171110,-171072,-171034,-170996,-170958,-170920,-170882,-170843,-170805,-170767,-170729,-170691,-170653,-170615,-170576,-170538,-170500,-170462,-170424,-170385,-170347,-170309,-170271,-170233,-170194,-170156,-170118,-170080,-170041,-170003,-169965,-169927,-169888,-169850,-169812,-169773,-169735,-169697,-169659,-169620,-169582,-169544,-169505,-169467,-169429,-169390,-169352,-169313,-169275,-169237,-169198,-169160,-169121,-169083,-169045,-169006,-168968,-168929,-168891,-168852,-168814,-168776,-168737,-168699,-168660,-168622,-168583,-168545,-168506,-168468,-168429,-168391,-168352,-168314,-168275,-168237,-168198,-168159,-168121,-168082,-168044,-168005,-167967,-167928,-167889,-167851,-167812,-167773,-167735,-167696,-167658,-167619,-167580,-167542,-167503,-167464,-167426,-167387,-167348,-167310,-167271,-167232,-167193,-167155,-167116,-167077,-167039,-167000,-166961,-166922,-166884,-166845,-166806,-166767,-166728,-166690,-166651,-166612,-166573,-166534,-166496,-166457,-166418,-166379,-166340,-166301,-166263,-166224,-166185,-166146,-166107,-166068,-166029,-165990,-165951,-165913,-165874,-165835,-165796,-165757,-165718,-165679,-165640,-165601,-165562,-165523,-165484,-165445,-165406,-165367,-165328,-165289,-165250,-165211,-165172,-165133,-165094,-165055,-165016,-164977,-164938,-164899,-164860,-164820,-164781,-164742,-164703,-164664,-164625,-164586,-164547,-164508,-164468,-164429,-164390,-164351,-164312,-164273,-164233,-164194,-164155,-164116,-164077,-164038,-163998,-163959,-163920,-163881,-163841,-163802,-163763,-163724,-163684,-163645,-163606,-163567,-163527,-163488,-163449,-163409,-163370,-163331,-163291,-163252,-163213,-163173,-163134,-163095,-163055,-163016,-162977,-162937,-162898,-162859,-162819,-162780,-162740,-162701,-162662,-162622,-162583,-162543,-162504,-162464,-162425,-162385,-162346,-162307,-162267,-162228,-162188,-162149,-162109,-162070,-162030,-161991,-161951,-161912,-161872,-161832,-161793,-161753,-161714,-161674,-161635,-161595,-161556,-161516,-161476,-161437,-161397,-161358,-161318,-161278,-161239,-161199,-161159,-161120,-161080,-161040,-161001,-160961,-160921,-160882,-160842,-160802,-160763,-160723,-160683,-160643,-160604,-160564,-160524,-160485,-160445,-160405,-160365,-160326,-160286,-160246,-160206,-160166,-160127,-160087,-160047,-160007,-159967,-159928,-159888,-159848,-159808,-159768,-159728,-159688,-159649,-159609,-159569,-159529,-159489,-159449,-159409,-159369,-159329,-159290,-159250,-159210,-159170,-159130,-159090,-159050,-159010,-158970,-158930,-158890,-158850,-158810,-158770,-158730,-158690,-158650,-158610,-158570,-158530,-158490,-158450,-158410,-158370,-158330,-158290,-158250,-158210,-158169,-158129,-158089,-158049,-158009,-157969,-157929,-157889,-157849,-157808,-157768,-157728,-157688,-157648,-157608,-157568,-157527,-157487,-157447,-157407,-157367,-157326,-157286,-157246,-157206,-157166,-157125,-157085,-157045,-157005,-156964,-156924,-156884,-156844,-156803,-156763,-156723,-156682,-156642,-156602,-156561,-156521,-156481,-156440,-156400,-156360,-156319,-156279,-156239,-156198,-156158,-156118,-156077,-156037,-155996,-155956,-155916,-155875,-155835,-155794,-155754,-155714,-155673,-155633,-155592,-155552,-155511,-155471,-155430,-155390,-155349,-155309,-155268,-155228,-155187,-155147,-155106,-155066,-155025,-154985,-154944,-154904,-154863,-154823,-154782,-154741,-154701,-154660,-154620,-154579,-154538,-154498,-154457,-154417,-154376,-154335,-154295,-154254,-154213,-154173,-154132,-154092,-154051,-154010,-153969,-153929,-153888,-153847,-153807,-153766,-153725,-153685,-153644,-153603,-153562,-153522,-153481,-153440,-153399,-153359,-153318,-153277,-153236,-153196,-153155,-153114,-153073,-153032,-152992,-152951,-152910,-152869,-152828,-152787,-152747,-152706,-152665,-152624,-152583,-152542,-152501,-152460,-152420,-152379,-152338,-152297,-152256,-152215,-152174,-152133,-152092,-152051,-152010,-151969,-151928,-151887,-151846,-151805,-151764,-151723,-151682,-151641,-151600,-151559,-151518,-151477,-151436,-151395,-151354,-151313,-151272,-151231,-151190,-151149,-151108,-151067,-151026,-150985,-150944,-150903,-150861,-150820,-150779,-150738,-150697,-150656,-150615,-150574,-150532,-150491,-150450,-150409,-150368,-150327,-150285,-150244,-150203,-150162,-150121,-150079,-150038,-149997,-149956,-149915,-149873,-149832,-149791,-149750,-149708,-149667,-149626,-149584,-149543,-149502,-149461,-149419,-149378,-149337,-149295,-149254,-149213,-149171,-149130,-149089,-149047,-149006,-148965,-148923,-148882,-148841,-148799,-148758,-148716,-148675,-148634,-148592,-148551,-148509,-148468,-148427,-148385,-148344,-148302,-148261,-148219,-148178,-148136,-148095,-148053,-148012,-147970,-147929,-147887,-147846,-147804,-147763,-147721,-147680,-147638,-147597,-147555,-147514,-147472,-147431,-147389,-147347,-147306,-147264,-147223,-147181,-147140,-147098,-147056,-147015,-146973,-146931,-146890,-146848,-146807,-146765,-146723,-146682,-146640,-146598,-146557,-146515,-146473,-146432,-146390,-146348,-146306,-146265,-146223,-146181,-146140,-146098,-146056,-146014,-145973,-145931,-145889,-145847,-145806,-145764,-145722,-145680,-145638,-145597,-145555,-145513,-145471,-145429,-145388,-145346,-145304,-145262,-145220,-145178,-145136,-145095,-145053,-145011,-144969,-144927,-144885,-144843,-144801,-144760,-144718,-144676,-144634,-144592,-144550,-144508,-144466,-144424,-144382,-144340,-144298,-144256,-144214,-144172,-144130,-144088,-144046,-144004,-143962,-143920,-143878,-143836,-143794,-143752,-143710,-143668,-143626,-143584,-143542,-143500,-143458,-143416,-143374,-143332,-143290,-143247,-143205,-143163,-143121,-143079,-143037,-142995,-142953,-142911,-142868,-142826,-142784,-142742,-142700,-142658,-142615,-142573,-142531,-142489,-142447,-142404,-142362,-142320,-142278,-142236,-142193,-142151,-142109,-142067,-142024,-141982,-141940,-141898,-141855,-141813,-141771,-141729,-141686,-141644,-141602,-141559,-141517,-141475,-141432,-141390,-141348,-141305,-141263,-141221,-141178,-141136,-141094,-141051,-141009,-140967,-140924,-140882,-140839,-140797,-140755,-140712,-140670,-140627,-140585,-140543,-140500,-140458,-140415,-140373,-140330,-140288,-140245,-140203,-140160,-140118,-140076,-140033,-139991,-139948,-139906,-139863,-139820,-139778,-139735,-139693,-139650,-139608,-139565,-139523,-139480,-139438,-139395,-139352,-139310,-139267,-139225,-139182,-139140,-139097,-139054,-139012,-138969,-138926,-138884,-138841,-138799,-138756,-138713,-138671,-138628,-138585,-138543,-138500,-138457,-138415,-138372,-138329,-138287,-138244,-138201,-138158,-138116,-138073,-138030,-137987,-137945,-137902,-137859,-137816,-137774,-137731,-137688,-137645,-137603,-137560,-137517,-137474,-137431,-137389,-137346,-137303,-137260,-137217,-137175,-137132,-137089,-137046,-137003,-136960,-136917,-136875,-136832,-136789,-136746,-136703,-136660,-136617,-136574,-136531,-136489,-136446,-136403,-136360,-136317,-136274,-136231,-136188,-136145,-136102,-136059,-136016,-135973,-135930,-135887,-135844,-135801,-135758,-135715,-135672,-135629,-135586,-135543,-135500,-135457,-135414,-135371,-135328,-135285,-135242,-135199,-135156,-135113,-135070,-135027,-134983,-134940,-134897,-134854,-134811,-134768,-134725,-134682,-134639,-134595,-134552,-134509,-134466,-134423,-134380,-134337,-134293,-134250,-134207,-134164,-134121,-134077,-134034,-133991,-133948,-133905,-133861,-133818,-133775,-133732,-133689,-133645,-133602,-133559,-133516,-133472,-133429,-133386,-133342,-133299,-133256,-133213,-133169,-133126,-133083,-133039,-132996,-132953,-132909,-132866,-132823,-132779,-132736,-132693,-132649,-132606,-132563,-132519,-132476,-132433,-132389,-132346,-132302,-132259,-132216,-132172,-132129,-132085,-132042,-131999,-131955,-131912,-131868,-131825,-131781,-131738,-131694,-131651,-131608,-131564,-131521,-131477,-131434,-131390,-131347,-131303,-131260,-131216,-131173,-131129,-131086,-131042,-130998,-130955,-130911,-130868,-130824,-130781,-130737,-130694,-130650,-130606,-130563,-130519,-130476,-130432,-130388,-130345,-130301,-130258,-130214,-130170,-130127,-130083,-130039,-129996,-129952,-129908,-129865,-129821,-129777,-129734,-129690,-129646,-129603,-129559,-129515,-129472,-129428,-129384,-129340,-129297,-129253,-129209,-129166,-129122,-129078,-129034,-128991,-128947,-128903,-128859,-128815,-128772,-128728,-128684,-128640,-128597,-128553,-128509,-128465,-128421,-128377,-128334,-128290,-128246,-128202,-128158,-128114,-128071,-128027,-127983,-127939,-127895,-127851,-127807,-127763,-127720,-127676,-127632,-127588,-127544,-127500,-127456,-127412,-127368,-127324,-127280,-127236,-127192,-127149,-127105,-127061,-127017,-126973,-126929,-126885,-126841,-126797,-126753,-126709,-126665,-126621,-126577,-126533,-126489,-126445,-126401,-126357,-126313,-126268,-126224,-126180,-126136,-126092,-126048,-126004,-125960,-125916,-125872,-125828,-125784,-125740,-125695,-125651,-125607,-125563,-125519,-125475,-125431,-125387,-125342,-125298,-125254,-125210,-125166,-125122,-125077,-125033,-124989,-124945,-124901,-124856,-124812,-124768,-124724,-124680,-124635,-124591,-124547,-124503,-124459,-124414,-124370,-124326,-124282,-124237,-124193,-124149,-124104,-124060,-124016,-123972,-123927,-123883,-123839,-123794,-123750,-123706,-123661,-123617,-123573,-123528,-123484,-123440,-123395,-123351,-123307,-123262,-123218,-123174,-123129,-123085,-123041,-122996,-122952,-122907,-122863,-122819,-122774,-122730,-122685,-122641,-122596,-122552,-122508,-122463,-122419,-122374,-122330,-122285,-122241,-122196,-122152,-122107,-122063,-122018,-121974,-121930,-121885,-121841,-121796,-121751,-121707,-121662,-121618,-121573,-121529,-121484,-121440,-121395,-121351,-121306,-121262,-121217,-121172,-121128,-121083,-121039,-120994,-120949,-120905,-120860,-120816,-120771,-120726,-120682,-120637,-120593,-120548,-120503,-120459,-120414,-120369,-120325,-120280,-120235,-120191,-120146,-120101,-120057,-120012,-119967,-119923,-119878,-119833,-119789,-119744,-119699,-119654,-119610,-119565,-119520,-119475,-119431,-119386,-119341,-119296,-119252,-119207,-119162,-119117,-119073,-119028,-118983,-118938,-118893,-118849,-118804,-118759,-118714,-118669,-118625,-118580,-118535,-118490,-118445,-118400,-118356,-118311,-118266,-118221,-118176,-118131,-118086,-118041,-117997,-117952,-117907,-117862,-117817,-117772,-117727,-117682,-117637,-117592,-117548,-117503,-117458,-117413,-117368,-117323,-117278,-117233,-117188,-117143,-117098,-117053,-117008,-116963,-116918,-116873,-116828,-116783,-116738,-116693,-116648,-116603,-116558,-116513,-116468,-116423,-116378,-116333,-116288,-116243,-116198,-116153,-116108,-116063,-116017,-115972,-115927,-115882,-115837,-115792,-115747,-115702,-115657,-115612,-115566,-115521,-115476,-115431,-115386,-115341,-115296,-115251,-115205,-115160,-115115,-115070,-115025,-114980,-114934,-114889,-114844,-114799,-114754,-114709,-114663,-114618,-114573,-114528,-114482,-114437,-114392,-114347,-114302,-114256,-114211,-114166,-114121,-114075,-114030,-113985,-113940,-113894,-113849,-113804,-113758,-113713,-113668,-113623,-113577,-113532,-113487,-113441,-113396,-113351,-113305,-113260,-113215,-113169,-113124,-113079,-113033,-112988,-112943,-112897,-112852,-112807,-112761,-112716,-112670,-112625,-112580,-112534,-112489,-112443,-112398,-112353,-112307,-112262,-112216,-112171,-112125,-112080,-112035,-111989,-111944,-111898,-111853,-111807,-111762,-111716,-111671,-111625,-111580,-111534,-111489,-111443,-111398,-111352,-111307,-111261,-111216,-111170,-111125,-111079,-111034,-110988,-110943,-110897,-110852,-110806,-110761,-110715,-110669,-110624,-110578,-110533,-110487,-110442,-110396,-110350,-110305,-110259,-110214,-110168,-110122,-110077,-110031,-109985,-109940,-109894,-109849,-109803,-109757,-109712,-109666,-109620,-109575,-109529,-109483,-109438,-109392,-109346,-109301,-109255,-109209,-109164,-109118,-109072,-109026,-108981,-108935,-108889,-108844,-108798,-108752,-108706,-108661,-108615,-108569,-108523,-108478,-108432,-108386,-108340,-108294,-108249,-108203,-108157,-108111,-108066,-108020,-107974,-107928,-107882,-107837,-107791,-107745,-107699,-107653,-107607,-107562,-107516,-107470,-107424,-107378,-107332,-107286,-107241,-107195,-107149,-107103,-107057,-107011,-106965,-106919,-106874,-106828,-106782,-106736,-106690,-106644,-106598,-106552,-106506,-106460,-106414,-106368,-106322,-106277,-106231,-106185,-106139,-106093,-106047,-106001,-105955,-105909,-105863,-105817,-105771,-105725,-105679,-105633,-105587,-105541,-105495,-105449,-105403,-105357,-105311,-105265,-105219,-105173,-105127,-105081,-105034,-104988,-104942,-104896,-104850,-104804,-104758,-104712,-104666,-104620,-104574,-104528,-104482,-104435,-104389,-104343,-104297,-104251,-104205,-104159,-104113,-104066,-104020,-103974,-103928,-103882,-103836,-103790,-103743,-103697,-103651,-103605,-103559,-103513,-103466,-103420,-103374,-103328,-103282,-103235,-103189,-103143,-103097,-103051,-103004,-102958,-102912,-102866,-102819,-102773,-102727,-102681,-102634,-102588,-102542,-102496,-102449,-102403,-102357,-102311,-102264,-102218,-102172,-102125,-102079,-102033,-101987,-101940,-101894,-101848,-101801,-101755,-101709,-101662,-101616,-101570,-101523,-101477,-101431,-101384,-101338,-101292,-101245,-101199,-101152,-101106,-101060,-101013,-100967,-100921,-100874,-100828,-100781,-100735,-100689,-100642,-100596,-100549,-100503,-100456,-100410,-100364,-100317,-100271,-100224,-100178,-100131,-100085,-100038,-99992,-99946,-99899,-99853,-99806,-99760,-99713,-99667,-99620,-99574,-99527,-99481,-99434,-99388,-99341,-99295,-99248,-99202,-99155,-99109,-99062,-99015,-98969,-98922,-98876,-98829,-98783,-98736,-98690,-98643,-98596,-98550,-98503,-98457,-98410,-98363,-98317,-98270,-98224,-98177,-98130,-98084,-98037,-97991,-97944,-97897,-97851,-97804,-97757,-97711,-97664,-97618,-97571,-97524,-97478,-97431,-97384,-97338,-97291,-97244,-97198,-97151,-97104,-97057,-97011,-96964,-96917,-96871,-96824,-96777,-96731,-96684,-96637,-96590,-96544,-96497,-96450,-96403,-96357,-96310,-96263,-96216,-96170,-96123,-96076,-96029,-95983,-95936,-95889,-95842,-95795,-95749,-95702,-95655,-95608,-95561,-95515,-95468,-95421,-95374,-95327,-95281,-95234,-95187,-95140,-95093,-95046,-95000,-94953,-94906,-94859,-94812,-94765,-94718,-94672,-94625,-94578,-94531,-94484,-94437,-94390,-94343,-94296,-94250,-94203,-94156,-94109,-94062,-94015,-93968,-93921,-93874,-93827,-93780,-93733,-93686,-93639,-93593,-93546,-93499,-93452,-93405,-93358,-93311,-93264,-93217,-93170,-93123,-93076,-93029,-92982,-92935,-92888,-92841,-92794,-92747,-92700,-92653,-92606,-92559,-92512,-92465,-92418,-92371,-92324,-92277,-92229,-92182,-92135,-92088,-92041,-91994,-91947,-91900,-91853,-91806,-91759,-91712,-91665,-91618,-91570,-91523,-91476,-91429,-91382,-91335,-91288,-91241,-91194,-91146,-91099,-91052,-91005,-90958,-90911,-90864,-90816,-90769,-90722,-90675,-90628,-90581,-90533,-90486,-90439,-90392,-90345,-90298,-90250,-90203,-90156,-90109,-90062,-90014,-89967,-89920,-89873,-89825,-89778,-89731,-89684,-89637,-89589,-89542,-89495,-89448,-89400,-89353,-89306,-89259,-89211,-89164,-89117,-89069,-89022,-88975,-88928,-88880,-88833,-88786,-88738,-88691,-88644,-88597,-88549,-88502,-88455,-88407,-88360,-88313,-88265,-88218,-88171,-88123,-88076,-88029,-87981,-87934,-87887,-87839,-87792,-87744,-87697,-87650,-87602,-87555,-87508,-87460,-87413,-87365,-87318,-87271,-87223,-87176,-87128,-87081,-87034,-86986,-86939,-86891,-86844,-86797,-86749,-86702,-86654,-86607,-86559,-86512,-86464,-86417,-86370,-86322,-86275,-86227,-86180,-86132,-86085,-86037,-85990,-85942,-85895,-85847,-85800,-85752,-85705,-85657,-85610,-85562,-85515,-85467,-85420,-85372,-85325,-85277,-85230,-85182,-85135,-85087,-85039,-84992,-84944,-84897,-84849,-84802,-84754,-84707,-84659,-84611,-84564,-84516,-84469,-84421,-84373,-84326,-84278,-84231,-84183,-84135,-84088,-84040,-83993,-83945,-83897,-83850,-83802,-83755,-83707,-83659,-83612,-83564,-83516,-83469,-83421,-83373,-83326,-83278,-83230,-83183,-83135,-83087,-83040,-82992,-82944,-82897,-82849,-82801,-82754,-82706,-82658,-82611,-82563,-82515,-82467,-82420,-82372,-82324,-82277,-82229,-82181,-82133,-82086,-82038,-81990,-81942,-81895,-81847,-81799,-81751,-81704,-81656,-81608,-81560,-81513,-81465,-81417,-81369,-81321,-81274,-81226,-81178,-81130,-81082,-81035,-80987,-80939,-80891,-80843,-80796,-80748,-80700,-80652,-80604,-80556,-80509,-80461,-80413,-80365,-80317,-80269,-80222,-80174,-80126,-80078,-80030,-79982,-79934,-79886,-79839,-79791,-79743,-79695,-79647,-79599,-79551,-79503,-79456,-79408,-79360,-79312,-79264,-79216,-79168,-79120,-79072,-79024,-78976,-78928,-78880,-78833,-78785,-78737,-78689,-78641,-78593,-78545,-78497,-78449,-78401,-78353,-78305,-78257,-78209,-78161,-78113,-78065,-78017,-77969,-77921,-77873,-77825,-77777,-77729,-77681,-77633,-77585,-77537,-77489,-77441,-77393,-77345,-77297,-77249,-77201,-77153,-77105,-77057,-77009,-76961,-76913,-76865,-76817,-76769,-76720,-76672,-76624,-76576,-76528,-76480,-76432,-76384,-76336,-76288,-76240,-76192,-76143,-76095,-76047,-75999,-75951,-75903,-75855,-75807,-75759,-75710,-75662,-75614,-75566,-75518,-75470,-75422,-75374,-75325,-75277,-75229,-75181,-75133,-75085,-75036,-74988,-74940,-74892,-74844,-74796,-74747,-74699,-74651,-74603,-74555,-74507,-74458,-74410,-74362,-74314,-74266,-74217,-74169,-74121,-74073,-74024,-73976,-73928,-73880,-73832,-73783,-73735,-73687,-73639,-73590,-73542,-73494,-73446,-73397,-73349,-73301,-73253,-73204,-73156,-73108,-73060,-73011,-72963,-72915,-72866,-72818,-72770,-72722,-72673,-72625,-72577,-72528,-72480,-72432,-72383,-72335,-72287,-72238,-72190,-72142,-72094,-72045,-71997,-71949,-71900,-71852,-71804,-71755,-71707,-71658,-71610,-71562,-71513,-71465,-71417,-71368,-71320,-71272,-71223,-71175,-71126,-71078,-71030,-70981,-70933,-70885,-70836,-70788,-70739,-70691,-70643,-70594,-70546,-70497,-70449,-70400,-70352,-70304,-70255,-70207,-70158,-70110,-70061,-70013,-69965,-69916,-69868,-69819,-69771,-69722,-69674,-69625,-69577,-69529,-69480,-69432,-69383,-69335,-69286,-69238,-69189,-69141,-69092,-69044,-68995,-68947,-68898,-68850,-68801,-68753,-68704,-68656,-68607,-68559,-68510,-68462,-68413,-68365,-68316,-68268,-68219,-68170,-68122,-68073,-68025,-67976,-67928,-67879,-67831,-67782,-67734,-67685,-67636,-67588,-67539,-67491,-67442,-67394,-67345,-67296,-67248,-67199,-67151,-67102,-67054,-67005,-66956,-66908,-66859,-66811,-66762,-66713,-66665,-66616,-66567,-66519,-66470,-66422,-66373,-66324,-66276,-66227,-66178,-66130,-66081,-66033,-65984,-65935,-65887,-65838,-65789,-65741,-65692,-65643,-65595,-65546,-65497,-65449,-65400,-65351,-65303,-65254,-65205,-65157,-65108,-65059,-65010,-64962,-64913,-64864,-64816,-64767,-64718,-64670,-64621,-64572,-64523,-64475,-64426,-64377,-64328,-64280,-64231,-64182,-64134,-64085,-64036,-63987,-63939,-63890,-63841,-63792,-63744,-63695,-63646,-63597,-63549,-63500,-63451,-63402,-63353,-63305,-63256,-63207,-63158,-63110,-63061,-63012,-62963,-62914,-62866,-62817,-62768,-62719,-62670,-62622,-62573,-62524,-62475,-62426,-62377,-62329,-62280,-62231,-62182,-62133,-62084,-62036,-61987,-61938,-61889,-61840,-61791,-61743,-61694,-61645,-61596,-61547,-61498,-61449,-61401,-61352,-61303,-61254,-61205,-61156,-61107,-61058,-61010,-60961,-60912,-60863,-60814,-60765,-60716,-60667,-60618,-60569,-60521,-60472,-60423,-60374,-60325,-60276,-60227,-60178,-60129,-60080,-60031,-59982,-59934,-59885,-59836,-59787,-59738,-59689,-59640,-59591,-59542,-59493,-59444,-59395,-59346,-59297,-59248,-59199,-59150,-59101,-59052,-59003,-58954,-58905,-58856,-58807,-58758,-58710,-58661,-58612,-58563,-58514,-58465,-58416,-58367,-58318,-58269,-58220,-58170,-58121,-58072,-58023,-57974,-57925,-57876,-57827,-57778,-57729,-57680,-57631,-57582,-57533,-57484,-57435,-57386,-57337,-57288,-57239,-57190,-57141,-57092,-57043,-56994,-56945,-56895,-56846,-56797,-56748,-56699,-56650,-56601,-56552,-56503,-56454,-56405,-56356,-56307,-56257,-56208,-56159,-56110,-56061,-56012,-55963,-55914,-55865,-55815,-55766,-55717,-55668,-55619,-55570,-55521,-55472,-55423,-55373,-55324,-55275,-55226,-55177,-55128,-55079,-55029,-54980,-54931,-54882,-54833,-54784,-54735,-54685,-54636,-54587,-54538,-54489,-54440,-54390,-54341,-54292,-54243,-54194,-54144,-54095,-54046,-53997,-53948,-53899,-53849,-53800,-53751,-53702,-53653,-53603,-53554,-53505,-53456,-53407,-53357,-53308,-53259,-53210,-53160,-53111,-53062,-53013,-52964,-52914,-52865,-52816,-52767,-52717,-52668,-52619,-52570,-52520,-52471,-52422,-52373,-52323,-52274,-52225,-52176,-52126,-52077,-52028,-51979,-51929,-51880,-51831,-51781,-51732,-51683,-51634,-51584,-51535,-51486,-51437,-51387,-51338,-51289,-51239,-51190,-51141,-51091,-51042,-50993,-50944,-50894,-50845,-50796,-50746,-50697,-50648,-50598,-50549,-50500,-50450,-50401,-50352,-50302,-50253,-50204,-50154,-50105,-50056,-50006,-49957,-49908,-49858,-49809,-49760,-49710,-49661,-49612,-49562,-49513,-49463,-49414,-49365,-49315,-49266,-49217,-49167,-49118,-49069,-49019,-48970,-48920,-48871,-48822,-48772,-48723,-48673,-48624,-48575,-48525,-48476,-48426,-48377,-48328,-48278,-48229,-48179,-48130,-48081,-48031,-47982,-47932,-47883,-47834,-47784,-47735,-47685,-47636,-47586,-47537,-47488,-47438,-47389,-47339,-47290,-47240,-47191,-47141,-47092,-47043,-46993,-46944,-46894,-46845,-46795,-46746,-46696,-46647,-46597,-46548,-46499,-46449,-46400,-46350,-46301,-46251,-46202,-46152,-46103,-46053,-46004,-45954,-45905,-45855,-45806,-45756,-45707,-45657,-45608,-45558,-45509,-45459,-45410,-45360,-45311,-45261,-45212,-45162,-45113,-45063,-45014,-44964,-44915,-44865,-44816,-44766,-44717,-44667,-44618,-44568,-44518,-44469,-44419,-44370,-44320,-44271,-44221,-44172,-44122,-44073,-44023,-43973,-43924,-43874,-43825,-43775,-43726,-43676,-43627,-43577,-43527,-43478,-43428,-43379,-43329,-43280,-43230,-43180,-43131,-43081,-43032,-42982,-42932,-42883,-42833,-42784,-42734,-42685,-42635,-42585,-42536,-42486,-42437,-42387,-42337,-42288,-42238,-42189,-42139,-42089,-42040,-41990,-41940,-41891,-41841,-41792,-41742,-41692,-41643,-41593,-41543,-41494,-41444,-41395,-41345,-41295,-41246,-41196,-41146,-41097,-41047,-40997,-40948,-40898,-40848,-40799,-40749,-40700,-40650,-40600,-40551,-40501,-40451,-40402,-40352,-40302,-40253,-40203,-40153,-40104,-40054,-40004,-39955,-39905,-39855,-39805,-39756,-39706,-39656,-39607,-39557,-39507,-39458,-39408,-39358,-39309,-39259,-39209,-39159,-39110,-39060,-39010,-38961,-38911,-38861,-38812,-38762,-38712,-38662,-38613,-38563,-38513,-38464,-38414,-38364,-38314,-38265,-38215,-38165,-38115,-38066,-38016,-37966,-37916,-37867,-37817,-37767,-37718,-37668,-37618,-37568,-37519,-37469,-37419,-37369,-37320,-37270,-37220,-37170,-37121,-37071,-37021,-36971,-36921,-36872,-36822,-36772,-36722,-36673,-36623,-36573,-36523,-36474,-36424,-36374,-36324,-36274,-36225,-36175,-36125,-36075,-36026,-35976,-35926,-35876,-35826,-35777,-35727,-35677,-35627,-35577,-35528,-35478,-35428,-35378,-35328,-35279,-35229,-35179,-35129,-35079,-35029,-34980,-34930,-34880,-34830,-34780,-34731,-34681,-34631,-34581,-34531,-34481,-34432,-34382,-34332,-34282,-34232,-34182,-34133,-34083,-34033,-33983,-33933,-33883,-33834,-33784,-33734,-33684,-33634,-33584,-33534,-33485,-33435,-33385,-33335,-33285,-33235,-33185,-33136,-33086,-33036,-32986,-32936,-32886,-32836,-32787,-32737,-32687,-32637,-32587,-32537,-32487,-32437,-32388,-32338,-32288,-32238,-32188,-32138,-32088,-32038,-31988,-31939,-31889,-31839,-31789,-31739,-31689,-31639,-31589,-31539,-31489,-31440,-31390,-31340,-31290,-31240,-31190,-31140,-31090,-31040,-30990,-30941,-30891,-30841,-30791,-30741,-30691,-30641,-30591,-30541,-30491,-30441,-30391,-30341,-30292,-30242,-30192,-30142,-30092,-30042,-29992,-29942,-29892,-29842,-29792,-29742,-29692,-29642,-29592,-29542,-29493,-29443,-29393,-29343,-29293,-29243,-29193,-29143,-29093,-29043,-28993,-28943,-28893,-28843,-28793,-28743,-28693,-28643,-28593,-28543,-28493,-28443,-28393,-28343,-28294,-28244,-28194,-28144,-28094,-28044,-27994,-27944,-27894,-27844,-27794,-27744,-27694,-27644,-27594,-27544,-27494,-27444,-27394,-27344,-27294,-27244,-27194,-27144,-27094,-27044,-26994,-26944,-26894,-26844,-26794,-26744,-26694,-26644,-26594,-26544,-26494,-26444,-26394,-26344,-26294,-26244,-26194,-26144,-26094,-26044,-25994,-25944,-25894,-25844,-25794,-25744,-25694,-25644,-25594,-25544,-25494,-25443,-25393,-25343,-25293,-25243,-25193,-25143,-25093,-25043,-24993,-24943,-24893,-24843,-24793,-24743,-24693,-24643,-24593,-24543,-24493,-24443,-24393,-24343,-24293,-24243,-24192,-24142,-24092,-24042,-23992,-23942,-23892,-23842,-23792,-23742,-23692,-23642,-23592,-23542,-23492,-23442,-23392,-23341,-23291,-23241,-23191,-23141,-23091,-23041,-22991,-22941,-22891,-22841,-22791,-22741,-22691,-22640,-22590,-22540,-22490,-22440,-22390,-22340,-22290,-22240,-22190,-22140,-22090,-22039,-21989,-21939,-21889,-21839,-21789,-21739,-21689,-21639,-21589,-21539,-21488,-21438,-21388,-21338,-21288,-21238,-21188,-21138,-21088,-21038,-20987,-20937,-20887,-20837,-20787,-20737,-20687,-20637,-20587,-20537,-20486,-20436,-20386,-20336,-20286,-20236,-20186,-20136,-20085,-20035,-19985,-19935,-19885,-19835,-19785,-19735,-19685,-19634,-19584,-19534,-19484,-19434,-19384,-19334,-19284,-19233,-19183,-19133,-19083,-19033,-18983,-18933,-18882,-18832,-18782,-18732,-18682,-18632,-18582,-18531,-18481,-18431,-18381,-18331,-18281,-18231,-18180,-18130,-18080,-18030,-17980,-17930,-17880,-17829,-17779,-17729,-17679,-17629,-17579,-17529,-17478,-17428,-17378,-17328,-17278,-17228,-17177,-17127,-17077,-17027,-16977,-16927,-16877,-16826,-16776,-16726,-16676,-16626,-16576,-16525,-16475,-16425,-16375,-16325,-16275,-16224,-16174,-16124,-16074,-16024,-15974,-15923,-15873,-15823,-15773,-15723,-15672,-15622,-15572,-15522,-15472,-15422,-15371,-15321,-15271,-15221,-15171,-15121,-15070,-15020,-14970,-14920,-14870,-14819,-14769,-14719,-14669,-14619,-14568,-14518,-14468,-14418,-14368,-14318,-14267,-14217,-14167,-14117,-14067,-14016,-13966,-13916,-13866,-13816,-13765,-13715,-13665,-13615,-13565,-13514,-13464,-13414,-13364,-13314,-13263,-13213,-13163,-13113,-13063,-13012,-12962,-12912,-12862,-12812,-12761,-12711,-12661,-12611,-12561,-12510,-12460,-12410,-12360,-12310,-12259,-12209,-12159,-12109,-12058,-12008,-11958,-11908,-11858,-11807,-11757,-11707,-11657,-11607,-11556,-11506,-11456,-11406,-11355,-11305,-11255,-11205,-11155,-11104,-11054,-11004,-10954,-10903,-10853,-10803,-10753,-10703,-10652,-10602,-10552,-10502,-10451,-10401,-10351,-10301,-10251,-10200,-10150,-10100,-10050,-9999,-9949,-9899,-9849,-9798,-9748,-9698,-9648,-9598,-9547,-9497,-9447,-9397,-9346,-9296,-9246,-9196,-9145,-9095,-9045,-8995,-8945,-8894,-8844,-8794,-8744,-8693,-8643,-8593,-8543,-8492,-8442,-8392,-8342,-8291,-8241,-8191,-8141,-8090,-8040,-7990,-7940,-7889,-7839,-7789,-7739,-7689,-7638,-7588,-7538,-7488,-7437,-7387,-7337,-7287,-7236,-7186,-7136,-7086,-7035,-6985,-6935,-6885,-6834,-6784,-6734,-6684,-6633,-6583,-6533,-6483,-6432,-6382,-6332,-6282,-6231,-6181,-6131,-6081,-6030,-5980,-5930,-5880,-5829,-5779,-5729,-5679,-5628,-5578,-5528,-5478,-5427,-5377,-5327,-5277,-5226,-5176,-5126,-5075,-5025,-4975,-4925,-4874,-4824,-4774,-4724,-4673,-4623,-4573,-4523,-4472,-4422,-4372,-4322,-4271,-4221,-4171,-4121,-4070,-4020,-3970,-3920,-3869,-3819,-3769,-3719,-3668,-3618,-3568,-3517,-3467,-3417,-3367,-3316,-3266,-3216,-3166,-3115,-3065,-3015,-2965,-2914,-2864,-2814,-2764,-2713,-2663,-2613,-2562,-2512,-2462,-2412,-2361,-2311,-2261,-2211,-2160,-2110,-2060,-2010,-1959,-1909,-1859,-1809,-1758,-1708,-1658,-1607,-1557,-1507,-1457,-1406,-1356,-1306,-1256,-1205,-1155,-1105,-1055,-1004,-954,-904,-854,-803,-753,-703,-652,-602,-552,-502,-451,-401,-351,-301,-250,-200,-150,-100,-49,0,50,101,151,201,251,302,352,402,452,503,553,603,653,704,754,804,855,905,955,1005,1056,1106,1156,1206,1257,1307,1357,1407,1458,1508,1558,1608,1659,1709,1759,1810,1860,1910,1960,2011,2061,2111,2161,2212,2262,2312,2362,2413,2463,2513,2563,2614,2664,2714,2765,2815,2865,2915,2966,3016,3066,3116,3167,3217,3267,3317,3368,3418,3468,3518,3569,3619,3669,3720,3770,3820,3870,3921,3971,4021,4071,4122,4172,4222,4272,4323,4373,4423,4473,4524,4574,4624,4674,4725,4775,4825,4875,4926,4976,5026,5076,5127,5177,5227,5278,5328,5378,5428,5479,5529,5579,5629,5680,5730,5780,5830,5881,5931,5981,6031,6082,6132,6182,6232,6283,6333,6383,6433,6484,6534,6584,6634,6685,6735,6785,6835,6886,6936,6986,7036,7087,7137,7187,7237,7288,7338,7388,7438,7489,7539,7589,7639,7690,7740,7790,7840,7890,7941,7991,8041,8091,8142,8192,8242,8292,8343,8393,8443,8493,8544,8594,8644,8694,8745,8795,8845,8895,8946,8996,9046,9096,9146,9197,9247,9297,9347,9398,9448,9498,9548,9599,9649,9699,9749,9799,9850,9900,9950,10000,10051,10101,10151,10201,10252,10302,10352,10402,10452,10503,10553,10603,10653,10704,10754,10804,10854,10904,10955,11005,11055,11105,11156,11206,11256,11306,11356,11407,11457,11507,11557,11608,11658,11708,11758,11808,11859,11909,11959,12009,12059,12110,12160,12210,12260,12311,12361,12411,12461,12511,12562,12612,12662,12712,12762,12813,12863,12913,12963,13013,13064,13114,13164,13214,13264,13315,13365,13415,13465,13515,13566,13616,13666,13716,13766,13817,13867,13917,13967,14017,14068,14118,14168,14218,14268,14319,14369,14419,14469,14519,14569,14620,14670,14720,14770,14820,14871,14921,14971,15021,15071,15122,15172,15222,15272,15322,15372,15423,15473,15523,15573,15623,15673,15724,15774,15824,15874,15924,15975,16025,16075,16125,16175,16225,16276,16326,16376,16426,16476,16526,16577,16627,16677,16727,16777,16827,16878,16928,16978,17028,17078,17128,17178,17229,17279,17329,17379,17429,17479,17530,17580,17630,17680,17730,17780,17830,17881,17931,17981,18031,18081,18131,18181,18232,18282,18332,18382,18432,18482,18532,18583,18633,18683,18733,18783,18833,18883,18934,18984,19034,19084,19134,19184,19234,19285,19335,19385,19435,19485,19535,19585,19635,19686,19736,19786,19836,19886,19936,19986,20036,20086,20137,20187,20237,20287,20337,20387,20437,20487,20538,20588,20638,20688,20738,20788,20838,20888,20938,20988,21039,21089,21139,21189,21239,21289,21339,21389,21439,21489,21540,21590,21640,21690,21740,21790,21840,21890,21940,21990,22040,22091,22141,22191,22241,22291,22341,22391,22441,22491,22541,22591,22641,22692,22742,22792,22842,22892,22942,22992,23042,23092,23142,23192,23242,23292,23342,23393,23443,23493,23543,23593,23643,23693,23743,23793,23843,23893,23943,23993,24043,24093,24143,24193,24244,24294,24344,24394,24444,24494,24544,24594,24644,24694,24744,24794,24844,24894,24944,24994,25044,25094,25144,25194,25244,25294,25344,25394,25444,25495,25545,25595,25645,25695,25745,25795,25845,25895,25945,25995,26045,26095,26145,26195,26245,26295,26345,26395,26445,26495,26545,26595,26645,26695,26745,26795,26845,26895,26945,26995,27045,27095,27145,27195,27245,27295,27345,27395,27445,27495,27545,27595,27645,27695,27745,27795,27845,27895,27945,27995,28045,28095,28145,28195,28245,28295,28344,28394,28444,28494,28544,28594,28644,28694,28744,28794,28844,28894,28944,28994,29044,29094,29144,29194,29244,29294,29344,29394,29444,29494,29543,29593,29643,29693,29743,29793,29843,29893,29943,29993,30043,30093,30143,30193,30243,30293,30342,30392,30442,30492,30542,30592,30642,30692,30742,30792,30842,30892,30942,30991,31041,31091,31141,31191,31241,31291,31341,31391,31441,31490,31540,31590,31640,31690,31740,31790,31840,31890,31940,31989,32039,32089,32139,32189,32239,32289,32339,32389,32438,32488,32538,32588,32638,32688,32738,32788,32837,32887,32937,32987,33037,33087,33137,33186,33236,33286,33336,33386,33436,33486,33535,33585,33635,33685,33735,33785,33835,33884,33934,33984,34034,34084,34134,34183,34233,34283,34333,34383,34433,34482,34532,34582,34632,34682,34732,34781,34831,34881,34931,34981,35030,35080,35130,35180,35230,35280,35329,35379,35429,35479,35529,35578,35628,35678,35728,35778,35827,35877,35927,35977,36027,36076,36126,36176,36226,36275,36325,36375,36425,36475,36524,36574,36624,36674,36723,36773,36823,36873,36922,36972,37022,37072,37122,37171,37221,37271,37321,37370,37420,37470,37520,37569,37619,37669,37719,37768,37818,37868,37917,37967,38017,38067,38116,38166,38216,38266,38315,38365,38415,38465,38514,38564,38614,38663,38713,38763,38813,38862,38912,38962,39011,39061,39111,39160,39210,39260,39310,39359,39409,39459,39508,39558,39608,39657,39707,39757,39806,39856,39906,39956,40005,40055,40105,40154,40204,40254,40303,40353,40403,40452,40502,40552,40601,40651,40701,40750,40800,40849,40899,40949,40998,41048,41098,41147,41197,41247,41296,41346,41396,41445,41495,41544,41594,41644,41693,41743,41793,41842,41892,41941,41991,42041,42090,42140,42190,42239,42289,42338,42388,42438,42487,42537,42586,42636,42686,42735,42785,42834,42884,42933,42983,43033,43082,43132,43181,43231,43281,43330,43380,43429,43479,43528,43578,43628,43677,43727,43776,43826,43875,43925,43974,44024,44074,44123,44173,44222,44272,44321,44371,44420,44470,44519,44569,44619,44668,44718,44767,44817,44866,44916,44965,45015,45064,45114,45163,45213,45262,45312,45361,45411,45460,45510,45559,45609,45658,45708,45757,45807,45856,45906,45955,46005,46054,46104,46153,46203,46252,46302,46351,46401,46450,46500,46549,46598,46648,46697,46747,46796,46846,46895,46945,46994,47044,47093,47142,47192,47241,47291,47340,47390,47439,47489,47538,47587,47637,47686,47736,47785,47835,47884,47933,47983,48032,48082,48131,48180,48230,48279,48329,48378,48427,48477,48526,48576,48625,48674,48724,48773,48823,48872,48921,48971,49020,49070,49119,49168,49218,49267,49316,49366,49415,49464,49514,49563,49613,49662,49711,49761,49810,49859,49909,49958,50007,50057,50106,50155,50205,50254,50303,50353,50402,50451,50501,50550,50599,50649,50698,50747,50797,50846,50895,50945,50994,51043,51092,51142,51191,51240,51290,51339,51388,51438,51487,51536,51585,51635,51684,51733,51782,51832,51881,51930,51980,52029,52078,52127,52177,52226,52275,52324,52374,52423,52472,52521,52571,52620,52669,52718,52768,52817,52866,52915,52965,53014,53063,53112,53161,53211,53260,53309,53358,53408,53457,53506,53555,53604,53654,53703,53752,53801,53850,53900,53949,53998,54047,54096,54145,54195,54244,54293,54342,54391,54441,54490,54539,54588,54637,54686,54736,54785,54834,54883,54932,54981,55030,55080,55129,55178,55227,55276,55325,55374,55424,55473,55522,55571,55620,55669,55718,55767,55816,55866,55915,55964,56013,56062,56111,56160,56209,56258,56308,56357,56406,56455,56504,56553,56602,56651,56700,56749,56798,56847,56896,56946,56995,57044,57093,57142,57191,57240,57289,57338,57387,57436,57485,57534,57583,57632,57681,57730,57779,57828,57877,57926,57975,58024,58073,58122,58171,58221,58270,58319,58368,58417,58466,58515,58564,58613,58662,58711,58759,58808,58857,58906,58955,59004,59053,59102,59151,59200,59249,59298,59347,59396,59445,59494,59543,59592,59641,59690,59739,59788,59837,59886,59935,59983,60032,60081,60130,60179,60228,60277,60326,60375,60424,60473,60522,60570,60619,60668,60717,60766,60815,60864,60913,60962,61011,61059,61108,61157,61206,61255,61304,61353,61402,61450,61499,61548,61597,61646,61695,61744,61792,61841,61890,61939,61988,62037,62085,62134,62183,62232,62281,62330,62378,62427,62476,62525,62574,62623,62671,62720,62769,62818,62867,62915,62964,63013,63062,63111,63159,63208,63257,63306,63354,63403,63452,63501,63550,63598,63647,63696,63745,63793,63842,63891,63940,63988,64037,64086,64135,64183,64232,64281,64329,64378,64427,64476,64524,64573,64622,64671,64719,64768,64817,64865,64914,64963,65011,65060,65109,65158,65206,65255,65304,65352,65401,65450,65498,65547,65596,65644,65693,65742,65790,65839,65888,65936,65985,66034,66082,66131,66179,66228,66277,66325,66374,66423,66471,66520,66568,66617,66666,66714,66763,66812,66860,66909,66957,67006,67055,67103,67152,67200,67249,67297,67346,67395,67443,67492,67540,67589,67637,67686,67735,67783,67832,67880,67929,67977,68026,68074,68123,68171,68220,68269,68317,68366,68414,68463,68511,68560,68608,68657,68705,68754,68802,68851,68899,68948,68996,69045,69093,69142,69190,69239,69287,69336,69384,69433,69481,69530,69578,69626,69675,69723,69772,69820,69869,69917,69966,70014,70062,70111,70159,70208,70256,70305,70353,70401,70450,70498,70547,70595,70644,70692,70740,70789,70837,70886,70934,70982,71031,71079,71127,71176,71224,71273,71321,71369,71418,71466,71514,71563,71611,71659,71708,71756,71805,71853,71901,71950,71998,72046,72095,72143,72191,72239,72288,72336,72384,72433,72481,72529,72578,72626,72674,72723,72771,72819,72867,72916,72964,73012,73061,73109,73157,73205,73254,73302,73350,73398,73447,73495,73543,73591,73640,73688,73736,73784,73833,73881,73929,73977,74025,74074,74122,74170,74218,74267,74315,74363,74411,74459,74508,74556,74604,74652,74700,74748,74797,74845,74893,74941,74989,75037,75086,75134,75182,75230,75278,75326,75375,75423,75471,75519,75567,75615,75663,75711,75760,75808,75856,75904,75952,76000,76048,76096,76144,76193,76241,76289,76337,76385,76433,76481,76529,76577,76625,76673,76721,76770,76818,76866,76914,76962,77010,77058,77106,77154,77202,77250,77298,77346,77394,77442,77490,77538,77586,77634,77682,77730,77778,77826,77874,77922,77970,78018,78066,78114,78162,78210,78258,78306,78354,78402,78450,78498,78546,78594,78642,78690,78738,78786,78834,78881,78929,78977,79025,79073,79121,79169,79217,79265,79313,79361,79409,79457,79504,79552,79600,79648,79696,79744,79792,79840,79887,79935,79983,80031,80079,80127,80175,80223,80270,80318,80366,80414,80462,80510,80557,80605,80653,80701,80749,80797,80844,80892,80940,80988,81036,81083,81131,81179,81227,81275,81322,81370,81418,81466,81514,81561,81609,81657,81705,81752,81800,81848,81896,81943,81991,82039,82087,82134,82182,82230,82278,82325,82373,82421,82468,82516,82564,82612,82659,82707,82755,82802,82850,82898,82945,82993,83041,83088,83136,83184,83231,83279,83327,83374,83422,83470,83517,83565,83613,83660,83708,83756,83803,83851,83898,83946,83994,84041,84089,84136,84184,84232,84279,84327,84374,84422,84470,84517,84565,84612,84660,84708,84755,84803,84850,84898,84945,84993,85040,85088,85136,85183,85231,85278,85326,85373,85421,85468,85516,85563,85611,85658,85706,85753,85801,85848,85896,85943,85991,86038,86086,86133,86181,86228,86276,86323,86371,86418,86465,86513,86560,86608,86655,86703,86750,86798,86845,86892,86940,86987,87035,87082,87129,87177,87224,87272,87319,87366,87414,87461,87509,87556,87603,87651,87698,87745,87793,87840,87888,87935,87982,88030,88077,88124,88172,88219,88266,88314,88361,88408,88456,88503,88550,88598,88645,88692,88739,88787,88834,88881,88929,88976,89023,89070,89118,89165,89212,89260,89307,89354,89401,89449,89496,89543,89590,89638,89685,89732,89779,89826,89874,89921,89968,90015,90063,90110,90157,90204,90251,90299,90346,90393,90440,90487,90534,90582,90629,90676,90723,90770,90817,90865,90912,90959,91006,91053,91100,91147,91195,91242,91289,91336,91383,91430,91477,91524,91571,91619,91666,91713,91760,91807,91854,91901,91948,91995,92042,92089,92136,92183,92230,92278,92325,92372,92419,92466,92513,92560,92607,92654,92701,92748,92795,92842,92889,92936,92983,93030,93077,93124,93171,93218,93265,93312,93359,93406,93453,93500,93547,93594,93640,93687,93734,93781,93828,93875,93922,93969,94016,94063,94110,94157,94204,94251,94297,94344,94391,94438,94485,94532,94579,94626,94673,94719,94766,94813,94860,94907,94954,95001,95047,95094,95141,95188,95235,95282,95328,95375,95422,95469,95516,95562,95609,95656,95703,95750,95796,95843,95890,95937,95984,96030,96077,96124,96171,96217,96264,96311,96358,96404,96451,96498,96545,96591,96638,96685,96732,96778,96825,96872,96918,96965,97012,97058,97105,97152,97199,97245,97292,97339,97385,97432,97479,97525,97572,97619,97665,97712,97758,97805,97852,97898,97945,97992,98038,98085,98131,98178,98225,98271,98318,98364,98411,98458,98504,98551,98597,98644,98691,98737,98784,98830,98877,98923,98970,99016,99063,99110,99156,99203,99249,99296,99342,99389,99435,99482,99528,99575,99621,99668,99714,99761,99807,99854,99900,99947,99993,100039,100086,100132,100179,100225,100272,100318,100365,100411,100457,100504,100550,100597,100643,100690,100736,100782,100829,100875,100922,100968,101014,101061,101107,101153,101200,101246,101293,101339,101385,101432,101478,101524,101571,101617,101663,101710,101756,101802,101849,101895,101941,101988,102034,102080,102126,102173,102219,102265,102312,102358,102404,102450,102497,102543,102589,102635,102682,102728,102774,102820,102867,102913,102959,103005,103052,103098,103144,103190,103236,103283,103329,103375,103421,103467,103514,103560,103606,103652,103698,103744,103791,103837,103883,103929,103975,104021,104067,104114,104160,104206,104252,104298,104344,104390,104436,104483,104529,104575,104621,104667,104713,104759,104805,104851,104897,104943,104989,105035,105082,105128,105174,105220,105266,105312,105358,105404,105450,105496,105542,105588,105634,105680,105726,105772,105818,105864,105910,105956,106002,106048,106094,106140,106186,106232,106278,106323,106369,106415,106461,106507,106553,106599,106645,106691,106737,106783,106829,106875,106920,106966,107012,107058,107104,107150,107196,107242,107287,107333,107379,107425,107471,107517,107563,107608,107654,107700,107746,107792,107838,107883,107929,107975,108021,108067,108112,108158,108204,108250,108295,108341,108387,108433,108479,108524,108570,108616,108662,108707,108753,108799,108845,108890,108936,108982,109027,109073,109119,109165,109210,109256,109302,109347,109393,109439,109484,109530,109576,109621,109667,109713,109758,109804,109850,109895,109941,109986,110032,110078,110123,110169,110215,110260,110306,110351,110397,110443,110488,110534,110579,110625,110670,110716,110762,110807,110853,110898,110944,110989,111035,111080,111126,111171,111217,111262,111308,111353,111399,111444,111490,111535,111581,111626,111672,111717,111763,111808,111854,111899,111945,111990,112036,112081,112126,112172,112217,112263,112308,112354,112399,112444,112490,112535,112581,112626,112671,112717,112762,112808,112853,112898,112944,112989,113034,113080,113125,113170,113216,113261,113306,113352,113397,113442,113488,113533,113578,113624,113669,113714,113759,113805,113850,113895,113941,113986,114031,114076,114122,114167,114212,114257,114303,114348,114393,114438,114483,114529,114574,114619,114664,114710,114755,114800,114845,114890,114935,114981,115026,115071,115116,115161,115206,115252,115297,115342,115387,115432,115477,115522,115567,115613,115658,115703,115748,115793,115838,115883,115928,115973,116018,116064,116109,116154,116199,116244,116289,116334,116379,116424,116469,116514,116559,116604,116649,116694,116739,116784,116829,116874,116919,116964,117009,117054,117099,117144,117189,117234,117279,117324,117369,117414,117459,117504,117549,117593,117638,117683,117728,117773,117818,117863,117908,117953,117998,118042,118087,118132,118177,118222,118267,118312,118357,118401,118446,118491,118536,118581,118626,118670,118715,118760,118805,118850,118894,118939,118984,119029,119074,119118,119163,119208,119253,119297,119342,119387,119432,119476,119521,119566,119611,119655,119700,119745,119790,119834,119879,119924,119968,120013,120058,120102,120147,120192,120236,120281,120326,120370,120415,120460,120504,120549,120594,120638,120683,120727,120772,120817,120861,120906,120950,120995,121040,121084,121129,121173,121218,121263,121307,121352,121396,121441,121485,121530,121574,121619,121663,121708,121752,121797,121842,121886,121931,121975,122019,122064,122108,122153,122197,122242,122286,122331,122375,122420,122464,122509,122553,122597,122642,122686,122731,122775,122820,122864,122908,122953,122997,123042,123086,123130,123175,123219,123263,123308,123352,123396,123441,123485,123529,123574,123618,123662,123707,123751,123795,123840,123884,123928,123973,124017,124061,124105,124150,124194,124238,124283,124327,124371,124415,124460,124504,124548,124592,124636,124681,124725,124769,124813,124857,124902,124946,124990,125034,125078,125123,125167,125211,125255,125299,125343,125388,125432,125476,125520,125564,125608,125652,125696,125741,125785,125829,125873,125917,125961,126005,126049,126093,126137,126181,126225,126269,126314,126358,126402,126446,126490,126534,126578,126622,126666,126710,126754,126798,126842,126886,126930,126974,127018,127062,127106,127150,127193,127237,127281,127325,127369,127413,127457,127501,127545,127589,127633,127677,127721,127764,127808,127852,127896,127940,127984,128028,128072,128115,128159,128203,128247,128291,128335,128378,128422,128466,128510,128554,128598,128641,128685,128729,128773,128816,128860,128904,128948,128992,129035,129079,129123,129167,129210,129254,129298,129341,129385,129429,129473,129516,129560,129604,129647,129691,129735,129778,129822,129866,129909,129953,129997,130040,130084,130128,130171,130215,130259,130302,130346,130389,130433,130477,130520,130564,130607,130651,130695,130738,130782,130825,130869,130912,130956,130999,131043,131087,131130,131174,131217,131261,131304,131348,131391,131435,131478,131522,131565,131609,131652,131695,131739,131782,131826,131869,131913,131956,132000,132043,132086,132130,132173,132217,132260,132303,132347,132390,132434,132477,132520,132564,132607,132650,132694,132737,132780,132824,132867,132910,132954,132997,133040,133084,133127,133170,133214,133257,133300,133343,133387,133430,133473,133517,133560,133603,133646,133690,133733,133776,133819,133862,133906,133949,133992,134035,134078,134122,134165,134208,134251,134294,134338,134381,134424,134467,134510,134553,134596,134640,134683,134726,134769,134812,134855,134898,134941,134984,135028,135071,135114,135157,135200,135243,135286,135329,135372,135415,135458,135501,135544,135587,135630,135673,135716,135759,135802,135845,135888,135931,135974,136017,136060,136103,136146,136189,136232,136275,136318,136361,136404,136447,136490,136532,136575,136618,136661,136704,136747,136790,136833,136876,136918,136961,137004,137047,137090,137133,137176,137218,137261,137304,137347,137390,137432,137475,137518,137561,137604,137646,137689,137732,137775,137817,137860,137903,137946,137988,138031,138074,138117,138159,138202,138245,138288,138330,138373,138416,138458,138501,138544,138586,138629,138672,138714,138757,138800,138842,138885,138927,138970,139013,139055,139098,139141,139183,139226,139268,139311,139353,139396,139439,139481,139524,139566,139609,139651,139694,139736,139779,139821,139864,139907,139949,139992,140034,140077,140119,140161,140204,140246,140289,140331,140374,140416,140459,140501,140544,140586,140628,140671,140713,140756,140798,140840,140883,140925,140968,141010,141052,141095,141137,141179,141222,141264,141306,141349,141391,141433,141476,141518,141560,141603,141645,141687,141730,141772,141814,141856,141899,141941,141983,142025,142068,142110,142152,142194,142237,142279,142321,142363,142405,142448,142490,142532,142574,142616,142659,142701,142743,142785,142827,142869,142912,142954,142996,143038,143080,143122,143164,143206,143248,143291,143333,143375,143417,143459,143501,143543,143585,143627,143669,143711,143753,143795,143837,143879,143921,143963,144005,144047,144089,144131,144173,144215,144257,144299,144341,144383,144425,144467,144509,144551,144593,144635,144677,144719,144761,144802,144844,144886,144928,144970,145012,145054,145096,145137,145179,145221,145263,145305,145347,145389,145430,145472,145514,145556,145598,145639,145681,145723,145765,145807,145848,145890,145932,145974,146015,146057,146099,146141,146182,146224,146266,146307,146349,146391,146433,146474,146516,146558,146599,146641,146683,146724,146766,146808,146849,146891,146932,146974,147016,147057,147099,147141,147182,147224,147265,147307,147348,147390,147432,147473,147515,147556,147598,147639,147681,147722,147764,147805,147847,147888,147930,147971,148013,148054,148096,148137,148179,148220,148262,148303,148345,148386,148428,148469,148510,148552,148593,148635,148676,148717,148759,148800,148842,148883,148924,148966,149007,149048,149090,149131,149172,149214,149255,149296,149338,149379,149420,149462,149503,149544,149585,149627,149668,149709,149751,149792,149833,149874,149916,149957,149998,150039,150080,150122,150163,150204,150245,150286,150328,150369,150410,150451,150492,150533,150575,150616,150657,150698,150739,150780,150821,150862,150904,150945,150986,151027,151068,151109,151150,151191,151232,151273,151314,151355,151396,151437,151478,151519,151560,151601,151642,151683,151724,151765,151806,151847,151888,151929,151970,152011,152052,152093,152134,152175,152216,152257,152298,152339,152380,152421,152461,152502,152543,152584,152625,152666,152707,152748,152788,152829,152870,152911,152952,152993,153033,153074,153115,153156,153197,153237,153278,153319,153360,153400,153441,153482,153523,153563,153604,153645,153686,153726,153767,153808,153848,153889,153930,153970,154011,154052,154093,154133,154174,154214,154255,154296,154336,154377,154418,154458,154499,154539,154580,154621,154661,154702,154742,154783,154824,154864,154905,154945,154986,155026,155067,155107,155148,155188,155229,155269,155310,155350,155391,155431,155472,155512,155553,155593,155634,155674,155715,155755,155795,155836,155876,155917,155957,155997,156038,156078,156119,156159,156199,156240,156280,156320,156361,156401,156441,156482,156522,156562,156603,156643,156683,156724,156764,156804,156845,156885,156925,156965,157006,157046,157086,157126,157167,157207,157247,157287,157327,157368,157408,157448,157488,157528,157569,157609,157649,157689,157729,157769,157809,157850,157890,157930,157970,158010,158050,158090,158130,158170,158211,158251,158291,158331,158371,158411,158451,158491,158531,158571,158611,158651,158691,158731,158771,158811,158851,158891,158931,158971,159011,159051,159091,159131,159171,159211,159251,159291,159330,159370,159410,159450,159490,159530,159570,159610,159650,159689,159729,159769,159809,159849,159889,159929,159968,160008,160048,160088,160128,160167,160207,160247,160287,160327,160366,160406,160446,160486,160525,160565,160605,160644,160684,160724,160764,160803,160843,160883,160922,160962,161002,161041,161081,161121,161160,161200,161240,161279,161319,161359,161398,161438,161477,161517,161557,161596,161636,161675,161715,161754,161794,161833,161873,161913,161952,161992,162031,162071,162110,162150,162189,162229,162268,162308,162347,162386,162426,162465,162505,162544,162584,162623,162663,162702,162741,162781,162820,162860,162899,162938,162978,163017,163056,163096,163135,163174,163214,163253,163292,163332,163371,163410,163450,163489,163528,163568,163607,163646,163685,163725,163764,163803,163842,163882,163921,163960,163999,164039,164078,164117,164156,164195,164234,164274,164313,164352,164391,164430,164469,164509,164548,164587,164626,164665,164704,164743,164782,164821,164861,164900,164939,164978,165017,165056,165095,165134,165173,165212,165251,165290,165329,165368,165407,165446,165485,165524,165563,165602,165641,165680,165719,165758,165797,165836,165875,165914,165952,165991,166030,166069,166108,166147,166186,166225,166264,166302,166341,166380,166419,166458,166497,166535,166574,166613,166652,166691,166729,166768,166807,166846,166885,166923,166962,167001,167040,167078,167117,167156,167194,167233,167272,167311,167349,167388,167427,167465,167504,167543,167581,167620,167659,167697,167736,167774,167813,167852,167890,167929,167968,168006,168045,168083,168122,168160,168199,168238,168276,168315,168353,168392,168430,168469,168507,168546,168584,168623,168661,168700,168738,168777,168815,168853,168892,168930,168969,169007,169046,169084,169122,169161,169199,169238,169276,169314,169353,169391,169430,169468,169506,169545,169583,169621,169660,169698,169736,169774,169813,169851,169889,169928,169966,170004,170042,170081,170119,170157,170195,170234,170272,170310,170348,170386,170425,170463,170501,170539,170577,170616,170654,170692,170730,170768,170806,170844,170883,170921,170959,170997,171035,171073,171111,171149,171187,171225,171263,171301,171339,171378,171416,171454,171492,171530,171568,171606,171644,171682,171720,171758,171796,171834,171871,171909,171947,171985,172023,172061,172099,172137,172175,172213,172251,172289,172326,172364,172402,172440,172478,172516,172554,172591,172629,172667,172705,172743,172781,172818,172856,172894,172932,172969,173007,173045,173083,173121,173158,173196,173234,173271,173309,173347,173385,173422,173460,173498,173535,173573,173611,173648,173686,173724,173761,173799,173837,173874,173912,173949,173987,174025,174062,174100,174137,174175,174212,174250,174288,174325,174363,174400,174438,174475,174513,174550,174588,174625,174663,174700,174738,174775,174813,174850,174887,174925,174962,175000,175037,175075,175112,175149,175187,175224,175262,175299,175336,175374,175411,175448,175486,175523,175560,175598,175635,175672,175710,175747,175784,175822,175859,175896,175933,175971,176008,176045,176082,176120,176157,176194,176231,176268,176306,176343,176380,176417,176454,176492,176529,176566,176603,176640,176677,176714,176752,176789,176826,176863,176900,176937,176974,177011,177048,177085,177123,177160,177197,177234,177271,177308,177345,177382,177419,177456,177493,177530,177567,177604,177641,177678,177715,177752,177788,177825,177862,177899,177936,177973,178010,178047,178084,178121,178158,178194,178231,178268,178305,178342,178379,178415,178452,178489,178526,178563,178600,178636,178673,178710,178747,178783,178820,178857,178894,178930,178967,179004,179041,179077,179114,179151,179187,179224,179261,179297,179334,179371,179407,179444,179481,179517,179554,179591,179627,179664,179700,179737,179774,179810,179847,179883,179920,179956,179993,180029,180066,180103,180139,180176,180212,180249,180285,180322,180358,180395,180431,180467,180504,180540,180577,180613,180650,180686,180723,180759,180795,180832,180868,180904,180941,180977,181014,181050,181086,181123,181159,181195,181232,181268,181304,181341,181377,181413,181449,181486,181522,181558,181594,181631,181667,181703,181739,181776,181812,181848,181884,181920,181957,181993,182029,182065,182101,182137,182174,182210,182246,182282,182318,182354,182390,182426,182463,182499,182535,182571,182607,182643,182679,182715,182751,182787,182823,182859,182895,182931,182967,183003,183039,183075,183111,183147,183183,183219,183255,183291,183327,183363,183399,183435,183470,183506,183542,183578,183614,183650,183686,183722,183757,183793,183829,183865,183901,183937,183972,184008,184044,184080,184116,184151,184187,184223,184259,184294,184330,184366,184402,184437,184473,184509,184545,184580,184616,184652,184687,184723,184759,184794,184830,184866,184901,184937,184972,185008,185044,185079,185115,185150,185186,185222,185257,185293,185328,185364,185399,185435,185470,185506,185541,185577,185612,185648,185683,185719,185754,185790,185825,185861,185896,185932,185967,186002,186038,186073,186109,186144,186179,186215,186250,186286,186321,186356,186392,186427,186462,186498,186533,186568,186604,186639,186674,186710,186745,186780,186815,186851,186886,186921,186956,186992,187027,187062,187097,187132,187168,187203,187238,187273,187308,187343,187379,187414,187449,187484,187519,187554,187589,187625,187660,187695,187730,187765,187800,187835,187870,187905,187940,187975,188010,188045,188080,188115,188150,188185,188220,188255,188290,188325,188360,188395,188430,188465,188500,188535,188570,188605,188640,188675,188709,188744,188779,188814,188849,188884,188919,188954,188988,189023,189058,189093,189128,189162,189197,189232,189267,189302,189336,189371,189406,189441,189475,189510,189545,189580,189614,189649,189684,189718,189753,189788,189822,189857,189892,189926,189961,189996,190030,190065,190099,190134,190169,190203,190238,190272,190307,190342,190376,190411,190445,190480,190514,190549,190583,190618,190652,190687,190721,190756,190790,190825,190859,190894,190928,190963,190997,191031,191066,191100,191135,191169,191203,191238,191272,191307,191341,191375,191410,191444,191478,191513,191547,191581,191616,191650,191684,191718,191753,191787,191821,191856,191890,191924,191958,191992,192027,192061,192095,192129,192164,192198,192232,192266,192300,192334,192369,192403,192437,192471,192505,192539,192573,192607,192641,192676,192710,192744,192778,192812,192846,192880,192914,192948,192982,193016,193050,193084,193118,193152,193186,193220,193254,193288,193322,193356,193390,193424,193458,193492,193525,193559,193593,193627,193661,193695,193729,193763,193796,193830,193864,193898,193932,193966,193999,194033,194067,194101,194135,194168,194202,194236,194270,194303,194337,194371,194405,194438,194472,194506,194539,194573,194607,194640,194674,194708,194741,194775,194809,194842,194876,194910,194943,194977,195010,195044,195078,195111,195145,195178,195212,195245,195279,195312,195346,195379,195413,195446,195480,195513,195547,195580,195614,195647,195681,195714,195748,195781,195815,195848,195881,195915,195948,195982,196015,196048,196082,196115,196148,196182,196215,196248,196282,196315,196348,196382,196415,196448,196481,196515,196548,196581,196615,196648,196681,196714,196747,196781,196814,196847,196880,196913,196947,196980,197013,197046,197079,197112,197146,197179,197212,197245,197278,197311,197344,197377,197410,197443,197476,197510,197543,197576,197609,197642,197675,197708,197741,197774,197807,197840,197873,197906,197939,197972,198004,198037,198070,198103,198136,198169,198202,198235,198268,198301,198334,198366,198399,198432,198465,198498,198531,198563,198596,198629,198662,198695,198727,198760,198793,198826,198858,198891,198924,198957,198989,199022,199055,199088,199120,199153,199186,199218,199251,199284,199316,199349,199382,199414,199447,199479,199512,199545,199577,199610,199642,199675,199708,199740,199773,199805,199838,199870,199903,199935,199968,200000,200033,200065,200098,200130,200163,200195,200228,200260,200292,200325,200357,200390,200422,200454,200487,200519,200552,200584,200616,200649,200681,200713,200746,200778,200810,200843,200875,200907,200940,200972,201004,201036,201069,201101,201133,201165,201198,201230,201262,201294,201326,201359,201391,201423,201455,201487,201519,201552,201584,201616,201648,201680,201712,201744,201776,201808,201841,201873,201905,201937,201969,202001,202033,202065,202097,202129,202161,202193,202225,202257,202289,202321,202353,202385,202417,202449,202481,202512,202544,202576,202608,202640,202672,202704,202736,202768,202799,202831,202863,202895,202927,202959,202990,203022,203054,203086,203118,203149,203181,203213,203245,203276,203308,203340,203372,203403,203435,203467,203498,203530,203562,203593,203625,203657,203688,203720,203752,203783,203815,203846,203878,203910,203941,203973,204004,204036,204067,204099,204131,204162,204194,204225,204257,204288,204320,204351,204383,204414,204446,204477,204508,204540,204571,204603,204634,204666,204697,204728,204760,204791,204823,204854,204885,204917,204948,204979,205011,205042,205073,205105,205136,205167,205198,205230,205261,205292,205324,205355,205386,205417,205448,205480,205511,205542,205573,205604,205636,205667,205698,205729,205760,205791,205823,205854,205885,205916,205947,205978,206009,206040,206071,206102,206133,206165,206196,206227,206258,206289,206320,206351,206382,206413,206444,206475,206506,206537,206567,206598,206629,206660,206691,206722,206753,206784,206815,206846,206877,206907,206938,206969,207000,207031,207062,207092,207123,207154,207185,207216,207246,207277,207308,207339,207370,207400,207431,207462,207492,207523,207554,207585,207615,207646,207677,207707,207738,207769,207799,207830,207861,207891,207922,207952,207983,208014,208044,208075,208105,208136,208166,208197,208228,208258,208289,208319,208350,208380,208411,208441,208472,208502,208533,208563,208593,208624,208654,208685,208715,208746,208776,208806,208837,208867,208897,208928,208958,208989,209019,209049,209080,209110,209140,209170,209201,209231,209261,209292,209322,209352,209382,209413,209443,209473,209503,209534,209564,209594,209624,209654,209684,209715,209745,209775,209805,209835,209865,209895,209926,209956,209986,210016,210046,210076,210106,210136,210166,210196,210226,210256,210286,210316,210346,210376,210406,210436,210466,210496,210526,210556,210586,210616,210646,210676,210706,210736,210765,210795,210825,210855,210885,210915,210945,210974,211004,211034,211064,211094,211124,211153,211183,211213,211243,211272,211302,211332,211362,211391,211421,211451,211481,211510,211540,211570,211599,211629,211659,211688,211718,211748,211777,211807,211836,211866,211896,211925,211955,211984,212014,212043,212073,212103,212132,212162,212191,212221,212250,212280,212309,212339,212368,212398,212427,212456,212486,212515,212545,212574,212604,212633,212662,212692,212721,212751,212780,212809,212839,212868,212897,212927,212956,212985,213015,213044,213073,213102,213132,213161,213190,213219,213249,213278,213307,213336,213366,213395,213424,213453,213482,213511,213541,213570,213599,213628,213657,213686,213715,213745,213774,213803,213832,213861,213890,213919,213948,213977,214006,214035,214064,214093,214122,214151,214180,214209,214238,214267,214296,214325,214354,214383,214412,214441,214470,214498,214527,214556,214585,214614,214643,214672,214701,214729,214758,214787,214816,214845,214873,214902,214931,214960,214989,215017,215046,215075,215104,215132,215161,215190,215218,215247,215276,215304,215333,215362,215390,215419,215448,215476,215505,215534,215562,215591,215619,215648,215677,215705,215734,215762,215791,215819,215848,215876,215905,215933,215962,215990,216019,216047,216076,216104,216133,216161,216190,216218,216246,216275,216303,216332,216360,216388,216417,216445,216473,216502,216530,216558,216587,216615,216643,216672,216700,216728,216757,216785,216813,216841,216870,216898,216926,216954,216982,217011,217039,217067,217095,217123,217152,217180,217208,217236,217264,217292,217320,217348,217377,217405,217433,217461,217489,217517,217545,217573,217601,217629,217657,217685,217713,217741,217769,217797,217825,217853,217881,217909,217937,217965,217993,218021,218049,218076,218104,218132,218160,218188,218216,218244,218271,218299,218327,218355,218383,218411,218438,218466,218494,218522,218549,218577,218605,218633,218660,218688,218716,218744,218771,218799,218827,218854,218882,218910,218937,218965,218993,219020,219048,219075,219103,219131,219158,219186,219213,219241,219268,219296,219324,219351,219379,219406,219434,219461,219489,219516,219544,219571,219598,219626,219653,219681,219708,219736,219763,219790,219818,219845,219873,219900,219927,219955,219982,220009,220037,220064,220091,220119,220146,220173,220200,220228,220255,220282,220309,220337,220364,220391,220418,220446,220473,220500,220527,220554,220581,220609,220636,220663,220690,220717,220744,220771,220798,220826,220853,220880,220907,220934,220961,220988,221015,221042,221069,221096,221123,221150,221177,221204,221231,221258,221285,221312,221339,221366,221393,221419,221446,221473,221500,221527,221554,221581,221608,221634,221661,221688,221715,221742,221769,221795,221822,221849,221876,221903,221929,221956,221983,222010,222036,222063,222090,222116,222143,222170,222196,222223,222250,222276,222303,222330,222356,222383,222410,222436,222463,222489,222516,222542,222569,222596,222622,222649,222675,222702,222728,222755,222781,222808,222834,222861,222887,222914,222940,222966,222993,223019,223046,223072,223099,223125,223151,223178,223204,223230,223257,223283,223309,223336,223362,223388,223415,223441,223467,223493,223520,223546,223572,223599,223625,223651,223677,223703,223730,223756,223782,223808,223834,223860,223887,223913,223939,223965,223991,224017,224043,224069,224096,224122,224148,224174,224200,224226,224252,224278,224304,224330,224356,224382,224408,224434,224460,224486,224512,224538,224564,224590,224615,224641,224667,224693,224719,224745,224771,224797,224823,224848,224874,224900,224926,224952,224978,225003,225029,225055,225081,225106,225132,225158,225184,225209,225235,225261,225287,225312,225338,225364,225389,225415,225441,225466,225492,225517,225543,225569,225594,225620,225646,225671,225697,225722,225748,225773,225799,225824,225850,225875,225901,225926,225952,225977,226003,226028,226054,226079,226105,226130,226156,226181,226206,226232,226257,226283,226308,226333,226359,226384,226409,226435,226460,226485,226511,226536,226561,226586,226612,226637,226662,226688,226713,226738,226763,226788,226814,226839,226864,226889,226914,226940,226965,226990,227015,227040,227065,227090,227115,227141,227166,227191,227216,227241,227266,227291,227316,227341,227366,227391,227416,227441,227466,227491,227516,227541,227566,227591,227616,227641,227666,227691,227716,227740,227765,227790,227815,227840,227865,227890,227914,227939,227964,227989,228014,228039,228063,228088,228113,228138,228162,228187,228212,228237,228261,228286,228311,228335,228360,228385,228409,228434,228459,228483,228508,228533,228557,228582,228607,228631,228656,228680,228705,228729,228754,228779,228803,228828,228852,228877,228901,228926,228950,228975,228999,229024,229048,229072,229097,229121,229146,229170,229194,229219,229243,229268,229292,229316,229341,229365,229389,229414,229438,229462,229487,229511,229535,229560,229584,229608,229632,229657,229681,229705,229729,229753,229778,229802,229826,229850,229874,229898,229923,229947,229971,229995,230019,230043,230067,230091,230116,230140,230164,230188,230212,230236,230260,230284,230308,230332,230356,230380,230404,230428,230452,230476,230500,230524,230548,230571,230595,230619,230643,230667,230691,230715,230739,230762,230786,230810,230834,230858,230882,230905,230929,230953,230977,231001,231024,231048,231072,231096,231119,231143,231167,231190,231214,231238,231261,231285,231309,231332,231356,231380,231403,231427,231450,231474,231498,231521,231545,231568,231592,231615,231639,231663,231686,231710,231733,231757,231780,231804,231827,231850,231874,231897,231921,231944,231968,231991,232014,232038,232061,232085,232108,232131,232155,232178,232201,232225,232248,232271,232295,232318,232341,232364,232388,232411,232434,232457,232481,232504,232527,232550,232574,232597,232620,232643,232666,232689,232713,232736,232759,232782,232805,232828,232851,232874,232897,232920,232944,232967,232990,233013,233036,233059,233082,233105,233128,233151,233174,233197,233220,233243,233265,233288,233311,233334,233357,233380,233403,233426,233449,233472,233494,233517,233540,233563,233586,233609,233631,233654,233677,233700,233722,233745,233768,233791,233813,233836,233859,233882,233904,233927,233950,233972,233995,234018,234040,234063,234086,234108,234131,234153,234176,234199,234221,234244,234266,234289,234311,234334,234356,234379,234401,234424,234446,234469,234491,234514,234536,234559,234581,234604,234626,234649,234671,234693,234716,234738,234760,234783,234805,234828,234850,234872,234894,234917,234939,234961,234984,235006,235028,235050,235073,235095,235117,235139,235162,235184,235206,235228,235250,235273,235295,235317,235339,235361,235383,235405,235428,235450,235472,235494,235516,235538,235560,235582,235604,235626,235648,235670,235692,235714,235736,235758,235780,235802,235824,235846,235868,235890,235912,235934,235956,235978,235999,236021,236043,236065,236087,236109,236131,236152,236174,236196,236218,236240,236261,236283,236305,236327,236348,236370,236392,236414,236435,236457,236479,236500,236522,236544,236565,236587,236609,236630,236652,236674,236695,236717,236738,236760,236782,236803,236825,236846,236868,236889,236911,236932,236954,236975,236997,237018,237040,237061,237083,237104,237126,237147,237168,237190,237211,237233,237254,237275,237297,237318,237339,237361,237382,237403,237425,237446,237467,237489,237510,237531,237552,237574,237595,237616,237637,237659,237680,237701,237722,237743,237765,237786,237807,237828,237849,237870,237891,237913,237934,237955,237976,237997,238018,238039,238060,238081,238102,238123,238144,238165,238186,238207,238228,238249,238270,238291,238312,238333,238354,238375,238396,238417,238437,238458,238479,238500,238521,238542,238563,238583,238604,238625,238646,238667,238688,238708,238729,238750,238771,238791,238812,238833,238853,238874,238895,238916,238936,238957,238978,238998,239019,239040,239060,239081,239101,239122,239143,239163,239184,239204,239225,239245,239266,239287,239307,239328,239348,239369,239389,239410,239430,239450,239471,239491,239512,239532,239553,239573,239593,239614,239634,239655,239675,239695,239716,239736,239756,239777,239797,239817,239838,239858,239878,239898,239919,239939,239959,239979,240000,240020,240040,240060,240080,240101,240121,240141,240161,240181,240201,240221,240242,240262,240282,240302,240322,240342,240362,240382,240402,240422,240442,240462,240482,240502,240522,240542,240562,240582,240602,240622,240642,240662,240682,240702,240722,240742,240762,240781,240801,240821,240841,240861,240881,240901,240920,240940,240960,240980,241000,241019,241039,241059,241079,241098,241118,241138,241157,241177,241197,241217,241236,241256,241276,241295,241315,241334,241354,241374,241393,241413,241433,241452,241472,241491,241511,241530,241550,241569,241589,241608,241628,241647,241667,241686,241706,241725,241745,241764,241784,241803,241822,241842,241861,241881,241900,241919,241939,241958,241977,241997,242016,242035,242055,242074,242093,242112,242132,242151,242170,242189,242209,242228,242247,242266,242286,242305,242324,242343,242362,242381,242401,242420,242439,242458,242477,242496,242515,242534,242553,242572,242591,242611,242630,242649,242668,242687,242706,242725,242744,242763,242782,242800,242819,242838,242857,242876,242895,242914,242933,242952,242971,242990,243008,243027,243046,243065,243084,243103,243121,243140,243159,243178,243196,243215,243234,243253,243271,243290,243309,243328,243346,243365,243384,243402,243421,243440,243458,243477,243496,243514,243533,243551,243570,243588,243607,243626,243644,243663,243681,243700,243718,243737,243755,243774,243792,243811,243829,243848,243866,243885,243903,243921,243940,243958,243977,243995,244013,244032,244050,244068,244087,244105,244123,244142,244160,244178,244197,244215,244233,244251,244270,244288,244306,244324,244343,244361,244379,244397,244415,244433,244452,244470,244488,244506,244524,244542,244560,244578,244597,244615,244633,244651,244669,244687,244705,244723,244741,244759,244777,244795,244813,244831,244849,244867,244885,244903,244921,244938,244956,244974,244992,245010,245028,245046,245064,245081,245099,245117,245135,245153,245171,245188,245206,245224,245242,245259,245277,245295,245313,245330,245348,245366,245383,245401,245419,245436,245454,245472,245489,245507,245525,245542,245560,245577,245595,245613,245630,245648,245665,245683,245700,245718,245735,245753,245770,245788,245805,245823,245840,245858,245875,245892,245910,245927,245945,245962,245979,245997,246014,246032,246049,246066,246084,246101,246118,246136,246153,246170,246187,246205,246222,246239,246256,246274,246291,246308,246325,246342,246360,246377,246394,246411,246428,246445,246463,246480,246497,246514,246531,246548,246565,246582,246599,246616,246633,246650,246667,246684,246701,246718,246735,246752,246769,246786,246803,246820,246837,246854,246871,246888,246905,246922,246938,246955,246972,246989,247006,247023,247040,247056,247073,247090,247107,247123,247140,247157,247174,247190,247207,247224,247241,247257,247274,247291,247307,247324,247341,247357,247374,247391,247407,247424,247440,247457,247474,247490,247507,247523,247540,247556,247573,247589,247606,247622,247639,247655,247672,247688,247705,247721,247738,247754,247771,247787,247803,247820,247836,247853,247869,247885,247902,247918,247934,247951,247967,247983,248000,248016,248032,248048,248065,248081,248097,248113,248130,248146,248162,248178,248194,248211,248227,248243,248259,248275,248291,248307,248323,248340,248356,248372,248388,248404,248420,248436,248452,248468,248484,248500,248516,248532,248548,248564,248580,248596,248612,248628,248644,248660,248676,248691,248707,248723,248739,248755,248771,248787,248803,248818,248834,248850,248866,248882,248897,248913,248929,248945,248960,248976,248992,249008,249023,249039,249055,249070,249086,249102,249117,249133,249149,249164,249180,249195,249211,249227,249242,249258,249273,249289,249304,249320,249335,249351,249367,249382,249398,249413,249428,249444,249459,249475,249490,249506,249521,249536,249552,249567,249583,249598,249613,249629,249644,249659,249675,249690,249705,249721,249736,249751,249766,249782,249797,249812,249827,249843,249858,249873,249888,249903,249919,249934,249949,249964,249979,249994,250009,250025,250040,250055,250070,250085,250100,250115,250130,250145,250160,250175,250190,250205,250220,250235,250250,250265,250280,250295,250310,250325,250340,250355,250370,250385,250399,250414,250429,250444,250459,250474,250489,250503,250518,250533,250548,250562,250577,250592,250607,250622,250636,250651,250666,250680,250695,250710,250724,250739,250754,250768,250783,250798,250812,250827,250842,250856,250871,250885,250900,250914,250929,250944,250958,250973,250987,251002,251016,251031,251045,251060,251074,251088,251103,251117,251132,251146,251161,251175,251189,251204,251218,251232,251247,251261,251275,251290,251304,251318,251333,251347,251361,251375,251390,251404,251418,251432,251447,251461,251475,251489,251503,251518,251532,251546,251560,251574,251588,251602,251617,251631,251645,251659,251673,251687,251701,251715,251729,251743,251757,251771,251785,251799,251813,251827,251841,251855,251869,251883,251897,251911,251925,251938,251952,251966,251980,251994,252008,252022,252035,252049,252063,252077,252091,252104,252118,252132,252146,252159,252173,252187,252201,252214,252228,252242,252255,252269,252283,252296,252310,252324,252337,252351,252365,252378,252392,252405,252419,252432,252446,252460,252473,252487,252500,252514,252527,252541,252554,252568,252581,252594,252608,252621,252635,252648,252662,252675,252688,252702,252715,252728,252742,252755,252768,252782,252795,252808,252822,252835,252848,252861,252875,252888,252901,252914,252928,252941,252954,252967,252980,252994,253007,253020,253033,253046,253059,253072,253085,253099,253112,253125,253138,253151,253164,253177,253190,253203,253216,253229,253242,253255,253268,253281,253294,253307,253320,253333,253346,253359,253371,253384,253397,253410,253423,253436,253449,253461,253474,253487,253500,253513,253525,253538,253551,253564,253577,253589,253602,253615,253627,253640,253653,253666,253678,253691,253704,253716,253729,253741,253754,253767,253779,253792,253804,253817,253830,253842,253855,253867,253880,253892,253905,253917,253930,253942,253955,253967,253980,253992,254004,254017,254029,254042,254054,254067,254079,254091,254104,254116,254128,254141,254153,254165,254178,254190,254202,254214,254227,254239,254251,254263,254276,254288,254300,254312,254324,254337,254349,254361,254373,254385,254397,254410,254422,254434,254446,254458,254470,254482,254494,254506,254518,254530,254542,254554,254566,254578,254590,254602,254614,254626,254638,254650,254662,254674,254686,254698,254710,254721,254733,254745,254757,254769,254781,254793,254804,254816,254828,254840,254852,254863,254875,254887,254899,254910,254922,254934,254945,254957,254969,254981,254992,255004,255015,255027,255039,255050,255062,255074,255085,255097,255108,255120,255131,255143,255155,255166,255178,255189,255201,255212,255224,255235,255246,255258,255269,255281,255292,255304,255315,255326,255338,255349,255361,255372,255383,255395,255406,255417,255429,255440,255451,255462,255474,255485,255496,255507,255519,255530,255541,255552,255564,255575,255586,255597,255608,255619,255630,255642,255653,255664,255675,255686,255697,255708,255719,255730,255741,255752,255763,255774,255785,255796,255807,255818,255829,255840,255851,255862,255873,255884,255895,255906,255917,255928,255939,255949,255960,255971,255982,255993,256004,256014,256025,256036,256047,256058,256068,256079,256090,256101,256111,256122,256133,256143,256154,256165,256176,256186,256197,256207,256218,256229,256239,256250,256261,256271,256282,256292,256303,256313,256324,256334,256345,256355,256366,256376,256387,256397,256408,256418,256429,256439,256450,256460,256470,256481,256491,256502,256512,256522,256533,256543,256553,256564,256574,256584,256595,256605,256615,256625,256636,256646,256656,256666,256677,256687,256697,256707,256717,256728,256738,256748,256758,256768,256778,256788,256798,256809,256819,256829,256839,256849,256859,256869,256879,256889,256899,256909,256919,256929,256939,256949,256959,256969,256979,256989,256999,257008,257018,257028,257038,257048,257058,257068,257078,257087,257097,257107,257117,257127,257136,257146,257156,257166,257175,257185,257195,257205,257214,257224,257234,257243,257253,257263,257272,257282,257292,257301,257311,257320,257330,257340,257349,257359,257368,257378,257387,257397,257406,257416,257425,257435,257444,257454,257463,257473,257482,257492,257501,257510,257520,257529,257539,257548,257557,257567,257576,257585,257595,257604,257613,257623,257632,257641,257651,257660,257669,257678,257688,257697,257706,257715,257724,257734,257743,257752,257761,257770,257779,257789,257798,257807,257816,257825,257834,257843,257852,257861,257870,257879,257888,257897,257906,257915,257924,257933,257942,257951,257960,257969,257978,257987,257996,258005,258014,258023,258031,258040,258049,258058,258067,258076,258084,258093,258102,258111,258120,258128,258137,258146,258155,258163,258172,258181,258190,258198,258207,258216,258224,258233,258242,258250,258259,258267,258276,258285,258293,258302,258310,258319,258327,258336,258345,258353,258362,258370,258379,258387,258396,258404,258412,258421,258429,258438,258446,258455,258463,258471,258480,258488,258496,258505,258513,258522,258530,258538,258546,258555,258563,258571,258580,258588,258596,258604,258613,258621,258629,258637,258645,258654,258662,258670,258678,258686,258694,258702,258711,258719,258727,258735,258743,258751,258759,258767,258775,258783,258791,258799,258807,258815,258823,258831,258839,258847,258855,258863,258871,258879,258887,258895,258902,258910,258918,258926,258934,258942,258950,258957,258965,258973,258981,258989,258996,259004,259012,259020,259027,259035,259043,259050,259058,259066,259073,259081,259089,259096,259104,259112,259119,259127,259135,259142,259150,259157,259165,259172,259180,259187,259195,259202,259210,259217,259225,259232,259240,259247,259255,259262,259270,259277,259285,259292,259299,259307,259314,259321,259329,259336,259343,259351,259358,259365,259373,259380,259387,259395,259402,259409,259416,259423,259431,259438,259445,259452,259459,259467,259474,259481,259488,259495,259502,259509,259517,259524,259531,259538,259545,259552,259559,259566,259573,259580,259587,259594,259601,259608,259615,259622,259629,259636,259643,259650,259657,259664,259670,259677,259684,259691,259698,259705,259712,259718,259725,259732,259739,259746,259752,259759,259766,259773,259779,259786,259793,259800,259806,259813,259820,259826,259833,259840,259846,259853,259860,259866,259873,259879,259886,259893,259899,259906,259912,259919,259925,259932,259938,259945,259951,259958,259964,259971,259977,259984,259990,259997,260003,260009,260016,260022,260029,260035,260041,260048,260054,260060,260067,260073,260079,260085,260092,260098,260104,260111,260117,260123,260129,260135,260142,260148,260154,260160,260166,260173,260179,260185,260191,260197,260203,260209,260215,260221,260228,260234,260240,260246,260252,260258,260264,260270,260276,260282,260288,260294,260300,260306,260312,260317,260323,260329,260335,260341,260347,260353,260359,260365,260370,260376,260382,260388,260394,260399,260405,260411,260417,260423,260428,260434,260440,260445,260451,260457,260463,260468,260474,260480,260485,260491,260496,260502,260508,260513,260519,260525,260530,260536,260541,260547,260552,260558,260563,260569,260574,260580,260585,260591,260596,260602,260607,260613,260618,260623,260629,260634,260640,260645,260650,260656,260661,260666,260672,260677,260682,260688,260693,260698,260703,260709,260714,260719,260724,260730,260735,260740,260745,260750,260756,260761,260766,260771,260776,260781,260786,260791,260797,260802,260807,260812,260817,260822,260827,260832,260837,260842,260847,260852,260857,260862,260867,260872,260877,260882,260887,260892,260896,260901,260906,260911,260916,260921,260926,260930,260935,260940,260945,260950,260955,260959,260964,260969,260974,260978,260983,260988,260992,260997,261002,261007,261011,261016,261021,261025,261030,261034,261039,261044,261048,261053,261057,261062,261067,261071,261076,261080,261085,261089,261094,261098,261103,261107,261112,261116,261120,261125,261129,261134,261138,261143,261147,261151,261156,261160,261164,261169,261173,261177,261182,261186,261190,261195,261199,261203,261207,261212,261216,261220,261224,261228,261233,261237,261241,261245,261249,261253,261258,261262,261266,261270,261274,261278,261282,261286,261290,261294,261298,261302,261306,261310,261314,261318,261322,261326,261330,261334,261338,261342,261346,261350,261354,261358,261362,261366,261369,261373,261377,261381,261385,261389,261392,261396,261400,261404,261408,261411,261415,261419,261423,261426,261430,261434,261437,261441,261445,261448,261452,261456,261459,261463,261467,261470,261474,261477,261481,261485,261488,261492,261495,261499,261502,261506,261509,261513,261516,261520,261523,261527,261530,261533,261537,261540,261544,261547,261551,261554,261557,261561,261564,261567,261571,261574,261577,261581,261584,261587,261590,261594,261597,261600,261603,261607,261610,261613,261616,261619,261623,261626,261629,261632,261635,261638,261641,261644,261648,261651,261654,261657,261660,261663,261666,261669,261672,261675,261678,261681,261684,261687,261690,261693,261696,261699,261702,261705,261708,261710,261713,261716,261719,261722,261725,261728,261730,261733,261736,261739,261742,261744,261747,261750,261753,261755,261758,261761,261764,261766,261769,261772,261774,261777,261780,261782,261785,261788,261790,261793,261795,261798,261801,261803,261806,261808,261811,261813,261816,261818,261821,261823,261826,261828,261831,261833,261836,261838,261840,261843,261845,261848,261850,261852,261855,261857,261859,261862,261864,261866,261869,261871,261873,261876,261878,261880,261882,261885,261887,261889,261891,261894,261896,261898,261900,261902,261904,261907,261909,261911,261913,261915,261917,261919,261921,261923,261925,261927,261929,261932,261934,261936,261938,261940,261942,261943,261945,261947,261949,261951,261953,261955,261957,261959,261961,261963,261965,261966,261968,261970,261972,261974,261975,261977,261979,261981,261983,261984,261986,261988,261990,261991,261993,261995,261996,261998,262000,262001,262003,262005,262006,262008,262010,262011,262013,262014,262016,262018,262019,262021,262022,262024,262025,262027,262028,262030,262031,262033,262034,262036,262037,262038,262040,262041,262043,262044,262045,262047,262048,262050,262051,262052,262054,262055,262056,262057,262059,262060,262061,262063,262064,262065,262066,262067,262069,262070,262071,262072,262073,262075,262076,262077,262078,262079,262080,262081,262082,262084,262085,262086,262087,262088,262089,262090,262091,262092,262093,262094,262095,262096,262097,262098,262099,262100,262101,262101,262102,262103,262104,262105,262106,262107,262108,262108,262109,262110,262111,262112,262112,262113,262114,262115,262115,262116,262117,262118,262118,262119,262120,262120,262121,262122,262122,262123,262124,262124,262125,262125,262126,262127,262127,262128,262128,262129,262129,262130,262130,262131,262131,262132,262132,262133,262133,262134,262134,262135,262135,262135,262136,262136,262137,262137,262137,262138,262138,262138,262139,262139,262139,262140,262140,262140,262140,262141,262141,262141,262141,262142,262142,262142,262142,262142,262143,262143,262143,262143,262143,262143,262143,262144,262144,262144,262144,262144,262144,262144,262144,262144,262144,262144,0};
diff --git a/apps/plugins/pdbox/PDa/intern/cos~.c b/apps/plugins/pdbox/PDa/intern/cos~.c
new file mode 100644
index 0000000000..30ec4e49a7
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/cos~.c
@@ -0,0 +1,122 @@
1
2#include <m_pd.h>
3#include <m_fixed.h>
4#include "cos_table.h"
5
6/* ------------------------ cos~ ----------------------------- */
7#define FRAC ((1<<(fix1-ILOGCOSTABSIZE))-1)
8
9static t_class *cos_class;
10
11typedef struct _cos
12{
13 t_object x_obj;
14 float x_f;
15} t_cos;
16
17static void *cos_new(void)
18{
19 t_cos *x = (t_cos *)pd_new(cos_class);
20 outlet_new(&x->x_obj, gensym("signal"));
21 x->x_f = 0;
22 return (x);
23}
24
25static t_int *cos_perform(t_int *w)
26{
27 t_sample *in = (t_sample *)(w[1]);
28 t_sample *out = (t_sample *)(w[2]);
29 int n = (int)(w[3]);
30 t_sample *tab = cos_table;
31 int off;
32 int frac;
33 unsigned int phase;
34
35 while (n--) {
36 phase = *in++;
37 phase &= ((1<<fix1)-1);
38 off = fixtoi((long long)phase<<ILOGCOSTABSIZE);
39
40 frac = phase&(itofix(1)-1);
41 *out = mult(*(tab + off),itofix(1) - frac) +
42 mult(*(tab + off + 1),frac);
43 out++;
44 }
45 return (w+4);
46}
47
48static void cos_dsp(t_cos *x, t_signal **sp)
49{
50 dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
51}
52
53
54void cos_tilde_setup(void)
55{
56 cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
57 sizeof(t_cos), 0, A_DEFFLOAT, 0);
58 CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
59 class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
60 class_sethelpsymbol(cos_class, gensym("osc~-help.pd"));
61}
62
63#include <m_pd.h>
64#include <m_fixed.h>
65#include "cos_table.h"
66
67/* ------------------------ cos~ ----------------------------- */
68#define FRAC ((1<<(fix1-ILOGCOSTABSIZE))-1)
69
70static t_class *cos_class;
71
72typedef struct _cos
73{
74 t_object x_obj;
75 float x_f;
76} t_cos;
77
78static void *cos_new(void)
79{
80 t_cos *x = (t_cos *)pd_new(cos_class);
81 outlet_new(&x->x_obj, gensym("signal"));
82 x->x_f = 0;
83 return (x);
84}
85
86static t_int *cos_perform(t_int *w)
87{
88 t_sample *in = (t_sample *)(w[1]);
89 t_sample *out = (t_sample *)(w[2]);
90 int n = (int)(w[3]);
91 t_sample *tab = cos_table;
92 int off;
93 int frac;
94 unsigned int phase;
95
96 while (n--) {
97 phase = *in++;
98 phase &= ((1<<fix1)-1);
99 off = fixtoi((long long)phase<<ILOGCOSTABSIZE);
100
101 frac = phase&(itofix(1)-1);
102 *out = mult(*(tab + off),itofix(1) - frac) +
103 mult(*(tab + off + 1),frac);
104 out++;
105 }
106 return (w+4);
107}
108
109static void cos_dsp(t_cos *x, t_signal **sp)
110{
111 dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
112}
113
114
115void cos_tilde_setup(void)
116{
117 cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
118 sizeof(t_cos), 0, A_DEFFLOAT, 0);
119 CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
120 class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
121 class_sethelpsymbol(cos_class, gensym("osc~-help.pd"));
122}
diff --git a/apps/plugins/pdbox/PDa/intern/dbtopow~.c b/apps/plugins/pdbox/PDa/intern/dbtopow~.c
new file mode 100644
index 0000000000..92ba76d550
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/dbtopow~.c
@@ -0,0 +1,104 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4#define LOGTEN 2.302585092994
5
6typedef struct dbtopow_tilde
7{
8 t_object x_obj;
9 float x_f;
10} t_dbtopow_tilde;
11
12t_class *dbtopow_tilde_class;
13
14static void *dbtopow_tilde_new(void)
15{
16 t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class);
17 outlet_new(&x->x_obj, gensym("signal"));
18 x->x_f = 0;
19 return (x);
20}
21
22static t_int *dbtopow_tilde_perform(t_int *w)
23{
24 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
25 t_int n = *(t_int *)(w+3);
26 for (; n--; in++, out++)
27 {
28 float f = *in;
29 if (f <= 0) *out = 0;
30 else
31 {
32 if (f > 870)
33 f = 870;
34 *out = exp((LOGTEN * 0.1) * (f-100.));
35 }
36 }
37 return (w + 4);
38}
39
40static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp)
41{
42 post("warning: %s not usable yet",__FUNCTION__);
43 dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
44}
45
46void dbtopow_tilde_setup(void)
47{
48 dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0,
49 sizeof(t_dbtopow_tilde), 0, 0);
50 CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f);
51 class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, gensym("dsp"), 0);
52}
53#include <m_pd.h>
54#include <m_fixed.h>
55
56#define LOGTEN 2.302585092994
57
58typedef struct dbtopow_tilde
59{
60 t_object x_obj;
61 float x_f;
62} t_dbtopow_tilde;
63
64t_class *dbtopow_tilde_class;
65
66static void *dbtopow_tilde_new(void)
67{
68 t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class);
69 outlet_new(&x->x_obj, gensym("signal"));
70 x->x_f = 0;
71 return (x);
72}
73
74static t_int *dbtopow_tilde_perform(t_int *w)
75{
76 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
77 t_int n = *(t_int *)(w+3);
78 for (; n--; in++, out++)
79 {
80 float f = *in;
81 if (f <= 0) *out = 0;
82 else
83 {
84 if (f > 870)
85 f = 870;
86 *out = exp((LOGTEN * 0.1) * (f-100.));
87 }
88 }
89 return (w + 4);
90}
91
92static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp)
93{
94 post("warning: %s not usable yet",__FUNCTION__);
95 dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
96}
97
98void dbtopow_tilde_setup(void)
99{
100 dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0,
101 sizeof(t_dbtopow_tilde), 0, 0);
102 CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f);
103 class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, gensym("dsp"), 0);
104}
diff --git a/apps/plugins/pdbox/PDa/intern/dbtorms~.c b/apps/plugins/pdbox/PDa/intern/dbtorms~.c
new file mode 100644
index 0000000000..9d45a076eb
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/dbtorms~.c
@@ -0,0 +1,106 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4
5#define LOGTEN 2.302585092994
6
7typedef struct dbtorms_tilde
8{
9 t_object x_obj;
10 float x_f;
11} t_dbtorms_tilde;
12
13t_class *dbtorms_tilde_class;
14
15static void *dbtorms_tilde_new(void)
16{
17 t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class);
18 outlet_new(&x->x_obj, gensym("signal"));
19 x->x_f = 0;
20 return (x);
21}
22
23static t_int *dbtorms_tilde_perform(t_int *w)
24{
25 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
26 t_int n = *(t_int *)(w+3);
27 for (; n--; in++, out++)
28 {
29 float f = *in;
30 if (f <= 0) *out = 0;
31 else
32 {
33 if (f > 485)
34 f = 485;
35 *out = exp((LOGTEN * 0.05) * (f-100.));
36 }
37 }
38 return (w + 4);
39}
40
41static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp)
42{
43 post("warning: %s not usable yet",__FUNCTION__);
44 dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
45}
46
47void dbtorms_tilde_setup(void)
48{
49 dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0,
50 sizeof(t_dbtorms_tilde), 0, 0);
51 CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f);
52 class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, gensym("dsp"), 0);
53}
54#include <m_pd.h>
55#include <m_fixed.h>
56
57
58#define LOGTEN 2.302585092994
59
60typedef struct dbtorms_tilde
61{
62 t_object x_obj;
63 float x_f;
64} t_dbtorms_tilde;
65
66t_class *dbtorms_tilde_class;
67
68static void *dbtorms_tilde_new(void)
69{
70 t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class);
71 outlet_new(&x->x_obj, gensym("signal"));
72 x->x_f = 0;
73 return (x);
74}
75
76static t_int *dbtorms_tilde_perform(t_int *w)
77{
78 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
79 t_int n = *(t_int *)(w+3);
80 for (; n--; in++, out++)
81 {
82 float f = *in;
83 if (f <= 0) *out = 0;
84 else
85 {
86 if (f > 485)
87 f = 485;
88 *out = exp((LOGTEN * 0.05) * (f-100.));
89 }
90 }
91 return (w + 4);
92}
93
94static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp)
95{
96 post("warning: %s not usable yet",__FUNCTION__);
97 dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
98}
99
100void dbtorms_tilde_setup(void)
101{
102 dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0,
103 sizeof(t_dbtorms_tilde), 0, 0);
104 CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f);
105 class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, gensym("dsp"), 0);
106}
diff --git a/apps/plugins/pdbox/PDa/intern/delay.h b/apps/plugins/pdbox/PDa/intern/delay.h
new file mode 100644
index 0000000000..1aacd5682f
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/delay.h
@@ -0,0 +1,84 @@
1
2#ifndef __DELAY_H__
3#define __DELAY_H__
4
5
6extern t_class *sigdelwrite_class;
7
8
9typedef struct delwritectl
10{
11 int c_n;
12 t_sample *c_vec;
13 int c_phase;
14} t_delwritectl;
15
16typedef struct _sigdelwrite
17{
18 t_object x_obj;
19 t_symbol *x_sym;
20 t_delwritectl x_cspace;
21 int x_sortno; /* DSP sort number at which this was last put on chain */
22 int x_rsortno; /* DSP sort # for first delread or write in chain */
23 int x_vecsize; /* vector size for delread~ to use */
24 float x_f;
25} t_sigdelwrite;
26
27#define XTRASAMPS 4
28#define SAMPBLK 4
29
30 /* routine to check that all delwrites/delreads/vds have same vecsize */
31static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize)
32{
33 if (x->x_rsortno != ugen_getsortno())
34 {
35 x->x_vecsize = vecsize;
36 x->x_rsortno = ugen_getsortno();
37 }
38 else if (vecsize != x->x_vecsize)
39 pd_error(x, "delread/delwrite/vd vector size mismatch");
40}
41
42#endif
43
44#ifndef __DELAY_H__
45#define __DELAY_H__
46
47
48extern t_class *sigdelwrite_class;
49
50
51typedef struct delwritectl
52{
53 int c_n;
54 t_sample *c_vec;
55 int c_phase;
56} t_delwritectl;
57
58typedef struct _sigdelwrite
59{
60 t_object x_obj;
61 t_symbol *x_sym;
62 t_delwritectl x_cspace;
63 int x_sortno; /* DSP sort number at which this was last put on chain */
64 int x_rsortno; /* DSP sort # for first delread or write in chain */
65 int x_vecsize; /* vector size for delread~ to use */
66 float x_f;
67} t_sigdelwrite;
68
69#define XTRASAMPS 4
70#define SAMPBLK 4
71
72 /* routine to check that all delwrites/delreads/vds have same vecsize */
73static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize)
74{
75 if (x->x_rsortno != ugen_getsortno())
76 {
77 x->x_vecsize = vecsize;
78 x->x_rsortno = ugen_getsortno();
79 }
80 else if (vecsize != x->x_vecsize)
81 pd_error(x, "delread/delwrite/vd vector size mismatch");
82}
83
84#endif
diff --git a/apps/plugins/pdbox/PDa/intern/delread~.c b/apps/plugins/pdbox/PDa/intern/delread~.c
new file mode 100644
index 0000000000..b0a58393be
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/delread~.c
@@ -0,0 +1,200 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3#include "delay.h"
4
5extern int ugen_getsortno(void);
6
7#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
8static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
9
10static t_class *sigdelread_class;
11
12typedef struct _sigdelread
13{
14 t_object x_obj;
15 t_symbol *x_sym;
16 t_float x_deltime; /* delay in msec */
17 int x_delsamps; /* delay in samples */
18 t_float x_sr; /* samples per msec */
19 t_float x_n; /* vector size */
20 int x_zerodel; /* 0 or vecsize depending on read/write order */
21} t_sigdelread;
22
23static void sigdelread_float(t_sigdelread *x, t_float f);
24
25static void *sigdelread_new(t_symbol *s, t_floatarg f)
26{
27 t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
28 x->x_sym = s;
29 x->x_sr = 1;
30 x->x_n = 1;
31 x->x_zerodel = 0;
32 sigdelread_float(x, f);
33 outlet_new(&x->x_obj, &s_signal);
34 return (x);
35}
36
37static void sigdelread_float(t_sigdelread *x, t_float f)
38{
39 int samps;
40 t_sigdelwrite *delwriter =
41 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
42 x->x_deltime = f;
43 if (delwriter)
44 {
45 int delsize = delwriter->x_cspace.c_n;
46 x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime)
47 + x->x_n - x->x_zerodel;
48 if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n;
49 else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS)
50 x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS;
51 }
52}
53
54static t_int *sigdelread_perform(t_int *w)
55{
56 t_sample *out = (t_sample *)(w[1]);
57 t_delwritectl *c = (t_delwritectl *)(w[2]);
58 int delsamps = *(int *)(w[3]);
59 int n = (int)(w[4]);
60 int phase = c->c_phase - delsamps, nsamps = c->c_n;
61 t_sample *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
62
63 if (phase < 0) phase += nsamps;
64 bp = vp + phase;
65 while (n--)
66 {
67 *out++ = *bp++;
68 if (bp == ep) bp -= nsamps;
69 }
70 return (w+5);
71}
72
73static void sigdelread_dsp(t_sigdelread *x, t_signal **sp)
74{
75 t_sigdelwrite *delwriter =
76 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
77 x->x_sr = sp[0]->s_sr * 0.001;
78 x->x_n = sp[0]->s_n;
79 if (delwriter)
80 {
81 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
82 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
83 0 : delwriter->x_vecsize);
84 sigdelread_float(x, x->x_deltime);
85 dsp_add(sigdelread_perform, 4,
86 sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n);
87 }
88 else if (*x->x_sym->s_name)
89 error("delread~: %s: no such delwrite~",x->x_sym->s_name);
90}
91
92void delread_tilde_setup(void)
93{
94 sigdelread_class = class_new(gensym("delread~"),
95 (t_newmethod)sigdelread_new, 0,
96 sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0);
97 class_addmethod(sigdelread_class, (t_method)sigdelread_dsp,
98 gensym("dsp"), 0);
99 class_addfloat(sigdelread_class, (t_method)sigdelread_float);
100}
101#include <m_pd.h>
102#include <m_fixed.h>
103#include "delay.h"
104
105extern int ugen_getsortno(void);
106
107#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
108static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
109
110static t_class *sigdelread_class;
111
112typedef struct _sigdelread
113{
114 t_object x_obj;
115 t_symbol *x_sym;
116 t_float x_deltime; /* delay in msec */
117 int x_delsamps; /* delay in samples */
118 t_float x_sr; /* samples per msec */
119 t_float x_n; /* vector size */
120 int x_zerodel; /* 0 or vecsize depending on read/write order */
121} t_sigdelread;
122
123static void sigdelread_float(t_sigdelread *x, t_float f);
124
125static void *sigdelread_new(t_symbol *s, t_floatarg f)
126{
127 t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
128 x->x_sym = s;
129 x->x_sr = 1;
130 x->x_n = 1;
131 x->x_zerodel = 0;
132 sigdelread_float(x, f);
133 outlet_new(&x->x_obj, &s_signal);
134 return (x);
135}
136
137static void sigdelread_float(t_sigdelread *x, t_float f)
138{
139 int samps;
140 t_sigdelwrite *delwriter =
141 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
142 x->x_deltime = f;
143 if (delwriter)
144 {
145 int delsize = delwriter->x_cspace.c_n;
146 x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime)
147 + x->x_n - x->x_zerodel;
148 if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n;
149 else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS)
150 x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS;
151 }
152}
153
154static t_int *sigdelread_perform(t_int *w)
155{
156 t_sample *out = (t_sample *)(w[1]);
157 t_delwritectl *c = (t_delwritectl *)(w[2]);
158 int delsamps = *(int *)(w[3]);
159 int n = (int)(w[4]);
160 int phase = c->c_phase - delsamps, nsamps = c->c_n;
161 t_sample *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
162
163 if (phase < 0) phase += nsamps;
164 bp = vp + phase;
165 while (n--)
166 {
167 *out++ = *bp++;
168 if (bp == ep) bp -= nsamps;
169 }
170 return (w+5);
171}
172
173static void sigdelread_dsp(t_sigdelread *x, t_signal **sp)
174{
175 t_sigdelwrite *delwriter =
176 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
177 x->x_sr = sp[0]->s_sr * 0.001;
178 x->x_n = sp[0]->s_n;
179 if (delwriter)
180 {
181 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
182 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
183 0 : delwriter->x_vecsize);
184 sigdelread_float(x, x->x_deltime);
185 dsp_add(sigdelread_perform, 4,
186 sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n);
187 }
188 else if (*x->x_sym->s_name)
189 error("delread~: %s: no such delwrite~",x->x_sym->s_name);
190}
191
192void delread_tilde_setup(void)
193{
194 sigdelread_class = class_new(gensym("delread~"),
195 (t_newmethod)sigdelread_new, 0,
196 sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0);
197 class_addmethod(sigdelread_class, (t_method)sigdelread_dsp,
198 gensym("dsp"), 0);
199 class_addfloat(sigdelread_class, (t_method)sigdelread_float);
200}
diff --git a/apps/plugins/pdbox/PDa/intern/delwrite~.c b/apps/plugins/pdbox/PDa/intern/delwrite~.c
new file mode 100644
index 0000000000..290793d9e4
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/delwrite~.c
@@ -0,0 +1,168 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4extern int ugen_getsortno(void);
5
6#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
7static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
8
9#include "delay.h"
10
11t_class *sigdelwrite_class;
12
13static void *sigdelwrite_new(t_symbol *s, t_floatarg msec)
14{
15 int nsamps;
16 t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
17 if (!*s->s_name) s = gensym("delwrite~");
18 pd_bind(&x->x_obj.ob_pd, s);
19 x->x_sym = s;
20 nsamps = msec * sys_getsr() * (float)(0.001f);
21 if (nsamps < 1) nsamps = 1;
22 nsamps += ((- nsamps) & (SAMPBLK - 1));
23 nsamps += DEFDELVS;
24 x->x_cspace.c_n = nsamps;
25 x->x_cspace.c_vec =
26 (t_sample *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
27 x->x_cspace.c_phase = XTRASAMPS;
28 x->x_sortno = 0;
29 x->x_vecsize = 0;
30 x->x_f = 0;
31 return (x);
32}
33
34static t_int *sigdelwrite_perform(t_int *w)
35{
36 t_sample *in = (t_sample *)(w[1]);
37 t_delwritectl *c = (t_delwritectl *)(w[2]);
38 int n = (int)(w[3]);
39 int phase = c->c_phase, nsamps = c->c_n;
40 t_sample *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
41 phase += n;
42 while (n--)
43 {
44 t_sample f = *in++;
45 if (PD_BADFLOAT(f))
46 f = 0;
47 *bp++ = f;
48 if (bp == ep)
49 {
50 vp[0] = ep[-4];
51 vp[1] = ep[-3];
52 vp[2] = ep[-2];
53 vp[3] = ep[-1];
54 bp = vp + XTRASAMPS;
55 phase -= nsamps;
56 }
57 }
58 c->c_phase = phase;
59 return (w+4);
60}
61
62static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp)
63{
64 dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n);
65 x->x_sortno = ugen_getsortno();
66 sigdelwrite_checkvecsize(x, sp[0]->s_n);
67}
68
69static void sigdelwrite_free(t_sigdelwrite *x)
70{
71 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
72 freebytes(x->x_cspace.c_vec,
73 (x->x_cspace.c_n + XTRASAMPS) * sizeof(float));
74}
75
76void delwrite_tilde_setup(void)
77{
78 sigdelwrite_class = class_new(gensym("delwrite~"),
79 (t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free,
80 sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0);
81 CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f);
82 class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp,
83 gensym("dsp"), 0);
84}
85#include <m_pd.h>
86#include <m_fixed.h>
87
88extern int ugen_getsortno(void);
89
90#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
91static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
92
93#include "delay.h"
94
95t_class *sigdelwrite_class;
96
97static void *sigdelwrite_new(t_symbol *s, t_floatarg msec)
98{
99 int nsamps;
100 t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
101 if (!*s->s_name) s = gensym("delwrite~");
102 pd_bind(&x->x_obj.ob_pd, s);
103 x->x_sym = s;
104 nsamps = msec * sys_getsr() * (float)(0.001f);
105 if (nsamps < 1) nsamps = 1;
106 nsamps += ((- nsamps) & (SAMPBLK - 1));
107 nsamps += DEFDELVS;
108 x->x_cspace.c_n = nsamps;
109 x->x_cspace.c_vec =
110 (t_sample *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
111 x->x_cspace.c_phase = XTRASAMPS;
112 x->x_sortno = 0;
113 x->x_vecsize = 0;
114 x->x_f = 0;
115 return (x);
116}
117
118static t_int *sigdelwrite_perform(t_int *w)
119{
120 t_sample *in = (t_sample *)(w[1]);
121 t_delwritectl *c = (t_delwritectl *)(w[2]);
122 int n = (int)(w[3]);
123 int phase = c->c_phase, nsamps = c->c_n;
124 t_sample *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
125 phase += n;
126 while (n--)
127 {
128 t_sample f = *in++;
129 if (PD_BADFLOAT(f))
130 f = 0;
131 *bp++ = f;
132 if (bp == ep)
133 {
134 vp[0] = ep[-4];
135 vp[1] = ep[-3];
136 vp[2] = ep[-2];
137 vp[3] = ep[-1];
138 bp = vp + XTRASAMPS;
139 phase -= nsamps;
140 }
141 }
142 c->c_phase = phase;
143 return (w+4);
144}
145
146static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp)
147{
148 dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n);
149 x->x_sortno = ugen_getsortno();
150 sigdelwrite_checkvecsize(x, sp[0]->s_n);
151}
152
153static void sigdelwrite_free(t_sigdelwrite *x)
154{
155 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
156 freebytes(x->x_cspace.c_vec,
157 (x->x_cspace.c_n + XTRASAMPS) * sizeof(float));
158}
159
160void delwrite_tilde_setup(void)
161{
162 sigdelwrite_class = class_new(gensym("delwrite~"),
163 (t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free,
164 sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0);
165 CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f);
166 class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp,
167 gensym("dsp"), 0);
168}
diff --git a/apps/plugins/pdbox/PDa/intern/env~.c b/apps/plugins/pdbox/PDa/intern/env~.c
new file mode 100644
index 0000000000..a9bf6998e1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/env~.c
@@ -0,0 +1,254 @@
1
2#define FIXEDPOINT
3#include <m_pd.h>
4#include <m_fixed.h>
5
6
7#define MAXOVERLAP 10
8#define MAXVSTAKEN 64
9
10typedef struct sigenv
11{
12 t_object x_obj; /* header */
13 void *x_outlet; /* a "float" outlet */
14 void *x_clock; /* a "clock" object */
15 t_sample *x_buf; /* a Hanning window */
16 int x_phase; /* number of points since last output */
17 int x_period; /* requested period of output */
18 int x_realperiod; /* period rounded up to vecsize multiple */
19 int x_npoints; /* analysis window size in samples */
20 t_float x_result; /* result to output */
21 t_sample x_sumbuf[MAXOVERLAP]; /* summing buffer */
22 t_float x_f;
23} t_sigenv;
24
25t_class *sigenv_class;
26static void sigenv_tick(t_sigenv *x);
27
28static void *sigenv_new(t_floatarg fnpoints, t_floatarg fperiod)
29{
30 int npoints = fnpoints;
31 int period = fperiod;
32 t_sigenv *x;
33 t_sample *buf;
34 int i;
35
36 if (npoints < 1) npoints = 1024;
37 if (period < 1) period = npoints/2;
38 if (period < npoints / MAXOVERLAP + 1)
39 period = npoints / MAXOVERLAP + 1;
40 if (!(buf = getbytes(sizeof(t_sample) * (npoints + MAXVSTAKEN))))
41 {
42 error("env: couldn't allocate buffer");
43 return (0);
44 }
45 x = (t_sigenv *)pd_new(sigenv_class);
46 x->x_buf = buf;
47 x->x_npoints = npoints;
48 x->x_phase = 0;
49 x->x_period = period;
50 for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
51 for (i = 0; i < npoints; i++)
52 buf[i] = ftofix((1. - cos((2 * 3.14159 * i) / npoints))/npoints);
53 for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
54 x->x_clock = clock_new(x, (t_method)sigenv_tick);
55 x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
56 x->x_f = 0;
57 return (x);
58}
59
60static t_int *sigenv_perform(t_int *w)
61{
62 t_sigenv *x = (t_sigenv *)(w[1]);
63 t_sample *in = (t_sample *)(w[2]);
64 int n = (int)(w[3]);
65 int count;
66 t_sample *sump;
67 in += n;
68 for (count = x->x_phase, sump = x->x_sumbuf;
69 count < x->x_npoints; count += x->x_realperiod, sump++)
70 {
71 t_sample *hp = x->x_buf + count;
72 t_sample *fp = in;
73 t_sample sum = *sump;
74 int i;
75
76 for (i = 0; i < n; i++)
77 {
78 fp--;
79 sum += *hp++ * ((*fp * *fp)>>16)>>16;
80 }
81 *sump = sum;
82 }
83 sump[0] = 0;
84 x->x_phase -= n;
85 if (x->x_phase < 0)
86 {
87 x->x_result = x->x_sumbuf[0];
88 for (count = x->x_realperiod, sump = x->x_sumbuf;
89 count < x->x_npoints; count += x->x_realperiod, sump++)
90 sump[0] = sump[1];
91 sump[0] = 0;
92 x->x_phase = x->x_realperiod - n;
93 clock_delay(x->x_clock, 0L);
94 }
95 return (w+4);
96}
97
98static void sigenv_dsp(t_sigenv *x, t_signal **sp)
99{
100 if (x->x_period % sp[0]->s_n) x->x_realperiod =
101 x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
102 else x->x_realperiod = x->x_period;
103 dsp_add(sigenv_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
104 if (sp[0]->s_n > MAXVSTAKEN) bug("sigenv_dsp");
105}
106
107static void sigenv_tick(t_sigenv *x) /* callback function for the clock */
108{
109 outlet_float(x->x_outlet, powtodb(x->x_result*3.051757e-05));
110}
111
112static void sigenv_ff(t_sigenv *x) /* cleanup on free */
113{
114 clock_free(x->x_clock);
115 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
116}
117
118
119void env_tilde_setup(void )
120{
121 sigenv_class = class_new(gensym("env~"), (t_newmethod)sigenv_new,
122 (t_method)sigenv_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
123 CLASS_MAINSIGNALIN(sigenv_class, t_sigenv, x_f);
124 class_addmethod(sigenv_class, (t_method)sigenv_dsp, gensym("dsp"), 0);
125}
126
127
128
129#define FIXEDPOINT
130#include <m_pd.h>
131#include <m_fixed.h>
132
133
134#define MAXOVERLAP 10
135#define MAXVSTAKEN 64
136
137typedef struct sigenv
138{
139 t_object x_obj; /* header */
140 void *x_outlet; /* a "float" outlet */
141 void *x_clock; /* a "clock" object */
142 t_sample *x_buf; /* a Hanning window */
143 int x_phase; /* number of points since last output */
144 int x_period; /* requested period of output */
145 int x_realperiod; /* period rounded up to vecsize multiple */
146 int x_npoints; /* analysis window size in samples */
147 t_float x_result; /* result to output */
148 t_sample x_sumbuf[MAXOVERLAP]; /* summing buffer */
149 t_float x_f;
150} t_sigenv;
151
152t_class *sigenv_class;
153static void sigenv_tick(t_sigenv *x);
154
155static void *sigenv_new(t_floatarg fnpoints, t_floatarg fperiod)
156{
157 int npoints = fnpoints;
158 int period = fperiod;
159 t_sigenv *x;
160 t_sample *buf;
161 int i;
162
163 if (npoints < 1) npoints = 1024;
164 if (period < 1) period = npoints/2;
165 if (period < npoints / MAXOVERLAP + 1)
166 period = npoints / MAXOVERLAP + 1;
167 if (!(buf = getbytes(sizeof(t_sample) * (npoints + MAXVSTAKEN))))
168 {
169 error("env: couldn't allocate buffer");
170 return (0);
171 }
172 x = (t_sigenv *)pd_new(sigenv_class);
173 x->x_buf = buf;
174 x->x_npoints = npoints;
175 x->x_phase = 0;
176 x->x_period = period;
177 for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
178 for (i = 0; i < npoints; i++)
179 buf[i] = ftofix((1. - cos((2 * 3.14159 * i) / npoints))/npoints);
180 for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
181 x->x_clock = clock_new(x, (t_method)sigenv_tick);
182 x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
183 x->x_f = 0;
184 return (x);
185}
186
187static t_int *sigenv_perform(t_int *w)
188{
189 t_sigenv *x = (t_sigenv *)(w[1]);
190 t_sample *in = (t_sample *)(w[2]);
191 int n = (int)(w[3]);
192 int count;
193 t_sample *sump;
194 in += n;
195 for (count = x->x_phase, sump = x->x_sumbuf;
196 count < x->x_npoints; count += x->x_realperiod, sump++)
197 {
198 t_sample *hp = x->x_buf + count;
199 t_sample *fp = in;
200 t_sample sum = *sump;
201 int i;
202
203 for (i = 0; i < n; i++)
204 {
205 fp--;
206 sum += *hp++ * ((*fp * *fp)>>16)>>16;
207 }
208 *sump = sum;
209 }
210 sump[0] = 0;
211 x->x_phase -= n;
212 if (x->x_phase < 0)
213 {
214 x->x_result = x->x_sumbuf[0];
215 for (count = x->x_realperiod, sump = x->x_sumbuf;
216 count < x->x_npoints; count += x->x_realperiod, sump++)
217 sump[0] = sump[1];
218 sump[0] = 0;
219 x->x_phase = x->x_realperiod - n;
220 clock_delay(x->x_clock, 0L);
221 }
222 return (w+4);
223}
224
225static void sigenv_dsp(t_sigenv *x, t_signal **sp)
226{
227 if (x->x_period % sp[0]->s_n) x->x_realperiod =
228 x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
229 else x->x_realperiod = x->x_period;
230 dsp_add(sigenv_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
231 if (sp[0]->s_n > MAXVSTAKEN) bug("sigenv_dsp");
232}
233
234static void sigenv_tick(t_sigenv *x) /* callback function for the clock */
235{
236 outlet_float(x->x_outlet, powtodb(x->x_result*3.051757e-05));
237}
238
239static void sigenv_ff(t_sigenv *x) /* cleanup on free */
240{
241 clock_free(x->x_clock);
242 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
243}
244
245
246void env_tilde_setup(void )
247{
248 sigenv_class = class_new(gensym("env~"), (t_newmethod)sigenv_new,
249 (t_method)sigenv_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
250 CLASS_MAINSIGNALIN(sigenv_class, t_sigenv, x_f);
251 class_addmethod(sigenv_class, (t_method)sigenv_dsp, gensym("dsp"), 0);
252}
253
254
diff --git a/apps/plugins/pdbox/PDa/intern/ftom~.c b/apps/plugins/pdbox/PDa/intern/ftom~.c
new file mode 100644
index 0000000000..253fd7bf73
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/ftom~.c
@@ -0,0 +1,88 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4typedef struct ftom_tilde
5{
6 t_object x_obj;
7 float x_f;
8} t_ftom_tilde;
9
10t_class *ftom_tilde_class;
11
12static void *ftom_tilde_new(void)
13{
14 t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class);
15 outlet_new(&x->x_obj, gensym("signal"));
16 x->x_f = 0;
17 return (x);
18}
19
20static t_int *ftom_tilde_perform(t_int *w)
21{
22 t_sample *in = *(t_sample **)(w+1), *out = *(t_float **)(w+2);
23 t_int n = *(t_int *)(w+3);
24 for (; n--; *in++, out++)
25 {
26 t_sample f = *in;
27 *out = ftofix((fixtof(f) > 0 ? 17.3123405046 * log(.12231220585 * fixtof(f)) : -1500));
28 }
29 return (w + 4);
30}
31
32static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp)
33{
34 post("warning: %s not usable yet",__FUNCTION__);
35 dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
36}
37
38void ftom_tilde_setup(void)
39{
40 ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0,
41 sizeof(t_ftom_tilde), 0, 0);
42 CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f);
43 class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, gensym("dsp"), 0);
44}
45#include <m_pd.h>
46#include <m_fixed.h>
47
48typedef struct ftom_tilde
49{
50 t_object x_obj;
51 float x_f;
52} t_ftom_tilde;
53
54t_class *ftom_tilde_class;
55
56static void *ftom_tilde_new(void)
57{
58 t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class);
59 outlet_new(&x->x_obj, gensym("signal"));
60 x->x_f = 0;
61 return (x);
62}
63
64static t_int *ftom_tilde_perform(t_int *w)
65{
66 t_sample *in = *(t_sample **)(w+1), *out = *(t_float **)(w+2);
67 t_int n = *(t_int *)(w+3);
68 for (; n--; *in++, out++)
69 {
70 t_sample f = *in;
71 *out = ftofix((fixtof(f) > 0 ? 17.3123405046 * log(.12231220585 * fixtof(f)) : -1500));
72 }
73 return (w + 4);
74}
75
76static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp)
77{
78 post("warning: %s not usable yet",__FUNCTION__);
79 dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
80}
81
82void ftom_tilde_setup(void)
83{
84 ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0,
85 sizeof(t_ftom_tilde), 0, 0);
86 CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f);
87 class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, gensym("dsp"), 0);
88}
diff --git a/apps/plugins/pdbox/PDa/intern/hip~.c b/apps/plugins/pdbox/PDa/intern/hip~.c
new file mode 100644
index 0000000000..a2a8c40cf2
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/hip~.c
@@ -0,0 +1,184 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4typedef struct hipctl
5{
6 t_sample c_x;
7 t_sample c_coef;
8} t_hipctl;
9
10typedef struct sighip
11{
12 t_object x_obj;
13 float x_sr;
14 float x_hz;
15 t_hipctl x_cspace;
16 t_hipctl *x_ctl;
17 float x_f;
18} t_sighip;
19
20t_class *sighip_class;
21static void sighip_ft1(t_sighip *x, t_floatarg f);
22
23static void *sighip_new(t_floatarg f)
24{
25 t_sighip *x = (t_sighip *)pd_new(sighip_class);
26 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
27 outlet_new(&x->x_obj, gensym("signal"));
28 x->x_sr = 44100;
29 x->x_ctl = &x->x_cspace;
30 x->x_cspace.c_x = 0;
31 sighip_ft1(x, f);
32 x->x_f = 0;
33 return (x);
34}
35
36static void sighip_ft1(t_sighip *x, t_floatarg f)
37{
38 t_float coeff;
39 if (f < 0.001) f = 10;
40 x->x_hz = f;
41 coeff = 1 - f * (2 * 3.14159) / x->x_sr;
42 if (coeff < 0) coeff = 0;
43 x->x_ctl->c_coef = ftofix(coeff);
44}
45
46static t_int *sighip_perform(t_int *w)
47{
48 t_sample *in = (t_sample *)(w[1]);
49 t_sample *out = (t_sample *)(w[2]);
50 t_hipctl *c = (t_hipctl *)(w[3]);
51 int n = (t_int)(w[4]);
52 int i;
53 t_sample last = c->c_x;
54 t_sample coef = c->c_coef;
55 for (i = 0; i < n; i++)
56 {
57 t_sample new = *in++ + mult(coef,last);
58 *out++ = new - last;
59 last = new;
60 }
61 if (PD_BADFLOAT(last))
62 last = 0;
63 c->c_x = last;
64 return (w+5);
65}
66
67static void sighip_dsp(t_sighip *x, t_signal **sp)
68{
69 x->x_sr = sp[0]->s_sr;
70 sighip_ft1(x, x->x_hz);
71 dsp_add(sighip_perform, 4,
72 sp[0]->s_vec, sp[1]->s_vec,
73 x->x_ctl, sp[0]->s_n);
74
75}
76
77static void sighip_clear(t_sighip *x, t_floatarg q)
78{
79 x->x_cspace.c_x = 0;
80}
81
82void hip_tilde_setup(void)
83{
84 sighip_class = class_new(gensym("hip~"), (t_newmethod)sighip_new, 0,
85 sizeof(t_sighip), 0, A_DEFFLOAT, 0);
86 CLASS_MAINSIGNALIN(sighip_class, t_sighip, x_f);
87 class_addmethod(sighip_class, (t_method)sighip_dsp, gensym("dsp"), 0);
88 class_addmethod(sighip_class, (t_method)sighip_ft1,
89 gensym("ft1"), A_FLOAT, 0);
90 class_addmethod(sighip_class, (t_method)sighip_clear, gensym("clear"), 0);
91 class_sethelpsymbol(sighip_class, gensym("lop~-help.pd"));
92}
93#include <m_pd.h>
94#include <m_fixed.h>
95
96typedef struct hipctl
97{
98 t_sample c_x;
99 t_sample c_coef;
100} t_hipctl;
101
102typedef struct sighip
103{
104 t_object x_obj;
105 float x_sr;
106 float x_hz;
107 t_hipctl x_cspace;
108 t_hipctl *x_ctl;
109 float x_f;
110} t_sighip;
111
112t_class *sighip_class;
113static void sighip_ft1(t_sighip *x, t_floatarg f);
114
115static void *sighip_new(t_floatarg f)
116{
117 t_sighip *x = (t_sighip *)pd_new(sighip_class);
118 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
119 outlet_new(&x->x_obj, gensym("signal"));
120 x->x_sr = 44100;
121 x->x_ctl = &x->x_cspace;
122 x->x_cspace.c_x = 0;
123 sighip_ft1(x, f);
124 x->x_f = 0;
125 return (x);
126}
127
128static void sighip_ft1(t_sighip *x, t_floatarg f)
129{
130 t_float coeff;
131 if (f < 0.001) f = 10;
132 x->x_hz = f;
133 coeff = 1 - f * (2 * 3.14159) / x->x_sr;
134 if (coeff < 0) coeff = 0;
135 x->x_ctl->c_coef = ftofix(coeff);
136}
137
138static t_int *sighip_perform(t_int *w)
139{
140 t_sample *in = (t_sample *)(w[1]);
141 t_sample *out = (t_sample *)(w[2]);
142 t_hipctl *c = (t_hipctl *)(w[3]);
143 int n = (t_int)(w[4]);
144 int i;
145 t_sample last = c->c_x;
146 t_sample coef = c->c_coef;
147 for (i = 0; i < n; i++)
148 {
149 t_sample new = *in++ + mult(coef,last);
150 *out++ = new - last;
151 last = new;
152 }
153 if (PD_BADFLOAT(last))
154 last = 0;
155 c->c_x = last;
156 return (w+5);
157}
158
159static void sighip_dsp(t_sighip *x, t_signal **sp)
160{
161 x->x_sr = sp[0]->s_sr;
162 sighip_ft1(x, x->x_hz);
163 dsp_add(sighip_perform, 4,
164 sp[0]->s_vec, sp[1]->s_vec,
165 x->x_ctl, sp[0]->s_n);
166
167}
168
169static void sighip_clear(t_sighip *x, t_floatarg q)
170{
171 x->x_cspace.c_x = 0;
172}
173
174void hip_tilde_setup(void)
175{
176 sighip_class = class_new(gensym("hip~"), (t_newmethod)sighip_new, 0,
177 sizeof(t_sighip), 0, A_DEFFLOAT, 0);
178 CLASS_MAINSIGNALIN(sighip_class, t_sighip, x_f);
179 class_addmethod(sighip_class, (t_method)sighip_dsp, gensym("dsp"), 0);
180 class_addmethod(sighip_class, (t_method)sighip_ft1,
181 gensym("ft1"), A_FLOAT, 0);
182 class_addmethod(sighip_class, (t_method)sighip_clear, gensym("clear"), 0);
183 class_sethelpsymbol(sighip_class, gensym("lop~-help.pd"));
184}
diff --git a/apps/plugins/pdbox/PDa/intern/intern_setup.c b/apps/plugins/pdbox/PDa/intern/intern_setup.c
new file mode 100644
index 0000000000..aec879973b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/intern_setup.c
@@ -0,0 +1,94 @@
1#include <stdio.h>
2
3void d_intern_setup() {
4 fprintf(stderr,"setup\n");
5 biquad_tilde_setup();
6 bp_tilde_setup();
7 clip_tilde_setup();
8 cos_tilde_setup();
9 dbtopow_tilde_setup();
10 dbtorms_tilde_setup();
11 delread_tilde_setup();
12 delwrite_tilde_setup();
13 env_tilde_setup();
14 ftom_tilde_setup();
15 hip_tilde_setup();
16 line_tilde_setup();
17 lop_tilde_setup();
18 mtof_tilde_setup();
19 noise_tilde_setup();
20 osc_tilde_setup();
21 phasor_tilde_setup();
22 powtodb_tilde_setup();
23 print_tilde_setup();
24 rmstodb_tilde_setup();
25 rsqrt_tilde_setup();
26 samphold_tilde_setup();
27 sfread_tilde_setup();
28 sfwrite_tilde_setup();
29 sig_tilde_setup();
30 snapshot_tilde_setup();
31 sqrt_tilde_setup();
32 tabosc4_tilde_setup();
33 tabplay_tilde_setup();
34 tabread4_tilde_setup();
35 tabread_tilde_setup();
36 tabread_setup();
37 tabreceive_tilde_setup();
38 tabsend_tilde_setup();
39 tabwrite_tilde_setup();
40 tabwrite_setup();
41 threshold_tilde_setup();
42 vcf_tilde_setup();
43 vd_tilde_setup();
44 vline_tilde_setup();
45 vsnapshot_tilde_setup();
46 wrap_tilde_setup();
47}
48#include <stdio.h>
49
50void d_intern_setup() {
51 fprintf(stderr,"setup\n");
52 biquad_tilde_setup();
53 bp_tilde_setup();
54 clip_tilde_setup();
55 cos_tilde_setup();
56 dbtopow_tilde_setup();
57 dbtorms_tilde_setup();
58 delread_tilde_setup();
59 delwrite_tilde_setup();
60 env_tilde_setup();
61 ftom_tilde_setup();
62 hip_tilde_setup();
63 line_tilde_setup();
64 lop_tilde_setup();
65 mtof_tilde_setup();
66 noise_tilde_setup();
67 osc_tilde_setup();
68 phasor_tilde_setup();
69 powtodb_tilde_setup();
70 print_tilde_setup();
71 rmstodb_tilde_setup();
72 rsqrt_tilde_setup();
73 samphold_tilde_setup();
74 sfread_tilde_setup();
75 sfwrite_tilde_setup();
76 sig_tilde_setup();
77 snapshot_tilde_setup();
78 sqrt_tilde_setup();
79 tabosc4_tilde_setup();
80 tabplay_tilde_setup();
81 tabread4_tilde_setup();
82 tabread_tilde_setup();
83 tabread_setup();
84 tabreceive_tilde_setup();
85 tabsend_tilde_setup();
86 tabwrite_tilde_setup();
87 tabwrite_setup();
88 threshold_tilde_setup();
89 vcf_tilde_setup();
90 vd_tilde_setup();
91 vline_tilde_setup();
92 vsnapshot_tilde_setup();
93 wrap_tilde_setup();
94}
diff --git a/apps/plugins/pdbox/PDa/intern/line~.c b/apps/plugins/pdbox/PDa/intern/line~.c
new file mode 100644
index 0000000000..ac7af8721e
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/line~.c
@@ -0,0 +1,202 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4static t_class *line_class;
5
6typedef struct _line
7{
8 t_object x_obj;
9 t_sample x_target;
10 t_sample x_value;
11 t_sample x_biginc;
12 t_sample x_inc;
13 t_sample x_1overn;
14 t_sample x_msectodsptick;
15 t_floatarg x_inletvalue;
16 t_floatarg x_inletwas;
17 int x_ticksleft;
18 int x_retarget;
19} t_line;
20
21static t_int *line_perform(t_int *w)
22{
23 t_line *x = (t_line *)(w[1]);
24 t_sample *out = (t_sample *)(w[2]);
25 int n = (int)(w[3]);
26 t_sample f = x->x_value;
27
28 if (x->x_retarget)
29 {
30 int nticks = mult(ftofix(x->x_inletwas),x->x_msectodsptick);
31 if (!nticks) nticks = itofix(1);
32 x->x_ticksleft = fixtoi(nticks);
33 x->x_biginc = (x->x_target - x->x_value);
34 x->x_biginc = idiv(x->x_biginc,nticks);
35 x->x_inc = mult(x->x_1overn, x->x_biginc);
36 x->x_retarget = 0;
37 }
38 if (x->x_ticksleft)
39 {
40 t_sample f = x->x_value;
41 while (n--) *out++ = f, f += x->x_inc;
42 x->x_value += x->x_biginc;
43 x->x_ticksleft--;
44 }
45 else
46 {
47 x->x_value = x->x_target;
48 while (n--) *out++ = x->x_value;
49 }
50 return (w+4);
51}
52
53static void line_float(t_line *x, t_float f)
54{
55 if (x->x_inletvalue <= 0)
56 {
57 x->x_target = x->x_value = ftofix(f);
58 x->x_ticksleft = x->x_retarget = 0;
59 }
60 else
61 {
62 x->x_target = ftofix(f);
63 x->x_retarget = 1;
64 x->x_inletwas = x->x_inletvalue;
65 x->x_inletvalue = 0;
66 }
67}
68
69static void line_stop(t_line *x)
70{
71 x->x_target = x->x_value;
72 x->x_ticksleft = x->x_retarget = 0;
73}
74
75static void line_dsp(t_line *x, t_signal **sp)
76{
77 dsp_add(line_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
78 x->x_1overn = ftofix(1)/sp[0]->s_n;
79 x->x_msectodsptick = idiv(sp[0]->s_sr, (1000 * sp[0]->s_n));
80}
81
82static void *line_new(void)
83{
84 t_line *x = (t_line *)pd_new(line_class);
85 outlet_new(&x->x_obj, gensym("signal"));
86 floatinlet_new(&x->x_obj, &x->x_inletvalue);
87 x->x_ticksleft = x->x_retarget = 0;
88 x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
89 return (x);
90}
91
92void line_tilde_setup(void)
93{
94 line_class = class_new(gensym("line~"), line_new, 0,
95 sizeof(t_line), 0, 0);
96 class_addfloat(line_class, (t_method)line_float);
97 class_addmethod(line_class, (t_method)line_dsp, gensym("dsp"), 0);
98 class_addmethod(line_class, (t_method)line_stop, gensym("stop"), 0);
99}
100
101
102#include <m_pd.h>
103#include <m_fixed.h>
104
105static t_class *line_class;
106
107typedef struct _line
108{
109 t_object x_obj;
110 t_sample x_target;
111 t_sample x_value;
112 t_sample x_biginc;
113 t_sample x_inc;
114 t_sample x_1overn;
115 t_sample x_msectodsptick;
116 t_floatarg x_inletvalue;
117 t_floatarg x_inletwas;
118 int x_ticksleft;
119 int x_retarget;
120} t_line;
121
122static t_int *line_perform(t_int *w)
123{
124 t_line *x = (t_line *)(w[1]);
125 t_sample *out = (t_sample *)(w[2]);
126 int n = (int)(w[3]);
127 t_sample f = x->x_value;
128
129 if (x->x_retarget)
130 {
131 int nticks = mult(ftofix(x->x_inletwas),x->x_msectodsptick);
132 if (!nticks) nticks = itofix(1);
133 x->x_ticksleft = fixtoi(nticks);
134 x->x_biginc = (x->x_target - x->x_value);
135 x->x_biginc = idiv(x->x_biginc,nticks);
136 x->x_inc = mult(x->x_1overn, x->x_biginc);
137 x->x_retarget = 0;
138 }
139 if (x->x_ticksleft)
140 {
141 t_sample f = x->x_value;
142 while (n--) *out++ = f, f += x->x_inc;
143 x->x_value += x->x_biginc;
144 x->x_ticksleft--;
145 }
146 else
147 {
148 x->x_value = x->x_target;
149 while (n--) *out++ = x->x_value;
150 }
151 return (w+4);
152}
153
154static void line_float(t_line *x, t_float f)
155{
156 if (x->x_inletvalue <= 0)
157 {
158 x->x_target = x->x_value = ftofix(f);
159 x->x_ticksleft = x->x_retarget = 0;
160 }
161 else
162 {
163 x->x_target = ftofix(f);
164 x->x_retarget = 1;
165 x->x_inletwas = x->x_inletvalue;
166 x->x_inletvalue = 0;
167 }
168}
169
170static void line_stop(t_line *x)
171{
172 x->x_target = x->x_value;
173 x->x_ticksleft = x->x_retarget = 0;
174}
175
176static void line_dsp(t_line *x, t_signal **sp)
177{
178 dsp_add(line_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
179 x->x_1overn = ftofix(1)/sp[0]->s_n;
180 x->x_msectodsptick = idiv(sp[0]->s_sr, (1000 * sp[0]->s_n));
181}
182
183static void *line_new(void)
184{
185 t_line *x = (t_line *)pd_new(line_class);
186 outlet_new(&x->x_obj, gensym("signal"));
187 floatinlet_new(&x->x_obj, &x->x_inletvalue);
188 x->x_ticksleft = x->x_retarget = 0;
189 x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
190 return (x);
191}
192
193void line_tilde_setup(void)
194{
195 line_class = class_new(gensym("line~"), line_new, 0,
196 sizeof(t_line), 0, 0);
197 class_addfloat(line_class, (t_method)line_float);
198 class_addmethod(line_class, (t_method)line_dsp, gensym("dsp"), 0);
199 class_addmethod(line_class, (t_method)line_stop, gensym("stop"), 0);
200}
201
202
diff --git a/apps/plugins/pdbox/PDa/intern/lop~.c b/apps/plugins/pdbox/PDa/intern/lop~.c
new file mode 100644
index 0000000000..49a17a7c5f
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/lop~.c
@@ -0,0 +1,180 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4typedef struct lopctl
5{
6 t_sample c_x;
7 t_sample c_coef;
8} t_lopctl;
9
10typedef struct siglop
11{
12 t_object x_obj;
13 float x_sr;
14 float x_hz;
15 t_lopctl x_cspace;
16 t_lopctl *x_ctl;
17 float x_f;
18} t_siglop;
19
20t_class *siglop_class;
21
22static void siglop_ft1(t_siglop *x, t_floatarg f);
23
24static void *siglop_new(t_floatarg f)
25{
26 t_siglop *x = (t_siglop *)pd_new(siglop_class);
27 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
28 outlet_new(&x->x_obj, gensym("signal"));
29 x->x_sr = 44100;
30 x->x_ctl = &x->x_cspace;
31 x->x_cspace.c_x = 0;
32 siglop_ft1(x, f);
33 x->x_f = 0;
34 return (x);
35}
36
37static void siglop_ft1(t_siglop *x, t_floatarg f)
38{
39 t_float coeff;
40 if (f < 0.001) f = 10;
41 x->x_hz = f;
42 coeff = f * (2 * 3.14159) / x->x_sr;
43 if (coeff > 1) coeff = 1;
44 x->x_ctl->c_coef = ftofix(coeff);
45}
46
47static void siglop_clear(t_siglop *x, t_floatarg q)
48{
49 x->x_cspace.c_x = 0;
50}
51
52
53static t_int *siglop_perform(t_int *w)
54{
55 t_sample *in = (t_sample *)(w[1]);
56 t_sample *out = (t_sample *)(w[2]);
57 t_lopctl *c = (t_lopctl *)(w[3]);
58 int n = (t_int)(w[4]);
59 int i;
60 t_sample last = c->c_x;
61 t_sample coef = c->c_coef;
62 t_sample feedback = ftofix(1) - coef;
63 for (i = 0; i < n; i++)
64 last = *out++ = mult(coef, *in++) + mult(feedback,last);
65 if (PD_BADFLOAT(last))
66 last = 0;
67 c->c_x = last;
68 return (w+5);
69}
70
71static void siglop_dsp(t_siglop *x, t_signal **sp)
72{
73 x->x_sr = sp[0]->s_sr;
74 siglop_ft1(x, x->x_hz);
75 dsp_add(siglop_perform, 4,
76 sp[0]->s_vec, sp[1]->s_vec,
77 x->x_ctl, sp[0]->s_n);
78
79}
80
81void lop_tilde_setup(void)
82{
83 siglop_class = class_new(gensym("lop~"), (t_newmethod)siglop_new, 0,
84 sizeof(t_siglop), 0, A_DEFFLOAT, 0);
85 CLASS_MAINSIGNALIN(siglop_class, t_siglop, x_f);
86 class_addmethod(siglop_class, (t_method)siglop_dsp, gensym("dsp"), 0);
87 class_addmethod(siglop_class, (t_method)siglop_ft1,
88 gensym("ft1"), A_FLOAT, 0);
89 class_addmethod(siglop_class, (t_method)siglop_clear, gensym("clear"), 0);
90}
91#include <m_pd.h>
92#include <m_fixed.h>
93
94typedef struct lopctl
95{
96 t_sample c_x;
97 t_sample c_coef;
98} t_lopctl;
99
100typedef struct siglop
101{
102 t_object x_obj;
103 float x_sr;
104 float x_hz;
105 t_lopctl x_cspace;
106 t_lopctl *x_ctl;
107 float x_f;
108} t_siglop;
109
110t_class *siglop_class;
111
112static void siglop_ft1(t_siglop *x, t_floatarg f);
113
114static void *siglop_new(t_floatarg f)
115{
116 t_siglop *x = (t_siglop *)pd_new(siglop_class);
117 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
118 outlet_new(&x->x_obj, gensym("signal"));
119 x->x_sr = 44100;
120 x->x_ctl = &x->x_cspace;
121 x->x_cspace.c_x = 0;
122 siglop_ft1(x, f);
123 x->x_f = 0;
124 return (x);
125}
126
127static void siglop_ft1(t_siglop *x, t_floatarg f)
128{
129 t_float coeff;
130 if (f < 0.001) f = 10;
131 x->x_hz = f;
132 coeff = f * (2 * 3.14159) / x->x_sr;
133 if (coeff > 1) coeff = 1;
134 x->x_ctl->c_coef = ftofix(coeff);
135}
136
137static void siglop_clear(t_siglop *x, t_floatarg q)
138{
139 x->x_cspace.c_x = 0;
140}
141
142
143static t_int *siglop_perform(t_int *w)
144{
145 t_sample *in = (t_sample *)(w[1]);
146 t_sample *out = (t_sample *)(w[2]);
147 t_lopctl *c = (t_lopctl *)(w[3]);
148 int n = (t_int)(w[4]);
149 int i;
150 t_sample last = c->c_x;
151 t_sample coef = c->c_coef;
152 t_sample feedback = ftofix(1) - coef;
153 for (i = 0; i < n; i++)
154 last = *out++ = mult(coef, *in++) + mult(feedback,last);
155 if (PD_BADFLOAT(last))
156 last = 0;
157 c->c_x = last;
158 return (w+5);
159}
160
161static void siglop_dsp(t_siglop *x, t_signal **sp)
162{
163 x->x_sr = sp[0]->s_sr;
164 siglop_ft1(x, x->x_hz);
165 dsp_add(siglop_perform, 4,
166 sp[0]->s_vec, sp[1]->s_vec,
167 x->x_ctl, sp[0]->s_n);
168
169}
170
171void lop_tilde_setup(void)
172{
173 siglop_class = class_new(gensym("lop~"), (t_newmethod)siglop_new, 0,
174 sizeof(t_siglop), 0, A_DEFFLOAT, 0);
175 CLASS_MAINSIGNALIN(siglop_class, t_siglop, x_f);
176 class_addmethod(siglop_class, (t_method)siglop_dsp, gensym("dsp"), 0);
177 class_addmethod(siglop_class, (t_method)siglop_ft1,
178 gensym("ft1"), A_FLOAT, 0);
179 class_addmethod(siglop_class, (t_method)siglop_clear, gensym("clear"), 0);
180}
diff --git a/apps/plugins/pdbox/PDa/intern/makefile b/apps/plugins/pdbox/PDa/intern/makefile
new file mode 100644
index 0000000000..99c508ab78
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/makefile
@@ -0,0 +1,48 @@
1
2
3SOURCE = $(shell ls *.c)
4TARGETS = $(SOURCE:.c=.pd_linux)
5
6EXT= pd_linux
7
8CFLAGS += -O2 -I../src -DFIXEDPOINT
9EFLAGS = -shared -Wl,-export-dynamic
10
11
12
13all: $(TARGETS)
14
15clean:
16 -rm $(TARGETS)
17 -rm *.o *~
18
19install:
20 install -d $(DESTDIR)/$(PREFIX)/lib/pd/extra
21 cp $(TARGETS) $(DESTDIR)/$(PREFIX)/lib/pd/extra
22
23%.$(EXT) : %.o
24 $(CC) -o $@ $(EFLAGS) $+
25
26
27SOURCE = $(shell ls *.c)
28TARGETS = $(SOURCE:.c=.pd_linux)
29
30EXT= pd_linux
31
32CFLAGS += -O2 -I../src -DFIXEDPOINT
33EFLAGS = -shared -Wl,-export-dynamic
34
35
36
37all: $(TARGETS)
38
39clean:
40 -rm $(TARGETS)
41 -rm *.o *~
42
43install:
44 install -d $(DESTDIR)/$(PREFIX)/lib/pd/extra
45 cp $(TARGETS) $(DESTDIR)/$(PREFIX)/lib/pd/extra
46
47%.$(EXT) : %.o
48 $(CC) -o $@ $(EFLAGS) $+
diff --git a/apps/plugins/pdbox/PDa/intern/mtof~.c b/apps/plugins/pdbox/PDa/intern/mtof~.c
new file mode 100644
index 0000000000..1db7dc52a7
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/mtof~.c
@@ -0,0 +1,98 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4typedef struct mtof_tilde
5{
6 t_object x_obj;
7 float x_f;
8} t_mtof_tilde;
9
10t_class *mtof_tilde_class;
11
12static void *mtof_tilde_new(void)
13{
14 t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class);
15 outlet_new(&x->x_obj, gensym("signal"));
16 x->x_f = 0;
17 return (x);
18}
19
20static t_int *mtof_tilde_perform(t_int *w)
21{
22 t_sample *in = *(t_sample **)(w+1), *out = *(t_sample **)(w+2);
23 t_int n = *(t_int *)(w+3);
24 for (; n--; in++, out++)
25 {
26 t_sample f = *in;
27 if (f <= ftofix(-1500.)) *out = 0;
28 else
29 {
30 if (f > ftofix(1499.)) f = ftofix(1499.);
31 *out = ftofix(8.17579891564 * exp(.0577622650 * fixtof(f)));
32 }
33 }
34 return (w + 4);
35}
36
37static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp)
38{
39 post("warning: %s not usable yet",__FUNCTION__);
40 dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
41}
42
43void mtof_tilde_setup(void)
44{
45 mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0,
46 sizeof(t_mtof_tilde), 0, 0);
47 CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f);
48 class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, gensym("dsp"), 0);
49}
50#include <m_pd.h>
51#include <m_fixed.h>
52
53typedef struct mtof_tilde
54{
55 t_object x_obj;
56 float x_f;
57} t_mtof_tilde;
58
59t_class *mtof_tilde_class;
60
61static void *mtof_tilde_new(void)
62{
63 t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class);
64 outlet_new(&x->x_obj, gensym("signal"));
65 x->x_f = 0;
66 return (x);
67}
68
69static t_int *mtof_tilde_perform(t_int *w)
70{
71 t_sample *in = *(t_sample **)(w+1), *out = *(t_sample **)(w+2);
72 t_int n = *(t_int *)(w+3);
73 for (; n--; in++, out++)
74 {
75 t_sample f = *in;
76 if (f <= ftofix(-1500.)) *out = 0;
77 else
78 {
79 if (f > ftofix(1499.)) f = ftofix(1499.);
80 *out = ftofix(8.17579891564 * exp(.0577622650 * fixtof(f)));
81 }
82 }
83 return (w + 4);
84}
85
86static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp)
87{
88 post("warning: %s not usable yet",__FUNCTION__);
89 dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
90}
91
92void mtof_tilde_setup(void)
93{
94 mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0,
95 sizeof(t_mtof_tilde), 0, 0);
96 CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f);
97 class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, gensym("dsp"), 0);
98}
diff --git a/apps/plugins/pdbox/PDa/intern/noise~.c b/apps/plugins/pdbox/PDa/intern/noise~.c
new file mode 100644
index 0000000000..2f61b9d395
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/noise~.c
@@ -0,0 +1,110 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4
5static t_class *noise_class;
6
7typedef struct _noise
8{
9 t_object x_obj;
10 int x_val;
11} t_noise;
12
13static void *noise_new(void)
14{
15 t_noise *x = (t_noise *)pd_new(noise_class);
16 static int init = 307;
17 x->x_val = (init *= 1319);
18 outlet_new(&x->x_obj, gensym("signal"));
19 return (x);
20}
21
22static t_int *noise_perform(t_int *w)
23{
24 t_sample *out = (t_sample *)(w[1]);
25 int *vp = (int *)(w[2]);
26 int n = (int)(w[3]);
27 int val = *vp;
28 while (n--)
29 {
30#ifndef FIXEDPOINT
31 *out++ = ((t_sample)((val & 0x7fffffff) - 0x40000000)) *
32 (t_sample)(1.0 / 0x40000000);
33#else
34 *out++=val>>(32-fix1);
35#endif
36 val = val * 435898247 + 382842987;
37
38 }
39 *vp = val;
40 return (w+4);
41}
42
43static void noise_dsp(t_noise *x, t_signal **sp)
44{
45 dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
46}
47
48void noise_tilde_setup(void)
49{
50 noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
51 sizeof(t_noise), 0, 0);
52 class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
53}
54
55
56#include <m_pd.h>
57#include <m_fixed.h>
58
59
60static t_class *noise_class;
61
62typedef struct _noise
63{
64 t_object x_obj;
65 int x_val;
66} t_noise;
67
68static void *noise_new(void)
69{
70 t_noise *x = (t_noise *)pd_new(noise_class);
71 static int init = 307;
72 x->x_val = (init *= 1319);
73 outlet_new(&x->x_obj, gensym("signal"));
74 return (x);
75}
76
77static t_int *noise_perform(t_int *w)
78{
79 t_sample *out = (t_sample *)(w[1]);
80 int *vp = (int *)(w[2]);
81 int n = (int)(w[3]);
82 int val = *vp;
83 while (n--)
84 {
85#ifndef FIXEDPOINT
86 *out++ = ((t_sample)((val & 0x7fffffff) - 0x40000000)) *
87 (t_sample)(1.0 / 0x40000000);
88#else
89 *out++=val>>(32-fix1);
90#endif
91 val = val * 435898247 + 382842987;
92
93 }
94 *vp = val;
95 return (w+4);
96}
97
98static void noise_dsp(t_noise *x, t_signal **sp)
99{
100 dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
101}
102
103void noise_tilde_setup(void)
104{
105 noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
106 sizeof(t_noise), 0, 0);
107 class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
108}
109
110
diff --git a/apps/plugins/pdbox/PDa/intern/osc~.c b/apps/plugins/pdbox/PDa/intern/osc~.c
new file mode 100644
index 0000000000..f8e89970e9
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/osc~.c
@@ -0,0 +1,174 @@
1
2
3#include <m_pd.h>
4#include <m_fixed.h>
5#include "cos_table.h"
6
7/* ------------------------ osc~ ----------------------------- */
8
9static t_class *osc_class, *scalarosc_class;
10
11typedef struct _osc
12{
13 t_object x_obj;
14 unsigned int x_phase;
15 t_sample x_conv;
16 t_sample x_f; /* frequency if scalar */
17} t_osc;
18
19static void *osc_new(t_floatarg f)
20{
21 t_osc *x = (t_osc *)pd_new(osc_class);
22 x->x_f = ftofix(f);
23 outlet_new(&x->x_obj, gensym("signal"));
24 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
25 x->x_phase = 0;
26 x->x_conv = 0;
27 return (x);
28}
29
30
31static t_int *osc_perform(t_int *w)
32{
33 t_osc *x = (t_osc *)(w[1]);
34 t_sample *in = (t_sample *)(w[2]);
35 t_sample *out = (t_sample *)(w[3]);
36 int n = (int)(w[4]);
37 t_sample *tab = cos_table;
38 unsigned int phase = x->x_phase;
39 int conv = x->x_conv;
40 int off;
41 int frac;
42 while (n--) {
43 phase+= mult(conv ,(*in++));
44 phase &= (itofix(1) -1);
45 off = fixtoi((long long)phase<<ILOGCOSTABSIZE);
46
47#ifdef NO_INTERPOLATION
48 *out = *(tab+off);
49#else
50// frac = phase & (itofix(1)-1);
51 frac = phase & ((1<<ILOGCOSTABSIZE)-1);
52 frac <<= (fix1-ILOGCOSTABSIZE);
53 *out = mult(*(tab + off),(itofix(1) - frac)) +
54 mult(*(tab + off + 1),frac);
55#endif
56 out++;
57 }
58 x->x_phase = phase;
59
60 return (w+5);
61}
62
63static void osc_dsp(t_osc *x, t_signal **sp)
64{
65 post("samplerate %f",sp[0]->s_sr);
66 x->x_conv = ftofix(1000.)/sp[0]->s_sr;
67 post("conf %d",x->x_conv);
68 x->x_conv = mult(x->x_conv + 500,ftofix(0.001));
69 post("conf %d",x->x_conv);
70 dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
71}
72
73static void osc_ft1(t_osc *x, t_float f)
74{
75 x->x_phase = ftofix(f); /* *2 ??? */
76}
77
78void osc_tilde_setup(void)
79{
80 osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
81 sizeof(t_osc), 0, A_DEFFLOAT, 0);
82 CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
83 class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
84 class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
85}
86
87
88
89
90#include <m_pd.h>
91#include <m_fixed.h>
92#include "cos_table.h"
93
94/* ------------------------ osc~ ----------------------------- */
95
96static t_class *osc_class, *scalarosc_class;
97
98typedef struct _osc
99{
100 t_object x_obj;
101 unsigned int x_phase;
102 t_sample x_conv;
103 t_sample x_f; /* frequency if scalar */
104} t_osc;
105
106static void *osc_new(t_floatarg f)
107{
108 t_osc *x = (t_osc *)pd_new(osc_class);
109 x->x_f = ftofix(f);
110 outlet_new(&x->x_obj, gensym("signal"));
111 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
112 x->x_phase = 0;
113 x->x_conv = 0;
114 return (x);
115}
116
117
118static t_int *osc_perform(t_int *w)
119{
120 t_osc *x = (t_osc *)(w[1]);
121 t_sample *in = (t_sample *)(w[2]);
122 t_sample *out = (t_sample *)(w[3]);
123 int n = (int)(w[4]);
124 t_sample *tab = cos_table;
125 unsigned int phase = x->x_phase;
126 int conv = x->x_conv;
127 int off;
128 int frac;
129 while (n--) {
130 phase+= mult(conv ,(*in++));
131 phase &= (itofix(1) -1);
132 off = fixtoi((long long)phase<<ILOGCOSTABSIZE);
133
134#ifdef NO_INTERPOLATION
135 *out = *(tab+off);
136#else
137// frac = phase & (itofix(1)-1);
138 frac = phase & ((1<<ILOGCOSTABSIZE)-1);
139 frac <<= (fix1-ILOGCOSTABSIZE);
140 *out = mult(*(tab + off),(itofix(1) - frac)) +
141 mult(*(tab + off + 1),frac);
142#endif
143 out++;
144 }
145 x->x_phase = phase;
146
147 return (w+5);
148}
149
150static void osc_dsp(t_osc *x, t_signal **sp)
151{
152 post("samplerate %f",sp[0]->s_sr);
153 x->x_conv = ftofix(1000.)/sp[0]->s_sr;
154 post("conf %d",x->x_conv);
155 x->x_conv = mult(x->x_conv + 500,ftofix(0.001));
156 post("conf %d",x->x_conv);
157 dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
158}
159
160static void osc_ft1(t_osc *x, t_float f)
161{
162 x->x_phase = ftofix(f); /* *2 ??? */
163}
164
165void osc_tilde_setup(void)
166{
167 osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
168 sizeof(t_osc), 0, A_DEFFLOAT, 0);
169 CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
170 class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
171 class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
172}
173
174
diff --git a/apps/plugins/pdbox/PDa/intern/phasor~.c b/apps/plugins/pdbox/PDa/intern/phasor~.c
new file mode 100644
index 0000000000..b823286b89
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/phasor~.c
@@ -0,0 +1,138 @@
1
2#include <m_pd.h>
3#include <m_fixed.h>
4
5/* -------------------------- phasor~ ------------------------------ */
6static t_class *phasor_class;
7
8typedef struct _phasor
9{
10 t_object x_obj;
11 unsigned int x_phase;
12 t_sample x_conv;
13 t_sample x_f; /* scalar frequency */
14} t_phasor;
15
16static void *phasor_new(t_floatarg f)
17{
18 t_phasor *x = (t_phasor *)pd_new(phasor_class);
19 x->x_f = ftofix(f);
20 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
21 x->x_phase = 0;
22 x->x_conv = 0;
23 outlet_new(&x->x_obj, gensym("signal"));
24 return (x);
25}
26
27static t_int *phasor_perform(t_int *w)
28{
29 t_phasor *x = (t_phasor *)(w[1]);
30 t_sample *in = (t_sample *)(w[2]);
31 t_sample *out = (t_sample *)(w[3]);
32 int n = (int)(w[4]);
33 unsigned int phase = x->x_phase;
34 int conv = x->x_conv;
35
36 while (n--) {
37 phase+= mult(conv , (*in++));
38 phase &= (itofix(1) - 1);
39 *out++ = phase;
40 }
41 x->x_phase = phase;
42
43 return (w+5);
44}
45
46static void phasor_dsp(t_phasor *x, t_signal **sp)
47{
48 x->x_conv = ftofix(1000.)/sp[0]->s_sr;
49 x->x_conv = mult(x->x_conv + 500,ftofix(0.001));
50 dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
51}
52
53
54static void phasor_ft1(t_phasor *x, t_float f)
55{
56 x->x_phase = ftofix(f);
57}
58
59void phasor_tilde_setup(void)
60{
61 phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
62 sizeof(t_phasor), 0, A_DEFFLOAT, 0);
63 CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
64 class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
65 class_addmethod(phasor_class, (t_method)phasor_ft1,
66 gensym("ft1"), A_FLOAT, 0);
67 class_sethelpsymbol(phasor_class, gensym("osc~-help.pd"));
68}
69
70
71#include <m_pd.h>
72#include <m_fixed.h>
73
74/* -------------------------- phasor~ ------------------------------ */
75static t_class *phasor_class;
76
77typedef struct _phasor
78{
79 t_object x_obj;
80 unsigned int x_phase;
81 t_sample x_conv;
82 t_sample x_f; /* scalar frequency */
83} t_phasor;
84
85static void *phasor_new(t_floatarg f)
86{
87 t_phasor *x = (t_phasor *)pd_new(phasor_class);
88 x->x_f = ftofix(f);
89 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
90 x->x_phase = 0;
91 x->x_conv = 0;
92 outlet_new(&x->x_obj, gensym("signal"));
93 return (x);
94}
95
96static t_int *phasor_perform(t_int *w)
97{
98 t_phasor *x = (t_phasor *)(w[1]);
99 t_sample *in = (t_sample *)(w[2]);
100 t_sample *out = (t_sample *)(w[3]);
101 int n = (int)(w[4]);
102 unsigned int phase = x->x_phase;
103 int conv = x->x_conv;
104
105 while (n--) {
106 phase+= mult(conv , (*in++));
107 phase &= (itofix(1) - 1);
108 *out++ = phase;
109 }
110 x->x_phase = phase;
111
112 return (w+5);
113}
114
115static void phasor_dsp(t_phasor *x, t_signal **sp)
116{
117 x->x_conv = ftofix(1000.)/sp[0]->s_sr;
118 x->x_conv = mult(x->x_conv + 500,ftofix(0.001));
119 dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
120}
121
122
123static void phasor_ft1(t_phasor *x, t_float f)
124{
125 x->x_phase = ftofix(f);
126}
127
128void phasor_tilde_setup(void)
129{
130 phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
131 sizeof(t_phasor), 0, A_DEFFLOAT, 0);
132 CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
133 class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
134 class_addmethod(phasor_class, (t_method)phasor_ft1,
135 gensym("ft1"), A_FLOAT, 0);
136 class_sethelpsymbol(phasor_class, gensym("osc~-help.pd"));
137}
138
diff --git a/apps/plugins/pdbox/PDa/intern/powtodb~.c b/apps/plugins/pdbox/PDa/intern/powtodb~.c
new file mode 100644
index 0000000000..65cf6c0c36
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/powtodb~.c
@@ -0,0 +1,106 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4#define LOGTEN 2.302585092994
5
6
7typedef struct powtodb_tilde
8{
9 t_object x_obj;
10 float x_f;
11} t_powtodb_tilde;
12
13t_class *powtodb_tilde_class;
14
15static void *powtodb_tilde_new(void)
16{
17 t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class);
18 outlet_new(&x->x_obj, gensym("signal"));
19 x->x_f = 0;
20 return (x);
21}
22
23static t_int *powtodb_tilde_perform(t_int *w)
24{
25 t_sample *in = *(t_sample **)(w+1), *out = *(t_sample **)(w+2);
26 t_int n = *(t_int *)(w+3);
27 for (; n--; in++, out++)
28 {
29 float f = *in;
30 if (f <= 0) *out = 0;
31 else
32 {
33 float g = 100 + 10./LOGTEN * log(f);
34 *out = (g < 0 ? 0 : g);
35 }
36 }
37 return (w + 4);
38}
39
40static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp)
41{
42 post("warning: %s not usable yet",__FUNCTION__);
43 dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
44}
45
46void powtodb_tilde_setup(void)
47{
48 powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0,
49 sizeof(t_powtodb_tilde), 0, 0);
50 CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f);
51 class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0);
52}
53
54#include <m_pd.h>
55#include <m_fixed.h>
56
57#define LOGTEN 2.302585092994
58
59
60typedef struct powtodb_tilde
61{
62 t_object x_obj;
63 float x_f;
64} t_powtodb_tilde;
65
66t_class *powtodb_tilde_class;
67
68static void *powtodb_tilde_new(void)
69{
70 t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class);
71 outlet_new(&x->x_obj, gensym("signal"));
72 x->x_f = 0;
73 return (x);
74}
75
76static t_int *powtodb_tilde_perform(t_int *w)
77{
78 t_sample *in = *(t_sample **)(w+1), *out = *(t_sample **)(w+2);
79 t_int n = *(t_int *)(w+3);
80 for (; n--; in++, out++)
81 {
82 float f = *in;
83 if (f <= 0) *out = 0;
84 else
85 {
86 float g = 100 + 10./LOGTEN * log(f);
87 *out = (g < 0 ? 0 : g);
88 }
89 }
90 return (w + 4);
91}
92
93static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp)
94{
95 post("warning: %s not usable yet",__FUNCTION__);
96 dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
97}
98
99void powtodb_tilde_setup(void)
100{
101 powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0,
102 sizeof(t_powtodb_tilde), 0, 0);
103 CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f);
104 class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0);
105}
106
diff --git a/apps/plugins/pdbox/PDa/intern/print~.c b/apps/plugins/pdbox/PDa/intern/print~.c
new file mode 100644
index 0000000000..3051ca37be
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/print~.c
@@ -0,0 +1,156 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4static t_class *print_class;
5
6typedef struct _print
7{
8 t_object x_obj;
9 float x_f;
10 t_symbol *x_sym;
11 int x_count;
12} t_print;
13
14static t_int *print_perform(t_int *w)
15{
16 t_print *x = (t_print *)(w[1]);
17 t_sample *in = (t_sample *)(w[2]);
18 int n = (int)(w[3]);
19 if (x->x_count)
20 {
21 post("%s:", x->x_sym->s_name);
22 if (n == 1) post("%8g", in[0]);
23 else if (n == 2) post("%8g %8g", in[0], in[1]);
24 else if (n == 4) post("%8g %8g %8g %8g",
25 in[0], in[1], in[2], in[3]);
26 else while (n > 0)
27 {
28 post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
29 fixtof(in[0]),
30 fixtof(in[1]),
31 fixtof(in[2]),
32 fixtof(in[3]),
33 fixtof(in[4]),
34 fixtof(in[5]),
35 fixtof(in[6]),
36 fixtof(in[7]));
37 n -= 8;
38 in += 8;
39 }
40 x->x_count--;
41 }
42 return (w+4);
43}
44
45static void print_dsp(t_print *x, t_signal **sp)
46{
47 dsp_add(print_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
48}
49
50static void print_float(t_print *x, t_float f)
51{
52 if (f < 0) f = 0;
53 x->x_count = f;
54}
55
56static void print_bang(t_print *x)
57{
58 x->x_count = 1;
59}
60
61static void *print_new(t_symbol *s)
62{
63 t_print *x = (t_print *)pd_new(print_class);
64 x->x_sym = (s->s_name[0]? s : gensym("print~"));
65 x->x_count = 0;
66 x->x_f = 0;
67 return (x);
68}
69
70void print_tilde_setup(void)
71{
72 print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0,
73 sizeof(t_print), 0, A_DEFSYM, 0);
74 CLASS_MAINSIGNALIN(print_class, t_print, x_f);
75 class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), 0);
76 class_addbang(print_class, print_bang);
77 class_addfloat(print_class, print_float);
78}
79#include <m_pd.h>
80#include <m_fixed.h>
81
82static t_class *print_class;
83
84typedef struct _print
85{
86 t_object x_obj;
87 float x_f;
88 t_symbol *x_sym;
89 int x_count;
90} t_print;
91
92static t_int *print_perform(t_int *w)
93{
94 t_print *x = (t_print *)(w[1]);
95 t_sample *in = (t_sample *)(w[2]);
96 int n = (int)(w[3]);
97 if (x->x_count)
98 {
99 post("%s:", x->x_sym->s_name);
100 if (n == 1) post("%8g", in[0]);
101 else if (n == 2) post("%8g %8g", in[0], in[1]);
102 else if (n == 4) post("%8g %8g %8g %8g",
103 in[0], in[1], in[2], in[3]);
104 else while (n > 0)
105 {
106 post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
107 fixtof(in[0]),
108 fixtof(in[1]),
109 fixtof(in[2]),
110 fixtof(in[3]),
111 fixtof(in[4]),
112 fixtof(in[5]),
113 fixtof(in[6]),
114 fixtof(in[7]));
115 n -= 8;
116 in += 8;
117 }
118 x->x_count--;
119 }
120 return (w+4);
121}
122
123static void print_dsp(t_print *x, t_signal **sp)
124{
125 dsp_add(print_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
126}
127
128static void print_float(t_print *x, t_float f)
129{
130 if (f < 0) f = 0;
131 x->x_count = f;
132}
133
134static void print_bang(t_print *x)
135{
136 x->x_count = 1;
137}
138
139static void *print_new(t_symbol *s)
140{
141 t_print *x = (t_print *)pd_new(print_class);
142 x->x_sym = (s->s_name[0]? s : gensym("print~"));
143 x->x_count = 0;
144 x->x_f = 0;
145 return (x);
146}
147
148void print_tilde_setup(void)
149{
150 print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0,
151 sizeof(t_print), 0, A_DEFSYM, 0);
152 CLASS_MAINSIGNALIN(print_class, t_print, x_f);
153 class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), 0);
154 class_addbang(print_class, print_bang);
155 class_addfloat(print_class, print_float);
156}
diff --git a/apps/plugins/pdbox/PDa/intern/rmstodb~.c b/apps/plugins/pdbox/PDa/intern/rmstodb~.c
new file mode 100644
index 0000000000..e57345880a
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/rmstodb~.c
@@ -0,0 +1,104 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4#define LOGTEN 2.302585092994
5
6
7typedef struct rmstodb_tilde
8{
9 t_object x_obj;
10 float x_f;
11} t_rmstodb_tilde;
12
13t_class *rmstodb_tilde_class;
14
15static void *rmstodb_tilde_new(void)
16{
17 t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class);
18 outlet_new(&x->x_obj, gensym("signal"));
19 x->x_f = 0;
20 return (x);
21}
22
23static t_int *rmstodb_tilde_perform(t_int *w)
24{
25 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
26 t_int n = *(t_int *)(w+3);
27 for (; n--; in++, out++)
28 {
29 float f = *in;
30 if (f <= 0) *out = 0;
31 else
32 {
33 float g = 100 + 20./LOGTEN * log(f);
34 *out = (g < 0 ? 0 : g);
35 }
36 }
37 return (w + 4);
38}
39
40static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp)
41{
42 post("warning: %s not usable yet",__FUNCTION__);
43 dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
44}
45
46void rmstodb_tilde_setup(void)
47{
48 rmstodb_tilde_class = class_new(gensym("rmstodb~"), (t_newmethod)rmstodb_tilde_new, 0,
49 sizeof(t_rmstodb_tilde), 0, 0);
50 CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f);
51 class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, gensym("dsp"), 0);
52}
53#include <m_pd.h>
54#include <m_fixed.h>
55
56#define LOGTEN 2.302585092994
57
58
59typedef struct rmstodb_tilde
60{
61 t_object x_obj;
62 float x_f;
63} t_rmstodb_tilde;
64
65t_class *rmstodb_tilde_class;
66
67static void *rmstodb_tilde_new(void)
68{
69 t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class);
70 outlet_new(&x->x_obj, gensym("signal"));
71 x->x_f = 0;
72 return (x);
73}
74
75static t_int *rmstodb_tilde_perform(t_int *w)
76{
77 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
78 t_int n = *(t_int *)(w+3);
79 for (; n--; in++, out++)
80 {
81 float f = *in;
82 if (f <= 0) *out = 0;
83 else
84 {
85 float g = 100 + 20./LOGTEN * log(f);
86 *out = (g < 0 ? 0 : g);
87 }
88 }
89 return (w + 4);
90}
91
92static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp)
93{
94 post("warning: %s not usable yet",__FUNCTION__);
95 dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
96}
97
98void rmstodb_tilde_setup(void)
99{
100 rmstodb_tilde_class = class_new(gensym("rmstodb~"), (t_newmethod)rmstodb_tilde_new, 0,
101 sizeof(t_rmstodb_tilde), 0, 0);
102 CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f);
103 class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, gensym("dsp"), 0);
104}
diff --git a/apps/plugins/pdbox/PDa/intern/rsqrt~.c b/apps/plugins/pdbox/PDa/intern/rsqrt~.c
new file mode 100644
index 0000000000..e33a21a0e9
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/rsqrt~.c
@@ -0,0 +1,210 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
5
6#define DUMTAB1SIZE 256
7#define DUMTAB2SIZE 1024
8
9static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
10
11static void init_rsqrt(void)
12{
13 int i;
14 for (i = 0; i < DUMTAB1SIZE; i++)
15 {
16 float f;
17 long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
18 *(long *)(&f) = l;
19 rsqrt_exptab[i] = 1./sqrt(f);
20 }
21 for (i = 0; i < DUMTAB2SIZE; i++)
22 {
23 float f = 1 + (1./DUMTAB2SIZE) * i;
24 rsqrt_mantissatab[i] = 1./sqrt(f);
25 }
26}
27
28 /* these are used in externs like "bonk" */
29
30float q8_rsqrt(float f)
31{
32 long l = *(long *)(&f);
33 if (f < 0) return (0);
34 else return (rsqrt_exptab[(l >> 23) & 0xff] *
35 rsqrt_mantissatab[(l >> 13) & 0x3ff]);
36}
37
38float q8_sqrt(float f)
39{
40 long l = *(long *)(&f);
41 if (f < 0) return (0);
42 else return (f * rsqrt_exptab[(l >> 23) & 0xff] *
43 rsqrt_mantissatab[(l >> 13) & 0x3ff]);
44}
45
46 /* the old names are OK unless we're in IRIX N32 */
47
48#ifndef N32
49float qsqrt(float f) {return (q8_sqrt(f)); }
50float qrsqrt(float f) {return (q8_rsqrt(f)); }
51#endif
52
53
54
55typedef struct sigrsqrt
56{
57 t_object x_obj;
58 float x_f;
59} t_sigrsqrt;
60
61static t_class *sigrsqrt_class;
62
63static void *sigrsqrt_new(void)
64{
65 t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
66 outlet_new(&x->x_obj, gensym("signal"));
67 x->x_f = 0;
68 return (x);
69}
70
71static t_int *sigrsqrt_perform(t_int *w)
72{
73 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
74 t_int n = *(t_int *)(w+3);
75 while (n--)
76 {
77 float f = *in;
78 long l = *(long *)(in++);
79 if (f < 0) *out++ = 0;
80 else
81 {
82 float g = rsqrt_exptab[(l >> 23) & 0xff] *
83 rsqrt_mantissatab[(l >> 13) & 0x3ff];
84 *out++ = 1.5 * g - 0.5 * g * g * g * f;
85 }
86 }
87 return (w + 4);
88}
89
90static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp)
91{
92 dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
93}
94
95void rsqrt_tilde_setup(void)
96{
97 init_rsqrt();
98 sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0,
99 sizeof(t_sigrsqrt), 0, 0);
100 /* an old name for it: */
101 class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0);
102 CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f);
103 class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, gensym("dsp"), 0);
104}
105
106#include <m_pd.h>
107#include <m_fixed.h>
108
109/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
110
111#define DUMTAB1SIZE 256
112#define DUMTAB2SIZE 1024
113
114static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
115
116static void init_rsqrt(void)
117{
118 int i;
119 for (i = 0; i < DUMTAB1SIZE; i++)
120 {
121 float f;
122 long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
123 *(long *)(&f) = l;
124 rsqrt_exptab[i] = 1./sqrt(f);
125 }
126 for (i = 0; i < DUMTAB2SIZE; i++)
127 {
128 float f = 1 + (1./DUMTAB2SIZE) * i;
129 rsqrt_mantissatab[i] = 1./sqrt(f);
130 }
131}
132
133 /* these are used in externs like "bonk" */
134
135float q8_rsqrt(float f)
136{
137 long l = *(long *)(&f);
138 if (f < 0) return (0);
139 else return (rsqrt_exptab[(l >> 23) & 0xff] *
140 rsqrt_mantissatab[(l >> 13) & 0x3ff]);
141}
142
143float q8_sqrt(float f)
144{
145 long l = *(long *)(&f);
146 if (f < 0) return (0);
147 else return (f * rsqrt_exptab[(l >> 23) & 0xff] *
148 rsqrt_mantissatab[(l >> 13) & 0x3ff]);
149}
150
151 /* the old names are OK unless we're in IRIX N32 */
152
153#ifndef N32
154float qsqrt(float f) {return (q8_sqrt(f)); }
155float qrsqrt(float f) {return (q8_rsqrt(f)); }
156#endif
157
158
159
160typedef struct sigrsqrt
161{
162 t_object x_obj;
163 float x_f;
164} t_sigrsqrt;
165
166static t_class *sigrsqrt_class;
167
168static void *sigrsqrt_new(void)
169{
170 t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
171 outlet_new(&x->x_obj, gensym("signal"));
172 x->x_f = 0;
173 return (x);
174}
175
176static t_int *sigrsqrt_perform(t_int *w)
177{
178 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
179 t_int n = *(t_int *)(w+3);
180 while (n--)
181 {
182 float f = *in;
183 long l = *(long *)(in++);
184 if (f < 0) *out++ = 0;
185 else
186 {
187 float g = rsqrt_exptab[(l >> 23) & 0xff] *
188 rsqrt_mantissatab[(l >> 13) & 0x3ff];
189 *out++ = 1.5 * g - 0.5 * g * g * g * f;
190 }
191 }
192 return (w + 4);
193}
194
195static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp)
196{
197 dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
198}
199
200void rsqrt_tilde_setup(void)
201{
202 init_rsqrt();
203 sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0,
204 sizeof(t_sigrsqrt), 0, 0);
205 /* an old name for it: */
206 class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0);
207 CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f);
208 class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, gensym("dsp"), 0);
209}
210
diff --git a/apps/plugins/pdbox/PDa/intern/samphold~.c b/apps/plugins/pdbox/PDa/intern/samphold~.c
new file mode 100644
index 0000000000..5ccf3d9cfe
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/samphold~.c
@@ -0,0 +1,150 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4typedef struct sigsamphold
5{
6 t_object x_obj;
7 t_sample x_f;
8 t_sample x_lastin;
9 t_sample x_lastout;
10} t_sigsamphold;
11
12t_class *sigsamphold_class;
13
14static void *sigsamphold_new(void)
15{
16 t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
17 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
18 outlet_new(&x->x_obj, gensym("signal"));
19 x->x_lastin = 0;
20 x->x_lastout = 0;
21 x->x_f = 0;
22 return (x);
23}
24
25static t_int *sigsamphold_perform(t_int *w)
26{
27 t_sample *in1 = (t_sample *)(w[1]);
28 t_sample *in2 = (t_sample *)(w[2]);
29 t_sample *out = (t_sample *)(w[3]);
30 t_sigsamphold *x = (t_sigsamphold *)(w[4]);
31 int n = (t_int)(w[5]);
32 int i;
33 t_sample lastin = x->x_lastin;
34 t_sample lastout = x->x_lastout;
35 for (i = 0; i < n; i++, *in1++)
36 {
37 t_sample next = *in2++;
38 if (next < lastin) lastout = *in1;
39 *out++ = lastout;
40 lastin = next;
41 }
42 x->x_lastin = lastin;
43 x->x_lastout = lastout;
44 return (w+6);
45}
46
47static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp)
48{
49 dsp_add(sigsamphold_perform, 5,
50 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
51 x, sp[0]->s_n);
52}
53
54static void sigsamphold_reset(t_sigsamphold *x)
55{
56 x->x_lastin = 0x7fffffff;
57}
58
59static void sigsamphold_set(t_sigsamphold *x, t_float f)
60{
61 x->x_lastout = f;
62}
63
64void samphold_tilde_setup(void)
65{
66 sigsamphold_class = class_new(gensym("samphold~"),
67 (t_newmethod)sigsamphold_new, 0, sizeof(t_sigsamphold), 0, 0);
68 CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, x_f);
69 class_addmethod(sigsamphold_class, (t_method)sigsamphold_set,
70 gensym("set"), A_FLOAT, 0);
71 class_addmethod(sigsamphold_class, (t_method)sigsamphold_reset,
72 gensym("reset"), 0);
73 class_addmethod(sigsamphold_class, (t_method)sigsamphold_dsp,
74 gensym("dsp"), 0);
75}
76#include <m_pd.h>
77#include <m_fixed.h>
78
79typedef struct sigsamphold
80{
81 t_object x_obj;
82 t_sample x_f;
83 t_sample x_lastin;
84 t_sample x_lastout;
85} t_sigsamphold;
86
87t_class *sigsamphold_class;
88
89static void *sigsamphold_new(void)
90{
91 t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
92 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
93 outlet_new(&x->x_obj, gensym("signal"));
94 x->x_lastin = 0;
95 x->x_lastout = 0;
96 x->x_f = 0;
97 return (x);
98}
99
100static t_int *sigsamphold_perform(t_int *w)
101{
102 t_sample *in1 = (t_sample *)(w[1]);
103 t_sample *in2 = (t_sample *)(w[2]);
104 t_sample *out = (t_sample *)(w[3]);
105 t_sigsamphold *x = (t_sigsamphold *)(w[4]);
106 int n = (t_int)(w[5]);
107 int i;
108 t_sample lastin = x->x_lastin;
109 t_sample lastout = x->x_lastout;
110 for (i = 0; i < n; i++, *in1++)
111 {
112 t_sample next = *in2++;
113 if (next < lastin) lastout = *in1;
114 *out++ = lastout;
115 lastin = next;
116 }
117 x->x_lastin = lastin;
118 x->x_lastout = lastout;
119 return (w+6);
120}
121
122static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp)
123{
124 dsp_add(sigsamphold_perform, 5,
125 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
126 x, sp[0]->s_n);
127}
128
129static void sigsamphold_reset(t_sigsamphold *x)
130{
131 x->x_lastin = 0x7fffffff;
132}
133
134static void sigsamphold_set(t_sigsamphold *x, t_float f)
135{
136 x->x_lastout = f;
137}
138
139void samphold_tilde_setup(void)
140{
141 sigsamphold_class = class_new(gensym("samphold~"),
142 (t_newmethod)sigsamphold_new, 0, sizeof(t_sigsamphold), 0, 0);
143 CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, x_f);
144 class_addmethod(sigsamphold_class, (t_method)sigsamphold_set,
145 gensym("set"), A_FLOAT, 0);
146 class_addmethod(sigsamphold_class, (t_method)sigsamphold_reset,
147 gensym("reset"), 0);
148 class_addmethod(sigsamphold_class, (t_method)sigsamphold_dsp,
149 gensym("dsp"), 0);
150}
diff --git a/apps/plugins/pdbox/PDa/intern/sformat.h b/apps/plugins/pdbox/PDa/intern/sformat.h
new file mode 100644
index 0000000000..b75ef98c9a
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/sformat.h
@@ -0,0 +1,110 @@
1
2#ifndef SFORMAT_H__
3#define SFORMAT_H__
4
5typedef unsigned short uint16;
6typedef unsigned long uint32;
7
8#define FORMAT_WAVE 0
9#define FORMAT_AIFF 1
10#define FORMAT_NEXT 2
11
12/* the NeXTStep sound header structure; can be big or little endian */
13
14typedef struct _nextstep
15{
16 char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
17 uint32 ns_onset; /* byte offset of first sample */
18 uint32 ns_length; /* length of sound in bytes */
19 uint32 ns_format; /* format; see below */
20 uint32 ns_sr; /* sample rate */
21 uint32 ns_nchans; /* number of channels */
22 char ns_info[4]; /* comment */
23} t_nextstep;
24
25#define NS_FORMAT_LINEAR_16 3
26#define NS_FORMAT_LINEAR_24 4
27#define NS_FORMAT_FLOAT 6
28#define SCALE (1./(1024. * 1024. * 1024. * 2.))
29
30/* the WAVE header. All Wave files are little endian. We assume
31 the "fmt" chunk comes first which is usually the case but perhaps not
32 always; same for AIFF and the "COMM" chunk. */
33
34typedef unsigned word;
35typedef unsigned long dword;
36
37typedef struct _wave
38{
39 char w_fileid[4]; /* chunk id 'RIFF' */
40 uint32 w_chunksize; /* chunk size */
41 char w_waveid[4]; /* wave chunk id 'WAVE' */
42 char w_fmtid[4]; /* format chunk id 'fmt ' */
43 uint32 w_fmtchunksize; /* format chunk size */
44 uint16 w_fmttag; /* format tag, 1 for PCM */
45 uint16 w_nchannels; /* number of channels */
46 uint32 w_samplespersec; /* sample rate in hz */
47 uint32 w_navgbytespersec; /* average bytes per second */
48 uint16 w_nblockalign; /* number of bytes per sample */
49 uint16 w_nbitspersample; /* number of bits in a sample */
50 char w_datachunkid[4]; /* data chunk id 'data' */
51 uint32 w_datachunksize; /* length of data chunk */
52} t_wave;
53
54
55#endif
56
57#ifndef SFORMAT_H__
58#define SFORMAT_H__
59
60typedef unsigned short uint16;
61typedef unsigned long uint32;
62
63#define FORMAT_WAVE 0
64#define FORMAT_AIFF 1
65#define FORMAT_NEXT 2
66
67/* the NeXTStep sound header structure; can be big or little endian */
68
69typedef struct _nextstep
70{
71 char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
72 uint32 ns_onset; /* byte offset of first sample */
73 uint32 ns_length; /* length of sound in bytes */
74 uint32 ns_format; /* format; see below */
75 uint32 ns_sr; /* sample rate */
76 uint32 ns_nchans; /* number of channels */
77 char ns_info[4]; /* comment */
78} t_nextstep;
79
80#define NS_FORMAT_LINEAR_16 3
81#define NS_FORMAT_LINEAR_24 4
82#define NS_FORMAT_FLOAT 6
83#define SCALE (1./(1024. * 1024. * 1024. * 2.))
84
85/* the WAVE header. All Wave files are little endian. We assume
86 the "fmt" chunk comes first which is usually the case but perhaps not
87 always; same for AIFF and the "COMM" chunk. */
88
89typedef unsigned word;
90typedef unsigned long dword;
91
92typedef struct _wave
93{
94 char w_fileid[4]; /* chunk id 'RIFF' */
95 uint32 w_chunksize; /* chunk size */
96 char w_waveid[4]; /* wave chunk id 'WAVE' */
97 char w_fmtid[4]; /* format chunk id 'fmt ' */
98 uint32 w_fmtchunksize; /* format chunk size */
99 uint16 w_fmttag; /* format tag, 1 for PCM */
100 uint16 w_nchannels; /* number of channels */
101 uint32 w_samplespersec; /* sample rate in hz */
102 uint32 w_navgbytespersec; /* average bytes per second */
103 uint16 w_nblockalign; /* number of bytes per sample */
104 uint16 w_nbitspersample; /* number of bits in a sample */
105 char w_datachunkid[4]; /* data chunk id 'data' */
106 uint32 w_datachunksize; /* length of data chunk */
107} t_wave;
108
109
110#endif
diff --git a/apps/plugins/pdbox/PDa/intern/sfread~.c b/apps/plugins/pdbox/PDa/intern/sfread~.c
new file mode 100644
index 0000000000..0980583fa3
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/sfread~.c
@@ -0,0 +1,576 @@
1#include <unistd.h>
2#include <fcntl.h>
3#include <errno.h>
4#include <stdio.h>
5#include <string.h>
6#include <unistd.h>
7#include <sys/mman.h>
8#include <sys/stat.h>
9
10#include <m_pd.h>
11#include <m_fixed.h>
12#include "g_canvas.h"
13
14/* ------------------------ sfread~ ----------------------------- */
15
16#include "sformat.h"
17
18static t_class *sfread_class;
19
20
21typedef struct _sfread
22{
23 t_object x_obj;
24 void* x_mapaddr;
25 int x_fd;
26
27 int x_play;
28 int x_channels;
29 long long x_size;
30 int x_loop;
31 t_time x_pos;
32
33 t_sample x_skip;
34 t_sample x_speed;
35
36 t_glist * x_glist;
37 t_outlet *x_bangout;
38} t_sfread;
39
40
41void sfread_open(t_sfread *x,t_symbol *filename)
42{
43 struct stat fstate;
44 char fname[MAXPDSTRING];
45
46 if (filename == &s_) {
47 post("sfread: open without filename");
48 return;
49 }
50
51 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
52 fname, MAXPDSTRING);
53
54
55 /* close the old file */
56
57 if (x->x_mapaddr) munmap(x->x_mapaddr,x->x_size);
58 if (x->x_fd >= 0) close(x->x_fd);
59
60 if ((x->x_fd = open(fname,O_RDONLY)) < 0)
61 {
62 error("can't open %s",fname);
63 x->x_play = 0;
64 x->x_mapaddr = NULL;
65 return;
66 }
67
68 /* get the size */
69
70 fstat(x->x_fd,&fstate);
71 x->x_size = fstate.st_size;
72
73 /* map the file into memory */
74
75 if (!(x->x_mapaddr = mmap(NULL,x->x_size,PROT_READ,MAP_PRIVATE,x->x_fd,0)))
76 {
77 error("can't mmap %s",fname);
78 return;
79 }
80}
81
82#define MAX_CHANS 4
83
84static t_int *sfread_perform(t_int *w)
85{
86 t_sfread* x = (t_sfread*)(w[1]);
87 short* buf = x->x_mapaddr;
88 t_time tmp;
89 int c = x->x_channels;
90 t_time pos = x->x_pos;
91 t_sample speed = x->x_speed;
92 t_time end = itofix(x->x_size/sizeof(short)/c);
93 int i,n;
94 t_sample* out[MAX_CHANS];
95
96 for (i=0;i<c;i++)
97 out[i] = (t_sample *)(w[3+i]);
98 n = (int)(w[3+c]);
99
100 /* loop */
101
102 if (pos > end)
103 pos = end;
104
105 if (pos + n*speed >= end) { // playing forward end
106 if (!x->x_loop) {
107 x->x_play=0;
108 }
109 pos = x->x_skip;
110 }
111 tmp = n*speed;
112
113 if (pos + n*speed <= 0) { // playing backwards end
114 if (!x->x_loop) {
115 x->x_play=0;
116 }
117 pos = end;
118
119 }
120 if (x->x_play && x->x_mapaddr) {
121 t_time aoff = fixtoi(pos)*c;
122 while (n--) {
123 long frac = (long long)((1<<fix1)-1)&pos;
124
125 for (i=0;i<c;i++) {
126 t_sample bs = *(buf+aoff+i)<<(fix1-16);
127 t_sample cs = *(buf+aoff+i+1)<<(fix1-16);
128 *out[i]++ = bs + mult((cs - bs),frac);
129
130 }
131 pos += speed;
132 aoff = fixtoi(pos)*c;
133 if (aoff > end) {
134 if (x->x_loop) pos = x->x_skip;
135 else break;
136 }
137 if (aoff < x->x_skip) {
138 if (x->x_loop) pos = end;
139 else break;
140 }
141 }
142 /* Fill with zero in case of end */
143 n++;
144 while (n--)
145 for (i=0;i<c;i++)
146 *out[i]++ = 0;
147 }
148 else {
149 while (n--) {
150 for (i=0;i<c;i++)
151 *out[i]++ = 0.;
152 }
153 }
154
155 x->x_pos = pos;
156 return (w+c+4);
157}
158
159
160static void sfread_float(t_sfread *x, t_floatarg f)
161{
162 int t = f;
163 if (t && x->x_mapaddr) {
164 x->x_play=1;
165 }
166 else {
167 x->x_play=0;
168 }
169
170}
171
172static void sfread_loop(t_sfread *x, t_floatarg f)
173{
174 x->x_loop = f;
175}
176
177
178
179static void sfread_size(t_sfread* x)
180{
181 t_atom a;
182
183 SETFLOAT(&a,x->x_size*0.5/x->x_channels);
184 outlet_list(x->x_bangout, gensym("size"),1,&a);
185}
186
187static void sfread_state(t_sfread* x)
188{
189 t_atom a;
190
191 SETFLOAT(&a,x->x_play);
192 outlet_list(x->x_bangout, gensym("state"),1,&a);
193}
194
195
196
197
198static void sfread_bang(t_sfread* x)
199{
200 x->x_pos = x->x_skip;
201 sfread_float(x,1.0);
202}
203
204
205static void sfread_dsp(t_sfread *x, t_signal **sp)
206{
207/* post("sfread: dsp"); */
208 switch (x->x_channels) {
209 case 1:
210 dsp_add(sfread_perform, 4, x, sp[0]->s_vec,
211 sp[1]->s_vec, sp[0]->s_n);
212 break;
213 case 2:
214 dsp_add(sfread_perform, 5, x, sp[0]->s_vec,
215 sp[1]->s_vec,sp[2]->s_vec, sp[0]->s_n);
216 break;
217 case 4:
218 dsp_add(sfread_perform, 6, x, sp[0]->s_vec,
219 sp[1]->s_vec,sp[2]->s_vec,
220 sp[3]->s_vec,sp[4]->s_vec,
221 sp[0]->s_n);
222 break;
223 }
224}
225
226
227static void sfread_speed(t_sfread* x, t_floatarg f)
228{
229 x->x_speed = ftofix(f);
230}
231
232static void sfread_offset(t_sfread* x, t_floatarg f)
233{
234 x->x_pos = (int)f;
235}
236
237static void *sfread_new(t_floatarg chan,t_floatarg skip)
238{
239 t_sfread *x = (t_sfread *)pd_new(sfread_class);
240 t_int c = chan;
241
242 x->x_glist = (t_glist*) canvas_getcurrent();
243
244 if (c<1 || c > MAX_CHANS) c = 1;
245 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
246 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft2"));
247
248
249 x->x_fd = -1;
250 x->x_mapaddr = NULL;
251
252 x->x_size = 0;
253 x->x_loop = 0;
254 x->x_channels = c;
255 x->x_mapaddr=NULL;
256 x->x_pos = 0;
257 x->x_skip = 0;
258 x->x_speed = ftofix(1.0);
259 x->x_play = 0;
260
261 while (c--) {
262 outlet_new(&x->x_obj, gensym("signal"));
263 }
264
265 x->x_bangout = outlet_new(&x->x_obj, &s_float);
266
267 return (x);
268}
269
270void sfread_tilde_setup(void)
271{
272 /* sfread */
273
274 sfread_class = class_new(gensym("sfread~"), (t_newmethod)sfread_new, 0,
275 sizeof(t_sfread), 0,A_DEFFLOAT,A_DEFFLOAT,0);
276 class_addmethod(sfread_class, nullfn, gensym("signal"), 0);
277 class_addmethod(sfread_class, (t_method) sfread_dsp, gensym("dsp"), 0);
278 class_addmethod(sfread_class, (t_method) sfread_open, gensym("open"), A_SYMBOL,A_NULL);
279 class_addmethod(sfread_class, (t_method) sfread_size, gensym("size"), 0);
280 class_addmethod(sfread_class, (t_method) sfread_offset, gensym("ft1"), A_FLOAT, A_NULL);
281 class_addmethod(sfread_class, (t_method) sfread_speed, gensym("ft2"), A_FLOAT, A_NULL);
282 class_addmethod(sfread_class, (t_method) sfread_state, gensym("state"), 0);
283 class_addfloat(sfread_class, sfread_float);
284 class_addbang(sfread_class,sfread_bang);
285 class_addmethod(sfread_class,(t_method)sfread_loop,gensym("loop"),A_FLOAT,A_NULL);
286
287}
288
289#include <unistd.h>
290#include <fcntl.h>
291#include <errno.h>
292#include <stdio.h>
293#include <string.h>
294#include <unistd.h>
295#include <sys/mman.h>
296#include <sys/stat.h>
297
298#include <m_pd.h>
299#include <m_fixed.h>
300#include "g_canvas.h"
301
302/* ------------------------ sfread~ ----------------------------- */
303
304#include "sformat.h"
305
306static t_class *sfread_class;
307
308
309typedef struct _sfread
310{
311 t_object x_obj;
312 void* x_mapaddr;
313 int x_fd;
314
315 int x_play;
316 int x_channels;
317 long long x_size;
318 int x_loop;
319 t_time x_pos;
320
321 t_sample x_skip;
322 t_sample x_speed;
323
324 t_glist * x_glist;
325 t_outlet *x_bangout;
326} t_sfread;
327
328
329void sfread_open(t_sfread *x,t_symbol *filename)
330{
331 struct stat fstate;
332 char fname[MAXPDSTRING];
333
334 if (filename == &s_) {
335 post("sfread: open without filename");
336 return;
337 }
338
339 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
340 fname, MAXPDSTRING);
341
342
343 /* close the old file */
344
345 if (x->x_mapaddr) munmap(x->x_mapaddr,x->x_size);
346 if (x->x_fd >= 0) close(x->x_fd);
347
348 if ((x->x_fd = open(fname,O_RDONLY)) < 0)
349 {
350 error("can't open %s",fname);
351 x->x_play = 0;
352 x->x_mapaddr = NULL;
353 return;
354 }
355
356 /* get the size */
357
358 fstat(x->x_fd,&fstate);
359 x->x_size = fstate.st_size;
360
361 /* map the file into memory */
362
363 if (!(x->x_mapaddr = mmap(NULL,x->x_size,PROT_READ,MAP_PRIVATE,x->x_fd,0)))
364 {
365 error("can't mmap %s",fname);
366 return;
367 }
368}
369
370#define MAX_CHANS 4
371
372static t_int *sfread_perform(t_int *w)
373{
374 t_sfread* x = (t_sfread*)(w[1]);
375 short* buf = x->x_mapaddr;
376 t_time tmp;
377 int c = x->x_channels;
378 t_time pos = x->x_pos;
379 t_sample speed = x->x_speed;
380 t_time end = itofix(x->x_size/sizeof(short)/c);
381 int i,n;
382 t_sample* out[MAX_CHANS];
383
384 for (i=0;i<c;i++)
385 out[i] = (t_sample *)(w[3+i]);
386 n = (int)(w[3+c]);
387
388 /* loop */
389
390 if (pos > end)
391 pos = end;
392
393 if (pos + n*speed >= end) { // playing forward end
394 if (!x->x_loop) {
395 x->x_play=0;
396 }
397 pos = x->x_skip;
398 }
399 tmp = n*speed;
400
401 if (pos + n*speed <= 0) { // playing backwards end
402 if (!x->x_loop) {
403 x->x_play=0;
404 }
405 pos = end;
406
407 }
408 if (x->x_play && x->x_mapaddr) {
409 t_time aoff = fixtoi(pos)*c;
410 while (n--) {
411 long frac = (long long)((1<<fix1)-1)&pos;
412
413 for (i=0;i<c;i++) {
414 t_sample bs = *(buf+aoff+i)<<(fix1-16);
415 t_sample cs = *(buf+aoff+i+1)<<(fix1-16);
416 *out[i]++ = bs + mult((cs - bs),frac);
417
418 }
419 pos += speed;
420 aoff = fixtoi(pos)*c;
421 if (aoff > end) {
422 if (x->x_loop) pos = x->x_skip;
423 else break;
424 }
425 if (aoff < x->x_skip) {
426 if (x->x_loop) pos = end;
427 else break;
428 }
429 }
430 /* Fill with zero in case of end */
431 n++;
432 while (n--)
433 for (i=0;i<c;i++)
434 *out[i]++ = 0;
435 }
436 else {
437 while (n--) {
438 for (i=0;i<c;i++)
439 *out[i]++ = 0.;
440 }
441 }
442
443 x->x_pos = pos;
444 return (w+c+4);
445}
446
447
448static void sfread_float(t_sfread *x, t_floatarg f)
449{
450 int t = f;
451 if (t && x->x_mapaddr) {
452 x->x_play=1;
453 }
454 else {
455 x->x_play=0;
456 }
457
458}
459
460static void sfread_loop(t_sfread *x, t_floatarg f)
461{
462 x->x_loop = f;
463}
464
465
466
467static void sfread_size(t_sfread* x)
468{
469 t_atom a;
470
471 SETFLOAT(&a,x->x_size*0.5/x->x_channels);
472 outlet_list(x->x_bangout, gensym("size"),1,&a);
473}
474
475static void sfread_state(t_sfread* x)
476{
477 t_atom a;
478
479 SETFLOAT(&a,x->x_play);
480 outlet_list(x->x_bangout, gensym("state"),1,&a);
481}
482
483
484
485
486static void sfread_bang(t_sfread* x)
487{
488 x->x_pos = x->x_skip;
489 sfread_float(x,1.0);
490}
491
492
493static void sfread_dsp(t_sfread *x, t_signal **sp)
494{
495/* post("sfread: dsp"); */
496 switch (x->x_channels) {
497 case 1:
498 dsp_add(sfread_perform, 4, x, sp[0]->s_vec,
499 sp[1]->s_vec, sp[0]->s_n);
500 break;
501 case 2:
502 dsp_add(sfread_perform, 5, x, sp[0]->s_vec,
503 sp[1]->s_vec,sp[2]->s_vec, sp[0]->s_n);
504 break;
505 case 4:
506 dsp_add(sfread_perform, 6, x, sp[0]->s_vec,
507 sp[1]->s_vec,sp[2]->s_vec,
508 sp[3]->s_vec,sp[4]->s_vec,
509 sp[0]->s_n);
510 break;
511 }
512}
513
514
515static void sfread_speed(t_sfread* x, t_floatarg f)
516{
517 x->x_speed = ftofix(f);
518}
519
520static void sfread_offset(t_sfread* x, t_floatarg f)
521{
522 x->x_pos = (int)f;
523}
524
525static void *sfread_new(t_floatarg chan,t_floatarg skip)
526{
527 t_sfread *x = (t_sfread *)pd_new(sfread_class);
528 t_int c = chan;
529
530 x->x_glist = (t_glist*) canvas_getcurrent();
531
532 if (c<1 || c > MAX_CHANS) c = 1;
533 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
534 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft2"));
535
536
537 x->x_fd = -1;
538 x->x_mapaddr = NULL;
539
540 x->x_size = 0;
541 x->x_loop = 0;
542 x->x_channels = c;
543 x->x_mapaddr=NULL;
544 x->x_pos = 0;
545 x->x_skip = 0;
546 x->x_speed = ftofix(1.0);
547 x->x_play = 0;
548
549 while (c--) {
550 outlet_new(&x->x_obj, gensym("signal"));
551 }
552
553 x->x_bangout = outlet_new(&x->x_obj, &s_float);
554
555 return (x);
556}
557
558void sfread_tilde_setup(void)
559{
560 /* sfread */
561
562 sfread_class = class_new(gensym("sfread~"), (t_newmethod)sfread_new, 0,
563 sizeof(t_sfread), 0,A_DEFFLOAT,A_DEFFLOAT,0);
564 class_addmethod(sfread_class, nullfn, gensym("signal"), 0);
565 class_addmethod(sfread_class, (t_method) sfread_dsp, gensym("dsp"), 0);
566 class_addmethod(sfread_class, (t_method) sfread_open, gensym("open"), A_SYMBOL,A_NULL);
567 class_addmethod(sfread_class, (t_method) sfread_size, gensym("size"), 0);
568 class_addmethod(sfread_class, (t_method) sfread_offset, gensym("ft1"), A_FLOAT, A_NULL);
569 class_addmethod(sfread_class, (t_method) sfread_speed, gensym("ft2"), A_FLOAT, A_NULL);
570 class_addmethod(sfread_class, (t_method) sfread_state, gensym("state"), 0);
571 class_addfloat(sfread_class, sfread_float);
572 class_addbang(sfread_class,sfread_bang);
573 class_addmethod(sfread_class,(t_method)sfread_loop,gensym("loop"),A_FLOAT,A_NULL);
574
575}
576
diff --git a/apps/plugins/pdbox/PDa/intern/sfwrite~.c b/apps/plugins/pdbox/PDa/intern/sfwrite~.c
new file mode 100644
index 0000000000..dd3bfc4a09
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/sfwrite~.c
@@ -0,0 +1,480 @@
1
2#include <unistd.h>
3#include <fcntl.h>
4#include <errno.h>
5#include <stdio.h>
6#include <string.h>
7#include <unistd.h>
8#include <sys/mman.h>
9#include <sys/stat.h>
10
11#include <m_pd.h>
12#include <m_fixed.h>
13#include "g_canvas.h"
14
15
16#define BLOCKTIME 10
17
18#define MAX_CHANS 4
19
20#include "sformat.h"
21
22static t_class *sfwrite_class;
23
24typedef struct _sfwrite
25{
26 t_object x_obj;
27 t_symbol* filename;
28 int x_file;
29
30 t_int rec;
31 t_int x_channels;
32 uint32 size;
33 t_glist * x_glist;
34 t_int x_blocked;
35 t_int x_blockwarn;
36} t_sfwrite;
37
38
39static void sfwrite_wave_setup(t_sfwrite* x,t_wave* w)
40{
41
42 strncpy(w->w_fileid,"RIFF",4); /* chunk id 'RIFF' */
43 w->w_chunksize = x->size + sizeof(t_wave) -8; /* chunk size */
44 strncpy(w->w_waveid,"WAVE",4); /* wave chunk id 'WAVE' */
45 strncpy(w->w_fmtid,"fmt ",4); /* format chunk id 'fmt '*/
46 w->w_fmtchunksize = 16; /* format chunk size */
47 w->w_fmttag = 1; /* format tag, 1 for PCM */
48 w->w_nchannels = x->x_channels; /* number of channels */
49 w->w_samplespersec = 44100; /* sample rate in hz */
50 w->w_navgbytespersec = 44100*x->x_channels*2; /* average bytes per second */
51 w->w_nblockalign = 4; /* number of bytes per sample */
52 w->w_nbitspersample = 16; /* number of bits in a sample */
53 strncpy(w->w_datachunkid,"data",4); /* data chunk id 'data'*/
54 w->w_datachunksize = x->size; /* length of data chunk */
55}
56
57
58
59static void sfwrite_close(t_sfwrite *x)
60{
61 if (x->x_file > 0) {
62 t_wave w;
63 sfwrite_wave_setup(x,&w);
64 lseek(x->x_file,0,SEEK_SET);
65 write(x->x_file,&w,sizeof(w));
66 close(x->x_file);
67 }
68 x->x_file = -1;
69}
70
71
72static void sfwrite_open(t_sfwrite *x,t_symbol *filename)
73{
74 char fname[MAXPDSTRING];
75
76 if (filename == &s_) {
77 post("sfwrite: open without filename");
78 return;
79 }
80
81 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
82 fname, MAXPDSTRING);
83
84 x->x_blocked = 0;
85 x->filename = filename;
86 post("sfwrite: filename = %s",x->filename->s_name);
87
88 sfwrite_close(x);
89
90 if ((x->x_file = open(fname,O_RDWR | O_CREAT,0664)) < 0)
91 {
92 error("can't create %s",fname);
93 return;
94 }
95
96 /* skip the header */
97
98 lseek(x->x_file,sizeof(t_wave),SEEK_SET);
99 x->size = 0;
100
101
102}
103
104static void sfwrite_block(t_sfwrite *x, t_floatarg f)
105{
106 x->x_blockwarn = f;
107}
108
109
110static void sfwrite_float(t_sfwrite *x, t_floatarg f)
111{
112 int t = f;
113 if (t) {
114 post("sfwrite: start", f);
115 x->rec=1;
116 }
117 else {
118 post("sfwrite: stop", f);
119 x->rec=0;
120 }
121
122}
123
124
125static short out[4*64];
126
127static t_int *sfwrite_perform(t_int *w)
128{
129 t_sfwrite* x = (t_sfwrite*)(w[1]);
130 t_sample * in[4];
131 int c = x->x_channels;
132 int i,num,n;
133 short* tout = out;
134 int ret;
135 int timebefore,timeafter;
136 double late;
137
138 for (i=0;i < c;i++) {
139 in[i] = (t_sample *)(w[2+i]);
140 }
141
142 n = num = (int)(w[2+c]);
143
144 /* loop */
145
146 if (x->rec && x->x_file) {
147
148 while (n--) {
149 for (i=0;i<c;i++) {
150 *tout++ = (*(in[i])++)>>(fix1-16);
151 }
152 }
153
154 timebefore = sys_getrealtime();
155 if ((ret =write(x->x_file,out,sizeof(short)*num*c)) < (signed int)sizeof(short)*num*c) {
156 post("sfwrite: short write %d",ret);
157
158 }
159 timeafter = sys_getrealtime();
160 late = timeafter - timebefore;
161
162#if 0
163 /* OK, we let only 10 ms block here */
164 if (late > BLOCKTIME && x->x_blockwarn) {
165 post("sfwrite blocked %f ms",late*1000);
166 x->x_blocked++;
167 if (x->x_blocked > x->x_blockwarn) {
168 x->rec = 0;
169 post("maximum blockcount %d reached, recording stopped (set blockcount with \"block <num>\"",x->x_blockwarn);
170 }
171 }
172#endif
173 x->size +=64*x->x_channels*sizeof(short) ;
174 }
175
176 return (w+3+c);
177}
178
179
180
181static void sfwrite_dsp(t_sfwrite *x, t_signal **sp)
182{
183 switch (x->x_channels) {
184 case 1:
185 dsp_add(sfwrite_perform, 3, x, sp[0]->s_vec,
186 sp[0]->s_n);
187 break;
188 case 2:
189 dsp_add(sfwrite_perform, 4, x, sp[0]->s_vec,
190 sp[1]->s_vec, sp[0]->s_n);
191 break;
192 case 4:
193 dsp_add(sfwrite_perform, 6, x, sp[0]->s_vec,
194 sp[1]->s_vec,
195 sp[2]->s_vec,
196 sp[3]->s_vec,
197 sp[0]->s_n);
198 break;
199 }
200}
201
202static void sfwrite_free(t_sfwrite* x)
203{
204 sfwrite_close(x);
205}
206
207
208static void *sfwrite_new(t_floatarg chan)
209{
210 t_sfwrite *x = (t_sfwrite *)pd_new(sfwrite_class);
211 t_int c = chan;
212
213 if (c<1 || c > MAX_CHANS) c = 1;
214
215 x->x_glist = (t_glist*) canvas_getcurrent();
216 x->x_channels = c--;
217 x->x_file=0;
218 x->rec = 0;
219 x->size = 0;
220 x->x_blocked = 0;
221 x->x_blockwarn = 10;
222 while (c--) {
223 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
224 }
225
226
227 return (x);
228}
229
230void sfwrite_tilde_setup(void)
231{
232 sfwrite_class = class_new(gensym("sfwrite~"), (t_newmethod)sfwrite_new, (t_method)sfwrite_free,
233 sizeof(t_sfwrite), 0,A_DEFFLOAT,0);
234 class_addmethod(sfwrite_class,nullfn,gensym("signal"), 0);
235 class_addmethod(sfwrite_class, (t_method) sfwrite_dsp, gensym("dsp"), 0);
236 class_addmethod(sfwrite_class, (t_method) sfwrite_open, gensym("open"), A_SYMBOL,A_NULL);
237 class_addmethod(sfwrite_class, (t_method) sfwrite_close, gensym("close"), 0);
238 class_addmethod(sfwrite_class, (t_method)sfwrite_block,gensym("block"),A_DEFFLOAT,0);
239 class_addfloat(sfwrite_class, sfwrite_float);
240}
241
242#include <unistd.h>
243#include <fcntl.h>
244#include <errno.h>
245#include <stdio.h>
246#include <string.h>
247#include <unistd.h>
248#include <sys/mman.h>
249#include <sys/stat.h>
250
251#include <m_pd.h>
252#include <m_fixed.h>
253#include "g_canvas.h"
254
255
256#define BLOCKTIME 10
257
258#define MAX_CHANS 4
259
260#include "sformat.h"
261
262static t_class *sfwrite_class;
263
264typedef struct _sfwrite
265{
266 t_object x_obj;
267 t_symbol* filename;
268 int x_file;
269
270 t_int rec;
271 t_int x_channels;
272 uint32 size;
273 t_glist * x_glist;
274 t_int x_blocked;
275 t_int x_blockwarn;
276} t_sfwrite;
277
278
279static void sfwrite_wave_setup(t_sfwrite* x,t_wave* w)
280{
281
282 strncpy(w->w_fileid,"RIFF",4); /* chunk id 'RIFF' */
283 w->w_chunksize = x->size + sizeof(t_wave) -8; /* chunk size */
284 strncpy(w->w_waveid,"WAVE",4); /* wave chunk id 'WAVE' */
285 strncpy(w->w_fmtid,"fmt ",4); /* format chunk id 'fmt '*/
286 w->w_fmtchunksize = 16; /* format chunk size */
287 w->w_fmttag = 1; /* format tag, 1 for PCM */
288 w->w_nchannels = x->x_channels; /* number of channels */
289 w->w_samplespersec = 44100; /* sample rate in hz */
290 w->w_navgbytespersec = 44100*x->x_channels*2; /* average bytes per second */
291 w->w_nblockalign = 4; /* number of bytes per sample */
292 w->w_nbitspersample = 16; /* number of bits in a sample */
293 strncpy(w->w_datachunkid,"data",4); /* data chunk id 'data'*/
294 w->w_datachunksize = x->size; /* length of data chunk */
295}
296
297
298
299static void sfwrite_close(t_sfwrite *x)
300{
301 if (x->x_file > 0) {
302 t_wave w;
303 sfwrite_wave_setup(x,&w);
304 lseek(x->x_file,0,SEEK_SET);
305 write(x->x_file,&w,sizeof(w));
306 close(x->x_file);
307 }
308 x->x_file = -1;
309}
310
311
312static void sfwrite_open(t_sfwrite *x,t_symbol *filename)
313{
314 char fname[MAXPDSTRING];
315
316 if (filename == &s_) {
317 post("sfwrite: open without filename");
318 return;
319 }
320
321 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
322 fname, MAXPDSTRING);
323
324 x->x_blocked = 0;
325 x->filename = filename;
326 post("sfwrite: filename = %s",x->filename->s_name);
327
328 sfwrite_close(x);
329
330 if ((x->x_file = open(fname,O_RDWR | O_CREAT,0664)) < 0)
331 {
332 error("can't create %s",fname);
333 return;
334 }
335
336 /* skip the header */
337
338 lseek(x->x_file,sizeof(t_wave),SEEK_SET);
339 x->size = 0;
340
341
342}
343
344static void sfwrite_block(t_sfwrite *x, t_floatarg f)
345{
346 x->x_blockwarn = f;
347}
348
349
350static void sfwrite_float(t_sfwrite *x, t_floatarg f)
351{
352 int t = f;
353 if (t) {
354 post("sfwrite: start", f);
355 x->rec=1;
356 }
357 else {
358 post("sfwrite: stop", f);
359 x->rec=0;
360 }
361
362}
363
364
365static short out[4*64];
366
367static t_int *sfwrite_perform(t_int *w)
368{
369 t_sfwrite* x = (t_sfwrite*)(w[1]);
370 t_sample * in[4];
371 int c = x->x_channels;
372 int i,num,n;
373 short* tout = out;
374 int ret;
375 int timebefore,timeafter;
376 double late;
377
378 for (i=0;i < c;i++) {
379 in[i] = (t_sample *)(w[2+i]);
380 }
381
382 n = num = (int)(w[2+c]);
383
384 /* loop */
385
386 if (x->rec && x->x_file) {
387
388 while (n--) {
389 for (i=0;i<c;i++) {
390 *tout++ = (*(in[i])++)>>(fix1-16);
391 }
392 }
393
394 timebefore = sys_getrealtime();
395 if ((ret =write(x->x_file,out,sizeof(short)*num*c)) < (signed int)sizeof(short)*num*c) {
396 post("sfwrite: short write %d",ret);
397
398 }
399 timeafter = sys_getrealtime();
400 late = timeafter - timebefore;
401
402#if 0
403 /* OK, we let only 10 ms block here */
404 if (late > BLOCKTIME && x->x_blockwarn) {
405 post("sfwrite blocked %f ms",late*1000);
406 x->x_blocked++;
407 if (x->x_blocked > x->x_blockwarn) {
408 x->rec = 0;
409 post("maximum blockcount %d reached, recording stopped (set blockcount with \"block <num>\"",x->x_blockwarn);
410 }
411 }
412#endif
413 x->size +=64*x->x_channels*sizeof(short) ;
414 }
415
416 return (w+3+c);
417}
418
419
420
421static void sfwrite_dsp(t_sfwrite *x, t_signal **sp)
422{
423 switch (x->x_channels) {
424 case 1:
425 dsp_add(sfwrite_perform, 3, x, sp[0]->s_vec,
426 sp[0]->s_n);
427 break;
428 case 2:
429 dsp_add(sfwrite_perform, 4, x, sp[0]->s_vec,
430 sp[1]->s_vec, sp[0]->s_n);
431 break;
432 case 4:
433 dsp_add(sfwrite_perform, 6, x, sp[0]->s_vec,
434 sp[1]->s_vec,
435 sp[2]->s_vec,
436 sp[3]->s_vec,
437 sp[0]->s_n);
438 break;
439 }
440}
441
442static void sfwrite_free(t_sfwrite* x)
443{
444 sfwrite_close(x);
445}
446
447
448static void *sfwrite_new(t_floatarg chan)
449{
450 t_sfwrite *x = (t_sfwrite *)pd_new(sfwrite_class);
451 t_int c = chan;
452
453 if (c<1 || c > MAX_CHANS) c = 1;
454
455 x->x_glist = (t_glist*) canvas_getcurrent();
456 x->x_channels = c--;
457 x->x_file=0;
458 x->rec = 0;
459 x->size = 0;
460 x->x_blocked = 0;
461 x->x_blockwarn = 10;
462 while (c--) {
463 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
464 }
465
466
467 return (x);
468}
469
470void sfwrite_tilde_setup(void)
471{
472 sfwrite_class = class_new(gensym("sfwrite~"), (t_newmethod)sfwrite_new, (t_method)sfwrite_free,
473 sizeof(t_sfwrite), 0,A_DEFFLOAT,0);
474 class_addmethod(sfwrite_class,nullfn,gensym("signal"), 0);
475 class_addmethod(sfwrite_class, (t_method) sfwrite_dsp, gensym("dsp"), 0);
476 class_addmethod(sfwrite_class, (t_method) sfwrite_open, gensym("open"), A_SYMBOL,A_NULL);
477 class_addmethod(sfwrite_class, (t_method) sfwrite_close, gensym("close"), 0);
478 class_addmethod(sfwrite_class, (t_method)sfwrite_block,gensym("block"),A_DEFFLOAT,0);
479 class_addfloat(sfwrite_class, sfwrite_float);
480}
diff --git a/apps/plugins/pdbox/PDa/intern/sig~.c b/apps/plugins/pdbox/PDa/intern/sig~.c
new file mode 100644
index 0000000000..70a616ce23
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/sig~.c
@@ -0,0 +1,134 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4static t_class *sig_tilde_class;
5
6typedef struct _sig
7{
8 t_object x_obj;
9 t_sample x_f;
10} t_sig;
11
12static t_int *sig_tilde_perform(t_int *w)
13{
14 t_sample f = *(t_sample *)(w[1]);
15 t_sample *out = (t_sample *)(w[2]);
16 int n = (int)(w[3]);
17 while (n--)
18 *out++ = f;
19 return (w+4);
20}
21
22static t_int *sig_tilde_perf8(t_int *w)
23{
24 t_sample f = *(t_sample *)(w[1]);
25 t_sample *out = (t_sample *)(w[2]);
26 int n = (int)(w[3]);
27
28 for (; n; n -= 8, out += 8)
29 {
30 out[0] = f;
31 out[1] = f;
32 out[2] = f;
33 out[3] = f;
34 out[4] = f;
35 out[5] = f;
36 out[6] = f;
37 out[7] = f;
38 }
39 return (w+4);
40}
41
42
43static void sig_tilde_float(t_sig *x, t_float f)
44{
45 x->x_f = ftofix(f);
46}
47
48static void sig_tilde_dsp(t_sig *x, t_signal **sp)
49{
50 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
51}
52
53static void *sig_tilde_new(t_floatarg f)
54{
55 t_sig *x = (t_sig *)pd_new(sig_tilde_class);
56 x->x_f = ftofix(f);
57 outlet_new(&x->x_obj, gensym("signal"));
58 return (x);
59}
60
61void sig_tilde_setup(void)
62{
63 sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
64 sizeof(t_sig), 0, A_DEFFLOAT, 0);
65 class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
66 class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
67}
68#include <m_pd.h>
69#include <m_fixed.h>
70
71static t_class *sig_tilde_class;
72
73typedef struct _sig
74{
75 t_object x_obj;
76 t_sample x_f;
77} t_sig;
78
79static t_int *sig_tilde_perform(t_int *w)
80{
81 t_sample f = *(t_sample *)(w[1]);
82 t_sample *out = (t_sample *)(w[2]);
83 int n = (int)(w[3]);
84 while (n--)
85 *out++ = f;
86 return (w+4);
87}
88
89static t_int *sig_tilde_perf8(t_int *w)
90{
91 t_sample f = *(t_sample *)(w[1]);
92 t_sample *out = (t_sample *)(w[2]);
93 int n = (int)(w[3]);
94
95 for (; n; n -= 8, out += 8)
96 {
97 out[0] = f;
98 out[1] = f;
99 out[2] = f;
100 out[3] = f;
101 out[4] = f;
102 out[5] = f;
103 out[6] = f;
104 out[7] = f;
105 }
106 return (w+4);
107}
108
109
110static void sig_tilde_float(t_sig *x, t_float f)
111{
112 x->x_f = ftofix(f);
113}
114
115static void sig_tilde_dsp(t_sig *x, t_signal **sp)
116{
117 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
118}
119
120static void *sig_tilde_new(t_floatarg f)
121{
122 t_sig *x = (t_sig *)pd_new(sig_tilde_class);
123 x->x_f = ftofix(f);
124 outlet_new(&x->x_obj, gensym("signal"));
125 return (x);
126}
127
128void sig_tilde_setup(void)
129{
130 sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
131 sizeof(t_sig), 0, A_DEFFLOAT, 0);
132 class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
133 class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
134}
diff --git a/apps/plugins/pdbox/PDa/intern/snapshot~.c b/apps/plugins/pdbox/PDa/intern/snapshot~.c
new file mode 100644
index 0000000000..f63aeb76cd
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/snapshot~.c
@@ -0,0 +1,114 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4
5static t_class *snapshot_tilde_class;
6
7typedef struct _snapshot
8{
9 t_object x_obj;
10 t_sample x_value;
11 float x_f;
12} t_snapshot;
13
14static void *snapshot_tilde_new(void)
15{
16 t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
17 x->x_value = 0;
18 outlet_new(&x->x_obj, &s_float);
19 x->x_f = 0;
20 return (x);
21}
22
23static t_int *snapshot_tilde_perform(t_int *w)
24{
25 t_sample *in = (t_sample *)(w[1]);
26 t_sample *out = (t_sample *)(w[2]);
27 *out = *in;
28 return (w+3);
29}
30
31static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
32{
33 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
34 &x->x_value);
35}
36
37static void snapshot_tilde_bang(t_snapshot *x)
38{
39 outlet_float(x->x_obj.ob_outlet, fixtof(x->x_value));
40}
41
42static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
43{
44 x->x_value = ftofix(f);
45}
46
47void snapshot_tilde_setup(void)
48{
49 snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
50 sizeof(t_snapshot), 0, 0);
51 CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
52 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
53 gensym("dsp"), 0);
54 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
55 gensym("set"), A_DEFFLOAT, 0);
56 class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
57}
58#include <m_pd.h>
59#include <m_fixed.h>
60
61
62static t_class *snapshot_tilde_class;
63
64typedef struct _snapshot
65{
66 t_object x_obj;
67 t_sample x_value;
68 float x_f;
69} t_snapshot;
70
71static void *snapshot_tilde_new(void)
72{
73 t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
74 x->x_value = 0;
75 outlet_new(&x->x_obj, &s_float);
76 x->x_f = 0;
77 return (x);
78}
79
80static t_int *snapshot_tilde_perform(t_int *w)
81{
82 t_sample *in = (t_sample *)(w[1]);
83 t_sample *out = (t_sample *)(w[2]);
84 *out = *in;
85 return (w+3);
86}
87
88static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
89{
90 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
91 &x->x_value);
92}
93
94static void snapshot_tilde_bang(t_snapshot *x)
95{
96 outlet_float(x->x_obj.ob_outlet, fixtof(x->x_value));
97}
98
99static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
100{
101 x->x_value = ftofix(f);
102}
103
104void snapshot_tilde_setup(void)
105{
106 snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
107 sizeof(t_snapshot), 0, 0);
108 CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
109 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
110 gensym("dsp"), 0);
111 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
112 gensym("set"), A_DEFFLOAT, 0);
113 class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
114}
diff --git a/apps/plugins/pdbox/PDa/intern/sqrt~.c b/apps/plugins/pdbox/PDa/intern/sqrt~.c
new file mode 100644
index 0000000000..5e4b649f8e
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/sqrt~.c
@@ -0,0 +1,154 @@
1#define DUMTAB1SIZE 256
2#define DUMTAB2SIZE 1024
3
4#include<m_pd.h>
5#include<m_fixed.h>
6
7/* sigsqrt - square root good to 8 mantissa bits */
8
9static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
10
11static void init_rsqrt(void)
12{
13 int i;
14 for (i = 0; i < DUMTAB1SIZE; i++)
15 {
16 float f;
17 long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
18 *(long *)(&f) = l;
19 rsqrt_exptab[i] = 1./sqrt(f);
20 }
21 for (i = 0; i < DUMTAB2SIZE; i++)
22 {
23 float f = 1 + (1./DUMTAB2SIZE) * i;
24 rsqrt_mantissatab[i] = 1./sqrt(f);
25 }
26}
27
28typedef struct sigsqrt
29{
30 t_object x_obj;
31 float x_f;
32} t_sigsqrt;
33
34static t_class *sigsqrt_class;
35
36static void *sigsqrt_new(void)
37{
38 t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
39 outlet_new(&x->x_obj, gensym("signal"));
40 x->x_f = 0;
41 return (x);
42}
43
44t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */
45{
46 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
47 t_int n = *(t_int *)(w+3);
48 while (n--)
49 {
50 float f = *in;
51 long l = *(long *)(in++);
52 if (f < 0) *out++ = 0;
53 else
54 {
55 float g = rsqrt_exptab[(l >> 23) & 0xff] *
56 rsqrt_mantissatab[(l >> 13) & 0x3ff];
57 *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
58 }
59 }
60 return (w + 4);
61}
62
63static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp)
64{
65 dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
66}
67
68void sqrt_tilde_setup(void)
69{
70 init_rsqrt();
71 sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0,
72 sizeof(t_sigsqrt), 0, 0);
73 class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */
74 CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f);
75 class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, gensym("dsp"), 0);
76}
77
78#define DUMTAB1SIZE 256
79#define DUMTAB2SIZE 1024
80
81#include<m_pd.h>
82#include<m_fixed.h>
83
84/* sigsqrt - square root good to 8 mantissa bits */
85
86static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
87
88static void init_rsqrt(void)
89{
90 int i;
91 for (i = 0; i < DUMTAB1SIZE; i++)
92 {
93 float f;
94 long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
95 *(long *)(&f) = l;
96 rsqrt_exptab[i] = 1./sqrt(f);
97 }
98 for (i = 0; i < DUMTAB2SIZE; i++)
99 {
100 float f = 1 + (1./DUMTAB2SIZE) * i;
101 rsqrt_mantissatab[i] = 1./sqrt(f);
102 }
103}
104
105typedef struct sigsqrt
106{
107 t_object x_obj;
108 float x_f;
109} t_sigsqrt;
110
111static t_class *sigsqrt_class;
112
113static void *sigsqrt_new(void)
114{
115 t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
116 outlet_new(&x->x_obj, gensym("signal"));
117 x->x_f = 0;
118 return (x);
119}
120
121t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */
122{
123 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
124 t_int n = *(t_int *)(w+3);
125 while (n--)
126 {
127 float f = *in;
128 long l = *(long *)(in++);
129 if (f < 0) *out++ = 0;
130 else
131 {
132 float g = rsqrt_exptab[(l >> 23) & 0xff] *
133 rsqrt_mantissatab[(l >> 13) & 0x3ff];
134 *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
135 }
136 }
137 return (w + 4);
138}
139
140static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp)
141{
142 dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
143}
144
145void sqrt_tilde_setup(void)
146{
147 init_rsqrt();
148 sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0,
149 sizeof(t_sigsqrt), 0, 0);
150 class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */
151 CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f);
152 class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, gensym("dsp"), 0);
153}
154
diff --git a/apps/plugins/pdbox/PDa/intern/tabosc4~.c b/apps/plugins/pdbox/PDa/intern/tabosc4~.c
new file mode 100644
index 0000000000..ec8ed84f31
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabosc4~.c
@@ -0,0 +1,264 @@
1
2#include <m_pd.h>
3#include <m_fixed.h>
4
5static t_class *tabosc4_tilde_class;
6
7typedef struct _tabosc4_tilde
8{
9 t_object x_obj;
10 int x_fnpoints;
11 int x_lognpoints;
12 t_sample *x_vec;
13 t_symbol *x_arrayname;
14 t_sample x_f;
15 unsigned int x_phase;
16 t_sample x_conv;
17} t_tabosc4_tilde;
18
19static void *tabosc4_tilde_new(t_symbol *s)
20{
21 t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
22 x->x_arrayname = s;
23 x->x_vec = 0;
24 x->x_fnpoints = 512;
25 outlet_new(&x->x_obj, gensym("signal"));
26 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
27 x->x_f = 0;
28 post("new done");
29 return (x);
30}
31
32static t_int *tabosc4_tilde_perform(t_int *w)
33{
34 t_tabosc4_tilde *x = (t_tabosc4_tilde *)(w[1]);
35 t_sample *in = (t_sample *)(w[2]);
36 t_sample *out = (t_sample *)(w[3]);
37 int n = (int)(w[4]);
38 t_sample *tab = x->x_vec;
39 unsigned int phase = x->x_phase;
40 int conv = x->x_conv;
41 int off;
42 int frac;
43 int logp = x->x_lognpoints;
44
45 if (!tab) goto zero;
46
47 while (n--) {
48 t_sample f2;
49 phase+= mult(conv ,(*in++));
50 phase &= (itofix(1) -1);
51 off = fixtoi((long long)phase<<logp);
52
53#ifdef NO_INTERPOLATION
54 *out = *(tab+off);
55#else
56 frac = phase & ((1<<logp)-1);
57 frac <<= (fix1-logp);
58
59 f2 = (off == x->x_fnpoints) ?
60 mult(*(tab),frac) :
61 mult(*(tab + off + 1),frac);
62
63 *out = mult(*(tab + off),(itofix(1) - frac)) + f2;
64#endif
65 out++;
66 }
67 x->x_phase = phase;
68
69 return (w+5);
70
71zero:
72 while (n--) *out++ = 0;
73
74 return (w+5);
75}
76
77void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s)
78{
79 t_garray *a;
80 int npoints, pointsinarray;
81 x->x_arrayname = s;
82
83 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
84 {
85 if (*s->s_name)
86 pd_error(x, "tabosc4~: %s: no such array", x->x_arrayname->s_name);
87 x->x_vec = 0;
88 }
89 else if (!garray_getfloatarray(a, &pointsinarray, &x->x_vec))
90 {
91 pd_error(x, "%s: bad template for tabosc4~", x->x_arrayname->s_name);
92 x->x_vec = 0;
93 }
94 else
95 {
96 int i;
97 x->x_fnpoints = pointsinarray;
98 x->x_lognpoints = ilog2(pointsinarray);
99 post("tabosc~: using %d (log %d) points of array",x->x_fnpoints,x->x_lognpoints);
100
101 garray_usedindsp(a);
102 }
103}
104
105static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f)
106{
107 x->x_phase = f;
108}
109
110static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp)
111{
112 x->x_conv = ftofix(1000.)/sp[0]->s_sr;
113 x->x_conv = mult(x->x_conv + 500,ftofix(0.001));
114
115 tabosc4_tilde_set(x, x->x_arrayname);
116 dsp_add(tabosc4_tilde_perform, 4, x,
117 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
118}
119
120void tabosc4_tilde_setup(void)
121{
122 tabosc4_tilde_class = class_new(gensym("tabosc4~"),
123 (t_newmethod)tabosc4_tilde_new, 0,
124 sizeof(t_tabosc4_tilde), 0, A_DEFSYM, 0);
125 CLASS_MAINSIGNALIN(tabosc4_tilde_class, t_tabosc4_tilde, x_f);
126 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_dsp,
127 gensym("dsp"), 0);
128 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_set,
129 gensym("set"), A_SYMBOL, 0);
130 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_ft1,
131 gensym("ft1"), A_FLOAT, 0);
132}
133
134#include <m_pd.h>
135#include <m_fixed.h>
136
137static t_class *tabosc4_tilde_class;
138
139typedef struct _tabosc4_tilde
140{
141 t_object x_obj;
142 int x_fnpoints;
143 int x_lognpoints;
144 t_sample *x_vec;
145 t_symbol *x_arrayname;
146 t_sample x_f;
147 unsigned int x_phase;
148 t_sample x_conv;
149} t_tabosc4_tilde;
150
151static void *tabosc4_tilde_new(t_symbol *s)
152{
153 t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
154 x->x_arrayname = s;
155 x->x_vec = 0;
156 x->x_fnpoints = 512;
157 outlet_new(&x->x_obj, gensym("signal"));
158 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
159 x->x_f = 0;
160 post("new done");
161 return (x);
162}
163
164static t_int *tabosc4_tilde_perform(t_int *w)
165{
166 t_tabosc4_tilde *x = (t_tabosc4_tilde *)(w[1]);
167 t_sample *in = (t_sample *)(w[2]);
168 t_sample *out = (t_sample *)(w[3]);
169 int n = (int)(w[4]);
170 t_sample *tab = x->x_vec;
171 unsigned int phase = x->x_phase;
172 int conv = x->x_conv;
173 int off;
174 int frac;
175 int logp = x->x_lognpoints;
176
177 if (!tab) goto zero;
178
179 while (n--) {
180 t_sample f2;
181 phase+= mult(conv ,(*in++));
182 phase &= (itofix(1) -1);
183 off = fixtoi((long long)phase<<logp);
184
185#ifdef NO_INTERPOLATION
186 *out = *(tab+off);
187#else
188 frac = phase & ((1<<logp)-1);
189 frac <<= (fix1-logp);
190
191 f2 = (off == x->x_fnpoints) ?
192 mult(*(tab),frac) :
193 mult(*(tab + off + 1),frac);
194
195 *out = mult(*(tab + off),(itofix(1) - frac)) + f2;
196#endif
197 out++;
198 }
199 x->x_phase = phase;
200
201 return (w+5);
202
203zero:
204 while (n--) *out++ = 0;
205
206 return (w+5);
207}
208
209void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s)
210{
211 t_garray *a;
212 int npoints, pointsinarray;
213 x->x_arrayname = s;
214
215 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
216 {
217 if (*s->s_name)
218 pd_error(x, "tabosc4~: %s: no such array", x->x_arrayname->s_name);
219 x->x_vec = 0;
220 }
221 else if (!garray_getfloatarray(a, &pointsinarray, &x->x_vec))
222 {
223 pd_error(x, "%s: bad template for tabosc4~", x->x_arrayname->s_name);
224 x->x_vec = 0;
225 }
226 else
227 {
228 int i;
229 x->x_fnpoints = pointsinarray;
230 x->x_lognpoints = ilog2(pointsinarray);
231 post("tabosc~: using %d (log %d) points of array",x->x_fnpoints,x->x_lognpoints);
232
233 garray_usedindsp(a);
234 }
235}
236
237static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f)
238{
239 x->x_phase = f;
240}
241
242static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp)
243{
244 x->x_conv = ftofix(1000.)/sp[0]->s_sr;
245 x->x_conv = mult(x->x_conv + 500,ftofix(0.001));
246
247 tabosc4_tilde_set(x, x->x_arrayname);
248 dsp_add(tabosc4_tilde_perform, 4, x,
249 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
250}
251
252void tabosc4_tilde_setup(void)
253{
254 tabosc4_tilde_class = class_new(gensym("tabosc4~"),
255 (t_newmethod)tabosc4_tilde_new, 0,
256 sizeof(t_tabosc4_tilde), 0, A_DEFSYM, 0);
257 CLASS_MAINSIGNALIN(tabosc4_tilde_class, t_tabosc4_tilde, x_f);
258 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_dsp,
259 gensym("dsp"), 0);
260 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_set,
261 gensym("set"), A_SYMBOL, 0);
262 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_ft1,
263 gensym("ft1"), A_FLOAT, 0);
264}
diff --git a/apps/plugins/pdbox/PDa/intern/tabplay~.c b/apps/plugins/pdbox/PDa/intern/tabplay~.c
new file mode 100644
index 0000000000..c0032a1e12
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabplay~.c
@@ -0,0 +1,264 @@
1
2#define FIXEDPOINT
3#include <m_pd.h>
4#include <m_fixed.h>
5
6static t_class *tabplay_tilde_class;
7
8typedef struct _tabplay_tilde
9{
10 t_object x_obj;
11 t_outlet *x_bangout;
12 int x_phase;
13 int x_nsampsintab;
14 int x_limit;
15 t_sample *x_vec;
16 t_symbol *x_arrayname;
17 t_clock *x_clock;
18} t_tabplay_tilde;
19
20static void tabplay_tilde_tick(t_tabplay_tilde *x);
21
22static void *tabplay_tilde_new(t_symbol *s)
23{
24 t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
25 x->x_clock = clock_new(x, (t_method)tabplay_tilde_tick);
26 x->x_phase = 0x7fffffff;
27 x->x_limit = 0;
28 x->x_arrayname = s;
29 outlet_new(&x->x_obj, &s_signal);
30 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
31 return (x);
32}
33
34static t_int *tabplay_tilde_perform(t_int *w)
35{
36 t_tabplay_tilde *x = (t_tabplay_tilde *)(w[1]);
37 t_sample *out = (t_sample *)(w[2]), *fp;
38 int n = (int)(w[3]), phase = x->x_phase,
39 endphase = (x->x_nsampsintab < x->x_limit ?
40 x->x_nsampsintab : x->x_limit), nxfer, n3;
41 if (!x->x_vec || phase >= endphase)
42 goto zero;
43
44 nxfer = endphase - phase;
45 fp = x->x_vec + phase;
46 if (nxfer > n)
47 nxfer = n;
48 n3 = n - nxfer;
49 phase += nxfer;
50 while (nxfer--)
51 *out++ = *fp++;
52 if (phase >= endphase)
53 {
54 clock_delay(x->x_clock, 0);
55 x->x_phase = 0x7fffffff;
56 while (n3--)
57 *out++ = 0;
58 }
59 else x->x_phase = phase;
60
61 return (w+4);
62zero:
63 while (n--) *out++ = 0;
64 return (w+4);
65}
66
67void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s)
68{
69 t_garray *a;
70
71 x->x_arrayname = s;
72 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
73 {
74 if (*s->s_name) pd_error(x, "tabplay~: %s: no such array",
75 x->x_arrayname->s_name);
76 x->x_vec = 0;
77 }
78 else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
79 {
80 error("%s: bad template for tabplay~", x->x_arrayname->s_name);
81 x->x_vec = 0;
82 }
83 else garray_usedindsp(a);
84}
85
86static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp)
87{
88 tabplay_tilde_set(x, x->x_arrayname);
89 dsp_add(tabplay_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
90}
91
92static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s,
93 int argc, t_atom *argv)
94{
95 long start = atom_getfloatarg(0, argc, argv);
96 long length = atom_getfloatarg(1, argc, argv);
97 if (start < 0) start = 0;
98 if (length <= 0)
99 x->x_limit = 0x7fffffff;
100 else
101 x->x_limit = start + length;
102 x->x_phase = start;
103}
104
105static void tabplay_tilde_stop(t_tabplay_tilde *x)
106{
107 x->x_phase = 0x7fffffff;
108}
109
110static void tabplay_tilde_tick(t_tabplay_tilde *x)
111{
112 outlet_bang(x->x_bangout);
113}
114
115static void tabplay_tilde_free(t_tabplay_tilde *x)
116{
117 clock_free(x->x_clock);
118}
119
120void tabplay_tilde_setup(void)
121{
122 tabplay_tilde_class = class_new(gensym("tabplay~"),
123 (t_newmethod)tabplay_tilde_new, (t_method)tabplay_tilde_free,
124 sizeof(t_tabplay_tilde), 0, A_DEFSYM, 0);
125 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_dsp,
126 gensym("dsp"), 0);
127 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_stop,
128 gensym("stop"), 0);
129 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_set,
130 gensym("set"), A_DEFSYM, 0);
131 class_addlist(tabplay_tilde_class, tabplay_tilde_list);
132}
133
134#define FIXEDPOINT
135#include <m_pd.h>
136#include <m_fixed.h>
137
138static t_class *tabplay_tilde_class;
139
140typedef struct _tabplay_tilde
141{
142 t_object x_obj;
143 t_outlet *x_bangout;
144 int x_phase;
145 int x_nsampsintab;
146 int x_limit;
147 t_sample *x_vec;
148 t_symbol *x_arrayname;
149 t_clock *x_clock;
150} t_tabplay_tilde;
151
152static void tabplay_tilde_tick(t_tabplay_tilde *x);
153
154static void *tabplay_tilde_new(t_symbol *s)
155{
156 t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
157 x->x_clock = clock_new(x, (t_method)tabplay_tilde_tick);
158 x->x_phase = 0x7fffffff;
159 x->x_limit = 0;
160 x->x_arrayname = s;
161 outlet_new(&x->x_obj, &s_signal);
162 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
163 return (x);
164}
165
166static t_int *tabplay_tilde_perform(t_int *w)
167{
168 t_tabplay_tilde *x = (t_tabplay_tilde *)(w[1]);
169 t_sample *out = (t_sample *)(w[2]), *fp;
170 int n = (int)(w[3]), phase = x->x_phase,
171 endphase = (x->x_nsampsintab < x->x_limit ?
172 x->x_nsampsintab : x->x_limit), nxfer, n3;
173 if (!x->x_vec || phase >= endphase)
174 goto zero;
175
176 nxfer = endphase - phase;
177 fp = x->x_vec + phase;
178 if (nxfer > n)
179 nxfer = n;
180 n3 = n - nxfer;
181 phase += nxfer;
182 while (nxfer--)
183 *out++ = *fp++;
184 if (phase >= endphase)
185 {
186 clock_delay(x->x_clock, 0);
187 x->x_phase = 0x7fffffff;
188 while (n3--)
189 *out++ = 0;
190 }
191 else x->x_phase = phase;
192
193 return (w+4);
194zero:
195 while (n--) *out++ = 0;
196 return (w+4);
197}
198
199void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s)
200{
201 t_garray *a;
202
203 x->x_arrayname = s;
204 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
205 {
206 if (*s->s_name) pd_error(x, "tabplay~: %s: no such array",
207 x->x_arrayname->s_name);
208 x->x_vec = 0;
209 }
210 else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
211 {
212 error("%s: bad template for tabplay~", x->x_arrayname->s_name);
213 x->x_vec = 0;
214 }
215 else garray_usedindsp(a);
216}
217
218static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp)
219{
220 tabplay_tilde_set(x, x->x_arrayname);
221 dsp_add(tabplay_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
222}
223
224static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s,
225 int argc, t_atom *argv)
226{
227 long start = atom_getfloatarg(0, argc, argv);
228 long length = atom_getfloatarg(1, argc, argv);
229 if (start < 0) start = 0;
230 if (length <= 0)
231 x->x_limit = 0x7fffffff;
232 else
233 x->x_limit = start + length;
234 x->x_phase = start;
235}
236
237static void tabplay_tilde_stop(t_tabplay_tilde *x)
238{
239 x->x_phase = 0x7fffffff;
240}
241
242static void tabplay_tilde_tick(t_tabplay_tilde *x)
243{
244 outlet_bang(x->x_bangout);
245}
246
247static void tabplay_tilde_free(t_tabplay_tilde *x)
248{
249 clock_free(x->x_clock);
250}
251
252void tabplay_tilde_setup(void)
253{
254 tabplay_tilde_class = class_new(gensym("tabplay~"),
255 (t_newmethod)tabplay_tilde_new, (t_method)tabplay_tilde_free,
256 sizeof(t_tabplay_tilde), 0, A_DEFSYM, 0);
257 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_dsp,
258 gensym("dsp"), 0);
259 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_stop,
260 gensym("stop"), 0);
261 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_set,
262 gensym("set"), A_DEFSYM, 0);
263 class_addlist(tabplay_tilde_class, tabplay_tilde_list);
264}
diff --git a/apps/plugins/pdbox/PDa/intern/tabread.c b/apps/plugins/pdbox/PDa/intern/tabread.c
new file mode 100644
index 0000000000..5cd51b3036
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabread.c
@@ -0,0 +1,104 @@
1#include <m_pd.h>
2
3/* ---------- tabread: control, non-interpolating ------------------------ */
4
5static t_class *tabread_class;
6
7typedef struct _tabread
8{
9 t_object x_obj;
10 t_symbol *x_arrayname;
11} t_tabread;
12
13static void tabread_float(t_tabread *x, t_float f)
14{
15 t_garray *a;
16 int npoints;
17 t_sample *vec;
18
19 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
20 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
21 else if (!garray_getfloatarray(a, &npoints, &vec))
22 pd_error(x, "%s: bad template for tabread", x->x_arrayname->s_name);
23 else
24 {
25 int n = f;
26 if (n < 0) n = 0;
27 else if (n >= npoints) n = npoints - 1;
28 outlet_float(x->x_obj.ob_outlet, (npoints ? fixtof(vec[n]) : 0));
29 }
30}
31
32static void tabread_set(t_tabread *x, t_symbol *s)
33{
34 x->x_arrayname = s;
35}
36
37static void *tabread_new(t_symbol *s)
38{
39 t_tabread *x = (t_tabread *)pd_new(tabread_class);
40 x->x_arrayname = s;
41 outlet_new(&x->x_obj, &s_float);
42 return (x);
43}
44
45void tabread_setup(void)
46{
47 tabread_class = class_new(gensym("tabread"), (t_newmethod)tabread_new,
48 0, sizeof(t_tabread), 0, A_DEFSYM, 0);
49 class_addfloat(tabread_class, (t_method)tabread_float);
50 class_addmethod(tabread_class, (t_method)tabread_set, gensym("set"),
51 A_SYMBOL, 0);
52}
53#include <m_pd.h>
54
55/* ---------- tabread: control, non-interpolating ------------------------ */
56
57static t_class *tabread_class;
58
59typedef struct _tabread
60{
61 t_object x_obj;
62 t_symbol *x_arrayname;
63} t_tabread;
64
65static void tabread_float(t_tabread *x, t_float f)
66{
67 t_garray *a;
68 int npoints;
69 t_sample *vec;
70
71 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
72 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
73 else if (!garray_getfloatarray(a, &npoints, &vec))
74 pd_error(x, "%s: bad template for tabread", x->x_arrayname->s_name);
75 else
76 {
77 int n = f;
78 if (n < 0) n = 0;
79 else if (n >= npoints) n = npoints - 1;
80 outlet_float(x->x_obj.ob_outlet, (npoints ? fixtof(vec[n]) : 0));
81 }
82}
83
84static void tabread_set(t_tabread *x, t_symbol *s)
85{
86 x->x_arrayname = s;
87}
88
89static void *tabread_new(t_symbol *s)
90{
91 t_tabread *x = (t_tabread *)pd_new(tabread_class);
92 x->x_arrayname = s;
93 outlet_new(&x->x_obj, &s_float);
94 return (x);
95}
96
97void tabread_setup(void)
98{
99 tabread_class = class_new(gensym("tabread"), (t_newmethod)tabread_new,
100 0, sizeof(t_tabread), 0, A_DEFSYM, 0);
101 class_addfloat(tabread_class, (t_method)tabread_float);
102 class_addmethod(tabread_class, (t_method)tabread_set, gensym("set"),
103 A_SYMBOL, 0);
104}
diff --git a/apps/plugins/pdbox/PDa/intern/tabread4~.c b/apps/plugins/pdbox/PDa/intern/tabread4~.c
new file mode 100644
index 0000000000..e530a9fce8
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabread4~.c
@@ -0,0 +1,210 @@
1
2#include <m_pd.h>
3#include <m_fixed.h>
4
5
6static t_class *tabread4_tilde_class;
7
8typedef struct _tabread4_tilde
9{
10 t_object x_obj;
11 int x_npoints;
12 t_sample *x_vec;
13 t_symbol *x_arrayname;
14 float x_f;
15} t_tabread4_tilde;
16
17static void *tabread4_tilde_new(t_symbol *s)
18{
19 t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
20 x->x_arrayname = s;
21 x->x_vec = 0;
22 outlet_new(&x->x_obj, gensym("signal"));
23 x->x_f = 0;
24 return (x);
25}
26
27static t_int *tabread4_tilde_perform(t_int *w)
28{
29 t_tabread4_tilde *x = (t_tabread4_tilde *)(w[1]);
30 t_sample *in = (t_sample *)(w[2]);
31 t_sample *out = (t_sample *)(w[3]);
32 int n = (int)(w[4]);
33 int maxindex;
34 t_sample *buf = x->x_vec, *fp;
35 int i;
36
37 maxindex = x->x_npoints - 3;
38
39 if (!buf) goto zero;
40
41 for (i = 0; i < n; i++)
42 {
43 t_time findex = ((long long) mult((*in++),ftofix(44.1)));
44 int index = fixtoi(findex);
45 t_sample frac;
46 // post("%d: index %d f %lld",index,findex,*in);
47
48 if (index < 1)
49 index = 1, frac = 0;
50 else if (index > maxindex)
51 index = maxindex, frac = 1;
52 else frac = findex - itofix(index);
53 fp = buf + index;
54 *out++ = fp[0] + mult(frac,fp[1]-fp[0]);
55 }
56 return (w+5);
57 zero:
58 while (n--) *out++ = 0;
59
60 return (w+5);
61}
62
63void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s)
64{
65 t_garray *a;
66
67 x->x_arrayname = s;
68 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
69 {
70 if (*s->s_name)
71 error("tabread4~: %s: no such array", x->x_arrayname->s_name);
72 x->x_vec = 0;
73 }
74 else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
75 {
76 error("%s: bad template for tabread4~", x->x_arrayname->s_name);
77 x->x_vec = 0;
78 }
79 else garray_usedindsp(a);
80}
81
82static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp)
83{
84 tabread4_tilde_set(x, x->x_arrayname);
85
86 dsp_add(tabread4_tilde_perform, 4, x,
87 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
88
89}
90
91static void tabread4_tilde_free(t_tabread4_tilde *x)
92{
93}
94
95void tabread4_tilde_setup(void)
96{
97 tabread4_tilde_class = class_new(gensym("tabread4~"),
98 (t_newmethod)tabread4_tilde_new, (t_method)tabread4_tilde_free,
99 sizeof(t_tabread4_tilde), 0, A_DEFSYM, 0);
100 CLASS_MAINSIGNALIN(tabread4_tilde_class, t_tabread4_tilde, x_f);
101 class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_dsp,
102 gensym("dsp"), 0);
103 class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_set,
104 gensym("set"), A_SYMBOL, 0);
105}
106
107#include <m_pd.h>
108#include <m_fixed.h>
109
110
111static t_class *tabread4_tilde_class;
112
113typedef struct _tabread4_tilde
114{
115 t_object x_obj;
116 int x_npoints;
117 t_sample *x_vec;
118 t_symbol *x_arrayname;
119 float x_f;
120} t_tabread4_tilde;
121
122static void *tabread4_tilde_new(t_symbol *s)
123{
124 t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
125 x->x_arrayname = s;
126 x->x_vec = 0;
127 outlet_new(&x->x_obj, gensym("signal"));
128 x->x_f = 0;
129 return (x);
130}
131
132static t_int *tabread4_tilde_perform(t_int *w)
133{
134 t_tabread4_tilde *x = (t_tabread4_tilde *)(w[1]);
135 t_sample *in = (t_sample *)(w[2]);
136 t_sample *out = (t_sample *)(w[3]);
137 int n = (int)(w[4]);
138 int maxindex;
139 t_sample *buf = x->x_vec, *fp;
140 int i;
141
142 maxindex = x->x_npoints - 3;
143
144 if (!buf) goto zero;
145
146 for (i = 0; i < n; i++)
147 {
148 t_time findex = ((long long) mult((*in++),ftofix(44.1)));
149 int index = fixtoi(findex);
150 t_sample frac;
151 // post("%d: index %d f %lld",index,findex,*in);
152
153 if (index < 1)
154 index = 1, frac = 0;
155 else if (index > maxindex)
156 index = maxindex, frac = 1;
157 else frac = findex - itofix(index);
158 fp = buf + index;
159 *out++ = fp[0] + mult(frac,fp[1]-fp[0]);
160 }
161 return (w+5);
162 zero:
163 while (n--) *out++ = 0;
164
165 return (w+5);
166}
167
168void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s)
169{
170 t_garray *a;
171
172 x->x_arrayname = s;
173 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
174 {
175 if (*s->s_name)
176 error("tabread4~: %s: no such array", x->x_arrayname->s_name);
177 x->x_vec = 0;
178 }
179 else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
180 {
181 error("%s: bad template for tabread4~", x->x_arrayname->s_name);
182 x->x_vec = 0;
183 }
184 else garray_usedindsp(a);
185}
186
187static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp)
188{
189 tabread4_tilde_set(x, x->x_arrayname);
190
191 dsp_add(tabread4_tilde_perform, 4, x,
192 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
193
194}
195
196static void tabread4_tilde_free(t_tabread4_tilde *x)
197{
198}
199
200void tabread4_tilde_setup(void)
201{
202 tabread4_tilde_class = class_new(gensym("tabread4~"),
203 (t_newmethod)tabread4_tilde_new, (t_method)tabread4_tilde_free,
204 sizeof(t_tabread4_tilde), 0, A_DEFSYM, 0);
205 CLASS_MAINSIGNALIN(tabread4_tilde_class, t_tabread4_tilde, x_f);
206 class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_dsp,
207 gensym("dsp"), 0);
208 class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_set,
209 gensym("set"), A_SYMBOL, 0);
210}
diff --git a/apps/plugins/pdbox/PDa/intern/tabread~.c b/apps/plugins/pdbox/PDa/intern/tabread~.c
new file mode 100644
index 0000000000..f1f4fd4729
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabread~.c
@@ -0,0 +1,194 @@
1#define FIXEDPOINT
2#include <m_pd.h>
3#include <m_fixed.h>
4
5static t_class *tabread_tilde_class;
6
7typedef struct _tabread_tilde
8{
9 t_object x_obj;
10 int x_npoints;
11 t_sample *x_vec;
12 t_symbol *x_arrayname;
13 float x_f;
14} t_tabread_tilde;
15
16static void *tabread_tilde_new(t_symbol *s)
17{
18 t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
19 x->x_arrayname = s;
20 x->x_vec = 0;
21 outlet_new(&x->x_obj, gensym("signal"));
22 x->x_f = 0;
23 return (x);
24}
25
26static t_int *tabread_tilde_perform(t_int *w)
27{
28 t_tabread_tilde *x = (t_tabread_tilde *)(w[1]);
29 t_sample *in = (t_sample *)(w[2]);
30 t_sample *out = (t_sample *)(w[3]);
31 int n = (int)(w[4]);
32 int maxindex;
33 t_sample *buf = x->x_vec, *fp;
34 int i;
35
36 maxindex = x->x_npoints - 1;
37 if (!buf) goto zero;
38
39 for (i = 0; i < n; i++)
40 {
41 int index = ((long long) mult((*in++),ftofix(44.1)) >> fix1);
42 if (index < 0)
43 index = 0;
44 else if (index > maxindex)
45 index = maxindex;
46 *out++ = buf[index];
47 }
48 return (w+5);
49 zero:
50 while (n--) *out++ = 0;
51
52 return (w+5);
53}
54
55void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s)
56{
57 t_garray *a;
58
59 x->x_arrayname = s;
60 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
61 {
62 if (*s->s_name)
63 error("tabread~: %s: no such array", x->x_arrayname->s_name);
64 x->x_vec = 0;
65 }
66 else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
67 {
68 error("%s: bad template for tabread~", x->x_arrayname->s_name);
69 x->x_vec = 0;
70 }
71 else garray_usedindsp(a);
72}
73
74static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp)
75{
76 tabread_tilde_set(x, x->x_arrayname);
77
78 dsp_add(tabread_tilde_perform, 4, x,
79 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
80
81}
82
83static void tabread_tilde_free(t_tabread_tilde *x)
84{
85}
86
87void tabread_tilde_setup(void)
88{
89 tabread_tilde_class = class_new(gensym("tabread~"),
90 (t_newmethod)tabread_tilde_new, (t_method)tabread_tilde_free,
91 sizeof(t_tabread_tilde), 0, A_DEFSYM, 0);
92 CLASS_MAINSIGNALIN(tabread_tilde_class, t_tabread_tilde, x_f);
93 class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_dsp,
94 gensym("dsp"), 0);
95 class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_set,
96 gensym("set"), A_SYMBOL, 0);
97}
98#define FIXEDPOINT
99#include <m_pd.h>
100#include <m_fixed.h>
101
102static t_class *tabread_tilde_class;
103
104typedef struct _tabread_tilde
105{
106 t_object x_obj;
107 int x_npoints;
108 t_sample *x_vec;
109 t_symbol *x_arrayname;
110 float x_f;
111} t_tabread_tilde;
112
113static void *tabread_tilde_new(t_symbol *s)
114{
115 t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
116 x->x_arrayname = s;
117 x->x_vec = 0;
118 outlet_new(&x->x_obj, gensym("signal"));
119 x->x_f = 0;
120 return (x);
121}
122
123static t_int *tabread_tilde_perform(t_int *w)
124{
125 t_tabread_tilde *x = (t_tabread_tilde *)(w[1]);
126 t_sample *in = (t_sample *)(w[2]);
127 t_sample *out = (t_sample *)(w[3]);
128 int n = (int)(w[4]);
129 int maxindex;
130 t_sample *buf = x->x_vec, *fp;
131 int i;
132
133 maxindex = x->x_npoints - 1;
134 if (!buf) goto zero;
135
136 for (i = 0; i < n; i++)
137 {
138 int index = ((long long) mult((*in++),ftofix(44.1)) >> fix1);
139 if (index < 0)
140 index = 0;
141 else if (index > maxindex)
142 index = maxindex;
143 *out++ = buf[index];
144 }
145 return (w+5);
146 zero:
147 while (n--) *out++ = 0;
148
149 return (w+5);
150}
151
152void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s)
153{
154 t_garray *a;
155
156 x->x_arrayname = s;
157 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
158 {
159 if (*s->s_name)
160 error("tabread~: %s: no such array", x->x_arrayname->s_name);
161 x->x_vec = 0;
162 }
163 else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
164 {
165 error("%s: bad template for tabread~", x->x_arrayname->s_name);
166 x->x_vec = 0;
167 }
168 else garray_usedindsp(a);
169}
170
171static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp)
172{
173 tabread_tilde_set(x, x->x_arrayname);
174
175 dsp_add(tabread_tilde_perform, 4, x,
176 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
177
178}
179
180static void tabread_tilde_free(t_tabread_tilde *x)
181{
182}
183
184void tabread_tilde_setup(void)
185{
186 tabread_tilde_class = class_new(gensym("tabread~"),
187 (t_newmethod)tabread_tilde_new, (t_method)tabread_tilde_free,
188 sizeof(t_tabread_tilde), 0, A_DEFSYM, 0);
189 CLASS_MAINSIGNALIN(tabread_tilde_class, t_tabread_tilde, x_f);
190 class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_dsp,
191 gensym("dsp"), 0);
192 class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_set,
193 gensym("set"), A_SYMBOL, 0);
194}
diff --git a/apps/plugins/pdbox/PDa/intern/tabreceive~.c b/apps/plugins/pdbox/PDa/intern/tabreceive~.c
new file mode 100644
index 0000000000..82f2ff388a
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabreceive~.c
@@ -0,0 +1,122 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4static t_class *tabreceive_class;
5
6typedef struct _tabreceive
7{
8 t_object x_obj;
9 t_sample *x_vec;
10 t_symbol *x_arrayname;
11} t_tabreceive;
12
13static t_int *tabreceive_perform(t_int *w)
14{
15 t_tabreceive *x = (t_tabreceive *)(w[1]);
16 t_sample *out = (t_sample *)(w[2]);
17 int n = w[3];
18 t_sample *from = x->x_vec;
19 if (from) while (n--) *out++ = *from++;
20 else while (n--) *out++ = 0;
21 return (w+4);
22}
23
24static void tabreceive_dsp(t_tabreceive *x, t_signal **sp)
25{
26 t_garray *a;
27 int vecsize;
28
29 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
30 {
31 if (*x->x_arrayname->s_name)
32 error("tabsend~: %s: no such array", x->x_arrayname->s_name);
33 }
34 else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
35 error("%s: bad template for tabreceive~", x->x_arrayname->s_name);
36 else
37 {
38 int n = sp[0]->s_n;
39 if (n < vecsize) vecsize = n;
40 garray_usedindsp(a);
41 dsp_add(tabreceive_perform, 3, x, sp[0]->s_vec, vecsize);
42 }
43}
44
45static void *tabreceive_new(t_symbol *s)
46{
47 t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
48 x->x_arrayname = s;
49 outlet_new(&x->x_obj, &s_signal);
50 return (x);
51}
52
53void tabreceive_tilde_setup(void)
54{
55 tabreceive_class = class_new(gensym("tabreceive~"),
56 (t_newmethod)tabreceive_new, 0,
57 sizeof(t_tabreceive), 0, A_DEFSYM, 0);
58 class_addmethod(tabreceive_class, (t_method)tabreceive_dsp,
59 gensym("dsp"), 0);
60}
61
62#include <m_pd.h>
63#include <m_fixed.h>
64
65static t_class *tabreceive_class;
66
67typedef struct _tabreceive
68{
69 t_object x_obj;
70 t_sample *x_vec;
71 t_symbol *x_arrayname;
72} t_tabreceive;
73
74static t_int *tabreceive_perform(t_int *w)
75{
76 t_tabreceive *x = (t_tabreceive *)(w[1]);
77 t_sample *out = (t_sample *)(w[2]);
78 int n = w[3];
79 t_sample *from = x->x_vec;
80 if (from) while (n--) *out++ = *from++;
81 else while (n--) *out++ = 0;
82 return (w+4);
83}
84
85static void tabreceive_dsp(t_tabreceive *x, t_signal **sp)
86{
87 t_garray *a;
88 int vecsize;
89
90 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
91 {
92 if (*x->x_arrayname->s_name)
93 error("tabsend~: %s: no such array", x->x_arrayname->s_name);
94 }
95 else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
96 error("%s: bad template for tabreceive~", x->x_arrayname->s_name);
97 else
98 {
99 int n = sp[0]->s_n;
100 if (n < vecsize) vecsize = n;
101 garray_usedindsp(a);
102 dsp_add(tabreceive_perform, 3, x, sp[0]->s_vec, vecsize);
103 }
104}
105
106static void *tabreceive_new(t_symbol *s)
107{
108 t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
109 x->x_arrayname = s;
110 outlet_new(&x->x_obj, &s_signal);
111 return (x);
112}
113
114void tabreceive_tilde_setup(void)
115{
116 tabreceive_class = class_new(gensym("tabreceive~"),
117 (t_newmethod)tabreceive_new, 0,
118 sizeof(t_tabreceive), 0, A_DEFSYM, 0);
119 class_addmethod(tabreceive_class, (t_method)tabreceive_dsp,
120 gensym("dsp"), 0);
121}
122
diff --git a/apps/plugins/pdbox/PDa/intern/tabsend~.c b/apps/plugins/pdbox/PDa/intern/tabsend~.c
new file mode 100644
index 0000000000..4d7ac9007e
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabsend~.c
@@ -0,0 +1,196 @@
1
2#include <m_pd.h>
3#include <m_fixed.h>
4static t_class *tabsend_class;
5
6typedef struct _tabsend
7{
8 t_object x_obj;
9 t_sample *x_vec;
10 int x_graphperiod;
11 int x_graphcount;
12 t_symbol *x_arrayname;
13 t_clock *x_clock;
14 float x_f;
15} t_tabsend;
16
17static void tabsend_tick(t_tabsend *x);
18
19static void *tabsend_new(t_symbol *s)
20{
21 t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
22 x->x_graphcount = 0;
23 x->x_arrayname = s;
24 x->x_clock = clock_new(x, (t_method)tabsend_tick);
25 x->x_f = 0;
26 return (x);
27}
28
29static t_int *tabsend_perform(t_int *w)
30{
31 t_tabsend *x = (t_tabsend *)(w[1]);
32 t_sample *in = (t_sample *)(w[2]);
33 int n = w[3];
34 t_sample *dest = x->x_vec;
35 int i = x->x_graphcount;
36 if (!x->x_vec) goto bad;
37
38 while (n--)
39 {
40 t_sample f = *in++;
41 if (PD_BADFLOAT(f))
42 f = 0;
43 *dest++ = f;
44 }
45 if (!i--)
46 {
47 clock_delay(x->x_clock, 0);
48 i = x->x_graphperiod;
49 }
50 x->x_graphcount = i;
51bad:
52 return (w+4);
53}
54
55static void tabsend_dsp(t_tabsend *x, t_signal **sp)
56{
57 int i, vecsize;
58 t_garray *a;
59
60 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
61 {
62 if (*x->x_arrayname->s_name)
63 error("tabsend~: %s: no such array", x->x_arrayname->s_name);
64 }
65 else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
66 error("%s: bad template for tabsend~", x->x_arrayname->s_name);
67 else
68 {
69 int n = sp[0]->s_n;
70 int ticksper = sp[0]->s_sr/n;
71 if (ticksper < 1) ticksper = 1;
72 x->x_graphperiod = ticksper;
73 if (x->x_graphcount > ticksper) x->x_graphcount = ticksper;
74 if (n < vecsize) vecsize = n;
75 garray_usedindsp(a);
76 dsp_add(tabsend_perform, 3, x, sp[0]->s_vec, vecsize);
77 }
78}
79
80static void tabsend_tick(t_tabsend *x)
81{
82 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
83 if (!a) bug("tabsend_tick");
84 else garray_redraw(a);
85}
86
87static void tabsend_free(t_tabsend *x)
88{
89 clock_free(x->x_clock);
90}
91
92void tabsend_tilde_setup(void)
93{
94 tabsend_class = class_new(gensym("tabsend~"), (t_newmethod)tabsend_new,
95 (t_method)tabsend_free, sizeof(t_tabsend), 0, A_DEFSYM, 0);
96 CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, x_f);
97 class_addmethod(tabsend_class, (t_method)tabsend_dsp, gensym("dsp"), 0);
98}
99
100#include <m_pd.h>
101#include <m_fixed.h>
102static t_class *tabsend_class;
103
104typedef struct _tabsend
105{
106 t_object x_obj;
107 t_sample *x_vec;
108 int x_graphperiod;
109 int x_graphcount;
110 t_symbol *x_arrayname;
111 t_clock *x_clock;
112 float x_f;
113} t_tabsend;
114
115static void tabsend_tick(t_tabsend *x);
116
117static void *tabsend_new(t_symbol *s)
118{
119 t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
120 x->x_graphcount = 0;
121 x->x_arrayname = s;
122 x->x_clock = clock_new(x, (t_method)tabsend_tick);
123 x->x_f = 0;
124 return (x);
125}
126
127static t_int *tabsend_perform(t_int *w)
128{
129 t_tabsend *x = (t_tabsend *)(w[1]);
130 t_sample *in = (t_sample *)(w[2]);
131 int n = w[3];
132 t_sample *dest = x->x_vec;
133 int i = x->x_graphcount;
134 if (!x->x_vec) goto bad;
135
136 while (n--)
137 {
138 t_sample f = *in++;
139 if (PD_BADFLOAT(f))
140 f = 0;
141 *dest++ = f;
142 }
143 if (!i--)
144 {
145 clock_delay(x->x_clock, 0);
146 i = x->x_graphperiod;
147 }
148 x->x_graphcount = i;
149bad:
150 return (w+4);
151}
152
153static void tabsend_dsp(t_tabsend *x, t_signal **sp)
154{
155 int i, vecsize;
156 t_garray *a;
157
158 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
159 {
160 if (*x->x_arrayname->s_name)
161 error("tabsend~: %s: no such array", x->x_arrayname->s_name);
162 }
163 else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
164 error("%s: bad template for tabsend~", x->x_arrayname->s_name);
165 else
166 {
167 int n = sp[0]->s_n;
168 int ticksper = sp[0]->s_sr/n;
169 if (ticksper < 1) ticksper = 1;
170 x->x_graphperiod = ticksper;
171 if (x->x_graphcount > ticksper) x->x_graphcount = ticksper;
172 if (n < vecsize) vecsize = n;
173 garray_usedindsp(a);
174 dsp_add(tabsend_perform, 3, x, sp[0]->s_vec, vecsize);
175 }
176}
177
178static void tabsend_tick(t_tabsend *x)
179{
180 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
181 if (!a) bug("tabsend_tick");
182 else garray_redraw(a);
183}
184
185static void tabsend_free(t_tabsend *x)
186{
187 clock_free(x->x_clock);
188}
189
190void tabsend_tilde_setup(void)
191{
192 tabsend_class = class_new(gensym("tabsend~"), (t_newmethod)tabsend_new,
193 (t_method)tabsend_free, sizeof(t_tabsend), 0, A_DEFSYM, 0);
194 CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, x_f);
195 class_addmethod(tabsend_class, (t_method)tabsend_dsp, gensym("dsp"), 0);
196}
diff --git a/apps/plugins/pdbox/PDa/intern/tabwrite.c b/apps/plugins/pdbox/PDa/intern/tabwrite.c
new file mode 100644
index 0000000000..8d6a6c0da8
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabwrite.c
@@ -0,0 +1,168 @@
1#include <m_pd.h>
2/* ------------------ tabwrite: control ------------------------ */
3
4static t_class *tabwrite_class;
5
6typedef struct _tabwrite
7{
8 t_object x_obj;
9 t_symbol *x_arrayname;
10 t_clock *x_clock;
11 float x_ft1;
12 double x_updtime;
13 int x_set;
14} t_tabwrite;
15
16static void tabwrite_tick(t_tabwrite *x)
17{
18 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
19 if (!a) bug("tabwrite_tick");
20 else garray_redraw(a);
21 x->x_set = 0;
22 x->x_updtime = clock_getsystime();
23}
24
25static void tabwrite_float(t_tabwrite *x, t_float f)
26{
27 int i, vecsize;
28 t_garray *a;
29 t_sample *vec;
30
31 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
32 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
33 else if (!garray_getfloatarray(a, &vecsize, &vec))
34 pd_error(x, "%s: bad template for tabwrite", x->x_arrayname->s_name);
35 else
36 {
37 int n = x->x_ft1;
38 double timesince = clock_gettimesince(x->x_updtime);
39 if (n < 0) n = 0;
40 else if (n >= vecsize) n = vecsize-1;
41 vec[n] = ftofix(f);
42 if (timesince > 1000)
43 {
44 tabwrite_tick(x);
45 }
46 else
47 {
48 if (x->x_set == 0)
49 {
50 clock_delay(x->x_clock, 1000 - timesince);
51 x->x_set = 1;
52 }
53 }
54 }
55}
56
57static void tabwrite_set(t_tabwrite *x, t_symbol *s)
58{
59 x->x_arrayname = s;
60}
61
62static void tabwrite_free(t_tabwrite *x)
63{
64 clock_free(x->x_clock);
65}
66
67static void *tabwrite_new(t_symbol *s)
68{
69 t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
70 x->x_ft1 = 0;
71 x->x_arrayname = s;
72 x->x_updtime = clock_getsystime();
73 x->x_clock = clock_new(x, (t_method)tabwrite_tick);
74 floatinlet_new(&x->x_obj, &x->x_ft1);
75 return (x);
76}
77
78void tabwrite_setup(void)
79{
80 tabwrite_class = class_new(gensym("tabwrite"), (t_newmethod)tabwrite_new,
81 (t_method)tabwrite_free, sizeof(t_tabwrite), 0, A_DEFSYM, 0);
82 class_addfloat(tabwrite_class, (t_method)tabwrite_float);
83 class_addmethod(tabwrite_class, (t_method)tabwrite_set, gensym("set"), A_SYMBOL, 0);
84}
85#include <m_pd.h>
86/* ------------------ tabwrite: control ------------------------ */
87
88static t_class *tabwrite_class;
89
90typedef struct _tabwrite
91{
92 t_object x_obj;
93 t_symbol *x_arrayname;
94 t_clock *x_clock;
95 float x_ft1;
96 double x_updtime;
97 int x_set;
98} t_tabwrite;
99
100static void tabwrite_tick(t_tabwrite *x)
101{
102 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
103 if (!a) bug("tabwrite_tick");
104 else garray_redraw(a);
105 x->x_set = 0;
106 x->x_updtime = clock_getsystime();
107}
108
109static void tabwrite_float(t_tabwrite *x, t_float f)
110{
111 int i, vecsize;
112 t_garray *a;
113 t_sample *vec;
114
115 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
116 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
117 else if (!garray_getfloatarray(a, &vecsize, &vec))
118 pd_error(x, "%s: bad template for tabwrite", x->x_arrayname->s_name);
119 else
120 {
121 int n = x->x_ft1;
122 double timesince = clock_gettimesince(x->x_updtime);
123 if (n < 0) n = 0;
124 else if (n >= vecsize) n = vecsize-1;
125 vec[n] = ftofix(f);
126 if (timesince > 1000)
127 {
128 tabwrite_tick(x);
129 }
130 else
131 {
132 if (x->x_set == 0)
133 {
134 clock_delay(x->x_clock, 1000 - timesince);
135 x->x_set = 1;
136 }
137 }
138 }
139}
140
141static void tabwrite_set(t_tabwrite *x, t_symbol *s)
142{
143 x->x_arrayname = s;
144}
145
146static void tabwrite_free(t_tabwrite *x)
147{
148 clock_free(x->x_clock);
149}
150
151static void *tabwrite_new(t_symbol *s)
152{
153 t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
154 x->x_ft1 = 0;
155 x->x_arrayname = s;
156 x->x_updtime = clock_getsystime();
157 x->x_clock = clock_new(x, (t_method)tabwrite_tick);
158 floatinlet_new(&x->x_obj, &x->x_ft1);
159 return (x);
160}
161
162void tabwrite_setup(void)
163{
164 tabwrite_class = class_new(gensym("tabwrite"), (t_newmethod)tabwrite_new,
165 (t_method)tabwrite_free, sizeof(t_tabwrite), 0, A_DEFSYM, 0);
166 class_addfloat(tabwrite_class, (t_method)tabwrite_float);
167 class_addmethod(tabwrite_class, (t_method)tabwrite_set, gensym("set"), A_SYMBOL, 0);
168}
diff --git a/apps/plugins/pdbox/PDa/intern/tabwrite~.c b/apps/plugins/pdbox/PDa/intern/tabwrite~.c
new file mode 100644
index 0000000000..47a49cd833
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/tabwrite~.c
@@ -0,0 +1,264 @@
1
2#include <m_pd.h>
3#include <m_fixed.h>
4
5static t_class *tabwrite_tilde_class;
6
7typedef struct _tabwrite_tilde
8{
9 t_object x_obj;
10 int x_phase;
11 int x_nsampsintab;
12 t_sample *x_vec;
13 t_symbol *x_arrayname;
14 t_clock *x_clock;
15 float x_f;
16} t_tabwrite_tilde;
17
18static void tabwrite_tilde_tick(t_tabwrite_tilde *x);
19
20static void *tabwrite_tilde_new(t_symbol *s)
21{
22 t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
23 x->x_clock = clock_new(x, (t_method)tabwrite_tilde_tick);
24 x->x_phase = 0x7fffffff;
25 x->x_arrayname = s;
26 x->x_f = 0;
27 return (x);
28}
29
30static t_int *tabwrite_tilde_perform(t_int *w)
31{
32 t_tabwrite_tilde *x = (t_tabwrite_tilde *)(w[1]);
33 t_sample *in = (t_sample *)(w[2]);
34 int n = (int)(w[3]), phase = x->x_phase, endphase = x->x_nsampsintab;
35 if (!x->x_vec) goto bad;
36
37 if (endphase > phase)
38 {
39 int nxfer = endphase - phase;
40 t_sample *fp = x->x_vec + phase;
41 if (nxfer > n) nxfer = n;
42 phase += nxfer;
43 while (nxfer--)
44 {
45 t_sample f = *in++;
46 *fp++ = f;
47 }
48 if (phase >= endphase)
49 {
50 clock_delay(x->x_clock, 0);
51 phase = 0x7fffffff;
52 }
53 x->x_phase = phase;
54 }
55bad:
56 return (w+4);
57}
58
59void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s)
60{
61 t_garray *a;
62
63 x->x_arrayname = s;
64 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
65 {
66 if (*s->s_name) pd_error(x, "tabwrite~: %s: no such array",
67 x->x_arrayname->s_name);
68 x->x_vec = 0;
69 }
70 else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
71 {
72 error("%s: bad template for tabwrite~", x->x_arrayname->s_name);
73 x->x_vec = 0;
74 }
75 else garray_usedindsp(a);
76}
77
78static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp)
79{
80 tabwrite_tilde_set(x, x->x_arrayname);
81 dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
82}
83
84static void tabwrite_tilde_bang(t_tabwrite_tilde *x)
85{
86 x->x_phase = 0;
87}
88
89static void tabwrite_tilde_float(t_tabwrite_tilde *x,t_float n)
90{
91 if (n < x->x_nsampsintab)
92 x->x_phase = n;
93 else
94 x->x_phase = 0;
95}
96
97static void tabwrite_tilde_stop(t_tabwrite_tilde *x)
98{
99 if (x->x_phase != 0x7fffffff)
100 {
101 tabwrite_tilde_tick(x);
102 x->x_phase = 0x7fffffff;
103 }
104}
105
106static void tabwrite_tilde_tick(t_tabwrite_tilde *x)
107{
108 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
109 if (!a) bug("tabwrite_tilde_tick");
110 else garray_redraw(a);
111}
112
113static void tabwrite_tilde_free(t_tabwrite_tilde *x)
114{
115 clock_free(x->x_clock);
116}
117
118void tabwrite_tilde_setup(void)
119{
120 tabwrite_tilde_class = class_new(gensym("tabwrite~"),
121 (t_newmethod)tabwrite_tilde_new, (t_method)tabwrite_tilde_free,
122 sizeof(t_tabwrite_tilde), 0, A_DEFSYM, 0);
123 CLASS_MAINSIGNALIN(tabwrite_tilde_class, t_tabwrite_tilde, x_f);
124 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_dsp,
125 gensym("dsp"), 0);
126 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_set,
127 gensym("set"), A_SYMBOL, 0);
128 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_stop,
129 gensym("stop"), 0);
130 class_addbang(tabwrite_tilde_class, tabwrite_tilde_bang);
131 class_addfloat(tabwrite_tilde_class, tabwrite_tilde_float);
132}
133
134#include <m_pd.h>
135#include <m_fixed.h>
136
137static t_class *tabwrite_tilde_class;
138
139typedef struct _tabwrite_tilde
140{
141 t_object x_obj;
142 int x_phase;
143 int x_nsampsintab;
144 t_sample *x_vec;
145 t_symbol *x_arrayname;
146 t_clock *x_clock;
147 float x_f;
148} t_tabwrite_tilde;
149
150static void tabwrite_tilde_tick(t_tabwrite_tilde *x);
151
152static void *tabwrite_tilde_new(t_symbol *s)
153{
154 t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
155 x->x_clock = clock_new(x, (t_method)tabwrite_tilde_tick);
156 x->x_phase = 0x7fffffff;
157 x->x_arrayname = s;
158 x->x_f = 0;
159 return (x);
160}
161
162static t_int *tabwrite_tilde_perform(t_int *w)
163{
164 t_tabwrite_tilde *x = (t_tabwrite_tilde *)(w[1]);
165 t_sample *in = (t_sample *)(w[2]);
166 int n = (int)(w[3]), phase = x->x_phase, endphase = x->x_nsampsintab;
167 if (!x->x_vec) goto bad;
168
169 if (endphase > phase)
170 {
171 int nxfer = endphase - phase;
172 t_sample *fp = x->x_vec + phase;
173 if (nxfer > n) nxfer = n;
174 phase += nxfer;
175 while (nxfer--)
176 {
177 t_sample f = *in++;
178 *fp++ = f;
179 }
180 if (phase >= endphase)
181 {
182 clock_delay(x->x_clock, 0);
183 phase = 0x7fffffff;
184 }
185 x->x_phase = phase;
186 }
187bad:
188 return (w+4);
189}
190
191void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s)
192{
193 t_garray *a;
194
195 x->x_arrayname = s;
196 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
197 {
198 if (*s->s_name) pd_error(x, "tabwrite~: %s: no such array",
199 x->x_arrayname->s_name);
200 x->x_vec = 0;
201 }
202 else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
203 {
204 error("%s: bad template for tabwrite~", x->x_arrayname->s_name);
205 x->x_vec = 0;
206 }
207 else garray_usedindsp(a);
208}
209
210static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp)
211{
212 tabwrite_tilde_set(x, x->x_arrayname);
213 dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
214}
215
216static void tabwrite_tilde_bang(t_tabwrite_tilde *x)
217{
218 x->x_phase = 0;
219}
220
221static void tabwrite_tilde_float(t_tabwrite_tilde *x,t_float n)
222{
223 if (n < x->x_nsampsintab)
224 x->x_phase = n;
225 else
226 x->x_phase = 0;
227}
228
229static void tabwrite_tilde_stop(t_tabwrite_tilde *x)
230{
231 if (x->x_phase != 0x7fffffff)
232 {
233 tabwrite_tilde_tick(x);
234 x->x_phase = 0x7fffffff;
235 }
236}
237
238static void tabwrite_tilde_tick(t_tabwrite_tilde *x)
239{
240 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
241 if (!a) bug("tabwrite_tilde_tick");
242 else garray_redraw(a);
243}
244
245static void tabwrite_tilde_free(t_tabwrite_tilde *x)
246{
247 clock_free(x->x_clock);
248}
249
250void tabwrite_tilde_setup(void)
251{
252 tabwrite_tilde_class = class_new(gensym("tabwrite~"),
253 (t_newmethod)tabwrite_tilde_new, (t_method)tabwrite_tilde_free,
254 sizeof(t_tabwrite_tilde), 0, A_DEFSYM, 0);
255 CLASS_MAINSIGNALIN(tabwrite_tilde_class, t_tabwrite_tilde, x_f);
256 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_dsp,
257 gensym("dsp"), 0);
258 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_set,
259 gensym("set"), A_SYMBOL, 0);
260 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_stop,
261 gensym("stop"), 0);
262 class_addbang(tabwrite_tilde_class, tabwrite_tilde_bang);
263 class_addfloat(tabwrite_tilde_class, tabwrite_tilde_float);
264}
diff --git a/apps/plugins/pdbox/PDa/intern/threshold~.c b/apps/plugins/pdbox/PDa/intern/threshold~.c
new file mode 100644
index 0000000000..78b15f7342
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/threshold~.c
@@ -0,0 +1,270 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4static t_class *threshold_tilde_class;
5
6typedef struct _threshold_tilde
7{
8 t_object x_obj;
9 t_outlet *x_outlet1; /* bang out for high thresh */
10 t_outlet *x_outlet2; /* bang out for low thresh */
11 t_clock *x_clock; /* wakeup for message output */
12 float x_f; /* scalar inlet */
13 int x_state; /* 1 = high, 0 = low */
14 t_sample x_hithresh; /* value of high threshold */
15 t_sample x_lothresh; /* value of low threshold */
16 float x_deadwait; /* msec remaining in dead period */
17 float x_msecpertick; /* msec per DSP tick */
18 float x_hideadtime; /* hi dead time in msec */
19 float x_lodeadtime; /* lo dead time in msec */
20} t_threshold_tilde;
21
22static void threshold_tilde_tick(t_threshold_tilde *x);
23static void threshold_tilde_set(t_threshold_tilde *x,
24 t_floatarg hithresh, t_floatarg hideadtime,
25 t_floatarg lothresh, t_floatarg lodeadtime);
26
27static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
28 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
29{
30 t_threshold_tilde *x = (t_threshold_tilde *)
31 pd_new(threshold_tilde_class);
32 x->x_state = 0; /* low state */
33 x->x_deadwait = 0; /* no dead time */
34 x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
35 x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
36 x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
37 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
38 x->x_msecpertick = 0.;
39 x->x_f = 0;
40 threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
41 return (x);
42}
43
44 /* "set" message to specify thresholds and dead times */
45static void threshold_tilde_set(t_threshold_tilde *x,
46 t_floatarg hithresh, t_floatarg hideadtime,
47 t_floatarg lothresh, t_floatarg lodeadtime)
48{
49 if (lothresh > hithresh)
50 lothresh = hithresh;
51 x->x_hithresh = ftofix(hithresh);
52 x->x_hideadtime = hideadtime;
53 x->x_lothresh = ftofix(lothresh);
54 x->x_lodeadtime = lodeadtime;
55}
56
57 /* number in inlet sets state -- note incompatible with JMAX which used
58 "int" message for this, impossible here because of auto signal conversion */
59static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
60{
61 x->x_state = (f != 0);
62 x->x_deadwait = 0;
63}
64
65static void threshold_tilde_tick(t_threshold_tilde *x)
66{
67 if (x->x_state)
68 outlet_bang(x->x_outlet1);
69 else outlet_bang(x->x_outlet2);
70}
71
72static t_int *threshold_tilde_perform(t_int *w)
73{
74 t_sample *in1 = (t_sample *)(w[1]);
75 t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
76 int n = (t_int)(w[3]);
77 if (x->x_deadwait > 0)
78 x->x_deadwait -= x->x_msecpertick;
79 else if (x->x_state)
80 {
81 /* we're high; look for low sample */
82 for (; n--; in1++)
83 {
84 if (*in1 < x->x_lothresh)
85 {
86 clock_delay(x->x_clock, 0L);
87 x->x_state = 0;
88 x->x_deadwait = x->x_lodeadtime;
89 goto done;
90 }
91 }
92 }
93 else
94 {
95 /* we're low; look for high sample */
96 for (; n--; in1++)
97 {
98 if (*in1 >= x->x_hithresh)
99 {
100 clock_delay(x->x_clock, 0L);
101 x->x_state = 1;
102 x->x_deadwait = x->x_hideadtime;
103 goto done;
104 }
105 }
106 }
107done:
108 return (w+4);
109}
110
111void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
112{
113 x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
114 dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
115}
116
117static void threshold_tilde_ff(t_threshold_tilde *x)
118{
119 clock_free(x->x_clock);
120}
121
122void threshold_tilde_setup( void)
123{
124 threshold_tilde_class = class_new(gensym("threshold~"),
125 (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
126 sizeof(t_threshold_tilde), 0,
127 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
128 CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
129 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
130 gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
131 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
132 gensym("ft1"), A_FLOAT, 0);
133 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
134 gensym("dsp"), 0);
135}
136#include <m_pd.h>
137#include <m_fixed.h>
138
139static t_class *threshold_tilde_class;
140
141typedef struct _threshold_tilde
142{
143 t_object x_obj;
144 t_outlet *x_outlet1; /* bang out for high thresh */
145 t_outlet *x_outlet2; /* bang out for low thresh */
146 t_clock *x_clock; /* wakeup for message output */
147 float x_f; /* scalar inlet */
148 int x_state; /* 1 = high, 0 = low */
149 t_sample x_hithresh; /* value of high threshold */
150 t_sample x_lothresh; /* value of low threshold */
151 float x_deadwait; /* msec remaining in dead period */
152 float x_msecpertick; /* msec per DSP tick */
153 float x_hideadtime; /* hi dead time in msec */
154 float x_lodeadtime; /* lo dead time in msec */
155} t_threshold_tilde;
156
157static void threshold_tilde_tick(t_threshold_tilde *x);
158static void threshold_tilde_set(t_threshold_tilde *x,
159 t_floatarg hithresh, t_floatarg hideadtime,
160 t_floatarg lothresh, t_floatarg lodeadtime);
161
162static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
163 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
164{
165 t_threshold_tilde *x = (t_threshold_tilde *)
166 pd_new(threshold_tilde_class);
167 x->x_state = 0; /* low state */
168 x->x_deadwait = 0; /* no dead time */
169 x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
170 x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
171 x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
172 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
173 x->x_msecpertick = 0.;
174 x->x_f = 0;
175 threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
176 return (x);
177}
178
179 /* "set" message to specify thresholds and dead times */
180static void threshold_tilde_set(t_threshold_tilde *x,
181 t_floatarg hithresh, t_floatarg hideadtime,
182 t_floatarg lothresh, t_floatarg lodeadtime)
183{
184 if (lothresh > hithresh)
185 lothresh = hithresh;
186 x->x_hithresh = ftofix(hithresh);
187 x->x_hideadtime = hideadtime;
188 x->x_lothresh = ftofix(lothresh);
189 x->x_lodeadtime = lodeadtime;
190}
191
192 /* number in inlet sets state -- note incompatible with JMAX which used
193 "int" message for this, impossible here because of auto signal conversion */
194static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
195{
196 x->x_state = (f != 0);
197 x->x_deadwait = 0;
198}
199
200static void threshold_tilde_tick(t_threshold_tilde *x)
201{
202 if (x->x_state)
203 outlet_bang(x->x_outlet1);
204 else outlet_bang(x->x_outlet2);
205}
206
207static t_int *threshold_tilde_perform(t_int *w)
208{
209 t_sample *in1 = (t_sample *)(w[1]);
210 t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
211 int n = (t_int)(w[3]);
212 if (x->x_deadwait > 0)
213 x->x_deadwait -= x->x_msecpertick;
214 else if (x->x_state)
215 {
216 /* we're high; look for low sample */
217 for (; n--; in1++)
218 {
219 if (*in1 < x->x_lothresh)
220 {
221 clock_delay(x->x_clock, 0L);
222 x->x_state = 0;
223 x->x_deadwait = x->x_lodeadtime;
224 goto done;
225 }
226 }
227 }
228 else
229 {
230 /* we're low; look for high sample */
231 for (; n--; in1++)
232 {
233 if (*in1 >= x->x_hithresh)
234 {
235 clock_delay(x->x_clock, 0L);
236 x->x_state = 1;
237 x->x_deadwait = x->x_hideadtime;
238 goto done;
239 }
240 }
241 }
242done:
243 return (w+4);
244}
245
246void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
247{
248 x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
249 dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
250}
251
252static void threshold_tilde_ff(t_threshold_tilde *x)
253{
254 clock_free(x->x_clock);
255}
256
257void threshold_tilde_setup( void)
258{
259 threshold_tilde_class = class_new(gensym("threshold~"),
260 (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
261 sizeof(t_threshold_tilde), 0,
262 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
263 CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
264 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
265 gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
266 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
267 gensym("ft1"), A_FLOAT, 0);
268 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
269 gensym("dsp"), 0);
270}
diff --git a/apps/plugins/pdbox/PDa/intern/vcf~.c b/apps/plugins/pdbox/PDa/intern/vcf~.c
new file mode 100644
index 0000000000..1ff09812a1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/vcf~.c
@@ -0,0 +1,238 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3#include "cos_table.h"
4
5/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
6/* GG: complex resonator with signal frequency control
7 this time using the bigger cos_table without interpolation
8 really have to switch to a separate fixpoint format sometime
9*/
10
11typedef struct vcfctl
12{
13 t_sample c_re;
14 t_sample c_im;
15 t_sample c_q;
16 t_sample c_isr;
17} t_vcfctl;
18
19typedef struct sigvcf
20{
21 t_object x_obj;
22 t_vcfctl x_cspace;
23 t_vcfctl *x_ctl;
24 float x_f;
25} t_sigvcf;
26
27t_class *sigvcf_class;
28
29static void *sigvcf_new(t_floatarg q)
30{
31 t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
32 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
33 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
34 outlet_new(&x->x_obj, gensym("signal"));
35 outlet_new(&x->x_obj, gensym("signal"));
36 x->x_ctl = &x->x_cspace;
37 x->x_cspace.c_re = 0;
38 x->x_cspace.c_im = 0;
39 x->x_cspace.c_q = ftofix(q);
40 x->x_cspace.c_isr = 0;
41 x->x_f = 0;
42 return (x);
43}
44
45static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
46{
47 x->x_ctl->c_q = (f > 0 ? ftofix(f) : 0);
48}
49
50static t_int *sigvcf_perform(t_int *w)
51{
52 t_sample *in1 = (t_sample *)(w[1]);
53 t_sample *in2 = (t_sample *)(w[2]);
54 t_sample *out1 = (t_sample *)(w[3]);
55 t_sample *out2 = (t_sample *)(w[4]);
56 t_vcfctl *c = (t_vcfctl *)(w[5]);
57 int n = (t_int)(w[6]);
58 int i;
59 t_sample re = c->c_re, re2;
60 t_sample im = c->c_im;
61 t_sample q = c->c_q;
62 t_sample qinv = (q > 0 ? idiv(ftofix(1.0),q) : 0);
63 t_sample ampcorrect = ftofix(2.0f) - idiv(ftofix(2.0f) , (q + ftofix(2.0f)));
64 t_sample isr = c->c_isr;
65 t_sample coefr, coefi;
66 t_sample *tab = cos_table;
67 t_sample oneminusr,cfindx,cf,r;
68
69 for (i = 0; i < n; i++)
70 {
71 cf = mult(*in2++,isr);
72 if (cf < 0) cf = 0;
73 cfindx = mult(cf,ftofix(0.15915494))>>(fix1-ILOGCOSTABSIZE); /* 1/2*PI */
74 r = (qinv > 0 ? ftofix(1.01) - mult(cf,qinv) : 0);
75
76 if (r < 0) r = 0;
77 oneminusr = ftofix(1.02f) - r; /* hand adapted */
78
79 /* r*cos(cf) */
80 coefr = mult(r,tab[cfindx]);
81
82 /* r*sin(cf) */
83 cfindx-=(ICOSTABSIZE>>2);
84 cfindx += cfindx < 0 ? ICOSTABSIZE:0;
85 coefi = mult(r,tab[cfindx]);
86
87 re2 = re;
88 *out1++ = re = mult(ampcorrect,mult(oneminusr,*in1++))
89 + mult(coefr,re2) - mult(coefi, im);
90 *out2++ = im = mult(coefi,re2) + mult(coefr,im);
91 }
92 c->c_re = re;
93 c->c_im = im;
94 return (w+7);
95}
96
97static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
98{
99 /* TODO sr is hardcoded */
100 x->x_ctl->c_isr = ftofix(0.0001424758);
101// idiv(ftofix(6.28318),ftofix(sp[0]->s_sr));
102 post("%f",fixtof(x->x_ctl->c_isr));
103 dsp_add(sigvcf_perform, 6,
104 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
105 x->x_ctl, sp[0]->s_n);
106
107}
108
109void vcf_tilde_setup(void)
110{
111 sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
112 sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
113 CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
114 class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
115 class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
116 gensym("ft1"), A_FLOAT, 0);
117 class_sethelpsymbol(sigvcf_class, gensym("lop~-help.pd"));
118}
119
120#include <m_pd.h>
121#include <m_fixed.h>
122#include "cos_table.h"
123
124/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
125/* GG: complex resonator with signal frequency control
126 this time using the bigger cos_table without interpolation
127 really have to switch to a separate fixpoint format sometime
128*/
129
130typedef struct vcfctl
131{
132 t_sample c_re;
133 t_sample c_im;
134 t_sample c_q;
135 t_sample c_isr;
136} t_vcfctl;
137
138typedef struct sigvcf
139{
140 t_object x_obj;
141 t_vcfctl x_cspace;
142 t_vcfctl *x_ctl;
143 float x_f;
144} t_sigvcf;
145
146t_class *sigvcf_class;
147
148static void *sigvcf_new(t_floatarg q)
149{
150 t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
151 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
152 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
153 outlet_new(&x->x_obj, gensym("signal"));
154 outlet_new(&x->x_obj, gensym("signal"));
155 x->x_ctl = &x->x_cspace;
156 x->x_cspace.c_re = 0;
157 x->x_cspace.c_im = 0;
158 x->x_cspace.c_q = ftofix(q);
159 x->x_cspace.c_isr = 0;
160 x->x_f = 0;
161 return (x);
162}
163
164static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
165{
166 x->x_ctl->c_q = (f > 0 ? ftofix(f) : 0);
167}
168
169static t_int *sigvcf_perform(t_int *w)
170{
171 t_sample *in1 = (t_sample *)(w[1]);
172 t_sample *in2 = (t_sample *)(w[2]);
173 t_sample *out1 = (t_sample *)(w[3]);
174 t_sample *out2 = (t_sample *)(w[4]);
175 t_vcfctl *c = (t_vcfctl *)(w[5]);
176 int n = (t_int)(w[6]);
177 int i;
178 t_sample re = c->c_re, re2;
179 t_sample im = c->c_im;
180 t_sample q = c->c_q;
181 t_sample qinv = (q > 0 ? idiv(ftofix(1.0),q) : 0);
182 t_sample ampcorrect = ftofix(2.0f) - idiv(ftofix(2.0f) , (q + ftofix(2.0f)));
183 t_sample isr = c->c_isr;
184 t_sample coefr, coefi;
185 t_sample *tab = cos_table;
186 t_sample oneminusr,cfindx,cf,r;
187
188 for (i = 0; i < n; i++)
189 {
190 cf = mult(*in2++,isr);
191 if (cf < 0) cf = 0;
192 cfindx = mult(cf,ftofix(0.15915494))>>(fix1-ILOGCOSTABSIZE); /* 1/2*PI */
193 r = (qinv > 0 ? ftofix(1.01) - mult(cf,qinv) : 0);
194
195 if (r < 0) r = 0;
196 oneminusr = ftofix(1.02f) - r; /* hand adapted */
197
198 /* r*cos(cf) */
199 coefr = mult(r,tab[cfindx]);
200
201 /* r*sin(cf) */
202 cfindx-=(ICOSTABSIZE>>2);
203 cfindx += cfindx < 0 ? ICOSTABSIZE:0;
204 coefi = mult(r,tab[cfindx]);
205
206 re2 = re;
207 *out1++ = re = mult(ampcorrect,mult(oneminusr,*in1++))
208 + mult(coefr,re2) - mult(coefi, im);
209 *out2++ = im = mult(coefi,re2) + mult(coefr,im);
210 }
211 c->c_re = re;
212 c->c_im = im;
213 return (w+7);
214}
215
216static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
217{
218 /* TODO sr is hardcoded */
219 x->x_ctl->c_isr = ftofix(0.0001424758);
220// idiv(ftofix(6.28318),ftofix(sp[0]->s_sr));
221 post("%f",fixtof(x->x_ctl->c_isr));
222 dsp_add(sigvcf_perform, 6,
223 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
224 x->x_ctl, sp[0]->s_n);
225
226}
227
228void vcf_tilde_setup(void)
229{
230 sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
231 sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
232 CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
233 class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
234 class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
235 gensym("ft1"), A_FLOAT, 0);
236 class_sethelpsymbol(sigvcf_class, gensym("lop~-help.pd"));
237}
238
diff --git a/apps/plugins/pdbox/PDa/intern/vd~.c b/apps/plugins/pdbox/PDa/intern/vd~.c
new file mode 100644
index 0000000000..2c68b27e25
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/vd~.c
@@ -0,0 +1,184 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4#include "delay.h"
5
6extern int ugen_getsortno(void);
7
8#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
9static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
10
11static t_class *sigvd_class;
12
13typedef struct _sigvd
14{
15 t_object x_obj;
16 t_symbol *x_sym;
17 t_sample x_sr; /* samples per msec */
18 int x_zerodel; /* 0 or vecsize depending on read/write order */
19 float x_f;
20} t_sigvd;
21
22static void *sigvd_new(t_symbol *s)
23{
24 t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
25 if (!*s->s_name) s = gensym("vd~");
26 x->x_sym = s;
27 x->x_sr = 1;
28 x->x_zerodel = 0;
29 outlet_new(&x->x_obj, &s_signal);
30 x->x_f = 0;
31 return (x);
32}
33
34
35static t_int *sigvd_perform(t_int *w)
36{
37 t_sample *in = (t_sample *)(w[1]);
38 t_sample *out = (t_sample *)(w[2]);
39 t_delwritectl *ctl = (t_delwritectl *)(w[3]);
40 t_sigvd *x = (t_sigvd *)(w[4]);
41 int n = (int)(w[5]);
42
43 int nsamps = ctl->c_n;
44 int fn = n;
45 t_sample limit = nsamps - n - 1;
46 t_sample *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
47 t_sample zerodel = x->x_zerodel;
48 while (n--)
49 {
50 t_time delsamps = ((long long) mult((*in++),ftofix(44.1)));//- itofix(zerodel);
51 int index = fixtoi(delsamps);
52 t_sample frac;
53 // post("%d: index %d f %lld",index,findex,*in);
54
55 frac = delsamps - itofix(index);
56 index+=fn;
57 if (index < 1 ) index += nsamps ;
58 if (index > limit) index-= nsamps;
59 bp = wp - index;
60 if (bp < vp + 2) bp += nsamps;
61 *out++ = bp[-1] + mult(frac,bp[-1]-bp[0]);
62 wp++;
63 }
64 return (w+6);
65}
66
67
68
69static void sigvd_dsp(t_sigvd *x, t_signal **sp)
70{
71 t_sigdelwrite *delwriter =
72 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
73 x->x_sr = sp[0]->s_sr * 0.001;
74 if (delwriter)
75 {
76 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
77 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
78 0 : delwriter->x_vecsize);
79 dsp_add(sigvd_perform, 5,
80 sp[0]->s_vec, sp[1]->s_vec,
81 &delwriter->x_cspace, x, sp[0]->s_n);
82 }
83 else error("vd~: %s: no such delwrite~",x->x_sym->s_name);
84}
85
86void vd_tilde_setup(void)
87{
88 sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0,
89 sizeof(t_sigvd), 0, A_DEFSYM, 0);
90 class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0);
91 CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f);
92}
93#include <m_pd.h>
94#include <m_fixed.h>
95
96#include "delay.h"
97
98extern int ugen_getsortno(void);
99
100#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
101static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
102
103static t_class *sigvd_class;
104
105typedef struct _sigvd
106{
107 t_object x_obj;
108 t_symbol *x_sym;
109 t_sample x_sr; /* samples per msec */
110 int x_zerodel; /* 0 or vecsize depending on read/write order */
111 float x_f;
112} t_sigvd;
113
114static void *sigvd_new(t_symbol *s)
115{
116 t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
117 if (!*s->s_name) s = gensym("vd~");
118 x->x_sym = s;
119 x->x_sr = 1;
120 x->x_zerodel = 0;
121 outlet_new(&x->x_obj, &s_signal);
122 x->x_f = 0;
123 return (x);
124}
125
126
127static t_int *sigvd_perform(t_int *w)
128{
129 t_sample *in = (t_sample *)(w[1]);
130 t_sample *out = (t_sample *)(w[2]);
131 t_delwritectl *ctl = (t_delwritectl *)(w[3]);
132 t_sigvd *x = (t_sigvd *)(w[4]);
133 int n = (int)(w[5]);
134
135 int nsamps = ctl->c_n;
136 int fn = n;
137 t_sample limit = nsamps - n - 1;
138 t_sample *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
139 t_sample zerodel = x->x_zerodel;
140 while (n--)
141 {
142 t_time delsamps = ((long long) mult((*in++),ftofix(44.1)));//- itofix(zerodel);
143 int index = fixtoi(delsamps);
144 t_sample frac;
145 // post("%d: index %d f %lld",index,findex,*in);
146
147 frac = delsamps - itofix(index);
148 index+=fn;
149 if (index < 1 ) index += nsamps ;
150 if (index > limit) index-= nsamps;
151 bp = wp - index;
152 if (bp < vp + 2) bp += nsamps;
153 *out++ = bp[-1] + mult(frac,bp[-1]-bp[0]);
154 wp++;
155 }
156 return (w+6);
157}
158
159
160
161static void sigvd_dsp(t_sigvd *x, t_signal **sp)
162{
163 t_sigdelwrite *delwriter =
164 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
165 x->x_sr = sp[0]->s_sr * 0.001;
166 if (delwriter)
167 {
168 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
169 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
170 0 : delwriter->x_vecsize);
171 dsp_add(sigvd_perform, 5,
172 sp[0]->s_vec, sp[1]->s_vec,
173 &delwriter->x_cspace, x, sp[0]->s_n);
174 }
175 else error("vd~: %s: no such delwrite~",x->x_sym->s_name);
176}
177
178void vd_tilde_setup(void)
179{
180 sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0,
181 sizeof(t_sigvd), 0, A_DEFSYM, 0);
182 class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0);
183 CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f);
184}
diff --git a/apps/plugins/pdbox/PDa/intern/vline~.c b/apps/plugins/pdbox/PDa/intern/vline~.c
new file mode 100644
index 0000000000..74edb83bc6
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/vline~.c
@@ -0,0 +1,368 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4
5
6static t_class *vline_tilde_class;
7
8typedef struct _vseg
9{
10 t_time s_targettime;
11 t_time s_starttime;
12 t_sample s_target;
13 struct _vseg *s_next;
14} t_vseg;
15
16typedef struct _vline
17{
18 t_object x_obj;
19 t_sample x_value;
20 t_sample x_inc;
21 t_time x_referencetime;
22 t_time x_samppermsec;
23 t_time x_msecpersamp;
24 t_time x_targettime;
25 t_sample x_target;
26 float x_inlet1;
27 float x_inlet2;
28 t_vseg *x_list;
29} t_vline;
30
31static t_int *vline_tilde_perform(t_int *w)
32{
33 t_vline *x = (t_vline *)(w[1]);
34 t_sample *out = (t_sample *)(w[2]);
35 int n = (int)(w[3]), i;
36 t_sample f = x->x_value;
37 t_sample inc = x->x_inc;
38 t_time msecpersamp = x->x_msecpersamp;
39 t_time samppermsec = x->x_samppermsec;
40 t_time timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
41 t_vseg *s = x->x_list;
42 for (i = 0; i < n; i++)
43 {
44 t_time timenext = timenow + msecpersamp;
45 checknext:
46 if (s)
47 {
48 /* has starttime elapsed? If so update value and increment */
49 if (s->s_starttime < timenext)
50 {
51 if (x->x_targettime <= timenext)
52 f = x->x_target, inc = 0;
53 /* if zero-length segment bash output value */
54 if (s->s_targettime <= s->s_starttime)
55 {
56 f = s->s_target;
57 inc = 0;
58 }
59 else
60 {
61 t_time incpermsec = div((s->s_target - f),
62 (s->s_targettime - s->s_starttime));
63 f = mult(f + incpermsec,(timenext - s->s_starttime));
64 inc = mult(incpermsec,msecpersamp);
65 }
66 x->x_inc = inc;
67 x->x_target = s->s_target;
68 x->x_targettime = s->s_targettime;
69 x->x_list = s->s_next;
70 t_freebytes(s, sizeof(*s));
71 s = x->x_list;
72 goto checknext;
73 }
74 }
75 if (x->x_targettime <= timenext)
76 f = x->x_target, inc = 0;
77 *out++ = f;
78 f = f + inc;
79 timenow = timenext;
80 }
81 x->x_value = f;
82 return (w+4);
83}
84
85static void vline_tilde_stop(t_vline *x)
86{
87 t_vseg *s1, *s2;
88 for (s1 = x->x_list; s1; s1 = s2)
89 s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
90 x->x_list = 0;
91 x->x_inc = 0;
92 x->x_inlet1 = x->x_inlet2 = 0;
93}
94
95static void vline_tilde_float(t_vline *x, t_float f)
96{
97 t_time timenow = clock_gettimesince(x->x_referencetime);
98 t_sample inlet1 = (x->x_inlet1 < 0 ? 0 : (t_sample)x->x_inlet1);
99 t_sample inlet2 = (t_sample) x->x_inlet2;
100 t_time starttime = timenow + inlet2;
101 t_vseg *s1, *s2, *deletefrom = 0,
102 *snew = (t_vseg *)t_getbytes(sizeof(*snew));
103 if (PD_BADFLOAT(f))
104 f = 0;
105
106 /* negative delay input means stop and jump immediately to new value */
107 if (inlet2 < 0)
108 {
109 vline_tilde_stop(x);
110 x->x_value = ftofix(f);
111 return;
112 }
113 /* check if we supplant the first item in the list. We supplant
114 an item by having an earlier starttime, or an equal starttime unless
115 the equal one was instantaneous and the new one isn't (in which case
116 we'll do a jump-and-slide starting at that time.) */
117 if (!x->x_list || x->x_list->s_starttime > starttime ||
118 (x->x_list->s_starttime == starttime &&
119 (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
120 {
121 deletefrom = x->x_list;
122 x->x_list = snew;
123 }
124 else
125 {
126 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
127 {
128 if (s2->s_starttime > starttime ||
129 (s2->s_starttime == starttime &&
130 (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
131 {
132 deletefrom = s2;
133 s1->s_next = snew;
134 goto didit;
135 }
136 }
137 s1->s_next = snew;
138 deletefrom = 0;
139 didit: ;
140 }
141 while (deletefrom)
142 {
143 s1 = deletefrom->s_next;
144 t_freebytes(deletefrom, sizeof(*deletefrom));
145 deletefrom = s1;
146 }
147 snew->s_next = 0;
148 snew->s_target = f;
149 snew->s_starttime = starttime;
150 snew->s_targettime = starttime + inlet1;
151 x->x_inlet1 = x->x_inlet2 = 0;
152}
153
154static void vline_tilde_dsp(t_vline *x, t_signal **sp)
155{
156 dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
157 x->x_samppermsec = idiv(ftofix(sp[0]->s_sr),ftofix(1000));
158 x->x_msecpersamp = idiv(ftofix(1000),ftofix(sp[0]->s_sr));
159}
160
161static void *vline_tilde_new(void)
162{
163 t_vline *x = (t_vline *)pd_new(vline_tilde_class);
164 outlet_new(&x->x_obj, gensym("signal"));
165 floatinlet_new(&x->x_obj, &x->x_inlet1);
166 floatinlet_new(&x->x_obj, &x->x_inlet2);
167 x->x_inlet1 = x->x_inlet2 = 0;
168 x->x_value = x->x_inc = 0;
169 x->x_referencetime = clock_getlogicaltime();
170 x->x_list = 0;
171 x->x_samppermsec = 0;
172 return (x);
173}
174
175void vline_tilde_setup(void)
176{
177 vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
178 (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
179 class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
180 class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
181 gensym("dsp"), 0);
182 class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
183 gensym("stop"), 0);
184}
185#include <m_pd.h>
186#include <m_fixed.h>
187
188
189
190static t_class *vline_tilde_class;
191
192typedef struct _vseg
193{
194 t_time s_targettime;
195 t_time s_starttime;
196 t_sample s_target;
197 struct _vseg *s_next;
198} t_vseg;
199
200typedef struct _vline
201{
202 t_object x_obj;
203 t_sample x_value;
204 t_sample x_inc;
205 t_time x_referencetime;
206 t_time x_samppermsec;
207 t_time x_msecpersamp;
208 t_time x_targettime;
209 t_sample x_target;
210 float x_inlet1;
211 float x_inlet2;
212 t_vseg *x_list;
213} t_vline;
214
215static t_int *vline_tilde_perform(t_int *w)
216{
217 t_vline *x = (t_vline *)(w[1]);
218 t_sample *out = (t_sample *)(w[2]);
219 int n = (int)(w[3]), i;
220 t_sample f = x->x_value;
221 t_sample inc = x->x_inc;
222 t_time msecpersamp = x->x_msecpersamp;
223 t_time samppermsec = x->x_samppermsec;
224 t_time timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
225 t_vseg *s = x->x_list;
226 for (i = 0; i < n; i++)
227 {
228 t_time timenext = timenow + msecpersamp;
229 checknext:
230 if (s)
231 {
232 /* has starttime elapsed? If so update value and increment */
233 if (s->s_starttime < timenext)
234 {
235 if (x->x_targettime <= timenext)
236 f = x->x_target, inc = 0;
237 /* if zero-length segment bash output value */
238 if (s->s_targettime <= s->s_starttime)
239 {
240 f = s->s_target;
241 inc = 0;
242 }
243 else
244 {
245 t_time incpermsec = div((s->s_target - f),
246 (s->s_targettime - s->s_starttime));
247 f = mult(f + incpermsec,(timenext - s->s_starttime));
248 inc = mult(incpermsec,msecpersamp);
249 }
250 x->x_inc = inc;
251 x->x_target = s->s_target;
252 x->x_targettime = s->s_targettime;
253 x->x_list = s->s_next;
254 t_freebytes(s, sizeof(*s));
255 s = x->x_list;
256 goto checknext;
257 }
258 }
259 if (x->x_targettime <= timenext)
260 f = x->x_target, inc = 0;
261 *out++ = f;
262 f = f + inc;
263 timenow = timenext;
264 }
265 x->x_value = f;
266 return (w+4);
267}
268
269static void vline_tilde_stop(t_vline *x)
270{
271 t_vseg *s1, *s2;
272 for (s1 = x->x_list; s1; s1 = s2)
273 s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
274 x->x_list = 0;
275 x->x_inc = 0;
276 x->x_inlet1 = x->x_inlet2 = 0;
277}
278
279static void vline_tilde_float(t_vline *x, t_float f)
280{
281 t_time timenow = clock_gettimesince(x->x_referencetime);
282 t_sample inlet1 = (x->x_inlet1 < 0 ? 0 : (t_sample)x->x_inlet1);
283 t_sample inlet2 = (t_sample) x->x_inlet2;
284 t_time starttime = timenow + inlet2;
285 t_vseg *s1, *s2, *deletefrom = 0,
286 *snew = (t_vseg *)t_getbytes(sizeof(*snew));
287 if (PD_BADFLOAT(f))
288 f = 0;
289
290 /* negative delay input means stop and jump immediately to new value */
291 if (inlet2 < 0)
292 {
293 vline_tilde_stop(x);
294 x->x_value = ftofix(f);
295 return;
296 }
297 /* check if we supplant the first item in the list. We supplant
298 an item by having an earlier starttime, or an equal starttime unless
299 the equal one was instantaneous and the new one isn't (in which case
300 we'll do a jump-and-slide starting at that time.) */
301 if (!x->x_list || x->x_list->s_starttime > starttime ||
302 (x->x_list->s_starttime == starttime &&
303 (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
304 {
305 deletefrom = x->x_list;
306 x->x_list = snew;
307 }
308 else
309 {
310 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
311 {
312 if (s2->s_starttime > starttime ||
313 (s2->s_starttime == starttime &&
314 (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
315 {
316 deletefrom = s2;
317 s1->s_next = snew;
318 goto didit;
319 }
320 }
321 s1->s_next = snew;
322 deletefrom = 0;
323 didit: ;
324 }
325 while (deletefrom)
326 {
327 s1 = deletefrom->s_next;
328 t_freebytes(deletefrom, sizeof(*deletefrom));
329 deletefrom = s1;
330 }
331 snew->s_next = 0;
332 snew->s_target = f;
333 snew->s_starttime = starttime;
334 snew->s_targettime = starttime + inlet1;
335 x->x_inlet1 = x->x_inlet2 = 0;
336}
337
338static void vline_tilde_dsp(t_vline *x, t_signal **sp)
339{
340 dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
341 x->x_samppermsec = idiv(ftofix(sp[0]->s_sr),ftofix(1000));
342 x->x_msecpersamp = idiv(ftofix(1000),ftofix(sp[0]->s_sr));
343}
344
345static void *vline_tilde_new(void)
346{
347 t_vline *x = (t_vline *)pd_new(vline_tilde_class);
348 outlet_new(&x->x_obj, gensym("signal"));
349 floatinlet_new(&x->x_obj, &x->x_inlet1);
350 floatinlet_new(&x->x_obj, &x->x_inlet2);
351 x->x_inlet1 = x->x_inlet2 = 0;
352 x->x_value = x->x_inc = 0;
353 x->x_referencetime = clock_getlogicaltime();
354 x->x_list = 0;
355 x->x_samppermsec = 0;
356 return (x);
357}
358
359void vline_tilde_setup(void)
360{
361 vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
362 (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
363 class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
364 class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
365 gensym("dsp"), 0);
366 class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
367 gensym("stop"), 0);
368}
diff --git a/apps/plugins/pdbox/PDa/intern/vsnapshot~.c b/apps/plugins/pdbox/PDa/intern/vsnapshot~.c
new file mode 100644
index 0000000000..afa9417248
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/vsnapshot~.c
@@ -0,0 +1,176 @@
1#include <m_pd.h>
2#include <m_fixed.h>
3
4
5static t_class *vsnapshot_tilde_class;
6
7typedef struct _vsnapshot
8{
9 t_object x_obj;
10 int x_n;
11 int x_gotone;
12 t_sample *x_vec;
13 float x_f;
14 float x_sampspermsec;
15 double x_time;
16} t_vsnapshot;
17
18static void *vsnapshot_tilde_new(void)
19{
20 t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
21 outlet_new(&x->x_obj, &s_float);
22 x->x_f = 0;
23 x->x_n = 0;
24 x->x_vec = 0;
25 x->x_gotone = 0;
26 return (x);
27}
28
29static t_int *vsnapshot_tilde_perform(t_int *w)
30{
31 t_sample *in = (t_sample *)(w[1]);
32 t_vsnapshot *x = (t_vsnapshot *)(w[2]);
33 t_sample *out = x->x_vec;
34 int n = x->x_n, i;
35 for (i = 0; i < n; i++)
36 out[i] = in[i];
37 x->x_time = clock_getlogicaltime();
38 x->x_gotone = 1;
39 return (w+3);
40}
41
42static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
43{
44 int n = sp[0]->s_n;
45 if (n != x->x_n)
46 {
47 if (x->x_vec)
48 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
49 x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
50 x->x_gotone = 0;
51 x->x_n = n;
52 }
53 x->x_sampspermsec = sp[0]->s_sr / 1000;
54 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
55}
56
57static void vsnapshot_tilde_bang(t_vsnapshot *x)
58{
59 float val;
60 if (x->x_gotone)
61 {
62 int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
63 if (indx < 0)
64 indx = 0;
65 else if (indx >= x->x_n)
66 indx = x->x_n - 1;
67 val = x->x_vec[indx];
68 }
69 else val = 0;
70 outlet_float(x->x_obj.ob_outlet, val);
71}
72
73static void vsnapshot_tilde_ff(t_vsnapshot *x)
74{
75 if (x->x_vec)
76 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
77}
78
79void vsnapshot_tilde_setup(void)
80{
81 vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
82 vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
83 sizeof(t_vsnapshot), 0, 0);
84 CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
85 class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
86 class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
87}
88
89#include <m_pd.h>
90#include <m_fixed.h>
91
92
93static t_class *vsnapshot_tilde_class;
94
95typedef struct _vsnapshot
96{
97 t_object x_obj;
98 int x_n;
99 int x_gotone;
100 t_sample *x_vec;
101 float x_f;
102 float x_sampspermsec;
103 double x_time;
104} t_vsnapshot;
105
106static void *vsnapshot_tilde_new(void)
107{
108 t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
109 outlet_new(&x->x_obj, &s_float);
110 x->x_f = 0;
111 x->x_n = 0;
112 x->x_vec = 0;
113 x->x_gotone = 0;
114 return (x);
115}
116
117static t_int *vsnapshot_tilde_perform(t_int *w)
118{
119 t_sample *in = (t_sample *)(w[1]);
120 t_vsnapshot *x = (t_vsnapshot *)(w[2]);
121 t_sample *out = x->x_vec;
122 int n = x->x_n, i;
123 for (i = 0; i < n; i++)
124 out[i] = in[i];
125 x->x_time = clock_getlogicaltime();
126 x->x_gotone = 1;
127 return (w+3);
128}
129
130static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
131{
132 int n = sp[0]->s_n;
133 if (n != x->x_n)
134 {
135 if (x->x_vec)
136 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
137 x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
138 x->x_gotone = 0;
139 x->x_n = n;
140 }
141 x->x_sampspermsec = sp[0]->s_sr / 1000;
142 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
143}
144
145static void vsnapshot_tilde_bang(t_vsnapshot *x)
146{
147 float val;
148 if (x->x_gotone)
149 {
150 int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
151 if (indx < 0)
152 indx = 0;
153 else if (indx >= x->x_n)
154 indx = x->x_n - 1;
155 val = x->x_vec[indx];
156 }
157 else val = 0;
158 outlet_float(x->x_obj.ob_outlet, val);
159}
160
161static void vsnapshot_tilde_ff(t_vsnapshot *x)
162{
163 if (x->x_vec)
164 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
165}
166
167void vsnapshot_tilde_setup(void)
168{
169 vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
170 vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
171 sizeof(t_vsnapshot), 0, 0);
172 CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
173 class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
174 class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
175}
176
diff --git a/apps/plugins/pdbox/PDa/intern/wrap~.c b/apps/plugins/pdbox/PDa/intern/wrap~.c
new file mode 100644
index 0000000000..dda79f2fcd
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/intern/wrap~.c
@@ -0,0 +1,104 @@
1
2#include <m_pd.h>
3#include <m_fixed.h>
4
5typedef struct wrap
6{
7 t_object x_obj;
8 float x_f;
9} t_sigwrap;
10
11t_class *sigwrap_class;
12
13static void *sigwrap_new(void)
14{
15 t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
16 outlet_new(&x->x_obj, gensym("signal"));
17 x->x_f = 0;
18 return (x);
19}
20
21static t_int *sigwrap_perform(t_int *w)
22{
23 t_sample *in = *(t_sample **)(w+1), *out = *(t_sample **)(w+2);
24 t_int n = *(t_int *)(w+3);
25 while (n--)
26 {
27 t_sample f = *in++;
28
29#ifndef FIXEDPOINT
30 int k = f;
31 if (f > 0) *out++ = f-k;
32 else *out++ = f - (k-1);
33#else
34 int k = ftofix(1.) - 1;
35 *out = f&k;
36#endif
37 }
38 return (w + 4);
39}
40
41static void sigwrap_dsp(t_sigwrap *x, t_signal **sp)
42{
43 dsp_add(sigwrap_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
44}
45
46void wrap_tilde_setup(void)
47{
48 sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0,
49 sizeof(t_sigwrap), 0, 0);
50 CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f);
51 class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, gensym("dsp"), 0);
52}
53
54#include <m_pd.h>
55#include <m_fixed.h>
56
57typedef struct wrap
58{
59 t_object x_obj;
60 float x_f;
61} t_sigwrap;
62
63t_class *sigwrap_class;
64
65static void *sigwrap_new(void)
66{
67 t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
68 outlet_new(&x->x_obj, gensym("signal"));
69 x->x_f = 0;
70 return (x);
71}
72
73static t_int *sigwrap_perform(t_int *w)
74{
75 t_sample *in = *(t_sample **)(w+1), *out = *(t_sample **)(w+2);
76 t_int n = *(t_int *)(w+3);
77 while (n--)
78 {
79 t_sample f = *in++;
80
81#ifndef FIXEDPOINT
82 int k = f;
83 if (f > 0) *out++ = f-k;
84 else *out++ = f - (k-1);
85#else
86 int k = ftofix(1.) - 1;
87 *out = f&k;
88#endif
89 }
90 return (w + 4);
91}
92
93static void sigwrap_dsp(t_sigwrap *x, t_signal **sp)
94{
95 dsp_add(sigwrap_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
96}
97
98void wrap_tilde_setup(void)
99{
100 sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0,
101 sizeof(t_sigwrap), 0, 0);
102 CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f);
103 class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, gensym("dsp"), 0);
104}
diff --git a/apps/plugins/pdbox/PDa/src/build.ipod b/apps/plugins/pdbox/PDa/src/build.ipod
new file mode 100644
index 0000000000..bb78632b2d
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/build.ipod
@@ -0,0 +1,10 @@
1
2# The compiler for iPod has a bug with -O6, thats why we try to compile twice
3
4make CFLAGS="-O6 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi " -k ipod
5make CFLAGS="-O2 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi" ipod
6
7# The compiler for iPod has a bug with -O6, thats why we try to compile twice
8
9make CFLAGS="-O6 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi " -k ipod
10make CFLAGS="-O2 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi" ipod
diff --git a/apps/plugins/pdbox/PDa/src/d_arithmetic.c b/apps/plugins/pdbox/PDa/src/d_arithmetic.c
new file mode 100644
index 0000000000..72404ba50d
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_arithmetic.c
@@ -0,0 +1,1684 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* arithmetic binops (+, -, *, /).
6If no creation argument is given, there are two signal inlets for vector/vector
7operation; otherwise it's vector/scalar and the second inlet takes a float
8to reset the value.
9*/
10
11#include "m_pd.h"
12
13/* ----------------------------- plus ----------------------------- */
14static t_class *plus_class, *scalarplus_class;
15
16typedef struct _plus
17{
18 t_object x_obj;
19 float x_f;
20} t_plus;
21
22typedef struct _scalarplus
23{
24 t_object x_obj;
25 float x_f;
26 t_float x_g; /* inlet value */
27} t_scalarplus;
28
29static void *plus_new(t_symbol *s, int argc, t_atom *argv)
30{
31 if (argc > 1) post("+~: extra arguments ignored");
32 if (argc)
33 {
34 t_scalarplus *x = (t_scalarplus *)pd_new(scalarplus_class);
35 floatinlet_new(&x->x_obj, &x->x_g);
36 x->x_g = atom_getfloatarg(0, argc, argv);
37 outlet_new(&x->x_obj, &s_signal);
38 x->x_f = 0;
39 return (x);
40 }
41 else
42 {
43 t_plus *x = (t_plus *)pd_new(plus_class);
44 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
45 outlet_new(&x->x_obj, &s_signal);
46 x->x_f = 0;
47 return (x);
48 }
49}
50
51t_int *plus_perform(t_int *w)
52{
53 t_sample *in1 = (t_sample *)(w[1]);
54 t_sample *in2 = (t_sample *)(w[2]);
55 t_sample *out = (t_sample *)(w[3]);
56 int n = (int)(w[4]);
57 while (n--) *out++ = *in1++ + *in2++;
58 return (w+5);
59}
60
61t_int *plus_perf8(t_int *w)
62{
63 t_sample *in1 = (t_sample *)(w[1]);
64 t_sample *in2 = (t_sample *)(w[2]);
65 t_sample *out = (t_sample *)(w[3]);
66 int n = (int)(w[4]);
67 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
68 {
69 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
70 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
71
72 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
73 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
74
75 out[0] = f0 + g0; out[1] = f1 + g1; out[2] = f2 + g2; out[3] = f3 + g3;
76 out[4] = f4 + g4; out[5] = f5 + g5; out[6] = f6 + g6; out[7] = f7 + g7;
77 }
78 return (w+5);
79}
80
81t_int *scalarplus_perform(t_int *w)
82{
83 t_sample *in = (t_sample *)(w[1]);
84 t_sample f = ftofix(*(t_float *)(w[2]));
85 t_sample *out = (t_sample *)(w[3]);
86 int n = (int)(w[4]);
87 while (n--) *out++ = *in++ + f;
88 return (w+5);
89}
90
91t_int *scalarplus_perf8(t_int *w)
92{
93 t_sample *in = (t_sample *)(w[1]);
94 t_sample g = ftofix(*(t_float *)(w[2]));
95 t_sample *out = (t_sample *)(w[3]);
96 int n = (int)(w[4]);
97 for (; n; n -= 8, in += 8, out += 8)
98 {
99 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
100 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
101
102 out[0] = f0 + g; out[1] = f1 + g; out[2] = f2 + g; out[3] = f3 + g;
103 out[4] = f4 + g; out[5] = f5 + g; out[6] = f6 + g; out[7] = f7 + g;
104 }
105 return (w+5);
106}
107
108void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n)
109{
110 if (n&7)
111 dsp_add(plus_perform, 4, in1, in2, out, n);
112 else
113 dsp_add(plus_perf8, 4, in1, in2, out, n);
114}
115
116static void plus_dsp(t_plus *x, t_signal **sp)
117{
118 dsp_add_plus(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
119}
120
121static void scalarplus_dsp(t_scalarplus *x, t_signal **sp)
122{
123 if (sp[0]->s_n&7)
124 dsp_add(scalarplus_perform, 4, sp[0]->s_vec, &x->x_g,
125 sp[1]->s_vec, sp[0]->s_n);
126 else
127 dsp_add(scalarplus_perf8, 4, sp[0]->s_vec, &x->x_g,
128 sp[1]->s_vec, sp[0]->s_n);
129}
130
131static void plus_setup(void)
132{
133 plus_class = class_new(gensym("+~"), (t_newmethod)plus_new, 0,
134 sizeof(t_plus), 0, A_GIMME, 0);
135 class_addmethod(plus_class, (t_method)plus_dsp, gensym("dsp"), 0);
136 CLASS_MAINSIGNALIN(plus_class, t_plus, x_f);
137 class_sethelpsymbol(plus_class, gensym("sigbinops"));
138 scalarplus_class = class_new(gensym("+~"), 0, 0,
139 sizeof(t_scalarplus), 0, 0);
140 CLASS_MAINSIGNALIN(scalarplus_class, t_scalarplus, x_f);
141 class_addmethod(scalarplus_class, (t_method)scalarplus_dsp, gensym("dsp"),
142 0);
143 class_sethelpsymbol(scalarplus_class, gensym("sigbinops"));
144}
145
146/* ----------------------------- minus ----------------------------- */
147static t_class *minus_class, *scalarminus_class;
148
149typedef struct _minus
150{
151 t_object x_obj;
152 float x_f;
153} t_minus;
154
155typedef struct _scalarminus
156{
157 t_object x_obj;
158 float x_f;
159 t_float x_g;
160} t_scalarminus;
161
162static void *minus_new(t_symbol *s, int argc, t_atom *argv)
163{
164 if (argc > 1) post("-~: extra arguments ignored");
165 if (argc)
166 {
167 t_scalarminus *x = (t_scalarminus *)pd_new(scalarminus_class);
168 floatinlet_new(&x->x_obj, &x->x_g);
169 x->x_g = atom_getfloatarg(0, argc, argv);
170 outlet_new(&x->x_obj, &s_signal);
171 x->x_f = 0;
172 return (x);
173 }
174 else
175 {
176 t_minus *x = (t_minus *)pd_new(minus_class);
177 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
178 outlet_new(&x->x_obj, &s_signal);
179 x->x_f = 0;
180 return (x);
181 }
182}
183
184t_int *minus_perform(t_int *w)
185{
186 t_sample *in1 = (t_sample *)(w[1]);
187 t_sample *in2 = (t_sample *)(w[2]);
188 t_sample *out = (t_sample *)(w[3]);
189 int n = (int)(w[4]);
190 while (n--) *out++ = *in1++ - *in2++;
191 return (w+5);
192}
193
194t_int *minus_perf8(t_int *w)
195{
196 t_sample *in1 = (t_sample *)(w[1]);
197 t_sample *in2 = (t_sample *)(w[2]);
198 t_sample *out = (t_sample *)(w[3]);
199 int n = (int)(w[4]);
200 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
201 {
202 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
203 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
204
205 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
206 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
207
208 out[0] = f0 - g0; out[1] = f1 - g1; out[2] = f2 - g2; out[3] = f3 - g3;
209 out[4] = f4 - g4; out[5] = f5 - g5; out[6] = f6 - g6; out[7] = f7 - g7;
210 }
211 return (w+5);
212}
213
214t_int *scalarminus_perform(t_int *w)
215{
216 t_sample *in = (t_sample *)(w[1]);
217 t_sample f = ftofix(*(t_float *)(w[2]));
218 t_sample *out = (t_sample *)(w[3]);
219 int n = (int)(w[4]);
220 while (n--) *out++ = *in++ - f;
221 return (w+5);
222}
223
224t_int *scalarminus_perf8(t_int *w)
225{
226 t_sample *in = (t_sample *)(w[1]);
227 t_sample g = ftofix(*(t_float *)(w[2]));
228 t_sample *out = (t_sample *)(w[3]);
229 int n = (int)(w[4]);
230 for (; n; n -= 8, in += 8, out += 8)
231 {
232 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
233 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
234
235 out[0] = f0 - g; out[1] = f1 - g; out[2] = f2 - g; out[3] = f3 - g;
236 out[4] = f4 - g; out[5] = f5 - g; out[6] = f6 - g; out[7] = f7 - g;
237 }
238 return (w+5);
239}
240
241static void minus_dsp(t_minus *x, t_signal **sp)
242{
243 if (sp[0]->s_n&7)
244 dsp_add(minus_perform, 4,
245 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
246 else
247 dsp_add(minus_perf8, 4,
248 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
249}
250
251static void scalarminus_dsp(t_scalarminus *x, t_signal **sp)
252{
253 if (sp[0]->s_n&7)
254 dsp_add(scalarminus_perform, 4, sp[0]->s_vec, &x->x_g,
255 sp[1]->s_vec, sp[0]->s_n);
256 else
257 dsp_add(scalarminus_perf8, 4, sp[0]->s_vec, &x->x_g,
258 sp[1]->s_vec, sp[0]->s_n);
259}
260
261static void minus_setup(void)
262{
263 minus_class = class_new(gensym("-~"), (t_newmethod)minus_new, 0,
264 sizeof(t_minus), 0, A_GIMME, 0);
265 CLASS_MAINSIGNALIN(minus_class, t_minus, x_f);
266 class_addmethod(minus_class, (t_method)minus_dsp, gensym("dsp"), 0);
267 class_sethelpsymbol(minus_class, gensym("sigbinops"));
268 scalarminus_class = class_new(gensym("-~"), 0, 0,
269 sizeof(t_scalarminus), 0, 0);
270 CLASS_MAINSIGNALIN(scalarminus_class, t_scalarminus, x_f);
271 class_addmethod(scalarminus_class, (t_method)scalarminus_dsp, gensym("dsp"),
272 0);
273 class_sethelpsymbol(scalarminus_class, gensym("sigbinops"));
274}
275
276/* ----------------------------- times ----------------------------- */
277
278static t_class *times_class, *scalartimes_class;
279
280typedef struct _times
281{
282 t_object x_obj;
283 float x_f;
284} t_times;
285
286typedef struct _scalartimes
287{
288 t_object x_obj;
289 float x_f;
290 t_float x_g;
291} t_scalartimes;
292
293static void *times_new(t_symbol *s, int argc, t_atom *argv)
294{
295 if (argc > 1) post("*~: extra arguments ignored");
296 if (argc)
297 {
298 t_scalartimes *x = (t_scalartimes *)pd_new(scalartimes_class);
299 floatinlet_new(&x->x_obj, &x->x_g);
300 x->x_g = atom_getfloatarg(0, argc, argv);
301 outlet_new(&x->x_obj, &s_signal);
302 x->x_f = 0;
303 return (x);
304 }
305 else
306 {
307 t_times *x = (t_times *)pd_new(times_class);
308 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
309 outlet_new(&x->x_obj, &s_signal);
310 x->x_f = 0;
311 return (x);
312 }
313}
314
315t_int *times_perform(t_int *w)
316{
317 t_sample *in1 = (t_sample *)(w[1]);
318 t_sample *in2 = (t_sample *)(w[2]);
319 t_sample *out = (t_sample *)(w[3]);
320 int n = (int)(w[4]);
321 while (n--) *out++ = mult(*in1++,*in2++);
322 return (w+5);
323}
324
325t_int *times_perf8(t_int *w)
326{
327 t_sample *in1 = (t_sample *)(w[1]);
328 t_sample *in2 = (t_sample *)(w[2]);
329 t_sample *out = (t_sample *)(w[3]);
330 int n = (int)(w[4]);
331 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
332 {
333 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
334 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
335
336 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
337 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
338
339 out[0] = mult(f0,g0); out[1] = mult(f1,g1); out[2] = mult(f2,g2); out[3] = mult(f3,g3);
340 out[4] = mult(f4,g4); out[5] = mult(f5,g5); out[6] = mult(f6,g6); out[7] = mult(f7,g7);
341 }
342 return (w+5);
343}
344
345t_int *scalartimes_perform(t_int *w)
346{
347 t_sample *in = (t_sample *)(w[1]);
348 t_sample f = ftofix(*(t_float *)(w[2]));
349 t_sample *out = (t_sample *)(w[3]);
350 int n = (int)(w[4]);
351 while (n--) *out++ = mult(*in++,f);
352 return (w+5);
353}
354
355t_int *scalartimes_perf8(t_int *w)
356{
357 t_sample *in = (t_sample *)(w[1]);
358 t_sample g = ftofix(*(t_float *)(w[2]));
359 t_sample *out = (t_sample *)(w[3]);
360 int n = (int)(w[4]);
361 for (; n; n -= 8, in += 8, out += 8)
362 {
363 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
364 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
365
366 out[0] = mult(f0,g); out[1] = mult(f1,g); out[2] = mult(f2,g); out[3] = mult(f3,g);
367 out[4] = mult(f4,g); out[5] = mult(f5,g); out[6] = mult(f6,g); out[7] = mult(f7,g);
368 }
369 return (w+5);
370}
371
372static void times_dsp(t_times *x, t_signal **sp)
373{
374 if (sp[0]->s_n&7)
375 dsp_add(times_perform, 4,
376 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
377 else
378 dsp_add(times_perf8, 4,
379 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
380}
381
382static void scalartimes_dsp(t_scalartimes *x, t_signal **sp)
383{
384 if (sp[0]->s_n&7)
385 dsp_add(scalartimes_perform, 4, sp[0]->s_vec, &x->x_g,
386 sp[1]->s_vec, sp[0]->s_n);
387 else
388 dsp_add(scalartimes_perf8, 4, sp[0]->s_vec, &x->x_g,
389 sp[1]->s_vec, sp[0]->s_n);
390}
391
392static void times_setup(void)
393{
394 times_class = class_new(gensym("*~"), (t_newmethod)times_new, 0,
395 sizeof(t_times), 0, A_GIMME, 0);
396 CLASS_MAINSIGNALIN(times_class, t_times, x_f);
397 class_addmethod(times_class, (t_method)times_dsp, gensym("dsp"), 0);
398 class_sethelpsymbol(times_class, gensym("sigbinops"));
399 scalartimes_class = class_new(gensym("*~"), 0, 0,
400 sizeof(t_scalartimes), 0, 0);
401 CLASS_MAINSIGNALIN(scalartimes_class, t_scalartimes, x_f);
402 class_addmethod(scalartimes_class, (t_method)scalartimes_dsp, gensym("dsp"),
403 0);
404 class_sethelpsymbol(scalartimes_class, gensym("sigbinops"));
405}
406
407/* ----------------------------- over ----------------------------- */
408static t_class *over_class, *scalarover_class;
409
410typedef struct _over
411{
412 t_object x_obj;
413 float x_f;
414} t_over;
415
416typedef struct _scalarover
417{
418 t_object x_obj;
419 float x_f;
420 t_float x_g;
421} t_scalarover;
422
423static void *over_new(t_symbol *s, int argc, t_atom *argv)
424{
425 if (argc > 1) post("/~: extra arguments ignored");
426 if (argc)
427 {
428 t_scalarover *x = (t_scalarover *)pd_new(scalarover_class);
429 floatinlet_new(&x->x_obj, &x->x_g);
430 x->x_g = atom_getfloatarg(0, argc, argv);
431 outlet_new(&x->x_obj, &s_signal);
432 x->x_f = 0;
433 return (x);
434 }
435 else
436 {
437 t_over *x = (t_over *)pd_new(over_class);
438 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
439 outlet_new(&x->x_obj, &s_signal);
440 x->x_f = 0;
441 return (x);
442 }
443}
444
445t_int *over_perform(t_int *w)
446{
447 t_sample *in1 = (t_sample *)(w[1]);
448 t_sample *in2 = (t_sample *)(w[2]);
449 t_sample *out = (t_sample *)(w[3]);
450 int n = (int)(w[4]);
451 while (n--)
452 {
453 float g = *in2++;
454 *out++ = (g ? *in1++ / g : 0);
455 }
456 return (w+5);
457}
458
459t_int *over_perf8(t_int *w)
460{
461 t_sample *in1 = (t_sample *)(w[1]);
462 t_sample *in2 = (t_sample *)(w[2]);
463 t_sample *out = (t_sample *)(w[3]);
464 int n = (int)(w[4]);
465 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
466 {
467 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
468 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
469
470 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
471 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
472
473 out[0] = (g0? idiv(f0,g0) : 0);
474 out[1] = (g1? idiv(f1,g1) : 0);
475 out[2] = (g2? idiv(f2,g2) : 0);
476 out[3] = (g3? idiv(f3,g3) : 0);
477 out[4] = (g4? idiv(f4,g4) : 0);
478 out[5] = (g5? idiv(f5,g5) : 0);
479 out[6] = (g6? idiv(f6,g6) : 0);
480 out[7] = (g7? idiv(f7,g7) : 0);
481 }
482 return (w+5);
483}
484
485t_int *scalarover_perform(t_int *w)
486{
487 t_sample *in = (t_sample *)(w[1]);
488 t_sample f = idiv(ftofix(1.),ftofix(*(t_float *)(w[2])));
489 t_sample *out = (t_sample *)(w[3]);
490 int n = (int)(w[4]);
491 while (n--) *out++ = mult(*in++,f);
492 return (w+5);
493}
494
495t_int *scalarover_perf8(t_int *w)
496{
497 t_sample *in = (t_sample *)(w[1]);
498 t_sample g = ftofix(*(t_float *)(w[2]));
499 t_sample *out = (t_sample *)(w[3]);
500 int n = (int)(w[4]);
501 if (g) g = idiv(ftofix(1.f),g);
502 for (; n; n -= 8, in += 8, out += 8)
503 {
504 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
505 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
506
507 out[0] = mult(f0,g); out[1] = mult(f1,g); out[2] = mult(f2,g); out[3] = mult(f3,g);
508 out[4] = mult(f4,g); out[5] = mult(f5,g); out[6] = mult(f6,g); out[7] = mult(f7,g);
509 }
510 return (w+5);
511}
512
513static void over_dsp(t_over *x, t_signal **sp)
514{
515 if (sp[0]->s_n&7)
516 dsp_add(over_perform, 4,
517 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
518 else
519 dsp_add(over_perf8, 4,
520 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
521}
522
523static void scalarover_dsp(t_scalarover *x, t_signal **sp)
524{
525 if (sp[0]->s_n&7)
526 dsp_add(scalarover_perform, 4, sp[0]->s_vec, &x->x_g,
527 sp[1]->s_vec, sp[0]->s_n);
528 else
529 dsp_add(scalarover_perf8, 4, sp[0]->s_vec, &x->x_g,
530 sp[1]->s_vec, sp[0]->s_n);
531}
532
533static void over_setup(void)
534{
535 over_class = class_new(gensym("/~"), (t_newmethod)over_new, 0,
536 sizeof(t_over), 0, A_GIMME, 0);
537 CLASS_MAINSIGNALIN(over_class, t_over, x_f);
538 class_addmethod(over_class, (t_method)over_dsp, gensym("dsp"), 0);
539 class_sethelpsymbol(over_class, gensym("sigbinops"));
540 scalarover_class = class_new(gensym("/~"), 0, 0,
541 sizeof(t_scalarover), 0, 0);
542 CLASS_MAINSIGNALIN(scalarover_class, t_scalarover, x_f);
543 class_addmethod(scalarover_class, (t_method)scalarover_dsp, gensym("dsp"),
544 0);
545 class_sethelpsymbol(scalarover_class, gensym("sigbinops"));
546}
547
548/* ----------------------------- max ----------------------------- */
549static t_class *max_class, *scalarmax_class;
550
551typedef struct _max
552{
553 t_object x_obj;
554 float x_f;
555} t_max;
556
557typedef struct _scalarmax
558{
559 t_object x_obj;
560 float x_f;
561 t_float x_g;
562} t_scalarmax;
563
564static void *max_new(t_symbol *s, int argc, t_atom *argv)
565{
566 if (argc > 1) post("max~: extra arguments ignored");
567 if (argc)
568 {
569 t_scalarmax *x = (t_scalarmax *)pd_new(scalarmax_class);
570 floatinlet_new(&x->x_obj, &x->x_g);
571 x->x_g = atom_getfloatarg(0, argc, argv);
572 outlet_new(&x->x_obj, &s_signal);
573 x->x_f = 0;
574 return (x);
575 }
576 else
577 {
578 t_max *x = (t_max *)pd_new(max_class);
579 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
580 outlet_new(&x->x_obj, &s_signal);
581 x->x_f = 0;
582 return (x);
583 }
584}
585
586t_int *max_perform(t_int *w)
587{
588 t_sample *in1 = (t_sample *)(w[1]);
589 t_sample *in2 = (t_sample *)(w[2]);
590 t_sample *out = (t_sample *)(w[3]);
591 int n = (int)(w[4]);
592 while (n--)
593 {
594 t_sample f = *in1++, g = *in2++;
595 *out++ = (f > g ? f : g);
596 }
597 return (w+5);
598}
599
600t_int *max_perf8(t_int *w)
601{
602 t_sample *in1 = (t_sample *)(w[1]);
603 t_sample *in2 = (t_sample *)(w[2]);
604 t_sample *out = (t_sample *)(w[3]);
605 int n = (int)(w[4]);
606 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
607 {
608 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
609 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
610
611 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
612 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
613
614 out[0] = (f0 > g0 ? f0 : g0); out[1] = (f1 > g1 ? f1 : g1);
615 out[2] = (f2 > g2 ? f2 : g2); out[3] = (f3 > g3 ? f3 : g3);
616 out[4] = (f4 > g4 ? f4 : g4); out[5] = (f5 > g5 ? f5 : g5);
617 out[6] = (f6 > g6 ? f6 : g6); out[7] = (f7 > g7 ? f7 : g7);
618 }
619 return (w+5);
620}
621
622t_int *scalarmax_perform(t_int *w)
623{
624 t_sample *in = (t_sample *)(w[1]);
625 t_sample f = ftofix(*(t_float *)(w[2]));
626 t_sample *out = (t_sample *)(w[3]);
627 int n = (int)(w[4]);
628 while (n--)
629 {
630 t_sample g = *in++;
631 *out++ = (f > g ? f : g);
632 }
633 return (w+5);
634}
635
636t_int *scalarmax_perf8(t_int *w)
637{
638 t_sample *in = (t_sample *)(w[1]);
639 t_sample g = ftofix(*(t_float *)(w[2]));
640 t_sample *out = (t_sample *)(w[3]);
641 int n = (int)(w[4]);
642 for (; n; n -= 8, in += 8, out += 8)
643 {
644 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
645 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
646
647 out[0] = (f0 > g ? f0 : g); out[1] = (f1 > g ? f1 : g);
648 out[2] = (f2 > g ? f2 : g); out[3] = (f3 > g ? f3 : g);
649 out[4] = (f4 > g ? f4 : g); out[5] = (f5 > g ? f5 : g);
650 out[6] = (f6 > g ? f6 : g); out[7] = (f7 > g ? f7 : g);
651 }
652 return (w+5);
653}
654
655static void max_dsp(t_max *x, t_signal **sp)
656{
657 if (sp[0]->s_n&7)
658 dsp_add(max_perform, 4,
659 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
660 else
661 dsp_add(max_perf8, 4,
662 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
663}
664
665static void scalarmax_dsp(t_scalarmax *x, t_signal **sp)
666{
667 if (sp[0]->s_n&7)
668 dsp_add(scalarmax_perform, 4, sp[0]->s_vec, &x->x_g,
669 sp[1]->s_vec, sp[0]->s_n);
670 else
671 dsp_add(scalarmax_perf8, 4, sp[0]->s_vec, &x->x_g,
672 sp[1]->s_vec, sp[0]->s_n);
673}
674
675static void max_setup(void)
676{
677 max_class = class_new(gensym("max~"), (t_newmethod)max_new, 0,
678 sizeof(t_max), 0, A_GIMME, 0);
679 CLASS_MAINSIGNALIN(max_class, t_max, x_f);
680 class_addmethod(max_class, (t_method)max_dsp, gensym("dsp"), 0);
681 class_sethelpsymbol(max_class, gensym("sigbinops"));
682 scalarmax_class = class_new(gensym("max~"), 0, 0,
683 sizeof(t_scalarmax), 0, 0);
684 CLASS_MAINSIGNALIN(scalarmax_class, t_scalarmax, x_f);
685 class_addmethod(scalarmax_class, (t_method)scalarmax_dsp, gensym("dsp"),
686 0);
687 class_sethelpsymbol(scalarmax_class, gensym("sigbinops"));
688}
689
690/* ----------------------------- min ----------------------------- */
691static t_class *min_class, *scalarmin_class;
692
693typedef struct _min
694{
695 t_object x_obj;
696 float x_f;
697} t_min;
698
699typedef struct _scalarmin
700{
701 t_object x_obj;
702 t_float x_g;
703 float x_f;
704} t_scalarmin;
705
706static void *min_new(t_symbol *s, int argc, t_atom *argv)
707{
708 if (argc > 1) post("min~: extra arguments ignored");
709 if (argc)
710 {
711 t_scalarmin *x = (t_scalarmin *)pd_new(scalarmin_class);
712 floatinlet_new(&x->x_obj, &x->x_g);
713 x->x_g = atom_getfloatarg(0, argc, argv);
714 outlet_new(&x->x_obj, &s_signal);
715 x->x_f = 0;
716 return (x);
717 }
718 else
719 {
720 t_min *x = (t_min *)pd_new(min_class);
721 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
722 outlet_new(&x->x_obj, &s_signal);
723 x->x_f = 0;
724 return (x);
725 }
726}
727
728t_int *min_perform(t_int *w)
729{
730 t_sample *in1 = (t_sample *)(w[1]);
731 t_sample *in2 = (t_sample *)(w[2]);
732 t_sample *out = (t_sample *)(w[3]);
733 int n = (int)(w[4]);
734 while (n--)
735 {
736 t_sample f = *in1++, g = *in2++;
737 *out++ = (f < g ? f : g);
738 }
739 return (w+5);
740}
741
742t_int *min_perf8(t_int *w)
743{
744 t_sample *in1 = (t_sample *)(w[1]);
745 t_sample *in2 = (t_sample *)(w[2]);
746 t_sample *out = (t_sample *)(w[3]);
747 int n = (int)(w[4]);
748 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
749 {
750 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
751 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
752
753 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
754 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
755
756 out[0] = (f0 < g0 ? f0 : g0); out[1] = (f1 < g1 ? f1 : g1);
757 out[2] = (f2 < g2 ? f2 : g2); out[3] = (f3 < g3 ? f3 : g3);
758 out[4] = (f4 < g4 ? f4 : g4); out[5] = (f5 < g5 ? f5 : g5);
759 out[6] = (f6 < g6 ? f6 : g6); out[7] = (f7 < g7 ? f7 : g7);
760 }
761 return (w+5);
762}
763
764t_int *scalarmin_perform(t_int *w)
765{
766 t_sample *in = (t_sample *)(w[1]);
767 t_sample f = ftofix(*(t_float *)(w[2]));
768 t_sample *out = (t_sample *)(w[3]);
769 int n = (int)(w[4]);
770 while (n--)
771 {
772 t_sample g = *in++;
773 *out++ = (f < g ? f : g);
774 }
775 return (w+5);
776}
777
778t_int *scalarmin_perf8(t_int *w)
779{
780 t_sample *in = (t_sample *)(w[1]);
781 t_sample g = ftofix(*(t_float *)(w[2]));
782 t_sample *out = (t_sample *)(w[3]);
783 int n = (int)(w[4]);
784 for (; n; n -= 8, in += 8, out += 8)
785 {
786 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
787 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
788
789 out[0] = (f0 < g ? f0 : g); out[1] = (f1 < g ? f1 : g);
790 out[2] = (f2 < g ? f2 : g); out[3] = (f3 < g ? f3 : g);
791 out[4] = (f4 < g ? f4 : g); out[5] = (f5 < g ? f5 : g);
792 out[6] = (f6 < g ? f6 : g); out[7] = (f7 < g ? f7 : g);
793 }
794 return (w+5);
795}
796
797static void min_dsp(t_min *x, t_signal **sp)
798{
799 if (sp[0]->s_n&7)
800 dsp_add(min_perform, 4,
801 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
802 else
803 dsp_add(min_perf8, 4,
804 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
805}
806
807static void scalarmin_dsp(t_scalarmin *x, t_signal **sp)
808{
809 if (sp[0]->s_n&7)
810 dsp_add(scalarmin_perform, 4, sp[0]->s_vec, &x->x_g,
811 sp[1]->s_vec, sp[0]->s_n);
812 else
813 dsp_add(scalarmin_perf8, 4, sp[0]->s_vec, &x->x_g,
814 sp[1]->s_vec, sp[0]->s_n);
815}
816
817static void min_setup(void)
818{
819 min_class = class_new(gensym("min~"), (t_newmethod)min_new, 0,
820 sizeof(t_min), 0, A_GIMME, 0);
821 CLASS_MAINSIGNALIN(min_class, t_min, x_f);
822 class_addmethod(min_class, (t_method)min_dsp, gensym("dsp"), 0);
823 class_sethelpsymbol(min_class, gensym("sigbinops"));
824 scalarmin_class = class_new(gensym("min~"), 0, 0,
825 sizeof(t_scalarmin), 0, 0);
826 CLASS_MAINSIGNALIN(scalarmin_class, t_scalarmin, x_f);
827 class_addmethod(scalarmin_class, (t_method)scalarmin_dsp, gensym("dsp"),
828 0);
829 class_sethelpsymbol(scalarmin_class, gensym("sigbinops"));
830}
831
832/* ----------------------- global setup routine ---------------- */
833void d_arithmetic_setup(void)
834{
835 plus_setup();
836 minus_setup();
837 times_setup();
838 over_setup();
839 max_setup();
840 min_setup();
841}
842
843/* Copyright (c) 1997-1999 Miller Puckette.
844* For information on usage and redistribution, and for a DISCLAIMER OF ALL
845* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
846
847/* arithmetic binops (+, -, *, /).
848If no creation argument is given, there are two signal inlets for vector/vector
849operation; otherwise it's vector/scalar and the second inlet takes a float
850to reset the value.
851*/
852
853#include "m_pd.h"
854
855/* ----------------------------- plus ----------------------------- */
856static t_class *plus_class, *scalarplus_class;
857
858typedef struct _plus
859{
860 t_object x_obj;
861 float x_f;
862} t_plus;
863
864typedef struct _scalarplus
865{
866 t_object x_obj;
867 float x_f;
868 t_float x_g; /* inlet value */
869} t_scalarplus;
870
871static void *plus_new(t_symbol *s, int argc, t_atom *argv)
872{
873 if (argc > 1) post("+~: extra arguments ignored");
874 if (argc)
875 {
876 t_scalarplus *x = (t_scalarplus *)pd_new(scalarplus_class);
877 floatinlet_new(&x->x_obj, &x->x_g);
878 x->x_g = atom_getfloatarg(0, argc, argv);
879 outlet_new(&x->x_obj, &s_signal);
880 x->x_f = 0;
881 return (x);
882 }
883 else
884 {
885 t_plus *x = (t_plus *)pd_new(plus_class);
886 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
887 outlet_new(&x->x_obj, &s_signal);
888 x->x_f = 0;
889 return (x);
890 }
891}
892
893t_int *plus_perform(t_int *w)
894{
895 t_sample *in1 = (t_sample *)(w[1]);
896 t_sample *in2 = (t_sample *)(w[2]);
897 t_sample *out = (t_sample *)(w[3]);
898 int n = (int)(w[4]);
899 while (n--) *out++ = *in1++ + *in2++;
900 return (w+5);
901}
902
903t_int *plus_perf8(t_int *w)
904{
905 t_sample *in1 = (t_sample *)(w[1]);
906 t_sample *in2 = (t_sample *)(w[2]);
907 t_sample *out = (t_sample *)(w[3]);
908 int n = (int)(w[4]);
909 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
910 {
911 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
912 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
913
914 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
915 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
916
917 out[0] = f0 + g0; out[1] = f1 + g1; out[2] = f2 + g2; out[3] = f3 + g3;
918 out[4] = f4 + g4; out[5] = f5 + g5; out[6] = f6 + g6; out[7] = f7 + g7;
919 }
920 return (w+5);
921}
922
923t_int *scalarplus_perform(t_int *w)
924{
925 t_sample *in = (t_sample *)(w[1]);
926 t_sample f = ftofix(*(t_float *)(w[2]));
927 t_sample *out = (t_sample *)(w[3]);
928 int n = (int)(w[4]);
929 while (n--) *out++ = *in++ + f;
930 return (w+5);
931}
932
933t_int *scalarplus_perf8(t_int *w)
934{
935 t_sample *in = (t_sample *)(w[1]);
936 t_sample g = ftofix(*(t_float *)(w[2]));
937 t_sample *out = (t_sample *)(w[3]);
938 int n = (int)(w[4]);
939 for (; n; n -= 8, in += 8, out += 8)
940 {
941 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
942 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
943
944 out[0] = f0 + g; out[1] = f1 + g; out[2] = f2 + g; out[3] = f3 + g;
945 out[4] = f4 + g; out[5] = f5 + g; out[6] = f6 + g; out[7] = f7 + g;
946 }
947 return (w+5);
948}
949
950void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n)
951{
952 if (n&7)
953 dsp_add(plus_perform, 4, in1, in2, out, n);
954 else
955 dsp_add(plus_perf8, 4, in1, in2, out, n);
956}
957
958static void plus_dsp(t_plus *x, t_signal **sp)
959{
960 dsp_add_plus(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
961}
962
963static void scalarplus_dsp(t_scalarplus *x, t_signal **sp)
964{
965 if (sp[0]->s_n&7)
966 dsp_add(scalarplus_perform, 4, sp[0]->s_vec, &x->x_g,
967 sp[1]->s_vec, sp[0]->s_n);
968 else
969 dsp_add(scalarplus_perf8, 4, sp[0]->s_vec, &x->x_g,
970 sp[1]->s_vec, sp[0]->s_n);
971}
972
973static void plus_setup(void)
974{
975 plus_class = class_new(gensym("+~"), (t_newmethod)plus_new, 0,
976 sizeof(t_plus), 0, A_GIMME, 0);
977 class_addmethod(plus_class, (t_method)plus_dsp, gensym("dsp"), 0);
978 CLASS_MAINSIGNALIN(plus_class, t_plus, x_f);
979 class_sethelpsymbol(plus_class, gensym("sigbinops"));
980 scalarplus_class = class_new(gensym("+~"), 0, 0,
981 sizeof(t_scalarplus), 0, 0);
982 CLASS_MAINSIGNALIN(scalarplus_class, t_scalarplus, x_f);
983 class_addmethod(scalarplus_class, (t_method)scalarplus_dsp, gensym("dsp"),
984 0);
985 class_sethelpsymbol(scalarplus_class, gensym("sigbinops"));
986}
987
988/* ----------------------------- minus ----------------------------- */
989static t_class *minus_class, *scalarminus_class;
990
991typedef struct _minus
992{
993 t_object x_obj;
994 float x_f;
995} t_minus;
996
997typedef struct _scalarminus
998{
999 t_object x_obj;
1000 float x_f;
1001 t_float x_g;
1002} t_scalarminus;
1003
1004static void *minus_new(t_symbol *s, int argc, t_atom *argv)
1005{
1006 if (argc > 1) post("-~: extra arguments ignored");
1007 if (argc)
1008 {
1009 t_scalarminus *x = (t_scalarminus *)pd_new(scalarminus_class);
1010 floatinlet_new(&x->x_obj, &x->x_g);
1011 x->x_g = atom_getfloatarg(0, argc, argv);
1012 outlet_new(&x->x_obj, &s_signal);
1013 x->x_f = 0;
1014 return (x);
1015 }
1016 else
1017 {
1018 t_minus *x = (t_minus *)pd_new(minus_class);
1019 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
1020 outlet_new(&x->x_obj, &s_signal);
1021 x->x_f = 0;
1022 return (x);
1023 }
1024}
1025
1026t_int *minus_perform(t_int *w)
1027{
1028 t_sample *in1 = (t_sample *)(w[1]);
1029 t_sample *in2 = (t_sample *)(w[2]);
1030 t_sample *out = (t_sample *)(w[3]);
1031 int n = (int)(w[4]);
1032 while (n--) *out++ = *in1++ - *in2++;
1033 return (w+5);
1034}
1035
1036t_int *minus_perf8(t_int *w)
1037{
1038 t_sample *in1 = (t_sample *)(w[1]);
1039 t_sample *in2 = (t_sample *)(w[2]);
1040 t_sample *out = (t_sample *)(w[3]);
1041 int n = (int)(w[4]);
1042 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
1043 {
1044 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
1045 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
1046
1047 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
1048 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
1049
1050 out[0] = f0 - g0; out[1] = f1 - g1; out[2] = f2 - g2; out[3] = f3 - g3;
1051 out[4] = f4 - g4; out[5] = f5 - g5; out[6] = f6 - g6; out[7] = f7 - g7;
1052 }
1053 return (w+5);
1054}
1055
1056t_int *scalarminus_perform(t_int *w)
1057{
1058 t_sample *in = (t_sample *)(w[1]);
1059 t_sample f = ftofix(*(t_float *)(w[2]));
1060 t_sample *out = (t_sample *)(w[3]);
1061 int n = (int)(w[4]);
1062 while (n--) *out++ = *in++ - f;
1063 return (w+5);
1064}
1065
1066t_int *scalarminus_perf8(t_int *w)
1067{
1068 t_sample *in = (t_sample *)(w[1]);
1069 t_sample g = ftofix(*(t_float *)(w[2]));
1070 t_sample *out = (t_sample *)(w[3]);
1071 int n = (int)(w[4]);
1072 for (; n; n -= 8, in += 8, out += 8)
1073 {
1074 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
1075 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
1076
1077 out[0] = f0 - g; out[1] = f1 - g; out[2] = f2 - g; out[3] = f3 - g;
1078 out[4] = f4 - g; out[5] = f5 - g; out[6] = f6 - g; out[7] = f7 - g;
1079 }
1080 return (w+5);
1081}
1082
1083static void minus_dsp(t_minus *x, t_signal **sp)
1084{
1085 if (sp[0]->s_n&7)
1086 dsp_add(minus_perform, 4,
1087 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1088 else
1089 dsp_add(minus_perf8, 4,
1090 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1091}
1092
1093static void scalarminus_dsp(t_scalarminus *x, t_signal **sp)
1094{
1095 if (sp[0]->s_n&7)
1096 dsp_add(scalarminus_perform, 4, sp[0]->s_vec, &x->x_g,
1097 sp[1]->s_vec, sp[0]->s_n);
1098 else
1099 dsp_add(scalarminus_perf8, 4, sp[0]->s_vec, &x->x_g,
1100 sp[1]->s_vec, sp[0]->s_n);
1101}
1102
1103static void minus_setup(void)
1104{
1105 minus_class = class_new(gensym("-~"), (t_newmethod)minus_new, 0,
1106 sizeof(t_minus), 0, A_GIMME, 0);
1107 CLASS_MAINSIGNALIN(minus_class, t_minus, x_f);
1108 class_addmethod(minus_class, (t_method)minus_dsp, gensym("dsp"), 0);
1109 class_sethelpsymbol(minus_class, gensym("sigbinops"));
1110 scalarminus_class = class_new(gensym("-~"), 0, 0,
1111 sizeof(t_scalarminus), 0, 0);
1112 CLASS_MAINSIGNALIN(scalarminus_class, t_scalarminus, x_f);
1113 class_addmethod(scalarminus_class, (t_method)scalarminus_dsp, gensym("dsp"),
1114 0);
1115 class_sethelpsymbol(scalarminus_class, gensym("sigbinops"));
1116}
1117
1118/* ----------------------------- times ----------------------------- */
1119
1120static t_class *times_class, *scalartimes_class;
1121
1122typedef struct _times
1123{
1124 t_object x_obj;
1125 float x_f;
1126} t_times;
1127
1128typedef struct _scalartimes
1129{
1130 t_object x_obj;
1131 float x_f;
1132 t_float x_g;
1133} t_scalartimes;
1134
1135static void *times_new(t_symbol *s, int argc, t_atom *argv)
1136{
1137 if (argc > 1) post("*~: extra arguments ignored");
1138 if (argc)
1139 {
1140 t_scalartimes *x = (t_scalartimes *)pd_new(scalartimes_class);
1141 floatinlet_new(&x->x_obj, &x->x_g);
1142 x->x_g = atom_getfloatarg(0, argc, argv);
1143 outlet_new(&x->x_obj, &s_signal);
1144 x->x_f = 0;
1145 return (x);
1146 }
1147 else
1148 {
1149 t_times *x = (t_times *)pd_new(times_class);
1150 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
1151 outlet_new(&x->x_obj, &s_signal);
1152 x->x_f = 0;
1153 return (x);
1154 }
1155}
1156
1157t_int *times_perform(t_int *w)
1158{
1159 t_sample *in1 = (t_sample *)(w[1]);
1160 t_sample *in2 = (t_sample *)(w[2]);
1161 t_sample *out = (t_sample *)(w[3]);
1162 int n = (int)(w[4]);
1163 while (n--) *out++ = mult(*in1++,*in2++);
1164 return (w+5);
1165}
1166
1167t_int *times_perf8(t_int *w)
1168{
1169 t_sample *in1 = (t_sample *)(w[1]);
1170 t_sample *in2 = (t_sample *)(w[2]);
1171 t_sample *out = (t_sample *)(w[3]);
1172 int n = (int)(w[4]);
1173 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
1174 {
1175 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
1176 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
1177
1178 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
1179 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
1180
1181 out[0] = mult(f0,g0); out[1] = mult(f1,g1); out[2] = mult(f2,g2); out[3] = mult(f3,g3);
1182 out[4] = mult(f4,g4); out[5] = mult(f5,g5); out[6] = mult(f6,g6); out[7] = mult(f7,g7);
1183 }
1184 return (w+5);
1185}
1186
1187t_int *scalartimes_perform(t_int *w)
1188{
1189 t_sample *in = (t_sample *)(w[1]);
1190 t_sample f = ftofix(*(t_float *)(w[2]));
1191 t_sample *out = (t_sample *)(w[3]);
1192 int n = (int)(w[4]);
1193 while (n--) *out++ = mult(*in++,f);
1194 return (w+5);
1195}
1196
1197t_int *scalartimes_perf8(t_int *w)
1198{
1199 t_sample *in = (t_sample *)(w[1]);
1200 t_sample g = ftofix(*(t_float *)(w[2]));
1201 t_sample *out = (t_sample *)(w[3]);
1202 int n = (int)(w[4]);
1203 for (; n; n -= 8, in += 8, out += 8)
1204 {
1205 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
1206 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
1207
1208 out[0] = mult(f0,g); out[1] = mult(f1,g); out[2] = mult(f2,g); out[3] = mult(f3,g);
1209 out[4] = mult(f4,g); out[5] = mult(f5,g); out[6] = mult(f6,g); out[7] = mult(f7,g);
1210 }
1211 return (w+5);
1212}
1213
1214static void times_dsp(t_times *x, t_signal **sp)
1215{
1216 if (sp[0]->s_n&7)
1217 dsp_add(times_perform, 4,
1218 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1219 else
1220 dsp_add(times_perf8, 4,
1221 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1222}
1223
1224static void scalartimes_dsp(t_scalartimes *x, t_signal **sp)
1225{
1226 if (sp[0]->s_n&7)
1227 dsp_add(scalartimes_perform, 4, sp[0]->s_vec, &x->x_g,
1228 sp[1]->s_vec, sp[0]->s_n);
1229 else
1230 dsp_add(scalartimes_perf8, 4, sp[0]->s_vec, &x->x_g,
1231 sp[1]->s_vec, sp[0]->s_n);
1232}
1233
1234static void times_setup(void)
1235{
1236 times_class = class_new(gensym("*~"), (t_newmethod)times_new, 0,
1237 sizeof(t_times), 0, A_GIMME, 0);
1238 CLASS_MAINSIGNALIN(times_class, t_times, x_f);
1239 class_addmethod(times_class, (t_method)times_dsp, gensym("dsp"), 0);
1240 class_sethelpsymbol(times_class, gensym("sigbinops"));
1241 scalartimes_class = class_new(gensym("*~"), 0, 0,
1242 sizeof(t_scalartimes), 0, 0);
1243 CLASS_MAINSIGNALIN(scalartimes_class, t_scalartimes, x_f);
1244 class_addmethod(scalartimes_class, (t_method)scalartimes_dsp, gensym("dsp"),
1245 0);
1246 class_sethelpsymbol(scalartimes_class, gensym("sigbinops"));
1247}
1248
1249/* ----------------------------- over ----------------------------- */
1250static t_class *over_class, *scalarover_class;
1251
1252typedef struct _over
1253{
1254 t_object x_obj;
1255 float x_f;
1256} t_over;
1257
1258typedef struct _scalarover
1259{
1260 t_object x_obj;
1261 float x_f;
1262 t_float x_g;
1263} t_scalarover;
1264
1265static void *over_new(t_symbol *s, int argc, t_atom *argv)
1266{
1267 if (argc > 1) post("/~: extra arguments ignored");
1268 if (argc)
1269 {
1270 t_scalarover *x = (t_scalarover *)pd_new(scalarover_class);
1271 floatinlet_new(&x->x_obj, &x->x_g);
1272 x->x_g = atom_getfloatarg(0, argc, argv);
1273 outlet_new(&x->x_obj, &s_signal);
1274 x->x_f = 0;
1275 return (x);
1276 }
1277 else
1278 {
1279 t_over *x = (t_over *)pd_new(over_class);
1280 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
1281 outlet_new(&x->x_obj, &s_signal);
1282 x->x_f = 0;
1283 return (x);
1284 }
1285}
1286
1287t_int *over_perform(t_int *w)
1288{
1289 t_sample *in1 = (t_sample *)(w[1]);
1290 t_sample *in2 = (t_sample *)(w[2]);
1291 t_sample *out = (t_sample *)(w[3]);
1292 int n = (int)(w[4]);
1293 while (n--)
1294 {
1295 float g = *in2++;
1296 *out++ = (g ? *in1++ / g : 0);
1297 }
1298 return (w+5);
1299}
1300
1301t_int *over_perf8(t_int *w)
1302{
1303 t_sample *in1 = (t_sample *)(w[1]);
1304 t_sample *in2 = (t_sample *)(w[2]);
1305 t_sample *out = (t_sample *)(w[3]);
1306 int n = (int)(w[4]);
1307 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
1308 {
1309 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
1310 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
1311
1312 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
1313 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
1314
1315 out[0] = (g0? idiv(f0,g0) : 0);
1316 out[1] = (g1? idiv(f1,g1) : 0);
1317 out[2] = (g2? idiv(f2,g2) : 0);
1318 out[3] = (g3? idiv(f3,g3) : 0);
1319 out[4] = (g4? idiv(f4,g4) : 0);
1320 out[5] = (g5? idiv(f5,g5) : 0);
1321 out[6] = (g6? idiv(f6,g6) : 0);
1322 out[7] = (g7? idiv(f7,g7) : 0);
1323 }
1324 return (w+5);
1325}
1326
1327t_int *scalarover_perform(t_int *w)
1328{
1329 t_sample *in = (t_sample *)(w[1]);
1330 t_sample f = idiv(ftofix(1.),ftofix(*(t_float *)(w[2])));
1331 t_sample *out = (t_sample *)(w[3]);
1332 int n = (int)(w[4]);
1333 while (n--) *out++ = mult(*in++,f);
1334 return (w+5);
1335}
1336
1337t_int *scalarover_perf8(t_int *w)
1338{
1339 t_sample *in = (t_sample *)(w[1]);
1340 t_sample g = ftofix(*(t_float *)(w[2]));
1341 t_sample *out = (t_sample *)(w[3]);
1342 int n = (int)(w[4]);
1343 if (g) g = idiv(ftofix(1.f),g);
1344 for (; n; n -= 8, in += 8, out += 8)
1345 {
1346 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
1347 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
1348
1349 out[0] = mult(f0,g); out[1] = mult(f1,g); out[2] = mult(f2,g); out[3] = mult(f3,g);
1350 out[4] = mult(f4,g); out[5] = mult(f5,g); out[6] = mult(f6,g); out[7] = mult(f7,g);
1351 }
1352 return (w+5);
1353}
1354
1355static void over_dsp(t_over *x, t_signal **sp)
1356{
1357 if (sp[0]->s_n&7)
1358 dsp_add(over_perform, 4,
1359 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1360 else
1361 dsp_add(over_perf8, 4,
1362 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1363}
1364
1365static void scalarover_dsp(t_scalarover *x, t_signal **sp)
1366{
1367 if (sp[0]->s_n&7)
1368 dsp_add(scalarover_perform, 4, sp[0]->s_vec, &x->x_g,
1369 sp[1]->s_vec, sp[0]->s_n);
1370 else
1371 dsp_add(scalarover_perf8, 4, sp[0]->s_vec, &x->x_g,
1372 sp[1]->s_vec, sp[0]->s_n);
1373}
1374
1375static void over_setup(void)
1376{
1377 over_class = class_new(gensym("/~"), (t_newmethod)over_new, 0,
1378 sizeof(t_over), 0, A_GIMME, 0);
1379 CLASS_MAINSIGNALIN(over_class, t_over, x_f);
1380 class_addmethod(over_class, (t_method)over_dsp, gensym("dsp"), 0);
1381 class_sethelpsymbol(over_class, gensym("sigbinops"));
1382 scalarover_class = class_new(gensym("/~"), 0, 0,
1383 sizeof(t_scalarover), 0, 0);
1384 CLASS_MAINSIGNALIN(scalarover_class, t_scalarover, x_f);
1385 class_addmethod(scalarover_class, (t_method)scalarover_dsp, gensym("dsp"),
1386 0);
1387 class_sethelpsymbol(scalarover_class, gensym("sigbinops"));
1388}
1389
1390/* ----------------------------- max ----------------------------- */
1391static t_class *max_class, *scalarmax_class;
1392
1393typedef struct _max
1394{
1395 t_object x_obj;
1396 float x_f;
1397} t_max;
1398
1399typedef struct _scalarmax
1400{
1401 t_object x_obj;
1402 float x_f;
1403 t_float x_g;
1404} t_scalarmax;
1405
1406static void *max_new(t_symbol *s, int argc, t_atom *argv)
1407{
1408 if (argc > 1) post("max~: extra arguments ignored");
1409 if (argc)
1410 {
1411 t_scalarmax *x = (t_scalarmax *)pd_new(scalarmax_class);
1412 floatinlet_new(&x->x_obj, &x->x_g);
1413 x->x_g = atom_getfloatarg(0, argc, argv);
1414 outlet_new(&x->x_obj, &s_signal);
1415 x->x_f = 0;
1416 return (x);
1417 }
1418 else
1419 {
1420 t_max *x = (t_max *)pd_new(max_class);
1421 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
1422 outlet_new(&x->x_obj, &s_signal);
1423 x->x_f = 0;
1424 return (x);
1425 }
1426}
1427
1428t_int *max_perform(t_int *w)
1429{
1430 t_sample *in1 = (t_sample *)(w[1]);
1431 t_sample *in2 = (t_sample *)(w[2]);
1432 t_sample *out = (t_sample *)(w[3]);
1433 int n = (int)(w[4]);
1434 while (n--)
1435 {
1436 t_sample f = *in1++, g = *in2++;
1437 *out++ = (f > g ? f : g);
1438 }
1439 return (w+5);
1440}
1441
1442t_int *max_perf8(t_int *w)
1443{
1444 t_sample *in1 = (t_sample *)(w[1]);
1445 t_sample *in2 = (t_sample *)(w[2]);
1446 t_sample *out = (t_sample *)(w[3]);
1447 int n = (int)(w[4]);
1448 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
1449 {
1450 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
1451 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
1452
1453 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
1454 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
1455
1456 out[0] = (f0 > g0 ? f0 : g0); out[1] = (f1 > g1 ? f1 : g1);
1457 out[2] = (f2 > g2 ? f2 : g2); out[3] = (f3 > g3 ? f3 : g3);
1458 out[4] = (f4 > g4 ? f4 : g4); out[5] = (f5 > g5 ? f5 : g5);
1459 out[6] = (f6 > g6 ? f6 : g6); out[7] = (f7 > g7 ? f7 : g7);
1460 }
1461 return (w+5);
1462}
1463
1464t_int *scalarmax_perform(t_int *w)
1465{
1466 t_sample *in = (t_sample *)(w[1]);
1467 t_sample f = ftofix(*(t_float *)(w[2]));
1468 t_sample *out = (t_sample *)(w[3]);
1469 int n = (int)(w[4]);
1470 while (n--)
1471 {
1472 t_sample g = *in++;
1473 *out++ = (f > g ? f : g);
1474 }
1475 return (w+5);
1476}
1477
1478t_int *scalarmax_perf8(t_int *w)
1479{
1480 t_sample *in = (t_sample *)(w[1]);
1481 t_sample g = ftofix(*(t_float *)(w[2]));
1482 t_sample *out = (t_sample *)(w[3]);
1483 int n = (int)(w[4]);
1484 for (; n; n -= 8, in += 8, out += 8)
1485 {
1486 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
1487 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
1488
1489 out[0] = (f0 > g ? f0 : g); out[1] = (f1 > g ? f1 : g);
1490 out[2] = (f2 > g ? f2 : g); out[3] = (f3 > g ? f3 : g);
1491 out[4] = (f4 > g ? f4 : g); out[5] = (f5 > g ? f5 : g);
1492 out[6] = (f6 > g ? f6 : g); out[7] = (f7 > g ? f7 : g);
1493 }
1494 return (w+5);
1495}
1496
1497static void max_dsp(t_max *x, t_signal **sp)
1498{
1499 if (sp[0]->s_n&7)
1500 dsp_add(max_perform, 4,
1501 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1502 else
1503 dsp_add(max_perf8, 4,
1504 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1505}
1506
1507static void scalarmax_dsp(t_scalarmax *x, t_signal **sp)
1508{
1509 if (sp[0]->s_n&7)
1510 dsp_add(scalarmax_perform, 4, sp[0]->s_vec, &x->x_g,
1511 sp[1]->s_vec, sp[0]->s_n);
1512 else
1513 dsp_add(scalarmax_perf8, 4, sp[0]->s_vec, &x->x_g,
1514 sp[1]->s_vec, sp[0]->s_n);
1515}
1516
1517static void max_setup(void)
1518{
1519 max_class = class_new(gensym("max~"), (t_newmethod)max_new, 0,
1520 sizeof(t_max), 0, A_GIMME, 0);
1521 CLASS_MAINSIGNALIN(max_class, t_max, x_f);
1522 class_addmethod(max_class, (t_method)max_dsp, gensym("dsp"), 0);
1523 class_sethelpsymbol(max_class, gensym("sigbinops"));
1524 scalarmax_class = class_new(gensym("max~"), 0, 0,
1525 sizeof(t_scalarmax), 0, 0);
1526 CLASS_MAINSIGNALIN(scalarmax_class, t_scalarmax, x_f);
1527 class_addmethod(scalarmax_class, (t_method)scalarmax_dsp, gensym("dsp"),
1528 0);
1529 class_sethelpsymbol(scalarmax_class, gensym("sigbinops"));
1530}
1531
1532/* ----------------------------- min ----------------------------- */
1533static t_class *min_class, *scalarmin_class;
1534
1535typedef struct _min
1536{
1537 t_object x_obj;
1538 float x_f;
1539} t_min;
1540
1541typedef struct _scalarmin
1542{
1543 t_object x_obj;
1544 t_float x_g;
1545 float x_f;
1546} t_scalarmin;
1547
1548static void *min_new(t_symbol *s, int argc, t_atom *argv)
1549{
1550 if (argc > 1) post("min~: extra arguments ignored");
1551 if (argc)
1552 {
1553 t_scalarmin *x = (t_scalarmin *)pd_new(scalarmin_class);
1554 floatinlet_new(&x->x_obj, &x->x_g);
1555 x->x_g = atom_getfloatarg(0, argc, argv);
1556 outlet_new(&x->x_obj, &s_signal);
1557 x->x_f = 0;
1558 return (x);
1559 }
1560 else
1561 {
1562 t_min *x = (t_min *)pd_new(min_class);
1563 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
1564 outlet_new(&x->x_obj, &s_signal);
1565 x->x_f = 0;
1566 return (x);
1567 }
1568}
1569
1570t_int *min_perform(t_int *w)
1571{
1572 t_sample *in1 = (t_sample *)(w[1]);
1573 t_sample *in2 = (t_sample *)(w[2]);
1574 t_sample *out = (t_sample *)(w[3]);
1575 int n = (int)(w[4]);
1576 while (n--)
1577 {
1578 t_sample f = *in1++, g = *in2++;
1579 *out++ = (f < g ? f : g);
1580 }
1581 return (w+5);
1582}
1583
1584t_int *min_perf8(t_int *w)
1585{
1586 t_sample *in1 = (t_sample *)(w[1]);
1587 t_sample *in2 = (t_sample *)(w[2]);
1588 t_sample *out = (t_sample *)(w[3]);
1589 int n = (int)(w[4]);
1590 for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
1591 {
1592 t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
1593 t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
1594
1595 t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
1596 t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
1597
1598 out[0] = (f0 < g0 ? f0 : g0); out[1] = (f1 < g1 ? f1 : g1);
1599 out[2] = (f2 < g2 ? f2 : g2); out[3] = (f3 < g3 ? f3 : g3);
1600 out[4] = (f4 < g4 ? f4 : g4); out[5] = (f5 < g5 ? f5 : g5);
1601 out[6] = (f6 < g6 ? f6 : g6); out[7] = (f7 < g7 ? f7 : g7);
1602 }
1603 return (w+5);
1604}
1605
1606t_int *scalarmin_perform(t_int *w)
1607{
1608 t_sample *in = (t_sample *)(w[1]);
1609 t_sample f = ftofix(*(t_float *)(w[2]));
1610 t_sample *out = (t_sample *)(w[3]);
1611 int n = (int)(w[4]);
1612 while (n--)
1613 {
1614 t_sample g = *in++;
1615 *out++ = (f < g ? f : g);
1616 }
1617 return (w+5);
1618}
1619
1620t_int *scalarmin_perf8(t_int *w)
1621{
1622 t_sample *in = (t_sample *)(w[1]);
1623 t_sample g = ftofix(*(t_float *)(w[2]));
1624 t_sample *out = (t_sample *)(w[3]);
1625 int n = (int)(w[4]);
1626 for (; n; n -= 8, in += 8, out += 8)
1627 {
1628 t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
1629 t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
1630
1631 out[0] = (f0 < g ? f0 : g); out[1] = (f1 < g ? f1 : g);
1632 out[2] = (f2 < g ? f2 : g); out[3] = (f3 < g ? f3 : g);
1633 out[4] = (f4 < g ? f4 : g); out[5] = (f5 < g ? f5 : g);
1634 out[6] = (f6 < g ? f6 : g); out[7] = (f7 < g ? f7 : g);
1635 }
1636 return (w+5);
1637}
1638
1639static void min_dsp(t_min *x, t_signal **sp)
1640{
1641 if (sp[0]->s_n&7)
1642 dsp_add(min_perform, 4,
1643 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1644 else
1645 dsp_add(min_perf8, 4,
1646 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
1647}
1648
1649static void scalarmin_dsp(t_scalarmin *x, t_signal **sp)
1650{
1651 if (sp[0]->s_n&7)
1652 dsp_add(scalarmin_perform, 4, sp[0]->s_vec, &x->x_g,
1653 sp[1]->s_vec, sp[0]->s_n);
1654 else
1655 dsp_add(scalarmin_perf8, 4, sp[0]->s_vec, &x->x_g,
1656 sp[1]->s_vec, sp[0]->s_n);
1657}
1658
1659static void min_setup(void)
1660{
1661 min_class = class_new(gensym("min~"), (t_newmethod)min_new, 0,
1662 sizeof(t_min), 0, A_GIMME, 0);
1663 CLASS_MAINSIGNALIN(min_class, t_min, x_f);
1664 class_addmethod(min_class, (t_method)min_dsp, gensym("dsp"), 0);
1665 class_sethelpsymbol(min_class, gensym("sigbinops"));
1666 scalarmin_class = class_new(gensym("min~"), 0, 0,
1667 sizeof(t_scalarmin), 0, 0);
1668 CLASS_MAINSIGNALIN(scalarmin_class, t_scalarmin, x_f);
1669 class_addmethod(scalarmin_class, (t_method)scalarmin_dsp, gensym("dsp"),
1670 0);
1671 class_sethelpsymbol(scalarmin_class, gensym("sigbinops"));
1672}
1673
1674/* ----------------------- global setup routine ---------------- */
1675void d_arithmetic_setup(void)
1676{
1677 plus_setup();
1678 minus_setup();
1679 times_setup();
1680 over_setup();
1681 max_setup();
1682 min_setup();
1683}
1684
diff --git a/apps/plugins/pdbox/PDa/src/d_array.c b/apps/plugins/pdbox/PDa/src/d_array.c
new file mode 100644
index 0000000000..14ae464b0b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_array.c
@@ -0,0 +1,2148 @@
1/* Copyright (c) 1997-1999 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* sampling */
6
7/* LATER make tabread4 and tabread~ */
8
9#include "m_pd.h"
10
11
12/* ------------------------- tabwrite~ -------------------------- */
13
14static t_class *tabwrite_tilde_class;
15
16typedef struct _tabwrite_tilde
17{
18 t_object x_obj;
19 int x_phase;
20 int x_nsampsintab;
21 float *x_vec;
22 t_symbol *x_arrayname;
23 t_clock *x_clock;
24 float x_f;
25} t_tabwrite_tilde;
26
27static void tabwrite_tilde_tick(t_tabwrite_tilde *x);
28
29static void *tabwrite_tilde_new(t_symbol *s)
30{
31 t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
32 x->x_clock = clock_new(x, (t_method)tabwrite_tilde_tick);
33 x->x_phase = 0x7fffffff;
34 x->x_arrayname = s;
35 x->x_f = 0;
36 return (x);
37}
38
39static t_int *tabwrite_tilde_perform(t_int *w)
40{
41 t_tabwrite_tilde *x = (t_tabwrite_tilde *)(w[1]);
42 t_float *in = (t_float *)(w[2]);
43 int n = (int)(w[3]), phase = x->x_phase, endphase = x->x_nsampsintab;
44 if (!x->x_vec) goto bad;
45
46 if (endphase > phase)
47 {
48 int nxfer = endphase - phase;
49 float *fp = x->x_vec + phase;
50 if (nxfer > n) nxfer = n;
51 phase += nxfer;
52 while (nxfer--)
53 {
54 float f = *in++;
55 if (PD_BIGORSMALL(f))
56 f = 0;
57 *fp++ = f;
58 }
59 if (phase >= endphase)
60 {
61 clock_delay(x->x_clock, 0);
62 phase = 0x7fffffff;
63 }
64 x->x_phase = phase;
65 }
66bad:
67 return (w+4);
68}
69
70void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s)
71{
72 t_garray *a;
73
74 x->x_arrayname = s;
75 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
76 {
77 if (*s->s_name) pd_error(x, "tabwrite~: %s: no such array",
78 x->x_arrayname->s_name);
79 x->x_vec = 0;
80 }
81 else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
82 {
83 pd_error(x, "%s: bad template for tabwrite~", x->x_arrayname->s_name);
84 x->x_vec = 0;
85 }
86 else garray_usedindsp(a);
87}
88
89static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp)
90{
91 tabwrite_tilde_set(x, x->x_arrayname);
92 dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
93}
94
95static void tabwrite_tilde_bang(t_tabwrite_tilde *x)
96{
97 x->x_phase = 0;
98}
99
100static void tabwrite_tilde_stop(t_tabwrite_tilde *x)
101{
102 if (x->x_phase != 0x7fffffff)
103 {
104 tabwrite_tilde_tick(x);
105 x->x_phase = 0x7fffffff;
106 }
107}
108
109static void tabwrite_tilde_tick(t_tabwrite_tilde *x)
110{
111 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
112 if (!a) bug("tabwrite_tilde_tick");
113 else garray_redraw(a);
114}
115
116static void tabwrite_tilde_free(t_tabwrite_tilde *x)
117{
118 clock_free(x->x_clock);
119}
120
121static void tabwrite_tilde_setup(void)
122{
123 tabwrite_tilde_class = class_new(gensym("tabwrite~"),
124 (t_newmethod)tabwrite_tilde_new, (t_method)tabwrite_tilde_free,
125 sizeof(t_tabwrite_tilde), 0, A_DEFSYM, 0);
126 CLASS_MAINSIGNALIN(tabwrite_tilde_class, t_tabwrite_tilde, x_f);
127 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_dsp,
128 gensym("dsp"), 0);
129 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_set,
130 gensym("set"), A_SYMBOL, 0);
131 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_stop,
132 gensym("stop"), 0);
133 class_addbang(tabwrite_tilde_class, tabwrite_tilde_bang);
134}
135
136/* ------------ tabplay~ - non-transposing sample playback --------------- */
137
138static t_class *tabplay_tilde_class;
139
140typedef struct _tabplay_tilde
141{
142 t_object x_obj;
143 t_outlet *x_bangout;
144 int x_phase;
145 int x_nsampsintab;
146 int x_limit;
147 float *x_vec;
148 t_symbol *x_arrayname;
149 t_clock *x_clock;
150} t_tabplay_tilde;
151
152static void tabplay_tilde_tick(t_tabplay_tilde *x);
153
154static void *tabplay_tilde_new(t_symbol *s)
155{
156 t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
157 x->x_clock = clock_new(x, (t_method)tabplay_tilde_tick);
158 x->x_phase = 0x7fffffff;
159 x->x_limit = 0;
160 x->x_arrayname = s;
161 outlet_new(&x->x_obj, &s_signal);
162 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
163 return (x);
164}
165
166static t_int *tabplay_tilde_perform(t_int *w)
167{
168 t_tabplay_tilde *x = (t_tabplay_tilde *)(w[1]);
169 t_float *out = (t_float *)(w[2]), *fp;
170 int n = (int)(w[3]), phase = x->x_phase,
171 endphase = (x->x_nsampsintab < x->x_limit ?
172 x->x_nsampsintab : x->x_limit), nxfer, n3;
173 if (!x->x_vec || phase >= endphase)
174 goto zero;
175
176 nxfer = endphase - phase;
177 fp = x->x_vec + phase;
178 if (nxfer > n)
179 nxfer = n;
180 n3 = n - nxfer;
181 phase += nxfer;
182 while (nxfer--)
183 *out++ = *fp++;
184 if (phase >= endphase)
185 {
186 clock_delay(x->x_clock, 0);
187 x->x_phase = 0x7fffffff;
188 while (n3--)
189 *out++ = 0;
190 }
191 else x->x_phase = phase;
192
193 return (w+4);
194zero:
195 while (n--) *out++ = 0;
196 return (w+4);
197}
198
199void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s)
200{
201 t_garray *a;
202
203 x->x_arrayname = s;
204 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
205 {
206 if (*s->s_name) pd_error(x, "tabplay~: %s: no such array",
207 x->x_arrayname->s_name);
208 x->x_vec = 0;
209 }
210 else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
211 {
212 pd_error(x, "%s: bad template for tabplay~", x->x_arrayname->s_name);
213 x->x_vec = 0;
214 }
215 else garray_usedindsp(a);
216}
217
218static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp)
219{
220 tabplay_tilde_set(x, x->x_arrayname);
221 dsp_add(tabplay_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
222}
223
224static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s,
225 int argc, t_atom *argv)
226{
227 long start = atom_getfloatarg(0, argc, argv);
228 long length = atom_getfloatarg(1, argc, argv);
229 if (start < 0) start = 0;
230 if (length <= 0)
231 x->x_limit = 0x7fffffff;
232 else
233 x->x_limit = start + length;
234 x->x_phase = start;
235}
236
237static void tabplay_tilde_stop(t_tabplay_tilde *x)
238{
239 x->x_phase = 0x7fffffff;
240}
241
242static void tabplay_tilde_tick(t_tabplay_tilde *x)
243{
244 outlet_bang(x->x_bangout);
245}
246
247static void tabplay_tilde_free(t_tabplay_tilde *x)
248{
249 clock_free(x->x_clock);
250}
251
252static void tabplay_tilde_setup(void)
253{
254 tabplay_tilde_class = class_new(gensym("tabplay~"),
255 (t_newmethod)tabplay_tilde_new, (t_method)tabplay_tilde_free,
256 sizeof(t_tabplay_tilde), 0, A_DEFSYM, 0);
257 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_dsp,
258 gensym("dsp"), 0);
259 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_stop,
260 gensym("stop"), 0);
261 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_set,
262 gensym("set"), A_DEFSYM, 0);
263 class_addlist(tabplay_tilde_class, tabplay_tilde_list);
264}
265
266/******************** tabread~ ***********************/
267
268static t_class *tabread_tilde_class;
269
270typedef struct _tabread_tilde
271{
272 t_object x_obj;
273 int x_npoints;
274 float *x_vec;
275 t_symbol *x_arrayname;
276 float x_f;
277} t_tabread_tilde;
278
279static void *tabread_tilde_new(t_symbol *s)
280{
281 t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
282 x->x_arrayname = s;
283 x->x_vec = 0;
284 outlet_new(&x->x_obj, gensym("signal"));
285 x->x_f = 0;
286 return (x);
287}
288
289static t_int *tabread_tilde_perform(t_int *w)
290{
291 t_tabread_tilde *x = (t_tabread_tilde *)(w[1]);
292 t_float *in = (t_float *)(w[2]);
293 t_float *out = (t_float *)(w[3]);
294 int n = (int)(w[4]);
295 int maxindex;
296 float *buf = x->x_vec, *fp;
297 int i;
298
299 maxindex = x->x_npoints - 1;
300 if (!buf) goto zero;
301
302 for (i = 0; i < n; i++)
303 {
304 int index = *in++;
305 if (index < 0)
306 index = 0;
307 else if (index > maxindex)
308 index = maxindex;
309 *out++ = buf[index];
310 }
311 return (w+5);
312 zero:
313 while (n--) *out++ = 0;
314
315 return (w+5);
316}
317
318void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s)
319{
320 t_garray *a;
321
322 x->x_arrayname = s;
323 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
324 {
325 if (*s->s_name)
326 pd_error(x, "tabread~: %s: no such array", x->x_arrayname->s_name);
327 x->x_vec = 0;
328 }
329 else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
330 {
331 pd_error(x, "%s: bad template for tabread~", x->x_arrayname->s_name);
332 x->x_vec = 0;
333 }
334 else garray_usedindsp(a);
335}
336
337static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp)
338{
339 tabread_tilde_set(x, x->x_arrayname);
340
341 dsp_add(tabread_tilde_perform, 4, x,
342 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
343
344}
345
346static void tabread_tilde_free(t_tabread_tilde *x)
347{
348}
349
350static void tabread_tilde_setup(void)
351{
352 tabread_tilde_class = class_new(gensym("tabread~"),
353 (t_newmethod)tabread_tilde_new, (t_method)tabread_tilde_free,
354 sizeof(t_tabread_tilde), 0, A_DEFSYM, 0);
355 CLASS_MAINSIGNALIN(tabread_tilde_class, t_tabread_tilde, x_f);
356 class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_dsp,
357 gensym("dsp"), 0);
358 class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_set,
359 gensym("set"), A_SYMBOL, 0);
360}
361
362/******************** tabread4~ ***********************/
363
364static t_class *tabread4_tilde_class;
365
366typedef struct _tabread4_tilde
367{
368 t_object x_obj;
369 int x_npoints;
370 float *x_vec;
371 t_symbol *x_arrayname;
372 float x_f;
373} t_tabread4_tilde;
374
375static void *tabread4_tilde_new(t_symbol *s)
376{
377 t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
378 x->x_arrayname = s;
379 x->x_vec = 0;
380 outlet_new(&x->x_obj, gensym("signal"));
381 x->x_f = 0;
382 return (x);
383}
384
385static t_int *tabread4_tilde_perform(t_int *w)
386{
387 t_tabread4_tilde *x = (t_tabread4_tilde *)(w[1]);
388 t_float *in = (t_float *)(w[2]);
389 t_float *out = (t_float *)(w[3]);
390 int n = (int)(w[4]);
391 int maxindex;
392 float *buf = x->x_vec, *fp;
393 int i;
394
395 maxindex = x->x_npoints - 3;
396
397 if (!buf) goto zero;
398
399#if 0 /* test for spam -- I'm not ready to deal with this */
400 for (i = 0, xmax = 0, xmin = maxindex, fp = in1; i < n; i++, fp++)
401 {
402 float f = *in1;
403 if (f < xmin) xmin = f;
404 else if (f > xmax) xmax = f;
405 }
406 if (xmax < xmin + x->c_maxextent) xmax = xmin + x->c_maxextent;
407 for (i = 0, splitlo = xmin+ x->c_maxextent, splithi = xmax - x->c_maxextent,
408 fp = in1; i < n; i++, fp++)
409 {
410 float f = *in1;
411 if (f > splitlo && f < splithi) goto zero;
412 }
413#endif
414
415 for (i = 0; i < n; i++)
416 {
417 float findex = *in++;
418 int index = findex;
419 float frac, a, b, c, d, cminusb;
420 static int count;
421 if (index < 1)
422 index = 1, frac = 0;
423 else if (index > maxindex)
424 index = maxindex, frac = 1;
425 else frac = findex - index;
426 fp = buf + index;
427 a = fp[-1];
428 b = fp[0];
429 c = fp[1];
430 d = fp[2];
431 /* if (!i && !(count++ & 1023))
432 post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
433 cminusb = c-b;
434 *out++ = b + frac * (
435 cminusb - 0.1666667f * (1.-frac) * (
436 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
437 )
438 );
439 }
440 return (w+5);
441 zero:
442 while (n--) *out++ = 0;
443
444 return (w+5);
445}
446
447void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s)
448{
449 t_garray *a;
450
451 x->x_arrayname = s;
452 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
453 {
454 if (*s->s_name)
455 pd_error(x, "tabread4~: %s: no such array", x->x_arrayname->s_name);
456 x->x_vec = 0;
457 }
458 else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
459 {
460 pd_error(x, "%s: bad template for tabread4~", x->x_arrayname->s_name);
461 x->x_vec = 0;
462 }
463 else garray_usedindsp(a);
464}
465
466static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp)
467{
468 tabread4_tilde_set(x, x->x_arrayname);
469
470 dsp_add(tabread4_tilde_perform, 4, x,
471 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
472
473}
474
475static void tabread4_tilde_free(t_tabread4_tilde *x)
476{
477}
478
479static void tabread4_tilde_setup(void)
480{
481 tabread4_tilde_class = class_new(gensym("tabread4~"),
482 (t_newmethod)tabread4_tilde_new, (t_method)tabread4_tilde_free,
483 sizeof(t_tabread4_tilde), 0, A_DEFSYM, 0);
484 CLASS_MAINSIGNALIN(tabread4_tilde_class, t_tabread4_tilde, x_f);
485 class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_dsp,
486 gensym("dsp"), 0);
487 class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_set,
488 gensym("set"), A_SYMBOL, 0);
489}
490
491/******************** tabosc4~ ***********************/
492
493/* this is all copied from d_osc.c... what include file could this go in? */
494#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
495
496 /* machine-dependent definitions. These ifdefs really
497 should have been by CPU type and not by operating system! */
498#ifdef IRIX
499 /* big-endian. Most significant byte is at low address in memory */
500#define HIOFFSET 0 /* word offset to find MSB */
501#define LOWOFFSET 1 /* word offset to find LSB */
502#define int32 long /* a data type that has 32 bits */
503#else
504#ifdef MSW
505 /* little-endian; most significant byte is at highest address */
506#define HIOFFSET 1
507#define LOWOFFSET 0
508#define int32 long
509#else
510#ifdef __FreeBSD__
511#include <machine/endian.h>
512#if BYTE_ORDER == LITTLE_ENDIAN
513#define HIOFFSET 1
514#define LOWOFFSET 0
515#else
516#define HIOFFSET 0 /* word offset to find MSB */
517#define LOWOFFSET 1 /* word offset to find LSB */
518#endif /* BYTE_ORDER */
519#include <sys/types.h>
520#define int32 int32_t
521#endif
522
523#ifdef __linux__
524#include <endian.h>
525#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
526#error No byte order defined
527#endif
528
529#if __BYTE_ORDER == __LITTLE_ENDIAN
530#define HIOFFSET 1
531#define LOWOFFSET 0
532#else
533#define HIOFFSET 0 /* word offset to find MSB */
534#define LOWOFFSET 1 /* word offset to find LSB */
535#endif /* __BYTE_ORDER */
536
537#include <sys/types.h>
538#define int32 int32_t
539
540#else
541#ifdef MACOSX
542#define HIOFFSET 0 /* word offset to find MSB */
543#define LOWOFFSET 1 /* word offset to find LSB */
544#define int32 int /* a data type that has 32 bits */
545
546#endif /* MACOSX */
547#endif /* __linux__ */
548#endif /* MSW */
549#endif /* SGI */
550
551union tabfudge
552{
553 double tf_d;
554 int32 tf_i[2];
555};
556
557static t_class *tabosc4_tilde_class;
558
559typedef struct _tabosc4_tilde
560{
561 t_object x_obj;
562 float x_fnpoints;
563 float x_finvnpoints;
564 float *x_vec;
565 t_symbol *x_arrayname;
566 float x_f;
567 double x_phase;
568 float x_conv;
569} t_tabosc4_tilde;
570
571static void *tabosc4_tilde_new(t_symbol *s)
572{
573 t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
574 x->x_arrayname = s;
575 x->x_vec = 0;
576 x->x_fnpoints = 512.;
577 x->x_finvnpoints = (1./512.);
578 outlet_new(&x->x_obj, gensym("signal"));
579 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
580 x->x_f = 0;
581 return (x);
582}
583
584static t_int *tabosc4_tilde_perform(t_int *w)
585{
586 t_tabosc4_tilde *x = (t_tabosc4_tilde *)(w[1]);
587 t_float *in = (t_float *)(w[2]);
588 t_float *out = (t_float *)(w[3]);
589 int n = (int)(w[4]);
590 int normhipart;
591 union tabfudge tf;
592 float fnpoints = x->x_fnpoints;
593 int mask = fnpoints - 1;
594 float conv = fnpoints * x->x_conv;
595 int maxindex;
596 float *tab = x->x_vec, *addr;
597 int i;
598 double dphase = fnpoints * x->x_phase + UNITBIT32;
599
600 if (!tab) goto zero;
601 tf.tf_d = UNITBIT32;
602 normhipart = tf.tf_i[HIOFFSET];
603
604#if 1
605 while (n--)
606 {
607 float frac, a, b, c, d, cminusb;
608 tf.tf_d = dphase;
609 dphase += *in++ * conv;
610 addr = tab + (tf.tf_i[HIOFFSET] & mask);
611 tf.tf_i[HIOFFSET] = normhipart;
612 frac = tf.tf_d - UNITBIT32;
613 a = addr[0];
614 b = addr[1];
615 c = addr[2];
616 d = addr[3];
617 cminusb = c-b;
618 *out++ = b + frac * (
619 cminusb - 0.1666667f * (1.-frac) * (
620 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
621 )
622 );
623 }
624#endif
625
626 tf.tf_d = UNITBIT32 * fnpoints;
627 normhipart = tf.tf_i[HIOFFSET];
628 tf.tf_d = dphase + (UNITBIT32 * fnpoints - UNITBIT32);
629 tf.tf_i[HIOFFSET] = normhipart;
630 x->x_phase = (tf.tf_d - UNITBIT32 * fnpoints) * x->x_finvnpoints;
631 return (w+5);
632 zero:
633 while (n--) *out++ = 0;
634
635 return (w+5);
636}
637
638void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s)
639{
640 t_garray *a;
641 int npoints, pointsinarray;
642
643 x->x_arrayname = s;
644 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
645 {
646 if (*s->s_name)
647 pd_error(x, "tabosc4~: %s: no such array", x->x_arrayname->s_name);
648 x->x_vec = 0;
649 }
650 else if (!garray_getfloatarray(a, &pointsinarray, &x->x_vec))
651 {
652 pd_error(x, "%s: bad template for tabosc4~", x->x_arrayname->s_name);
653 x->x_vec = 0;
654 }
655 else if ((npoints = pointsinarray - 3) != (1 << ilog2(pointsinarray - 3)))
656 {
657 pd_error(x, "%s: number of points (%d) not a power of 2 plus three",
658 x->x_arrayname->s_name, pointsinarray);
659 x->x_vec = 0;
660 garray_usedindsp(a);
661 }
662 else
663 {
664 x->x_fnpoints = npoints;
665 x->x_finvnpoints = 1./npoints;
666 garray_usedindsp(a);
667 }
668}
669
670static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f)
671{
672 x->x_phase = f;
673}
674
675static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp)
676{
677 x->x_conv = 1. / sp[0]->s_sr;
678 tabosc4_tilde_set(x, x->x_arrayname);
679
680 dsp_add(tabosc4_tilde_perform, 4, x,
681 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
682}
683
684static void tabosc4_tilde_setup(void)
685{
686 tabosc4_tilde_class = class_new(gensym("tabosc4~"),
687 (t_newmethod)tabosc4_tilde_new, 0,
688 sizeof(t_tabosc4_tilde), 0, A_DEFSYM, 0);
689 CLASS_MAINSIGNALIN(tabosc4_tilde_class, t_tabosc4_tilde, x_f);
690 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_dsp,
691 gensym("dsp"), 0);
692 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_set,
693 gensym("set"), A_SYMBOL, 0);
694 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_ft1,
695 gensym("ft1"), A_FLOAT, 0);
696}
697
698/* ------------------------ tabsend~ ------------------------- */
699
700static t_class *tabsend_class;
701
702typedef struct _tabsend
703{
704 t_object x_obj;
705 float *x_vec;
706 int x_graphperiod;
707 int x_graphcount;
708 t_symbol *x_arrayname;
709 t_clock *x_clock;
710 float x_f;
711} t_tabsend;
712
713static void tabsend_tick(t_tabsend *x);
714
715static void *tabsend_new(t_symbol *s)
716{
717 t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
718 x->x_graphcount = 0;
719 x->x_arrayname = s;
720 x->x_clock = clock_new(x, (t_method)tabsend_tick);
721 x->x_f = 0;
722 return (x);
723}
724
725static t_int *tabsend_perform(t_int *w)
726{
727 t_tabsend *x = (t_tabsend *)(w[1]);
728 t_float *in = (t_float *)(w[2]);
729 int n = w[3];
730 t_float *dest = x->x_vec;
731 int i = x->x_graphcount;
732 if (!x->x_vec) goto bad;
733
734 while (n--)
735 {
736 float f = *in++;
737 if (PD_BIGORSMALL(f))
738 f = 0;
739 *dest++ = f;
740 }
741 if (!i--)
742 {
743 clock_delay(x->x_clock, 0);
744 i = x->x_graphperiod;
745 }
746 x->x_graphcount = i;
747bad:
748 return (w+4);
749}
750
751static void tabsend_dsp(t_tabsend *x, t_signal **sp)
752{
753 int i, vecsize;
754 t_garray *a;
755
756 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
757 {
758 if (*x->x_arrayname->s_name)
759 pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name);
760 }
761 else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
762 pd_error(x, "%s: bad template for tabsend~", x->x_arrayname->s_name);
763 else
764 {
765 int n = sp[0]->s_n;
766 int ticksper = sp[0]->s_sr/n;
767 if (ticksper < 1) ticksper = 1;
768 x->x_graphperiod = ticksper;
769 if (x->x_graphcount > ticksper) x->x_graphcount = ticksper;
770 if (n < vecsize) vecsize = n;
771 garray_usedindsp(a);
772 dsp_add(tabsend_perform, 3, x, sp[0]->s_vec, vecsize);
773 }
774}
775
776static void tabsend_tick(t_tabsend *x)
777{
778 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
779 if (!a) bug("tabsend_tick");
780 else garray_redraw(a);
781}
782
783static void tabsend_free(t_tabsend *x)
784{
785 clock_free(x->x_clock);
786}
787
788static void tabsend_setup(void)
789{
790 tabsend_class = class_new(gensym("tabsend~"), (t_newmethod)tabsend_new,
791 (t_method)tabsend_free, sizeof(t_tabsend), 0, A_DEFSYM, 0);
792 CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, x_f);
793 class_addmethod(tabsend_class, (t_method)tabsend_dsp, gensym("dsp"), 0);
794}
795
796/* ------------------------ tabreceive~ ------------------------- */
797
798static t_class *tabreceive_class;
799
800typedef struct _tabreceive
801{
802 t_object x_obj;
803 float *x_vec;
804 t_symbol *x_arrayname;
805} t_tabreceive;
806
807static t_int *tabreceive_perform(t_int *w)
808{
809 t_tabreceive *x = (t_tabreceive *)(w[1]);
810 t_float *out = (t_float *)(w[2]);
811 int n = w[3];
812 t_float *from = x->x_vec;
813 if (from) while (n--) *out++ = *from++;
814 else while (n--) *out++ = 0;
815 return (w+4);
816}
817
818static void tabreceive_dsp(t_tabreceive *x, t_signal **sp)
819{
820 t_garray *a;
821 int vecsize;
822
823 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
824 {
825 if (*x->x_arrayname->s_name)
826 pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name);
827 }
828 else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
829 pd_error(x, "%s: bad template for tabreceive~", x->x_arrayname->s_name);
830 else
831 {
832 int n = sp[0]->s_n;
833 if (n < vecsize) vecsize = n;
834 garray_usedindsp(a);
835 dsp_add(tabreceive_perform, 3, x, sp[0]->s_vec, vecsize);
836 }
837}
838
839static void *tabreceive_new(t_symbol *s)
840{
841 t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
842 x->x_arrayname = s;
843 outlet_new(&x->x_obj, &s_signal);
844 return (x);
845}
846
847static void tabreceive_setup(void)
848{
849 tabreceive_class = class_new(gensym("tabreceive~"),
850 (t_newmethod)tabreceive_new, 0,
851 sizeof(t_tabreceive), 0, A_DEFSYM, 0);
852 class_addmethod(tabreceive_class, (t_method)tabreceive_dsp,
853 gensym("dsp"), 0);
854}
855
856
857/* ---------- tabread: control, non-interpolating ------------------------ */
858
859static t_class *tabread_class;
860
861typedef struct _tabread
862{
863 t_object x_obj;
864 t_symbol *x_arrayname;
865} t_tabread;
866
867static void tabread_float(t_tabread *x, t_float f)
868{
869 t_garray *a;
870 int npoints;
871 t_float *vec;
872
873 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
874 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
875 else if (!garray_getfloatarray(a, &npoints, &vec))
876 pd_error(x, "%s: bad template for tabread", x->x_arrayname->s_name);
877 else
878 {
879 int n = f;
880 if (n < 0) n = 0;
881 else if (n >= npoints) n = npoints - 1;
882 outlet_float(x->x_obj.ob_outlet, (npoints ? vec[n] : 0));
883 }
884}
885
886static void tabread_set(t_tabread *x, t_symbol *s)
887{
888 x->x_arrayname = s;
889}
890
891static void *tabread_new(t_symbol *s)
892{
893 t_tabread *x = (t_tabread *)pd_new(tabread_class);
894 x->x_arrayname = s;
895 outlet_new(&x->x_obj, &s_float);
896 return (x);
897}
898
899static void tabread_setup(void)
900{
901 tabread_class = class_new(gensym("tabread"), (t_newmethod)tabread_new,
902 0, sizeof(t_tabread), 0, A_DEFSYM, 0);
903 class_addfloat(tabread_class, (t_method)tabread_float);
904 class_addmethod(tabread_class, (t_method)tabread_set, gensym("set"),
905 A_SYMBOL, 0);
906}
907
908/* ---------- tabread4: control, non-interpolating ------------------------ */
909
910static t_class *tabread4_class;
911
912typedef struct _tabread4
913{
914 t_object x_obj;
915 t_symbol *x_arrayname;
916} t_tabread4;
917
918static void tabread4_float(t_tabread4 *x, t_float f)
919{
920 t_garray *a;
921 int npoints;
922 t_float *vec;
923
924 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
925 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
926 else if (!garray_getfloatarray(a, &npoints, &vec))
927 pd_error(x, "%s: bad template for tabread4", x->x_arrayname->s_name);
928 else if (npoints < 4)
929 outlet_float(x->x_obj.ob_outlet, 0);
930 else if (f <= 1)
931 outlet_float(x->x_obj.ob_outlet, vec[1]);
932 else if (f >= npoints - 2)
933 outlet_float(x->x_obj.ob_outlet, vec[npoints - 2]);
934 else
935 {
936 int n = f;
937 float a, b, c, d, cminusb, frac, *fp;
938 if (n >= npoints - 2)
939 n = npoints - 3;
940 fp = vec + n;
941 frac = f - n;
942 a = fp[-1];
943 b = fp[0];
944 c = fp[1];
945 d = fp[2];
946 cminusb = c-b;
947 outlet_float(x->x_obj.ob_outlet, b + frac * (
948 cminusb - 0.1666667f * (1.-frac) * (
949 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))));
950 }
951}
952
953static void tabread4_set(t_tabread4 *x, t_symbol *s)
954{
955 x->x_arrayname = s;
956}
957
958static void *tabread4_new(t_symbol *s)
959{
960 t_tabread4 *x = (t_tabread4 *)pd_new(tabread4_class);
961 x->x_arrayname = s;
962 outlet_new(&x->x_obj, &s_float);
963 return (x);
964}
965
966static void tabread4_setup(void)
967{
968 tabread4_class = class_new(gensym("tabread4"), (t_newmethod)tabread4_new,
969 0, sizeof(t_tabread4), 0, A_DEFSYM, 0);
970 class_addfloat(tabread4_class, (t_method)tabread4_float);
971 class_addmethod(tabread4_class, (t_method)tabread4_set, gensym("set"),
972 A_SYMBOL, 0);
973}
974
975/* ------------------ tabwrite: control ------------------------ */
976
977static t_class *tabwrite_class;
978
979typedef struct _tabwrite
980{
981 t_object x_obj;
982 t_symbol *x_arrayname;
983 t_clock *x_clock;
984 float x_ft1;
985 double x_updtime;
986 int x_set;
987} t_tabwrite;
988
989static void tabwrite_tick(t_tabwrite *x)
990{
991 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
992 if (!a) bug("tabwrite_tick");
993 else garray_redraw(a);
994 x->x_set = 0;
995 x->x_updtime = clock_getsystime();
996}
997
998static void tabwrite_float(t_tabwrite *x, t_float f)
999{
1000 int i, vecsize;
1001 t_garray *a;
1002 t_float *vec;
1003
1004 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1005 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
1006 else if (!garray_getfloatarray(a, &vecsize, &vec))
1007 pd_error(x, "%s: bad template for tabwrite", x->x_arrayname->s_name);
1008 else
1009 {
1010 int n = x->x_ft1;
1011 double timesince = clock_gettimesince(x->x_updtime);
1012 if (n < 0) n = 0;
1013 else if (n >= vecsize) n = vecsize-1;
1014 vec[n] = f;
1015 if (timesince > 1000)
1016 {
1017 tabwrite_tick(x);
1018 }
1019 else
1020 {
1021 if (x->x_set == 0)
1022 {
1023 clock_delay(x->x_clock, 1000 - timesince);
1024 x->x_set = 1;
1025 }
1026 }
1027 }
1028}
1029
1030static void tabwrite_set(t_tabwrite *x, t_symbol *s)
1031{
1032 x->x_arrayname = s;
1033}
1034
1035static void tabwrite_free(t_tabwrite *x)
1036{
1037 clock_free(x->x_clock);
1038}
1039
1040static void *tabwrite_new(t_symbol *s)
1041{
1042 t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
1043 x->x_ft1 = 0;
1044 x->x_arrayname = s;
1045 x->x_updtime = clock_getsystime();
1046 x->x_clock = clock_new(x, (t_method)tabwrite_tick);
1047 floatinlet_new(&x->x_obj, &x->x_ft1);
1048 return (x);
1049}
1050
1051void tabwrite_setup(void)
1052{
1053 tabwrite_class = class_new(gensym("tabwrite"), (t_newmethod)tabwrite_new,
1054 (t_method)tabwrite_free, sizeof(t_tabwrite), 0, A_DEFSYM, 0);
1055 class_addfloat(tabwrite_class, (t_method)tabwrite_float);
1056 class_addmethod(tabwrite_class, (t_method)tabwrite_set, gensym("set"), A_SYMBOL, 0);
1057}
1058
1059/* ------------------------ global setup routine ------------------------- */
1060
1061void d_array_setup(void)
1062{
1063 tabwrite_tilde_setup();
1064 tabplay_tilde_setup();
1065 tabread_tilde_setup();
1066 tabread4_tilde_setup();
1067 tabosc4_tilde_setup();
1068 tabsend_setup();
1069 tabreceive_setup();
1070 tabread_setup();
1071 tabread4_setup();
1072 tabwrite_setup();
1073}
1074
1075/* Copyright (c) 1997-1999 Miller Puckette and others.
1076* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1077* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1078
1079/* sampling */
1080
1081/* LATER make tabread4 and tabread~ */
1082
1083#include "m_pd.h"
1084
1085
1086/* ------------------------- tabwrite~ -------------------------- */
1087
1088static t_class *tabwrite_tilde_class;
1089
1090typedef struct _tabwrite_tilde
1091{
1092 t_object x_obj;
1093 int x_phase;
1094 int x_nsampsintab;
1095 float *x_vec;
1096 t_symbol *x_arrayname;
1097 t_clock *x_clock;
1098 float x_f;
1099} t_tabwrite_tilde;
1100
1101static void tabwrite_tilde_tick(t_tabwrite_tilde *x);
1102
1103static void *tabwrite_tilde_new(t_symbol *s)
1104{
1105 t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
1106 x->x_clock = clock_new(x, (t_method)tabwrite_tilde_tick);
1107 x->x_phase = 0x7fffffff;
1108 x->x_arrayname = s;
1109 x->x_f = 0;
1110 return (x);
1111}
1112
1113static t_int *tabwrite_tilde_perform(t_int *w)
1114{
1115 t_tabwrite_tilde *x = (t_tabwrite_tilde *)(w[1]);
1116 t_float *in = (t_float *)(w[2]);
1117 int n = (int)(w[3]), phase = x->x_phase, endphase = x->x_nsampsintab;
1118 if (!x->x_vec) goto bad;
1119
1120 if (endphase > phase)
1121 {
1122 int nxfer = endphase - phase;
1123 float *fp = x->x_vec + phase;
1124 if (nxfer > n) nxfer = n;
1125 phase += nxfer;
1126 while (nxfer--)
1127 {
1128 float f = *in++;
1129 if (PD_BIGORSMALL(f))
1130 f = 0;
1131 *fp++ = f;
1132 }
1133 if (phase >= endphase)
1134 {
1135 clock_delay(x->x_clock, 0);
1136 phase = 0x7fffffff;
1137 }
1138 x->x_phase = phase;
1139 }
1140bad:
1141 return (w+4);
1142}
1143
1144void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s)
1145{
1146 t_garray *a;
1147
1148 x->x_arrayname = s;
1149 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1150 {
1151 if (*s->s_name) pd_error(x, "tabwrite~: %s: no such array",
1152 x->x_arrayname->s_name);
1153 x->x_vec = 0;
1154 }
1155 else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
1156 {
1157 pd_error(x, "%s: bad template for tabwrite~", x->x_arrayname->s_name);
1158 x->x_vec = 0;
1159 }
1160 else garray_usedindsp(a);
1161}
1162
1163static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp)
1164{
1165 tabwrite_tilde_set(x, x->x_arrayname);
1166 dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
1167}
1168
1169static void tabwrite_tilde_bang(t_tabwrite_tilde *x)
1170{
1171 x->x_phase = 0;
1172}
1173
1174static void tabwrite_tilde_stop(t_tabwrite_tilde *x)
1175{
1176 if (x->x_phase != 0x7fffffff)
1177 {
1178 tabwrite_tilde_tick(x);
1179 x->x_phase = 0x7fffffff;
1180 }
1181}
1182
1183static void tabwrite_tilde_tick(t_tabwrite_tilde *x)
1184{
1185 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
1186 if (!a) bug("tabwrite_tilde_tick");
1187 else garray_redraw(a);
1188}
1189
1190static void tabwrite_tilde_free(t_tabwrite_tilde *x)
1191{
1192 clock_free(x->x_clock);
1193}
1194
1195static void tabwrite_tilde_setup(void)
1196{
1197 tabwrite_tilde_class = class_new(gensym("tabwrite~"),
1198 (t_newmethod)tabwrite_tilde_new, (t_method)tabwrite_tilde_free,
1199 sizeof(t_tabwrite_tilde), 0, A_DEFSYM, 0);
1200 CLASS_MAINSIGNALIN(tabwrite_tilde_class, t_tabwrite_tilde, x_f);
1201 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_dsp,
1202 gensym("dsp"), 0);
1203 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_set,
1204 gensym("set"), A_SYMBOL, 0);
1205 class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_stop,
1206 gensym("stop"), 0);
1207 class_addbang(tabwrite_tilde_class, tabwrite_tilde_bang);
1208}
1209
1210/* ------------ tabplay~ - non-transposing sample playback --------------- */
1211
1212static t_class *tabplay_tilde_class;
1213
1214typedef struct _tabplay_tilde
1215{
1216 t_object x_obj;
1217 t_outlet *x_bangout;
1218 int x_phase;
1219 int x_nsampsintab;
1220 int x_limit;
1221 float *x_vec;
1222 t_symbol *x_arrayname;
1223 t_clock *x_clock;
1224} t_tabplay_tilde;
1225
1226static void tabplay_tilde_tick(t_tabplay_tilde *x);
1227
1228static void *tabplay_tilde_new(t_symbol *s)
1229{
1230 t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
1231 x->x_clock = clock_new(x, (t_method)tabplay_tilde_tick);
1232 x->x_phase = 0x7fffffff;
1233 x->x_limit = 0;
1234 x->x_arrayname = s;
1235 outlet_new(&x->x_obj, &s_signal);
1236 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
1237 return (x);
1238}
1239
1240static t_int *tabplay_tilde_perform(t_int *w)
1241{
1242 t_tabplay_tilde *x = (t_tabplay_tilde *)(w[1]);
1243 t_float *out = (t_float *)(w[2]), *fp;
1244 int n = (int)(w[3]), phase = x->x_phase,
1245 endphase = (x->x_nsampsintab < x->x_limit ?
1246 x->x_nsampsintab : x->x_limit), nxfer, n3;
1247 if (!x->x_vec || phase >= endphase)
1248 goto zero;
1249
1250 nxfer = endphase - phase;
1251 fp = x->x_vec + phase;
1252 if (nxfer > n)
1253 nxfer = n;
1254 n3 = n - nxfer;
1255 phase += nxfer;
1256 while (nxfer--)
1257 *out++ = *fp++;
1258 if (phase >= endphase)
1259 {
1260 clock_delay(x->x_clock, 0);
1261 x->x_phase = 0x7fffffff;
1262 while (n3--)
1263 *out++ = 0;
1264 }
1265 else x->x_phase = phase;
1266
1267 return (w+4);
1268zero:
1269 while (n--) *out++ = 0;
1270 return (w+4);
1271}
1272
1273void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s)
1274{
1275 t_garray *a;
1276
1277 x->x_arrayname = s;
1278 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1279 {
1280 if (*s->s_name) pd_error(x, "tabplay~: %s: no such array",
1281 x->x_arrayname->s_name);
1282 x->x_vec = 0;
1283 }
1284 else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
1285 {
1286 pd_error(x, "%s: bad template for tabplay~", x->x_arrayname->s_name);
1287 x->x_vec = 0;
1288 }
1289 else garray_usedindsp(a);
1290}
1291
1292static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp)
1293{
1294 tabplay_tilde_set(x, x->x_arrayname);
1295 dsp_add(tabplay_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
1296}
1297
1298static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s,
1299 int argc, t_atom *argv)
1300{
1301 long start = atom_getfloatarg(0, argc, argv);
1302 long length = atom_getfloatarg(1, argc, argv);
1303 if (start < 0) start = 0;
1304 if (length <= 0)
1305 x->x_limit = 0x7fffffff;
1306 else
1307 x->x_limit = start + length;
1308 x->x_phase = start;
1309}
1310
1311static void tabplay_tilde_stop(t_tabplay_tilde *x)
1312{
1313 x->x_phase = 0x7fffffff;
1314}
1315
1316static void tabplay_tilde_tick(t_tabplay_tilde *x)
1317{
1318 outlet_bang(x->x_bangout);
1319}
1320
1321static void tabplay_tilde_free(t_tabplay_tilde *x)
1322{
1323 clock_free(x->x_clock);
1324}
1325
1326static void tabplay_tilde_setup(void)
1327{
1328 tabplay_tilde_class = class_new(gensym("tabplay~"),
1329 (t_newmethod)tabplay_tilde_new, (t_method)tabplay_tilde_free,
1330 sizeof(t_tabplay_tilde), 0, A_DEFSYM, 0);
1331 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_dsp,
1332 gensym("dsp"), 0);
1333 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_stop,
1334 gensym("stop"), 0);
1335 class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_set,
1336 gensym("set"), A_DEFSYM, 0);
1337 class_addlist(tabplay_tilde_class, tabplay_tilde_list);
1338}
1339
1340/******************** tabread~ ***********************/
1341
1342static t_class *tabread_tilde_class;
1343
1344typedef struct _tabread_tilde
1345{
1346 t_object x_obj;
1347 int x_npoints;
1348 float *x_vec;
1349 t_symbol *x_arrayname;
1350 float x_f;
1351} t_tabread_tilde;
1352
1353static void *tabread_tilde_new(t_symbol *s)
1354{
1355 t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
1356 x->x_arrayname = s;
1357 x->x_vec = 0;
1358 outlet_new(&x->x_obj, gensym("signal"));
1359 x->x_f = 0;
1360 return (x);
1361}
1362
1363static t_int *tabread_tilde_perform(t_int *w)
1364{
1365 t_tabread_tilde *x = (t_tabread_tilde *)(w[1]);
1366 t_float *in = (t_float *)(w[2]);
1367 t_float *out = (t_float *)(w[3]);
1368 int n = (int)(w[4]);
1369 int maxindex;
1370 float *buf = x->x_vec, *fp;
1371 int i;
1372
1373 maxindex = x->x_npoints - 1;
1374 if (!buf) goto zero;
1375
1376 for (i = 0; i < n; i++)
1377 {
1378 int index = *in++;
1379 if (index < 0)
1380 index = 0;
1381 else if (index > maxindex)
1382 index = maxindex;
1383 *out++ = buf[index];
1384 }
1385 return (w+5);
1386 zero:
1387 while (n--) *out++ = 0;
1388
1389 return (w+5);
1390}
1391
1392void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s)
1393{
1394 t_garray *a;
1395
1396 x->x_arrayname = s;
1397 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1398 {
1399 if (*s->s_name)
1400 pd_error(x, "tabread~: %s: no such array", x->x_arrayname->s_name);
1401 x->x_vec = 0;
1402 }
1403 else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
1404 {
1405 pd_error(x, "%s: bad template for tabread~", x->x_arrayname->s_name);
1406 x->x_vec = 0;
1407 }
1408 else garray_usedindsp(a);
1409}
1410
1411static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp)
1412{
1413 tabread_tilde_set(x, x->x_arrayname);
1414
1415 dsp_add(tabread_tilde_perform, 4, x,
1416 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
1417
1418}
1419
1420static void tabread_tilde_free(t_tabread_tilde *x)
1421{
1422}
1423
1424static void tabread_tilde_setup(void)
1425{
1426 tabread_tilde_class = class_new(gensym("tabread~"),
1427 (t_newmethod)tabread_tilde_new, (t_method)tabread_tilde_free,
1428 sizeof(t_tabread_tilde), 0, A_DEFSYM, 0);
1429 CLASS_MAINSIGNALIN(tabread_tilde_class, t_tabread_tilde, x_f);
1430 class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_dsp,
1431 gensym("dsp"), 0);
1432 class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_set,
1433 gensym("set"), A_SYMBOL, 0);
1434}
1435
1436/******************** tabread4~ ***********************/
1437
1438static t_class *tabread4_tilde_class;
1439
1440typedef struct _tabread4_tilde
1441{
1442 t_object x_obj;
1443 int x_npoints;
1444 float *x_vec;
1445 t_symbol *x_arrayname;
1446 float x_f;
1447} t_tabread4_tilde;
1448
1449static void *tabread4_tilde_new(t_symbol *s)
1450{
1451 t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
1452 x->x_arrayname = s;
1453 x->x_vec = 0;
1454 outlet_new(&x->x_obj, gensym("signal"));
1455 x->x_f = 0;
1456 return (x);
1457}
1458
1459static t_int *tabread4_tilde_perform(t_int *w)
1460{
1461 t_tabread4_tilde *x = (t_tabread4_tilde *)(w[1]);
1462 t_float *in = (t_float *)(w[2]);
1463 t_float *out = (t_float *)(w[3]);
1464 int n = (int)(w[4]);
1465 int maxindex;
1466 float *buf = x->x_vec, *fp;
1467 int i;
1468
1469 maxindex = x->x_npoints - 3;
1470
1471 if (!buf) goto zero;
1472
1473#if 0 /* test for spam -- I'm not ready to deal with this */
1474 for (i = 0, xmax = 0, xmin = maxindex, fp = in1; i < n; i++, fp++)
1475 {
1476 float f = *in1;
1477 if (f < xmin) xmin = f;
1478 else if (f > xmax) xmax = f;
1479 }
1480 if (xmax < xmin + x->c_maxextent) xmax = xmin + x->c_maxextent;
1481 for (i = 0, splitlo = xmin+ x->c_maxextent, splithi = xmax - x->c_maxextent,
1482 fp = in1; i < n; i++, fp++)
1483 {
1484 float f = *in1;
1485 if (f > splitlo && f < splithi) goto zero;
1486 }
1487#endif
1488
1489 for (i = 0; i < n; i++)
1490 {
1491 float findex = *in++;
1492 int index = findex;
1493 float frac, a, b, c, d, cminusb;
1494 static int count;
1495 if (index < 1)
1496 index = 1, frac = 0;
1497 else if (index > maxindex)
1498 index = maxindex, frac = 1;
1499 else frac = findex - index;
1500 fp = buf + index;
1501 a = fp[-1];
1502 b = fp[0];
1503 c = fp[1];
1504 d = fp[2];
1505 /* if (!i && !(count++ & 1023))
1506 post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
1507 cminusb = c-b;
1508 *out++ = b + frac * (
1509 cminusb - 0.1666667f * (1.-frac) * (
1510 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
1511 )
1512 );
1513 }
1514 return (w+5);
1515 zero:
1516 while (n--) *out++ = 0;
1517
1518 return (w+5);
1519}
1520
1521void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s)
1522{
1523 t_garray *a;
1524
1525 x->x_arrayname = s;
1526 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1527 {
1528 if (*s->s_name)
1529 pd_error(x, "tabread4~: %s: no such array", x->x_arrayname->s_name);
1530 x->x_vec = 0;
1531 }
1532 else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
1533 {
1534 pd_error(x, "%s: bad template for tabread4~", x->x_arrayname->s_name);
1535 x->x_vec = 0;
1536 }
1537 else garray_usedindsp(a);
1538}
1539
1540static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp)
1541{
1542 tabread4_tilde_set(x, x->x_arrayname);
1543
1544 dsp_add(tabread4_tilde_perform, 4, x,
1545 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
1546
1547}
1548
1549static void tabread4_tilde_free(t_tabread4_tilde *x)
1550{
1551}
1552
1553static void tabread4_tilde_setup(void)
1554{
1555 tabread4_tilde_class = class_new(gensym("tabread4~"),
1556 (t_newmethod)tabread4_tilde_new, (t_method)tabread4_tilde_free,
1557 sizeof(t_tabread4_tilde), 0, A_DEFSYM, 0);
1558 CLASS_MAINSIGNALIN(tabread4_tilde_class, t_tabread4_tilde, x_f);
1559 class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_dsp,
1560 gensym("dsp"), 0);
1561 class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_set,
1562 gensym("set"), A_SYMBOL, 0);
1563}
1564
1565/******************** tabosc4~ ***********************/
1566
1567/* this is all copied from d_osc.c... what include file could this go in? */
1568#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
1569
1570 /* machine-dependent definitions. These ifdefs really
1571 should have been by CPU type and not by operating system! */
1572#ifdef IRIX
1573 /* big-endian. Most significant byte is at low address in memory */
1574#define HIOFFSET 0 /* word offset to find MSB */
1575#define LOWOFFSET 1 /* word offset to find LSB */
1576#define int32 long /* a data type that has 32 bits */
1577#else
1578#ifdef MSW
1579 /* little-endian; most significant byte is at highest address */
1580#define HIOFFSET 1
1581#define LOWOFFSET 0
1582#define int32 long
1583#else
1584#ifdef __FreeBSD__
1585#include <machine/endian.h>
1586#if BYTE_ORDER == LITTLE_ENDIAN
1587#define HIOFFSET 1
1588#define LOWOFFSET 0
1589#else
1590#define HIOFFSET 0 /* word offset to find MSB */
1591#define LOWOFFSET 1 /* word offset to find LSB */
1592#endif /* BYTE_ORDER */
1593#include <sys/types.h>
1594#define int32 int32_t
1595#endif
1596
1597#ifdef __linux__
1598#include <endian.h>
1599#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
1600#error No byte order defined
1601#endif
1602
1603#if __BYTE_ORDER == __LITTLE_ENDIAN
1604#define HIOFFSET 1
1605#define LOWOFFSET 0
1606#else
1607#define HIOFFSET 0 /* word offset to find MSB */
1608#define LOWOFFSET 1 /* word offset to find LSB */
1609#endif /* __BYTE_ORDER */
1610
1611#include <sys/types.h>
1612#define int32 int32_t
1613
1614#else
1615#ifdef MACOSX
1616#define HIOFFSET 0 /* word offset to find MSB */
1617#define LOWOFFSET 1 /* word offset to find LSB */
1618#define int32 int /* a data type that has 32 bits */
1619
1620#endif /* MACOSX */
1621#endif /* __linux__ */
1622#endif /* MSW */
1623#endif /* SGI */
1624
1625union tabfudge
1626{
1627 double tf_d;
1628 int32 tf_i[2];
1629};
1630
1631static t_class *tabosc4_tilde_class;
1632
1633typedef struct _tabosc4_tilde
1634{
1635 t_object x_obj;
1636 float x_fnpoints;
1637 float x_finvnpoints;
1638 float *x_vec;
1639 t_symbol *x_arrayname;
1640 float x_f;
1641 double x_phase;
1642 float x_conv;
1643} t_tabosc4_tilde;
1644
1645static void *tabosc4_tilde_new(t_symbol *s)
1646{
1647 t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
1648 x->x_arrayname = s;
1649 x->x_vec = 0;
1650 x->x_fnpoints = 512.;
1651 x->x_finvnpoints = (1./512.);
1652 outlet_new(&x->x_obj, gensym("signal"));
1653 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
1654 x->x_f = 0;
1655 return (x);
1656}
1657
1658static t_int *tabosc4_tilde_perform(t_int *w)
1659{
1660 t_tabosc4_tilde *x = (t_tabosc4_tilde *)(w[1]);
1661 t_float *in = (t_float *)(w[2]);
1662 t_float *out = (t_float *)(w[3]);
1663 int n = (int)(w[4]);
1664 int normhipart;
1665 union tabfudge tf;
1666 float fnpoints = x->x_fnpoints;
1667 int mask = fnpoints - 1;
1668 float conv = fnpoints * x->x_conv;
1669 int maxindex;
1670 float *tab = x->x_vec, *addr;
1671 int i;
1672 double dphase = fnpoints * x->x_phase + UNITBIT32;
1673
1674 if (!tab) goto zero;
1675 tf.tf_d = UNITBIT32;
1676 normhipart = tf.tf_i[HIOFFSET];
1677
1678#if 1
1679 while (n--)
1680 {
1681 float frac, a, b, c, d, cminusb;
1682 tf.tf_d = dphase;
1683 dphase += *in++ * conv;
1684 addr = tab + (tf.tf_i[HIOFFSET] & mask);
1685 tf.tf_i[HIOFFSET] = normhipart;
1686 frac = tf.tf_d - UNITBIT32;
1687 a = addr[0];
1688 b = addr[1];
1689 c = addr[2];
1690 d = addr[3];
1691 cminusb = c-b;
1692 *out++ = b + frac * (
1693 cminusb - 0.1666667f * (1.-frac) * (
1694 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
1695 )
1696 );
1697 }
1698#endif
1699
1700 tf.tf_d = UNITBIT32 * fnpoints;
1701 normhipart = tf.tf_i[HIOFFSET];
1702 tf.tf_d = dphase + (UNITBIT32 * fnpoints - UNITBIT32);
1703 tf.tf_i[HIOFFSET] = normhipart;
1704 x->x_phase = (tf.tf_d - UNITBIT32 * fnpoints) * x->x_finvnpoints;
1705 return (w+5);
1706 zero:
1707 while (n--) *out++ = 0;
1708
1709 return (w+5);
1710}
1711
1712void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s)
1713{
1714 t_garray *a;
1715 int npoints, pointsinarray;
1716
1717 x->x_arrayname = s;
1718 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1719 {
1720 if (*s->s_name)
1721 pd_error(x, "tabosc4~: %s: no such array", x->x_arrayname->s_name);
1722 x->x_vec = 0;
1723 }
1724 else if (!garray_getfloatarray(a, &pointsinarray, &x->x_vec))
1725 {
1726 pd_error(x, "%s: bad template for tabosc4~", x->x_arrayname->s_name);
1727 x->x_vec = 0;
1728 }
1729 else if ((npoints = pointsinarray - 3) != (1 << ilog2(pointsinarray - 3)))
1730 {
1731 pd_error(x, "%s: number of points (%d) not a power of 2 plus three",
1732 x->x_arrayname->s_name, pointsinarray);
1733 x->x_vec = 0;
1734 garray_usedindsp(a);
1735 }
1736 else
1737 {
1738 x->x_fnpoints = npoints;
1739 x->x_finvnpoints = 1./npoints;
1740 garray_usedindsp(a);
1741 }
1742}
1743
1744static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f)
1745{
1746 x->x_phase = f;
1747}
1748
1749static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp)
1750{
1751 x->x_conv = 1. / sp[0]->s_sr;
1752 tabosc4_tilde_set(x, x->x_arrayname);
1753
1754 dsp_add(tabosc4_tilde_perform, 4, x,
1755 sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
1756}
1757
1758static void tabosc4_tilde_setup(void)
1759{
1760 tabosc4_tilde_class = class_new(gensym("tabosc4~"),
1761 (t_newmethod)tabosc4_tilde_new, 0,
1762 sizeof(t_tabosc4_tilde), 0, A_DEFSYM, 0);
1763 CLASS_MAINSIGNALIN(tabosc4_tilde_class, t_tabosc4_tilde, x_f);
1764 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_dsp,
1765 gensym("dsp"), 0);
1766 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_set,
1767 gensym("set"), A_SYMBOL, 0);
1768 class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_ft1,
1769 gensym("ft1"), A_FLOAT, 0);
1770}
1771
1772/* ------------------------ tabsend~ ------------------------- */
1773
1774static t_class *tabsend_class;
1775
1776typedef struct _tabsend
1777{
1778 t_object x_obj;
1779 float *x_vec;
1780 int x_graphperiod;
1781 int x_graphcount;
1782 t_symbol *x_arrayname;
1783 t_clock *x_clock;
1784 float x_f;
1785} t_tabsend;
1786
1787static void tabsend_tick(t_tabsend *x);
1788
1789static void *tabsend_new(t_symbol *s)
1790{
1791 t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
1792 x->x_graphcount = 0;
1793 x->x_arrayname = s;
1794 x->x_clock = clock_new(x, (t_method)tabsend_tick);
1795 x->x_f = 0;
1796 return (x);
1797}
1798
1799static t_int *tabsend_perform(t_int *w)
1800{
1801 t_tabsend *x = (t_tabsend *)(w[1]);
1802 t_float *in = (t_float *)(w[2]);
1803 int n = w[3];
1804 t_float *dest = x->x_vec;
1805 int i = x->x_graphcount;
1806 if (!x->x_vec) goto bad;
1807
1808 while (n--)
1809 {
1810 float f = *in++;
1811 if (PD_BIGORSMALL(f))
1812 f = 0;
1813 *dest++ = f;
1814 }
1815 if (!i--)
1816 {
1817 clock_delay(x->x_clock, 0);
1818 i = x->x_graphperiod;
1819 }
1820 x->x_graphcount = i;
1821bad:
1822 return (w+4);
1823}
1824
1825static void tabsend_dsp(t_tabsend *x, t_signal **sp)
1826{
1827 int i, vecsize;
1828 t_garray *a;
1829
1830 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1831 {
1832 if (*x->x_arrayname->s_name)
1833 pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name);
1834 }
1835 else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
1836 pd_error(x, "%s: bad template for tabsend~", x->x_arrayname->s_name);
1837 else
1838 {
1839 int n = sp[0]->s_n;
1840 int ticksper = sp[0]->s_sr/n;
1841 if (ticksper < 1) ticksper = 1;
1842 x->x_graphperiod = ticksper;
1843 if (x->x_graphcount > ticksper) x->x_graphcount = ticksper;
1844 if (n < vecsize) vecsize = n;
1845 garray_usedindsp(a);
1846 dsp_add(tabsend_perform, 3, x, sp[0]->s_vec, vecsize);
1847 }
1848}
1849
1850static void tabsend_tick(t_tabsend *x)
1851{
1852 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
1853 if (!a) bug("tabsend_tick");
1854 else garray_redraw(a);
1855}
1856
1857static void tabsend_free(t_tabsend *x)
1858{
1859 clock_free(x->x_clock);
1860}
1861
1862static void tabsend_setup(void)
1863{
1864 tabsend_class = class_new(gensym("tabsend~"), (t_newmethod)tabsend_new,
1865 (t_method)tabsend_free, sizeof(t_tabsend), 0, A_DEFSYM, 0);
1866 CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, x_f);
1867 class_addmethod(tabsend_class, (t_method)tabsend_dsp, gensym("dsp"), 0);
1868}
1869
1870/* ------------------------ tabreceive~ ------------------------- */
1871
1872static t_class *tabreceive_class;
1873
1874typedef struct _tabreceive
1875{
1876 t_object x_obj;
1877 float *x_vec;
1878 t_symbol *x_arrayname;
1879} t_tabreceive;
1880
1881static t_int *tabreceive_perform(t_int *w)
1882{
1883 t_tabreceive *x = (t_tabreceive *)(w[1]);
1884 t_float *out = (t_float *)(w[2]);
1885 int n = w[3];
1886 t_float *from = x->x_vec;
1887 if (from) while (n--) *out++ = *from++;
1888 else while (n--) *out++ = 0;
1889 return (w+4);
1890}
1891
1892static void tabreceive_dsp(t_tabreceive *x, t_signal **sp)
1893{
1894 t_garray *a;
1895 int vecsize;
1896
1897 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1898 {
1899 if (*x->x_arrayname->s_name)
1900 pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name);
1901 }
1902 else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
1903 pd_error(x, "%s: bad template for tabreceive~", x->x_arrayname->s_name);
1904 else
1905 {
1906 int n = sp[0]->s_n;
1907 if (n < vecsize) vecsize = n;
1908 garray_usedindsp(a);
1909 dsp_add(tabreceive_perform, 3, x, sp[0]->s_vec, vecsize);
1910 }
1911}
1912
1913static void *tabreceive_new(t_symbol *s)
1914{
1915 t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
1916 x->x_arrayname = s;
1917 outlet_new(&x->x_obj, &s_signal);
1918 return (x);
1919}
1920
1921static void tabreceive_setup(void)
1922{
1923 tabreceive_class = class_new(gensym("tabreceive~"),
1924 (t_newmethod)tabreceive_new, 0,
1925 sizeof(t_tabreceive), 0, A_DEFSYM, 0);
1926 class_addmethod(tabreceive_class, (t_method)tabreceive_dsp,
1927 gensym("dsp"), 0);
1928}
1929
1930
1931/* ---------- tabread: control, non-interpolating ------------------------ */
1932
1933static t_class *tabread_class;
1934
1935typedef struct _tabread
1936{
1937 t_object x_obj;
1938 t_symbol *x_arrayname;
1939} t_tabread;
1940
1941static void tabread_float(t_tabread *x, t_float f)
1942{
1943 t_garray *a;
1944 int npoints;
1945 t_float *vec;
1946
1947 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1948 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
1949 else if (!garray_getfloatarray(a, &npoints, &vec))
1950 pd_error(x, "%s: bad template for tabread", x->x_arrayname->s_name);
1951 else
1952 {
1953 int n = f;
1954 if (n < 0) n = 0;
1955 else if (n >= npoints) n = npoints - 1;
1956 outlet_float(x->x_obj.ob_outlet, (npoints ? vec[n] : 0));
1957 }
1958}
1959
1960static void tabread_set(t_tabread *x, t_symbol *s)
1961{
1962 x->x_arrayname = s;
1963}
1964
1965static void *tabread_new(t_symbol *s)
1966{
1967 t_tabread *x = (t_tabread *)pd_new(tabread_class);
1968 x->x_arrayname = s;
1969 outlet_new(&x->x_obj, &s_float);
1970 return (x);
1971}
1972
1973static void tabread_setup(void)
1974{
1975 tabread_class = class_new(gensym("tabread"), (t_newmethod)tabread_new,
1976 0, sizeof(t_tabread), 0, A_DEFSYM, 0);
1977 class_addfloat(tabread_class, (t_method)tabread_float);
1978 class_addmethod(tabread_class, (t_method)tabread_set, gensym("set"),
1979 A_SYMBOL, 0);
1980}
1981
1982/* ---------- tabread4: control, non-interpolating ------------------------ */
1983
1984static t_class *tabread4_class;
1985
1986typedef struct _tabread4
1987{
1988 t_object x_obj;
1989 t_symbol *x_arrayname;
1990} t_tabread4;
1991
1992static void tabread4_float(t_tabread4 *x, t_float f)
1993{
1994 t_garray *a;
1995 int npoints;
1996 t_float *vec;
1997
1998 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
1999 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
2000 else if (!garray_getfloatarray(a, &npoints, &vec))
2001 pd_error(x, "%s: bad template for tabread4", x->x_arrayname->s_name);
2002 else if (npoints < 4)
2003 outlet_float(x->x_obj.ob_outlet, 0);
2004 else if (f <= 1)
2005 outlet_float(x->x_obj.ob_outlet, vec[1]);
2006 else if (f >= npoints - 2)
2007 outlet_float(x->x_obj.ob_outlet, vec[npoints - 2]);
2008 else
2009 {
2010 int n = f;
2011 float a, b, c, d, cminusb, frac, *fp;
2012 if (n >= npoints - 2)
2013 n = npoints - 3;
2014 fp = vec + n;
2015 frac = f - n;
2016 a = fp[-1];
2017 b = fp[0];
2018 c = fp[1];
2019 d = fp[2];
2020 cminusb = c-b;
2021 outlet_float(x->x_obj.ob_outlet, b + frac * (
2022 cminusb - 0.1666667f * (1.-frac) * (
2023 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))));
2024 }
2025}
2026
2027static void tabread4_set(t_tabread4 *x, t_symbol *s)
2028{
2029 x->x_arrayname = s;
2030}
2031
2032static void *tabread4_new(t_symbol *s)
2033{
2034 t_tabread4 *x = (t_tabread4 *)pd_new(tabread4_class);
2035 x->x_arrayname = s;
2036 outlet_new(&x->x_obj, &s_float);
2037 return (x);
2038}
2039
2040static void tabread4_setup(void)
2041{
2042 tabread4_class = class_new(gensym("tabread4"), (t_newmethod)tabread4_new,
2043 0, sizeof(t_tabread4), 0, A_DEFSYM, 0);
2044 class_addfloat(tabread4_class, (t_method)tabread4_float);
2045 class_addmethod(tabread4_class, (t_method)tabread4_set, gensym("set"),
2046 A_SYMBOL, 0);
2047}
2048
2049/* ------------------ tabwrite: control ------------------------ */
2050
2051static t_class *tabwrite_class;
2052
2053typedef struct _tabwrite
2054{
2055 t_object x_obj;
2056 t_symbol *x_arrayname;
2057 t_clock *x_clock;
2058 float x_ft1;
2059 double x_updtime;
2060 int x_set;
2061} t_tabwrite;
2062
2063static void tabwrite_tick(t_tabwrite *x)
2064{
2065 t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
2066 if (!a) bug("tabwrite_tick");
2067 else garray_redraw(a);
2068 x->x_set = 0;
2069 x->x_updtime = clock_getsystime();
2070}
2071
2072static void tabwrite_float(t_tabwrite *x, t_float f)
2073{
2074 int i, vecsize;
2075 t_garray *a;
2076 t_float *vec;
2077
2078 if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
2079 pd_error(x, "%s: no such array", x->x_arrayname->s_name);
2080 else if (!garray_getfloatarray(a, &vecsize, &vec))
2081 pd_error(x, "%s: bad template for tabwrite", x->x_arrayname->s_name);
2082 else
2083 {
2084 int n = x->x_ft1;
2085 double timesince = clock_gettimesince(x->x_updtime);
2086 if (n < 0) n = 0;
2087 else if (n >= vecsize) n = vecsize-1;
2088 vec[n] = f;
2089 if (timesince > 1000)
2090 {
2091 tabwrite_tick(x);
2092 }
2093 else
2094 {
2095 if (x->x_set == 0)
2096 {
2097 clock_delay(x->x_clock, 1000 - timesince);
2098 x->x_set = 1;
2099 }
2100 }
2101 }
2102}
2103
2104static void tabwrite_set(t_tabwrite *x, t_symbol *s)
2105{
2106 x->x_arrayname = s;
2107}
2108
2109static void tabwrite_free(t_tabwrite *x)
2110{
2111 clock_free(x->x_clock);
2112}
2113
2114static void *tabwrite_new(t_symbol *s)
2115{
2116 t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
2117 x->x_ft1 = 0;
2118 x->x_arrayname = s;
2119 x->x_updtime = clock_getsystime();
2120 x->x_clock = clock_new(x, (t_method)tabwrite_tick);
2121 floatinlet_new(&x->x_obj, &x->x_ft1);
2122 return (x);
2123}
2124
2125void tabwrite_setup(void)
2126{
2127 tabwrite_class = class_new(gensym("tabwrite"), (t_newmethod)tabwrite_new,
2128 (t_method)tabwrite_free, sizeof(t_tabwrite), 0, A_DEFSYM, 0);
2129 class_addfloat(tabwrite_class, (t_method)tabwrite_float);
2130 class_addmethod(tabwrite_class, (t_method)tabwrite_set, gensym("set"), A_SYMBOL, 0);
2131}
2132
2133/* ------------------------ global setup routine ------------------------- */
2134
2135void d_array_setup(void)
2136{
2137 tabwrite_tilde_setup();
2138 tabplay_tilde_setup();
2139 tabread_tilde_setup();
2140 tabread4_tilde_setup();
2141 tabosc4_tilde_setup();
2142 tabsend_setup();
2143 tabreceive_setup();
2144 tabread_setup();
2145 tabread4_setup();
2146 tabwrite_setup();
2147}
2148
diff --git a/apps/plugins/pdbox/PDa/src/d_ctl.c b/apps/plugins/pdbox/PDa/src/d_ctl.c
new file mode 100644
index 0000000000..d3262af800
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_ctl.c
@@ -0,0 +1,1568 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* sig~ and line~ control-to-signal converters;
6 snapshot~ signal-to-control converter.
7*/
8
9#include "m_pd.h"
10#include "math.h"
11
12/* -------------------------- sig~ ------------------------------ */
13static t_class *sig_tilde_class;
14
15typedef struct _sig
16{
17 t_object x_obj;
18 float x_f;
19} t_sig;
20
21static t_int *sig_tilde_perform(t_int *w)
22{
23 t_float f = *(t_float *)(w[1]);
24 t_float *out = (t_float *)(w[2]);
25 int n = (int)(w[3]);
26 while (n--)
27 *out++ = f;
28 return (w+4);
29}
30
31static t_int *sig_tilde_perf8(t_int *w)
32{
33 t_float f = *(t_float *)(w[1]);
34 t_float *out = (t_float *)(w[2]);
35 int n = (int)(w[3]);
36
37 for (; n; n -= 8, out += 8)
38 {
39 out[0] = f;
40 out[1] = f;
41 out[2] = f;
42 out[3] = f;
43 out[4] = f;
44 out[5] = f;
45 out[6] = f;
46 out[7] = f;
47 }
48 return (w+4);
49}
50
51void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
52{
53 if (n&7)
54 dsp_add(sig_tilde_perform, 3, in, out, n);
55 else
56 dsp_add(sig_tilde_perf8, 3, in, out, n);
57}
58
59static void sig_tilde_float(t_sig *x, t_float f)
60{
61 x->x_f = f;
62}
63
64static void sig_tilde_dsp(t_sig *x, t_signal **sp)
65{
66 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
67}
68
69static void *sig_tilde_new(t_floatarg f)
70{
71 t_sig *x = (t_sig *)pd_new(sig_tilde_class);
72 x->x_f = f;
73 outlet_new(&x->x_obj, gensym("signal"));
74 return (x);
75}
76
77static void sig_tilde_setup(void)
78{
79 sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
80 sizeof(t_sig), 0, A_DEFFLOAT, 0);
81 class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
82 class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
83}
84
85
86#ifndef FIXEDPOINT
87
88/* -------------------------- line~ ------------------------------ */
89static t_class *line_tilde_class;
90
91typedef struct _line
92{
93 t_object x_obj;
94 float x_target;
95 float x_value;
96 float x_biginc;
97 float x_inc;
98 float x_1overn;
99 float x_dspticktomsec;
100 float x_inletvalue;
101 float x_inletwas;
102 int x_ticksleft;
103 int x_retarget;
104} t_line;
105
106static t_int *line_tilde_perform(t_int *w)
107{
108 t_line *x = (t_line *)(w[1]);
109 t_float *out = (t_float *)(w[2]);
110 int n = (int)(w[3]);
111 float f = x->x_value;
112
113 if (PD_BIGORSMALL(f))
114 x->x_value = f = 0;
115 if (x->x_retarget)
116 {
117 int nticks = x->x_inletwas * x->x_dspticktomsec;
118 if (!nticks) nticks = 1;
119 x->x_ticksleft = nticks;
120 x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
121 x->x_inc = x->x_1overn * x->x_biginc;
122 x->x_retarget = 0;
123 }
124 if (x->x_ticksleft)
125 {
126 float f = x->x_value;
127 while (n--) *out++ = f, f += x->x_inc;
128 x->x_value += x->x_biginc;
129 x->x_ticksleft--;
130 }
131 else
132 {
133 x->x_value = x->x_target;
134 while (n--) *out++ = x->x_value;
135 }
136 return (w+4);
137}
138
139static void line_tilde_float(t_line *x, t_float f)
140{
141 if (x->x_inletvalue <= 0)
142 {
143 x->x_target = x->x_value = f;
144 x->x_ticksleft = x->x_retarget = 0;
145 }
146 else
147 {
148 x->x_target = f;
149 x->x_retarget = 1;
150 x->x_inletwas = x->x_inletvalue;
151 x->x_inletvalue = 0;
152 }
153}
154
155static void line_tilde_stop(t_line *x)
156{
157 x->x_target = x->x_value;
158 x->x_ticksleft = x->x_retarget = 0;
159}
160
161static void line_tilde_dsp(t_line *x, t_signal **sp)
162{
163 dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
164 x->x_1overn = 1./sp[0]->s_n;
165 x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n);
166}
167
168static void *line_tilde_new(void)
169{
170 t_line *x = (t_line *)pd_new(line_tilde_class);
171 outlet_new(&x->x_obj, gensym("signal"));
172 floatinlet_new(&x->x_obj, &x->x_inletvalue);
173 x->x_ticksleft = x->x_retarget = 0;
174 x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
175 return (x);
176}
177
178static void line_tilde_setup(void)
179{
180 line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0,
181 sizeof(t_line), 0, 0);
182 class_addfloat(line_tilde_class, (t_method)line_tilde_float);
183 class_addmethod(line_tilde_class, (t_method)line_tilde_dsp,
184 gensym("dsp"), 0);
185 class_addmethod(line_tilde_class, (t_method)line_tilde_stop,
186 gensym("stop"), 0);
187}
188
189/* -------------------------- vline~ ------------------------------ */
190static t_class *vline_tilde_class;
191
192typedef struct _vseg
193{
194 double s_targettime;
195 double s_starttime;
196 float s_target;
197 struct _vseg *s_next;
198} t_vseg;
199
200typedef struct _vline
201{
202 t_object x_obj;
203 double x_value;
204 double x_inc;
205 double x_referencetime;
206 double x_samppermsec;
207 double x_msecpersamp;
208 double x_targettime;
209 float x_target;
210 float x_inlet1;
211 float x_inlet2;
212 t_vseg *x_list;
213} t_vline;
214
215static t_int *vline_tilde_perform(t_int *w)
216{
217 t_vline *x = (t_vline *)(w[1]);
218 t_float *out = (t_float *)(w[2]);
219 int n = (int)(w[3]), i;
220 double f = x->x_value;
221 double inc = x->x_inc;
222 double msecpersamp = x->x_msecpersamp;
223 double samppermsec = x->x_samppermsec;
224 double timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
225 t_vseg *s = x->x_list;
226 for (i = 0; i < n; i++)
227 {
228 double timenext = timenow + msecpersamp;
229 checknext:
230 if (s)
231 {
232 /* has starttime elapsed? If so update value and increment */
233 if (s->s_starttime < timenext)
234 {
235 if (x->x_targettime <= timenext)
236 f = x->x_target, inc = 0;
237 /* if zero-length segment bash output value */
238 if (s->s_targettime <= s->s_starttime)
239 {
240 f = s->s_target;
241 inc = 0;
242 }
243 else
244 {
245 double incpermsec = (s->s_target - f)/
246 (s->s_targettime - s->s_starttime);
247 f = f + incpermsec * (timenext - s->s_starttime);
248 inc = incpermsec * msecpersamp;
249 }
250 x->x_inc = inc;
251 x->x_target = s->s_target;
252 x->x_targettime = s->s_targettime;
253 x->x_list = s->s_next;
254 t_freebytes(s, sizeof(*s));
255 s = x->x_list;
256 goto checknext;
257 }
258 }
259 if (x->x_targettime <= timenext)
260 f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20;
261 *out++ = f;
262 f = f + inc;
263 timenow = timenext;
264 }
265 x->x_value = f;
266 return (w+4);
267}
268
269static void vline_tilde_stop(t_vline *x)
270{
271 t_vseg *s1, *s2;
272 for (s1 = x->x_list; s1; s1 = s2)
273 s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
274 x->x_list = 0;
275 x->x_inc = 0;
276 x->x_inlet1 = x->x_inlet2 = 0;
277 x->x_target = x->x_value;
278 x->x_targettime = 1e20;
279}
280
281static void vline_tilde_float(t_vline *x, t_float f)
282{
283 double timenow = clock_gettimesince(x->x_referencetime);
284 float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1);
285 float inlet2 = x->x_inlet2;
286 double starttime = timenow + inlet2;
287 t_vseg *s1, *s2, *deletefrom = 0, *snew;
288 if (PD_BIGORSMALL(f))
289 f = 0;
290
291 /* negative delay input means stop and jump immediately to new value */
292 if (inlet2 < 0)
293 {
294 x->x_value = f;
295 vline_tilde_stop(x);
296 return;
297 }
298 snew = (t_vseg *)t_getbytes(sizeof(*snew));
299 /* check if we supplant the first item in the list. We supplant
300 an item by having an earlier starttime, or an equal starttime unless
301 the equal one was instantaneous and the new one isn't (in which case
302 we'll do a jump-and-slide starting at that time.) */
303 if (!x->x_list || x->x_list->s_starttime > starttime ||
304 (x->x_list->s_starttime == starttime &&
305 (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
306 {
307 deletefrom = x->x_list;
308 x->x_list = snew;
309 }
310 else
311 {
312 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
313 {
314 if (s2->s_starttime > starttime ||
315 (s2->s_starttime == starttime &&
316 (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
317 {
318 deletefrom = s2;
319 s1->s_next = snew;
320 goto didit;
321 }
322 }
323 s1->s_next = snew;
324 deletefrom = 0;
325 didit: ;
326 }
327 while (deletefrom)
328 {
329 s1 = deletefrom->s_next;
330 t_freebytes(deletefrom, sizeof(*deletefrom));
331 deletefrom = s1;
332 }
333 snew->s_next = 0;
334 snew->s_target = f;
335 snew->s_starttime = starttime;
336 snew->s_targettime = starttime + inlet1;
337 x->x_inlet1 = x->x_inlet2 = 0;
338}
339
340static void vline_tilde_dsp(t_vline *x, t_signal **sp)
341{
342 dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
343 x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000;
344 x->x_msecpersamp = ((double)1000) / sp[0]->s_sr;
345}
346
347static void *vline_tilde_new(void)
348{
349 t_vline *x = (t_vline *)pd_new(vline_tilde_class);
350 outlet_new(&x->x_obj, gensym("signal"));
351 floatinlet_new(&x->x_obj, &x->x_inlet1);
352 floatinlet_new(&x->x_obj, &x->x_inlet2);
353 x->x_inlet1 = x->x_inlet2 = 0;
354 x->x_value = x->x_inc = 0;
355 x->x_referencetime = clock_getlogicaltime();
356 x->x_list = 0;
357 x->x_samppermsec = 0;
358 x->x_targettime = 1e20;
359 return (x);
360}
361
362static void vline_tilde_setup(void)
363{
364 vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
365 (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
366 class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
367 class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
368 gensym("dsp"), 0);
369 class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
370 gensym("stop"), 0);
371}
372
373/* -------------------------- snapshot~ ------------------------------ */
374static t_class *snapshot_tilde_class;
375
376typedef struct _snapshot
377{
378 t_object x_obj;
379 t_sample x_value;
380 float x_f;
381} t_snapshot;
382
383static void *snapshot_tilde_new(void)
384{
385 t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
386 x->x_value = 0;
387 outlet_new(&x->x_obj, &s_float);
388 x->x_f = 0;
389 return (x);
390}
391
392static t_int *snapshot_tilde_perform(t_int *w)
393{
394 t_float *in = (t_float *)(w[1]);
395 t_float *out = (t_float *)(w[2]);
396 *out = *in;
397 return (w+3);
398}
399
400static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
401{
402 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
403 &x->x_value);
404}
405
406static void snapshot_tilde_bang(t_snapshot *x)
407{
408 outlet_float(x->x_obj.ob_outlet, x->x_value);
409}
410
411static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
412{
413 x->x_value = f;
414}
415
416static void snapshot_tilde_setup(void)
417{
418 snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
419 sizeof(t_snapshot), 0, 0);
420 CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
421 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
422 gensym("dsp"), 0);
423 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
424 gensym("set"), A_DEFFLOAT, 0);
425 class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
426}
427
428/* -------------------------- vsnapshot~ ------------------------------ */
429static t_class *vsnapshot_tilde_class;
430
431typedef struct _vsnapshot
432{
433 t_object x_obj;
434 int x_n;
435 int x_gotone;
436 t_sample *x_vec;
437 float x_f;
438 float x_sampspermsec;
439 double x_time;
440} t_vsnapshot;
441
442static void *vsnapshot_tilde_new(void)
443{
444 t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
445 outlet_new(&x->x_obj, &s_float);
446 x->x_f = 0;
447 x->x_n = 0;
448 x->x_vec = 0;
449 x->x_gotone = 0;
450 return (x);
451}
452
453static t_int *vsnapshot_tilde_perform(t_int *w)
454{
455 t_float *in = (t_float *)(w[1]);
456 t_vsnapshot *x = (t_vsnapshot *)(w[2]);
457 t_float *out = x->x_vec;
458 int n = x->x_n, i;
459 for (i = 0; i < n; i++)
460 out[i] = in[i];
461 x->x_time = clock_getlogicaltime();
462 x->x_gotone = 1;
463 return (w+3);
464}
465
466static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
467{
468 int n = sp[0]->s_n;
469 if (n != x->x_n)
470 {
471 if (x->x_vec)
472 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
473 x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
474 x->x_gotone = 0;
475 x->x_n = n;
476 }
477 x->x_sampspermsec = sp[0]->s_sr / 1000;
478 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
479}
480
481static void vsnapshot_tilde_bang(t_vsnapshot *x)
482{
483 float val;
484 if (x->x_gotone)
485 {
486 int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
487 if (indx < 0)
488 indx = 0;
489 else if (indx >= x->x_n)
490 indx = x->x_n - 1;
491 val = x->x_vec[indx];
492 }
493 else val = 0;
494 outlet_float(x->x_obj.ob_outlet, val);
495}
496
497static void vsnapshot_tilde_ff(t_vsnapshot *x)
498{
499 if (x->x_vec)
500 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
501}
502
503static void vsnapshot_tilde_setup(void)
504{
505 vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
506 vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
507 sizeof(t_vsnapshot), 0, 0);
508 CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
509 class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
510 class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
511}
512
513
514/* ---------------- env~ - simple envelope follower. ----------------- */
515
516#define MAXOVERLAP 10
517#define MAXVSTAKEN 64
518
519typedef struct sigenv
520{
521 t_object x_obj; /* header */
522 void *x_outlet; /* a "float" outlet */
523 void *x_clock; /* a "clock" object */
524 float *x_buf; /* a Hanning window */
525 int x_phase; /* number of points since last output */
526 int x_period; /* requested period of output */
527 int x_realperiod; /* period rounded up to vecsize multiple */
528 int x_npoints; /* analysis window size in samples */
529 float x_result; /* result to output */
530 float x_sumbuf[MAXOVERLAP]; /* summing buffer */
531 float x_f;
532} t_sigenv;
533
534t_class *env_tilde_class;
535static void env_tilde_tick(t_sigenv *x);
536
537static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
538{
539 int npoints = fnpoints;
540 int period = fperiod;
541 t_sigenv *x;
542 float *buf;
543 int i;
544
545 if (npoints < 1) npoints = 1024;
546 if (period < 1) period = npoints/2;
547 if (period < npoints / MAXOVERLAP + 1)
548 period = npoints / MAXOVERLAP + 1;
549 if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
550 {
551 error("env: couldn't allocate buffer");
552 return (0);
553 }
554 x = (t_sigenv *)pd_new(env_tilde_class);
555 x->x_buf = buf;
556 x->x_npoints = npoints;
557 x->x_phase = 0;
558 x->x_period = period;
559 for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
560 for (i = 0; i < npoints; i++)
561 buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
562 for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
563 x->x_clock = clock_new(x, (t_method)env_tilde_tick);
564 x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
565 x->x_f = 0;
566 return (x);
567}
568
569static t_int *env_tilde_perform(t_int *w)
570{
571 t_sigenv *x = (t_sigenv *)(w[1]);
572 t_float *in = (t_float *)(w[2]);
573 int n = (int)(w[3]);
574 int count;
575 float *sump;
576 in += n;
577 for (count = x->x_phase, sump = x->x_sumbuf;
578 count < x->x_npoints; count += x->x_realperiod, sump++)
579 {
580 float *hp = x->x_buf + count;
581 float *fp = in;
582 float sum = *sump;
583 int i;
584
585 for (i = 0; i < n; i++)
586 {
587 fp--;
588 sum += *hp++ * (*fp * *fp);
589 }
590 *sump = sum;
591 }
592 sump[0] = 0;
593 x->x_phase -= n;
594 if (x->x_phase < 0)
595 {
596 x->x_result = x->x_sumbuf[0];
597 for (count = x->x_realperiod, sump = x->x_sumbuf;
598 count < x->x_npoints; count += x->x_realperiod, sump++)
599 sump[0] = sump[1];
600 sump[0] = 0;
601 x->x_phase = x->x_realperiod - n;
602 clock_delay(x->x_clock, 0L);
603 }
604 return (w+4);
605}
606
607static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
608{
609 if (x->x_period % sp[0]->s_n) x->x_realperiod =
610 x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
611 else x->x_realperiod = x->x_period;
612 dsp_add(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
613 if (sp[0]->s_n > MAXVSTAKEN) bug("env_tilde_dsp");
614}
615
616static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
617{
618 outlet_float(x->x_outlet, powtodb(x->x_result));
619}
620
621static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
622{
623 clock_free(x->x_clock);
624 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
625}
626
627
628void env_tilde_setup(void )
629{
630 env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new,
631 (t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
632 CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f);
633 class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, gensym("dsp"), 0);
634}
635
636/* --------------------- threshold~ ----------------------------- */
637
638static t_class *threshold_tilde_class;
639
640typedef struct _threshold_tilde
641{
642 t_object x_obj;
643 t_outlet *x_outlet1; /* bang out for high thresh */
644 t_outlet *x_outlet2; /* bang out for low thresh */
645 t_clock *x_clock; /* wakeup for message output */
646 float x_f; /* scalar inlet */
647 int x_state; /* 1 = high, 0 = low */
648 float x_hithresh; /* value of high threshold */
649 float x_lothresh; /* value of low threshold */
650 float x_deadwait; /* msec remaining in dead period */
651 float x_msecpertick; /* msec per DSP tick */
652 float x_hideadtime; /* hi dead time in msec */
653 float x_lodeadtime; /* lo dead time in msec */
654} t_threshold_tilde;
655
656static void threshold_tilde_tick(t_threshold_tilde *x);
657static void threshold_tilde_set(t_threshold_tilde *x,
658 t_floatarg hithresh, t_floatarg hideadtime,
659 t_floatarg lothresh, t_floatarg lodeadtime);
660
661static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
662 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
663{
664 t_threshold_tilde *x = (t_threshold_tilde *)
665 pd_new(threshold_tilde_class);
666 x->x_state = 0; /* low state */
667 x->x_deadwait = 0; /* no dead time */
668 x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
669 x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
670 x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
671 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
672 x->x_msecpertick = 0.;
673 x->x_f = 0;
674 threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
675 return (x);
676}
677
678 /* "set" message to specify thresholds and dead times */
679static void threshold_tilde_set(t_threshold_tilde *x,
680 t_floatarg hithresh, t_floatarg hideadtime,
681 t_floatarg lothresh, t_floatarg lodeadtime)
682{
683 if (lothresh > hithresh)
684 lothresh = hithresh;
685 x->x_hithresh = hithresh;
686 x->x_hideadtime = hideadtime;
687 x->x_lothresh = lothresh;
688 x->x_lodeadtime = lodeadtime;
689}
690
691 /* number in inlet sets state -- note incompatible with JMAX which used
692 "int" message for this, impossible here because of auto signal conversion */
693static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
694{
695 x->x_state = (f != 0);
696 x->x_deadwait = 0;
697}
698
699static void threshold_tilde_tick(t_threshold_tilde *x)
700{
701 if (x->x_state)
702 outlet_bang(x->x_outlet1);
703 else outlet_bang(x->x_outlet2);
704}
705
706static t_int *threshold_tilde_perform(t_int *w)
707{
708 float *in1 = (float *)(w[1]);
709 t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
710 int n = (t_int)(w[3]);
711 if (x->x_deadwait > 0)
712 x->x_deadwait -= x->x_msecpertick;
713 else if (x->x_state)
714 {
715 /* we're high; look for low sample */
716 for (; n--; in1++)
717 {
718 if (*in1 < x->x_lothresh)
719 {
720 clock_delay(x->x_clock, 0L);
721 x->x_state = 0;
722 x->x_deadwait = x->x_lodeadtime;
723 goto done;
724 }
725 }
726 }
727 else
728 {
729 /* we're low; look for high sample */
730 for (; n--; in1++)
731 {
732 if (*in1 >= x->x_hithresh)
733 {
734 clock_delay(x->x_clock, 0L);
735 x->x_state = 1;
736 x->x_deadwait = x->x_hideadtime;
737 goto done;
738 }
739 }
740 }
741done:
742 return (w+4);
743}
744
745void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
746{
747 x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
748 dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
749}
750
751static void threshold_tilde_ff(t_threshold_tilde *x)
752{
753 clock_free(x->x_clock);
754}
755
756static void threshold_tilde_setup( void)
757{
758 threshold_tilde_class = class_new(gensym("threshold~"),
759 (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
760 sizeof(t_threshold_tilde), 0,
761 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
762 CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
763 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
764 gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
765 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
766 gensym("ft1"), A_FLOAT, 0);
767 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
768 gensym("dsp"), 0);
769}
770
771/* ------------------------ global setup routine ------------------------- */
772
773void d_ctl_setup(void)
774{
775 sig_tilde_setup();
776 line_tilde_setup();
777 vline_tilde_setup();
778 snapshot_tilde_setup();
779 vsnapshot_tilde_setup();
780 env_tilde_setup();
781 threshold_tilde_setup();
782}
783
784#endif
785/* Copyright (c) 1997-1999 Miller Puckette.
786* For information on usage and redistribution, and for a DISCLAIMER OF ALL
787* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
788
789/* sig~ and line~ control-to-signal converters;
790 snapshot~ signal-to-control converter.
791*/
792
793#include "m_pd.h"
794#include "math.h"
795
796/* -------------------------- sig~ ------------------------------ */
797static t_class *sig_tilde_class;
798
799typedef struct _sig
800{
801 t_object x_obj;
802 float x_f;
803} t_sig;
804
805static t_int *sig_tilde_perform(t_int *w)
806{
807 t_float f = *(t_float *)(w[1]);
808 t_float *out = (t_float *)(w[2]);
809 int n = (int)(w[3]);
810 while (n--)
811 *out++ = f;
812 return (w+4);
813}
814
815static t_int *sig_tilde_perf8(t_int *w)
816{
817 t_float f = *(t_float *)(w[1]);
818 t_float *out = (t_float *)(w[2]);
819 int n = (int)(w[3]);
820
821 for (; n; n -= 8, out += 8)
822 {
823 out[0] = f;
824 out[1] = f;
825 out[2] = f;
826 out[3] = f;
827 out[4] = f;
828 out[5] = f;
829 out[6] = f;
830 out[7] = f;
831 }
832 return (w+4);
833}
834
835void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
836{
837 if (n&7)
838 dsp_add(sig_tilde_perform, 3, in, out, n);
839 else
840 dsp_add(sig_tilde_perf8, 3, in, out, n);
841}
842
843static void sig_tilde_float(t_sig *x, t_float f)
844{
845 x->x_f = f;
846}
847
848static void sig_tilde_dsp(t_sig *x, t_signal **sp)
849{
850 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
851}
852
853static void *sig_tilde_new(t_floatarg f)
854{
855 t_sig *x = (t_sig *)pd_new(sig_tilde_class);
856 x->x_f = f;
857 outlet_new(&x->x_obj, gensym("signal"));
858 return (x);
859}
860
861static void sig_tilde_setup(void)
862{
863 sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
864 sizeof(t_sig), 0, A_DEFFLOAT, 0);
865 class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
866 class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
867}
868
869
870#ifndef FIXEDPOINT
871
872/* -------------------------- line~ ------------------------------ */
873static t_class *line_tilde_class;
874
875typedef struct _line
876{
877 t_object x_obj;
878 float x_target;
879 float x_value;
880 float x_biginc;
881 float x_inc;
882 float x_1overn;
883 float x_dspticktomsec;
884 float x_inletvalue;
885 float x_inletwas;
886 int x_ticksleft;
887 int x_retarget;
888} t_line;
889
890static t_int *line_tilde_perform(t_int *w)
891{
892 t_line *x = (t_line *)(w[1]);
893 t_float *out = (t_float *)(w[2]);
894 int n = (int)(w[3]);
895 float f = x->x_value;
896
897 if (PD_BIGORSMALL(f))
898 x->x_value = f = 0;
899 if (x->x_retarget)
900 {
901 int nticks = x->x_inletwas * x->x_dspticktomsec;
902 if (!nticks) nticks = 1;
903 x->x_ticksleft = nticks;
904 x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
905 x->x_inc = x->x_1overn * x->x_biginc;
906 x->x_retarget = 0;
907 }
908 if (x->x_ticksleft)
909 {
910 float f = x->x_value;
911 while (n--) *out++ = f, f += x->x_inc;
912 x->x_value += x->x_biginc;
913 x->x_ticksleft--;
914 }
915 else
916 {
917 x->x_value = x->x_target;
918 while (n--) *out++ = x->x_value;
919 }
920 return (w+4);
921}
922
923static void line_tilde_float(t_line *x, t_float f)
924{
925 if (x->x_inletvalue <= 0)
926 {
927 x->x_target = x->x_value = f;
928 x->x_ticksleft = x->x_retarget = 0;
929 }
930 else
931 {
932 x->x_target = f;
933 x->x_retarget = 1;
934 x->x_inletwas = x->x_inletvalue;
935 x->x_inletvalue = 0;
936 }
937}
938
939static void line_tilde_stop(t_line *x)
940{
941 x->x_target = x->x_value;
942 x->x_ticksleft = x->x_retarget = 0;
943}
944
945static void line_tilde_dsp(t_line *x, t_signal **sp)
946{
947 dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
948 x->x_1overn = 1./sp[0]->s_n;
949 x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n);
950}
951
952static void *line_tilde_new(void)
953{
954 t_line *x = (t_line *)pd_new(line_tilde_class);
955 outlet_new(&x->x_obj, gensym("signal"));
956 floatinlet_new(&x->x_obj, &x->x_inletvalue);
957 x->x_ticksleft = x->x_retarget = 0;
958 x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
959 return (x);
960}
961
962static void line_tilde_setup(void)
963{
964 line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0,
965 sizeof(t_line), 0, 0);
966 class_addfloat(line_tilde_class, (t_method)line_tilde_float);
967 class_addmethod(line_tilde_class, (t_method)line_tilde_dsp,
968 gensym("dsp"), 0);
969 class_addmethod(line_tilde_class, (t_method)line_tilde_stop,
970 gensym("stop"), 0);
971}
972
973/* -------------------------- vline~ ------------------------------ */
974static t_class *vline_tilde_class;
975
976typedef struct _vseg
977{
978 double s_targettime;
979 double s_starttime;
980 float s_target;
981 struct _vseg *s_next;
982} t_vseg;
983
984typedef struct _vline
985{
986 t_object x_obj;
987 double x_value;
988 double x_inc;
989 double x_referencetime;
990 double x_samppermsec;
991 double x_msecpersamp;
992 double x_targettime;
993 float x_target;
994 float x_inlet1;
995 float x_inlet2;
996 t_vseg *x_list;
997} t_vline;
998
999static t_int *vline_tilde_perform(t_int *w)
1000{
1001 t_vline *x = (t_vline *)(w[1]);
1002 t_float *out = (t_float *)(w[2]);
1003 int n = (int)(w[3]), i;
1004 double f = x->x_value;
1005 double inc = x->x_inc;
1006 double msecpersamp = x->x_msecpersamp;
1007 double samppermsec = x->x_samppermsec;
1008 double timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
1009 t_vseg *s = x->x_list;
1010 for (i = 0; i < n; i++)
1011 {
1012 double timenext = timenow + msecpersamp;
1013 checknext:
1014 if (s)
1015 {
1016 /* has starttime elapsed? If so update value and increment */
1017 if (s->s_starttime < timenext)
1018 {
1019 if (x->x_targettime <= timenext)
1020 f = x->x_target, inc = 0;
1021 /* if zero-length segment bash output value */
1022 if (s->s_targettime <= s->s_starttime)
1023 {
1024 f = s->s_target;
1025 inc = 0;
1026 }
1027 else
1028 {
1029 double incpermsec = (s->s_target - f)/
1030 (s->s_targettime - s->s_starttime);
1031 f = f + incpermsec * (timenext - s->s_starttime);
1032 inc = incpermsec * msecpersamp;
1033 }
1034 x->x_inc = inc;
1035 x->x_target = s->s_target;
1036 x->x_targettime = s->s_targettime;
1037 x->x_list = s->s_next;
1038 t_freebytes(s, sizeof(*s));
1039 s = x->x_list;
1040 goto checknext;
1041 }
1042 }
1043 if (x->x_targettime <= timenext)
1044 f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20;
1045 *out++ = f;
1046 f = f + inc;
1047 timenow = timenext;
1048 }
1049 x->x_value = f;
1050 return (w+4);
1051}
1052
1053static void vline_tilde_stop(t_vline *x)
1054{
1055 t_vseg *s1, *s2;
1056 for (s1 = x->x_list; s1; s1 = s2)
1057 s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
1058 x->x_list = 0;
1059 x->x_inc = 0;
1060 x->x_inlet1 = x->x_inlet2 = 0;
1061 x->x_target = x->x_value;
1062 x->x_targettime = 1e20;
1063}
1064
1065static void vline_tilde_float(t_vline *x, t_float f)
1066{
1067 double timenow = clock_gettimesince(x->x_referencetime);
1068 float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1);
1069 float inlet2 = x->x_inlet2;
1070 double starttime = timenow + inlet2;
1071 t_vseg *s1, *s2, *deletefrom = 0, *snew;
1072 if (PD_BIGORSMALL(f))
1073 f = 0;
1074
1075 /* negative delay input means stop and jump immediately to new value */
1076 if (inlet2 < 0)
1077 {
1078 x->x_value = f;
1079 vline_tilde_stop(x);
1080 return;
1081 }
1082 snew = (t_vseg *)t_getbytes(sizeof(*snew));
1083 /* check if we supplant the first item in the list. We supplant
1084 an item by having an earlier starttime, or an equal starttime unless
1085 the equal one was instantaneous and the new one isn't (in which case
1086 we'll do a jump-and-slide starting at that time.) */
1087 if (!x->x_list || x->x_list->s_starttime > starttime ||
1088 (x->x_list->s_starttime == starttime &&
1089 (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
1090 {
1091 deletefrom = x->x_list;
1092 x->x_list = snew;
1093 }
1094 else
1095 {
1096 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
1097 {
1098 if (s2->s_starttime > starttime ||
1099 (s2->s_starttime == starttime &&
1100 (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
1101 {
1102 deletefrom = s2;
1103 s1->s_next = snew;
1104 goto didit;
1105 }
1106 }
1107 s1->s_next = snew;
1108 deletefrom = 0;
1109 didit: ;
1110 }
1111 while (deletefrom)
1112 {
1113 s1 = deletefrom->s_next;
1114 t_freebytes(deletefrom, sizeof(*deletefrom));
1115 deletefrom = s1;
1116 }
1117 snew->s_next = 0;
1118 snew->s_target = f;
1119 snew->s_starttime = starttime;
1120 snew->s_targettime = starttime + inlet1;
1121 x->x_inlet1 = x->x_inlet2 = 0;
1122}
1123
1124static void vline_tilde_dsp(t_vline *x, t_signal **sp)
1125{
1126 dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
1127 x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000;
1128 x->x_msecpersamp = ((double)1000) / sp[0]->s_sr;
1129}
1130
1131static void *vline_tilde_new(void)
1132{
1133 t_vline *x = (t_vline *)pd_new(vline_tilde_class);
1134 outlet_new(&x->x_obj, gensym("signal"));
1135 floatinlet_new(&x->x_obj, &x->x_inlet1);
1136 floatinlet_new(&x->x_obj, &x->x_inlet2);
1137 x->x_inlet1 = x->x_inlet2 = 0;
1138 x->x_value = x->x_inc = 0;
1139 x->x_referencetime = clock_getlogicaltime();
1140 x->x_list = 0;
1141 x->x_samppermsec = 0;
1142 x->x_targettime = 1e20;
1143 return (x);
1144}
1145
1146static void vline_tilde_setup(void)
1147{
1148 vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
1149 (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
1150 class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
1151 class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
1152 gensym("dsp"), 0);
1153 class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
1154 gensym("stop"), 0);
1155}
1156
1157/* -------------------------- snapshot~ ------------------------------ */
1158static t_class *snapshot_tilde_class;
1159
1160typedef struct _snapshot
1161{
1162 t_object x_obj;
1163 t_sample x_value;
1164 float x_f;
1165} t_snapshot;
1166
1167static void *snapshot_tilde_new(void)
1168{
1169 t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
1170 x->x_value = 0;
1171 outlet_new(&x->x_obj, &s_float);
1172 x->x_f = 0;
1173 return (x);
1174}
1175
1176static t_int *snapshot_tilde_perform(t_int *w)
1177{
1178 t_float *in = (t_float *)(w[1]);
1179 t_float *out = (t_float *)(w[2]);
1180 *out = *in;
1181 return (w+3);
1182}
1183
1184static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
1185{
1186 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
1187 &x->x_value);
1188}
1189
1190static void snapshot_tilde_bang(t_snapshot *x)
1191{
1192 outlet_float(x->x_obj.ob_outlet, x->x_value);
1193}
1194
1195static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
1196{
1197 x->x_value = f;
1198}
1199
1200static void snapshot_tilde_setup(void)
1201{
1202 snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
1203 sizeof(t_snapshot), 0, 0);
1204 CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
1205 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
1206 gensym("dsp"), 0);
1207 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
1208 gensym("set"), A_DEFFLOAT, 0);
1209 class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
1210}
1211
1212/* -------------------------- vsnapshot~ ------------------------------ */
1213static t_class *vsnapshot_tilde_class;
1214
1215typedef struct _vsnapshot
1216{
1217 t_object x_obj;
1218 int x_n;
1219 int x_gotone;
1220 t_sample *x_vec;
1221 float x_f;
1222 float x_sampspermsec;
1223 double x_time;
1224} t_vsnapshot;
1225
1226static void *vsnapshot_tilde_new(void)
1227{
1228 t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
1229 outlet_new(&x->x_obj, &s_float);
1230 x->x_f = 0;
1231 x->x_n = 0;
1232 x->x_vec = 0;
1233 x->x_gotone = 0;
1234 return (x);
1235}
1236
1237static t_int *vsnapshot_tilde_perform(t_int *w)
1238{
1239 t_float *in = (t_float *)(w[1]);
1240 t_vsnapshot *x = (t_vsnapshot *)(w[2]);
1241 t_float *out = x->x_vec;
1242 int n = x->x_n, i;
1243 for (i = 0; i < n; i++)
1244 out[i] = in[i];
1245 x->x_time = clock_getlogicaltime();
1246 x->x_gotone = 1;
1247 return (w+3);
1248}
1249
1250static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
1251{
1252 int n = sp[0]->s_n;
1253 if (n != x->x_n)
1254 {
1255 if (x->x_vec)
1256 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
1257 x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
1258 x->x_gotone = 0;
1259 x->x_n = n;
1260 }
1261 x->x_sampspermsec = sp[0]->s_sr / 1000;
1262 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
1263}
1264
1265static void vsnapshot_tilde_bang(t_vsnapshot *x)
1266{
1267 float val;
1268 if (x->x_gotone)
1269 {
1270 int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
1271 if (indx < 0)
1272 indx = 0;
1273 else if (indx >= x->x_n)
1274 indx = x->x_n - 1;
1275 val = x->x_vec[indx];
1276 }
1277 else val = 0;
1278 outlet_float(x->x_obj.ob_outlet, val);
1279}
1280
1281static void vsnapshot_tilde_ff(t_vsnapshot *x)
1282{
1283 if (x->x_vec)
1284 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
1285}
1286
1287static void vsnapshot_tilde_setup(void)
1288{
1289 vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
1290 vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
1291 sizeof(t_vsnapshot), 0, 0);
1292 CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
1293 class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
1294 class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
1295}
1296
1297
1298/* ---------------- env~ - simple envelope follower. ----------------- */
1299
1300#define MAXOVERLAP 10
1301#define MAXVSTAKEN 64
1302
1303typedef struct sigenv
1304{
1305 t_object x_obj; /* header */
1306 void *x_outlet; /* a "float" outlet */
1307 void *x_clock; /* a "clock" object */
1308 float *x_buf; /* a Hanning window */
1309 int x_phase; /* number of points since last output */
1310 int x_period; /* requested period of output */
1311 int x_realperiod; /* period rounded up to vecsize multiple */
1312 int x_npoints; /* analysis window size in samples */
1313 float x_result; /* result to output */
1314 float x_sumbuf[MAXOVERLAP]; /* summing buffer */
1315 float x_f;
1316} t_sigenv;
1317
1318t_class *env_tilde_class;
1319static void env_tilde_tick(t_sigenv *x);
1320
1321static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
1322{
1323 int npoints = fnpoints;
1324 int period = fperiod;
1325 t_sigenv *x;
1326 float *buf;
1327 int i;
1328
1329 if (npoints < 1) npoints = 1024;
1330 if (period < 1) period = npoints/2;
1331 if (period < npoints / MAXOVERLAP + 1)
1332 period = npoints / MAXOVERLAP + 1;
1333 if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
1334 {
1335 error("env: couldn't allocate buffer");
1336 return (0);
1337 }
1338 x = (t_sigenv *)pd_new(env_tilde_class);
1339 x->x_buf = buf;
1340 x->x_npoints = npoints;
1341 x->x_phase = 0;
1342 x->x_period = period;
1343 for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
1344 for (i = 0; i < npoints; i++)
1345 buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
1346 for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
1347 x->x_clock = clock_new(x, (t_method)env_tilde_tick);
1348 x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
1349 x->x_f = 0;
1350 return (x);
1351}
1352
1353static t_int *env_tilde_perform(t_int *w)
1354{
1355 t_sigenv *x = (t_sigenv *)(w[1]);
1356 t_float *in = (t_float *)(w[2]);
1357 int n = (int)(w[3]);
1358 int count;
1359 float *sump;
1360 in += n;
1361 for (count = x->x_phase, sump = x->x_sumbuf;
1362 count < x->x_npoints; count += x->x_realperiod, sump++)
1363 {
1364 float *hp = x->x_buf + count;
1365 float *fp = in;
1366 float sum = *sump;
1367 int i;
1368
1369 for (i = 0; i < n; i++)
1370 {
1371 fp--;
1372 sum += *hp++ * (*fp * *fp);
1373 }
1374 *sump = sum;
1375 }
1376 sump[0] = 0;
1377 x->x_phase -= n;
1378 if (x->x_phase < 0)
1379 {
1380 x->x_result = x->x_sumbuf[0];
1381 for (count = x->x_realperiod, sump = x->x_sumbuf;
1382 count < x->x_npoints; count += x->x_realperiod, sump++)
1383 sump[0] = sump[1];
1384 sump[0] = 0;
1385 x->x_phase = x->x_realperiod - n;
1386 clock_delay(x->x_clock, 0L);
1387 }
1388 return (w+4);
1389}
1390
1391static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
1392{
1393 if (x->x_period % sp[0]->s_n) x->x_realperiod =
1394 x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
1395 else x->x_realperiod = x->x_period;
1396 dsp_add(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
1397 if (sp[0]->s_n > MAXVSTAKEN) bug("env_tilde_dsp");
1398}
1399
1400static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
1401{
1402 outlet_float(x->x_outlet, powtodb(x->x_result));
1403}
1404
1405static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
1406{
1407 clock_free(x->x_clock);
1408 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
1409}
1410
1411
1412void env_tilde_setup(void )
1413{
1414 env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new,
1415 (t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
1416 CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f);
1417 class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, gensym("dsp"), 0);
1418}
1419
1420/* --------------------- threshold~ ----------------------------- */
1421
1422static t_class *threshold_tilde_class;
1423
1424typedef struct _threshold_tilde
1425{
1426 t_object x_obj;
1427 t_outlet *x_outlet1; /* bang out for high thresh */
1428 t_outlet *x_outlet2; /* bang out for low thresh */
1429 t_clock *x_clock; /* wakeup for message output */
1430 float x_f; /* scalar inlet */
1431 int x_state; /* 1 = high, 0 = low */
1432 float x_hithresh; /* value of high threshold */
1433 float x_lothresh; /* value of low threshold */
1434 float x_deadwait; /* msec remaining in dead period */
1435 float x_msecpertick; /* msec per DSP tick */
1436 float x_hideadtime; /* hi dead time in msec */
1437 float x_lodeadtime; /* lo dead time in msec */
1438} t_threshold_tilde;
1439
1440static void threshold_tilde_tick(t_threshold_tilde *x);
1441static void threshold_tilde_set(t_threshold_tilde *x,
1442 t_floatarg hithresh, t_floatarg hideadtime,
1443 t_floatarg lothresh, t_floatarg lodeadtime);
1444
1445static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
1446 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
1447{
1448 t_threshold_tilde *x = (t_threshold_tilde *)
1449 pd_new(threshold_tilde_class);
1450 x->x_state = 0; /* low state */
1451 x->x_deadwait = 0; /* no dead time */
1452 x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
1453 x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
1454 x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
1455 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
1456 x->x_msecpertick = 0.;
1457 x->x_f = 0;
1458 threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
1459 return (x);
1460}
1461
1462 /* "set" message to specify thresholds and dead times */
1463static void threshold_tilde_set(t_threshold_tilde *x,
1464 t_floatarg hithresh, t_floatarg hideadtime,
1465 t_floatarg lothresh, t_floatarg lodeadtime)
1466{
1467 if (lothresh > hithresh)
1468 lothresh = hithresh;
1469 x->x_hithresh = hithresh;
1470 x->x_hideadtime = hideadtime;
1471 x->x_lothresh = lothresh;
1472 x->x_lodeadtime = lodeadtime;
1473}
1474
1475 /* number in inlet sets state -- note incompatible with JMAX which used
1476 "int" message for this, impossible here because of auto signal conversion */
1477static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
1478{
1479 x->x_state = (f != 0);
1480 x->x_deadwait = 0;
1481}
1482
1483static void threshold_tilde_tick(t_threshold_tilde *x)
1484{
1485 if (x->x_state)
1486 outlet_bang(x->x_outlet1);
1487 else outlet_bang(x->x_outlet2);
1488}
1489
1490static t_int *threshold_tilde_perform(t_int *w)
1491{
1492 float *in1 = (float *)(w[1]);
1493 t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
1494 int n = (t_int)(w[3]);
1495 if (x->x_deadwait > 0)
1496 x->x_deadwait -= x->x_msecpertick;
1497 else if (x->x_state)
1498 {
1499 /* we're high; look for low sample */
1500 for (; n--; in1++)
1501 {
1502 if (*in1 < x->x_lothresh)
1503 {
1504 clock_delay(x->x_clock, 0L);
1505 x->x_state = 0;
1506 x->x_deadwait = x->x_lodeadtime;
1507 goto done;
1508 }
1509 }
1510 }
1511 else
1512 {
1513 /* we're low; look for high sample */
1514 for (; n--; in1++)
1515 {
1516 if (*in1 >= x->x_hithresh)
1517 {
1518 clock_delay(x->x_clock, 0L);
1519 x->x_state = 1;
1520 x->x_deadwait = x->x_hideadtime;
1521 goto done;
1522 }
1523 }
1524 }
1525done:
1526 return (w+4);
1527}
1528
1529void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
1530{
1531 x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
1532 dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
1533}
1534
1535static void threshold_tilde_ff(t_threshold_tilde *x)
1536{
1537 clock_free(x->x_clock);
1538}
1539
1540static void threshold_tilde_setup( void)
1541{
1542 threshold_tilde_class = class_new(gensym("threshold~"),
1543 (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
1544 sizeof(t_threshold_tilde), 0,
1545 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
1546 CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
1547 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
1548 gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1549 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
1550 gensym("ft1"), A_FLOAT, 0);
1551 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
1552 gensym("dsp"), 0);
1553}
1554
1555/* ------------------------ global setup routine ------------------------- */
1556
1557void d_ctl_setup(void)
1558{
1559 sig_tilde_setup();
1560 line_tilde_setup();
1561 vline_tilde_setup();
1562 snapshot_tilde_setup();
1563 vsnapshot_tilde_setup();
1564 env_tilde_setup();
1565 threshold_tilde_setup();
1566}
1567
1568#endif
diff --git a/apps/plugins/pdbox/PDa/src/d_dac.c b/apps/plugins/pdbox/PDa/src/d_dac.c
new file mode 100644
index 0000000000..ce7c7127f0
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_dac.c
@@ -0,0 +1,368 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* The dac~ and adc~ routines.
6*/
7
8#include "m_pd.h"
9#include "s_stuff.h"
10
11/* ----------------------------- dac~ --------------------------- */
12static t_class *dac_class;
13
14typedef struct _dac
15{
16 t_object x_obj;
17 t_int x_n;
18 t_int *x_vec;
19 float x_f;
20} t_dac;
21
22static void *dac_new(t_symbol *s, int argc, t_atom *argv)
23{
24 t_dac *x = (t_dac *)pd_new(dac_class);
25 t_atom defarg[2], *ap;
26 int i;
27 if (!argc)
28 {
29 argv = defarg;
30 argc = 2;
31 SETFLOAT(&defarg[0], 1);
32 SETFLOAT(&defarg[1], 2);
33 }
34 x->x_n = argc;
35 x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
36 for (i = 0; i < argc; i++)
37 x->x_vec[i] = atom_getintarg(i, argc, argv);
38 for (i = 1; i < argc; i++)
39 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
40 x->x_f = 0;
41 return (x);
42}
43
44static void dac_dsp(t_dac *x, t_signal **sp)
45{
46 t_int i, *ip;
47 t_signal **sp2;
48 for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
49 {
50 int ch = *ip - 1;
51 if ((*sp2)->s_n != DEFDACBLKSIZE)
52 error("dac~: bad vector size");
53 else if (ch >= 0 && ch < sys_get_outchannels())
54 dsp_add(plus_perform, 4, sys_soundout + DEFDACBLKSIZE*ch,
55 (*sp2)->s_vec, sys_soundout + DEFDACBLKSIZE*ch, DEFDACBLKSIZE);
56 }
57}
58
59static void dac_free(t_dac *x)
60{
61 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
62}
63
64static void dac_setup(void)
65{
66 dac_class = class_new(gensym("dac~"), (t_newmethod)dac_new,
67 (t_method)dac_free, sizeof(t_dac), 0, A_GIMME, 0);
68 CLASS_MAINSIGNALIN(dac_class, t_dac, x_f);
69 class_addmethod(dac_class, (t_method)dac_dsp, gensym("dsp"), A_CANT, 0);
70 class_sethelpsymbol(dac_class, gensym("adc~_dac~"));
71}
72
73/* ----------------------------- adc~ --------------------------- */
74static t_class *adc_class;
75
76typedef struct _adc
77{
78 t_object x_obj;
79 t_int x_n;
80 t_int *x_vec;
81} t_adc;
82
83static void *adc_new(t_symbol *s, int argc, t_atom *argv)
84{
85 t_adc *x = (t_adc *)pd_new(adc_class);
86 t_atom defarg[2], *ap;
87 int i;
88 if (!argc)
89 {
90 argv = defarg;
91 argc = 2;
92 SETFLOAT(&defarg[0], 1);
93 SETFLOAT(&defarg[1], 2);
94 }
95 x->x_n = argc;
96 x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
97 for (i = 0; i < argc; i++)
98 x->x_vec[i] = atom_getintarg(i, argc, argv);
99 for (i = 0; i < argc; i++)
100 outlet_new(&x->x_obj, &s_signal);
101 return (x);
102}
103
104t_int *copy_perform(t_int *w)
105{
106 t_float *in1 = (t_float *)(w[1]);
107 t_float *out = (t_float *)(w[2]);
108 int n = (int)(w[3]);
109 while (n--) *out++ = *in1++;
110 return (w+4);
111}
112
113t_int *copy_perf8(t_int *w)
114{
115 t_float *in1 = (t_float *)(w[1]);
116 t_float *out = (t_float *)(w[2]);
117 int n = (int)(w[3]);
118
119 for (; n; n -= 8, in1 += 8, out += 8)
120 {
121 float f0 = in1[0];
122 float f1 = in1[1];
123 float f2 = in1[2];
124 float f3 = in1[3];
125 float f4 = in1[4];
126 float f5 = in1[5];
127 float f6 = in1[6];
128 float f7 = in1[7];
129
130 out[0] = f0;
131 out[1] = f1;
132 out[2] = f2;
133 out[3] = f3;
134 out[4] = f4;
135 out[5] = f5;
136 out[6] = f6;
137 out[7] = f7;
138 }
139 return (w+4);
140}
141
142void dsp_add_copy(t_sample *in, t_sample *out, int n)
143{
144 if (n&7)
145 dsp_add(copy_perform, 3, in, out, n);
146 else
147 dsp_add(copy_perf8, 3, in, out, n);
148}
149
150static void adc_dsp(t_adc *x, t_signal **sp)
151{
152 t_int i, *ip;
153 t_signal **sp2;
154 for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
155 {
156 int ch = *ip - 1;
157 if ((*sp2)->s_n != DEFDACBLKSIZE)
158 error("adc~: bad vector size");
159 else if (ch >= 0 && ch < sys_get_inchannels())
160 dsp_add_copy(sys_soundin + DEFDACBLKSIZE*ch,
161 (*sp2)->s_vec, DEFDACBLKSIZE);
162 else dsp_add_zero((*sp2)->s_vec, DEFDACBLKSIZE);
163 }
164}
165
166static void adc_free(t_adc *x)
167{
168 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
169}
170
171static void adc_setup(void)
172{
173 adc_class = class_new(gensym("adc~"), (t_newmethod)adc_new,
174 (t_method)adc_free, sizeof(t_adc), 0, A_GIMME, 0);
175 class_addmethod(adc_class, (t_method)adc_dsp, gensym("dsp"), A_CANT, 0);
176 class_sethelpsymbol(adc_class, gensym("adc~_dac~"));
177}
178
179void d_dac_setup(void)
180{
181 dac_setup();
182 adc_setup();
183}
184
185/* Copyright (c) 1997-1999 Miller Puckette.
186* For information on usage and redistribution, and for a DISCLAIMER OF ALL
187* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
188
189/* The dac~ and adc~ routines.
190*/
191
192#include "m_pd.h"
193#include "s_stuff.h"
194
195/* ----------------------------- dac~ --------------------------- */
196static t_class *dac_class;
197
198typedef struct _dac
199{
200 t_object x_obj;
201 t_int x_n;
202 t_int *x_vec;
203 float x_f;
204} t_dac;
205
206static void *dac_new(t_symbol *s, int argc, t_atom *argv)
207{
208 t_dac *x = (t_dac *)pd_new(dac_class);
209 t_atom defarg[2], *ap;
210 int i;
211 if (!argc)
212 {
213 argv = defarg;
214 argc = 2;
215 SETFLOAT(&defarg[0], 1);
216 SETFLOAT(&defarg[1], 2);
217 }
218 x->x_n = argc;
219 x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
220 for (i = 0; i < argc; i++)
221 x->x_vec[i] = atom_getintarg(i, argc, argv);
222 for (i = 1; i < argc; i++)
223 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
224 x->x_f = 0;
225 return (x);
226}
227
228static void dac_dsp(t_dac *x, t_signal **sp)
229{
230 t_int i, *ip;
231 t_signal **sp2;
232 for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
233 {
234 int ch = *ip - 1;
235 if ((*sp2)->s_n != DEFDACBLKSIZE)
236 error("dac~: bad vector size");
237 else if (ch >= 0 && ch < sys_get_outchannels())
238 dsp_add(plus_perform, 4, sys_soundout + DEFDACBLKSIZE*ch,
239 (*sp2)->s_vec, sys_soundout + DEFDACBLKSIZE*ch, DEFDACBLKSIZE);
240 }
241}
242
243static void dac_free(t_dac *x)
244{
245 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
246}
247
248static void dac_setup(void)
249{
250 dac_class = class_new(gensym("dac~"), (t_newmethod)dac_new,
251 (t_method)dac_free, sizeof(t_dac), 0, A_GIMME, 0);
252 CLASS_MAINSIGNALIN(dac_class, t_dac, x_f);
253 class_addmethod(dac_class, (t_method)dac_dsp, gensym("dsp"), A_CANT, 0);
254 class_sethelpsymbol(dac_class, gensym("adc~_dac~"));
255}
256
257/* ----------------------------- adc~ --------------------------- */
258static t_class *adc_class;
259
260typedef struct _adc
261{
262 t_object x_obj;
263 t_int x_n;
264 t_int *x_vec;
265} t_adc;
266
267static void *adc_new(t_symbol *s, int argc, t_atom *argv)
268{
269 t_adc *x = (t_adc *)pd_new(adc_class);
270 t_atom defarg[2], *ap;
271 int i;
272 if (!argc)
273 {
274 argv = defarg;
275 argc = 2;
276 SETFLOAT(&defarg[0], 1);
277 SETFLOAT(&defarg[1], 2);
278 }
279 x->x_n = argc;
280 x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
281 for (i = 0; i < argc; i++)
282 x->x_vec[i] = atom_getintarg(i, argc, argv);
283 for (i = 0; i < argc; i++)
284 outlet_new(&x->x_obj, &s_signal);
285 return (x);
286}
287
288t_int *copy_perform(t_int *w)
289{
290 t_float *in1 = (t_float *)(w[1]);
291 t_float *out = (t_float *)(w[2]);
292 int n = (int)(w[3]);
293 while (n--) *out++ = *in1++;
294 return (w+4);
295}
296
297t_int *copy_perf8(t_int *w)
298{
299 t_float *in1 = (t_float *)(w[1]);
300 t_float *out = (t_float *)(w[2]);
301 int n = (int)(w[3]);
302
303 for (; n; n -= 8, in1 += 8, out += 8)
304 {
305 float f0 = in1[0];
306 float f1 = in1[1];
307 float f2 = in1[2];
308 float f3 = in1[3];
309 float f4 = in1[4];
310 float f5 = in1[5];
311 float f6 = in1[6];
312 float f7 = in1[7];
313
314 out[0] = f0;
315 out[1] = f1;
316 out[2] = f2;
317 out[3] = f3;
318 out[4] = f4;
319 out[5] = f5;
320 out[6] = f6;
321 out[7] = f7;
322 }
323 return (w+4);
324}
325
326void dsp_add_copy(t_sample *in, t_sample *out, int n)
327{
328 if (n&7)
329 dsp_add(copy_perform, 3, in, out, n);
330 else
331 dsp_add(copy_perf8, 3, in, out, n);
332}
333
334static void adc_dsp(t_adc *x, t_signal **sp)
335{
336 t_int i, *ip;
337 t_signal **sp2;
338 for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
339 {
340 int ch = *ip - 1;
341 if ((*sp2)->s_n != DEFDACBLKSIZE)
342 error("adc~: bad vector size");
343 else if (ch >= 0 && ch < sys_get_inchannels())
344 dsp_add_copy(sys_soundin + DEFDACBLKSIZE*ch,
345 (*sp2)->s_vec, DEFDACBLKSIZE);
346 else dsp_add_zero((*sp2)->s_vec, DEFDACBLKSIZE);
347 }
348}
349
350static void adc_free(t_adc *x)
351{
352 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
353}
354
355static void adc_setup(void)
356{
357 adc_class = class_new(gensym("adc~"), (t_newmethod)adc_new,
358 (t_method)adc_free, sizeof(t_adc), 0, A_GIMME, 0);
359 class_addmethod(adc_class, (t_method)adc_dsp, gensym("dsp"), A_CANT, 0);
360 class_sethelpsymbol(adc_class, gensym("adc~_dac~"));
361}
362
363void d_dac_setup(void)
364{
365 dac_setup();
366 adc_setup();
367}
368
diff --git a/apps/plugins/pdbox/PDa/src/d_delay.c b/apps/plugins/pdbox/PDa/src/d_delay.c
new file mode 100644
index 0000000000..37fb90ea5b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_delay.c
@@ -0,0 +1,638 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* send~, delread~, throw~, catch~ */
6
7#include "m_pd.h"
8extern int ugen_getsortno(void);
9
10#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
11static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
12
13/* ----------------------------- delwrite~ ----------------------------- */
14static t_class *sigdelwrite_class;
15
16typedef struct delwritectl
17{
18 int c_n;
19 float *c_vec;
20 int c_phase;
21} t_delwritectl;
22
23typedef struct _sigdelwrite
24{
25 t_object x_obj;
26 t_symbol *x_sym;
27 t_delwritectl x_cspace;
28 int x_sortno; /* DSP sort number at which this was last put on chain */
29 int x_rsortno; /* DSP sort # for first delread or write in chain */
30 int x_vecsize; /* vector size for delread~ to use */
31 float x_f;
32} t_sigdelwrite;
33
34#define XTRASAMPS 4
35#define SAMPBLK 4
36
37 /* routine to check that all delwrites/delreads/vds have same vecsize */
38static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize)
39{
40 /*
41 LATER this should really check sample rate and blocking, once that is
42 supported. Probably we don't actually care about vecsize.
43 For now just suppress this check... */
44#if 0
45 if (x->x_rsortno != ugen_getsortno())
46 {
47 x->x_vecsize = vecsize;
48 x->x_rsortno = ugen_getsortno();
49 }
50 else if (vecsize != x->x_vecsize)
51 pd_error(x, "delread/delwrite/vd vector size mismatch");
52#endif
53}
54
55static void *sigdelwrite_new(t_symbol *s, t_floatarg msec)
56{
57 int nsamps;
58 t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
59 if (!*s->s_name) s = gensym("delwrite~");
60 pd_bind(&x->x_obj.ob_pd, s);
61 x->x_sym = s;
62 nsamps = msec * sys_getsr() * (float)(0.001f);
63 if (nsamps < 1) nsamps = 1;
64 nsamps += ((- nsamps) & (SAMPBLK - 1));
65 nsamps += DEFDELVS;
66 x->x_cspace.c_n = nsamps;
67 x->x_cspace.c_vec =
68 (float *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
69 x->x_cspace.c_phase = XTRASAMPS;
70 x->x_sortno = 0;
71 x->x_vecsize = 0;
72 x->x_f = 0;
73 return (x);
74}
75
76static t_int *sigdelwrite_perform(t_int *w)
77{
78 t_float *in = (t_float *)(w[1]);
79 t_delwritectl *c = (t_delwritectl *)(w[2]);
80 int n = (int)(w[3]);
81 int phase = c->c_phase, nsamps = c->c_n;
82 float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
83 phase += n;
84 while (n--)
85 {
86 float f = *in++;
87 if (PD_BIGORSMALL(f))
88 f = 0;
89 *bp++ = f;
90 if (bp == ep)
91 {
92 vp[0] = ep[-4];
93 vp[1] = ep[-3];
94 vp[2] = ep[-2];
95 vp[3] = ep[-1];
96 bp = vp + XTRASAMPS;
97 phase -= nsamps;
98 }
99 }
100 c->c_phase = phase;
101 return (w+4);
102}
103
104static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp)
105{
106 dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n);
107 x->x_sortno = ugen_getsortno();
108 sigdelwrite_checkvecsize(x, sp[0]->s_n);
109}
110
111static void sigdelwrite_free(t_sigdelwrite *x)
112{
113 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
114 freebytes(x->x_cspace.c_vec,
115 (x->x_cspace.c_n + XTRASAMPS) * sizeof(float));
116}
117
118static void sigdelwrite_setup(void)
119{
120 sigdelwrite_class = class_new(gensym("delwrite~"),
121 (t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free,
122 sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0);
123 CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f);
124 class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp,
125 gensym("dsp"), 0);
126}
127
128/* ----------------------------- delread~ ----------------------------- */
129static t_class *sigdelread_class;
130
131typedef struct _sigdelread
132{
133 t_object x_obj;
134 t_symbol *x_sym;
135 t_float x_deltime; /* delay in msec */
136 int x_delsamps; /* delay in samples */
137 t_float x_sr; /* samples per msec */
138 t_float x_n; /* vector size */
139 int x_zerodel; /* 0 or vecsize depending on read/write order */
140} t_sigdelread;
141
142static void sigdelread_float(t_sigdelread *x, t_float f);
143
144static void *sigdelread_new(t_symbol *s, t_floatarg f)
145{
146 t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
147 x->x_sym = s;
148 x->x_sr = 1;
149 x->x_n = 1;
150 x->x_zerodel = 0;
151 sigdelread_float(x, f);
152 outlet_new(&x->x_obj, &s_signal);
153 return (x);
154}
155
156static void sigdelread_float(t_sigdelread *x, t_float f)
157{
158 int samps;
159 t_sigdelwrite *delwriter =
160 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
161 x->x_deltime = f;
162 if (delwriter)
163 {
164 int delsize = delwriter->x_cspace.c_n;
165 x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime)
166 + x->x_n - x->x_zerodel;
167 if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n;
168 else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS)
169 x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS;
170 }
171}
172
173static t_int *sigdelread_perform(t_int *w)
174{
175 t_float *out = (t_float *)(w[1]);
176 t_delwritectl *c = (t_delwritectl *)(w[2]);
177 int delsamps = *(int *)(w[3]);
178 int n = (int)(w[4]);
179 int phase = c->c_phase - delsamps, nsamps = c->c_n;
180 float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
181
182 if (phase < 0) phase += nsamps;
183 bp = vp + phase;
184 while (n--)
185 {
186 *out++ = *bp++;
187 if (bp == ep) bp -= nsamps;
188 }
189 return (w+5);
190}
191
192static void sigdelread_dsp(t_sigdelread *x, t_signal **sp)
193{
194 t_sigdelwrite *delwriter =
195 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
196 x->x_sr = sp[0]->s_sr * 0.001;
197 x->x_n = sp[0]->s_n;
198 if (delwriter)
199 {
200 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
201 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
202 0 : delwriter->x_vecsize);
203 sigdelread_float(x, x->x_deltime);
204 dsp_add(sigdelread_perform, 4,
205 sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n);
206 }
207 else if (*x->x_sym->s_name)
208 error("delread~: %s: no such delwrite~",x->x_sym->s_name);
209}
210
211static void sigdelread_setup(void)
212{
213 sigdelread_class = class_new(gensym("delread~"),
214 (t_newmethod)sigdelread_new, 0,
215 sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0);
216 class_addmethod(sigdelread_class, (t_method)sigdelread_dsp,
217 gensym("dsp"), 0);
218 class_addfloat(sigdelread_class, (t_method)sigdelread_float);
219}
220
221
222/* ----------------------------- vd~ ----------------------------- */
223static t_class *sigvd_class;
224
225typedef struct _sigvd
226{
227 t_object x_obj;
228 t_symbol *x_sym;
229 t_float x_sr; /* samples per msec */
230 int x_zerodel; /* 0 or vecsize depending on read/write order */
231 float x_f;
232} t_sigvd;
233
234static void *sigvd_new(t_symbol *s)
235{
236 t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
237 if (!*s->s_name) s = gensym("vd~");
238 x->x_sym = s;
239 x->x_sr = 1;
240 x->x_zerodel = 0;
241 outlet_new(&x->x_obj, &s_signal);
242 x->x_f = 0;
243 return (x);
244}
245
246static t_int *sigvd_perform(t_int *w)
247{
248 t_float *in = (t_float *)(w[1]);
249 t_float *out = (t_float *)(w[2]);
250 t_delwritectl *ctl = (t_delwritectl *)(w[3]);
251 t_sigvd *x = (t_sigvd *)(w[4]);
252 int n = (int)(w[5]);
253
254 int nsamps = ctl->c_n;
255 float limit = nsamps - n - 1;
256 float fn = n-1;
257 float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
258 float zerodel = x->x_zerodel;
259 while (n--)
260 {
261 float delsamps = x->x_sr * *in++ - zerodel, frac;
262 int idelsamps;
263 float a, b, c, d, cminusb;
264 if (delsamps < 1.00001f) delsamps = 1.00001f;
265 if (delsamps > limit) delsamps = limit;
266 delsamps += fn;
267 fn = fn - 1.0f;
268 idelsamps = delsamps;
269 frac = delsamps - (float)idelsamps;
270 bp = wp - idelsamps;
271 if (bp < vp + 4) bp += nsamps;
272 d = bp[-3];
273 c = bp[-2];
274 b = bp[-1];
275 a = bp[0];
276 cminusb = c-b;
277 *out++ = b + frac * (
278 cminusb - 0.1666667f * (1.-frac) * (
279 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
280 )
281 );
282 }
283 return (w+6);
284}
285
286static void sigvd_dsp(t_sigvd *x, t_signal **sp)
287{
288 t_sigdelwrite *delwriter =
289 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
290 x->x_sr = sp[0]->s_sr * 0.001;
291 if (delwriter)
292 {
293 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
294 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
295 0 : delwriter->x_vecsize);
296 dsp_add(sigvd_perform, 5,
297 sp[0]->s_vec, sp[1]->s_vec,
298 &delwriter->x_cspace, x, sp[0]->s_n);
299 }
300 else error("vd~: %s: no such delwrite~",x->x_sym->s_name);
301}
302
303static void sigvd_setup(void)
304{
305 sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0,
306 sizeof(t_sigvd), 0, A_DEFSYM, 0);
307 class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0);
308 CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f);
309}
310
311/* ----------------------- global setup routine ---------------- */
312
313void d_delay_setup(void)
314{
315 sigdelwrite_setup();
316 sigdelread_setup();
317 sigvd_setup();
318}
319
320/* Copyright (c) 1997-1999 Miller Puckette.
321* For information on usage and redistribution, and for a DISCLAIMER OF ALL
322* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
323
324/* send~, delread~, throw~, catch~ */
325
326#include "m_pd.h"
327extern int ugen_getsortno(void);
328
329#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
330static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
331
332/* ----------------------------- delwrite~ ----------------------------- */
333static t_class *sigdelwrite_class;
334
335typedef struct delwritectl
336{
337 int c_n;
338 float *c_vec;
339 int c_phase;
340} t_delwritectl;
341
342typedef struct _sigdelwrite
343{
344 t_object x_obj;
345 t_symbol *x_sym;
346 t_delwritectl x_cspace;
347 int x_sortno; /* DSP sort number at which this was last put on chain */
348 int x_rsortno; /* DSP sort # for first delread or write in chain */
349 int x_vecsize; /* vector size for delread~ to use */
350 float x_f;
351} t_sigdelwrite;
352
353#define XTRASAMPS 4
354#define SAMPBLK 4
355
356 /* routine to check that all delwrites/delreads/vds have same vecsize */
357static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize)
358{
359 /*
360 LATER this should really check sample rate and blocking, once that is
361 supported. Probably we don't actually care about vecsize.
362 For now just suppress this check... */
363#if 0
364 if (x->x_rsortno != ugen_getsortno())
365 {
366 x->x_vecsize = vecsize;
367 x->x_rsortno = ugen_getsortno();
368 }
369 else if (vecsize != x->x_vecsize)
370 pd_error(x, "delread/delwrite/vd vector size mismatch");
371#endif
372}
373
374static void *sigdelwrite_new(t_symbol *s, t_floatarg msec)
375{
376 int nsamps;
377 t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
378 if (!*s->s_name) s = gensym("delwrite~");
379 pd_bind(&x->x_obj.ob_pd, s);
380 x->x_sym = s;
381 nsamps = msec * sys_getsr() * (float)(0.001f);
382 if (nsamps < 1) nsamps = 1;
383 nsamps += ((- nsamps) & (SAMPBLK - 1));
384 nsamps += DEFDELVS;
385 x->x_cspace.c_n = nsamps;
386 x->x_cspace.c_vec =
387 (float *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
388 x->x_cspace.c_phase = XTRASAMPS;
389 x->x_sortno = 0;
390 x->x_vecsize = 0;
391 x->x_f = 0;
392 return (x);
393}
394
395static t_int *sigdelwrite_perform(t_int *w)
396{
397 t_float *in = (t_float *)(w[1]);
398 t_delwritectl *c = (t_delwritectl *)(w[2]);
399 int n = (int)(w[3]);
400 int phase = c->c_phase, nsamps = c->c_n;
401 float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
402 phase += n;
403 while (n--)
404 {
405 float f = *in++;
406 if (PD_BIGORSMALL(f))
407 f = 0;
408 *bp++ = f;
409 if (bp == ep)
410 {
411 vp[0] = ep[-4];
412 vp[1] = ep[-3];
413 vp[2] = ep[-2];
414 vp[3] = ep[-1];
415 bp = vp + XTRASAMPS;
416 phase -= nsamps;
417 }
418 }
419 c->c_phase = phase;
420 return (w+4);
421}
422
423static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp)
424{
425 dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n);
426 x->x_sortno = ugen_getsortno();
427 sigdelwrite_checkvecsize(x, sp[0]->s_n);
428}
429
430static void sigdelwrite_free(t_sigdelwrite *x)
431{
432 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
433 freebytes(x->x_cspace.c_vec,
434 (x->x_cspace.c_n + XTRASAMPS) * sizeof(float));
435}
436
437static void sigdelwrite_setup(void)
438{
439 sigdelwrite_class = class_new(gensym("delwrite~"),
440 (t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free,
441 sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0);
442 CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f);
443 class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp,
444 gensym("dsp"), 0);
445}
446
447/* ----------------------------- delread~ ----------------------------- */
448static t_class *sigdelread_class;
449
450typedef struct _sigdelread
451{
452 t_object x_obj;
453 t_symbol *x_sym;
454 t_float x_deltime; /* delay in msec */
455 int x_delsamps; /* delay in samples */
456 t_float x_sr; /* samples per msec */
457 t_float x_n; /* vector size */
458 int x_zerodel; /* 0 or vecsize depending on read/write order */
459} t_sigdelread;
460
461static void sigdelread_float(t_sigdelread *x, t_float f);
462
463static void *sigdelread_new(t_symbol *s, t_floatarg f)
464{
465 t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
466 x->x_sym = s;
467 x->x_sr = 1;
468 x->x_n = 1;
469 x->x_zerodel = 0;
470 sigdelread_float(x, f);
471 outlet_new(&x->x_obj, &s_signal);
472 return (x);
473}
474
475static void sigdelread_float(t_sigdelread *x, t_float f)
476{
477 int samps;
478 t_sigdelwrite *delwriter =
479 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
480 x->x_deltime = f;
481 if (delwriter)
482 {
483 int delsize = delwriter->x_cspace.c_n;
484 x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime)
485 + x->x_n - x->x_zerodel;
486 if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n;
487 else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS)
488 x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS;
489 }
490}
491
492static t_int *sigdelread_perform(t_int *w)
493{
494 t_float *out = (t_float *)(w[1]);
495 t_delwritectl *c = (t_delwritectl *)(w[2]);
496 int delsamps = *(int *)(w[3]);
497 int n = (int)(w[4]);
498 int phase = c->c_phase - delsamps, nsamps = c->c_n;
499 float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
500
501 if (phase < 0) phase += nsamps;
502 bp = vp + phase;
503 while (n--)
504 {
505 *out++ = *bp++;
506 if (bp == ep) bp -= nsamps;
507 }
508 return (w+5);
509}
510
511static void sigdelread_dsp(t_sigdelread *x, t_signal **sp)
512{
513 t_sigdelwrite *delwriter =
514 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
515 x->x_sr = sp[0]->s_sr * 0.001;
516 x->x_n = sp[0]->s_n;
517 if (delwriter)
518 {
519 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
520 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
521 0 : delwriter->x_vecsize);
522 sigdelread_float(x, x->x_deltime);
523 dsp_add(sigdelread_perform, 4,
524 sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n);
525 }
526 else if (*x->x_sym->s_name)
527 error("delread~: %s: no such delwrite~",x->x_sym->s_name);
528}
529
530static void sigdelread_setup(void)
531{
532 sigdelread_class = class_new(gensym("delread~"),
533 (t_newmethod)sigdelread_new, 0,
534 sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0);
535 class_addmethod(sigdelread_class, (t_method)sigdelread_dsp,
536 gensym("dsp"), 0);
537 class_addfloat(sigdelread_class, (t_method)sigdelread_float);
538}
539
540
541/* ----------------------------- vd~ ----------------------------- */
542static t_class *sigvd_class;
543
544typedef struct _sigvd
545{
546 t_object x_obj;
547 t_symbol *x_sym;
548 t_float x_sr; /* samples per msec */
549 int x_zerodel; /* 0 or vecsize depending on read/write order */
550 float x_f;
551} t_sigvd;
552
553static void *sigvd_new(t_symbol *s)
554{
555 t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
556 if (!*s->s_name) s = gensym("vd~");
557 x->x_sym = s;
558 x->x_sr = 1;
559 x->x_zerodel = 0;
560 outlet_new(&x->x_obj, &s_signal);
561 x->x_f = 0;
562 return (x);
563}
564
565static t_int *sigvd_perform(t_int *w)
566{
567 t_float *in = (t_float *)(w[1]);
568 t_float *out = (t_float *)(w[2]);
569 t_delwritectl *ctl = (t_delwritectl *)(w[3]);
570 t_sigvd *x = (t_sigvd *)(w[4]);
571 int n = (int)(w[5]);
572
573 int nsamps = ctl->c_n;
574 float limit = nsamps - n - 1;
575 float fn = n-1;
576 float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
577 float zerodel = x->x_zerodel;
578 while (n--)
579 {
580 float delsamps = x->x_sr * *in++ - zerodel, frac;
581 int idelsamps;
582 float a, b, c, d, cminusb;
583 if (delsamps < 1.00001f) delsamps = 1.00001f;
584 if (delsamps > limit) delsamps = limit;
585 delsamps += fn;
586 fn = fn - 1.0f;
587 idelsamps = delsamps;
588 frac = delsamps - (float)idelsamps;
589 bp = wp - idelsamps;
590 if (bp < vp + 4) bp += nsamps;
591 d = bp[-3];
592 c = bp[-2];
593 b = bp[-1];
594 a = bp[0];
595 cminusb = c-b;
596 *out++ = b + frac * (
597 cminusb - 0.1666667f * (1.-frac) * (
598 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
599 )
600 );
601 }
602 return (w+6);
603}
604
605static void sigvd_dsp(t_sigvd *x, t_signal **sp)
606{
607 t_sigdelwrite *delwriter =
608 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
609 x->x_sr = sp[0]->s_sr * 0.001;
610 if (delwriter)
611 {
612 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
613 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
614 0 : delwriter->x_vecsize);
615 dsp_add(sigvd_perform, 5,
616 sp[0]->s_vec, sp[1]->s_vec,
617 &delwriter->x_cspace, x, sp[0]->s_n);
618 }
619 else error("vd~: %s: no such delwrite~",x->x_sym->s_name);
620}
621
622static void sigvd_setup(void)
623{
624 sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0,
625 sizeof(t_sigvd), 0, A_DEFSYM, 0);
626 class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0);
627 CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f);
628}
629
630/* ----------------------- global setup routine ---------------- */
631
632void d_delay_setup(void)
633{
634 sigdelwrite_setup();
635 sigdelread_setup();
636 sigvd_setup();
637}
638
diff --git a/apps/plugins/pdbox/PDa/src/d_fft.c b/apps/plugins/pdbox/PDa/src/d_fft.c
new file mode 100644
index 0000000000..9916fdcb88
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_fft.c
@@ -0,0 +1,688 @@
1/* Copyright (c) 1997-1999 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include "m_pd.h"
6
7/* ------------------------ fft~ and ifft~ -------------------------------- */
8static t_class *sigfft_class, *sigifft_class;
9
10typedef struct fft
11{
12 t_object x_obj;
13 float x_f;
14} t_sigfft;
15
16static void *sigfft_new(void)
17{
18 t_sigfft *x = (t_sigfft *)pd_new(sigfft_class);
19 outlet_new(&x->x_obj, gensym("signal"));
20 outlet_new(&x->x_obj, gensym("signal"));
21 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
22 x->x_f = 0;
23 return (x);
24}
25
26static void *sigifft_new(void)
27{
28 t_sigfft *x = (t_sigfft *)pd_new(sigifft_class);
29 outlet_new(&x->x_obj, gensym("signal"));
30 outlet_new(&x->x_obj, gensym("signal"));
31 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
32 x->x_f = 0;
33 return (x);
34}
35
36static t_int *sigfft_swap(t_int *w)
37{
38 t_sample *in1 = (t_sample *)(w[1]);
39 t_sample *in2 = (t_sample *)(w[2]);
40 int n = w[3];
41 for (;n--; in1++, in2++)
42 {
43 float f = *in1;
44 *in1 = *in2;
45 *in2 = f;
46 }
47 return (w+4);
48}
49
50static t_int *sigfft_perform(t_int *w)
51{
52 t_sample *in1 = (t_sample *)(w[1]);
53 t_sample *in2 = (t_sample *)(w[2]);
54 int n = w[3];
55 mayer_fft(n, in1, in2);
56 return (w+4);
57}
58
59static t_int *sigifft_perform(t_int *w)
60{
61 t_sample *in1 = (t_sample *)(w[1]);
62 t_sample *in2 = (t_sample *)(w[2]);
63 int n = w[3];
64 mayer_ifft(n, in1, in2);
65 return (w+4);
66}
67
68static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w))
69{
70 int n = sp[0]->s_n;
71 t_sample *in1 = sp[0]->s_vec;
72 t_sample *in2 = sp[1]->s_vec;
73 t_sample *out1 = sp[2]->s_vec;
74 t_sample *out2 = sp[3]->s_vec;
75 if (out1 == in2 && out2 == in1)
76 dsp_add(sigfft_swap, 3, out1, out2, n);
77 else if (out1 == in2)
78 {
79 dsp_add(copy_perform, 3, in2, out2, n);
80 dsp_add(copy_perform, 3, in1, out1, n);
81 }
82 else
83 {
84 if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n);
85 if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n);
86 }
87 dsp_add(f, 3, sp[2]->s_vec, sp[3]->s_vec, n);
88}
89
90static void sigfft_dsp(t_sigfft *x, t_signal **sp)
91{
92 sigfft_dspx(x, sp, sigfft_perform);
93}
94
95static void sigifft_dsp(t_sigfft *x, t_signal **sp)
96{
97 sigfft_dspx(x, sp, sigifft_perform);
98}
99
100static void sigfft_setup(void)
101{
102 sigfft_class = class_new(gensym("fft~"), sigfft_new, 0,
103 sizeof(t_sigfft), 0, 0);
104 CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, x_f);
105 class_addmethod(sigfft_class, (t_method)sigfft_dsp, gensym("dsp"), 0);
106
107 sigifft_class = class_new(gensym("ifft~"), sigifft_new, 0,
108 sizeof(t_sigfft), 0, 0);
109 CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, x_f);
110 class_addmethod(sigifft_class, (t_method)sigifft_dsp, gensym("dsp"), 0);
111 class_sethelpsymbol(sigifft_class, gensym("fft~"));
112}
113
114/* ----------------------- rfft~ -------------------------------- */
115
116static t_class *sigrfft_class;
117
118typedef struct rfft
119{
120 t_object x_obj;
121 float x_f;
122} t_sigrfft;
123
124static void *sigrfft_new(void)
125{
126 t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class);
127 outlet_new(&x->x_obj, gensym("signal"));
128 outlet_new(&x->x_obj, gensym("signal"));
129 x->x_f = 0;
130 return (x);
131}
132
133static t_int *sigrfft_flip(t_int *w)
134{
135 t_sample *in = (t_sample *)(w[1]);
136 t_sample *out = (t_sample *)(w[2]);
137 int n = w[3];
138 while (n--) *(--out) = *in++;
139 *(--out) = 0; /* to hell with it */
140 return (w+4);
141}
142
143static t_int *sigrfft_perform(t_int *w)
144{
145 t_sample *in = (t_sample *)(w[1]);
146 int n = w[2];
147 mayer_realfft(n, in);
148 return (w+3);
149}
150
151static void sigrfft_dsp(t_sigrfft *x, t_signal **sp)
152{
153 int n = sp[0]->s_n, n2 = (n>>1);
154 t_sample *in1 = sp[0]->s_vec;
155 t_sample *out1 = sp[1]->s_vec;
156 t_sample *out2 = sp[2]->s_vec;
157 if (n < 4)
158 {
159 error("fft: minimum 4 points");
160 return;
161 }
162 if (in1 == out2) /* this probably never happens */
163 {
164 dsp_add(sigrfft_perform, 2, out2, n);
165 dsp_add(copy_perform, 3, out2, out1, n2);
166 dsp_add(sigrfft_flip, 3, out2 + (n2+1), out2 + n2, n2-1);
167 }
168 else
169 {
170 if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n);
171 dsp_add(sigrfft_perform, 2, out1, n);
172 dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1);
173 }
174 dsp_add_zero(out1 + n2, n2);
175 dsp_add_zero(out2 + n2, n2);
176}
177
178static void sigrfft_setup(void)
179{
180 sigrfft_class = class_new(gensym("rfft~"), sigrfft_new, 0,
181 sizeof(t_sigrfft), 0, 0);
182 CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, x_f);
183 class_addmethod(sigrfft_class, (t_method)sigrfft_dsp, gensym("dsp"), 0);
184 class_sethelpsymbol(sigrfft_class, gensym("fft~"));
185}
186
187/* ----------------------- rifft~ -------------------------------- */
188
189static t_class *sigrifft_class;
190
191typedef struct rifft
192{
193 t_object x_obj;
194 float x_f;
195} t_sigrifft;
196
197static void *sigrifft_new(void)
198{
199 t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class);
200 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
201 outlet_new(&x->x_obj, gensym("signal"));
202 x->x_f = 0;
203 return (x);
204}
205
206static t_int *sigrifft_perform(t_int *w)
207{
208 t_sample *in = (t_sample *)(w[1]);
209 int n = w[2];
210 mayer_realifft(n, in);
211 return (w+3);
212}
213
214static void sigrifft_dsp(t_sigrifft *x, t_signal **sp)
215{
216 int n = sp[0]->s_n, n2 = (n>>1);
217 t_sample *in1 = sp[0]->s_vec;
218 t_sample *in2 = sp[1]->s_vec;
219 t_sample *out1 = sp[2]->s_vec;
220 if (n < 4)
221 {
222 error("fft: minimum 4 points");
223 return;
224 }
225 if (in2 == out1)
226 {
227 dsp_add(sigrfft_flip, 3, out1+1, out1 + n, (n2-1));
228 dsp_add(copy_perform, 3, in1, out1, n2);
229 }
230 else
231 {
232 if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2);
233 dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1);
234 }
235 dsp_add(sigrifft_perform, 2, out1, n);
236}
237
238static void sigrifft_setup(void)
239{
240 sigrifft_class = class_new(gensym("rifft~"), sigrifft_new, 0,
241 sizeof(t_sigrifft), 0, 0);
242 CLASS_MAINSIGNALIN(sigrifft_class, t_sigrifft, x_f);
243 class_addmethod(sigrifft_class, (t_method)sigrifft_dsp, gensym("dsp"), 0);
244 class_sethelpsymbol(sigrifft_class, gensym("fft~"));
245}
246
247/* ----------------------- framp~ -------------------------------- */
248
249#if 0
250static t_class *sigframp_class;
251
252typedef struct framp
253{
254 t_object x_obj;
255 float x_f;
256} t_sigframp;
257
258static void *sigframp_new(void)
259{
260 t_sigframp *x = (t_sigframp *)pd_new(sigframp_class);
261 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
262 outlet_new(&x->x_obj, gensym("signal"));
263 outlet_new(&x->x_obj, gensym("signal"));
264 x->x_f = 0;
265 return (x);
266}
267
268static t_int *sigframp_perform(t_int *w)
269{
270 float *inreal = (t_float *)(w[1]);
271 float *inimag = (t_float *)(w[2]);
272 float *outfreq = (t_float *)(w[3]);
273 float *outamp = (t_float *)(w[4]);
274 float lastreal = 0, currentreal = inreal[0], nextreal = inreal[1];
275 float lastimag = 0, currentimag = inimag[0], nextimag = inimag[1];
276 int n = w[5];
277 int m = n + 1;
278 float fbin = 1, oneovern2 = 1.f/((float)n * (float)n);
279
280 inreal += 2;
281 inimag += 2;
282 *outamp++ = *outfreq++ = 0;
283 n -= 2;
284 while (n--)
285 {
286 float re, im, pow, freq;
287 lastreal = currentreal;
288 currentreal = nextreal;
289 nextreal = *inreal++;
290 lastimag = currentimag;
291 currentimag = nextimag;
292 nextimag = *inimag++;
293 re = currentreal - 0.5f * (lastreal + nextreal);
294 im = currentimag - 0.5f * (lastimag + nextimag);
295 pow = re * re + im * im;
296 if (pow > 1e-19)
297 {
298 float detune = ((lastreal - nextreal) * re +
299 (lastimag - nextimag) * im) / (2.0f * pow);
300 if (detune > 2 || detune < -2) freq = pow = 0;
301 else freq = fbin + detune;
302 }
303 else freq = pow = 0;
304 *outfreq++ = freq;
305 *outamp++ = oneovern2 * pow;
306 fbin += 1.0f;
307 }
308 while (m--) *outamp++ = *outfreq++ = 0;
309 return (w+6);
310}
311
312t_int *sigsqrt_perform(t_int *w);
313
314static void sigframp_dsp(t_sigframp *x, t_signal **sp)
315{
316 int n = sp[0]->s_n, n2 = (n>>1);
317 if (n < 4)
318 {
319 error("framp: minimum 4 points");
320 return;
321 }
322 dsp_add(sigframp_perform, 5, sp[0]->s_vec, sp[1]->s_vec,
323 sp[2]->s_vec, sp[3]->s_vec, n2);
324 dsp_add(sigsqrt_perform, 3, sp[3]->s_vec, sp[3]->s_vec, n2);
325}
326
327static void sigframp_setup(void)
328{
329 sigframp_class = class_new(gensym("framp~"), sigframp_new, 0,
330 sizeof(t_sigframp), 0, 0);
331 CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, x_f);
332 class_addmethod(sigframp_class, (t_method)sigframp_dsp, gensym("dsp"), 0);
333}
334#endif
335
336/* ------------------------ global setup routine ------------------------- */
337
338void d_fft_setup(void)
339{
340 sigfft_setup();
341 sigrfft_setup();
342 sigrifft_setup();
343// sigframp_setup();
344}
345/* Copyright (c) 1997-1999 Miller Puckette and others.
346* For information on usage and redistribution, and for a DISCLAIMER OF ALL
347* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
348
349#include "m_pd.h"
350
351/* ------------------------ fft~ and ifft~ -------------------------------- */
352static t_class *sigfft_class, *sigifft_class;
353
354typedef struct fft
355{
356 t_object x_obj;
357 float x_f;
358} t_sigfft;
359
360static void *sigfft_new(void)
361{
362 t_sigfft *x = (t_sigfft *)pd_new(sigfft_class);
363 outlet_new(&x->x_obj, gensym("signal"));
364 outlet_new(&x->x_obj, gensym("signal"));
365 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
366 x->x_f = 0;
367 return (x);
368}
369
370static void *sigifft_new(void)
371{
372 t_sigfft *x = (t_sigfft *)pd_new(sigifft_class);
373 outlet_new(&x->x_obj, gensym("signal"));
374 outlet_new(&x->x_obj, gensym("signal"));
375 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
376 x->x_f = 0;
377 return (x);
378}
379
380static t_int *sigfft_swap(t_int *w)
381{
382 t_sample *in1 = (t_sample *)(w[1]);
383 t_sample *in2 = (t_sample *)(w[2]);
384 int n = w[3];
385 for (;n--; in1++, in2++)
386 {
387 float f = *in1;
388 *in1 = *in2;
389 *in2 = f;
390 }
391 return (w+4);
392}
393
394static t_int *sigfft_perform(t_int *w)
395{
396 t_sample *in1 = (t_sample *)(w[1]);
397 t_sample *in2 = (t_sample *)(w[2]);
398 int n = w[3];
399 mayer_fft(n, in1, in2);
400 return (w+4);
401}
402
403static t_int *sigifft_perform(t_int *w)
404{
405 t_sample *in1 = (t_sample *)(w[1]);
406 t_sample *in2 = (t_sample *)(w[2]);
407 int n = w[3];
408 mayer_ifft(n, in1, in2);
409 return (w+4);
410}
411
412static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w))
413{
414 int n = sp[0]->s_n;
415 t_sample *in1 = sp[0]->s_vec;
416 t_sample *in2 = sp[1]->s_vec;
417 t_sample *out1 = sp[2]->s_vec;
418 t_sample *out2 = sp[3]->s_vec;
419 if (out1 == in2 && out2 == in1)
420 dsp_add(sigfft_swap, 3, out1, out2, n);
421 else if (out1 == in2)
422 {
423 dsp_add(copy_perform, 3, in2, out2, n);
424 dsp_add(copy_perform, 3, in1, out1, n);
425 }
426 else
427 {
428 if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n);
429 if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n);
430 }
431 dsp_add(f, 3, sp[2]->s_vec, sp[3]->s_vec, n);
432}
433
434static void sigfft_dsp(t_sigfft *x, t_signal **sp)
435{
436 sigfft_dspx(x, sp, sigfft_perform);
437}
438
439static void sigifft_dsp(t_sigfft *x, t_signal **sp)
440{
441 sigfft_dspx(x, sp, sigifft_perform);
442}
443
444static void sigfft_setup(void)
445{
446 sigfft_class = class_new(gensym("fft~"), sigfft_new, 0,
447 sizeof(t_sigfft), 0, 0);
448 CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, x_f);
449 class_addmethod(sigfft_class, (t_method)sigfft_dsp, gensym("dsp"), 0);
450
451 sigifft_class = class_new(gensym("ifft~"), sigifft_new, 0,
452 sizeof(t_sigfft), 0, 0);
453 CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, x_f);
454 class_addmethod(sigifft_class, (t_method)sigifft_dsp, gensym("dsp"), 0);
455 class_sethelpsymbol(sigifft_class, gensym("fft~"));
456}
457
458/* ----------------------- rfft~ -------------------------------- */
459
460static t_class *sigrfft_class;
461
462typedef struct rfft
463{
464 t_object x_obj;
465 float x_f;
466} t_sigrfft;
467
468static void *sigrfft_new(void)
469{
470 t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class);
471 outlet_new(&x->x_obj, gensym("signal"));
472 outlet_new(&x->x_obj, gensym("signal"));
473 x->x_f = 0;
474 return (x);
475}
476
477static t_int *sigrfft_flip(t_int *w)
478{
479 t_sample *in = (t_sample *)(w[1]);
480 t_sample *out = (t_sample *)(w[2]);
481 int n = w[3];
482 while (n--) *(--out) = *in++;
483 *(--out) = 0; /* to hell with it */
484 return (w+4);
485}
486
487static t_int *sigrfft_perform(t_int *w)
488{
489 t_sample *in = (t_sample *)(w[1]);
490 int n = w[2];
491 mayer_realfft(n, in);
492 return (w+3);
493}
494
495static void sigrfft_dsp(t_sigrfft *x, t_signal **sp)
496{
497 int n = sp[0]->s_n, n2 = (n>>1);
498 t_sample *in1 = sp[0]->s_vec;
499 t_sample *out1 = sp[1]->s_vec;
500 t_sample *out2 = sp[2]->s_vec;
501 if (n < 4)
502 {
503 error("fft: minimum 4 points");
504 return;
505 }
506 if (in1 == out2) /* this probably never happens */
507 {
508 dsp_add(sigrfft_perform, 2, out2, n);
509 dsp_add(copy_perform, 3, out2, out1, n2);
510 dsp_add(sigrfft_flip, 3, out2 + (n2+1), out2 + n2, n2-1);
511 }
512 else
513 {
514 if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n);
515 dsp_add(sigrfft_perform, 2, out1, n);
516 dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1);
517 }
518 dsp_add_zero(out1 + n2, n2);
519 dsp_add_zero(out2 + n2, n2);
520}
521
522static void sigrfft_setup(void)
523{
524 sigrfft_class = class_new(gensym("rfft~"), sigrfft_new, 0,
525 sizeof(t_sigrfft), 0, 0);
526 CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, x_f);
527 class_addmethod(sigrfft_class, (t_method)sigrfft_dsp, gensym("dsp"), 0);
528 class_sethelpsymbol(sigrfft_class, gensym("fft~"));
529}
530
531/* ----------------------- rifft~ -------------------------------- */
532
533static t_class *sigrifft_class;
534
535typedef struct rifft
536{
537 t_object x_obj;
538 float x_f;
539} t_sigrifft;
540
541static void *sigrifft_new(void)
542{
543 t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class);
544 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
545 outlet_new(&x->x_obj, gensym("signal"));
546 x->x_f = 0;
547 return (x);
548}
549
550static t_int *sigrifft_perform(t_int *w)
551{
552 t_sample *in = (t_sample *)(w[1]);
553 int n = w[2];
554 mayer_realifft(n, in);
555 return (w+3);
556}
557
558static void sigrifft_dsp(t_sigrifft *x, t_signal **sp)
559{
560 int n = sp[0]->s_n, n2 = (n>>1);
561 t_sample *in1 = sp[0]->s_vec;
562 t_sample *in2 = sp[1]->s_vec;
563 t_sample *out1 = sp[2]->s_vec;
564 if (n < 4)
565 {
566 error("fft: minimum 4 points");
567 return;
568 }
569 if (in2 == out1)
570 {
571 dsp_add(sigrfft_flip, 3, out1+1, out1 + n, (n2-1));
572 dsp_add(copy_perform, 3, in1, out1, n2);
573 }
574 else
575 {
576 if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2);
577 dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1);
578 }
579 dsp_add(sigrifft_perform, 2, out1, n);
580}
581
582static void sigrifft_setup(void)
583{
584 sigrifft_class = class_new(gensym("rifft~"), sigrifft_new, 0,
585 sizeof(t_sigrifft), 0, 0);
586 CLASS_MAINSIGNALIN(sigrifft_class, t_sigrifft, x_f);
587 class_addmethod(sigrifft_class, (t_method)sigrifft_dsp, gensym("dsp"), 0);
588 class_sethelpsymbol(sigrifft_class, gensym("fft~"));
589}
590
591/* ----------------------- framp~ -------------------------------- */
592
593#if 0
594static t_class *sigframp_class;
595
596typedef struct framp
597{
598 t_object x_obj;
599 float x_f;
600} t_sigframp;
601
602static void *sigframp_new(void)
603{
604 t_sigframp *x = (t_sigframp *)pd_new(sigframp_class);
605 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
606 outlet_new(&x->x_obj, gensym("signal"));
607 outlet_new(&x->x_obj, gensym("signal"));
608 x->x_f = 0;
609 return (x);
610}
611
612static t_int *sigframp_perform(t_int *w)
613{
614 float *inreal = (t_float *)(w[1]);
615 float *inimag = (t_float *)(w[2]);
616 float *outfreq = (t_float *)(w[3]);
617 float *outamp = (t_float *)(w[4]);
618 float lastreal = 0, currentreal = inreal[0], nextreal = inreal[1];
619 float lastimag = 0, currentimag = inimag[0], nextimag = inimag[1];
620 int n = w[5];
621 int m = n + 1;
622 float fbin = 1, oneovern2 = 1.f/((float)n * (float)n);
623
624 inreal += 2;
625 inimag += 2;
626 *outamp++ = *outfreq++ = 0;
627 n -= 2;
628 while (n--)
629 {
630 float re, im, pow, freq;
631 lastreal = currentreal;
632 currentreal = nextreal;
633 nextreal = *inreal++;
634 lastimag = currentimag;
635 currentimag = nextimag;
636 nextimag = *inimag++;
637 re = currentreal - 0.5f * (lastreal + nextreal);
638 im = currentimag - 0.5f * (lastimag + nextimag);
639 pow = re * re + im * im;
640 if (pow > 1e-19)
641 {
642 float detune = ((lastreal - nextreal) * re +
643 (lastimag - nextimag) * im) / (2.0f * pow);
644 if (detune > 2 || detune < -2) freq = pow = 0;
645 else freq = fbin + detune;
646 }
647 else freq = pow = 0;
648 *outfreq++ = freq;
649 *outamp++ = oneovern2 * pow;
650 fbin += 1.0f;
651 }
652 while (m--) *outamp++ = *outfreq++ = 0;
653 return (w+6);
654}
655
656t_int *sigsqrt_perform(t_int *w);
657
658static void sigframp_dsp(t_sigframp *x, t_signal **sp)
659{
660 int n = sp[0]->s_n, n2 = (n>>1);
661 if (n < 4)
662 {
663 error("framp: minimum 4 points");
664 return;
665 }
666 dsp_add(sigframp_perform, 5, sp[0]->s_vec, sp[1]->s_vec,
667 sp[2]->s_vec, sp[3]->s_vec, n2);
668 dsp_add(sigsqrt_perform, 3, sp[3]->s_vec, sp[3]->s_vec, n2);
669}
670
671static void sigframp_setup(void)
672{
673 sigframp_class = class_new(gensym("framp~"), sigframp_new, 0,
674 sizeof(t_sigframp), 0, 0);
675 CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, x_f);
676 class_addmethod(sigframp_class, (t_method)sigframp_dsp, gensym("dsp"), 0);
677}
678#endif
679
680/* ------------------------ global setup routine ------------------------- */
681
682void d_fft_setup(void)
683{
684 sigfft_setup();
685 sigrfft_setup();
686 sigrifft_setup();
687// sigframp_setup();
688}
diff --git a/apps/plugins/pdbox/PDa/src/d_fftroutine.c b/apps/plugins/pdbox/PDa/src/d_fftroutine.c
new file mode 100644
index 0000000000..dde24fa358
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_fftroutine.c
@@ -0,0 +1,2002 @@
1/*****************************************************************************/
2/* */
3/* Fast Fourier Transform */
4/* Network Abstraction, Definitions */
5/* Kevin Peterson, MIT Media Lab, EMS */
6/* UROP - Fall '86 */
7/* REV: 6/12/87(KHP) - To incorporate link list of different sized networks */
8/* */
9/*****************************************************************************/
10
11/*****************************************************************************/
12/* added debug option 5/91 brown@nadia */
13/* change sign at AAA */
14/* */
15/* Fast Fourier Transform */
16/* FFT Network Interaction and Support Modules */
17/* Kevin Peterson, MIT Media Lab, EMS */
18/* UROP - Fall '86 */
19/* REV: 6/12/87(KHP) - Generalized to one procedure call with typed I/O */
20/* */
21/*****************************************************************************/
22
23/* Overview:
24
25 My realization of the FFT involves a representation of a network of
26 "butterfly" elements that takes a set of 'N' sound samples as input and
27 computes the discrete Fourier transform. This network consists of a
28 series of stages (log2 N), each stage consisting of N/2 parallel butterfly
29 elements. Consecutive stages are connected by specific, predetermined flow
30 paths, (see Oppenheim, Schafer for details) and each butterfly element has
31 an associated multiplicative coefficient.
32
33 FFT NETWORK:
34 -----------
35 ____ _ ____ _ ____ _ ____ _ ____
36 o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
37 |reg1| | | |W^r1| | | |reg1| | | |W^r1| | | |reg1|
38 | | | | | | | | | | | | | | | | | | .....
39 | | | | | | | | | | | | | | | | | |
40 o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
41 | | | | | | | |
42 | | | | | | | |
43 ____ | | ____ | | ____ | | ____ | | ____
44 o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
45 |reg2| | | |W^r2| | | |reg2| | | |W^r2| | | |reg2|
46 | | | | | | | | | | | | | | | | | | .....
47 | | | | | | | | | | | | | | | | | |
48 o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
49 | | | | | | | |
50 | | | | | | | |
51 : : : : : : : : :
52 : : : : : : : : :
53 : : : : : : : : :
54 : : : : : : : : :
55 : : : : : : : : :
56
57 ____ | | ____ | | ____ | | ____ | | ____
58 o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
59 |reg | | | |W^r | | | |reg | | | |W^r | | | |reg |
60 | N/2| | | | N/2| | | | N/2| | | | N/2| | | | N/2| .....
61 | | | | | | | | | | | | | | | | | |
62 o--|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|--o
63
64 ^ ^ ^ ^
65 Initial | Bttrfly | Rd/Wrt | Bttrfly | Rd/Wrt
66 Buffer | | Register | | Register
67 |____________|____________|____________|
68 |
69 |
70 Interconnect
71 Paths
72
73 The use of "in-place" computation permits one to use only one set of
74 registers realized by an array of complex number structures. To describe
75 the coefficients for each butterfly I am using a two dimensional array
76 (stage, butterfly) of complex numbers. The predetermined stage connections
77 will be described in a two dimensional array of indicies. These indicies
78 will be used to determine the order of reading at each stage of the
79 computation.
80*/
81
82
83/*****************************************************************************/
84/* INCLUDE FILES */
85/*****************************************************************************/
86
87#include <stdio.h>
88#include <math.h>
89#include <stdlib.h>
90
91 /* the following is needed only to declare pd_fft() as exportable in MSW */
92#include "m_pd.h"
93
94/* some basic definitions */
95#ifndef BOOL
96#define BOOL int
97#define TRUE 1
98#define FALSE 0
99#endif
100
101#define SAMPLE float /* data type used in calculation */
102
103#define SHORT_SIZE sizeof(short)
104#define INT_SIZE sizeof(int)
105#define FLOAT_SIZE sizeof(float)
106#define SAMPLE_SIZE sizeof(SAMPLE)
107#define PNTR_SIZE sizeof(char *)
108
109#define PI 3.1415927
110#define TWO_PI 6.2831854
111
112/* type definitions for I/O buffers */
113#define REAL 0 /* real only */
114#define IMAG 2 /* imaginary only */
115#define RECT 8 /* real and imaginary */
116#define MAG 16 /* magnitude only */
117#define PHASE 32 /* phase only */
118#define POLAR 64 /* magnitude and phase*/
119
120/* scale definitions for I/O buffers */
121#define LINEAR 0
122#define DB 1 /* 20log10 */
123
124/* transform direction definition */
125#define FORWARD 1 /* Forward FFT */
126#define INVERSE 2 /* Inverse FFT */
127
128/* window type definitions */
129#define HANNING 1
130#define RECTANGULAR 0
131
132
133
134/* network structure definition */
135
136typedef struct Tfft_net {
137 int n;
138 int stages;
139 int bps;
140 int direction;
141 int window_type;
142 int *load_index;
143 SAMPLE *window, *inv_window;
144 SAMPLE *regr;
145 SAMPLE *regi;
146 SAMPLE **indexpr;
147 SAMPLE **indexpi;
148 SAMPLE **indexqr;
149 SAMPLE **indexqi;
150 SAMPLE *coeffr, *inv_coeffr;
151 SAMPLE *coeffi, *inv_coeffi;
152 struct Tfft_net *next;
153} FFT_NET;
154
155
156void cfft(int trnsfrm_dir, int npnt, int window,
157 float *source_buf, int source_form, int source_scale,
158 float *result_buf, int result_form, int result_scale, int debug);
159
160
161/*****************************************************************************/
162/* GLOBAL DECLARATIONS */
163/*****************************************************************************/
164
165static FFT_NET *firstnet;
166
167/* prototypes */
168
169void net_alloc(FFT_NET *fft_net);
170void net_dealloc(FFT_NET *fft_net);
171int power_of_two(int n);
172void create_hanning(SAMPLE *window, int n, SAMPLE scale);
173void create_rectangular(SAMPLE *window, int n, SAMPLE scale);
174void short_to_float(short *short_buf, float *float_buf, int n);
175void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
176 int buf_scale, int trnsfrm_dir);
177void compute_fft(FFT_NET *fft_net);
178void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
179 int buf_scale, int debug);
180void build_fft_network(FFT_NET *fft_net, int n, int window_type);
181
182/*****************************************************************************/
183/* GENERALIZED FAST FOURIER TRANSFORM MODULE */
184/*****************************************************************************/
185
186void cfft(int trnsfrm_dir, int npnt, int window,
187 float *source_buf, int source_form, int source_scale,
188 float *result_buf, int result_form, int result_scale, int debug)
189
190/* modifies: result_buf
191 effects: Computes npnt FFT specified by form, scale, and dir parameters.
192 Source samples (single precision float) are taken from soure_buf and
193 the transfrmd representation is stored in result_buf (single precision
194 float). The parameters are defined as follows:
195
196 trnsfrm_dir = FORWARD | INVERSE
197 npnt = 2^k for some any positive integer k
198 window = HANNING | RECTANGULAR
199 (RECT = real and imag parts, POLAR = magnitude and phase)
200 source_form = REAL | IMAG | RECT | POLAR
201 result_form = REAL | IMAG | RECT | MAG | PHASE | POLAR
202 xxxxxx_scale= LINEAR | DB ( 20log10 |mag| )
203
204 The input/output buffers are stored in a form appropriate to the type.
205 For example: REAL => {real, real, real ...},
206 MAG => {mag, mag, mag, ... },
207 RECT => {real, imag, real, imag, ... },
208 POLAR => {mag, phase, mag, phase, ... }.
209
210 To look at the magnitude (in db) of a 1024 point FFT of a real time
211 signal we have:
212
213 fft(FORWARD, 1024, RECTANGULAR, input, REAL, LINEAR, output, MAG, DB)
214
215 All possible input and output combinations are possible given the
216 choice of type and scale parameters.
217*/
218
219{
220 FFT_NET *thisnet = (FFT_NET *)0;
221 FFT_NET *lastnet = (FFT_NET *)0;
222
223 /* A linked list of fft networks of different sizes is maintained to
224 avoid building with every call. The network is built on the first
225 call but reused for subsequent calls requesting the same size
226 transformation.
227 */
228
229 thisnet=firstnet;
230 while (thisnet) {
231 if (!(thisnet->n == npnt) || !(thisnet->window_type == window)) {
232 /* current net doesn't match size or window type */
233 lastnet=thisnet;
234 thisnet=thisnet->next;
235 continue; /* keep looking */
236 }
237
238 else { /* network matches desired size */
239 load_registers(thisnet, source_buf, source_form, source_scale,
240 trnsfrm_dir);
241 compute_fft(thisnet); /* do transformation */
242 store_registers(thisnet, result_buf, result_form, result_scale,debug);
243 return;
244 }
245 }
246
247 /* none of existing networks match required size*/
248
249 if (lastnet) { /* add new network to end of list */
250 thisnet = (FFT_NET *)malloc(sizeof(FFT_NET)); /* allocate */
251 thisnet->next = 0;
252 lastnet->next = thisnet; /* add to end of list */
253 }
254 else { /* first network to be created */
255 thisnet=firstnet=(FFT_NET *)malloc(sizeof(FFT_NET)); /* alloc. */
256 thisnet->next = 0;
257 }
258
259 /* build new network and compute transformation */
260 build_fft_network(thisnet, npnt, window);
261 load_registers(thisnet, source_buf, source_form, source_scale,
262 trnsfrm_dir);
263 compute_fft(thisnet);
264 store_registers(thisnet, result_buf, result_form, result_scale,debug);
265 return;
266}
267
268void fft_clear(void)
269
270/* effects: Deallocates all preserved FFT networks. Should be used when
271 finished with all computations.
272*/
273
274{
275 FFT_NET *thisnet, *nextnet;
276
277 if (firstnet) {
278 thisnet=firstnet;
279 do {
280 nextnet = thisnet->next;
281 net_dealloc(thisnet);
282 free((char *)thisnet);
283 } while (thisnet = nextnet);
284 }
285}
286
287
288/*****************************************************************************/
289/* NETWORK CONSTRUCTION */
290/*****************************************************************************/
291
292void build_fft_network(FFT_NET *fft_net, int n, int window_type)
293
294
295/* modifies:fft_net
296 effects: Constructs the fft network as described in fft.h. Butterfly
297 coefficients, read/write indicies, bit reversed load indicies,
298 and array allocations are computed.
299*/
300
301{
302 int cntr, i, j, s;
303 int stages, bps;
304 int **p, **q, *pp, *qp;
305 SAMPLE two_pi_div_n = TWO_PI / n;
306
307
308 /* network definition */
309 fft_net->n = n;
310 fft_net->bps = bps = n/2;
311 for (i = 0, j = n; j > 1; j >>= 1, i++);
312 fft_net->stages = stages = i;
313 fft_net->direction = FORWARD;
314 fft_net->window_type = window_type;
315 fft_net->next = (FFT_NET *)0;
316
317 /* allocate registers, index, coefficient arrays */
318 net_alloc(fft_net);
319
320
321 /* create appropriate windows */
322 if (window_type==HANNING) {
323 create_hanning(fft_net->window, n, 1.);
324 create_hanning(fft_net->inv_window, n, 1./n);
325 }
326 else {
327 create_rectangular(fft_net->window, n, 1.);
328 create_rectangular(fft_net->inv_window, n, 1./n);
329 }
330
331
332 /* calculate butterfly coefficients */ {
333
334 int num_diff_coeffs, power_inc, power;
335 SAMPLE *coeffpr = fft_net->coeffr;
336 SAMPLE *coeffpi = fft_net->coeffi;
337 SAMPLE *inv_coeffpr = fft_net->inv_coeffr;
338 SAMPLE *inv_coeffpi = fft_net->inv_coeffi;
339
340 /* stage one coeffs are 1 + 0j */
341 for (i = 0; i < bps; i++) {
342 *coeffpr = *inv_coeffpr = 1.;
343 *coeffpi = *inv_coeffpi = 0.;
344 coeffpr++; inv_coeffpr++;
345 coeffpi++; inv_coeffpi++;
346 }
347
348 /* stage 2 to last stage coeffs need calculation */
349 /* (1<<r <=> 2^r */
350 for (s = 2; s <= stages; s++) {
351
352 num_diff_coeffs = n / (1 << (stages - s + 1));
353 power_inc = 1 << (stages -s);
354 cntr = 0;
355
356 for (i = bps/num_diff_coeffs; i > 0; i--) {
357
358 power = 0;
359
360 for (j = num_diff_coeffs; j > 0; j--) {
361 *coeffpr = cos(two_pi_div_n*power);
362 *inv_coeffpr = cos(two_pi_div_n*power);
363/* AAA change these signs */ *coeffpi = -sin(two_pi_div_n*power);
364/* change back */ *inv_coeffpi = sin(two_pi_div_n*power);
365 power += power_inc;
366 coeffpr++; inv_coeffpr++;
367 coeffpi++; inv_coeffpi++;
368 }
369 }
370 }
371 }
372
373 /* calculate network indicies: stage exchange indicies are
374 calculated and then used as offset values from the base
375 register locations. The final addresses are then stored in
376 fft_net.
377 */ {
378
379 int index, inc;
380 SAMPLE **indexpr = fft_net->indexpr;
381 SAMPLE **indexpi = fft_net->indexpi;
382 SAMPLE **indexqr = fft_net->indexqr;
383 SAMPLE **indexqi = fft_net->indexqi;
384 SAMPLE *regr = fft_net->regr;
385 SAMPLE *regi = fft_net->regi;
386
387
388 /* allocate temporary 2d stage exchange index, 1d temp
389 load index */
390 p = (int **)malloc(stages * PNTR_SIZE);
391 q = (int **)malloc(stages * PNTR_SIZE);
392
393 for (s = 0; s < stages; s++) {
394 p[s] = (int *)malloc(bps * INT_SIZE);
395 q[s] = (int *)malloc(bps * INT_SIZE);
396 }
397
398 /* calculate stage exchange indicies: */
399 for (s = 0; s < stages; s++) {
400 pp = p[s];
401 qp = q[s];
402 inc = 1 << s;
403 cntr = 1 << (stages-s-1);
404 i = j = index = 0;
405
406 do {
407 do {
408 qp[i] = index + inc;
409 pp[i++] = index++;
410 } while (++j < inc);
411 index = qp[i-1] + 1;
412 j = 0;
413 } while (--cntr);
414 }
415
416 /* compute actual address values using indicies as offsets */
417 for (s = 0; s < stages; s++) {
418 for (i = 0; i < bps; i++) {
419 *indexpr++ = regr + p[s][i];
420 *indexpi++ = regi + p[s][i];
421 *indexqr++ = regr + q[s][i];
422 *indexqi++ = regi + q[s][i];
423 }
424 }
425 }
426
427
428 /* calculate load indicies (bit reverse ordering) */
429 /* bit reverse ordering achieved by passing normal
430 order indicies backwards through the network */
431
432 /* init to normal order indicies */ {
433 int *load_index,*load_indexp;
434 int *temp_indexp, *temp_index;
435 temp_index=temp_indexp=(int *)malloc(n * INT_SIZE);
436
437 i = 0; j = n;
438 load_index = load_indexp = fft_net->load_index;
439
440 while (j--)
441 *load_indexp++ = i++;
442
443 /* pass indicies backwards through net */
444 for (s = stages - 1; s > 0; s--) {
445 pp = p[s];
446 qp = q[s];
447
448 for (i = 0; i < bps; i++) {
449 temp_index[pp[i]]=load_index[2*i];
450 temp_index[qp[i]]=load_index[2*i+1];
451 }
452 j = n;
453 load_indexp = load_index;
454 temp_indexp = temp_index;
455 while (j--)
456 *load_indexp++ = *temp_indexp++;
457 }
458
459 /* free all temporary arrays */
460 free((char *)temp_index);
461 for (s = 0; s < stages; s++) {
462 free((char *)p[s]);free((char *)q[s]);
463 }
464 free((char *)p);free((char *)q);
465 }
466}
467
468
469
470/*****************************************************************************/
471/* REGISTER LOAD AND STORE */
472/*****************************************************************************/
473
474void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
475 int buf_scale, int trnsfrm_dir)
476
477/* effects: Multiplies the input buffer with the appropriate window and
478 stores the resulting values in the initial registers of the
479 network. Input buffer must contain values appropriate to form.
480 For RECT, the buffer contains real num. followed by imag num,
481 and for POLAR, it contains magnitude followed by phase. Pure
482 inputs are listed normally. Both LINEAR and DB scales are
483 interpreted.
484*/
485
486{
487 int *load_index = fft_net->load_index;
488 SAMPLE *window;
489 int index, i = 0, n = fft_net->n;
490
491 if (trnsfrm_dir==FORWARD) window = fft_net->window;
492 else if (trnsfrm_dir==INVERSE) window = fft_net->inv_window;
493 else {
494 fprintf(stderr, "load_registers:illegal transform direction\n");
495 exit(0);
496 }
497 fft_net->direction = trnsfrm_dir;
498
499 switch(buf_scale) {
500 case LINEAR: {
501
502 switch (buf_form) {
503 case REAL: { /* pure REAL */
504 while (i < fft_net->n) {
505 index = load_index[i];
506 fft_net->regr[i]=(SAMPLE)buf[index] * window[index];
507 fft_net->regi[i]=0.;
508 i++;
509 }
510 } break;
511
512 case IMAG: { /* pure IMAGinary */
513 while (i < fft_net->n) {
514 index = load_index[i];
515 fft_net->regr[i]=0;
516 fft_net->regi[i]=(SAMPLE)buf[index] * window[index];
517 i++;
518 }
519 } break;
520
521 case RECT: { /* both REAL and IMAGinary */
522 while (i < fft_net->n) {
523 index = load_index[i];
524 fft_net->regr[i]=(SAMPLE)buf[index*2] * window[index];
525 fft_net->regi[i]=(SAMPLE)buf[index*2+1] * window[index];
526 i++;
527 }
528 } break;
529
530 case POLAR: { /* magnitude followed by phase */
531 while (i < fft_net->n) {
532 index = load_index[i];
533 fft_net->regr[i]=(SAMPLE)(buf[index*2] * cos(buf[index*2+1]))
534 * window[index];
535 fft_net->regi[i]=(SAMPLE)(buf[index*2] * sin(buf[index*2+1]))
536 * window[index];
537 i++;
538 }
539 } break;
540
541 default: {
542 fprintf(stderr, "load_registers:illegal input form\n");
543 exit(0);
544 } break;
545 }
546 } break;
547
548 case DB: {
549
550 switch (buf_form) {
551 case REAL: { /* log pure REAL */
552 while (i < fft_net->n) {
553 index = load_index[i];
554 fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
555 * window[index]; /* window scaling after linearization */
556 fft_net->regi[i]=0.;
557 i++;
558 }
559 } break;
560
561 case IMAG: { /* log pure IMAGinary */
562 while (i < fft_net->n) {
563 index = load_index[i];
564 fft_net->regr[i]=0.;
565 fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
566 * window[index];
567 i++;
568 }
569 } break;
570
571 case RECT: { /* log REAL and log IMAGinary */
572 while (i < fft_net->n) {
573 index = load_index[i];
574 fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2])
575 * window[index];
576 fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2+1])
577 * window[index];
578 i++;
579 }
580 } break;
581
582 case POLAR: { /* log mag followed by phase */
583 while (i < fft_net->n) {
584 index = load_index[i];
585 fft_net->regr[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
586 * cos(buf[index*2+1])) * window[index];
587 fft_net->regi[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
588 * sin(buf[index*2+1])) * window[index];
589 i++;
590 }
591 } break;
592
593 default: {
594 fprintf(stderr, "load_registers:illegal input form\n");
595 exit(0);
596 } break;
597 }
598 } break;
599
600 default: {
601 fprintf(stderr, "load_registers:illegal input scale\n");
602 exit(0);
603 } break;
604 }
605}
606
607
608void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
609 int buf_scale, int debug)
610
611/* modifies: buf
612 effects: Writes the final contents of the network registers into buf in
613 either linear or db scale, polar or rectangular form. If any of
614 the pure forms(REAL, IMAG, MAG, or PHASE) are used then only the
615 corresponding part of the registers is stored in buf.
616*/
617
618{
619 int i;
620 SAMPLE real, imag, mag, phase;
621 int n;
622
623 i = 0;
624 n = fft_net->n;
625
626 switch (buf_scale) {
627 case LINEAR: {
628
629 switch (buf_form) {
630 case REAL: { /* pure REAL */
631 do {
632 *buf++ = (float)fft_net->regr[i];
633 } while (++i < n);
634 } break;
635
636 case IMAG: { /* pure IMAGinary */
637 do {
638 *buf++ = (float)fft_net->regi[i];
639 } while (++i < n);
640 } break;
641
642 case RECT: { /* both REAL and IMAGinary */
643 do {
644 *buf++ = (float)fft_net->regr[i];
645 *buf++ = (float)fft_net->regi[i];
646 } while (++i < n);
647 } break;
648
649 case MAG: { /* magnitude only */
650 do {
651 real = fft_net->regr[i];
652 imag = fft_net->regi[i];
653 *buf++ = (float)sqrt(real*real+imag*imag);
654 } while (++i < n);
655 } break;
656
657 case PHASE: { /* phase only */
658 do {
659 real = fft_net->regr[i];
660 imag = fft_net->regi[i];
661 if (real > .00001)
662 *buf++ = (float)atan2(imag, real);
663 else { /* deal with bad case */
664 if (imag > 0){ *buf++ = PI / 2.;
665 if(debug) fprintf(stderr,"real=0 and imag > 0\n");}
666 else if (imag < 0){ *buf++ = -PI / 2.;
667 if(debug) fprintf(stderr,"real=0 and imag < 0\n");}
668 else { *buf++ = 0;
669 if(debug) fprintf(stderr,"real=0 and imag=0\n");}
670 }
671 } while (++i < n);
672 } break;
673
674 case POLAR: { /* magnitude and phase */
675 do {
676 real = fft_net->regr[i];
677 imag = fft_net->regi[i];
678 *buf++ = (float)sqrt(real*real+imag*imag);
679 if (real) /* a hack to avoid div by zero */
680 *buf++ = (float)atan2(imag, real);
681 else { /* deal with bad case */
682 if (imag > 0) *buf++ = PI / 2.;
683 else if (imag < 0) *buf++ = -PI / 2.;
684 else *buf++ = 0;
685 }
686 } while (++i < n);
687 } break;
688
689 default: {
690 fprintf(stderr, "store_registers:illegal output form\n");
691 exit(0);
692 } break;
693 }
694 } break;
695
696 case DB: {
697
698 switch (buf_form) {
699 case REAL: { /* real only */
700 do {
701 *buf++ = (float)20.*log10(fft_net->regr[i]);
702 } while (++i < n);
703 } break;
704
705 case IMAG: { /* imag only */
706 do {
707 *buf++ = (float)20.*log10(fft_net->regi[i]);
708 } while (++i < n);
709 } break;
710
711 case RECT: { /* real and imag */
712 do {
713 *buf++ = (float)20.*log10(fft_net->regr[i]);
714 *buf++ = (float)20.*log10(fft_net->regi[i]);
715 } while (++i < n);
716 } break;
717
718 case MAG: { /* magnitude only */
719 do {
720 real = fft_net->regr[i];
721 imag = fft_net->regi[i];
722 *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
723 } while (++i < n);
724 } break;
725
726 case PHASE: { /* phase only */
727 do {
728 real = fft_net->regr[i];
729 imag = fft_net->regi[i];
730 if (real)
731 *buf++ = (float)atan2(imag, real);
732 else { /* deal with bad case */
733 if (imag > 0) *buf++ = PI / 2.;
734 else if (imag < 0) *buf++ = -PI / 2.;
735 else *buf++ = 0;
736 }
737 } while (++i < n);
738 } break;
739
740 case POLAR: { /* magnitude and phase */
741 do {
742 real = fft_net->regr[i];
743 imag = fft_net->regi[i];
744 *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
745 if (real)
746 *buf++ = (float)atan2(imag, real);
747 else { /* deal with bad case */
748 if (imag > 0) *buf++ = PI / 2.;
749 else if (imag < 0) *buf++ = -PI / 2.;
750 else *buf++ = 0;
751 }
752 } while (++i < n);
753 } break;
754
755 default: {
756 fprintf(stderr, "store_registers:illegal output form\n");
757 exit(0);
758 } break;
759 }
760 } break;
761
762 default: {
763 fprintf(stderr, "store_registers:illegal output scale\n");
764 exit(0);
765 } break;
766 }
767}
768
769
770
771/*****************************************************************************/
772/* COMPUTE TRANSFORMATION */
773/*****************************************************************************/
774
775void compute_fft(FFT_NET *fft_net)
776
777
778/* modifies: fft_net
779 effects: Passes the values (already loaded) in the registers through
780 the network, multiplying with appropriate coefficients at each
781 stage. The fft result will be in the registers at the end of
782 the computation. The direction of the transformation is indicated
783 by the network flag 'direction'. The form of the computation is:
784
785 X(pn) = X(p) + C*X(q)
786 X(qn) = X(p) - C*X(q)
787
788 where X(pn,qn) represents the output of the registers at each stage.
789 The calculations are actually done in place. Register pointers are
790 used to speed up the calculations.
791
792 Register and coefficient addresses involved in the calculations
793 are stored sequentially and are accessed as such. fft_net->indexp,
794 indexq contain pointers to the relevant addresses, and fft_net->coeffs,
795 inv_coeffs points to the appropriate coefficients at each stage of the
796 computation.
797*/
798
799{
800 SAMPLE **xpr, **xpi, **xqr, **xqi, *cr, *ci;
801 int i;
802 SAMPLE tpr, tpi, tqr, tqi;
803 int bps = fft_net->bps;
804 int cnt = bps * (fft_net->stages - 1);
805
806 /* predetermined register addresses and coefficients */
807 xpr = fft_net->indexpr;
808 xpi = fft_net->indexpi;
809 xqr = fft_net->indexqr;
810 xqi = fft_net->indexqi;
811
812 if (fft_net->direction==FORWARD) { /* FORWARD FFT coefficients */
813 cr = fft_net->coeffr;
814 ci = fft_net->coeffi;
815 }
816 else { /* INVERSE FFT coefficients */
817 cr = fft_net->inv_coeffr;
818 ci = fft_net->inv_coeffi;
819 }
820
821 /* stage one coefficients are 1 + 0j so C*X(q)=X(q) */
822 /* bps mults can be avoided */
823
824 for (i = 0; i < bps; i++) {
825
826 /* add X(p) and X(q) */
827 tpr = **xpr + **xqr;
828 tpi = **xpi + **xqi;
829 tqr = **xpr - **xqr;
830 tqi = **xpi - **xqi;
831
832 /* exchange register with temp */
833 **xpr = tpr;
834 **xpi = tpi;
835 **xqr = tqr;
836 **xqi = tqi;
837
838 /* next set of register for calculations: */
839 xpr++; xpi++; xqr++; xqi++; cr++; ci++;
840
841 }
842
843 for (i = 0; i < cnt; i++) {
844
845 /* mult X(q) by coeff C */
846 tqr = **xqr * *cr - **xqi * *ci;
847 tqi = **xqr * *ci + **xqi * *cr;
848
849 /* exchange register with temp */
850 **xqr = tqr;
851 **xqi = tqi;
852
853 /* add X(p) and X(q) */
854 tpr = **xpr + **xqr;
855 tpi = **xpi + **xqi;
856 tqr = **xpr - **xqr;
857 tqi = **xpi - **xqi;
858
859 /* exchange register with temp */
860 **xpr = tpr;
861 **xpi = tpi;
862 **xqr = tqr;
863 **xqi = tqi;
864 /* next set of register for calculations: */
865 xpr++; xpi++; xqr++; xqi++; cr++; ci++;
866 }
867}
868
869
870/****************************************************************************/
871/* SUPPORT MODULES */
872/****************************************************************************/
873
874void net_alloc(FFT_NET *fft_net)
875
876
877/* effects: Allocates appropriate two dimensional arrays and assigns
878 correct internal pointers.
879*/
880
881{
882
883 int stages, bps, n;
884
885 n = fft_net->n;
886 stages = fft_net->stages;
887 bps = fft_net->bps;
888
889
890 /* two dimensional arrays with elements stored sequentially */
891
892 fft_net->load_index = (int *)malloc(n * INT_SIZE);
893 fft_net->regr = (SAMPLE *)malloc(n * SAMPLE_SIZE);
894 fft_net->regi = (SAMPLE *)malloc(n * SAMPLE_SIZE);
895 fft_net->coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
896 fft_net->coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
897 fft_net->inv_coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
898 fft_net->inv_coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
899 fft_net->indexpr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
900 fft_net->indexpi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
901 fft_net->indexqr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
902 fft_net->indexqi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
903
904 /* one dimensional load window */
905 fft_net->window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
906 fft_net->inv_window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
907}
908
909void net_dealloc(FFT_NET *fft_net)
910
911
912/* effects: Deallocates given FFT network.
913*/
914
915{
916
917 free((char *)fft_net->load_index);
918 free((char *)fft_net->regr);
919 free((char *)fft_net->regi);
920 free((char *)fft_net->coeffr);
921 free((char *)fft_net->coeffi);
922 free((char *)fft_net->inv_coeffr);
923 free((char *)fft_net->inv_coeffi);
924 free((char *)fft_net->indexpr);
925 free((char *)fft_net->indexpi);
926 free((char *)fft_net->indexqr);
927 free((char *)fft_net->indexqi);
928 free((char *)fft_net->window);
929 free((char *)fft_net->inv_window);
930}
931
932
933BOOL power_of_two(n)
934
935int n;
936
937/* effects: Returns TRUE if n is a power of two, otherwise FALSE.
938*/
939
940{
941 int i;
942
943 for (i = n; i > 1; i >>= 1)
944 if (i & 1) return FALSE; /* more than one bit high */
945 return TRUE;
946}
947
948
949void create_hanning(SAMPLE *window, int n, SAMPLE scale)
950
951/* effects: Fills the buffer window with a hanning window of the appropriate
952 size scaled by scale.
953*/
954
955{
956 SAMPLE a, pi_div_n = PI/n;
957 int k;
958
959 for (k=1; k <= n; k++) {
960 a = sin(k * pi_div_n);
961 *window++ = scale * a * a;
962 }
963}
964
965
966void create_rectangular(SAMPLE *window, int n, SAMPLE scale)
967
968/* effects: Fills the buffer window with a rectangular window of the
969 appropriate size of height scale.
970*/
971
972{
973 while (n--)
974 *window++ = scale;
975}
976
977
978void short_to_float(short *short_buf, float *float_buf, int n)
979
980/* effects; Converts short_buf to floats and stores them in float_buf.
981*/
982
983{
984 while (n--) {
985 *float_buf++ = (float)*short_buf++;
986 }
987}
988
989
990/* here's the meat: */
991
992void pd_fft(float *buf, int npoints, int inverse)
993{
994 double renorm;
995 float *fp, *fp2;
996 int i;
997 renorm = (inverse ? npoints : 1.);
998 cfft((inverse ? INVERSE : FORWARD), npoints, RECTANGULAR,
999 buf, RECT, LINEAR, buf, RECT, LINEAR, 0);
1000 for (i = npoints << 1, fp = buf; i--; fp++) *fp *= renorm;
1001}
1002/*****************************************************************************/
1003/* */
1004/* Fast Fourier Transform */
1005/* Network Abstraction, Definitions */
1006/* Kevin Peterson, MIT Media Lab, EMS */
1007/* UROP - Fall '86 */
1008/* REV: 6/12/87(KHP) - To incorporate link list of different sized networks */
1009/* */
1010/*****************************************************************************/
1011
1012/*****************************************************************************/
1013/* added debug option 5/91 brown@nadia */
1014/* change sign at AAA */
1015/* */
1016/* Fast Fourier Transform */
1017/* FFT Network Interaction and Support Modules */
1018/* Kevin Peterson, MIT Media Lab, EMS */
1019/* UROP - Fall '86 */
1020/* REV: 6/12/87(KHP) - Generalized to one procedure call with typed I/O */
1021/* */
1022/*****************************************************************************/
1023
1024/* Overview:
1025
1026 My realization of the FFT involves a representation of a network of
1027 "butterfly" elements that takes a set of 'N' sound samples as input and
1028 computes the discrete Fourier transform. This network consists of a
1029 series of stages (log2 N), each stage consisting of N/2 parallel butterfly
1030 elements. Consecutive stages are connected by specific, predetermined flow
1031 paths, (see Oppenheim, Schafer for details) and each butterfly element has
1032 an associated multiplicative coefficient.
1033
1034 FFT NETWORK:
1035 -----------
1036 ____ _ ____ _ ____ _ ____ _ ____
1037 o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
1038 |reg1| | | |W^r1| | | |reg1| | | |W^r1| | | |reg1|
1039 | | | | | | | | | | | | | | | | | | .....
1040 | | | | | | | | | | | | | | | | | |
1041 o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
1042 | | | | | | | |
1043 | | | | | | | |
1044 ____ | | ____ | | ____ | | ____ | | ____
1045 o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
1046 |reg2| | | |W^r2| | | |reg2| | | |W^r2| | | |reg2|
1047 | | | | | | | | | | | | | | | | | | .....
1048 | | | | | | | | | | | | | | | | | |
1049 o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
1050 | | | | | | | |
1051 | | | | | | | |
1052 : : : : : : : : :
1053 : : : : : : : : :
1054 : : : : : : : : :
1055 : : : : : : : : :
1056 : : : : : : : : :
1057
1058 ____ | | ____ | | ____ | | ____ | | ____
1059 o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
1060 |reg | | | |W^r | | | |reg | | | |W^r | | | |reg |
1061 | N/2| | | | N/2| | | | N/2| | | | N/2| | | | N/2| .....
1062 | | | | | | | | | | | | | | | | | |
1063 o--|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|--o
1064
1065 ^ ^ ^ ^
1066 Initial | Bttrfly | Rd/Wrt | Bttrfly | Rd/Wrt
1067 Buffer | | Register | | Register
1068 |____________|____________|____________|
1069 |
1070 |
1071 Interconnect
1072 Paths
1073
1074 The use of "in-place" computation permits one to use only one set of
1075 registers realized by an array of complex number structures. To describe
1076 the coefficients for each butterfly I am using a two dimensional array
1077 (stage, butterfly) of complex numbers. The predetermined stage connections
1078 will be described in a two dimensional array of indicies. These indicies
1079 will be used to determine the order of reading at each stage of the
1080 computation.
1081*/
1082
1083
1084/*****************************************************************************/
1085/* INCLUDE FILES */
1086/*****************************************************************************/
1087
1088#include <stdio.h>
1089#include <math.h>
1090#include <stdlib.h>
1091
1092 /* the following is needed only to declare pd_fft() as exportable in MSW */
1093#include "m_pd.h"
1094
1095/* some basic definitions */
1096#ifndef BOOL
1097#define BOOL int
1098#define TRUE 1
1099#define FALSE 0
1100#endif
1101
1102#define SAMPLE float /* data type used in calculation */
1103
1104#define SHORT_SIZE sizeof(short)
1105#define INT_SIZE sizeof(int)
1106#define FLOAT_SIZE sizeof(float)
1107#define SAMPLE_SIZE sizeof(SAMPLE)
1108#define PNTR_SIZE sizeof(char *)
1109
1110#define PI 3.1415927
1111#define TWO_PI 6.2831854
1112
1113/* type definitions for I/O buffers */
1114#define REAL 0 /* real only */
1115#define IMAG 2 /* imaginary only */
1116#define RECT 8 /* real and imaginary */
1117#define MAG 16 /* magnitude only */
1118#define PHASE 32 /* phase only */
1119#define POLAR 64 /* magnitude and phase*/
1120
1121/* scale definitions for I/O buffers */
1122#define LINEAR 0
1123#define DB 1 /* 20log10 */
1124
1125/* transform direction definition */
1126#define FORWARD 1 /* Forward FFT */
1127#define INVERSE 2 /* Inverse FFT */
1128
1129/* window type definitions */
1130#define HANNING 1
1131#define RECTANGULAR 0
1132
1133
1134
1135/* network structure definition */
1136
1137typedef struct Tfft_net {
1138 int n;
1139 int stages;
1140 int bps;
1141 int direction;
1142 int window_type;
1143 int *load_index;
1144 SAMPLE *window, *inv_window;
1145 SAMPLE *regr;
1146 SAMPLE *regi;
1147 SAMPLE **indexpr;
1148 SAMPLE **indexpi;
1149 SAMPLE **indexqr;
1150 SAMPLE **indexqi;
1151 SAMPLE *coeffr, *inv_coeffr;
1152 SAMPLE *coeffi, *inv_coeffi;
1153 struct Tfft_net *next;
1154} FFT_NET;
1155
1156
1157void cfft(int trnsfrm_dir, int npnt, int window,
1158 float *source_buf, int source_form, int source_scale,
1159 float *result_buf, int result_form, int result_scale, int debug);
1160
1161
1162/*****************************************************************************/
1163/* GLOBAL DECLARATIONS */
1164/*****************************************************************************/
1165
1166static FFT_NET *firstnet;
1167
1168/* prototypes */
1169
1170void net_alloc(FFT_NET *fft_net);
1171void net_dealloc(FFT_NET *fft_net);
1172int power_of_two(int n);
1173void create_hanning(SAMPLE *window, int n, SAMPLE scale);
1174void create_rectangular(SAMPLE *window, int n, SAMPLE scale);
1175void short_to_float(short *short_buf, float *float_buf, int n);
1176void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
1177 int buf_scale, int trnsfrm_dir);
1178void compute_fft(FFT_NET *fft_net);
1179void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
1180 int buf_scale, int debug);
1181void build_fft_network(FFT_NET *fft_net, int n, int window_type);
1182
1183/*****************************************************************************/
1184/* GENERALIZED FAST FOURIER TRANSFORM MODULE */
1185/*****************************************************************************/
1186
1187void cfft(int trnsfrm_dir, int npnt, int window,
1188 float *source_buf, int source_form, int source_scale,
1189 float *result_buf, int result_form, int result_scale, int debug)
1190
1191/* modifies: result_buf
1192 effects: Computes npnt FFT specified by form, scale, and dir parameters.
1193 Source samples (single precision float) are taken from soure_buf and
1194 the transfrmd representation is stored in result_buf (single precision
1195 float). The parameters are defined as follows:
1196
1197 trnsfrm_dir = FORWARD | INVERSE
1198 npnt = 2^k for some any positive integer k
1199 window = HANNING | RECTANGULAR
1200 (RECT = real and imag parts, POLAR = magnitude and phase)
1201 source_form = REAL | IMAG | RECT | POLAR
1202 result_form = REAL | IMAG | RECT | MAG | PHASE | POLAR
1203 xxxxxx_scale= LINEAR | DB ( 20log10 |mag| )
1204
1205 The input/output buffers are stored in a form appropriate to the type.
1206 For example: REAL => {real, real, real ...},
1207 MAG => {mag, mag, mag, ... },
1208 RECT => {real, imag, real, imag, ... },
1209 POLAR => {mag, phase, mag, phase, ... }.
1210
1211 To look at the magnitude (in db) of a 1024 point FFT of a real time
1212 signal we have:
1213
1214 fft(FORWARD, 1024, RECTANGULAR, input, REAL, LINEAR, output, MAG, DB)
1215
1216 All possible input and output combinations are possible given the
1217 choice of type and scale parameters.
1218*/
1219
1220{
1221 FFT_NET *thisnet = (FFT_NET *)0;
1222 FFT_NET *lastnet = (FFT_NET *)0;
1223
1224 /* A linked list of fft networks of different sizes is maintained to
1225 avoid building with every call. The network is built on the first
1226 call but reused for subsequent calls requesting the same size
1227 transformation.
1228 */
1229
1230 thisnet=firstnet;
1231 while (thisnet) {
1232 if (!(thisnet->n == npnt) || !(thisnet->window_type == window)) {
1233 /* current net doesn't match size or window type */
1234 lastnet=thisnet;
1235 thisnet=thisnet->next;
1236 continue; /* keep looking */
1237 }
1238
1239 else { /* network matches desired size */
1240 load_registers(thisnet, source_buf, source_form, source_scale,
1241 trnsfrm_dir);
1242 compute_fft(thisnet); /* do transformation */
1243 store_registers(thisnet, result_buf, result_form, result_scale,debug);
1244 return;
1245 }
1246 }
1247
1248 /* none of existing networks match required size*/
1249
1250 if (lastnet) { /* add new network to end of list */
1251 thisnet = (FFT_NET *)malloc(sizeof(FFT_NET)); /* allocate */
1252 thisnet->next = 0;
1253 lastnet->next = thisnet; /* add to end of list */
1254 }
1255 else { /* first network to be created */
1256 thisnet=firstnet=(FFT_NET *)malloc(sizeof(FFT_NET)); /* alloc. */
1257 thisnet->next = 0;
1258 }
1259
1260 /* build new network and compute transformation */
1261 build_fft_network(thisnet, npnt, window);
1262 load_registers(thisnet, source_buf, source_form, source_scale,
1263 trnsfrm_dir);
1264 compute_fft(thisnet);
1265 store_registers(thisnet, result_buf, result_form, result_scale,debug);
1266 return;
1267}
1268
1269void fft_clear(void)
1270
1271/* effects: Deallocates all preserved FFT networks. Should be used when
1272 finished with all computations.
1273*/
1274
1275{
1276 FFT_NET *thisnet, *nextnet;
1277
1278 if (firstnet) {
1279 thisnet=firstnet;
1280 do {
1281 nextnet = thisnet->next;
1282 net_dealloc(thisnet);
1283 free((char *)thisnet);
1284 } while (thisnet = nextnet);
1285 }
1286}
1287
1288
1289/*****************************************************************************/
1290/* NETWORK CONSTRUCTION */
1291/*****************************************************************************/
1292
1293void build_fft_network(FFT_NET *fft_net, int n, int window_type)
1294
1295
1296/* modifies:fft_net
1297 effects: Constructs the fft network as described in fft.h. Butterfly
1298 coefficients, read/write indicies, bit reversed load indicies,
1299 and array allocations are computed.
1300*/
1301
1302{
1303 int cntr, i, j, s;
1304 int stages, bps;
1305 int **p, **q, *pp, *qp;
1306 SAMPLE two_pi_div_n = TWO_PI / n;
1307
1308
1309 /* network definition */
1310 fft_net->n = n;
1311 fft_net->bps = bps = n/2;
1312 for (i = 0, j = n; j > 1; j >>= 1, i++);
1313 fft_net->stages = stages = i;
1314 fft_net->direction = FORWARD;
1315 fft_net->window_type = window_type;
1316 fft_net->next = (FFT_NET *)0;
1317
1318 /* allocate registers, index, coefficient arrays */
1319 net_alloc(fft_net);
1320
1321
1322 /* create appropriate windows */
1323 if (window_type==HANNING) {
1324 create_hanning(fft_net->window, n, 1.);
1325 create_hanning(fft_net->inv_window, n, 1./n);
1326 }
1327 else {
1328 create_rectangular(fft_net->window, n, 1.);
1329 create_rectangular(fft_net->inv_window, n, 1./n);
1330 }
1331
1332
1333 /* calculate butterfly coefficients */ {
1334
1335 int num_diff_coeffs, power_inc, power;
1336 SAMPLE *coeffpr = fft_net->coeffr;
1337 SAMPLE *coeffpi = fft_net->coeffi;
1338 SAMPLE *inv_coeffpr = fft_net->inv_coeffr;
1339 SAMPLE *inv_coeffpi = fft_net->inv_coeffi;
1340
1341 /* stage one coeffs are 1 + 0j */
1342 for (i = 0; i < bps; i++) {
1343 *coeffpr = *inv_coeffpr = 1.;
1344 *coeffpi = *inv_coeffpi = 0.;
1345 coeffpr++; inv_coeffpr++;
1346 coeffpi++; inv_coeffpi++;
1347 }
1348
1349 /* stage 2 to last stage coeffs need calculation */
1350 /* (1<<r <=> 2^r */
1351 for (s = 2; s <= stages; s++) {
1352
1353 num_diff_coeffs = n / (1 << (stages - s + 1));
1354 power_inc = 1 << (stages -s);
1355 cntr = 0;
1356
1357 for (i = bps/num_diff_coeffs; i > 0; i--) {
1358
1359 power = 0;
1360
1361 for (j = num_diff_coeffs; j > 0; j--) {
1362 *coeffpr = cos(two_pi_div_n*power);
1363 *inv_coeffpr = cos(two_pi_div_n*power);
1364/* AAA change these signs */ *coeffpi = -sin(two_pi_div_n*power);
1365/* change back */ *inv_coeffpi = sin(two_pi_div_n*power);
1366 power += power_inc;
1367 coeffpr++; inv_coeffpr++;
1368 coeffpi++; inv_coeffpi++;
1369 }
1370 }
1371 }
1372 }
1373
1374 /* calculate network indicies: stage exchange indicies are
1375 calculated and then used as offset values from the base
1376 register locations. The final addresses are then stored in
1377 fft_net.
1378 */ {
1379
1380 int index, inc;
1381 SAMPLE **indexpr = fft_net->indexpr;
1382 SAMPLE **indexpi = fft_net->indexpi;
1383 SAMPLE **indexqr = fft_net->indexqr;
1384 SAMPLE **indexqi = fft_net->indexqi;
1385 SAMPLE *regr = fft_net->regr;
1386 SAMPLE *regi = fft_net->regi;
1387
1388
1389 /* allocate temporary 2d stage exchange index, 1d temp
1390 load index */
1391 p = (int **)malloc(stages * PNTR_SIZE);
1392 q = (int **)malloc(stages * PNTR_SIZE);
1393
1394 for (s = 0; s < stages; s++) {
1395 p[s] = (int *)malloc(bps * INT_SIZE);
1396 q[s] = (int *)malloc(bps * INT_SIZE);
1397 }
1398
1399 /* calculate stage exchange indicies: */
1400 for (s = 0; s < stages; s++) {
1401 pp = p[s];
1402 qp = q[s];
1403 inc = 1 << s;
1404 cntr = 1 << (stages-s-1);
1405 i = j = index = 0;
1406
1407 do {
1408 do {
1409 qp[i] = index + inc;
1410 pp[i++] = index++;
1411 } while (++j < inc);
1412 index = qp[i-1] + 1;
1413 j = 0;
1414 } while (--cntr);
1415 }
1416
1417 /* compute actual address values using indicies as offsets */
1418 for (s = 0; s < stages; s++) {
1419 for (i = 0; i < bps; i++) {
1420 *indexpr++ = regr + p[s][i];
1421 *indexpi++ = regi + p[s][i];
1422 *indexqr++ = regr + q[s][i];
1423 *indexqi++ = regi + q[s][i];
1424 }
1425 }
1426 }
1427
1428
1429 /* calculate load indicies (bit reverse ordering) */
1430 /* bit reverse ordering achieved by passing normal
1431 order indicies backwards through the network */
1432
1433 /* init to normal order indicies */ {
1434 int *load_index,*load_indexp;
1435 int *temp_indexp, *temp_index;
1436 temp_index=temp_indexp=(int *)malloc(n * INT_SIZE);
1437
1438 i = 0; j = n;
1439 load_index = load_indexp = fft_net->load_index;
1440
1441 while (j--)
1442 *load_indexp++ = i++;
1443
1444 /* pass indicies backwards through net */
1445 for (s = stages - 1; s > 0; s--) {
1446 pp = p[s];
1447 qp = q[s];
1448
1449 for (i = 0; i < bps; i++) {
1450 temp_index[pp[i]]=load_index[2*i];
1451 temp_index[qp[i]]=load_index[2*i+1];
1452 }
1453 j = n;
1454 load_indexp = load_index;
1455 temp_indexp = temp_index;
1456 while (j--)
1457 *load_indexp++ = *temp_indexp++;
1458 }
1459
1460 /* free all temporary arrays */
1461 free((char *)temp_index);
1462 for (s = 0; s < stages; s++) {
1463 free((char *)p[s]);free((char *)q[s]);
1464 }
1465 free((char *)p);free((char *)q);
1466 }
1467}
1468
1469
1470
1471/*****************************************************************************/
1472/* REGISTER LOAD AND STORE */
1473/*****************************************************************************/
1474
1475void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
1476 int buf_scale, int trnsfrm_dir)
1477
1478/* effects: Multiplies the input buffer with the appropriate window and
1479 stores the resulting values in the initial registers of the
1480 network. Input buffer must contain values appropriate to form.
1481 For RECT, the buffer contains real num. followed by imag num,
1482 and for POLAR, it contains magnitude followed by phase. Pure
1483 inputs are listed normally. Both LINEAR and DB scales are
1484 interpreted.
1485*/
1486
1487{
1488 int *load_index = fft_net->load_index;
1489 SAMPLE *window;
1490 int index, i = 0, n = fft_net->n;
1491
1492 if (trnsfrm_dir==FORWARD) window = fft_net->window;
1493 else if (trnsfrm_dir==INVERSE) window = fft_net->inv_window;
1494 else {
1495 fprintf(stderr, "load_registers:illegal transform direction\n");
1496 exit(0);
1497 }
1498 fft_net->direction = trnsfrm_dir;
1499
1500 switch(buf_scale) {
1501 case LINEAR: {
1502
1503 switch (buf_form) {
1504 case REAL: { /* pure REAL */
1505 while (i < fft_net->n) {
1506 index = load_index[i];
1507 fft_net->regr[i]=(SAMPLE)buf[index] * window[index];
1508 fft_net->regi[i]=0.;
1509 i++;
1510 }
1511 } break;
1512
1513 case IMAG: { /* pure IMAGinary */
1514 while (i < fft_net->n) {
1515 index = load_index[i];
1516 fft_net->regr[i]=0;
1517 fft_net->regi[i]=(SAMPLE)buf[index] * window[index];
1518 i++;
1519 }
1520 } break;
1521
1522 case RECT: { /* both REAL and IMAGinary */
1523 while (i < fft_net->n) {
1524 index = load_index[i];
1525 fft_net->regr[i]=(SAMPLE)buf[index*2] * window[index];
1526 fft_net->regi[i]=(SAMPLE)buf[index*2+1] * window[index];
1527 i++;
1528 }
1529 } break;
1530
1531 case POLAR: { /* magnitude followed by phase */
1532 while (i < fft_net->n) {
1533 index = load_index[i];
1534 fft_net->regr[i]=(SAMPLE)(buf[index*2] * cos(buf[index*2+1]))
1535 * window[index];
1536 fft_net->regi[i]=(SAMPLE)(buf[index*2] * sin(buf[index*2+1]))
1537 * window[index];
1538 i++;
1539 }
1540 } break;
1541
1542 default: {
1543 fprintf(stderr, "load_registers:illegal input form\n");
1544 exit(0);
1545 } break;
1546 }
1547 } break;
1548
1549 case DB: {
1550
1551 switch (buf_form) {
1552 case REAL: { /* log pure REAL */
1553 while (i < fft_net->n) {
1554 index = load_index[i];
1555 fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
1556 * window[index]; /* window scaling after linearization */
1557 fft_net->regi[i]=0.;
1558 i++;
1559 }
1560 } break;
1561
1562 case IMAG: { /* log pure IMAGinary */
1563 while (i < fft_net->n) {
1564 index = load_index[i];
1565 fft_net->regr[i]=0.;
1566 fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
1567 * window[index];
1568 i++;
1569 }
1570 } break;
1571
1572 case RECT: { /* log REAL and log IMAGinary */
1573 while (i < fft_net->n) {
1574 index = load_index[i];
1575 fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2])
1576 * window[index];
1577 fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2+1])
1578 * window[index];
1579 i++;
1580 }
1581 } break;
1582
1583 case POLAR: { /* log mag followed by phase */
1584 while (i < fft_net->n) {
1585 index = load_index[i];
1586 fft_net->regr[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
1587 * cos(buf[index*2+1])) * window[index];
1588 fft_net->regi[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
1589 * sin(buf[index*2+1])) * window[index];
1590 i++;
1591 }
1592 } break;
1593
1594 default: {
1595 fprintf(stderr, "load_registers:illegal input form\n");
1596 exit(0);
1597 } break;
1598 }
1599 } break;
1600
1601 default: {
1602 fprintf(stderr, "load_registers:illegal input scale\n");
1603 exit(0);
1604 } break;
1605 }
1606}
1607
1608
1609void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
1610 int buf_scale, int debug)
1611
1612/* modifies: buf
1613 effects: Writes the final contents of the network registers into buf in
1614 either linear or db scale, polar or rectangular form. If any of
1615 the pure forms(REAL, IMAG, MAG, or PHASE) are used then only the
1616 corresponding part of the registers is stored in buf.
1617*/
1618
1619{
1620 int i;
1621 SAMPLE real, imag, mag, phase;
1622 int n;
1623
1624 i = 0;
1625 n = fft_net->n;
1626
1627 switch (buf_scale) {
1628 case LINEAR: {
1629
1630 switch (buf_form) {
1631 case REAL: { /* pure REAL */
1632 do {
1633 *buf++ = (float)fft_net->regr[i];
1634 } while (++i < n);
1635 } break;
1636
1637 case IMAG: { /* pure IMAGinary */
1638 do {
1639 *buf++ = (float)fft_net->regi[i];
1640 } while (++i < n);
1641 } break;
1642
1643 case RECT: { /* both REAL and IMAGinary */
1644 do {
1645 *buf++ = (float)fft_net->regr[i];
1646 *buf++ = (float)fft_net->regi[i];
1647 } while (++i < n);
1648 } break;
1649
1650 case MAG: { /* magnitude only */
1651 do {
1652 real = fft_net->regr[i];
1653 imag = fft_net->regi[i];
1654 *buf++ = (float)sqrt(real*real+imag*imag);
1655 } while (++i < n);
1656 } break;
1657
1658 case PHASE: { /* phase only */
1659 do {
1660 real = fft_net->regr[i];
1661 imag = fft_net->regi[i];
1662 if (real > .00001)
1663 *buf++ = (float)atan2(imag, real);
1664 else { /* deal with bad case */
1665 if (imag > 0){ *buf++ = PI / 2.;
1666 if(debug) fprintf(stderr,"real=0 and imag > 0\n");}
1667 else if (imag < 0){ *buf++ = -PI / 2.;
1668 if(debug) fprintf(stderr,"real=0 and imag < 0\n");}
1669 else { *buf++ = 0;
1670 if(debug) fprintf(stderr,"real=0 and imag=0\n");}
1671 }
1672 } while (++i < n);
1673 } break;
1674
1675 case POLAR: { /* magnitude and phase */
1676 do {
1677 real = fft_net->regr[i];
1678 imag = fft_net->regi[i];
1679 *buf++ = (float)sqrt(real*real+imag*imag);
1680 if (real) /* a hack to avoid div by zero */
1681 *buf++ = (float)atan2(imag, real);
1682 else { /* deal with bad case */
1683 if (imag > 0) *buf++ = PI / 2.;
1684 else if (imag < 0) *buf++ = -PI / 2.;
1685 else *buf++ = 0;
1686 }
1687 } while (++i < n);
1688 } break;
1689
1690 default: {
1691 fprintf(stderr, "store_registers:illegal output form\n");
1692 exit(0);
1693 } break;
1694 }
1695 } break;
1696
1697 case DB: {
1698
1699 switch (buf_form) {
1700 case REAL: { /* real only */
1701 do {
1702 *buf++ = (float)20.*log10(fft_net->regr[i]);
1703 } while (++i < n);
1704 } break;
1705
1706 case IMAG: { /* imag only */
1707 do {
1708 *buf++ = (float)20.*log10(fft_net->regi[i]);
1709 } while (++i < n);
1710 } break;
1711
1712 case RECT: { /* real and imag */
1713 do {
1714 *buf++ = (float)20.*log10(fft_net->regr[i]);
1715 *buf++ = (float)20.*log10(fft_net->regi[i]);
1716 } while (++i < n);
1717 } break;
1718
1719 case MAG: { /* magnitude only */
1720 do {
1721 real = fft_net->regr[i];
1722 imag = fft_net->regi[i];
1723 *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
1724 } while (++i < n);
1725 } break;
1726
1727 case PHASE: { /* phase only */
1728 do {
1729 real = fft_net->regr[i];
1730 imag = fft_net->regi[i];
1731 if (real)
1732 *buf++ = (float)atan2(imag, real);
1733 else { /* deal with bad case */
1734 if (imag > 0) *buf++ = PI / 2.;
1735 else if (imag < 0) *buf++ = -PI / 2.;
1736 else *buf++ = 0;
1737 }
1738 } while (++i < n);
1739 } break;
1740
1741 case POLAR: { /* magnitude and phase */
1742 do {
1743 real = fft_net->regr[i];
1744 imag = fft_net->regi[i];
1745 *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
1746 if (real)
1747 *buf++ = (float)atan2(imag, real);
1748 else { /* deal with bad case */
1749 if (imag > 0) *buf++ = PI / 2.;
1750 else if (imag < 0) *buf++ = -PI / 2.;
1751 else *buf++ = 0;
1752 }
1753 } while (++i < n);
1754 } break;
1755
1756 default: {
1757 fprintf(stderr, "store_registers:illegal output form\n");
1758 exit(0);
1759 } break;
1760 }
1761 } break;
1762
1763 default: {
1764 fprintf(stderr, "store_registers:illegal output scale\n");
1765 exit(0);
1766 } break;
1767 }
1768}
1769
1770
1771
1772/*****************************************************************************/
1773/* COMPUTE TRANSFORMATION */
1774/*****************************************************************************/
1775
1776void compute_fft(FFT_NET *fft_net)
1777
1778
1779/* modifies: fft_net
1780 effects: Passes the values (already loaded) in the registers through
1781 the network, multiplying with appropriate coefficients at each
1782 stage. The fft result will be in the registers at the end of
1783 the computation. The direction of the transformation is indicated
1784 by the network flag 'direction'. The form of the computation is:
1785
1786 X(pn) = X(p) + C*X(q)
1787 X(qn) = X(p) - C*X(q)
1788
1789 where X(pn,qn) represents the output of the registers at each stage.
1790 The calculations are actually done in place. Register pointers are
1791 used to speed up the calculations.
1792
1793 Register and coefficient addresses involved in the calculations
1794 are stored sequentially and are accessed as such. fft_net->indexp,
1795 indexq contain pointers to the relevant addresses, and fft_net->coeffs,
1796 inv_coeffs points to the appropriate coefficients at each stage of the
1797 computation.
1798*/
1799
1800{
1801 SAMPLE **xpr, **xpi, **xqr, **xqi, *cr, *ci;
1802 int i;
1803 SAMPLE tpr, tpi, tqr, tqi;
1804 int bps = fft_net->bps;
1805 int cnt = bps * (fft_net->stages - 1);
1806
1807 /* predetermined register addresses and coefficients */
1808 xpr = fft_net->indexpr;
1809 xpi = fft_net->indexpi;
1810 xqr = fft_net->indexqr;
1811 xqi = fft_net->indexqi;
1812
1813 if (fft_net->direction==FORWARD) { /* FORWARD FFT coefficients */
1814 cr = fft_net->coeffr;
1815 ci = fft_net->coeffi;
1816 }
1817 else { /* INVERSE FFT coefficients */
1818 cr = fft_net->inv_coeffr;
1819 ci = fft_net->inv_coeffi;
1820 }
1821
1822 /* stage one coefficients are 1 + 0j so C*X(q)=X(q) */
1823 /* bps mults can be avoided */
1824
1825 for (i = 0; i < bps; i++) {
1826
1827 /* add X(p) and X(q) */
1828 tpr = **xpr + **xqr;
1829 tpi = **xpi + **xqi;
1830 tqr = **xpr - **xqr;
1831 tqi = **xpi - **xqi;
1832
1833 /* exchange register with temp */
1834 **xpr = tpr;
1835 **xpi = tpi;
1836 **xqr = tqr;
1837 **xqi = tqi;
1838
1839 /* next set of register for calculations: */
1840 xpr++; xpi++; xqr++; xqi++; cr++; ci++;
1841
1842 }
1843
1844 for (i = 0; i < cnt; i++) {
1845
1846 /* mult X(q) by coeff C */
1847 tqr = **xqr * *cr - **xqi * *ci;
1848 tqi = **xqr * *ci + **xqi * *cr;
1849
1850 /* exchange register with temp */
1851 **xqr = tqr;
1852 **xqi = tqi;
1853
1854 /* add X(p) and X(q) */
1855 tpr = **xpr + **xqr;
1856 tpi = **xpi + **xqi;
1857 tqr = **xpr - **xqr;
1858 tqi = **xpi - **xqi;
1859
1860 /* exchange register with temp */
1861 **xpr = tpr;
1862 **xpi = tpi;
1863 **xqr = tqr;
1864 **xqi = tqi;
1865 /* next set of register for calculations: */
1866 xpr++; xpi++; xqr++; xqi++; cr++; ci++;
1867 }
1868}
1869
1870
1871/****************************************************************************/
1872/* SUPPORT MODULES */
1873/****************************************************************************/
1874
1875void net_alloc(FFT_NET *fft_net)
1876
1877
1878/* effects: Allocates appropriate two dimensional arrays and assigns
1879 correct internal pointers.
1880*/
1881
1882{
1883
1884 int stages, bps, n;
1885
1886 n = fft_net->n;
1887 stages = fft_net->stages;
1888 bps = fft_net->bps;
1889
1890
1891 /* two dimensional arrays with elements stored sequentially */
1892
1893 fft_net->load_index = (int *)malloc(n * INT_SIZE);
1894 fft_net->regr = (SAMPLE *)malloc(n * SAMPLE_SIZE);
1895 fft_net->regi = (SAMPLE *)malloc(n * SAMPLE_SIZE);
1896 fft_net->coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
1897 fft_net->coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
1898 fft_net->inv_coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
1899 fft_net->inv_coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
1900 fft_net->indexpr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
1901 fft_net->indexpi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
1902 fft_net->indexqr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
1903 fft_net->indexqi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
1904
1905 /* one dimensional load window */
1906 fft_net->window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
1907 fft_net->inv_window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
1908}
1909
1910void net_dealloc(FFT_NET *fft_net)
1911
1912
1913/* effects: Deallocates given FFT network.
1914*/
1915
1916{
1917
1918 free((char *)fft_net->load_index);
1919 free((char *)fft_net->regr);
1920 free((char *)fft_net->regi);
1921 free((char *)fft_net->coeffr);
1922 free((char *)fft_net->coeffi);
1923 free((char *)fft_net->inv_coeffr);
1924 free((char *)fft_net->inv_coeffi);
1925 free((char *)fft_net->indexpr);
1926 free((char *)fft_net->indexpi);
1927 free((char *)fft_net->indexqr);
1928 free((char *)fft_net->indexqi);
1929 free((char *)fft_net->window);
1930 free((char *)fft_net->inv_window);
1931}
1932
1933
1934BOOL power_of_two(n)
1935
1936int n;
1937
1938/* effects: Returns TRUE if n is a power of two, otherwise FALSE.
1939*/
1940
1941{
1942 int i;
1943
1944 for (i = n; i > 1; i >>= 1)
1945 if (i & 1) return FALSE; /* more than one bit high */
1946 return TRUE;
1947}
1948
1949
1950void create_hanning(SAMPLE *window, int n, SAMPLE scale)
1951
1952/* effects: Fills the buffer window with a hanning window of the appropriate
1953 size scaled by scale.
1954*/
1955
1956{
1957 SAMPLE a, pi_div_n = PI/n;
1958 int k;
1959
1960 for (k=1; k <= n; k++) {
1961 a = sin(k * pi_div_n);
1962 *window++ = scale * a * a;
1963 }
1964}
1965
1966
1967void create_rectangular(SAMPLE *window, int n, SAMPLE scale)
1968
1969/* effects: Fills the buffer window with a rectangular window of the
1970 appropriate size of height scale.
1971*/
1972
1973{
1974 while (n--)
1975 *window++ = scale;
1976}
1977
1978
1979void short_to_float(short *short_buf, float *float_buf, int n)
1980
1981/* effects; Converts short_buf to floats and stores them in float_buf.
1982*/
1983
1984{
1985 while (n--) {
1986 *float_buf++ = (float)*short_buf++;
1987 }
1988}
1989
1990
1991/* here's the meat: */
1992
1993void pd_fft(float *buf, int npoints, int inverse)
1994{
1995 double renorm;
1996 float *fp, *fp2;
1997 int i;
1998 renorm = (inverse ? npoints : 1.);
1999 cfft((inverse ? INVERSE : FORWARD), npoints, RECTANGULAR,
2000 buf, RECT, LINEAR, buf, RECT, LINEAR, 0);
2001 for (i = npoints << 1, fp = buf; i--; fp++) *fp *= renorm;
2002}
diff --git a/apps/plugins/pdbox/PDa/src/d_filter.c b/apps/plugins/pdbox/PDa/src/d_filter.c
new file mode 100644
index 0000000000..05bb7cd58e
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_filter.c
@@ -0,0 +1,1094 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* "filters", both linear and nonlinear.
6*/
7#include "m_pd.h"
8#include <math.h>
9
10/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */
11
12typedef struct hipctl
13{
14 float c_x;
15 float c_coef;
16} t_hipctl;
17
18typedef struct sighip
19{
20 t_object x_obj;
21 float x_sr;
22 float x_hz;
23 t_hipctl x_cspace;
24 t_hipctl *x_ctl;
25 float x_f;
26} t_sighip;
27
28t_class *sighip_class;
29static void sighip_ft1(t_sighip *x, t_floatarg f);
30
31static void *sighip_new(t_floatarg f)
32{
33 t_sighip *x = (t_sighip *)pd_new(sighip_class);
34 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
35 outlet_new(&x->x_obj, gensym("signal"));
36 x->x_sr = 44100;
37 x->x_ctl = &x->x_cspace;
38 x->x_cspace.c_x = 0;
39 sighip_ft1(x, f);
40 x->x_f = 0;
41 return (x);
42}
43
44static void sighip_ft1(t_sighip *x, t_floatarg f)
45{
46 if (f < 0) f = 0;
47 x->x_hz = f;
48 x->x_ctl->c_coef = 1 - f * (2 * 3.14159) / x->x_sr;
49 if (x->x_ctl->c_coef < 0)
50 x->x_ctl->c_coef = 0;
51 else if (x->x_ctl->c_coef > 1)
52 x->x_ctl->c_coef = 1;
53}
54
55static t_int *sighip_perform(t_int *w)
56{
57 float *in = (float *)(w[1]);
58 float *out = (float *)(w[2]);
59 t_hipctl *c = (t_hipctl *)(w[3]);
60 int n = (t_int)(w[4]);
61 int i;
62 float last = c->c_x;
63 float coef = c->c_coef;
64 if (coef < 1)
65 {
66 for (i = 0; i < n; i++)
67 {
68 float new = *in++ + coef * last;
69 *out++ = new - last;
70 last = new;
71 }
72 if (PD_BIGORSMALL(last))
73 last = 0;
74 c->c_x = last;
75 }
76 else
77 {
78 for (i = 0; i < n; i++)
79 *out++ = *in++;
80 c->c_x = 0;
81 }
82 return (w+5);
83}
84
85static void sighip_dsp(t_sighip *x, t_signal **sp)
86{
87 x->x_sr = sp[0]->s_sr;
88 sighip_ft1(x, x->x_hz);
89 dsp_add(sighip_perform, 4,
90 sp[0]->s_vec, sp[1]->s_vec,
91 x->x_ctl, sp[0]->s_n);
92
93}
94
95static void sighip_clear(t_sighip *x, t_floatarg q)
96{
97 x->x_cspace.c_x = 0;
98}
99
100void sighip_setup(void)
101{
102 sighip_class = class_new(gensym("hip~"), (t_newmethod)sighip_new, 0,
103 sizeof(t_sighip), 0, A_DEFFLOAT, 0);
104 CLASS_MAINSIGNALIN(sighip_class, t_sighip, x_f);
105 class_addmethod(sighip_class, (t_method)sighip_dsp, gensym("dsp"), 0);
106 class_addmethod(sighip_class, (t_method)sighip_ft1,
107 gensym("ft1"), A_FLOAT, 0);
108 class_addmethod(sighip_class, (t_method)sighip_clear, gensym("clear"), 0);
109}
110
111/* ---------------- lop~ - 1-pole lopass filter. ----------------- */
112
113typedef struct lopctl
114{
115 float c_x;
116 float c_coef;
117} t_lopctl;
118
119typedef struct siglop
120{
121 t_object x_obj;
122 float x_sr;
123 float x_hz;
124 t_lopctl x_cspace;
125 t_lopctl *x_ctl;
126 float x_f;
127} t_siglop;
128
129t_class *siglop_class;
130
131static void siglop_ft1(t_siglop *x, t_floatarg f);
132
133static void *siglop_new(t_floatarg f)
134{
135 t_siglop *x = (t_siglop *)pd_new(siglop_class);
136 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
137 outlet_new(&x->x_obj, gensym("signal"));
138 x->x_sr = 44100;
139 x->x_ctl = &x->x_cspace;
140 x->x_cspace.c_x = 0;
141 siglop_ft1(x, f);
142 x->x_f = 0;
143 return (x);
144}
145
146static void siglop_ft1(t_siglop *x, t_floatarg f)
147{
148 if (f < 0) f = 0;
149 x->x_hz = f;
150 x->x_ctl->c_coef = f * (2 * 3.14159) / x->x_sr;
151 if (x->x_ctl->c_coef > 1)
152 x->x_ctl->c_coef = 1;
153 else if (x->x_ctl->c_coef < 0)
154 x->x_ctl->c_coef = 0;
155}
156
157static void siglop_clear(t_siglop *x, t_floatarg q)
158{
159 x->x_cspace.c_x = 0;
160}
161
162static t_int *siglop_perform(t_int *w)
163{
164 float *in = (float *)(w[1]);
165 float *out = (float *)(w[2]);
166 t_lopctl *c = (t_lopctl *)(w[3]);
167 int n = (t_int)(w[4]);
168 int i;
169 float last = c->c_x;
170 float coef = c->c_coef;
171 float feedback = 1 - coef;
172 for (i = 0; i < n; i++)
173 last = *out++ = coef * *in++ + feedback * last;
174 if (PD_BIGORSMALL(last))
175 last = 0;
176 c->c_x = last;
177 return (w+5);
178}
179
180static void siglop_dsp(t_siglop *x, t_signal **sp)
181{
182 x->x_sr = sp[0]->s_sr;
183 siglop_ft1(x, x->x_hz);
184 dsp_add(siglop_perform, 4,
185 sp[0]->s_vec, sp[1]->s_vec,
186 x->x_ctl, sp[0]->s_n);
187
188}
189
190void siglop_setup(void)
191{
192 siglop_class = class_new(gensym("lop~"), (t_newmethod)siglop_new, 0,
193 sizeof(t_siglop), 0, A_DEFFLOAT, 0);
194 CLASS_MAINSIGNALIN(siglop_class, t_siglop, x_f);
195 class_addmethod(siglop_class, (t_method)siglop_dsp, gensym("dsp"), 0);
196 class_addmethod(siglop_class, (t_method)siglop_ft1,
197 gensym("ft1"), A_FLOAT, 0);
198 class_addmethod(siglop_class, (t_method)siglop_clear, gensym("clear"), 0);
199}
200
201/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */
202
203typedef struct bpctl
204{
205 float c_x1;
206 float c_x2;
207 float c_coef1;
208 float c_coef2;
209 float c_gain;
210} t_bpctl;
211
212typedef struct sigbp
213{
214 t_object x_obj;
215 float x_sr;
216 float x_freq;
217 float x_q;
218 t_bpctl x_cspace;
219 t_bpctl *x_ctl;
220 float x_f;
221} t_sigbp;
222
223t_class *sigbp_class;
224
225static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
226
227static void *sigbp_new(t_floatarg f, t_floatarg q)
228{
229 t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
230 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
231 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2"));
232 outlet_new(&x->x_obj, gensym("signal"));
233 x->x_sr = 44100;
234 x->x_ctl = &x->x_cspace;
235 x->x_cspace.c_x1 = 0;
236 x->x_cspace.c_x2 = 0;
237 sigbp_docoef(x, f, q);
238 x->x_f = 0;
239 return (x);
240}
241
242static float sigbp_qcos(float f)
243{
244 if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f)
245 {
246 float g = f*f;
247 return (((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1);
248 }
249 else return (0);
250}
251
252static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q)
253{
254 float r, oneminusr, omega;
255 if (f < 0.001) f = 10;
256 if (q < 0) q = 0;
257 x->x_freq = f;
258 x->x_q = q;
259 omega = f * (2.0f * 3.14159f) / x->x_sr;
260 if (q < 0.001) oneminusr = 1.0f;
261 else oneminusr = omega/q;
262 if (oneminusr > 1.0f) oneminusr = 1.0f;
263 r = 1.0f - oneminusr;
264 x->x_ctl->c_coef1 = 2.0f * sigbp_qcos(omega) * r;
265 x->x_ctl->c_coef2 = - r * r;
266 x->x_ctl->c_gain = 2 * oneminusr * (oneminusr + r * omega);
267 /* post("r %f, omega %f, coef1 %f, coef2 %f",
268 r, omega, x->x_ctl->c_coef1, x->x_ctl->c_coef2); */
269}
270
271static void sigbp_ft1(t_sigbp *x, t_floatarg f)
272{
273 sigbp_docoef(x, f, x->x_q);
274}
275
276static void sigbp_ft2(t_sigbp *x, t_floatarg q)
277{
278 sigbp_docoef(x, x->x_freq, q);
279}
280
281static void sigbp_clear(t_sigbp *x, t_floatarg q)
282{
283 x->x_ctl->c_x1 = x->x_ctl->c_x2 = 0;
284}
285
286static t_int *sigbp_perform(t_int *w)
287{
288 float *in = (float *)(w[1]);
289 float *out = (float *)(w[2]);
290 t_bpctl *c = (t_bpctl *)(w[3]);
291 int n = (t_int)(w[4]);
292 int i;
293 float last = c->c_x1;
294 float prev = c->c_x2;
295 float coef1 = c->c_coef1;
296 float coef2 = c->c_coef2;
297 float gain = c->c_gain;
298 for (i = 0; i < n; i++)
299 {
300 float output = *in++ + coef1 * last + coef2 * prev;
301 *out++ = gain * output;
302 prev = last;
303 last = output;
304 }
305 if (PD_BIGORSMALL(last))
306 last = 0;
307 if (PD_BIGORSMALL(prev))
308 prev = 0;
309 c->c_x1 = last;
310 c->c_x2 = prev;
311 return (w+5);
312}
313
314static void sigbp_dsp(t_sigbp *x, t_signal **sp)
315{
316 x->x_sr = sp[0]->s_sr;
317 sigbp_docoef(x, x->x_freq, x->x_q);
318 dsp_add(sigbp_perform, 4,
319 sp[0]->s_vec, sp[1]->s_vec,
320 x->x_ctl, sp[0]->s_n);
321
322}
323
324void sigbp_setup(void)
325{
326 sigbp_class = class_new(gensym("bp~"), (t_newmethod)sigbp_new, 0,
327 sizeof(t_sigbp), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
328 CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, x_f);
329 class_addmethod(sigbp_class, (t_method)sigbp_dsp, gensym("dsp"), 0);
330 class_addmethod(sigbp_class, (t_method)sigbp_ft1,
331 gensym("ft1"), A_FLOAT, 0);
332 class_addmethod(sigbp_class, (t_method)sigbp_ft2,
333 gensym("ft2"), A_FLOAT, 0);
334 class_addmethod(sigbp_class, (t_method)sigbp_clear, gensym("clear"), 0);
335}
336
337/* ---------------- biquad~ - raw biquad filter ----------------- */
338
339typedef struct biquadctl
340{
341 float c_x1;
342 float c_x2;
343 float c_fb1;
344 float c_fb2;
345 float c_ff1;
346 float c_ff2;
347 float c_ff3;
348} t_biquadctl;
349
350typedef struct sigbiquad
351{
352 t_object x_obj;
353 float x_f;
354 t_biquadctl x_cspace;
355 t_biquadctl *x_ctl;
356} t_sigbiquad;
357
358t_class *sigbiquad_class;
359
360static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
361
362static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv)
363{
364 t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
365 outlet_new(&x->x_obj, gensym("signal"));
366 x->x_ctl = &x->x_cspace;
367 x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0;
368 sigbiquad_list(x, s, argc, argv);
369 x->x_f = 0;
370 return (x);
371}
372
373static t_int *sigbiquad_perform(t_int *w)
374{
375 float *in = (float *)(w[1]);
376 float *out = (float *)(w[2]);
377 t_biquadctl *c = (t_biquadctl *)(w[3]);
378 int n = (t_int)(w[4]);
379 int i;
380 float last = c->c_x1;
381 float prev = c->c_x2;
382 float fb1 = c->c_fb1;
383 float fb2 = c->c_fb2;
384 float ff1 = c->c_ff1;
385 float ff2 = c->c_ff2;
386 float ff3 = c->c_ff3;
387 for (i = 0; i < n; i++)
388 {
389 float output = *in++ + fb1 * last + fb2 * prev;
390 if (PD_BIGORSMALL(output))
391 output = 0;
392 *out++ = ff1 * output + ff2 * last + ff3 * prev;
393 prev = last;
394 last = output;
395 }
396 c->c_x1 = last;
397 c->c_x2 = prev;
398 return (w+5);
399}
400
401static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
402{
403 float fb1 = atom_getfloatarg(0, argc, argv);
404 float fb2 = atom_getfloatarg(1, argc, argv);
405 float ff1 = atom_getfloatarg(2, argc, argv);
406 float ff2 = atom_getfloatarg(3, argc, argv);
407 float ff3 = atom_getfloatarg(4, argc, argv);
408 float discriminant = fb1 * fb1 + 4 * fb2;
409 t_biquadctl *c = x->x_ctl;
410 if (discriminant < 0) /* imaginary roots -- resonant filter */
411 {
412 /* they're conjugates so we just check that the product
413 is less than one */
414 if (fb2 >= -1.0f) goto stable;
415 }
416 else /* real roots */
417 {
418 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
419 vertex between -1 and 1, and that it's nonnegative
420 at both ends, which implies both roots are in [1-,1]. */
421 if (fb1 <= 2.0f && fb1 >= -2.0f &&
422 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
423 goto stable;
424 }
425 /* if unstable, just bash to zero */
426 fb1 = fb2 = ff1 = ff2 = ff3 = 0;
427stable:
428 c->c_fb1 = fb1;
429 c->c_fb2 = fb2;
430 c->c_ff1 = ff1;
431 c->c_ff2 = ff2;
432 c->c_ff3 = ff3;
433}
434
435static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
436{
437 t_biquadctl *c = x->x_ctl;
438 c->c_x1 = atom_getfloatarg(0, argc, argv);
439 c->c_x2 = atom_getfloatarg(1, argc, argv);
440}
441
442static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp)
443{
444 dsp_add(sigbiquad_perform, 4,
445 sp[0]->s_vec, sp[1]->s_vec,
446 x->x_ctl, sp[0]->s_n);
447
448}
449
450void sigbiquad_setup(void)
451{
452 sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new,
453 0, sizeof(t_sigbiquad), 0, A_GIMME, 0);
454 CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f);
455 class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0);
456 class_addlist(sigbiquad_class, sigbiquad_list);
457 class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"),
458 A_GIMME, 0);
459 class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"),
460 A_GIMME, 0);
461}
462
463/* ---------------- samphold~ - sample and hold ----------------- */
464
465typedef struct sigsamphold
466{
467 t_object x_obj;
468 float x_f;
469 float x_lastin;
470 float x_lastout;
471} t_sigsamphold;
472
473t_class *sigsamphold_class;
474
475static void *sigsamphold_new(void)
476{
477 t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
478 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
479 outlet_new(&x->x_obj, gensym("signal"));
480 x->x_lastin = 0;
481 x->x_lastout = 0;
482 x->x_f = 0;
483 return (x);
484}
485
486static t_int *sigsamphold_perform(t_int *w)
487{
488 float *in1 = (float *)(w[1]);
489 float *in2 = (float *)(w[2]);
490 float *out = (float *)(w[3]);
491 t_sigsamphold *x = (t_sigsamphold *)(w[4]);
492 int n = (t_int)(w[5]);
493 int i;
494 float lastin = x->x_lastin;
495 float lastout = x->x_lastout;
496 for (i = 0; i < n; i++, *in1++)
497 {
498 float next = *in2++;
499 if (next < lastin) lastout = *in1;
500 *out++ = lastout;
501 lastin = next;
502 }
503 x->x_lastin = lastin;
504 x->x_lastout = lastout;
505 return (w+6);
506}
507
508static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp)
509{
510 dsp_add(sigsamphold_perform, 5,
511 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
512 x, sp[0]->s_n);
513}
514
515static void sigsamphold_reset(t_sigsamphold *x)
516{
517 x->x_lastin = 1e20;
518}
519
520static void sigsamphold_set(t_sigsamphold *x, t_float f)
521{
522 x->x_lastout = f;
523}
524
525void sigsamphold_setup(void)
526{
527 sigsamphold_class = class_new(gensym("samphold~"),
528 (t_newmethod)sigsamphold_new, 0, sizeof(t_sigsamphold), 0, 0);
529 CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, x_f);
530 class_addmethod(sigsamphold_class, (t_method)sigsamphold_set,
531 gensym("set"), A_FLOAT, 0);
532 class_addmethod(sigsamphold_class, (t_method)sigsamphold_reset,
533 gensym("reset"), 0);
534 class_addmethod(sigsamphold_class, (t_method)sigsamphold_dsp,
535 gensym("dsp"), 0);
536}
537
538/* ------------------------ setup routine ------------------------- */
539
540void d_filter_setup(void)
541{
542 sighip_setup();
543 siglop_setup();
544 sigbp_setup();
545 sigbiquad_setup();
546 sigsamphold_setup();
547}
548/* Copyright (c) 1997-1999 Miller Puckette.
549* For information on usage and redistribution, and for a DISCLAIMER OF ALL
550* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
551
552/* "filters", both linear and nonlinear.
553*/
554#include "m_pd.h"
555#include <math.h>
556
557/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */
558
559typedef struct hipctl
560{
561 float c_x;
562 float c_coef;
563} t_hipctl;
564
565typedef struct sighip
566{
567 t_object x_obj;
568 float x_sr;
569 float x_hz;
570 t_hipctl x_cspace;
571 t_hipctl *x_ctl;
572 float x_f;
573} t_sighip;
574
575t_class *sighip_class;
576static void sighip_ft1(t_sighip *x, t_floatarg f);
577
578static void *sighip_new(t_floatarg f)
579{
580 t_sighip *x = (t_sighip *)pd_new(sighip_class);
581 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
582 outlet_new(&x->x_obj, gensym("signal"));
583 x->x_sr = 44100;
584 x->x_ctl = &x->x_cspace;
585 x->x_cspace.c_x = 0;
586 sighip_ft1(x, f);
587 x->x_f = 0;
588 return (x);
589}
590
591static void sighip_ft1(t_sighip *x, t_floatarg f)
592{
593 if (f < 0) f = 0;
594 x->x_hz = f;
595 x->x_ctl->c_coef = 1 - f * (2 * 3.14159) / x->x_sr;
596 if (x->x_ctl->c_coef < 0)
597 x->x_ctl->c_coef = 0;
598 else if (x->x_ctl->c_coef > 1)
599 x->x_ctl->c_coef = 1;
600}
601
602static t_int *sighip_perform(t_int *w)
603{
604 float *in = (float *)(w[1]);
605 float *out = (float *)(w[2]);
606 t_hipctl *c = (t_hipctl *)(w[3]);
607 int n = (t_int)(w[4]);
608 int i;
609 float last = c->c_x;
610 float coef = c->c_coef;
611 if (coef < 1)
612 {
613 for (i = 0; i < n; i++)
614 {
615 float new = *in++ + coef * last;
616 *out++ = new - last;
617 last = new;
618 }
619 if (PD_BIGORSMALL(last))
620 last = 0;
621 c->c_x = last;
622 }
623 else
624 {
625 for (i = 0; i < n; i++)
626 *out++ = *in++;
627 c->c_x = 0;
628 }
629 return (w+5);
630}
631
632static void sighip_dsp(t_sighip *x, t_signal **sp)
633{
634 x->x_sr = sp[0]->s_sr;
635 sighip_ft1(x, x->x_hz);
636 dsp_add(sighip_perform, 4,
637 sp[0]->s_vec, sp[1]->s_vec,
638 x->x_ctl, sp[0]->s_n);
639
640}
641
642static void sighip_clear(t_sighip *x, t_floatarg q)
643{
644 x->x_cspace.c_x = 0;
645}
646
647void sighip_setup(void)
648{
649 sighip_class = class_new(gensym("hip~"), (t_newmethod)sighip_new, 0,
650 sizeof(t_sighip), 0, A_DEFFLOAT, 0);
651 CLASS_MAINSIGNALIN(sighip_class, t_sighip, x_f);
652 class_addmethod(sighip_class, (t_method)sighip_dsp, gensym("dsp"), 0);
653 class_addmethod(sighip_class, (t_method)sighip_ft1,
654 gensym("ft1"), A_FLOAT, 0);
655 class_addmethod(sighip_class, (t_method)sighip_clear, gensym("clear"), 0);
656}
657
658/* ---------------- lop~ - 1-pole lopass filter. ----------------- */
659
660typedef struct lopctl
661{
662 float c_x;
663 float c_coef;
664} t_lopctl;
665
666typedef struct siglop
667{
668 t_object x_obj;
669 float x_sr;
670 float x_hz;
671 t_lopctl x_cspace;
672 t_lopctl *x_ctl;
673 float x_f;
674} t_siglop;
675
676t_class *siglop_class;
677
678static void siglop_ft1(t_siglop *x, t_floatarg f);
679
680static void *siglop_new(t_floatarg f)
681{
682 t_siglop *x = (t_siglop *)pd_new(siglop_class);
683 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
684 outlet_new(&x->x_obj, gensym("signal"));
685 x->x_sr = 44100;
686 x->x_ctl = &x->x_cspace;
687 x->x_cspace.c_x = 0;
688 siglop_ft1(x, f);
689 x->x_f = 0;
690 return (x);
691}
692
693static void siglop_ft1(t_siglop *x, t_floatarg f)
694{
695 if (f < 0) f = 0;
696 x->x_hz = f;
697 x->x_ctl->c_coef = f * (2 * 3.14159) / x->x_sr;
698 if (x->x_ctl->c_coef > 1)
699 x->x_ctl->c_coef = 1;
700 else if (x->x_ctl->c_coef < 0)
701 x->x_ctl->c_coef = 0;
702}
703
704static void siglop_clear(t_siglop *x, t_floatarg q)
705{
706 x->x_cspace.c_x = 0;
707}
708
709static t_int *siglop_perform(t_int *w)
710{
711 float *in = (float *)(w[1]);
712 float *out = (float *)(w[2]);
713 t_lopctl *c = (t_lopctl *)(w[3]);
714 int n = (t_int)(w[4]);
715 int i;
716 float last = c->c_x;
717 float coef = c->c_coef;
718 float feedback = 1 - coef;
719 for (i = 0; i < n; i++)
720 last = *out++ = coef * *in++ + feedback * last;
721 if (PD_BIGORSMALL(last))
722 last = 0;
723 c->c_x = last;
724 return (w+5);
725}
726
727static void siglop_dsp(t_siglop *x, t_signal **sp)
728{
729 x->x_sr = sp[0]->s_sr;
730 siglop_ft1(x, x->x_hz);
731 dsp_add(siglop_perform, 4,
732 sp[0]->s_vec, sp[1]->s_vec,
733 x->x_ctl, sp[0]->s_n);
734
735}
736
737void siglop_setup(void)
738{
739 siglop_class = class_new(gensym("lop~"), (t_newmethod)siglop_new, 0,
740 sizeof(t_siglop), 0, A_DEFFLOAT, 0);
741 CLASS_MAINSIGNALIN(siglop_class, t_siglop, x_f);
742 class_addmethod(siglop_class, (t_method)siglop_dsp, gensym("dsp"), 0);
743 class_addmethod(siglop_class, (t_method)siglop_ft1,
744 gensym("ft1"), A_FLOAT, 0);
745 class_addmethod(siglop_class, (t_method)siglop_clear, gensym("clear"), 0);
746}
747
748/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */
749
750typedef struct bpctl
751{
752 float c_x1;
753 float c_x2;
754 float c_coef1;
755 float c_coef2;
756 float c_gain;
757} t_bpctl;
758
759typedef struct sigbp
760{
761 t_object x_obj;
762 float x_sr;
763 float x_freq;
764 float x_q;
765 t_bpctl x_cspace;
766 t_bpctl *x_ctl;
767 float x_f;
768} t_sigbp;
769
770t_class *sigbp_class;
771
772static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
773
774static void *sigbp_new(t_floatarg f, t_floatarg q)
775{
776 t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
777 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
778 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2"));
779 outlet_new(&x->x_obj, gensym("signal"));
780 x->x_sr = 44100;
781 x->x_ctl = &x->x_cspace;
782 x->x_cspace.c_x1 = 0;
783 x->x_cspace.c_x2 = 0;
784 sigbp_docoef(x, f, q);
785 x->x_f = 0;
786 return (x);
787}
788
789static float sigbp_qcos(float f)
790{
791 if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f)
792 {
793 float g = f*f;
794 return (((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1);
795 }
796 else return (0);
797}
798
799static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q)
800{
801 float r, oneminusr, omega;
802 if (f < 0.001) f = 10;
803 if (q < 0) q = 0;
804 x->x_freq = f;
805 x->x_q = q;
806 omega = f * (2.0f * 3.14159f) / x->x_sr;
807 if (q < 0.001) oneminusr = 1.0f;
808 else oneminusr = omega/q;
809 if (oneminusr > 1.0f) oneminusr = 1.0f;
810 r = 1.0f - oneminusr;
811 x->x_ctl->c_coef1 = 2.0f * sigbp_qcos(omega) * r;
812 x->x_ctl->c_coef2 = - r * r;
813 x->x_ctl->c_gain = 2 * oneminusr * (oneminusr + r * omega);
814 /* post("r %f, omega %f, coef1 %f, coef2 %f",
815 r, omega, x->x_ctl->c_coef1, x->x_ctl->c_coef2); */
816}
817
818static void sigbp_ft1(t_sigbp *x, t_floatarg f)
819{
820 sigbp_docoef(x, f, x->x_q);
821}
822
823static void sigbp_ft2(t_sigbp *x, t_floatarg q)
824{
825 sigbp_docoef(x, x->x_freq, q);
826}
827
828static void sigbp_clear(t_sigbp *x, t_floatarg q)
829{
830 x->x_ctl->c_x1 = x->x_ctl->c_x2 = 0;
831}
832
833static t_int *sigbp_perform(t_int *w)
834{
835 float *in = (float *)(w[1]);
836 float *out = (float *)(w[2]);
837 t_bpctl *c = (t_bpctl *)(w[3]);
838 int n = (t_int)(w[4]);
839 int i;
840 float last = c->c_x1;
841 float prev = c->c_x2;
842 float coef1 = c->c_coef1;
843 float coef2 = c->c_coef2;
844 float gain = c->c_gain;
845 for (i = 0; i < n; i++)
846 {
847 float output = *in++ + coef1 * last + coef2 * prev;
848 *out++ = gain * output;
849 prev = last;
850 last = output;
851 }
852 if (PD_BIGORSMALL(last))
853 last = 0;
854 if (PD_BIGORSMALL(prev))
855 prev = 0;
856 c->c_x1 = last;
857 c->c_x2 = prev;
858 return (w+5);
859}
860
861static void sigbp_dsp(t_sigbp *x, t_signal **sp)
862{
863 x->x_sr = sp[0]->s_sr;
864 sigbp_docoef(x, x->x_freq, x->x_q);
865 dsp_add(sigbp_perform, 4,
866 sp[0]->s_vec, sp[1]->s_vec,
867 x->x_ctl, sp[0]->s_n);
868
869}
870
871void sigbp_setup(void)
872{
873 sigbp_class = class_new(gensym("bp~"), (t_newmethod)sigbp_new, 0,
874 sizeof(t_sigbp), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
875 CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, x_f);
876 class_addmethod(sigbp_class, (t_method)sigbp_dsp, gensym("dsp"), 0);
877 class_addmethod(sigbp_class, (t_method)sigbp_ft1,
878 gensym("ft1"), A_FLOAT, 0);
879 class_addmethod(sigbp_class, (t_method)sigbp_ft2,
880 gensym("ft2"), A_FLOAT, 0);
881 class_addmethod(sigbp_class, (t_method)sigbp_clear, gensym("clear"), 0);
882}
883
884/* ---------------- biquad~ - raw biquad filter ----------------- */
885
886typedef struct biquadctl
887{
888 float c_x1;
889 float c_x2;
890 float c_fb1;
891 float c_fb2;
892 float c_ff1;
893 float c_ff2;
894 float c_ff3;
895} t_biquadctl;
896
897typedef struct sigbiquad
898{
899 t_object x_obj;
900 float x_f;
901 t_biquadctl x_cspace;
902 t_biquadctl *x_ctl;
903} t_sigbiquad;
904
905t_class *sigbiquad_class;
906
907static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
908
909static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv)
910{
911 t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
912 outlet_new(&x->x_obj, gensym("signal"));
913 x->x_ctl = &x->x_cspace;
914 x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0;
915 sigbiquad_list(x, s, argc, argv);
916 x->x_f = 0;
917 return (x);
918}
919
920static t_int *sigbiquad_perform(t_int *w)
921{
922 float *in = (float *)(w[1]);
923 float *out = (float *)(w[2]);
924 t_biquadctl *c = (t_biquadctl *)(w[3]);
925 int n = (t_int)(w[4]);
926 int i;
927 float last = c->c_x1;
928 float prev = c->c_x2;
929 float fb1 = c->c_fb1;
930 float fb2 = c->c_fb2;
931 float ff1 = c->c_ff1;
932 float ff2 = c->c_ff2;
933 float ff3 = c->c_ff3;
934 for (i = 0; i < n; i++)
935 {
936 float output = *in++ + fb1 * last + fb2 * prev;
937 if (PD_BIGORSMALL(output))
938 output = 0;
939 *out++ = ff1 * output + ff2 * last + ff3 * prev;
940 prev = last;
941 last = output;
942 }
943 c->c_x1 = last;
944 c->c_x2 = prev;
945 return (w+5);
946}
947
948static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
949{
950 float fb1 = atom_getfloatarg(0, argc, argv);
951 float fb2 = atom_getfloatarg(1, argc, argv);
952 float ff1 = atom_getfloatarg(2, argc, argv);
953 float ff2 = atom_getfloatarg(3, argc, argv);
954 float ff3 = atom_getfloatarg(4, argc, argv);
955 float discriminant = fb1 * fb1 + 4 * fb2;
956 t_biquadctl *c = x->x_ctl;
957 if (discriminant < 0) /* imaginary roots -- resonant filter */
958 {
959 /* they're conjugates so we just check that the product
960 is less than one */
961 if (fb2 >= -1.0f) goto stable;
962 }
963 else /* real roots */
964 {
965 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
966 vertex between -1 and 1, and that it's nonnegative
967 at both ends, which implies both roots are in [1-,1]. */
968 if (fb1 <= 2.0f && fb1 >= -2.0f &&
969 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
970 goto stable;
971 }
972 /* if unstable, just bash to zero */
973 fb1 = fb2 = ff1 = ff2 = ff3 = 0;
974stable:
975 c->c_fb1 = fb1;
976 c->c_fb2 = fb2;
977 c->c_ff1 = ff1;
978 c->c_ff2 = ff2;
979 c->c_ff3 = ff3;
980}
981
982static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
983{
984 t_biquadctl *c = x->x_ctl;
985 c->c_x1 = atom_getfloatarg(0, argc, argv);
986 c->c_x2 = atom_getfloatarg(1, argc, argv);
987}
988
989static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp)
990{
991 dsp_add(sigbiquad_perform, 4,
992 sp[0]->s_vec, sp[1]->s_vec,
993 x->x_ctl, sp[0]->s_n);
994
995}
996
997void sigbiquad_setup(void)
998{
999 sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new,
1000 0, sizeof(t_sigbiquad), 0, A_GIMME, 0);
1001 CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f);
1002 class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0);
1003 class_addlist(sigbiquad_class, sigbiquad_list);
1004 class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"),
1005 A_GIMME, 0);
1006 class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"),
1007 A_GIMME, 0);
1008}
1009
1010/* ---------------- samphold~ - sample and hold ----------------- */
1011
1012typedef struct sigsamphold
1013{
1014 t_object x_obj;
1015 float x_f;
1016 float x_lastin;
1017 float x_lastout;
1018} t_sigsamphold;
1019
1020t_class *sigsamphold_class;
1021
1022static void *sigsamphold_new(void)
1023{
1024 t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
1025 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
1026 outlet_new(&x->x_obj, gensym("signal"));
1027 x->x_lastin = 0;
1028 x->x_lastout = 0;
1029 x->x_f = 0;
1030 return (x);
1031}
1032
1033static t_int *sigsamphold_perform(t_int *w)
1034{
1035 float *in1 = (float *)(w[1]);
1036 float *in2 = (float *)(w[2]);
1037 float *out = (float *)(w[3]);
1038 t_sigsamphold *x = (t_sigsamphold *)(w[4]);
1039 int n = (t_int)(w[5]);
1040 int i;
1041 float lastin = x->x_lastin;
1042 float lastout = x->x_lastout;
1043 for (i = 0; i < n; i++, *in1++)
1044 {
1045 float next = *in2++;
1046 if (next < lastin) lastout = *in1;
1047 *out++ = lastout;
1048 lastin = next;
1049 }
1050 x->x_lastin = lastin;
1051 x->x_lastout = lastout;
1052 return (w+6);
1053}
1054
1055static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp)
1056{
1057 dsp_add(sigsamphold_perform, 5,
1058 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
1059 x, sp[0]->s_n);
1060}
1061
1062static void sigsamphold_reset(t_sigsamphold *x)
1063{
1064 x->x_lastin = 1e20;
1065}
1066
1067static void sigsamphold_set(t_sigsamphold *x, t_float f)
1068{
1069 x->x_lastout = f;
1070}
1071
1072void sigsamphold_setup(void)
1073{
1074 sigsamphold_class = class_new(gensym("samphold~"),
1075 (t_newmethod)sigsamphold_new, 0, sizeof(t_sigsamphold), 0, 0);
1076 CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, x_f);
1077 class_addmethod(sigsamphold_class, (t_method)sigsamphold_set,
1078 gensym("set"), A_FLOAT, 0);
1079 class_addmethod(sigsamphold_class, (t_method)sigsamphold_reset,
1080 gensym("reset"), 0);
1081 class_addmethod(sigsamphold_class, (t_method)sigsamphold_dsp,
1082 gensym("dsp"), 0);
1083}
1084
1085/* ------------------------ setup routine ------------------------- */
1086
1087void d_filter_setup(void)
1088{
1089 sighip_setup();
1090 siglop_setup();
1091 sigbp_setup();
1092 sigbiquad_setup();
1093 sigsamphold_setup();
1094}
diff --git a/apps/plugins/pdbox/PDa/src/d_global.c b/apps/plugins/pdbox/PDa/src/d_global.c
new file mode 100644
index 0000000000..2b129ac5f4
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_global.c
@@ -0,0 +1,616 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* send~, receive~, throw~, catch~ */
6
7#include "m_pd.h"
8#include <string.h>
9
10#define DEFSENDVS 64 /* LATER get send to get this from canvas */
11
12/* ----------------------------- send~ ----------------------------- */
13static t_class *sigsend_class;
14
15typedef struct _sigsend
16{
17 t_object x_obj;
18 t_symbol *x_sym;
19 int x_n;
20 t_sample *x_vec;
21 float x_f;
22} t_sigsend;
23
24static void *sigsend_new(t_symbol *s)
25{
26 t_sigsend *x = (t_sigsend *)pd_new(sigsend_class);
27 pd_bind(&x->x_obj.ob_pd, s);
28 x->x_sym = s;
29 x->x_n = DEFSENDVS;
30 x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample));
31 memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample));
32 x->x_f = 0;
33 return (x);
34}
35
36static t_int *sigsend_perform(t_int *w)
37{
38 t_sample *in = (t_sample *)(w[1]);
39 t_sample *out = (t_sample *)(w[2]);
40 int n = (int)(w[3]);
41 while (n--)
42 {
43 *out = (PD_BIGORSMALL(*in) ? 0 : *in);
44 out++;
45 in++;
46 }
47 return (w+4);
48}
49
50static void sigsend_dsp(t_sigsend *x, t_signal **sp)
51{
52 if (x->x_n == sp[0]->s_n)
53 dsp_add(sigsend_perform, 3, sp[0]->s_vec, x->x_vec, sp[0]->s_n);
54 else error("sigsend %s: unexpected vector size", x->x_sym->s_name);
55}
56
57static void sigsend_free(t_sigsend *x)
58{
59 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
60 freebytes(x->x_vec, x->x_n * sizeof(float));
61}
62
63static void sigsend_setup(void)
64{
65 sigsend_class = class_new(gensym("send~"), (t_newmethod)sigsend_new,
66 (t_method)sigsend_free, sizeof(t_sigsend), 0, A_DEFSYM, 0);
67 class_addcreator((t_newmethod)sigsend_new, gensym("s~"), A_DEFSYM, 0);
68 CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, x_f);
69 class_addmethod(sigsend_class, (t_method)sigsend_dsp, gensym("dsp"), 0);
70}
71
72/* ----------------------------- receive~ ----------------------------- */
73static t_class *sigreceive_class;
74
75typedef struct _sigreceive
76{
77 t_object x_obj;
78 t_symbol *x_sym;
79 t_sample *x_wherefrom;
80 int x_n;
81} t_sigreceive;
82
83static void *sigreceive_new(t_symbol *s)
84{
85 t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class);
86 x->x_n = DEFSENDVS; /* LATER find our vector size correctly */
87 x->x_sym = s;
88 x->x_wherefrom = 0;
89 outlet_new(&x->x_obj, &s_signal);
90 return (x);
91}
92
93static t_int *sigreceive_perform(t_int *w)
94{
95 t_sigreceive *x = (t_sigreceive *)(w[1]);
96 t_sample *out = (t_sample *)(w[2]);
97 int n = (int)(w[3]);
98 t_sample *in = x->x_wherefrom;
99 if (in)
100 {
101 while (n--)
102 *out++ = *in++;
103 }
104 else
105 {
106 while (n--)
107 *out++ = 0;
108 }
109 return (w+4);
110}
111
112static void sigreceive_set(t_sigreceive *x, t_symbol *s)
113{
114 t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->x_sym = s),
115 sigsend_class);
116 if (sender)
117 {
118 if (sender->x_n == x->x_n)
119 x->x_wherefrom = sender->x_vec;
120 else
121 {
122 pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
123 x->x_wherefrom = 0;
124 }
125 }
126 else
127 {
128 pd_error(x, "receive~ %s: no matching send", x->x_sym->s_name);
129 x->x_wherefrom = 0;
130 }
131}
132
133static void sigreceive_dsp(t_sigreceive *x, t_signal **sp)
134{
135 if (sp[0]->s_n != x->x_n)
136 {
137 pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
138 }
139 else
140 {
141 sigreceive_set(x, x->x_sym);
142 dsp_add(sigreceive_perform, 3,
143 x, sp[0]->s_vec, sp[0]->s_n);
144 }
145}
146
147static void sigreceive_setup(void)
148{
149 sigreceive_class = class_new(gensym("receive~"),
150 (t_newmethod)sigreceive_new, 0,
151 sizeof(t_sigreceive), 0, A_DEFSYM, 0);
152 class_addcreator((t_newmethod)sigreceive_new, gensym("r~"), A_DEFSYM, 0);
153 class_addmethod(sigreceive_class, (t_method)sigreceive_set, gensym("set"),
154 A_SYMBOL, 0);
155 class_addmethod(sigreceive_class, (t_method)sigreceive_dsp, gensym("dsp"),
156 0);
157 class_sethelpsymbol(sigreceive_class, gensym("send~"));
158}
159
160/* ----------------------------- catch~ ----------------------------- */
161static t_class *sigcatch_class;
162
163typedef struct _sigcatch
164{
165 t_object x_obj;
166 t_symbol *x_sym;
167 int x_n;
168 t_sample *x_vec;
169} t_sigcatch;
170
171static void *sigcatch_new(t_symbol *s)
172{
173 t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class);
174 pd_bind(&x->x_obj.ob_pd, s);
175 x->x_sym = s;
176 x->x_n = DEFSENDVS;
177 x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample));
178 memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample));
179 outlet_new(&x->x_obj, &s_signal);
180 return (x);
181}
182
183static t_int *sigcatch_perform(t_int *w)
184{
185 t_sample *in = (t_sample *)(w[1]);
186 t_sample *out = (t_sample *)(w[2]);
187 int n = (int)(w[3]);
188 while (n--) *out++ = *in, *in++ = 0;
189 return (w+4);
190}
191
192static void sigcatch_dsp(t_sigcatch *x, t_signal **sp)
193{
194 if (x->x_n == sp[0]->s_n)
195 dsp_add(sigcatch_perform, 3, x->x_vec, sp[0]->s_vec, sp[0]->s_n);
196 else error("sigcatch %s: unexpected vector size", x->x_sym->s_name);
197}
198
199static void sigcatch_free(t_sigcatch *x)
200{
201 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
202 freebytes(x->x_vec, x->x_n * sizeof(float));
203}
204
205static void sigcatch_setup(void)
206{
207 sigcatch_class = class_new(gensym("catch~"), (t_newmethod)sigcatch_new,
208 (t_method)sigcatch_free, sizeof(t_sigcatch), CLASS_NOINLET, A_DEFSYM, 0);
209 class_addmethod(sigcatch_class, (t_method)sigcatch_dsp, gensym("dsp"), 0);
210 class_sethelpsymbol(sigcatch_class, gensym("throw~"));
211}
212
213/* ----------------------------- throw~ ----------------------------- */
214static t_class *sigthrow_class;
215
216typedef struct _sigthrow
217{
218 t_object x_obj;
219 t_symbol *x_sym;
220 t_sample *x_whereto;
221 int x_n;
222 t_float x_f;
223} t_sigthrow;
224
225static void *sigthrow_new(t_symbol *s)
226{
227 t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class);
228 x->x_sym = s;
229 x->x_whereto = 0;
230 x->x_n = DEFSENDVS;
231 x->x_f = 0;
232 return (x);
233}
234
235static t_int *sigthrow_perform(t_int *w)
236{
237 t_sigthrow *x = (t_sigthrow *)(w[1]);
238 t_sample *in = (t_sample *)(w[2]);
239 int n = (int)(w[3]);
240 t_sample *out = x->x_whereto;
241 if (out)
242 {
243 while (n--)
244 {
245 *out += (PD_BIGORSMALL(*in) ? 0 : *in);
246 out++;
247 in++;
248 }
249 }
250 return (w+4);
251}
252
253static void sigthrow_set(t_sigthrow *x, t_symbol *s)
254{
255 t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass((x->x_sym = s),
256 sigcatch_class);
257 if (catcher)
258 {
259 if (catcher->x_n == x->x_n)
260 x->x_whereto = catcher->x_vec;
261 else
262 {
263 pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
264 x->x_whereto = 0;
265 }
266 }
267 else
268 {
269 pd_error(x, "throw~ %s: no matching catch", x->x_sym->s_name);
270 x->x_whereto = 0;
271 }
272}
273
274static void sigthrow_dsp(t_sigthrow *x, t_signal **sp)
275{
276 if (sp[0]->s_n != x->x_n)
277 {
278 pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
279 }
280 else
281 {
282 sigthrow_set(x, x->x_sym);
283 dsp_add(sigthrow_perform, 3,
284 x, sp[0]->s_vec, sp[0]->s_n);
285 }
286}
287
288static void sigthrow_setup(void)
289{
290 sigthrow_class = class_new(gensym("throw~"), (t_newmethod)sigthrow_new, 0,
291 sizeof(t_sigthrow), 0, A_DEFSYM, 0);
292 class_addcreator((t_newmethod)sigthrow_new, gensym("r~"), A_DEFSYM, 0);
293 class_addmethod(sigthrow_class, (t_method)sigthrow_set, gensym("set"),
294 A_SYMBOL, 0);
295 CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, x_f);
296 class_addmethod(sigthrow_class, (t_method)sigthrow_dsp, gensym("dsp"), 0);
297}
298
299/* ----------------------- global setup routine ---------------- */
300
301void d_global_setup(void)
302{
303 sigsend_setup();
304 sigreceive_setup();
305 sigcatch_setup();
306 sigthrow_setup();
307}
308
309/* Copyright (c) 1997-1999 Miller Puckette.
310* For information on usage and redistribution, and for a DISCLAIMER OF ALL
311* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
312
313/* send~, receive~, throw~, catch~ */
314
315#include "m_pd.h"
316#include <string.h>
317
318#define DEFSENDVS 64 /* LATER get send to get this from canvas */
319
320/* ----------------------------- send~ ----------------------------- */
321static t_class *sigsend_class;
322
323typedef struct _sigsend
324{
325 t_object x_obj;
326 t_symbol *x_sym;
327 int x_n;
328 t_sample *x_vec;
329 float x_f;
330} t_sigsend;
331
332static void *sigsend_new(t_symbol *s)
333{
334 t_sigsend *x = (t_sigsend *)pd_new(sigsend_class);
335 pd_bind(&x->x_obj.ob_pd, s);
336 x->x_sym = s;
337 x->x_n = DEFSENDVS;
338 x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample));
339 memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample));
340 x->x_f = 0;
341 return (x);
342}
343
344static t_int *sigsend_perform(t_int *w)
345{
346 t_sample *in = (t_sample *)(w[1]);
347 t_sample *out = (t_sample *)(w[2]);
348 int n = (int)(w[3]);
349 while (n--)
350 {
351 *out = (PD_BIGORSMALL(*in) ? 0 : *in);
352 out++;
353 in++;
354 }
355 return (w+4);
356}
357
358static void sigsend_dsp(t_sigsend *x, t_signal **sp)
359{
360 if (x->x_n == sp[0]->s_n)
361 dsp_add(sigsend_perform, 3, sp[0]->s_vec, x->x_vec, sp[0]->s_n);
362 else error("sigsend %s: unexpected vector size", x->x_sym->s_name);
363}
364
365static void sigsend_free(t_sigsend *x)
366{
367 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
368 freebytes(x->x_vec, x->x_n * sizeof(float));
369}
370
371static void sigsend_setup(void)
372{
373 sigsend_class = class_new(gensym("send~"), (t_newmethod)sigsend_new,
374 (t_method)sigsend_free, sizeof(t_sigsend), 0, A_DEFSYM, 0);
375 class_addcreator((t_newmethod)sigsend_new, gensym("s~"), A_DEFSYM, 0);
376 CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, x_f);
377 class_addmethod(sigsend_class, (t_method)sigsend_dsp, gensym("dsp"), 0);
378}
379
380/* ----------------------------- receive~ ----------------------------- */
381static t_class *sigreceive_class;
382
383typedef struct _sigreceive
384{
385 t_object x_obj;
386 t_symbol *x_sym;
387 t_sample *x_wherefrom;
388 int x_n;
389} t_sigreceive;
390
391static void *sigreceive_new(t_symbol *s)
392{
393 t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class);
394 x->x_n = DEFSENDVS; /* LATER find our vector size correctly */
395 x->x_sym = s;
396 x->x_wherefrom = 0;
397 outlet_new(&x->x_obj, &s_signal);
398 return (x);
399}
400
401static t_int *sigreceive_perform(t_int *w)
402{
403 t_sigreceive *x = (t_sigreceive *)(w[1]);
404 t_sample *out = (t_sample *)(w[2]);
405 int n = (int)(w[3]);
406 t_sample *in = x->x_wherefrom;
407 if (in)
408 {
409 while (n--)
410 *out++ = *in++;
411 }
412 else
413 {
414 while (n--)
415 *out++ = 0;
416 }
417 return (w+4);
418}
419
420static void sigreceive_set(t_sigreceive *x, t_symbol *s)
421{
422 t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->x_sym = s),
423 sigsend_class);
424 if (sender)
425 {
426 if (sender->x_n == x->x_n)
427 x->x_wherefrom = sender->x_vec;
428 else
429 {
430 pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
431 x->x_wherefrom = 0;
432 }
433 }
434 else
435 {
436 pd_error(x, "receive~ %s: no matching send", x->x_sym->s_name);
437 x->x_wherefrom = 0;
438 }
439}
440
441static void sigreceive_dsp(t_sigreceive *x, t_signal **sp)
442{
443 if (sp[0]->s_n != x->x_n)
444 {
445 pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
446 }
447 else
448 {
449 sigreceive_set(x, x->x_sym);
450 dsp_add(sigreceive_perform, 3,
451 x, sp[0]->s_vec, sp[0]->s_n);
452 }
453}
454
455static void sigreceive_setup(void)
456{
457 sigreceive_class = class_new(gensym("receive~"),
458 (t_newmethod)sigreceive_new, 0,
459 sizeof(t_sigreceive), 0, A_DEFSYM, 0);
460 class_addcreator((t_newmethod)sigreceive_new, gensym("r~"), A_DEFSYM, 0);
461 class_addmethod(sigreceive_class, (t_method)sigreceive_set, gensym("set"),
462 A_SYMBOL, 0);
463 class_addmethod(sigreceive_class, (t_method)sigreceive_dsp, gensym("dsp"),
464 0);
465 class_sethelpsymbol(sigreceive_class, gensym("send~"));
466}
467
468/* ----------------------------- catch~ ----------------------------- */
469static t_class *sigcatch_class;
470
471typedef struct _sigcatch
472{
473 t_object x_obj;
474 t_symbol *x_sym;
475 int x_n;
476 t_sample *x_vec;
477} t_sigcatch;
478
479static void *sigcatch_new(t_symbol *s)
480{
481 t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class);
482 pd_bind(&x->x_obj.ob_pd, s);
483 x->x_sym = s;
484 x->x_n = DEFSENDVS;
485 x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample));
486 memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample));
487 outlet_new(&x->x_obj, &s_signal);
488 return (x);
489}
490
491static t_int *sigcatch_perform(t_int *w)
492{
493 t_sample *in = (t_sample *)(w[1]);
494 t_sample *out = (t_sample *)(w[2]);
495 int n = (int)(w[3]);
496 while (n--) *out++ = *in, *in++ = 0;
497 return (w+4);
498}
499
500static void sigcatch_dsp(t_sigcatch *x, t_signal **sp)
501{
502 if (x->x_n == sp[0]->s_n)
503 dsp_add(sigcatch_perform, 3, x->x_vec, sp[0]->s_vec, sp[0]->s_n);
504 else error("sigcatch %s: unexpected vector size", x->x_sym->s_name);
505}
506
507static void sigcatch_free(t_sigcatch *x)
508{
509 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
510 freebytes(x->x_vec, x->x_n * sizeof(float));
511}
512
513static void sigcatch_setup(void)
514{
515 sigcatch_class = class_new(gensym("catch~"), (t_newmethod)sigcatch_new,
516 (t_method)sigcatch_free, sizeof(t_sigcatch), CLASS_NOINLET, A_DEFSYM, 0);
517 class_addmethod(sigcatch_class, (t_method)sigcatch_dsp, gensym("dsp"), 0);
518 class_sethelpsymbol(sigcatch_class, gensym("throw~"));
519}
520
521/* ----------------------------- throw~ ----------------------------- */
522static t_class *sigthrow_class;
523
524typedef struct _sigthrow
525{
526 t_object x_obj;
527 t_symbol *x_sym;
528 t_sample *x_whereto;
529 int x_n;
530 t_float x_f;
531} t_sigthrow;
532
533static void *sigthrow_new(t_symbol *s)
534{
535 t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class);
536 x->x_sym = s;
537 x->x_whereto = 0;
538 x->x_n = DEFSENDVS;
539 x->x_f = 0;
540 return (x);
541}
542
543static t_int *sigthrow_perform(t_int *w)
544{
545 t_sigthrow *x = (t_sigthrow *)(w[1]);
546 t_sample *in = (t_sample *)(w[2]);
547 int n = (int)(w[3]);
548 t_sample *out = x->x_whereto;
549 if (out)
550 {
551 while (n--)
552 {
553 *out += (PD_BIGORSMALL(*in) ? 0 : *in);
554 out++;
555 in++;
556 }
557 }
558 return (w+4);
559}
560
561static void sigthrow_set(t_sigthrow *x, t_symbol *s)
562{
563 t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass((x->x_sym = s),
564 sigcatch_class);
565 if (catcher)
566 {
567 if (catcher->x_n == x->x_n)
568 x->x_whereto = catcher->x_vec;
569 else
570 {
571 pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
572 x->x_whereto = 0;
573 }
574 }
575 else
576 {
577 pd_error(x, "throw~ %s: no matching catch", x->x_sym->s_name);
578 x->x_whereto = 0;
579 }
580}
581
582static void sigthrow_dsp(t_sigthrow *x, t_signal **sp)
583{
584 if (sp[0]->s_n != x->x_n)
585 {
586 pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
587 }
588 else
589 {
590 sigthrow_set(x, x->x_sym);
591 dsp_add(sigthrow_perform, 3,
592 x, sp[0]->s_vec, sp[0]->s_n);
593 }
594}
595
596static void sigthrow_setup(void)
597{
598 sigthrow_class = class_new(gensym("throw~"), (t_newmethod)sigthrow_new, 0,
599 sizeof(t_sigthrow), 0, A_DEFSYM, 0);
600 class_addcreator((t_newmethod)sigthrow_new, gensym("r~"), A_DEFSYM, 0);
601 class_addmethod(sigthrow_class, (t_method)sigthrow_set, gensym("set"),
602 A_SYMBOL, 0);
603 CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, x_f);
604 class_addmethod(sigthrow_class, (t_method)sigthrow_dsp, gensym("dsp"), 0);
605}
606
607/* ----------------------- global setup routine ---------------- */
608
609void d_global_setup(void)
610{
611 sigsend_setup();
612 sigreceive_setup();
613 sigcatch_setup();
614 sigthrow_setup();
615}
616
diff --git a/apps/plugins/pdbox/PDa/src/d_imayer_fft.c b/apps/plugins/pdbox/PDa/src/d_imayer_fft.c
new file mode 100644
index 0000000000..d8e9e9f243
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_imayer_fft.c
@@ -0,0 +1,1032 @@
1/*
2** Algorithm: complex multiplication
3**
4** Performance: Bad accuracy, great speed.
5**
6** The simplest, way of generating trig values. Note, this method is
7** not stable, and errors accumulate rapidly.
8**
9** Computation: 2 *, 1 + per value.
10*/
11
12
13#include "m_fixed.h"
14
15
16#define TRIG_FAST
17
18#ifdef TRIG_FAST
19char mtrig_algorithm[] = "Simple";
20#define TRIG_VARS \
21 t_fixed t_c,t_s;
22#define TRIG_INIT(k,c,s) \
23 { \
24 t_c = fcostab[k]; \
25 t_s = fsintab[k]; \
26 c = itofix(1); \
27 s = 0; \
28 }
29#define TRIG_NEXT(k,c,s) \
30 { \
31 t_fixed t = c; \
32 c = mult(t,t_c) - mult(s,t_s); \
33 s = mult(t,t_s) + mult(s,t_c); \
34 }
35#define TRIG_23(k,c1,s1,c2,s2,c3,s3) \
36 { \
37 c2 = mult(c1,c1) - mult(s1,s1); \
38 s2 = (mult(c1,s1)<<2); \
39 c3 = mult(c2,c1) - mult(s2,s1); \
40 s3 = mult(c2,s1) + mult(s2,c1); \
41 }
42#endif
43#define TRIG_RESET(k,c,s)
44
45/*
46** Algorithm: O. Buneman's trig generator.
47**
48** Performance: Good accuracy, mediocre speed.
49**
50** Manipulates a log(n) table to stably create n evenly spaced trig
51** values. The newly generated values lay halfway between two
52** known values, and are calculated by appropriatelly scaling the
53** average of the known trig values appropriatelly according to the
54** angle between them. This process is inherently stable; and is
55** about as accurate as most trig library functions. The errors
56** caused by this code segment are primarily due to the less stable
57** method to calculate values for 2t and s 3t. Note: I believe this
58** algorithm is patented(!), see readme file for more details.
59**
60** Computation: 1 +, 1 *, much integer math, per trig value
61**
62*/
63
64#ifdef TRIG_GOOD
65#define TRIG_VARS \
66 int t_lam=0; \
67 double coswrk[TRIG_TABLE_SIZE],sinwrk[TRIG_TABLE_SIZE];
68#define TRIG_INIT(k,c,s) \
69 { \
70 int i; \
71 for (i=0 ; i<=k ; i++) \
72 {coswrk[i]=fcostab[i];sinwrk[i]=fsintab[i];} \
73 t_lam = 0; \
74 c = 1; \
75 s = 0; \
76 }
77#define TRIG_NEXT(k,c,s) \
78 { \
79 int i,j; \
80 (t_lam)++; \
81 for (i=0 ; !((1<<i)&t_lam) ; i++); \
82 i = k-i; \
83 s = sinwrk[i]; \
84 c = coswrk[i]; \
85 if (i>1) \
86 { \
87 for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
88 j = k - j; \
89 sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
90 coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
91 } \
92 }
93#endif
94
95
96#define TRIG_TAB_SIZE 22
97
98static long long halsec[TRIG_TAB_SIZE]= {1,2,3};
99
100#define FFTmult(x,y) mult(x,y)
101
102
103
104
105#include "d_imayer_tables.h"
106
107#define SQRT2 ftofix(1.414213562373095048801688724209698)
108
109
110void imayer_fht(t_fixed *fz, int n)
111{
112 int k,k1,k2,k3,k4,kx;
113 t_fixed *fi,*fn,*gi;
114 TRIG_VARS;
115
116 for (k1=1,k2=0;k1<n;k1++)
117 {
118 t_fixed aa;
119 for (k=n>>1; (!((k2^=k)&k)); k>>=1);
120 if (k1>k2)
121 {
122 aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
123 }
124 }
125 for ( k=0 ; (1<<k)<n ; k++ );
126 k &= 1;
127 if (k==0)
128 {
129 for (fi=fz,fn=fz+n;fi<fn;fi+=4)
130 {
131 t_fixed f0,f1,f2,f3;
132 f1 = fi[0 ]-fi[1 ];
133 f0 = fi[0 ]+fi[1 ];
134 f3 = fi[2 ]-fi[3 ];
135 f2 = fi[2 ]+fi[3 ];
136 fi[2 ] = (f0-f2);
137 fi[0 ] = (f0+f2);
138 fi[3 ] = (f1-f3);
139 fi[1 ] = (f1+f3);
140 }
141 }
142 else
143 {
144 for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
145 {
146 t_fixed bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
147 bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
148 bc1 = fi[0 ] - gi[0 ];
149 bs1 = fi[0 ] + gi[0 ];
150 bc2 = fi[2 ] - gi[2 ];
151 bs2 = fi[2 ] + gi[2 ];
152 bc3 = fi[4 ] - gi[4 ];
153 bs3 = fi[4 ] + gi[4 ];
154 bc4 = fi[6 ] - gi[6 ];
155 bs4 = fi[6 ] + gi[6 ];
156 bf1 = (bs1 - bs2);
157 bf0 = (bs1 + bs2);
158 bg1 = (bc1 - bc2);
159 bg0 = (bc1 + bc2);
160 bf3 = (bs3 - bs4);
161 bf2 = (bs3 + bs4);
162 bg3 = FFTmult(SQRT2,bc4);
163 bg2 = FFTmult(SQRT2,bc3);
164 fi[4 ] = bf0 - bf2;
165 fi[0 ] = bf0 + bf2;
166 fi[6 ] = bf1 - bf3;
167 fi[2 ] = bf1 + bf3;
168 gi[4 ] = bg0 - bg2;
169 gi[0 ] = bg0 + bg2;
170 gi[6 ] = bg1 - bg3;
171 gi[2 ] = bg1 + bg3;
172 }
173 }
174 if (n<16) return;
175
176 do
177 {
178 t_fixed s1,c1;
179 int ii;
180 k += 2;
181 k1 = 1 << k;
182 k2 = k1 << 1;
183 k4 = k2 << 1;
184 k3 = k2 + k1;
185 kx = k1 >> 1;
186 fi = fz;
187 gi = fi + kx;
188 fn = fz + n;
189 do
190 {
191 t_fixed g0,f0,f1,g1,f2,g2,f3,g3;
192 f1 = fi[0 ] - fi[k1];
193 f0 = fi[0 ] + fi[k1];
194 f3 = fi[k2] - fi[k3];
195 f2 = fi[k2] + fi[k3];
196 fi[k2] = f0 - f2;
197 fi[0 ] = f0 + f2;
198 fi[k3] = f1 - f3;
199 fi[k1] = f1 + f3;
200 g1 = gi[0 ] - gi[k1];
201 g0 = gi[0 ] + gi[k1];
202 g3 = FFTmult(SQRT2, gi[k3]);
203 g2 = FFTmult(SQRT2, gi[k2]);
204 gi[k2] = g0 - g2;
205 gi[0 ] = g0 + g2;
206 gi[k3] = g1 - g3;
207 gi[k1] = g1 + g3;
208 gi += k4;
209 fi += k4;
210 } while (fi<fn);
211 TRIG_INIT(k,c1,s1);
212 for (ii=1;ii<kx;ii++)
213 {
214 t_fixed c2,s2;
215 TRIG_NEXT(k,c1,s1);
216 c2 = FFTmult(c1,c1) - FFTmult(s1,s1);
217 s2 = 2*FFTmult(c1,s1);
218 fn = fz + n;
219 fi = fz +ii;
220 gi = fz +k1-ii;
221 do
222 {
223 t_fixed a,b,g0,f0,f1,g1,f2,g2,f3,g3;
224 b = FFTmult(s2,fi[k1]) - FFTmult(c2,gi[k1]);
225 a = FFTmult(c2,fi[k1]) + FFTmult(s2,gi[k1]);
226 f1 = fi[0 ] - a;
227 f0 = fi[0 ] + a;
228 g1 = gi[0 ] - b;
229 g0 = gi[0 ] + b;
230 b = FFTmult(s2,fi[k3]) - FFTmult(c2,gi[k3]);
231 a = FFTmult(c2,fi[k3]) + FFTmult(s2,gi[k3]);
232 f3 = fi[k2] - a;
233 f2 = fi[k2] + a;
234 g3 = gi[k2] - b;
235 g2 = gi[k2] + b;
236 b = FFTmult(s1,f2) - FFTmult(c1,g3);
237 a = FFTmult(c1,f2) + FFTmult(s1,g3);
238 fi[k2] = f0 - a;
239 fi[0 ] = f0 + a;
240 gi[k3] = g1 - b;
241 gi[k1] = g1 + b;
242 b = FFTmult(c1,g2) - FFTmult(s1,f3);
243 a = FFTmult(s1,g2) + FFTmult(c1,f3);
244 gi[k2] = g0 - a;
245 gi[0 ] = g0 + a;
246 fi[k3] = f1 - b;
247 fi[k1] = f1 + b;
248 gi += k4;
249 fi += k4;
250 } while (fi<fn);
251 }
252 TRIG_RESET(k,c1,s1);
253 } while (k4<n);
254}
255
256
257void imayer_fft(int n, t_fixed *real, t_fixed *imag)
258{
259 t_fixed a,b,c,d;
260 t_fixed q,r,s,t;
261 int i,j,k;
262 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
263 a = real[i]; b = real[j]; q=a+b; r=a-b;
264 c = imag[i]; d = imag[j]; s=c+d; t=c-d;
265 real[i] = (q+t)>>1; real[j] = (q-t)>>1;
266 imag[i] = (s-r)>>1; imag[j] = (s+r)>>1;
267 }
268 imayer_fht(real,n);
269 imayer_fht(imag,n);
270}
271
272void imayer_ifft(int n, t_fixed *real, t_fixed *imag)
273{
274 t_fixed a,b,c,d;
275 t_fixed q,r,s,t;
276 int i,j,k;
277 imayer_fht(real,n);
278 imayer_fht(imag,n);
279 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
280 a = real[i]; b = real[j]; q=a+b; r=a-b;
281 c = imag[i]; d = imag[j]; s=c+d; t=c-d;
282 imag[i] = (s+r)>>1; imag[j] = (s-r)>>1;
283 real[i] = (q-t)>>1; real[j] = (q+t)>>1;
284 }
285}
286
287void imayer_realfft(int n, t_fixed *real)
288{
289 t_fixed a,b,c,d;
290 int i,j,k;
291 imayer_fht(real,n);
292 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
293 a = real[i];
294 b = real[j];
295 real[j] = (a-b)>>1;
296 real[i] = (a+b)>>1;
297 }
298}
299
300void imayer_realifft(int n, t_fixed *real)
301{
302 t_fixed a,b,c,d;
303 int i,j,k;
304 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
305 a = real[i];
306 b = real[j];
307 real[j] = (a-b);
308 real[i] = (a+b);
309 }
310 imayer_fht(real,n);
311}
312
313
314
315#ifdef TEST
316
317static double dfcostab[TRIG_TAB_SIZE]=
318 {
319 .00000000000000000000000000000000000000000000000000,
320 .70710678118654752440084436210484903928483593768847,
321 .92387953251128675612818318939678828682241662586364,
322 .98078528040323044912618223613423903697393373089333,
323 .99518472667219688624483695310947992157547486872985,
324 .99879545620517239271477160475910069444320361470461,
325 .99969881869620422011576564966617219685006108125772,
326 .99992470183914454092164649119638322435060646880221,
327 .99998117528260114265699043772856771617391725094433,
328 .99999529380957617151158012570011989955298763362218,
329 .99999882345170190992902571017152601904826792288976,
330 .99999970586288221916022821773876567711626389934930,
331 .99999992646571785114473148070738785694820115568892,
332 .99999998161642929380834691540290971450507605124278,
333 .99999999540410731289097193313960614895889430318945,
334 .99999999885102682756267330779455410840053741619428,
335 .99999999971275670684941397221864177608908945791828,
336 .99999999992818917670977509588385049026048033310951
337 };
338static double dfsintab[TRIG_TAB_SIZE]=
339 {
340 1.0000000000000000000000000000000000000000000000000,
341 .70710678118654752440084436210484903928483593768846,
342 .38268343236508977172845998403039886676134456248561,
343 .19509032201612826784828486847702224092769161775195,
344 .09801714032956060199419556388864184586113667316749,
345 .04906767432741801425495497694268265831474536302574,
346 .02454122852291228803173452945928292506546611923944,
347 .01227153828571992607940826195100321214037231959176,
348 .00613588464915447535964023459037258091705788631738,
349 .00306795676296597627014536549091984251894461021344,
350 .00153398018628476561230369715026407907995486457522,
351 .00076699031874270452693856835794857664314091945205,
352 .00038349518757139558907246168118138126339502603495,
353 .00019174759731070330743990956198900093346887403385,
354 .00009587379909597734587051721097647635118706561284,
355 .00004793689960306688454900399049465887274686668768,
356 .00002396844980841821872918657716502182009476147489,
357 .00001198422490506970642152156159698898480473197753
358 };
359
360static double dhalsec[TRIG_TAB_SIZE]=
361 {
362 0,
363 0,
364 .54119610014619698439972320536638942006107206337801,
365 .50979557910415916894193980398784391368261849190893,
366 .50241928618815570551167011928012092247859337193963,
367 .50060299823519630134550410676638239611758632599591,
368 .50015063602065098821477101271097658495974913010340,
369 .50003765191554772296778139077905492847503165398345,
370 .50000941253588775676512870469186533538523133757983,
371 .50000235310628608051401267171204408939326297376426,
372 .50000058827484117879868526730916804925780637276181,
373 .50000014706860214875463798283871198206179118093251,
374 .50000003676714377807315864400643020315103490883972,
375 .50000000919178552207366560348853455333939112569380,
376 .50000000229794635411562887767906868558991922348920,
377 .50000000057448658687873302235147272458812263401372,
378 .50000000014362164661654736863252589967935073278768,
379 .50000000003590541164769084922906986545517021050714
380 };
381
382
383#include <stdio.h>
384
385
386int writetables()
387{
388 int i;
389
390 printf("/* Tables for fixed point lookup with %d bit precision*/\n\n",fix1);
391
392 printf("static int fsintab[TRIG_TAB_SIZE]= {\n");
393
394 for (i=0;i<TRIG_TAB_SIZE-1;i++)
395 printf("%ld, \n",ftofix(dfsintab[i]));
396 printf("%ld }; \n",ftofix(dfsintab[i]));
397
398
399 printf("\n\nstatic int fcostab[TRIG_TAB_SIZE]= {\n");
400
401 for (i=0;i<TRIG_TAB_SIZE-1;i++)
402 printf("%ld, \n",ftofix(dfcostab[i]));
403 printf("%ld }; \n",ftofix(dfcostab[i]));
404
405}
406
407
408#define OUTPUT \
409 fprintf(stderr,"Integer - Float\n");\
410 for (i=0;i<NP;i++)\
411 fprintf(stderr,"%f %f --> %f %f\n",fixtof(r[i]),fixtof(im[i]),\
412 fr[i],fim[i]);\
413 fprintf(stderr,"\n\n");
414
415
416
417int main()
418{
419 int i;
420 t_fixed r[256];
421 t_fixed im[256];
422 float fr[256];
423 float fim[256];
424
425
426#if 1
427 writetables();
428 exit(0);
429#endif
430
431
432#if 0
433 t_fixed c1,s1,c2,s2,c3,s3;
434 int k;
435 int i;
436
437 TRIG_VARS;
438
439 for (k=2;k<10;k+=2) {
440 TRIG_INIT(k,c1,s1);
441 for (i=0;i<8;i++) {
442 TRIG_NEXT(k,c1,s1);
443 TRIG_23(k,c1,s1,c2,s2,c3,s3);
444 printf("TRIG value k=%d,%d val1 = %f %f\n",k,i,fixtof(c1),fixtof(s1));
445 }
446 }
447#endif
448
449
450
451#if 1
452
453 #define NP 16
454
455 for (i=0;i<NP;i++) {
456 fr[i] = 0.;
457 r[i] = 0.;
458 fim[i] = 0.;
459 im[i] = 0;
460 }
461
462#if 0
463 for (i=0;i<NP;i++) {
464 if (i&1) {
465 fr[i] = 0.1*i;
466 r[i] = ftofix(0.1*i);
467 }
468 else {
469 fr[i] = 0.;
470 r[i] = 0.;
471 }
472 }
473#endif
474#if 0
475 for (i=0;i<NP;i++) {
476 fr[i] = 0.1;
477 r[i] = ftofix(0.1);
478 }
479#endif
480
481 r[1] = ftofix(0.1);
482 fr[1] = 0.1;
483
484
485
486 /* TEST RUN */
487
488 OUTPUT
489
490 imayer_fft(NP,r,im);
491 mayer_fft(NP,fr,fim);
492// imayer_fht(r,NP);
493// mayer_fht(fr,NP);
494
495#if 1
496 for (i=0;i<NP;i++) {
497 r[i] = mult(ftofix(0.01),r[i]);
498 fr[i] = 0.01*fr[i];
499 }
500#endif
501
502 OUTPUT
503
504
505 imayer_fft(NP,r,im);
506 mayer_fft(NP,fr,fim);
507
508 OUTPUT
509
510
511#endif
512
513
514}
515
516#endif
517/*
518** Algorithm: complex multiplication
519**
520** Performance: Bad accuracy, great speed.
521**
522** The simplest, way of generating trig values. Note, this method is
523** not stable, and errors accumulate rapidly.
524**
525** Computation: 2 *, 1 + per value.
526*/
527
528
529#include "m_fixed.h"
530
531
532#define TRIG_FAST
533
534#ifdef TRIG_FAST
535char mtrig_algorithm[] = "Simple";
536#define TRIG_VARS \
537 t_fixed t_c,t_s;
538#define TRIG_INIT(k,c,s) \
539 { \
540 t_c = fcostab[k]; \
541 t_s = fsintab[k]; \
542 c = itofix(1); \
543 s = 0; \
544 }
545#define TRIG_NEXT(k,c,s) \
546 { \
547 t_fixed t = c; \
548 c = mult(t,t_c) - mult(s,t_s); \
549 s = mult(t,t_s) + mult(s,t_c); \
550 }
551#define TRIG_23(k,c1,s1,c2,s2,c3,s3) \
552 { \
553 c2 = mult(c1,c1) - mult(s1,s1); \
554 s2 = (mult(c1,s1)<<2); \
555 c3 = mult(c2,c1) - mult(s2,s1); \
556 s3 = mult(c2,s1) + mult(s2,c1); \
557 }
558#endif
559#define TRIG_RESET(k,c,s)
560
561/*
562** Algorithm: O. Buneman's trig generator.
563**
564** Performance: Good accuracy, mediocre speed.
565**
566** Manipulates a log(n) table to stably create n evenly spaced trig
567** values. The newly generated values lay halfway between two
568** known values, and are calculated by appropriatelly scaling the
569** average of the known trig values appropriatelly according to the
570** angle between them. This process is inherently stable; and is
571** about as accurate as most trig library functions. The errors
572** caused by this code segment are primarily due to the less stable
573** method to calculate values for 2t and s 3t. Note: I believe this
574** algorithm is patented(!), see readme file for more details.
575**
576** Computation: 1 +, 1 *, much integer math, per trig value
577**
578*/
579
580#ifdef TRIG_GOOD
581#define TRIG_VARS \
582 int t_lam=0; \
583 double coswrk[TRIG_TABLE_SIZE],sinwrk[TRIG_TABLE_SIZE];
584#define TRIG_INIT(k,c,s) \
585 { \
586 int i; \
587 for (i=0 ; i<=k ; i++) \
588 {coswrk[i]=fcostab[i];sinwrk[i]=fsintab[i];} \
589 t_lam = 0; \
590 c = 1; \
591 s = 0; \
592 }
593#define TRIG_NEXT(k,c,s) \
594 { \
595 int i,j; \
596 (t_lam)++; \
597 for (i=0 ; !((1<<i)&t_lam) ; i++); \
598 i = k-i; \
599 s = sinwrk[i]; \
600 c = coswrk[i]; \
601 if (i>1) \
602 { \
603 for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
604 j = k - j; \
605 sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
606 coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
607 } \
608 }
609#endif
610
611
612#define TRIG_TAB_SIZE 22
613
614static long long halsec[TRIG_TAB_SIZE]= {1,2,3};
615
616#define FFTmult(x,y) mult(x,y)
617
618
619
620
621#include "d_imayer_tables.h"
622
623#define SQRT2 ftofix(1.414213562373095048801688724209698)
624
625
626void imayer_fht(t_fixed *fz, int n)
627{
628 int k,k1,k2,k3,k4,kx;
629 t_fixed *fi,*fn,*gi;
630 TRIG_VARS;
631
632 for (k1=1,k2=0;k1<n;k1++)
633 {
634 t_fixed aa;
635 for (k=n>>1; (!((k2^=k)&k)); k>>=1);
636 if (k1>k2)
637 {
638 aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
639 }
640 }
641 for ( k=0 ; (1<<k)<n ; k++ );
642 k &= 1;
643 if (k==0)
644 {
645 for (fi=fz,fn=fz+n;fi<fn;fi+=4)
646 {
647 t_fixed f0,f1,f2,f3;
648 f1 = fi[0 ]-fi[1 ];
649 f0 = fi[0 ]+fi[1 ];
650 f3 = fi[2 ]-fi[3 ];
651 f2 = fi[2 ]+fi[3 ];
652 fi[2 ] = (f0-f2);
653 fi[0 ] = (f0+f2);
654 fi[3 ] = (f1-f3);
655 fi[1 ] = (f1+f3);
656 }
657 }
658 else
659 {
660 for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
661 {
662 t_fixed bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
663 bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
664 bc1 = fi[0 ] - gi[0 ];
665 bs1 = fi[0 ] + gi[0 ];
666 bc2 = fi[2 ] - gi[2 ];
667 bs2 = fi[2 ] + gi[2 ];
668 bc3 = fi[4 ] - gi[4 ];
669 bs3 = fi[4 ] + gi[4 ];
670 bc4 = fi[6 ] - gi[6 ];
671 bs4 = fi[6 ] + gi[6 ];
672 bf1 = (bs1 - bs2);
673 bf0 = (bs1 + bs2);
674 bg1 = (bc1 - bc2);
675 bg0 = (bc1 + bc2);
676 bf3 = (bs3 - bs4);
677 bf2 = (bs3 + bs4);
678 bg3 = FFTmult(SQRT2,bc4);
679 bg2 = FFTmult(SQRT2,bc3);
680 fi[4 ] = bf0 - bf2;
681 fi[0 ] = bf0 + bf2;
682 fi[6 ] = bf1 - bf3;
683 fi[2 ] = bf1 + bf3;
684 gi[4 ] = bg0 - bg2;
685 gi[0 ] = bg0 + bg2;
686 gi[6 ] = bg1 - bg3;
687 gi[2 ] = bg1 + bg3;
688 }
689 }
690 if (n<16) return;
691
692 do
693 {
694 t_fixed s1,c1;
695 int ii;
696 k += 2;
697 k1 = 1 << k;
698 k2 = k1 << 1;
699 k4 = k2 << 1;
700 k3 = k2 + k1;
701 kx = k1 >> 1;
702 fi = fz;
703 gi = fi + kx;
704 fn = fz + n;
705 do
706 {
707 t_fixed g0,f0,f1,g1,f2,g2,f3,g3;
708 f1 = fi[0 ] - fi[k1];
709 f0 = fi[0 ] + fi[k1];
710 f3 = fi[k2] - fi[k3];
711 f2 = fi[k2] + fi[k3];
712 fi[k2] = f0 - f2;
713 fi[0 ] = f0 + f2;
714 fi[k3] = f1 - f3;
715 fi[k1] = f1 + f3;
716 g1 = gi[0 ] - gi[k1];
717 g0 = gi[0 ] + gi[k1];
718 g3 = FFTmult(SQRT2, gi[k3]);
719 g2 = FFTmult(SQRT2, gi[k2]);
720 gi[k2] = g0 - g2;
721 gi[0 ] = g0 + g2;
722 gi[k3] = g1 - g3;
723 gi[k1] = g1 + g3;
724 gi += k4;
725 fi += k4;
726 } while (fi<fn);
727 TRIG_INIT(k,c1,s1);
728 for (ii=1;ii<kx;ii++)
729 {
730 t_fixed c2,s2;
731 TRIG_NEXT(k,c1,s1);
732 c2 = FFTmult(c1,c1) - FFTmult(s1,s1);
733 s2 = 2*FFTmult(c1,s1);
734 fn = fz + n;
735 fi = fz +ii;
736 gi = fz +k1-ii;
737 do
738 {
739 t_fixed a,b,g0,f0,f1,g1,f2,g2,f3,g3;
740 b = FFTmult(s2,fi[k1]) - FFTmult(c2,gi[k1]);
741 a = FFTmult(c2,fi[k1]) + FFTmult(s2,gi[k1]);
742 f1 = fi[0 ] - a;
743 f0 = fi[0 ] + a;
744 g1 = gi[0 ] - b;
745 g0 = gi[0 ] + b;
746 b = FFTmult(s2,fi[k3]) - FFTmult(c2,gi[k3]);
747 a = FFTmult(c2,fi[k3]) + FFTmult(s2,gi[k3]);
748 f3 = fi[k2] - a;
749 f2 = fi[k2] + a;
750 g3 = gi[k2] - b;
751 g2 = gi[k2] + b;
752 b = FFTmult(s1,f2) - FFTmult(c1,g3);
753 a = FFTmult(c1,f2) + FFTmult(s1,g3);
754 fi[k2] = f0 - a;
755 fi[0 ] = f0 + a;
756 gi[k3] = g1 - b;
757 gi[k1] = g1 + b;
758 b = FFTmult(c1,g2) - FFTmult(s1,f3);
759 a = FFTmult(s1,g2) + FFTmult(c1,f3);
760 gi[k2] = g0 - a;
761 gi[0 ] = g0 + a;
762 fi[k3] = f1 - b;
763 fi[k1] = f1 + b;
764 gi += k4;
765 fi += k4;
766 } while (fi<fn);
767 }
768 TRIG_RESET(k,c1,s1);
769 } while (k4<n);
770}
771
772
773void imayer_fft(int n, t_fixed *real, t_fixed *imag)
774{
775 t_fixed a,b,c,d;
776 t_fixed q,r,s,t;
777 int i,j,k;
778 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
779 a = real[i]; b = real[j]; q=a+b; r=a-b;
780 c = imag[i]; d = imag[j]; s=c+d; t=c-d;
781 real[i] = (q+t)>>1; real[j] = (q-t)>>1;
782 imag[i] = (s-r)>>1; imag[j] = (s+r)>>1;
783 }
784 imayer_fht(real,n);
785 imayer_fht(imag,n);
786}
787
788void imayer_ifft(int n, t_fixed *real, t_fixed *imag)
789{
790 t_fixed a,b,c,d;
791 t_fixed q,r,s,t;
792 int i,j,k;
793 imayer_fht(real,n);
794 imayer_fht(imag,n);
795 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
796 a = real[i]; b = real[j]; q=a+b; r=a-b;
797 c = imag[i]; d = imag[j]; s=c+d; t=c-d;
798 imag[i] = (s+r)>>1; imag[j] = (s-r)>>1;
799 real[i] = (q-t)>>1; real[j] = (q+t)>>1;
800 }
801}
802
803void imayer_realfft(int n, t_fixed *real)
804{
805 t_fixed a,b,c,d;
806 int i,j,k;
807 imayer_fht(real,n);
808 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
809 a = real[i];
810 b = real[j];
811 real[j] = (a-b)>>1;
812 real[i] = (a+b)>>1;
813 }
814}
815
816void imayer_realifft(int n, t_fixed *real)
817{
818 t_fixed a,b,c,d;
819 int i,j,k;
820 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
821 a = real[i];
822 b = real[j];
823 real[j] = (a-b);
824 real[i] = (a+b);
825 }
826 imayer_fht(real,n);
827}
828
829
830
831#ifdef TEST
832
833static double dfcostab[TRIG_TAB_SIZE]=
834 {
835 .00000000000000000000000000000000000000000000000000,
836 .70710678118654752440084436210484903928483593768847,
837 .92387953251128675612818318939678828682241662586364,
838 .98078528040323044912618223613423903697393373089333,
839 .99518472667219688624483695310947992157547486872985,
840 .99879545620517239271477160475910069444320361470461,
841 .99969881869620422011576564966617219685006108125772,
842 .99992470183914454092164649119638322435060646880221,
843 .99998117528260114265699043772856771617391725094433,
844 .99999529380957617151158012570011989955298763362218,
845 .99999882345170190992902571017152601904826792288976,
846 .99999970586288221916022821773876567711626389934930,
847 .99999992646571785114473148070738785694820115568892,
848 .99999998161642929380834691540290971450507605124278,
849 .99999999540410731289097193313960614895889430318945,
850 .99999999885102682756267330779455410840053741619428,
851 .99999999971275670684941397221864177608908945791828,
852 .99999999992818917670977509588385049026048033310951
853 };
854static double dfsintab[TRIG_TAB_SIZE]=
855 {
856 1.0000000000000000000000000000000000000000000000000,
857 .70710678118654752440084436210484903928483593768846,
858 .38268343236508977172845998403039886676134456248561,
859 .19509032201612826784828486847702224092769161775195,
860 .09801714032956060199419556388864184586113667316749,
861 .04906767432741801425495497694268265831474536302574,
862 .02454122852291228803173452945928292506546611923944,
863 .01227153828571992607940826195100321214037231959176,
864 .00613588464915447535964023459037258091705788631738,
865 .00306795676296597627014536549091984251894461021344,
866 .00153398018628476561230369715026407907995486457522,
867 .00076699031874270452693856835794857664314091945205,
868 .00038349518757139558907246168118138126339502603495,
869 .00019174759731070330743990956198900093346887403385,
870 .00009587379909597734587051721097647635118706561284,
871 .00004793689960306688454900399049465887274686668768,
872 .00002396844980841821872918657716502182009476147489,
873 .00001198422490506970642152156159698898480473197753
874 };
875
876static double dhalsec[TRIG_TAB_SIZE]=
877 {
878 0,
879 0,
880 .54119610014619698439972320536638942006107206337801,
881 .50979557910415916894193980398784391368261849190893,
882 .50241928618815570551167011928012092247859337193963,
883 .50060299823519630134550410676638239611758632599591,
884 .50015063602065098821477101271097658495974913010340,
885 .50003765191554772296778139077905492847503165398345,
886 .50000941253588775676512870469186533538523133757983,
887 .50000235310628608051401267171204408939326297376426,
888 .50000058827484117879868526730916804925780637276181,
889 .50000014706860214875463798283871198206179118093251,
890 .50000003676714377807315864400643020315103490883972,
891 .50000000919178552207366560348853455333939112569380,
892 .50000000229794635411562887767906868558991922348920,
893 .50000000057448658687873302235147272458812263401372,
894 .50000000014362164661654736863252589967935073278768,
895 .50000000003590541164769084922906986545517021050714
896 };
897
898
899#include <stdio.h>
900
901
902int writetables()
903{
904 int i;
905
906 printf("/* Tables for fixed point lookup with %d bit precision*/\n\n",fix1);
907
908 printf("static int fsintab[TRIG_TAB_SIZE]= {\n");
909
910 for (i=0;i<TRIG_TAB_SIZE-1;i++)
911 printf("%ld, \n",ftofix(dfsintab[i]));
912 printf("%ld }; \n",ftofix(dfsintab[i]));
913
914
915 printf("\n\nstatic int fcostab[TRIG_TAB_SIZE]= {\n");
916
917 for (i=0;i<TRIG_TAB_SIZE-1;i++)
918 printf("%ld, \n",ftofix(dfcostab[i]));
919 printf("%ld }; \n",ftofix(dfcostab[i]));
920
921}
922
923
924#define OUTPUT \
925 fprintf(stderr,"Integer - Float\n");\
926 for (i=0;i<NP;i++)\
927 fprintf(stderr,"%f %f --> %f %f\n",fixtof(r[i]),fixtof(im[i]),\
928 fr[i],fim[i]);\
929 fprintf(stderr,"\n\n");
930
931
932
933int main()
934{
935 int i;
936 t_fixed r[256];
937 t_fixed im[256];
938 float fr[256];
939 float fim[256];
940
941
942#if 1
943 writetables();
944 exit(0);
945#endif
946
947
948#if 0
949 t_fixed c1,s1,c2,s2,c3,s3;
950 int k;
951 int i;
952
953 TRIG_VARS;
954
955 for (k=2;k<10;k+=2) {
956 TRIG_INIT(k,c1,s1);
957 for (i=0;i<8;i++) {
958 TRIG_NEXT(k,c1,s1);
959 TRIG_23(k,c1,s1,c2,s2,c3,s3);
960 printf("TRIG value k=%d,%d val1 = %f %f\n",k,i,fixtof(c1),fixtof(s1));
961 }
962 }
963#endif
964
965
966
967#if 1
968
969 #define NP 16
970
971 for (i=0;i<NP;i++) {
972 fr[i] = 0.;
973 r[i] = 0.;
974 fim[i] = 0.;
975 im[i] = 0;
976 }
977
978#if 0
979 for (i=0;i<NP;i++) {
980 if (i&1) {
981 fr[i] = 0.1*i;
982 r[i] = ftofix(0.1*i);
983 }
984 else {
985 fr[i] = 0.;
986 r[i] = 0.;
987 }
988 }
989#endif
990#if 0
991 for (i=0;i<NP;i++) {
992 fr[i] = 0.1;
993 r[i] = ftofix(0.1);
994 }
995#endif
996
997 r[1] = ftofix(0.1);
998 fr[1] = 0.1;
999
1000
1001
1002 /* TEST RUN */
1003
1004 OUTPUT
1005
1006 imayer_fft(NP,r,im);
1007 mayer_fft(NP,fr,fim);
1008// imayer_fht(r,NP);
1009// mayer_fht(fr,NP);
1010
1011#if 1
1012 for (i=0;i<NP;i++) {
1013 r[i] = mult(ftofix(0.01),r[i]);
1014 fr[i] = 0.01*fr[i];
1015 }
1016#endif
1017
1018 OUTPUT
1019
1020
1021 imayer_fft(NP,r,im);
1022 mayer_fft(NP,fr,fim);
1023
1024 OUTPUT
1025
1026
1027#endif
1028
1029
1030}
1031
1032#endif
diff --git a/apps/plugins/pdbox/PDa/src/d_imayer_tables.h b/apps/plugins/pdbox/PDa/src/d_imayer_tables.h
new file mode 100644
index 0000000000..e02d62490b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_imayer_tables.h
@@ -0,0 +1,100 @@
1/* Tables for fixed point lookup with 18 bit precision*/
2
3static int fsintab[TRIG_TAB_SIZE]= {
4262144,
5185363,
6100318,
751141,
825694,
912862,
106433,
113216,
121608,
13804,
14402,
15201,
16100,
1750,
1825,
1912,
206,
213,
220,
230,
240,
250 };
26
27
28static int fcostab[TRIG_TAB_SIZE]= {
290,
30185363,
31242189,
32257106,
33260881,
34261828,
35262065,
36262124,
37262139,
38262142,
39262143,
40262143,
41262143,
42262143,
43262143,
44262143,
45262143,
46262143,
470,
480,
490,
500 };
51/* Tables for fixed point lookup with 18 bit precision*/
52
53static int fsintab[TRIG_TAB_SIZE]= {
54262144,
55185363,
56100318,
5751141,
5825694,
5912862,
606433,
613216,
621608,
63804,
64402,
65201,
66100,
6750,
6825,
6912,
706,
713,
720,
730,
740,
750 };
76
77
78static int fcostab[TRIG_TAB_SIZE]= {
790,
80185363,
81242189,
82257106,
83260881,
84261828,
85262065,
86262124,
87262139,
88262142,
89262143,
90262143,
91262143,
92262143,
93262143,
94262143,
95262143,
96262143,
970,
980,
990,
1000 };
diff --git a/apps/plugins/pdbox/PDa/src/d_math.c b/apps/plugins/pdbox/PDa/src/d_math.c
new file mode 100644
index 0000000000..ee8a96692c
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_math.c
@@ -0,0 +1,1146 @@
1/* Copyright (c) 1997-2001 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* mathematical functions and other transfer functions, including tilde
6 versions of stuff from x_acoustics.c.
7*/
8
9#include "m_pd.h"
10#include <math.h>
11#define LOGTEN 2.302585092994
12
13/* ------------------------- clip~ -------------------------- */
14static t_class *clip_class;
15
16typedef struct _clip
17{
18 t_object x_obj;
19 float x_f;
20 t_sample x_lo;
21 t_sample x_hi;
22} t_clip;
23
24static void *clip_new(t_floatarg lo, t_floatarg hi)
25{
26 t_clip *x = (t_clip *)pd_new(clip_class);
27 x->x_lo = lo;
28 x->x_hi = hi;
29 outlet_new(&x->x_obj, gensym("signal"));
30 floatinlet_new(&x->x_obj, &x->x_lo);
31 floatinlet_new(&x->x_obj, &x->x_hi);
32 x->x_f = 0;
33 return (x);
34}
35
36static t_int *clip_perform(t_int *w)
37{
38 t_clip *x = (t_clip *)(w[1]);
39 t_float *in = (t_float *)(w[2]);
40 t_float *out = (t_float *)(w[3]);
41 int n = (int)(w[4]);
42 while (n--)
43 {
44 float f = *in++;
45 if (f < x->x_lo) f = x->x_lo;
46 if (f > x->x_hi) f = x->x_hi;
47 *out++ = f;
48 }
49 return (w+5);
50}
51
52static void clip_dsp(t_clip *x, t_signal **sp)
53{
54 dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
55}
56
57static void clip_setup(void)
58{
59 clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0,
60 sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
61 CLASS_MAINSIGNALIN(clip_class, t_clip, x_f);
62 class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), 0);
63}
64
65/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
66
67#define DUMTAB1SIZE 256
68#define DUMTAB2SIZE 1024
69
70static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
71
72static void init_rsqrt(void)
73{
74 int i;
75 for (i = 0; i < DUMTAB1SIZE; i++)
76 {
77 float f;
78 long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
79 *(long *)(&f) = l;
80 rsqrt_exptab[i] = 1./sqrt(f);
81 }
82 for (i = 0; i < DUMTAB2SIZE; i++)
83 {
84 float f = 1 + (1./DUMTAB2SIZE) * i;
85 rsqrt_mantissatab[i] = 1./sqrt(f);
86 }
87}
88
89 /* these are used in externs like "bonk" */
90
91float q8_rsqrt(float f)
92{
93 long l = *(long *)(&f);
94 if (f < 0) return (0);
95 else return (rsqrt_exptab[(l >> 23) & 0xff] *
96 rsqrt_mantissatab[(l >> 13) & 0x3ff]);
97}
98
99float q8_sqrt(float f)
100{
101 long l = *(long *)(&f);
102 if (f < 0) return (0);
103 else return (f * rsqrt_exptab[(l >> 23) & 0xff] *
104 rsqrt_mantissatab[(l >> 13) & 0x3ff]);
105}
106
107 /* the old names are OK unless we're in IRIX N32 */
108
109#ifndef N32
110float qsqrt(float f) {return (q8_sqrt(f)); }
111float qrsqrt(float f) {return (q8_rsqrt(f)); }
112#endif
113
114
115
116typedef struct sigrsqrt
117{
118 t_object x_obj;
119 float x_f;
120} t_sigrsqrt;
121
122static t_class *sigrsqrt_class;
123
124static void *sigrsqrt_new(void)
125{
126 t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
127 outlet_new(&x->x_obj, gensym("signal"));
128 x->x_f = 0;
129 return (x);
130}
131
132static t_int *sigrsqrt_perform(t_int *w)
133{
134 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
135 t_int n = *(t_int *)(w+3);
136 while (n--)
137 {
138 float f = *in;
139 long l = *(long *)(in++);
140 if (f < 0) *out++ = 0;
141 else
142 {
143 float g = rsqrt_exptab[(l >> 23) & 0xff] *
144 rsqrt_mantissatab[(l >> 13) & 0x3ff];
145 *out++ = 1.5 * g - 0.5 * g * g * g * f;
146 }
147 }
148 return (w + 4);
149}
150
151static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp)
152{
153 dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
154}
155
156void sigrsqrt_setup(void)
157{
158 init_rsqrt();
159 sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0,
160 sizeof(t_sigrsqrt), 0, 0);
161 /* an old name for it: */
162 class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0);
163 CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f);
164 class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, gensym("dsp"), 0);
165}
166
167
168/* sigsqrt - square root good to 8 mantissa bits */
169
170typedef struct sigsqrt
171{
172 t_object x_obj;
173 float x_f;
174} t_sigsqrt;
175
176static t_class *sigsqrt_class;
177
178static void *sigsqrt_new(void)
179{
180 t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
181 outlet_new(&x->x_obj, gensym("signal"));
182 x->x_f = 0;
183 return (x);
184}
185
186t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */
187{
188 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
189 t_int n = *(t_int *)(w+3);
190 while (n--)
191 {
192 float f = *in;
193 long l = *(long *)(in++);
194 if (f < 0) *out++ = 0;
195 else
196 {
197 float g = rsqrt_exptab[(l >> 23) & 0xff] *
198 rsqrt_mantissatab[(l >> 13) & 0x3ff];
199 *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
200 }
201 }
202 return (w + 4);
203}
204
205static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp)
206{
207 dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
208}
209
210void sigsqrt_setup(void)
211{
212 sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0,
213 sizeof(t_sigsqrt), 0, 0);
214 class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */
215 CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f);
216 class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, gensym("dsp"), 0);
217}
218
219/* ------------------------------ wrap~ -------------------------- */
220
221typedef struct wrap
222{
223 t_object x_obj;
224 float x_f;
225} t_sigwrap;
226
227t_class *sigwrap_class;
228
229static void *sigwrap_new(void)
230{
231 t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
232 outlet_new(&x->x_obj, gensym("signal"));
233 x->x_f = 0;
234 return (x);
235}
236
237static t_int *sigwrap_perform(t_int *w)
238{
239 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
240 t_int n = *(t_int *)(w+3);
241 while (n--)
242 {
243 float f = *in++;
244 int k = f;
245 if (f > 0) *out++ = f-k;
246 else *out++ = f - (k-1);
247 }
248 return (w + 4);
249}
250
251static void sigwrap_dsp(t_sigwrap *x, t_signal **sp)
252{
253 dsp_add(sigwrap_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
254}
255
256void sigwrap_setup(void)
257{
258 sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0,
259 sizeof(t_sigwrap), 0, 0);
260 CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f);
261 class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, gensym("dsp"), 0);
262}
263
264/* ------------------------------ mtof_tilde~ -------------------------- */
265
266typedef struct mtof_tilde
267{
268 t_object x_obj;
269 float x_f;
270} t_mtof_tilde;
271
272t_class *mtof_tilde_class;
273
274static void *mtof_tilde_new(void)
275{
276 t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class);
277 outlet_new(&x->x_obj, gensym("signal"));
278 x->x_f = 0;
279 return (x);
280}
281
282static t_int *mtof_tilde_perform(t_int *w)
283{
284 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
285 t_int n = *(t_int *)(w+3);
286 for (; n--; in++, out++)
287 {
288 float f = *in;
289 if (f <= -1500) *out = 0;
290 else
291 {
292 if (f > 1499) f = 1499;
293 *out = 8.17579891564 * exp(.0577622650 * f);
294 }
295 }
296 return (w + 4);
297}
298
299static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp)
300{
301 dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
302}
303
304void mtof_tilde_setup(void)
305{
306 mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0,
307 sizeof(t_mtof_tilde), 0, 0);
308 CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f);
309 class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, gensym("dsp"), 0);
310}
311
312/* ------------------------------ ftom_tilde~ -------------------------- */
313
314typedef struct ftom_tilde
315{
316 t_object x_obj;
317 float x_f;
318} t_ftom_tilde;
319
320t_class *ftom_tilde_class;
321
322static void *ftom_tilde_new(void)
323{
324 t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class);
325 outlet_new(&x->x_obj, gensym("signal"));
326 x->x_f = 0;
327 return (x);
328}
329
330static t_int *ftom_tilde_perform(t_int *w)
331{
332 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
333 t_int n = *(t_int *)(w+3);
334 for (; n--; *in++, out++)
335 {
336 float f = *in;
337 *out = (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
338 }
339 return (w + 4);
340}
341
342static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp)
343{
344 dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
345}
346
347void ftom_tilde_setup(void)
348{
349 ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0,
350 sizeof(t_ftom_tilde), 0, 0);
351 CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f);
352 class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, gensym("dsp"), 0);
353}
354
355/* ------------------------------ dbtorms~ -------------------------- */
356
357typedef struct dbtorms_tilde
358{
359 t_object x_obj;
360 float x_f;
361} t_dbtorms_tilde;
362
363t_class *dbtorms_tilde_class;
364
365static void *dbtorms_tilde_new(void)
366{
367 t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class);
368 outlet_new(&x->x_obj, gensym("signal"));
369 x->x_f = 0;
370 return (x);
371}
372
373static t_int *dbtorms_tilde_perform(t_int *w)
374{
375 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
376 t_int n = *(t_int *)(w+3);
377 for (; n--; in++, out++)
378 {
379 float f = *in;
380 if (f <= 0) *out = 0;
381 else
382 {
383 if (f > 485)
384 f = 485;
385 *out = exp((LOGTEN * 0.05) * (f-100.));
386 }
387 }
388 return (w + 4);
389}
390
391static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp)
392{
393 dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
394}
395
396void dbtorms_tilde_setup(void)
397{
398 dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0,
399 sizeof(t_dbtorms_tilde), 0, 0);
400 CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f);
401 class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, gensym("dsp"), 0);
402}
403
404/* ------------------------------ rmstodb~ -------------------------- */
405
406typedef struct rmstodb_tilde
407{
408 t_object x_obj;
409 float x_f;
410} t_rmstodb_tilde;
411
412t_class *rmstodb_tilde_class;
413
414static void *rmstodb_tilde_new(void)
415{
416 t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class);
417 outlet_new(&x->x_obj, gensym("signal"));
418 x->x_f = 0;
419 return (x);
420}
421
422static t_int *rmstodb_tilde_perform(t_int *w)
423{
424 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
425 t_int n = *(t_int *)(w+3);
426 for (; n--; in++, out++)
427 {
428 float f = *in;
429 if (f <= 0) *out = 0;
430 else
431 {
432 float g = 100 + 20./LOGTEN * log(f);
433 *out = (g < 0 ? 0 : g);
434 }
435 }
436 return (w + 4);
437}
438
439static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp)
440{
441 dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
442}
443
444void rmstodb_tilde_setup(void)
445{
446 rmstodb_tilde_class = class_new(gensym("rmstodb~"), (t_newmethod)rmstodb_tilde_new, 0,
447 sizeof(t_rmstodb_tilde), 0, 0);
448 CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f);
449 class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, gensym("dsp"), 0);
450}
451
452/* ------------------------------ dbtopow~ -------------------------- */
453
454typedef struct dbtopow_tilde
455{
456 t_object x_obj;
457 float x_f;
458} t_dbtopow_tilde;
459
460t_class *dbtopow_tilde_class;
461
462static void *dbtopow_tilde_new(void)
463{
464 t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class);
465 outlet_new(&x->x_obj, gensym("signal"));
466 x->x_f = 0;
467 return (x);
468}
469
470static t_int *dbtopow_tilde_perform(t_int *w)
471{
472 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
473 t_int n = *(t_int *)(w+3);
474 for (; n--; in++, out++)
475 {
476 float f = *in;
477 if (f <= 0) *out = 0;
478 else
479 {
480 if (f > 870)
481 f = 870;
482 *out = exp((LOGTEN * 0.1) * (f-100.));
483 }
484 }
485 return (w + 4);
486}
487
488static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp)
489{
490 dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
491}
492
493void dbtopow_tilde_setup(void)
494{
495 dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0,
496 sizeof(t_dbtopow_tilde), 0, 0);
497 CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f);
498 class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, gensym("dsp"), 0);
499}
500
501/* ------------------------------ powtodb~ -------------------------- */
502
503typedef struct powtodb_tilde
504{
505 t_object x_obj;
506 float x_f;
507} t_powtodb_tilde;
508
509t_class *powtodb_tilde_class;
510
511static void *powtodb_tilde_new(void)
512{
513 t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class);
514 outlet_new(&x->x_obj, gensym("signal"));
515 x->x_f = 0;
516 return (x);
517}
518
519static t_int *powtodb_tilde_perform(t_int *w)
520{
521 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
522 t_int n = *(t_int *)(w+3);
523 for (; n--; in++, out++)
524 {
525 float f = *in;
526 if (f <= 0) *out = 0;
527 else
528 {
529 float g = 100 + 10./LOGTEN * log(f);
530 *out = (g < 0 ? 0 : g);
531 }
532 }
533 return (w + 4);
534}
535
536static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp)
537{
538 dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
539}
540
541void powtodb_tilde_setup(void)
542{
543 powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0,
544 sizeof(t_powtodb_tilde), 0, 0);
545 CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f);
546 class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0);
547}
548
549
550/* ------------------------ global setup routine ------------------------- */
551
552void d_math_setup(void)
553{
554 t_symbol *s = gensym("acoustics~.pd");
555 clip_setup();
556 sigrsqrt_setup();
557 sigsqrt_setup();
558 sigwrap_setup();
559 mtof_tilde_setup();
560 ftom_tilde_setup();
561 dbtorms_tilde_setup();
562 rmstodb_tilde_setup();
563 dbtopow_tilde_setup();
564 powtodb_tilde_setup();
565
566 class_sethelpsymbol(mtof_tilde_class, s);
567 class_sethelpsymbol(ftom_tilde_class, s);
568 class_sethelpsymbol(dbtorms_tilde_class, s);
569 class_sethelpsymbol(rmstodb_tilde_class, s);
570 class_sethelpsymbol(dbtopow_tilde_class, s);
571 class_sethelpsymbol(powtodb_tilde_class, s);
572}
573
574/* Copyright (c) 1997-2001 Miller Puckette and others.
575* For information on usage and redistribution, and for a DISCLAIMER OF ALL
576* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
577
578/* mathematical functions and other transfer functions, including tilde
579 versions of stuff from x_acoustics.c.
580*/
581
582#include "m_pd.h"
583#include <math.h>
584#define LOGTEN 2.302585092994
585
586/* ------------------------- clip~ -------------------------- */
587static t_class *clip_class;
588
589typedef struct _clip
590{
591 t_object x_obj;
592 float x_f;
593 t_sample x_lo;
594 t_sample x_hi;
595} t_clip;
596
597static void *clip_new(t_floatarg lo, t_floatarg hi)
598{
599 t_clip *x = (t_clip *)pd_new(clip_class);
600 x->x_lo = lo;
601 x->x_hi = hi;
602 outlet_new(&x->x_obj, gensym("signal"));
603 floatinlet_new(&x->x_obj, &x->x_lo);
604 floatinlet_new(&x->x_obj, &x->x_hi);
605 x->x_f = 0;
606 return (x);
607}
608
609static t_int *clip_perform(t_int *w)
610{
611 t_clip *x = (t_clip *)(w[1]);
612 t_float *in = (t_float *)(w[2]);
613 t_float *out = (t_float *)(w[3]);
614 int n = (int)(w[4]);
615 while (n--)
616 {
617 float f = *in++;
618 if (f < x->x_lo) f = x->x_lo;
619 if (f > x->x_hi) f = x->x_hi;
620 *out++ = f;
621 }
622 return (w+5);
623}
624
625static void clip_dsp(t_clip *x, t_signal **sp)
626{
627 dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
628}
629
630static void clip_setup(void)
631{
632 clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0,
633 sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
634 CLASS_MAINSIGNALIN(clip_class, t_clip, x_f);
635 class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), 0);
636}
637
638/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
639
640#define DUMTAB1SIZE 256
641#define DUMTAB2SIZE 1024
642
643static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
644
645static void init_rsqrt(void)
646{
647 int i;
648 for (i = 0; i < DUMTAB1SIZE; i++)
649 {
650 float f;
651 long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
652 *(long *)(&f) = l;
653 rsqrt_exptab[i] = 1./sqrt(f);
654 }
655 for (i = 0; i < DUMTAB2SIZE; i++)
656 {
657 float f = 1 + (1./DUMTAB2SIZE) * i;
658 rsqrt_mantissatab[i] = 1./sqrt(f);
659 }
660}
661
662 /* these are used in externs like "bonk" */
663
664float q8_rsqrt(float f)
665{
666 long l = *(long *)(&f);
667 if (f < 0) return (0);
668 else return (rsqrt_exptab[(l >> 23) & 0xff] *
669 rsqrt_mantissatab[(l >> 13) & 0x3ff]);
670}
671
672float q8_sqrt(float f)
673{
674 long l = *(long *)(&f);
675 if (f < 0) return (0);
676 else return (f * rsqrt_exptab[(l >> 23) & 0xff] *
677 rsqrt_mantissatab[(l >> 13) & 0x3ff]);
678}
679
680 /* the old names are OK unless we're in IRIX N32 */
681
682#ifndef N32
683float qsqrt(float f) {return (q8_sqrt(f)); }
684float qrsqrt(float f) {return (q8_rsqrt(f)); }
685#endif
686
687
688
689typedef struct sigrsqrt
690{
691 t_object x_obj;
692 float x_f;
693} t_sigrsqrt;
694
695static t_class *sigrsqrt_class;
696
697static void *sigrsqrt_new(void)
698{
699 t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
700 outlet_new(&x->x_obj, gensym("signal"));
701 x->x_f = 0;
702 return (x);
703}
704
705static t_int *sigrsqrt_perform(t_int *w)
706{
707 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
708 t_int n = *(t_int *)(w+3);
709 while (n--)
710 {
711 float f = *in;
712 long l = *(long *)(in++);
713 if (f < 0) *out++ = 0;
714 else
715 {
716 float g = rsqrt_exptab[(l >> 23) & 0xff] *
717 rsqrt_mantissatab[(l >> 13) & 0x3ff];
718 *out++ = 1.5 * g - 0.5 * g * g * g * f;
719 }
720 }
721 return (w + 4);
722}
723
724static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp)
725{
726 dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
727}
728
729void sigrsqrt_setup(void)
730{
731 init_rsqrt();
732 sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0,
733 sizeof(t_sigrsqrt), 0, 0);
734 /* an old name for it: */
735 class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0);
736 CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f);
737 class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, gensym("dsp"), 0);
738}
739
740
741/* sigsqrt - square root good to 8 mantissa bits */
742
743typedef struct sigsqrt
744{
745 t_object x_obj;
746 float x_f;
747} t_sigsqrt;
748
749static t_class *sigsqrt_class;
750
751static void *sigsqrt_new(void)
752{
753 t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
754 outlet_new(&x->x_obj, gensym("signal"));
755 x->x_f = 0;
756 return (x);
757}
758
759t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */
760{
761 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
762 t_int n = *(t_int *)(w+3);
763 while (n--)
764 {
765 float f = *in;
766 long l = *(long *)(in++);
767 if (f < 0) *out++ = 0;
768 else
769 {
770 float g = rsqrt_exptab[(l >> 23) & 0xff] *
771 rsqrt_mantissatab[(l >> 13) & 0x3ff];
772 *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
773 }
774 }
775 return (w + 4);
776}
777
778static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp)
779{
780 dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
781}
782
783void sigsqrt_setup(void)
784{
785 sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0,
786 sizeof(t_sigsqrt), 0, 0);
787 class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */
788 CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f);
789 class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, gensym("dsp"), 0);
790}
791
792/* ------------------------------ wrap~ -------------------------- */
793
794typedef struct wrap
795{
796 t_object x_obj;
797 float x_f;
798} t_sigwrap;
799
800t_class *sigwrap_class;
801
802static void *sigwrap_new(void)
803{
804 t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
805 outlet_new(&x->x_obj, gensym("signal"));
806 x->x_f = 0;
807 return (x);
808}
809
810static t_int *sigwrap_perform(t_int *w)
811{
812 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
813 t_int n = *(t_int *)(w+3);
814 while (n--)
815 {
816 float f = *in++;
817 int k = f;
818 if (f > 0) *out++ = f-k;
819 else *out++ = f - (k-1);
820 }
821 return (w + 4);
822}
823
824static void sigwrap_dsp(t_sigwrap *x, t_signal **sp)
825{
826 dsp_add(sigwrap_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
827}
828
829void sigwrap_setup(void)
830{
831 sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0,
832 sizeof(t_sigwrap), 0, 0);
833 CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f);
834 class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, gensym("dsp"), 0);
835}
836
837/* ------------------------------ mtof_tilde~ -------------------------- */
838
839typedef struct mtof_tilde
840{
841 t_object x_obj;
842 float x_f;
843} t_mtof_tilde;
844
845t_class *mtof_tilde_class;
846
847static void *mtof_tilde_new(void)
848{
849 t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class);
850 outlet_new(&x->x_obj, gensym("signal"));
851 x->x_f = 0;
852 return (x);
853}
854
855static t_int *mtof_tilde_perform(t_int *w)
856{
857 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
858 t_int n = *(t_int *)(w+3);
859 for (; n--; in++, out++)
860 {
861 float f = *in;
862 if (f <= -1500) *out = 0;
863 else
864 {
865 if (f > 1499) f = 1499;
866 *out = 8.17579891564 * exp(.0577622650 * f);
867 }
868 }
869 return (w + 4);
870}
871
872static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp)
873{
874 dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
875}
876
877void mtof_tilde_setup(void)
878{
879 mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0,
880 sizeof(t_mtof_tilde), 0, 0);
881 CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f);
882 class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, gensym("dsp"), 0);
883}
884
885/* ------------------------------ ftom_tilde~ -------------------------- */
886
887typedef struct ftom_tilde
888{
889 t_object x_obj;
890 float x_f;
891} t_ftom_tilde;
892
893t_class *ftom_tilde_class;
894
895static void *ftom_tilde_new(void)
896{
897 t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class);
898 outlet_new(&x->x_obj, gensym("signal"));
899 x->x_f = 0;
900 return (x);
901}
902
903static t_int *ftom_tilde_perform(t_int *w)
904{
905 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
906 t_int n = *(t_int *)(w+3);
907 for (; n--; *in++, out++)
908 {
909 float f = *in;
910 *out = (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
911 }
912 return (w + 4);
913}
914
915static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp)
916{
917 dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
918}
919
920void ftom_tilde_setup(void)
921{
922 ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0,
923 sizeof(t_ftom_tilde), 0, 0);
924 CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f);
925 class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, gensym("dsp"), 0);
926}
927
928/* ------------------------------ dbtorms~ -------------------------- */
929
930typedef struct dbtorms_tilde
931{
932 t_object x_obj;
933 float x_f;
934} t_dbtorms_tilde;
935
936t_class *dbtorms_tilde_class;
937
938static void *dbtorms_tilde_new(void)
939{
940 t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class);
941 outlet_new(&x->x_obj, gensym("signal"));
942 x->x_f = 0;
943 return (x);
944}
945
946static t_int *dbtorms_tilde_perform(t_int *w)
947{
948 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
949 t_int n = *(t_int *)(w+3);
950 for (; n--; in++, out++)
951 {
952 float f = *in;
953 if (f <= 0) *out = 0;
954 else
955 {
956 if (f > 485)
957 f = 485;
958 *out = exp((LOGTEN * 0.05) * (f-100.));
959 }
960 }
961 return (w + 4);
962}
963
964static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp)
965{
966 dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
967}
968
969void dbtorms_tilde_setup(void)
970{
971 dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0,
972 sizeof(t_dbtorms_tilde), 0, 0);
973 CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f);
974 class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, gensym("dsp"), 0);
975}
976
977/* ------------------------------ rmstodb~ -------------------------- */
978
979typedef struct rmstodb_tilde
980{
981 t_object x_obj;
982 float x_f;
983} t_rmstodb_tilde;
984
985t_class *rmstodb_tilde_class;
986
987static void *rmstodb_tilde_new(void)
988{
989 t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class);
990 outlet_new(&x->x_obj, gensym("signal"));
991 x->x_f = 0;
992 return (x);
993}
994
995static t_int *rmstodb_tilde_perform(t_int *w)
996{
997 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
998 t_int n = *(t_int *)(w+3);
999 for (; n--; in++, out++)
1000 {
1001 float f = *in;
1002 if (f <= 0) *out = 0;
1003 else
1004 {
1005 float g = 100 + 20./LOGTEN * log(f);
1006 *out = (g < 0 ? 0 : g);
1007 }
1008 }
1009 return (w + 4);
1010}
1011
1012static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp)
1013{
1014 dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
1015}
1016
1017void rmstodb_tilde_setup(void)
1018{
1019 rmstodb_tilde_class = class_new(gensym("rmstodb~"), (t_newmethod)rmstodb_tilde_new, 0,
1020 sizeof(t_rmstodb_tilde), 0, 0);
1021 CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f);
1022 class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, gensym("dsp"), 0);
1023}
1024
1025/* ------------------------------ dbtopow~ -------------------------- */
1026
1027typedef struct dbtopow_tilde
1028{
1029 t_object x_obj;
1030 float x_f;
1031} t_dbtopow_tilde;
1032
1033t_class *dbtopow_tilde_class;
1034
1035static void *dbtopow_tilde_new(void)
1036{
1037 t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class);
1038 outlet_new(&x->x_obj, gensym("signal"));
1039 x->x_f = 0;
1040 return (x);
1041}
1042
1043static t_int *dbtopow_tilde_perform(t_int *w)
1044{
1045 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
1046 t_int n = *(t_int *)(w+3);
1047 for (; n--; in++, out++)
1048 {
1049 float f = *in;
1050 if (f <= 0) *out = 0;
1051 else
1052 {
1053 if (f > 870)
1054 f = 870;
1055 *out = exp((LOGTEN * 0.1) * (f-100.));
1056 }
1057 }
1058 return (w + 4);
1059}
1060
1061static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp)
1062{
1063 dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
1064}
1065
1066void dbtopow_tilde_setup(void)
1067{
1068 dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0,
1069 sizeof(t_dbtopow_tilde), 0, 0);
1070 CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f);
1071 class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, gensym("dsp"), 0);
1072}
1073
1074/* ------------------------------ powtodb~ -------------------------- */
1075
1076typedef struct powtodb_tilde
1077{
1078 t_object x_obj;
1079 float x_f;
1080} t_powtodb_tilde;
1081
1082t_class *powtodb_tilde_class;
1083
1084static void *powtodb_tilde_new(void)
1085{
1086 t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class);
1087 outlet_new(&x->x_obj, gensym("signal"));
1088 x->x_f = 0;
1089 return (x);
1090}
1091
1092static t_int *powtodb_tilde_perform(t_int *w)
1093{
1094 float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
1095 t_int n = *(t_int *)(w+3);
1096 for (; n--; in++, out++)
1097 {
1098 float f = *in;
1099 if (f <= 0) *out = 0;
1100 else
1101 {
1102 float g = 100 + 10./LOGTEN * log(f);
1103 *out = (g < 0 ? 0 : g);
1104 }
1105 }
1106 return (w + 4);
1107}
1108
1109static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp)
1110{
1111 dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
1112}
1113
1114void powtodb_tilde_setup(void)
1115{
1116 powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0,
1117 sizeof(t_powtodb_tilde), 0, 0);
1118 CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f);
1119 class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0);
1120}
1121
1122
1123/* ------------------------ global setup routine ------------------------- */
1124
1125void d_math_setup(void)
1126{
1127 t_symbol *s = gensym("acoustics~.pd");
1128 clip_setup();
1129 sigrsqrt_setup();
1130 sigsqrt_setup();
1131 sigwrap_setup();
1132 mtof_tilde_setup();
1133 ftom_tilde_setup();
1134 dbtorms_tilde_setup();
1135 rmstodb_tilde_setup();
1136 dbtopow_tilde_setup();
1137 powtodb_tilde_setup();
1138
1139 class_sethelpsymbol(mtof_tilde_class, s);
1140 class_sethelpsymbol(ftom_tilde_class, s);
1141 class_sethelpsymbol(dbtorms_tilde_class, s);
1142 class_sethelpsymbol(rmstodb_tilde_class, s);
1143 class_sethelpsymbol(dbtopow_tilde_class, s);
1144 class_sethelpsymbol(powtodb_tilde_class, s);
1145}
1146
diff --git a/apps/plugins/pdbox/PDa/src/d_mayer_fft.c b/apps/plugins/pdbox/PDa/src/d_mayer_fft.c
new file mode 100644
index 0000000000..7c29c6e7c8
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_mayer_fft.c
@@ -0,0 +1,838 @@
1/*
2** FFT and FHT routines
3** Copyright 1988, 1993; Ron Mayer
4**
5** mayer_fht(fz,n);
6** Does a hartley transform of "n" points in the array "fz".
7** mayer_fft(n,real,imag)
8** Does a fourier transform of "n" points of the "real" and
9** "imag" arrays.
10** mayer_ifft(n,real,imag)
11** Does an inverse fourier transform of "n" points of the "real"
12** and "imag" arrays.
13** mayer_realfft(n,real)
14** Does a real-valued fourier transform of "n" points of the
15** "real" array. The real part of the transform ends
16** up in the first half of the array and the imaginary part of the
17** transform ends up in the second half of the array.
18** mayer_realifft(n,real)
19** The inverse of the realfft() routine above.
20**
21**
22** NOTE: This routine uses at least 2 patented algorithms, and may be
23** under the restrictions of a bunch of different organizations.
24** Although I wrote it completely myself, it is kind of a derivative
25** of a routine I once authored and released under the GPL, so it
26** may fall under the free software foundation's restrictions;
27** it was worked on as a Stanford Univ project, so they claim
28** some rights to it; it was further optimized at work here, so
29** I think this company claims parts of it. The patents are
30** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
31** trig generator), both at Stanford Univ.
32** If it were up to me, I'd say go do whatever you want with it;
33** but it would be polite to give credit to the following people
34** if you use this anywhere:
35** Euler - probable inventor of the fourier transform.
36** Gauss - probable inventor of the FFT.
37** Hartley - probable inventor of the hartley transform.
38** Buneman - for a really cool trig generator
39** Mayer(me) - for authoring this particular version and
40** including all the optimizations in one package.
41** Thanks,
42** Ron Mayer; mayer@acuson.com
43**
44*/
45
46/* This is a slightly modified version of Mayer's contribution; write
47* msp@ucsd.edu for the original code. Kudos to Mayer for a fine piece
48* of work. -msp
49*/
50
51#ifdef MSW
52#pragma warning( disable : 4305 ) /* uncast const double to float */
53#pragma warning( disable : 4244 ) /* uncast double to float */
54#pragma warning( disable : 4101 ) /* unused local variables */
55#endif
56
57#define REAL float
58#define GOOD_TRIG
59
60#ifdef GOOD_TRIG
61#else
62#define FAST_TRIG
63#endif
64
65#if defined(GOOD_TRIG)
66#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
67#define TRIG_VARS \
68 int t_lam=0;
69#define TRIG_INIT(k,c,s) \
70 { \
71 int i; \
72 for (i=2 ; i<=k ; i++) \
73 {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
74 t_lam = 0; \
75 c = 1; \
76 s = 0; \
77 }
78#define TRIG_NEXT(k,c,s) \
79 { \
80 int i,j; \
81 (t_lam)++; \
82 for (i=0 ; !((1<<i)&t_lam) ; i++); \
83 i = k-i; \
84 s = sinwrk[i]; \
85 c = coswrk[i]; \
86 if (i>1) \
87 { \
88 for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
89 j = k - j; \
90 sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
91 coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
92 } \
93 }
94#define TRIG_RESET(k,c,s)
95#endif
96
97#if defined(FAST_TRIG)
98#define TRIG_VARS \
99 REAL t_c,t_s;
100#define TRIG_INIT(k,c,s) \
101 { \
102 t_c = costab[k]; \
103 t_s = sintab[k]; \
104 c = 1; \
105 s = 0; \
106 }
107#define TRIG_NEXT(k,c,s) \
108 { \
109 REAL t = c; \
110 c = t*t_c - s*t_s; \
111 s = t*t_s + s*t_c; \
112 }
113#define TRIG_RESET(k,c,s)
114#endif
115
116static REAL halsec[20]=
117 {
118 0,
119 0,
120 .54119610014619698439972320536638942006107206337801,
121 .50979557910415916894193980398784391368261849190893,
122 .50241928618815570551167011928012092247859337193963,
123 .50060299823519630134550410676638239611758632599591,
124 .50015063602065098821477101271097658495974913010340,
125 .50003765191554772296778139077905492847503165398345,
126 .50000941253588775676512870469186533538523133757983,
127 .50000235310628608051401267171204408939326297376426,
128 .50000058827484117879868526730916804925780637276181,
129 .50000014706860214875463798283871198206179118093251,
130 .50000003676714377807315864400643020315103490883972,
131 .50000000919178552207366560348853455333939112569380,
132 .50000000229794635411562887767906868558991922348920,
133 .50000000057448658687873302235147272458812263401372
134 };
135static REAL costab[20]=
136 {
137 .00000000000000000000000000000000000000000000000000,
138 .70710678118654752440084436210484903928483593768847,
139 .92387953251128675612818318939678828682241662586364,
140 .98078528040323044912618223613423903697393373089333,
141 .99518472667219688624483695310947992157547486872985,
142 .99879545620517239271477160475910069444320361470461,
143 .99969881869620422011576564966617219685006108125772,
144 .99992470183914454092164649119638322435060646880221,
145 .99998117528260114265699043772856771617391725094433,
146 .99999529380957617151158012570011989955298763362218,
147 .99999882345170190992902571017152601904826792288976,
148 .99999970586288221916022821773876567711626389934930,
149 .99999992646571785114473148070738785694820115568892,
150 .99999998161642929380834691540290971450507605124278,
151 .99999999540410731289097193313960614895889430318945,
152 .99999999885102682756267330779455410840053741619428
153 };
154static REAL sintab[20]=
155 {
156 1.0000000000000000000000000000000000000000000000000,
157 .70710678118654752440084436210484903928483593768846,
158 .38268343236508977172845998403039886676134456248561,
159 .19509032201612826784828486847702224092769161775195,
160 .09801714032956060199419556388864184586113667316749,
161 .04906767432741801425495497694268265831474536302574,
162 .02454122852291228803173452945928292506546611923944,
163 .01227153828571992607940826195100321214037231959176,
164 .00613588464915447535964023459037258091705788631738,
165 .00306795676296597627014536549091984251894461021344,
166 .00153398018628476561230369715026407907995486457522,
167 .00076699031874270452693856835794857664314091945205,
168 .00038349518757139558907246168118138126339502603495,
169 .00019174759731070330743990956198900093346887403385,
170 .00009587379909597734587051721097647635118706561284,
171 .00004793689960306688454900399049465887274686668768
172 };
173static REAL coswrk[20]=
174 {
175 .00000000000000000000000000000000000000000000000000,
176 .70710678118654752440084436210484903928483593768847,
177 .92387953251128675612818318939678828682241662586364,
178 .98078528040323044912618223613423903697393373089333,
179 .99518472667219688624483695310947992157547486872985,
180 .99879545620517239271477160475910069444320361470461,
181 .99969881869620422011576564966617219685006108125772,
182 .99992470183914454092164649119638322435060646880221,
183 .99998117528260114265699043772856771617391725094433,
184 .99999529380957617151158012570011989955298763362218,
185 .99999882345170190992902571017152601904826792288976,
186 .99999970586288221916022821773876567711626389934930,
187 .99999992646571785114473148070738785694820115568892,
188 .99999998161642929380834691540290971450507605124278,
189 .99999999540410731289097193313960614895889430318945,
190 .99999999885102682756267330779455410840053741619428
191 };
192static REAL sinwrk[20]=
193 {
194 1.0000000000000000000000000000000000000000000000000,
195 .70710678118654752440084436210484903928483593768846,
196 .38268343236508977172845998403039886676134456248561,
197 .19509032201612826784828486847702224092769161775195,
198 .09801714032956060199419556388864184586113667316749,
199 .04906767432741801425495497694268265831474536302574,
200 .02454122852291228803173452945928292506546611923944,
201 .01227153828571992607940826195100321214037231959176,
202 .00613588464915447535964023459037258091705788631738,
203 .00306795676296597627014536549091984251894461021344,
204 .00153398018628476561230369715026407907995486457522,
205 .00076699031874270452693856835794857664314091945205,
206 .00038349518757139558907246168118138126339502603495,
207 .00019174759731070330743990956198900093346887403385,
208 .00009587379909597734587051721097647635118706561284,
209 .00004793689960306688454900399049465887274686668768
210 };
211
212
213#define SQRT2_2 0.70710678118654752440084436210484
214#define SQRT2 2*0.70710678118654752440084436210484
215
216void mayer_fht(REAL *fz, int n)
217{
218/* REAL a,b;
219REAL c1,s1,s2,c2,s3,c3,s4,c4;
220 REAL f0,g0,f1,g1,f2,g2,f3,g3; */
221 int k,k1,k2,k3,k4,kx;
222 REAL *fi,*fn,*gi;
223 TRIG_VARS;
224
225 for (k1=1,k2=0;k1<n;k1++)
226 {
227 REAL aa;
228 for (k=n>>1; (!((k2^=k)&k)); k>>=1);
229 if (k1>k2)
230 {
231 aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
232 }
233 }
234 for ( k=0 ; (1<<k)<n ; k++ );
235 k &= 1;
236 if (k==0)
237 {
238 for (fi=fz,fn=fz+n;fi<fn;fi+=4)
239 {
240 REAL f0,f1,f2,f3;
241 f1 = fi[0 ]-fi[1 ];
242 f0 = fi[0 ]+fi[1 ];
243 f3 = fi[2 ]-fi[3 ];
244 f2 = fi[2 ]+fi[3 ];
245 fi[2 ] = (f0-f2);
246 fi[0 ] = (f0+f2);
247 fi[3 ] = (f1-f3);
248 fi[1 ] = (f1+f3);
249 }
250 }
251 else
252 {
253 for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
254 {
255 REAL bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
256 bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
257 bc1 = fi[0 ] - gi[0 ];
258 bs1 = fi[0 ] + gi[0 ];
259 bc2 = fi[2 ] - gi[2 ];
260 bs2 = fi[2 ] + gi[2 ];
261 bc3 = fi[4 ] - gi[4 ];
262 bs3 = fi[4 ] + gi[4 ];
263 bc4 = fi[6 ] - gi[6 ];
264 bs4 = fi[6 ] + gi[6 ];
265 bf1 = (bs1 - bs2);
266 bf0 = (bs1 + bs2);
267 bg1 = (bc1 - bc2);
268 bg0 = (bc1 + bc2);
269 bf3 = (bs3 - bs4);
270 bf2 = (bs3 + bs4);
271 bg3 = SQRT2*bc4;
272 bg2 = SQRT2*bc3;
273 fi[4 ] = bf0 - bf2;
274 fi[0 ] = bf0 + bf2;
275 fi[6 ] = bf1 - bf3;
276 fi[2 ] = bf1 + bf3;
277 gi[4 ] = bg0 - bg2;
278 gi[0 ] = bg0 + bg2;
279 gi[6 ] = bg1 - bg3;
280 gi[2 ] = bg1 + bg3;
281 }
282 }
283 if (n<16) return;
284
285 do
286 {
287 REAL s1,c1;
288 int ii;
289 k += 2;
290 k1 = 1 << k;
291 k2 = k1 << 1;
292 k4 = k2 << 1;
293 k3 = k2 + k1;
294 kx = k1 >> 1;
295 fi = fz;
296 gi = fi + kx;
297 fn = fz + n;
298 do
299 {
300 REAL g0,f0,f1,g1,f2,g2,f3,g3;
301 f1 = fi[0 ] - fi[k1];
302 f0 = fi[0 ] + fi[k1];
303 f3 = fi[k2] - fi[k3];
304 f2 = fi[k2] + fi[k3];
305 fi[k2] = f0 - f2;
306 fi[0 ] = f0 + f2;
307 fi[k3] = f1 - f3;
308 fi[k1] = f1 + f3;
309 g1 = gi[0 ] - gi[k1];
310 g0 = gi[0 ] + gi[k1];
311 g3 = SQRT2 * gi[k3];
312 g2 = SQRT2 * gi[k2];
313 gi[k2] = g0 - g2;
314 gi[0 ] = g0 + g2;
315 gi[k3] = g1 - g3;
316 gi[k1] = g1 + g3;
317 gi += k4;
318 fi += k4;
319 } while (fi<fn);
320 TRIG_INIT(k,c1,s1);
321 for (ii=1;ii<kx;ii++)
322 {
323 REAL c2,s2;
324 TRIG_NEXT(k,c1,s1);
325 c2 = c1*c1 - s1*s1;
326 s2 = 2*(c1*s1);
327 fn = fz + n;
328 fi = fz +ii;
329 gi = fz +k1-ii;
330 do
331 {
332 REAL a,b,g0,f0,f1,g1,f2,g2,f3,g3;
333 b = s2*fi[k1] - c2*gi[k1];
334 a = c2*fi[k1] + s2*gi[k1];
335 f1 = fi[0 ] - a;
336 f0 = fi[0 ] + a;
337 g1 = gi[0 ] - b;
338 g0 = gi[0 ] + b;
339 b = s2*fi[k3] - c2*gi[k3];
340 a = c2*fi[k3] + s2*gi[k3];
341 f3 = fi[k2] - a;
342 f2 = fi[k2] + a;
343 g3 = gi[k2] - b;
344 g2 = gi[k2] + b;
345 b = s1*f2 - c1*g3;
346 a = c1*f2 + s1*g3;
347 fi[k2] = f0 - a;
348 fi[0 ] = f0 + a;
349 gi[k3] = g1 - b;
350 gi[k1] = g1 + b;
351 b = c1*g2 - s1*f3;
352 a = s1*g2 + c1*f3;
353 gi[k2] = g0 - a;
354 gi[0 ] = g0 + a;
355 fi[k3] = f1 - b;
356 fi[k1] = f1 + b;
357 gi += k4;
358 fi += k4;
359 } while (fi<fn);
360 }
361 TRIG_RESET(k,c1,s1);
362 } while (k4<n);
363}
364
365void mayer_fft(int n, REAL *real, REAL *imag)
366{
367 REAL a,b,c,d;
368 REAL q,r,s,t;
369 int i,j,k;
370 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
371 a = real[i]; b = real[j]; q=a+b; r=a-b;
372 c = imag[i]; d = imag[j]; s=c+d; t=c-d;
373 real[i] = (q+t)*.5; real[j] = (q-t)*.5;
374 imag[i] = (s-r)*.5; imag[j] = (s+r)*.5;
375 }
376 mayer_fht(real,n);
377 mayer_fht(imag,n);
378}
379
380void mayer_ifft(int n, REAL *real, REAL *imag)
381{
382 REAL a,b,c,d;
383 REAL q,r,s,t;
384 int i,j,k;
385 mayer_fht(real,n);
386 mayer_fht(imag,n);
387 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
388 a = real[i]; b = real[j]; q=a+b; r=a-b;
389 c = imag[i]; d = imag[j]; s=c+d; t=c-d;
390 imag[i] = (s+r)*0.5; imag[j] = (s-r)*0.5;
391 real[i] = (q-t)*0.5; real[j] = (q+t)*0.5;
392 }
393}
394
395void mayer_realfft(int n, REAL *real)
396{
397 REAL a,b,c,d;
398 int i,j,k;
399 mayer_fht(real,n);
400 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
401 a = real[i];
402 b = real[j];
403 real[j] = (a-b)*0.5;
404 real[i] = (a+b)*0.5;
405 }
406}
407
408void mayer_realifft(int n, REAL *real)
409{
410 REAL a,b,c,d;
411 int i,j,k;
412 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
413 a = real[i];
414 b = real[j];
415 real[j] = (a-b);
416 real[i] = (a+b);
417 }
418 mayer_fht(real,n);
419}
420/*
421** FFT and FHT routines
422** Copyright 1988, 1993; Ron Mayer
423**
424** mayer_fht(fz,n);
425** Does a hartley transform of "n" points in the array "fz".
426** mayer_fft(n,real,imag)
427** Does a fourier transform of "n" points of the "real" and
428** "imag" arrays.
429** mayer_ifft(n,real,imag)
430** Does an inverse fourier transform of "n" points of the "real"
431** and "imag" arrays.
432** mayer_realfft(n,real)
433** Does a real-valued fourier transform of "n" points of the
434** "real" array. The real part of the transform ends
435** up in the first half of the array and the imaginary part of the
436** transform ends up in the second half of the array.
437** mayer_realifft(n,real)
438** The inverse of the realfft() routine above.
439**
440**
441** NOTE: This routine uses at least 2 patented algorithms, and may be
442** under the restrictions of a bunch of different organizations.
443** Although I wrote it completely myself, it is kind of a derivative
444** of a routine I once authored and released under the GPL, so it
445** may fall under the free software foundation's restrictions;
446** it was worked on as a Stanford Univ project, so they claim
447** some rights to it; it was further optimized at work here, so
448** I think this company claims parts of it. The patents are
449** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
450** trig generator), both at Stanford Univ.
451** If it were up to me, I'd say go do whatever you want with it;
452** but it would be polite to give credit to the following people
453** if you use this anywhere:
454** Euler - probable inventor of the fourier transform.
455** Gauss - probable inventor of the FFT.
456** Hartley - probable inventor of the hartley transform.
457** Buneman - for a really cool trig generator
458** Mayer(me) - for authoring this particular version and
459** including all the optimizations in one package.
460** Thanks,
461** Ron Mayer; mayer@acuson.com
462**
463*/
464
465/* This is a slightly modified version of Mayer's contribution; write
466* msp@ucsd.edu for the original code. Kudos to Mayer for a fine piece
467* of work. -msp
468*/
469
470#ifdef MSW
471#pragma warning( disable : 4305 ) /* uncast const double to float */
472#pragma warning( disable : 4244 ) /* uncast double to float */
473#pragma warning( disable : 4101 ) /* unused local variables */
474#endif
475
476#define REAL float
477#define GOOD_TRIG
478
479#ifdef GOOD_TRIG
480#else
481#define FAST_TRIG
482#endif
483
484#if defined(GOOD_TRIG)
485#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
486#define TRIG_VARS \
487 int t_lam=0;
488#define TRIG_INIT(k,c,s) \
489 { \
490 int i; \
491 for (i=2 ; i<=k ; i++) \
492 {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
493 t_lam = 0; \
494 c = 1; \
495 s = 0; \
496 }
497#define TRIG_NEXT(k,c,s) \
498 { \
499 int i,j; \
500 (t_lam)++; \
501 for (i=0 ; !((1<<i)&t_lam) ; i++); \
502 i = k-i; \
503 s = sinwrk[i]; \
504 c = coswrk[i]; \
505 if (i>1) \
506 { \
507 for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
508 j = k - j; \
509 sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
510 coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
511 } \
512 }
513#define TRIG_RESET(k,c,s)
514#endif
515
516#if defined(FAST_TRIG)
517#define TRIG_VARS \
518 REAL t_c,t_s;
519#define TRIG_INIT(k,c,s) \
520 { \
521 t_c = costab[k]; \
522 t_s = sintab[k]; \
523 c = 1; \
524 s = 0; \
525 }
526#define TRIG_NEXT(k,c,s) \
527 { \
528 REAL t = c; \
529 c = t*t_c - s*t_s; \
530 s = t*t_s + s*t_c; \
531 }
532#define TRIG_RESET(k,c,s)
533#endif
534
535static REAL halsec[20]=
536 {
537 0,
538 0,
539 .54119610014619698439972320536638942006107206337801,
540 .50979557910415916894193980398784391368261849190893,
541 .50241928618815570551167011928012092247859337193963,
542 .50060299823519630134550410676638239611758632599591,
543 .50015063602065098821477101271097658495974913010340,
544 .50003765191554772296778139077905492847503165398345,
545 .50000941253588775676512870469186533538523133757983,
546 .50000235310628608051401267171204408939326297376426,
547 .50000058827484117879868526730916804925780637276181,
548 .50000014706860214875463798283871198206179118093251,
549 .50000003676714377807315864400643020315103490883972,
550 .50000000919178552207366560348853455333939112569380,
551 .50000000229794635411562887767906868558991922348920,
552 .50000000057448658687873302235147272458812263401372
553 };
554static REAL costab[20]=
555 {
556 .00000000000000000000000000000000000000000000000000,
557 .70710678118654752440084436210484903928483593768847,
558 .92387953251128675612818318939678828682241662586364,
559 .98078528040323044912618223613423903697393373089333,
560 .99518472667219688624483695310947992157547486872985,
561 .99879545620517239271477160475910069444320361470461,
562 .99969881869620422011576564966617219685006108125772,
563 .99992470183914454092164649119638322435060646880221,
564 .99998117528260114265699043772856771617391725094433,
565 .99999529380957617151158012570011989955298763362218,
566 .99999882345170190992902571017152601904826792288976,
567 .99999970586288221916022821773876567711626389934930,
568 .99999992646571785114473148070738785694820115568892,
569 .99999998161642929380834691540290971450507605124278,
570 .99999999540410731289097193313960614895889430318945,
571 .99999999885102682756267330779455410840053741619428
572 };
573static REAL sintab[20]=
574 {
575 1.0000000000000000000000000000000000000000000000000,
576 .70710678118654752440084436210484903928483593768846,
577 .38268343236508977172845998403039886676134456248561,
578 .19509032201612826784828486847702224092769161775195,
579 .09801714032956060199419556388864184586113667316749,
580 .04906767432741801425495497694268265831474536302574,
581 .02454122852291228803173452945928292506546611923944,
582 .01227153828571992607940826195100321214037231959176,
583 .00613588464915447535964023459037258091705788631738,
584 .00306795676296597627014536549091984251894461021344,
585 .00153398018628476561230369715026407907995486457522,
586 .00076699031874270452693856835794857664314091945205,
587 .00038349518757139558907246168118138126339502603495,
588 .00019174759731070330743990956198900093346887403385,
589 .00009587379909597734587051721097647635118706561284,
590 .00004793689960306688454900399049465887274686668768
591 };
592static REAL coswrk[20]=
593 {
594 .00000000000000000000000000000000000000000000000000,
595 .70710678118654752440084436210484903928483593768847,
596 .92387953251128675612818318939678828682241662586364,
597 .98078528040323044912618223613423903697393373089333,
598 .99518472667219688624483695310947992157547486872985,
599 .99879545620517239271477160475910069444320361470461,
600 .99969881869620422011576564966617219685006108125772,
601 .99992470183914454092164649119638322435060646880221,
602 .99998117528260114265699043772856771617391725094433,
603 .99999529380957617151158012570011989955298763362218,
604 .99999882345170190992902571017152601904826792288976,
605 .99999970586288221916022821773876567711626389934930,
606 .99999992646571785114473148070738785694820115568892,
607 .99999998161642929380834691540290971450507605124278,
608 .99999999540410731289097193313960614895889430318945,
609 .99999999885102682756267330779455410840053741619428
610 };
611static REAL sinwrk[20]=
612 {
613 1.0000000000000000000000000000000000000000000000000,
614 .70710678118654752440084436210484903928483593768846,
615 .38268343236508977172845998403039886676134456248561,
616 .19509032201612826784828486847702224092769161775195,
617 .09801714032956060199419556388864184586113667316749,
618 .04906767432741801425495497694268265831474536302574,
619 .02454122852291228803173452945928292506546611923944,
620 .01227153828571992607940826195100321214037231959176,
621 .00613588464915447535964023459037258091705788631738,
622 .00306795676296597627014536549091984251894461021344,
623 .00153398018628476561230369715026407907995486457522,
624 .00076699031874270452693856835794857664314091945205,
625 .00038349518757139558907246168118138126339502603495,
626 .00019174759731070330743990956198900093346887403385,
627 .00009587379909597734587051721097647635118706561284,
628 .00004793689960306688454900399049465887274686668768
629 };
630
631
632#define SQRT2_2 0.70710678118654752440084436210484
633#define SQRT2 2*0.70710678118654752440084436210484
634
635void mayer_fht(REAL *fz, int n)
636{
637/* REAL a,b;
638REAL c1,s1,s2,c2,s3,c3,s4,c4;
639 REAL f0,g0,f1,g1,f2,g2,f3,g3; */
640 int k,k1,k2,k3,k4,kx;
641 REAL *fi,*fn,*gi;
642 TRIG_VARS;
643
644 for (k1=1,k2=0;k1<n;k1++)
645 {
646 REAL aa;
647 for (k=n>>1; (!((k2^=k)&k)); k>>=1);
648 if (k1>k2)
649 {
650 aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
651 }
652 }
653 for ( k=0 ; (1<<k)<n ; k++ );
654 k &= 1;
655 if (k==0)
656 {
657 for (fi=fz,fn=fz+n;fi<fn;fi+=4)
658 {
659 REAL f0,f1,f2,f3;
660 f1 = fi[0 ]-fi[1 ];
661 f0 = fi[0 ]+fi[1 ];
662 f3 = fi[2 ]-fi[3 ];
663 f2 = fi[2 ]+fi[3 ];
664 fi[2 ] = (f0-f2);
665 fi[0 ] = (f0+f2);
666 fi[3 ] = (f1-f3);
667 fi[1 ] = (f1+f3);
668 }
669 }
670 else
671 {
672 for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
673 {
674 REAL bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
675 bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
676 bc1 = fi[0 ] - gi[0 ];
677 bs1 = fi[0 ] + gi[0 ];
678 bc2 = fi[2 ] - gi[2 ];
679 bs2 = fi[2 ] + gi[2 ];
680 bc3 = fi[4 ] - gi[4 ];
681 bs3 = fi[4 ] + gi[4 ];
682 bc4 = fi[6 ] - gi[6 ];
683 bs4 = fi[6 ] + gi[6 ];
684 bf1 = (bs1 - bs2);
685 bf0 = (bs1 + bs2);
686 bg1 = (bc1 - bc2);
687 bg0 = (bc1 + bc2);
688 bf3 = (bs3 - bs4);
689 bf2 = (bs3 + bs4);
690 bg3 = SQRT2*bc4;
691 bg2 = SQRT2*bc3;
692 fi[4 ] = bf0 - bf2;
693 fi[0 ] = bf0 + bf2;
694 fi[6 ] = bf1 - bf3;
695 fi[2 ] = bf1 + bf3;
696 gi[4 ] = bg0 - bg2;
697 gi[0 ] = bg0 + bg2;
698 gi[6 ] = bg1 - bg3;
699 gi[2 ] = bg1 + bg3;
700 }
701 }
702 if (n<16) return;
703
704 do
705 {
706 REAL s1,c1;
707 int ii;
708 k += 2;
709 k1 = 1 << k;
710 k2 = k1 << 1;
711 k4 = k2 << 1;
712 k3 = k2 + k1;
713 kx = k1 >> 1;
714 fi = fz;
715 gi = fi + kx;
716 fn = fz + n;
717 do
718 {
719 REAL g0,f0,f1,g1,f2,g2,f3,g3;
720 f1 = fi[0 ] - fi[k1];
721 f0 = fi[0 ] + fi[k1];
722 f3 = fi[k2] - fi[k3];
723 f2 = fi[k2] + fi[k3];
724 fi[k2] = f0 - f2;
725 fi[0 ] = f0 + f2;
726 fi[k3] = f1 - f3;
727 fi[k1] = f1 + f3;
728 g1 = gi[0 ] - gi[k1];
729 g0 = gi[0 ] + gi[k1];
730 g3 = SQRT2 * gi[k3];
731 g2 = SQRT2 * gi[k2];
732 gi[k2] = g0 - g2;
733 gi[0 ] = g0 + g2;
734 gi[k3] = g1 - g3;
735 gi[k1] = g1 + g3;
736 gi += k4;
737 fi += k4;
738 } while (fi<fn);
739 TRIG_INIT(k,c1,s1);
740 for (ii=1;ii<kx;ii++)
741 {
742 REAL c2,s2;
743 TRIG_NEXT(k,c1,s1);
744 c2 = c1*c1 - s1*s1;
745 s2 = 2*(c1*s1);
746 fn = fz + n;
747 fi = fz +ii;
748 gi = fz +k1-ii;
749 do
750 {
751 REAL a,b,g0,f0,f1,g1,f2,g2,f3,g3;
752 b = s2*fi[k1] - c2*gi[k1];
753 a = c2*fi[k1] + s2*gi[k1];
754 f1 = fi[0 ] - a;
755 f0 = fi[0 ] + a;
756 g1 = gi[0 ] - b;
757 g0 = gi[0 ] + b;
758 b = s2*fi[k3] - c2*gi[k3];
759 a = c2*fi[k3] + s2*gi[k3];
760 f3 = fi[k2] - a;
761 f2 = fi[k2] + a;
762 g3 = gi[k2] - b;
763 g2 = gi[k2] + b;
764 b = s1*f2 - c1*g3;
765 a = c1*f2 + s1*g3;
766 fi[k2] = f0 - a;
767 fi[0 ] = f0 + a;
768 gi[k3] = g1 - b;
769 gi[k1] = g1 + b;
770 b = c1*g2 - s1*f3;
771 a = s1*g2 + c1*f3;
772 gi[k2] = g0 - a;
773 gi[0 ] = g0 + a;
774 fi[k3] = f1 - b;
775 fi[k1] = f1 + b;
776 gi += k4;
777 fi += k4;
778 } while (fi<fn);
779 }
780 TRIG_RESET(k,c1,s1);
781 } while (k4<n);
782}
783
784void mayer_fft(int n, REAL *real, REAL *imag)
785{
786 REAL a,b,c,d;
787 REAL q,r,s,t;
788 int i,j,k;
789 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
790 a = real[i]; b = real[j]; q=a+b; r=a-b;
791 c = imag[i]; d = imag[j]; s=c+d; t=c-d;
792 real[i] = (q+t)*.5; real[j] = (q-t)*.5;
793 imag[i] = (s-r)*.5; imag[j] = (s+r)*.5;
794 }
795 mayer_fht(real,n);
796 mayer_fht(imag,n);
797}
798
799void mayer_ifft(int n, REAL *real, REAL *imag)
800{
801 REAL a,b,c,d;
802 REAL q,r,s,t;
803 int i,j,k;
804 mayer_fht(real,n);
805 mayer_fht(imag,n);
806 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
807 a = real[i]; b = real[j]; q=a+b; r=a-b;
808 c = imag[i]; d = imag[j]; s=c+d; t=c-d;
809 imag[i] = (s+r)*0.5; imag[j] = (s-r)*0.5;
810 real[i] = (q-t)*0.5; real[j] = (q+t)*0.5;
811 }
812}
813
814void mayer_realfft(int n, REAL *real)
815{
816 REAL a,b,c,d;
817 int i,j,k;
818 mayer_fht(real,n);
819 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
820 a = real[i];
821 b = real[j];
822 real[j] = (a-b)*0.5;
823 real[i] = (a+b)*0.5;
824 }
825}
826
827void mayer_realifft(int n, REAL *real)
828{
829 REAL a,b,c,d;
830 int i,j,k;
831 for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
832 a = real[i];
833 b = real[j];
834 real[j] = (a-b);
835 real[i] = (a+b);
836 }
837 mayer_fht(real,n);
838}
diff --git a/apps/plugins/pdbox/PDa/src/d_misc.c b/apps/plugins/pdbox/PDa/src/d_misc.c
new file mode 100644
index 0000000000..f601d66d90
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_misc.c
@@ -0,0 +1,524 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* miscellaneous: print~; more to come.
6*/
7
8#include "m_pd.h"
9#include <stdio.h>
10#include <string.h>
11
12/* ------------------------- print~ -------------------------- */
13static t_class *print_class;
14
15typedef struct _print
16{
17 t_object x_obj;
18 float x_f;
19 t_symbol *x_sym;
20 int x_count;
21} t_print;
22
23static t_int *print_perform(t_int *w)
24{
25 t_print *x = (t_print *)(w[1]);
26 t_float *in = (t_float *)(w[2]);
27 int n = (int)(w[3]);
28 if (x->x_count)
29 {
30 post("%s:", x->x_sym->s_name);
31 if (n == 1) post("%8g", in[0]);
32 else if (n == 2) post("%8g %8g", in[0], in[1]);
33 else if (n == 4) post("%8g %8g %8g %8g",
34 in[0], in[1], in[2], in[3]);
35 else while (n > 0)
36 {
37 post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
38 in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
39 n -= 8;
40 in += 8;
41 }
42 x->x_count--;
43 }
44 return (w+4);
45}
46
47static void print_dsp(t_print *x, t_signal **sp)
48{
49 dsp_add(print_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
50}
51
52static void print_float(t_print *x, t_float f)
53{
54 if (f < 0) f = 0;
55 x->x_count = f;
56}
57
58static void print_bang(t_print *x)
59{
60 x->x_count = 1;
61}
62
63static void *print_new(t_symbol *s)
64{
65 t_print *x = (t_print *)pd_new(print_class);
66 x->x_sym = (s->s_name[0]? s : gensym("print~"));
67 x->x_count = 0;
68 x->x_f = 0;
69 return (x);
70}
71
72static void print_setup(void)
73{
74 print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0,
75 sizeof(t_print), 0, A_DEFSYM, 0);
76 CLASS_MAINSIGNALIN(print_class, t_print, x_f);
77 class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), 0);
78 class_addbang(print_class, print_bang);
79 class_addfloat(print_class, print_float);
80}
81
82/* ------------------------- scope~ -------------------------- */
83/* this has been replaced by arrays; to be deleted later */
84
85#include "g_canvas.h"
86
87static t_class *scope_class;
88
89#define SCOPESIZE 256
90
91typedef struct _scope
92{
93 t_object x_obj;
94 t_sample x_samps[SCOPESIZE];
95 int x_phase;
96 int x_drawn;
97 void *x_canvas;
98} t_scope;
99
100static t_int *scope_perform(t_int *w)
101{
102 t_scope *x = (t_scope *)(w[1]);
103 t_float *in = (t_float *)(w[2]);
104 int n = (int)(w[3]), phase = x->x_phase;
105 while (n--)
106 {
107 x->x_samps[phase] = *in++;
108 phase = (phase + 1) & (SCOPESIZE-1);
109 }
110 x->x_phase = phase;
111 return (w+4);
112}
113
114static void scope_dsp(t_scope *x, t_signal **sp)
115{
116 dsp_add(scope_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
117}
118
119static void scope_erase(t_scope *x)
120{
121 if (x->x_drawn) sys_vgui(".x%x.c delete gumbo\n", x->x_canvas);
122}
123
124#define X1 10.
125#define X2 20.
126#define YC 5.
127static void scope_bang(t_scope *x)
128{
129 int n, phase;
130 char hugebuf[10000], *s = hugebuf;
131 scope_erase(x);
132 sys_vgui(".x%x.c create line 10c 5c 20c 5c -tags gumbo\n", x->x_canvas);
133 sprintf(s, ".x%x.c create line ", (t_int)x->x_canvas);
134 s += strlen(s);
135 for (n = 0, phase = x->x_phase;
136 n < SCOPESIZE; phase = ((phase+1) & (SCOPESIZE-1)), n++)
137 {
138 sprintf(s, "%fc %fc ", X1 + (X2 - X1) * (float)n * (1./SCOPESIZE),
139 YC - 5 * x->x_samps[phase]);
140 s += strlen(s);
141 /* post("phase %d", phase); */
142 }
143 sprintf(s, "-tags gumbo\n");
144 sys_gui(hugebuf);
145 x->x_drawn = 1;
146}
147
148static void scope_free(t_scope *x)
149{
150 scope_erase(x);
151}
152
153static void *scope_new(t_symbol *s)
154{
155 t_scope *x = (t_scope *)pd_new(scope_class);
156 error("scope: this is now obsolete; use arrays and tabwrite~ instead");
157 x->x_phase = 0;
158 x->x_drawn = 0;
159 x->x_canvas = canvas_getcurrent();
160 return (x);
161}
162
163static void scope_setup(void)
164{
165 scope_class = class_new(gensym("scope~"), (t_newmethod)scope_new,
166 (t_method)scope_free, sizeof(t_scope), 0, A_DEFSYM, 0);
167 class_addmethod(scope_class, nullfn, gensym("signal"), 0);
168 class_addmethod(scope_class, (t_method)scope_dsp, gensym("dsp"), 0);
169 class_addbang(scope_class, scope_bang);
170}
171
172/* ------------------------ bang~ -------------------------- */
173
174static t_class *bang_tilde_class;
175
176typedef struct _bang
177{
178 t_object x_obj;
179 t_clock *x_clock;
180} t_bang;
181
182static t_int *bang_tilde_perform(t_int *w)
183{
184 t_bang *x = (t_bang *)(w[1]);
185 clock_delay(x->x_clock, 0);
186 return (w+2);
187}
188
189static void bang_tilde_dsp(t_bang *x, t_signal **sp)
190{
191 dsp_add(bang_tilde_perform, 1, x);
192}
193
194static void bang_tilde_tick(t_bang *x)
195{
196 outlet_bang(x->x_obj.ob_outlet);
197}
198
199static void bang_tilde_free(t_bang *x)
200{
201 clock_free(x->x_clock);
202}
203
204static void *bang_tilde_new(t_symbol *s)
205{
206 t_bang *x = (t_bang *)pd_new(bang_tilde_class);
207 x->x_clock = clock_new(x, (t_method)bang_tilde_tick);
208 outlet_new(&x->x_obj, &s_bang);
209 return (x);
210}
211
212static void bang_tilde_setup(void)
213{
214 bang_tilde_class = class_new(gensym("bang~"), (t_newmethod)bang_tilde_new,
215 (t_method)bang_tilde_free, sizeof(t_bang), 0, 0);
216 class_addmethod(bang_tilde_class, (t_method)bang_tilde_dsp,
217 gensym("dsp"), 0);
218}
219
220/* ------------------------ samplerate~~ -------------------------- */
221
222static t_class *samplerate_tilde_class;
223
224typedef struct _samplerate
225{
226 t_object x_obj;
227} t_samplerate;
228
229static void samplerate_tilde_bang(t_samplerate *x)
230{
231 outlet_float(x->x_obj.ob_outlet, sys_getsr());
232}
233
234static void *samplerate_tilde_new(t_symbol *s)
235{
236 t_samplerate *x = (t_samplerate *)pd_new(samplerate_tilde_class);
237 outlet_new(&x->x_obj, &s_float);
238 return (x);
239}
240
241static void samplerate_tilde_setup(void)
242{
243 samplerate_tilde_class = class_new(gensym("samplerate~"),
244 (t_newmethod)samplerate_tilde_new, 0, sizeof(t_samplerate), 0, 0);
245 class_addbang(samplerate_tilde_class, samplerate_tilde_bang);
246}
247
248/* ------------------------ global setup routine ------------------------- */
249
250void d_misc_setup(void)
251{
252#ifndef FIXEDPOINT
253 print_setup();
254#endif
255 scope_setup();
256 bang_tilde_setup();
257 samplerate_tilde_setup();
258}
259
260
261
262
263/* Copyright (c) 1997-1999 Miller Puckette.
264* For information on usage and redistribution, and for a DISCLAIMER OF ALL
265* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
266
267/* miscellaneous: print~; more to come.
268*/
269
270#include "m_pd.h"
271#include <stdio.h>
272#include <string.h>
273
274/* ------------------------- print~ -------------------------- */
275static t_class *print_class;
276
277typedef struct _print
278{
279 t_object x_obj;
280 float x_f;
281 t_symbol *x_sym;
282 int x_count;
283} t_print;
284
285static t_int *print_perform(t_int *w)
286{
287 t_print *x = (t_print *)(w[1]);
288 t_float *in = (t_float *)(w[2]);
289 int n = (int)(w[3]);
290 if (x->x_count)
291 {
292 post("%s:", x->x_sym->s_name);
293 if (n == 1) post("%8g", in[0]);
294 else if (n == 2) post("%8g %8g", in[0], in[1]);
295 else if (n == 4) post("%8g %8g %8g %8g",
296 in[0], in[1], in[2], in[3]);
297 else while (n > 0)
298 {
299 post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
300 in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
301 n -= 8;
302 in += 8;
303 }
304 x->x_count--;
305 }
306 return (w+4);
307}
308
309static void print_dsp(t_print *x, t_signal **sp)
310{
311 dsp_add(print_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
312}
313
314static void print_float(t_print *x, t_float f)
315{
316 if (f < 0) f = 0;
317 x->x_count = f;
318}
319
320static void print_bang(t_print *x)
321{
322 x->x_count = 1;
323}
324
325static void *print_new(t_symbol *s)
326{
327 t_print *x = (t_print *)pd_new(print_class);
328 x->x_sym = (s->s_name[0]? s : gensym("print~"));
329 x->x_count = 0;
330 x->x_f = 0;
331 return (x);
332}
333
334static void print_setup(void)
335{
336 print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0,
337 sizeof(t_print), 0, A_DEFSYM, 0);
338 CLASS_MAINSIGNALIN(print_class, t_print, x_f);
339 class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), 0);
340 class_addbang(print_class, print_bang);
341 class_addfloat(print_class, print_float);
342}
343
344/* ------------------------- scope~ -------------------------- */
345/* this has been replaced by arrays; to be deleted later */
346
347#include "g_canvas.h"
348
349static t_class *scope_class;
350
351#define SCOPESIZE 256
352
353typedef struct _scope
354{
355 t_object x_obj;
356 t_sample x_samps[SCOPESIZE];
357 int x_phase;
358 int x_drawn;
359 void *x_canvas;
360} t_scope;
361
362static t_int *scope_perform(t_int *w)
363{
364 t_scope *x = (t_scope *)(w[1]);
365 t_float *in = (t_float *)(w[2]);
366 int n = (int)(w[3]), phase = x->x_phase;
367 while (n--)
368 {
369 x->x_samps[phase] = *in++;
370 phase = (phase + 1) & (SCOPESIZE-1);
371 }
372 x->x_phase = phase;
373 return (w+4);
374}
375
376static void scope_dsp(t_scope *x, t_signal **sp)
377{
378 dsp_add(scope_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
379}
380
381static void scope_erase(t_scope *x)
382{
383 if (x->x_drawn) sys_vgui(".x%x.c delete gumbo\n", x->x_canvas);
384}
385
386#define X1 10.
387#define X2 20.
388#define YC 5.
389static void scope_bang(t_scope *x)
390{
391 int n, phase;
392 char hugebuf[10000], *s = hugebuf;
393 scope_erase(x);
394 sys_vgui(".x%x.c create line 10c 5c 20c 5c -tags gumbo\n", x->x_canvas);
395 sprintf(s, ".x%x.c create line ", (t_int)x->x_canvas);
396 s += strlen(s);
397 for (n = 0, phase = x->x_phase;
398 n < SCOPESIZE; phase = ((phase+1) & (SCOPESIZE-1)), n++)
399 {
400 sprintf(s, "%fc %fc ", X1 + (X2 - X1) * (float)n * (1./SCOPESIZE),
401 YC - 5 * x->x_samps[phase]);
402 s += strlen(s);
403 /* post("phase %d", phase); */
404 }
405 sprintf(s, "-tags gumbo\n");
406 sys_gui(hugebuf);
407 x->x_drawn = 1;
408}
409
410static void scope_free(t_scope *x)
411{
412 scope_erase(x);
413}
414
415static void *scope_new(t_symbol *s)
416{
417 t_scope *x = (t_scope *)pd_new(scope_class);
418 error("scope: this is now obsolete; use arrays and tabwrite~ instead");
419 x->x_phase = 0;
420 x->x_drawn = 0;
421 x->x_canvas = canvas_getcurrent();
422 return (x);
423}
424
425static void scope_setup(void)
426{
427 scope_class = class_new(gensym("scope~"), (t_newmethod)scope_new,
428 (t_method)scope_free, sizeof(t_scope), 0, A_DEFSYM, 0);
429 class_addmethod(scope_class, nullfn, gensym("signal"), 0);
430 class_addmethod(scope_class, (t_method)scope_dsp, gensym("dsp"), 0);
431 class_addbang(scope_class, scope_bang);
432}
433
434/* ------------------------ bang~ -------------------------- */
435
436static t_class *bang_tilde_class;
437
438typedef struct _bang
439{
440 t_object x_obj;
441 t_clock *x_clock;
442} t_bang;
443
444static t_int *bang_tilde_perform(t_int *w)
445{
446 t_bang *x = (t_bang *)(w[1]);
447 clock_delay(x->x_clock, 0);
448 return (w+2);
449}
450
451static void bang_tilde_dsp(t_bang *x, t_signal **sp)
452{
453 dsp_add(bang_tilde_perform, 1, x);
454}
455
456static void bang_tilde_tick(t_bang *x)
457{
458 outlet_bang(x->x_obj.ob_outlet);
459}
460
461static void bang_tilde_free(t_bang *x)
462{
463 clock_free(x->x_clock);
464}
465
466static void *bang_tilde_new(t_symbol *s)
467{
468 t_bang *x = (t_bang *)pd_new(bang_tilde_class);
469 x->x_clock = clock_new(x, (t_method)bang_tilde_tick);
470 outlet_new(&x->x_obj, &s_bang);
471 return (x);
472}
473
474static void bang_tilde_setup(void)
475{
476 bang_tilde_class = class_new(gensym("bang~"), (t_newmethod)bang_tilde_new,
477 (t_method)bang_tilde_free, sizeof(t_bang), 0, 0);
478 class_addmethod(bang_tilde_class, (t_method)bang_tilde_dsp,
479 gensym("dsp"), 0);
480}
481
482/* ------------------------ samplerate~~ -------------------------- */
483
484static t_class *samplerate_tilde_class;
485
486typedef struct _samplerate
487{
488 t_object x_obj;
489} t_samplerate;
490
491static void samplerate_tilde_bang(t_samplerate *x)
492{
493 outlet_float(x->x_obj.ob_outlet, sys_getsr());
494}
495
496static void *samplerate_tilde_new(t_symbol *s)
497{
498 t_samplerate *x = (t_samplerate *)pd_new(samplerate_tilde_class);
499 outlet_new(&x->x_obj, &s_float);
500 return (x);
501}
502
503static void samplerate_tilde_setup(void)
504{
505 samplerate_tilde_class = class_new(gensym("samplerate~"),
506 (t_newmethod)samplerate_tilde_new, 0, sizeof(t_samplerate), 0, 0);
507 class_addbang(samplerate_tilde_class, samplerate_tilde_bang);
508}
509
510/* ------------------------ global setup routine ------------------------- */
511
512void d_misc_setup(void)
513{
514#ifndef FIXEDPOINT
515 print_setup();
516#endif
517 scope_setup();
518 bang_tilde_setup();
519 samplerate_tilde_setup();
520}
521
522
523
524
diff --git a/apps/plugins/pdbox/PDa/src/d_osc.c b/apps/plugins/pdbox/PDa/src/d_osc.c
new file mode 100644
index 0000000000..8a3486d981
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_osc.c
@@ -0,0 +1,1070 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c.
6*/
7
8#include "m_pd.h"
9#include "math.h"
10
11#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
12
13 /* machine-dependent definitions. These ifdefs really
14 should have been by CPU type and not by operating system! */
15#ifdef IRIX
16 /* big-endian. Most significant byte is at low address in memory */
17#define HIOFFSET 0 /* word offset to find MSB */
18#define LOWOFFSET 1 /* word offset to find LSB */
19#define int32 long /* a data type that has 32 bits */
20#else
21#ifdef MSW
22 /* little-endian; most significant byte is at highest address */
23#define HIOFFSET 1
24#define LOWOFFSET 0
25#define int32 long
26#else
27#ifdef __FreeBSD__
28#include <machine/endian.h>
29#if BYTE_ORDER == LITTLE_ENDIAN
30#define HIOFFSET 1
31#define LOWOFFSET 0
32#else
33#define HIOFFSET 0 /* word offset to find MSB */
34#define LOWOFFSET 1 /* word offset to find LSB */
35#endif /* BYTE_ORDER */
36#include <sys/types.h>
37#define int32 int32_t
38#endif
39#ifdef __linux__
40
41#include <endian.h>
42
43#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
44#error No byte order defined
45#endif
46
47#if __BYTE_ORDER == __LITTLE_ENDIAN
48#define HIOFFSET 1
49#define LOWOFFSET 0
50#else
51#define HIOFFSET 0 /* word offset to find MSB */
52#define LOWOFFSET 1 /* word offset to find LSB */
53#endif /* __BYTE_ORDER */
54
55#include <sys/types.h>
56#define int32 int32_t
57
58#else
59#ifdef MACOSX
60#define HIOFFSET 0 /* word offset to find MSB */
61#define LOWOFFSET 1 /* word offset to find LSB */
62#define int32 int /* a data type that has 32 bits */
63
64#endif /* MACOSX */
65#endif /* __linux__ */
66#endif /* MSW */
67#endif /* SGI */
68
69union tabfudge
70{
71 double tf_d;
72 int32 tf_i[2];
73};
74
75
76/* -------------------------- phasor~ ------------------------------ */
77static t_class *phasor_class, *scalarphasor_class;
78
79#if 1 /* in the style of R. Hoeldrich (ICMC 1995 Banff) */
80
81typedef struct _phasor
82{
83 t_object x_obj;
84 double x_phase;
85 float x_conv;
86 float x_f; /* scalar frequency */
87} t_phasor;
88
89static void *phasor_new(t_floatarg f)
90{
91 t_phasor *x = (t_phasor *)pd_new(phasor_class);
92 x->x_f = f;
93 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
94 x->x_phase = 0;
95 x->x_conv = 0;
96 outlet_new(&x->x_obj, gensym("signal"));
97 return (x);
98}
99
100static t_int *phasor_perform(t_int *w)
101{
102 t_phasor *x = (t_phasor *)(w[1]);
103 t_float *in = (t_float *)(w[2]);
104 t_float *out = (t_float *)(w[3]);
105 int n = (int)(w[4]);
106 double dphase = x->x_phase + UNITBIT32;
107 union tabfudge tf;
108 int normhipart;
109 float conv = x->x_conv;
110
111 tf.tf_d = UNITBIT32;
112 normhipart = tf.tf_i[HIOFFSET];
113 tf.tf_d = dphase;
114
115 while (n--)
116 {
117 tf.tf_i[HIOFFSET] = normhipart;
118 dphase += *in++ * conv;
119 *out++ = tf.tf_d - UNITBIT32;
120 tf.tf_d = dphase;
121 }
122 tf.tf_i[HIOFFSET] = normhipart;
123 x->x_phase = tf.tf_d - UNITBIT32;
124 return (w+5);
125}
126
127static void phasor_dsp(t_phasor *x, t_signal **sp)
128{
129 x->x_conv = 1./sp[0]->s_sr;
130 dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
131}
132
133static void phasor_ft1(t_phasor *x, t_float f)
134{
135 x->x_phase = f;
136}
137
138static void phasor_setup(void)
139{
140 phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
141 sizeof(t_phasor), 0, A_DEFFLOAT, 0);
142 CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
143 class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
144 class_addmethod(phasor_class, (t_method)phasor_ft1,
145 gensym("ft1"), A_FLOAT, 0);
146}
147
148#endif /* Hoeldrich version */
149
150/* ------------------------ cos~ ----------------------------- */
151
152float *cos_table;
153
154static t_class *cos_class;
155
156typedef struct _cos
157{
158 t_object x_obj;
159 float x_f;
160} t_cos;
161
162static void *cos_new(void)
163{
164 t_cos *x = (t_cos *)pd_new(cos_class);
165 outlet_new(&x->x_obj, gensym("signal"));
166 x->x_f = 0;
167 return (x);
168}
169
170static t_int *cos_perform(t_int *w)
171{
172 t_float *in = (t_float *)(w[1]);
173 t_float *out = (t_float *)(w[2]);
174 int n = (int)(w[3]);
175 float *tab = cos_table, *addr, f1, f2, frac;
176 double dphase;
177 int normhipart;
178 union tabfudge tf;
179
180 tf.tf_d = UNITBIT32;
181 normhipart = tf.tf_i[HIOFFSET];
182
183#if 0 /* this is the readable version of the code. */
184 while (n--)
185 {
186 dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
187 tf.tf_d = dphase;
188 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
189 tf.tf_i[HIOFFSET] = normhipart;
190 frac = tf.tf_d - UNITBIT32;
191 f1 = addr[0];
192 f2 = addr[1];
193 *out++ = f1 + frac * (f2 - f1);
194 }
195#endif
196#if 1 /* this is the same, unwrapped by hand. */
197 dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
198 tf.tf_d = dphase;
199 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
200 tf.tf_i[HIOFFSET] = normhipart;
201 while (--n)
202 {
203 dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
204 frac = tf.tf_d - UNITBIT32;
205 tf.tf_d = dphase;
206 f1 = addr[0];
207 f2 = addr[1];
208 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
209 *out++ = f1 + frac * (f2 - f1);
210 tf.tf_i[HIOFFSET] = normhipart;
211 }
212 frac = tf.tf_d - UNITBIT32;
213 f1 = addr[0];
214 f2 = addr[1];
215 *out++ = f1 + frac * (f2 - f1);
216#endif
217 return (w+4);
218}
219
220static void cos_dsp(t_cos *x, t_signal **sp)
221{
222 dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
223}
224
225static void cos_maketable(void)
226{
227 int i;
228 float *fp, phase, phsinc = (2. * 3.14159) / COSTABSIZE;
229 union tabfudge tf;
230
231 if (cos_table) return;
232 cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
233 for (i = COSTABSIZE + 1, fp = cos_table, phase = 0; i--;
234 fp++, phase += phsinc)
235 *fp = cos(phase);
236
237 /* here we check at startup whether the byte alignment
238 is as we declared it. If not, the code has to be
239 recompiled the other way. */
240 tf.tf_d = UNITBIT32 + 0.5;
241 if ((unsigned)tf.tf_i[LOWOFFSET] != 0x80000000)
242 bug("cos~: unexpected machine alignment");
243}
244
245static void cos_setup(void)
246{
247 cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
248 sizeof(t_cos), 0, A_DEFFLOAT, 0);
249 CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
250 class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
251 cos_maketable();
252}
253
254/* ------------------------ osc~ ----------------------------- */
255
256static t_class *osc_class, *scalarosc_class;
257
258typedef struct _osc
259{
260 t_object x_obj;
261 double x_phase;
262 float x_conv;
263 float x_f; /* frequency if scalar */
264} t_osc;
265
266static void *osc_new(t_floatarg f)
267{
268 t_osc *x = (t_osc *)pd_new(osc_class);
269 x->x_f = f;
270 outlet_new(&x->x_obj, gensym("signal"));
271 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
272 x->x_phase = 0;
273 x->x_conv = 0;
274 return (x);
275}
276
277static t_int *osc_perform(t_int *w)
278{
279 t_osc *x = (t_osc *)(w[1]);
280 t_float *in = (t_float *)(w[2]);
281 t_float *out = (t_float *)(w[3]);
282 int n = (int)(w[4]);
283 float *tab = cos_table, *addr, f1, f2, frac;
284 double dphase = x->x_phase + UNITBIT32;
285 int normhipart;
286 union tabfudge tf;
287 float conv = x->x_conv;
288
289 tf.tf_d = UNITBIT32;
290 normhipart = tf.tf_i[HIOFFSET];
291#if 0
292 while (n--)
293 {
294 tf.tf_d = dphase;
295 dphase += *in++ * conv;
296 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
297 tf.tf_i[HIOFFSET] = normhipart;
298 frac = tf.tf_d - UNITBIT32;
299 f1 = addr[0];
300 f2 = addr[1];
301 *out++ = f1 + frac * (f2 - f1);
302 }
303#endif
304#if 1
305 tf.tf_d = dphase;
306 dphase += *in++ * conv;
307 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
308 tf.tf_i[HIOFFSET] = normhipart;
309 frac = tf.tf_d - UNITBIT32;
310 while (--n)
311 {
312 tf.tf_d = dphase;
313 f1 = addr[0];
314 dphase += *in++ * conv;
315 f2 = addr[1];
316 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
317 tf.tf_i[HIOFFSET] = normhipart;
318 *out++ = f1 + frac * (f2 - f1);
319 frac = tf.tf_d - UNITBIT32;
320 }
321 f1 = addr[0];
322 f2 = addr[1];
323 *out++ = f1 + frac * (f2 - f1);
324#endif
325
326 tf.tf_d = UNITBIT32 * COSTABSIZE;
327 normhipart = tf.tf_i[HIOFFSET];
328 tf.tf_d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
329 tf.tf_i[HIOFFSET] = normhipart;
330 x->x_phase = tf.tf_d - UNITBIT32 * COSTABSIZE;
331 return (w+5);
332}
333
334static void osc_dsp(t_osc *x, t_signal **sp)
335{
336 x->x_conv = COSTABSIZE/sp[0]->s_sr;
337 dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
338}
339
340static void osc_ft1(t_osc *x, t_float f)
341{
342 x->x_phase = COSTABSIZE * f;
343}
344
345static void osc_setup(void)
346{
347 osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
348 sizeof(t_osc), 0, A_DEFFLOAT, 0);
349 CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
350 class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
351 class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
352
353 cos_maketable();
354}
355
356/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
357
358typedef struct vcfctl
359{
360 float c_re;
361 float c_im;
362 float c_q;
363 float c_isr;
364} t_vcfctl;
365
366typedef struct sigvcf
367{
368 t_object x_obj;
369 t_vcfctl x_cspace;
370 t_vcfctl *x_ctl;
371 float x_f;
372} t_sigvcf;
373
374t_class *sigvcf_class;
375
376static void *sigvcf_new(t_floatarg q)
377{
378 t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
379 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
380 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
381 outlet_new(&x->x_obj, gensym("signal"));
382 outlet_new(&x->x_obj, gensym("signal"));
383 x->x_ctl = &x->x_cspace;
384 x->x_cspace.c_re = 0;
385 x->x_cspace.c_im = 0;
386 x->x_cspace.c_q = q;
387 x->x_cspace.c_isr = 0;
388 x->x_f = 0;
389 return (x);
390}
391
392static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
393{
394 x->x_ctl->c_q = (f > 0 ? f : 0.f);
395}
396
397static t_int *sigvcf_perform(t_int *w)
398{
399 float *in1 = (float *)(w[1]);
400 float *in2 = (float *)(w[2]);
401 float *out1 = (float *)(w[3]);
402 float *out2 = (float *)(w[4]);
403 t_vcfctl *c = (t_vcfctl *)(w[5]);
404 int n = (t_int)(w[6]);
405 int i;
406 float re = c->c_re, re2;
407 float im = c->c_im;
408 float q = c->c_q;
409 float qinv = (q > 0? 1.0f/q : 0);
410 float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
411 float isr = c->c_isr;
412 float coefr, coefi;
413 float *tab = cos_table, *addr, f1, f2, frac;
414 double dphase;
415 int normhipart, tabindex;
416 union tabfudge tf;
417
418 tf.tf_d = UNITBIT32;
419 normhipart = tf.tf_i[HIOFFSET];
420
421 for (i = 0; i < n; i++)
422 {
423 float cf, cfindx, r, oneminusr;
424 cf = *in2++ * isr;
425 if (cf < 0) cf = 0;
426 cfindx = cf * (float)(COSTABSIZE/6.28318f);
427 r = (qinv > 0 ? 1 - cf * qinv : 0);
428 if (r < 0) r = 0;
429 oneminusr = 1.0f - r;
430 dphase = ((double)(cfindx)) + UNITBIT32;
431 tf.tf_d = dphase;
432 tabindex = tf.tf_i[HIOFFSET] & (COSTABSIZE-1);
433 addr = tab + tabindex;
434 tf.tf_i[HIOFFSET] = normhipart;
435 frac = tf.tf_d - UNITBIT32;
436 f1 = addr[0];
437 f2 = addr[1];
438 coefr = r * (f1 + frac * (f2 - f1));
439
440 addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
441 f1 = addr[0];
442 f2 = addr[1];
443 coefi = r * (f1 + frac * (f2 - f1));
444
445 f1 = *in1++;
446 re2 = re;
447 *out1++ = re = ampcorrect * oneminusr * f1
448 + coefr * re2 - coefi * im;
449 *out2++ = im = coefi * re2 + coefr * im;
450 }
451 if (PD_BIGORSMALL(re))
452 re = 0;
453 if (PD_BIGORSMALL(im))
454 im = 0;
455 c->c_re = re;
456 c->c_im = im;
457 return (w+7);
458}
459
460static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
461{
462 x->x_ctl->c_isr = 6.28318f/sp[0]->s_sr;
463 dsp_add(sigvcf_perform, 6,
464 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
465 x->x_ctl, sp[0]->s_n);
466
467}
468
469void sigvcf_setup(void)
470{
471 sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
472 sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
473 CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
474 class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
475 class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
476 gensym("ft1"), A_FLOAT, 0);
477}
478
479/* -------------------------- noise~ ------------------------------ */
480static t_class *noise_class;
481
482typedef struct _noise
483{
484 t_object x_obj;
485 int x_val;
486} t_noise;
487
488static void *noise_new(void)
489{
490 t_noise *x = (t_noise *)pd_new(noise_class);
491 static int init = 307;
492 x->x_val = (init *= 1319);
493 outlet_new(&x->x_obj, gensym("signal"));
494 return (x);
495}
496
497static t_int *noise_perform(t_int *w)
498{
499 t_float *out = (t_float *)(w[1]);
500 int *vp = (int *)(w[2]);
501 int n = (int)(w[3]);
502 int val = *vp;
503 while (n--)
504 {
505 *out++ = ((float)((val & 0x7fffffff) - 0x40000000)) *
506 (float)(1.0 / 0x40000000);
507 val = val * 435898247 + 382842987;
508 }
509 *vp = val;
510 return (w+4);
511}
512
513static void noise_dsp(t_noise *x, t_signal **sp)
514{
515 dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
516}
517
518static void noise_setup(void)
519{
520 noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
521 sizeof(t_noise), 0, 0);
522 class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
523}
524
525
526/* ----------------------- global setup routine ---------------- */
527void d_osc_setup(void)
528{
529 phasor_setup();
530 cos_setup();
531 osc_setup();
532 sigvcf_setup();
533 noise_setup();
534}
535
536/* Copyright (c) 1997-1999 Miller Puckette.
537* For information on usage and redistribution, and for a DISCLAIMER OF ALL
538* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
539
540/* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c.
541*/
542
543#include "m_pd.h"
544#include "math.h"
545
546#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
547
548 /* machine-dependent definitions. These ifdefs really
549 should have been by CPU type and not by operating system! */
550#ifdef IRIX
551 /* big-endian. Most significant byte is at low address in memory */
552#define HIOFFSET 0 /* word offset to find MSB */
553#define LOWOFFSET 1 /* word offset to find LSB */
554#define int32 long /* a data type that has 32 bits */
555#else
556#ifdef MSW
557 /* little-endian; most significant byte is at highest address */
558#define HIOFFSET 1
559#define LOWOFFSET 0
560#define int32 long
561#else
562#ifdef __FreeBSD__
563#include <machine/endian.h>
564#if BYTE_ORDER == LITTLE_ENDIAN
565#define HIOFFSET 1
566#define LOWOFFSET 0
567#else
568#define HIOFFSET 0 /* word offset to find MSB */
569#define LOWOFFSET 1 /* word offset to find LSB */
570#endif /* BYTE_ORDER */
571#include <sys/types.h>
572#define int32 int32_t
573#endif
574#ifdef __linux__
575
576#include <endian.h>
577
578#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
579#error No byte order defined
580#endif
581
582#if __BYTE_ORDER == __LITTLE_ENDIAN
583#define HIOFFSET 1
584#define LOWOFFSET 0
585#else
586#define HIOFFSET 0 /* word offset to find MSB */
587#define LOWOFFSET 1 /* word offset to find LSB */
588#endif /* __BYTE_ORDER */
589
590#include <sys/types.h>
591#define int32 int32_t
592
593#else
594#ifdef MACOSX
595#define HIOFFSET 0 /* word offset to find MSB */
596#define LOWOFFSET 1 /* word offset to find LSB */
597#define int32 int /* a data type that has 32 bits */
598
599#endif /* MACOSX */
600#endif /* __linux__ */
601#endif /* MSW */
602#endif /* SGI */
603
604union tabfudge
605{
606 double tf_d;
607 int32 tf_i[2];
608};
609
610
611/* -------------------------- phasor~ ------------------------------ */
612static t_class *phasor_class, *scalarphasor_class;
613
614#if 1 /* in the style of R. Hoeldrich (ICMC 1995 Banff) */
615
616typedef struct _phasor
617{
618 t_object x_obj;
619 double x_phase;
620 float x_conv;
621 float x_f; /* scalar frequency */
622} t_phasor;
623
624static void *phasor_new(t_floatarg f)
625{
626 t_phasor *x = (t_phasor *)pd_new(phasor_class);
627 x->x_f = f;
628 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
629 x->x_phase = 0;
630 x->x_conv = 0;
631 outlet_new(&x->x_obj, gensym("signal"));
632 return (x);
633}
634
635static t_int *phasor_perform(t_int *w)
636{
637 t_phasor *x = (t_phasor *)(w[1]);
638 t_float *in = (t_float *)(w[2]);
639 t_float *out = (t_float *)(w[3]);
640 int n = (int)(w[4]);
641 double dphase = x->x_phase + UNITBIT32;
642 union tabfudge tf;
643 int normhipart;
644 float conv = x->x_conv;
645
646 tf.tf_d = UNITBIT32;
647 normhipart = tf.tf_i[HIOFFSET];
648 tf.tf_d = dphase;
649
650 while (n--)
651 {
652 tf.tf_i[HIOFFSET] = normhipart;
653 dphase += *in++ * conv;
654 *out++ = tf.tf_d - UNITBIT32;
655 tf.tf_d = dphase;
656 }
657 tf.tf_i[HIOFFSET] = normhipart;
658 x->x_phase = tf.tf_d - UNITBIT32;
659 return (w+5);
660}
661
662static void phasor_dsp(t_phasor *x, t_signal **sp)
663{
664 x->x_conv = 1./sp[0]->s_sr;
665 dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
666}
667
668static void phasor_ft1(t_phasor *x, t_float f)
669{
670 x->x_phase = f;
671}
672
673static void phasor_setup(void)
674{
675 phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
676 sizeof(t_phasor), 0, A_DEFFLOAT, 0);
677 CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
678 class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
679 class_addmethod(phasor_class, (t_method)phasor_ft1,
680 gensym("ft1"), A_FLOAT, 0);
681}
682
683#endif /* Hoeldrich version */
684
685/* ------------------------ cos~ ----------------------------- */
686
687float *cos_table;
688
689static t_class *cos_class;
690
691typedef struct _cos
692{
693 t_object x_obj;
694 float x_f;
695} t_cos;
696
697static void *cos_new(void)
698{
699 t_cos *x = (t_cos *)pd_new(cos_class);
700 outlet_new(&x->x_obj, gensym("signal"));
701 x->x_f = 0;
702 return (x);
703}
704
705static t_int *cos_perform(t_int *w)
706{
707 t_float *in = (t_float *)(w[1]);
708 t_float *out = (t_float *)(w[2]);
709 int n = (int)(w[3]);
710 float *tab = cos_table, *addr, f1, f2, frac;
711 double dphase;
712 int normhipart;
713 union tabfudge tf;
714
715 tf.tf_d = UNITBIT32;
716 normhipart = tf.tf_i[HIOFFSET];
717
718#if 0 /* this is the readable version of the code. */
719 while (n--)
720 {
721 dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
722 tf.tf_d = dphase;
723 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
724 tf.tf_i[HIOFFSET] = normhipart;
725 frac = tf.tf_d - UNITBIT32;
726 f1 = addr[0];
727 f2 = addr[1];
728 *out++ = f1 + frac * (f2 - f1);
729 }
730#endif
731#if 1 /* this is the same, unwrapped by hand. */
732 dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
733 tf.tf_d = dphase;
734 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
735 tf.tf_i[HIOFFSET] = normhipart;
736 while (--n)
737 {
738 dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
739 frac = tf.tf_d - UNITBIT32;
740 tf.tf_d = dphase;
741 f1 = addr[0];
742 f2 = addr[1];
743 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
744 *out++ = f1 + frac * (f2 - f1);
745 tf.tf_i[HIOFFSET] = normhipart;
746 }
747 frac = tf.tf_d - UNITBIT32;
748 f1 = addr[0];
749 f2 = addr[1];
750 *out++ = f1 + frac * (f2 - f1);
751#endif
752 return (w+4);
753}
754
755static void cos_dsp(t_cos *x, t_signal **sp)
756{
757 dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
758}
759
760static void cos_maketable(void)
761{
762 int i;
763 float *fp, phase, phsinc = (2. * 3.14159) / COSTABSIZE;
764 union tabfudge tf;
765
766 if (cos_table) return;
767 cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
768 for (i = COSTABSIZE + 1, fp = cos_table, phase = 0; i--;
769 fp++, phase += phsinc)
770 *fp = cos(phase);
771
772 /* here we check at startup whether the byte alignment
773 is as we declared it. If not, the code has to be
774 recompiled the other way. */
775 tf.tf_d = UNITBIT32 + 0.5;
776 if ((unsigned)tf.tf_i[LOWOFFSET] != 0x80000000)
777 bug("cos~: unexpected machine alignment");
778}
779
780static void cos_setup(void)
781{
782 cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
783 sizeof(t_cos), 0, A_DEFFLOAT, 0);
784 CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
785 class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
786 cos_maketable();
787}
788
789/* ------------------------ osc~ ----------------------------- */
790
791static t_class *osc_class, *scalarosc_class;
792
793typedef struct _osc
794{
795 t_object x_obj;
796 double x_phase;
797 float x_conv;
798 float x_f; /* frequency if scalar */
799} t_osc;
800
801static void *osc_new(t_floatarg f)
802{
803 t_osc *x = (t_osc *)pd_new(osc_class);
804 x->x_f = f;
805 outlet_new(&x->x_obj, gensym("signal"));
806 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
807 x->x_phase = 0;
808 x->x_conv = 0;
809 return (x);
810}
811
812static t_int *osc_perform(t_int *w)
813{
814 t_osc *x = (t_osc *)(w[1]);
815 t_float *in = (t_float *)(w[2]);
816 t_float *out = (t_float *)(w[3]);
817 int n = (int)(w[4]);
818 float *tab = cos_table, *addr, f1, f2, frac;
819 double dphase = x->x_phase + UNITBIT32;
820 int normhipart;
821 union tabfudge tf;
822 float conv = x->x_conv;
823
824 tf.tf_d = UNITBIT32;
825 normhipart = tf.tf_i[HIOFFSET];
826#if 0
827 while (n--)
828 {
829 tf.tf_d = dphase;
830 dphase += *in++ * conv;
831 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
832 tf.tf_i[HIOFFSET] = normhipart;
833 frac = tf.tf_d - UNITBIT32;
834 f1 = addr[0];
835 f2 = addr[1];
836 *out++ = f1 + frac * (f2 - f1);
837 }
838#endif
839#if 1
840 tf.tf_d = dphase;
841 dphase += *in++ * conv;
842 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
843 tf.tf_i[HIOFFSET] = normhipart;
844 frac = tf.tf_d - UNITBIT32;
845 while (--n)
846 {
847 tf.tf_d = dphase;
848 f1 = addr[0];
849 dphase += *in++ * conv;
850 f2 = addr[1];
851 addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
852 tf.tf_i[HIOFFSET] = normhipart;
853 *out++ = f1 + frac * (f2 - f1);
854 frac = tf.tf_d - UNITBIT32;
855 }
856 f1 = addr[0];
857 f2 = addr[1];
858 *out++ = f1 + frac * (f2 - f1);
859#endif
860
861 tf.tf_d = UNITBIT32 * COSTABSIZE;
862 normhipart = tf.tf_i[HIOFFSET];
863 tf.tf_d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
864 tf.tf_i[HIOFFSET] = normhipart;
865 x->x_phase = tf.tf_d - UNITBIT32 * COSTABSIZE;
866 return (w+5);
867}
868
869static void osc_dsp(t_osc *x, t_signal **sp)
870{
871 x->x_conv = COSTABSIZE/sp[0]->s_sr;
872 dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
873}
874
875static void osc_ft1(t_osc *x, t_float f)
876{
877 x->x_phase = COSTABSIZE * f;
878}
879
880static void osc_setup(void)
881{
882 osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
883 sizeof(t_osc), 0, A_DEFFLOAT, 0);
884 CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
885 class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
886 class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
887
888 cos_maketable();
889}
890
891/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
892
893typedef struct vcfctl
894{
895 float c_re;
896 float c_im;
897 float c_q;
898 float c_isr;
899} t_vcfctl;
900
901typedef struct sigvcf
902{
903 t_object x_obj;
904 t_vcfctl x_cspace;
905 t_vcfctl *x_ctl;
906 float x_f;
907} t_sigvcf;
908
909t_class *sigvcf_class;
910
911static void *sigvcf_new(t_floatarg q)
912{
913 t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
914 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
915 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
916 outlet_new(&x->x_obj, gensym("signal"));
917 outlet_new(&x->x_obj, gensym("signal"));
918 x->x_ctl = &x->x_cspace;
919 x->x_cspace.c_re = 0;
920 x->x_cspace.c_im = 0;
921 x->x_cspace.c_q = q;
922 x->x_cspace.c_isr = 0;
923 x->x_f = 0;
924 return (x);
925}
926
927static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
928{
929 x->x_ctl->c_q = (f > 0 ? f : 0.f);
930}
931
932static t_int *sigvcf_perform(t_int *w)
933{
934 float *in1 = (float *)(w[1]);
935 float *in2 = (float *)(w[2]);
936 float *out1 = (float *)(w[3]);
937 float *out2 = (float *)(w[4]);
938 t_vcfctl *c = (t_vcfctl *)(w[5]);
939 int n = (t_int)(w[6]);
940 int i;
941 float re = c->c_re, re2;
942 float im = c->c_im;
943 float q = c->c_q;
944 float qinv = (q > 0? 1.0f/q : 0);
945 float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
946 float isr = c->c_isr;
947 float coefr, coefi;
948 float *tab = cos_table, *addr, f1, f2, frac;
949 double dphase;
950 int normhipart, tabindex;
951 union tabfudge tf;
952
953 tf.tf_d = UNITBIT32;
954 normhipart = tf.tf_i[HIOFFSET];
955
956 for (i = 0; i < n; i++)
957 {
958 float cf, cfindx, r, oneminusr;
959 cf = *in2++ * isr;
960 if (cf < 0) cf = 0;
961 cfindx = cf * (float)(COSTABSIZE/6.28318f);
962 r = (qinv > 0 ? 1 - cf * qinv : 0);
963 if (r < 0) r = 0;
964 oneminusr = 1.0f - r;
965 dphase = ((double)(cfindx)) + UNITBIT32;
966 tf.tf_d = dphase;
967 tabindex = tf.tf_i[HIOFFSET] & (COSTABSIZE-1);
968 addr = tab + tabindex;
969 tf.tf_i[HIOFFSET] = normhipart;
970 frac = tf.tf_d - UNITBIT32;
971 f1 = addr[0];
972 f2 = addr[1];
973 coefr = r * (f1 + frac * (f2 - f1));
974
975 addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
976 f1 = addr[0];
977 f2 = addr[1];
978 coefi = r * (f1 + frac * (f2 - f1));
979
980 f1 = *in1++;
981 re2 = re;
982 *out1++ = re = ampcorrect * oneminusr * f1
983 + coefr * re2 - coefi * im;
984 *out2++ = im = coefi * re2 + coefr * im;
985 }
986 if (PD_BIGORSMALL(re))
987 re = 0;
988 if (PD_BIGORSMALL(im))
989 im = 0;
990 c->c_re = re;
991 c->c_im = im;
992 return (w+7);
993}
994
995static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
996{
997 x->x_ctl->c_isr = 6.28318f/sp[0]->s_sr;
998 dsp_add(sigvcf_perform, 6,
999 sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
1000 x->x_ctl, sp[0]->s_n);
1001
1002}
1003
1004void sigvcf_setup(void)
1005{
1006 sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
1007 sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
1008 CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
1009 class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
1010 class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
1011 gensym("ft1"), A_FLOAT, 0);
1012}
1013
1014/* -------------------------- noise~ ------------------------------ */
1015static t_class *noise_class;
1016
1017typedef struct _noise
1018{
1019 t_object x_obj;
1020 int x_val;
1021} t_noise;
1022
1023static void *noise_new(void)
1024{
1025 t_noise *x = (t_noise *)pd_new(noise_class);
1026 static int init = 307;
1027 x->x_val = (init *= 1319);
1028 outlet_new(&x->x_obj, gensym("signal"));
1029 return (x);
1030}
1031
1032static t_int *noise_perform(t_int *w)
1033{
1034 t_float *out = (t_float *)(w[1]);
1035 int *vp = (int *)(w[2]);
1036 int n = (int)(w[3]);
1037 int val = *vp;
1038 while (n--)
1039 {
1040 *out++ = ((float)((val & 0x7fffffff) - 0x40000000)) *
1041 (float)(1.0 / 0x40000000);
1042 val = val * 435898247 + 382842987;
1043 }
1044 *vp = val;
1045 return (w+4);
1046}
1047
1048static void noise_dsp(t_noise *x, t_signal **sp)
1049{
1050 dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
1051}
1052
1053static void noise_setup(void)
1054{
1055 noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
1056 sizeof(t_noise), 0, 0);
1057 class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
1058}
1059
1060
1061/* ----------------------- global setup routine ---------------- */
1062void d_osc_setup(void)
1063{
1064 phasor_setup();
1065 cos_setup();
1066 osc_setup();
1067 sigvcf_setup();
1068 noise_setup();
1069}
1070
diff --git a/apps/plugins/pdbox/PDa/src/d_resample.c b/apps/plugins/pdbox/PDa/src/d_resample.c
new file mode 100644
index 0000000000..4e617ec4df
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_resample.c
@@ -0,0 +1,450 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* upsampling/downsampling methods for inlet~/outlet~
6 *
7 * mfg.gfd.uil
8 * IOhannes
9 *
10 * 2509:forum::für::umläute:2001
11 */
12
13
14
15#include "m_pd.h"
16
17/* --------------------- up/down-sampling --------------------- */
18t_int *downsampling_perform_0(t_int *w)
19{
20 t_sample *in = (t_sample *)(w[1]); /* original signal */
21 t_sample *out = (t_sample *)(w[2]); /* downsampled signal */
22 int down = (int)(w[3]); /* downsampling factor */
23 int parent = (int)(w[4]); /* original vectorsize */
24
25 int n=parent/down;
26
27 while(n--){
28 *out++=*in;
29 in+=down;
30 }
31
32 return (w+5);
33}
34
35t_int *upsampling_perform_0(t_int *w)
36{
37 t_sample *in = (t_sample *)(w[1]); /* original signal */
38 t_sample *out = (t_sample *)(w[2]); /* upsampled signal */
39 int up = (int)(w[3]); /* upsampling factor */
40 int parent = (int)(w[4]); /* original vectorsize */
41
42 int n=parent*up;
43 t_sample *dummy = out;
44
45 while(n--)*out++=0;
46
47 n = parent;
48 out = dummy;
49 while(n--){
50 *out=*in++;
51 out+=up;
52 }
53
54 return (w+5);
55}
56
57t_int *upsampling_perform_hold(t_int *w)
58{
59 t_sample *in = (t_sample *)(w[1]); /* original signal */
60 t_sample *out = (t_sample *)(w[2]); /* upsampled signal */
61 int up = (int)(w[3]); /* upsampling factor */
62 int parent = (int)(w[4]); /* original vectorsize */
63 int i=up;
64
65 int n=parent;
66 t_sample *dum_out = out;
67 t_sample *dum_in = in;
68
69 while (i--) {
70 n = parent;
71 out = dum_out+i;
72 in = dum_in;
73 while(n--){
74 *out=*in++;
75 out+=up;
76 }
77 }
78 return (w+5);
79}
80
81t_int *upsampling_perform_linear(t_int *w)
82{
83 t_resample *x= (t_resample *)(w[1]);
84 t_sample *in = (t_sample *)(w[2]); /* original signal */
85 t_sample *out = (t_sample *)(w[3]); /* upsampled signal */
86 int up = (int)(w[4]); /* upsampling factor */
87 int parent = (int)(w[5]); /* original vectorsize */
88 int length = parent*up;
89 int n;
90 t_sample *fp;
91 t_sample a=*x->buffer, b=*in;
92
93
94 for (n=0; n<length; n++) {
95 t_float findex = (t_float)(n+1)/up;
96 int index = findex;
97 t_sample frac=findex - index;
98 if (frac==0.)frac=1.;
99 *out++ = frac * b + (1.-frac) * a;
100 fp = in+index;
101 b=*fp;
102 a=(index)?*(fp-1):a;
103 }
104
105 *x->buffer = a;
106 return (w+6);
107}
108
109/* ----------------------- public -------------------------------- */
110
111/* utils */
112
113void resample_init(t_resample *x)
114{
115 x->method=0;
116
117 x->downsample=x->upsample=1;
118
119 x->s_n = x->coefsize = x->bufsize = 0;
120 x->s_vec = x->coeffs = x->buffer = 0;
121}
122
123void resample_free(t_resample *x)
124{
125 if (x->s_n) t_freebytes(x->s_vec, x->s_n*sizeof(*x->s_vec));
126 if (x->coefsize) t_freebytes(x->coeffs, x->coefsize*sizeof(*x->coeffs));
127 if (x->bufsize) t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
128
129 x->s_n = x->coefsize = x->bufsize = 0;
130 x->s_vec = x->coeffs = x->buffer = 0;
131}
132
133
134/* dsp-adding */
135
136void resample_dsp(t_resample *x,
137 t_sample* in, int insize,
138 t_sample* out, int outsize,
139 int method)
140{
141 if (insize == outsize){
142 bug("nothing to be done");
143 return;
144 }
145
146 if (insize > outsize) { /* downsampling */
147 if (insize % outsize) {
148 error("bad downsampling factor");
149 return;
150 }
151 switch (method) {
152 default:
153 dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize);
154 }
155
156
157 } else { /* upsampling */
158 if (outsize % insize) {
159 error("bad upsampling factor");
160 return;
161 }
162 switch (method) {
163 case 1:
164 dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize);
165 break;
166 case 2:
167 if (x->bufsize != 1) {
168 t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
169 x->bufsize = 1;
170 x->buffer = t_getbytes(x->bufsize*sizeof(*x->buffer));
171 }
172 dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize);
173 break;
174 default:
175 dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize);
176 }
177 }
178}
179
180void resamplefrom_dsp(t_resample *x,
181 t_sample *in,
182 int insize, int outsize, int method)
183{
184 if (insize==outsize) {
185 t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
186 x->s_n = 0;
187 x->s_vec = in;
188 return;
189 }
190
191 if (x->s_n != outsize) {
192 t_sample *buf=x->s_vec;
193 t_freebytes(buf, x->s_n * sizeof(*buf));
194 buf = (t_sample *)t_getbytes(outsize * sizeof(*buf));
195 x->s_vec = buf;
196 x->s_n = outsize;
197 }
198
199 resample_dsp(x, in, insize, x->s_vec, x->s_n, method);
200 return;
201}
202
203void resampleto_dsp(t_resample *x,
204 t_sample *out,
205 int insize, int outsize, int method)
206{
207 if (insize==outsize) {
208 if (x->s_n)t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
209 x->s_n = 0;
210 x->s_vec = out;
211 return;
212 }
213
214 if (x->s_n != insize) {
215 t_sample *buf=x->s_vec;
216 t_freebytes(buf, x->s_n * sizeof(*buf));
217 buf = (t_sample *)t_getbytes(insize * sizeof(*buf));
218 x->s_vec = buf;
219 x->s_n = insize;
220 }
221
222 resample_dsp(x, x->s_vec, x->s_n, out, outsize, method);
223
224 return;
225}
226/* Copyright (c) 1997-1999 Miller Puckette.
227 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
228 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
229
230/* upsampling/downsampling methods for inlet~/outlet~
231 *
232 * mfg.gfd.uil
233 * IOhannes
234 *
235 * 2509:forum::für::umläute:2001
236 */
237
238
239
240#include "m_pd.h"
241
242/* --------------------- up/down-sampling --------------------- */
243t_int *downsampling_perform_0(t_int *w)
244{
245 t_sample *in = (t_sample *)(w[1]); /* original signal */
246 t_sample *out = (t_sample *)(w[2]); /* downsampled signal */
247 int down = (int)(w[3]); /* downsampling factor */
248 int parent = (int)(w[4]); /* original vectorsize */
249
250 int n=parent/down;
251
252 while(n--){
253 *out++=*in;
254 in+=down;
255 }
256
257 return (w+5);
258}
259
260t_int *upsampling_perform_0(t_int *w)
261{
262 t_sample *in = (t_sample *)(w[1]); /* original signal */
263 t_sample *out = (t_sample *)(w[2]); /* upsampled signal */
264 int up = (int)(w[3]); /* upsampling factor */
265 int parent = (int)(w[4]); /* original vectorsize */
266
267 int n=parent*up;
268 t_sample *dummy = out;
269
270 while(n--)*out++=0;
271
272 n = parent;
273 out = dummy;
274 while(n--){
275 *out=*in++;
276 out+=up;
277 }
278
279 return (w+5);
280}
281
282t_int *upsampling_perform_hold(t_int *w)
283{
284 t_sample *in = (t_sample *)(w[1]); /* original signal */
285 t_sample *out = (t_sample *)(w[2]); /* upsampled signal */
286 int up = (int)(w[3]); /* upsampling factor */
287 int parent = (int)(w[4]); /* original vectorsize */
288 int i=up;
289
290 int n=parent;
291 t_sample *dum_out = out;
292 t_sample *dum_in = in;
293
294 while (i--) {
295 n = parent;
296 out = dum_out+i;
297 in = dum_in;
298 while(n--){
299 *out=*in++;
300 out+=up;
301 }
302 }
303 return (w+5);
304}
305
306t_int *upsampling_perform_linear(t_int *w)
307{
308 t_resample *x= (t_resample *)(w[1]);
309 t_sample *in = (t_sample *)(w[2]); /* original signal */
310 t_sample *out = (t_sample *)(w[3]); /* upsampled signal */
311 int up = (int)(w[4]); /* upsampling factor */
312 int parent = (int)(w[5]); /* original vectorsize */
313 int length = parent*up;
314 int n;
315 t_sample *fp;
316 t_sample a=*x->buffer, b=*in;
317
318
319 for (n=0; n<length; n++) {
320 t_float findex = (t_float)(n+1)/up;
321 int index = findex;
322 t_sample frac=findex - index;
323 if (frac==0.)frac=1.;
324 *out++ = frac * b + (1.-frac) * a;
325 fp = in+index;
326 b=*fp;
327 a=(index)?*(fp-1):a;
328 }
329
330 *x->buffer = a;
331 return (w+6);
332}
333
334/* ----------------------- public -------------------------------- */
335
336/* utils */
337
338void resample_init(t_resample *x)
339{
340 x->method=0;
341
342 x->downsample=x->upsample=1;
343
344 x->s_n = x->coefsize = x->bufsize = 0;
345 x->s_vec = x->coeffs = x->buffer = 0;
346}
347
348void resample_free(t_resample *x)
349{
350 if (x->s_n) t_freebytes(x->s_vec, x->s_n*sizeof(*x->s_vec));
351 if (x->coefsize) t_freebytes(x->coeffs, x->coefsize*sizeof(*x->coeffs));
352 if (x->bufsize) t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
353
354 x->s_n = x->coefsize = x->bufsize = 0;
355 x->s_vec = x->coeffs = x->buffer = 0;
356}
357
358
359/* dsp-adding */
360
361void resample_dsp(t_resample *x,
362 t_sample* in, int insize,
363 t_sample* out, int outsize,
364 int method)
365{
366 if (insize == outsize){
367 bug("nothing to be done");
368 return;
369 }
370
371 if (insize > outsize) { /* downsampling */
372 if (insize % outsize) {
373 error("bad downsampling factor");
374 return;
375 }
376 switch (method) {
377 default:
378 dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize);
379 }
380
381
382 } else { /* upsampling */
383 if (outsize % insize) {
384 error("bad upsampling factor");
385 return;
386 }
387 switch (method) {
388 case 1:
389 dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize);
390 break;
391 case 2:
392 if (x->bufsize != 1) {
393 t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
394 x->bufsize = 1;
395 x->buffer = t_getbytes(x->bufsize*sizeof(*x->buffer));
396 }
397 dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize);
398 break;
399 default:
400 dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize);
401 }
402 }
403}
404
405void resamplefrom_dsp(t_resample *x,
406 t_sample *in,
407 int insize, int outsize, int method)
408{
409 if (insize==outsize) {
410 t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
411 x->s_n = 0;
412 x->s_vec = in;
413 return;
414 }
415
416 if (x->s_n != outsize) {
417 t_sample *buf=x->s_vec;
418 t_freebytes(buf, x->s_n * sizeof(*buf));
419 buf = (t_sample *)t_getbytes(outsize * sizeof(*buf));
420 x->s_vec = buf;
421 x->s_n = outsize;
422 }
423
424 resample_dsp(x, in, insize, x->s_vec, x->s_n, method);
425 return;
426}
427
428void resampleto_dsp(t_resample *x,
429 t_sample *out,
430 int insize, int outsize, int method)
431{
432 if (insize==outsize) {
433 if (x->s_n)t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
434 x->s_n = 0;
435 x->s_vec = out;
436 return;
437 }
438
439 if (x->s_n != insize) {
440 t_sample *buf=x->s_vec;
441 t_freebytes(buf, x->s_n * sizeof(*buf));
442 buf = (t_sample *)t_getbytes(insize * sizeof(*buf));
443 x->s_vec = buf;
444 x->s_n = insize;
445 }
446
447 resample_dsp(x, x->s_vec, x->s_n, out, outsize, method);
448
449 return;
450}
diff --git a/apps/plugins/pdbox/PDa/src/d_soundfile.c b/apps/plugins/pdbox/PDa/src/d_soundfile.c
new file mode 100644
index 0000000000..872a44a923
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_soundfile.c
@@ -0,0 +1,4734 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* this file contains, first, a collection of soundfile access routines, a
6sort of soundfile library. Second, the "soundfiler" object is defined which
7uses the routines to read or write soundfiles, synchronously, from garrays.
8These operations are not to be done in "real time" as they may have to wait
9for disk accesses (even the write routine.) Finally, the realtime objects
10readsf~ and writesf~ are defined which confine disk operations to a separate
11thread so that they can be used in real time. The readsf~ and writesf~
12objects use Posix-like threads. */
13
14#ifdef UNIX
15#include <unistd.h>
16#include <fcntl.h>
17#endif
18#include <pthread.h>
19#ifdef MSW
20#include <io.h>
21#endif
22#include <stdio.h>
23#include <string.h>
24#include <errno.h>
25
26#include "m_pd.h"
27
28#define MAXSFCHANS 64
29
30/***************** soundfile header structures ************************/
31
32typedef unsigned short uint16;
33typedef unsigned long uint32;
34
35#define FORMAT_WAVE 0
36#define FORMAT_AIFF 1
37#define FORMAT_NEXT 2
38
39/* the NeXTStep sound header structure; can be big or little endian */
40
41typedef struct _nextstep
42{
43 char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
44 uint32 ns_onset; /* byte offset of first sample */
45 uint32 ns_length; /* length of sound in bytes */
46 uint32 ns_format; /* format; see below */
47 uint32 ns_sr; /* sample rate */
48 uint32 ns_nchans; /* number of channels */
49 char ns_info[4]; /* comment */
50} t_nextstep;
51
52#define NS_FORMAT_LINEAR_16 3
53#define NS_FORMAT_LINEAR_24 4
54#define NS_FORMAT_FLOAT 6
55#define SCALE (1./(1024. * 1024. * 1024. * 2.))
56
57/* the WAVE header. All Wave files are little endian. We assume
58 the "fmt" chunk comes first which is usually the case but perhaps not
59 always; same for AIFF and the "COMM" chunk. */
60
61typedef unsigned word;
62typedef unsigned long dword;
63
64typedef struct _wave
65{
66 char w_fileid[4]; /* chunk id 'RIFF' */
67 uint32 w_chunksize; /* chunk size */
68 char w_waveid[4]; /* wave chunk id 'WAVE' */
69 char w_fmtid[4]; /* format chunk id 'fmt ' */
70 uint32 w_fmtchunksize; /* format chunk size */
71 uint16 w_fmttag; /* format tag (WAV_INT etc) */
72 uint16 w_nchannels; /* number of channels */
73 uint32 w_samplespersec; /* sample rate in hz */
74 uint32 w_navgbytespersec; /* average bytes per second */
75 uint16 w_nblockalign; /* number of bytes per frame */
76 uint16 w_nbitspersample; /* number of bits in a sample */
77 char w_datachunkid[4]; /* data chunk id 'data' */
78 uint32 w_datachunksize; /* length of data chunk */
79} t_wave;
80
81typedef struct _fmt /* format chunk */
82{
83 uint16 f_fmttag; /* format tag, 1 for PCM */
84 uint16 f_nchannels; /* number of channels */
85 uint32 f_samplespersec; /* sample rate in hz */
86 uint32 f_navgbytespersec; /* average bytes per second */
87 uint16 f_nblockalign; /* number of bytes per frame */
88 uint16 f_nbitspersample; /* number of bits in a sample */
89} t_fmt;
90
91typedef struct _wavechunk /* ... and the last two items */
92{
93 char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
94 uint32 wc_size; /* length of data chunk */
95} t_wavechunk;
96
97#define WAV_INT 1
98#define WAV_FLOAT 3
99
100/* the AIFF header. I'm assuming AIFC is compatible but don't really know
101 that. */
102
103typedef struct _datachunk
104{
105 char dc_id[4]; /* data chunk id 'SSND' */
106 uint32 dc_size; /* length of data chunk */
107} t_datachunk;
108
109typedef struct _comm
110{
111 uint16 c_nchannels; /* number of channels */
112 uint16 c_nframeshi; /* # of sample frames (hi) */
113 uint16 c_nframeslo; /* # of sample frames (lo) */
114 uint16 c_bitspersamp; /* bits per sample */
115 unsigned char c_samprate[10]; /* sample rate, 80-bit float! */
116} t_comm;
117
118 /* this version is more convenient for writing them out: */
119typedef struct _aiff
120{
121 char a_fileid[4]; /* chunk id 'FORM' */
122 uint32 a_chunksize; /* chunk size */
123 char a_aiffid[4]; /* aiff chunk id 'AIFF' */
124 char a_fmtid[4]; /* format chunk id 'COMM' */
125 uint32 a_fmtchunksize; /* format chunk size, 18 */
126 uint16 a_nchannels; /* number of channels */
127 uint16 a_nframeshi; /* # of sample frames (hi) */
128 uint16 a_nframeslo; /* # of sample frames (lo) */
129 uint16 a_bitspersamp; /* bits per sample */
130 unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
131} t_aiff;
132
133#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
134
135
136#define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */
137
138#define WHDR1 sizeof(t_nextstep)
139#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
140#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
141
142#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
143
144#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
145
146#ifdef MSW
147#include <fcntl.h>
148#define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
149#else
150#define BINCREATE O_WRONLY | O_CREAT | O_TRUNC
151#endif
152
153/* this routine returns 1 if the high order byte comes at the lower
154address on our architecture (big-endianness.). It's 1 for Motorola,
1550 for Intel: */
156
157extern int garray_ambigendian(void);
158
159/* byte swappers */
160
161static uint32 swap4(uint32 n, int doit)
162{
163 if (doit)
164 return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
165 ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
166 else return (n);
167}
168
169static uint16 swap2(uint32 n, int doit)
170{
171 if (doit)
172 return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
173 else return (n);
174}
175
176static void swapstring(char *foo, int doit)
177{
178 if (doit)
179 {
180 char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
181 foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
182 }
183}
184
185/******************** soundfile access routines **********************/
186
187/* This routine opens a file, looks for either a nextstep or "wave" header,
188* seeks to end of it, and fills in bytes per sample and number of channels.
189* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
190* are supported. If "headersize" is nonzero, the
191* caller should supply the number of channels, endinanness, and bytes per
192* sample; the header is ignored. Otherwise, the routine tries to read the
193* header and fill in the properties.
194*/
195
196int open_soundfile(const char *dirname, const char *filename, int headersize,
197 int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
198 long skipframes)
199{
200 char buf[OBUFSIZE], *bufptr;
201 int fd, format, nchannels, bigendian, bytespersamp, swap, sysrtn;
202 long bytelimit = 0x7fffffff;
203 errno = 0;
204 fd = open_via_path(dirname, filename,
205 "", buf, &bufptr, MAXPDSTRING, 1);
206 if (fd < 0)
207 return (-1);
208 if (headersize >= 0) /* header detection overridden */
209 {
210 bigendian = *p_bigendian;
211 nchannels = *p_nchannels;
212 bytespersamp = *p_bytespersamp;
213 bytelimit = *p_bytelimit;
214 }
215 else
216 {
217 int bytesread = read(fd, buf, READHDRSIZE);
218 int format;
219 if (bytesread < 4)
220 goto badheader;
221 if (!strncmp(buf, ".snd", 4))
222 format = FORMAT_NEXT, bigendian = 1;
223 else if (!strncmp(buf, "dns.", 4))
224 format = FORMAT_NEXT, bigendian = 0;
225 else if (!strncmp(buf, "RIFF", 4))
226 {
227 if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4))
228 goto badheader;
229 format = FORMAT_WAVE, bigendian = 0;
230 }
231 else if (!strncmp(buf, "FORM", 4))
232 {
233 if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4))
234 goto badheader;
235 format = FORMAT_AIFF, bigendian = 1;
236 }
237 else
238 goto badheader;
239 swap = (bigendian != garray_ambigendian());
240 if (format == FORMAT_NEXT) /* nextstep header */
241 {
242 uint32 param;
243 if (bytesread < (int)sizeof(t_nextstep))
244 goto badheader;
245 nchannels = swap4(((t_nextstep *)buf)->ns_nchans, swap);
246 format = swap4(((t_nextstep *)buf)->ns_format, swap);
247 headersize = swap4(((t_nextstep *)buf)->ns_onset, swap);
248 if (format == NS_FORMAT_LINEAR_16)
249 bytespersamp = 2;
250 else if (format == NS_FORMAT_LINEAR_24)
251 bytespersamp = 3;
252 else if (format == NS_FORMAT_FLOAT)
253 bytespersamp = 4;
254 else goto badheader;
255 bytelimit = 0x7fffffff;
256 }
257 else if (format == FORMAT_WAVE) /* wave header */
258 {
259 /* This is awful. You have to skip over chunks,
260 except that if one happens to be a "fmt" chunk, you want to
261 find out the format from that one. The case where the
262 "fmt" chunk comes after the audio isn't handled. */
263 headersize = 12;
264 if (bytesread < 20)
265 goto badheader;
266 /* First we guess a number of channels, etc., in case there's
267 no "fmt" chunk to follow. */
268 nchannels = 1;
269 bytespersamp = 2;
270 /* copy the first chunk header to beginnning of buffer. */
271 memcpy(buf, buf + headersize, sizeof(t_wavechunk));
272 /* post("chunk %c %c %c %c",
273 ((t_wavechunk *)buf)->wc_id[0],
274 ((t_wavechunk *)buf)->wc_id[1],
275 ((t_wavechunk *)buf)->wc_id[2],
276 ((t_wavechunk *)buf)->wc_id[3]); */
277 /* read chunks in loop until we get to the data chunk */
278 while (strncmp(((t_wavechunk *)buf)->wc_id, "data", 4))
279 {
280 long chunksize = swap4(((t_wavechunk *)buf)->wc_size,
281 swap), seekto = headersize + chunksize + 8, seekout;
282
283 if (!strncmp(((t_wavechunk *)buf)->wc_id, "fmt ", 4))
284 {
285 long commblockonset = headersize + 8;
286 seekout = lseek(fd, commblockonset, SEEK_SET);
287 if (seekout != commblockonset)
288 goto badheader;
289 if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt))
290 goto badheader;
291 nchannels = swap2(((t_fmt *)buf)->f_nchannels, swap);
292 format = swap2(((t_fmt *)buf)->f_nbitspersample, swap);
293 if (format == 16)
294 bytespersamp = 2;
295 else if (format == 24)
296 bytespersamp = 3;
297 else if (format == 32)
298 bytespersamp = 4;
299 else goto badheader;
300 }
301 seekout = lseek(fd, seekto, SEEK_SET);
302 if (seekout != seekto)
303 goto badheader;
304 if (read(fd, buf, sizeof(t_wavechunk)) <
305 (int) sizeof(t_wavechunk))
306 goto badheader;
307 /* post("new chunk %c %c %c %c at %d",
308 ((t_wavechunk *)buf)->wc_id[0],
309 ((t_wavechunk *)buf)->wc_id[1],
310 ((t_wavechunk *)buf)->wc_id[2],
311 ((t_wavechunk *)buf)->wc_id[3], seekto); */
312 headersize = seekto;
313 }
314 bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap);
315 headersize += 8;
316 }
317 else
318 {
319 /* AIFF. same as WAVE; actually predates it. Disgusting. */
320 headersize = 12;
321 if (bytesread < 20)
322 goto badheader;
323 /* First we guess a number of channels, etc., in case there's
324 no COMM block to follow. */
325 nchannels = 1;
326 bytespersamp = 2;
327 /* copy the first chunk header to beginnning of buffer. */
328 memcpy(buf, buf + headersize, sizeof(t_datachunk));
329 /* read chunks in loop until we get to the data chunk */
330 while (strncmp(((t_datachunk *)buf)->dc_id, "SSND", 4))
331 {
332 long chunksize = swap4(((t_datachunk *)buf)->dc_size,
333 swap), seekto = headersize + chunksize + 8, seekout;
334 /* post("chunk %c %c %c %c seek %d",
335 ((t_datachunk *)buf)->dc_id[0],
336 ((t_datachunk *)buf)->dc_id[1],
337 ((t_datachunk *)buf)->dc_id[2],
338 ((t_datachunk *)buf)->dc_id[3], seekto); */
339 if (!strncmp(((t_datachunk *)buf)->dc_id, "COMM", 4))
340 {
341 long commblockonset = headersize + 8;
342 seekout = lseek(fd, commblockonset, SEEK_SET);
343 if (seekout != commblockonset)
344 goto badheader;
345 if (read(fd, buf, sizeof(t_comm)) <
346 (int) sizeof(t_comm))
347 goto badheader;
348 nchannels = swap2(((t_comm *)buf)->c_nchannels, swap);
349 format = swap2(((t_comm *)buf)->c_bitspersamp, swap);
350 if (format == 16)
351 bytespersamp = 2;
352 else if (format == 24)
353 bytespersamp = 3;
354 else goto badheader;
355 }
356 seekout = lseek(fd, seekto, SEEK_SET);
357 if (seekout != seekto)
358 goto badheader;
359 if (read(fd, buf, sizeof(t_datachunk)) <
360 (int) sizeof(t_datachunk))
361 goto badheader;
362 headersize = seekto;
363 }
364 bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap);
365 headersize += 8;
366 }
367 }
368 /* seek past header and any sample frames to skip */
369 sysrtn = lseek(fd, nchannels * bytespersamp * skipframes + headersize, 0);
370 if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
371 return (-1);
372 bytelimit -= nchannels * bytespersamp * skipframes;
373 if (bytelimit < 0)
374 bytelimit = 0;
375 /* copy sample format back to caller */
376 *p_bigendian = bigendian;
377 *p_nchannels = nchannels;
378 *p_bytespersamp = bytespersamp;
379 *p_bytelimit = bytelimit;
380 return (fd);
381badheader:
382 /* the header wasn't recognized. We're threadable here so let's not
383 print out the error... */
384 errno = EIO;
385 return (-1);
386}
387
388static void soundfile_xferin(int sfchannels, int nvecs, t_sample **vecs,
389 long itemsread, unsigned char *buf, int nitems, int bytespersamp,
390 int bigendian)
391{
392 int i, j;
393 unsigned char *sp, *sp2;
394 t_sample *fp;
395 int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
396 int bytesperframe = bytespersamp * sfchannels;
397 for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
398 {
399 if (bytespersamp == 2)
400 {
401 if (bigendian)
402 {
403 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
404 j < nitems; j++, sp2 += bytesperframe, fp++)
405 *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
406 }
407 else
408 {
409 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
410 j < nitems; j++, sp2 += bytesperframe, fp++)
411 *fp = ((short*)sp2)[0]<<(fix1-16);
412 }
413 }
414 else if (bytespersamp == 3)
415 {
416 if (bigendian)
417 {
418 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
419 j < nitems; j++, sp2 += bytesperframe, fp++)
420 *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
421 | (sp2[2] << 8));
422 }
423 else
424 {
425 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
426 j < nitems; j++, sp2 += bytesperframe, fp++)
427 *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
428 | (sp2[0] << 8));
429 }
430 }
431 else if (bytespersamp == 4)
432 {
433 if (bigendian)
434 {
435 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
436 j < nitems; j++, sp2 += bytesperframe, fp++)
437 *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
438 | (sp2[2] << 8) | sp2[3]);
439 }
440 else
441 {
442 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
443 j < nitems; j++, sp2 += bytesperframe, fp++)
444 *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
445 | (sp2[1] << 8) | sp2[0]);
446 }
447 }
448 }
449 /* zero out other outputs */
450 for (i = sfchannels; i < nvecs; i++)
451 for (j = nitems, fp = vecs[i]; j--; )
452 *fp++ = 0;
453
454}
455
456 /* soundfiler_write ...
457
458 usage: write [flags] filename table ...
459 flags:
460 -nframes <frames>
461 -skip <frames>
462 -bytes <bytes per sample>
463 -normalize
464 -nextstep
465 -wave
466 -big
467 -little
468 */
469
470 /* the routine which actually does the work should LATER also be called
471 from garray_write16. */
472
473
474 /* Parse arguments for writing. The "obj" argument is only for flagging
475 errors. For streaming to a file the "normalize", "onset" and "nframes"
476 arguments shouldn't be set but the calling routine flags this. */
477
478static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
479 t_symbol **p_filesym,
480 int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
481 int *p_normalize, long *p_onset, long *p_nframes, float *p_rate)
482{
483 int argc = *p_argc;
484 t_atom *argv = *p_argv;
485 int bytespersamp = 2, bigendian = 0,
486 endianness = -1, swap, filetype = -1, normalize = 0;
487 long onset = 0, nframes = 0x7fffffff;
488 t_symbol *filesym;
489 float rate = -1;
490
491 while (argc > 0 && argv->a_type == A_SYMBOL &&
492 *argv->a_w.w_symbol->s_name == '-')
493 {
494 char *flag = argv->a_w.w_symbol->s_name + 1;
495 if (!strcmp(flag, "skip"))
496 {
497 if (argc < 2 || argv[1].a_type != A_FLOAT ||
498 ((onset = argv[1].a_w.w_float) < 0))
499 goto usage;
500 argc -= 2; argv += 2;
501 }
502 else if (!strcmp(flag, "nframes"))
503 {
504 if (argc < 2 || argv[1].a_type != A_FLOAT ||
505 ((nframes = argv[1].a_w.w_float) < 0))
506 goto usage;
507 argc -= 2; argv += 2;
508 }
509 else if (!strcmp(flag, "bytes"))
510 {
511 if (argc < 2 || argv[1].a_type != A_FLOAT ||
512 ((bytespersamp = argv[1].a_w.w_float) < 2) ||
513 bytespersamp > 4)
514 goto usage;
515 argc -= 2; argv += 2;
516 }
517 else if (!strcmp(flag, "normalize"))
518 {
519 normalize = 1;
520 argc -= 1; argv += 1;
521 }
522 else if (!strcmp(flag, "wave"))
523 {
524 filetype = FORMAT_WAVE;
525 argc -= 1; argv += 1;
526 }
527 else if (!strcmp(flag, "nextstep"))
528 {
529 filetype = FORMAT_NEXT;
530 argc -= 1; argv += 1;
531 }
532 else if (!strcmp(flag, "aiff"))
533 {
534 filetype = FORMAT_AIFF;
535 argc -= 1; argv += 1;
536 }
537 else if (!strcmp(flag, "big"))
538 {
539 endianness = 1;
540 argc -= 1; argv += 1;
541 }
542 else if (!strcmp(flag, "little"))
543 {
544 endianness = 0;
545 argc -= 1; argv += 1;
546 }
547 else if (!strcmp(flag, "r") || !strcmp(flag, "rate"))
548 {
549 if (argc < 2 || argv[1].a_type != A_FLOAT ||
550 ((rate = argv[1].a_w.w_float) <= 0))
551 goto usage;
552 argc -= 2; argv += 2;
553 }
554 else goto usage;
555 }
556 if (!argc || argv->a_type != A_SYMBOL)
557 goto usage;
558 filesym = argv->a_w.w_symbol;
559
560 /* check if format not specified and fill in */
561 if (filetype < 0)
562 {
563 if (strlen(filesym->s_name) >= 5 &&
564 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") ||
565 !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF")))
566 filetype = FORMAT_AIFF;
567 if (strlen(filesym->s_name) >= 6 &&
568 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") ||
569 !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF")))
570 filetype = FORMAT_AIFF;
571 if (strlen(filesym->s_name) >= 5 &&
572 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") ||
573 !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND")))
574 filetype = FORMAT_NEXT;
575 if (strlen(filesym->s_name) >= 4 &&
576 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") ||
577 !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU")))
578 filetype = FORMAT_NEXT;
579 if (filetype < 0)
580 filetype = FORMAT_WAVE;
581 }
582 /* don't handle AIFF floating point samples */
583 if (bytespersamp == 4)
584 {
585 if (filetype == FORMAT_AIFF)
586 {
587 pd_error(obj, "AIFF floating-point file format unavailable");
588 goto usage;
589 }
590 }
591 /* for WAVE force little endian; for nextstep use machine native */
592 if (filetype == FORMAT_WAVE)
593 {
594 bigendian = 0;
595 if (endianness == 1)
596 pd_error(obj, "WAVE file forced to little endian");
597 }
598 else if (filetype == FORMAT_AIFF)
599 {
600 bigendian = 1;
601 if (endianness == 0)
602 pd_error(obj, "AIFF file forced to big endian");
603 }
604 else if (endianness == -1)
605 {
606 bigendian = garray_ambigendian();
607 }
608 else bigendian = endianness;
609 swap = (bigendian != garray_ambigendian());
610
611 argc--; argv++;
612
613 *p_argc = argc;
614 *p_argv = argv;
615 *p_filesym = filesym;
616 *p_filetype = filetype;
617 *p_bytespersamp = bytespersamp;
618 *p_swap = swap;
619 *p_normalize = normalize;
620 *p_onset = onset;
621 *p_nframes = nframes;
622 *p_bigendian = bigendian;
623 *p_rate = rate;
624 return (0);
625usage:
626 return (-1);
627}
628
629static int create_soundfile(t_canvas *canvas, const char *filename,
630 int filetype, int nframes, int bytespersamp,
631 int bigendian, int nchannels, int swap, float samplerate)
632{
633 char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
634 char headerbuf[WRITEHDRSIZE];
635 t_wave *wavehdr = (t_wave *)headerbuf;
636 t_nextstep *nexthdr = (t_nextstep *)headerbuf;
637 t_aiff *aiffhdr = (t_aiff *)headerbuf;
638 int fd, headersize = 0;
639
640 strncpy(filenamebuf, filename, MAXPDSTRING-10);
641 filenamebuf[MAXPDSTRING-10] = 0;
642
643 if (filetype == FORMAT_NEXT)
644 {
645 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
646 strcat(filenamebuf, ".snd");
647 if (bigendian)
648 strncpy(nexthdr->ns_fileid, ".snd", 4);
649 else strncpy(nexthdr->ns_fileid, "dns.", 4);
650 nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
651 nexthdr->ns_length = 0;
652 nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
653 (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);
654 nexthdr->ns_sr = swap4(samplerate, swap);
655 nexthdr->ns_nchans = swap4(nchannels, swap);
656 strcpy(nexthdr->ns_info, "Pd ");
657 swapstring(nexthdr->ns_info, swap);
658 headersize = sizeof(t_nextstep);
659 }
660 else if (filetype == FORMAT_AIFF)
661 {
662 long datasize = nframes * nchannels * bytespersamp;
663 long longtmp;
664 static unsigned char dogdoo[] =
665 {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
666 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
667 strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
668 strcat(filenamebuf, ".aif");
669 strncpy(aiffhdr->a_fileid, "FORM", 4);
670 aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
671 strncpy(aiffhdr->a_aiffid, "AIFF", 4);
672 strncpy(aiffhdr->a_fmtid, "COMM", 4);
673 aiffhdr->a_fmtchunksize = swap4(18, swap);
674 aiffhdr->a_nchannels = swap2(nchannels, swap);
675 longtmp = swap4(nframes, swap);
676 memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
677 aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
678 memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
679 longtmp = swap4(datasize, swap);
680 memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
681 headersize = AIFFPLUS;
682 }
683 else /* WAVE format */
684 {
685 long datasize = nframes * nchannels * bytespersamp;
686 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
687 strcat(filenamebuf, ".wav");
688 strncpy(wavehdr->w_fileid, "RIFF", 4);
689 wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
690 strncpy(wavehdr->w_waveid, "WAVE", 4);
691 strncpy(wavehdr->w_fmtid, "fmt ", 4);
692 wavehdr->w_fmtchunksize = swap4(16, swap);
693 wavehdr->w_fmttag =
694 swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap);
695 wavehdr->w_nchannels = swap2(nchannels, swap);
696 wavehdr->w_samplespersec = swap4(samplerate, swap);
697 wavehdr->w_navgbytespersec =
698 swap4((int)(samplerate * nchannels * bytespersamp), swap);
699 wavehdr->w_nblockalign = swap2(nchannels * bytespersamp, swap);
700 wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
701 strncpy(wavehdr->w_datachunkid, "data", 4);
702 wavehdr->w_datachunksize = swap4(datasize, swap);
703 headersize = sizeof(t_wave);
704 }
705
706 canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
707 sys_bashfilename(buf2, buf2);
708 if ((fd = open(buf2, BINCREATE, 0666)) < 0)
709 return (-1);
710
711 if (write(fd, headerbuf, headersize) < headersize)
712 {
713 close (fd);
714 return (-1);
715 }
716 return (fd);
717}
718
719static void soundfile_finishwrite(void *obj, char *filename, int fd,
720 int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
721{
722 if (itemswritten < nframes)
723 {
724 if (nframes < 0x7fffffff)
725 pd_error(obj, "soundfiler_write: %d out of %d bytes written",
726 itemswritten, nframes);
727 /* try to fix size fields in header */
728 if (filetype == FORMAT_WAVE)
729 {
730 long datasize = itemswritten * bytesperframe, mofo;
731
732 if (lseek(fd,
733 ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
734 SEEK_SET) == 0)
735 goto baddonewrite;
736 mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
737 if (write(fd, (char *)(&mofo), 4) < 4)
738 goto baddonewrite;
739 if (lseek(fd,
740 ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
741 SEEK_SET) == 0)
742 goto baddonewrite;
743 mofo = swap4(datasize, swap);
744 if (write(fd, (char *)(&mofo), 4) < 4)
745 goto baddonewrite;
746 }
747 if (filetype == FORMAT_AIFF)
748 {
749 long mofo;
750 if (lseek(fd,
751 ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
752 SEEK_SET) == 0)
753 goto baddonewrite;
754 mofo = swap4(nframes, swap);
755 if (write(fd, (char *)(&mofo), 4) < 4)
756 goto baddonewrite;
757 }
758 if (filetype == FORMAT_NEXT)
759 {
760 /* do it the lazy way: just set the size field to 'unknown size'*/
761 uint32 nextsize = 0xffffffff;
762 if (lseek(fd, 8, SEEK_SET) == 0)
763 {
764 goto baddonewrite;
765 }
766 if (write(fd, &nextsize, 4) < 4)
767 {
768 goto baddonewrite;
769 }
770 }
771 }
772 return;
773baddonewrite:
774 post("%s: %s", filename, strerror(errno));
775}
776
777static void soundfile_xferout(int nchannels, t_sample **vecs,
778 unsigned char *buf, int nitems, long onset, int bytespersamp,
779 int bigendian, float normalfactor)
780{
781 int i, j;
782 unsigned char *sp, *sp2;
783 t_sample *fp;
784 int bytesperframe = bytespersamp * nchannels;
785 long xx;
786 for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
787 {
788 if (bytespersamp == 2)
789 {
790 float ff = normalfactor * 32768.;
791 if (bigendian)
792 {
793 for (j = 0, sp2 = sp, fp = vecs[i] + onset;
794 j < nitems; j++, sp2 += bytesperframe, fp++)
795 {
796 int xx = 32768. + (*fp * ff);
797 xx -= 32768;
798 if (xx < -32767)
799 xx = -32767;
800 if (xx > 32767)
801 xx = 32767;
802 sp2[0] = (xx >> 8);
803 sp2[1] = xx;
804 }
805 }
806 else
807 {
808 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
809 j < nitems; j++, sp2 += bytesperframe, fp++)
810 {
811 int xx = 32768. + (*fp * ff);
812 xx -= 32768;
813 if (xx < -32767)
814 xx = -32767;
815 if (xx > 32767)
816 xx = 32767;
817 sp2[1] = (xx >> 8);
818 sp2[0] = xx;
819 }
820 }
821 }
822 else if (bytespersamp == 3)
823 {
824 float ff = normalfactor * 8388608.;
825 if (bigendian)
826 {
827 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
828 j < nitems; j++, sp2 += bytesperframe, fp++)
829 {
830 int xx = 8388608. + (*fp * ff);
831 xx -= 8388608;
832 if (xx < -8388607)
833 xx = -8388607;
834 if (xx > 8388607)
835 xx = 8388607;
836 sp2[0] = (xx >> 16);
837 sp2[1] = (xx >> 8);
838 sp2[2] = xx;
839 }
840 }
841 else
842 {
843 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
844 j < nitems; j++, sp2 += bytesperframe, fp++)
845 {
846 int xx = 8388608. + (*fp * ff);
847 xx -= 8388608;
848 if (xx < -8388607)
849 xx = -8388607;
850 if (xx > 8388607)
851 xx = 8388607;
852 sp2[2] = (xx >> 16);
853 sp2[1] = (xx >> 8);
854 sp2[0] = xx;
855 }
856 }
857 }
858 else if (bytespersamp == 4)
859 {
860 if (bigendian)
861 {
862 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
863 j < nitems; j++, sp2 += bytesperframe, fp++)
864 {
865 float f2 = *fp * normalfactor;
866 xx = *(long *)&f2;
867 sp2[0] = (xx >> 24); sp2[1] = (xx >> 16);
868 sp2[2] = (xx >> 8); sp2[3] = xx;
869 }
870 }
871 else
872 {
873 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
874 j < nitems; j++, sp2 += bytesperframe, fp++)
875 {
876 float f2 = *fp * normalfactor;
877 xx = *(long *)&f2;
878 sp2[3] = (xx >> 24); sp2[2] = (xx >> 16);
879 sp2[1] = (xx >> 8); sp2[0] = xx;
880 }
881 }
882 }
883 }
884}
885
886
887/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
888#define DEFMAXSIZE 4000000 /* default maximum 16 MB per channel */
889#define SAMPBUFSIZE 1024
890
891
892static t_class *soundfiler_class;
893
894typedef struct _soundfiler
895{
896 t_object x_obj;
897 t_canvas *x_canvas;
898} t_soundfiler;
899
900static t_soundfiler *soundfiler_new(void)
901{
902 t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class);
903 x->x_canvas = canvas_getcurrent();
904 outlet_new(&x->x_obj, &s_float);
905 return (x);
906}
907
908 /* soundfiler_read ...
909
910 usage: read [flags] filename table ...
911 flags:
912 -skip <frames> ... frames to skip in file
913 -nframes <frames>
914 -onset <frames> ... onset in table to read into (NOT DONE YET)
915 -raw <headersize channels bytes endian>
916 -resize
917 -maxsize <max-size>
918 */
919
920static void soundfiler_read(t_soundfiler *x, t_symbol *s,
921 int argc, t_atom *argv)
922{
923 int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
924 resize = 0, i, j;
925 long skipframes = 0, nframes = 0, finalsize = 0, itemsleft,
926 maxsize = DEFMAXSIZE, itemsread = 0, bytelimit = 0x7fffffff;
927 int fd = -1;
928 char endianness, *filename;
929 t_garray *garrays[MAXSFCHANS];
930 t_sample *vecs[MAXSFCHANS];
931 char sampbuf[SAMPBUFSIZE];
932 int bufframes, nitems;
933 FILE *fp;
934 while (argc > 0 && argv->a_type == A_SYMBOL &&
935 *argv->a_w.w_symbol->s_name == '-')
936 {
937 char *flag = argv->a_w.w_symbol->s_name + 1;
938 if (!strcmp(flag, "skip"))
939 {
940 if (argc < 2 || argv[1].a_type != A_FLOAT ||
941 ((skipframes = argv[1].a_w.w_float) < 0))
942 goto usage;
943 argc -= 2; argv += 2;
944 }
945 else if (!strcmp(flag, "nframes"))
946 {
947 if (argc < 2 || argv[1].a_type != A_FLOAT ||
948 ((nframes = argv[1].a_w.w_float) < 0))
949 goto usage;
950 argc -= 2; argv += 2;
951 }
952 else if (!strcmp(flag, "raw"))
953 {
954 if (argc < 5 ||
955 argv[1].a_type != A_FLOAT ||
956 ((headersize = argv[1].a_w.w_float) < 0) ||
957 argv[2].a_type != A_FLOAT ||
958 ((channels = argv[2].a_w.w_float) < 1) ||
959 (channels > MAXSFCHANS) ||
960 argv[3].a_type != A_FLOAT ||
961 ((bytespersamp = argv[3].a_w.w_float) < 2) ||
962 (bytespersamp > 4) ||
963 argv[4].a_type != A_SYMBOL ||
964 ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
965 && endianness != 'l' && endianness != 'n'))
966 goto usage;
967 if (endianness == 'b')
968 bigendian = 1;
969 else if (endianness == 'l')
970 bigendian = 0;
971 else
972 bigendian = garray_ambigendian();
973 argc -= 5; argv += 5;
974 }
975 else if (!strcmp(flag, "resize"))
976 {
977 resize = 1;
978 argc -= 1; argv += 1;
979 }
980 else if (!strcmp(flag, "maxsize"))
981 {
982 if (argc < 2 || argv[1].a_type != A_FLOAT ||
983 ((maxsize = argv[1].a_w.w_float) < 0))
984 goto usage;
985 resize = 1; /* maxsize implies resize. */
986 argc -= 2; argv += 2;
987 }
988 else goto usage;
989 }
990 if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
991 goto usage;
992 filename = argv[0].a_w.w_symbol->s_name;
993 argc--; argv++;
994
995 for (i = 0; i < argc; i++)
996 {
997 int vecsize;
998 if (argv[i].a_type != A_SYMBOL)
999 goto usage;
1000 if (!(garrays[i] =
1001 (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
1002 {
1003 pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
1004 goto done;
1005 }
1006 else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
1007 error("%s: bad template for tabwrite",
1008 argv[i].a_w.w_symbol->s_name);
1009 if (finalsize && finalsize != vecsize && !resize)
1010 {
1011 post("soundfiler_read: arrays have different lengths; resizing...");
1012 resize = 1;
1013 }
1014 finalsize = vecsize;
1015 }
1016 fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
1017 headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
1018 skipframes);
1019
1020 if (fd < 0)
1021 {
1022 pd_error(x, "soundfiler_read: %s: %s", filename, (errno == EIO ?
1023 "unknown or bad header format" : strerror(errno)));
1024 goto done;
1025 }
1026
1027 if (resize)
1028 {
1029 /* figure out what to resize to */
1030 long poswas, eofis, framesinfile;
1031
1032 poswas = lseek(fd, 0, SEEK_CUR);
1033 eofis = lseek(fd, 0, SEEK_END);
1034 if (poswas < 0 || eofis < 0)
1035 {
1036 pd_error(x, "lseek failed");
1037 goto done;
1038 }
1039 lseek(fd, poswas, SEEK_SET);
1040 framesinfile = (eofis - poswas) / (channels * bytespersamp);
1041 if (framesinfile > maxsize)
1042 {
1043 pd_error(x, "soundfiler_read: truncated to %d elements", maxsize);
1044 framesinfile = maxsize;
1045 }
1046 if (framesinfile > bytelimit / (channels * bytespersamp))
1047 framesinfile = bytelimit / (channels * bytespersamp);
1048 finalsize = framesinfile;
1049 for (i = 0; i < argc; i++)
1050 {
1051 int vecsize;
1052
1053 garray_resize(garrays[i], finalsize);
1054 /* for sanity's sake let's clear the save-in-patch flag here */
1055 garray_setsaveit(garrays[i], 0);
1056 garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
1057 /* if the resize failed, garray_resize reported the error */
1058 if (vecsize != framesinfile)
1059 {
1060 pd_error(x, "resize failed");
1061 goto done;
1062 }
1063 }
1064 }
1065 if (!finalsize) finalsize = 0x7fffffff;
1066 if (finalsize > bytelimit / (channels * bytespersamp))
1067 finalsize = bytelimit / (channels * bytespersamp);
1068 fp = fdopen(fd, "rb");
1069 bufframes = SAMPBUFSIZE / (channels * bytespersamp);
1070
1071 for (itemsread = 0; itemsread < finalsize; )
1072 {
1073 int thisread = finalsize - itemsread;
1074 thisread = (thisread > bufframes ? bufframes : thisread);
1075 nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
1076 if (nitems <= 0) break;
1077 soundfile_xferin(channels, argc, vecs, itemsread,
1078 (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
1079 itemsread += nitems;
1080 }
1081 /* zero out remaining elements of vectors */
1082
1083 for (i = 0; i < argc; i++)
1084 {
1085 int nzero, vecsize;
1086 garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
1087 for (j = itemsread; j < vecsize; j++)
1088 vecs[i][j] = 0;
1089 }
1090 /* zero out vectors in excess of number of channels */
1091 for (i = channels; i < argc; i++)
1092 {
1093 int vecsize;
1094 t_sample *foo;
1095 garray_getfloatarray(garrays[i], &vecsize, &foo);
1096 for (j = 0; j < vecsize; j++)
1097 foo[j] = 0;
1098 }
1099 /* do all graphics updates */
1100 for (i = 0; i < argc; i++)
1101 garray_redraw(garrays[i]);
1102 fclose(fp);
1103 fd = -1;
1104 goto done;
1105usage:
1106 pd_error(x, "usage: read [flags] filename tablename...");
1107 post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
1108 post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
1109done:
1110 if (fd >= 0)
1111 close (fd);
1112 outlet_float(x->x_obj.ob_outlet, (float)itemsread);
1113}
1114
1115 /* this is broken out from soundfiler_write below so garray_write can
1116 call it too... not done yet though. */
1117
1118long soundfiler_dowrite(void *obj, t_canvas *canvas,
1119 int argc, t_atom *argv)
1120{
1121 int headersize, bytespersamp, bigendian,
1122 endianness, swap, filetype, normalize, i, j, nchannels;
1123 long onset, nframes, itemsleft,
1124 maxsize = DEFMAXSIZE, itemswritten = 0;
1125 t_garray *garrays[MAXSFCHANS];
1126 t_sample *vecs[MAXSFCHANS];
1127 char sampbuf[SAMPBUFSIZE];
1128 int bufframes, nitems;
1129 int fd = -1;
1130 float normfactor, biggest = 0, samplerate;
1131 t_symbol *filesym;
1132
1133 if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
1134 &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,
1135 &samplerate))
1136 goto usage;
1137 nchannels = argc;
1138 if (nchannels < 1 || nchannels > MAXSFCHANS)
1139 goto usage;
1140 if (samplerate < 0)
1141 samplerate = sys_getsr();
1142 for (i = 0; i < nchannels; i++)
1143 {
1144 int vecsize;
1145 if (argv[i].a_type != A_SYMBOL)
1146 goto usage;
1147 if (!(garrays[i] =
1148 (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
1149 {
1150 pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
1151 goto fail;
1152 }
1153 else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
1154 error("%s: bad template for tabwrite",
1155 argv[i].a_w.w_symbol->s_name);
1156 if (nframes > vecsize - onset)
1157 nframes = vecsize - onset;
1158
1159 for (j = 0; j < vecsize; j++)
1160 {
1161 if (vecs[i][j] > biggest)
1162 biggest = vecs[i][j];
1163 else if (-vecs[i][j] > biggest)
1164 biggest = -vecs[i][j];
1165 }
1166 }
1167 if (nframes <= 0)
1168 {
1169 pd_error(obj, "soundfiler_write: no samples at onset %ld", onset);
1170 goto fail;
1171 }
1172
1173 if ((fd = create_soundfile(canvas, filesym->s_name, filetype,
1174 nframes, bytespersamp, bigendian, nchannels,
1175 swap, samplerate)) < 0)
1176 {
1177 post("%s: %s\n", filesym->s_name, strerror(errno));
1178 goto fail;
1179 }
1180 if (!normalize)
1181 {
1182 if ((bytespersamp != 4) && (biggest > 1))
1183 {
1184 post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
1185 normalize = 1;
1186 }
1187 else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
1188 }
1189 if (normalize)
1190 normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
1191 else normfactor = 1;
1192
1193 bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
1194
1195 for (itemswritten = 0; itemswritten < nframes; )
1196 {
1197 int thiswrite = nframes - itemswritten, nitems, nbytes;
1198 thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
1199 soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
1200 onset, bytespersamp, bigendian, normfactor);
1201 nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
1202 if (nbytes < nchannels * bytespersamp * thiswrite)
1203 {
1204 post("%s: %s", filesym->s_name, strerror(errno));
1205 if (nbytes > 0)
1206 itemswritten += nbytes / (nchannels * bytespersamp);
1207 break;
1208 }
1209 itemswritten += thiswrite;
1210 onset += thiswrite;
1211 }
1212 if (fd >= 0)
1213 {
1214 soundfile_finishwrite(obj, filesym->s_name, fd,
1215 filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
1216 close (fd);
1217 }
1218 return ((float)itemswritten);
1219usage:
1220 pd_error(obj, "usage: write [flags] filename tablename...");
1221 post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
1222 post("-big -little -normalize");
1223 post("(defaults to a 16-bit wave file).");
1224fail:
1225 if (fd >= 0)
1226 close (fd);
1227 return (0);
1228}
1229
1230static void soundfiler_write(t_soundfiler *x, t_symbol *s,
1231 int argc, t_atom *argv)
1232{
1233 long bozo = soundfiler_dowrite(x, x->x_canvas,
1234 argc, argv);
1235 outlet_float(x->x_obj.ob_outlet, (float)bozo);
1236}
1237
1238static void soundfiler_setup(void)
1239{
1240 soundfiler_class = class_new(gensym("soundfiler"), (t_newmethod)soundfiler_new,
1241 0, sizeof(t_soundfiler), 0, 0);
1242 class_addmethod(soundfiler_class, (t_method)soundfiler_read, gensym("read"),
1243 A_GIMME, 0);
1244 class_addmethod(soundfiler_class, (t_method)soundfiler_write,
1245 gensym("write"), A_GIMME, 0);
1246}
1247
1248
1249#ifndef FIXEDPOINT
1250/************************* readsf object ******************************/
1251
1252/* READSF uses the Posix threads package; for the moment we're Linux
1253only although this should be portable to the other platforms.
1254
1255Each instance of readsf~ owns a "child" thread for doing the UNIX (MSW?) file
1256reading. The parent thread signals the child each time:
1257 (1) a file wants opening or closing;
1258 (2) we've eaten another 1/16 of the shared buffer (so that the
1259 child thread should check if it's time to read some more.)
1260The child signals the parent whenever a read has completed. Signalling
1261is done by setting "conditions" and putting data in mutex-controlled common
1262areas.
1263*/
1264
1265#define MAXBYTESPERSAMPLE 4
1266#define MAXVECSIZE 128
1267
1268#define READSIZE 65536
1269#define WRITESIZE 65536
1270#define DEFBUFPERCHAN 262144
1271#define MINBUFSIZE (4 * READSIZE)
1272#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
1273
1274#define REQUEST_NOTHING 0
1275#define REQUEST_OPEN 1
1276#define REQUEST_CLOSE 2
1277#define REQUEST_QUIT 3
1278#define REQUEST_BUSY 4
1279
1280#define STATE_IDLE 0
1281#define STATE_STARTUP 1
1282#define STATE_STREAM 2
1283
1284static t_class *readsf_class;
1285
1286typedef struct _readsf
1287{
1288 t_object x_obj;
1289 t_canvas *x_canvas;
1290 t_clock *x_clock;
1291 char *x_buf; /* soundfile buffer */
1292 int x_bufsize; /* buffer size in bytes */
1293 int x_noutlets; /* number of audio outlets */
1294 t_sample *(x_outvec[MAXSFCHANS]); /* audio vectors */
1295 int x_vecsize; /* vector size for transfers */
1296 t_outlet *x_bangout; /* bang-on-done outlet */
1297 int x_state; /* opened, running, or idle */
1298 float x_insamplerate; /* sample rate of input signal if known */
1299 /* parameters to communicate with subthread */
1300 int x_requestcode; /* pending request from parent to I/O thread */
1301 char *x_filename; /* file to open (string is permanently allocated) */
1302 int x_fileerror; /* slot for "errno" return */
1303 int x_skipheaderbytes; /* size of header we'll skip */
1304 int x_bytespersample; /* bytes per sample (2 or 3) */
1305 int x_bigendian; /* true if file is big-endian */
1306 int x_sfchannels; /* number of channels in soundfile */
1307 float x_samplerate; /* sample rate of soundfile */
1308 long x_onsetframes; /* number of sample frames to skip */
1309 long x_bytelimit; /* max number of data bytes to read */
1310 int x_fd; /* filedesc */
1311 int x_fifosize; /* buffer size appropriately rounded down */
1312 int x_fifohead; /* index of next byte to get from file */
1313 int x_fifotail; /* index of next byte the ugen will read */
1314 int x_eof; /* true if fifohead has stopped changing */
1315 int x_sigcountdown; /* counter for signalling child for more data */
1316 int x_sigperiod; /* number of ticks per signal */
1317 int x_filetype; /* writesf~ only; type of file to create */
1318 int x_itemswritten; /* writesf~ only; items writen */
1319 int x_swap; /* writesf~ only; true if byte swapping */
1320 float x_f; /* writesf~ only; scalar for signal inlet */
1321 pthread_mutex_t x_mutex;
1322 pthread_cond_t x_requestcondition;
1323 pthread_cond_t x_answercondition;
1324 pthread_t x_childthread;
1325} t_readsf;
1326
1327
1328/************** the child thread which performs file I/O ***********/
1329
1330#if 0
1331static void pute(char *s) /* debug routine */
1332{
1333 write(2, s, strlen(s));
1334}
1335#define DEBUG_SOUNDFILE
1336#endif
1337
1338#if 1
1339#define sfread_cond_wait pthread_cond_wait
1340#define sfread_cond_signal pthread_cond_signal
1341#else
1342#include <sys/time.h> /* debugging version... */
1343#include <sys/types.h>
1344static void readsf_fakewait(pthread_mutex_t *b)
1345{
1346 struct timeval timout;
1347 timout.tv_sec = 0;
1348 timout.tv_usec = 1000000;
1349 pthread_mutex_unlock(b);
1350 select(0, 0, 0, 0, &timout);
1351 pthread_mutex_lock(b);
1352}
1353
1354#define sfread_cond_wait(a,b) readsf_fakewait(b)
1355#define sfread_cond_signal(a)
1356#endif
1357
1358static void *readsf_child_main(void *zz)
1359{
1360 t_readsf *x = zz;
1361#ifdef DEBUG_SOUNDFILE
1362 pute("1\n");
1363#endif
1364 pthread_mutex_lock(&x->x_mutex);
1365 while (1)
1366 {
1367 int fd, fifohead;
1368 char *buf;
1369#ifdef DEBUG_SOUNDFILE
1370 pute("0\n");
1371#endif
1372 if (x->x_requestcode == REQUEST_NOTHING)
1373 {
1374#ifdef DEBUG_SOUNDFILE
1375 pute("wait 2\n");
1376#endif
1377 sfread_cond_signal(&x->x_answercondition);
1378 sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
1379#ifdef DEBUG_SOUNDFILE
1380 pute("3\n");
1381#endif
1382 }
1383 else if (x->x_requestcode == REQUEST_OPEN)
1384 {
1385 char boo[80];
1386 int sysrtn, wantbytes;
1387
1388 /* copy file stuff out of the data structure so we can
1389 relinquish the mutex while we're in open_soundfile(). */
1390 long onsetframes = x->x_onsetframes;
1391 long bytelimit = 0x7fffffff;
1392 int skipheaderbytes = x->x_skipheaderbytes;
1393 int bytespersample = x->x_bytespersample;
1394 int sfchannels = x->x_sfchannels;
1395 int bigendian = x->x_bigendian;
1396 char *filename = x->x_filename;
1397 char *dirname = canvas_getdir(x->x_canvas)->s_name;
1398 /* alter the request code so that an ensuing "open" will get
1399 noticed. */
1400#ifdef DEBUG_SOUNDFILE
1401 pute("4\n");
1402#endif
1403 x->x_requestcode = REQUEST_BUSY;
1404 x->x_fileerror = 0;
1405
1406 /* if there's already a file open, close it */
1407 if (x->x_fd >= 0)
1408 {
1409 fd = x->x_fd;
1410 pthread_mutex_unlock(&x->x_mutex);
1411 close (fd);
1412 pthread_mutex_lock(&x->x_mutex);
1413 x->x_fd = -1;
1414 if (x->x_requestcode != REQUEST_BUSY)
1415 goto lost;
1416 }
1417 /* open the soundfile with the mutex unlocked */
1418 pthread_mutex_unlock(&x->x_mutex);
1419 fd = open_soundfile(dirname, filename,
1420 skipheaderbytes, &bytespersample, &bigendian,
1421 &sfchannels, &bytelimit, onsetframes);
1422 pthread_mutex_lock(&x->x_mutex);
1423
1424#ifdef DEBUG_SOUNDFILE
1425 pute("5\n");
1426#endif
1427 /* copy back into the instance structure. */
1428 x->x_bytespersample = bytespersample;
1429 x->x_sfchannels = sfchannels;
1430 x->x_bigendian = bigendian;
1431 x->x_fd = fd;
1432 x->x_bytelimit = bytelimit;
1433 if (fd < 0)
1434 {
1435 x->x_fileerror = errno;
1436 x->x_eof = 1;
1437#ifdef DEBUG_SOUNDFILE
1438 pute("open failed\n");
1439 pute(filename);
1440 pute(dirname);
1441#endif
1442 goto lost;
1443 }
1444 /* check if another request has been made; if so, field it */
1445 if (x->x_requestcode != REQUEST_BUSY)
1446 goto lost;
1447#ifdef DEBUG_SOUNDFILE
1448 pute("6\n");
1449#endif
1450 x->x_fifohead = 0;
1451 /* set fifosize from bufsize. fifosize must be a
1452 multiple of the number of bytes eaten for each DSP
1453 tick. We pessimistically assume MAXVECSIZE samples
1454 per tick since that could change. There could be a
1455 problem here if the vector size increases while a
1456 soundfile is being played... */
1457 x->x_fifosize = x->x_bufsize - (x->x_bufsize %
1458 (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
1459 /* arrange for the "request" condition to be signalled 16
1460 times per buffer */
1461#ifdef DEBUG_SOUNDFILE
1462 sprintf(boo, "fifosize %d\n",
1463 x->x_fifosize);
1464 pute(boo);
1465#endif
1466 x->x_sigcountdown = x->x_sigperiod =
1467 (x->x_fifosize /
1468 (16 * x->x_bytespersample * x->x_sfchannels *
1469 x->x_vecsize));
1470 /* in a loop, wait for the fifo to get hungry and feed it */
1471
1472 while (x->x_requestcode == REQUEST_BUSY)
1473 {
1474 int fifosize = x->x_fifosize;
1475#ifdef DEBUG_SOUNDFILE
1476 pute("77\n");
1477#endif
1478 if (x->x_eof)
1479 break;
1480 if (x->x_fifohead >= x->x_fifotail)
1481 {
1482 /* if the head is >= the tail, we can immediately read
1483 to the end of the fifo. Unless, that is, we would
1484 read all the way to the end of the buffer and the
1485 "tail" is zero; this would fill the buffer completely
1486 which isn't allowed because you can't tell a completely
1487 full buffer from an empty one. */
1488 if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE))
1489 {
1490 wantbytes = fifosize - x->x_fifohead;
1491 if (wantbytes > READSIZE)
1492 wantbytes = READSIZE;
1493 if (wantbytes > x->x_bytelimit)
1494 wantbytes = x->x_bytelimit;
1495#ifdef DEBUG_SOUNDFILE
1496 sprintf(boo, "head %d, tail %d, size %d\n",
1497 x->x_fifohead, x->x_fifotail, wantbytes);
1498 pute(boo);
1499#endif
1500 }
1501 else
1502 {
1503#ifdef DEBUG_SOUNDFILE
1504 pute("wait 7a ...\n");
1505#endif
1506 sfread_cond_signal(&x->x_answercondition);
1507#ifdef DEBUG_SOUNDFILE
1508 pute("signalled\n");
1509#endif
1510 sfread_cond_wait(&x->x_requestcondition,
1511 &x->x_mutex);
1512#ifdef DEBUG_SOUNDFILE
1513 pute("7a done\n");
1514#endif
1515 continue;
1516 }
1517 }
1518 else
1519 {
1520 /* otherwise check if there are at least READSIZE
1521 bytes to read. If not, wait and loop back. */
1522 wantbytes = x->x_fifotail - x->x_fifohead - 1;
1523 if (wantbytes < READSIZE)
1524 {
1525#ifdef DEBUG_SOUNDFILE
1526 pute("wait 7...\n");
1527#endif
1528 sfread_cond_signal(&x->x_answercondition);
1529 sfread_cond_wait(&x->x_requestcondition,
1530 &x->x_mutex);
1531#ifdef DEBUG_SOUNDFILE
1532 pute("7 done\n");
1533#endif
1534 continue;
1535 }
1536 else wantbytes = READSIZE;
1537 if (wantbytes > x->x_bytelimit)
1538 wantbytes = x->x_bytelimit;
1539 }
1540#ifdef DEBUG_SOUNDFILE
1541 pute("8\n");
1542#endif
1543 fd = x->x_fd;
1544 buf = x->x_buf;
1545 fifohead = x->x_fifohead;
1546 pthread_mutex_unlock(&x->x_mutex);
1547 sysrtn = read(fd, buf + fifohead, wantbytes);
1548 pthread_mutex_lock(&x->x_mutex);
1549 if (x->x_requestcode != REQUEST_BUSY)
1550 break;
1551 if (sysrtn < 0)
1552 {
1553#ifdef DEBUG_SOUNDFILE
1554 pute("fileerror\n");
1555#endif
1556 x->x_fileerror = errno;
1557 break;
1558 }
1559 else if (sysrtn == 0)
1560 {
1561 x->x_eof = 1;
1562 break;
1563 }
1564 else
1565 {
1566 x->x_fifohead += sysrtn;
1567 x->x_bytelimit -= sysrtn;
1568 if (x->x_bytelimit <= 0)
1569 {
1570 x->x_eof = 1;
1571 break;
1572 }
1573 if (x->x_fifohead == fifosize)
1574 x->x_fifohead = 0;
1575 }
1576#ifdef DEBUG_SOUNDFILE
1577 sprintf(boo, "after: head %d, tail %d\n",
1578 x->x_fifohead, x->x_fifotail);
1579 pute(boo);
1580#endif
1581 /* signal parent in case it's waiting for data */
1582 sfread_cond_signal(&x->x_answercondition);
1583 }
1584 lost:
1585
1586 if (x->x_requestcode == REQUEST_BUSY)
1587 x->x_requestcode = REQUEST_NOTHING;
1588 /* fell out of read loop: close file if necessary,
1589 set EOF and signal once more */
1590 if (x->x_fd >= 0)
1591 {
1592 fd = x->x_fd;
1593 pthread_mutex_unlock(&x->x_mutex);
1594 close (fd);
1595 pthread_mutex_lock(&x->x_mutex);
1596 x->x_fd = -1;
1597 }
1598 sfread_cond_signal(&x->x_answercondition);
1599
1600 }
1601 else if (x->x_requestcode == REQUEST_CLOSE)
1602 {
1603 if (x->x_fd >= 0)
1604 {
1605 fd = x->x_fd;
1606 pthread_mutex_unlock(&x->x_mutex);
1607 close (fd);
1608 pthread_mutex_lock(&x->x_mutex);
1609 x->x_fd = -1;
1610 }
1611 if (x->x_requestcode == REQUEST_CLOSE)
1612 x->x_requestcode = REQUEST_NOTHING;
1613 sfread_cond_signal(&x->x_answercondition);
1614 }
1615 else if (x->x_requestcode == REQUEST_QUIT)
1616 {
1617 if (x->x_fd >= 0)
1618 {
1619 fd = x->x_fd;
1620 pthread_mutex_unlock(&x->x_mutex);
1621 close (fd);
1622 pthread_mutex_lock(&x->x_mutex);
1623 x->x_fd = -1;
1624 }
1625 x->x_requestcode = REQUEST_NOTHING;
1626 sfread_cond_signal(&x->x_answercondition);
1627 break;
1628 }
1629 else
1630 {
1631#ifdef DEBUG_SOUNDFILE
1632 pute("13\n");
1633#endif
1634 }
1635 }
1636#ifdef DEBUG_SOUNDFILE
1637 pute("thread exit\n");
1638#endif
1639 pthread_mutex_unlock(&x->x_mutex);
1640 return (0);
1641}
1642
1643/******** the object proper runs in the calling (parent) thread ****/
1644
1645static void readsf_tick(t_readsf *x);
1646
1647static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize)
1648{
1649 t_readsf *x;
1650 int nchannels = fnchannels, bufsize = fbufsize, i;
1651 char *buf;
1652
1653 if (nchannels < 1)
1654 nchannels = 1;
1655 else if (nchannels > MAXSFCHANS)
1656 nchannels = MAXSFCHANS;
1657 if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
1658 else if (bufsize < MINBUFSIZE)
1659 bufsize = MINBUFSIZE;
1660 else if (bufsize > MAXBUFSIZE)
1661 bufsize = MAXBUFSIZE;
1662 buf = getbytes(bufsize);
1663 if (!buf) return (0);
1664
1665 x = (t_readsf *)pd_new(readsf_class);
1666
1667 for (i = 0; i < nchannels; i++)
1668 outlet_new(&x->x_obj, gensym("signal"));
1669 x->x_noutlets = nchannels;
1670 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
1671 pthread_mutex_init(&x->x_mutex, 0);
1672 pthread_cond_init(&x->x_requestcondition, 0);
1673 pthread_cond_init(&x->x_answercondition, 0);
1674 x->x_vecsize = MAXVECSIZE;
1675 x->x_state = STATE_IDLE;
1676 x->x_clock = clock_new(x, (t_method)readsf_tick);
1677 x->x_canvas = canvas_getcurrent();
1678 x->x_bytespersample = 2;
1679 x->x_sfchannels = 1;
1680 x->x_fd = -1;
1681 x->x_buf = buf;
1682 x->x_bufsize = bufsize;
1683 x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
1684 pthread_create(&x->x_childthread, 0, readsf_child_main, x);
1685 return (x);
1686}
1687
1688static void readsf_tick(t_readsf *x)
1689{
1690 outlet_bang(x->x_bangout);
1691}
1692
1693static t_int *readsf_perform(t_int *w)
1694{
1695 t_readsf *x = (t_readsf *)(w[1]);
1696 int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j,
1697 bytespersample = x->x_bytespersample,
1698 bigendian = x->x_bigendian;
1699 float *fp;
1700 if (x->x_state == STATE_STREAM)
1701 {
1702 int wantbytes, nchannels, sfchannels = x->x_sfchannels;
1703 pthread_mutex_lock(&x->x_mutex);
1704 wantbytes = sfchannels * vecsize * bytespersample;
1705 while (
1706 !x->x_eof && x->x_fifohead >= x->x_fifotail &&
1707 x->x_fifohead < x->x_fifotail + wantbytes-1)
1708 {
1709#ifdef DEBUG_SOUNDFILE
1710 pute("wait...\n");
1711#endif
1712 sfread_cond_signal(&x->x_requestcondition);
1713 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
1714#ifdef DEBUG_SOUNDFILE
1715 pute("done\n");
1716#endif
1717 }
1718 if (x->x_eof && x->x_fifohead >= x->x_fifotail &&
1719 x->x_fifohead < x->x_fifotail + wantbytes-1)
1720 {
1721 int xfersize;
1722 if (x->x_fileerror)
1723 {
1724 pd_error(x, "dsp: %s: %s", x->x_filename,
1725 (x->x_fileerror == EIO ?
1726 "unknown or bad header format" :
1727 strerror(x->x_fileerror)));
1728 }
1729 clock_delay(x->x_clock, 0);
1730 x->x_state = STATE_IDLE;
1731
1732 /* if there's a partial buffer left, copy it out. */
1733 xfersize = (x->x_fifohead - x->x_fifotail + 1) /
1734 (sfchannels * bytespersample);
1735 if (xfersize)
1736 {
1737 soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
1738 (unsigned char *)(x->x_buf + x->x_fifotail), xfersize,
1739 bytespersample, bigendian);
1740 vecsize -= xfersize;
1741 }
1742 /* then zero out the (rest of the) output */
1743 for (i = 0; i < noutlets; i++)
1744 for (j = vecsize, fp = x->x_outvec[i] + xfersize; j--; )
1745 *fp++ = 0;
1746
1747 sfread_cond_signal(&x->x_requestcondition);
1748 pthread_mutex_unlock(&x->x_mutex);
1749 return (w+2);
1750 }
1751
1752 soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
1753 (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
1754 bytespersample, bigendian);
1755
1756 x->x_fifotail += wantbytes;
1757 if (x->x_fifotail >= x->x_fifosize)
1758 x->x_fifotail = 0;
1759 if ((--x->x_sigcountdown) <= 0)
1760 {
1761 sfread_cond_signal(&x->x_requestcondition);
1762 x->x_sigcountdown = x->x_sigperiod;
1763 }
1764 pthread_mutex_unlock(&x->x_mutex);
1765 }
1766 else
1767 {
1768 idle:
1769 for (i = 0; i < noutlets; i++)
1770 for (j = vecsize, fp = x->x_outvec[i]; j--; )
1771 *fp++ = 0;
1772 }
1773 return (w+2);
1774}
1775
1776static void readsf_start(t_readsf *x)
1777{
1778 /* start making output. If we're in the "startup" state change
1779 to the "running" state. */
1780 if (x->x_state == STATE_STARTUP)
1781 x->x_state = STATE_STREAM;
1782 else pd_error(x, "readsf: start requested with no prior 'open'");
1783}
1784
1785static void readsf_stop(t_readsf *x)
1786{
1787 /* LATER rethink whether you need the mutex just to set a variable? */
1788 pthread_mutex_lock(&x->x_mutex);
1789 x->x_state = STATE_IDLE;
1790 x->x_requestcode = REQUEST_CLOSE;
1791 sfread_cond_signal(&x->x_requestcondition);
1792 pthread_mutex_unlock(&x->x_mutex);
1793}
1794
1795static void readsf_float(t_readsf *x, t_floatarg f)
1796{
1797 if (f != 0)
1798 readsf_start(x);
1799 else readsf_stop(x);
1800}
1801
1802 /* open method. Called as:
1803 open filename [skipframes headersize channels bytespersamp endianness]
1804 (if headersize is zero, header is taken to be automatically
1805 detected; thus, use the special "-1" to mean a truly headerless file.)
1806 */
1807
1808static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv)
1809{
1810 t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
1811 t_float onsetframes = atom_getfloatarg(1, argc, argv);
1812 t_float headerbytes = atom_getfloatarg(2, argc, argv);
1813 t_float channels = atom_getfloatarg(3, argc, argv);
1814 t_float bytespersamp = atom_getfloatarg(4, argc, argv);
1815 t_symbol *endian = atom_getsymbolarg(5, argc, argv);
1816 if (!*filesym->s_name)
1817 return;
1818 pthread_mutex_lock(&x->x_mutex);
1819 x->x_requestcode = REQUEST_OPEN;
1820 x->x_filename = filesym->s_name;
1821 x->x_fifotail = 0;
1822 x->x_fifohead = 0;
1823 if (*endian->s_name == 'b')
1824 x->x_bigendian = 1;
1825 else if (*endian->s_name == 'l')
1826 x->x_bigendian = 0;
1827 else if (*endian->s_name)
1828 pd_error(x, "endianness neither 'b' nor 'l'");
1829 else x->x_bigendian = garray_ambigendian();
1830 x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0);
1831 x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes :
1832 (headerbytes == 0 ? -1 : 0));
1833 x->x_sfchannels = (channels >= 1 ? channels : 1);
1834 x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
1835 x->x_eof = 0;
1836 x->x_fileerror = 0;
1837 x->x_state = STATE_STARTUP;
1838 sfread_cond_signal(&x->x_requestcondition);
1839 pthread_mutex_unlock(&x->x_mutex);
1840}
1841
1842static void readsf_dsp(t_readsf *x, t_signal **sp)
1843{
1844 int i, noutlets = x->x_noutlets;
1845 pthread_mutex_lock(&x->x_mutex);
1846 x->x_vecsize = sp[0]->s_n;
1847
1848 x->x_sigperiod = (x->x_fifosize /
1849 (x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
1850 for (i = 0; i < noutlets; i++)
1851 x->x_outvec[i] = sp[i]->s_vec;
1852 pthread_mutex_unlock(&x->x_mutex);
1853 dsp_add(readsf_perform, 1, x);
1854}
1855
1856static void readsf_print(t_readsf *x)
1857{
1858 post("state %d", x->x_state);
1859 post("fifo head %d", x->x_fifohead);
1860 post("fifo tail %d", x->x_fifotail);
1861 post("fifo size %d", x->x_fifosize);
1862 post("fd %d", x->x_fd);
1863 post("eof %d", x->x_eof);
1864}
1865
1866static void readsf_free(t_readsf *x)
1867{
1868 /* request QUIT and wait for acknowledge */
1869 void *threadrtn;
1870 pthread_mutex_lock(&x->x_mutex);
1871 x->x_requestcode = REQUEST_QUIT;
1872 sfread_cond_signal(&x->x_requestcondition);
1873 while (x->x_requestcode != REQUEST_NOTHING)
1874 {
1875 sfread_cond_signal(&x->x_requestcondition);
1876 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
1877 }
1878 pthread_mutex_unlock(&x->x_mutex);
1879 if (pthread_join(x->x_childthread, &threadrtn))
1880 error("readsf_free: join failed");
1881
1882 pthread_cond_destroy(&x->x_requestcondition);
1883 pthread_cond_destroy(&x->x_answercondition);
1884 pthread_mutex_destroy(&x->x_mutex);
1885 freebytes(x->x_buf, x->x_bufsize);
1886 clock_free(x->x_clock);
1887}
1888
1889static void readsf_setup(void)
1890{
1891 readsf_class = class_new(gensym("readsf~"), (t_newmethod)readsf_new,
1892 (t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
1893 class_addfloat(readsf_class, (t_method)readsf_float);
1894 class_addmethod(readsf_class, (t_method)readsf_start, gensym("start"), 0);
1895 class_addmethod(readsf_class, (t_method)readsf_stop, gensym("stop"), 0);
1896 class_addmethod(readsf_class, (t_method)readsf_dsp, gensym("dsp"), 0);
1897 class_addmethod(readsf_class, (t_method)readsf_open, gensym("open"),
1898 A_GIMME, 0);
1899 class_addmethod(readsf_class, (t_method)readsf_print, gensym("print"), 0);
1900}
1901
1902/******************************* writesf *******************/
1903
1904static t_class *writesf_class;
1905
1906#define t_writesf t_readsf /* just re-use the structure */
1907
1908/************** the child thread which performs file I/O ***********/
1909
1910static void *writesf_child_main(void *zz)
1911{
1912 t_writesf *x = zz;
1913#ifdef DEBUG_SOUNDFILE
1914 pute("1\n");
1915#endif
1916 pthread_mutex_lock(&x->x_mutex);
1917 while (1)
1918 {
1919#ifdef DEBUG_SOUNDFILE
1920 pute("0\n");
1921#endif
1922 if (x->x_requestcode == REQUEST_NOTHING)
1923 {
1924#ifdef DEBUG_SOUNDFILE
1925 pute("wait 2\n");
1926#endif
1927 sfread_cond_signal(&x->x_answercondition);
1928 sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
1929#ifdef DEBUG_SOUNDFILE
1930 pute("3\n");
1931#endif
1932 }
1933 else if (x->x_requestcode == REQUEST_OPEN)
1934 {
1935 char boo[80];
1936 int fd, sysrtn, writebytes;
1937
1938 /* copy file stuff out of the data structure so we can
1939 relinquish the mutex while we're in open_soundfile(). */
1940 long onsetframes = x->x_onsetframes;
1941 long bytelimit = 0x7fffffff;
1942 int skipheaderbytes = x->x_skipheaderbytes;
1943 int bytespersample = x->x_bytespersample;
1944 int sfchannels = x->x_sfchannels;
1945 int bigendian = x->x_bigendian;
1946 int filetype = x->x_filetype;
1947 char *filename = x->x_filename;
1948 t_canvas *canvas = x->x_canvas;
1949 float samplerate = x->x_samplerate;
1950
1951 /* alter the request code so that an ensuing "open" will get
1952 noticed. */
1953#ifdef DEBUG_SOUNDFILE
1954 pute("4\n");
1955#endif
1956 x->x_requestcode = REQUEST_BUSY;
1957 x->x_fileerror = 0;
1958
1959 /* if there's already a file open, close it */
1960 if (x->x_fd >= 0)
1961 {
1962 pthread_mutex_unlock(&x->x_mutex);
1963 close (x->x_fd);
1964 pthread_mutex_lock(&x->x_mutex);
1965 x->x_fd = -1;
1966 if (x->x_requestcode != REQUEST_BUSY)
1967 continue;
1968 }
1969 /* open the soundfile with the mutex unlocked */
1970 pthread_mutex_unlock(&x->x_mutex);
1971 fd = create_soundfile(canvas, filename, filetype, 0,
1972 bytespersample, bigendian, sfchannels,
1973 garray_ambigendian() != bigendian, samplerate);
1974 pthread_mutex_lock(&x->x_mutex);
1975#ifdef DEBUG_SOUNDFILE
1976 pute("5\n");
1977#endif
1978
1979 if (fd < 0)
1980 {
1981 x->x_fd = -1;
1982 x->x_eof = 1;
1983 x->x_fileerror = errno;
1984#ifdef DEBUG_SOUNDFILE
1985 pute("open failed\n");
1986 pute(filename);
1987#endif
1988 x->x_requestcode = REQUEST_NOTHING;
1989 continue;
1990 }
1991 /* check if another request has been made; if so, field it */
1992 if (x->x_requestcode != REQUEST_BUSY)
1993 continue;
1994#ifdef DEBUG_SOUNDFILE
1995 pute("6\n");
1996#endif
1997 x->x_fd = fd;
1998 x->x_fifotail = 0;
1999 x->x_itemswritten = 0;
2000 x->x_swap = garray_ambigendian() != bigendian;
2001 /* in a loop, wait for the fifo to have data and write it
2002 to disk */
2003 while (x->x_requestcode == REQUEST_BUSY ||
2004 (x->x_requestcode == REQUEST_CLOSE &&
2005 x->x_fifohead != x->x_fifotail))
2006 {
2007 int fifosize = x->x_fifosize, fifotail;
2008 char *buf = x->x_buf;
2009#ifdef DEBUG_SOUNDFILE
2010 pute("77\n");
2011#endif
2012
2013 /* if the head is < the tail, we can immediately write
2014 from tail to end of fifo to disk; otherwise we hold off
2015 writing until there are at least WRITESIZE bytes in the
2016 buffer */
2017 if (x->x_fifohead < x->x_fifotail ||
2018 x->x_fifohead >= x->x_fifotail + WRITESIZE
2019 || (x->x_requestcode == REQUEST_CLOSE &&
2020 x->x_fifohead != x->x_fifotail))
2021 {
2022 writebytes = (x->x_fifohead < x->x_fifotail ?
2023 fifosize : x->x_fifohead) - x->x_fifotail;
2024 if (writebytes > READSIZE)
2025 writebytes = READSIZE;
2026 }
2027 else
2028 {
2029#ifdef DEBUG_SOUNDFILE
2030 pute("wait 7a ...\n");
2031#endif
2032 sfread_cond_signal(&x->x_answercondition);
2033#ifdef DEBUG_SOUNDFILE
2034 pute("signalled\n");
2035#endif
2036 sfread_cond_wait(&x->x_requestcondition,
2037 &x->x_mutex);
2038#ifdef DEBUG_SOUNDFILE
2039 pute("7a done\n");
2040#endif
2041 continue;
2042 }
2043#ifdef DEBUG_SOUNDFILE
2044 pute("8\n");
2045#endif
2046 fifotail = x->x_fifotail;
2047 fd = x->x_fd;
2048 pthread_mutex_unlock(&x->x_mutex);
2049 sysrtn = write(fd, buf + fifotail, writebytes);
2050 pthread_mutex_lock(&x->x_mutex);
2051 if (x->x_requestcode != REQUEST_BUSY &&
2052 x->x_requestcode != REQUEST_CLOSE)
2053 break;
2054 if (sysrtn < writebytes)
2055 {
2056#ifdef DEBUG_SOUNDFILE
2057 pute("fileerror\n");
2058#endif
2059 x->x_fileerror = errno;
2060 break;
2061 }
2062 else
2063 {
2064 x->x_fifotail += sysrtn;
2065 if (x->x_fifotail == fifosize)
2066 x->x_fifotail = 0;
2067 }
2068 x->x_itemswritten +=
2069 sysrtn / (x->x_bytespersample * x->x_sfchannels);
2070 sprintf(boo, "after: head %d, tail %d\n",
2071 x->x_fifohead, x->x_fifotail);
2072#ifdef DEBUG_SOUNDFILE
2073 pute(boo);
2074#endif
2075 /* signal parent in case it's waiting for data */
2076 sfread_cond_signal(&x->x_answercondition);
2077 }
2078 }
2079 else if (x->x_requestcode == REQUEST_CLOSE ||
2080 x->x_requestcode == REQUEST_QUIT)
2081 {
2082 int quit = (x->x_requestcode == REQUEST_QUIT);
2083 if (x->x_fd >= 0)
2084 {
2085 int bytesperframe = x->x_bytespersample * x->x_sfchannels;
2086 int bigendian = x->x_bigendian;
2087 char *filename = x->x_filename;
2088 int fd = x->x_fd;
2089 int filetype = x->x_filetype;
2090 int itemswritten = x->x_itemswritten;
2091 int swap = x->x_swap;
2092 pthread_mutex_unlock(&x->x_mutex);
2093
2094 soundfile_finishwrite(x, filename, fd,
2095 filetype, 0x7fffffff, itemswritten,
2096 bytesperframe, swap);
2097 close (fd);
2098
2099 pthread_mutex_lock(&x->x_mutex);
2100 x->x_fd = -1;
2101 }
2102 x->x_requestcode = REQUEST_NOTHING;
2103 sfread_cond_signal(&x->x_answercondition);
2104 if (quit)
2105 break;
2106 }
2107 else
2108 {
2109#ifdef DEBUG_SOUNDFILE
2110 pute("13\n");
2111#endif
2112 }
2113 }
2114#ifdef DEBUG_SOUNDFILE
2115 pute("thread exit\n");
2116#endif
2117 pthread_mutex_unlock(&x->x_mutex);
2118 return (0);
2119}
2120
2121/******** the object proper runs in the calling (parent) thread ****/
2122
2123static void writesf_tick(t_writesf *x);
2124
2125static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize)
2126{
2127 t_writesf *x;
2128 int nchannels = fnchannels, bufsize = fbufsize, i;
2129 char *buf;
2130
2131 if (nchannels < 1)
2132 nchannels = 1;
2133 else if (nchannels > MAXSFCHANS)
2134 nchannels = MAXSFCHANS;
2135 if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
2136 else if (bufsize < MINBUFSIZE)
2137 bufsize = MINBUFSIZE;
2138 else if (bufsize > MAXBUFSIZE)
2139 bufsize = MAXBUFSIZE;
2140 buf = getbytes(bufsize);
2141 if (!buf) return (0);
2142
2143 x = (t_writesf *)pd_new(writesf_class);
2144
2145 for (i = 1; i < nchannels; i++)
2146 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
2147
2148 x->x_f = 0;
2149 x->x_sfchannels = nchannels;
2150 pthread_mutex_init(&x->x_mutex, 0);
2151 pthread_cond_init(&x->x_requestcondition, 0);
2152 pthread_cond_init(&x->x_answercondition, 0);
2153 x->x_vecsize = MAXVECSIZE;
2154 x->x_insamplerate = x->x_samplerate = 0;
2155 x->x_state = STATE_IDLE;
2156 x->x_clock = 0; /* no callback needed here */
2157 x->x_canvas = canvas_getcurrent();
2158 x->x_bytespersample = 2;
2159 x->x_fd = -1;
2160 x->x_buf = buf;
2161 x->x_bufsize = bufsize;
2162 x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
2163 pthread_create(&x->x_childthread, 0, writesf_child_main, x);
2164 return (x);
2165}
2166
2167static t_int *writesf_perform(t_int *w)
2168{
2169 t_writesf *x = (t_writesf *)(w[1]);
2170 int vecsize = x->x_vecsize, sfchannels = x->x_sfchannels, i, j,
2171 bytespersample = x->x_bytespersample,
2172 bigendian = x->x_bigendian;
2173 float *fp;
2174 if (x->x_state == STATE_STREAM)
2175 {
2176 int wantbytes;
2177 pthread_mutex_lock(&x->x_mutex);
2178 wantbytes = sfchannels * vecsize * bytespersample;
2179 while (x->x_fifotail > x->x_fifohead &&
2180 x->x_fifotail < x->x_fifohead + wantbytes + 1)
2181 {
2182#ifdef DEBUG_SOUNDFILE
2183 pute("wait...\n");
2184#endif
2185 sfread_cond_signal(&x->x_requestcondition);
2186 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
2187#ifdef DEBUG_SOUNDFILE
2188 pute("done\n");
2189#endif
2190 }
2191
2192 soundfile_xferout(sfchannels, x->x_outvec,
2193 (unsigned char *)(x->x_buf + x->x_fifohead), vecsize, 0,
2194 bytespersample, bigendian, 1.);
2195
2196 x->x_fifohead += wantbytes;
2197 if (x->x_fifohead >= x->x_fifosize)
2198 x->x_fifohead = 0;
2199 if ((--x->x_sigcountdown) <= 0)
2200 {
2201#ifdef DEBUG_SOUNDFILE
2202 pute("signal 1\n");
2203#endif
2204 sfread_cond_signal(&x->x_requestcondition);
2205 x->x_sigcountdown = x->x_sigperiod;
2206 }
2207 pthread_mutex_unlock(&x->x_mutex);
2208 }
2209 return (w+2);
2210}
2211
2212static void writesf_start(t_writesf *x)
2213{
2214 /* start making output. If we're in the "startup" state change
2215 to the "running" state. */
2216 if (x->x_state == STATE_STARTUP)
2217 x->x_state = STATE_STREAM;
2218 else
2219 pd_error(x, "writesf: start requested with no prior 'open'");
2220}
2221
2222static void writesf_stop(t_writesf *x)
2223{
2224 /* LATER rethink whether you need the mutex just to set a Svariable? */
2225 pthread_mutex_lock(&x->x_mutex);
2226 x->x_state = STATE_IDLE;
2227 x->x_requestcode = REQUEST_CLOSE;
2228#ifdef DEBUG_SOUNDFILE
2229 pute("signal 2\n");
2230#endif
2231 sfread_cond_signal(&x->x_requestcondition);
2232 pthread_mutex_unlock(&x->x_mutex);
2233}
2234
2235
2236 /* open method. Called as: open [args] filename with args as in
2237 soundfiler_writeargparse().
2238 */
2239
2240static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv)
2241{
2242 t_symbol *filesym;
2243 int filetype, bytespersamp, swap, bigendian, normalize;
2244 long onset, nframes;
2245 float samplerate;
2246 if (soundfiler_writeargparse(x, &argc,
2247 &argv, &filesym, &filetype, &bytespersamp, &swap, &bigendian,
2248 &normalize, &onset, &nframes, &samplerate))
2249 {
2250 pd_error(x,
2251 "writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ...");
2252 post("... [-big,-little] [-rate ####] filename");
2253 }
2254 if (normalize || onset || (nframes != 0x7fffffff))
2255 pd_error(x, "normalize/onset/nframes argument to writesf~: ignored");
2256 if (argc)
2257 pd_error(x, "extra argument(s) to writesf~: ignored");
2258 pthread_mutex_lock(&x->x_mutex);
2259 x->x_bytespersample = bytespersamp;
2260 x->x_swap = swap;
2261 x->x_bigendian = bigendian;
2262 x->x_filename = filesym->s_name;
2263 x->x_filetype = filetype;
2264 x->x_itemswritten = 0;
2265 x->x_requestcode = REQUEST_OPEN;
2266 x->x_fifotail = 0;
2267 x->x_fifohead = 0;
2268 x->x_eof = 0;
2269 x->x_fileerror = 0;
2270 x->x_state = STATE_STARTUP;
2271 x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
2272 if (samplerate > 0)
2273 x->x_samplerate = samplerate;
2274 else if (x->x_insamplerate > 0)
2275 x->x_samplerate = x->x_insamplerate;
2276 else x->x_samplerate = sys_getsr();
2277 /* set fifosize from bufsize. fifosize must be a
2278 multiple of the number of bytes eaten for each DSP
2279 tick. */
2280 x->x_fifosize = x->x_bufsize - (x->x_bufsize %
2281 (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
2282 /* arrange for the "request" condition to be signalled 16
2283 times per buffer */
2284 x->x_sigcountdown = x->x_sigperiod =
2285 (x->x_fifosize /
2286 (16 * x->x_bytespersample * x->x_sfchannels *
2287 x->x_vecsize));
2288 sfread_cond_signal(&x->x_requestcondition);
2289 pthread_mutex_unlock(&x->x_mutex);
2290}
2291
2292static void writesf_dsp(t_writesf *x, t_signal **sp)
2293{
2294 int i, ninlets = x->x_sfchannels;
2295 pthread_mutex_lock(&x->x_mutex);
2296 x->x_vecsize = sp[0]->s_n;
2297
2298 x->x_sigperiod = (x->x_fifosize /
2299 (x->x_bytespersample * ninlets * x->x_vecsize));
2300 for (i = 0; i < ninlets; i++)
2301 x->x_outvec[i] = sp[i]->s_vec;
2302 x->x_insamplerate = sp[0]->s_sr;
2303 pthread_mutex_unlock(&x->x_mutex);
2304 dsp_add(writesf_perform, 1, x);
2305}
2306
2307static void writesf_print(t_writesf *x)
2308{
2309 post("state %d", x->x_state);
2310 post("fifo head %d", x->x_fifohead);
2311 post("fifo tail %d", x->x_fifotail);
2312 post("fifo size %d", x->x_fifosize);
2313 post("fd %d", x->x_fd);
2314 post("eof %d", x->x_eof);
2315}
2316
2317static void writesf_free(t_writesf *x)
2318{
2319 /* request QUIT and wait for acknowledge */
2320 void *threadrtn;
2321 pthread_mutex_lock(&x->x_mutex);
2322 x->x_requestcode = REQUEST_QUIT;
2323 /* post("stopping writesf thread..."); */
2324 sfread_cond_signal(&x->x_requestcondition);
2325 while (x->x_requestcode != REQUEST_NOTHING)
2326 {
2327 /* post("signalling..."); */
2328 sfread_cond_signal(&x->x_requestcondition);
2329 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
2330 }
2331 pthread_mutex_unlock(&x->x_mutex);
2332 if (pthread_join(x->x_childthread, &threadrtn))
2333 error("writesf_free: join failed");
2334 /* post("... done."); */
2335
2336 pthread_cond_destroy(&x->x_requestcondition);
2337 pthread_cond_destroy(&x->x_answercondition);
2338 pthread_mutex_destroy(&x->x_mutex);
2339 freebytes(x->x_buf, x->x_bufsize);
2340}
2341
2342static void writesf_setup(void)
2343{
2344 writesf_class = class_new(gensym("writesf~"), (t_newmethod)writesf_new,
2345 (t_method)writesf_free, sizeof(t_writesf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
2346 class_addmethod(writesf_class, (t_method)writesf_start, gensym("start"), 0);
2347 class_addmethod(writesf_class, (t_method)writesf_stop, gensym("stop"), 0);
2348 class_addmethod(writesf_class, (t_method)writesf_dsp, gensym("dsp"), 0);
2349 class_addmethod(writesf_class, (t_method)writesf_open, gensym("open"),
2350 A_GIMME, 0);
2351 class_addmethod(writesf_class, (t_method)writesf_print, gensym("print"), 0);
2352 CLASS_MAINSIGNALIN(writesf_class, t_writesf, x_f);
2353}
2354
2355#endif
2356
2357/* ------------------------ global setup routine ------------------------- */
2358
2359void d_soundfile_setup(void)
2360{
2361 soundfiler_setup();
2362#ifndef FIXEDPOINT
2363 readsf_setup();
2364 writesf_setup();
2365#endif
2366}
2367
2368/* Copyright (c) 1997-1999 Miller Puckette.
2369* For information on usage and redistribution, and for a DISCLAIMER OF ALL
2370* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
2371
2372/* this file contains, first, a collection of soundfile access routines, a
2373sort of soundfile library. Second, the "soundfiler" object is defined which
2374uses the routines to read or write soundfiles, synchronously, from garrays.
2375These operations are not to be done in "real time" as they may have to wait
2376for disk accesses (even the write routine.) Finally, the realtime objects
2377readsf~ and writesf~ are defined which confine disk operations to a separate
2378thread so that they can be used in real time. The readsf~ and writesf~
2379objects use Posix-like threads. */
2380
2381#ifdef UNIX
2382#include <unistd.h>
2383#include <fcntl.h>
2384#endif
2385#include <pthread.h>
2386#ifdef MSW
2387#include <io.h>
2388#endif
2389#include <stdio.h>
2390#include <string.h>
2391#include <errno.h>
2392
2393#include "m_pd.h"
2394
2395#define MAXSFCHANS 64
2396
2397/***************** soundfile header structures ************************/
2398
2399typedef unsigned short uint16;
2400typedef unsigned long uint32;
2401
2402#define FORMAT_WAVE 0
2403#define FORMAT_AIFF 1
2404#define FORMAT_NEXT 2
2405
2406/* the NeXTStep sound header structure; can be big or little endian */
2407
2408typedef struct _nextstep
2409{
2410 char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
2411 uint32 ns_onset; /* byte offset of first sample */
2412 uint32 ns_length; /* length of sound in bytes */
2413 uint32 ns_format; /* format; see below */
2414 uint32 ns_sr; /* sample rate */
2415 uint32 ns_nchans; /* number of channels */
2416 char ns_info[4]; /* comment */
2417} t_nextstep;
2418
2419#define NS_FORMAT_LINEAR_16 3
2420#define NS_FORMAT_LINEAR_24 4
2421#define NS_FORMAT_FLOAT 6
2422#define SCALE (1./(1024. * 1024. * 1024. * 2.))
2423
2424/* the WAVE header. All Wave files are little endian. We assume
2425 the "fmt" chunk comes first which is usually the case but perhaps not
2426 always; same for AIFF and the "COMM" chunk. */
2427
2428typedef unsigned word;
2429typedef unsigned long dword;
2430
2431typedef struct _wave
2432{
2433 char w_fileid[4]; /* chunk id 'RIFF' */
2434 uint32 w_chunksize; /* chunk size */
2435 char w_waveid[4]; /* wave chunk id 'WAVE' */
2436 char w_fmtid[4]; /* format chunk id 'fmt ' */
2437 uint32 w_fmtchunksize; /* format chunk size */
2438 uint16 w_fmttag; /* format tag (WAV_INT etc) */
2439 uint16 w_nchannels; /* number of channels */
2440 uint32 w_samplespersec; /* sample rate in hz */
2441 uint32 w_navgbytespersec; /* average bytes per second */
2442 uint16 w_nblockalign; /* number of bytes per frame */
2443 uint16 w_nbitspersample; /* number of bits in a sample */
2444 char w_datachunkid[4]; /* data chunk id 'data' */
2445 uint32 w_datachunksize; /* length of data chunk */
2446} t_wave;
2447
2448typedef struct _fmt /* format chunk */
2449{
2450 uint16 f_fmttag; /* format tag, 1 for PCM */
2451 uint16 f_nchannels; /* number of channels */
2452 uint32 f_samplespersec; /* sample rate in hz */
2453 uint32 f_navgbytespersec; /* average bytes per second */
2454 uint16 f_nblockalign; /* number of bytes per frame */
2455 uint16 f_nbitspersample; /* number of bits in a sample */
2456} t_fmt;
2457
2458typedef struct _wavechunk /* ... and the last two items */
2459{
2460 char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
2461 uint32 wc_size; /* length of data chunk */
2462} t_wavechunk;
2463
2464#define WAV_INT 1
2465#define WAV_FLOAT 3
2466
2467/* the AIFF header. I'm assuming AIFC is compatible but don't really know
2468 that. */
2469
2470typedef struct _datachunk
2471{
2472 char dc_id[4]; /* data chunk id 'SSND' */
2473 uint32 dc_size; /* length of data chunk */
2474} t_datachunk;
2475
2476typedef struct _comm
2477{
2478 uint16 c_nchannels; /* number of channels */
2479 uint16 c_nframeshi; /* # of sample frames (hi) */
2480 uint16 c_nframeslo; /* # of sample frames (lo) */
2481 uint16 c_bitspersamp; /* bits per sample */
2482 unsigned char c_samprate[10]; /* sample rate, 80-bit float! */
2483} t_comm;
2484
2485 /* this version is more convenient for writing them out: */
2486typedef struct _aiff
2487{
2488 char a_fileid[4]; /* chunk id 'FORM' */
2489 uint32 a_chunksize; /* chunk size */
2490 char a_aiffid[4]; /* aiff chunk id 'AIFF' */
2491 char a_fmtid[4]; /* format chunk id 'COMM' */
2492 uint32 a_fmtchunksize; /* format chunk size, 18 */
2493 uint16 a_nchannels; /* number of channels */
2494 uint16 a_nframeshi; /* # of sample frames (hi) */
2495 uint16 a_nframeslo; /* # of sample frames (lo) */
2496 uint16 a_bitspersamp; /* bits per sample */
2497 unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
2498} t_aiff;
2499
2500#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
2501
2502
2503#define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */
2504
2505#define WHDR1 sizeof(t_nextstep)
2506#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
2507#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
2508
2509#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
2510
2511#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
2512
2513#ifdef MSW
2514#include <fcntl.h>
2515#define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
2516#else
2517#define BINCREATE O_WRONLY | O_CREAT | O_TRUNC
2518#endif
2519
2520/* this routine returns 1 if the high order byte comes at the lower
2521address on our architecture (big-endianness.). It's 1 for Motorola,
25220 for Intel: */
2523
2524extern int garray_ambigendian(void);
2525
2526/* byte swappers */
2527
2528static uint32 swap4(uint32 n, int doit)
2529{
2530 if (doit)
2531 return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
2532 ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
2533 else return (n);
2534}
2535
2536static uint16 swap2(uint32 n, int doit)
2537{
2538 if (doit)
2539 return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
2540 else return (n);
2541}
2542
2543static void swapstring(char *foo, int doit)
2544{
2545 if (doit)
2546 {
2547 char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
2548 foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
2549 }
2550}
2551
2552/******************** soundfile access routines **********************/
2553
2554/* This routine opens a file, looks for either a nextstep or "wave" header,
2555* seeks to end of it, and fills in bytes per sample and number of channels.
2556* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
2557* are supported. If "headersize" is nonzero, the
2558* caller should supply the number of channels, endinanness, and bytes per
2559* sample; the header is ignored. Otherwise, the routine tries to read the
2560* header and fill in the properties.
2561*/
2562
2563int open_soundfile(const char *dirname, const char *filename, int headersize,
2564 int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
2565 long skipframes)
2566{
2567 char buf[OBUFSIZE], *bufptr;
2568 int fd, format, nchannels, bigendian, bytespersamp, swap, sysrtn;
2569 long bytelimit = 0x7fffffff;
2570 errno = 0;
2571 fd = open_via_path(dirname, filename,
2572 "", buf, &bufptr, MAXPDSTRING, 1);
2573 if (fd < 0)
2574 return (-1);
2575 if (headersize >= 0) /* header detection overridden */
2576 {
2577 bigendian = *p_bigendian;
2578 nchannels = *p_nchannels;
2579 bytespersamp = *p_bytespersamp;
2580 bytelimit = *p_bytelimit;
2581 }
2582 else
2583 {
2584 int bytesread = read(fd, buf, READHDRSIZE);
2585 int format;
2586 if (bytesread < 4)
2587 goto badheader;
2588 if (!strncmp(buf, ".snd", 4))
2589 format = FORMAT_NEXT, bigendian = 1;
2590 else if (!strncmp(buf, "dns.", 4))
2591 format = FORMAT_NEXT, bigendian = 0;
2592 else if (!strncmp(buf, "RIFF", 4))
2593 {
2594 if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4))
2595 goto badheader;
2596 format = FORMAT_WAVE, bigendian = 0;
2597 }
2598 else if (!strncmp(buf, "FORM", 4))
2599 {
2600 if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4))
2601 goto badheader;
2602 format = FORMAT_AIFF, bigendian = 1;
2603 }
2604 else
2605 goto badheader;
2606 swap = (bigendian != garray_ambigendian());
2607 if (format == FORMAT_NEXT) /* nextstep header */
2608 {
2609 uint32 param;
2610 if (bytesread < (int)sizeof(t_nextstep))
2611 goto badheader;
2612 nchannels = swap4(((t_nextstep *)buf)->ns_nchans, swap);
2613 format = swap4(((t_nextstep *)buf)->ns_format, swap);
2614 headersize = swap4(((t_nextstep *)buf)->ns_onset, swap);
2615 if (format == NS_FORMAT_LINEAR_16)
2616 bytespersamp = 2;
2617 else if (format == NS_FORMAT_LINEAR_24)
2618 bytespersamp = 3;
2619 else if (format == NS_FORMAT_FLOAT)
2620 bytespersamp = 4;
2621 else goto badheader;
2622 bytelimit = 0x7fffffff;
2623 }
2624 else if (format == FORMAT_WAVE) /* wave header */
2625 {
2626 /* This is awful. You have to skip over chunks,
2627 except that if one happens to be a "fmt" chunk, you want to
2628 find out the format from that one. The case where the
2629 "fmt" chunk comes after the audio isn't handled. */
2630 headersize = 12;
2631 if (bytesread < 20)
2632 goto badheader;
2633 /* First we guess a number of channels, etc., in case there's
2634 no "fmt" chunk to follow. */
2635 nchannels = 1;
2636 bytespersamp = 2;
2637 /* copy the first chunk header to beginnning of buffer. */
2638 memcpy(buf, buf + headersize, sizeof(t_wavechunk));
2639 /* post("chunk %c %c %c %c",
2640 ((t_wavechunk *)buf)->wc_id[0],
2641 ((t_wavechunk *)buf)->wc_id[1],
2642 ((t_wavechunk *)buf)->wc_id[2],
2643 ((t_wavechunk *)buf)->wc_id[3]); */
2644 /* read chunks in loop until we get to the data chunk */
2645 while (strncmp(((t_wavechunk *)buf)->wc_id, "data", 4))
2646 {
2647 long chunksize = swap4(((t_wavechunk *)buf)->wc_size,
2648 swap), seekto = headersize + chunksize + 8, seekout;
2649
2650 if (!strncmp(((t_wavechunk *)buf)->wc_id, "fmt ", 4))
2651 {
2652 long commblockonset = headersize + 8;
2653 seekout = lseek(fd, commblockonset, SEEK_SET);
2654 if (seekout != commblockonset)
2655 goto badheader;
2656 if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt))
2657 goto badheader;
2658 nchannels = swap2(((t_fmt *)buf)->f_nchannels, swap);
2659 format = swap2(((t_fmt *)buf)->f_nbitspersample, swap);
2660 if (format == 16)
2661 bytespersamp = 2;
2662 else if (format == 24)
2663 bytespersamp = 3;
2664 else if (format == 32)
2665 bytespersamp = 4;
2666 else goto badheader;
2667 }
2668 seekout = lseek(fd, seekto, SEEK_SET);
2669 if (seekout != seekto)
2670 goto badheader;
2671 if (read(fd, buf, sizeof(t_wavechunk)) <
2672 (int) sizeof(t_wavechunk))
2673 goto badheader;
2674 /* post("new chunk %c %c %c %c at %d",
2675 ((t_wavechunk *)buf)->wc_id[0],
2676 ((t_wavechunk *)buf)->wc_id[1],
2677 ((t_wavechunk *)buf)->wc_id[2],
2678 ((t_wavechunk *)buf)->wc_id[3], seekto); */
2679 headersize = seekto;
2680 }
2681 bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap);
2682 headersize += 8;
2683 }
2684 else
2685 {
2686 /* AIFF. same as WAVE; actually predates it. Disgusting. */
2687 headersize = 12;
2688 if (bytesread < 20)
2689 goto badheader;
2690 /* First we guess a number of channels, etc., in case there's
2691 no COMM block to follow. */
2692 nchannels = 1;
2693 bytespersamp = 2;
2694 /* copy the first chunk header to beginnning of buffer. */
2695 memcpy(buf, buf + headersize, sizeof(t_datachunk));
2696 /* read chunks in loop until we get to the data chunk */
2697 while (strncmp(((t_datachunk *)buf)->dc_id, "SSND", 4))
2698 {
2699 long chunksize = swap4(((t_datachunk *)buf)->dc_size,
2700 swap), seekto = headersize + chunksize + 8, seekout;
2701 /* post("chunk %c %c %c %c seek %d",
2702 ((t_datachunk *)buf)->dc_id[0],
2703 ((t_datachunk *)buf)->dc_id[1],
2704 ((t_datachunk *)buf)->dc_id[2],
2705 ((t_datachunk *)buf)->dc_id[3], seekto); */
2706 if (!strncmp(((t_datachunk *)buf)->dc_id, "COMM", 4))
2707 {
2708 long commblockonset = headersize + 8;
2709 seekout = lseek(fd, commblockonset, SEEK_SET);
2710 if (seekout != commblockonset)
2711 goto badheader;
2712 if (read(fd, buf, sizeof(t_comm)) <
2713 (int) sizeof(t_comm))
2714 goto badheader;
2715 nchannels = swap2(((t_comm *)buf)->c_nchannels, swap);
2716 format = swap2(((t_comm *)buf)->c_bitspersamp, swap);
2717 if (format == 16)
2718 bytespersamp = 2;
2719 else if (format == 24)
2720 bytespersamp = 3;
2721 else goto badheader;
2722 }
2723 seekout = lseek(fd, seekto, SEEK_SET);
2724 if (seekout != seekto)
2725 goto badheader;
2726 if (read(fd, buf, sizeof(t_datachunk)) <
2727 (int) sizeof(t_datachunk))
2728 goto badheader;
2729 headersize = seekto;
2730 }
2731 bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap);
2732 headersize += 8;
2733 }
2734 }
2735 /* seek past header and any sample frames to skip */
2736 sysrtn = lseek(fd, nchannels * bytespersamp * skipframes + headersize, 0);
2737 if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
2738 return (-1);
2739 bytelimit -= nchannels * bytespersamp * skipframes;
2740 if (bytelimit < 0)
2741 bytelimit = 0;
2742 /* copy sample format back to caller */
2743 *p_bigendian = bigendian;
2744 *p_nchannels = nchannels;
2745 *p_bytespersamp = bytespersamp;
2746 *p_bytelimit = bytelimit;
2747 return (fd);
2748badheader:
2749 /* the header wasn't recognized. We're threadable here so let's not
2750 print out the error... */
2751 errno = EIO;
2752 return (-1);
2753}
2754
2755static void soundfile_xferin(int sfchannels, int nvecs, t_sample **vecs,
2756 long itemsread, unsigned char *buf, int nitems, int bytespersamp,
2757 int bigendian)
2758{
2759 int i, j;
2760 unsigned char *sp, *sp2;
2761 t_sample *fp;
2762 int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
2763 int bytesperframe = bytespersamp * sfchannels;
2764 for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
2765 {
2766 if (bytespersamp == 2)
2767 {
2768 if (bigendian)
2769 {
2770 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
2771 j < nitems; j++, sp2 += bytesperframe, fp++)
2772 *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
2773 }
2774 else
2775 {
2776 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
2777 j < nitems; j++, sp2 += bytesperframe, fp++)
2778 *fp = ((short*)sp2)[0]<<(fix1-16);
2779 }
2780 }
2781 else if (bytespersamp == 3)
2782 {
2783 if (bigendian)
2784 {
2785 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
2786 j < nitems; j++, sp2 += bytesperframe, fp++)
2787 *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
2788 | (sp2[2] << 8));
2789 }
2790 else
2791 {
2792 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
2793 j < nitems; j++, sp2 += bytesperframe, fp++)
2794 *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
2795 | (sp2[0] << 8));
2796 }
2797 }
2798 else if (bytespersamp == 4)
2799 {
2800 if (bigendian)
2801 {
2802 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
2803 j < nitems; j++, sp2 += bytesperframe, fp++)
2804 *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
2805 | (sp2[2] << 8) | sp2[3]);
2806 }
2807 else
2808 {
2809 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
2810 j < nitems; j++, sp2 += bytesperframe, fp++)
2811 *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
2812 | (sp2[1] << 8) | sp2[0]);
2813 }
2814 }
2815 }
2816 /* zero out other outputs */
2817 for (i = sfchannels; i < nvecs; i++)
2818 for (j = nitems, fp = vecs[i]; j--; )
2819 *fp++ = 0;
2820
2821}
2822
2823 /* soundfiler_write ...
2824
2825 usage: write [flags] filename table ...
2826 flags:
2827 -nframes <frames>
2828 -skip <frames>
2829 -bytes <bytes per sample>
2830 -normalize
2831 -nextstep
2832 -wave
2833 -big
2834 -little
2835 */
2836
2837 /* the routine which actually does the work should LATER also be called
2838 from garray_write16. */
2839
2840
2841 /* Parse arguments for writing. The "obj" argument is only for flagging
2842 errors. For streaming to a file the "normalize", "onset" and "nframes"
2843 arguments shouldn't be set but the calling routine flags this. */
2844
2845static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
2846 t_symbol **p_filesym,
2847 int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
2848 int *p_normalize, long *p_onset, long *p_nframes, float *p_rate)
2849{
2850 int argc = *p_argc;
2851 t_atom *argv = *p_argv;
2852 int bytespersamp = 2, bigendian = 0,
2853 endianness = -1, swap, filetype = -1, normalize = 0;
2854 long onset = 0, nframes = 0x7fffffff;
2855 t_symbol *filesym;
2856 float rate = -1;
2857
2858 while (argc > 0 && argv->a_type == A_SYMBOL &&
2859 *argv->a_w.w_symbol->s_name == '-')
2860 {
2861 char *flag = argv->a_w.w_symbol->s_name + 1;
2862 if (!strcmp(flag, "skip"))
2863 {
2864 if (argc < 2 || argv[1].a_type != A_FLOAT ||
2865 ((onset = argv[1].a_w.w_float) < 0))
2866 goto usage;
2867 argc -= 2; argv += 2;
2868 }
2869 else if (!strcmp(flag, "nframes"))
2870 {
2871 if (argc < 2 || argv[1].a_type != A_FLOAT ||
2872 ((nframes = argv[1].a_w.w_float) < 0))
2873 goto usage;
2874 argc -= 2; argv += 2;
2875 }
2876 else if (!strcmp(flag, "bytes"))
2877 {
2878 if (argc < 2 || argv[1].a_type != A_FLOAT ||
2879 ((bytespersamp = argv[1].a_w.w_float) < 2) ||
2880 bytespersamp > 4)
2881 goto usage;
2882 argc -= 2; argv += 2;
2883 }
2884 else if (!strcmp(flag, "normalize"))
2885 {
2886 normalize = 1;
2887 argc -= 1; argv += 1;
2888 }
2889 else if (!strcmp(flag, "wave"))
2890 {
2891 filetype = FORMAT_WAVE;
2892 argc -= 1; argv += 1;
2893 }
2894 else if (!strcmp(flag, "nextstep"))
2895 {
2896 filetype = FORMAT_NEXT;
2897 argc -= 1; argv += 1;
2898 }
2899 else if (!strcmp(flag, "aiff"))
2900 {
2901 filetype = FORMAT_AIFF;
2902 argc -= 1; argv += 1;
2903 }
2904 else if (!strcmp(flag, "big"))
2905 {
2906 endianness = 1;
2907 argc -= 1; argv += 1;
2908 }
2909 else if (!strcmp(flag, "little"))
2910 {
2911 endianness = 0;
2912 argc -= 1; argv += 1;
2913 }
2914 else if (!strcmp(flag, "r") || !strcmp(flag, "rate"))
2915 {
2916 if (argc < 2 || argv[1].a_type != A_FLOAT ||
2917 ((rate = argv[1].a_w.w_float) <= 0))
2918 goto usage;
2919 argc -= 2; argv += 2;
2920 }
2921 else goto usage;
2922 }
2923 if (!argc || argv->a_type != A_SYMBOL)
2924 goto usage;
2925 filesym = argv->a_w.w_symbol;
2926
2927 /* check if format not specified and fill in */
2928 if (filetype < 0)
2929 {
2930 if (strlen(filesym->s_name) >= 5 &&
2931 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") ||
2932 !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF")))
2933 filetype = FORMAT_AIFF;
2934 if (strlen(filesym->s_name) >= 6 &&
2935 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") ||
2936 !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF")))
2937 filetype = FORMAT_AIFF;
2938 if (strlen(filesym->s_name) >= 5 &&
2939 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") ||
2940 !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND")))
2941 filetype = FORMAT_NEXT;
2942 if (strlen(filesym->s_name) >= 4 &&
2943 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") ||
2944 !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU")))
2945 filetype = FORMAT_NEXT;
2946 if (filetype < 0)
2947 filetype = FORMAT_WAVE;
2948 }
2949 /* don't handle AIFF floating point samples */
2950 if (bytespersamp == 4)
2951 {
2952 if (filetype == FORMAT_AIFF)
2953 {
2954 pd_error(obj, "AIFF floating-point file format unavailable");
2955 goto usage;
2956 }
2957 }
2958 /* for WAVE force little endian; for nextstep use machine native */
2959 if (filetype == FORMAT_WAVE)
2960 {
2961 bigendian = 0;
2962 if (endianness == 1)
2963 pd_error(obj, "WAVE file forced to little endian");
2964 }
2965 else if (filetype == FORMAT_AIFF)
2966 {
2967 bigendian = 1;
2968 if (endianness == 0)
2969 pd_error(obj, "AIFF file forced to big endian");
2970 }
2971 else if (endianness == -1)
2972 {
2973 bigendian = garray_ambigendian();
2974 }
2975 else bigendian = endianness;
2976 swap = (bigendian != garray_ambigendian());
2977
2978 argc--; argv++;
2979
2980 *p_argc = argc;
2981 *p_argv = argv;
2982 *p_filesym = filesym;
2983 *p_filetype = filetype;
2984 *p_bytespersamp = bytespersamp;
2985 *p_swap = swap;
2986 *p_normalize = normalize;
2987 *p_onset = onset;
2988 *p_nframes = nframes;
2989 *p_bigendian = bigendian;
2990 *p_rate = rate;
2991 return (0);
2992usage:
2993 return (-1);
2994}
2995
2996static int create_soundfile(t_canvas *canvas, const char *filename,
2997 int filetype, int nframes, int bytespersamp,
2998 int bigendian, int nchannels, int swap, float samplerate)
2999{
3000 char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
3001 char headerbuf[WRITEHDRSIZE];
3002 t_wave *wavehdr = (t_wave *)headerbuf;
3003 t_nextstep *nexthdr = (t_nextstep *)headerbuf;
3004 t_aiff *aiffhdr = (t_aiff *)headerbuf;
3005 int fd, headersize = 0;
3006
3007 strncpy(filenamebuf, filename, MAXPDSTRING-10);
3008 filenamebuf[MAXPDSTRING-10] = 0;
3009
3010 if (filetype == FORMAT_NEXT)
3011 {
3012 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
3013 strcat(filenamebuf, ".snd");
3014 if (bigendian)
3015 strncpy(nexthdr->ns_fileid, ".snd", 4);
3016 else strncpy(nexthdr->ns_fileid, "dns.", 4);
3017 nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
3018 nexthdr->ns_length = 0;
3019 nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
3020 (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);
3021 nexthdr->ns_sr = swap4(samplerate, swap);
3022 nexthdr->ns_nchans = swap4(nchannels, swap);
3023 strcpy(nexthdr->ns_info, "Pd ");
3024 swapstring(nexthdr->ns_info, swap);
3025 headersize = sizeof(t_nextstep);
3026 }
3027 else if (filetype == FORMAT_AIFF)
3028 {
3029 long datasize = nframes * nchannels * bytespersamp;
3030 long longtmp;
3031 static unsigned char dogdoo[] =
3032 {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
3033 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
3034 strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
3035 strcat(filenamebuf, ".aif");
3036 strncpy(aiffhdr->a_fileid, "FORM", 4);
3037 aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
3038 strncpy(aiffhdr->a_aiffid, "AIFF", 4);
3039 strncpy(aiffhdr->a_fmtid, "COMM", 4);
3040 aiffhdr->a_fmtchunksize = swap4(18, swap);
3041 aiffhdr->a_nchannels = swap2(nchannels, swap);
3042 longtmp = swap4(nframes, swap);
3043 memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
3044 aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
3045 memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
3046 longtmp = swap4(datasize, swap);
3047 memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
3048 headersize = AIFFPLUS;
3049 }
3050 else /* WAVE format */
3051 {
3052 long datasize = nframes * nchannels * bytespersamp;
3053 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
3054 strcat(filenamebuf, ".wav");
3055 strncpy(wavehdr->w_fileid, "RIFF", 4);
3056 wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
3057 strncpy(wavehdr->w_waveid, "WAVE", 4);
3058 strncpy(wavehdr->w_fmtid, "fmt ", 4);
3059 wavehdr->w_fmtchunksize = swap4(16, swap);
3060 wavehdr->w_fmttag =
3061 swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap);
3062 wavehdr->w_nchannels = swap2(nchannels, swap);
3063 wavehdr->w_samplespersec = swap4(samplerate, swap);
3064 wavehdr->w_navgbytespersec =
3065 swap4((int)(samplerate * nchannels * bytespersamp), swap);
3066 wavehdr->w_nblockalign = swap2(nchannels * bytespersamp, swap);
3067 wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
3068 strncpy(wavehdr->w_datachunkid, "data", 4);
3069 wavehdr->w_datachunksize = swap4(datasize, swap);
3070 headersize = sizeof(t_wave);
3071 }
3072
3073 canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
3074 sys_bashfilename(buf2, buf2);
3075 if ((fd = open(buf2, BINCREATE, 0666)) < 0)
3076 return (-1);
3077
3078 if (write(fd, headerbuf, headersize) < headersize)
3079 {
3080 close (fd);
3081 return (-1);
3082 }
3083 return (fd);
3084}
3085
3086static void soundfile_finishwrite(void *obj, char *filename, int fd,
3087 int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
3088{
3089 if (itemswritten < nframes)
3090 {
3091 if (nframes < 0x7fffffff)
3092 pd_error(obj, "soundfiler_write: %d out of %d bytes written",
3093 itemswritten, nframes);
3094 /* try to fix size fields in header */
3095 if (filetype == FORMAT_WAVE)
3096 {
3097 long datasize = itemswritten * bytesperframe, mofo;
3098
3099 if (lseek(fd,
3100 ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
3101 SEEK_SET) == 0)
3102 goto baddonewrite;
3103 mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
3104 if (write(fd, (char *)(&mofo), 4) < 4)
3105 goto baddonewrite;
3106 if (lseek(fd,
3107 ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
3108 SEEK_SET) == 0)
3109 goto baddonewrite;
3110 mofo = swap4(datasize, swap);
3111 if (write(fd, (char *)(&mofo), 4) < 4)
3112 goto baddonewrite;
3113 }
3114 if (filetype == FORMAT_AIFF)
3115 {
3116 long mofo;
3117 if (lseek(fd,
3118 ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
3119 SEEK_SET) == 0)
3120 goto baddonewrite;
3121 mofo = swap4(nframes, swap);
3122 if (write(fd, (char *)(&mofo), 4) < 4)
3123 goto baddonewrite;
3124 }
3125 if (filetype == FORMAT_NEXT)
3126 {
3127 /* do it the lazy way: just set the size field to 'unknown size'*/
3128 uint32 nextsize = 0xffffffff;
3129 if (lseek(fd, 8, SEEK_SET) == 0)
3130 {
3131 goto baddonewrite;
3132 }
3133 if (write(fd, &nextsize, 4) < 4)
3134 {
3135 goto baddonewrite;
3136 }
3137 }
3138 }
3139 return;
3140baddonewrite:
3141 post("%s: %s", filename, strerror(errno));
3142}
3143
3144static void soundfile_xferout(int nchannels, t_sample **vecs,
3145 unsigned char *buf, int nitems, long onset, int bytespersamp,
3146 int bigendian, float normalfactor)
3147{
3148 int i, j;
3149 unsigned char *sp, *sp2;
3150 t_sample *fp;
3151 int bytesperframe = bytespersamp * nchannels;
3152 long xx;
3153 for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
3154 {
3155 if (bytespersamp == 2)
3156 {
3157 float ff = normalfactor * 32768.;
3158 if (bigendian)
3159 {
3160 for (j = 0, sp2 = sp, fp = vecs[i] + onset;
3161 j < nitems; j++, sp2 += bytesperframe, fp++)
3162 {
3163 int xx = 32768. + (*fp * ff);
3164 xx -= 32768;
3165 if (xx < -32767)
3166 xx = -32767;
3167 if (xx > 32767)
3168 xx = 32767;
3169 sp2[0] = (xx >> 8);
3170 sp2[1] = xx;
3171 }
3172 }
3173 else
3174 {
3175 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
3176 j < nitems; j++, sp2 += bytesperframe, fp++)
3177 {
3178 int xx = 32768. + (*fp * ff);
3179 xx -= 32768;
3180 if (xx < -32767)
3181 xx = -32767;
3182 if (xx > 32767)
3183 xx = 32767;
3184 sp2[1] = (xx >> 8);
3185 sp2[0] = xx;
3186 }
3187 }
3188 }
3189 else if (bytespersamp == 3)
3190 {
3191 float ff = normalfactor * 8388608.;
3192 if (bigendian)
3193 {
3194 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
3195 j < nitems; j++, sp2 += bytesperframe, fp++)
3196 {
3197 int xx = 8388608. + (*fp * ff);
3198 xx -= 8388608;
3199 if (xx < -8388607)
3200 xx = -8388607;
3201 if (xx > 8388607)
3202 xx = 8388607;
3203 sp2[0] = (xx >> 16);
3204 sp2[1] = (xx >> 8);
3205 sp2[2] = xx;
3206 }
3207 }
3208 else
3209 {
3210 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
3211 j < nitems; j++, sp2 += bytesperframe, fp++)
3212 {
3213 int xx = 8388608. + (*fp * ff);
3214 xx -= 8388608;
3215 if (xx < -8388607)
3216 xx = -8388607;
3217 if (xx > 8388607)
3218 xx = 8388607;
3219 sp2[2] = (xx >> 16);
3220 sp2[1] = (xx >> 8);
3221 sp2[0] = xx;
3222 }
3223 }
3224 }
3225 else if (bytespersamp == 4)
3226 {
3227 if (bigendian)
3228 {
3229 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
3230 j < nitems; j++, sp2 += bytesperframe, fp++)
3231 {
3232 float f2 = *fp * normalfactor;
3233 xx = *(long *)&f2;
3234 sp2[0] = (xx >> 24); sp2[1] = (xx >> 16);
3235 sp2[2] = (xx >> 8); sp2[3] = xx;
3236 }
3237 }
3238 else
3239 {
3240 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
3241 j < nitems; j++, sp2 += bytesperframe, fp++)
3242 {
3243 float f2 = *fp * normalfactor;
3244 xx = *(long *)&f2;
3245 sp2[3] = (xx >> 24); sp2[2] = (xx >> 16);
3246 sp2[1] = (xx >> 8); sp2[0] = xx;
3247 }
3248 }
3249 }
3250 }
3251}
3252
3253
3254/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
3255#define DEFMAXSIZE 4000000 /* default maximum 16 MB per channel */
3256#define SAMPBUFSIZE 1024
3257
3258
3259static t_class *soundfiler_class;
3260
3261typedef struct _soundfiler
3262{
3263 t_object x_obj;
3264 t_canvas *x_canvas;
3265} t_soundfiler;
3266
3267static t_soundfiler *soundfiler_new(void)
3268{
3269 t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class);
3270 x->x_canvas = canvas_getcurrent();
3271 outlet_new(&x->x_obj, &s_float);
3272 return (x);
3273}
3274
3275 /* soundfiler_read ...
3276
3277 usage: read [flags] filename table ...
3278 flags:
3279 -skip <frames> ... frames to skip in file
3280 -nframes <frames>
3281 -onset <frames> ... onset in table to read into (NOT DONE YET)
3282 -raw <headersize channels bytes endian>
3283 -resize
3284 -maxsize <max-size>
3285 */
3286
3287static void soundfiler_read(t_soundfiler *x, t_symbol *s,
3288 int argc, t_atom *argv)
3289{
3290 int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
3291 resize = 0, i, j;
3292 long skipframes = 0, nframes = 0, finalsize = 0, itemsleft,
3293 maxsize = DEFMAXSIZE, itemsread = 0, bytelimit = 0x7fffffff;
3294 int fd = -1;
3295 char endianness, *filename;
3296 t_garray *garrays[MAXSFCHANS];
3297 t_sample *vecs[MAXSFCHANS];
3298 char sampbuf[SAMPBUFSIZE];
3299 int bufframes, nitems;
3300 FILE *fp;
3301 while (argc > 0 && argv->a_type == A_SYMBOL &&
3302 *argv->a_w.w_symbol->s_name == '-')
3303 {
3304 char *flag = argv->a_w.w_symbol->s_name + 1;
3305 if (!strcmp(flag, "skip"))
3306 {
3307 if (argc < 2 || argv[1].a_type != A_FLOAT ||
3308 ((skipframes = argv[1].a_w.w_float) < 0))
3309 goto usage;
3310 argc -= 2; argv += 2;
3311 }
3312 else if (!strcmp(flag, "nframes"))
3313 {
3314 if (argc < 2 || argv[1].a_type != A_FLOAT ||
3315 ((nframes = argv[1].a_w.w_float) < 0))
3316 goto usage;
3317 argc -= 2; argv += 2;
3318 }
3319 else if (!strcmp(flag, "raw"))
3320 {
3321 if (argc < 5 ||
3322 argv[1].a_type != A_FLOAT ||
3323 ((headersize = argv[1].a_w.w_float) < 0) ||
3324 argv[2].a_type != A_FLOAT ||
3325 ((channels = argv[2].a_w.w_float) < 1) ||
3326 (channels > MAXSFCHANS) ||
3327 argv[3].a_type != A_FLOAT ||
3328 ((bytespersamp = argv[3].a_w.w_float) < 2) ||
3329 (bytespersamp > 4) ||
3330 argv[4].a_type != A_SYMBOL ||
3331 ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
3332 && endianness != 'l' && endianness != 'n'))
3333 goto usage;
3334 if (endianness == 'b')
3335 bigendian = 1;
3336 else if (endianness == 'l')
3337 bigendian = 0;
3338 else
3339 bigendian = garray_ambigendian();
3340 argc -= 5; argv += 5;
3341 }
3342 else if (!strcmp(flag, "resize"))
3343 {
3344 resize = 1;
3345 argc -= 1; argv += 1;
3346 }
3347 else if (!strcmp(flag, "maxsize"))
3348 {
3349 if (argc < 2 || argv[1].a_type != A_FLOAT ||
3350 ((maxsize = argv[1].a_w.w_float) < 0))
3351 goto usage;
3352 resize = 1; /* maxsize implies resize. */
3353 argc -= 2; argv += 2;
3354 }
3355 else goto usage;
3356 }
3357 if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
3358 goto usage;
3359 filename = argv[0].a_w.w_symbol->s_name;
3360 argc--; argv++;
3361
3362 for (i = 0; i < argc; i++)
3363 {
3364 int vecsize;
3365 if (argv[i].a_type != A_SYMBOL)
3366 goto usage;
3367 if (!(garrays[i] =
3368 (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
3369 {
3370 pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
3371 goto done;
3372 }
3373 else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
3374 error("%s: bad template for tabwrite",
3375 argv[i].a_w.w_symbol->s_name);
3376 if (finalsize && finalsize != vecsize && !resize)
3377 {
3378 post("soundfiler_read: arrays have different lengths; resizing...");
3379 resize = 1;
3380 }
3381 finalsize = vecsize;
3382 }
3383 fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
3384 headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
3385 skipframes);
3386
3387 if (fd < 0)
3388 {
3389 pd_error(x, "soundfiler_read: %s: %s", filename, (errno == EIO ?
3390 "unknown or bad header format" : strerror(errno)));
3391 goto done;
3392 }
3393
3394 if (resize)
3395 {
3396 /* figure out what to resize to */
3397 long poswas, eofis, framesinfile;
3398
3399 poswas = lseek(fd, 0, SEEK_CUR);
3400 eofis = lseek(fd, 0, SEEK_END);
3401 if (poswas < 0 || eofis < 0)
3402 {
3403 pd_error(x, "lseek failed");
3404 goto done;
3405 }
3406 lseek(fd, poswas, SEEK_SET);
3407 framesinfile = (eofis - poswas) / (channels * bytespersamp);
3408 if (framesinfile > maxsize)
3409 {
3410 pd_error(x, "soundfiler_read: truncated to %d elements", maxsize);
3411 framesinfile = maxsize;
3412 }
3413 if (framesinfile > bytelimit / (channels * bytespersamp))
3414 framesinfile = bytelimit / (channels * bytespersamp);
3415 finalsize = framesinfile;
3416 for (i = 0; i < argc; i++)
3417 {
3418 int vecsize;
3419
3420 garray_resize(garrays[i], finalsize);
3421 /* for sanity's sake let's clear the save-in-patch flag here */
3422 garray_setsaveit(garrays[i], 0);
3423 garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
3424 /* if the resize failed, garray_resize reported the error */
3425 if (vecsize != framesinfile)
3426 {
3427 pd_error(x, "resize failed");
3428 goto done;
3429 }
3430 }
3431 }
3432 if (!finalsize) finalsize = 0x7fffffff;
3433 if (finalsize > bytelimit / (channels * bytespersamp))
3434 finalsize = bytelimit / (channels * bytespersamp);
3435 fp = fdopen(fd, "rb");
3436 bufframes = SAMPBUFSIZE / (channels * bytespersamp);
3437
3438 for (itemsread = 0; itemsread < finalsize; )
3439 {
3440 int thisread = finalsize - itemsread;
3441 thisread = (thisread > bufframes ? bufframes : thisread);
3442 nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
3443 if (nitems <= 0) break;
3444 soundfile_xferin(channels, argc, vecs, itemsread,
3445 (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
3446 itemsread += nitems;
3447 }
3448 /* zero out remaining elements of vectors */
3449
3450 for (i = 0; i < argc; i++)
3451 {
3452 int nzero, vecsize;
3453 garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
3454 for (j = itemsread; j < vecsize; j++)
3455 vecs[i][j] = 0;
3456 }
3457 /* zero out vectors in excess of number of channels */
3458 for (i = channels; i < argc; i++)
3459 {
3460 int vecsize;
3461 t_sample *foo;
3462 garray_getfloatarray(garrays[i], &vecsize, &foo);
3463 for (j = 0; j < vecsize; j++)
3464 foo[j] = 0;
3465 }
3466 /* do all graphics updates */
3467 for (i = 0; i < argc; i++)
3468 garray_redraw(garrays[i]);
3469 fclose(fp);
3470 fd = -1;
3471 goto done;
3472usage:
3473 pd_error(x, "usage: read [flags] filename tablename...");
3474 post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
3475 post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
3476done:
3477 if (fd >= 0)
3478 close (fd);
3479 outlet_float(x->x_obj.ob_outlet, (float)itemsread);
3480}
3481
3482 /* this is broken out from soundfiler_write below so garray_write can
3483 call it too... not done yet though. */
3484
3485long soundfiler_dowrite(void *obj, t_canvas *canvas,
3486 int argc, t_atom *argv)
3487{
3488 int headersize, bytespersamp, bigendian,
3489 endianness, swap, filetype, normalize, i, j, nchannels;
3490 long onset, nframes, itemsleft,
3491 maxsize = DEFMAXSIZE, itemswritten = 0;
3492 t_garray *garrays[MAXSFCHANS];
3493 t_sample *vecs[MAXSFCHANS];
3494 char sampbuf[SAMPBUFSIZE];
3495 int bufframes, nitems;
3496 int fd = -1;
3497 float normfactor, biggest = 0, samplerate;
3498 t_symbol *filesym;
3499
3500 if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
3501 &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,
3502 &samplerate))
3503 goto usage;
3504 nchannels = argc;
3505 if (nchannels < 1 || nchannels > MAXSFCHANS)
3506 goto usage;
3507 if (samplerate < 0)
3508 samplerate = sys_getsr();
3509 for (i = 0; i < nchannels; i++)
3510 {
3511 int vecsize;
3512 if (argv[i].a_type != A_SYMBOL)
3513 goto usage;
3514 if (!(garrays[i] =
3515 (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
3516 {
3517 pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
3518 goto fail;
3519 }
3520 else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
3521 error("%s: bad template for tabwrite",
3522 argv[i].a_w.w_symbol->s_name);
3523 if (nframes > vecsize - onset)
3524 nframes = vecsize - onset;
3525
3526 for (j = 0; j < vecsize; j++)
3527 {
3528 if (vecs[i][j] > biggest)
3529 biggest = vecs[i][j];
3530 else if (-vecs[i][j] > biggest)
3531 biggest = -vecs[i][j];
3532 }
3533 }
3534 if (nframes <= 0)
3535 {
3536 pd_error(obj, "soundfiler_write: no samples at onset %ld", onset);
3537 goto fail;
3538 }
3539
3540 if ((fd = create_soundfile(canvas, filesym->s_name, filetype,
3541 nframes, bytespersamp, bigendian, nchannels,
3542 swap, samplerate)) < 0)
3543 {
3544 post("%s: %s\n", filesym->s_name, strerror(errno));
3545 goto fail;
3546 }
3547 if (!normalize)
3548 {
3549 if ((bytespersamp != 4) && (biggest > 1))
3550 {
3551 post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
3552 normalize = 1;
3553 }
3554 else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
3555 }
3556 if (normalize)
3557 normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
3558 else normfactor = 1;
3559
3560 bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
3561
3562 for (itemswritten = 0; itemswritten < nframes; )
3563 {
3564 int thiswrite = nframes - itemswritten, nitems, nbytes;
3565 thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
3566 soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
3567 onset, bytespersamp, bigendian, normfactor);
3568 nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
3569 if (nbytes < nchannels * bytespersamp * thiswrite)
3570 {
3571 post("%s: %s", filesym->s_name, strerror(errno));
3572 if (nbytes > 0)
3573 itemswritten += nbytes / (nchannels * bytespersamp);
3574 break;
3575 }
3576 itemswritten += thiswrite;
3577 onset += thiswrite;
3578 }
3579 if (fd >= 0)
3580 {
3581 soundfile_finishwrite(obj, filesym->s_name, fd,
3582 filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
3583 close (fd);
3584 }
3585 return ((float)itemswritten);
3586usage:
3587 pd_error(obj, "usage: write [flags] filename tablename...");
3588 post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
3589 post("-big -little -normalize");
3590 post("(defaults to a 16-bit wave file).");
3591fail:
3592 if (fd >= 0)
3593 close (fd);
3594 return (0);
3595}
3596
3597static void soundfiler_write(t_soundfiler *x, t_symbol *s,
3598 int argc, t_atom *argv)
3599{
3600 long bozo = soundfiler_dowrite(x, x->x_canvas,
3601 argc, argv);
3602 outlet_float(x->x_obj.ob_outlet, (float)bozo);
3603}
3604
3605static void soundfiler_setup(void)
3606{
3607 soundfiler_class = class_new(gensym("soundfiler"), (t_newmethod)soundfiler_new,
3608 0, sizeof(t_soundfiler), 0, 0);
3609 class_addmethod(soundfiler_class, (t_method)soundfiler_read, gensym("read"),
3610 A_GIMME, 0);
3611 class_addmethod(soundfiler_class, (t_method)soundfiler_write,
3612 gensym("write"), A_GIMME, 0);
3613}
3614
3615
3616#ifndef FIXEDPOINT
3617/************************* readsf object ******************************/
3618
3619/* READSF uses the Posix threads package; for the moment we're Linux
3620only although this should be portable to the other platforms.
3621
3622Each instance of readsf~ owns a "child" thread for doing the UNIX (MSW?) file
3623reading. The parent thread signals the child each time:
3624 (1) a file wants opening or closing;
3625 (2) we've eaten another 1/16 of the shared buffer (so that the
3626 child thread should check if it's time to read some more.)
3627The child signals the parent whenever a read has completed. Signalling
3628is done by setting "conditions" and putting data in mutex-controlled common
3629areas.
3630*/
3631
3632#define MAXBYTESPERSAMPLE 4
3633#define MAXVECSIZE 128
3634
3635#define READSIZE 65536
3636#define WRITESIZE 65536
3637#define DEFBUFPERCHAN 262144
3638#define MINBUFSIZE (4 * READSIZE)
3639#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
3640
3641#define REQUEST_NOTHING 0
3642#define REQUEST_OPEN 1
3643#define REQUEST_CLOSE 2
3644#define REQUEST_QUIT 3
3645#define REQUEST_BUSY 4
3646
3647#define STATE_IDLE 0
3648#define STATE_STARTUP 1
3649#define STATE_STREAM 2
3650
3651static t_class *readsf_class;
3652
3653typedef struct _readsf
3654{
3655 t_object x_obj;
3656 t_canvas *x_canvas;
3657 t_clock *x_clock;
3658 char *x_buf; /* soundfile buffer */
3659 int x_bufsize; /* buffer size in bytes */
3660 int x_noutlets; /* number of audio outlets */
3661 t_sample *(x_outvec[MAXSFCHANS]); /* audio vectors */
3662 int x_vecsize; /* vector size for transfers */
3663 t_outlet *x_bangout; /* bang-on-done outlet */
3664 int x_state; /* opened, running, or idle */
3665 float x_insamplerate; /* sample rate of input signal if known */
3666 /* parameters to communicate with subthread */
3667 int x_requestcode; /* pending request from parent to I/O thread */
3668 char *x_filename; /* file to open (string is permanently allocated) */
3669 int x_fileerror; /* slot for "errno" return */
3670 int x_skipheaderbytes; /* size of header we'll skip */
3671 int x_bytespersample; /* bytes per sample (2 or 3) */
3672 int x_bigendian; /* true if file is big-endian */
3673 int x_sfchannels; /* number of channels in soundfile */
3674 float x_samplerate; /* sample rate of soundfile */
3675 long x_onsetframes; /* number of sample frames to skip */
3676 long x_bytelimit; /* max number of data bytes to read */
3677 int x_fd; /* filedesc */
3678 int x_fifosize; /* buffer size appropriately rounded down */
3679 int x_fifohead; /* index of next byte to get from file */
3680 int x_fifotail; /* index of next byte the ugen will read */
3681 int x_eof; /* true if fifohead has stopped changing */
3682 int x_sigcountdown; /* counter for signalling child for more data */
3683 int x_sigperiod; /* number of ticks per signal */
3684 int x_filetype; /* writesf~ only; type of file to create */
3685 int x_itemswritten; /* writesf~ only; items writen */
3686 int x_swap; /* writesf~ only; true if byte swapping */
3687 float x_f; /* writesf~ only; scalar for signal inlet */
3688 pthread_mutex_t x_mutex;
3689 pthread_cond_t x_requestcondition;
3690 pthread_cond_t x_answercondition;
3691 pthread_t x_childthread;
3692} t_readsf;
3693
3694
3695/************** the child thread which performs file I/O ***********/
3696
3697#if 0
3698static void pute(char *s) /* debug routine */
3699{
3700 write(2, s, strlen(s));
3701}
3702#define DEBUG_SOUNDFILE
3703#endif
3704
3705#if 1
3706#define sfread_cond_wait pthread_cond_wait
3707#define sfread_cond_signal pthread_cond_signal
3708#else
3709#include <sys/time.h> /* debugging version... */
3710#include <sys/types.h>
3711static void readsf_fakewait(pthread_mutex_t *b)
3712{
3713 struct timeval timout;
3714 timout.tv_sec = 0;
3715 timout.tv_usec = 1000000;
3716 pthread_mutex_unlock(b);
3717 select(0, 0, 0, 0, &timout);
3718 pthread_mutex_lock(b);
3719}
3720
3721#define sfread_cond_wait(a,b) readsf_fakewait(b)
3722#define sfread_cond_signal(a)
3723#endif
3724
3725static void *readsf_child_main(void *zz)
3726{
3727 t_readsf *x = zz;
3728#ifdef DEBUG_SOUNDFILE
3729 pute("1\n");
3730#endif
3731 pthread_mutex_lock(&x->x_mutex);
3732 while (1)
3733 {
3734 int fd, fifohead;
3735 char *buf;
3736#ifdef DEBUG_SOUNDFILE
3737 pute("0\n");
3738#endif
3739 if (x->x_requestcode == REQUEST_NOTHING)
3740 {
3741#ifdef DEBUG_SOUNDFILE
3742 pute("wait 2\n");
3743#endif
3744 sfread_cond_signal(&x->x_answercondition);
3745 sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
3746#ifdef DEBUG_SOUNDFILE
3747 pute("3\n");
3748#endif
3749 }
3750 else if (x->x_requestcode == REQUEST_OPEN)
3751 {
3752 char boo[80];
3753 int sysrtn, wantbytes;
3754
3755 /* copy file stuff out of the data structure so we can
3756 relinquish the mutex while we're in open_soundfile(). */
3757 long onsetframes = x->x_onsetframes;
3758 long bytelimit = 0x7fffffff;
3759 int skipheaderbytes = x->x_skipheaderbytes;
3760 int bytespersample = x->x_bytespersample;
3761 int sfchannels = x->x_sfchannels;
3762 int bigendian = x->x_bigendian;
3763 char *filename = x->x_filename;
3764 char *dirname = canvas_getdir(x->x_canvas)->s_name;
3765 /* alter the request code so that an ensuing "open" will get
3766 noticed. */
3767#ifdef DEBUG_SOUNDFILE
3768 pute("4\n");
3769#endif
3770 x->x_requestcode = REQUEST_BUSY;
3771 x->x_fileerror = 0;
3772
3773 /* if there's already a file open, close it */
3774 if (x->x_fd >= 0)
3775 {
3776 fd = x->x_fd;
3777 pthread_mutex_unlock(&x->x_mutex);
3778 close (fd);
3779 pthread_mutex_lock(&x->x_mutex);
3780 x->x_fd = -1;
3781 if (x->x_requestcode != REQUEST_BUSY)
3782 goto lost;
3783 }
3784 /* open the soundfile with the mutex unlocked */
3785 pthread_mutex_unlock(&x->x_mutex);
3786 fd = open_soundfile(dirname, filename,
3787 skipheaderbytes, &bytespersample, &bigendian,
3788 &sfchannels, &bytelimit, onsetframes);
3789 pthread_mutex_lock(&x->x_mutex);
3790
3791#ifdef DEBUG_SOUNDFILE
3792 pute("5\n");
3793#endif
3794 /* copy back into the instance structure. */
3795 x->x_bytespersample = bytespersample;
3796 x->x_sfchannels = sfchannels;
3797 x->x_bigendian = bigendian;
3798 x->x_fd = fd;
3799 x->x_bytelimit = bytelimit;
3800 if (fd < 0)
3801 {
3802 x->x_fileerror = errno;
3803 x->x_eof = 1;
3804#ifdef DEBUG_SOUNDFILE
3805 pute("open failed\n");
3806 pute(filename);
3807 pute(dirname);
3808#endif
3809 goto lost;
3810 }
3811 /* check if another request has been made; if so, field it */
3812 if (x->x_requestcode != REQUEST_BUSY)
3813 goto lost;
3814#ifdef DEBUG_SOUNDFILE
3815 pute("6\n");
3816#endif
3817 x->x_fifohead = 0;
3818 /* set fifosize from bufsize. fifosize must be a
3819 multiple of the number of bytes eaten for each DSP
3820 tick. We pessimistically assume MAXVECSIZE samples
3821 per tick since that could change. There could be a
3822 problem here if the vector size increases while a
3823 soundfile is being played... */
3824 x->x_fifosize = x->x_bufsize - (x->x_bufsize %
3825 (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
3826 /* arrange for the "request" condition to be signalled 16
3827 times per buffer */
3828#ifdef DEBUG_SOUNDFILE
3829 sprintf(boo, "fifosize %d\n",
3830 x->x_fifosize);
3831 pute(boo);
3832#endif
3833 x->x_sigcountdown = x->x_sigperiod =
3834 (x->x_fifosize /
3835 (16 * x->x_bytespersample * x->x_sfchannels *
3836 x->x_vecsize));
3837 /* in a loop, wait for the fifo to get hungry and feed it */
3838
3839 while (x->x_requestcode == REQUEST_BUSY)
3840 {
3841 int fifosize = x->x_fifosize;
3842#ifdef DEBUG_SOUNDFILE
3843 pute("77\n");
3844#endif
3845 if (x->x_eof)
3846 break;
3847 if (x->x_fifohead >= x->x_fifotail)
3848 {
3849 /* if the head is >= the tail, we can immediately read
3850 to the end of the fifo. Unless, that is, we would
3851 read all the way to the end of the buffer and the
3852 "tail" is zero; this would fill the buffer completely
3853 which isn't allowed because you can't tell a completely
3854 full buffer from an empty one. */
3855 if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE))
3856 {
3857 wantbytes = fifosize - x->x_fifohead;
3858 if (wantbytes > READSIZE)
3859 wantbytes = READSIZE;
3860 if (wantbytes > x->x_bytelimit)
3861 wantbytes = x->x_bytelimit;
3862#ifdef DEBUG_SOUNDFILE
3863 sprintf(boo, "head %d, tail %d, size %d\n",
3864 x->x_fifohead, x->x_fifotail, wantbytes);
3865 pute(boo);
3866#endif
3867 }
3868 else
3869 {
3870#ifdef DEBUG_SOUNDFILE
3871 pute("wait 7a ...\n");
3872#endif
3873 sfread_cond_signal(&x->x_answercondition);
3874#ifdef DEBUG_SOUNDFILE
3875 pute("signalled\n");
3876#endif
3877 sfread_cond_wait(&x->x_requestcondition,
3878 &x->x_mutex);
3879#ifdef DEBUG_SOUNDFILE
3880 pute("7a done\n");
3881#endif
3882 continue;
3883 }
3884 }
3885 else
3886 {
3887 /* otherwise check if there are at least READSIZE
3888 bytes to read. If not, wait and loop back. */
3889 wantbytes = x->x_fifotail - x->x_fifohead - 1;
3890 if (wantbytes < READSIZE)
3891 {
3892#ifdef DEBUG_SOUNDFILE
3893 pute("wait 7...\n");
3894#endif
3895 sfread_cond_signal(&x->x_answercondition);
3896 sfread_cond_wait(&x->x_requestcondition,
3897 &x->x_mutex);
3898#ifdef DEBUG_SOUNDFILE
3899 pute("7 done\n");
3900#endif
3901 continue;
3902 }
3903 else wantbytes = READSIZE;
3904 if (wantbytes > x->x_bytelimit)
3905 wantbytes = x->x_bytelimit;
3906 }
3907#ifdef DEBUG_SOUNDFILE
3908 pute("8\n");
3909#endif
3910 fd = x->x_fd;
3911 buf = x->x_buf;
3912 fifohead = x->x_fifohead;
3913 pthread_mutex_unlock(&x->x_mutex);
3914 sysrtn = read(fd, buf + fifohead, wantbytes);
3915 pthread_mutex_lock(&x->x_mutex);
3916 if (x->x_requestcode != REQUEST_BUSY)
3917 break;
3918 if (sysrtn < 0)
3919 {
3920#ifdef DEBUG_SOUNDFILE
3921 pute("fileerror\n");
3922#endif
3923 x->x_fileerror = errno;
3924 break;
3925 }
3926 else if (sysrtn == 0)
3927 {
3928 x->x_eof = 1;
3929 break;
3930 }
3931 else
3932 {
3933 x->x_fifohead += sysrtn;
3934 x->x_bytelimit -= sysrtn;
3935 if (x->x_bytelimit <= 0)
3936 {
3937 x->x_eof = 1;
3938 break;
3939 }
3940 if (x->x_fifohead == fifosize)
3941 x->x_fifohead = 0;
3942 }
3943#ifdef DEBUG_SOUNDFILE
3944 sprintf(boo, "after: head %d, tail %d\n",
3945 x->x_fifohead, x->x_fifotail);
3946 pute(boo);
3947#endif
3948 /* signal parent in case it's waiting for data */
3949 sfread_cond_signal(&x->x_answercondition);
3950 }
3951 lost:
3952
3953 if (x->x_requestcode == REQUEST_BUSY)
3954 x->x_requestcode = REQUEST_NOTHING;
3955 /* fell out of read loop: close file if necessary,
3956 set EOF and signal once more */
3957 if (x->x_fd >= 0)
3958 {
3959 fd = x->x_fd;
3960 pthread_mutex_unlock(&x->x_mutex);
3961 close (fd);
3962 pthread_mutex_lock(&x->x_mutex);
3963 x->x_fd = -1;
3964 }
3965 sfread_cond_signal(&x->x_answercondition);
3966
3967 }
3968 else if (x->x_requestcode == REQUEST_CLOSE)
3969 {
3970 if (x->x_fd >= 0)
3971 {
3972 fd = x->x_fd;
3973 pthread_mutex_unlock(&x->x_mutex);
3974 close (fd);
3975 pthread_mutex_lock(&x->x_mutex);
3976 x->x_fd = -1;
3977 }
3978 if (x->x_requestcode == REQUEST_CLOSE)
3979 x->x_requestcode = REQUEST_NOTHING;
3980 sfread_cond_signal(&x->x_answercondition);
3981 }
3982 else if (x->x_requestcode == REQUEST_QUIT)
3983 {
3984 if (x->x_fd >= 0)
3985 {
3986 fd = x->x_fd;
3987 pthread_mutex_unlock(&x->x_mutex);
3988 close (fd);
3989 pthread_mutex_lock(&x->x_mutex);
3990 x->x_fd = -1;
3991 }
3992 x->x_requestcode = REQUEST_NOTHING;
3993 sfread_cond_signal(&x->x_answercondition);
3994 break;
3995 }
3996 else
3997 {
3998#ifdef DEBUG_SOUNDFILE
3999 pute("13\n");
4000#endif
4001 }
4002 }
4003#ifdef DEBUG_SOUNDFILE
4004 pute("thread exit\n");
4005#endif
4006 pthread_mutex_unlock(&x->x_mutex);
4007 return (0);
4008}
4009
4010/******** the object proper runs in the calling (parent) thread ****/
4011
4012static void readsf_tick(t_readsf *x);
4013
4014static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize)
4015{
4016 t_readsf *x;
4017 int nchannels = fnchannels, bufsize = fbufsize, i;
4018 char *buf;
4019
4020 if (nchannels < 1)
4021 nchannels = 1;
4022 else if (nchannels > MAXSFCHANS)
4023 nchannels = MAXSFCHANS;
4024 if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
4025 else if (bufsize < MINBUFSIZE)
4026 bufsize = MINBUFSIZE;
4027 else if (bufsize > MAXBUFSIZE)
4028 bufsize = MAXBUFSIZE;
4029 buf = getbytes(bufsize);
4030 if (!buf) return (0);
4031
4032 x = (t_readsf *)pd_new(readsf_class);
4033
4034 for (i = 0; i < nchannels; i++)
4035 outlet_new(&x->x_obj, gensym("signal"));
4036 x->x_noutlets = nchannels;
4037 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
4038 pthread_mutex_init(&x->x_mutex, 0);
4039 pthread_cond_init(&x->x_requestcondition, 0);
4040 pthread_cond_init(&x->x_answercondition, 0);
4041 x->x_vecsize = MAXVECSIZE;
4042 x->x_state = STATE_IDLE;
4043 x->x_clock = clock_new(x, (t_method)readsf_tick);
4044 x->x_canvas = canvas_getcurrent();
4045 x->x_bytespersample = 2;
4046 x->x_sfchannels = 1;
4047 x->x_fd = -1;
4048 x->x_buf = buf;
4049 x->x_bufsize = bufsize;
4050 x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
4051 pthread_create(&x->x_childthread, 0, readsf_child_main, x);
4052 return (x);
4053}
4054
4055static void readsf_tick(t_readsf *x)
4056{
4057 outlet_bang(x->x_bangout);
4058}
4059
4060static t_int *readsf_perform(t_int *w)
4061{
4062 t_readsf *x = (t_readsf *)(w[1]);
4063 int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j,
4064 bytespersample = x->x_bytespersample,
4065 bigendian = x->x_bigendian;
4066 float *fp;
4067 if (x->x_state == STATE_STREAM)
4068 {
4069 int wantbytes, nchannels, sfchannels = x->x_sfchannels;
4070 pthread_mutex_lock(&x->x_mutex);
4071 wantbytes = sfchannels * vecsize * bytespersample;
4072 while (
4073 !x->x_eof && x->x_fifohead >= x->x_fifotail &&
4074 x->x_fifohead < x->x_fifotail + wantbytes-1)
4075 {
4076#ifdef DEBUG_SOUNDFILE
4077 pute("wait...\n");
4078#endif
4079 sfread_cond_signal(&x->x_requestcondition);
4080 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
4081#ifdef DEBUG_SOUNDFILE
4082 pute("done\n");
4083#endif
4084 }
4085 if (x->x_eof && x->x_fifohead >= x->x_fifotail &&
4086 x->x_fifohead < x->x_fifotail + wantbytes-1)
4087 {
4088 int xfersize;
4089 if (x->x_fileerror)
4090 {
4091 pd_error(x, "dsp: %s: %s", x->x_filename,
4092 (x->x_fileerror == EIO ?
4093 "unknown or bad header format" :
4094 strerror(x->x_fileerror)));
4095 }
4096 clock_delay(x->x_clock, 0);
4097 x->x_state = STATE_IDLE;
4098
4099 /* if there's a partial buffer left, copy it out. */
4100 xfersize = (x->x_fifohead - x->x_fifotail + 1) /
4101 (sfchannels * bytespersample);
4102 if (xfersize)
4103 {
4104 soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
4105 (unsigned char *)(x->x_buf + x->x_fifotail), xfersize,
4106 bytespersample, bigendian);
4107 vecsize -= xfersize;
4108 }
4109 /* then zero out the (rest of the) output */
4110 for (i = 0; i < noutlets; i++)
4111 for (j = vecsize, fp = x->x_outvec[i] + xfersize; j--; )
4112 *fp++ = 0;
4113
4114 sfread_cond_signal(&x->x_requestcondition);
4115 pthread_mutex_unlock(&x->x_mutex);
4116 return (w+2);
4117 }
4118
4119 soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
4120 (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
4121 bytespersample, bigendian);
4122
4123 x->x_fifotail += wantbytes;
4124 if (x->x_fifotail >= x->x_fifosize)
4125 x->x_fifotail = 0;
4126 if ((--x->x_sigcountdown) <= 0)
4127 {
4128 sfread_cond_signal(&x->x_requestcondition);
4129 x->x_sigcountdown = x->x_sigperiod;
4130 }
4131 pthread_mutex_unlock(&x->x_mutex);
4132 }
4133 else
4134 {
4135 idle:
4136 for (i = 0; i < noutlets; i++)
4137 for (j = vecsize, fp = x->x_outvec[i]; j--; )
4138 *fp++ = 0;
4139 }
4140 return (w+2);
4141}
4142
4143static void readsf_start(t_readsf *x)
4144{
4145 /* start making output. If we're in the "startup" state change
4146 to the "running" state. */
4147 if (x->x_state == STATE_STARTUP)
4148 x->x_state = STATE_STREAM;
4149 else pd_error(x, "readsf: start requested with no prior 'open'");
4150}
4151
4152static void readsf_stop(t_readsf *x)
4153{
4154 /* LATER rethink whether you need the mutex just to set a variable? */
4155 pthread_mutex_lock(&x->x_mutex);
4156 x->x_state = STATE_IDLE;
4157 x->x_requestcode = REQUEST_CLOSE;
4158 sfread_cond_signal(&x->x_requestcondition);
4159 pthread_mutex_unlock(&x->x_mutex);
4160}
4161
4162static void readsf_float(t_readsf *x, t_floatarg f)
4163{
4164 if (f != 0)
4165 readsf_start(x);
4166 else readsf_stop(x);
4167}
4168
4169 /* open method. Called as:
4170 open filename [skipframes headersize channels bytespersamp endianness]
4171 (if headersize is zero, header is taken to be automatically
4172 detected; thus, use the special "-1" to mean a truly headerless file.)
4173 */
4174
4175static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv)
4176{
4177 t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
4178 t_float onsetframes = atom_getfloatarg(1, argc, argv);
4179 t_float headerbytes = atom_getfloatarg(2, argc, argv);
4180 t_float channels = atom_getfloatarg(3, argc, argv);
4181 t_float bytespersamp = atom_getfloatarg(4, argc, argv);
4182 t_symbol *endian = atom_getsymbolarg(5, argc, argv);
4183 if (!*filesym->s_name)
4184 return;
4185 pthread_mutex_lock(&x->x_mutex);
4186 x->x_requestcode = REQUEST_OPEN;
4187 x->x_filename = filesym->s_name;
4188 x->x_fifotail = 0;
4189 x->x_fifohead = 0;
4190 if (*endian->s_name == 'b')
4191 x->x_bigendian = 1;
4192 else if (*endian->s_name == 'l')
4193 x->x_bigendian = 0;
4194 else if (*endian->s_name)
4195 pd_error(x, "endianness neither 'b' nor 'l'");
4196 else x->x_bigendian = garray_ambigendian();
4197 x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0);
4198 x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes :
4199 (headerbytes == 0 ? -1 : 0));
4200 x->x_sfchannels = (channels >= 1 ? channels : 1);
4201 x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
4202 x->x_eof = 0;
4203 x->x_fileerror = 0;
4204 x->x_state = STATE_STARTUP;
4205 sfread_cond_signal(&x->x_requestcondition);
4206 pthread_mutex_unlock(&x->x_mutex);
4207}
4208
4209static void readsf_dsp(t_readsf *x, t_signal **sp)
4210{
4211 int i, noutlets = x->x_noutlets;
4212 pthread_mutex_lock(&x->x_mutex);
4213 x->x_vecsize = sp[0]->s_n;
4214
4215 x->x_sigperiod = (x->x_fifosize /
4216 (x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
4217 for (i = 0; i < noutlets; i++)
4218 x->x_outvec[i] = sp[i]->s_vec;
4219 pthread_mutex_unlock(&x->x_mutex);
4220 dsp_add(readsf_perform, 1, x);
4221}
4222
4223static void readsf_print(t_readsf *x)
4224{
4225 post("state %d", x->x_state);
4226 post("fifo head %d", x->x_fifohead);
4227 post("fifo tail %d", x->x_fifotail);
4228 post("fifo size %d", x->x_fifosize);
4229 post("fd %d", x->x_fd);
4230 post("eof %d", x->x_eof);
4231}
4232
4233static void readsf_free(t_readsf *x)
4234{
4235 /* request QUIT and wait for acknowledge */
4236 void *threadrtn;
4237 pthread_mutex_lock(&x->x_mutex);
4238 x->x_requestcode = REQUEST_QUIT;
4239 sfread_cond_signal(&x->x_requestcondition);
4240 while (x->x_requestcode != REQUEST_NOTHING)
4241 {
4242 sfread_cond_signal(&x->x_requestcondition);
4243 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
4244 }
4245 pthread_mutex_unlock(&x->x_mutex);
4246 if (pthread_join(x->x_childthread, &threadrtn))
4247 error("readsf_free: join failed");
4248
4249 pthread_cond_destroy(&x->x_requestcondition);
4250 pthread_cond_destroy(&x->x_answercondition);
4251 pthread_mutex_destroy(&x->x_mutex);
4252 freebytes(x->x_buf, x->x_bufsize);
4253 clock_free(x->x_clock);
4254}
4255
4256static void readsf_setup(void)
4257{
4258 readsf_class = class_new(gensym("readsf~"), (t_newmethod)readsf_new,
4259 (t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
4260 class_addfloat(readsf_class, (t_method)readsf_float);
4261 class_addmethod(readsf_class, (t_method)readsf_start, gensym("start"), 0);
4262 class_addmethod(readsf_class, (t_method)readsf_stop, gensym("stop"), 0);
4263 class_addmethod(readsf_class, (t_method)readsf_dsp, gensym("dsp"), 0);
4264 class_addmethod(readsf_class, (t_method)readsf_open, gensym("open"),
4265 A_GIMME, 0);
4266 class_addmethod(readsf_class, (t_method)readsf_print, gensym("print"), 0);
4267}
4268
4269/******************************* writesf *******************/
4270
4271static t_class *writesf_class;
4272
4273#define t_writesf t_readsf /* just re-use the structure */
4274
4275/************** the child thread which performs file I/O ***********/
4276
4277static void *writesf_child_main(void *zz)
4278{
4279 t_writesf *x = zz;
4280#ifdef DEBUG_SOUNDFILE
4281 pute("1\n");
4282#endif
4283 pthread_mutex_lock(&x->x_mutex);
4284 while (1)
4285 {
4286#ifdef DEBUG_SOUNDFILE
4287 pute("0\n");
4288#endif
4289 if (x->x_requestcode == REQUEST_NOTHING)
4290 {
4291#ifdef DEBUG_SOUNDFILE
4292 pute("wait 2\n");
4293#endif
4294 sfread_cond_signal(&x->x_answercondition);
4295 sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
4296#ifdef DEBUG_SOUNDFILE
4297 pute("3\n");
4298#endif
4299 }
4300 else if (x->x_requestcode == REQUEST_OPEN)
4301 {
4302 char boo[80];
4303 int fd, sysrtn, writebytes;
4304
4305 /* copy file stuff out of the data structure so we can
4306 relinquish the mutex while we're in open_soundfile(). */
4307 long onsetframes = x->x_onsetframes;
4308 long bytelimit = 0x7fffffff;
4309 int skipheaderbytes = x->x_skipheaderbytes;
4310 int bytespersample = x->x_bytespersample;
4311 int sfchannels = x->x_sfchannels;
4312 int bigendian = x->x_bigendian;
4313 int filetype = x->x_filetype;
4314 char *filename = x->x_filename;
4315 t_canvas *canvas = x->x_canvas;
4316 float samplerate = x->x_samplerate;
4317
4318 /* alter the request code so that an ensuing "open" will get
4319 noticed. */
4320#ifdef DEBUG_SOUNDFILE
4321 pute("4\n");
4322#endif
4323 x->x_requestcode = REQUEST_BUSY;
4324 x->x_fileerror = 0;
4325
4326 /* if there's already a file open, close it */
4327 if (x->x_fd >= 0)
4328 {
4329 pthread_mutex_unlock(&x->x_mutex);
4330 close (x->x_fd);
4331 pthread_mutex_lock(&x->x_mutex);
4332 x->x_fd = -1;
4333 if (x->x_requestcode != REQUEST_BUSY)
4334 continue;
4335 }
4336 /* open the soundfile with the mutex unlocked */
4337 pthread_mutex_unlock(&x->x_mutex);
4338 fd = create_soundfile(canvas, filename, filetype, 0,
4339 bytespersample, bigendian, sfchannels,
4340 garray_ambigendian() != bigendian, samplerate);
4341 pthread_mutex_lock(&x->x_mutex);
4342#ifdef DEBUG_SOUNDFILE
4343 pute("5\n");
4344#endif
4345
4346 if (fd < 0)
4347 {
4348 x->x_fd = -1;
4349 x->x_eof = 1;
4350 x->x_fileerror = errno;
4351#ifdef DEBUG_SOUNDFILE
4352 pute("open failed\n");
4353 pute(filename);
4354#endif
4355 x->x_requestcode = REQUEST_NOTHING;
4356 continue;
4357 }
4358 /* check if another request has been made; if so, field it */
4359 if (x->x_requestcode != REQUEST_BUSY)
4360 continue;
4361#ifdef DEBUG_SOUNDFILE
4362 pute("6\n");
4363#endif
4364 x->x_fd = fd;
4365 x->x_fifotail = 0;
4366 x->x_itemswritten = 0;
4367 x->x_swap = garray_ambigendian() != bigendian;
4368 /* in a loop, wait for the fifo to have data and write it
4369 to disk */
4370 while (x->x_requestcode == REQUEST_BUSY ||
4371 (x->x_requestcode == REQUEST_CLOSE &&
4372 x->x_fifohead != x->x_fifotail))
4373 {
4374 int fifosize = x->x_fifosize, fifotail;
4375 char *buf = x->x_buf;
4376#ifdef DEBUG_SOUNDFILE
4377 pute("77\n");
4378#endif
4379
4380 /* if the head is < the tail, we can immediately write
4381 from tail to end of fifo to disk; otherwise we hold off
4382 writing until there are at least WRITESIZE bytes in the
4383 buffer */
4384 if (x->x_fifohead < x->x_fifotail ||
4385 x->x_fifohead >= x->x_fifotail + WRITESIZE
4386 || (x->x_requestcode == REQUEST_CLOSE &&
4387 x->x_fifohead != x->x_fifotail))
4388 {
4389 writebytes = (x->x_fifohead < x->x_fifotail ?
4390 fifosize : x->x_fifohead) - x->x_fifotail;
4391 if (writebytes > READSIZE)
4392 writebytes = READSIZE;
4393 }
4394 else
4395 {
4396#ifdef DEBUG_SOUNDFILE
4397 pute("wait 7a ...\n");
4398#endif
4399 sfread_cond_signal(&x->x_answercondition);
4400#ifdef DEBUG_SOUNDFILE
4401 pute("signalled\n");
4402#endif
4403 sfread_cond_wait(&x->x_requestcondition,
4404 &x->x_mutex);
4405#ifdef DEBUG_SOUNDFILE
4406 pute("7a done\n");
4407#endif
4408 continue;
4409 }
4410#ifdef DEBUG_SOUNDFILE
4411 pute("8\n");
4412#endif
4413 fifotail = x->x_fifotail;
4414 fd = x->x_fd;
4415 pthread_mutex_unlock(&x->x_mutex);
4416 sysrtn = write(fd, buf + fifotail, writebytes);
4417 pthread_mutex_lock(&x->x_mutex);
4418 if (x->x_requestcode != REQUEST_BUSY &&
4419 x->x_requestcode != REQUEST_CLOSE)
4420 break;
4421 if (sysrtn < writebytes)
4422 {
4423#ifdef DEBUG_SOUNDFILE
4424 pute("fileerror\n");
4425#endif
4426 x->x_fileerror = errno;
4427 break;
4428 }
4429 else
4430 {
4431 x->x_fifotail += sysrtn;
4432 if (x->x_fifotail == fifosize)
4433 x->x_fifotail = 0;
4434 }
4435 x->x_itemswritten +=
4436 sysrtn / (x->x_bytespersample * x->x_sfchannels);
4437 sprintf(boo, "after: head %d, tail %d\n",
4438 x->x_fifohead, x->x_fifotail);
4439#ifdef DEBUG_SOUNDFILE
4440 pute(boo);
4441#endif
4442 /* signal parent in case it's waiting for data */
4443 sfread_cond_signal(&x->x_answercondition);
4444 }
4445 }
4446 else if (x->x_requestcode == REQUEST_CLOSE ||
4447 x->x_requestcode == REQUEST_QUIT)
4448 {
4449 int quit = (x->x_requestcode == REQUEST_QUIT);
4450 if (x->x_fd >= 0)
4451 {
4452 int bytesperframe = x->x_bytespersample * x->x_sfchannels;
4453 int bigendian = x->x_bigendian;
4454 char *filename = x->x_filename;
4455 int fd = x->x_fd;
4456 int filetype = x->x_filetype;
4457 int itemswritten = x->x_itemswritten;
4458 int swap = x->x_swap;
4459 pthread_mutex_unlock(&x->x_mutex);
4460
4461 soundfile_finishwrite(x, filename, fd,
4462 filetype, 0x7fffffff, itemswritten,
4463 bytesperframe, swap);
4464 close (fd);
4465
4466 pthread_mutex_lock(&x->x_mutex);
4467 x->x_fd = -1;
4468 }
4469 x->x_requestcode = REQUEST_NOTHING;
4470 sfread_cond_signal(&x->x_answercondition);
4471 if (quit)
4472 break;
4473 }
4474 else
4475 {
4476#ifdef DEBUG_SOUNDFILE
4477 pute("13\n");
4478#endif
4479 }
4480 }
4481#ifdef DEBUG_SOUNDFILE
4482 pute("thread exit\n");
4483#endif
4484 pthread_mutex_unlock(&x->x_mutex);
4485 return (0);
4486}
4487
4488/******** the object proper runs in the calling (parent) thread ****/
4489
4490static void writesf_tick(t_writesf *x);
4491
4492static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize)
4493{
4494 t_writesf *x;
4495 int nchannels = fnchannels, bufsize = fbufsize, i;
4496 char *buf;
4497
4498 if (nchannels < 1)
4499 nchannels = 1;
4500 else if (nchannels > MAXSFCHANS)
4501 nchannels = MAXSFCHANS;
4502 if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
4503 else if (bufsize < MINBUFSIZE)
4504 bufsize = MINBUFSIZE;
4505 else if (bufsize > MAXBUFSIZE)
4506 bufsize = MAXBUFSIZE;
4507 buf = getbytes(bufsize);
4508 if (!buf) return (0);
4509
4510 x = (t_writesf *)pd_new(writesf_class);
4511
4512 for (i = 1; i < nchannels; i++)
4513 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
4514
4515 x->x_f = 0;
4516 x->x_sfchannels = nchannels;
4517 pthread_mutex_init(&x->x_mutex, 0);
4518 pthread_cond_init(&x->x_requestcondition, 0);
4519 pthread_cond_init(&x->x_answercondition, 0);
4520 x->x_vecsize = MAXVECSIZE;
4521 x->x_insamplerate = x->x_samplerate = 0;
4522 x->x_state = STATE_IDLE;
4523 x->x_clock = 0; /* no callback needed here */
4524 x->x_canvas = canvas_getcurrent();
4525 x->x_bytespersample = 2;
4526 x->x_fd = -1;
4527 x->x_buf = buf;
4528 x->x_bufsize = bufsize;
4529 x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
4530 pthread_create(&x->x_childthread, 0, writesf_child_main, x);
4531 return (x);
4532}
4533
4534static t_int *writesf_perform(t_int *w)
4535{
4536 t_writesf *x = (t_writesf *)(w[1]);
4537 int vecsize = x->x_vecsize, sfchannels = x->x_sfchannels, i, j,
4538 bytespersample = x->x_bytespersample,
4539 bigendian = x->x_bigendian;
4540 float *fp;
4541 if (x->x_state == STATE_STREAM)
4542 {
4543 int wantbytes;
4544 pthread_mutex_lock(&x->x_mutex);
4545 wantbytes = sfchannels * vecsize * bytespersample;
4546 while (x->x_fifotail > x->x_fifohead &&
4547 x->x_fifotail < x->x_fifohead + wantbytes + 1)
4548 {
4549#ifdef DEBUG_SOUNDFILE
4550 pute("wait...\n");
4551#endif
4552 sfread_cond_signal(&x->x_requestcondition);
4553 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
4554#ifdef DEBUG_SOUNDFILE
4555 pute("done\n");
4556#endif
4557 }
4558
4559 soundfile_xferout(sfchannels, x->x_outvec,
4560 (unsigned char *)(x->x_buf + x->x_fifohead), vecsize, 0,
4561 bytespersample, bigendian, 1.);
4562
4563 x->x_fifohead += wantbytes;
4564 if (x->x_fifohead >= x->x_fifosize)
4565 x->x_fifohead = 0;
4566 if ((--x->x_sigcountdown) <= 0)
4567 {
4568#ifdef DEBUG_SOUNDFILE
4569 pute("signal 1\n");
4570#endif
4571 sfread_cond_signal(&x->x_requestcondition);
4572 x->x_sigcountdown = x->x_sigperiod;
4573 }
4574 pthread_mutex_unlock(&x->x_mutex);
4575 }
4576 return (w+2);
4577}
4578
4579static void writesf_start(t_writesf *x)
4580{
4581 /* start making output. If we're in the "startup" state change
4582 to the "running" state. */
4583 if (x->x_state == STATE_STARTUP)
4584 x->x_state = STATE_STREAM;
4585 else
4586 pd_error(x, "writesf: start requested with no prior 'open'");
4587}
4588
4589static void writesf_stop(t_writesf *x)
4590{
4591 /* LATER rethink whether you need the mutex just to set a Svariable? */
4592 pthread_mutex_lock(&x->x_mutex);
4593 x->x_state = STATE_IDLE;
4594 x->x_requestcode = REQUEST_CLOSE;
4595#ifdef DEBUG_SOUNDFILE
4596 pute("signal 2\n");
4597#endif
4598 sfread_cond_signal(&x->x_requestcondition);
4599 pthread_mutex_unlock(&x->x_mutex);
4600}
4601
4602
4603 /* open method. Called as: open [args] filename with args as in
4604 soundfiler_writeargparse().
4605 */
4606
4607static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv)
4608{
4609 t_symbol *filesym;
4610 int filetype, bytespersamp, swap, bigendian, normalize;
4611 long onset, nframes;
4612 float samplerate;
4613 if (soundfiler_writeargparse(x, &argc,
4614 &argv, &filesym, &filetype, &bytespersamp, &swap, &bigendian,
4615 &normalize, &onset, &nframes, &samplerate))
4616 {
4617 pd_error(x,
4618 "writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ...");
4619 post("... [-big,-little] [-rate ####] filename");
4620 }
4621 if (normalize || onset || (nframes != 0x7fffffff))
4622 pd_error(x, "normalize/onset/nframes argument to writesf~: ignored");
4623 if (argc)
4624 pd_error(x, "extra argument(s) to writesf~: ignored");
4625 pthread_mutex_lock(&x->x_mutex);
4626 x->x_bytespersample = bytespersamp;
4627 x->x_swap = swap;
4628 x->x_bigendian = bigendian;
4629 x->x_filename = filesym->s_name;
4630 x->x_filetype = filetype;
4631 x->x_itemswritten = 0;
4632 x->x_requestcode = REQUEST_OPEN;
4633 x->x_fifotail = 0;
4634 x->x_fifohead = 0;
4635 x->x_eof = 0;
4636 x->x_fileerror = 0;
4637 x->x_state = STATE_STARTUP;
4638 x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
4639 if (samplerate > 0)
4640 x->x_samplerate = samplerate;
4641 else if (x->x_insamplerate > 0)
4642 x->x_samplerate = x->x_insamplerate;
4643 else x->x_samplerate = sys_getsr();
4644 /* set fifosize from bufsize. fifosize must be a
4645 multiple of the number of bytes eaten for each DSP
4646 tick. */
4647 x->x_fifosize = x->x_bufsize - (x->x_bufsize %
4648 (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
4649 /* arrange for the "request" condition to be signalled 16
4650 times per buffer */
4651 x->x_sigcountdown = x->x_sigperiod =
4652 (x->x_fifosize /
4653 (16 * x->x_bytespersample * x->x_sfchannels *
4654 x->x_vecsize));
4655 sfread_cond_signal(&x->x_requestcondition);
4656 pthread_mutex_unlock(&x->x_mutex);
4657}
4658
4659static void writesf_dsp(t_writesf *x, t_signal **sp)
4660{
4661 int i, ninlets = x->x_sfchannels;
4662 pthread_mutex_lock(&x->x_mutex);
4663 x->x_vecsize = sp[0]->s_n;
4664
4665 x->x_sigperiod = (x->x_fifosize /
4666 (x->x_bytespersample * ninlets * x->x_vecsize));
4667 for (i = 0; i < ninlets; i++)
4668 x->x_outvec[i] = sp[i]->s_vec;
4669 x->x_insamplerate = sp[0]->s_sr;
4670 pthread_mutex_unlock(&x->x_mutex);
4671 dsp_add(writesf_perform, 1, x);
4672}
4673
4674static void writesf_print(t_writesf *x)
4675{
4676 post("state %d", x->x_state);
4677 post("fifo head %d", x->x_fifohead);
4678 post("fifo tail %d", x->x_fifotail);
4679 post("fifo size %d", x->x_fifosize);
4680 post("fd %d", x->x_fd);
4681 post("eof %d", x->x_eof);
4682}
4683
4684static void writesf_free(t_writesf *x)
4685{
4686 /* request QUIT and wait for acknowledge */
4687 void *threadrtn;
4688 pthread_mutex_lock(&x->x_mutex);
4689 x->x_requestcode = REQUEST_QUIT;
4690 /* post("stopping writesf thread..."); */
4691 sfread_cond_signal(&x->x_requestcondition);
4692 while (x->x_requestcode != REQUEST_NOTHING)
4693 {
4694 /* post("signalling..."); */
4695 sfread_cond_signal(&x->x_requestcondition);
4696 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
4697 }
4698 pthread_mutex_unlock(&x->x_mutex);
4699 if (pthread_join(x->x_childthread, &threadrtn))
4700 error("writesf_free: join failed");
4701 /* post("... done."); */
4702
4703 pthread_cond_destroy(&x->x_requestcondition);
4704 pthread_cond_destroy(&x->x_answercondition);
4705 pthread_mutex_destroy(&x->x_mutex);
4706 freebytes(x->x_buf, x->x_bufsize);
4707}
4708
4709static void writesf_setup(void)
4710{
4711 writesf_class = class_new(gensym("writesf~"), (t_newmethod)writesf_new,
4712 (t_method)writesf_free, sizeof(t_writesf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
4713 class_addmethod(writesf_class, (t_method)writesf_start, gensym("start"), 0);
4714 class_addmethod(writesf_class, (t_method)writesf_stop, gensym("stop"), 0);
4715 class_addmethod(writesf_class, (t_method)writesf_dsp, gensym("dsp"), 0);
4716 class_addmethod(writesf_class, (t_method)writesf_open, gensym("open"),
4717 A_GIMME, 0);
4718 class_addmethod(writesf_class, (t_method)writesf_print, gensym("print"), 0);
4719 CLASS_MAINSIGNALIN(writesf_class, t_writesf, x_f);
4720}
4721
4722#endif
4723
4724/* ------------------------ global setup routine ------------------------- */
4725
4726void d_soundfile_setup(void)
4727{
4728 soundfiler_setup();
4729#ifndef FIXEDPOINT
4730 readsf_setup();
4731 writesf_setup();
4732#endif
4733}
4734
diff --git a/apps/plugins/pdbox/PDa/src/d_ugen.c b/apps/plugins/pdbox/PDa/src/d_ugen.c
new file mode 100644
index 0000000000..9820f190cc
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_ugen.c
@@ -0,0 +1,2252 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* These routines build a copy of the DSP portion of a graph, which is
6 then sorted into a linear list of DSP operations which are added to
7 the DSP duty cycle called by the scheduler. Once that's been done,
8 we delete the copy. The DSP objects are represented by "ugenbox"
9 structures which are parallel to the DSP objects in the graph and
10 have vectors of siginlets and sigoutlets which record their
11 interconnections.
12*/
13
14/* hacked to run subpatches with different samplerates
15 * only samplerates that are a power_of_2-multiple of the
16 *
17 * mfg.gfd.uil
18 * IOhannes
19 *
20 * edited lines are marked with "IOhannes"
21 *
22 */
23
24
25#include "m_pd.h"
26#include "m_imp.h"
27#include <stdlib.h>
28#include <stdarg.h>
29
30extern t_class *vinlet_class, *voutlet_class, *canvas_class;
31t_sample *obj_findsignalscalar(t_object *x, int m);
32static int ugen_loud;
33EXTERN_STRUCT _vinlet;
34EXTERN_STRUCT _voutlet;
35
36void vinlet_dspprolog(struct _vinlet *x, t_signal **parentsigs,
37 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
38 int switched);
39void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs,
40 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
41 int switched);
42void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs,
43 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
44 int switched);
45
46t_int *zero_perform(t_int *w) /* zero out a vector */
47{
48 t_float *out = (t_float *)(w[1]);
49 int n = (int)(w[2]);
50 while (n--) *out++ = 0;
51 return (w+3);
52}
53
54t_int *zero_perf8(t_int *w)
55{
56 t_float *out = (t_float *)(w[1]);
57 int n = (int)(w[2]);
58
59 for (; n; n -= 8, out += 8)
60 {
61 out[0] = 0;
62 out[1] = 0;
63 out[2] = 0;
64 out[3] = 0;
65 out[4] = 0;
66 out[5] = 0;
67 out[6] = 0;
68 out[7] = 0;
69 }
70 return (w+3);
71}
72
73void dsp_add_zero(t_sample *out, int n)
74{
75 if (n&7)
76 dsp_add(zero_perform, 2, out, n);
77 else
78 dsp_add(zero_perf8, 2, out, n);
79}
80
81/* ---------------------------- block~ ----------------------------- */
82
83/* The "block~ object maintains the containing canvas's DSP computation,
84calling it at a super- or sub-multiple of the containing canvas's
85calling frequency. The block~'s creation arguments specify block size
86and overlap. Block~ does no "dsp" computation in its own right, but it
87adds prolog and epilog code before and after the canvas's unit generators.
88
89A subcanvas need not have a block~ at all; if there's none, its
90ugens are simply put on the list without any prolog or epilog code.
91
92Block~ may be invoked as switch~, in which case it also acts to switch the
93subcanvas on and off. The overall order of scheduling for a subcanvas
94is thus,
95
96 inlet and outlet prologue code (1)
97 block prologue (2)
98 the objects in the subcanvas, including inlets and outlets
99 block epilogue (2)
100 outlet epilogue code (2)
101
102where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
103
104If we're reblocked, the inlet prolog and outlet epilog code takes care of
105overlapping and buffering to deal with vector size changes. If we're switched
106but not reblocked, the inlet prolog is not needed, and the output epilog is
107ONLY run when the block is switched off; in this case the epilog code simply
108copies zeros to all signal outlets.
109*/
110
111static int dsp_phase;
112static t_class *block_class;
113
114typedef struct _block
115{
116 t_object x_obj;
117 int x_vecsize;
118 int x_overlap;
119 int x_phase; /* from 0 to period-1; when zero we run the block */
120 int x_period; /* submultiple of containing canvas */
121 int x_frequency; /* supermultiple of comtaining canvas */
122 int x_count;
123 int x_blocklength; /* length of dspchain for this block */
124 int x_epiloglength; /* length of epilog */
125 char x_switched; /* true if we're acting as a a switch */
126 char x_switchon; /* true if we're switched on */
127 char x_reblock; /* true if inlets and outlets are reblocking */
128 int x_upsample; /* IOhannes: upsampling-factor */
129 int x_downsample; /* IOhannes: downsampling-factor */
130
131} t_block;
132
133static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
134 t_floatarg fupsample);
135
136static void *block_new(t_floatarg fvecsize, t_floatarg foverlap,
137 t_floatarg fupsample) /* IOhannes */
138{
139 t_block *x = (t_block *)pd_new(block_class);
140 x->x_phase = 0;
141 x->x_period = 1;
142 x->x_frequency = 1;
143 x->x_switched = 0;
144 x->x_switchon = 1;
145 block_set(x, fvecsize, foverlap, fupsample);
146 return (x);
147}
148
149static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
150 t_floatarg fupsample)
151{
152 int upsample, downsample; /* IOhannes */
153 int vecsize = fvecsize;
154 int overlap = foverlap;
155 int dspstate = canvas_suspend_dsp();
156 if (overlap < 1)
157 overlap = 1;
158 if (vecsize < 0)
159 vecsize = 0; /* this means we'll get it from parent later. */
160
161 /* IOhannes { */
162 if (fupsample <= 0) upsample = downsample = 1;
163 else if (fupsample >= 1) {
164 upsample = fupsample;
165 downsample = 1;
166 } else {
167 downsample = 1.0 / fupsample;
168 upsample = 1;
169 }
170 /* } IOhannes */
171
172 if (vecsize && (vecsize != (1 << ilog2(vecsize))))
173 {
174 pd_error(x, "block~: vector size not a power of 2");
175 vecsize = 64;
176 }
177 if (overlap != (1 << ilog2(overlap)))
178 {
179 pd_error(x, "block~: overlap not a power of 2");
180 overlap = 1;
181 }
182 /* IOhannes { */
183 if (downsample != (1 << ilog2(downsample)))
184 {
185 pd_error(x, "block~: downsampling not a power of 2");
186 downsample = 1;
187 }
188 if (upsample != (1 << ilog2(upsample)))
189 {
190 pd_error(x, "block~: upsampling not a power of 2");
191 upsample = 1;
192 }
193 /* } IOhannes */
194
195
196 x->x_vecsize = vecsize;
197 x->x_overlap = overlap;
198 /* IOhannes { */
199 x->x_upsample = upsample;
200 x->x_downsample = downsample;
201 /* } IOhannes */
202 canvas_resume_dsp(dspstate);
203}
204
205static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap,
206 t_floatarg fupsample) /* IOhannes */
207{
208 t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
209 x->x_switched = 1;
210 x->x_switchon = 0;
211 return (x);
212}
213
214static void block_float(t_block *x, t_floatarg f)
215{
216 if (x->x_switched)
217 x->x_switchon = (f != 0);
218}
219#define PROLOGCALL 2
220#define EPILOGCALL 2
221
222static t_int *block_prolog(t_int *w)
223{
224 t_block *x = (t_block *)w[1];
225 int phase = x->x_phase;
226 /* if we're switched off, jump past the epilog code */
227 if (!x->x_switchon)
228 return (w + x->x_blocklength);
229 if (phase)
230 {
231 phase++;
232 if (phase == x->x_period) phase = 0;
233 x->x_phase = phase;
234 return (w + x->x_blocklength); /* skip block; jump past epilog */
235 }
236 else
237 {
238 x->x_count = x->x_frequency;
239 x->x_phase = (x->x_period > 1 ? 1 : 0);
240 return (w + PROLOGCALL); /* beginning of block is next ugen */
241 }
242}
243
244static t_int *block_epilog(t_int *w)
245{
246 t_block *x = (t_block *)w[1];
247 int count = x->x_count - 1;
248 if (!x->x_reblock)
249 return (w + x->x_epiloglength + EPILOGCALL);
250 if (count)
251 {
252 x->x_count = count;
253 return (w - (x->x_blocklength -
254 (PROLOGCALL + EPILOGCALL))); /* go to ugen after prolog */
255 }
256 else return (w + EPILOGCALL);
257}
258
259static void block_dsp(t_block *x, t_signal **sp)
260{
261 /* do nothing here */
262}
263
264/* ------------------ DSP call list ----------------------- */
265
266static t_int *dsp_chain;
267static int dsp_chainsize;
268
269void dsp_add(t_perfroutine f, int n, ...)
270{
271 int newsize = dsp_chainsize + n+1, i;
272 va_list ap;
273
274 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
275 newsize * sizeof (t_int));
276 dsp_chain[dsp_chainsize-1] = (t_int)f;
277 va_start(ap, n);
278 for (i = 0; i < n; i++)
279 dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
280 va_end(ap);
281 dsp_chain[newsize-1] = 0;
282 dsp_chainsize = newsize;
283}
284
285 /* at Guenter's suggestion, here's a vectorized version */
286void dsp_addv(t_perfroutine f, int n, t_int *vec)
287{
288 int newsize = dsp_chainsize + n+1, i;
289
290 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
291 newsize * sizeof (t_int));
292 dsp_chain[dsp_chainsize-1] = (t_int)f;
293 for (i = 0; i < n; i++)
294 dsp_chain[dsp_chainsize + i] = vec[i];
295 dsp_chain[newsize-1] = 0;
296 dsp_chainsize = newsize;
297}
298
299void dsp_tick(void)
300{
301 if (dsp_chain)
302 {
303 t_int *ip;
304 for (ip = dsp_chain; *ip; ) ip = (*(t_perfroutine)(*ip))(ip);
305 dsp_phase++;
306 }
307}
308
309/* ---------------- signals ---------------------------- */
310
311int ilog2(int n)
312{
313 int r = -1;
314 if (n <= 0) return(0);
315 while (n)
316 {
317 r++;
318 n >>= 1;
319 }
320 return (r);
321}
322
323 /* list of signals which can be reused, sorted by buffer size */
324static t_signal *signal_freelist[MAXLOGSIG+1];
325 /* list of reusable "borrowed" signals (which don't own sample buffers) */
326static t_signal *signal_freeborrowed;
327 /* list of all signals allocated (not including "borrowed" ones) */
328static t_signal *signal_usedlist;
329
330 /* call this when DSP is stopped to free all the signals */
331void signal_cleanup(void)
332{
333 t_signal **svec, *sig, *sig2;
334 int i;
335 while (sig = signal_usedlist)
336 {
337 signal_usedlist = sig->s_nextused;
338 if (!sig->s_isborrowed)
339 t_freebytes(sig->s_vec, sig->s_n * sizeof (*sig->s_vec));
340 t_freebytes(sig, sizeof *sig);
341 }
342 for (i = 0; i <= MAXLOGSIG; i++)
343 signal_freelist[i] = 0;
344 signal_freeborrowed = 0;
345}
346
347 /* mark the signal "reusable." */
348void signal_makereusable(t_signal *sig)
349{
350 int logn = ilog2(sig->s_n);
351#if 1
352 t_signal *s5;
353 for (s5 = signal_freeborrowed; s5; s5 = s5->s_nextfree)
354 {
355 if (s5 == sig)
356 {
357 bug("signal_free 3");
358 return;
359 }
360 }
361 for (s5 = signal_freelist[logn]; s5; s5 = s5->s_nextfree)
362 {
363 if (s5 == sig)
364 {
365 bug("signal_free 4");
366 return;
367 }
368 }
369#endif
370 if (ugen_loud) post("free %x: %d", sig, sig->s_isborrowed);
371 if (sig->s_isborrowed)
372 {
373 /* if the signal is borrowed, decrement the borrowed-from signal's
374 reference count, possibly marking it reusable too */
375 t_signal *s2 = sig->s_borrowedfrom;
376 if ((s2 == sig) || !s2)
377 bug("signal_free");
378 s2->s_refcount--;
379 if (!s2->s_refcount)
380 signal_makereusable(s2);
381 sig->s_nextfree = signal_freeborrowed;
382 signal_freeborrowed = sig;
383 }
384 else
385 {
386 /* if it's a real signal (not borrowed), put it on the free list
387 so we can reuse it. */
388 if (signal_freelist[logn] == sig) bug("signal_free 2");
389 sig->s_nextfree = signal_freelist[logn];
390 signal_freelist[logn] = sig;
391 }
392}
393
394 /* reclaim or make an audio signal. If n is zero, return a "borrowed"
395 signal whose buffer and size will be obtained later via
396 signal_setborrowed(). */
397
398t_signal *signal_new(int n, float sr)
399{
400 int logn, n2;
401 t_signal *ret, **whichlist;
402 t_sample *fp;
403 logn = ilog2(n);
404 if (n)
405 {
406 if (n != (1 << logn))
407 bug("signal buffer not a power of 2");
408 if (logn > MAXLOGSIG)
409 bug("signal buffer too large");
410 whichlist = signal_freelist + logn;
411 }
412 else
413 whichlist = &signal_freeborrowed;
414
415 /* first try to reclaim one from the free list */
416 if (ret = *whichlist)
417 *whichlist = ret->s_nextfree;
418 else
419 {
420 /* LATER figure out what to do for out-of-space here! */
421 ret = (t_signal *)t_getbytes(sizeof *ret);
422 if (n)
423 {
424 ret->s_vec = (t_sample *)getbytes(n * sizeof (*ret->s_vec));
425 ret->s_isborrowed = 0;
426 }
427 else
428 {
429 ret->s_vec = 0;
430 ret->s_isborrowed = 1;
431 }
432 ret->s_nextused = signal_usedlist;
433 signal_usedlist = ret;
434 }
435 ret->s_n = n;
436 ret->s_sr = sr;
437 ret->s_refcount = 0;
438 ret->s_borrowedfrom = 0;
439 if (ugen_loud) post("new %x: %d", ret, ret->s_isborrowed);
440 return (ret);
441}
442
443static t_signal *signal_newlike(const t_signal *sig)
444{
445 return (signal_new(sig->s_n, sig->s_sr));
446}
447
448void signal_setborrowed(t_signal *sig, t_signal *sig2)
449{
450 if (!sig->s_isborrowed || sig->s_borrowedfrom)
451 bug("signal_setborrowed");
452 if (sig == sig2)
453 bug("signal_setborrowed 2");
454 sig->s_borrowedfrom = sig2;
455 sig->s_vec = sig2->s_vec;
456 sig->s_n = sig2->s_n;
457}
458
459int signal_compatible(t_signal *s1, t_signal *s2)
460{
461 return (s1->s_n == s2->s_n && s1->s_sr == s2->s_sr);
462}
463
464/* ------------------ ugen ("unit generator") sorting ----------------- */
465
466typedef struct _ugenbox
467{
468 struct _siginlet *u_in;
469 int u_nin;
470 struct _sigoutlet *u_out;
471 int u_nout;
472 int u_phase;
473 struct _ugenbox *u_next;
474 t_object *u_obj;
475 int u_done;
476} t_ugenbox;
477
478typedef struct _siginlet
479{
480 int i_nconnect;
481 int i_ngot;
482 t_signal *i_signal;
483} t_siginlet;
484
485typedef struct _sigoutconnect
486{
487 t_ugenbox *oc_who;
488 int oc_inno;
489 struct _sigoutconnect *oc_next;
490} t_sigoutconnect;
491
492typedef struct _sigoutlet
493{
494 int o_nconnect;
495 int o_nsent;
496 t_signal *o_signal;
497 t_sigoutconnect *o_connections;
498} t_sigoutlet;
499
500
501struct _dspcontext
502{
503 struct _ugenbox *dc_ugenlist;
504 struct _dspcontext *dc_parentcontext;
505 int dc_ninlets;
506 int dc_noutlets;
507 t_signal **dc_iosigs;
508 float dc_srate;
509 int dc_vecsize;
510 char dc_toplevel; /* true if "iosigs" is invalid. */
511 char dc_reblock; /* true if we have to reblock inlets/outlets */
512 char dc_switched; /* true if we're switched */
513
514};
515
516#define t_dspcontext struct _dspcontext
517
518static int ugen_sortno = 0;
519static t_dspcontext *ugen_currentcontext;
520
521void ugen_stop(void)
522{
523 t_signal *s;
524 int i;
525 if (dsp_chain)
526 {
527 freebytes(dsp_chain, dsp_chainsize * sizeof (t_int));
528 dsp_chain = 0;
529 }
530 signal_cleanup();
531
532}
533
534void ugen_start(void)
535{
536 ugen_stop();
537 ugen_sortno++;
538 dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
539 dsp_chain[0] = 0;
540 dsp_chainsize = 1;
541 if (ugen_currentcontext) bug("ugen_start");
542}
543
544int ugen_getsortno(void)
545{
546 return (ugen_sortno);
547}
548
549#if 0
550void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
551{
552 int i, count;
553 t_signal *sig;
554 for (count = 0, sig = signal_usedlist; sig;
555 count++, sig = sig->s_nextused)
556 ;
557 post("used signals %d", count);
558 for (i = 0; i < MAXLOGSIG; i++)
559 {
560 for (count = 0, sig = signal_freelist[i]; sig;
561 count++, sig = sig->s_nextfree)
562 ;
563 if (count)
564 post("size %d: free %d", (1 << i), count);
565 }
566 for (count = 0, sig = signal_freeborrowed; sig;
567 count++, sig = sig->s_nextfree)
568 ;
569 post("free borrowed %d", count);
570
571 ugen_loud = argc;
572}
573#endif
574
575 /* start building the graph for a canvas */
576t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
577 int ninlets, int noutlets)
578{
579 t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
580 float parent_srate, srate;
581 int parent_vecsize, vecsize;
582
583 if (ugen_loud) post("ugen_start_graph...");
584
585 dc->dc_ugenlist = 0;
586 dc->dc_toplevel = toplevel;
587 dc->dc_iosigs = sp;
588 dc->dc_ninlets = ninlets;
589 dc->dc_noutlets = noutlets;
590 dc->dc_parentcontext = ugen_currentcontext;
591 ugen_currentcontext = dc;
592 return (dc);
593}
594
595 /* first the canvas calls this to create all the boxes... */
596void ugen_add(t_dspcontext *dc, t_object *obj)
597{
598 t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
599 int i;
600 t_sigoutlet *uout;
601 t_siginlet *uin;
602
603 x->u_next = dc->dc_ugenlist;
604 dc->dc_ugenlist = x;
605 x->u_obj = obj;
606 x->u_nin = obj_nsiginlets(obj);
607 x->u_in = getbytes(x->u_nin * sizeof (*x->u_in));
608 for (uin = x->u_in, i = x->u_nin; i--; uin++)
609 uin->i_nconnect = 0;
610 x->u_nout = obj_nsigoutlets(obj);
611 x->u_out = getbytes(x->u_nout * sizeof (*x->u_out));
612 for (uout = x->u_out, i = x->u_nout; i--; uout++)
613 uout->o_connections = 0, uout->o_nconnect = 0;
614}
615
616 /* and then this to make all the connections. */
617void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
618 int inno)
619{
620 t_ugenbox *u1, *u2;
621 t_sigoutlet *uout;
622 t_siginlet *uin;
623 t_sigoutconnect *oc;
624 int sigoutno = obj_sigoutletindex(x1, outno);
625 int siginno = obj_siginletindex(x2, inno);
626 if (ugen_loud)
627 post("%s -> %s: %d->%d",
628 class_getname(x1->ob_pd),
629 class_getname(x2->ob_pd), outno, inno);
630 for (u1 = dc->dc_ugenlist; u1 && u1->u_obj != x1; u1 = u1->u_next);
631 for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next);
632 if (!u1 || !u2 || siginno < 0)
633 {
634 pd_error(u1->u_obj,
635 "signal outlet connect to nonsignal inlet (ignored)");
636 return;
637 }
638 if (sigoutno < 0 || sigoutno >= u1->u_nout || siginno >= u2->u_nin)
639 {
640 bug("ugen_connect %s %s %d %d (%d %d)",
641 class_getname(x1->ob_pd),
642 class_getname(x2->ob_pd), sigoutno, siginno, u1->u_nout,
643 u2->u_nin);
644 }
645 uout = u1->u_out + sigoutno;
646 uin = u2->u_in + siginno;
647
648 /* add a new connection to the outlet's list */
649 oc = (t_sigoutconnect *)getbytes(sizeof *oc);
650 oc->oc_next = uout->o_connections;
651 uout->o_connections = oc;
652 oc->oc_who = u2;
653 oc->oc_inno = siginno;
654 /* update inlet and outlet counts */
655 uout->o_nconnect++;
656 uin->i_nconnect++;
657}
658
659 /* get the index of a ugenbox or -1 if it's not on the list */
660static int ugen_index(t_dspcontext *dc, t_ugenbox *x)
661{
662 int ret;
663 t_ugenbox *u;
664 for (u = dc->dc_ugenlist, ret = 0; u; u = u->u_next, ret++)
665 if (u == x) return (ret);
666 return (-1);
667}
668
669 /* put a ugenbox on the chain, recursively putting any others on that
670 this one might uncover. */
671static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
672{
673 t_sigoutlet *uout;
674 t_siginlet *uin;
675 t_sigoutconnect *oc, *oc2;
676 t_class *class = pd_class(&u->u_obj->ob_pd);
677 int i, n;
678 /* suppress creating new signals for the outputs of signal
679 inlets and subpatchs; except in the case we're an inlet and "blocking"
680 is set. We don't yet know if a subcanvas will be "blocking" so there
681 we delay new signal creation, which will be handled by calling
682 signal_setborrowed in the ugen_done_graph routine below. */
683 int nonewsigs = (class == canvas_class ||
684 (class == vinlet_class) && !(dc->dc_reblock));
685 /* when we encounter a subcanvas or a signal outlet, suppress freeing
686 the input signals as they may be "borrowed" for the super or sub
687 patch; same exception as above, but also if we're "switched" we
688 have to do a copy rather than a borrow. */
689 int nofreesigs = (class == canvas_class ||
690 (class == voutlet_class) && !(dc->dc_reblock || dc->dc_switched));
691 t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
692 t_ugenbox *u2;
693
694 if (ugen_loud) post("doit %s %d %d", class_getname(class), nofreesigs,
695 nonewsigs);
696 for (i = 0, uin = u->u_in; i < u->u_nin; i++, uin++)
697 {
698 if (!uin->i_nconnect)
699 {
700 t_sample *scalar;
701 s3 = signal_new(dc->dc_vecsize, dc->dc_srate);
702 /* post("%s: unconnected signal inlet set to zero",
703 class_getname(u->u_obj->ob_pd)); */
704 if (scalar = obj_findsignalscalar(u->u_obj, i))
705 dsp_add_scalarcopy(scalar, s3->s_vec, s3->s_n);
706 else
707 dsp_add_zero(s3->s_vec, s3->s_n);
708 uin->i_signal = s3;
709 s3->s_refcount = 1;
710 }
711 }
712 insig = (t_signal **)getbytes((u->u_nin + u->u_nout) * sizeof(t_signal *));
713 outsig = insig + u->u_nin;
714 for (sig = insig, uin = u->u_in, i = u->u_nin; i--; sig++, uin++)
715 {
716 int newrefcount;
717 *sig = uin->i_signal;
718 newrefcount = --(*sig)->s_refcount;
719 /* if the reference count went to zero, we free the signal now,
720 unless it's a subcanvas or outlet; these might keep the
721 signal around to send to objects connected to them. In this
722 case we increment the reference count; the corresponding decrement
723 is in sig_makereusable(). */
724 if (nofreesigs)
725 (*sig)->s_refcount++;
726 else if (!newrefcount)
727 signal_makereusable(*sig);
728 }
729 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
730 {
731 /* similarly, for outlets of subcanvases we delay creating
732 them; instead we create "borrowed" ones so that the refcount
733 is known. The subcanvas replaces the fake signal with one showing
734 where the output data actually is, to avoid having to copy it.
735 For any other object, we just allocate a new output vector;
736 since we've already freed the inputs the objects might get called
737 "in place." */
738 if (nonewsigs)
739 {
740 *sig = uout->o_signal =
741 signal_new(0, dc->dc_srate);
742 }
743 else
744 *sig = uout->o_signal = signal_new(dc->dc_vecsize, dc->dc_srate);
745 (*sig)->s_refcount = uout->o_nconnect;
746 }
747 /* now call the DSP scheduling routine for the ugen. This
748 routine must fill in "borrowed" signal outputs in case it's either
749 a subcanvas or a signal inlet. */
750 mess1(&u->u_obj->ob_pd, gensym("dsp"), insig);
751
752 /* if any output signals aren't connected to anyone, free them
753 now; otherwise they'll either get freed when the reference count
754 goes back to zero, or even later as explained above. */
755
756 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
757 {
758 if (!(*sig)->s_refcount)
759 signal_makereusable(*sig);
760 }
761 if (ugen_loud)
762 {
763 if (u->u_nin + u->u_nout == 0) post("put %s %d",
764 class_getname(u->u_obj->ob_pd), ugen_index(dc, u));
765 else if (u->u_nin + u->u_nout == 1) post("put %s %d (%x)",
766 class_getname(u->u_obj->ob_pd), ugen_index(dc, u), sig[0]);
767 else if (u->u_nin + u->u_nout == 2) post("put %s %d (%x %x)",
768 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
769 sig[0], sig[1]);
770 else post("put %s %d (%x %x %x ...)",
771 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
772 sig[0], sig[1], sig[2]);
773 }
774
775 /* pass it on and trip anyone whose last inlet was filled */
776 for (uout = u->u_out, i = u->u_nout; i--; uout++)
777 {
778 s1 = uout->o_signal;
779 for (oc = uout->o_connections; oc; oc = oc->oc_next)
780 {
781 u2 = oc->oc_who;
782 uin = &u2->u_in[oc->oc_inno];
783 /* if there's already someone here, sum the two */
784 if (s2 = uin->i_signal)
785 {
786 s1->s_refcount--;
787 s2->s_refcount--;
788 if (!signal_compatible(s1, s2))
789 {
790 pd_error(u->u_obj, "%s: incompatible signal inputs",
791 class_getname(u->u_obj->ob_pd));
792 return;
793 }
794 s3 = signal_newlike(s1);
795 dsp_add_plus(s1->s_vec, s2->s_vec, s3->s_vec, s1->s_n);
796 uin->i_signal = s3;
797 s3->s_refcount = 1;
798 if (!s1->s_refcount) signal_makereusable(s1);
799 if (!s2->s_refcount) signal_makereusable(s2);
800 }
801 else uin->i_signal = s1;
802 uin->i_ngot++;
803 /* if we didn't fill this inlet don't bother yet */
804 if (uin->i_ngot < uin->i_nconnect)
805 goto notyet;
806 /* if there's more than one, check them all */
807 if (u2->u_nin > 1)
808 {
809 for (uin = u2->u_in, n = u2->u_nin; n--; uin++)
810 if (uin->i_ngot < uin->i_nconnect) goto notyet;
811 }
812 /* so now we can schedule the ugen. */
813 ugen_doit(dc, u2);
814 notyet: ;
815 }
816 }
817 t_freebytes(insig,(u->u_nin + u->u_nout) * sizeof(t_signal *));
818 u->u_done = 1;
819}
820
821 /* once the DSP graph is built, we call this routine to sort it.
822 This routine also deletes the graph; later we might want to leave the
823 graph around, in case the user is editing the DSP network, to save having
824 to recreate it all the time. But not today. */
825
826void ugen_done_graph(t_dspcontext *dc)
827{
828 t_ugenbox *u, *u2;
829 t_sigoutlet *uout;
830 t_siginlet *uin;
831 t_sigoutconnect *oc, *oc2;
832 int i, n;
833 t_block *blk;
834 t_dspcontext *parent_context = dc->dc_parentcontext;
835 float parent_srate;
836 int parent_vecsize;
837 int period, frequency, phase, vecsize;
838 float srate;
839 int chainblockbegin; /* DSP chain onset before block prolog code */
840 int chainblockend; /* and after block epilog code */
841 int chainafterall; /* and after signal outlet epilog */
842 int reblock = 0, switched;
843 int downsample = 1, upsample = 1; /* IOhannes */
844 /* debugging printout */
845
846 if (ugen_loud)
847 {
848 post("ugen_done_graph...");
849 for (u = dc->dc_ugenlist; u; u = u->u_next)
850 {
851 post("ugen: %s", class_getname(u->u_obj->ob_pd));
852 for (uout = u->u_out, i = 0; i < u->u_nout; uout++, i++)
853 for (oc = uout->o_connections; oc; oc = oc->oc_next)
854 {
855 post("... out %d to %s, index %d, inlet %d", i,
856 class_getname(oc->oc_who->u_obj->ob_pd),
857 ugen_index(dc, oc->oc_who), oc->oc_inno);
858 }
859 }
860 }
861
862 /* search for an object of class "block~" */
863 for (u = dc->dc_ugenlist, blk = 0; u; u = u->u_next)
864 {
865 t_pd *zz = &u->u_obj->ob_pd;
866 if (pd_class(zz) == block_class)
867 {
868 if (blk)
869 pd_error(blk, "conflicting block~ objects in same page");
870 else blk = (t_block *)zz;
871 }
872 }
873
874 /* figure out block size, calling frequency, sample rate */
875 if (parent_context)
876 {
877 parent_srate = parent_context->dc_srate;
878 parent_vecsize = parent_context->dc_vecsize;
879 }
880 else
881 {
882 parent_srate = sys_getsr();
883 parent_vecsize = sys_getblksize();
884 }
885 if (blk)
886 {
887 int realoverlap;
888 vecsize = blk->x_vecsize;
889 if (vecsize == 0)
890 vecsize = parent_vecsize;
891 realoverlap = blk->x_overlap;
892 if (realoverlap > vecsize) realoverlap = vecsize;
893 /* IOhannes { */
894 downsample = blk->x_downsample;
895 upsample = blk->x_upsample;
896 if (downsample > parent_vecsize) downsample=parent_vecsize;
897 period = (vecsize * downsample)/
898 (parent_vecsize * realoverlap * upsample);
899 frequency = (parent_vecsize * realoverlap * upsample)/
900 (vecsize * downsample);
901 /* } IOhannes*/
902 phase = blk->x_phase;
903 srate = parent_srate * realoverlap * upsample / downsample;
904 /* IOhannes */
905 if (period < 1) period = 1;
906 if (frequency < 1) frequency = 1;
907 blk->x_frequency = frequency;
908 blk->x_period = period;
909 blk->x_phase = dsp_phase & (period - 1);
910 if (! parent_context || (realoverlap != 1) ||
911 (vecsize != parent_vecsize) ||
912 (downsample != 1) || (upsample != 1)) /* IOhannes */
913 reblock = 1;
914 switched = blk->x_switched;
915 }
916 else
917 {
918 srate = parent_srate;
919 vecsize = parent_vecsize;
920 downsample = upsample = 1;/* IOhannes */
921 period = frequency = 1;
922 phase = 0;
923 if (!parent_context) reblock = 1;
924 switched = 0;
925 }
926 dc->dc_reblock = reblock;
927 dc->dc_switched = switched;
928 dc->dc_srate = srate;
929 dc->dc_vecsize = vecsize;
930
931 /* if we're reblocking or switched, we now have to create output
932 signals to fill in for the "borrowed" ones we have now. This
933 is also possibly true even if we're not blocked/switched, in
934 the case that there was a signal loop. But we don't know this
935 yet. */
936
937 if (dc->dc_iosigs && (switched || reblock))
938 {
939 t_signal **sigp;
940 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
941 i++, sigp++)
942 {
943 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
944 {
945 signal_setborrowed(*sigp,
946 signal_new(parent_vecsize, parent_srate));
947 (*sigp)->s_refcount++;
948
949 if (ugen_loud) post("set %x->%x", *sigp,
950 (*sigp)->s_borrowedfrom);
951 }
952 }
953 }
954
955 if (ugen_loud)
956 post("reblock %d, switched %d", reblock, switched);
957
958 /* schedule prologs for inlets and outlets. If the "reblock" flag
959 is set, an inlet will put code on the DSP chain to copy its input
960 into an internal buffer here, before any unit generators' DSP code
961 gets scheduled. If we don't "reblock", inlets will need to get
962 pointers to their corresponding inlets/outlets on the box we're inside,
963 if any. Outlets will also need pointers, unless we're switched, in
964 which case outlet epilog code will kick in. */
965
966 for (u = dc->dc_ugenlist; u; u = u->u_next)
967 {
968 t_pd *zz = &u->u_obj->ob_pd;
969 t_signal **insigs = dc->dc_iosigs, **outsigs = dc->dc_iosigs;
970 if (outsigs) outsigs += dc->dc_ninlets;
971
972 if (pd_class(zz) == vinlet_class)
973 vinlet_dspprolog((struct _vinlet *)zz,
974 dc->dc_iosigs, vecsize, dsp_phase, period, frequency,
975 downsample, upsample, /* IOhannes */
976 reblock, switched);
977 else if (pd_class(zz) == voutlet_class)
978 voutlet_dspprolog((struct _voutlet *)zz,
979 outsigs, vecsize, dsp_phase, period, frequency,
980 downsample, upsample, /* IOhannes */
981 reblock, switched);
982 }
983 chainblockbegin = dsp_chainsize;
984
985 if (blk && (reblock || switched)) /* add the block DSP prolog */
986 dsp_add(block_prolog, 1, blk);
987
988 /* Initialize for sorting */
989 for (u = dc->dc_ugenlist; u; u = u->u_next)
990 {
991 u->u_done = 0;
992 for (uout = u->u_out, i = u->u_nout; i--; uout++)
993 uout->o_nsent = 0;
994 for (uin = u->u_in, i = u->u_nin; i--; uin++)
995 uin->i_ngot = 0, uin->i_signal = 0;
996 }
997
998 /* Do the sort */
999
1000 for (u = dc->dc_ugenlist; u; u = u->u_next)
1001 {
1002 /* check that we have no connected signal inlets */
1003 if (u->u_done) continue;
1004 for (uin = u->u_in, i = u->u_nin; i--; uin++)
1005 if (uin->i_nconnect) goto next;
1006
1007 ugen_doit(dc, u);
1008 next: ;
1009 }
1010
1011 /* check for a DSP loop, which is evidenced here by the presence
1012 of ugens not yet scheduled. */
1013
1014 for (u = dc->dc_ugenlist; u; u = u->u_next)
1015 if (!u->u_done)
1016 {
1017 t_signal **sigp;
1018 pd_error(u->u_obj,
1019 "DSP loop detected (some tilde objects not scheduled)");
1020 /* this might imply that we have unfilled "borrowed" outputs
1021 which we'd better fill in now. */
1022 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
1023 i++, sigp++)
1024 {
1025 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
1026 {
1027 t_signal *s3 = signal_new(parent_vecsize, parent_srate);
1028 signal_setborrowed(*sigp, s3);
1029 (*sigp)->s_refcount++;
1030 dsp_add_zero(s3->s_vec, s3->s_n);
1031 if (ugen_loud)
1032 post("oops, belatedly set %x->%x", *sigp,
1033 (*sigp)->s_borrowedfrom);
1034 }
1035 }
1036 break; /* don't need to keep looking. */
1037 }
1038
1039 if (blk && (reblock || switched)) /* add block DSP epilog */
1040 dsp_add(block_epilog, 1, blk);
1041 chainblockend = dsp_chainsize;
1042
1043 /* add epilogs for outlets. */
1044
1045 for (u = dc->dc_ugenlist; u; u = u->u_next)
1046 {
1047 t_pd *zz = &u->u_obj->ob_pd;
1048 if (pd_class(zz) == voutlet_class)
1049 {
1050 t_signal **iosigs = dc->dc_iosigs;
1051 if (iosigs) iosigs += dc->dc_ninlets;
1052 voutlet_dspepilog((struct _voutlet *)zz,
1053 iosigs, vecsize, dsp_phase, period, frequency,
1054 downsample, upsample, /* IOhannes */
1055 reblock, switched);
1056 }
1057 }
1058
1059 chainafterall = dsp_chainsize;
1060 if (blk)
1061 {
1062 blk->x_blocklength = chainblockend - chainblockbegin;
1063 blk->x_epiloglength = chainafterall - chainblockend;
1064 blk->x_reblock = reblock;
1065 }
1066
1067 if (ugen_loud)
1068 {
1069 t_int *ip;
1070 if (!dc->dc_parentcontext)
1071 for (i = dsp_chainsize, ip = dsp_chain; i--; ip++)
1072 post("chain %x", *ip);
1073 post("... ugen_done_graph done.");
1074 }
1075 /* now delete everything. */
1076 while (dc->dc_ugenlist)
1077 {
1078 for (uout = dc->dc_ugenlist->u_out, n = dc->dc_ugenlist->u_nout;
1079 n--; uout++)
1080 {
1081 oc = uout->o_connections;
1082 while (oc)
1083 {
1084 oc2 = oc->oc_next;
1085 freebytes(oc, sizeof *oc);
1086 oc = oc2;
1087 }
1088 }
1089 freebytes(dc->dc_ugenlist->u_out, dc->dc_ugenlist->u_nout *
1090 sizeof (*dc->dc_ugenlist->u_out));
1091 freebytes(dc->dc_ugenlist->u_in, dc->dc_ugenlist->u_nin *
1092 sizeof(*dc->dc_ugenlist->u_in));
1093 u = dc->dc_ugenlist;
1094 dc->dc_ugenlist = u->u_next;
1095 freebytes(u, sizeof *u);
1096 }
1097 if (ugen_currentcontext == dc)
1098 ugen_currentcontext = dc->dc_parentcontext;
1099 else bug("ugen_currentcontext");
1100 freebytes(dc, sizeof(*dc));
1101
1102}
1103
1104t_signal *ugen_getiosig(int index, int inout)
1105{
1106 if (!ugen_currentcontext) bug("ugen_getiosig");
1107 if (ugen_currentcontext->dc_toplevel) return (0);
1108 if (inout) index += ugen_currentcontext->dc_ninlets;
1109 return (ugen_currentcontext->dc_iosigs[index]);
1110}
1111
1112
1113/* -------------------- setup routine -------------------------- */
1114
1115void d_ugen_setup(void) /* really just block_setup */
1116{
1117 block_class = class_new(gensym("block~"), (t_newmethod)block_new, 0,
1118 sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
1119 class_addcreator((t_newmethod)switch_new, gensym("switch~"),
1120 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
1121 class_addmethod(block_class, (t_method)block_set, gensym("set"),
1122 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
1123 class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), 0);
1124 class_addfloat(block_class, block_float);
1125}
1126
1127/* Copyright (c) 1997-1999 Miller Puckette.
1128* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1129* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1130
1131/* These routines build a copy of the DSP portion of a graph, which is
1132 then sorted into a linear list of DSP operations which are added to
1133 the DSP duty cycle called by the scheduler. Once that's been done,
1134 we delete the copy. The DSP objects are represented by "ugenbox"
1135 structures which are parallel to the DSP objects in the graph and
1136 have vectors of siginlets and sigoutlets which record their
1137 interconnections.
1138*/
1139
1140/* hacked to run subpatches with different samplerates
1141 * only samplerates that are a power_of_2-multiple of the
1142 *
1143 * mfg.gfd.uil
1144 * IOhannes
1145 *
1146 * edited lines are marked with "IOhannes"
1147 *
1148 */
1149
1150
1151#include "m_pd.h"
1152#include "m_imp.h"
1153#include <stdlib.h>
1154#include <stdarg.h>
1155
1156extern t_class *vinlet_class, *voutlet_class, *canvas_class;
1157t_sample *obj_findsignalscalar(t_object *x, int m);
1158static int ugen_loud;
1159EXTERN_STRUCT _vinlet;
1160EXTERN_STRUCT _voutlet;
1161
1162void vinlet_dspprolog(struct _vinlet *x, t_signal **parentsigs,
1163 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1164 int switched);
1165void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs,
1166 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1167 int switched);
1168void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs,
1169 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1170 int switched);
1171
1172t_int *zero_perform(t_int *w) /* zero out a vector */
1173{
1174 t_float *out = (t_float *)(w[1]);
1175 int n = (int)(w[2]);
1176 while (n--) *out++ = 0;
1177 return (w+3);
1178}
1179
1180t_int *zero_perf8(t_int *w)
1181{
1182 t_float *out = (t_float *)(w[1]);
1183 int n = (int)(w[2]);
1184
1185 for (; n; n -= 8, out += 8)
1186 {
1187 out[0] = 0;
1188 out[1] = 0;
1189 out[2] = 0;
1190 out[3] = 0;
1191 out[4] = 0;
1192 out[5] = 0;
1193 out[6] = 0;
1194 out[7] = 0;
1195 }
1196 return (w+3);
1197}
1198
1199void dsp_add_zero(t_sample *out, int n)
1200{
1201 if (n&7)
1202 dsp_add(zero_perform, 2, out, n);
1203 else
1204 dsp_add(zero_perf8, 2, out, n);
1205}
1206
1207/* ---------------------------- block~ ----------------------------- */
1208
1209/* The "block~ object maintains the containing canvas's DSP computation,
1210calling it at a super- or sub-multiple of the containing canvas's
1211calling frequency. The block~'s creation arguments specify block size
1212and overlap. Block~ does no "dsp" computation in its own right, but it
1213adds prolog and epilog code before and after the canvas's unit generators.
1214
1215A subcanvas need not have a block~ at all; if there's none, its
1216ugens are simply put on the list without any prolog or epilog code.
1217
1218Block~ may be invoked as switch~, in which case it also acts to switch the
1219subcanvas on and off. The overall order of scheduling for a subcanvas
1220is thus,
1221
1222 inlet and outlet prologue code (1)
1223 block prologue (2)
1224 the objects in the subcanvas, including inlets and outlets
1225 block epilogue (2)
1226 outlet epilogue code (2)
1227
1228where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
1229
1230If we're reblocked, the inlet prolog and outlet epilog code takes care of
1231overlapping and buffering to deal with vector size changes. If we're switched
1232but not reblocked, the inlet prolog is not needed, and the output epilog is
1233ONLY run when the block is switched off; in this case the epilog code simply
1234copies zeros to all signal outlets.
1235*/
1236
1237static int dsp_phase;
1238static t_class *block_class;
1239
1240typedef struct _block
1241{
1242 t_object x_obj;
1243 int x_vecsize;
1244 int x_overlap;
1245 int x_phase; /* from 0 to period-1; when zero we run the block */
1246 int x_period; /* submultiple of containing canvas */
1247 int x_frequency; /* supermultiple of comtaining canvas */
1248 int x_count;
1249 int x_blocklength; /* length of dspchain for this block */
1250 int x_epiloglength; /* length of epilog */
1251 char x_switched; /* true if we're acting as a a switch */
1252 char x_switchon; /* true if we're switched on */
1253 char x_reblock; /* true if inlets and outlets are reblocking */
1254 int x_upsample; /* IOhannes: upsampling-factor */
1255 int x_downsample; /* IOhannes: downsampling-factor */
1256
1257} t_block;
1258
1259static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
1260 t_floatarg fupsample);
1261
1262static void *block_new(t_floatarg fvecsize, t_floatarg foverlap,
1263 t_floatarg fupsample) /* IOhannes */
1264{
1265 t_block *x = (t_block *)pd_new(block_class);
1266 x->x_phase = 0;
1267 x->x_period = 1;
1268 x->x_frequency = 1;
1269 x->x_switched = 0;
1270 x->x_switchon = 1;
1271 block_set(x, fvecsize, foverlap, fupsample);
1272 return (x);
1273}
1274
1275static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
1276 t_floatarg fupsample)
1277{
1278 int upsample, downsample; /* IOhannes */
1279 int vecsize = fvecsize;
1280 int overlap = foverlap;
1281 int dspstate = canvas_suspend_dsp();
1282 if (overlap < 1)
1283 overlap = 1;
1284 if (vecsize < 0)
1285 vecsize = 0; /* this means we'll get it from parent later. */
1286
1287 /* IOhannes { */
1288 if (fupsample <= 0) upsample = downsample = 1;
1289 else if (fupsample >= 1) {
1290 upsample = fupsample;
1291 downsample = 1;
1292 } else {
1293 downsample = 1.0 / fupsample;
1294 upsample = 1;
1295 }
1296 /* } IOhannes */
1297
1298 if (vecsize && (vecsize != (1 << ilog2(vecsize))))
1299 {
1300 pd_error(x, "block~: vector size not a power of 2");
1301 vecsize = 64;
1302 }
1303 if (overlap != (1 << ilog2(overlap)))
1304 {
1305 pd_error(x, "block~: overlap not a power of 2");
1306 overlap = 1;
1307 }
1308 /* IOhannes { */
1309 if (downsample != (1 << ilog2(downsample)))
1310 {
1311 pd_error(x, "block~: downsampling not a power of 2");
1312 downsample = 1;
1313 }
1314 if (upsample != (1 << ilog2(upsample)))
1315 {
1316 pd_error(x, "block~: upsampling not a power of 2");
1317 upsample = 1;
1318 }
1319 /* } IOhannes */
1320
1321
1322 x->x_vecsize = vecsize;
1323 x->x_overlap = overlap;
1324 /* IOhannes { */
1325 x->x_upsample = upsample;
1326 x->x_downsample = downsample;
1327 /* } IOhannes */
1328 canvas_resume_dsp(dspstate);
1329}
1330
1331static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap,
1332 t_floatarg fupsample) /* IOhannes */
1333{
1334 t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
1335 x->x_switched = 1;
1336 x->x_switchon = 0;
1337 return (x);
1338}
1339
1340static void block_float(t_block *x, t_floatarg f)
1341{
1342 if (x->x_switched)
1343 x->x_switchon = (f != 0);
1344}
1345#define PROLOGCALL 2
1346#define EPILOGCALL 2
1347
1348static t_int *block_prolog(t_int *w)
1349{
1350 t_block *x = (t_block *)w[1];
1351 int phase = x->x_phase;
1352 /* if we're switched off, jump past the epilog code */
1353 if (!x->x_switchon)
1354 return (w + x->x_blocklength);
1355 if (phase)
1356 {
1357 phase++;
1358 if (phase == x->x_period) phase = 0;
1359 x->x_phase = phase;
1360 return (w + x->x_blocklength); /* skip block; jump past epilog */
1361 }
1362 else
1363 {
1364 x->x_count = x->x_frequency;
1365 x->x_phase = (x->x_period > 1 ? 1 : 0);
1366 return (w + PROLOGCALL); /* beginning of block is next ugen */
1367 }
1368}
1369
1370static t_int *block_epilog(t_int *w)
1371{
1372 t_block *x = (t_block *)w[1];
1373 int count = x->x_count - 1;
1374 if (!x->x_reblock)
1375 return (w + x->x_epiloglength + EPILOGCALL);
1376 if (count)
1377 {
1378 x->x_count = count;
1379 return (w - (x->x_blocklength -
1380 (PROLOGCALL + EPILOGCALL))); /* go to ugen after prolog */
1381 }
1382 else return (w + EPILOGCALL);
1383}
1384
1385static void block_dsp(t_block *x, t_signal **sp)
1386{
1387 /* do nothing here */
1388}
1389
1390/* ------------------ DSP call list ----------------------- */
1391
1392static t_int *dsp_chain;
1393static int dsp_chainsize;
1394
1395void dsp_add(t_perfroutine f, int n, ...)
1396{
1397 int newsize = dsp_chainsize + n+1, i;
1398 va_list ap;
1399
1400 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
1401 newsize * sizeof (t_int));
1402 dsp_chain[dsp_chainsize-1] = (t_int)f;
1403 va_start(ap, n);
1404 for (i = 0; i < n; i++)
1405 dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
1406 va_end(ap);
1407 dsp_chain[newsize-1] = 0;
1408 dsp_chainsize = newsize;
1409}
1410
1411 /* at Guenter's suggestion, here's a vectorized version */
1412void dsp_addv(t_perfroutine f, int n, t_int *vec)
1413{
1414 int newsize = dsp_chainsize + n+1, i;
1415
1416 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
1417 newsize * sizeof (t_int));
1418 dsp_chain[dsp_chainsize-1] = (t_int)f;
1419 for (i = 0; i < n; i++)
1420 dsp_chain[dsp_chainsize + i] = vec[i];
1421 dsp_chain[newsize-1] = 0;
1422 dsp_chainsize = newsize;
1423}
1424
1425void dsp_tick(void)
1426{
1427 if (dsp_chain)
1428 {
1429 t_int *ip;
1430 for (ip = dsp_chain; *ip; ) ip = (*(t_perfroutine)(*ip))(ip);
1431 dsp_phase++;
1432 }
1433}
1434
1435/* ---------------- signals ---------------------------- */
1436
1437int ilog2(int n)
1438{
1439 int r = -1;
1440 if (n <= 0) return(0);
1441 while (n)
1442 {
1443 r++;
1444 n >>= 1;
1445 }
1446 return (r);
1447}
1448
1449 /* list of signals which can be reused, sorted by buffer size */
1450static t_signal *signal_freelist[MAXLOGSIG+1];
1451 /* list of reusable "borrowed" signals (which don't own sample buffers) */
1452static t_signal *signal_freeborrowed;
1453 /* list of all signals allocated (not including "borrowed" ones) */
1454static t_signal *signal_usedlist;
1455
1456 /* call this when DSP is stopped to free all the signals */
1457void signal_cleanup(void)
1458{
1459 t_signal **svec, *sig, *sig2;
1460 int i;
1461 while (sig = signal_usedlist)
1462 {
1463 signal_usedlist = sig->s_nextused;
1464 if (!sig->s_isborrowed)
1465 t_freebytes(sig->s_vec, sig->s_n * sizeof (*sig->s_vec));
1466 t_freebytes(sig, sizeof *sig);
1467 }
1468 for (i = 0; i <= MAXLOGSIG; i++)
1469 signal_freelist[i] = 0;
1470 signal_freeborrowed = 0;
1471}
1472
1473 /* mark the signal "reusable." */
1474void signal_makereusable(t_signal *sig)
1475{
1476 int logn = ilog2(sig->s_n);
1477#if 1
1478 t_signal *s5;
1479 for (s5 = signal_freeborrowed; s5; s5 = s5->s_nextfree)
1480 {
1481 if (s5 == sig)
1482 {
1483 bug("signal_free 3");
1484 return;
1485 }
1486 }
1487 for (s5 = signal_freelist[logn]; s5; s5 = s5->s_nextfree)
1488 {
1489 if (s5 == sig)
1490 {
1491 bug("signal_free 4");
1492 return;
1493 }
1494 }
1495#endif
1496 if (ugen_loud) post("free %x: %d", sig, sig->s_isborrowed);
1497 if (sig->s_isborrowed)
1498 {
1499 /* if the signal is borrowed, decrement the borrowed-from signal's
1500 reference count, possibly marking it reusable too */
1501 t_signal *s2 = sig->s_borrowedfrom;
1502 if ((s2 == sig) || !s2)
1503 bug("signal_free");
1504 s2->s_refcount--;
1505 if (!s2->s_refcount)
1506 signal_makereusable(s2);
1507 sig->s_nextfree = signal_freeborrowed;
1508 signal_freeborrowed = sig;
1509 }
1510 else
1511 {
1512 /* if it's a real signal (not borrowed), put it on the free list
1513 so we can reuse it. */
1514 if (signal_freelist[logn] == sig) bug("signal_free 2");
1515 sig->s_nextfree = signal_freelist[logn];
1516 signal_freelist[logn] = sig;
1517 }
1518}
1519
1520 /* reclaim or make an audio signal. If n is zero, return a "borrowed"
1521 signal whose buffer and size will be obtained later via
1522 signal_setborrowed(). */
1523
1524t_signal *signal_new(int n, float sr)
1525{
1526 int logn, n2;
1527 t_signal *ret, **whichlist;
1528 t_sample *fp;
1529 logn = ilog2(n);
1530 if (n)
1531 {
1532 if (n != (1 << logn))
1533 bug("signal buffer not a power of 2");
1534 if (logn > MAXLOGSIG)
1535 bug("signal buffer too large");
1536 whichlist = signal_freelist + logn;
1537 }
1538 else
1539 whichlist = &signal_freeborrowed;
1540
1541 /* first try to reclaim one from the free list */
1542 if (ret = *whichlist)
1543 *whichlist = ret->s_nextfree;
1544 else
1545 {
1546 /* LATER figure out what to do for out-of-space here! */
1547 ret = (t_signal *)t_getbytes(sizeof *ret);
1548 if (n)
1549 {
1550 ret->s_vec = (t_sample *)getbytes(n * sizeof (*ret->s_vec));
1551 ret->s_isborrowed = 0;
1552 }
1553 else
1554 {
1555 ret->s_vec = 0;
1556 ret->s_isborrowed = 1;
1557 }
1558 ret->s_nextused = signal_usedlist;
1559 signal_usedlist = ret;
1560 }
1561 ret->s_n = n;
1562 ret->s_sr = sr;
1563 ret->s_refcount = 0;
1564 ret->s_borrowedfrom = 0;
1565 if (ugen_loud) post("new %x: %d", ret, ret->s_isborrowed);
1566 return (ret);
1567}
1568
1569static t_signal *signal_newlike(const t_signal *sig)
1570{
1571 return (signal_new(sig->s_n, sig->s_sr));
1572}
1573
1574void signal_setborrowed(t_signal *sig, t_signal *sig2)
1575{
1576 if (!sig->s_isborrowed || sig->s_borrowedfrom)
1577 bug("signal_setborrowed");
1578 if (sig == sig2)
1579 bug("signal_setborrowed 2");
1580 sig->s_borrowedfrom = sig2;
1581 sig->s_vec = sig2->s_vec;
1582 sig->s_n = sig2->s_n;
1583}
1584
1585int signal_compatible(t_signal *s1, t_signal *s2)
1586{
1587 return (s1->s_n == s2->s_n && s1->s_sr == s2->s_sr);
1588}
1589
1590/* ------------------ ugen ("unit generator") sorting ----------------- */
1591
1592typedef struct _ugenbox
1593{
1594 struct _siginlet *u_in;
1595 int u_nin;
1596 struct _sigoutlet *u_out;
1597 int u_nout;
1598 int u_phase;
1599 struct _ugenbox *u_next;
1600 t_object *u_obj;
1601 int u_done;
1602} t_ugenbox;
1603
1604typedef struct _siginlet
1605{
1606 int i_nconnect;
1607 int i_ngot;
1608 t_signal *i_signal;
1609} t_siginlet;
1610
1611typedef struct _sigoutconnect
1612{
1613 t_ugenbox *oc_who;
1614 int oc_inno;
1615 struct _sigoutconnect *oc_next;
1616} t_sigoutconnect;
1617
1618typedef struct _sigoutlet
1619{
1620 int o_nconnect;
1621 int o_nsent;
1622 t_signal *o_signal;
1623 t_sigoutconnect *o_connections;
1624} t_sigoutlet;
1625
1626
1627struct _dspcontext
1628{
1629 struct _ugenbox *dc_ugenlist;
1630 struct _dspcontext *dc_parentcontext;
1631 int dc_ninlets;
1632 int dc_noutlets;
1633 t_signal **dc_iosigs;
1634 float dc_srate;
1635 int dc_vecsize;
1636 char dc_toplevel; /* true if "iosigs" is invalid. */
1637 char dc_reblock; /* true if we have to reblock inlets/outlets */
1638 char dc_switched; /* true if we're switched */
1639
1640};
1641
1642#define t_dspcontext struct _dspcontext
1643
1644static int ugen_sortno = 0;
1645static t_dspcontext *ugen_currentcontext;
1646
1647void ugen_stop(void)
1648{
1649 t_signal *s;
1650 int i;
1651 if (dsp_chain)
1652 {
1653 freebytes(dsp_chain, dsp_chainsize * sizeof (t_int));
1654 dsp_chain = 0;
1655 }
1656 signal_cleanup();
1657
1658}
1659
1660void ugen_start(void)
1661{
1662 ugen_stop();
1663 ugen_sortno++;
1664 dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
1665 dsp_chain[0] = 0;
1666 dsp_chainsize = 1;
1667 if (ugen_currentcontext) bug("ugen_start");
1668}
1669
1670int ugen_getsortno(void)
1671{
1672 return (ugen_sortno);
1673}
1674
1675#if 0
1676void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
1677{
1678 int i, count;
1679 t_signal *sig;
1680 for (count = 0, sig = signal_usedlist; sig;
1681 count++, sig = sig->s_nextused)
1682 ;
1683 post("used signals %d", count);
1684 for (i = 0; i < MAXLOGSIG; i++)
1685 {
1686 for (count = 0, sig = signal_freelist[i]; sig;
1687 count++, sig = sig->s_nextfree)
1688 ;
1689 if (count)
1690 post("size %d: free %d", (1 << i), count);
1691 }
1692 for (count = 0, sig = signal_freeborrowed; sig;
1693 count++, sig = sig->s_nextfree)
1694 ;
1695 post("free borrowed %d", count);
1696
1697 ugen_loud = argc;
1698}
1699#endif
1700
1701 /* start building the graph for a canvas */
1702t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
1703 int ninlets, int noutlets)
1704{
1705 t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
1706 float parent_srate, srate;
1707 int parent_vecsize, vecsize;
1708
1709 if (ugen_loud) post("ugen_start_graph...");
1710
1711 dc->dc_ugenlist = 0;
1712 dc->dc_toplevel = toplevel;
1713 dc->dc_iosigs = sp;
1714 dc->dc_ninlets = ninlets;
1715 dc->dc_noutlets = noutlets;
1716 dc->dc_parentcontext = ugen_currentcontext;
1717 ugen_currentcontext = dc;
1718 return (dc);
1719}
1720
1721 /* first the canvas calls this to create all the boxes... */
1722void ugen_add(t_dspcontext *dc, t_object *obj)
1723{
1724 t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
1725 int i;
1726 t_sigoutlet *uout;
1727 t_siginlet *uin;
1728
1729 x->u_next = dc->dc_ugenlist;
1730 dc->dc_ugenlist = x;
1731 x->u_obj = obj;
1732 x->u_nin = obj_nsiginlets(obj);
1733 x->u_in = getbytes(x->u_nin * sizeof (*x->u_in));
1734 for (uin = x->u_in, i = x->u_nin; i--; uin++)
1735 uin->i_nconnect = 0;
1736 x->u_nout = obj_nsigoutlets(obj);
1737 x->u_out = getbytes(x->u_nout * sizeof (*x->u_out));
1738 for (uout = x->u_out, i = x->u_nout; i--; uout++)
1739 uout->o_connections = 0, uout->o_nconnect = 0;
1740}
1741
1742 /* and then this to make all the connections. */
1743void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
1744 int inno)
1745{
1746 t_ugenbox *u1, *u2;
1747 t_sigoutlet *uout;
1748 t_siginlet *uin;
1749 t_sigoutconnect *oc;
1750 int sigoutno = obj_sigoutletindex(x1, outno);
1751 int siginno = obj_siginletindex(x2, inno);
1752 if (ugen_loud)
1753 post("%s -> %s: %d->%d",
1754 class_getname(x1->ob_pd),
1755 class_getname(x2->ob_pd), outno, inno);
1756 for (u1 = dc->dc_ugenlist; u1 && u1->u_obj != x1; u1 = u1->u_next);
1757 for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next);
1758 if (!u1 || !u2 || siginno < 0)
1759 {
1760 pd_error(u1->u_obj,
1761 "signal outlet connect to nonsignal inlet (ignored)");
1762 return;
1763 }
1764 if (sigoutno < 0 || sigoutno >= u1->u_nout || siginno >= u2->u_nin)
1765 {
1766 bug("ugen_connect %s %s %d %d (%d %d)",
1767 class_getname(x1->ob_pd),
1768 class_getname(x2->ob_pd), sigoutno, siginno, u1->u_nout,
1769 u2->u_nin);
1770 }
1771 uout = u1->u_out + sigoutno;
1772 uin = u2->u_in + siginno;
1773
1774 /* add a new connection to the outlet's list */
1775 oc = (t_sigoutconnect *)getbytes(sizeof *oc);
1776 oc->oc_next = uout->o_connections;
1777 uout->o_connections = oc;
1778 oc->oc_who = u2;
1779 oc->oc_inno = siginno;
1780 /* update inlet and outlet counts */
1781 uout->o_nconnect++;
1782 uin->i_nconnect++;
1783}
1784
1785 /* get the index of a ugenbox or -1 if it's not on the list */
1786static int ugen_index(t_dspcontext *dc, t_ugenbox *x)
1787{
1788 int ret;
1789 t_ugenbox *u;
1790 for (u = dc->dc_ugenlist, ret = 0; u; u = u->u_next, ret++)
1791 if (u == x) return (ret);
1792 return (-1);
1793}
1794
1795 /* put a ugenbox on the chain, recursively putting any others on that
1796 this one might uncover. */
1797static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
1798{
1799 t_sigoutlet *uout;
1800 t_siginlet *uin;
1801 t_sigoutconnect *oc, *oc2;
1802 t_class *class = pd_class(&u->u_obj->ob_pd);
1803 int i, n;
1804 /* suppress creating new signals for the outputs of signal
1805 inlets and subpatchs; except in the case we're an inlet and "blocking"
1806 is set. We don't yet know if a subcanvas will be "blocking" so there
1807 we delay new signal creation, which will be handled by calling
1808 signal_setborrowed in the ugen_done_graph routine below. */
1809 int nonewsigs = (class == canvas_class ||
1810 (class == vinlet_class) && !(dc->dc_reblock));
1811 /* when we encounter a subcanvas or a signal outlet, suppress freeing
1812 the input signals as they may be "borrowed" for the super or sub
1813 patch; same exception as above, but also if we're "switched" we
1814 have to do a copy rather than a borrow. */
1815 int nofreesigs = (class == canvas_class ||
1816 (class == voutlet_class) && !(dc->dc_reblock || dc->dc_switched));
1817 t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
1818 t_ugenbox *u2;
1819
1820 if (ugen_loud) post("doit %s %d %d", class_getname(class), nofreesigs,
1821 nonewsigs);
1822 for (i = 0, uin = u->u_in; i < u->u_nin; i++, uin++)
1823 {
1824 if (!uin->i_nconnect)
1825 {
1826 t_sample *scalar;
1827 s3 = signal_new(dc->dc_vecsize, dc->dc_srate);
1828 /* post("%s: unconnected signal inlet set to zero",
1829 class_getname(u->u_obj->ob_pd)); */
1830 if (scalar = obj_findsignalscalar(u->u_obj, i))
1831 dsp_add_scalarcopy(scalar, s3->s_vec, s3->s_n);
1832 else
1833 dsp_add_zero(s3->s_vec, s3->s_n);
1834 uin->i_signal = s3;
1835 s3->s_refcount = 1;
1836 }
1837 }
1838 insig = (t_signal **)getbytes((u->u_nin + u->u_nout) * sizeof(t_signal *));
1839 outsig = insig + u->u_nin;
1840 for (sig = insig, uin = u->u_in, i = u->u_nin; i--; sig++, uin++)
1841 {
1842 int newrefcount;
1843 *sig = uin->i_signal;
1844 newrefcount = --(*sig)->s_refcount;
1845 /* if the reference count went to zero, we free the signal now,
1846 unless it's a subcanvas or outlet; these might keep the
1847 signal around to send to objects connected to them. In this
1848 case we increment the reference count; the corresponding decrement
1849 is in sig_makereusable(). */
1850 if (nofreesigs)
1851 (*sig)->s_refcount++;
1852 else if (!newrefcount)
1853 signal_makereusable(*sig);
1854 }
1855 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
1856 {
1857 /* similarly, for outlets of subcanvases we delay creating
1858 them; instead we create "borrowed" ones so that the refcount
1859 is known. The subcanvas replaces the fake signal with one showing
1860 where the output data actually is, to avoid having to copy it.
1861 For any other object, we just allocate a new output vector;
1862 since we've already freed the inputs the objects might get called
1863 "in place." */
1864 if (nonewsigs)
1865 {
1866 *sig = uout->o_signal =
1867 signal_new(0, dc->dc_srate);
1868 }
1869 else
1870 *sig = uout->o_signal = signal_new(dc->dc_vecsize, dc->dc_srate);
1871 (*sig)->s_refcount = uout->o_nconnect;
1872 }
1873 /* now call the DSP scheduling routine for the ugen. This
1874 routine must fill in "borrowed" signal outputs in case it's either
1875 a subcanvas or a signal inlet. */
1876 mess1(&u->u_obj->ob_pd, gensym("dsp"), insig);
1877
1878 /* if any output signals aren't connected to anyone, free them
1879 now; otherwise they'll either get freed when the reference count
1880 goes back to zero, or even later as explained above. */
1881
1882 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
1883 {
1884 if (!(*sig)->s_refcount)
1885 signal_makereusable(*sig);
1886 }
1887 if (ugen_loud)
1888 {
1889 if (u->u_nin + u->u_nout == 0) post("put %s %d",
1890 class_getname(u->u_obj->ob_pd), ugen_index(dc, u));
1891 else if (u->u_nin + u->u_nout == 1) post("put %s %d (%x)",
1892 class_getname(u->u_obj->ob_pd), ugen_index(dc, u), sig[0]);
1893 else if (u->u_nin + u->u_nout == 2) post("put %s %d (%x %x)",
1894 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
1895 sig[0], sig[1]);
1896 else post("put %s %d (%x %x %x ...)",
1897 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
1898 sig[0], sig[1], sig[2]);
1899 }
1900
1901 /* pass it on and trip anyone whose last inlet was filled */
1902 for (uout = u->u_out, i = u->u_nout; i--; uout++)
1903 {
1904 s1 = uout->o_signal;
1905 for (oc = uout->o_connections; oc; oc = oc->oc_next)
1906 {
1907 u2 = oc->oc_who;
1908 uin = &u2->u_in[oc->oc_inno];
1909 /* if there's already someone here, sum the two */
1910 if (s2 = uin->i_signal)
1911 {
1912 s1->s_refcount--;
1913 s2->s_refcount--;
1914 if (!signal_compatible(s1, s2))
1915 {
1916 pd_error(u->u_obj, "%s: incompatible signal inputs",
1917 class_getname(u->u_obj->ob_pd));
1918 return;
1919 }
1920 s3 = signal_newlike(s1);
1921 dsp_add_plus(s1->s_vec, s2->s_vec, s3->s_vec, s1->s_n);
1922 uin->i_signal = s3;
1923 s3->s_refcount = 1;
1924 if (!s1->s_refcount) signal_makereusable(s1);
1925 if (!s2->s_refcount) signal_makereusable(s2);
1926 }
1927 else uin->i_signal = s1;
1928 uin->i_ngot++;
1929 /* if we didn't fill this inlet don't bother yet */
1930 if (uin->i_ngot < uin->i_nconnect)
1931 goto notyet;
1932 /* if there's more than one, check them all */
1933 if (u2->u_nin > 1)
1934 {
1935 for (uin = u2->u_in, n = u2->u_nin; n--; uin++)
1936 if (uin->i_ngot < uin->i_nconnect) goto notyet;
1937 }
1938 /* so now we can schedule the ugen. */
1939 ugen_doit(dc, u2);
1940 notyet: ;
1941 }
1942 }
1943 t_freebytes(insig,(u->u_nin + u->u_nout) * sizeof(t_signal *));
1944 u->u_done = 1;
1945}
1946
1947 /* once the DSP graph is built, we call this routine to sort it.
1948 This routine also deletes the graph; later we might want to leave the
1949 graph around, in case the user is editing the DSP network, to save having
1950 to recreate it all the time. But not today. */
1951
1952void ugen_done_graph(t_dspcontext *dc)
1953{
1954 t_ugenbox *u, *u2;
1955 t_sigoutlet *uout;
1956 t_siginlet *uin;
1957 t_sigoutconnect *oc, *oc2;
1958 int i, n;
1959 t_block *blk;
1960 t_dspcontext *parent_context = dc->dc_parentcontext;
1961 float parent_srate;
1962 int parent_vecsize;
1963 int period, frequency, phase, vecsize;
1964 float srate;
1965 int chainblockbegin; /* DSP chain onset before block prolog code */
1966 int chainblockend; /* and after block epilog code */
1967 int chainafterall; /* and after signal outlet epilog */
1968 int reblock = 0, switched;
1969 int downsample = 1, upsample = 1; /* IOhannes */
1970 /* debugging printout */
1971
1972 if (ugen_loud)
1973 {
1974 post("ugen_done_graph...");
1975 for (u = dc->dc_ugenlist; u; u = u->u_next)
1976 {
1977 post("ugen: %s", class_getname(u->u_obj->ob_pd));
1978 for (uout = u->u_out, i = 0; i < u->u_nout; uout++, i++)
1979 for (oc = uout->o_connections; oc; oc = oc->oc_next)
1980 {
1981 post("... out %d to %s, index %d, inlet %d", i,
1982 class_getname(oc->oc_who->u_obj->ob_pd),
1983 ugen_index(dc, oc->oc_who), oc->oc_inno);
1984 }
1985 }
1986 }
1987
1988 /* search for an object of class "block~" */
1989 for (u = dc->dc_ugenlist, blk = 0; u; u = u->u_next)
1990 {
1991 t_pd *zz = &u->u_obj->ob_pd;
1992 if (pd_class(zz) == block_class)
1993 {
1994 if (blk)
1995 pd_error(blk, "conflicting block~ objects in same page");
1996 else blk = (t_block *)zz;
1997 }
1998 }
1999
2000 /* figure out block size, calling frequency, sample rate */
2001 if (parent_context)
2002 {
2003 parent_srate = parent_context->dc_srate;
2004 parent_vecsize = parent_context->dc_vecsize;
2005 }
2006 else
2007 {
2008 parent_srate = sys_getsr();
2009 parent_vecsize = sys_getblksize();
2010 }
2011 if (blk)
2012 {
2013 int realoverlap;
2014 vecsize = blk->x_vecsize;
2015 if (vecsize == 0)
2016 vecsize = parent_vecsize;
2017 realoverlap = blk->x_overlap;
2018 if (realoverlap > vecsize) realoverlap = vecsize;
2019 /* IOhannes { */
2020 downsample = blk->x_downsample;
2021 upsample = blk->x_upsample;
2022 if (downsample > parent_vecsize) downsample=parent_vecsize;
2023 period = (vecsize * downsample)/
2024 (parent_vecsize * realoverlap * upsample);
2025 frequency = (parent_vecsize * realoverlap * upsample)/
2026 (vecsize * downsample);
2027 /* } IOhannes*/
2028 phase = blk->x_phase;
2029 srate = parent_srate * realoverlap * upsample / downsample;
2030 /* IOhannes */
2031 if (period < 1) period = 1;
2032 if (frequency < 1) frequency = 1;
2033 blk->x_frequency = frequency;
2034 blk->x_period = period;
2035 blk->x_phase = dsp_phase & (period - 1);
2036 if (! parent_context || (realoverlap != 1) ||
2037 (vecsize != parent_vecsize) ||
2038 (downsample != 1) || (upsample != 1)) /* IOhannes */
2039 reblock = 1;
2040 switched = blk->x_switched;
2041 }
2042 else
2043 {
2044 srate = parent_srate;
2045 vecsize = parent_vecsize;
2046 downsample = upsample = 1;/* IOhannes */
2047 period = frequency = 1;
2048 phase = 0;
2049 if (!parent_context) reblock = 1;
2050 switched = 0;
2051 }
2052 dc->dc_reblock = reblock;
2053 dc->dc_switched = switched;
2054 dc->dc_srate = srate;
2055 dc->dc_vecsize = vecsize;
2056
2057 /* if we're reblocking or switched, we now have to create output
2058 signals to fill in for the "borrowed" ones we have now. This
2059 is also possibly true even if we're not blocked/switched, in
2060 the case that there was a signal loop. But we don't know this
2061 yet. */
2062
2063 if (dc->dc_iosigs && (switched || reblock))
2064 {
2065 t_signal **sigp;
2066 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
2067 i++, sigp++)
2068 {
2069 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
2070 {
2071 signal_setborrowed(*sigp,
2072 signal_new(parent_vecsize, parent_srate));
2073 (*sigp)->s_refcount++;
2074
2075 if (ugen_loud) post("set %x->%x", *sigp,
2076 (*sigp)->s_borrowedfrom);
2077 }
2078 }
2079 }
2080
2081 if (ugen_loud)
2082 post("reblock %d, switched %d", reblock, switched);
2083
2084 /* schedule prologs for inlets and outlets. If the "reblock" flag
2085 is set, an inlet will put code on the DSP chain to copy its input
2086 into an internal buffer here, before any unit generators' DSP code
2087 gets scheduled. If we don't "reblock", inlets will need to get
2088 pointers to their corresponding inlets/outlets on the box we're inside,
2089 if any. Outlets will also need pointers, unless we're switched, in
2090 which case outlet epilog code will kick in. */
2091
2092 for (u = dc->dc_ugenlist; u; u = u->u_next)
2093 {
2094 t_pd *zz = &u->u_obj->ob_pd;
2095 t_signal **insigs = dc->dc_iosigs, **outsigs = dc->dc_iosigs;
2096 if (outsigs) outsigs += dc->dc_ninlets;
2097
2098 if (pd_class(zz) == vinlet_class)
2099 vinlet_dspprolog((struct _vinlet *)zz,
2100 dc->dc_iosigs, vecsize, dsp_phase, period, frequency,
2101 downsample, upsample, /* IOhannes */
2102 reblock, switched);
2103 else if (pd_class(zz) == voutlet_class)
2104 voutlet_dspprolog((struct _voutlet *)zz,
2105 outsigs, vecsize, dsp_phase, period, frequency,
2106 downsample, upsample, /* IOhannes */
2107 reblock, switched);
2108 }
2109 chainblockbegin = dsp_chainsize;
2110
2111 if (blk && (reblock || switched)) /* add the block DSP prolog */
2112 dsp_add(block_prolog, 1, blk);
2113
2114 /* Initialize for sorting */
2115 for (u = dc->dc_ugenlist; u; u = u->u_next)
2116 {
2117 u->u_done = 0;
2118 for (uout = u->u_out, i = u->u_nout; i--; uout++)
2119 uout->o_nsent = 0;
2120 for (uin = u->u_in, i = u->u_nin; i--; uin++)
2121 uin->i_ngot = 0, uin->i_signal = 0;
2122 }
2123
2124 /* Do the sort */
2125
2126 for (u = dc->dc_ugenlist; u; u = u->u_next)
2127 {
2128 /* check that we have no connected signal inlets */
2129 if (u->u_done) continue;
2130 for (uin = u->u_in, i = u->u_nin; i--; uin++)
2131 if (uin->i_nconnect) goto next;
2132
2133 ugen_doit(dc, u);
2134 next: ;
2135 }
2136
2137 /* check for a DSP loop, which is evidenced here by the presence
2138 of ugens not yet scheduled. */
2139
2140 for (u = dc->dc_ugenlist; u; u = u->u_next)
2141 if (!u->u_done)
2142 {
2143 t_signal **sigp;
2144 pd_error(u->u_obj,
2145 "DSP loop detected (some tilde objects not scheduled)");
2146 /* this might imply that we have unfilled "borrowed" outputs
2147 which we'd better fill in now. */
2148 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
2149 i++, sigp++)
2150 {
2151 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
2152 {
2153 t_signal *s3 = signal_new(parent_vecsize, parent_srate);
2154 signal_setborrowed(*sigp, s3);
2155 (*sigp)->s_refcount++;
2156 dsp_add_zero(s3->s_vec, s3->s_n);
2157 if (ugen_loud)
2158 post("oops, belatedly set %x->%x", *sigp,
2159 (*sigp)->s_borrowedfrom);
2160 }
2161 }
2162 break; /* don't need to keep looking. */
2163 }
2164
2165 if (blk && (reblock || switched)) /* add block DSP epilog */
2166 dsp_add(block_epilog, 1, blk);
2167 chainblockend = dsp_chainsize;
2168
2169 /* add epilogs for outlets. */
2170
2171 for (u = dc->dc_ugenlist; u; u = u->u_next)
2172 {
2173 t_pd *zz = &u->u_obj->ob_pd;
2174 if (pd_class(zz) == voutlet_class)
2175 {
2176 t_signal **iosigs = dc->dc_iosigs;
2177 if (iosigs) iosigs += dc->dc_ninlets;
2178 voutlet_dspepilog((struct _voutlet *)zz,
2179 iosigs, vecsize, dsp_phase, period, frequency,
2180 downsample, upsample, /* IOhannes */
2181 reblock, switched);
2182 }
2183 }
2184
2185 chainafterall = dsp_chainsize;
2186 if (blk)
2187 {
2188 blk->x_blocklength = chainblockend - chainblockbegin;
2189 blk->x_epiloglength = chainafterall - chainblockend;
2190 blk->x_reblock = reblock;
2191 }
2192
2193 if (ugen_loud)
2194 {
2195 t_int *ip;
2196 if (!dc->dc_parentcontext)
2197 for (i = dsp_chainsize, ip = dsp_chain; i--; ip++)
2198 post("chain %x", *ip);
2199 post("... ugen_done_graph done.");
2200 }
2201 /* now delete everything. */
2202 while (dc->dc_ugenlist)
2203 {
2204 for (uout = dc->dc_ugenlist->u_out, n = dc->dc_ugenlist->u_nout;
2205 n--; uout++)
2206 {
2207 oc = uout->o_connections;
2208 while (oc)
2209 {
2210 oc2 = oc->oc_next;
2211 freebytes(oc, sizeof *oc);
2212 oc = oc2;
2213 }
2214 }
2215 freebytes(dc->dc_ugenlist->u_out, dc->dc_ugenlist->u_nout *
2216 sizeof (*dc->dc_ugenlist->u_out));
2217 freebytes(dc->dc_ugenlist->u_in, dc->dc_ugenlist->u_nin *
2218 sizeof(*dc->dc_ugenlist->u_in));
2219 u = dc->dc_ugenlist;
2220 dc->dc_ugenlist = u->u_next;
2221 freebytes(u, sizeof *u);
2222 }
2223 if (ugen_currentcontext == dc)
2224 ugen_currentcontext = dc->dc_parentcontext;
2225 else bug("ugen_currentcontext");
2226 freebytes(dc, sizeof(*dc));
2227
2228}
2229
2230t_signal *ugen_getiosig(int index, int inout)
2231{
2232 if (!ugen_currentcontext) bug("ugen_getiosig");
2233 if (ugen_currentcontext->dc_toplevel) return (0);
2234 if (inout) index += ugen_currentcontext->dc_ninlets;
2235 return (ugen_currentcontext->dc_iosigs[index]);
2236}
2237
2238
2239/* -------------------- setup routine -------------------------- */
2240
2241void d_ugen_setup(void) /* really just block_setup */
2242{
2243 block_class = class_new(gensym("block~"), (t_newmethod)block_new, 0,
2244 sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
2245 class_addcreator((t_newmethod)switch_new, gensym("switch~"),
2246 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
2247 class_addmethod(block_class, (t_method)block_set, gensym("set"),
2248 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
2249 class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), 0);
2250 class_addfloat(block_class, block_float);
2251}
2252
diff --git a/apps/plugins/pdbox/PDa/src/delme.pd b/apps/plugins/pdbox/PDa/src/delme.pd
new file mode 100644
index 0000000000..8e2c4f240c
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/delme.pd
@@ -0,0 +1,16 @@
1#N canvas 0 0 236 296 10;
2#X obj 79 77 gcanvas 80 80 0 0;
3#X floatatom 42 209 5 0 0 0 - - -;
4#X floatatom 107 205 5 0 0 0 - - -;
5#X floatatom 149 210 5 0 0 0 - - -;
6#X connect 0 0 1 0;
7#X connect 0 1 2 0;
8#X connect 0 2 3 0;
9#N canvas 0 0 236 296 10;
10#X obj 79 77 gcanvas 80 80 0 0;
11#X floatatom 42 209 5 0 0 0 - - -;
12#X floatatom 107 205 5 0 0 0 - - -;
13#X floatatom 149 210 5 0 0 0 - - -;
14#X connect 0 0 1 0;
15#X connect 0 1 2 0;
16#X connect 0 2 3 0;
diff --git a/apps/plugins/pdbox/PDa/src/g_all_guis.c b/apps/plugins/pdbox/PDa/src/g_all_guis.c
new file mode 100644
index 0000000000..9254bafebd
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_all_guis.c
@@ -0,0 +1,1324 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
7
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <ctype.h>
13#include "m_pd.h"
14#include "g_canvas.h"
15#include "t_tk.h"
16#include "g_all_guis.h"
17#include <math.h>
18
19#ifdef MSW
20#include <io.h>
21#else
22#include <unistd.h>
23#endif
24
25/* #define GGEE_HSLIDER_COMPATIBLE */
26
27/*------------------ global varaibles -------------------------*/
28
29int iemgui_color_hex[]=
30{
31 16579836, 10526880, 4210752, 16572640, 16572608,
32 16579784, 14220504, 14220540, 14476540, 16308476,
33 14737632, 8158332, 2105376, 16525352, 16559172,
34 15263784, 1370132, 2684148, 3952892, 16003312,
35 12369084, 6316128, 0, 9177096, 5779456,
36 7874580, 2641940, 17488, 5256, 5767248
37};
38
39int iemgui_vu_db2i[]=
40{
41 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
42 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
43 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
44 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
45 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
46 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
47 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
48 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
49 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
50 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
51 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
52 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
53 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
54 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
55 9, 9, 9, 9, 9,10,10,10,10,10,
56 11,11,11,11,11,12,12,12,12,12,
57 13,13,13,13,14,14,14,14,15,15,
58 15,15,16,16,16,16,17,17,17,18,
59 18,18,19,19,19,20,20,20,21,21,
60 22,22,23,23,24,24,25,26,27,28,
61 29,30,31,32,33,33,34,34,35,35,
62 36,36,37,37,37,38,38,38,39,39,
63 39,39,39,39,40,40
64};
65
66int iemgui_vu_col[]=
67{
68 0,17,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
69 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
70};
71
72char *iemgui_vu_scale_str[]=
73{
74 "",
75 "<-99",
76 "",
77 "",
78 "",
79 "-50",
80 "",
81 "",
82 "",
83 "-30",
84 "",
85 "",
86 "",
87 "-20",
88 "",
89 "",
90 "",
91 "-12",
92 "",
93 "",
94 "",
95 "-6",
96 "",
97 "",
98 "",
99 "-2",
100 "",
101 "",
102 "",
103 "-0dB",
104 "",
105 "",
106 "",
107 "+2",
108 "",
109 "",
110 "",
111 "+6",
112 "",
113 "",
114 "",
115 ">+12",
116 "",
117 "",
118 "",
119 "",
120 "",
121};
122
123
124/*------------------ global functions -------------------------*/
125
126
127int iemgui_clip_size(int size)
128{
129 if(size < IEM_GUI_MINSIZE)
130 size = IEM_GUI_MINSIZE;
131 return(size);
132}
133
134int iemgui_clip_font(int size)
135{
136 if(size < IEM_FONT_MINSIZE)
137 size = IEM_FONT_MINSIZE;
138 return(size);
139}
140
141int iemgui_modulo_color(int col)
142{
143 while(col >= IEM_GUI_MAX_COLOR)
144 col -= IEM_GUI_MAX_COLOR;
145 while(col < 0)
146 col += IEM_GUI_MAX_COLOR;
147 return(col);
148}
149
150t_symbol *iemgui_raute2dollar(t_symbol *s)
151{
152 if (s->s_name[0] == '#')
153 {
154 char buf[MAXPDSTRING];
155 strncpy(buf, s->s_name, MAXPDSTRING);
156 buf[MAXPDSTRING-1] = 0;
157 buf[0] = '$';
158 return (gensym(buf));
159 }
160 else return (s);
161}
162
163t_symbol *iemgui_dollar2raute(t_symbol *s)
164{
165 if (s->s_name[0] == '$')
166 {
167 char buf[MAXPDSTRING];
168 strncpy(buf, s->s_name, MAXPDSTRING);
169 buf[MAXPDSTRING-1] = 0;
170 buf[0] = '#';
171 return (gensym(buf));
172 }
173 else return (s);
174}
175
176void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui)
177{
178 iemgui->x_fsf.x_put_in2out = 1;
179 if(iemgui->x_fsf.x_snd_able && iemgui->x_fsf.x_rcv_able)
180 {
181 if(!strcmp(iemgui->x_snd->s_name, iemgui->x_rcv->s_name))
182 iemgui->x_fsf.x_put_in2out = 0;
183 }
184}
185
186t_symbol *iemgui_new_dogetname(t_iemgui *iemgui, int indx, t_atom *argv)
187{
188 if (IS_A_SYMBOL(argv, indx))
189 return (atom_getsymbolarg(indx, 100000, argv));
190 else if (IS_A_FLOAT(argv, indx))
191 {
192 char str[80];
193 sprintf(str, "%d", (int)atom_getintarg(indx, 100000, argv));
194 return (gensym(str));
195 }
196 else return (gensym("empty"));
197}
198
199void iemgui_new_getnames(t_iemgui *iemgui, int indx, t_atom *argv)
200{
201 if (argv)
202 {
203 iemgui->x_snd = iemgui_new_dogetname(iemgui, indx, argv);
204 iemgui->x_rcv = iemgui_new_dogetname(iemgui, indx+1, argv);
205 iemgui->x_lab = iemgui_new_dogetname(iemgui, indx+2, argv);
206 }
207 else iemgui->x_snd = iemgui->x_rcv = iemgui->x_lab = gensym("empty");
208 iemgui->x_snd_unexpanded = iemgui->x_rcv_unexpanded =
209 iemgui->x_lab_unexpanded = 0;
210 iemgui->x_binbufindex = indx;
211 iemgui->x_labelbindex = indx + 3;
212}
213
214 /* convert symbols in "$" form to the expanded symbols */
215void iemgui_all_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym)
216{
217 /* save unexpanded ones for later */
218 iemgui->x_snd_unexpanded = srlsym[0];
219 iemgui->x_rcv_unexpanded = srlsym[1];
220 iemgui->x_lab_unexpanded = srlsym[2];
221 srlsym[0] = canvas_realizedollar(iemgui->x_glist, srlsym[0]);
222 srlsym[1] = canvas_realizedollar(iemgui->x_glist, srlsym[1]);
223 srlsym[2] = canvas_realizedollar(iemgui->x_glist, srlsym[2]);
224}
225
226 /* initialize a single symbol in unexpanded form. We reach into the
227 binbuf to grab them; if there's nothing there, set it to the
228 fallback; if still nothing, set to "empty". */
229static void iemgui_init_sym2dollararg(t_iemgui *iemgui, t_symbol **symp,
230 int indx, t_symbol *fallback)
231{
232 if (!*symp)
233 {
234 t_binbuf *b = iemgui->x_obj.ob_binbuf;
235 if (binbuf_getnatom(b) > indx)
236 {
237 char buf[80];
238 atom_string(binbuf_getvec(b) + indx, buf, 80);
239 *symp = gensym(buf);
240 }
241 else if (fallback)
242 *symp = fallback;
243 else *symp = gensym("empty");
244 }
245}
246
247 /* get the unexpanded versions of the symbols; initialize them if
248 necessary. */
249void iemgui_all_sym2dollararg(t_iemgui *iemgui, t_symbol **srlsym)
250{
251 iemgui_init_sym2dollararg(iemgui, &iemgui->x_snd_unexpanded,
252 iemgui->x_binbufindex+1, iemgui->x_snd);
253 iemgui_init_sym2dollararg(iemgui, &iemgui->x_rcv_unexpanded,
254 iemgui->x_binbufindex+2, iemgui->x_rcv);
255 iemgui_init_sym2dollararg(iemgui, &iemgui->x_lab_unexpanded,
256 iemgui->x_labelbindex, iemgui->x_lab);
257 srlsym[0] = iemgui->x_snd_unexpanded;
258 srlsym[1] = iemgui->x_rcv_unexpanded;
259 srlsym[2] = iemgui->x_lab_unexpanded;
260}
261
262void iemgui_first_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym)
263{
264 /* delete this function */
265}
266
267void iemgui_all_col2save(t_iemgui *iemgui, int *bflcol)
268{
269 bflcol[0] = -1 - (((0xfc0000 & iemgui->x_bcol) >> 6)|
270 ((0xfc00 & iemgui->x_bcol) >> 4)|((0xfc & iemgui->x_bcol) >> 2));
271 bflcol[1] = -1 - (((0xfc0000 & iemgui->x_fcol) >> 6)|
272 ((0xfc00 & iemgui->x_fcol) >> 4)|((0xfc & iemgui->x_fcol) >> 2));
273 bflcol[2] = -1 - (((0xfc0000 & iemgui->x_lcol) >> 6)|
274 ((0xfc00 & iemgui->x_lcol) >> 4)|((0xfc & iemgui->x_lcol) >> 2));
275}
276
277void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol)
278{
279 if(bflcol[0] < 0)
280 {
281 bflcol[0] = -1 - bflcol[0];
282 iemgui->x_bcol = ((bflcol[0] & 0x3f000) << 6)|((bflcol[0] & 0xfc0) << 4)|
283 ((bflcol[0] & 0x3f) << 2);
284 }
285 else
286 {
287 bflcol[0] = iemgui_modulo_color(bflcol[0]);
288 iemgui->x_bcol = iemgui_color_hex[bflcol[0]];
289 }
290 if(bflcol[1] < 0)
291 {
292 bflcol[1] = -1 - bflcol[1];
293 iemgui->x_fcol = ((bflcol[1] & 0x3f000) << 6)|((bflcol[1] & 0xfc0) << 4)|
294 ((bflcol[1] & 0x3f) << 2);
295 }
296 else
297 {
298 bflcol[1] = iemgui_modulo_color(bflcol[1]);
299 iemgui->x_fcol = iemgui_color_hex[bflcol[1]];
300 }
301 if(bflcol[2] < 0)
302 {
303 bflcol[2] = -1 - bflcol[2];
304 iemgui->x_lcol = ((bflcol[2] & 0x3f000) << 6)|((bflcol[2] & 0xfc0) << 4)|
305 ((bflcol[2] & 0x3f) << 2);
306 }
307 else
308 {
309 bflcol[2] = iemgui_modulo_color(bflcol[2]);
310 iemgui->x_lcol = iemgui_color_hex[bflcol[2]];
311 }
312}
313
314int iemgui_compatible_col(int i)
315{
316 int j;
317
318 if(i >= 0)
319 {
320 j = iemgui_modulo_color(i);
321 return(iemgui_color_hex[(j)]);
322 }
323 else
324 return((-1 -i)&0xffffff);
325}
326
327void iemgui_all_dollar2raute(t_symbol **srlsym)
328{
329 srlsym[0] = iemgui_dollar2raute(srlsym[0]);
330 srlsym[1] = iemgui_dollar2raute(srlsym[1]);
331 srlsym[2] = iemgui_dollar2raute(srlsym[2]);
332}
333
334void iemgui_all_raute2dollar(t_symbol **srlsym)
335{
336 srlsym[0] = iemgui_raute2dollar(srlsym[0]);
337 srlsym[1] = iemgui_raute2dollar(srlsym[1]);
338 srlsym[2] = iemgui_raute2dollar(srlsym[2]);
339}
340
341void iemgui_send(void *x, t_iemgui *iemgui, t_symbol *s)
342{
343 t_symbol *snd;
344 int pargc, tail_len, nth_arg, sndable=1, oldsndrcvable=0;
345 t_atom *pargv;
346
347 if(iemgui->x_fsf.x_rcv_able)
348 oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
349 if(iemgui->x_fsf.x_snd_able)
350 oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
351
352 if(!strcmp(s->s_name, "empty")) sndable = 0;
353 snd = iemgui_raute2dollar(s);
354 iemgui->x_snd_unexpanded = snd;
355 iemgui->x_snd = snd = canvas_realizedollar(iemgui->x_glist, snd);
356 post("send: before %s, after %s", iemgui->x_snd_unexpanded->s_name,
357 iemgui->x_snd->s_name);
358
359 iemgui->x_fsf.x_snd_able = sndable;
360 iemgui_verify_snd_ne_rcv(iemgui);
361 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_IO + oldsndrcvable);
362}
363
364void iemgui_receive(void *x, t_iemgui *iemgui, t_symbol *s)
365{
366 t_symbol *rcv;
367 int pargc, tail_len, nth_arg, rcvable=1, oldsndrcvable=0;
368 t_atom *pargv;
369
370 if(iemgui->x_fsf.x_rcv_able)
371 oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
372 if(iemgui->x_fsf.x_snd_able)
373 oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
374
375 if(!strcmp(s->s_name, "empty")) rcvable = 0;
376 rcv = iemgui_raute2dollar(s);
377 iemgui->x_rcv_unexpanded = rcv;
378 iemgui->x_rcv = rcv = canvas_realizedollar(iemgui->x_glist, rcv);
379 if(rcvable)
380 {
381 if(strcmp(rcv->s_name, iemgui->x_rcv->s_name))
382 {
383 if(iemgui->x_fsf.x_rcv_able)
384 pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
385 iemgui->x_rcv = rcv;
386 pd_bind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
387 }
388 }
389 else if(!rcvable && iemgui->x_fsf.x_rcv_able)
390 {
391 pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
392 iemgui->x_rcv = rcv;
393 }
394 iemgui->x_fsf.x_rcv_able = rcvable;
395 iemgui_verify_snd_ne_rcv(iemgui);
396 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_IO + oldsndrcvable);
397}
398
399void iemgui_label(void *x, t_iemgui *iemgui, t_symbol *s)
400{
401 t_symbol *lab;
402 int pargc, tail_len, nth_arg;
403 t_atom *pargv;
404
405 lab = iemgui_raute2dollar(s);
406 iemgui->x_lab_unexpanded = lab;
407 iemgui->x_lab = lab = canvas_realizedollar(iemgui->x_glist, lab);
408
409 if(glist_isvisible(iemgui->x_glist))
410 sys_vgui(".x%x.c itemconfigure %xLABEL -text {%s} \n",
411 glist_getcanvas(iemgui->x_glist), x,
412 strcmp(s->s_name, "empty")?iemgui->x_lab->s_name:"");
413}
414
415void iemgui_label_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
416{
417 iemgui->x_ldx = (int)atom_getintarg(0, ac, av);
418 iemgui->x_ldy = (int)atom_getintarg(1, ac, av);
419 if(glist_isvisible(iemgui->x_glist))
420 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
421 glist_getcanvas(iemgui->x_glist), x,
422 iemgui->x_obj.te_xpix+iemgui->x_ldx,
423 iemgui->x_obj.te_ypix+iemgui->x_ldy);
424}
425
426void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
427{
428 int f = (int)atom_getintarg(0, ac, av);
429
430 if(f == 1) strcpy(iemgui->x_font, "helvetica");
431 else if(f == 2) strcpy(iemgui->x_font, "times");
432 else
433 {
434 f = 0;
435 strcpy(iemgui->x_font, "courier");
436 }
437 iemgui->x_fsf.x_font_style = f;
438 f = (int)atom_getintarg(1, ac, av);
439 if(f < 4)
440 f = 4;
441 iemgui->x_fontsize = f;
442 if(glist_isvisible(iemgui->x_glist))
443 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold}\n",
444 glist_getcanvas(iemgui->x_glist), x, iemgui->x_font, iemgui->x_fontsize);
445}
446
447void iemgui_size(void *x, t_iemgui *iemgui)
448{
449 if(glist_isvisible(iemgui->x_glist))
450 {
451 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
452 canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
453 }
454}
455
456void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
457{
458 iemgui->x_obj.te_xpix += (int)atom_getintarg(0, ac, av);
459 iemgui->x_obj.te_ypix += (int)atom_getintarg(1, ac, av);
460 if(glist_isvisible(iemgui->x_glist))
461 {
462 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
463 canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
464 }
465}
466
467void iemgui_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
468{
469 iemgui->x_obj.te_xpix = (int)atom_getintarg(0, ac, av);
470 iemgui->x_obj.te_ypix = (int)atom_getintarg(1, ac, av);
471 if(glist_isvisible(iemgui->x_glist))
472 {
473 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
474 canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
475 }
476}
477
478void iemgui_color(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
479{
480 iemgui->x_bcol = iemgui_compatible_col(atom_getintarg(0, ac, av));
481 if(ac > 2)
482 {
483 iemgui->x_fcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
484 iemgui->x_lcol = iemgui_compatible_col(atom_getintarg(2, ac, av));
485 }
486 else
487 iemgui->x_lcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
488 if(glist_isvisible(iemgui->x_glist))
489 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_CONFIG);
490}
491
492void iemgui_displace(t_gobj *z, t_glist *glist, int dx, int dy)
493{
494 t_iemguidummy *x = (t_iemguidummy *)z;
495
496 x->x_gui.x_obj.te_xpix += dx;
497 x->x_gui.x_obj.te_ypix += dy;
498 (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_MOVE);
499 canvas_fixlinesfor(glist_getcanvas(glist), (t_text *)z);
500}
501
502void iemgui_select(t_gobj *z, t_glist *glist, int selected)
503{
504 t_iemguidummy *x = (t_iemguidummy *)z;
505
506 x->x_gui.x_fsf.x_selected = selected;
507 (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_SELECT);
508}
509
510void iemgui_delete(t_gobj *z, t_glist *glist)
511{
512 canvas_deletelinesfor(glist, (t_text *)z);
513}
514
515void iemgui_vis(t_gobj *z, t_glist *glist, int vis)
516{
517 t_iemguidummy *x = (t_iemguidummy *)z;
518
519 if (vis)
520 (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_NEW);
521 else
522 (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_ERASE);
523}
524
525void iemgui_save(t_iemgui *iemgui, t_symbol **srl, int *bflcol)
526{
527 srl[0] = iemgui->x_snd;
528 srl[1] = iemgui->x_rcv;
529 srl[2] = iemgui->x_lab;
530 iemgui_all_sym2dollararg(iemgui, srl);
531 iemgui_all_col2save(iemgui, bflcol);
532}
533
534void iemgui_properties(t_iemgui *iemgui, t_symbol **srl)
535{
536 srl[0] = iemgui->x_snd;
537 srl[1] = iemgui->x_rcv;
538 srl[2] = iemgui->x_lab;
539 iemgui_all_sym2dollararg(iemgui, srl);
540 iemgui_all_dollar2raute(srl);
541}
542
543int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv)
544{
545 char str[144];
546 int init = (int)atom_getintarg(5, argc, argv);
547 int ldx = (int)atom_getintarg(10, argc, argv);
548 int ldy = (int)atom_getintarg(11, argc, argv);
549 int f = (int)atom_getintarg(12, argc, argv);
550 int fs = (int)atom_getintarg(13, argc, argv);
551 int bcol = (int)atom_getintarg(14, argc, argv);
552 int fcol = (int)atom_getintarg(15, argc, argv);
553 int lcol = (int)atom_getintarg(16, argc, argv);
554 int sndable=1, rcvable=1, oldsndrcvable=0;
555
556 if(iemgui->x_fsf.x_rcv_able)
557 oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
558 if(iemgui->x_fsf.x_snd_able)
559 oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
560 if(IS_A_SYMBOL(argv,7))
561 srl[0] = atom_getsymbolarg(7, argc, argv);
562 else if(IS_A_FLOAT(argv,7))
563 {
564 sprintf(str, "%d", (int)atom_getintarg(7, argc, argv));
565 srl[0] = gensym(str);
566 }
567 if(IS_A_SYMBOL(argv,8))
568 srl[1] = atom_getsymbolarg(8, argc, argv);
569 else if(IS_A_FLOAT(argv,8))
570 {
571 sprintf(str, "%d", (int)atom_getintarg(8, argc, argv));
572 srl[1] = gensym(str);
573 }
574 if(IS_A_SYMBOL(argv,9))
575 srl[2] = atom_getsymbolarg(9, argc, argv);
576 else if(IS_A_FLOAT(argv,9))
577 {
578 sprintf(str, "%d", (int)atom_getintarg(9, argc, argv));
579 srl[2] = gensym(str);
580 }
581 if(init != 0) init = 1;
582 iemgui->x_isa.x_loadinit = init;
583 if(!strcmp(srl[0]->s_name, "empty")) sndable = 0;
584 if(!strcmp(srl[1]->s_name, "empty")) rcvable = 0;
585 iemgui_all_raute2dollar(srl);
586 iemgui_all_dollararg2sym(iemgui, srl);
587 if(rcvable)
588 {
589 if(strcmp(srl[1]->s_name, iemgui->x_rcv->s_name))
590 {
591 if(iemgui->x_fsf.x_rcv_able)
592 pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
593 iemgui->x_rcv = srl[1];
594 pd_bind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
595 }
596 }
597 else if(!rcvable && iemgui->x_fsf.x_rcv_able)
598 {
599 pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
600 iemgui->x_rcv = srl[1];
601 }
602 iemgui->x_snd = srl[0];
603 iemgui->x_fsf.x_snd_able = sndable;
604 iemgui->x_fsf.x_rcv_able = rcvable;
605 iemgui->x_lcol = lcol & 0xffffff;
606 iemgui->x_fcol = fcol & 0xffffff;
607 iemgui->x_bcol = bcol & 0xffffff;
608 iemgui->x_lab = srl[2];
609 iemgui->x_ldx = ldx;
610 iemgui->x_ldy = ldy;
611 if(f == 1) strcpy(iemgui->x_font, "helvetica");
612 else if(f == 2) strcpy(iemgui->x_font, "times");
613 else
614 {
615 f = 0;
616 strcpy(iemgui->x_font, "courier");
617 }
618 iemgui->x_fsf.x_font_style = f;
619 if(fs < 4)
620 fs = 4;
621 iemgui->x_fontsize = fs;
622 iemgui_verify_snd_ne_rcv(iemgui);
623 return(oldsndrcvable);
624}
625
626void iem_inttosymargs(t_iem_init_symargs *symargp, int n)
627{
628 memset(symargp, 0, sizeof(*symargp));
629 symargp->x_loadinit = (n >> 0);
630 symargp->x_scale = (n >> 20);
631 symargp->x_flashed = 0;
632 symargp->x_locked = 0;
633 symargp->x_reverse = 0;
634 symargp->dummy = 0;
635}
636
637int iem_symargstoint(t_iem_init_symargs *symargp)
638{
639 return (
640 (((symargp->x_loadinit & 1) << 0) |
641 ((symargp->x_scale & 1) << 20)));
642}
643
644void iem_inttofstyle(t_iem_fstyle_flags *fstylep, int n)
645{
646 memset(fstylep, 0, sizeof(*fstylep));
647 fstylep->x_font_style = (n >> 0);
648 fstylep->x_shiftdown = 0;
649 fstylep->x_selected = 0;
650 fstylep->x_finemoved = 0;
651 fstylep->x_put_in2out = 0;
652 fstylep->x_change = 0;
653 fstylep->x_thick = 0;
654 fstylep->x_lin0_log1 = 0;
655 fstylep->x_steady = 0;
656 fstylep->dummy = 0;
657}
658
659int iem_fstyletoint(t_iem_fstyle_flags *fstylep)
660{
661 return ((fstylep->x_font_style << 0) & 63);
662}
663/* Copyright (c) 1997-1999 Miller Puckette.
664 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
665 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
666
667/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
668/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
669
670
671#include <stdlib.h>
672#include <string.h>
673#include <stdio.h>
674#include <ctype.h>
675#include "m_pd.h"
676#include "g_canvas.h"
677#include "t_tk.h"
678#include "g_all_guis.h"
679#include <math.h>
680
681#ifdef MSW
682#include <io.h>
683#else
684#include <unistd.h>
685#endif
686
687/* #define GGEE_HSLIDER_COMPATIBLE */
688
689/*------------------ global varaibles -------------------------*/
690
691int iemgui_color_hex[]=
692{
693 16579836, 10526880, 4210752, 16572640, 16572608,
694 16579784, 14220504, 14220540, 14476540, 16308476,
695 14737632, 8158332, 2105376, 16525352, 16559172,
696 15263784, 1370132, 2684148, 3952892, 16003312,
697 12369084, 6316128, 0, 9177096, 5779456,
698 7874580, 2641940, 17488, 5256, 5767248
699};
700
701int iemgui_vu_db2i[]=
702{
703 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
704 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
705 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
706 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
707 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
708 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
709 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
710 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
711 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
712 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
713 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
714 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
715 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
716 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
717 9, 9, 9, 9, 9,10,10,10,10,10,
718 11,11,11,11,11,12,12,12,12,12,
719 13,13,13,13,14,14,14,14,15,15,
720 15,15,16,16,16,16,17,17,17,18,
721 18,18,19,19,19,20,20,20,21,21,
722 22,22,23,23,24,24,25,26,27,28,
723 29,30,31,32,33,33,34,34,35,35,
724 36,36,37,37,37,38,38,38,39,39,
725 39,39,39,39,40,40
726};
727
728int iemgui_vu_col[]=
729{
730 0,17,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
731 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
732};
733
734char *iemgui_vu_scale_str[]=
735{
736 "",
737 "<-99",
738 "",
739 "",
740 "",
741 "-50",
742 "",
743 "",
744 "",
745 "-30",
746 "",
747 "",
748 "",
749 "-20",
750 "",
751 "",
752 "",
753 "-12",
754 "",
755 "",
756 "",
757 "-6",
758 "",
759 "",
760 "",
761 "-2",
762 "",
763 "",
764 "",
765 "-0dB",
766 "",
767 "",
768 "",
769 "+2",
770 "",
771 "",
772 "",
773 "+6",
774 "",
775 "",
776 "",
777 ">+12",
778 "",
779 "",
780 "",
781 "",
782 "",
783};
784
785
786/*------------------ global functions -------------------------*/
787
788
789int iemgui_clip_size(int size)
790{
791 if(size < IEM_GUI_MINSIZE)
792 size = IEM_GUI_MINSIZE;
793 return(size);
794}
795
796int iemgui_clip_font(int size)
797{
798 if(size < IEM_FONT_MINSIZE)
799 size = IEM_FONT_MINSIZE;
800 return(size);
801}
802
803int iemgui_modulo_color(int col)
804{
805 while(col >= IEM_GUI_MAX_COLOR)
806 col -= IEM_GUI_MAX_COLOR;
807 while(col < 0)
808 col += IEM_GUI_MAX_COLOR;
809 return(col);
810}
811
812t_symbol *iemgui_raute2dollar(t_symbol *s)
813{
814 if (s->s_name[0] == '#')
815 {
816 char buf[MAXPDSTRING];
817 strncpy(buf, s->s_name, MAXPDSTRING);
818 buf[MAXPDSTRING-1] = 0;
819 buf[0] = '$';
820 return (gensym(buf));
821 }
822 else return (s);
823}
824
825t_symbol *iemgui_dollar2raute(t_symbol *s)
826{
827 if (s->s_name[0] == '$')
828 {
829 char buf[MAXPDSTRING];
830 strncpy(buf, s->s_name, MAXPDSTRING);
831 buf[MAXPDSTRING-1] = 0;
832 buf[0] = '#';
833 return (gensym(buf));
834 }
835 else return (s);
836}
837
838void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui)
839{
840 iemgui->x_fsf.x_put_in2out = 1;
841 if(iemgui->x_fsf.x_snd_able && iemgui->x_fsf.x_rcv_able)
842 {
843 if(!strcmp(iemgui->x_snd->s_name, iemgui->x_rcv->s_name))
844 iemgui->x_fsf.x_put_in2out = 0;
845 }
846}
847
848t_symbol *iemgui_new_dogetname(t_iemgui *iemgui, int indx, t_atom *argv)
849{
850 if (IS_A_SYMBOL(argv, indx))
851 return (atom_getsymbolarg(indx, 100000, argv));
852 else if (IS_A_FLOAT(argv, indx))
853 {
854 char str[80];
855 sprintf(str, "%d", (int)atom_getintarg(indx, 100000, argv));
856 return (gensym(str));
857 }
858 else return (gensym("empty"));
859}
860
861void iemgui_new_getnames(t_iemgui *iemgui, int indx, t_atom *argv)
862{
863 if (argv)
864 {
865 iemgui->x_snd = iemgui_new_dogetname(iemgui, indx, argv);
866 iemgui->x_rcv = iemgui_new_dogetname(iemgui, indx+1, argv);
867 iemgui->x_lab = iemgui_new_dogetname(iemgui, indx+2, argv);
868 }
869 else iemgui->x_snd = iemgui->x_rcv = iemgui->x_lab = gensym("empty");
870 iemgui->x_snd_unexpanded = iemgui->x_rcv_unexpanded =
871 iemgui->x_lab_unexpanded = 0;
872 iemgui->x_binbufindex = indx;
873 iemgui->x_labelbindex = indx + 3;
874}
875
876 /* convert symbols in "$" form to the expanded symbols */
877void iemgui_all_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym)
878{
879 /* save unexpanded ones for later */
880 iemgui->x_snd_unexpanded = srlsym[0];
881 iemgui->x_rcv_unexpanded = srlsym[1];
882 iemgui->x_lab_unexpanded = srlsym[2];
883 srlsym[0] = canvas_realizedollar(iemgui->x_glist, srlsym[0]);
884 srlsym[1] = canvas_realizedollar(iemgui->x_glist, srlsym[1]);
885 srlsym[2] = canvas_realizedollar(iemgui->x_glist, srlsym[2]);
886}
887
888 /* initialize a single symbol in unexpanded form. We reach into the
889 binbuf to grab them; if there's nothing there, set it to the
890 fallback; if still nothing, set to "empty". */
891static void iemgui_init_sym2dollararg(t_iemgui *iemgui, t_symbol **symp,
892 int indx, t_symbol *fallback)
893{
894 if (!*symp)
895 {
896 t_binbuf *b = iemgui->x_obj.ob_binbuf;
897 if (binbuf_getnatom(b) > indx)
898 {
899 char buf[80];
900 atom_string(binbuf_getvec(b) + indx, buf, 80);
901 *symp = gensym(buf);
902 }
903 else if (fallback)
904 *symp = fallback;
905 else *symp = gensym("empty");
906 }
907}
908
909 /* get the unexpanded versions of the symbols; initialize them if
910 necessary. */
911void iemgui_all_sym2dollararg(t_iemgui *iemgui, t_symbol **srlsym)
912{
913 iemgui_init_sym2dollararg(iemgui, &iemgui->x_snd_unexpanded,
914 iemgui->x_binbufindex+1, iemgui->x_snd);
915 iemgui_init_sym2dollararg(iemgui, &iemgui->x_rcv_unexpanded,
916 iemgui->x_binbufindex+2, iemgui->x_rcv);
917 iemgui_init_sym2dollararg(iemgui, &iemgui->x_lab_unexpanded,
918 iemgui->x_labelbindex, iemgui->x_lab);
919 srlsym[0] = iemgui->x_snd_unexpanded;
920 srlsym[1] = iemgui->x_rcv_unexpanded;
921 srlsym[2] = iemgui->x_lab_unexpanded;
922}
923
924void iemgui_first_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym)
925{
926 /* delete this function */
927}
928
929void iemgui_all_col2save(t_iemgui *iemgui, int *bflcol)
930{
931 bflcol[0] = -1 - (((0xfc0000 & iemgui->x_bcol) >> 6)|
932 ((0xfc00 & iemgui->x_bcol) >> 4)|((0xfc & iemgui->x_bcol) >> 2));
933 bflcol[1] = -1 - (((0xfc0000 & iemgui->x_fcol) >> 6)|
934 ((0xfc00 & iemgui->x_fcol) >> 4)|((0xfc & iemgui->x_fcol) >> 2));
935 bflcol[2] = -1 - (((0xfc0000 & iemgui->x_lcol) >> 6)|
936 ((0xfc00 & iemgui->x_lcol) >> 4)|((0xfc & iemgui->x_lcol) >> 2));
937}
938
939void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol)
940{
941 if(bflcol[0] < 0)
942 {
943 bflcol[0] = -1 - bflcol[0];
944 iemgui->x_bcol = ((bflcol[0] & 0x3f000) << 6)|((bflcol[0] & 0xfc0) << 4)|
945 ((bflcol[0] & 0x3f) << 2);
946 }
947 else
948 {
949 bflcol[0] = iemgui_modulo_color(bflcol[0]);
950 iemgui->x_bcol = iemgui_color_hex[bflcol[0]];
951 }
952 if(bflcol[1] < 0)
953 {
954 bflcol[1] = -1 - bflcol[1];
955 iemgui->x_fcol = ((bflcol[1] & 0x3f000) << 6)|((bflcol[1] & 0xfc0) << 4)|
956 ((bflcol[1] & 0x3f) << 2);
957 }
958 else
959 {
960 bflcol[1] = iemgui_modulo_color(bflcol[1]);
961 iemgui->x_fcol = iemgui_color_hex[bflcol[1]];
962 }
963 if(bflcol[2] < 0)
964 {
965 bflcol[2] = -1 - bflcol[2];
966 iemgui->x_lcol = ((bflcol[2] & 0x3f000) << 6)|((bflcol[2] & 0xfc0) << 4)|
967 ((bflcol[2] & 0x3f) << 2);
968 }
969 else
970 {
971 bflcol[2] = iemgui_modulo_color(bflcol[2]);
972 iemgui->x_lcol = iemgui_color_hex[bflcol[2]];
973 }
974}
975
976int iemgui_compatible_col(int i)
977{
978 int j;
979
980 if(i >= 0)
981 {
982 j = iemgui_modulo_color(i);
983 return(iemgui_color_hex[(j)]);
984 }
985 else
986 return((-1 -i)&0xffffff);
987}
988
989void iemgui_all_dollar2raute(t_symbol **srlsym)
990{
991 srlsym[0] = iemgui_dollar2raute(srlsym[0]);
992 srlsym[1] = iemgui_dollar2raute(srlsym[1]);
993 srlsym[2] = iemgui_dollar2raute(srlsym[2]);
994}
995
996void iemgui_all_raute2dollar(t_symbol **srlsym)
997{
998 srlsym[0] = iemgui_raute2dollar(srlsym[0]);
999 srlsym[1] = iemgui_raute2dollar(srlsym[1]);
1000 srlsym[2] = iemgui_raute2dollar(srlsym[2]);
1001}
1002
1003void iemgui_send(void *x, t_iemgui *iemgui, t_symbol *s)
1004{
1005 t_symbol *snd;
1006 int pargc, tail_len, nth_arg, sndable=1, oldsndrcvable=0;
1007 t_atom *pargv;
1008
1009 if(iemgui->x_fsf.x_rcv_able)
1010 oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
1011 if(iemgui->x_fsf.x_snd_able)
1012 oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
1013
1014 if(!strcmp(s->s_name, "empty")) sndable = 0;
1015 snd = iemgui_raute2dollar(s);
1016 iemgui->x_snd_unexpanded = snd;
1017 iemgui->x_snd = snd = canvas_realizedollar(iemgui->x_glist, snd);
1018 post("send: before %s, after %s", iemgui->x_snd_unexpanded->s_name,
1019 iemgui->x_snd->s_name);
1020
1021 iemgui->x_fsf.x_snd_able = sndable;
1022 iemgui_verify_snd_ne_rcv(iemgui);
1023 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_IO + oldsndrcvable);
1024}
1025
1026void iemgui_receive(void *x, t_iemgui *iemgui, t_symbol *s)
1027{
1028 t_symbol *rcv;
1029 int pargc, tail_len, nth_arg, rcvable=1, oldsndrcvable=0;
1030 t_atom *pargv;
1031
1032 if(iemgui->x_fsf.x_rcv_able)
1033 oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
1034 if(iemgui->x_fsf.x_snd_able)
1035 oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
1036
1037 if(!strcmp(s->s_name, "empty")) rcvable = 0;
1038 rcv = iemgui_raute2dollar(s);
1039 iemgui->x_rcv_unexpanded = rcv;
1040 iemgui->x_rcv = rcv = canvas_realizedollar(iemgui->x_glist, rcv);
1041 if(rcvable)
1042 {
1043 if(strcmp(rcv->s_name, iemgui->x_rcv->s_name))
1044 {
1045 if(iemgui->x_fsf.x_rcv_able)
1046 pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
1047 iemgui->x_rcv = rcv;
1048 pd_bind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
1049 }
1050 }
1051 else if(!rcvable && iemgui->x_fsf.x_rcv_able)
1052 {
1053 pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
1054 iemgui->x_rcv = rcv;
1055 }
1056 iemgui->x_fsf.x_rcv_able = rcvable;
1057 iemgui_verify_snd_ne_rcv(iemgui);
1058 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_IO + oldsndrcvable);
1059}
1060
1061void iemgui_label(void *x, t_iemgui *iemgui, t_symbol *s)
1062{
1063 t_symbol *lab;
1064 int pargc, tail_len, nth_arg;
1065 t_atom *pargv;
1066
1067 lab = iemgui_raute2dollar(s);
1068 iemgui->x_lab_unexpanded = lab;
1069 iemgui->x_lab = lab = canvas_realizedollar(iemgui->x_glist, lab);
1070
1071 if(glist_isvisible(iemgui->x_glist))
1072 sys_vgui(".x%x.c itemconfigure %xLABEL -text {%s} \n",
1073 glist_getcanvas(iemgui->x_glist), x,
1074 strcmp(s->s_name, "empty")?iemgui->x_lab->s_name:"");
1075}
1076
1077void iemgui_label_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
1078{
1079 iemgui->x_ldx = (int)atom_getintarg(0, ac, av);
1080 iemgui->x_ldy = (int)atom_getintarg(1, ac, av);
1081 if(glist_isvisible(iemgui->x_glist))
1082 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
1083 glist_getcanvas(iemgui->x_glist), x,
1084 iemgui->x_obj.te_xpix+iemgui->x_ldx,
1085 iemgui->x_obj.te_ypix+iemgui->x_ldy);
1086}
1087
1088void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
1089{
1090 int f = (int)atom_getintarg(0, ac, av);
1091
1092 if(f == 1) strcpy(iemgui->x_font, "helvetica");
1093 else if(f == 2) strcpy(iemgui->x_font, "times");
1094 else
1095 {
1096 f = 0;
1097 strcpy(iemgui->x_font, "courier");
1098 }
1099 iemgui->x_fsf.x_font_style = f;
1100 f = (int)atom_getintarg(1, ac, av);
1101 if(f < 4)
1102 f = 4;
1103 iemgui->x_fontsize = f;
1104 if(glist_isvisible(iemgui->x_glist))
1105 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold}\n",
1106 glist_getcanvas(iemgui->x_glist), x, iemgui->x_font, iemgui->x_fontsize);
1107}
1108
1109void iemgui_size(void *x, t_iemgui *iemgui)
1110{
1111 if(glist_isvisible(iemgui->x_glist))
1112 {
1113 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
1114 canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
1115 }
1116}
1117
1118void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
1119{
1120 iemgui->x_obj.te_xpix += (int)atom_getintarg(0, ac, av);
1121 iemgui->x_obj.te_ypix += (int)atom_getintarg(1, ac, av);
1122 if(glist_isvisible(iemgui->x_glist))
1123 {
1124 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
1125 canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
1126 }
1127}
1128
1129void iemgui_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
1130{
1131 iemgui->x_obj.te_xpix = (int)atom_getintarg(0, ac, av);
1132 iemgui->x_obj.te_ypix = (int)atom_getintarg(1, ac, av);
1133 if(glist_isvisible(iemgui->x_glist))
1134 {
1135 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
1136 canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
1137 }
1138}
1139
1140void iemgui_color(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
1141{
1142 iemgui->x_bcol = iemgui_compatible_col(atom_getintarg(0, ac, av));
1143 if(ac > 2)
1144 {
1145 iemgui->x_fcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
1146 iemgui->x_lcol = iemgui_compatible_col(atom_getintarg(2, ac, av));
1147 }
1148 else
1149 iemgui->x_lcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
1150 if(glist_isvisible(iemgui->x_glist))
1151 (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_CONFIG);
1152}
1153
1154void iemgui_displace(t_gobj *z, t_glist *glist, int dx, int dy)
1155{
1156 t_iemguidummy *x = (t_iemguidummy *)z;
1157
1158 x->x_gui.x_obj.te_xpix += dx;
1159 x->x_gui.x_obj.te_ypix += dy;
1160 (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_MOVE);
1161 canvas_fixlinesfor(glist_getcanvas(glist), (t_text *)z);
1162}
1163
1164void iemgui_select(t_gobj *z, t_glist *glist, int selected)
1165{
1166 t_iemguidummy *x = (t_iemguidummy *)z;
1167
1168 x->x_gui.x_fsf.x_selected = selected;
1169 (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_SELECT);
1170}
1171
1172void iemgui_delete(t_gobj *z, t_glist *glist)
1173{
1174 canvas_deletelinesfor(glist, (t_text *)z);
1175}
1176
1177void iemgui_vis(t_gobj *z, t_glist *glist, int vis)
1178{
1179 t_iemguidummy *x = (t_iemguidummy *)z;
1180
1181 if (vis)
1182 (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_NEW);
1183 else
1184 (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_ERASE);
1185}
1186
1187void iemgui_save(t_iemgui *iemgui, t_symbol **srl, int *bflcol)
1188{
1189 srl[0] = iemgui->x_snd;
1190 srl[1] = iemgui->x_rcv;
1191 srl[2] = iemgui->x_lab;
1192 iemgui_all_sym2dollararg(iemgui, srl);
1193 iemgui_all_col2save(iemgui, bflcol);
1194}
1195
1196void iemgui_properties(t_iemgui *iemgui, t_symbol **srl)
1197{
1198 srl[0] = iemgui->x_snd;
1199 srl[1] = iemgui->x_rcv;
1200 srl[2] = iemgui->x_lab;
1201 iemgui_all_sym2dollararg(iemgui, srl);
1202 iemgui_all_dollar2raute(srl);
1203}
1204
1205int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv)
1206{
1207 char str[144];
1208 int init = (int)atom_getintarg(5, argc, argv);
1209 int ldx = (int)atom_getintarg(10, argc, argv);
1210 int ldy = (int)atom_getintarg(11, argc, argv);
1211 int f = (int)atom_getintarg(12, argc, argv);
1212 int fs = (int)atom_getintarg(13, argc, argv);
1213 int bcol = (int)atom_getintarg(14, argc, argv);
1214 int fcol = (int)atom_getintarg(15, argc, argv);
1215 int lcol = (int)atom_getintarg(16, argc, argv);
1216 int sndable=1, rcvable=1, oldsndrcvable=0;
1217
1218 if(iemgui->x_fsf.x_rcv_able)
1219 oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
1220 if(iemgui->x_fsf.x_snd_able)
1221 oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
1222 if(IS_A_SYMBOL(argv,7))
1223 srl[0] = atom_getsymbolarg(7, argc, argv);
1224 else if(IS_A_FLOAT(argv,7))
1225 {
1226 sprintf(str, "%d", (int)atom_getintarg(7, argc, argv));
1227 srl[0] = gensym(str);
1228 }
1229 if(IS_A_SYMBOL(argv,8))
1230 srl[1] = atom_getsymbolarg(8, argc, argv);
1231 else if(IS_A_FLOAT(argv,8))
1232 {
1233 sprintf(str, "%d", (int)atom_getintarg(8, argc, argv));
1234 srl[1] = gensym(str);
1235 }
1236 if(IS_A_SYMBOL(argv,9))
1237 srl[2] = atom_getsymbolarg(9, argc, argv);
1238 else if(IS_A_FLOAT(argv,9))
1239 {
1240 sprintf(str, "%d", (int)atom_getintarg(9, argc, argv));
1241 srl[2] = gensym(str);
1242 }
1243 if(init != 0) init = 1;
1244 iemgui->x_isa.x_loadinit = init;
1245 if(!strcmp(srl[0]->s_name, "empty")) sndable = 0;
1246 if(!strcmp(srl[1]->s_name, "empty")) rcvable = 0;
1247 iemgui_all_raute2dollar(srl);
1248 iemgui_all_dollararg2sym(iemgui, srl);
1249 if(rcvable)
1250 {
1251 if(strcmp(srl[1]->s_name, iemgui->x_rcv->s_name))
1252 {
1253 if(iemgui->x_fsf.x_rcv_able)
1254 pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
1255 iemgui->x_rcv = srl[1];
1256 pd_bind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
1257 }
1258 }
1259 else if(!rcvable && iemgui->x_fsf.x_rcv_able)
1260 {
1261 pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
1262 iemgui->x_rcv = srl[1];
1263 }
1264 iemgui->x_snd = srl[0];
1265 iemgui->x_fsf.x_snd_able = sndable;
1266 iemgui->x_fsf.x_rcv_able = rcvable;
1267 iemgui->x_lcol = lcol & 0xffffff;
1268 iemgui->x_fcol = fcol & 0xffffff;
1269 iemgui->x_bcol = bcol & 0xffffff;
1270 iemgui->x_lab = srl[2];
1271 iemgui->x_ldx = ldx;
1272 iemgui->x_ldy = ldy;
1273 if(f == 1) strcpy(iemgui->x_font, "helvetica");
1274 else if(f == 2) strcpy(iemgui->x_font, "times");
1275 else
1276 {
1277 f = 0;
1278 strcpy(iemgui->x_font, "courier");
1279 }
1280 iemgui->x_fsf.x_font_style = f;
1281 if(fs < 4)
1282 fs = 4;
1283 iemgui->x_fontsize = fs;
1284 iemgui_verify_snd_ne_rcv(iemgui);
1285 return(oldsndrcvable);
1286}
1287
1288void iem_inttosymargs(t_iem_init_symargs *symargp, int n)
1289{
1290 memset(symargp, 0, sizeof(*symargp));
1291 symargp->x_loadinit = (n >> 0);
1292 symargp->x_scale = (n >> 20);
1293 symargp->x_flashed = 0;
1294 symargp->x_locked = 0;
1295 symargp->x_reverse = 0;
1296 symargp->dummy = 0;
1297}
1298
1299int iem_symargstoint(t_iem_init_symargs *symargp)
1300{
1301 return (
1302 (((symargp->x_loadinit & 1) << 0) |
1303 ((symargp->x_scale & 1) << 20)));
1304}
1305
1306void iem_inttofstyle(t_iem_fstyle_flags *fstylep, int n)
1307{
1308 memset(fstylep, 0, sizeof(*fstylep));
1309 fstylep->x_font_style = (n >> 0);
1310 fstylep->x_shiftdown = 0;
1311 fstylep->x_selected = 0;
1312 fstylep->x_finemoved = 0;
1313 fstylep->x_put_in2out = 0;
1314 fstylep->x_change = 0;
1315 fstylep->x_thick = 0;
1316 fstylep->x_lin0_log1 = 0;
1317 fstylep->x_steady = 0;
1318 fstylep->dummy = 0;
1319}
1320
1321int iem_fstyletoint(t_iem_fstyle_flags *fstylep)
1322{
1323 return ((fstylep->x_font_style << 0) & 63);
1324}
diff --git a/apps/plugins/pdbox/PDa/src/g_all_guis.h b/apps/plugins/pdbox/PDa/src/g_all_guis.h
new file mode 100644
index 0000000000..6d03ee9d3b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_all_guis.h
@@ -0,0 +1,658 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4/* g_7_guis.h written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
5
6
7#define IEM_GUI_COLNR_WHITE 0
8#define IEM_GUI_COLNR_ML_GREY 1
9#define IEM_GUI_COLNR_D_GREY 2
10#define IEM_GUI_COLNR_L_RED 3
11#define IEM_GUI_COLNR_L_ORANGE 4
12#define IEM_GUI_COLNR_L_YELLOW 5
13#define IEM_GUI_COLNR_L_GREEN 6
14#define IEM_GUI_COLNR_L_CYAN 7
15#define IEM_GUI_COLNR_L_BLUE 8
16#define IEM_GUI_COLNR_L_MAGENTA 9
17
18#define IEM_GUI_COLNR_LL_GREY 10
19#define IEM_GUI_COLNR_M_GREY 11
20#define IEM_GUI_COLNR_DD_GREY 12
21#define IEM_GUI_COLNR_RED 13
22#define IEM_GUI_COLNR_ORANGE 14
23#define IEM_GUI_COLNR_YELLOW 15
24#define IEM_GUI_COLNR_GREEN 16
25#define IEM_GUI_COLNR_CYAN 17
26#define IEM_GUI_COLNR_BLUE 18
27#define IEM_GUI_COLNR_MAGENTA 19
28
29#define IEM_GUI_COLNR_L_GREY 20
30#define IEM_GUI_COLNR_MD_GREY 21
31#define IEM_GUI_COLNR_BLACK 22
32#define IEM_GUI_COLNR_D_RED 23
33#define IEM_GUI_COLNR_D_ORANGE 24
34#define IEM_GUI_COLNR_D_YELLOW 25
35#define IEM_GUI_COLNR_D_GREEN 26
36#define IEM_GUI_COLNR_D_CYAN 27
37#define IEM_GUI_COLNR_D_BLUE 28
38#define IEM_GUI_COLNR_D_MAGENTA 29
39
40#define IEM_GUI_COLOR_SELECTED 255
41#define IEM_GUI_COLOR_NORMAL 0
42
43#define IEM_GUI_MAX_COLOR 30
44
45#define IEM_GUI_DEFAULTSIZE 15
46#define IEM_GUI_MINSIZE 8
47#define IEM_GUI_MAXSIZE 1000
48#define IEM_SL_DEFAULTSIZE 128
49#define IEM_SL_MINSIZE 2
50#define IEM_FONT_MINSIZE 4
51
52#define IEM_BNG_DEFAULTHOLDFLASHTIME 250
53#define IEM_BNG_DEFAULTBREAKFLASHTIME 50
54#define IEM_BNG_MINHOLDFLASHTIME 50
55#define IEM_BNG_MINBREAKFLASHTIME 10
56
57#define IEM_VU_DEFAULTSIZE 3
58#define IEM_VU_LARGESMALL 2
59#define IEM_VU_MINSIZE 2
60#define IEM_VU_MAXSIZE 25
61#define IEM_VU_STEPS 40
62
63#define IEM_VU_MINDB -99.9
64#define IEM_VU_MAXDB 12.0
65#define IEM_VU_OFFSET 100.0
66
67#define IEM_RADIO_MAX 128
68
69#define IEM_SYM_UNIQUE_SND 256
70#define IEM_SYM_UNIQUE_RCV 512
71#define IEM_SYM_UNIQUE_LAB 1024
72#define IEM_SYM_UNIQUE_ALL 1792
73#define IEM_FONT_STYLE_ALL 255
74
75#define IEM_MAX_SYM_LEN 127
76
77#define IEM_GUI_DRAW_MODE_UPDATE 0
78#define IEM_GUI_DRAW_MODE_MOVE 1
79#define IEM_GUI_DRAW_MODE_NEW 2
80#define IEM_GUI_DRAW_MODE_SELECT 3
81#define IEM_GUI_DRAW_MODE_ERASE 4
82#define IEM_GUI_DRAW_MODE_CONFIG 5
83#define IEM_GUI_DRAW_MODE_IO 6
84
85
86#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER)
87#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
88#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
89#define IS_A_DOLLAR(atom,index) ((atom+index)->a_type == A_DOLLAR)
90#define IS_A_DOLLSYM(atom,index) ((atom+index)->a_type == A_DOLLSYM)
91
92#define IEM_FSTYLE_FLAGS_ALL 0x007fffff
93#define IEM_INIT_ARGS_ALL 0x01ffffff
94
95#define IEM_GUI_OLD_SND_FLAG 1
96#define IEM_GUI_OLD_RCV_FLAG 2
97
98#define IEM_GUI_COLOR_EDITED 16711680
99#define IEMGUI_MAX_NUM_LEN 32
100
101typedef struct _iem_fstyle_flags
102{
103 unsigned int x_font_style:6;
104 unsigned int x_rcv_able:1;
105 unsigned int x_snd_able:1;
106 unsigned int x_lab_is_unique:1;
107 unsigned int x_rcv_is_unique:1;
108 unsigned int x_snd_is_unique:1;
109 unsigned int x_lab_arg_tail_len:6;
110 unsigned int x_lab_is_arg_num:6;
111 unsigned int x_shiftdown:1;
112 unsigned int x_selected:1;
113 unsigned int x_finemoved:1;
114 unsigned int x_put_in2out:1;
115 unsigned int x_change:1;
116 unsigned int x_thick:1;
117 unsigned int x_lin0_log1:1;
118 unsigned int x_steady:1;
119 unsigned int dummy:1;
120} t_iem_fstyle_flags;
121
122typedef struct _iem_init_symargs
123{
124 unsigned int x_loadinit:1;
125 unsigned int x_rcv_arg_tail_len:6;
126 unsigned int x_snd_arg_tail_len:6;
127 unsigned int x_rcv_is_arg_num:6;
128 unsigned int x_snd_is_arg_num:6;
129 unsigned int x_scale:1;
130 unsigned int x_flashed:1;
131 unsigned int x_locked:1;
132 unsigned int x_reverse:1; /* bugfix */
133 unsigned int dummy:3;
134} t_iem_init_symargs;
135
136typedef void (*t_iemfunptr)(void *x, t_glist *glist, int mode);
137
138typedef struct _iemgui
139{
140 t_object x_obj;
141 t_glist *x_glist;
142 t_iemfunptr x_draw;
143 int x_h;
144 int x_w;
145 int x_ldx;
146 int x_ldy;
147 char x_font[16];
148 t_iem_fstyle_flags x_fsf;
149 int x_fontsize;
150 t_iem_init_symargs x_isa;
151 int x_fcol;
152 int x_bcol;
153 int x_lcol;
154 t_symbol *x_snd; /* send symbol */
155 t_symbol *x_rcv; /* receive */
156 t_symbol *x_lab; /* label */
157 t_symbol *x_snd_unexpanded; /* same 3, with '$' unexpanded */
158 t_symbol *x_rcv_unexpanded;
159 t_symbol *x_lab_unexpanded;
160 int x_binbufindex; /* where in binbuf to find these */
161 int x_labelbindex; /* where in binbuf to find label */
162} t_iemgui;
163
164typedef struct _iemguidummy
165{
166 t_iemgui x_gui;
167 int x_dum1;
168 int x_dum2;
169 int x_dum3;
170} t_iemguidummy;
171
172typedef struct _bng
173{
174 t_iemgui x_gui;
175 int x_flashed;
176 int x_flashtime_break;
177 int x_flashtime_hold;
178 t_clock *x_clock_hld;
179 t_clock *x_clock_brk;
180 t_clock *x_clock_lck;
181} t_bng;
182
183typedef struct _hslider
184{
185 t_iemgui x_gui;
186 int x_pos;
187 int x_val;
188 int x_center;
189 int x_thick;
190 int x_lin0_log1;
191 int x_steady;
192 double x_min;
193 double x_max;
194 double x_k;
195} t_hslider;
196
197typedef struct _hdial
198{
199 t_iemgui x_gui;
200 int x_on;
201 int x_on_old;
202 int x_change;
203 int x_number;
204 t_atom x_at[2];
205} t_hdial;
206
207typedef struct _toggle
208{
209 t_iemgui x_gui;
210 float x_on;
211 float x_nonzero;
212} t_toggle;
213
214typedef struct _my_canvas
215{
216 t_iemgui x_gui;
217 t_atom x_at[3];
218 int x_vis_w;
219 int x_vis_h;
220} t_my_canvas;
221
222typedef struct _vslider
223{
224 t_iemgui x_gui;
225 int x_pos;
226 int x_val;
227 int x_lin0_log1;
228 int x_steady;
229 double x_min;
230 double x_max;
231 double x_k;
232} t_vslider;
233
234typedef struct _vu
235{
236 t_iemgui x_gui;
237 int x_led_size;
238 int x_peak;
239 int x_rms;
240 float x_fp;
241 float x_fr;
242 int x_scale;
243 void *x_out_rms;
244 void *x_out_peak;
245} t_vu;
246
247typedef struct _my_numbox
248{
249 t_iemgui x_gui;
250 t_clock *x_clock_reset;
251 t_clock *x_clock_wait;
252 double x_val;
253 double x_min;
254 double x_max;
255 double x_k;
256 int x_lin0_log1;
257 char x_buf[IEMGUI_MAX_NUM_LEN];
258 int x_numwidth;
259 int x_log_height;
260} t_my_numbox;
261
262typedef struct _vdial
263{
264 t_iemgui x_gui;
265 int x_on;
266 int x_on_old;
267 int x_change;
268 int x_number;
269 t_atom x_at[2];
270} t_vdial;
271
272#define t_vradio t_vdial
273#define t_hradio t_hdial
274
275extern int sys_noloadbang;
276extern int iemgui_color_hex[];
277extern int iemgui_vu_db2i[];
278extern int iemgui_vu_col[];
279extern char *iemgui_vu_scale_str[];
280
281EXTERN int iemgui_clip_size(int size);
282EXTERN int iemgui_clip_font(int size);
283EXTERN int iemgui_modulo_color(int col);
284EXTERN t_symbol *iemgui_unique2dollarzero(t_symbol *s, int unique_num, int and_unique_flag);
285EXTERN t_symbol *iemgui_sym2dollararg(t_symbol *s, int nth_arg, int tail_len);
286EXTERN t_symbol *iemgui_dollarzero2unique(t_symbol *s, int unique_num);
287EXTERN t_symbol *iemgui_dollararg2sym(t_symbol *s, int nth_arg, int tail_len, int pargc, t_atom *pargv);
288EXTERN int iemgui_is_dollarzero(t_symbol *s);
289EXTERN int iemgui_is_dollararg(t_symbol *s, int *tail_len);
290EXTERN void iemgui_fetch_unique(t_iemgui *iemgui);
291EXTERN void iemgui_fetch_parent_args(t_iemgui *iemgui, int *pargc, t_atom **pargv);
292EXTERN void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui);
293EXTERN void iemgui_all_unique2dollarzero(t_iemgui *iemgui, t_symbol **srlsym);
294EXTERN void iemgui_all_sym2dollararg(t_iemgui *iemgui, t_symbol **srlsym);
295EXTERN void iemgui_all_dollarzero2unique(t_iemgui *iemgui, t_symbol **srlsym);
296EXTERN t_symbol *iemgui_new_dogetname(t_iemgui *iemgui, int indx, t_atom *argv);
297EXTERN void iemgui_new_getnames(t_iemgui *iemgui, int indx, t_atom *argv);
298EXTERN void iemgui_all_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym);
299EXTERN void iemgui_first_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym);
300EXTERN void iemgui_all_col2save(t_iemgui *iemgui, int *bflcol);
301EXTERN void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol);
302EXTERN int iemgui_compatible_col(int i);
303EXTERN void iemgui_all_dollar2raute(t_symbol **srlsym);
304EXTERN void iemgui_all_raute2dollar(t_symbol **srlsym);
305EXTERN void iemgui_send(void *x, t_iemgui *iemgui, t_symbol *s);
306EXTERN void iemgui_receive(void *x, t_iemgui *iemgui, t_symbol *s);
307EXTERN void iemgui_label(void *x, t_iemgui *iemgui, t_symbol *s);
308EXTERN void iemgui_label_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
309EXTERN void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
310EXTERN void iemgui_size(void *x, t_iemgui *iemgui);
311EXTERN void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
312EXTERN void iemgui_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
313EXTERN void iemgui_color(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
314EXTERN int iemgui_list(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
315EXTERN void iemgui_displace(t_gobj *z, t_glist *glist, int dx, int dy);
316EXTERN void iemgui_select(t_gobj *z, t_glist *glist, int selected);
317EXTERN void iemgui_delete(t_gobj *z, t_glist *glist);
318EXTERN void iemgui_vis(t_gobj *z, t_glist *glist, int vis);
319EXTERN void iemgui_save(t_iemgui *iemgui, t_symbol **srl, int *bflcol);
320EXTERN void iemgui_properties(t_iemgui *iemgui, t_symbol **srl);
321EXTERN int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv);
322
323EXTERN int canvas_getdollarzero(void);
324EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
325
326EXTERN void iem_inttosymargs(t_iem_init_symargs *symargp, int n);
327EXTERN int iem_symargstoint(t_iem_init_symargs *symargp);
328EXTERN void iem_inttofstyle(t_iem_fstyle_flags *fstylep, int n);
329EXTERN int iem_fstyletoint(t_iem_fstyle_flags *fstylep);
330/* Copyright (c) 1997-1999 Miller Puckette.
331* For information on usage and redistribution, and for a DISCLAIMER OF ALL
332* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
333/* g_7_guis.h written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
334
335
336#define IEM_GUI_COLNR_WHITE 0
337#define IEM_GUI_COLNR_ML_GREY 1
338#define IEM_GUI_COLNR_D_GREY 2
339#define IEM_GUI_COLNR_L_RED 3
340#define IEM_GUI_COLNR_L_ORANGE 4
341#define IEM_GUI_COLNR_L_YELLOW 5
342#define IEM_GUI_COLNR_L_GREEN 6
343#define IEM_GUI_COLNR_L_CYAN 7
344#define IEM_GUI_COLNR_L_BLUE 8
345#define IEM_GUI_COLNR_L_MAGENTA 9
346
347#define IEM_GUI_COLNR_LL_GREY 10
348#define IEM_GUI_COLNR_M_GREY 11
349#define IEM_GUI_COLNR_DD_GREY 12
350#define IEM_GUI_COLNR_RED 13
351#define IEM_GUI_COLNR_ORANGE 14
352#define IEM_GUI_COLNR_YELLOW 15
353#define IEM_GUI_COLNR_GREEN 16
354#define IEM_GUI_COLNR_CYAN 17
355#define IEM_GUI_COLNR_BLUE 18
356#define IEM_GUI_COLNR_MAGENTA 19
357
358#define IEM_GUI_COLNR_L_GREY 20
359#define IEM_GUI_COLNR_MD_GREY 21
360#define IEM_GUI_COLNR_BLACK 22
361#define IEM_GUI_COLNR_D_RED 23
362#define IEM_GUI_COLNR_D_ORANGE 24
363#define IEM_GUI_COLNR_D_YELLOW 25
364#define IEM_GUI_COLNR_D_GREEN 26
365#define IEM_GUI_COLNR_D_CYAN 27
366#define IEM_GUI_COLNR_D_BLUE 28
367#define IEM_GUI_COLNR_D_MAGENTA 29
368
369#define IEM_GUI_COLOR_SELECTED 255
370#define IEM_GUI_COLOR_NORMAL 0
371
372#define IEM_GUI_MAX_COLOR 30
373
374#define IEM_GUI_DEFAULTSIZE 15
375#define IEM_GUI_MINSIZE 8
376#define IEM_GUI_MAXSIZE 1000
377#define IEM_SL_DEFAULTSIZE 128
378#define IEM_SL_MINSIZE 2
379#define IEM_FONT_MINSIZE 4
380
381#define IEM_BNG_DEFAULTHOLDFLASHTIME 250
382#define IEM_BNG_DEFAULTBREAKFLASHTIME 50
383#define IEM_BNG_MINHOLDFLASHTIME 50
384#define IEM_BNG_MINBREAKFLASHTIME 10
385
386#define IEM_VU_DEFAULTSIZE 3
387#define IEM_VU_LARGESMALL 2
388#define IEM_VU_MINSIZE 2
389#define IEM_VU_MAXSIZE 25
390#define IEM_VU_STEPS 40
391
392#define IEM_VU_MINDB -99.9
393#define IEM_VU_MAXDB 12.0
394#define IEM_VU_OFFSET 100.0
395
396#define IEM_RADIO_MAX 128
397
398#define IEM_SYM_UNIQUE_SND 256
399#define IEM_SYM_UNIQUE_RCV 512
400#define IEM_SYM_UNIQUE_LAB 1024
401#define IEM_SYM_UNIQUE_ALL 1792
402#define IEM_FONT_STYLE_ALL 255
403
404#define IEM_MAX_SYM_LEN 127
405
406#define IEM_GUI_DRAW_MODE_UPDATE 0
407#define IEM_GUI_DRAW_MODE_MOVE 1
408#define IEM_GUI_DRAW_MODE_NEW 2
409#define IEM_GUI_DRAW_MODE_SELECT 3
410#define IEM_GUI_DRAW_MODE_ERASE 4
411#define IEM_GUI_DRAW_MODE_CONFIG 5
412#define IEM_GUI_DRAW_MODE_IO 6
413
414
415#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER)
416#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
417#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
418#define IS_A_DOLLAR(atom,index) ((atom+index)->a_type == A_DOLLAR)
419#define IS_A_DOLLSYM(atom,index) ((atom+index)->a_type == A_DOLLSYM)
420
421#define IEM_FSTYLE_FLAGS_ALL 0x007fffff
422#define IEM_INIT_ARGS_ALL 0x01ffffff
423
424#define IEM_GUI_OLD_SND_FLAG 1
425#define IEM_GUI_OLD_RCV_FLAG 2
426
427#define IEM_GUI_COLOR_EDITED 16711680
428#define IEMGUI_MAX_NUM_LEN 32
429
430typedef struct _iem_fstyle_flags
431{
432 unsigned int x_font_style:6;
433 unsigned int x_rcv_able:1;
434 unsigned int x_snd_able:1;
435 unsigned int x_lab_is_unique:1;
436 unsigned int x_rcv_is_unique:1;
437 unsigned int x_snd_is_unique:1;
438 unsigned int x_lab_arg_tail_len:6;
439 unsigned int x_lab_is_arg_num:6;
440 unsigned int x_shiftdown:1;
441 unsigned int x_selected:1;
442 unsigned int x_finemoved:1;
443 unsigned int x_put_in2out:1;
444 unsigned int x_change:1;
445 unsigned int x_thick:1;
446 unsigned int x_lin0_log1:1;
447 unsigned int x_steady:1;
448 unsigned int dummy:1;
449} t_iem_fstyle_flags;
450
451typedef struct _iem_init_symargs
452{
453 unsigned int x_loadinit:1;
454 unsigned int x_rcv_arg_tail_len:6;
455 unsigned int x_snd_arg_tail_len:6;
456 unsigned int x_rcv_is_arg_num:6;
457 unsigned int x_snd_is_arg_num:6;
458 unsigned int x_scale:1;
459 unsigned int x_flashed:1;
460 unsigned int x_locked:1;
461 unsigned int x_reverse:1; /* bugfix */
462 unsigned int dummy:3;
463} t_iem_init_symargs;
464
465typedef void (*t_iemfunptr)(void *x, t_glist *glist, int mode);
466
467typedef struct _iemgui
468{
469 t_object x_obj;
470 t_glist *x_glist;
471 t_iemfunptr x_draw;
472 int x_h;
473 int x_w;
474 int x_ldx;
475 int x_ldy;
476 char x_font[16];
477 t_iem_fstyle_flags x_fsf;
478 int x_fontsize;
479 t_iem_init_symargs x_isa;
480 int x_fcol;
481 int x_bcol;
482 int x_lcol;
483 t_symbol *x_snd; /* send symbol */
484 t_symbol *x_rcv; /* receive */
485 t_symbol *x_lab; /* label */
486 t_symbol *x_snd_unexpanded; /* same 3, with '$' unexpanded */
487 t_symbol *x_rcv_unexpanded;
488 t_symbol *x_lab_unexpanded;
489 int x_binbufindex; /* where in binbuf to find these */
490 int x_labelbindex; /* where in binbuf to find label */
491} t_iemgui;
492
493typedef struct _iemguidummy
494{
495 t_iemgui x_gui;
496 int x_dum1;
497 int x_dum2;
498 int x_dum3;
499} t_iemguidummy;
500
501typedef struct _bng
502{
503 t_iemgui x_gui;
504 int x_flashed;
505 int x_flashtime_break;
506 int x_flashtime_hold;
507 t_clock *x_clock_hld;
508 t_clock *x_clock_brk;
509 t_clock *x_clock_lck;
510} t_bng;
511
512typedef struct _hslider
513{
514 t_iemgui x_gui;
515 int x_pos;
516 int x_val;
517 int x_center;
518 int x_thick;
519 int x_lin0_log1;
520 int x_steady;
521 double x_min;
522 double x_max;
523 double x_k;
524} t_hslider;
525
526typedef struct _hdial
527{
528 t_iemgui x_gui;
529 int x_on;
530 int x_on_old;
531 int x_change;
532 int x_number;
533 t_atom x_at[2];
534} t_hdial;
535
536typedef struct _toggle
537{
538 t_iemgui x_gui;
539 float x_on;
540 float x_nonzero;
541} t_toggle;
542
543typedef struct _my_canvas
544{
545 t_iemgui x_gui;
546 t_atom x_at[3];
547 int x_vis_w;
548 int x_vis_h;
549} t_my_canvas;
550
551typedef struct _vslider
552{
553 t_iemgui x_gui;
554 int x_pos;
555 int x_val;
556 int x_lin0_log1;
557 int x_steady;
558 double x_min;
559 double x_max;
560 double x_k;
561} t_vslider;
562
563typedef struct _vu
564{
565 t_iemgui x_gui;
566 int x_led_size;
567 int x_peak;
568 int x_rms;
569 float x_fp;
570 float x_fr;
571 int x_scale;
572 void *x_out_rms;
573 void *x_out_peak;
574} t_vu;
575
576typedef struct _my_numbox
577{
578 t_iemgui x_gui;
579 t_clock *x_clock_reset;
580 t_clock *x_clock_wait;
581 double x_val;
582 double x_min;
583 double x_max;
584 double x_k;
585 int x_lin0_log1;
586 char x_buf[IEMGUI_MAX_NUM_LEN];
587 int x_numwidth;
588 int x_log_height;
589} t_my_numbox;
590
591typedef struct _vdial
592{
593 t_iemgui x_gui;
594 int x_on;
595 int x_on_old;
596 int x_change;
597 int x_number;
598 t_atom x_at[2];
599} t_vdial;
600
601#define t_vradio t_vdial
602#define t_hradio t_hdial
603
604extern int sys_noloadbang;
605extern int iemgui_color_hex[];
606extern int iemgui_vu_db2i[];
607extern int iemgui_vu_col[];
608extern char *iemgui_vu_scale_str[];
609
610EXTERN int iemgui_clip_size(int size);
611EXTERN int iemgui_clip_font(int size);
612EXTERN int iemgui_modulo_color(int col);
613EXTERN t_symbol *iemgui_unique2dollarzero(t_symbol *s, int unique_num, int and_unique_flag);
614EXTERN t_symbol *iemgui_sym2dollararg(t_symbol *s, int nth_arg, int tail_len);
615EXTERN t_symbol *iemgui_dollarzero2unique(t_symbol *s, int unique_num);
616EXTERN t_symbol *iemgui_dollararg2sym(t_symbol *s, int nth_arg, int tail_len, int pargc, t_atom *pargv);
617EXTERN int iemgui_is_dollarzero(t_symbol *s);
618EXTERN int iemgui_is_dollararg(t_symbol *s, int *tail_len);
619EXTERN void iemgui_fetch_unique(t_iemgui *iemgui);
620EXTERN void iemgui_fetch_parent_args(t_iemgui *iemgui, int *pargc, t_atom **pargv);
621EXTERN void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui);
622EXTERN void iemgui_all_unique2dollarzero(t_iemgui *iemgui, t_symbol **srlsym);
623EXTERN void iemgui_all_sym2dollararg(t_iemgui *iemgui, t_symbol **srlsym);
624EXTERN void iemgui_all_dollarzero2unique(t_iemgui *iemgui, t_symbol **srlsym);
625EXTERN t_symbol *iemgui_new_dogetname(t_iemgui *iemgui, int indx, t_atom *argv);
626EXTERN void iemgui_new_getnames(t_iemgui *iemgui, int indx, t_atom *argv);
627EXTERN void iemgui_all_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym);
628EXTERN void iemgui_first_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym);
629EXTERN void iemgui_all_col2save(t_iemgui *iemgui, int *bflcol);
630EXTERN void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol);
631EXTERN int iemgui_compatible_col(int i);
632EXTERN void iemgui_all_dollar2raute(t_symbol **srlsym);
633EXTERN void iemgui_all_raute2dollar(t_symbol **srlsym);
634EXTERN void iemgui_send(void *x, t_iemgui *iemgui, t_symbol *s);
635EXTERN void iemgui_receive(void *x, t_iemgui *iemgui, t_symbol *s);
636EXTERN void iemgui_label(void *x, t_iemgui *iemgui, t_symbol *s);
637EXTERN void iemgui_label_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
638EXTERN void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
639EXTERN void iemgui_size(void *x, t_iemgui *iemgui);
640EXTERN void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
641EXTERN void iemgui_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
642EXTERN void iemgui_color(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
643EXTERN int iemgui_list(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
644EXTERN void iemgui_displace(t_gobj *z, t_glist *glist, int dx, int dy);
645EXTERN void iemgui_select(t_gobj *z, t_glist *glist, int selected);
646EXTERN void iemgui_delete(t_gobj *z, t_glist *glist);
647EXTERN void iemgui_vis(t_gobj *z, t_glist *glist, int vis);
648EXTERN void iemgui_save(t_iemgui *iemgui, t_symbol **srl, int *bflcol);
649EXTERN void iemgui_properties(t_iemgui *iemgui, t_symbol **srl);
650EXTERN int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv);
651
652EXTERN int canvas_getdollarzero(void);
653EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
654
655EXTERN void iem_inttosymargs(t_iem_init_symargs *symargp, int n);
656EXTERN int iem_symargstoint(t_iem_init_symargs *symargp);
657EXTERN void iem_inttofstyle(t_iem_fstyle_flags *fstylep, int n);
658EXTERN int iem_fstyletoint(t_iem_fstyle_flags *fstylep);
diff --git a/apps/plugins/pdbox/PDa/src/g_array.c b/apps/plugins/pdbox/PDa/src/g_array.c
new file mode 100644
index 0000000000..f259ac8dcb
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_array.c
@@ -0,0 +1,2734 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include <stdlib.h>
6#include <string.h>
7#include <stdio.h> /* for read/write to files */
8#include "m_pd.h"
9#include "g_canvas.h"
10#include <math.h>
11
12/* see also the "plot" object in g_scalar.c which deals with graphing
13arrays which are fields in scalars. Someday we should unify the
14two, but how? */
15
16 /* aux routine to bash leading '#' to '$' for dialogs in u_main.tk
17 which can't send symbols starting with '$' (because the Pd message
18 interpreter would change them!) */
19
20static t_symbol *sharptodollar(t_symbol *s)
21{
22 if (*s->s_name == '#')
23 {
24 char buf[MAXPDSTRING];
25 strncpy(buf, s->s_name, MAXPDSTRING);
26 buf[MAXPDSTRING-1] = 0;
27 buf[0] = '$';
28 return (gensym(buf));
29 }
30 else return (s);
31}
32
33/* --------- "pure" arrays with scalars for elements. --------------- */
34
35/* Pure arrays have no a priori graphical capabilities.
36They are instantiated by "garrays" below or can be elements of other
37scalars (g_scalar.c); their graphical behavior is defined accordingly. */
38
39t_array *array_new(t_symbol *templatesym, t_gpointer *parent)
40{
41 t_array *x = (t_array *)getbytes(sizeof (*x));
42 t_template *template;
43 t_gpointer *gp;
44 template = template_findbyname(templatesym);
45 x->a_templatesym = templatesym;
46 x->a_n = 1;
47 x->a_elemsize = sizeof(t_word) * template->t_n;
48 x->a_vec = (char *)getbytes(x->a_elemsize);
49 /* note here we blithely copy a gpointer instead of "setting" a
50 new one; this gpointer isn't accounted for and needn't be since
51 we'll be deleted before the thing pointed to gets deleted anyway;
52 see array_free. */
53 x->a_gp = *parent;
54 x->a_stub = gstub_new(0, x);
55 word_init((t_word *)(x->a_vec), template, parent);
56 return (x);
57}
58
59void array_resize(t_array *x, t_template *template, int n)
60{
61 int elemsize, oldn;
62 t_gpointer *gp;
63
64 if (n < 1)
65 n = 1;
66 oldn = x->a_n;
67 elemsize = sizeof(t_word) * template->t_n;
68
69 x->a_vec = (char *)resizebytes(x->a_vec, oldn * elemsize,
70 n * elemsize);
71 x->a_n = n;
72 if (n > oldn)
73 {
74 char *cp = x->a_vec + elemsize * oldn;
75 int i = n - oldn;
76 for (; i--; cp += elemsize)
77 {
78 t_word *wp = (t_word *)cp;
79 word_init(wp, template, &x->a_gp);
80 }
81 }
82}
83
84void word_free(t_word *wp, t_template *template);
85
86void array_free(t_array *x)
87{
88 int i;
89 t_template *scalartemplate = template_findbyname(x->a_templatesym);
90 /* we don't unset our gpointer here since it was never "set." */
91 /* gpointer_unset(&x->a_gp); */
92 gstub_cutoff(x->a_stub);
93 for (i = 0; i < x->a_n; i++)
94 {
95 t_word *wp = (t_word *)(x->a_vec + x->a_elemsize * i);
96 word_free(wp, scalartemplate);
97 }
98 freebytes(x->a_vec, x->a_elemsize * x->a_n);
99 freebytes(x, sizeof *x);
100}
101
102/* --------------------- graphical arrays (garrays) ------------------- */
103
104t_class *garray_class;
105static int gcount = 0;
106
107struct _garray
108{
109 t_gobj x_gobj;
110 t_glist *x_glist;
111 t_array x_array; /* actual array; note only 4 fields used as below */
112 t_symbol *x_name;
113 t_symbol *x_realname; /* name with "$" expanded */
114 t_float x_firstx; /* X value of first item */
115 t_float x_xinc; /* X increment */
116 char x_usedindsp; /* true if some DSP routine is using this */
117 char x_saveit; /* true if we should save this with parent */
118};
119
120 /* macros to get into the "array" structure */
121#define x_n x_array.a_n
122#define x_elemsize x_array.a_elemsize
123#define x_vec x_array.a_vec
124#define x_templatesym x_array.a_templatesym
125
126t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *templatesym,
127 t_floatarg f, t_floatarg saveit)
128{
129 int n = f, i;
130 int zz, nwords;
131 t_garray *x;
132 t_pd *x2;
133 t_template *template;
134 char *str;
135 if (s == &s_)
136 {
137 char buf[40];
138 sprintf(buf, "array%d", ++gcount);
139 s = gensym(buf);
140 templatesym = &s_float;
141 n = 100;
142 }
143 else if (!strncmp((str = s->s_name), "array", 5)
144 && (zz = atoi(str + 5)) > gcount) gcount = zz;
145 template = template_findbyname(templatesym);
146 if (!template)
147 {
148 error("array: couldn't find template %s", templatesym->s_name);
149 return (0);
150 }
151 nwords = template->t_n;
152 for (i = 0; i < nwords; i++)
153 {
154 /* we can't have array or list elements yet because what scalar
155 can act as their "parent"??? */
156 if (template->t_vec[i].ds_type == DT_ARRAY
157 || template->t_vec[i].ds_type == DT_LIST)
158 {
159 error("array: template %s can't have sublists or arrays",
160 templatesym->s_name);
161 return (0);
162 }
163 }
164 x = (t_garray *)pd_new(garray_class);
165
166 if (n <= 0) n = 100;
167 x->x_n = n;
168 x->x_elemsize = nwords * sizeof(t_word);
169 x->x_vec = getbytes(x->x_n * x->x_elemsize);
170 memset(x->x_vec, 0, x->x_n * x->x_elemsize);
171 /* LATER should check that malloc */
172 x->x_name = s;
173 x->x_realname = canvas_realizedollar(gl, s);
174 pd_bind(&x->x_gobj.g_pd, x->x_realname);
175 x->x_templatesym = templatesym;
176 x->x_firstx = 0;
177 x->x_xinc = 1; /* LATER make methods to set this... */
178 glist_add(gl, &x->x_gobj);
179 x->x_glist = gl;
180 x->x_usedindsp = 0;
181 x->x_saveit = (saveit != 0);
182 if (x2 = pd_findbyclass(gensym("#A"), garray_class))
183 pd_unbind(x2, gensym("#A"));
184
185 pd_bind(&x->x_gobj.g_pd, gensym("#A"));
186
187 return (x);
188}
189
190 /* called from array menu item to create a new one */
191void canvas_menuarray(t_glist *canvas)
192{
193 t_glist *x = (t_glist *)canvas;
194 char cmdbuf[200];
195 sprintf(cmdbuf, "pdtk_array_dialog %%s array%d 100 1 1\n",
196 ++gcount);
197 gfxstub_new(&x->gl_pd, x, cmdbuf);
198}
199
200 /* called from graph_dialog to set properties */
201void garray_properties(t_garray *x)
202{
203 char cmdbuf[200];
204 gfxstub_deleteforkey(x);
205 /* create dialog window. LATER fix this to escape '$'
206 properly; right now we just detect a leading '$' and escape
207 it. There should be a systematic way of doing this. */
208 if (x->x_name->s_name[0] == '$')
209 sprintf(cmdbuf, "pdtk_array_dialog %%s \\%s %d %d 0\n",
210 x->x_name->s_name, x->x_n, x->x_saveit);
211 else sprintf(cmdbuf, "pdtk_array_dialog %%s %s %d %d 0\n",
212 x->x_name->s_name, x->x_n, x->x_saveit);
213 gfxstub_new(&x->x_gobj.g_pd, x, cmdbuf);
214}
215
216 /* this is called back from the dialog window to create a garray.
217 The otherflag requests that we find an existing graph to put it in. */
218void glist_arraydialog(t_glist *parent, t_symbol *name, t_floatarg size,
219 t_floatarg saveit, t_floatarg otherflag)
220{
221 t_glist *gl;
222 t_garray *a;
223 if (size < 1)
224 size = 1;
225 if (otherflag == 0 || (!(gl = glist_findgraph(parent))))
226 gl = glist_addglist(parent, &s_, 0, 1,
227 (size > 1 ? size-1 : size), -1, 0, 0, 0, 0);
228 a = graph_array(gl, sharptodollar(name), &s_float, size, saveit);
229}
230
231 /* this is called from the properties dialog window for an existing array */
232void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize,
233 t_floatarg saveit, t_floatarg deleteit)
234{
235 if (deleteit != 0)
236 {
237 glist_delete(x->x_glist, &x->x_gobj);
238 }
239 else
240 {
241 int size;
242 t_symbol *argname = sharptodollar(name);
243 if (argname != x->x_name)
244 {
245 x->x_name = argname;
246 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
247 x->x_realname = canvas_realizedollar(x->x_glist, argname);
248 pd_bind(&x->x_gobj.g_pd, x->x_realname);
249 }
250 size = fsize;
251 if (size < 1)
252 size = 1;
253 if (size != x->x_n)
254 garray_resize(x, size);
255 garray_setsaveit(x, (saveit != 0));
256 garray_redraw(x);
257 }
258}
259
260static void garray_free(t_garray *x)
261{
262 t_pd *x2;
263 gfxstub_deleteforkey(x);
264 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
265 /* LATER find a way to get #A unbound earlier (at end of load?) */
266 while (x2 = pd_findbyclass(gensym("#A"), garray_class))
267 pd_unbind(x2, gensym("#A"));
268 freebytes(x->x_vec, x->x_n * x->x_elemsize);
269}
270
271/* ------------- code used by both array and plot widget functions ---- */
272
273 /* routine to get screen coordinates of a point in an array */
274void array_getcoordinate(t_glist *glist,
275 char *elem, int xonset, int yonset, int wonset, int indx,
276 float basex, float basey, float xinc,
277 float *xp, float *yp, float *wp)
278{
279 float xval, yval, ypix, wpix;
280 if (xonset >= 0)
281 xval = fixtof(*(t_sample *)(elem + xonset));
282 else xval = indx * xinc;
283 if (yonset >= 0)
284 yval = fixtof(*(t_sample *)(elem + yonset));
285 else yval = 0;
286 ypix = glist_ytopixels(glist, basey + yval);
287 if (wonset >= 0)
288 {
289 /* found "w" field which controls linewidth. */
290 float wval = *(float *)(elem + wonset);
291 wpix = glist_ytopixels(glist, basey + yval + wval) - ypix;
292 if (wpix < 0)
293 wpix = -wpix;
294 }
295 else wpix = 1;
296 *xp = glist_xtopixels(glist, basex + xval);
297 *yp = ypix;
298 *wp = wpix;
299}
300
301static float array_motion_xcumulative;
302static float array_motion_ycumulative;
303static t_symbol *array_motion_xfield;
304static t_symbol *array_motion_yfield;
305static t_glist *array_motion_glist;
306static t_gobj *array_motion_gobj;
307static t_word *array_motion_wp;
308static t_template *array_motion_template;
309static int array_motion_npoints;
310static int array_motion_elemsize;
311static int array_motion_altkey;
312static float array_motion_initx;
313static float array_motion_xperpix;
314static float array_motion_yperpix;
315static int array_motion_lastx;
316static int array_motion_fatten;
317
318 /* LATER protect against the template changing or the scalar disappearing
319 probably by attaching a gpointer here ... */
320
321static void array_motion(void *z, t_floatarg dx, t_floatarg dy)
322{
323 array_motion_xcumulative += dx * array_motion_xperpix;
324 array_motion_ycumulative += dy * array_motion_yperpix;
325 if (*array_motion_xfield->s_name)
326 {
327 /* it's an x, y plot; can drag many points at once */
328 int i;
329 char *charword = (char *)array_motion_wp;
330 for (i = 0; i < array_motion_npoints; i++)
331 {
332 t_word *thisword = (t_word *)(charword + i * array_motion_elemsize);
333 if (*array_motion_xfield->s_name)
334 {
335 float xwas = template_getfloat(array_motion_template,
336 array_motion_xfield, thisword, 1);
337 template_setfloat(array_motion_template,
338 array_motion_xfield, thisword, xwas + dx, 1);
339 }
340 if (*array_motion_yfield->s_name)
341 {
342 float ywas = template_getfloat(array_motion_template,
343 array_motion_yfield, thisword, 1);
344 if (array_motion_fatten)
345 {
346 if (i == 0)
347 {
348 float newy = ywas + dy * array_motion_yperpix;
349 if (newy < 0)
350 newy = 0;
351 template_setfloat(array_motion_template,
352 array_motion_yfield, thisword, newy, 1);
353 }
354 }
355 else
356 {
357 template_setfloat(array_motion_template,
358 array_motion_yfield, thisword,
359 ywas + dy * array_motion_yperpix, 1);
360 }
361 }
362 }
363 }
364 else
365 {
366 /* a y-only plot. */
367 int thisx = array_motion_initx +
368 array_motion_xcumulative, x2;
369 int increment, i, nchange;
370 char *charword = (char *)array_motion_wp;
371 float newy = array_motion_ycumulative,
372 oldy = template_getfloat(
373 array_motion_template, array_motion_yfield,
374 (t_word *)(charword + array_motion_elemsize * array_motion_lastx), 1);
375 float ydiff = newy - oldy;
376 if (thisx < 0) thisx = 0;
377 else if (thisx >= array_motion_npoints)
378 thisx = array_motion_npoints - 1;
379 increment = (thisx > array_motion_lastx ? -1 : 1);
380 nchange = 1 + increment * (array_motion_lastx - thisx);
381
382 for (i = 0, x2 = thisx; i < nchange; i++, x2 += increment)
383 {
384 template_setfloat(array_motion_template,
385 array_motion_yfield,
386 (t_word *)(charword + array_motion_elemsize * x2),
387 newy, 1);
388 if (nchange > 1)
389 newy -= ydiff * (1./(nchange - 1));
390 }
391 array_motion_lastx = thisx;
392 }
393 glist_redrawitem(array_motion_glist, array_motion_gobj);
394}
395
396int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
397 t_symbol *elemtemplatesym,
398 float linewidth, float xloc, float xinc, float yloc,
399 int xpix, int ypix, int shift, int alt, int dbl, int doit)
400{
401 t_canvas *elemtemplatecanvas;
402 t_template *elemtemplate;
403 int elemsize, yonset, wonset, xonset, i;
404
405 if (!array_getfields(elemtemplatesym, &elemtemplatecanvas,
406 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
407 {
408 float best = 100;
409 int incr;
410 /* if it has more than 2000 points, just check 300 of them. */
411 if (array->a_n < 2000)
412 incr = 1;
413 else incr = array->a_n / 300;
414 for (i = 0; i < array->a_n; i += incr)
415 {
416 float pxpix, pypix, pwpix, dx, dy;
417 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
418 xonset, yonset, wonset, i, xloc, yloc, xinc,
419 &pxpix, &pypix, &pwpix);
420 if (pwpix < 4)
421 pwpix = 4;
422 dx = pxpix - xpix;
423 if (dx < 0) dx = -dx;
424 if (dx > 8)
425 continue;
426 dy = pypix - ypix;
427 if (dy < 0) dy = -dy;
428 if (dx + dy < best)
429 best = dx + dy;
430 if (wonset >= 0)
431 {
432 dy = (pypix + pwpix) - ypix;
433 if (dy < 0) dy = -dy;
434 if (dx + dy < best)
435 best = dx + dy;
436 dy = (pypix - pwpix) - ypix;
437 if (dy < 0) dy = -dy;
438 if (dx + dy < best)
439 best = dx + dy;
440 }
441 }
442 if (best > 8)
443 return (0);
444 best += 0.001; /* add truncation error margin */
445 for (i = 0; i < array->a_n; i += incr)
446 {
447 float pxpix, pypix, pwpix, dx, dy, dy2, dy3;
448 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
449 xonset, yonset, wonset, i, xloc, yloc, xinc,
450 &pxpix, &pypix, &pwpix);
451 if (pwpix < 4)
452 pwpix = 4;
453 dx = pxpix - xpix;
454 if (dx < 0) dx = -dx;
455 dy = pypix - ypix;
456 if (dy < 0) dy = -dy;
457 if (wonset >= 0)
458 {
459 dy2 = (pypix + pwpix) - ypix;
460 if (dy2 < 0) dy2 = -dy2;
461 dy3 = (pypix - pwpix) - ypix;
462 if (dy3 < 0) dy3 = -dy3;
463 if (yonset <= 0)
464 dy = 100;
465 }
466 else dy2 = dy3 = 100;
467 if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best)
468 {
469 if (dy < dy2 && dy < dy3)
470 array_motion_fatten = 0;
471 else if (dy2 < dy3)
472 array_motion_fatten = -1;
473 else array_motion_fatten = 1;
474 if (doit)
475 {
476 char *elem = (char *)array->a_vec;
477 array_motion_elemsize = elemsize;
478 array_motion_glist = glist;
479 array_motion_gobj = gobj;
480 array_motion_template = elemtemplate;
481 array_motion_xperpix = glist_dpixtodx(glist, 1);
482 array_motion_yperpix = glist_dpixtody(glist, 1);
483 if (alt && xpix < pxpix) /* delete a point */
484 {
485 if (array->a_n <= 1)
486 return (0);
487 memmove((char *)(array->a_vec) + elemsize * i,
488 (char *)(array->a_vec) + elemsize * (i+1),
489 (array->a_n - 1 - i) * elemsize);
490 array_resize(array, elemtemplate, array->a_n - 1);
491 glist_redrawitem(array_motion_glist, array_motion_gobj);
492 return (0);
493 }
494 else if (alt)
495 {
496 /* add a point (after the clicked-on one) */
497 array_resize(array, elemtemplate, array->a_n + 1);
498 elem = (char *)array->a_vec;
499 memmove(elem + elemsize * (i+1),
500 elem + elemsize * i,
501 (array->a_n - i - 1) * elemsize);
502 i++;
503 }
504 if (xonset >= 0)
505 {
506 array_motion_xfield = gensym("x");
507 array_motion_xcumulative =
508 *(float *)((elem + elemsize * i) + xonset);
509 array_motion_wp = (t_word *)(elem + i * elemsize);
510 array_motion_npoints = array->a_n - i;
511 }
512 else
513 {
514 array_motion_xfield = &s_;
515 array_motion_xcumulative = 0;
516 array_motion_wp = (t_word *)elem;
517 array_motion_npoints = array->a_n;
518
519 array_motion_initx = i;
520 array_motion_lastx = i;
521 array_motion_xperpix *= (xinc == 0 ? 1 : 1./xinc);
522 }
523 if (array_motion_fatten)
524 {
525 array_motion_yfield = gensym("w");
526 array_motion_ycumulative =
527 *(float *)((elem + elemsize * i) + wonset);
528 array_motion_yperpix *= array_motion_fatten;
529 }
530 else if (yonset >= 0)
531 {
532 array_motion_yfield = gensym("y");
533 array_motion_ycumulative =
534 *(float *)((elem + elemsize * i) + yonset);
535 }
536 else
537 {
538 array_motion_yfield = &s_;
539 array_motion_ycumulative = 0;
540 }
541 glist_grab(glist, 0, array_motion, 0, xpix, ypix);
542 }
543 if (alt)
544 {
545 if (xpix < pxpix)
546 return (CURSOR_EDITMODE_DISCONNECT);
547 else return (CURSOR_RUNMODE_ADDPOINT);
548 }
549 else return (array_motion_fatten ?
550 CURSOR_RUNMODE_THICKEN : CURSOR_RUNMODE_CLICKME);
551 }
552 }
553 }
554 return (0);
555}
556
557/* -------------------- widget behavior for garray ------------ */
558
559static void garray_getrect(t_gobj *z, t_glist *glist,
560 int *xp1, int *yp1, int *xp2, int *yp2)
561{
562 t_garray *x = (t_garray *)z;
563 float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
564 t_canvas *elemtemplatecanvas;
565 t_template *elemtemplate;
566 int elemsize, yonset, wonset, xonset, i;
567
568 if (!array_getfields(x->x_templatesym, &elemtemplatecanvas,
569 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
570 {
571 int incr;
572 /* if it has more than 2000 points, just check 300 of them. */
573 if (x->x_array.a_n < 2000)
574 incr = 1;
575 else incr = x->x_array.a_n / 300;
576 for (i = 0; i < x->x_array.a_n; i += incr)
577 {
578 float pxpix, pypix, pwpix, dx, dy;
579 array_getcoordinate(glist, (char *)(x->x_array.a_vec) +
580 i * elemsize,
581 xonset, yonset, wonset, i, 0, 0, 1,
582 &pxpix, &pypix, &pwpix);
583 if (pwpix < 2)
584 pwpix = 2;
585 if (pxpix < x1)
586 x1 = pxpix;
587 if (pxpix > x2)
588 x2 = pxpix;
589 if (pypix - pwpix < y1)
590 y1 = pypix - pwpix;
591 if (pypix + pwpix > y2)
592 y2 = pypix + pwpix;
593 }
594 }
595 *xp1 = x1;
596 *yp1 = y1;
597 *xp2 = x2;
598 *yp2 = y2;
599}
600
601static void garray_displace(t_gobj *z, t_glist *glist, int dx, int dy)
602{
603 /* refuse */
604}
605
606static void garray_select(t_gobj *z, t_glist *glist, int state)
607{
608 t_garray *x = (t_garray *)z;
609 /* fill in later */
610}
611
612static void garray_activate(t_gobj *z, t_glist *glist, int state)
613{
614}
615
616static void garray_delete(t_gobj *z, t_glist *glist)
617{
618 /* nothing to do */
619}
620
621static void garray_vis(t_gobj *z, t_glist *glist, int vis)
622{
623 t_garray *x = (t_garray *)z;
624 if (vis)
625 {
626 int i, xonset, yonset, type;
627 t_symbol *arraytype;
628 t_template *template = template_findbyname(x->x_templatesym);
629 if (!template)
630 return;
631 if (!template_find_field(template, gensym("y"), &yonset, &type,
632 &arraytype) || type != DT_FLOAT)
633 {
634 error("%s: needs floating-point 'y' field",
635 x->x_templatesym->s_name);
636 sys_vgui(".x%x.c create text 50 50 -text foo\
637 -tags .x%x.a%x\n",
638 glist_getcanvas(glist), glist_getcanvas(glist), x);
639 }
640 else if (!template_find_field(template, gensym("x"), &xonset, &type,
641 &arraytype) || type != DT_FLOAT)
642 {
643 float firsty, xcum = x->x_firstx;
644 int lastpixel = -1, ndrawn = 0;
645 float yval = 0, xpix;
646 int ixpix = 0;
647 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
648 for (i = 0; i < x->x_n; i++)
649 {
650 yval = fixtof(*(t_sample *)(x->x_vec +
651 template->t_n * i * sizeof (t_word) + yonset));
652 xpix = glist_xtopixels(glist, xcum);
653 ixpix = xpix + 0.5;
654 if (ixpix != lastpixel)
655 {
656 sys_vgui("%d %f \\\n", ixpix,
657 glist_ytopixels(glist, yval));
658 ndrawn++;
659 }
660 lastpixel = ixpix;
661 if (ndrawn >= 1000) break;
662 xcum += x->x_xinc;
663 }
664 /* TK will complain if there aren't at least 2 points... */
665 if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
666 else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix,
667 glist_ytopixels(glist, yval));
668 sys_vgui("-tags .x%x.a%x\n", glist_getcanvas(glist), x);
669 firsty = fixtof(*(t_sample *)(x->x_vec + yonset));
670 sys_vgui(".x%x.c create text %f %f -text {%s} -anchor e\
671 -font -*-courier-bold--normal--%d-* -tags .x%x.a%x\n",
672 glist_getcanvas(glist),
673 glist_xtopixels(glist, x->x_firstx) - 5.,
674 glist_ytopixels(glist, firsty),
675 x->x_name->s_name, glist_getfont(glist),
676 glist_getcanvas(glist), x);
677 }
678 else
679 {
680 post("x, y arrays not yet supported");
681 }
682 }
683 else
684 {
685 sys_vgui(".x%x.c delete .x%x.a%x\n",
686 glist_getcanvas(glist), glist_getcanvas(glist), x);
687 }
688}
689
690static int garray_click(t_gobj *z, struct _glist *glist,
691 int xpix, int ypix, int shift, int alt, int dbl, int doit)
692{
693 t_garray *x = (t_garray *)z;
694 return (array_doclick(&x->x_array, glist, z, x->x_templatesym, 1, 0, 1, 0,
695 xpix, ypix, shift, alt, dbl, doit));
696}
697
698#define ARRAYWRITECHUNKSIZE 1000
699
700static void garray_save(t_gobj *z, t_binbuf *b)
701{
702 t_garray *x = (t_garray *)z;
703 binbuf_addv(b, "sssisi;", gensym("#X"), gensym("array"),
704 x->x_name, x->x_n, x->x_templatesym, x->x_saveit);
705 fprintf(stderr,"array save\n");
706 if (x->x_saveit)
707 {
708 int n = x->x_n, n2 = 0;
709 if (x->x_templatesym != &s_float)
710 {
711 pd_error(x, "sorry, you can only save 'float' arrays now");
712 return;
713 }
714 if (n > 200000)
715 post("warning: I'm saving an array with %d points!\n", n);
716 while (n2 < n)
717 {
718 int chunk = n - n2, i;
719 if (chunk > ARRAYWRITECHUNKSIZE)
720 chunk = ARRAYWRITECHUNKSIZE;
721 binbuf_addv(b, "si", gensym("#A"), n2);
722 for (i = 0; i < chunk; i++)
723 binbuf_addv(b, "f", fixtof(((t_sample *)(x->x_vec))[n2+i]));
724 binbuf_addv(b, ";");
725 n2 += chunk;
726 }
727 }
728}
729
730t_widgetbehavior garray_widgetbehavior =
731{
732 garray_getrect,
733 garray_displace,
734 garray_select,
735 garray_activate,
736 garray_delete,
737 garray_vis,
738 garray_click
739};
740
741/* ----------------------- public functions -------------------- */
742
743void garray_usedindsp(t_garray *x)
744{
745 x->x_usedindsp = 1;
746}
747
748void garray_redraw(t_garray *x)
749{
750 if (glist_isvisible(x->x_glist))
751 {
752 garray_vis(&x->x_gobj, x->x_glist, 0);
753 garray_vis(&x->x_gobj, x->x_glist, 1);
754 }
755}
756
757 /* This functiopn gets the template of an array; if we can't figure
758 out what template an array's elements belong to we're in grave trouble
759 when it's time to free or resize it. */
760t_template *garray_template(t_garray *x)
761{
762 t_template *template = template_findbyname(x->x_templatesym);
763 if (!template)
764 bug("garray_template");
765 return (template);
766}
767
768int garray_npoints(t_garray *x) /* get the length */
769{
770 return (x->x_n);
771}
772
773char *garray_vec(t_garray *x) /* get the contents */
774{
775 return ((char *)(x->x_vec));
776}
777
778 /* routine that checks if we're just an array of floats and if
779 so returns the goods */
780
781int garray_getfloatarray(t_garray *x, int *size, t_sample **vec)
782{
783 t_template *template = garray_template(x);
784 int yonset, type;
785 t_symbol *arraytype;
786 if (!template_find_field(template, gensym("y"), &yonset,
787 &type, &arraytype) || type != DT_FLOAT)
788 error("%s: needs floating-point 'y' field",
789 x->x_templatesym->s_name);
790 else if (template->t_n != 1)
791 error("%s: has more than one field", x->x_templatesym->s_name);
792 else
793 {
794 *size = garray_npoints(x);
795 *vec = (t_sample *)garray_vec(x);
796 return (1);
797 }
798 return (0);
799}
800
801 /* get any floating-point field of any element of an array */
802float garray_get(t_garray *x, t_symbol *s, t_int indx)
803{
804 t_template *template = garray_template(x);
805 int yonset, type;
806 t_symbol *arraytype;
807 if (!template_find_field(template, gensym("y"), &yonset,
808 &type, &arraytype) || type != DT_FLOAT)
809 {
810 error("%s: needs floating-point '%s' field", x->x_templatesym->s_name,
811 s->s_name);
812 return (0);
813 }
814 if (indx < 0) indx = 0;
815 else if (indx >= x->x_n) indx = x->x_n - 1;
816 return (*(float *)((x->x_vec + sizeof(t_word) * indx) + yonset));
817}
818
819 /* set the "saveit" flag */
820void garray_setsaveit(t_garray *x, int saveit)
821{
822 if (x->x_saveit && !saveit)
823 post("warning: array %s: clearing save-in-patch flag",
824 x->x_name->s_name);
825 x->x_saveit = saveit;
826}
827
828/*------------------- Pd messages ------------------------ */
829static void garray_const(t_garray *x, t_floatarg g)
830{
831 t_template *template = garray_template(x);
832 int yonset, type, i;
833 t_symbol *arraytype;
834 if (!template_find_field(template, gensym("y"), &yonset,
835 &type, &arraytype) || type != DT_FLOAT)
836 error("%s: needs floating-point 'y' field",
837 x->x_templatesym->s_name);
838 else for (i = 0; i < x->x_n; i++)
839 *(float *)(((char *)x->x_vec + sizeof(t_word) * i) + yonset) = g;
840 garray_redraw(x);
841}
842
843 /* sum of Fourier components; called from routines below */
844static void garray_dofo(t_garray *x, int npoints, float dcval,
845 int nsin, t_float *vsin, int sineflag)
846{
847 t_template *template = garray_template(x);
848 int yonset, type, i, j;
849 t_symbol *arraytype;
850 double phase, phaseincr, fj;
851 if (npoints == 0)
852 npoints = 512; /* dunno what a good default would be... */
853 if (npoints != (1 << ilog2(npoints)))
854 post("%s: rounnding to %d points", x->x_templatesym->s_name,
855 (npoints = (1<<ilog2(npoints))));
856 garray_resize(x, npoints + 3);
857 phaseincr = 2. * 3.14159 / npoints;
858 if (!template_find_field(template, gensym("y"), &yonset,
859 &type, &arraytype) || type != DT_FLOAT)
860 {
861 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
862 return;
863 }
864 for (i = 0, phase = -phaseincr; i < x->x_n; i++, phase += phaseincr )
865 {
866 double sum = dcval;
867 if (sineflag)
868 for (j = 0, fj = phase; j < nsin; j++, fj += phase)
869 sum += vsin[j] * sin(fj);
870 else
871 for (j = 0, fj = 0; j < nsin; j++, fj += phase)
872 sum += vsin[j] * cos(fj);
873 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = sum;
874 }
875 garray_redraw(x);
876}
877
878static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
879{
880 t_template *template = garray_template(x);
881
882 t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
883 int npoints, i;
884 if (argc < 2)
885 {
886 error("sinesum: %s: need number of points and partial strengths",
887 x->x_templatesym->s_name);
888 return;
889 }
890
891 npoints = atom_getfloatarg(0, argc, argv);
892 argv++, argc--;
893
894 svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
895 if (!svec) return;
896
897 for (i = 0; i < argc; i++)
898 svec[i] = atom_getfloatarg(i, argc, argv);
899 garray_dofo(x, npoints, 0, argc, svec, 1);
900 t_freebytes(svec, sizeof(t_float) * argc);
901}
902
903static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
904{
905 t_template *template = garray_template(x);
906
907 t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
908 int npoints, i;
909 if (argc < 2)
910 {
911 error("sinesum: %s: need number of points and partial strengths",
912 x->x_templatesym->s_name);
913 return;
914 }
915
916 npoints = atom_getfloatarg(0, argc, argv);
917 argv++, argc--;
918
919 svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
920 if (!svec) return;
921
922 for (i = 0; i < argc; i++)
923 svec[i] = atom_getfloatarg(i, argc, argv);
924 garray_dofo(x, npoints, 0, argc, svec, 0);
925 t_freebytes(svec, sizeof(t_float) * argc);
926}
927
928static void garray_normalize(t_garray *x, t_float f)
929{
930 t_template *template = garray_template(x);
931 int yonset, type, npoints, i;
932 double maxv, renormer;
933 t_symbol *arraytype;
934
935 if (f <= 0)
936 f = 1;
937
938 if (!template_find_field(template, gensym("y"), &yonset,
939 &type, &arraytype) || type != DT_FLOAT)
940 {
941 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
942 return;
943 }
944 for (i = 0, maxv = 0; i < x->x_n; i++)
945 {
946 double v = *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
947 if (v > maxv)
948 maxv = v;
949 if (-v > maxv)
950 maxv = -v;
951 }
952 if (maxv >= 0)
953 {
954 renormer = f / maxv;
955 for (i = 0; i < x->x_n; i++)
956 {
957 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)
958 *= renormer;
959 }
960 }
961 garray_redraw(x);
962}
963
964 /* list -- the first value is an index; subsequent values are put in
965 the "y" slot of the array. This generalizes Max's "table", sort of. */
966static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv)
967{
968 t_template *template = garray_template(x);
969 int yonset, type, i;
970 t_symbol *arraytype;
971 if (!template_find_field(template, gensym("y"), &yonset,
972 &type, &arraytype) || type != DT_FLOAT)
973 error("%s: needs floating-point 'y' field",
974 x->x_templatesym->s_name);
975 else if (argc < 2) return;
976 else
977 {
978 int firstindex = atom_getfloat(argv);
979 argc--;
980 argv++;
981 /* drop negative x values */
982 if (firstindex < 0)
983 {
984 argc += firstindex;
985 argv -= firstindex;
986 firstindex = 0;
987 if (argc <= 0) return;
988 }
989 if (argc + firstindex > x->x_n)
990 {
991 argc = x->x_n - firstindex;
992 if (argc <= 0) return;
993 }
994 for (i = 0; i < argc; i++)
995 *(t_sample *)((x->x_vec + sizeof(t_word) * (i + firstindex)) + yonset) =
996 ftofix(atom_getfloat(argv + i));
997 }
998 garray_redraw(x);
999}
1000
1001 /* forward a "bounds" message to the owning graph */
1002static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1,
1003 t_floatarg x2, t_floatarg y2)
1004{
1005 vmess(&x->x_glist->gl_pd, gensym("bounds"), "ffff", x1, y1, x2, y2);
1006}
1007
1008 /* same for "xticks", etc */
1009static void garray_xticks(t_garray *x,
1010 t_floatarg point, t_floatarg inc, t_floatarg f)
1011{
1012 vmess(&x->x_glist->gl_pd, gensym("xticks"), "fff", point, inc, f);
1013}
1014
1015static void garray_yticks(t_garray *x,
1016 t_floatarg point, t_floatarg inc, t_floatarg f)
1017{
1018 vmess(&x->x_glist->gl_pd, gensym("yticks"), "fff", point, inc, f);
1019}
1020
1021static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
1022{
1023 typedmess(&x->x_glist->gl_pd, s, argc, argv);
1024}
1025
1026static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
1027{
1028 typedmess(&x->x_glist->gl_pd, s, argc, argv);
1029}
1030 /* change the name of a garray. */
1031static void garray_rename(t_garray *x, t_symbol *s)
1032{
1033 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
1034 pd_bind(&x->x_gobj.g_pd, x->x_realname = x->x_name = s);
1035 garray_redraw(x);
1036}
1037
1038static void garray_read(t_garray *x, t_symbol *filename)
1039{
1040 int nelem = x->x_n, filedesc;
1041 FILE *fd;
1042 char buf[MAXPDSTRING], *bufptr;
1043 t_template *template = garray_template(x);
1044 int yonset, type, i;
1045 t_symbol *arraytype;
1046 if (!template_find_field(template, gensym("y"), &yonset,
1047 &type, &arraytype) || type != DT_FLOAT)
1048 {
1049 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1050 return;
1051 }
1052 if ((filedesc = open_via_path(
1053 canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
1054 filename->s_name, "", buf, &bufptr, MAXPDSTRING, 0)) < 0
1055 || !(fd = fdopen(filedesc, "r")))
1056 {
1057 error("%s: can't open", filename->s_name);
1058 return;
1059 }
1060 for (i = 0; i < nelem; i++)
1061 {
1062 if (!fscanf(fd, "%f", (float *)((x->x_vec + sizeof(t_word) * i) +
1063 yonset)))
1064 {
1065 post("%s: read %d elements into table of size %d",
1066 filename->s_name, i, nelem);
1067 break;
1068 }
1069 }
1070 while (i < nelem)
1071 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = 0, i++;
1072 fclose(fd);
1073 garray_redraw(x);
1074}
1075
1076 /* this should be renamed and moved... */
1077int garray_ambigendian(void)
1078{
1079 unsigned short s = 1;
1080 unsigned char c = *(char *)(&s);
1081 return (c==0);
1082}
1083
1084#define BINREADMODE "rb"
1085#define BINWRITEMODE "wb"
1086
1087static void garray_read16(t_garray *x, t_symbol *filename,
1088 t_symbol *endian, t_floatarg fskip)
1089{
1090 int skip = fskip, filedesc;
1091 int i, nelem;
1092 t_sample *vec;
1093 FILE *fd;
1094 char buf[MAXPDSTRING], *bufptr;
1095 short s;
1096 int cpubig = garray_ambigendian(), swap = 0;
1097 char c = endian->s_name[0];
1098 if (c == 'b')
1099 {
1100 if (!cpubig) swap = 1;
1101 }
1102 else if (c == 'l')
1103 {
1104 if (cpubig) swap = 1;
1105 }
1106 else if (c)
1107 {
1108 error("array_read16: endianness is 'l' (low byte first ala INTEL)");
1109 post("... or 'b' (high byte first ala MIPS,DEC,PPC)");
1110 }
1111 if (!garray_getfloatarray(x, &nelem, &vec))
1112 {
1113 error("%s: not a float array", x->x_templatesym->s_name);
1114 return;
1115 }
1116 if ((filedesc = open_via_path(
1117 canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
1118 filename->s_name, "", buf, &bufptr, MAXPDSTRING, 1)) < 0
1119 || !(fd = fdopen(filedesc, BINREADMODE)))
1120 {
1121 error("%s: can't open", filename->s_name);
1122 return;
1123 }
1124 if (skip)
1125 {
1126 long pos = fseek(fd, (long)skip, SEEK_SET);
1127 if (pos < 0)
1128 {
1129 error("%s: can't seek to byte %d", buf, skip);
1130 fclose(fd);
1131 return;
1132 }
1133 }
1134
1135 for (i = 0; i < nelem; i++)
1136 {
1137 if (fread(&s, sizeof(s), 1, fd) < 1)
1138 {
1139 post("%s: read %d elements into table of size %d",
1140 filename->s_name, i, nelem);
1141 break;
1142 }
1143 if (swap) s = ((s & 0xff) << 8) | ((s & 0xff00) >> 8);
1144 vec[i] = s * (1./32768.);
1145 }
1146 while (i < nelem) vec[i++] = 0;
1147 fclose(fd);
1148 garray_redraw(x);
1149}
1150
1151static void garray_write(t_garray *x, t_symbol *filename)
1152{
1153 FILE *fd;
1154 char buf[MAXPDSTRING];
1155 t_template *template = garray_template(x);
1156 int yonset, type, i;
1157 t_symbol *arraytype;
1158 if (!template_find_field(template, gensym("y"), &yonset,
1159 &type, &arraytype) || type != DT_FLOAT)
1160 {
1161 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1162 return;
1163 }
1164 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
1165 buf, MAXPDSTRING);
1166 sys_bashfilename(buf, buf);
1167 if (!(fd = fopen(buf, "w")))
1168 {
1169 error("%s: can't create", buf);
1170 return;
1171 }
1172 for (i = 0; i < x->x_n; i++)
1173 {
1174 if (fprintf(fd, "%g\n",
1175 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)) < 1)
1176 {
1177 post("%s: write error", filename->s_name);
1178 break;
1179 }
1180 }
1181 fclose(fd);
1182}
1183
1184static unsigned char waveheader[] = {
11850x52, 0x49, 0x46, 0x46,
11860x00, 0x00, 0x00, 0x00,
11870x57, 0x41, 0x56, 0x45,
11880x66, 0x6d, 0x74, 0x20,
1189
11900x10, 0x00, 0x00, 0x00,
11910x01, 0x00, 0x01, 0x00,
11920x44, 0xac, 0x00, 0x00,
11930x88, 0x58, 0x01, 0x00,
1194
11950x02, 0x00, 0x10, 0x00,
11960x64, 0x61, 0x74, 0x61,
11970x00, 0x00, 0x00, 0x00,
1198};
1199
1200 /* wave format only so far */
1201static void garray_write16(t_garray *x, t_symbol *filename, t_symbol *format)
1202{
1203 t_template *template = garray_template(x);
1204 int yonset, type, i;
1205 t_symbol *arraytype;
1206 FILE *fd;
1207 int aiff = (format == gensym("aiff"));
1208 char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
1209 int swap = garray_ambigendian(); /* wave is only little endian */
1210 int intbuf;
1211 strncpy(filenamebuf, filename->s_name, MAXPDSTRING-10);
1212 filenamebuf[MAXPDSTRING-10] = 0;
1213 if (sizeof(int) != 4) post("write16: only works on 32-bit machines");
1214 if (aiff)
1215 {
1216 if (strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
1217 strcat(filenamebuf, ".aiff");
1218 }
1219 else
1220 {
1221 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
1222 strcat(filenamebuf, ".wav");
1223 }
1224 if (!template_find_field(template, gensym("y"), &yonset,
1225 &type, &arraytype) || type != DT_FLOAT)
1226 {
1227 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1228 return;
1229 }
1230 canvas_makefilename(glist_getcanvas(x->x_glist), filenamebuf,
1231 buf2, MAXPDSTRING);
1232 sys_bashfilename(buf2, buf2);
1233 if (!(fd = fopen(buf2, BINWRITEMODE)))
1234 {
1235 error("%s: can't create", buf2);
1236 return;
1237 }
1238 intbuf = 2 * x->x_n + 36;
1239 if (swap)
1240 {
1241 unsigned char *foo = (unsigned char *)&intbuf, xxx;
1242 xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
1243 xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
1244 }
1245 memcpy((void *)(waveheader + 4), (void *)(&intbuf), 4);
1246 intbuf = 2 * x->x_n;
1247 if (swap)
1248 {
1249 unsigned char *foo = (unsigned char *)&intbuf, xxx;
1250 xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
1251 xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
1252 }
1253 memcpy((void *)(waveheader + 40), (void *)(&intbuf), 4);
1254 if (fwrite(waveheader, sizeof(waveheader), 1, fd) < 1)
1255 {
1256 post("%s: write error", buf2);
1257 goto closeit;
1258 }
1259 for (i = 0; i < x->x_n; i++)
1260 {
1261 float f = 32767. * *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
1262 short sh;
1263 if (f < -32768) f = -32768;
1264 else if (f > 32767) f = 32767;
1265 sh = f;
1266 if (swap)
1267 {
1268 unsigned char *foo = (unsigned char *)&sh, xxx;
1269 xxx = foo[0]; foo[0] = foo[1]; foo[1] = xxx;
1270 }
1271 if (fwrite(&sh, sizeof(sh), 1, fd) < 1)
1272 {
1273 post("%s: write error", buf2);
1274 goto closeit;
1275 }
1276 }
1277closeit:
1278 fclose(fd);
1279}
1280
1281void garray_resize(t_garray *x, t_floatarg f)
1282{
1283 int was = x->x_n, elemsize;
1284 t_glist *gl;
1285 int dspwas;
1286 int n = f;
1287 char *nvec;
1288
1289 if (n < 1) n = 1;
1290 elemsize = template_findbyname(x->x_templatesym)->t_n * sizeof(t_word);
1291 nvec = t_resizebytes(x->x_vec, was * elemsize, n * elemsize);
1292 if (!nvec)
1293 {
1294 pd_error(x, "array resize failed: out of memory");
1295 return;
1296 }
1297 x->x_vec = nvec;
1298 /* LATER should check t_resizebytes result */
1299 if (n > was)
1300 memset(x->x_vec + was*elemsize,
1301 0, (n - was) * elemsize);
1302 x->x_n = n;
1303
1304 /* if this is the only array in the graph,
1305 reset the graph's coordinates */
1306 gl = x->x_glist;
1307 if (gl->gl_list == &x->x_gobj && !x->x_gobj.g_next)
1308 {
1309 vmess(&gl->gl_pd, gensym("bounds"), "ffff",
1310 0., gl->gl_y1, (double)(n > 1 ? n-1 : 1), gl->gl_y2);
1311 /* close any dialogs that might have the wrong info now... */
1312 gfxstub_deleteforkey(gl);
1313 }
1314 else garray_redraw(x);
1315 if (x->x_usedindsp) canvas_update_dsp();
1316}
1317
1318static void garray_print(t_garray *x)
1319{
1320 post("garray %s: template %s, length %d",
1321 x->x_name->s_name, x->x_templatesym->s_name, x->x_n);
1322}
1323
1324void g_array_setup(void)
1325{
1326 garray_class = class_new(gensym("array"), 0, (t_method)garray_free,
1327 sizeof(t_garray), CLASS_GOBJ, 0);
1328 class_setwidget(garray_class, &garray_widgetbehavior);
1329 class_addmethod(garray_class, (t_method)garray_const, gensym("const"),
1330 A_DEFFLOAT, A_NULL);
1331 class_addlist(garray_class, garray_list);
1332 class_addmethod(garray_class, (t_method)garray_bounds, gensym("bounds"),
1333 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
1334 class_addmethod(garray_class, (t_method)garray_xticks, gensym("xticks"),
1335 A_FLOAT, A_FLOAT, A_FLOAT, 0);
1336 class_addmethod(garray_class, (t_method)garray_xlabel, gensym("xlabel"),
1337 A_GIMME, 0);
1338 class_addmethod(garray_class, (t_method)garray_yticks, gensym("yticks"),
1339 A_FLOAT, A_FLOAT, A_FLOAT, 0);
1340 class_addmethod(garray_class, (t_method)garray_ylabel, gensym("ylabel"),
1341 A_GIMME, 0);
1342 class_addmethod(garray_class, (t_method)garray_rename, gensym("rename"),
1343 A_SYMBOL, 0);
1344 class_addmethod(garray_class, (t_method)garray_read, gensym("read"),
1345 A_SYMBOL, A_NULL);
1346 class_addmethod(garray_class, (t_method)garray_read16, gensym("read16"),
1347 A_SYMBOL, A_DEFFLOAT, A_DEFSYM, A_NULL);
1348 class_addmethod(garray_class, (t_method)garray_write, gensym("write"),
1349 A_SYMBOL, A_NULL);
1350 class_addmethod(garray_class, (t_method)garray_write16, gensym("write16"),
1351 A_SYMBOL, A_DEFSYM, A_NULL);
1352 class_addmethod(garray_class, (t_method)garray_resize, gensym("resize"),
1353 A_FLOAT, A_NULL);
1354 class_addmethod(garray_class, (t_method)garray_print, gensym("print"),
1355 A_NULL);
1356 class_addmethod(garray_class, (t_method)garray_sinesum, gensym("sinesum"),
1357 A_GIMME, 0);
1358 class_addmethod(garray_class, (t_method)garray_cosinesum,
1359 gensym("cosinesum"), A_GIMME, 0);
1360 class_addmethod(garray_class, (t_method)garray_normalize,
1361 gensym("normalize"), A_DEFFLOAT, 0);
1362 class_addmethod(garray_class, (t_method)garray_arraydialog,
1363 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
1364 class_setsavefn(garray_class, garray_save);
1365}
1366
1367
1368/* Copyright (c) 1997-1999 Miller Puckette.
1369* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1370* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1371
1372#include <stdlib.h>
1373#include <string.h>
1374#include <stdio.h> /* for read/write to files */
1375#include "m_pd.h"
1376#include "g_canvas.h"
1377#include <math.h>
1378
1379/* see also the "plot" object in g_scalar.c which deals with graphing
1380arrays which are fields in scalars. Someday we should unify the
1381two, but how? */
1382
1383 /* aux routine to bash leading '#' to '$' for dialogs in u_main.tk
1384 which can't send symbols starting with '$' (because the Pd message
1385 interpreter would change them!) */
1386
1387static t_symbol *sharptodollar(t_symbol *s)
1388{
1389 if (*s->s_name == '#')
1390 {
1391 char buf[MAXPDSTRING];
1392 strncpy(buf, s->s_name, MAXPDSTRING);
1393 buf[MAXPDSTRING-1] = 0;
1394 buf[0] = '$';
1395 return (gensym(buf));
1396 }
1397 else return (s);
1398}
1399
1400/* --------- "pure" arrays with scalars for elements. --------------- */
1401
1402/* Pure arrays have no a priori graphical capabilities.
1403They are instantiated by "garrays" below or can be elements of other
1404scalars (g_scalar.c); their graphical behavior is defined accordingly. */
1405
1406t_array *array_new(t_symbol *templatesym, t_gpointer *parent)
1407{
1408 t_array *x = (t_array *)getbytes(sizeof (*x));
1409 t_template *template;
1410 t_gpointer *gp;
1411 template = template_findbyname(templatesym);
1412 x->a_templatesym = templatesym;
1413 x->a_n = 1;
1414 x->a_elemsize = sizeof(t_word) * template->t_n;
1415 x->a_vec = (char *)getbytes(x->a_elemsize);
1416 /* note here we blithely copy a gpointer instead of "setting" a
1417 new one; this gpointer isn't accounted for and needn't be since
1418 we'll be deleted before the thing pointed to gets deleted anyway;
1419 see array_free. */
1420 x->a_gp = *parent;
1421 x->a_stub = gstub_new(0, x);
1422 word_init((t_word *)(x->a_vec), template, parent);
1423 return (x);
1424}
1425
1426void array_resize(t_array *x, t_template *template, int n)
1427{
1428 int elemsize, oldn;
1429 t_gpointer *gp;
1430
1431 if (n < 1)
1432 n = 1;
1433 oldn = x->a_n;
1434 elemsize = sizeof(t_word) * template->t_n;
1435
1436 x->a_vec = (char *)resizebytes(x->a_vec, oldn * elemsize,
1437 n * elemsize);
1438 x->a_n = n;
1439 if (n > oldn)
1440 {
1441 char *cp = x->a_vec + elemsize * oldn;
1442 int i = n - oldn;
1443 for (; i--; cp += elemsize)
1444 {
1445 t_word *wp = (t_word *)cp;
1446 word_init(wp, template, &x->a_gp);
1447 }
1448 }
1449}
1450
1451void word_free(t_word *wp, t_template *template);
1452
1453void array_free(t_array *x)
1454{
1455 int i;
1456 t_template *scalartemplate = template_findbyname(x->a_templatesym);
1457 /* we don't unset our gpointer here since it was never "set." */
1458 /* gpointer_unset(&x->a_gp); */
1459 gstub_cutoff(x->a_stub);
1460 for (i = 0; i < x->a_n; i++)
1461 {
1462 t_word *wp = (t_word *)(x->a_vec + x->a_elemsize * i);
1463 word_free(wp, scalartemplate);
1464 }
1465 freebytes(x->a_vec, x->a_elemsize * x->a_n);
1466 freebytes(x, sizeof *x);
1467}
1468
1469/* --------------------- graphical arrays (garrays) ------------------- */
1470
1471t_class *garray_class;
1472static int gcount = 0;
1473
1474struct _garray
1475{
1476 t_gobj x_gobj;
1477 t_glist *x_glist;
1478 t_array x_array; /* actual array; note only 4 fields used as below */
1479 t_symbol *x_name;
1480 t_symbol *x_realname; /* name with "$" expanded */
1481 t_float x_firstx; /* X value of first item */
1482 t_float x_xinc; /* X increment */
1483 char x_usedindsp; /* true if some DSP routine is using this */
1484 char x_saveit; /* true if we should save this with parent */
1485};
1486
1487 /* macros to get into the "array" structure */
1488#define x_n x_array.a_n
1489#define x_elemsize x_array.a_elemsize
1490#define x_vec x_array.a_vec
1491#define x_templatesym x_array.a_templatesym
1492
1493t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *templatesym,
1494 t_floatarg f, t_floatarg saveit)
1495{
1496 int n = f, i;
1497 int zz, nwords;
1498 t_garray *x;
1499 t_pd *x2;
1500 t_template *template;
1501 char *str;
1502 if (s == &s_)
1503 {
1504 char buf[40];
1505 sprintf(buf, "array%d", ++gcount);
1506 s = gensym(buf);
1507 templatesym = &s_float;
1508 n = 100;
1509 }
1510 else if (!strncmp((str = s->s_name), "array", 5)
1511 && (zz = atoi(str + 5)) > gcount) gcount = zz;
1512 template = template_findbyname(templatesym);
1513 if (!template)
1514 {
1515 error("array: couldn't find template %s", templatesym->s_name);
1516 return (0);
1517 }
1518 nwords = template->t_n;
1519 for (i = 0; i < nwords; i++)
1520 {
1521 /* we can't have array or list elements yet because what scalar
1522 can act as their "parent"??? */
1523 if (template->t_vec[i].ds_type == DT_ARRAY
1524 || template->t_vec[i].ds_type == DT_LIST)
1525 {
1526 error("array: template %s can't have sublists or arrays",
1527 templatesym->s_name);
1528 return (0);
1529 }
1530 }
1531 x = (t_garray *)pd_new(garray_class);
1532
1533 if (n <= 0) n = 100;
1534 x->x_n = n;
1535 x->x_elemsize = nwords * sizeof(t_word);
1536 x->x_vec = getbytes(x->x_n * x->x_elemsize);
1537 memset(x->x_vec, 0, x->x_n * x->x_elemsize);
1538 /* LATER should check that malloc */
1539 x->x_name = s;
1540 x->x_realname = canvas_realizedollar(gl, s);
1541 pd_bind(&x->x_gobj.g_pd, x->x_realname);
1542 x->x_templatesym = templatesym;
1543 x->x_firstx = 0;
1544 x->x_xinc = 1; /* LATER make methods to set this... */
1545 glist_add(gl, &x->x_gobj);
1546 x->x_glist = gl;
1547 x->x_usedindsp = 0;
1548 x->x_saveit = (saveit != 0);
1549 if (x2 = pd_findbyclass(gensym("#A"), garray_class))
1550 pd_unbind(x2, gensym("#A"));
1551
1552 pd_bind(&x->x_gobj.g_pd, gensym("#A"));
1553
1554 return (x);
1555}
1556
1557 /* called from array menu item to create a new one */
1558void canvas_menuarray(t_glist *canvas)
1559{
1560 t_glist *x = (t_glist *)canvas;
1561 char cmdbuf[200];
1562 sprintf(cmdbuf, "pdtk_array_dialog %%s array%d 100 1 1\n",
1563 ++gcount);
1564 gfxstub_new(&x->gl_pd, x, cmdbuf);
1565}
1566
1567 /* called from graph_dialog to set properties */
1568void garray_properties(t_garray *x)
1569{
1570 char cmdbuf[200];
1571 gfxstub_deleteforkey(x);
1572 /* create dialog window. LATER fix this to escape '$'
1573 properly; right now we just detect a leading '$' and escape
1574 it. There should be a systematic way of doing this. */
1575 if (x->x_name->s_name[0] == '$')
1576 sprintf(cmdbuf, "pdtk_array_dialog %%s \\%s %d %d 0\n",
1577 x->x_name->s_name, x->x_n, x->x_saveit);
1578 else sprintf(cmdbuf, "pdtk_array_dialog %%s %s %d %d 0\n",
1579 x->x_name->s_name, x->x_n, x->x_saveit);
1580 gfxstub_new(&x->x_gobj.g_pd, x, cmdbuf);
1581}
1582
1583 /* this is called back from the dialog window to create a garray.
1584 The otherflag requests that we find an existing graph to put it in. */
1585void glist_arraydialog(t_glist *parent, t_symbol *name, t_floatarg size,
1586 t_floatarg saveit, t_floatarg otherflag)
1587{
1588 t_glist *gl;
1589 t_garray *a;
1590 if (size < 1)
1591 size = 1;
1592 if (otherflag == 0 || (!(gl = glist_findgraph(parent))))
1593 gl = glist_addglist(parent, &s_, 0, 1,
1594 (size > 1 ? size-1 : size), -1, 0, 0, 0, 0);
1595 a = graph_array(gl, sharptodollar(name), &s_float, size, saveit);
1596}
1597
1598 /* this is called from the properties dialog window for an existing array */
1599void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize,
1600 t_floatarg saveit, t_floatarg deleteit)
1601{
1602 if (deleteit != 0)
1603 {
1604 glist_delete(x->x_glist, &x->x_gobj);
1605 }
1606 else
1607 {
1608 int size;
1609 t_symbol *argname = sharptodollar(name);
1610 if (argname != x->x_name)
1611 {
1612 x->x_name = argname;
1613 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
1614 x->x_realname = canvas_realizedollar(x->x_glist, argname);
1615 pd_bind(&x->x_gobj.g_pd, x->x_realname);
1616 }
1617 size = fsize;
1618 if (size < 1)
1619 size = 1;
1620 if (size != x->x_n)
1621 garray_resize(x, size);
1622 garray_setsaveit(x, (saveit != 0));
1623 garray_redraw(x);
1624 }
1625}
1626
1627static void garray_free(t_garray *x)
1628{
1629 t_pd *x2;
1630 gfxstub_deleteforkey(x);
1631 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
1632 /* LATER find a way to get #A unbound earlier (at end of load?) */
1633 while (x2 = pd_findbyclass(gensym("#A"), garray_class))
1634 pd_unbind(x2, gensym("#A"));
1635 freebytes(x->x_vec, x->x_n * x->x_elemsize);
1636}
1637
1638/* ------------- code used by both array and plot widget functions ---- */
1639
1640 /* routine to get screen coordinates of a point in an array */
1641void array_getcoordinate(t_glist *glist,
1642 char *elem, int xonset, int yonset, int wonset, int indx,
1643 float basex, float basey, float xinc,
1644 float *xp, float *yp, float *wp)
1645{
1646 float xval, yval, ypix, wpix;
1647 if (xonset >= 0)
1648 xval = fixtof(*(t_sample *)(elem + xonset));
1649 else xval = indx * xinc;
1650 if (yonset >= 0)
1651 yval = fixtof(*(t_sample *)(elem + yonset));
1652 else yval = 0;
1653 ypix = glist_ytopixels(glist, basey + yval);
1654 if (wonset >= 0)
1655 {
1656 /* found "w" field which controls linewidth. */
1657 float wval = *(float *)(elem + wonset);
1658 wpix = glist_ytopixels(glist, basey + yval + wval) - ypix;
1659 if (wpix < 0)
1660 wpix = -wpix;
1661 }
1662 else wpix = 1;
1663 *xp = glist_xtopixels(glist, basex + xval);
1664 *yp = ypix;
1665 *wp = wpix;
1666}
1667
1668static float array_motion_xcumulative;
1669static float array_motion_ycumulative;
1670static t_symbol *array_motion_xfield;
1671static t_symbol *array_motion_yfield;
1672static t_glist *array_motion_glist;
1673static t_gobj *array_motion_gobj;
1674static t_word *array_motion_wp;
1675static t_template *array_motion_template;
1676static int array_motion_npoints;
1677static int array_motion_elemsize;
1678static int array_motion_altkey;
1679static float array_motion_initx;
1680static float array_motion_xperpix;
1681static float array_motion_yperpix;
1682static int array_motion_lastx;
1683static int array_motion_fatten;
1684
1685 /* LATER protect against the template changing or the scalar disappearing
1686 probably by attaching a gpointer here ... */
1687
1688static void array_motion(void *z, t_floatarg dx, t_floatarg dy)
1689{
1690 array_motion_xcumulative += dx * array_motion_xperpix;
1691 array_motion_ycumulative += dy * array_motion_yperpix;
1692 if (*array_motion_xfield->s_name)
1693 {
1694 /* it's an x, y plot; can drag many points at once */
1695 int i;
1696 char *charword = (char *)array_motion_wp;
1697 for (i = 0; i < array_motion_npoints; i++)
1698 {
1699 t_word *thisword = (t_word *)(charword + i * array_motion_elemsize);
1700 if (*array_motion_xfield->s_name)
1701 {
1702 float xwas = template_getfloat(array_motion_template,
1703 array_motion_xfield, thisword, 1);
1704 template_setfloat(array_motion_template,
1705 array_motion_xfield, thisword, xwas + dx, 1);
1706 }
1707 if (*array_motion_yfield->s_name)
1708 {
1709 float ywas = template_getfloat(array_motion_template,
1710 array_motion_yfield, thisword, 1);
1711 if (array_motion_fatten)
1712 {
1713 if (i == 0)
1714 {
1715 float newy = ywas + dy * array_motion_yperpix;
1716 if (newy < 0)
1717 newy = 0;
1718 template_setfloat(array_motion_template,
1719 array_motion_yfield, thisword, newy, 1);
1720 }
1721 }
1722 else
1723 {
1724 template_setfloat(array_motion_template,
1725 array_motion_yfield, thisword,
1726 ywas + dy * array_motion_yperpix, 1);
1727 }
1728 }
1729 }
1730 }
1731 else
1732 {
1733 /* a y-only plot. */
1734 int thisx = array_motion_initx +
1735 array_motion_xcumulative, x2;
1736 int increment, i, nchange;
1737 char *charword = (char *)array_motion_wp;
1738 float newy = array_motion_ycumulative,
1739 oldy = template_getfloat(
1740 array_motion_template, array_motion_yfield,
1741 (t_word *)(charword + array_motion_elemsize * array_motion_lastx), 1);
1742 float ydiff = newy - oldy;
1743 if (thisx < 0) thisx = 0;
1744 else if (thisx >= array_motion_npoints)
1745 thisx = array_motion_npoints - 1;
1746 increment = (thisx > array_motion_lastx ? -1 : 1);
1747 nchange = 1 + increment * (array_motion_lastx - thisx);
1748
1749 for (i = 0, x2 = thisx; i < nchange; i++, x2 += increment)
1750 {
1751 template_setfloat(array_motion_template,
1752 array_motion_yfield,
1753 (t_word *)(charword + array_motion_elemsize * x2),
1754 newy, 1);
1755 if (nchange > 1)
1756 newy -= ydiff * (1./(nchange - 1));
1757 }
1758 array_motion_lastx = thisx;
1759 }
1760 glist_redrawitem(array_motion_glist, array_motion_gobj);
1761}
1762
1763int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
1764 t_symbol *elemtemplatesym,
1765 float linewidth, float xloc, float xinc, float yloc,
1766 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1767{
1768 t_canvas *elemtemplatecanvas;
1769 t_template *elemtemplate;
1770 int elemsize, yonset, wonset, xonset, i;
1771
1772 if (!array_getfields(elemtemplatesym, &elemtemplatecanvas,
1773 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
1774 {
1775 float best = 100;
1776 int incr;
1777 /* if it has more than 2000 points, just check 300 of them. */
1778 if (array->a_n < 2000)
1779 incr = 1;
1780 else incr = array->a_n / 300;
1781 for (i = 0; i < array->a_n; i += incr)
1782 {
1783 float pxpix, pypix, pwpix, dx, dy;
1784 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
1785 xonset, yonset, wonset, i, xloc, yloc, xinc,
1786 &pxpix, &pypix, &pwpix);
1787 if (pwpix < 4)
1788 pwpix = 4;
1789 dx = pxpix - xpix;
1790 if (dx < 0) dx = -dx;
1791 if (dx > 8)
1792 continue;
1793 dy = pypix - ypix;
1794 if (dy < 0) dy = -dy;
1795 if (dx + dy < best)
1796 best = dx + dy;
1797 if (wonset >= 0)
1798 {
1799 dy = (pypix + pwpix) - ypix;
1800 if (dy < 0) dy = -dy;
1801 if (dx + dy < best)
1802 best = dx + dy;
1803 dy = (pypix - pwpix) - ypix;
1804 if (dy < 0) dy = -dy;
1805 if (dx + dy < best)
1806 best = dx + dy;
1807 }
1808 }
1809 if (best > 8)
1810 return (0);
1811 best += 0.001; /* add truncation error margin */
1812 for (i = 0; i < array->a_n; i += incr)
1813 {
1814 float pxpix, pypix, pwpix, dx, dy, dy2, dy3;
1815 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
1816 xonset, yonset, wonset, i, xloc, yloc, xinc,
1817 &pxpix, &pypix, &pwpix);
1818 if (pwpix < 4)
1819 pwpix = 4;
1820 dx = pxpix - xpix;
1821 if (dx < 0) dx = -dx;
1822 dy = pypix - ypix;
1823 if (dy < 0) dy = -dy;
1824 if (wonset >= 0)
1825 {
1826 dy2 = (pypix + pwpix) - ypix;
1827 if (dy2 < 0) dy2 = -dy2;
1828 dy3 = (pypix - pwpix) - ypix;
1829 if (dy3 < 0) dy3 = -dy3;
1830 if (yonset <= 0)
1831 dy = 100;
1832 }
1833 else dy2 = dy3 = 100;
1834 if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best)
1835 {
1836 if (dy < dy2 && dy < dy3)
1837 array_motion_fatten = 0;
1838 else if (dy2 < dy3)
1839 array_motion_fatten = -1;
1840 else array_motion_fatten = 1;
1841 if (doit)
1842 {
1843 char *elem = (char *)array->a_vec;
1844 array_motion_elemsize = elemsize;
1845 array_motion_glist = glist;
1846 array_motion_gobj = gobj;
1847 array_motion_template = elemtemplate;
1848 array_motion_xperpix = glist_dpixtodx(glist, 1);
1849 array_motion_yperpix = glist_dpixtody(glist, 1);
1850 if (alt && xpix < pxpix) /* delete a point */
1851 {
1852 if (array->a_n <= 1)
1853 return (0);
1854 memmove((char *)(array->a_vec) + elemsize * i,
1855 (char *)(array->a_vec) + elemsize * (i+1),
1856 (array->a_n - 1 - i) * elemsize);
1857 array_resize(array, elemtemplate, array->a_n - 1);
1858 glist_redrawitem(array_motion_glist, array_motion_gobj);
1859 return (0);
1860 }
1861 else if (alt)
1862 {
1863 /* add a point (after the clicked-on one) */
1864 array_resize(array, elemtemplate, array->a_n + 1);
1865 elem = (char *)array->a_vec;
1866 memmove(elem + elemsize * (i+1),
1867 elem + elemsize * i,
1868 (array->a_n - i - 1) * elemsize);
1869 i++;
1870 }
1871 if (xonset >= 0)
1872 {
1873 array_motion_xfield = gensym("x");
1874 array_motion_xcumulative =
1875 *(float *)((elem + elemsize * i) + xonset);
1876 array_motion_wp = (t_word *)(elem + i * elemsize);
1877 array_motion_npoints = array->a_n - i;
1878 }
1879 else
1880 {
1881 array_motion_xfield = &s_;
1882 array_motion_xcumulative = 0;
1883 array_motion_wp = (t_word *)elem;
1884 array_motion_npoints = array->a_n;
1885
1886 array_motion_initx = i;
1887 array_motion_lastx = i;
1888 array_motion_xperpix *= (xinc == 0 ? 1 : 1./xinc);
1889 }
1890 if (array_motion_fatten)
1891 {
1892 array_motion_yfield = gensym("w");
1893 array_motion_ycumulative =
1894 *(float *)((elem + elemsize * i) + wonset);
1895 array_motion_yperpix *= array_motion_fatten;
1896 }
1897 else if (yonset >= 0)
1898 {
1899 array_motion_yfield = gensym("y");
1900 array_motion_ycumulative =
1901 *(float *)((elem + elemsize * i) + yonset);
1902 }
1903 else
1904 {
1905 array_motion_yfield = &s_;
1906 array_motion_ycumulative = 0;
1907 }
1908 glist_grab(glist, 0, array_motion, 0, xpix, ypix);
1909 }
1910 if (alt)
1911 {
1912 if (xpix < pxpix)
1913 return (CURSOR_EDITMODE_DISCONNECT);
1914 else return (CURSOR_RUNMODE_ADDPOINT);
1915 }
1916 else return (array_motion_fatten ?
1917 CURSOR_RUNMODE_THICKEN : CURSOR_RUNMODE_CLICKME);
1918 }
1919 }
1920 }
1921 return (0);
1922}
1923
1924/* -------------------- widget behavior for garray ------------ */
1925
1926static void garray_getrect(t_gobj *z, t_glist *glist,
1927 int *xp1, int *yp1, int *xp2, int *yp2)
1928{
1929 t_garray *x = (t_garray *)z;
1930 float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
1931 t_canvas *elemtemplatecanvas;
1932 t_template *elemtemplate;
1933 int elemsize, yonset, wonset, xonset, i;
1934
1935 if (!array_getfields(x->x_templatesym, &elemtemplatecanvas,
1936 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
1937 {
1938 int incr;
1939 /* if it has more than 2000 points, just check 300 of them. */
1940 if (x->x_array.a_n < 2000)
1941 incr = 1;
1942 else incr = x->x_array.a_n / 300;
1943 for (i = 0; i < x->x_array.a_n; i += incr)
1944 {
1945 float pxpix, pypix, pwpix, dx, dy;
1946 array_getcoordinate(glist, (char *)(x->x_array.a_vec) +
1947 i * elemsize,
1948 xonset, yonset, wonset, i, 0, 0, 1,
1949 &pxpix, &pypix, &pwpix);
1950 if (pwpix < 2)
1951 pwpix = 2;
1952 if (pxpix < x1)
1953 x1 = pxpix;
1954 if (pxpix > x2)
1955 x2 = pxpix;
1956 if (pypix - pwpix < y1)
1957 y1 = pypix - pwpix;
1958 if (pypix + pwpix > y2)
1959 y2 = pypix + pwpix;
1960 }
1961 }
1962 *xp1 = x1;
1963 *yp1 = y1;
1964 *xp2 = x2;
1965 *yp2 = y2;
1966}
1967
1968static void garray_displace(t_gobj *z, t_glist *glist, int dx, int dy)
1969{
1970 /* refuse */
1971}
1972
1973static void garray_select(t_gobj *z, t_glist *glist, int state)
1974{
1975 t_garray *x = (t_garray *)z;
1976 /* fill in later */
1977}
1978
1979static void garray_activate(t_gobj *z, t_glist *glist, int state)
1980{
1981}
1982
1983static void garray_delete(t_gobj *z, t_glist *glist)
1984{
1985 /* nothing to do */
1986}
1987
1988static void garray_vis(t_gobj *z, t_glist *glist, int vis)
1989{
1990 t_garray *x = (t_garray *)z;
1991 if (vis)
1992 {
1993 int i, xonset, yonset, type;
1994 t_symbol *arraytype;
1995 t_template *template = template_findbyname(x->x_templatesym);
1996 if (!template)
1997 return;
1998 if (!template_find_field(template, gensym("y"), &yonset, &type,
1999 &arraytype) || type != DT_FLOAT)
2000 {
2001 error("%s: needs floating-point 'y' field",
2002 x->x_templatesym->s_name);
2003 sys_vgui(".x%x.c create text 50 50 -text foo\
2004 -tags .x%x.a%x\n",
2005 glist_getcanvas(glist), glist_getcanvas(glist), x);
2006 }
2007 else if (!template_find_field(template, gensym("x"), &xonset, &type,
2008 &arraytype) || type != DT_FLOAT)
2009 {
2010 float firsty, xcum = x->x_firstx;
2011 int lastpixel = -1, ndrawn = 0;
2012 float yval = 0, xpix;
2013 int ixpix = 0;
2014 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
2015 for (i = 0; i < x->x_n; i++)
2016 {
2017 yval = fixtof(*(t_sample *)(x->x_vec +
2018 template->t_n * i * sizeof (t_word) + yonset));
2019 xpix = glist_xtopixels(glist, xcum);
2020 ixpix = xpix + 0.5;
2021 if (ixpix != lastpixel)
2022 {
2023 sys_vgui("%d %f \\\n", ixpix,
2024 glist_ytopixels(glist, yval));
2025 ndrawn++;
2026 }
2027 lastpixel = ixpix;
2028 if (ndrawn >= 1000) break;
2029 xcum += x->x_xinc;
2030 }
2031 /* TK will complain if there aren't at least 2 points... */
2032 if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
2033 else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix,
2034 glist_ytopixels(glist, yval));
2035 sys_vgui("-tags .x%x.a%x\n", glist_getcanvas(glist), x);
2036 firsty = fixtof(*(t_sample *)(x->x_vec + yonset));
2037 sys_vgui(".x%x.c create text %f %f -text {%s} -anchor e\
2038 -font -*-courier-bold--normal--%d-* -tags .x%x.a%x\n",
2039 glist_getcanvas(glist),
2040 glist_xtopixels(glist, x->x_firstx) - 5.,
2041 glist_ytopixels(glist, firsty),
2042 x->x_name->s_name, glist_getfont(glist),
2043 glist_getcanvas(glist), x);
2044 }
2045 else
2046 {
2047 post("x, y arrays not yet supported");
2048 }
2049 }
2050 else
2051 {
2052 sys_vgui(".x%x.c delete .x%x.a%x\n",
2053 glist_getcanvas(glist), glist_getcanvas(glist), x);
2054 }
2055}
2056
2057static int garray_click(t_gobj *z, struct _glist *glist,
2058 int xpix, int ypix, int shift, int alt, int dbl, int doit)
2059{
2060 t_garray *x = (t_garray *)z;
2061 return (array_doclick(&x->x_array, glist, z, x->x_templatesym, 1, 0, 1, 0,
2062 xpix, ypix, shift, alt, dbl, doit));
2063}
2064
2065#define ARRAYWRITECHUNKSIZE 1000
2066
2067static void garray_save(t_gobj *z, t_binbuf *b)
2068{
2069 t_garray *x = (t_garray *)z;
2070 binbuf_addv(b, "sssisi;", gensym("#X"), gensym("array"),
2071 x->x_name, x->x_n, x->x_templatesym, x->x_saveit);
2072 fprintf(stderr,"array save\n");
2073 if (x->x_saveit)
2074 {
2075 int n = x->x_n, n2 = 0;
2076 if (x->x_templatesym != &s_float)
2077 {
2078 pd_error(x, "sorry, you can only save 'float' arrays now");
2079 return;
2080 }
2081 if (n > 200000)
2082 post("warning: I'm saving an array with %d points!\n", n);
2083 while (n2 < n)
2084 {
2085 int chunk = n - n2, i;
2086 if (chunk > ARRAYWRITECHUNKSIZE)
2087 chunk = ARRAYWRITECHUNKSIZE;
2088 binbuf_addv(b, "si", gensym("#A"), n2);
2089 for (i = 0; i < chunk; i++)
2090 binbuf_addv(b, "f", fixtof(((t_sample *)(x->x_vec))[n2+i]));
2091 binbuf_addv(b, ";");
2092 n2 += chunk;
2093 }
2094 }
2095}
2096
2097t_widgetbehavior garray_widgetbehavior =
2098{
2099 garray_getrect,
2100 garray_displace,
2101 garray_select,
2102 garray_activate,
2103 garray_delete,
2104 garray_vis,
2105 garray_click
2106};
2107
2108/* ----------------------- public functions -------------------- */
2109
2110void garray_usedindsp(t_garray *x)
2111{
2112 x->x_usedindsp = 1;
2113}
2114
2115void garray_redraw(t_garray *x)
2116{
2117 if (glist_isvisible(x->x_glist))
2118 {
2119 garray_vis(&x->x_gobj, x->x_glist, 0);
2120 garray_vis(&x->x_gobj, x->x_glist, 1);
2121 }
2122}
2123
2124 /* This functiopn gets the template of an array; if we can't figure
2125 out what template an array's elements belong to we're in grave trouble
2126 when it's time to free or resize it. */
2127t_template *garray_template(t_garray *x)
2128{
2129 t_template *template = template_findbyname(x->x_templatesym);
2130 if (!template)
2131 bug("garray_template");
2132 return (template);
2133}
2134
2135int garray_npoints(t_garray *x) /* get the length */
2136{
2137 return (x->x_n);
2138}
2139
2140char *garray_vec(t_garray *x) /* get the contents */
2141{
2142 return ((char *)(x->x_vec));
2143}
2144
2145 /* routine that checks if we're just an array of floats and if
2146 so returns the goods */
2147
2148int garray_getfloatarray(t_garray *x, int *size, t_sample **vec)
2149{
2150 t_template *template = garray_template(x);
2151 int yonset, type;
2152 t_symbol *arraytype;
2153 if (!template_find_field(template, gensym("y"), &yonset,
2154 &type, &arraytype) || type != DT_FLOAT)
2155 error("%s: needs floating-point 'y' field",
2156 x->x_templatesym->s_name);
2157 else if (template->t_n != 1)
2158 error("%s: has more than one field", x->x_templatesym->s_name);
2159 else
2160 {
2161 *size = garray_npoints(x);
2162 *vec = (t_sample *)garray_vec(x);
2163 return (1);
2164 }
2165 return (0);
2166}
2167
2168 /* get any floating-point field of any element of an array */
2169float garray_get(t_garray *x, t_symbol *s, t_int indx)
2170{
2171 t_template *template = garray_template(x);
2172 int yonset, type;
2173 t_symbol *arraytype;
2174 if (!template_find_field(template, gensym("y"), &yonset,
2175 &type, &arraytype) || type != DT_FLOAT)
2176 {
2177 error("%s: needs floating-point '%s' field", x->x_templatesym->s_name,
2178 s->s_name);
2179 return (0);
2180 }
2181 if (indx < 0) indx = 0;
2182 else if (indx >= x->x_n) indx = x->x_n - 1;
2183 return (*(float *)((x->x_vec + sizeof(t_word) * indx) + yonset));
2184}
2185
2186 /* set the "saveit" flag */
2187void garray_setsaveit(t_garray *x, int saveit)
2188{
2189 if (x->x_saveit && !saveit)
2190 post("warning: array %s: clearing save-in-patch flag",
2191 x->x_name->s_name);
2192 x->x_saveit = saveit;
2193}
2194
2195/*------------------- Pd messages ------------------------ */
2196static void garray_const(t_garray *x, t_floatarg g)
2197{
2198 t_template *template = garray_template(x);
2199 int yonset, type, i;
2200 t_symbol *arraytype;
2201 if (!template_find_field(template, gensym("y"), &yonset,
2202 &type, &arraytype) || type != DT_FLOAT)
2203 error("%s: needs floating-point 'y' field",
2204 x->x_templatesym->s_name);
2205 else for (i = 0; i < x->x_n; i++)
2206 *(float *)(((char *)x->x_vec + sizeof(t_word) * i) + yonset) = g;
2207 garray_redraw(x);
2208}
2209
2210 /* sum of Fourier components; called from routines below */
2211static void garray_dofo(t_garray *x, int npoints, float dcval,
2212 int nsin, t_float *vsin, int sineflag)
2213{
2214 t_template *template = garray_template(x);
2215 int yonset, type, i, j;
2216 t_symbol *arraytype;
2217 double phase, phaseincr, fj;
2218 if (npoints == 0)
2219 npoints = 512; /* dunno what a good default would be... */
2220 if (npoints != (1 << ilog2(npoints)))
2221 post("%s: rounnding to %d points", x->x_templatesym->s_name,
2222 (npoints = (1<<ilog2(npoints))));
2223 garray_resize(x, npoints + 3);
2224 phaseincr = 2. * 3.14159 / npoints;
2225 if (!template_find_field(template, gensym("y"), &yonset,
2226 &type, &arraytype) || type != DT_FLOAT)
2227 {
2228 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
2229 return;
2230 }
2231 for (i = 0, phase = -phaseincr; i < x->x_n; i++, phase += phaseincr )
2232 {
2233 double sum = dcval;
2234 if (sineflag)
2235 for (j = 0, fj = phase; j < nsin; j++, fj += phase)
2236 sum += vsin[j] * sin(fj);
2237 else
2238 for (j = 0, fj = 0; j < nsin; j++, fj += phase)
2239 sum += vsin[j] * cos(fj);
2240 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = sum;
2241 }
2242 garray_redraw(x);
2243}
2244
2245static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
2246{
2247 t_template *template = garray_template(x);
2248
2249 t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
2250 int npoints, i;
2251 if (argc < 2)
2252 {
2253 error("sinesum: %s: need number of points and partial strengths",
2254 x->x_templatesym->s_name);
2255 return;
2256 }
2257
2258 npoints = atom_getfloatarg(0, argc, argv);
2259 argv++, argc--;
2260
2261 svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
2262 if (!svec) return;
2263
2264 for (i = 0; i < argc; i++)
2265 svec[i] = atom_getfloatarg(i, argc, argv);
2266 garray_dofo(x, npoints, 0, argc, svec, 1);
2267 t_freebytes(svec, sizeof(t_float) * argc);
2268}
2269
2270static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
2271{
2272 t_template *template = garray_template(x);
2273
2274 t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
2275 int npoints, i;
2276 if (argc < 2)
2277 {
2278 error("sinesum: %s: need number of points and partial strengths",
2279 x->x_templatesym->s_name);
2280 return;
2281 }
2282
2283 npoints = atom_getfloatarg(0, argc, argv);
2284 argv++, argc--;
2285
2286 svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
2287 if (!svec) return;
2288
2289 for (i = 0; i < argc; i++)
2290 svec[i] = atom_getfloatarg(i, argc, argv);
2291 garray_dofo(x, npoints, 0, argc, svec, 0);
2292 t_freebytes(svec, sizeof(t_float) * argc);
2293}
2294
2295static void garray_normalize(t_garray *x, t_float f)
2296{
2297 t_template *template = garray_template(x);
2298 int yonset, type, npoints, i;
2299 double maxv, renormer;
2300 t_symbol *arraytype;
2301
2302 if (f <= 0)
2303 f = 1;
2304
2305 if (!template_find_field(template, gensym("y"), &yonset,
2306 &type, &arraytype) || type != DT_FLOAT)
2307 {
2308 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
2309 return;
2310 }
2311 for (i = 0, maxv = 0; i < x->x_n; i++)
2312 {
2313 double v = *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
2314 if (v > maxv)
2315 maxv = v;
2316 if (-v > maxv)
2317 maxv = -v;
2318 }
2319 if (maxv >= 0)
2320 {
2321 renormer = f / maxv;
2322 for (i = 0; i < x->x_n; i++)
2323 {
2324 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)
2325 *= renormer;
2326 }
2327 }
2328 garray_redraw(x);
2329}
2330
2331 /* list -- the first value is an index; subsequent values are put in
2332 the "y" slot of the array. This generalizes Max's "table", sort of. */
2333static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv)
2334{
2335 t_template *template = garray_template(x);
2336 int yonset, type, i;
2337 t_symbol *arraytype;
2338 if (!template_find_field(template, gensym("y"), &yonset,
2339 &type, &arraytype) || type != DT_FLOAT)
2340 error("%s: needs floating-point 'y' field",
2341 x->x_templatesym->s_name);
2342 else if (argc < 2) return;
2343 else
2344 {
2345 int firstindex = atom_getfloat(argv);
2346 argc--;
2347 argv++;
2348 /* drop negative x values */
2349 if (firstindex < 0)
2350 {
2351 argc += firstindex;
2352 argv -= firstindex;
2353 firstindex = 0;
2354 if (argc <= 0) return;
2355 }
2356 if (argc + firstindex > x->x_n)
2357 {
2358 argc = x->x_n - firstindex;
2359 if (argc <= 0) return;
2360 }
2361 for (i = 0; i < argc; i++)
2362 *(t_sample *)((x->x_vec + sizeof(t_word) * (i + firstindex)) + yonset) =
2363 ftofix(atom_getfloat(argv + i));
2364 }
2365 garray_redraw(x);
2366}
2367
2368 /* forward a "bounds" message to the owning graph */
2369static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1,
2370 t_floatarg x2, t_floatarg y2)
2371{
2372 vmess(&x->x_glist->gl_pd, gensym("bounds"), "ffff", x1, y1, x2, y2);
2373}
2374
2375 /* same for "xticks", etc */
2376static void garray_xticks(t_garray *x,
2377 t_floatarg point, t_floatarg inc, t_floatarg f)
2378{
2379 vmess(&x->x_glist->gl_pd, gensym("xticks"), "fff", point, inc, f);
2380}
2381
2382static void garray_yticks(t_garray *x,
2383 t_floatarg point, t_floatarg inc, t_floatarg f)
2384{
2385 vmess(&x->x_glist->gl_pd, gensym("yticks"), "fff", point, inc, f);
2386}
2387
2388static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
2389{
2390 typedmess(&x->x_glist->gl_pd, s, argc, argv);
2391}
2392
2393static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
2394{
2395 typedmess(&x->x_glist->gl_pd, s, argc, argv);
2396}
2397 /* change the name of a garray. */
2398static void garray_rename(t_garray *x, t_symbol *s)
2399{
2400 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
2401 pd_bind(&x->x_gobj.g_pd, x->x_realname = x->x_name = s);
2402 garray_redraw(x);
2403}
2404
2405static void garray_read(t_garray *x, t_symbol *filename)
2406{
2407 int nelem = x->x_n, filedesc;
2408 FILE *fd;
2409 char buf[MAXPDSTRING], *bufptr;
2410 t_template *template = garray_template(x);
2411 int yonset, type, i;
2412 t_symbol *arraytype;
2413 if (!template_find_field(template, gensym("y"), &yonset,
2414 &type, &arraytype) || type != DT_FLOAT)
2415 {
2416 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
2417 return;
2418 }
2419 if ((filedesc = open_via_path(
2420 canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
2421 filename->s_name, "", buf, &bufptr, MAXPDSTRING, 0)) < 0
2422 || !(fd = fdopen(filedesc, "r")))
2423 {
2424 error("%s: can't open", filename->s_name);
2425 return;
2426 }
2427 for (i = 0; i < nelem; i++)
2428 {
2429 if (!fscanf(fd, "%f", (float *)((x->x_vec + sizeof(t_word) * i) +
2430 yonset)))
2431 {
2432 post("%s: read %d elements into table of size %d",
2433 filename->s_name, i, nelem);
2434 break;
2435 }
2436 }
2437 while (i < nelem)
2438 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = 0, i++;
2439 fclose(fd);
2440 garray_redraw(x);
2441}
2442
2443 /* this should be renamed and moved... */
2444int garray_ambigendian(void)
2445{
2446 unsigned short s = 1;
2447 unsigned char c = *(char *)(&s);
2448 return (c==0);
2449}
2450
2451#define BINREADMODE "rb"
2452#define BINWRITEMODE "wb"
2453
2454static void garray_read16(t_garray *x, t_symbol *filename,
2455 t_symbol *endian, t_floatarg fskip)
2456{
2457 int skip = fskip, filedesc;
2458 int i, nelem;
2459 t_sample *vec;
2460 FILE *fd;
2461 char buf[MAXPDSTRING], *bufptr;
2462 short s;
2463 int cpubig = garray_ambigendian(), swap = 0;
2464 char c = endian->s_name[0];
2465 if (c == 'b')
2466 {
2467 if (!cpubig) swap = 1;
2468 }
2469 else if (c == 'l')
2470 {
2471 if (cpubig) swap = 1;
2472 }
2473 else if (c)
2474 {
2475 error("array_read16: endianness is 'l' (low byte first ala INTEL)");
2476 post("... or 'b' (high byte first ala MIPS,DEC,PPC)");
2477 }
2478 if (!garray_getfloatarray(x, &nelem, &vec))
2479 {
2480 error("%s: not a float array", x->x_templatesym->s_name);
2481 return;
2482 }
2483 if ((filedesc = open_via_path(
2484 canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
2485 filename->s_name, "", buf, &bufptr, MAXPDSTRING, 1)) < 0
2486 || !(fd = fdopen(filedesc, BINREADMODE)))
2487 {
2488 error("%s: can't open", filename->s_name);
2489 return;
2490 }
2491 if (skip)
2492 {
2493 long pos = fseek(fd, (long)skip, SEEK_SET);
2494 if (pos < 0)
2495 {
2496 error("%s: can't seek to byte %d", buf, skip);
2497 fclose(fd);
2498 return;
2499 }
2500 }
2501
2502 for (i = 0; i < nelem; i++)
2503 {
2504 if (fread(&s, sizeof(s), 1, fd) < 1)
2505 {
2506 post("%s: read %d elements into table of size %d",
2507 filename->s_name, i, nelem);
2508 break;
2509 }
2510 if (swap) s = ((s & 0xff) << 8) | ((s & 0xff00) >> 8);
2511 vec[i] = s * (1./32768.);
2512 }
2513 while (i < nelem) vec[i++] = 0;
2514 fclose(fd);
2515 garray_redraw(x);
2516}
2517
2518static void garray_write(t_garray *x, t_symbol *filename)
2519{
2520 FILE *fd;
2521 char buf[MAXPDSTRING];
2522 t_template *template = garray_template(x);
2523 int yonset, type, i;
2524 t_symbol *arraytype;
2525 if (!template_find_field(template, gensym("y"), &yonset,
2526 &type, &arraytype) || type != DT_FLOAT)
2527 {
2528 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
2529 return;
2530 }
2531 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
2532 buf, MAXPDSTRING);
2533 sys_bashfilename(buf, buf);
2534 if (!(fd = fopen(buf, "w")))
2535 {
2536 error("%s: can't create", buf);
2537 return;
2538 }
2539 for (i = 0; i < x->x_n; i++)
2540 {
2541 if (fprintf(fd, "%g\n",
2542 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)) < 1)
2543 {
2544 post("%s: write error", filename->s_name);
2545 break;
2546 }
2547 }
2548 fclose(fd);
2549}
2550
2551static unsigned char waveheader[] = {
25520x52, 0x49, 0x46, 0x46,
25530x00, 0x00, 0x00, 0x00,
25540x57, 0x41, 0x56, 0x45,
25550x66, 0x6d, 0x74, 0x20,
2556
25570x10, 0x00, 0x00, 0x00,
25580x01, 0x00, 0x01, 0x00,
25590x44, 0xac, 0x00, 0x00,
25600x88, 0x58, 0x01, 0x00,
2561
25620x02, 0x00, 0x10, 0x00,
25630x64, 0x61, 0x74, 0x61,
25640x00, 0x00, 0x00, 0x00,
2565};
2566
2567 /* wave format only so far */
2568static void garray_write16(t_garray *x, t_symbol *filename, t_symbol *format)
2569{
2570 t_template *template = garray_template(x);
2571 int yonset, type, i;
2572 t_symbol *arraytype;
2573 FILE *fd;
2574 int aiff = (format == gensym("aiff"));
2575 char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
2576 int swap = garray_ambigendian(); /* wave is only little endian */
2577 int intbuf;
2578 strncpy(filenamebuf, filename->s_name, MAXPDSTRING-10);
2579 filenamebuf[MAXPDSTRING-10] = 0;
2580 if (sizeof(int) != 4) post("write16: only works on 32-bit machines");
2581 if (aiff)
2582 {
2583 if (strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
2584 strcat(filenamebuf, ".aiff");
2585 }
2586 else
2587 {
2588 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
2589 strcat(filenamebuf, ".wav");
2590 }
2591 if (!template_find_field(template, gensym("y"), &yonset,
2592 &type, &arraytype) || type != DT_FLOAT)
2593 {
2594 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
2595 return;
2596 }
2597 canvas_makefilename(glist_getcanvas(x->x_glist), filenamebuf,
2598 buf2, MAXPDSTRING);
2599 sys_bashfilename(buf2, buf2);
2600 if (!(fd = fopen(buf2, BINWRITEMODE)))
2601 {
2602 error("%s: can't create", buf2);
2603 return;
2604 }
2605 intbuf = 2 * x->x_n + 36;
2606 if (swap)
2607 {
2608 unsigned char *foo = (unsigned char *)&intbuf, xxx;
2609 xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
2610 xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
2611 }
2612 memcpy((void *)(waveheader + 4), (void *)(&intbuf), 4);
2613 intbuf = 2 * x->x_n;
2614 if (swap)
2615 {
2616 unsigned char *foo = (unsigned char *)&intbuf, xxx;
2617 xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
2618 xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
2619 }
2620 memcpy((void *)(waveheader + 40), (void *)(&intbuf), 4);
2621 if (fwrite(waveheader, sizeof(waveheader), 1, fd) < 1)
2622 {
2623 post("%s: write error", buf2);
2624 goto closeit;
2625 }
2626 for (i = 0; i < x->x_n; i++)
2627 {
2628 float f = 32767. * *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
2629 short sh;
2630 if (f < -32768) f = -32768;
2631 else if (f > 32767) f = 32767;
2632 sh = f;
2633 if (swap)
2634 {
2635 unsigned char *foo = (unsigned char *)&sh, xxx;
2636 xxx = foo[0]; foo[0] = foo[1]; foo[1] = xxx;
2637 }
2638 if (fwrite(&sh, sizeof(sh), 1, fd) < 1)
2639 {
2640 post("%s: write error", buf2);
2641 goto closeit;
2642 }
2643 }
2644closeit:
2645 fclose(fd);
2646}
2647
2648void garray_resize(t_garray *x, t_floatarg f)
2649{
2650 int was = x->x_n, elemsize;
2651 t_glist *gl;
2652 int dspwas;
2653 int n = f;
2654 char *nvec;
2655
2656 if (n < 1) n = 1;
2657 elemsize = template_findbyname(x->x_templatesym)->t_n * sizeof(t_word);
2658 nvec = t_resizebytes(x->x_vec, was * elemsize, n * elemsize);
2659 if (!nvec)
2660 {
2661 pd_error(x, "array resize failed: out of memory");
2662 return;
2663 }
2664 x->x_vec = nvec;
2665 /* LATER should check t_resizebytes result */
2666 if (n > was)
2667 memset(x->x_vec + was*elemsize,
2668 0, (n - was) * elemsize);
2669 x->x_n = n;
2670
2671 /* if this is the only array in the graph,
2672 reset the graph's coordinates */
2673 gl = x->x_glist;
2674 if (gl->gl_list == &x->x_gobj && !x->x_gobj.g_next)
2675 {
2676 vmess(&gl->gl_pd, gensym("bounds"), "ffff",
2677 0., gl->gl_y1, (double)(n > 1 ? n-1 : 1), gl->gl_y2);
2678 /* close any dialogs that might have the wrong info now... */
2679 gfxstub_deleteforkey(gl);
2680 }
2681 else garray_redraw(x);
2682 if (x->x_usedindsp) canvas_update_dsp();
2683}
2684
2685static void garray_print(t_garray *x)
2686{
2687 post("garray %s: template %s, length %d",
2688 x->x_name->s_name, x->x_templatesym->s_name, x->x_n);
2689}
2690
2691void g_array_setup(void)
2692{
2693 garray_class = class_new(gensym("array"), 0, (t_method)garray_free,
2694 sizeof(t_garray), CLASS_GOBJ, 0);
2695 class_setwidget(garray_class, &garray_widgetbehavior);
2696 class_addmethod(garray_class, (t_method)garray_const, gensym("const"),
2697 A_DEFFLOAT, A_NULL);
2698 class_addlist(garray_class, garray_list);
2699 class_addmethod(garray_class, (t_method)garray_bounds, gensym("bounds"),
2700 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2701 class_addmethod(garray_class, (t_method)garray_xticks, gensym("xticks"),
2702 A_FLOAT, A_FLOAT, A_FLOAT, 0);
2703 class_addmethod(garray_class, (t_method)garray_xlabel, gensym("xlabel"),
2704 A_GIMME, 0);
2705 class_addmethod(garray_class, (t_method)garray_yticks, gensym("yticks"),
2706 A_FLOAT, A_FLOAT, A_FLOAT, 0);
2707 class_addmethod(garray_class, (t_method)garray_ylabel, gensym("ylabel"),
2708 A_GIMME, 0);
2709 class_addmethod(garray_class, (t_method)garray_rename, gensym("rename"),
2710 A_SYMBOL, 0);
2711 class_addmethod(garray_class, (t_method)garray_read, gensym("read"),
2712 A_SYMBOL, A_NULL);
2713 class_addmethod(garray_class, (t_method)garray_read16, gensym("read16"),
2714 A_SYMBOL, A_DEFFLOAT, A_DEFSYM, A_NULL);
2715 class_addmethod(garray_class, (t_method)garray_write, gensym("write"),
2716 A_SYMBOL, A_NULL);
2717 class_addmethod(garray_class, (t_method)garray_write16, gensym("write16"),
2718 A_SYMBOL, A_DEFSYM, A_NULL);
2719 class_addmethod(garray_class, (t_method)garray_resize, gensym("resize"),
2720 A_FLOAT, A_NULL);
2721 class_addmethod(garray_class, (t_method)garray_print, gensym("print"),
2722 A_NULL);
2723 class_addmethod(garray_class, (t_method)garray_sinesum, gensym("sinesum"),
2724 A_GIMME, 0);
2725 class_addmethod(garray_class, (t_method)garray_cosinesum,
2726 gensym("cosinesum"), A_GIMME, 0);
2727 class_addmethod(garray_class, (t_method)garray_normalize,
2728 gensym("normalize"), A_DEFFLOAT, 0);
2729 class_addmethod(garray_class, (t_method)garray_arraydialog,
2730 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2731 class_setsavefn(garray_class, garray_save);
2732}
2733
2734
diff --git a/apps/plugins/pdbox/PDa/src/g_bang.c b/apps/plugins/pdbox/PDa/src/g_bang.c
new file mode 100644
index 0000000000..c676bf8675
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_bang.c
@@ -0,0 +1,1108 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
7
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <ctype.h>
13#include "m_pd.h"
14#include "g_canvas.h"
15#include "t_tk.h"
16#include "g_all_guis.h"
17#include <math.h>
18
19#ifdef MSW
20#include <io.h>
21#else
22#include <unistd.h>
23#endif
24
25
26/* --------------- bng gui-bang ------------------------- */
27
28t_widgetbehavior bng_widgetbehavior;
29static t_class *bng_class;
30
31/* widget helper functions */
32
33
34void bng_draw_update(t_bng *x, t_glist *glist)
35{
36 if(glist_isvisible(glist))
37 {
38 sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", glist_getcanvas(glist), x,
39 x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
40 }
41}
42
43void bng_draw_new(t_bng *x, t_glist *glist)
44{
45 int xpos=text_xpix(&x->x_gui.x_obj, glist);
46 int ypos=text_ypix(&x->x_gui.x_obj, glist);
47 t_canvas *canvas=glist_getcanvas(glist);
48
49 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
50 canvas, xpos, ypos,
51 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h,
52 x->x_gui.x_bcol, x);
53 sys_vgui(".x%x.c create oval %d %d %d %d -fill #%6.6x -tags %xBUT\n",
54 canvas, xpos+1, ypos+1,
55 xpos + x->x_gui.x_w-1, ypos + x->x_gui.x_h-1,
56 x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
57 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
58 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
59 canvas, xpos+x->x_gui.x_ldx,
60 ypos+x->x_gui.x_ldy,
61 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
62 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
63 if(!x->x_gui.x_fsf.x_snd_able)
64 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
65 canvas, xpos,
66 ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
67 ypos + x->x_gui.x_h, x, 0);
68 if(!x->x_gui.x_fsf.x_rcv_able)
69 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
70 canvas, xpos, ypos,
71 xpos + IOWIDTH, ypos+1, x, 0);
72}
73
74void bng_draw_move(t_bng *x, t_glist *glist)
75{
76 int xpos=text_xpix(&x->x_gui.x_obj, glist);
77 int ypos=text_ypix(&x->x_gui.x_obj, glist);
78 t_canvas *canvas=glist_getcanvas(glist);
79
80 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
81 canvas, x, xpos, ypos,
82 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h);
83 sys_vgui(".x%x.c coords %xBUT %d %d %d %d\n",
84 canvas, x, xpos+1,ypos+1,
85 xpos + x->x_gui.x_w-1, ypos + x->x_gui.x_h-1);
86 sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", canvas, x,
87 x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
88 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
89 canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
90 if(!x->x_gui.x_fsf.x_snd_able)
91 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
92 canvas, x, 0, xpos,
93 ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
94 ypos + x->x_gui.x_h);
95 if(!x->x_gui.x_fsf.x_rcv_able)
96 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
97 canvas, x, 0, xpos, ypos,
98 xpos + IOWIDTH, ypos+1);
99}
100
101void bng_draw_erase(t_bng* x, t_glist* glist)
102{
103 t_canvas *canvas=glist_getcanvas(glist);
104
105 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
106 sys_vgui(".x%x.c delete %xBUT\n", canvas, x);
107 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
108 if(!x->x_gui.x_fsf.x_snd_able)
109 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
110 if(!x->x_gui.x_fsf.x_rcv_able)
111 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
112}
113
114void bng_draw_config(t_bng* x, t_glist* glist)
115{
116 t_canvas *canvas=glist_getcanvas(glist);
117
118 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
119 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
120 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
121 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
122 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
123 sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", canvas, x,
124 x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
125}
126
127void bng_draw_io(t_bng* x, t_glist* glist, int old_snd_rcv_flags)
128{
129 int xpos=text_xpix(&x->x_gui.x_obj, glist);
130 int ypos=text_ypix(&x->x_gui.x_obj, glist);
131 t_canvas *canvas=glist_getcanvas(glist);
132
133 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
134 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
135 canvas, xpos,
136 ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
137 ypos + x->x_gui.x_h, x, 0);
138 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
139 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
140 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
141 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
142 canvas, xpos, ypos,
143 xpos + IOWIDTH, ypos+1, x, 0);
144 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
145 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
146}
147
148void bng_draw_select(t_bng* x, t_glist* glist)
149{
150 t_canvas *canvas=glist_getcanvas(glist);
151
152 if(x->x_gui.x_fsf.x_selected)
153 {
154 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
155 sys_vgui(".x%x.c itemconfigure %xBUT -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
156 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
157 }
158 else
159 {
160 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
161 sys_vgui(".x%x.c itemconfigure %xBUT -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
162 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
163 }
164}
165
166void bng_draw(t_bng *x, t_glist *glist, int mode)
167{
168 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
169 bng_draw_update(x, glist);
170 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
171 bng_draw_move(x, glist);
172 else if(mode == IEM_GUI_DRAW_MODE_NEW)
173 bng_draw_new(x, glist);
174 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
175 bng_draw_select(x, glist);
176 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
177 bng_draw_erase(x, glist);
178 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
179 bng_draw_config(x, glist);
180 else if(mode >= IEM_GUI_DRAW_MODE_IO)
181 bng_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
182}
183
184/* ------------------------ bng widgetbehaviour----------------------------- */
185
186static void bng_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
187{
188 t_bng *x = (t_bng *)z;
189
190 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
191 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
192 *xp2 = *xp1 + x->x_gui.x_w;
193 *yp2 = *yp1 + x->x_gui.x_h;
194}
195
196static void bng_save(t_gobj *z, t_binbuf *b)
197{
198 t_bng *x = (t_bng *)z;
199 int bflcol[3];
200 t_symbol *srl[3];
201
202 iemgui_save(&x->x_gui, srl, bflcol);
203 binbuf_addv(b, "ssiisiiiisssiiiiiii", gensym("#X"),gensym("obj"),
204 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
205 gensym("bng"), x->x_gui.x_w,
206 x->x_flashtime_hold, x->x_flashtime_break,
207 iem_symargstoint(&x->x_gui.x_isa),
208 srl[0], srl[1], srl[2],
209 x->x_gui.x_ldx, x->x_gui.x_ldy,
210 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
211 bflcol[0], bflcol[1], bflcol[2]);
212 binbuf_addv(b, ";");
213}
214
215void bng_check_minmax(t_bng *x, int ftbreak, int fthold)
216{
217 if(ftbreak > fthold)
218 {
219 int h;
220
221 h = ftbreak;
222 ftbreak = fthold;
223 fthold = h;
224 }
225 if(ftbreak < IEM_BNG_MINBREAKFLASHTIME)
226 ftbreak = IEM_BNG_MINBREAKFLASHTIME;
227 if(fthold < IEM_BNG_MINHOLDFLASHTIME)
228 fthold = IEM_BNG_MINHOLDFLASHTIME;
229 x->x_flashtime_break = ftbreak;
230 x->x_flashtime_hold = fthold;
231}
232
233static void bng_properties(t_gobj *z, t_glist *owner)
234{
235 t_bng *x = (t_bng *)z;
236 char buf[800];
237 t_symbol *srl[3];
238
239 iemgui_properties(&x->x_gui, srl);
240 sprintf(buf, "pdtk_iemgui_dialog %%s BANG \
241 ----------dimensions(pix):----------- %d %d size: 0 0 empty \
242 --------flash-time(ms)(ms):--------- %d intrrpt: %d hold: %d \
243 %d empty empty %d %d empty %d \
244 %s %s \
245 %s %d %d \
246 %d %d \
247 %d %d %d\n",
248 x->x_gui.x_w, IEM_GUI_MINSIZE,
249 x->x_flashtime_break, x->x_flashtime_hold, 2,/*min_max_schedule+clip*/
250 -1, x->x_gui.x_isa.x_loadinit, -1, -1,/*no linlog, no multi*/
251 srl[0]->s_name, srl[1]->s_name,
252 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
253 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
254 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
255 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
256}
257
258static void bng_set(t_bng *x)
259{
260 if(x->x_flashed)
261 {
262 x->x_flashed = 0;
263 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
264 clock_delay(x->x_clock_brk, x->x_flashtime_break);
265 x->x_flashed = 1;
266 }
267 else
268 {
269 x->x_flashed = 1;
270 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
271 }
272 clock_delay(x->x_clock_hld, x->x_flashtime_hold);
273}
274
275static void bng_bout1(t_bng *x)/*wird nur mehr gesendet, wenn snd != rcv*/
276{
277 if(!x->x_gui.x_fsf.x_put_in2out)
278 {
279 x->x_gui.x_isa.x_locked = 1;
280 clock_delay(x->x_clock_lck, 2);
281 }
282 outlet_bang(x->x_gui.x_obj.ob_outlet);
283 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing && x->x_gui.x_fsf.x_put_in2out)
284 pd_bang(x->x_gui.x_snd->s_thing);
285}
286
287static void bng_bout2(t_bng *x)/*wird immer gesendet, wenn moeglich*/
288{
289 if(!x->x_gui.x_fsf.x_put_in2out)
290 {
291 x->x_gui.x_isa.x_locked = 1;
292 clock_delay(x->x_clock_lck, 2);
293 }
294 outlet_bang(x->x_gui.x_obj.ob_outlet);
295 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
296 pd_bang(x->x_gui.x_snd->s_thing);
297}
298
299static void bng_bang(t_bng *x)/*wird nur mehr gesendet, wenn snd != rcv*/
300{
301 if(!x->x_gui.x_isa.x_locked)
302 {
303 bng_set(x);
304 bng_bout1(x);
305 }
306}
307
308static void bng_bang2(t_bng *x)/*wird immer gesendet, wenn moeglich*/
309{
310 if(!x->x_gui.x_isa.x_locked)
311 {
312 bng_set(x);
313 bng_bout2(x);
314 }
315}
316
317static void bng_dialog(t_bng *x, t_symbol *s, int argc, t_atom *argv)
318{
319 t_symbol *srl[3];
320 int a = (int)atom_getintarg(0, argc, argv);
321 int fthold = (int)atom_getintarg(2, argc, argv);
322 int ftbreak = (int)atom_getintarg(3, argc, argv);
323 int sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
324
325 x->x_gui.x_w = iemgui_clip_size(a);
326 x->x_gui.x_h = x->x_gui.x_w;
327 bng_check_minmax(x, ftbreak, fthold);
328 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
329 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
330 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
331 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
332}
333
334static void bng_click(t_bng *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
335{
336 bng_set(x);
337 bng_bout2(x);
338}
339
340static int bng_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
341{
342 if(doit)
343 bng_click((t_bng *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
344 return (1);
345}
346
347static void bng_float(t_bng *x, t_floatarg f)
348{bng_bang2(x);}
349
350static void bng_symbol(t_bng *x, t_symbol *s)
351{bng_bang2(x);}
352
353static void bng_pointer(t_bng *x, t_gpointer *gp)
354{bng_bang2(x);}
355
356static void bng_list(t_bng *x, t_symbol *s, int ac, t_atom *av)
357{
358 bng_bang2(x);
359}
360
361static void bng_anything(t_bng *x, t_symbol *s, int argc, t_atom *argv)
362{bng_bang2(x);}
363
364static void bng_loadbang(t_bng *x)
365{
366 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
367 {
368 bng_set(x);
369 bng_bout2(x);
370 }
371}
372
373static void bng_size(t_bng *x, t_symbol *s, int ac, t_atom *av)
374{
375 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
376 x->x_gui.x_h = x->x_gui.x_w;
377 iemgui_size((void *)x, &x->x_gui);
378}
379
380static void bng_delta(t_bng *x, t_symbol *s, int ac, t_atom *av)
381{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
382
383static void bng_pos(t_bng *x, t_symbol *s, int ac, t_atom *av)
384{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
385
386static void bng_flashtime(t_bng *x, t_symbol *s, int ac, t_atom *av)
387{
388 bng_check_minmax(x, (int)atom_getintarg(0, ac, av),
389 (int)atom_getintarg(1, ac, av));
390}
391
392static void bng_color(t_bng *x, t_symbol *s, int ac, t_atom *av)
393{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
394
395static void bng_send(t_bng *x, t_symbol *s)
396{iemgui_send(x, &x->x_gui, s);}
397
398static void bng_receive(t_bng *x, t_symbol *s)
399{iemgui_receive(x, &x->x_gui, s);}
400
401static void bng_label(t_bng *x, t_symbol *s)
402{iemgui_label((void *)x, &x->x_gui, s);}
403
404static void bng_label_pos(t_bng *x, t_symbol *s, int ac, t_atom *av)
405{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
406
407static void bng_label_font(t_bng *x, t_symbol *s, int ac, t_atom *av)
408{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
409
410static void bng_init(t_bng *x, t_floatarg f)
411{
412 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
413}
414
415static void bng_tick_hld(t_bng *x)
416{
417 x->x_flashed = 0;
418 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
419}
420
421static void bng_tick_brk(t_bng *x)
422{
423 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
424}
425
426static void bng_tick_lck(t_bng *x)
427{
428 x->x_gui.x_isa.x_locked = 0;
429}
430
431static void *bng_new(t_symbol *s, int argc, t_atom *argv)
432{
433 t_bng *x = (t_bng *)pd_new(bng_class);
434 int bflcol[]={-262144, -1, -1};
435 int a=IEM_GUI_DEFAULTSIZE;
436 int ldx=0, ldy=-6;
437 int fs=8;
438 int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME,
439 fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
440 char str[144];
441
442 iem_inttosymargs(&x->x_gui.x_isa, 0);
443 iem_inttofstyle(&x->x_gui.x_fsf, 0);
444
445 if((argc == 14)&&IS_A_FLOAT(argv,0)
446 &&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
447 &&IS_A_FLOAT(argv,3)
448 &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
449 &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
450 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
451 &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
452 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
453 &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13))
454 {
455
456 a = (int)atom_getintarg(0, argc, argv);
457 fthold = (int)atom_getintarg(1, argc, argv);
458 ftbreak = (int)atom_getintarg(2, argc, argv);
459 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(3, argc, argv));
460 iemgui_new_getnames(&x->x_gui, 4, argv);
461 ldx = (int)atom_getintarg(7, argc, argv);
462 ldy = (int)atom_getintarg(8, argc, argv);
463 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv));
464 fs = (int)atom_getintarg(10, argc, argv);
465 bflcol[0] = (int)atom_getintarg(11, argc, argv);
466 bflcol[1] = (int)atom_getintarg(12, argc, argv);
467 bflcol[2] = (int)atom_getintarg(13, argc, argv);
468 }
469 else iemgui_new_getnames(&x->x_gui, 4, 0);
470
471 x->x_gui.x_draw = (t_iemfunptr)bng_draw;
472
473 x->x_gui.x_fsf.x_snd_able = 1;
474 x->x_gui.x_fsf.x_rcv_able = 1;
475 x->x_flashed = 0;
476 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
477 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
478 x->x_gui.x_fsf.x_snd_able = 0;
479 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
480 x->x_gui.x_fsf.x_rcv_able = 0;
481 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
482 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
483 else { x->x_gui.x_fsf.x_font_style = 0;
484 strcpy(x->x_gui.x_font, "courier"); }
485
486 if (x->x_gui.x_fsf.x_rcv_able)
487 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
488 x->x_gui.x_ldx = ldx;
489 x->x_gui.x_ldy = ldy;
490
491 if(fs < 4)
492 fs = 4;
493 x->x_gui.x_fontsize = fs;
494 x->x_gui.x_w = iemgui_clip_size(a);
495 x->x_gui.x_h = x->x_gui.x_w;
496 bng_check_minmax(x, ftbreak, fthold);
497 iemgui_all_colfromload(&x->x_gui, bflcol);
498 x->x_gui.x_isa.x_locked = 0;
499 iemgui_verify_snd_ne_rcv(&x->x_gui);
500 x->x_clock_hld = clock_new(x, (t_method)bng_tick_hld);
501 x->x_clock_brk = clock_new(x, (t_method)bng_tick_brk);
502 x->x_clock_lck = clock_new(x, (t_method)bng_tick_lck);
503 outlet_new(&x->x_gui.x_obj, &s_bang);
504 return (x);
505}
506
507static void bng_ff(t_bng *x)
508{
509 if(x->x_gui.x_fsf.x_rcv_able)
510 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
511 clock_free(x->x_clock_lck);
512 clock_free(x->x_clock_brk);
513 clock_free(x->x_clock_hld);
514 gfxstub_deleteforkey(x);
515}
516
517void g_bang_setup(void)
518{
519 bng_class = class_new(gensym("bng"), (t_newmethod)bng_new,
520 (t_method)bng_ff, sizeof(t_bng), 0, A_GIMME, 0);
521 class_addbang(bng_class, bng_bang);
522 class_addfloat(bng_class, bng_float);
523 class_addsymbol(bng_class, bng_symbol);
524 class_addpointer(bng_class, bng_pointer);
525 class_addlist(bng_class, bng_list);
526 class_addanything(bng_class, bng_anything);
527 class_addmethod(bng_class, (t_method)bng_click, gensym("click"),
528 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
529 class_addmethod(bng_class, (t_method)bng_dialog, gensym("dialog"),
530 A_GIMME, 0);
531 class_addmethod(bng_class, (t_method)bng_loadbang, gensym("loadbang"), 0);
532 class_addmethod(bng_class, (t_method)bng_size, gensym("size"), A_GIMME, 0);
533 class_addmethod(bng_class, (t_method)bng_delta, gensym("delta"), A_GIMME, 0);
534 class_addmethod(bng_class, (t_method)bng_pos, gensym("pos"), A_GIMME, 0);
535 class_addmethod(bng_class, (t_method)bng_flashtime, gensym("flashtime"), A_GIMME, 0);
536 class_addmethod(bng_class, (t_method)bng_color, gensym("color"), A_GIMME, 0);
537 class_addmethod(bng_class, (t_method)bng_send, gensym("send"), A_DEFSYM, 0);
538 class_addmethod(bng_class, (t_method)bng_receive, gensym("receive"), A_DEFSYM, 0);
539 class_addmethod(bng_class, (t_method)bng_label, gensym("label"), A_DEFSYM, 0);
540 class_addmethod(bng_class, (t_method)bng_label_pos, gensym("label_pos"), A_GIMME, 0);
541 class_addmethod(bng_class, (t_method)bng_label_font, gensym("label_font"), A_GIMME, 0);
542 class_addmethod(bng_class, (t_method)bng_init, gensym("init"), A_FLOAT, 0);
543 bng_widgetbehavior.w_getrectfn = bng_getrect;
544 bng_widgetbehavior.w_displacefn = iemgui_displace;
545 bng_widgetbehavior.w_selectfn = iemgui_select;
546 bng_widgetbehavior.w_activatefn = NULL;
547 bng_widgetbehavior.w_deletefn = iemgui_delete;
548 bng_widgetbehavior.w_visfn = iemgui_vis;
549 bng_widgetbehavior.w_clickfn = bng_newclick;
550 class_setwidget(bng_class, &bng_widgetbehavior);
551 class_sethelpsymbol(bng_class, gensym("bng"));
552 class_setsavefn(bng_class, bng_save);
553 class_setpropertiesfn(bng_class, bng_properties);
554}
555/* Copyright (c) 1997-1999 Miller Puckette.
556 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
557 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
558
559/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
560/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
561
562
563#include <stdlib.h>
564#include <string.h>
565#include <stdio.h>
566#include <ctype.h>
567#include "m_pd.h"
568#include "g_canvas.h"
569#include "t_tk.h"
570#include "g_all_guis.h"
571#include <math.h>
572
573#ifdef MSW
574#include <io.h>
575#else
576#include <unistd.h>
577#endif
578
579
580/* --------------- bng gui-bang ------------------------- */
581
582t_widgetbehavior bng_widgetbehavior;
583static t_class *bng_class;
584
585/* widget helper functions */
586
587
588void bng_draw_update(t_bng *x, t_glist *glist)
589{
590 if(glist_isvisible(glist))
591 {
592 sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", glist_getcanvas(glist), x,
593 x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
594 }
595}
596
597void bng_draw_new(t_bng *x, t_glist *glist)
598{
599 int xpos=text_xpix(&x->x_gui.x_obj, glist);
600 int ypos=text_ypix(&x->x_gui.x_obj, glist);
601 t_canvas *canvas=glist_getcanvas(glist);
602
603 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
604 canvas, xpos, ypos,
605 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h,
606 x->x_gui.x_bcol, x);
607 sys_vgui(".x%x.c create oval %d %d %d %d -fill #%6.6x -tags %xBUT\n",
608 canvas, xpos+1, ypos+1,
609 xpos + x->x_gui.x_w-1, ypos + x->x_gui.x_h-1,
610 x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
611 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
612 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
613 canvas, xpos+x->x_gui.x_ldx,
614 ypos+x->x_gui.x_ldy,
615 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
616 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
617 if(!x->x_gui.x_fsf.x_snd_able)
618 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
619 canvas, xpos,
620 ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
621 ypos + x->x_gui.x_h, x, 0);
622 if(!x->x_gui.x_fsf.x_rcv_able)
623 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
624 canvas, xpos, ypos,
625 xpos + IOWIDTH, ypos+1, x, 0);
626}
627
628void bng_draw_move(t_bng *x, t_glist *glist)
629{
630 int xpos=text_xpix(&x->x_gui.x_obj, glist);
631 int ypos=text_ypix(&x->x_gui.x_obj, glist);
632 t_canvas *canvas=glist_getcanvas(glist);
633
634 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
635 canvas, x, xpos, ypos,
636 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h);
637 sys_vgui(".x%x.c coords %xBUT %d %d %d %d\n",
638 canvas, x, xpos+1,ypos+1,
639 xpos + x->x_gui.x_w-1, ypos + x->x_gui.x_h-1);
640 sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", canvas, x,
641 x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
642 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
643 canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
644 if(!x->x_gui.x_fsf.x_snd_able)
645 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
646 canvas, x, 0, xpos,
647 ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
648 ypos + x->x_gui.x_h);
649 if(!x->x_gui.x_fsf.x_rcv_able)
650 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
651 canvas, x, 0, xpos, ypos,
652 xpos + IOWIDTH, ypos+1);
653}
654
655void bng_draw_erase(t_bng* x, t_glist* glist)
656{
657 t_canvas *canvas=glist_getcanvas(glist);
658
659 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
660 sys_vgui(".x%x.c delete %xBUT\n", canvas, x);
661 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
662 if(!x->x_gui.x_fsf.x_snd_able)
663 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
664 if(!x->x_gui.x_fsf.x_rcv_able)
665 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
666}
667
668void bng_draw_config(t_bng* x, t_glist* glist)
669{
670 t_canvas *canvas=glist_getcanvas(glist);
671
672 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
673 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
674 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
675 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
676 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
677 sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", canvas, x,
678 x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
679}
680
681void bng_draw_io(t_bng* x, t_glist* glist, int old_snd_rcv_flags)
682{
683 int xpos=text_xpix(&x->x_gui.x_obj, glist);
684 int ypos=text_ypix(&x->x_gui.x_obj, glist);
685 t_canvas *canvas=glist_getcanvas(glist);
686
687 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
688 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
689 canvas, xpos,
690 ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
691 ypos + x->x_gui.x_h, x, 0);
692 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
693 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
694 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
695 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
696 canvas, xpos, ypos,
697 xpos + IOWIDTH, ypos+1, x, 0);
698 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
699 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
700}
701
702void bng_draw_select(t_bng* x, t_glist* glist)
703{
704 t_canvas *canvas=glist_getcanvas(glist);
705
706 if(x->x_gui.x_fsf.x_selected)
707 {
708 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
709 sys_vgui(".x%x.c itemconfigure %xBUT -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
710 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
711 }
712 else
713 {
714 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
715 sys_vgui(".x%x.c itemconfigure %xBUT -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
716 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
717 }
718}
719
720void bng_draw(t_bng *x, t_glist *glist, int mode)
721{
722 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
723 bng_draw_update(x, glist);
724 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
725 bng_draw_move(x, glist);
726 else if(mode == IEM_GUI_DRAW_MODE_NEW)
727 bng_draw_new(x, glist);
728 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
729 bng_draw_select(x, glist);
730 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
731 bng_draw_erase(x, glist);
732 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
733 bng_draw_config(x, glist);
734 else if(mode >= IEM_GUI_DRAW_MODE_IO)
735 bng_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
736}
737
738/* ------------------------ bng widgetbehaviour----------------------------- */
739
740static void bng_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
741{
742 t_bng *x = (t_bng *)z;
743
744 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
745 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
746 *xp2 = *xp1 + x->x_gui.x_w;
747 *yp2 = *yp1 + x->x_gui.x_h;
748}
749
750static void bng_save(t_gobj *z, t_binbuf *b)
751{
752 t_bng *x = (t_bng *)z;
753 int bflcol[3];
754 t_symbol *srl[3];
755
756 iemgui_save(&x->x_gui, srl, bflcol);
757 binbuf_addv(b, "ssiisiiiisssiiiiiii", gensym("#X"),gensym("obj"),
758 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
759 gensym("bng"), x->x_gui.x_w,
760 x->x_flashtime_hold, x->x_flashtime_break,
761 iem_symargstoint(&x->x_gui.x_isa),
762 srl[0], srl[1], srl[2],
763 x->x_gui.x_ldx, x->x_gui.x_ldy,
764 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
765 bflcol[0], bflcol[1], bflcol[2]);
766 binbuf_addv(b, ";");
767}
768
769void bng_check_minmax(t_bng *x, int ftbreak, int fthold)
770{
771 if(ftbreak > fthold)
772 {
773 int h;
774
775 h = ftbreak;
776 ftbreak = fthold;
777 fthold = h;
778 }
779 if(ftbreak < IEM_BNG_MINBREAKFLASHTIME)
780 ftbreak = IEM_BNG_MINBREAKFLASHTIME;
781 if(fthold < IEM_BNG_MINHOLDFLASHTIME)
782 fthold = IEM_BNG_MINHOLDFLASHTIME;
783 x->x_flashtime_break = ftbreak;
784 x->x_flashtime_hold = fthold;
785}
786
787static void bng_properties(t_gobj *z, t_glist *owner)
788{
789 t_bng *x = (t_bng *)z;
790 char buf[800];
791 t_symbol *srl[3];
792
793 iemgui_properties(&x->x_gui, srl);
794 sprintf(buf, "pdtk_iemgui_dialog %%s BANG \
795 ----------dimensions(pix):----------- %d %d size: 0 0 empty \
796 --------flash-time(ms)(ms):--------- %d intrrpt: %d hold: %d \
797 %d empty empty %d %d empty %d \
798 %s %s \
799 %s %d %d \
800 %d %d \
801 %d %d %d\n",
802 x->x_gui.x_w, IEM_GUI_MINSIZE,
803 x->x_flashtime_break, x->x_flashtime_hold, 2,/*min_max_schedule+clip*/
804 -1, x->x_gui.x_isa.x_loadinit, -1, -1,/*no linlog, no multi*/
805 srl[0]->s_name, srl[1]->s_name,
806 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
807 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
808 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
809 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
810}
811
812static void bng_set(t_bng *x)
813{
814 if(x->x_flashed)
815 {
816 x->x_flashed = 0;
817 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
818 clock_delay(x->x_clock_brk, x->x_flashtime_break);
819 x->x_flashed = 1;
820 }
821 else
822 {
823 x->x_flashed = 1;
824 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
825 }
826 clock_delay(x->x_clock_hld, x->x_flashtime_hold);
827}
828
829static void bng_bout1(t_bng *x)/*wird nur mehr gesendet, wenn snd != rcv*/
830{
831 if(!x->x_gui.x_fsf.x_put_in2out)
832 {
833 x->x_gui.x_isa.x_locked = 1;
834 clock_delay(x->x_clock_lck, 2);
835 }
836 outlet_bang(x->x_gui.x_obj.ob_outlet);
837 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing && x->x_gui.x_fsf.x_put_in2out)
838 pd_bang(x->x_gui.x_snd->s_thing);
839}
840
841static void bng_bout2(t_bng *x)/*wird immer gesendet, wenn moeglich*/
842{
843 if(!x->x_gui.x_fsf.x_put_in2out)
844 {
845 x->x_gui.x_isa.x_locked = 1;
846 clock_delay(x->x_clock_lck, 2);
847 }
848 outlet_bang(x->x_gui.x_obj.ob_outlet);
849 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
850 pd_bang(x->x_gui.x_snd->s_thing);
851}
852
853static void bng_bang(t_bng *x)/*wird nur mehr gesendet, wenn snd != rcv*/
854{
855 if(!x->x_gui.x_isa.x_locked)
856 {
857 bng_set(x);
858 bng_bout1(x);
859 }
860}
861
862static void bng_bang2(t_bng *x)/*wird immer gesendet, wenn moeglich*/
863{
864 if(!x->x_gui.x_isa.x_locked)
865 {
866 bng_set(x);
867 bng_bout2(x);
868 }
869}
870
871static void bng_dialog(t_bng *x, t_symbol *s, int argc, t_atom *argv)
872{
873 t_symbol *srl[3];
874 int a = (int)atom_getintarg(0, argc, argv);
875 int fthold = (int)atom_getintarg(2, argc, argv);
876 int ftbreak = (int)atom_getintarg(3, argc, argv);
877 int sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
878
879 x->x_gui.x_w = iemgui_clip_size(a);
880 x->x_gui.x_h = x->x_gui.x_w;
881 bng_check_minmax(x, ftbreak, fthold);
882 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
883 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
884 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
885 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
886}
887
888static void bng_click(t_bng *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
889{
890 bng_set(x);
891 bng_bout2(x);
892}
893
894static int bng_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
895{
896 if(doit)
897 bng_click((t_bng *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
898 return (1);
899}
900
901static void bng_float(t_bng *x, t_floatarg f)
902{bng_bang2(x);}
903
904static void bng_symbol(t_bng *x, t_symbol *s)
905{bng_bang2(x);}
906
907static void bng_pointer(t_bng *x, t_gpointer *gp)
908{bng_bang2(x);}
909
910static void bng_list(t_bng *x, t_symbol *s, int ac, t_atom *av)
911{
912 bng_bang2(x);
913}
914
915static void bng_anything(t_bng *x, t_symbol *s, int argc, t_atom *argv)
916{bng_bang2(x);}
917
918static void bng_loadbang(t_bng *x)
919{
920 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
921 {
922 bng_set(x);
923 bng_bout2(x);
924 }
925}
926
927static void bng_size(t_bng *x, t_symbol *s, int ac, t_atom *av)
928{
929 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
930 x->x_gui.x_h = x->x_gui.x_w;
931 iemgui_size((void *)x, &x->x_gui);
932}
933
934static void bng_delta(t_bng *x, t_symbol *s, int ac, t_atom *av)
935{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
936
937static void bng_pos(t_bng *x, t_symbol *s, int ac, t_atom *av)
938{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
939
940static void bng_flashtime(t_bng *x, t_symbol *s, int ac, t_atom *av)
941{
942 bng_check_minmax(x, (int)atom_getintarg(0, ac, av),
943 (int)atom_getintarg(1, ac, av));
944}
945
946static void bng_color(t_bng *x, t_symbol *s, int ac, t_atom *av)
947{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
948
949static void bng_send(t_bng *x, t_symbol *s)
950{iemgui_send(x, &x->x_gui, s);}
951
952static void bng_receive(t_bng *x, t_symbol *s)
953{iemgui_receive(x, &x->x_gui, s);}
954
955static void bng_label(t_bng *x, t_symbol *s)
956{iemgui_label((void *)x, &x->x_gui, s);}
957
958static void bng_label_pos(t_bng *x, t_symbol *s, int ac, t_atom *av)
959{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
960
961static void bng_label_font(t_bng *x, t_symbol *s, int ac, t_atom *av)
962{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
963
964static void bng_init(t_bng *x, t_floatarg f)
965{
966 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
967}
968
969static void bng_tick_hld(t_bng *x)
970{
971 x->x_flashed = 0;
972 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
973}
974
975static void bng_tick_brk(t_bng *x)
976{
977 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
978}
979
980static void bng_tick_lck(t_bng *x)
981{
982 x->x_gui.x_isa.x_locked = 0;
983}
984
985static void *bng_new(t_symbol *s, int argc, t_atom *argv)
986{
987 t_bng *x = (t_bng *)pd_new(bng_class);
988 int bflcol[]={-262144, -1, -1};
989 int a=IEM_GUI_DEFAULTSIZE;
990 int ldx=0, ldy=-6;
991 int fs=8;
992 int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME,
993 fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
994 char str[144];
995
996 iem_inttosymargs(&x->x_gui.x_isa, 0);
997 iem_inttofstyle(&x->x_gui.x_fsf, 0);
998
999 if((argc == 14)&&IS_A_FLOAT(argv,0)
1000 &&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
1001 &&IS_A_FLOAT(argv,3)
1002 &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
1003 &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
1004 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
1005 &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
1006 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
1007 &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13))
1008 {
1009
1010 a = (int)atom_getintarg(0, argc, argv);
1011 fthold = (int)atom_getintarg(1, argc, argv);
1012 ftbreak = (int)atom_getintarg(2, argc, argv);
1013 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(3, argc, argv));
1014 iemgui_new_getnames(&x->x_gui, 4, argv);
1015 ldx = (int)atom_getintarg(7, argc, argv);
1016 ldy = (int)atom_getintarg(8, argc, argv);
1017 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv));
1018 fs = (int)atom_getintarg(10, argc, argv);
1019 bflcol[0] = (int)atom_getintarg(11, argc, argv);
1020 bflcol[1] = (int)atom_getintarg(12, argc, argv);
1021 bflcol[2] = (int)atom_getintarg(13, argc, argv);
1022 }
1023 else iemgui_new_getnames(&x->x_gui, 4, 0);
1024
1025 x->x_gui.x_draw = (t_iemfunptr)bng_draw;
1026
1027 x->x_gui.x_fsf.x_snd_able = 1;
1028 x->x_gui.x_fsf.x_rcv_able = 1;
1029 x->x_flashed = 0;
1030 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
1031 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
1032 x->x_gui.x_fsf.x_snd_able = 0;
1033 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
1034 x->x_gui.x_fsf.x_rcv_able = 0;
1035 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
1036 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
1037 else { x->x_gui.x_fsf.x_font_style = 0;
1038 strcpy(x->x_gui.x_font, "courier"); }
1039
1040 if (x->x_gui.x_fsf.x_rcv_able)
1041 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1042 x->x_gui.x_ldx = ldx;
1043 x->x_gui.x_ldy = ldy;
1044
1045 if(fs < 4)
1046 fs = 4;
1047 x->x_gui.x_fontsize = fs;
1048 x->x_gui.x_w = iemgui_clip_size(a);
1049 x->x_gui.x_h = x->x_gui.x_w;
1050 bng_check_minmax(x, ftbreak, fthold);
1051 iemgui_all_colfromload(&x->x_gui, bflcol);
1052 x->x_gui.x_isa.x_locked = 0;
1053 iemgui_verify_snd_ne_rcv(&x->x_gui);
1054 x->x_clock_hld = clock_new(x, (t_method)bng_tick_hld);
1055 x->x_clock_brk = clock_new(x, (t_method)bng_tick_brk);
1056 x->x_clock_lck = clock_new(x, (t_method)bng_tick_lck);
1057 outlet_new(&x->x_gui.x_obj, &s_bang);
1058 return (x);
1059}
1060
1061static void bng_ff(t_bng *x)
1062{
1063 if(x->x_gui.x_fsf.x_rcv_able)
1064 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1065 clock_free(x->x_clock_lck);
1066 clock_free(x->x_clock_brk);
1067 clock_free(x->x_clock_hld);
1068 gfxstub_deleteforkey(x);
1069}
1070
1071void g_bang_setup(void)
1072{
1073 bng_class = class_new(gensym("bng"), (t_newmethod)bng_new,
1074 (t_method)bng_ff, sizeof(t_bng), 0, A_GIMME, 0);
1075 class_addbang(bng_class, bng_bang);
1076 class_addfloat(bng_class, bng_float);
1077 class_addsymbol(bng_class, bng_symbol);
1078 class_addpointer(bng_class, bng_pointer);
1079 class_addlist(bng_class, bng_list);
1080 class_addanything(bng_class, bng_anything);
1081 class_addmethod(bng_class, (t_method)bng_click, gensym("click"),
1082 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1083 class_addmethod(bng_class, (t_method)bng_dialog, gensym("dialog"),
1084 A_GIMME, 0);
1085 class_addmethod(bng_class, (t_method)bng_loadbang, gensym("loadbang"), 0);
1086 class_addmethod(bng_class, (t_method)bng_size, gensym("size"), A_GIMME, 0);
1087 class_addmethod(bng_class, (t_method)bng_delta, gensym("delta"), A_GIMME, 0);
1088 class_addmethod(bng_class, (t_method)bng_pos, gensym("pos"), A_GIMME, 0);
1089 class_addmethod(bng_class, (t_method)bng_flashtime, gensym("flashtime"), A_GIMME, 0);
1090 class_addmethod(bng_class, (t_method)bng_color, gensym("color"), A_GIMME, 0);
1091 class_addmethod(bng_class, (t_method)bng_send, gensym("send"), A_DEFSYM, 0);
1092 class_addmethod(bng_class, (t_method)bng_receive, gensym("receive"), A_DEFSYM, 0);
1093 class_addmethod(bng_class, (t_method)bng_label, gensym("label"), A_DEFSYM, 0);
1094 class_addmethod(bng_class, (t_method)bng_label_pos, gensym("label_pos"), A_GIMME, 0);
1095 class_addmethod(bng_class, (t_method)bng_label_font, gensym("label_font"), A_GIMME, 0);
1096 class_addmethod(bng_class, (t_method)bng_init, gensym("init"), A_FLOAT, 0);
1097 bng_widgetbehavior.w_getrectfn = bng_getrect;
1098 bng_widgetbehavior.w_displacefn = iemgui_displace;
1099 bng_widgetbehavior.w_selectfn = iemgui_select;
1100 bng_widgetbehavior.w_activatefn = NULL;
1101 bng_widgetbehavior.w_deletefn = iemgui_delete;
1102 bng_widgetbehavior.w_visfn = iemgui_vis;
1103 bng_widgetbehavior.w_clickfn = bng_newclick;
1104 class_setwidget(bng_class, &bng_widgetbehavior);
1105 class_sethelpsymbol(bng_class, gensym("bng"));
1106 class_setsavefn(bng_class, bng_save);
1107 class_setpropertiesfn(bng_class, bng_properties);
1108}
diff --git a/apps/plugins/pdbox/PDa/src/g_canvas.c b/apps/plugins/pdbox/PDa/src/g_canvas.c
new file mode 100644
index 0000000000..f4ef8b14aa
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_canvas.c
@@ -0,0 +1,2952 @@
1/* Copyright (c) 1997-2001 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* this file defines the "glist" class, also known as "canvas" (the two used
6to be different but are now unified except for some fossilized names.) */
7
8/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
9
10/* bug-fix: canvas_menuclose(): by Krzysztof Czaja */
11/* bug-fix: table_new(): I reversed the y-bounds */
12
13/* IOhannes :
14 * changed the canvas_restore, so that it might accept $args as well
15 * (like "pd $0_test")
16 * so you can make multiple & distinguishable templates
17 * 1511:forum::für::umläute:2001
18 * changes marked with IOhannes
19 */
20
21#include <stdlib.h>
22#include <stdio.h>
23#include "m_pd.h"
24#include "m_imp.h"
25#include "s_stuff.h"
26#include "g_canvas.h"
27#include <string.h>
28#include "g_all_guis.h"
29
30struct _canvasenvironment
31{
32 t_symbol *ce_dir; /* directory patch lives in */
33 int ce_argc; /* number of "$" arguments */
34 t_atom *ce_argv; /* array of "$" arguments */
35 int ce_dollarzero; /* value of "$0" */
36};
37
38#define GLIST_DEFCANVASWIDTH 240
39#define GLIST_DEFCANVASHEIGHT 300
40
41#ifdef MACOSX
42#define GLIST_DEFCANVASYLOC 22
43#else
44#define GLIST_DEFCANVASYLOC 0
45#endif
46
47/* ---------------------- variables --------------------------- */
48
49extern t_pd *newest;
50t_class *canvas_class;
51static int canvas_dspstate; /* whether DSP is on or off */
52t_canvas *canvas_editing; /* last canvas to start text edting */
53t_canvas *canvas_whichfind; /* last canvas we did a find in */
54t_canvas *canvas_list; /* list of all root canvases */
55
56/* ------------------ forward function declarations --------------- */
57static void canvas_start_dsp(void);
58static void canvas_stop_dsp(void);
59static void canvas_drawlines(t_canvas *x);
60static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2);
61static void canvas_reflecttitle(t_canvas *x);
62static void canvas_addtolist(t_canvas *x);
63static void canvas_takeofflist(t_canvas *x);
64static void canvas_pop(t_canvas *x, t_floatarg fvis);
65void canvas_create_editor(t_glist *x, int createit);
66
67/* --------- functions to handle the canvas environment ----------- */
68
69static t_symbol *canvas_newfilename = &s_;
70static t_symbol *canvas_newdirectory = &s_;
71static int canvas_newargc;
72static t_atom *canvas_newargv;
73
74static void glist_doupdatewindowlist(t_glist *gl, char *sbuf)
75{
76 t_gobj *g;
77 if (!gl->gl_owner)
78 {
79 /* this is a canvas; if we have a window, put on "windows" list */
80 t_canvas *canvas = (t_canvas *)gl;
81 if (canvas->gl_havewindow)
82 {
83 if (strlen(sbuf) + strlen(gl->gl_name->s_name) + 100 <= 1024)
84 {
85 char tbuf[1024];
86 sprintf(tbuf, "{%s .x%x} ", gl->gl_name->s_name, (t_int)canvas);
87 strcat(sbuf, tbuf);
88 }
89 }
90 }
91 for (g = gl->gl_list; g; g = g->g_next)
92 {
93 if (pd_class(&g->g_pd) == canvas_class)
94 glist_doupdatewindowlist((t_glist *)g, sbuf);
95 }
96 return;
97}
98
99 /* maintain the list of visible toplevels for the GUI's "windows" menu */
100void canvas_updatewindowlist( void)
101{
102 t_canvas *x;
103 char sbuf[1024];
104 strcpy(sbuf, "set menu_windowlist {");
105 /* find all root canvases */
106 for (x = canvas_list; x; x = x->gl_next)
107 glist_doupdatewindowlist(x, sbuf);
108 /* next line updates the window menu state before -postcommand tries it */
109 strcat(sbuf, "}\npdtk_fixwindowmenu\n");
110 sys_gui(sbuf);
111}
112
113 /* add a glist the list of "root" canvases (toplevels without parents.) */
114static void canvas_addtolist(t_canvas *x)
115{
116 x->gl_next = canvas_list;
117 canvas_list = x;
118}
119
120static void canvas_takeofflist(t_canvas *x)
121{
122 /* take it off the window list */
123 if (x == canvas_list) canvas_list = x->gl_next;
124 else
125 {
126 t_canvas *z;
127 for (z = canvas_list; z->gl_next != x; z = z->gl_next)
128 ;
129 z->gl_next = x->gl_next;
130 }
131}
132
133
134void canvas_setargs(int argc, t_atom *argv)
135{
136 /* if there's an old one lying around free it here. This
137 happens if an abstraction is loaded but never gets as far
138 as calling canvas_new(). */
139 if (canvas_newargv)
140 freebytes(canvas_newargv, canvas_newargc * sizeof(t_atom));
141 canvas_newargc = argc;
142 canvas_newargv = copybytes(argv, argc * sizeof(t_atom));
143}
144
145void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym)
146{
147 canvas_newfilename = filesym;
148 canvas_newdirectory = dirsym;
149}
150
151t_canvas *canvas_getcurrent(void)
152{
153 return ((t_canvas *)pd_findbyclass(&s__X, canvas_class));
154}
155
156void canvas_setcurrent(t_canvas *x)
157{
158 pd_pushsym(&x->gl_pd);
159}
160
161void canvas_unsetcurrent(t_canvas *x)
162{
163 pd_popsym(&x->gl_pd);
164}
165
166t_canvasenvironment *canvas_getenv(t_canvas *x)
167{
168 if (!x) bug("canvas_getenv");
169 while (!x->gl_env)
170 if (!(x = x->gl_owner))
171 bug("t_canvasenvironment", x);
172 return (x->gl_env);
173}
174
175int canvas_getdollarzero( void)
176{
177 t_canvas *x = canvas_getcurrent();
178 t_canvasenvironment *env = (x ? canvas_getenv(x) : 0);
179 if (env)
180 return (env->ce_dollarzero);
181 else return (0);
182}
183
184void canvas_getargs(int *argcp, t_atom **argvp)
185{
186 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
187 *argcp = e->ce_argc;
188 *argvp = e->ce_argv;
189}
190
191t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s)
192{
193 t_symbol *ret;
194 char *name = s->s_name;
195 if (*name == '$' && name[1] >= '0' && name[1] <= '9')
196 {
197 t_canvasenvironment *env = canvas_getenv(x);
198 canvas_setcurrent(x);
199 ret = binbuf_realizedollsym(gensym(name+1),
200 env->ce_argc, env->ce_argv, 1);
201 canvas_unsetcurrent(x);
202 }
203 else ret = s;
204 return (ret);
205}
206
207t_symbol *canvas_getcurrentdir(void)
208{
209 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
210 return (e->ce_dir);
211}
212
213t_symbol *canvas_getdir(t_canvas *x)
214{
215 t_canvasenvironment *e = canvas_getenv(x);
216 return (e->ce_dir);
217}
218
219void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize)
220{
221 char *dir = canvas_getenv(x)->ce_dir->s_name;
222 if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir)
223 {
224 strncpy(result, file, resultsize);
225 result[resultsize-1] = 0;
226 }
227 else
228 {
229 int nleft;
230 strncpy(result, dir, resultsize);
231 result[resultsize-1] = 0;
232 nleft = resultsize - strlen(result) - 1;
233 if (nleft <= 0) return;
234 strcat(result, "/");
235 strncat(result, file, nleft);
236 result[resultsize-1] = 0;
237 }
238}
239
240void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir)
241{
242 if (strcmp(x->gl_name->s_name, "Pd"))
243 pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
244 x->gl_name = s;
245 if (strcmp(x->gl_name->s_name, "Pd"))
246 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
247 if (glist_isvisible(x))
248 canvas_reflecttitle(x);
249 if (dir && dir != &s_)
250 {
251 t_canvasenvironment *e = canvas_getenv(x);
252 e->ce_dir = dir;
253 }
254}
255
256/* --------------- traversing the set of lines in a canvas ----------- */
257
258int canvas_getindex(t_canvas *x, t_gobj *y)
259{
260 t_gobj *y2;
261 int indexno;
262 for (indexno = 0, y2 = x->gl_list; y2 && y2 != y; y2 = y2->g_next)
263 indexno++;
264 return (indexno);
265}
266
267void linetraverser_start(t_linetraverser *t, t_canvas *x)
268{
269 t->tr_ob = 0;
270 t->tr_x = x;
271 t->tr_nextoc = 0;
272 t->tr_nextoutno = t->tr_nout = 0;
273}
274
275t_outconnect *linetraverser_next(t_linetraverser *t)
276{
277 t_outconnect *rval = t->tr_nextoc;
278 int outno;
279 while (!rval)
280 {
281 outno = t->tr_nextoutno;
282 while (outno == t->tr_nout)
283 {
284 t_gobj *y;
285 t_object *ob = 0;
286 if (!t->tr_ob) y = t->tr_x->gl_list;
287 else y = t->tr_ob->ob_g.g_next;
288 for (; y; y = y->g_next)
289 if (ob = pd_checkobject(&y->g_pd)) break;
290 if (!ob) return (0);
291 t->tr_ob = ob;
292 t->tr_nout = obj_noutlets(ob);
293 outno = 0;
294 if (glist_isvisible(t->tr_x))
295 gobj_getrect(y, t->tr_x,
296 &t->tr_x11, &t->tr_y11, &t->tr_x12, &t->tr_y12);
297 else t->tr_x11 = t->tr_y11 = t->tr_x12 = t->tr_y12 = 0;
298 }
299 t->tr_nextoutno = outno + 1;
300 rval = obj_starttraverseoutlet(t->tr_ob, &t->tr_outlet, outno);
301 t->tr_outno = outno;
302 }
303 t->tr_nextoc = obj_nexttraverseoutlet(rval, &t->tr_ob2,
304 &t->tr_inlet, &t->tr_inno);
305 t->tr_nin = obj_ninlets(t->tr_ob2);
306 if (!t->tr_nin) bug("drawline");
307 if (glist_isvisible(t->tr_x))
308 {
309 int inplus = (t->tr_nin == 1 ? 1 : t->tr_nin - 1);
310 int outplus = (t->tr_nout == 1 ? 1 : t->tr_nout - 1);
311 gobj_getrect(&t->tr_ob2->ob_g, t->tr_x,
312 &t->tr_x21, &t->tr_y21, &t->tr_x22, &t->tr_y22);
313 t->tr_lx1 = t->tr_x11 +
314 ((t->tr_x12 - t->tr_x11 - IOWIDTH) * t->tr_outno) /
315 outplus + IOMIDDLE;
316 t->tr_ly1 = t->tr_y12;
317 t->tr_lx2 = t->tr_x21 +
318 ((t->tr_x22 - t->tr_x21 - IOWIDTH) * t->tr_inno)/inplus +
319 IOMIDDLE;
320 t->tr_ly2 = t->tr_y21;
321 }
322 else
323 {
324 t->tr_x21 = t->tr_y21 = t->tr_x22 = t->tr_y22 = 0;
325 t->tr_lx1 = t->tr_ly1 = t->tr_lx2 = t->tr_ly2 = 0;
326 }
327
328 return (rval);
329}
330
331void linetraverser_skipobject(t_linetraverser *t)
332{
333 t->tr_nextoc = 0;
334 t->tr_nextoutno = t->tr_nout;
335}
336
337/* -------------------- the canvas object -------------------------- */
338int glist_valid = 10000;
339
340void glist_init(t_glist *x)
341{
342 /* zero out everyone except "pd" field */
343 memset(((char *)x) + sizeof(x->gl_pd), 0, sizeof(*x) - sizeof(x->gl_pd));
344 x->gl_stub = gstub_new(x, 0);
345 x->gl_valid = ++glist_valid;
346 x->gl_xlabel = (t_symbol **)t_getbytes(0);
347 x->gl_ylabel = (t_symbol **)t_getbytes(0);
348}
349
350 /* make a new glist. It will either be a "root" canvas or else
351 its parent will be a "text" object in another window... we don't
352 know which yet. */
353t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
354{
355 t_canvas *x = (t_canvas *)pd_new(canvas_class);
356 t_canvas *owner = canvas_getcurrent();
357 t_symbol *s = &s_;
358 int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT;
359 int xloc = 0, yloc = GLIST_DEFCANVASYLOC;
360 int font = (owner ? owner->gl_font : sys_defaultfont);
361 glist_init(x);
362 x->gl_obj.te_type = T_OBJECT;
363 if (!owner)
364 canvas_addtolist(x);
365 /* post("canvas %x, owner %x", x, owner); */
366
367 if (argc == 5) /* toplevel: x, y, w, h, font */
368 {
369 xloc = atom_getintarg(0, argc, argv);
370 yloc = atom_getintarg(1, argc, argv);
371 width = atom_getintarg(2, argc, argv);
372 height = atom_getintarg(3, argc, argv);
373 font = atom_getintarg(4, argc, argv);
374 }
375 else if (argc == 6) /* subwindow: x, y, w, h, name, vis */
376 {
377 xloc = atom_getintarg(0, argc, argv);
378 yloc = atom_getintarg(1, argc, argv);
379 width = atom_getintarg(2, argc, argv);
380 height = atom_getintarg(3, argc, argv);
381 s = atom_getsymbolarg(4, argc, argv);
382 vis = atom_getintarg(5, argc, argv);
383 }
384 /* (otherwise assume we're being created from the menu.) */
385
386 if (canvas_newdirectory->s_name[0])
387 {
388 static int dollarzero = 1000;
389 t_canvasenvironment *env = x->gl_env =
390 (t_canvasenvironment *)getbytes(sizeof(*x->gl_env));
391 env->ce_dir = canvas_newdirectory;
392 env->ce_argc = canvas_newargc;
393 env->ce_argv = canvas_newargv;
394 env->ce_dollarzero = dollarzero++;
395 canvas_newdirectory = &s_;
396 canvas_newargc = 0;
397 canvas_newargv = 0;
398 }
399 else x->gl_env = 0;
400
401 if (yloc < GLIST_DEFCANVASYLOC)
402 yloc = GLIST_DEFCANVASYLOC;
403 if (xloc < 0)
404 xloc = 0;
405 x->gl_x1 = 0;
406 x->gl_y1 = 0;
407 x->gl_x2 = 1;
408 x->gl_y2 = 1;
409 canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height);
410 x->gl_owner = owner;
411 x->gl_name = (*s->s_name ? s :
412 (canvas_newfilename ? canvas_newfilename : gensym("Pd")));
413 if (strcmp(x->gl_name->s_name, "Pd"))
414 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
415 x->gl_loading = 1;
416 x->gl_willvis = vis;
417 x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8);
418 x->gl_font = sys_nearestfontsize(font);
419 pd_pushsym(&x->gl_pd);
420 return(x);
421}
422
423void canvas_setgraph(t_glist *x, int flag);
424
425static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv)
426{
427 x->gl_x1 = atom_getfloatarg(0, argc, argv);
428 x->gl_y1 = atom_getfloatarg(1, argc, argv);
429 x->gl_x2 = atom_getfloatarg(2, argc, argv);
430 x->gl_y2 = atom_getfloatarg(3, argc, argv);
431 x->gl_pixwidth = atom_getintarg(4, argc, argv);
432 x->gl_pixheight = atom_getintarg(5, argc, argv);
433 canvas_setgraph(x, atom_getintarg(6, argc, argv));
434}
435
436 /* make a new glist and add it to this glist. It will appear as
437 a "graph", not a text object. */
438t_glist *glist_addglist(t_glist *g, t_symbol *sym,
439 float x1, float y1, float x2, float y2,
440 float px1, float py1, float px2, float py2)
441{
442 static int gcount = 0;
443 int zz;
444 int menu = 0;
445 char *str;
446 t_glist *x = (t_glist *)pd_new(canvas_class);
447 glist_init(x);
448 x->gl_obj.te_type = T_OBJECT;
449 if (!*sym->s_name)
450 {
451 char buf[40];
452 sprintf(buf, "graph%d", ++gcount);
453 sym = gensym(buf);
454 menu = 1;
455 }
456 else if (!strncmp((str = sym->s_name), "graph", 5)
457 && (zz = atoi(str + 5)) > gcount)
458 gcount = zz;
459 /* in 0.34 and earlier, the pixel rectangle and the y bounds were
460 reversed; this would behave the same, except that the dialog window
461 would be confusing. The "correct" way is to have "py1" be the value
462 that is higher on the screen. */
463 if (py2 < py1)
464 {
465 float zz;
466 zz = y2;
467 y2 = y1;
468 y1 = zz;
469 zz = py2;
470 py2 = py1;
471 py1 = zz;
472 }
473 if (x1 == x2 || y1 == y2)
474 x1 = 0, x2 = 100, y1 = 1, y2 = -1;
475 if (px1 >= px2 || py1 >= py2)
476 px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH,
477 py2 = 20 + GLIST_DEFGRAPHHEIGHT;
478 x->gl_name = sym;
479 x->gl_x1 = x1;
480 x->gl_x2 = x2;
481 x->gl_y1 = y1;
482 x->gl_y2 = y2;
483 x->gl_obj.te_xpix = px1;
484 x->gl_obj.te_ypix = py1;
485 x->gl_pixwidth = px2 - px1;
486 x->gl_pixheight = py2 - py1;
487 x->gl_font = (canvas_getcurrent() ?
488 canvas_getcurrent()->gl_font : sys_defaultfont);
489 x->gl_screenx1 = x->gl_screeny1 = 0;
490 x->gl_screenx2 = 240;
491 x->gl_screeny2 = 300;
492 if (strcmp(x->gl_name->s_name, "Pd"))
493 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
494 x->gl_owner = g;
495 x->gl_stretch = 1;
496 x->gl_isgraph = 1;
497 x->gl_obj.te_binbuf = binbuf_new();
498 binbuf_addv(x->gl_obj.te_binbuf, "s", gensym("graph"));
499 if (!menu)
500 pd_pushsym(&x->gl_pd);
501 glist_add(g, &x->gl_gobj);
502 if (glist_isvisible(g))
503 canvas_create_editor(x, 1);
504 return (x);
505}
506
507 /* call glist_addglist from a Pd message */
508void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv)
509{
510 t_symbol *sym = atom_getsymbolarg(0, argc, argv);
511 float x1 = atom_getfloatarg(1, argc, argv);
512 float y1 = atom_getfloatarg(2, argc, argv);
513 float x2 = atom_getfloatarg(3, argc, argv);
514 float y2 = atom_getfloatarg(4, argc, argv);
515 float px1 = atom_getfloatarg(5, argc, argv);
516 float py1 = atom_getfloatarg(6, argc, argv);
517 float px2 = atom_getfloatarg(7, argc, argv);
518 float py2 = atom_getfloatarg(8, argc, argv);
519 glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2);
520}
521
522 /* return true if the glist should appear as a graph on parent;
523 otherwise it appears as a text box. */
524int glist_isgraph(t_glist *x)
525{
526 return (x->gl_isgraph);
527}
528
529 /* This is sent from the GUI to inform a toplevel that its window has been
530 moved or resized. */
531static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2)
532{
533 int heightwas = y2 - y1;
534 int heightchange = y2 - y1 - (x->gl_screeny2 - x->gl_screeny1);
535 x->gl_screenx1 = x1;
536 x->gl_screeny1 = y1;
537 x->gl_screenx2 = x2;
538 x->gl_screeny2 = y2;
539 /* post("set bounds %d %d %d %d", x1, y1, x2, y2); */
540 if (!glist_isgraph(x) && (x->gl_y2 < x->gl_y1))
541 {
542 /* if it's flipped so that y grows upward,
543 fix so that zero is bottom edge and redraw. This is
544 only appropriate if we're a regular "text" object on the
545 parent. */
546 float diff = x->gl_y1 - x->gl_y2;
547 t_gobj *y;
548 x->gl_y1 = heightwas * diff;
549 x->gl_y2 = x->gl_y1 - diff;
550 /* and move text objects accordingly; they should stick
551 to the bottom, not the top. */
552 for (y = x->gl_list; y; y = y->g_next)
553 if (pd_checkobject(&y->g_pd))
554 gobj_displace(y, x, 0, heightchange);
555 canvas_redraw(x);
556 }
557}
558
559t_symbol *canvas_makebindsym(t_symbol *s)
560{
561 char buf[MAXPDSTRING];
562 strcpy(buf, "pd-");
563 strcat(buf, s->s_name);
564 return (gensym(buf));
565}
566
567void canvas_reflecttitle(t_canvas *x)
568{
569 char namebuf[MAXPDSTRING];
570 t_canvasenvironment *env = canvas_getenv(x);
571 if (env->ce_argc)
572 {
573 int i;
574 strcpy(namebuf, " (");
575 for (i = 0; i < env->ce_argc; i++)
576 {
577 if (strlen(namebuf) > MAXPDSTRING/2 - 5)
578 break;
579 if (i != 0)
580 strcat(namebuf, " ");
581 atom_string(&env->ce_argv[i], namebuf + strlen(namebuf),
582 MAXPDSTRING/2);
583 }
584 strcat(namebuf, ")");
585 }
586 else namebuf[0] = 0;
587 sys_vgui("wm title .x%x {%s%c%s - %s}\n",
588 x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf,
589 canvas_getdir(x)->s_name);
590}
591
592void canvas_dirty(t_canvas *x, t_int n)
593{
594 t_canvas *x2 = canvas_getrootfor(x);
595 if ((unsigned)n != x2->gl_dirty)
596 {
597 x2->gl_dirty = n;
598 canvas_reflecttitle(x2);
599 }
600}
601
602 /* the window becomes "mapped" (visible and not miniaturized) or
603 "unmapped" (either miniaturized or just plain gone.) This should be
604 called from the GUI after the fact to "notify" us that we're mapped. */
605void canvas_map(t_canvas *x, t_floatarg f)
606{
607 int flag = (f != 0);
608 t_gobj *y;
609 if (flag)
610 {
611 if (!glist_isvisible(x))
612 {
613 t_selection *sel;
614 if (!x->gl_havewindow)
615 {
616 bug("canvas_map");
617 canvas_vis(x, 1);
618 }
619 for (y = x->gl_list; y; y = y->g_next)
620 gobj_vis(y, x, 1);
621 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
622 gobj_select(sel->sel_what, x, 1);
623 x->gl_mapped = 1;
624 canvas_drawlines(x);
625 /* simulate a mouse up so u_main will calculate scrollbars...
626 ugly! */
627 sys_vgui("pdtk_canvas_mouseup .x%x.c 0 0 0\n", x);
628 }
629 }
630 else
631 {
632 if (glist_isvisible(x))
633 {
634 /* just clear out the whole canvas... */
635 sys_vgui(".x%x.c delete all\n", x);
636 /* alternatively, we could have erased them one by one...
637 for (y = x->gl_list; y; y = y->g_next)
638 gobj_vis(y, x, 0);
639 ... but we should go through and erase the lines as well
640 if we do it that way. */
641 x->gl_mapped = 0;
642 }
643 }
644}
645
646void canvas_redraw(t_canvas *x)
647{
648 if (glist_isvisible(x))
649 {
650 canvas_map(x, 0);
651 canvas_map(x, 1);
652 }
653}
654
655/* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */
656
657static t_editor *editor_new(t_glist *owner)
658{
659 char buf[40];
660 t_editor *x = (t_editor *)getbytes(sizeof(*x));
661 x->e_connectbuf = binbuf_new();
662 x->e_deleted = binbuf_new();
663 x->e_glist = owner;
664 sprintf(buf, ".x%x", (t_int)owner);
665 x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf));
666 return (x);
667}
668
669static void editor_free(t_editor *x, t_glist *y)
670{
671 glist_noselect(y);
672 guiconnect_notarget(x->e_guiconnect, 1000);
673 binbuf_free(x->e_connectbuf);
674 binbuf_free(x->e_deleted);
675 freebytes((void *)x, sizeof(*x));
676}
677
678 /* recursively create or destroy all editors of a glist and its
679 sub-glists, as long as they aren't toplevels. */
680void canvas_create_editor(t_glist *x, int createit)
681{
682 t_gobj *y;
683 t_object *ob;
684 if (createit)
685 {
686 if (x->gl_editor)
687 bug("canvas_create_editor");
688 else
689 {
690 x->gl_editor = editor_new(x);
691 for (y = x->gl_list; y; y = y->g_next)
692 if (ob = pd_checkobject(&y->g_pd))
693 rtext_new(x, ob);
694 }
695 }
696 else
697 {
698 if (!x->gl_editor)
699 bug("canvas_create_editor");
700 else
701 {
702 for (y = x->gl_list; y; y = y->g_next)
703 if (ob = pd_checkobject(&y->g_pd))
704 rtext_free(glist_findrtext(x, ob));
705 editor_free(x->gl_editor, x);
706 x->gl_editor = 0;
707 }
708 }
709 for (y = x->gl_list; y; y = y->g_next)
710 if (pd_class(&y->g_pd) == canvas_class &&
711 ((t_canvas *)y)->gl_isgraph)
712 canvas_create_editor((t_canvas *)y, createit);
713}
714
715 /* we call this when we want the window to become visible, mapped, and
716 in front of all windows; or with "f" zero, when we want to get rid of
717 the window. */
718void canvas_vis(t_canvas *x, t_floatarg f)
719{
720 char buf[30];
721 int flag = (f != 0);
722 if (flag)
723 {
724 /* test if we're already visible and toplevel */
725 if (glist_isvisible(x) && !x->gl_isgraph)
726 { /* just put us in front */
727#ifdef MSW
728 canvas_vis(x, 0);
729 canvas_vis(x, 1);
730#else
731 sys_vgui("raise .x%x\n", x);
732 sys_vgui("focus .x%x.c\n", x);
733 sys_vgui("wm deiconify .x%x\n", x);
734#endif
735 }
736 else
737 {
738 canvas_create_editor(x, 1);
739 sys_vgui("pdtk_canvas_new .x%x %d %d +%d+%d %d\n", x,
740 (int)(x->gl_screenx2 - x->gl_screenx1),
741 (int)(x->gl_screeny2 - x->gl_screeny1),
742 (int)(x->gl_screenx1), (int)(x->gl_screeny1),
743 x->gl_edit);
744 canvas_reflecttitle(x);
745 x->gl_havewindow = 1;
746 canvas_updatewindowlist();
747 }
748 }
749 else /* make invisible */
750 {
751 int i;
752 t_canvas *x2;
753 if (!x->gl_havewindow)
754 {
755 /* bug workaround -- a graph in a visible patch gets "invised"
756 when the patch is closed, and must lose the editor here. It's
757 probably not the natural place to do this. Other cases like
758 subpatches fall here too but don'd need the editor freed, so
759 we check if it exists. */
760 if (x->gl_editor)
761 canvas_create_editor(x, 0);
762 return;
763 }
764 glist_noselect(x);
765 if (glist_isvisible(x))
766 canvas_map(x, 0);
767 canvas_create_editor(x, 0);
768 sys_vgui("destroy .x%x\n", x);
769 for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++)
770 ;
771 sys_vgui(".mbar.find delete %d\n", i);
772 /* if we're a graph on our parent, and if the parent exists
773 and is visible, show ourselves on parent. */
774 if (glist_isgraph(x) && x->gl_owner)
775 {
776 t_glist *gl2 = x->gl_owner;
777 canvas_create_editor(x, 1);
778 if (glist_isvisible(gl2))
779 gobj_vis(&x->gl_gobj, gl2, 0);
780 x->gl_havewindow = 0;
781 if (glist_isvisible(gl2))
782 gobj_vis(&x->gl_gobj, gl2, 1);
783 }
784 else x->gl_havewindow = 0;
785 canvas_updatewindowlist();
786 }
787}
788
789 /* we call this on a non-toplevel glist to "open" it into its
790 own window. */
791void glist_menu_open(t_glist *x)
792{
793 if (glist_isvisible(x) && !glist_istoplevel(x))
794 {
795 t_glist *gl2 = x->gl_owner;
796 if (!gl2)
797 bug("canvas_vis"); /* shouldn't happen but don't get too upset. */
798 else
799 {
800 /* erase ourself in parent window */
801 gobj_vis(&x->gl_gobj, gl2, 0);
802 /* get rid of our editor (and subeditors) */
803 canvas_create_editor(x, 0);
804 x->gl_havewindow = 1;
805 /* redraw ourself in parent window (blanked out this time) */
806 gobj_vis(&x->gl_gobj, gl2, 1);
807 }
808 }
809 canvas_vis(x, 1);
810}
811
812int glist_isvisible(t_glist *x)
813{
814 return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped);
815}
816
817int glist_istoplevel(t_glist *x)
818{
819 /* we consider a graph "toplevel" if it has its own window
820 or if it appears as a box in its parent window so that we
821 don't draw the actual contents there. */
822 return (x->gl_havewindow || !x->gl_isgraph);
823}
824
825int glist_getfont(t_glist *x)
826{
827 return (glist_getcanvas(x)->gl_font);
828}
829
830void canvas_free(t_canvas *x)
831{
832 t_gobj *y;
833 int dspstate = canvas_suspend_dsp();
834 canvas_noundo(x);
835 if (canvas_editing == x)
836 canvas_editing = 0;
837 if (canvas_whichfind == x)
838 canvas_whichfind = 0;
839 glist_noselect(x);
840 while (y = x->gl_list)
841 glist_delete(x, y);
842 canvas_vis(x, 0);
843
844 if (strcmp(x->gl_name->s_name, "Pd"))
845 pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
846 if (x->gl_env)
847 {
848 freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom));
849 freebytes(x->gl_env, sizeof(*x->gl_env));
850 }
851 canvas_resume_dsp(dspstate);
852 glist_cleanup(x);
853 gfxstub_deleteforkey(x); /* probably unnecessary */
854 if (!x->gl_owner)
855 canvas_takeofflist(x);
856}
857
858/* ----------------- lines ---------- */
859
860static void canvas_drawlines(t_canvas *x)
861{
862 t_linetraverser t;
863 t_outconnect *oc;
864 {
865 linetraverser_start(&t, x);
866 while (oc = linetraverser_next(&t))
867 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
868 glist_getcanvas(x),
869 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2,
870 (outlet_getsymbol(t.tr_outlet) == &s_signal ? 2:1),
871 oc);
872 }
873}
874
875void canvas_fixlinesfor(t_canvas *x, t_text *text)
876{
877 t_linetraverser t;
878 t_outconnect *oc;
879
880 linetraverser_start(&t, x);
881 while (oc = linetraverser_next(&t))
882 {
883 if (t.tr_ob == text || t.tr_ob2 == text)
884 {
885 sys_vgui(".x%x.c coords l%x %d %d %d %d\n",
886 glist_getcanvas(x), oc,
887 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2);
888 }
889 }
890}
891
892 /* kill all lines for the object */
893void canvas_deletelinesfor(t_canvas *x, t_text *text)
894{
895 t_linetraverser t;
896 t_outconnect *oc;
897 linetraverser_start(&t, x);
898 while (oc = linetraverser_next(&t))
899 {
900 if (t.tr_ob == text || t.tr_ob2 == text)
901 {
902 if (x->gl_editor)
903 {
904 sys_vgui(".x%x.c delete l%x\n",
905 glist_getcanvas(x), oc);
906 }
907 obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
908 }
909 }
910}
911
912 /* kill all lines for one inlet or outlet */
913void canvas_deletelinesforio(t_canvas *x, t_text *text,
914 t_inlet *inp, t_outlet *outp)
915{
916 t_linetraverser t;
917 t_outconnect *oc;
918 linetraverser_start(&t, x);
919 while (oc = linetraverser_next(&t))
920 {
921 if ((t.tr_ob == text && t.tr_outlet == outp) ||
922 (t.tr_ob2 == text && t.tr_inlet == inp))
923 {
924 if (x->gl_editor)
925 {
926 sys_vgui(".x%x.c delete l%x\n",
927 glist_getcanvas(x), oc);
928 }
929 obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
930 }
931 }
932}
933
934static void canvas_pop(t_canvas *x, t_floatarg fvis)
935{
936 if (fvis != 0)
937 canvas_vis(x, 1);
938 pd_popsym(&x->gl_pd);
939 canvas_resortinlets(x);
940 canvas_resortoutlets(x);
941 x->gl_loading = 0;
942}
943
944void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv);
945
946
947void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
948{ /* IOhannes */
949 t_pd *z;
950 /* this should be unnecessary, but sometimes the canvas's name gets
951 out of sync with the owning box's argument; this fixes that */
952 if (argc > 3)
953 {
954 t_atom *ap=argv+3;
955 if (ap->a_type == A_SYMBOL)
956 {
957 char *buf=ap->a_w.w_symbol->s_name, *bufp;
958 if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9')
959 {
960 for (bufp = buf+2; *bufp; bufp++)
961 if (*bufp < '0' || *bufp > '9')
962 {
963 SETDOLLSYM(ap, gensym(buf+1));
964 goto didit;
965 }
966 SETDOLLAR(ap, atoi(buf+1));
967 didit: ;
968 }
969 }
970
971 if (ap->a_type == A_DOLLSYM)
972 {
973 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
974 canvas_rename(x, binbuf_realizedollsym(ap->a_w.w_symbol,
975 e->ce_argc, e->ce_argv, 1), 0);
976 }
977 else if (ap->a_type == A_SYMBOL)
978 canvas_rename(x, argv[3].a_w.w_symbol, 0);
979 }
980 canvas_pop(x, x->gl_willvis);
981
982 if (!(z = gensym("#X")->s_thing)) error("canvas_restore: out of context");
983 else if (*z != canvas_class) error("canvas_restore: wasn't a canvas");
984 else
985 {
986 t_canvas *x2 = (t_canvas *)z;
987 x->gl_owner = x2;
988 canvas_objfor(x2, &x->gl_obj, argc, argv);
989 }
990}
991
992static void canvas_loadbangabstractions(t_canvas *x)
993{
994 t_gobj *y;
995 t_symbol *s = gensym("loadbang");
996 for (y = x->gl_list; y; y = y->g_next)
997 if (pd_class(&y->g_pd) == canvas_class)
998 {
999 if (canvas_isabstraction((t_canvas *)y))
1000 canvas_loadbang((t_canvas *)y);
1001 else
1002 canvas_loadbangabstractions((t_canvas *)y);
1003 }
1004}
1005
1006void canvas_loadbangsubpatches(t_canvas *x)
1007{
1008 t_gobj *y;
1009 t_symbol *s = gensym("loadbang");
1010 for (y = x->gl_list; y; y = y->g_next)
1011 if (pd_class(&y->g_pd) == canvas_class)
1012 {
1013 if (!canvas_isabstraction((t_canvas *)y))
1014 canvas_loadbangsubpatches((t_canvas *)y);
1015 }
1016 for (y = x->gl_list; y; y = y->g_next)
1017 if ((pd_class(&y->g_pd) != canvas_class) &&
1018 zgetfn(&y->g_pd, s))
1019 pd_vmess(&y->g_pd, s, "");
1020}
1021
1022void canvas_loadbang(t_canvas *x)
1023{
1024 t_gobj *y;
1025 canvas_loadbangabstractions(x);
1026 canvas_loadbangsubpatches(x);
1027}
1028
1029 /* When you ask a canvas its size the result is 2 pixels more than what
1030 you gave it to open it; perhaps there's a 1-pixel border all around it
1031 or something. Anyway, we just add the 2 pixels back here; seems we
1032 have to do this for linux but not MSW; not sure about MacOS. */
1033
1034#ifdef MSW
1035#define HORIZBORDER 0
1036#define VERTBORDER 0
1037#else
1038#define HORIZBORDER 2
1039#define VERTBORDER 2
1040#endif
1041
1042static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom,
1043 t_symbol *topgeom)
1044{
1045 int cxpix, cypix, cw, ch, txpix, typix, tw, th;
1046 if (sscanf(canvasgeom->s_name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix)
1047 < 4 ||
1048 sscanf(topgeom->s_name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4)
1049 bug("canvas_relocate");
1050 /* for some reason this is initially called with cw=ch=1 so
1051 we just suppress that here. */
1052 if (cw > 5 && ch > 5)
1053 canvas_setbounds(x, txpix, typix,
1054 txpix + cw - HORIZBORDER, typix + ch - VERTBORDER);
1055}
1056
1057void canvas_popabstraction(t_canvas *x)
1058{
1059 newest = &x->gl_pd;
1060 pd_popsym(&x->gl_pd);
1061 x->gl_loading = 0;
1062 canvas_resortinlets(x);
1063 canvas_resortoutlets(x);
1064}
1065
1066void canvas_logerror(t_object *y)
1067{
1068#ifdef LATER
1069 canvas_vis(x, 1);
1070 if (!glist_isselected(x, &y->ob_g))
1071 glist_select(x, &y->ob_g);
1072#endif
1073}
1074
1075/* -------------------------- subcanvases ---------------------- */
1076
1077static void *subcanvas_new(t_symbol *s)
1078{
1079 t_atom a[6];
1080 t_canvas *x, *z = canvas_getcurrent();
1081 if (!*s->s_name) s = gensym("/SUBPATCH/");
1082 SETFLOAT(a, 0);
1083 SETFLOAT(a+1, GLIST_DEFCANVASYLOC);
1084 SETFLOAT(a+2, GLIST_DEFCANVASWIDTH);
1085 SETFLOAT(a+3, GLIST_DEFCANVASHEIGHT);
1086 SETSYMBOL(a+4, s);
1087 SETFLOAT(a+5, 1);
1088 x = canvas_new(0, 0, 6, a);
1089 x->gl_owner = z;
1090 canvas_pop(x, 1);
1091 return (x);
1092}
1093
1094static void canvas_click(t_canvas *x,
1095 t_floatarg xpos, t_floatarg ypos,
1096 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
1097{
1098 canvas_vis(x, 1);
1099}
1100
1101
1102 /* find out from subcanvas contents how much to fatten the box */
1103void canvas_fattensub(t_canvas *x,
1104 int *xp1, int *yp1, int *xp2, int *yp2)
1105{
1106 t_gobj *y;
1107 *xp2 += 50; /* fake for now */
1108 *yp2 += 50;
1109}
1110
1111static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av)
1112{
1113 if (ac && av->a_type == A_SYMBOL)
1114 canvas_rename(x, av->a_w.w_symbol, 0);
1115 else canvas_rename(x, gensym("Pd"), 0);
1116}
1117
1118/* ------------------ table ---------------------------*/
1119
1120static int tabcount = 0;
1121
1122static void *table_new(t_symbol *s, t_floatarg f)
1123{
1124 t_atom a[9];
1125 t_glist *gl;
1126 t_canvas *x, *z = canvas_getcurrent();
1127 if (s == &s_)
1128 {
1129 char tabname[255];
1130 t_symbol *t = gensym("table");
1131 sprintf(tabname, "%s%d", t->s_name, tabcount++);
1132 s = gensym(tabname);
1133 }
1134 if (f <= 1)
1135 f = 100;
1136 SETFLOAT(a, 0);
1137 SETFLOAT(a+1, GLIST_DEFCANVASYLOC);
1138 SETFLOAT(a+2, 600);
1139 SETFLOAT(a+3, 400);
1140 SETSYMBOL(a+4, s);
1141 SETFLOAT(a+5, 0);
1142 x = canvas_new(0, 0, 6, a);
1143
1144 x->gl_owner = z;
1145
1146 /* create a graph for the table */
1147 gl = glist_addglist((t_glist*)x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1,
1148 50, 350, 550, 50);
1149
1150 graph_array(gl, s, &s_float, f, 0);
1151
1152 canvas_pop(x, 0);
1153
1154 return (x);
1155}
1156
1157 /* return true if the "canvas" object is an abstraction (so we don't
1158 save its contents, fogr example.) */
1159int canvas_isabstraction(t_canvas *x)
1160{
1161 return (x->gl_env != 0);
1162}
1163
1164 /* return true if the "canvas" object is a "table". */
1165int canvas_istable(t_canvas *x)
1166{
1167 t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
1168 int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
1169 int istable = (argc && argv[0].a_type == A_SYMBOL &&
1170 argv[0].a_w.w_symbol == gensym("table"));
1171 return (istable);
1172}
1173
1174 /* return true if the "canvas" object should be treated as a text
1175 object. This is true for abstractions but also for "table"s... */
1176int canvas_showtext(t_canvas *x)
1177{
1178 t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
1179 int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
1180 int isarray = (argc && argv[0].a_type == A_SYMBOL &&
1181 argv[0].a_w.w_symbol == gensym("graph"));
1182 return (!isarray);
1183}
1184
1185static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp);
1186static void canvas_dsp(t_canvas *x, t_signal **sp)
1187{
1188 canvas_dodsp(x, 0, sp);
1189}
1190
1191 /* get the document containing this canvas */
1192t_canvas *canvas_getrootfor(t_canvas *x)
1193{
1194 if ((!x->gl_owner) || canvas_isabstraction(x))
1195 return (x);
1196 else return (canvas_getrootfor(x->gl_owner));
1197}
1198
1199/* ------------------------- DSP chain handling ------------------------- */
1200
1201EXTERN_STRUCT _dspcontext;
1202#define t_dspcontext struct _dspcontext
1203
1204void ugen_start(void);
1205void ugen_stop(void);
1206
1207t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
1208 int ninlets, int noutlets);
1209void ugen_add(t_dspcontext *dc, t_object *x);
1210void ugen_connect(t_dspcontext *dc, t_object *x1, int outno,
1211 t_object *x2, int inno);
1212void ugen_done_graph(t_dspcontext *dc);
1213
1214 /* schedule one canvas for DSP. This is called below for all "root"
1215 canvases, but is also called from the "dsp" method for sub-
1216 canvases, which are treated almost like any other tilde object. */
1217
1218static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp)
1219{
1220 t_linetraverser t;
1221 t_outconnect *oc;
1222 t_gobj *y;
1223 t_object *ob;
1224 t_symbol *dspsym = gensym("dsp");
1225 t_dspcontext *dc;
1226
1227 /* create a new "DSP graph" object to use in sorting this canvas.
1228 If we aren't toplevel, there are already other dspcontexts around. */
1229
1230 dc = ugen_start_graph(toplevel, sp,
1231 obj_nsiginlets(&x->gl_obj),
1232 obj_nsigoutlets(&x->gl_obj));
1233
1234 /* find all the "dsp" boxes and add them to the graph */
1235
1236 for (y = x->gl_list; y; y = y->g_next)
1237 if ((ob = pd_checkobject(&y->g_pd)) && zgetfn(&y->g_pd, dspsym))
1238 ugen_add(dc, ob);
1239
1240 /* ... and all dsp interconnections */
1241 linetraverser_start(&t, x);
1242 while (oc = linetraverser_next(&t))
1243 if (obj_issignaloutlet(t.tr_ob, t.tr_outno))
1244 ugen_connect(dc, t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
1245
1246 /* finally, sort them and add them to the DSP chain */
1247 ugen_done_graph(dc);
1248}
1249
1250 /* this routine starts DSP for all root canvases. */
1251static void canvas_start_dsp(void)
1252{
1253 t_canvas *x;
1254 if (canvas_dspstate) ugen_stop();
1255 else sys_gui("pdtk_pd_dsp ON\n");
1256 ugen_start();
1257
1258 for (x = canvas_list; x; x = x->gl_next)
1259 canvas_dodsp(x, 1, 0);
1260
1261 canvas_dspstate = 1;
1262}
1263
1264static void canvas_stop_dsp(void)
1265{
1266 if (canvas_dspstate)
1267 {
1268 ugen_stop();
1269 sys_gui("pdtk_pd_dsp OFF\n");
1270 canvas_dspstate = 0;
1271 }
1272}
1273
1274 /* DSP can be suspended before, and resumed after, operations which
1275 might affect the DSP chain. For example, we suspend before loading and
1276 resume afterward, so that DSP doesn't get resorted for every DSP object
1277 int the patch. */
1278
1279int canvas_suspend_dsp(void)
1280{
1281 int rval = canvas_dspstate;
1282 if (rval) canvas_stop_dsp();
1283 return (rval);
1284}
1285
1286void canvas_resume_dsp(int oldstate)
1287{
1288 if (oldstate) canvas_start_dsp();
1289}
1290
1291 /* this is equivalent to suspending and resuming in one step. */
1292void canvas_update_dsp(void)
1293{
1294 if (canvas_dspstate) canvas_start_dsp();
1295}
1296
1297void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv)
1298{
1299 int newstate;
1300 if (argc)
1301 {
1302 newstate = atom_getintarg(0, argc, argv);
1303 if (newstate && !canvas_dspstate)
1304 {
1305 sys_set_audio_state(1);
1306 canvas_start_dsp();
1307 }
1308 else if (!newstate && canvas_dspstate)
1309 {
1310 canvas_stop_dsp();
1311 sys_set_audio_state(0);
1312 }
1313 }
1314 else post("dsp state %d", canvas_dspstate);
1315}
1316
1317 /* LATER replace this with a queueing scheme */
1318void glist_redrawitem(t_glist *owner, t_gobj *gobj)
1319{
1320 if (glist_isvisible(owner))
1321 {
1322 gobj_vis(gobj, owner, 0);
1323 gobj_vis(gobj, owner, 1);
1324 }
1325}
1326
1327 /* redraw all "scalars" (do this if a drawing command is changed.)
1328 LATER we'll use the "template" information to select which ones we
1329 redraw. */
1330static void glist_redrawall(t_glist *gl)
1331{
1332 t_gobj *g;
1333 int vis = glist_isvisible(gl);
1334 for (g = gl->gl_list; g; g = g->g_next)
1335 {
1336 t_class *cl;
1337 if (vis && g->g_pd == scalar_class)
1338 glist_redrawitem(gl, g);
1339 else if (g->g_pd == canvas_class)
1340 glist_redrawall((t_glist *)g);
1341 }
1342}
1343
1344 /* public interface for above */
1345void canvas_redrawallfortemplate(t_canvas *templatecanvas)
1346{
1347 t_canvas *x;
1348 /* find all root canvases */
1349 for (x = canvas_list; x; x = x->gl_next)
1350 glist_redrawall(x);
1351}
1352
1353/* ------------------------------- setup routine ------------------------ */
1354
1355 /* why are some of these "glist" and others "canvas"? */
1356extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv);
1357extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1358extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1359extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1360extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1361extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1362extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1363 /* old version... */
1364extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1365extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1366 /* new version: */
1367extern void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1368extern void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1369extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1370extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1371extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1372extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1373extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1374extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
1375extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv);
1376
1377void g_graph_setup(void);
1378void g_editor_setup(void);
1379void g_readwrite_setup(void);
1380extern void graph_properties(t_gobj *z, t_glist *owner);
1381
1382void g_canvas_setup(void)
1383{
1384 /* we prevent the user from typing "canvas" in an object box
1385 by sending 0 for a creator function. */
1386 canvas_class = class_new(gensym("canvas"), 0,
1387 (t_method)canvas_free, sizeof(t_canvas), CLASS_NOINLET, 0);
1388 /* here is the real creator function, invoked in patch files
1389 by sending the "canvas" message to #N, which is bound
1390 to pd_camvasmaker. */
1391 class_addmethod(pd_canvasmaker, (t_method)canvas_new, gensym("canvas"),
1392 A_GIMME, 0);
1393 class_addmethod(canvas_class, (t_method)canvas_restore,
1394 gensym("restore"), A_GIMME, 0);
1395 class_addmethod(canvas_class, (t_method)canvas_coords,
1396 gensym("coords"), A_GIMME, 0);
1397
1398/* -------------------------- objects ----------------------------- */
1399 class_addmethod(canvas_class, (t_method)canvas_obj,
1400 gensym("obj"), A_GIMME, A_NULL);
1401 class_addmethod(canvas_class, (t_method)canvas_msg,
1402 gensym("msg"), A_GIMME, A_NULL);
1403 class_addmethod(canvas_class, (t_method)canvas_floatatom,
1404 gensym("floatatom"), A_GIMME, A_NULL);
1405 class_addmethod(canvas_class, (t_method)canvas_symbolatom,
1406 gensym("symbolatom"), A_GIMME, A_NULL);
1407 class_addmethod(canvas_class, (t_method)glist_text,
1408 gensym("text"), A_GIMME, A_NULL);
1409 class_addmethod(canvas_class, (t_method)glist_glist, gensym("graph"),
1410 A_GIMME, A_NULL);
1411 class_addmethod(canvas_class, (t_method)glist_scalar,
1412 gensym("scalar"), A_GIMME, A_NULL);
1413
1414 /* -------------- Thomas Musil's GUI objects ------------ */
1415 class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"),
1416 A_GIMME, A_NULL);
1417 class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"),
1418 A_GIMME, A_NULL);
1419 class_addmethod(canvas_class, (t_method)canvas_vslider, gensym("vslider"),
1420 A_GIMME, A_NULL);
1421 class_addmethod(canvas_class, (t_method)canvas_hslider, gensym("hslider"),
1422 A_GIMME, A_NULL);
1423 class_addmethod(canvas_class, (t_method)canvas_hdial, gensym("hdial"),
1424 A_GIMME, A_NULL);
1425 class_addmethod(canvas_class, (t_method)canvas_vdial, gensym("vdial"),
1426 A_GIMME, A_NULL);
1427 class_addmethod(canvas_class, (t_method)canvas_hradio, gensym("hradio"),
1428 A_GIMME, A_NULL);
1429 class_addmethod(canvas_class, (t_method)canvas_vradio, gensym("vradio"),
1430 A_GIMME, A_NULL);
1431 class_addmethod(canvas_class, (t_method)canvas_vumeter, gensym("vumeter"),
1432 A_GIMME, A_NULL);
1433 class_addmethod(canvas_class, (t_method)canvas_mycnv, gensym("mycnv"),
1434 A_GIMME, A_NULL);
1435 class_addmethod(canvas_class, (t_method)canvas_numbox, gensym("numbox"),
1436 A_GIMME, A_NULL);
1437
1438/* ------------------------ gui stuff --------------------------- */
1439 class_addmethod(canvas_class, (t_method)canvas_pop, gensym("pop"),
1440 A_DEFFLOAT, A_NULL);
1441 class_addmethod(canvas_class, (t_method)canvas_loadbang,
1442 gensym("loadbang"), A_NULL);
1443 class_addmethod(canvas_class, (t_method)canvas_relocate,
1444 gensym("relocate"), A_SYMBOL, A_SYMBOL, A_NULL);
1445 class_addmethod(canvas_class, (t_method)canvas_vis,
1446 gensym("vis"), A_FLOAT, A_NULL);
1447 class_addmethod(canvas_class, (t_method)glist_menu_open,
1448 gensym("menu-open"), A_NULL);
1449 class_addmethod(canvas_class, (t_method)canvas_map,
1450 gensym("map"), A_FLOAT, A_NULL);
1451 class_setpropertiesfn(canvas_class, graph_properties);
1452
1453/* ---------------------- list handling ------------------------ */
1454 class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"),
1455 A_NULL);
1456
1457/* ----- subcanvases, which you get by typing "pd" in a box ---- */
1458 class_addcreator((t_newmethod)subcanvas_new, gensym("pd"), A_DEFSYMBOL, 0);
1459 class_addcreator((t_newmethod)subcanvas_new, gensym("page"), A_DEFSYMBOL, 0);
1460
1461 class_addmethod(canvas_class, (t_method)canvas_click,
1462 gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1463 class_addmethod(canvas_class, (t_method)canvas_dsp, gensym("dsp"), 0);
1464 class_addmethod(canvas_class, (t_method)canvas_rename_method,
1465 gensym("rename"), A_GIMME, 0);
1466
1467/*---------------------------- tables -- GG ------------------- */
1468
1469 class_addcreator((t_newmethod)table_new, gensym("table"),
1470 A_DEFSYM, A_DEFFLOAT, 0);
1471
1472/* -------------- setups from other files for canvas_class ---------------- */
1473 g_graph_setup();
1474 g_editor_setup();
1475 g_readwrite_setup();
1476}
1477/* Copyright (c) 1997-2001 Miller Puckette and others.
1478* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1479* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1480
1481/* this file defines the "glist" class, also known as "canvas" (the two used
1482to be different but are now unified except for some fossilized names.) */
1483
1484/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
1485
1486/* bug-fix: canvas_menuclose(): by Krzysztof Czaja */
1487/* bug-fix: table_new(): I reversed the y-bounds */
1488
1489/* IOhannes :
1490 * changed the canvas_restore, so that it might accept $args as well
1491 * (like "pd $0_test")
1492 * so you can make multiple & distinguishable templates
1493 * 1511:forum::für::umläute:2001
1494 * changes marked with IOhannes
1495 */
1496
1497#include <stdlib.h>
1498#include <stdio.h>
1499#include "m_pd.h"
1500#include "m_imp.h"
1501#include "s_stuff.h"
1502#include "g_canvas.h"
1503#include <string.h>
1504#include "g_all_guis.h"
1505
1506struct _canvasenvironment
1507{
1508 t_symbol *ce_dir; /* directory patch lives in */
1509 int ce_argc; /* number of "$" arguments */
1510 t_atom *ce_argv; /* array of "$" arguments */
1511 int ce_dollarzero; /* value of "$0" */
1512};
1513
1514#define GLIST_DEFCANVASWIDTH 240
1515#define GLIST_DEFCANVASHEIGHT 300
1516
1517#ifdef MACOSX
1518#define GLIST_DEFCANVASYLOC 22
1519#else
1520#define GLIST_DEFCANVASYLOC 0
1521#endif
1522
1523/* ---------------------- variables --------------------------- */
1524
1525extern t_pd *newest;
1526t_class *canvas_class;
1527static int canvas_dspstate; /* whether DSP is on or off */
1528t_canvas *canvas_editing; /* last canvas to start text edting */
1529t_canvas *canvas_whichfind; /* last canvas we did a find in */
1530t_canvas *canvas_list; /* list of all root canvases */
1531
1532/* ------------------ forward function declarations --------------- */
1533static void canvas_start_dsp(void);
1534static void canvas_stop_dsp(void);
1535static void canvas_drawlines(t_canvas *x);
1536static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2);
1537static void canvas_reflecttitle(t_canvas *x);
1538static void canvas_addtolist(t_canvas *x);
1539static void canvas_takeofflist(t_canvas *x);
1540static void canvas_pop(t_canvas *x, t_floatarg fvis);
1541void canvas_create_editor(t_glist *x, int createit);
1542
1543/* --------- functions to handle the canvas environment ----------- */
1544
1545static t_symbol *canvas_newfilename = &s_;
1546static t_symbol *canvas_newdirectory = &s_;
1547static int canvas_newargc;
1548static t_atom *canvas_newargv;
1549
1550static void glist_doupdatewindowlist(t_glist *gl, char *sbuf)
1551{
1552 t_gobj *g;
1553 if (!gl->gl_owner)
1554 {
1555 /* this is a canvas; if we have a window, put on "windows" list */
1556 t_canvas *canvas = (t_canvas *)gl;
1557 if (canvas->gl_havewindow)
1558 {
1559 if (strlen(sbuf) + strlen(gl->gl_name->s_name) + 100 <= 1024)
1560 {
1561 char tbuf[1024];
1562 sprintf(tbuf, "{%s .x%x} ", gl->gl_name->s_name, (t_int)canvas);
1563 strcat(sbuf, tbuf);
1564 }
1565 }
1566 }
1567 for (g = gl->gl_list; g; g = g->g_next)
1568 {
1569 if (pd_class(&g->g_pd) == canvas_class)
1570 glist_doupdatewindowlist((t_glist *)g, sbuf);
1571 }
1572 return;
1573}
1574
1575 /* maintain the list of visible toplevels for the GUI's "windows" menu */
1576void canvas_updatewindowlist( void)
1577{
1578 t_canvas *x;
1579 char sbuf[1024];
1580 strcpy(sbuf, "set menu_windowlist {");
1581 /* find all root canvases */
1582 for (x = canvas_list; x; x = x->gl_next)
1583 glist_doupdatewindowlist(x, sbuf);
1584 /* next line updates the window menu state before -postcommand tries it */
1585 strcat(sbuf, "}\npdtk_fixwindowmenu\n");
1586 sys_gui(sbuf);
1587}
1588
1589 /* add a glist the list of "root" canvases (toplevels without parents.) */
1590static void canvas_addtolist(t_canvas *x)
1591{
1592 x->gl_next = canvas_list;
1593 canvas_list = x;
1594}
1595
1596static void canvas_takeofflist(t_canvas *x)
1597{
1598 /* take it off the window list */
1599 if (x == canvas_list) canvas_list = x->gl_next;
1600 else
1601 {
1602 t_canvas *z;
1603 for (z = canvas_list; z->gl_next != x; z = z->gl_next)
1604 ;
1605 z->gl_next = x->gl_next;
1606 }
1607}
1608
1609
1610void canvas_setargs(int argc, t_atom *argv)
1611{
1612 /* if there's an old one lying around free it here. This
1613 happens if an abstraction is loaded but never gets as far
1614 as calling canvas_new(). */
1615 if (canvas_newargv)
1616 freebytes(canvas_newargv, canvas_newargc * sizeof(t_atom));
1617 canvas_newargc = argc;
1618 canvas_newargv = copybytes(argv, argc * sizeof(t_atom));
1619}
1620
1621void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym)
1622{
1623 canvas_newfilename = filesym;
1624 canvas_newdirectory = dirsym;
1625}
1626
1627t_canvas *canvas_getcurrent(void)
1628{
1629 return ((t_canvas *)pd_findbyclass(&s__X, canvas_class));
1630}
1631
1632void canvas_setcurrent(t_canvas *x)
1633{
1634 pd_pushsym(&x->gl_pd);
1635}
1636
1637void canvas_unsetcurrent(t_canvas *x)
1638{
1639 pd_popsym(&x->gl_pd);
1640}
1641
1642t_canvasenvironment *canvas_getenv(t_canvas *x)
1643{
1644 if (!x) bug("canvas_getenv");
1645 while (!x->gl_env)
1646 if (!(x = x->gl_owner))
1647 bug("t_canvasenvironment", x);
1648 return (x->gl_env);
1649}
1650
1651int canvas_getdollarzero( void)
1652{
1653 t_canvas *x = canvas_getcurrent();
1654 t_canvasenvironment *env = (x ? canvas_getenv(x) : 0);
1655 if (env)
1656 return (env->ce_dollarzero);
1657 else return (0);
1658}
1659
1660void canvas_getargs(int *argcp, t_atom **argvp)
1661{
1662 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
1663 *argcp = e->ce_argc;
1664 *argvp = e->ce_argv;
1665}
1666
1667t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s)
1668{
1669 t_symbol *ret;
1670 char *name = s->s_name;
1671 if (*name == '$' && name[1] >= '0' && name[1] <= '9')
1672 {
1673 t_canvasenvironment *env = canvas_getenv(x);
1674 canvas_setcurrent(x);
1675 ret = binbuf_realizedollsym(gensym(name+1),
1676 env->ce_argc, env->ce_argv, 1);
1677 canvas_unsetcurrent(x);
1678 }
1679 else ret = s;
1680 return (ret);
1681}
1682
1683t_symbol *canvas_getcurrentdir(void)
1684{
1685 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
1686 return (e->ce_dir);
1687}
1688
1689t_symbol *canvas_getdir(t_canvas *x)
1690{
1691 t_canvasenvironment *e = canvas_getenv(x);
1692 return (e->ce_dir);
1693}
1694
1695void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize)
1696{
1697 char *dir = canvas_getenv(x)->ce_dir->s_name;
1698 if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir)
1699 {
1700 strncpy(result, file, resultsize);
1701 result[resultsize-1] = 0;
1702 }
1703 else
1704 {
1705 int nleft;
1706 strncpy(result, dir, resultsize);
1707 result[resultsize-1] = 0;
1708 nleft = resultsize - strlen(result) - 1;
1709 if (nleft <= 0) return;
1710 strcat(result, "/");
1711 strncat(result, file, nleft);
1712 result[resultsize-1] = 0;
1713 }
1714}
1715
1716void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir)
1717{
1718 if (strcmp(x->gl_name->s_name, "Pd"))
1719 pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
1720 x->gl_name = s;
1721 if (strcmp(x->gl_name->s_name, "Pd"))
1722 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
1723 if (glist_isvisible(x))
1724 canvas_reflecttitle(x);
1725 if (dir && dir != &s_)
1726 {
1727 t_canvasenvironment *e = canvas_getenv(x);
1728 e->ce_dir = dir;
1729 }
1730}
1731
1732/* --------------- traversing the set of lines in a canvas ----------- */
1733
1734int canvas_getindex(t_canvas *x, t_gobj *y)
1735{
1736 t_gobj *y2;
1737 int indexno;
1738 for (indexno = 0, y2 = x->gl_list; y2 && y2 != y; y2 = y2->g_next)
1739 indexno++;
1740 return (indexno);
1741}
1742
1743void linetraverser_start(t_linetraverser *t, t_canvas *x)
1744{
1745 t->tr_ob = 0;
1746 t->tr_x = x;
1747 t->tr_nextoc = 0;
1748 t->tr_nextoutno = t->tr_nout = 0;
1749}
1750
1751t_outconnect *linetraverser_next(t_linetraverser *t)
1752{
1753 t_outconnect *rval = t->tr_nextoc;
1754 int outno;
1755 while (!rval)
1756 {
1757 outno = t->tr_nextoutno;
1758 while (outno == t->tr_nout)
1759 {
1760 t_gobj *y;
1761 t_object *ob = 0;
1762 if (!t->tr_ob) y = t->tr_x->gl_list;
1763 else y = t->tr_ob->ob_g.g_next;
1764 for (; y; y = y->g_next)
1765 if (ob = pd_checkobject(&y->g_pd)) break;
1766 if (!ob) return (0);
1767 t->tr_ob = ob;
1768 t->tr_nout = obj_noutlets(ob);
1769 outno = 0;
1770 if (glist_isvisible(t->tr_x))
1771 gobj_getrect(y, t->tr_x,
1772 &t->tr_x11, &t->tr_y11, &t->tr_x12, &t->tr_y12);
1773 else t->tr_x11 = t->tr_y11 = t->tr_x12 = t->tr_y12 = 0;
1774 }
1775 t->tr_nextoutno = outno + 1;
1776 rval = obj_starttraverseoutlet(t->tr_ob, &t->tr_outlet, outno);
1777 t->tr_outno = outno;
1778 }
1779 t->tr_nextoc = obj_nexttraverseoutlet(rval, &t->tr_ob2,
1780 &t->tr_inlet, &t->tr_inno);
1781 t->tr_nin = obj_ninlets(t->tr_ob2);
1782 if (!t->tr_nin) bug("drawline");
1783 if (glist_isvisible(t->tr_x))
1784 {
1785 int inplus = (t->tr_nin == 1 ? 1 : t->tr_nin - 1);
1786 int outplus = (t->tr_nout == 1 ? 1 : t->tr_nout - 1);
1787 gobj_getrect(&t->tr_ob2->ob_g, t->tr_x,
1788 &t->tr_x21, &t->tr_y21, &t->tr_x22, &t->tr_y22);
1789 t->tr_lx1 = t->tr_x11 +
1790 ((t->tr_x12 - t->tr_x11 - IOWIDTH) * t->tr_outno) /
1791 outplus + IOMIDDLE;
1792 t->tr_ly1 = t->tr_y12;
1793 t->tr_lx2 = t->tr_x21 +
1794 ((t->tr_x22 - t->tr_x21 - IOWIDTH) * t->tr_inno)/inplus +
1795 IOMIDDLE;
1796 t->tr_ly2 = t->tr_y21;
1797 }
1798 else
1799 {
1800 t->tr_x21 = t->tr_y21 = t->tr_x22 = t->tr_y22 = 0;
1801 t->tr_lx1 = t->tr_ly1 = t->tr_lx2 = t->tr_ly2 = 0;
1802 }
1803
1804 return (rval);
1805}
1806
1807void linetraverser_skipobject(t_linetraverser *t)
1808{
1809 t->tr_nextoc = 0;
1810 t->tr_nextoutno = t->tr_nout;
1811}
1812
1813/* -------------------- the canvas object -------------------------- */
1814int glist_valid = 10000;
1815
1816void glist_init(t_glist *x)
1817{
1818 /* zero out everyone except "pd" field */
1819 memset(((char *)x) + sizeof(x->gl_pd), 0, sizeof(*x) - sizeof(x->gl_pd));
1820 x->gl_stub = gstub_new(x, 0);
1821 x->gl_valid = ++glist_valid;
1822 x->gl_xlabel = (t_symbol **)t_getbytes(0);
1823 x->gl_ylabel = (t_symbol **)t_getbytes(0);
1824}
1825
1826 /* make a new glist. It will either be a "root" canvas or else
1827 its parent will be a "text" object in another window... we don't
1828 know which yet. */
1829t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
1830{
1831 t_canvas *x = (t_canvas *)pd_new(canvas_class);
1832 t_canvas *owner = canvas_getcurrent();
1833 t_symbol *s = &s_;
1834 int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT;
1835 int xloc = 0, yloc = GLIST_DEFCANVASYLOC;
1836 int font = (owner ? owner->gl_font : sys_defaultfont);
1837 glist_init(x);
1838 x->gl_obj.te_type = T_OBJECT;
1839 if (!owner)
1840 canvas_addtolist(x);
1841 /* post("canvas %x, owner %x", x, owner); */
1842
1843 if (argc == 5) /* toplevel: x, y, w, h, font */
1844 {
1845 xloc = atom_getintarg(0, argc, argv);
1846 yloc = atom_getintarg(1, argc, argv);
1847 width = atom_getintarg(2, argc, argv);
1848 height = atom_getintarg(3, argc, argv);
1849 font = atom_getintarg(4, argc, argv);
1850 }
1851 else if (argc == 6) /* subwindow: x, y, w, h, name, vis */
1852 {
1853 xloc = atom_getintarg(0, argc, argv);
1854 yloc = atom_getintarg(1, argc, argv);
1855 width = atom_getintarg(2, argc, argv);
1856 height = atom_getintarg(3, argc, argv);
1857 s = atom_getsymbolarg(4, argc, argv);
1858 vis = atom_getintarg(5, argc, argv);
1859 }
1860 /* (otherwise assume we're being created from the menu.) */
1861
1862 if (canvas_newdirectory->s_name[0])
1863 {
1864 static int dollarzero = 1000;
1865 t_canvasenvironment *env = x->gl_env =
1866 (t_canvasenvironment *)getbytes(sizeof(*x->gl_env));
1867 env->ce_dir = canvas_newdirectory;
1868 env->ce_argc = canvas_newargc;
1869 env->ce_argv = canvas_newargv;
1870 env->ce_dollarzero = dollarzero++;
1871 canvas_newdirectory = &s_;
1872 canvas_newargc = 0;
1873 canvas_newargv = 0;
1874 }
1875 else x->gl_env = 0;
1876
1877 if (yloc < GLIST_DEFCANVASYLOC)
1878 yloc = GLIST_DEFCANVASYLOC;
1879 if (xloc < 0)
1880 xloc = 0;
1881 x->gl_x1 = 0;
1882 x->gl_y1 = 0;
1883 x->gl_x2 = 1;
1884 x->gl_y2 = 1;
1885 canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height);
1886 x->gl_owner = owner;
1887 x->gl_name = (*s->s_name ? s :
1888 (canvas_newfilename ? canvas_newfilename : gensym("Pd")));
1889 if (strcmp(x->gl_name->s_name, "Pd"))
1890 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
1891 x->gl_loading = 1;
1892 x->gl_willvis = vis;
1893 x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8);
1894 x->gl_font = sys_nearestfontsize(font);
1895 pd_pushsym(&x->gl_pd);
1896 return(x);
1897}
1898
1899void canvas_setgraph(t_glist *x, int flag);
1900
1901static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv)
1902{
1903 x->gl_x1 = atom_getfloatarg(0, argc, argv);
1904 x->gl_y1 = atom_getfloatarg(1, argc, argv);
1905 x->gl_x2 = atom_getfloatarg(2, argc, argv);
1906 x->gl_y2 = atom_getfloatarg(3, argc, argv);
1907 x->gl_pixwidth = atom_getintarg(4, argc, argv);
1908 x->gl_pixheight = atom_getintarg(5, argc, argv);
1909 canvas_setgraph(x, atom_getintarg(6, argc, argv));
1910}
1911
1912 /* make a new glist and add it to this glist. It will appear as
1913 a "graph", not a text object. */
1914t_glist *glist_addglist(t_glist *g, t_symbol *sym,
1915 float x1, float y1, float x2, float y2,
1916 float px1, float py1, float px2, float py2)
1917{
1918 static int gcount = 0;
1919 int zz;
1920 int menu = 0;
1921 char *str;
1922 t_glist *x = (t_glist *)pd_new(canvas_class);
1923 glist_init(x);
1924 x->gl_obj.te_type = T_OBJECT;
1925 if (!*sym->s_name)
1926 {
1927 char buf[40];
1928 sprintf(buf, "graph%d", ++gcount);
1929 sym = gensym(buf);
1930 menu = 1;
1931 }
1932 else if (!strncmp((str = sym->s_name), "graph", 5)
1933 && (zz = atoi(str + 5)) > gcount)
1934 gcount = zz;
1935 /* in 0.34 and earlier, the pixel rectangle and the y bounds were
1936 reversed; this would behave the same, except that the dialog window
1937 would be confusing. The "correct" way is to have "py1" be the value
1938 that is higher on the screen. */
1939 if (py2 < py1)
1940 {
1941 float zz;
1942 zz = y2;
1943 y2 = y1;
1944 y1 = zz;
1945 zz = py2;
1946 py2 = py1;
1947 py1 = zz;
1948 }
1949 if (x1 == x2 || y1 == y2)
1950 x1 = 0, x2 = 100, y1 = 1, y2 = -1;
1951 if (px1 >= px2 || py1 >= py2)
1952 px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH,
1953 py2 = 20 + GLIST_DEFGRAPHHEIGHT;
1954 x->gl_name = sym;
1955 x->gl_x1 = x1;
1956 x->gl_x2 = x2;
1957 x->gl_y1 = y1;
1958 x->gl_y2 = y2;
1959 x->gl_obj.te_xpix = px1;
1960 x->gl_obj.te_ypix = py1;
1961 x->gl_pixwidth = px2 - px1;
1962 x->gl_pixheight = py2 - py1;
1963 x->gl_font = (canvas_getcurrent() ?
1964 canvas_getcurrent()->gl_font : sys_defaultfont);
1965 x->gl_screenx1 = x->gl_screeny1 = 0;
1966 x->gl_screenx2 = 240;
1967 x->gl_screeny2 = 300;
1968 if (strcmp(x->gl_name->s_name, "Pd"))
1969 pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
1970 x->gl_owner = g;
1971 x->gl_stretch = 1;
1972 x->gl_isgraph = 1;
1973 x->gl_obj.te_binbuf = binbuf_new();
1974 binbuf_addv(x->gl_obj.te_binbuf, "s", gensym("graph"));
1975 if (!menu)
1976 pd_pushsym(&x->gl_pd);
1977 glist_add(g, &x->gl_gobj);
1978 if (glist_isvisible(g))
1979 canvas_create_editor(x, 1);
1980 return (x);
1981}
1982
1983 /* call glist_addglist from a Pd message */
1984void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv)
1985{
1986 t_symbol *sym = atom_getsymbolarg(0, argc, argv);
1987 float x1 = atom_getfloatarg(1, argc, argv);
1988 float y1 = atom_getfloatarg(2, argc, argv);
1989 float x2 = atom_getfloatarg(3, argc, argv);
1990 float y2 = atom_getfloatarg(4, argc, argv);
1991 float px1 = atom_getfloatarg(5, argc, argv);
1992 float py1 = atom_getfloatarg(6, argc, argv);
1993 float px2 = atom_getfloatarg(7, argc, argv);
1994 float py2 = atom_getfloatarg(8, argc, argv);
1995 glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2);
1996}
1997
1998 /* return true if the glist should appear as a graph on parent;
1999 otherwise it appears as a text box. */
2000int glist_isgraph(t_glist *x)
2001{
2002 return (x->gl_isgraph);
2003}
2004
2005 /* This is sent from the GUI to inform a toplevel that its window has been
2006 moved or resized. */
2007static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2)
2008{
2009 int heightwas = y2 - y1;
2010 int heightchange = y2 - y1 - (x->gl_screeny2 - x->gl_screeny1);
2011 x->gl_screenx1 = x1;
2012 x->gl_screeny1 = y1;
2013 x->gl_screenx2 = x2;
2014 x->gl_screeny2 = y2;
2015 /* post("set bounds %d %d %d %d", x1, y1, x2, y2); */
2016 if (!glist_isgraph(x) && (x->gl_y2 < x->gl_y1))
2017 {
2018 /* if it's flipped so that y grows upward,
2019 fix so that zero is bottom edge and redraw. This is
2020 only appropriate if we're a regular "text" object on the
2021 parent. */
2022 float diff = x->gl_y1 - x->gl_y2;
2023 t_gobj *y;
2024 x->gl_y1 = heightwas * diff;
2025 x->gl_y2 = x->gl_y1 - diff;
2026 /* and move text objects accordingly; they should stick
2027 to the bottom, not the top. */
2028 for (y = x->gl_list; y; y = y->g_next)
2029 if (pd_checkobject(&y->g_pd))
2030 gobj_displace(y, x, 0, heightchange);
2031 canvas_redraw(x);
2032 }
2033}
2034
2035t_symbol *canvas_makebindsym(t_symbol *s)
2036{
2037 char buf[MAXPDSTRING];
2038 strcpy(buf, "pd-");
2039 strcat(buf, s->s_name);
2040 return (gensym(buf));
2041}
2042
2043void canvas_reflecttitle(t_canvas *x)
2044{
2045 char namebuf[MAXPDSTRING];
2046 t_canvasenvironment *env = canvas_getenv(x);
2047 if (env->ce_argc)
2048 {
2049 int i;
2050 strcpy(namebuf, " (");
2051 for (i = 0; i < env->ce_argc; i++)
2052 {
2053 if (strlen(namebuf) > MAXPDSTRING/2 - 5)
2054 break;
2055 if (i != 0)
2056 strcat(namebuf, " ");
2057 atom_string(&env->ce_argv[i], namebuf + strlen(namebuf),
2058 MAXPDSTRING/2);
2059 }
2060 strcat(namebuf, ")");
2061 }
2062 else namebuf[0] = 0;
2063 sys_vgui("wm title .x%x {%s%c%s - %s}\n",
2064 x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf,
2065 canvas_getdir(x)->s_name);
2066}
2067
2068void canvas_dirty(t_canvas *x, t_int n)
2069{
2070 t_canvas *x2 = canvas_getrootfor(x);
2071 if ((unsigned)n != x2->gl_dirty)
2072 {
2073 x2->gl_dirty = n;
2074 canvas_reflecttitle(x2);
2075 }
2076}
2077
2078 /* the window becomes "mapped" (visible and not miniaturized) or
2079 "unmapped" (either miniaturized or just plain gone.) This should be
2080 called from the GUI after the fact to "notify" us that we're mapped. */
2081void canvas_map(t_canvas *x, t_floatarg f)
2082{
2083 int flag = (f != 0);
2084 t_gobj *y;
2085 if (flag)
2086 {
2087 if (!glist_isvisible(x))
2088 {
2089 t_selection *sel;
2090 if (!x->gl_havewindow)
2091 {
2092 bug("canvas_map");
2093 canvas_vis(x, 1);
2094 }
2095 for (y = x->gl_list; y; y = y->g_next)
2096 gobj_vis(y, x, 1);
2097 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
2098 gobj_select(sel->sel_what, x, 1);
2099 x->gl_mapped = 1;
2100 canvas_drawlines(x);
2101 /* simulate a mouse up so u_main will calculate scrollbars...
2102 ugly! */
2103 sys_vgui("pdtk_canvas_mouseup .x%x.c 0 0 0\n", x);
2104 }
2105 }
2106 else
2107 {
2108 if (glist_isvisible(x))
2109 {
2110 /* just clear out the whole canvas... */
2111 sys_vgui(".x%x.c delete all\n", x);
2112 /* alternatively, we could have erased them one by one...
2113 for (y = x->gl_list; y; y = y->g_next)
2114 gobj_vis(y, x, 0);
2115 ... but we should go through and erase the lines as well
2116 if we do it that way. */
2117 x->gl_mapped = 0;
2118 }
2119 }
2120}
2121
2122void canvas_redraw(t_canvas *x)
2123{
2124 if (glist_isvisible(x))
2125 {
2126 canvas_map(x, 0);
2127 canvas_map(x, 1);
2128 }
2129}
2130
2131/* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */
2132
2133static t_editor *editor_new(t_glist *owner)
2134{
2135 char buf[40];
2136 t_editor *x = (t_editor *)getbytes(sizeof(*x));
2137 x->e_connectbuf = binbuf_new();
2138 x->e_deleted = binbuf_new();
2139 x->e_glist = owner;
2140 sprintf(buf, ".x%x", (t_int)owner);
2141 x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf));
2142 return (x);
2143}
2144
2145static void editor_free(t_editor *x, t_glist *y)
2146{
2147 glist_noselect(y);
2148 guiconnect_notarget(x->e_guiconnect, 1000);
2149 binbuf_free(x->e_connectbuf);
2150 binbuf_free(x->e_deleted);
2151 freebytes((void *)x, sizeof(*x));
2152}
2153
2154 /* recursively create or destroy all editors of a glist and its
2155 sub-glists, as long as they aren't toplevels. */
2156void canvas_create_editor(t_glist *x, int createit)
2157{
2158 t_gobj *y;
2159 t_object *ob;
2160 if (createit)
2161 {
2162 if (x->gl_editor)
2163 bug("canvas_create_editor");
2164 else
2165 {
2166 x->gl_editor = editor_new(x);
2167 for (y = x->gl_list; y; y = y->g_next)
2168 if (ob = pd_checkobject(&y->g_pd))
2169 rtext_new(x, ob);
2170 }
2171 }
2172 else
2173 {
2174 if (!x->gl_editor)
2175 bug("canvas_create_editor");
2176 else
2177 {
2178 for (y = x->gl_list; y; y = y->g_next)
2179 if (ob = pd_checkobject(&y->g_pd))
2180 rtext_free(glist_findrtext(x, ob));
2181 editor_free(x->gl_editor, x);
2182 x->gl_editor = 0;
2183 }
2184 }
2185 for (y = x->gl_list; y; y = y->g_next)
2186 if (pd_class(&y->g_pd) == canvas_class &&
2187 ((t_canvas *)y)->gl_isgraph)
2188 canvas_create_editor((t_canvas *)y, createit);
2189}
2190
2191 /* we call this when we want the window to become visible, mapped, and
2192 in front of all windows; or with "f" zero, when we want to get rid of
2193 the window. */
2194void canvas_vis(t_canvas *x, t_floatarg f)
2195{
2196 char buf[30];
2197 int flag = (f != 0);
2198 if (flag)
2199 {
2200 /* test if we're already visible and toplevel */
2201 if (glist_isvisible(x) && !x->gl_isgraph)
2202 { /* just put us in front */
2203#ifdef MSW
2204 canvas_vis(x, 0);
2205 canvas_vis(x, 1);
2206#else
2207 sys_vgui("raise .x%x\n", x);
2208 sys_vgui("focus .x%x.c\n", x);
2209 sys_vgui("wm deiconify .x%x\n", x);
2210#endif
2211 }
2212 else
2213 {
2214 canvas_create_editor(x, 1);
2215 sys_vgui("pdtk_canvas_new .x%x %d %d +%d+%d %d\n", x,
2216 (int)(x->gl_screenx2 - x->gl_screenx1),
2217 (int)(x->gl_screeny2 - x->gl_screeny1),
2218 (int)(x->gl_screenx1), (int)(x->gl_screeny1),
2219 x->gl_edit);
2220 canvas_reflecttitle(x);
2221 x->gl_havewindow = 1;
2222 canvas_updatewindowlist();
2223 }
2224 }
2225 else /* make invisible */
2226 {
2227 int i;
2228 t_canvas *x2;
2229 if (!x->gl_havewindow)
2230 {
2231 /* bug workaround -- a graph in a visible patch gets "invised"
2232 when the patch is closed, and must lose the editor here. It's
2233 probably not the natural place to do this. Other cases like
2234 subpatches fall here too but don'd need the editor freed, so
2235 we check if it exists. */
2236 if (x->gl_editor)
2237 canvas_create_editor(x, 0);
2238 return;
2239 }
2240 glist_noselect(x);
2241 if (glist_isvisible(x))
2242 canvas_map(x, 0);
2243 canvas_create_editor(x, 0);
2244 sys_vgui("destroy .x%x\n", x);
2245 for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++)
2246 ;
2247 sys_vgui(".mbar.find delete %d\n", i);
2248 /* if we're a graph on our parent, and if the parent exists
2249 and is visible, show ourselves on parent. */
2250 if (glist_isgraph(x) && x->gl_owner)
2251 {
2252 t_glist *gl2 = x->gl_owner;
2253 canvas_create_editor(x, 1);
2254 if (glist_isvisible(gl2))
2255 gobj_vis(&x->gl_gobj, gl2, 0);
2256 x->gl_havewindow = 0;
2257 if (glist_isvisible(gl2))
2258 gobj_vis(&x->gl_gobj, gl2, 1);
2259 }
2260 else x->gl_havewindow = 0;
2261 canvas_updatewindowlist();
2262 }
2263}
2264
2265 /* we call this on a non-toplevel glist to "open" it into its
2266 own window. */
2267void glist_menu_open(t_glist *x)
2268{
2269 if (glist_isvisible(x) && !glist_istoplevel(x))
2270 {
2271 t_glist *gl2 = x->gl_owner;
2272 if (!gl2)
2273 bug("canvas_vis"); /* shouldn't happen but don't get too upset. */
2274 else
2275 {
2276 /* erase ourself in parent window */
2277 gobj_vis(&x->gl_gobj, gl2, 0);
2278 /* get rid of our editor (and subeditors) */
2279 canvas_create_editor(x, 0);
2280 x->gl_havewindow = 1;
2281 /* redraw ourself in parent window (blanked out this time) */
2282 gobj_vis(&x->gl_gobj, gl2, 1);
2283 }
2284 }
2285 canvas_vis(x, 1);
2286}
2287
2288int glist_isvisible(t_glist *x)
2289{
2290 return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped);
2291}
2292
2293int glist_istoplevel(t_glist *x)
2294{
2295 /* we consider a graph "toplevel" if it has its own window
2296 or if it appears as a box in its parent window so that we
2297 don't draw the actual contents there. */
2298 return (x->gl_havewindow || !x->gl_isgraph);
2299}
2300
2301int glist_getfont(t_glist *x)
2302{
2303 return (glist_getcanvas(x)->gl_font);
2304}
2305
2306void canvas_free(t_canvas *x)
2307{
2308 t_gobj *y;
2309 int dspstate = canvas_suspend_dsp();
2310 canvas_noundo(x);
2311 if (canvas_editing == x)
2312 canvas_editing = 0;
2313 if (canvas_whichfind == x)
2314 canvas_whichfind = 0;
2315 glist_noselect(x);
2316 while (y = x->gl_list)
2317 glist_delete(x, y);
2318 canvas_vis(x, 0);
2319
2320 if (strcmp(x->gl_name->s_name, "Pd"))
2321 pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
2322 if (x->gl_env)
2323 {
2324 freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom));
2325 freebytes(x->gl_env, sizeof(*x->gl_env));
2326 }
2327 canvas_resume_dsp(dspstate);
2328 glist_cleanup(x);
2329 gfxstub_deleteforkey(x); /* probably unnecessary */
2330 if (!x->gl_owner)
2331 canvas_takeofflist(x);
2332}
2333
2334/* ----------------- lines ---------- */
2335
2336static void canvas_drawlines(t_canvas *x)
2337{
2338 t_linetraverser t;
2339 t_outconnect *oc;
2340 {
2341 linetraverser_start(&t, x);
2342 while (oc = linetraverser_next(&t))
2343 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
2344 glist_getcanvas(x),
2345 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2,
2346 (outlet_getsymbol(t.tr_outlet) == &s_signal ? 2:1),
2347 oc);
2348 }
2349}
2350
2351void canvas_fixlinesfor(t_canvas *x, t_text *text)
2352{
2353 t_linetraverser t;
2354 t_outconnect *oc;
2355
2356 linetraverser_start(&t, x);
2357 while (oc = linetraverser_next(&t))
2358 {
2359 if (t.tr_ob == text || t.tr_ob2 == text)
2360 {
2361 sys_vgui(".x%x.c coords l%x %d %d %d %d\n",
2362 glist_getcanvas(x), oc,
2363 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2);
2364 }
2365 }
2366}
2367
2368 /* kill all lines for the object */
2369void canvas_deletelinesfor(t_canvas *x, t_text *text)
2370{
2371 t_linetraverser t;
2372 t_outconnect *oc;
2373 linetraverser_start(&t, x);
2374 while (oc = linetraverser_next(&t))
2375 {
2376 if (t.tr_ob == text || t.tr_ob2 == text)
2377 {
2378 if (x->gl_editor)
2379 {
2380 sys_vgui(".x%x.c delete l%x\n",
2381 glist_getcanvas(x), oc);
2382 }
2383 obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
2384 }
2385 }
2386}
2387
2388 /* kill all lines for one inlet or outlet */
2389void canvas_deletelinesforio(t_canvas *x, t_text *text,
2390 t_inlet *inp, t_outlet *outp)
2391{
2392 t_linetraverser t;
2393 t_outconnect *oc;
2394 linetraverser_start(&t, x);
2395 while (oc = linetraverser_next(&t))
2396 {
2397 if ((t.tr_ob == text && t.tr_outlet == outp) ||
2398 (t.tr_ob2 == text && t.tr_inlet == inp))
2399 {
2400 if (x->gl_editor)
2401 {
2402 sys_vgui(".x%x.c delete l%x\n",
2403 glist_getcanvas(x), oc);
2404 }
2405 obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
2406 }
2407 }
2408}
2409
2410static void canvas_pop(t_canvas *x, t_floatarg fvis)
2411{
2412 if (fvis != 0)
2413 canvas_vis(x, 1);
2414 pd_popsym(&x->gl_pd);
2415 canvas_resortinlets(x);
2416 canvas_resortoutlets(x);
2417 x->gl_loading = 0;
2418}
2419
2420void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv);
2421
2422
2423void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
2424{ /* IOhannes */
2425 t_pd *z;
2426 /* this should be unnecessary, but sometimes the canvas's name gets
2427 out of sync with the owning box's argument; this fixes that */
2428 if (argc > 3)
2429 {
2430 t_atom *ap=argv+3;
2431 if (ap->a_type == A_SYMBOL)
2432 {
2433 char *buf=ap->a_w.w_symbol->s_name, *bufp;
2434 if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9')
2435 {
2436 for (bufp = buf+2; *bufp; bufp++)
2437 if (*bufp < '0' || *bufp > '9')
2438 {
2439 SETDOLLSYM(ap, gensym(buf+1));
2440 goto didit;
2441 }
2442 SETDOLLAR(ap, atoi(buf+1));
2443 didit: ;
2444 }
2445 }
2446
2447 if (ap->a_type == A_DOLLSYM)
2448 {
2449 t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
2450 canvas_rename(x, binbuf_realizedollsym(ap->a_w.w_symbol,
2451 e->ce_argc, e->ce_argv, 1), 0);
2452 }
2453 else if (ap->a_type == A_SYMBOL)
2454 canvas_rename(x, argv[3].a_w.w_symbol, 0);
2455 }
2456 canvas_pop(x, x->gl_willvis);
2457
2458 if (!(z = gensym("#X")->s_thing)) error("canvas_restore: out of context");
2459 else if (*z != canvas_class) error("canvas_restore: wasn't a canvas");
2460 else
2461 {
2462 t_canvas *x2 = (t_canvas *)z;
2463 x->gl_owner = x2;
2464 canvas_objfor(x2, &x->gl_obj, argc, argv);
2465 }
2466}
2467
2468static void canvas_loadbangabstractions(t_canvas *x)
2469{
2470 t_gobj *y;
2471 t_symbol *s = gensym("loadbang");
2472 for (y = x->gl_list; y; y = y->g_next)
2473 if (pd_class(&y->g_pd) == canvas_class)
2474 {
2475 if (canvas_isabstraction((t_canvas *)y))
2476 canvas_loadbang((t_canvas *)y);
2477 else
2478 canvas_loadbangabstractions((t_canvas *)y);
2479 }
2480}
2481
2482void canvas_loadbangsubpatches(t_canvas *x)
2483{
2484 t_gobj *y;
2485 t_symbol *s = gensym("loadbang");
2486 for (y = x->gl_list; y; y = y->g_next)
2487 if (pd_class(&y->g_pd) == canvas_class)
2488 {
2489 if (!canvas_isabstraction((t_canvas *)y))
2490 canvas_loadbangsubpatches((t_canvas *)y);
2491 }
2492 for (y = x->gl_list; y; y = y->g_next)
2493 if ((pd_class(&y->g_pd) != canvas_class) &&
2494 zgetfn(&y->g_pd, s))
2495 pd_vmess(&y->g_pd, s, "");
2496}
2497
2498void canvas_loadbang(t_canvas *x)
2499{
2500 t_gobj *y;
2501 canvas_loadbangabstractions(x);
2502 canvas_loadbangsubpatches(x);
2503}
2504
2505 /* When you ask a canvas its size the result is 2 pixels more than what
2506 you gave it to open it; perhaps there's a 1-pixel border all around it
2507 or something. Anyway, we just add the 2 pixels back here; seems we
2508 have to do this for linux but not MSW; not sure about MacOS. */
2509
2510#ifdef MSW
2511#define HORIZBORDER 0
2512#define VERTBORDER 0
2513#else
2514#define HORIZBORDER 2
2515#define VERTBORDER 2
2516#endif
2517
2518static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom,
2519 t_symbol *topgeom)
2520{
2521 int cxpix, cypix, cw, ch, txpix, typix, tw, th;
2522 if (sscanf(canvasgeom->s_name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix)
2523 < 4 ||
2524 sscanf(topgeom->s_name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4)
2525 bug("canvas_relocate");
2526 /* for some reason this is initially called with cw=ch=1 so
2527 we just suppress that here. */
2528 if (cw > 5 && ch > 5)
2529 canvas_setbounds(x, txpix, typix,
2530 txpix + cw - HORIZBORDER, typix + ch - VERTBORDER);
2531}
2532
2533void canvas_popabstraction(t_canvas *x)
2534{
2535 newest = &x->gl_pd;
2536 pd_popsym(&x->gl_pd);
2537 x->gl_loading = 0;
2538 canvas_resortinlets(x);
2539 canvas_resortoutlets(x);
2540}
2541
2542void canvas_logerror(t_object *y)
2543{
2544#ifdef LATER
2545 canvas_vis(x, 1);
2546 if (!glist_isselected(x, &y->ob_g))
2547 glist_select(x, &y->ob_g);
2548#endif
2549}
2550
2551/* -------------------------- subcanvases ---------------------- */
2552
2553static void *subcanvas_new(t_symbol *s)
2554{
2555 t_atom a[6];
2556 t_canvas *x, *z = canvas_getcurrent();
2557 if (!*s->s_name) s = gensym("/SUBPATCH/");
2558 SETFLOAT(a, 0);
2559 SETFLOAT(a+1, GLIST_DEFCANVASYLOC);
2560 SETFLOAT(a+2, GLIST_DEFCANVASWIDTH);
2561 SETFLOAT(a+3, GLIST_DEFCANVASHEIGHT);
2562 SETSYMBOL(a+4, s);
2563 SETFLOAT(a+5, 1);
2564 x = canvas_new(0, 0, 6, a);
2565 x->gl_owner = z;
2566 canvas_pop(x, 1);
2567 return (x);
2568}
2569
2570static void canvas_click(t_canvas *x,
2571 t_floatarg xpos, t_floatarg ypos,
2572 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
2573{
2574 canvas_vis(x, 1);
2575}
2576
2577
2578 /* find out from subcanvas contents how much to fatten the box */
2579void canvas_fattensub(t_canvas *x,
2580 int *xp1, int *yp1, int *xp2, int *yp2)
2581{
2582 t_gobj *y;
2583 *xp2 += 50; /* fake for now */
2584 *yp2 += 50;
2585}
2586
2587static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av)
2588{
2589 if (ac && av->a_type == A_SYMBOL)
2590 canvas_rename(x, av->a_w.w_symbol, 0);
2591 else canvas_rename(x, gensym("Pd"), 0);
2592}
2593
2594/* ------------------ table ---------------------------*/
2595
2596static int tabcount = 0;
2597
2598static void *table_new(t_symbol *s, t_floatarg f)
2599{
2600 t_atom a[9];
2601 t_glist *gl;
2602 t_canvas *x, *z = canvas_getcurrent();
2603 if (s == &s_)
2604 {
2605 char tabname[255];
2606 t_symbol *t = gensym("table");
2607 sprintf(tabname, "%s%d", t->s_name, tabcount++);
2608 s = gensym(tabname);
2609 }
2610 if (f <= 1)
2611 f = 100;
2612 SETFLOAT(a, 0);
2613 SETFLOAT(a+1, GLIST_DEFCANVASYLOC);
2614 SETFLOAT(a+2, 600);
2615 SETFLOAT(a+3, 400);
2616 SETSYMBOL(a+4, s);
2617 SETFLOAT(a+5, 0);
2618 x = canvas_new(0, 0, 6, a);
2619
2620 x->gl_owner = z;
2621
2622 /* create a graph for the table */
2623 gl = glist_addglist((t_glist*)x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1,
2624 50, 350, 550, 50);
2625
2626 graph_array(gl, s, &s_float, f, 0);
2627
2628 canvas_pop(x, 0);
2629
2630 return (x);
2631}
2632
2633 /* return true if the "canvas" object is an abstraction (so we don't
2634 save its contents, fogr example.) */
2635int canvas_isabstraction(t_canvas *x)
2636{
2637 return (x->gl_env != 0);
2638}
2639
2640 /* return true if the "canvas" object is a "table". */
2641int canvas_istable(t_canvas *x)
2642{
2643 t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
2644 int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
2645 int istable = (argc && argv[0].a_type == A_SYMBOL &&
2646 argv[0].a_w.w_symbol == gensym("table"));
2647 return (istable);
2648}
2649
2650 /* return true if the "canvas" object should be treated as a text
2651 object. This is true for abstractions but also for "table"s... */
2652int canvas_showtext(t_canvas *x)
2653{
2654 t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
2655 int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
2656 int isarray = (argc && argv[0].a_type == A_SYMBOL &&
2657 argv[0].a_w.w_symbol == gensym("graph"));
2658 return (!isarray);
2659}
2660
2661static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp);
2662static void canvas_dsp(t_canvas *x, t_signal **sp)
2663{
2664 canvas_dodsp(x, 0, sp);
2665}
2666
2667 /* get the document containing this canvas */
2668t_canvas *canvas_getrootfor(t_canvas *x)
2669{
2670 if ((!x->gl_owner) || canvas_isabstraction(x))
2671 return (x);
2672 else return (canvas_getrootfor(x->gl_owner));
2673}
2674
2675/* ------------------------- DSP chain handling ------------------------- */
2676
2677EXTERN_STRUCT _dspcontext;
2678#define t_dspcontext struct _dspcontext
2679
2680void ugen_start(void);
2681void ugen_stop(void);
2682
2683t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
2684 int ninlets, int noutlets);
2685void ugen_add(t_dspcontext *dc, t_object *x);
2686void ugen_connect(t_dspcontext *dc, t_object *x1, int outno,
2687 t_object *x2, int inno);
2688void ugen_done_graph(t_dspcontext *dc);
2689
2690 /* schedule one canvas for DSP. This is called below for all "root"
2691 canvases, but is also called from the "dsp" method for sub-
2692 canvases, which are treated almost like any other tilde object. */
2693
2694static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp)
2695{
2696 t_linetraverser t;
2697 t_outconnect *oc;
2698 t_gobj *y;
2699 t_object *ob;
2700 t_symbol *dspsym = gensym("dsp");
2701 t_dspcontext *dc;
2702
2703 /* create a new "DSP graph" object to use in sorting this canvas.
2704 If we aren't toplevel, there are already other dspcontexts around. */
2705
2706 dc = ugen_start_graph(toplevel, sp,
2707 obj_nsiginlets(&x->gl_obj),
2708 obj_nsigoutlets(&x->gl_obj));
2709
2710 /* find all the "dsp" boxes and add them to the graph */
2711
2712 for (y = x->gl_list; y; y = y->g_next)
2713 if ((ob = pd_checkobject(&y->g_pd)) && zgetfn(&y->g_pd, dspsym))
2714 ugen_add(dc, ob);
2715
2716 /* ... and all dsp interconnections */
2717 linetraverser_start(&t, x);
2718 while (oc = linetraverser_next(&t))
2719 if (obj_issignaloutlet(t.tr_ob, t.tr_outno))
2720 ugen_connect(dc, t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
2721
2722 /* finally, sort them and add them to the DSP chain */
2723 ugen_done_graph(dc);
2724}
2725
2726 /* this routine starts DSP for all root canvases. */
2727static void canvas_start_dsp(void)
2728{
2729 t_canvas *x;
2730 if (canvas_dspstate) ugen_stop();
2731 else sys_gui("pdtk_pd_dsp ON\n");
2732 ugen_start();
2733
2734 for (x = canvas_list; x; x = x->gl_next)
2735 canvas_dodsp(x, 1, 0);
2736
2737 canvas_dspstate = 1;
2738}
2739
2740static void canvas_stop_dsp(void)
2741{
2742 if (canvas_dspstate)
2743 {
2744 ugen_stop();
2745 sys_gui("pdtk_pd_dsp OFF\n");
2746 canvas_dspstate = 0;
2747 }
2748}
2749
2750 /* DSP can be suspended before, and resumed after, operations which
2751 might affect the DSP chain. For example, we suspend before loading and
2752 resume afterward, so that DSP doesn't get resorted for every DSP object
2753 int the patch. */
2754
2755int canvas_suspend_dsp(void)
2756{
2757 int rval = canvas_dspstate;
2758 if (rval) canvas_stop_dsp();
2759 return (rval);
2760}
2761
2762void canvas_resume_dsp(int oldstate)
2763{
2764 if (oldstate) canvas_start_dsp();
2765}
2766
2767 /* this is equivalent to suspending and resuming in one step. */
2768void canvas_update_dsp(void)
2769{
2770 if (canvas_dspstate) canvas_start_dsp();
2771}
2772
2773void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv)
2774{
2775 int newstate;
2776 if (argc)
2777 {
2778 newstate = atom_getintarg(0, argc, argv);
2779 if (newstate && !canvas_dspstate)
2780 {
2781 sys_set_audio_state(1);
2782 canvas_start_dsp();
2783 }
2784 else if (!newstate && canvas_dspstate)
2785 {
2786 canvas_stop_dsp();
2787 sys_set_audio_state(0);
2788 }
2789 }
2790 else post("dsp state %d", canvas_dspstate);
2791}
2792
2793 /* LATER replace this with a queueing scheme */
2794void glist_redrawitem(t_glist *owner, t_gobj *gobj)
2795{
2796 if (glist_isvisible(owner))
2797 {
2798 gobj_vis(gobj, owner, 0);
2799 gobj_vis(gobj, owner, 1);
2800 }
2801}
2802
2803 /* redraw all "scalars" (do this if a drawing command is changed.)
2804 LATER we'll use the "template" information to select which ones we
2805 redraw. */
2806static void glist_redrawall(t_glist *gl)
2807{
2808 t_gobj *g;
2809 int vis = glist_isvisible(gl);
2810 for (g = gl->gl_list; g; g = g->g_next)
2811 {
2812 t_class *cl;
2813 if (vis && g->g_pd == scalar_class)
2814 glist_redrawitem(gl, g);
2815 else if (g->g_pd == canvas_class)
2816 glist_redrawall((t_glist *)g);
2817 }
2818}
2819
2820 /* public interface for above */
2821void canvas_redrawallfortemplate(t_canvas *templatecanvas)
2822{
2823 t_canvas *x;
2824 /* find all root canvases */
2825 for (x = canvas_list; x; x = x->gl_next)
2826 glist_redrawall(x);
2827}
2828
2829/* ------------------------------- setup routine ------------------------ */
2830
2831 /* why are some of these "glist" and others "canvas"? */
2832extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv);
2833extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2834extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2835extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2836extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2837extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2838extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2839 /* old version... */
2840extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2841extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2842 /* new version: */
2843extern void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2844extern void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2845extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2846extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2847extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2848extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2849extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2850extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
2851extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv);
2852
2853void g_graph_setup(void);
2854void g_editor_setup(void);
2855void g_readwrite_setup(void);
2856extern void graph_properties(t_gobj *z, t_glist *owner);
2857
2858void g_canvas_setup(void)
2859{
2860 /* we prevent the user from typing "canvas" in an object box
2861 by sending 0 for a creator function. */
2862 canvas_class = class_new(gensym("canvas"), 0,
2863 (t_method)canvas_free, sizeof(t_canvas), CLASS_NOINLET, 0);
2864 /* here is the real creator function, invoked in patch files
2865 by sending the "canvas" message to #N, which is bound
2866 to pd_camvasmaker. */
2867 class_addmethod(pd_canvasmaker, (t_method)canvas_new, gensym("canvas"),
2868 A_GIMME, 0);
2869 class_addmethod(canvas_class, (t_method)canvas_restore,
2870 gensym("restore"), A_GIMME, 0);
2871 class_addmethod(canvas_class, (t_method)canvas_coords,
2872 gensym("coords"), A_GIMME, 0);
2873
2874/* -------------------------- objects ----------------------------- */
2875 class_addmethod(canvas_class, (t_method)canvas_obj,
2876 gensym("obj"), A_GIMME, A_NULL);
2877 class_addmethod(canvas_class, (t_method)canvas_msg,
2878 gensym("msg"), A_GIMME, A_NULL);
2879 class_addmethod(canvas_class, (t_method)canvas_floatatom,
2880 gensym("floatatom"), A_GIMME, A_NULL);
2881 class_addmethod(canvas_class, (t_method)canvas_symbolatom,
2882 gensym("symbolatom"), A_GIMME, A_NULL);
2883 class_addmethod(canvas_class, (t_method)glist_text,
2884 gensym("text"), A_GIMME, A_NULL);
2885 class_addmethod(canvas_class, (t_method)glist_glist, gensym("graph"),
2886 A_GIMME, A_NULL);
2887 class_addmethod(canvas_class, (t_method)glist_scalar,
2888 gensym("scalar"), A_GIMME, A_NULL);
2889
2890 /* -------------- Thomas Musil's GUI objects ------------ */
2891 class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"),
2892 A_GIMME, A_NULL);
2893 class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"),
2894 A_GIMME, A_NULL);
2895 class_addmethod(canvas_class, (t_method)canvas_vslider, gensym("vslider"),
2896 A_GIMME, A_NULL);
2897 class_addmethod(canvas_class, (t_method)canvas_hslider, gensym("hslider"),
2898 A_GIMME, A_NULL);
2899 class_addmethod(canvas_class, (t_method)canvas_hdial, gensym("hdial"),
2900 A_GIMME, A_NULL);
2901 class_addmethod(canvas_class, (t_method)canvas_vdial, gensym("vdial"),
2902 A_GIMME, A_NULL);
2903 class_addmethod(canvas_class, (t_method)canvas_hradio, gensym("hradio"),
2904 A_GIMME, A_NULL);
2905 class_addmethod(canvas_class, (t_method)canvas_vradio, gensym("vradio"),
2906 A_GIMME, A_NULL);
2907 class_addmethod(canvas_class, (t_method)canvas_vumeter, gensym("vumeter"),
2908 A_GIMME, A_NULL);
2909 class_addmethod(canvas_class, (t_method)canvas_mycnv, gensym("mycnv"),
2910 A_GIMME, A_NULL);
2911 class_addmethod(canvas_class, (t_method)canvas_numbox, gensym("numbox"),
2912 A_GIMME, A_NULL);
2913
2914/* ------------------------ gui stuff --------------------------- */
2915 class_addmethod(canvas_class, (t_method)canvas_pop, gensym("pop"),
2916 A_DEFFLOAT, A_NULL);
2917 class_addmethod(canvas_class, (t_method)canvas_loadbang,
2918 gensym("loadbang"), A_NULL);
2919 class_addmethod(canvas_class, (t_method)canvas_relocate,
2920 gensym("relocate"), A_SYMBOL, A_SYMBOL, A_NULL);
2921 class_addmethod(canvas_class, (t_method)canvas_vis,
2922 gensym("vis"), A_FLOAT, A_NULL);
2923 class_addmethod(canvas_class, (t_method)glist_menu_open,
2924 gensym("menu-open"), A_NULL);
2925 class_addmethod(canvas_class, (t_method)canvas_map,
2926 gensym("map"), A_FLOAT, A_NULL);
2927 class_setpropertiesfn(canvas_class, graph_properties);
2928
2929/* ---------------------- list handling ------------------------ */
2930 class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"),
2931 A_NULL);
2932
2933/* ----- subcanvases, which you get by typing "pd" in a box ---- */
2934 class_addcreator((t_newmethod)subcanvas_new, gensym("pd"), A_DEFSYMBOL, 0);
2935 class_addcreator((t_newmethod)subcanvas_new, gensym("page"), A_DEFSYMBOL, 0);
2936
2937 class_addmethod(canvas_class, (t_method)canvas_click,
2938 gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
2939 class_addmethod(canvas_class, (t_method)canvas_dsp, gensym("dsp"), 0);
2940 class_addmethod(canvas_class, (t_method)canvas_rename_method,
2941 gensym("rename"), A_GIMME, 0);
2942
2943/*---------------------------- tables -- GG ------------------- */
2944
2945 class_addcreator((t_newmethod)table_new, gensym("table"),
2946 A_DEFSYM, A_DEFFLOAT, 0);
2947
2948/* -------------- setups from other files for canvas_class ---------------- */
2949 g_graph_setup();
2950 g_editor_setup();
2951 g_readwrite_setup();
2952}
diff --git a/apps/plugins/pdbox/PDa/src/g_canvas.h b/apps/plugins/pdbox/PDa/src/g_canvas.h
new file mode 100644
index 0000000000..54ab985feb
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_canvas.h
@@ -0,0 +1,1204 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* this file defines the structure for "glists" and related structures and
6functions. "Glists" and "canvases" and "graphs" used to be different
7structures until being unified in version 0.35.
8
9A glist occupies its own window if the "gl_havewindow" flag is set. Its
10appearance on its "parent" or "owner" (if it has one) is as a graph if
11"gl_isgraph" is set, and otherwise as a text box.
12
13A glist is "root" if it has no owner, i.e., a document window. In this
14case "gl_havewindow" is always set.
15
16We maintain a list of root windows, so that we can traverse the whole
17collection of everything in a Pd process.
18
19If a glist has a window it may still not be "mapped." Miniaturized
20windows aren't mapped, for example, but a window is also not mapped
21immediately upon creation. In either case gl_havewindow is true but
22gl_mapped is false.
23
24Closing a non-root window makes it invisible; closing a root destroys it.
25
26A glist that's just a text object on its parent is always "toplevel." An
27embedded glist can switch back and forth to appear as a toplevel by double-
28clicking on it. Single-clicking a text box makes the toplevel become visible
29and raises the window it's in.
30
31If a glist shows up as a graph on its parent, the graph is blanked while the
32glist has its own window, even if miniaturized.
33
34*/
35
36/* NOTE: this file describes Pd implementation details which may change
37in future releases. The public (stable) API is in m_pd.h. */
38
39#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
40extern "C" {
41#endif
42
43/* --------------------- geometry ---------------------------- */
44#define IOWIDTH 7 /* width of an inlet/outlet in pixels */
45#define IOMIDDLE ((IOWIDTH-1)/2)
46#define GLIST_DEFGRAPHWIDTH 200
47#define GLIST_DEFGRAPHHEIGHT 140
48/* ----------------------- data ------------------------------- */
49
50typedef struct _updateheader
51{
52 struct _updateheader *upd_next;
53 unsigned int upd_array:1; /* true if array, false if glist */
54 unsigned int upd_queued:1; /* true if we're queued */
55} t_updateheader;
56
57 /* types to support glists grabbing mouse motion or keys from parent */
58typedef void (*t_glistmotionfn)(void *z, t_floatarg dx, t_floatarg dy);
59typedef void (*t_glistkeyfn)(void *z, t_floatarg key);
60
61EXTERN_STRUCT _rtext;
62#define t_rtext struct _rtext
63
64EXTERN_STRUCT _gtemplate;
65#define t_gtemplate struct _gtemplate
66
67EXTERN_STRUCT _guiconnect;
68#define t_guiconnect struct _guiconnect
69
70EXTERN_STRUCT _tscalar;
71#define t_tscalar struct _tscalar
72
73EXTERN_STRUCT _canvasenvironment;
74#define t_canvasenvironment struct _canvasenvironment
75
76typedef struct _selection
77{
78 t_gobj *sel_what;
79 struct _selection *sel_next;
80} t_selection;
81
82 /* this structure is instantiated whenever a glist becomes visible. */
83typedef struct _editor
84{
85 t_updateheader e_upd; /* update header structure */
86 t_selection *e_updlist; /* list of objects to update */
87 t_rtext *e_rtext; /* text responder linked list */
88 t_selection *e_selection; /* head of the selection list */
89 t_rtext *e_textedfor; /* the rtext if any that we are editing */
90 t_gobj *e_grab; /* object being "dragged" */
91 t_glistmotionfn e_motionfn; /* ... motion callback */
92 t_glistkeyfn e_keyfn; /* ... keypress callback */
93 t_binbuf *e_connectbuf; /* connections to deleted objects */
94 t_binbuf *e_deleted; /* last stuff we deleted */
95 t_guiconnect *e_guiconnect; /* GUI connection for filtering messages */
96 struct _glist *e_glist; /* glist which owns this */
97 int e_xwas; /* xpos on last mousedown or motion event */
98 int e_ywas; /* ypos, similarly */
99 int e_selectline_index1; /* indices for the selected line if any */
100 int e_selectline_outno; /* (only valid if e_selectedline is set) */
101 int e_selectline_index2;
102 int e_selectline_inno;
103 t_outconnect *e_selectline_tag;
104 unsigned int e_onmotion: 3; /* action to take on motion */
105 unsigned int e_lastmoved: 1; /* one if mouse has moved since click */
106 unsigned int e_textdirty: 1; /* one if e_textedfor has changed */
107 unsigned int e_selectedline: 1; /* one if a line is selected */
108} t_editor;
109
110#define MA_NONE 0 /* e_onmotion: do nothing on mouse motion */
111#define MA_MOVE 1 /* drag the selection around */
112#define MA_CONNECT 2 /* make a connection */
113#define MA_REGION 3 /* selection region */
114#define MA_PASSOUT 4 /* send on to e_grab */
115#define MA_DRAGTEXT 5 /* drag in text editor to alter selection */
116
117/* editor structure for "garrays". We don't bother to delete and regenerate
118this structure when the "garray" becomes invisible or visible, although we
119could do so if the structure gets big (like the "editor" above.) */
120
121typedef struct _arrayvis
122{
123 t_updateheader av_upd; /* update header structure */
124 t_garray *av_garray; /* owning structure */
125} t_arrayvis;
126
127/* the t_tick structure describes where to draw x and y "ticks" for a glist */
128
129typedef struct _tick /* where to put ticks on x or y axes */
130{
131 float k_point; /* one point to draw a big tick at */
132 float k_inc; /* x or y increment per little tick */
133 int k_lperb; /* little ticks per big; 0 if no ticks to draw */
134} t_tick;
135
136/* the t_glist structure, which describes a list of elements that live on an
137area of a window.
138
139*/
140
141struct _glist
142{
143 t_object gl_obj; /* header in case we're a glist */
144 t_gobj *gl_list; /* the actual data */
145 struct _gstub *gl_stub; /* safe pointer handler */
146 int gl_valid; /* incremented when pointers might be stale */
147 struct _glist *gl_owner; /* parent glist, supercanvas, or 0 if none */
148 int gl_pixwidth; /* width in pixels (on parent, if a graph) */
149 int gl_pixheight;
150 float gl_x1; /* bounding rectangle in our own coordinates */
151 float gl_y1;
152 float gl_x2;
153 float gl_y2;
154 int gl_screenx1; /* screen coordinates when toplevel */
155 int gl_screeny1;
156 int gl_screenx2;
157 int gl_screeny2;
158 t_tick gl_xtick; /* ticks marking X values */
159 int gl_nxlabels; /* number of X coordinate labels */
160 t_symbol **gl_xlabel; /* ... an array to hold them */
161 float gl_xlabely; /* ... and their Y coordinates */
162 t_tick gl_ytick; /* same as above for Y ticks and labels */
163 int gl_nylabels;
164 t_symbol **gl_ylabel;
165 float gl_ylabelx;
166 t_editor *gl_editor; /* editor structure when visible */
167 t_symbol *gl_name; /* symbol bound here */
168 int gl_font; /* nominal font size in points, e.g., 10 */
169 struct _glist *gl_next; /* link in list of toplevels */
170 t_canvasenvironment *gl_env; /* root canvases and abstractions only */
171 unsigned int gl_havewindow:1; /* true if we own a window */
172 unsigned int gl_mapped:1; /* true if, moreover, it's "mapped" */
173 unsigned int gl_dirty:1; /* (root canvas only:) patch has changed */
174 unsigned int gl_loading:1; /* am now loading from file */
175 unsigned int gl_willvis:1; /* make me visible after loading */
176 unsigned int gl_edit:1; /* edit mode */
177 unsigned int gl_isdeleting:1; /* we're inside glist_delete -- hack! */
178 unsigned int gl_stretch:1; /* stretch contents on resize */
179 unsigned int gl_isgraph:1; /* show as graph on parent */
180};
181
182#define gl_gobj gl_obj.te_g
183#define gl_pd gl_gobj.g_pd
184
185/* a data structure to describe a field in a pure datum */
186
187#define DT_FLOAT 0
188#define DT_SYMBOL 1
189#define DT_LIST 2
190#define DT_ARRAY 3
191
192typedef struct _dataslot
193{
194 int ds_type;
195 t_symbol *ds_name;
196 t_symbol *ds_arraytemplate; /* filled in for arrays only */
197} t_dataslot;
198
199
200/* T.Grill - changed t_pd member to t_pdobj to avoid name clashed */
201typedef struct _template
202{
203 t_pd t_pdobj; /* header */
204 struct _gtemplate *t_list; /* list of "struct"/gtemplate objects */
205 t_symbol *t_sym; /* name */
206 int t_n; /* number of dataslots (fields) */
207 t_dataslot *t_vec; /* array of dataslots */
208} t_template;
209
210struct _array
211{
212 int a_n; /* number of elements */
213 int a_elemsize; /* size in bytes; LATER get this from template */
214 char *a_vec; /* array of elements */
215 t_symbol *a_templatesym; /* template for elements */
216 int a_valid; /* protection against stale pointers into array */
217 t_gpointer a_gp; /* pointer to scalar or array element we're in */
218 t_gstub *a_stub;
219};
220
221 /* structure for traversing all the connections in a glist */
222typedef struct _linetraverser
223{
224 t_canvas *tr_x;
225 t_object *tr_ob;
226 int tr_nout;
227 int tr_outno;
228 t_object *tr_ob2;
229 t_outlet *tr_outlet;
230 t_inlet *tr_inlet;
231 int tr_nin;
232 int tr_inno;
233 int tr_x11, tr_y11, tr_x12, tr_y12;
234 int tr_x21, tr_y21, tr_x22, tr_y22;
235 int tr_lx1, tr_ly1, tr_lx2, tr_ly2;
236 t_outconnect *tr_nextoc;
237 int tr_nextoutno;
238} t_linetraverser;
239
240/* function types used to define graphical behavior for gobjs, a bit like X
241widgets. We don't use Pd methods because Pd's typechecking can't specify the
242types of pointer arguments. Also it's more convenient this way, since
243every "patchable" object can just get the "text" behaviors. */
244
245 /* Call this to get a gobj's bounding rectangle in pixels */
246typedef void (*t_getrectfn)(t_gobj *x, struct _glist *glist,
247 int *x1, int *y1, int *x2, int *y2);
248 /* and this to displace a gobj: */
249typedef void (*t_displacefn)(t_gobj *x, struct _glist *glist, int dx, int dy);
250 /* change color to show selection: */
251typedef void (*t_selectfn)(t_gobj *x, struct _glist *glist, int state);
252 /* change appearance to show activation/deactivation: */
253typedef void (*t_activatefn)(t_gobj *x, struct _glist *glist, int state);
254 /* warn a gobj it's about to be deleted */
255typedef void (*t_deletefn)(t_gobj *x, struct _glist *glist);
256 /* making visible or invisible */
257typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag);
258 /* field a mouse click (when not in "edit" mode) */
259typedef int (*t_clickfn)(t_gobj *x, struct _glist *glist,
260 int xpix, int ypix, int shift, int alt, int dbl, int doit);
261 /* ... and later, resizing; getting/setting font or color... */
262
263struct _widgetbehavior
264{
265 t_getrectfn w_getrectfn;
266 t_displacefn w_displacefn;
267 t_selectfn w_selectfn;
268 t_activatefn w_activatefn;
269 t_deletefn w_deletefn;
270 t_visfn w_visfn;
271 t_clickfn w_clickfn;
272};
273
274/* -------- behaviors for scalars defined by objects in template --------- */
275/* these are set by "drawing commands" in g_template.c which add appearance to
276scalars, which live in some other window. If the scalar is just included
277in a canvas the "parent" is a misnomer. There is also a text scalar object
278which really does draw the scalar on the parent window; see g_scalar.c. */
279
280/* note how the click function wants the whole scalar, not the "data", so
281doesn't work on array elements... LATER reconsider this */
282
283 /* bounding rectangle: */
284typedef void (*t_parentgetrectfn)(t_gobj *x, struct _glist *glist,
285 t_word *data, t_template *tmpl, float basex, float basey,
286 int *x1, int *y1, int *x2, int *y2);
287 /* displace it */
288typedef void (*t_parentdisplacefn)(t_gobj *x, struct _glist *glist,
289 t_word *data, t_template *tmpl, float basex, float basey,
290 int dx, int dy);
291 /* change color to show selection */
292typedef void (*t_parentselectfn)(t_gobj *x, struct _glist *glist,
293 t_word *data, t_template *tmpl, float basex, float basey,
294 int state);
295 /* change appearance to show activation/deactivation: */
296typedef void (*t_parentactivatefn)(t_gobj *x, struct _glist *glist,
297 t_word *data, t_template *tmpl, float basex, float basey,
298 int state);
299 /* making visible or invisible */
300typedef void (*t_parentvisfn)(t_gobj *x, struct _glist *glist,
301 t_word *data, t_template *tmpl, float basex, float basey,
302 int flag);
303 /* field a mouse click */
304typedef int (*t_parentclickfn)(t_gobj *x, struct _glist *glist,
305 t_scalar *sc, t_template *tmpl, float basex, float basey,
306 int xpix, int ypix, int shift, int alt, int dbl, int doit);
307
308struct _parentwidgetbehavior
309{
310 t_parentgetrectfn w_parentgetrectfn;
311 t_parentdisplacefn w_parentdisplacefn;
312 t_parentselectfn w_parentselectfn;
313 t_parentactivatefn w_parentactivatefn;
314 t_parentvisfn w_parentvisfn;
315 t_parentclickfn w_parentclickfn;
316};
317
318 /* cursor definitions; used as return value for t_parentclickfn */
319#define CURSOR_RUNMODE_NOTHING 0
320#define CURSOR_RUNMODE_CLICKME 1
321#define CURSOR_RUNMODE_THICKEN 2
322#define CURSOR_RUNMODE_ADDPOINT 3
323#define CURSOR_EDITMODE_NOTHING 4
324#define CURSOR_EDITMODE_CONNECT 5
325#define CURSOR_EDITMODE_DISCONNECT 6
326EXTERN void canvas_setcursor(t_glist *x, unsigned int cursornum);
327
328extern t_canvas *canvas_editing; /* last canvas to start text edting */
329extern t_canvas *canvas_whichfind; /* last canvas we did a find in */
330extern t_canvas *canvas_list; /* list of all root canvases */
331extern t_class *vinlet_class, *voutlet_class;
332extern int glist_valid; /* incremented when pointers might be stale */
333
334/* ------------------- functions on any gobj ----------------------------- */
335EXTERN void gobj_getrect(t_gobj *x, t_glist *owner, int *x1, int *y1,
336 int *x2, int *y2);
337EXTERN void gobj_displace(t_gobj *x, t_glist *owner, int dx, int dy);
338EXTERN void gobj_select(t_gobj *x, t_glist *owner, int state);
339EXTERN void gobj_activate(t_gobj *x, t_glist *owner, int state);
340EXTERN void gobj_delete(t_gobj *x, t_glist *owner);
341EXTERN void gobj_vis(t_gobj *x, t_glist *glist, int flag);
342EXTERN int gobj_click(t_gobj *x, struct _glist *glist,
343 int xpix, int ypix, int shift, int alt, int dbl, int doit);
344EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
345EXTERN void gobj_properties(t_gobj *x, struct _glist *glist);
346EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
347
348/* -------------------- functions on glists --------------------- */
349EXTERN t_glist *glist_new( void);
350EXTERN void glist_init(t_glist *x);
351EXTERN void glist_add(t_glist *x, t_gobj *g);
352EXTERN void glist_cleanup(t_glist *x);
353EXTERN void glist_free(t_glist *x);
354
355EXTERN void glist_clear(t_glist *x);
356EXTERN t_canvas *glist_getcanvas(t_glist *x);
357EXTERN int glist_isselected(t_glist *x, t_gobj *y);
358EXTERN void glist_select(t_glist *x, t_gobj *y);
359EXTERN void glist_deselect(t_glist *x, t_gobj *y);
360EXTERN void glist_noselect(t_glist *x);
361EXTERN void glist_selectall(t_glist *x);
362EXTERN void glist_delete(t_glist *x, t_gobj *y);
363EXTERN void glist_retext(t_glist *x, t_text *y);
364EXTERN void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
365 t_glistkeyfn keyfn, int xpos, int ypos);
366EXTERN int glist_isvisible(t_glist *x);
367EXTERN int glist_istoplevel(t_glist *x);
368EXTERN t_glist *glist_findgraph(t_glist *x);
369EXTERN int glist_getfont(t_glist *x);
370EXTERN void glist_sort(t_glist *canvas);
371EXTERN void glist_read(t_glist *x, t_symbol *filename, t_symbol *format);
372EXTERN void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format);
373
374EXTERN float glist_pixelstox(t_glist *x, float xpix);
375EXTERN float glist_pixelstoy(t_glist *x, float ypix);
376EXTERN float glist_xtopixels(t_glist *x, float xval);
377EXTERN float glist_ytopixels(t_glist *x, float yval);
378EXTERN float glist_dpixtodx(t_glist *x, float dxpix);
379EXTERN float glist_dpixtody(t_glist *x, float dypix);
380
381EXTERN void glist_redrawitem(t_glist *owner, t_gobj *gobj);
382EXTERN void glist_getnextxy(t_glist *gl, int *xval, int *yval);
383EXTERN void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv);
384EXTERN t_glist *glist_addglist(t_glist *g, t_symbol *sym,
385 float x1, float y1, float x2, float y2,
386 float px1, float py1, float px2, float py2);
387EXTERN void glist_arraydialog(t_glist *parent, t_symbol *name,
388 t_floatarg size, t_floatarg saveit, t_floatarg newgraph);
389EXTERN t_binbuf *glist_writetobinbuf(t_glist *x, int wholething);
390EXTERN int glist_isgraph(t_glist *x);
391EXTERN void glist_redraw(t_glist *x);
392EXTERN void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
393 char *tag, int x1, int y1, int x2, int y2);
394EXTERN void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag);
395EXTERN void canvas_create_editor(t_glist *x, int createit);
396void canvas_deletelinesforio(t_canvas *x, t_text *text,
397 t_inlet *inp, t_outlet *outp);
398
399
400/* -------------------- functions on texts ------------------------- */
401EXTERN void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize);
402EXTERN void text_drawborder(t_text *x, t_glist *glist, char *tag,
403 int width, int height, int firsttime);
404EXTERN void text_eraseborder(t_text *x, t_glist *glist, char *tag);
405EXTERN int text_xcoord(t_text *x, t_glist *glist);
406EXTERN int text_ycoord(t_text *x, t_glist *glist);
407EXTERN int text_xpix(t_text *x, t_glist *glist);
408EXTERN int text_ypix(t_text *x, t_glist *glist);
409EXTERN int text_shouldvis(t_text *x, t_glist *glist);
410
411/* -------------------- functions on rtexts ------------------------- */
412#define RTEXT_DOWN 1
413#define RTEXT_DRAG 2
414#define RTEXT_DBL 3
415#define RTEXT_SHIFT 4
416
417EXTERN t_rtext *rtext_new(t_glist *glist, t_text *who);
418EXTERN t_rtext *glist_findrtext(t_glist *gl, t_text *who);
419EXTERN void rtext_draw(t_rtext *x);
420EXTERN void rtext_erase(t_rtext *x);
421EXTERN t_rtext *rtext_remove(t_rtext *first, t_rtext *x);
422EXTERN int rtext_height(t_rtext *x);
423EXTERN void rtext_displace(t_rtext *x, int dx, int dy);
424EXTERN void rtext_select(t_rtext *x, int state);
425EXTERN void rtext_activate(t_rtext *x, int state);
426EXTERN void rtext_free(t_rtext *x);
427EXTERN void rtext_key(t_rtext *x, int n, t_symbol *s);
428EXTERN void rtext_mouse(t_rtext *x, int xval, int yval, int flag);
429EXTERN void rtext_retext(t_rtext *x);
430EXTERN int rtext_width(t_rtext *x);
431EXTERN int rtext_height(t_rtext *x);
432EXTERN char *rtext_gettag(t_rtext *x);
433EXTERN void rtext_gettext(t_rtext *x, char **buf, int *bufsize);
434
435/* -------------------- functions on canvases ------------------------ */
436EXTERN t_class *canvas_class;
437
438EXTERN t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv);
439EXTERN t_symbol *canvas_makebindsym(t_symbol *s);
440EXTERN void canvas_vistext(t_canvas *x, t_text *y);
441EXTERN void canvas_fixlinesfor(t_canvas *x, t_text *text);
442EXTERN void canvas_deletelinesfor(t_canvas *x, t_text *text);
443EXTERN void canvas_stowconnections(t_canvas *x);
444EXTERN void canvas_restoreconnections(t_canvas *x);
445EXTERN void canvas_redraw(t_canvas *x);
446
447EXTERN t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *sym);
448EXTERN void canvas_rminlet(t_canvas *x, t_inlet *ip);
449EXTERN t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *sym);
450EXTERN void canvas_rmoutlet(t_canvas *x, t_outlet *op);
451EXTERN void canvas_redrawallfortemplate(t_canvas *tmpl);
452EXTERN void canvas_zapallfortemplate(t_canvas *tmpl);
453EXTERN void canvas_setusedastemplate(t_canvas *x);
454EXTERN t_canvas *canvas_getcurrent(void);
455EXTERN void canvas_setcurrent(t_canvas *x);
456EXTERN void canvas_unsetcurrent(t_canvas *x);
457EXTERN t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s);
458EXTERN t_canvas *canvas_getrootfor(t_canvas *x);
459EXTERN void canvas_dirty(t_canvas *x, t_int n);
460EXTERN int canvas_getfont(t_canvas *x);
461typedef int (*t_canvasapply)(t_canvas *x, t_int x1, t_int x2, t_int x3);
462
463EXTERN t_int *canvas_recurapply(t_canvas *x, t_canvasapply *fn,
464 t_int x1, t_int x2, t_int x3);
465
466EXTERN void canvas_resortinlets(t_canvas *x);
467EXTERN void canvas_resortoutlets(t_canvas *x);
468EXTERN void canvas_free(t_canvas *x);
469EXTERN void canvas_updatewindowlist( void);
470EXTERN void canvas_editmode(t_canvas *x, t_floatarg yesplease);
471EXTERN int canvas_isabstraction(t_canvas *x);
472EXTERN int canvas_istable(t_canvas *x);
473EXTERN int canvas_showtext(t_canvas *x);
474EXTERN void canvas_vis(t_canvas *x, t_floatarg f);
475EXTERN t_canvasenvironment *canvas_getenv(t_canvas *x);
476EXTERN void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir);
477EXTERN void canvas_loadbang(t_canvas *x);
478EXTERN int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos,
479 int *x1p, int *y1p, int *x2p, int *y2p);
480EXTERN int canvas_setdeleting(t_canvas *x, int flag);
481
482typedef void (*t_undofn)(t_canvas *canvas, void *buf,
483 int action); /* a function that does UNDO/REDO */
484#define UNDO_FREE 0 /* free current undo/redo buffer */
485#define UNDO_UNDO 1 /* undo */
486#define UNDO_REDO 2 /* redo */
487EXTERN void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
488 const char *name);
489EXTERN void canvas_noundo(t_canvas *x);
490EXTERN int canvas_getindex(t_canvas *x, t_gobj *y);
491
492/* T.Grill - made public for dynamic object creation */
493/* in g_editor.c */
494EXTERN void canvas_connect(t_canvas *x,
495 t_floatarg fwhoout, t_floatarg foutno,t_floatarg fwhoin, t_floatarg finno);
496EXTERN void canvas_disconnect(t_canvas *x,
497 float index1, float outno, float index2, float inno);
498EXTERN int canvas_isconnected (t_canvas *x,
499 t_text *ob1, int n1, t_text *ob2, int n2);
500EXTERN void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy);
501
502
503/* ---- functions on canvasses as objects --------------------- */
504
505EXTERN void canvas_fattenforscalars(t_canvas *x,
506 int *x1, int *y1, int *x2, int *y2);
507EXTERN void canvas_visforscalars(t_canvas *x, t_glist *glist, int vis);
508EXTERN int canvas_clicksub(t_canvas *x, int xpix, int ypix, int shift,
509 int alt, int dbl, int doit);
510EXTERN t_glist *canvas_getglistonsuper(void);
511
512EXTERN void linetraverser_start(t_linetraverser *t, t_canvas *x);
513EXTERN t_outconnect *linetraverser_next(t_linetraverser *t);
514EXTERN void linetraverser_skipobject(t_linetraverser *t);
515
516/* --------------------- functions on tscalars --------------------- */
517
518EXTERN void tscalar_getrect(t_tscalar *x, t_glist *owner,
519 int *xp1, int *yp1, int *xp2, int *yp2);
520EXTERN void tscalar_vis(t_tscalar *x, t_glist *owner, int flag);
521EXTERN int tscalar_click(t_tscalar *x, int xpix, int ypix, int shift,
522 int alt, int dbl, int doit);
523
524/* --------- functions on garrays (graphical arrays) -------------------- */
525
526EXTERN t_template *garray_template(t_garray *x);
527
528/* -------------------- arrays --------------------- */
529EXTERN t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *tmpl,
530 t_floatarg f, t_floatarg saveit);
531EXTERN t_array *array_new(t_symbol *templatesym, t_gpointer *parent);
532EXTERN void array_resize(t_array *x, t_template *tmpl, int n);
533EXTERN void array_free(t_array *x);
534
535/* --------------------- gpointers and stubs ---------------- */
536EXTERN t_gstub *gstub_new(t_glist *gl, t_array *a);
537EXTERN void gstub_cutoff(t_gstub *gs);
538EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x);
539
540/* --------------------- scalars ------------------------- */
541EXTERN void word_init(t_word *wp, t_template *tmpl, t_gpointer *gp);
542EXTERN void word_restore(t_word *wp, t_template *tmpl,
543 int argc, t_atom *argv);
544EXTERN t_scalar *scalar_new(t_glist *owner,
545 t_symbol *templatesym);
546EXTERN void scalar_getbasexy(t_scalar *x, float *basex, float *basey);
547
548/* ------helper routines for "garrays" and "plots" -------------- */
549EXTERN int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
550 t_symbol *elemtemplatesym,
551 float linewidth, float xloc, float xinc, float yloc,
552 int xpix, int ypix, int shift, int alt, int dbl, int doit);
553
554EXTERN void array_getcoordinate(t_glist *glist,
555 char *elem, int xonset, int yonset, int wonset, int indx,
556 float basex, float basey, float xinc,
557 float *xp, float *yp, float *wp);
558
559EXTERN int array_getfields(t_symbol *elemtemplatesym,
560 t_canvas **elemtemplatecanvasp,
561 t_template **elemtemplatep, int *elemsizep,
562 int *xonsetp, int *yonsetp, int *wonsetp);
563
564/* --------------------- templates ------------------------- */
565EXTERN t_template *template_new(t_symbol *sym, int argc, t_atom *argv);
566EXTERN void template_free(t_template *x);
567EXTERN int template_match(t_template *x1, t_template *x2);
568EXTERN int template_find_field(t_template *x, t_symbol *name, int *p_onset,
569 int *p_type, t_symbol **p_arraytype);
570EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
571 int loud);
572EXTERN void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
573 t_float f, int loud);
574EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
575 t_word *wp, int loud);
576EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
577 t_word *wp, t_symbol *s, int loud);
578
579EXTERN t_template *gtemplate_get(t_gtemplate *x);
580EXTERN t_template *template_findbyname(t_symbol *s);
581EXTERN t_canvas *template_findcanvas(t_template *tmpl);
582
583EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname,
584 t_word *wp, int loud);
585EXTERN void template_setfloat(t_template *x, t_symbol *fieldname,
586 t_word *wp, t_float f, int loud);
587EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
588 t_word *wp, int loud);
589EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
590 t_word *wp, t_symbol *s, int loud);
591
592/* ----------------------- guiconnects, g_guiconnect.c --------- */
593EXTERN t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym);
594EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay);
595
596/* ------------- IEMGUI routines used in other g_ files ---------------- */
597EXTERN t_symbol *iemgui_raute2dollar(t_symbol *s);
598EXTERN t_symbol *iemgui_dollar2raute(t_symbol *s);
599
600#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
601}
602#endif
603/* Copyright (c) 1997-1999 Miller Puckette.
604* For information on usage and redistribution, and for a DISCLAIMER OF ALL
605* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
606
607/* this file defines the structure for "glists" and related structures and
608functions. "Glists" and "canvases" and "graphs" used to be different
609structures until being unified in version 0.35.
610
611A glist occupies its own window if the "gl_havewindow" flag is set. Its
612appearance on its "parent" or "owner" (if it has one) is as a graph if
613"gl_isgraph" is set, and otherwise as a text box.
614
615A glist is "root" if it has no owner, i.e., a document window. In this
616case "gl_havewindow" is always set.
617
618We maintain a list of root windows, so that we can traverse the whole
619collection of everything in a Pd process.
620
621If a glist has a window it may still not be "mapped." Miniaturized
622windows aren't mapped, for example, but a window is also not mapped
623immediately upon creation. In either case gl_havewindow is true but
624gl_mapped is false.
625
626Closing a non-root window makes it invisible; closing a root destroys it.
627
628A glist that's just a text object on its parent is always "toplevel." An
629embedded glist can switch back and forth to appear as a toplevel by double-
630clicking on it. Single-clicking a text box makes the toplevel become visible
631and raises the window it's in.
632
633If a glist shows up as a graph on its parent, the graph is blanked while the
634glist has its own window, even if miniaturized.
635
636*/
637
638/* NOTE: this file describes Pd implementation details which may change
639in future releases. The public (stable) API is in m_pd.h. */
640
641#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
642extern "C" {
643#endif
644
645/* --------------------- geometry ---------------------------- */
646#define IOWIDTH 7 /* width of an inlet/outlet in pixels */
647#define IOMIDDLE ((IOWIDTH-1)/2)
648#define GLIST_DEFGRAPHWIDTH 200
649#define GLIST_DEFGRAPHHEIGHT 140
650/* ----------------------- data ------------------------------- */
651
652typedef struct _updateheader
653{
654 struct _updateheader *upd_next;
655 unsigned int upd_array:1; /* true if array, false if glist */
656 unsigned int upd_queued:1; /* true if we're queued */
657} t_updateheader;
658
659 /* types to support glists grabbing mouse motion or keys from parent */
660typedef void (*t_glistmotionfn)(void *z, t_floatarg dx, t_floatarg dy);
661typedef void (*t_glistkeyfn)(void *z, t_floatarg key);
662
663EXTERN_STRUCT _rtext;
664#define t_rtext struct _rtext
665
666EXTERN_STRUCT _gtemplate;
667#define t_gtemplate struct _gtemplate
668
669EXTERN_STRUCT _guiconnect;
670#define t_guiconnect struct _guiconnect
671
672EXTERN_STRUCT _tscalar;
673#define t_tscalar struct _tscalar
674
675EXTERN_STRUCT _canvasenvironment;
676#define t_canvasenvironment struct _canvasenvironment
677
678typedef struct _selection
679{
680 t_gobj *sel_what;
681 struct _selection *sel_next;
682} t_selection;
683
684 /* this structure is instantiated whenever a glist becomes visible. */
685typedef struct _editor
686{
687 t_updateheader e_upd; /* update header structure */
688 t_selection *e_updlist; /* list of objects to update */
689 t_rtext *e_rtext; /* text responder linked list */
690 t_selection *e_selection; /* head of the selection list */
691 t_rtext *e_textedfor; /* the rtext if any that we are editing */
692 t_gobj *e_grab; /* object being "dragged" */
693 t_glistmotionfn e_motionfn; /* ... motion callback */
694 t_glistkeyfn e_keyfn; /* ... keypress callback */
695 t_binbuf *e_connectbuf; /* connections to deleted objects */
696 t_binbuf *e_deleted; /* last stuff we deleted */
697 t_guiconnect *e_guiconnect; /* GUI connection for filtering messages */
698 struct _glist *e_glist; /* glist which owns this */
699 int e_xwas; /* xpos on last mousedown or motion event */
700 int e_ywas; /* ypos, similarly */
701 int e_selectline_index1; /* indices for the selected line if any */
702 int e_selectline_outno; /* (only valid if e_selectedline is set) */
703 int e_selectline_index2;
704 int e_selectline_inno;
705 t_outconnect *e_selectline_tag;
706 unsigned int e_onmotion: 3; /* action to take on motion */
707 unsigned int e_lastmoved: 1; /* one if mouse has moved since click */
708 unsigned int e_textdirty: 1; /* one if e_textedfor has changed */
709 unsigned int e_selectedline: 1; /* one if a line is selected */
710} t_editor;
711
712#define MA_NONE 0 /* e_onmotion: do nothing on mouse motion */
713#define MA_MOVE 1 /* drag the selection around */
714#define MA_CONNECT 2 /* make a connection */
715#define MA_REGION 3 /* selection region */
716#define MA_PASSOUT 4 /* send on to e_grab */
717#define MA_DRAGTEXT 5 /* drag in text editor to alter selection */
718
719/* editor structure for "garrays". We don't bother to delete and regenerate
720this structure when the "garray" becomes invisible or visible, although we
721could do so if the structure gets big (like the "editor" above.) */
722
723typedef struct _arrayvis
724{
725 t_updateheader av_upd; /* update header structure */
726 t_garray *av_garray; /* owning structure */
727} t_arrayvis;
728
729/* the t_tick structure describes where to draw x and y "ticks" for a glist */
730
731typedef struct _tick /* where to put ticks on x or y axes */
732{
733 float k_point; /* one point to draw a big tick at */
734 float k_inc; /* x or y increment per little tick */
735 int k_lperb; /* little ticks per big; 0 if no ticks to draw */
736} t_tick;
737
738/* the t_glist structure, which describes a list of elements that live on an
739area of a window.
740
741*/
742
743struct _glist
744{
745 t_object gl_obj; /* header in case we're a glist */
746 t_gobj *gl_list; /* the actual data */
747 struct _gstub *gl_stub; /* safe pointer handler */
748 int gl_valid; /* incremented when pointers might be stale */
749 struct _glist *gl_owner; /* parent glist, supercanvas, or 0 if none */
750 int gl_pixwidth; /* width in pixels (on parent, if a graph) */
751 int gl_pixheight;
752 float gl_x1; /* bounding rectangle in our own coordinates */
753 float gl_y1;
754 float gl_x2;
755 float gl_y2;
756 int gl_screenx1; /* screen coordinates when toplevel */
757 int gl_screeny1;
758 int gl_screenx2;
759 int gl_screeny2;
760 t_tick gl_xtick; /* ticks marking X values */
761 int gl_nxlabels; /* number of X coordinate labels */
762 t_symbol **gl_xlabel; /* ... an array to hold them */
763 float gl_xlabely; /* ... and their Y coordinates */
764 t_tick gl_ytick; /* same as above for Y ticks and labels */
765 int gl_nylabels;
766 t_symbol **gl_ylabel;
767 float gl_ylabelx;
768 t_editor *gl_editor; /* editor structure when visible */
769 t_symbol *gl_name; /* symbol bound here */
770 int gl_font; /* nominal font size in points, e.g., 10 */
771 struct _glist *gl_next; /* link in list of toplevels */
772 t_canvasenvironment *gl_env; /* root canvases and abstractions only */
773 unsigned int gl_havewindow:1; /* true if we own a window */
774 unsigned int gl_mapped:1; /* true if, moreover, it's "mapped" */
775 unsigned int gl_dirty:1; /* (root canvas only:) patch has changed */
776 unsigned int gl_loading:1; /* am now loading from file */
777 unsigned int gl_willvis:1; /* make me visible after loading */
778 unsigned int gl_edit:1; /* edit mode */
779 unsigned int gl_isdeleting:1; /* we're inside glist_delete -- hack! */
780 unsigned int gl_stretch:1; /* stretch contents on resize */
781 unsigned int gl_isgraph:1; /* show as graph on parent */
782};
783
784#define gl_gobj gl_obj.te_g
785#define gl_pd gl_gobj.g_pd
786
787/* a data structure to describe a field in a pure datum */
788
789#define DT_FLOAT 0
790#define DT_SYMBOL 1
791#define DT_LIST 2
792#define DT_ARRAY 3
793
794typedef struct _dataslot
795{
796 int ds_type;
797 t_symbol *ds_name;
798 t_symbol *ds_arraytemplate; /* filled in for arrays only */
799} t_dataslot;
800
801
802/* T.Grill - changed t_pd member to t_pdobj to avoid name clashed */
803typedef struct _template
804{
805 t_pd t_pdobj; /* header */
806 struct _gtemplate *t_list; /* list of "struct"/gtemplate objects */
807 t_symbol *t_sym; /* name */
808 int t_n; /* number of dataslots (fields) */
809 t_dataslot *t_vec; /* array of dataslots */
810} t_template;
811
812struct _array
813{
814 int a_n; /* number of elements */
815 int a_elemsize; /* size in bytes; LATER get this from template */
816 char *a_vec; /* array of elements */
817 t_symbol *a_templatesym; /* template for elements */
818 int a_valid; /* protection against stale pointers into array */
819 t_gpointer a_gp; /* pointer to scalar or array element we're in */
820 t_gstub *a_stub;
821};
822
823 /* structure for traversing all the connections in a glist */
824typedef struct _linetraverser
825{
826 t_canvas *tr_x;
827 t_object *tr_ob;
828 int tr_nout;
829 int tr_outno;
830 t_object *tr_ob2;
831 t_outlet *tr_outlet;
832 t_inlet *tr_inlet;
833 int tr_nin;
834 int tr_inno;
835 int tr_x11, tr_y11, tr_x12, tr_y12;
836 int tr_x21, tr_y21, tr_x22, tr_y22;
837 int tr_lx1, tr_ly1, tr_lx2, tr_ly2;
838 t_outconnect *tr_nextoc;
839 int tr_nextoutno;
840} t_linetraverser;
841
842/* function types used to define graphical behavior for gobjs, a bit like X
843widgets. We don't use Pd methods because Pd's typechecking can't specify the
844types of pointer arguments. Also it's more convenient this way, since
845every "patchable" object can just get the "text" behaviors. */
846
847 /* Call this to get a gobj's bounding rectangle in pixels */
848typedef void (*t_getrectfn)(t_gobj *x, struct _glist *glist,
849 int *x1, int *y1, int *x2, int *y2);
850 /* and this to displace a gobj: */
851typedef void (*t_displacefn)(t_gobj *x, struct _glist *glist, int dx, int dy);
852 /* change color to show selection: */
853typedef void (*t_selectfn)(t_gobj *x, struct _glist *glist, int state);
854 /* change appearance to show activation/deactivation: */
855typedef void (*t_activatefn)(t_gobj *x, struct _glist *glist, int state);
856 /* warn a gobj it's about to be deleted */
857typedef void (*t_deletefn)(t_gobj *x, struct _glist *glist);
858 /* making visible or invisible */
859typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag);
860 /* field a mouse click (when not in "edit" mode) */
861typedef int (*t_clickfn)(t_gobj *x, struct _glist *glist,
862 int xpix, int ypix, int shift, int alt, int dbl, int doit);
863 /* ... and later, resizing; getting/setting font or color... */
864
865struct _widgetbehavior
866{
867 t_getrectfn w_getrectfn;
868 t_displacefn w_displacefn;
869 t_selectfn w_selectfn;
870 t_activatefn w_activatefn;
871 t_deletefn w_deletefn;
872 t_visfn w_visfn;
873 t_clickfn w_clickfn;
874};
875
876/* -------- behaviors for scalars defined by objects in template --------- */
877/* these are set by "drawing commands" in g_template.c which add appearance to
878scalars, which live in some other window. If the scalar is just included
879in a canvas the "parent" is a misnomer. There is also a text scalar object
880which really does draw the scalar on the parent window; see g_scalar.c. */
881
882/* note how the click function wants the whole scalar, not the "data", so
883doesn't work on array elements... LATER reconsider this */
884
885 /* bounding rectangle: */
886typedef void (*t_parentgetrectfn)(t_gobj *x, struct _glist *glist,
887 t_word *data, t_template *tmpl, float basex, float basey,
888 int *x1, int *y1, int *x2, int *y2);
889 /* displace it */
890typedef void (*t_parentdisplacefn)(t_gobj *x, struct _glist *glist,
891 t_word *data, t_template *tmpl, float basex, float basey,
892 int dx, int dy);
893 /* change color to show selection */
894typedef void (*t_parentselectfn)(t_gobj *x, struct _glist *glist,
895 t_word *data, t_template *tmpl, float basex, float basey,
896 int state);
897 /* change appearance to show activation/deactivation: */
898typedef void (*t_parentactivatefn)(t_gobj *x, struct _glist *glist,
899 t_word *data, t_template *tmpl, float basex, float basey,
900 int state);
901 /* making visible or invisible */
902typedef void (*t_parentvisfn)(t_gobj *x, struct _glist *glist,
903 t_word *data, t_template *tmpl, float basex, float basey,
904 int flag);
905 /* field a mouse click */
906typedef int (*t_parentclickfn)(t_gobj *x, struct _glist *glist,
907 t_scalar *sc, t_template *tmpl, float basex, float basey,
908 int xpix, int ypix, int shift, int alt, int dbl, int doit);
909
910struct _parentwidgetbehavior
911{
912 t_parentgetrectfn w_parentgetrectfn;
913 t_parentdisplacefn w_parentdisplacefn;
914 t_parentselectfn w_parentselectfn;
915 t_parentactivatefn w_parentactivatefn;
916 t_parentvisfn w_parentvisfn;
917 t_parentclickfn w_parentclickfn;
918};
919
920 /* cursor definitions; used as return value for t_parentclickfn */
921#define CURSOR_RUNMODE_NOTHING 0
922#define CURSOR_RUNMODE_CLICKME 1
923#define CURSOR_RUNMODE_THICKEN 2
924#define CURSOR_RUNMODE_ADDPOINT 3
925#define CURSOR_EDITMODE_NOTHING 4
926#define CURSOR_EDITMODE_CONNECT 5
927#define CURSOR_EDITMODE_DISCONNECT 6
928EXTERN void canvas_setcursor(t_glist *x, unsigned int cursornum);
929
930extern t_canvas *canvas_editing; /* last canvas to start text edting */
931extern t_canvas *canvas_whichfind; /* last canvas we did a find in */
932extern t_canvas *canvas_list; /* list of all root canvases */
933extern t_class *vinlet_class, *voutlet_class;
934extern int glist_valid; /* incremented when pointers might be stale */
935
936/* ------------------- functions on any gobj ----------------------------- */
937EXTERN void gobj_getrect(t_gobj *x, t_glist *owner, int *x1, int *y1,
938 int *x2, int *y2);
939EXTERN void gobj_displace(t_gobj *x, t_glist *owner, int dx, int dy);
940EXTERN void gobj_select(t_gobj *x, t_glist *owner, int state);
941EXTERN void gobj_activate(t_gobj *x, t_glist *owner, int state);
942EXTERN void gobj_delete(t_gobj *x, t_glist *owner);
943EXTERN void gobj_vis(t_gobj *x, t_glist *glist, int flag);
944EXTERN int gobj_click(t_gobj *x, struct _glist *glist,
945 int xpix, int ypix, int shift, int alt, int dbl, int doit);
946EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
947EXTERN void gobj_properties(t_gobj *x, struct _glist *glist);
948EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
949
950/* -------------------- functions on glists --------------------- */
951EXTERN t_glist *glist_new( void);
952EXTERN void glist_init(t_glist *x);
953EXTERN void glist_add(t_glist *x, t_gobj *g);
954EXTERN void glist_cleanup(t_glist *x);
955EXTERN void glist_free(t_glist *x);
956
957EXTERN void glist_clear(t_glist *x);
958EXTERN t_canvas *glist_getcanvas(t_glist *x);
959EXTERN int glist_isselected(t_glist *x, t_gobj *y);
960EXTERN void glist_select(t_glist *x, t_gobj *y);
961EXTERN void glist_deselect(t_glist *x, t_gobj *y);
962EXTERN void glist_noselect(t_glist *x);
963EXTERN void glist_selectall(t_glist *x);
964EXTERN void glist_delete(t_glist *x, t_gobj *y);
965EXTERN void glist_retext(t_glist *x, t_text *y);
966EXTERN void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
967 t_glistkeyfn keyfn, int xpos, int ypos);
968EXTERN int glist_isvisible(t_glist *x);
969EXTERN int glist_istoplevel(t_glist *x);
970EXTERN t_glist *glist_findgraph(t_glist *x);
971EXTERN int glist_getfont(t_glist *x);
972EXTERN void glist_sort(t_glist *canvas);
973EXTERN void glist_read(t_glist *x, t_symbol *filename, t_symbol *format);
974EXTERN void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format);
975
976EXTERN float glist_pixelstox(t_glist *x, float xpix);
977EXTERN float glist_pixelstoy(t_glist *x, float ypix);
978EXTERN float glist_xtopixels(t_glist *x, float xval);
979EXTERN float glist_ytopixels(t_glist *x, float yval);
980EXTERN float glist_dpixtodx(t_glist *x, float dxpix);
981EXTERN float glist_dpixtody(t_glist *x, float dypix);
982
983EXTERN void glist_redrawitem(t_glist *owner, t_gobj *gobj);
984EXTERN void glist_getnextxy(t_glist *gl, int *xval, int *yval);
985EXTERN void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv);
986EXTERN t_glist *glist_addglist(t_glist *g, t_symbol *sym,
987 float x1, float y1, float x2, float y2,
988 float px1, float py1, float px2, float py2);
989EXTERN void glist_arraydialog(t_glist *parent, t_symbol *name,
990 t_floatarg size, t_floatarg saveit, t_floatarg newgraph);
991EXTERN t_binbuf *glist_writetobinbuf(t_glist *x, int wholething);
992EXTERN int glist_isgraph(t_glist *x);
993EXTERN void glist_redraw(t_glist *x);
994EXTERN void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
995 char *tag, int x1, int y1, int x2, int y2);
996EXTERN void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag);
997EXTERN void canvas_create_editor(t_glist *x, int createit);
998void canvas_deletelinesforio(t_canvas *x, t_text *text,
999 t_inlet *inp, t_outlet *outp);
1000
1001
1002/* -------------------- functions on texts ------------------------- */
1003EXTERN void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize);
1004EXTERN void text_drawborder(t_text *x, t_glist *glist, char *tag,
1005 int width, int height, int firsttime);
1006EXTERN void text_eraseborder(t_text *x, t_glist *glist, char *tag);
1007EXTERN int text_xcoord(t_text *x, t_glist *glist);
1008EXTERN int text_ycoord(t_text *x, t_glist *glist);
1009EXTERN int text_xpix(t_text *x, t_glist *glist);
1010EXTERN int text_ypix(t_text *x, t_glist *glist);
1011EXTERN int text_shouldvis(t_text *x, t_glist *glist);
1012
1013/* -------------------- functions on rtexts ------------------------- */
1014#define RTEXT_DOWN 1
1015#define RTEXT_DRAG 2
1016#define RTEXT_DBL 3
1017#define RTEXT_SHIFT 4
1018
1019EXTERN t_rtext *rtext_new(t_glist *glist, t_text *who);
1020EXTERN t_rtext *glist_findrtext(t_glist *gl, t_text *who);
1021EXTERN void rtext_draw(t_rtext *x);
1022EXTERN void rtext_erase(t_rtext *x);
1023EXTERN t_rtext *rtext_remove(t_rtext *first, t_rtext *x);
1024EXTERN int rtext_height(t_rtext *x);
1025EXTERN void rtext_displace(t_rtext *x, int dx, int dy);
1026EXTERN void rtext_select(t_rtext *x, int state);
1027EXTERN void rtext_activate(t_rtext *x, int state);
1028EXTERN void rtext_free(t_rtext *x);
1029EXTERN void rtext_key(t_rtext *x, int n, t_symbol *s);
1030EXTERN void rtext_mouse(t_rtext *x, int xval, int yval, int flag);
1031EXTERN void rtext_retext(t_rtext *x);
1032EXTERN int rtext_width(t_rtext *x);
1033EXTERN int rtext_height(t_rtext *x);
1034EXTERN char *rtext_gettag(t_rtext *x);
1035EXTERN void rtext_gettext(t_rtext *x, char **buf, int *bufsize);
1036
1037/* -------------------- functions on canvases ------------------------ */
1038EXTERN t_class *canvas_class;
1039
1040EXTERN t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv);
1041EXTERN t_symbol *canvas_makebindsym(t_symbol *s);
1042EXTERN void canvas_vistext(t_canvas *x, t_text *y);
1043EXTERN void canvas_fixlinesfor(t_canvas *x, t_text *text);
1044EXTERN void canvas_deletelinesfor(t_canvas *x, t_text *text);
1045EXTERN void canvas_stowconnections(t_canvas *x);
1046EXTERN void canvas_restoreconnections(t_canvas *x);
1047EXTERN void canvas_redraw(t_canvas *x);
1048
1049EXTERN t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *sym);
1050EXTERN void canvas_rminlet(t_canvas *x, t_inlet *ip);
1051EXTERN t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *sym);
1052EXTERN void canvas_rmoutlet(t_canvas *x, t_outlet *op);
1053EXTERN void canvas_redrawallfortemplate(t_canvas *tmpl);
1054EXTERN void canvas_zapallfortemplate(t_canvas *tmpl);
1055EXTERN void canvas_setusedastemplate(t_canvas *x);
1056EXTERN t_canvas *canvas_getcurrent(void);
1057EXTERN void canvas_setcurrent(t_canvas *x);
1058EXTERN void canvas_unsetcurrent(t_canvas *x);
1059EXTERN t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s);
1060EXTERN t_canvas *canvas_getrootfor(t_canvas *x);
1061EXTERN void canvas_dirty(t_canvas *x, t_int n);
1062EXTERN int canvas_getfont(t_canvas *x);
1063typedef int (*t_canvasapply)(t_canvas *x, t_int x1, t_int x2, t_int x3);
1064
1065EXTERN t_int *canvas_recurapply(t_canvas *x, t_canvasapply *fn,
1066 t_int x1, t_int x2, t_int x3);
1067
1068EXTERN void canvas_resortinlets(t_canvas *x);
1069EXTERN void canvas_resortoutlets(t_canvas *x);
1070EXTERN void canvas_free(t_canvas *x);
1071EXTERN void canvas_updatewindowlist( void);
1072EXTERN void canvas_editmode(t_canvas *x, t_floatarg yesplease);
1073EXTERN int canvas_isabstraction(t_canvas *x);
1074EXTERN int canvas_istable(t_canvas *x);
1075EXTERN int canvas_showtext(t_canvas *x);
1076EXTERN void canvas_vis(t_canvas *x, t_floatarg f);
1077EXTERN t_canvasenvironment *canvas_getenv(t_canvas *x);
1078EXTERN void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir);
1079EXTERN void canvas_loadbang(t_canvas *x);
1080EXTERN int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos,
1081 int *x1p, int *y1p, int *x2p, int *y2p);
1082EXTERN int canvas_setdeleting(t_canvas *x, int flag);
1083
1084typedef void (*t_undofn)(t_canvas *canvas, void *buf,
1085 int action); /* a function that does UNDO/REDO */
1086#define UNDO_FREE 0 /* free current undo/redo buffer */
1087#define UNDO_UNDO 1 /* undo */
1088#define UNDO_REDO 2 /* redo */
1089EXTERN void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
1090 const char *name);
1091EXTERN void canvas_noundo(t_canvas *x);
1092EXTERN int canvas_getindex(t_canvas *x, t_gobj *y);
1093
1094/* T.Grill - made public for dynamic object creation */
1095/* in g_editor.c */
1096EXTERN void canvas_connect(t_canvas *x,
1097 t_floatarg fwhoout, t_floatarg foutno,t_floatarg fwhoin, t_floatarg finno);
1098EXTERN void canvas_disconnect(t_canvas *x,
1099 float index1, float outno, float index2, float inno);
1100EXTERN int canvas_isconnected (t_canvas *x,
1101 t_text *ob1, int n1, t_text *ob2, int n2);
1102EXTERN void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy);
1103
1104
1105/* ---- functions on canvasses as objects --------------------- */
1106
1107EXTERN void canvas_fattenforscalars(t_canvas *x,
1108 int *x1, int *y1, int *x2, int *y2);
1109EXTERN void canvas_visforscalars(t_canvas *x, t_glist *glist, int vis);
1110EXTERN int canvas_clicksub(t_canvas *x, int xpix, int ypix, int shift,
1111 int alt, int dbl, int doit);
1112EXTERN t_glist *canvas_getglistonsuper(void);
1113
1114EXTERN void linetraverser_start(t_linetraverser *t, t_canvas *x);
1115EXTERN t_outconnect *linetraverser_next(t_linetraverser *t);
1116EXTERN void linetraverser_skipobject(t_linetraverser *t);
1117
1118/* --------------------- functions on tscalars --------------------- */
1119
1120EXTERN void tscalar_getrect(t_tscalar *x, t_glist *owner,
1121 int *xp1, int *yp1, int *xp2, int *yp2);
1122EXTERN void tscalar_vis(t_tscalar *x, t_glist *owner, int flag);
1123EXTERN int tscalar_click(t_tscalar *x, int xpix, int ypix, int shift,
1124 int alt, int dbl, int doit);
1125
1126/* --------- functions on garrays (graphical arrays) -------------------- */
1127
1128EXTERN t_template *garray_template(t_garray *x);
1129
1130/* -------------------- arrays --------------------- */
1131EXTERN t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *tmpl,
1132 t_floatarg f, t_floatarg saveit);
1133EXTERN t_array *array_new(t_symbol *templatesym, t_gpointer *parent);
1134EXTERN void array_resize(t_array *x, t_template *tmpl, int n);
1135EXTERN void array_free(t_array *x);
1136
1137/* --------------------- gpointers and stubs ---------------- */
1138EXTERN t_gstub *gstub_new(t_glist *gl, t_array *a);
1139EXTERN void gstub_cutoff(t_gstub *gs);
1140EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x);
1141
1142/* --------------------- scalars ------------------------- */
1143EXTERN void word_init(t_word *wp, t_template *tmpl, t_gpointer *gp);
1144EXTERN void word_restore(t_word *wp, t_template *tmpl,
1145 int argc, t_atom *argv);
1146EXTERN t_scalar *scalar_new(t_glist *owner,
1147 t_symbol *templatesym);
1148EXTERN void scalar_getbasexy(t_scalar *x, float *basex, float *basey);
1149
1150/* ------helper routines for "garrays" and "plots" -------------- */
1151EXTERN int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
1152 t_symbol *elemtemplatesym,
1153 float linewidth, float xloc, float xinc, float yloc,
1154 int xpix, int ypix, int shift, int alt, int dbl, int doit);
1155
1156EXTERN void array_getcoordinate(t_glist *glist,
1157 char *elem, int xonset, int yonset, int wonset, int indx,
1158 float basex, float basey, float xinc,
1159 float *xp, float *yp, float *wp);
1160
1161EXTERN int array_getfields(t_symbol *elemtemplatesym,
1162 t_canvas **elemtemplatecanvasp,
1163 t_template **elemtemplatep, int *elemsizep,
1164 int *xonsetp, int *yonsetp, int *wonsetp);
1165
1166/* --------------------- templates ------------------------- */
1167EXTERN t_template *template_new(t_symbol *sym, int argc, t_atom *argv);
1168EXTERN void template_free(t_template *x);
1169EXTERN int template_match(t_template *x1, t_template *x2);
1170EXTERN int template_find_field(t_template *x, t_symbol *name, int *p_onset,
1171 int *p_type, t_symbol **p_arraytype);
1172EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
1173 int loud);
1174EXTERN void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
1175 t_float f, int loud);
1176EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
1177 t_word *wp, int loud);
1178EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
1179 t_word *wp, t_symbol *s, int loud);
1180
1181EXTERN t_template *gtemplate_get(t_gtemplate *x);
1182EXTERN t_template *template_findbyname(t_symbol *s);
1183EXTERN t_canvas *template_findcanvas(t_template *tmpl);
1184
1185EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname,
1186 t_word *wp, int loud);
1187EXTERN void template_setfloat(t_template *x, t_symbol *fieldname,
1188 t_word *wp, t_float f, int loud);
1189EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
1190 t_word *wp, int loud);
1191EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
1192 t_word *wp, t_symbol *s, int loud);
1193
1194/* ----------------------- guiconnects, g_guiconnect.c --------- */
1195EXTERN t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym);
1196EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay);
1197
1198/* ------------- IEMGUI routines used in other g_ files ---------------- */
1199EXTERN t_symbol *iemgui_raute2dollar(t_symbol *s);
1200EXTERN t_symbol *iemgui_dollar2raute(t_symbol *s);
1201
1202#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
1203}
1204#endif
diff --git a/apps/plugins/pdbox/PDa/src/g_editor.c b/apps/plugins/pdbox/PDa/src/g_editor.c
new file mode 100644
index 0000000000..a1dea79df1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_editor.c
@@ -0,0 +1,4548 @@
1/* Copyright (c) 1997-2001 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include <stdlib.h>
6#include <stdio.h>
7#include "m_pd.h"
8#include "m_imp.h"
9#include "s_stuff.h"
10#include "g_canvas.h"
11#include <string.h>
12
13void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename,
14 int selectem);
15
16void open_via_helppath(const char *name, const char *dir);
17char *class_gethelpdir(t_class *c);
18
19/* ------------------ forward declarations --------------- */
20static void canvas_doclear(t_canvas *x);
21static void glist_setlastxy(t_glist *gl, int xval, int yval);
22static void glist_donewloadbangs(t_glist *x);
23static t_binbuf *canvas_docopy(t_canvas *x);
24static void canvas_dopaste(t_canvas *x, t_binbuf *b);
25static void canvas_paste(t_canvas *x);
26static void canvas_clearline(t_canvas *x);
27static t_binbuf *copy_binbuf;
28
29/* ---------------- generic widget behavior ------------------------- */
30
31void gobj_getrect(t_gobj *x, t_glist *glist, int *x1, int *y1,
32 int *x2, int *y2)
33{
34 if (x->g_pd->c_wb && x->g_pd->c_wb->w_getrectfn)
35 (*x->g_pd->c_wb->w_getrectfn)(x, glist, x1, y1, x2, y2);
36}
37
38void gobj_displace(t_gobj *x, t_glist *glist, int dx, int dy)
39{
40 if (x->g_pd->c_wb && x->g_pd->c_wb->w_displacefn)
41 (*x->g_pd->c_wb->w_displacefn)(x, glist, dx, dy);
42}
43
44void gobj_select(t_gobj *x, t_glist *glist, int state)
45{
46 if (x->g_pd->c_wb && x->g_pd->c_wb->w_selectfn)
47 (*x->g_pd->c_wb->w_selectfn)(x, glist, state);
48}
49
50void gobj_activate(t_gobj *x, t_glist *glist, int state)
51{
52 if (x->g_pd->c_wb && x->g_pd->c_wb->w_activatefn)
53 (*x->g_pd->c_wb->w_activatefn)(x, glist, state);
54}
55
56void gobj_delete(t_gobj *x, t_glist *glist)
57{
58 if (x->g_pd->c_wb && x->g_pd->c_wb->w_deletefn)
59 (*x->g_pd->c_wb->w_deletefn)(x, glist);
60}
61
62void gobj_vis(t_gobj *x, struct _glist *glist, int flag)
63{
64 if (x->g_pd->c_wb && x->g_pd->c_wb->w_visfn)
65 (*x->g_pd->c_wb->w_visfn)(x, glist, flag);
66}
67
68int gobj_click(t_gobj *x, struct _glist *glist,
69 int xpix, int ypix, int shift, int alt, int dbl, int doit)
70{
71 if (x->g_pd->c_wb && x->g_pd->c_wb->w_clickfn)
72 return ((*x->g_pd->c_wb->w_clickfn)(x,
73 glist, xpix, ypix, shift, alt, dbl, doit));
74 else return (0);
75}
76
77/* ------------------------ managing the selection ----------------- */
78
79void glist_selectline(t_glist *x, t_outconnect *oc, int index1,
80 int outno, int index2, int inno)
81{
82 if (x->gl_editor)
83 {
84 glist_noselect(x);
85 x->gl_editor->e_selectedline = 1;
86 x->gl_editor->e_selectline_index1 = index1;
87 x->gl_editor->e_selectline_outno = outno;
88 x->gl_editor->e_selectline_index2 = index2;
89 x->gl_editor->e_selectline_inno = inno;
90 x->gl_editor->e_selectline_tag = oc;
91 sys_vgui(".x%x.c itemconfigure l%x -fill blue\n",
92 x, x->gl_editor->e_selectline_tag);
93 }
94}
95
96void glist_deselectline(t_glist *x)
97{
98 if (x->gl_editor)
99 {
100 x->gl_editor->e_selectedline = 0;
101 sys_vgui(".x%x.c itemconfigure l%x -fill black\n",
102 x, x->gl_editor->e_selectline_tag);
103 }
104}
105
106int glist_isselected(t_glist *x, t_gobj *y)
107{
108 if (x->gl_editor)
109 {
110 t_selection *sel;
111 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
112 if (sel->sel_what == y) return (1);
113 }
114 return (0);
115}
116
117 /* call this for unselected objects only */
118void glist_select(t_glist *x, t_gobj *y)
119{
120 if (x->gl_editor)
121 {
122 t_selection *sel = (t_selection *)getbytes(sizeof(*sel));
123 if (x->gl_editor->e_selectedline)
124 glist_deselectline(x);
125 /* LATER #ifdef out the following check */
126 if (glist_isselected(x, y)) bug("glist_select");
127 sel->sel_next = x->gl_editor->e_selection;
128 sel->sel_what = y;
129 x->gl_editor->e_selection = sel;
130 gobj_select(y, x, 1);
131 }
132}
133
134 /* call this for selected objects only */
135void glist_deselect(t_glist *x, t_gobj *y)
136{
137 int fixdsp = 0;
138 static int reenter = 0;
139 if (reenter) return;
140 reenter = 1;
141 if (x->gl_editor)
142 {
143 t_selection *sel, *sel2;
144 t_rtext *z = 0;
145 if (!glist_isselected(x, y)) bug("glist_deselect");
146 if (x->gl_editor->e_textedfor)
147 {
148 t_rtext *fuddy = glist_findrtext(x, (t_text *)y);
149 if (x->gl_editor->e_textedfor == fuddy)
150 {
151 if (x->gl_editor->e_textdirty)
152 {
153 z = fuddy;
154 canvas_stowconnections(glist_getcanvas(x));
155 }
156 gobj_activate(y, x, 0);
157 }
158 if (zgetfn(&y->g_pd, gensym("dsp")))
159 fixdsp = 1;
160 }
161 if ((sel = x->gl_editor->e_selection)->sel_what == y)
162 {
163 x->gl_editor->e_selection = x->gl_editor->e_selection->sel_next;
164 gobj_select(sel->sel_what, x, 0);
165 freebytes(sel, sizeof(*sel));
166 }
167 else
168 {
169 for (sel = x->gl_editor->e_selection; sel2 = sel->sel_next;
170 sel = sel2)
171 {
172 if (sel2->sel_what == y)
173 {
174 sel->sel_next = sel2->sel_next;
175 gobj_select(sel2->sel_what, x, 0);
176 freebytes(sel2, sizeof(*sel2));
177 break;
178 }
179 }
180 }
181 if (z)
182 {
183 char *buf;
184 int bufsize;
185
186 rtext_gettext(z, &buf, &bufsize);
187 text_setto((t_text *)y, x, buf, bufsize);
188 canvas_fixlinesfor(glist_getcanvas(x), (t_text *)y);
189 x->gl_editor->e_textedfor = 0;
190 }
191 if (fixdsp)
192 canvas_update_dsp();
193 }
194 reenter = 0;
195}
196
197void glist_noselect(t_glist *x)
198{
199 if (x->gl_editor)
200 {
201 while (x->gl_editor->e_selection)
202 glist_deselect(x, x->gl_editor->e_selection->sel_what);
203 if (x->gl_editor->e_selectedline)
204 glist_deselectline(x);
205 }
206}
207
208void glist_selectall(t_glist *x)
209{
210 if (x->gl_editor)
211 {
212 glist_noselect(x);
213 if (x->gl_list)
214 {
215 t_selection *sel = (t_selection *)getbytes(sizeof(*sel));
216 t_gobj *y = x->gl_list;
217 x->gl_editor->e_selection = sel;
218 sel->sel_what = y;
219 gobj_select(y, x, 1);
220 while (y = y->g_next)
221 {
222 t_selection *sel2 = (t_selection *)getbytes(sizeof(*sel2));
223 sel->sel_next = sel2;
224 sel = sel2;
225 sel->sel_what = y;
226 gobj_select(y, x, 1);
227 }
228 sel->sel_next = 0;
229 }
230 }
231}
232
233 /* get the index of a gobj in a glist. If y is zero, return the
234 total number of objects. */
235int glist_getindex(t_glist *x, t_gobj *y)
236{
237 t_gobj *y2;
238 int indx;
239
240 for (y2 = x->gl_list, indx = 0; y2 && y2 != y; y2 = y2->g_next)
241 indx++;
242 return (indx);
243}
244
245 /* get the index of the object, among selected items, if "selected"
246 is set; otherwise, among unselected ones. If y is zero, just
247 counts the selected or unselected objects. */
248int glist_selectionindex(t_glist *x, t_gobj *y, int selected)
249{
250 t_gobj *y2;
251 int indx;
252
253 for (y2 = x->gl_list, indx = 0; y2 && y2 != y; y2 = y2->g_next)
254 if (selected == glist_isselected(x, y2))
255 indx++;
256 return (indx);
257}
258
259static t_gobj *glist_nth(t_glist *x, int n)
260{
261 t_gobj *y;
262 int indx;
263 for (y = x->gl_list, indx = 0; y; y = y->g_next, indx++)
264 if (indx == n)
265 return (y);
266 return (0);
267}
268
269/* ------------------- support for undo/redo -------------------------- */
270
271static t_undofn canvas_undo_fn; /* current undo function if any */
272static int canvas_undo_whatnext; /* whether we can now UNDO or REDO */
273static void *canvas_undo_buf; /* data private to the undo function */
274static t_canvas *canvas_undo_canvas; /* which canvas we can undo on */
275static const char *canvas_undo_name;
276
277void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
278 const char *name)
279{
280 int hadone = 0;
281 /* blow away the old undo information. In one special case the
282 old undo info is re-used; if so we shouldn't free it here. */
283 if (canvas_undo_fn && canvas_undo_buf && (buf != canvas_undo_buf))
284 {
285 (*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_FREE);
286 hadone = 1;
287 }
288 canvas_undo_canvas = x;
289 canvas_undo_fn = undofn;
290 canvas_undo_buf = buf;
291 canvas_undo_whatnext = UNDO_UNDO;
292 canvas_undo_name = name;
293 if (x && glist_isvisible(x) && glist_istoplevel(x))
294 /* enable undo in menu */
295 sys_vgui("pdtk_undomenu .x%x %s no\n", x, name);
296 else if (hadone)
297 sys_vgui("pdtk_undomenu nobody no no\n");
298}
299
300 /* clear undo if it happens to be for the canvas x.
301 (but if x is 0, clear it regardless of who owns it.) */
302void canvas_noundo(t_canvas *x)
303{
304 if (!x || (x == canvas_undo_canvas))
305 canvas_setundo(0, 0, 0, "foo");
306}
307
308static void canvas_undo(t_canvas *x)
309{
310 if (x != canvas_undo_canvas)
311 bug("canvas_undo 1");
312 else if (canvas_undo_whatnext != UNDO_UNDO)
313 bug("canvas_undo 2");
314 else
315 {
316 /* post("undo"); */
317 (*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_UNDO);
318 /* enable redo in menu */
319 if (glist_isvisible(x) && glist_istoplevel(x))
320 sys_vgui("pdtk_undomenu .x%x no %s\n", x, canvas_undo_name);
321 canvas_undo_whatnext = UNDO_REDO;
322 }
323}
324
325static void canvas_redo(t_canvas *x)
326{
327 if (x != canvas_undo_canvas)
328 bug("canvas_undo 1");
329 else if (canvas_undo_whatnext != UNDO_REDO)
330 bug("canvas_undo 2");
331 else
332 {
333 /* post("redo"); */
334 (*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_REDO);
335 /* enable undo in menu */
336 if (glist_isvisible(x) && glist_istoplevel(x))
337 sys_vgui("pdtk_undomenu .x%x %s no\n", x, canvas_undo_name);
338 canvas_undo_whatnext = UNDO_UNDO;
339 }
340}
341
342/* ------- specific undo methods: 1. connect and disconnect -------- */
343
344typedef struct _undo_connect
345{
346 int u_index1;
347 int u_outletno;
348 int u_index2;
349 int u_inletno;
350} t_undo_connect;
351
352static void *canvas_undo_set_disconnect(t_canvas *x,
353 int index1, int outno, int index2, int inno)
354{
355 t_undo_connect *buf = (t_undo_connect *)getbytes(sizeof(*buf));
356 buf->u_index1 = index1;
357 buf->u_outletno = outno;
358 buf->u_index2 = index2;
359 buf->u_inletno = inno;
360 return (buf);
361}
362
363void canvas_disconnect(t_canvas *x,
364 float index1, float outno, float index2, float inno)
365{
366 t_linetraverser t;
367 t_outconnect *oc;
368 linetraverser_start(&t, x);
369 while (oc = linetraverser_next(&t))
370 {
371 int srcno = canvas_getindex(x, &t.tr_ob->ob_g);
372 int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g);
373 if (srcno == index1 && t.tr_outno == outno &&
374 sinkno == index2 && t.tr_inno == inno)
375 {
376 sys_vgui(".x%x.c delete l%x\n", x, oc);
377 obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
378 break;
379 }
380 }
381}
382
383static void canvas_undo_disconnect(t_canvas *x, void *z, int action)
384{
385 t_undo_connect *buf = z;
386 if (action == UNDO_UNDO)
387 {
388 canvas_connect(x, buf->u_index1, buf->u_outletno,
389 buf->u_index2, buf->u_inletno);
390 }
391 else if (action == UNDO_REDO)
392 {
393 canvas_disconnect(x, buf->u_index1, buf->u_outletno,
394 buf->u_index2, buf->u_inletno);
395 }
396 else if (action == UNDO_FREE)
397 t_freebytes(buf, sizeof(*buf));
398}
399
400 /* connect just calls disconnect actions backward... */
401static void *canvas_undo_set_connect(t_canvas *x,
402 int index1, int outno, int index2, int inno)
403{
404 return (canvas_undo_set_disconnect(x, index1, outno, index2, inno));
405}
406
407static void canvas_undo_connect(t_canvas *x, void *z, int action)
408{
409 int myaction;
410 if (action == UNDO_UNDO)
411 myaction = UNDO_REDO;
412 else if (action == UNDO_REDO)
413 myaction = UNDO_UNDO;
414 else myaction = action;
415 canvas_undo_disconnect(x, z, myaction);
416}
417
418/* ---------- ... 2. cut, clear, and typing into objects: -------- */
419
420#define UCUT_CUT 1 /* operation was a cut */
421#define UCUT_CLEAR 2 /* .. a clear */
422#define UCUT_TEXT 3 /* text typed into a box */
423
424typedef struct _undo_cut
425{
426 t_binbuf *u_objectbuf; /* the object cleared or typed into */
427 t_binbuf *u_reconnectbuf; /* connections into and out of object */
428 t_binbuf *u_redotextbuf; /* buffer to paste back for redo if TEXT */
429 int u_mode; /* from flags above */
430} t_undo_cut;
431
432static void *canvas_undo_set_cut(t_canvas *x, int mode)
433{
434 t_undo_cut *buf;
435 t_gobj *y;
436 t_linetraverser t;
437 t_outconnect *oc;
438 int nnotsel= glist_selectionindex(x, 0, 0);
439 buf = (t_undo_cut *)getbytes(sizeof(*buf));
440 buf->u_mode = mode;
441 buf->u_redotextbuf = 0;
442
443 /* store connections into/out of the selection */
444 buf->u_reconnectbuf = binbuf_new();
445 linetraverser_start(&t, x);
446 while (oc = linetraverser_next(&t))
447 {
448 int issel1 = glist_isselected(x, &t.tr_ob->ob_g);
449 int issel2 = glist_isselected(x, &t.tr_ob2->ob_g);
450 if (issel1 != issel2)
451 {
452 binbuf_addv(buf->u_reconnectbuf, "ssiiii;",
453 gensym("#X"), gensym("connect"),
454 (issel1 ? nnotsel : 0)
455 + glist_selectionindex(x, &t.tr_ob->ob_g, issel1),
456 t.tr_outno,
457 (issel2 ? nnotsel : 0) +
458 glist_selectionindex(x, &t.tr_ob2->ob_g, issel2),
459 t.tr_inno);
460 }
461 }
462 if (mode == UCUT_TEXT)
463 {
464 buf->u_objectbuf = canvas_docopy(x);
465 }
466 else if (mode == UCUT_CUT)
467 {
468 buf->u_objectbuf = 0;
469 }
470 else if (mode == UCUT_CLEAR)
471 {
472 buf->u_objectbuf = canvas_docopy(x);
473 }
474 return (buf);
475}
476
477static void canvas_undo_cut(t_canvas *x, void *z, int action)
478{
479 t_undo_cut *buf = z;
480 int mode = buf->u_mode;
481 if (action == UNDO_UNDO)
482 {
483 if (mode == UCUT_CUT)
484 canvas_dopaste(x, copy_binbuf);
485 else if (mode == UCUT_CLEAR)
486 canvas_dopaste(x, buf->u_objectbuf);
487 else if (mode == UCUT_TEXT)
488 {
489 t_gobj *y1, *y2;
490 glist_noselect(x);
491 for (y1 = x->gl_list; y2 = y1->g_next; y1 = y2)
492 ;
493 if (y1)
494 {
495 if (!buf->u_redotextbuf)
496 {
497 glist_noselect(x);
498 glist_select(x, y1);
499 buf->u_redotextbuf = canvas_docopy(x);
500 glist_noselect(x);
501 }
502 glist_delete(x, y1);
503 }
504 canvas_dopaste(x, buf->u_objectbuf);
505 }
506 pd_bind(&x->gl_pd, gensym("#X"));
507 binbuf_eval(buf->u_reconnectbuf, 0, 0, 0);
508 pd_unbind(&x->gl_pd, gensym("#X"));
509 }
510 else if (action == UNDO_REDO)
511 {
512 if (mode == UCUT_CUT || mode == UCUT_CLEAR)
513 canvas_doclear(x);
514 else if (mode == UCUT_TEXT)
515 {
516 t_gobj *y1, *y2;
517 for (y1 = x->gl_list; y2 = y1->g_next; y1 = y2)
518 ;
519 if (y1)
520 glist_delete(x, y1);
521 canvas_dopaste(x, buf->u_redotextbuf);
522 pd_bind(&x->gl_pd, gensym("#X"));
523 binbuf_eval(buf->u_reconnectbuf, 0, 0, 0);
524 pd_unbind(&x->gl_pd, gensym("#X"));
525 }
526 }
527 else if (action == UNDO_FREE)
528 {
529 if (buf->u_objectbuf)
530 binbuf_free(buf->u_objectbuf);
531 if (buf->u_reconnectbuf)
532 binbuf_free(buf->u_reconnectbuf);
533 if (buf->u_redotextbuf)
534 binbuf_free(buf->u_redotextbuf);
535 t_freebytes(buf, sizeof(*buf));
536 }
537}
538
539/* --------- 3. motion, including "tidy up" and stretching ----------- */
540
541typedef struct _undo_move_elem
542{
543 int e_index;
544 int e_xpix;
545 int e_ypix;
546} t_undo_move_elem;
547
548typedef struct _undo_move
549{
550 t_undo_move_elem *u_vec;
551 int u_n;
552} t_undo_move;
553
554static int canvas_undo_already_set_move;
555
556static void *canvas_undo_set_move(t_canvas *x, int selected)
557{
558 int x1, y1, x2, y2, i, indx;
559 t_gobj *y;
560 t_undo_move *buf = (t_undo_move *)getbytes(sizeof(*buf));
561 buf->u_n = selected ? glist_selectionindex(x, 0, 1) : glist_getindex(x, 0);
562 buf->u_vec = (t_undo_move_elem *)getbytes(sizeof(*buf->u_vec) *
563 (selected ? glist_selectionindex(x, 0, 1) : glist_getindex(x, 0)));
564 if (selected)
565 {
566 for (y = x->gl_list, i = indx = 0; y; y = y->g_next, indx++)
567 if (glist_isselected(x, y))
568 {
569 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
570 buf->u_vec[i].e_index = indx;
571 buf->u_vec[i].e_xpix = x1;
572 buf->u_vec[i].e_ypix = y1;
573 i++;
574 }
575 }
576 else
577 {
578 for (y = x->gl_list, indx = 0; y; y = y->g_next, indx++)
579 {
580 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
581 buf->u_vec[indx].e_index = indx;
582 buf->u_vec[indx].e_xpix = x1;
583 buf->u_vec[indx].e_ypix = y1;
584 }
585 }
586 canvas_undo_already_set_move = 1;
587 return (buf);
588}
589
590static void canvas_undo_move(t_canvas *x, void *z, int action)
591{
592 t_undo_move *buf = z;
593 if (action == UNDO_UNDO || action == UNDO_REDO)
594 {
595 int i;
596 for (i = 0; i < buf->u_n; i++)
597 {
598 int x1, y1, x2, y2, newx, newy;
599 t_gobj *y;
600 newx = buf->u_vec[i].e_xpix;
601 newy = buf->u_vec[i].e_ypix;
602 y = glist_nth(x, buf->u_vec[i].e_index);
603 if (y)
604 {
605 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
606 gobj_displace(y, x, newx-x1, newy - y1);
607 buf->u_vec[i].e_xpix = x1;
608 buf->u_vec[i].e_ypix = y1;
609 }
610 }
611 }
612 else if (action == UNDO_FREE)
613 {
614 t_freebytes(buf->u_vec, buf->u_n * sizeof(*buf->u_vec));
615 t_freebytes(buf, sizeof(*buf));
616 }
617}
618
619/* --------- 4. paste (also duplicate) ----------- */
620
621typedef struct _undo_paste
622{
623 int u_index; /* index of first object pasted */
624} t_undo_paste;
625
626static void *canvas_undo_set_paste(t_canvas *x)
627{
628 t_undo_paste *buf = (t_undo_paste *)getbytes(sizeof(*buf));
629 buf->u_index = glist_getindex(x, 0);
630 return (buf);
631}
632
633static void canvas_undo_paste(t_canvas *x, void *z, int action)
634{
635 t_undo_paste *buf = z;
636 if (action == UNDO_UNDO)
637 {
638 t_gobj *y;
639 glist_noselect(x);
640 for (y = glist_nth(x, buf->u_index); y; y = y->g_next)
641 glist_select(x, y);
642 canvas_doclear(x);
643 }
644 else if (action == UNDO_REDO)
645 {
646 t_selection *sel;
647 canvas_dopaste(x, copy_binbuf);
648 /* if it was "duplicate" have to re-enact the displacement. */
649 if (canvas_undo_name && canvas_undo_name[0] == 'd')
650 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
651 gobj_displace(sel->sel_what, x, 10, 10);
652 }
653else if (action == UNDO_FREE)
654 t_freebytes(buf, sizeof(*buf));
655}
656
657 /* recursively check for abstractions to reload as result of a save.
658 Don't reload the one we just saved ("except") though. */
659 /* LATER try to do the same trick for externs. */
660static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir,
661 t_gobj *except)
662{
663 t_gobj *g;
664 int i, nobj = glist_getindex(gl, 0); /* number of objects */
665 for (g = gl->gl_list, i = 0; g && i < nobj; i++)
666 {
667 if (g != except && pd_class(&g->g_pd) == canvas_class &&
668 canvas_isabstraction((t_canvas *)g) &&
669 ((t_canvas *)g)->gl_name == name &&
670 canvas_getdir((t_canvas *)g) == dir)
671 {
672 /* we're going to remake the object, so "g" will go stale.
673 Get its index here, and afterward restore g. Also, the
674 replacement will be at teh end of the list, so we don't
675 do g = g->g_next in this case. */
676 int j = glist_getindex(gl, g);
677 if (!gl->gl_havewindow)
678 canvas_vis(glist_getcanvas(gl), 1);
679 glist_noselect(gl);
680 glist_select(gl, g);
681 canvas_setundo(gl, canvas_undo_cut,
682 canvas_undo_set_cut(gl, UCUT_CLEAR), "clear");
683 canvas_doclear(gl);
684 canvas_undo(gl);
685 glist_noselect(gl);
686 g = glist_nth(gl, j);
687 }
688 else
689 {
690 if (g != except && pd_class(&g->g_pd) == canvas_class)
691 glist_doreload((t_canvas *)g, name, dir, except);
692 g = g->g_next;
693 }
694 }
695}
696
697 /* call canvas_doreload on everyone */
698void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except)
699{
700 t_canvas *x;
701 /* find all root canvases */
702 for (x = canvas_list; x; x = x->gl_next)
703 glist_doreload(x, name, dir, except);
704}
705
706/* ------------------------ event handling ------------------------ */
707
708#define CURSOR_RUNMODE_NOTHING 0
709#define CURSOR_RUNMODE_CLICKME 1
710#define CURSOR_RUNMODE_THICKEN 2
711#define CURSOR_RUNMODE_ADDPOINT 3
712#define CURSOR_EDITMODE_NOTHING 4
713#define CURSOR_EDITMODE_CONNECT 5
714#define CURSOR_EDITMODE_DISCONNECT 6
715
716static char *cursorlist[] = {
717#ifdef MSW
718 "right_ptr", /* CURSOR_RUNMODE_NOTHING */
719#else
720 "left_ptr", /* CURSOR_RUNMODE_NOTHING */
721#endif
722 "arrow", /* CURSOR_RUNMODE_CLICKME */
723 "sb_v_double_arrow", /* CURSOR_RUNMODE_THICKEN */
724 "plus", /* CURSOR_RUNMODE_ADDPOINT */
725 "hand2", /* CURSOR_EDITMODE_NOTHING */
726 "circle", /* CURSOR_EDITMODE_CONNECT */
727 "X_cursor" /* CURSOR_EDITMODE_DISCONNECT */
728};
729
730void canvas_setcursor(t_canvas *x, unsigned int cursornum)
731{
732 static t_canvas *xwas;
733 static unsigned int cursorwas;
734 if (cursornum >= sizeof(cursorlist)/sizeof *cursorlist)
735 {
736 bug("canvas_setcursor");
737 return;
738 }
739 if (xwas != x || cursorwas != cursornum)
740 {
741 sys_vgui(".x%x configure -cursor %s\n", x, cursorlist[cursornum]);
742 xwas = x;
743 cursorwas = cursornum;
744 }
745}
746
747 /* check if a point lies in a gobj. */
748int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos,
749 int *x1p, int *y1p, int *x2p, int *y2p)
750{
751 int x1, y1, x2, y2;
752 t_text *ob;
753 if ((ob = pd_checkobject(&y->g_pd)) &&
754 !text_shouldvis(ob, x))
755 return (0);
756 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
757 if (xpos >= x1 && xpos <= x2 && ypos >= y1 && ypos <= y2)
758 {
759 *x1p = x1;
760 *y1p = y1;
761 *x2p = x2;
762 *y2p = y2;
763 return (1);
764 }
765 else return (0);
766}
767
768 /* find the last gobj, if any, containing the point. */
769static t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos,
770 int *x1p, int *y1p, int *x2p, int *y2p)
771{
772 t_gobj *y, *rval = 0;
773 for (y = x->gl_list; y; y = y->g_next)
774 {
775 if (canvas_hitbox(x, y, xpos, ypos, x1p, y1p, x2p, y2p))
776 rval = y;
777 }
778 return (rval);
779}
780
781 /* right-clicking on a canvas object pops up a menu. */
782static void canvas_rightclick(t_canvas *x, int xpos, int ypos, t_gobj *y)
783{
784 int canprop, canopen;
785 canprop = (!y || (y && class_getpropertiesfn(pd_class(&y->g_pd))));
786 canopen = (y && zgetfn(&y->g_pd, gensym("menu-open")));
787 sys_vgui("pdtk_canvas_popup .x%x %d %d %d %d\n",
788 x, xpos, ypos, canprop, canopen);
789}
790
791 /* tell GUI to create a properties dialog on the canvas. We tell
792 the user the negative of the "pixel" y scale to make it appear to grow
793 naturally upward, whereas pixels grow downward. */
794static void canvas_properties(t_glist *x)
795{
796 char graphbuf[200];
797 sprintf(graphbuf, "pdtk_canvas_dialog %%s %g %g %g %g \n",
798 glist_dpixtodx(x, 1), -glist_dpixtody(x, 1),
799 (float)glist_isgraph(x), (float)x->gl_stretch);
800 gfxstub_new(&x->gl_pd, x, graphbuf);
801}
802
803
804void canvas_setgraph(t_glist *x, int flag)
805{
806 if (!flag && glist_isgraph(x))
807 {
808 if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
809 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
810 x->gl_isgraph = 0;
811 if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
812 {
813 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
814 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
815 }
816 }
817 else if (flag && !glist_isgraph(x))
818 {
819 if (x->gl_pixwidth <= 0)
820 x->gl_pixwidth = GLIST_DEFGRAPHWIDTH;
821
822 if (x->gl_pixheight <= 0)
823 x->gl_pixheight = GLIST_DEFGRAPHHEIGHT;
824
825 if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
826 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
827 x->gl_isgraph = 1;
828 /* if (x->gl_owner && glist_isvisible(x->gl_owner))
829 canvas_vis(x, 1); */
830 if (x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
831 canvas_create_editor(x, 1);
832 if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
833 {
834 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
835 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
836 }
837 }
838}
839
840 /* called from the gui when "OK" is selected on the canvas properties
841 dialog. Again we negate "y" scale. */
842static void canvas_donecanvasdialog(t_glist *x, t_floatarg xperpix,
843 t_floatarg yperpix, t_floatarg fgraphme)
844{
845 int graphme = (fgraphme != 0), redraw = 0;
846 yperpix = -yperpix;
847 if (xperpix == 0)
848 xperpix = 1;
849 if (yperpix == 0)
850 yperpix = 1;
851 canvas_setgraph(x, graphme);
852 if (!x->gl_isgraph && (xperpix != glist_dpixtodx(x, 1)))
853 {
854 if (xperpix > 0)
855 {
856 x->gl_x1 = 0;
857 x->gl_x2 = xperpix;
858 }
859 else
860 {
861 x->gl_x1 = -xperpix * (x->gl_screenx2 - x->gl_screenx1);
862 x->gl_x2 = x->gl_x1 + xperpix;
863 }
864 redraw = 1;
865 }
866 if (!x->gl_isgraph && (yperpix != glist_dpixtody(x, 1)))
867 {
868 if (yperpix > 0)
869 {
870 x->gl_y1 = 0;
871 x->gl_y2 = yperpix;
872 }
873 else
874 {
875 x->gl_y1 = -yperpix * (x->gl_screeny2 - x->gl_screeny1);
876 x->gl_y2 = x->gl_y1 + yperpix;
877 }
878 redraw = 1;
879 }
880 if (redraw)
881 canvas_redraw(x);
882}
883
884 /* called from the gui when a popup menu comes back with "properties,"
885 "open," or "help." */
886static void canvas_done_popup(t_canvas *x, float which, float xpos, float ypos)
887{
888 char pathbuf[MAXPDSTRING], namebuf[MAXPDSTRING];
889 t_gobj *y;
890 for (y = x->gl_list; y; y = y->g_next)
891 {
892 int x1, y1, x2, y2;
893 if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2))
894 {
895 if (which == 0) /* properties */
896 {
897 if (!class_getpropertiesfn(pd_class(&y->g_pd)))
898 continue;
899 (*class_getpropertiesfn(pd_class(&y->g_pd)))(y, x);
900 return;
901 }
902 else if (which == 1) /* open */
903 {
904 if (!zgetfn(&y->g_pd, gensym("menu-open")))
905 continue;
906 vmess(&y->g_pd, gensym("menu-open"), "");
907 return;
908 }
909 else /* help */
910 {
911 char *dir;
912 if (pd_class(&y->g_pd) == canvas_class &&
913 canvas_isabstraction((t_canvas *)y))
914 {
915 t_object *ob = (t_object *)y;
916 int ac = binbuf_getnatom(ob->te_binbuf);
917 t_atom *av = binbuf_getvec(ob->te_binbuf);
918 if (ac < 1)
919 return;
920 atom_string(av, namebuf, MAXPDSTRING);
921 dir = canvas_getdir((t_canvas *)y)->s_name;
922 }
923 else
924 {
925 strcpy(namebuf, class_gethelpname(pd_class(&y->g_pd)));
926 dir = class_gethelpdir(pd_class(&y->g_pd));
927 }
928 if (strcmp(namebuf + strlen(namebuf) - 3, ".pd"))
929 strcat(namebuf, ".pd");
930 open_via_helppath(namebuf, dir);
931 return;
932 }
933 }
934 }
935 if (which == 0)
936 canvas_properties(x);
937 else if (which == 2)
938 {
939 strcpy(pathbuf, sys_libdir->s_name);
940 strcat(pathbuf, "/doc/5.reference/0.INTRO.txt");
941 sys_vgui("menu_opentext %s\n", pathbuf);
942 }
943}
944
945#define NOMOD 0
946#define SHIFTMOD 1
947#define CTRLMOD 2
948#define ALTMOD 4
949#define RIGHTCLICK 8
950
951/* on one-button-mouse machines, you can use double click to
952 mean right click (which gets the popup menu.) Do this for Mac. */
953#ifdef MACOSX
954#define SIMULATERIGHTCLICK
955#endif
956
957#ifdef SIMULATERIGHTCLICK
958static double canvas_upclicktime;
959static int canvas_upx, canvas_upy;
960#define DCLICKINTERVAL 0.25
961#endif
962
963 /* mouse click */
964void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
965 int mod, int doit)
966{
967 t_gobj *y;
968 int shiftmod, runmode, altmod, rightclick;
969 int x1, y1, x2, y2, clickreturned = 0;
970
971 if (!x->gl_editor)
972 {
973 bug("editor");
974 return;
975 }
976
977 shiftmod = (mod & SHIFTMOD);
978 runmode = ((mod & CTRLMOD) || (!x->gl_edit));
979 altmod = (mod & ALTMOD);
980 rightclick = (mod & RIGHTCLICK);
981
982 canvas_undo_already_set_move = 0;
983
984 /* if keyboard was grabbed, notify grabber and cancel the grab */
985 if (doit && x->gl_editor->e_grab && x->gl_editor->e_keyfn)
986 {
987 (* x->gl_editor->e_keyfn) (x->gl_editor->e_grab, 0);
988 glist_grab(x, 0, 0, 0, 0, 0);
989 }
990
991#ifdef SIMULATERIGHTCLICK
992 if (doit && !runmode && xpos == canvas_upx && ypos == canvas_upy &&
993 sys_getrealtime() - canvas_upclicktime < DCLICKINTERVAL)
994 rightclick = 1;
995#endif
996
997 x->gl_editor->e_lastmoved = 0;
998 if (doit)
999 {
1000 x->gl_editor->e_grab = 0;
1001 x->gl_editor->e_onmotion = MA_NONE;
1002 }
1003 /* post("click %d %d %d %d", xpos, ypos, which, mod); */
1004
1005 if (x->gl_editor->e_onmotion != MA_NONE)
1006 return;
1007
1008 x->gl_editor->e_xwas = xpos;
1009 x->gl_editor->e_ywas = ypos;
1010
1011 if (runmode && !rightclick)
1012 {
1013 for (y = x->gl_list; y; y = y->g_next)
1014 {
1015 /* check if the object wants to be clicked */
1016 if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2)
1017 && (clickreturned = gobj_click(y, x, xpos, ypos,
1018 shiftmod, altmod, 0, doit)))
1019 break;
1020 }
1021 if (!doit)
1022 {
1023 if (y)
1024 canvas_setcursor(x, clickreturned);
1025 else canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
1026 }
1027 return;
1028 }
1029 /* if not a runmode left click, fall here. */
1030 if (y = canvas_findhitbox(x, xpos, ypos, &x1, &y1, &x2, &y2))
1031 {
1032 t_object *ob = pd_checkobject(&y->g_pd);
1033 /* check you're in the rectangle */
1034 ob = pd_checkobject(&y->g_pd);
1035 if (rightclick)
1036 canvas_rightclick(x, xpos, ypos, y);
1037 else if (shiftmod)
1038 {
1039 if (doit)
1040 {
1041 t_rtext *rt;
1042 if (ob && (rt = x->gl_editor->e_textedfor) &&
1043 rt == glist_findrtext(x, ob))
1044 {
1045 rtext_mouse(rt, xpos - x1, ypos - y1, RTEXT_SHIFT);
1046 x->gl_editor->e_onmotion = MA_DRAGTEXT;
1047 x->gl_editor->e_xwas = x1;
1048 x->gl_editor->e_ywas = y1;
1049 }
1050 else
1051 {
1052 if (glist_isselected(x, y))
1053 glist_deselect(x, y);
1054 else glist_select(x, y);
1055 }
1056 }
1057 }
1058 else
1059 {
1060 /* look for an outlet */
1061 int noutlet;
1062 if (ob && (noutlet = obj_noutlets(ob)) && ypos >= y2-4)
1063 {
1064 int width = x2 - x1;
1065 int nout1 = (noutlet > 1 ? noutlet - 1 : 1);
1066 int closest = ((xpos-x1) * (nout1) + width/2)/width;
1067 int hotspot = x1 +
1068 (width - IOWIDTH) * closest / (nout1);
1069 if (closest < noutlet &&
1070 xpos >= (hotspot-1) && xpos <= hotspot + (IOWIDTH+1))
1071 {
1072 if (doit)
1073 {
1074 int issignal = obj_issignaloutlet(ob, closest);
1075 x->gl_editor->e_onmotion = MA_CONNECT;
1076 x->gl_editor->e_xwas = xpos;
1077 x->gl_editor->e_ywas = ypos;
1078 sys_vgui(
1079 ".x%x.c create line %d %d %d %d -width %d -tags x\n",
1080 x, xpos, ypos, xpos, ypos,
1081 (issignal ? 2 : 1));
1082 }
1083 else canvas_setcursor(x, CURSOR_EDITMODE_CONNECT);
1084 }
1085 else if (doit)
1086 goto nooutletafterall;
1087 }
1088 /* not in an outlet; select and move */
1089 else if (doit)
1090 {
1091 t_rtext *rt;
1092 /* check if the box is being text edited */
1093 nooutletafterall:
1094 if (ob && (rt = x->gl_editor->e_textedfor) &&
1095 rt == glist_findrtext(x, ob))
1096 {
1097 rtext_mouse(rt, xpos - x1, ypos - y1, RTEXT_DOWN);
1098 x->gl_editor->e_onmotion = MA_DRAGTEXT;
1099 x->gl_editor->e_xwas = x1;
1100 x->gl_editor->e_ywas = y1;
1101 }
1102 else
1103 {
1104 /* otherwise select and drag to displace */
1105 if (!glist_isselected(x, y))
1106 {
1107 glist_noselect(x);
1108 glist_select(x, y);
1109 }
1110 x->gl_editor->e_onmotion = MA_MOVE;
1111 }
1112 }
1113 else canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
1114 }
1115 return;
1116 }
1117 /* if right click doesn't hit any boxes, call rightclick
1118 routine anyway */
1119 if (rightclick)
1120 canvas_rightclick(x, xpos, ypos, 0);
1121
1122 /* if not an editing action, and if we didn't hit a
1123 box, set cursor and return */
1124 if (runmode || rightclick)
1125 {
1126 canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
1127 return;
1128 }
1129 /* having failed to find a box, we try lines now. */
1130 if (!runmode && !altmod && !shiftmod)
1131 {
1132 t_linetraverser t;
1133 t_outconnect *oc;
1134 float fx = xpos, fy = ypos;
1135 t_glist *glist2 = glist_getcanvas(x);
1136 linetraverser_start(&t, glist2);
1137 while (oc = linetraverser_next(&t))
1138 {
1139 float lx1 = t.tr_lx1, ly1 = t.tr_ly1,
1140 lx2 = t.tr_lx2, ly2 = t.tr_ly2;
1141 float area = (lx2 - lx1) * (fy - ly1) -
1142 (ly2 - ly1) * (fx - lx1);
1143 float dsquare = (lx2-lx1) * (lx2-lx1) + (ly2-ly1) * (ly2-ly1);
1144 if (area * area >= 50 * dsquare) continue;
1145 if ((lx2-lx1) * (fx-lx1) + (ly2-ly1) * (fy-ly1) < 0) continue;
1146 if ((lx2-lx1) * (lx2-fx) + (ly2-ly1) * (ly2-fy) < 0) continue;
1147 if (doit)
1148 {
1149 glist_selectline(glist2, oc,
1150 canvas_getindex(glist2, &t.tr_ob->ob_g), t.tr_outno,
1151 canvas_getindex(glist2, &t.tr_ob2->ob_g), t.tr_inno);
1152 }
1153 canvas_setcursor(x, CURSOR_EDITMODE_DISCONNECT);
1154 return;
1155 }
1156 }
1157 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
1158 if (doit)
1159 {
1160 if (!shiftmod) glist_noselect(x);
1161 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags x\n",
1162 x, xpos, ypos, xpos, ypos);
1163 x->gl_editor->e_xwas = xpos;
1164 x->gl_editor->e_ywas = ypos;
1165 x->gl_editor->e_onmotion = MA_REGION;
1166 }
1167}
1168
1169void canvas_mousedown(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
1170 t_floatarg which, t_floatarg mod)
1171{
1172 canvas_doclick(x, xpos, ypos, which, mod, 1);
1173}
1174
1175int canvas_isconnected (t_canvas *x, t_text *ob1, int n1,
1176 t_text *ob2, int n2)
1177{
1178 t_linetraverser t;
1179 t_outconnect *oc;
1180 linetraverser_start(&t, x);
1181 while (oc = linetraverser_next(&t))
1182 if (t.tr_ob == ob1 && t.tr_outno == n1 &&
1183 t.tr_ob2 == ob2 && t.tr_inno == n2)
1184 return (1);
1185 return (0);
1186}
1187
1188void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
1189{
1190 int x11, y11, x12, y12;
1191 t_gobj *y1;
1192 int x21, y21, x22, y22;
1193 t_gobj *y2;
1194 int xwas = x->gl_editor->e_xwas,
1195 ywas = x->gl_editor->e_ywas;
1196 if (doit) sys_vgui(".x%x.c delete x\n", x);
1197 else sys_vgui(".x%x.c coords x %d %d %d %d\n",
1198 x, x->gl_editor->e_xwas,
1199 x->gl_editor->e_ywas, xpos, ypos);
1200
1201 if ((y1 = canvas_findhitbox(x, xwas, ywas, &x11, &y11, &x12, &y12))
1202 && (y2 = canvas_findhitbox(x, xpos, ypos, &x21, &y21, &x22, &y22)))
1203 {
1204 t_object *ob1 = pd_checkobject(&y1->g_pd);
1205 t_object *ob2 = pd_checkobject(&y2->g_pd);
1206 int noutlet1, ninlet2;
1207 if (ob1 && ob2 && ob1 != ob2 &&
1208 (noutlet1 = obj_noutlets(ob1))
1209 && (ninlet2 = obj_ninlets(ob2)))
1210 {
1211 int width1 = x12 - x11, closest1, hotspot1;
1212 int width2 = x22 - x21, closest2, hotspot2;
1213 int lx1, lx2, ly1, ly2;
1214 t_outconnect *oc;
1215
1216 if (noutlet1 > 1)
1217 {
1218 closest1 = ((xwas-x11) * (noutlet1-1) + width1/2)/width1;
1219 hotspot1 = x11 +
1220 (width1 - IOWIDTH) * closest1 / (noutlet1-1);
1221 }
1222 else closest1 = 0, hotspot1 = x11;
1223
1224 if (ninlet2 > 1)
1225 {
1226 closest2 = ((xpos-x21) * (ninlet2-1) + width2/2)/width2;
1227 hotspot2 = x21 +
1228 (width2 - IOWIDTH) * closest2 / (ninlet2-1);
1229 }
1230 else closest2 = 0, hotspot2 = x21;
1231
1232 if (closest1 >= noutlet1)
1233 closest1 = noutlet1 - 1;
1234 if (closest2 >= ninlet2)
1235 closest2 = ninlet2 - 1;
1236
1237 if (canvas_isconnected (x, ob1, closest1, ob2, closest2))
1238 {
1239 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
1240 return;
1241 }
1242 if (obj_issignaloutlet(ob1, closest1) &&
1243 !obj_issignalinlet(ob2, closest2))
1244 {
1245 if (doit)
1246 error("can't connect signal outlet to control inlet");
1247 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
1248 return;
1249 }
1250 if (doit)
1251 {
1252 oc = obj_connect(ob1, closest1, ob2, closest2);
1253 lx1 = x11 + (noutlet1 > 1 ?
1254 ((x12-x11-IOWIDTH) * closest1)/(noutlet1-1) : 0)
1255 + IOMIDDLE;
1256 ly1 = y12;
1257 lx2 = x21 + (ninlet2 > 1 ?
1258 ((x22-x21-IOWIDTH) * closest2)/(ninlet2-1) : 0)
1259 + IOMIDDLE;
1260 ly2 = y21;
1261 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
1262 glist_getcanvas(x),
1263 lx1, ly1, lx2, ly2,
1264 (obj_issignaloutlet(ob1, closest1) ? 2 : 1), oc);
1265 canvas_setundo(x, canvas_undo_connect,
1266 canvas_undo_set_connect(x,
1267 canvas_getindex(x, &ob1->ob_g), closest1,
1268 canvas_getindex(x, &ob2->ob_g), closest2),
1269 "connect");
1270 }
1271 else canvas_setcursor(x, CURSOR_EDITMODE_CONNECT);
1272 return;
1273 }
1274 }
1275 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
1276}
1277
1278void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy)
1279{
1280 t_gobj *y;
1281 for (y = x->gl_list; y; y = y->g_next)
1282 {
1283 int x1, y1, x2, y2;
1284 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
1285 if (hix >= x1 && lox <= x2 && hiy >= y1 && loy <= y2
1286 && !glist_isselected(x, y))
1287 glist_select(x, y);
1288 }
1289}
1290
1291static void canvas_doregion(t_canvas *x, int xpos, int ypos, int doit)
1292{
1293 if (doit)
1294 {
1295 int lox, loy, hix, hiy;
1296 if (x->gl_editor->e_xwas < xpos)
1297 lox = x->gl_editor->e_xwas, hix = xpos;
1298 else hix = x->gl_editor->e_xwas, lox = xpos;
1299 if (x->gl_editor->e_ywas < ypos)
1300 loy = x->gl_editor->e_ywas, hiy = ypos;
1301 else hiy = x->gl_editor->e_ywas, loy = ypos;
1302 canvas_selectinrect(x, lox, loy, hix, hiy);
1303 sys_vgui(".x%x.c delete x\n", x);
1304 x->gl_editor->e_onmotion = 0;
1305 }
1306 else sys_vgui(".x%x.c coords x %d %d %d %d\n",
1307 x, x->gl_editor->e_xwas,
1308 x->gl_editor->e_ywas, xpos, ypos);
1309}
1310
1311void canvas_mouseup(t_canvas *x,
1312 t_floatarg fxpos, t_floatarg fypos, t_floatarg fwhich)
1313{
1314 t_gobj *y;
1315
1316 int xpos = fxpos, ypos = fypos, which = fwhich;
1317
1318 if (!x->gl_editor)
1319 {
1320 bug("editor");
1321 return;
1322 }
1323
1324#ifdef SIMULATERIGHTCLICK
1325 canvas_upclicktime = sys_getrealtime();
1326 canvas_upx = xpos;
1327 canvas_upy = ypos;
1328#endif
1329
1330 if (x->gl_editor->e_onmotion == MA_CONNECT)
1331 canvas_doconnect(x, xpos, ypos, which, 1);
1332 else if (x->gl_editor->e_onmotion == MA_REGION)
1333 canvas_doregion(x, xpos, ypos, 1);
1334 else if (x->gl_editor->e_onmotion == MA_MOVE)
1335 {
1336 /* after motion, if there's only one item selected, activate it */
1337 if (x->gl_editor->e_selection &&
1338 !(x->gl_editor->e_selection->sel_next))
1339 gobj_activate(x->gl_editor->e_selection->sel_what,
1340 x, 1);
1341 }
1342 else if (x->gl_editor->e_onmotion == MA_PASSOUT)
1343 x->gl_editor->e_onmotion = 0;
1344 x->gl_editor->e_onmotion = MA_NONE;
1345
1346
1347#if 1
1348 /* GG misused the (unused) dbl parameter to tell if mouseup */
1349
1350 for (y = x->gl_list; y; y = y->g_next) {
1351 int x1, y1, x2, y2, clickreturned = 0;
1352
1353 /* check if the object wants to be clicked */
1354 if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2)
1355 && (clickreturned = gobj_click(y, x, xpos, ypos,
1356 0, 0, 1, 0)))
1357 break;
1358 }
1359#endif
1360
1361
1362}
1363
1364 /* displace the selection by (dx, dy) pixels */
1365static void canvas_displaceselection(t_canvas *x, int dx, int dy)
1366{
1367 t_selection *y;
1368 int resortin = 0, resortout = 0;
1369 if (!canvas_undo_already_set_move)
1370 {
1371 canvas_setundo(x, canvas_undo_move, canvas_undo_set_move(x, 1),
1372 "motion");
1373 canvas_undo_already_set_move = 1;
1374 }
1375 for (y = x->gl_editor->e_selection; y; y = y->sel_next)
1376 {
1377 t_class *cl = pd_class(&y->sel_what->g_pd);
1378 gobj_displace(y->sel_what, x, dx, dy);
1379 if (cl == vinlet_class) resortin = 1;
1380 else if (cl == voutlet_class) resortout = 1;
1381 }
1382 if (resortin) canvas_resortinlets(x);
1383 if (resortout) canvas_resortoutlets(x);
1384 canvas_dirty(x, 1);
1385}
1386
1387 /* this routine is called whenever a key is pressed or released. "x"
1388 may be zero if there's no current canvas. The first argument is true or
1389 fals for down/up; the second one is either a symbolic key name (e.g.,
1390 "Right" or an Ascii key number. */
1391void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
1392{
1393 static t_symbol *keynumsym, *keyupsym, *keynamesym;
1394 int keynum, fflag;
1395 t_symbol *gotkeysym;
1396
1397 int down, shift;
1398
1399 if (ac < 3)
1400 return;
1401 if (!x->gl_editor)
1402 {
1403 bug("editor");
1404 return;
1405 }
1406 canvas_undo_already_set_move = 0;
1407 down = (atom_getfloat(av) != 0); /* nonzero if it's a key down */
1408 shift = (atom_getfloat(av+2) != 0); /* nonzero if shift-ed */
1409 if (av[1].a_type == A_SYMBOL)
1410 gotkeysym = av[1].a_w.w_symbol;
1411 else if (av[1].a_type == A_FLOAT)
1412 {
1413 char buf[3];
1414 sprintf(buf, "%c", (int)(av[1].a_w.w_float));
1415 gotkeysym = gensym(buf);
1416 }
1417 else gotkeysym = gensym("?");
1418 fflag = (av[0].a_type == A_FLOAT ? av[0].a_w.w_float : 0);
1419 keynum = (av[1].a_type == A_FLOAT ? av[1].a_w.w_float : 0);
1420 if (keynum == '\\' || keynum == '{' || keynum == '}')
1421 {
1422 post("%c: dropped", (int)keynum);
1423 return;
1424 }
1425 if (keynum == '\r') keynum = '\n';
1426 if (av[1].a_type == A_SYMBOL &&
1427 !strcmp(av[1].a_w.w_symbol->s_name, "Return"))
1428 keynum = '\n';
1429 if (!keynumsym)
1430 {
1431 keynumsym = gensym("#key");
1432 keyupsym = gensym("#keyup");
1433 keynamesym = gensym("#keyname");
1434 }
1435#ifdef MACOSX
1436 if (keynum == 30)
1437 keynum = 0, gotkeysym = gensym("Up");
1438 else if (keynum == 31)
1439 keynum = 0, gotkeysym = gensym("Down");
1440 else if (keynum == 28)
1441 keynum = 0, gotkeysym = gensym("Left");
1442 else if (keynum == 29)
1443 keynum = 0, gotkeysym = gensym("Right");
1444#endif
1445 if (keynumsym->s_thing && down)
1446 pd_float(keynumsym->s_thing, (float)keynum);
1447 if (keyupsym->s_thing && !down)
1448 pd_float(keyupsym->s_thing, (float)keynum);
1449 if (keynamesym->s_thing)
1450 {
1451 t_atom at[2];
1452 at[0] = av[0];
1453 SETFLOAT(at, down);
1454 SETSYMBOL(at+1, gotkeysym);
1455 pd_list(keynamesym->s_thing, 0, 2, at);
1456 }
1457 if (!x->gl_editor) /* if that 'invis'ed the window, we'd better stop. */
1458 return;
1459 if (x && down)
1460 {
1461 /* if an object has "grabbed" keys just send them on */
1462 if (x->gl_editor->e_grab
1463 && x->gl_editor->e_keyfn && keynum)
1464 (* x->gl_editor->e_keyfn)
1465 (x->gl_editor->e_grab, (float)keynum);
1466 /* if a text editor is open send it on */
1467 else if (x->gl_editor->e_textedfor)
1468 {
1469 if (!x->gl_editor->e_textdirty)
1470 {
1471 canvas_setundo(x, canvas_undo_cut,
1472 canvas_undo_set_cut(x, UCUT_TEXT), "typing");
1473 }
1474 rtext_key(x->gl_editor->e_textedfor,
1475 (int)keynum, gotkeysym);
1476 if (x->gl_editor->e_textdirty)
1477 canvas_dirty(x, 1);
1478 }
1479 /* check for backspace or clear */
1480 else if (keynum == 8 || keynum == 127)
1481 {
1482 if (x->gl_editor->e_selectedline)
1483 canvas_clearline(x);
1484 else if (x->gl_editor->e_selection)
1485 {
1486 canvas_setundo(x, canvas_undo_cut,
1487 canvas_undo_set_cut(x, UCUT_CLEAR), "clear");
1488 canvas_doclear(x);
1489 }
1490 }
1491 /* check for arrow keys */
1492 else if (!strcmp(gotkeysym->s_name, "Up"))
1493 canvas_displaceselection(x, 0, shift ? -10 : -1);
1494 else if (!strcmp(gotkeysym->s_name, "Down"))
1495 canvas_displaceselection(x, 0, shift ? 10 : 1);
1496 else if (!strcmp(gotkeysym->s_name, "Left"))
1497 canvas_displaceselection(x, shift ? -10 : -1, 0);
1498 else if (!strcmp(gotkeysym->s_name, "Right"))
1499 canvas_displaceselection(x, shift ? 10 : 1, 0);
1500 }
1501}
1502
1503void canvas_motion(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
1504 t_floatarg fmod)
1505{
1506 /* post("motion %d %d", xpos, ypos); */
1507 int mod = fmod;
1508 if (!x->gl_editor)
1509 {
1510 bug("editor");
1511 return;
1512 }
1513 glist_setlastxy(x, xpos, ypos);
1514 if (x->gl_editor->e_onmotion == MA_MOVE)
1515 {
1516 canvas_displaceselection(x,
1517 xpos - x->gl_editor->e_xwas, ypos - x->gl_editor->e_ywas);
1518 x->gl_editor->e_xwas = xpos;
1519 x->gl_editor->e_ywas = ypos;
1520 }
1521 else if (x->gl_editor->e_onmotion == MA_REGION)
1522 canvas_doregion(x, xpos, ypos, 0);
1523 else if (x->gl_editor->e_onmotion == MA_CONNECT)
1524 canvas_doconnect(x, xpos, ypos, 0, 0);
1525 else if (x->gl_editor->e_onmotion == MA_PASSOUT)
1526 {
1527 if (!x->gl_editor->e_motionfn)
1528 bug("e_motionfn");
1529 (*x->gl_editor->e_motionfn)(&x->gl_editor->e_grab->g_pd,
1530 xpos - x->gl_editor->e_xwas,
1531 ypos - x->gl_editor->e_ywas);
1532 x->gl_editor->e_xwas = xpos;
1533 x->gl_editor->e_ywas = ypos;
1534 }
1535 else if (x->gl_editor->e_onmotion == MA_DRAGTEXT)
1536 {
1537 t_rtext *rt = x->gl_editor->e_textedfor;
1538 if (rt)
1539 rtext_mouse(rt, xpos - x->gl_editor->e_xwas,
1540 ypos - x->gl_editor->e_ywas, RTEXT_DRAG);
1541 }
1542 else canvas_doclick(x, xpos, ypos, 0, mod, 0);
1543
1544 x->gl_editor->e_lastmoved = 1;
1545}
1546
1547void canvas_startmotion(t_canvas *x)
1548{
1549 int xval, yval;
1550 if (!x->gl_editor) return;
1551 glist_getnextxy(x, &xval, &yval);
1552 if (xval == 0 && yval == 0) return;
1553 x->gl_editor->e_onmotion = MA_MOVE;
1554 x->gl_editor->e_xwas = xval;
1555 x->gl_editor->e_ywas = yval;
1556}
1557
1558/* ----------------------------- window stuff ----------------------- */
1559
1560void canvas_print(t_canvas *x, t_symbol *s)
1561{
1562 if (*s->s_name) sys_vgui(".x%x.c postscript -file %s\n", x, s->s_name);
1563 else sys_vgui(".x%x.c postscript -file x.ps\n", x);
1564}
1565
1566void canvas_menuclose(t_canvas *x, t_floatarg force)
1567{
1568 if (x->gl_owner)
1569 canvas_vis(x, 0);
1570 else if ((force != 0) || (!x->gl_dirty))
1571 pd_free(&x->gl_pd);
1572 else sys_vgui("pdtk_check {This window has been modified. Close anyway?}\
1573 {.x%x menuclose 1;\n}\n", x);
1574}
1575
1576 /* put up a dialog which may call canvas_font back to do the work */
1577static void canvas_menufont(t_canvas *x)
1578{
1579 char buf[80];
1580 t_canvas *x2 = canvas_getrootfor(x);
1581 gfxstub_deleteforkey(x2);
1582 sprintf(buf, "pdtk_canvas_dofont %%s %d\n", x2->gl_font);
1583 gfxstub_new(&x2->gl_pd, &x2->gl_pd, buf);
1584}
1585
1586static int canvas_find_index1, canvas_find_index2;
1587static t_binbuf *canvas_findbuf;
1588int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf);
1589
1590 /* find an atom or string of atoms */
1591static int canvas_dofind(t_canvas *x, int *myindex1p)
1592{
1593 t_gobj *y;
1594 int myindex1 = *myindex1p, myindex2;
1595 if (myindex1 >= canvas_find_index1)
1596 {
1597 for (y = x->gl_list, myindex2 = 0; y;
1598 y = y->g_next, myindex2++)
1599 {
1600 t_object *ob = 0;
1601 if (ob = pd_checkobject(&y->g_pd))
1602 {
1603 if (binbuf_match(ob->ob_binbuf, canvas_findbuf))
1604 {
1605 if (myindex1 > canvas_find_index1 ||
1606 myindex1 == canvas_find_index1 &&
1607 myindex2 > canvas_find_index2)
1608 {
1609 canvas_find_index1 = myindex1;
1610 canvas_find_index2 = myindex2;
1611 glist_noselect(x);
1612 canvas_vis(x, 1);
1613 canvas_editmode(x, 1.);
1614 glist_select(x, y);
1615 return (1);
1616 }
1617 }
1618 }
1619 }
1620 }
1621 for (y = x->gl_list, myindex2 = 0; y; y = y->g_next, myindex2++)
1622 {
1623 if (pd_class(&y->g_pd) == canvas_class)
1624 {
1625 (*myindex1p)++;
1626 if (canvas_dofind((t_canvas *)y, myindex1p))
1627 return (1);
1628 }
1629 }
1630 return (0);
1631}
1632
1633static void canvas_find(t_canvas *x, t_symbol *s, int ac, t_atom *av)
1634{
1635 int myindex1 = 0, i;
1636 for (i = 0; i < ac; i++)
1637 {
1638 if (av[i].a_type == A_SYMBOL)
1639 {
1640 if (!strcmp(av[i].a_w.w_symbol->s_name, "_semi_"))
1641 SETSEMI(&av[i]);
1642 else if (!strcmp(av[i].a_w.w_symbol->s_name, "_comma_"))
1643 SETCOMMA(&av[i]);
1644 }
1645 }
1646 if (!canvas_findbuf)
1647 canvas_findbuf = binbuf_new();
1648 binbuf_clear(canvas_findbuf);
1649 binbuf_add(canvas_findbuf, ac, av);
1650 canvas_find_index1 = 0;
1651 canvas_find_index2 = -1;
1652 canvas_whichfind = x;
1653 if (!canvas_dofind(x, &myindex1))
1654 {
1655 binbuf_print(canvas_findbuf);
1656 post("... couldn't find");
1657 }
1658}
1659
1660static void canvas_find_again(t_canvas *x)
1661{
1662 int myindex1 = 0;
1663 if (!canvas_findbuf || !canvas_whichfind)
1664 return;
1665 if (!canvas_dofind(canvas_whichfind, &myindex1))
1666 {
1667 binbuf_print(canvas_findbuf);
1668 post("... couldn't find");
1669 }
1670}
1671
1672static void canvas_find_parent(t_canvas *x)
1673{
1674 if (x->gl_owner)
1675 canvas_vis(glist_getcanvas(x->gl_owner), 1);
1676}
1677
1678static int glist_dofinderror(t_glist *gl, void *error_object)
1679{
1680 t_gobj *g;
1681 for (g = gl->gl_list; g; g = g->g_next)
1682 {
1683 if ((void *)g == error_object)
1684 {
1685 /* got it... now show it. */
1686 glist_noselect(gl);
1687 canvas_vis(glist_getcanvas(gl), 1);
1688 canvas_editmode(glist_getcanvas(gl), 1.);
1689 glist_select(gl, g);
1690 return (1);
1691 }
1692 else if (g->g_pd == canvas_class)
1693 {
1694 if (glist_dofinderror((t_canvas *)g, error_object))
1695 return (1);
1696 }
1697 }
1698 return (0);
1699}
1700
1701void canvas_finderror(void *error_object)
1702{
1703 t_canvas *x;
1704 /* find all root canvases */
1705 for (x = canvas_list; x; x = x->gl_next)
1706 {
1707 if (glist_dofinderror(x, error_object))
1708 return;
1709 }
1710 post("... sorry, I couldn't find the source of that error.");
1711}
1712
1713void canvas_stowconnections(t_canvas *x)
1714{
1715 t_gobj *selhead = 0, *seltail = 0, *nonhead = 0, *nontail = 0, *y, *y2;
1716 t_linetraverser t;
1717 t_outconnect *oc;
1718 if (!x->gl_editor) return;
1719 /* split list to "selected" and "unselected" parts */
1720 for (y = x->gl_list; y; y = y2)
1721 {
1722 y2 = y->g_next;
1723 if (glist_isselected(x, y))
1724 {
1725 if (seltail)
1726 {
1727 seltail->g_next = y;
1728 seltail = y;
1729 y->g_next = 0;
1730 }
1731 else
1732 {
1733 selhead = seltail = y;
1734 seltail->g_next = 0;
1735 }
1736 }
1737 else
1738 {
1739 if (nontail)
1740 {
1741 nontail->g_next = y;
1742 nontail = y;
1743 y->g_next = 0;
1744 }
1745 else
1746 {
1747 nonhead = nontail = y;
1748 nontail->g_next = 0;
1749 }
1750 }
1751 }
1752 /* move the selected part to the end */
1753 if (!nonhead) x->gl_list = selhead;
1754 else x->gl_list = nonhead, nontail->g_next = selhead;
1755
1756 /* add connections to binbuf */
1757 binbuf_clear(x->gl_editor->e_connectbuf);
1758 linetraverser_start(&t, x);
1759 while (oc = linetraverser_next(&t))
1760 {
1761 int s1 = glist_isselected(x, &t.tr_ob->ob_g);
1762 int s2 = glist_isselected(x, &t.tr_ob2->ob_g);
1763 if (s1 != s2)
1764 binbuf_addv(x->gl_editor->e_connectbuf, "ssiiii;",
1765 gensym("#X"), gensym("connect"),
1766 glist_getindex(x, &t.tr_ob->ob_g), t.tr_outno,
1767 glist_getindex(x, &t.tr_ob2->ob_g), t.tr_inno);
1768 }
1769}
1770
1771void canvas_restoreconnections(t_canvas *x)
1772{
1773 pd_bind(&x->gl_pd, gensym("#X"));
1774 binbuf_eval(x->gl_editor->e_connectbuf, 0, 0, 0);
1775 pd_unbind(&x->gl_pd, gensym("#X"));
1776}
1777
1778static t_binbuf *canvas_docopy(t_canvas *x)
1779{
1780 t_gobj *y;
1781 t_linetraverser t;
1782 t_outconnect *oc;
1783 t_binbuf *b = binbuf_new();
1784 for (y = x->gl_list; y; y = y->g_next)
1785 {
1786 if (glist_isselected(x, y))
1787 gobj_save(y, b);
1788 }
1789 linetraverser_start(&t, x);
1790 while (oc = linetraverser_next(&t))
1791 {
1792 if (glist_isselected(x, &t.tr_ob->ob_g)
1793 && glist_isselected(x, &t.tr_ob2->ob_g))
1794 {
1795 binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"),
1796 glist_selectionindex(x, &t.tr_ob->ob_g, 1), t.tr_outno,
1797 glist_selectionindex(x, &t.tr_ob2->ob_g, 1), t.tr_inno);
1798 }
1799 }
1800 return (b);
1801}
1802
1803static void canvas_copy(t_canvas *x)
1804{
1805 if (!x->gl_editor || !x->gl_editor->e_selection)
1806 return;
1807 binbuf_free(copy_binbuf);
1808 copy_binbuf = canvas_docopy(x);
1809}
1810
1811static void canvas_clearline(t_canvas *x)
1812{
1813 if (x->gl_editor->e_selectedline)
1814 {
1815 canvas_disconnect(x, x->gl_editor->e_selectline_index1,
1816 x->gl_editor->e_selectline_outno,
1817 x->gl_editor->e_selectline_index2,
1818 x->gl_editor->e_selectline_inno);
1819 canvas_setundo(x, canvas_undo_disconnect,
1820 canvas_undo_set_disconnect(x,
1821 x->gl_editor->e_selectline_index1,
1822 x->gl_editor->e_selectline_outno,
1823 x->gl_editor->e_selectline_index2,
1824 x->gl_editor->e_selectline_inno),
1825 "disconnect");
1826 }
1827}
1828
1829extern t_pd *newest;
1830static void canvas_doclear(t_canvas *x)
1831{
1832 t_gobj *y, *y2;
1833 int dspstate;
1834
1835 dspstate = canvas_suspend_dsp();
1836 if (x->gl_editor->e_selectedline)
1837 {
1838 canvas_disconnect(x, x->gl_editor->e_selectline_index1,
1839 x->gl_editor->e_selectline_outno,
1840 x->gl_editor->e_selectline_index2,
1841 x->gl_editor->e_selectline_inno);
1842 canvas_setundo(x, canvas_undo_disconnect,
1843 canvas_undo_set_disconnect(x,
1844 x->gl_editor->e_selectline_index1,
1845 x->gl_editor->e_selectline_outno,
1846 x->gl_editor->e_selectline_index2,
1847 x->gl_editor->e_selectline_inno),
1848 "disconnect");
1849 }
1850 /* if text is selected, deselecting it might remake the
1851 object. So we deselect it and hunt for a "new" object on
1852 the glist to reselect. */
1853 if (x->gl_editor->e_textedfor)
1854 {
1855 newest = 0;
1856 glist_noselect(x);
1857 if (newest)
1858 {
1859 for (y = x->gl_list; y; y = y->g_next)
1860 if (&y->g_pd == newest) glist_select(x, y);
1861 }
1862 }
1863 while (1) /* this is pretty wierd... should rewrite it */
1864 {
1865 for (y = x->gl_list; y; y = y2)
1866 {
1867 y2 = y->g_next;
1868 if (glist_isselected(x, y))
1869 {
1870 glist_delete(x, y);
1871#if 0
1872 if (y2) post("cut 5 %x %x", y2, y2->g_next);
1873 else post("cut 6");
1874#endif
1875 goto next;
1876 }
1877 }
1878 goto restore;
1879 next: ;
1880 }
1881restore:
1882 canvas_resume_dsp(dspstate);
1883 canvas_dirty(x, 1);
1884}
1885
1886static void canvas_cut(t_canvas *x)
1887{
1888 if (x->gl_editor && x->gl_editor->e_selectedline)
1889 canvas_clearline(x);
1890 else if (x->gl_editor && x->gl_editor->e_selection)
1891 {
1892 canvas_setundo(x, canvas_undo_cut,
1893 canvas_undo_set_cut(x, UCUT_CUT), "cut");
1894 canvas_copy(x);
1895 canvas_doclear(x);
1896 }
1897}
1898
1899static int paste_onset;
1900static t_canvas *paste_canvas;
1901
1902static void glist_donewloadbangs(t_glist *x)
1903{
1904 if (x->gl_editor)
1905 {
1906 t_selection *sel;
1907 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
1908 if (pd_class(&sel->sel_what->g_pd) == canvas_class)
1909 canvas_loadbang((t_canvas *)(&sel->sel_what->g_pd));
1910 }
1911}
1912
1913static void canvas_dopaste(t_canvas *x, t_binbuf *b)
1914{
1915 t_gobj *newgobj, *last, *g2;
1916 int dspstate = canvas_suspend_dsp(), nbox, count;
1917
1918 canvas_editmode(x, 1.);
1919 glist_noselect(x);
1920 for (g2 = x->gl_list, nbox = 0; g2; g2 = g2->g_next) nbox++;
1921
1922 paste_onset = nbox;
1923 paste_canvas = x;
1924
1925 pd_bind(&x->gl_pd, gensym("#X"));
1926 binbuf_eval(b, 0, 0, 0);
1927 pd_unbind(&x->gl_pd, gensym("#X"));
1928 for (g2 = x->gl_list, count = 0; g2; g2 = g2->g_next, count++)
1929 if (count >= nbox)
1930 glist_select(x, g2);
1931 paste_canvas = 0;
1932 canvas_resume_dsp(dspstate);
1933 canvas_dirty(x, 1);
1934 glist_donewloadbangs(x);
1935}
1936
1937static void canvas_paste(t_canvas *x)
1938{
1939 canvas_setundo(x, canvas_undo_paste, canvas_undo_set_paste(x), "paste");
1940 canvas_dopaste(x, copy_binbuf);
1941}
1942
1943static void canvas_duplicate(t_canvas *x)
1944{
1945 if (x->gl_editor->e_onmotion == MA_NONE)
1946 {
1947 t_selection *y;
1948 canvas_copy(x);
1949 canvas_setundo(x, canvas_undo_paste, canvas_undo_set_paste(x),
1950 "duplicate");
1951 canvas_dopaste(x, copy_binbuf);
1952 for (y = x->gl_editor->e_selection; y; y = y->sel_next)
1953 gobj_displace(y->sel_what, x,
1954 10, 10);
1955 canvas_dirty(x, 1);
1956 }
1957}
1958
1959static void canvas_selectall(t_canvas *x)
1960{
1961 t_gobj *y;
1962 if (!x->gl_edit)
1963 canvas_editmode(x, 1);
1964 for (y = x->gl_list; y; y = y->g_next)
1965 {
1966 if (!glist_isselected(x, y))
1967 glist_select(x, y);
1968 }
1969}
1970
1971void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
1972 t_floatarg fwhoin, t_floatarg finno)
1973{
1974 int whoout = fwhoout, outno = foutno, whoin = fwhoin, inno = finno;
1975 t_gobj *src = 0, *sink = 0;
1976 t_object *objsrc, *objsink;
1977 t_outconnect *oc;
1978 int nin = whoin, nout = whoout;
1979 if (paste_canvas == x) whoout += paste_onset, whoin += paste_onset;
1980 for (src = x->gl_list; whoout; src = src->g_next, whoout--)
1981 if (!src->g_next) goto bad; /* bug fix thanks to Hannes */
1982 for (sink = x->gl_list; whoin; sink = sink->g_next, whoin--)
1983 if (!sink->g_next) goto bad;
1984 if (!(objsrc = pd_checkobject(&src->g_pd)) ||
1985 !(objsink = pd_checkobject(&sink->g_pd)))
1986 goto bad;
1987 if (!(oc = obj_connect(objsrc, outno, objsink, inno))) goto bad;
1988 if (glist_isvisible(x))
1989 {
1990 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
1991 glist_getcanvas(x), 0, 0, 0, 0,
1992 (obj_issignaloutlet(objsrc, outno) ? 2 : 1),oc);
1993 canvas_fixlinesfor(x, objsrc);
1994 }
1995 return;
1996
1997bad:
1998 post("%s %d %d %d %d (%s->%s) connection failed",
1999 x->gl_name->s_name, nout, outno, nin, inno,
2000 (src? class_getname(pd_class(&src->g_pd)) : "???"),
2001 (sink? class_getname(pd_class(&sink->g_pd)) : "???"));
2002}
2003
2004#define XTOLERANCE 4
2005#define YTOLERANCE 3
2006#define NHIST 15
2007
2008 /* LATER might have to speed this up */
2009static void canvas_tidy(t_canvas *x)
2010{
2011 t_gobj *y, *y2, *y3;
2012 int ax1, ay1, ax2, ay2, bx1, by1, bx2, by2;
2013 int histogram[NHIST], *ip, i, besthist, bestdist;
2014 /* if nobody is selected, this means do it to all boxes;
2015 othewise just the selection */
2016 int all = (x->gl_editor ? (x->gl_editor->e_selection == 0) : 1);
2017
2018 canvas_setundo(x, canvas_undo_move, canvas_undo_set_move(x, !all),
2019 "motion");
2020
2021 /* tidy horizontally */
2022 for (y = x->gl_list; y; y = y->g_next)
2023 if (all || glist_isselected(x, y))
2024 {
2025 gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
2026
2027 for (y2 = x->gl_list; y2; y2 = y2->g_next)
2028 if (all || glist_isselected(x, y2))
2029 {
2030 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
2031 if (by1 <= ay1 + YTOLERANCE && by1 >= ay1 - YTOLERANCE &&
2032 bx1 < ax1)
2033 goto nothorizhead;
2034 }
2035
2036 for (y2 = x->gl_list; y2; y2 = y2->g_next)
2037 if (all || glist_isselected(x, y2))
2038 {
2039 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
2040 if (by1 <= ay1 + YTOLERANCE && by1 >= ay1 - YTOLERANCE
2041 && by1 != ay1)
2042 gobj_displace(y2, x, 0, ay1-by1);
2043 }
2044 nothorizhead: ;
2045 }
2046 /* tidy vertically. First guess the user's favorite vertical spacing */
2047 for (i = NHIST, ip = histogram; i--; ip++) *ip = 0;
2048 for (y = x->gl_list; y; y = y->g_next)
2049 if (all || glist_isselected(x, y))
2050 {
2051 gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
2052 for (y2 = x->gl_list; y2; y2 = y2->g_next)
2053 if (all || glist_isselected(x, y2))
2054 {
2055 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
2056 if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE)
2057 {
2058 int distance = by1-ay2;
2059 if (distance >= 0 && distance < NHIST)
2060 histogram[distance]++;
2061 }
2062 }
2063 }
2064 for (i = 1, besthist = 0, bestdist = 4, ip = histogram + 1;
2065 i < (NHIST-1); i++, ip++)
2066 {
2067 int hit = ip[-1] + 2 * ip[0] + ip[1];
2068 if (hit > besthist)
2069 {
2070 besthist = hit;
2071 bestdist = i;
2072 }
2073 }
2074 post("best vertical distance %d", bestdist);
2075 for (y = x->gl_list; y; y = y->g_next)
2076 if (all || glist_isselected(x, y))
2077 {
2078 int keep = 1;
2079 gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
2080 for (y2 = x->gl_list; y2; y2 = y2->g_next)
2081 if (all || glist_isselected(x, y2))
2082 {
2083 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
2084 if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE &&
2085 ay1 >= by2 - 10 && ay1 < by2 + NHIST)
2086 goto nothead;
2087 }
2088 while (keep)
2089 {
2090 keep = 0;
2091 for (y2 = x->gl_list; y2; y2 = y2->g_next)
2092 if (all || glist_isselected(x, y2))
2093 {
2094 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
2095 if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE &&
2096 by1 > ay1 && by1 < ay2 + NHIST)
2097 {
2098 int vmove = ay2 + bestdist - by1;
2099 gobj_displace(y2, x, ax1-bx1, vmove);
2100 ay1 = by1 + vmove;
2101 ay2 = by2 + vmove;
2102 keep = 1;
2103 break;
2104 }
2105 }
2106 }
2107 nothead: ;
2108 }
2109 canvas_dirty(x, 1);
2110}
2111
2112static void canvas_texteditor(t_canvas *x)
2113{
2114 t_rtext *foo;
2115 char *buf;
2116 int bufsize;
2117 if (foo = x->gl_editor->e_textedfor)
2118 rtext_gettext(foo, &buf, &bufsize);
2119 else buf = "", bufsize = 0;
2120 sys_vgui("pdtk_pd_texteditor {%.*s}\n", bufsize, buf);
2121
2122}
2123
2124void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av)
2125{
2126 /* canvas_editing can be zero; canvas_key checks for that */
2127 canvas_key(canvas_editing, s, ac, av);
2128}
2129
2130void canvas_editmode(t_canvas *x, t_floatarg fyesplease)
2131{
2132 int yesplease = fyesplease;
2133 if (yesplease && x->gl_edit)
2134 return;
2135 x->gl_edit = !x->gl_edit;
2136 if (x->gl_edit && glist_isvisible(x) && glist_istoplevel(x))
2137 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
2138 else
2139 {
2140 glist_noselect(x);
2141 if (glist_isvisible(x) && glist_istoplevel(x))
2142 canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
2143 }
2144 sys_vgui("pdtk_canvas_editval .x%x %d\n",
2145 glist_getcanvas(x), x->gl_edit);
2146}
2147
2148 /* called by canvas_font below */
2149static void canvas_dofont(t_canvas *x, t_floatarg font, t_floatarg xresize,
2150 t_floatarg yresize)
2151{
2152 t_gobj *y;
2153 x->gl_font = font;
2154 if (xresize != 1 || yresize != 1)
2155 {
2156 canvas_setundo(x, canvas_undo_move, canvas_undo_set_move(x, 0),
2157 "motion");
2158 for (y = x->gl_list; y; y = y->g_next)
2159 {
2160 int x1, x2, y1, y2, nx1, ny1;
2161 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
2162 nx1 = x1 * xresize + 0.5;
2163 ny1 = y1 * yresize + 0.5;
2164 gobj_displace(y, x, nx1-x1, ny1-y1);
2165 }
2166 }
2167 if (glist_isvisible(x))
2168 glist_redraw(x);
2169 for (y = x->gl_list; y; y = y->g_next)
2170 if (pd_class(&y->g_pd) == canvas_class
2171 && !canvas_isabstraction((t_canvas *)y))
2172 canvas_dofont((t_canvas *)y, font, xresize, yresize);
2173}
2174
2175 /* canvas_menufont calls up a TK dialog which calls this back */
2176static void canvas_font(t_canvas *x, t_floatarg font, t_floatarg resize,
2177 t_floatarg whichresize)
2178{
2179 float realresize, realresx = 1, realresy = 1;
2180 t_canvas *x2 = canvas_getrootfor(x);
2181 if (!resize) realresize = 1;
2182 else
2183 {
2184 if (resize < 20) resize = 20;
2185 if (resize > 500) resize = 500;
2186 realresize = resize * 0.01;
2187 }
2188 if (whichresize != 3) realresx = realresize;
2189 if (whichresize != 2) realresy = realresize;
2190 canvas_dofont(x2, font, realresx, realresy);
2191 sys_defaultfont = font;
2192}
2193
2194static t_glist *canvas_last_glist;
2195static int canvas_last_glist_x, canvas_last_glist_y;
2196
2197void glist_getnextxy(t_glist *gl, int *xpix, int *ypix)
2198{
2199 if (canvas_last_glist == gl)
2200 *xpix = canvas_last_glist_x, *ypix = canvas_last_glist_y;
2201 else *xpix = *ypix = 40;
2202}
2203
2204static void glist_setlastxy(t_glist *gl, int xval, int yval)
2205{
2206 canvas_last_glist = gl;
2207 canvas_last_glist_x = xval;
2208 canvas_last_glist_y = yval;
2209}
2210
2211
2212void g_editor_setup(void)
2213{
2214/* ------------------------ events ---------------------------------- */
2215 class_addmethod(canvas_class, (t_method)canvas_mousedown, gensym("mouse"),
2216 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2217 class_addmethod(canvas_class, (t_method)canvas_mouseup, gensym("mouseup"),
2218 A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2219 class_addmethod(canvas_class, (t_method)canvas_key, gensym("key"),
2220 A_GIMME, A_NULL);
2221 class_addmethod(canvas_class, (t_method)canvas_motion, gensym("motion"),
2222 A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2223
2224/* ------------------------ menu actions ---------------------------- */
2225 class_addmethod(canvas_class, (t_method)canvas_menuclose,
2226 gensym("menuclose"), A_DEFFLOAT, 0);
2227 class_addmethod(canvas_class, (t_method)canvas_cut,
2228 gensym("cut"), A_NULL);
2229 class_addmethod(canvas_class, (t_method)canvas_copy,
2230 gensym("copy"), A_NULL);
2231 class_addmethod(canvas_class, (t_method)canvas_paste,
2232 gensym("paste"), A_NULL);
2233 class_addmethod(canvas_class, (t_method)canvas_duplicate,
2234 gensym("duplicate"), A_NULL);
2235 class_addmethod(canvas_class, (t_method)canvas_selectall,
2236 gensym("selectall"), A_NULL);
2237 class_addmethod(canvas_class, (t_method)canvas_undo,
2238 gensym("undo"), A_NULL);
2239 class_addmethod(canvas_class, (t_method)canvas_redo,
2240 gensym("redo"), A_NULL);
2241 class_addmethod(canvas_class, (t_method)canvas_tidy,
2242 gensym("tidy"), A_NULL);
2243 class_addmethod(canvas_class, (t_method)canvas_texteditor,
2244 gensym("texteditor"), A_NULL);
2245 class_addmethod(canvas_class, (t_method)canvas_editmode,
2246 gensym("editmode"), A_DEFFLOAT, A_NULL);
2247 class_addmethod(canvas_class, (t_method)canvas_print,
2248 gensym("print"), A_SYMBOL, A_NULL);
2249 class_addmethod(canvas_class, (t_method)canvas_menufont,
2250 gensym("menufont"), A_NULL);
2251 class_addmethod(canvas_class, (t_method)canvas_font,
2252 gensym("font"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2253 class_addmethod(canvas_class, (t_method)canvas_find,
2254 gensym("find"), A_GIMME, A_NULL);
2255 class_addmethod(canvas_class, (t_method)canvas_find_again,
2256 gensym("findagain"), A_NULL);
2257 class_addmethod(canvas_class, (t_method)canvas_find_parent,
2258 gensym("findparent"), A_NULL);
2259 class_addmethod(canvas_class, (t_method)canvas_done_popup,
2260 gensym("done-popup"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2261 class_addmethod(canvas_class, (t_method)canvas_donecanvasdialog,
2262 gensym("donecanvasdialog"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2263 class_addmethod(canvas_class, (t_method)glist_arraydialog,
2264 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2265
2266/* -------------- connect method used in reading files ------------------ */
2267 class_addmethod(canvas_class, (t_method)canvas_connect,
2268 gensym("connect"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2269
2270 class_addmethod(canvas_class, (t_method)canvas_disconnect,
2271 gensym("disconnect"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2272/* -------------- copy buffer ------------------ */
2273 copy_binbuf = binbuf_new();
2274}
2275/* Copyright (c) 1997-2001 Miller Puckette and others.
2276* For information on usage and redistribution, and for a DISCLAIMER OF ALL
2277* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
2278
2279#include <stdlib.h>
2280#include <stdio.h>
2281#include "m_pd.h"
2282#include "m_imp.h"
2283#include "s_stuff.h"
2284#include "g_canvas.h"
2285#include <string.h>
2286
2287void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename,
2288 int selectem);
2289
2290void open_via_helppath(const char *name, const char *dir);
2291char *class_gethelpdir(t_class *c);
2292
2293/* ------------------ forward declarations --------------- */
2294static void canvas_doclear(t_canvas *x);
2295static void glist_setlastxy(t_glist *gl, int xval, int yval);
2296static void glist_donewloadbangs(t_glist *x);
2297static t_binbuf *canvas_docopy(t_canvas *x);
2298static void canvas_dopaste(t_canvas *x, t_binbuf *b);
2299static void canvas_paste(t_canvas *x);
2300static void canvas_clearline(t_canvas *x);
2301static t_binbuf *copy_binbuf;
2302
2303/* ---------------- generic widget behavior ------------------------- */
2304
2305void gobj_getrect(t_gobj *x, t_glist *glist, int *x1, int *y1,
2306 int *x2, int *y2)
2307{
2308 if (x->g_pd->c_wb && x->g_pd->c_wb->w_getrectfn)
2309 (*x->g_pd->c_wb->w_getrectfn)(x, glist, x1, y1, x2, y2);
2310}
2311
2312void gobj_displace(t_gobj *x, t_glist *glist, int dx, int dy)
2313{
2314 if (x->g_pd->c_wb && x->g_pd->c_wb->w_displacefn)
2315 (*x->g_pd->c_wb->w_displacefn)(x, glist, dx, dy);
2316}
2317
2318void gobj_select(t_gobj *x, t_glist *glist, int state)
2319{
2320 if (x->g_pd->c_wb && x->g_pd->c_wb->w_selectfn)
2321 (*x->g_pd->c_wb->w_selectfn)(x, glist, state);
2322}
2323
2324void gobj_activate(t_gobj *x, t_glist *glist, int state)
2325{
2326 if (x->g_pd->c_wb && x->g_pd->c_wb->w_activatefn)
2327 (*x->g_pd->c_wb->w_activatefn)(x, glist, state);
2328}
2329
2330void gobj_delete(t_gobj *x, t_glist *glist)
2331{
2332 if (x->g_pd->c_wb && x->g_pd->c_wb->w_deletefn)
2333 (*x->g_pd->c_wb->w_deletefn)(x, glist);
2334}
2335
2336void gobj_vis(t_gobj *x, struct _glist *glist, int flag)
2337{
2338 if (x->g_pd->c_wb && x->g_pd->c_wb->w_visfn)
2339 (*x->g_pd->c_wb->w_visfn)(x, glist, flag);
2340}
2341
2342int gobj_click(t_gobj *x, struct _glist *glist,
2343 int xpix, int ypix, int shift, int alt, int dbl, int doit)
2344{
2345 if (x->g_pd->c_wb && x->g_pd->c_wb->w_clickfn)
2346 return ((*x->g_pd->c_wb->w_clickfn)(x,
2347 glist, xpix, ypix, shift, alt, dbl, doit));
2348 else return (0);
2349}
2350
2351/* ------------------------ managing the selection ----------------- */
2352
2353void glist_selectline(t_glist *x, t_outconnect *oc, int index1,
2354 int outno, int index2, int inno)
2355{
2356 if (x->gl_editor)
2357 {
2358 glist_noselect(x);
2359 x->gl_editor->e_selectedline = 1;
2360 x->gl_editor->e_selectline_index1 = index1;
2361 x->gl_editor->e_selectline_outno = outno;
2362 x->gl_editor->e_selectline_index2 = index2;
2363 x->gl_editor->e_selectline_inno = inno;
2364 x->gl_editor->e_selectline_tag = oc;
2365 sys_vgui(".x%x.c itemconfigure l%x -fill blue\n",
2366 x, x->gl_editor->e_selectline_tag);
2367 }
2368}
2369
2370void glist_deselectline(t_glist *x)
2371{
2372 if (x->gl_editor)
2373 {
2374 x->gl_editor->e_selectedline = 0;
2375 sys_vgui(".x%x.c itemconfigure l%x -fill black\n",
2376 x, x->gl_editor->e_selectline_tag);
2377 }
2378}
2379
2380int glist_isselected(t_glist *x, t_gobj *y)
2381{
2382 if (x->gl_editor)
2383 {
2384 t_selection *sel;
2385 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
2386 if (sel->sel_what == y) return (1);
2387 }
2388 return (0);
2389}
2390
2391 /* call this for unselected objects only */
2392void glist_select(t_glist *x, t_gobj *y)
2393{
2394 if (x->gl_editor)
2395 {
2396 t_selection *sel = (t_selection *)getbytes(sizeof(*sel));
2397 if (x->gl_editor->e_selectedline)
2398 glist_deselectline(x);
2399 /* LATER #ifdef out the following check */
2400 if (glist_isselected(x, y)) bug("glist_select");
2401 sel->sel_next = x->gl_editor->e_selection;
2402 sel->sel_what = y;
2403 x->gl_editor->e_selection = sel;
2404 gobj_select(y, x, 1);
2405 }
2406}
2407
2408 /* call this for selected objects only */
2409void glist_deselect(t_glist *x, t_gobj *y)
2410{
2411 int fixdsp = 0;
2412 static int reenter = 0;
2413 if (reenter) return;
2414 reenter = 1;
2415 if (x->gl_editor)
2416 {
2417 t_selection *sel, *sel2;
2418 t_rtext *z = 0;
2419 if (!glist_isselected(x, y)) bug("glist_deselect");
2420 if (x->gl_editor->e_textedfor)
2421 {
2422 t_rtext *fuddy = glist_findrtext(x, (t_text *)y);
2423 if (x->gl_editor->e_textedfor == fuddy)
2424 {
2425 if (x->gl_editor->e_textdirty)
2426 {
2427 z = fuddy;
2428 canvas_stowconnections(glist_getcanvas(x));
2429 }
2430 gobj_activate(y, x, 0);
2431 }
2432 if (zgetfn(&y->g_pd, gensym("dsp")))
2433 fixdsp = 1;
2434 }
2435 if ((sel = x->gl_editor->e_selection)->sel_what == y)
2436 {
2437 x->gl_editor->e_selection = x->gl_editor->e_selection->sel_next;
2438 gobj_select(sel->sel_what, x, 0);
2439 freebytes(sel, sizeof(*sel));
2440 }
2441 else
2442 {
2443 for (sel = x->gl_editor->e_selection; sel2 = sel->sel_next;
2444 sel = sel2)
2445 {
2446 if (sel2->sel_what == y)
2447 {
2448 sel->sel_next = sel2->sel_next;
2449 gobj_select(sel2->sel_what, x, 0);
2450 freebytes(sel2, sizeof(*sel2));
2451 break;
2452 }
2453 }
2454 }
2455 if (z)
2456 {
2457 char *buf;
2458 int bufsize;
2459
2460 rtext_gettext(z, &buf, &bufsize);
2461 text_setto((t_text *)y, x, buf, bufsize);
2462 canvas_fixlinesfor(glist_getcanvas(x), (t_text *)y);
2463 x->gl_editor->e_textedfor = 0;
2464 }
2465 if (fixdsp)
2466 canvas_update_dsp();
2467 }
2468 reenter = 0;
2469}
2470
2471void glist_noselect(t_glist *x)
2472{
2473 if (x->gl_editor)
2474 {
2475 while (x->gl_editor->e_selection)
2476 glist_deselect(x, x->gl_editor->e_selection->sel_what);
2477 if (x->gl_editor->e_selectedline)
2478 glist_deselectline(x);
2479 }
2480}
2481
2482void glist_selectall(t_glist *x)
2483{
2484 if (x->gl_editor)
2485 {
2486 glist_noselect(x);
2487 if (x->gl_list)
2488 {
2489 t_selection *sel = (t_selection *)getbytes(sizeof(*sel));
2490 t_gobj *y = x->gl_list;
2491 x->gl_editor->e_selection = sel;
2492 sel->sel_what = y;
2493 gobj_select(y, x, 1);
2494 while (y = y->g_next)
2495 {
2496 t_selection *sel2 = (t_selection *)getbytes(sizeof(*sel2));
2497 sel->sel_next = sel2;
2498 sel = sel2;
2499 sel->sel_what = y;
2500 gobj_select(y, x, 1);
2501 }
2502 sel->sel_next = 0;
2503 }
2504 }
2505}
2506
2507 /* get the index of a gobj in a glist. If y is zero, return the
2508 total number of objects. */
2509int glist_getindex(t_glist *x, t_gobj *y)
2510{
2511 t_gobj *y2;
2512 int indx;
2513
2514 for (y2 = x->gl_list, indx = 0; y2 && y2 != y; y2 = y2->g_next)
2515 indx++;
2516 return (indx);
2517}
2518
2519 /* get the index of the object, among selected items, if "selected"
2520 is set; otherwise, among unselected ones. If y is zero, just
2521 counts the selected or unselected objects. */
2522int glist_selectionindex(t_glist *x, t_gobj *y, int selected)
2523{
2524 t_gobj *y2;
2525 int indx;
2526
2527 for (y2 = x->gl_list, indx = 0; y2 && y2 != y; y2 = y2->g_next)
2528 if (selected == glist_isselected(x, y2))
2529 indx++;
2530 return (indx);
2531}
2532
2533static t_gobj *glist_nth(t_glist *x, int n)
2534{
2535 t_gobj *y;
2536 int indx;
2537 for (y = x->gl_list, indx = 0; y; y = y->g_next, indx++)
2538 if (indx == n)
2539 return (y);
2540 return (0);
2541}
2542
2543/* ------------------- support for undo/redo -------------------------- */
2544
2545static t_undofn canvas_undo_fn; /* current undo function if any */
2546static int canvas_undo_whatnext; /* whether we can now UNDO or REDO */
2547static void *canvas_undo_buf; /* data private to the undo function */
2548static t_canvas *canvas_undo_canvas; /* which canvas we can undo on */
2549static const char *canvas_undo_name;
2550
2551void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
2552 const char *name)
2553{
2554 int hadone = 0;
2555 /* blow away the old undo information. In one special case the
2556 old undo info is re-used; if so we shouldn't free it here. */
2557 if (canvas_undo_fn && canvas_undo_buf && (buf != canvas_undo_buf))
2558 {
2559 (*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_FREE);
2560 hadone = 1;
2561 }
2562 canvas_undo_canvas = x;
2563 canvas_undo_fn = undofn;
2564 canvas_undo_buf = buf;
2565 canvas_undo_whatnext = UNDO_UNDO;
2566 canvas_undo_name = name;
2567 if (x && glist_isvisible(x) && glist_istoplevel(x))
2568 /* enable undo in menu */
2569 sys_vgui("pdtk_undomenu .x%x %s no\n", x, name);
2570 else if (hadone)
2571 sys_vgui("pdtk_undomenu nobody no no\n");
2572}
2573
2574 /* clear undo if it happens to be for the canvas x.
2575 (but if x is 0, clear it regardless of who owns it.) */
2576void canvas_noundo(t_canvas *x)
2577{
2578 if (!x || (x == canvas_undo_canvas))
2579 canvas_setundo(0, 0, 0, "foo");
2580}
2581
2582static void canvas_undo(t_canvas *x)
2583{
2584 if (x != canvas_undo_canvas)
2585 bug("canvas_undo 1");
2586 else if (canvas_undo_whatnext != UNDO_UNDO)
2587 bug("canvas_undo 2");
2588 else
2589 {
2590 /* post("undo"); */
2591 (*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_UNDO);
2592 /* enable redo in menu */
2593 if (glist_isvisible(x) && glist_istoplevel(x))
2594 sys_vgui("pdtk_undomenu .x%x no %s\n", x, canvas_undo_name);
2595 canvas_undo_whatnext = UNDO_REDO;
2596 }
2597}
2598
2599static void canvas_redo(t_canvas *x)
2600{
2601 if (x != canvas_undo_canvas)
2602 bug("canvas_undo 1");
2603 else if (canvas_undo_whatnext != UNDO_REDO)
2604 bug("canvas_undo 2");
2605 else
2606 {
2607 /* post("redo"); */
2608 (*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_REDO);
2609 /* enable undo in menu */
2610 if (glist_isvisible(x) && glist_istoplevel(x))
2611 sys_vgui("pdtk_undomenu .x%x %s no\n", x, canvas_undo_name);
2612 canvas_undo_whatnext = UNDO_UNDO;
2613 }
2614}
2615
2616/* ------- specific undo methods: 1. connect and disconnect -------- */
2617
2618typedef struct _undo_connect
2619{
2620 int u_index1;
2621 int u_outletno;
2622 int u_index2;
2623 int u_inletno;
2624} t_undo_connect;
2625
2626static void *canvas_undo_set_disconnect(t_canvas *x,
2627 int index1, int outno, int index2, int inno)
2628{
2629 t_undo_connect *buf = (t_undo_connect *)getbytes(sizeof(*buf));
2630 buf->u_index1 = index1;
2631 buf->u_outletno = outno;
2632 buf->u_index2 = index2;
2633 buf->u_inletno = inno;
2634 return (buf);
2635}
2636
2637void canvas_disconnect(t_canvas *x,
2638 float index1, float outno, float index2, float inno)
2639{
2640 t_linetraverser t;
2641 t_outconnect *oc;
2642 linetraverser_start(&t, x);
2643 while (oc = linetraverser_next(&t))
2644 {
2645 int srcno = canvas_getindex(x, &t.tr_ob->ob_g);
2646 int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g);
2647 if (srcno == index1 && t.tr_outno == outno &&
2648 sinkno == index2 && t.tr_inno == inno)
2649 {
2650 sys_vgui(".x%x.c delete l%x\n", x, oc);
2651 obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
2652 break;
2653 }
2654 }
2655}
2656
2657static void canvas_undo_disconnect(t_canvas *x, void *z, int action)
2658{
2659 t_undo_connect *buf = z;
2660 if (action == UNDO_UNDO)
2661 {
2662 canvas_connect(x, buf->u_index1, buf->u_outletno,
2663 buf->u_index2, buf->u_inletno);
2664 }
2665 else if (action == UNDO_REDO)
2666 {
2667 canvas_disconnect(x, buf->u_index1, buf->u_outletno,
2668 buf->u_index2, buf->u_inletno);
2669 }
2670 else if (action == UNDO_FREE)
2671 t_freebytes(buf, sizeof(*buf));
2672}
2673
2674 /* connect just calls disconnect actions backward... */
2675static void *canvas_undo_set_connect(t_canvas *x,
2676 int index1, int outno, int index2, int inno)
2677{
2678 return (canvas_undo_set_disconnect(x, index1, outno, index2, inno));
2679}
2680
2681static void canvas_undo_connect(t_canvas *x, void *z, int action)
2682{
2683 int myaction;
2684 if (action == UNDO_UNDO)
2685 myaction = UNDO_REDO;
2686 else if (action == UNDO_REDO)
2687 myaction = UNDO_UNDO;
2688 else myaction = action;
2689 canvas_undo_disconnect(x, z, myaction);
2690}
2691
2692/* ---------- ... 2. cut, clear, and typing into objects: -------- */
2693
2694#define UCUT_CUT 1 /* operation was a cut */
2695#define UCUT_CLEAR 2 /* .. a clear */
2696#define UCUT_TEXT 3 /* text typed into a box */
2697
2698typedef struct _undo_cut
2699{
2700 t_binbuf *u_objectbuf; /* the object cleared or typed into */
2701 t_binbuf *u_reconnectbuf; /* connections into and out of object */
2702 t_binbuf *u_redotextbuf; /* buffer to paste back for redo if TEXT */
2703 int u_mode; /* from flags above */
2704} t_undo_cut;
2705
2706static void *canvas_undo_set_cut(t_canvas *x, int mode)
2707{
2708 t_undo_cut *buf;
2709 t_gobj *y;
2710 t_linetraverser t;
2711 t_outconnect *oc;
2712 int nnotsel= glist_selectionindex(x, 0, 0);
2713 buf = (t_undo_cut *)getbytes(sizeof(*buf));
2714 buf->u_mode = mode;
2715 buf->u_redotextbuf = 0;
2716
2717 /* store connections into/out of the selection */
2718 buf->u_reconnectbuf = binbuf_new();
2719 linetraverser_start(&t, x);
2720 while (oc = linetraverser_next(&t))
2721 {
2722 int issel1 = glist_isselected(x, &t.tr_ob->ob_g);
2723 int issel2 = glist_isselected(x, &t.tr_ob2->ob_g);
2724 if (issel1 != issel2)
2725 {
2726 binbuf_addv(buf->u_reconnectbuf, "ssiiii;",
2727 gensym("#X"), gensym("connect"),
2728 (issel1 ? nnotsel : 0)
2729 + glist_selectionindex(x, &t.tr_ob->ob_g, issel1),
2730 t.tr_outno,
2731 (issel2 ? nnotsel : 0) +
2732 glist_selectionindex(x, &t.tr_ob2->ob_g, issel2),
2733 t.tr_inno);
2734 }
2735 }
2736 if (mode == UCUT_TEXT)
2737 {
2738 buf->u_objectbuf = canvas_docopy(x);
2739 }
2740 else if (mode == UCUT_CUT)
2741 {
2742 buf->u_objectbuf = 0;
2743 }
2744 else if (mode == UCUT_CLEAR)
2745 {
2746 buf->u_objectbuf = canvas_docopy(x);
2747 }
2748 return (buf);
2749}
2750
2751static void canvas_undo_cut(t_canvas *x, void *z, int action)
2752{
2753 t_undo_cut *buf = z;
2754 int mode = buf->u_mode;
2755 if (action == UNDO_UNDO)
2756 {
2757 if (mode == UCUT_CUT)
2758 canvas_dopaste(x, copy_binbuf);
2759 else if (mode == UCUT_CLEAR)
2760 canvas_dopaste(x, buf->u_objectbuf);
2761 else if (mode == UCUT_TEXT)
2762 {
2763 t_gobj *y1, *y2;
2764 glist_noselect(x);
2765 for (y1 = x->gl_list; y2 = y1->g_next; y1 = y2)
2766 ;
2767 if (y1)
2768 {
2769 if (!buf->u_redotextbuf)
2770 {
2771 glist_noselect(x);
2772 glist_select(x, y1);
2773 buf->u_redotextbuf = canvas_docopy(x);
2774 glist_noselect(x);
2775 }
2776 glist_delete(x, y1);
2777 }
2778 canvas_dopaste(x, buf->u_objectbuf);
2779 }
2780 pd_bind(&x->gl_pd, gensym("#X"));
2781 binbuf_eval(buf->u_reconnectbuf, 0, 0, 0);
2782 pd_unbind(&x->gl_pd, gensym("#X"));
2783 }
2784 else if (action == UNDO_REDO)
2785 {
2786 if (mode == UCUT_CUT || mode == UCUT_CLEAR)
2787 canvas_doclear(x);
2788 else if (mode == UCUT_TEXT)
2789 {
2790 t_gobj *y1, *y2;
2791 for (y1 = x->gl_list; y2 = y1->g_next; y1 = y2)
2792 ;
2793 if (y1)
2794 glist_delete(x, y1);
2795 canvas_dopaste(x, buf->u_redotextbuf);
2796 pd_bind(&x->gl_pd, gensym("#X"));
2797 binbuf_eval(buf->u_reconnectbuf, 0, 0, 0);
2798 pd_unbind(&x->gl_pd, gensym("#X"));
2799 }
2800 }
2801 else if (action == UNDO_FREE)
2802 {
2803 if (buf->u_objectbuf)
2804 binbuf_free(buf->u_objectbuf);
2805 if (buf->u_reconnectbuf)
2806 binbuf_free(buf->u_reconnectbuf);
2807 if (buf->u_redotextbuf)
2808 binbuf_free(buf->u_redotextbuf);
2809 t_freebytes(buf, sizeof(*buf));
2810 }
2811}
2812
2813/* --------- 3. motion, including "tidy up" and stretching ----------- */
2814
2815typedef struct _undo_move_elem
2816{
2817 int e_index;
2818 int e_xpix;
2819 int e_ypix;
2820} t_undo_move_elem;
2821
2822typedef struct _undo_move
2823{
2824 t_undo_move_elem *u_vec;
2825 int u_n;
2826} t_undo_move;
2827
2828static int canvas_undo_already_set_move;
2829
2830static void *canvas_undo_set_move(t_canvas *x, int selected)
2831{
2832 int x1, y1, x2, y2, i, indx;
2833 t_gobj *y;
2834 t_undo_move *buf = (t_undo_move *)getbytes(sizeof(*buf));
2835 buf->u_n = selected ? glist_selectionindex(x, 0, 1) : glist_getindex(x, 0);
2836 buf->u_vec = (t_undo_move_elem *)getbytes(sizeof(*buf->u_vec) *
2837 (selected ? glist_selectionindex(x, 0, 1) : glist_getindex(x, 0)));
2838 if (selected)
2839 {
2840 for (y = x->gl_list, i = indx = 0; y; y = y->g_next, indx++)
2841 if (glist_isselected(x, y))
2842 {
2843 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
2844 buf->u_vec[i].e_index = indx;
2845 buf->u_vec[i].e_xpix = x1;
2846 buf->u_vec[i].e_ypix = y1;
2847 i++;
2848 }
2849 }
2850 else
2851 {
2852 for (y = x->gl_list, indx = 0; y; y = y->g_next, indx++)
2853 {
2854 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
2855 buf->u_vec[indx].e_index = indx;
2856 buf->u_vec[indx].e_xpix = x1;
2857 buf->u_vec[indx].e_ypix = y1;
2858 }
2859 }
2860 canvas_undo_already_set_move = 1;
2861 return (buf);
2862}
2863
2864static void canvas_undo_move(t_canvas *x, void *z, int action)
2865{
2866 t_undo_move *buf = z;
2867 if (action == UNDO_UNDO || action == UNDO_REDO)
2868 {
2869 int i;
2870 for (i = 0; i < buf->u_n; i++)
2871 {
2872 int x1, y1, x2, y2, newx, newy;
2873 t_gobj *y;
2874 newx = buf->u_vec[i].e_xpix;
2875 newy = buf->u_vec[i].e_ypix;
2876 y = glist_nth(x, buf->u_vec[i].e_index);
2877 if (y)
2878 {
2879 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
2880 gobj_displace(y, x, newx-x1, newy - y1);
2881 buf->u_vec[i].e_xpix = x1;
2882 buf->u_vec[i].e_ypix = y1;
2883 }
2884 }
2885 }
2886 else if (action == UNDO_FREE)
2887 {
2888 t_freebytes(buf->u_vec, buf->u_n * sizeof(*buf->u_vec));
2889 t_freebytes(buf, sizeof(*buf));
2890 }
2891}
2892
2893/* --------- 4. paste (also duplicate) ----------- */
2894
2895typedef struct _undo_paste
2896{
2897 int u_index; /* index of first object pasted */
2898} t_undo_paste;
2899
2900static void *canvas_undo_set_paste(t_canvas *x)
2901{
2902 t_undo_paste *buf = (t_undo_paste *)getbytes(sizeof(*buf));
2903 buf->u_index = glist_getindex(x, 0);
2904 return (buf);
2905}
2906
2907static void canvas_undo_paste(t_canvas *x, void *z, int action)
2908{
2909 t_undo_paste *buf = z;
2910 if (action == UNDO_UNDO)
2911 {
2912 t_gobj *y;
2913 glist_noselect(x);
2914 for (y = glist_nth(x, buf->u_index); y; y = y->g_next)
2915 glist_select(x, y);
2916 canvas_doclear(x);
2917 }
2918 else if (action == UNDO_REDO)
2919 {
2920 t_selection *sel;
2921 canvas_dopaste(x, copy_binbuf);
2922 /* if it was "duplicate" have to re-enact the displacement. */
2923 if (canvas_undo_name && canvas_undo_name[0] == 'd')
2924 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
2925 gobj_displace(sel->sel_what, x, 10, 10);
2926 }
2927else if (action == UNDO_FREE)
2928 t_freebytes(buf, sizeof(*buf));
2929}
2930
2931 /* recursively check for abstractions to reload as result of a save.
2932 Don't reload the one we just saved ("except") though. */
2933 /* LATER try to do the same trick for externs. */
2934static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir,
2935 t_gobj *except)
2936{
2937 t_gobj *g;
2938 int i, nobj = glist_getindex(gl, 0); /* number of objects */
2939 for (g = gl->gl_list, i = 0; g && i < nobj; i++)
2940 {
2941 if (g != except && pd_class(&g->g_pd) == canvas_class &&
2942 canvas_isabstraction((t_canvas *)g) &&
2943 ((t_canvas *)g)->gl_name == name &&
2944 canvas_getdir((t_canvas *)g) == dir)
2945 {
2946 /* we're going to remake the object, so "g" will go stale.
2947 Get its index here, and afterward restore g. Also, the
2948 replacement will be at teh end of the list, so we don't
2949 do g = g->g_next in this case. */
2950 int j = glist_getindex(gl, g);
2951 if (!gl->gl_havewindow)
2952 canvas_vis(glist_getcanvas(gl), 1);
2953 glist_noselect(gl);
2954 glist_select(gl, g);
2955 canvas_setundo(gl, canvas_undo_cut,
2956 canvas_undo_set_cut(gl, UCUT_CLEAR), "clear");
2957 canvas_doclear(gl);
2958 canvas_undo(gl);
2959 glist_noselect(gl);
2960 g = glist_nth(gl, j);
2961 }
2962 else
2963 {
2964 if (g != except && pd_class(&g->g_pd) == canvas_class)
2965 glist_doreload((t_canvas *)g, name, dir, except);
2966 g = g->g_next;
2967 }
2968 }
2969}
2970
2971 /* call canvas_doreload on everyone */
2972void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except)
2973{
2974 t_canvas *x;
2975 /* find all root canvases */
2976 for (x = canvas_list; x; x = x->gl_next)
2977 glist_doreload(x, name, dir, except);
2978}
2979
2980/* ------------------------ event handling ------------------------ */
2981
2982#define CURSOR_RUNMODE_NOTHING 0
2983#define CURSOR_RUNMODE_CLICKME 1
2984#define CURSOR_RUNMODE_THICKEN 2
2985#define CURSOR_RUNMODE_ADDPOINT 3
2986#define CURSOR_EDITMODE_NOTHING 4
2987#define CURSOR_EDITMODE_CONNECT 5
2988#define CURSOR_EDITMODE_DISCONNECT 6
2989
2990static char *cursorlist[] = {
2991#ifdef MSW
2992 "right_ptr", /* CURSOR_RUNMODE_NOTHING */
2993#else
2994 "left_ptr", /* CURSOR_RUNMODE_NOTHING */
2995#endif
2996 "arrow", /* CURSOR_RUNMODE_CLICKME */
2997 "sb_v_double_arrow", /* CURSOR_RUNMODE_THICKEN */
2998 "plus", /* CURSOR_RUNMODE_ADDPOINT */
2999 "hand2", /* CURSOR_EDITMODE_NOTHING */
3000 "circle", /* CURSOR_EDITMODE_CONNECT */
3001 "X_cursor" /* CURSOR_EDITMODE_DISCONNECT */
3002};
3003
3004void canvas_setcursor(t_canvas *x, unsigned int cursornum)
3005{
3006 static t_canvas *xwas;
3007 static unsigned int cursorwas;
3008 if (cursornum >= sizeof(cursorlist)/sizeof *cursorlist)
3009 {
3010 bug("canvas_setcursor");
3011 return;
3012 }
3013 if (xwas != x || cursorwas != cursornum)
3014 {
3015 sys_vgui(".x%x configure -cursor %s\n", x, cursorlist[cursornum]);
3016 xwas = x;
3017 cursorwas = cursornum;
3018 }
3019}
3020
3021 /* check if a point lies in a gobj. */
3022int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos,
3023 int *x1p, int *y1p, int *x2p, int *y2p)
3024{
3025 int x1, y1, x2, y2;
3026 t_text *ob;
3027 if ((ob = pd_checkobject(&y->g_pd)) &&
3028 !text_shouldvis(ob, x))
3029 return (0);
3030 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
3031 if (xpos >= x1 && xpos <= x2 && ypos >= y1 && ypos <= y2)
3032 {
3033 *x1p = x1;
3034 *y1p = y1;
3035 *x2p = x2;
3036 *y2p = y2;
3037 return (1);
3038 }
3039 else return (0);
3040}
3041
3042 /* find the last gobj, if any, containing the point. */
3043static t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos,
3044 int *x1p, int *y1p, int *x2p, int *y2p)
3045{
3046 t_gobj *y, *rval = 0;
3047 for (y = x->gl_list; y; y = y->g_next)
3048 {
3049 if (canvas_hitbox(x, y, xpos, ypos, x1p, y1p, x2p, y2p))
3050 rval = y;
3051 }
3052 return (rval);
3053}
3054
3055 /* right-clicking on a canvas object pops up a menu. */
3056static void canvas_rightclick(t_canvas *x, int xpos, int ypos, t_gobj *y)
3057{
3058 int canprop, canopen;
3059 canprop = (!y || (y && class_getpropertiesfn(pd_class(&y->g_pd))));
3060 canopen = (y && zgetfn(&y->g_pd, gensym("menu-open")));
3061 sys_vgui("pdtk_canvas_popup .x%x %d %d %d %d\n",
3062 x, xpos, ypos, canprop, canopen);
3063}
3064
3065 /* tell GUI to create a properties dialog on the canvas. We tell
3066 the user the negative of the "pixel" y scale to make it appear to grow
3067 naturally upward, whereas pixels grow downward. */
3068static void canvas_properties(t_glist *x)
3069{
3070 char graphbuf[200];
3071 sprintf(graphbuf, "pdtk_canvas_dialog %%s %g %g %g %g \n",
3072 glist_dpixtodx(x, 1), -glist_dpixtody(x, 1),
3073 (float)glist_isgraph(x), (float)x->gl_stretch);
3074 gfxstub_new(&x->gl_pd, x, graphbuf);
3075}
3076
3077
3078void canvas_setgraph(t_glist *x, int flag)
3079{
3080 if (!flag && glist_isgraph(x))
3081 {
3082 if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
3083 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
3084 x->gl_isgraph = 0;
3085 if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
3086 {
3087 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
3088 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
3089 }
3090 }
3091 else if (flag && !glist_isgraph(x))
3092 {
3093 if (x->gl_pixwidth <= 0)
3094 x->gl_pixwidth = GLIST_DEFGRAPHWIDTH;
3095
3096 if (x->gl_pixheight <= 0)
3097 x->gl_pixheight = GLIST_DEFGRAPHHEIGHT;
3098
3099 if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
3100 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
3101 x->gl_isgraph = 1;
3102 /* if (x->gl_owner && glist_isvisible(x->gl_owner))
3103 canvas_vis(x, 1); */
3104 if (x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
3105 canvas_create_editor(x, 1);
3106 if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
3107 {
3108 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
3109 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
3110 }
3111 }
3112}
3113
3114 /* called from the gui when "OK" is selected on the canvas properties
3115 dialog. Again we negate "y" scale. */
3116static void canvas_donecanvasdialog(t_glist *x, t_floatarg xperpix,
3117 t_floatarg yperpix, t_floatarg fgraphme)
3118{
3119 int graphme = (fgraphme != 0), redraw = 0;
3120 yperpix = -yperpix;
3121 if (xperpix == 0)
3122 xperpix = 1;
3123 if (yperpix == 0)
3124 yperpix = 1;
3125 canvas_setgraph(x, graphme);
3126 if (!x->gl_isgraph && (xperpix != glist_dpixtodx(x, 1)))
3127 {
3128 if (xperpix > 0)
3129 {
3130 x->gl_x1 = 0;
3131 x->gl_x2 = xperpix;
3132 }
3133 else
3134 {
3135 x->gl_x1 = -xperpix * (x->gl_screenx2 - x->gl_screenx1);
3136 x->gl_x2 = x->gl_x1 + xperpix;
3137 }
3138 redraw = 1;
3139 }
3140 if (!x->gl_isgraph && (yperpix != glist_dpixtody(x, 1)))
3141 {
3142 if (yperpix > 0)
3143 {
3144 x->gl_y1 = 0;
3145 x->gl_y2 = yperpix;
3146 }
3147 else
3148 {
3149 x->gl_y1 = -yperpix * (x->gl_screeny2 - x->gl_screeny1);
3150 x->gl_y2 = x->gl_y1 + yperpix;
3151 }
3152 redraw = 1;
3153 }
3154 if (redraw)
3155 canvas_redraw(x);
3156}
3157
3158 /* called from the gui when a popup menu comes back with "properties,"
3159 "open," or "help." */
3160static void canvas_done_popup(t_canvas *x, float which, float xpos, float ypos)
3161{
3162 char pathbuf[MAXPDSTRING], namebuf[MAXPDSTRING];
3163 t_gobj *y;
3164 for (y = x->gl_list; y; y = y->g_next)
3165 {
3166 int x1, y1, x2, y2;
3167 if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2))
3168 {
3169 if (which == 0) /* properties */
3170 {
3171 if (!class_getpropertiesfn(pd_class(&y->g_pd)))
3172 continue;
3173 (*class_getpropertiesfn(pd_class(&y->g_pd)))(y, x);
3174 return;
3175 }
3176 else if (which == 1) /* open */
3177 {
3178 if (!zgetfn(&y->g_pd, gensym("menu-open")))
3179 continue;
3180 vmess(&y->g_pd, gensym("menu-open"), "");
3181 return;
3182 }
3183 else /* help */
3184 {
3185 char *dir;
3186 if (pd_class(&y->g_pd) == canvas_class &&
3187 canvas_isabstraction((t_canvas *)y))
3188 {
3189 t_object *ob = (t_object *)y;
3190 int ac = binbuf_getnatom(ob->te_binbuf);
3191 t_atom *av = binbuf_getvec(ob->te_binbuf);
3192 if (ac < 1)
3193 return;
3194 atom_string(av, namebuf, MAXPDSTRING);
3195 dir = canvas_getdir((t_canvas *)y)->s_name;
3196 }
3197 else
3198 {
3199 strcpy(namebuf, class_gethelpname(pd_class(&y->g_pd)));
3200 dir = class_gethelpdir(pd_class(&y->g_pd));
3201 }
3202 if (strcmp(namebuf + strlen(namebuf) - 3, ".pd"))
3203 strcat(namebuf, ".pd");
3204 open_via_helppath(namebuf, dir);
3205 return;
3206 }
3207 }
3208 }
3209 if (which == 0)
3210 canvas_properties(x);
3211 else if (which == 2)
3212 {
3213 strcpy(pathbuf, sys_libdir->s_name);
3214 strcat(pathbuf, "/doc/5.reference/0.INTRO.txt");
3215 sys_vgui("menu_opentext %s\n", pathbuf);
3216 }
3217}
3218
3219#define NOMOD 0
3220#define SHIFTMOD 1
3221#define CTRLMOD 2
3222#define ALTMOD 4
3223#define RIGHTCLICK 8
3224
3225/* on one-button-mouse machines, you can use double click to
3226 mean right click (which gets the popup menu.) Do this for Mac. */
3227#ifdef MACOSX
3228#define SIMULATERIGHTCLICK
3229#endif
3230
3231#ifdef SIMULATERIGHTCLICK
3232static double canvas_upclicktime;
3233static int canvas_upx, canvas_upy;
3234#define DCLICKINTERVAL 0.25
3235#endif
3236
3237 /* mouse click */
3238void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
3239 int mod, int doit)
3240{
3241 t_gobj *y;
3242 int shiftmod, runmode, altmod, rightclick;
3243 int x1, y1, x2, y2, clickreturned = 0;
3244
3245 if (!x->gl_editor)
3246 {
3247 bug("editor");
3248 return;
3249 }
3250
3251 shiftmod = (mod & SHIFTMOD);
3252 runmode = ((mod & CTRLMOD) || (!x->gl_edit));
3253 altmod = (mod & ALTMOD);
3254 rightclick = (mod & RIGHTCLICK);
3255
3256 canvas_undo_already_set_move = 0;
3257
3258 /* if keyboard was grabbed, notify grabber and cancel the grab */
3259 if (doit && x->gl_editor->e_grab && x->gl_editor->e_keyfn)
3260 {
3261 (* x->gl_editor->e_keyfn) (x->gl_editor->e_grab, 0);
3262 glist_grab(x, 0, 0, 0, 0, 0);
3263 }
3264
3265#ifdef SIMULATERIGHTCLICK
3266 if (doit && !runmode && xpos == canvas_upx && ypos == canvas_upy &&
3267 sys_getrealtime() - canvas_upclicktime < DCLICKINTERVAL)
3268 rightclick = 1;
3269#endif
3270
3271 x->gl_editor->e_lastmoved = 0;
3272 if (doit)
3273 {
3274 x->gl_editor->e_grab = 0;
3275 x->gl_editor->e_onmotion = MA_NONE;
3276 }
3277 /* post("click %d %d %d %d", xpos, ypos, which, mod); */
3278
3279 if (x->gl_editor->e_onmotion != MA_NONE)
3280 return;
3281
3282 x->gl_editor->e_xwas = xpos;
3283 x->gl_editor->e_ywas = ypos;
3284
3285 if (runmode && !rightclick)
3286 {
3287 for (y = x->gl_list; y; y = y->g_next)
3288 {
3289 /* check if the object wants to be clicked */
3290 if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2)
3291 && (clickreturned = gobj_click(y, x, xpos, ypos,
3292 shiftmod, altmod, 0, doit)))
3293 break;
3294 }
3295 if (!doit)
3296 {
3297 if (y)
3298 canvas_setcursor(x, clickreturned);
3299 else canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
3300 }
3301 return;
3302 }
3303 /* if not a runmode left click, fall here. */
3304 if (y = canvas_findhitbox(x, xpos, ypos, &x1, &y1, &x2, &y2))
3305 {
3306 t_object *ob = pd_checkobject(&y->g_pd);
3307 /* check you're in the rectangle */
3308 ob = pd_checkobject(&y->g_pd);
3309 if (rightclick)
3310 canvas_rightclick(x, xpos, ypos, y);
3311 else if (shiftmod)
3312 {
3313 if (doit)
3314 {
3315 t_rtext *rt;
3316 if (ob && (rt = x->gl_editor->e_textedfor) &&
3317 rt == glist_findrtext(x, ob))
3318 {
3319 rtext_mouse(rt, xpos - x1, ypos - y1, RTEXT_SHIFT);
3320 x->gl_editor->e_onmotion = MA_DRAGTEXT;
3321 x->gl_editor->e_xwas = x1;
3322 x->gl_editor->e_ywas = y1;
3323 }
3324 else
3325 {
3326 if (glist_isselected(x, y))
3327 glist_deselect(x, y);
3328 else glist_select(x, y);
3329 }
3330 }
3331 }
3332 else
3333 {
3334 /* look for an outlet */
3335 int noutlet;
3336 if (ob && (noutlet = obj_noutlets(ob)) && ypos >= y2-4)
3337 {
3338 int width = x2 - x1;
3339 int nout1 = (noutlet > 1 ? noutlet - 1 : 1);
3340 int closest = ((xpos-x1) * (nout1) + width/2)/width;
3341 int hotspot = x1 +
3342 (width - IOWIDTH) * closest / (nout1);
3343 if (closest < noutlet &&
3344 xpos >= (hotspot-1) && xpos <= hotspot + (IOWIDTH+1))
3345 {
3346 if (doit)
3347 {
3348 int issignal = obj_issignaloutlet(ob, closest);
3349 x->gl_editor->e_onmotion = MA_CONNECT;
3350 x->gl_editor->e_xwas = xpos;
3351 x->gl_editor->e_ywas = ypos;
3352 sys_vgui(
3353 ".x%x.c create line %d %d %d %d -width %d -tags x\n",
3354 x, xpos, ypos, xpos, ypos,
3355 (issignal ? 2 : 1));
3356 }
3357 else canvas_setcursor(x, CURSOR_EDITMODE_CONNECT);
3358 }
3359 else if (doit)
3360 goto nooutletafterall;
3361 }
3362 /* not in an outlet; select and move */
3363 else if (doit)
3364 {
3365 t_rtext *rt;
3366 /* check if the box is being text edited */
3367 nooutletafterall:
3368 if (ob && (rt = x->gl_editor->e_textedfor) &&
3369 rt == glist_findrtext(x, ob))
3370 {
3371 rtext_mouse(rt, xpos - x1, ypos - y1, RTEXT_DOWN);
3372 x->gl_editor->e_onmotion = MA_DRAGTEXT;
3373 x->gl_editor->e_xwas = x1;
3374 x->gl_editor->e_ywas = y1;
3375 }
3376 else
3377 {
3378 /* otherwise select and drag to displace */
3379 if (!glist_isselected(x, y))
3380 {
3381 glist_noselect(x);
3382 glist_select(x, y);
3383 }
3384 x->gl_editor->e_onmotion = MA_MOVE;
3385 }
3386 }
3387 else canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
3388 }
3389 return;
3390 }
3391 /* if right click doesn't hit any boxes, call rightclick
3392 routine anyway */
3393 if (rightclick)
3394 canvas_rightclick(x, xpos, ypos, 0);
3395
3396 /* if not an editing action, and if we didn't hit a
3397 box, set cursor and return */
3398 if (runmode || rightclick)
3399 {
3400 canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
3401 return;
3402 }
3403 /* having failed to find a box, we try lines now. */
3404 if (!runmode && !altmod && !shiftmod)
3405 {
3406 t_linetraverser t;
3407 t_outconnect *oc;
3408 float fx = xpos, fy = ypos;
3409 t_glist *glist2 = glist_getcanvas(x);
3410 linetraverser_start(&t, glist2);
3411 while (oc = linetraverser_next(&t))
3412 {
3413 float lx1 = t.tr_lx1, ly1 = t.tr_ly1,
3414 lx2 = t.tr_lx2, ly2 = t.tr_ly2;
3415 float area = (lx2 - lx1) * (fy - ly1) -
3416 (ly2 - ly1) * (fx - lx1);
3417 float dsquare = (lx2-lx1) * (lx2-lx1) + (ly2-ly1) * (ly2-ly1);
3418 if (area * area >= 50 * dsquare) continue;
3419 if ((lx2-lx1) * (fx-lx1) + (ly2-ly1) * (fy-ly1) < 0) continue;
3420 if ((lx2-lx1) * (lx2-fx) + (ly2-ly1) * (ly2-fy) < 0) continue;
3421 if (doit)
3422 {
3423 glist_selectline(glist2, oc,
3424 canvas_getindex(glist2, &t.tr_ob->ob_g), t.tr_outno,
3425 canvas_getindex(glist2, &t.tr_ob2->ob_g), t.tr_inno);
3426 }
3427 canvas_setcursor(x, CURSOR_EDITMODE_DISCONNECT);
3428 return;
3429 }
3430 }
3431 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
3432 if (doit)
3433 {
3434 if (!shiftmod) glist_noselect(x);
3435 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags x\n",
3436 x, xpos, ypos, xpos, ypos);
3437 x->gl_editor->e_xwas = xpos;
3438 x->gl_editor->e_ywas = ypos;
3439 x->gl_editor->e_onmotion = MA_REGION;
3440 }
3441}
3442
3443void canvas_mousedown(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
3444 t_floatarg which, t_floatarg mod)
3445{
3446 canvas_doclick(x, xpos, ypos, which, mod, 1);
3447}
3448
3449int canvas_isconnected (t_canvas *x, t_text *ob1, int n1,
3450 t_text *ob2, int n2)
3451{
3452 t_linetraverser t;
3453 t_outconnect *oc;
3454 linetraverser_start(&t, x);
3455 while (oc = linetraverser_next(&t))
3456 if (t.tr_ob == ob1 && t.tr_outno == n1 &&
3457 t.tr_ob2 == ob2 && t.tr_inno == n2)
3458 return (1);
3459 return (0);
3460}
3461
3462void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
3463{
3464 int x11, y11, x12, y12;
3465 t_gobj *y1;
3466 int x21, y21, x22, y22;
3467 t_gobj *y2;
3468 int xwas = x->gl_editor->e_xwas,
3469 ywas = x->gl_editor->e_ywas;
3470 if (doit) sys_vgui(".x%x.c delete x\n", x);
3471 else sys_vgui(".x%x.c coords x %d %d %d %d\n",
3472 x, x->gl_editor->e_xwas,
3473 x->gl_editor->e_ywas, xpos, ypos);
3474
3475 if ((y1 = canvas_findhitbox(x, xwas, ywas, &x11, &y11, &x12, &y12))
3476 && (y2 = canvas_findhitbox(x, xpos, ypos, &x21, &y21, &x22, &y22)))
3477 {
3478 t_object *ob1 = pd_checkobject(&y1->g_pd);
3479 t_object *ob2 = pd_checkobject(&y2->g_pd);
3480 int noutlet1, ninlet2;
3481 if (ob1 && ob2 && ob1 != ob2 &&
3482 (noutlet1 = obj_noutlets(ob1))
3483 && (ninlet2 = obj_ninlets(ob2)))
3484 {
3485 int width1 = x12 - x11, closest1, hotspot1;
3486 int width2 = x22 - x21, closest2, hotspot2;
3487 int lx1, lx2, ly1, ly2;
3488 t_outconnect *oc;
3489
3490 if (noutlet1 > 1)
3491 {
3492 closest1 = ((xwas-x11) * (noutlet1-1) + width1/2)/width1;
3493 hotspot1 = x11 +
3494 (width1 - IOWIDTH) * closest1 / (noutlet1-1);
3495 }
3496 else closest1 = 0, hotspot1 = x11;
3497
3498 if (ninlet2 > 1)
3499 {
3500 closest2 = ((xpos-x21) * (ninlet2-1) + width2/2)/width2;
3501 hotspot2 = x21 +
3502 (width2 - IOWIDTH) * closest2 / (ninlet2-1);
3503 }
3504 else closest2 = 0, hotspot2 = x21;
3505
3506 if (closest1 >= noutlet1)
3507 closest1 = noutlet1 - 1;
3508 if (closest2 >= ninlet2)
3509 closest2 = ninlet2 - 1;
3510
3511 if (canvas_isconnected (x, ob1, closest1, ob2, closest2))
3512 {
3513 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
3514 return;
3515 }
3516 if (obj_issignaloutlet(ob1, closest1) &&
3517 !obj_issignalinlet(ob2, closest2))
3518 {
3519 if (doit)
3520 error("can't connect signal outlet to control inlet");
3521 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
3522 return;
3523 }
3524 if (doit)
3525 {
3526 oc = obj_connect(ob1, closest1, ob2, closest2);
3527 lx1 = x11 + (noutlet1 > 1 ?
3528 ((x12-x11-IOWIDTH) * closest1)/(noutlet1-1) : 0)
3529 + IOMIDDLE;
3530 ly1 = y12;
3531 lx2 = x21 + (ninlet2 > 1 ?
3532 ((x22-x21-IOWIDTH) * closest2)/(ninlet2-1) : 0)
3533 + IOMIDDLE;
3534 ly2 = y21;
3535 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
3536 glist_getcanvas(x),
3537 lx1, ly1, lx2, ly2,
3538 (obj_issignaloutlet(ob1, closest1) ? 2 : 1), oc);
3539 canvas_setundo(x, canvas_undo_connect,
3540 canvas_undo_set_connect(x,
3541 canvas_getindex(x, &ob1->ob_g), closest1,
3542 canvas_getindex(x, &ob2->ob_g), closest2),
3543 "connect");
3544 }
3545 else canvas_setcursor(x, CURSOR_EDITMODE_CONNECT);
3546 return;
3547 }
3548 }
3549 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
3550}
3551
3552void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy)
3553{
3554 t_gobj *y;
3555 for (y = x->gl_list; y; y = y->g_next)
3556 {
3557 int x1, y1, x2, y2;
3558 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
3559 if (hix >= x1 && lox <= x2 && hiy >= y1 && loy <= y2
3560 && !glist_isselected(x, y))
3561 glist_select(x, y);
3562 }
3563}
3564
3565static void canvas_doregion(t_canvas *x, int xpos, int ypos, int doit)
3566{
3567 if (doit)
3568 {
3569 int lox, loy, hix, hiy;
3570 if (x->gl_editor->e_xwas < xpos)
3571 lox = x->gl_editor->e_xwas, hix = xpos;
3572 else hix = x->gl_editor->e_xwas, lox = xpos;
3573 if (x->gl_editor->e_ywas < ypos)
3574 loy = x->gl_editor->e_ywas, hiy = ypos;
3575 else hiy = x->gl_editor->e_ywas, loy = ypos;
3576 canvas_selectinrect(x, lox, loy, hix, hiy);
3577 sys_vgui(".x%x.c delete x\n", x);
3578 x->gl_editor->e_onmotion = 0;
3579 }
3580 else sys_vgui(".x%x.c coords x %d %d %d %d\n",
3581 x, x->gl_editor->e_xwas,
3582 x->gl_editor->e_ywas, xpos, ypos);
3583}
3584
3585void canvas_mouseup(t_canvas *x,
3586 t_floatarg fxpos, t_floatarg fypos, t_floatarg fwhich)
3587{
3588 t_gobj *y;
3589
3590 int xpos = fxpos, ypos = fypos, which = fwhich;
3591
3592 if (!x->gl_editor)
3593 {
3594 bug("editor");
3595 return;
3596 }
3597
3598#ifdef SIMULATERIGHTCLICK
3599 canvas_upclicktime = sys_getrealtime();
3600 canvas_upx = xpos;
3601 canvas_upy = ypos;
3602#endif
3603
3604 if (x->gl_editor->e_onmotion == MA_CONNECT)
3605 canvas_doconnect(x, xpos, ypos, which, 1);
3606 else if (x->gl_editor->e_onmotion == MA_REGION)
3607 canvas_doregion(x, xpos, ypos, 1);
3608 else if (x->gl_editor->e_onmotion == MA_MOVE)
3609 {
3610 /* after motion, if there's only one item selected, activate it */
3611 if (x->gl_editor->e_selection &&
3612 !(x->gl_editor->e_selection->sel_next))
3613 gobj_activate(x->gl_editor->e_selection->sel_what,
3614 x, 1);
3615 }
3616 else if (x->gl_editor->e_onmotion == MA_PASSOUT)
3617 x->gl_editor->e_onmotion = 0;
3618 x->gl_editor->e_onmotion = MA_NONE;
3619
3620
3621#if 1
3622 /* GG misused the (unused) dbl parameter to tell if mouseup */
3623
3624 for (y = x->gl_list; y; y = y->g_next) {
3625 int x1, y1, x2, y2, clickreturned = 0;
3626
3627 /* check if the object wants to be clicked */
3628 if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2)
3629 && (clickreturned = gobj_click(y, x, xpos, ypos,
3630 0, 0, 1, 0)))
3631 break;
3632 }
3633#endif
3634
3635
3636}
3637
3638 /* displace the selection by (dx, dy) pixels */
3639static void canvas_displaceselection(t_canvas *x, int dx, int dy)
3640{
3641 t_selection *y;
3642 int resortin = 0, resortout = 0;
3643 if (!canvas_undo_already_set_move)
3644 {
3645 canvas_setundo(x, canvas_undo_move, canvas_undo_set_move(x, 1),
3646 "motion");
3647 canvas_undo_already_set_move = 1;
3648 }
3649 for (y = x->gl_editor->e_selection; y; y = y->sel_next)
3650 {
3651 t_class *cl = pd_class(&y->sel_what->g_pd);
3652 gobj_displace(y->sel_what, x, dx, dy);
3653 if (cl == vinlet_class) resortin = 1;
3654 else if (cl == voutlet_class) resortout = 1;
3655 }
3656 if (resortin) canvas_resortinlets(x);
3657 if (resortout) canvas_resortoutlets(x);
3658 canvas_dirty(x, 1);
3659}
3660
3661 /* this routine is called whenever a key is pressed or released. "x"
3662 may be zero if there's no current canvas. The first argument is true or
3663 fals for down/up; the second one is either a symbolic key name (e.g.,
3664 "Right" or an Ascii key number. */
3665void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
3666{
3667 static t_symbol *keynumsym, *keyupsym, *keynamesym;
3668 int keynum, fflag;
3669 t_symbol *gotkeysym;
3670
3671 int down, shift;
3672
3673 if (ac < 3)
3674 return;
3675 if (!x->gl_editor)
3676 {
3677 bug("editor");
3678 return;
3679 }
3680 canvas_undo_already_set_move = 0;
3681 down = (atom_getfloat(av) != 0); /* nonzero if it's a key down */
3682 shift = (atom_getfloat(av+2) != 0); /* nonzero if shift-ed */
3683 if (av[1].a_type == A_SYMBOL)
3684 gotkeysym = av[1].a_w.w_symbol;
3685 else if (av[1].a_type == A_FLOAT)
3686 {
3687 char buf[3];
3688 sprintf(buf, "%c", (int)(av[1].a_w.w_float));
3689 gotkeysym = gensym(buf);
3690 }
3691 else gotkeysym = gensym("?");
3692 fflag = (av[0].a_type == A_FLOAT ? av[0].a_w.w_float : 0);
3693 keynum = (av[1].a_type == A_FLOAT ? av[1].a_w.w_float : 0);
3694 if (keynum == '\\' || keynum == '{' || keynum == '}')
3695 {
3696 post("%c: dropped", (int)keynum);
3697 return;
3698 }
3699 if (keynum == '\r') keynum = '\n';
3700 if (av[1].a_type == A_SYMBOL &&
3701 !strcmp(av[1].a_w.w_symbol->s_name, "Return"))
3702 keynum = '\n';
3703 if (!keynumsym)
3704 {
3705 keynumsym = gensym("#key");
3706 keyupsym = gensym("#keyup");
3707 keynamesym = gensym("#keyname");
3708 }
3709#ifdef MACOSX
3710 if (keynum == 30)
3711 keynum = 0, gotkeysym = gensym("Up");
3712 else if (keynum == 31)
3713 keynum = 0, gotkeysym = gensym("Down");
3714 else if (keynum == 28)
3715 keynum = 0, gotkeysym = gensym("Left");
3716 else if (keynum == 29)
3717 keynum = 0, gotkeysym = gensym("Right");
3718#endif
3719 if (keynumsym->s_thing && down)
3720 pd_float(keynumsym->s_thing, (float)keynum);
3721 if (keyupsym->s_thing && !down)
3722 pd_float(keyupsym->s_thing, (float)keynum);
3723 if (keynamesym->s_thing)
3724 {
3725 t_atom at[2];
3726 at[0] = av[0];
3727 SETFLOAT(at, down);
3728 SETSYMBOL(at+1, gotkeysym);
3729 pd_list(keynamesym->s_thing, 0, 2, at);
3730 }
3731 if (!x->gl_editor) /* if that 'invis'ed the window, we'd better stop. */
3732 return;
3733 if (x && down)
3734 {
3735 /* if an object has "grabbed" keys just send them on */
3736 if (x->gl_editor->e_grab
3737 && x->gl_editor->e_keyfn && keynum)
3738 (* x->gl_editor->e_keyfn)
3739 (x->gl_editor->e_grab, (float)keynum);
3740 /* if a text editor is open send it on */
3741 else if (x->gl_editor->e_textedfor)
3742 {
3743 if (!x->gl_editor->e_textdirty)
3744 {
3745 canvas_setundo(x, canvas_undo_cut,
3746 canvas_undo_set_cut(x, UCUT_TEXT), "typing");
3747 }
3748 rtext_key(x->gl_editor->e_textedfor,
3749 (int)keynum, gotkeysym);
3750 if (x->gl_editor->e_textdirty)
3751 canvas_dirty(x, 1);
3752 }
3753 /* check for backspace or clear */
3754 else if (keynum == 8 || keynum == 127)
3755 {
3756 if (x->gl_editor->e_selectedline)
3757 canvas_clearline(x);
3758 else if (x->gl_editor->e_selection)
3759 {
3760 canvas_setundo(x, canvas_undo_cut,
3761 canvas_undo_set_cut(x, UCUT_CLEAR), "clear");
3762 canvas_doclear(x);
3763 }
3764 }
3765 /* check for arrow keys */
3766 else if (!strcmp(gotkeysym->s_name, "Up"))
3767 canvas_displaceselection(x, 0, shift ? -10 : -1);
3768 else if (!strcmp(gotkeysym->s_name, "Down"))
3769 canvas_displaceselection(x, 0, shift ? 10 : 1);
3770 else if (!strcmp(gotkeysym->s_name, "Left"))
3771 canvas_displaceselection(x, shift ? -10 : -1, 0);
3772 else if (!strcmp(gotkeysym->s_name, "Right"))
3773 canvas_displaceselection(x, shift ? 10 : 1, 0);
3774 }
3775}
3776
3777void canvas_motion(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
3778 t_floatarg fmod)
3779{
3780 /* post("motion %d %d", xpos, ypos); */
3781 int mod = fmod;
3782 if (!x->gl_editor)
3783 {
3784 bug("editor");
3785 return;
3786 }
3787 glist_setlastxy(x, xpos, ypos);
3788 if (x->gl_editor->e_onmotion == MA_MOVE)
3789 {
3790 canvas_displaceselection(x,
3791 xpos - x->gl_editor->e_xwas, ypos - x->gl_editor->e_ywas);
3792 x->gl_editor->e_xwas = xpos;
3793 x->gl_editor->e_ywas = ypos;
3794 }
3795 else if (x->gl_editor->e_onmotion == MA_REGION)
3796 canvas_doregion(x, xpos, ypos, 0);
3797 else if (x->gl_editor->e_onmotion == MA_CONNECT)
3798 canvas_doconnect(x, xpos, ypos, 0, 0);
3799 else if (x->gl_editor->e_onmotion == MA_PASSOUT)
3800 {
3801 if (!x->gl_editor->e_motionfn)
3802 bug("e_motionfn");
3803 (*x->gl_editor->e_motionfn)(&x->gl_editor->e_grab->g_pd,
3804 xpos - x->gl_editor->e_xwas,
3805 ypos - x->gl_editor->e_ywas);
3806 x->gl_editor->e_xwas = xpos;
3807 x->gl_editor->e_ywas = ypos;
3808 }
3809 else if (x->gl_editor->e_onmotion == MA_DRAGTEXT)
3810 {
3811 t_rtext *rt = x->gl_editor->e_textedfor;
3812 if (rt)
3813 rtext_mouse(rt, xpos - x->gl_editor->e_xwas,
3814 ypos - x->gl_editor->e_ywas, RTEXT_DRAG);
3815 }
3816 else canvas_doclick(x, xpos, ypos, 0, mod, 0);
3817
3818 x->gl_editor->e_lastmoved = 1;
3819}
3820
3821void canvas_startmotion(t_canvas *x)
3822{
3823 int xval, yval;
3824 if (!x->gl_editor) return;
3825 glist_getnextxy(x, &xval, &yval);
3826 if (xval == 0 && yval == 0) return;
3827 x->gl_editor->e_onmotion = MA_MOVE;
3828 x->gl_editor->e_xwas = xval;
3829 x->gl_editor->e_ywas = yval;
3830}
3831
3832/* ----------------------------- window stuff ----------------------- */
3833
3834void canvas_print(t_canvas *x, t_symbol *s)
3835{
3836 if (*s->s_name) sys_vgui(".x%x.c postscript -file %s\n", x, s->s_name);
3837 else sys_vgui(".x%x.c postscript -file x.ps\n", x);
3838}
3839
3840void canvas_menuclose(t_canvas *x, t_floatarg force)
3841{
3842 if (x->gl_owner)
3843 canvas_vis(x, 0);
3844 else if ((force != 0) || (!x->gl_dirty))
3845 pd_free(&x->gl_pd);
3846 else sys_vgui("pdtk_check {This window has been modified. Close anyway?}\
3847 {.x%x menuclose 1;\n}\n", x);
3848}
3849
3850 /* put up a dialog which may call canvas_font back to do the work */
3851static void canvas_menufont(t_canvas *x)
3852{
3853 char buf[80];
3854 t_canvas *x2 = canvas_getrootfor(x);
3855 gfxstub_deleteforkey(x2);
3856 sprintf(buf, "pdtk_canvas_dofont %%s %d\n", x2->gl_font);
3857 gfxstub_new(&x2->gl_pd, &x2->gl_pd, buf);
3858}
3859
3860static int canvas_find_index1, canvas_find_index2;
3861static t_binbuf *canvas_findbuf;
3862int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf);
3863
3864 /* find an atom or string of atoms */
3865static int canvas_dofind(t_canvas *x, int *myindex1p)
3866{
3867 t_gobj *y;
3868 int myindex1 = *myindex1p, myindex2;
3869 if (myindex1 >= canvas_find_index1)
3870 {
3871 for (y = x->gl_list, myindex2 = 0; y;
3872 y = y->g_next, myindex2++)
3873 {
3874 t_object *ob = 0;
3875 if (ob = pd_checkobject(&y->g_pd))
3876 {
3877 if (binbuf_match(ob->ob_binbuf, canvas_findbuf))
3878 {
3879 if (myindex1 > canvas_find_index1 ||
3880 myindex1 == canvas_find_index1 &&
3881 myindex2 > canvas_find_index2)
3882 {
3883 canvas_find_index1 = myindex1;
3884 canvas_find_index2 = myindex2;
3885 glist_noselect(x);
3886 canvas_vis(x, 1);
3887 canvas_editmode(x, 1.);
3888 glist_select(x, y);
3889 return (1);
3890 }
3891 }
3892 }
3893 }
3894 }
3895 for (y = x->gl_list, myindex2 = 0; y; y = y->g_next, myindex2++)
3896 {
3897 if (pd_class(&y->g_pd) == canvas_class)
3898 {
3899 (*myindex1p)++;
3900 if (canvas_dofind((t_canvas *)y, myindex1p))
3901 return (1);
3902 }
3903 }
3904 return (0);
3905}
3906
3907static void canvas_find(t_canvas *x, t_symbol *s, int ac, t_atom *av)
3908{
3909 int myindex1 = 0, i;
3910 for (i = 0; i < ac; i++)
3911 {
3912 if (av[i].a_type == A_SYMBOL)
3913 {
3914 if (!strcmp(av[i].a_w.w_symbol->s_name, "_semi_"))
3915 SETSEMI(&av[i]);
3916 else if (!strcmp(av[i].a_w.w_symbol->s_name, "_comma_"))
3917 SETCOMMA(&av[i]);
3918 }
3919 }
3920 if (!canvas_findbuf)
3921 canvas_findbuf = binbuf_new();
3922 binbuf_clear(canvas_findbuf);
3923 binbuf_add(canvas_findbuf, ac, av);
3924 canvas_find_index1 = 0;
3925 canvas_find_index2 = -1;
3926 canvas_whichfind = x;
3927 if (!canvas_dofind(x, &myindex1))
3928 {
3929 binbuf_print(canvas_findbuf);
3930 post("... couldn't find");
3931 }
3932}
3933
3934static void canvas_find_again(t_canvas *x)
3935{
3936 int myindex1 = 0;
3937 if (!canvas_findbuf || !canvas_whichfind)
3938 return;
3939 if (!canvas_dofind(canvas_whichfind, &myindex1))
3940 {
3941 binbuf_print(canvas_findbuf);
3942 post("... couldn't find");
3943 }
3944}
3945
3946static void canvas_find_parent(t_canvas *x)
3947{
3948 if (x->gl_owner)
3949 canvas_vis(glist_getcanvas(x->gl_owner), 1);
3950}
3951
3952static int glist_dofinderror(t_glist *gl, void *error_object)
3953{
3954 t_gobj *g;
3955 for (g = gl->gl_list; g; g = g->g_next)
3956 {
3957 if ((void *)g == error_object)
3958 {
3959 /* got it... now show it. */
3960 glist_noselect(gl);
3961 canvas_vis(glist_getcanvas(gl), 1);
3962 canvas_editmode(glist_getcanvas(gl), 1.);
3963 glist_select(gl, g);
3964 return (1);
3965 }
3966 else if (g->g_pd == canvas_class)
3967 {
3968 if (glist_dofinderror((t_canvas *)g, error_object))
3969 return (1);
3970 }
3971 }
3972 return (0);
3973}
3974
3975void canvas_finderror(void *error_object)
3976{
3977 t_canvas *x;
3978 /* find all root canvases */
3979 for (x = canvas_list; x; x = x->gl_next)
3980 {
3981 if (glist_dofinderror(x, error_object))
3982 return;
3983 }
3984 post("... sorry, I couldn't find the source of that error.");
3985}
3986
3987void canvas_stowconnections(t_canvas *x)
3988{
3989 t_gobj *selhead = 0, *seltail = 0, *nonhead = 0, *nontail = 0, *y, *y2;
3990 t_linetraverser t;
3991 t_outconnect *oc;
3992 if (!x->gl_editor) return;
3993 /* split list to "selected" and "unselected" parts */
3994 for (y = x->gl_list; y; y = y2)
3995 {
3996 y2 = y->g_next;
3997 if (glist_isselected(x, y))
3998 {
3999 if (seltail)
4000 {
4001 seltail->g_next = y;
4002 seltail = y;
4003 y->g_next = 0;
4004 }
4005 else
4006 {
4007 selhead = seltail = y;
4008 seltail->g_next = 0;
4009 }
4010 }
4011 else
4012 {
4013 if (nontail)
4014 {
4015 nontail->g_next = y;
4016 nontail = y;
4017 y->g_next = 0;
4018 }
4019 else
4020 {
4021 nonhead = nontail = y;
4022 nontail->g_next = 0;
4023 }
4024 }
4025 }
4026 /* move the selected part to the end */
4027 if (!nonhead) x->gl_list = selhead;
4028 else x->gl_list = nonhead, nontail->g_next = selhead;
4029
4030 /* add connections to binbuf */
4031 binbuf_clear(x->gl_editor->e_connectbuf);
4032 linetraverser_start(&t, x);
4033 while (oc = linetraverser_next(&t))
4034 {
4035 int s1 = glist_isselected(x, &t.tr_ob->ob_g);
4036 int s2 = glist_isselected(x, &t.tr_ob2->ob_g);
4037 if (s1 != s2)
4038 binbuf_addv(x->gl_editor->e_connectbuf, "ssiiii;",
4039 gensym("#X"), gensym("connect"),
4040 glist_getindex(x, &t.tr_ob->ob_g), t.tr_outno,
4041 glist_getindex(x, &t.tr_ob2->ob_g), t.tr_inno);
4042 }
4043}
4044
4045void canvas_restoreconnections(t_canvas *x)
4046{
4047 pd_bind(&x->gl_pd, gensym("#X"));
4048 binbuf_eval(x->gl_editor->e_connectbuf, 0, 0, 0);
4049 pd_unbind(&x->gl_pd, gensym("#X"));
4050}
4051
4052static t_binbuf *canvas_docopy(t_canvas *x)
4053{
4054 t_gobj *y;
4055 t_linetraverser t;
4056 t_outconnect *oc;
4057 t_binbuf *b = binbuf_new();
4058 for (y = x->gl_list; y; y = y->g_next)
4059 {
4060 if (glist_isselected(x, y))
4061 gobj_save(y, b);
4062 }
4063 linetraverser_start(&t, x);
4064 while (oc = linetraverser_next(&t))
4065 {
4066 if (glist_isselected(x, &t.tr_ob->ob_g)
4067 && glist_isselected(x, &t.tr_ob2->ob_g))
4068 {
4069 binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"),
4070 glist_selectionindex(x, &t.tr_ob->ob_g, 1), t.tr_outno,
4071 glist_selectionindex(x, &t.tr_ob2->ob_g, 1), t.tr_inno);
4072 }
4073 }
4074 return (b);
4075}
4076
4077static void canvas_copy(t_canvas *x)
4078{
4079 if (!x->gl_editor || !x->gl_editor->e_selection)
4080 return;
4081 binbuf_free(copy_binbuf);
4082 copy_binbuf = canvas_docopy(x);
4083}
4084
4085static void canvas_clearline(t_canvas *x)
4086{
4087 if (x->gl_editor->e_selectedline)
4088 {
4089 canvas_disconnect(x, x->gl_editor->e_selectline_index1,
4090 x->gl_editor->e_selectline_outno,
4091 x->gl_editor->e_selectline_index2,
4092 x->gl_editor->e_selectline_inno);
4093 canvas_setundo(x, canvas_undo_disconnect,
4094 canvas_undo_set_disconnect(x,
4095 x->gl_editor->e_selectline_index1,
4096 x->gl_editor->e_selectline_outno,
4097 x->gl_editor->e_selectline_index2,
4098 x->gl_editor->e_selectline_inno),
4099 "disconnect");
4100 }
4101}
4102
4103extern t_pd *newest;
4104static void canvas_doclear(t_canvas *x)
4105{
4106 t_gobj *y, *y2;
4107 int dspstate;
4108
4109 dspstate = canvas_suspend_dsp();
4110 if (x->gl_editor->e_selectedline)
4111 {
4112 canvas_disconnect(x, x->gl_editor->e_selectline_index1,
4113 x->gl_editor->e_selectline_outno,
4114 x->gl_editor->e_selectline_index2,
4115 x->gl_editor->e_selectline_inno);
4116 canvas_setundo(x, canvas_undo_disconnect,
4117 canvas_undo_set_disconnect(x,
4118 x->gl_editor->e_selectline_index1,
4119 x->gl_editor->e_selectline_outno,
4120 x->gl_editor->e_selectline_index2,
4121 x->gl_editor->e_selectline_inno),
4122 "disconnect");
4123 }
4124 /* if text is selected, deselecting it might remake the
4125 object. So we deselect it and hunt for a "new" object on
4126 the glist to reselect. */
4127 if (x->gl_editor->e_textedfor)
4128 {
4129 newest = 0;
4130 glist_noselect(x);
4131 if (newest)
4132 {
4133 for (y = x->gl_list; y; y = y->g_next)
4134 if (&y->g_pd == newest) glist_select(x, y);
4135 }
4136 }
4137 while (1) /* this is pretty wierd... should rewrite it */
4138 {
4139 for (y = x->gl_list; y; y = y2)
4140 {
4141 y2 = y->g_next;
4142 if (glist_isselected(x, y))
4143 {
4144 glist_delete(x, y);
4145#if 0
4146 if (y2) post("cut 5 %x %x", y2, y2->g_next);
4147 else post("cut 6");
4148#endif
4149 goto next;
4150 }
4151 }
4152 goto restore;
4153 next: ;
4154 }
4155restore:
4156 canvas_resume_dsp(dspstate);
4157 canvas_dirty(x, 1);
4158}
4159
4160static void canvas_cut(t_canvas *x)
4161{
4162 if (x->gl_editor && x->gl_editor->e_selectedline)
4163 canvas_clearline(x);
4164 else if (x->gl_editor && x->gl_editor->e_selection)
4165 {
4166 canvas_setundo(x, canvas_undo_cut,
4167 canvas_undo_set_cut(x, UCUT_CUT), "cut");
4168 canvas_copy(x);
4169 canvas_doclear(x);
4170 }
4171}
4172
4173static int paste_onset;
4174static t_canvas *paste_canvas;
4175
4176static void glist_donewloadbangs(t_glist *x)
4177{
4178 if (x->gl_editor)
4179 {
4180 t_selection *sel;
4181 for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
4182 if (pd_class(&sel->sel_what->g_pd) == canvas_class)
4183 canvas_loadbang((t_canvas *)(&sel->sel_what->g_pd));
4184 }
4185}
4186
4187static void canvas_dopaste(t_canvas *x, t_binbuf *b)
4188{
4189 t_gobj *newgobj, *last, *g2;
4190 int dspstate = canvas_suspend_dsp(), nbox, count;
4191
4192 canvas_editmode(x, 1.);
4193 glist_noselect(x);
4194 for (g2 = x->gl_list, nbox = 0; g2; g2 = g2->g_next) nbox++;
4195
4196 paste_onset = nbox;
4197 paste_canvas = x;
4198
4199 pd_bind(&x->gl_pd, gensym("#X"));
4200 binbuf_eval(b, 0, 0, 0);
4201 pd_unbind(&x->gl_pd, gensym("#X"));
4202 for (g2 = x->gl_list, count = 0; g2; g2 = g2->g_next, count++)
4203 if (count >= nbox)
4204 glist_select(x, g2);
4205 paste_canvas = 0;
4206 canvas_resume_dsp(dspstate);
4207 canvas_dirty(x, 1);
4208 glist_donewloadbangs(x);
4209}
4210
4211static void canvas_paste(t_canvas *x)
4212{
4213 canvas_setundo(x, canvas_undo_paste, canvas_undo_set_paste(x), "paste");
4214 canvas_dopaste(x, copy_binbuf);
4215}
4216
4217static void canvas_duplicate(t_canvas *x)
4218{
4219 if (x->gl_editor->e_onmotion == MA_NONE)
4220 {
4221 t_selection *y;
4222 canvas_copy(x);
4223 canvas_setundo(x, canvas_undo_paste, canvas_undo_set_paste(x),
4224 "duplicate");
4225 canvas_dopaste(x, copy_binbuf);
4226 for (y = x->gl_editor->e_selection; y; y = y->sel_next)
4227 gobj_displace(y->sel_what, x,
4228 10, 10);
4229 canvas_dirty(x, 1);
4230 }
4231}
4232
4233static void canvas_selectall(t_canvas *x)
4234{
4235 t_gobj *y;
4236 if (!x->gl_edit)
4237 canvas_editmode(x, 1);
4238 for (y = x->gl_list; y; y = y->g_next)
4239 {
4240 if (!glist_isselected(x, y))
4241 glist_select(x, y);
4242 }
4243}
4244
4245void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
4246 t_floatarg fwhoin, t_floatarg finno)
4247{
4248 int whoout = fwhoout, outno = foutno, whoin = fwhoin, inno = finno;
4249 t_gobj *src = 0, *sink = 0;
4250 t_object *objsrc, *objsink;
4251 t_outconnect *oc;
4252 int nin = whoin, nout = whoout;
4253 if (paste_canvas == x) whoout += paste_onset, whoin += paste_onset;
4254 for (src = x->gl_list; whoout; src = src->g_next, whoout--)
4255 if (!src->g_next) goto bad; /* bug fix thanks to Hannes */
4256 for (sink = x->gl_list; whoin; sink = sink->g_next, whoin--)
4257 if (!sink->g_next) goto bad;
4258 if (!(objsrc = pd_checkobject(&src->g_pd)) ||
4259 !(objsink = pd_checkobject(&sink->g_pd)))
4260 goto bad;
4261 if (!(oc = obj_connect(objsrc, outno, objsink, inno))) goto bad;
4262 if (glist_isvisible(x))
4263 {
4264 sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
4265 glist_getcanvas(x), 0, 0, 0, 0,
4266 (obj_issignaloutlet(objsrc, outno) ? 2 : 1),oc);
4267 canvas_fixlinesfor(x, objsrc);
4268 }
4269 return;
4270
4271bad:
4272 post("%s %d %d %d %d (%s->%s) connection failed",
4273 x->gl_name->s_name, nout, outno, nin, inno,
4274 (src? class_getname(pd_class(&src->g_pd)) : "???"),
4275 (sink? class_getname(pd_class(&sink->g_pd)) : "???"));
4276}
4277
4278#define XTOLERANCE 4
4279#define YTOLERANCE 3
4280#define NHIST 15
4281
4282 /* LATER might have to speed this up */
4283static void canvas_tidy(t_canvas *x)
4284{
4285 t_gobj *y, *y2, *y3;
4286 int ax1, ay1, ax2, ay2, bx1, by1, bx2, by2;
4287 int histogram[NHIST], *ip, i, besthist, bestdist;
4288 /* if nobody is selected, this means do it to all boxes;
4289 othewise just the selection */
4290 int all = (x->gl_editor ? (x->gl_editor->e_selection == 0) : 1);
4291
4292 canvas_setundo(x, canvas_undo_move, canvas_undo_set_move(x, !all),
4293 "motion");
4294
4295 /* tidy horizontally */
4296 for (y = x->gl_list; y; y = y->g_next)
4297 if (all || glist_isselected(x, y))
4298 {
4299 gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
4300
4301 for (y2 = x->gl_list; y2; y2 = y2->g_next)
4302 if (all || glist_isselected(x, y2))
4303 {
4304 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
4305 if (by1 <= ay1 + YTOLERANCE && by1 >= ay1 - YTOLERANCE &&
4306 bx1 < ax1)
4307 goto nothorizhead;
4308 }
4309
4310 for (y2 = x->gl_list; y2; y2 = y2->g_next)
4311 if (all || glist_isselected(x, y2))
4312 {
4313 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
4314 if (by1 <= ay1 + YTOLERANCE && by1 >= ay1 - YTOLERANCE
4315 && by1 != ay1)
4316 gobj_displace(y2, x, 0, ay1-by1);
4317 }
4318 nothorizhead: ;
4319 }
4320 /* tidy vertically. First guess the user's favorite vertical spacing */
4321 for (i = NHIST, ip = histogram; i--; ip++) *ip = 0;
4322 for (y = x->gl_list; y; y = y->g_next)
4323 if (all || glist_isselected(x, y))
4324 {
4325 gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
4326 for (y2 = x->gl_list; y2; y2 = y2->g_next)
4327 if (all || glist_isselected(x, y2))
4328 {
4329 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
4330 if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE)
4331 {
4332 int distance = by1-ay2;
4333 if (distance >= 0 && distance < NHIST)
4334 histogram[distance]++;
4335 }
4336 }
4337 }
4338 for (i = 1, besthist = 0, bestdist = 4, ip = histogram + 1;
4339 i < (NHIST-1); i++, ip++)
4340 {
4341 int hit = ip[-1] + 2 * ip[0] + ip[1];
4342 if (hit > besthist)
4343 {
4344 besthist = hit;
4345 bestdist = i;
4346 }
4347 }
4348 post("best vertical distance %d", bestdist);
4349 for (y = x->gl_list; y; y = y->g_next)
4350 if (all || glist_isselected(x, y))
4351 {
4352 int keep = 1;
4353 gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
4354 for (y2 = x->gl_list; y2; y2 = y2->g_next)
4355 if (all || glist_isselected(x, y2))
4356 {
4357 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
4358 if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE &&
4359 ay1 >= by2 - 10 && ay1 < by2 + NHIST)
4360 goto nothead;
4361 }
4362 while (keep)
4363 {
4364 keep = 0;
4365 for (y2 = x->gl_list; y2; y2 = y2->g_next)
4366 if (all || glist_isselected(x, y2))
4367 {
4368 gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
4369 if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE &&
4370 by1 > ay1 && by1 < ay2 + NHIST)
4371 {
4372 int vmove = ay2 + bestdist - by1;
4373 gobj_displace(y2, x, ax1-bx1, vmove);
4374 ay1 = by1 + vmove;
4375 ay2 = by2 + vmove;
4376 keep = 1;
4377 break;
4378 }
4379 }
4380 }
4381 nothead: ;
4382 }
4383 canvas_dirty(x, 1);
4384}
4385
4386static void canvas_texteditor(t_canvas *x)
4387{
4388 t_rtext *foo;
4389 char *buf;
4390 int bufsize;
4391 if (foo = x->gl_editor->e_textedfor)
4392 rtext_gettext(foo, &buf, &bufsize);
4393 else buf = "", bufsize = 0;
4394 sys_vgui("pdtk_pd_texteditor {%.*s}\n", bufsize, buf);
4395
4396}
4397
4398void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av)
4399{
4400 /* canvas_editing can be zero; canvas_key checks for that */
4401 canvas_key(canvas_editing, s, ac, av);
4402}
4403
4404void canvas_editmode(t_canvas *x, t_floatarg fyesplease)
4405{
4406 int yesplease = fyesplease;
4407 if (yesplease && x->gl_edit)
4408 return;
4409 x->gl_edit = !x->gl_edit;
4410 if (x->gl_edit && glist_isvisible(x) && glist_istoplevel(x))
4411 canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
4412 else
4413 {
4414 glist_noselect(x);
4415 if (glist_isvisible(x) && glist_istoplevel(x))
4416 canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
4417 }
4418 sys_vgui("pdtk_canvas_editval .x%x %d\n",
4419 glist_getcanvas(x), x->gl_edit);
4420}
4421
4422 /* called by canvas_font below */
4423static void canvas_dofont(t_canvas *x, t_floatarg font, t_floatarg xresize,
4424 t_floatarg yresize)
4425{
4426 t_gobj *y;
4427 x->gl_font = font;
4428 if (xresize != 1 || yresize != 1)
4429 {
4430 canvas_setundo(x, canvas_undo_move, canvas_undo_set_move(x, 0),
4431 "motion");
4432 for (y = x->gl_list; y; y = y->g_next)
4433 {
4434 int x1, x2, y1, y2, nx1, ny1;
4435 gobj_getrect(y, x, &x1, &y1, &x2, &y2);
4436 nx1 = x1 * xresize + 0.5;
4437 ny1 = y1 * yresize + 0.5;
4438 gobj_displace(y, x, nx1-x1, ny1-y1);
4439 }
4440 }
4441 if (glist_isvisible(x))
4442 glist_redraw(x);
4443 for (y = x->gl_list; y; y = y->g_next)
4444 if (pd_class(&y->g_pd) == canvas_class
4445 && !canvas_isabstraction((t_canvas *)y))
4446 canvas_dofont((t_canvas *)y, font, xresize, yresize);
4447}
4448
4449 /* canvas_menufont calls up a TK dialog which calls this back */
4450static void canvas_font(t_canvas *x, t_floatarg font, t_floatarg resize,
4451 t_floatarg whichresize)
4452{
4453 float realresize, realresx = 1, realresy = 1;
4454 t_canvas *x2 = canvas_getrootfor(x);
4455 if (!resize) realresize = 1;
4456 else
4457 {
4458 if (resize < 20) resize = 20;
4459 if (resize > 500) resize = 500;
4460 realresize = resize * 0.01;
4461 }
4462 if (whichresize != 3) realresx = realresize;
4463 if (whichresize != 2) realresy = realresize;
4464 canvas_dofont(x2, font, realresx, realresy);
4465 sys_defaultfont = font;
4466}
4467
4468static t_glist *canvas_last_glist;
4469static int canvas_last_glist_x, canvas_last_glist_y;
4470
4471void glist_getnextxy(t_glist *gl, int *xpix, int *ypix)
4472{
4473 if (canvas_last_glist == gl)
4474 *xpix = canvas_last_glist_x, *ypix = canvas_last_glist_y;
4475 else *xpix = *ypix = 40;
4476}
4477
4478static void glist_setlastxy(t_glist *gl, int xval, int yval)
4479{
4480 canvas_last_glist = gl;
4481 canvas_last_glist_x = xval;
4482 canvas_last_glist_y = yval;
4483}
4484
4485
4486void g_editor_setup(void)
4487{
4488/* ------------------------ events ---------------------------------- */
4489 class_addmethod(canvas_class, (t_method)canvas_mousedown, gensym("mouse"),
4490 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4491 class_addmethod(canvas_class, (t_method)canvas_mouseup, gensym("mouseup"),
4492 A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4493 class_addmethod(canvas_class, (t_method)canvas_key, gensym("key"),
4494 A_GIMME, A_NULL);
4495 class_addmethod(canvas_class, (t_method)canvas_motion, gensym("motion"),
4496 A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4497
4498/* ------------------------ menu actions ---------------------------- */
4499 class_addmethod(canvas_class, (t_method)canvas_menuclose,
4500 gensym("menuclose"), A_DEFFLOAT, 0);
4501 class_addmethod(canvas_class, (t_method)canvas_cut,
4502 gensym("cut"), A_NULL);
4503 class_addmethod(canvas_class, (t_method)canvas_copy,
4504 gensym("copy"), A_NULL);
4505 class_addmethod(canvas_class, (t_method)canvas_paste,
4506 gensym("paste"), A_NULL);
4507 class_addmethod(canvas_class, (t_method)canvas_duplicate,
4508 gensym("duplicate"), A_NULL);
4509 class_addmethod(canvas_class, (t_method)canvas_selectall,
4510 gensym("selectall"), A_NULL);
4511 class_addmethod(canvas_class, (t_method)canvas_undo,
4512 gensym("undo"), A_NULL);
4513 class_addmethod(canvas_class, (t_method)canvas_redo,
4514 gensym("redo"), A_NULL);
4515 class_addmethod(canvas_class, (t_method)canvas_tidy,
4516 gensym("tidy"), A_NULL);
4517 class_addmethod(canvas_class, (t_method)canvas_texteditor,
4518 gensym("texteditor"), A_NULL);
4519 class_addmethod(canvas_class, (t_method)canvas_editmode,
4520 gensym("editmode"), A_DEFFLOAT, A_NULL);
4521 class_addmethod(canvas_class, (t_method)canvas_print,
4522 gensym("print"), A_SYMBOL, A_NULL);
4523 class_addmethod(canvas_class, (t_method)canvas_menufont,
4524 gensym("menufont"), A_NULL);
4525 class_addmethod(canvas_class, (t_method)canvas_font,
4526 gensym("font"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4527 class_addmethod(canvas_class, (t_method)canvas_find,
4528 gensym("find"), A_GIMME, A_NULL);
4529 class_addmethod(canvas_class, (t_method)canvas_find_again,
4530 gensym("findagain"), A_NULL);
4531 class_addmethod(canvas_class, (t_method)canvas_find_parent,
4532 gensym("findparent"), A_NULL);
4533 class_addmethod(canvas_class, (t_method)canvas_done_popup,
4534 gensym("done-popup"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4535 class_addmethod(canvas_class, (t_method)canvas_donecanvasdialog,
4536 gensym("donecanvasdialog"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4537 class_addmethod(canvas_class, (t_method)glist_arraydialog,
4538 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4539
4540/* -------------- connect method used in reading files ------------------ */
4541 class_addmethod(canvas_class, (t_method)canvas_connect,
4542 gensym("connect"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4543
4544 class_addmethod(canvas_class, (t_method)canvas_disconnect,
4545 gensym("disconnect"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
4546/* -------------- copy buffer ------------------ */
4547 copy_binbuf = binbuf_new();
4548}
diff --git a/apps/plugins/pdbox/PDa/src/g_graph.c b/apps/plugins/pdbox/PDa/src/g_graph.c
new file mode 100644
index 0000000000..6a64900213
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_graph.c
@@ -0,0 +1,2224 @@
1/* Copyright (c) 1997-2001 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* This file deals with the behavior of glists as either "text objects" or
6"graphs" inside another glist. LATER move the inlet/outlet code of g_canvas.c
7to this file... */
8
9#include <stdlib.h>
10#include "m_pd.h"
11#include "t_tk.h"
12#include "g_canvas.h"
13#include <stdio.h>
14#include <string.h>
15
16/* ---------------------- forward definitions ----------------- */
17
18static void graph_vis(t_gobj *gr, t_glist *unused_glist, int vis);
19static void graph_graphrect(t_gobj *z, t_glist *glist,
20 int *xp1, int *yp1, int *xp2, int *yp2);
21static void graph_getrect(t_gobj *z, t_glist *glist,
22 int *xp1, int *yp1, int *xp2, int *yp2);
23
24/* -------------------- maintaining the list -------------------- */
25
26void glist_add(t_glist *x, t_gobj *y)
27{
28 t_object *ob;
29 y->g_next = 0;
30 if (!x->gl_list) x->gl_list = y;
31 else
32 {
33 t_gobj *y2;
34 for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next);
35 y2->g_next = y;
36 }
37 if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
38 rtext_new(x, ob);
39 if (glist_isvisible(x))
40 gobj_vis(y, x, 1);
41 if (class_isdrawcommand(y->g_pd))
42 canvas_redrawallfortemplate(glist_getcanvas(x));
43}
44
45 /* this is to protect against a hairy problem in which deleting
46 a sub-canvas might delete an inlet on a box, after the box had
47 been invisible-ized, so that we have to protect against redrawing it! */
48int canvas_setdeleting(t_canvas *x, int flag)
49{
50 int ret = x->gl_isdeleting;
51 x->gl_isdeleting = flag;
52 return (ret);
53}
54
55 /* delete an object from a glist and free it */
56void glist_delete(t_glist *x, t_gobj *y)
57{
58 t_gobj *g;
59 t_object *ob;
60 t_gotfn chkdsp = zgetfn(&y->g_pd, gensym("dsp"));
61 t_canvas *canvas = glist_getcanvas(x);
62 int drawcommand = class_isdrawcommand(y->g_pd);
63 int wasdeleting;
64
65 wasdeleting = canvas_setdeleting(canvas, 1);
66 if (x->gl_editor)
67 {
68 if (x->gl_editor->e_grab == y) x->gl_editor->e_grab = 0;
69 if (glist_isselected(x, y)) glist_deselect(x, y);
70
71 /* HACK -- we had phantom outlets not getting erased on the
72 screen because the canvas_setdeleting() mechanism is too
73 crude. LATER carefully set up rules for when the rtexts
74 should exist, so that they stay around until all the
75 steps of becoming invisible are done. In the meantime, just
76 zap the inlets and outlets here... */
77 if (pd_class(&y->g_pd) == canvas_class)
78 {
79 t_glist *gl = (t_glist *)y;
80 if (gl->gl_isgraph)
81 {
82 char tag[80];
83 sprintf(tag, "graph%x", (int)gl);
84 glist_eraseiofor(x, &gl->gl_obj, tag);
85 }
86 else
87 {
88 text_eraseborder(&gl->gl_obj, x,
89 rtext_gettag(glist_findrtext(x, &gl->gl_obj)));
90 }
91 }
92 }
93 gobj_delete(y, x);
94 if (glist_isvisible(canvas))
95 gobj_vis(y, x, 0);
96 if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
97 rtext_new(x, ob);
98 if (x->gl_list == y) x->gl_list = y->g_next;
99 else for (g = x->gl_list; g; g = g->g_next)
100 if (g->g_next == y)
101 {
102 g->g_next = y->g_next;
103 break;
104 }
105 pd_free(&y->g_pd);
106 if (chkdsp) canvas_update_dsp();
107 if (drawcommand) canvas_redrawallfortemplate(canvas);
108 canvas_setdeleting(canvas, wasdeleting);
109 x->gl_valid = ++glist_valid;
110}
111
112 /* remove every object from a glist. Experimental. */
113void glist_clear(t_glist *x)
114{
115 t_gobj *y, *y2;
116 int dspstate = canvas_suspend_dsp();
117 while (y = x->gl_list)
118 glist_delete(x, y);
119 canvas_resume_dsp(dspstate);
120}
121
122void glist_retext(t_glist *glist, t_text *y)
123{
124 t_canvas *c = glist_getcanvas(glist);
125 /* check that we have built rtexts yet. LATER need a better test. */
126 if (glist->gl_editor && glist->gl_editor->e_rtext)
127 {
128 t_rtext *rt = glist_findrtext(glist, y);
129 if (rt)
130 rtext_retext(rt);
131 }
132}
133
134void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
135 t_glistkeyfn keyfn, int xpos, int ypos)
136{
137 t_glist *x2 = glist_getcanvas(x);
138 if (motionfn)
139 x2->gl_editor->e_onmotion = MA_PASSOUT;
140 else x2->gl_editor->e_onmotion = 0;
141 x2->gl_editor->e_grab = y;
142 x2->gl_editor->e_motionfn = motionfn;
143 x2->gl_editor->e_keyfn = keyfn;
144 x2->gl_editor->e_xwas = xpos;
145 x2->gl_editor->e_ywas = ypos;
146}
147
148t_canvas *glist_getcanvas(t_glist *x)
149{
150 while (x->gl_owner && !x->gl_havewindow && x->gl_isgraph)
151 x = x->gl_owner;
152 return((t_canvas *)x);
153}
154
155static float gobj_getxforsort(t_gobj *g)
156{
157 if (pd_class(&g->g_pd) == scalar_class)
158 {
159 float x1, y1;
160 scalar_getbasexy((t_scalar *)g, &x1, &y1);
161 return(x1);
162 }
163 else return (0);
164}
165
166static t_gobj *glist_merge(t_glist *x, t_gobj *g1, t_gobj *g2)
167{
168 t_gobj *g = 0, *g9 = 0;
169 float f1 = 0, f2 = 0;
170 if (g1)
171 f1 = gobj_getxforsort(g1);
172 if (g2)
173 f2 = gobj_getxforsort(g2);
174 while (1)
175 {
176 if (g1)
177 {
178 if (g2)
179 {
180 if (f1 <= f2)
181 goto put1;
182 else goto put2;
183 }
184 else goto put1;
185 }
186 else if (g2)
187 goto put2;
188 else break;
189 put1:
190 if (g9)
191 g9->g_next = g1, g9 = g1;
192 else g9 = g = g1;
193 if (g1 = g1->g_next)
194 f1 = gobj_getxforsort(g1);
195 g9->g_next = 0;
196 continue;
197 put2:
198 if (g9)
199 g9->g_next = g2, g9 = g2;
200 else g9 = g = g2;
201 if (g2 = g2->g_next)
202 f2 = gobj_getxforsort(g2);
203 g9->g_next = 0;
204 continue;
205 }
206 return (g);
207}
208
209static t_gobj *glist_dosort(t_glist *x,
210 t_gobj *g, int nitems)
211{
212 if (nitems < 2)
213 return (g);
214 else
215 {
216 int n1 = nitems/2, n2 = nitems - n1, i;
217 t_gobj *g2, *g3;
218 for (g2 = g, i = n1-1; i--; g2 = g2->g_next)
219 ;
220 g3 = g2->g_next;
221 g2->g_next = 0;
222 g = glist_dosort(x, g, n1);
223 g3 = glist_dosort(x, g3, n2);
224 return (glist_merge(x, g, g3));
225 }
226}
227
228void glist_sort(t_glist *x)
229{
230 int nitems = 0, foo = 0;
231 float lastx = -1e37;
232 t_gobj *g;
233 for (g = x->gl_list; g; g = g->g_next)
234 {
235 float x1 = gobj_getxforsort(g);
236 if (x1 < lastx)
237 foo = 1;
238 lastx = x1;
239 nitems++;
240 }
241 if (foo)
242 x->gl_list = glist_dosort(x, x->gl_list, nitems);
243}
244
245void glist_cleanup(t_glist *x)
246{
247 freebytes(x->gl_xlabel, x->gl_nxlabels * sizeof(*(x->gl_xlabel)));
248 freebytes(x->gl_ylabel, x->gl_nylabels * sizeof(*(x->gl_ylabel)));
249 gstub_cutoff(x->gl_stub);
250}
251
252void glist_free(t_glist *x)
253{
254 glist_cleanup(x);
255 freebytes(x, sizeof(*x));
256}
257
258/* --------------- inlets and outlets ----------- */
259
260
261t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *s)
262{
263 t_inlet *ip = inlet_new(&x->gl_obj, who, s, 0);
264 if (!x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
265 {
266 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
267 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
268 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
269 }
270 if (!x->gl_loading) canvas_resortinlets(x);
271 return (ip);
272}
273
274void canvas_rminlet(t_canvas *x, t_inlet *ip)
275{
276 t_canvas *owner = x->gl_owner;
277 int redraw = (owner && glist_isvisible(owner) && (!owner->gl_isdeleting)
278 && glist_istoplevel(owner));
279
280 if (owner) canvas_deletelinesforio(owner, &x->gl_obj, ip, 0);
281 if (redraw)
282 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
283 inlet_free(ip);
284 if (redraw)
285 {
286 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
287 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
288 }
289}
290
291extern t_inlet *vinlet_getit(t_pd *x);
292extern void obj_moveinletfirst(t_object *x, t_inlet *i);
293
294void canvas_resortinlets(t_canvas *x)
295{
296 int ninlets = 0, i, j, xmax;
297 t_gobj *y, **vec, **vp, **maxp;
298
299 for (ninlets = 0, y = x->gl_list; y; y = y->g_next)
300 if (pd_class(&y->g_pd) == vinlet_class) ninlets++;
301
302 if (ninlets < 2) return;
303
304 vec = (t_gobj **)getbytes(ninlets * sizeof(*vec));
305
306 for (y = x->gl_list, vp = vec; y; y = y->g_next)
307 if (pd_class(&y->g_pd) == vinlet_class) *vp++ = y;
308
309 for (i = ninlets; i--;)
310 {
311 t_inlet *ip;
312 for (vp = vec, xmax = -0x7fffffff, maxp = 0, j = ninlets;
313 j--; vp++)
314 {
315 int x1, y1, x2, y2;
316 t_gobj *g = *vp;
317 if (!g) continue;
318 gobj_getrect(g, x, &x1, &y1, &x2, &y2);
319 if (x1 > xmax) xmax = x1, maxp = vp;
320 }
321 if (!maxp) break;
322 y = *maxp;
323 *maxp = 0;
324 ip = vinlet_getit(&y->g_pd);
325
326 obj_moveinletfirst(&x->gl_obj, ip);
327 }
328 freebytes(vec, ninlets * sizeof(*vec));
329 if (x->gl_owner && glist_isvisible(x->gl_owner))
330 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
331}
332
333t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *s)
334{
335 t_outlet *op = outlet_new(&x->gl_obj, s);
336 if (!x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
337 {
338 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
339 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
340 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
341 }
342 if (!x->gl_loading) canvas_resortoutlets(x);
343 return (op);
344}
345
346void canvas_rmoutlet(t_canvas *x, t_outlet *op)
347{
348 t_canvas *owner = x->gl_owner;
349 int redraw = (owner && glist_isvisible(owner) && (!owner->gl_isdeleting)
350 && glist_istoplevel(owner));
351
352 if (owner) canvas_deletelinesforio(owner, &x->gl_obj, 0, op);
353 if (redraw)
354 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
355
356 outlet_free(op);
357 if (redraw)
358 {
359 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
360 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
361 }
362}
363
364extern t_outlet *voutlet_getit(t_pd *x);
365extern void obj_moveoutletfirst(t_object *x, t_outlet *i);
366
367void canvas_resortoutlets(t_canvas *x)
368{
369 int noutlets = 0, i, j, xmax;
370 t_gobj *y, **vec, **vp, **maxp;
371
372 for (noutlets = 0, y = x->gl_list; y; y = y->g_next)
373 if (pd_class(&y->g_pd) == voutlet_class) noutlets++;
374
375 if (noutlets < 2) return;
376
377 vec = (t_gobj **)getbytes(noutlets * sizeof(*vec));
378
379 for (y = x->gl_list, vp = vec; y; y = y->g_next)
380 if (pd_class(&y->g_pd) == voutlet_class) *vp++ = y;
381
382 for (i = noutlets; i--;)
383 {
384 t_outlet *ip;
385 for (vp = vec, xmax = -0x7fffffff, maxp = 0, j = noutlets;
386 j--; vp++)
387 {
388 int x1, y1, x2, y2;
389 t_gobj *g = *vp;
390 if (!g) continue;
391 gobj_getrect(g, x, &x1, &y1, &x2, &y2);
392 if (x1 > xmax) xmax = x1, maxp = vp;
393 }
394 if (!maxp) break;
395 y = *maxp;
396 *maxp = 0;
397 ip = voutlet_getit(&y->g_pd);
398
399 obj_moveoutletfirst(&x->gl_obj, ip);
400 }
401 freebytes(vec, noutlets * sizeof(*vec));
402 if (x->gl_owner && glist_isvisible(x->gl_owner))
403 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
404}
405
406/* ----------calculating coordinates and controlling appearance --------- */
407
408
409static void graph_bounds(t_glist *x, t_floatarg x1, t_floatarg y1,
410 t_floatarg x2, t_floatarg y2)
411{
412 x->gl_x1 = x1;
413 x->gl_x2 = x2;
414 x->gl_y1 = y1;
415 x->gl_y2 = y2;
416 if (x->gl_x2 == x->gl_x1 ||
417 x->gl_y2 == x->gl_y1)
418 {
419 error("graph: empty bounds rectangle");
420 x1 = y1 = 0;
421 x2 = y2 = 1;
422 }
423 glist_redraw(x);
424}
425
426static void graph_xticks(t_glist *x,
427 t_floatarg point, t_floatarg inc, t_floatarg f)
428{
429 x->gl_xtick.k_point = point;
430 x->gl_xtick.k_inc = inc;
431 x->gl_xtick.k_lperb = f;
432 glist_redraw(x);
433}
434
435static void graph_yticks(t_glist *x,
436 t_floatarg point, t_floatarg inc, t_floatarg f)
437{
438 x->gl_ytick.k_point = point;
439 x->gl_ytick.k_inc = inc;
440 x->gl_ytick.k_lperb = f;
441 glist_redraw(x);
442}
443
444static void graph_xlabel(t_glist *x, t_symbol *s, int argc, t_atom *argv)
445{
446 int i;
447 if (argc < 1) error("graph_xlabel: no y value given");
448 else
449 {
450 x->gl_xlabely = atom_getfloat(argv);
451 argv++; argc--;
452 x->gl_xlabel = (t_symbol **)t_resizebytes(x->gl_xlabel,
453 x->gl_nxlabels * sizeof (t_symbol *), argc * sizeof (t_symbol *));
454 x->gl_nxlabels = argc;
455 for (i = 0; i < argc; i++) x->gl_xlabel[i] = atom_gensym(&argv[i]);
456 }
457 glist_redraw(x);
458}
459
460static void graph_ylabel(t_glist *x, t_symbol *s, int argc, t_atom *argv)
461{
462 int i;
463 if (argc < 1) error("graph_ylabel: no x value given");
464 else
465 {
466 x->gl_ylabelx = atom_getfloat(argv);
467 argv++; argc--;
468 x->gl_ylabel = (t_symbol **)t_resizebytes(x->gl_ylabel,
469 x->gl_nylabels * sizeof (t_symbol *), argc * sizeof (t_symbol *));
470 x->gl_nylabels = argc;
471 for (i = 0; i < argc; i++) x->gl_ylabel[i] = atom_gensym(&argv[i]);
472 }
473 glist_redraw(x);
474}
475
476/****** routines to convert pixels to X or Y value and vice versa ******/
477
478 /* convert an x pixel value to an x coordinate value */
479float glist_pixelstox(t_glist *x, float xpix)
480{
481 /* if we appear as a text box on parent, our range in our
482 coordinates (x1, etc.) specifies the coordinate range
483 of a one-pixel square at top left of the window. */
484 if (!x->gl_isgraph)
485 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) * xpix);
486
487 /* if we're a graph when shown on parent, but own our own
488 window right now, our range in our coordinates (x1, etc.) is spread
489 over the visible window size, given by screenx1, etc. */
490 else if (x->gl_isgraph && x->gl_havewindow)
491 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) *
492 (xpix) / (x->gl_screenx2 - x->gl_screenx1));
493
494 /* otherwise, we appear in a graph within a parent glist,
495 so get our screen rectangle on parent and transform. */
496 else
497 {
498 int x1, y1, x2, y2;
499 if (!x->gl_owner)
500 bug("glist_pixelstox");
501 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
502 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) *
503 (xpix - x1) / (x2 - x1));
504 }
505}
506
507float glist_pixelstoy(t_glist *x, float ypix)
508{
509 if (!x->gl_isgraph)
510 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) * ypix);
511 else if (x->gl_isgraph && x->gl_havewindow)
512 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) *
513 (ypix) / (x->gl_screeny2 - x->gl_screeny1));
514 else
515 {
516 int x1, y1, x2, y2;
517 if (!x->gl_owner)
518 bug("glist_pixelstox");
519 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
520 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) *
521 (ypix - y1) / (y2 - y1));
522 }
523}
524
525 /* convert an x coordinate value to an x pixel location in window */
526float glist_xtopixels(t_glist *x, float xval)
527{
528 if (!x->gl_isgraph)
529 return ((xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
530 else if (x->gl_isgraph && x->gl_havewindow)
531 return (x->gl_screenx2 - x->gl_screenx1) *
532 (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1);
533 else
534 {
535 int x1, y1, x2, y2;
536 if (!x->gl_owner)
537 bug("glist_pixelstox");
538 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
539 return (x1 + (x2 - x1) * (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
540 }
541}
542
543float glist_ytopixels(t_glist *x, float yval)
544{
545 if (!x->gl_isgraph)
546 return ((yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
547 else if (x->gl_isgraph && x->gl_havewindow)
548 return (x->gl_screeny2 - x->gl_screeny1) *
549 (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1);
550 else
551 {
552 int x1, y1, x2, y2;
553 if (!x->gl_owner)
554 bug("glist_pixelstox");
555 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
556 return (y1 + (y2 - y1) * (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
557 }
558}
559
560 /* convert an X screen distance to an X coordinate increment.
561 This is terribly inefficient;
562 but probably not a big enough CPU hog to warrant optimizing. */
563float glist_dpixtodx(t_glist *x, float dxpix)
564{
565 return (dxpix * (glist_pixelstox(x, 1) - glist_pixelstox(x, 0)));
566}
567
568float glist_dpixtody(t_glist *x, float dypix)
569{
570 return (dypix * (glist_pixelstoy(x, 1) - glist_pixelstoy(x, 0)));
571}
572
573 /* get the window location in pixels of a "text" object. The
574 object's x and y positions are in pixels when the glist they're
575 in is toplevel. If it's not, we convert to pixels on the parent
576 window. */
577int text_xpix(t_text *x, t_glist *glist)
578{
579 if (glist->gl_havewindow || !glist->gl_isgraph)
580 return (x->te_xpix);
581 else return (glist_xtopixels(glist,
582 glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
583 x->te_xpix / (glist->gl_screenx2 - glist->gl_screenx1)));
584}
585
586int text_ypix(t_text *x, t_glist *glist)
587{
588 if (glist->gl_havewindow || !glist->gl_isgraph)
589 return (x->te_ypix);
590 else return (glist_ytopixels(glist,
591 glist->gl_y1 + (glist->gl_y2 - glist->gl_y1) *
592 x->te_ypix / (glist->gl_screeny2 - glist->gl_screeny1)));
593}
594
595 /* redraw all the items in a glist. We construe this to mean
596 redrawing in its own window and on parent, as needed in each case.
597 This is too conservative -- for instance, when you draw an "open"
598 rectangle on the parent, you shouldn't have to redraw the window! */
599void glist_redraw(t_glist *x)
600{
601 if (glist_isvisible(x))
602 {
603 /* LATER fix the graph_vis() code to handle both cases */
604 if (glist_istoplevel(x))
605 {
606 t_gobj *g;
607 t_linetraverser t;
608 t_outconnect *oc;
609 for (g = x->gl_list; g; g = g->g_next)
610 {
611 gobj_vis(g, x, 0);
612 gobj_vis(g, x, 1);
613 }
614 /* redraw all the lines */
615 linetraverser_start(&t, x);
616 while (oc = linetraverser_next(&t))
617 sys_vgui(".x%x.c coords l%x %d %d %d %d\n",
618 glist_getcanvas(x), oc,
619 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2);
620 }
621 if (x->gl_owner)
622 {
623 graph_vis(&x->gl_gobj, x->gl_owner, 0);
624 graph_vis(&x->gl_gobj, x->gl_owner, 1);
625 }
626 }
627}
628
629/* --------------------------- widget behavior ------------------- */
630
631extern t_widgetbehavior text_widgetbehavior;
632
633 /* Note that some code in here would also be useful for drawing
634 graph decorations in toplevels... */
635static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
636{
637 t_glist *x = (t_glist *)gr;
638 char tag[50];
639 t_gobj *g;
640 int x1, y1, x2, y2;
641 /* ordinary subpatches: just act like a text object */
642 if (!x->gl_isgraph)
643 {
644 text_widgetbehavior.w_visfn(gr, parent_glist, vis);
645 return;
646 }
647
648 if (vis && canvas_showtext(x))
649 rtext_draw(glist_findrtext(parent_glist, &x->gl_obj));
650 graph_getrect(gr, parent_glist, &x1, &y1, &x2, &y2);
651 if (!vis)
652 rtext_erase(glist_findrtext(parent_glist, &x->gl_obj));
653
654 sprintf(tag, "graph%x", (int)x);
655 if (vis)
656 glist_drawiofor(parent_glist, &x->gl_obj, 1,
657 tag, x1, y1, x2, y2);
658 else glist_eraseiofor(parent_glist, &x->gl_obj, tag);
659 /* if we look like a graph but have been moved to a toplevel,
660 just show the bounding rectangle */
661 if (x->gl_havewindow)
662 {
663 if (vis)
664 {
665 sys_vgui(".x%x.c create polygon\
666 %d %d %d %d %d %d %d %d %d %d -tags %s -fill #c0c0c0\n",
667 glist_getcanvas(x->gl_owner),
668 x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
669 }
670 else
671 {
672 sys_vgui(".x%x.c delete %s\n",
673 glist_getcanvas(x->gl_owner), tag);
674 }
675 return;
676 }
677 /* otherwise draw (or erase) us as a graph inside another glist. */
678 if (vis)
679 {
680 int i;
681 float f;
682
683 /* draw a rectangle around the graph */
684 sys_vgui(".x%x.c create line\
685 %d %d %d %d %d %d %d %d %d %d -tags %s\n",
686 glist_getcanvas(x->gl_owner),
687 x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
688
689 /* draw ticks on horizontal borders. If lperb field is
690 zero, this is disabled. */
691 if (x->gl_xtick.k_lperb)
692 {
693 float upix, lpix;
694 if (y2 < y1)
695 upix = y1, lpix = y2;
696 else upix = y2, lpix = y1;
697 for (i = 0, f = x->gl_xtick.k_point;
698 f < 0.99 * x->gl_x2 + 0.01*x->gl_x1; i++,
699 f += x->gl_xtick.k_inc)
700 {
701 int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4);
702 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
703 glist_getcanvas(x->gl_owner),
704 (int)glist_xtopixels(x, f), (int)upix,
705 (int)glist_xtopixels(x, f), (int)upix - tickpix, tag);
706 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
707 glist_getcanvas(x->gl_owner),
708 (int)glist_xtopixels(x, f), (int)lpix,
709 (int)glist_xtopixels(x, f), (int)lpix + tickpix, tag);
710 }
711 for (i = 1, f = x->gl_xtick.k_point - x->gl_xtick.k_inc;
712 f > 0.99 * x->gl_x1 + 0.01*x->gl_x2;
713 i++, f -= x->gl_xtick.k_inc)
714 {
715 int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4);
716 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
717 glist_getcanvas(x->gl_owner),
718 (int)glist_xtopixels(x, f), (int)upix,
719 (int)glist_xtopixels(x, f), (int)upix - tickpix, tag);
720 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
721 glist_getcanvas(x->gl_owner),
722 (int)glist_xtopixels(x, f), (int)lpix,
723 (int)glist_xtopixels(x, f), (int)lpix + tickpix, tag);
724 }
725 }
726
727 /* draw ticks in vertical borders*/
728 if (x->gl_ytick.k_lperb)
729 {
730 float ubound, lbound;
731 if (x->gl_y2 < x->gl_y1)
732 ubound = x->gl_y1, lbound = x->gl_y2;
733 else ubound = x->gl_y2, lbound = x->gl_y1;
734 for (i = 0, f = x->gl_ytick.k_point;
735 f < 0.99 * ubound + 0.01 * lbound;
736 i++, f += x->gl_ytick.k_inc)
737 {
738 int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4);
739 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
740 glist_getcanvas(x->gl_owner),
741 x1, (int)glist_ytopixels(x, f),
742 x1 + tickpix, (int)glist_ytopixels(x, f), tag);
743 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
744 glist_getcanvas(x->gl_owner),
745 x2, (int)glist_ytopixels(x, f),
746 x2 - tickpix, (int)glist_ytopixels(x, f), tag);
747 }
748 for (i = 1, f = x->gl_ytick.k_point - x->gl_ytick.k_inc;
749 f > 0.99 * lbound + 0.01 * ubound;
750 i++, f -= x->gl_ytick.k_inc)
751 {
752 int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4);
753 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
754 glist_getcanvas(x->gl_owner),
755 x1, (int)glist_ytopixels(x, f),
756 x1 + tickpix, (int)glist_ytopixels(x, f), tag);
757 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
758 glist_getcanvas(x->gl_owner),
759 x2, (int)glist_ytopixels(x, f),
760 x2 - tickpix, (int)glist_ytopixels(x, f), tag);
761 }
762 }
763 /* draw x labels */
764 for (i = 0; i < x->gl_nxlabels; i++)
765 sys_vgui(".x%x.c create text\
766 %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
767 glist_getcanvas(x),
768 (int)glist_xtopixels(x, atof(x->gl_xlabel[i]->s_name)),
769 (int)glist_ytopixels(x, x->gl_xlabely), x->gl_xlabel[i]->s_name,
770 glist_getfont(x), tag);
771
772 /* draw y labels */
773 for (i = 0; i < x->gl_nylabels; i++)
774 sys_vgui(".x%x.c create text\
775 %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
776 glist_getcanvas(x),
777 (int)glist_xtopixels(x, x->gl_ylabelx),
778 (int)glist_ytopixels(x, atof(x->gl_ylabel[i]->s_name)),
779 x->gl_ylabel[i]->s_name,
780 glist_getfont(x), tag);
781
782 /* draw contents of graph as glist */
783 for (g = x->gl_list; g; g = g->g_next)
784 gobj_vis(g, x, 1);
785 }
786 else
787 {
788 sys_vgui(".x%x.c delete %s\n",
789 glist_getcanvas(x->gl_owner), tag);
790 for (g = x->gl_list; g; g = g->g_next)
791 gobj_vis(g, x, 0);
792 }
793}
794
795 /* get the graph's rectangle, not counting extra swelling for controls
796 to keep them inside the graph. This is the "logical" pixel size. */
797
798static void graph_graphrect(t_gobj *z, t_glist *glist,
799 int *xp1, int *yp1, int *xp2, int *yp2)
800{
801 t_glist *x = (t_glist *)z;
802 int x1 = text_xpix(&x->gl_obj, glist);
803 int y1 = text_ypix(&x->gl_obj, glist);
804 int x2, y2;
805#if 0 /* this used to adjust graph size when it was in another graph;
806 now we just preserve the size. */
807 /* same logic here as in text_xpix(): */
808 if (glist->gl_havewindow)
809 {
810 x2 = x1 + x->gl_pixwidth;
811 y2 = y1 + x->gl_pixheight;
812 }
813 else
814 {
815 x2 = glist_xtopixels(glist,
816 glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
817 (x->gl_obj.te_xpix + x->gl_pixwidth) /
818 (glist->gl_screenx2 - glist->gl_screenx1));
819 y2 = glist_ytopixels(glist,
820 glist->gl_y1 + (glist->gl_y2 - glist->gl_y1) *
821 (x->gl_obj.te_ypix + x->gl_pixheight) /
822 (glist->gl_screeny2 - glist->gl_screeny1));
823 }
824#endif
825 x2 = x1 + x->gl_pixwidth;
826 y2 = y1 + x->gl_pixheight;
827
828 *xp1 = x1;
829 *yp1 = y1;
830 *xp2 = x2;
831 *yp2 = y2;
832}
833
834 /* get the rectangle, enlarged to contain all the "contents" --
835 meaning their formal bounds rectangles. */
836static void graph_getrect(t_gobj *z, t_glist *glist,
837 int *xp1, int *yp1, int *xp2, int *yp2)
838{
839 int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
840 t_glist *x = (t_glist *)z;
841 if (x->gl_isgraph)
842 {
843 int hadwindow;
844 t_gobj *g;
845 t_text *ob;
846 int x21, y21, x22, y22;
847
848 graph_graphrect(z, glist, &x1, &y1, &x2, &y2);
849 if (canvas_showtext(x))
850 {
851 text_widgetbehavior.w_getrectfn(z, glist, &x21, &y21, &x22, &y22);
852 if (x22 > x2)
853 x2 = x22;
854 if (y22 > y2)
855 y2 = y22;
856 }
857 /* lie about whether we have our own window to affect gobj_getrect
858 calls below. (LATER add argument to gobj_getrect()?) */
859 hadwindow = x->gl_havewindow;
860 x->gl_havewindow = 0;
861 for (g = x->gl_list; g; g = g->g_next)
862 if ((!(ob = pd_checkobject(&g->g_pd))) || text_shouldvis(ob, x))
863 {
864 /* don't do this for arrays, just let them hang outsize the
865 box. */
866 if (pd_class(&g->g_pd) == garray_class)
867 continue;
868 gobj_getrect(g, x, &x21, &y21, &x22, &y22);
869 if (x22 > x2)
870 x2 = x22;
871 if (y22 > y2)
872 y2 = y22;
873 }
874 x->gl_havewindow = hadwindow;
875 }
876 else text_widgetbehavior.w_getrectfn(z, glist, &x1, &y1, &x2, &y2);
877 *xp1 = x1;
878 *yp1 = y1;
879 *xp2 = x2;
880 *yp2 = y2;
881}
882
883static void graph_displace(t_gobj *z, t_glist *glist, int dx, int dy)
884{
885 t_glist *x = (t_glist *)z;
886 if (!x->gl_isgraph)
887 text_widgetbehavior.w_displacefn(z, glist, dx, dy);
888 else
889 {
890 x->gl_obj.te_xpix += dx;
891 x->gl_obj.te_ypix += dy;
892 glist_redraw(x);
893 canvas_fixlinesfor(glist_getcanvas(glist), &x->gl_obj);
894 }
895}
896
897static void graph_select(t_gobj *z, t_glist *glist, int state)
898{
899 t_glist *x = (t_glist *)z;
900 if (!x->gl_isgraph)
901 text_widgetbehavior.w_selectfn(z, glist, state);
902 else
903 {
904 t_rtext *y = glist_findrtext(glist, &x->gl_obj);
905 if (canvas_showtext(x))
906 rtext_select(y, state);
907 sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
908 rtext_gettag(y), (state? "blue" : "black"));
909 sys_vgui(".x%x.c itemconfigure graph%x -fill %s\n",
910 glist_getcanvas(glist), z, (state? "blue" : "black"));
911 }
912}
913
914static void graph_activate(t_gobj *z, t_glist *glist, int state)
915{
916 t_glist *x = (t_glist *)z;
917 if (canvas_showtext(x))
918 text_widgetbehavior.w_activatefn(z, glist, state);
919}
920
921#if 0
922static void graph_delete(t_gobj *z, t_glist *glist)
923{
924 t_glist *x = (t_glist *)z;
925 if (!x->gl_isgraph)
926 text_widgetbehavior.w_deletefn(z, glist);
927 else
928 {
929 t_gobj *y;
930 while (y = x->gl_list) glist_delete(x, y);
931#if 0 /* I think this was just wrong. */
932 if (glist_isvisible(x))
933 sys_vgui(".x%x.c delete graph%x\n", glist_getcanvas(glist), x);
934#endif
935 }
936}
937#endif
938
939static void graph_delete(t_gobj *z, t_glist *glist)
940{
941 t_glist *x = (t_glist *)z;
942 t_gobj *y;
943 text_widgetbehavior.w_deletefn(z, glist);
944 while (y = x->gl_list)
945 glist_delete(x, y);
946}
947
948static float graph_lastxpix, graph_lastypix;
949
950static void graph_motion(void *z, t_floatarg dx, t_floatarg dy)
951{
952 t_glist *x = (t_glist *)z;
953 float newxpix = graph_lastxpix + dx, newypix = graph_lastypix + dy;
954 t_garray *a = (t_garray *)(x->gl_list);
955 int oldx = 0.5 + glist_pixelstox(x, graph_lastxpix);
956 int newx = 0.5 + glist_pixelstox(x, newxpix);
957 t_sample *vec;
958 int nelem, i;
959 float oldy = glist_pixelstoy(x, graph_lastypix);
960 float newy = glist_pixelstoy(x, newypix);
961 graph_lastxpix = newxpix;
962 graph_lastypix = newypix;
963 /* verify that the array is OK */
964 if (!a || pd_class((t_pd *)a) != garray_class)
965 return;
966 if (!garray_getfloatarray(a, &nelem, &vec))
967 return;
968 if (oldx < 0) oldx = 0;
969 if (oldx >= nelem)
970 oldx = nelem - 1;
971 if (newx < 0) newx = 0;
972 if (newx >= nelem)
973 newx = nelem - 1;
974 if (oldx < newx - 1)
975 {
976 for (i = oldx + 1; i <= newx; i++)
977 vec[i] = newy + (oldy - newy) *
978 ((float)(newx - i))/(float)(newx - oldx);
979 }
980 else if (oldx > newx + 1)
981 {
982 for (i = oldx - 1; i >= newx; i--)
983 vec[i] = newy + (oldy - newy) *
984 ((float)(newx - i))/(float)(newx - oldx);
985 }
986 else vec[newx] = newy;
987 garray_redraw(a);
988}
989
990static int graph_click(t_gobj *z, struct _glist *glist,
991 int xpix, int ypix, int shift, int alt, int dbl, int doit)
992{
993 t_glist *x = (t_glist *)z;
994 t_gobj *y;
995 int clickreturned = 0;
996 if (!x->gl_isgraph)
997 return (text_widgetbehavior.w_clickfn(z, glist,
998 xpix, ypix, shift, alt, dbl, doit));
999 else if (x->gl_havewindow)
1000 return (0);
1001 else
1002 {
1003 for (y = x->gl_list; y; y = y->g_next)
1004 {
1005 int x1, y1, x2, y2;
1006 /* check if the object wants to be clicked */
1007 if (canvas_hitbox(x, y, xpix, ypix, &x1, &y1, &x2, &y2)
1008 && (clickreturned = gobj_click(y, x, xpix, ypix,
1009 shift, alt, 0, doit)))
1010 break;
1011 }
1012 if (!doit)
1013 {
1014 if (y)
1015 canvas_setcursor(glist_getcanvas(x), clickreturned);
1016 else canvas_setcursor(glist_getcanvas(x), CURSOR_RUNMODE_NOTHING);
1017 }
1018 return (clickreturned);
1019 }
1020}
1021
1022void garray_properties(t_garray *x);
1023
1024t_widgetbehavior graph_widgetbehavior =
1025{
1026 graph_getrect,
1027 graph_displace,
1028 graph_select,
1029 graph_activate,
1030 graph_delete,
1031 graph_vis,
1032 graph_click,
1033};
1034
1035void graph_properties(t_gobj *z, t_glist *owner)
1036{
1037 t_glist *x = (t_glist *)z;
1038 {
1039 t_gobj *y;
1040 char graphbuf[200];
1041 sprintf(graphbuf, "pdtk_graph_dialog %%s %g %g %g %g %d %d\n",
1042 x->gl_x1, x->gl_y1, x->gl_x2, x->gl_y2,
1043 x->gl_pixwidth, x->gl_pixheight);
1044 gfxstub_new(&x->gl_pd, x, graphbuf);
1045
1046 for (y = x->gl_list; y; y = y->g_next)
1047 if (pd_class(&y->g_pd) == garray_class)
1048 garray_properties((t_garray *)y);
1049 }
1050}
1051
1052 /* find the graph most recently added to this glist;
1053 if none exists, return 0. */
1054
1055t_glist *glist_findgraph(t_glist *x)
1056{
1057 t_gobj *y = 0, *z;
1058 for (z = x->gl_list; z; z = z->g_next)
1059 if (pd_class(&z->g_pd) == canvas_class && ((t_glist *)z)->gl_isgraph)
1060 y = z;
1061 return ((t_glist *)y);
1062}
1063
1064 /* message back from dialog GUI to set parameters. Args are:
1065 1-4: bounds in our coordinates; 5-6: size in parent */
1066static void graph_dialog(t_glist *x, t_symbol *s, int argc, t_atom *argv)
1067{
1068 t_float x1 = atom_getfloatarg(0, argc, argv);
1069 t_float y1 = atom_getfloatarg(1, argc, argv);
1070 t_float x2 = atom_getfloatarg(2, argc, argv);
1071 t_float y2 = atom_getfloatarg(3, argc, argv);
1072 t_float xpix = atom_getfloatarg(4, argc, argv);
1073 t_float ypix = atom_getfloatarg(5, argc, argv);
1074 if (x1 != x->gl_x1 || x2 != x->gl_x2 ||
1075 y1 != x->gl_y1 || y2 != x->gl_y2)
1076 graph_bounds(x, x1, y1, x2, y2);
1077 if (xpix != x->gl_pixwidth || ypix != x->gl_pixheight)
1078 {
1079 x->gl_pixwidth = xpix;
1080 x->gl_pixheight = ypix;
1081 glist_redraw(x);
1082 if (x->gl_owner)
1083 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1084 }
1085}
1086
1087extern void canvas_menuarray(t_glist *canvas);
1088
1089void g_graph_setup(void)
1090{
1091 class_setwidget(canvas_class, &graph_widgetbehavior);
1092 class_addmethod(canvas_class, (t_method)graph_bounds, gensym("bounds"),
1093 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1094 class_addmethod(canvas_class, (t_method)graph_xticks, gensym("xticks"),
1095 A_FLOAT, A_FLOAT, A_FLOAT, 0);
1096 class_addmethod(canvas_class, (t_method)graph_xlabel, gensym("xlabel"),
1097 A_GIMME, 0);
1098 class_addmethod(canvas_class, (t_method)graph_yticks, gensym("yticks"),
1099 A_FLOAT, A_FLOAT, A_FLOAT, 0);
1100 class_addmethod(canvas_class, (t_method)graph_ylabel, gensym("ylabel"),
1101 A_GIMME, 0);
1102 class_addmethod(canvas_class, (t_method)graph_array, gensym("array"),
1103 A_SYMBOL, A_FLOAT, A_SYMBOL, A_DEFFLOAT, A_NULL);
1104 class_addmethod(canvas_class, (t_method)canvas_menuarray,
1105 gensym("menuarray"), A_NULL);
1106 class_addmethod(canvas_class, (t_method)graph_dialog, gensym("dialog"),
1107 A_GIMME, 0);
1108 class_addmethod(canvas_class, (t_method)glist_arraydialog,
1109 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
1110 class_addmethod(canvas_class, (t_method)glist_sort,
1111 gensym("sort"), A_NULL);
1112}
1113/* Copyright (c) 1997-2001 Miller Puckette and others.
1114* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1115* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1116
1117/* This file deals with the behavior of glists as either "text objects" or
1118"graphs" inside another glist. LATER move the inlet/outlet code of g_canvas.c
1119to this file... */
1120
1121#include <stdlib.h>
1122#include "m_pd.h"
1123#include "t_tk.h"
1124#include "g_canvas.h"
1125#include <stdio.h>
1126#include <string.h>
1127
1128/* ---------------------- forward definitions ----------------- */
1129
1130static void graph_vis(t_gobj *gr, t_glist *unused_glist, int vis);
1131static void graph_graphrect(t_gobj *z, t_glist *glist,
1132 int *xp1, int *yp1, int *xp2, int *yp2);
1133static void graph_getrect(t_gobj *z, t_glist *glist,
1134 int *xp1, int *yp1, int *xp2, int *yp2);
1135
1136/* -------------------- maintaining the list -------------------- */
1137
1138void glist_add(t_glist *x, t_gobj *y)
1139{
1140 t_object *ob;
1141 y->g_next = 0;
1142 if (!x->gl_list) x->gl_list = y;
1143 else
1144 {
1145 t_gobj *y2;
1146 for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next);
1147 y2->g_next = y;
1148 }
1149 if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
1150 rtext_new(x, ob);
1151 if (glist_isvisible(x))
1152 gobj_vis(y, x, 1);
1153 if (class_isdrawcommand(y->g_pd))
1154 canvas_redrawallfortemplate(glist_getcanvas(x));
1155}
1156
1157 /* this is to protect against a hairy problem in which deleting
1158 a sub-canvas might delete an inlet on a box, after the box had
1159 been invisible-ized, so that we have to protect against redrawing it! */
1160int canvas_setdeleting(t_canvas *x, int flag)
1161{
1162 int ret = x->gl_isdeleting;
1163 x->gl_isdeleting = flag;
1164 return (ret);
1165}
1166
1167 /* delete an object from a glist and free it */
1168void glist_delete(t_glist *x, t_gobj *y)
1169{
1170 t_gobj *g;
1171 t_object *ob;
1172 t_gotfn chkdsp = zgetfn(&y->g_pd, gensym("dsp"));
1173 t_canvas *canvas = glist_getcanvas(x);
1174 int drawcommand = class_isdrawcommand(y->g_pd);
1175 int wasdeleting;
1176
1177 wasdeleting = canvas_setdeleting(canvas, 1);
1178 if (x->gl_editor)
1179 {
1180 if (x->gl_editor->e_grab == y) x->gl_editor->e_grab = 0;
1181 if (glist_isselected(x, y)) glist_deselect(x, y);
1182
1183 /* HACK -- we had phantom outlets not getting erased on the
1184 screen because the canvas_setdeleting() mechanism is too
1185 crude. LATER carefully set up rules for when the rtexts
1186 should exist, so that they stay around until all the
1187 steps of becoming invisible are done. In the meantime, just
1188 zap the inlets and outlets here... */
1189 if (pd_class(&y->g_pd) == canvas_class)
1190 {
1191 t_glist *gl = (t_glist *)y;
1192 if (gl->gl_isgraph)
1193 {
1194 char tag[80];
1195 sprintf(tag, "graph%x", (int)gl);
1196 glist_eraseiofor(x, &gl->gl_obj, tag);
1197 }
1198 else
1199 {
1200 text_eraseborder(&gl->gl_obj, x,
1201 rtext_gettag(glist_findrtext(x, &gl->gl_obj)));
1202 }
1203 }
1204 }
1205 gobj_delete(y, x);
1206 if (glist_isvisible(canvas))
1207 gobj_vis(y, x, 0);
1208 if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
1209 rtext_new(x, ob);
1210 if (x->gl_list == y) x->gl_list = y->g_next;
1211 else for (g = x->gl_list; g; g = g->g_next)
1212 if (g->g_next == y)
1213 {
1214 g->g_next = y->g_next;
1215 break;
1216 }
1217 pd_free(&y->g_pd);
1218 if (chkdsp) canvas_update_dsp();
1219 if (drawcommand) canvas_redrawallfortemplate(canvas);
1220 canvas_setdeleting(canvas, wasdeleting);
1221 x->gl_valid = ++glist_valid;
1222}
1223
1224 /* remove every object from a glist. Experimental. */
1225void glist_clear(t_glist *x)
1226{
1227 t_gobj *y, *y2;
1228 int dspstate = canvas_suspend_dsp();
1229 while (y = x->gl_list)
1230 glist_delete(x, y);
1231 canvas_resume_dsp(dspstate);
1232}
1233
1234void glist_retext(t_glist *glist, t_text *y)
1235{
1236 t_canvas *c = glist_getcanvas(glist);
1237 /* check that we have built rtexts yet. LATER need a better test. */
1238 if (glist->gl_editor && glist->gl_editor->e_rtext)
1239 {
1240 t_rtext *rt = glist_findrtext(glist, y);
1241 if (rt)
1242 rtext_retext(rt);
1243 }
1244}
1245
1246void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
1247 t_glistkeyfn keyfn, int xpos, int ypos)
1248{
1249 t_glist *x2 = glist_getcanvas(x);
1250 if (motionfn)
1251 x2->gl_editor->e_onmotion = MA_PASSOUT;
1252 else x2->gl_editor->e_onmotion = 0;
1253 x2->gl_editor->e_grab = y;
1254 x2->gl_editor->e_motionfn = motionfn;
1255 x2->gl_editor->e_keyfn = keyfn;
1256 x2->gl_editor->e_xwas = xpos;
1257 x2->gl_editor->e_ywas = ypos;
1258}
1259
1260t_canvas *glist_getcanvas(t_glist *x)
1261{
1262 while (x->gl_owner && !x->gl_havewindow && x->gl_isgraph)
1263 x = x->gl_owner;
1264 return((t_canvas *)x);
1265}
1266
1267static float gobj_getxforsort(t_gobj *g)
1268{
1269 if (pd_class(&g->g_pd) == scalar_class)
1270 {
1271 float x1, y1;
1272 scalar_getbasexy((t_scalar *)g, &x1, &y1);
1273 return(x1);
1274 }
1275 else return (0);
1276}
1277
1278static t_gobj *glist_merge(t_glist *x, t_gobj *g1, t_gobj *g2)
1279{
1280 t_gobj *g = 0, *g9 = 0;
1281 float f1 = 0, f2 = 0;
1282 if (g1)
1283 f1 = gobj_getxforsort(g1);
1284 if (g2)
1285 f2 = gobj_getxforsort(g2);
1286 while (1)
1287 {
1288 if (g1)
1289 {
1290 if (g2)
1291 {
1292 if (f1 <= f2)
1293 goto put1;
1294 else goto put2;
1295 }
1296 else goto put1;
1297 }
1298 else if (g2)
1299 goto put2;
1300 else break;
1301 put1:
1302 if (g9)
1303 g9->g_next = g1, g9 = g1;
1304 else g9 = g = g1;
1305 if (g1 = g1->g_next)
1306 f1 = gobj_getxforsort(g1);
1307 g9->g_next = 0;
1308 continue;
1309 put2:
1310 if (g9)
1311 g9->g_next = g2, g9 = g2;
1312 else g9 = g = g2;
1313 if (g2 = g2->g_next)
1314 f2 = gobj_getxforsort(g2);
1315 g9->g_next = 0;
1316 continue;
1317 }
1318 return (g);
1319}
1320
1321static t_gobj *glist_dosort(t_glist *x,
1322 t_gobj *g, int nitems)
1323{
1324 if (nitems < 2)
1325 return (g);
1326 else
1327 {
1328 int n1 = nitems/2, n2 = nitems - n1, i;
1329 t_gobj *g2, *g3;
1330 for (g2 = g, i = n1-1; i--; g2 = g2->g_next)
1331 ;
1332 g3 = g2->g_next;
1333 g2->g_next = 0;
1334 g = glist_dosort(x, g, n1);
1335 g3 = glist_dosort(x, g3, n2);
1336 return (glist_merge(x, g, g3));
1337 }
1338}
1339
1340void glist_sort(t_glist *x)
1341{
1342 int nitems = 0, foo = 0;
1343 float lastx = -1e37;
1344 t_gobj *g;
1345 for (g = x->gl_list; g; g = g->g_next)
1346 {
1347 float x1 = gobj_getxforsort(g);
1348 if (x1 < lastx)
1349 foo = 1;
1350 lastx = x1;
1351 nitems++;
1352 }
1353 if (foo)
1354 x->gl_list = glist_dosort(x, x->gl_list, nitems);
1355}
1356
1357void glist_cleanup(t_glist *x)
1358{
1359 freebytes(x->gl_xlabel, x->gl_nxlabels * sizeof(*(x->gl_xlabel)));
1360 freebytes(x->gl_ylabel, x->gl_nylabels * sizeof(*(x->gl_ylabel)));
1361 gstub_cutoff(x->gl_stub);
1362}
1363
1364void glist_free(t_glist *x)
1365{
1366 glist_cleanup(x);
1367 freebytes(x, sizeof(*x));
1368}
1369
1370/* --------------- inlets and outlets ----------- */
1371
1372
1373t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *s)
1374{
1375 t_inlet *ip = inlet_new(&x->gl_obj, who, s, 0);
1376 if (!x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
1377 {
1378 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
1379 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
1380 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1381 }
1382 if (!x->gl_loading) canvas_resortinlets(x);
1383 return (ip);
1384}
1385
1386void canvas_rminlet(t_canvas *x, t_inlet *ip)
1387{
1388 t_canvas *owner = x->gl_owner;
1389 int redraw = (owner && glist_isvisible(owner) && (!owner->gl_isdeleting)
1390 && glist_istoplevel(owner));
1391
1392 if (owner) canvas_deletelinesforio(owner, &x->gl_obj, ip, 0);
1393 if (redraw)
1394 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
1395 inlet_free(ip);
1396 if (redraw)
1397 {
1398 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
1399 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1400 }
1401}
1402
1403extern t_inlet *vinlet_getit(t_pd *x);
1404extern void obj_moveinletfirst(t_object *x, t_inlet *i);
1405
1406void canvas_resortinlets(t_canvas *x)
1407{
1408 int ninlets = 0, i, j, xmax;
1409 t_gobj *y, **vec, **vp, **maxp;
1410
1411 for (ninlets = 0, y = x->gl_list; y; y = y->g_next)
1412 if (pd_class(&y->g_pd) == vinlet_class) ninlets++;
1413
1414 if (ninlets < 2) return;
1415
1416 vec = (t_gobj **)getbytes(ninlets * sizeof(*vec));
1417
1418 for (y = x->gl_list, vp = vec; y; y = y->g_next)
1419 if (pd_class(&y->g_pd) == vinlet_class) *vp++ = y;
1420
1421 for (i = ninlets; i--;)
1422 {
1423 t_inlet *ip;
1424 for (vp = vec, xmax = -0x7fffffff, maxp = 0, j = ninlets;
1425 j--; vp++)
1426 {
1427 int x1, y1, x2, y2;
1428 t_gobj *g = *vp;
1429 if (!g) continue;
1430 gobj_getrect(g, x, &x1, &y1, &x2, &y2);
1431 if (x1 > xmax) xmax = x1, maxp = vp;
1432 }
1433 if (!maxp) break;
1434 y = *maxp;
1435 *maxp = 0;
1436 ip = vinlet_getit(&y->g_pd);
1437
1438 obj_moveinletfirst(&x->gl_obj, ip);
1439 }
1440 freebytes(vec, ninlets * sizeof(*vec));
1441 if (x->gl_owner && glist_isvisible(x->gl_owner))
1442 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1443}
1444
1445t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *s)
1446{
1447 t_outlet *op = outlet_new(&x->gl_obj, s);
1448 if (!x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
1449 {
1450 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
1451 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
1452 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1453 }
1454 if (!x->gl_loading) canvas_resortoutlets(x);
1455 return (op);
1456}
1457
1458void canvas_rmoutlet(t_canvas *x, t_outlet *op)
1459{
1460 t_canvas *owner = x->gl_owner;
1461 int redraw = (owner && glist_isvisible(owner) && (!owner->gl_isdeleting)
1462 && glist_istoplevel(owner));
1463
1464 if (owner) canvas_deletelinesforio(owner, &x->gl_obj, 0, op);
1465 if (redraw)
1466 gobj_vis(&x->gl_gobj, x->gl_owner, 0);
1467
1468 outlet_free(op);
1469 if (redraw)
1470 {
1471 gobj_vis(&x->gl_gobj, x->gl_owner, 1);
1472 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1473 }
1474}
1475
1476extern t_outlet *voutlet_getit(t_pd *x);
1477extern void obj_moveoutletfirst(t_object *x, t_outlet *i);
1478
1479void canvas_resortoutlets(t_canvas *x)
1480{
1481 int noutlets = 0, i, j, xmax;
1482 t_gobj *y, **vec, **vp, **maxp;
1483
1484 for (noutlets = 0, y = x->gl_list; y; y = y->g_next)
1485 if (pd_class(&y->g_pd) == voutlet_class) noutlets++;
1486
1487 if (noutlets < 2) return;
1488
1489 vec = (t_gobj **)getbytes(noutlets * sizeof(*vec));
1490
1491 for (y = x->gl_list, vp = vec; y; y = y->g_next)
1492 if (pd_class(&y->g_pd) == voutlet_class) *vp++ = y;
1493
1494 for (i = noutlets; i--;)
1495 {
1496 t_outlet *ip;
1497 for (vp = vec, xmax = -0x7fffffff, maxp = 0, j = noutlets;
1498 j--; vp++)
1499 {
1500 int x1, y1, x2, y2;
1501 t_gobj *g = *vp;
1502 if (!g) continue;
1503 gobj_getrect(g, x, &x1, &y1, &x2, &y2);
1504 if (x1 > xmax) xmax = x1, maxp = vp;
1505 }
1506 if (!maxp) break;
1507 y = *maxp;
1508 *maxp = 0;
1509 ip = voutlet_getit(&y->g_pd);
1510
1511 obj_moveoutletfirst(&x->gl_obj, ip);
1512 }
1513 freebytes(vec, noutlets * sizeof(*vec));
1514 if (x->gl_owner && glist_isvisible(x->gl_owner))
1515 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
1516}
1517
1518/* ----------calculating coordinates and controlling appearance --------- */
1519
1520
1521static void graph_bounds(t_glist *x, t_floatarg x1, t_floatarg y1,
1522 t_floatarg x2, t_floatarg y2)
1523{
1524 x->gl_x1 = x1;
1525 x->gl_x2 = x2;
1526 x->gl_y1 = y1;
1527 x->gl_y2 = y2;
1528 if (x->gl_x2 == x->gl_x1 ||
1529 x->gl_y2 == x->gl_y1)
1530 {
1531 error("graph: empty bounds rectangle");
1532 x1 = y1 = 0;
1533 x2 = y2 = 1;
1534 }
1535 glist_redraw(x);
1536}
1537
1538static void graph_xticks(t_glist *x,
1539 t_floatarg point, t_floatarg inc, t_floatarg f)
1540{
1541 x->gl_xtick.k_point = point;
1542 x->gl_xtick.k_inc = inc;
1543 x->gl_xtick.k_lperb = f;
1544 glist_redraw(x);
1545}
1546
1547static void graph_yticks(t_glist *x,
1548 t_floatarg point, t_floatarg inc, t_floatarg f)
1549{
1550 x->gl_ytick.k_point = point;
1551 x->gl_ytick.k_inc = inc;
1552 x->gl_ytick.k_lperb = f;
1553 glist_redraw(x);
1554}
1555
1556static void graph_xlabel(t_glist *x, t_symbol *s, int argc, t_atom *argv)
1557{
1558 int i;
1559 if (argc < 1) error("graph_xlabel: no y value given");
1560 else
1561 {
1562 x->gl_xlabely = atom_getfloat(argv);
1563 argv++; argc--;
1564 x->gl_xlabel = (t_symbol **)t_resizebytes(x->gl_xlabel,
1565 x->gl_nxlabels * sizeof (t_symbol *), argc * sizeof (t_symbol *));
1566 x->gl_nxlabels = argc;
1567 for (i = 0; i < argc; i++) x->gl_xlabel[i] = atom_gensym(&argv[i]);
1568 }
1569 glist_redraw(x);
1570}
1571
1572static void graph_ylabel(t_glist *x, t_symbol *s, int argc, t_atom *argv)
1573{
1574 int i;
1575 if (argc < 1) error("graph_ylabel: no x value given");
1576 else
1577 {
1578 x->gl_ylabelx = atom_getfloat(argv);
1579 argv++; argc--;
1580 x->gl_ylabel = (t_symbol **)t_resizebytes(x->gl_ylabel,
1581 x->gl_nylabels * sizeof (t_symbol *), argc * sizeof (t_symbol *));
1582 x->gl_nylabels = argc;
1583 for (i = 0; i < argc; i++) x->gl_ylabel[i] = atom_gensym(&argv[i]);
1584 }
1585 glist_redraw(x);
1586}
1587
1588/****** routines to convert pixels to X or Y value and vice versa ******/
1589
1590 /* convert an x pixel value to an x coordinate value */
1591float glist_pixelstox(t_glist *x, float xpix)
1592{
1593 /* if we appear as a text box on parent, our range in our
1594 coordinates (x1, etc.) specifies the coordinate range
1595 of a one-pixel square at top left of the window. */
1596 if (!x->gl_isgraph)
1597 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) * xpix);
1598
1599 /* if we're a graph when shown on parent, but own our own
1600 window right now, our range in our coordinates (x1, etc.) is spread
1601 over the visible window size, given by screenx1, etc. */
1602 else if (x->gl_isgraph && x->gl_havewindow)
1603 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) *
1604 (xpix) / (x->gl_screenx2 - x->gl_screenx1));
1605
1606 /* otherwise, we appear in a graph within a parent glist,
1607 so get our screen rectangle on parent and transform. */
1608 else
1609 {
1610 int x1, y1, x2, y2;
1611 if (!x->gl_owner)
1612 bug("glist_pixelstox");
1613 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
1614 return (x->gl_x1 + (x->gl_x2 - x->gl_x1) *
1615 (xpix - x1) / (x2 - x1));
1616 }
1617}
1618
1619float glist_pixelstoy(t_glist *x, float ypix)
1620{
1621 if (!x->gl_isgraph)
1622 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) * ypix);
1623 else if (x->gl_isgraph && x->gl_havewindow)
1624 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) *
1625 (ypix) / (x->gl_screeny2 - x->gl_screeny1));
1626 else
1627 {
1628 int x1, y1, x2, y2;
1629 if (!x->gl_owner)
1630 bug("glist_pixelstox");
1631 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
1632 return (x->gl_y1 + (x->gl_y2 - x->gl_y1) *
1633 (ypix - y1) / (y2 - y1));
1634 }
1635}
1636
1637 /* convert an x coordinate value to an x pixel location in window */
1638float glist_xtopixels(t_glist *x, float xval)
1639{
1640 if (!x->gl_isgraph)
1641 return ((xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
1642 else if (x->gl_isgraph && x->gl_havewindow)
1643 return (x->gl_screenx2 - x->gl_screenx1) *
1644 (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1);
1645 else
1646 {
1647 int x1, y1, x2, y2;
1648 if (!x->gl_owner)
1649 bug("glist_pixelstox");
1650 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
1651 return (x1 + (x2 - x1) * (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
1652 }
1653}
1654
1655float glist_ytopixels(t_glist *x, float yval)
1656{
1657 if (!x->gl_isgraph)
1658 return ((yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
1659 else if (x->gl_isgraph && x->gl_havewindow)
1660 return (x->gl_screeny2 - x->gl_screeny1) *
1661 (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1);
1662 else
1663 {
1664 int x1, y1, x2, y2;
1665 if (!x->gl_owner)
1666 bug("glist_pixelstox");
1667 graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
1668 return (y1 + (y2 - y1) * (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
1669 }
1670}
1671
1672 /* convert an X screen distance to an X coordinate increment.
1673 This is terribly inefficient;
1674 but probably not a big enough CPU hog to warrant optimizing. */
1675float glist_dpixtodx(t_glist *x, float dxpix)
1676{
1677 return (dxpix * (glist_pixelstox(x, 1) - glist_pixelstox(x, 0)));
1678}
1679
1680float glist_dpixtody(t_glist *x, float dypix)
1681{
1682 return (dypix * (glist_pixelstoy(x, 1) - glist_pixelstoy(x, 0)));
1683}
1684
1685 /* get the window location in pixels of a "text" object. The
1686 object's x and y positions are in pixels when the glist they're
1687 in is toplevel. If it's not, we convert to pixels on the parent
1688 window. */
1689int text_xpix(t_text *x, t_glist *glist)
1690{
1691 if (glist->gl_havewindow || !glist->gl_isgraph)
1692 return (x->te_xpix);
1693 else return (glist_xtopixels(glist,
1694 glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
1695 x->te_xpix / (glist->gl_screenx2 - glist->gl_screenx1)));
1696}
1697
1698int text_ypix(t_text *x, t_glist *glist)
1699{
1700 if (glist->gl_havewindow || !glist->gl_isgraph)
1701 return (x->te_ypix);
1702 else return (glist_ytopixels(glist,
1703 glist->gl_y1 + (glist->gl_y2 - glist->gl_y1) *
1704 x->te_ypix / (glist->gl_screeny2 - glist->gl_screeny1)));
1705}
1706
1707 /* redraw all the items in a glist. We construe this to mean
1708 redrawing in its own window and on parent, as needed in each case.
1709 This is too conservative -- for instance, when you draw an "open"
1710 rectangle on the parent, you shouldn't have to redraw the window! */
1711void glist_redraw(t_glist *x)
1712{
1713 if (glist_isvisible(x))
1714 {
1715 /* LATER fix the graph_vis() code to handle both cases */
1716 if (glist_istoplevel(x))
1717 {
1718 t_gobj *g;
1719 t_linetraverser t;
1720 t_outconnect *oc;
1721 for (g = x->gl_list; g; g = g->g_next)
1722 {
1723 gobj_vis(g, x, 0);
1724 gobj_vis(g, x, 1);
1725 }
1726 /* redraw all the lines */
1727 linetraverser_start(&t, x);
1728 while (oc = linetraverser_next(&t))
1729 sys_vgui(".x%x.c coords l%x %d %d %d %d\n",
1730 glist_getcanvas(x), oc,
1731 t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2);
1732 }
1733 if (x->gl_owner)
1734 {
1735 graph_vis(&x->gl_gobj, x->gl_owner, 0);
1736 graph_vis(&x->gl_gobj, x->gl_owner, 1);
1737 }
1738 }
1739}
1740
1741/* --------------------------- widget behavior ------------------- */
1742
1743extern t_widgetbehavior text_widgetbehavior;
1744
1745 /* Note that some code in here would also be useful for drawing
1746 graph decorations in toplevels... */
1747static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
1748{
1749 t_glist *x = (t_glist *)gr;
1750 char tag[50];
1751 t_gobj *g;
1752 int x1, y1, x2, y2;
1753 /* ordinary subpatches: just act like a text object */
1754 if (!x->gl_isgraph)
1755 {
1756 text_widgetbehavior.w_visfn(gr, parent_glist, vis);
1757 return;
1758 }
1759
1760 if (vis && canvas_showtext(x))
1761 rtext_draw(glist_findrtext(parent_glist, &x->gl_obj));
1762 graph_getrect(gr, parent_glist, &x1, &y1, &x2, &y2);
1763 if (!vis)
1764 rtext_erase(glist_findrtext(parent_glist, &x->gl_obj));
1765
1766 sprintf(tag, "graph%x", (int)x);
1767 if (vis)
1768 glist_drawiofor(parent_glist, &x->gl_obj, 1,
1769 tag, x1, y1, x2, y2);
1770 else glist_eraseiofor(parent_glist, &x->gl_obj, tag);
1771 /* if we look like a graph but have been moved to a toplevel,
1772 just show the bounding rectangle */
1773 if (x->gl_havewindow)
1774 {
1775 if (vis)
1776 {
1777 sys_vgui(".x%x.c create polygon\
1778 %d %d %d %d %d %d %d %d %d %d -tags %s -fill #c0c0c0\n",
1779 glist_getcanvas(x->gl_owner),
1780 x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
1781 }
1782 else
1783 {
1784 sys_vgui(".x%x.c delete %s\n",
1785 glist_getcanvas(x->gl_owner), tag);
1786 }
1787 return;
1788 }
1789 /* otherwise draw (or erase) us as a graph inside another glist. */
1790 if (vis)
1791 {
1792 int i;
1793 float f;
1794
1795 /* draw a rectangle around the graph */
1796 sys_vgui(".x%x.c create line\
1797 %d %d %d %d %d %d %d %d %d %d -tags %s\n",
1798 glist_getcanvas(x->gl_owner),
1799 x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
1800
1801 /* draw ticks on horizontal borders. If lperb field is
1802 zero, this is disabled. */
1803 if (x->gl_xtick.k_lperb)
1804 {
1805 float upix, lpix;
1806 if (y2 < y1)
1807 upix = y1, lpix = y2;
1808 else upix = y2, lpix = y1;
1809 for (i = 0, f = x->gl_xtick.k_point;
1810 f < 0.99 * x->gl_x2 + 0.01*x->gl_x1; i++,
1811 f += x->gl_xtick.k_inc)
1812 {
1813 int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4);
1814 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1815 glist_getcanvas(x->gl_owner),
1816 (int)glist_xtopixels(x, f), (int)upix,
1817 (int)glist_xtopixels(x, f), (int)upix - tickpix, tag);
1818 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1819 glist_getcanvas(x->gl_owner),
1820 (int)glist_xtopixels(x, f), (int)lpix,
1821 (int)glist_xtopixels(x, f), (int)lpix + tickpix, tag);
1822 }
1823 for (i = 1, f = x->gl_xtick.k_point - x->gl_xtick.k_inc;
1824 f > 0.99 * x->gl_x1 + 0.01*x->gl_x2;
1825 i++, f -= x->gl_xtick.k_inc)
1826 {
1827 int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4);
1828 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1829 glist_getcanvas(x->gl_owner),
1830 (int)glist_xtopixels(x, f), (int)upix,
1831 (int)glist_xtopixels(x, f), (int)upix - tickpix, tag);
1832 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1833 glist_getcanvas(x->gl_owner),
1834 (int)glist_xtopixels(x, f), (int)lpix,
1835 (int)glist_xtopixels(x, f), (int)lpix + tickpix, tag);
1836 }
1837 }
1838
1839 /* draw ticks in vertical borders*/
1840 if (x->gl_ytick.k_lperb)
1841 {
1842 float ubound, lbound;
1843 if (x->gl_y2 < x->gl_y1)
1844 ubound = x->gl_y1, lbound = x->gl_y2;
1845 else ubound = x->gl_y2, lbound = x->gl_y1;
1846 for (i = 0, f = x->gl_ytick.k_point;
1847 f < 0.99 * ubound + 0.01 * lbound;
1848 i++, f += x->gl_ytick.k_inc)
1849 {
1850 int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4);
1851 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1852 glist_getcanvas(x->gl_owner),
1853 x1, (int)glist_ytopixels(x, f),
1854 x1 + tickpix, (int)glist_ytopixels(x, f), tag);
1855 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1856 glist_getcanvas(x->gl_owner),
1857 x2, (int)glist_ytopixels(x, f),
1858 x2 - tickpix, (int)glist_ytopixels(x, f), tag);
1859 }
1860 for (i = 1, f = x->gl_ytick.k_point - x->gl_ytick.k_inc;
1861 f > 0.99 * lbound + 0.01 * ubound;
1862 i++, f -= x->gl_ytick.k_inc)
1863 {
1864 int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4);
1865 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1866 glist_getcanvas(x->gl_owner),
1867 x1, (int)glist_ytopixels(x, f),
1868 x1 + tickpix, (int)glist_ytopixels(x, f), tag);
1869 sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
1870 glist_getcanvas(x->gl_owner),
1871 x2, (int)glist_ytopixels(x, f),
1872 x2 - tickpix, (int)glist_ytopixels(x, f), tag);
1873 }
1874 }
1875 /* draw x labels */
1876 for (i = 0; i < x->gl_nxlabels; i++)
1877 sys_vgui(".x%x.c create text\
1878 %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
1879 glist_getcanvas(x),
1880 (int)glist_xtopixels(x, atof(x->gl_xlabel[i]->s_name)),
1881 (int)glist_ytopixels(x, x->gl_xlabely), x->gl_xlabel[i]->s_name,
1882 glist_getfont(x), tag);
1883
1884 /* draw y labels */
1885 for (i = 0; i < x->gl_nylabels; i++)
1886 sys_vgui(".x%x.c create text\
1887 %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
1888 glist_getcanvas(x),
1889 (int)glist_xtopixels(x, x->gl_ylabelx),
1890 (int)glist_ytopixels(x, atof(x->gl_ylabel[i]->s_name)),
1891 x->gl_ylabel[i]->s_name,
1892 glist_getfont(x), tag);
1893
1894 /* draw contents of graph as glist */
1895 for (g = x->gl_list; g; g = g->g_next)
1896 gobj_vis(g, x, 1);
1897 }
1898 else
1899 {
1900 sys_vgui(".x%x.c delete %s\n",
1901 glist_getcanvas(x->gl_owner), tag);
1902 for (g = x->gl_list; g; g = g->g_next)
1903 gobj_vis(g, x, 0);
1904 }
1905}
1906
1907 /* get the graph's rectangle, not counting extra swelling for controls
1908 to keep them inside the graph. This is the "logical" pixel size. */
1909
1910static void graph_graphrect(t_gobj *z, t_glist *glist,
1911 int *xp1, int *yp1, int *xp2, int *yp2)
1912{
1913 t_glist *x = (t_glist *)z;
1914 int x1 = text_xpix(&x->gl_obj, glist);
1915 int y1 = text_ypix(&x->gl_obj, glist);
1916 int x2, y2;
1917#if 0 /* this used to adjust graph size when it was in another graph;
1918 now we just preserve the size. */
1919 /* same logic here as in text_xpix(): */
1920 if (glist->gl_havewindow)
1921 {
1922 x2 = x1 + x->gl_pixwidth;
1923 y2 = y1 + x->gl_pixheight;
1924 }
1925 else
1926 {
1927 x2 = glist_xtopixels(glist,
1928 glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
1929 (x->gl_obj.te_xpix + x->gl_pixwidth) /
1930 (glist->gl_screenx2 - glist->gl_screenx1));
1931 y2 = glist_ytopixels(glist,
1932 glist->gl_y1 + (glist->gl_y2 - glist->gl_y1) *
1933 (x->gl_obj.te_ypix + x->gl_pixheight) /
1934 (glist->gl_screeny2 - glist->gl_screeny1));
1935 }
1936#endif
1937 x2 = x1 + x->gl_pixwidth;
1938 y2 = y1 + x->gl_pixheight;
1939
1940 *xp1 = x1;
1941 *yp1 = y1;
1942 *xp2 = x2;
1943 *yp2 = y2;
1944}
1945
1946 /* get the rectangle, enlarged to contain all the "contents" --
1947 meaning their formal bounds rectangles. */
1948static void graph_getrect(t_gobj *z, t_glist *glist,
1949 int *xp1, int *yp1, int *xp2, int *yp2)
1950{
1951 int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
1952 t_glist *x = (t_glist *)z;
1953 if (x->gl_isgraph)
1954 {
1955 int hadwindow;
1956 t_gobj *g;
1957 t_text *ob;
1958 int x21, y21, x22, y22;
1959
1960 graph_graphrect(z, glist, &x1, &y1, &x2, &y2);
1961 if (canvas_showtext(x))
1962 {
1963 text_widgetbehavior.w_getrectfn(z, glist, &x21, &y21, &x22, &y22);
1964 if (x22 > x2)
1965 x2 = x22;
1966 if (y22 > y2)
1967 y2 = y22;
1968 }
1969 /* lie about whether we have our own window to affect gobj_getrect
1970 calls below. (LATER add argument to gobj_getrect()?) */
1971 hadwindow = x->gl_havewindow;
1972 x->gl_havewindow = 0;
1973 for (g = x->gl_list; g; g = g->g_next)
1974 if ((!(ob = pd_checkobject(&g->g_pd))) || text_shouldvis(ob, x))
1975 {
1976 /* don't do this for arrays, just let them hang outsize the
1977 box. */
1978 if (pd_class(&g->g_pd) == garray_class)
1979 continue;
1980 gobj_getrect(g, x, &x21, &y21, &x22, &y22);
1981 if (x22 > x2)
1982 x2 = x22;
1983 if (y22 > y2)
1984 y2 = y22;
1985 }
1986 x->gl_havewindow = hadwindow;
1987 }
1988 else text_widgetbehavior.w_getrectfn(z, glist, &x1, &y1, &x2, &y2);
1989 *xp1 = x1;
1990 *yp1 = y1;
1991 *xp2 = x2;
1992 *yp2 = y2;
1993}
1994
1995static void graph_displace(t_gobj *z, t_glist *glist, int dx, int dy)
1996{
1997 t_glist *x = (t_glist *)z;
1998 if (!x->gl_isgraph)
1999 text_widgetbehavior.w_displacefn(z, glist, dx, dy);
2000 else
2001 {
2002 x->gl_obj.te_xpix += dx;
2003 x->gl_obj.te_ypix += dy;
2004 glist_redraw(x);
2005 canvas_fixlinesfor(glist_getcanvas(glist), &x->gl_obj);
2006 }
2007}
2008
2009static void graph_select(t_gobj *z, t_glist *glist, int state)
2010{
2011 t_glist *x = (t_glist *)z;
2012 if (!x->gl_isgraph)
2013 text_widgetbehavior.w_selectfn(z, glist, state);
2014 else
2015 {
2016 t_rtext *y = glist_findrtext(glist, &x->gl_obj);
2017 if (canvas_showtext(x))
2018 rtext_select(y, state);
2019 sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
2020 rtext_gettag(y), (state? "blue" : "black"));
2021 sys_vgui(".x%x.c itemconfigure graph%x -fill %s\n",
2022 glist_getcanvas(glist), z, (state? "blue" : "black"));
2023 }
2024}
2025
2026static void graph_activate(t_gobj *z, t_glist *glist, int state)
2027{
2028 t_glist *x = (t_glist *)z;
2029 if (canvas_showtext(x))
2030 text_widgetbehavior.w_activatefn(z, glist, state);
2031}
2032
2033#if 0
2034static void graph_delete(t_gobj *z, t_glist *glist)
2035{
2036 t_glist *x = (t_glist *)z;
2037 if (!x->gl_isgraph)
2038 text_widgetbehavior.w_deletefn(z, glist);
2039 else
2040 {
2041 t_gobj *y;
2042 while (y = x->gl_list) glist_delete(x, y);
2043#if 0 /* I think this was just wrong. */
2044 if (glist_isvisible(x))
2045 sys_vgui(".x%x.c delete graph%x\n", glist_getcanvas(glist), x);
2046#endif
2047 }
2048}
2049#endif
2050
2051static void graph_delete(t_gobj *z, t_glist *glist)
2052{
2053 t_glist *x = (t_glist *)z;
2054 t_gobj *y;
2055 text_widgetbehavior.w_deletefn(z, glist);
2056 while (y = x->gl_list)
2057 glist_delete(x, y);
2058}
2059
2060static float graph_lastxpix, graph_lastypix;
2061
2062static void graph_motion(void *z, t_floatarg dx, t_floatarg dy)
2063{
2064 t_glist *x = (t_glist *)z;
2065 float newxpix = graph_lastxpix + dx, newypix = graph_lastypix + dy;
2066 t_garray *a = (t_garray *)(x->gl_list);
2067 int oldx = 0.5 + glist_pixelstox(x, graph_lastxpix);
2068 int newx = 0.5 + glist_pixelstox(x, newxpix);
2069 t_sample *vec;
2070 int nelem, i;
2071 float oldy = glist_pixelstoy(x, graph_lastypix);
2072 float newy = glist_pixelstoy(x, newypix);
2073 graph_lastxpix = newxpix;
2074 graph_lastypix = newypix;
2075 /* verify that the array is OK */
2076 if (!a || pd_class((t_pd *)a) != garray_class)
2077 return;
2078 if (!garray_getfloatarray(a, &nelem, &vec))
2079 return;
2080 if (oldx < 0) oldx = 0;
2081 if (oldx >= nelem)
2082 oldx = nelem - 1;
2083 if (newx < 0) newx = 0;
2084 if (newx >= nelem)
2085 newx = nelem - 1;
2086 if (oldx < newx - 1)
2087 {
2088 for (i = oldx + 1; i <= newx; i++)
2089 vec[i] = newy + (oldy - newy) *
2090 ((float)(newx - i))/(float)(newx - oldx);
2091 }
2092 else if (oldx > newx + 1)
2093 {
2094 for (i = oldx - 1; i >= newx; i--)
2095 vec[i] = newy + (oldy - newy) *
2096 ((float)(newx - i))/(float)(newx - oldx);
2097 }
2098 else vec[newx] = newy;
2099 garray_redraw(a);
2100}
2101
2102static int graph_click(t_gobj *z, struct _glist *glist,
2103 int xpix, int ypix, int shift, int alt, int dbl, int doit)
2104{
2105 t_glist *x = (t_glist *)z;
2106 t_gobj *y;
2107 int clickreturned = 0;
2108 if (!x->gl_isgraph)
2109 return (text_widgetbehavior.w_clickfn(z, glist,
2110 xpix, ypix, shift, alt, dbl, doit));
2111 else if (x->gl_havewindow)
2112 return (0);
2113 else
2114 {
2115 for (y = x->gl_list; y; y = y->g_next)
2116 {
2117 int x1, y1, x2, y2;
2118 /* check if the object wants to be clicked */
2119 if (canvas_hitbox(x, y, xpix, ypix, &x1, &y1, &x2, &y2)
2120 && (clickreturned = gobj_click(y, x, xpix, ypix,
2121 shift, alt, 0, doit)))
2122 break;
2123 }
2124 if (!doit)
2125 {
2126 if (y)
2127 canvas_setcursor(glist_getcanvas(x), clickreturned);
2128 else canvas_setcursor(glist_getcanvas(x), CURSOR_RUNMODE_NOTHING);
2129 }
2130 return (clickreturned);
2131 }
2132}
2133
2134void garray_properties(t_garray *x);
2135
2136t_widgetbehavior graph_widgetbehavior =
2137{
2138 graph_getrect,
2139 graph_displace,
2140 graph_select,
2141 graph_activate,
2142 graph_delete,
2143 graph_vis,
2144 graph_click,
2145};
2146
2147void graph_properties(t_gobj *z, t_glist *owner)
2148{
2149 t_glist *x = (t_glist *)z;
2150 {
2151 t_gobj *y;
2152 char graphbuf[200];
2153 sprintf(graphbuf, "pdtk_graph_dialog %%s %g %g %g %g %d %d\n",
2154 x->gl_x1, x->gl_y1, x->gl_x2, x->gl_y2,
2155 x->gl_pixwidth, x->gl_pixheight);
2156 gfxstub_new(&x->gl_pd, x, graphbuf);
2157
2158 for (y = x->gl_list; y; y = y->g_next)
2159 if (pd_class(&y->g_pd) == garray_class)
2160 garray_properties((t_garray *)y);
2161 }
2162}
2163
2164 /* find the graph most recently added to this glist;
2165 if none exists, return 0. */
2166
2167t_glist *glist_findgraph(t_glist *x)
2168{
2169 t_gobj *y = 0, *z;
2170 for (z = x->gl_list; z; z = z->g_next)
2171 if (pd_class(&z->g_pd) == canvas_class && ((t_glist *)z)->gl_isgraph)
2172 y = z;
2173 return ((t_glist *)y);
2174}
2175
2176 /* message back from dialog GUI to set parameters. Args are:
2177 1-4: bounds in our coordinates; 5-6: size in parent */
2178static void graph_dialog(t_glist *x, t_symbol *s, int argc, t_atom *argv)
2179{
2180 t_float x1 = atom_getfloatarg(0, argc, argv);
2181 t_float y1 = atom_getfloatarg(1, argc, argv);
2182 t_float x2 = atom_getfloatarg(2, argc, argv);
2183 t_float y2 = atom_getfloatarg(3, argc, argv);
2184 t_float xpix = atom_getfloatarg(4, argc, argv);
2185 t_float ypix = atom_getfloatarg(5, argc, argv);
2186 if (x1 != x->gl_x1 || x2 != x->gl_x2 ||
2187 y1 != x->gl_y1 || y2 != x->gl_y2)
2188 graph_bounds(x, x1, y1, x2, y2);
2189 if (xpix != x->gl_pixwidth || ypix != x->gl_pixheight)
2190 {
2191 x->gl_pixwidth = xpix;
2192 x->gl_pixheight = ypix;
2193 glist_redraw(x);
2194 if (x->gl_owner)
2195 canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
2196 }
2197}
2198
2199extern void canvas_menuarray(t_glist *canvas);
2200
2201void g_graph_setup(void)
2202{
2203 class_setwidget(canvas_class, &graph_widgetbehavior);
2204 class_addmethod(canvas_class, (t_method)graph_bounds, gensym("bounds"),
2205 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
2206 class_addmethod(canvas_class, (t_method)graph_xticks, gensym("xticks"),
2207 A_FLOAT, A_FLOAT, A_FLOAT, 0);
2208 class_addmethod(canvas_class, (t_method)graph_xlabel, gensym("xlabel"),
2209 A_GIMME, 0);
2210 class_addmethod(canvas_class, (t_method)graph_yticks, gensym("yticks"),
2211 A_FLOAT, A_FLOAT, A_FLOAT, 0);
2212 class_addmethod(canvas_class, (t_method)graph_ylabel, gensym("ylabel"),
2213 A_GIMME, 0);
2214 class_addmethod(canvas_class, (t_method)graph_array, gensym("array"),
2215 A_SYMBOL, A_FLOAT, A_SYMBOL, A_DEFFLOAT, A_NULL);
2216 class_addmethod(canvas_class, (t_method)canvas_menuarray,
2217 gensym("menuarray"), A_NULL);
2218 class_addmethod(canvas_class, (t_method)graph_dialog, gensym("dialog"),
2219 A_GIMME, 0);
2220 class_addmethod(canvas_class, (t_method)glist_arraydialog,
2221 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
2222 class_addmethod(canvas_class, (t_method)glist_sort,
2223 gensym("sort"), A_NULL);
2224}
diff --git a/apps/plugins/pdbox/PDa/src/g_guiconnect.c b/apps/plugins/pdbox/PDa/src/g_guiconnect.c
new file mode 100644
index 0000000000..c1673827fe
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_guiconnect.c
@@ -0,0 +1,188 @@
1/* Copyright (c) 1997-2000 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* a thing to forward messages from the GUI, dealing with race conditions
6in which the "target" gets deleted while the GUI is sending it something.
7*/
8
9#include "m_pd.h"
10#include "g_canvas.h"
11
12struct _guiconnect
13{
14 t_object x_obj;
15 t_pd *x_who;
16 t_symbol *x_sym;
17 t_clock *x_clock;
18};
19
20static t_class *guiconnect_class;
21
22t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym)
23{
24 t_guiconnect *x = (t_guiconnect *)pd_new(guiconnect_class);
25 x->x_who = who;
26 x->x_sym = sym;
27 pd_bind(&x->x_obj.ob_pd, sym);
28 return (x);
29}
30
31 /* cleanup routine; delete any resources we have */
32static void guiconnect_free(t_guiconnect *x)
33{
34 if (x->x_sym)
35 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
36 if (x->x_clock)
37 clock_free(x->x_clock);
38}
39
40 /* this is called when the clock times out to indicate the GUI should
41 be gone by now. */
42static void guiconnect_tick(t_guiconnect *x)
43{
44 pd_free(&x->x_obj.ob_pd);
45}
46
47 /* the target calls this to disconnect. If the gui has "signed off"
48 we're ready to delete the object; otherwise we wait either for signoff
49 or for a timeout. */
50void guiconnect_notarget(t_guiconnect *x, double timedelay)
51{
52 if (!x->x_sym)
53 pd_free(&x->x_obj.ob_pd);
54 else
55 {
56 x->x_who = 0;
57 if (timedelay > 0)
58 {
59 x->x_clock = clock_new(x, (t_method)guiconnect_tick);
60 clock_delay(x->x_clock, timedelay);
61 }
62 }
63}
64
65 /* the GUI calls this to send messages to the target. */
66static void guiconnect_anything(t_guiconnect *x,
67 t_symbol *s, int ac, t_atom *av)
68{
69 if (x->x_who)
70 typedmess(x->x_who, s, ac, av);
71}
72
73 /* the GUI calls this when it disappears. (If there's any chance the
74 GUI will fail to do this, the "target", when it signs off, should specify
75 a timeout after which the guiconnect will disappear.) */
76static void guiconnect_signoff(t_guiconnect *x)
77{
78 if (!x->x_who)
79 pd_free(&x->x_obj.ob_pd);
80 else
81 {
82 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
83 x->x_sym = 0;
84 }
85}
86
87void g_guiconnect_setup(void)
88{
89 guiconnect_class = class_new(gensym("guiconnect"), 0,
90 (t_method)guiconnect_free, sizeof(t_guiconnect), CLASS_PD, 0);
91 class_addanything(guiconnect_class, guiconnect_anything);
92 class_addmethod(guiconnect_class, (t_method)guiconnect_signoff,
93 gensym("signoff"), 0);
94}
95/* Copyright (c) 1997-2000 Miller Puckette.
96* For information on usage and redistribution, and for a DISCLAIMER OF ALL
97* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
98
99/* a thing to forward messages from the GUI, dealing with race conditions
100in which the "target" gets deleted while the GUI is sending it something.
101*/
102
103#include "m_pd.h"
104#include "g_canvas.h"
105
106struct _guiconnect
107{
108 t_object x_obj;
109 t_pd *x_who;
110 t_symbol *x_sym;
111 t_clock *x_clock;
112};
113
114static t_class *guiconnect_class;
115
116t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym)
117{
118 t_guiconnect *x = (t_guiconnect *)pd_new(guiconnect_class);
119 x->x_who = who;
120 x->x_sym = sym;
121 pd_bind(&x->x_obj.ob_pd, sym);
122 return (x);
123}
124
125 /* cleanup routine; delete any resources we have */
126static void guiconnect_free(t_guiconnect *x)
127{
128 if (x->x_sym)
129 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
130 if (x->x_clock)
131 clock_free(x->x_clock);
132}
133
134 /* this is called when the clock times out to indicate the GUI should
135 be gone by now. */
136static void guiconnect_tick(t_guiconnect *x)
137{
138 pd_free(&x->x_obj.ob_pd);
139}
140
141 /* the target calls this to disconnect. If the gui has "signed off"
142 we're ready to delete the object; otherwise we wait either for signoff
143 or for a timeout. */
144void guiconnect_notarget(t_guiconnect *x, double timedelay)
145{
146 if (!x->x_sym)
147 pd_free(&x->x_obj.ob_pd);
148 else
149 {
150 x->x_who = 0;
151 if (timedelay > 0)
152 {
153 x->x_clock = clock_new(x, (t_method)guiconnect_tick);
154 clock_delay(x->x_clock, timedelay);
155 }
156 }
157}
158
159 /* the GUI calls this to send messages to the target. */
160static void guiconnect_anything(t_guiconnect *x,
161 t_symbol *s, int ac, t_atom *av)
162{
163 if (x->x_who)
164 typedmess(x->x_who, s, ac, av);
165}
166
167 /* the GUI calls this when it disappears. (If there's any chance the
168 GUI will fail to do this, the "target", when it signs off, should specify
169 a timeout after which the guiconnect will disappear.) */
170static void guiconnect_signoff(t_guiconnect *x)
171{
172 if (!x->x_who)
173 pd_free(&x->x_obj.ob_pd);
174 else
175 {
176 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
177 x->x_sym = 0;
178 }
179}
180
181void g_guiconnect_setup(void)
182{
183 guiconnect_class = class_new(gensym("guiconnect"), 0,
184 (t_method)guiconnect_free, sizeof(t_guiconnect), CLASS_PD, 0);
185 class_addanything(guiconnect_class, guiconnect_anything);
186 class_addmethod(guiconnect_class, (t_method)guiconnect_signoff,
187 gensym("signoff"), 0);
188}
diff --git a/apps/plugins/pdbox/PDa/src/g_hdial.c b/apps/plugins/pdbox/PDa/src/g_hdial.c
new file mode 100644
index 0000000000..447e984244
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_hdial.c
@@ -0,0 +1,1470 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
7
8/* name change to hradio by MSP and changed to
9put out a "float" as in sliders, toggles, etc. */
10
11#include <stdlib.h>
12#include <string.h>
13#include <stdio.h>
14#include <ctype.h>
15#include "m_pd.h"
16#include "g_canvas.h"
17#include "t_tk.h"
18#include "g_all_guis.h"
19#include <math.h>
20
21#ifdef MSW
22#include <io.h>
23#else
24#include <unistd.h>
25#endif
26
27/* ------------- hdl gui-horicontal dial ---------------------- */
28
29t_widgetbehavior hradio_widgetbehavior;
30static t_class *hradio_class, *hradio_old_class;
31
32/* widget helper functions */
33
34void hradio_draw_update(t_hradio *x, t_glist *glist)
35{
36 if(glist_isvisible(glist))
37 {
38 t_canvas *canvas=glist_getcanvas(glist);
39
40 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
41 canvas, x, x->x_on_old,
42 x->x_gui.x_bcol, x->x_gui.x_bcol);
43 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
44 canvas, x, x->x_on,
45 x->x_gui.x_fcol, x->x_gui.x_fcol);
46 }
47}
48
49void hradio_draw_new(t_hradio *x, t_glist *glist)
50{
51 t_canvas *canvas=glist_getcanvas(glist);
52 int n=x->x_number, i, dx=x->x_gui.x_w, s4=dx/4;
53 int yy11=text_ypix(&x->x_gui.x_obj, glist), yy12=yy11+dx;
54 int yy21=yy11+s4, yy22=yy12-s4;
55 int xx11b=text_xpix(&x->x_gui.x_obj, glist), xx11=xx11b, xx21=xx11b+s4;
56 int xx22=xx11b+dx-s4;
57
58
59 for(i=0; i<n; i++)
60 {
61 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE%d\n",
62 canvas, xx11, yy11, xx11+dx, yy12,
63 x->x_gui.x_bcol, x, i);
64 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xBUT%d\n",
65 canvas, xx21, yy21, xx22, yy22,
66 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
67 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol, x, i);
68 xx11 += dx;
69 xx21 += dx;
70 xx22 += dx;
71 }
72 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
73 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
74 canvas, xx11b+x->x_gui.x_ldx, yy11+x->x_gui.x_ldy,
75 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
76 x->x_gui.x_font, x->x_gui.x_fontsize,
77 x->x_gui.x_lcol, x);
78 if(!x->x_gui.x_fsf.x_snd_able)
79 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
80 canvas, xx11b, yy12-1, xx11b + IOWIDTH, yy12, x, 0);
81 if(!x->x_gui.x_fsf.x_rcv_able)
82 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
83 canvas, xx11b, yy11, xx11b + IOWIDTH, yy11+1, x, 0);
84
85}
86
87void hradio_draw_move(t_hradio *x, t_glist *glist)
88{
89 t_canvas *canvas=glist_getcanvas(glist);
90 int n=x->x_number, i, dx=x->x_gui.x_w, s4=dx/4;
91 int yy11=text_ypix(&x->x_gui.x_obj, glist), yy12=yy11+dx;
92 int yy21=yy11+s4, yy22=yy12-s4;
93 int xx11b=text_xpix(&x->x_gui.x_obj, glist), xx11=xx11b, xx21=xx11b+s4;
94 int xx22=xx11b+dx-s4;
95
96 xx11 = xx11b;
97 xx21=xx11b+s4;
98 xx22=xx11b+dx-s4;
99 for(i=0; i<n; i++)
100 {
101 sys_vgui(".x%x.c coords %xBASE%d %d %d %d %d\n",
102 canvas, x, i, xx11, yy11, xx11+dx, yy12);
103 sys_vgui(".x%x.c coords %xBUT%d %d %d %d %d\n",
104 canvas, x, i, xx21, yy21, xx22, yy22);
105 xx11 += dx;
106 xx21 += dx;
107 xx22 += dx;
108 }
109 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
110 canvas, x, xx11b+x->x_gui.x_ldx, yy11+x->x_gui.x_ldy);
111 if(!x->x_gui.x_fsf.x_snd_able)
112 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
113 canvas, x, 0, xx11b, yy12-1, xx11b + IOWIDTH, yy12);
114 if(!x->x_gui.x_fsf.x_rcv_able)
115 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
116 canvas, x, 0, xx11b, yy11, xx11b + IOWIDTH, yy11+1);
117}
118
119void hradio_draw_erase(t_hradio* x, t_glist* glist)
120{
121 t_canvas *canvas=glist_getcanvas(glist);
122 int n=x->x_number, i;
123
124 for(i=0; i<n; i++)
125 {
126 sys_vgui(".x%x.c delete %xBASE%d\n", canvas, x, i);
127 sys_vgui(".x%x.c delete %xBUT%d\n", canvas, x, i);
128 }
129 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
130 if(!x->x_gui.x_fsf.x_snd_able)
131 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
132 if(!x->x_gui.x_fsf.x_rcv_able)
133 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
134}
135
136void hradio_draw_config(t_hradio* x, t_glist* glist)
137{
138 t_canvas *canvas=glist_getcanvas(glist);
139 int n=x->x_number, i;
140
141 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
142 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
143 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
144 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
145 for(i=0; i<n; i++)
146 {
147 sys_vgui(".x%x.c itemconfigure %xBASE%d -fill #%6.6x\n", canvas, x, i,
148 x->x_gui.x_bcol);
149 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n", canvas, x, i,
150 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
151 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol);
152 }
153}
154
155void hradio_draw_io(t_hradio* x, t_glist* glist, int old_snd_rcv_flags)
156{
157 t_canvas *canvas=glist_getcanvas(glist);
158 int xpos=text_xpix(&x->x_gui.x_obj, glist);
159 int ypos=text_ypix(&x->x_gui.x_obj, glist);
160
161 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
162 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
163 canvas,
164 xpos, ypos + x->x_gui.x_w-1,
165 xpos + IOWIDTH, ypos + x->x_gui.x_w,
166 x, 0);
167 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
168 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
169 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
170 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
171 canvas,
172 xpos, ypos,
173 xpos + IOWIDTH, ypos+1, x, 0);
174 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
175 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
176}
177
178void hradio_draw_select(t_hradio* x, t_glist* glist)
179{
180 t_canvas *canvas=glist_getcanvas(glist);
181 int n=x->x_number, i;
182
183 if(x->x_gui.x_fsf.x_selected)
184 {
185 for(i=0; i<n; i++)
186 {
187 sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
188 IEM_GUI_COLOR_SELECTED);
189 }
190 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
191 }
192 else
193 {
194 for(i=0; i<n; i++)
195 {
196 sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
197 IEM_GUI_COLOR_NORMAL);
198 }
199 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x,
200 x->x_gui.x_lcol);
201 }
202}
203
204void hradio_draw(t_hradio *x, t_glist *glist, int mode)
205{
206 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
207 hradio_draw_update(x, glist);
208 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
209 hradio_draw_move(x, glist);
210 else if(mode == IEM_GUI_DRAW_MODE_NEW)
211 hradio_draw_new(x, glist);
212 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
213 hradio_draw_select(x, glist);
214 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
215 hradio_draw_erase(x, glist);
216 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
217 hradio_draw_config(x, glist);
218 else if(mode >= IEM_GUI_DRAW_MODE_IO)
219 hradio_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
220}
221
222/* ------------------------ hdl widgetbehaviour----------------------------- */
223
224static void hradio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
225{
226 t_hradio *x = (t_hradio *)z;
227
228 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
229 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
230 *xp2 = *xp1 + x->x_gui.x_w*x->x_number;
231 *yp2 = *yp1 + x->x_gui.x_h;
232}
233
234static void hradio_save(t_gobj *z, t_binbuf *b)
235{
236 t_hradio *x = (t_hradio *)z;
237 int bflcol[3];
238 t_symbol *srl[3];
239
240 iemgui_save(&x->x_gui, srl, bflcol);
241 binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"),
242 (t_int)text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist),
243 (t_int)text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist),
244 (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class ?
245 gensym("hdl") : gensym("hradio")),
246 x->x_gui.x_w,
247 x->x_change, iem_symargstoint(&x->x_gui.x_isa), x->x_number,
248 srl[0], srl[1], srl[2],
249 x->x_gui.x_ldx, x->x_gui.x_ldy,
250 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
251 bflcol[0], bflcol[1], bflcol[2], x->x_on);
252 binbuf_addv(b, ";");
253}
254
255static void hradio_properties(t_gobj *z, t_glist *owner)
256{
257 t_hradio *x = (t_hradio *)z;
258 char buf[800];
259 t_symbol *srl[3];
260 int hchange=-1;
261
262 iemgui_properties(&x->x_gui, srl);
263 if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
264 hchange = x->x_change;
265 sprintf(buf, "pdtk_iemgui_dialog %%s hradio \
266 ----------dimensions(pix):----------- %d %d size: 0 0 empty \
267 empty 0.0 empty 0.0 empty %d \
268 %d new-only new&old %d %d number: %d \
269 %s %s \
270 %s %d %d \
271 %d %d \
272 %d %d %d\n",
273 x->x_gui.x_w, IEM_GUI_MINSIZE,
274 0,/*no_schedule*/
275 hchange, x->x_gui.x_isa.x_loadinit, -1, x->x_number,
276 srl[0]->s_name, srl[1]->s_name,
277 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
278 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
279 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
280 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
281}
282
283static void hradio_dialog(t_hradio *x, t_symbol *s, int argc, t_atom *argv)
284{
285 t_symbol *srl[3];
286 int a = (int)atom_getintarg(0, argc, argv);
287 int chg = (int)atom_getintarg(4, argc, argv);
288 int num = (int)atom_getintarg(6, argc, argv);
289 int sr_flags;
290
291 if(chg != 0) chg = 1;
292 x->x_change = chg;
293 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
294 x->x_gui.x_w = iemgui_clip_size(a);
295 x->x_gui.x_h = x->x_gui.x_w;
296 if(x->x_number != num)
297 {
298 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
299 x->x_number = num;
300 if(x->x_on >= x->x_number)
301 {
302 x->x_on = x->x_number - 1;
303 x->x_on_old = x->x_on;
304 }
305 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
306 }
307 else
308 {
309 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
310 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
311 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
312 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
313 }
314
315}
316
317static void hradio_set(t_hradio *x, t_floatarg f)
318{
319 int i=(int)f;
320 int old=x->x_on_old;
321
322 if(i < 0)
323 i = 0;
324 if(i >= x->x_number)
325 i = x->x_number-1;
326 if(x->x_on != x->x_on_old)
327 {
328 old = x->x_on_old;
329 x->x_on_old = x->x_on;
330 x->x_on = i;
331 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
332 x->x_on_old = old;
333 }
334 else
335 {
336 x->x_on = i;
337 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
338 }
339}
340
341static void hradio_bang(t_hradio *x)
342{
343 /* compatibility with earlier "hdial" behavior */
344 if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
345 {
346 if((x->x_change)&&(x->x_on != x->x_on_old))
347 {
348 SETFLOAT(x->x_at, (float)x->x_on_old);
349 SETFLOAT(x->x_at+1, 0.0);
350 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
351 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
352 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
353 }
354 x->x_on_old = x->x_on;
355 SETFLOAT(x->x_at, (float)x->x_on);
356 SETFLOAT(x->x_at+1, 1.0);
357 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
358 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
359 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
360 }
361 else
362 {
363 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
364 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
365 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
366 }
367}
368
369static void hradio_fout(t_hradio *x, t_floatarg f)
370{
371 int i=(int)f;
372
373 if(i < 0)
374 i = 0;
375 if(i >= x->x_number)
376 i = x->x_number-1;
377
378 if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
379 {
380 if((x->x_change)&&(i != x->x_on_old))
381 {
382 SETFLOAT(x->x_at, (float)x->x_on_old);
383 SETFLOAT(x->x_at+1, 0.0);
384 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
385 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
386 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
387 }
388 if(x->x_on != x->x_on_old)
389 x->x_on_old = x->x_on;
390 x->x_on = i;
391 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
392 x->x_on_old = x->x_on;
393 SETFLOAT(x->x_at, (float)x->x_on);
394 SETFLOAT(x->x_at+1, 1.0);
395 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
396 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
397 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
398 }
399 else
400 {
401 x->x_on_old = x->x_on;
402 x->x_on = i;
403 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
404 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
405 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
406 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
407 }
408}
409
410static void hradio_float(t_hradio *x, t_floatarg f)
411{
412 int i=(int)f;
413
414 if(i < 0)
415 i = 0;
416 if(i >= x->x_number)
417 i = x->x_number-1;
418
419 if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
420 {
421 /* compatibility with earlier "vdial" behavior */
422 if((x->x_change)&&(i != x->x_on_old))
423 {
424 if(x->x_gui.x_fsf.x_put_in2out)
425 {
426 SETFLOAT(x->x_at, (float)x->x_on_old);
427 SETFLOAT(x->x_at+1, 0.0);
428 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
429 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
430 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
431 }
432 }
433 if(x->x_on != x->x_on_old)
434 x->x_on_old = x->x_on;
435 x->x_on = i;
436 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
437 x->x_on_old = x->x_on;
438 if(x->x_gui.x_fsf.x_put_in2out)
439 {
440 SETFLOAT(x->x_at, (float)x->x_on);
441 SETFLOAT(x->x_at+1, 1.0);
442 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
443 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
444 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
445 }
446 }
447 else
448 {
449 x->x_on_old = x->x_on;
450 x->x_on = i;
451 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
452 if (x->x_gui.x_fsf.x_put_in2out)
453 {
454 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
455 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
456 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
457 }
458 }
459}
460
461static void hradio_click(t_hradio *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
462{
463 int xx = (int)xpos - (int)text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
464
465 hradio_fout(x, (float)(xx / x->x_gui.x_w));
466}
467
468static int hradio_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
469{
470 if(doit)
471 hradio_click((t_hradio *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
472 return (1);
473}
474
475static void hradio_loadbang(t_hradio *x)
476{
477 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
478 hradio_bang(x);
479}
480
481static void hradio_number(t_hradio *x, t_floatarg num)
482{
483 int n=(int)num;
484
485 if(n < 1)
486 n = 1;
487 if(n > IEM_RADIO_MAX)
488 n = IEM_RADIO_MAX;
489 if(n != x->x_number)
490 {
491 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
492 x->x_number = n;
493 if(x->x_on >= x->x_number)
494 x->x_on = x->x_number - 1;
495 x->x_on_old = x->x_on;
496 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
497 }
498}
499
500static void hradio_size(t_hradio *x, t_symbol *s, int ac, t_atom *av)
501{
502 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
503 x->x_gui.x_h = x->x_gui.x_w;
504 iemgui_size((void *)x, &x->x_gui);
505}
506
507static void hradio_delta(t_hradio *x, t_symbol *s, int ac, t_atom *av)
508{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
509
510static void hradio_pos(t_hradio *x, t_symbol *s, int ac, t_atom *av)
511{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
512
513static void hradio_color(t_hradio *x, t_symbol *s, int ac, t_atom *av)
514{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
515
516static void hradio_send(t_hradio *x, t_symbol *s)
517{iemgui_send(x, &x->x_gui, s);}
518
519static void hradio_receive(t_hradio *x, t_symbol *s)
520{iemgui_receive(x, &x->x_gui, s);}
521
522static void hradio_label(t_hradio *x, t_symbol *s)
523{iemgui_label((void *)x, &x->x_gui, s);}
524
525static void hradio_label_pos(t_hradio *x, t_symbol *s, int ac, t_atom *av)
526{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
527
528static void hradio_label_font(t_hradio *x, t_symbol *s, int ac, t_atom *av)
529{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
530
531static void hradio_init(t_hradio *x, t_floatarg f)
532{
533 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
534}
535
536static void hradio_double_change(t_hradio *x)
537{x->x_change = 1;}
538
539static void hradio_single_change(t_hradio *x)
540{x->x_change = 0;}
541
542static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old)
543{
544 t_hradio *x = (t_hradio *)pd_new(old? hradio_old_class : hradio_class);
545 int bflcol[]={-262144, -1, -1};
546 int a=IEM_GUI_DEFAULTSIZE, on=0, f=0;
547 int ldx=0, ldy=-6, chg=1, num=8;
548 int fs=8;
549 int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
550 char str[144];
551
552 iem_inttosymargs(&x->x_gui.x_isa, 0);
553 iem_inttofstyle(&x->x_gui.x_fsf, 0);
554
555 if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
556 &&IS_A_FLOAT(argv,3)
557 &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
558 &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
559 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
560 &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
561 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
562 &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)&&IS_A_FLOAT(argv,14))
563 {
564 a = (int)atom_getintarg(0, argc, argv);
565 chg = (int)atom_getintarg(1, argc, argv);
566 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(2, argc, argv));
567 num = (int)atom_getintarg(3, argc, argv);
568 iemgui_new_getnames(&x->x_gui, 4, argv);
569 ldx = (int)atom_getintarg(7, argc, argv);
570 ldy = (int)atom_getintarg(8, argc, argv);
571 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv));
572 fs = (int)atom_getintarg(10, argc, argv);
573 bflcol[0] = (int)atom_getintarg(11, argc, argv);
574 bflcol[1] = (int)atom_getintarg(12, argc, argv);
575 bflcol[2] = (int)atom_getintarg(13, argc, argv);
576 on = (int)atom_getintarg(14, argc, argv);
577 }
578 else iemgui_new_getnames(&x->x_gui, 4, 0);
579 x->x_gui.x_draw = (t_iemfunptr)hradio_draw;
580 x->x_gui.x_fsf.x_snd_able = 1;
581 x->x_gui.x_fsf.x_rcv_able = 1;
582 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
583 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
584 x->x_gui.x_fsf.x_snd_able = 0;
585 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
586 x->x_gui.x_fsf.x_rcv_able = 0;
587 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
588 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
589 else { x->x_gui.x_fsf.x_font_style = 0;
590 strcpy(x->x_gui.x_font, "courier"); }
591 if(num < 1)
592 num = 1;
593 if(num > IEM_RADIO_MAX)
594 num = IEM_RADIO_MAX;
595 x->x_number = num;
596 if(on < 0)
597 on = 0;
598 if(on >= x->x_number)
599 on = x->x_number - 1;
600 if(x->x_gui.x_isa.x_loadinit)
601 x->x_on = on;
602 else
603 x->x_on = 0;
604 x->x_on_old = x->x_on;
605 x->x_change = (chg==0)?0:1;
606 if (x->x_gui.x_fsf.x_rcv_able)
607 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
608 x->x_gui.x_ldx = ldx;
609 x->x_gui.x_ldy = ldy;
610 if(fs < 4)
611 fs = 4;
612 x->x_gui.x_fontsize = fs;
613 x->x_gui.x_w = iemgui_clip_size(a);
614 x->x_gui.x_h = x->x_gui.x_w;
615 iemgui_verify_snd_ne_rcv(&x->x_gui);
616 iemgui_all_colfromload(&x->x_gui, bflcol);
617 outlet_new(&x->x_gui.x_obj, &s_list);
618 return (x);
619}
620
621static void *hradio_new(t_symbol *s, int argc, t_atom *argv)
622{
623 return (hradio_donew(s, argc, argv, 0));
624}
625
626static void *hdial_new(t_symbol *s, int argc, t_atom *argv)
627{
628 return (hradio_donew(s, argc, argv, 1));
629}
630
631static void hradio_ff(t_hradio *x)
632{
633 if(x->x_gui.x_fsf.x_rcv_able)
634 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
635 gfxstub_deleteforkey(x);
636}
637
638void g_hradio_setup(void)
639{
640 hradio_class = class_new(gensym("hradio"), (t_newmethod)hradio_new,
641 (t_method)hradio_ff, sizeof(t_hradio), 0, A_GIMME, 0);
642 class_addbang(hradio_class, hradio_bang);
643 class_addfloat(hradio_class, hradio_float);
644 class_addmethod(hradio_class, (t_method)hradio_click, gensym("click"),
645 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
646 class_addmethod(hradio_class, (t_method)hradio_dialog, gensym("dialog"),
647 A_GIMME, 0);
648 class_addmethod(hradio_class, (t_method)hradio_loadbang,
649 gensym("loadbang"), 0);
650 class_addmethod(hradio_class, (t_method)hradio_set,
651 gensym("set"), A_FLOAT, 0);
652 class_addmethod(hradio_class, (t_method)hradio_size,
653 gensym("size"), A_GIMME, 0);
654 class_addmethod(hradio_class, (t_method)hradio_delta,
655 gensym("delta"), A_GIMME, 0);
656 class_addmethod(hradio_class, (t_method)hradio_pos,
657 gensym("pos"), A_GIMME, 0);
658 class_addmethod(hradio_class, (t_method)hradio_color,
659 gensym("color"), A_GIMME, 0);
660 class_addmethod(hradio_class, (t_method)hradio_send,
661 gensym("send"), A_DEFSYM, 0);
662 class_addmethod(hradio_class, (t_method)hradio_receive,
663 gensym("receive"), A_DEFSYM, 0);
664 class_addmethod(hradio_class, (t_method)hradio_label,
665 gensym("label"), A_DEFSYM, 0);
666 class_addmethod(hradio_class, (t_method)hradio_label_pos,
667 gensym("label_pos"), A_GIMME, 0);
668 class_addmethod(hradio_class, (t_method)hradio_label_font,
669 gensym("label_font"), A_GIMME, 0);
670 class_addmethod(hradio_class, (t_method)hradio_init,
671 gensym("init"), A_FLOAT, 0);
672 class_addmethod(hradio_class, (t_method)hradio_number,
673 gensym("number"), A_FLOAT, 0);
674 class_addmethod(hradio_class, (t_method)hradio_single_change,
675 gensym("single_change"), 0);
676 class_addmethod(hradio_class, (t_method)hradio_double_change,
677 gensym("double_change"), 0);
678 hradio_widgetbehavior.w_getrectfn = hradio_getrect;
679 hradio_widgetbehavior.w_displacefn = iemgui_displace;
680 hradio_widgetbehavior.w_selectfn = iemgui_select;
681 hradio_widgetbehavior.w_activatefn = NULL;
682 hradio_widgetbehavior.w_deletefn = iemgui_delete;
683 hradio_widgetbehavior.w_visfn = iemgui_vis;
684 hradio_widgetbehavior.w_clickfn = hradio_newclick;
685 class_setwidget(hradio_class, &hradio_widgetbehavior);
686 class_sethelpsymbol(hradio_class, gensym("hradio"));
687 class_setsavefn(hradio_class, hradio_save);
688 class_setpropertiesfn(hradio_class, hradio_properties);
689
690 /*obsolete version (0.34-0.35) */
691 hradio_old_class = class_new(gensym("hdl"), (t_newmethod)hdial_new,
692 (t_method)hradio_ff, sizeof(t_hradio), 0, A_GIMME, 0);
693 class_addcreator((t_newmethod)hradio_new, gensym("rdb"), A_GIMME, 0);
694 class_addcreator((t_newmethod)hradio_new, gensym("radiobut"), A_GIMME, 0);
695 class_addcreator((t_newmethod)hradio_new, gensym("radiobutton"),
696 A_GIMME, 0);
697 class_addbang(hradio_old_class, hradio_bang);
698 class_addfloat(hradio_old_class, hradio_float);
699 class_addmethod(hradio_old_class, (t_method)hradio_click, gensym("click"),
700 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
701 class_addmethod(hradio_old_class, (t_method)hradio_dialog, gensym("dialog"),
702 A_GIMME, 0);
703 class_addmethod(hradio_old_class, (t_method)hradio_loadbang,
704 gensym("loadbang"), 0);
705 class_addmethod(hradio_old_class, (t_method)hradio_set,
706 gensym("set"), A_FLOAT, 0);
707 class_addmethod(hradio_old_class, (t_method)hradio_size,
708 gensym("size"), A_GIMME, 0);
709 class_addmethod(hradio_old_class, (t_method)hradio_delta,
710 gensym("delta"), A_GIMME, 0);
711 class_addmethod(hradio_old_class, (t_method)hradio_pos,
712 gensym("pos"), A_GIMME, 0);
713 class_addmethod(hradio_old_class, (t_method)hradio_color,
714 gensym("color"), A_GIMME, 0);
715 class_addmethod(hradio_old_class, (t_method)hradio_send,
716 gensym("send"), A_DEFSYM, 0);
717 class_addmethod(hradio_old_class, (t_method)hradio_receive,
718 gensym("receive"), A_DEFSYM, 0);
719 class_addmethod(hradio_old_class, (t_method)hradio_label,
720 gensym("label"), A_DEFSYM, 0);
721 class_addmethod(hradio_old_class, (t_method)hradio_label_pos,
722 gensym("label_pos"), A_GIMME, 0);
723 class_addmethod(hradio_old_class, (t_method)hradio_label_font,
724 gensym("label_font"), A_GIMME, 0);
725 class_addmethod(hradio_old_class, (t_method)hradio_init,
726 gensym("init"), A_FLOAT, 0);
727 class_addmethod(hradio_old_class, (t_method)hradio_number,
728 gensym("number"), A_FLOAT, 0);
729 class_addmethod(hradio_old_class, (t_method)hradio_single_change,
730 gensym("single_change"), 0);
731 class_addmethod(hradio_old_class, (t_method)hradio_double_change,
732 gensym("double_change"), 0);
733 class_setwidget(hradio_old_class, &hradio_widgetbehavior);
734 class_sethelpsymbol(hradio_old_class, gensym("hradio"));
735}
736/* Copyright (c) 1997-1999 Miller Puckette.
737 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
738 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
739
740/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
741/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
742
743/* name change to hradio by MSP and changed to
744put out a "float" as in sliders, toggles, etc. */
745
746#include <stdlib.h>
747#include <string.h>
748#include <stdio.h>
749#include <ctype.h>
750#include "m_pd.h"
751#include "g_canvas.h"
752#include "t_tk.h"
753#include "g_all_guis.h"
754#include <math.h>
755
756#ifdef MSW
757#include <io.h>
758#else
759#include <unistd.h>
760#endif
761
762/* ------------- hdl gui-horicontal dial ---------------------- */
763
764t_widgetbehavior hradio_widgetbehavior;
765static t_class *hradio_class, *hradio_old_class;
766
767/* widget helper functions */
768
769void hradio_draw_update(t_hradio *x, t_glist *glist)
770{
771 if(glist_isvisible(glist))
772 {
773 t_canvas *canvas=glist_getcanvas(glist);
774
775 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
776 canvas, x, x->x_on_old,
777 x->x_gui.x_bcol, x->x_gui.x_bcol);
778 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
779 canvas, x, x->x_on,
780 x->x_gui.x_fcol, x->x_gui.x_fcol);
781 }
782}
783
784void hradio_draw_new(t_hradio *x, t_glist *glist)
785{
786 t_canvas *canvas=glist_getcanvas(glist);
787 int n=x->x_number, i, dx=x->x_gui.x_w, s4=dx/4;
788 int yy11=text_ypix(&x->x_gui.x_obj, glist), yy12=yy11+dx;
789 int yy21=yy11+s4, yy22=yy12-s4;
790 int xx11b=text_xpix(&x->x_gui.x_obj, glist), xx11=xx11b, xx21=xx11b+s4;
791 int xx22=xx11b+dx-s4;
792
793
794 for(i=0; i<n; i++)
795 {
796 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE%d\n",
797 canvas, xx11, yy11, xx11+dx, yy12,
798 x->x_gui.x_bcol, x, i);
799 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xBUT%d\n",
800 canvas, xx21, yy21, xx22, yy22,
801 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
802 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol, x, i);
803 xx11 += dx;
804 xx21 += dx;
805 xx22 += dx;
806 }
807 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
808 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
809 canvas, xx11b+x->x_gui.x_ldx, yy11+x->x_gui.x_ldy,
810 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
811 x->x_gui.x_font, x->x_gui.x_fontsize,
812 x->x_gui.x_lcol, x);
813 if(!x->x_gui.x_fsf.x_snd_able)
814 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
815 canvas, xx11b, yy12-1, xx11b + IOWIDTH, yy12, x, 0);
816 if(!x->x_gui.x_fsf.x_rcv_able)
817 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
818 canvas, xx11b, yy11, xx11b + IOWIDTH, yy11+1, x, 0);
819
820}
821
822void hradio_draw_move(t_hradio *x, t_glist *glist)
823{
824 t_canvas *canvas=glist_getcanvas(glist);
825 int n=x->x_number, i, dx=x->x_gui.x_w, s4=dx/4;
826 int yy11=text_ypix(&x->x_gui.x_obj, glist), yy12=yy11+dx;
827 int yy21=yy11+s4, yy22=yy12-s4;
828 int xx11b=text_xpix(&x->x_gui.x_obj, glist), xx11=xx11b, xx21=xx11b+s4;
829 int xx22=xx11b+dx-s4;
830
831 xx11 = xx11b;
832 xx21=xx11b+s4;
833 xx22=xx11b+dx-s4;
834 for(i=0; i<n; i++)
835 {
836 sys_vgui(".x%x.c coords %xBASE%d %d %d %d %d\n",
837 canvas, x, i, xx11, yy11, xx11+dx, yy12);
838 sys_vgui(".x%x.c coords %xBUT%d %d %d %d %d\n",
839 canvas, x, i, xx21, yy21, xx22, yy22);
840 xx11 += dx;
841 xx21 += dx;
842 xx22 += dx;
843 }
844 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
845 canvas, x, xx11b+x->x_gui.x_ldx, yy11+x->x_gui.x_ldy);
846 if(!x->x_gui.x_fsf.x_snd_able)
847 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
848 canvas, x, 0, xx11b, yy12-1, xx11b + IOWIDTH, yy12);
849 if(!x->x_gui.x_fsf.x_rcv_able)
850 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
851 canvas, x, 0, xx11b, yy11, xx11b + IOWIDTH, yy11+1);
852}
853
854void hradio_draw_erase(t_hradio* x, t_glist* glist)
855{
856 t_canvas *canvas=glist_getcanvas(glist);
857 int n=x->x_number, i;
858
859 for(i=0; i<n; i++)
860 {
861 sys_vgui(".x%x.c delete %xBASE%d\n", canvas, x, i);
862 sys_vgui(".x%x.c delete %xBUT%d\n", canvas, x, i);
863 }
864 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
865 if(!x->x_gui.x_fsf.x_snd_able)
866 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
867 if(!x->x_gui.x_fsf.x_rcv_able)
868 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
869}
870
871void hradio_draw_config(t_hradio* x, t_glist* glist)
872{
873 t_canvas *canvas=glist_getcanvas(glist);
874 int n=x->x_number, i;
875
876 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
877 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
878 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
879 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
880 for(i=0; i<n; i++)
881 {
882 sys_vgui(".x%x.c itemconfigure %xBASE%d -fill #%6.6x\n", canvas, x, i,
883 x->x_gui.x_bcol);
884 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n", canvas, x, i,
885 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
886 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol);
887 }
888}
889
890void hradio_draw_io(t_hradio* x, t_glist* glist, int old_snd_rcv_flags)
891{
892 t_canvas *canvas=glist_getcanvas(glist);
893 int xpos=text_xpix(&x->x_gui.x_obj, glist);
894 int ypos=text_ypix(&x->x_gui.x_obj, glist);
895
896 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
897 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
898 canvas,
899 xpos, ypos + x->x_gui.x_w-1,
900 xpos + IOWIDTH, ypos + x->x_gui.x_w,
901 x, 0);
902 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
903 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
904 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
905 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
906 canvas,
907 xpos, ypos,
908 xpos + IOWIDTH, ypos+1, x, 0);
909 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
910 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
911}
912
913void hradio_draw_select(t_hradio* x, t_glist* glist)
914{
915 t_canvas *canvas=glist_getcanvas(glist);
916 int n=x->x_number, i;
917
918 if(x->x_gui.x_fsf.x_selected)
919 {
920 for(i=0; i<n; i++)
921 {
922 sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
923 IEM_GUI_COLOR_SELECTED);
924 }
925 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
926 }
927 else
928 {
929 for(i=0; i<n; i++)
930 {
931 sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
932 IEM_GUI_COLOR_NORMAL);
933 }
934 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x,
935 x->x_gui.x_lcol);
936 }
937}
938
939void hradio_draw(t_hradio *x, t_glist *glist, int mode)
940{
941 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
942 hradio_draw_update(x, glist);
943 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
944 hradio_draw_move(x, glist);
945 else if(mode == IEM_GUI_DRAW_MODE_NEW)
946 hradio_draw_new(x, glist);
947 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
948 hradio_draw_select(x, glist);
949 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
950 hradio_draw_erase(x, glist);
951 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
952 hradio_draw_config(x, glist);
953 else if(mode >= IEM_GUI_DRAW_MODE_IO)
954 hradio_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
955}
956
957/* ------------------------ hdl widgetbehaviour----------------------------- */
958
959static void hradio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
960{
961 t_hradio *x = (t_hradio *)z;
962
963 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
964 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
965 *xp2 = *xp1 + x->x_gui.x_w*x->x_number;
966 *yp2 = *yp1 + x->x_gui.x_h;
967}
968
969static void hradio_save(t_gobj *z, t_binbuf *b)
970{
971 t_hradio *x = (t_hradio *)z;
972 int bflcol[3];
973 t_symbol *srl[3];
974
975 iemgui_save(&x->x_gui, srl, bflcol);
976 binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"),
977 (t_int)text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist),
978 (t_int)text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist),
979 (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class ?
980 gensym("hdl") : gensym("hradio")),
981 x->x_gui.x_w,
982 x->x_change, iem_symargstoint(&x->x_gui.x_isa), x->x_number,
983 srl[0], srl[1], srl[2],
984 x->x_gui.x_ldx, x->x_gui.x_ldy,
985 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
986 bflcol[0], bflcol[1], bflcol[2], x->x_on);
987 binbuf_addv(b, ";");
988}
989
990static void hradio_properties(t_gobj *z, t_glist *owner)
991{
992 t_hradio *x = (t_hradio *)z;
993 char buf[800];
994 t_symbol *srl[3];
995 int hchange=-1;
996
997 iemgui_properties(&x->x_gui, srl);
998 if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
999 hchange = x->x_change;
1000 sprintf(buf, "pdtk_iemgui_dialog %%s hradio \
1001 ----------dimensions(pix):----------- %d %d size: 0 0 empty \
1002 empty 0.0 empty 0.0 empty %d \
1003 %d new-only new&old %d %d number: %d \
1004 %s %s \
1005 %s %d %d \
1006 %d %d \
1007 %d %d %d\n",
1008 x->x_gui.x_w, IEM_GUI_MINSIZE,
1009 0,/*no_schedule*/
1010 hchange, x->x_gui.x_isa.x_loadinit, -1, x->x_number,
1011 srl[0]->s_name, srl[1]->s_name,
1012 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
1013 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
1014 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
1015 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
1016}
1017
1018static void hradio_dialog(t_hradio *x, t_symbol *s, int argc, t_atom *argv)
1019{
1020 t_symbol *srl[3];
1021 int a = (int)atom_getintarg(0, argc, argv);
1022 int chg = (int)atom_getintarg(4, argc, argv);
1023 int num = (int)atom_getintarg(6, argc, argv);
1024 int sr_flags;
1025
1026 if(chg != 0) chg = 1;
1027 x->x_change = chg;
1028 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
1029 x->x_gui.x_w = iemgui_clip_size(a);
1030 x->x_gui.x_h = x->x_gui.x_w;
1031 if(x->x_number != num)
1032 {
1033 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
1034 x->x_number = num;
1035 if(x->x_on >= x->x_number)
1036 {
1037 x->x_on = x->x_number - 1;
1038 x->x_on_old = x->x_on;
1039 }
1040 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
1041 }
1042 else
1043 {
1044 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
1045 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
1046 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
1047 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
1048 }
1049
1050}
1051
1052static void hradio_set(t_hradio *x, t_floatarg f)
1053{
1054 int i=(int)f;
1055 int old=x->x_on_old;
1056
1057 if(i < 0)
1058 i = 0;
1059 if(i >= x->x_number)
1060 i = x->x_number-1;
1061 if(x->x_on != x->x_on_old)
1062 {
1063 old = x->x_on_old;
1064 x->x_on_old = x->x_on;
1065 x->x_on = i;
1066 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1067 x->x_on_old = old;
1068 }
1069 else
1070 {
1071 x->x_on = i;
1072 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1073 }
1074}
1075
1076static void hradio_bang(t_hradio *x)
1077{
1078 /* compatibility with earlier "hdial" behavior */
1079 if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
1080 {
1081 if((x->x_change)&&(x->x_on != x->x_on_old))
1082 {
1083 SETFLOAT(x->x_at, (float)x->x_on_old);
1084 SETFLOAT(x->x_at+1, 0.0);
1085 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1086 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1087 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1088 }
1089 x->x_on_old = x->x_on;
1090 SETFLOAT(x->x_at, (float)x->x_on);
1091 SETFLOAT(x->x_at+1, 1.0);
1092 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1093 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1094 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1095 }
1096 else
1097 {
1098 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
1099 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1100 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
1101 }
1102}
1103
1104static void hradio_fout(t_hradio *x, t_floatarg f)
1105{
1106 int i=(int)f;
1107
1108 if(i < 0)
1109 i = 0;
1110 if(i >= x->x_number)
1111 i = x->x_number-1;
1112
1113 if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
1114 {
1115 if((x->x_change)&&(i != x->x_on_old))
1116 {
1117 SETFLOAT(x->x_at, (float)x->x_on_old);
1118 SETFLOAT(x->x_at+1, 0.0);
1119 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1120 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1121 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1122 }
1123 if(x->x_on != x->x_on_old)
1124 x->x_on_old = x->x_on;
1125 x->x_on = i;
1126 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1127 x->x_on_old = x->x_on;
1128 SETFLOAT(x->x_at, (float)x->x_on);
1129 SETFLOAT(x->x_at+1, 1.0);
1130 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1131 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1132 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1133 }
1134 else
1135 {
1136 x->x_on_old = x->x_on;
1137 x->x_on = i;
1138 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1139 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
1140 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1141 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
1142 }
1143}
1144
1145static void hradio_float(t_hradio *x, t_floatarg f)
1146{
1147 int i=(int)f;
1148
1149 if(i < 0)
1150 i = 0;
1151 if(i >= x->x_number)
1152 i = x->x_number-1;
1153
1154 if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
1155 {
1156 /* compatibility with earlier "vdial" behavior */
1157 if((x->x_change)&&(i != x->x_on_old))
1158 {
1159 if(x->x_gui.x_fsf.x_put_in2out)
1160 {
1161 SETFLOAT(x->x_at, (float)x->x_on_old);
1162 SETFLOAT(x->x_at+1, 0.0);
1163 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1164 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1165 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1166 }
1167 }
1168 if(x->x_on != x->x_on_old)
1169 x->x_on_old = x->x_on;
1170 x->x_on = i;
1171 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1172 x->x_on_old = x->x_on;
1173 if(x->x_gui.x_fsf.x_put_in2out)
1174 {
1175 SETFLOAT(x->x_at, (float)x->x_on);
1176 SETFLOAT(x->x_at+1, 1.0);
1177 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1178 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1179 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1180 }
1181 }
1182 else
1183 {
1184 x->x_on_old = x->x_on;
1185 x->x_on = i;
1186 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1187 if (x->x_gui.x_fsf.x_put_in2out)
1188 {
1189 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
1190 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1191 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
1192 }
1193 }
1194}
1195
1196static void hradio_click(t_hradio *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
1197{
1198 int xx = (int)xpos - (int)text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
1199
1200 hradio_fout(x, (float)(xx / x->x_gui.x_w));
1201}
1202
1203static int hradio_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
1204{
1205 if(doit)
1206 hradio_click((t_hradio *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
1207 return (1);
1208}
1209
1210static void hradio_loadbang(t_hradio *x)
1211{
1212 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
1213 hradio_bang(x);
1214}
1215
1216static void hradio_number(t_hradio *x, t_floatarg num)
1217{
1218 int n=(int)num;
1219
1220 if(n < 1)
1221 n = 1;
1222 if(n > IEM_RADIO_MAX)
1223 n = IEM_RADIO_MAX;
1224 if(n != x->x_number)
1225 {
1226 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
1227 x->x_number = n;
1228 if(x->x_on >= x->x_number)
1229 x->x_on = x->x_number - 1;
1230 x->x_on_old = x->x_on;
1231 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
1232 }
1233}
1234
1235static void hradio_size(t_hradio *x, t_symbol *s, int ac, t_atom *av)
1236{
1237 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
1238 x->x_gui.x_h = x->x_gui.x_w;
1239 iemgui_size((void *)x, &x->x_gui);
1240}
1241
1242static void hradio_delta(t_hradio *x, t_symbol *s, int ac, t_atom *av)
1243{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
1244
1245static void hradio_pos(t_hradio *x, t_symbol *s, int ac, t_atom *av)
1246{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
1247
1248static void hradio_color(t_hradio *x, t_symbol *s, int ac, t_atom *av)
1249{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
1250
1251static void hradio_send(t_hradio *x, t_symbol *s)
1252{iemgui_send(x, &x->x_gui, s);}
1253
1254static void hradio_receive(t_hradio *x, t_symbol *s)
1255{iemgui_receive(x, &x->x_gui, s);}
1256
1257static void hradio_label(t_hradio *x, t_symbol *s)
1258{iemgui_label((void *)x, &x->x_gui, s);}
1259
1260static void hradio_label_pos(t_hradio *x, t_symbol *s, int ac, t_atom *av)
1261{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
1262
1263static void hradio_label_font(t_hradio *x, t_symbol *s, int ac, t_atom *av)
1264{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
1265
1266static void hradio_init(t_hradio *x, t_floatarg f)
1267{
1268 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
1269}
1270
1271static void hradio_double_change(t_hradio *x)
1272{x->x_change = 1;}
1273
1274static void hradio_single_change(t_hradio *x)
1275{x->x_change = 0;}
1276
1277static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old)
1278{
1279 t_hradio *x = (t_hradio *)pd_new(old? hradio_old_class : hradio_class);
1280 int bflcol[]={-262144, -1, -1};
1281 int a=IEM_GUI_DEFAULTSIZE, on=0, f=0;
1282 int ldx=0, ldy=-6, chg=1, num=8;
1283 int fs=8;
1284 int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
1285 char str[144];
1286
1287 iem_inttosymargs(&x->x_gui.x_isa, 0);
1288 iem_inttofstyle(&x->x_gui.x_fsf, 0);
1289
1290 if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
1291 &&IS_A_FLOAT(argv,3)
1292 &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
1293 &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
1294 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
1295 &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
1296 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
1297 &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)&&IS_A_FLOAT(argv,14))
1298 {
1299 a = (int)atom_getintarg(0, argc, argv);
1300 chg = (int)atom_getintarg(1, argc, argv);
1301 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(2, argc, argv));
1302 num = (int)atom_getintarg(3, argc, argv);
1303 iemgui_new_getnames(&x->x_gui, 4, argv);
1304 ldx = (int)atom_getintarg(7, argc, argv);
1305 ldy = (int)atom_getintarg(8, argc, argv);
1306 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv));
1307 fs = (int)atom_getintarg(10, argc, argv);
1308 bflcol[0] = (int)atom_getintarg(11, argc, argv);
1309 bflcol[1] = (int)atom_getintarg(12, argc, argv);
1310 bflcol[2] = (int)atom_getintarg(13, argc, argv);
1311 on = (int)atom_getintarg(14, argc, argv);
1312 }
1313 else iemgui_new_getnames(&x->x_gui, 4, 0);
1314 x->x_gui.x_draw = (t_iemfunptr)hradio_draw;
1315 x->x_gui.x_fsf.x_snd_able = 1;
1316 x->x_gui.x_fsf.x_rcv_able = 1;
1317 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
1318 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
1319 x->x_gui.x_fsf.x_snd_able = 0;
1320 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
1321 x->x_gui.x_fsf.x_rcv_able = 0;
1322 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
1323 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
1324 else { x->x_gui.x_fsf.x_font_style = 0;
1325 strcpy(x->x_gui.x_font, "courier"); }
1326 if(num < 1)
1327 num = 1;
1328 if(num > IEM_RADIO_MAX)
1329 num = IEM_RADIO_MAX;
1330 x->x_number = num;
1331 if(on < 0)
1332 on = 0;
1333 if(on >= x->x_number)
1334 on = x->x_number - 1;
1335 if(x->x_gui.x_isa.x_loadinit)
1336 x->x_on = on;
1337 else
1338 x->x_on = 0;
1339 x->x_on_old = x->x_on;
1340 x->x_change = (chg==0)?0:1;
1341 if (x->x_gui.x_fsf.x_rcv_able)
1342 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1343 x->x_gui.x_ldx = ldx;
1344 x->x_gui.x_ldy = ldy;
1345 if(fs < 4)
1346 fs = 4;
1347 x->x_gui.x_fontsize = fs;
1348 x->x_gui.x_w = iemgui_clip_size(a);
1349 x->x_gui.x_h = x->x_gui.x_w;
1350 iemgui_verify_snd_ne_rcv(&x->x_gui);
1351 iemgui_all_colfromload(&x->x_gui, bflcol);
1352 outlet_new(&x->x_gui.x_obj, &s_list);
1353 return (x);
1354}
1355
1356static void *hradio_new(t_symbol *s, int argc, t_atom *argv)
1357{
1358 return (hradio_donew(s, argc, argv, 0));
1359}
1360
1361static void *hdial_new(t_symbol *s, int argc, t_atom *argv)
1362{
1363 return (hradio_donew(s, argc, argv, 1));
1364}
1365
1366static void hradio_ff(t_hradio *x)
1367{
1368 if(x->x_gui.x_fsf.x_rcv_able)
1369 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1370 gfxstub_deleteforkey(x);
1371}
1372
1373void g_hradio_setup(void)
1374{
1375 hradio_class = class_new(gensym("hradio"), (t_newmethod)hradio_new,
1376 (t_method)hradio_ff, sizeof(t_hradio), 0, A_GIMME, 0);
1377 class_addbang(hradio_class, hradio_bang);
1378 class_addfloat(hradio_class, hradio_float);
1379 class_addmethod(hradio_class, (t_method)hradio_click, gensym("click"),
1380 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1381 class_addmethod(hradio_class, (t_method)hradio_dialog, gensym("dialog"),
1382 A_GIMME, 0);
1383 class_addmethod(hradio_class, (t_method)hradio_loadbang,
1384 gensym("loadbang"), 0);
1385 class_addmethod(hradio_class, (t_method)hradio_set,
1386 gensym("set"), A_FLOAT, 0);
1387 class_addmethod(hradio_class, (t_method)hradio_size,
1388 gensym("size"), A_GIMME, 0);
1389 class_addmethod(hradio_class, (t_method)hradio_delta,
1390 gensym("delta"), A_GIMME, 0);
1391 class_addmethod(hradio_class, (t_method)hradio_pos,
1392 gensym("pos"), A_GIMME, 0);
1393 class_addmethod(hradio_class, (t_method)hradio_color,
1394 gensym("color"), A_GIMME, 0);
1395 class_addmethod(hradio_class, (t_method)hradio_send,
1396 gensym("send"), A_DEFSYM, 0);
1397 class_addmethod(hradio_class, (t_method)hradio_receive,
1398 gensym("receive"), A_DEFSYM, 0);
1399 class_addmethod(hradio_class, (t_method)hradio_label,
1400 gensym("label"), A_DEFSYM, 0);
1401 class_addmethod(hradio_class, (t_method)hradio_label_pos,
1402 gensym("label_pos"), A_GIMME, 0);
1403 class_addmethod(hradio_class, (t_method)hradio_label_font,
1404 gensym("label_font"), A_GIMME, 0);
1405 class_addmethod(hradio_class, (t_method)hradio_init,
1406 gensym("init"), A_FLOAT, 0);
1407 class_addmethod(hradio_class, (t_method)hradio_number,
1408 gensym("number"), A_FLOAT, 0);
1409 class_addmethod(hradio_class, (t_method)hradio_single_change,
1410 gensym("single_change"), 0);
1411 class_addmethod(hradio_class, (t_method)hradio_double_change,
1412 gensym("double_change"), 0);
1413 hradio_widgetbehavior.w_getrectfn = hradio_getrect;
1414 hradio_widgetbehavior.w_displacefn = iemgui_displace;
1415 hradio_widgetbehavior.w_selectfn = iemgui_select;
1416 hradio_widgetbehavior.w_activatefn = NULL;
1417 hradio_widgetbehavior.w_deletefn = iemgui_delete;
1418 hradio_widgetbehavior.w_visfn = iemgui_vis;
1419 hradio_widgetbehavior.w_clickfn = hradio_newclick;
1420 class_setwidget(hradio_class, &hradio_widgetbehavior);
1421 class_sethelpsymbol(hradio_class, gensym("hradio"));
1422 class_setsavefn(hradio_class, hradio_save);
1423 class_setpropertiesfn(hradio_class, hradio_properties);
1424
1425 /*obsolete version (0.34-0.35) */
1426 hradio_old_class = class_new(gensym("hdl"), (t_newmethod)hdial_new,
1427 (t_method)hradio_ff, sizeof(t_hradio), 0, A_GIMME, 0);
1428 class_addcreator((t_newmethod)hradio_new, gensym("rdb"), A_GIMME, 0);
1429 class_addcreator((t_newmethod)hradio_new, gensym("radiobut"), A_GIMME, 0);
1430 class_addcreator((t_newmethod)hradio_new, gensym("radiobutton"),
1431 A_GIMME, 0);
1432 class_addbang(hradio_old_class, hradio_bang);
1433 class_addfloat(hradio_old_class, hradio_float);
1434 class_addmethod(hradio_old_class, (t_method)hradio_click, gensym("click"),
1435 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1436 class_addmethod(hradio_old_class, (t_method)hradio_dialog, gensym("dialog"),
1437 A_GIMME, 0);
1438 class_addmethod(hradio_old_class, (t_method)hradio_loadbang,
1439 gensym("loadbang"), 0);
1440 class_addmethod(hradio_old_class, (t_method)hradio_set,
1441 gensym("set"), A_FLOAT, 0);
1442 class_addmethod(hradio_old_class, (t_method)hradio_size,
1443 gensym("size"), A_GIMME, 0);
1444 class_addmethod(hradio_old_class, (t_method)hradio_delta,
1445 gensym("delta"), A_GIMME, 0);
1446 class_addmethod(hradio_old_class, (t_method)hradio_pos,
1447 gensym("pos"), A_GIMME, 0);
1448 class_addmethod(hradio_old_class, (t_method)hradio_color,
1449 gensym("color"), A_GIMME, 0);
1450 class_addmethod(hradio_old_class, (t_method)hradio_send,
1451 gensym("send"), A_DEFSYM, 0);
1452 class_addmethod(hradio_old_class, (t_method)hradio_receive,
1453 gensym("receive"), A_DEFSYM, 0);
1454 class_addmethod(hradio_old_class, (t_method)hradio_label,
1455 gensym("label"), A_DEFSYM, 0);
1456 class_addmethod(hradio_old_class, (t_method)hradio_label_pos,
1457 gensym("label_pos"), A_GIMME, 0);
1458 class_addmethod(hradio_old_class, (t_method)hradio_label_font,
1459 gensym("label_font"), A_GIMME, 0);
1460 class_addmethod(hradio_old_class, (t_method)hradio_init,
1461 gensym("init"), A_FLOAT, 0);
1462 class_addmethod(hradio_old_class, (t_method)hradio_number,
1463 gensym("number"), A_FLOAT, 0);
1464 class_addmethod(hradio_old_class, (t_method)hradio_single_change,
1465 gensym("single_change"), 0);
1466 class_addmethod(hradio_old_class, (t_method)hradio_double_change,
1467 gensym("double_change"), 0);
1468 class_setwidget(hradio_old_class, &hradio_widgetbehavior);
1469 class_sethelpsymbol(hradio_old_class, gensym("hradio"));
1470}
diff --git a/apps/plugins/pdbox/PDa/src/g_hslider.c b/apps/plugins/pdbox/PDa/src/g_hslider.c
new file mode 100644
index 0000000000..77cd05c127
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_hslider.c
@@ -0,0 +1,1308 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
7
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <ctype.h>
13#include "m_pd.h"
14#include "g_canvas.h"
15#include "t_tk.h"
16#include "g_all_guis.h"
17#include <math.h>
18
19#ifdef MSW
20#include <io.h>
21#else
22#include <unistd.h>
23#endif
24
25
26/* ------------ hsl gui-horicontal slider ----------------------- */
27
28t_widgetbehavior hslider_widgetbehavior;
29static t_class *hslider_class;
30
31/* widget helper functions */
32
33static void hslider_draw_update(t_hslider *x, t_glist *glist)
34{
35 t_canvas *canvas=glist_getcanvas(glist);
36 int ypos=text_ypix(&x->x_gui.x_obj, glist);
37
38 if (glist_isvisible(glist))
39 {
40 int r = text_xpix(&x->x_gui.x_obj, glist) + (x->x_val + 50)/100;
41 sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
42 canvas, x, r, ypos+1,
43 r, ypos + x->x_gui.x_h);
44 if(x->x_val == x->x_center)
45 {
46 if(!x->x_thick)
47 {
48 sys_vgui(".x%x.c itemconfigure %xKNOB -width 7\n", canvas, x);
49 x->x_thick = 1;
50 }
51 }
52 else
53 {
54 if(x->x_thick)
55 {
56 sys_vgui(".x%x.c itemconfigure %xKNOB -width 3\n", canvas, x);
57 x->x_thick = 0;
58 }
59 }
60 }
61}
62
63static void hslider_draw_new(t_hslider *x, t_glist *glist)
64{
65 int xpos=text_xpix(&x->x_gui.x_obj, glist);
66 int ypos=text_ypix(&x->x_gui.x_obj, glist);
67 int r = xpos + (x->x_val + 50)/100;
68 t_canvas *canvas=glist_getcanvas(glist);
69
70 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
71 canvas, xpos-3, ypos,
72 xpos + x->x_gui.x_w+2, ypos + x->x_gui.x_h,
73 x->x_gui.x_bcol, x);
74 sys_vgui(".x%x.c create line %d %d %d %d -width 3 -fill #%6.6x -tags %xKNOB\n",
75 canvas, r, ypos+1, r,
76 ypos + x->x_gui.x_h, x->x_gui.x_fcol, x);
77 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
78 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
79 canvas, xpos+x->x_gui.x_ldx,
80 ypos+x->x_gui.x_ldy,
81 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
82 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
83 if(!x->x_gui.x_fsf.x_snd_able)
84 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
85 canvas, xpos-3, ypos + x->x_gui.x_h-1,
86 xpos+4, ypos + x->x_gui.x_h, x, 0);
87 if(!x->x_gui.x_fsf.x_rcv_able)
88 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
89 canvas, xpos-3, ypos,
90 xpos+4, ypos+1, x, 0);
91}
92
93static void hslider_draw_move(t_hslider *x, t_glist *glist)
94{
95 int xpos=text_xpix(&x->x_gui.x_obj, glist);
96 int ypos=text_ypix(&x->x_gui.x_obj, glist);
97 int r = xpos + (x->x_val + 50)/100;
98 t_canvas *canvas=glist_getcanvas(glist);
99
100 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
101 canvas, x,
102 xpos-3, ypos,
103 xpos + x->x_gui.x_w+2, ypos + x->x_gui.x_h);
104 sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
105 canvas, x, r, ypos+1,
106 r, ypos + x->x_gui.x_h);
107 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
108 canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
109 if(!x->x_gui.x_fsf.x_snd_able)
110 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
111 canvas, x, 0,
112 xpos-3, ypos + x->x_gui.x_h-1,
113 xpos+4, ypos + x->x_gui.x_h);
114 if(!x->x_gui.x_fsf.x_rcv_able)
115 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
116 canvas, x, 0,
117 xpos-3, ypos,
118 xpos+4, ypos+1);
119}
120
121static void hslider_draw_erase(t_hslider* x,t_glist* glist)
122{
123 t_canvas *canvas=glist_getcanvas(glist);
124
125 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
126 sys_vgui(".x%x.c delete %xKNOB\n", canvas, x);
127 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
128 if(!x->x_gui.x_fsf.x_snd_able)
129 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
130 if(!x->x_gui.x_fsf.x_rcv_able)
131 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
132}
133
134static void hslider_draw_config(t_hslider* x,t_glist* glist)
135{
136 t_canvas *canvas=glist_getcanvas(glist);
137
138 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
139 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
140 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
141 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
142 sys_vgui(".x%x.c itemconfigure %xKNOB -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
143 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
144}
145
146static void hslider_draw_io(t_hslider* x,t_glist* glist, int old_snd_rcv_flags)
147{
148 int xpos=text_xpix(&x->x_gui.x_obj, glist);
149 int ypos=text_ypix(&x->x_gui.x_obj, glist);
150 t_canvas *canvas=glist_getcanvas(glist);
151
152 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
153 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
154 canvas, xpos-3, ypos + x->x_gui.x_h-1,
155 xpos+4, ypos + x->x_gui.x_h, x, 0);
156 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
157 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
158 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
159 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
160 canvas, xpos-3, ypos,
161 xpos+4, ypos+1, x, 0);
162 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
163 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
164}
165
166static void hslider_draw_select(t_hslider* x,t_glist* glist)
167{
168 t_canvas *canvas=glist_getcanvas(glist);
169
170 if(x->x_gui.x_fsf.x_selected)
171 {
172 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
173 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
174 }
175 else
176 {
177 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
178 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
179 }
180}
181
182void hslider_draw(t_hslider *x, t_glist *glist, int mode)
183{
184 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
185 hslider_draw_update(x, glist);
186 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
187 hslider_draw_move(x, glist);
188 else if(mode == IEM_GUI_DRAW_MODE_NEW)
189 hslider_draw_new(x, glist);
190 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
191 hslider_draw_select(x, glist);
192 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
193 hslider_draw_erase(x, glist);
194 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
195 hslider_draw_config(x, glist);
196 else if(mode >= IEM_GUI_DRAW_MODE_IO)
197 hslider_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
198}
199
200/* ------------------------ hsl widgetbehaviour----------------------------- */
201
202
203static void hslider_getrect(t_gobj *z, t_glist *glist,
204 int *xp1, int *yp1, int *xp2, int *yp2)
205{
206 t_hslider* x = (t_hslider*)z;
207
208 *xp1 = text_xpix(&x->x_gui.x_obj, glist) - 3;
209 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
210 *xp2 = *xp1 + x->x_gui.x_w + 5;
211 *yp2 = *yp1 + x->x_gui.x_h;
212}
213
214static void hslider_save(t_gobj *z, t_binbuf *b)
215{
216 t_hslider *x = (t_hslider *)z;
217 int bflcol[3];
218 t_symbol *srl[3];
219
220 iemgui_save(&x->x_gui, srl, bflcol);
221 binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
222 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
223 gensym("hsl"), x->x_gui.x_w, x->x_gui.x_h,
224 (float)x->x_min, (float)x->x_max,
225 x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa),
226 srl[0], srl[1], srl[2],
227 x->x_gui.x_ldx, x->x_gui.x_ldy,
228 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
229 bflcol[0], bflcol[1], bflcol[2],
230 x->x_val, x->x_steady);
231 binbuf_addv(b, ";");
232}
233
234void hslider_check_width(t_hslider *x, int w)
235{
236 if(w < IEM_SL_MINSIZE)
237 w = IEM_SL_MINSIZE;
238 x->x_gui.x_w = w;
239 x->x_center = (x->x_gui.x_w-1)*50;
240 if(x->x_val > (x->x_gui.x_w*100 - 100))
241 {
242 x->x_pos = x->x_gui.x_w*100 - 100;
243 x->x_val = x->x_pos;
244 }
245 if(x->x_lin0_log1)
246 x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
247 else
248 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
249}
250
251void hslider_check_minmax(t_hslider *x, double min, double max)
252{
253 if(x->x_lin0_log1)
254 {
255 if((min == 0.0)&&(max == 0.0))
256 max = 1.0;
257 if(max > 0.0)
258 {
259 if(min <= 0.0)
260 min = 0.01*max;
261 }
262 else
263 {
264 if(min > 0.0)
265 max = 0.01*min;
266 }
267 }
268 x->x_min = min;
269 x->x_max = max;
270 if(x->x_min > x->x_max) /* bugfix */
271 x->x_gui.x_isa.x_reverse = 1;
272 else
273 x->x_gui.x_isa.x_reverse = 0;
274 if(x->x_lin0_log1)
275 x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
276 else
277 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
278}
279
280static void hslider_properties(t_gobj *z, t_glist *owner)
281{
282 t_hslider *x = (t_hslider *)z;
283 char buf[800];
284 t_symbol *srl[3];
285
286 iemgui_properties(&x->x_gui, srl);
287 sprintf(buf, "pdtk_iemgui_dialog %%s HSLIDER \
288 --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
289 -----------output-range:----------- %g left: %g right: %g \
290 %d lin log %d %d empty %d \
291 %s %s \
292 %s %d %d \
293 %d %d \
294 %d %d %d\n",
295 x->x_gui.x_w, IEM_SL_MINSIZE, x->x_gui.x_h, IEM_GUI_MINSIZE,
296 x->x_min, x->x_max, 0.0,/*no_schedule*/
297 x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
298 srl[0]->s_name, srl[1]->s_name,
299 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
300 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
301 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
302 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
303}
304
305static void hslider_set(t_hslider *x, t_floatarg f) /* bugfix */
306{
307 double g;
308
309 if(x->x_gui.x_isa.x_reverse) /* bugfix */
310 {
311 if(f > x->x_min)
312 f = x->x_min;
313 if(f < x->x_max)
314 f = x->x_max;
315 }
316 else
317 {
318 if(f > x->x_max)
319 f = x->x_max;
320 if(f < x->x_min)
321 f = x->x_min;
322 }
323 if(x->x_lin0_log1)
324 g = log(f/x->x_min)/x->x_k;
325 else
326 g = (f - x->x_min) / x->x_k;
327 x->x_val = (int)(100.0*g + 0.49999);
328 x->x_pos = x->x_val;
329 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
330}
331
332static void hslider_bang(t_hslider *x)
333{
334 double out;
335
336 if(x->x_lin0_log1)
337 out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
338 else
339 out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
340 if((out < 1.0e-10)&&(out > -1.0e-10))
341 out = 0.0;
342 outlet_float(x->x_gui.x_obj.ob_outlet, out);
343 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
344 pd_float(x->x_gui.x_snd->s_thing, out);
345}
346
347static void hslider_dialog(t_hslider *x, t_symbol *s, int argc, t_atom *argv)
348{
349 t_symbol *srl[3];
350 int w = (int)atom_getintarg(0, argc, argv);
351 int h = (int)atom_getintarg(1, argc, argv);
352 double min = (double)atom_getfloatarg(2, argc, argv);
353 double max = (double)atom_getfloatarg(3, argc, argv);
354 int lilo = (int)atom_getintarg(4, argc, argv);
355 int steady = (int)atom_getintarg(17, argc, argv);
356 int sr_flags;
357
358 if(lilo != 0) lilo = 1;
359 x->x_lin0_log1 = lilo;
360 if(steady)
361 x->x_steady = 1;
362 else
363 x->x_steady = 0;
364 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
365 x->x_gui.x_h = iemgui_clip_size(h);
366 hslider_check_width(x, w);
367 hslider_check_minmax(x, min, max);
368 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
369 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
370 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
371 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
372}
373
374static void hslider_motion(t_hslider *x, t_floatarg dx, t_floatarg dy)
375{
376 int old = x->x_val;
377
378 if(x->x_gui.x_fsf.x_finemoved)
379 x->x_pos += (int)dx;
380 else
381 x->x_pos += 100*(int)dx;
382 x->x_val = x->x_pos;
383 if(x->x_val > (100*x->x_gui.x_w - 100))
384 {
385 x->x_val = 100*x->x_gui.x_w - 100;
386 x->x_pos += 50;
387 x->x_pos -= x->x_pos%100;
388 }
389 if(x->x_val < 0)
390 {
391 x->x_val = 0;
392 x->x_pos -= 50;
393 x->x_pos -= x->x_pos%100;
394 }
395 if(old != x->x_val)
396 {
397 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
398 hslider_bang(x);
399 }
400}
401
402static void hslider_click(t_hslider *x, t_floatarg xpos, t_floatarg ypos,
403 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
404{
405 if(!x->x_steady)
406 x->x_val = (int)(100.0 * (xpos - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)));
407 if(x->x_val > (100*x->x_gui.x_w - 100))
408 x->x_val = 100*x->x_gui.x_w - 100;
409 if(x->x_val < 0)
410 x->x_val = 0;
411 x->x_pos = x->x_val;
412 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
413 hslider_bang(x);
414 glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, (t_glistmotionfn)hslider_motion,
415 0, xpos, ypos);
416}
417
418static int hslider_newclick(t_gobj *z, struct _glist *glist,
419 int xpix, int ypix, int shift, int alt, int dbl, int doit)
420{
421 t_hslider* x = (t_hslider *)z;
422
423 if(doit)
424 {
425 hslider_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
426 0, (t_floatarg)alt);
427 if(shift)
428 x->x_gui.x_fsf.x_finemoved = 1;
429 else
430 x->x_gui.x_fsf.x_finemoved = 0;
431 }
432 return (1);
433}
434
435static void hslider_size(t_hslider *x, t_symbol *s, int ac, t_atom *av)
436{
437 hslider_check_width(x, (int)atom_getintarg(0, ac, av));
438 if(ac > 1)
439 x->x_gui.x_h = iemgui_clip_size((int)atom_getintarg(1, ac, av));
440 iemgui_size((void *)x, &x->x_gui);
441}
442
443static void hslider_delta(t_hslider *x, t_symbol *s, int ac, t_atom *av)
444{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
445
446static void hslider_pos(t_hslider *x, t_symbol *s, int ac, t_atom *av)
447{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
448
449static void hslider_range(t_hslider *x, t_symbol *s, int ac, t_atom *av)
450{
451 hslider_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
452 (double)atom_getfloatarg(1, ac, av));
453}
454
455static void hslider_color(t_hslider *x, t_symbol *s, int ac, t_atom *av)
456{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
457
458static void hslider_send(t_hslider *x, t_symbol *s)
459{iemgui_send(x, &x->x_gui, s);}
460
461static void hslider_receive(t_hslider *x, t_symbol *s)
462{iemgui_receive(x, &x->x_gui, s);}
463
464static void hslider_label(t_hslider *x, t_symbol *s)
465{iemgui_label((void *)x, &x->x_gui, s);}
466
467static void hslider_label_pos(t_hslider *x, t_symbol *s, int ac, t_atom *av)
468{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
469
470static void hslider_label_font(t_hslider *x, t_symbol *s, int ac, t_atom *av)
471{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
472
473static void hslider_log(t_hslider *x)
474{
475 x->x_lin0_log1 = 1;
476 hslider_check_minmax(x, x->x_min, x->x_max);
477}
478
479static void hslider_lin(t_hslider *x)
480{
481 x->x_lin0_log1 = 0;
482 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
483}
484
485static void hslider_init(t_hslider *x, t_floatarg f)
486{
487 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
488}
489
490static void hslider_steady(t_hslider *x, t_floatarg f)
491{
492 x->x_steady = (f==0.0)?0:1;
493}
494
495static void hslider_float(t_hslider *x, t_floatarg f)
496{
497 double out;
498
499 hslider_set(x, f);
500 if(x->x_lin0_log1)
501 out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
502 else
503 out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
504 if((out < 1.0e-10)&&(out > -1.0e-10))
505 out = 0.0;
506 if(x->x_gui.x_fsf.x_put_in2out)
507 {
508 outlet_float(x->x_gui.x_obj.ob_outlet, out);
509 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
510 pd_float(x->x_gui.x_snd->s_thing, out);
511 }
512}
513
514static void hslider_loadbang(t_hslider *x)
515{
516 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
517 {
518 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
519 hslider_bang(x);
520 }
521}
522
523static void *hslider_new(t_symbol *s, int argc, t_atom *argv)
524{
525 t_hslider *x = (t_hslider *)pd_new(hslider_class);
526 int bflcol[]={-262144, -1, -1};
527 int w=IEM_SL_DEFAULTSIZE, h=IEM_GUI_DEFAULTSIZE;
528 int lilo=0, ldx=-2, ldy=-6, f=0, v=0, steady=1;
529 int fs=8;
530 double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
531 char str[144];
532
533 iem_inttosymargs(&x->x_gui.x_isa, 0);
534 iem_inttofstyle(&x->x_gui.x_fsf, 0);
535
536 if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
537 &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
538 &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
539 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
540 &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
541 &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
542 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
543 &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
544 &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
545 {
546 w = (int)atom_getintarg(0, argc, argv);
547 h = (int)atom_getintarg(1, argc, argv);
548 min = (double)atom_getfloatarg(2, argc, argv);
549 max = (double)atom_getfloatarg(3, argc, argv);
550 lilo = (int)atom_getintarg(4, argc, argv);
551 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
552 iemgui_new_getnames(&x->x_gui, 6, argv);
553 ldx = (int)atom_getintarg(9, argc, argv);
554 ldy = (int)atom_getintarg(10, argc, argv);
555 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
556 fs = (int)atom_getintarg(12, argc, argv);
557 bflcol[0] = (int)atom_getintarg(13, argc, argv);
558 bflcol[1] = (int)atom_getintarg(14, argc, argv);
559 bflcol[2] = (int)atom_getintarg(15, argc, argv);
560 v = (int)atom_getintarg(16, argc, argv);
561 }
562 else iemgui_new_getnames(&x->x_gui, 6, 0);
563 if((argc == 18)&&IS_A_FLOAT(argv,17))
564 steady = (int)atom_getintarg(17, argc, argv);
565
566 x->x_gui.x_draw = (t_iemfunptr)hslider_draw;
567
568 x->x_gui.x_fsf.x_snd_able = 1;
569 x->x_gui.x_fsf.x_rcv_able = 1;
570
571 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
572 if(x->x_gui.x_isa.x_loadinit)
573 x->x_val = v;
574 else
575 x->x_val = 0;
576 x->x_pos = x->x_val;
577 if(lilo != 0) lilo = 1;
578 x->x_lin0_log1 = lilo;
579 if(steady != 0) steady = 1;
580 x->x_steady = steady;
581 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
582 x->x_gui.x_fsf.x_snd_able = 0;
583 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
584 x->x_gui.x_fsf.x_rcv_able = 0;
585 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
586 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
587 else { x->x_gui.x_fsf.x_font_style = 0;
588 strcpy(x->x_gui.x_font, "courier"); }
589 if(x->x_gui.x_fsf.x_rcv_able)
590 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
591 x->x_gui.x_ldx = ldx;
592 x->x_gui.x_ldy = ldy;
593 if(fs < 4)
594 fs = 4;
595 x->x_gui.x_fontsize = fs;
596 x->x_gui.x_h = iemgui_clip_size(h);
597 hslider_check_width(x, w);
598 hslider_check_minmax(x, min, max);
599 iemgui_all_colfromload(&x->x_gui, bflcol);
600 x->x_thick = 0;
601 iemgui_verify_snd_ne_rcv(&x->x_gui);
602 outlet_new(&x->x_gui.x_obj, &s_float);
603 return (x);
604}
605
606static void hslider_free(t_hslider *x)
607{
608 if(x->x_gui.x_fsf.x_rcv_able)
609 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
610 gfxstub_deleteforkey(x);
611}
612
613void g_hslider_setup(void)
614{
615 hslider_class = class_new(gensym("hsl"), (t_newmethod)hslider_new,
616 (t_method)hslider_free, sizeof(t_hslider), 0, A_GIMME, 0);
617#ifndef GGEE_HSLIDER_COMPATIBLE
618 class_addcreator((t_newmethod)hslider_new, gensym("hslider"), A_GIMME, 0);
619#endif
620 class_addbang(hslider_class,hslider_bang);
621 class_addfloat(hslider_class,hslider_float);
622 class_addmethod(hslider_class, (t_method)hslider_click, gensym("click"),
623 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
624 class_addmethod(hslider_class, (t_method)hslider_motion, gensym("motion"),
625 A_FLOAT, A_FLOAT, 0);
626 class_addmethod(hslider_class, (t_method)hslider_dialog, gensym("dialog"), A_GIMME, 0);
627 class_addmethod(hslider_class, (t_method)hslider_loadbang, gensym("loadbang"), 0);
628 class_addmethod(hslider_class, (t_method)hslider_set, gensym("set"), A_FLOAT, 0);
629 class_addmethod(hslider_class, (t_method)hslider_size, gensym("size"), A_GIMME, 0);
630 class_addmethod(hslider_class, (t_method)hslider_delta, gensym("delta"), A_GIMME, 0);
631 class_addmethod(hslider_class, (t_method)hslider_pos, gensym("pos"), A_GIMME, 0);
632 class_addmethod(hslider_class, (t_method)hslider_range, gensym("range"), A_GIMME, 0);
633 class_addmethod(hslider_class, (t_method)hslider_color, gensym("color"), A_GIMME, 0);
634 class_addmethod(hslider_class, (t_method)hslider_send, gensym("send"), A_DEFSYM, 0);
635 class_addmethod(hslider_class, (t_method)hslider_receive, gensym("receive"), A_DEFSYM, 0);
636 class_addmethod(hslider_class, (t_method)hslider_label, gensym("label"), A_DEFSYM, 0);
637 class_addmethod(hslider_class, (t_method)hslider_label_pos, gensym("label_pos"), A_GIMME, 0);
638 class_addmethod(hslider_class, (t_method)hslider_label_font, gensym("label_font"), A_GIMME, 0);
639 class_addmethod(hslider_class, (t_method)hslider_log, gensym("log"), 0);
640 class_addmethod(hslider_class, (t_method)hslider_lin, gensym("lin"), 0);
641 class_addmethod(hslider_class, (t_method)hslider_init, gensym("init"), A_FLOAT, 0);
642 class_addmethod(hslider_class, (t_method)hslider_steady, gensym("steady"), A_FLOAT, 0);
643 hslider_widgetbehavior.w_getrectfn = hslider_getrect;
644 hslider_widgetbehavior.w_displacefn = iemgui_displace;
645 hslider_widgetbehavior.w_selectfn = iemgui_select;
646 hslider_widgetbehavior.w_activatefn = NULL;
647 hslider_widgetbehavior.w_deletefn = iemgui_delete;
648 hslider_widgetbehavior.w_visfn = iemgui_vis;
649 hslider_widgetbehavior.w_clickfn = hslider_newclick;
650 class_setwidget(hslider_class, &hslider_widgetbehavior);
651 class_sethelpsymbol(hslider_class, gensym("hslider"));
652 class_setsavefn(hslider_class, hslider_save);
653 class_setpropertiesfn(hslider_class, hslider_properties);
654}
655/* Copyright (c) 1997-1999 Miller Puckette.
656 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
657 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
658
659/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
660/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
661
662
663#include <stdlib.h>
664#include <string.h>
665#include <stdio.h>
666#include <ctype.h>
667#include "m_pd.h"
668#include "g_canvas.h"
669#include "t_tk.h"
670#include "g_all_guis.h"
671#include <math.h>
672
673#ifdef MSW
674#include <io.h>
675#else
676#include <unistd.h>
677#endif
678
679
680/* ------------ hsl gui-horicontal slider ----------------------- */
681
682t_widgetbehavior hslider_widgetbehavior;
683static t_class *hslider_class;
684
685/* widget helper functions */
686
687static void hslider_draw_update(t_hslider *x, t_glist *glist)
688{
689 t_canvas *canvas=glist_getcanvas(glist);
690 int ypos=text_ypix(&x->x_gui.x_obj, glist);
691
692 if (glist_isvisible(glist))
693 {
694 int r = text_xpix(&x->x_gui.x_obj, glist) + (x->x_val + 50)/100;
695 sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
696 canvas, x, r, ypos+1,
697 r, ypos + x->x_gui.x_h);
698 if(x->x_val == x->x_center)
699 {
700 if(!x->x_thick)
701 {
702 sys_vgui(".x%x.c itemconfigure %xKNOB -width 7\n", canvas, x);
703 x->x_thick = 1;
704 }
705 }
706 else
707 {
708 if(x->x_thick)
709 {
710 sys_vgui(".x%x.c itemconfigure %xKNOB -width 3\n", canvas, x);
711 x->x_thick = 0;
712 }
713 }
714 }
715}
716
717static void hslider_draw_new(t_hslider *x, t_glist *glist)
718{
719 int xpos=text_xpix(&x->x_gui.x_obj, glist);
720 int ypos=text_ypix(&x->x_gui.x_obj, glist);
721 int r = xpos + (x->x_val + 50)/100;
722 t_canvas *canvas=glist_getcanvas(glist);
723
724 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
725 canvas, xpos-3, ypos,
726 xpos + x->x_gui.x_w+2, ypos + x->x_gui.x_h,
727 x->x_gui.x_bcol, x);
728 sys_vgui(".x%x.c create line %d %d %d %d -width 3 -fill #%6.6x -tags %xKNOB\n",
729 canvas, r, ypos+1, r,
730 ypos + x->x_gui.x_h, x->x_gui.x_fcol, x);
731 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
732 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
733 canvas, xpos+x->x_gui.x_ldx,
734 ypos+x->x_gui.x_ldy,
735 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
736 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
737 if(!x->x_gui.x_fsf.x_snd_able)
738 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
739 canvas, xpos-3, ypos + x->x_gui.x_h-1,
740 xpos+4, ypos + x->x_gui.x_h, x, 0);
741 if(!x->x_gui.x_fsf.x_rcv_able)
742 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
743 canvas, xpos-3, ypos,
744 xpos+4, ypos+1, x, 0);
745}
746
747static void hslider_draw_move(t_hslider *x, t_glist *glist)
748{
749 int xpos=text_xpix(&x->x_gui.x_obj, glist);
750 int ypos=text_ypix(&x->x_gui.x_obj, glist);
751 int r = xpos + (x->x_val + 50)/100;
752 t_canvas *canvas=glist_getcanvas(glist);
753
754 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
755 canvas, x,
756 xpos-3, ypos,
757 xpos + x->x_gui.x_w+2, ypos + x->x_gui.x_h);
758 sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
759 canvas, x, r, ypos+1,
760 r, ypos + x->x_gui.x_h);
761 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
762 canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
763 if(!x->x_gui.x_fsf.x_snd_able)
764 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
765 canvas, x, 0,
766 xpos-3, ypos + x->x_gui.x_h-1,
767 xpos+4, ypos + x->x_gui.x_h);
768 if(!x->x_gui.x_fsf.x_rcv_able)
769 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
770 canvas, x, 0,
771 xpos-3, ypos,
772 xpos+4, ypos+1);
773}
774
775static void hslider_draw_erase(t_hslider* x,t_glist* glist)
776{
777 t_canvas *canvas=glist_getcanvas(glist);
778
779 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
780 sys_vgui(".x%x.c delete %xKNOB\n", canvas, x);
781 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
782 if(!x->x_gui.x_fsf.x_snd_able)
783 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
784 if(!x->x_gui.x_fsf.x_rcv_able)
785 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
786}
787
788static void hslider_draw_config(t_hslider* x,t_glist* glist)
789{
790 t_canvas *canvas=glist_getcanvas(glist);
791
792 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
793 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
794 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
795 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
796 sys_vgui(".x%x.c itemconfigure %xKNOB -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
797 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
798}
799
800static void hslider_draw_io(t_hslider* x,t_glist* glist, int old_snd_rcv_flags)
801{
802 int xpos=text_xpix(&x->x_gui.x_obj, glist);
803 int ypos=text_ypix(&x->x_gui.x_obj, glist);
804 t_canvas *canvas=glist_getcanvas(glist);
805
806 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
807 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
808 canvas, xpos-3, ypos + x->x_gui.x_h-1,
809 xpos+4, ypos + x->x_gui.x_h, x, 0);
810 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
811 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
812 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
813 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
814 canvas, xpos-3, ypos,
815 xpos+4, ypos+1, x, 0);
816 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
817 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
818}
819
820static void hslider_draw_select(t_hslider* x,t_glist* glist)
821{
822 t_canvas *canvas=glist_getcanvas(glist);
823
824 if(x->x_gui.x_fsf.x_selected)
825 {
826 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
827 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
828 }
829 else
830 {
831 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
832 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
833 }
834}
835
836void hslider_draw(t_hslider *x, t_glist *glist, int mode)
837{
838 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
839 hslider_draw_update(x, glist);
840 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
841 hslider_draw_move(x, glist);
842 else if(mode == IEM_GUI_DRAW_MODE_NEW)
843 hslider_draw_new(x, glist);
844 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
845 hslider_draw_select(x, glist);
846 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
847 hslider_draw_erase(x, glist);
848 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
849 hslider_draw_config(x, glist);
850 else if(mode >= IEM_GUI_DRAW_MODE_IO)
851 hslider_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
852}
853
854/* ------------------------ hsl widgetbehaviour----------------------------- */
855
856
857static void hslider_getrect(t_gobj *z, t_glist *glist,
858 int *xp1, int *yp1, int *xp2, int *yp2)
859{
860 t_hslider* x = (t_hslider*)z;
861
862 *xp1 = text_xpix(&x->x_gui.x_obj, glist) - 3;
863 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
864 *xp2 = *xp1 + x->x_gui.x_w + 5;
865 *yp2 = *yp1 + x->x_gui.x_h;
866}
867
868static void hslider_save(t_gobj *z, t_binbuf *b)
869{
870 t_hslider *x = (t_hslider *)z;
871 int bflcol[3];
872 t_symbol *srl[3];
873
874 iemgui_save(&x->x_gui, srl, bflcol);
875 binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
876 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
877 gensym("hsl"), x->x_gui.x_w, x->x_gui.x_h,
878 (float)x->x_min, (float)x->x_max,
879 x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa),
880 srl[0], srl[1], srl[2],
881 x->x_gui.x_ldx, x->x_gui.x_ldy,
882 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
883 bflcol[0], bflcol[1], bflcol[2],
884 x->x_val, x->x_steady);
885 binbuf_addv(b, ";");
886}
887
888void hslider_check_width(t_hslider *x, int w)
889{
890 if(w < IEM_SL_MINSIZE)
891 w = IEM_SL_MINSIZE;
892 x->x_gui.x_w = w;
893 x->x_center = (x->x_gui.x_w-1)*50;
894 if(x->x_val > (x->x_gui.x_w*100 - 100))
895 {
896 x->x_pos = x->x_gui.x_w*100 - 100;
897 x->x_val = x->x_pos;
898 }
899 if(x->x_lin0_log1)
900 x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
901 else
902 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
903}
904
905void hslider_check_minmax(t_hslider *x, double min, double max)
906{
907 if(x->x_lin0_log1)
908 {
909 if((min == 0.0)&&(max == 0.0))
910 max = 1.0;
911 if(max > 0.0)
912 {
913 if(min <= 0.0)
914 min = 0.01*max;
915 }
916 else
917 {
918 if(min > 0.0)
919 max = 0.01*min;
920 }
921 }
922 x->x_min = min;
923 x->x_max = max;
924 if(x->x_min > x->x_max) /* bugfix */
925 x->x_gui.x_isa.x_reverse = 1;
926 else
927 x->x_gui.x_isa.x_reverse = 0;
928 if(x->x_lin0_log1)
929 x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
930 else
931 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
932}
933
934static void hslider_properties(t_gobj *z, t_glist *owner)
935{
936 t_hslider *x = (t_hslider *)z;
937 char buf[800];
938 t_symbol *srl[3];
939
940 iemgui_properties(&x->x_gui, srl);
941 sprintf(buf, "pdtk_iemgui_dialog %%s HSLIDER \
942 --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
943 -----------output-range:----------- %g left: %g right: %g \
944 %d lin log %d %d empty %d \
945 %s %s \
946 %s %d %d \
947 %d %d \
948 %d %d %d\n",
949 x->x_gui.x_w, IEM_SL_MINSIZE, x->x_gui.x_h, IEM_GUI_MINSIZE,
950 x->x_min, x->x_max, 0.0,/*no_schedule*/
951 x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
952 srl[0]->s_name, srl[1]->s_name,
953 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
954 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
955 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
956 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
957}
958
959static void hslider_set(t_hslider *x, t_floatarg f) /* bugfix */
960{
961 double g;
962
963 if(x->x_gui.x_isa.x_reverse) /* bugfix */
964 {
965 if(f > x->x_min)
966 f = x->x_min;
967 if(f < x->x_max)
968 f = x->x_max;
969 }
970 else
971 {
972 if(f > x->x_max)
973 f = x->x_max;
974 if(f < x->x_min)
975 f = x->x_min;
976 }
977 if(x->x_lin0_log1)
978 g = log(f/x->x_min)/x->x_k;
979 else
980 g = (f - x->x_min) / x->x_k;
981 x->x_val = (int)(100.0*g + 0.49999);
982 x->x_pos = x->x_val;
983 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
984}
985
986static void hslider_bang(t_hslider *x)
987{
988 double out;
989
990 if(x->x_lin0_log1)
991 out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
992 else
993 out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
994 if((out < 1.0e-10)&&(out > -1.0e-10))
995 out = 0.0;
996 outlet_float(x->x_gui.x_obj.ob_outlet, out);
997 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
998 pd_float(x->x_gui.x_snd->s_thing, out);
999}
1000
1001static void hslider_dialog(t_hslider *x, t_symbol *s, int argc, t_atom *argv)
1002{
1003 t_symbol *srl[3];
1004 int w = (int)atom_getintarg(0, argc, argv);
1005 int h = (int)atom_getintarg(1, argc, argv);
1006 double min = (double)atom_getfloatarg(2, argc, argv);
1007 double max = (double)atom_getfloatarg(3, argc, argv);
1008 int lilo = (int)atom_getintarg(4, argc, argv);
1009 int steady = (int)atom_getintarg(17, argc, argv);
1010 int sr_flags;
1011
1012 if(lilo != 0) lilo = 1;
1013 x->x_lin0_log1 = lilo;
1014 if(steady)
1015 x->x_steady = 1;
1016 else
1017 x->x_steady = 0;
1018 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
1019 x->x_gui.x_h = iemgui_clip_size(h);
1020 hslider_check_width(x, w);
1021 hslider_check_minmax(x, min, max);
1022 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
1023 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
1024 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
1025 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
1026}
1027
1028static void hslider_motion(t_hslider *x, t_floatarg dx, t_floatarg dy)
1029{
1030 int old = x->x_val;
1031
1032 if(x->x_gui.x_fsf.x_finemoved)
1033 x->x_pos += (int)dx;
1034 else
1035 x->x_pos += 100*(int)dx;
1036 x->x_val = x->x_pos;
1037 if(x->x_val > (100*x->x_gui.x_w - 100))
1038 {
1039 x->x_val = 100*x->x_gui.x_w - 100;
1040 x->x_pos += 50;
1041 x->x_pos -= x->x_pos%100;
1042 }
1043 if(x->x_val < 0)
1044 {
1045 x->x_val = 0;
1046 x->x_pos -= 50;
1047 x->x_pos -= x->x_pos%100;
1048 }
1049 if(old != x->x_val)
1050 {
1051 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1052 hslider_bang(x);
1053 }
1054}
1055
1056static void hslider_click(t_hslider *x, t_floatarg xpos, t_floatarg ypos,
1057 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
1058{
1059 if(!x->x_steady)
1060 x->x_val = (int)(100.0 * (xpos - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)));
1061 if(x->x_val > (100*x->x_gui.x_w - 100))
1062 x->x_val = 100*x->x_gui.x_w - 100;
1063 if(x->x_val < 0)
1064 x->x_val = 0;
1065 x->x_pos = x->x_val;
1066 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1067 hslider_bang(x);
1068 glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, (t_glistmotionfn)hslider_motion,
1069 0, xpos, ypos);
1070}
1071
1072static int hslider_newclick(t_gobj *z, struct _glist *glist,
1073 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1074{
1075 t_hslider* x = (t_hslider *)z;
1076
1077 if(doit)
1078 {
1079 hslider_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
1080 0, (t_floatarg)alt);
1081 if(shift)
1082 x->x_gui.x_fsf.x_finemoved = 1;
1083 else
1084 x->x_gui.x_fsf.x_finemoved = 0;
1085 }
1086 return (1);
1087}
1088
1089static void hslider_size(t_hslider *x, t_symbol *s, int ac, t_atom *av)
1090{
1091 hslider_check_width(x, (int)atom_getintarg(0, ac, av));
1092 if(ac > 1)
1093 x->x_gui.x_h = iemgui_clip_size((int)atom_getintarg(1, ac, av));
1094 iemgui_size((void *)x, &x->x_gui);
1095}
1096
1097static void hslider_delta(t_hslider *x, t_symbol *s, int ac, t_atom *av)
1098{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
1099
1100static void hslider_pos(t_hslider *x, t_symbol *s, int ac, t_atom *av)
1101{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
1102
1103static void hslider_range(t_hslider *x, t_symbol *s, int ac, t_atom *av)
1104{
1105 hslider_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
1106 (double)atom_getfloatarg(1, ac, av));
1107}
1108
1109static void hslider_color(t_hslider *x, t_symbol *s, int ac, t_atom *av)
1110{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
1111
1112static void hslider_send(t_hslider *x, t_symbol *s)
1113{iemgui_send(x, &x->x_gui, s);}
1114
1115static void hslider_receive(t_hslider *x, t_symbol *s)
1116{iemgui_receive(x, &x->x_gui, s);}
1117
1118static void hslider_label(t_hslider *x, t_symbol *s)
1119{iemgui_label((void *)x, &x->x_gui, s);}
1120
1121static void hslider_label_pos(t_hslider *x, t_symbol *s, int ac, t_atom *av)
1122{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
1123
1124static void hslider_label_font(t_hslider *x, t_symbol *s, int ac, t_atom *av)
1125{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
1126
1127static void hslider_log(t_hslider *x)
1128{
1129 x->x_lin0_log1 = 1;
1130 hslider_check_minmax(x, x->x_min, x->x_max);
1131}
1132
1133static void hslider_lin(t_hslider *x)
1134{
1135 x->x_lin0_log1 = 0;
1136 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
1137}
1138
1139static void hslider_init(t_hslider *x, t_floatarg f)
1140{
1141 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
1142}
1143
1144static void hslider_steady(t_hslider *x, t_floatarg f)
1145{
1146 x->x_steady = (f==0.0)?0:1;
1147}
1148
1149static void hslider_float(t_hslider *x, t_floatarg f)
1150{
1151 double out;
1152
1153 hslider_set(x, f);
1154 if(x->x_lin0_log1)
1155 out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
1156 else
1157 out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
1158 if((out < 1.0e-10)&&(out > -1.0e-10))
1159 out = 0.0;
1160 if(x->x_gui.x_fsf.x_put_in2out)
1161 {
1162 outlet_float(x->x_gui.x_obj.ob_outlet, out);
1163 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1164 pd_float(x->x_gui.x_snd->s_thing, out);
1165 }
1166}
1167
1168static void hslider_loadbang(t_hslider *x)
1169{
1170 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
1171 {
1172 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1173 hslider_bang(x);
1174 }
1175}
1176
1177static void *hslider_new(t_symbol *s, int argc, t_atom *argv)
1178{
1179 t_hslider *x = (t_hslider *)pd_new(hslider_class);
1180 int bflcol[]={-262144, -1, -1};
1181 int w=IEM_SL_DEFAULTSIZE, h=IEM_GUI_DEFAULTSIZE;
1182 int lilo=0, ldx=-2, ldy=-6, f=0, v=0, steady=1;
1183 int fs=8;
1184 double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
1185 char str[144];
1186
1187 iem_inttosymargs(&x->x_gui.x_isa, 0);
1188 iem_inttofstyle(&x->x_gui.x_fsf, 0);
1189
1190 if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
1191 &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
1192 &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
1193 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
1194 &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
1195 &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
1196 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
1197 &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
1198 &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
1199 {
1200 w = (int)atom_getintarg(0, argc, argv);
1201 h = (int)atom_getintarg(1, argc, argv);
1202 min = (double)atom_getfloatarg(2, argc, argv);
1203 max = (double)atom_getfloatarg(3, argc, argv);
1204 lilo = (int)atom_getintarg(4, argc, argv);
1205 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
1206 iemgui_new_getnames(&x->x_gui, 6, argv);
1207 ldx = (int)atom_getintarg(9, argc, argv);
1208 ldy = (int)atom_getintarg(10, argc, argv);
1209 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
1210 fs = (int)atom_getintarg(12, argc, argv);
1211 bflcol[0] = (int)atom_getintarg(13, argc, argv);
1212 bflcol[1] = (int)atom_getintarg(14, argc, argv);
1213 bflcol[2] = (int)atom_getintarg(15, argc, argv);
1214 v = (int)atom_getintarg(16, argc, argv);
1215 }
1216 else iemgui_new_getnames(&x->x_gui, 6, 0);
1217 if((argc == 18)&&IS_A_FLOAT(argv,17))
1218 steady = (int)atom_getintarg(17, argc, argv);
1219
1220 x->x_gui.x_draw = (t_iemfunptr)hslider_draw;
1221
1222 x->x_gui.x_fsf.x_snd_able = 1;
1223 x->x_gui.x_fsf.x_rcv_able = 1;
1224
1225 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
1226 if(x->x_gui.x_isa.x_loadinit)
1227 x->x_val = v;
1228 else
1229 x->x_val = 0;
1230 x->x_pos = x->x_val;
1231 if(lilo != 0) lilo = 1;
1232 x->x_lin0_log1 = lilo;
1233 if(steady != 0) steady = 1;
1234 x->x_steady = steady;
1235 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
1236 x->x_gui.x_fsf.x_snd_able = 0;
1237 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
1238 x->x_gui.x_fsf.x_rcv_able = 0;
1239 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
1240 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
1241 else { x->x_gui.x_fsf.x_font_style = 0;
1242 strcpy(x->x_gui.x_font, "courier"); }
1243 if(x->x_gui.x_fsf.x_rcv_able)
1244 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1245 x->x_gui.x_ldx = ldx;
1246 x->x_gui.x_ldy = ldy;
1247 if(fs < 4)
1248 fs = 4;
1249 x->x_gui.x_fontsize = fs;
1250 x->x_gui.x_h = iemgui_clip_size(h);
1251 hslider_check_width(x, w);
1252 hslider_check_minmax(x, min, max);
1253 iemgui_all_colfromload(&x->x_gui, bflcol);
1254 x->x_thick = 0;
1255 iemgui_verify_snd_ne_rcv(&x->x_gui);
1256 outlet_new(&x->x_gui.x_obj, &s_float);
1257 return (x);
1258}
1259
1260static void hslider_free(t_hslider *x)
1261{
1262 if(x->x_gui.x_fsf.x_rcv_able)
1263 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1264 gfxstub_deleteforkey(x);
1265}
1266
1267void g_hslider_setup(void)
1268{
1269 hslider_class = class_new(gensym("hsl"), (t_newmethod)hslider_new,
1270 (t_method)hslider_free, sizeof(t_hslider), 0, A_GIMME, 0);
1271#ifndef GGEE_HSLIDER_COMPATIBLE
1272 class_addcreator((t_newmethod)hslider_new, gensym("hslider"), A_GIMME, 0);
1273#endif
1274 class_addbang(hslider_class,hslider_bang);
1275 class_addfloat(hslider_class,hslider_float);
1276 class_addmethod(hslider_class, (t_method)hslider_click, gensym("click"),
1277 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1278 class_addmethod(hslider_class, (t_method)hslider_motion, gensym("motion"),
1279 A_FLOAT, A_FLOAT, 0);
1280 class_addmethod(hslider_class, (t_method)hslider_dialog, gensym("dialog"), A_GIMME, 0);
1281 class_addmethod(hslider_class, (t_method)hslider_loadbang, gensym("loadbang"), 0);
1282 class_addmethod(hslider_class, (t_method)hslider_set, gensym("set"), A_FLOAT, 0);
1283 class_addmethod(hslider_class, (t_method)hslider_size, gensym("size"), A_GIMME, 0);
1284 class_addmethod(hslider_class, (t_method)hslider_delta, gensym("delta"), A_GIMME, 0);
1285 class_addmethod(hslider_class, (t_method)hslider_pos, gensym("pos"), A_GIMME, 0);
1286 class_addmethod(hslider_class, (t_method)hslider_range, gensym("range"), A_GIMME, 0);
1287 class_addmethod(hslider_class, (t_method)hslider_color, gensym("color"), A_GIMME, 0);
1288 class_addmethod(hslider_class, (t_method)hslider_send, gensym("send"), A_DEFSYM, 0);
1289 class_addmethod(hslider_class, (t_method)hslider_receive, gensym("receive"), A_DEFSYM, 0);
1290 class_addmethod(hslider_class, (t_method)hslider_label, gensym("label"), A_DEFSYM, 0);
1291 class_addmethod(hslider_class, (t_method)hslider_label_pos, gensym("label_pos"), A_GIMME, 0);
1292 class_addmethod(hslider_class, (t_method)hslider_label_font, gensym("label_font"), A_GIMME, 0);
1293 class_addmethod(hslider_class, (t_method)hslider_log, gensym("log"), 0);
1294 class_addmethod(hslider_class, (t_method)hslider_lin, gensym("lin"), 0);
1295 class_addmethod(hslider_class, (t_method)hslider_init, gensym("init"), A_FLOAT, 0);
1296 class_addmethod(hslider_class, (t_method)hslider_steady, gensym("steady"), A_FLOAT, 0);
1297 hslider_widgetbehavior.w_getrectfn = hslider_getrect;
1298 hslider_widgetbehavior.w_displacefn = iemgui_displace;
1299 hslider_widgetbehavior.w_selectfn = iemgui_select;
1300 hslider_widgetbehavior.w_activatefn = NULL;
1301 hslider_widgetbehavior.w_deletefn = iemgui_delete;
1302 hslider_widgetbehavior.w_visfn = iemgui_vis;
1303 hslider_widgetbehavior.w_clickfn = hslider_newclick;
1304 class_setwidget(hslider_class, &hslider_widgetbehavior);
1305 class_sethelpsymbol(hslider_class, gensym("hslider"));
1306 class_setsavefn(hslider_class, hslider_save);
1307 class_setpropertiesfn(hslider_class, hslider_properties);
1308}
diff --git a/apps/plugins/pdbox/PDa/src/g_io.c b/apps/plugins/pdbox/PDa/src/g_io.c
new file mode 100644
index 0000000000..39788d2adb
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_io.c
@@ -0,0 +1,1224 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* graphical inlets and outlets, both for control and signals. */
6
7/* This code is highly inefficient; messages actually have to be forwarded
8by inlets and outlets. The outlet is in even worse shape than the inlet;
9in order to avoid having a "signal" method in the class, the oulet actually
10sprouts an inlet, which forwards the message to the "outlet" object, which
11sends it on to the outlet proper. Another way to do it would be to have
12separate classes for "signal" and "control" outlets, but this would complicate
13life elsewhere. */
14
15
16/* hacked to run subpatches with different samplerates
17 *
18 * mfg.gfd.uil
19 * IOhannes
20 *
21 * edited lines are marked with "IOhannes"
22 *
23 */
24
25#include "m_pd.h"
26#include "g_canvas.h"
27#include <string.h>
28void signal_setborrowed(t_signal *sig, t_signal *sig2);
29void signal_makereusable(t_signal *sig);
30
31/* ------------------------- vinlet -------------------------- */
32t_class *vinlet_class;
33
34typedef struct _vinlet
35{
36 t_object x_obj;
37 t_canvas *x_canvas;
38 t_inlet *x_inlet;
39 int x_bufsize;
40 t_float *x_buf; /* signal buffer; zero if not a signal */
41 t_float *x_endbuf;
42 t_float *x_fill;
43 t_float *x_read;
44 int x_hop;
45 /* if not reblocking, the next slot communicates the parent's inlet
46 signal from the prolog to the DSP routine: */
47 t_signal *x_directsignal;
48
49 t_resample x_updown; /* IOhannes */
50} t_vinlet;
51
52static void *vinlet_new(t_symbol *s)
53{
54 t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
55 x->x_canvas = canvas_getcurrent();
56 x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, 0);
57 x->x_bufsize = 0;
58 x->x_buf = 0;
59 outlet_new(&x->x_obj, 0);
60 return (x);
61}
62
63static void vinlet_bang(t_vinlet *x)
64{
65 outlet_bang(x->x_obj.ob_outlet);
66}
67
68static void vinlet_pointer(t_vinlet *x, t_gpointer *gp)
69{
70 outlet_pointer(x->x_obj.ob_outlet, gp);
71}
72
73static void vinlet_float(t_vinlet *x, t_float f)
74{
75 outlet_float(x->x_obj.ob_outlet, f);
76}
77
78static void vinlet_symbol(t_vinlet *x, t_symbol *s)
79{
80 outlet_symbol(x->x_obj.ob_outlet, s);
81}
82
83static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
84{
85 outlet_list(x->x_obj.ob_outlet, s, argc, argv);
86}
87
88static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
89{
90 outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
91}
92
93static void vinlet_free(t_vinlet *x)
94{
95 canvas_rminlet(x->x_canvas, x->x_inlet);
96 resample_free(&x->x_updown);
97}
98
99t_inlet *vinlet_getit(t_pd *x)
100{
101 if (pd_class(x) != vinlet_class) bug("vinlet_getit");
102 return (((t_vinlet *)x)->x_inlet);
103}
104
105/* ------------------------- signal inlet -------------------------- */
106int vinlet_issignal(t_vinlet *x)
107{
108 return (x->x_buf != 0);
109}
110
111static int tot;
112
113t_int *vinlet_perform(t_int *w)
114{
115 t_vinlet *x = (t_vinlet *)(w[1]);
116 t_float *out = (t_float *)(w[2]);
117 int n = (int)(w[3]);
118 t_float *in = x->x_read;
119#if 0
120 if (tot < 5) post("-in %x out %x n %d", in, out, n);
121 if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf);
122 if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]);
123#endif
124 while (n--) *out++ = *in++;
125 if (in == x->x_endbuf) in = x->x_buf;
126 x->x_read = in;
127 return (w+4);
128}
129
130static void vinlet_dsp(t_vinlet *x, t_signal **sp)
131{
132 t_signal *outsig;
133 /* no buffer means we're not a signal inlet */
134 if (!x->x_buf)
135 return;
136 outsig = sp[0];
137 if (x->x_directsignal)
138 {
139 signal_setborrowed(sp[0], x->x_directsignal);
140 }
141 else
142 {
143 dsp_add(vinlet_perform, 3, x, outsig->s_vec, outsig->s_n);
144 x->x_read = x->x_buf;
145 }
146}
147
148 /* prolog code: loads buffer from parent patch */
149t_int *vinlet_doprolog(t_int *w)
150{
151 t_vinlet *x = (t_vinlet *)(w[1]);
152 t_float *in = (t_float *)(w[2]);
153 int n = (int)(w[3]);
154 t_float *out = x->x_fill;
155 if (out == x->x_endbuf)
156 {
157 t_float *f1 = x->x_buf, *f2 = x->x_buf + x->x_hop;
158 int nshift = x->x_bufsize - x->x_hop;
159 out -= x->x_hop;
160 while (nshift--) *f1++ = *f2++;
161 }
162#if 0
163 if (tot < 5) post("in %x out %x n %x", in, out, n), tot++;
164 if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]);
165#endif
166
167 while (n--) *out++ = *in++;
168 x->x_fill = out;
169 return (w+4);
170}
171
172int inlet_getsignalindex(t_inlet *x);
173
174 /* set up prolog DSP code */
175void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs,
176 int myvecsize, int phase, int period, int frequency, int downsample, int upsample/* IOhannes */, int reblock,
177 int switched)
178{
179 t_signal *insig, *outsig;
180 x->x_updown.downsample = downsample;
181 x->x_updown.upsample = upsample;
182
183 /* if the "reblock" flag is set, arrange to copy data in from the
184 parent. */
185 if (reblock)
186 {
187 int parentvecsize, bufsize, oldbufsize, prologphase;
188 int re_parentvecsize; /* resampled parentvectorsize: IOhannes */
189 /* this should never happen: */
190 if (!x->x_buf) return;
191
192 /* the prolog code counts from 0 to period-1; the
193 phase is backed up by one so that AFTER the prolog code
194 runs, the "x_fill" phase is in sync with the "x_read" phase. */
195 prologphase = (phase - 1) & (period - 1);
196 if (parentsigs)
197 {
198 insig = parentsigs[inlet_getsignalindex(x->x_inlet)];
199 parentvecsize = insig->s_n;
200 re_parentvecsize = parentvecsize * upsample / downsample;
201 }
202 else
203 {
204 insig = 0;
205 parentvecsize = 1;
206 re_parentvecsize = 1;
207 }
208
209 bufsize = re_parentvecsize;
210 if (bufsize < myvecsize) bufsize = myvecsize;
211 if (bufsize != (oldbufsize = x->x_bufsize))
212 {
213 t_float *buf = x->x_buf;
214 t_freebytes(buf, oldbufsize * sizeof(*buf));
215 buf = (t_float *)t_getbytes(bufsize * sizeof(*buf));
216 memset((char *)buf, 0, bufsize * sizeof(*buf));
217 x->x_bufsize = bufsize;
218 x->x_endbuf = buf + bufsize;
219 x->x_buf = buf;
220 }
221 if (parentsigs)
222 {
223 /* IOhannes { */
224 x->x_hop = period * re_parentvecsize;
225
226 x->x_fill = x->x_endbuf -
227 (x->x_hop - prologphase * re_parentvecsize);
228
229 if (upsample * downsample == 1)
230 dsp_add(vinlet_doprolog, 3, x, insig->s_vec, re_parentvecsize);
231 else {
232 resamplefrom_dsp(&x->x_updown, insig->s_vec, parentvecsize, re_parentvecsize, x->x_updown.method);
233 dsp_add(vinlet_doprolog, 3, x, x->x_updown.s_vec, re_parentvecsize);
234 }
235
236 /* } IOhannes */
237 /* if the input signal's reference count is zero, we have
238 to free it here because we didn't in ugen_doit(). */
239 if (!insig->s_refcount)
240 signal_makereusable(insig);
241 }
242 else memset((char *)(x->x_buf), 0, bufsize * sizeof(*x->x_buf));
243 x->x_directsignal = 0;
244 }
245 else
246 {
247 /* no reblocking; in this case our output signal is "borrowed"
248 and merely needs to be pointed to the real one. */
249 x->x_directsignal = parentsigs[inlet_getsignalindex(x->x_inlet)];
250 }
251}
252
253//static void *vinlet_newsig(void)
254static void *vinlet_newsig(t_symbol *s)
255{
256 t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
257 x->x_canvas = canvas_getcurrent();
258 x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal);
259 x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
260 x->x_bufsize = 0;
261 x->x_directsignal = 0;
262 outlet_new(&x->x_obj, &s_signal);
263
264 resample_init(&x->x_updown);
265
266 /* this should be though over:
267 * it might prove hard to provide consistency between labeled up- & downsampling methods
268 * maybe indeces would be better...
269 *
270 * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !)
271 */
272 if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */
273 else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
274 else x->x_updown.method=0; /* up: zero-padding */
275
276 return (x);
277}
278
279static void vinlet_setup(void)
280{
281 vinlet_class = class_new(gensym("inlet"), (t_newmethod)vinlet_new,
282 (t_method)vinlet_free, sizeof(t_vinlet), CLASS_NOINLET, A_DEFSYM, 0);
283 class_addcreator((t_newmethod)vinlet_newsig, gensym("inlet~"), A_DEFSYM, 0);
284 class_addbang(vinlet_class, vinlet_bang);
285 class_addpointer(vinlet_class, vinlet_pointer);
286 class_addfloat(vinlet_class, vinlet_float);
287 class_addsymbol(vinlet_class, vinlet_symbol);
288 class_addlist(vinlet_class, vinlet_list);
289 class_addanything(vinlet_class, vinlet_anything);
290 class_addmethod(vinlet_class, (t_method)vinlet_dsp, gensym("dsp"), 0);
291 class_sethelpsymbol(vinlet_class, gensym("pd"));
292}
293
294/* ------------------------- voutlet -------------------------- */
295
296t_class *voutlet_class;
297
298typedef struct _voutlet
299{
300 t_object x_obj;
301 t_canvas *x_canvas;
302 t_outlet *x_parentoutlet;
303 int x_bufsize;
304 t_sample *x_buf; /* signal buffer; zero if not a signal */
305 t_sample *x_endbuf;
306 t_sample *x_empty; /* next to read out of buffer in epilog code */
307 t_sample *x_write; /* next to write in to buffer */
308 int x_hop; /* hopsize */
309 /* vice versa from the inlet, if we don't block, this holds the
310 parent's outlet signal, valid between the prolog and the dsp setup
311 routines. */
312 t_signal *x_directsignal;
313 /* and here's a flag indicating that we aren't blocked but have to
314 do a copy (because we're switched). */
315 char x_justcopyout;
316 t_resample x_updown; /* IOhannes */
317} t_voutlet;
318
319static void *voutlet_new(t_symbol *s)
320{
321 t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
322 x->x_canvas = canvas_getcurrent();
323 x->x_parentoutlet = canvas_addoutlet(x->x_canvas, &x->x_obj.ob_pd, 0);
324 inlet_new(&x->x_obj, &x->x_obj.ob_pd, 0, 0);
325 x->x_bufsize = 0;
326 x->x_buf = 0;
327 return (x);
328}
329
330static void voutlet_bang(t_voutlet *x)
331{
332 outlet_bang(x->x_parentoutlet);
333}
334
335static void voutlet_pointer(t_voutlet *x, t_gpointer *gp)
336{
337 outlet_pointer(x->x_parentoutlet, gp);
338}
339
340static void voutlet_float(t_voutlet *x, t_float f)
341{
342 outlet_float(x->x_parentoutlet, f);
343}
344
345static void voutlet_symbol(t_voutlet *x, t_symbol *s)
346{
347 outlet_symbol(x->x_parentoutlet, s);
348}
349
350static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
351{
352 outlet_list(x->x_parentoutlet, s, argc, argv);
353}
354
355static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
356{
357 outlet_anything(x->x_parentoutlet, s, argc, argv);
358}
359
360static void voutlet_free(t_voutlet *x)
361{
362 canvas_rmoutlet(x->x_canvas, x->x_parentoutlet);
363 resample_free(&x->x_updown);
364}
365
366t_outlet *voutlet_getit(t_pd *x)
367{
368 if (pd_class(x) != voutlet_class) bug("voutlet_getit");
369 return (((t_voutlet *)x)->x_parentoutlet);
370}
371
372/* ------------------------- signal outlet -------------------------- */
373
374int voutlet_issignal(t_voutlet *x)
375{
376 return (x->x_buf != 0);
377}
378
379 /* LATER optimize for non-overlapped case where the "+=" isn't needed */
380t_int *voutlet_perform(t_int *w)
381{
382 t_voutlet *x = (t_voutlet *)(w[1]);
383 t_sample *in = (t_sample *)(w[2]);
384 int n = (int)(w[3]);
385 t_sample *out = x->x_write, *outwas = out;
386#if 0
387 if (tot < 5) post("-in %x out %x n %d", in, out, n);
388 if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf);
389#endif
390 while (n--)
391 {
392 *out++ += *in++;
393 if (out == x->x_endbuf) out = x->x_buf;
394 }
395 outwas += x->x_hop;
396 if (outwas >= x->x_endbuf) outwas = x->x_buf;
397 x->x_write = outwas;
398 return (w+4);
399}
400
401 /* epilog code for blocking: write buffer to parent patch */
402static t_int *voutlet_doepilog(t_int *w)
403{
404 t_voutlet *x = (t_voutlet *)(w[1]);
405 t_sample *out = (t_sample *)(w[2]); /* IOhannes */
406
407 int n = (int)(w[3]);
408 t_sample *in = x->x_empty;
409 if (x->x_updown.downsample != x->x_updown.upsample) out = x->x_updown.s_vec; /* IOhannes */
410
411#if 0
412 if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++;
413#endif
414 for (; n--; in++) *out++ = *in, *in = 0;
415 if (in == x->x_endbuf) in = x->x_buf;
416 x->x_empty = in;
417 return (w+4);
418}
419
420/* IOhannes { */
421static t_int *voutlet_doepilog_resampling(t_int *w)
422{
423 t_voutlet *x = (t_voutlet *)(w[1]);
424 // t_float *dummy = (t_float *)(w[2]);
425 int n = (int)(w[2]);
426 t_sample *in = x->x_empty;
427 t_sample *out = x->x_updown.s_vec; /* IOhannes */
428
429#if 0
430 if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++;
431#endif
432 for (; n--; in++) *out++ = *in, *in = 0;
433 if (in == x->x_endbuf) in = x->x_buf;
434 x->x_empty = in;
435 return (w+3);
436}
437/* } IOhannes */
438int outlet_getsignalindex(t_outlet *x);
439
440 /* prolog for outlets -- store pointer to the outlet on the
441 parent, which, if "reblock" is false, will want to refer
442 back to whatever we see on our input during the "dsp" method
443 called later. */
444void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs,
445 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
446 int switched)
447{
448 x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */
449 x->x_justcopyout = (switched && !reblock);
450 if (reblock)
451 {
452 x->x_directsignal = 0;
453 }
454 else
455 {
456 if (!parentsigs) bug("voutlet_dspprolog");
457 x->x_directsignal =
458 parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
459 }
460}
461
462static void voutlet_dsp(t_voutlet *x, t_signal **sp)
463{
464 t_signal *insig;
465 if (!x->x_buf) return;
466 insig = sp[0];
467 if (x->x_justcopyout)
468 dsp_add_copy(insig->s_vec, x->x_directsignal->s_vec, insig->s_n);
469 else if (x->x_directsignal)
470 {
471 /* if we're just going to make the signal available on the
472 parent patch, hand it off to the parent signal. */
473 /* this is done elsewhere--> sp[0]->s_refcount++; */
474 signal_setborrowed(x->x_directsignal, sp[0]);
475 }
476 else
477 dsp_add(voutlet_perform, 3, x, insig->s_vec, insig->s_n);
478}
479
480 /* set up epilog DSP code. If we're reblocking, this is the
481 time to copy the samples out to the containing object's outlets.
482 If we aren't reblocking, there's nothing to do here. */
483void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs,
484 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
485 int switched)
486{
487 if (!x->x_buf) return; /* this shouldn't be necesssary... */
488 x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */
489 if (reblock)
490 {
491 t_signal *insig, *outsig;
492 int parentvecsize, bufsize, oldbufsize;
493 int re_parentvecsize; /* IOhannes */
494 int bigperiod, epilogphase, blockphase;
495 if (parentsigs)
496 {
497 outsig = parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
498 parentvecsize = outsig->s_n;
499 re_parentvecsize = parentvecsize * upsample / downsample;
500 }
501 else
502 {
503 outsig = 0;
504 parentvecsize = 1;
505 re_parentvecsize = 1;
506 }
507 // bigperiod = (downsample * myvecsize)/(upsample * parentvecsize); /* IOhannes */
508 bigperiod = myvecsize/re_parentvecsize; /* IOhannes */
509 if (!bigperiod) bigperiod = 1;
510 epilogphase = phase & (bigperiod - 1);
511 blockphase = (phase + period - 1) & (bigperiod - 1) & (- period);
512 // bufsize = parentvecsize * upsample; /* IOhannes */
513 bufsize = re_parentvecsize; /* IOhannes */
514 if (bufsize < myvecsize) bufsize = myvecsize;
515 if (bufsize != (oldbufsize = x->x_bufsize))
516 {
517 t_sample *buf = x->x_buf;
518 t_freebytes(buf, oldbufsize * sizeof(*buf));
519 buf = (t_sample *)t_getbytes(bufsize * sizeof(*buf));
520 memset((char *)buf, 0, bufsize * sizeof(*buf));
521 x->x_bufsize = bufsize;
522 x->x_endbuf = buf + bufsize;
523 x->x_buf = buf;
524 }
525 /* IOhannes: { */
526 if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog");
527 x->x_write = x->x_buf + re_parentvecsize * blockphase;
528 if (x->x_write == x->x_endbuf) x->x_write = x->x_buf;
529 if (period == 1 && frequency > 1)
530 x->x_hop = re_parentvecsize / frequency;
531 else x->x_hop = period * re_parentvecsize;
532 /* } IOhannes */
533 /* post("phase %d, block %d, parent %d", phase & 63,
534 parentvecsize * blockphase, parentvecsize * epilogphase); */
535 if (parentsigs)
536 {
537 /* set epilog pointer and schedule it */
538 /* IOhannes { */
539 x->x_empty = x->x_buf + re_parentvecsize * epilogphase;
540 if (upsample * downsample == 1)
541 dsp_add(voutlet_doepilog, 3, x, outsig->s_vec, re_parentvecsize);
542 else {
543 dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize);
544 resampleto_dsp(&x->x_updown, outsig->s_vec, re_parentvecsize, parentvecsize, x->x_updown.method);
545 }
546 /* } IOhannes */
547 }
548 }
549 /* if we aren't blocked but we are switched, the epilog code just
550 copies zeros to the output. In this case the blocking code actually
551 jumps over the epilog if the block is running. */
552 else if (switched)
553 {
554 if (parentsigs)
555 {
556 t_signal *outsig =
557 parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
558 dsp_add_zero(outsig->s_vec, outsig->s_n);
559 }
560 }
561}
562
563static void *voutlet_newsig(t_symbol *s)
564{
565 t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
566 x->x_canvas = canvas_getcurrent();
567 x->x_parentoutlet = canvas_addoutlet(x->x_canvas,
568 &x->x_obj.ob_pd, &s_signal);
569 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
570 x->x_endbuf = x->x_buf = (t_sample *)getbytes(0);
571 x->x_bufsize = 0;
572
573 resample_init(&x->x_updown);
574
575 /* this should be though over:
576 * it might prove hard to provide consistency between labeled up- & downsampling methods
577 * maybe indeces would be better...
578 *
579 * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !)
580 */
581 if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */
582 else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
583 else if (s == gensym("linear"))x->x_updown.method=2; /* up: linear interpolation */
584 else x->x_updown.method=0; /* up: zero-padding; down: ignore samples inbetween */
585
586 return (x);
587}
588
589
590static void voutlet_setup(void)
591{
592 voutlet_class = class_new(gensym("outlet"), (t_newmethod)voutlet_new,
593 (t_method)voutlet_free, sizeof(t_voutlet), CLASS_NOINLET, A_DEFSYM, 0);
594 class_addcreator((t_newmethod)voutlet_newsig, gensym("outlet~"), A_DEFSYM, 0);
595 class_addbang(voutlet_class, voutlet_bang);
596 class_addpointer(voutlet_class, voutlet_pointer);
597 class_addfloat(voutlet_class, (t_method)voutlet_float);
598 class_addsymbol(voutlet_class, voutlet_symbol);
599 class_addlist(voutlet_class, voutlet_list);
600 class_addanything(voutlet_class, voutlet_anything);
601 class_addmethod(voutlet_class, (t_method)voutlet_dsp, gensym("dsp"), 0);
602 class_sethelpsymbol(voutlet_class, gensym("pd"));
603}
604
605
606/* ---------------------------- overall setup ----------------------------- */
607
608void g_io_setup(void)
609{
610 vinlet_setup();
611 voutlet_setup();
612}
613/* Copyright (c) 1997-1999 Miller Puckette.
614* For information on usage and redistribution, and for a DISCLAIMER OF ALL
615* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
616
617/* graphical inlets and outlets, both for control and signals. */
618
619/* This code is highly inefficient; messages actually have to be forwarded
620by inlets and outlets. The outlet is in even worse shape than the inlet;
621in order to avoid having a "signal" method in the class, the oulet actually
622sprouts an inlet, which forwards the message to the "outlet" object, which
623sends it on to the outlet proper. Another way to do it would be to have
624separate classes for "signal" and "control" outlets, but this would complicate
625life elsewhere. */
626
627
628/* hacked to run subpatches with different samplerates
629 *
630 * mfg.gfd.uil
631 * IOhannes
632 *
633 * edited lines are marked with "IOhannes"
634 *
635 */
636
637#include "m_pd.h"
638#include "g_canvas.h"
639#include <string.h>
640void signal_setborrowed(t_signal *sig, t_signal *sig2);
641void signal_makereusable(t_signal *sig);
642
643/* ------------------------- vinlet -------------------------- */
644t_class *vinlet_class;
645
646typedef struct _vinlet
647{
648 t_object x_obj;
649 t_canvas *x_canvas;
650 t_inlet *x_inlet;
651 int x_bufsize;
652 t_float *x_buf; /* signal buffer; zero if not a signal */
653 t_float *x_endbuf;
654 t_float *x_fill;
655 t_float *x_read;
656 int x_hop;
657 /* if not reblocking, the next slot communicates the parent's inlet
658 signal from the prolog to the DSP routine: */
659 t_signal *x_directsignal;
660
661 t_resample x_updown; /* IOhannes */
662} t_vinlet;
663
664static void *vinlet_new(t_symbol *s)
665{
666 t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
667 x->x_canvas = canvas_getcurrent();
668 x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, 0);
669 x->x_bufsize = 0;
670 x->x_buf = 0;
671 outlet_new(&x->x_obj, 0);
672 return (x);
673}
674
675static void vinlet_bang(t_vinlet *x)
676{
677 outlet_bang(x->x_obj.ob_outlet);
678}
679
680static void vinlet_pointer(t_vinlet *x, t_gpointer *gp)
681{
682 outlet_pointer(x->x_obj.ob_outlet, gp);
683}
684
685static void vinlet_float(t_vinlet *x, t_float f)
686{
687 outlet_float(x->x_obj.ob_outlet, f);
688}
689
690static void vinlet_symbol(t_vinlet *x, t_symbol *s)
691{
692 outlet_symbol(x->x_obj.ob_outlet, s);
693}
694
695static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
696{
697 outlet_list(x->x_obj.ob_outlet, s, argc, argv);
698}
699
700static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
701{
702 outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
703}
704
705static void vinlet_free(t_vinlet *x)
706{
707 canvas_rminlet(x->x_canvas, x->x_inlet);
708 resample_free(&x->x_updown);
709}
710
711t_inlet *vinlet_getit(t_pd *x)
712{
713 if (pd_class(x) != vinlet_class) bug("vinlet_getit");
714 return (((t_vinlet *)x)->x_inlet);
715}
716
717/* ------------------------- signal inlet -------------------------- */
718int vinlet_issignal(t_vinlet *x)
719{
720 return (x->x_buf != 0);
721}
722
723static int tot;
724
725t_int *vinlet_perform(t_int *w)
726{
727 t_vinlet *x = (t_vinlet *)(w[1]);
728 t_float *out = (t_float *)(w[2]);
729 int n = (int)(w[3]);
730 t_float *in = x->x_read;
731#if 0
732 if (tot < 5) post("-in %x out %x n %d", in, out, n);
733 if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf);
734 if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]);
735#endif
736 while (n--) *out++ = *in++;
737 if (in == x->x_endbuf) in = x->x_buf;
738 x->x_read = in;
739 return (w+4);
740}
741
742static void vinlet_dsp(t_vinlet *x, t_signal **sp)
743{
744 t_signal *outsig;
745 /* no buffer means we're not a signal inlet */
746 if (!x->x_buf)
747 return;
748 outsig = sp[0];
749 if (x->x_directsignal)
750 {
751 signal_setborrowed(sp[0], x->x_directsignal);
752 }
753 else
754 {
755 dsp_add(vinlet_perform, 3, x, outsig->s_vec, outsig->s_n);
756 x->x_read = x->x_buf;
757 }
758}
759
760 /* prolog code: loads buffer from parent patch */
761t_int *vinlet_doprolog(t_int *w)
762{
763 t_vinlet *x = (t_vinlet *)(w[1]);
764 t_float *in = (t_float *)(w[2]);
765 int n = (int)(w[3]);
766 t_float *out = x->x_fill;
767 if (out == x->x_endbuf)
768 {
769 t_float *f1 = x->x_buf, *f2 = x->x_buf + x->x_hop;
770 int nshift = x->x_bufsize - x->x_hop;
771 out -= x->x_hop;
772 while (nshift--) *f1++ = *f2++;
773 }
774#if 0
775 if (tot < 5) post("in %x out %x n %x", in, out, n), tot++;
776 if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]);
777#endif
778
779 while (n--) *out++ = *in++;
780 x->x_fill = out;
781 return (w+4);
782}
783
784int inlet_getsignalindex(t_inlet *x);
785
786 /* set up prolog DSP code */
787void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs,
788 int myvecsize, int phase, int period, int frequency, int downsample, int upsample/* IOhannes */, int reblock,
789 int switched)
790{
791 t_signal *insig, *outsig;
792 x->x_updown.downsample = downsample;
793 x->x_updown.upsample = upsample;
794
795 /* if the "reblock" flag is set, arrange to copy data in from the
796 parent. */
797 if (reblock)
798 {
799 int parentvecsize, bufsize, oldbufsize, prologphase;
800 int re_parentvecsize; /* resampled parentvectorsize: IOhannes */
801 /* this should never happen: */
802 if (!x->x_buf) return;
803
804 /* the prolog code counts from 0 to period-1; the
805 phase is backed up by one so that AFTER the prolog code
806 runs, the "x_fill" phase is in sync with the "x_read" phase. */
807 prologphase = (phase - 1) & (period - 1);
808 if (parentsigs)
809 {
810 insig = parentsigs[inlet_getsignalindex(x->x_inlet)];
811 parentvecsize = insig->s_n;
812 re_parentvecsize = parentvecsize * upsample / downsample;
813 }
814 else
815 {
816 insig = 0;
817 parentvecsize = 1;
818 re_parentvecsize = 1;
819 }
820
821 bufsize = re_parentvecsize;
822 if (bufsize < myvecsize) bufsize = myvecsize;
823 if (bufsize != (oldbufsize = x->x_bufsize))
824 {
825 t_float *buf = x->x_buf;
826 t_freebytes(buf, oldbufsize * sizeof(*buf));
827 buf = (t_float *)t_getbytes(bufsize * sizeof(*buf));
828 memset((char *)buf, 0, bufsize * sizeof(*buf));
829 x->x_bufsize = bufsize;
830 x->x_endbuf = buf + bufsize;
831 x->x_buf = buf;
832 }
833 if (parentsigs)
834 {
835 /* IOhannes { */
836 x->x_hop = period * re_parentvecsize;
837
838 x->x_fill = x->x_endbuf -
839 (x->x_hop - prologphase * re_parentvecsize);
840
841 if (upsample * downsample == 1)
842 dsp_add(vinlet_doprolog, 3, x, insig->s_vec, re_parentvecsize);
843 else {
844 resamplefrom_dsp(&x->x_updown, insig->s_vec, parentvecsize, re_parentvecsize, x->x_updown.method);
845 dsp_add(vinlet_doprolog, 3, x, x->x_updown.s_vec, re_parentvecsize);
846 }
847
848 /* } IOhannes */
849 /* if the input signal's reference count is zero, we have
850 to free it here because we didn't in ugen_doit(). */
851 if (!insig->s_refcount)
852 signal_makereusable(insig);
853 }
854 else memset((char *)(x->x_buf), 0, bufsize * sizeof(*x->x_buf));
855 x->x_directsignal = 0;
856 }
857 else
858 {
859 /* no reblocking; in this case our output signal is "borrowed"
860 and merely needs to be pointed to the real one. */
861 x->x_directsignal = parentsigs[inlet_getsignalindex(x->x_inlet)];
862 }
863}
864
865//static void *vinlet_newsig(void)
866static void *vinlet_newsig(t_symbol *s)
867{
868 t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
869 x->x_canvas = canvas_getcurrent();
870 x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal);
871 x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
872 x->x_bufsize = 0;
873 x->x_directsignal = 0;
874 outlet_new(&x->x_obj, &s_signal);
875
876 resample_init(&x->x_updown);
877
878 /* this should be though over:
879 * it might prove hard to provide consistency between labeled up- & downsampling methods
880 * maybe indeces would be better...
881 *
882 * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !)
883 */
884 if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */
885 else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
886 else x->x_updown.method=0; /* up: zero-padding */
887
888 return (x);
889}
890
891static void vinlet_setup(void)
892{
893 vinlet_class = class_new(gensym("inlet"), (t_newmethod)vinlet_new,
894 (t_method)vinlet_free, sizeof(t_vinlet), CLASS_NOINLET, A_DEFSYM, 0);
895 class_addcreator((t_newmethod)vinlet_newsig, gensym("inlet~"), A_DEFSYM, 0);
896 class_addbang(vinlet_class, vinlet_bang);
897 class_addpointer(vinlet_class, vinlet_pointer);
898 class_addfloat(vinlet_class, vinlet_float);
899 class_addsymbol(vinlet_class, vinlet_symbol);
900 class_addlist(vinlet_class, vinlet_list);
901 class_addanything(vinlet_class, vinlet_anything);
902 class_addmethod(vinlet_class, (t_method)vinlet_dsp, gensym("dsp"), 0);
903 class_sethelpsymbol(vinlet_class, gensym("pd"));
904}
905
906/* ------------------------- voutlet -------------------------- */
907
908t_class *voutlet_class;
909
910typedef struct _voutlet
911{
912 t_object x_obj;
913 t_canvas *x_canvas;
914 t_outlet *x_parentoutlet;
915 int x_bufsize;
916 t_sample *x_buf; /* signal buffer; zero if not a signal */
917 t_sample *x_endbuf;
918 t_sample *x_empty; /* next to read out of buffer in epilog code */
919 t_sample *x_write; /* next to write in to buffer */
920 int x_hop; /* hopsize */
921 /* vice versa from the inlet, if we don't block, this holds the
922 parent's outlet signal, valid between the prolog and the dsp setup
923 routines. */
924 t_signal *x_directsignal;
925 /* and here's a flag indicating that we aren't blocked but have to
926 do a copy (because we're switched). */
927 char x_justcopyout;
928 t_resample x_updown; /* IOhannes */
929} t_voutlet;
930
931static void *voutlet_new(t_symbol *s)
932{
933 t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
934 x->x_canvas = canvas_getcurrent();
935 x->x_parentoutlet = canvas_addoutlet(x->x_canvas, &x->x_obj.ob_pd, 0);
936 inlet_new(&x->x_obj, &x->x_obj.ob_pd, 0, 0);
937 x->x_bufsize = 0;
938 x->x_buf = 0;
939 return (x);
940}
941
942static void voutlet_bang(t_voutlet *x)
943{
944 outlet_bang(x->x_parentoutlet);
945}
946
947static void voutlet_pointer(t_voutlet *x, t_gpointer *gp)
948{
949 outlet_pointer(x->x_parentoutlet, gp);
950}
951
952static void voutlet_float(t_voutlet *x, t_float f)
953{
954 outlet_float(x->x_parentoutlet, f);
955}
956
957static void voutlet_symbol(t_voutlet *x, t_symbol *s)
958{
959 outlet_symbol(x->x_parentoutlet, s);
960}
961
962static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
963{
964 outlet_list(x->x_parentoutlet, s, argc, argv);
965}
966
967static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
968{
969 outlet_anything(x->x_parentoutlet, s, argc, argv);
970}
971
972static void voutlet_free(t_voutlet *x)
973{
974 canvas_rmoutlet(x->x_canvas, x->x_parentoutlet);
975 resample_free(&x->x_updown);
976}
977
978t_outlet *voutlet_getit(t_pd *x)
979{
980 if (pd_class(x) != voutlet_class) bug("voutlet_getit");
981 return (((t_voutlet *)x)->x_parentoutlet);
982}
983
984/* ------------------------- signal outlet -------------------------- */
985
986int voutlet_issignal(t_voutlet *x)
987{
988 return (x->x_buf != 0);
989}
990
991 /* LATER optimize for non-overlapped case where the "+=" isn't needed */
992t_int *voutlet_perform(t_int *w)
993{
994 t_voutlet *x = (t_voutlet *)(w[1]);
995 t_sample *in = (t_sample *)(w[2]);
996 int n = (int)(w[3]);
997 t_sample *out = x->x_write, *outwas = out;
998#if 0
999 if (tot < 5) post("-in %x out %x n %d", in, out, n);
1000 if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf);
1001#endif
1002 while (n--)
1003 {
1004 *out++ += *in++;
1005 if (out == x->x_endbuf) out = x->x_buf;
1006 }
1007 outwas += x->x_hop;
1008 if (outwas >= x->x_endbuf) outwas = x->x_buf;
1009 x->x_write = outwas;
1010 return (w+4);
1011}
1012
1013 /* epilog code for blocking: write buffer to parent patch */
1014static t_int *voutlet_doepilog(t_int *w)
1015{
1016 t_voutlet *x = (t_voutlet *)(w[1]);
1017 t_sample *out = (t_sample *)(w[2]); /* IOhannes */
1018
1019 int n = (int)(w[3]);
1020 t_sample *in = x->x_empty;
1021 if (x->x_updown.downsample != x->x_updown.upsample) out = x->x_updown.s_vec; /* IOhannes */
1022
1023#if 0
1024 if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++;
1025#endif
1026 for (; n--; in++) *out++ = *in, *in = 0;
1027 if (in == x->x_endbuf) in = x->x_buf;
1028 x->x_empty = in;
1029 return (w+4);
1030}
1031
1032/* IOhannes { */
1033static t_int *voutlet_doepilog_resampling(t_int *w)
1034{
1035 t_voutlet *x = (t_voutlet *)(w[1]);
1036 // t_float *dummy = (t_float *)(w[2]);
1037 int n = (int)(w[2]);
1038 t_sample *in = x->x_empty;
1039 t_sample *out = x->x_updown.s_vec; /* IOhannes */
1040
1041#if 0
1042 if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++;
1043#endif
1044 for (; n--; in++) *out++ = *in, *in = 0;
1045 if (in == x->x_endbuf) in = x->x_buf;
1046 x->x_empty = in;
1047 return (w+3);
1048}
1049/* } IOhannes */
1050int outlet_getsignalindex(t_outlet *x);
1051
1052 /* prolog for outlets -- store pointer to the outlet on the
1053 parent, which, if "reblock" is false, will want to refer
1054 back to whatever we see on our input during the "dsp" method
1055 called later. */
1056void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs,
1057 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1058 int switched)
1059{
1060 x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */
1061 x->x_justcopyout = (switched && !reblock);
1062 if (reblock)
1063 {
1064 x->x_directsignal = 0;
1065 }
1066 else
1067 {
1068 if (!parentsigs) bug("voutlet_dspprolog");
1069 x->x_directsignal =
1070 parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
1071 }
1072}
1073
1074static void voutlet_dsp(t_voutlet *x, t_signal **sp)
1075{
1076 t_signal *insig;
1077 if (!x->x_buf) return;
1078 insig = sp[0];
1079 if (x->x_justcopyout)
1080 dsp_add_copy(insig->s_vec, x->x_directsignal->s_vec, insig->s_n);
1081 else if (x->x_directsignal)
1082 {
1083 /* if we're just going to make the signal available on the
1084 parent patch, hand it off to the parent signal. */
1085 /* this is done elsewhere--> sp[0]->s_refcount++; */
1086 signal_setborrowed(x->x_directsignal, sp[0]);
1087 }
1088 else
1089 dsp_add(voutlet_perform, 3, x, insig->s_vec, insig->s_n);
1090}
1091
1092 /* set up epilog DSP code. If we're reblocking, this is the
1093 time to copy the samples out to the containing object's outlets.
1094 If we aren't reblocking, there's nothing to do here. */
1095void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs,
1096 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1097 int switched)
1098{
1099 if (!x->x_buf) return; /* this shouldn't be necesssary... */
1100 x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */
1101 if (reblock)
1102 {
1103 t_signal *insig, *outsig;
1104 int parentvecsize, bufsize, oldbufsize;
1105 int re_parentvecsize; /* IOhannes */
1106 int bigperiod, epilogphase, blockphase;
1107 if (parentsigs)
1108 {
1109 outsig = parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
1110 parentvecsize = outsig->s_n;
1111 re_parentvecsize = parentvecsize * upsample / downsample;
1112 }
1113 else
1114 {
1115 outsig = 0;
1116 parentvecsize = 1;
1117 re_parentvecsize = 1;
1118 }
1119 // bigperiod = (downsample * myvecsize)/(upsample * parentvecsize); /* IOhannes */
1120 bigperiod = myvecsize/re_parentvecsize; /* IOhannes */
1121 if (!bigperiod) bigperiod = 1;
1122 epilogphase = phase & (bigperiod - 1);
1123 blockphase = (phase + period - 1) & (bigperiod - 1) & (- period);
1124 // bufsize = parentvecsize * upsample; /* IOhannes */
1125 bufsize = re_parentvecsize; /* IOhannes */
1126 if (bufsize < myvecsize) bufsize = myvecsize;
1127 if (bufsize != (oldbufsize = x->x_bufsize))
1128 {
1129 t_sample *buf = x->x_buf;
1130 t_freebytes(buf, oldbufsize * sizeof(*buf));
1131 buf = (t_sample *)t_getbytes(bufsize * sizeof(*buf));
1132 memset((char *)buf, 0, bufsize * sizeof(*buf));
1133 x->x_bufsize = bufsize;
1134 x->x_endbuf = buf + bufsize;
1135 x->x_buf = buf;
1136 }
1137 /* IOhannes: { */
1138 if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog");
1139 x->x_write = x->x_buf + re_parentvecsize * blockphase;
1140 if (x->x_write == x->x_endbuf) x->x_write = x->x_buf;
1141 if (period == 1 && frequency > 1)
1142 x->x_hop = re_parentvecsize / frequency;
1143 else x->x_hop = period * re_parentvecsize;
1144 /* } IOhannes */
1145 /* post("phase %d, block %d, parent %d", phase & 63,
1146 parentvecsize * blockphase, parentvecsize * epilogphase); */
1147 if (parentsigs)
1148 {
1149 /* set epilog pointer and schedule it */
1150 /* IOhannes { */
1151 x->x_empty = x->x_buf + re_parentvecsize * epilogphase;
1152 if (upsample * downsample == 1)
1153 dsp_add(voutlet_doepilog, 3, x, outsig->s_vec, re_parentvecsize);
1154 else {
1155 dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize);
1156 resampleto_dsp(&x->x_updown, outsig->s_vec, re_parentvecsize, parentvecsize, x->x_updown.method);
1157 }
1158 /* } IOhannes */
1159 }
1160 }
1161 /* if we aren't blocked but we are switched, the epilog code just
1162 copies zeros to the output. In this case the blocking code actually
1163 jumps over the epilog if the block is running. */
1164 else if (switched)
1165 {
1166 if (parentsigs)
1167 {
1168 t_signal *outsig =
1169 parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
1170 dsp_add_zero(outsig->s_vec, outsig->s_n);
1171 }
1172 }
1173}
1174
1175static void *voutlet_newsig(t_symbol *s)
1176{
1177 t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
1178 x->x_canvas = canvas_getcurrent();
1179 x->x_parentoutlet = canvas_addoutlet(x->x_canvas,
1180 &x->x_obj.ob_pd, &s_signal);
1181 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
1182 x->x_endbuf = x->x_buf = (t_sample *)getbytes(0);
1183 x->x_bufsize = 0;
1184
1185 resample_init(&x->x_updown);
1186
1187 /* this should be though over:
1188 * it might prove hard to provide consistency between labeled up- & downsampling methods
1189 * maybe indeces would be better...
1190 *
1191 * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !)
1192 */
1193 if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */
1194 else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
1195 else if (s == gensym("linear"))x->x_updown.method=2; /* up: linear interpolation */
1196 else x->x_updown.method=0; /* up: zero-padding; down: ignore samples inbetween */
1197
1198 return (x);
1199}
1200
1201
1202static void voutlet_setup(void)
1203{
1204 voutlet_class = class_new(gensym("outlet"), (t_newmethod)voutlet_new,
1205 (t_method)voutlet_free, sizeof(t_voutlet), CLASS_NOINLET, A_DEFSYM, 0);
1206 class_addcreator((t_newmethod)voutlet_newsig, gensym("outlet~"), A_DEFSYM, 0);
1207 class_addbang(voutlet_class, voutlet_bang);
1208 class_addpointer(voutlet_class, voutlet_pointer);
1209 class_addfloat(voutlet_class, (t_method)voutlet_float);
1210 class_addsymbol(voutlet_class, voutlet_symbol);
1211 class_addlist(voutlet_class, voutlet_list);
1212 class_addanything(voutlet_class, voutlet_anything);
1213 class_addmethod(voutlet_class, (t_method)voutlet_dsp, gensym("dsp"), 0);
1214 class_sethelpsymbol(voutlet_class, gensym("pd"));
1215}
1216
1217
1218/* ---------------------------- overall setup ----------------------------- */
1219
1220void g_io_setup(void)
1221{
1222 vinlet_setup();
1223 voutlet_setup();
1224}
diff --git a/apps/plugins/pdbox/PDa/src/g_mycanvas.c b/apps/plugins/pdbox/PDa/src/g_mycanvas.c
new file mode 100644
index 0000000000..24dfbb246b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_mycanvas.c
@@ -0,0 +1,770 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
7
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <ctype.h>
13#include "m_pd.h"
14#include "g_canvas.h"
15#include "t_tk.h"
16#include "g_all_guis.h"
17#include <math.h>
18
19#ifdef MSW
20#include <io.h>
21#else
22#include <unistd.h>
23#endif
24
25/* ---------- cnv my gui-canvas for a window ---------------- */
26
27t_widgetbehavior my_canvas_widgetbehavior;
28static t_class *my_canvas_class;
29
30/* widget helper functions */
31
32void my_canvas_draw_new(t_my_canvas *x, t_glist *glist)
33{
34 int xpos=text_xpix(&x->x_gui.x_obj, glist);
35 int ypos=text_ypix(&x->x_gui.x_obj, glist);
36 t_canvas *canvas=glist_getcanvas(glist);
37
38 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xRECT\n",
39 canvas, xpos, ypos,
40 xpos + x->x_vis_w, ypos + x->x_vis_h,
41 x->x_gui.x_bcol, x->x_gui.x_bcol, x);
42 sys_vgui(".x%x.c create rectangle %d %d %d %d -outline #%6.6x -tags %xBASE\n",
43 canvas, xpos, ypos,
44 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h,
45 x->x_gui.x_bcol, x);
46 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
47 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
48 canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
49 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
50 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
51}
52
53void my_canvas_draw_move(t_my_canvas *x, t_glist *glist)
54{
55 int xpos=text_xpix(&x->x_gui.x_obj, glist);
56 int ypos=text_ypix(&x->x_gui.x_obj, glist);
57 t_canvas *canvas=glist_getcanvas(glist);
58
59 sys_vgui(".x%x.c coords %xRECT %d %d %d %d\n",
60 canvas, x, xpos, ypos, xpos + x->x_vis_w,
61 ypos + x->x_vis_h);
62 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
63 canvas, x, xpos, ypos,
64 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h);
65 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
66 canvas, x, xpos+x->x_gui.x_ldx,
67 ypos+x->x_gui.x_ldy);
68}
69
70void my_canvas_draw_erase(t_my_canvas* x, t_glist* glist)
71{
72 t_canvas *canvas=glist_getcanvas(glist);
73
74 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
75 sys_vgui(".x%x.c delete %xRECT\n", canvas, x);
76 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
77}
78
79void my_canvas_draw_config(t_my_canvas* x, t_glist* glist)
80{
81 t_canvas *canvas=glist_getcanvas(glist);
82
83 sys_vgui(".x%x.c itemconfigure %xRECT -fill #%6.6x -outline #%6.6x\n", canvas, x,
84 x->x_gui.x_bcol, x->x_gui.x_bcol);
85 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x,
86 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_bcol);
87 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
88 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol,
89 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
90}
91
92void my_canvas_draw_select(t_my_canvas* x, t_glist* glist)
93{
94 t_canvas *canvas=glist_getcanvas(glist);
95
96 if(x->x_gui.x_fsf.x_selected)
97 {
98 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
99 }
100 else
101 {
102 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, x->x_gui.x_bcol);
103 }
104}
105
106void my_canvas_draw(t_my_canvas *x, t_glist *glist, int mode)
107{
108 if(mode == IEM_GUI_DRAW_MODE_MOVE)
109 my_canvas_draw_move(x, glist);
110 else if(mode == IEM_GUI_DRAW_MODE_NEW)
111 my_canvas_draw_new(x, glist);
112 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
113 my_canvas_draw_select(x, glist);
114 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
115 my_canvas_draw_erase(x, glist);
116 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
117 my_canvas_draw_config(x, glist);
118}
119
120/* ------------------------ cnv widgetbehaviour----------------------------- */
121
122static void my_canvas_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
123{
124 t_my_canvas *x = (t_my_canvas *)z;
125
126 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
127 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
128 *xp2 = *xp1 + x->x_gui.x_w;
129 *yp2 = *yp1 + x->x_gui.x_h;
130}
131
132static void my_canvas_save(t_gobj *z, t_binbuf *b)
133{
134 t_my_canvas *x = (t_my_canvas *)z;
135 int bflcol[3];
136 t_symbol *srl[3];
137
138 iemgui_save(&x->x_gui, srl, bflcol);
139 binbuf_addv(b, "ssiisiiisssiiiiiii", gensym("#X"),gensym("obj"),
140 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
141 gensym("cnv"), x->x_gui.x_w, x->x_vis_w, x->x_vis_h,
142 srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy,
143 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
144 bflcol[0], bflcol[2], iem_symargstoint(&x->x_gui.x_isa));
145 binbuf_addv(b, ";");
146}
147
148static void my_canvas_properties(t_gobj *z, t_glist *owner)
149{
150 t_my_canvas *x = (t_my_canvas *)z;
151 char buf[800];
152 t_symbol *srl[3];
153
154 iemgui_properties(&x->x_gui, srl);
155 sprintf(buf, "pdtk_iemgui_dialog %%s MY_CANVAS \
156 ------selectable_dimensions(pix):------ %d %d size: 0.0 0.0 empty \
157 ------visible_rectangle(pix)(pix):------ %d width: %d height: %d \
158 %d empty empty %d %d empty %d \
159 %s %s \
160 %s %d %d \
161 %d %d \
162 %d %d %d\n",
163 x->x_gui.x_w, 1,
164 x->x_vis_w, x->x_vis_h, 0,/*no_schedule*/
165 -1, -1, -1, -1,/*no linlog, no init, no multi*/
166 srl[0]->s_name, srl[1]->s_name,
167 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
168 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
169 0xffffff & x->x_gui.x_bcol, -1/*no frontcolor*/, 0xffffff & x->x_gui.x_lcol);
170 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
171}
172
173static void my_canvas_get_pos(t_my_canvas *x)
174{
175 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
176 {
177 x->x_at[0].a_w.w_float = text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
178 x->x_at[1].a_w.w_float = text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
179 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
180 }
181}
182
183static void my_canvas_dialog(t_my_canvas *x, t_symbol *s, int argc, t_atom *argv)
184{
185 t_symbol *srl[3];
186 int a = (int)atom_getintarg(0, argc, argv);
187 int w = (int)atom_getintarg(2, argc, argv);
188 int h = (int)atom_getintarg(3, argc, argv);
189 int sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
190
191 x->x_gui.x_isa.x_loadinit = 0;
192 if(a < 1)
193 a = 1;
194 x->x_gui.x_w = a;
195 x->x_gui.x_h = x->x_gui.x_w;
196 if(w < 1)
197 w = 1;
198 x->x_vis_w = w;
199 if(h < 1)
200 h = 1;
201 x->x_vis_h = h;
202 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
203 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
204}
205
206static void my_canvas_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
207{
208 int i = (int)atom_getintarg(0, ac, av);
209
210 if(i < 1)
211 i = 1;
212 x->x_gui.x_w = i;
213 x->x_gui.x_h = i;
214 iemgui_size((void *)x, &x->x_gui);
215}
216
217static void my_canvas_delta(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
218{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
219
220static void my_canvas_pos(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
221{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
222
223static void my_canvas_vis_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
224{
225 int i;
226
227 i = (int)atom_getintarg(0, ac, av);
228 if(i < 1)
229 i = 1;
230 x->x_vis_w = i;
231 if(ac > 1)
232 {
233 i = (int)atom_getintarg(1, ac, av);
234 if(i < 1)
235 i = 1;
236 }
237 x->x_vis_h = i;
238 if(glist_isvisible(x->x_gui.x_glist))
239 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
240}
241
242static void my_canvas_color(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
243{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
244
245static void my_canvas_send(t_my_canvas *x, t_symbol *s)
246{iemgui_send(x, &x->x_gui, s);}
247
248static void my_canvas_receive(t_my_canvas *x, t_symbol *s)
249{iemgui_receive(x, &x->x_gui, s);}
250
251static void my_canvas_label(t_my_canvas *x, t_symbol *s)
252{iemgui_label((void *)x, &x->x_gui, s);}
253
254static void my_canvas_label_pos(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
255{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
256
257static void my_canvas_label_font(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
258{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
259
260static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
261{
262 t_my_canvas *x = (t_my_canvas *)pd_new(my_canvas_class);
263 int bflcol[]={-233017, -1, -66577};
264 int a=IEM_GUI_DEFAULTSIZE, w=100, h=60;
265 int ldx=20, ldy=12, f=2, i=0;
266 int fs=14;
267 char str[144];
268
269 iem_inttosymargs(&x->x_gui.x_isa, 0);
270 iem_inttofstyle(&x->x_gui.x_fsf, 0);
271
272 if(((argc >= 10)&&(argc <= 13))
273 &&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2))
274 {
275 a = (int)atom_getintarg(0, argc, argv);
276 w = (int)atom_getintarg(1, argc, argv);
277 h = (int)atom_getintarg(2, argc, argv);
278 }
279 if((argc >= 12)&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))&&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4)))
280 {
281 i = 2;
282 iemgui_new_getnames(&x->x_gui, 3, argv);
283 }
284 else if((argc == 11)&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3)))
285 {
286 i = 1;
287 iemgui_new_getnames(&x->x_gui, 3, argv);
288 }
289 else iemgui_new_getnames(&x->x_gui, 3, 0);
290
291 if(((argc >= 10)&&(argc <= 13))
292 &&(IS_A_SYMBOL(argv,i+3)||IS_A_FLOAT(argv,i+3))&&IS_A_FLOAT(argv,i+4)
293 &&IS_A_FLOAT(argv,i+5)&&IS_A_FLOAT(argv,i+6)
294 &&IS_A_FLOAT(argv,i+7)&&IS_A_FLOAT(argv,i+8)
295 &&IS_A_FLOAT(argv,i+9))
296 {
297 /* disastrously, the "label" sits in a different part of the
298 message. So we have to track its location separately (in
299 the slot x_labelbindex) and initialize it specially here. */
300 iemgui_new_dogetname(&x->x_gui, i+3, argv);
301 x->x_gui.x_labelbindex = i+4;
302 ldx = (int)atom_getintarg(i+4, argc, argv);
303 ldy = (int)atom_getintarg(i+5, argc, argv);
304 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(i+6, argc, argv));
305 fs = (int)atom_getintarg(i+7, argc, argv);
306 bflcol[0] = (int)atom_getintarg(i+8, argc, argv);
307 bflcol[2] = (int)atom_getintarg(i+9, argc, argv);
308 }
309 if((argc == 13)&&IS_A_FLOAT(argv,i+10))
310 {
311 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(i+10, argc, argv));
312 }
313 x->x_gui.x_draw = (t_iemfunptr)my_canvas_draw;
314 x->x_gui.x_fsf.x_snd_able = 1;
315 x->x_gui.x_fsf.x_rcv_able = 1;
316 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
317 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
318 x->x_gui.x_fsf.x_snd_able = 0;
319 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
320 x->x_gui.x_fsf.x_rcv_able = 0;
321 if(a < 1)
322 a = 1;
323 x->x_gui.x_w = a;
324 x->x_gui.x_h = x->x_gui.x_w;
325 if(w < 1)
326 w = 1;
327 x->x_vis_w = w;
328 if(h < 1)
329 h = 1;
330 x->x_vis_h = h;
331 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
332 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
333 else { x->x_gui.x_fsf.x_font_style = 0;
334 strcpy(x->x_gui.x_font, "courier"); }
335 if (x->x_gui.x_fsf.x_rcv_able)
336 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
337 x->x_gui.x_ldx = ldx;
338 x->x_gui.x_ldy = ldy;
339 if(fs < 4)
340 fs = 4;
341 x->x_gui.x_fontsize = fs;
342 iemgui_all_colfromload(&x->x_gui, bflcol);
343 x->x_at[0].a_type = A_FLOAT;
344 x->x_at[1].a_type = A_FLOAT;
345 iemgui_verify_snd_ne_rcv(&x->x_gui);
346 return (x);
347}
348
349static void my_canvas_ff(t_my_canvas *x)
350{
351 if(x->x_gui.x_fsf.x_rcv_able)
352 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
353 gfxstub_deleteforkey(x);
354}
355
356void g_mycanvas_setup(void)
357{
358 my_canvas_class = class_new(gensym("cnv"), (t_newmethod)my_canvas_new,
359 (t_method)my_canvas_ff, sizeof(t_my_canvas), CLASS_NOINLET, A_GIMME, 0);
360 class_addcreator((t_newmethod)my_canvas_new, gensym("my_canvas"), A_GIMME, 0);
361 class_addmethod(my_canvas_class, (t_method)my_canvas_dialog, gensym("dialog"), A_GIMME, 0);
362 class_addmethod(my_canvas_class, (t_method)my_canvas_size, gensym("size"), A_GIMME, 0);
363 class_addmethod(my_canvas_class, (t_method)my_canvas_delta, gensym("delta"), A_GIMME, 0);
364 class_addmethod(my_canvas_class, (t_method)my_canvas_pos, gensym("pos"), A_GIMME, 0);
365 class_addmethod(my_canvas_class, (t_method)my_canvas_vis_size, gensym("vis_size"), A_GIMME, 0);
366 class_addmethod(my_canvas_class, (t_method)my_canvas_color, gensym("color"), A_GIMME, 0);
367 class_addmethod(my_canvas_class, (t_method)my_canvas_send, gensym("send"), A_DEFSYM, 0);
368 class_addmethod(my_canvas_class, (t_method)my_canvas_receive, gensym("receive"), A_DEFSYM, 0);
369 class_addmethod(my_canvas_class, (t_method)my_canvas_label, gensym("label"), A_DEFSYM, 0);
370 class_addmethod(my_canvas_class, (t_method)my_canvas_label_pos, gensym("label_pos"), A_GIMME, 0);
371 class_addmethod(my_canvas_class, (t_method)my_canvas_label_font, gensym("label_font"), A_GIMME, 0);
372 class_addmethod(my_canvas_class, (t_method)my_canvas_get_pos, gensym("get_pos"), 0);
373
374 my_canvas_widgetbehavior.w_getrectfn = my_canvas_getrect;
375 my_canvas_widgetbehavior.w_displacefn = iemgui_displace;
376 my_canvas_widgetbehavior.w_selectfn = iemgui_select;
377 my_canvas_widgetbehavior.w_activatefn = NULL;
378 my_canvas_widgetbehavior.w_deletefn = iemgui_delete;
379 my_canvas_widgetbehavior.w_visfn = iemgui_vis;
380 my_canvas_widgetbehavior.w_clickfn = NULL;
381 class_setwidget(my_canvas_class, &my_canvas_widgetbehavior);
382 class_sethelpsymbol(my_canvas_class, gensym("my_canvas"));
383 class_setsavefn(my_canvas_class, my_canvas_save);
384 class_setpropertiesfn(my_canvas_class, my_canvas_properties);
385}
386/* Copyright (c) 1997-1999 Miller Puckette.
387 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
388 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
389
390/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
391/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
392
393
394#include <stdlib.h>
395#include <string.h>
396#include <stdio.h>
397#include <ctype.h>
398#include "m_pd.h"
399#include "g_canvas.h"
400#include "t_tk.h"
401#include "g_all_guis.h"
402#include <math.h>
403
404#ifdef MSW
405#include <io.h>
406#else
407#include <unistd.h>
408#endif
409
410/* ---------- cnv my gui-canvas for a window ---------------- */
411
412t_widgetbehavior my_canvas_widgetbehavior;
413static t_class *my_canvas_class;
414
415/* widget helper functions */
416
417void my_canvas_draw_new(t_my_canvas *x, t_glist *glist)
418{
419 int xpos=text_xpix(&x->x_gui.x_obj, glist);
420 int ypos=text_ypix(&x->x_gui.x_obj, glist);
421 t_canvas *canvas=glist_getcanvas(glist);
422
423 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xRECT\n",
424 canvas, xpos, ypos,
425 xpos + x->x_vis_w, ypos + x->x_vis_h,
426 x->x_gui.x_bcol, x->x_gui.x_bcol, x);
427 sys_vgui(".x%x.c create rectangle %d %d %d %d -outline #%6.6x -tags %xBASE\n",
428 canvas, xpos, ypos,
429 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h,
430 x->x_gui.x_bcol, x);
431 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
432 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
433 canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
434 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
435 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
436}
437
438void my_canvas_draw_move(t_my_canvas *x, t_glist *glist)
439{
440 int xpos=text_xpix(&x->x_gui.x_obj, glist);
441 int ypos=text_ypix(&x->x_gui.x_obj, glist);
442 t_canvas *canvas=glist_getcanvas(glist);
443
444 sys_vgui(".x%x.c coords %xRECT %d %d %d %d\n",
445 canvas, x, xpos, ypos, xpos + x->x_vis_w,
446 ypos + x->x_vis_h);
447 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
448 canvas, x, xpos, ypos,
449 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h);
450 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
451 canvas, x, xpos+x->x_gui.x_ldx,
452 ypos+x->x_gui.x_ldy);
453}
454
455void my_canvas_draw_erase(t_my_canvas* x, t_glist* glist)
456{
457 t_canvas *canvas=glist_getcanvas(glist);
458
459 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
460 sys_vgui(".x%x.c delete %xRECT\n", canvas, x);
461 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
462}
463
464void my_canvas_draw_config(t_my_canvas* x, t_glist* glist)
465{
466 t_canvas *canvas=glist_getcanvas(glist);
467
468 sys_vgui(".x%x.c itemconfigure %xRECT -fill #%6.6x -outline #%6.6x\n", canvas, x,
469 x->x_gui.x_bcol, x->x_gui.x_bcol);
470 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x,
471 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_bcol);
472 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
473 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol,
474 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
475}
476
477void my_canvas_draw_select(t_my_canvas* x, t_glist* glist)
478{
479 t_canvas *canvas=glist_getcanvas(glist);
480
481 if(x->x_gui.x_fsf.x_selected)
482 {
483 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
484 }
485 else
486 {
487 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, x->x_gui.x_bcol);
488 }
489}
490
491void my_canvas_draw(t_my_canvas *x, t_glist *glist, int mode)
492{
493 if(mode == IEM_GUI_DRAW_MODE_MOVE)
494 my_canvas_draw_move(x, glist);
495 else if(mode == IEM_GUI_DRAW_MODE_NEW)
496 my_canvas_draw_new(x, glist);
497 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
498 my_canvas_draw_select(x, glist);
499 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
500 my_canvas_draw_erase(x, glist);
501 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
502 my_canvas_draw_config(x, glist);
503}
504
505/* ------------------------ cnv widgetbehaviour----------------------------- */
506
507static void my_canvas_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
508{
509 t_my_canvas *x = (t_my_canvas *)z;
510
511 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
512 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
513 *xp2 = *xp1 + x->x_gui.x_w;
514 *yp2 = *yp1 + x->x_gui.x_h;
515}
516
517static void my_canvas_save(t_gobj *z, t_binbuf *b)
518{
519 t_my_canvas *x = (t_my_canvas *)z;
520 int bflcol[3];
521 t_symbol *srl[3];
522
523 iemgui_save(&x->x_gui, srl, bflcol);
524 binbuf_addv(b, "ssiisiiisssiiiiiii", gensym("#X"),gensym("obj"),
525 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
526 gensym("cnv"), x->x_gui.x_w, x->x_vis_w, x->x_vis_h,
527 srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy,
528 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
529 bflcol[0], bflcol[2], iem_symargstoint(&x->x_gui.x_isa));
530 binbuf_addv(b, ";");
531}
532
533static void my_canvas_properties(t_gobj *z, t_glist *owner)
534{
535 t_my_canvas *x = (t_my_canvas *)z;
536 char buf[800];
537 t_symbol *srl[3];
538
539 iemgui_properties(&x->x_gui, srl);
540 sprintf(buf, "pdtk_iemgui_dialog %%s MY_CANVAS \
541 ------selectable_dimensions(pix):------ %d %d size: 0.0 0.0 empty \
542 ------visible_rectangle(pix)(pix):------ %d width: %d height: %d \
543 %d empty empty %d %d empty %d \
544 %s %s \
545 %s %d %d \
546 %d %d \
547 %d %d %d\n",
548 x->x_gui.x_w, 1,
549 x->x_vis_w, x->x_vis_h, 0,/*no_schedule*/
550 -1, -1, -1, -1,/*no linlog, no init, no multi*/
551 srl[0]->s_name, srl[1]->s_name,
552 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
553 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
554 0xffffff & x->x_gui.x_bcol, -1/*no frontcolor*/, 0xffffff & x->x_gui.x_lcol);
555 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
556}
557
558static void my_canvas_get_pos(t_my_canvas *x)
559{
560 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
561 {
562 x->x_at[0].a_w.w_float = text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
563 x->x_at[1].a_w.w_float = text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
564 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
565 }
566}
567
568static void my_canvas_dialog(t_my_canvas *x, t_symbol *s, int argc, t_atom *argv)
569{
570 t_symbol *srl[3];
571 int a = (int)atom_getintarg(0, argc, argv);
572 int w = (int)atom_getintarg(2, argc, argv);
573 int h = (int)atom_getintarg(3, argc, argv);
574 int sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
575
576 x->x_gui.x_isa.x_loadinit = 0;
577 if(a < 1)
578 a = 1;
579 x->x_gui.x_w = a;
580 x->x_gui.x_h = x->x_gui.x_w;
581 if(w < 1)
582 w = 1;
583 x->x_vis_w = w;
584 if(h < 1)
585 h = 1;
586 x->x_vis_h = h;
587 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
588 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
589}
590
591static void my_canvas_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
592{
593 int i = (int)atom_getintarg(0, ac, av);
594
595 if(i < 1)
596 i = 1;
597 x->x_gui.x_w = i;
598 x->x_gui.x_h = i;
599 iemgui_size((void *)x, &x->x_gui);
600}
601
602static void my_canvas_delta(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
603{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
604
605static void my_canvas_pos(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
606{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
607
608static void my_canvas_vis_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
609{
610 int i;
611
612 i = (int)atom_getintarg(0, ac, av);
613 if(i < 1)
614 i = 1;
615 x->x_vis_w = i;
616 if(ac > 1)
617 {
618 i = (int)atom_getintarg(1, ac, av);
619 if(i < 1)
620 i = 1;
621 }
622 x->x_vis_h = i;
623 if(glist_isvisible(x->x_gui.x_glist))
624 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
625}
626
627static void my_canvas_color(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
628{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
629
630static void my_canvas_send(t_my_canvas *x, t_symbol *s)
631{iemgui_send(x, &x->x_gui, s);}
632
633static void my_canvas_receive(t_my_canvas *x, t_symbol *s)
634{iemgui_receive(x, &x->x_gui, s);}
635
636static void my_canvas_label(t_my_canvas *x, t_symbol *s)
637{iemgui_label((void *)x, &x->x_gui, s);}
638
639static void my_canvas_label_pos(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
640{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
641
642static void my_canvas_label_font(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
643{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
644
645static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
646{
647 t_my_canvas *x = (t_my_canvas *)pd_new(my_canvas_class);
648 int bflcol[]={-233017, -1, -66577};
649 int a=IEM_GUI_DEFAULTSIZE, w=100, h=60;
650 int ldx=20, ldy=12, f=2, i=0;
651 int fs=14;
652 char str[144];
653
654 iem_inttosymargs(&x->x_gui.x_isa, 0);
655 iem_inttofstyle(&x->x_gui.x_fsf, 0);
656
657 if(((argc >= 10)&&(argc <= 13))
658 &&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2))
659 {
660 a = (int)atom_getintarg(0, argc, argv);
661 w = (int)atom_getintarg(1, argc, argv);
662 h = (int)atom_getintarg(2, argc, argv);
663 }
664 if((argc >= 12)&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))&&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4)))
665 {
666 i = 2;
667 iemgui_new_getnames(&x->x_gui, 3, argv);
668 }
669 else if((argc == 11)&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3)))
670 {
671 i = 1;
672 iemgui_new_getnames(&x->x_gui, 3, argv);
673 }
674 else iemgui_new_getnames(&x->x_gui, 3, 0);
675
676 if(((argc >= 10)&&(argc <= 13))
677 &&(IS_A_SYMBOL(argv,i+3)||IS_A_FLOAT(argv,i+3))&&IS_A_FLOAT(argv,i+4)
678 &&IS_A_FLOAT(argv,i+5)&&IS_A_FLOAT(argv,i+6)
679 &&IS_A_FLOAT(argv,i+7)&&IS_A_FLOAT(argv,i+8)
680 &&IS_A_FLOAT(argv,i+9))
681 {
682 /* disastrously, the "label" sits in a different part of the
683 message. So we have to track its location separately (in
684 the slot x_labelbindex) and initialize it specially here. */
685 iemgui_new_dogetname(&x->x_gui, i+3, argv);
686 x->x_gui.x_labelbindex = i+4;
687 ldx = (int)atom_getintarg(i+4, argc, argv);
688 ldy = (int)atom_getintarg(i+5, argc, argv);
689 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(i+6, argc, argv));
690 fs = (int)atom_getintarg(i+7, argc, argv);
691 bflcol[0] = (int)atom_getintarg(i+8, argc, argv);
692 bflcol[2] = (int)atom_getintarg(i+9, argc, argv);
693 }
694 if((argc == 13)&&IS_A_FLOAT(argv,i+10))
695 {
696 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(i+10, argc, argv));
697 }
698 x->x_gui.x_draw = (t_iemfunptr)my_canvas_draw;
699 x->x_gui.x_fsf.x_snd_able = 1;
700 x->x_gui.x_fsf.x_rcv_able = 1;
701 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
702 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
703 x->x_gui.x_fsf.x_snd_able = 0;
704 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
705 x->x_gui.x_fsf.x_rcv_able = 0;
706 if(a < 1)
707 a = 1;
708 x->x_gui.x_w = a;
709 x->x_gui.x_h = x->x_gui.x_w;
710 if(w < 1)
711 w = 1;
712 x->x_vis_w = w;
713 if(h < 1)
714 h = 1;
715 x->x_vis_h = h;
716 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
717 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
718 else { x->x_gui.x_fsf.x_font_style = 0;
719 strcpy(x->x_gui.x_font, "courier"); }
720 if (x->x_gui.x_fsf.x_rcv_able)
721 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
722 x->x_gui.x_ldx = ldx;
723 x->x_gui.x_ldy = ldy;
724 if(fs < 4)
725 fs = 4;
726 x->x_gui.x_fontsize = fs;
727 iemgui_all_colfromload(&x->x_gui, bflcol);
728 x->x_at[0].a_type = A_FLOAT;
729 x->x_at[1].a_type = A_FLOAT;
730 iemgui_verify_snd_ne_rcv(&x->x_gui);
731 return (x);
732}
733
734static void my_canvas_ff(t_my_canvas *x)
735{
736 if(x->x_gui.x_fsf.x_rcv_able)
737 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
738 gfxstub_deleteforkey(x);
739}
740
741void g_mycanvas_setup(void)
742{
743 my_canvas_class = class_new(gensym("cnv"), (t_newmethod)my_canvas_new,
744 (t_method)my_canvas_ff, sizeof(t_my_canvas), CLASS_NOINLET, A_GIMME, 0);
745 class_addcreator((t_newmethod)my_canvas_new, gensym("my_canvas"), A_GIMME, 0);
746 class_addmethod(my_canvas_class, (t_method)my_canvas_dialog, gensym("dialog"), A_GIMME, 0);
747 class_addmethod(my_canvas_class, (t_method)my_canvas_size, gensym("size"), A_GIMME, 0);
748 class_addmethod(my_canvas_class, (t_method)my_canvas_delta, gensym("delta"), A_GIMME, 0);
749 class_addmethod(my_canvas_class, (t_method)my_canvas_pos, gensym("pos"), A_GIMME, 0);
750 class_addmethod(my_canvas_class, (t_method)my_canvas_vis_size, gensym("vis_size"), A_GIMME, 0);
751 class_addmethod(my_canvas_class, (t_method)my_canvas_color, gensym("color"), A_GIMME, 0);
752 class_addmethod(my_canvas_class, (t_method)my_canvas_send, gensym("send"), A_DEFSYM, 0);
753 class_addmethod(my_canvas_class, (t_method)my_canvas_receive, gensym("receive"), A_DEFSYM, 0);
754 class_addmethod(my_canvas_class, (t_method)my_canvas_label, gensym("label"), A_DEFSYM, 0);
755 class_addmethod(my_canvas_class, (t_method)my_canvas_label_pos, gensym("label_pos"), A_GIMME, 0);
756 class_addmethod(my_canvas_class, (t_method)my_canvas_label_font, gensym("label_font"), A_GIMME, 0);
757 class_addmethod(my_canvas_class, (t_method)my_canvas_get_pos, gensym("get_pos"), 0);
758
759 my_canvas_widgetbehavior.w_getrectfn = my_canvas_getrect;
760 my_canvas_widgetbehavior.w_displacefn = iemgui_displace;
761 my_canvas_widgetbehavior.w_selectfn = iemgui_select;
762 my_canvas_widgetbehavior.w_activatefn = NULL;
763 my_canvas_widgetbehavior.w_deletefn = iemgui_delete;
764 my_canvas_widgetbehavior.w_visfn = iemgui_vis;
765 my_canvas_widgetbehavior.w_clickfn = NULL;
766 class_setwidget(my_canvas_class, &my_canvas_widgetbehavior);
767 class_sethelpsymbol(my_canvas_class, gensym("my_canvas"));
768 class_setsavefn(my_canvas_class, my_canvas_save);
769 class_setpropertiesfn(my_canvas_class, my_canvas_properties);
770}
diff --git a/apps/plugins/pdbox/PDa/src/g_numbox.c b/apps/plugins/pdbox/PDa/src/g_numbox.c
new file mode 100644
index 0000000000..e7421204d3
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_numbox.c
@@ -0,0 +1,1814 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* my_numbox.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6
7#include <stdlib.h>
8#include <string.h>
9#include <stdio.h>
10#include <ctype.h>
11#include "m_pd.h"
12#include "g_canvas.h"
13#include "t_tk.h"
14#include "g_all_guis.h"
15#include <math.h>
16
17#ifdef MSW
18#include <io.h>
19#else
20#include <unistd.h>
21#endif
22
23/*------------------ global varaibles -------------------------*/
24
25
26/*------------------ global functions -------------------------*/
27
28static void my_numbox_key(void *z, t_floatarg fkey);
29
30/* ------------ nmx gui-my number box ----------------------- */
31
32t_widgetbehavior my_numbox_widgetbehavior;
33static t_class *my_numbox_class;
34
35/* widget helper functions */
36
37static void my_numbox_tick_reset(t_my_numbox *x)
38{
39 if(x->x_gui.x_fsf.x_change)
40 {
41 x->x_gui.x_fsf.x_change = 0;
42 glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
43 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
44 }
45}
46
47static void my_numbox_tick_wait(t_my_numbox *x)
48{
49 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
50}
51
52void my_numbox_clip(t_my_numbox *x)
53{
54 if(x->x_val < x->x_min)
55 x->x_val = x->x_min;
56 if(x->x_val > x->x_max)
57 x->x_val = x->x_max;
58}
59
60void my_numbox_calc_fontwidth(t_my_numbox *x)
61{
62 int w, f=31;
63
64 if(x->x_gui.x_fsf.x_font_style == 1)
65 f = 27;
66 else if(x->x_gui.x_fsf.x_font_style == 2)
67 f = 25;
68
69 w = x->x_gui.x_fontsize * f * x->x_gui.x_w;
70 w /= 36;
71 x->x_numwidth = w + (x->x_gui.x_h / 2) + 4;
72}
73
74void my_numbox_ftoa(t_my_numbox *x)
75{
76 double f=x->x_val;
77 int bufsize, is_exp=0, i, idecimal;
78
79 sprintf(x->x_buf, "%g", f);
80 bufsize = strlen(x->x_buf);
81 if(bufsize >= 5)/* if it is in exponential mode */
82 {
83 i = bufsize - 4;
84 if((x->x_buf[i] == 'e') || (x->x_buf[i] == 'E'))
85 is_exp = 1;
86 }
87 if(bufsize > x->x_gui.x_w)/* if to reduce */
88 {
89 if(is_exp)
90 {
91 if(x->x_gui.x_w <= 5)
92 {
93 x->x_buf[0] = (f < 0.0 ? '-' : '+');
94 x->x_buf[1] = 0;
95 }
96 i = bufsize - 4;
97 for(idecimal=0; idecimal < i; idecimal++)
98 if(x->x_buf[idecimal] == '.')
99 break;
100 if(idecimal > (x->x_gui.x_w - 4))
101 {
102 x->x_buf[0] = (f < 0.0 ? '-' : '+');
103 x->x_buf[1] = 0;
104 }
105 else
106 {
107 int new_exp_index=x->x_gui.x_w-4, old_exp_index=bufsize-4;
108
109 for(i=0; i < 4; i++, new_exp_index++, old_exp_index++)
110 x->x_buf[new_exp_index] = x->x_buf[old_exp_index];
111 x->x_buf[x->x_gui.x_w] = 0;
112 }
113
114 }
115 else
116 {
117 for(idecimal=0; idecimal < bufsize; idecimal++)
118 if(x->x_buf[idecimal] == '.')
119 break;
120 if(idecimal > x->x_gui.x_w)
121 {
122 x->x_buf[0] = (f < 0.0 ? '-' : '+');
123 x->x_buf[1] = 0;
124 }
125 else
126 x->x_buf[x->x_gui.x_w] = 0;
127 }
128 }
129}
130
131static void my_numbox_draw_update(t_my_numbox *x, t_glist *glist)
132{
133 if (glist_isvisible(glist))
134 {
135 if(x->x_gui.x_fsf.x_change)
136 {
137 if(x->x_buf[0])
138 {
139 char *cp=x->x_buf;
140 int sl = strlen(x->x_buf);
141
142 x->x_buf[sl] = '>';
143 x->x_buf[sl+1] = 0;
144 if(sl >= x->x_gui.x_w)
145 cp += sl - x->x_gui.x_w + 1;
146 sys_vgui(
147 ".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
148 glist_getcanvas(glist), x, IEM_GUI_COLOR_EDITED, cp);
149 x->x_buf[sl] = 0;
150 }
151 else
152 {
153 my_numbox_ftoa(x);
154 sys_vgui(
155 ".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
156 glist_getcanvas(glist), x, IEM_GUI_COLOR_EDITED, x->x_buf);
157 x->x_buf[0] = 0;
158 }
159 }
160 else
161 {
162 my_numbox_ftoa(x);
163 sys_vgui(
164 ".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
165 glist_getcanvas(glist), x,
166 x->x_gui.x_fsf.x_selected?
167 IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol,
168 x->x_buf);
169 x->x_buf[0] = 0;
170 }
171 }
172}
173
174static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist)
175{
176 int half=x->x_gui.x_h/2, d=1+x->x_gui.x_h/34;
177 int xpos=text_xpix(&x->x_gui.x_obj, glist);
178 int ypos=text_ypix(&x->x_gui.x_obj, glist);
179 t_canvas *canvas=glist_getcanvas(glist);
180
181 sys_vgui(
182".x%x.c create polygon %d %d %d %d %d %d %d %d %d %d -outline #%6.6x \
183-fill #%6.6x -tags %xBASE1\n",
184 canvas, xpos, ypos,
185 xpos + x->x_numwidth-4, ypos,
186 xpos + x->x_numwidth, ypos+4,
187 xpos + x->x_numwidth, ypos + x->x_gui.x_h,
188 xpos, ypos + x->x_gui.x_h,
189 IEM_GUI_COLOR_NORMAL, x->x_gui.x_bcol, x);
190 sys_vgui(
191 ".x%x.c create line %d %d %d %d %d %d -fill #%6.6x -tags %xBASE2\n",
192 canvas, xpos, ypos,
193 xpos + half, ypos + half,
194 xpos, ypos + x->x_gui.x_h,
195 x->x_gui.x_fcol, x);
196 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
197 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
198 canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
199 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
200 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
201 my_numbox_ftoa(x);
202 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
203 -font {%s %d bold} -fill #%6.6x -tags %xNUMBER\n",
204 canvas, xpos+half+2, ypos+half+d,
205 x->x_buf, x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_fcol, x);
206 if(!x->x_gui.x_fsf.x_snd_able)
207 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
208 canvas,
209 xpos, ypos + x->x_gui.x_h-1,
210 xpos+IOWIDTH, ypos + x->x_gui.x_h,
211 x, 0);
212 if(!x->x_gui.x_fsf.x_rcv_able)
213 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
214 canvas,
215 xpos, ypos,
216 xpos+IOWIDTH, ypos+1,
217 x, 0);
218}
219
220static void my_numbox_draw_move(t_my_numbox *x, t_glist *glist)
221{
222 int half = x->x_gui.x_h/2, d=1+x->x_gui.x_h/34;
223 int xpos=text_xpix(&x->x_gui.x_obj, glist);
224 int ypos=text_ypix(&x->x_gui.x_obj, glist);
225 t_canvas *canvas=glist_getcanvas(glist);
226
227 sys_vgui(".x%x.c coords %xBASE1 %d %d %d %d %d %d %d %d %d %d\n",
228 canvas, x, xpos, ypos,
229 xpos + x->x_numwidth-4, ypos,
230 xpos + x->x_numwidth, ypos+4,
231 xpos + x->x_numwidth, ypos + x->x_gui.x_h,
232 xpos, ypos + x->x_gui.x_h);
233 sys_vgui(".x%x.c coords %xBASE2 %d %d %d %d %d %d\n",
234 canvas, x, xpos, ypos,
235 xpos + half, ypos + half,
236 xpos, ypos + x->x_gui.x_h);
237 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
238 canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
239 sys_vgui(".x%x.c coords %xNUMBER %d %d\n",
240 canvas, x, xpos+half+2, ypos+half+d);
241 if(!x->x_gui.x_fsf.x_snd_able)
242 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
243 canvas, x, 0,
244 xpos, ypos + x->x_gui.x_h-1,
245 xpos+IOWIDTH, ypos + x->x_gui.x_h);
246 if(!x->x_gui.x_fsf.x_rcv_able)
247 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
248 canvas, x, 0,
249 xpos, ypos,
250 xpos+IOWIDTH, ypos+1);
251}
252
253static void my_numbox_draw_erase(t_my_numbox* x,t_glist* glist)
254{
255 t_canvas *canvas=glist_getcanvas(glist);
256
257 sys_vgui(".x%x.c delete %xBASE1\n", canvas, x);
258 sys_vgui(".x%x.c delete %xBASE2\n", canvas, x);
259 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
260 sys_vgui(".x%x.c delete %xNUMBER\n", canvas, x);
261 if(!x->x_gui.x_fsf.x_snd_able)
262 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
263 if(!x->x_gui.x_fsf.x_rcv_able)
264 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
265}
266
267static void my_numbox_draw_config(t_my_numbox* x,t_glist* glist)
268{
269 t_canvas *canvas=glist_getcanvas(glist);
270
271 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
272 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
273 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
274 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
275 sys_vgui(".x%x.c itemconfigure %xNUMBER -font {%s %d bold} -fill #%6.6x \n",
276 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
277 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol);
278 sys_vgui(".x%x.c itemconfigure %xBASE1 -fill #%6.6x\n", canvas,
279 x, x->x_gui.x_bcol);
280 sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n", canvas,
281 x, x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol);
282}
283
284static void my_numbox_draw_io(t_my_numbox* x,t_glist* glist, int old_snd_rcv_flags)
285{
286 int xpos=text_xpix(&x->x_gui.x_obj, glist);
287 int ypos=text_ypix(&x->x_gui.x_obj, glist);
288 t_canvas *canvas=glist_getcanvas(glist);
289
290 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
291 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
292 canvas,
293 xpos, ypos + x->x_gui.x_h-1,
294 xpos+IOWIDTH, ypos + x->x_gui.x_h,
295 x, 0);
296 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
297 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
298 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
299 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
300 canvas,
301 xpos, ypos,
302 xpos+IOWIDTH, ypos+1,
303 x, 0);
304 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
305 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
306}
307
308static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist)
309{
310 t_canvas *canvas=glist_getcanvas(glist);
311
312 if(x->x_gui.x_fsf.x_selected)
313 {
314 if(x->x_gui.x_fsf.x_change)
315 {
316 x->x_gui.x_fsf.x_change = 0;
317 clock_unset(x->x_clock_reset);
318 x->x_buf[0] = 0;
319 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
320 }
321 sys_vgui(".x%x.c itemconfigure %xBASE1 -outline #%6.6x\n",
322 canvas, x, IEM_GUI_COLOR_SELECTED);
323 sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n",
324 canvas, x, IEM_GUI_COLOR_SELECTED);
325 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n",
326 canvas, x, IEM_GUI_COLOR_SELECTED);
327 sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x\n",
328 canvas, x, IEM_GUI_COLOR_SELECTED);
329 }
330 else
331 {
332 sys_vgui(".x%x.c itemconfigure %xBASE1 -outline #%6.6x\n",
333 canvas, x, IEM_GUI_COLOR_NORMAL);
334 sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n",
335 canvas, x, x->x_gui.x_fcol);
336 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n",
337 canvas, x, x->x_gui.x_lcol);
338 sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x\n",
339 canvas, x, x->x_gui.x_fcol);
340 }
341}
342
343void my_numbox_draw(t_my_numbox *x, t_glist *glist, int mode)
344{
345 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
346 my_numbox_draw_update(x, glist);
347 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
348 my_numbox_draw_move(x, glist);
349 else if(mode == IEM_GUI_DRAW_MODE_NEW)
350 my_numbox_draw_new(x, glist);
351 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
352 my_numbox_draw_select(x, glist);
353 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
354 my_numbox_draw_erase(x, glist);
355 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
356 my_numbox_draw_config(x, glist);
357 else if(mode >= IEM_GUI_DRAW_MODE_IO)
358 my_numbox_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
359}
360
361/* ------------------------ nbx widgetbehaviour----------------------------- */
362
363
364static void my_numbox_getrect(t_gobj *z, t_glist *glist,
365 int *xp1, int *yp1, int *xp2, int *yp2)
366{
367 t_my_numbox* x = (t_my_numbox*)z;
368
369 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
370 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
371 *xp2 = *xp1 + x->x_numwidth;
372 *yp2 = *yp1 + x->x_gui.x_h;
373}
374
375static void my_numbox_save(t_gobj *z, t_binbuf *b)
376{
377 t_my_numbox *x = (t_my_numbox *)z;
378 int bflcol[3];
379 t_symbol *srl[3];
380
381 iemgui_save(&x->x_gui, srl, bflcol);
382 if(x->x_gui.x_fsf.x_change)
383 {
384 x->x_gui.x_fsf.x_change = 0;
385 clock_unset(x->x_clock_reset);
386 glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
387 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
388
389 }
390 binbuf_addv(b, "ssiisiiffiisssiiiiiiifi", gensym("#X"),gensym("obj"),
391 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
392 gensym("nbx"), x->x_gui.x_w, x->x_gui.x_h,
393 (float)x->x_min, (float)x->x_max,
394 x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa),
395 srl[0], srl[1], srl[2],
396 x->x_gui.x_ldx, x->x_gui.x_ldy,
397 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
398 bflcol[0], bflcol[1], bflcol[2],
399 x->x_val, x->x_log_height);
400 binbuf_addv(b, ";");
401}
402
403int my_numbox_check_minmax(t_my_numbox *x, double min, double max)
404{
405 int ret=0;
406
407 if(x->x_lin0_log1)
408 {
409 if((min == 0.0)&&(max == 0.0))
410 max = 1.0;
411 if(max > 0.0)
412 {
413 if(min <= 0.0)
414 min = 0.01*max;
415 }
416 else
417 {
418 if(min > 0.0)
419 max = 0.01*min;
420 }
421 }
422 x->x_min = min;
423 x->x_max = max;
424 if(x->x_val < x->x_min)
425 {
426 x->x_val = x->x_min;
427 ret = 1;
428 }
429 if(x->x_val > x->x_max)
430 {
431 x->x_val = x->x_max;
432 ret = 1;
433 }
434 if(x->x_lin0_log1)
435 x->x_k = exp(log(x->x_max/x->x_min)/(double)(x->x_log_height));
436 else
437 x->x_k = 1.0;
438 return(ret);
439}
440
441static void my_numbox_properties(t_gobj *z, t_glist *owner)
442{
443 t_my_numbox *x = (t_my_numbox *)z;
444 char buf[800];
445 t_symbol *srl[3];
446
447 iemgui_properties(&x->x_gui, srl);
448 if(x->x_gui.x_fsf.x_change)
449 {
450 x->x_gui.x_fsf.x_change = 0;
451 clock_unset(x->x_clock_reset);
452 glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
453 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
454
455 }
456 sprintf(buf, "pdtk_iemgui_dialog %%s NUMBERBOX \
457 -------dimensions(digits)(pix):------- %d %d width: %d %d height: \
458 -----------output-range:----------- %g min: %g max: %d \
459 %d lin log %d %d log-height: %d \
460 %s %s \
461 %s %d %d \
462 %d %d \
463 %d %d %d\n",
464 x->x_gui.x_w, 1, x->x_gui.x_h, 8,
465 x->x_min, x->x_max, 0,/*no_schedule*/
466 x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, -1,
467 x->x_log_height, /*no multi, but iem-characteristic*/
468 srl[0]->s_name, srl[1]->s_name,
469 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
470 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
471 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol,
472 0xffffff & x->x_gui.x_lcol);
473 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
474}
475
476static void my_numbox_bang(t_my_numbox *x)
477{
478 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_val);
479 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
480 pd_float(x->x_gui.x_snd->s_thing, x->x_val);
481}
482
483static void my_numbox_dialog(t_my_numbox *x, t_symbol *s, int argc,
484 t_atom *argv)
485{
486 t_symbol *srl[3];
487 int w = (int)atom_getintarg(0, argc, argv);
488 int h = (int)atom_getintarg(1, argc, argv);
489 double min = (double)atom_getfloatarg(2, argc, argv);
490 double max = (double)atom_getfloatarg(3, argc, argv);
491 int lilo = (int)atom_getintarg(4, argc, argv);
492 int log_height = (int)atom_getintarg(6, argc, argv);
493 int sr_flags;
494
495 if(lilo != 0) lilo = 1;
496 x->x_lin0_log1 = lilo;
497 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
498 if(w < 1)
499 w = 1;
500 x->x_gui.x_w = w;
501 if(h < 8)
502 h = 8;
503 x->x_gui.x_h = h;
504 if(log_height < 10)
505 log_height = 10;
506 x->x_log_height = log_height;
507 my_numbox_calc_fontwidth(x);
508 /*if(my_numbox_check_minmax(x, min, max))
509 my_numbox_bang(x);*/
510 my_numbox_check_minmax(x, min, max);
511 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
512 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
513 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
514 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
515 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
516}
517
518static void my_numbox_motion(t_my_numbox *x, t_floatarg dx, t_floatarg dy)
519{
520 double k2=1.0;
521
522 if(x->x_gui.x_fsf.x_finemoved)
523 k2 = 0.01;
524 if(x->x_lin0_log1)
525 x->x_val *= pow(x->x_k, -k2*dy);
526 else
527 x->x_val -= k2*dy;
528 my_numbox_clip(x);
529 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
530 my_numbox_bang(x);
531 clock_unset(x->x_clock_reset);
532}
533
534static void my_numbox_click(t_my_numbox *x, t_floatarg xpos, t_floatarg ypos,
535 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
536{
537 glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
538 (t_glistmotionfn)my_numbox_motion, my_numbox_key, xpos, ypos);
539}
540
541static int my_numbox_newclick(t_gobj *z, struct _glist *glist,
542 int xpix, int ypix, int shift, int alt, int dbl, int doit)
543{
544 t_my_numbox* x = (t_my_numbox *)z;
545
546 if(doit)
547 {
548 my_numbox_click( x, (t_floatarg)xpix, (t_floatarg)ypix,
549 (t_floatarg)shift, 0, (t_floatarg)alt);
550 if(shift)
551 x->x_gui.x_fsf.x_finemoved = 1;
552 else
553 x->x_gui.x_fsf.x_finemoved = 0;
554 if(!x->x_gui.x_fsf.x_change)
555 {
556 clock_delay(x->x_clock_wait, 50);
557 x->x_gui.x_fsf.x_change = 1;
558 clock_delay(x->x_clock_reset, 3000);
559 /* glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.ob_g,
560 0, my_numbox_key, 0, 0); */
561
562 x->x_buf[0] = 0;
563 }
564 else
565 {
566 x->x_gui.x_fsf.x_change = 0;
567 clock_unset(x->x_clock_reset);
568 glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
569 x->x_buf[0] = 0;
570 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
571 }
572 }
573 return (1);
574}
575
576static void my_numbox_set(t_my_numbox *x, t_floatarg f)
577{
578 x->x_val = f;
579 my_numbox_clip(x);
580 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
581}
582
583static void my_numbox_log_height(t_my_numbox *x, t_floatarg lh)
584{
585 if(lh < 10.0)
586 lh = 10.0;
587 x->x_log_height = (int)lh;
588 if(x->x_lin0_log1)
589 x->x_k = exp(log(x->x_max/x->x_min)/(double)(x->x_log_height));
590 else
591 x->x_k = 1.0;
592
593}
594
595static void my_numbox_float(t_my_numbox *x, t_floatarg f)
596{
597 my_numbox_set(x, f);
598 if(x->x_gui.x_fsf.x_put_in2out)
599 my_numbox_bang(x);
600}
601
602static void my_numbox_size(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
603{
604 int h, w;
605
606 w = (int)atom_getintarg(0, ac, av);
607 if(w < 1)
608 w = 1;
609 x->x_gui.x_w = w;
610 if(ac > 1)
611 {
612 h = (int)atom_getintarg(1, ac, av);
613 if(h < 8)
614 h = 8;
615 x->x_gui.x_h = h;
616 }
617 my_numbox_calc_fontwidth(x);
618 iemgui_size((void *)x, &x->x_gui);
619}
620
621static void my_numbox_delta(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
622{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
623
624static void my_numbox_pos(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
625{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
626
627static void my_numbox_range(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
628{
629 if(my_numbox_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
630 (double)atom_getfloatarg(1, ac, av)))
631 {
632 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
633 /*my_numbox_bang(x);*/
634 }
635}
636
637static void my_numbox_color(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
638{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
639
640static void my_numbox_send(t_my_numbox *x, t_symbol *s)
641{iemgui_send(x, &x->x_gui, s);}
642
643static void my_numbox_receive(t_my_numbox *x, t_symbol *s)
644{iemgui_receive(x, &x->x_gui, s);}
645
646static void my_numbox_label(t_my_numbox *x, t_symbol *s)
647{iemgui_label((void *)x, &x->x_gui, s);}
648
649static void my_numbox_label_pos(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
650{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
651
652static void my_numbox_label_font(t_my_numbox *x,
653 t_symbol *s, int ac, t_atom *av)
654{
655 int f = (int)atom_getintarg(1, ac, av);
656
657 if(f < 4)
658 f = 4;
659 x->x_gui.x_fontsize = f;
660 f = (int)atom_getintarg(0, ac, av);
661 if((f < 0) || (f > 2))
662 f = 0;
663 x->x_gui.x_fsf.x_font_style = f;
664 my_numbox_calc_fontwidth(x);
665 iemgui_label_font((void *)x, &x->x_gui, s, ac, av);
666}
667
668static void my_numbox_log(t_my_numbox *x)
669{
670 x->x_lin0_log1 = 1;
671 if(my_numbox_check_minmax(x, x->x_min, x->x_max))
672 {
673 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
674 /*my_numbox_bang(x);*/
675 }
676}
677
678static void my_numbox_lin(t_my_numbox *x)
679{
680 x->x_lin0_log1 = 0;
681}
682
683static void my_numbox_init(t_my_numbox *x, t_floatarg f)
684{
685 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
686}
687
688static void my_numbox_loadbang(t_my_numbox *x)
689{
690 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
691 {
692 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
693 my_numbox_bang(x);
694 }
695}
696
697static void my_numbox_key(void *z, t_floatarg fkey)
698{
699 t_my_numbox *x = z;
700 char c=fkey;
701 char buf[3];
702 buf[1] = 0;
703
704 if (c == 0)
705 {
706 x->x_gui.x_fsf.x_change = 0;
707 clock_unset(x->x_clock_reset);
708 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
709 return;
710 }
711 if(((c>='0')&&(c<='9'))||(c=='.')||(c=='-')||
712 (c=='e')||(c=='+')||(c=='E'))
713 {
714 if(strlen(x->x_buf) < (IEMGUI_MAX_NUM_LEN-2))
715 {
716 buf[0] = c;
717 strcat(x->x_buf, buf);
718 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
719 }
720 }
721 else if((c=='\b')||(c==127))
722 {
723 int sl=strlen(x->x_buf)-1;
724
725 if(sl < 0)
726 sl = 0;
727 x->x_buf[sl] = 0;
728 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
729 }
730 else if((c=='\n')||(c==13))
731 {
732 x->x_val = atof(x->x_buf);
733 x->x_buf[0] = 0;
734 x->x_gui.x_fsf.x_change = 0;
735 clock_unset(x->x_clock_reset);
736 my_numbox_clip(x);
737 my_numbox_bang(x);
738 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
739 }
740 clock_delay(x->x_clock_reset, 3000);
741}
742
743static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
744{
745 if (IS_A_FLOAT(av,0))
746 {
747 my_numbox_set(x, atom_getfloatarg(0, ac, av));
748 my_numbox_bang(x);
749 }
750}
751
752static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
753{
754 t_my_numbox *x = (t_my_numbox *)pd_new(my_numbox_class);
755 int bflcol[]={-262144, -1, -1};
756 int w=5, h=14;
757 int lilo=0, f=0, ldx=0, ldy=-6;
758 int fs=10;
759 int log_height=256;
760 double min=-1.0e+37, max=1.0e+37,v=0.0;
761 char str[144];
762
763 if((argc >= 17)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
764 &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
765 &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
766 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
767 &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
768 &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
769 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
770 &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
771 &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
772 {
773 w = (int)atom_getintarg(0, argc, argv);
774 h = (int)atom_getintarg(1, argc, argv);
775 min = (double)atom_getfloatarg(2, argc, argv);
776 max = (double)atom_getfloatarg(3, argc, argv);
777 lilo = (int)atom_getintarg(4, argc, argv);
778 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
779 iemgui_new_getnames(&x->x_gui, 6, argv);
780 ldx = (int)atom_getintarg(9, argc, argv);
781 ldy = (int)atom_getintarg(10, argc, argv);
782 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
783 fs = (int)atom_getintarg(12, argc, argv);
784 bflcol[0] = (int)atom_getintarg(13, argc, argv);
785 bflcol[1] = (int)atom_getintarg(14, argc, argv);
786 bflcol[2] = (int)atom_getintarg(15, argc, argv);
787 v = atom_getfloatarg(16, argc, argv);
788 }
789 else iemgui_new_getnames(&x->x_gui, 6, 0);
790 if((argc == 18)&&IS_A_FLOAT(argv,17))
791 {
792 log_height = (int)atom_getintarg(17, argc, argv);
793 }
794 x->x_gui.x_draw = (t_iemfunptr)my_numbox_draw;
795 x->x_gui.x_fsf.x_snd_able = 1;
796 x->x_gui.x_fsf.x_rcv_able = 1;
797 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
798 if(x->x_gui.x_isa.x_loadinit)
799 x->x_val = v;
800 else
801 x->x_val = 0.0;
802 if(lilo != 0) lilo = 1;
803 x->x_lin0_log1 = lilo;
804 if(log_height < 10)
805 log_height = 10;
806 x->x_log_height = log_height;
807 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
808 x->x_gui.x_fsf.x_snd_able = 0;
809 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
810 x->x_gui.x_fsf.x_rcv_able = 0;
811 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
812 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
813 else { x->x_gui.x_fsf.x_font_style = 0;
814 strcpy(x->x_gui.x_font, "courier"); }
815 if (x->x_gui.x_fsf.x_rcv_able)
816 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
817 x->x_gui.x_ldx = ldx;
818 x->x_gui.x_ldy = ldy;
819 if(fs < 4)
820 fs = 4;
821 x->x_gui.x_fontsize = fs;
822 if(w < 1)
823 w = 1;
824 x->x_gui.x_w = w;
825 if(h < 8)
826 h = 8;
827 x->x_gui.x_h = h;
828 x->x_buf[0] = 0;
829 my_numbox_calc_fontwidth(x);
830 my_numbox_check_minmax(x, min, max);
831 iemgui_all_colfromload(&x->x_gui, bflcol);
832 iemgui_verify_snd_ne_rcv(&x->x_gui);
833 x->x_clock_reset = clock_new(x, (t_method)my_numbox_tick_reset);
834 x->x_clock_wait = clock_new(x, (t_method)my_numbox_tick_wait);
835 x->x_gui.x_fsf.x_change = 0;
836 outlet_new(&x->x_gui.x_obj, &s_float);
837 return (x);
838}
839
840static void my_numbox_free(t_my_numbox *x)
841{
842 if(x->x_gui.x_fsf.x_rcv_able)
843 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
844 clock_free(x->x_clock_reset);
845 clock_free(x->x_clock_wait);
846 gfxstub_deleteforkey(x);
847}
848
849void g_numbox_setup(void)
850{
851 my_numbox_class = class_new(gensym("nbx"), (t_newmethod)my_numbox_new,
852 (t_method)my_numbox_free, sizeof(t_my_numbox), 0, A_GIMME, 0);
853 class_addcreator((t_newmethod)my_numbox_new, gensym("my_numbox"),
854 A_GIMME, 0);
855 class_addbang(my_numbox_class,my_numbox_bang);
856 class_addfloat(my_numbox_class,my_numbox_float);
857 class_addlist(my_numbox_class, my_numbox_list);
858 class_addmethod(my_numbox_class, (t_method)my_numbox_click,
859 gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
860 class_addmethod(my_numbox_class, (t_method)my_numbox_motion,
861 gensym("motion"), A_FLOAT, A_FLOAT, 0);
862 class_addmethod(my_numbox_class, (t_method)my_numbox_dialog,
863 gensym("dialog"), A_GIMME, 0);
864 class_addmethod(my_numbox_class, (t_method)my_numbox_loadbang,
865 gensym("loadbang"), 0);
866 class_addmethod(my_numbox_class, (t_method)my_numbox_set,
867 gensym("set"), A_FLOAT, 0);
868 class_addmethod(my_numbox_class, (t_method)my_numbox_size,
869 gensym("size"), A_GIMME, 0);
870 class_addmethod(my_numbox_class, (t_method)my_numbox_delta,
871 gensym("delta"), A_GIMME, 0);
872 class_addmethod(my_numbox_class, (t_method)my_numbox_pos,
873 gensym("pos"), A_GIMME, 0);
874 class_addmethod(my_numbox_class, (t_method)my_numbox_range,
875 gensym("range"), A_GIMME, 0);
876 class_addmethod(my_numbox_class, (t_method)my_numbox_color,
877 gensym("color"), A_GIMME, 0);
878 class_addmethod(my_numbox_class, (t_method)my_numbox_send,
879 gensym("send"), A_DEFSYM, 0);
880 class_addmethod(my_numbox_class, (t_method)my_numbox_receive,
881 gensym("receive"), A_DEFSYM, 0);
882 class_addmethod(my_numbox_class, (t_method)my_numbox_label,
883 gensym("label"), A_DEFSYM, 0);
884 class_addmethod(my_numbox_class, (t_method)my_numbox_label_pos,
885 gensym("label_pos"), A_GIMME, 0);
886 class_addmethod(my_numbox_class, (t_method)my_numbox_label_font,
887 gensym("label_font"), A_GIMME, 0);
888 class_addmethod(my_numbox_class, (t_method)my_numbox_log,
889 gensym("log"), 0);
890 class_addmethod(my_numbox_class, (t_method)my_numbox_lin,
891 gensym("lin"), 0);
892 class_addmethod(my_numbox_class, (t_method)my_numbox_init,
893 gensym("init"), A_FLOAT, 0);
894 class_addmethod(my_numbox_class, (t_method)my_numbox_log_height,
895 gensym("log_height"), A_FLOAT, 0);
896 my_numbox_widgetbehavior.w_getrectfn = my_numbox_getrect;
897 my_numbox_widgetbehavior.w_displacefn = iemgui_displace;
898 my_numbox_widgetbehavior.w_selectfn = iemgui_select;
899 my_numbox_widgetbehavior.w_activatefn = NULL;
900 my_numbox_widgetbehavior.w_deletefn = iemgui_delete;
901 my_numbox_widgetbehavior.w_visfn = iemgui_vis;
902 my_numbox_widgetbehavior.w_clickfn = my_numbox_newclick;
903 class_setwidget(my_numbox_class, &my_numbox_widgetbehavior);
904 class_sethelpsymbol(my_numbox_class, gensym("numbox2"));
905 class_setsavefn(my_numbox_class, my_numbox_save);
906 class_setpropertiesfn(my_numbox_class, my_numbox_properties);
907}
908/* Copyright (c) 1997-1999 Miller Puckette.
909 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
910 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
911
912/* my_numbox.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
913
914#include <stdlib.h>
915#include <string.h>
916#include <stdio.h>
917#include <ctype.h>
918#include "m_pd.h"
919#include "g_canvas.h"
920#include "t_tk.h"
921#include "g_all_guis.h"
922#include <math.h>
923
924#ifdef MSW
925#include <io.h>
926#else
927#include <unistd.h>
928#endif
929
930/*------------------ global varaibles -------------------------*/
931
932
933/*------------------ global functions -------------------------*/
934
935static void my_numbox_key(void *z, t_floatarg fkey);
936
937/* ------------ nmx gui-my number box ----------------------- */
938
939t_widgetbehavior my_numbox_widgetbehavior;
940static t_class *my_numbox_class;
941
942/* widget helper functions */
943
944static void my_numbox_tick_reset(t_my_numbox *x)
945{
946 if(x->x_gui.x_fsf.x_change)
947 {
948 x->x_gui.x_fsf.x_change = 0;
949 glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
950 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
951 }
952}
953
954static void my_numbox_tick_wait(t_my_numbox *x)
955{
956 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
957}
958
959void my_numbox_clip(t_my_numbox *x)
960{
961 if(x->x_val < x->x_min)
962 x->x_val = x->x_min;
963 if(x->x_val > x->x_max)
964 x->x_val = x->x_max;
965}
966
967void my_numbox_calc_fontwidth(t_my_numbox *x)
968{
969 int w, f=31;
970
971 if(x->x_gui.x_fsf.x_font_style == 1)
972 f = 27;
973 else if(x->x_gui.x_fsf.x_font_style == 2)
974 f = 25;
975
976 w = x->x_gui.x_fontsize * f * x->x_gui.x_w;
977 w /= 36;
978 x->x_numwidth = w + (x->x_gui.x_h / 2) + 4;
979}
980
981void my_numbox_ftoa(t_my_numbox *x)
982{
983 double f=x->x_val;
984 int bufsize, is_exp=0, i, idecimal;
985
986 sprintf(x->x_buf, "%g", f);
987 bufsize = strlen(x->x_buf);
988 if(bufsize >= 5)/* if it is in exponential mode */
989 {
990 i = bufsize - 4;
991 if((x->x_buf[i] == 'e') || (x->x_buf[i] == 'E'))
992 is_exp = 1;
993 }
994 if(bufsize > x->x_gui.x_w)/* if to reduce */
995 {
996 if(is_exp)
997 {
998 if(x->x_gui.x_w <= 5)
999 {
1000 x->x_buf[0] = (f < 0.0 ? '-' : '+');
1001 x->x_buf[1] = 0;
1002 }
1003 i = bufsize - 4;
1004 for(idecimal=0; idecimal < i; idecimal++)
1005 if(x->x_buf[idecimal] == '.')
1006 break;
1007 if(idecimal > (x->x_gui.x_w - 4))
1008 {
1009 x->x_buf[0] = (f < 0.0 ? '-' : '+');
1010 x->x_buf[1] = 0;
1011 }
1012 else
1013 {
1014 int new_exp_index=x->x_gui.x_w-4, old_exp_index=bufsize-4;
1015
1016 for(i=0; i < 4; i++, new_exp_index++, old_exp_index++)
1017 x->x_buf[new_exp_index] = x->x_buf[old_exp_index];
1018 x->x_buf[x->x_gui.x_w] = 0;
1019 }
1020
1021 }
1022 else
1023 {
1024 for(idecimal=0; idecimal < bufsize; idecimal++)
1025 if(x->x_buf[idecimal] == '.')
1026 break;
1027 if(idecimal > x->x_gui.x_w)
1028 {
1029 x->x_buf[0] = (f < 0.0 ? '-' : '+');
1030 x->x_buf[1] = 0;
1031 }
1032 else
1033 x->x_buf[x->x_gui.x_w] = 0;
1034 }
1035 }
1036}
1037
1038static void my_numbox_draw_update(t_my_numbox *x, t_glist *glist)
1039{
1040 if (glist_isvisible(glist))
1041 {
1042 if(x->x_gui.x_fsf.x_change)
1043 {
1044 if(x->x_buf[0])
1045 {
1046 char *cp=x->x_buf;
1047 int sl = strlen(x->x_buf);
1048
1049 x->x_buf[sl] = '>';
1050 x->x_buf[sl+1] = 0;
1051 if(sl >= x->x_gui.x_w)
1052 cp += sl - x->x_gui.x_w + 1;
1053 sys_vgui(
1054 ".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
1055 glist_getcanvas(glist), x, IEM_GUI_COLOR_EDITED, cp);
1056 x->x_buf[sl] = 0;
1057 }
1058 else
1059 {
1060 my_numbox_ftoa(x);
1061 sys_vgui(
1062 ".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
1063 glist_getcanvas(glist), x, IEM_GUI_COLOR_EDITED, x->x_buf);
1064 x->x_buf[0] = 0;
1065 }
1066 }
1067 else
1068 {
1069 my_numbox_ftoa(x);
1070 sys_vgui(
1071 ".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
1072 glist_getcanvas(glist), x,
1073 x->x_gui.x_fsf.x_selected?
1074 IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol,
1075 x->x_buf);
1076 x->x_buf[0] = 0;
1077 }
1078 }
1079}
1080
1081static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist)
1082{
1083 int half=x->x_gui.x_h/2, d=1+x->x_gui.x_h/34;
1084 int xpos=text_xpix(&x->x_gui.x_obj, glist);
1085 int ypos=text_ypix(&x->x_gui.x_obj, glist);
1086 t_canvas *canvas=glist_getcanvas(glist);
1087
1088 sys_vgui(
1089".x%x.c create polygon %d %d %d %d %d %d %d %d %d %d -outline #%6.6x \
1090-fill #%6.6x -tags %xBASE1\n",
1091 canvas, xpos, ypos,
1092 xpos + x->x_numwidth-4, ypos,
1093 xpos + x->x_numwidth, ypos+4,
1094 xpos + x->x_numwidth, ypos + x->x_gui.x_h,
1095 xpos, ypos + x->x_gui.x_h,
1096 IEM_GUI_COLOR_NORMAL, x->x_gui.x_bcol, x);
1097 sys_vgui(
1098 ".x%x.c create line %d %d %d %d %d %d -fill #%6.6x -tags %xBASE2\n",
1099 canvas, xpos, ypos,
1100 xpos + half, ypos + half,
1101 xpos, ypos + x->x_gui.x_h,
1102 x->x_gui.x_fcol, x);
1103 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
1104 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
1105 canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
1106 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
1107 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
1108 my_numbox_ftoa(x);
1109 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
1110 -font {%s %d bold} -fill #%6.6x -tags %xNUMBER\n",
1111 canvas, xpos+half+2, ypos+half+d,
1112 x->x_buf, x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_fcol, x);
1113 if(!x->x_gui.x_fsf.x_snd_able)
1114 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
1115 canvas,
1116 xpos, ypos + x->x_gui.x_h-1,
1117 xpos+IOWIDTH, ypos + x->x_gui.x_h,
1118 x, 0);
1119 if(!x->x_gui.x_fsf.x_rcv_able)
1120 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
1121 canvas,
1122 xpos, ypos,
1123 xpos+IOWIDTH, ypos+1,
1124 x, 0);
1125}
1126
1127static void my_numbox_draw_move(t_my_numbox *x, t_glist *glist)
1128{
1129 int half = x->x_gui.x_h/2, d=1+x->x_gui.x_h/34;
1130 int xpos=text_xpix(&x->x_gui.x_obj, glist);
1131 int ypos=text_ypix(&x->x_gui.x_obj, glist);
1132 t_canvas *canvas=glist_getcanvas(glist);
1133
1134 sys_vgui(".x%x.c coords %xBASE1 %d %d %d %d %d %d %d %d %d %d\n",
1135 canvas, x, xpos, ypos,
1136 xpos + x->x_numwidth-4, ypos,
1137 xpos + x->x_numwidth, ypos+4,
1138 xpos + x->x_numwidth, ypos + x->x_gui.x_h,
1139 xpos, ypos + x->x_gui.x_h);
1140 sys_vgui(".x%x.c coords %xBASE2 %d %d %d %d %d %d\n",
1141 canvas, x, xpos, ypos,
1142 xpos + half, ypos + half,
1143 xpos, ypos + x->x_gui.x_h);
1144 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
1145 canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
1146 sys_vgui(".x%x.c coords %xNUMBER %d %d\n",
1147 canvas, x, xpos+half+2, ypos+half+d);
1148 if(!x->x_gui.x_fsf.x_snd_able)
1149 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
1150 canvas, x, 0,
1151 xpos, ypos + x->x_gui.x_h-1,
1152 xpos+IOWIDTH, ypos + x->x_gui.x_h);
1153 if(!x->x_gui.x_fsf.x_rcv_able)
1154 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
1155 canvas, x, 0,
1156 xpos, ypos,
1157 xpos+IOWIDTH, ypos+1);
1158}
1159
1160static void my_numbox_draw_erase(t_my_numbox* x,t_glist* glist)
1161{
1162 t_canvas *canvas=glist_getcanvas(glist);
1163
1164 sys_vgui(".x%x.c delete %xBASE1\n", canvas, x);
1165 sys_vgui(".x%x.c delete %xBASE2\n", canvas, x);
1166 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
1167 sys_vgui(".x%x.c delete %xNUMBER\n", canvas, x);
1168 if(!x->x_gui.x_fsf.x_snd_able)
1169 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
1170 if(!x->x_gui.x_fsf.x_rcv_able)
1171 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
1172}
1173
1174static void my_numbox_draw_config(t_my_numbox* x,t_glist* glist)
1175{
1176 t_canvas *canvas=glist_getcanvas(glist);
1177
1178 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
1179 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
1180 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
1181 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
1182 sys_vgui(".x%x.c itemconfigure %xNUMBER -font {%s %d bold} -fill #%6.6x \n",
1183 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
1184 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol);
1185 sys_vgui(".x%x.c itemconfigure %xBASE1 -fill #%6.6x\n", canvas,
1186 x, x->x_gui.x_bcol);
1187 sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n", canvas,
1188 x, x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol);
1189}
1190
1191static void my_numbox_draw_io(t_my_numbox* x,t_glist* glist, int old_snd_rcv_flags)
1192{
1193 int xpos=text_xpix(&x->x_gui.x_obj, glist);
1194 int ypos=text_ypix(&x->x_gui.x_obj, glist);
1195 t_canvas *canvas=glist_getcanvas(glist);
1196
1197 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
1198 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
1199 canvas,
1200 xpos, ypos + x->x_gui.x_h-1,
1201 xpos+IOWIDTH, ypos + x->x_gui.x_h,
1202 x, 0);
1203 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
1204 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
1205 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
1206 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
1207 canvas,
1208 xpos, ypos,
1209 xpos+IOWIDTH, ypos+1,
1210 x, 0);
1211 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
1212 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
1213}
1214
1215static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist)
1216{
1217 t_canvas *canvas=glist_getcanvas(glist);
1218
1219 if(x->x_gui.x_fsf.x_selected)
1220 {
1221 if(x->x_gui.x_fsf.x_change)
1222 {
1223 x->x_gui.x_fsf.x_change = 0;
1224 clock_unset(x->x_clock_reset);
1225 x->x_buf[0] = 0;
1226 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1227 }
1228 sys_vgui(".x%x.c itemconfigure %xBASE1 -outline #%6.6x\n",
1229 canvas, x, IEM_GUI_COLOR_SELECTED);
1230 sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n",
1231 canvas, x, IEM_GUI_COLOR_SELECTED);
1232 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n",
1233 canvas, x, IEM_GUI_COLOR_SELECTED);
1234 sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x\n",
1235 canvas, x, IEM_GUI_COLOR_SELECTED);
1236 }
1237 else
1238 {
1239 sys_vgui(".x%x.c itemconfigure %xBASE1 -outline #%6.6x\n",
1240 canvas, x, IEM_GUI_COLOR_NORMAL);
1241 sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n",
1242 canvas, x, x->x_gui.x_fcol);
1243 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n",
1244 canvas, x, x->x_gui.x_lcol);
1245 sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x\n",
1246 canvas, x, x->x_gui.x_fcol);
1247 }
1248}
1249
1250void my_numbox_draw(t_my_numbox *x, t_glist *glist, int mode)
1251{
1252 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
1253 my_numbox_draw_update(x, glist);
1254 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
1255 my_numbox_draw_move(x, glist);
1256 else if(mode == IEM_GUI_DRAW_MODE_NEW)
1257 my_numbox_draw_new(x, glist);
1258 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
1259 my_numbox_draw_select(x, glist);
1260 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
1261 my_numbox_draw_erase(x, glist);
1262 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
1263 my_numbox_draw_config(x, glist);
1264 else if(mode >= IEM_GUI_DRAW_MODE_IO)
1265 my_numbox_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
1266}
1267
1268/* ------------------------ nbx widgetbehaviour----------------------------- */
1269
1270
1271static void my_numbox_getrect(t_gobj *z, t_glist *glist,
1272 int *xp1, int *yp1, int *xp2, int *yp2)
1273{
1274 t_my_numbox* x = (t_my_numbox*)z;
1275
1276 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
1277 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
1278 *xp2 = *xp1 + x->x_numwidth;
1279 *yp2 = *yp1 + x->x_gui.x_h;
1280}
1281
1282static void my_numbox_save(t_gobj *z, t_binbuf *b)
1283{
1284 t_my_numbox *x = (t_my_numbox *)z;
1285 int bflcol[3];
1286 t_symbol *srl[3];
1287
1288 iemgui_save(&x->x_gui, srl, bflcol);
1289 if(x->x_gui.x_fsf.x_change)
1290 {
1291 x->x_gui.x_fsf.x_change = 0;
1292 clock_unset(x->x_clock_reset);
1293 glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
1294 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1295
1296 }
1297 binbuf_addv(b, "ssiisiiffiisssiiiiiiifi", gensym("#X"),gensym("obj"),
1298 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
1299 gensym("nbx"), x->x_gui.x_w, x->x_gui.x_h,
1300 (float)x->x_min, (float)x->x_max,
1301 x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa),
1302 srl[0], srl[1], srl[2],
1303 x->x_gui.x_ldx, x->x_gui.x_ldy,
1304 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
1305 bflcol[0], bflcol[1], bflcol[2],
1306 x->x_val, x->x_log_height);
1307 binbuf_addv(b, ";");
1308}
1309
1310int my_numbox_check_minmax(t_my_numbox *x, double min, double max)
1311{
1312 int ret=0;
1313
1314 if(x->x_lin0_log1)
1315 {
1316 if((min == 0.0)&&(max == 0.0))
1317 max = 1.0;
1318 if(max > 0.0)
1319 {
1320 if(min <= 0.0)
1321 min = 0.01*max;
1322 }
1323 else
1324 {
1325 if(min > 0.0)
1326 max = 0.01*min;
1327 }
1328 }
1329 x->x_min = min;
1330 x->x_max = max;
1331 if(x->x_val < x->x_min)
1332 {
1333 x->x_val = x->x_min;
1334 ret = 1;
1335 }
1336 if(x->x_val > x->x_max)
1337 {
1338 x->x_val = x->x_max;
1339 ret = 1;
1340 }
1341 if(x->x_lin0_log1)
1342 x->x_k = exp(log(x->x_max/x->x_min)/(double)(x->x_log_height));
1343 else
1344 x->x_k = 1.0;
1345 return(ret);
1346}
1347
1348static void my_numbox_properties(t_gobj *z, t_glist *owner)
1349{
1350 t_my_numbox *x = (t_my_numbox *)z;
1351 char buf[800];
1352 t_symbol *srl[3];
1353
1354 iemgui_properties(&x->x_gui, srl);
1355 if(x->x_gui.x_fsf.x_change)
1356 {
1357 x->x_gui.x_fsf.x_change = 0;
1358 clock_unset(x->x_clock_reset);
1359 glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
1360 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1361
1362 }
1363 sprintf(buf, "pdtk_iemgui_dialog %%s NUMBERBOX \
1364 -------dimensions(digits)(pix):------- %d %d width: %d %d height: \
1365 -----------output-range:----------- %g min: %g max: %d \
1366 %d lin log %d %d log-height: %d \
1367 %s %s \
1368 %s %d %d \
1369 %d %d \
1370 %d %d %d\n",
1371 x->x_gui.x_w, 1, x->x_gui.x_h, 8,
1372 x->x_min, x->x_max, 0,/*no_schedule*/
1373 x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, -1,
1374 x->x_log_height, /*no multi, but iem-characteristic*/
1375 srl[0]->s_name, srl[1]->s_name,
1376 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
1377 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
1378 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol,
1379 0xffffff & x->x_gui.x_lcol);
1380 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
1381}
1382
1383static void my_numbox_bang(t_my_numbox *x)
1384{
1385 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_val);
1386 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1387 pd_float(x->x_gui.x_snd->s_thing, x->x_val);
1388}
1389
1390static void my_numbox_dialog(t_my_numbox *x, t_symbol *s, int argc,
1391 t_atom *argv)
1392{
1393 t_symbol *srl[3];
1394 int w = (int)atom_getintarg(0, argc, argv);
1395 int h = (int)atom_getintarg(1, argc, argv);
1396 double min = (double)atom_getfloatarg(2, argc, argv);
1397 double max = (double)atom_getfloatarg(3, argc, argv);
1398 int lilo = (int)atom_getintarg(4, argc, argv);
1399 int log_height = (int)atom_getintarg(6, argc, argv);
1400 int sr_flags;
1401
1402 if(lilo != 0) lilo = 1;
1403 x->x_lin0_log1 = lilo;
1404 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
1405 if(w < 1)
1406 w = 1;
1407 x->x_gui.x_w = w;
1408 if(h < 8)
1409 h = 8;
1410 x->x_gui.x_h = h;
1411 if(log_height < 10)
1412 log_height = 10;
1413 x->x_log_height = log_height;
1414 my_numbox_calc_fontwidth(x);
1415 /*if(my_numbox_check_minmax(x, min, max))
1416 my_numbox_bang(x);*/
1417 my_numbox_check_minmax(x, min, max);
1418 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1419 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
1420 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
1421 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
1422 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
1423}
1424
1425static void my_numbox_motion(t_my_numbox *x, t_floatarg dx, t_floatarg dy)
1426{
1427 double k2=1.0;
1428
1429 if(x->x_gui.x_fsf.x_finemoved)
1430 k2 = 0.01;
1431 if(x->x_lin0_log1)
1432 x->x_val *= pow(x->x_k, -k2*dy);
1433 else
1434 x->x_val -= k2*dy;
1435 my_numbox_clip(x);
1436 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1437 my_numbox_bang(x);
1438 clock_unset(x->x_clock_reset);
1439}
1440
1441static void my_numbox_click(t_my_numbox *x, t_floatarg xpos, t_floatarg ypos,
1442 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
1443{
1444 glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
1445 (t_glistmotionfn)my_numbox_motion, my_numbox_key, xpos, ypos);
1446}
1447
1448static int my_numbox_newclick(t_gobj *z, struct _glist *glist,
1449 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1450{
1451 t_my_numbox* x = (t_my_numbox *)z;
1452
1453 if(doit)
1454 {
1455 my_numbox_click( x, (t_floatarg)xpix, (t_floatarg)ypix,
1456 (t_floatarg)shift, 0, (t_floatarg)alt);
1457 if(shift)
1458 x->x_gui.x_fsf.x_finemoved = 1;
1459 else
1460 x->x_gui.x_fsf.x_finemoved = 0;
1461 if(!x->x_gui.x_fsf.x_change)
1462 {
1463 clock_delay(x->x_clock_wait, 50);
1464 x->x_gui.x_fsf.x_change = 1;
1465 clock_delay(x->x_clock_reset, 3000);
1466 /* glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.ob_g,
1467 0, my_numbox_key, 0, 0); */
1468
1469 x->x_buf[0] = 0;
1470 }
1471 else
1472 {
1473 x->x_gui.x_fsf.x_change = 0;
1474 clock_unset(x->x_clock_reset);
1475 glist_grab(x->x_gui.x_glist, 0, 0, 0, 0, 0);
1476 x->x_buf[0] = 0;
1477 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1478 }
1479 }
1480 return (1);
1481}
1482
1483static void my_numbox_set(t_my_numbox *x, t_floatarg f)
1484{
1485 x->x_val = f;
1486 my_numbox_clip(x);
1487 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1488}
1489
1490static void my_numbox_log_height(t_my_numbox *x, t_floatarg lh)
1491{
1492 if(lh < 10.0)
1493 lh = 10.0;
1494 x->x_log_height = (int)lh;
1495 if(x->x_lin0_log1)
1496 x->x_k = exp(log(x->x_max/x->x_min)/(double)(x->x_log_height));
1497 else
1498 x->x_k = 1.0;
1499
1500}
1501
1502static void my_numbox_float(t_my_numbox *x, t_floatarg f)
1503{
1504 my_numbox_set(x, f);
1505 if(x->x_gui.x_fsf.x_put_in2out)
1506 my_numbox_bang(x);
1507}
1508
1509static void my_numbox_size(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
1510{
1511 int h, w;
1512
1513 w = (int)atom_getintarg(0, ac, av);
1514 if(w < 1)
1515 w = 1;
1516 x->x_gui.x_w = w;
1517 if(ac > 1)
1518 {
1519 h = (int)atom_getintarg(1, ac, av);
1520 if(h < 8)
1521 h = 8;
1522 x->x_gui.x_h = h;
1523 }
1524 my_numbox_calc_fontwidth(x);
1525 iemgui_size((void *)x, &x->x_gui);
1526}
1527
1528static void my_numbox_delta(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
1529{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
1530
1531static void my_numbox_pos(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
1532{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
1533
1534static void my_numbox_range(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
1535{
1536 if(my_numbox_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
1537 (double)atom_getfloatarg(1, ac, av)))
1538 {
1539 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1540 /*my_numbox_bang(x);*/
1541 }
1542}
1543
1544static void my_numbox_color(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
1545{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
1546
1547static void my_numbox_send(t_my_numbox *x, t_symbol *s)
1548{iemgui_send(x, &x->x_gui, s);}
1549
1550static void my_numbox_receive(t_my_numbox *x, t_symbol *s)
1551{iemgui_receive(x, &x->x_gui, s);}
1552
1553static void my_numbox_label(t_my_numbox *x, t_symbol *s)
1554{iemgui_label((void *)x, &x->x_gui, s);}
1555
1556static void my_numbox_label_pos(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
1557{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
1558
1559static void my_numbox_label_font(t_my_numbox *x,
1560 t_symbol *s, int ac, t_atom *av)
1561{
1562 int f = (int)atom_getintarg(1, ac, av);
1563
1564 if(f < 4)
1565 f = 4;
1566 x->x_gui.x_fontsize = f;
1567 f = (int)atom_getintarg(0, ac, av);
1568 if((f < 0) || (f > 2))
1569 f = 0;
1570 x->x_gui.x_fsf.x_font_style = f;
1571 my_numbox_calc_fontwidth(x);
1572 iemgui_label_font((void *)x, &x->x_gui, s, ac, av);
1573}
1574
1575static void my_numbox_log(t_my_numbox *x)
1576{
1577 x->x_lin0_log1 = 1;
1578 if(my_numbox_check_minmax(x, x->x_min, x->x_max))
1579 {
1580 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1581 /*my_numbox_bang(x);*/
1582 }
1583}
1584
1585static void my_numbox_lin(t_my_numbox *x)
1586{
1587 x->x_lin0_log1 = 0;
1588}
1589
1590static void my_numbox_init(t_my_numbox *x, t_floatarg f)
1591{
1592 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
1593}
1594
1595static void my_numbox_loadbang(t_my_numbox *x)
1596{
1597 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
1598 {
1599 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1600 my_numbox_bang(x);
1601 }
1602}
1603
1604static void my_numbox_key(void *z, t_floatarg fkey)
1605{
1606 t_my_numbox *x = z;
1607 char c=fkey;
1608 char buf[3];
1609 buf[1] = 0;
1610
1611 if (c == 0)
1612 {
1613 x->x_gui.x_fsf.x_change = 0;
1614 clock_unset(x->x_clock_reset);
1615 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1616 return;
1617 }
1618 if(((c>='0')&&(c<='9'))||(c=='.')||(c=='-')||
1619 (c=='e')||(c=='+')||(c=='E'))
1620 {
1621 if(strlen(x->x_buf) < (IEMGUI_MAX_NUM_LEN-2))
1622 {
1623 buf[0] = c;
1624 strcat(x->x_buf, buf);
1625 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1626 }
1627 }
1628 else if((c=='\b')||(c==127))
1629 {
1630 int sl=strlen(x->x_buf)-1;
1631
1632 if(sl < 0)
1633 sl = 0;
1634 x->x_buf[sl] = 0;
1635 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1636 }
1637 else if((c=='\n')||(c==13))
1638 {
1639 x->x_val = atof(x->x_buf);
1640 x->x_buf[0] = 0;
1641 x->x_gui.x_fsf.x_change = 0;
1642 clock_unset(x->x_clock_reset);
1643 my_numbox_clip(x);
1644 my_numbox_bang(x);
1645 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1646 }
1647 clock_delay(x->x_clock_reset, 3000);
1648}
1649
1650static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
1651{
1652 if (IS_A_FLOAT(av,0))
1653 {
1654 my_numbox_set(x, atom_getfloatarg(0, ac, av));
1655 my_numbox_bang(x);
1656 }
1657}
1658
1659static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
1660{
1661 t_my_numbox *x = (t_my_numbox *)pd_new(my_numbox_class);
1662 int bflcol[]={-262144, -1, -1};
1663 int w=5, h=14;
1664 int lilo=0, f=0, ldx=0, ldy=-6;
1665 int fs=10;
1666 int log_height=256;
1667 double min=-1.0e+37, max=1.0e+37,v=0.0;
1668 char str[144];
1669
1670 if((argc >= 17)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
1671 &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
1672 &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
1673 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
1674 &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
1675 &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
1676 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
1677 &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
1678 &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
1679 {
1680 w = (int)atom_getintarg(0, argc, argv);
1681 h = (int)atom_getintarg(1, argc, argv);
1682 min = (double)atom_getfloatarg(2, argc, argv);
1683 max = (double)atom_getfloatarg(3, argc, argv);
1684 lilo = (int)atom_getintarg(4, argc, argv);
1685 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
1686 iemgui_new_getnames(&x->x_gui, 6, argv);
1687 ldx = (int)atom_getintarg(9, argc, argv);
1688 ldy = (int)atom_getintarg(10, argc, argv);
1689 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
1690 fs = (int)atom_getintarg(12, argc, argv);
1691 bflcol[0] = (int)atom_getintarg(13, argc, argv);
1692 bflcol[1] = (int)atom_getintarg(14, argc, argv);
1693 bflcol[2] = (int)atom_getintarg(15, argc, argv);
1694 v = atom_getfloatarg(16, argc, argv);
1695 }
1696 else iemgui_new_getnames(&x->x_gui, 6, 0);
1697 if((argc == 18)&&IS_A_FLOAT(argv,17))
1698 {
1699 log_height = (int)atom_getintarg(17, argc, argv);
1700 }
1701 x->x_gui.x_draw = (t_iemfunptr)my_numbox_draw;
1702 x->x_gui.x_fsf.x_snd_able = 1;
1703 x->x_gui.x_fsf.x_rcv_able = 1;
1704 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
1705 if(x->x_gui.x_isa.x_loadinit)
1706 x->x_val = v;
1707 else
1708 x->x_val = 0.0;
1709 if(lilo != 0) lilo = 1;
1710 x->x_lin0_log1 = lilo;
1711 if(log_height < 10)
1712 log_height = 10;
1713 x->x_log_height = log_height;
1714 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
1715 x->x_gui.x_fsf.x_snd_able = 0;
1716 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
1717 x->x_gui.x_fsf.x_rcv_able = 0;
1718 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
1719 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
1720 else { x->x_gui.x_fsf.x_font_style = 0;
1721 strcpy(x->x_gui.x_font, "courier"); }
1722 if (x->x_gui.x_fsf.x_rcv_able)
1723 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1724 x->x_gui.x_ldx = ldx;
1725 x->x_gui.x_ldy = ldy;
1726 if(fs < 4)
1727 fs = 4;
1728 x->x_gui.x_fontsize = fs;
1729 if(w < 1)
1730 w = 1;
1731 x->x_gui.x_w = w;
1732 if(h < 8)
1733 h = 8;
1734 x->x_gui.x_h = h;
1735 x->x_buf[0] = 0;
1736 my_numbox_calc_fontwidth(x);
1737 my_numbox_check_minmax(x, min, max);
1738 iemgui_all_colfromload(&x->x_gui, bflcol);
1739 iemgui_verify_snd_ne_rcv(&x->x_gui);
1740 x->x_clock_reset = clock_new(x, (t_method)my_numbox_tick_reset);
1741 x->x_clock_wait = clock_new(x, (t_method)my_numbox_tick_wait);
1742 x->x_gui.x_fsf.x_change = 0;
1743 outlet_new(&x->x_gui.x_obj, &s_float);
1744 return (x);
1745}
1746
1747static void my_numbox_free(t_my_numbox *x)
1748{
1749 if(x->x_gui.x_fsf.x_rcv_able)
1750 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1751 clock_free(x->x_clock_reset);
1752 clock_free(x->x_clock_wait);
1753 gfxstub_deleteforkey(x);
1754}
1755
1756void g_numbox_setup(void)
1757{
1758 my_numbox_class = class_new(gensym("nbx"), (t_newmethod)my_numbox_new,
1759 (t_method)my_numbox_free, sizeof(t_my_numbox), 0, A_GIMME, 0);
1760 class_addcreator((t_newmethod)my_numbox_new, gensym("my_numbox"),
1761 A_GIMME, 0);
1762 class_addbang(my_numbox_class,my_numbox_bang);
1763 class_addfloat(my_numbox_class,my_numbox_float);
1764 class_addlist(my_numbox_class, my_numbox_list);
1765 class_addmethod(my_numbox_class, (t_method)my_numbox_click,
1766 gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1767 class_addmethod(my_numbox_class, (t_method)my_numbox_motion,
1768 gensym("motion"), A_FLOAT, A_FLOAT, 0);
1769 class_addmethod(my_numbox_class, (t_method)my_numbox_dialog,
1770 gensym("dialog"), A_GIMME, 0);
1771 class_addmethod(my_numbox_class, (t_method)my_numbox_loadbang,
1772 gensym("loadbang"), 0);
1773 class_addmethod(my_numbox_class, (t_method)my_numbox_set,
1774 gensym("set"), A_FLOAT, 0);
1775 class_addmethod(my_numbox_class, (t_method)my_numbox_size,
1776 gensym("size"), A_GIMME, 0);
1777 class_addmethod(my_numbox_class, (t_method)my_numbox_delta,
1778 gensym("delta"), A_GIMME, 0);
1779 class_addmethod(my_numbox_class, (t_method)my_numbox_pos,
1780 gensym("pos"), A_GIMME, 0);
1781 class_addmethod(my_numbox_class, (t_method)my_numbox_range,
1782 gensym("range"), A_GIMME, 0);
1783 class_addmethod(my_numbox_class, (t_method)my_numbox_color,
1784 gensym("color"), A_GIMME, 0);
1785 class_addmethod(my_numbox_class, (t_method)my_numbox_send,
1786 gensym("send"), A_DEFSYM, 0);
1787 class_addmethod(my_numbox_class, (t_method)my_numbox_receive,
1788 gensym("receive"), A_DEFSYM, 0);
1789 class_addmethod(my_numbox_class, (t_method)my_numbox_label,
1790 gensym("label"), A_DEFSYM, 0);
1791 class_addmethod(my_numbox_class, (t_method)my_numbox_label_pos,
1792 gensym("label_pos"), A_GIMME, 0);
1793 class_addmethod(my_numbox_class, (t_method)my_numbox_label_font,
1794 gensym("label_font"), A_GIMME, 0);
1795 class_addmethod(my_numbox_class, (t_method)my_numbox_log,
1796 gensym("log"), 0);
1797 class_addmethod(my_numbox_class, (t_method)my_numbox_lin,
1798 gensym("lin"), 0);
1799 class_addmethod(my_numbox_class, (t_method)my_numbox_init,
1800 gensym("init"), A_FLOAT, 0);
1801 class_addmethod(my_numbox_class, (t_method)my_numbox_log_height,
1802 gensym("log_height"), A_FLOAT, 0);
1803 my_numbox_widgetbehavior.w_getrectfn = my_numbox_getrect;
1804 my_numbox_widgetbehavior.w_displacefn = iemgui_displace;
1805 my_numbox_widgetbehavior.w_selectfn = iemgui_select;
1806 my_numbox_widgetbehavior.w_activatefn = NULL;
1807 my_numbox_widgetbehavior.w_deletefn = iemgui_delete;
1808 my_numbox_widgetbehavior.w_visfn = iemgui_vis;
1809 my_numbox_widgetbehavior.w_clickfn = my_numbox_newclick;
1810 class_setwidget(my_numbox_class, &my_numbox_widgetbehavior);
1811 class_sethelpsymbol(my_numbox_class, gensym("numbox2"));
1812 class_setsavefn(my_numbox_class, my_numbox_save);
1813 class_setpropertiesfn(my_numbox_class, my_numbox_properties);
1814}
diff --git a/apps/plugins/pdbox/PDa/src/g_readwrite.c b/apps/plugins/pdbox/PDa/src/g_readwrite.c
new file mode 100644
index 0000000000..a25b60c443
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_readwrite.c
@@ -0,0 +1,1446 @@
1/* Copyright (c) 1997-2002 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* this file reads and writes the "data" portions of a canvas to a file.
6See also canvas_saveto(), etc., in g_editor.c. The data portion is a
7collection of "scalar" objects. Routines here can save collections of
8scalars into a file and reload them; also, support is included here for
9*/
10
11#include <stdlib.h>
12#include <stdio.h>
13#include "m_pd.h"
14#include "g_canvas.h"
15#include <string.h>
16
17 /* the following routines read "scalars" from a file into a canvas. */
18
19static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout,
20 int *p_next)
21{
22 int i, j;
23 int indexwas = *p_next;
24 *p_indexout = indexwas;
25 if (indexwas >= natoms)
26 return (0);
27 for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++)
28 ;
29 if (i >= natoms)
30 *p_next = i;
31 else *p_next = i + 1;
32 return (i - indexwas);
33}
34
35int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
36 int *p_nextmsg, int selectit);
37
38static void canvas_readerror(int natoms, t_atom *vec, int message,
39 int nline, char *s)
40{
41 error(s);
42 startpost("line was:");
43 postatom(nline, vec + message);
44 endpost();
45}
46
47 /* fill in the contents of the scalar into the vector w. */
48
49static void glist_readatoms(t_glist *x, int natoms, t_atom *vec,
50 int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv)
51{
52 int message, nline, n, i;
53
54 t_template *template = template_findbyname(templatesym);
55 if (!template)
56 {
57 error("%s: no such template", templatesym->s_name);
58 *p_nextmsg = natoms;
59 return;
60 }
61 word_restore(w, template, argc, argv);
62 n = template->t_n;
63 for (i = 0; i < n; i++)
64 {
65 if (template->t_vec[i].ds_type == DT_ARRAY)
66 {
67 int j;
68 t_array *a = w[i].w_array;
69 int elemsize = a->a_elemsize, nitems = 0;
70 t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate;
71 t_template *arraytemplate =
72 template_findbyname(arraytemplatesym);
73 if (!arraytemplate)
74 {
75 error("%s: no such template", arraytemplatesym->s_name);
76 }
77 else while (1)
78 {
79 t_word *element;
80 int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
81 /* empty line terminates array */
82 if (!nline)
83 break;
84 array_resize(a, arraytemplate, nitems + 1);
85 element = (t_word *)(((char *)a->a_vec) +
86 nitems * elemsize);
87 glist_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym,
88 element, nline, vec + message);
89 nitems++;
90 }
91 }
92 else if (template->t_vec[i].ds_type == DT_LIST)
93 {
94 while (1)
95 {
96 if (!glist_readscalar(w->w_list, natoms, vec,
97 p_nextmsg, 0))
98 break;
99 }
100 }
101 }
102}
103
104int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
105 int *p_nextmsg, int selectit)
106{
107 int message, i, j, nline;
108 t_template *template;
109 t_symbol *templatesym;
110 t_scalar *sc;
111 int nextmsg = *p_nextmsg;
112 int wasvis = glist_isvisible(x);
113
114 if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL)
115 {
116 if (nextmsg < natoms)
117 post("stopping early: type %d", vec[nextmsg].a_type);
118 *p_nextmsg = natoms;
119 return (0);
120 }
121 templatesym = canvas_makebindsym(vec[nextmsg].a_w.w_symbol);
122 *p_nextmsg = nextmsg + 1;
123
124 if (!(template = template_findbyname(templatesym)))
125 {
126 error("canvas_read: %s: no such template", templatesym->s_name);
127 *p_nextmsg = natoms;
128 return (0);
129 }
130 sc = scalar_new(x, templatesym);
131 if (!sc)
132 {
133 error("couldn't create scalar \"%s\"", templatesym->s_name);
134 *p_nextmsg = natoms;
135 return (0);
136 }
137 if (wasvis)
138 {
139 /* temporarily lie about vis flag while this is built */
140 glist_getcanvas(x)->gl_mapped = 0;
141 }
142 glist_add(x, &sc->sc_gobj);
143
144 nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
145 glist_readatoms(x, natoms, vec, p_nextmsg, templatesym, sc->sc_vec,
146 nline, vec + message);
147 if (wasvis)
148 {
149 /* reset vis flag as before */
150 glist_getcanvas(x)->gl_mapped = 1;
151 gobj_vis(&sc->sc_gobj, x, 1);
152 }
153 if (selectit)
154 {
155 glist_select(x, &sc->sc_gobj);
156 }
157 return (1);
158}
159
160void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem)
161{
162 t_canvas *canvas = glist_getcanvas(x);
163 int cr = 0, natoms, nline, message, nextmsg = 0, i, j, nitems;
164 t_atom *vec;
165 t_gobj *gobj;
166
167 natoms = binbuf_getnatom(b);
168 vec = binbuf_getvec(b);
169
170
171 /* check for file type */
172 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
173 if (nline != 1 && vec[message].a_type != A_SYMBOL &&
174 strcmp(vec[message].a_w.w_symbol->s_name, "data"))
175 {
176 pd_error(x, "%s: file apparently of wrong type", filename);
177 binbuf_free(b);
178 return;
179 }
180 /* read in templates and check for consistency */
181 while (1)
182 {
183 t_template *newtemplate, *existtemplate;
184 t_symbol *templatesym;
185 t_atom *templateargs = getbytes(0);
186 int ntemplateargs = 0, newnargs;
187 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
188 if (nline < 2)
189 break;
190 else if (nline > 2)
191 canvas_readerror(natoms, vec, message, nline,
192 "extra items ignored");
193 else if (vec[message].a_type != A_SYMBOL ||
194 strcmp(vec[message].a_w.w_symbol->s_name, "template") ||
195 vec[message + 1].a_type != A_SYMBOL)
196 {
197 canvas_readerror(natoms, vec, message, nline,
198 "bad template header");
199 continue;
200 }
201 templatesym = canvas_makebindsym(vec[message + 1].a_w.w_symbol);
202 while (1)
203 {
204 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
205 if (nline != 2 && nline != 3)
206 break;
207 newnargs = ntemplateargs + nline;
208 templateargs = (t_atom *)t_resizebytes(templateargs,
209 sizeof(*templateargs) * ntemplateargs,
210 sizeof(*templateargs) * newnargs);
211 templateargs[ntemplateargs] = vec[message];
212 templateargs[ntemplateargs + 1] = vec[message + 1];
213 if (nline == 3)
214 templateargs[ntemplateargs + 2] = vec[message + 2];
215 ntemplateargs = newnargs;
216 }
217 newtemplate = template_new(templatesym, ntemplateargs, templateargs);
218 t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs);
219 if (!(existtemplate = template_findbyname(templatesym)))
220 {
221 error("%s: template not found in current patch",
222 templatesym->s_name);
223 template_free(newtemplate);
224 return;
225 }
226 if (!template_match(existtemplate, newtemplate))
227 {
228 error("%s: template doesn't match current one",
229 templatesym->s_name);
230 template_free(newtemplate);
231 return;
232 }
233 template_free(newtemplate);
234 }
235 while (nextmsg < natoms)
236 {
237 glist_readscalar(x, natoms, vec, &nextmsg, selectem);
238 }
239}
240
241static void glist_doread(t_glist *x, t_symbol *filename, t_symbol *format,
242 int clearme)
243{
244 t_binbuf *b = binbuf_new();
245 t_canvas *canvas = glist_getcanvas(x);
246 int wasvis = glist_isvisible(canvas);
247 int cr = 0, natoms, nline, message, nextmsg = 0, i, j;
248 t_atom *vec;
249
250 if (!strcmp(format->s_name, "cr"))
251 cr = 1;
252 else if (*format->s_name)
253 error("qlist_read: unknown flag: %s", format->s_name);
254
255 if (binbuf_read_via_path(b, filename->s_name,
256 canvas_getdir(canvas)->s_name, cr))
257 {
258 pd_error(x, "read failed");
259 binbuf_free(b);
260 return;
261 }
262 if (wasvis)
263 canvas_vis(canvas, 0);
264 if (clearme)
265 glist_clear(x);
266 glist_readfrombinbuf(x, b, filename->s_name, 0);
267 if (wasvis)
268 canvas_vis(canvas, 1);
269 binbuf_free(b);
270}
271
272void glist_read(t_glist *x, t_symbol *filename, t_symbol *format)
273{
274 glist_doread(x, filename, format, 1);
275}
276
277void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format)
278{
279 glist_doread(x, filename, format, 0);
280}
281
282 /* read text from a "properties" window, called from a gfxstub set
283 up in scalar_properties(). We try to restore the object; if successful
284 we delete the scalar and put the new thing in its place on the list. */
285void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b)
286{
287 int ntotal, nnew, scindex;
288 t_gobj *y, *y2 = 0, *newone, *oldone = 0;
289 for (y = x->gl_list, ntotal = 0, scindex = -1; y; y = y->g_next)
290 {
291 if (y == &sc->sc_gobj)
292 scindex = ntotal, oldone = y;
293 ntotal++;
294 }
295
296 if (scindex == -1)
297 bug("data_properties: scalar disappeared");
298 glist_readfrombinbuf(x, b, "properties dialog", 0);
299 newone = 0;
300 if (scindex >= 0)
301 {
302 /* take the new object off the list */
303 if (ntotal)
304 {
305 for (y = x->gl_list, nnew = 1; y2 = y->g_next;
306 y = y2, nnew++)
307 if (nnew == ntotal)
308 {
309 newone = y2;
310 y->g_next = y2->g_next;
311 break;
312 }
313 }
314 else newone = x->gl_list, x->gl_list = newone->g_next;
315 }
316 if (!newone)
317 error("couldn't update properties (perhaps a format problem?)");
318 else if (!oldone)
319 bug("data_properties: couldn't find old element");
320 else
321 {
322 glist_delete(x, oldone);
323 if (scindex > 0)
324 {
325 for (y = x->gl_list, nnew = 1; y;
326 y = y->g_next, nnew++)
327 if (nnew == scindex || !y->g_next)
328 {
329 newone->g_next = y->g_next;
330 y->g_next = newone;
331 goto didit;
332 }
333 bug("data_properties: can't reinsert");
334 }
335 else newone->g_next = x->gl_list, x->gl_list = newone;
336 }
337didit:
338 ;
339}
340
341 /* ----------- routines to write data to a binbuf ----------- */
342
343void canvas_doaddtemplate(t_symbol *templatesym,
344 int *p_ntemplates, t_symbol ***p_templatevec)
345{
346 int n = *p_ntemplates, i;
347 t_symbol **templatevec = *p_templatevec;
348 for (i = 0; i < n; i++)
349 if (templatevec[i] == templatesym)
350 return;
351 templatevec = (t_symbol **)t_resizebytes(templatevec,
352 n * sizeof(*templatevec), (n+1) * sizeof(*templatevec));
353 templatevec[n] = templatesym;
354 *p_templatevec = templatevec;
355 *p_ntemplates = n+1;
356}
357
358static void glist_writelist(t_gobj *y, t_binbuf *b);
359
360void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b,
361 int amarrayelement)
362{
363 t_dataslot *ds;
364 t_template *template = template_findbyname(templatesym);
365 t_atom *a = (t_atom *)t_getbytes(0);
366 int i, n = template->t_n, natom = 0;
367 if (!amarrayelement)
368 {
369 t_atom templatename;
370 SETSYMBOL(&templatename, gensym(templatesym->s_name + 3));
371 binbuf_add(b, 1, &templatename);
372 }
373 if (!template)
374 bug("canvas_writescalar");
375 /* write the atoms (floats and symbols) */
376 for (i = 0; i < n; i++)
377 {
378 if (template->t_vec[i].ds_type == DT_FLOAT ||
379 template->t_vec[i].ds_type == DT_SYMBOL)
380 {
381 a = (t_atom *)t_resizebytes(a,
382 natom * sizeof(*a), (natom + 1) * sizeof (*a));
383 if (template->t_vec[i].ds_type == DT_FLOAT)
384 SETFLOAT(a + natom, w[i].w_float);
385 else SETSYMBOL(a + natom, w[i].w_symbol);
386 natom++;
387 }
388 }
389 /* array elements have to have at least something */
390 if (natom == 0 && amarrayelement)
391 SETSYMBOL(a + natom, &s_bang), natom++;
392 binbuf_add(b, natom, a);
393 binbuf_addsemi(b);
394 t_freebytes(a, natom * sizeof(*a));
395 for (i = 0; i < n; i++)
396 {
397 if (template->t_vec[i].ds_type == DT_ARRAY)
398 {
399 int j;
400 t_array *a = w[i].w_array;
401 int elemsize = a->a_elemsize, nitems = a->a_n;
402 t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate;
403 for (j = 0; j < nitems; j++)
404 canvas_writescalar(arraytemplatesym,
405 (t_word *)(((char *)a->a_vec) + elemsize * j), b, 1);
406 binbuf_addsemi(b);
407 }
408 else if (template->t_vec[i].ds_type == DT_LIST)
409 {
410 glist_writelist(w->w_list->gl_list, b);
411 binbuf_addsemi(b);
412 }
413 }
414}
415
416static void glist_writelist(t_gobj *y, t_binbuf *b)
417{
418 for (; y; y = y->g_next)
419 {
420 if (pd_class(&y->g_pd) == scalar_class)
421 {
422 canvas_writescalar(((t_scalar *)y)->sc_template,
423 ((t_scalar *)y)->sc_vec, b, 0);
424 }
425 }
426}
427
428 /* ------------ routines to write out templates for data ------- */
429
430static void canvas_addtemplatesforlist(t_gobj *y,
431 int *p_ntemplates, t_symbol ***p_templatevec);
432
433static void canvas_addtemplatesforscalar(t_symbol *templatesym,
434 t_word *w, int *p_ntemplates, t_symbol ***p_templatevec)
435{
436 t_dataslot *ds;
437 int i;
438 t_template *template = template_findbyname(templatesym);
439 canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec);
440 if (!template)
441 bug("canvas_addtemplatesforscalar");
442 else for (ds = template->t_vec, i = template->t_n; i--; ds++, w++)
443 {
444 if (ds->ds_type == DT_ARRAY)
445 {
446 int j;
447 t_array *a = w->w_array;
448 int elemsize = a->a_elemsize, nitems = a->a_n;
449 t_symbol *arraytemplatesym = ds->ds_arraytemplate;
450 canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec);
451 for (j = 0; j < nitems; j++)
452 canvas_addtemplatesforscalar(arraytemplatesym,
453 (t_word *)(((char *)a->a_vec) + elemsize * j),
454 p_ntemplates, p_templatevec);
455 }
456 else if (ds->ds_type == DT_LIST)
457 canvas_addtemplatesforlist(w->w_list->gl_list,
458 p_ntemplates, p_templatevec);
459 }
460}
461
462static void canvas_addtemplatesforlist(t_gobj *y,
463 int *p_ntemplates, t_symbol ***p_templatevec)
464{
465 for (; y; y = y->g_next)
466 {
467 if (pd_class(&y->g_pd) == scalar_class)
468 {
469 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
470 ((t_scalar *)y)->sc_vec, p_ntemplates, p_templatevec);
471 }
472 }
473}
474
475 /* write all "scalars" in a glist to a binbuf. */
476t_binbuf *glist_writetobinbuf(t_glist *x, int wholething)
477{
478 int i;
479 t_symbol **templatevec = getbytes(0);
480 int ntemplates = 0;
481 t_gobj *y;
482 t_binbuf *b = binbuf_new();
483
484 for (y = x->gl_list; y; y = y->g_next)
485 {
486 if ((pd_class(&y->g_pd) == scalar_class) &&
487 (wholething || glist_isselected(x, y)))
488 {
489 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
490 ((t_scalar *)y)->sc_vec, &ntemplates, &templatevec);
491 }
492 }
493 binbuf_addv(b, "s;", gensym("data"));
494 for (i = 0; i < ntemplates; i++)
495 {
496 t_template *template = template_findbyname(templatevec[i]);
497 int j, m = template->t_n;
498 /* drop "pd-" prefix from template symbol to print it: */
499 binbuf_addv(b, "ss;", gensym("template"),
500 gensym(templatevec[i]->s_name + 3));
501 for (j = 0; j < m; j++)
502 {
503 t_symbol *type;
504 switch (template->t_vec[j].ds_type)
505 {
506 case DT_FLOAT: type = &s_float; break;
507 case DT_SYMBOL: type = &s_symbol; break;
508 case DT_ARRAY: type = gensym("array"); break;
509 case DT_LIST: type = &s_list; break;
510 default: type = &s_float; bug("canvas_write");
511 }
512 if (template->t_vec[j].ds_type == DT_ARRAY)
513 binbuf_addv(b, "sss;", type, template->t_vec[j].ds_name,
514 gensym(template->t_vec[j].ds_arraytemplate->s_name + 3));
515 else binbuf_addv(b, "ss;", type, template->t_vec[j].ds_name);
516 }
517 binbuf_addsemi(b);
518 }
519 binbuf_addsemi(b);
520 /* now write out the objects themselves */
521 for (y = x->gl_list; y; y = y->g_next)
522 {
523 if ((pd_class(&y->g_pd) == scalar_class) &&
524 (wholething || glist_isselected(x, y)))
525 {
526 canvas_writescalar(((t_scalar *)y)->sc_template,
527 ((t_scalar *)y)->sc_vec, b, 0);
528 }
529 }
530 return (b);
531}
532
533static void glist_write(t_glist *x, t_symbol *filename, t_symbol *format)
534{
535 int cr = 0, i;
536 t_binbuf *b;
537 char buf[MAXPDSTRING];
538 t_symbol **templatevec = getbytes(0);
539 int ntemplates = 0;
540 t_gobj *y;
541 t_canvas *canvas = glist_getcanvas(x);
542 canvas_makefilename(canvas, filename->s_name, buf, MAXPDSTRING);
543 if (!strcmp(format->s_name, "cr"))
544 cr = 1;
545 else if (*format->s_name)
546 error("qlist_read: unknown flag: %s", format->s_name);
547
548 b = glist_writetobinbuf(x, 1);
549 if (b)
550 {
551 if (binbuf_write(b, buf, "", cr))
552 error("%s: write failed", filename->s_name);
553 binbuf_free(b);
554 }
555}
556
557/* ------ routines to save and restore canvases (patches) recursively. ----*/
558
559 /* save to a binbuf, called recursively; cf. canvas_savetofile() which
560 saves the document, and is only called on root canvases. */
561static void canvas_saveto(t_canvas *x, t_binbuf *b)
562{
563 t_gobj *y;
564 t_linetraverser t;
565 t_outconnect *oc;
566 /* subpatch */
567 if (x->gl_owner && !x->gl_env)
568 {
569 binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"),
570 (t_int)(x->gl_screenx1),
571 (t_int)(x->gl_screeny1),
572 (t_int)(x->gl_screenx2 - x->gl_screenx1),
573 (t_int)(x->gl_screeny2 - x->gl_screeny1),
574 (*x->gl_name->s_name ? x->gl_name: gensym("(subpatch)")),
575 x->gl_mapped);
576 }
577 /* root or abstraction */
578 else binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"),
579 (t_int)(x->gl_screenx1),
580 (t_int)(x->gl_screeny1),
581 (t_int)(x->gl_screenx2 - x->gl_screenx1),
582 (t_int)(x->gl_screeny2 - x->gl_screeny1),
583 x->gl_font);
584
585 for (y = x->gl_list; y; y = y->g_next)
586 gobj_save(y, b);
587
588 linetraverser_start(&t, x);
589 while (oc = linetraverser_next(&t))
590 {
591 int srcno = canvas_getindex(x, &t.tr_ob->ob_g);
592 int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g);
593 binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"),
594 srcno, t.tr_outno, sinkno, t.tr_inno);
595 }
596 /* unless everything is the default (as in ordinary subpatches)
597 print out a "coords" message to set up the coordinate systems */
598 if (x->gl_isgraph || x->gl_x1 || x->gl_y1 ||
599 x->gl_x2 != 1 || x->gl_y2 != 1 || x->gl_pixwidth || x->gl_pixheight)
600 binbuf_addv(b, "ssfffffff;", gensym("#X"), gensym("coords"),
601 x->gl_x1, x->gl_y1,
602 x->gl_x2, x->gl_y2,
603 (float)x->gl_pixwidth, (float)x->gl_pixheight,
604 (float)x->gl_isgraph);
605}
606
607 /* call this recursively to collect all the template names for
608 a canvas or for the selection. */
609static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp,
610 t_symbol ***templatevecp, int wholething)
611{
612 t_gobj *y;
613
614 for (y = x->gl_list; y; y = y->g_next)
615 {
616 if ((pd_class(&y->g_pd) == scalar_class) &&
617 (wholething || glist_isselected(x, y)))
618 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
619 ((t_scalar *)y)->sc_vec, ntemplatesp, templatevecp);
620 else if ((pd_class(&y->g_pd) == canvas_class) &&
621 (wholething || glist_isselected(x, y)))
622 canvas_collecttemplatesfor((t_canvas *)y,
623 ntemplatesp, templatevecp, 1);
624 }
625}
626
627 /* save the templates needed by a canvas to a binbuf. */
628static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething)
629{
630 t_symbol **templatevec = getbytes(0);
631 int i, ntemplates = 0;
632 t_gobj *y;
633 canvas_collecttemplatesfor(x, &ntemplates, &templatevec, wholething);
634 for (i = 0; i < ntemplates; i++)
635 {
636 t_template *template = template_findbyname(templatevec[i]);
637 int j, m = template->t_n;
638 if (!template)
639 {
640 bug("canvas_savetemplatesto");
641 continue;
642 }
643 /* drop "pd-" prefix from template symbol to print */
644 binbuf_addv(b, "sss", &s__N, gensym("struct"),
645 gensym(templatevec[i]->s_name + 3));
646 for (j = 0; j < m; j++)
647 {
648 t_symbol *type;
649 switch (template->t_vec[j].ds_type)
650 {
651 case DT_FLOAT: type = &s_float; break;
652 case DT_SYMBOL: type = &s_symbol; break;
653 case DT_ARRAY: type = gensym("array"); break;
654 case DT_LIST: type = &s_list; break;
655 default: type = &s_float; bug("canvas_write");
656 }
657 if (template->t_vec[j].ds_type == DT_ARRAY)
658 binbuf_addv(b, "sss", type, template->t_vec[j].ds_name,
659 gensym(template->t_vec[j].ds_arraytemplate->s_name + 3));
660 else binbuf_addv(b, "ss", type, template->t_vec[j].ds_name);
661 }
662 binbuf_addsemi(b);
663 }
664}
665
666void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except);
667
668 /* save a "root" canvas to a file; cf. canvas_saveto() which saves the
669 body (and which is called recursively.) */
670static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir)
671{
672 t_binbuf *b = binbuf_new();
673 canvas_savetemplatesto(x, b, 1);
674 canvas_saveto(x, b);
675 if (binbuf_write(b, filename->s_name, dir->s_name, 0)) sys_ouch();
676 else
677 {
678 /* if not an abstraction, reset title bar and directory */
679 if (!x->gl_owner)
680 canvas_rename(x, filename, dir);
681 post("saved to: %s/%s", dir->s_name, filename->s_name);
682 canvas_dirty(x, 0);
683 canvas_reload(filename, dir, &x->gl_gobj);
684 }
685 binbuf_free(b);
686}
687
688static void canvas_menusaveas(t_canvas *x)
689{
690 t_canvas *x2 = canvas_getrootfor(x);
691 sys_vgui("pdtk_canvas_saveas .x%x \"%s\" \"%s\"\n", x2,
692 x2->gl_name->s_name, canvas_getdir(x2)->s_name);
693}
694
695static void canvas_menusave(t_canvas *x)
696{
697 t_canvas *x2 = canvas_getrootfor(x);
698 char *name = x2->gl_name->s_name;
699 if (*name && strncmp(name, "Untitled", 8)
700 && (strlen(name) < 4 || strcmp(name + strlen(name)-4, ".pat")))
701 canvas_savetofile(x2, x2->gl_name, canvas_getdir(x2));
702 else canvas_menusaveas(x2);
703}
704
705
706void g_readwrite_setup(void)
707{
708 class_addmethod(canvas_class, (t_method)glist_write,
709 gensym("write"), A_SYMBOL, A_DEFSYM, A_NULL);
710 class_addmethod(canvas_class, (t_method)glist_read,
711 gensym("read"), A_SYMBOL, A_DEFSYM, A_NULL);
712 class_addmethod(canvas_class, (t_method)glist_mergefile,
713 gensym("mergefile"), A_SYMBOL, A_DEFSYM, A_NULL);
714 class_addmethod(canvas_class, (t_method)canvas_savetofile,
715 gensym("savetofile"), A_SYMBOL, A_SYMBOL, 0);
716 class_addmethod(canvas_class, (t_method)canvas_saveto,
717 gensym("saveto"), A_CANT, 0);
718/* ------------------ from the menu ------------------------- */
719 class_addmethod(canvas_class, (t_method)canvas_menusave,
720 gensym("menusave"), 0);
721 class_addmethod(canvas_class, (t_method)canvas_menusaveas,
722 gensym("menusaveas"), 0);
723}
724/* Copyright (c) 1997-2002 Miller Puckette and others.
725* For information on usage and redistribution, and for a DISCLAIMER OF ALL
726* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
727
728/* this file reads and writes the "data" portions of a canvas to a file.
729See also canvas_saveto(), etc., in g_editor.c. The data portion is a
730collection of "scalar" objects. Routines here can save collections of
731scalars into a file and reload them; also, support is included here for
732*/
733
734#include <stdlib.h>
735#include <stdio.h>
736#include "m_pd.h"
737#include "g_canvas.h"
738#include <string.h>
739
740 /* the following routines read "scalars" from a file into a canvas. */
741
742static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout,
743 int *p_next)
744{
745 int i, j;
746 int indexwas = *p_next;
747 *p_indexout = indexwas;
748 if (indexwas >= natoms)
749 return (0);
750 for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++)
751 ;
752 if (i >= natoms)
753 *p_next = i;
754 else *p_next = i + 1;
755 return (i - indexwas);
756}
757
758int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
759 int *p_nextmsg, int selectit);
760
761static void canvas_readerror(int natoms, t_atom *vec, int message,
762 int nline, char *s)
763{
764 error(s);
765 startpost("line was:");
766 postatom(nline, vec + message);
767 endpost();
768}
769
770 /* fill in the contents of the scalar into the vector w. */
771
772static void glist_readatoms(t_glist *x, int natoms, t_atom *vec,
773 int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv)
774{
775 int message, nline, n, i;
776
777 t_template *template = template_findbyname(templatesym);
778 if (!template)
779 {
780 error("%s: no such template", templatesym->s_name);
781 *p_nextmsg = natoms;
782 return;
783 }
784 word_restore(w, template, argc, argv);
785 n = template->t_n;
786 for (i = 0; i < n; i++)
787 {
788 if (template->t_vec[i].ds_type == DT_ARRAY)
789 {
790 int j;
791 t_array *a = w[i].w_array;
792 int elemsize = a->a_elemsize, nitems = 0;
793 t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate;
794 t_template *arraytemplate =
795 template_findbyname(arraytemplatesym);
796 if (!arraytemplate)
797 {
798 error("%s: no such template", arraytemplatesym->s_name);
799 }
800 else while (1)
801 {
802 t_word *element;
803 int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
804 /* empty line terminates array */
805 if (!nline)
806 break;
807 array_resize(a, arraytemplate, nitems + 1);
808 element = (t_word *)(((char *)a->a_vec) +
809 nitems * elemsize);
810 glist_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym,
811 element, nline, vec + message);
812 nitems++;
813 }
814 }
815 else if (template->t_vec[i].ds_type == DT_LIST)
816 {
817 while (1)
818 {
819 if (!glist_readscalar(w->w_list, natoms, vec,
820 p_nextmsg, 0))
821 break;
822 }
823 }
824 }
825}
826
827int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
828 int *p_nextmsg, int selectit)
829{
830 int message, i, j, nline;
831 t_template *template;
832 t_symbol *templatesym;
833 t_scalar *sc;
834 int nextmsg = *p_nextmsg;
835 int wasvis = glist_isvisible(x);
836
837 if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL)
838 {
839 if (nextmsg < natoms)
840 post("stopping early: type %d", vec[nextmsg].a_type);
841 *p_nextmsg = natoms;
842 return (0);
843 }
844 templatesym = canvas_makebindsym(vec[nextmsg].a_w.w_symbol);
845 *p_nextmsg = nextmsg + 1;
846
847 if (!(template = template_findbyname(templatesym)))
848 {
849 error("canvas_read: %s: no such template", templatesym->s_name);
850 *p_nextmsg = natoms;
851 return (0);
852 }
853 sc = scalar_new(x, templatesym);
854 if (!sc)
855 {
856 error("couldn't create scalar \"%s\"", templatesym->s_name);
857 *p_nextmsg = natoms;
858 return (0);
859 }
860 if (wasvis)
861 {
862 /* temporarily lie about vis flag while this is built */
863 glist_getcanvas(x)->gl_mapped = 0;
864 }
865 glist_add(x, &sc->sc_gobj);
866
867 nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
868 glist_readatoms(x, natoms, vec, p_nextmsg, templatesym, sc->sc_vec,
869 nline, vec + message);
870 if (wasvis)
871 {
872 /* reset vis flag as before */
873 glist_getcanvas(x)->gl_mapped = 1;
874 gobj_vis(&sc->sc_gobj, x, 1);
875 }
876 if (selectit)
877 {
878 glist_select(x, &sc->sc_gobj);
879 }
880 return (1);
881}
882
883void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem)
884{
885 t_canvas *canvas = glist_getcanvas(x);
886 int cr = 0, natoms, nline, message, nextmsg = 0, i, j, nitems;
887 t_atom *vec;
888 t_gobj *gobj;
889
890 natoms = binbuf_getnatom(b);
891 vec = binbuf_getvec(b);
892
893
894 /* check for file type */
895 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
896 if (nline != 1 && vec[message].a_type != A_SYMBOL &&
897 strcmp(vec[message].a_w.w_symbol->s_name, "data"))
898 {
899 pd_error(x, "%s: file apparently of wrong type", filename);
900 binbuf_free(b);
901 return;
902 }
903 /* read in templates and check for consistency */
904 while (1)
905 {
906 t_template *newtemplate, *existtemplate;
907 t_symbol *templatesym;
908 t_atom *templateargs = getbytes(0);
909 int ntemplateargs = 0, newnargs;
910 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
911 if (nline < 2)
912 break;
913 else if (nline > 2)
914 canvas_readerror(natoms, vec, message, nline,
915 "extra items ignored");
916 else if (vec[message].a_type != A_SYMBOL ||
917 strcmp(vec[message].a_w.w_symbol->s_name, "template") ||
918 vec[message + 1].a_type != A_SYMBOL)
919 {
920 canvas_readerror(natoms, vec, message, nline,
921 "bad template header");
922 continue;
923 }
924 templatesym = canvas_makebindsym(vec[message + 1].a_w.w_symbol);
925 while (1)
926 {
927 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
928 if (nline != 2 && nline != 3)
929 break;
930 newnargs = ntemplateargs + nline;
931 templateargs = (t_atom *)t_resizebytes(templateargs,
932 sizeof(*templateargs) * ntemplateargs,
933 sizeof(*templateargs) * newnargs);
934 templateargs[ntemplateargs] = vec[message];
935 templateargs[ntemplateargs + 1] = vec[message + 1];
936 if (nline == 3)
937 templateargs[ntemplateargs + 2] = vec[message + 2];
938 ntemplateargs = newnargs;
939 }
940 newtemplate = template_new(templatesym, ntemplateargs, templateargs);
941 t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs);
942 if (!(existtemplate = template_findbyname(templatesym)))
943 {
944 error("%s: template not found in current patch",
945 templatesym->s_name);
946 template_free(newtemplate);
947 return;
948 }
949 if (!template_match(existtemplate, newtemplate))
950 {
951 error("%s: template doesn't match current one",
952 templatesym->s_name);
953 template_free(newtemplate);
954 return;
955 }
956 template_free(newtemplate);
957 }
958 while (nextmsg < natoms)
959 {
960 glist_readscalar(x, natoms, vec, &nextmsg, selectem);
961 }
962}
963
964static void glist_doread(t_glist *x, t_symbol *filename, t_symbol *format,
965 int clearme)
966{
967 t_binbuf *b = binbuf_new();
968 t_canvas *canvas = glist_getcanvas(x);
969 int wasvis = glist_isvisible(canvas);
970 int cr = 0, natoms, nline, message, nextmsg = 0, i, j;
971 t_atom *vec;
972
973 if (!strcmp(format->s_name, "cr"))
974 cr = 1;
975 else if (*format->s_name)
976 error("qlist_read: unknown flag: %s", format->s_name);
977
978 if (binbuf_read_via_path(b, filename->s_name,
979 canvas_getdir(canvas)->s_name, cr))
980 {
981 pd_error(x, "read failed");
982 binbuf_free(b);
983 return;
984 }
985 if (wasvis)
986 canvas_vis(canvas, 0);
987 if (clearme)
988 glist_clear(x);
989 glist_readfrombinbuf(x, b, filename->s_name, 0);
990 if (wasvis)
991 canvas_vis(canvas, 1);
992 binbuf_free(b);
993}
994
995void glist_read(t_glist *x, t_symbol *filename, t_symbol *format)
996{
997 glist_doread(x, filename, format, 1);
998}
999
1000void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format)
1001{
1002 glist_doread(x, filename, format, 0);
1003}
1004
1005 /* read text from a "properties" window, called from a gfxstub set
1006 up in scalar_properties(). We try to restore the object; if successful
1007 we delete the scalar and put the new thing in its place on the list. */
1008void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b)
1009{
1010 int ntotal, nnew, scindex;
1011 t_gobj *y, *y2 = 0, *newone, *oldone = 0;
1012 for (y = x->gl_list, ntotal = 0, scindex = -1; y; y = y->g_next)
1013 {
1014 if (y == &sc->sc_gobj)
1015 scindex = ntotal, oldone = y;
1016 ntotal++;
1017 }
1018
1019 if (scindex == -1)
1020 bug("data_properties: scalar disappeared");
1021 glist_readfrombinbuf(x, b, "properties dialog", 0);
1022 newone = 0;
1023 if (scindex >= 0)
1024 {
1025 /* take the new object off the list */
1026 if (ntotal)
1027 {
1028 for (y = x->gl_list, nnew = 1; y2 = y->g_next;
1029 y = y2, nnew++)
1030 if (nnew == ntotal)
1031 {
1032 newone = y2;
1033 y->g_next = y2->g_next;
1034 break;
1035 }
1036 }
1037 else newone = x->gl_list, x->gl_list = newone->g_next;
1038 }
1039 if (!newone)
1040 error("couldn't update properties (perhaps a format problem?)");
1041 else if (!oldone)
1042 bug("data_properties: couldn't find old element");
1043 else
1044 {
1045 glist_delete(x, oldone);
1046 if (scindex > 0)
1047 {
1048 for (y = x->gl_list, nnew = 1; y;
1049 y = y->g_next, nnew++)
1050 if (nnew == scindex || !y->g_next)
1051 {
1052 newone->g_next = y->g_next;
1053 y->g_next = newone;
1054 goto didit;
1055 }
1056 bug("data_properties: can't reinsert");
1057 }
1058 else newone->g_next = x->gl_list, x->gl_list = newone;
1059 }
1060didit:
1061 ;
1062}
1063
1064 /* ----------- routines to write data to a binbuf ----------- */
1065
1066void canvas_doaddtemplate(t_symbol *templatesym,
1067 int *p_ntemplates, t_symbol ***p_templatevec)
1068{
1069 int n = *p_ntemplates, i;
1070 t_symbol **templatevec = *p_templatevec;
1071 for (i = 0; i < n; i++)
1072 if (templatevec[i] == templatesym)
1073 return;
1074 templatevec = (t_symbol **)t_resizebytes(templatevec,
1075 n * sizeof(*templatevec), (n+1) * sizeof(*templatevec));
1076 templatevec[n] = templatesym;
1077 *p_templatevec = templatevec;
1078 *p_ntemplates = n+1;
1079}
1080
1081static void glist_writelist(t_gobj *y, t_binbuf *b);
1082
1083void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b,
1084 int amarrayelement)
1085{
1086 t_dataslot *ds;
1087 t_template *template = template_findbyname(templatesym);
1088 t_atom *a = (t_atom *)t_getbytes(0);
1089 int i, n = template->t_n, natom = 0;
1090 if (!amarrayelement)
1091 {
1092 t_atom templatename;
1093 SETSYMBOL(&templatename, gensym(templatesym->s_name + 3));
1094 binbuf_add(b, 1, &templatename);
1095 }
1096 if (!template)
1097 bug("canvas_writescalar");
1098 /* write the atoms (floats and symbols) */
1099 for (i = 0; i < n; i++)
1100 {
1101 if (template->t_vec[i].ds_type == DT_FLOAT ||
1102 template->t_vec[i].ds_type == DT_SYMBOL)
1103 {
1104 a = (t_atom *)t_resizebytes(a,
1105 natom * sizeof(*a), (natom + 1) * sizeof (*a));
1106 if (template->t_vec[i].ds_type == DT_FLOAT)
1107 SETFLOAT(a + natom, w[i].w_float);
1108 else SETSYMBOL(a + natom, w[i].w_symbol);
1109 natom++;
1110 }
1111 }
1112 /* array elements have to have at least something */
1113 if (natom == 0 && amarrayelement)
1114 SETSYMBOL(a + natom, &s_bang), natom++;
1115 binbuf_add(b, natom, a);
1116 binbuf_addsemi(b);
1117 t_freebytes(a, natom * sizeof(*a));
1118 for (i = 0; i < n; i++)
1119 {
1120 if (template->t_vec[i].ds_type == DT_ARRAY)
1121 {
1122 int j;
1123 t_array *a = w[i].w_array;
1124 int elemsize = a->a_elemsize, nitems = a->a_n;
1125 t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate;
1126 for (j = 0; j < nitems; j++)
1127 canvas_writescalar(arraytemplatesym,
1128 (t_word *)(((char *)a->a_vec) + elemsize * j), b, 1);
1129 binbuf_addsemi(b);
1130 }
1131 else if (template->t_vec[i].ds_type == DT_LIST)
1132 {
1133 glist_writelist(w->w_list->gl_list, b);
1134 binbuf_addsemi(b);
1135 }
1136 }
1137}
1138
1139static void glist_writelist(t_gobj *y, t_binbuf *b)
1140{
1141 for (; y; y = y->g_next)
1142 {
1143 if (pd_class(&y->g_pd) == scalar_class)
1144 {
1145 canvas_writescalar(((t_scalar *)y)->sc_template,
1146 ((t_scalar *)y)->sc_vec, b, 0);
1147 }
1148 }
1149}
1150
1151 /* ------------ routines to write out templates for data ------- */
1152
1153static void canvas_addtemplatesforlist(t_gobj *y,
1154 int *p_ntemplates, t_symbol ***p_templatevec);
1155
1156static void canvas_addtemplatesforscalar(t_symbol *templatesym,
1157 t_word *w, int *p_ntemplates, t_symbol ***p_templatevec)
1158{
1159 t_dataslot *ds;
1160 int i;
1161 t_template *template = template_findbyname(templatesym);
1162 canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec);
1163 if (!template)
1164 bug("canvas_addtemplatesforscalar");
1165 else for (ds = template->t_vec, i = template->t_n; i--; ds++, w++)
1166 {
1167 if (ds->ds_type == DT_ARRAY)
1168 {
1169 int j;
1170 t_array *a = w->w_array;
1171 int elemsize = a->a_elemsize, nitems = a->a_n;
1172 t_symbol *arraytemplatesym = ds->ds_arraytemplate;
1173 canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec);
1174 for (j = 0; j < nitems; j++)
1175 canvas_addtemplatesforscalar(arraytemplatesym,
1176 (t_word *)(((char *)a->a_vec) + elemsize * j),
1177 p_ntemplates, p_templatevec);
1178 }
1179 else if (ds->ds_type == DT_LIST)
1180 canvas_addtemplatesforlist(w->w_list->gl_list,
1181 p_ntemplates, p_templatevec);
1182 }
1183}
1184
1185static void canvas_addtemplatesforlist(t_gobj *y,
1186 int *p_ntemplates, t_symbol ***p_templatevec)
1187{
1188 for (; y; y = y->g_next)
1189 {
1190 if (pd_class(&y->g_pd) == scalar_class)
1191 {
1192 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
1193 ((t_scalar *)y)->sc_vec, p_ntemplates, p_templatevec);
1194 }
1195 }
1196}
1197
1198 /* write all "scalars" in a glist to a binbuf. */
1199t_binbuf *glist_writetobinbuf(t_glist *x, int wholething)
1200{
1201 int i;
1202 t_symbol **templatevec = getbytes(0);
1203 int ntemplates = 0;
1204 t_gobj *y;
1205 t_binbuf *b = binbuf_new();
1206
1207 for (y = x->gl_list; y; y = y->g_next)
1208 {
1209 if ((pd_class(&y->g_pd) == scalar_class) &&
1210 (wholething || glist_isselected(x, y)))
1211 {
1212 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
1213 ((t_scalar *)y)->sc_vec, &ntemplates, &templatevec);
1214 }
1215 }
1216 binbuf_addv(b, "s;", gensym("data"));
1217 for (i = 0; i < ntemplates; i++)
1218 {
1219 t_template *template = template_findbyname(templatevec[i]);
1220 int j, m = template->t_n;
1221 /* drop "pd-" prefix from template symbol to print it: */
1222 binbuf_addv(b, "ss;", gensym("template"),
1223 gensym(templatevec[i]->s_name + 3));
1224 for (j = 0; j < m; j++)
1225 {
1226 t_symbol *type;
1227 switch (template->t_vec[j].ds_type)
1228 {
1229 case DT_FLOAT: type = &s_float; break;
1230 case DT_SYMBOL: type = &s_symbol; break;
1231 case DT_ARRAY: type = gensym("array"); break;
1232 case DT_LIST: type = &s_list; break;
1233 default: type = &s_float; bug("canvas_write");
1234 }
1235 if (template->t_vec[j].ds_type == DT_ARRAY)
1236 binbuf_addv(b, "sss;", type, template->t_vec[j].ds_name,
1237 gensym(template->t_vec[j].ds_arraytemplate->s_name + 3));
1238 else binbuf_addv(b, "ss;", type, template->t_vec[j].ds_name);
1239 }
1240 binbuf_addsemi(b);
1241 }
1242 binbuf_addsemi(b);
1243 /* now write out the objects themselves */
1244 for (y = x->gl_list; y; y = y->g_next)
1245 {
1246 if ((pd_class(&y->g_pd) == scalar_class) &&
1247 (wholething || glist_isselected(x, y)))
1248 {
1249 canvas_writescalar(((t_scalar *)y)->sc_template,
1250 ((t_scalar *)y)->sc_vec, b, 0);
1251 }
1252 }
1253 return (b);
1254}
1255
1256static void glist_write(t_glist *x, t_symbol *filename, t_symbol *format)
1257{
1258 int cr = 0, i;
1259 t_binbuf *b;
1260 char buf[MAXPDSTRING];
1261 t_symbol **templatevec = getbytes(0);
1262 int ntemplates = 0;
1263 t_gobj *y;
1264 t_canvas *canvas = glist_getcanvas(x);
1265 canvas_makefilename(canvas, filename->s_name, buf, MAXPDSTRING);
1266 if (!strcmp(format->s_name, "cr"))
1267 cr = 1;
1268 else if (*format->s_name)
1269 error("qlist_read: unknown flag: %s", format->s_name);
1270
1271 b = glist_writetobinbuf(x, 1);
1272 if (b)
1273 {
1274 if (binbuf_write(b, buf, "", cr))
1275 error("%s: write failed", filename->s_name);
1276 binbuf_free(b);
1277 }
1278}
1279
1280/* ------ routines to save and restore canvases (patches) recursively. ----*/
1281
1282 /* save to a binbuf, called recursively; cf. canvas_savetofile() which
1283 saves the document, and is only called on root canvases. */
1284static void canvas_saveto(t_canvas *x, t_binbuf *b)
1285{
1286 t_gobj *y;
1287 t_linetraverser t;
1288 t_outconnect *oc;
1289 /* subpatch */
1290 if (x->gl_owner && !x->gl_env)
1291 {
1292 binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"),
1293 (t_int)(x->gl_screenx1),
1294 (t_int)(x->gl_screeny1),
1295 (t_int)(x->gl_screenx2 - x->gl_screenx1),
1296 (t_int)(x->gl_screeny2 - x->gl_screeny1),
1297 (*x->gl_name->s_name ? x->gl_name: gensym("(subpatch)")),
1298 x->gl_mapped);
1299 }
1300 /* root or abstraction */
1301 else binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"),
1302 (t_int)(x->gl_screenx1),
1303 (t_int)(x->gl_screeny1),
1304 (t_int)(x->gl_screenx2 - x->gl_screenx1),
1305 (t_int)(x->gl_screeny2 - x->gl_screeny1),
1306 x->gl_font);
1307
1308 for (y = x->gl_list; y; y = y->g_next)
1309 gobj_save(y, b);
1310
1311 linetraverser_start(&t, x);
1312 while (oc = linetraverser_next(&t))
1313 {
1314 int srcno = canvas_getindex(x, &t.tr_ob->ob_g);
1315 int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g);
1316 binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"),
1317 srcno, t.tr_outno, sinkno, t.tr_inno);
1318 }
1319 /* unless everything is the default (as in ordinary subpatches)
1320 print out a "coords" message to set up the coordinate systems */
1321 if (x->gl_isgraph || x->gl_x1 || x->gl_y1 ||
1322 x->gl_x2 != 1 || x->gl_y2 != 1 || x->gl_pixwidth || x->gl_pixheight)
1323 binbuf_addv(b, "ssfffffff;", gensym("#X"), gensym("coords"),
1324 x->gl_x1, x->gl_y1,
1325 x->gl_x2, x->gl_y2,
1326 (float)x->gl_pixwidth, (float)x->gl_pixheight,
1327 (float)x->gl_isgraph);
1328}
1329
1330 /* call this recursively to collect all the template names for
1331 a canvas or for the selection. */
1332static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp,
1333 t_symbol ***templatevecp, int wholething)
1334{
1335 t_gobj *y;
1336
1337 for (y = x->gl_list; y; y = y->g_next)
1338 {
1339 if ((pd_class(&y->g_pd) == scalar_class) &&
1340 (wholething || glist_isselected(x, y)))
1341 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
1342 ((t_scalar *)y)->sc_vec, ntemplatesp, templatevecp);
1343 else if ((pd_class(&y->g_pd) == canvas_class) &&
1344 (wholething || glist_isselected(x, y)))
1345 canvas_collecttemplatesfor((t_canvas *)y,
1346 ntemplatesp, templatevecp, 1);
1347 }
1348}
1349
1350 /* save the templates needed by a canvas to a binbuf. */
1351static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething)
1352{
1353 t_symbol **templatevec = getbytes(0);
1354 int i, ntemplates = 0;
1355 t_gobj *y;
1356 canvas_collecttemplatesfor(x, &ntemplates, &templatevec, wholething);
1357 for (i = 0; i < ntemplates; i++)
1358 {
1359 t_template *template = template_findbyname(templatevec[i]);
1360 int j, m = template->t_n;
1361 if (!template)
1362 {
1363 bug("canvas_savetemplatesto");
1364 continue;
1365 }
1366 /* drop "pd-" prefix from template symbol to print */
1367 binbuf_addv(b, "sss", &s__N, gensym("struct"),
1368 gensym(templatevec[i]->s_name + 3));
1369 for (j = 0; j < m; j++)
1370 {
1371 t_symbol *type;
1372 switch (template->t_vec[j].ds_type)
1373 {
1374 case DT_FLOAT: type = &s_float; break;
1375 case DT_SYMBOL: type = &s_symbol; break;
1376 case DT_ARRAY: type = gensym("array"); break;
1377 case DT_LIST: type = &s_list; break;
1378 default: type = &s_float; bug("canvas_write");
1379 }
1380 if (template->t_vec[j].ds_type == DT_ARRAY)
1381 binbuf_addv(b, "sss", type, template->t_vec[j].ds_name,
1382 gensym(template->t_vec[j].ds_arraytemplate->s_name + 3));
1383 else binbuf_addv(b, "ss", type, template->t_vec[j].ds_name);
1384 }
1385 binbuf_addsemi(b);
1386 }
1387}
1388
1389void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except);
1390
1391 /* save a "root" canvas to a file; cf. canvas_saveto() which saves the
1392 body (and which is called recursively.) */
1393static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir)
1394{
1395 t_binbuf *b = binbuf_new();
1396 canvas_savetemplatesto(x, b, 1);
1397 canvas_saveto(x, b);
1398 if (binbuf_write(b, filename->s_name, dir->s_name, 0)) sys_ouch();
1399 else
1400 {
1401 /* if not an abstraction, reset title bar and directory */
1402 if (!x->gl_owner)
1403 canvas_rename(x, filename, dir);
1404 post("saved to: %s/%s", dir->s_name, filename->s_name);
1405 canvas_dirty(x, 0);
1406 canvas_reload(filename, dir, &x->gl_gobj);
1407 }
1408 binbuf_free(b);
1409}
1410
1411static void canvas_menusaveas(t_canvas *x)
1412{
1413 t_canvas *x2 = canvas_getrootfor(x);
1414 sys_vgui("pdtk_canvas_saveas .x%x \"%s\" \"%s\"\n", x2,
1415 x2->gl_name->s_name, canvas_getdir(x2)->s_name);
1416}
1417
1418static void canvas_menusave(t_canvas *x)
1419{
1420 t_canvas *x2 = canvas_getrootfor(x);
1421 char *name = x2->gl_name->s_name;
1422 if (*name && strncmp(name, "Untitled", 8)
1423 && (strlen(name) < 4 || strcmp(name + strlen(name)-4, ".pat")))
1424 canvas_savetofile(x2, x2->gl_name, canvas_getdir(x2));
1425 else canvas_menusaveas(x2);
1426}
1427
1428
1429void g_readwrite_setup(void)
1430{
1431 class_addmethod(canvas_class, (t_method)glist_write,
1432 gensym("write"), A_SYMBOL, A_DEFSYM, A_NULL);
1433 class_addmethod(canvas_class, (t_method)glist_read,
1434 gensym("read"), A_SYMBOL, A_DEFSYM, A_NULL);
1435 class_addmethod(canvas_class, (t_method)glist_mergefile,
1436 gensym("mergefile"), A_SYMBOL, A_DEFSYM, A_NULL);
1437 class_addmethod(canvas_class, (t_method)canvas_savetofile,
1438 gensym("savetofile"), A_SYMBOL, A_SYMBOL, 0);
1439 class_addmethod(canvas_class, (t_method)canvas_saveto,
1440 gensym("saveto"), A_CANT, 0);
1441/* ------------------ from the menu ------------------------- */
1442 class_addmethod(canvas_class, (t_method)canvas_menusave,
1443 gensym("menusave"), 0);
1444 class_addmethod(canvas_class, (t_method)canvas_menusaveas,
1445 gensym("menusaveas"), 0);
1446}
diff --git a/apps/plugins/pdbox/PDa/src/g_rtext.c b/apps/plugins/pdbox/PDa/src/g_rtext.c
new file mode 100644
index 0000000000..8ffc8f415b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_rtext.c
@@ -0,0 +1,972 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
6/* have to insert gui-objects into editor-list */
7/* all changes are labeled with iemlib */
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <ctype.h>
13#include "m_pd.h"
14#include "s_stuff.h"
15#include "g_canvas.h"
16#include "t_tk.h"
17
18#define LMARGIN 1
19#define RMARGIN 1
20#define TMARGIN 2
21#define BMARGIN 2
22
23#define SEND_FIRST 1
24#define SEND_UPDATE 2
25#define SEND_CHECK 0
26
27struct _rtext
28{
29 char *x_buf;
30 int x_bufsize;
31 int x_selstart;
32 int x_selend;
33 int x_active;
34 int x_dragfrom;
35 int x_height;
36 int x_drawnwidth;
37 int x_drawnheight;
38 t_text *x_text;
39 t_glist *x_glist;
40 char x_tag[50];
41 struct _rtext *x_next;
42};
43
44t_rtext *rtext_new(t_glist *glist, t_text *who)
45{
46 t_rtext *x = (t_rtext *)getbytes(sizeof *x);
47 int w = 0, h = 0, indx;
48 x->x_height = -1;
49 x->x_text = who;
50 x->x_glist = glist;
51 x->x_next = glist->gl_editor->e_rtext;
52 x->x_selstart = x->x_selend = x->x_active =
53 x->x_drawnwidth = x->x_drawnheight = 0;
54 binbuf_gettext(who->te_binbuf, &x->x_buf, &x->x_bufsize);
55 glist->gl_editor->e_rtext = x;
56 sprintf(x->x_tag, ".x%x.t%x", (t_int)glist_getcanvas(x->x_glist),
57 (t_int)x);
58 return (x);
59}
60
61static t_rtext *rtext_entered;
62
63void rtext_free(t_rtext *x)
64{
65 if (x->x_glist->gl_editor->e_textedfor == x)
66 x->x_glist->gl_editor->e_textedfor = 0;
67 if (x->x_glist->gl_editor->e_rtext == x)
68 x->x_glist->gl_editor->e_rtext = x->x_next;
69 else
70 {
71 t_rtext *e2;
72 for (e2 = x->x_glist->gl_editor->e_rtext; e2; e2 = e2->x_next)
73 if (e2->x_next == x)
74 {
75 e2->x_next = x->x_next;
76 break;
77 }
78 }
79 if (rtext_entered == x) rtext_entered = 0;
80 freebytes(x->x_buf, x->x_bufsize);
81 freebytes(x, sizeof *x);
82}
83
84char *rtext_gettag(t_rtext *x)
85{
86 return (x->x_tag);
87}
88
89void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
90{
91 *buf = x->x_buf;
92 *bufsize = x->x_bufsize;
93}
94
95
96/* LATER deal with tcl-significant characters */
97
98static int firstone(char *s, int c, int n)
99{
100 char *s2 = s + n;
101 int i = 0;
102 while (s != s2)
103 {
104 if (*s == c) return (i);
105 i++;
106 s++;
107 }
108 return (-1);
109}
110
111static int lastone(char *s, int c, int n)
112{
113 char *s2 = s + n;
114 while (s2 != s)
115 {
116 s2--;
117 n--;
118 if (*s2 == c) return (n);
119 }
120 return (-1);
121}
122
123 /* the following routine computes line breaks and carries out
124 some action which could be:
125 SEND_FIRST - draw the box for the first time
126 SEND_UPDATE - redraw the updated box
127 otherwise - don't draw, just calculate.
128 Called with *widthp and *heightpas coordinates of
129 a test point, the routine reports the index of the character found
130 there in *indexp. *widthp and *heightp are set to the width and height
131 of the entire text in pixels.
132 */
133
134 /* LATER get this and sys_vgui to work together properly,
135 breaking up messages as needed. As of now, there's
136 a limit of 1950 characters, imposed by sys_vgui(). */
137#define UPBUFSIZE 4000
138#define BOXWIDTH 60
139
140/* Older (pre-8.3.4) TCL versions handle text selection differently; this
141flag is set from the GUI if this happens. LATER take this out: early 2006? */
142
143extern int sys_oldtclversion;
144
145static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
146 int *indexp)
147{
148 float dispx, dispy;
149 char tempbuf[UPBUFSIZE], *tp = tempbuf, *bp = x->x_buf;
150 int outchars, inchars = x->x_bufsize, nlines = 0, ncolumns = 0,
151 pixwide, pixhigh;
152 int font = glist_getfont(x->x_glist);
153 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
154 int findx = (*widthp + (fontwidth/2)) / fontwidth,
155 findy = *heightp / fontheight;
156 int reportedindex = 0;
157 t_canvas *canvas = glist_getcanvas(x->x_glist);
158 int widthspec = x->x_text->te_width;
159 int widthlimit = (widthspec ? widthspec : BOXWIDTH);
160 while (inchars)
161 {
162 int maxindex = (inchars > widthlimit ? widthlimit : inchars);
163 int eatchar = 1;
164 int foundit = firstone(bp, '\n', maxindex);
165 if (foundit < 0)
166 {
167 if (inchars > widthlimit)
168 {
169 foundit = lastone(bp, ' ', maxindex);
170 if (foundit < 0)
171 {
172 foundit = maxindex;
173 eatchar = 0;
174 }
175 }
176 else
177 {
178 foundit = inchars;
179 eatchar = 0;
180 }
181 }
182 if (nlines == findy)
183 {
184 int actualx = (findx < 0 ? 0 :
185 (findx > foundit ? foundit : findx));
186 *indexp = (bp - x->x_buf) + actualx;
187 reportedindex = 1;
188 }
189 strncpy(tp, bp, foundit);
190 tp += foundit;
191 bp += (foundit + eatchar);
192 inchars -= (foundit + eatchar);
193 if (inchars) *tp++ = '\n';
194 if (foundit > ncolumns) ncolumns = foundit;
195 nlines++;
196 }
197 outchars = tp - tempbuf;
198 if (outchars > 1950) outchars = 1950;
199 if (!reportedindex)
200 *indexp = outchars;
201 dispx = text_xpix(x->x_text, x->x_glist);
202 dispy = text_ypix(x->x_text, x->x_glist);
203 if (nlines < 1) nlines = 1;
204 if (!widthspec)
205 {
206 while (ncolumns < 3)
207 {
208 tempbuf[outchars++] = ' ';
209 ncolumns++;
210 }
211 }
212 else ncolumns = widthspec;
213 pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN);
214 pixhigh = nlines * fontheight + (TMARGIN + BMARGIN);
215
216 if (action == SEND_FIRST)
217 sys_vgui("pdtk_text_new .x%x.c %s %f %f {%.*s} %d %s\n",
218 canvas, x->x_tag,
219 dispx + LMARGIN, dispy + TMARGIN,
220 outchars, tempbuf, sys_hostfontsize(font),
221 (glist_isselected(x->x_glist,
222 &x->x_glist->gl_gobj)? "blue" : "black"));
223 else if (action == SEND_UPDATE)
224 {
225 sys_vgui("pdtk_text_set .x%x.c %s {%.*s}\n",
226 canvas, x->x_tag, outchars, tempbuf);
227 if (pixwide != x->x_drawnwidth || pixhigh != x->x_drawnheight)
228 text_drawborder(x->x_text, x->x_glist, x->x_tag,
229 pixwide, pixhigh, 0);
230 if (x->x_active)
231 {
232 if (x->x_selend > x->x_selstart)
233 {
234 sys_vgui(".x%x.c select from %s %d\n", canvas,
235 x->x_tag, x->x_selstart);
236 sys_vgui(".x%x.c select to %s %d\n", canvas,
237 x->x_tag, x->x_selend + (sys_oldtclversion ? 0 : -1));
238 sys_vgui(".x%x.c focus \"\"\n", canvas);
239 }
240 else
241 {
242 sys_vgui(".x%x.c select clear\n", canvas);
243 sys_vgui(".x%x.c icursor %s %d\n", canvas, x->x_tag,
244 x->x_selstart);
245 sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
246 }
247 }
248 }
249 x->x_drawnwidth = pixwide;
250 x->x_drawnheight = pixhigh;
251
252 *widthp = pixwide;
253 *heightp = pixhigh;
254}
255
256void rtext_retext(t_rtext *x)
257{
258 int w = 0, h = 0, indx;
259 t_text *text = x->x_text;
260 t_freebytes(x->x_buf, x->x_bufsize);
261 binbuf_gettext(text->te_binbuf, &x->x_buf, &x->x_bufsize);
262 /* special case: for number boxes, try to pare the number down
263 to the specified width of the box. */
264 if (text->te_width > 0 && text->te_type == T_ATOM &&
265 x->x_bufsize > text->te_width)
266 {
267 t_atom *atomp = binbuf_getvec(text->te_binbuf);
268 int natom = binbuf_getnatom(text->te_binbuf);
269 int bufsize = x->x_bufsize;
270 if (natom == 1 && atomp->a_type == A_FLOAT)
271 {
272 /* try to reduce size by dropping decimal digits */
273 int wantreduce = bufsize - text->te_width;
274 char *decimal = 0, *nextchar, *ebuf = x->x_buf + bufsize,
275 *s1, *s2;
276 int ndecimals;
277 for (decimal = x->x_buf; decimal < ebuf; decimal++)
278 if (*decimal == '.')
279 break;
280 if (decimal >= ebuf)
281 goto giveup;
282 for (nextchar = decimal + 1; nextchar < ebuf; nextchar++)
283 if (*nextchar < '0' || *nextchar > '9')
284 break;
285 if (nextchar - decimal - 1 < wantreduce)
286 goto giveup;
287 for (s1 = nextchar - wantreduce, s2 = s1 + wantreduce;
288 s2 < ebuf; s1++, s2++)
289 *s1 = *s2;
290 t_resizebytes(x->x_buf, bufsize, text->te_width);
291 bufsize = text->te_width;
292 goto done;
293 giveup:
294 /* give up and bash it to "+" or "-" */
295 x->x_buf[0] = (atomp->a_w.w_float < 0 ? '-' : '+');
296 t_resizebytes(x->x_buf, bufsize, 1);
297 bufsize = 1;
298 }
299 else if (bufsize > text->te_width)
300 {
301 x->x_buf[text->te_width - 1] = '>';
302 t_resizebytes(x->x_buf, bufsize, text->te_width);
303 bufsize = text->te_width;
304 }
305 done:
306 x->x_bufsize = bufsize;
307 }
308 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
309}
310
311/* find the rtext that goes with a text item */
312t_rtext *glist_findrtext(t_glist *gl, t_text *who)
313{
314 t_rtext *x = gl->gl_editor->e_rtext;
315 while (x && x->x_text != who) x = x->x_next;
316 if (!x) bug("glist_findrtext");
317 return (x);
318}
319
320int rtext_width(t_rtext *x)
321{
322 int w = 0, h = 0, indx;
323 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
324 return (w);
325}
326
327int rtext_height(t_rtext *x)
328{
329 int w = 0, h = 0, indx;
330 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
331 return (h);
332}
333
334void rtext_draw(t_rtext *x)
335{
336 int w = 0, h = 0, indx;
337 rtext_senditup(x, SEND_FIRST, &w, &h, &indx);
338}
339
340void rtext_erase(t_rtext *x)
341{
342 sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag);
343}
344
345void rtext_displace(t_rtext *x, int dx, int dy)
346{
347 sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist),
348 x->x_tag, dx, dy);
349}
350
351void rtext_select(t_rtext *x, int state)
352{
353 t_glist *glist = x->x_glist;
354 t_canvas *canvas = glist_getcanvas(glist);
355 sys_vgui(".x%x.c itemconfigure %s -fill %s\n", canvas,
356 x->x_tag, (state? "blue" : "black"));
357 canvas_editing = canvas;
358}
359
360void rtext_activate(t_rtext *x, int state)
361{
362 int w = 0, h = 0, indx;
363 t_glist *glist = x->x_glist;
364 t_canvas *canvas = glist_getcanvas(glist);
365 if (state)
366 {
367 sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
368 glist->gl_editor->e_textedfor = x;
369 glist->gl_editor->e_textdirty = 0;
370 x->x_dragfrom = x->x_selstart = 0;
371 x->x_selend = x->x_bufsize;
372 x->x_active = 1;
373 }
374 else
375 {
376 sys_vgui("selection clear .x%x.c\n", canvas);
377 sys_vgui(".x%x.c focus \"\"\n", canvas);
378 if (glist->gl_editor->e_textedfor == x)
379 glist->gl_editor->e_textedfor = 0;
380 x->x_active = 0;
381 }
382 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
383}
384
385void rtext_key(t_rtext *x, int keynum, t_symbol *keysym)
386{
387 int w = 0, h = 0, indx, i, newsize, ndel;
388 char *s1, *s2;
389 if (keynum)
390 {
391 int n = keynum;
392 if (n == '\r') n = '\n';
393 if (n == '\b') /* backspace */
394 {
395 /* LATER delete the box if all text is selected...
396 this causes reentrancy problems now. */
397 /* if ((!x->x_selstart) && (x->x_selend == x->x_bufsize))
398 {
399 ....
400 } */
401 if (x->x_selstart && (x->x_selstart == x->x_selend))
402 x->x_selstart--;
403 }
404 else if (n == 127) /* delete */
405 {
406 if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend))
407 x->x_selend++;
408 }
409
410 ndel = x->x_selend - x->x_selstart;
411 for (i = x->x_selend; i < x->x_bufsize; i++)
412 x->x_buf[i- ndel] = x->x_buf[i];
413 newsize = x->x_bufsize - ndel;
414 x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
415 x->x_bufsize = newsize;
416
417 if (n == '\n' || isprint(n))
418 {
419 newsize = x->x_bufsize+1;
420 x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
421 for (i = x->x_bufsize; i > x->x_selstart; i--)
422 x->x_buf[i] = x->x_buf[i-1];
423 x->x_buf[x->x_selstart] = n;
424 x->x_bufsize = newsize;
425 x->x_selstart = x->x_selstart + 1;
426 }
427 x->x_selend = x->x_selstart;
428 x->x_glist->gl_editor->e_textdirty = 1;
429 }
430 else if (!strcmp(keysym->s_name, "Right"))
431 {
432 if (x->x_selend == x->x_selstart && x->x_selstart < x->x_bufsize)
433 x->x_selend = x->x_selstart = x->x_selstart + 1;
434 else
435 x->x_selstart = x->x_selend;
436 }
437 else if (!strcmp(keysym->s_name, "Left"))
438 {
439 if (x->x_selend == x->x_selstart && x->x_selstart > 0)
440 x->x_selend = x->x_selstart = x->x_selstart - 1;
441 else
442 x->x_selend = x->x_selstart;
443 }
444 /* this should be improved... life's too short */
445 else if (!strcmp(keysym->s_name, "Up"))
446 {
447 if (x->x_selstart)
448 x->x_selstart--;
449 while (x->x_selstart > 0 && x->x_buf[x->x_selstart] != '\n')
450 x->x_selstart--;
451 x->x_selend = x->x_selstart;
452 }
453 else if (!strcmp(keysym->s_name, "Down"))
454 {
455 while (x->x_selend < x->x_bufsize &&
456 x->x_buf[x->x_selend] != '\n')
457 x->x_selend++;
458 if (x->x_selend < x->x_bufsize)
459 x->x_selend++;
460 x->x_selstart = x->x_selend;
461 }
462 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
463}
464
465void rtext_mouse(t_rtext *x, int xval, int yval, int flag)
466{
467 int w = xval, h = yval, indx;
468 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
469 if (flag == RTEXT_DOWN)
470 {
471 x->x_dragfrom = x->x_selstart = x->x_selend = indx;
472 }
473 else if (flag == RTEXT_SHIFT)
474 {
475 if (indx * 2 > x->x_selstart + x->x_selend)
476 x->x_dragfrom = x->x_selstart, x->x_selend = indx;
477 else
478 x->x_dragfrom = x->x_selend, x->x_selstart = indx;
479 }
480 else if (flag == RTEXT_DRAG)
481 {
482 x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx);
483 x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx);
484 }
485 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
486}
487/* Copyright (c) 1997-1999 Miller Puckette.
488* For information on usage and redistribution, and for a DISCLAIMER OF ALL
489* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
490
491/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
492/* have to insert gui-objects into editor-list */
493/* all changes are labeled with iemlib */
494
495#include <stdlib.h>
496#include <string.h>
497#include <stdio.h>
498#include <ctype.h>
499#include "m_pd.h"
500#include "s_stuff.h"
501#include "g_canvas.h"
502#include "t_tk.h"
503
504#define LMARGIN 1
505#define RMARGIN 1
506#define TMARGIN 2
507#define BMARGIN 2
508
509#define SEND_FIRST 1
510#define SEND_UPDATE 2
511#define SEND_CHECK 0
512
513struct _rtext
514{
515 char *x_buf;
516 int x_bufsize;
517 int x_selstart;
518 int x_selend;
519 int x_active;
520 int x_dragfrom;
521 int x_height;
522 int x_drawnwidth;
523 int x_drawnheight;
524 t_text *x_text;
525 t_glist *x_glist;
526 char x_tag[50];
527 struct _rtext *x_next;
528};
529
530t_rtext *rtext_new(t_glist *glist, t_text *who)
531{
532 t_rtext *x = (t_rtext *)getbytes(sizeof *x);
533 int w = 0, h = 0, indx;
534 x->x_height = -1;
535 x->x_text = who;
536 x->x_glist = glist;
537 x->x_next = glist->gl_editor->e_rtext;
538 x->x_selstart = x->x_selend = x->x_active =
539 x->x_drawnwidth = x->x_drawnheight = 0;
540 binbuf_gettext(who->te_binbuf, &x->x_buf, &x->x_bufsize);
541 glist->gl_editor->e_rtext = x;
542 sprintf(x->x_tag, ".x%x.t%x", (t_int)glist_getcanvas(x->x_glist),
543 (t_int)x);
544 return (x);
545}
546
547static t_rtext *rtext_entered;
548
549void rtext_free(t_rtext *x)
550{
551 if (x->x_glist->gl_editor->e_textedfor == x)
552 x->x_glist->gl_editor->e_textedfor = 0;
553 if (x->x_glist->gl_editor->e_rtext == x)
554 x->x_glist->gl_editor->e_rtext = x->x_next;
555 else
556 {
557 t_rtext *e2;
558 for (e2 = x->x_glist->gl_editor->e_rtext; e2; e2 = e2->x_next)
559 if (e2->x_next == x)
560 {
561 e2->x_next = x->x_next;
562 break;
563 }
564 }
565 if (rtext_entered == x) rtext_entered = 0;
566 freebytes(x->x_buf, x->x_bufsize);
567 freebytes(x, sizeof *x);
568}
569
570char *rtext_gettag(t_rtext *x)
571{
572 return (x->x_tag);
573}
574
575void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
576{
577 *buf = x->x_buf;
578 *bufsize = x->x_bufsize;
579}
580
581
582/* LATER deal with tcl-significant characters */
583
584static int firstone(char *s, int c, int n)
585{
586 char *s2 = s + n;
587 int i = 0;
588 while (s != s2)
589 {
590 if (*s == c) return (i);
591 i++;
592 s++;
593 }
594 return (-1);
595}
596
597static int lastone(char *s, int c, int n)
598{
599 char *s2 = s + n;
600 while (s2 != s)
601 {
602 s2--;
603 n--;
604 if (*s2 == c) return (n);
605 }
606 return (-1);
607}
608
609 /* the following routine computes line breaks and carries out
610 some action which could be:
611 SEND_FIRST - draw the box for the first time
612 SEND_UPDATE - redraw the updated box
613 otherwise - don't draw, just calculate.
614 Called with *widthp and *heightpas coordinates of
615 a test point, the routine reports the index of the character found
616 there in *indexp. *widthp and *heightp are set to the width and height
617 of the entire text in pixels.
618 */
619
620 /* LATER get this and sys_vgui to work together properly,
621 breaking up messages as needed. As of now, there's
622 a limit of 1950 characters, imposed by sys_vgui(). */
623#define UPBUFSIZE 4000
624#define BOXWIDTH 60
625
626/* Older (pre-8.3.4) TCL versions handle text selection differently; this
627flag is set from the GUI if this happens. LATER take this out: early 2006? */
628
629extern int sys_oldtclversion;
630
631static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
632 int *indexp)
633{
634 float dispx, dispy;
635 char tempbuf[UPBUFSIZE], *tp = tempbuf, *bp = x->x_buf;
636 int outchars, inchars = x->x_bufsize, nlines = 0, ncolumns = 0,
637 pixwide, pixhigh;
638 int font = glist_getfont(x->x_glist);
639 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
640 int findx = (*widthp + (fontwidth/2)) / fontwidth,
641 findy = *heightp / fontheight;
642 int reportedindex = 0;
643 t_canvas *canvas = glist_getcanvas(x->x_glist);
644 int widthspec = x->x_text->te_width;
645 int widthlimit = (widthspec ? widthspec : BOXWIDTH);
646 while (inchars)
647 {
648 int maxindex = (inchars > widthlimit ? widthlimit : inchars);
649 int eatchar = 1;
650 int foundit = firstone(bp, '\n', maxindex);
651 if (foundit < 0)
652 {
653 if (inchars > widthlimit)
654 {
655 foundit = lastone(bp, ' ', maxindex);
656 if (foundit < 0)
657 {
658 foundit = maxindex;
659 eatchar = 0;
660 }
661 }
662 else
663 {
664 foundit = inchars;
665 eatchar = 0;
666 }
667 }
668 if (nlines == findy)
669 {
670 int actualx = (findx < 0 ? 0 :
671 (findx > foundit ? foundit : findx));
672 *indexp = (bp - x->x_buf) + actualx;
673 reportedindex = 1;
674 }
675 strncpy(tp, bp, foundit);
676 tp += foundit;
677 bp += (foundit + eatchar);
678 inchars -= (foundit + eatchar);
679 if (inchars) *tp++ = '\n';
680 if (foundit > ncolumns) ncolumns = foundit;
681 nlines++;
682 }
683 outchars = tp - tempbuf;
684 if (outchars > 1950) outchars = 1950;
685 if (!reportedindex)
686 *indexp = outchars;
687 dispx = text_xpix(x->x_text, x->x_glist);
688 dispy = text_ypix(x->x_text, x->x_glist);
689 if (nlines < 1) nlines = 1;
690 if (!widthspec)
691 {
692 while (ncolumns < 3)
693 {
694 tempbuf[outchars++] = ' ';
695 ncolumns++;
696 }
697 }
698 else ncolumns = widthspec;
699 pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN);
700 pixhigh = nlines * fontheight + (TMARGIN + BMARGIN);
701
702 if (action == SEND_FIRST)
703 sys_vgui("pdtk_text_new .x%x.c %s %f %f {%.*s} %d %s\n",
704 canvas, x->x_tag,
705 dispx + LMARGIN, dispy + TMARGIN,
706 outchars, tempbuf, sys_hostfontsize(font),
707 (glist_isselected(x->x_glist,
708 &x->x_glist->gl_gobj)? "blue" : "black"));
709 else if (action == SEND_UPDATE)
710 {
711 sys_vgui("pdtk_text_set .x%x.c %s {%.*s}\n",
712 canvas, x->x_tag, outchars, tempbuf);
713 if (pixwide != x->x_drawnwidth || pixhigh != x->x_drawnheight)
714 text_drawborder(x->x_text, x->x_glist, x->x_tag,
715 pixwide, pixhigh, 0);
716 if (x->x_active)
717 {
718 if (x->x_selend > x->x_selstart)
719 {
720 sys_vgui(".x%x.c select from %s %d\n", canvas,
721 x->x_tag, x->x_selstart);
722 sys_vgui(".x%x.c select to %s %d\n", canvas,
723 x->x_tag, x->x_selend + (sys_oldtclversion ? 0 : -1));
724 sys_vgui(".x%x.c focus \"\"\n", canvas);
725 }
726 else
727 {
728 sys_vgui(".x%x.c select clear\n", canvas);
729 sys_vgui(".x%x.c icursor %s %d\n", canvas, x->x_tag,
730 x->x_selstart);
731 sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
732 }
733 }
734 }
735 x->x_drawnwidth = pixwide;
736 x->x_drawnheight = pixhigh;
737
738 *widthp = pixwide;
739 *heightp = pixhigh;
740}
741
742void rtext_retext(t_rtext *x)
743{
744 int w = 0, h = 0, indx;
745 t_text *text = x->x_text;
746 t_freebytes(x->x_buf, x->x_bufsize);
747 binbuf_gettext(text->te_binbuf, &x->x_buf, &x->x_bufsize);
748 /* special case: for number boxes, try to pare the number down
749 to the specified width of the box. */
750 if (text->te_width > 0 && text->te_type == T_ATOM &&
751 x->x_bufsize > text->te_width)
752 {
753 t_atom *atomp = binbuf_getvec(text->te_binbuf);
754 int natom = binbuf_getnatom(text->te_binbuf);
755 int bufsize = x->x_bufsize;
756 if (natom == 1 && atomp->a_type == A_FLOAT)
757 {
758 /* try to reduce size by dropping decimal digits */
759 int wantreduce = bufsize - text->te_width;
760 char *decimal = 0, *nextchar, *ebuf = x->x_buf + bufsize,
761 *s1, *s2;
762 int ndecimals;
763 for (decimal = x->x_buf; decimal < ebuf; decimal++)
764 if (*decimal == '.')
765 break;
766 if (decimal >= ebuf)
767 goto giveup;
768 for (nextchar = decimal + 1; nextchar < ebuf; nextchar++)
769 if (*nextchar < '0' || *nextchar > '9')
770 break;
771 if (nextchar - decimal - 1 < wantreduce)
772 goto giveup;
773 for (s1 = nextchar - wantreduce, s2 = s1 + wantreduce;
774 s2 < ebuf; s1++, s2++)
775 *s1 = *s2;
776 t_resizebytes(x->x_buf, bufsize, text->te_width);
777 bufsize = text->te_width;
778 goto done;
779 giveup:
780 /* give up and bash it to "+" or "-" */
781 x->x_buf[0] = (atomp->a_w.w_float < 0 ? '-' : '+');
782 t_resizebytes(x->x_buf, bufsize, 1);
783 bufsize = 1;
784 }
785 else if (bufsize > text->te_width)
786 {
787 x->x_buf[text->te_width - 1] = '>';
788 t_resizebytes(x->x_buf, bufsize, text->te_width);
789 bufsize = text->te_width;
790 }
791 done:
792 x->x_bufsize = bufsize;
793 }
794 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
795}
796
797/* find the rtext that goes with a text item */
798t_rtext *glist_findrtext(t_glist *gl, t_text *who)
799{
800 t_rtext *x = gl->gl_editor->e_rtext;
801 while (x && x->x_text != who) x = x->x_next;
802 if (!x) bug("glist_findrtext");
803 return (x);
804}
805
806int rtext_width(t_rtext *x)
807{
808 int w = 0, h = 0, indx;
809 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
810 return (w);
811}
812
813int rtext_height(t_rtext *x)
814{
815 int w = 0, h = 0, indx;
816 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
817 return (h);
818}
819
820void rtext_draw(t_rtext *x)
821{
822 int w = 0, h = 0, indx;
823 rtext_senditup(x, SEND_FIRST, &w, &h, &indx);
824}
825
826void rtext_erase(t_rtext *x)
827{
828 sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag);
829}
830
831void rtext_displace(t_rtext *x, int dx, int dy)
832{
833 sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist),
834 x->x_tag, dx, dy);
835}
836
837void rtext_select(t_rtext *x, int state)
838{
839 t_glist *glist = x->x_glist;
840 t_canvas *canvas = glist_getcanvas(glist);
841 sys_vgui(".x%x.c itemconfigure %s -fill %s\n", canvas,
842 x->x_tag, (state? "blue" : "black"));
843 canvas_editing = canvas;
844}
845
846void rtext_activate(t_rtext *x, int state)
847{
848 int w = 0, h = 0, indx;
849 t_glist *glist = x->x_glist;
850 t_canvas *canvas = glist_getcanvas(glist);
851 if (state)
852 {
853 sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
854 glist->gl_editor->e_textedfor = x;
855 glist->gl_editor->e_textdirty = 0;
856 x->x_dragfrom = x->x_selstart = 0;
857 x->x_selend = x->x_bufsize;
858 x->x_active = 1;
859 }
860 else
861 {
862 sys_vgui("selection clear .x%x.c\n", canvas);
863 sys_vgui(".x%x.c focus \"\"\n", canvas);
864 if (glist->gl_editor->e_textedfor == x)
865 glist->gl_editor->e_textedfor = 0;
866 x->x_active = 0;
867 }
868 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
869}
870
871void rtext_key(t_rtext *x, int keynum, t_symbol *keysym)
872{
873 int w = 0, h = 0, indx, i, newsize, ndel;
874 char *s1, *s2;
875 if (keynum)
876 {
877 int n = keynum;
878 if (n == '\r') n = '\n';
879 if (n == '\b') /* backspace */
880 {
881 /* LATER delete the box if all text is selected...
882 this causes reentrancy problems now. */
883 /* if ((!x->x_selstart) && (x->x_selend == x->x_bufsize))
884 {
885 ....
886 } */
887 if (x->x_selstart && (x->x_selstart == x->x_selend))
888 x->x_selstart--;
889 }
890 else if (n == 127) /* delete */
891 {
892 if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend))
893 x->x_selend++;
894 }
895
896 ndel = x->x_selend - x->x_selstart;
897 for (i = x->x_selend; i < x->x_bufsize; i++)
898 x->x_buf[i- ndel] = x->x_buf[i];
899 newsize = x->x_bufsize - ndel;
900 x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
901 x->x_bufsize = newsize;
902
903 if (n == '\n' || isprint(n))
904 {
905 newsize = x->x_bufsize+1;
906 x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
907 for (i = x->x_bufsize; i > x->x_selstart; i--)
908 x->x_buf[i] = x->x_buf[i-1];
909 x->x_buf[x->x_selstart] = n;
910 x->x_bufsize = newsize;
911 x->x_selstart = x->x_selstart + 1;
912 }
913 x->x_selend = x->x_selstart;
914 x->x_glist->gl_editor->e_textdirty = 1;
915 }
916 else if (!strcmp(keysym->s_name, "Right"))
917 {
918 if (x->x_selend == x->x_selstart && x->x_selstart < x->x_bufsize)
919 x->x_selend = x->x_selstart = x->x_selstart + 1;
920 else
921 x->x_selstart = x->x_selend;
922 }
923 else if (!strcmp(keysym->s_name, "Left"))
924 {
925 if (x->x_selend == x->x_selstart && x->x_selstart > 0)
926 x->x_selend = x->x_selstart = x->x_selstart - 1;
927 else
928 x->x_selend = x->x_selstart;
929 }
930 /* this should be improved... life's too short */
931 else if (!strcmp(keysym->s_name, "Up"))
932 {
933 if (x->x_selstart)
934 x->x_selstart--;
935 while (x->x_selstart > 0 && x->x_buf[x->x_selstart] != '\n')
936 x->x_selstart--;
937 x->x_selend = x->x_selstart;
938 }
939 else if (!strcmp(keysym->s_name, "Down"))
940 {
941 while (x->x_selend < x->x_bufsize &&
942 x->x_buf[x->x_selend] != '\n')
943 x->x_selend++;
944 if (x->x_selend < x->x_bufsize)
945 x->x_selend++;
946 x->x_selstart = x->x_selend;
947 }
948 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
949}
950
951void rtext_mouse(t_rtext *x, int xval, int yval, int flag)
952{
953 int w = xval, h = yval, indx;
954 rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
955 if (flag == RTEXT_DOWN)
956 {
957 x->x_dragfrom = x->x_selstart = x->x_selend = indx;
958 }
959 else if (flag == RTEXT_SHIFT)
960 {
961 if (indx * 2 > x->x_selstart + x->x_selend)
962 x->x_dragfrom = x->x_selstart, x->x_selend = indx;
963 else
964 x->x_dragfrom = x->x_selend, x->x_selstart = indx;
965 }
966 else if (flag == RTEXT_DRAG)
967 {
968 x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx);
969 x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx);
970 }
971 rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
972}
diff --git a/apps/plugins/pdbox/PDa/src/g_scalar.c b/apps/plugins/pdbox/PDa/src/g_scalar.c
new file mode 100644
index 0000000000..b3c6d824fc
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_scalar.c
@@ -0,0 +1,802 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* This file defines the "scalar" object, which is not a text object, just a
6"gobj". Scalars have templates which describe their structures, which
7can contain numbers, sublists, and arrays.
8
9Also, the "tscalar" object, an ordinary text object that owns a single "scalar"
10and draws it on the parent. This is intended as a way that abstractions can
11control their appearances by adding stuff to draw.
12*/
13
14/* IOhannes :
15 * changed the canvas_restore, so that it might accept $args as well (like "pd $0_test")
16 * so you can make multiple & distinguishable templates
17 * 1511:forum::für::umläute:2001
18 * changes marked with IOhannes
19 * added Krzysztof Czajas fix to avoid crashing...
20 */
21
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h> /* for read/write to files */
25#include "m_pd.h"
26#include "g_canvas.h"
27
28t_class *scalar_class;
29
30void word_init(t_word *wp, t_template *template, t_gpointer *gp)
31{
32 int i, nitems = template->t_n;
33 t_dataslot *datatypes = template->t_vec;
34 for (i = 0; i < nitems; i++, datatypes++, wp++)
35 {
36 int type = datatypes->ds_type;
37 if (type == DT_FLOAT)
38 wp->w_float = 0;
39 else if (type == DT_SYMBOL)
40 wp->w_symbol = &s_symbol;
41 else if (type == DT_ARRAY)
42 {
43 wp->w_array = array_new(datatypes->ds_arraytemplate, gp);
44 }
45 else if (type == DT_LIST)
46 {
47 /* LATER test this and get it to work */
48 wp->w_list = canvas_new(0, 0, 0, 0);
49 }
50 }
51}
52
53void word_restore(t_word *wp, t_template *template,
54 int argc, t_atom *argv)
55{
56 int i, nitems = template->t_n;
57 t_dataslot *datatypes = template->t_vec;
58 for (i = 0; i < nitems; i++, datatypes++, wp++)
59 {
60 int type = datatypes->ds_type;
61 if (type == DT_FLOAT)
62 {
63 float f;
64 if (argc)
65 {
66 f = atom_getfloat(argv);
67 argv++, argc--;
68 }
69 else f = 0;
70 wp->w_float = f;
71 }
72 else if (type == DT_SYMBOL)
73 {
74 t_symbol *s;
75 if (argc)
76 {
77 s = atom_getsymbol(argv);
78 argv++, argc--;
79 }
80 else s = &s_;
81 wp->w_symbol = s;
82 }
83 }
84 if (argc)
85 post("warning: word_restore: extra arguments");
86}
87
88void word_free(t_word *wp, t_template *template)
89{
90 int i;
91 t_dataslot *dt;
92 for (dt = template->t_vec, i = 0; i < template->t_n; i++, dt++)
93 {
94 if (dt->ds_type == DT_ARRAY)
95 array_free(wp[i].w_array);
96 else if (dt->ds_type == DT_LIST)
97 canvas_free(wp[i].w_list);
98 }
99}
100
101 /* make a new scalar and add to the glist. We create a "gp" here which
102 will be used for array items to point back here. This gp doesn't do
103 reference counting or "validation" updates though; the parent won't go away
104 without the contained arrays going away too. The "gp" is copied out
105 by value in the word_init() routine so we can throw our copy away. */
106
107t_scalar *scalar_new(t_glist *owner, t_symbol *templatesym)
108{
109 t_scalar *x;
110 t_template *template;
111 t_gpointer gp;
112 gpointer_init(&gp);
113 template = template_findbyname(templatesym);
114 if (!template)
115 {
116 error("scalar: couldn't find template %s", templatesym->s_name);
117 return (0);
118 }
119 x = (t_scalar *)getbytes(sizeof(t_scalar) +
120 (template->t_n - 1) * sizeof(*x->sc_vec));
121 x->sc_gobj.g_pd = scalar_class;
122 x->sc_template = templatesym;
123 gpointer_setglist(&gp, owner, x);
124 word_init(x->sc_vec, template, &gp);
125 return (x);
126}
127
128 /* Pd method to create a new scalar, add it to a glist, and initialize
129 it from the message arguments. */
130
131int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
132 int *p_nextmsg, int selectit);
133
134void glist_scalar(t_glist *glist,
135 t_symbol *classname, t_int argc, t_atom *argv)
136{
137 t_symbol *templatesym =
138 canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
139 t_binbuf *b;
140 int natoms, nextmsg = 0;
141 t_atom *vec;
142 if (!template_findbyname(templatesym))
143 {
144 pd_error(glist, "%s: no such template",
145 atom_getsymbolarg(0, argc, argv)->s_name);
146 return;
147 }
148
149 b = binbuf_new();
150 binbuf_restore(b, argc, argv);
151 natoms = binbuf_getnatom(b);
152 vec = binbuf_getvec(b);
153
154 glist_readscalar(glist, natoms, vec, &nextmsg, 0);
155 binbuf_free(b);
156}
157
158/* -------------------- widget behavior for scalar ------------ */
159void scalar_getbasexy(t_scalar *x, float *basex, float *basey)
160{
161 t_template *template = template_findbyname(x->sc_template);
162 *basex = template_getfloat(template, gensym("x"), x->sc_vec, 0);
163 *basey = template_getfloat(template, gensym("y"), x->sc_vec, 0);
164}
165
166static void scalar_getrect(t_gobj *z, t_glist *owner,
167 int *xp1, int *yp1, int *xp2, int *yp2)
168{
169 t_scalar *x = (t_scalar *)z;
170 int hit = 0;
171 t_template *template = template_findbyname(x->sc_template);
172 t_canvas *templatecanvas = template_findcanvas(template);
173 int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
174 t_gobj *y;
175 float basex, basey;
176 scalar_getbasexy(x, &basex, &basey);
177 /* if someone deleted the template canvas, we're just a point */
178 if (!templatecanvas)
179 {
180 x1 = x2 = glist_xtopixels(owner, basex);
181 y1 = y2 = glist_ytopixels(owner, basey);
182 }
183 else
184 {
185 int hit = 0;
186 x1 = y1 = 0x7fffffff;
187 x2 = y2 = -0x7fffffff;
188 for (y = templatecanvas->gl_list; y; y = y->g_next)
189 {
190 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
191 int nx1, ny1, nx2, ny2;
192 if (!wb) continue;
193 (*wb->w_parentgetrectfn)(y, owner,
194 x->sc_vec, template, basex, basey,
195 &nx1, &ny1, &nx2, &ny2);
196 if (hit)
197 {
198 if (nx1 < x1) x1 = nx1;
199 if (ny1 < y1) y1 = ny1;
200 if (nx2 > x2) x2 = nx2;
201 if (ny2 > y2) y2 = ny2;
202 }
203 else x1 = nx1, y1 = ny1, x2 = nx2, y2 = ny2, hit = 1;
204 }
205 if (!hit) x1 = y1 = x2 = y2 = 0;
206 }
207 /* post("scalar x1 %d y1 %d x2 %d y2 %d", x1, y1, x2, y2); */
208 *xp1 = x1;
209 *yp1 = y1;
210 *xp2 = x2;
211 *yp2 = y2;
212}
213
214static void scalar_select(t_gobj *z, t_glist *owner, int state)
215{
216 t_scalar *x = (t_scalar *)z;
217 /* post("scalar_select %d", state); */
218 /* later */
219 if (state)
220 {
221 int x1, y1, x2, y2;
222 scalar_getrect(z, owner, &x1, &y1, &x2, &y2);
223 x1--; x2++; y1--; y2++;
224 sys_vgui(".x%x.c create line %d %d %d %d %d %d %d %d %d %d \
225 -width 0 -fill blue -tags select%x\n",
226 glist_getcanvas(owner), x1, y1, x1, y2, x2, y2, x2, y1, x1, y1,
227 x);
228 }
229 else sys_vgui(".x%x.c delete select%x\n", glist_getcanvas(owner), x);
230}
231
232static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy)
233{
234 t_scalar *x = (t_scalar *)z;
235 t_symbol *templatesym = x->sc_template;
236 t_template *template = template_findbyname(templatesym);
237 t_symbol *zz;
238 int xonset, yonset, xtype, ytype, gotx, goty;
239 if (!template)
240 {
241 error("scalar: couldn't find template %s", templatesym->s_name);
242 return;
243 }
244 gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz);
245 if (gotx && (xtype != DT_FLOAT))
246 gotx = 0;
247 goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz);
248 if (goty && (ytype != DT_FLOAT))
249 goty = 0;
250 if (gotx)
251 *(t_float *)(((char *)(x->sc_vec)) + xonset) +=
252 dx * (glist_pixelstox(glist, 1) - glist_pixelstox(glist, 0));
253 if (goty)
254 *(t_float *)(((char *)(x->sc_vec)) + yonset) +=
255 dy * (glist_pixelstoy(glist, 1) - glist_pixelstoy(glist, 0));
256 glist_redrawitem(glist, z);
257 if (glist_isselected(glist, z))
258 {
259 scalar_select(z, glist, 0);
260 scalar_select(z, glist, 1);
261 }
262}
263
264static void scalar_activate(t_gobj *z, t_glist *owner, int state)
265{
266 /* post("scalar_activate %d", state); */
267 /* later */
268}
269
270static void scalar_delete(t_gobj *z, t_glist *glist)
271{
272 /* nothing to do */
273}
274
275static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
276{
277 t_scalar *x = (t_scalar *)z;
278 t_template *template = template_findbyname(x->sc_template);
279 t_canvas *templatecanvas = template_findcanvas(template);
280 t_gobj *y;
281 float basex, basey;
282 scalar_getbasexy(x, &basex, &basey);
283 /* if we don't know how to draw it, make a small rectangle */
284 if (!templatecanvas)
285 {
286 if (vis)
287 {
288 int x1 = glist_xtopixels(owner, basex);
289 int y1 = glist_ytopixels(owner, basey);
290 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags scalar%x\n",
291 glist_getcanvas(owner), x1-1, y1-1, x1+1, y1+1, x);
292 }
293 else sys_vgui(".x%x.c delete scalar%x\n", glist_getcanvas(owner), x);
294 return;
295 }
296
297 for (y = templatecanvas->gl_list; y; y = y->g_next)
298 {
299 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
300 if (!wb) continue;
301 (*wb->w_parentvisfn)(y, owner, x->sc_vec, template, basex, basey, vis);
302 }
303}
304
305static int scalar_click(t_gobj *z, struct _glist *owner,
306 int xpix, int ypix, int shift, int alt, int dbl, int doit)
307{
308 t_scalar *x = (t_scalar *)z;
309 int hit = 0;
310 t_template *template = template_findbyname(x->sc_template);
311 t_canvas *templatecanvas = template_findcanvas(template);
312 t_gobj *y;
313 float basex, basey;
314 scalar_getbasexy(x, &basex, &basey);
315 for (y = templatecanvas->gl_list; y; y = y->g_next)
316 {
317 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
318 if (!wb) continue;
319 if (hit = (*wb->w_parentclickfn)(y, owner,
320 x, template, basex, basey,
321 xpix, ypix, shift, alt, dbl, doit))
322 return (hit);
323 }
324 return (0);
325}
326
327void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b,
328 int amarrayelement);
329
330static void scalar_save(t_gobj *z, t_binbuf *b)
331{
332 t_scalar *x = (t_scalar *)z;
333 t_binbuf *b2 = binbuf_new();
334 t_atom a, *argv;
335 int i, argc;
336 canvas_writescalar(x->sc_template, x->sc_vec, b2, 0);
337 binbuf_addv(b, "ss", &s__X, gensym("scalar"));
338 binbuf_addbinbuf(b, b2);
339 binbuf_addsemi(b);
340 binbuf_free(b2);
341}
342
343static void scalar_properties(t_gobj *z, struct _glist *owner)
344{
345 t_scalar *x = (t_scalar *)z;
346 char *buf, buf2[80];
347 int bufsize;
348 t_binbuf *b;
349 glist_noselect(owner);
350 glist_select(owner, z);
351 b = glist_writetobinbuf(owner, 0);
352 binbuf_gettext(b, &buf, &bufsize);
353 binbuf_free(b);
354 buf = t_resizebytes(buf, bufsize, bufsize+1);
355 buf[bufsize] = 0;
356 sprintf(buf2, "pdtk_data_dialog %%s {");
357 gfxstub_new((t_pd *)owner, x, buf2);
358 sys_gui(buf);
359 sys_gui("}\n");
360 t_freebytes(buf, bufsize+1);
361}
362
363static t_widgetbehavior scalar_widgetbehavior =
364{
365 scalar_getrect,
366 scalar_displace,
367 scalar_select,
368 scalar_activate,
369 scalar_delete,
370 scalar_vis,
371 scalar_click,
372};
373
374static void scalar_free(t_scalar *x)
375{
376 int i;
377 t_dataslot *datatypes, *dt;
378 t_symbol *templatesym = x->sc_template;
379 t_template *template = template_findbyname(templatesym);
380 if (!template)
381 {
382 error("scalar: couldn't find template %s", templatesym->s_name);
383 return;
384 }
385 word_free(x->sc_vec, template);
386 gfxstub_deleteforkey(x);
387 /* the "size" field in the class is zero, so Pd doesn't try to free
388 us automatically (see pd_free()) */
389 freebytes(x, sizeof(t_scalar) + (template->t_n - 1) * sizeof(*x->sc_vec));
390}
391
392/* ----------------- setup function ------------------- */
393
394void g_scalar_setup(void)
395{
396 scalar_class = class_new(gensym("scalar"), 0, (t_method)scalar_free, 0,
397 CLASS_GOBJ, 0);
398 class_setwidget(scalar_class, &scalar_widgetbehavior);
399 class_setsavefn(scalar_class, scalar_save);
400 class_setpropertiesfn(scalar_class, scalar_properties);
401}
402/* Copyright (c) 1997-1999 Miller Puckette.
403* For information on usage and redistribution, and for a DISCLAIMER OF ALL
404* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
405
406/* This file defines the "scalar" object, which is not a text object, just a
407"gobj". Scalars have templates which describe their structures, which
408can contain numbers, sublists, and arrays.
409
410Also, the "tscalar" object, an ordinary text object that owns a single "scalar"
411and draws it on the parent. This is intended as a way that abstractions can
412control their appearances by adding stuff to draw.
413*/
414
415/* IOhannes :
416 * changed the canvas_restore, so that it might accept $args as well (like "pd $0_test")
417 * so you can make multiple & distinguishable templates
418 * 1511:forum::für::umläute:2001
419 * changes marked with IOhannes
420 * added Krzysztof Czajas fix to avoid crashing...
421 */
422
423#include <stdlib.h>
424#include <string.h>
425#include <stdio.h> /* for read/write to files */
426#include "m_pd.h"
427#include "g_canvas.h"
428
429t_class *scalar_class;
430
431void word_init(t_word *wp, t_template *template, t_gpointer *gp)
432{
433 int i, nitems = template->t_n;
434 t_dataslot *datatypes = template->t_vec;
435 for (i = 0; i < nitems; i++, datatypes++, wp++)
436 {
437 int type = datatypes->ds_type;
438 if (type == DT_FLOAT)
439 wp->w_float = 0;
440 else if (type == DT_SYMBOL)
441 wp->w_symbol = &s_symbol;
442 else if (type == DT_ARRAY)
443 {
444 wp->w_array = array_new(datatypes->ds_arraytemplate, gp);
445 }
446 else if (type == DT_LIST)
447 {
448 /* LATER test this and get it to work */
449 wp->w_list = canvas_new(0, 0, 0, 0);
450 }
451 }
452}
453
454void word_restore(t_word *wp, t_template *template,
455 int argc, t_atom *argv)
456{
457 int i, nitems = template->t_n;
458 t_dataslot *datatypes = template->t_vec;
459 for (i = 0; i < nitems; i++, datatypes++, wp++)
460 {
461 int type = datatypes->ds_type;
462 if (type == DT_FLOAT)
463 {
464 float f;
465 if (argc)
466 {
467 f = atom_getfloat(argv);
468 argv++, argc--;
469 }
470 else f = 0;
471 wp->w_float = f;
472 }
473 else if (type == DT_SYMBOL)
474 {
475 t_symbol *s;
476 if (argc)
477 {
478 s = atom_getsymbol(argv);
479 argv++, argc--;
480 }
481 else s = &s_;
482 wp->w_symbol = s;
483 }
484 }
485 if (argc)
486 post("warning: word_restore: extra arguments");
487}
488
489void word_free(t_word *wp, t_template *template)
490{
491 int i;
492 t_dataslot *dt;
493 for (dt = template->t_vec, i = 0; i < template->t_n; i++, dt++)
494 {
495 if (dt->ds_type == DT_ARRAY)
496 array_free(wp[i].w_array);
497 else if (dt->ds_type == DT_LIST)
498 canvas_free(wp[i].w_list);
499 }
500}
501
502 /* make a new scalar and add to the glist. We create a "gp" here which
503 will be used for array items to point back here. This gp doesn't do
504 reference counting or "validation" updates though; the parent won't go away
505 without the contained arrays going away too. The "gp" is copied out
506 by value in the word_init() routine so we can throw our copy away. */
507
508t_scalar *scalar_new(t_glist *owner, t_symbol *templatesym)
509{
510 t_scalar *x;
511 t_template *template;
512 t_gpointer gp;
513 gpointer_init(&gp);
514 template = template_findbyname(templatesym);
515 if (!template)
516 {
517 error("scalar: couldn't find template %s", templatesym->s_name);
518 return (0);
519 }
520 x = (t_scalar *)getbytes(sizeof(t_scalar) +
521 (template->t_n - 1) * sizeof(*x->sc_vec));
522 x->sc_gobj.g_pd = scalar_class;
523 x->sc_template = templatesym;
524 gpointer_setglist(&gp, owner, x);
525 word_init(x->sc_vec, template, &gp);
526 return (x);
527}
528
529 /* Pd method to create a new scalar, add it to a glist, and initialize
530 it from the message arguments. */
531
532int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
533 int *p_nextmsg, int selectit);
534
535void glist_scalar(t_glist *glist,
536 t_symbol *classname, t_int argc, t_atom *argv)
537{
538 t_symbol *templatesym =
539 canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
540 t_binbuf *b;
541 int natoms, nextmsg = 0;
542 t_atom *vec;
543 if (!template_findbyname(templatesym))
544 {
545 pd_error(glist, "%s: no such template",
546 atom_getsymbolarg(0, argc, argv)->s_name);
547 return;
548 }
549
550 b = binbuf_new();
551 binbuf_restore(b, argc, argv);
552 natoms = binbuf_getnatom(b);
553 vec = binbuf_getvec(b);
554
555 glist_readscalar(glist, natoms, vec, &nextmsg, 0);
556 binbuf_free(b);
557}
558
559/* -------------------- widget behavior for scalar ------------ */
560void scalar_getbasexy(t_scalar *x, float *basex, float *basey)
561{
562 t_template *template = template_findbyname(x->sc_template);
563 *basex = template_getfloat(template, gensym("x"), x->sc_vec, 0);
564 *basey = template_getfloat(template, gensym("y"), x->sc_vec, 0);
565}
566
567static void scalar_getrect(t_gobj *z, t_glist *owner,
568 int *xp1, int *yp1, int *xp2, int *yp2)
569{
570 t_scalar *x = (t_scalar *)z;
571 int hit = 0;
572 t_template *template = template_findbyname(x->sc_template);
573 t_canvas *templatecanvas = template_findcanvas(template);
574 int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
575 t_gobj *y;
576 float basex, basey;
577 scalar_getbasexy(x, &basex, &basey);
578 /* if someone deleted the template canvas, we're just a point */
579 if (!templatecanvas)
580 {
581 x1 = x2 = glist_xtopixels(owner, basex);
582 y1 = y2 = glist_ytopixels(owner, basey);
583 }
584 else
585 {
586 int hit = 0;
587 x1 = y1 = 0x7fffffff;
588 x2 = y2 = -0x7fffffff;
589 for (y = templatecanvas->gl_list; y; y = y->g_next)
590 {
591 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
592 int nx1, ny1, nx2, ny2;
593 if (!wb) continue;
594 (*wb->w_parentgetrectfn)(y, owner,
595 x->sc_vec, template, basex, basey,
596 &nx1, &ny1, &nx2, &ny2);
597 if (hit)
598 {
599 if (nx1 < x1) x1 = nx1;
600 if (ny1 < y1) y1 = ny1;
601 if (nx2 > x2) x2 = nx2;
602 if (ny2 > y2) y2 = ny2;
603 }
604 else x1 = nx1, y1 = ny1, x2 = nx2, y2 = ny2, hit = 1;
605 }
606 if (!hit) x1 = y1 = x2 = y2 = 0;
607 }
608 /* post("scalar x1 %d y1 %d x2 %d y2 %d", x1, y1, x2, y2); */
609 *xp1 = x1;
610 *yp1 = y1;
611 *xp2 = x2;
612 *yp2 = y2;
613}
614
615static void scalar_select(t_gobj *z, t_glist *owner, int state)
616{
617 t_scalar *x = (t_scalar *)z;
618 /* post("scalar_select %d", state); */
619 /* later */
620 if (state)
621 {
622 int x1, y1, x2, y2;
623 scalar_getrect(z, owner, &x1, &y1, &x2, &y2);
624 x1--; x2++; y1--; y2++;
625 sys_vgui(".x%x.c create line %d %d %d %d %d %d %d %d %d %d \
626 -width 0 -fill blue -tags select%x\n",
627 glist_getcanvas(owner), x1, y1, x1, y2, x2, y2, x2, y1, x1, y1,
628 x);
629 }
630 else sys_vgui(".x%x.c delete select%x\n", glist_getcanvas(owner), x);
631}
632
633static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy)
634{
635 t_scalar *x = (t_scalar *)z;
636 t_symbol *templatesym = x->sc_template;
637 t_template *template = template_findbyname(templatesym);
638 t_symbol *zz;
639 int xonset, yonset, xtype, ytype, gotx, goty;
640 if (!template)
641 {
642 error("scalar: couldn't find template %s", templatesym->s_name);
643 return;
644 }
645 gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz);
646 if (gotx && (xtype != DT_FLOAT))
647 gotx = 0;
648 goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz);
649 if (goty && (ytype != DT_FLOAT))
650 goty = 0;
651 if (gotx)
652 *(t_float *)(((char *)(x->sc_vec)) + xonset) +=
653 dx * (glist_pixelstox(glist, 1) - glist_pixelstox(glist, 0));
654 if (goty)
655 *(t_float *)(((char *)(x->sc_vec)) + yonset) +=
656 dy * (glist_pixelstoy(glist, 1) - glist_pixelstoy(glist, 0));
657 glist_redrawitem(glist, z);
658 if (glist_isselected(glist, z))
659 {
660 scalar_select(z, glist, 0);
661 scalar_select(z, glist, 1);
662 }
663}
664
665static void scalar_activate(t_gobj *z, t_glist *owner, int state)
666{
667 /* post("scalar_activate %d", state); */
668 /* later */
669}
670
671static void scalar_delete(t_gobj *z, t_glist *glist)
672{
673 /* nothing to do */
674}
675
676static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
677{
678 t_scalar *x = (t_scalar *)z;
679 t_template *template = template_findbyname(x->sc_template);
680 t_canvas *templatecanvas = template_findcanvas(template);
681 t_gobj *y;
682 float basex, basey;
683 scalar_getbasexy(x, &basex, &basey);
684 /* if we don't know how to draw it, make a small rectangle */
685 if (!templatecanvas)
686 {
687 if (vis)
688 {
689 int x1 = glist_xtopixels(owner, basex);
690 int y1 = glist_ytopixels(owner, basey);
691 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags scalar%x\n",
692 glist_getcanvas(owner), x1-1, y1-1, x1+1, y1+1, x);
693 }
694 else sys_vgui(".x%x.c delete scalar%x\n", glist_getcanvas(owner), x);
695 return;
696 }
697
698 for (y = templatecanvas->gl_list; y; y = y->g_next)
699 {
700 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
701 if (!wb) continue;
702 (*wb->w_parentvisfn)(y, owner, x->sc_vec, template, basex, basey, vis);
703 }
704}
705
706static int scalar_click(t_gobj *z, struct _glist *owner,
707 int xpix, int ypix, int shift, int alt, int dbl, int doit)
708{
709 t_scalar *x = (t_scalar *)z;
710 int hit = 0;
711 t_template *template = template_findbyname(x->sc_template);
712 t_canvas *templatecanvas = template_findcanvas(template);
713 t_gobj *y;
714 float basex, basey;
715 scalar_getbasexy(x, &basex, &basey);
716 for (y = templatecanvas->gl_list; y; y = y->g_next)
717 {
718 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
719 if (!wb) continue;
720 if (hit = (*wb->w_parentclickfn)(y, owner,
721 x, template, basex, basey,
722 xpix, ypix, shift, alt, dbl, doit))
723 return (hit);
724 }
725 return (0);
726}
727
728void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b,
729 int amarrayelement);
730
731static void scalar_save(t_gobj *z, t_binbuf *b)
732{
733 t_scalar *x = (t_scalar *)z;
734 t_binbuf *b2 = binbuf_new();
735 t_atom a, *argv;
736 int i, argc;
737 canvas_writescalar(x->sc_template, x->sc_vec, b2, 0);
738 binbuf_addv(b, "ss", &s__X, gensym("scalar"));
739 binbuf_addbinbuf(b, b2);
740 binbuf_addsemi(b);
741 binbuf_free(b2);
742}
743
744static void scalar_properties(t_gobj *z, struct _glist *owner)
745{
746 t_scalar *x = (t_scalar *)z;
747 char *buf, buf2[80];
748 int bufsize;
749 t_binbuf *b;
750 glist_noselect(owner);
751 glist_select(owner, z);
752 b = glist_writetobinbuf(owner, 0);
753 binbuf_gettext(b, &buf, &bufsize);
754 binbuf_free(b);
755 buf = t_resizebytes(buf, bufsize, bufsize+1);
756 buf[bufsize] = 0;
757 sprintf(buf2, "pdtk_data_dialog %%s {");
758 gfxstub_new((t_pd *)owner, x, buf2);
759 sys_gui(buf);
760 sys_gui("}\n");
761 t_freebytes(buf, bufsize+1);
762}
763
764static t_widgetbehavior scalar_widgetbehavior =
765{
766 scalar_getrect,
767 scalar_displace,
768 scalar_select,
769 scalar_activate,
770 scalar_delete,
771 scalar_vis,
772 scalar_click,
773};
774
775static void scalar_free(t_scalar *x)
776{
777 int i;
778 t_dataslot *datatypes, *dt;
779 t_symbol *templatesym = x->sc_template;
780 t_template *template = template_findbyname(templatesym);
781 if (!template)
782 {
783 error("scalar: couldn't find template %s", templatesym->s_name);
784 return;
785 }
786 word_free(x->sc_vec, template);
787 gfxstub_deleteforkey(x);
788 /* the "size" field in the class is zero, so Pd doesn't try to free
789 us automatically (see pd_free()) */
790 freebytes(x, sizeof(t_scalar) + (template->t_n - 1) * sizeof(*x->sc_vec));
791}
792
793/* ----------------- setup function ------------------- */
794
795void g_scalar_setup(void)
796{
797 scalar_class = class_new(gensym("scalar"), 0, (t_method)scalar_free, 0,
798 CLASS_GOBJ, 0);
799 class_setwidget(scalar_class, &scalar_widgetbehavior);
800 class_setsavefn(scalar_class, scalar_save);
801 class_setpropertiesfn(scalar_class, scalar_properties);
802}
diff --git a/apps/plugins/pdbox/PDa/src/g_template.c b/apps/plugins/pdbox/PDa/src/g_template.c
new file mode 100644
index 0000000000..c65613a0d6
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_template.c
@@ -0,0 +1,3358 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include <stdlib.h>
6#include <string.h>
7#include <stdio.h>
8
9#include "m_pd.h"
10#include "s_stuff.h" /* for sys_hostfontsize */
11#include "g_canvas.h"
12
13/*
14This file contains text objects you would put in a canvas to define a
15template. Templates describe objects of type "array" (g_array.c) and
16"scalar" (g_scalar.c).
17*/
18
19/* T.Grill - changed the _template.t_pd member to t_pdobj to avoid name clashes
20with the t_pd type */
21
22 /* the structure of a "struct" object (also the obsolete "gtemplate"
23 you get when using the name "template" in a box.) */
24
25struct _gtemplate
26{
27 t_object x_obj;
28 t_template *x_template;
29 t_canvas *x_owner;
30 t_symbol *x_sym;
31 struct _gtemplate *x_next;
32 int x_argc;
33 t_atom *x_argv;
34};
35
36/* ---------------- forward definitions ---------------- */
37
38static void template_conformarray(t_template *tfrom, t_template *tto,
39 int *conformaction, t_array *a);
40static void template_conformglist(t_template *tfrom, t_template *tto,
41 t_glist *glist, int *conformaction);
42
43/* ---------------------- storage ------------------------- */
44
45static t_class *gtemplate_class;
46static t_class *template_class;
47
48/* there's a pre-defined "float" template. LATER should we bind this
49to a symbol such as "pd-float"??? */
50
51static t_dataslot template_float_vec =
52{
53 DT_FLOAT,
54 &s_y,
55 &s_
56};
57
58static t_template template_float =
59{
60 0, /* class -- fill in in setup routine */
61 0, /* list of "struct"/t_gtemplate objects */
62 &s_float, /* name */
63 1, /* number of items */
64 &template_float_vec
65};
66
67 /* return true if two dataslot definitions match */
68static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2,
69 int nametoo)
70{
71 return ((!nametoo || ds1->ds_name == ds2->ds_name) &&
72 ds1->ds_type == ds2->ds_type &&
73 (ds1->ds_type != DT_ARRAY ||
74 ds1->ds_arraytemplate == ds2->ds_arraytemplate));
75}
76
77/* -- templates, the active ingredient in gtemplates defined below. ------- */
78
79t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
80{
81 t_template *x = (t_template *)pd_new(template_class);
82 x->t_n = 0;
83 x->t_vec = (t_dataslot *)t_getbytes(0);
84 while (argc > 0)
85 {
86 int newtype, oldn, newn;
87 t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
88 if (argc < 2 || argv[0].a_type != A_SYMBOL ||
89 argv[1].a_type != A_SYMBOL)
90 goto bad;
91 newtypesym = argv[0].a_w.w_symbol;
92 newname = argv[1].a_w.w_symbol;
93 if (newtypesym == &s_float)
94 newtype = DT_FLOAT;
95 else if (newtypesym == &s_symbol)
96 newtype = DT_SYMBOL;
97 else if (newtypesym == &s_list)
98 newtype = DT_LIST;
99 else if (newtypesym == gensym("array"))
100 {
101 if (argc < 3 || argv[2].a_type != A_SYMBOL)
102 {
103 pd_error(x, "array lacks element template or name");
104 goto bad;
105 }
106 newarraytemplate = canvas_makebindsym(argv[2].a_w.w_symbol);
107 newtype = DT_ARRAY;
108 argc--;
109 argv++;
110 }
111 else
112 {
113 pd_error(x, "%s: no such type", newtypesym->s_name);
114 return (0);
115 }
116 newn = (oldn = x->t_n) + 1;
117 x->t_vec = (t_dataslot *)t_resizebytes(x->t_vec,
118 oldn * sizeof(*x->t_vec), newn * sizeof(*x->t_vec));
119 x->t_n = newn;
120 x->t_vec[oldn].ds_type = newtype;
121 x->t_vec[oldn].ds_name = newname;
122 x->t_vec[oldn].ds_arraytemplate = newarraytemplate;
123 bad:
124 argc -= 2; argv += 2;
125 }
126 if (templatesym->s_name)
127 {
128 x->t_sym = templatesym;
129 pd_bind(&x->t_pdobj, x->t_sym);
130 }
131 else x->t_sym = templatesym;
132 return (x);
133}
134
135int template_size(t_template *x)
136{
137 return (x->t_n * sizeof(t_word));
138}
139
140int template_find_field(t_template *x, t_symbol *name, int *p_onset,
141 int *p_type, t_symbol **p_arraytype)
142{
143 t_template *t;
144 int i, n;
145 if (!x)
146 {
147 bug("template_find_field");
148 return (0);
149 }
150 n = x->t_n;
151 for (i = 0; i < n; i++)
152 if (x->t_vec[i].ds_name == name)
153 {
154 *p_onset = i * sizeof(t_word);
155 *p_type = x->t_vec[i].ds_type;
156 *p_arraytype = x->t_vec[i].ds_arraytemplate;
157 return (1);
158 }
159 return (0);
160}
161
162t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
163 int loud)
164{
165 int onset, type;
166 t_symbol *arraytype;
167 t_sample val = 0;
168 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
169 {
170 if (type == DT_FLOAT)
171 val = *(t_sample *)(((char *)wp) + onset);
172 else if (loud) error("%s.%s: not a number",
173 x->t_sym->s_name, fieldname->s_name);
174 }
175 else if (loud) error("%s.%s: no such field",
176 x->t_sym->s_name, fieldname->s_name);
177 return (fixtof(val));
178}
179
180void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
181 t_float f, int loud)
182{
183 int onset, type;
184 t_symbol *arraytype;
185 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
186 {
187 if (type == DT_FLOAT)
188 *(t_sample *)(((char *)wp) + onset) = ftofix(f);
189 else if (loud) error("%s.%s: not a number",
190 x->t_sym->s_name, fieldname->s_name);
191 }
192 else if (loud) error("%s.%s: no such field",
193 x->t_sym->s_name, fieldname->s_name);
194}
195
196t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
197 int loud)
198{
199 int onset, type;
200 t_symbol *arraytype;
201 t_symbol *val = &s_;
202 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
203 {
204 if (type == DT_SYMBOL)
205 val = *(t_symbol **)(((char *)wp) + onset);
206 else if (loud) error("%s.%s: not a symbol",
207 x->t_sym->s_name, fieldname->s_name);
208 }
209 else if (loud) error("%s.%s: no such field",
210 x->t_sym->s_name, fieldname->s_name);
211 return (val);
212}
213
214void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
215 t_symbol *s, int loud)
216{
217 int onset, type;
218 t_symbol *arraytype;
219 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
220 {
221 if (type == DT_SYMBOL)
222 *(t_symbol **)(((char *)wp) + onset) = s;
223 else if (loud) error("%s.%s: not a symbol",
224 x->t_sym->s_name, fieldname->s_name);
225 }
226 else if (loud) error("%s.%s: no such field",
227 x->t_sym->s_name, fieldname->s_name);
228}
229
230 /* stringent check to see if a "saved" template, x2, matches the current
231 one (x1). It's OK if x1 has additional scalar elements but not (yet)
232 arrays or lists. This is used for reading in "data files". */
233int template_match(t_template *x1, t_template *x2)
234{
235 int i;
236 if (x1->t_n < x2->t_n)
237 return (0);
238 for (i = x2->t_n; i < x1->t_n; i++)
239 {
240 if (x1->t_vec[i].ds_type == DT_ARRAY ||
241 x1->t_vec[i].ds_type == DT_LIST)
242 return (0);
243 }
244 if (x2->t_n > x1->t_n)
245 post("add elements...");
246 for (i = 0; i < x2->t_n; i++)
247 if (!dataslot_matches(&x1->t_vec[i], &x2->t_vec[i], 1))
248 return (0);
249 return (1);
250}
251
252/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
253
254/* the following routines handle updating scalars to agree with changes
255in their template. The old template is assumed to be the "installed" one
256so we can delete old items; but making new ones we have to avoid scalar_new
257which would make an old one whereas we will want a new one (but whose array
258elements might still be old ones.
259 LATER deal with graphics updates too... */
260
261 /* conform the word vector of a scalar to the new template */
262static void template_conformwords(t_template *tfrom, t_template *tto,
263 int *conformaction, t_word *wfrom, t_word *wto)
264{
265 int nfrom = tfrom->t_n, nto = tto->t_n, i;
266 for (i = 0; i < nto; i++)
267 {
268 if (conformaction[i] >= 0)
269 {
270 /* we swap the two, in case it's an array or list, so that
271 when "wfrom" is deleted the old one gets cleaned up. */
272 t_word wwas = wto[i];
273 wto[i] = wfrom[conformaction[i]];
274 wfrom[conformaction[i]] = wwas;
275 }
276 }
277}
278
279 /* conform a scalar, recursively conforming sublists and arrays */
280static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
281 int *conformaction, t_glist *glist, t_scalar *scfrom)
282{
283 t_scalar *x;
284 t_gpointer gp;
285 int nto = tto->t_n, nfrom = tfrom->t_n, i;
286 t_template *scalartemplate;
287 /* post("conform scalar"); */
288 /* possibly replace the scalar */
289 if (scfrom->sc_template == tfrom->t_sym)
290 {
291 /* see scalar_new() for comment about the gpointer. */
292 gpointer_init(&gp);
293 x = (t_scalar *)getbytes(sizeof(t_scalar) +
294 (tto->t_n - 1) * sizeof(*x->sc_vec));
295 x->sc_gobj.g_pd = scalar_class;
296 x->sc_template = tfrom->t_sym;
297 gpointer_setglist(&gp, glist, x);
298 /* Here we initialize to the new template, but array and list
299 elements will still belong to old template. */
300 word_init(x->sc_vec, tto, &gp);
301
302 template_conformwords(tfrom, tto, conformaction,
303 scfrom->sc_vec, x->sc_vec);
304
305 /* replace the old one with the new one in the list */
306 if (glist->gl_list == &scfrom->sc_gobj)
307 {
308 glist->gl_list = &x->sc_gobj;
309 x->sc_gobj.g_next = scfrom->sc_gobj.g_next;
310 }
311 else
312 {
313 t_gobj *y, *y2;
314 for (y = glist->gl_list; y2 = y->g_next; y = y2)
315 if (y2 == &scfrom->sc_gobj)
316 {
317 x->sc_gobj.g_next = y2->g_next;
318 y->g_next = &x->sc_gobj;
319 goto nobug;
320 }
321 bug("template_conformscalar");
322 nobug: ;
323 }
324 /* burn the old one */
325 pd_free(&scfrom->sc_gobj.g_pd);
326 }
327 else x = scfrom;
328 scalartemplate = template_findbyname(x->sc_template);
329 /* convert all array elements and sublists */
330 for (i = 0; i < scalartemplate->t_n; i++)
331 {
332 t_dataslot *ds = scalartemplate->t_vec + i;
333 if (ds->ds_type == DT_LIST)
334 {
335 t_glist *gl2 = x->sc_vec[i].w_list;
336 template_conformglist(tfrom, tto, gl2, conformaction);
337 }
338 else if (ds->ds_type == DT_ARRAY)
339 {
340 template_conformarray(tfrom, tto, conformaction,
341 x->sc_vec[i].w_array);
342 }
343 }
344 return (x);
345}
346
347 /* conform an array, recursively conforming sublists and arrays */
348static void template_conformarray(t_template *tfrom, t_template *tto,
349 int *conformaction, t_array *a)
350{
351 int i;
352 if (a->a_templatesym == tfrom->t_sym)
353 {
354 /* the array elements must all be conformed */
355 int oldelemsize = sizeof(t_word) * tfrom->t_n,
356 newelemsize = sizeof(t_word) * tto->t_n;
357 char *newarray = getbytes(sizeof(t_word) * tto->t_n * a->a_n);
358 char *oldarray = a->a_vec;
359 if (a->a_elemsize != oldelemsize)
360 bug("template_conformarray");
361 for (i = 0; i < a->a_n; i++)
362 {
363 t_word *wp = (t_word *)(newarray + newelemsize * i);
364 word_init(wp, tto, &a->a_gp);
365 template_conformwords(tfrom, tto, conformaction,
366 (t_word *)(oldarray + oldelemsize * i), wp);
367 }
368 }
369 bug("template_conformarray: this part not written");
370 /* go through item by item conforming subarrays and sublists... */
371}
372
373 /* this routine searches for every scalar in the glist that belongs
374 to the "from" template and makes it belong to the "to" template. Descend
375 glists recursively.
376 We don't handle redrawing here; this is to be filled in LATER... */
377
378static void template_conformglist(t_template *tfrom, t_template *tto,
379 t_glist *glist, int *conformaction)
380{
381 t_gobj *g;
382 /* post("conform glist %s", glist->gl_name->s_name); */
383 for (g = glist->gl_list; g; g = g->g_next)
384 {
385 if (pd_class(&g->g_pd) == scalar_class)
386 g = &template_conformscalar(tfrom, tto, conformaction,
387 glist, (t_scalar *)g)->sc_gobj;
388 else if (pd_class(&g->g_pd) == canvas_class)
389 template_conformglist(tfrom, tto, (t_glist *)g, conformaction);
390 }
391}
392
393 /* globally conform all scalars from one template to another */
394void template_conform(t_template *tfrom, t_template *tto)
395{
396 int nto = tto->t_n, nfrom = tfrom->t_n, i, j,
397 *conformaction = (int *)getbytes(sizeof(int) * nto),
398 *conformedfrom = (int *)getbytes(sizeof(int) * nfrom), doit = 0;
399 for (i = 0; i < nto; i++)
400 conformaction[i] = -1;
401 for (i = 0; i < nfrom; i++)
402 conformedfrom[i] = 0;
403 for (i = 0; i < nto; i++)
404 {
405 t_dataslot *dataslot = &tto->t_vec[i];
406 for (j = 0; j < nfrom; j++)
407 {
408 t_dataslot *dataslot2 = &tfrom->t_vec[j];
409 if (dataslot_matches(dataslot, dataslot2, 1))
410 {
411 conformaction[i] = j;
412 conformedfrom[j] = 1;
413 }
414 }
415 }
416 for (i = 0; i < nto; i++)
417 if (conformaction[i] < 0)
418 {
419 t_dataslot *dataslot = &tto->t_vec[i];
420 for (j = 0; j < nfrom; j++)
421 if (!conformedfrom[j] &&
422 dataslot_matches(dataslot, &tfrom->t_vec[j], 1))
423 {
424 conformaction[i] = j;
425 conformedfrom[j] = 1;
426 }
427 }
428 if (nto != nfrom)
429 doit = 1;
430 else for (i = 0; i < nto; i++)
431 if (conformaction[i] != i)
432 doit = 1;
433
434 if (doit)
435 {
436 t_glist *gl;
437 /* post("conforming template '%s' to new structure",
438 tfrom->t_sym->s_name);
439 for (i = 0; i < nto; i++)
440 post("... %d", conformaction[i]); */
441 for (gl = canvas_list; gl; gl = gl->gl_next)
442 template_conformglist(tfrom, tto, gl, conformaction);
443 }
444 freebytes(conformaction, sizeof(int) * nto);
445 freebytes(conformedfrom, sizeof(int) * nfrom);
446}
447
448t_template *template_findbyname(t_symbol *s)
449{
450 int i;
451 if (s == &s_float)
452 return (&template_float);
453 else return ((t_template *)pd_findbyclass(s, template_class));
454}
455
456t_canvas *template_findcanvas(t_template *template)
457{
458 t_gtemplate *gt;
459 if (!template)
460 bug("template_findcanvas");
461 if (!(gt = template->t_list))
462 return (0);
463 return (gt->x_owner);
464 /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
465}
466
467 /* call this when reading a patch from a file to declare what templates
468 we'll need. If there's already a template, check if it matches.
469 If it doesn't it's still OK as long as there are no "struct" (gtemplate)
470 objects hanging from it; we just conform everyone to the new template.
471 If there are still struct objects belonging to the other template, we're
472 in trouble. LATER we'll figure out how to conform the new patch's objects
473 to the pre-existing struct. */
474static void *template_usetemplate(void *dummy, t_symbol *s,
475 int argc, t_atom *argv)
476{
477 t_template *x;
478 t_symbol *templatesym =
479 canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
480 if (!argc)
481 return (0);
482 argc--; argv++;
483 /* check if there's already a template by this name. */
484 if ((x = (t_template *)pd_findbyclass(templatesym, template_class)))
485 {
486 t_template *y = template_new(&s_, argc, argv);
487 /* If the new template is the same as the old one,
488 there's nothing to do. */
489 if (!template_match(x, y))
490 {
491 /* Are there "struct" objects upholding this template? */
492 if (x->t_list)
493 {
494 /* don't know what to do here! */
495 error("%s: template mismatch",
496 templatesym->s_name);
497 }
498 else
499 {
500 /* conform everyone to the new template */
501 template_conform(x, y);
502 pd_free(&x->t_pdobj);
503 template_new(templatesym, argc, argv);
504 }
505 }
506 pd_free(&y->t_pdobj);
507 }
508 /* otherwise, just make one. */
509 else template_new(templatesym, argc, argv);
510 return (0);
511}
512
513 /* here we assume someone has already cleaned up all instances of this. */
514void template_free(t_template *x)
515{
516 if (*x->t_sym->s_name)
517 pd_unbind(&x->t_pdobj, x->t_sym);
518 t_freebytes(x->t_vec, x->t_n * sizeof(*x->t_vec));
519}
520
521static void template_setup(void)
522{
523 template_class = class_new(gensym("template"), 0, (t_method)template_free,
524 sizeof(t_template), CLASS_PD, 0);
525 class_addmethod(pd_canvasmaker, (t_method)template_usetemplate,
526 gensym("struct"), A_GIMME, 0);
527
528}
529
530/* ---------------- gtemplates. One per canvas. ----------- */
531
532/* this is a "text" object that searches for, and if necessary creates,
533a "template" (above). Other objects in the canvas then can give drawing
534instructions for the template. The template doesn't go away when the
535gtemplate is deleted, so that you can replace it with
536another one to add new fields, for example. */
537
538static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
539{
540 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
541 t_template *t = template_findbyname(sym);
542 int i;
543 t_symbol *sx = gensym("x");
544 x->x_owner = canvas_getcurrent();
545 x->x_next = 0;
546 x->x_sym = sym;
547 x->x_argc = argc;
548 x->x_argv = (t_atom *)getbytes(argc * sizeof(t_atom));
549 for (i = 0; i < argc; i++)
550 x->x_argv[i] = argv[i];
551
552 /* already have a template by this name? */
553 if (t)
554 {
555 x->x_template = t;
556 /* if it's already got a "struct" or "gtemplate" object we
557 just tack this one to the end of the list and leave it
558 there. */
559 if (t->t_list)
560 {
561 t_gtemplate *x2, *x3;
562 for (x2 = x->x_template->t_list; x3 = x2->x_next; x2 = x3)
563 ;
564 x2->x_next = x;
565 post("template %s: warning: already exists.", sym->s_name);
566 }
567 else
568 {
569 /* if there's none, we just replace the template with
570 our own and conform it. */
571 t_template *y = template_new(&s_, argc, argv);
572 /* Unless the new template is different from the old one,
573 there's nothing to do. */
574 if (!template_match(t, y))
575 {
576 /* conform everyone to the new template */
577 template_conform(t, y);
578 pd_free(&t->t_pdobj);
579 t = template_new(sym, argc, argv);
580 }
581 pd_free(&y->t_pdobj);
582 t->t_list = x;
583 }
584 }
585 else
586 {
587 /* otherwise make a new one and we're the only struct on it. */
588 x->x_template = t = template_new(sym, argc, argv);
589 t->t_list = x;
590 }
591 return (x);
592}
593
594static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv)
595{
596 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
597 t_symbol *sym = atom_getsymbolarg(0, argc, argv);
598 if (argc >= 1)
599 argc--; argv++;
600 return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
601}
602
603 /* old version (0.34) -- delete 2003 or so */
604static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv)
605{
606 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
607 t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->gl_name);
608 static int warned;
609 if (!warned)
610 {
611 post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
612 sym->s_name);
613 warned = 1;
614 }
615 return (gtemplate_donew(sym, argc, argv));
616}
617
618t_template *gtemplate_get(t_gtemplate *x)
619{
620 return (x->x_template);
621}
622
623static void gtemplate_free(t_gtemplate *x)
624{
625 /* get off the template's list */
626 t_template *t = x->x_template;
627 if (x == t->t_list)
628 {
629 if (x->x_next)
630 {
631 /* if we were first on the list, and there are others on
632 the list, make a new template corresponding to the new
633 first-on-list and replace teh existing template with it. */
634 t_template *z = template_new(&s_, x->x_argc, x->x_argv);
635 template_conform(t, z);
636 pd_free(&t->t_pdobj);
637 pd_free(&z->t_pdobj);
638 z = template_new(x->x_sym, x->x_argc, x->x_argv);
639 z->t_list = x->x_next;
640 }
641 else t->t_list = 0;
642 }
643 else
644 {
645 t_gtemplate *x2, *x3;
646 for (x2 = t->t_list; x3 = x2->x_next; x2 = x3)
647 {
648 if (x == x3)
649 {
650 x2->x_next = x3->x_next;
651 break;
652 }
653 }
654 }
655 freebytes(x->x_argv, sizeof(t_atom) * x->x_argc);
656}
657
658static void gtemplate_setup(void)
659{
660 gtemplate_class = class_new(gensym("struct"),
661 (t_newmethod)gtemplate_new, (t_method)gtemplate_free,
662 sizeof(t_gtemplate), CLASS_NOINLET, A_GIMME, 0);
663 class_addcreator((t_newmethod)gtemplate_new_old, gensym("template"),
664 A_GIMME, 0);
665}
666
667/* --------------- FIELD DESCRIPTORS ---------------------- */
668
669/* a field descriptor can hold a constant or a variable; if a variable,
670it's the name of a field in the template we belong to. LATER, we might
671want to cache the offset of the field so we don't have to search for it
672every single time we draw the object.
673*/
674
675typedef struct _fielddesc
676{
677 char fd_type; /* LATER consider removing this? */
678 char fd_var;
679 union
680 {
681 t_float fd_float; /* the field is a constant float */
682 t_symbol *fd_symbol; /* the field is a constant symbol */
683 t_symbol *fd_varsym; /* the field is variable and this is the name */
684 } fd_un;
685} t_fielddesc;
686
687#define FIELDDESC_SETFLOAT(x, f) \
688 ((x)->fd_type = A_FLOAT, (x)->fd_var = 0, (x)->fd_un.fd_float = (f))
689#define FIELDDESC_SETSYMBOL(x, s) \
690 ((x)->fd_type = A_SYMBOL, (x)->fd_var = 0, (x)->fd_un.fd_symbol = (s))
691#define FIELDDESC_SETVAR(x, s, type) \
692 ((x)->fd_type = type, (x)->fd_var = 1, (x)->fd_un.fd_varsym = (s))
693
694#define CLOSED 1
695#define BEZ 2
696#define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
697
698static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
699{
700 if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
701 else if (argv->a_type == A_SYMBOL)
702 FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_FLOAT);
703 else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
704}
705
706static void fielddesc_setarrayarg(t_fielddesc *fd, int argc, t_atom *argv)
707{
708 if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
709 else if (argv->a_type == A_SYMBOL)
710 FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_ARRAY);
711 else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
712}
713
714static t_float fielddesc_getfloat(t_fielddesc *f, t_template *template,
715 t_word *wp, int loud)
716{
717 if (f->fd_type == A_FLOAT)
718 {
719 if (f->fd_var)
720 return (template_getfloat(template, f->fd_un.fd_varsym, wp, loud));
721 else return (f->fd_un.fd_float);
722 }
723 else
724 {
725 if (loud)
726 error("symbolic data field used as number");
727 return (0);
728 }
729}
730
731static t_symbol *fielddesc_getsymbol(t_fielddesc *f, t_template *template,
732 t_word *wp, int loud)
733{
734 if (f->fd_type == A_SYMBOL)
735 {
736 if (f->fd_var)
737 return(template_getsymbol(template, f->fd_un.fd_varsym, wp, loud));
738 else return (f->fd_un.fd_symbol);
739 }
740 else
741 {
742 if (loud)
743 error("numeric data field used as symbol");
744 return (&s_);
745 }
746}
747
748/* ---------------- curves and polygons (joined segments) ---------------- */
749
750/*
751curves belong to templates and describe how the data in the template are to
752be drawn. The coordinates of the curve (and other display features) can
753be attached to fields in the template.
754*/
755
756t_class *curve_class;
757
758typedef struct _curve
759{
760 t_object x_obj;
761 int x_flags; /* CLOSED and/or BEZ */
762 t_fielddesc x_fillcolor;
763 t_fielddesc x_outlinecolor;
764 t_fielddesc x_width;
765 int x_npoints;
766 t_fielddesc *x_vec;
767} t_curve;
768
769static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
770{
771 t_curve *x = (t_curve *)pd_new(curve_class);
772 char *classname = classsym->s_name;
773 int flags = 0;
774 int nxy, i;
775 t_fielddesc *fd;
776 if (classname[0] == 'f')
777 {
778 classname += 6;
779 flags |= CLOSED;
780 if (argc) fielddesc_setfloatarg(&x->x_fillcolor, argc--, argv++);
781 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
782 }
783 else classname += 4;
784 if (classname[0] == 'c') flags |= BEZ;
785 x->x_flags = flags;
786 if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
787 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
788 if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
789 else FIELDDESC_SETFLOAT(&x->x_width, 1);
790 if (argc < 0) argc = 0;
791 nxy = (argc + (argc & 1));
792 x->x_npoints = (nxy>>1);
793 x->x_vec = (t_fielddesc *)t_getbytes(nxy * sizeof(t_fielddesc));
794 for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++)
795 fielddesc_setfloatarg(fd, 1, argv);
796 if (argc & 1) FIELDDESC_SETFLOAT(fd, 0);
797
798 return (x);
799}
800
801/* -------------------- widget behavior for curve ------------ */
802
803static void curve_getrect(t_gobj *z, t_glist *glist,
804 t_word *data, t_template *template, float basex, float basey,
805 int *xp1, int *yp1, int *xp2, int *yp2)
806{
807 t_curve *x = (t_curve *)z;
808 int i, n = x->x_npoints;
809 t_fielddesc *f = x->x_vec;
810 int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
811 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
812 {
813 int xloc = glist_xtopixels(glist,
814 basex + fielddesc_getfloat(f, template, data, 0));
815 int yloc = glist_ytopixels(glist,
816 basey + fielddesc_getfloat(f+1, template, data, 0));
817 if (xloc < x1) x1 = xloc;
818 if (xloc > x2) x2 = xloc;
819 if (yloc < y1) y1 = yloc;
820 if (yloc > y2) y2 = yloc;
821 }
822 *xp1 = x1;
823 *yp1 = y1;
824 *xp2 = x2;
825 *yp2 = y2;
826}
827
828static void curve_displace(t_gobj *z, t_glist *glist,
829 t_word *data, t_template *template, float basex, float basey,
830 int dx, int dy)
831{
832 /* refuse */
833}
834
835static void curve_select(t_gobj *z, t_glist *glist,
836 t_word *data, t_template *template, float basex, float basey,
837 int state)
838{
839 /* fill in later */
840}
841
842static void curve_activate(t_gobj *z, t_glist *glist,
843 t_word *data, t_template *template, float basex, float basey,
844 int state)
845{
846 /* fill in later */
847}
848
849static int rangecolor(int n) /* 0 to 9 in 5 steps */
850{
851 int n2 = n/2; /* 0 to 4 */
852 int ret = (n2 << 6); /* 0 to 256 in 5 steps */
853 if (ret > 255) ret = 255;
854 return (ret);
855}
856
857static void numbertocolor(int n, char *s)
858{
859 int red, blue, green;
860 if (n < 0) n = 0;
861 red = n / 100;
862 blue = ((n / 10) % 10);
863 green = n % 10;
864 sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(red), rangecolor(blue),
865 rangecolor(green));
866}
867
868static void curve_vis(t_gobj *z, t_glist *glist,
869 t_word *data, t_template *template, float basex, float basey,
870 int vis)
871{
872 t_curve *x = (t_curve *)z;
873 int i, n = x->x_npoints;
874 t_fielddesc *f = x->x_vec;
875
876 if (vis)
877 {
878 if (n > 1)
879 {
880 int flags = x->x_flags, closed = (flags & CLOSED);
881 float width = fielddesc_getfloat(&x->x_width, template, data, 1);
882 char outline[20], fill[20];
883 if (width < 1) width = 1;
884 numbertocolor(
885 fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
886 outline);
887 if (flags & CLOSED)
888 {
889 numbertocolor(
890 fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
891 fill);
892 sys_vgui(".x%x.c create polygon\\\n",
893 glist_getcanvas(glist));
894 }
895 else sys_vgui(".x%x.c create line\\\n",
896 glist_getcanvas(glist));
897 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
898 {
899 float xloc = glist_xtopixels(glist,
900 basex + fielddesc_getfloat(f, template, data, 1));
901 float yloc = glist_ytopixels(glist,
902 basey + fielddesc_getfloat(f+1, template, data, 1));
903 sys_vgui("%d %d\\\n", (int)xloc, (int)yloc);
904 }
905 sys_vgui("-width %f\\\n",
906 fielddesc_getfloat(&x->x_width, template, data, 1));
907 if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n",
908 fill, outline);
909 else sys_vgui("-fill %s\\\n", outline);
910 if (flags & BEZ) sys_vgui("-smooth 1\\\n");
911 sys_vgui("-tags curve%x\n", data);
912 }
913 else post("warning: curves need at least two points to be graphed");
914 }
915 else
916 {
917 if (n > 1) sys_vgui(".x%x.c delete curve%x\n",
918 glist_getcanvas(glist), data);
919 }
920}
921
922static int curve_motion_field;
923static float curve_motion_xcumulative;
924static float curve_motion_xbase;
925static float curve_motion_xper;
926static float curve_motion_ycumulative;
927static float curve_motion_ybase;
928static float curve_motion_yper;
929static t_glist *curve_motion_glist;
930static t_gobj *curve_motion_gobj;
931static t_word *curve_motion_wp;
932static t_template *curve_motion_template;
933
934 /* LATER protect against the template changing or the scalar disappearing
935 probably by attaching a gpointer here ... */
936
937static void curve_motion(void *z, t_floatarg dx, t_floatarg dy)
938{
939 t_curve *x = (t_curve *)z;
940 t_fielddesc *f = x->x_vec + curve_motion_field;
941 curve_motion_xcumulative += dx;
942 curve_motion_ycumulative += dy;
943 if (f->fd_var)
944 {
945 template_setfloat(curve_motion_template,
946 f->fd_un.fd_varsym,
947 curve_motion_wp,
948 curve_motion_xbase + curve_motion_xcumulative * curve_motion_xper,
949 1);
950 }
951 if ((f+1)->fd_var)
952 {
953 template_setfloat(curve_motion_template,
954 (f+1)->fd_un.fd_varsym,
955 curve_motion_wp,
956 curve_motion_ybase + curve_motion_ycumulative * curve_motion_yper,
957 1);
958 }
959 glist_redrawitem(curve_motion_glist, curve_motion_gobj);
960}
961
962static int curve_click(t_gobj *z, t_glist *glist,
963 t_scalar *sc, t_template *template, float basex, float basey,
964 int xpix, int ypix, int shift, int alt, int dbl, int doit)
965{
966 t_curve *x = (t_curve *)z;
967 int i, n = x->x_npoints;
968 int bestn = -1;
969 int besterror = 0x7fffffff;
970 t_fielddesc *f = x->x_vec;
971 t_word *data = sc->sc_vec;
972 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
973 {
974 int xloc = glist_xtopixels(glist,
975 basex + fielddesc_getfloat(f, template, data, 0));
976 int yloc = glist_ytopixels(glist,
977 basey + fielddesc_getfloat(f+1, template, data, 0));
978 int xerr = xloc - xpix, yerr = yloc - ypix;
979 if (!f->fd_var && !(f+1)->fd_var)
980 continue;
981 if (xerr < 0)
982 xerr = -xerr;
983 if (yerr < 0)
984 yerr = -yerr;
985 if (yerr > xerr)
986 xerr = yerr;
987 if (xerr < besterror)
988 {
989 besterror = xerr;
990 bestn = i;
991 curve_motion_xbase = fielddesc_getfloat(f, template, data, 0);
992 curve_motion_ybase = fielddesc_getfloat(f+1, template, data, 0);
993 }
994 }
995 if (besterror > 10)
996 return (0);
997 if (doit)
998 {
999 curve_motion_xper = glist_pixelstox(glist, 1)
1000 - glist_pixelstox(glist, 0);
1001 curve_motion_yper = glist_pixelstoy(glist, 1)
1002 - glist_pixelstoy(glist, 0);
1003 curve_motion_xcumulative = curve_motion_ycumulative = 0;
1004 curve_motion_glist = glist;
1005 curve_motion_gobj = &sc->sc_gobj;
1006 curve_motion_wp = data;
1007 curve_motion_field = 2*bestn;
1008 curve_motion_template = template;
1009 glist_grab(glist, z, curve_motion, 0, xpix, ypix);
1010 }
1011 return (1);
1012}
1013
1014t_parentwidgetbehavior curve_widgetbehavior =
1015{
1016 curve_getrect,
1017 curve_displace,
1018 curve_select,
1019 curve_activate,
1020 curve_vis,
1021 curve_click,
1022};
1023
1024static void curve_free(t_curve *x)
1025{
1026 t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec));
1027}
1028
1029static void curve_setup(void)
1030{
1031 curve_class = class_new(gensym("drawpolygon"), (t_newmethod)curve_new,
1032 (t_method)curve_free, sizeof(t_curve), CLASS_NOINLET, A_GIMME, 0);
1033 class_setdrawcommand(curve_class);
1034 class_addcreator((t_newmethod)curve_new, gensym("drawcurve"),
1035 A_GIMME, 0);
1036 class_addcreator((t_newmethod)curve_new, gensym("filledpolygon"),
1037 A_GIMME, 0);
1038 class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
1039 A_GIMME, 0);
1040 class_setparentwidget(curve_class, &curve_widgetbehavior);
1041}
1042
1043/* --------- plots for showing arrays --------------- */
1044
1045t_class *plot_class;
1046
1047typedef struct _plot
1048{
1049 t_object x_obj;
1050 int x_flags;
1051 t_fielddesc x_outlinecolor;
1052 t_fielddesc x_width;
1053 t_fielddesc x_xloc;
1054 t_fielddesc x_yloc;
1055 t_fielddesc x_xinc;
1056 t_fielddesc x_data;
1057} t_plot;
1058
1059static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv)
1060{
1061 t_plot *x = (t_plot *)pd_new(plot_class);
1062 int flags = 0;
1063 int nxy, i;
1064 t_fielddesc *fd;
1065 t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
1066 if (!strcmp(firstarg->s_name, "curve"))
1067 {
1068 flags |= BEZ;
1069 argc--, argv++;
1070 }
1071 if (argc) fielddesc_setarrayarg(&x->x_data, argc--, argv++);
1072 else FIELDDESC_SETFLOAT(&x->x_data, 1);
1073 if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
1074 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
1075 if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
1076 else FIELDDESC_SETFLOAT(&x->x_width, 1);
1077 if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
1078 else FIELDDESC_SETFLOAT(&x->x_xloc, 1);
1079 if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
1080 else FIELDDESC_SETFLOAT(&x->x_yloc, 1);
1081 if (argc) fielddesc_setfloatarg(&x->x_xinc, argc--, argv++);
1082 else FIELDDESC_SETFLOAT(&x->x_xinc, 1);
1083 x->x_flags = flags;
1084 return (x);
1085}
1086
1087/* -------------------- widget behavior for plot ------------ */
1088
1089
1090 /* get everything we'll need from the owner template of the array being
1091 plotted. Not used for garrays, but see below */
1092static int plot_readownertemplate(t_plot *x,
1093 t_word *data, t_template *ownertemplate,
1094 t_symbol **elemtemplatesymp, t_array **arrayp,
1095 float *linewidthp, float *xlocp, float *xincp, float *ylocp)
1096{
1097 int arrayonset, type;
1098 t_symbol *elemtemplatesym;
1099 t_array *array;
1100
1101 /* find the data and verify it's an array */
1102 if (x->x_data.fd_type != A_ARRAY || !x->x_data.fd_var)
1103 {
1104 error("plot: needs an array field");
1105 return (-1);
1106 }
1107 if (!template_find_field(ownertemplate, x->x_data.fd_un.fd_varsym,
1108 &arrayonset, &type, &elemtemplatesym))
1109 {
1110 error("plot: %s: no such field", x->x_data.fd_un.fd_varsym->s_name);
1111 return (-1);
1112 }
1113 if (type != DT_ARRAY)
1114 {
1115 error("plot: %s: not an array", x->x_data.fd_un.fd_varsym->s_name);
1116 return (-1);
1117 }
1118 array = *(t_array **)(((char *)data) + arrayonset);
1119 *linewidthp = fielddesc_getfloat(&x->x_width, ownertemplate, data, 1);
1120 *xlocp = fielddesc_getfloat(&x->x_xloc, ownertemplate, data, 1);
1121 *xincp = fielddesc_getfloat(&x->x_xinc, ownertemplate, data, 1);
1122 *ylocp = fielddesc_getfloat(&x->x_yloc, ownertemplate, data, 1);
1123 *elemtemplatesymp = elemtemplatesym;
1124 *arrayp = array;
1125 return (0);
1126}
1127
1128 /* get everything else you could possibly need about a plot,
1129 either for plot's own purposes or for plotting a "garray" */
1130int array_getfields(t_symbol *elemtemplatesym,
1131 t_canvas **elemtemplatecanvasp,
1132 t_template **elemtemplatep, int *elemsizep,
1133 int *xonsetp, int *yonsetp, int *wonsetp)
1134{
1135 int arrayonset, elemsize, yonset, wonset, xonset, type;
1136 t_template *elemtemplate;
1137 t_symbol *dummy;
1138 t_canvas *elemtemplatecanvas = 0;
1139
1140 /* the "float" template is special in not having to have a canvas;
1141 template_findbyname is hardwired to return a predefined
1142 template. */
1143
1144 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
1145 {
1146 error("plot: %s: no such template", elemtemplatesym->s_name);
1147 return (-1);
1148 }
1149 if (!((elemtemplatesym == &s_float) ||
1150 (elemtemplatecanvas = template_findcanvas(elemtemplate))))
1151 {
1152 error("plot: %s: no canvas for this template", elemtemplatesym->s_name);
1153 return (-1);
1154 }
1155 elemsize = elemtemplate->t_n * sizeof(t_word);
1156 if (!template_find_field(elemtemplate, gensym("y"), &yonset, &type, &dummy)
1157 || type != DT_FLOAT)
1158 yonset = -1;
1159 if (!template_find_field(elemtemplate, gensym("x"), &xonset, &type, &dummy)
1160 || type != DT_FLOAT)
1161 xonset = -1;
1162 if (!template_find_field(elemtemplate, gensym("w"), &wonset, &type, &dummy)
1163 || type != DT_FLOAT)
1164 wonset = -1;
1165
1166 /* fill in slots for return values */
1167 *elemtemplatecanvasp = elemtemplatecanvas;
1168 *elemtemplatep = elemtemplate;
1169 *elemsizep = elemsize;
1170 *xonsetp = xonset;
1171 *yonsetp = yonset;
1172 *wonsetp = wonset;
1173 return (0);
1174}
1175
1176static void plot_getrect(t_gobj *z, t_glist *glist,
1177 t_word *data, t_template *template, float basex, float basey,
1178 int *xp1, int *yp1, int *xp2, int *yp2)
1179{
1180 t_plot *x = (t_plot *)z;
1181 int elemsize, yonset, wonset, xonset;
1182 t_canvas *elemtemplatecanvas;
1183 t_template *elemtemplate;
1184 t_symbol *elemtemplatesym;
1185 float linewidth, xloc, xinc, yloc;
1186 t_array *array;
1187 float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
1188 int i;
1189 float xpix, ypix, wpix;
1190
1191 if (!plot_readownertemplate(x, data, template,
1192 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) &&
1193 !array_getfields(elemtemplatesym, &elemtemplatecanvas,
1194 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
1195 {
1196 for (i = 0; i < array->a_n; i++)
1197 {
1198 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
1199 xonset, yonset, wonset, i, basex + xloc, basey + yloc, xinc,
1200 &xpix, &ypix, &wpix);
1201 if (xpix < x1)
1202 x1 = xpix;
1203 if (xpix > x2)
1204 x2 = xpix;
1205 if (ypix - wpix < y1)
1206 y1 = ypix - wpix;
1207 if (ypix + wpix > y2)
1208 y2 = ypix + wpix;
1209 }
1210 }
1211
1212 *xp1 = x1;
1213 *yp1 = y1;
1214 *xp2 = x2;
1215 *yp2 = y2;
1216}
1217
1218static void plot_displace(t_gobj *z, t_glist *glist,
1219 t_word *data, t_template *template, float basex, float basey,
1220 int dx, int dy)
1221{
1222 /* not yet */
1223}
1224
1225static void plot_select(t_gobj *z, t_glist *glist,
1226 t_word *data, t_template *template, float basex, float basey,
1227 int state)
1228{
1229 /* not yet */
1230}
1231
1232static void plot_activate(t_gobj *z, t_glist *glist,
1233 t_word *data, t_template *template, float basex, float basey,
1234 int state)
1235{
1236 /* not yet */
1237}
1238
1239static void plot_vis(t_gobj *z, t_glist *glist,
1240 t_word *data, t_template *template, float basex, float basey,
1241 int vis)
1242{
1243 t_plot *x = (t_plot *)z;
1244 int elemsize, yonset, wonset, xonset;
1245 t_canvas *elemtemplatecanvas;
1246 t_template *elemtemplate;
1247 t_symbol *elemtemplatesym;
1248 float linewidth, xloc, xinc, yloc;
1249 t_array *array;
1250 int nelem;
1251 char *elem;
1252 if (plot_readownertemplate(x, data, template,
1253 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) ||
1254 array_getfields(elemtemplatesym, &elemtemplatecanvas,
1255 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
1256 return;
1257 nelem = array->a_n;
1258 elem = (char *)array->a_vec;
1259 if (vis)
1260 {
1261 char outline[20];
1262 int lastpixel = -1, ndrawn = 0;
1263 float xsum, yval = 0, wval = 0, xpix;
1264 int ixpix = 0, i;
1265
1266 /* draw the trace */
1267 numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
1268 outline);
1269 if (wonset >= 0)
1270 {
1271 /* found "w" field which controls linewidth. The trace is
1272 a filled polygon with 2n points. */
1273 sys_vgui(".x%x.c create polygon \\\n",
1274 glist_getcanvas(glist));
1275
1276 for (i = 0, xsum = xloc; i < nelem; i++)
1277 {
1278 float usexloc;
1279 if (xonset >= 0)
1280 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
1281 else usexloc = xsum, xsum += xinc;
1282 if (yonset >= 0)
1283 yval = *(float *)((elem + elemsize * i) + yonset);
1284 else yval = 0;
1285 wval = *(float *)((elem + elemsize * i) + wonset);
1286 xpix = glist_xtopixels(glist, basex + usexloc);
1287 ixpix = xpix + 0.5;
1288 if (xonset >= 0 || ixpix != lastpixel)
1289 {
1290 sys_vgui("%d %f \\\n", ixpix,
1291 glist_ytopixels(glist,
1292 basey + yloc + yval - wval));
1293 ndrawn++;
1294 }
1295 lastpixel = ixpix;
1296 if (ndrawn >= 1000) goto ouch;
1297 }
1298 lastpixel = -1;
1299 for (i = nelem-1; i >= 0; i--)
1300 {
1301 float usexloc;
1302 if (xonset >= 0)
1303 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
1304 else xsum -= xinc, usexloc = xsum;
1305 if (yonset >= 0)
1306 yval = *(float *)((elem + elemsize * i) + yonset);
1307 else yval = 0;
1308 wval = *(float *)((elem + elemsize * i) + wonset);
1309 xpix = glist_xtopixels(glist, basex + usexloc);
1310 ixpix = xpix + 0.5;
1311 if (xonset >= 0 || ixpix != lastpixel)
1312 {
1313 sys_vgui("%d %f \\\n", ixpix, glist_ytopixels(glist,
1314 basey + yloc + yval + wval));
1315 ndrawn++;
1316 }
1317 lastpixel = ixpix;
1318 if (ndrawn >= 1000) goto ouch;
1319 }
1320 /* TK will complain if there aren't at least 3 points. There
1321 should be at least two already. */
1322 if (ndrawn < 4)
1323 {
1324 sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
1325 basey + yloc + yval + wval));
1326 sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
1327 basey + yloc + yval - wval));
1328 }
1329 ouch:
1330 sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline, outline);
1331 if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
1332
1333 sys_vgui("-tags plot%x\n", data);
1334 }
1335 else if (linewidth > 0)
1336 {
1337 /* no "w" field. If the linewidth is positive, draw a
1338 segmented line with the requested width; otherwise don't
1339 draw the trace at all. */
1340 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
1341
1342 for (xsum = xloc, i = 0; i < nelem; i++)
1343 {
1344 float usexloc;
1345 if (xonset >= 0)
1346 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
1347 else usexloc = xsum, xsum += xinc;
1348 if (yonset >= 0)
1349 yval = *(float *)((elem + elemsize * i) + yonset);
1350 else yval = 0;
1351 xpix = glist_xtopixels(glist, basex + usexloc);
1352 ixpix = xpix + 0.5;
1353 if (xonset >= 0 || ixpix != lastpixel)
1354 {
1355 sys_vgui("%d %f \\\n", ixpix,
1356 glist_ytopixels(glist, basey + yloc + yval));
1357 ndrawn++;
1358 }
1359 lastpixel = ixpix;
1360 if (ndrawn >= 1000) break;
1361 }
1362 /* TK will complain if there aren't at least 2 points... */
1363 if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
1364 else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
1365 glist_ytopixels(glist, basey + yloc + yval));
1366
1367 sys_vgui("-width %f\\\n", linewidth);
1368 sys_vgui("-fill %s\\\n", outline);
1369 if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
1370
1371 sys_vgui("-tags plot%x\n", data);
1372 }
1373 /* We're done with the outline; now draw all the points.
1374 This code is inefficient since the template has to be
1375 searched for drawing instructions for every last point. */
1376
1377 for (xsum = xloc, i = 0; i < nelem; i++)
1378 {
1379 float usexloc, useyloc;
1380 t_gobj *y;
1381 if (xonset >= 0)
1382 usexloc = basex + xloc +
1383 *(float *)((elem + elemsize * i) + xonset);
1384 else usexloc = basex + xsum, xsum += xinc;
1385 if (yonset >= 0)
1386 yval = *(float *)((elem + elemsize * i) + yonset);
1387 else yval = 0;
1388 useyloc = basey + yloc + yval;
1389 for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
1390 {
1391 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
1392 if (!wb) continue;
1393 (*wb->w_parentvisfn)(y, glist,
1394 (t_word *)(elem + elemsize * i),
1395 elemtemplate, usexloc, useyloc, vis);
1396 }
1397 }
1398 }
1399 else
1400 {
1401 /* un-draw the individual points */
1402 int i;
1403 for (i = 0; i < nelem; i++)
1404 {
1405 t_gobj *y;
1406 for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
1407 {
1408 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
1409 if (!wb) continue;
1410 (*wb->w_parentvisfn)(y, glist,
1411 (t_word *)(elem + elemsize * i), elemtemplate,
1412 0, 0, 0);
1413 }
1414 }
1415 /* and then the trace */
1416 sys_vgui(".x%x.c delete plot%x\n",
1417 glist_getcanvas(glist), data);
1418 }
1419}
1420
1421
1422static int plot_click(t_gobj *z, t_glist *glist,
1423 t_scalar *sc, t_template *template, float basex, float basey,
1424 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1425{
1426 t_plot *x = (t_plot *)z;
1427 t_symbol *elemtemplatesym;
1428 float linewidth, xloc, xinc, yloc;
1429 t_array *array;
1430 t_word *data = sc->sc_vec;
1431
1432 if (!plot_readownertemplate(x, data, template,
1433 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc))
1434 {
1435 return (array_doclick(array, glist, &sc->sc_gobj,
1436 elemtemplatesym,
1437 linewidth, basex + xloc, xinc, basey + yloc,
1438 xpix, ypix, shift, alt, dbl, doit));
1439 }
1440 else return (0);
1441}
1442
1443t_parentwidgetbehavior plot_widgetbehavior =
1444{
1445 plot_getrect,
1446 plot_displace,
1447 plot_select,
1448 plot_activate,
1449 plot_vis,
1450 plot_click,
1451};
1452
1453static void plot_setup(void)
1454{
1455 plot_class = class_new(gensym("plot"), (t_newmethod)plot_new, 0,
1456 sizeof(t_plot), CLASS_NOINLET, A_GIMME, 0);
1457 class_setdrawcommand(plot_class);
1458 class_setparentwidget(plot_class, &plot_widgetbehavior);
1459}
1460
1461/* ---------------- drawnumber: draw a number ---------------- */
1462
1463/*
1464 drawnumbers draw numeric fields at controllable locations, with
1465 controllable color and label .
1466 invocation: (drawnumber|drawsymbol) variable x y color label
1467*/
1468
1469t_class *drawnumber_class;
1470
1471#define DRAW_SYMBOL 1
1472
1473typedef struct _drawnumber
1474{
1475 t_object x_obj;
1476 t_fielddesc x_value;
1477 t_fielddesc x_xloc;
1478 t_fielddesc x_yloc;
1479 t_fielddesc x_color;
1480 t_symbol *x_label;
1481 int x_flags;
1482} t_drawnumber;
1483
1484static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv)
1485{
1486 t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
1487 char *classname = classsym->s_name;
1488 int flags = 0;
1489 if (classname[4] == 's')
1490 flags |= DRAW_SYMBOL;
1491 x->x_flags = flags;
1492 if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
1493 else FIELDDESC_SETFLOAT(&x->x_value, 0);
1494 if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
1495 else FIELDDESC_SETFLOAT(&x->x_xloc, 0);
1496 if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
1497 else FIELDDESC_SETFLOAT(&x->x_yloc, 0);
1498 if (argc) fielddesc_setfloatarg(&x->x_color, argc--, argv++);
1499 else FIELDDESC_SETFLOAT(&x->x_color, 1);
1500 if (argc)
1501 x->x_label = atom_getsymbolarg(0, argc, argv);
1502 else x->x_label = &s_;
1503
1504 return (x);
1505}
1506
1507/* -------------------- widget behavior for drawnumber ------------ */
1508
1509#define DRAWNUMBER_BUFSIZE 80
1510static void drawnumber_sprintf(t_drawnumber *x, char *buf, t_atom *ap)
1511{
1512 int nchars;
1513 strncpy(buf, x->x_label->s_name, DRAWNUMBER_BUFSIZE);
1514 buf[DRAWNUMBER_BUFSIZE - 1] = 0;
1515 nchars = strlen(buf);
1516 atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars);
1517}
1518
1519static void drawnumber_getrect(t_gobj *z, t_glist *glist,
1520 t_word *data, t_template *template, float basex, float basey,
1521 int *xp1, int *yp1, int *xp2, int *yp2)
1522{
1523 t_drawnumber *x = (t_drawnumber *)z;
1524 t_atom at;
1525 int xloc = glist_xtopixels(glist,
1526 basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
1527 int yloc = glist_ytopixels(glist,
1528 basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
1529 int font = glist_getfont(glist);
1530 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
1531 char buf[DRAWNUMBER_BUFSIZE];
1532 if (x->x_flags & DRAW_SYMBOL)
1533 SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
1534 else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
1535 drawnumber_sprintf(x, buf, &at);
1536 *xp1 = xloc;
1537 *yp1 = yloc;
1538 *xp2 = xloc + fontwidth * strlen(buf);
1539 *yp2 = yloc + fontheight;
1540}
1541
1542static void drawnumber_displace(t_gobj *z, t_glist *glist,
1543 t_word *data, t_template *template, float basex, float basey,
1544 int dx, int dy)
1545{
1546 /* refuse */
1547}
1548
1549static void drawnumber_select(t_gobj *z, t_glist *glist,
1550 t_word *data, t_template *template, float basex, float basey,
1551 int state)
1552{
1553 post("drawnumber_select %d", state);
1554 /* fill in later */
1555}
1556
1557static void drawnumber_activate(t_gobj *z, t_glist *glist,
1558 t_word *data, t_template *template, float basex, float basey,
1559 int state)
1560{
1561 post("drawnumber_activate %d", state);
1562}
1563
1564static void drawnumber_vis(t_gobj *z, t_glist *glist,
1565 t_word *data, t_template *template, float basex, float basey,
1566 int vis)
1567{
1568 t_drawnumber *x = (t_drawnumber *)z;
1569
1570 if (vis)
1571 {
1572 t_atom at;
1573 int xloc = glist_xtopixels(glist,
1574 basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
1575 int yloc = glist_ytopixels(glist,
1576 basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
1577 char colorstring[20], buf[DRAWNUMBER_BUFSIZE];
1578 numbertocolor(fielddesc_getfloat(&x->x_color, template, data, 1),
1579 colorstring);
1580 if (x->x_flags & DRAW_SYMBOL)
1581 SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
1582 else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
1583 drawnumber_sprintf(x, buf, &at);
1584 sys_vgui(".x%x.c create text %d %d -anchor nw -fill %s -text {%s}",
1585 glist_getcanvas(glist), xloc, yloc, colorstring, buf);
1586 sys_vgui(" -font -*-courier-bold--normal--%d-*",
1587 sys_hostfontsize(glist_getfont(glist)));
1588 sys_vgui(" -tags drawnumber%x\n", data);
1589 }
1590 else sys_vgui(".x%x.c delete drawnumber%x\n", glist_getcanvas(glist), data);
1591}
1592
1593static float drawnumber_motion_ycumulative;
1594static t_glist *drawnumber_motion_glist;
1595static t_gobj *drawnumber_motion_gobj;
1596static t_word *drawnumber_motion_wp;
1597static t_template *drawnumber_motion_template;
1598
1599 /* LATER protect against the template changing or the scalar disappearing
1600 probably by attaching a gpointer here ... */
1601
1602static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy)
1603{
1604 t_drawnumber *x = (t_drawnumber *)z;
1605 t_fielddesc *f = &x->x_value;
1606 drawnumber_motion_ycumulative -= dy;
1607 template_setfloat(drawnumber_motion_template,
1608 f->fd_un.fd_varsym,
1609 drawnumber_motion_wp,
1610 drawnumber_motion_ycumulative,
1611 1);
1612 glist_redrawitem(drawnumber_motion_glist, drawnumber_motion_gobj);
1613}
1614
1615static int drawnumber_click(t_gobj *z, t_glist *glist,
1616 t_scalar *sc, t_template *template, float basex, float basey,
1617 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1618{
1619 t_drawnumber *x = (t_drawnumber *)z;
1620 int x1, y1, x2, y2;
1621 t_word *data = sc->sc_vec;
1622 drawnumber_getrect(z, glist,
1623 sc->sc_vec, template, basex, basey,
1624 &x1, &y1, &x2, &y2);
1625 if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
1626 && x->x_value.fd_var)
1627 {
1628 if (doit)
1629 {
1630 drawnumber_motion_glist = glist;
1631 drawnumber_motion_gobj = &sc->sc_gobj;
1632 drawnumber_motion_wp = data;
1633 drawnumber_motion_template = template;
1634 drawnumber_motion_ycumulative =
1635 fielddesc_getfloat(&x->x_value, template, data, 0);
1636 glist_grab(glist, z, drawnumber_motion, 0, xpix, ypix);
1637 }
1638 return (1);
1639 }
1640 else return (0);
1641}
1642
1643t_parentwidgetbehavior drawnumber_widgetbehavior =
1644{
1645 drawnumber_getrect,
1646 drawnumber_displace,
1647 drawnumber_select,
1648 drawnumber_activate,
1649 drawnumber_vis,
1650 drawnumber_click,
1651};
1652
1653static void drawnumber_free(t_drawnumber *x)
1654{
1655}
1656
1657static void drawnumber_setup(void)
1658{
1659 drawnumber_class = class_new(gensym("drawnumber"),
1660 (t_newmethod)drawnumber_new, (t_method)drawnumber_free,
1661 sizeof(t_drawnumber), CLASS_NOINLET, A_GIMME, 0);
1662 class_setdrawcommand(drawnumber_class);
1663 class_addcreator((t_newmethod)drawnumber_new, gensym("drawsymbol"),
1664 A_GIMME, 0);
1665 class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
1666}
1667
1668/* ---------------------- setup function ---------------------------- */
1669
1670void g_template_setup(void)
1671{
1672 template_setup();
1673 gtemplate_setup();
1674 template_float.t_pdobj = template_class;
1675 curve_setup();
1676 plot_setup();
1677 drawnumber_setup();
1678}
1679
1680/* Copyright (c) 1997-1999 Miller Puckette.
1681* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1682* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1683
1684#include <stdlib.h>
1685#include <string.h>
1686#include <stdio.h>
1687
1688#include "m_pd.h"
1689#include "s_stuff.h" /* for sys_hostfontsize */
1690#include "g_canvas.h"
1691
1692/*
1693This file contains text objects you would put in a canvas to define a
1694template. Templates describe objects of type "array" (g_array.c) and
1695"scalar" (g_scalar.c).
1696*/
1697
1698/* T.Grill - changed the _template.t_pd member to t_pdobj to avoid name clashes
1699with the t_pd type */
1700
1701 /* the structure of a "struct" object (also the obsolete "gtemplate"
1702 you get when using the name "template" in a box.) */
1703
1704struct _gtemplate
1705{
1706 t_object x_obj;
1707 t_template *x_template;
1708 t_canvas *x_owner;
1709 t_symbol *x_sym;
1710 struct _gtemplate *x_next;
1711 int x_argc;
1712 t_atom *x_argv;
1713};
1714
1715/* ---------------- forward definitions ---------------- */
1716
1717static void template_conformarray(t_template *tfrom, t_template *tto,
1718 int *conformaction, t_array *a);
1719static void template_conformglist(t_template *tfrom, t_template *tto,
1720 t_glist *glist, int *conformaction);
1721
1722/* ---------------------- storage ------------------------- */
1723
1724static t_class *gtemplate_class;
1725static t_class *template_class;
1726
1727/* there's a pre-defined "float" template. LATER should we bind this
1728to a symbol such as "pd-float"??? */
1729
1730static t_dataslot template_float_vec =
1731{
1732 DT_FLOAT,
1733 &s_y,
1734 &s_
1735};
1736
1737static t_template template_float =
1738{
1739 0, /* class -- fill in in setup routine */
1740 0, /* list of "struct"/t_gtemplate objects */
1741 &s_float, /* name */
1742 1, /* number of items */
1743 &template_float_vec
1744};
1745
1746 /* return true if two dataslot definitions match */
1747static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2,
1748 int nametoo)
1749{
1750 return ((!nametoo || ds1->ds_name == ds2->ds_name) &&
1751 ds1->ds_type == ds2->ds_type &&
1752 (ds1->ds_type != DT_ARRAY ||
1753 ds1->ds_arraytemplate == ds2->ds_arraytemplate));
1754}
1755
1756/* -- templates, the active ingredient in gtemplates defined below. ------- */
1757
1758t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
1759{
1760 t_template *x = (t_template *)pd_new(template_class);
1761 x->t_n = 0;
1762 x->t_vec = (t_dataslot *)t_getbytes(0);
1763 while (argc > 0)
1764 {
1765 int newtype, oldn, newn;
1766 t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
1767 if (argc < 2 || argv[0].a_type != A_SYMBOL ||
1768 argv[1].a_type != A_SYMBOL)
1769 goto bad;
1770 newtypesym = argv[0].a_w.w_symbol;
1771 newname = argv[1].a_w.w_symbol;
1772 if (newtypesym == &s_float)
1773 newtype = DT_FLOAT;
1774 else if (newtypesym == &s_symbol)
1775 newtype = DT_SYMBOL;
1776 else if (newtypesym == &s_list)
1777 newtype = DT_LIST;
1778 else if (newtypesym == gensym("array"))
1779 {
1780 if (argc < 3 || argv[2].a_type != A_SYMBOL)
1781 {
1782 pd_error(x, "array lacks element template or name");
1783 goto bad;
1784 }
1785 newarraytemplate = canvas_makebindsym(argv[2].a_w.w_symbol);
1786 newtype = DT_ARRAY;
1787 argc--;
1788 argv++;
1789 }
1790 else
1791 {
1792 pd_error(x, "%s: no such type", newtypesym->s_name);
1793 return (0);
1794 }
1795 newn = (oldn = x->t_n) + 1;
1796 x->t_vec = (t_dataslot *)t_resizebytes(x->t_vec,
1797 oldn * sizeof(*x->t_vec), newn * sizeof(*x->t_vec));
1798 x->t_n = newn;
1799 x->t_vec[oldn].ds_type = newtype;
1800 x->t_vec[oldn].ds_name = newname;
1801 x->t_vec[oldn].ds_arraytemplate = newarraytemplate;
1802 bad:
1803 argc -= 2; argv += 2;
1804 }
1805 if (templatesym->s_name)
1806 {
1807 x->t_sym = templatesym;
1808 pd_bind(&x->t_pdobj, x->t_sym);
1809 }
1810 else x->t_sym = templatesym;
1811 return (x);
1812}
1813
1814int template_size(t_template *x)
1815{
1816 return (x->t_n * sizeof(t_word));
1817}
1818
1819int template_find_field(t_template *x, t_symbol *name, int *p_onset,
1820 int *p_type, t_symbol **p_arraytype)
1821{
1822 t_template *t;
1823 int i, n;
1824 if (!x)
1825 {
1826 bug("template_find_field");
1827 return (0);
1828 }
1829 n = x->t_n;
1830 for (i = 0; i < n; i++)
1831 if (x->t_vec[i].ds_name == name)
1832 {
1833 *p_onset = i * sizeof(t_word);
1834 *p_type = x->t_vec[i].ds_type;
1835 *p_arraytype = x->t_vec[i].ds_arraytemplate;
1836 return (1);
1837 }
1838 return (0);
1839}
1840
1841t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
1842 int loud)
1843{
1844 int onset, type;
1845 t_symbol *arraytype;
1846 t_sample val = 0;
1847 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
1848 {
1849 if (type == DT_FLOAT)
1850 val = *(t_sample *)(((char *)wp) + onset);
1851 else if (loud) error("%s.%s: not a number",
1852 x->t_sym->s_name, fieldname->s_name);
1853 }
1854 else if (loud) error("%s.%s: no such field",
1855 x->t_sym->s_name, fieldname->s_name);
1856 return (fixtof(val));
1857}
1858
1859void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
1860 t_float f, int loud)
1861{
1862 int onset, type;
1863 t_symbol *arraytype;
1864 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
1865 {
1866 if (type == DT_FLOAT)
1867 *(t_sample *)(((char *)wp) + onset) = ftofix(f);
1868 else if (loud) error("%s.%s: not a number",
1869 x->t_sym->s_name, fieldname->s_name);
1870 }
1871 else if (loud) error("%s.%s: no such field",
1872 x->t_sym->s_name, fieldname->s_name);
1873}
1874
1875t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
1876 int loud)
1877{
1878 int onset, type;
1879 t_symbol *arraytype;
1880 t_symbol *val = &s_;
1881 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
1882 {
1883 if (type == DT_SYMBOL)
1884 val = *(t_symbol **)(((char *)wp) + onset);
1885 else if (loud) error("%s.%s: not a symbol",
1886 x->t_sym->s_name, fieldname->s_name);
1887 }
1888 else if (loud) error("%s.%s: no such field",
1889 x->t_sym->s_name, fieldname->s_name);
1890 return (val);
1891}
1892
1893void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
1894 t_symbol *s, int loud)
1895{
1896 int onset, type;
1897 t_symbol *arraytype;
1898 if (template_find_field(x, fieldname, &onset, &type, &arraytype))
1899 {
1900 if (type == DT_SYMBOL)
1901 *(t_symbol **)(((char *)wp) + onset) = s;
1902 else if (loud) error("%s.%s: not a symbol",
1903 x->t_sym->s_name, fieldname->s_name);
1904 }
1905 else if (loud) error("%s.%s: no such field",
1906 x->t_sym->s_name, fieldname->s_name);
1907}
1908
1909 /* stringent check to see if a "saved" template, x2, matches the current
1910 one (x1). It's OK if x1 has additional scalar elements but not (yet)
1911 arrays or lists. This is used for reading in "data files". */
1912int template_match(t_template *x1, t_template *x2)
1913{
1914 int i;
1915 if (x1->t_n < x2->t_n)
1916 return (0);
1917 for (i = x2->t_n; i < x1->t_n; i++)
1918 {
1919 if (x1->t_vec[i].ds_type == DT_ARRAY ||
1920 x1->t_vec[i].ds_type == DT_LIST)
1921 return (0);
1922 }
1923 if (x2->t_n > x1->t_n)
1924 post("add elements...");
1925 for (i = 0; i < x2->t_n; i++)
1926 if (!dataslot_matches(&x1->t_vec[i], &x2->t_vec[i], 1))
1927 return (0);
1928 return (1);
1929}
1930
1931/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
1932
1933/* the following routines handle updating scalars to agree with changes
1934in their template. The old template is assumed to be the "installed" one
1935so we can delete old items; but making new ones we have to avoid scalar_new
1936which would make an old one whereas we will want a new one (but whose array
1937elements might still be old ones.
1938 LATER deal with graphics updates too... */
1939
1940 /* conform the word vector of a scalar to the new template */
1941static void template_conformwords(t_template *tfrom, t_template *tto,
1942 int *conformaction, t_word *wfrom, t_word *wto)
1943{
1944 int nfrom = tfrom->t_n, nto = tto->t_n, i;
1945 for (i = 0; i < nto; i++)
1946 {
1947 if (conformaction[i] >= 0)
1948 {
1949 /* we swap the two, in case it's an array or list, so that
1950 when "wfrom" is deleted the old one gets cleaned up. */
1951 t_word wwas = wto[i];
1952 wto[i] = wfrom[conformaction[i]];
1953 wfrom[conformaction[i]] = wwas;
1954 }
1955 }
1956}
1957
1958 /* conform a scalar, recursively conforming sublists and arrays */
1959static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
1960 int *conformaction, t_glist *glist, t_scalar *scfrom)
1961{
1962 t_scalar *x;
1963 t_gpointer gp;
1964 int nto = tto->t_n, nfrom = tfrom->t_n, i;
1965 t_template *scalartemplate;
1966 /* post("conform scalar"); */
1967 /* possibly replace the scalar */
1968 if (scfrom->sc_template == tfrom->t_sym)
1969 {
1970 /* see scalar_new() for comment about the gpointer. */
1971 gpointer_init(&gp);
1972 x = (t_scalar *)getbytes(sizeof(t_scalar) +
1973 (tto->t_n - 1) * sizeof(*x->sc_vec));
1974 x->sc_gobj.g_pd = scalar_class;
1975 x->sc_template = tfrom->t_sym;
1976 gpointer_setglist(&gp, glist, x);
1977 /* Here we initialize to the new template, but array and list
1978 elements will still belong to old template. */
1979 word_init(x->sc_vec, tto, &gp);
1980
1981 template_conformwords(tfrom, tto, conformaction,
1982 scfrom->sc_vec, x->sc_vec);
1983
1984 /* replace the old one with the new one in the list */
1985 if (glist->gl_list == &scfrom->sc_gobj)
1986 {
1987 glist->gl_list = &x->sc_gobj;
1988 x->sc_gobj.g_next = scfrom->sc_gobj.g_next;
1989 }
1990 else
1991 {
1992 t_gobj *y, *y2;
1993 for (y = glist->gl_list; y2 = y->g_next; y = y2)
1994 if (y2 == &scfrom->sc_gobj)
1995 {
1996 x->sc_gobj.g_next = y2->g_next;
1997 y->g_next = &x->sc_gobj;
1998 goto nobug;
1999 }
2000 bug("template_conformscalar");
2001 nobug: ;
2002 }
2003 /* burn the old one */
2004 pd_free(&scfrom->sc_gobj.g_pd);
2005 }
2006 else x = scfrom;
2007 scalartemplate = template_findbyname(x->sc_template);
2008 /* convert all array elements and sublists */
2009 for (i = 0; i < scalartemplate->t_n; i++)
2010 {
2011 t_dataslot *ds = scalartemplate->t_vec + i;
2012 if (ds->ds_type == DT_LIST)
2013 {
2014 t_glist *gl2 = x->sc_vec[i].w_list;
2015 template_conformglist(tfrom, tto, gl2, conformaction);
2016 }
2017 else if (ds->ds_type == DT_ARRAY)
2018 {
2019 template_conformarray(tfrom, tto, conformaction,
2020 x->sc_vec[i].w_array);
2021 }
2022 }
2023 return (x);
2024}
2025
2026 /* conform an array, recursively conforming sublists and arrays */
2027static void template_conformarray(t_template *tfrom, t_template *tto,
2028 int *conformaction, t_array *a)
2029{
2030 int i;
2031 if (a->a_templatesym == tfrom->t_sym)
2032 {
2033 /* the array elements must all be conformed */
2034 int oldelemsize = sizeof(t_word) * tfrom->t_n,
2035 newelemsize = sizeof(t_word) * tto->t_n;
2036 char *newarray = getbytes(sizeof(t_word) * tto->t_n * a->a_n);
2037 char *oldarray = a->a_vec;
2038 if (a->a_elemsize != oldelemsize)
2039 bug("template_conformarray");
2040 for (i = 0; i < a->a_n; i++)
2041 {
2042 t_word *wp = (t_word *)(newarray + newelemsize * i);
2043 word_init(wp, tto, &a->a_gp);
2044 template_conformwords(tfrom, tto, conformaction,
2045 (t_word *)(oldarray + oldelemsize * i), wp);
2046 }
2047 }
2048 bug("template_conformarray: this part not written");
2049 /* go through item by item conforming subarrays and sublists... */
2050}
2051
2052 /* this routine searches for every scalar in the glist that belongs
2053 to the "from" template and makes it belong to the "to" template. Descend
2054 glists recursively.
2055 We don't handle redrawing here; this is to be filled in LATER... */
2056
2057static void template_conformglist(t_template *tfrom, t_template *tto,
2058 t_glist *glist, int *conformaction)
2059{
2060 t_gobj *g;
2061 /* post("conform glist %s", glist->gl_name->s_name); */
2062 for (g = glist->gl_list; g; g = g->g_next)
2063 {
2064 if (pd_class(&g->g_pd) == scalar_class)
2065 g = &template_conformscalar(tfrom, tto, conformaction,
2066 glist, (t_scalar *)g)->sc_gobj;
2067 else if (pd_class(&g->g_pd) == canvas_class)
2068 template_conformglist(tfrom, tto, (t_glist *)g, conformaction);
2069 }
2070}
2071
2072 /* globally conform all scalars from one template to another */
2073void template_conform(t_template *tfrom, t_template *tto)
2074{
2075 int nto = tto->t_n, nfrom = tfrom->t_n, i, j,
2076 *conformaction = (int *)getbytes(sizeof(int) * nto),
2077 *conformedfrom = (int *)getbytes(sizeof(int) * nfrom), doit = 0;
2078 for (i = 0; i < nto; i++)
2079 conformaction[i] = -1;
2080 for (i = 0; i < nfrom; i++)
2081 conformedfrom[i] = 0;
2082 for (i = 0; i < nto; i++)
2083 {
2084 t_dataslot *dataslot = &tto->t_vec[i];
2085 for (j = 0; j < nfrom; j++)
2086 {
2087 t_dataslot *dataslot2 = &tfrom->t_vec[j];
2088 if (dataslot_matches(dataslot, dataslot2, 1))
2089 {
2090 conformaction[i] = j;
2091 conformedfrom[j] = 1;
2092 }
2093 }
2094 }
2095 for (i = 0; i < nto; i++)
2096 if (conformaction[i] < 0)
2097 {
2098 t_dataslot *dataslot = &tto->t_vec[i];
2099 for (j = 0; j < nfrom; j++)
2100 if (!conformedfrom[j] &&
2101 dataslot_matches(dataslot, &tfrom->t_vec[j], 1))
2102 {
2103 conformaction[i] = j;
2104 conformedfrom[j] = 1;
2105 }
2106 }
2107 if (nto != nfrom)
2108 doit = 1;
2109 else for (i = 0; i < nto; i++)
2110 if (conformaction[i] != i)
2111 doit = 1;
2112
2113 if (doit)
2114 {
2115 t_glist *gl;
2116 /* post("conforming template '%s' to new structure",
2117 tfrom->t_sym->s_name);
2118 for (i = 0; i < nto; i++)
2119 post("... %d", conformaction[i]); */
2120 for (gl = canvas_list; gl; gl = gl->gl_next)
2121 template_conformglist(tfrom, tto, gl, conformaction);
2122 }
2123 freebytes(conformaction, sizeof(int) * nto);
2124 freebytes(conformedfrom, sizeof(int) * nfrom);
2125}
2126
2127t_template *template_findbyname(t_symbol *s)
2128{
2129 int i;
2130 if (s == &s_float)
2131 return (&template_float);
2132 else return ((t_template *)pd_findbyclass(s, template_class));
2133}
2134
2135t_canvas *template_findcanvas(t_template *template)
2136{
2137 t_gtemplate *gt;
2138 if (!template)
2139 bug("template_findcanvas");
2140 if (!(gt = template->t_list))
2141 return (0);
2142 return (gt->x_owner);
2143 /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
2144}
2145
2146 /* call this when reading a patch from a file to declare what templates
2147 we'll need. If there's already a template, check if it matches.
2148 If it doesn't it's still OK as long as there are no "struct" (gtemplate)
2149 objects hanging from it; we just conform everyone to the new template.
2150 If there are still struct objects belonging to the other template, we're
2151 in trouble. LATER we'll figure out how to conform the new patch's objects
2152 to the pre-existing struct. */
2153static void *template_usetemplate(void *dummy, t_symbol *s,
2154 int argc, t_atom *argv)
2155{
2156 t_template *x;
2157 t_symbol *templatesym =
2158 canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
2159 if (!argc)
2160 return (0);
2161 argc--; argv++;
2162 /* check if there's already a template by this name. */
2163 if ((x = (t_template *)pd_findbyclass(templatesym, template_class)))
2164 {
2165 t_template *y = template_new(&s_, argc, argv);
2166 /* If the new template is the same as the old one,
2167 there's nothing to do. */
2168 if (!template_match(x, y))
2169 {
2170 /* Are there "struct" objects upholding this template? */
2171 if (x->t_list)
2172 {
2173 /* don't know what to do here! */
2174 error("%s: template mismatch",
2175 templatesym->s_name);
2176 }
2177 else
2178 {
2179 /* conform everyone to the new template */
2180 template_conform(x, y);
2181 pd_free(&x->t_pdobj);
2182 template_new(templatesym, argc, argv);
2183 }
2184 }
2185 pd_free(&y->t_pdobj);
2186 }
2187 /* otherwise, just make one. */
2188 else template_new(templatesym, argc, argv);
2189 return (0);
2190}
2191
2192 /* here we assume someone has already cleaned up all instances of this. */
2193void template_free(t_template *x)
2194{
2195 if (*x->t_sym->s_name)
2196 pd_unbind(&x->t_pdobj, x->t_sym);
2197 t_freebytes(x->t_vec, x->t_n * sizeof(*x->t_vec));
2198}
2199
2200static void template_setup(void)
2201{
2202 template_class = class_new(gensym("template"), 0, (t_method)template_free,
2203 sizeof(t_template), CLASS_PD, 0);
2204 class_addmethod(pd_canvasmaker, (t_method)template_usetemplate,
2205 gensym("struct"), A_GIMME, 0);
2206
2207}
2208
2209/* ---------------- gtemplates. One per canvas. ----------- */
2210
2211/* this is a "text" object that searches for, and if necessary creates,
2212a "template" (above). Other objects in the canvas then can give drawing
2213instructions for the template. The template doesn't go away when the
2214gtemplate is deleted, so that you can replace it with
2215another one to add new fields, for example. */
2216
2217static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
2218{
2219 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
2220 t_template *t = template_findbyname(sym);
2221 int i;
2222 t_symbol *sx = gensym("x");
2223 x->x_owner = canvas_getcurrent();
2224 x->x_next = 0;
2225 x->x_sym = sym;
2226 x->x_argc = argc;
2227 x->x_argv = (t_atom *)getbytes(argc * sizeof(t_atom));
2228 for (i = 0; i < argc; i++)
2229 x->x_argv[i] = argv[i];
2230
2231 /* already have a template by this name? */
2232 if (t)
2233 {
2234 x->x_template = t;
2235 /* if it's already got a "struct" or "gtemplate" object we
2236 just tack this one to the end of the list and leave it
2237 there. */
2238 if (t->t_list)
2239 {
2240 t_gtemplate *x2, *x3;
2241 for (x2 = x->x_template->t_list; x3 = x2->x_next; x2 = x3)
2242 ;
2243 x2->x_next = x;
2244 post("template %s: warning: already exists.", sym->s_name);
2245 }
2246 else
2247 {
2248 /* if there's none, we just replace the template with
2249 our own and conform it. */
2250 t_template *y = template_new(&s_, argc, argv);
2251 /* Unless the new template is different from the old one,
2252 there's nothing to do. */
2253 if (!template_match(t, y))
2254 {
2255 /* conform everyone to the new template */
2256 template_conform(t, y);
2257 pd_free(&t->t_pdobj);
2258 t = template_new(sym, argc, argv);
2259 }
2260 pd_free(&y->t_pdobj);
2261 t->t_list = x;
2262 }
2263 }
2264 else
2265 {
2266 /* otherwise make a new one and we're the only struct on it. */
2267 x->x_template = t = template_new(sym, argc, argv);
2268 t->t_list = x;
2269 }
2270 return (x);
2271}
2272
2273static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv)
2274{
2275 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
2276 t_symbol *sym = atom_getsymbolarg(0, argc, argv);
2277 if (argc >= 1)
2278 argc--; argv++;
2279 return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
2280}
2281
2282 /* old version (0.34) -- delete 2003 or so */
2283static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv)
2284{
2285 t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
2286 t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->gl_name);
2287 static int warned;
2288 if (!warned)
2289 {
2290 post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
2291 sym->s_name);
2292 warned = 1;
2293 }
2294 return (gtemplate_donew(sym, argc, argv));
2295}
2296
2297t_template *gtemplate_get(t_gtemplate *x)
2298{
2299 return (x->x_template);
2300}
2301
2302static void gtemplate_free(t_gtemplate *x)
2303{
2304 /* get off the template's list */
2305 t_template *t = x->x_template;
2306 if (x == t->t_list)
2307 {
2308 if (x->x_next)
2309 {
2310 /* if we were first on the list, and there are others on
2311 the list, make a new template corresponding to the new
2312 first-on-list and replace teh existing template with it. */
2313 t_template *z = template_new(&s_, x->x_argc, x->x_argv);
2314 template_conform(t, z);
2315 pd_free(&t->t_pdobj);
2316 pd_free(&z->t_pdobj);
2317 z = template_new(x->x_sym, x->x_argc, x->x_argv);
2318 z->t_list = x->x_next;
2319 }
2320 else t->t_list = 0;
2321 }
2322 else
2323 {
2324 t_gtemplate *x2, *x3;
2325 for (x2 = t->t_list; x3 = x2->x_next; x2 = x3)
2326 {
2327 if (x == x3)
2328 {
2329 x2->x_next = x3->x_next;
2330 break;
2331 }
2332 }
2333 }
2334 freebytes(x->x_argv, sizeof(t_atom) * x->x_argc);
2335}
2336
2337static void gtemplate_setup(void)
2338{
2339 gtemplate_class = class_new(gensym("struct"),
2340 (t_newmethod)gtemplate_new, (t_method)gtemplate_free,
2341 sizeof(t_gtemplate), CLASS_NOINLET, A_GIMME, 0);
2342 class_addcreator((t_newmethod)gtemplate_new_old, gensym("template"),
2343 A_GIMME, 0);
2344}
2345
2346/* --------------- FIELD DESCRIPTORS ---------------------- */
2347
2348/* a field descriptor can hold a constant or a variable; if a variable,
2349it's the name of a field in the template we belong to. LATER, we might
2350want to cache the offset of the field so we don't have to search for it
2351every single time we draw the object.
2352*/
2353
2354typedef struct _fielddesc
2355{
2356 char fd_type; /* LATER consider removing this? */
2357 char fd_var;
2358 union
2359 {
2360 t_float fd_float; /* the field is a constant float */
2361 t_symbol *fd_symbol; /* the field is a constant symbol */
2362 t_symbol *fd_varsym; /* the field is variable and this is the name */
2363 } fd_un;
2364} t_fielddesc;
2365
2366#define FIELDDESC_SETFLOAT(x, f) \
2367 ((x)->fd_type = A_FLOAT, (x)->fd_var = 0, (x)->fd_un.fd_float = (f))
2368#define FIELDDESC_SETSYMBOL(x, s) \
2369 ((x)->fd_type = A_SYMBOL, (x)->fd_var = 0, (x)->fd_un.fd_symbol = (s))
2370#define FIELDDESC_SETVAR(x, s, type) \
2371 ((x)->fd_type = type, (x)->fd_var = 1, (x)->fd_un.fd_varsym = (s))
2372
2373#define CLOSED 1
2374#define BEZ 2
2375#define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
2376
2377static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
2378{
2379 if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
2380 else if (argv->a_type == A_SYMBOL)
2381 FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_FLOAT);
2382 else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
2383}
2384
2385static void fielddesc_setarrayarg(t_fielddesc *fd, int argc, t_atom *argv)
2386{
2387 if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
2388 else if (argv->a_type == A_SYMBOL)
2389 FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_ARRAY);
2390 else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
2391}
2392
2393static t_float fielddesc_getfloat(t_fielddesc *f, t_template *template,
2394 t_word *wp, int loud)
2395{
2396 if (f->fd_type == A_FLOAT)
2397 {
2398 if (f->fd_var)
2399 return (template_getfloat(template, f->fd_un.fd_varsym, wp, loud));
2400 else return (f->fd_un.fd_float);
2401 }
2402 else
2403 {
2404 if (loud)
2405 error("symbolic data field used as number");
2406 return (0);
2407 }
2408}
2409
2410static t_symbol *fielddesc_getsymbol(t_fielddesc *f, t_template *template,
2411 t_word *wp, int loud)
2412{
2413 if (f->fd_type == A_SYMBOL)
2414 {
2415 if (f->fd_var)
2416 return(template_getsymbol(template, f->fd_un.fd_varsym, wp, loud));
2417 else return (f->fd_un.fd_symbol);
2418 }
2419 else
2420 {
2421 if (loud)
2422 error("numeric data field used as symbol");
2423 return (&s_);
2424 }
2425}
2426
2427/* ---------------- curves and polygons (joined segments) ---------------- */
2428
2429/*
2430curves belong to templates and describe how the data in the template are to
2431be drawn. The coordinates of the curve (and other display features) can
2432be attached to fields in the template.
2433*/
2434
2435t_class *curve_class;
2436
2437typedef struct _curve
2438{
2439 t_object x_obj;
2440 int x_flags; /* CLOSED and/or BEZ */
2441 t_fielddesc x_fillcolor;
2442 t_fielddesc x_outlinecolor;
2443 t_fielddesc x_width;
2444 int x_npoints;
2445 t_fielddesc *x_vec;
2446} t_curve;
2447
2448static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
2449{
2450 t_curve *x = (t_curve *)pd_new(curve_class);
2451 char *classname = classsym->s_name;
2452 int flags = 0;
2453 int nxy, i;
2454 t_fielddesc *fd;
2455 if (classname[0] == 'f')
2456 {
2457 classname += 6;
2458 flags |= CLOSED;
2459 if (argc) fielddesc_setfloatarg(&x->x_fillcolor, argc--, argv++);
2460 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
2461 }
2462 else classname += 4;
2463 if (classname[0] == 'c') flags |= BEZ;
2464 x->x_flags = flags;
2465 if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
2466 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
2467 if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
2468 else FIELDDESC_SETFLOAT(&x->x_width, 1);
2469 if (argc < 0) argc = 0;
2470 nxy = (argc + (argc & 1));
2471 x->x_npoints = (nxy>>1);
2472 x->x_vec = (t_fielddesc *)t_getbytes(nxy * sizeof(t_fielddesc));
2473 for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++)
2474 fielddesc_setfloatarg(fd, 1, argv);
2475 if (argc & 1) FIELDDESC_SETFLOAT(fd, 0);
2476
2477 return (x);
2478}
2479
2480/* -------------------- widget behavior for curve ------------ */
2481
2482static void curve_getrect(t_gobj *z, t_glist *glist,
2483 t_word *data, t_template *template, float basex, float basey,
2484 int *xp1, int *yp1, int *xp2, int *yp2)
2485{
2486 t_curve *x = (t_curve *)z;
2487 int i, n = x->x_npoints;
2488 t_fielddesc *f = x->x_vec;
2489 int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
2490 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
2491 {
2492 int xloc = glist_xtopixels(glist,
2493 basex + fielddesc_getfloat(f, template, data, 0));
2494 int yloc = glist_ytopixels(glist,
2495 basey + fielddesc_getfloat(f+1, template, data, 0));
2496 if (xloc < x1) x1 = xloc;
2497 if (xloc > x2) x2 = xloc;
2498 if (yloc < y1) y1 = yloc;
2499 if (yloc > y2) y2 = yloc;
2500 }
2501 *xp1 = x1;
2502 *yp1 = y1;
2503 *xp2 = x2;
2504 *yp2 = y2;
2505}
2506
2507static void curve_displace(t_gobj *z, t_glist *glist,
2508 t_word *data, t_template *template, float basex, float basey,
2509 int dx, int dy)
2510{
2511 /* refuse */
2512}
2513
2514static void curve_select(t_gobj *z, t_glist *glist,
2515 t_word *data, t_template *template, float basex, float basey,
2516 int state)
2517{
2518 /* fill in later */
2519}
2520
2521static void curve_activate(t_gobj *z, t_glist *glist,
2522 t_word *data, t_template *template, float basex, float basey,
2523 int state)
2524{
2525 /* fill in later */
2526}
2527
2528static int rangecolor(int n) /* 0 to 9 in 5 steps */
2529{
2530 int n2 = n/2; /* 0 to 4 */
2531 int ret = (n2 << 6); /* 0 to 256 in 5 steps */
2532 if (ret > 255) ret = 255;
2533 return (ret);
2534}
2535
2536static void numbertocolor(int n, char *s)
2537{
2538 int red, blue, green;
2539 if (n < 0) n = 0;
2540 red = n / 100;
2541 blue = ((n / 10) % 10);
2542 green = n % 10;
2543 sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(red), rangecolor(blue),
2544 rangecolor(green));
2545}
2546
2547static void curve_vis(t_gobj *z, t_glist *glist,
2548 t_word *data, t_template *template, float basex, float basey,
2549 int vis)
2550{
2551 t_curve *x = (t_curve *)z;
2552 int i, n = x->x_npoints;
2553 t_fielddesc *f = x->x_vec;
2554
2555 if (vis)
2556 {
2557 if (n > 1)
2558 {
2559 int flags = x->x_flags, closed = (flags & CLOSED);
2560 float width = fielddesc_getfloat(&x->x_width, template, data, 1);
2561 char outline[20], fill[20];
2562 if (width < 1) width = 1;
2563 numbertocolor(
2564 fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
2565 outline);
2566 if (flags & CLOSED)
2567 {
2568 numbertocolor(
2569 fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
2570 fill);
2571 sys_vgui(".x%x.c create polygon\\\n",
2572 glist_getcanvas(glist));
2573 }
2574 else sys_vgui(".x%x.c create line\\\n",
2575 glist_getcanvas(glist));
2576 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
2577 {
2578 float xloc = glist_xtopixels(glist,
2579 basex + fielddesc_getfloat(f, template, data, 1));
2580 float yloc = glist_ytopixels(glist,
2581 basey + fielddesc_getfloat(f+1, template, data, 1));
2582 sys_vgui("%d %d\\\n", (int)xloc, (int)yloc);
2583 }
2584 sys_vgui("-width %f\\\n",
2585 fielddesc_getfloat(&x->x_width, template, data, 1));
2586 if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n",
2587 fill, outline);
2588 else sys_vgui("-fill %s\\\n", outline);
2589 if (flags & BEZ) sys_vgui("-smooth 1\\\n");
2590 sys_vgui("-tags curve%x\n", data);
2591 }
2592 else post("warning: curves need at least two points to be graphed");
2593 }
2594 else
2595 {
2596 if (n > 1) sys_vgui(".x%x.c delete curve%x\n",
2597 glist_getcanvas(glist), data);
2598 }
2599}
2600
2601static int curve_motion_field;
2602static float curve_motion_xcumulative;
2603static float curve_motion_xbase;
2604static float curve_motion_xper;
2605static float curve_motion_ycumulative;
2606static float curve_motion_ybase;
2607static float curve_motion_yper;
2608static t_glist *curve_motion_glist;
2609static t_gobj *curve_motion_gobj;
2610static t_word *curve_motion_wp;
2611static t_template *curve_motion_template;
2612
2613 /* LATER protect against the template changing or the scalar disappearing
2614 probably by attaching a gpointer here ... */
2615
2616static void curve_motion(void *z, t_floatarg dx, t_floatarg dy)
2617{
2618 t_curve *x = (t_curve *)z;
2619 t_fielddesc *f = x->x_vec + curve_motion_field;
2620 curve_motion_xcumulative += dx;
2621 curve_motion_ycumulative += dy;
2622 if (f->fd_var)
2623 {
2624 template_setfloat(curve_motion_template,
2625 f->fd_un.fd_varsym,
2626 curve_motion_wp,
2627 curve_motion_xbase + curve_motion_xcumulative * curve_motion_xper,
2628 1);
2629 }
2630 if ((f+1)->fd_var)
2631 {
2632 template_setfloat(curve_motion_template,
2633 (f+1)->fd_un.fd_varsym,
2634 curve_motion_wp,
2635 curve_motion_ybase + curve_motion_ycumulative * curve_motion_yper,
2636 1);
2637 }
2638 glist_redrawitem(curve_motion_glist, curve_motion_gobj);
2639}
2640
2641static int curve_click(t_gobj *z, t_glist *glist,
2642 t_scalar *sc, t_template *template, float basex, float basey,
2643 int xpix, int ypix, int shift, int alt, int dbl, int doit)
2644{
2645 t_curve *x = (t_curve *)z;
2646 int i, n = x->x_npoints;
2647 int bestn = -1;
2648 int besterror = 0x7fffffff;
2649 t_fielddesc *f = x->x_vec;
2650 t_word *data = sc->sc_vec;
2651 for (i = 0, f = x->x_vec; i < n; i++, f += 2)
2652 {
2653 int xloc = glist_xtopixels(glist,
2654 basex + fielddesc_getfloat(f, template, data, 0));
2655 int yloc = glist_ytopixels(glist,
2656 basey + fielddesc_getfloat(f+1, template, data, 0));
2657 int xerr = xloc - xpix, yerr = yloc - ypix;
2658 if (!f->fd_var && !(f+1)->fd_var)
2659 continue;
2660 if (xerr < 0)
2661 xerr = -xerr;
2662 if (yerr < 0)
2663 yerr = -yerr;
2664 if (yerr > xerr)
2665 xerr = yerr;
2666 if (xerr < besterror)
2667 {
2668 besterror = xerr;
2669 bestn = i;
2670 curve_motion_xbase = fielddesc_getfloat(f, template, data, 0);
2671 curve_motion_ybase = fielddesc_getfloat(f+1, template, data, 0);
2672 }
2673 }
2674 if (besterror > 10)
2675 return (0);
2676 if (doit)
2677 {
2678 curve_motion_xper = glist_pixelstox(glist, 1)
2679 - glist_pixelstox(glist, 0);
2680 curve_motion_yper = glist_pixelstoy(glist, 1)
2681 - glist_pixelstoy(glist, 0);
2682 curve_motion_xcumulative = curve_motion_ycumulative = 0;
2683 curve_motion_glist = glist;
2684 curve_motion_gobj = &sc->sc_gobj;
2685 curve_motion_wp = data;
2686 curve_motion_field = 2*bestn;
2687 curve_motion_template = template;
2688 glist_grab(glist, z, curve_motion, 0, xpix, ypix);
2689 }
2690 return (1);
2691}
2692
2693t_parentwidgetbehavior curve_widgetbehavior =
2694{
2695 curve_getrect,
2696 curve_displace,
2697 curve_select,
2698 curve_activate,
2699 curve_vis,
2700 curve_click,
2701};
2702
2703static void curve_free(t_curve *x)
2704{
2705 t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec));
2706}
2707
2708static void curve_setup(void)
2709{
2710 curve_class = class_new(gensym("drawpolygon"), (t_newmethod)curve_new,
2711 (t_method)curve_free, sizeof(t_curve), CLASS_NOINLET, A_GIMME, 0);
2712 class_setdrawcommand(curve_class);
2713 class_addcreator((t_newmethod)curve_new, gensym("drawcurve"),
2714 A_GIMME, 0);
2715 class_addcreator((t_newmethod)curve_new, gensym("filledpolygon"),
2716 A_GIMME, 0);
2717 class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
2718 A_GIMME, 0);
2719 class_setparentwidget(curve_class, &curve_widgetbehavior);
2720}
2721
2722/* --------- plots for showing arrays --------------- */
2723
2724t_class *plot_class;
2725
2726typedef struct _plot
2727{
2728 t_object x_obj;
2729 int x_flags;
2730 t_fielddesc x_outlinecolor;
2731 t_fielddesc x_width;
2732 t_fielddesc x_xloc;
2733 t_fielddesc x_yloc;
2734 t_fielddesc x_xinc;
2735 t_fielddesc x_data;
2736} t_plot;
2737
2738static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv)
2739{
2740 t_plot *x = (t_plot *)pd_new(plot_class);
2741 int flags = 0;
2742 int nxy, i;
2743 t_fielddesc *fd;
2744 t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
2745 if (!strcmp(firstarg->s_name, "curve"))
2746 {
2747 flags |= BEZ;
2748 argc--, argv++;
2749 }
2750 if (argc) fielddesc_setarrayarg(&x->x_data, argc--, argv++);
2751 else FIELDDESC_SETFLOAT(&x->x_data, 1);
2752 if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
2753 else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
2754 if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
2755 else FIELDDESC_SETFLOAT(&x->x_width, 1);
2756 if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
2757 else FIELDDESC_SETFLOAT(&x->x_xloc, 1);
2758 if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
2759 else FIELDDESC_SETFLOAT(&x->x_yloc, 1);
2760 if (argc) fielddesc_setfloatarg(&x->x_xinc, argc--, argv++);
2761 else FIELDDESC_SETFLOAT(&x->x_xinc, 1);
2762 x->x_flags = flags;
2763 return (x);
2764}
2765
2766/* -------------------- widget behavior for plot ------------ */
2767
2768
2769 /* get everything we'll need from the owner template of the array being
2770 plotted. Not used for garrays, but see below */
2771static int plot_readownertemplate(t_plot *x,
2772 t_word *data, t_template *ownertemplate,
2773 t_symbol **elemtemplatesymp, t_array **arrayp,
2774 float *linewidthp, float *xlocp, float *xincp, float *ylocp)
2775{
2776 int arrayonset, type;
2777 t_symbol *elemtemplatesym;
2778 t_array *array;
2779
2780 /* find the data and verify it's an array */
2781 if (x->x_data.fd_type != A_ARRAY || !x->x_data.fd_var)
2782 {
2783 error("plot: needs an array field");
2784 return (-1);
2785 }
2786 if (!template_find_field(ownertemplate, x->x_data.fd_un.fd_varsym,
2787 &arrayonset, &type, &elemtemplatesym))
2788 {
2789 error("plot: %s: no such field", x->x_data.fd_un.fd_varsym->s_name);
2790 return (-1);
2791 }
2792 if (type != DT_ARRAY)
2793 {
2794 error("plot: %s: not an array", x->x_data.fd_un.fd_varsym->s_name);
2795 return (-1);
2796 }
2797 array = *(t_array **)(((char *)data) + arrayonset);
2798 *linewidthp = fielddesc_getfloat(&x->x_width, ownertemplate, data, 1);
2799 *xlocp = fielddesc_getfloat(&x->x_xloc, ownertemplate, data, 1);
2800 *xincp = fielddesc_getfloat(&x->x_xinc, ownertemplate, data, 1);
2801 *ylocp = fielddesc_getfloat(&x->x_yloc, ownertemplate, data, 1);
2802 *elemtemplatesymp = elemtemplatesym;
2803 *arrayp = array;
2804 return (0);
2805}
2806
2807 /* get everything else you could possibly need about a plot,
2808 either for plot's own purposes or for plotting a "garray" */
2809int array_getfields(t_symbol *elemtemplatesym,
2810 t_canvas **elemtemplatecanvasp,
2811 t_template **elemtemplatep, int *elemsizep,
2812 int *xonsetp, int *yonsetp, int *wonsetp)
2813{
2814 int arrayonset, elemsize, yonset, wonset, xonset, type;
2815 t_template *elemtemplate;
2816 t_symbol *dummy;
2817 t_canvas *elemtemplatecanvas = 0;
2818
2819 /* the "float" template is special in not having to have a canvas;
2820 template_findbyname is hardwired to return a predefined
2821 template. */
2822
2823 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
2824 {
2825 error("plot: %s: no such template", elemtemplatesym->s_name);
2826 return (-1);
2827 }
2828 if (!((elemtemplatesym == &s_float) ||
2829 (elemtemplatecanvas = template_findcanvas(elemtemplate))))
2830 {
2831 error("plot: %s: no canvas for this template", elemtemplatesym->s_name);
2832 return (-1);
2833 }
2834 elemsize = elemtemplate->t_n * sizeof(t_word);
2835 if (!template_find_field(elemtemplate, gensym("y"), &yonset, &type, &dummy)
2836 || type != DT_FLOAT)
2837 yonset = -1;
2838 if (!template_find_field(elemtemplate, gensym("x"), &xonset, &type, &dummy)
2839 || type != DT_FLOAT)
2840 xonset = -1;
2841 if (!template_find_field(elemtemplate, gensym("w"), &wonset, &type, &dummy)
2842 || type != DT_FLOAT)
2843 wonset = -1;
2844
2845 /* fill in slots for return values */
2846 *elemtemplatecanvasp = elemtemplatecanvas;
2847 *elemtemplatep = elemtemplate;
2848 *elemsizep = elemsize;
2849 *xonsetp = xonset;
2850 *yonsetp = yonset;
2851 *wonsetp = wonset;
2852 return (0);
2853}
2854
2855static void plot_getrect(t_gobj *z, t_glist *glist,
2856 t_word *data, t_template *template, float basex, float basey,
2857 int *xp1, int *yp1, int *xp2, int *yp2)
2858{
2859 t_plot *x = (t_plot *)z;
2860 int elemsize, yonset, wonset, xonset;
2861 t_canvas *elemtemplatecanvas;
2862 t_template *elemtemplate;
2863 t_symbol *elemtemplatesym;
2864 float linewidth, xloc, xinc, yloc;
2865 t_array *array;
2866 float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
2867 int i;
2868 float xpix, ypix, wpix;
2869
2870 if (!plot_readownertemplate(x, data, template,
2871 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) &&
2872 !array_getfields(elemtemplatesym, &elemtemplatecanvas,
2873 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
2874 {
2875 for (i = 0; i < array->a_n; i++)
2876 {
2877 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
2878 xonset, yonset, wonset, i, basex + xloc, basey + yloc, xinc,
2879 &xpix, &ypix, &wpix);
2880 if (xpix < x1)
2881 x1 = xpix;
2882 if (xpix > x2)
2883 x2 = xpix;
2884 if (ypix - wpix < y1)
2885 y1 = ypix - wpix;
2886 if (ypix + wpix > y2)
2887 y2 = ypix + wpix;
2888 }
2889 }
2890
2891 *xp1 = x1;
2892 *yp1 = y1;
2893 *xp2 = x2;
2894 *yp2 = y2;
2895}
2896
2897static void plot_displace(t_gobj *z, t_glist *glist,
2898 t_word *data, t_template *template, float basex, float basey,
2899 int dx, int dy)
2900{
2901 /* not yet */
2902}
2903
2904static void plot_select(t_gobj *z, t_glist *glist,
2905 t_word *data, t_template *template, float basex, float basey,
2906 int state)
2907{
2908 /* not yet */
2909}
2910
2911static void plot_activate(t_gobj *z, t_glist *glist,
2912 t_word *data, t_template *template, float basex, float basey,
2913 int state)
2914{
2915 /* not yet */
2916}
2917
2918static void plot_vis(t_gobj *z, t_glist *glist,
2919 t_word *data, t_template *template, float basex, float basey,
2920 int vis)
2921{
2922 t_plot *x = (t_plot *)z;
2923 int elemsize, yonset, wonset, xonset;
2924 t_canvas *elemtemplatecanvas;
2925 t_template *elemtemplate;
2926 t_symbol *elemtemplatesym;
2927 float linewidth, xloc, xinc, yloc;
2928 t_array *array;
2929 int nelem;
2930 char *elem;
2931 if (plot_readownertemplate(x, data, template,
2932 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) ||
2933 array_getfields(elemtemplatesym, &elemtemplatecanvas,
2934 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
2935 return;
2936 nelem = array->a_n;
2937 elem = (char *)array->a_vec;
2938 if (vis)
2939 {
2940 char outline[20];
2941 int lastpixel = -1, ndrawn = 0;
2942 float xsum, yval = 0, wval = 0, xpix;
2943 int ixpix = 0, i;
2944
2945 /* draw the trace */
2946 numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
2947 outline);
2948 if (wonset >= 0)
2949 {
2950 /* found "w" field which controls linewidth. The trace is
2951 a filled polygon with 2n points. */
2952 sys_vgui(".x%x.c create polygon \\\n",
2953 glist_getcanvas(glist));
2954
2955 for (i = 0, xsum = xloc; i < nelem; i++)
2956 {
2957 float usexloc;
2958 if (xonset >= 0)
2959 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
2960 else usexloc = xsum, xsum += xinc;
2961 if (yonset >= 0)
2962 yval = *(float *)((elem + elemsize * i) + yonset);
2963 else yval = 0;
2964 wval = *(float *)((elem + elemsize * i) + wonset);
2965 xpix = glist_xtopixels(glist, basex + usexloc);
2966 ixpix = xpix + 0.5;
2967 if (xonset >= 0 || ixpix != lastpixel)
2968 {
2969 sys_vgui("%d %f \\\n", ixpix,
2970 glist_ytopixels(glist,
2971 basey + yloc + yval - wval));
2972 ndrawn++;
2973 }
2974 lastpixel = ixpix;
2975 if (ndrawn >= 1000) goto ouch;
2976 }
2977 lastpixel = -1;
2978 for (i = nelem-1; i >= 0; i--)
2979 {
2980 float usexloc;
2981 if (xonset >= 0)
2982 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
2983 else xsum -= xinc, usexloc = xsum;
2984 if (yonset >= 0)
2985 yval = *(float *)((elem + elemsize * i) + yonset);
2986 else yval = 0;
2987 wval = *(float *)((elem + elemsize * i) + wonset);
2988 xpix = glist_xtopixels(glist, basex + usexloc);
2989 ixpix = xpix + 0.5;
2990 if (xonset >= 0 || ixpix != lastpixel)
2991 {
2992 sys_vgui("%d %f \\\n", ixpix, glist_ytopixels(glist,
2993 basey + yloc + yval + wval));
2994 ndrawn++;
2995 }
2996 lastpixel = ixpix;
2997 if (ndrawn >= 1000) goto ouch;
2998 }
2999 /* TK will complain if there aren't at least 3 points. There
3000 should be at least two already. */
3001 if (ndrawn < 4)
3002 {
3003 sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
3004 basey + yloc + yval + wval));
3005 sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
3006 basey + yloc + yval - wval));
3007 }
3008 ouch:
3009 sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline, outline);
3010 if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
3011
3012 sys_vgui("-tags plot%x\n", data);
3013 }
3014 else if (linewidth > 0)
3015 {
3016 /* no "w" field. If the linewidth is positive, draw a
3017 segmented line with the requested width; otherwise don't
3018 draw the trace at all. */
3019 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
3020
3021 for (xsum = xloc, i = 0; i < nelem; i++)
3022 {
3023 float usexloc;
3024 if (xonset >= 0)
3025 usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
3026 else usexloc = xsum, xsum += xinc;
3027 if (yonset >= 0)
3028 yval = *(float *)((elem + elemsize * i) + yonset);
3029 else yval = 0;
3030 xpix = glist_xtopixels(glist, basex + usexloc);
3031 ixpix = xpix + 0.5;
3032 if (xonset >= 0 || ixpix != lastpixel)
3033 {
3034 sys_vgui("%d %f \\\n", ixpix,
3035 glist_ytopixels(glist, basey + yloc + yval));
3036 ndrawn++;
3037 }
3038 lastpixel = ixpix;
3039 if (ndrawn >= 1000) break;
3040 }
3041 /* TK will complain if there aren't at least 2 points... */
3042 if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
3043 else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
3044 glist_ytopixels(glist, basey + yloc + yval));
3045
3046 sys_vgui("-width %f\\\n", linewidth);
3047 sys_vgui("-fill %s\\\n", outline);
3048 if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
3049
3050 sys_vgui("-tags plot%x\n", data);
3051 }
3052 /* We're done with the outline; now draw all the points.
3053 This code is inefficient since the template has to be
3054 searched for drawing instructions for every last point. */
3055
3056 for (xsum = xloc, i = 0; i < nelem; i++)
3057 {
3058 float usexloc, useyloc;
3059 t_gobj *y;
3060 if (xonset >= 0)
3061 usexloc = basex + xloc +
3062 *(float *)((elem + elemsize * i) + xonset);
3063 else usexloc = basex + xsum, xsum += xinc;
3064 if (yonset >= 0)
3065 yval = *(float *)((elem + elemsize * i) + yonset);
3066 else yval = 0;
3067 useyloc = basey + yloc + yval;
3068 for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
3069 {
3070 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
3071 if (!wb) continue;
3072 (*wb->w_parentvisfn)(y, glist,
3073 (t_word *)(elem + elemsize * i),
3074 elemtemplate, usexloc, useyloc, vis);
3075 }
3076 }
3077 }
3078 else
3079 {
3080 /* un-draw the individual points */
3081 int i;
3082 for (i = 0; i < nelem; i++)
3083 {
3084 t_gobj *y;
3085 for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
3086 {
3087 t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
3088 if (!wb) continue;
3089 (*wb->w_parentvisfn)(y, glist,
3090 (t_word *)(elem + elemsize * i), elemtemplate,
3091 0, 0, 0);
3092 }
3093 }
3094 /* and then the trace */
3095 sys_vgui(".x%x.c delete plot%x\n",
3096 glist_getcanvas(glist), data);
3097 }
3098}
3099
3100
3101static int plot_click(t_gobj *z, t_glist *glist,
3102 t_scalar *sc, t_template *template, float basex, float basey,
3103 int xpix, int ypix, int shift, int alt, int dbl, int doit)
3104{
3105 t_plot *x = (t_plot *)z;
3106 t_symbol *elemtemplatesym;
3107 float linewidth, xloc, xinc, yloc;
3108 t_array *array;
3109 t_word *data = sc->sc_vec;
3110
3111 if (!plot_readownertemplate(x, data, template,
3112 &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc))
3113 {
3114 return (array_doclick(array, glist, &sc->sc_gobj,
3115 elemtemplatesym,
3116 linewidth, basex + xloc, xinc, basey + yloc,
3117 xpix, ypix, shift, alt, dbl, doit));
3118 }
3119 else return (0);
3120}
3121
3122t_parentwidgetbehavior plot_widgetbehavior =
3123{
3124 plot_getrect,
3125 plot_displace,
3126 plot_select,
3127 plot_activate,
3128 plot_vis,
3129 plot_click,
3130};
3131
3132static void plot_setup(void)
3133{
3134 plot_class = class_new(gensym("plot"), (t_newmethod)plot_new, 0,
3135 sizeof(t_plot), CLASS_NOINLET, A_GIMME, 0);
3136 class_setdrawcommand(plot_class);
3137 class_setparentwidget(plot_class, &plot_widgetbehavior);
3138}
3139
3140/* ---------------- drawnumber: draw a number ---------------- */
3141
3142/*
3143 drawnumbers draw numeric fields at controllable locations, with
3144 controllable color and label .
3145 invocation: (drawnumber|drawsymbol) variable x y color label
3146*/
3147
3148t_class *drawnumber_class;
3149
3150#define DRAW_SYMBOL 1
3151
3152typedef struct _drawnumber
3153{
3154 t_object x_obj;
3155 t_fielddesc x_value;
3156 t_fielddesc x_xloc;
3157 t_fielddesc x_yloc;
3158 t_fielddesc x_color;
3159 t_symbol *x_label;
3160 int x_flags;
3161} t_drawnumber;
3162
3163static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv)
3164{
3165 t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
3166 char *classname = classsym->s_name;
3167 int flags = 0;
3168 if (classname[4] == 's')
3169 flags |= DRAW_SYMBOL;
3170 x->x_flags = flags;
3171 if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
3172 else FIELDDESC_SETFLOAT(&x->x_value, 0);
3173 if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
3174 else FIELDDESC_SETFLOAT(&x->x_xloc, 0);
3175 if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
3176 else FIELDDESC_SETFLOAT(&x->x_yloc, 0);
3177 if (argc) fielddesc_setfloatarg(&x->x_color, argc--, argv++);
3178 else FIELDDESC_SETFLOAT(&x->x_color, 1);
3179 if (argc)
3180 x->x_label = atom_getsymbolarg(0, argc, argv);
3181 else x->x_label = &s_;
3182
3183 return (x);
3184}
3185
3186/* -------------------- widget behavior for drawnumber ------------ */
3187
3188#define DRAWNUMBER_BUFSIZE 80
3189static void drawnumber_sprintf(t_drawnumber *x, char *buf, t_atom *ap)
3190{
3191 int nchars;
3192 strncpy(buf, x->x_label->s_name, DRAWNUMBER_BUFSIZE);
3193 buf[DRAWNUMBER_BUFSIZE - 1] = 0;
3194 nchars = strlen(buf);
3195 atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars);
3196}
3197
3198static void drawnumber_getrect(t_gobj *z, t_glist *glist,
3199 t_word *data, t_template *template, float basex, float basey,
3200 int *xp1, int *yp1, int *xp2, int *yp2)
3201{
3202 t_drawnumber *x = (t_drawnumber *)z;
3203 t_atom at;
3204 int xloc = glist_xtopixels(glist,
3205 basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
3206 int yloc = glist_ytopixels(glist,
3207 basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
3208 int font = glist_getfont(glist);
3209 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
3210 char buf[DRAWNUMBER_BUFSIZE];
3211 if (x->x_flags & DRAW_SYMBOL)
3212 SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
3213 else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
3214 drawnumber_sprintf(x, buf, &at);
3215 *xp1 = xloc;
3216 *yp1 = yloc;
3217 *xp2 = xloc + fontwidth * strlen(buf);
3218 *yp2 = yloc + fontheight;
3219}
3220
3221static void drawnumber_displace(t_gobj *z, t_glist *glist,
3222 t_word *data, t_template *template, float basex, float basey,
3223 int dx, int dy)
3224{
3225 /* refuse */
3226}
3227
3228static void drawnumber_select(t_gobj *z, t_glist *glist,
3229 t_word *data, t_template *template, float basex, float basey,
3230 int state)
3231{
3232 post("drawnumber_select %d", state);
3233 /* fill in later */
3234}
3235
3236static void drawnumber_activate(t_gobj *z, t_glist *glist,
3237 t_word *data, t_template *template, float basex, float basey,
3238 int state)
3239{
3240 post("drawnumber_activate %d", state);
3241}
3242
3243static void drawnumber_vis(t_gobj *z, t_glist *glist,
3244 t_word *data, t_template *template, float basex, float basey,
3245 int vis)
3246{
3247 t_drawnumber *x = (t_drawnumber *)z;
3248
3249 if (vis)
3250 {
3251 t_atom at;
3252 int xloc = glist_xtopixels(glist,
3253 basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
3254 int yloc = glist_ytopixels(glist,
3255 basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
3256 char colorstring[20], buf[DRAWNUMBER_BUFSIZE];
3257 numbertocolor(fielddesc_getfloat(&x->x_color, template, data, 1),
3258 colorstring);
3259 if (x->x_flags & DRAW_SYMBOL)
3260 SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
3261 else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
3262 drawnumber_sprintf(x, buf, &at);
3263 sys_vgui(".x%x.c create text %d %d -anchor nw -fill %s -text {%s}",
3264 glist_getcanvas(glist), xloc, yloc, colorstring, buf);
3265 sys_vgui(" -font -*-courier-bold--normal--%d-*",
3266 sys_hostfontsize(glist_getfont(glist)));
3267 sys_vgui(" -tags drawnumber%x\n", data);
3268 }
3269 else sys_vgui(".x%x.c delete drawnumber%x\n", glist_getcanvas(glist), data);
3270}
3271
3272static float drawnumber_motion_ycumulative;
3273static t_glist *drawnumber_motion_glist;
3274static t_gobj *drawnumber_motion_gobj;
3275static t_word *drawnumber_motion_wp;
3276static t_template *drawnumber_motion_template;
3277
3278 /* LATER protect against the template changing or the scalar disappearing
3279 probably by attaching a gpointer here ... */
3280
3281static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy)
3282{
3283 t_drawnumber *x = (t_drawnumber *)z;
3284 t_fielddesc *f = &x->x_value;
3285 drawnumber_motion_ycumulative -= dy;
3286 template_setfloat(drawnumber_motion_template,
3287 f->fd_un.fd_varsym,
3288 drawnumber_motion_wp,
3289 drawnumber_motion_ycumulative,
3290 1);
3291 glist_redrawitem(drawnumber_motion_glist, drawnumber_motion_gobj);
3292}
3293
3294static int drawnumber_click(t_gobj *z, t_glist *glist,
3295 t_scalar *sc, t_template *template, float basex, float basey,
3296 int xpix, int ypix, int shift, int alt, int dbl, int doit)
3297{
3298 t_drawnumber *x = (t_drawnumber *)z;
3299 int x1, y1, x2, y2;
3300 t_word *data = sc->sc_vec;
3301 drawnumber_getrect(z, glist,
3302 sc->sc_vec, template, basex, basey,
3303 &x1, &y1, &x2, &y2);
3304 if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
3305 && x->x_value.fd_var)
3306 {
3307 if (doit)
3308 {
3309 drawnumber_motion_glist = glist;
3310 drawnumber_motion_gobj = &sc->sc_gobj;
3311 drawnumber_motion_wp = data;
3312 drawnumber_motion_template = template;
3313 drawnumber_motion_ycumulative =
3314 fielddesc_getfloat(&x->x_value, template, data, 0);
3315 glist_grab(glist, z, drawnumber_motion, 0, xpix, ypix);
3316 }
3317 return (1);
3318 }
3319 else return (0);
3320}
3321
3322t_parentwidgetbehavior drawnumber_widgetbehavior =
3323{
3324 drawnumber_getrect,
3325 drawnumber_displace,
3326 drawnumber_select,
3327 drawnumber_activate,
3328 drawnumber_vis,
3329 drawnumber_click,
3330};
3331
3332static void drawnumber_free(t_drawnumber *x)
3333{
3334}
3335
3336static void drawnumber_setup(void)
3337{
3338 drawnumber_class = class_new(gensym("drawnumber"),
3339 (t_newmethod)drawnumber_new, (t_method)drawnumber_free,
3340 sizeof(t_drawnumber), CLASS_NOINLET, A_GIMME, 0);
3341 class_setdrawcommand(drawnumber_class);
3342 class_addcreator((t_newmethod)drawnumber_new, gensym("drawsymbol"),
3343 A_GIMME, 0);
3344 class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
3345}
3346
3347/* ---------------------- setup function ---------------------------- */
3348
3349void g_template_setup(void)
3350{
3351 template_setup();
3352 gtemplate_setup();
3353 template_float.t_pdobj = template_class;
3354 curve_setup();
3355 plot_setup();
3356 drawnumber_setup();
3357}
3358
diff --git a/apps/plugins/pdbox/PDa/src/g_text.c b/apps/plugins/pdbox/PDa/src/g_text.c
new file mode 100644
index 0000000000..8cf1fe2834
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_text.c
@@ -0,0 +1,2632 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
6/* the methods for calling the gui-objects from menu are implemented */
7/* all changes are labeled with iemlib */
8
9#include <stdlib.h>
10#include "m_pd.h"
11#include "m_imp.h"
12#include "s_stuff.h"
13#include "t_tk.h"
14#include "g_canvas.h"
15#include <stdio.h>
16#include <string.h>
17#include <math.h>
18
19static t_class *text_class;
20static t_class *message_class;
21static t_class *gatom_class;
22static void text_vis(t_gobj *z, t_glist *glist, int vis);
23static void text_displace(t_gobj *z, t_glist *glist,
24 int dx, int dy);
25static void text_getrect(t_gobj *z, t_glist *glist,
26 int *xp1, int *yp1, int *xp2, int *yp2);
27
28void canvas_startmotion(t_canvas *x);
29t_widgetbehavior text_widgetbehavior;
30
31/* ----------------- the "text" object. ------------------ */
32
33 /* add a "text" object (comment) to a glist. While this one goes for any glist,
34 the other 3 below are for canvases only. (why?) This is called
35 without args if invoked from the GUI; otherwise at least x and y
36 are provided. */
37
38void glist_text(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
39{
40 t_text *x = (t_text *)pd_new(text_class);
41 t_atom at;
42 x->te_width = 0; /* don't know it yet. */
43 x->te_type = T_TEXT;
44 x->te_binbuf = binbuf_new();
45 if (argc > 1)
46 {
47 x->te_xpix = atom_getfloatarg(0, argc, argv);
48 x->te_ypix = atom_getfloatarg(1, argc, argv);
49 if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
50 else
51 {
52 SETSYMBOL(&at, gensym("comment"));
53 binbuf_restore(x->te_binbuf, 1, &at);
54 }
55 glist_add(gl, &x->te_g);
56 }
57 else
58 {
59 int xpix, ypix;
60 pd_vmess((t_pd *)glist_getcanvas(gl), gensym("editmode"), "i", 1);
61 SETSYMBOL(&at, gensym("comment"));
62 glist_noselect(gl);
63 glist_getnextxy(gl, &xpix, &ypix);
64 x->te_xpix = glist_pixelstox(gl, xpix-3);
65 x->te_ypix = glist_pixelstoy(gl, ypix-3);
66 binbuf_restore(x->te_binbuf, 1, &at);
67 glist_add(gl, &x->te_g);
68 glist_noselect(gl);
69 glist_select(gl, &x->te_g);
70 /* it would be nice to "activate" here, but then the second,
71 "put-me-down" click changes the text selection, which is quite
72 irritating, so I took this back out. It's OK in messages
73 and objects though since there's no text in them at menu
74 creation. */
75 /* gobj_activate(&x->te_g, gl, 1); */
76 canvas_startmotion(glist_getcanvas(gl));
77 }
78}
79
80/* ----------------- the "object" object. ------------------ */
81
82extern t_pd *newest;
83void canvas_getargs(int *argcp, t_atom **argvp);
84
85static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected,
86 t_binbuf *b)
87{
88 t_text *x;
89 int argc;
90 t_atom *argv;
91 newest = 0;
92 canvas_setcurrent((t_canvas *)gl);
93 canvas_getargs(&argc, &argv);
94 binbuf_eval(b, &pd_objectmaker, argc, argv);
95 if (binbuf_getnatom(b))
96 {
97 if (!newest)
98 {
99 binbuf_print(b);
100 post("... couldn't create");
101 x = 0;
102 }
103 else if (!(x = pd_checkobject(newest)))
104 {
105 binbuf_print(b);
106 post("... didn't return a patchable object");
107 }
108 }
109 else x = 0;
110 if (!x)
111 {
112
113 /* LATER make the color reflect this */
114 x = (t_text *)pd_new(text_class);
115 }
116 x->te_binbuf = b;
117 x->te_xpix = xpix;
118 x->te_ypix = ypix;
119 x->te_width = 0;
120 x->te_type = T_OBJECT;
121 glist_add(gl, &x->te_g);
122 if (selected)
123 {
124 /* this is called if we've been created from the menu. */
125 glist_select(gl, &x->te_g);
126 gobj_activate(&x->te_g, gl, 1);
127 }
128 if (pd_class(&x->ob_pd) == vinlet_class)
129 canvas_resortinlets(glist_getcanvas(gl));
130 if (pd_class(&x->ob_pd) == voutlet_class)
131 canvas_resortoutlets(glist_getcanvas(gl));
132 canvas_unsetcurrent((t_canvas *)gl);
133}
134
135 /* object creation routine. These are called without any arguments if
136 they're invoked from the
137 gui; when pasting or restoring from a file, we get at least x and y. */
138
139void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
140{
141 t_text *x;
142 if (argc >= 2)
143 {
144 t_binbuf *b = binbuf_new();
145 binbuf_restore(b, argc-2, argv+2);
146 canvas_objtext(gl, atom_getintarg(0, argc, argv),
147 atom_getintarg(1, argc, argv), 0, b);
148 }
149 else
150 {
151 t_binbuf *b = binbuf_new();
152 int xpix, ypix;
153 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
154 glist_noselect(gl);
155 glist_getnextxy(gl, &xpix, &ypix);
156 canvas_objtext(gl, xpix, ypix, 1, b);
157 canvas_startmotion(glist_getcanvas(gl));
158 }
159}
160
161/* make an object box for an object that's already there. */
162
163/* iemlib */
164void canvas_iemguis(t_glist *gl, t_symbol *guiobjname)
165{
166 t_atom at;
167 t_binbuf *b = binbuf_new();
168 int xpix, ypix;
169
170 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
171 glist_noselect(gl);
172 SETSYMBOL(&at, guiobjname);
173 binbuf_restore(b, 1, &at);
174 glist_getnextxy(gl, &xpix, &ypix);
175 canvas_objtext(gl, xpix, ypix, 1, b);
176 canvas_startmotion(glist_getcanvas(gl));
177}
178
179void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
180{
181 canvas_iemguis(gl, gensym("bng"));
182}
183
184void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
185{
186 canvas_iemguis(gl, gensym("tgl"));
187}
188
189void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
190{
191 canvas_iemguis(gl, gensym("vsl"));
192}
193
194void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
195{
196 canvas_iemguis(gl, gensym("hsl"));
197}
198
199void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
200{
201 canvas_iemguis(gl, gensym("hdl"));
202}
203
204void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
205{
206 canvas_iemguis(gl, gensym("vdl"));
207}
208
209void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
210{
211 canvas_iemguis(gl, gensym("hradio"));
212}
213
214void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
215{
216 canvas_iemguis(gl, gensym("vradio"));
217}
218
219void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
220{
221 canvas_iemguis(gl, gensym("vu"));
222}
223
224void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
225{
226 canvas_iemguis(gl, gensym("cnv"));
227}
228
229void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
230{
231 canvas_iemguis(gl, gensym("nbx"));
232}
233
234/* iemlib */
235
236void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv)
237{
238 x->te_width = 0; /* don't know it yet. */
239 x->te_type = T_OBJECT;
240 x->te_binbuf = binbuf_new();
241 x->te_xpix = atom_getfloatarg(0, argc, argv);
242 x->te_ypix = atom_getfloatarg(1, argc, argv);
243 if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
244 glist_add(gl, &x->te_g);
245}
246
247/* ---------------------- the "message" text item ------------------------ */
248
249typedef struct _messresponder
250{
251 t_pd mr_pd;
252 t_outlet *mr_outlet;
253} t_messresponder;
254
255typedef struct _message
256{
257 t_text m_text;
258 t_messresponder m_messresponder;
259 t_glist *m_glist;
260 t_clock *m_clock;
261} t_message;
262
263static t_class *message_class, *messresponder_class;
264
265static void messresponder_bang(t_messresponder *x)
266{
267 outlet_bang(x->mr_outlet);
268}
269
270static void messresponder_float(t_messresponder *x, t_float f)
271{
272 outlet_float(x->mr_outlet, f);
273}
274
275static void messresponder_symbol(t_messresponder *x, t_symbol *s)
276{
277 outlet_symbol(x->mr_outlet, s);
278}
279
280static void messresponder_list(t_messresponder *x,
281 t_symbol *s, int argc, t_atom *argv)
282{
283 outlet_list(x->mr_outlet, s, argc, argv);
284}
285
286static void messresponder_anything(t_messresponder *x,
287 t_symbol *s, int argc, t_atom *argv)
288{
289 outlet_anything(x->mr_outlet, s, argc, argv);
290}
291
292static void message_bang(t_message *x)
293{
294 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 0, 0);
295}
296
297static void message_float(t_message *x, t_float f)
298{
299 t_atom at;
300 SETFLOAT(&at, f);
301 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
302}
303
304static void message_symbol(t_message *x, t_symbol *s)
305{
306 t_atom at;
307 SETSYMBOL(&at, s);
308 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
309}
310
311static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv)
312{
313 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, argc, argv);
314}
315
316static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv)
317{
318 binbuf_clear(x->m_text.te_binbuf);
319 binbuf_add(x->m_text.te_binbuf, argc, argv);
320 glist_retext(x->m_glist, &x->m_text);
321}
322
323static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv)
324{
325 binbuf_add(x->m_text.te_binbuf, argc, argv);
326 glist_retext(x->m_glist, &x->m_text);
327}
328
329static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
330{
331 binbuf_add(x->m_text.te_binbuf, argc, argv);
332 binbuf_addsemi(x->m_text.te_binbuf);
333 glist_retext(x->m_glist, &x->m_text);
334}
335
336static void message_click(t_message *x,
337 t_floatarg xpos, t_floatarg ypos, t_floatarg shift,
338 t_floatarg ctrl, t_floatarg alt)
339{
340 message_float(x, 0);
341 if (glist_isvisible(x->m_glist))
342 {
343 t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
344 sys_vgui(".x%x.c itemconfigure %sR -width 5\n",
345 glist_getcanvas(x->m_glist), rtext_gettag(y));
346 clock_delay(x->m_clock, 120);
347 }
348}
349
350static void message_tick(t_message *x)
351{
352 if (glist_isvisible(x->m_glist))
353 {
354 t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
355 sys_vgui(".x%x.c itemconfigure %sR -width 1\n",
356 glist_getcanvas(x->m_glist), rtext_gettag(y));
357 }
358}
359
360static void message_free(t_message *x)
361{
362 clock_free(x->m_clock);
363}
364
365void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
366{
367 t_message *x = (t_message *)pd_new(message_class);
368 x->m_messresponder.mr_pd = messresponder_class;
369 x->m_messresponder.mr_outlet = outlet_new(&x->m_text, &s_float);
370 x->m_text.te_width = 0; /* don't know it yet. */
371 x->m_text.te_type = T_MESSAGE;
372 x->m_text.te_binbuf = binbuf_new();
373 x->m_glist = gl;
374 x->m_clock = clock_new(x, (t_method)message_tick);
375 if (argc > 1)
376 {
377 x->m_text.te_xpix = atom_getfloatarg(0, argc, argv);
378 x->m_text.te_ypix = atom_getfloatarg(1, argc, argv);
379 if (argc > 2) binbuf_restore(x->m_text.te_binbuf, argc-2, argv+2);
380 glist_add(gl, &x->m_text.te_g);
381 }
382 else
383 {
384 int xpix, ypix;
385 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
386 glist_noselect(gl);
387 glist_getnextxy(gl, &xpix, &ypix);
388 x->m_text.te_xpix = xpix-3;
389 x->m_text.te_ypix = ypix-3;
390 glist_add(gl, &x->m_text.te_g);
391 glist_noselect(gl);
392 glist_select(gl, &x->m_text.te_g);
393 gobj_activate(&x->m_text.te_g, gl, 1);
394 canvas_startmotion(glist_getcanvas(gl));
395 }
396}
397
398/* ---------------------- the "atom" text item ------------------------ */
399
400#define ATOMBUFSIZE 40
401#define ATOM_LABELLEFT 0
402#define ATOM_LABELRIGHT 1
403#define ATOM_LABELUP 2
404#define ATOM_LABELDOWN 3
405
406typedef struct _gatom
407{
408 t_text a_text;
409 t_atom a_atom; /* this holds the value and the type */
410 t_glist *a_glist; /* owning glist */
411 t_float a_toggle; /* value to toggle to */
412 t_float a_draghi; /* high end of drag range */
413 t_float a_draglo; /* low end of drag range */
414 t_symbol *a_label; /* symbol to show as label next to box */
415 t_symbol *a_symfrom; /* "receive" name -- bind ourselvs to this */
416 t_symbol *a_symto; /* "send" name -- send to this on output */
417 char a_buf[ATOMBUFSIZE];/* string buffer for typing */
418 char a_shift; /* was shift key down when dragging started? */
419 char a_wherelabel; /* 0-3 for left, right, above, below */
420 t_symbol *a_expanded_to; /* a_symto after $0, $1, ... expansion */
421} t_gatom;
422
423 /* prepend "-" as necessary to avoid empty strings, so we can
424 use them in Pd messages. A more complete solution would be
425 to introduce some quoting mechanism; but then we'd be much more
426 complicated. */
427static t_symbol *gatom_escapit(t_symbol *s)
428{
429 if (!*s->s_name)
430 return (gensym("-"));
431 else if (*s->s_name == '-')
432 {
433 char shmo[100];
434 shmo[0] = '-';
435 strncpy(shmo+1, s->s_name, 99);
436 shmo[99] = 0;
437 return (gensym(shmo));
438 }
439 else return (iemgui_dollar2raute(s));
440}
441
442 /* undo previous operation: strip leading "-" if found. */
443static t_symbol *gatom_unescapit(t_symbol *s)
444{
445 if (*s->s_name == '-')
446 return (gensym(s->s_name+1));
447 else return (iemgui_raute2dollar(s));
448}
449
450#if 0 /* ??? */
451 /* expand leading $0, $1, etc. in the symbol */
452static t_symbol *gatom_realizedollar(t_gatom *x, t_symbol *s)
453{
454 return (canvas_realizedollar(x->a_glist, s));
455}
456#endif
457
458static void gatom_retext(t_gatom *x, int senditup)
459{
460 binbuf_clear(x->a_text.te_binbuf);
461 binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom);
462 if (senditup)
463 glist_retext(x->a_glist, &x->a_text);
464}
465
466static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv)
467{
468 t_atom oldatom = x->a_atom;
469 int senditup = 0;
470 if (!argc) return;
471 if (x->a_atom.a_type == A_FLOAT)
472 x->a_atom.a_w.w_float = atom_getfloat(argv),
473 senditup = (x->a_atom.a_w.w_float != oldatom.a_w.w_float);
474 else if (x->a_atom.a_type == A_SYMBOL)
475 x->a_atom.a_w.w_symbol = atom_getsymbol(argv),
476 senditup = (x->a_atom.a_w.w_symbol != oldatom.a_w.w_symbol);
477 gatom_retext(x, senditup);
478 x->a_buf[0] = 0;
479}
480
481static void gatom_bang(t_gatom *x)
482{
483 if (x->a_atom.a_type == A_FLOAT)
484 {
485 if (x->a_text.te_outlet)
486 outlet_float(x->a_text.te_outlet, x->a_atom.a_w.w_float);
487 if (*x->a_expanded_to->s_name && x->a_expanded_to->s_thing)
488 {
489 if (x->a_symto == x->a_symfrom)
490 pd_error(x,
491 "%s: atom with same send/receive name (infinite loop)",
492 x->a_symto->s_name);
493 else pd_float(x->a_expanded_to->s_thing, x->a_atom.a_w.w_float);
494 }
495 }
496 else if (x->a_atom.a_type == A_SYMBOL)
497 {
498 if (x->a_text.te_outlet)
499 outlet_symbol(x->a_text.te_outlet, x->a_atom.a_w.w_symbol);
500 if (*x->a_symto->s_name && x->a_expanded_to->s_thing)
501 {
502 if (x->a_symto == x->a_symfrom)
503 pd_error(x,
504 "%s: atom with same send/receive name (infinite loop)",
505 x->a_symto->s_name);
506 else pd_symbol(x->a_expanded_to->s_thing, x->a_atom.a_w.w_symbol);
507 }
508 }
509}
510
511static void gatom_float(t_gatom *x, t_float f)
512{
513 t_atom at;
514 SETFLOAT(&at, f);
515 gatom_set(x, 0, 1, &at);
516 gatom_bang(x);
517}
518
519static void gatom_clipfloat(t_gatom *x, t_float f)
520{
521 if (x->a_draglo != 0 || x->a_draghi != 0)
522 {
523 if (f < x->a_draglo)
524 f = x->a_draglo;
525 if (f > x->a_draghi)
526 f = x->a_draghi;
527 }
528 gatom_float(x, f);
529}
530
531static void gatom_symbol(t_gatom *x, t_symbol *s)
532{
533 t_atom at;
534 SETSYMBOL(&at, s);
535 gatom_set(x, 0, 1, &at);
536 gatom_bang(x);
537}
538
539static void gatom_motion(void *z, t_floatarg dx, t_floatarg dy)
540{
541 t_gatom *x = (t_gatom *)z;
542 if (dy == 0) return;
543 if (x->a_atom.a_type == A_FLOAT)
544 {
545 if (x->a_shift)
546 {
547 double nval = x->a_atom.a_w.w_float - 0.01 * dy;
548 double trunc = 0.01 * (floor(100. * nval + 0.5));
549 if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
550 gatom_clipfloat(x, nval);
551 }
552 else
553 {
554 double nval = x->a_atom.a_w.w_float - dy;
555 double trunc = 0.01 * (floor(100. * nval + 0.5));
556 if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
557 trunc = floor(nval + 0.5);
558 if (trunc < nval + 0.001 && trunc > nval - 0.001) nval = trunc;
559 gatom_clipfloat(x, nval);
560 }
561 }
562}
563
564static void gatom_key(void *z, t_floatarg f)
565{
566 t_gatom *x = (t_gatom *)z;
567 int c = f;
568 int len = strlen(x->a_buf);
569 t_atom at;
570 char sbuf[ATOMBUFSIZE + 4];
571 if (c == 0)
572 {
573 /* we're being notified that no more keys will come for this grab */
574 if (x->a_buf[0])
575 gatom_retext(x, 1);
576 return;
577 }
578 else if (c == ' ') return;
579 else if (c == '\b')
580 {
581 if (len > 0)
582 x->a_buf[len-1] = 0;
583 goto redraw;
584 }
585 else if (c == '\n')
586 {
587 if (x->a_atom.a_type == A_FLOAT)
588 x->a_atom.a_w.w_float = atof(x->a_buf);
589 else if (x->a_atom.a_type == A_SYMBOL)
590 x->a_atom.a_w.w_symbol = gensym(x->a_buf);
591 else bug("gatom_key");
592 gatom_bang(x);
593 gatom_retext(x, 1);
594 x->a_buf[0] = 0;
595 }
596 else if (len < (ATOMBUFSIZE-1))
597 {
598 /* for numbers, only let reasonable characters through */
599 if ((x->a_atom.a_type == A_SYMBOL) ||
600 (c >= '0' && c <= '9' || c == '.' || c == '-'
601 || c == 'e' || c == 'E'))
602 {
603 x->a_buf[len] = c;
604 x->a_buf[len+1] = 0;
605 goto redraw;
606 }
607 }
608 return;
609redraw:
610 /* LATER figure out how to avoid creating all these symbols! */
611 sprintf(sbuf, "%s...", x->a_buf);
612 SETSYMBOL(&at, gensym(sbuf));
613 binbuf_clear(x->a_text.te_binbuf);
614 binbuf_add(x->a_text.te_binbuf, 1, &at);
615 glist_retext(x->a_glist, &x->a_text);
616}
617
618static void gatom_click(t_gatom *x,
619 t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl,
620 t_floatarg alt)
621{
622 if (x->a_text.te_width == 1)
623 {
624 if (x->a_atom.a_type == A_FLOAT)
625 gatom_float(x, (x->a_atom.a_w.w_float == 0));
626 }
627 else
628 {
629 if (alt)
630 {
631 if (x->a_atom.a_type != A_FLOAT) return;
632 if (x->a_atom.a_w.w_float != 0)
633 {
634 x->a_toggle = x->a_atom.a_w.w_float;
635 gatom_float(x, 0);
636 return;
637 }
638 else gatom_float(x, x->a_toggle);
639 }
640 x->a_shift = shift;
641 x->a_buf[0] = 0;
642 glist_grab(x->a_glist, &x->a_text.te_g, gatom_motion, gatom_key,
643 xpos, ypos);
644 }
645}
646
647 /* message back from dialog window */
648static void gatom_param(t_gatom *x, t_symbol *sel, int argc, t_atom *argv)
649{
650 t_float width = atom_getfloatarg(0, argc, argv);
651 t_float draglo = atom_getfloatarg(1, argc, argv);
652 t_float draghi = atom_getfloatarg(2, argc, argv);
653 t_symbol *label = gatom_unescapit(atom_getsymbolarg(3, argc, argv));
654 t_float wherelabel = atom_getfloatarg(4, argc, argv);
655 t_symbol *symfrom = gatom_unescapit(atom_getsymbolarg(5, argc, argv));
656 t_symbol *symto = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
657
658 gobj_vis(&x->a_text.te_g, x->a_glist, 0);
659 if (!*symfrom->s_name && *x->a_symfrom->s_name)
660 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
661 else if (*symfrom->s_name && !*x->a_symfrom->s_name && x->a_text.te_inlet)
662 {
663 canvas_deletelinesforio(x->a_glist, &x->a_text,
664 x->a_text.te_inlet, 0);
665 inlet_free(x->a_text.te_inlet);
666 }
667 if (!*symto->s_name && *x->a_symto->s_name)
668 outlet_new(&x->a_text, 0);
669 else if (*symto->s_name && !*x->a_symto->s_name && x->a_text.te_outlet)
670 {
671 canvas_deletelinesforio(x->a_glist, &x->a_text,
672 0, x->a_text.te_outlet);
673 outlet_free(x->a_text.te_outlet);
674 }
675 if (draglo >= draghi)
676 draglo = draghi = 0;
677 x->a_draglo = draglo;
678 x->a_draghi = draghi;
679 if (width < 0)
680 width = 4;
681 else if (width > 80)
682 width = 80;
683 x->a_text.te_width = width;
684 x->a_wherelabel = ((int)wherelabel & 3);
685 x->a_label = label;
686 if (*x->a_symfrom->s_name)
687 pd_unbind(&x->a_text.te_pd,
688 canvas_realizedollar(x->a_glist, x->a_symfrom));
689 x->a_symfrom = symfrom;
690 if (*x->a_symfrom->s_name)
691 pd_bind(&x->a_text.te_pd,
692 canvas_realizedollar(x->a_glist, x->a_symfrom));
693 x->a_symto = symto;
694 x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
695 gobj_vis(&x->a_text.te_g, x->a_glist, 1);
696
697 /* glist_retext(x->a_glist, &x->a_text); */
698}
699
700 /* ---------------- gatom-specific widget functions --------------- */
701static void gatom_getwherelabel(t_gatom *x, t_glist *glist, int *xp, int *yp)
702{
703 int x1, y1, x2, y2, width, height;
704 text_getrect(&x->a_text.te_g, glist, &x1, &y1, &x2, &y2);
705 width = x2 - x1;
706 height = y2 - y1;
707 if (x->a_wherelabel == ATOM_LABELLEFT)
708 {
709 *xp = x1 - 3 -
710 strlen(canvas_realizedollar(x->a_glist, x->a_label)->s_name) *
711 sys_fontwidth(glist_getfont(glist));
712 *yp = y1 + 2;
713 }
714 else if (x->a_wherelabel == ATOM_LABELRIGHT)
715 {
716 *xp = x2 + 2;
717 *yp = y1 + 2;
718 }
719 else if (x->a_wherelabel == ATOM_LABELUP)
720 {
721 *xp = x1 - 1;
722 *yp = y1 - 1 - sys_fontheight(glist_getfont(glist));;
723 }
724 else
725 {
726 *xp = x1 - 1;
727 *yp = y2 + 3;
728 }
729}
730
731static void gatom_displace(t_gobj *z, t_glist *glist,
732 int dx, int dy)
733{
734 t_gatom *x = (t_gatom*)z;
735 text_displace(z, glist, dx, dy);
736 sys_vgui(".x%x.c move %x.l %d %d\n", glist_getcanvas(glist),
737 x, dx, dy);
738}
739
740static void gatom_vis(t_gobj *z, t_glist *glist, int vis)
741{
742 t_gatom *x = (t_gatom*)z;
743 text_vis(z, glist, vis);
744 if (*x->a_label->s_name)
745 {
746 if (vis)
747 {
748 int x1, y1;
749 gatom_getwherelabel(x, glist, &x1, &y1);
750 sys_vgui("pdtk_text_new .x%x.c %x.l %f %f {%s} %d %s\n",
751 glist_getcanvas(glist), x,
752 (double)x1, (double)y1,
753 canvas_realizedollar(x->a_glist, x->a_label)->s_name,
754 sys_hostfontsize(glist_getfont(glist)),
755 "black");
756 }
757 else sys_vgui(".x%x.c delete %x.l\n", glist_getcanvas(glist), x);
758 }
759}
760
761void canvas_atom(t_glist *gl, t_atomtype type,
762 t_symbol *s, int argc, t_atom *argv)
763{
764 t_gatom *x = (t_gatom *)pd_new(gatom_class);
765 t_atom at;
766 x->a_text.te_width = 0; /* don't know it yet. */
767 x->a_text.te_type = T_ATOM;
768 x->a_text.te_binbuf = binbuf_new();
769 x->a_glist = gl;
770 x->a_atom.a_type = type;
771 x->a_toggle = 1;
772 x->a_draglo = 0;
773 x->a_draghi = 0;
774 x->a_wherelabel = 0;
775 x->a_label = &s_;
776 x->a_symfrom = &s_;
777 x->a_symto = x->a_expanded_to = &s_;
778 if (type == A_FLOAT)
779 {
780 x->a_atom.a_w.w_float = 0;
781 x->a_text.te_width = 5;
782 SETFLOAT(&at, 0);
783 }
784 else
785 {
786 x->a_atom.a_w.w_symbol = &s_symbol;
787 x->a_text.te_width = 10;
788 SETSYMBOL(&at, &s_symbol);
789 }
790 binbuf_add(x->a_text.te_binbuf, 1, &at);
791 if (argc > 1)
792 /* create from file. x, y, width, low-range, high-range, flags,
793 label, receive-name, send-name */
794 {
795 x->a_text.te_xpix = atom_getfloatarg(0, argc, argv);
796 x->a_text.te_ypix = atom_getfloatarg(1, argc, argv);
797 x->a_text.te_width = atom_getintarg(2, argc, argv);
798 /* sanity check because some very old patches have trash in this
799 field... remove this in 2003 or so: */
800 if (x->a_text.te_width < 0 || x->a_text.te_width > 500)
801 x->a_text.te_width = 4;
802 x->a_draglo = atom_getfloatarg(3, argc, argv);
803 x->a_draghi = atom_getfloatarg(4, argc, argv);
804 x->a_wherelabel = (((int)atom_getfloatarg(5, argc, argv)) & 3);
805 x->a_label = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
806 x->a_symfrom = gatom_unescapit(atom_getsymbolarg(7, argc, argv));
807 if (*x->a_symfrom->s_name)
808 pd_bind(&x->a_text.te_pd,
809 canvas_realizedollar(x->a_glist, x->a_symfrom));
810
811 x->a_symto = gatom_unescapit(atom_getsymbolarg(8, argc, argv));
812 x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
813 if (x->a_symto == &s_)
814 outlet_new(&x->a_text,
815 x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
816 if (x->a_symfrom == &s_)
817 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
818 glist_add(gl, &x->a_text.te_g);
819 }
820 else
821 {
822 int xpix, ypix;
823 outlet_new(&x->a_text,
824 x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
825 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
826 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
827 glist_noselect(gl);
828 glist_getnextxy(gl, &xpix, &ypix);
829 x->a_text.te_xpix = xpix;
830 x->a_text.te_ypix = ypix;
831 glist_add(gl, &x->a_text.te_g);
832 glist_noselect(gl);
833 glist_select(gl, &x->a_text.te_g);
834 canvas_startmotion(glist_getcanvas(gl));
835 }
836}
837
838void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
839{
840 canvas_atom(gl, A_FLOAT, s, argc, argv);
841}
842
843void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
844{
845 canvas_atom(gl, A_SYMBOL, s, argc, argv);
846}
847
848static void gatom_free(t_gatom *x)
849{
850 if (*x->a_symfrom->s_name)
851 pd_unbind(&x->a_text.te_pd,
852 canvas_realizedollar(x->a_glist, x->a_symfrom));
853 gfxstub_deleteforkey(x);
854}
855
856static void gatom_properties(t_gobj *z, t_glist *owner)
857{
858 t_gatom *x = (t_gatom *)z;
859 char buf[200];
860 sprintf(buf, "pdtk_gatom_dialog %%s %d %g %g %d %s %s %s\n",
861 x->a_text.te_width, x->a_draglo, x->a_draghi,
862 x->a_wherelabel, gatom_escapit(x->a_label)->s_name,
863 gatom_escapit(x->a_symfrom)->s_name,
864 gatom_escapit(x->a_symto)->s_name);
865 gfxstub_new(&x->a_text.te_pd, x, buf);
866}
867
868
869/* -------------------- widget behavior for text objects ------------ */
870
871static void text_getrect(t_gobj *z, t_glist *glist,
872 int *xp1, int *yp1, int *xp2, int *yp2)
873{
874 t_text *x = (t_text *)z;
875 int width, height, iscomment = (x->te_type == T_TEXT);
876 float x1, y1, x2, y2;
877
878 /* for number boxes, we know width and height a priori, and should
879 report them here so that graphs can get swelled to fit. */
880
881 if (x->te_type == T_ATOM && x->te_width > 0)
882 {
883 int font = glist_getfont(glist);
884 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
885 width = (x->te_width > 0 ? x->te_width : 6) * fontwidth + 2;
886 height = fontheight + 1; /* borrowed from TMARGIN, etc, in g_rtext.c */
887 }
888 /* if we're invisible we don't know our size so we just lie about
889 it. This is called on invisible boxes to establish order of inlets
890 and possibly other reasons.
891 To find out if the box is visible we can't just check the "vis"
892 flag because we might be within the vis() routine and not have set
893 that yet. So we check directly whether the "rtext" list has been
894 built. LATER reconsider when "vis" flag should be on and off? */
895
896 else if (glist->gl_editor && glist->gl_editor->e_rtext)
897 {
898 t_rtext *y = glist_findrtext(glist, x);
899 width = rtext_width(y);
900 height = rtext_height(y) - (iscomment << 1);
901 }
902 else width = height = 10;
903 x1 = text_xpix(x, glist);
904 y1 = text_ypix(x, glist);
905 x2 = x1 + width;
906 y2 = y1 + height;
907 y1 += iscomment;
908 *xp1 = x1;
909 *yp1 = y1;
910 *xp2 = x2;
911 *yp2 = y2;
912}
913
914static void text_displace(t_gobj *z, t_glist *glist,
915 int dx, int dy)
916{
917 t_text *x = (t_text *)z;
918 x->te_xpix += dx;
919 x->te_ypix += dy;
920 if (glist_isvisible(glist))
921 {
922 t_rtext *y = glist_findrtext(glist, x);
923 rtext_displace(y, dx, dy);
924 text_drawborder(x, glist, rtext_gettag(y),
925 rtext_width(y), rtext_height(y), 0);
926 canvas_fixlinesfor(glist_getcanvas(glist), x);
927 }
928}
929
930static void text_select(t_gobj *z, t_glist *glist, int state)
931{
932 t_text *x = (t_text *)z;
933 t_rtext *y = glist_findrtext(glist, x);
934 rtext_select(y, state);
935 if (glist_isvisible(glist) && text_shouldvis(x, glist))
936 sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
937 rtext_gettag(y), (state? "blue" : "black"));
938}
939
940static void text_activate(t_gobj *z, t_glist *glist, int state)
941{
942 t_text *x = (t_text *)z;
943 t_rtext *y = glist_findrtext(glist, x);
944 if (z->g_pd != gatom_class) rtext_activate(y, state);
945}
946
947static void text_delete(t_gobj *z, t_glist *glist)
948{
949 t_text *x = (t_text *)z;
950 canvas_deletelinesfor(glist, x);
951}
952
953 /* return true if the text box should be drawn.
954 We don't show object boxes inside graphs. */
955int text_shouldvis(t_text *x, t_glist *glist)
956{
957 return (glist->gl_havewindow ||
958 (x->te_pd != canvas_class && x->te_pd->c_wb != &text_widgetbehavior) ||
959 (x->te_pd == canvas_class && (((t_glist *)x)->gl_isgraph)));
960}
961
962static void text_vis(t_gobj *z, t_glist *glist, int vis)
963{
964 t_text *x = (t_text *)z;
965 if (vis)
966 {
967 if (text_shouldvis(x, glist))
968 {
969 t_rtext *y = glist_findrtext(glist, x);
970 if (x->te_type == T_ATOM)
971 glist_retext(glist, x);
972 text_drawborder(x, glist, rtext_gettag(y),
973 rtext_width(y), rtext_height(y), 1);
974 rtext_draw(y);
975 }
976 }
977 else
978 {
979 t_rtext *y = glist_findrtext(glist, x);
980 if (text_shouldvis(x, glist))
981 {
982 text_eraseborder(x, glist, rtext_gettag(y));
983 rtext_erase(y);
984 }
985 }
986}
987
988static int text_click(t_gobj *z, struct _glist *glist,
989 int xpix, int ypix, int shift, int alt, int dbl, int doit)
990{
991 t_text *x = (t_text *)z;
992 if (x->te_type == T_OBJECT)
993 {
994 t_symbol *clicksym = gensym("click");
995 if (zgetfn(&x->te_pd, clicksym))
996 {
997 if (doit)
998 pd_vmess(&x->te_pd, clicksym, "fffff",
999 (double)xpix, (double)ypix,
1000 (double)shift, 0, (double)alt);
1001 return (1);
1002 }
1003 else return (0);
1004 }
1005 else if (x->te_type == T_ATOM)
1006 {
1007 if (doit)
1008 gatom_click((t_gatom *)x, (t_floatarg)xpix, (t_floatarg)ypix,
1009 (t_floatarg)shift, 0, (t_floatarg)alt);
1010 return (1);
1011 }
1012 else if (x->te_type == T_MESSAGE)
1013 {
1014 if (doit)
1015 message_click((t_message *)x, (t_floatarg)xpix, (t_floatarg)ypix,
1016 (t_floatarg)shift, 0, (t_floatarg)alt);
1017 return (1);
1018 }
1019 else return (0);
1020}
1021
1022void text_save(t_gobj *z, t_binbuf *b)
1023{
1024 t_text *x = (t_text *)z;
1025 if (x->te_type == T_OBJECT)
1026 {
1027 /* if we have a "saveto" method, and if we don't happen to be
1028 a canvas that's an abstraction, the saveto method does the work */
1029 if (zgetfn(&x->te_pd, gensym("saveto")) &&
1030 !((pd_class(&x->te_pd) == canvas_class) &&
1031 (canvas_isabstraction((t_canvas *)x)
1032 || canvas_istable((t_canvas *)x))))
1033 {
1034 mess1(&x->te_pd, gensym("saveto"), b);
1035 binbuf_addv(b, "ssii", gensym("#X"), gensym("restore"),
1036 (t_int)x->te_xpix, (t_int)x->te_ypix);
1037 }
1038 else /* otherwise just save the text */
1039 {
1040 binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"),
1041 (t_int)x->te_xpix, (t_int)x->te_ypix);
1042 }
1043 binbuf_addbinbuf(b, x->te_binbuf);
1044 binbuf_addv(b, ";");
1045 }
1046 else if (x->te_type == T_MESSAGE)
1047 {
1048 binbuf_addv(b, "ssii", gensym("#X"), gensym("msg"),
1049 (t_int)x->te_xpix, (t_int)x->te_ypix);
1050 binbuf_addbinbuf(b, x->te_binbuf);
1051 binbuf_addv(b, ";");
1052 }
1053 else if (x->te_type == T_ATOM)
1054 {
1055 t_atomtype t = ((t_gatom *)x)->a_atom.a_type;
1056 t_symbol *sel = (t == A_SYMBOL ? gensym("symbolatom") :
1057 (t == A_FLOAT ? gensym("floatatom") : gensym("intatom")));
1058 t_symbol *label = gatom_escapit(((t_gatom *)x)->a_label);
1059 t_symbol *symfrom = gatom_escapit(((t_gatom *)x)->a_symfrom);
1060 t_symbol *symto = gatom_escapit(((t_gatom *)x)->a_symto);
1061 binbuf_addv(b, "ssiiifffsss", gensym("#X"), sel,
1062 (t_int)x->te_xpix, (t_int)x->te_ypix, (t_int)x->te_width,
1063 (double)((t_gatom *)x)->a_draglo,
1064 (double)((t_gatom *)x)->a_draghi,
1065 (double)((t_gatom *)x)->a_wherelabel,
1066 label, symfrom, symto);
1067 binbuf_addv(b, ";");
1068 }
1069 else
1070 {
1071 binbuf_addv(b, "ssii", gensym("#X"), gensym("text"),
1072 (t_int)x->te_xpix, (t_int)x->te_ypix);
1073 binbuf_addbinbuf(b, x->te_binbuf);
1074 binbuf_addv(b, ";");
1075 }
1076}
1077
1078 /* this one is for everyone but "gatoms"; it's imposed in m_class.c */
1079t_widgetbehavior text_widgetbehavior =
1080{
1081 text_getrect,
1082 text_displace,
1083 text_select,
1084 text_activate,
1085 text_delete,
1086 text_vis,
1087 text_click,
1088};
1089
1090static t_widgetbehavior gatom_widgetbehavior =
1091{
1092 text_getrect,
1093 gatom_displace,
1094 text_select,
1095 text_activate,
1096 text_delete,
1097 gatom_vis,
1098 text_click,
1099};
1100
1101/* -------------------- the "text" class ------------ */
1102
1103#ifdef MACOSX
1104#define EXTRAPIX 2
1105#else
1106#define EXTRAPIX 1
1107#endif
1108
1109 /* draw inlets and outlets for a text object or for a graph. */
1110void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
1111 char *tag, int x1, int y1, int x2, int y2)
1112{
1113 int n = obj_noutlets(ob), nplus = (n == 1 ? 1 : n-1), i;
1114 int width = x2 - x1;
1115 for (i = 0; i < n; i++)
1116 {
1117 int onset = x1 + (width - IOWIDTH) * i / nplus;
1118 if (firsttime)
1119 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %so%d\n",
1120 glist_getcanvas(glist),
1121 onset, y2 - 1,
1122 onset + IOWIDTH, y2,
1123 tag, i);
1124 else
1125 sys_vgui(".x%x.c coords %so%d %d %d %d %d\n",
1126 glist_getcanvas(glist), tag, i,
1127 onset, y2 - 1,
1128 onset + IOWIDTH, y2);
1129 }
1130 n = obj_ninlets(ob);
1131 nplus = (n == 1 ? 1 : n-1);
1132 for (i = 0; i < n; i++)
1133 {
1134 int onset = x1 + (width - IOWIDTH) * i / nplus;
1135 if (firsttime)
1136 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %si%d\n",
1137 glist_getcanvas(glist),
1138 onset, y1,
1139 onset + IOWIDTH, y1 + EXTRAPIX,
1140 tag, i);
1141 else
1142 sys_vgui(".x%x.c coords %si%d %d %d %d %d\n",
1143 glist_getcanvas(glist), tag, i,
1144 onset, y1,
1145 onset + IOWIDTH, y1 + EXTRAPIX);
1146 }
1147}
1148
1149void text_drawborder(t_text *x, t_glist *glist,
1150 char *tag, int width2, int height2, int firsttime)
1151{
1152 t_object *ob;
1153 int x1, y1, x2, y2, width, height;
1154 text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2);
1155 width = x2 - x1;
1156 height = y2 - y1;
1157 if (x->te_type == T_OBJECT)
1158 {
1159 if (firsttime)
1160 sys_vgui(".x%x.c create line\
1161 %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
1162 glist_getcanvas(glist),
1163 x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, tag);
1164 else
1165 sys_vgui(".x%x.c coords %sR\
1166 %d %d %d %d %d %d %d %d %d %d\n",
1167 glist_getcanvas(glist), tag,
1168 x1, y1, x2, y1, x2, y2, x1, y2, x1, y1);
1169 }
1170 else if (x->te_type == T_MESSAGE)
1171 {
1172 if (firsttime)
1173 sys_vgui(".x%x.c create line\
1174 %d %d %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
1175 glist_getcanvas(glist),
1176 x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
1177 x1, y2, x1, y1,
1178 tag);
1179 else
1180 sys_vgui(".x%x.c coords %sR\
1181 %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
1182 glist_getcanvas(glist), tag,
1183 x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
1184 x1, y2, x1, y1);
1185 }
1186 else if (x->te_type == T_ATOM)
1187 {
1188 if (firsttime)
1189 sys_vgui(".x%x.c create line\
1190 %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
1191 glist_getcanvas(glist),
1192 x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1,
1193 tag);
1194 else
1195 sys_vgui(".x%x.c coords %sR\
1196 %d %d %d %d %d %d %d %d %d %d %d %d\n",
1197 glist_getcanvas(glist), tag,
1198 x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1);
1199 }
1200 /* draw inlets/outlets */
1201
1202 if (ob = pd_checkobject(&x->te_pd))
1203 glist_drawiofor(glist, ob, firsttime, tag, x1, y1, x2, y2);
1204}
1205
1206void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag)
1207{
1208 int i, n;
1209 n = obj_noutlets(ob);
1210 for (i = 0; i < n; i++)
1211 sys_vgui(".x%x.c delete %so%d\n",
1212 glist_getcanvas(glist), tag, i);
1213 n = obj_ninlets(ob);
1214 for (i = 0; i < n; i++)
1215 sys_vgui(".x%x.c delete %si%d\n",
1216 glist_getcanvas(glist), tag, i);
1217}
1218
1219void text_eraseborder(t_text *x, t_glist *glist, char *tag)
1220{
1221 if (x->te_type == T_TEXT) return;
1222 sys_vgui(".x%x.c delete %sR\n",
1223 glist_getcanvas(glist), tag);
1224 glist_eraseiofor(glist, x, tag);
1225}
1226
1227 /* change text; if T_OBJECT, remake it. LATER we'll have an undo buffer
1228 which should be filled in here before making the change. */
1229
1230void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
1231{
1232 if (x->te_type == T_OBJECT)
1233 {
1234 t_binbuf *b = binbuf_new();
1235 int natom1, natom2;
1236 t_atom *vec1, *vec2;
1237 binbuf_text(b, buf, bufsize);
1238 natom1 = binbuf_getnatom(x->te_binbuf);
1239 vec1 = binbuf_getvec(x->te_binbuf);
1240 natom2 = binbuf_getnatom(b);
1241 vec2 = binbuf_getvec(b);
1242 /* special case: if pd args change just pass the message on. */
1243 if (natom1 >= 1 && natom2 >= 1 && vec1[0].a_type == A_SYMBOL
1244 && !strcmp(vec1[0].a_w.w_symbol->s_name, "pd") &&
1245 vec2[0].a_type == A_SYMBOL
1246 && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
1247 {
1248 typedmess(&x->te_pd, gensym("rename"), natom2-1, vec2+1);
1249 binbuf_free(x->te_binbuf);
1250 x->te_binbuf = b;
1251 }
1252 else /* normally, just destroy the old one and make a new one. */
1253 {
1254 int xwas = x->te_xpix, ywas = x->te_ypix;
1255 glist_delete(glist, &x->te_g);
1256 canvas_objtext(glist, xwas, ywas, 0, b);
1257 /* if it's an abstraction loadbang it here */
1258 if (newest && pd_class(newest) == canvas_class)
1259 canvas_loadbang((t_canvas *)newest);
1260 canvas_restoreconnections(glist_getcanvas(glist));
1261 }
1262 /* if we made a new "pd" or changed a window name,
1263 update window list */
1264 if (natom2 >= 1 && vec2[0].a_type == A_SYMBOL
1265 && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
1266 canvas_updatewindowlist();
1267 }
1268 else binbuf_text(x->te_binbuf, buf, bufsize);
1269}
1270
1271void g_text_setup(void)
1272{
1273 text_class = class_new(gensym("text"), 0, 0, sizeof(t_text),
1274 CLASS_NOINLET | CLASS_PATCHABLE, 0);
1275
1276 message_class = class_new(gensym("message"), 0, (t_method)message_free,
1277 sizeof(t_message), CLASS_PATCHABLE, 0);
1278 class_addbang(message_class, message_bang);
1279 class_addfloat(message_class, message_float);
1280 class_addsymbol(message_class, message_symbol);
1281 class_addlist(message_class, message_list);
1282 class_addanything(message_class, message_list);
1283
1284 class_addmethod(message_class, (t_method)message_click, gensym("click"),
1285 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1286 class_addmethod(message_class, (t_method)message_set, gensym("set"),
1287 A_GIMME, 0);
1288 class_addmethod(message_class, (t_method)message_add, gensym("add"),
1289 A_GIMME, 0);
1290 class_addmethod(message_class, (t_method)message_add2, gensym("add2"),
1291 A_GIMME, 0);
1292
1293 messresponder_class = class_new(gensym("messresponder"), 0, 0,
1294 sizeof(t_text), CLASS_PD, 0);
1295 class_addbang(messresponder_class, messresponder_bang);
1296 class_addfloat(messresponder_class, (t_method) messresponder_float);
1297 class_addsymbol(messresponder_class, messresponder_symbol);
1298 class_addlist(messresponder_class, messresponder_list);
1299 class_addanything(messresponder_class, messresponder_anything);
1300
1301 gatom_class = class_new(gensym("gatom"), 0, (t_method)gatom_free,
1302 sizeof(t_gatom), CLASS_NOINLET | CLASS_PATCHABLE, 0);
1303 class_addbang(gatom_class, gatom_bang);
1304 class_addfloat(gatom_class, gatom_float);
1305 class_addsymbol(gatom_class, gatom_symbol);
1306 class_addmethod(gatom_class, (t_method)gatom_set, gensym("set"),
1307 A_GIMME, 0);
1308 class_addmethod(gatom_class, (t_method)gatom_click, gensym("click"),
1309 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1310 class_addmethod(gatom_class, (t_method)gatom_param, gensym("param"),
1311 A_GIMME, 0);
1312 class_setwidget(gatom_class, &gatom_widgetbehavior);
1313 class_setpropertiesfn(gatom_class, gatom_properties);
1314}
1315
1316
1317/* Copyright (c) 1997-1999 Miller Puckette.
1318* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1319* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1320
1321/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
1322/* the methods for calling the gui-objects from menu are implemented */
1323/* all changes are labeled with iemlib */
1324
1325#include <stdlib.h>
1326#include "m_pd.h"
1327#include "m_imp.h"
1328#include "s_stuff.h"
1329#include "t_tk.h"
1330#include "g_canvas.h"
1331#include <stdio.h>
1332#include <string.h>
1333#include <math.h>
1334
1335static t_class *text_class;
1336static t_class *message_class;
1337static t_class *gatom_class;
1338static void text_vis(t_gobj *z, t_glist *glist, int vis);
1339static void text_displace(t_gobj *z, t_glist *glist,
1340 int dx, int dy);
1341static void text_getrect(t_gobj *z, t_glist *glist,
1342 int *xp1, int *yp1, int *xp2, int *yp2);
1343
1344void canvas_startmotion(t_canvas *x);
1345t_widgetbehavior text_widgetbehavior;
1346
1347/* ----------------- the "text" object. ------------------ */
1348
1349 /* add a "text" object (comment) to a glist. While this one goes for any glist,
1350 the other 3 below are for canvases only. (why?) This is called
1351 without args if invoked from the GUI; otherwise at least x and y
1352 are provided. */
1353
1354void glist_text(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1355{
1356 t_text *x = (t_text *)pd_new(text_class);
1357 t_atom at;
1358 x->te_width = 0; /* don't know it yet. */
1359 x->te_type = T_TEXT;
1360 x->te_binbuf = binbuf_new();
1361 if (argc > 1)
1362 {
1363 x->te_xpix = atom_getfloatarg(0, argc, argv);
1364 x->te_ypix = atom_getfloatarg(1, argc, argv);
1365 if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
1366 else
1367 {
1368 SETSYMBOL(&at, gensym("comment"));
1369 binbuf_restore(x->te_binbuf, 1, &at);
1370 }
1371 glist_add(gl, &x->te_g);
1372 }
1373 else
1374 {
1375 int xpix, ypix;
1376 pd_vmess((t_pd *)glist_getcanvas(gl), gensym("editmode"), "i", 1);
1377 SETSYMBOL(&at, gensym("comment"));
1378 glist_noselect(gl);
1379 glist_getnextxy(gl, &xpix, &ypix);
1380 x->te_xpix = glist_pixelstox(gl, xpix-3);
1381 x->te_ypix = glist_pixelstoy(gl, ypix-3);
1382 binbuf_restore(x->te_binbuf, 1, &at);
1383 glist_add(gl, &x->te_g);
1384 glist_noselect(gl);
1385 glist_select(gl, &x->te_g);
1386 /* it would be nice to "activate" here, but then the second,
1387 "put-me-down" click changes the text selection, which is quite
1388 irritating, so I took this back out. It's OK in messages
1389 and objects though since there's no text in them at menu
1390 creation. */
1391 /* gobj_activate(&x->te_g, gl, 1); */
1392 canvas_startmotion(glist_getcanvas(gl));
1393 }
1394}
1395
1396/* ----------------- the "object" object. ------------------ */
1397
1398extern t_pd *newest;
1399void canvas_getargs(int *argcp, t_atom **argvp);
1400
1401static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected,
1402 t_binbuf *b)
1403{
1404 t_text *x;
1405 int argc;
1406 t_atom *argv;
1407 newest = 0;
1408 canvas_setcurrent((t_canvas *)gl);
1409 canvas_getargs(&argc, &argv);
1410 binbuf_eval(b, &pd_objectmaker, argc, argv);
1411 if (binbuf_getnatom(b))
1412 {
1413 if (!newest)
1414 {
1415 binbuf_print(b);
1416 post("... couldn't create");
1417 x = 0;
1418 }
1419 else if (!(x = pd_checkobject(newest)))
1420 {
1421 binbuf_print(b);
1422 post("... didn't return a patchable object");
1423 }
1424 }
1425 else x = 0;
1426 if (!x)
1427 {
1428
1429 /* LATER make the color reflect this */
1430 x = (t_text *)pd_new(text_class);
1431 }
1432 x->te_binbuf = b;
1433 x->te_xpix = xpix;
1434 x->te_ypix = ypix;
1435 x->te_width = 0;
1436 x->te_type = T_OBJECT;
1437 glist_add(gl, &x->te_g);
1438 if (selected)
1439 {
1440 /* this is called if we've been created from the menu. */
1441 glist_select(gl, &x->te_g);
1442 gobj_activate(&x->te_g, gl, 1);
1443 }
1444 if (pd_class(&x->ob_pd) == vinlet_class)
1445 canvas_resortinlets(glist_getcanvas(gl));
1446 if (pd_class(&x->ob_pd) == voutlet_class)
1447 canvas_resortoutlets(glist_getcanvas(gl));
1448 canvas_unsetcurrent((t_canvas *)gl);
1449}
1450
1451 /* object creation routine. These are called without any arguments if
1452 they're invoked from the
1453 gui; when pasting or restoring from a file, we get at least x and y. */
1454
1455void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1456{
1457 t_text *x;
1458 if (argc >= 2)
1459 {
1460 t_binbuf *b = binbuf_new();
1461 binbuf_restore(b, argc-2, argv+2);
1462 canvas_objtext(gl, atom_getintarg(0, argc, argv),
1463 atom_getintarg(1, argc, argv), 0, b);
1464 }
1465 else
1466 {
1467 t_binbuf *b = binbuf_new();
1468 int xpix, ypix;
1469 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
1470 glist_noselect(gl);
1471 glist_getnextxy(gl, &xpix, &ypix);
1472 canvas_objtext(gl, xpix, ypix, 1, b);
1473 canvas_startmotion(glist_getcanvas(gl));
1474 }
1475}
1476
1477/* make an object box for an object that's already there. */
1478
1479/* iemlib */
1480void canvas_iemguis(t_glist *gl, t_symbol *guiobjname)
1481{
1482 t_atom at;
1483 t_binbuf *b = binbuf_new();
1484 int xpix, ypix;
1485
1486 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
1487 glist_noselect(gl);
1488 SETSYMBOL(&at, guiobjname);
1489 binbuf_restore(b, 1, &at);
1490 glist_getnextxy(gl, &xpix, &ypix);
1491 canvas_objtext(gl, xpix, ypix, 1, b);
1492 canvas_startmotion(glist_getcanvas(gl));
1493}
1494
1495void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1496{
1497 canvas_iemguis(gl, gensym("bng"));
1498}
1499
1500void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1501{
1502 canvas_iemguis(gl, gensym("tgl"));
1503}
1504
1505void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1506{
1507 canvas_iemguis(gl, gensym("vsl"));
1508}
1509
1510void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1511{
1512 canvas_iemguis(gl, gensym("hsl"));
1513}
1514
1515void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1516{
1517 canvas_iemguis(gl, gensym("hdl"));
1518}
1519
1520void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1521{
1522 canvas_iemguis(gl, gensym("vdl"));
1523}
1524
1525void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1526{
1527 canvas_iemguis(gl, gensym("hradio"));
1528}
1529
1530void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1531{
1532 canvas_iemguis(gl, gensym("vradio"));
1533}
1534
1535void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1536{
1537 canvas_iemguis(gl, gensym("vu"));
1538}
1539
1540void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1541{
1542 canvas_iemguis(gl, gensym("cnv"));
1543}
1544
1545void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1546{
1547 canvas_iemguis(gl, gensym("nbx"));
1548}
1549
1550/* iemlib */
1551
1552void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv)
1553{
1554 x->te_width = 0; /* don't know it yet. */
1555 x->te_type = T_OBJECT;
1556 x->te_binbuf = binbuf_new();
1557 x->te_xpix = atom_getfloatarg(0, argc, argv);
1558 x->te_ypix = atom_getfloatarg(1, argc, argv);
1559 if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
1560 glist_add(gl, &x->te_g);
1561}
1562
1563/* ---------------------- the "message" text item ------------------------ */
1564
1565typedef struct _messresponder
1566{
1567 t_pd mr_pd;
1568 t_outlet *mr_outlet;
1569} t_messresponder;
1570
1571typedef struct _message
1572{
1573 t_text m_text;
1574 t_messresponder m_messresponder;
1575 t_glist *m_glist;
1576 t_clock *m_clock;
1577} t_message;
1578
1579static t_class *message_class, *messresponder_class;
1580
1581static void messresponder_bang(t_messresponder *x)
1582{
1583 outlet_bang(x->mr_outlet);
1584}
1585
1586static void messresponder_float(t_messresponder *x, t_float f)
1587{
1588 outlet_float(x->mr_outlet, f);
1589}
1590
1591static void messresponder_symbol(t_messresponder *x, t_symbol *s)
1592{
1593 outlet_symbol(x->mr_outlet, s);
1594}
1595
1596static void messresponder_list(t_messresponder *x,
1597 t_symbol *s, int argc, t_atom *argv)
1598{
1599 outlet_list(x->mr_outlet, s, argc, argv);
1600}
1601
1602static void messresponder_anything(t_messresponder *x,
1603 t_symbol *s, int argc, t_atom *argv)
1604{
1605 outlet_anything(x->mr_outlet, s, argc, argv);
1606}
1607
1608static void message_bang(t_message *x)
1609{
1610 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 0, 0);
1611}
1612
1613static void message_float(t_message *x, t_float f)
1614{
1615 t_atom at;
1616 SETFLOAT(&at, f);
1617 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
1618}
1619
1620static void message_symbol(t_message *x, t_symbol *s)
1621{
1622 t_atom at;
1623 SETSYMBOL(&at, s);
1624 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
1625}
1626
1627static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv)
1628{
1629 binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, argc, argv);
1630}
1631
1632static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv)
1633{
1634 binbuf_clear(x->m_text.te_binbuf);
1635 binbuf_add(x->m_text.te_binbuf, argc, argv);
1636 glist_retext(x->m_glist, &x->m_text);
1637}
1638
1639static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv)
1640{
1641 binbuf_add(x->m_text.te_binbuf, argc, argv);
1642 glist_retext(x->m_glist, &x->m_text);
1643}
1644
1645static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
1646{
1647 binbuf_add(x->m_text.te_binbuf, argc, argv);
1648 binbuf_addsemi(x->m_text.te_binbuf);
1649 glist_retext(x->m_glist, &x->m_text);
1650}
1651
1652static void message_click(t_message *x,
1653 t_floatarg xpos, t_floatarg ypos, t_floatarg shift,
1654 t_floatarg ctrl, t_floatarg alt)
1655{
1656 message_float(x, 0);
1657 if (glist_isvisible(x->m_glist))
1658 {
1659 t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
1660 sys_vgui(".x%x.c itemconfigure %sR -width 5\n",
1661 glist_getcanvas(x->m_glist), rtext_gettag(y));
1662 clock_delay(x->m_clock, 120);
1663 }
1664}
1665
1666static void message_tick(t_message *x)
1667{
1668 if (glist_isvisible(x->m_glist))
1669 {
1670 t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
1671 sys_vgui(".x%x.c itemconfigure %sR -width 1\n",
1672 glist_getcanvas(x->m_glist), rtext_gettag(y));
1673 }
1674}
1675
1676static void message_free(t_message *x)
1677{
1678 clock_free(x->m_clock);
1679}
1680
1681void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
1682{
1683 t_message *x = (t_message *)pd_new(message_class);
1684 x->m_messresponder.mr_pd = messresponder_class;
1685 x->m_messresponder.mr_outlet = outlet_new(&x->m_text, &s_float);
1686 x->m_text.te_width = 0; /* don't know it yet. */
1687 x->m_text.te_type = T_MESSAGE;
1688 x->m_text.te_binbuf = binbuf_new();
1689 x->m_glist = gl;
1690 x->m_clock = clock_new(x, (t_method)message_tick);
1691 if (argc > 1)
1692 {
1693 x->m_text.te_xpix = atom_getfloatarg(0, argc, argv);
1694 x->m_text.te_ypix = atom_getfloatarg(1, argc, argv);
1695 if (argc > 2) binbuf_restore(x->m_text.te_binbuf, argc-2, argv+2);
1696 glist_add(gl, &x->m_text.te_g);
1697 }
1698 else
1699 {
1700 int xpix, ypix;
1701 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
1702 glist_noselect(gl);
1703 glist_getnextxy(gl, &xpix, &ypix);
1704 x->m_text.te_xpix = xpix-3;
1705 x->m_text.te_ypix = ypix-3;
1706 glist_add(gl, &x->m_text.te_g);
1707 glist_noselect(gl);
1708 glist_select(gl, &x->m_text.te_g);
1709 gobj_activate(&x->m_text.te_g, gl, 1);
1710 canvas_startmotion(glist_getcanvas(gl));
1711 }
1712}
1713
1714/* ---------------------- the "atom" text item ------------------------ */
1715
1716#define ATOMBUFSIZE 40
1717#define ATOM_LABELLEFT 0
1718#define ATOM_LABELRIGHT 1
1719#define ATOM_LABELUP 2
1720#define ATOM_LABELDOWN 3
1721
1722typedef struct _gatom
1723{
1724 t_text a_text;
1725 t_atom a_atom; /* this holds the value and the type */
1726 t_glist *a_glist; /* owning glist */
1727 t_float a_toggle; /* value to toggle to */
1728 t_float a_draghi; /* high end of drag range */
1729 t_float a_draglo; /* low end of drag range */
1730 t_symbol *a_label; /* symbol to show as label next to box */
1731 t_symbol *a_symfrom; /* "receive" name -- bind ourselvs to this */
1732 t_symbol *a_symto; /* "send" name -- send to this on output */
1733 char a_buf[ATOMBUFSIZE];/* string buffer for typing */
1734 char a_shift; /* was shift key down when dragging started? */
1735 char a_wherelabel; /* 0-3 for left, right, above, below */
1736 t_symbol *a_expanded_to; /* a_symto after $0, $1, ... expansion */
1737} t_gatom;
1738
1739 /* prepend "-" as necessary to avoid empty strings, so we can
1740 use them in Pd messages. A more complete solution would be
1741 to introduce some quoting mechanism; but then we'd be much more
1742 complicated. */
1743static t_symbol *gatom_escapit(t_symbol *s)
1744{
1745 if (!*s->s_name)
1746 return (gensym("-"));
1747 else if (*s->s_name == '-')
1748 {
1749 char shmo[100];
1750 shmo[0] = '-';
1751 strncpy(shmo+1, s->s_name, 99);
1752 shmo[99] = 0;
1753 return (gensym(shmo));
1754 }
1755 else return (iemgui_dollar2raute(s));
1756}
1757
1758 /* undo previous operation: strip leading "-" if found. */
1759static t_symbol *gatom_unescapit(t_symbol *s)
1760{
1761 if (*s->s_name == '-')
1762 return (gensym(s->s_name+1));
1763 else return (iemgui_raute2dollar(s));
1764}
1765
1766#if 0 /* ??? */
1767 /* expand leading $0, $1, etc. in the symbol */
1768static t_symbol *gatom_realizedollar(t_gatom *x, t_symbol *s)
1769{
1770 return (canvas_realizedollar(x->a_glist, s));
1771}
1772#endif
1773
1774static void gatom_retext(t_gatom *x, int senditup)
1775{
1776 binbuf_clear(x->a_text.te_binbuf);
1777 binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom);
1778 if (senditup)
1779 glist_retext(x->a_glist, &x->a_text);
1780}
1781
1782static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv)
1783{
1784 t_atom oldatom = x->a_atom;
1785 int senditup = 0;
1786 if (!argc) return;
1787 if (x->a_atom.a_type == A_FLOAT)
1788 x->a_atom.a_w.w_float = atom_getfloat(argv),
1789 senditup = (x->a_atom.a_w.w_float != oldatom.a_w.w_float);
1790 else if (x->a_atom.a_type == A_SYMBOL)
1791 x->a_atom.a_w.w_symbol = atom_getsymbol(argv),
1792 senditup = (x->a_atom.a_w.w_symbol != oldatom.a_w.w_symbol);
1793 gatom_retext(x, senditup);
1794 x->a_buf[0] = 0;
1795}
1796
1797static void gatom_bang(t_gatom *x)
1798{
1799 if (x->a_atom.a_type == A_FLOAT)
1800 {
1801 if (x->a_text.te_outlet)
1802 outlet_float(x->a_text.te_outlet, x->a_atom.a_w.w_float);
1803 if (*x->a_expanded_to->s_name && x->a_expanded_to->s_thing)
1804 {
1805 if (x->a_symto == x->a_symfrom)
1806 pd_error(x,
1807 "%s: atom with same send/receive name (infinite loop)",
1808 x->a_symto->s_name);
1809 else pd_float(x->a_expanded_to->s_thing, x->a_atom.a_w.w_float);
1810 }
1811 }
1812 else if (x->a_atom.a_type == A_SYMBOL)
1813 {
1814 if (x->a_text.te_outlet)
1815 outlet_symbol(x->a_text.te_outlet, x->a_atom.a_w.w_symbol);
1816 if (*x->a_symto->s_name && x->a_expanded_to->s_thing)
1817 {
1818 if (x->a_symto == x->a_symfrom)
1819 pd_error(x,
1820 "%s: atom with same send/receive name (infinite loop)",
1821 x->a_symto->s_name);
1822 else pd_symbol(x->a_expanded_to->s_thing, x->a_atom.a_w.w_symbol);
1823 }
1824 }
1825}
1826
1827static void gatom_float(t_gatom *x, t_float f)
1828{
1829 t_atom at;
1830 SETFLOAT(&at, f);
1831 gatom_set(x, 0, 1, &at);
1832 gatom_bang(x);
1833}
1834
1835static void gatom_clipfloat(t_gatom *x, t_float f)
1836{
1837 if (x->a_draglo != 0 || x->a_draghi != 0)
1838 {
1839 if (f < x->a_draglo)
1840 f = x->a_draglo;
1841 if (f > x->a_draghi)
1842 f = x->a_draghi;
1843 }
1844 gatom_float(x, f);
1845}
1846
1847static void gatom_symbol(t_gatom *x, t_symbol *s)
1848{
1849 t_atom at;
1850 SETSYMBOL(&at, s);
1851 gatom_set(x, 0, 1, &at);
1852 gatom_bang(x);
1853}
1854
1855static void gatom_motion(void *z, t_floatarg dx, t_floatarg dy)
1856{
1857 t_gatom *x = (t_gatom *)z;
1858 if (dy == 0) return;
1859 if (x->a_atom.a_type == A_FLOAT)
1860 {
1861 if (x->a_shift)
1862 {
1863 double nval = x->a_atom.a_w.w_float - 0.01 * dy;
1864 double trunc = 0.01 * (floor(100. * nval + 0.5));
1865 if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
1866 gatom_clipfloat(x, nval);
1867 }
1868 else
1869 {
1870 double nval = x->a_atom.a_w.w_float - dy;
1871 double trunc = 0.01 * (floor(100. * nval + 0.5));
1872 if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
1873 trunc = floor(nval + 0.5);
1874 if (trunc < nval + 0.001 && trunc > nval - 0.001) nval = trunc;
1875 gatom_clipfloat(x, nval);
1876 }
1877 }
1878}
1879
1880static void gatom_key(void *z, t_floatarg f)
1881{
1882 t_gatom *x = (t_gatom *)z;
1883 int c = f;
1884 int len = strlen(x->a_buf);
1885 t_atom at;
1886 char sbuf[ATOMBUFSIZE + 4];
1887 if (c == 0)
1888 {
1889 /* we're being notified that no more keys will come for this grab */
1890 if (x->a_buf[0])
1891 gatom_retext(x, 1);
1892 return;
1893 }
1894 else if (c == ' ') return;
1895 else if (c == '\b')
1896 {
1897 if (len > 0)
1898 x->a_buf[len-1] = 0;
1899 goto redraw;
1900 }
1901 else if (c == '\n')
1902 {
1903 if (x->a_atom.a_type == A_FLOAT)
1904 x->a_atom.a_w.w_float = atof(x->a_buf);
1905 else if (x->a_atom.a_type == A_SYMBOL)
1906 x->a_atom.a_w.w_symbol = gensym(x->a_buf);
1907 else bug("gatom_key");
1908 gatom_bang(x);
1909 gatom_retext(x, 1);
1910 x->a_buf[0] = 0;
1911 }
1912 else if (len < (ATOMBUFSIZE-1))
1913 {
1914 /* for numbers, only let reasonable characters through */
1915 if ((x->a_atom.a_type == A_SYMBOL) ||
1916 (c >= '0' && c <= '9' || c == '.' || c == '-'
1917 || c == 'e' || c == 'E'))
1918 {
1919 x->a_buf[len] = c;
1920 x->a_buf[len+1] = 0;
1921 goto redraw;
1922 }
1923 }
1924 return;
1925redraw:
1926 /* LATER figure out how to avoid creating all these symbols! */
1927 sprintf(sbuf, "%s...", x->a_buf);
1928 SETSYMBOL(&at, gensym(sbuf));
1929 binbuf_clear(x->a_text.te_binbuf);
1930 binbuf_add(x->a_text.te_binbuf, 1, &at);
1931 glist_retext(x->a_glist, &x->a_text);
1932}
1933
1934static void gatom_click(t_gatom *x,
1935 t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl,
1936 t_floatarg alt)
1937{
1938 if (x->a_text.te_width == 1)
1939 {
1940 if (x->a_atom.a_type == A_FLOAT)
1941 gatom_float(x, (x->a_atom.a_w.w_float == 0));
1942 }
1943 else
1944 {
1945 if (alt)
1946 {
1947 if (x->a_atom.a_type != A_FLOAT) return;
1948 if (x->a_atom.a_w.w_float != 0)
1949 {
1950 x->a_toggle = x->a_atom.a_w.w_float;
1951 gatom_float(x, 0);
1952 return;
1953 }
1954 else gatom_float(x, x->a_toggle);
1955 }
1956 x->a_shift = shift;
1957 x->a_buf[0] = 0;
1958 glist_grab(x->a_glist, &x->a_text.te_g, gatom_motion, gatom_key,
1959 xpos, ypos);
1960 }
1961}
1962
1963 /* message back from dialog window */
1964static void gatom_param(t_gatom *x, t_symbol *sel, int argc, t_atom *argv)
1965{
1966 t_float width = atom_getfloatarg(0, argc, argv);
1967 t_float draglo = atom_getfloatarg(1, argc, argv);
1968 t_float draghi = atom_getfloatarg(2, argc, argv);
1969 t_symbol *label = gatom_unescapit(atom_getsymbolarg(3, argc, argv));
1970 t_float wherelabel = atom_getfloatarg(4, argc, argv);
1971 t_symbol *symfrom = gatom_unescapit(atom_getsymbolarg(5, argc, argv));
1972 t_symbol *symto = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
1973
1974 gobj_vis(&x->a_text.te_g, x->a_glist, 0);
1975 if (!*symfrom->s_name && *x->a_symfrom->s_name)
1976 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
1977 else if (*symfrom->s_name && !*x->a_symfrom->s_name && x->a_text.te_inlet)
1978 {
1979 canvas_deletelinesforio(x->a_glist, &x->a_text,
1980 x->a_text.te_inlet, 0);
1981 inlet_free(x->a_text.te_inlet);
1982 }
1983 if (!*symto->s_name && *x->a_symto->s_name)
1984 outlet_new(&x->a_text, 0);
1985 else if (*symto->s_name && !*x->a_symto->s_name && x->a_text.te_outlet)
1986 {
1987 canvas_deletelinesforio(x->a_glist, &x->a_text,
1988 0, x->a_text.te_outlet);
1989 outlet_free(x->a_text.te_outlet);
1990 }
1991 if (draglo >= draghi)
1992 draglo = draghi = 0;
1993 x->a_draglo = draglo;
1994 x->a_draghi = draghi;
1995 if (width < 0)
1996 width = 4;
1997 else if (width > 80)
1998 width = 80;
1999 x->a_text.te_width = width;
2000 x->a_wherelabel = ((int)wherelabel & 3);
2001 x->a_label = label;
2002 if (*x->a_symfrom->s_name)
2003 pd_unbind(&x->a_text.te_pd,
2004 canvas_realizedollar(x->a_glist, x->a_symfrom));
2005 x->a_symfrom = symfrom;
2006 if (*x->a_symfrom->s_name)
2007 pd_bind(&x->a_text.te_pd,
2008 canvas_realizedollar(x->a_glist, x->a_symfrom));
2009 x->a_symto = symto;
2010 x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
2011 gobj_vis(&x->a_text.te_g, x->a_glist, 1);
2012
2013 /* glist_retext(x->a_glist, &x->a_text); */
2014}
2015
2016 /* ---------------- gatom-specific widget functions --------------- */
2017static void gatom_getwherelabel(t_gatom *x, t_glist *glist, int *xp, int *yp)
2018{
2019 int x1, y1, x2, y2, width, height;
2020 text_getrect(&x->a_text.te_g, glist, &x1, &y1, &x2, &y2);
2021 width = x2 - x1;
2022 height = y2 - y1;
2023 if (x->a_wherelabel == ATOM_LABELLEFT)
2024 {
2025 *xp = x1 - 3 -
2026 strlen(canvas_realizedollar(x->a_glist, x->a_label)->s_name) *
2027 sys_fontwidth(glist_getfont(glist));
2028 *yp = y1 + 2;
2029 }
2030 else if (x->a_wherelabel == ATOM_LABELRIGHT)
2031 {
2032 *xp = x2 + 2;
2033 *yp = y1 + 2;
2034 }
2035 else if (x->a_wherelabel == ATOM_LABELUP)
2036 {
2037 *xp = x1 - 1;
2038 *yp = y1 - 1 - sys_fontheight(glist_getfont(glist));;
2039 }
2040 else
2041 {
2042 *xp = x1 - 1;
2043 *yp = y2 + 3;
2044 }
2045}
2046
2047static void gatom_displace(t_gobj *z, t_glist *glist,
2048 int dx, int dy)
2049{
2050 t_gatom *x = (t_gatom*)z;
2051 text_displace(z, glist, dx, dy);
2052 sys_vgui(".x%x.c move %x.l %d %d\n", glist_getcanvas(glist),
2053 x, dx, dy);
2054}
2055
2056static void gatom_vis(t_gobj *z, t_glist *glist, int vis)
2057{
2058 t_gatom *x = (t_gatom*)z;
2059 text_vis(z, glist, vis);
2060 if (*x->a_label->s_name)
2061 {
2062 if (vis)
2063 {
2064 int x1, y1;
2065 gatom_getwherelabel(x, glist, &x1, &y1);
2066 sys_vgui("pdtk_text_new .x%x.c %x.l %f %f {%s} %d %s\n",
2067 glist_getcanvas(glist), x,
2068 (double)x1, (double)y1,
2069 canvas_realizedollar(x->a_glist, x->a_label)->s_name,
2070 sys_hostfontsize(glist_getfont(glist)),
2071 "black");
2072 }
2073 else sys_vgui(".x%x.c delete %x.l\n", glist_getcanvas(glist), x);
2074 }
2075}
2076
2077void canvas_atom(t_glist *gl, t_atomtype type,
2078 t_symbol *s, int argc, t_atom *argv)
2079{
2080 t_gatom *x = (t_gatom *)pd_new(gatom_class);
2081 t_atom at;
2082 x->a_text.te_width = 0; /* don't know it yet. */
2083 x->a_text.te_type = T_ATOM;
2084 x->a_text.te_binbuf = binbuf_new();
2085 x->a_glist = gl;
2086 x->a_atom.a_type = type;
2087 x->a_toggle = 1;
2088 x->a_draglo = 0;
2089 x->a_draghi = 0;
2090 x->a_wherelabel = 0;
2091 x->a_label = &s_;
2092 x->a_symfrom = &s_;
2093 x->a_symto = x->a_expanded_to = &s_;
2094 if (type == A_FLOAT)
2095 {
2096 x->a_atom.a_w.w_float = 0;
2097 x->a_text.te_width = 5;
2098 SETFLOAT(&at, 0);
2099 }
2100 else
2101 {
2102 x->a_atom.a_w.w_symbol = &s_symbol;
2103 x->a_text.te_width = 10;
2104 SETSYMBOL(&at, &s_symbol);
2105 }
2106 binbuf_add(x->a_text.te_binbuf, 1, &at);
2107 if (argc > 1)
2108 /* create from file. x, y, width, low-range, high-range, flags,
2109 label, receive-name, send-name */
2110 {
2111 x->a_text.te_xpix = atom_getfloatarg(0, argc, argv);
2112 x->a_text.te_ypix = atom_getfloatarg(1, argc, argv);
2113 x->a_text.te_width = atom_getintarg(2, argc, argv);
2114 /* sanity check because some very old patches have trash in this
2115 field... remove this in 2003 or so: */
2116 if (x->a_text.te_width < 0 || x->a_text.te_width > 500)
2117 x->a_text.te_width = 4;
2118 x->a_draglo = atom_getfloatarg(3, argc, argv);
2119 x->a_draghi = atom_getfloatarg(4, argc, argv);
2120 x->a_wherelabel = (((int)atom_getfloatarg(5, argc, argv)) & 3);
2121 x->a_label = gatom_unescapit(atom_getsymbolarg(6, argc, argv));
2122 x->a_symfrom = gatom_unescapit(atom_getsymbolarg(7, argc, argv));
2123 if (*x->a_symfrom->s_name)
2124 pd_bind(&x->a_text.te_pd,
2125 canvas_realizedollar(x->a_glist, x->a_symfrom));
2126
2127 x->a_symto = gatom_unescapit(atom_getsymbolarg(8, argc, argv));
2128 x->a_expanded_to = canvas_realizedollar(x->a_glist, x->a_symto);
2129 if (x->a_symto == &s_)
2130 outlet_new(&x->a_text,
2131 x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
2132 if (x->a_symfrom == &s_)
2133 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
2134 glist_add(gl, &x->a_text.te_g);
2135 }
2136 else
2137 {
2138 int xpix, ypix;
2139 outlet_new(&x->a_text,
2140 x->a_atom.a_type == A_FLOAT ? &s_float: &s_symbol);
2141 inlet_new(&x->a_text, &x->a_text.te_pd, 0, 0);
2142 pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
2143 glist_noselect(gl);
2144 glist_getnextxy(gl, &xpix, &ypix);
2145 x->a_text.te_xpix = xpix;
2146 x->a_text.te_ypix = ypix;
2147 glist_add(gl, &x->a_text.te_g);
2148 glist_noselect(gl);
2149 glist_select(gl, &x->a_text.te_g);
2150 canvas_startmotion(glist_getcanvas(gl));
2151 }
2152}
2153
2154void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
2155{
2156 canvas_atom(gl, A_FLOAT, s, argc, argv);
2157}
2158
2159void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
2160{
2161 canvas_atom(gl, A_SYMBOL, s, argc, argv);
2162}
2163
2164static void gatom_free(t_gatom *x)
2165{
2166 if (*x->a_symfrom->s_name)
2167 pd_unbind(&x->a_text.te_pd,
2168 canvas_realizedollar(x->a_glist, x->a_symfrom));
2169 gfxstub_deleteforkey(x);
2170}
2171
2172static void gatom_properties(t_gobj *z, t_glist *owner)
2173{
2174 t_gatom *x = (t_gatom *)z;
2175 char buf[200];
2176 sprintf(buf, "pdtk_gatom_dialog %%s %d %g %g %d %s %s %s\n",
2177 x->a_text.te_width, x->a_draglo, x->a_draghi,
2178 x->a_wherelabel, gatom_escapit(x->a_label)->s_name,
2179 gatom_escapit(x->a_symfrom)->s_name,
2180 gatom_escapit(x->a_symto)->s_name);
2181 gfxstub_new(&x->a_text.te_pd, x, buf);
2182}
2183
2184
2185/* -------------------- widget behavior for text objects ------------ */
2186
2187static void text_getrect(t_gobj *z, t_glist *glist,
2188 int *xp1, int *yp1, int *xp2, int *yp2)
2189{
2190 t_text *x = (t_text *)z;
2191 int width, height, iscomment = (x->te_type == T_TEXT);
2192 float x1, y1, x2, y2;
2193
2194 /* for number boxes, we know width and height a priori, and should
2195 report them here so that graphs can get swelled to fit. */
2196
2197 if (x->te_type == T_ATOM && x->te_width > 0)
2198 {
2199 int font = glist_getfont(glist);
2200 int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
2201 width = (x->te_width > 0 ? x->te_width : 6) * fontwidth + 2;
2202 height = fontheight + 1; /* borrowed from TMARGIN, etc, in g_rtext.c */
2203 }
2204 /* if we're invisible we don't know our size so we just lie about
2205 it. This is called on invisible boxes to establish order of inlets
2206 and possibly other reasons.
2207 To find out if the box is visible we can't just check the "vis"
2208 flag because we might be within the vis() routine and not have set
2209 that yet. So we check directly whether the "rtext" list has been
2210 built. LATER reconsider when "vis" flag should be on and off? */
2211
2212 else if (glist->gl_editor && glist->gl_editor->e_rtext)
2213 {
2214 t_rtext *y = glist_findrtext(glist, x);
2215 width = rtext_width(y);
2216 height = rtext_height(y) - (iscomment << 1);
2217 }
2218 else width = height = 10;
2219 x1 = text_xpix(x, glist);
2220 y1 = text_ypix(x, glist);
2221 x2 = x1 + width;
2222 y2 = y1 + height;
2223 y1 += iscomment;
2224 *xp1 = x1;
2225 *yp1 = y1;
2226 *xp2 = x2;
2227 *yp2 = y2;
2228}
2229
2230static void text_displace(t_gobj *z, t_glist *glist,
2231 int dx, int dy)
2232{
2233 t_text *x = (t_text *)z;
2234 x->te_xpix += dx;
2235 x->te_ypix += dy;
2236 if (glist_isvisible(glist))
2237 {
2238 t_rtext *y = glist_findrtext(glist, x);
2239 rtext_displace(y, dx, dy);
2240 text_drawborder(x, glist, rtext_gettag(y),
2241 rtext_width(y), rtext_height(y), 0);
2242 canvas_fixlinesfor(glist_getcanvas(glist), x);
2243 }
2244}
2245
2246static void text_select(t_gobj *z, t_glist *glist, int state)
2247{
2248 t_text *x = (t_text *)z;
2249 t_rtext *y = glist_findrtext(glist, x);
2250 rtext_select(y, state);
2251 if (glist_isvisible(glist) && text_shouldvis(x, glist))
2252 sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
2253 rtext_gettag(y), (state? "blue" : "black"));
2254}
2255
2256static void text_activate(t_gobj *z, t_glist *glist, int state)
2257{
2258 t_text *x = (t_text *)z;
2259 t_rtext *y = glist_findrtext(glist, x);
2260 if (z->g_pd != gatom_class) rtext_activate(y, state);
2261}
2262
2263static void text_delete(t_gobj *z, t_glist *glist)
2264{
2265 t_text *x = (t_text *)z;
2266 canvas_deletelinesfor(glist, x);
2267}
2268
2269 /* return true if the text box should be drawn.
2270 We don't show object boxes inside graphs. */
2271int text_shouldvis(t_text *x, t_glist *glist)
2272{
2273 return (glist->gl_havewindow ||
2274 (x->te_pd != canvas_class && x->te_pd->c_wb != &text_widgetbehavior) ||
2275 (x->te_pd == canvas_class && (((t_glist *)x)->gl_isgraph)));
2276}
2277
2278static void text_vis(t_gobj *z, t_glist *glist, int vis)
2279{
2280 t_text *x = (t_text *)z;
2281 if (vis)
2282 {
2283 if (text_shouldvis(x, glist))
2284 {
2285 t_rtext *y = glist_findrtext(glist, x);
2286 if (x->te_type == T_ATOM)
2287 glist_retext(glist, x);
2288 text_drawborder(x, glist, rtext_gettag(y),
2289 rtext_width(y), rtext_height(y), 1);
2290 rtext_draw(y);
2291 }
2292 }
2293 else
2294 {
2295 t_rtext *y = glist_findrtext(glist, x);
2296 if (text_shouldvis(x, glist))
2297 {
2298 text_eraseborder(x, glist, rtext_gettag(y));
2299 rtext_erase(y);
2300 }
2301 }
2302}
2303
2304static int text_click(t_gobj *z, struct _glist *glist,
2305 int xpix, int ypix, int shift, int alt, int dbl, int doit)
2306{
2307 t_text *x = (t_text *)z;
2308 if (x->te_type == T_OBJECT)
2309 {
2310 t_symbol *clicksym = gensym("click");
2311 if (zgetfn(&x->te_pd, clicksym))
2312 {
2313 if (doit)
2314 pd_vmess(&x->te_pd, clicksym, "fffff",
2315 (double)xpix, (double)ypix,
2316 (double)shift, 0, (double)alt);
2317 return (1);
2318 }
2319 else return (0);
2320 }
2321 else if (x->te_type == T_ATOM)
2322 {
2323 if (doit)
2324 gatom_click((t_gatom *)x, (t_floatarg)xpix, (t_floatarg)ypix,
2325 (t_floatarg)shift, 0, (t_floatarg)alt);
2326 return (1);
2327 }
2328 else if (x->te_type == T_MESSAGE)
2329 {
2330 if (doit)
2331 message_click((t_message *)x, (t_floatarg)xpix, (t_floatarg)ypix,
2332 (t_floatarg)shift, 0, (t_floatarg)alt);
2333 return (1);
2334 }
2335 else return (0);
2336}
2337
2338void text_save(t_gobj *z, t_binbuf *b)
2339{
2340 t_text *x = (t_text *)z;
2341 if (x->te_type == T_OBJECT)
2342 {
2343 /* if we have a "saveto" method, and if we don't happen to be
2344 a canvas that's an abstraction, the saveto method does the work */
2345 if (zgetfn(&x->te_pd, gensym("saveto")) &&
2346 !((pd_class(&x->te_pd) == canvas_class) &&
2347 (canvas_isabstraction((t_canvas *)x)
2348 || canvas_istable((t_canvas *)x))))
2349 {
2350 mess1(&x->te_pd, gensym("saveto"), b);
2351 binbuf_addv(b, "ssii", gensym("#X"), gensym("restore"),
2352 (t_int)x->te_xpix, (t_int)x->te_ypix);
2353 }
2354 else /* otherwise just save the text */
2355 {
2356 binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"),
2357 (t_int)x->te_xpix, (t_int)x->te_ypix);
2358 }
2359 binbuf_addbinbuf(b, x->te_binbuf);
2360 binbuf_addv(b, ";");
2361 }
2362 else if (x->te_type == T_MESSAGE)
2363 {
2364 binbuf_addv(b, "ssii", gensym("#X"), gensym("msg"),
2365 (t_int)x->te_xpix, (t_int)x->te_ypix);
2366 binbuf_addbinbuf(b, x->te_binbuf);
2367 binbuf_addv(b, ";");
2368 }
2369 else if (x->te_type == T_ATOM)
2370 {
2371 t_atomtype t = ((t_gatom *)x)->a_atom.a_type;
2372 t_symbol *sel = (t == A_SYMBOL ? gensym("symbolatom") :
2373 (t == A_FLOAT ? gensym("floatatom") : gensym("intatom")));
2374 t_symbol *label = gatom_escapit(((t_gatom *)x)->a_label);
2375 t_symbol *symfrom = gatom_escapit(((t_gatom *)x)->a_symfrom);
2376 t_symbol *symto = gatom_escapit(((t_gatom *)x)->a_symto);
2377 binbuf_addv(b, "ssiiifffsss", gensym("#X"), sel,
2378 (t_int)x->te_xpix, (t_int)x->te_ypix, (t_int)x->te_width,
2379 (double)((t_gatom *)x)->a_draglo,
2380 (double)((t_gatom *)x)->a_draghi,
2381 (double)((t_gatom *)x)->a_wherelabel,
2382 label, symfrom, symto);
2383 binbuf_addv(b, ";");
2384 }
2385 else
2386 {
2387 binbuf_addv(b, "ssii", gensym("#X"), gensym("text"),
2388 (t_int)x->te_xpix, (t_int)x->te_ypix);
2389 binbuf_addbinbuf(b, x->te_binbuf);
2390 binbuf_addv(b, ";");
2391 }
2392}
2393
2394 /* this one is for everyone but "gatoms"; it's imposed in m_class.c */
2395t_widgetbehavior text_widgetbehavior =
2396{
2397 text_getrect,
2398 text_displace,
2399 text_select,
2400 text_activate,
2401 text_delete,
2402 text_vis,
2403 text_click,
2404};
2405
2406static t_widgetbehavior gatom_widgetbehavior =
2407{
2408 text_getrect,
2409 gatom_displace,
2410 text_select,
2411 text_activate,
2412 text_delete,
2413 gatom_vis,
2414 text_click,
2415};
2416
2417/* -------------------- the "text" class ------------ */
2418
2419#ifdef MACOSX
2420#define EXTRAPIX 2
2421#else
2422#define EXTRAPIX 1
2423#endif
2424
2425 /* draw inlets and outlets for a text object or for a graph. */
2426void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
2427 char *tag, int x1, int y1, int x2, int y2)
2428{
2429 int n = obj_noutlets(ob), nplus = (n == 1 ? 1 : n-1), i;
2430 int width = x2 - x1;
2431 for (i = 0; i < n; i++)
2432 {
2433 int onset = x1 + (width - IOWIDTH) * i / nplus;
2434 if (firsttime)
2435 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %so%d\n",
2436 glist_getcanvas(glist),
2437 onset, y2 - 1,
2438 onset + IOWIDTH, y2,
2439 tag, i);
2440 else
2441 sys_vgui(".x%x.c coords %so%d %d %d %d %d\n",
2442 glist_getcanvas(glist), tag, i,
2443 onset, y2 - 1,
2444 onset + IOWIDTH, y2);
2445 }
2446 n = obj_ninlets(ob);
2447 nplus = (n == 1 ? 1 : n-1);
2448 for (i = 0; i < n; i++)
2449 {
2450 int onset = x1 + (width - IOWIDTH) * i / nplus;
2451 if (firsttime)
2452 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %si%d\n",
2453 glist_getcanvas(glist),
2454 onset, y1,
2455 onset + IOWIDTH, y1 + EXTRAPIX,
2456 tag, i);
2457 else
2458 sys_vgui(".x%x.c coords %si%d %d %d %d %d\n",
2459 glist_getcanvas(glist), tag, i,
2460 onset, y1,
2461 onset + IOWIDTH, y1 + EXTRAPIX);
2462 }
2463}
2464
2465void text_drawborder(t_text *x, t_glist *glist,
2466 char *tag, int width2, int height2, int firsttime)
2467{
2468 t_object *ob;
2469 int x1, y1, x2, y2, width, height;
2470 text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2);
2471 width = x2 - x1;
2472 height = y2 - y1;
2473 if (x->te_type == T_OBJECT)
2474 {
2475 if (firsttime)
2476 sys_vgui(".x%x.c create line\
2477 %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
2478 glist_getcanvas(glist),
2479 x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, tag);
2480 else
2481 sys_vgui(".x%x.c coords %sR\
2482 %d %d %d %d %d %d %d %d %d %d\n",
2483 glist_getcanvas(glist), tag,
2484 x1, y1, x2, y1, x2, y2, x1, y2, x1, y1);
2485 }
2486 else if (x->te_type == T_MESSAGE)
2487 {
2488 if (firsttime)
2489 sys_vgui(".x%x.c create line\
2490 %d %d %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
2491 glist_getcanvas(glist),
2492 x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
2493 x1, y2, x1, y1,
2494 tag);
2495 else
2496 sys_vgui(".x%x.c coords %sR\
2497 %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
2498 glist_getcanvas(glist), tag,
2499 x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
2500 x1, y2, x1, y1);
2501 }
2502 else if (x->te_type == T_ATOM)
2503 {
2504 if (firsttime)
2505 sys_vgui(".x%x.c create line\
2506 %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
2507 glist_getcanvas(glist),
2508 x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1,
2509 tag);
2510 else
2511 sys_vgui(".x%x.c coords %sR\
2512 %d %d %d %d %d %d %d %d %d %d %d %d\n",
2513 glist_getcanvas(glist), tag,
2514 x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1);
2515 }
2516 /* draw inlets/outlets */
2517
2518 if (ob = pd_checkobject(&x->te_pd))
2519 glist_drawiofor(glist, ob, firsttime, tag, x1, y1, x2, y2);
2520}
2521
2522void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag)
2523{
2524 int i, n;
2525 n = obj_noutlets(ob);
2526 for (i = 0; i < n; i++)
2527 sys_vgui(".x%x.c delete %so%d\n",
2528 glist_getcanvas(glist), tag, i);
2529 n = obj_ninlets(ob);
2530 for (i = 0; i < n; i++)
2531 sys_vgui(".x%x.c delete %si%d\n",
2532 glist_getcanvas(glist), tag, i);
2533}
2534
2535void text_eraseborder(t_text *x, t_glist *glist, char *tag)
2536{
2537 if (x->te_type == T_TEXT) return;
2538 sys_vgui(".x%x.c delete %sR\n",
2539 glist_getcanvas(glist), tag);
2540 glist_eraseiofor(glist, x, tag);
2541}
2542
2543 /* change text; if T_OBJECT, remake it. LATER we'll have an undo buffer
2544 which should be filled in here before making the change. */
2545
2546void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
2547{
2548 if (x->te_type == T_OBJECT)
2549 {
2550 t_binbuf *b = binbuf_new();
2551 int natom1, natom2;
2552 t_atom *vec1, *vec2;
2553 binbuf_text(b, buf, bufsize);
2554 natom1 = binbuf_getnatom(x->te_binbuf);
2555 vec1 = binbuf_getvec(x->te_binbuf);
2556 natom2 = binbuf_getnatom(b);
2557 vec2 = binbuf_getvec(b);
2558 /* special case: if pd args change just pass the message on. */
2559 if (natom1 >= 1 && natom2 >= 1 && vec1[0].a_type == A_SYMBOL
2560 && !strcmp(vec1[0].a_w.w_symbol->s_name, "pd") &&
2561 vec2[0].a_type == A_SYMBOL
2562 && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
2563 {
2564 typedmess(&x->te_pd, gensym("rename"), natom2-1, vec2+1);
2565 binbuf_free(x->te_binbuf);
2566 x->te_binbuf = b;
2567 }
2568 else /* normally, just destroy the old one and make a new one. */
2569 {
2570 int xwas = x->te_xpix, ywas = x->te_ypix;
2571 glist_delete(glist, &x->te_g);
2572 canvas_objtext(glist, xwas, ywas, 0, b);
2573 /* if it's an abstraction loadbang it here */
2574 if (newest && pd_class(newest) == canvas_class)
2575 canvas_loadbang((t_canvas *)newest);
2576 canvas_restoreconnections(glist_getcanvas(glist));
2577 }
2578 /* if we made a new "pd" or changed a window name,
2579 update window list */
2580 if (natom2 >= 1 && vec2[0].a_type == A_SYMBOL
2581 && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
2582 canvas_updatewindowlist();
2583 }
2584 else binbuf_text(x->te_binbuf, buf, bufsize);
2585}
2586
2587void g_text_setup(void)
2588{
2589 text_class = class_new(gensym("text"), 0, 0, sizeof(t_text),
2590 CLASS_NOINLET | CLASS_PATCHABLE, 0);
2591
2592 message_class = class_new(gensym("message"), 0, (t_method)message_free,
2593 sizeof(t_message), CLASS_PATCHABLE, 0);
2594 class_addbang(message_class, message_bang);
2595 class_addfloat(message_class, message_float);
2596 class_addsymbol(message_class, message_symbol);
2597 class_addlist(message_class, message_list);
2598 class_addanything(message_class, message_list);
2599
2600 class_addmethod(message_class, (t_method)message_click, gensym("click"),
2601 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
2602 class_addmethod(message_class, (t_method)message_set, gensym("set"),
2603 A_GIMME, 0);
2604 class_addmethod(message_class, (t_method)message_add, gensym("add"),
2605 A_GIMME, 0);
2606 class_addmethod(message_class, (t_method)message_add2, gensym("add2"),
2607 A_GIMME, 0);
2608
2609 messresponder_class = class_new(gensym("messresponder"), 0, 0,
2610 sizeof(t_text), CLASS_PD, 0);
2611 class_addbang(messresponder_class, messresponder_bang);
2612 class_addfloat(messresponder_class, (t_method) messresponder_float);
2613 class_addsymbol(messresponder_class, messresponder_symbol);
2614 class_addlist(messresponder_class, messresponder_list);
2615 class_addanything(messresponder_class, messresponder_anything);
2616
2617 gatom_class = class_new(gensym("gatom"), 0, (t_method)gatom_free,
2618 sizeof(t_gatom), CLASS_NOINLET | CLASS_PATCHABLE, 0);
2619 class_addbang(gatom_class, gatom_bang);
2620 class_addfloat(gatom_class, gatom_float);
2621 class_addsymbol(gatom_class, gatom_symbol);
2622 class_addmethod(gatom_class, (t_method)gatom_set, gensym("set"),
2623 A_GIMME, 0);
2624 class_addmethod(gatom_class, (t_method)gatom_click, gensym("click"),
2625 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
2626 class_addmethod(gatom_class, (t_method)gatom_param, gensym("param"),
2627 A_GIMME, 0);
2628 class_setwidget(gatom_class, &gatom_widgetbehavior);
2629 class_setpropertiesfn(gatom_class, gatom_properties);
2630}
2631
2632
diff --git a/apps/plugins/pdbox/PDa/src/g_toggle.c b/apps/plugins/pdbox/PDa/src/g_toggle.c
new file mode 100644
index 0000000000..b6bb9f3daf
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_toggle.c
@@ -0,0 +1,948 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
7
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <ctype.h>
13#include "m_pd.h"
14#include "g_canvas.h"
15#include "t_tk.h"
16#include "g_all_guis.h"
17#include <math.h>
18
19#ifdef MSW
20#include <io.h>
21#else
22#include <unistd.h>
23#endif
24
25/* --------------- tgl gui-toggle ------------------------- */
26
27t_widgetbehavior toggle_widgetbehavior;
28static t_class *toggle_class;
29
30/* widget helper functions */
31
32void toggle_draw_update(t_toggle *x, t_glist *glist)
33{
34 if(glist_isvisible(glist))
35 {
36 t_canvas *canvas=glist_getcanvas(glist);
37
38 sys_vgui(".x%x.c itemconfigure %xX1 -fill #%6.6x\n", canvas, x,
39 (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol);
40 sys_vgui(".x%x.c itemconfigure %xX2 -fill #%6.6x\n", canvas, x,
41 (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol);
42 }
43}
44
45void toggle_draw_new(t_toggle *x, t_glist *glist)
46{
47 t_canvas *canvas=glist_getcanvas(glist);
48 int w=1, xx=text_xpix(&x->x_gui.x_obj, glist), yy=text_ypix(&x->x_gui.x_obj, glist);
49
50 if(x->x_gui.x_w >= 30)
51 w = 2;
52 if(x->x_gui.x_w >= 60)
53 w = 3;
54 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
55 canvas, xx, yy, xx + x->x_gui.x_w, yy + x->x_gui.x_h,
56 x->x_gui.x_bcol, x);
57 sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xX1\n",
58 canvas, xx+w+1, yy+w+1, xx + x->x_gui.x_w-w, yy + x->x_gui.x_h-w, w,
59 (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
60 sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xX2\n",
61 canvas, xx+w+1, yy + x->x_gui.x_h-w-1, xx + x->x_gui.x_w-w, yy+w, w,
62 (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
63 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
64 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
65 canvas, xx+x->x_gui.x_ldx,
66 yy+x->x_gui.x_ldy,
67 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
68 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
69 if(!x->x_gui.x_fsf.x_snd_able)
70 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
71 canvas, xx, yy + x->x_gui.x_h-1, xx + IOWIDTH, yy + x->x_gui.x_h, x, 0);
72 if(!x->x_gui.x_fsf.x_rcv_able)
73 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
74 canvas, xx, yy, xx + IOWIDTH, yy+1, x, 0);
75}
76
77void toggle_draw_move(t_toggle *x, t_glist *glist)
78{
79 t_canvas *canvas=glist_getcanvas(glist);
80 int w=1, xx=text_xpix(&x->x_gui.x_obj, glist), yy=text_ypix(&x->x_gui.x_obj, glist);
81
82 if(x->x_gui.x_w >= 30)
83 w = 2;
84
85 if(x->x_gui.x_w >= 60)
86 w = 3;
87 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
88 canvas, x, xx, yy, xx + x->x_gui.x_w, yy + x->x_gui.x_h);
89 sys_vgui(".x%x.c itemconfigure %xX1 -width %d\n", canvas, x, w);
90 sys_vgui(".x%x.c coords %xX1 %d %d %d %d\n",
91 canvas, x, xx+w+1, yy+w+1, xx + x->x_gui.x_w-w, yy + x->x_gui.x_h-w);
92 sys_vgui(".x%x.c itemconfigure %xX2 -width %d\n", canvas, x, w);
93 sys_vgui(".x%x.c coords %xX2 %d %d %d %d\n",
94 canvas, x, xx+w+1, yy + x->x_gui.x_h-w-1, xx + x->x_gui.x_w-w, yy+w);
95 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
96 canvas, x, xx+x->x_gui.x_ldx, yy+x->x_gui.x_ldy);
97 if(!x->x_gui.x_fsf.x_snd_able)
98 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
99 canvas, x, 0, xx, yy + x->x_gui.x_h-1, xx + IOWIDTH, yy + x->x_gui.x_h);
100 if(!x->x_gui.x_fsf.x_rcv_able)
101 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
102 canvas, x, 0, xx, yy, xx + IOWIDTH, yy+1);
103}
104
105void toggle_draw_erase(t_toggle* x, t_glist* glist)
106{
107 t_canvas *canvas=glist_getcanvas(glist);
108
109 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
110 sys_vgui(".x%x.c delete %xX1\n", canvas, x);
111 sys_vgui(".x%x.c delete %xX2\n", canvas, x);
112 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
113 if(!x->x_gui.x_fsf.x_snd_able)
114 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
115 if(!x->x_gui.x_fsf.x_rcv_able)
116 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
117}
118
119void toggle_draw_config(t_toggle* x, t_glist* glist)
120{
121 t_canvas *canvas=glist_getcanvas(glist);
122
123 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
124 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
125 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
126 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
127 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x,
128 x->x_gui.x_bcol);
129 sys_vgui(".x%x.c itemconfigure %xX1 -fill #%6.6x\n", canvas, x,
130 x->x_on?x->x_gui.x_fcol:x->x_gui.x_bcol);
131 sys_vgui(".x%x.c itemconfigure %xX2 -fill #%6.6x\n", canvas, x,
132 x->x_on?x->x_gui.x_fcol:x->x_gui.x_bcol);
133}
134
135void toggle_draw_io(t_toggle* x, t_glist* glist, int old_snd_rcv_flags)
136{
137 int xpos=text_xpix(&x->x_gui.x_obj, glist);
138 int ypos=text_ypix(&x->x_gui.x_obj, glist);
139 t_canvas *canvas=glist_getcanvas(glist);
140
141 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
142 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
143 canvas, xpos,
144 ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
145 ypos + x->x_gui.x_h, x, 0);
146 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
147 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
148 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
149 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
150 canvas, xpos, ypos,
151 xpos + IOWIDTH, ypos+1, x, 0);
152 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
153 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
154}
155
156void toggle_draw_select(t_toggle* x, t_glist* glist)
157{
158 t_canvas *canvas=glist_getcanvas(glist);
159
160 if(x->x_gui.x_fsf.x_selected)
161 {
162 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
163 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
164 }
165 else
166 {
167 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
168 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
169 }
170}
171
172void toggle_draw(t_toggle *x, t_glist *glist, int mode)
173{
174 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
175 toggle_draw_update(x, glist);
176 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
177 toggle_draw_move(x, glist);
178 else if(mode == IEM_GUI_DRAW_MODE_NEW)
179 toggle_draw_new(x, glist);
180 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
181 toggle_draw_select(x, glist);
182 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
183 toggle_draw_erase(x, glist);
184 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
185 toggle_draw_config(x, glist);
186 else if(mode >= IEM_GUI_DRAW_MODE_IO)
187 toggle_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
188}
189
190/* ------------------------ tgl widgetbehaviour----------------------------- */
191
192static void toggle_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
193{
194 t_toggle *x = (t_toggle *)z;
195
196 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
197 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
198 *xp2 = *xp1 + x->x_gui.x_w;
199 *yp2 = *yp1 + x->x_gui.x_h;
200}
201
202static void toggle_save(t_gobj *z, t_binbuf *b)
203{
204 t_toggle *x = (t_toggle *)z;
205 int bflcol[3];
206 t_symbol *srl[3];
207
208 iemgui_save(&x->x_gui, srl, bflcol);
209 binbuf_addv(b, "ssiisiisssiiiiiiiff", gensym("#X"),gensym("obj"),
210 (t_int)x->x_gui.x_obj.te_xpix,
211 (t_int)x->x_gui.x_obj.te_ypix,
212 gensym("tgl"), x->x_gui.x_w,
213 iem_symargstoint(&x->x_gui.x_isa),
214 srl[0], srl[1], srl[2],
215 x->x_gui.x_ldx, x->x_gui.x_ldy,
216 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
217 bflcol[0], bflcol[1], bflcol[2], x->x_on, x->x_nonzero);
218 binbuf_addv(b, ";");
219}
220
221static void toggle_properties(t_gobj *z, t_glist *owner)
222{
223 t_toggle *x = (t_toggle *)z;
224 char buf[800];
225 t_symbol *srl[3];
226
227 iemgui_properties(&x->x_gui, srl);
228 sprintf(buf, "pdtk_iemgui_dialog %%s TOGGLE \
229 ----------dimensions(pix):----------- %d %d size: 0 0 empty \
230 -----------non-zero-value:----------- %g value: 0.0 empty %g \
231 -1 lin log %d %d empty %d \
232 %s %s \
233 %s %d %d \
234 %d %d \
235 %d %d %d\n",
236 x->x_gui.x_w, IEM_GUI_MINSIZE,
237 x->x_nonzero, 1.0,/*non_zero-schedule*/
238 x->x_gui.x_isa.x_loadinit, -1, -1,/*no multi*/
239 srl[0]->s_name, srl[1]->s_name,
240 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
241 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
242 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
243 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
244}
245
246static void toggle_bang(t_toggle *x)
247{
248 x->x_on = (x->x_on==0.0)?x->x_nonzero:0.0;
249 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
250 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
251 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
252 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
253}
254
255static void toggle_dialog(t_toggle *x, t_symbol *s, int argc, t_atom *argv)
256{
257 t_symbol *srl[3];
258 int a = (int)atom_getintarg(0, argc, argv);
259 float nonzero = (float)atom_getfloatarg(2, argc, argv);
260 int sr_flags;
261
262 if(nonzero == 0.0)
263 nonzero = 1.0;
264 x->x_nonzero = nonzero;
265 if(x->x_on != 0.0)
266 x->x_on = x->x_nonzero;
267 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
268 x->x_gui.x_w = iemgui_clip_size(a);
269 x->x_gui.x_h = x->x_gui.x_w;
270 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
271 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
272 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
273 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
274}
275
276static void toggle_click(t_toggle *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
277{toggle_bang(x);}
278
279static int toggle_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
280{
281 if(doit)
282 toggle_click((t_toggle *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
283 return (1);
284}
285
286static void toggle_set(t_toggle *x, t_floatarg f)
287{
288 x->x_on = f;
289 if(f != 0.0)
290 x->x_nonzero = f;
291 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
292}
293
294static void toggle_float(t_toggle *x, t_floatarg f)
295{
296 toggle_set(x, f);
297 if(x->x_gui.x_fsf.x_put_in2out)
298 {
299 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
300 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
301 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
302 }
303}
304
305static void toggle_fout(t_toggle *x, t_floatarg f)
306{
307 toggle_set(x, f);
308 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
309 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
310 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
311}
312
313static void toggle_loadbang(t_toggle *x)
314{
315 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
316 toggle_fout(x, (float)x->x_on);
317}
318
319static void toggle_size(t_toggle *x, t_symbol *s, int ac, t_atom *av)
320{
321 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
322 x->x_gui.x_h = x->x_gui.x_w;
323 iemgui_size((void *)x, &x->x_gui);
324}
325
326static void toggle_delta(t_toggle *x, t_symbol *s, int ac, t_atom *av)
327{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
328
329static void toggle_pos(t_toggle *x, t_symbol *s, int ac, t_atom *av)
330{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
331
332static void toggle_color(t_toggle *x, t_symbol *s, int ac, t_atom *av)
333{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
334
335static void toggle_send(t_toggle *x, t_symbol *s)
336{iemgui_send(x, &x->x_gui, s);}
337
338static void toggle_receive(t_toggle *x, t_symbol *s)
339{iemgui_receive(x, &x->x_gui, s);}
340
341static void toggle_label(t_toggle *x, t_symbol *s)
342{iemgui_label((void *)x, &x->x_gui, s);}
343
344static void toggle_label_font(t_toggle *x, t_symbol *s, int ac, t_atom *av)
345{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
346
347static void toggle_label_pos(t_toggle *x, t_symbol *s, int ac, t_atom *av)
348{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
349
350static void toggle_init(t_toggle *x, t_floatarg f)
351{
352 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
353}
354
355static void toggle_nonzero(t_toggle *x, t_floatarg f)
356{
357 if(f != 0.0)
358 x->x_nonzero = f;
359}
360
361static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
362{
363 t_toggle *x = (t_toggle *)pd_new(toggle_class);
364 int bflcol[]={-262144, -1, -1};
365 int a=IEM_GUI_DEFAULTSIZE, f=0;
366 int ldx=0, ldy=-6;
367 int fs=8;
368 float on=0.0, nonzero=1.0;
369 char str[144];
370
371 iem_inttosymargs(&x->x_gui.x_isa, 0);
372 iem_inttofstyle(&x->x_gui.x_fsf, 0);
373
374 if(((argc == 13)||(argc == 14))&&IS_A_FLOAT(argv,0)
375 &&IS_A_FLOAT(argv,1)
376 &&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2))
377 &&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))
378 &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
379 &&IS_A_FLOAT(argv,5)&&IS_A_FLOAT(argv,6)
380 &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,9)
381 &&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12))
382 {
383 a = (int)atom_getintarg(0, argc, argv);
384 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(1, argc, argv));
385 iemgui_new_getnames(&x->x_gui, 2, argv);
386 ldx = (int)atom_getintarg(5, argc, argv);
387 ldy = (int)atom_getintarg(6, argc, argv);
388 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(7, argc, argv));
389 fs = (int)atom_getintarg(8, argc, argv);
390 bflcol[0] = (int)atom_getintarg(9, argc, argv);
391 bflcol[1] = (int)atom_getintarg(10, argc, argv);
392 bflcol[2] = (int)atom_getintarg(11, argc, argv);
393 on = (float)atom_getfloatarg(12, argc, argv);
394 }
395 else iemgui_new_getnames(&x->x_gui, 2, 0);
396 if((argc == 14)&&IS_A_FLOAT(argv,13))
397 nonzero = (float)atom_getfloatarg(13, argc, argv);
398 x->x_gui.x_draw = (t_iemfunptr)toggle_draw;
399
400 x->x_gui.x_fsf.x_snd_able = 1;
401 x->x_gui.x_fsf.x_rcv_able = 1;
402 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
403 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
404 x->x_gui.x_fsf.x_snd_able = 0;
405 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
406 x->x_gui.x_fsf.x_rcv_able = 0;
407 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
408 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
409 else { x->x_gui.x_fsf.x_font_style = 0;
410 strcpy(x->x_gui.x_font, "courier"); }
411 x->x_nonzero = (nonzero!=0.0)?nonzero:1.0;
412 if(x->x_gui.x_isa.x_loadinit)
413 x->x_on = (on!=0.0)?nonzero:0.0;
414 else
415 x->x_on = 0.0;
416 if (x->x_gui.x_fsf.x_rcv_able)
417 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
418 x->x_gui.x_ldx = ldx;
419 x->x_gui.x_ldy = ldy;
420
421 if(fs < 4)
422 fs = 4;
423 x->x_gui.x_fontsize = fs;
424 x->x_gui.x_w = iemgui_clip_size(a);
425 x->x_gui.x_h = x->x_gui.x_w;
426 iemgui_all_colfromload(&x->x_gui, bflcol);
427 iemgui_verify_snd_ne_rcv(&x->x_gui);
428 outlet_new(&x->x_gui.x_obj, &s_float);
429 return (x);
430}
431
432static void toggle_ff(t_toggle *x)
433{
434 if(x->x_gui.x_fsf.x_rcv_able)
435 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
436 gfxstub_deleteforkey(x);
437}
438
439void g_toggle_setup(void)
440{
441 toggle_class = class_new(gensym("tgl"), (t_newmethod)toggle_new,
442 (t_method)toggle_ff, sizeof(t_toggle), 0, A_GIMME, 0);
443 class_addcreator((t_newmethod)toggle_new, gensym("toggle"), A_GIMME, 0);
444 class_addbang(toggle_class, toggle_bang);
445 class_addfloat(toggle_class, toggle_float);
446 class_addmethod(toggle_class, (t_method)toggle_click, gensym("click"),
447 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
448 class_addmethod(toggle_class, (t_method)toggle_dialog, gensym("dialog"),
449 A_GIMME, 0);
450 class_addmethod(toggle_class, (t_method)toggle_loadbang, gensym("loadbang"), 0);
451 class_addmethod(toggle_class, (t_method)toggle_set, gensym("set"), A_FLOAT, 0);
452 class_addmethod(toggle_class, (t_method)toggle_size, gensym("size"), A_GIMME, 0);
453 class_addmethod(toggle_class, (t_method)toggle_delta, gensym("delta"), A_GIMME, 0);
454 class_addmethod(toggle_class, (t_method)toggle_pos, gensym("pos"), A_GIMME, 0);
455 class_addmethod(toggle_class, (t_method)toggle_color, gensym("color"), A_GIMME, 0);
456 class_addmethod(toggle_class, (t_method)toggle_send, gensym("send"), A_DEFSYM, 0);
457 class_addmethod(toggle_class, (t_method)toggle_receive, gensym("receive"), A_DEFSYM, 0);
458 class_addmethod(toggle_class, (t_method)toggle_label, gensym("label"), A_DEFSYM, 0);
459 class_addmethod(toggle_class, (t_method)toggle_label_pos, gensym("label_pos"), A_GIMME, 0);
460 class_addmethod(toggle_class, (t_method)toggle_label_font, gensym("label_font"), A_GIMME, 0);
461 class_addmethod(toggle_class, (t_method)toggle_init, gensym("init"), A_FLOAT, 0);
462 class_addmethod(toggle_class, (t_method)toggle_nonzero, gensym("nonzero"), A_FLOAT, 0);
463 toggle_widgetbehavior.w_getrectfn = toggle_getrect;
464 toggle_widgetbehavior.w_displacefn = iemgui_displace;
465 toggle_widgetbehavior.w_selectfn = iemgui_select;
466 toggle_widgetbehavior.w_activatefn = NULL;
467 toggle_widgetbehavior.w_deletefn = iemgui_delete;
468 toggle_widgetbehavior.w_visfn = iemgui_vis;
469 toggle_widgetbehavior.w_clickfn = toggle_newclick;
470 class_setwidget(toggle_class, &toggle_widgetbehavior);
471 class_sethelpsymbol(toggle_class, gensym("toggle"));
472 class_setsavefn(toggle_class, toggle_save);
473 class_setpropertiesfn(toggle_class, toggle_properties);
474}
475/* Copyright (c) 1997-1999 Miller Puckette.
476 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
477 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
478
479/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
480/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
481
482
483#include <stdlib.h>
484#include <string.h>
485#include <stdio.h>
486#include <ctype.h>
487#include "m_pd.h"
488#include "g_canvas.h"
489#include "t_tk.h"
490#include "g_all_guis.h"
491#include <math.h>
492
493#ifdef MSW
494#include <io.h>
495#else
496#include <unistd.h>
497#endif
498
499/* --------------- tgl gui-toggle ------------------------- */
500
501t_widgetbehavior toggle_widgetbehavior;
502static t_class *toggle_class;
503
504/* widget helper functions */
505
506void toggle_draw_update(t_toggle *x, t_glist *glist)
507{
508 if(glist_isvisible(glist))
509 {
510 t_canvas *canvas=glist_getcanvas(glist);
511
512 sys_vgui(".x%x.c itemconfigure %xX1 -fill #%6.6x\n", canvas, x,
513 (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol);
514 sys_vgui(".x%x.c itemconfigure %xX2 -fill #%6.6x\n", canvas, x,
515 (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol);
516 }
517}
518
519void toggle_draw_new(t_toggle *x, t_glist *glist)
520{
521 t_canvas *canvas=glist_getcanvas(glist);
522 int w=1, xx=text_xpix(&x->x_gui.x_obj, glist), yy=text_ypix(&x->x_gui.x_obj, glist);
523
524 if(x->x_gui.x_w >= 30)
525 w = 2;
526 if(x->x_gui.x_w >= 60)
527 w = 3;
528 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
529 canvas, xx, yy, xx + x->x_gui.x_w, yy + x->x_gui.x_h,
530 x->x_gui.x_bcol, x);
531 sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xX1\n",
532 canvas, xx+w+1, yy+w+1, xx + x->x_gui.x_w-w, yy + x->x_gui.x_h-w, w,
533 (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
534 sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xX2\n",
535 canvas, xx+w+1, yy + x->x_gui.x_h-w-1, xx + x->x_gui.x_w-w, yy+w, w,
536 (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
537 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
538 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
539 canvas, xx+x->x_gui.x_ldx,
540 yy+x->x_gui.x_ldy,
541 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
542 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
543 if(!x->x_gui.x_fsf.x_snd_able)
544 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
545 canvas, xx, yy + x->x_gui.x_h-1, xx + IOWIDTH, yy + x->x_gui.x_h, x, 0);
546 if(!x->x_gui.x_fsf.x_rcv_able)
547 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
548 canvas, xx, yy, xx + IOWIDTH, yy+1, x, 0);
549}
550
551void toggle_draw_move(t_toggle *x, t_glist *glist)
552{
553 t_canvas *canvas=glist_getcanvas(glist);
554 int w=1, xx=text_xpix(&x->x_gui.x_obj, glist), yy=text_ypix(&x->x_gui.x_obj, glist);
555
556 if(x->x_gui.x_w >= 30)
557 w = 2;
558
559 if(x->x_gui.x_w >= 60)
560 w = 3;
561 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
562 canvas, x, xx, yy, xx + x->x_gui.x_w, yy + x->x_gui.x_h);
563 sys_vgui(".x%x.c itemconfigure %xX1 -width %d\n", canvas, x, w);
564 sys_vgui(".x%x.c coords %xX1 %d %d %d %d\n",
565 canvas, x, xx+w+1, yy+w+1, xx + x->x_gui.x_w-w, yy + x->x_gui.x_h-w);
566 sys_vgui(".x%x.c itemconfigure %xX2 -width %d\n", canvas, x, w);
567 sys_vgui(".x%x.c coords %xX2 %d %d %d %d\n",
568 canvas, x, xx+w+1, yy + x->x_gui.x_h-w-1, xx + x->x_gui.x_w-w, yy+w);
569 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
570 canvas, x, xx+x->x_gui.x_ldx, yy+x->x_gui.x_ldy);
571 if(!x->x_gui.x_fsf.x_snd_able)
572 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
573 canvas, x, 0, xx, yy + x->x_gui.x_h-1, xx + IOWIDTH, yy + x->x_gui.x_h);
574 if(!x->x_gui.x_fsf.x_rcv_able)
575 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
576 canvas, x, 0, xx, yy, xx + IOWIDTH, yy+1);
577}
578
579void toggle_draw_erase(t_toggle* x, t_glist* glist)
580{
581 t_canvas *canvas=glist_getcanvas(glist);
582
583 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
584 sys_vgui(".x%x.c delete %xX1\n", canvas, x);
585 sys_vgui(".x%x.c delete %xX2\n", canvas, x);
586 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
587 if(!x->x_gui.x_fsf.x_snd_able)
588 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
589 if(!x->x_gui.x_fsf.x_rcv_able)
590 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
591}
592
593void toggle_draw_config(t_toggle* x, t_glist* glist)
594{
595 t_canvas *canvas=glist_getcanvas(glist);
596
597 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
598 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
599 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
600 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
601 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x,
602 x->x_gui.x_bcol);
603 sys_vgui(".x%x.c itemconfigure %xX1 -fill #%6.6x\n", canvas, x,
604 x->x_on?x->x_gui.x_fcol:x->x_gui.x_bcol);
605 sys_vgui(".x%x.c itemconfigure %xX2 -fill #%6.6x\n", canvas, x,
606 x->x_on?x->x_gui.x_fcol:x->x_gui.x_bcol);
607}
608
609void toggle_draw_io(t_toggle* x, t_glist* glist, int old_snd_rcv_flags)
610{
611 int xpos=text_xpix(&x->x_gui.x_obj, glist);
612 int ypos=text_ypix(&x->x_gui.x_obj, glist);
613 t_canvas *canvas=glist_getcanvas(glist);
614
615 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
616 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
617 canvas, xpos,
618 ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
619 ypos + x->x_gui.x_h, x, 0);
620 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
621 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
622 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
623 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
624 canvas, xpos, ypos,
625 xpos + IOWIDTH, ypos+1, x, 0);
626 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
627 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
628}
629
630void toggle_draw_select(t_toggle* x, t_glist* glist)
631{
632 t_canvas *canvas=glist_getcanvas(glist);
633
634 if(x->x_gui.x_fsf.x_selected)
635 {
636 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
637 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
638 }
639 else
640 {
641 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
642 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
643 }
644}
645
646void toggle_draw(t_toggle *x, t_glist *glist, int mode)
647{
648 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
649 toggle_draw_update(x, glist);
650 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
651 toggle_draw_move(x, glist);
652 else if(mode == IEM_GUI_DRAW_MODE_NEW)
653 toggle_draw_new(x, glist);
654 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
655 toggle_draw_select(x, glist);
656 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
657 toggle_draw_erase(x, glist);
658 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
659 toggle_draw_config(x, glist);
660 else if(mode >= IEM_GUI_DRAW_MODE_IO)
661 toggle_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
662}
663
664/* ------------------------ tgl widgetbehaviour----------------------------- */
665
666static void toggle_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
667{
668 t_toggle *x = (t_toggle *)z;
669
670 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
671 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
672 *xp2 = *xp1 + x->x_gui.x_w;
673 *yp2 = *yp1 + x->x_gui.x_h;
674}
675
676static void toggle_save(t_gobj *z, t_binbuf *b)
677{
678 t_toggle *x = (t_toggle *)z;
679 int bflcol[3];
680 t_symbol *srl[3];
681
682 iemgui_save(&x->x_gui, srl, bflcol);
683 binbuf_addv(b, "ssiisiisssiiiiiiiff", gensym("#X"),gensym("obj"),
684 (t_int)x->x_gui.x_obj.te_xpix,
685 (t_int)x->x_gui.x_obj.te_ypix,
686 gensym("tgl"), x->x_gui.x_w,
687 iem_symargstoint(&x->x_gui.x_isa),
688 srl[0], srl[1], srl[2],
689 x->x_gui.x_ldx, x->x_gui.x_ldy,
690 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
691 bflcol[0], bflcol[1], bflcol[2], x->x_on, x->x_nonzero);
692 binbuf_addv(b, ";");
693}
694
695static void toggle_properties(t_gobj *z, t_glist *owner)
696{
697 t_toggle *x = (t_toggle *)z;
698 char buf[800];
699 t_symbol *srl[3];
700
701 iemgui_properties(&x->x_gui, srl);
702 sprintf(buf, "pdtk_iemgui_dialog %%s TOGGLE \
703 ----------dimensions(pix):----------- %d %d size: 0 0 empty \
704 -----------non-zero-value:----------- %g value: 0.0 empty %g \
705 -1 lin log %d %d empty %d \
706 %s %s \
707 %s %d %d \
708 %d %d \
709 %d %d %d\n",
710 x->x_gui.x_w, IEM_GUI_MINSIZE,
711 x->x_nonzero, 1.0,/*non_zero-schedule*/
712 x->x_gui.x_isa.x_loadinit, -1, -1,/*no multi*/
713 srl[0]->s_name, srl[1]->s_name,
714 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
715 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
716 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
717 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
718}
719
720static void toggle_bang(t_toggle *x)
721{
722 x->x_on = (x->x_on==0.0)?x->x_nonzero:0.0;
723 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
724 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
725 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
726 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
727}
728
729static void toggle_dialog(t_toggle *x, t_symbol *s, int argc, t_atom *argv)
730{
731 t_symbol *srl[3];
732 int a = (int)atom_getintarg(0, argc, argv);
733 float nonzero = (float)atom_getfloatarg(2, argc, argv);
734 int sr_flags;
735
736 if(nonzero == 0.0)
737 nonzero = 1.0;
738 x->x_nonzero = nonzero;
739 if(x->x_on != 0.0)
740 x->x_on = x->x_nonzero;
741 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
742 x->x_gui.x_w = iemgui_clip_size(a);
743 x->x_gui.x_h = x->x_gui.x_w;
744 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
745 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
746 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
747 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
748}
749
750static void toggle_click(t_toggle *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
751{toggle_bang(x);}
752
753static int toggle_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
754{
755 if(doit)
756 toggle_click((t_toggle *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
757 return (1);
758}
759
760static void toggle_set(t_toggle *x, t_floatarg f)
761{
762 x->x_on = f;
763 if(f != 0.0)
764 x->x_nonzero = f;
765 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
766}
767
768static void toggle_float(t_toggle *x, t_floatarg f)
769{
770 toggle_set(x, f);
771 if(x->x_gui.x_fsf.x_put_in2out)
772 {
773 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
774 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
775 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
776 }
777}
778
779static void toggle_fout(t_toggle *x, t_floatarg f)
780{
781 toggle_set(x, f);
782 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
783 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
784 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
785}
786
787static void toggle_loadbang(t_toggle *x)
788{
789 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
790 toggle_fout(x, (float)x->x_on);
791}
792
793static void toggle_size(t_toggle *x, t_symbol *s, int ac, t_atom *av)
794{
795 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
796 x->x_gui.x_h = x->x_gui.x_w;
797 iemgui_size((void *)x, &x->x_gui);
798}
799
800static void toggle_delta(t_toggle *x, t_symbol *s, int ac, t_atom *av)
801{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
802
803static void toggle_pos(t_toggle *x, t_symbol *s, int ac, t_atom *av)
804{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
805
806static void toggle_color(t_toggle *x, t_symbol *s, int ac, t_atom *av)
807{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
808
809static void toggle_send(t_toggle *x, t_symbol *s)
810{iemgui_send(x, &x->x_gui, s);}
811
812static void toggle_receive(t_toggle *x, t_symbol *s)
813{iemgui_receive(x, &x->x_gui, s);}
814
815static void toggle_label(t_toggle *x, t_symbol *s)
816{iemgui_label((void *)x, &x->x_gui, s);}
817
818static void toggle_label_font(t_toggle *x, t_symbol *s, int ac, t_atom *av)
819{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
820
821static void toggle_label_pos(t_toggle *x, t_symbol *s, int ac, t_atom *av)
822{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
823
824static void toggle_init(t_toggle *x, t_floatarg f)
825{
826 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
827}
828
829static void toggle_nonzero(t_toggle *x, t_floatarg f)
830{
831 if(f != 0.0)
832 x->x_nonzero = f;
833}
834
835static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
836{
837 t_toggle *x = (t_toggle *)pd_new(toggle_class);
838 int bflcol[]={-262144, -1, -1};
839 int a=IEM_GUI_DEFAULTSIZE, f=0;
840 int ldx=0, ldy=-6;
841 int fs=8;
842 float on=0.0, nonzero=1.0;
843 char str[144];
844
845 iem_inttosymargs(&x->x_gui.x_isa, 0);
846 iem_inttofstyle(&x->x_gui.x_fsf, 0);
847
848 if(((argc == 13)||(argc == 14))&&IS_A_FLOAT(argv,0)
849 &&IS_A_FLOAT(argv,1)
850 &&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2))
851 &&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))
852 &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
853 &&IS_A_FLOAT(argv,5)&&IS_A_FLOAT(argv,6)
854 &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,9)
855 &&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12))
856 {
857 a = (int)atom_getintarg(0, argc, argv);
858 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(1, argc, argv));
859 iemgui_new_getnames(&x->x_gui, 2, argv);
860 ldx = (int)atom_getintarg(5, argc, argv);
861 ldy = (int)atom_getintarg(6, argc, argv);
862 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(7, argc, argv));
863 fs = (int)atom_getintarg(8, argc, argv);
864 bflcol[0] = (int)atom_getintarg(9, argc, argv);
865 bflcol[1] = (int)atom_getintarg(10, argc, argv);
866 bflcol[2] = (int)atom_getintarg(11, argc, argv);
867 on = (float)atom_getfloatarg(12, argc, argv);
868 }
869 else iemgui_new_getnames(&x->x_gui, 2, 0);
870 if((argc == 14)&&IS_A_FLOAT(argv,13))
871 nonzero = (float)atom_getfloatarg(13, argc, argv);
872 x->x_gui.x_draw = (t_iemfunptr)toggle_draw;
873
874 x->x_gui.x_fsf.x_snd_able = 1;
875 x->x_gui.x_fsf.x_rcv_able = 1;
876 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
877 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
878 x->x_gui.x_fsf.x_snd_able = 0;
879 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
880 x->x_gui.x_fsf.x_rcv_able = 0;
881 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
882 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
883 else { x->x_gui.x_fsf.x_font_style = 0;
884 strcpy(x->x_gui.x_font, "courier"); }
885 x->x_nonzero = (nonzero!=0.0)?nonzero:1.0;
886 if(x->x_gui.x_isa.x_loadinit)
887 x->x_on = (on!=0.0)?nonzero:0.0;
888 else
889 x->x_on = 0.0;
890 if (x->x_gui.x_fsf.x_rcv_able)
891 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
892 x->x_gui.x_ldx = ldx;
893 x->x_gui.x_ldy = ldy;
894
895 if(fs < 4)
896 fs = 4;
897 x->x_gui.x_fontsize = fs;
898 x->x_gui.x_w = iemgui_clip_size(a);
899 x->x_gui.x_h = x->x_gui.x_w;
900 iemgui_all_colfromload(&x->x_gui, bflcol);
901 iemgui_verify_snd_ne_rcv(&x->x_gui);
902 outlet_new(&x->x_gui.x_obj, &s_float);
903 return (x);
904}
905
906static void toggle_ff(t_toggle *x)
907{
908 if(x->x_gui.x_fsf.x_rcv_able)
909 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
910 gfxstub_deleteforkey(x);
911}
912
913void g_toggle_setup(void)
914{
915 toggle_class = class_new(gensym("tgl"), (t_newmethod)toggle_new,
916 (t_method)toggle_ff, sizeof(t_toggle), 0, A_GIMME, 0);
917 class_addcreator((t_newmethod)toggle_new, gensym("toggle"), A_GIMME, 0);
918 class_addbang(toggle_class, toggle_bang);
919 class_addfloat(toggle_class, toggle_float);
920 class_addmethod(toggle_class, (t_method)toggle_click, gensym("click"),
921 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
922 class_addmethod(toggle_class, (t_method)toggle_dialog, gensym("dialog"),
923 A_GIMME, 0);
924 class_addmethod(toggle_class, (t_method)toggle_loadbang, gensym("loadbang"), 0);
925 class_addmethod(toggle_class, (t_method)toggle_set, gensym("set"), A_FLOAT, 0);
926 class_addmethod(toggle_class, (t_method)toggle_size, gensym("size"), A_GIMME, 0);
927 class_addmethod(toggle_class, (t_method)toggle_delta, gensym("delta"), A_GIMME, 0);
928 class_addmethod(toggle_class, (t_method)toggle_pos, gensym("pos"), A_GIMME, 0);
929 class_addmethod(toggle_class, (t_method)toggle_color, gensym("color"), A_GIMME, 0);
930 class_addmethod(toggle_class, (t_method)toggle_send, gensym("send"), A_DEFSYM, 0);
931 class_addmethod(toggle_class, (t_method)toggle_receive, gensym("receive"), A_DEFSYM, 0);
932 class_addmethod(toggle_class, (t_method)toggle_label, gensym("label"), A_DEFSYM, 0);
933 class_addmethod(toggle_class, (t_method)toggle_label_pos, gensym("label_pos"), A_GIMME, 0);
934 class_addmethod(toggle_class, (t_method)toggle_label_font, gensym("label_font"), A_GIMME, 0);
935 class_addmethod(toggle_class, (t_method)toggle_init, gensym("init"), A_FLOAT, 0);
936 class_addmethod(toggle_class, (t_method)toggle_nonzero, gensym("nonzero"), A_FLOAT, 0);
937 toggle_widgetbehavior.w_getrectfn = toggle_getrect;
938 toggle_widgetbehavior.w_displacefn = iemgui_displace;
939 toggle_widgetbehavior.w_selectfn = iemgui_select;
940 toggle_widgetbehavior.w_activatefn = NULL;
941 toggle_widgetbehavior.w_deletefn = iemgui_delete;
942 toggle_widgetbehavior.w_visfn = iemgui_vis;
943 toggle_widgetbehavior.w_clickfn = toggle_newclick;
944 class_setwidget(toggle_class, &toggle_widgetbehavior);
945 class_sethelpsymbol(toggle_class, gensym("toggle"));
946 class_setsavefn(toggle_class, toggle_save);
947 class_setpropertiesfn(toggle_class, toggle_properties);
948}
diff --git a/apps/plugins/pdbox/PDa/src/g_traversal.c b/apps/plugins/pdbox/PDa/src/g_traversal.c
new file mode 100644
index 0000000000..2a34f5c1e6
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_traversal.c
@@ -0,0 +1,2168 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* This file defines Text objects which traverse data contained in scalars
6and arrays:
7
8pointer - point to an object belonging to a template
9get - get numeric fields
10set - change numeric fields
11element - get an array element
12getsize - get the size of an array
13setsize - change the size of an array
14append - add an element to a list
15sublist - get a pointer into a list which is an element of another scalar
16
17*/
18
19#include <stdlib.h>
20#include <string.h>
21#include <stdio.h> /* for read/write to files */
22#include "m_pd.h"
23#include "g_canvas.h"
24
25/* ------------- gstubs and gpointers - safe pointing --------------- */
26
27/* create a gstub which is "owned" by a glist (gl) or an array ("a"). */
28
29t_gstub *gstub_new(t_glist *gl, t_array *a)
30{
31 t_gstub *gs = t_getbytes(sizeof(*gs));
32 if (gl)
33 {
34 gs->gs_which = GP_GLIST;
35 gs->gs_un.gs_glist = gl;
36 }
37 else
38 {
39 gs->gs_which = GP_ARRAY;
40 gs->gs_un.gs_array = a;
41 }
42 gs->gs_refcount = 0;
43 return (gs);
44}
45
46/* when a "gpointer" is set to point to this stub (so we can later chase
47down the owner) we increase a reference count. The following routine is called
48whenever a gpointer is unset from pointing here. If the owner is
49gone and the refcount goes to zero, we can free the gstub safely. */
50
51static void gstub_dis(t_gstub *gs)
52{
53 int refcount = --gs->gs_refcount;
54 if ((!refcount) && gs->gs_which == GP_NONE)
55 t_freebytes(gs, sizeof (*gs));
56 else if (refcount < 0) bug("gstub_dis");
57}
58
59/* this routing is called by the owner to inform the gstub that it is
60being deleted. If no gpointers are pointing here, we can free the gstub;
61otherwise we wait for the last gstub_dis() to free it. */
62
63void gstub_cutoff(t_gstub *gs)
64{
65 gs->gs_which = GP_NONE;
66 if (gs->gs_refcount < 0) bug("gstub_cutoff");
67 if (!gs->gs_refcount) t_freebytes(gs, sizeof (*gs));
68}
69
70/* call this to verify that a pointer is fresh, i.e., that it either
71points to real data or to the head of a list, and that in either case
72the object hasn't disappeared since this pointer was generated.
73Unless "headok" is set, the routine also fails for the head of a list. */
74
75int gpointer_check(const t_gpointer *gp, int headok)
76{
77 t_gstub *gs = gp->gp_stub;
78 if (!gs) return (0);
79 if (gs->gs_which == GP_ARRAY)
80 {
81 if (gs->gs_un.gs_array->a_valid != gp->gp_valid) return (0);
82 else return (1);
83 }
84 else if (gs->gs_which == GP_GLIST)
85 {
86 if (!headok && !gp->gp_un.gp_scalar) return (0);
87 else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid) return (0);
88 else return (1);
89 }
90 else return (0);
91}
92
93/* call this if you know the pointer is fresh but don't know if we're pointing
94to the head of a list or to real data. Any pointer is known to be fresh
95when it appears as the argument of a message, but if your "pointer" method
96or inlet stores it and you use it later, call gpointer_check above. */
97
98/* LATER reconsider the above... I no longer think it's true! */
99
100static int gpointer_ishead(const t_gpointer *gp)
101{
102 return ((gp->gp_stub->gs_which == GP_GLIST) && !gp->gp_un.gp_scalar);
103}
104
105/* get the template for the object pointer to. Assumes we've already checked
106freshness. Returns 0 if head of list. */
107
108static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
109{
110 t_gstub *gs = gp->gp_stub;
111 if (gs->gs_which == GP_GLIST)
112 {
113 t_scalar *sc = gp->gp_un.gp_scalar;
114 if (sc)
115 return (sc->sc_template);
116 else return (0);
117 }
118 else
119 {
120 t_array *a = gs->gs_un.gs_array;
121 return (a->a_templatesym);
122 }
123}
124
125 /* copy a pointer to another, assuming the first one is fresh and
126 the second one hasn't yet been initialized. */
127void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
128{
129 *gpto = *gpfrom;
130 if (gpto->gp_stub)
131 gpto->gp_stub->gs_refcount++;
132 else bug("gpointer_copy");
133}
134
135void gpointer_unset(t_gpointer *gp)
136{
137 t_gstub *gs;
138 if (gs = gp->gp_stub)
139 {
140 gstub_dis(gs);
141 gp->gp_stub = 0;
142 }
143}
144
145void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x)
146{
147 t_gstub *gs;
148 if (gs = gp->gp_stub) gstub_dis(gs);
149 gp->gp_stub = gs = glist->gl_stub;
150 gp->gp_valid = glist->gl_valid;
151 gp->gp_un.gp_scalar = x;
152 gs->gs_refcount++;
153}
154
155static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w)
156{
157 t_gstub *gs;
158 if (gs = gp->gp_stub) gstub_dis(gs);
159 gp->gp_stub = gs = array->a_stub;
160 gp->gp_valid = array->a_valid;
161 gp->gp_un.gp_w = w;
162 gs->gs_refcount++;
163}
164
165void gpointer_init(t_gpointer *gp)
166{
167 gp->gp_stub = 0;
168 gp->gp_valid = 0;
169 gp->gp_un.gp_scalar = 0;
170}
171
172/* ---------------------- pointers ----------------------------- */
173
174static t_class *ptrobj_class;
175
176typedef struct
177{
178 t_symbol *to_type;
179 t_outlet *to_outlet;
180} t_typedout;
181
182typedef struct _ptrobj
183{
184 t_object x_obj;
185 t_gpointer x_gp;
186 t_typedout *x_typedout;
187 int x_ntypedout;
188 t_outlet *x_otherout;
189 t_outlet *x_bangout;
190} t_ptrobj;
191
192static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv)
193{
194 t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
195 t_typedout *to;
196 int n;
197 gpointer_init(&x->x_gp);
198 x->x_typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
199 x->x_ntypedout = n = argc;
200 for (; n--; to++)
201 {
202 to->to_outlet = outlet_new(&x->x_obj, &s_pointer);
203 to->to_type = canvas_makebindsym(atom_getsymbol(argv++));
204 }
205 x->x_otherout = outlet_new(&x->x_obj, &s_pointer);
206 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
207 pointerinlet_new(&x->x_obj, &x->x_gp);
208 return (x);
209}
210
211static void ptrobj_traverse(t_ptrobj *x, t_symbol *s)
212{
213 t_glist *glist = (t_glist *)pd_findbyclass(s, canvas_class);
214 if (glist) gpointer_setglist(&x->x_gp, glist, 0);
215 else pd_error(x, "pointer: list '%s' not found", s->s_name);
216}
217
218static void ptrobj_vnext(t_ptrobj *x, float f)
219{
220 t_gobj *gobj;
221 t_gpointer *gp = &x->x_gp;
222 t_gstub *gs = gp->gp_stub;
223 t_glist *glist;
224 int wantselected = (f != 0);
225
226 if (!gs)
227 {
228 pd_error(x, "ptrobj_next: no current pointer");
229 return;
230 }
231 if (gs->gs_which != GP_GLIST)
232 {
233 pd_error(x, "ptrobj_next: lists only, not arrays");
234 return;
235 }
236 glist = gs->gs_un.gs_glist;
237 if (glist->gl_valid != gp->gp_valid)
238 {
239 pd_error(x, "ptrobj_next: stale pointer");
240 return;
241 }
242 if (wantselected && !glist_isvisible(glist))
243 {
244 pd_error(x,
245 "ptrobj_vnext: next-selected only works for a visible window");
246 return;
247 }
248 gobj = &gp->gp_un.gp_scalar->sc_gobj;
249
250 if (!gobj) gobj = glist->gl_list;
251 else gobj = gobj->g_next;
252 while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) ||
253 (wantselected && !glist_isselected(glist, gobj))))
254 gobj = gobj->g_next;
255
256 if (gobj)
257 {
258 t_typedout *to;
259 int n;
260 t_scalar *sc = (t_scalar *)gobj;
261 t_symbol *templatesym = sc->sc_template;
262
263 gp->gp_un.gp_scalar = sc;
264 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
265 {
266 if (to->to_type == templatesym)
267 {
268 outlet_pointer(to->to_outlet, &x->x_gp);
269 return;
270 }
271 }
272 outlet_pointer(x->x_otherout, &x->x_gp);
273 }
274 else
275 {
276 gpointer_unset(gp);
277 outlet_bang(x->x_bangout);
278 }
279}
280
281static void ptrobj_next(t_ptrobj *x)
282{
283 ptrobj_vnext(x, 0);
284}
285
286static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv)
287{
288 t_scalar *sc;
289 t_symbol *templatesym;
290 int n;
291 t_typedout *to;
292 t_glist *glist;
293 t_pd *canvas;
294 t_gstub *gs;
295 if (!gpointer_check(&x->x_gp, 1))
296 {
297 pd_error(x, "ptrobj_bang: empty pointer");
298 return;
299 }
300 gs = x->x_gp.gp_stub;
301 if (gs->gs_which == GP_GLIST)
302 glist = gs->gs_un.gs_glist;
303 else
304 {
305 t_array *owner_array = gs->gs_un.gs_array;
306 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
307 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
308 glist = owner_array->a_gp.gp_stub->gs_un.gs_glist;
309 }
310 canvas = (t_pd *)glist_getcanvas(glist);
311 if (argc && argv->a_type == A_SYMBOL)
312 pd_typedmess(canvas, argv->a_w.w_symbol, argc-1, argv+1);
313 else pd_error(x, "send-window: no message?");
314}
315
316static void ptrobj_bang(t_ptrobj *x)
317{
318 t_symbol *templatesym;
319 int n;
320 t_typedout *to;
321 if (!gpointer_check(&x->x_gp, 1))
322 {
323 pd_error(x, "ptrobj_bang: empty pointer");
324 return;
325 }
326 templatesym = gpointer_gettemplatesym(&x->x_gp);
327 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
328 {
329 if (to->to_type == templatesym)
330 {
331 outlet_pointer(to->to_outlet, &x->x_gp);
332 return;
333 }
334 }
335 outlet_pointer(x->x_otherout, &x->x_gp);
336}
337
338
339static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp)
340{
341 gpointer_unset(&x->x_gp);
342 gpointer_copy(gp, &x->x_gp);
343 ptrobj_bang(x);
344}
345
346static void ptrobj_free(t_ptrobj *x)
347{
348 freebytes(x->x_typedout, x->x_ntypedout * sizeof (*x->x_typedout));
349 gpointer_unset(&x->x_gp);
350}
351
352static void ptrobj_setup(void)
353{
354 ptrobj_class = class_new(gensym("pointer"), (t_newmethod)ptrobj_new,
355 (t_method)ptrobj_free, sizeof(t_ptrobj), 0, A_GIMME, 0);
356 class_addmethod(ptrobj_class, (t_method)ptrobj_traverse, gensym("traverse"),
357 A_SYMBOL, 0);
358 class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), 0);
359 class_addmethod(ptrobj_class, (t_method)ptrobj_vnext, gensym("vnext"),
360 A_DEFFLOAT, 0);
361 class_addmethod(ptrobj_class, (t_method)ptrobj_sendwindow,
362 gensym("send-window"), A_GIMME, 0);
363 class_addpointer(ptrobj_class, ptrobj_pointer);
364 class_addbang(ptrobj_class, ptrobj_bang);
365}
366
367/* ---------------------- get ----------------------------- */
368
369static t_class *get_class;
370
371typedef struct _getvariable
372{
373 t_symbol *gv_sym;
374 t_outlet *gv_outlet;
375} t_getvariable;
376
377typedef struct _get
378{
379 t_object x_obj;
380 t_symbol *x_templatesym;
381 int x_nout;
382 t_getvariable *x_variables;
383} t_get;
384
385static void *get_new(t_symbol *why, int argc, t_atom *argv)
386{
387 t_get *x = (t_get *)pd_new(get_class);
388 int i;
389 t_getvariable *sp;
390 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
391 if (argc) argc--, argv++;
392 x->x_variables
393 = (t_getvariable *)getbytes(argc * sizeof (*x->x_variables));
394 x->x_nout = argc;
395 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
396 {
397 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
398 sp->gv_outlet = outlet_new(&x->x_obj, 0);
399 /* LATER connect with the template and set the outlet's type
400 correctly. We can't yet guarantee that the template is there
401 before we hit this routine. */
402 }
403 return (x);
404}
405
406static void get_pointer(t_get *x, t_gpointer *gp)
407{
408 int nitems = x->x_nout, i;
409 t_symbol *templatesym = x->x_templatesym;
410 t_template *template = template_findbyname(templatesym);
411 t_gstub *gs = gp->gp_stub;
412 t_word *vec;
413 t_getvariable *vp;
414 if (!template)
415 {
416 pd_error(x, "get: couldn't find template %s", templatesym->s_name);
417 return;
418 }
419 if (gpointer_ishead(gp))
420 {
421 pd_error(x, "get: empty pointer");
422 return;
423 }
424 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
425 else vec = gp->gp_un.gp_scalar->sc_vec;
426 for (i = nitems - 1, vp = x->x_variables + i; i >= 0; i--, vp--)
427 {
428 float f = template_getfloat(template, vp->gv_sym, vec, 1);
429 outlet_float(vp->gv_outlet, f);
430 /* LATER deal with other types. */
431 }
432}
433
434static void get_free(t_get *x)
435{
436 freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables));
437}
438
439static void get_setup(void)
440{
441 get_class = class_new(gensym("get"), (t_newmethod)get_new,
442 (t_method)get_free, sizeof(t_get), 0, A_GIMME, 0);
443 class_addpointer(get_class, get_pointer);
444}
445
446/* ---------------------- set ----------------------------- */
447
448static t_class *set_class;
449
450typedef struct _setvariable
451{
452 t_symbol *gv_sym;
453 t_float gv_f; /* LATER take other types */
454} t_setvariable;
455
456typedef struct _set
457{
458 t_object x_obj;
459 t_gpointer x_gp;
460 t_symbol *x_templatesym;
461 int x_nin;
462 t_setvariable *x_variables;
463} t_set;
464
465static void *set_new(t_symbol *why, int argc, t_atom *argv)
466{
467 t_set *x = (t_set *)pd_new(set_class);
468 int i;
469 t_setvariable *sp;
470 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
471 if (argc) argc--, argv++;
472 x->x_variables
473 = (t_setvariable *)getbytes(argc * sizeof (*x->x_variables));
474 x->x_nin = argc;
475 if (argc)
476 {
477 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
478 {
479 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
480 sp->gv_f = 0;
481 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
482 /* LATER figure out type as in "get" object. */
483 }
484 }
485 pointerinlet_new(&x->x_obj, &x->x_gp);
486 gpointer_init(&x->x_gp);
487 return (x);
488}
489
490static void set_float(t_set *x, t_float f)
491{
492 int nitems = x->x_nin, i;
493 t_symbol *templatesym = x->x_templatesym;
494 t_template *template = template_findbyname(templatesym);
495 t_setvariable *vp;
496 t_gpointer *gp = &x->x_gp;
497 t_gstub *gs = gp->gp_stub;
498 t_word *vec;
499 if (!template)
500 {
501 pd_error(x, "set: couldn't find template %s", templatesym->s_name);
502 return;
503 }
504 if (!gpointer_check(gp, 0))
505 {
506 pd_error(x, "set: empty pointer");
507 return;
508 }
509 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
510 {
511 pd_error(x, "set %s: got wrong template (%s)",
512 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
513 return;
514 }
515 if (!nitems) return;
516 x->x_variables[0].gv_f = f;
517 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
518 else vec = gp->gp_un.gp_scalar->sc_vec;
519 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
520 {
521 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
522 /* LATER deal with other types ala get_pointer. */
523 }
524 if (gs->gs_which == GP_GLIST)
525 glist_redrawitem(gs->gs_un.gs_glist, (t_gobj *)(gp->gp_un.gp_scalar));
526 else
527 {
528 t_array *owner_array = gs->gs_un.gs_array;
529 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
530 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
531 glist_redrawitem(owner_array->a_gp.gp_stub->gs_un.gs_glist,
532 (t_gobj *)(owner_array->a_gp.gp_un.gp_scalar));
533 }
534}
535
536static void set_free(t_set *x)
537{
538 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
539 gpointer_unset(&x->x_gp);
540}
541
542static void set_setup(void)
543{
544 set_class = class_new(gensym("set"), (t_newmethod)set_new,
545 (t_method)set_free, sizeof(t_set), 0, A_GIMME, 0);
546 class_addfloat(set_class, set_float);
547}
548
549/* ---------------------- elem ----------------------------- */
550
551static t_class *elem_class;
552
553typedef struct _elem
554{
555 t_object x_obj;
556 t_symbol *x_templatesym;
557 t_symbol *x_fieldsym;
558 t_gpointer x_gp;
559 t_gpointer x_gparent;
560} t_elem;
561
562static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym)
563{
564 t_elem *x = (t_elem *)pd_new(elem_class);
565 x->x_templatesym = canvas_makebindsym(templatesym);
566 x->x_fieldsym = fieldsym;
567 gpointer_init(&x->x_gp);
568 gpointer_init(&x->x_gparent);
569 pointerinlet_new(&x->x_obj, &x->x_gparent);
570 outlet_new(&x->x_obj, &s_pointer);
571 return (x);
572}
573
574static void elem_float(t_elem *x, t_float f)
575{
576 int indx = f, nitems, onset;
577 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
578 *elemtemplatesym;
579 t_template *template = template_findbyname(templatesym);
580 t_template *elemtemplate;
581 t_gpointer *gparent = &x->x_gparent;
582 t_word *w;
583 t_array *array;
584 int elemsize, type;
585
586 if (!gpointer_check(gparent, 0))
587 {
588 pd_error(x, "element: empty pointer");
589 return;
590 }
591 if (gpointer_gettemplatesym(gparent) != x->x_templatesym)
592 {
593 pd_error(x, "element %s: got wrong template (%s)",
594 x->x_templatesym->s_name, gpointer_gettemplatesym(gparent)->s_name);
595 return;
596 }
597 if (gparent->gp_stub->gs_which == GP_ARRAY) w = gparent->gp_un.gp_w;
598 else w = gparent->gp_un.gp_scalar->sc_vec;
599 if (!template)
600 {
601 pd_error(x, "element: couldn't find template %s", templatesym->s_name);
602 return;
603 }
604 if (!template_find_field(template, fieldsym,
605 &onset, &type, &elemtemplatesym))
606 {
607 pd_error(x, "element: couldn't find array field %s", fieldsym->s_name);
608 return;
609 }
610 if (type != DT_ARRAY)
611 {
612 pd_error(x, "element: field %s not of type array", fieldsym->s_name);
613 return;
614 }
615 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
616 {
617 pd_error(x, "element: couldn't find field template %s",
618 elemtemplatesym->s_name);
619 return;
620 }
621
622 elemsize = elemtemplate->t_n * sizeof(t_word);
623
624 array = *(t_array **)(((char *)w) + onset);
625
626 nitems = array->a_n;
627 if (indx < 0) indx = 0;
628 if (indx >= nitems) indx = nitems-1;
629
630 gpointer_setarray(&x->x_gp, array,
631 (t_word *)((char *)(array->a_vec) + indx * elemsize));
632 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
633}
634
635static void elem_free(t_elem *x, t_gpointer *gp)
636{
637 gpointer_unset(&x->x_gp);
638 gpointer_unset(&x->x_gparent);
639}
640
641static void elem_setup(void)
642{
643 elem_class = class_new(gensym("element"), (t_newmethod)elem_new,
644 (t_method)elem_free, sizeof(t_elem), 0, A_DEFSYM, A_DEFSYM, 0);
645 class_addfloat(elem_class, elem_float);
646}
647
648/* ---------------------- getsize ----------------------------- */
649
650static t_class *getsize_class;
651
652typedef struct _getsize
653{
654 t_object x_obj;
655 t_symbol *x_templatesym;
656 t_symbol *x_fieldsym;
657} t_getsize;
658
659static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym)
660{
661 t_getsize *x = (t_getsize *)pd_new(getsize_class);
662 x->x_templatesym = canvas_makebindsym(templatesym);
663 x->x_fieldsym = fieldsym;
664 outlet_new(&x->x_obj, &s_float);
665 return (x);
666}
667
668static void getsize_pointer(t_getsize *x, t_gpointer *gp)
669{
670 int nitems, onset, type;
671 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
672 *elemtemplatesym;
673 t_template *template = template_findbyname(templatesym);
674 t_word *w;
675 t_array *array;
676 int elemsize;
677 t_gstub *gs = gp->gp_stub;
678 if (!template)
679 {
680 pd_error(x, "getsize: couldn't find template %s", templatesym->s_name);
681 return;
682 }
683 if (!template_find_field(template, fieldsym,
684 &onset, &type, &elemtemplatesym))
685 {
686 pd_error(x, "getsize: couldn't find array field %s", fieldsym->s_name);
687 return;
688 }
689 if (type != DT_ARRAY)
690 {
691 pd_error(x, "getsize: field %s not of type array", fieldsym->s_name);
692 return;
693 }
694 if (gpointer_ishead(gp))
695 {
696 pd_error(x, "getsize: empty pointer");
697 return;
698 }
699 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
700 {
701 pd_error(x, "getsize %s: got wrong template (%s)",
702 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
703 return;
704 }
705 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
706 else w = gp->gp_un.gp_scalar->sc_vec;
707
708 array = *(t_array **)(((char *)w) + onset);
709 outlet_float(x->x_obj.ob_outlet, (float)(array->a_n));
710}
711
712static void getsize_setup(void)
713{
714 getsize_class = class_new(gensym("getsize"), (t_newmethod)getsize_new, 0,
715 sizeof(t_getsize), 0, A_DEFSYM, A_DEFSYM, 0);
716 class_addpointer(getsize_class, getsize_pointer);
717}
718
719/* ---------------------- setsize ----------------------------- */
720
721static t_class *setsize_class;
722
723typedef struct _setsize
724{
725 t_object x_obj;
726 t_symbol *x_templatesym;
727 t_symbol *x_fieldsym;
728 t_gpointer x_gp;
729} t_setsize;
730
731static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym,
732 t_floatarg newsize)
733{
734 t_setsize *x = (t_setsize *)pd_new(setsize_class);
735 x->x_templatesym = canvas_makebindsym(templatesym);
736 x->x_fieldsym = fieldsym;
737 gpointer_init(&x->x_gp);
738
739 pointerinlet_new(&x->x_obj, &x->x_gp);
740 return (x);
741}
742
743static void setsize_float(t_setsize *x, t_float f)
744{
745 int nitems, onset, type;
746 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
747 *elemtemplatesym;
748 t_template *template = template_findbyname(templatesym);
749 t_template *elemtemplate;
750 t_word *w;
751 t_atom at;
752 t_array *array;
753 int elemsize;
754 int newsize = f;
755 t_gpointer *gp = &x->x_gp;
756 t_gstub *gs = gp->gp_stub;
757 if (!gpointer_check(&x->x_gp, 0))
758 {
759 pd_error(x, "setsize: empty pointer");
760 return;
761 }
762 if (gpointer_gettemplatesym(&x->x_gp) != x->x_templatesym)
763 {
764 pd_error(x, "setsize %s: got wrong template (%s)",
765 x->x_templatesym->s_name,
766 gpointer_gettemplatesym(&x->x_gp)->s_name);
767 return;
768 }
769 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
770 else w = gp->gp_un.gp_scalar->sc_vec;
771
772 if (!template)
773 {
774 pd_error(x,"setsize: couldn't find template %s", templatesym->s_name);
775 return;
776 }
777 if (!template_find_field(template, fieldsym,
778 &onset, &type, &elemtemplatesym))
779 {
780 pd_error(x,"setsize: couldn't find array field %s", fieldsym->s_name);
781 return;
782 }
783 if (type != DT_ARRAY)
784 {
785 pd_error(x,"setsize: field %s not of type array", fieldsym->s_name);
786 return;
787 }
788
789 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
790 {
791 pd_error(x,"element: couldn't find field template %s",
792 elemtemplatesym->s_name);
793 return;
794 }
795
796 elemsize = elemtemplate->t_n * sizeof(t_word);
797
798 array = *(t_array **)(((char *)w) + onset);
799
800 if (elemsize != array->a_elemsize) bug("setsize_gpointer");
801
802 nitems = array->a_n;
803 if (newsize < 1) newsize = 1;
804 if (newsize == nitems) return;
805
806 /* erase the array before resizing it. If we belong to a
807 scalar it's easy, but if we belong to an element of another
808 array we have to search back until we get to a scalar to erase.
809 When graphics updates become queueable this may fall apart... */
810
811
812 if (gs->gs_which == GP_GLIST)
813 {
814 if (glist_isvisible(gs->gs_un.gs_glist))
815 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 0);
816 }
817 else
818 {
819 t_array *owner_array = gs->gs_un.gs_array;
820 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
821 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
822 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
823 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
824 owner_array->a_gp.gp_stub->gs_un.gs_glist, 0);
825 }
826 /* now do the resizing and, if growing, initialize new scalars */
827 array->a_vec = (char *)resizebytes(array->a_vec,
828 elemsize * nitems, elemsize * newsize);
829 array->a_n = newsize;
830 if (newsize > nitems)
831 {
832 char *newelem = ((char *)array->a_vec) + nitems * elemsize;
833 int i = 0, nnew = newsize - nitems;
834
835 while (nnew--)
836 {
837 word_init((t_word *)newelem, elemtemplate, gp);
838 newelem += elemsize;
839 /* post("new %x %x, ntypes %d", newelem, *(int *)newelem, ntypes); */
840 }
841 }
842
843 /* redraw again. */
844 if (gs->gs_which == GP_GLIST)
845 {
846 if (glist_isvisible(gs->gs_un.gs_glist))
847 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 1);
848 }
849 else
850 {
851 t_array *owner_array = gs->gs_un.gs_array;
852 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
853 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
854 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
855 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
856 owner_array->a_gp.gp_stub->gs_un.gs_glist, 1);
857 }
858}
859
860
861static void setsize_free(t_setsize *x)
862{
863 gpointer_unset(&x->x_gp);
864}
865
866static void setsize_setup(void)
867{
868 setsize_class = class_new(gensym("setsize"), (t_newmethod)setsize_new,
869 (t_method)setsize_free, sizeof(t_setsize), 0,
870 A_DEFSYM, A_DEFSYM, A_DEFFLOAT, 0);
871 class_addfloat(setsize_class, setsize_float);
872}
873
874/* ---------------------- append ----------------------------- */
875
876static t_class *append_class;
877
878typedef struct _appendvariable
879{
880 t_symbol *gv_sym;
881 t_float gv_f;
882} t_appendvariable;
883
884typedef struct _append
885{
886 t_object x_obj;
887 t_gpointer x_gp;
888 t_symbol *x_templatesym;
889 int x_nin;
890 t_appendvariable *x_variables;
891} t_append;
892
893static void *append_new(t_symbol *why, int argc, t_atom *argv)
894{
895 t_append *x = (t_append *)pd_new(append_class);
896 int i;
897 t_appendvariable *sp;
898 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
899 if (argc) argc--, argv++;
900 x->x_variables
901 = (t_appendvariable *)getbytes(argc * sizeof (*x->x_variables));
902 x->x_nin = argc;
903 if (argc)
904 {
905 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
906 {
907 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
908 sp->gv_f = 0;
909 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
910 }
911 }
912 pointerinlet_new(&x->x_obj, &x->x_gp);
913 outlet_new(&x->x_obj, &s_pointer);
914 gpointer_init(&x->x_gp);
915 return (x);
916}
917
918static void append_float(t_append *x, t_float f)
919{
920 int nitems = x->x_nin, i;
921 t_symbol *templatesym = x->x_templatesym;
922 t_template *template = template_findbyname(templatesym);
923 t_appendvariable *vp;
924 t_gpointer *gp = &x->x_gp;
925 t_gstub *gs = gp->gp_stub;
926 t_word *vec;
927 t_scalar *sc, *oldsc;
928 t_glist *glist;
929 if (!template)
930 {
931 pd_error(x, "append: couldn't find template %s", templatesym->s_name);
932 return;
933 }
934 if (!gs)
935 {
936 pd_error(x, "append: no current pointer");
937 return;
938 }
939 if (gs->gs_which != GP_GLIST)
940 {
941 pd_error(x, "append: lists only, not arrays");
942 return;
943 }
944 glist = gs->gs_un.gs_glist;
945 if (glist->gl_valid != gp->gp_valid)
946 {
947 pd_error(x, "append: stale pointer");
948 return;
949 }
950 if (!nitems) return;
951 x->x_variables[0].gv_f = f;
952
953 sc = scalar_new(glist, templatesym);
954 if (!sc)
955 {
956 pd_error(x, "%s: couldn't create scalar", templatesym->s_name);
957 return;
958 }
959 oldsc = gp->gp_un.gp_scalar;
960
961 if (oldsc)
962 {
963 sc->sc_gobj.g_next = oldsc->sc_gobj.g_next;
964 oldsc->sc_gobj.g_next = &sc->sc_gobj;
965 }
966 else
967 {
968 sc->sc_gobj.g_next = glist->gl_list;
969 glist->gl_list = &sc->sc_gobj;
970 }
971 if (glist_isvisible(glist_getcanvas(glist)))
972 gobj_vis(&sc->sc_gobj, glist, 1);
973
974 gp->gp_un.gp_scalar = sc;
975 vec = sc->sc_vec;
976 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
977 {
978 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
979 }
980
981 glist_redrawitem(glist, (t_gobj *)sc);
982
983 outlet_pointer(x->x_obj.ob_outlet, gp);
984}
985
986static void append_free(t_append *x)
987{
988 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
989 gpointer_unset(&x->x_gp);
990}
991
992static void append_setup(void)
993{
994 append_class = class_new(gensym("append"), (t_newmethod)append_new,
995 (t_method)append_free, sizeof(t_append), 0, A_GIMME, 0);
996 class_addfloat(append_class, append_float);
997}
998
999/* ---------------------- sublist ----------------------------- */
1000
1001static t_class *sublist_class;
1002
1003typedef struct _sublist
1004{
1005 t_object x_obj;
1006 t_symbol *x_templatesym;
1007 t_symbol *x_fieldsym;
1008 t_gpointer x_gp;
1009} t_sublist;
1010
1011static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym)
1012{
1013 t_sublist *x = (t_sublist *)pd_new(sublist_class);
1014 x->x_templatesym = canvas_makebindsym(templatesym);
1015 x->x_fieldsym = fieldsym;
1016 gpointer_init(&x->x_gp);
1017 outlet_new(&x->x_obj, &s_pointer);
1018 return (x);
1019}
1020
1021static void sublist_pointer(t_sublist *x, t_gpointer *gp)
1022{
1023 t_symbol *templatesym = x->x_templatesym, *dummy;
1024 t_template *template = template_findbyname(templatesym);
1025 t_gstub *gs = gp->gp_stub;
1026 t_word *vec;
1027 t_getvariable *vp;
1028 int onset, type;
1029 t_word *w;
1030
1031 if (!template)
1032 {
1033 pd_error(x, "sublist: couldn't find template %s", templatesym->s_name);
1034 return;
1035 }
1036 if (gpointer_ishead(gp))
1037 {
1038 pd_error(x, "sublist: empty pointer");
1039 return;
1040 }
1041 if (!template_find_field(template, x->x_fieldsym,
1042 &onset, &type, &dummy))
1043 {
1044 pd_error(x, "sublist: couldn't find field %s", x->x_fieldsym->s_name);
1045 return;
1046 }
1047 if (type != DT_LIST)
1048 {
1049 pd_error(x, "sublist: field %s not of type list", x->x_fieldsym->s_name);
1050 return;
1051 }
1052 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
1053 else w = gp->gp_un.gp_scalar->sc_vec;
1054
1055 gpointer_setglist(&x->x_gp, *(t_glist **)(((char *)w) + onset), 0);
1056
1057 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
1058}
1059
1060static void sublist_free(t_sublist *x, t_gpointer *gp)
1061{
1062 gpointer_unset(&x->x_gp);
1063}
1064
1065static void sublist_setup(void)
1066{
1067 sublist_class = class_new(gensym("sublist"), (t_newmethod)sublist_new,
1068 (t_method)sublist_free, sizeof(t_sublist), 0, A_DEFSYM, A_DEFSYM, 0);
1069 class_addpointer(sublist_class, sublist_pointer);
1070}
1071
1072/* ----------------- setup function ------------------- */
1073
1074void g_traversal_setup(void)
1075{
1076 ptrobj_setup();
1077 get_setup();
1078 set_setup();
1079 elem_setup();
1080 getsize_setup();
1081 setsize_setup();
1082 append_setup();
1083 sublist_setup();
1084}
1085/* Copyright (c) 1997-1999 Miller Puckette.
1086* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1087* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1088
1089/* This file defines Text objects which traverse data contained in scalars
1090and arrays:
1091
1092pointer - point to an object belonging to a template
1093get - get numeric fields
1094set - change numeric fields
1095element - get an array element
1096getsize - get the size of an array
1097setsize - change the size of an array
1098append - add an element to a list
1099sublist - get a pointer into a list which is an element of another scalar
1100
1101*/
1102
1103#include <stdlib.h>
1104#include <string.h>
1105#include <stdio.h> /* for read/write to files */
1106#include "m_pd.h"
1107#include "g_canvas.h"
1108
1109/* ------------- gstubs and gpointers - safe pointing --------------- */
1110
1111/* create a gstub which is "owned" by a glist (gl) or an array ("a"). */
1112
1113t_gstub *gstub_new(t_glist *gl, t_array *a)
1114{
1115 t_gstub *gs = t_getbytes(sizeof(*gs));
1116 if (gl)
1117 {
1118 gs->gs_which = GP_GLIST;
1119 gs->gs_un.gs_glist = gl;
1120 }
1121 else
1122 {
1123 gs->gs_which = GP_ARRAY;
1124 gs->gs_un.gs_array = a;
1125 }
1126 gs->gs_refcount = 0;
1127 return (gs);
1128}
1129
1130/* when a "gpointer" is set to point to this stub (so we can later chase
1131down the owner) we increase a reference count. The following routine is called
1132whenever a gpointer is unset from pointing here. If the owner is
1133gone and the refcount goes to zero, we can free the gstub safely. */
1134
1135static void gstub_dis(t_gstub *gs)
1136{
1137 int refcount = --gs->gs_refcount;
1138 if ((!refcount) && gs->gs_which == GP_NONE)
1139 t_freebytes(gs, sizeof (*gs));
1140 else if (refcount < 0) bug("gstub_dis");
1141}
1142
1143/* this routing is called by the owner to inform the gstub that it is
1144being deleted. If no gpointers are pointing here, we can free the gstub;
1145otherwise we wait for the last gstub_dis() to free it. */
1146
1147void gstub_cutoff(t_gstub *gs)
1148{
1149 gs->gs_which = GP_NONE;
1150 if (gs->gs_refcount < 0) bug("gstub_cutoff");
1151 if (!gs->gs_refcount) t_freebytes(gs, sizeof (*gs));
1152}
1153
1154/* call this to verify that a pointer is fresh, i.e., that it either
1155points to real data or to the head of a list, and that in either case
1156the object hasn't disappeared since this pointer was generated.
1157Unless "headok" is set, the routine also fails for the head of a list. */
1158
1159int gpointer_check(const t_gpointer *gp, int headok)
1160{
1161 t_gstub *gs = gp->gp_stub;
1162 if (!gs) return (0);
1163 if (gs->gs_which == GP_ARRAY)
1164 {
1165 if (gs->gs_un.gs_array->a_valid != gp->gp_valid) return (0);
1166 else return (1);
1167 }
1168 else if (gs->gs_which == GP_GLIST)
1169 {
1170 if (!headok && !gp->gp_un.gp_scalar) return (0);
1171 else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid) return (0);
1172 else return (1);
1173 }
1174 else return (0);
1175}
1176
1177/* call this if you know the pointer is fresh but don't know if we're pointing
1178to the head of a list or to real data. Any pointer is known to be fresh
1179when it appears as the argument of a message, but if your "pointer" method
1180or inlet stores it and you use it later, call gpointer_check above. */
1181
1182/* LATER reconsider the above... I no longer think it's true! */
1183
1184static int gpointer_ishead(const t_gpointer *gp)
1185{
1186 return ((gp->gp_stub->gs_which == GP_GLIST) && !gp->gp_un.gp_scalar);
1187}
1188
1189/* get the template for the object pointer to. Assumes we've already checked
1190freshness. Returns 0 if head of list. */
1191
1192static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
1193{
1194 t_gstub *gs = gp->gp_stub;
1195 if (gs->gs_which == GP_GLIST)
1196 {
1197 t_scalar *sc = gp->gp_un.gp_scalar;
1198 if (sc)
1199 return (sc->sc_template);
1200 else return (0);
1201 }
1202 else
1203 {
1204 t_array *a = gs->gs_un.gs_array;
1205 return (a->a_templatesym);
1206 }
1207}
1208
1209 /* copy a pointer to another, assuming the first one is fresh and
1210 the second one hasn't yet been initialized. */
1211void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
1212{
1213 *gpto = *gpfrom;
1214 if (gpto->gp_stub)
1215 gpto->gp_stub->gs_refcount++;
1216 else bug("gpointer_copy");
1217}
1218
1219void gpointer_unset(t_gpointer *gp)
1220{
1221 t_gstub *gs;
1222 if (gs = gp->gp_stub)
1223 {
1224 gstub_dis(gs);
1225 gp->gp_stub = 0;
1226 }
1227}
1228
1229void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x)
1230{
1231 t_gstub *gs;
1232 if (gs = gp->gp_stub) gstub_dis(gs);
1233 gp->gp_stub = gs = glist->gl_stub;
1234 gp->gp_valid = glist->gl_valid;
1235 gp->gp_un.gp_scalar = x;
1236 gs->gs_refcount++;
1237}
1238
1239static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w)
1240{
1241 t_gstub *gs;
1242 if (gs = gp->gp_stub) gstub_dis(gs);
1243 gp->gp_stub = gs = array->a_stub;
1244 gp->gp_valid = array->a_valid;
1245 gp->gp_un.gp_w = w;
1246 gs->gs_refcount++;
1247}
1248
1249void gpointer_init(t_gpointer *gp)
1250{
1251 gp->gp_stub = 0;
1252 gp->gp_valid = 0;
1253 gp->gp_un.gp_scalar = 0;
1254}
1255
1256/* ---------------------- pointers ----------------------------- */
1257
1258static t_class *ptrobj_class;
1259
1260typedef struct
1261{
1262 t_symbol *to_type;
1263 t_outlet *to_outlet;
1264} t_typedout;
1265
1266typedef struct _ptrobj
1267{
1268 t_object x_obj;
1269 t_gpointer x_gp;
1270 t_typedout *x_typedout;
1271 int x_ntypedout;
1272 t_outlet *x_otherout;
1273 t_outlet *x_bangout;
1274} t_ptrobj;
1275
1276static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv)
1277{
1278 t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
1279 t_typedout *to;
1280 int n;
1281 gpointer_init(&x->x_gp);
1282 x->x_typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
1283 x->x_ntypedout = n = argc;
1284 for (; n--; to++)
1285 {
1286 to->to_outlet = outlet_new(&x->x_obj, &s_pointer);
1287 to->to_type = canvas_makebindsym(atom_getsymbol(argv++));
1288 }
1289 x->x_otherout = outlet_new(&x->x_obj, &s_pointer);
1290 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
1291 pointerinlet_new(&x->x_obj, &x->x_gp);
1292 return (x);
1293}
1294
1295static void ptrobj_traverse(t_ptrobj *x, t_symbol *s)
1296{
1297 t_glist *glist = (t_glist *)pd_findbyclass(s, canvas_class);
1298 if (glist) gpointer_setglist(&x->x_gp, glist, 0);
1299 else pd_error(x, "pointer: list '%s' not found", s->s_name);
1300}
1301
1302static void ptrobj_vnext(t_ptrobj *x, float f)
1303{
1304 t_gobj *gobj;
1305 t_gpointer *gp = &x->x_gp;
1306 t_gstub *gs = gp->gp_stub;
1307 t_glist *glist;
1308 int wantselected = (f != 0);
1309
1310 if (!gs)
1311 {
1312 pd_error(x, "ptrobj_next: no current pointer");
1313 return;
1314 }
1315 if (gs->gs_which != GP_GLIST)
1316 {
1317 pd_error(x, "ptrobj_next: lists only, not arrays");
1318 return;
1319 }
1320 glist = gs->gs_un.gs_glist;
1321 if (glist->gl_valid != gp->gp_valid)
1322 {
1323 pd_error(x, "ptrobj_next: stale pointer");
1324 return;
1325 }
1326 if (wantselected && !glist_isvisible(glist))
1327 {
1328 pd_error(x,
1329 "ptrobj_vnext: next-selected only works for a visible window");
1330 return;
1331 }
1332 gobj = &gp->gp_un.gp_scalar->sc_gobj;
1333
1334 if (!gobj) gobj = glist->gl_list;
1335 else gobj = gobj->g_next;
1336 while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) ||
1337 (wantselected && !glist_isselected(glist, gobj))))
1338 gobj = gobj->g_next;
1339
1340 if (gobj)
1341 {
1342 t_typedout *to;
1343 int n;
1344 t_scalar *sc = (t_scalar *)gobj;
1345 t_symbol *templatesym = sc->sc_template;
1346
1347 gp->gp_un.gp_scalar = sc;
1348 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
1349 {
1350 if (to->to_type == templatesym)
1351 {
1352 outlet_pointer(to->to_outlet, &x->x_gp);
1353 return;
1354 }
1355 }
1356 outlet_pointer(x->x_otherout, &x->x_gp);
1357 }
1358 else
1359 {
1360 gpointer_unset(gp);
1361 outlet_bang(x->x_bangout);
1362 }
1363}
1364
1365static void ptrobj_next(t_ptrobj *x)
1366{
1367 ptrobj_vnext(x, 0);
1368}
1369
1370static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv)
1371{
1372 t_scalar *sc;
1373 t_symbol *templatesym;
1374 int n;
1375 t_typedout *to;
1376 t_glist *glist;
1377 t_pd *canvas;
1378 t_gstub *gs;
1379 if (!gpointer_check(&x->x_gp, 1))
1380 {
1381 pd_error(x, "ptrobj_bang: empty pointer");
1382 return;
1383 }
1384 gs = x->x_gp.gp_stub;
1385 if (gs->gs_which == GP_GLIST)
1386 glist = gs->gs_un.gs_glist;
1387 else
1388 {
1389 t_array *owner_array = gs->gs_un.gs_array;
1390 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
1391 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
1392 glist = owner_array->a_gp.gp_stub->gs_un.gs_glist;
1393 }
1394 canvas = (t_pd *)glist_getcanvas(glist);
1395 if (argc && argv->a_type == A_SYMBOL)
1396 pd_typedmess(canvas, argv->a_w.w_symbol, argc-1, argv+1);
1397 else pd_error(x, "send-window: no message?");
1398}
1399
1400static void ptrobj_bang(t_ptrobj *x)
1401{
1402 t_symbol *templatesym;
1403 int n;
1404 t_typedout *to;
1405 if (!gpointer_check(&x->x_gp, 1))
1406 {
1407 pd_error(x, "ptrobj_bang: empty pointer");
1408 return;
1409 }
1410 templatesym = gpointer_gettemplatesym(&x->x_gp);
1411 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
1412 {
1413 if (to->to_type == templatesym)
1414 {
1415 outlet_pointer(to->to_outlet, &x->x_gp);
1416 return;
1417 }
1418 }
1419 outlet_pointer(x->x_otherout, &x->x_gp);
1420}
1421
1422
1423static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp)
1424{
1425 gpointer_unset(&x->x_gp);
1426 gpointer_copy(gp, &x->x_gp);
1427 ptrobj_bang(x);
1428}
1429
1430static void ptrobj_free(t_ptrobj *x)
1431{
1432 freebytes(x->x_typedout, x->x_ntypedout * sizeof (*x->x_typedout));
1433 gpointer_unset(&x->x_gp);
1434}
1435
1436static void ptrobj_setup(void)
1437{
1438 ptrobj_class = class_new(gensym("pointer"), (t_newmethod)ptrobj_new,
1439 (t_method)ptrobj_free, sizeof(t_ptrobj), 0, A_GIMME, 0);
1440 class_addmethod(ptrobj_class, (t_method)ptrobj_traverse, gensym("traverse"),
1441 A_SYMBOL, 0);
1442 class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), 0);
1443 class_addmethod(ptrobj_class, (t_method)ptrobj_vnext, gensym("vnext"),
1444 A_DEFFLOAT, 0);
1445 class_addmethod(ptrobj_class, (t_method)ptrobj_sendwindow,
1446 gensym("send-window"), A_GIMME, 0);
1447 class_addpointer(ptrobj_class, ptrobj_pointer);
1448 class_addbang(ptrobj_class, ptrobj_bang);
1449}
1450
1451/* ---------------------- get ----------------------------- */
1452
1453static t_class *get_class;
1454
1455typedef struct _getvariable
1456{
1457 t_symbol *gv_sym;
1458 t_outlet *gv_outlet;
1459} t_getvariable;
1460
1461typedef struct _get
1462{
1463 t_object x_obj;
1464 t_symbol *x_templatesym;
1465 int x_nout;
1466 t_getvariable *x_variables;
1467} t_get;
1468
1469static void *get_new(t_symbol *why, int argc, t_atom *argv)
1470{
1471 t_get *x = (t_get *)pd_new(get_class);
1472 int i;
1473 t_getvariable *sp;
1474 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
1475 if (argc) argc--, argv++;
1476 x->x_variables
1477 = (t_getvariable *)getbytes(argc * sizeof (*x->x_variables));
1478 x->x_nout = argc;
1479 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
1480 {
1481 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
1482 sp->gv_outlet = outlet_new(&x->x_obj, 0);
1483 /* LATER connect with the template and set the outlet's type
1484 correctly. We can't yet guarantee that the template is there
1485 before we hit this routine. */
1486 }
1487 return (x);
1488}
1489
1490static void get_pointer(t_get *x, t_gpointer *gp)
1491{
1492 int nitems = x->x_nout, i;
1493 t_symbol *templatesym = x->x_templatesym;
1494 t_template *template = template_findbyname(templatesym);
1495 t_gstub *gs = gp->gp_stub;
1496 t_word *vec;
1497 t_getvariable *vp;
1498 if (!template)
1499 {
1500 pd_error(x, "get: couldn't find template %s", templatesym->s_name);
1501 return;
1502 }
1503 if (gpointer_ishead(gp))
1504 {
1505 pd_error(x, "get: empty pointer");
1506 return;
1507 }
1508 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
1509 else vec = gp->gp_un.gp_scalar->sc_vec;
1510 for (i = nitems - 1, vp = x->x_variables + i; i >= 0; i--, vp--)
1511 {
1512 float f = template_getfloat(template, vp->gv_sym, vec, 1);
1513 outlet_float(vp->gv_outlet, f);
1514 /* LATER deal with other types. */
1515 }
1516}
1517
1518static void get_free(t_get *x)
1519{
1520 freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables));
1521}
1522
1523static void get_setup(void)
1524{
1525 get_class = class_new(gensym("get"), (t_newmethod)get_new,
1526 (t_method)get_free, sizeof(t_get), 0, A_GIMME, 0);
1527 class_addpointer(get_class, get_pointer);
1528}
1529
1530/* ---------------------- set ----------------------------- */
1531
1532static t_class *set_class;
1533
1534typedef struct _setvariable
1535{
1536 t_symbol *gv_sym;
1537 t_float gv_f; /* LATER take other types */
1538} t_setvariable;
1539
1540typedef struct _set
1541{
1542 t_object x_obj;
1543 t_gpointer x_gp;
1544 t_symbol *x_templatesym;
1545 int x_nin;
1546 t_setvariable *x_variables;
1547} t_set;
1548
1549static void *set_new(t_symbol *why, int argc, t_atom *argv)
1550{
1551 t_set *x = (t_set *)pd_new(set_class);
1552 int i;
1553 t_setvariable *sp;
1554 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
1555 if (argc) argc--, argv++;
1556 x->x_variables
1557 = (t_setvariable *)getbytes(argc * sizeof (*x->x_variables));
1558 x->x_nin = argc;
1559 if (argc)
1560 {
1561 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
1562 {
1563 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
1564 sp->gv_f = 0;
1565 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
1566 /* LATER figure out type as in "get" object. */
1567 }
1568 }
1569 pointerinlet_new(&x->x_obj, &x->x_gp);
1570 gpointer_init(&x->x_gp);
1571 return (x);
1572}
1573
1574static void set_float(t_set *x, t_float f)
1575{
1576 int nitems = x->x_nin, i;
1577 t_symbol *templatesym = x->x_templatesym;
1578 t_template *template = template_findbyname(templatesym);
1579 t_setvariable *vp;
1580 t_gpointer *gp = &x->x_gp;
1581 t_gstub *gs = gp->gp_stub;
1582 t_word *vec;
1583 if (!template)
1584 {
1585 pd_error(x, "set: couldn't find template %s", templatesym->s_name);
1586 return;
1587 }
1588 if (!gpointer_check(gp, 0))
1589 {
1590 pd_error(x, "set: empty pointer");
1591 return;
1592 }
1593 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
1594 {
1595 pd_error(x, "set %s: got wrong template (%s)",
1596 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
1597 return;
1598 }
1599 if (!nitems) return;
1600 x->x_variables[0].gv_f = f;
1601 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
1602 else vec = gp->gp_un.gp_scalar->sc_vec;
1603 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
1604 {
1605 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
1606 /* LATER deal with other types ala get_pointer. */
1607 }
1608 if (gs->gs_which == GP_GLIST)
1609 glist_redrawitem(gs->gs_un.gs_glist, (t_gobj *)(gp->gp_un.gp_scalar));
1610 else
1611 {
1612 t_array *owner_array = gs->gs_un.gs_array;
1613 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
1614 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
1615 glist_redrawitem(owner_array->a_gp.gp_stub->gs_un.gs_glist,
1616 (t_gobj *)(owner_array->a_gp.gp_un.gp_scalar));
1617 }
1618}
1619
1620static void set_free(t_set *x)
1621{
1622 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
1623 gpointer_unset(&x->x_gp);
1624}
1625
1626static void set_setup(void)
1627{
1628 set_class = class_new(gensym("set"), (t_newmethod)set_new,
1629 (t_method)set_free, sizeof(t_set), 0, A_GIMME, 0);
1630 class_addfloat(set_class, set_float);
1631}
1632
1633/* ---------------------- elem ----------------------------- */
1634
1635static t_class *elem_class;
1636
1637typedef struct _elem
1638{
1639 t_object x_obj;
1640 t_symbol *x_templatesym;
1641 t_symbol *x_fieldsym;
1642 t_gpointer x_gp;
1643 t_gpointer x_gparent;
1644} t_elem;
1645
1646static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym)
1647{
1648 t_elem *x = (t_elem *)pd_new(elem_class);
1649 x->x_templatesym = canvas_makebindsym(templatesym);
1650 x->x_fieldsym = fieldsym;
1651 gpointer_init(&x->x_gp);
1652 gpointer_init(&x->x_gparent);
1653 pointerinlet_new(&x->x_obj, &x->x_gparent);
1654 outlet_new(&x->x_obj, &s_pointer);
1655 return (x);
1656}
1657
1658static void elem_float(t_elem *x, t_float f)
1659{
1660 int indx = f, nitems, onset;
1661 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
1662 *elemtemplatesym;
1663 t_template *template = template_findbyname(templatesym);
1664 t_template *elemtemplate;
1665 t_gpointer *gparent = &x->x_gparent;
1666 t_word *w;
1667 t_array *array;
1668 int elemsize, type;
1669
1670 if (!gpointer_check(gparent, 0))
1671 {
1672 pd_error(x, "element: empty pointer");
1673 return;
1674 }
1675 if (gpointer_gettemplatesym(gparent) != x->x_templatesym)
1676 {
1677 pd_error(x, "element %s: got wrong template (%s)",
1678 x->x_templatesym->s_name, gpointer_gettemplatesym(gparent)->s_name);
1679 return;
1680 }
1681 if (gparent->gp_stub->gs_which == GP_ARRAY) w = gparent->gp_un.gp_w;
1682 else w = gparent->gp_un.gp_scalar->sc_vec;
1683 if (!template)
1684 {
1685 pd_error(x, "element: couldn't find template %s", templatesym->s_name);
1686 return;
1687 }
1688 if (!template_find_field(template, fieldsym,
1689 &onset, &type, &elemtemplatesym))
1690 {
1691 pd_error(x, "element: couldn't find array field %s", fieldsym->s_name);
1692 return;
1693 }
1694 if (type != DT_ARRAY)
1695 {
1696 pd_error(x, "element: field %s not of type array", fieldsym->s_name);
1697 return;
1698 }
1699 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
1700 {
1701 pd_error(x, "element: couldn't find field template %s",
1702 elemtemplatesym->s_name);
1703 return;
1704 }
1705
1706 elemsize = elemtemplate->t_n * sizeof(t_word);
1707
1708 array = *(t_array **)(((char *)w) + onset);
1709
1710 nitems = array->a_n;
1711 if (indx < 0) indx = 0;
1712 if (indx >= nitems) indx = nitems-1;
1713
1714 gpointer_setarray(&x->x_gp, array,
1715 (t_word *)((char *)(array->a_vec) + indx * elemsize));
1716 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
1717}
1718
1719static void elem_free(t_elem *x, t_gpointer *gp)
1720{
1721 gpointer_unset(&x->x_gp);
1722 gpointer_unset(&x->x_gparent);
1723}
1724
1725static void elem_setup(void)
1726{
1727 elem_class = class_new(gensym("element"), (t_newmethod)elem_new,
1728 (t_method)elem_free, sizeof(t_elem), 0, A_DEFSYM, A_DEFSYM, 0);
1729 class_addfloat(elem_class, elem_float);
1730}
1731
1732/* ---------------------- getsize ----------------------------- */
1733
1734static t_class *getsize_class;
1735
1736typedef struct _getsize
1737{
1738 t_object x_obj;
1739 t_symbol *x_templatesym;
1740 t_symbol *x_fieldsym;
1741} t_getsize;
1742
1743static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym)
1744{
1745 t_getsize *x = (t_getsize *)pd_new(getsize_class);
1746 x->x_templatesym = canvas_makebindsym(templatesym);
1747 x->x_fieldsym = fieldsym;
1748 outlet_new(&x->x_obj, &s_float);
1749 return (x);
1750}
1751
1752static void getsize_pointer(t_getsize *x, t_gpointer *gp)
1753{
1754 int nitems, onset, type;
1755 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
1756 *elemtemplatesym;
1757 t_template *template = template_findbyname(templatesym);
1758 t_word *w;
1759 t_array *array;
1760 int elemsize;
1761 t_gstub *gs = gp->gp_stub;
1762 if (!template)
1763 {
1764 pd_error(x, "getsize: couldn't find template %s", templatesym->s_name);
1765 return;
1766 }
1767 if (!template_find_field(template, fieldsym,
1768 &onset, &type, &elemtemplatesym))
1769 {
1770 pd_error(x, "getsize: couldn't find array field %s", fieldsym->s_name);
1771 return;
1772 }
1773 if (type != DT_ARRAY)
1774 {
1775 pd_error(x, "getsize: field %s not of type array", fieldsym->s_name);
1776 return;
1777 }
1778 if (gpointer_ishead(gp))
1779 {
1780 pd_error(x, "getsize: empty pointer");
1781 return;
1782 }
1783 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
1784 {
1785 pd_error(x, "getsize %s: got wrong template (%s)",
1786 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
1787 return;
1788 }
1789 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
1790 else w = gp->gp_un.gp_scalar->sc_vec;
1791
1792 array = *(t_array **)(((char *)w) + onset);
1793 outlet_float(x->x_obj.ob_outlet, (float)(array->a_n));
1794}
1795
1796static void getsize_setup(void)
1797{
1798 getsize_class = class_new(gensym("getsize"), (t_newmethod)getsize_new, 0,
1799 sizeof(t_getsize), 0, A_DEFSYM, A_DEFSYM, 0);
1800 class_addpointer(getsize_class, getsize_pointer);
1801}
1802
1803/* ---------------------- setsize ----------------------------- */
1804
1805static t_class *setsize_class;
1806
1807typedef struct _setsize
1808{
1809 t_object x_obj;
1810 t_symbol *x_templatesym;
1811 t_symbol *x_fieldsym;
1812 t_gpointer x_gp;
1813} t_setsize;
1814
1815static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym,
1816 t_floatarg newsize)
1817{
1818 t_setsize *x = (t_setsize *)pd_new(setsize_class);
1819 x->x_templatesym = canvas_makebindsym(templatesym);
1820 x->x_fieldsym = fieldsym;
1821 gpointer_init(&x->x_gp);
1822
1823 pointerinlet_new(&x->x_obj, &x->x_gp);
1824 return (x);
1825}
1826
1827static void setsize_float(t_setsize *x, t_float f)
1828{
1829 int nitems, onset, type;
1830 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
1831 *elemtemplatesym;
1832 t_template *template = template_findbyname(templatesym);
1833 t_template *elemtemplate;
1834 t_word *w;
1835 t_atom at;
1836 t_array *array;
1837 int elemsize;
1838 int newsize = f;
1839 t_gpointer *gp = &x->x_gp;
1840 t_gstub *gs = gp->gp_stub;
1841 if (!gpointer_check(&x->x_gp, 0))
1842 {
1843 pd_error(x, "setsize: empty pointer");
1844 return;
1845 }
1846 if (gpointer_gettemplatesym(&x->x_gp) != x->x_templatesym)
1847 {
1848 pd_error(x, "setsize %s: got wrong template (%s)",
1849 x->x_templatesym->s_name,
1850 gpointer_gettemplatesym(&x->x_gp)->s_name);
1851 return;
1852 }
1853 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
1854 else w = gp->gp_un.gp_scalar->sc_vec;
1855
1856 if (!template)
1857 {
1858 pd_error(x,"setsize: couldn't find template %s", templatesym->s_name);
1859 return;
1860 }
1861 if (!template_find_field(template, fieldsym,
1862 &onset, &type, &elemtemplatesym))
1863 {
1864 pd_error(x,"setsize: couldn't find array field %s", fieldsym->s_name);
1865 return;
1866 }
1867 if (type != DT_ARRAY)
1868 {
1869 pd_error(x,"setsize: field %s not of type array", fieldsym->s_name);
1870 return;
1871 }
1872
1873 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
1874 {
1875 pd_error(x,"element: couldn't find field template %s",
1876 elemtemplatesym->s_name);
1877 return;
1878 }
1879
1880 elemsize = elemtemplate->t_n * sizeof(t_word);
1881
1882 array = *(t_array **)(((char *)w) + onset);
1883
1884 if (elemsize != array->a_elemsize) bug("setsize_gpointer");
1885
1886 nitems = array->a_n;
1887 if (newsize < 1) newsize = 1;
1888 if (newsize == nitems) return;
1889
1890 /* erase the array before resizing it. If we belong to a
1891 scalar it's easy, but if we belong to an element of another
1892 array we have to search back until we get to a scalar to erase.
1893 When graphics updates become queueable this may fall apart... */
1894
1895
1896 if (gs->gs_which == GP_GLIST)
1897 {
1898 if (glist_isvisible(gs->gs_un.gs_glist))
1899 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 0);
1900 }
1901 else
1902 {
1903 t_array *owner_array = gs->gs_un.gs_array;
1904 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
1905 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
1906 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
1907 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
1908 owner_array->a_gp.gp_stub->gs_un.gs_glist, 0);
1909 }
1910 /* now do the resizing and, if growing, initialize new scalars */
1911 array->a_vec = (char *)resizebytes(array->a_vec,
1912 elemsize * nitems, elemsize * newsize);
1913 array->a_n = newsize;
1914 if (newsize > nitems)
1915 {
1916 char *newelem = ((char *)array->a_vec) + nitems * elemsize;
1917 int i = 0, nnew = newsize - nitems;
1918
1919 while (nnew--)
1920 {
1921 word_init((t_word *)newelem, elemtemplate, gp);
1922 newelem += elemsize;
1923 /* post("new %x %x, ntypes %d", newelem, *(int *)newelem, ntypes); */
1924 }
1925 }
1926
1927 /* redraw again. */
1928 if (gs->gs_which == GP_GLIST)
1929 {
1930 if (glist_isvisible(gs->gs_un.gs_glist))
1931 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 1);
1932 }
1933 else
1934 {
1935 t_array *owner_array = gs->gs_un.gs_array;
1936 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
1937 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
1938 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
1939 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
1940 owner_array->a_gp.gp_stub->gs_un.gs_glist, 1);
1941 }
1942}
1943
1944
1945static void setsize_free(t_setsize *x)
1946{
1947 gpointer_unset(&x->x_gp);
1948}
1949
1950static void setsize_setup(void)
1951{
1952 setsize_class = class_new(gensym("setsize"), (t_newmethod)setsize_new,
1953 (t_method)setsize_free, sizeof(t_setsize), 0,
1954 A_DEFSYM, A_DEFSYM, A_DEFFLOAT, 0);
1955 class_addfloat(setsize_class, setsize_float);
1956}
1957
1958/* ---------------------- append ----------------------------- */
1959
1960static t_class *append_class;
1961
1962typedef struct _appendvariable
1963{
1964 t_symbol *gv_sym;
1965 t_float gv_f;
1966} t_appendvariable;
1967
1968typedef struct _append
1969{
1970 t_object x_obj;
1971 t_gpointer x_gp;
1972 t_symbol *x_templatesym;
1973 int x_nin;
1974 t_appendvariable *x_variables;
1975} t_append;
1976
1977static void *append_new(t_symbol *why, int argc, t_atom *argv)
1978{
1979 t_append *x = (t_append *)pd_new(append_class);
1980 int i;
1981 t_appendvariable *sp;
1982 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
1983 if (argc) argc--, argv++;
1984 x->x_variables
1985 = (t_appendvariable *)getbytes(argc * sizeof (*x->x_variables));
1986 x->x_nin = argc;
1987 if (argc)
1988 {
1989 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
1990 {
1991 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
1992 sp->gv_f = 0;
1993 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
1994 }
1995 }
1996 pointerinlet_new(&x->x_obj, &x->x_gp);
1997 outlet_new(&x->x_obj, &s_pointer);
1998 gpointer_init(&x->x_gp);
1999 return (x);
2000}
2001
2002static void append_float(t_append *x, t_float f)
2003{
2004 int nitems = x->x_nin, i;
2005 t_symbol *templatesym = x->x_templatesym;
2006 t_template *template = template_findbyname(templatesym);
2007 t_appendvariable *vp;
2008 t_gpointer *gp = &x->x_gp;
2009 t_gstub *gs = gp->gp_stub;
2010 t_word *vec;
2011 t_scalar *sc, *oldsc;
2012 t_glist *glist;
2013 if (!template)
2014 {
2015 pd_error(x, "append: couldn't find template %s", templatesym->s_name);
2016 return;
2017 }
2018 if (!gs)
2019 {
2020 pd_error(x, "append: no current pointer");
2021 return;
2022 }
2023 if (gs->gs_which != GP_GLIST)
2024 {
2025 pd_error(x, "append: lists only, not arrays");
2026 return;
2027 }
2028 glist = gs->gs_un.gs_glist;
2029 if (glist->gl_valid != gp->gp_valid)
2030 {
2031 pd_error(x, "append: stale pointer");
2032 return;
2033 }
2034 if (!nitems) return;
2035 x->x_variables[0].gv_f = f;
2036
2037 sc = scalar_new(glist, templatesym);
2038 if (!sc)
2039 {
2040 pd_error(x, "%s: couldn't create scalar", templatesym->s_name);
2041 return;
2042 }
2043 oldsc = gp->gp_un.gp_scalar;
2044
2045 if (oldsc)
2046 {
2047 sc->sc_gobj.g_next = oldsc->sc_gobj.g_next;
2048 oldsc->sc_gobj.g_next = &sc->sc_gobj;
2049 }
2050 else
2051 {
2052 sc->sc_gobj.g_next = glist->gl_list;
2053 glist->gl_list = &sc->sc_gobj;
2054 }
2055 if (glist_isvisible(glist_getcanvas(glist)))
2056 gobj_vis(&sc->sc_gobj, glist, 1);
2057
2058 gp->gp_un.gp_scalar = sc;
2059 vec = sc->sc_vec;
2060 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
2061 {
2062 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
2063 }
2064
2065 glist_redrawitem(glist, (t_gobj *)sc);
2066
2067 outlet_pointer(x->x_obj.ob_outlet, gp);
2068}
2069
2070static void append_free(t_append *x)
2071{
2072 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
2073 gpointer_unset(&x->x_gp);
2074}
2075
2076static void append_setup(void)
2077{
2078 append_class = class_new(gensym("append"), (t_newmethod)append_new,
2079 (t_method)append_free, sizeof(t_append), 0, A_GIMME, 0);
2080 class_addfloat(append_class, append_float);
2081}
2082
2083/* ---------------------- sublist ----------------------------- */
2084
2085static t_class *sublist_class;
2086
2087typedef struct _sublist
2088{
2089 t_object x_obj;
2090 t_symbol *x_templatesym;
2091 t_symbol *x_fieldsym;
2092 t_gpointer x_gp;
2093} t_sublist;
2094
2095static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym)
2096{
2097 t_sublist *x = (t_sublist *)pd_new(sublist_class);
2098 x->x_templatesym = canvas_makebindsym(templatesym);
2099 x->x_fieldsym = fieldsym;
2100 gpointer_init(&x->x_gp);
2101 outlet_new(&x->x_obj, &s_pointer);
2102 return (x);
2103}
2104
2105static void sublist_pointer(t_sublist *x, t_gpointer *gp)
2106{
2107 t_symbol *templatesym = x->x_templatesym, *dummy;
2108 t_template *template = template_findbyname(templatesym);
2109 t_gstub *gs = gp->gp_stub;
2110 t_word *vec;
2111 t_getvariable *vp;
2112 int onset, type;
2113 t_word *w;
2114
2115 if (!template)
2116 {
2117 pd_error(x, "sublist: couldn't find template %s", templatesym->s_name);
2118 return;
2119 }
2120 if (gpointer_ishead(gp))
2121 {
2122 pd_error(x, "sublist: empty pointer");
2123 return;
2124 }
2125 if (!template_find_field(template, x->x_fieldsym,
2126 &onset, &type, &dummy))
2127 {
2128 pd_error(x, "sublist: couldn't find field %s", x->x_fieldsym->s_name);
2129 return;
2130 }
2131 if (type != DT_LIST)
2132 {
2133 pd_error(x, "sublist: field %s not of type list", x->x_fieldsym->s_name);
2134 return;
2135 }
2136 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
2137 else w = gp->gp_un.gp_scalar->sc_vec;
2138
2139 gpointer_setglist(&x->x_gp, *(t_glist **)(((char *)w) + onset), 0);
2140
2141 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
2142}
2143
2144static void sublist_free(t_sublist *x, t_gpointer *gp)
2145{
2146 gpointer_unset(&x->x_gp);
2147}
2148
2149static void sublist_setup(void)
2150{
2151 sublist_class = class_new(gensym("sublist"), (t_newmethod)sublist_new,
2152 (t_method)sublist_free, sizeof(t_sublist), 0, A_DEFSYM, A_DEFSYM, 0);
2153 class_addpointer(sublist_class, sublist_pointer);
2154}
2155
2156/* ----------------- setup function ------------------- */
2157
2158void g_traversal_setup(void)
2159{
2160 ptrobj_setup();
2161 get_setup();
2162 set_setup();
2163 elem_setup();
2164 getsize_setup();
2165 setsize_setup();
2166 append_setup();
2167 sublist_setup();
2168}
diff --git a/apps/plugins/pdbox/PDa/src/g_vdial.c b/apps/plugins/pdbox/PDa/src/g_vdial.c
new file mode 100644
index 0000000000..08b1338daf
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_vdial.c
@@ -0,0 +1,1432 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* vdial.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6
7/* name change to vradio by MSP (it's a radio button really) and changed to
8put out a "float" as in sliders, toggles, etc. */
9
10#include <stdlib.h>
11#include <string.h>
12#include <stdio.h>
13#include <ctype.h>
14#include "m_pd.h"
15#include "g_canvas.h"
16#include "t_tk.h"
17#include "g_all_guis.h"
18#include <math.h>
19
20/*------------------ global variables -------------------------*/
21
22
23/*------------------ global functions -------------------------*/
24
25
26
27
28/* ------------- vdl gui-vertical radio button ---------------------- */
29
30t_widgetbehavior vradio_widgetbehavior;
31static t_class *vradio_class, *vradio_old_class;
32
33/* widget helper functions */
34
35void vradio_draw_update(t_vradio *x, t_glist *glist)
36{
37 if(glist_isvisible(glist))
38 {
39 t_canvas *canvas=glist_getcanvas(glist);
40
41 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
42 canvas, x, x->x_on_old,
43 x->x_gui.x_bcol, x->x_gui.x_bcol);
44 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
45 canvas, x, x->x_on,
46 x->x_gui.x_fcol, x->x_gui.x_fcol);
47 }
48}
49
50void vradio_draw_new(t_vradio *x, t_glist *glist)
51{
52 t_canvas *canvas=glist_getcanvas(glist);
53 int n=x->x_number, i, dy=x->x_gui.x_h, s4=dy/4;
54 int yy11b=text_ypix(&x->x_gui.x_obj, glist);
55 int yy11=yy11b, yy12=yy11+dy;
56 int yy21=yy11+s4, yy22=yy12-s4;
57 int xx11=text_xpix(&x->x_gui.x_obj, glist), xx12=xx11+dy;
58 int xx21=xx11+s4, xx22=xx12-s4;
59
60 for(i=0; i<n; i++)
61 {
62 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE%d\n",
63 canvas, xx11, yy11, xx12, yy12,
64 x->x_gui.x_bcol, x, i);
65 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xBUT%d\n",
66 canvas, xx21, yy21, xx22, yy22,
67 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
68 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol, x, i);
69 yy11 += dy;
70 yy12 += dy;
71 yy21 += dy;
72 yy22 += dy;
73 }
74 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
75 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
76 canvas, xx11+x->x_gui.x_ldx, yy11b+x->x_gui.x_ldy,
77 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
78 x->x_gui.x_font, x->x_gui.x_fontsize,
79 x->x_gui.x_lcol, x);
80 if(!x->x_gui.x_fsf.x_snd_able)
81 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
82 canvas, xx11, yy11-1, xx11 + IOWIDTH, yy11, x, 0);
83 if(!x->x_gui.x_fsf.x_rcv_able)
84 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
85 canvas, xx11, yy11b, xx11 + IOWIDTH, yy11b+1, x, 0);
86}
87
88void vradio_draw_move(t_vradio *x, t_glist *glist)
89{
90 t_canvas *canvas=glist_getcanvas(glist);
91 int n=x->x_number, i, dy=x->x_gui.x_h, s4=dy/4;
92 int yy11b=text_ypix(&x->x_gui.x_obj, glist);
93 int yy11=yy11b, yy12=yy11+dy;
94 int yy21=yy11+s4, yy22=yy12-s4;
95 int xx11=text_xpix(&x->x_gui.x_obj, glist), xx12=xx11+dy;
96 int xx21=xx11+s4, xx22=xx12-s4;
97
98 for(i=0; i<n; i++)
99 {
100 sys_vgui(".x%x.c coords %xBASE%d %d %d %d %d\n",
101 canvas, x, i, xx11, yy11, xx12, yy12);
102 sys_vgui(".x%x.c coords %xBUT%d %d %d %d %d\n",
103 canvas, x, i, xx21, yy21, xx22, yy22);
104 yy11 += dy;
105 yy12 += dy;
106 yy21 += dy;
107 yy22 += dy;
108 }
109 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
110 canvas, x, xx11+x->x_gui.x_ldx, yy11b+x->x_gui.x_ldy);
111 if(!x->x_gui.x_fsf.x_snd_able)
112 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
113 canvas, x, 0, xx11, yy11-1, xx11 + IOWIDTH, yy11);
114 if(!x->x_gui.x_fsf.x_rcv_able)
115 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
116 canvas, x, 0, xx11, yy11b, xx11 + IOWIDTH, yy11b+1);
117}
118
119void vradio_draw_erase(t_vradio* x, t_glist* glist)
120{
121 t_canvas *canvas=glist_getcanvas(glist);
122 int n=x->x_number, i;
123
124 for(i=0; i<n; i++)
125 {
126 sys_vgui(".x%x.c delete %xBASE%d\n", canvas, x, i);
127 sys_vgui(".x%x.c delete %xBUT%d\n", canvas, x, i);
128 }
129 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
130 if(!x->x_gui.x_fsf.x_snd_able)
131 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
132 if(!x->x_gui.x_fsf.x_rcv_able)
133 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
134}
135
136void vradio_draw_config(t_vradio* x, t_glist* glist)
137{
138 t_canvas *canvas=glist_getcanvas(glist);
139 int n=x->x_number, i;
140
141 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
142 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
143 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
144 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
145 for(i=0; i<n; i++)
146 {
147 sys_vgui(".x%x.c itemconfigure %xBASE%d -fill #%6.6x\n", canvas, x, i,
148 x->x_gui.x_bcol);
149 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n", canvas, x, i,
150 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
151 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol);
152 }
153}
154
155void vradio_draw_io(t_vradio* x, t_glist* glist, int old_snd_rcv_flags)
156{
157 t_canvas *canvas=glist_getcanvas(glist);
158 int xpos=text_xpix(&x->x_gui.x_obj, glist);
159 int ypos=text_ypix(&x->x_gui.x_obj, glist);
160
161 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
162 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
163 canvas, xpos,
164 ypos+(x->x_number*x->x_gui.x_h)-1,
165 xpos+ IOWIDTH,
166 ypos+(x->x_number*x->x_gui.x_h), x, 0);
167 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
168 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
169 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
170 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
171 canvas, xpos, ypos,
172 xpos+ IOWIDTH, ypos+1,
173 x, 0);
174 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
175 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
176}
177
178void vradio_draw_select(t_vradio* x, t_glist* glist)
179{
180 t_canvas *canvas=glist_getcanvas(glist);
181 int n=x->x_number, i;
182
183 if(x->x_gui.x_fsf.x_selected)
184 {
185 for(i=0; i<n; i++)
186 {
187 sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
188 IEM_GUI_COLOR_SELECTED);
189 }
190 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
191 }
192 else
193 {
194 for(i=0; i<n; i++)
195 {
196 sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
197 IEM_GUI_COLOR_NORMAL);
198 }
199 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x,
200 x->x_gui.x_lcol);
201 }
202}
203
204void vradio_draw(t_vradio *x, t_glist *glist, int mode)
205{
206 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
207 vradio_draw_update(x, glist);
208 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
209 vradio_draw_move(x, glist);
210 else if(mode == IEM_GUI_DRAW_MODE_NEW)
211 vradio_draw_new(x, glist);
212 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
213 vradio_draw_select(x, glist);
214 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
215 vradio_draw_erase(x, glist);
216 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
217 vradio_draw_config(x, glist);
218 else if(mode >= IEM_GUI_DRAW_MODE_IO)
219 vradio_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
220}
221
222/* ------------------------ vdl widgetbehaviour----------------------------- */
223
224static void vradio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
225{
226 t_vradio *x = (t_vradio *)z;
227
228 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
229 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
230 *xp2 = *xp1 + x->x_gui.x_w;
231 *yp2 = *yp1 + x->x_gui.x_h*x->x_number;
232}
233
234static void vradio_save(t_gobj *z, t_binbuf *b)
235{
236 t_vradio *x = (t_vradio *)z;
237 int bflcol[3];
238 t_symbol *srl[3];
239
240 iemgui_save(&x->x_gui, srl, bflcol);
241 binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"),
242 (t_int)x->x_gui.x_obj.te_xpix,
243 (t_int)x->x_gui.x_obj.te_ypix,
244 (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class ?
245 gensym("vdl") : gensym("vradio")),
246 x->x_gui.x_w,
247 x->x_change, iem_symargstoint(&x->x_gui.x_isa), x->x_number,
248 srl[0], srl[1], srl[2],
249 x->x_gui.x_ldx, x->x_gui.x_ldy,
250 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
251 bflcol[0], bflcol[1], bflcol[2], x->x_on);
252 binbuf_addv(b, ";");
253}
254
255static void vradio_properties(t_gobj *z, t_glist *owner)
256{
257 t_vradio *x = (t_vradio *)z;
258 char buf[800];
259 t_symbol *srl[3];
260 int hchange=-1;
261
262 iemgui_properties(&x->x_gui, srl);
263 if(pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
264 hchange = x->x_change;
265 sprintf(buf, "pdtk_iemgui_dialog %%s vradio \
266 ----------dimensions(pix):----------- %d %d size: 0 0 empty \
267 empty 0.0 empty 0.0 empty %d \
268 %d new-only new&old %d %d number: %d \
269 %s %s \
270 %s %d %d \
271 %d %d \
272 %d %d %d\n",
273 x->x_gui.x_w, IEM_GUI_MINSIZE,
274 0,/*no_schedule*/
275 hchange, x->x_gui.x_isa.x_loadinit, -1, x->x_number,
276 srl[0]->s_name, srl[1]->s_name,
277 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
278 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
279 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
280 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
281}
282
283static void vradio_dialog(t_vradio *x, t_symbol *s, int argc, t_atom *argv)
284{
285 t_symbol *srl[3];
286 int a = (int)atom_getintarg(0, argc, argv);
287 int chg = (int)atom_getintarg(4, argc, argv);
288 int num = (int)atom_getintarg(6, argc, argv);
289 int sr_flags;
290
291 if(chg != 0) chg = 1;
292 x->x_change = chg;
293 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
294 x->x_gui.x_w = iemgui_clip_size(a);
295 x->x_gui.x_h = x->x_gui.x_w;
296 if(x->x_number != num)
297 {
298 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
299 x->x_number = num;
300 if(x->x_on >= x->x_number)
301 {
302 x->x_on = x->x_number - 1;
303 x->x_on_old = x->x_on;
304 }
305 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
306 }
307 else
308 {
309 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
310 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
311 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
312 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
313 }
314}
315
316static void vradio_set(t_vradio *x, t_floatarg f)
317{
318 int i=(int)f;
319 int old;
320
321 if(i < 0)
322 i = 0;
323 if(i >= x->x_number)
324 i = x->x_number-1;
325 if(x->x_on != x->x_on_old)
326 {
327 old = x->x_on_old;
328 x->x_on_old = x->x_on;
329 x->x_on = i;
330 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
331 x->x_on_old = old;
332 }
333 else
334 {
335 x->x_on = i;
336 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
337 }
338}
339
340static void vradio_bang(t_vradio *x)
341{
342 /* compatibility with earlier "vdial" behavior */
343 if (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
344 {
345 if((x->x_change)&&(x->x_on != x->x_on_old))
346 {
347 SETFLOAT(x->x_at, (float)x->x_on_old);
348 SETFLOAT(x->x_at+1, 0.0);
349 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
350 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
351 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
352 }
353 x->x_on_old = x->x_on;
354 SETFLOAT(x->x_at, (float)x->x_on);
355 SETFLOAT(x->x_at+1, 1.0);
356 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
357 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
358 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
359 }
360 else
361 {
362 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
363 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
364 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
365 }
366}
367
368static void vradio_fout(t_vradio *x, t_floatarg f)
369{
370 int i=(int)f;
371
372 if(i < 0)
373 i = 0;
374 if(i >= x->x_number)
375 i = x->x_number-1;
376
377 if (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
378 {
379 /* compatibility with earlier "vdial" behavior */
380 if((x->x_change)&&(i != x->x_on_old))
381 {
382 SETFLOAT(x->x_at, (float)x->x_on_old);
383 SETFLOAT(x->x_at+1, 0.0);
384 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
385 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
386 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
387 }
388 if(x->x_on != x->x_on_old)
389 x->x_on_old = x->x_on;
390 x->x_on = i;
391 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
392 x->x_on_old = x->x_on;
393 SETFLOAT(x->x_at, (float)x->x_on);
394 SETFLOAT(x->x_at+1, 1.0);
395 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
396 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
397 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
398 }
399 else
400 {
401 x->x_on_old = x->x_on;
402 x->x_on = i;
403 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
404 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
405 if (x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
406 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
407 }
408}
409
410static void vradio_float(t_vradio *x, t_floatarg f)
411{
412 int i=(int)f;
413
414 if(i < 0)
415 i = 0;
416 if(i >= x->x_number)
417 i = x->x_number-1;
418
419 if (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
420 {
421 /* compatibility with earlier "vdial" behavior */
422 if((x->x_change)&&(i != x->x_on_old))
423 {
424 if(x->x_gui.x_fsf.x_put_in2out)
425 {
426 SETFLOAT(x->x_at, (float)x->x_on_old);
427 SETFLOAT(x->x_at+1, 0.0);
428 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
429 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
430 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
431 }
432 }
433 if(x->x_on != x->x_on_old)
434 x->x_on_old = x->x_on;
435 x->x_on = i;
436 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
437 x->x_on_old = x->x_on;
438 if(x->x_gui.x_fsf.x_put_in2out)
439 {
440 SETFLOAT(x->x_at, (float)x->x_on);
441 SETFLOAT(x->x_at+1, 1.0);
442 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
443 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
444 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
445 }
446 }
447 else
448 {
449 x->x_on_old = x->x_on;
450 x->x_on = i;
451 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
452 if (x->x_gui.x_fsf.x_put_in2out)
453 {
454 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
455 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
456 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
457 }
458 }
459}
460
461static void vradio_click(t_vradio *x, t_floatarg xpos, t_floatarg ypos,
462 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
463{
464 int yy = (int)ypos - text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
465
466 vradio_fout(x, (float)(yy / x->x_gui.x_h));
467}
468
469static int vradio_newclick(t_gobj *z, struct _glist *glist,
470 int xpix, int ypix, int shift, int alt, int dbl, int doit)
471{
472 if(doit)
473 vradio_click((t_vradio *)z, (t_floatarg)xpix, (t_floatarg)ypix,
474 (t_floatarg)shift, 0, (t_floatarg)alt);
475 return (1);
476}
477
478static void vradio_loadbang(t_vradio *x)
479{
480 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
481 vradio_bang(x);
482}
483
484static void vradio_number(t_vradio *x, t_floatarg num)
485{
486 int n=(int)num;
487
488 if(n < 1)
489 n = 1;
490 if(n > IEM_RADIO_MAX)
491 n = IEM_RADIO_MAX;
492 if(n != x->x_number)
493 {
494 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
495 x->x_number = n;
496 if(x->x_on >= x->x_number)
497 x->x_on = x->x_number - 1;
498 x->x_on_old = x->x_on;
499 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
500 }
501}
502
503static void vradio_size(t_vradio *x, t_symbol *s, int ac, t_atom *av)
504{
505 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
506 x->x_gui.x_h = x->x_gui.x_w;
507 iemgui_size((void *)x, &x->x_gui);
508}
509
510static void vradio_delta(t_vradio *x, t_symbol *s, int ac, t_atom *av)
511{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
512
513static void vradio_pos(t_vradio *x, t_symbol *s, int ac, t_atom *av)
514{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
515
516static void vradio_color(t_vradio *x, t_symbol *s, int ac, t_atom *av)
517{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
518
519static void vradio_send(t_vradio *x, t_symbol *s)
520{iemgui_send(x, &x->x_gui, s);}
521
522static void vradio_receive(t_vradio *x, t_symbol *s)
523{iemgui_receive(x, &x->x_gui, s);}
524
525static void vradio_label(t_vradio *x, t_symbol *s)
526{iemgui_label((void *)x, &x->x_gui, s);}
527
528static void vradio_label_pos(t_vradio *x, t_symbol *s, int ac, t_atom *av)
529{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
530
531static void vradio_label_font(t_vradio *x, t_symbol *s, int ac, t_atom *av)
532{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
533
534static void vradio_init(t_vradio *x, t_floatarg f)
535{
536 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
537}
538
539static void vradio_double_change(t_vradio *x)
540{x->x_change = 1;}
541
542static void vradio_single_change(t_vradio *x)
543{x->x_change = 0;}
544
545static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old)
546{
547 t_vradio *x = (t_vradio *)pd_new(old? vradio_old_class : vradio_class);
548 int bflcol[]={-262144, -1, -1};
549 int a=IEM_GUI_DEFAULTSIZE, on=0, f=0;
550 int ldx=0, ldy=-6, chg=1, num=8;
551 int fs=8;
552 int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
553 char str[144];
554
555 if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
556 &&IS_A_FLOAT(argv,3)
557 &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
558 &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
559 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
560 &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
561 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
562 &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)&&IS_A_FLOAT(argv,14))
563 {
564 a = (int)atom_getintarg(0, argc, argv);
565 chg = (int)atom_getintarg(1, argc, argv);
566 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(2, argc, argv));
567 num = (int)atom_getintarg(3, argc, argv);
568 iemgui_new_getnames(&x->x_gui, 4, argv);
569 ldx = (int)atom_getintarg(7, argc, argv);
570 ldy = (int)atom_getintarg(8, argc, argv);
571 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv));
572 fs = (int)atom_getintarg(10, argc, argv);
573 bflcol[0] = (int)atom_getintarg(11, argc, argv);
574 bflcol[1] = (int)atom_getintarg(12, argc, argv);
575 bflcol[2] = (int)atom_getintarg(13, argc, argv);
576 on = (int)atom_getintarg(14, argc, argv);
577 }
578 else iemgui_new_getnames(&x->x_gui, 4, 0);
579 x->x_gui.x_draw = (t_iemfunptr)vradio_draw;
580 x->x_gui.x_fsf.x_snd_able = 1;
581 x->x_gui.x_fsf.x_rcv_able = 1;
582 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
583 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
584 x->x_gui.x_fsf.x_snd_able = 0;
585 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
586 x->x_gui.x_fsf.x_rcv_able = 0;
587 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
588 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
589 else { x->x_gui.x_fsf.x_font_style = 0;
590 strcpy(x->x_gui.x_font, "courier"); }
591 if(num < 1)
592 num = 1;
593 if(num > IEM_RADIO_MAX)
594 num = IEM_RADIO_MAX;
595 x->x_number = num;
596 if(on < 0)
597 on = 0;
598 if(on >= x->x_number)
599 on = x->x_number - 1;
600 if(x->x_gui.x_isa.x_loadinit)
601 x->x_on = on;
602 else
603 x->x_on = 0;
604 x->x_on_old = x->x_on;
605 x->x_change = (chg==0)?0:1;
606 if (x->x_gui.x_fsf.x_rcv_able)
607 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
608 x->x_gui.x_ldx = ldx;
609 x->x_gui.x_ldy = ldy;
610 if(fs < 4)
611 fs = 4;
612 x->x_gui.x_fontsize = fs;
613 x->x_gui.x_w = iemgui_clip_size(a);
614 x->x_gui.x_h = x->x_gui.x_w;
615 iemgui_verify_snd_ne_rcv(&x->x_gui);
616 iemgui_all_colfromload(&x->x_gui, bflcol);
617 outlet_new(&x->x_gui.x_obj, &s_list);
618 return (x);
619}
620
621static void *vradio_new(t_symbol *s, int argc, t_atom *argv)
622{
623 return (vradio_donew(s, argc, argv, 0));
624}
625
626static void *vdial_new(t_symbol *s, int argc, t_atom *argv)
627{
628 return (vradio_donew(s, argc, argv, 1));
629}
630
631static void vradio_ff(t_vradio *x)
632{
633 if(x->x_gui.x_fsf.x_rcv_able)
634 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
635 gfxstub_deleteforkey(x);
636}
637
638void g_vradio_setup(void)
639{
640 vradio_class = class_new(gensym("vradio"), (t_newmethod)vradio_new,
641 (t_method)vradio_ff, sizeof(t_vradio), 0, A_GIMME, 0);
642 class_addbang(vradio_class, vradio_bang);
643 class_addfloat(vradio_class, vradio_float);
644 class_addmethod(vradio_class, (t_method)vradio_click, gensym("click"),
645 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
646 class_addmethod(vradio_class, (t_method)vradio_dialog, gensym("dialog"),
647 A_GIMME, 0);
648 class_addmethod(vradio_class, (t_method)vradio_loadbang,
649 gensym("loadbang"), 0);
650 class_addmethod(vradio_class, (t_method)vradio_set,
651 gensym("set"), A_FLOAT, 0);
652 class_addmethod(vradio_class, (t_method)vradio_size,
653 gensym("size"), A_GIMME, 0);
654 class_addmethod(vradio_class, (t_method)vradio_delta,
655 gensym("delta"), A_GIMME, 0);
656 class_addmethod(vradio_class, (t_method)vradio_pos,
657 gensym("pos"), A_GIMME, 0);
658 class_addmethod(vradio_class, (t_method)vradio_color,
659 gensym("color"), A_GIMME, 0);
660 class_addmethod(vradio_class, (t_method)vradio_send,
661 gensym("send"), A_DEFSYM, 0);
662 class_addmethod(vradio_class, (t_method)vradio_receive,
663 gensym("receive"), A_DEFSYM, 0);
664 class_addmethod(vradio_class, (t_method)vradio_label,
665 gensym("label"), A_DEFSYM, 0);
666 class_addmethod(vradio_class, (t_method)vradio_label_pos,
667 gensym("label_pos"), A_GIMME, 0);
668 class_addmethod(vradio_class, (t_method)vradio_label_font,
669 gensym("label_font"), A_GIMME, 0);
670 class_addmethod(vradio_class, (t_method)vradio_init,
671 gensym("init"), A_FLOAT, 0);
672 class_addmethod(vradio_class, (t_method)vradio_number,
673 gensym("number"), A_FLOAT, 0);
674 class_addmethod(vradio_class, (t_method)vradio_single_change,
675 gensym("single_change"), 0);
676 class_addmethod(vradio_class, (t_method)vradio_double_change,
677 gensym("double_change"), 0);
678 vradio_widgetbehavior.w_getrectfn = vradio_getrect;
679 vradio_widgetbehavior.w_displacefn = iemgui_displace;
680 vradio_widgetbehavior.w_selectfn = iemgui_select;
681 vradio_widgetbehavior.w_activatefn = NULL;
682 vradio_widgetbehavior.w_deletefn = iemgui_delete;
683 vradio_widgetbehavior.w_visfn = iemgui_vis;
684 vradio_widgetbehavior.w_clickfn = vradio_newclick;
685 class_setwidget(vradio_class, &vradio_widgetbehavior);
686 class_sethelpsymbol(vradio_class, gensym("vradio"));
687 class_setsavefn(vradio_class, vradio_save);
688 class_setpropertiesfn(vradio_class, vradio_properties);
689
690 /* obsolete version (0.34-0.35) */
691 vradio_old_class = class_new(gensym("vdl"), (t_newmethod)vdial_new,
692 (t_method)vradio_ff, sizeof(t_vradio), 0, A_GIMME, 0);
693 class_addbang(vradio_old_class, vradio_bang);
694 class_addfloat(vradio_old_class, vradio_float);
695 class_addmethod(vradio_old_class, (t_method)vradio_click, gensym("click"),
696 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
697 class_addmethod(vradio_old_class, (t_method)vradio_dialog, gensym("dialog"),
698 A_GIMME, 0);
699 class_addmethod(vradio_old_class, (t_method)vradio_loadbang, gensym("loadbang"), 0);
700 class_addmethod(vradio_old_class, (t_method)vradio_set, gensym("set"), A_FLOAT, 0);
701 class_addmethod(vradio_old_class, (t_method)vradio_size, gensym("size"), A_GIMME, 0);
702 class_addmethod(vradio_old_class, (t_method)vradio_delta, gensym("delta"), A_GIMME, 0);
703 class_addmethod(vradio_old_class, (t_method)vradio_pos, gensym("pos"), A_GIMME, 0);
704 class_addmethod(vradio_old_class, (t_method)vradio_color, gensym("color"), A_GIMME, 0);
705 class_addmethod(vradio_old_class, (t_method)vradio_send, gensym("send"), A_DEFSYM, 0);
706 class_addmethod(vradio_old_class, (t_method)vradio_receive, gensym("receive"), A_DEFSYM, 0);
707 class_addmethod(vradio_old_class, (t_method)vradio_label, gensym("label"), A_DEFSYM, 0);
708 class_addmethod(vradio_old_class, (t_method)vradio_label_pos, gensym("label_pos"), A_GIMME, 0);
709 class_addmethod(vradio_old_class, (t_method)vradio_label_font, gensym("label_font"), A_GIMME, 0);
710 class_addmethod(vradio_old_class, (t_method)vradio_init, gensym("init"), A_FLOAT, 0);
711 class_addmethod(vradio_old_class, (t_method)vradio_number, gensym("number"), A_FLOAT, 0);
712 class_addmethod(vradio_old_class, (t_method)vradio_single_change, gensym("single_change"), 0);
713 class_addmethod(vradio_old_class, (t_method)vradio_double_change, gensym("double_change"), 0);
714 class_setwidget(vradio_old_class, &vradio_widgetbehavior);
715 class_sethelpsymbol(vradio_old_class, gensym("vradio"));
716}
717/* Copyright (c) 1997-1999 Miller Puckette.
718 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
719 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
720
721/* vdial.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
722
723/* name change to vradio by MSP (it's a radio button really) and changed to
724put out a "float" as in sliders, toggles, etc. */
725
726#include <stdlib.h>
727#include <string.h>
728#include <stdio.h>
729#include <ctype.h>
730#include "m_pd.h"
731#include "g_canvas.h"
732#include "t_tk.h"
733#include "g_all_guis.h"
734#include <math.h>
735
736/*------------------ global variables -------------------------*/
737
738
739/*------------------ global functions -------------------------*/
740
741
742
743
744/* ------------- vdl gui-vertical radio button ---------------------- */
745
746t_widgetbehavior vradio_widgetbehavior;
747static t_class *vradio_class, *vradio_old_class;
748
749/* widget helper functions */
750
751void vradio_draw_update(t_vradio *x, t_glist *glist)
752{
753 if(glist_isvisible(glist))
754 {
755 t_canvas *canvas=glist_getcanvas(glist);
756
757 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
758 canvas, x, x->x_on_old,
759 x->x_gui.x_bcol, x->x_gui.x_bcol);
760 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
761 canvas, x, x->x_on,
762 x->x_gui.x_fcol, x->x_gui.x_fcol);
763 }
764}
765
766void vradio_draw_new(t_vradio *x, t_glist *glist)
767{
768 t_canvas *canvas=glist_getcanvas(glist);
769 int n=x->x_number, i, dy=x->x_gui.x_h, s4=dy/4;
770 int yy11b=text_ypix(&x->x_gui.x_obj, glist);
771 int yy11=yy11b, yy12=yy11+dy;
772 int yy21=yy11+s4, yy22=yy12-s4;
773 int xx11=text_xpix(&x->x_gui.x_obj, glist), xx12=xx11+dy;
774 int xx21=xx11+s4, xx22=xx12-s4;
775
776 for(i=0; i<n; i++)
777 {
778 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE%d\n",
779 canvas, xx11, yy11, xx12, yy12,
780 x->x_gui.x_bcol, x, i);
781 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xBUT%d\n",
782 canvas, xx21, yy21, xx22, yy22,
783 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
784 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol, x, i);
785 yy11 += dy;
786 yy12 += dy;
787 yy21 += dy;
788 yy22 += dy;
789 }
790 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
791 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
792 canvas, xx11+x->x_gui.x_ldx, yy11b+x->x_gui.x_ldy,
793 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
794 x->x_gui.x_font, x->x_gui.x_fontsize,
795 x->x_gui.x_lcol, x);
796 if(!x->x_gui.x_fsf.x_snd_able)
797 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
798 canvas, xx11, yy11-1, xx11 + IOWIDTH, yy11, x, 0);
799 if(!x->x_gui.x_fsf.x_rcv_able)
800 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
801 canvas, xx11, yy11b, xx11 + IOWIDTH, yy11b+1, x, 0);
802}
803
804void vradio_draw_move(t_vradio *x, t_glist *glist)
805{
806 t_canvas *canvas=glist_getcanvas(glist);
807 int n=x->x_number, i, dy=x->x_gui.x_h, s4=dy/4;
808 int yy11b=text_ypix(&x->x_gui.x_obj, glist);
809 int yy11=yy11b, yy12=yy11+dy;
810 int yy21=yy11+s4, yy22=yy12-s4;
811 int xx11=text_xpix(&x->x_gui.x_obj, glist), xx12=xx11+dy;
812 int xx21=xx11+s4, xx22=xx12-s4;
813
814 for(i=0; i<n; i++)
815 {
816 sys_vgui(".x%x.c coords %xBASE%d %d %d %d %d\n",
817 canvas, x, i, xx11, yy11, xx12, yy12);
818 sys_vgui(".x%x.c coords %xBUT%d %d %d %d %d\n",
819 canvas, x, i, xx21, yy21, xx22, yy22);
820 yy11 += dy;
821 yy12 += dy;
822 yy21 += dy;
823 yy22 += dy;
824 }
825 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
826 canvas, x, xx11+x->x_gui.x_ldx, yy11b+x->x_gui.x_ldy);
827 if(!x->x_gui.x_fsf.x_snd_able)
828 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
829 canvas, x, 0, xx11, yy11-1, xx11 + IOWIDTH, yy11);
830 if(!x->x_gui.x_fsf.x_rcv_able)
831 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
832 canvas, x, 0, xx11, yy11b, xx11 + IOWIDTH, yy11b+1);
833}
834
835void vradio_draw_erase(t_vradio* x, t_glist* glist)
836{
837 t_canvas *canvas=glist_getcanvas(glist);
838 int n=x->x_number, i;
839
840 for(i=0; i<n; i++)
841 {
842 sys_vgui(".x%x.c delete %xBASE%d\n", canvas, x, i);
843 sys_vgui(".x%x.c delete %xBUT%d\n", canvas, x, i);
844 }
845 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
846 if(!x->x_gui.x_fsf.x_snd_able)
847 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
848 if(!x->x_gui.x_fsf.x_rcv_able)
849 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
850}
851
852void vradio_draw_config(t_vradio* x, t_glist* glist)
853{
854 t_canvas *canvas=glist_getcanvas(glist);
855 int n=x->x_number, i;
856
857 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
858 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
859 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
860 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
861 for(i=0; i<n; i++)
862 {
863 sys_vgui(".x%x.c itemconfigure %xBASE%d -fill #%6.6x\n", canvas, x, i,
864 x->x_gui.x_bcol);
865 sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n", canvas, x, i,
866 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
867 (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol);
868 }
869}
870
871void vradio_draw_io(t_vradio* x, t_glist* glist, int old_snd_rcv_flags)
872{
873 t_canvas *canvas=glist_getcanvas(glist);
874 int xpos=text_xpix(&x->x_gui.x_obj, glist);
875 int ypos=text_ypix(&x->x_gui.x_obj, glist);
876
877 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
878 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
879 canvas, xpos,
880 ypos+(x->x_number*x->x_gui.x_h)-1,
881 xpos+ IOWIDTH,
882 ypos+(x->x_number*x->x_gui.x_h), x, 0);
883 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
884 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
885 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
886 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
887 canvas, xpos, ypos,
888 xpos+ IOWIDTH, ypos+1,
889 x, 0);
890 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
891 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
892}
893
894void vradio_draw_select(t_vradio* x, t_glist* glist)
895{
896 t_canvas *canvas=glist_getcanvas(glist);
897 int n=x->x_number, i;
898
899 if(x->x_gui.x_fsf.x_selected)
900 {
901 for(i=0; i<n; i++)
902 {
903 sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
904 IEM_GUI_COLOR_SELECTED);
905 }
906 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
907 }
908 else
909 {
910 for(i=0; i<n; i++)
911 {
912 sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
913 IEM_GUI_COLOR_NORMAL);
914 }
915 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x,
916 x->x_gui.x_lcol);
917 }
918}
919
920void vradio_draw(t_vradio *x, t_glist *glist, int mode)
921{
922 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
923 vradio_draw_update(x, glist);
924 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
925 vradio_draw_move(x, glist);
926 else if(mode == IEM_GUI_DRAW_MODE_NEW)
927 vradio_draw_new(x, glist);
928 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
929 vradio_draw_select(x, glist);
930 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
931 vradio_draw_erase(x, glist);
932 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
933 vradio_draw_config(x, glist);
934 else if(mode >= IEM_GUI_DRAW_MODE_IO)
935 vradio_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
936}
937
938/* ------------------------ vdl widgetbehaviour----------------------------- */
939
940static void vradio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
941{
942 t_vradio *x = (t_vradio *)z;
943
944 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
945 *yp1 = text_ypix(&x->x_gui.x_obj, glist);
946 *xp2 = *xp1 + x->x_gui.x_w;
947 *yp2 = *yp1 + x->x_gui.x_h*x->x_number;
948}
949
950static void vradio_save(t_gobj *z, t_binbuf *b)
951{
952 t_vradio *x = (t_vradio *)z;
953 int bflcol[3];
954 t_symbol *srl[3];
955
956 iemgui_save(&x->x_gui, srl, bflcol);
957 binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"),
958 (t_int)x->x_gui.x_obj.te_xpix,
959 (t_int)x->x_gui.x_obj.te_ypix,
960 (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class ?
961 gensym("vdl") : gensym("vradio")),
962 x->x_gui.x_w,
963 x->x_change, iem_symargstoint(&x->x_gui.x_isa), x->x_number,
964 srl[0], srl[1], srl[2],
965 x->x_gui.x_ldx, x->x_gui.x_ldy,
966 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
967 bflcol[0], bflcol[1], bflcol[2], x->x_on);
968 binbuf_addv(b, ";");
969}
970
971static void vradio_properties(t_gobj *z, t_glist *owner)
972{
973 t_vradio *x = (t_vradio *)z;
974 char buf[800];
975 t_symbol *srl[3];
976 int hchange=-1;
977
978 iemgui_properties(&x->x_gui, srl);
979 if(pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
980 hchange = x->x_change;
981 sprintf(buf, "pdtk_iemgui_dialog %%s vradio \
982 ----------dimensions(pix):----------- %d %d size: 0 0 empty \
983 empty 0.0 empty 0.0 empty %d \
984 %d new-only new&old %d %d number: %d \
985 %s %s \
986 %s %d %d \
987 %d %d \
988 %d %d %d\n",
989 x->x_gui.x_w, IEM_GUI_MINSIZE,
990 0,/*no_schedule*/
991 hchange, x->x_gui.x_isa.x_loadinit, -1, x->x_number,
992 srl[0]->s_name, srl[1]->s_name,
993 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
994 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
995 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
996 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
997}
998
999static void vradio_dialog(t_vradio *x, t_symbol *s, int argc, t_atom *argv)
1000{
1001 t_symbol *srl[3];
1002 int a = (int)atom_getintarg(0, argc, argv);
1003 int chg = (int)atom_getintarg(4, argc, argv);
1004 int num = (int)atom_getintarg(6, argc, argv);
1005 int sr_flags;
1006
1007 if(chg != 0) chg = 1;
1008 x->x_change = chg;
1009 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
1010 x->x_gui.x_w = iemgui_clip_size(a);
1011 x->x_gui.x_h = x->x_gui.x_w;
1012 if(x->x_number != num)
1013 {
1014 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
1015 x->x_number = num;
1016 if(x->x_on >= x->x_number)
1017 {
1018 x->x_on = x->x_number - 1;
1019 x->x_on_old = x->x_on;
1020 }
1021 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
1022 }
1023 else
1024 {
1025 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
1026 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
1027 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
1028 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
1029 }
1030}
1031
1032static void vradio_set(t_vradio *x, t_floatarg f)
1033{
1034 int i=(int)f;
1035 int old;
1036
1037 if(i < 0)
1038 i = 0;
1039 if(i >= x->x_number)
1040 i = x->x_number-1;
1041 if(x->x_on != x->x_on_old)
1042 {
1043 old = x->x_on_old;
1044 x->x_on_old = x->x_on;
1045 x->x_on = i;
1046 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1047 x->x_on_old = old;
1048 }
1049 else
1050 {
1051 x->x_on = i;
1052 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1053 }
1054}
1055
1056static void vradio_bang(t_vradio *x)
1057{
1058 /* compatibility with earlier "vdial" behavior */
1059 if (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
1060 {
1061 if((x->x_change)&&(x->x_on != x->x_on_old))
1062 {
1063 SETFLOAT(x->x_at, (float)x->x_on_old);
1064 SETFLOAT(x->x_at+1, 0.0);
1065 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1066 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1067 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1068 }
1069 x->x_on_old = x->x_on;
1070 SETFLOAT(x->x_at, (float)x->x_on);
1071 SETFLOAT(x->x_at+1, 1.0);
1072 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1073 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1074 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1075 }
1076 else
1077 {
1078 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
1079 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1080 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
1081 }
1082}
1083
1084static void vradio_fout(t_vradio *x, t_floatarg f)
1085{
1086 int i=(int)f;
1087
1088 if(i < 0)
1089 i = 0;
1090 if(i >= x->x_number)
1091 i = x->x_number-1;
1092
1093 if (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
1094 {
1095 /* compatibility with earlier "vdial" behavior */
1096 if((x->x_change)&&(i != x->x_on_old))
1097 {
1098 SETFLOAT(x->x_at, (float)x->x_on_old);
1099 SETFLOAT(x->x_at+1, 0.0);
1100 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1101 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1102 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1103 }
1104 if(x->x_on != x->x_on_old)
1105 x->x_on_old = x->x_on;
1106 x->x_on = i;
1107 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1108 x->x_on_old = x->x_on;
1109 SETFLOAT(x->x_at, (float)x->x_on);
1110 SETFLOAT(x->x_at+1, 1.0);
1111 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1112 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1113 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1114 }
1115 else
1116 {
1117 x->x_on_old = x->x_on;
1118 x->x_on = i;
1119 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1120 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
1121 if (x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1122 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
1123 }
1124}
1125
1126static void vradio_float(t_vradio *x, t_floatarg f)
1127{
1128 int i=(int)f;
1129
1130 if(i < 0)
1131 i = 0;
1132 if(i >= x->x_number)
1133 i = x->x_number-1;
1134
1135 if (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
1136 {
1137 /* compatibility with earlier "vdial" behavior */
1138 if((x->x_change)&&(i != x->x_on_old))
1139 {
1140 if(x->x_gui.x_fsf.x_put_in2out)
1141 {
1142 SETFLOAT(x->x_at, (float)x->x_on_old);
1143 SETFLOAT(x->x_at+1, 0.0);
1144 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1145 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1146 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1147 }
1148 }
1149 if(x->x_on != x->x_on_old)
1150 x->x_on_old = x->x_on;
1151 x->x_on = i;
1152 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1153 x->x_on_old = x->x_on;
1154 if(x->x_gui.x_fsf.x_put_in2out)
1155 {
1156 SETFLOAT(x->x_at, (float)x->x_on);
1157 SETFLOAT(x->x_at+1, 1.0);
1158 outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
1159 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1160 pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
1161 }
1162 }
1163 else
1164 {
1165 x->x_on_old = x->x_on;
1166 x->x_on = i;
1167 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1168 if (x->x_gui.x_fsf.x_put_in2out)
1169 {
1170 outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
1171 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
1172 pd_float(x->x_gui.x_snd->s_thing, x->x_on);
1173 }
1174 }
1175}
1176
1177static void vradio_click(t_vradio *x, t_floatarg xpos, t_floatarg ypos,
1178 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
1179{
1180 int yy = (int)ypos - text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
1181
1182 vradio_fout(x, (float)(yy / x->x_gui.x_h));
1183}
1184
1185static int vradio_newclick(t_gobj *z, struct _glist *glist,
1186 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1187{
1188 if(doit)
1189 vradio_click((t_vradio *)z, (t_floatarg)xpix, (t_floatarg)ypix,
1190 (t_floatarg)shift, 0, (t_floatarg)alt);
1191 return (1);
1192}
1193
1194static void vradio_loadbang(t_vradio *x)
1195{
1196 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
1197 vradio_bang(x);
1198}
1199
1200static void vradio_number(t_vradio *x, t_floatarg num)
1201{
1202 int n=(int)num;
1203
1204 if(n < 1)
1205 n = 1;
1206 if(n > IEM_RADIO_MAX)
1207 n = IEM_RADIO_MAX;
1208 if(n != x->x_number)
1209 {
1210 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
1211 x->x_number = n;
1212 if(x->x_on >= x->x_number)
1213 x->x_on = x->x_number - 1;
1214 x->x_on_old = x->x_on;
1215 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
1216 }
1217}
1218
1219static void vradio_size(t_vradio *x, t_symbol *s, int ac, t_atom *av)
1220{
1221 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
1222 x->x_gui.x_h = x->x_gui.x_w;
1223 iemgui_size((void *)x, &x->x_gui);
1224}
1225
1226static void vradio_delta(t_vradio *x, t_symbol *s, int ac, t_atom *av)
1227{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
1228
1229static void vradio_pos(t_vradio *x, t_symbol *s, int ac, t_atom *av)
1230{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
1231
1232static void vradio_color(t_vradio *x, t_symbol *s, int ac, t_atom *av)
1233{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
1234
1235static void vradio_send(t_vradio *x, t_symbol *s)
1236{iemgui_send(x, &x->x_gui, s);}
1237
1238static void vradio_receive(t_vradio *x, t_symbol *s)
1239{iemgui_receive(x, &x->x_gui, s);}
1240
1241static void vradio_label(t_vradio *x, t_symbol *s)
1242{iemgui_label((void *)x, &x->x_gui, s);}
1243
1244static void vradio_label_pos(t_vradio *x, t_symbol *s, int ac, t_atom *av)
1245{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
1246
1247static void vradio_label_font(t_vradio *x, t_symbol *s, int ac, t_atom *av)
1248{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
1249
1250static void vradio_init(t_vradio *x, t_floatarg f)
1251{
1252 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
1253}
1254
1255static void vradio_double_change(t_vradio *x)
1256{x->x_change = 1;}
1257
1258static void vradio_single_change(t_vradio *x)
1259{x->x_change = 0;}
1260
1261static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old)
1262{
1263 t_vradio *x = (t_vradio *)pd_new(old? vradio_old_class : vradio_class);
1264 int bflcol[]={-262144, -1, -1};
1265 int a=IEM_GUI_DEFAULTSIZE, on=0, f=0;
1266 int ldx=0, ldy=-6, chg=1, num=8;
1267 int fs=8;
1268 int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
1269 char str[144];
1270
1271 if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
1272 &&IS_A_FLOAT(argv,3)
1273 &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
1274 &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
1275 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
1276 &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
1277 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
1278 &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)&&IS_A_FLOAT(argv,14))
1279 {
1280 a = (int)atom_getintarg(0, argc, argv);
1281 chg = (int)atom_getintarg(1, argc, argv);
1282 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(2, argc, argv));
1283 num = (int)atom_getintarg(3, argc, argv);
1284 iemgui_new_getnames(&x->x_gui, 4, argv);
1285 ldx = (int)atom_getintarg(7, argc, argv);
1286 ldy = (int)atom_getintarg(8, argc, argv);
1287 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv));
1288 fs = (int)atom_getintarg(10, argc, argv);
1289 bflcol[0] = (int)atom_getintarg(11, argc, argv);
1290 bflcol[1] = (int)atom_getintarg(12, argc, argv);
1291 bflcol[2] = (int)atom_getintarg(13, argc, argv);
1292 on = (int)atom_getintarg(14, argc, argv);
1293 }
1294 else iemgui_new_getnames(&x->x_gui, 4, 0);
1295 x->x_gui.x_draw = (t_iemfunptr)vradio_draw;
1296 x->x_gui.x_fsf.x_snd_able = 1;
1297 x->x_gui.x_fsf.x_rcv_able = 1;
1298 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
1299 if (!strcmp(x->x_gui.x_snd->s_name, "empty"))
1300 x->x_gui.x_fsf.x_snd_able = 0;
1301 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
1302 x->x_gui.x_fsf.x_rcv_able = 0;
1303 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
1304 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
1305 else { x->x_gui.x_fsf.x_font_style = 0;
1306 strcpy(x->x_gui.x_font, "courier"); }
1307 if(num < 1)
1308 num = 1;
1309 if(num > IEM_RADIO_MAX)
1310 num = IEM_RADIO_MAX;
1311 x->x_number = num;
1312 if(on < 0)
1313 on = 0;
1314 if(on >= x->x_number)
1315 on = x->x_number - 1;
1316 if(x->x_gui.x_isa.x_loadinit)
1317 x->x_on = on;
1318 else
1319 x->x_on = 0;
1320 x->x_on_old = x->x_on;
1321 x->x_change = (chg==0)?0:1;
1322 if (x->x_gui.x_fsf.x_rcv_able)
1323 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1324 x->x_gui.x_ldx = ldx;
1325 x->x_gui.x_ldy = ldy;
1326 if(fs < 4)
1327 fs = 4;
1328 x->x_gui.x_fontsize = fs;
1329 x->x_gui.x_w = iemgui_clip_size(a);
1330 x->x_gui.x_h = x->x_gui.x_w;
1331 iemgui_verify_snd_ne_rcv(&x->x_gui);
1332 iemgui_all_colfromload(&x->x_gui, bflcol);
1333 outlet_new(&x->x_gui.x_obj, &s_list);
1334 return (x);
1335}
1336
1337static void *vradio_new(t_symbol *s, int argc, t_atom *argv)
1338{
1339 return (vradio_donew(s, argc, argv, 0));
1340}
1341
1342static void *vdial_new(t_symbol *s, int argc, t_atom *argv)
1343{
1344 return (vradio_donew(s, argc, argv, 1));
1345}
1346
1347static void vradio_ff(t_vradio *x)
1348{
1349 if(x->x_gui.x_fsf.x_rcv_able)
1350 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1351 gfxstub_deleteforkey(x);
1352}
1353
1354void g_vradio_setup(void)
1355{
1356 vradio_class = class_new(gensym("vradio"), (t_newmethod)vradio_new,
1357 (t_method)vradio_ff, sizeof(t_vradio), 0, A_GIMME, 0);
1358 class_addbang(vradio_class, vradio_bang);
1359 class_addfloat(vradio_class, vradio_float);
1360 class_addmethod(vradio_class, (t_method)vradio_click, gensym("click"),
1361 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1362 class_addmethod(vradio_class, (t_method)vradio_dialog, gensym("dialog"),
1363 A_GIMME, 0);
1364 class_addmethod(vradio_class, (t_method)vradio_loadbang,
1365 gensym("loadbang"), 0);
1366 class_addmethod(vradio_class, (t_method)vradio_set,
1367 gensym("set"), A_FLOAT, 0);
1368 class_addmethod(vradio_class, (t_method)vradio_size,
1369 gensym("size"), A_GIMME, 0);
1370 class_addmethod(vradio_class, (t_method)vradio_delta,
1371 gensym("delta"), A_GIMME, 0);
1372 class_addmethod(vradio_class, (t_method)vradio_pos,
1373 gensym("pos"), A_GIMME, 0);
1374 class_addmethod(vradio_class, (t_method)vradio_color,
1375 gensym("color"), A_GIMME, 0);
1376 class_addmethod(vradio_class, (t_method)vradio_send,
1377 gensym("send"), A_DEFSYM, 0);
1378 class_addmethod(vradio_class, (t_method)vradio_receive,
1379 gensym("receive"), A_DEFSYM, 0);
1380 class_addmethod(vradio_class, (t_method)vradio_label,
1381 gensym("label"), A_DEFSYM, 0);
1382 class_addmethod(vradio_class, (t_method)vradio_label_pos,
1383 gensym("label_pos"), A_GIMME, 0);
1384 class_addmethod(vradio_class, (t_method)vradio_label_font,
1385 gensym("label_font"), A_GIMME, 0);
1386 class_addmethod(vradio_class, (t_method)vradio_init,
1387 gensym("init"), A_FLOAT, 0);
1388 class_addmethod(vradio_class, (t_method)vradio_number,
1389 gensym("number"), A_FLOAT, 0);
1390 class_addmethod(vradio_class, (t_method)vradio_single_change,
1391 gensym("single_change"), 0);
1392 class_addmethod(vradio_class, (t_method)vradio_double_change,
1393 gensym("double_change"), 0);
1394 vradio_widgetbehavior.w_getrectfn = vradio_getrect;
1395 vradio_widgetbehavior.w_displacefn = iemgui_displace;
1396 vradio_widgetbehavior.w_selectfn = iemgui_select;
1397 vradio_widgetbehavior.w_activatefn = NULL;
1398 vradio_widgetbehavior.w_deletefn = iemgui_delete;
1399 vradio_widgetbehavior.w_visfn = iemgui_vis;
1400 vradio_widgetbehavior.w_clickfn = vradio_newclick;
1401 class_setwidget(vradio_class, &vradio_widgetbehavior);
1402 class_sethelpsymbol(vradio_class, gensym("vradio"));
1403 class_setsavefn(vradio_class, vradio_save);
1404 class_setpropertiesfn(vradio_class, vradio_properties);
1405
1406 /* obsolete version (0.34-0.35) */
1407 vradio_old_class = class_new(gensym("vdl"), (t_newmethod)vdial_new,
1408 (t_method)vradio_ff, sizeof(t_vradio), 0, A_GIMME, 0);
1409 class_addbang(vradio_old_class, vradio_bang);
1410 class_addfloat(vradio_old_class, vradio_float);
1411 class_addmethod(vradio_old_class, (t_method)vradio_click, gensym("click"),
1412 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1413 class_addmethod(vradio_old_class, (t_method)vradio_dialog, gensym("dialog"),
1414 A_GIMME, 0);
1415 class_addmethod(vradio_old_class, (t_method)vradio_loadbang, gensym("loadbang"), 0);
1416 class_addmethod(vradio_old_class, (t_method)vradio_set, gensym("set"), A_FLOAT, 0);
1417 class_addmethod(vradio_old_class, (t_method)vradio_size, gensym("size"), A_GIMME, 0);
1418 class_addmethod(vradio_old_class, (t_method)vradio_delta, gensym("delta"), A_GIMME, 0);
1419 class_addmethod(vradio_old_class, (t_method)vradio_pos, gensym("pos"), A_GIMME, 0);
1420 class_addmethod(vradio_old_class, (t_method)vradio_color, gensym("color"), A_GIMME, 0);
1421 class_addmethod(vradio_old_class, (t_method)vradio_send, gensym("send"), A_DEFSYM, 0);
1422 class_addmethod(vradio_old_class, (t_method)vradio_receive, gensym("receive"), A_DEFSYM, 0);
1423 class_addmethod(vradio_old_class, (t_method)vradio_label, gensym("label"), A_DEFSYM, 0);
1424 class_addmethod(vradio_old_class, (t_method)vradio_label_pos, gensym("label_pos"), A_GIMME, 0);
1425 class_addmethod(vradio_old_class, (t_method)vradio_label_font, gensym("label_font"), A_GIMME, 0);
1426 class_addmethod(vradio_old_class, (t_method)vradio_init, gensym("init"), A_FLOAT, 0);
1427 class_addmethod(vradio_old_class, (t_method)vradio_number, gensym("number"), A_FLOAT, 0);
1428 class_addmethod(vradio_old_class, (t_method)vradio_single_change, gensym("single_change"), 0);
1429 class_addmethod(vradio_old_class, (t_method)vradio_double_change, gensym("double_change"), 0);
1430 class_setwidget(vradio_old_class, &vradio_widgetbehavior);
1431 class_sethelpsymbol(vradio_old_class, gensym("vradio"));
1432}
diff --git a/apps/plugins/pdbox/PDa/src/g_vslider.c b/apps/plugins/pdbox/PDa/src/g_vslider.c
new file mode 100644
index 0000000000..8e2e326f30
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_vslider.c
@@ -0,0 +1,1254 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
7
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <ctype.h>
13#include "m_pd.h"
14#include "g_canvas.h"
15#include "t_tk.h"
16#include "g_all_guis.h"
17#include <math.h>
18
19#ifdef MSW
20#include <io.h>
21#else
22#include <unistd.h>
23#endif
24
25
26/* ------------ vsl gui-vertical slider ----------------------- */
27
28t_widgetbehavior vslider_widgetbehavior;
29static t_class *vslider_class;
30
31/* widget helper functions */
32
33static void vslider_draw_update(t_vslider *x, t_glist *glist)
34{
35 if (glist_isvisible(glist))
36 {
37 int r = text_ypix(&x->x_gui.x_obj, glist) + x->x_gui.x_h - (x->x_val + 50)/100;
38 int xpos=text_xpix(&x->x_gui.x_obj, glist);
39
40 sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
41 glist_getcanvas(glist), x, xpos+1, r,
42 xpos + x->x_gui.x_w, r);
43 }
44}
45
46static void vslider_draw_new(t_vslider *x, t_glist *glist)
47{
48 int xpos=text_xpix(&x->x_gui.x_obj, glist);
49 int ypos=text_ypix(&x->x_gui.x_obj, glist);
50 int r = ypos + x->x_gui.x_h - (x->x_val + 50)/100;
51 t_canvas *canvas=glist_getcanvas(glist);
52
53 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
54 canvas, xpos, ypos-2,
55 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h+3,
56 x->x_gui.x_bcol, x);
57 sys_vgui(".x%x.c create line %d %d %d %d -width 3 -fill #%6.6x -tags %xKNOB\n",
58 canvas, xpos+1, r,
59 xpos + x->x_gui.x_w, r, x->x_gui.x_fcol, x);
60 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
61 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
62 canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
63 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
64 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
65 if(!x->x_gui.x_fsf.x_snd_able)
66 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
67 canvas,
68 xpos, ypos + x->x_gui.x_h+2,
69 xpos+7, ypos + x->x_gui.x_h+3,
70 x, 0);
71 if(!x->x_gui.x_fsf.x_rcv_able)
72 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
73 canvas,
74 xpos, ypos-2,
75 xpos+7, ypos-1,
76 x, 0);
77}
78
79static void vslider_draw_move(t_vslider *x, t_glist *glist)
80{
81 int xpos=text_xpix(&x->x_gui.x_obj, glist);
82 int ypos=text_ypix(&x->x_gui.x_obj, glist);
83 int r = ypos + x->x_gui.x_h - (x->x_val + 50)/100;
84 t_canvas *canvas=glist_getcanvas(glist);
85
86 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
87 canvas, x,
88 xpos, ypos-2,
89 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h+3);
90 sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
91 canvas, x, xpos+1, r,
92 xpos + x->x_gui.x_w, r);
93 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
94 canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
95 if(!x->x_gui.x_fsf.x_snd_able)
96 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
97 canvas, x, 0,
98 xpos, ypos + x->x_gui.x_h+2,
99 xpos+7, ypos + x->x_gui.x_h+3);
100 if(!x->x_gui.x_fsf.x_rcv_able)
101 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
102 canvas, x, 0,
103 xpos, ypos-2,
104 xpos+7, ypos-1);
105}
106
107static void vslider_draw_erase(t_vslider* x,t_glist* glist)
108{
109 t_canvas *canvas=glist_getcanvas(glist);
110
111 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
112 sys_vgui(".x%x.c delete %xKNOB\n", canvas, x);
113 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
114 if(!x->x_gui.x_fsf.x_snd_able)
115 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
116 if(!x->x_gui.x_fsf.x_rcv_able)
117 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
118}
119
120static void vslider_draw_config(t_vslider* x,t_glist* glist)
121{
122 t_canvas *canvas=glist_getcanvas(glist);
123
124 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
125 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
126 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
127 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
128 sys_vgui(".x%x.c itemconfigure %xKNOB -fill #%6.6x\n", canvas,
129 x, x->x_gui.x_fcol);
130 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas,
131 x, x->x_gui.x_bcol);
132}
133
134static void vslider_draw_io(t_vslider* x,t_glist* glist, int old_snd_rcv_flags)
135{
136 int xpos=text_xpix(&x->x_gui.x_obj, glist);
137 int ypos=text_ypix(&x->x_gui.x_obj, glist);
138 t_canvas *canvas=glist_getcanvas(glist);
139
140 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
141 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
142 canvas,
143 xpos, ypos + x->x_gui.x_h+2,
144 xpos+7, ypos + x->x_gui.x_h+3,
145 x, 0);
146 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
147 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
148 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
149 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
150 canvas,
151 xpos, ypos-2,
152 xpos+7, ypos-1,
153 x, 0);
154 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
155 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
156}
157
158static void vslider_draw_select(t_vslider *x, t_glist *glist)
159{
160 t_canvas *canvas=glist_getcanvas(glist);
161
162 if(x->x_gui.x_fsf.x_selected)
163 {
164 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
165 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
166 }
167 else
168 {
169 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
170 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
171 }
172}
173
174void vslider_draw(t_vslider *x, t_glist *glist, int mode)
175{
176 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
177 vslider_draw_update(x, glist);
178 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
179 vslider_draw_move(x, glist);
180 else if(mode == IEM_GUI_DRAW_MODE_NEW)
181 vslider_draw_new(x, glist);
182 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
183 vslider_draw_select(x, glist);
184 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
185 vslider_draw_erase(x, glist);
186 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
187 vslider_draw_config(x, glist);
188 else if(mode >= IEM_GUI_DRAW_MODE_IO)
189 vslider_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
190}
191
192/* ------------------------ vsl widgetbehaviour----------------------------- */
193
194
195static void vslider_getrect(t_gobj *z, t_glist *glist,
196 int *xp1, int *yp1, int *xp2, int *yp2)
197{
198 t_vslider* x = (t_vslider*)z;
199
200 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
201 *yp1 = text_ypix(&x->x_gui.x_obj, glist) - 2;
202 *xp2 = *xp1 + x->x_gui.x_w;
203 *yp2 = *yp1 + x->x_gui.x_h + 5;
204}
205
206static void vslider_save(t_gobj *z, t_binbuf *b)
207{
208 t_vslider *x = (t_vslider *)z;
209 int bflcol[3];
210 t_symbol *srl[3];
211
212 iemgui_save(&x->x_gui, srl, bflcol);
213 binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
214 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
215 gensym("vsl"), x->x_gui.x_w, x->x_gui.x_h,
216 (float)x->x_min, (float)x->x_max,
217 x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa),
218 srl[0], srl[1], srl[2],
219 x->x_gui.x_ldx, x->x_gui.x_ldy,
220 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
221 bflcol[0], bflcol[1], bflcol[2],
222 x->x_val, x->x_steady);
223 binbuf_addv(b, ";");
224}
225
226void vslider_check_height(t_vslider *x, int h)
227{
228 if(h < IEM_SL_MINSIZE)
229 h = IEM_SL_MINSIZE;
230 x->x_gui.x_h = h;
231 if(x->x_val > (x->x_gui.x_h*100 - 100))
232 {
233 x->x_pos = x->x_gui.x_h*100 - 100;
234 x->x_val = x->x_pos;
235 }
236 if(x->x_lin0_log1)
237 x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_h - 1);
238 else
239 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
240}
241
242void vslider_check_minmax(t_vslider *x, double min, double max)
243{
244 if(x->x_lin0_log1)
245 {
246 if((min == 0.0)&&(max == 0.0))
247 max = 1.0;
248 if(max > 0.0)
249 {
250 if(min <= 0.0)
251 min = 0.01*max;
252 }
253 else
254 {
255 if(min > 0.0)
256 max = 0.01*min;
257 }
258 }
259 x->x_min = min;
260 x->x_max = max;
261 if(x->x_min > x->x_max) /* bugfix */
262 x->x_gui.x_isa.x_reverse = 1;
263 else
264 x->x_gui.x_isa.x_reverse = 0;
265 if(x->x_lin0_log1)
266 x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_h - 1);
267 else
268 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
269}
270
271static void vslider_properties(t_gobj *z, t_glist *owner)
272{
273 t_vslider *x = (t_vslider *)z;
274 char buf[800];
275 t_symbol *srl[3];
276
277 iemgui_properties(&x->x_gui, srl);
278
279 sprintf(buf, "pdtk_iemgui_dialog %%s VSLIDER \
280 --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
281 -----------output-range:----------- %g bottom: %g top: %d \
282 %d lin log %d %d empty %d \
283 %s %s \
284 %s %d %d \
285 %d %d \
286 %d %d %d\n",
287 x->x_gui.x_w, IEM_GUI_MINSIZE, x->x_gui.x_h, IEM_SL_MINSIZE,
288 x->x_min, x->x_max, 0,/*no_schedule*/
289 x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
290 srl[0]->s_name, srl[1]->s_name,
291 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
292 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
293 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
294 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
295}
296
297static void vslider_bang(t_vslider *x)
298{
299 double out;
300
301 if(x->x_lin0_log1)
302 out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
303 else
304 out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
305 if((out < 1.0e-10)&&(out > -1.0e-10))
306 out = 0.0;
307
308 outlet_float(x->x_gui.x_obj.ob_outlet, out);
309 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
310 pd_float(x->x_gui.x_snd->s_thing, out);
311}
312
313static void vslider_dialog(t_vslider *x, t_symbol *s, int argc, t_atom *argv)
314{
315 t_symbol *srl[3];
316 int w = (int)atom_getintarg(0, argc, argv);
317 int h = (int)atom_getintarg(1, argc, argv);
318 double min = (double)atom_getfloatarg(2, argc, argv);
319 double max = (double)atom_getfloatarg(3, argc, argv);
320 int lilo = (int)atom_getintarg(4, argc, argv);
321 int steady = (int)atom_getintarg(17, argc, argv);
322 int sr_flags;
323
324 if(lilo != 0) lilo = 1;
325 x->x_lin0_log1 = lilo;
326 if(steady)
327 x->x_steady = 1;
328 else
329 x->x_steady = 0;
330 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
331 x->x_gui.x_w = iemgui_clip_size(w);
332 vslider_check_height(x, h);
333 vslider_check_minmax(x, min, max);
334 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
335 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
336 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
337 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
338}
339
340static void vslider_motion(t_vslider *x, t_floatarg dx, t_floatarg dy)
341{
342 int old = x->x_val;
343
344 if(x->x_gui.x_fsf.x_finemoved)
345 x->x_pos -= (int)dy;
346 else
347 x->x_pos -= 100*(int)dy;
348 x->x_val = x->x_pos;
349 if(x->x_val > (100*x->x_gui.x_h - 100))
350 {
351 x->x_val = 100*x->x_gui.x_h - 100;
352 x->x_pos += 50;
353 x->x_pos -= x->x_pos%100;
354 }
355 if(x->x_val < 0)
356 {
357 x->x_val = 0;
358 x->x_pos -= 50;
359 x->x_pos -= x->x_pos%100;
360 }
361 if(old != x->x_val)
362 {
363 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
364 vslider_bang(x);
365 }
366}
367
368static void vslider_click(t_vslider *x, t_floatarg xpos, t_floatarg ypos,
369 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
370{
371 if(!x->x_steady)
372 x->x_val = (int)(100.0 * (x->x_gui.x_h + text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist) - ypos));
373 if(x->x_val > (100*x->x_gui.x_h - 100))
374 x->x_val = 100*x->x_gui.x_h - 100;
375 if(x->x_val < 0)
376 x->x_val = 0;
377 x->x_pos = x->x_val;
378 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
379 vslider_bang(x);
380 glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
381 (t_glistmotionfn)vslider_motion, 0, xpos, ypos);
382}
383
384static int vslider_newclick(t_gobj *z, struct _glist *glist,
385 int xpix, int ypix, int shift, int alt, int dbl, int doit)
386{
387 t_vslider* x = (t_vslider *)z;
388
389 if(doit)
390 {
391 vslider_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
392 0, (t_floatarg)alt);
393 if(shift)
394 x->x_gui.x_fsf.x_finemoved = 1;
395 else
396 x->x_gui.x_fsf.x_finemoved = 0;
397 }
398 return (1);
399}
400
401static void vslider_set(t_vslider *x, t_floatarg f)
402{
403 double g;
404
405 if(x->x_gui.x_isa.x_reverse) /* bugfix */
406 {
407 if(f > x->x_min)
408 f = x->x_min;
409 if(f < x->x_max)
410 f = x->x_max;
411 }
412 else
413 {
414 if(f > x->x_max)
415 f = x->x_max;
416 if(f < x->x_min)
417 f = x->x_min;
418 }
419 if(x->x_lin0_log1)
420 g = log(f/x->x_min)/x->x_k;
421 else
422 g = (f - x->x_min) / x->x_k;
423 x->x_val = (int)(100.0*g + 0.49999);
424 x->x_pos = x->x_val;
425 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
426}
427
428static void vslider_float(t_vslider *x, t_floatarg f)
429{
430 vslider_set(x, f);
431 if(x->x_gui.x_fsf.x_put_in2out)
432 vslider_bang(x);
433}
434
435static void vslider_size(t_vslider *x, t_symbol *s, int ac, t_atom *av)
436{
437 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
438 if(ac > 1)
439 vslider_check_height(x, (int)atom_getintarg(1, ac, av));
440 iemgui_size((void *)x, &x->x_gui);
441}
442
443static void vslider_delta(t_vslider *x, t_symbol *s, int ac, t_atom *av)
444{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
445
446static void vslider_pos(t_vslider *x, t_symbol *s, int ac, t_atom *av)
447{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
448
449static void vslider_range(t_vslider *x, t_symbol *s, int ac, t_atom *av)
450{
451 vslider_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
452 (double)atom_getfloatarg(1, ac, av));
453}
454
455static void vslider_color(t_vslider *x, t_symbol *s, int ac, t_atom *av)
456{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
457
458static void vslider_send(t_vslider *x, t_symbol *s)
459{iemgui_send(x, &x->x_gui, s);}
460
461static void vslider_receive(t_vslider *x, t_symbol *s)
462{iemgui_receive(x, &x->x_gui, s);}
463
464static void vslider_label(t_vslider *x, t_symbol *s)
465{iemgui_label((void *)x, &x->x_gui, s);}
466
467static void vslider_label_pos(t_vslider *x, t_symbol *s, int ac, t_atom *av)
468{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
469
470static void vslider_label_font(t_vslider *x, t_symbol *s, int ac, t_atom *av)
471{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
472
473static void vslider_log(t_vslider *x)
474{
475 x->x_lin0_log1 = 1;
476 vslider_check_minmax(x, x->x_min, x->x_max);
477}
478
479static void vslider_lin(t_vslider *x)
480{
481 x->x_lin0_log1 = 0;
482 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
483}
484
485static void vslider_init(t_vslider *x, t_floatarg f)
486{
487 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
488}
489
490static void vslider_steady(t_vslider *x, t_floatarg f)
491{
492 x->x_steady = (f==0.0)?0:1;
493}
494
495static void vslider_loadbang(t_vslider *x)
496{
497 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
498 {
499 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
500 vslider_bang(x);
501 }
502}
503
504static void *vslider_new(t_symbol *s, int argc, t_atom *argv)
505{
506 t_vslider *x = (t_vslider *)pd_new(vslider_class);
507 int bflcol[]={-262144, -1, -1};
508 int w=IEM_GUI_DEFAULTSIZE, h=IEM_SL_DEFAULTSIZE;
509 int lilo=0, f=0, ldx=0, ldy=-8;
510 int fs=8, v=0, steady=1;
511 double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
512 char str[144];
513
514 iem_inttosymargs(&x->x_gui.x_isa, 0);
515 iem_inttofstyle(&x->x_gui.x_fsf, 0);
516
517 if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
518 &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
519 &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
520 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
521 &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
522 &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
523 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
524 &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
525 &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
526 {
527 w = (int)atom_getintarg(0, argc, argv);
528 h = (int)atom_getintarg(1, argc, argv);
529 min = (double)atom_getfloatarg(2, argc, argv);
530 max = (double)atom_getfloatarg(3, argc, argv);
531 lilo = (int)atom_getintarg(4, argc, argv);
532 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
533 iemgui_new_getnames(&x->x_gui, 6, argv);
534 ldx = (int)atom_getintarg(9, argc, argv);
535 ldy = (int)atom_getintarg(10, argc, argv);
536 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
537 fs = (int)atom_getintarg(12, argc, argv);
538 bflcol[0] = (int)atom_getintarg(13, argc, argv);
539 bflcol[1] = (int)atom_getintarg(14, argc, argv);
540 bflcol[2] = (int)atom_getintarg(15, argc, argv);
541 v = (int)atom_getintarg(16, argc, argv);
542 }
543 else iemgui_new_getnames(&x->x_gui, 6, 0);
544 if((argc == 18)&&IS_A_FLOAT(argv,17))
545 steady = (int)atom_getintarg(17, argc, argv);
546 x->x_gui.x_draw = (t_iemfunptr)vslider_draw;
547 x->x_gui.x_fsf.x_snd_able = 1;
548 x->x_gui.x_fsf.x_rcv_able = 1;
549 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
550 if(x->x_gui.x_isa.x_loadinit)
551 x->x_val = v;
552 else
553 x->x_val = 0;
554 x->x_pos = x->x_val;
555 if(lilo != 0) lilo = 1;
556 x->x_lin0_log1 = lilo;
557 if(steady != 0) steady = 1;
558 x->x_steady = steady;
559 if(!strcmp(x->x_gui.x_snd->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0;
560 if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0;
561 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
562 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
563 else { x->x_gui.x_fsf.x_font_style = 0;
564 strcpy(x->x_gui.x_font, "courier"); }
565 if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
566 x->x_gui.x_ldx = ldx;
567 x->x_gui.x_ldy = ldy;
568 if(fs < 4)
569 fs = 4;
570 x->x_gui.x_fontsize = fs;
571 x->x_gui.x_w = iemgui_clip_size(w);
572 vslider_check_height(x, h);
573 vslider_check_minmax(x, min, max);
574 iemgui_all_colfromload(&x->x_gui, bflcol);
575 iemgui_verify_snd_ne_rcv(&x->x_gui);
576 outlet_new(&x->x_gui.x_obj, &s_float);
577 return (x);
578}
579
580static void vslider_free(t_vslider *x)
581{
582 if(x->x_gui.x_fsf.x_rcv_able)
583 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
584 gfxstub_deleteforkey(x);
585}
586
587void g_vslider_setup(void)
588{
589 vslider_class = class_new(gensym("vsl"), (t_newmethod)vslider_new,
590 (t_method)vslider_free, sizeof(t_vslider), 0, A_GIMME, 0);
591 class_addcreator((t_newmethod)vslider_new, gensym("vslider"), A_GIMME, 0);
592 class_addbang(vslider_class,vslider_bang);
593 class_addfloat(vslider_class,vslider_float);
594 class_addmethod(vslider_class, (t_method)vslider_click, gensym("click"),
595 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
596 class_addmethod(vslider_class, (t_method)vslider_motion, gensym("motion"),
597 A_FLOAT, A_FLOAT, 0);
598 class_addmethod(vslider_class, (t_method)vslider_dialog, gensym("dialog"),
599 A_GIMME, 0);
600 class_addmethod(vslider_class, (t_method)vslider_loadbang, gensym("loadbang"), 0);
601 class_addmethod(vslider_class, (t_method)vslider_set, gensym("set"), A_FLOAT, 0);
602 class_addmethod(vslider_class, (t_method)vslider_size, gensym("size"), A_GIMME, 0);
603 class_addmethod(vslider_class, (t_method)vslider_delta, gensym("delta"), A_GIMME, 0);
604 class_addmethod(vslider_class, (t_method)vslider_pos, gensym("pos"), A_GIMME, 0);
605 class_addmethod(vslider_class, (t_method)vslider_range, gensym("range"), A_GIMME, 0);
606 class_addmethod(vslider_class, (t_method)vslider_color, gensym("color"), A_GIMME, 0);
607 class_addmethod(vslider_class, (t_method)vslider_send, gensym("send"), A_DEFSYM, 0);
608 class_addmethod(vslider_class, (t_method)vslider_receive, gensym("receive"), A_DEFSYM, 0);
609 class_addmethod(vslider_class, (t_method)vslider_label, gensym("label"), A_DEFSYM, 0);
610 class_addmethod(vslider_class, (t_method)vslider_label_pos, gensym("label_pos"), A_GIMME, 0);
611 class_addmethod(vslider_class, (t_method)vslider_label_font, gensym("label_font"), A_GIMME, 0);
612 class_addmethod(vslider_class, (t_method)vslider_log, gensym("log"), 0);
613 class_addmethod(vslider_class, (t_method)vslider_lin, gensym("lin"), 0);
614 class_addmethod(vslider_class, (t_method)vslider_init, gensym("init"), A_FLOAT, 0);
615 class_addmethod(vslider_class, (t_method)vslider_steady, gensym("steady"), A_FLOAT, 0);
616 vslider_widgetbehavior.w_getrectfn = vslider_getrect;
617 vslider_widgetbehavior.w_displacefn = iemgui_displace;
618 vslider_widgetbehavior.w_selectfn = iemgui_select;
619 vslider_widgetbehavior.w_activatefn = NULL;
620 vslider_widgetbehavior.w_deletefn = iemgui_delete;
621 vslider_widgetbehavior.w_visfn = iemgui_vis;
622 vslider_widgetbehavior.w_clickfn = vslider_newclick;
623 class_setwidget(vslider_class, &vslider_widgetbehavior);
624 class_sethelpsymbol(vslider_class, gensym("vslider"));
625 class_setsavefn(vslider_class, vslider_save);
626 class_setpropertiesfn(vslider_class, vslider_properties);
627}
628/* Copyright (c) 1997-1999 Miller Puckette.
629 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
630 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
631
632/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
633/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
634
635
636#include <stdlib.h>
637#include <string.h>
638#include <stdio.h>
639#include <ctype.h>
640#include "m_pd.h"
641#include "g_canvas.h"
642#include "t_tk.h"
643#include "g_all_guis.h"
644#include <math.h>
645
646#ifdef MSW
647#include <io.h>
648#else
649#include <unistd.h>
650#endif
651
652
653/* ------------ vsl gui-vertical slider ----------------------- */
654
655t_widgetbehavior vslider_widgetbehavior;
656static t_class *vslider_class;
657
658/* widget helper functions */
659
660static void vslider_draw_update(t_vslider *x, t_glist *glist)
661{
662 if (glist_isvisible(glist))
663 {
664 int r = text_ypix(&x->x_gui.x_obj, glist) + x->x_gui.x_h - (x->x_val + 50)/100;
665 int xpos=text_xpix(&x->x_gui.x_obj, glist);
666
667 sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
668 glist_getcanvas(glist), x, xpos+1, r,
669 xpos + x->x_gui.x_w, r);
670 }
671}
672
673static void vslider_draw_new(t_vslider *x, t_glist *glist)
674{
675 int xpos=text_xpix(&x->x_gui.x_obj, glist);
676 int ypos=text_ypix(&x->x_gui.x_obj, glist);
677 int r = ypos + x->x_gui.x_h - (x->x_val + 50)/100;
678 t_canvas *canvas=glist_getcanvas(glist);
679
680 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
681 canvas, xpos, ypos-2,
682 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h+3,
683 x->x_gui.x_bcol, x);
684 sys_vgui(".x%x.c create line %d %d %d %d -width 3 -fill #%6.6x -tags %xKNOB\n",
685 canvas, xpos+1, r,
686 xpos + x->x_gui.x_w, r, x->x_gui.x_fcol, x);
687 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
688 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
689 canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
690 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
691 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
692 if(!x->x_gui.x_fsf.x_snd_able)
693 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
694 canvas,
695 xpos, ypos + x->x_gui.x_h+2,
696 xpos+7, ypos + x->x_gui.x_h+3,
697 x, 0);
698 if(!x->x_gui.x_fsf.x_rcv_able)
699 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
700 canvas,
701 xpos, ypos-2,
702 xpos+7, ypos-1,
703 x, 0);
704}
705
706static void vslider_draw_move(t_vslider *x, t_glist *glist)
707{
708 int xpos=text_xpix(&x->x_gui.x_obj, glist);
709 int ypos=text_ypix(&x->x_gui.x_obj, glist);
710 int r = ypos + x->x_gui.x_h - (x->x_val + 50)/100;
711 t_canvas *canvas=glist_getcanvas(glist);
712
713 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
714 canvas, x,
715 xpos, ypos-2,
716 xpos + x->x_gui.x_w, ypos + x->x_gui.x_h+3);
717 sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
718 canvas, x, xpos+1, r,
719 xpos + x->x_gui.x_w, r);
720 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
721 canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
722 if(!x->x_gui.x_fsf.x_snd_able)
723 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
724 canvas, x, 0,
725 xpos, ypos + x->x_gui.x_h+2,
726 xpos+7, ypos + x->x_gui.x_h+3);
727 if(!x->x_gui.x_fsf.x_rcv_able)
728 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
729 canvas, x, 0,
730 xpos, ypos-2,
731 xpos+7, ypos-1);
732}
733
734static void vslider_draw_erase(t_vslider* x,t_glist* glist)
735{
736 t_canvas *canvas=glist_getcanvas(glist);
737
738 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
739 sys_vgui(".x%x.c delete %xKNOB\n", canvas, x);
740 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
741 if(!x->x_gui.x_fsf.x_snd_able)
742 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
743 if(!x->x_gui.x_fsf.x_rcv_able)
744 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
745}
746
747static void vslider_draw_config(t_vslider* x,t_glist* glist)
748{
749 t_canvas *canvas=glist_getcanvas(glist);
750
751 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
752 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
753 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
754 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
755 sys_vgui(".x%x.c itemconfigure %xKNOB -fill #%6.6x\n", canvas,
756 x, x->x_gui.x_fcol);
757 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas,
758 x, x->x_gui.x_bcol);
759}
760
761static void vslider_draw_io(t_vslider* x,t_glist* glist, int old_snd_rcv_flags)
762{
763 int xpos=text_xpix(&x->x_gui.x_obj, glist);
764 int ypos=text_ypix(&x->x_gui.x_obj, glist);
765 t_canvas *canvas=glist_getcanvas(glist);
766
767 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
768 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
769 canvas,
770 xpos, ypos + x->x_gui.x_h+2,
771 xpos+7, ypos + x->x_gui.x_h+3,
772 x, 0);
773 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
774 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
775 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
776 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
777 canvas,
778 xpos, ypos-2,
779 xpos+7, ypos-1,
780 x, 0);
781 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
782 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
783}
784
785static void vslider_draw_select(t_vslider *x, t_glist *glist)
786{
787 t_canvas *canvas=glist_getcanvas(glist);
788
789 if(x->x_gui.x_fsf.x_selected)
790 {
791 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
792 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
793 }
794 else
795 {
796 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
797 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
798 }
799}
800
801void vslider_draw(t_vslider *x, t_glist *glist, int mode)
802{
803 if(mode == IEM_GUI_DRAW_MODE_UPDATE)
804 vslider_draw_update(x, glist);
805 else if(mode == IEM_GUI_DRAW_MODE_MOVE)
806 vslider_draw_move(x, glist);
807 else if(mode == IEM_GUI_DRAW_MODE_NEW)
808 vslider_draw_new(x, glist);
809 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
810 vslider_draw_select(x, glist);
811 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
812 vslider_draw_erase(x, glist);
813 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
814 vslider_draw_config(x, glist);
815 else if(mode >= IEM_GUI_DRAW_MODE_IO)
816 vslider_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
817}
818
819/* ------------------------ vsl widgetbehaviour----------------------------- */
820
821
822static void vslider_getrect(t_gobj *z, t_glist *glist,
823 int *xp1, int *yp1, int *xp2, int *yp2)
824{
825 t_vslider* x = (t_vslider*)z;
826
827 *xp1 = text_xpix(&x->x_gui.x_obj, glist);
828 *yp1 = text_ypix(&x->x_gui.x_obj, glist) - 2;
829 *xp2 = *xp1 + x->x_gui.x_w;
830 *yp2 = *yp1 + x->x_gui.x_h + 5;
831}
832
833static void vslider_save(t_gobj *z, t_binbuf *b)
834{
835 t_vslider *x = (t_vslider *)z;
836 int bflcol[3];
837 t_symbol *srl[3];
838
839 iemgui_save(&x->x_gui, srl, bflcol);
840 binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
841 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
842 gensym("vsl"), x->x_gui.x_w, x->x_gui.x_h,
843 (float)x->x_min, (float)x->x_max,
844 x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa),
845 srl[0], srl[1], srl[2],
846 x->x_gui.x_ldx, x->x_gui.x_ldy,
847 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
848 bflcol[0], bflcol[1], bflcol[2],
849 x->x_val, x->x_steady);
850 binbuf_addv(b, ";");
851}
852
853void vslider_check_height(t_vslider *x, int h)
854{
855 if(h < IEM_SL_MINSIZE)
856 h = IEM_SL_MINSIZE;
857 x->x_gui.x_h = h;
858 if(x->x_val > (x->x_gui.x_h*100 - 100))
859 {
860 x->x_pos = x->x_gui.x_h*100 - 100;
861 x->x_val = x->x_pos;
862 }
863 if(x->x_lin0_log1)
864 x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_h - 1);
865 else
866 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
867}
868
869void vslider_check_minmax(t_vslider *x, double min, double max)
870{
871 if(x->x_lin0_log1)
872 {
873 if((min == 0.0)&&(max == 0.0))
874 max = 1.0;
875 if(max > 0.0)
876 {
877 if(min <= 0.0)
878 min = 0.01*max;
879 }
880 else
881 {
882 if(min > 0.0)
883 max = 0.01*min;
884 }
885 }
886 x->x_min = min;
887 x->x_max = max;
888 if(x->x_min > x->x_max) /* bugfix */
889 x->x_gui.x_isa.x_reverse = 1;
890 else
891 x->x_gui.x_isa.x_reverse = 0;
892 if(x->x_lin0_log1)
893 x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_h - 1);
894 else
895 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
896}
897
898static void vslider_properties(t_gobj *z, t_glist *owner)
899{
900 t_vslider *x = (t_vslider *)z;
901 char buf[800];
902 t_symbol *srl[3];
903
904 iemgui_properties(&x->x_gui, srl);
905
906 sprintf(buf, "pdtk_iemgui_dialog %%s VSLIDER \
907 --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
908 -----------output-range:----------- %g bottom: %g top: %d \
909 %d lin log %d %d empty %d \
910 %s %s \
911 %s %d %d \
912 %d %d \
913 %d %d %d\n",
914 x->x_gui.x_w, IEM_GUI_MINSIZE, x->x_gui.x_h, IEM_SL_MINSIZE,
915 x->x_min, x->x_max, 0,/*no_schedule*/
916 x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
917 srl[0]->s_name, srl[1]->s_name,
918 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
919 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
920 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
921 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
922}
923
924static void vslider_bang(t_vslider *x)
925{
926 double out;
927
928 if(x->x_lin0_log1)
929 out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
930 else
931 out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
932 if((out < 1.0e-10)&&(out > -1.0e-10))
933 out = 0.0;
934
935 outlet_float(x->x_gui.x_obj.ob_outlet, out);
936 if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
937 pd_float(x->x_gui.x_snd->s_thing, out);
938}
939
940static void vslider_dialog(t_vslider *x, t_symbol *s, int argc, t_atom *argv)
941{
942 t_symbol *srl[3];
943 int w = (int)atom_getintarg(0, argc, argv);
944 int h = (int)atom_getintarg(1, argc, argv);
945 double min = (double)atom_getfloatarg(2, argc, argv);
946 double max = (double)atom_getfloatarg(3, argc, argv);
947 int lilo = (int)atom_getintarg(4, argc, argv);
948 int steady = (int)atom_getintarg(17, argc, argv);
949 int sr_flags;
950
951 if(lilo != 0) lilo = 1;
952 x->x_lin0_log1 = lilo;
953 if(steady)
954 x->x_steady = 1;
955 else
956 x->x_steady = 0;
957 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
958 x->x_gui.x_w = iemgui_clip_size(w);
959 vslider_check_height(x, h);
960 vslider_check_minmax(x, min, max);
961 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
962 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
963 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
964 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
965}
966
967static void vslider_motion(t_vslider *x, t_floatarg dx, t_floatarg dy)
968{
969 int old = x->x_val;
970
971 if(x->x_gui.x_fsf.x_finemoved)
972 x->x_pos -= (int)dy;
973 else
974 x->x_pos -= 100*(int)dy;
975 x->x_val = x->x_pos;
976 if(x->x_val > (100*x->x_gui.x_h - 100))
977 {
978 x->x_val = 100*x->x_gui.x_h - 100;
979 x->x_pos += 50;
980 x->x_pos -= x->x_pos%100;
981 }
982 if(x->x_val < 0)
983 {
984 x->x_val = 0;
985 x->x_pos -= 50;
986 x->x_pos -= x->x_pos%100;
987 }
988 if(old != x->x_val)
989 {
990 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
991 vslider_bang(x);
992 }
993}
994
995static void vslider_click(t_vslider *x, t_floatarg xpos, t_floatarg ypos,
996 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
997{
998 if(!x->x_steady)
999 x->x_val = (int)(100.0 * (x->x_gui.x_h + text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist) - ypos));
1000 if(x->x_val > (100*x->x_gui.x_h - 100))
1001 x->x_val = 100*x->x_gui.x_h - 100;
1002 if(x->x_val < 0)
1003 x->x_val = 0;
1004 x->x_pos = x->x_val;
1005 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1006 vslider_bang(x);
1007 glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
1008 (t_glistmotionfn)vslider_motion, 0, xpos, ypos);
1009}
1010
1011static int vslider_newclick(t_gobj *z, struct _glist *glist,
1012 int xpix, int ypix, int shift, int alt, int dbl, int doit)
1013{
1014 t_vslider* x = (t_vslider *)z;
1015
1016 if(doit)
1017 {
1018 vslider_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
1019 0, (t_floatarg)alt);
1020 if(shift)
1021 x->x_gui.x_fsf.x_finemoved = 1;
1022 else
1023 x->x_gui.x_fsf.x_finemoved = 0;
1024 }
1025 return (1);
1026}
1027
1028static void vslider_set(t_vslider *x, t_floatarg f)
1029{
1030 double g;
1031
1032 if(x->x_gui.x_isa.x_reverse) /* bugfix */
1033 {
1034 if(f > x->x_min)
1035 f = x->x_min;
1036 if(f < x->x_max)
1037 f = x->x_max;
1038 }
1039 else
1040 {
1041 if(f > x->x_max)
1042 f = x->x_max;
1043 if(f < x->x_min)
1044 f = x->x_min;
1045 }
1046 if(x->x_lin0_log1)
1047 g = log(f/x->x_min)/x->x_k;
1048 else
1049 g = (f - x->x_min) / x->x_k;
1050 x->x_val = (int)(100.0*g + 0.49999);
1051 x->x_pos = x->x_val;
1052 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1053}
1054
1055static void vslider_float(t_vslider *x, t_floatarg f)
1056{
1057 vslider_set(x, f);
1058 if(x->x_gui.x_fsf.x_put_in2out)
1059 vslider_bang(x);
1060}
1061
1062static void vslider_size(t_vslider *x, t_symbol *s, int ac, t_atom *av)
1063{
1064 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
1065 if(ac > 1)
1066 vslider_check_height(x, (int)atom_getintarg(1, ac, av));
1067 iemgui_size((void *)x, &x->x_gui);
1068}
1069
1070static void vslider_delta(t_vslider *x, t_symbol *s, int ac, t_atom *av)
1071{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
1072
1073static void vslider_pos(t_vslider *x, t_symbol *s, int ac, t_atom *av)
1074{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
1075
1076static void vslider_range(t_vslider *x, t_symbol *s, int ac, t_atom *av)
1077{
1078 vslider_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
1079 (double)atom_getfloatarg(1, ac, av));
1080}
1081
1082static void vslider_color(t_vslider *x, t_symbol *s, int ac, t_atom *av)
1083{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
1084
1085static void vslider_send(t_vslider *x, t_symbol *s)
1086{iemgui_send(x, &x->x_gui, s);}
1087
1088static void vslider_receive(t_vslider *x, t_symbol *s)
1089{iemgui_receive(x, &x->x_gui, s);}
1090
1091static void vslider_label(t_vslider *x, t_symbol *s)
1092{iemgui_label((void *)x, &x->x_gui, s);}
1093
1094static void vslider_label_pos(t_vslider *x, t_symbol *s, int ac, t_atom *av)
1095{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
1096
1097static void vslider_label_font(t_vslider *x, t_symbol *s, int ac, t_atom *av)
1098{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
1099
1100static void vslider_log(t_vslider *x)
1101{
1102 x->x_lin0_log1 = 1;
1103 vslider_check_minmax(x, x->x_min, x->x_max);
1104}
1105
1106static void vslider_lin(t_vslider *x)
1107{
1108 x->x_lin0_log1 = 0;
1109 x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
1110}
1111
1112static void vslider_init(t_vslider *x, t_floatarg f)
1113{
1114 x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
1115}
1116
1117static void vslider_steady(t_vslider *x, t_floatarg f)
1118{
1119 x->x_steady = (f==0.0)?0:1;
1120}
1121
1122static void vslider_loadbang(t_vslider *x)
1123{
1124 if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
1125 {
1126 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
1127 vslider_bang(x);
1128 }
1129}
1130
1131static void *vslider_new(t_symbol *s, int argc, t_atom *argv)
1132{
1133 t_vslider *x = (t_vslider *)pd_new(vslider_class);
1134 int bflcol[]={-262144, -1, -1};
1135 int w=IEM_GUI_DEFAULTSIZE, h=IEM_SL_DEFAULTSIZE;
1136 int lilo=0, f=0, ldx=0, ldy=-8;
1137 int fs=8, v=0, steady=1;
1138 double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
1139 char str[144];
1140
1141 iem_inttosymargs(&x->x_gui.x_isa, 0);
1142 iem_inttofstyle(&x->x_gui.x_fsf, 0);
1143
1144 if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
1145 &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
1146 &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
1147 &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
1148 &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
1149 &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
1150 &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
1151 &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
1152 &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
1153 {
1154 w = (int)atom_getintarg(0, argc, argv);
1155 h = (int)atom_getintarg(1, argc, argv);
1156 min = (double)atom_getfloatarg(2, argc, argv);
1157 max = (double)atom_getfloatarg(3, argc, argv);
1158 lilo = (int)atom_getintarg(4, argc, argv);
1159 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
1160 iemgui_new_getnames(&x->x_gui, 6, argv);
1161 ldx = (int)atom_getintarg(9, argc, argv);
1162 ldy = (int)atom_getintarg(10, argc, argv);
1163 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
1164 fs = (int)atom_getintarg(12, argc, argv);
1165 bflcol[0] = (int)atom_getintarg(13, argc, argv);
1166 bflcol[1] = (int)atom_getintarg(14, argc, argv);
1167 bflcol[2] = (int)atom_getintarg(15, argc, argv);
1168 v = (int)atom_getintarg(16, argc, argv);
1169 }
1170 else iemgui_new_getnames(&x->x_gui, 6, 0);
1171 if((argc == 18)&&IS_A_FLOAT(argv,17))
1172 steady = (int)atom_getintarg(17, argc, argv);
1173 x->x_gui.x_draw = (t_iemfunptr)vslider_draw;
1174 x->x_gui.x_fsf.x_snd_able = 1;
1175 x->x_gui.x_fsf.x_rcv_able = 1;
1176 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
1177 if(x->x_gui.x_isa.x_loadinit)
1178 x->x_val = v;
1179 else
1180 x->x_val = 0;
1181 x->x_pos = x->x_val;
1182 if(lilo != 0) lilo = 1;
1183 x->x_lin0_log1 = lilo;
1184 if(steady != 0) steady = 1;
1185 x->x_steady = steady;
1186 if(!strcmp(x->x_gui.x_snd->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0;
1187 if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0;
1188 if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
1189 else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
1190 else { x->x_gui.x_fsf.x_font_style = 0;
1191 strcpy(x->x_gui.x_font, "courier"); }
1192 if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1193 x->x_gui.x_ldx = ldx;
1194 x->x_gui.x_ldy = ldy;
1195 if(fs < 4)
1196 fs = 4;
1197 x->x_gui.x_fontsize = fs;
1198 x->x_gui.x_w = iemgui_clip_size(w);
1199 vslider_check_height(x, h);
1200 vslider_check_minmax(x, min, max);
1201 iemgui_all_colfromload(&x->x_gui, bflcol);
1202 iemgui_verify_snd_ne_rcv(&x->x_gui);
1203 outlet_new(&x->x_gui.x_obj, &s_float);
1204 return (x);
1205}
1206
1207static void vslider_free(t_vslider *x)
1208{
1209 if(x->x_gui.x_fsf.x_rcv_able)
1210 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1211 gfxstub_deleteforkey(x);
1212}
1213
1214void g_vslider_setup(void)
1215{
1216 vslider_class = class_new(gensym("vsl"), (t_newmethod)vslider_new,
1217 (t_method)vslider_free, sizeof(t_vslider), 0, A_GIMME, 0);
1218 class_addcreator((t_newmethod)vslider_new, gensym("vslider"), A_GIMME, 0);
1219 class_addbang(vslider_class,vslider_bang);
1220 class_addfloat(vslider_class,vslider_float);
1221 class_addmethod(vslider_class, (t_method)vslider_click, gensym("click"),
1222 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1223 class_addmethod(vslider_class, (t_method)vslider_motion, gensym("motion"),
1224 A_FLOAT, A_FLOAT, 0);
1225 class_addmethod(vslider_class, (t_method)vslider_dialog, gensym("dialog"),
1226 A_GIMME, 0);
1227 class_addmethod(vslider_class, (t_method)vslider_loadbang, gensym("loadbang"), 0);
1228 class_addmethod(vslider_class, (t_method)vslider_set, gensym("set"), A_FLOAT, 0);
1229 class_addmethod(vslider_class, (t_method)vslider_size, gensym("size"), A_GIMME, 0);
1230 class_addmethod(vslider_class, (t_method)vslider_delta, gensym("delta"), A_GIMME, 0);
1231 class_addmethod(vslider_class, (t_method)vslider_pos, gensym("pos"), A_GIMME, 0);
1232 class_addmethod(vslider_class, (t_method)vslider_range, gensym("range"), A_GIMME, 0);
1233 class_addmethod(vslider_class, (t_method)vslider_color, gensym("color"), A_GIMME, 0);
1234 class_addmethod(vslider_class, (t_method)vslider_send, gensym("send"), A_DEFSYM, 0);
1235 class_addmethod(vslider_class, (t_method)vslider_receive, gensym("receive"), A_DEFSYM, 0);
1236 class_addmethod(vslider_class, (t_method)vslider_label, gensym("label"), A_DEFSYM, 0);
1237 class_addmethod(vslider_class, (t_method)vslider_label_pos, gensym("label_pos"), A_GIMME, 0);
1238 class_addmethod(vslider_class, (t_method)vslider_label_font, gensym("label_font"), A_GIMME, 0);
1239 class_addmethod(vslider_class, (t_method)vslider_log, gensym("log"), 0);
1240 class_addmethod(vslider_class, (t_method)vslider_lin, gensym("lin"), 0);
1241 class_addmethod(vslider_class, (t_method)vslider_init, gensym("init"), A_FLOAT, 0);
1242 class_addmethod(vslider_class, (t_method)vslider_steady, gensym("steady"), A_FLOAT, 0);
1243 vslider_widgetbehavior.w_getrectfn = vslider_getrect;
1244 vslider_widgetbehavior.w_displacefn = iemgui_displace;
1245 vslider_widgetbehavior.w_selectfn = iemgui_select;
1246 vslider_widgetbehavior.w_activatefn = NULL;
1247 vslider_widgetbehavior.w_deletefn = iemgui_delete;
1248 vslider_widgetbehavior.w_visfn = iemgui_vis;
1249 vslider_widgetbehavior.w_clickfn = vslider_newclick;
1250 class_setwidget(vslider_class, &vslider_widgetbehavior);
1251 class_sethelpsymbol(vslider_class, gensym("vslider"));
1252 class_setsavefn(vslider_class, vslider_save);
1253 class_setpropertiesfn(vslider_class, vslider_properties);
1254}
diff --git a/apps/plugins/pdbox/PDa/src/g_vumeter.c b/apps/plugins/pdbox/PDa/src/g_vumeter.c
new file mode 100644
index 0000000000..c7b3f1f209
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_vumeter.c
@@ -0,0 +1,1426 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
6/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
7
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <ctype.h>
13#include "m_pd.h"
14#include "g_canvas.h"
15#include "t_tk.h"
16#include "g_all_guis.h"
17#include <math.h>
18
19#ifdef MSW
20#include <io.h>
21#else
22#include <unistd.h>
23#endif
24
25/* ----- vu gui-peak- & rms- vu-meter-display ---------- */
26
27t_widgetbehavior vu_widgetbehavior;
28static t_class *vu_class;
29
30/* widget helper functions */
31
32static void vu_update_rms(t_vu *x, t_glist *glist)
33{
34 if(glist_isvisible(glist))
35 {
36 int w4=x->x_gui.x_w/4, off=text_ypix(&x->x_gui.x_obj, glist)-1;
37 int xpos=text_xpix(&x->x_gui.x_obj, glist), quad1=xpos+w4+1, quad3=xpos+x->x_gui.x_w-w4-1;
38
39 sys_vgui(".x%x.c coords %xRCOVER %d %d %d %d\n",
40 glist_getcanvas(glist), x, quad1, off, quad3,
41 off + (x->x_led_size+1)*(IEM_VU_STEPS-x->x_rms));
42 }
43}
44
45static void vu_update_peak(t_vu *x, t_glist *glist)
46{
47 t_canvas *canvas=glist_getcanvas(glist);
48
49 if(glist_isvisible(glist))
50 {
51 int xpos=text_xpix(&x->x_gui.x_obj, glist);
52 int ypos=text_ypix(&x->x_gui.x_obj, glist);
53
54 if(x->x_peak)
55 {
56 int i=iemgui_vu_col[x->x_peak];
57 int j=ypos + (x->x_led_size+1)*(IEM_VU_STEPS+1-x->x_peak)
58 - (x->x_led_size+1)/2;
59
60 sys_vgui(".x%x.c coords %xPLED %d %d %d %d\n", canvas, x,
61 xpos, j,
62 xpos+x->x_gui.x_w+1, j);
63 sys_vgui(".x%x.c itemconfigure %xPLED -fill #%6.6x\n", canvas, x,
64 iemgui_color_hex[i]);
65 }
66 else
67 {
68 int mid=xpos+x->x_gui.x_w/2;
69
70 sys_vgui(".x%x.c itemconfigure %xPLED -fill #%6.6x\n",
71 canvas, x, x->x_gui.x_bcol);
72 sys_vgui(".x%x.c coords %xPLED %d %d %d %d\n",
73 canvas, x, mid, ypos+20,
74 mid, ypos+20);
75 }
76 }
77}
78
79static void vu_draw_new(t_vu *x, t_glist *glist)
80{
81 t_canvas *canvas=glist_getcanvas(glist);
82
83 int xpos=text_xpix(&x->x_gui.x_obj, glist);
84 int ypos=text_ypix(&x->x_gui.x_obj, glist);
85 int w4=x->x_gui.x_w/4, mid=xpos+x->x_gui.x_w/2,
86 quad1=xpos+w4+1;
87 int quad3=xpos+x->x_gui.x_w-w4,
88 end=xpos+x->x_gui.x_w+4;
89 int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
90 int led_col, yyy, i, k4=ypos-k3;
91
92 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
93 canvas, xpos-1, ypos-2,
94 xpos+x->x_gui.x_w+1,
95 ypos+x->x_gui.x_h+2, x->x_gui.x_bcol, x);
96 for(i=1; i<=IEM_VU_STEPS; i++)
97 {
98 led_col = iemgui_vu_col[i];
99 yyy = k4 + k1*(k2-i);
100 sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xRLED%d\n",
101 canvas, quad1, yyy, quad3, yyy, x->x_led_size, iemgui_color_hex[led_col], x, i);
102 if(((i+2)&3) && (x->x_scale))
103 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
104 -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
105 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
106 x->x_gui.x_lcol, x, i);
107 }
108 if(x->x_scale)
109 {
110 i=IEM_VU_STEPS+1;
111 yyy = k4 + k1*(k2-i);
112 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
113 -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
114 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
115 x->x_gui.x_lcol, x, i);
116 }
117 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xRCOVER\n",
118 canvas, quad1, ypos-1, quad3-1,
119 ypos-1 + k1*IEM_VU_STEPS, x->x_gui.x_bcol, x->x_gui.x_bcol, x);
120 sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xPLED\n",
121 canvas, mid, ypos+10,
122 mid, ypos+10, x->x_led_size, x->x_gui.x_bcol, x);
123 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
124 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
125 canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
126 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
127 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
128 if(!x->x_gui.x_fsf.x_snd_able)
129 {
130 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
131 canvas,
132 xpos-1, ypos + x->x_gui.x_h+1,
133 xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2,
134 x, 0);
135 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
136 canvas,
137 xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
138 xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2,
139 x, 1);
140 }
141 if(!x->x_gui.x_fsf.x_rcv_able)
142 {
143 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
144 canvas,
145 xpos-1, ypos-2,
146 xpos + IOWIDTH-1, ypos-1,
147 x, 0);
148 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
149 canvas,
150 xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
151 xpos+x->x_gui.x_w+1, ypos-1,
152 x, 1);
153 }
154}
155
156
157static void vu_draw_move(t_vu *x, t_glist *glist)
158{
159 t_canvas *canvas=glist_getcanvas(glist);
160
161 int xpos=text_xpix(&x->x_gui.x_obj, glist);
162 int ypos=text_ypix(&x->x_gui.x_obj, glist);
163 int w4=x->x_gui.x_w/4, quad1=xpos+w4+1;
164 int quad3=xpos+x->x_gui.x_w-w4,
165 end=xpos+x->x_gui.x_w+4;
166 int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
167 int yyy, i, k4=ypos-k3;
168
169 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
170 canvas, x, xpos-1, ypos-2,
171 xpos+x->x_gui.x_w+1,ypos+x->x_gui.x_h+2);
172 for(i=1; i<=IEM_VU_STEPS; i++)
173 {
174 yyy = k4 + k1*(k2-i);
175 sys_vgui(".x%x.c coords %xRLED%d %d %d %d %d\n",
176 canvas, x, i, quad1, yyy, quad3, yyy);
177 if(((i+2)&3) && (x->x_scale))
178 sys_vgui(".x%x.c coords %xSCALE%d %d %d\n",
179 canvas, x, i, end, yyy+k3);
180 }
181 if(x->x_scale)
182 {
183 i=IEM_VU_STEPS+1;
184 yyy = k4 + k1*(k2-i);
185 sys_vgui(".x%x.c coords %xSCALE%d %d %d\n",
186 canvas, x, i, end, yyy+k3);
187 }
188 vu_update_peak(x, glist);
189 vu_update_rms(x, glist);
190 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
191 canvas, x, xpos+x->x_gui.x_ldx,
192 ypos+x->x_gui.x_ldy);
193 if(!x->x_gui.x_fsf.x_snd_able)
194 {
195 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
196 canvas, x, 0,
197 xpos-1, ypos + x->x_gui.x_h+1,
198 xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2);
199 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
200 canvas, x, 1,
201 xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
202 xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2);
203 }
204 if(!x->x_gui.x_fsf.x_rcv_able)
205 {
206 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
207 canvas, x, 0,
208 xpos-1, ypos-2,
209 xpos + IOWIDTH-1, ypos-1);
210 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
211 canvas, x, 1,
212 xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
213 xpos+x->x_gui.x_w+1, ypos-1);
214 }
215}
216
217static void vu_draw_erase(t_vu* x,t_glist* glist)
218{
219 int i;
220 t_canvas *canvas=glist_getcanvas(glist);
221
222 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
223 for(i=1; i<=IEM_VU_STEPS; i++)
224 {
225 sys_vgui(".x%x.c delete %xRLED%d\n", canvas, x, i);
226 if(((i+2)&3) && (x->x_scale))
227 sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
228 }
229 if(x->x_scale)
230 {
231 i=IEM_VU_STEPS+1;
232 sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
233 }
234 sys_vgui(".x%x.c delete %xPLED\n", canvas, x);
235 sys_vgui(".x%x.c delete %xRCOVER\n", canvas, x);
236 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
237 if(!x->x_gui.x_fsf.x_snd_able)
238 {
239 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
240 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 1);
241 }
242 if(!x->x_gui.x_fsf.x_rcv_able)
243 {
244 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
245 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 1);
246 }
247}
248
249static void vu_draw_config(t_vu* x, t_glist* glist)
250{
251 int i;
252 t_canvas *canvas=glist_getcanvas(glist);
253
254 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
255 for(i=1; i<=IEM_VU_STEPS; i++)
256 {
257 sys_vgui(".x%x.c itemconfigure %xRLED%d -width %d\n", canvas, x, i,
258 x->x_led_size);
259 if(((i+2)&3) && (x->x_scale))
260 sys_vgui(".x%x.c itemconfigure %xSCALE%d -text {%s} -font {%s %d bold} -fill #%6.6x\n",
261 canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
262 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol);
263 }
264 if(x->x_scale)
265 {
266 i=IEM_VU_STEPS+1;
267 sys_vgui(".x%x.c itemconfigure %xSCALE%d -text {%s} -font {%s %d bold} -fill #%6.6x\n",
268 canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
269 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol);
270 }
271 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
272 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
273 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
274 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
275
276 sys_vgui(".x%x.c itemconfigure %xRCOVER -fill #%6.6x -outline #%6.6x\n", canvas,
277 x, x->x_gui.x_bcol, x->x_gui.x_bcol);
278 sys_vgui(".x%x.c itemconfigure %xPLED -width %d\n", canvas, x,
279 x->x_led_size);
280}
281
282static void vu_draw_io(t_vu* x, t_glist* glist, int old_snd_rcv_flags)
283{
284 int xpos=text_xpix(&x->x_gui.x_obj, glist);
285 int ypos=text_ypix(&x->x_gui.x_obj, glist);
286 t_canvas *canvas=glist_getcanvas(glist);
287
288 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
289 {
290 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
291 canvas,
292 xpos-1, ypos + x->x_gui.x_h+1,
293 xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2,
294 x, 0);
295 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
296 canvas,
297 xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
298 xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2,
299 x, 1);
300 }
301 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
302 {
303 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
304 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 1);
305 }
306 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
307 {
308 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
309 canvas,
310 xpos-1, ypos-2,
311 xpos + IOWIDTH-1, ypos-1,
312 x, 0);
313 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
314 canvas,
315 xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
316 xpos+x->x_gui.x_w+1, ypos-1,
317 x, 1);
318 }
319 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
320 {
321 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
322 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 1);
323 }
324}
325
326static void vu_draw_select(t_vu* x,t_glist* glist)
327{
328 int i;
329 t_canvas *canvas=glist_getcanvas(glist);
330
331 if(x->x_gui.x_fsf.x_selected)
332 {
333 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
334 for(i=1; i<=IEM_VU_STEPS; i++)
335 {
336 if(((i+2)&3) && (x->x_scale))
337 sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
338 canvas, x, i, IEM_GUI_COLOR_SELECTED);
339 }
340 if(x->x_scale)
341 {
342 i=IEM_VU_STEPS+1;
343 sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
344 canvas, x, i, IEM_GUI_COLOR_SELECTED);
345 }
346 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
347 }
348 else
349 {
350 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
351 for(i=1; i<=IEM_VU_STEPS; i++)
352 {
353 if(((i+2)&3) && (x->x_scale))
354 sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
355 canvas, x, i, x->x_gui.x_lcol);
356 }
357 if(x->x_scale)
358 {
359 i=IEM_VU_STEPS+1;
360 sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
361 canvas, x, i, x->x_gui.x_lcol);
362 }
363 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
364 }
365}
366
367void vu_draw(t_vu *x, t_glist *glist, int mode)
368{
369 if(mode == IEM_GUI_DRAW_MODE_MOVE)
370 vu_draw_move(x, glist);
371 else if(mode == IEM_GUI_DRAW_MODE_NEW)
372 vu_draw_new(x, glist);
373 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
374 vu_draw_select(x, glist);
375 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
376 vu_draw_erase(x, glist);
377 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
378 vu_draw_config(x, glist);
379 else if(mode >= IEM_GUI_DRAW_MODE_IO)
380 vu_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
381}
382
383/* ------------------------ vu widgetbehaviour----------------------------- */
384
385
386static void vu_getrect(t_gobj *z, t_glist *glist,
387 int *xp1, int *yp1, int *xp2, int *yp2)
388{
389 t_vu* x = (t_vu*)z;
390
391 *xp1 = text_xpix(&x->x_gui.x_obj, glist) - 1;
392 *yp1 = text_ypix(&x->x_gui.x_obj, glist) - 2;
393 *xp2 = *xp1 + x->x_gui.x_w + 2;
394 *yp2 = *yp1 + x->x_gui.x_h + 4;
395}
396
397static void vu_save(t_gobj *z, t_binbuf *b)
398{
399 t_vu *x = (t_vu *)z;
400 int bflcol[3];
401 t_symbol *srl[3];
402
403 iemgui_save(&x->x_gui, srl, bflcol);
404 binbuf_addv(b, "ssiisiissiiiiiiii", gensym("#X"),gensym("obj"),
405 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
406 gensym("vu"), x->x_gui.x_w, x->x_gui.x_h,
407 srl[1], srl[2],
408 x->x_gui.x_ldx, x->x_gui.x_ldy,
409 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
410 bflcol[0], bflcol[2], x->x_scale,
411 iem_symargstoint(&x->x_gui.x_isa));
412 binbuf_addv(b, ";");
413}
414
415void vu_check_height(t_vu *x, int h)
416{
417 int n;
418
419 n = h / IEM_VU_STEPS;
420 if(n < IEM_VU_MINSIZE)
421 n = IEM_VU_MINSIZE;
422 x->x_led_size = n-1;
423 x->x_gui.x_h = IEM_VU_STEPS * n;
424}
425
426static void vu_scale(t_vu *x, t_floatarg fscale)
427{
428 int i, scale = (int)fscale;
429
430 if(scale != 0) scale = 1;
431 if(x->x_scale && !scale)
432 {
433 t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
434
435 x->x_scale = (int)scale;
436 if(glist_isvisible(x->x_gui.x_glist))
437 {
438 for(i=1; i<=IEM_VU_STEPS; i++)
439 {
440 if((i+2)&3)
441 sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
442 }
443 i=IEM_VU_STEPS+1;
444 sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
445 }
446 }
447 if(!x->x_scale && scale)
448 {
449 int w4=x->x_gui.x_w/4, end=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w+4;
450 int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
451 int yyy, k4=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)-k3;
452 t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
453
454 x->x_scale = (int)scale;
455 if(glist_isvisible(x->x_gui.x_glist))
456 {
457 for(i=1; i<=IEM_VU_STEPS; i++)
458 {
459 yyy = k4 + k1*(k2-i);
460 if((i+2)&3)
461 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
462 -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
463 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
464 x->x_gui.x_lcol, x, i);
465 }
466 i=IEM_VU_STEPS+1;
467 yyy = k4 + k1*(k2-i);
468 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
469 -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
470 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
471 x->x_gui.x_lcol, x, i);
472 }
473 }
474}
475
476static void vu_properties(t_gobj *z, t_glist *owner)
477{
478 t_vu *x = (t_vu *)z;
479 char buf[800];
480 t_symbol *srl[3];
481
482 iemgui_properties(&x->x_gui, srl);
483 sprintf(buf, "pdtk_iemgui_dialog %%s VU-METER \
484 --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
485 empty 0.0 empty 0.0 empty %d \
486 %d no_scale scale %d %d empty %d \
487 %s %s \
488 %s %d %d \
489 %d %d \
490 %d %d %d\n",
491 x->x_gui.x_w, IEM_GUI_MINSIZE, x->x_gui.x_h, IEM_VU_STEPS*IEM_VU_MINSIZE,
492 0,/*no_schedule*/
493 x->x_scale, -1, -1, -1,/*no linlog, no init, no multi*/
494 "nosndno", srl[1]->s_name,/*no send*/
495 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
496 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
497 0xffffff & x->x_gui.x_bcol, -1/*no front-color*/, 0xffffff & x->x_gui.x_lcol);
498 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
499}
500
501static void vu_dialog(t_vu *x, t_symbol *s, int argc, t_atom *argv)
502{
503 t_symbol *srl[3];
504 int w = (int)atom_getintarg(0, argc, argv);
505 int h = (int)atom_getintarg(1, argc, argv);
506 int scale = (int)atom_getintarg(4, argc, argv);
507 int sr_flags;
508
509 srl[0] = gensym("empty");
510 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
511 x->x_gui.x_fsf.x_snd_able = 0;
512 x->x_gui.x_isa.x_loadinit = 0;
513 x->x_gui.x_w = iemgui_clip_size(w);
514 vu_check_height(x, h);
515 if(scale != 0)
516 scale = 1;
517 vu_scale(x, (float)scale);
518 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
519 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
520 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
521 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
522}
523
524static void vu_size(t_vu *x, t_symbol *s, int ac, t_atom *av)
525{
526 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
527 if(ac > 1)
528 vu_check_height(x, (int)atom_getintarg(1, ac, av));
529 if(glist_isvisible(x->x_gui.x_glist))
530 {
531 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
532 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
533 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
534 }
535}
536
537static void vu_delta(t_vu *x, t_symbol *s, int ac, t_atom *av)
538{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
539
540static void vu_pos(t_vu *x, t_symbol *s, int ac, t_atom *av)
541{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
542
543static void vu_color(t_vu *x, t_symbol *s, int ac, t_atom *av)
544{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
545
546static void vu_receive(t_vu *x, t_symbol *s)
547{iemgui_receive(x, &x->x_gui, s);}
548
549static void vu_label(t_vu *x, t_symbol *s)
550{iemgui_label((void *)x, &x->x_gui, s);}
551
552static void vu_label_pos(t_vu *x, t_symbol *s, int ac, t_atom *av)
553{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
554
555static void vu_label_font(t_vu *x, t_symbol *s, int ac, t_atom *av)
556{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
557
558static void vu_float(t_vu *x, t_floatarg rms)
559{
560 int i;
561
562 if(rms <= IEM_VU_MINDB)
563 x->x_rms = 0;
564 else if(rms >= IEM_VU_MAXDB)
565 x->x_rms = IEM_VU_STEPS;
566 else
567 {
568 int i = (int)(2.0*(rms + IEM_VU_OFFSET));
569 x->x_rms = iemgui_vu_db2i[i];
570 }
571 i = (int)(100.0*rms + 10000.5);
572 rms = 0.01*(float)(i - 10000);
573 x->x_fr = rms;
574 outlet_float(x->x_out_rms, rms);
575 vu_update_rms(x, x->x_gui.x_glist);
576}
577
578static void vu_ft1(t_vu *x, t_floatarg peak)
579{
580 int i;
581
582 if(peak <= IEM_VU_MINDB)
583 x->x_peak = 0;
584 else if(peak >= IEM_VU_MAXDB)
585 x->x_peak = IEM_VU_STEPS;
586 else
587 {
588 int i = (int)(2.0*(peak + IEM_VU_OFFSET));
589 x->x_peak = iemgui_vu_db2i[i];
590 }
591 i = (int)(100.0*peak + 10000.5);
592 peak = 0.01*(float)(i - 10000);
593 x->x_fp = peak;
594 outlet_float(x->x_out_peak, peak);
595 vu_update_peak(x, x->x_gui.x_glist);
596}
597
598static void vu_bang(t_vu *x)
599{
600 outlet_float(x->x_out_peak, x->x_fp);
601 outlet_float(x->x_out_rms, x->x_fr);
602 vu_update_rms(x, x->x_gui.x_glist);
603 vu_update_peak(x, x->x_gui.x_glist);
604}
605
606static void *vu_new(t_symbol *s, int argc, t_atom *argv)
607{
608 t_vu *x = (t_vu *)pd_new(vu_class);
609 int bflcol[]={-66577, -1, -1};
610 int w=IEM_GUI_DEFAULTSIZE, h=IEM_VU_STEPS*IEM_VU_DEFAULTSIZE;
611 int ldx=-1, ldy=-8, f=0, fs=8, scale=1;
612 int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
613 char str[144];
614
615 iem_inttosymargs(&x->x_gui.x_isa, 0);
616 iem_inttofstyle(&x->x_gui.x_fsf, 0);
617
618 if((argc >= 11)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
619 &&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2))
620 &&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))
621 &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
622 &&IS_A_FLOAT(argv,6)&&IS_A_FLOAT(argv,7)
623 &&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10))
624 {
625 w = (int)atom_getintarg(0, argc, argv);
626 h = (int)atom_getintarg(1, argc, argv);
627 iemgui_new_getnames(&x->x_gui, 1, argv);
628 ldx = (int)atom_getintarg(4, argc, argv);
629 ldy = (int)atom_getintarg(5, argc, argv);
630 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(6, argc, argv));
631 fs = (int)atom_getintarg(7, argc, argv);
632 bflcol[0] = (int)atom_getintarg(8, argc, argv);
633 bflcol[2] = (int)atom_getintarg(9, argc, argv);
634 scale = (int)atom_getintarg(10, argc, argv);
635 }
636 else iemgui_new_getnames(&x->x_gui, 1, 0);
637 if((argc == 12)&&IS_A_FLOAT(argv,11))
638 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(11, argc, argv));
639 x->x_gui.x_draw = (t_iemfunptr)vu_draw;
640
641 x->x_gui.x_fsf.x_snd_able = 0;
642 x->x_gui.x_fsf.x_rcv_able = 1;
643 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
644 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
645 x->x_gui.x_fsf.x_rcv_able = 0;
646 if (x->x_gui.x_fsf.x_font_style == 1)
647 strcpy(x->x_gui.x_font, "helvetica");
648 else if(x->x_gui.x_fsf.x_font_style == 2)
649 strcpy(x->x_gui.x_font, "times");
650 else { x->x_gui.x_fsf.x_font_style = 0;
651 strcpy(x->x_gui.x_font, "courier"); }
652 if(x->x_gui.x_fsf.x_rcv_able)
653 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
654 x->x_gui.x_ldx = ldx;
655 x->x_gui.x_ldy = ldy;
656
657 if(fs < 4)
658 fs = 4;
659 x->x_gui.x_fontsize = fs;
660 x->x_gui.x_w = iemgui_clip_size(w);
661 vu_check_height(x, h);
662 iemgui_all_colfromload(&x->x_gui, bflcol);
663 if(scale != 0)
664 scale = 1;
665 x->x_scale = scale;
666 x->x_peak = 0;
667 x->x_rms = 0;
668 x->x_fp = -101.0;
669 x->x_fr = -101.0;
670 iemgui_verify_snd_ne_rcv(&x->x_gui);
671 inlet_new(&x->x_gui.x_obj, &x->x_gui.x_obj.ob_pd, &s_float, gensym("ft1"));
672 x->x_out_rms = outlet_new(&x->x_gui.x_obj, &s_float);
673 x->x_out_peak = outlet_new(&x->x_gui.x_obj, &s_float);
674 return (x);
675}
676
677static void vu_free(t_vu *x)
678{
679 if(x->x_gui.x_fsf.x_rcv_able)
680 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
681 gfxstub_deleteforkey(x);
682}
683
684void g_vumeter_setup(void)
685{
686 vu_class = class_new(gensym("vu"), (t_newmethod)vu_new, (t_method)vu_free,
687 sizeof(t_vu), 0, A_GIMME, 0);
688 class_addbang(vu_class,vu_bang);
689 class_addfloat(vu_class,vu_float);
690 class_addmethod(vu_class, (t_method)vu_ft1, gensym("ft1"), A_FLOAT, 0);
691 class_addmethod(vu_class, (t_method)vu_dialog, gensym("dialog"),
692 A_GIMME, 0);
693 class_addmethod(vu_class, (t_method)vu_size, gensym("size"), A_GIMME, 0);
694 class_addmethod(vu_class, (t_method)vu_scale, gensym("scale"), A_DEFFLOAT, 0);
695 class_addmethod(vu_class, (t_method)vu_delta, gensym("delta"), A_GIMME, 0);
696 class_addmethod(vu_class, (t_method)vu_pos, gensym("pos"), A_GIMME, 0);
697 class_addmethod(vu_class, (t_method)vu_color, gensym("color"), A_GIMME, 0);
698 class_addmethod(vu_class, (t_method)vu_receive, gensym("receive"), A_DEFSYM, 0);
699 class_addmethod(vu_class, (t_method)vu_label, gensym("label"), A_DEFSYM, 0);
700 class_addmethod(vu_class, (t_method)vu_label_pos, gensym("label_pos"), A_GIMME, 0);
701 class_addmethod(vu_class, (t_method)vu_label_font, gensym("label_font"), A_GIMME, 0);
702 vu_widgetbehavior.w_getrectfn = vu_getrect;
703 vu_widgetbehavior.w_displacefn = iemgui_displace;
704 vu_widgetbehavior.w_selectfn = iemgui_select;
705 vu_widgetbehavior.w_activatefn = NULL;
706 vu_widgetbehavior.w_deletefn = iemgui_delete;
707 vu_widgetbehavior.w_visfn = iemgui_vis;
708 vu_widgetbehavior.w_clickfn = NULL;
709 class_setwidget(vu_class,&vu_widgetbehavior);
710 class_sethelpsymbol(vu_class, gensym("vu"));
711 class_setsavefn(vu_class, vu_save);
712 class_setpropertiesfn(vu_class, vu_properties);
713}
714/* Copyright (c) 1997-1999 Miller Puckette.
715 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
716 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
717
718/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
719/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
720
721
722#include <stdlib.h>
723#include <string.h>
724#include <stdio.h>
725#include <ctype.h>
726#include "m_pd.h"
727#include "g_canvas.h"
728#include "t_tk.h"
729#include "g_all_guis.h"
730#include <math.h>
731
732#ifdef MSW
733#include <io.h>
734#else
735#include <unistd.h>
736#endif
737
738/* ----- vu gui-peak- & rms- vu-meter-display ---------- */
739
740t_widgetbehavior vu_widgetbehavior;
741static t_class *vu_class;
742
743/* widget helper functions */
744
745static void vu_update_rms(t_vu *x, t_glist *glist)
746{
747 if(glist_isvisible(glist))
748 {
749 int w4=x->x_gui.x_w/4, off=text_ypix(&x->x_gui.x_obj, glist)-1;
750 int xpos=text_xpix(&x->x_gui.x_obj, glist), quad1=xpos+w4+1, quad3=xpos+x->x_gui.x_w-w4-1;
751
752 sys_vgui(".x%x.c coords %xRCOVER %d %d %d %d\n",
753 glist_getcanvas(glist), x, quad1, off, quad3,
754 off + (x->x_led_size+1)*(IEM_VU_STEPS-x->x_rms));
755 }
756}
757
758static void vu_update_peak(t_vu *x, t_glist *glist)
759{
760 t_canvas *canvas=glist_getcanvas(glist);
761
762 if(glist_isvisible(glist))
763 {
764 int xpos=text_xpix(&x->x_gui.x_obj, glist);
765 int ypos=text_ypix(&x->x_gui.x_obj, glist);
766
767 if(x->x_peak)
768 {
769 int i=iemgui_vu_col[x->x_peak];
770 int j=ypos + (x->x_led_size+1)*(IEM_VU_STEPS+1-x->x_peak)
771 - (x->x_led_size+1)/2;
772
773 sys_vgui(".x%x.c coords %xPLED %d %d %d %d\n", canvas, x,
774 xpos, j,
775 xpos+x->x_gui.x_w+1, j);
776 sys_vgui(".x%x.c itemconfigure %xPLED -fill #%6.6x\n", canvas, x,
777 iemgui_color_hex[i]);
778 }
779 else
780 {
781 int mid=xpos+x->x_gui.x_w/2;
782
783 sys_vgui(".x%x.c itemconfigure %xPLED -fill #%6.6x\n",
784 canvas, x, x->x_gui.x_bcol);
785 sys_vgui(".x%x.c coords %xPLED %d %d %d %d\n",
786 canvas, x, mid, ypos+20,
787 mid, ypos+20);
788 }
789 }
790}
791
792static void vu_draw_new(t_vu *x, t_glist *glist)
793{
794 t_canvas *canvas=glist_getcanvas(glist);
795
796 int xpos=text_xpix(&x->x_gui.x_obj, glist);
797 int ypos=text_ypix(&x->x_gui.x_obj, glist);
798 int w4=x->x_gui.x_w/4, mid=xpos+x->x_gui.x_w/2,
799 quad1=xpos+w4+1;
800 int quad3=xpos+x->x_gui.x_w-w4,
801 end=xpos+x->x_gui.x_w+4;
802 int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
803 int led_col, yyy, i, k4=ypos-k3;
804
805 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
806 canvas, xpos-1, ypos-2,
807 xpos+x->x_gui.x_w+1,
808 ypos+x->x_gui.x_h+2, x->x_gui.x_bcol, x);
809 for(i=1; i<=IEM_VU_STEPS; i++)
810 {
811 led_col = iemgui_vu_col[i];
812 yyy = k4 + k1*(k2-i);
813 sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xRLED%d\n",
814 canvas, quad1, yyy, quad3, yyy, x->x_led_size, iemgui_color_hex[led_col], x, i);
815 if(((i+2)&3) && (x->x_scale))
816 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
817 -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
818 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
819 x->x_gui.x_lcol, x, i);
820 }
821 if(x->x_scale)
822 {
823 i=IEM_VU_STEPS+1;
824 yyy = k4 + k1*(k2-i);
825 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
826 -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
827 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
828 x->x_gui.x_lcol, x, i);
829 }
830 sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xRCOVER\n",
831 canvas, quad1, ypos-1, quad3-1,
832 ypos-1 + k1*IEM_VU_STEPS, x->x_gui.x_bcol, x->x_gui.x_bcol, x);
833 sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xPLED\n",
834 canvas, mid, ypos+10,
835 mid, ypos+10, x->x_led_size, x->x_gui.x_bcol, x);
836 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
837 -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
838 canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
839 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
840 x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
841 if(!x->x_gui.x_fsf.x_snd_able)
842 {
843 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
844 canvas,
845 xpos-1, ypos + x->x_gui.x_h+1,
846 xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2,
847 x, 0);
848 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
849 canvas,
850 xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
851 xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2,
852 x, 1);
853 }
854 if(!x->x_gui.x_fsf.x_rcv_able)
855 {
856 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
857 canvas,
858 xpos-1, ypos-2,
859 xpos + IOWIDTH-1, ypos-1,
860 x, 0);
861 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
862 canvas,
863 xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
864 xpos+x->x_gui.x_w+1, ypos-1,
865 x, 1);
866 }
867}
868
869
870static void vu_draw_move(t_vu *x, t_glist *glist)
871{
872 t_canvas *canvas=glist_getcanvas(glist);
873
874 int xpos=text_xpix(&x->x_gui.x_obj, glist);
875 int ypos=text_ypix(&x->x_gui.x_obj, glist);
876 int w4=x->x_gui.x_w/4, quad1=xpos+w4+1;
877 int quad3=xpos+x->x_gui.x_w-w4,
878 end=xpos+x->x_gui.x_w+4;
879 int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
880 int yyy, i, k4=ypos-k3;
881
882 sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
883 canvas, x, xpos-1, ypos-2,
884 xpos+x->x_gui.x_w+1,ypos+x->x_gui.x_h+2);
885 for(i=1; i<=IEM_VU_STEPS; i++)
886 {
887 yyy = k4 + k1*(k2-i);
888 sys_vgui(".x%x.c coords %xRLED%d %d %d %d %d\n",
889 canvas, x, i, quad1, yyy, quad3, yyy);
890 if(((i+2)&3) && (x->x_scale))
891 sys_vgui(".x%x.c coords %xSCALE%d %d %d\n",
892 canvas, x, i, end, yyy+k3);
893 }
894 if(x->x_scale)
895 {
896 i=IEM_VU_STEPS+1;
897 yyy = k4 + k1*(k2-i);
898 sys_vgui(".x%x.c coords %xSCALE%d %d %d\n",
899 canvas, x, i, end, yyy+k3);
900 }
901 vu_update_peak(x, glist);
902 vu_update_rms(x, glist);
903 sys_vgui(".x%x.c coords %xLABEL %d %d\n",
904 canvas, x, xpos+x->x_gui.x_ldx,
905 ypos+x->x_gui.x_ldy);
906 if(!x->x_gui.x_fsf.x_snd_able)
907 {
908 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
909 canvas, x, 0,
910 xpos-1, ypos + x->x_gui.x_h+1,
911 xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2);
912 sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
913 canvas, x, 1,
914 xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
915 xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2);
916 }
917 if(!x->x_gui.x_fsf.x_rcv_able)
918 {
919 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
920 canvas, x, 0,
921 xpos-1, ypos-2,
922 xpos + IOWIDTH-1, ypos-1);
923 sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
924 canvas, x, 1,
925 xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
926 xpos+x->x_gui.x_w+1, ypos-1);
927 }
928}
929
930static void vu_draw_erase(t_vu* x,t_glist* glist)
931{
932 int i;
933 t_canvas *canvas=glist_getcanvas(glist);
934
935 sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
936 for(i=1; i<=IEM_VU_STEPS; i++)
937 {
938 sys_vgui(".x%x.c delete %xRLED%d\n", canvas, x, i);
939 if(((i+2)&3) && (x->x_scale))
940 sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
941 }
942 if(x->x_scale)
943 {
944 i=IEM_VU_STEPS+1;
945 sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
946 }
947 sys_vgui(".x%x.c delete %xPLED\n", canvas, x);
948 sys_vgui(".x%x.c delete %xRCOVER\n", canvas, x);
949 sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
950 if(!x->x_gui.x_fsf.x_snd_able)
951 {
952 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
953 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 1);
954 }
955 if(!x->x_gui.x_fsf.x_rcv_able)
956 {
957 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
958 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 1);
959 }
960}
961
962static void vu_draw_config(t_vu* x, t_glist* glist)
963{
964 int i;
965 t_canvas *canvas=glist_getcanvas(glist);
966
967 sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
968 for(i=1; i<=IEM_VU_STEPS; i++)
969 {
970 sys_vgui(".x%x.c itemconfigure %xRLED%d -width %d\n", canvas, x, i,
971 x->x_led_size);
972 if(((i+2)&3) && (x->x_scale))
973 sys_vgui(".x%x.c itemconfigure %xSCALE%d -text {%s} -font {%s %d bold} -fill #%6.6x\n",
974 canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
975 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol);
976 }
977 if(x->x_scale)
978 {
979 i=IEM_VU_STEPS+1;
980 sys_vgui(".x%x.c itemconfigure %xSCALE%d -text {%s} -font {%s %d bold} -fill #%6.6x\n",
981 canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
982 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol);
983 }
984 sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
985 canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
986 x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
987 strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
988
989 sys_vgui(".x%x.c itemconfigure %xRCOVER -fill #%6.6x -outline #%6.6x\n", canvas,
990 x, x->x_gui.x_bcol, x->x_gui.x_bcol);
991 sys_vgui(".x%x.c itemconfigure %xPLED -width %d\n", canvas, x,
992 x->x_led_size);
993}
994
995static void vu_draw_io(t_vu* x, t_glist* glist, int old_snd_rcv_flags)
996{
997 int xpos=text_xpix(&x->x_gui.x_obj, glist);
998 int ypos=text_ypix(&x->x_gui.x_obj, glist);
999 t_canvas *canvas=glist_getcanvas(glist);
1000
1001 if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
1002 {
1003 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
1004 canvas,
1005 xpos-1, ypos + x->x_gui.x_h+1,
1006 xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2,
1007 x, 0);
1008 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
1009 canvas,
1010 xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
1011 xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2,
1012 x, 1);
1013 }
1014 if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
1015 {
1016 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
1017 sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 1);
1018 }
1019 if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
1020 {
1021 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
1022 canvas,
1023 xpos-1, ypos-2,
1024 xpos + IOWIDTH-1, ypos-1,
1025 x, 0);
1026 sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
1027 canvas,
1028 xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
1029 xpos+x->x_gui.x_w+1, ypos-1,
1030 x, 1);
1031 }
1032 if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
1033 {
1034 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
1035 sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 1);
1036 }
1037}
1038
1039static void vu_draw_select(t_vu* x,t_glist* glist)
1040{
1041 int i;
1042 t_canvas *canvas=glist_getcanvas(glist);
1043
1044 if(x->x_gui.x_fsf.x_selected)
1045 {
1046 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
1047 for(i=1; i<=IEM_VU_STEPS; i++)
1048 {
1049 if(((i+2)&3) && (x->x_scale))
1050 sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
1051 canvas, x, i, IEM_GUI_COLOR_SELECTED);
1052 }
1053 if(x->x_scale)
1054 {
1055 i=IEM_VU_STEPS+1;
1056 sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
1057 canvas, x, i, IEM_GUI_COLOR_SELECTED);
1058 }
1059 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
1060 }
1061 else
1062 {
1063 sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
1064 for(i=1; i<=IEM_VU_STEPS; i++)
1065 {
1066 if(((i+2)&3) && (x->x_scale))
1067 sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
1068 canvas, x, i, x->x_gui.x_lcol);
1069 }
1070 if(x->x_scale)
1071 {
1072 i=IEM_VU_STEPS+1;
1073 sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
1074 canvas, x, i, x->x_gui.x_lcol);
1075 }
1076 sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
1077 }
1078}
1079
1080void vu_draw(t_vu *x, t_glist *glist, int mode)
1081{
1082 if(mode == IEM_GUI_DRAW_MODE_MOVE)
1083 vu_draw_move(x, glist);
1084 else if(mode == IEM_GUI_DRAW_MODE_NEW)
1085 vu_draw_new(x, glist);
1086 else if(mode == IEM_GUI_DRAW_MODE_SELECT)
1087 vu_draw_select(x, glist);
1088 else if(mode == IEM_GUI_DRAW_MODE_ERASE)
1089 vu_draw_erase(x, glist);
1090 else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
1091 vu_draw_config(x, glist);
1092 else if(mode >= IEM_GUI_DRAW_MODE_IO)
1093 vu_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
1094}
1095
1096/* ------------------------ vu widgetbehaviour----------------------------- */
1097
1098
1099static void vu_getrect(t_gobj *z, t_glist *glist,
1100 int *xp1, int *yp1, int *xp2, int *yp2)
1101{
1102 t_vu* x = (t_vu*)z;
1103
1104 *xp1 = text_xpix(&x->x_gui.x_obj, glist) - 1;
1105 *yp1 = text_ypix(&x->x_gui.x_obj, glist) - 2;
1106 *xp2 = *xp1 + x->x_gui.x_w + 2;
1107 *yp2 = *yp1 + x->x_gui.x_h + 4;
1108}
1109
1110static void vu_save(t_gobj *z, t_binbuf *b)
1111{
1112 t_vu *x = (t_vu *)z;
1113 int bflcol[3];
1114 t_symbol *srl[3];
1115
1116 iemgui_save(&x->x_gui, srl, bflcol);
1117 binbuf_addv(b, "ssiisiissiiiiiiii", gensym("#X"),gensym("obj"),
1118 (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
1119 gensym("vu"), x->x_gui.x_w, x->x_gui.x_h,
1120 srl[1], srl[2],
1121 x->x_gui.x_ldx, x->x_gui.x_ldy,
1122 iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize,
1123 bflcol[0], bflcol[2], x->x_scale,
1124 iem_symargstoint(&x->x_gui.x_isa));
1125 binbuf_addv(b, ";");
1126}
1127
1128void vu_check_height(t_vu *x, int h)
1129{
1130 int n;
1131
1132 n = h / IEM_VU_STEPS;
1133 if(n < IEM_VU_MINSIZE)
1134 n = IEM_VU_MINSIZE;
1135 x->x_led_size = n-1;
1136 x->x_gui.x_h = IEM_VU_STEPS * n;
1137}
1138
1139static void vu_scale(t_vu *x, t_floatarg fscale)
1140{
1141 int i, scale = (int)fscale;
1142
1143 if(scale != 0) scale = 1;
1144 if(x->x_scale && !scale)
1145 {
1146 t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
1147
1148 x->x_scale = (int)scale;
1149 if(glist_isvisible(x->x_gui.x_glist))
1150 {
1151 for(i=1; i<=IEM_VU_STEPS; i++)
1152 {
1153 if((i+2)&3)
1154 sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
1155 }
1156 i=IEM_VU_STEPS+1;
1157 sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
1158 }
1159 }
1160 if(!x->x_scale && scale)
1161 {
1162 int w4=x->x_gui.x_w/4, end=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w+4;
1163 int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
1164 int yyy, k4=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)-k3;
1165 t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
1166
1167 x->x_scale = (int)scale;
1168 if(glist_isvisible(x->x_gui.x_glist))
1169 {
1170 for(i=1; i<=IEM_VU_STEPS; i++)
1171 {
1172 yyy = k4 + k1*(k2-i);
1173 if((i+2)&3)
1174 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
1175 -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
1176 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
1177 x->x_gui.x_lcol, x, i);
1178 }
1179 i=IEM_VU_STEPS+1;
1180 yyy = k4 + k1*(k2-i);
1181 sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
1182 -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
1183 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
1184 x->x_gui.x_lcol, x, i);
1185 }
1186 }
1187}
1188
1189static void vu_properties(t_gobj *z, t_glist *owner)
1190{
1191 t_vu *x = (t_vu *)z;
1192 char buf[800];
1193 t_symbol *srl[3];
1194
1195 iemgui_properties(&x->x_gui, srl);
1196 sprintf(buf, "pdtk_iemgui_dialog %%s VU-METER \
1197 --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
1198 empty 0.0 empty 0.0 empty %d \
1199 %d no_scale scale %d %d empty %d \
1200 %s %s \
1201 %s %d %d \
1202 %d %d \
1203 %d %d %d\n",
1204 x->x_gui.x_w, IEM_GUI_MINSIZE, x->x_gui.x_h, IEM_VU_STEPS*IEM_VU_MINSIZE,
1205 0,/*no_schedule*/
1206 x->x_scale, -1, -1, -1,/*no linlog, no init, no multi*/
1207 "nosndno", srl[1]->s_name,/*no send*/
1208 srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
1209 x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
1210 0xffffff & x->x_gui.x_bcol, -1/*no front-color*/, 0xffffff & x->x_gui.x_lcol);
1211 gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
1212}
1213
1214static void vu_dialog(t_vu *x, t_symbol *s, int argc, t_atom *argv)
1215{
1216 t_symbol *srl[3];
1217 int w = (int)atom_getintarg(0, argc, argv);
1218 int h = (int)atom_getintarg(1, argc, argv);
1219 int scale = (int)atom_getintarg(4, argc, argv);
1220 int sr_flags;
1221
1222 srl[0] = gensym("empty");
1223 sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
1224 x->x_gui.x_fsf.x_snd_able = 0;
1225 x->x_gui.x_isa.x_loadinit = 0;
1226 x->x_gui.x_w = iemgui_clip_size(w);
1227 vu_check_height(x, h);
1228 if(scale != 0)
1229 scale = 1;
1230 vu_scale(x, (float)scale);
1231 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
1232 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
1233 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
1234 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
1235}
1236
1237static void vu_size(t_vu *x, t_symbol *s, int ac, t_atom *av)
1238{
1239 x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
1240 if(ac > 1)
1241 vu_check_height(x, (int)atom_getintarg(1, ac, av));
1242 if(glist_isvisible(x->x_gui.x_glist))
1243 {
1244 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
1245 (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
1246 canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
1247 }
1248}
1249
1250static void vu_delta(t_vu *x, t_symbol *s, int ac, t_atom *av)
1251{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
1252
1253static void vu_pos(t_vu *x, t_symbol *s, int ac, t_atom *av)
1254{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
1255
1256static void vu_color(t_vu *x, t_symbol *s, int ac, t_atom *av)
1257{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
1258
1259static void vu_receive(t_vu *x, t_symbol *s)
1260{iemgui_receive(x, &x->x_gui, s);}
1261
1262static void vu_label(t_vu *x, t_symbol *s)
1263{iemgui_label((void *)x, &x->x_gui, s);}
1264
1265static void vu_label_pos(t_vu *x, t_symbol *s, int ac, t_atom *av)
1266{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
1267
1268static void vu_label_font(t_vu *x, t_symbol *s, int ac, t_atom *av)
1269{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
1270
1271static void vu_float(t_vu *x, t_floatarg rms)
1272{
1273 int i;
1274
1275 if(rms <= IEM_VU_MINDB)
1276 x->x_rms = 0;
1277 else if(rms >= IEM_VU_MAXDB)
1278 x->x_rms = IEM_VU_STEPS;
1279 else
1280 {
1281 int i = (int)(2.0*(rms + IEM_VU_OFFSET));
1282 x->x_rms = iemgui_vu_db2i[i];
1283 }
1284 i = (int)(100.0*rms + 10000.5);
1285 rms = 0.01*(float)(i - 10000);
1286 x->x_fr = rms;
1287 outlet_float(x->x_out_rms, rms);
1288 vu_update_rms(x, x->x_gui.x_glist);
1289}
1290
1291static void vu_ft1(t_vu *x, t_floatarg peak)
1292{
1293 int i;
1294
1295 if(peak <= IEM_VU_MINDB)
1296 x->x_peak = 0;
1297 else if(peak >= IEM_VU_MAXDB)
1298 x->x_peak = IEM_VU_STEPS;
1299 else
1300 {
1301 int i = (int)(2.0*(peak + IEM_VU_OFFSET));
1302 x->x_peak = iemgui_vu_db2i[i];
1303 }
1304 i = (int)(100.0*peak + 10000.5);
1305 peak = 0.01*(float)(i - 10000);
1306 x->x_fp = peak;
1307 outlet_float(x->x_out_peak, peak);
1308 vu_update_peak(x, x->x_gui.x_glist);
1309}
1310
1311static void vu_bang(t_vu *x)
1312{
1313 outlet_float(x->x_out_peak, x->x_fp);
1314 outlet_float(x->x_out_rms, x->x_fr);
1315 vu_update_rms(x, x->x_gui.x_glist);
1316 vu_update_peak(x, x->x_gui.x_glist);
1317}
1318
1319static void *vu_new(t_symbol *s, int argc, t_atom *argv)
1320{
1321 t_vu *x = (t_vu *)pd_new(vu_class);
1322 int bflcol[]={-66577, -1, -1};
1323 int w=IEM_GUI_DEFAULTSIZE, h=IEM_VU_STEPS*IEM_VU_DEFAULTSIZE;
1324 int ldx=-1, ldy=-8, f=0, fs=8, scale=1;
1325 int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
1326 char str[144];
1327
1328 iem_inttosymargs(&x->x_gui.x_isa, 0);
1329 iem_inttofstyle(&x->x_gui.x_fsf, 0);
1330
1331 if((argc >= 11)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
1332 &&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2))
1333 &&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))
1334 &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
1335 &&IS_A_FLOAT(argv,6)&&IS_A_FLOAT(argv,7)
1336 &&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10))
1337 {
1338 w = (int)atom_getintarg(0, argc, argv);
1339 h = (int)atom_getintarg(1, argc, argv);
1340 iemgui_new_getnames(&x->x_gui, 1, argv);
1341 ldx = (int)atom_getintarg(4, argc, argv);
1342 ldy = (int)atom_getintarg(5, argc, argv);
1343 iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(6, argc, argv));
1344 fs = (int)atom_getintarg(7, argc, argv);
1345 bflcol[0] = (int)atom_getintarg(8, argc, argv);
1346 bflcol[2] = (int)atom_getintarg(9, argc, argv);
1347 scale = (int)atom_getintarg(10, argc, argv);
1348 }
1349 else iemgui_new_getnames(&x->x_gui, 1, 0);
1350 if((argc == 12)&&IS_A_FLOAT(argv,11))
1351 iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(11, argc, argv));
1352 x->x_gui.x_draw = (t_iemfunptr)vu_draw;
1353
1354 x->x_gui.x_fsf.x_snd_able = 0;
1355 x->x_gui.x_fsf.x_rcv_able = 1;
1356 x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
1357 if (!strcmp(x->x_gui.x_rcv->s_name, "empty"))
1358 x->x_gui.x_fsf.x_rcv_able = 0;
1359 if (x->x_gui.x_fsf.x_font_style == 1)
1360 strcpy(x->x_gui.x_font, "helvetica");
1361 else if(x->x_gui.x_fsf.x_font_style == 2)
1362 strcpy(x->x_gui.x_font, "times");
1363 else { x->x_gui.x_fsf.x_font_style = 0;
1364 strcpy(x->x_gui.x_font, "courier"); }
1365 if(x->x_gui.x_fsf.x_rcv_able)
1366 pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1367 x->x_gui.x_ldx = ldx;
1368 x->x_gui.x_ldy = ldy;
1369
1370 if(fs < 4)
1371 fs = 4;
1372 x->x_gui.x_fontsize = fs;
1373 x->x_gui.x_w = iemgui_clip_size(w);
1374 vu_check_height(x, h);
1375 iemgui_all_colfromload(&x->x_gui, bflcol);
1376 if(scale != 0)
1377 scale = 1;
1378 x->x_scale = scale;
1379 x->x_peak = 0;
1380 x->x_rms = 0;
1381 x->x_fp = -101.0;
1382 x->x_fr = -101.0;
1383 iemgui_verify_snd_ne_rcv(&x->x_gui);
1384 inlet_new(&x->x_gui.x_obj, &x->x_gui.x_obj.ob_pd, &s_float, gensym("ft1"));
1385 x->x_out_rms = outlet_new(&x->x_gui.x_obj, &s_float);
1386 x->x_out_peak = outlet_new(&x->x_gui.x_obj, &s_float);
1387 return (x);
1388}
1389
1390static void vu_free(t_vu *x)
1391{
1392 if(x->x_gui.x_fsf.x_rcv_able)
1393 pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
1394 gfxstub_deleteforkey(x);
1395}
1396
1397void g_vumeter_setup(void)
1398{
1399 vu_class = class_new(gensym("vu"), (t_newmethod)vu_new, (t_method)vu_free,
1400 sizeof(t_vu), 0, A_GIMME, 0);
1401 class_addbang(vu_class,vu_bang);
1402 class_addfloat(vu_class,vu_float);
1403 class_addmethod(vu_class, (t_method)vu_ft1, gensym("ft1"), A_FLOAT, 0);
1404 class_addmethod(vu_class, (t_method)vu_dialog, gensym("dialog"),
1405 A_GIMME, 0);
1406 class_addmethod(vu_class, (t_method)vu_size, gensym("size"), A_GIMME, 0);
1407 class_addmethod(vu_class, (t_method)vu_scale, gensym("scale"), A_DEFFLOAT, 0);
1408 class_addmethod(vu_class, (t_method)vu_delta, gensym("delta"), A_GIMME, 0);
1409 class_addmethod(vu_class, (t_method)vu_pos, gensym("pos"), A_GIMME, 0);
1410 class_addmethod(vu_class, (t_method)vu_color, gensym("color"), A_GIMME, 0);
1411 class_addmethod(vu_class, (t_method)vu_receive, gensym("receive"), A_DEFSYM, 0);
1412 class_addmethod(vu_class, (t_method)vu_label, gensym("label"), A_DEFSYM, 0);
1413 class_addmethod(vu_class, (t_method)vu_label_pos, gensym("label_pos"), A_GIMME, 0);
1414 class_addmethod(vu_class, (t_method)vu_label_font, gensym("label_font"), A_GIMME, 0);
1415 vu_widgetbehavior.w_getrectfn = vu_getrect;
1416 vu_widgetbehavior.w_displacefn = iemgui_displace;
1417 vu_widgetbehavior.w_selectfn = iemgui_select;
1418 vu_widgetbehavior.w_activatefn = NULL;
1419 vu_widgetbehavior.w_deletefn = iemgui_delete;
1420 vu_widgetbehavior.w_visfn = iemgui_vis;
1421 vu_widgetbehavior.w_clickfn = NULL;
1422 class_setwidget(vu_class,&vu_widgetbehavior);
1423 class_sethelpsymbol(vu_class, gensym("vu"));
1424 class_setsavefn(vu_class, vu_save);
1425 class_setpropertiesfn(vu_class, vu_properties);
1426}
diff --git a/apps/plugins/pdbox/PDa/src/m_atom.c b/apps/plugins/pdbox/PDa/src/m_atom.c
new file mode 100644
index 0000000000..a4b08ff2cb
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_atom.c
@@ -0,0 +1,258 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include "m_pd.h"
6#include <stdio.h>
7#include <string.h>
8
9 /* convenience routines for checking and getting values of
10 atoms. There's no "pointer" version since there's nothing
11 safe to return if there's an error. */
12
13t_float atom_getfloat(t_atom *a)
14{
15 if (a->a_type == A_FLOAT) return (a->a_w.w_float);
16 else return (0);
17}
18
19t_int atom_getint(t_atom *a)
20{
21 return (atom_getfloat(a));
22}
23
24t_symbol *atom_getsymbol(t_atom *a) /* LATER think about this more carefully */
25{
26 char buf[30];
27 if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol);
28 else return (&s_float);
29}
30
31t_symbol *atom_gensym(t_atom *a) /* this works better for graph labels */
32{
33 char buf[30];
34 if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol);
35 else if (a->a_type == A_FLOAT)
36 sprintf(buf, "%g", a->a_w.w_float);
37 else strcpy(buf, "???");
38 return (gensym(buf));
39}
40
41t_float atom_getfloatarg(int which, int argc, t_atom *argv)
42{
43 if (argc <= which) return (0);
44 argv += which;
45 if (argv->a_type == A_FLOAT) return (argv->a_w.w_float);
46 else return (0);
47}
48
49t_int atom_getintarg(int which, int argc, t_atom *argv)
50{
51 return (atom_getfloatarg(which, argc, argv));
52}
53
54t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv)
55{
56 if (argc <= which) return (&s_);
57 argv += which;
58 if (argv->a_type == A_SYMBOL) return (argv->a_w.w_symbol);
59 else return (&s_);
60}
61
62/* convert an atom into a string, in the reverse sense of binbuf_text (q.v.)
63* special attention is paid to symbols containing the special characters
64* ';', ',', '$', and '\'; these are quoted with a preceding '\', except that
65* the '$' only gets quoted at the beginning of the string.
66*/
67
68void atom_string(t_atom *a, char *buf, unsigned int bufsize)
69{
70 char tbuf[30];
71 switch(a->a_type)
72 {
73 case A_SEMI: strcpy(buf, ";"); break;
74 case A_COMMA: strcpy(buf, ","); break;
75 case A_POINTER:
76 strcpy(buf, "(pointer)");
77 break;
78 case A_FLOAT:
79 sprintf(tbuf, "%g", a->a_w.w_float);
80 if (strlen(tbuf) < bufsize-1) strcpy(buf, tbuf);
81 else if (a->a_w.w_float < 0) strcpy(buf, "-");
82 else strcat(buf, "+");
83 break;
84 case A_SYMBOL:
85 {
86 char *sp;
87 unsigned int len;
88 int quote;
89 for (sp = a->a_w.w_symbol->s_name, len = 0, quote = 0; *sp; sp++, len++)
90 if (*sp == ';' || *sp == ',' || *sp == '\\' ||
91 (*sp == '$' && sp == a->a_w.w_symbol->s_name && sp[1] >= '0'
92 && sp[1] <= '9'))
93 quote = 1;
94 if (quote)
95 {
96 char *bp = buf, *ep = buf + (bufsize-2);
97 sp = a->a_w.w_symbol->s_name;
98 while (bp < ep && *sp)
99 {
100 if (*sp == ';' || *sp == ',' || *sp == '\\' ||
101 (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
102 *bp++ = '\\';
103 *bp++ = *sp++;
104 }
105 if (*sp) *bp++ = '*';
106 *bp = 0;
107 /* post("quote %s -> %s", a->a_w.w_symbol->s_name, buf); */
108 }
109 else
110 {
111 if (len < bufsize-1) strcpy(buf, a->a_w.w_symbol->s_name);
112 else
113 {
114 strncpy(buf, a->a_w.w_symbol->s_name, bufsize - 2);
115 strcpy(buf + (bufsize - 2), "*");
116 }
117 }
118 }
119 break;
120 case A_DOLLAR:
121 sprintf(buf, "$%d", a->a_w.w_index);
122 break;
123 case A_DOLLSYM:
124 sprintf(buf, "$%s", a->a_w.w_symbol->s_name);
125 break;
126 default:
127 bug("atom_string");
128 }
129}
130/* Copyright (c) 1997-1999 Miller Puckette.
131* For information on usage and redistribution, and for a DISCLAIMER OF ALL
132* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
133
134#include "m_pd.h"
135#include <stdio.h>
136#include <string.h>
137
138 /* convenience routines for checking and getting values of
139 atoms. There's no "pointer" version since there's nothing
140 safe to return if there's an error. */
141
142t_float atom_getfloat(t_atom *a)
143{
144 if (a->a_type == A_FLOAT) return (a->a_w.w_float);
145 else return (0);
146}
147
148t_int atom_getint(t_atom *a)
149{
150 return (atom_getfloat(a));
151}
152
153t_symbol *atom_getsymbol(t_atom *a) /* LATER think about this more carefully */
154{
155 char buf[30];
156 if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol);
157 else return (&s_float);
158}
159
160t_symbol *atom_gensym(t_atom *a) /* this works better for graph labels */
161{
162 char buf[30];
163 if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol);
164 else if (a->a_type == A_FLOAT)
165 sprintf(buf, "%g", a->a_w.w_float);
166 else strcpy(buf, "???");
167 return (gensym(buf));
168}
169
170t_float atom_getfloatarg(int which, int argc, t_atom *argv)
171{
172 if (argc <= which) return (0);
173 argv += which;
174 if (argv->a_type == A_FLOAT) return (argv->a_w.w_float);
175 else return (0);
176}
177
178t_int atom_getintarg(int which, int argc, t_atom *argv)
179{
180 return (atom_getfloatarg(which, argc, argv));
181}
182
183t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv)
184{
185 if (argc <= which) return (&s_);
186 argv += which;
187 if (argv->a_type == A_SYMBOL) return (argv->a_w.w_symbol);
188 else return (&s_);
189}
190
191/* convert an atom into a string, in the reverse sense of binbuf_text (q.v.)
192* special attention is paid to symbols containing the special characters
193* ';', ',', '$', and '\'; these are quoted with a preceding '\', except that
194* the '$' only gets quoted at the beginning of the string.
195*/
196
197void atom_string(t_atom *a, char *buf, unsigned int bufsize)
198{
199 char tbuf[30];
200 switch(a->a_type)
201 {
202 case A_SEMI: strcpy(buf, ";"); break;
203 case A_COMMA: strcpy(buf, ","); break;
204 case A_POINTER:
205 strcpy(buf, "(pointer)");
206 break;
207 case A_FLOAT:
208 sprintf(tbuf, "%g", a->a_w.w_float);
209 if (strlen(tbuf) < bufsize-1) strcpy(buf, tbuf);
210 else if (a->a_w.w_float < 0) strcpy(buf, "-");
211 else strcat(buf, "+");
212 break;
213 case A_SYMBOL:
214 {
215 char *sp;
216 unsigned int len;
217 int quote;
218 for (sp = a->a_w.w_symbol->s_name, len = 0, quote = 0; *sp; sp++, len++)
219 if (*sp == ';' || *sp == ',' || *sp == '\\' ||
220 (*sp == '$' && sp == a->a_w.w_symbol->s_name && sp[1] >= '0'
221 && sp[1] <= '9'))
222 quote = 1;
223 if (quote)
224 {
225 char *bp = buf, *ep = buf + (bufsize-2);
226 sp = a->a_w.w_symbol->s_name;
227 while (bp < ep && *sp)
228 {
229 if (*sp == ';' || *sp == ',' || *sp == '\\' ||
230 (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
231 *bp++ = '\\';
232 *bp++ = *sp++;
233 }
234 if (*sp) *bp++ = '*';
235 *bp = 0;
236 /* post("quote %s -> %s", a->a_w.w_symbol->s_name, buf); */
237 }
238 else
239 {
240 if (len < bufsize-1) strcpy(buf, a->a_w.w_symbol->s_name);
241 else
242 {
243 strncpy(buf, a->a_w.w_symbol->s_name, bufsize - 2);
244 strcpy(buf + (bufsize - 2), "*");
245 }
246 }
247 }
248 break;
249 case A_DOLLAR:
250 sprintf(buf, "$%d", a->a_w.w_index);
251 break;
252 case A_DOLLSYM:
253 sprintf(buf, "$%s", a->a_w.w_symbol->s_name);
254 break;
255 default:
256 bug("atom_string");
257 }
258}
diff --git a/apps/plugins/pdbox/PDa/src/m_binbuf.c b/apps/plugins/pdbox/PDa/src/m_binbuf.c
new file mode 100644
index 0000000000..c215e399e6
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_binbuf.c
@@ -0,0 +1,2438 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5
6/* IOhannes :
7 * changed the canvas_restore in "g_canvas.c", so that it might accept $args as well (like "pd $0_test")
8 * so you can make multiple & distinguishable templates
9 * 1511:forum::für::umläute:2001
10 * change marked with IOhannes
11 */
12
13#include <stdlib.h>
14#include "m_pd.h"
15#include "s_stuff.h"
16#include <stdio.h>
17#ifdef UNIX
18#include <unistd.h>
19#endif
20#ifdef MSW
21#include <io.h>
22#endif
23#include <fcntl.h>
24#include <string.h>
25#include <stdarg.h>
26
27struct _binbuf
28{
29 int b_n;
30 t_atom *b_vec;
31};
32
33t_binbuf *binbuf_new(void)
34{
35 t_binbuf *x = (t_binbuf *)t_getbytes(sizeof(*x));
36 x->b_n = 0;
37 x->b_vec = t_getbytes(0);
38 return (x);
39}
40
41void binbuf_free(t_binbuf *x)
42{
43 t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec));
44 t_freebytes(x, sizeof(*x));
45}
46
47t_binbuf *binbuf_duplicate(t_binbuf *y)
48{
49 t_binbuf *x = (t_binbuf *)t_getbytes(sizeof(*x));
50 x->b_n = y->b_n;
51 x->b_vec = t_getbytes(x->b_n * sizeof(*x->b_vec));
52 memcpy(x->b_vec, y->b_vec, x->b_n * sizeof(*x->b_vec));
53 return (x);
54}
55
56void binbuf_clear(t_binbuf *x)
57{
58 x->b_vec = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec), 0);
59 x->b_n = 0;
60}
61
62 /* convert text to a binbuf */
63void binbuf_text(t_binbuf *x, char *text, size_t size)
64{
65 char buf[MAXPDSTRING+1], *bufp, *ebuf = buf+MAXPDSTRING;
66 const char *textp = text, *etext = text+size;
67 t_atom *ap;
68 int nalloc = 16, natom = 0;
69 t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec));
70 x->b_vec = t_getbytes(nalloc * sizeof(*x->b_vec));
71 ap = x->b_vec;
72 x->b_n = 0;
73 while (1)
74 {
75 int type;
76 /* skip leading space */
77 while ((textp != etext) && (*textp == ' ' || *textp == '\n'
78 || *textp == '\r' || *textp == '\t')) textp++;
79 if (textp == etext) break;
80 if (*textp == ';') SETSEMI(ap), textp++;
81 else if (*textp == ',') SETCOMMA(ap), textp++;
82 else
83 {
84 /* it's an atom other than a comma or semi */
85 char c;
86 int floatstate = 0, slash = 0, lastslash = 0,
87 firstslash = (*textp == '\\');
88 bufp = buf;
89 do
90 {
91 c = *bufp = *textp++;
92 lastslash = slash;
93 slash = (c == '\\');
94
95 if (floatstate >= 0)
96 {
97 int digit = (c >= '0' && c <= '9'),
98 dot = (c == '.'), minus = (c == '-'),
99 plusminus = (minus || (c == '+')),
100 expon = (c == 'e' || c == 'E');
101 if (floatstate == 0) /* beginning */
102 {
103 if (minus) floatstate = 1;
104 else if (digit) floatstate = 2;
105 else if (dot) floatstate = 3;
106 else floatstate = -1;
107 }
108 else if (floatstate == 1) /* got minus */
109 {
110 if (digit) floatstate = 2;
111 else if (dot) floatstate = 3;
112 else floatstate = -1;
113 }
114 else if (floatstate == 2) /* got digits */
115 {
116 if (dot) floatstate = 4;
117 else if (expon) floatstate = 6;
118 else if (!digit) floatstate = -1;
119 }
120 else if (floatstate == 3) /* got '.' without digits */
121 {
122 if (digit) floatstate = 5;
123 else floatstate = -1;
124 }
125 else if (floatstate == 4) /* got '.' after digits */
126 {
127 if (digit) floatstate = 5;
128 else if (expon) floatstate = 6;
129 else floatstate = -1;
130 }
131 else if (floatstate == 5) /* got digits after . */
132 {
133 if (expon) floatstate = 6;
134 else if (!digit) floatstate = -1;
135 }
136 else if (floatstate == 6) /* got 'e' */
137 {
138 if (plusminus) floatstate = 7;
139 else if (digit) floatstate = 8;
140 else floatstate = -1;
141 }
142 else if (floatstate == 7) /* got plus or minus */
143 {
144 if (digit) floatstate = 8;
145 else floatstate = -1;
146 }
147 else if (floatstate == 8) /* got digits */
148 {
149 if (!digit) floatstate = -1;
150 }
151 }
152 if (!slash) bufp++;
153 }
154 while (textp != etext && bufp != ebuf &&
155 (slash || (*textp != ' ' && *textp != '\n' && *textp != '\r'
156 && *textp != '\t' &&*textp != ',' && *textp != ';')));
157 *bufp = 0;
158#if 0
159 post("buf %s", buf);
160#endif
161 if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash)
162 {
163 for (bufp = buf+2; *bufp; bufp++)
164 if (*bufp < '0' || *bufp > '9')
165 {
166 SETDOLLSYM(ap, gensym(buf+1));
167 goto didit;
168 }
169 SETDOLLAR(ap, atoi(buf+1));
170 didit: ;
171 }
172 else
173 {
174 if (floatstate == 2 || floatstate == 4 || floatstate == 5 ||
175 floatstate == 8)
176 SETFLOAT(ap, atof(buf));
177 else SETSYMBOL(ap, gensym(buf));
178 }
179 }
180 ap++;
181 natom++;
182 if (natom == nalloc)
183 {
184 x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec),
185 nalloc * (2*sizeof(*x->b_vec)));
186 nalloc = nalloc * 2;
187 ap = x->b_vec + natom;
188 }
189 if (textp == etext) break;
190 }
191 /* reallocate the vector to exactly the right size */
192 x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec),
193 natom * sizeof(*x->b_vec));
194 x->b_n = natom;
195}
196
197 /* convert a binbuf to text; no null termination. */
198void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp)
199{
200 char *buf = getbytes(0), *newbuf;
201 int length = 0;
202 char string[MAXPDSTRING];
203 t_atom *ap;
204 int indx;
205
206 for (ap = x->b_vec, indx = x->b_n; indx--; ap++)
207 {
208 int newlength;
209 if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
210 length && buf[length-1] == ' ') length--;
211 atom_string(ap, string, MAXPDSTRING);
212 newlength = length + strlen(string) + 1;
213 if (!(newbuf = resizebytes(buf, length, newlength))) break;
214 buf = newbuf;
215 strcpy(buf + length, string);
216 length = newlength;
217 if (ap->a_type == A_SEMI) buf[length-1] = '\n';
218 else buf[length-1] = ' ';
219 }
220 if (length && buf[length-1] == ' ')
221 {
222 if (newbuf = t_resizebytes(buf, length, length-1))
223 {
224 buf = newbuf;
225 length--;
226 }
227 }
228 *bufp = buf;
229 *lengthp = length;
230}
231
232/* LATER improve the out-of-space behavior below. Also fix this so that
233writing to file doesn't buffer everything together. */
234
235void binbuf_add(t_binbuf *x, int argc, t_atom *argv)
236{
237 int newsize = x->b_n + argc, i;
238 t_atom *ap;
239 if (ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec),
240 newsize * sizeof(*x->b_vec)))
241 x->b_vec = ap;
242 else
243 {
244 error("binbuf_addmessage: out of space");
245 return;
246 }
247#if 0
248 startpost("binbuf_add: ");
249 postatom(argc, argv);
250 endpost();
251#endif
252 for (ap = x->b_vec + x->b_n, i = argc; i--; ap++)
253 *ap = *(argv++);
254 x->b_n = newsize;
255}
256
257#define MAXADDMESSV 100
258void binbuf_addv(t_binbuf *x, char *fmt, ...)
259{
260 va_list ap;
261 t_atom arg[MAXADDMESSV], *at =arg;
262 int nargs = 0;
263 char *fp = fmt;
264
265 va_start(ap, fmt);
266 while (1)
267 {
268 if (nargs >= MAXADDMESSV)
269 {
270 error("binbuf_addmessv: only %d allowed", MAXADDMESSV);
271 break;
272 }
273 switch(*fp++)
274 {
275 case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
276 case 'f': SETFLOAT(at, va_arg(ap, double)); break;
277 case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
278 case ';': SETSEMI(at); break;
279 case ',': SETCOMMA(at); break;
280 default: goto done;
281 }
282 at++;
283 nargs++;
284 }
285done:
286 va_end(ap);
287 binbuf_add(x, nargs, arg);
288}
289
290/* add a binbuf to another one for saving. Semicolons and commas go to
291symbols ";", "'",; the symbol ";" goes to "\;", etc. */
292
293void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y)
294{
295 t_binbuf *z = binbuf_new();
296 int i;
297 t_atom *ap;
298 binbuf_add(z, y->b_n, y->b_vec);
299 for (i = 0, ap = z->b_vec; i < z->b_n; i++, ap++)
300 {
301 char tbuf[MAXPDSTRING];
302 switch (ap->a_type)
303 {
304 case A_FLOAT:
305 break;
306 case A_SEMI:
307 SETSYMBOL(ap, gensym(";"));
308 break;
309 case A_COMMA:
310 SETSYMBOL(ap, gensym(","));
311 break;
312 case A_DOLLAR:
313 sprintf(tbuf, "$%d", ap->a_w.w_index);
314 SETSYMBOL(ap, gensym(tbuf));
315 break;
316 case A_DOLLSYM:
317 sprintf(tbuf, "$%s", ap->a_w.w_symbol->s_name);
318 SETSYMBOL(ap, gensym(tbuf));
319 break;
320 case A_SYMBOL:
321 /* FIXME make this general */
322 if (!strcmp(ap->a_w.w_symbol->s_name, ";"))
323 SETSYMBOL(ap, gensym(";"));
324 else if (!strcmp(ap->a_w.w_symbol->s_name, ","))
325 SETSYMBOL(ap, gensym(","));
326 break;
327 default:
328 bug("binbuf_addbinbuf");
329 }
330 }
331
332 binbuf_add(x, z->b_n, z->b_vec);
333}
334
335void binbuf_addsemi(t_binbuf *x)
336{
337 t_atom a;
338 SETSEMI(&a);
339 binbuf_add(x, 1, &a);
340}
341
342/* Supply atoms to a binbuf from a message, making the opposite changes
343from binbuf_addbinbuf. The symbol ";" goes to a semicolon, etc. */
344
345void binbuf_restore(t_binbuf *x, int argc, t_atom *argv)
346{
347 int newsize = x->b_n + argc, i;
348 t_atom *ap;
349 if (ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec),
350 newsize * sizeof(*x->b_vec)))
351 x->b_vec = ap;
352 else
353 {
354 error("binbuf_addmessage: out of space");
355 return;
356 }
357
358 for (ap = x->b_vec + x->b_n, i = argc; i--; ap++)
359 {
360 if (argv->a_type == A_SYMBOL)
361 {
362 char *str = argv->a_w.w_symbol->s_name;
363 if (!strcmp(str, ";")) SETSEMI(ap);
364 else if (!strcmp(str, ",")) SETCOMMA(ap);
365 else if (str[0] == '$' && str[1] >= '0' && str[1] <= '9')
366 {
367 int dollsym = 0;
368 char *str2;
369 for (str2 = str + 2; *str2; str2++)
370 if (*str2 < '0' || *str2 > '9')
371 dollsym = 1;
372 if (dollsym)
373 SETDOLLSYM(ap, gensym(str + 1));
374 else
375 {
376 int dollar = 0;
377 sscanf(argv->a_w.w_symbol->s_name + 1, "%d", &dollar);
378 SETDOLLAR(ap, dollar);
379 }
380 }
381 else *ap = *argv;
382 argv++;
383 }
384 else *ap = *(argv++);
385 }
386 x->b_n = newsize;
387}
388
389
390#define MSTACKSIZE 2048
391
392void binbuf_print(t_binbuf *x)
393{
394 int i, startedpost = 0, newline = 1;
395 for (i = 0; i < x->b_n; i++)
396 {
397 if (newline)
398 {
399 if (startedpost) endpost();
400 startpost("");
401 startedpost = 1;
402 }
403 postatom(1, x->b_vec + i);
404 if (x->b_vec[i].a_type == A_SEMI)
405 newline = 1;
406 else newline = 0;
407 }
408 if (startedpost) endpost();
409}
410
411int binbuf_getnatom(t_binbuf *x)
412{
413 return (x->b_n);
414}
415
416t_atom *binbuf_getvec(t_binbuf *x)
417{
418 return (x->b_vec);
419}
420
421int canvas_getdollarzero( void);
422
423t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew)
424{
425 int argno = atol(s->s_name), lastnum;
426 char buf[MAXPDSTRING], c, *sp;
427 for (lastnum = 0, sp = s->s_name; ((c = *sp) && c >= '0' && c <= '9');
428 sp++, lastnum++)
429 if (!c || argno < 0 || argno > ac)
430 {
431 if (!tonew)
432 return (0);
433 else sprintf(buf, "$%d", argno);
434 }
435 else if (argno == 0)
436 sprintf(buf, "%d", canvas_getdollarzero());
437 else
438 atom_string(av+(argno-1), buf, MAXPDSTRING/2-1);
439 strncat(buf, sp, MAXPDSTRING/2-1);
440 return (gensym(buf));
441}
442
443void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv)
444{
445 static t_atom mstack[MSTACKSIZE], *msp = mstack, *ems = mstack+MSTACKSIZE;
446 t_atom *stackwas = msp;
447 t_atom *at = x->b_vec;
448 int ac = x->b_n;
449 int nargs;
450 while (1)
451 {
452 t_pd *nexttarget;
453 /* get a target. */
454 while (!target)
455 {
456 t_symbol *s;
457 while (ac && (at->a_type == A_SEMI || at->a_type == A_COMMA))
458 ac--, at++;
459 if (!ac) break;
460 if (at->a_type == A_DOLLAR)
461 {
462 if (at->a_w.w_index <= 0 || at->a_w.w_index > argc)
463 {
464 error("$%d: not enough arguments supplied",
465 at->a_w.w_index);
466 goto cleanup;
467 }
468 else if (argv[at->a_w.w_index-1].a_type != A_SYMBOL)
469 {
470 error("$%d: symbol needed as message destination",
471 at->a_w.w_index);
472 goto cleanup;
473 }
474 else s = argv[at->a_w.w_index-1].a_w.w_symbol;
475 }
476 else if (at->a_type == A_DOLLSYM)
477 {
478 if (!(s = binbuf_realizedollsym(at->a_w.w_symbol,
479 argc, argv, 0)))
480 {
481 error("$%s: not enough arguments supplied",
482 at->a_w.w_symbol->s_name);
483 goto cleanup;
484 }
485 }
486 else s = atom_getsymbol(at);
487 if (!(target = s->s_thing))
488 {
489 error("%s: no such object", s->s_name);
490 cleanup:
491 do at++, ac--;
492 while (ac && at->a_type != A_SEMI);
493 /* LATER eat args until semicolon and continue */
494 continue;
495 }
496 else
497 {
498 at++, ac--;
499 break;
500 }
501 }
502 if (!ac) break;
503 nargs = 0;
504 nexttarget = target;
505 while (1)
506 {
507 t_symbol *s9;
508 if (!ac) goto gotmess;
509 if (msp >= ems)
510 {
511 error("message stack overflow");
512 goto broken;
513 }
514 switch (at->a_type)
515 {
516 case A_SEMI:
517 /* semis and commas in new message just get bashed to
518 a symbol. This is needed so you can pass them to "expr." */
519 if (target == &pd_objectmaker)
520 {
521 SETSYMBOL(msp, gensym(";"));
522 break;
523 }
524 else
525 {
526 nexttarget = 0;
527 goto gotmess;
528 }
529 case A_COMMA:
530 if (target == &pd_objectmaker)
531 {
532 SETSYMBOL(msp, gensym(","));
533 break;
534 }
535 else goto gotmess;
536 case A_FLOAT:
537 case A_SYMBOL:
538 *msp = *at;
539 break;
540 case A_DOLLAR:
541 if (at->a_w.w_index > 0 && at->a_w.w_index <= argc)
542 *msp = argv[at->a_w.w_index-1];
543 else if (at->a_w.w_index == 0)
544 SETFLOAT(msp, canvas_getdollarzero());
545 else
546 {
547 if (target == &pd_objectmaker)
548 SETFLOAT(msp, 0);
549 else
550 {
551 error("$%d: argument number out of range",
552 at->a_w.w_index);
553 SETFLOAT(msp, 0);
554 }
555 }
556 break;
557 case A_DOLLSYM:
558 s9 = binbuf_realizedollsym(at->a_w.w_symbol, argc, argv,
559 target == &pd_objectmaker);
560 if (!s9)
561 goto broken;
562 SETSYMBOL(msp, s9);
563 break;
564 default:
565 bug("bad item in binbuf");
566 goto broken;
567 }
568 msp++;
569 ac--;
570 at++;
571 nargs++;
572 }
573 gotmess:
574 if (nargs)
575 {
576 switch (stackwas->a_type)
577 {
578 case A_SYMBOL:
579 typedmess(target, stackwas->a_w.w_symbol, nargs-1, stackwas+1);
580 break;
581 case A_FLOAT:
582 if (nargs == 1) pd_float(target, stackwas->a_w.w_float);
583 else pd_list(target, 0, nargs, stackwas);
584 break;
585 }
586 }
587 msp = stackwas;
588 if (!ac) break;
589 target = nexttarget;
590 at++;
591 ac--;
592 }
593
594 return;
595broken:
596 msp = stackwas;
597}
598
599static int binbuf_doopen(char *s, int mode)
600{
601 char namebuf[MAXPDSTRING];
602#ifdef MSW
603 mode |= O_BINARY;
604#endif
605 sys_bashfilename(s, namebuf);
606 return (open(namebuf, mode));
607}
608
609static FILE *binbuf_dofopen(char *s, char *mode)
610{
611 char namebuf[MAXPDSTRING];
612 sys_bashfilename(s, namebuf);
613 return (fopen(namebuf, mode));
614}
615
616int binbuf_read(t_binbuf *b, char *filename, char *dirname, int crflag)
617{
618 long length;
619 int fd;
620 int readret;
621 char *buf;
622 char namebuf[MAXPDSTRING];
623
624 namebuf[0] = 0;
625 if (*dirname)
626 strcat(namebuf, dirname), strcat(namebuf, "/");
627 strcat(namebuf, filename);
628
629 if ((fd = binbuf_doopen(namebuf, 0)) < 0)
630 {
631 fprintf(stderr, "open: ");
632 perror(namebuf);
633 return (1);
634 }
635 if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0, SEEK_SET) < 0
636 || !(buf = t_getbytes(length)))
637 {
638 fprintf(stderr, "lseek: ");
639 perror(namebuf);
640 close(fd);
641 return(1);
642 }
643 if ((readret = read(fd, buf, length)) < length)
644 {
645 fprintf(stderr, "read (%d %ld) -> %d\n", fd, length, readret);
646 perror(namebuf);
647 close(fd);
648 t_freebytes(buf, length);
649 return(1);
650 }
651 /* optionally map carriage return to semicolon */
652 if (crflag)
653 {
654 int i;
655 for (i = 0; i < length; i++)
656 if (buf[i] == '\n')
657 buf[i] = ';';
658 }
659 binbuf_text(b, buf, length);
660
661#if 0
662 startpost("binbuf_read "); postatom(b->b_n, b->b_vec); endpost();
663#endif
664
665 t_freebytes(buf, length);
666 close(fd);
667 return (0);
668}
669
670int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
671 int crflag)
672{
673 int filedesc;
674 char buf[MAXPDSTRING], *bufptr;
675 if ((filedesc = open_via_path(
676 dirname, filename, "", buf, &bufptr, MAXPDSTRING, 0)) < 0)
677 {
678 error("%s: can't open", filename);
679 return (1);
680 }
681 else close (filedesc);
682 if (binbuf_read(b, bufptr, buf, crflag))
683 return (1);
684 else return (0);
685}
686
687#define WBUFSIZE 4096
688static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd);
689
690 /* write a binbuf to a text file. If "crflag" is set we suppress
691 semicolons. */
692int binbuf_write(t_binbuf *x, char *filename, char *dir, int crflag)
693{
694 FILE *f = 0;
695 char sbuf[WBUFSIZE], fbuf[MAXPDSTRING], *bp = sbuf, *ep = sbuf + WBUFSIZE;
696 t_atom *ap;
697 int indx, deleteit = 0;
698 int ncolumn = 0;
699
700 fbuf[0] = 0;
701 if (*dir)
702 strcat(fbuf, dir), strcat(fbuf, "/");
703 strcat(fbuf, filename);
704 if (!strcmp(filename + strlen(filename) - 4, ".pat"))
705 {
706 x = binbuf_convert(x, 0);
707 deleteit = 1;
708 }
709
710 if (!(f = binbuf_dofopen(fbuf, "w")))
711 {
712 fprintf(stderr, "open: ");
713 sys_unixerror(fbuf);
714 goto fail;
715 }
716 for (ap = x->b_vec, indx = x->b_n; indx--; ap++)
717 {
718 int length;
719 /* estimate how many characters will be needed. Printing out
720 symbols may need extra characters for inserting backslashes. */
721 if (ap->a_type == A_SYMBOL || ap->a_type == A_DOLLSYM)
722 length = 80 + strlen(ap->a_w.w_symbol->s_name);
723 else length = 40;
724 if (ep - bp < length)
725 {
726 if (fwrite(sbuf, bp-sbuf, 1, f) < 1)
727 {
728 sys_unixerror(fbuf);
729 goto fail;
730 }
731 bp = sbuf;
732 }
733 if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
734 bp > sbuf && bp[-1] == ' ') bp--;
735 if (!crflag || ap->a_type != A_SEMI)
736 {
737 atom_string(ap, bp, (ep-bp)-2);
738 length = strlen(bp);
739 bp += length;
740 ncolumn += length;
741 }
742 if (ap->a_type == A_SEMI || (!crflag && ncolumn > 65))
743 {
744 *bp++ = '\n';
745 ncolumn = 0;
746 }
747 else
748 {
749 *bp++ = ' ';
750 ncolumn++;
751 }
752 }
753 if (fwrite(sbuf, bp-sbuf, 1, f) < 1)
754 {
755 sys_unixerror(fbuf);
756 goto fail;
757 }
758 if (deleteit)
759 binbuf_free(x);
760 fclose(f);
761 return (0);
762fail:
763 if (deleteit)
764 binbuf_free(x);
765 if (f)
766 fclose(f);
767 return (1);
768}
769
770/* The following routine attempts to convert from max to pd or back. The
771max to pd direction is working OK but you will need to make lots of
772abstractions for objects like "gate" which don't exist in Pd. conversion
773from Pd to Max hasn't been tested for patches with subpatches yet! */
774
775#define MAXSTACK 1000
776
777#define ISSYMBOL(a, b) ((a)->a_type == A_SYMBOL && \
778 !strcmp((a)->a_w.w_symbol->s_name, (b)))
779
780static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
781{
782 t_binbuf *newb = binbuf_new();
783 t_atom *vec = oldb->b_vec;
784 t_int n = oldb->b_n, nextindex, stackdepth = 0, stack[MAXSTACK],
785 nobj = 0, i;
786 t_atom outmess[MAXSTACK], *nextmess;
787 if (!maxtopd)
788 binbuf_addv(newb, "ss;", gensym("max"), gensym("v2"));
789 for (nextindex = 0; nextindex < n; )
790 {
791 int endmess, natom;
792 char *first, *second;
793 for (endmess = nextindex; endmess < n && vec[endmess].a_type != A_SEMI;
794 endmess++)
795 ;
796 if (endmess == n) break;
797 if (endmess == nextindex || endmess == nextindex + 1
798 || vec[nextindex].a_type != A_SYMBOL ||
799 vec[nextindex+1].a_type != A_SYMBOL)
800 {
801 nextindex = endmess + 1;
802 continue;
803 }
804 natom = endmess - nextindex;
805 if (natom > MAXSTACK-10) natom = MAXSTACK-10;
806 nextmess = vec + nextindex;
807 first = nextmess->a_w.w_symbol->s_name;
808 second = (nextmess+1)->a_w.w_symbol->s_name;
809 if (maxtopd)
810 {
811 /* case 1: importing a ".pat" file into Pd. */
812
813 /* dollar signs in file translate to symbols */
814 for (i = 0; i < natom; i++)
815 {
816 if (nextmess[i].a_type == A_DOLLAR)
817 {
818 char buf[100];
819 sprintf(buf, "$%d", nextmess[i].a_w.w_index);
820 SETSYMBOL(nextmess+i, gensym(buf));
821 }
822 else if (nextmess[i].a_type == A_DOLLSYM)
823 {
824 char buf[100];
825 sprintf(buf, "$%s", nextmess[i].a_w.w_symbol->s_name);
826 SETSYMBOL(nextmess+i, gensym(buf));
827 }
828 }
829 if (!strcmp(first, "#N"))
830 {
831 if (!strcmp(second, "vpatcher"))
832 {
833 if (stackdepth >= MAXSTACK)
834 {
835 post("too many embedded patches");
836 return (newb);
837 }
838 stack[stackdepth] = nobj;
839 stackdepth++;
840 nobj = 0;
841 binbuf_addv(newb, "ssfffff;",
842 gensym("#N"), gensym("canvas"),
843 atom_getfloatarg(2, natom, nextmess),
844 atom_getfloatarg(3, natom, nextmess),
845 atom_getfloatarg(4, natom, nextmess) -
846 atom_getfloatarg(2, natom, nextmess),
847 atom_getfloatarg(5, natom, nextmess) -
848 atom_getfloatarg(3, natom, nextmess),
849 (float)sys_defaultfont);
850 }
851 }
852 if (!strcmp(first, "#P"))
853 {
854 /* drop initial "hidden" flag */
855 if (!strcmp(second, "hidden"))
856 {
857 nextmess++;
858 natom--;
859 second = (nextmess+1)->a_w.w_symbol->s_name;
860 }
861 if (natom >= 7 && !strcmp(second, "newobj")
862 && (ISSYMBOL(&nextmess[6], "patcher") ||
863 ISSYMBOL(&nextmess[6], "p")))
864 {
865 binbuf_addv(newb, "ssffss;",
866 gensym("#X"), gensym("restore"),
867 atom_getfloatarg(2, natom, nextmess),
868 atom_getfloatarg(3, natom, nextmess),
869 gensym("pd"), atom_getsymbolarg(7, natom, nextmess));
870 if (stackdepth) stackdepth--;
871 nobj = stack[stackdepth];
872 nobj++;
873 }
874 else if (!strcmp(second, "newex") || !strcmp(second, "newobj"))
875 {
876 t_symbol *classname =
877 atom_getsymbolarg(6, natom, nextmess);
878 if (classname == gensym("trigger") ||
879 classname == gensym("t"))
880 {
881 for (i = 7; i < natom; i++)
882 if (nextmess[i].a_type == A_SYMBOL &&
883 nextmess[i].a_w.w_symbol == gensym("i"))
884 nextmess[i].a_w.w_symbol = gensym("f");
885 }
886 if (classname == gensym("table"))
887 classname = gensym("TABLE");
888 SETSYMBOL(outmess, gensym("#X"));
889 SETSYMBOL(outmess + 1, gensym("obj"));
890 outmess[2] = nextmess[2];
891 outmess[3] = nextmess[3];
892 SETSYMBOL(outmess+4, classname);
893 for (i = 7; i < natom; i++)
894 outmess[i-2] = nextmess[i];
895 SETSEMI(outmess + natom - 2);
896 binbuf_add(newb, natom - 1, outmess);
897 nobj++;
898 }
899 else if (!strcmp(second, "message") ||
900 !strcmp(second, "comment"))
901 {
902 SETSYMBOL(outmess, gensym("#X"));
903 SETSYMBOL(outmess + 1, gensym(
904 (strcmp(second, "message") ? "text" : "msg")));
905 outmess[2] = nextmess[2];
906 outmess[3] = nextmess[3];
907 for (i = 6; i < natom; i++)
908 outmess[i-2] = nextmess[i];
909 SETSEMI(outmess + natom - 2);
910 binbuf_add(newb, natom - 1, outmess);
911 nobj++;
912 }
913 else if (!strcmp(second, "button"))
914 {
915 binbuf_addv(newb, "ssffs;",
916 gensym("#X"), gensym("obj"),
917 atom_getfloatarg(2, natom, nextmess),
918 atom_getfloatarg(3, natom, nextmess),
919 gensym("bng"));
920 nobj++;
921 }
922 else if (!strcmp(second, "number") || !strcmp(second, "flonum"))
923 {
924 binbuf_addv(newb, "ssff;",
925 gensym("#X"), gensym("floatatom"),
926 atom_getfloatarg(2, natom, nextmess),
927 atom_getfloatarg(3, natom, nextmess));
928 nobj++;
929 }
930 else if (!strcmp(second, "slider"))
931 {
932 float inc = atom_getfloatarg(7, natom, nextmess);
933 if (inc <= 0)
934 inc = 1;
935 binbuf_addv(newb, "ssffsffffffsssfffffffff;",
936 gensym("#X"), gensym("obj"),
937 atom_getfloatarg(2, natom, nextmess),
938 atom_getfloatarg(3, natom, nextmess),
939 gensym("vsl"),
940 atom_getfloatarg(4, natom, nextmess),
941 atom_getfloatarg(5, natom, nextmess),
942 atom_getfloatarg(6, natom, nextmess),
943 atom_getfloatarg(6, natom, nextmess)
944 + (atom_getfloatarg(5, natom, nextmess) - 1) * inc,
945 0., 0.,
946 gensym("empty"), gensym("empty"), gensym("empty"),
947 0., -8., 0., 8., -262144., -1., -1., 0., 1.);
948 nobj++;
949 }
950 else if (!strcmp(second, "toggle"))
951 {
952 binbuf_addv(newb, "ssffs;",
953 gensym("#X"), gensym("obj"),
954 atom_getfloatarg(2, natom, nextmess),
955 atom_getfloatarg(3, natom, nextmess),
956 gensym("tgl"));
957 nobj++;
958 }
959 else if (!strcmp(second, "inlet"))
960 {
961 binbuf_addv(newb, "ssffs;",
962 gensym("#X"), gensym("obj"),
963 atom_getfloatarg(2, natom, nextmess),
964 atom_getfloatarg(3, natom, nextmess),
965 gensym((natom > 5 ? "inlet~" : "inlet")));
966 nobj++;
967 }
968 else if (!strcmp(second, "outlet"))
969 {
970 binbuf_addv(newb, "ssffs;",
971 gensym("#X"), gensym("obj"),
972 atom_getfloatarg(2, natom, nextmess),
973 atom_getfloatarg(3, natom, nextmess),
974 gensym((natom > 5 ? "outlet~" : "outlet")));
975 nobj++;
976 }
977 else if (!strcmp(second, "user"))
978 {
979 binbuf_addv(newb, "ssffs;",
980 gensym("#X"), gensym("obj"),
981 atom_getfloatarg(3, natom, nextmess),
982 atom_getfloatarg(4, natom, nextmess),
983 atom_getsymbolarg(2, natom, nextmess));
984 nobj++;
985 }
986 else if (!strcmp(second, "connect")||
987 !strcmp(second, "fasten"))
988 {
989 binbuf_addv(newb, "ssffff;",
990 gensym("#X"), gensym("connect"),
991 nobj - atom_getfloatarg(2, natom, nextmess) - 1,
992 atom_getfloatarg(3, natom, nextmess),
993 nobj - atom_getfloatarg(4, natom, nextmess) - 1,
994 atom_getfloatarg(5, natom, nextmess));
995 }
996 }
997 }
998 else /* Pd to Max */
999 {
1000 if (!strcmp(first, "#N"))
1001 {
1002 if (!strcmp(second, "canvas"))
1003 {
1004 if (stackdepth >= MAXSTACK)
1005 {
1006 post("too many embedded patches");
1007 return (newb);
1008 }
1009 stack[stackdepth] = nobj;
1010 stackdepth++;
1011 nobj = 0;
1012 binbuf_addv(newb, "ssffff;",
1013 gensym("#N"), gensym("vpatcher"),
1014 atom_getfloatarg(2, natom, nextmess),
1015 atom_getfloatarg(3, natom, nextmess),
1016 atom_getfloatarg(4, natom, nextmess),
1017 atom_getfloatarg(5, natom, nextmess));
1018 }
1019 }
1020 if (!strcmp(first, "#X"))
1021 {
1022 if (natom >= 5 && !strcmp(second, "restore")
1023 && (ISSYMBOL (&nextmess[4], "pd")))
1024 {
1025 binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
1026 binbuf_addv(newb, "ssffffss;",
1027 gensym("#P"), gensym("newobj"),
1028 atom_getfloatarg(2, natom, nextmess),
1029 atom_getfloatarg(3, natom, nextmess), 50., 1.,
1030 gensym("patcher"),
1031 atom_getsymbolarg(5, natom, nextmess));
1032 if (stackdepth) stackdepth--;
1033 nobj = stack[stackdepth];
1034 nobj++;
1035 }
1036 else if (!strcmp(second, "obj"))
1037 {
1038 t_symbol *classname =
1039 atom_getsymbolarg(4, natom, nextmess);
1040 if (classname == gensym("inlet"))
1041 binbuf_addv(newb, "ssfff;", gensym("#P"),
1042 gensym("inlet"),
1043 atom_getfloatarg(2, natom, nextmess),
1044 atom_getfloatarg(3, natom, nextmess),
1045 15.);
1046 else if (classname == gensym("inlet~"))
1047 binbuf_addv(newb, "ssffff;", gensym("#P"),
1048 gensym("inlet"),
1049 atom_getfloatarg(2, natom, nextmess),
1050 atom_getfloatarg(3, natom, nextmess),
1051 15., 1.);
1052 else if (classname == gensym("outlet"))
1053 binbuf_addv(newb, "ssfff;", gensym("#P"),
1054 gensym("outlet"),
1055 atom_getfloatarg(2, natom, nextmess),
1056 atom_getfloatarg(3, natom, nextmess),
1057 15.);
1058 else if (classname == gensym("outlet~"))
1059 binbuf_addv(newb, "ssffff;", gensym("#P"),
1060 gensym("outlet"),
1061 atom_getfloatarg(2, natom, nextmess),
1062 atom_getfloatarg(3, natom, nextmess),
1063 15., 1.);
1064 else if (classname == gensym("bng"))
1065 binbuf_addv(newb, "ssffff;", gensym("#P"),
1066 gensym("button"),
1067 atom_getfloatarg(2, natom, nextmess),
1068 atom_getfloatarg(3, natom, nextmess),
1069 atom_getfloatarg(5, natom, nextmess), 0.);
1070 else if (classname == gensym("tgl"))
1071 binbuf_addv(newb, "ssffff;", gensym("#P"),
1072 gensym("toggle"),
1073 atom_getfloatarg(2, natom, nextmess),
1074 atom_getfloatarg(3, natom, nextmess),
1075 atom_getfloatarg(5, natom, nextmess), 0.);
1076 else if (classname == gensym("vsl"))
1077 binbuf_addv(newb, "ssffffff;", gensym("#P"),
1078 gensym("slider"),
1079 atom_getfloatarg(2, natom, nextmess),
1080 atom_getfloatarg(3, natom, nextmess),
1081 atom_getfloatarg(5, natom, nextmess),
1082 atom_getfloatarg(6, natom, nextmess),
1083 (atom_getfloatarg(8, natom, nextmess) -
1084 atom_getfloatarg(7, natom, nextmess)) /
1085 (atom_getfloatarg(6, natom, nextmess) == 1? 1 :
1086 atom_getfloatarg(6, natom, nextmess) - 1),
1087 atom_getfloatarg(7, natom, nextmess));
1088 else
1089 {
1090 SETSYMBOL(outmess, gensym("#P"));
1091 SETSYMBOL(outmess + 1, gensym("newex"));
1092 outmess[2] = nextmess[2];
1093 outmess[3] = nextmess[3];
1094 SETFLOAT(outmess + 4, 50);
1095 SETFLOAT(outmess + 5, 1);
1096 for (i = 4; i < natom; i++)
1097 outmess[i+2] = nextmess[i];
1098 SETSEMI(outmess + natom + 2);
1099 binbuf_add(newb, natom + 3, outmess);
1100 }
1101 nobj++;
1102
1103 }
1104 else if (!strcmp(second, "msg") ||
1105 !strcmp(second, "text"))
1106 {
1107 SETSYMBOL(outmess, gensym("#P"));
1108 SETSYMBOL(outmess + 1, gensym(
1109 (strcmp(second, "msg") ? "comment" : "message")));
1110 outmess[2] = nextmess[2];
1111 outmess[3] = nextmess[3];
1112 SETFLOAT(outmess + 4, 50);
1113 SETFLOAT(outmess + 5, 1);
1114 for (i = 4; i < natom; i++)
1115 outmess[i+2] = nextmess[i];
1116 SETSEMI(outmess + natom + 2);
1117 binbuf_add(newb, natom + 3, outmess);
1118 nobj++;
1119 }
1120 else if (!strcmp(second, "floatatom"))
1121 {
1122 binbuf_addv(newb, "ssfff;",
1123 gensym("#P"), gensym("flonum"),
1124 atom_getfloatarg(2, natom, nextmess),
1125 atom_getfloatarg(3, natom, nextmess), 35);
1126 nobj++;
1127 }
1128 else if (!strcmp(second, "connect"))
1129 {
1130 binbuf_addv(newb, "ssffff;",
1131 gensym("#P"), gensym("connect"),
1132 nobj - atom_getfloatarg(2, natom, nextmess) - 1,
1133 atom_getfloatarg(3, natom, nextmess),
1134 nobj - atom_getfloatarg(4, natom, nextmess) - 1,
1135 atom_getfloatarg(5, natom, nextmess));
1136 }
1137 }
1138 }
1139 nextindex = endmess + 1;
1140 }
1141 if (!maxtopd)
1142 binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
1143#if 0
1144 binbuf_write(newb, "import-result.pd", "/tmp", 0);
1145#endif
1146 return (newb);
1147}
1148
1149 /* function to support searching */
1150int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf)
1151{
1152 int indexin, nmatched;
1153 for (indexin = 0; indexin <= inbuf->b_n - searchbuf->b_n; indexin++)
1154 {
1155 for (nmatched = 0; nmatched < searchbuf->b_n; nmatched++)
1156 {
1157 t_atom *a1 = &inbuf->b_vec[indexin + nmatched],
1158 *a2 = &searchbuf->b_vec[nmatched];
1159 if (a1->a_type != a2->a_type ||
1160 a1->a_type == A_SYMBOL && a1->a_w.w_symbol != a2->a_w.w_symbol
1161 ||
1162 a1->a_type == A_FLOAT && a1->a_w.w_float != a2->a_w.w_float
1163 ||
1164 a1->a_type == A_DOLLAR && a1->a_w.w_index != a2->a_w.w_index
1165 ||
1166 a1->a_type == A_DOLLSYM && a1->a_w.w_symbol != a2->a_w.w_symbol)
1167 goto nomatch;
1168 }
1169 return (1);
1170 nomatch: ;
1171 }
1172 return (0);
1173}
1174
1175void pd_doloadbang(void);
1176
1177/* LATER make this evaluate the file on-the-fly. */
1178/* LATER figure out how to log errors */
1179void binbuf_evalfile(t_symbol *name, t_symbol *dir)
1180{
1181 t_binbuf *b = binbuf_new();
1182 int import = !strcmp(name->s_name + strlen(name->s_name) - 4, ".pat");
1183 /* set filename so that new canvases can pick them up */
1184 int dspstate = canvas_suspend_dsp();
1185 glob_setfilename(0, name, dir);
1186 if (binbuf_read(b, name->s_name, dir->s_name, 0))
1187 {
1188 perror(name->s_name);
1189 }
1190 else
1191 {
1192 if (import)
1193 {
1194 t_binbuf *newb = binbuf_convert(b, 1);
1195 binbuf_free(b);
1196 b = newb;
1197 }
1198 binbuf_eval(b, 0, 0, 0);
1199 }
1200 glob_setfilename(0, &s_, &s_); /* bug fix by Krzysztof Czaja */
1201 binbuf_free(b);
1202 canvas_resume_dsp(dspstate);
1203}
1204
1205void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir)
1206{
1207 t_pd *x = 0;
1208 /* even though binbuf_evalfile appears to take care of dspstate,
1209 we have to do it again here, because canvas_startdsp() assumes
1210 that all toplevel canvases are visible. LATER check if this
1211 is still necessary -- probably not. */
1212
1213 int dspstate = canvas_suspend_dsp();
1214 binbuf_evalfile(name, dir);
1215 while ((x != s__X.s_thing) && (x = s__X.s_thing))
1216 vmess(x, gensym("pop"), "i", 1);
1217 pd_doloadbang();
1218 canvas_resume_dsp(dspstate);
1219}
1220/* Copyright (c) 1997-1999 Miller Puckette.
1221* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1222* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1223
1224
1225/* IOhannes :
1226 * changed the canvas_restore in "g_canvas.c", so that it might accept $args as well (like "pd $0_test")
1227 * so you can make multiple & distinguishable templates
1228 * 1511:forum::für::umläute:2001
1229 * change marked with IOhannes
1230 */
1231
1232#include <stdlib.h>
1233#include "m_pd.h"
1234#include "s_stuff.h"
1235#include <stdio.h>
1236#ifdef UNIX
1237#include <unistd.h>
1238#endif
1239#ifdef MSW
1240#include <io.h>
1241#endif
1242#include <fcntl.h>
1243#include <string.h>
1244#include <stdarg.h>
1245
1246struct _binbuf
1247{
1248 int b_n;
1249 t_atom *b_vec;
1250};
1251
1252t_binbuf *binbuf_new(void)
1253{
1254 t_binbuf *x = (t_binbuf *)t_getbytes(sizeof(*x));
1255 x->b_n = 0;
1256 x->b_vec = t_getbytes(0);
1257 return (x);
1258}
1259
1260void binbuf_free(t_binbuf *x)
1261{
1262 t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec));
1263 t_freebytes(x, sizeof(*x));
1264}
1265
1266t_binbuf *binbuf_duplicate(t_binbuf *y)
1267{
1268 t_binbuf *x = (t_binbuf *)t_getbytes(sizeof(*x));
1269 x->b_n = y->b_n;
1270 x->b_vec = t_getbytes(x->b_n * sizeof(*x->b_vec));
1271 memcpy(x->b_vec, y->b_vec, x->b_n * sizeof(*x->b_vec));
1272 return (x);
1273}
1274
1275void binbuf_clear(t_binbuf *x)
1276{
1277 x->b_vec = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec), 0);
1278 x->b_n = 0;
1279}
1280
1281 /* convert text to a binbuf */
1282void binbuf_text(t_binbuf *x, char *text, size_t size)
1283{
1284 char buf[MAXPDSTRING+1], *bufp, *ebuf = buf+MAXPDSTRING;
1285 const char *textp = text, *etext = text+size;
1286 t_atom *ap;
1287 int nalloc = 16, natom = 0;
1288 t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec));
1289 x->b_vec = t_getbytes(nalloc * sizeof(*x->b_vec));
1290 ap = x->b_vec;
1291 x->b_n = 0;
1292 while (1)
1293 {
1294 int type;
1295 /* skip leading space */
1296 while ((textp != etext) && (*textp == ' ' || *textp == '\n'
1297 || *textp == '\r' || *textp == '\t')) textp++;
1298 if (textp == etext) break;
1299 if (*textp == ';') SETSEMI(ap), textp++;
1300 else if (*textp == ',') SETCOMMA(ap), textp++;
1301 else
1302 {
1303 /* it's an atom other than a comma or semi */
1304 char c;
1305 int floatstate = 0, slash = 0, lastslash = 0,
1306 firstslash = (*textp == '\\');
1307 bufp = buf;
1308 do
1309 {
1310 c = *bufp = *textp++;
1311 lastslash = slash;
1312 slash = (c == '\\');
1313
1314 if (floatstate >= 0)
1315 {
1316 int digit = (c >= '0' && c <= '9'),
1317 dot = (c == '.'), minus = (c == '-'),
1318 plusminus = (minus || (c == '+')),
1319 expon = (c == 'e' || c == 'E');
1320 if (floatstate == 0) /* beginning */
1321 {
1322 if (minus) floatstate = 1;
1323 else if (digit) floatstate = 2;
1324 else if (dot) floatstate = 3;
1325 else floatstate = -1;
1326 }
1327 else if (floatstate == 1) /* got minus */
1328 {
1329 if (digit) floatstate = 2;
1330 else if (dot) floatstate = 3;
1331 else floatstate = -1;
1332 }
1333 else if (floatstate == 2) /* got digits */
1334 {
1335 if (dot) floatstate = 4;
1336 else if (expon) floatstate = 6;
1337 else if (!digit) floatstate = -1;
1338 }
1339 else if (floatstate == 3) /* got '.' without digits */
1340 {
1341 if (digit) floatstate = 5;
1342 else floatstate = -1;
1343 }
1344 else if (floatstate == 4) /* got '.' after digits */
1345 {
1346 if (digit) floatstate = 5;
1347 else if (expon) floatstate = 6;
1348 else floatstate = -1;
1349 }
1350 else if (floatstate == 5) /* got digits after . */
1351 {
1352 if (expon) floatstate = 6;
1353 else if (!digit) floatstate = -1;
1354 }
1355 else if (floatstate == 6) /* got 'e' */
1356 {
1357 if (plusminus) floatstate = 7;
1358 else if (digit) floatstate = 8;
1359 else floatstate = -1;
1360 }
1361 else if (floatstate == 7) /* got plus or minus */
1362 {
1363 if (digit) floatstate = 8;
1364 else floatstate = -1;
1365 }
1366 else if (floatstate == 8) /* got digits */
1367 {
1368 if (!digit) floatstate = -1;
1369 }
1370 }
1371 if (!slash) bufp++;
1372 }
1373 while (textp != etext && bufp != ebuf &&
1374 (slash || (*textp != ' ' && *textp != '\n' && *textp != '\r'
1375 && *textp != '\t' &&*textp != ',' && *textp != ';')));
1376 *bufp = 0;
1377#if 0
1378 post("buf %s", buf);
1379#endif
1380 if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash)
1381 {
1382 for (bufp = buf+2; *bufp; bufp++)
1383 if (*bufp < '0' || *bufp > '9')
1384 {
1385 SETDOLLSYM(ap, gensym(buf+1));
1386 goto didit;
1387 }
1388 SETDOLLAR(ap, atoi(buf+1));
1389 didit: ;
1390 }
1391 else
1392 {
1393 if (floatstate == 2 || floatstate == 4 || floatstate == 5 ||
1394 floatstate == 8)
1395 SETFLOAT(ap, atof(buf));
1396 else SETSYMBOL(ap, gensym(buf));
1397 }
1398 }
1399 ap++;
1400 natom++;
1401 if (natom == nalloc)
1402 {
1403 x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec),
1404 nalloc * (2*sizeof(*x->b_vec)));
1405 nalloc = nalloc * 2;
1406 ap = x->b_vec + natom;
1407 }
1408 if (textp == etext) break;
1409 }
1410 /* reallocate the vector to exactly the right size */
1411 x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec),
1412 natom * sizeof(*x->b_vec));
1413 x->b_n = natom;
1414}
1415
1416 /* convert a binbuf to text; no null termination. */
1417void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp)
1418{
1419 char *buf = getbytes(0), *newbuf;
1420 int length = 0;
1421 char string[MAXPDSTRING];
1422 t_atom *ap;
1423 int indx;
1424
1425 for (ap = x->b_vec, indx = x->b_n; indx--; ap++)
1426 {
1427 int newlength;
1428 if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
1429 length && buf[length-1] == ' ') length--;
1430 atom_string(ap, string, MAXPDSTRING);
1431 newlength = length + strlen(string) + 1;
1432 if (!(newbuf = resizebytes(buf, length, newlength))) break;
1433 buf = newbuf;
1434 strcpy(buf + length, string);
1435 length = newlength;
1436 if (ap->a_type == A_SEMI) buf[length-1] = '\n';
1437 else buf[length-1] = ' ';
1438 }
1439 if (length && buf[length-1] == ' ')
1440 {
1441 if (newbuf = t_resizebytes(buf, length, length-1))
1442 {
1443 buf = newbuf;
1444 length--;
1445 }
1446 }
1447 *bufp = buf;
1448 *lengthp = length;
1449}
1450
1451/* LATER improve the out-of-space behavior below. Also fix this so that
1452writing to file doesn't buffer everything together. */
1453
1454void binbuf_add(t_binbuf *x, int argc, t_atom *argv)
1455{
1456 int newsize = x->b_n + argc, i;
1457 t_atom *ap;
1458 if (ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec),
1459 newsize * sizeof(*x->b_vec)))
1460 x->b_vec = ap;
1461 else
1462 {
1463 error("binbuf_addmessage: out of space");
1464 return;
1465 }
1466#if 0
1467 startpost("binbuf_add: ");
1468 postatom(argc, argv);
1469 endpost();
1470#endif
1471 for (ap = x->b_vec + x->b_n, i = argc; i--; ap++)
1472 *ap = *(argv++);
1473 x->b_n = newsize;
1474}
1475
1476#define MAXADDMESSV 100
1477void binbuf_addv(t_binbuf *x, char *fmt, ...)
1478{
1479 va_list ap;
1480 t_atom arg[MAXADDMESSV], *at =arg;
1481 int nargs = 0;
1482 char *fp = fmt;
1483
1484 va_start(ap, fmt);
1485 while (1)
1486 {
1487 if (nargs >= MAXADDMESSV)
1488 {
1489 error("binbuf_addmessv: only %d allowed", MAXADDMESSV);
1490 break;
1491 }
1492 switch(*fp++)
1493 {
1494 case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
1495 case 'f': SETFLOAT(at, va_arg(ap, double)); break;
1496 case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
1497 case ';': SETSEMI(at); break;
1498 case ',': SETCOMMA(at); break;
1499 default: goto done;
1500 }
1501 at++;
1502 nargs++;
1503 }
1504done:
1505 va_end(ap);
1506 binbuf_add(x, nargs, arg);
1507}
1508
1509/* add a binbuf to another one for saving. Semicolons and commas go to
1510symbols ";", "'",; the symbol ";" goes to "\;", etc. */
1511
1512void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y)
1513{
1514 t_binbuf *z = binbuf_new();
1515 int i;
1516 t_atom *ap;
1517 binbuf_add(z, y->b_n, y->b_vec);
1518 for (i = 0, ap = z->b_vec; i < z->b_n; i++, ap++)
1519 {
1520 char tbuf[MAXPDSTRING];
1521 switch (ap->a_type)
1522 {
1523 case A_FLOAT:
1524 break;
1525 case A_SEMI:
1526 SETSYMBOL(ap, gensym(";"));
1527 break;
1528 case A_COMMA:
1529 SETSYMBOL(ap, gensym(","));
1530 break;
1531 case A_DOLLAR:
1532 sprintf(tbuf, "$%d", ap->a_w.w_index);
1533 SETSYMBOL(ap, gensym(tbuf));
1534 break;
1535 case A_DOLLSYM:
1536 sprintf(tbuf, "$%s", ap->a_w.w_symbol->s_name);
1537 SETSYMBOL(ap, gensym(tbuf));
1538 break;
1539 case A_SYMBOL:
1540 /* FIXME make this general */
1541 if (!strcmp(ap->a_w.w_symbol->s_name, ";"))
1542 SETSYMBOL(ap, gensym(";"));
1543 else if (!strcmp(ap->a_w.w_symbol->s_name, ","))
1544 SETSYMBOL(ap, gensym(","));
1545 break;
1546 default:
1547 bug("binbuf_addbinbuf");
1548 }
1549 }
1550
1551 binbuf_add(x, z->b_n, z->b_vec);
1552}
1553
1554void binbuf_addsemi(t_binbuf *x)
1555{
1556 t_atom a;
1557 SETSEMI(&a);
1558 binbuf_add(x, 1, &a);
1559}
1560
1561/* Supply atoms to a binbuf from a message, making the opposite changes
1562from binbuf_addbinbuf. The symbol ";" goes to a semicolon, etc. */
1563
1564void binbuf_restore(t_binbuf *x, int argc, t_atom *argv)
1565{
1566 int newsize = x->b_n + argc, i;
1567 t_atom *ap;
1568 if (ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec),
1569 newsize * sizeof(*x->b_vec)))
1570 x->b_vec = ap;
1571 else
1572 {
1573 error("binbuf_addmessage: out of space");
1574 return;
1575 }
1576
1577 for (ap = x->b_vec + x->b_n, i = argc; i--; ap++)
1578 {
1579 if (argv->a_type == A_SYMBOL)
1580 {
1581 char *str = argv->a_w.w_symbol->s_name;
1582 if (!strcmp(str, ";")) SETSEMI(ap);
1583 else if (!strcmp(str, ",")) SETCOMMA(ap);
1584 else if (str[0] == '$' && str[1] >= '0' && str[1] <= '9')
1585 {
1586 int dollsym = 0;
1587 char *str2;
1588 for (str2 = str + 2; *str2; str2++)
1589 if (*str2 < '0' || *str2 > '9')
1590 dollsym = 1;
1591 if (dollsym)
1592 SETDOLLSYM(ap, gensym(str + 1));
1593 else
1594 {
1595 int dollar = 0;
1596 sscanf(argv->a_w.w_symbol->s_name + 1, "%d", &dollar);
1597 SETDOLLAR(ap, dollar);
1598 }
1599 }
1600 else *ap = *argv;
1601 argv++;
1602 }
1603 else *ap = *(argv++);
1604 }
1605 x->b_n = newsize;
1606}
1607
1608
1609#define MSTACKSIZE 2048
1610
1611void binbuf_print(t_binbuf *x)
1612{
1613 int i, startedpost = 0, newline = 1;
1614 for (i = 0; i < x->b_n; i++)
1615 {
1616 if (newline)
1617 {
1618 if (startedpost) endpost();
1619 startpost("");
1620 startedpost = 1;
1621 }
1622 postatom(1, x->b_vec + i);
1623 if (x->b_vec[i].a_type == A_SEMI)
1624 newline = 1;
1625 else newline = 0;
1626 }
1627 if (startedpost) endpost();
1628}
1629
1630int binbuf_getnatom(t_binbuf *x)
1631{
1632 return (x->b_n);
1633}
1634
1635t_atom *binbuf_getvec(t_binbuf *x)
1636{
1637 return (x->b_vec);
1638}
1639
1640int canvas_getdollarzero( void);
1641
1642t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew)
1643{
1644 int argno = atol(s->s_name), lastnum;
1645 char buf[MAXPDSTRING], c, *sp;
1646 for (lastnum = 0, sp = s->s_name; ((c = *sp) && c >= '0' && c <= '9');
1647 sp++, lastnum++)
1648 if (!c || argno < 0 || argno > ac)
1649 {
1650 if (!tonew)
1651 return (0);
1652 else sprintf(buf, "$%d", argno);
1653 }
1654 else if (argno == 0)
1655 sprintf(buf, "%d", canvas_getdollarzero());
1656 else
1657 atom_string(av+(argno-1), buf, MAXPDSTRING/2-1);
1658 strncat(buf, sp, MAXPDSTRING/2-1);
1659 return (gensym(buf));
1660}
1661
1662void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv)
1663{
1664 static t_atom mstack[MSTACKSIZE], *msp = mstack, *ems = mstack+MSTACKSIZE;
1665 t_atom *stackwas = msp;
1666 t_atom *at = x->b_vec;
1667 int ac = x->b_n;
1668 int nargs;
1669 while (1)
1670 {
1671 t_pd *nexttarget;
1672 /* get a target. */
1673 while (!target)
1674 {
1675 t_symbol *s;
1676 while (ac && (at->a_type == A_SEMI || at->a_type == A_COMMA))
1677 ac--, at++;
1678 if (!ac) break;
1679 if (at->a_type == A_DOLLAR)
1680 {
1681 if (at->a_w.w_index <= 0 || at->a_w.w_index > argc)
1682 {
1683 error("$%d: not enough arguments supplied",
1684 at->a_w.w_index);
1685 goto cleanup;
1686 }
1687 else if (argv[at->a_w.w_index-1].a_type != A_SYMBOL)
1688 {
1689 error("$%d: symbol needed as message destination",
1690 at->a_w.w_index);
1691 goto cleanup;
1692 }
1693 else s = argv[at->a_w.w_index-1].a_w.w_symbol;
1694 }
1695 else if (at->a_type == A_DOLLSYM)
1696 {
1697 if (!(s = binbuf_realizedollsym(at->a_w.w_symbol,
1698 argc, argv, 0)))
1699 {
1700 error("$%s: not enough arguments supplied",
1701 at->a_w.w_symbol->s_name);
1702 goto cleanup;
1703 }
1704 }
1705 else s = atom_getsymbol(at);
1706 if (!(target = s->s_thing))
1707 {
1708 error("%s: no such object", s->s_name);
1709 cleanup:
1710 do at++, ac--;
1711 while (ac && at->a_type != A_SEMI);
1712 /* LATER eat args until semicolon and continue */
1713 continue;
1714 }
1715 else
1716 {
1717 at++, ac--;
1718 break;
1719 }
1720 }
1721 if (!ac) break;
1722 nargs = 0;
1723 nexttarget = target;
1724 while (1)
1725 {
1726 t_symbol *s9;
1727 if (!ac) goto gotmess;
1728 if (msp >= ems)
1729 {
1730 error("message stack overflow");
1731 goto broken;
1732 }
1733 switch (at->a_type)
1734 {
1735 case A_SEMI:
1736 /* semis and commas in new message just get bashed to
1737 a symbol. This is needed so you can pass them to "expr." */
1738 if (target == &pd_objectmaker)
1739 {
1740 SETSYMBOL(msp, gensym(";"));
1741 break;
1742 }
1743 else
1744 {
1745 nexttarget = 0;
1746 goto gotmess;
1747 }
1748 case A_COMMA:
1749 if (target == &pd_objectmaker)
1750 {
1751 SETSYMBOL(msp, gensym(","));
1752 break;
1753 }
1754 else goto gotmess;
1755 case A_FLOAT:
1756 case A_SYMBOL:
1757 *msp = *at;
1758 break;
1759 case A_DOLLAR:
1760 if (at->a_w.w_index > 0 && at->a_w.w_index <= argc)
1761 *msp = argv[at->a_w.w_index-1];
1762 else if (at->a_w.w_index == 0)
1763 SETFLOAT(msp, canvas_getdollarzero());
1764 else
1765 {
1766 if (target == &pd_objectmaker)
1767 SETFLOAT(msp, 0);
1768 else
1769 {
1770 error("$%d: argument number out of range",
1771 at->a_w.w_index);
1772 SETFLOAT(msp, 0);
1773 }
1774 }
1775 break;
1776 case A_DOLLSYM:
1777 s9 = binbuf_realizedollsym(at->a_w.w_symbol, argc, argv,
1778 target == &pd_objectmaker);
1779 if (!s9)
1780 goto broken;
1781 SETSYMBOL(msp, s9);
1782 break;
1783 default:
1784 bug("bad item in binbuf");
1785 goto broken;
1786 }
1787 msp++;
1788 ac--;
1789 at++;
1790 nargs++;
1791 }
1792 gotmess:
1793 if (nargs)
1794 {
1795 switch (stackwas->a_type)
1796 {
1797 case A_SYMBOL:
1798 typedmess(target, stackwas->a_w.w_symbol, nargs-1, stackwas+1);
1799 break;
1800 case A_FLOAT:
1801 if (nargs == 1) pd_float(target, stackwas->a_w.w_float);
1802 else pd_list(target, 0, nargs, stackwas);
1803 break;
1804 }
1805 }
1806 msp = stackwas;
1807 if (!ac) break;
1808 target = nexttarget;
1809 at++;
1810 ac--;
1811 }
1812
1813 return;
1814broken:
1815 msp = stackwas;
1816}
1817
1818static int binbuf_doopen(char *s, int mode)
1819{
1820 char namebuf[MAXPDSTRING];
1821#ifdef MSW
1822 mode |= O_BINARY;
1823#endif
1824 sys_bashfilename(s, namebuf);
1825 return (open(namebuf, mode));
1826}
1827
1828static FILE *binbuf_dofopen(char *s, char *mode)
1829{
1830 char namebuf[MAXPDSTRING];
1831 sys_bashfilename(s, namebuf);
1832 return (fopen(namebuf, mode));
1833}
1834
1835int binbuf_read(t_binbuf *b, char *filename, char *dirname, int crflag)
1836{
1837 long length;
1838 int fd;
1839 int readret;
1840 char *buf;
1841 char namebuf[MAXPDSTRING];
1842
1843 namebuf[0] = 0;
1844 if (*dirname)
1845 strcat(namebuf, dirname), strcat(namebuf, "/");
1846 strcat(namebuf, filename);
1847
1848 if ((fd = binbuf_doopen(namebuf, 0)) < 0)
1849 {
1850 fprintf(stderr, "open: ");
1851 perror(namebuf);
1852 return (1);
1853 }
1854 if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0, SEEK_SET) < 0
1855 || !(buf = t_getbytes(length)))
1856 {
1857 fprintf(stderr, "lseek: ");
1858 perror(namebuf);
1859 close(fd);
1860 return(1);
1861 }
1862 if ((readret = read(fd, buf, length)) < length)
1863 {
1864 fprintf(stderr, "read (%d %ld) -> %d\n", fd, length, readret);
1865 perror(namebuf);
1866 close(fd);
1867 t_freebytes(buf, length);
1868 return(1);
1869 }
1870 /* optionally map carriage return to semicolon */
1871 if (crflag)
1872 {
1873 int i;
1874 for (i = 0; i < length; i++)
1875 if (buf[i] == '\n')
1876 buf[i] = ';';
1877 }
1878 binbuf_text(b, buf, length);
1879
1880#if 0
1881 startpost("binbuf_read "); postatom(b->b_n, b->b_vec); endpost();
1882#endif
1883
1884 t_freebytes(buf, length);
1885 close(fd);
1886 return (0);
1887}
1888
1889int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
1890 int crflag)
1891{
1892 int filedesc;
1893 char buf[MAXPDSTRING], *bufptr;
1894 if ((filedesc = open_via_path(
1895 dirname, filename, "", buf, &bufptr, MAXPDSTRING, 0)) < 0)
1896 {
1897 error("%s: can't open", filename);
1898 return (1);
1899 }
1900 else close (filedesc);
1901 if (binbuf_read(b, bufptr, buf, crflag))
1902 return (1);
1903 else return (0);
1904}
1905
1906#define WBUFSIZE 4096
1907static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd);
1908
1909 /* write a binbuf to a text file. If "crflag" is set we suppress
1910 semicolons. */
1911int binbuf_write(t_binbuf *x, char *filename, char *dir, int crflag)
1912{
1913 FILE *f = 0;
1914 char sbuf[WBUFSIZE], fbuf[MAXPDSTRING], *bp = sbuf, *ep = sbuf + WBUFSIZE;
1915 t_atom *ap;
1916 int indx, deleteit = 0;
1917 int ncolumn = 0;
1918
1919 fbuf[0] = 0;
1920 if (*dir)
1921 strcat(fbuf, dir), strcat(fbuf, "/");
1922 strcat(fbuf, filename);
1923 if (!strcmp(filename + strlen(filename) - 4, ".pat"))
1924 {
1925 x = binbuf_convert(x, 0);
1926 deleteit = 1;
1927 }
1928
1929 if (!(f = binbuf_dofopen(fbuf, "w")))
1930 {
1931 fprintf(stderr, "open: ");
1932 sys_unixerror(fbuf);
1933 goto fail;
1934 }
1935 for (ap = x->b_vec, indx = x->b_n; indx--; ap++)
1936 {
1937 int length;
1938 /* estimate how many characters will be needed. Printing out
1939 symbols may need extra characters for inserting backslashes. */
1940 if (ap->a_type == A_SYMBOL || ap->a_type == A_DOLLSYM)
1941 length = 80 + strlen(ap->a_w.w_symbol->s_name);
1942 else length = 40;
1943 if (ep - bp < length)
1944 {
1945 if (fwrite(sbuf, bp-sbuf, 1, f) < 1)
1946 {
1947 sys_unixerror(fbuf);
1948 goto fail;
1949 }
1950 bp = sbuf;
1951 }
1952 if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
1953 bp > sbuf && bp[-1] == ' ') bp--;
1954 if (!crflag || ap->a_type != A_SEMI)
1955 {
1956 atom_string(ap, bp, (ep-bp)-2);
1957 length = strlen(bp);
1958 bp += length;
1959 ncolumn += length;
1960 }
1961 if (ap->a_type == A_SEMI || (!crflag && ncolumn > 65))
1962 {
1963 *bp++ = '\n';
1964 ncolumn = 0;
1965 }
1966 else
1967 {
1968 *bp++ = ' ';
1969 ncolumn++;
1970 }
1971 }
1972 if (fwrite(sbuf, bp-sbuf, 1, f) < 1)
1973 {
1974 sys_unixerror(fbuf);
1975 goto fail;
1976 }
1977 if (deleteit)
1978 binbuf_free(x);
1979 fclose(f);
1980 return (0);
1981fail:
1982 if (deleteit)
1983 binbuf_free(x);
1984 if (f)
1985 fclose(f);
1986 return (1);
1987}
1988
1989/* The following routine attempts to convert from max to pd or back. The
1990max to pd direction is working OK but you will need to make lots of
1991abstractions for objects like "gate" which don't exist in Pd. conversion
1992from Pd to Max hasn't been tested for patches with subpatches yet! */
1993
1994#define MAXSTACK 1000
1995
1996#define ISSYMBOL(a, b) ((a)->a_type == A_SYMBOL && \
1997 !strcmp((a)->a_w.w_symbol->s_name, (b)))
1998
1999static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
2000{
2001 t_binbuf *newb = binbuf_new();
2002 t_atom *vec = oldb->b_vec;
2003 t_int n = oldb->b_n, nextindex, stackdepth = 0, stack[MAXSTACK],
2004 nobj = 0, i;
2005 t_atom outmess[MAXSTACK], *nextmess;
2006 if (!maxtopd)
2007 binbuf_addv(newb, "ss;", gensym("max"), gensym("v2"));
2008 for (nextindex = 0; nextindex < n; )
2009 {
2010 int endmess, natom;
2011 char *first, *second;
2012 for (endmess = nextindex; endmess < n && vec[endmess].a_type != A_SEMI;
2013 endmess++)
2014 ;
2015 if (endmess == n) break;
2016 if (endmess == nextindex || endmess == nextindex + 1
2017 || vec[nextindex].a_type != A_SYMBOL ||
2018 vec[nextindex+1].a_type != A_SYMBOL)
2019 {
2020 nextindex = endmess + 1;
2021 continue;
2022 }
2023 natom = endmess - nextindex;
2024 if (natom > MAXSTACK-10) natom = MAXSTACK-10;
2025 nextmess = vec + nextindex;
2026 first = nextmess->a_w.w_symbol->s_name;
2027 second = (nextmess+1)->a_w.w_symbol->s_name;
2028 if (maxtopd)
2029 {
2030 /* case 1: importing a ".pat" file into Pd. */
2031
2032 /* dollar signs in file translate to symbols */
2033 for (i = 0; i < natom; i++)
2034 {
2035 if (nextmess[i].a_type == A_DOLLAR)
2036 {
2037 char buf[100];
2038 sprintf(buf, "$%d", nextmess[i].a_w.w_index);
2039 SETSYMBOL(nextmess+i, gensym(buf));
2040 }
2041 else if (nextmess[i].a_type == A_DOLLSYM)
2042 {
2043 char buf[100];
2044 sprintf(buf, "$%s", nextmess[i].a_w.w_symbol->s_name);
2045 SETSYMBOL(nextmess+i, gensym(buf));
2046 }
2047 }
2048 if (!strcmp(first, "#N"))
2049 {
2050 if (!strcmp(second, "vpatcher"))
2051 {
2052 if (stackdepth >= MAXSTACK)
2053 {
2054 post("too many embedded patches");
2055 return (newb);
2056 }
2057 stack[stackdepth] = nobj;
2058 stackdepth++;
2059 nobj = 0;
2060 binbuf_addv(newb, "ssfffff;",
2061 gensym("#N"), gensym("canvas"),
2062 atom_getfloatarg(2, natom, nextmess),
2063 atom_getfloatarg(3, natom, nextmess),
2064 atom_getfloatarg(4, natom, nextmess) -
2065 atom_getfloatarg(2, natom, nextmess),
2066 atom_getfloatarg(5, natom, nextmess) -
2067 atom_getfloatarg(3, natom, nextmess),
2068 (float)sys_defaultfont);
2069 }
2070 }
2071 if (!strcmp(first, "#P"))
2072 {
2073 /* drop initial "hidden" flag */
2074 if (!strcmp(second, "hidden"))
2075 {
2076 nextmess++;
2077 natom--;
2078 second = (nextmess+1)->a_w.w_symbol->s_name;
2079 }
2080 if (natom >= 7 && !strcmp(second, "newobj")
2081 && (ISSYMBOL(&nextmess[6], "patcher") ||
2082 ISSYMBOL(&nextmess[6], "p")))
2083 {
2084 binbuf_addv(newb, "ssffss;",
2085 gensym("#X"), gensym("restore"),
2086 atom_getfloatarg(2, natom, nextmess),
2087 atom_getfloatarg(3, natom, nextmess),
2088 gensym("pd"), atom_getsymbolarg(7, natom, nextmess));
2089 if (stackdepth) stackdepth--;
2090 nobj = stack[stackdepth];
2091 nobj++;
2092 }
2093 else if (!strcmp(second, "newex") || !strcmp(second, "newobj"))
2094 {
2095 t_symbol *classname =
2096 atom_getsymbolarg(6, natom, nextmess);
2097 if (classname == gensym("trigger") ||
2098 classname == gensym("t"))
2099 {
2100 for (i = 7; i < natom; i++)
2101 if (nextmess[i].a_type == A_SYMBOL &&
2102 nextmess[i].a_w.w_symbol == gensym("i"))
2103 nextmess[i].a_w.w_symbol = gensym("f");
2104 }
2105 if (classname == gensym("table"))
2106 classname = gensym("TABLE");
2107 SETSYMBOL(outmess, gensym("#X"));
2108 SETSYMBOL(outmess + 1, gensym("obj"));
2109 outmess[2] = nextmess[2];
2110 outmess[3] = nextmess[3];
2111 SETSYMBOL(outmess+4, classname);
2112 for (i = 7; i < natom; i++)
2113 outmess[i-2] = nextmess[i];
2114 SETSEMI(outmess + natom - 2);
2115 binbuf_add(newb, natom - 1, outmess);
2116 nobj++;
2117 }
2118 else if (!strcmp(second, "message") ||
2119 !strcmp(second, "comment"))
2120 {
2121 SETSYMBOL(outmess, gensym("#X"));
2122 SETSYMBOL(outmess + 1, gensym(
2123 (strcmp(second, "message") ? "text" : "msg")));
2124 outmess[2] = nextmess[2];
2125 outmess[3] = nextmess[3];
2126 for (i = 6; i < natom; i++)
2127 outmess[i-2] = nextmess[i];
2128 SETSEMI(outmess + natom - 2);
2129 binbuf_add(newb, natom - 1, outmess);
2130 nobj++;
2131 }
2132 else if (!strcmp(second, "button"))
2133 {
2134 binbuf_addv(newb, "ssffs;",
2135 gensym("#X"), gensym("obj"),
2136 atom_getfloatarg(2, natom, nextmess),
2137 atom_getfloatarg(3, natom, nextmess),
2138 gensym("bng"));
2139 nobj++;
2140 }
2141 else if (!strcmp(second, "number") || !strcmp(second, "flonum"))
2142 {
2143 binbuf_addv(newb, "ssff;",
2144 gensym("#X"), gensym("floatatom"),
2145 atom_getfloatarg(2, natom, nextmess),
2146 atom_getfloatarg(3, natom, nextmess));
2147 nobj++;
2148 }
2149 else if (!strcmp(second, "slider"))
2150 {
2151 float inc = atom_getfloatarg(7, natom, nextmess);
2152 if (inc <= 0)
2153 inc = 1;
2154 binbuf_addv(newb, "ssffsffffffsssfffffffff;",
2155 gensym("#X"), gensym("obj"),
2156 atom_getfloatarg(2, natom, nextmess),
2157 atom_getfloatarg(3, natom, nextmess),
2158 gensym("vsl"),
2159 atom_getfloatarg(4, natom, nextmess),
2160 atom_getfloatarg(5, natom, nextmess),
2161 atom_getfloatarg(6, natom, nextmess),
2162 atom_getfloatarg(6, natom, nextmess)
2163 + (atom_getfloatarg(5, natom, nextmess) - 1) * inc,
2164 0., 0.,
2165 gensym("empty"), gensym("empty"), gensym("empty"),
2166 0., -8., 0., 8., -262144., -1., -1., 0., 1.);
2167 nobj++;
2168 }
2169 else if (!strcmp(second, "toggle"))
2170 {
2171 binbuf_addv(newb, "ssffs;",
2172 gensym("#X"), gensym("obj"),
2173 atom_getfloatarg(2, natom, nextmess),
2174 atom_getfloatarg(3, natom, nextmess),
2175 gensym("tgl"));
2176 nobj++;
2177 }
2178 else if (!strcmp(second, "inlet"))
2179 {
2180 binbuf_addv(newb, "ssffs;",
2181 gensym("#X"), gensym("obj"),
2182 atom_getfloatarg(2, natom, nextmess),
2183 atom_getfloatarg(3, natom, nextmess),
2184 gensym((natom > 5 ? "inlet~" : "inlet")));
2185 nobj++;
2186 }
2187 else if (!strcmp(second, "outlet"))
2188 {
2189 binbuf_addv(newb, "ssffs;",
2190 gensym("#X"), gensym("obj"),
2191 atom_getfloatarg(2, natom, nextmess),
2192 atom_getfloatarg(3, natom, nextmess),
2193 gensym((natom > 5 ? "outlet~" : "outlet")));
2194 nobj++;
2195 }
2196 else if (!strcmp(second, "user"))
2197 {
2198 binbuf_addv(newb, "ssffs;",
2199 gensym("#X"), gensym("obj"),
2200 atom_getfloatarg(3, natom, nextmess),
2201 atom_getfloatarg(4, natom, nextmess),
2202 atom_getsymbolarg(2, natom, nextmess));
2203 nobj++;
2204 }
2205 else if (!strcmp(second, "connect")||
2206 !strcmp(second, "fasten"))
2207 {
2208 binbuf_addv(newb, "ssffff;",
2209 gensym("#X"), gensym("connect"),
2210 nobj - atom_getfloatarg(2, natom, nextmess) - 1,
2211 atom_getfloatarg(3, natom, nextmess),
2212 nobj - atom_getfloatarg(4, natom, nextmess) - 1,
2213 atom_getfloatarg(5, natom, nextmess));
2214 }
2215 }
2216 }
2217 else /* Pd to Max */
2218 {
2219 if (!strcmp(first, "#N"))
2220 {
2221 if (!strcmp(second, "canvas"))
2222 {
2223 if (stackdepth >= MAXSTACK)
2224 {
2225 post("too many embedded patches");
2226 return (newb);
2227 }
2228 stack[stackdepth] = nobj;
2229 stackdepth++;
2230 nobj = 0;
2231 binbuf_addv(newb, "ssffff;",
2232 gensym("#N"), gensym("vpatcher"),
2233 atom_getfloatarg(2, natom, nextmess),
2234 atom_getfloatarg(3, natom, nextmess),
2235 atom_getfloatarg(4, natom, nextmess),
2236 atom_getfloatarg(5, natom, nextmess));
2237 }
2238 }
2239 if (!strcmp(first, "#X"))
2240 {
2241 if (natom >= 5 && !strcmp(second, "restore")
2242 && (ISSYMBOL (&nextmess[4], "pd")))
2243 {
2244 binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
2245 binbuf_addv(newb, "ssffffss;",
2246 gensym("#P"), gensym("newobj"),
2247 atom_getfloatarg(2, natom, nextmess),
2248 atom_getfloatarg(3, natom, nextmess), 50., 1.,
2249 gensym("patcher"),
2250 atom_getsymbolarg(5, natom, nextmess));
2251 if (stackdepth) stackdepth--;
2252 nobj = stack[stackdepth];
2253 nobj++;
2254 }
2255 else if (!strcmp(second, "obj"))
2256 {
2257 t_symbol *classname =
2258 atom_getsymbolarg(4, natom, nextmess);
2259 if (classname == gensym("inlet"))
2260 binbuf_addv(newb, "ssfff;", gensym("#P"),
2261 gensym("inlet"),
2262 atom_getfloatarg(2, natom, nextmess),
2263 atom_getfloatarg(3, natom, nextmess),
2264 15.);
2265 else if (classname == gensym("inlet~"))
2266 binbuf_addv(newb, "ssffff;", gensym("#P"),
2267 gensym("inlet"),
2268 atom_getfloatarg(2, natom, nextmess),
2269 atom_getfloatarg(3, natom, nextmess),
2270 15., 1.);
2271 else if (classname == gensym("outlet"))
2272 binbuf_addv(newb, "ssfff;", gensym("#P"),
2273 gensym("outlet"),
2274 atom_getfloatarg(2, natom, nextmess),
2275 atom_getfloatarg(3, natom, nextmess),
2276 15.);
2277 else if (classname == gensym("outlet~"))
2278 binbuf_addv(newb, "ssffff;", gensym("#P"),
2279 gensym("outlet"),
2280 atom_getfloatarg(2, natom, nextmess),
2281 atom_getfloatarg(3, natom, nextmess),
2282 15., 1.);
2283 else if (classname == gensym("bng"))
2284 binbuf_addv(newb, "ssffff;", gensym("#P"),
2285 gensym("button"),
2286 atom_getfloatarg(2, natom, nextmess),
2287 atom_getfloatarg(3, natom, nextmess),
2288 atom_getfloatarg(5, natom, nextmess), 0.);
2289 else if (classname == gensym("tgl"))
2290 binbuf_addv(newb, "ssffff;", gensym("#P"),
2291 gensym("toggle"),
2292 atom_getfloatarg(2, natom, nextmess),
2293 atom_getfloatarg(3, natom, nextmess),
2294 atom_getfloatarg(5, natom, nextmess), 0.);
2295 else if (classname == gensym("vsl"))
2296 binbuf_addv(newb, "ssffffff;", gensym("#P"),
2297 gensym("slider"),
2298 atom_getfloatarg(2, natom, nextmess),
2299 atom_getfloatarg(3, natom, nextmess),
2300 atom_getfloatarg(5, natom, nextmess),
2301 atom_getfloatarg(6, natom, nextmess),
2302 (atom_getfloatarg(8, natom, nextmess) -
2303 atom_getfloatarg(7, natom, nextmess)) /
2304 (atom_getfloatarg(6, natom, nextmess) == 1? 1 :
2305 atom_getfloatarg(6, natom, nextmess) - 1),
2306 atom_getfloatarg(7, natom, nextmess));
2307 else
2308 {
2309 SETSYMBOL(outmess, gensym("#P"));
2310 SETSYMBOL(outmess + 1, gensym("newex"));
2311 outmess[2] = nextmess[2];
2312 outmess[3] = nextmess[3];
2313 SETFLOAT(outmess + 4, 50);
2314 SETFLOAT(outmess + 5, 1);
2315 for (i = 4; i < natom; i++)
2316 outmess[i+2] = nextmess[i];
2317 SETSEMI(outmess + natom + 2);
2318 binbuf_add(newb, natom + 3, outmess);
2319 }
2320 nobj++;
2321
2322 }
2323 else if (!strcmp(second, "msg") ||
2324 !strcmp(second, "text"))
2325 {
2326 SETSYMBOL(outmess, gensym("#P"));
2327 SETSYMBOL(outmess + 1, gensym(
2328 (strcmp(second, "msg") ? "comment" : "message")));
2329 outmess[2] = nextmess[2];
2330 outmess[3] = nextmess[3];
2331 SETFLOAT(outmess + 4, 50);
2332 SETFLOAT(outmess + 5, 1);
2333 for (i = 4; i < natom; i++)
2334 outmess[i+2] = nextmess[i];
2335 SETSEMI(outmess + natom + 2);
2336 binbuf_add(newb, natom + 3, outmess);
2337 nobj++;
2338 }
2339 else if (!strcmp(second, "floatatom"))
2340 {
2341 binbuf_addv(newb, "ssfff;",
2342 gensym("#P"), gensym("flonum"),
2343 atom_getfloatarg(2, natom, nextmess),
2344 atom_getfloatarg(3, natom, nextmess), 35);
2345 nobj++;
2346 }
2347 else if (!strcmp(second, "connect"))
2348 {
2349 binbuf_addv(newb, "ssffff;",
2350 gensym("#P"), gensym("connect"),
2351 nobj - atom_getfloatarg(2, natom, nextmess) - 1,
2352 atom_getfloatarg(3, natom, nextmess),
2353 nobj - atom_getfloatarg(4, natom, nextmess) - 1,
2354 atom_getfloatarg(5, natom, nextmess));
2355 }
2356 }
2357 }
2358 nextindex = endmess + 1;
2359 }
2360 if (!maxtopd)
2361 binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
2362#if 0
2363 binbuf_write(newb, "import-result.pd", "/tmp", 0);
2364#endif
2365 return (newb);
2366}
2367
2368 /* function to support searching */
2369int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf)
2370{
2371 int indexin, nmatched;
2372 for (indexin = 0; indexin <= inbuf->b_n - searchbuf->b_n; indexin++)
2373 {
2374 for (nmatched = 0; nmatched < searchbuf->b_n; nmatched++)
2375 {
2376 t_atom *a1 = &inbuf->b_vec[indexin + nmatched],
2377 *a2 = &searchbuf->b_vec[nmatched];
2378 if (a1->a_type != a2->a_type ||
2379 a1->a_type == A_SYMBOL && a1->a_w.w_symbol != a2->a_w.w_symbol
2380 ||
2381 a1->a_type == A_FLOAT && a1->a_w.w_float != a2->a_w.w_float
2382 ||
2383 a1->a_type == A_DOLLAR && a1->a_w.w_index != a2->a_w.w_index
2384 ||
2385 a1->a_type == A_DOLLSYM && a1->a_w.w_symbol != a2->a_w.w_symbol)
2386 goto nomatch;
2387 }
2388 return (1);
2389 nomatch: ;
2390 }
2391 return (0);
2392}
2393
2394void pd_doloadbang(void);
2395
2396/* LATER make this evaluate the file on-the-fly. */
2397/* LATER figure out how to log errors */
2398void binbuf_evalfile(t_symbol *name, t_symbol *dir)
2399{
2400 t_binbuf *b = binbuf_new();
2401 int import = !strcmp(name->s_name + strlen(name->s_name) - 4, ".pat");
2402 /* set filename so that new canvases can pick them up */
2403 int dspstate = canvas_suspend_dsp();
2404 glob_setfilename(0, name, dir);
2405 if (binbuf_read(b, name->s_name, dir->s_name, 0))
2406 {
2407 perror(name->s_name);
2408 }
2409 else
2410 {
2411 if (import)
2412 {
2413 t_binbuf *newb = binbuf_convert(b, 1);
2414 binbuf_free(b);
2415 b = newb;
2416 }
2417 binbuf_eval(b, 0, 0, 0);
2418 }
2419 glob_setfilename(0, &s_, &s_); /* bug fix by Krzysztof Czaja */
2420 binbuf_free(b);
2421 canvas_resume_dsp(dspstate);
2422}
2423
2424void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir)
2425{
2426 t_pd *x = 0;
2427 /* even though binbuf_evalfile appears to take care of dspstate,
2428 we have to do it again here, because canvas_startdsp() assumes
2429 that all toplevel canvases are visible. LATER check if this
2430 is still necessary -- probably not. */
2431
2432 int dspstate = canvas_suspend_dsp();
2433 binbuf_evalfile(name, dir);
2434 while ((x != s__X.s_thing) && (x = s__X.s_thing))
2435 vmess(x, gensym("pop"), "i", 1);
2436 pd_doloadbang();
2437 canvas_resume_dsp(dspstate);
2438}
diff --git a/apps/plugins/pdbox/PDa/src/m_class.c b/apps/plugins/pdbox/PDa/src/m_class.c
new file mode 100644
index 0000000000..0b6d4df885
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_class.c
@@ -0,0 +1,1648 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#define PD_CLASS_DEF
6#include "m_pd.h"
7#include "m_imp.h"
8#include "s_stuff.h"
9#include <stdlib.h>
10#ifdef UNIX
11#include <unistd.h>
12#endif
13#ifdef MSW
14#include <io.h>
15#endif
16
17#include <stdarg.h>
18#include <string.h>
19
20static t_symbol *class_loadsym; /* name under which an extern is invoked */
21static void pd_defaultfloat(t_pd *x, t_float f);
22static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv);
23t_pd pd_objectmaker; /* factory for creating "object" boxes */
24t_pd pd_canvasmaker; /* factory for creating canvases */
25
26static t_symbol *class_extern_dir = &s_;
27
28static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv)
29{
30 pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name);
31}
32
33static void pd_defaultbang(t_pd *x)
34{
35 if (*(*x)->c_listmethod != pd_defaultlist)
36 (*(*x)->c_listmethod)(x, 0, 0, 0);
37 else (*(*x)->c_anymethod)(x, &s_bang, 0, 0);
38}
39
40static void pd_defaultpointer(t_pd *x, t_gpointer *gp)
41{
42 if (*(*x)->c_listmethod != pd_defaultlist)
43 {
44 t_atom at;
45 SETPOINTER(&at, gp);
46 (*(*x)->c_listmethod)(x, 0, 1, &at);
47 }
48 else
49 {
50 t_atom at;
51 SETPOINTER(&at, gp);
52 (*(*x)->c_anymethod)(x, &s_pointer, 1, &at);
53 }
54}
55
56static void pd_defaultfloat(t_pd *x, t_float f)
57{
58 if (*(*x)->c_listmethod != pd_defaultlist)
59 {
60 t_atom at;
61 SETFLOAT(&at, f);
62 (*(*x)->c_listmethod)(x, 0, 1, &at);
63 }
64 else
65 {
66 t_atom at;
67 SETFLOAT(&at, f);
68 (*(*x)->c_anymethod)(x, &s_float, 1, &at);
69 }
70}
71
72static void pd_defaultsymbol(t_pd *x, t_symbol *s)
73{
74 if (*(*x)->c_listmethod != pd_defaultlist)
75 {
76 t_atom at;
77 SETSYMBOL(&at, s);
78 (*(*x)->c_listmethod)(x, 0, 1, &at);
79 }
80 else
81 {
82 t_atom at;
83 SETSYMBOL(&at, s);
84 (*(*x)->c_anymethod)(x, &s_symbol, 1, &at);
85 }
86}
87
88void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
89static void class_nosavefn(t_gobj *z, t_binbuf *b);
90
91 /* handle "list" messages to Pds without explicit list methods defined. */
92static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv)
93{
94 /* a list with one element which is a number can be handled by a
95 "float" method if any is defined; same for "symbol", "pointer". */
96 if (argc == 1)
97 {
98 if (argv->a_type == A_FLOAT &&
99 *(*x)->c_floatmethod != pd_defaultfloat)
100 {
101 (*(*x)->c_floatmethod)(x, argv->a_w.w_float);
102 return;
103 }
104 else if (argv->a_type == A_SYMBOL &&
105 *(*x)->c_symbolmethod != pd_defaultsymbol)
106 {
107 (*(*x)->c_symbolmethod)(x, argv->a_w.w_symbol);
108 return;
109 }
110 else if (argv->a_type == A_POINTER &&
111 *(*x)->c_pointermethod != pd_defaultpointer)
112 {
113 (*(*x)->c_pointermethod)(x, argv->a_w.w_gpointer);
114 return;
115 }
116 }
117 /* Next try for an "anything" method */
118 if ((*x)->c_anymethod != pd_defaultanything)
119 (*(*x)->c_anymethod)(x, &s_list, argc, argv);
120
121 /* if the object is patchable (i.e., can have proper inlets)
122 send it on to obj_list which will unpack the list into the inlets */
123 else if ((*x)->c_patchable)
124 obj_list((t_object *)x, s, argc, argv);
125 /* otherwise gove up and complain. */
126 else pd_defaultanything(x, &s_list, argc, argv);
127}
128
129 /* for now we assume that all "gobjs" are text unless explicitly
130 overridden later by calling class_setbehavior(). I'm not sure
131 how to deal with Pds that aren't gobjs; shouldn't there be a
132 way to check that at run time? Perhaps the presence of a "newmethod"
133 should be our cue, or perhaps the "tiny" flag. */
134
135 /* another matter. This routine does two unrelated things: it creates
136 a Pd class, but also adds a "new" method to create an instance of it.
137 These are combined for historical reasons and for brevity in writing
138 objects. To avoid adding a "new" method send a null function pointer.
139 To add additional ones, use class_addcreator below. Some "classes", like
140 "select", are actually two classes of the same name, one for the single-
141 argument form, one for the multiple one; see select_setup() to find out
142 how this is handled. */
143
144extern t_widgetbehavior text_widgetbehavior;
145extern void text_save(t_gobj *z, t_binbuf *b);
146
147t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod,
148 size_t size, int flags, t_atomtype type1, ...)
149{
150 va_list ap;
151 t_atomtype vec[MAXPDARG+1], *vp = vec;
152 int count = 0;
153 t_class *c;
154 int typeflag = flags & CLASS_TYPEMASK;
155 if (!typeflag) typeflag = CLASS_PATCHABLE;
156 *vp = type1;
157
158 va_start(ap, type1);
159 while (*vp)
160 {
161 if (count == MAXPDARG)
162 {
163 error("class %s: sorry: only %d creation args allowed",
164 s->s_name, MAXPDARG);
165 break;
166 }
167 vp++;
168 count++;
169 *vp = va_arg(ap, t_atomtype);
170 }
171 va_end(ap);
172 if (pd_objectmaker && newmethod)
173 {
174 /* add a "new" method by the name specified by the object */
175 class_addmethod(pd_objectmaker, (t_method)newmethod, s,
176 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
177 if (class_loadsym)
178 {
179 /* if we're loading an extern it might have been invoked by a
180 longer file name; in this case, make this an admissible name
181 too. */
182 char *loadstring = class_loadsym->s_name,
183 l1 = strlen(s->s_name), l2 = strlen(loadstring);
184 if (l2 > l1 && !strcmp(s->s_name, loadstring + (l2 - l1)))
185 class_addmethod(pd_objectmaker, (t_method)newmethod,
186 class_loadsym,
187 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
188 }
189 }
190 c = (t_class *)t_getbytes(sizeof(*c));
191 c->c_name = c->c_helpname = s;
192 c->c_size = size;
193 c->c_methods = t_getbytes(0);
194 c->c_nmethod = 0;
195 c->c_freemethod = (t_method)freemethod;
196 c->c_bangmethod = pd_defaultbang;
197 c->c_pointermethod = pd_defaultpointer;
198 c->c_floatmethod = pd_defaultfloat;
199 c->c_symbolmethod = pd_defaultsymbol;
200 c->c_listmethod = pd_defaultlist;
201 c->c_anymethod = pd_defaultanything;
202 c->c_wb = (typeflag == CLASS_PATCHABLE ? &text_widgetbehavior : 0);
203 c->c_pwb = 0;
204 c->c_firstin = ((flags & CLASS_NOINLET) == 0);
205 c->c_patchable = (typeflag == CLASS_PATCHABLE);
206 c->c_gobj = (typeflag >= CLASS_GOBJ);
207 c->c_drawcommand = 0;
208 c->c_floatsignalin = 0;
209 c->c_externdir = class_extern_dir;
210 c->c_savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn);
211#if 0
212 post("class: %s", c->c_name->s_name);
213#endif
214 return (c);
215}
216
217 /* add a creation method, which is a function that returns a Pd object
218 suitable for putting in an object box. We presume you've got a class it
219 can belong to, but this won't be used until the newmethod is actually
220 called back (and the new method explicitly takes care of this.) */
221
222void class_addcreator(t_newmethod newmethod, t_symbol *s,
223 t_atomtype type1, ...)
224{
225 va_list ap;
226 t_atomtype vec[MAXPDARG+1], *vp = vec;
227 int count = 0;
228 *vp = type1;
229
230 va_start(ap, type1);
231 while (*vp)
232 {
233 if (count == MAXPDARG)
234 {
235 error("class %s: sorry: only %d creation args allowed",
236 s->s_name, MAXPDARG);
237 break;
238 }
239 vp++;
240 count++;
241 *vp = va_arg(ap, t_atomtype);
242 }
243 va_end(ap);
244 class_addmethod(pd_objectmaker, (t_method)newmethod, s,
245 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
246}
247
248void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
249 t_atomtype arg1, ...)
250{
251 va_list ap;
252 t_methodentry *m;
253 t_atomtype argtype = arg1;
254 int nargs;
255
256 va_start(ap, arg1);
257 /* "signal" method specifies that we take audio signals but
258 that we don't want automatic float to signal conversion. This
259 is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */
260 if (sel == &s_signal)
261 {
262 if (c->c_floatsignalin)
263 post("warning: signal method overrides class_mainsignalin");
264 c->c_floatsignalin = -1;
265 }
266 /* check for special cases. "Pointer" is missing here so that
267 pd_objectmaker's pointer method can be typechecked differently. */
268 if (sel == &s_bang)
269 {
270 if (argtype) goto phooey;
271 class_addbang(c, fn);
272 }
273 else if (sel == &s_float)
274 {
275 if (argtype != A_FLOAT || va_arg(ap, t_atomtype)) goto phooey;
276 class_doaddfloat(c, fn);
277 }
278 else if (sel == &s_symbol)
279 {
280 if (argtype != A_SYMBOL || va_arg(ap, t_atomtype)) goto phooey;
281 class_addsymbol(c, fn);
282 }
283 else if (sel == &s_list)
284 {
285 if (argtype != A_GIMME) goto phooey;
286 class_addlist(c, fn);
287 }
288 else if (sel == &s_anything)
289 {
290 if (argtype != A_GIMME) goto phooey;
291 class_addanything(c, fn);
292 }
293 else
294 {
295 c->c_methods = t_resizebytes(c->c_methods,
296 c->c_nmethod * sizeof(*c->c_methods),
297 (c->c_nmethod + 1) * sizeof(*c->c_methods));
298 m = c->c_methods + c->c_nmethod;
299 c->c_nmethod++;
300 m->me_name = sel;
301 m->me_fun = (t_gotfn)fn;
302 nargs = 0;
303 while (argtype != A_NULL && nargs < MAXPDARG)
304 {
305 m->me_arg[nargs++] = argtype;
306 argtype = va_arg(ap, t_atomtype);
307 }
308 if (argtype != A_NULL)
309 error("%s_%s: only 5 arguments are typecheckable; use A_GIMME",
310 c->c_name->s_name, sel->s_name);
311 va_end(ap);
312 m->me_arg[nargs] = A_NULL;
313 }
314 return;
315phooey:
316 bug("class_addmethod: %s_%s: bad argument types\n",
317 c->c_name->s_name, sel->s_name);
318}
319
320 /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */
321void class_addbang(t_class *c, t_method fn)
322{
323 c->c_bangmethod = (t_bangmethod)fn;
324}
325
326void class_addpointer(t_class *c, t_method fn)
327{
328 c->c_pointermethod = (t_pointermethod)fn;
329}
330
331void class_doaddfloat(t_class *c, t_method fn)
332{
333 c->c_floatmethod = (t_floatmethod)fn;
334}
335
336void class_addsymbol(t_class *c, t_method fn)
337{
338 c->c_symbolmethod = (t_symbolmethod)fn;
339}
340
341void class_addlist(t_class *c, t_method fn)
342{
343 c->c_listmethod = (t_listmethod)fn;
344}
345
346void class_addanything(t_class *c, t_method fn)
347{
348 c->c_anymethod = (t_anymethod)fn;
349}
350
351void class_setwidget(t_class *c, t_widgetbehavior *w)
352{
353 c->c_wb = w;
354}
355
356void class_setparentwidget(t_class *c, t_parentwidgetbehavior *pw)
357{
358 c->c_pwb = pw;
359}
360
361char *class_getname(t_class *c)
362{
363 return (c->c_name->s_name);
364}
365
366char *class_gethelpname(t_class *c)
367{
368 return (c->c_helpname->s_name);
369}
370
371void class_sethelpsymbol(t_class *c, t_symbol *s)
372{
373 c->c_helpname = s;
374}
375
376t_parentwidgetbehavior *pd_getparentwidget(t_pd *x)
377{
378 return ((*x)->c_pwb);
379}
380
381void class_setdrawcommand(t_class *c)
382{
383 c->c_drawcommand = 1;
384}
385
386int class_isdrawcommand(t_class *c)
387{
388 return (c->c_drawcommand);
389}
390
391static void pd_floatforsignal(t_pd *x, t_float f)
392{
393 int offset = (*x)->c_floatsignalin;
394 if (offset > 0)
395 *(t_sample *)(((char *)x) + offset) = ftofix(f);
396 else
397 pd_error(x, "%s: float unexpected for signal input",
398 (*x)->c_name->s_name);
399}
400
401void class_domainsignalin(t_class *c, int onset)
402{
403 if (onset <= 0) onset = -1;
404 else
405 {
406 if (c->c_floatmethod != pd_defaultfloat)
407 post("warning: %s: float method overwritten", c->c_name->s_name);
408 c->c_floatmethod = (t_floatmethod)pd_floatforsignal;
409 }
410 c->c_floatsignalin = onset;
411}
412
413void class_set_extern_dir(t_symbol *s)
414{
415 class_extern_dir = s;
416}
417
418char *class_gethelpdir(t_class *c)
419{
420 return (c->c_externdir->s_name);
421}
422
423static void class_nosavefn(t_gobj *z, t_binbuf *b)
424{
425 bug("save function called but not defined");
426}
427
428void class_setsavefn(t_class *c, t_savefn f)
429{
430 c->c_savefn = f;
431}
432
433t_savefn class_getsavefn(t_class *c)
434{
435 return (c->c_savefn);
436}
437
438void class_setpropertiesfn(t_class *c, t_propertiesfn f)
439{
440 c->c_propertiesfn = f;
441}
442
443t_propertiesfn class_getpropertiesfn(t_class *c)
444{
445 return (c->c_propertiesfn);
446}
447
448/* ---------------- the symbol table ------------------------ */
449
450#define HASHSIZE 1024
451
452static t_symbol *symhash[HASHSIZE];
453
454t_symbol *dogensym(char *s, t_symbol *oldsym)
455{
456 t_symbol **sym1, *sym2;
457 unsigned int hash1 = 0, hash2 = 0;
458 int length = 0;
459 char *s2 = s;
460 while (*s2)
461 {
462 hash1 += *s2;
463 hash2 += hash1;
464 length++;
465 s2++;
466 }
467 sym1 = symhash + (hash2 & (HASHSIZE-1));
468 while (sym2 = *sym1)
469 {
470 if (!strcmp(sym2->s_name, s)) return(sym2);
471 sym1 = &sym2->s_next;
472 }
473 if (oldsym) sym2 = oldsym;
474 else
475 {
476 sym2 = (t_symbol *)t_getbytes(sizeof(*sym2));
477 sym2->s_name = t_getbytes(length+1);
478 sym2->s_next = 0;
479 sym2->s_thing = 0;
480 strcpy(sym2->s_name, s);
481 }
482 *sym1 = sym2;
483 return (sym2);
484}
485
486t_symbol *gensym(char *s)
487{
488 return(dogensym(s, 0));
489}
490
491static t_symbol *addfileextent(t_symbol *s)
492{
493 char namebuf[MAXPDSTRING], *str = s->s_name;
494 int ln = strlen(str);
495 if (!strcmp(str + ln - 3, ".pd")) return (s);
496 strcpy(namebuf, str);
497 strcpy(namebuf+ln, ".pd");
498 return (gensym(namebuf));
499}
500
501static int tryingalready;
502
503void canvas_popabstraction(t_canvas *x);
504extern t_pd *newest;
505
506t_symbol* pathsearch(t_symbol *s,char* ext);
507int pd_setloadingabstraction(t_symbol *sym);
508
509 /* this routine is called when a new "object" is requested whose class Pd
510 doesn't know. Pd tries to load it as an extern, then as an abstraction. */
511void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv)
512{
513 t_pd *current;
514 t_symbol *dir = canvas_getcurrentdir();
515 int fd;
516 char dirbuf[MAXPDSTRING], *nameptr;
517 if (tryingalready) return;
518 newest = 0;
519 class_loadsym = s;
520 if (sys_load_lib(dir->s_name, s->s_name))
521 {
522 tryingalready = 1;
523 typedmess(dummy, s, argc, argv);
524 tryingalready = 0;
525 return;
526 }
527 class_loadsym = 0;
528 current = s__X.s_thing;
529 if ((fd = open_via_path(dir->s_name, s->s_name, ".pd",
530 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 ||
531 (fd = open_via_path(dir->s_name, s->s_name, ".pat",
532 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0)
533 {
534 close (fd);
535 if (!pd_setloadingabstraction(s))
536 {
537 canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */
538 binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
539 if (s__X.s_thing != current)
540 canvas_popabstraction((t_canvas *)(s__X.s_thing));
541 canvas_setargs(0, 0);
542 }
543 else error("%s: can't load abstraction within itself\n", s->s_name);
544 }
545 else newest = 0;
546}
547
548t_symbol s_pointer = {"pointer", 0, 0};
549t_symbol s_float = {"float", 0, 0};
550t_symbol s_symbol = {"symbol", 0, 0};
551t_symbol s_bang = {"bang", 0, 0};
552t_symbol s_list = {"list", 0, 0};
553t_symbol s_anything = {"anything", 0, 0};
554t_symbol s_signal = {"signal", 0, 0};
555t_symbol s__N = {"#N", 0, 0};
556t_symbol s__X = {"#X", 0, 0};
557t_symbol s_x = {"x", 0, 0};
558t_symbol s_y = {"y", 0, 0};
559t_symbol s_ = {"", 0, 0};
560
561static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang,
562 &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_};
563
564void mess_init(void)
565{
566 t_symbol **sp;
567 int i;
568
569 if (pd_objectmaker) return;
570 for (i = sizeof(symlist)/sizeof(*symlist), sp = symlist; i--; sp++)
571 (void) dogensym((*sp)->s_name, *sp);
572 pd_objectmaker = class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd),
573 CLASS_DEFAULT, A_NULL);
574 pd_canvasmaker = class_new(gensym("classmaker"), 0, 0, sizeof(t_pd),
575 CLASS_DEFAULT, A_NULL);
576 pd_bind(&pd_canvasmaker, &s__N);
577 class_addanything(pd_objectmaker, (t_method)new_anything);
578}
579
580t_pd *newest;
581
582/* This is externally available, but note that it might later disappear; the
583whole "newest" thing is a hack which needs to be redesigned. */
584t_pd *pd_newest(void)
585{
586 return (newest);
587}
588
589 /* horribly, we need prototypes for each of the artificial function
590 calls in typedmess(), to keep the compiler quiet. */
591typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv);
592typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
593
594typedef t_pd *(*t_fun0)(
595 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
596typedef t_pd *(*t_fun1)(t_int i1,
597 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
598typedef t_pd *(*t_fun2)(t_int i1, t_int i2,
599 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
600typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3,
601 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
602typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4,
603 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
604typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5,
605 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
606typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6,
607 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
608
609void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv)
610{
611 t_method *f;
612 t_class *c = *x;
613 t_methodentry *m;
614 t_atomtype *wp, wanttype;
615 int i;
616 t_int ai[MAXPDARG+1], *ap = ai;
617 t_floatarg ad[MAXPDARG+1], *dp = ad;
618 int narg = 0;
619 t_pd *bonzo;
620
621 /* check for messages that are handled by fixed slots in the class
622 structure. We don't catch "pointer" though so that sending "pointer"
623 to pd_objectmaker doesn't require that we supply a pointer value. */
624 if (s == &s_float)
625 {
626 if (!argc) (*c->c_floatmethod)(x, 0.);
627 else if (argv->a_type == A_FLOAT)
628 (*c->c_floatmethod)(x, argv->a_w.w_float);
629 else goto badarg;
630 return;
631 }
632 if (s == &s_bang)
633 {
634 (*c->c_bangmethod)(x);
635 return;
636 }
637 if (s == &s_list)
638 {
639 (*c->c_listmethod)(x, s, argc, argv);
640 return;
641 }
642 if (s == &s_symbol)
643 {
644 if (argc && argv->a_type == A_SYMBOL)
645 (*c->c_symbolmethod)(x, argv->a_w.w_symbol);
646 else
647 (*c->c_symbolmethod)(x, &s_);
648 return;
649 }
650 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
651 if (m->me_name == s)
652 {
653 wp = m->me_arg;
654 if (*wp == A_GIMME)
655 {
656 if (x == &pd_objectmaker)
657 newest = (*((t_newgimme)(m->me_fun)))(s, argc, argv);
658 else (*((t_messgimme)(m->me_fun)))(x, s, argc, argv);
659 return;
660 }
661 if (argc > MAXPDARG) argc = MAXPDARG;
662 if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++;
663 while (wanttype = *wp++)
664 {
665 switch (wanttype)
666 {
667 case A_POINTER:
668 if (!argc) goto badarg;
669 else
670 {
671 if (argv->a_type == A_POINTER)
672 *ap = (t_int)(argv->a_w.w_gpointer);
673 else goto badarg;
674 argc--;
675 argv++;
676 }
677 narg++;
678 ap++;
679 break;
680 case A_FLOAT:
681 if (!argc) goto badarg;
682 case A_DEFFLOAT:
683 if (!argc) *dp = 0;
684 else
685 {
686 if (argv->a_type == A_FLOAT)
687 *dp = argv->a_w.w_float;
688 else goto badarg;
689 argc--;
690 argv++;
691 }
692 dp++;
693 break;
694 case A_SYMBOL:
695 if (!argc) goto badarg;
696 case A_DEFSYM:
697 if (!argc) *ap = (t_int)(&s_);
698 else
699 {
700 if (argv->a_type == A_SYMBOL)
701 *ap = (t_int)(argv->a_w.w_symbol);
702 /* if it's an unfilled "dollar" argument it appears
703 as zero here; cheat and bash it to the null
704 symbol. Unfortunately, this lets real zeros
705 pass as symbols too, which seems wrong... */
706 else if (x == &pd_objectmaker && argv->a_type == A_FLOAT
707 && argv->a_w.w_float == 0)
708 *ap = (t_int)(&s_);
709 else goto badarg;
710 argc--;
711 argv++;
712 }
713 narg++;
714 ap++;
715 }
716 }
717 switch (narg)
718 {
719 case 0 : bonzo = (*(t_fun0)(m->me_fun))
720 (ad[0], ad[1], ad[2], ad[3], ad[4]); break;
721 case 1 : bonzo = (*(t_fun1)(m->me_fun))
722 (ai[0], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
723 case 2 : bonzo = (*(t_fun2)(m->me_fun))
724 (ai[0], ai[1], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
725 case 3 : bonzo = (*(t_fun3)(m->me_fun))
726 (ai[0], ai[1], ai[2], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
727 case 4 : bonzo = (*(t_fun4)(m->me_fun))
728 (ai[0], ai[1], ai[2], ai[3],
729 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
730 case 5 : bonzo = (*(t_fun5)(m->me_fun))
731 (ai[0], ai[1], ai[2], ai[3], ai[4],
732 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
733 case 6 : bonzo = (*(t_fun6)(m->me_fun))
734 (ai[0], ai[1], ai[2], ai[3], ai[4], ai[5],
735 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
736 default: bonzo = 0;
737 }
738 if (x == &pd_objectmaker)
739 newest = bonzo;
740 return;
741 }
742 (*c->c_anymethod)(x, s, argc, argv);
743 return;
744badarg:
745 pd_error(x, "Bad arguments for message '%s' to object '%s'",
746 s->s_name, c->c_name->s_name);
747}
748
749void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...)
750{
751 va_list ap;
752 t_atom arg[MAXPDARG], *at =arg;
753 int nargs = 0;
754 char *fp = fmt;
755
756 va_start(ap, fmt);
757 while (1)
758 {
759 if (nargs > MAXPDARG)
760 {
761 pd_error(x, "pd_vmess: only %d allowed", MAXPDARG);
762 break;
763 }
764 switch(*fp++)
765 {
766 case 'f': SETFLOAT(at, va_arg(ap, double)); break;
767 case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
768 case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
769 case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break;
770 default: goto done;
771 }
772 at++;
773 nargs++;
774 }
775done:
776 va_end(ap);
777 typedmess(x, sel, nargs, arg);
778}
779
780void pd_forwardmess(t_pd *x, int argc, t_atom *argv)
781{
782 if (argc)
783 {
784 t_atomtype t = argv->a_type;
785 if (t == A_SYMBOL) pd_typedmess(x, argv->a_w.w_symbol, argc-1, argv+1);
786 else if (t == A_POINTER)
787 {
788 if (argc == 1) pd_pointer(x, argv->a_w.w_gpointer);
789 else pd_list(x, &s_list, argc, argv);
790 }
791 else if (t == A_FLOAT)
792 {
793 if (argc == 1) pd_float(x, argv->a_w.w_float);
794 else pd_list(x, &s_list, argc, argv);
795 }
796 else bug("pd_forwardmess");
797 }
798
799}
800
801void nullfn(void) {}
802
803t_gotfn getfn(t_pd *x, t_symbol *s)
804{
805 t_class *c = *x;
806 t_methodentry *m;
807 int i;
808
809 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
810 if (m->me_name == s) return(m->me_fun);
811 pd_error(x, "%s: no method for message '%s'", c->c_name->s_name, s->s_name);
812 return((t_gotfn)nullfn);
813}
814
815t_gotfn zgetfn(t_pd *x, t_symbol *s)
816{
817 t_class *c = *x;
818 t_methodentry *m;
819 int i;
820
821 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
822 if (m->me_name == s) return(m->me_fun);
823 return(0);
824}
825/* Copyright (c) 1997-1999 Miller Puckette.
826* For information on usage and redistribution, and for a DISCLAIMER OF ALL
827* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
828
829#define PD_CLASS_DEF
830#include "m_pd.h"
831#include "m_imp.h"
832#include "s_stuff.h"
833#include <stdlib.h>
834#ifdef UNIX
835#include <unistd.h>
836#endif
837#ifdef MSW
838#include <io.h>
839#endif
840
841#include <stdarg.h>
842#include <string.h>
843
844static t_symbol *class_loadsym; /* name under which an extern is invoked */
845static void pd_defaultfloat(t_pd *x, t_float f);
846static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv);
847t_pd pd_objectmaker; /* factory for creating "object" boxes */
848t_pd pd_canvasmaker; /* factory for creating canvases */
849
850static t_symbol *class_extern_dir = &s_;
851
852static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv)
853{
854 pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name);
855}
856
857static void pd_defaultbang(t_pd *x)
858{
859 if (*(*x)->c_listmethod != pd_defaultlist)
860 (*(*x)->c_listmethod)(x, 0, 0, 0);
861 else (*(*x)->c_anymethod)(x, &s_bang, 0, 0);
862}
863
864static void pd_defaultpointer(t_pd *x, t_gpointer *gp)
865{
866 if (*(*x)->c_listmethod != pd_defaultlist)
867 {
868 t_atom at;
869 SETPOINTER(&at, gp);
870 (*(*x)->c_listmethod)(x, 0, 1, &at);
871 }
872 else
873 {
874 t_atom at;
875 SETPOINTER(&at, gp);
876 (*(*x)->c_anymethod)(x, &s_pointer, 1, &at);
877 }
878}
879
880static void pd_defaultfloat(t_pd *x, t_float f)
881{
882 if (*(*x)->c_listmethod != pd_defaultlist)
883 {
884 t_atom at;
885 SETFLOAT(&at, f);
886 (*(*x)->c_listmethod)(x, 0, 1, &at);
887 }
888 else
889 {
890 t_atom at;
891 SETFLOAT(&at, f);
892 (*(*x)->c_anymethod)(x, &s_float, 1, &at);
893 }
894}
895
896static void pd_defaultsymbol(t_pd *x, t_symbol *s)
897{
898 if (*(*x)->c_listmethod != pd_defaultlist)
899 {
900 t_atom at;
901 SETSYMBOL(&at, s);
902 (*(*x)->c_listmethod)(x, 0, 1, &at);
903 }
904 else
905 {
906 t_atom at;
907 SETSYMBOL(&at, s);
908 (*(*x)->c_anymethod)(x, &s_symbol, 1, &at);
909 }
910}
911
912void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
913static void class_nosavefn(t_gobj *z, t_binbuf *b);
914
915 /* handle "list" messages to Pds without explicit list methods defined. */
916static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv)
917{
918 /* a list with one element which is a number can be handled by a
919 "float" method if any is defined; same for "symbol", "pointer". */
920 if (argc == 1)
921 {
922 if (argv->a_type == A_FLOAT &&
923 *(*x)->c_floatmethod != pd_defaultfloat)
924 {
925 (*(*x)->c_floatmethod)(x, argv->a_w.w_float);
926 return;
927 }
928 else if (argv->a_type == A_SYMBOL &&
929 *(*x)->c_symbolmethod != pd_defaultsymbol)
930 {
931 (*(*x)->c_symbolmethod)(x, argv->a_w.w_symbol);
932 return;
933 }
934 else if (argv->a_type == A_POINTER &&
935 *(*x)->c_pointermethod != pd_defaultpointer)
936 {
937 (*(*x)->c_pointermethod)(x, argv->a_w.w_gpointer);
938 return;
939 }
940 }
941 /* Next try for an "anything" method */
942 if ((*x)->c_anymethod != pd_defaultanything)
943 (*(*x)->c_anymethod)(x, &s_list, argc, argv);
944
945 /* if the object is patchable (i.e., can have proper inlets)
946 send it on to obj_list which will unpack the list into the inlets */
947 else if ((*x)->c_patchable)
948 obj_list((t_object *)x, s, argc, argv);
949 /* otherwise gove up and complain. */
950 else pd_defaultanything(x, &s_list, argc, argv);
951}
952
953 /* for now we assume that all "gobjs" are text unless explicitly
954 overridden later by calling class_setbehavior(). I'm not sure
955 how to deal with Pds that aren't gobjs; shouldn't there be a
956 way to check that at run time? Perhaps the presence of a "newmethod"
957 should be our cue, or perhaps the "tiny" flag. */
958
959 /* another matter. This routine does two unrelated things: it creates
960 a Pd class, but also adds a "new" method to create an instance of it.
961 These are combined for historical reasons and for brevity in writing
962 objects. To avoid adding a "new" method send a null function pointer.
963 To add additional ones, use class_addcreator below. Some "classes", like
964 "select", are actually two classes of the same name, one for the single-
965 argument form, one for the multiple one; see select_setup() to find out
966 how this is handled. */
967
968extern t_widgetbehavior text_widgetbehavior;
969extern void text_save(t_gobj *z, t_binbuf *b);
970
971t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod,
972 size_t size, int flags, t_atomtype type1, ...)
973{
974 va_list ap;
975 t_atomtype vec[MAXPDARG+1], *vp = vec;
976 int count = 0;
977 t_class *c;
978 int typeflag = flags & CLASS_TYPEMASK;
979 if (!typeflag) typeflag = CLASS_PATCHABLE;
980 *vp = type1;
981
982 va_start(ap, type1);
983 while (*vp)
984 {
985 if (count == MAXPDARG)
986 {
987 error("class %s: sorry: only %d creation args allowed",
988 s->s_name, MAXPDARG);
989 break;
990 }
991 vp++;
992 count++;
993 *vp = va_arg(ap, t_atomtype);
994 }
995 va_end(ap);
996 if (pd_objectmaker && newmethod)
997 {
998 /* add a "new" method by the name specified by the object */
999 class_addmethod(pd_objectmaker, (t_method)newmethod, s,
1000 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
1001 if (class_loadsym)
1002 {
1003 /* if we're loading an extern it might have been invoked by a
1004 longer file name; in this case, make this an admissible name
1005 too. */
1006 char *loadstring = class_loadsym->s_name,
1007 l1 = strlen(s->s_name), l2 = strlen(loadstring);
1008 if (l2 > l1 && !strcmp(s->s_name, loadstring + (l2 - l1)))
1009 class_addmethod(pd_objectmaker, (t_method)newmethod,
1010 class_loadsym,
1011 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
1012 }
1013 }
1014 c = (t_class *)t_getbytes(sizeof(*c));
1015 c->c_name = c->c_helpname = s;
1016 c->c_size = size;
1017 c->c_methods = t_getbytes(0);
1018 c->c_nmethod = 0;
1019 c->c_freemethod = (t_method)freemethod;
1020 c->c_bangmethod = pd_defaultbang;
1021 c->c_pointermethod = pd_defaultpointer;
1022 c->c_floatmethod = pd_defaultfloat;
1023 c->c_symbolmethod = pd_defaultsymbol;
1024 c->c_listmethod = pd_defaultlist;
1025 c->c_anymethod = pd_defaultanything;
1026 c->c_wb = (typeflag == CLASS_PATCHABLE ? &text_widgetbehavior : 0);
1027 c->c_pwb = 0;
1028 c->c_firstin = ((flags & CLASS_NOINLET) == 0);
1029 c->c_patchable = (typeflag == CLASS_PATCHABLE);
1030 c->c_gobj = (typeflag >= CLASS_GOBJ);
1031 c->c_drawcommand = 0;
1032 c->c_floatsignalin = 0;
1033 c->c_externdir = class_extern_dir;
1034 c->c_savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn);
1035#if 0
1036 post("class: %s", c->c_name->s_name);
1037#endif
1038 return (c);
1039}
1040
1041 /* add a creation method, which is a function that returns a Pd object
1042 suitable for putting in an object box. We presume you've got a class it
1043 can belong to, but this won't be used until the newmethod is actually
1044 called back (and the new method explicitly takes care of this.) */
1045
1046void class_addcreator(t_newmethod newmethod, t_symbol *s,
1047 t_atomtype type1, ...)
1048{
1049 va_list ap;
1050 t_atomtype vec[MAXPDARG+1], *vp = vec;
1051 int count = 0;
1052 *vp = type1;
1053
1054 va_start(ap, type1);
1055 while (*vp)
1056 {
1057 if (count == MAXPDARG)
1058 {
1059 error("class %s: sorry: only %d creation args allowed",
1060 s->s_name, MAXPDARG);
1061 break;
1062 }
1063 vp++;
1064 count++;
1065 *vp = va_arg(ap, t_atomtype);
1066 }
1067 va_end(ap);
1068 class_addmethod(pd_objectmaker, (t_method)newmethod, s,
1069 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
1070}
1071
1072void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
1073 t_atomtype arg1, ...)
1074{
1075 va_list ap;
1076 t_methodentry *m;
1077 t_atomtype argtype = arg1;
1078 int nargs;
1079
1080 va_start(ap, arg1);
1081 /* "signal" method specifies that we take audio signals but
1082 that we don't want automatic float to signal conversion. This
1083 is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */
1084 if (sel == &s_signal)
1085 {
1086 if (c->c_floatsignalin)
1087 post("warning: signal method overrides class_mainsignalin");
1088 c->c_floatsignalin = -1;
1089 }
1090 /* check for special cases. "Pointer" is missing here so that
1091 pd_objectmaker's pointer method can be typechecked differently. */
1092 if (sel == &s_bang)
1093 {
1094 if (argtype) goto phooey;
1095 class_addbang(c, fn);
1096 }
1097 else if (sel == &s_float)
1098 {
1099 if (argtype != A_FLOAT || va_arg(ap, t_atomtype)) goto phooey;
1100 class_doaddfloat(c, fn);
1101 }
1102 else if (sel == &s_symbol)
1103 {
1104 if (argtype != A_SYMBOL || va_arg(ap, t_atomtype)) goto phooey;
1105 class_addsymbol(c, fn);
1106 }
1107 else if (sel == &s_list)
1108 {
1109 if (argtype != A_GIMME) goto phooey;
1110 class_addlist(c, fn);
1111 }
1112 else if (sel == &s_anything)
1113 {
1114 if (argtype != A_GIMME) goto phooey;
1115 class_addanything(c, fn);
1116 }
1117 else
1118 {
1119 c->c_methods = t_resizebytes(c->c_methods,
1120 c->c_nmethod * sizeof(*c->c_methods),
1121 (c->c_nmethod + 1) * sizeof(*c->c_methods));
1122 m = c->c_methods + c->c_nmethod;
1123 c->c_nmethod++;
1124 m->me_name = sel;
1125 m->me_fun = (t_gotfn)fn;
1126 nargs = 0;
1127 while (argtype != A_NULL && nargs < MAXPDARG)
1128 {
1129 m->me_arg[nargs++] = argtype;
1130 argtype = va_arg(ap, t_atomtype);
1131 }
1132 if (argtype != A_NULL)
1133 error("%s_%s: only 5 arguments are typecheckable; use A_GIMME",
1134 c->c_name->s_name, sel->s_name);
1135 va_end(ap);
1136 m->me_arg[nargs] = A_NULL;
1137 }
1138 return;
1139phooey:
1140 bug("class_addmethod: %s_%s: bad argument types\n",
1141 c->c_name->s_name, sel->s_name);
1142}
1143
1144 /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */
1145void class_addbang(t_class *c, t_method fn)
1146{
1147 c->c_bangmethod = (t_bangmethod)fn;
1148}
1149
1150void class_addpointer(t_class *c, t_method fn)
1151{
1152 c->c_pointermethod = (t_pointermethod)fn;
1153}
1154
1155void class_doaddfloat(t_class *c, t_method fn)
1156{
1157 c->c_floatmethod = (t_floatmethod)fn;
1158}
1159
1160void class_addsymbol(t_class *c, t_method fn)
1161{
1162 c->c_symbolmethod = (t_symbolmethod)fn;
1163}
1164
1165void class_addlist(t_class *c, t_method fn)
1166{
1167 c->c_listmethod = (t_listmethod)fn;
1168}
1169
1170void class_addanything(t_class *c, t_method fn)
1171{
1172 c->c_anymethod = (t_anymethod)fn;
1173}
1174
1175void class_setwidget(t_class *c, t_widgetbehavior *w)
1176{
1177 c->c_wb = w;
1178}
1179
1180void class_setparentwidget(t_class *c, t_parentwidgetbehavior *pw)
1181{
1182 c->c_pwb = pw;
1183}
1184
1185char *class_getname(t_class *c)
1186{
1187 return (c->c_name->s_name);
1188}
1189
1190char *class_gethelpname(t_class *c)
1191{
1192 return (c->c_helpname->s_name);
1193}
1194
1195void class_sethelpsymbol(t_class *c, t_symbol *s)
1196{
1197 c->c_helpname = s;
1198}
1199
1200t_parentwidgetbehavior *pd_getparentwidget(t_pd *x)
1201{
1202 return ((*x)->c_pwb);
1203}
1204
1205void class_setdrawcommand(t_class *c)
1206{
1207 c->c_drawcommand = 1;
1208}
1209
1210int class_isdrawcommand(t_class *c)
1211{
1212 return (c->c_drawcommand);
1213}
1214
1215static void pd_floatforsignal(t_pd *x, t_float f)
1216{
1217 int offset = (*x)->c_floatsignalin;
1218 if (offset > 0)
1219 *(t_sample *)(((char *)x) + offset) = ftofix(f);
1220 else
1221 pd_error(x, "%s: float unexpected for signal input",
1222 (*x)->c_name->s_name);
1223}
1224
1225void class_domainsignalin(t_class *c, int onset)
1226{
1227 if (onset <= 0) onset = -1;
1228 else
1229 {
1230 if (c->c_floatmethod != pd_defaultfloat)
1231 post("warning: %s: float method overwritten", c->c_name->s_name);
1232 c->c_floatmethod = (t_floatmethod)pd_floatforsignal;
1233 }
1234 c->c_floatsignalin = onset;
1235}
1236
1237void class_set_extern_dir(t_symbol *s)
1238{
1239 class_extern_dir = s;
1240}
1241
1242char *class_gethelpdir(t_class *c)
1243{
1244 return (c->c_externdir->s_name);
1245}
1246
1247static void class_nosavefn(t_gobj *z, t_binbuf *b)
1248{
1249 bug("save function called but not defined");
1250}
1251
1252void class_setsavefn(t_class *c, t_savefn f)
1253{
1254 c->c_savefn = f;
1255}
1256
1257t_savefn class_getsavefn(t_class *c)
1258{
1259 return (c->c_savefn);
1260}
1261
1262void class_setpropertiesfn(t_class *c, t_propertiesfn f)
1263{
1264 c->c_propertiesfn = f;
1265}
1266
1267t_propertiesfn class_getpropertiesfn(t_class *c)
1268{
1269 return (c->c_propertiesfn);
1270}
1271
1272/* ---------------- the symbol table ------------------------ */
1273
1274#define HASHSIZE 1024
1275
1276static t_symbol *symhash[HASHSIZE];
1277
1278t_symbol *dogensym(char *s, t_symbol *oldsym)
1279{
1280 t_symbol **sym1, *sym2;
1281 unsigned int hash1 = 0, hash2 = 0;
1282 int length = 0;
1283 char *s2 = s;
1284 while (*s2)
1285 {
1286 hash1 += *s2;
1287 hash2 += hash1;
1288 length++;
1289 s2++;
1290 }
1291 sym1 = symhash + (hash2 & (HASHSIZE-1));
1292 while (sym2 = *sym1)
1293 {
1294 if (!strcmp(sym2->s_name, s)) return(sym2);
1295 sym1 = &sym2->s_next;
1296 }
1297 if (oldsym) sym2 = oldsym;
1298 else
1299 {
1300 sym2 = (t_symbol *)t_getbytes(sizeof(*sym2));
1301 sym2->s_name = t_getbytes(length+1);
1302 sym2->s_next = 0;
1303 sym2->s_thing = 0;
1304 strcpy(sym2->s_name, s);
1305 }
1306 *sym1 = sym2;
1307 return (sym2);
1308}
1309
1310t_symbol *gensym(char *s)
1311{
1312 return(dogensym(s, 0));
1313}
1314
1315static t_symbol *addfileextent(t_symbol *s)
1316{
1317 char namebuf[MAXPDSTRING], *str = s->s_name;
1318 int ln = strlen(str);
1319 if (!strcmp(str + ln - 3, ".pd")) return (s);
1320 strcpy(namebuf, str);
1321 strcpy(namebuf+ln, ".pd");
1322 return (gensym(namebuf));
1323}
1324
1325static int tryingalready;
1326
1327void canvas_popabstraction(t_canvas *x);
1328extern t_pd *newest;
1329
1330t_symbol* pathsearch(t_symbol *s,char* ext);
1331int pd_setloadingabstraction(t_symbol *sym);
1332
1333 /* this routine is called when a new "object" is requested whose class Pd
1334 doesn't know. Pd tries to load it as an extern, then as an abstraction. */
1335void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv)
1336{
1337 t_pd *current;
1338 t_symbol *dir = canvas_getcurrentdir();
1339 int fd;
1340 char dirbuf[MAXPDSTRING], *nameptr;
1341 if (tryingalready) return;
1342 newest = 0;
1343 class_loadsym = s;
1344 if (sys_load_lib(dir->s_name, s->s_name))
1345 {
1346 tryingalready = 1;
1347 typedmess(dummy, s, argc, argv);
1348 tryingalready = 0;
1349 return;
1350 }
1351 class_loadsym = 0;
1352 current = s__X.s_thing;
1353 if ((fd = open_via_path(dir->s_name, s->s_name, ".pd",
1354 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 ||
1355 (fd = open_via_path(dir->s_name, s->s_name, ".pat",
1356 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0)
1357 {
1358 close (fd);
1359 if (!pd_setloadingabstraction(s))
1360 {
1361 canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */
1362 binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
1363 if (s__X.s_thing != current)
1364 canvas_popabstraction((t_canvas *)(s__X.s_thing));
1365 canvas_setargs(0, 0);
1366 }
1367 else error("%s: can't load abstraction within itself\n", s->s_name);
1368 }
1369 else newest = 0;
1370}
1371
1372t_symbol s_pointer = {"pointer", 0, 0};
1373t_symbol s_float = {"float", 0, 0};
1374t_symbol s_symbol = {"symbol", 0, 0};
1375t_symbol s_bang = {"bang", 0, 0};
1376t_symbol s_list = {"list", 0, 0};
1377t_symbol s_anything = {"anything", 0, 0};
1378t_symbol s_signal = {"signal", 0, 0};
1379t_symbol s__N = {"#N", 0, 0};
1380t_symbol s__X = {"#X", 0, 0};
1381t_symbol s_x = {"x", 0, 0};
1382t_symbol s_y = {"y", 0, 0};
1383t_symbol s_ = {"", 0, 0};
1384
1385static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang,
1386 &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_};
1387
1388void mess_init(void)
1389{
1390 t_symbol **sp;
1391 int i;
1392
1393 if (pd_objectmaker) return;
1394 for (i = sizeof(symlist)/sizeof(*symlist), sp = symlist; i--; sp++)
1395 (void) dogensym((*sp)->s_name, *sp);
1396 pd_objectmaker = class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd),
1397 CLASS_DEFAULT, A_NULL);
1398 pd_canvasmaker = class_new(gensym("classmaker"), 0, 0, sizeof(t_pd),
1399 CLASS_DEFAULT, A_NULL);
1400 pd_bind(&pd_canvasmaker, &s__N);
1401 class_addanything(pd_objectmaker, (t_method)new_anything);
1402}
1403
1404t_pd *newest;
1405
1406/* This is externally available, but note that it might later disappear; the
1407whole "newest" thing is a hack which needs to be redesigned. */
1408t_pd *pd_newest(void)
1409{
1410 return (newest);
1411}
1412
1413 /* horribly, we need prototypes for each of the artificial function
1414 calls in typedmess(), to keep the compiler quiet. */
1415typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv);
1416typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
1417
1418typedef t_pd *(*t_fun0)(
1419 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1420typedef t_pd *(*t_fun1)(t_int i1,
1421 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1422typedef t_pd *(*t_fun2)(t_int i1, t_int i2,
1423 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1424typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3,
1425 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1426typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4,
1427 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1428typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5,
1429 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1430typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6,
1431 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1432
1433void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv)
1434{
1435 t_method *f;
1436 t_class *c = *x;
1437 t_methodentry *m;
1438 t_atomtype *wp, wanttype;
1439 int i;
1440 t_int ai[MAXPDARG+1], *ap = ai;
1441 t_floatarg ad[MAXPDARG+1], *dp = ad;
1442 int narg = 0;
1443 t_pd *bonzo;
1444
1445 /* check for messages that are handled by fixed slots in the class
1446 structure. We don't catch "pointer" though so that sending "pointer"
1447 to pd_objectmaker doesn't require that we supply a pointer value. */
1448 if (s == &s_float)
1449 {
1450 if (!argc) (*c->c_floatmethod)(x, 0.);
1451 else if (argv->a_type == A_FLOAT)
1452 (*c->c_floatmethod)(x, argv->a_w.w_float);
1453 else goto badarg;
1454 return;
1455 }
1456 if (s == &s_bang)
1457 {
1458 (*c->c_bangmethod)(x);
1459 return;
1460 }
1461 if (s == &s_list)
1462 {
1463 (*c->c_listmethod)(x, s, argc, argv);
1464 return;
1465 }
1466 if (s == &s_symbol)
1467 {
1468 if (argc && argv->a_type == A_SYMBOL)
1469 (*c->c_symbolmethod)(x, argv->a_w.w_symbol);
1470 else
1471 (*c->c_symbolmethod)(x, &s_);
1472 return;
1473 }
1474 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
1475 if (m->me_name == s)
1476 {
1477 wp = m->me_arg;
1478 if (*wp == A_GIMME)
1479 {
1480 if (x == &pd_objectmaker)
1481 newest = (*((t_newgimme)(m->me_fun)))(s, argc, argv);
1482 else (*((t_messgimme)(m->me_fun)))(x, s, argc, argv);
1483 return;
1484 }
1485 if (argc > MAXPDARG) argc = MAXPDARG;
1486 if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++;
1487 while (wanttype = *wp++)
1488 {
1489 switch (wanttype)
1490 {
1491 case A_POINTER:
1492 if (!argc) goto badarg;
1493 else
1494 {
1495 if (argv->a_type == A_POINTER)
1496 *ap = (t_int)(argv->a_w.w_gpointer);
1497 else goto badarg;
1498 argc--;
1499 argv++;
1500 }
1501 narg++;
1502 ap++;
1503 break;
1504 case A_FLOAT:
1505 if (!argc) goto badarg;
1506 case A_DEFFLOAT:
1507 if (!argc) *dp = 0;
1508 else
1509 {
1510 if (argv->a_type == A_FLOAT)
1511 *dp = argv->a_w.w_float;
1512 else goto badarg;
1513 argc--;
1514 argv++;
1515 }
1516 dp++;
1517 break;
1518 case A_SYMBOL:
1519 if (!argc) goto badarg;
1520 case A_DEFSYM:
1521 if (!argc) *ap = (t_int)(&s_);
1522 else
1523 {
1524 if (argv->a_type == A_SYMBOL)
1525 *ap = (t_int)(argv->a_w.w_symbol);
1526 /* if it's an unfilled "dollar" argument it appears
1527 as zero here; cheat and bash it to the null
1528 symbol. Unfortunately, this lets real zeros
1529 pass as symbols too, which seems wrong... */
1530 else if (x == &pd_objectmaker && argv->a_type == A_FLOAT
1531 && argv->a_w.w_float == 0)
1532 *ap = (t_int)(&s_);
1533 else goto badarg;
1534 argc--;
1535 argv++;
1536 }
1537 narg++;
1538 ap++;
1539 }
1540 }
1541 switch (narg)
1542 {
1543 case 0 : bonzo = (*(t_fun0)(m->me_fun))
1544 (ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1545 case 1 : bonzo = (*(t_fun1)(m->me_fun))
1546 (ai[0], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1547 case 2 : bonzo = (*(t_fun2)(m->me_fun))
1548 (ai[0], ai[1], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1549 case 3 : bonzo = (*(t_fun3)(m->me_fun))
1550 (ai[0], ai[1], ai[2], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1551 case 4 : bonzo = (*(t_fun4)(m->me_fun))
1552 (ai[0], ai[1], ai[2], ai[3],
1553 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1554 case 5 : bonzo = (*(t_fun5)(m->me_fun))
1555 (ai[0], ai[1], ai[2], ai[3], ai[4],
1556 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1557 case 6 : bonzo = (*(t_fun6)(m->me_fun))
1558 (ai[0], ai[1], ai[2], ai[3], ai[4], ai[5],
1559 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1560 default: bonzo = 0;
1561 }
1562 if (x == &pd_objectmaker)
1563 newest = bonzo;
1564 return;
1565 }
1566 (*c->c_anymethod)(x, s, argc, argv);
1567 return;
1568badarg:
1569 pd_error(x, "Bad arguments for message '%s' to object '%s'",
1570 s->s_name, c->c_name->s_name);
1571}
1572
1573void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...)
1574{
1575 va_list ap;
1576 t_atom arg[MAXPDARG], *at =arg;
1577 int nargs = 0;
1578 char *fp = fmt;
1579
1580 va_start(ap, fmt);
1581 while (1)
1582 {
1583 if (nargs > MAXPDARG)
1584 {
1585 pd_error(x, "pd_vmess: only %d allowed", MAXPDARG);
1586 break;
1587 }
1588 switch(*fp++)
1589 {
1590 case 'f': SETFLOAT(at, va_arg(ap, double)); break;
1591 case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
1592 case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
1593 case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break;
1594 default: goto done;
1595 }
1596 at++;
1597 nargs++;
1598 }
1599done:
1600 va_end(ap);
1601 typedmess(x, sel, nargs, arg);
1602}
1603
1604void pd_forwardmess(t_pd *x, int argc, t_atom *argv)
1605{
1606 if (argc)
1607 {
1608 t_atomtype t = argv->a_type;
1609 if (t == A_SYMBOL) pd_typedmess(x, argv->a_w.w_symbol, argc-1, argv+1);
1610 else if (t == A_POINTER)
1611 {
1612 if (argc == 1) pd_pointer(x, argv->a_w.w_gpointer);
1613 else pd_list(x, &s_list, argc, argv);
1614 }
1615 else if (t == A_FLOAT)
1616 {
1617 if (argc == 1) pd_float(x, argv->a_w.w_float);
1618 else pd_list(x, &s_list, argc, argv);
1619 }
1620 else bug("pd_forwardmess");
1621 }
1622
1623}
1624
1625void nullfn(void) {}
1626
1627t_gotfn getfn(t_pd *x, t_symbol *s)
1628{
1629 t_class *c = *x;
1630 t_methodentry *m;
1631 int i;
1632
1633 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
1634 if (m->me_name == s) return(m->me_fun);
1635 pd_error(x, "%s: no method for message '%s'", c->c_name->s_name, s->s_name);
1636 return((t_gotfn)nullfn);
1637}
1638
1639t_gotfn zgetfn(t_pd *x, t_symbol *s)
1640{
1641 t_class *c = *x;
1642 t_methodentry *m;
1643 int i;
1644
1645 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
1646 if (m->me_name == s) return(m->me_fun);
1647 return(0);
1648}
diff --git a/apps/plugins/pdbox/PDa/src/m_conf.c b/apps/plugins/pdbox/PDa/src/m_conf.c
new file mode 100644
index 0000000000..8d3f5423a1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_conf.c
@@ -0,0 +1,202 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
6/* all changes are labeled with iemlib */
7
8#include "m_pd.h"
9
10void g_array_setup(void);
11void g_canvas_setup(void);
12void g_guiconnect_setup(void);
13/* iemlib */
14void g_bang_setup(void);
15void g_hradio_setup(void);
16void g_hslider_setup(void);
17void g_mycanvas_setup(void);
18void g_numbox_setup(void);
19void g_toggle_setup(void);
20void g_vradio_setup(void);
21void g_vslider_setup(void);
22void g_vumeter_setup(void);
23/* iemlib */
24void g_io_setup(void);
25void g_scalar_setup(void);
26void g_template_setup(void);
27void g_text_setup(void);
28void g_traversal_setup(void);
29void m_pd_setup(void);
30void x_acoustics_setup(void);
31void x_interface_setup(void);
32void x_connective_setup(void);
33void x_time_setup(void);
34void x_arithmetic_setup(void);
35void x_midi_setup(void);
36void x_misc_setup(void);
37void x_net_setup(void);
38void x_qlist_setup(void);
39void x_gui_setup(void);
40void d_arithmetic_setup(void);
41void d_array_setup(void);
42void d_ctl_setup(void);
43void d_dac_setup(void);
44void d_delay_setup(void);
45void d_fft_setup(void);
46void d_filter_setup(void);
47void d_global_setup(void);
48void d_math_setup(void);
49void d_misc_setup(void);
50void d_osc_setup(void);
51void d_soundfile_setup(void);
52void d_ugen_setup(void);
53
54void conf_init(void)
55{
56 g_array_setup();
57 g_canvas_setup();
58 g_guiconnect_setup();
59/* iemlib */
60
61 g_bang_setup();
62 g_hradio_setup();
63 g_hslider_setup();
64 g_mycanvas_setup();
65 g_numbox_setup();
66 g_toggle_setup();
67 g_vradio_setup();
68 g_vslider_setup();
69 g_vumeter_setup();
70/* iemlib */
71
72 g_io_setup();
73 g_scalar_setup();
74 g_template_setup();
75 g_text_setup();
76 g_traversal_setup();
77 m_pd_setup();
78 x_acoustics_setup();
79 x_interface_setup();
80 x_connective_setup();
81 x_time_setup();
82 x_arithmetic_setup();
83
84 x_midi_setup();
85 x_misc_setup();
86 x_net_setup();
87 x_qlist_setup();
88 x_gui_setup();
89 d_arithmetic_setup();
90 d_dac_setup();
91 d_fft_setup();
92 d_global_setup();
93 d_misc_setup();
94#ifdef STATIC
95 d_intern_setup();
96#endif
97 d_soundfile_setup();
98 d_ugen_setup();
99
100}
101
102/* Copyright (c) 1997-1999 Miller Puckette.
103* For information on usage and redistribution, and for a DISCLAIMER OF ALL
104* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
105
106/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
107/* all changes are labeled with iemlib */
108
109#include "m_pd.h"
110
111void g_array_setup(void);
112void g_canvas_setup(void);
113void g_guiconnect_setup(void);
114/* iemlib */
115void g_bang_setup(void);
116void g_hradio_setup(void);
117void g_hslider_setup(void);
118void g_mycanvas_setup(void);
119void g_numbox_setup(void);
120void g_toggle_setup(void);
121void g_vradio_setup(void);
122void g_vslider_setup(void);
123void g_vumeter_setup(void);
124/* iemlib */
125void g_io_setup(void);
126void g_scalar_setup(void);
127void g_template_setup(void);
128void g_text_setup(void);
129void g_traversal_setup(void);
130void m_pd_setup(void);
131void x_acoustics_setup(void);
132void x_interface_setup(void);
133void x_connective_setup(void);
134void x_time_setup(void);
135void x_arithmetic_setup(void);
136void x_midi_setup(void);
137void x_misc_setup(void);
138void x_net_setup(void);
139void x_qlist_setup(void);
140void x_gui_setup(void);
141void d_arithmetic_setup(void);
142void d_array_setup(void);
143void d_ctl_setup(void);
144void d_dac_setup(void);
145void d_delay_setup(void);
146void d_fft_setup(void);
147void d_filter_setup(void);
148void d_global_setup(void);
149void d_math_setup(void);
150void d_misc_setup(void);
151void d_osc_setup(void);
152void d_soundfile_setup(void);
153void d_ugen_setup(void);
154
155void conf_init(void)
156{
157 g_array_setup();
158 g_canvas_setup();
159 g_guiconnect_setup();
160/* iemlib */
161
162 g_bang_setup();
163 g_hradio_setup();
164 g_hslider_setup();
165 g_mycanvas_setup();
166 g_numbox_setup();
167 g_toggle_setup();
168 g_vradio_setup();
169 g_vslider_setup();
170 g_vumeter_setup();
171/* iemlib */
172
173 g_io_setup();
174 g_scalar_setup();
175 g_template_setup();
176 g_text_setup();
177 g_traversal_setup();
178 m_pd_setup();
179 x_acoustics_setup();
180 x_interface_setup();
181 x_connective_setup();
182 x_time_setup();
183 x_arithmetic_setup();
184
185 x_midi_setup();
186 x_misc_setup();
187 x_net_setup();
188 x_qlist_setup();
189 x_gui_setup();
190 d_arithmetic_setup();
191 d_dac_setup();
192 d_fft_setup();
193 d_global_setup();
194 d_misc_setup();
195#ifdef STATIC
196 d_intern_setup();
197#endif
198 d_soundfile_setup();
199 d_ugen_setup();
200
201}
202
diff --git a/apps/plugins/pdbox/PDa/src/m_fixed.c b/apps/plugins/pdbox/PDa/src/m_fixed.c
new file mode 100644
index 0000000000..c91fa0512e
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_fixed.c
@@ -0,0 +1,252 @@
1
2#include <sys/socket.h>
3#include <netinet/in.h>
4#include <netinet/tcp.h>
5#include <netdb.h>
6#include <stdio.h>
7
8#include "m_pd.h"
9#include "m_imp.h"
10
11static t_class *ipod_class = 0;
12
13typedef struct _ipod
14{
15 t_object x_obj;
16 t_symbol* x_what;
17} t_ipod;
18
19static t_ipod* ipod;
20static t_int x_fd = -1;
21
22
23
24static void ipod_connect()
25{
26 struct sockaddr_in server;
27 struct hostent *hp;
28 int sockfd;
29 int portno = 3334;
30 char hostname[] = "127.0.0.1";
31 int intarg;
32 if (x_fd >= 0)
33 {
34 error("ipod_connect: already connected");
35 return;
36 }
37
38 /* create a socket */
39 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
40
41 if (sockfd < 0)
42 {
43 sys_sockerror("socket");
44 return;
45 }
46
47 /* connect socket using hostname provided in command line */
48
49 server.sin_family = AF_INET;
50 hp = gethostbyname(hostname);
51 if (hp == 0)
52 {
53 post("bad host?\n");
54 return;
55 }
56
57 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
58
59 server.sin_port = htons((u_short)portno);
60 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
61 {
62 sys_sockerror("connecting stream socket");
63 sys_closesocket(sockfd);
64 return;
65 }
66 post("connected %s %d",hostname,portno);
67 x_fd = sockfd;
68}
69
70
71
72static void ipod_bang(t_ipod *x)
73{
74 static char sendme[200];
75 sprintf(sendme,"%s bang;\n",x->x_what->s_name);
76 send(x_fd,sendme,strlen(sendme),0);
77
78// if (x->x_sym->s_thing) pd_bang(x->x_sym->s_thing);
79}
80
81static void ipod_float(t_ipod *x, t_float f)
82{
83 static char sendme[200];
84
85 sprintf(sendme,"%s %f;\n",x->x_what->s_name,f);
86 send(x_fd,sendme,strlen(sendme),0);
87
88// post("forwarding float %s",x->x_what->s_name);
89// if (x->x_sym->s_thing) pd_float(x->x_sym->s_thing, f);
90}
91
92static void *ipod_new(t_symbol* what)
93{
94 t_ipod *x = (t_ipod *)pd_new(ipod_class);
95 post("new ipod %s",what->s_name);
96 x->x_what = what;
97 return (x);
98}
99
100static void ipod_setup(void)
101{
102 ipod_class = class_new(gensym("ipod"), (t_newmethod)ipod_new, 0,
103 sizeof(t_ipod), 0, A_DEFSYM, 0);
104 class_addbang(ipod_class, ipod_bang);
105 class_addfloat(ipod_class, ipod_float);
106 ipod_connect();
107}
108
109void pd_checkgui(t_pd *x, t_symbol *s)
110{
111 if (!strncmp(s->s_name,"pod_",4))
112 if (!strcmp((*x)->c_name->s_name,"gatom") ||
113 !strcmp((*x)->c_name->s_name,"vsl") ||
114 !strcmp((*x)->c_name->s_name,"hsl") ||
115 !strcmp((*x)->c_name->s_name,"bng") ||
116 !strcmp((*x)->c_name->s_name,"vradio") ||
117 !strcmp((*x)->c_name->s_name,"hradio")) {
118
119 post("binding %s to %s",s->s_name,(*x)->c_name->s_name);
120 if (!ipod_class) ipod_setup();
121 ipod = ipod_new(s);
122 pd_bind(&ipod->x_obj.ob_pd,s);
123 }
124}
125
126
127
128#include <sys/socket.h>
129#include <netinet/in.h>
130#include <netinet/tcp.h>
131#include <netdb.h>
132#include <stdio.h>
133
134#include "m_pd.h"
135#include "m_imp.h"
136
137static t_class *ipod_class = 0;
138
139typedef struct _ipod
140{
141 t_object x_obj;
142 t_symbol* x_what;
143} t_ipod;
144
145static t_ipod* ipod;
146static t_int x_fd = -1;
147
148
149
150static void ipod_connect()
151{
152 struct sockaddr_in server;
153 struct hostent *hp;
154 int sockfd;
155 int portno = 3334;
156 char hostname[] = "127.0.0.1";
157 int intarg;
158 if (x_fd >= 0)
159 {
160 error("ipod_connect: already connected");
161 return;
162 }
163
164 /* create a socket */
165 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
166
167 if (sockfd < 0)
168 {
169 sys_sockerror("socket");
170 return;
171 }
172
173 /* connect socket using hostname provided in command line */
174
175 server.sin_family = AF_INET;
176 hp = gethostbyname(hostname);
177 if (hp == 0)
178 {
179 post("bad host?\n");
180 return;
181 }
182
183 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
184
185 server.sin_port = htons((u_short)portno);
186 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
187 {
188 sys_sockerror("connecting stream socket");
189 sys_closesocket(sockfd);
190 return;
191 }
192 post("connected %s %d",hostname,portno);
193 x_fd = sockfd;
194}
195
196
197
198static void ipod_bang(t_ipod *x)
199{
200 static char sendme[200];
201 sprintf(sendme,"%s bang;\n",x->x_what->s_name);
202 send(x_fd,sendme,strlen(sendme),0);
203
204// if (x->x_sym->s_thing) pd_bang(x->x_sym->s_thing);
205}
206
207static void ipod_float(t_ipod *x, t_float f)
208{
209 static char sendme[200];
210
211 sprintf(sendme,"%s %f;\n",x->x_what->s_name,f);
212 send(x_fd,sendme,strlen(sendme),0);
213
214// post("forwarding float %s",x->x_what->s_name);
215// if (x->x_sym->s_thing) pd_float(x->x_sym->s_thing, f);
216}
217
218static void *ipod_new(t_symbol* what)
219{
220 t_ipod *x = (t_ipod *)pd_new(ipod_class);
221 post("new ipod %s",what->s_name);
222 x->x_what = what;
223 return (x);
224}
225
226static void ipod_setup(void)
227{
228 ipod_class = class_new(gensym("ipod"), (t_newmethod)ipod_new, 0,
229 sizeof(t_ipod), 0, A_DEFSYM, 0);
230 class_addbang(ipod_class, ipod_bang);
231 class_addfloat(ipod_class, ipod_float);
232 ipod_connect();
233}
234
235void pd_checkgui(t_pd *x, t_symbol *s)
236{
237 if (!strncmp(s->s_name,"pod_",4))
238 if (!strcmp((*x)->c_name->s_name,"gatom") ||
239 !strcmp((*x)->c_name->s_name,"vsl") ||
240 !strcmp((*x)->c_name->s_name,"hsl") ||
241 !strcmp((*x)->c_name->s_name,"bng") ||
242 !strcmp((*x)->c_name->s_name,"vradio") ||
243 !strcmp((*x)->c_name->s_name,"hradio")) {
244
245 post("binding %s to %s",s->s_name,(*x)->c_name->s_name);
246 if (!ipod_class) ipod_setup();
247 ipod = ipod_new(s);
248 pd_bind(&ipod->x_obj.ob_pd,s);
249 }
250}
251
252
diff --git a/apps/plugins/pdbox/PDa/src/m_fixed.h b/apps/plugins/pdbox/PDa/src/m_fixed.h
new file mode 100644
index 0000000000..4ccc121ac1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_fixed.h
@@ -0,0 +1,110 @@
1#ifndef __M_FIXED_H__
2#define __M_FIXED_H__
3
4typedef int t_sample;
5
6#define t_fixed int
7#define fix1 18 /* (18) number of bits after comma */
8
9
10#define fixfac ((float)(1<<fix1)) /* float factor (for scaling ftofix ..) */
11
12
13/* fixed point multiplication and division */
14
15#define mult(a,b) (long long)(((long long) (a) * (long long) (b))>>fix1)
16#define idiv(a,b) ((((long long) (a) )<<fix1)/(long long) (b) )
17
18/* conversion macros */
19
20#define itofix(a) ((a) << fix1)
21#define ftofix(a) ((t_fixed)( (a) *(double)fixfac + 0.5))
22
23#define fixtof(a) ((double) (a) * 1./(fixfac-0.5))
24#define fixtoi(a) ((a) >>fix1)
25
26
27/* Not working !! */
28
29#define fnum(a) ( (a) >>(fix1-16))
30#define ffrac(a) (0)
31
32
33/* mapping of fft functions */
34
35#ifdef FIXEDPOINT
36#define mayer_realifft imayer_realifft
37#define mayer_realfft imayer_realfft
38#define mayer_fft imayer_fft
39#define mayer_ifft imayer_ifft
40#endif
41
42#ifdef FIXEDPOINT
43#define SCALE16(x) (x>>(fix1-15))
44#define SCALE32(x) (x<<(32-fix1))
45#define INVSCALE16(x) (x<<8)
46#else
47#define SCALE16(x) (32767.*x)
48#define SCALE32(x) (2147483648.*x)
49#define INVSCALE16(x) ((float)3.051850e-05*x)
50#endif
51
52
53#endif
54
55
56#ifndef __M_FIXED_H__
57#define __M_FIXED_H__
58
59typedef int t_sample;
60
61#define t_fixed int
62#define fix1 18 /* (18) number of bits after comma */
63
64
65#define fixfac ((float)(1<<fix1)) /* float factor (for scaling ftofix ..) */
66
67
68/* fixed point multiplication and division */
69
70#define mult(a,b) (long long)(((long long) (a) * (long long) (b))>>fix1)
71#define idiv(a,b) ((((long long) (a) )<<fix1)/(long long) (b) )
72
73/* conversion macros */
74
75#define itofix(a) ((a) << fix1)
76#define ftofix(a) ((t_fixed)( (a) *(double)fixfac + 0.5))
77
78#define fixtof(a) ((double) (a) * 1./(fixfac-0.5))
79#define fixtoi(a) ((a) >>fix1)
80
81
82/* Not working !! */
83
84#define fnum(a) ( (a) >>(fix1-16))
85#define ffrac(a) (0)
86
87
88/* mapping of fft functions */
89
90#ifdef FIXEDPOINT
91#define mayer_realifft imayer_realifft
92#define mayer_realfft imayer_realfft
93#define mayer_fft imayer_fft
94#define mayer_ifft imayer_ifft
95#endif
96
97#ifdef FIXEDPOINT
98#define SCALE16(x) (x>>(fix1-15))
99#define SCALE32(x) (x<<(32-fix1))
100#define INVSCALE16(x) (x<<8)
101#else
102#define SCALE16(x) (32767.*x)
103#define SCALE32(x) (2147483648.*x)
104#define INVSCALE16(x) ((float)3.051850e-05*x)
105#endif
106
107
108#endif
109
110
diff --git a/apps/plugins/pdbox/PDa/src/m_glob.c b/apps/plugins/pdbox/PDa/src/m_glob.c
new file mode 100644
index 0000000000..5d62087b3c
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_glob.c
@@ -0,0 +1,210 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include "m_pd.h"
6#include "m_imp.h"
7
8t_class *glob_pdobject;
9static t_class *maxclass;
10
11/* These "glob" routines, which implement messages to Pd, are from all
12over. Some others are prototyped in m_imp.h as well. */
13
14void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
15void glob_quit(void *dummy);
16void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv);
17void glob_meters(void *dummy, t_floatarg f);
18void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av);
19void glob_audiostatus(void *dummy);
20void glob_finderror(t_pd *dummy);
21void glob_audio_properties(t_pd *dummy, t_floatarg flongform);
22void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
23void glob_audio_setapi(t_pd *dummy, t_floatarg f);
24void glob_midi_properties(t_pd *dummy, t_floatarg flongform);
25void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
26void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform);
27void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
28void glob_ping(t_pd *dummy);
29
30void alsa_resync( void);
31
32
33#ifdef MSW
34void glob_audio(void *dummy, t_floatarg adc, t_floatarg dac);
35#endif
36
37/* a method you add for debugging printout */
38void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv);
39
40#if 0
41void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
42{
43 *(int *)1 = 3;
44}
45#endif
46
47void max_default(t_pd *x, t_symbol *s, int argc, t_atom *argv)
48{
49 int i;
50 char str[80];
51 startpost("%s: unknown message %s ", class_getname(pd_class(x)),
52 s->s_name);
53 for (i = 0; i < argc; i++)
54 {
55 atom_string(argv+i, str, 80);
56 poststring(str);
57 }
58 endpost();
59}
60
61void glob_init(void)
62{
63 maxclass = class_new(gensym("max"), 0, 0, sizeof(t_pd),
64 CLASS_DEFAULT, A_NULL);
65 class_addanything(maxclass, max_default);
66 pd_bind(&maxclass, gensym("max"));
67
68 glob_pdobject = class_new(gensym("pd"), 0, 0, sizeof(t_pd),
69 CLASS_DEFAULT, A_NULL);
70 class_addmethod(glob_pdobject, (t_method)glob_initfromgui, gensym("init"),
71 A_GIMME, 0);
72 class_addmethod(glob_pdobject, (t_method)glob_setfilename, gensym("filename"),
73 A_SYMBOL, A_SYMBOL, 0);
74 class_addmethod(glob_pdobject, (t_method)glob_evalfile, gensym("open"),
75 A_SYMBOL, A_SYMBOL, 0);
76 class_addmethod(glob_pdobject, (t_method)glob_quit, gensym("quit"), 0);
77 class_addmethod(glob_pdobject, (t_method)glob_foo, gensym("foo"), A_GIMME, 0);
78 class_addmethod(glob_pdobject, (t_method)glob_dsp, gensym("dsp"), A_GIMME, 0);
79 class_addmethod(glob_pdobject, (t_method)glob_meters, gensym("meters"),
80 A_FLOAT, 0);
81 class_addmethod(glob_pdobject, (t_method)glob_key, gensym("key"), A_GIMME, 0);
82 class_addmethod(glob_pdobject, (t_method)glob_audiostatus,
83 gensym("audiostatus"), 0);
84 class_addmethod(glob_pdobject, (t_method)glob_finderror,
85 gensym("finderror"), 0);
86 class_addmethod(glob_pdobject, (t_method)glob_audio_properties,
87 gensym("audio-properties"), A_DEFFLOAT, 0);
88 class_addmethod(glob_pdobject, (t_method)glob_audio_dialog,
89 gensym("audio-dialog"), A_GIMME, 0);
90 class_addmethod(glob_pdobject, (t_method)glob_audio_setapi,
91 gensym("audio-setapi"), A_FLOAT, 0);
92 class_addmethod(glob_pdobject, (t_method)glob_midi_properties,
93 gensym("midi-properties"), A_DEFFLOAT, 0);
94 class_addmethod(glob_pdobject, (t_method)glob_midi_dialog,
95 gensym("midi-dialog"), A_GIMME, 0);
96 class_addmethod(glob_pdobject, (t_method)glob_start_path_dialog,
97 gensym("start-path-dialog"), A_DEFFLOAT, 0);
98 class_addmethod(glob_pdobject, (t_method)glob_path_dialog,
99 gensym("path-dialog"), A_GIMME, 0);
100#ifdef __linux__
101 class_addmethod(glob_pdobject, (t_method)glob_ping, gensym("ping"), 0);
102#endif
103 class_addanything(glob_pdobject, max_default);
104 pd_bind(&glob_pdobject, gensym("pd"));
105}
106/* Copyright (c) 1997-1999 Miller Puckette.
107* For information on usage and redistribution, and for a DISCLAIMER OF ALL
108* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
109
110#include "m_pd.h"
111#include "m_imp.h"
112
113t_class *glob_pdobject;
114static t_class *maxclass;
115
116/* These "glob" routines, which implement messages to Pd, are from all
117over. Some others are prototyped in m_imp.h as well. */
118
119void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
120void glob_quit(void *dummy);
121void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv);
122void glob_meters(void *dummy, t_floatarg f);
123void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av);
124void glob_audiostatus(void *dummy);
125void glob_finderror(t_pd *dummy);
126void glob_audio_properties(t_pd *dummy, t_floatarg flongform);
127void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
128void glob_audio_setapi(t_pd *dummy, t_floatarg f);
129void glob_midi_properties(t_pd *dummy, t_floatarg flongform);
130void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
131void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform);
132void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
133void glob_ping(t_pd *dummy);
134
135void alsa_resync( void);
136
137
138#ifdef MSW
139void glob_audio(void *dummy, t_floatarg adc, t_floatarg dac);
140#endif
141
142/* a method you add for debugging printout */
143void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv);
144
145#if 0
146void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
147{
148 *(int *)1 = 3;
149}
150#endif
151
152void max_default(t_pd *x, t_symbol *s, int argc, t_atom *argv)
153{
154 int i;
155 char str[80];
156 startpost("%s: unknown message %s ", class_getname(pd_class(x)),
157 s->s_name);
158 for (i = 0; i < argc; i++)
159 {
160 atom_string(argv+i, str, 80);
161 poststring(str);
162 }
163 endpost();
164}
165
166void glob_init(void)
167{
168 maxclass = class_new(gensym("max"), 0, 0, sizeof(t_pd),
169 CLASS_DEFAULT, A_NULL);
170 class_addanything(maxclass, max_default);
171 pd_bind(&maxclass, gensym("max"));
172
173 glob_pdobject = class_new(gensym("pd"), 0, 0, sizeof(t_pd),
174 CLASS_DEFAULT, A_NULL);
175 class_addmethod(glob_pdobject, (t_method)glob_initfromgui, gensym("init"),
176 A_GIMME, 0);
177 class_addmethod(glob_pdobject, (t_method)glob_setfilename, gensym("filename"),
178 A_SYMBOL, A_SYMBOL, 0);
179 class_addmethod(glob_pdobject, (t_method)glob_evalfile, gensym("open"),
180 A_SYMBOL, A_SYMBOL, 0);
181 class_addmethod(glob_pdobject, (t_method)glob_quit, gensym("quit"), 0);
182 class_addmethod(glob_pdobject, (t_method)glob_foo, gensym("foo"), A_GIMME, 0);
183 class_addmethod(glob_pdobject, (t_method)glob_dsp, gensym("dsp"), A_GIMME, 0);
184 class_addmethod(glob_pdobject, (t_method)glob_meters, gensym("meters"),
185 A_FLOAT, 0);
186 class_addmethod(glob_pdobject, (t_method)glob_key, gensym("key"), A_GIMME, 0);
187 class_addmethod(glob_pdobject, (t_method)glob_audiostatus,
188 gensym("audiostatus"), 0);
189 class_addmethod(glob_pdobject, (t_method)glob_finderror,
190 gensym("finderror"), 0);
191 class_addmethod(glob_pdobject, (t_method)glob_audio_properties,
192 gensym("audio-properties"), A_DEFFLOAT, 0);
193 class_addmethod(glob_pdobject, (t_method)glob_audio_dialog,
194 gensym("audio-dialog"), A_GIMME, 0);
195 class_addmethod(glob_pdobject, (t_method)glob_audio_setapi,
196 gensym("audio-setapi"), A_FLOAT, 0);
197 class_addmethod(glob_pdobject, (t_method)glob_midi_properties,
198 gensym("midi-properties"), A_DEFFLOAT, 0);
199 class_addmethod(glob_pdobject, (t_method)glob_midi_dialog,
200 gensym("midi-dialog"), A_GIMME, 0);
201 class_addmethod(glob_pdobject, (t_method)glob_start_path_dialog,
202 gensym("start-path-dialog"), A_DEFFLOAT, 0);
203 class_addmethod(glob_pdobject, (t_method)glob_path_dialog,
204 gensym("path-dialog"), A_GIMME, 0);
205#ifdef __linux__
206 class_addmethod(glob_pdobject, (t_method)glob_ping, gensym("ping"), 0);
207#endif
208 class_addanything(glob_pdobject, max_default);
209 pd_bind(&glob_pdobject, gensym("pd"));
210}
diff --git a/apps/plugins/pdbox/PDa/src/m_imp.h b/apps/plugins/pdbox/PDa/src/m_imp.h
new file mode 100644
index 0000000000..7632af1c2d
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_imp.h
@@ -0,0 +1,156 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* This file contains function prototypes and data types used to implement
6Pd, but not shared with Pd objects. */
7
8/* NOTE: this file describes Pd implementation details which may change
9in future releases. The public (stable) API is in m_pd.h. */
10
11/* LATER consider whether to use 'char' for method arg types to save space */
12
13/* the structure for a method handler ala Max */
14typedef struct _methodentry
15{
16 t_symbol *me_name;
17 t_gotfn me_fun;
18 t_atomtype me_arg[MAXPDARG+1];
19} t_methodentry;
20
21EXTERN_STRUCT _widgetbehavior;
22
23typedef void (*t_bangmethod)(t_pd *x);
24typedef void (*t_pointermethod)(t_pd *x, t_gpointer *gp);
25typedef void (*t_floatmethod)(t_pd *x, t_float f);
26typedef void (*t_symbolmethod)(t_pd *x, t_symbol *s);
27typedef void (*t_listmethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
28typedef void (*t_anymethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
29
30struct _class
31{
32 t_symbol *c_name; /* name (mostly for error reporting) */
33 t_symbol *c_helpname; /* name of help file */
34 t_symbol *c_externdir; /* directory extern was loaded from */
35 size_t c_size; /* size of an instance */
36 t_methodentry *c_methods; /* methods other than bang, etc below */
37 int c_nmethod; /* number of methods */
38 t_method c_freemethod; /* function to call before freeing */
39 t_bangmethod c_bangmethod; /* common methods */
40 t_pointermethod c_pointermethod;
41 t_floatmethod c_floatmethod;
42 t_symbolmethod c_symbolmethod;
43 t_listmethod c_listmethod;
44 t_anymethod c_anymethod;
45 struct _widgetbehavior *c_wb; /* "gobjs" only */
46 struct _parentwidgetbehavior *c_pwb;/* widget behavior in parent */
47 t_savefn c_savefn; /* function to call when saving */
48 t_propertiesfn c_propertiesfn; /* function to start prop dialog */
49 int c_floatsignalin; /* onset to float for signal input */
50 char c_gobj; /* true if is a gobj */
51 char c_patchable; /* true if we have a t_object header */
52 char c_firstin; /* if patchable, true if draw first inlet */
53 char c_drawcommand; /* a drawing command for a template */
54};
55
56
57/* m_obj.c */
58EXTERN int obj_noutlets(t_object *x);
59EXTERN int obj_ninlets(t_object *x);
60EXTERN t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op,
61 int nout);
62EXTERN t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
63 t_object **destp, t_inlet **inletp, int *whichp);
64EXTERN t_outconnect *obj_connect(t_object *source, int outno,
65 t_object *sink, int inno);
66EXTERN void obj_disconnect(t_object *source, int outno, t_object *sink,
67 int inno);
68EXTERN void outlet_setstacklim(void);
69EXTERN int obj_issignalinlet(t_object *x, int m);
70EXTERN int obj_issignaloutlet(t_object *x, int m);
71EXTERN int obj_nsiginlets(t_object *x);
72EXTERN int obj_nsigoutlets(t_object *x);
73EXTERN int obj_siginletindex(t_object *x, int m);
74EXTERN int obj_sigoutletindex(t_object *x, int m);
75
76/* misc */
77EXTERN void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir);
78EXTERN void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv);
79/* Copyright (c) 1997-1999 Miller Puckette.
80* For information on usage and redistribution, and for a DISCLAIMER OF ALL
81* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
82
83/* This file contains function prototypes and data types used to implement
84Pd, but not shared with Pd objects. */
85
86/* NOTE: this file describes Pd implementation details which may change
87in future releases. The public (stable) API is in m_pd.h. */
88
89/* LATER consider whether to use 'char' for method arg types to save space */
90
91/* the structure for a method handler ala Max */
92typedef struct _methodentry
93{
94 t_symbol *me_name;
95 t_gotfn me_fun;
96 t_atomtype me_arg[MAXPDARG+1];
97} t_methodentry;
98
99EXTERN_STRUCT _widgetbehavior;
100
101typedef void (*t_bangmethod)(t_pd *x);
102typedef void (*t_pointermethod)(t_pd *x, t_gpointer *gp);
103typedef void (*t_floatmethod)(t_pd *x, t_float f);
104typedef void (*t_symbolmethod)(t_pd *x, t_symbol *s);
105typedef void (*t_listmethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
106typedef void (*t_anymethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
107
108struct _class
109{
110 t_symbol *c_name; /* name (mostly for error reporting) */
111 t_symbol *c_helpname; /* name of help file */
112 t_symbol *c_externdir; /* directory extern was loaded from */
113 size_t c_size; /* size of an instance */
114 t_methodentry *c_methods; /* methods other than bang, etc below */
115 int c_nmethod; /* number of methods */
116 t_method c_freemethod; /* function to call before freeing */
117 t_bangmethod c_bangmethod; /* common methods */
118 t_pointermethod c_pointermethod;
119 t_floatmethod c_floatmethod;
120 t_symbolmethod c_symbolmethod;
121 t_listmethod c_listmethod;
122 t_anymethod c_anymethod;
123 struct _widgetbehavior *c_wb; /* "gobjs" only */
124 struct _parentwidgetbehavior *c_pwb;/* widget behavior in parent */
125 t_savefn c_savefn; /* function to call when saving */
126 t_propertiesfn c_propertiesfn; /* function to start prop dialog */
127 int c_floatsignalin; /* onset to float for signal input */
128 char c_gobj; /* true if is a gobj */
129 char c_patchable; /* true if we have a t_object header */
130 char c_firstin; /* if patchable, true if draw first inlet */
131 char c_drawcommand; /* a drawing command for a template */
132};
133
134
135/* m_obj.c */
136EXTERN int obj_noutlets(t_object *x);
137EXTERN int obj_ninlets(t_object *x);
138EXTERN t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op,
139 int nout);
140EXTERN t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
141 t_object **destp, t_inlet **inletp, int *whichp);
142EXTERN t_outconnect *obj_connect(t_object *source, int outno,
143 t_object *sink, int inno);
144EXTERN void obj_disconnect(t_object *source, int outno, t_object *sink,
145 int inno);
146EXTERN void outlet_setstacklim(void);
147EXTERN int obj_issignalinlet(t_object *x, int m);
148EXTERN int obj_issignaloutlet(t_object *x, int m);
149EXTERN int obj_nsiginlets(t_object *x);
150EXTERN int obj_nsigoutlets(t_object *x);
151EXTERN int obj_siginletindex(t_object *x, int m);
152EXTERN int obj_sigoutletindex(t_object *x, int m);
153
154/* misc */
155EXTERN void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir);
156EXTERN void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv);
diff --git a/apps/plugins/pdbox/PDa/src/m_memory.c b/apps/plugins/pdbox/PDa/src/m_memory.c
new file mode 100644
index 0000000000..085154299b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_memory.c
@@ -0,0 +1,178 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include <stdlib.h>
6#include <string.h>
7#include "m_pd.h"
8#include "m_imp.h"
9
10/* #define LOUD */
11#ifdef LOUD
12#include <stdio.h>
13#endif
14
15/* #define DEBUGMEM */
16#ifdef DEBUGMEM
17static int totalmem = 0;
18#endif
19
20void *getbytes(size_t nbytes)
21{
22 void *ret;
23 if (nbytes < 1) nbytes = 1;
24 ret = (void *)calloc(nbytes, 1);
25#ifdef LOUD
26 fprintf(stderr, "new %x %d\n", (int)ret, nbytes);
27#endif /* LOUD */
28#ifdef DEBUGMEM
29 totalmem += nbytes;
30#endif
31 if (!ret)
32 post("pd: getbytes() failed -- out of memory");
33 return (ret);
34}
35
36void *getzbytes(size_t nbytes) /* obsolete name */
37{
38 return (getbytes(nbytes));
39}
40
41void *copybytes(void *src, size_t nbytes)
42{
43 void *ret;
44 ret = getbytes(nbytes);
45 if (nbytes)
46 memcpy(ret, src, nbytes);
47 return (ret);
48}
49
50void *resizebytes(void *old, size_t oldsize, size_t newsize)
51{
52 void *ret;
53 if (newsize < 1) newsize = 1;
54 if (oldsize < 1) oldsize = 1;
55 ret = (void *)realloc((char *)old, newsize);
56 if (newsize > oldsize && ret)
57 memset(((char *)ret) + oldsize, 0, newsize - oldsize);
58#ifdef LOUD
59 fprintf(stderr, "resize %x %d --> %x %d\n", (int)old, oldsize, (int)ret, newsize);
60#endif /* LOUD */
61#ifdef DEBUGMEM
62 totalmem += (newsize - oldsize);
63#endif
64 if (!ret)
65 post("pd: resizebytes() failed -- out of memory");
66 return (ret);
67}
68
69void freebytes(void *fatso, size_t nbytes)
70{
71 if (nbytes == 0)
72 nbytes = 1;
73#ifdef LOUD
74 fprintf(stderr, "free %x %d\n", (int)fatso, nbytes);
75#endif /* LOUD */
76#ifdef DEBUGMEM
77 totalmem -= nbytes;
78#endif
79 free(fatso);
80}
81
82#ifdef DEBUGMEM
83#include <stdio.h>
84
85void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
86{
87 fprintf(stderr, "total mem %d\n", totalmem);
88}
89#endif
90/* Copyright (c) 1997-1999 Miller Puckette.
91* For information on usage and redistribution, and for a DISCLAIMER OF ALL
92* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
93
94#include <stdlib.h>
95#include <string.h>
96#include "m_pd.h"
97#include "m_imp.h"
98
99/* #define LOUD */
100#ifdef LOUD
101#include <stdio.h>
102#endif
103
104/* #define DEBUGMEM */
105#ifdef DEBUGMEM
106static int totalmem = 0;
107#endif
108
109void *getbytes(size_t nbytes)
110{
111 void *ret;
112 if (nbytes < 1) nbytes = 1;
113 ret = (void *)calloc(nbytes, 1);
114#ifdef LOUD
115 fprintf(stderr, "new %x %d\n", (int)ret, nbytes);
116#endif /* LOUD */
117#ifdef DEBUGMEM
118 totalmem += nbytes;
119#endif
120 if (!ret)
121 post("pd: getbytes() failed -- out of memory");
122 return (ret);
123}
124
125void *getzbytes(size_t nbytes) /* obsolete name */
126{
127 return (getbytes(nbytes));
128}
129
130void *copybytes(void *src, size_t nbytes)
131{
132 void *ret;
133 ret = getbytes(nbytes);
134 if (nbytes)
135 memcpy(ret, src, nbytes);
136 return (ret);
137}
138
139void *resizebytes(void *old, size_t oldsize, size_t newsize)
140{
141 void *ret;
142 if (newsize < 1) newsize = 1;
143 if (oldsize < 1) oldsize = 1;
144 ret = (void *)realloc((char *)old, newsize);
145 if (newsize > oldsize && ret)
146 memset(((char *)ret) + oldsize, 0, newsize - oldsize);
147#ifdef LOUD
148 fprintf(stderr, "resize %x %d --> %x %d\n", (int)old, oldsize, (int)ret, newsize);
149#endif /* LOUD */
150#ifdef DEBUGMEM
151 totalmem += (newsize - oldsize);
152#endif
153 if (!ret)
154 post("pd: resizebytes() failed -- out of memory");
155 return (ret);
156}
157
158void freebytes(void *fatso, size_t nbytes)
159{
160 if (nbytes == 0)
161 nbytes = 1;
162#ifdef LOUD
163 fprintf(stderr, "free %x %d\n", (int)fatso, nbytes);
164#endif /* LOUD */
165#ifdef DEBUGMEM
166 totalmem -= nbytes;
167#endif
168 free(fatso);
169}
170
171#ifdef DEBUGMEM
172#include <stdio.h>
173
174void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
175{
176 fprintf(stderr, "total mem %d\n", totalmem);
177}
178#endif
diff --git a/apps/plugins/pdbox/PDa/src/m_obj.c b/apps/plugins/pdbox/PDa/src/m_obj.c
new file mode 100644
index 0000000000..d53da5722e
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_obj.c
@@ -0,0 +1,1394 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* this file handles Max-style patchable objects, i.e., objects which
6can interconnect via inlets and outlets; also, the (terse) generic
7behavior for "gobjs" appears at the end of this file. */
8
9#include "m_pd.h"
10#include "m_imp.h"
11
12union inletunion
13{
14 t_symbol *iu_symto;
15 t_gpointer *iu_pointerslot;
16 t_float *iu_floatslot;
17 t_symbol **iu_symslot;
18 t_sample iu_floatsignalvalue;
19};
20
21struct _inlet
22{
23 t_pd i_pd;
24 struct _inlet *i_next;
25 t_object *i_owner;
26 t_pd *i_dest;
27 t_symbol *i_symfrom;
28 union inletunion i_un;
29};
30
31#define i_symto i_un.iu_symto
32#define i_pointerslot i_un.iu_pointerslot
33#define i_floatslot i_un.iu_floatslot
34#define i_symslot i_un.iu_symslot
35
36static t_class *inlet_class, *pointerinlet_class, *floatinlet_class,
37 *symbolinlet_class;
38
39#define ISINLET(pd) ((*(pd) == inlet_class) || \
40 (*(pd) == pointerinlet_class) || \
41 (*(pd) == floatinlet_class) || \
42 (*(pd) == symbolinlet_class))
43
44/* --------------------- generic inlets ala max ------------------ */
45
46t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2)
47{
48 t_inlet *x = (t_inlet *)pd_new(inlet_class), *y, *y2;
49 x->i_owner = owner;
50 x->i_dest = dest;
51 if (s1 == &s_signal)
52 x->i_un.iu_floatsignalvalue = 0;
53 else x->i_symto = s2;
54 x->i_symfrom = s1;
55 x->i_next = 0;
56 if (y = owner->ob_inlet)
57 {
58 while (y2 = y->i_next) y = y2;
59 y->i_next = x;
60 }
61 else owner->ob_inlet = x;
62 return (x);
63}
64
65static void inlet_wrong(t_inlet *x, t_symbol *s)
66{
67 pd_error(x->i_owner, "inlet: expected '%s' but got '%s'",
68 x->i_symfrom->s_name, s->s_name);
69}
70
71 /* LATER figure out how to make these efficient: */
72static void inlet_bang(t_inlet *x)
73{
74 if (x->i_symfrom == &s_bang)
75 pd_vmess(x->i_dest, x->i_symto, "");
76 else if (!x->i_symfrom) pd_bang(x->i_dest);
77 else inlet_wrong(x, &s_bang);
78}
79
80static void inlet_pointer(t_inlet *x, t_gpointer *gp)
81{
82 if (x->i_symfrom == &s_pointer)
83 pd_vmess(x->i_dest, x->i_symto, "p", gp);
84 else if (!x->i_symfrom) pd_pointer(x->i_dest, gp);
85 else inlet_wrong(x, &s_pointer);
86}
87
88static void inlet_float(t_inlet *x, t_float f)
89{
90 if (x->i_symfrom == &s_float)
91 pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
92 else if (x->i_symfrom == &s_signal)
93 x->i_un.iu_floatsignalvalue = ftofix(f);
94 else if (!x->i_symfrom)
95 pd_float(x->i_dest, f);
96 else inlet_wrong(x, &s_float);
97}
98
99static void inlet_symbol(t_inlet *x, t_symbol *s)
100{
101 if (x->i_symfrom == &s_symbol)
102 pd_vmess(x->i_dest, x->i_symto, "s", s);
103 else if (!x->i_symfrom) pd_symbol(x->i_dest, s);
104 else inlet_wrong(x, &s_symbol);
105}
106
107static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
108{
109 t_atom at;
110 if (x->i_symfrom == &s_list || x->i_symfrom == &s_float
111 || x->i_symfrom == &s_symbol || x->i_symfrom == &s_pointer)
112 typedmess(x->i_dest, x->i_symto, argc, argv);
113 else if (!x->i_symfrom) pd_list(x->i_dest, s, argc, argv);
114 else inlet_wrong(x, &s_list);
115}
116
117static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
118{
119 if (x->i_symfrom == s)
120 typedmess(x->i_dest, x->i_symto, argc, argv);
121 else if (!x->i_symfrom)
122 typedmess(x->i_dest, s, argc, argv);
123 else inlet_wrong(x, s);
124}
125
126void inlet_free(t_inlet *x)
127{
128 t_object *y = x->i_owner;
129 t_inlet *x2;
130 if (y->ob_inlet == x) y->ob_inlet = x->i_next;
131 else for (x2 = y->ob_inlet; x2; x2 = x2->i_next)
132 if (x2->i_next == x)
133 {
134 x2->i_next = x->i_next;
135 break;
136 }
137 t_freebytes(x, sizeof(*x));
138}
139
140/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
141
142static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp)
143{
144 gpointer_unset(x->i_pointerslot);
145 *(x->i_pointerslot) = *gp;
146 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
147}
148
149t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp)
150{
151 t_inlet *x = (t_inlet *)pd_new(pointerinlet_class), *y, *y2;
152 x->i_owner = owner;
153 x->i_dest = 0;
154 x->i_symfrom = &s_pointer;
155 x->i_pointerslot = gp;
156 x->i_next = 0;
157 if (y = owner->ob_inlet)
158 {
159 while (y2 = y->i_next) y = y2;
160 y->i_next = x;
161 }
162 else owner->ob_inlet = x;
163 return (x);
164}
165
166static void floatinlet_float(t_inlet *x, t_float f)
167{
168 *(x->i_floatslot) = f;
169}
170
171t_inlet *floatinlet_new(t_object *owner, t_float *fp)
172{
173 t_inlet *x = (t_inlet *)pd_new(floatinlet_class), *y, *y2;
174 x->i_owner = owner;
175 x->i_dest = 0;
176 x->i_symfrom = &s_float;
177 x->i_floatslot = fp;
178 x->i_next = 0;
179 if (y = owner->ob_inlet)
180 {
181 while (y2 = y->i_next) y = y2;
182 y->i_next = x;
183 }
184 else owner->ob_inlet = x;
185 return (x);
186}
187
188static void symbolinlet_symbol(t_inlet *x, t_symbol *s)
189{
190 *(x->i_symslot) = s;
191}
192
193t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp)
194{
195 t_inlet *x = (t_inlet *)pd_new(symbolinlet_class), *y, *y2;
196 x->i_owner = owner;
197 x->i_dest = 0;
198 x->i_symfrom = &s_symbol;
199 x->i_symslot = sp;
200 x->i_next = 0;
201 if (y = owner->ob_inlet)
202 {
203 while (y2 = y->i_next) y = y2;
204 y->i_next = x;
205 }
206 else owner->ob_inlet = x;
207 return (x);
208}
209
210/* ---------------------- routine to handle lists ---------------------- */
211
212 /* objects interpret lists by feeding them to the individual inlets.
213 Before you call this check that the object doesn't have a more
214 specific way to handle lists. */
215void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv)
216{
217 t_atom *ap;
218 int count;
219 t_inlet *ip = ((t_object *)x)->ob_inlet;
220 if (!argc) return;
221 for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->i_next)
222 {
223 if (ap->a_type == A_POINTER) pd_pointer(&ip->i_pd, ap->a_w.w_gpointer);
224 else if (ap->a_type == A_FLOAT) pd_float(&ip->i_pd, ap->a_w.w_float);
225 else pd_symbol(&ip->i_pd, ap->a_w.w_symbol);
226 }
227 if (argv->a_type == A_POINTER) pd_pointer(&x->ob_pd, argv->a_w.w_gpointer);
228 else if (argv->a_type == A_FLOAT) pd_float(&x->ob_pd, argv->a_w.w_float);
229 else pd_symbol(&x->ob_pd, argv->a_w.w_symbol);
230}
231
232void obj_init(void)
233{
234 inlet_class = class_new(gensym("inlet"), 0, 0,
235 sizeof(t_inlet), CLASS_PD, 0);
236 class_addbang(inlet_class, inlet_bang);
237 class_addpointer(inlet_class, inlet_pointer);
238 class_addfloat(inlet_class, inlet_float);
239 class_addsymbol(inlet_class, inlet_symbol);
240 class_addlist(inlet_class, inlet_list);
241 class_addanything(inlet_class, inlet_anything);
242
243 pointerinlet_class = class_new(gensym("inlet"), 0, 0,
244 sizeof(t_inlet), CLASS_PD, 0);
245 class_addpointer(pointerinlet_class, pointerinlet_pointer);
246
247 floatinlet_class = class_new(gensym("inlet"), 0, 0,
248 sizeof(t_inlet), CLASS_PD, 0);
249 class_addfloat(floatinlet_class, (t_method)floatinlet_float);
250
251 symbolinlet_class = class_new(gensym("inlet"), 0, 0,
252 sizeof(t_inlet), CLASS_PD, 0);
253 class_addsymbol(symbolinlet_class, symbolinlet_symbol);
254
255}
256
257/* --------------------------- outlets ------------------------------ */
258
259static char *stacklimit, *topstack;
260#define STACKSIZE 1000000
261static int outlet_eventno;
262
263 /* set a stack limit (on each incoming event that can set off messages)
264 for the outlet functions to check to prevent stack overflow from message
265 recursion */
266void outlet_setstacklim(void)
267{
268 char c;
269 topstack = &c;
270 stacklimit = (&c) - STACKSIZE;
271 outlet_eventno++;
272}
273
274 /* get a number unique to the (clock, MIDI, GUI, etc.) event we're on */
275int sched_geteventno( void)
276{
277 return (outlet_eventno);
278}
279
280struct _outconnect
281{
282 struct _outconnect *oc_next;
283 t_pd *oc_to;
284};
285
286struct _outlet
287{
288 t_object *o_owner;
289 struct _outlet *o_next;
290 t_outconnect *o_connections;
291 t_symbol *o_sym;
292};
293
294t_outlet *outlet_new(t_object *owner, t_symbol *s)
295{
296 t_outlet *x = (t_outlet *)getbytes(sizeof(*x)), *y, *y2;
297 x->o_owner = owner;
298 x->o_next = 0;
299 if (y = owner->ob_outlet)
300 {
301 while (y2 = y->o_next) y = y2;
302 y->o_next = x;
303 }
304 else owner->ob_outlet = x;
305 x->o_connections = 0;
306 x->o_sym = s;
307 return (x);
308}
309
310static void outlet_stackerror(t_outlet *x)
311{
312 pd_error(x->o_owner, "stack overflow");
313 stacklimit = topstack;
314}
315
316void outlet_bang(t_outlet *x)
317{
318 t_outconnect *oc;
319 char c;
320 if (&c < stacklimit)
321 outlet_stackerror(x);
322 else for (oc = x->o_connections; oc; oc = oc->oc_next)
323 pd_bang(oc->oc_to);
324}
325
326void outlet_pointer(t_outlet *x, t_gpointer *gp)
327{
328 t_outconnect *oc;
329 t_gpointer gpointer;
330 char c;
331 if (&c < stacklimit)
332 outlet_stackerror(x);
333 else
334 {
335#if 0
336 gpointer_copy(gp, &gpointer);
337 for (oc = x->o_connections; oc; oc = oc->oc_next)
338 pd_pointer(oc->oc_to, &gpointer);
339 gpointer_unset(&gpointer);
340#else
341 gpointer = *gp;
342 for (oc = x->o_connections; oc; oc = oc->oc_next)
343 pd_pointer(oc->oc_to, &gpointer);
344#endif
345 }
346}
347
348void outlet_float(t_outlet *x, t_float f)
349{
350 t_outconnect *oc;
351 char c;
352 if (&c < stacklimit)
353 outlet_stackerror(x);
354 else for (oc = x->o_connections; oc; oc = oc->oc_next)
355 pd_float(oc->oc_to, f);
356}
357
358void outlet_symbol(t_outlet *x, t_symbol *s)
359{
360 t_outconnect *oc;
361 char c;
362 if (&c < stacklimit)
363 outlet_stackerror(x);
364 else for (oc = x->o_connections; oc; oc = oc->oc_next)
365 pd_symbol(oc->oc_to, s);
366}
367
368void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
369{
370 t_outconnect *oc;
371 char c;
372 if (&c < stacklimit)
373 outlet_stackerror(x);
374 else for (oc = x->o_connections; oc; oc = oc->oc_next)
375 pd_list(oc->oc_to, s, argc, argv);
376}
377
378void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
379{
380 t_outconnect *oc;
381 char c;
382 if (&c < stacklimit)
383 outlet_stackerror(x);
384 else for (oc = x->o_connections; oc; oc = oc->oc_next)
385 typedmess(oc->oc_to, s, argc, argv);
386}
387
388 /* get the outlet's declared symbol */
389t_symbol *outlet_getsymbol(t_outlet *x)
390{
391 return (x->o_sym);
392}
393
394void outlet_free(t_outlet *x)
395{
396 t_object *y = x->o_owner;
397 t_outlet *x2;
398 if (y->ob_outlet == x) y->ob_outlet = x->o_next;
399 else for (x2 = y->ob_outlet; x2; x2 = x2->o_next)
400 if (x2->o_next == x)
401 {
402 x2->o_next = x->o_next;
403 break;
404 }
405 t_freebytes(x, sizeof(*x));
406}
407
408t_outconnect *obj_connect(t_object *source, int outno,
409 t_object *sink, int inno)
410{
411 t_inlet *i;
412 t_outlet *o;
413 t_pd *to;
414 t_outconnect *oc, *oc2;
415
416 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ;
417 if (!o) return (0);
418
419 if (sink->ob_pd->c_firstin)
420 {
421 if (!inno)
422 {
423 to = &sink->ob_pd;
424 goto doit;
425 }
426 else inno--;
427 }
428 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
429 if (!i) return (0);
430 to = &i->i_pd;
431doit:
432 oc = (t_outconnect *)t_getbytes(sizeof(*oc));
433 oc->oc_next = 0;
434 oc->oc_to = to;
435 /* append it to the end of the list */
436 /* LATER we might cache the last "oc" to make this faster. */
437 if ((oc2 = o->o_connections))
438 {
439 while (oc2->oc_next) oc2 = oc2->oc_next;
440 oc2->oc_next = oc;
441 }
442 else o->o_connections = oc;
443 if (o->o_sym == &s_signal) canvas_update_dsp();
444
445 return (oc);
446}
447
448void obj_disconnect(t_object *source, int outno, t_object *sink, int inno)
449{
450 t_inlet *i;
451 t_outlet *o;
452 t_pd *to;
453 t_outconnect *oc, *oc2;
454
455 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--)
456 if (!o) return;
457 if (sink->ob_pd->c_firstin)
458 {
459 if (!inno)
460 {
461 to = &sink->ob_pd;
462 goto doit;
463 }
464 else inno--;
465 }
466 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
467 if (!i) return;
468 to = &i->i_pd;
469doit:
470 if (!(oc = o->o_connections)) return;
471 if (oc->oc_to == to)
472 {
473 o->o_connections = oc->oc_next;
474 freebytes(oc, sizeof(*oc));
475 goto done;
476 }
477 while (oc2 = oc->oc_next)
478 {
479 if (oc2->oc_to == to)
480 {
481 oc->oc_next = oc2->oc_next;
482 freebytes(oc2, sizeof(*oc2));
483 goto done;
484 }
485 oc = oc2;
486 }
487done:
488 if (o->o_sym == &s_signal) canvas_update_dsp();
489}
490
491/* ------ traversal routines for code that can't see our structures ------ */
492
493int obj_noutlets(t_object *x)
494{
495 int n;
496 t_outlet *o;
497 for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++;
498 return (n);
499}
500
501int obj_ninlets(t_object *x)
502{
503 int n;
504 t_inlet *i;
505 for (i = x->ob_inlet, n = 0; i; i = i->i_next) n++;
506 if (x->ob_pd->c_firstin) n++;
507 return (n);
508}
509
510t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout)
511{
512 t_outlet *o = x->ob_outlet;
513 while (nout-- && o) o = o->o_next;
514 *op = o;
515 if (o) return (o->o_connections);
516 else return (0);
517}
518
519t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
520 t_object **destp, t_inlet **inletp, int *whichp)
521{
522 t_pd *y;
523 y = lastconnect->oc_to;
524 if (ISINLET(y))
525 {
526 int n;
527 t_inlet *i = (t_inlet *)y, *i2;
528 t_object *dest = i->i_owner;
529 for (n = dest->ob_pd->c_firstin, i2 = dest->ob_inlet;
530 i2 && i2 != i; i2 = i2->i_next) n++;
531 *whichp = n;
532 *destp = dest;
533 *inletp = i;
534 }
535 else
536 {
537 *whichp = 0;
538 *inletp = 0;
539 *destp = ((t_object *)y);
540 }
541 return (lastconnect->oc_next);
542}
543
544 /* this one checks that a pd is indeed a patchable object, and returns
545 it, correctly typed, or zero if the check failed. */
546t_object *pd_checkobject(t_pd *x)
547{
548 if ((*x)->c_patchable) return ((t_object *)x);
549 else return (0);
550}
551
552 /* move an inlet or outlet to the head of the list */
553void obj_moveinletfirst(t_object *x, t_inlet *i)
554{
555 t_inlet *i2;
556 if (x->ob_inlet == i) return;
557 else for (i2 = x->ob_inlet; i2; i2 = i2->i_next)
558 if (i2->i_next == i)
559 {
560 i2->i_next = i->i_next;
561 i->i_next = x->ob_inlet;
562 x->ob_inlet = i;
563 return;
564 }
565}
566
567void obj_moveoutletfirst(t_object *x, t_outlet *o)
568{
569 t_outlet *o2;
570 if (x->ob_outlet == o) return;
571 else for (o2 = x->ob_outlet; o2; o2 = o2->o_next)
572 if (o2->o_next == o)
573 {
574 o2->o_next = o->o_next;
575 o->o_next = x->ob_outlet;
576 x->ob_outlet = o;
577 return;
578 }
579}
580
581 /* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
582 /* LATER try to consolidate all the slightly different routines. */
583
584int obj_nsiginlets(t_object *x)
585{
586 int n;
587 t_inlet *i;
588 for (i = x->ob_inlet, n = 0; i; i = i->i_next)
589 if (i->i_symfrom == &s_signal) n++;
590 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) n++;
591 return (n);
592}
593
594 /* get the index, among signal inlets, of the mth inlet overall */
595int obj_siginletindex(t_object *x, int m)
596{
597 int n = 0;
598 t_inlet *i;
599 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
600 {
601 if (!m--) return (0);
602 n++;
603 }
604 for (i = x->ob_inlet; i; i = i->i_next, m--)
605 if (i->i_symfrom == &s_signal)
606 {
607 if (m == 0) return (n);
608 n++;
609 }
610 return (-1);
611}
612
613int obj_issignalinlet(t_object *x, int m)
614{
615 t_inlet *i;
616 if (x->ob_pd->c_firstin)
617 {
618 if (!m)
619 return (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin);
620 else m--;
621 }
622 for (i = x->ob_inlet; i && m; i = i->i_next, m--)
623 ;
624 return (i && (i->i_symfrom == &s_signal));
625}
626
627int obj_nsigoutlets(t_object *x)
628{
629 int n;
630 t_outlet *o;
631 for (o = x->ob_outlet, n = 0; o; o = o->o_next)
632 if (o->o_sym == &s_signal) n++;
633 return (n);
634}
635
636int obj_sigoutletindex(t_object *x, int m)
637{
638 int n;
639 t_outlet *o2;
640 for (o2 = x->ob_outlet, n = 0; o2; o2 = o2->o_next, m--)
641 if (o2->o_sym == &s_signal)
642 {
643 if (m == 0) return (n);
644 n++;
645 }
646 return (-1);
647}
648
649int obj_issignaloutlet(t_object *x, int m)
650{
651 int n;
652 t_outlet *o2;
653 for (o2 = x->ob_outlet, n = 0; o2 && m--; o2 = o2->o_next);
654 return (o2 && (o2->o_sym == &s_signal));
655}
656
657t_sample *obj_findsignalscalar(t_object *x, int m)
658{
659 int n = 0;
660 t_inlet *i;
661 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
662 {
663 if (!m--)
664 return (x->ob_pd->c_floatsignalin > 0 ?
665 (t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
666 n++;
667 }
668 for (i = x->ob_inlet; i; i = i->i_next, m--)
669 if (i->i_symfrom == &s_signal)
670 {
671 if (m == 0)
672 return (&i->i_un.iu_floatsignalvalue);
673 n++;
674 }
675 return (0);
676}
677
678/* and these are only used in g_io.c... */
679
680int inlet_getsignalindex(t_inlet *x)
681{
682 int n = 0;
683 t_inlet *i;
684 for (i = x->i_owner->ob_inlet, n = 0; i && i != x; i = i->i_next)
685 if (i->i_symfrom == &s_signal) n++;
686 return (n);
687}
688
689int outlet_getsignalindex(t_outlet *x)
690{
691 int n = 0;
692 t_outlet *o;
693 for (o = x->o_owner->ob_outlet, n = 0; o && o != x; o = o->o_next)
694 if (o->o_sym == &s_signal) n++;
695 return (n);
696}
697
698/* Copyright (c) 1997-1999 Miller Puckette.
699* For information on usage and redistribution, and for a DISCLAIMER OF ALL
700* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
701
702/* this file handles Max-style patchable objects, i.e., objects which
703can interconnect via inlets and outlets; also, the (terse) generic
704behavior for "gobjs" appears at the end of this file. */
705
706#include "m_pd.h"
707#include "m_imp.h"
708
709union inletunion
710{
711 t_symbol *iu_symto;
712 t_gpointer *iu_pointerslot;
713 t_float *iu_floatslot;
714 t_symbol **iu_symslot;
715 t_sample iu_floatsignalvalue;
716};
717
718struct _inlet
719{
720 t_pd i_pd;
721 struct _inlet *i_next;
722 t_object *i_owner;
723 t_pd *i_dest;
724 t_symbol *i_symfrom;
725 union inletunion i_un;
726};
727
728#define i_symto i_un.iu_symto
729#define i_pointerslot i_un.iu_pointerslot
730#define i_floatslot i_un.iu_floatslot
731#define i_symslot i_un.iu_symslot
732
733static t_class *inlet_class, *pointerinlet_class, *floatinlet_class,
734 *symbolinlet_class;
735
736#define ISINLET(pd) ((*(pd) == inlet_class) || \
737 (*(pd) == pointerinlet_class) || \
738 (*(pd) == floatinlet_class) || \
739 (*(pd) == symbolinlet_class))
740
741/* --------------------- generic inlets ala max ------------------ */
742
743t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2)
744{
745 t_inlet *x = (t_inlet *)pd_new(inlet_class), *y, *y2;
746 x->i_owner = owner;
747 x->i_dest = dest;
748 if (s1 == &s_signal)
749 x->i_un.iu_floatsignalvalue = 0;
750 else x->i_symto = s2;
751 x->i_symfrom = s1;
752 x->i_next = 0;
753 if (y = owner->ob_inlet)
754 {
755 while (y2 = y->i_next) y = y2;
756 y->i_next = x;
757 }
758 else owner->ob_inlet = x;
759 return (x);
760}
761
762static void inlet_wrong(t_inlet *x, t_symbol *s)
763{
764 pd_error(x->i_owner, "inlet: expected '%s' but got '%s'",
765 x->i_symfrom->s_name, s->s_name);
766}
767
768 /* LATER figure out how to make these efficient: */
769static void inlet_bang(t_inlet *x)
770{
771 if (x->i_symfrom == &s_bang)
772 pd_vmess(x->i_dest, x->i_symto, "");
773 else if (!x->i_symfrom) pd_bang(x->i_dest);
774 else inlet_wrong(x, &s_bang);
775}
776
777static void inlet_pointer(t_inlet *x, t_gpointer *gp)
778{
779 if (x->i_symfrom == &s_pointer)
780 pd_vmess(x->i_dest, x->i_symto, "p", gp);
781 else if (!x->i_symfrom) pd_pointer(x->i_dest, gp);
782 else inlet_wrong(x, &s_pointer);
783}
784
785static void inlet_float(t_inlet *x, t_float f)
786{
787 if (x->i_symfrom == &s_float)
788 pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
789 else if (x->i_symfrom == &s_signal)
790 x->i_un.iu_floatsignalvalue = ftofix(f);
791 else if (!x->i_symfrom)
792 pd_float(x->i_dest, f);
793 else inlet_wrong(x, &s_float);
794}
795
796static void inlet_symbol(t_inlet *x, t_symbol *s)
797{
798 if (x->i_symfrom == &s_symbol)
799 pd_vmess(x->i_dest, x->i_symto, "s", s);
800 else if (!x->i_symfrom) pd_symbol(x->i_dest, s);
801 else inlet_wrong(x, &s_symbol);
802}
803
804static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
805{
806 t_atom at;
807 if (x->i_symfrom == &s_list || x->i_symfrom == &s_float
808 || x->i_symfrom == &s_symbol || x->i_symfrom == &s_pointer)
809 typedmess(x->i_dest, x->i_symto, argc, argv);
810 else if (!x->i_symfrom) pd_list(x->i_dest, s, argc, argv);
811 else inlet_wrong(x, &s_list);
812}
813
814static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
815{
816 if (x->i_symfrom == s)
817 typedmess(x->i_dest, x->i_symto, argc, argv);
818 else if (!x->i_symfrom)
819 typedmess(x->i_dest, s, argc, argv);
820 else inlet_wrong(x, s);
821}
822
823void inlet_free(t_inlet *x)
824{
825 t_object *y = x->i_owner;
826 t_inlet *x2;
827 if (y->ob_inlet == x) y->ob_inlet = x->i_next;
828 else for (x2 = y->ob_inlet; x2; x2 = x2->i_next)
829 if (x2->i_next == x)
830 {
831 x2->i_next = x->i_next;
832 break;
833 }
834 t_freebytes(x, sizeof(*x));
835}
836
837/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
838
839static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp)
840{
841 gpointer_unset(x->i_pointerslot);
842 *(x->i_pointerslot) = *gp;
843 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
844}
845
846t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp)
847{
848 t_inlet *x = (t_inlet *)pd_new(pointerinlet_class), *y, *y2;
849 x->i_owner = owner;
850 x->i_dest = 0;
851 x->i_symfrom = &s_pointer;
852 x->i_pointerslot = gp;
853 x->i_next = 0;
854 if (y = owner->ob_inlet)
855 {
856 while (y2 = y->i_next) y = y2;
857 y->i_next = x;
858 }
859 else owner->ob_inlet = x;
860 return (x);
861}
862
863static void floatinlet_float(t_inlet *x, t_float f)
864{
865 *(x->i_floatslot) = f;
866}
867
868t_inlet *floatinlet_new(t_object *owner, t_float *fp)
869{
870 t_inlet *x = (t_inlet *)pd_new(floatinlet_class), *y, *y2;
871 x->i_owner = owner;
872 x->i_dest = 0;
873 x->i_symfrom = &s_float;
874 x->i_floatslot = fp;
875 x->i_next = 0;
876 if (y = owner->ob_inlet)
877 {
878 while (y2 = y->i_next) y = y2;
879 y->i_next = x;
880 }
881 else owner->ob_inlet = x;
882 return (x);
883}
884
885static void symbolinlet_symbol(t_inlet *x, t_symbol *s)
886{
887 *(x->i_symslot) = s;
888}
889
890t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp)
891{
892 t_inlet *x = (t_inlet *)pd_new(symbolinlet_class), *y, *y2;
893 x->i_owner = owner;
894 x->i_dest = 0;
895 x->i_symfrom = &s_symbol;
896 x->i_symslot = sp;
897 x->i_next = 0;
898 if (y = owner->ob_inlet)
899 {
900 while (y2 = y->i_next) y = y2;
901 y->i_next = x;
902 }
903 else owner->ob_inlet = x;
904 return (x);
905}
906
907/* ---------------------- routine to handle lists ---------------------- */
908
909 /* objects interpret lists by feeding them to the individual inlets.
910 Before you call this check that the object doesn't have a more
911 specific way to handle lists. */
912void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv)
913{
914 t_atom *ap;
915 int count;
916 t_inlet *ip = ((t_object *)x)->ob_inlet;
917 if (!argc) return;
918 for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->i_next)
919 {
920 if (ap->a_type == A_POINTER) pd_pointer(&ip->i_pd, ap->a_w.w_gpointer);
921 else if (ap->a_type == A_FLOAT) pd_float(&ip->i_pd, ap->a_w.w_float);
922 else pd_symbol(&ip->i_pd, ap->a_w.w_symbol);
923 }
924 if (argv->a_type == A_POINTER) pd_pointer(&x->ob_pd, argv->a_w.w_gpointer);
925 else if (argv->a_type == A_FLOAT) pd_float(&x->ob_pd, argv->a_w.w_float);
926 else pd_symbol(&x->ob_pd, argv->a_w.w_symbol);
927}
928
929void obj_init(void)
930{
931 inlet_class = class_new(gensym("inlet"), 0, 0,
932 sizeof(t_inlet), CLASS_PD, 0);
933 class_addbang(inlet_class, inlet_bang);
934 class_addpointer(inlet_class, inlet_pointer);
935 class_addfloat(inlet_class, inlet_float);
936 class_addsymbol(inlet_class, inlet_symbol);
937 class_addlist(inlet_class, inlet_list);
938 class_addanything(inlet_class, inlet_anything);
939
940 pointerinlet_class = class_new(gensym("inlet"), 0, 0,
941 sizeof(t_inlet), CLASS_PD, 0);
942 class_addpointer(pointerinlet_class, pointerinlet_pointer);
943
944 floatinlet_class = class_new(gensym("inlet"), 0, 0,
945 sizeof(t_inlet), CLASS_PD, 0);
946 class_addfloat(floatinlet_class, (t_method)floatinlet_float);
947
948 symbolinlet_class = class_new(gensym("inlet"), 0, 0,
949 sizeof(t_inlet), CLASS_PD, 0);
950 class_addsymbol(symbolinlet_class, symbolinlet_symbol);
951
952}
953
954/* --------------------------- outlets ------------------------------ */
955
956static char *stacklimit, *topstack;
957#define STACKSIZE 1000000
958static int outlet_eventno;
959
960 /* set a stack limit (on each incoming event that can set off messages)
961 for the outlet functions to check to prevent stack overflow from message
962 recursion */
963void outlet_setstacklim(void)
964{
965 char c;
966 topstack = &c;
967 stacklimit = (&c) - STACKSIZE;
968 outlet_eventno++;
969}
970
971 /* get a number unique to the (clock, MIDI, GUI, etc.) event we're on */
972int sched_geteventno( void)
973{
974 return (outlet_eventno);
975}
976
977struct _outconnect
978{
979 struct _outconnect *oc_next;
980 t_pd *oc_to;
981};
982
983struct _outlet
984{
985 t_object *o_owner;
986 struct _outlet *o_next;
987 t_outconnect *o_connections;
988 t_symbol *o_sym;
989};
990
991t_outlet *outlet_new(t_object *owner, t_symbol *s)
992{
993 t_outlet *x = (t_outlet *)getbytes(sizeof(*x)), *y, *y2;
994 x->o_owner = owner;
995 x->o_next = 0;
996 if (y = owner->ob_outlet)
997 {
998 while (y2 = y->o_next) y = y2;
999 y->o_next = x;
1000 }
1001 else owner->ob_outlet = x;
1002 x->o_connections = 0;
1003 x->o_sym = s;
1004 return (x);
1005}
1006
1007static void outlet_stackerror(t_outlet *x)
1008{
1009 pd_error(x->o_owner, "stack overflow");
1010 stacklimit = topstack;
1011}
1012
1013void outlet_bang(t_outlet *x)
1014{
1015 t_outconnect *oc;
1016 char c;
1017 if (&c < stacklimit)
1018 outlet_stackerror(x);
1019 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1020 pd_bang(oc->oc_to);
1021}
1022
1023void outlet_pointer(t_outlet *x, t_gpointer *gp)
1024{
1025 t_outconnect *oc;
1026 t_gpointer gpointer;
1027 char c;
1028 if (&c < stacklimit)
1029 outlet_stackerror(x);
1030 else
1031 {
1032#if 0
1033 gpointer_copy(gp, &gpointer);
1034 for (oc = x->o_connections; oc; oc = oc->oc_next)
1035 pd_pointer(oc->oc_to, &gpointer);
1036 gpointer_unset(&gpointer);
1037#else
1038 gpointer = *gp;
1039 for (oc = x->o_connections; oc; oc = oc->oc_next)
1040 pd_pointer(oc->oc_to, &gpointer);
1041#endif
1042 }
1043}
1044
1045void outlet_float(t_outlet *x, t_float f)
1046{
1047 t_outconnect *oc;
1048 char c;
1049 if (&c < stacklimit)
1050 outlet_stackerror(x);
1051 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1052 pd_float(oc->oc_to, f);
1053}
1054
1055void outlet_symbol(t_outlet *x, t_symbol *s)
1056{
1057 t_outconnect *oc;
1058 char c;
1059 if (&c < stacklimit)
1060 outlet_stackerror(x);
1061 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1062 pd_symbol(oc->oc_to, s);
1063}
1064
1065void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
1066{
1067 t_outconnect *oc;
1068 char c;
1069 if (&c < stacklimit)
1070 outlet_stackerror(x);
1071 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1072 pd_list(oc->oc_to, s, argc, argv);
1073}
1074
1075void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
1076{
1077 t_outconnect *oc;
1078 char c;
1079 if (&c < stacklimit)
1080 outlet_stackerror(x);
1081 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1082 typedmess(oc->oc_to, s, argc, argv);
1083}
1084
1085 /* get the outlet's declared symbol */
1086t_symbol *outlet_getsymbol(t_outlet *x)
1087{
1088 return (x->o_sym);
1089}
1090
1091void outlet_free(t_outlet *x)
1092{
1093 t_object *y = x->o_owner;
1094 t_outlet *x2;
1095 if (y->ob_outlet == x) y->ob_outlet = x->o_next;
1096 else for (x2 = y->ob_outlet; x2; x2 = x2->o_next)
1097 if (x2->o_next == x)
1098 {
1099 x2->o_next = x->o_next;
1100 break;
1101 }
1102 t_freebytes(x, sizeof(*x));
1103}
1104
1105t_outconnect *obj_connect(t_object *source, int outno,
1106 t_object *sink, int inno)
1107{
1108 t_inlet *i;
1109 t_outlet *o;
1110 t_pd *to;
1111 t_outconnect *oc, *oc2;
1112
1113 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ;
1114 if (!o) return (0);
1115
1116 if (sink->ob_pd->c_firstin)
1117 {
1118 if (!inno)
1119 {
1120 to = &sink->ob_pd;
1121 goto doit;
1122 }
1123 else inno--;
1124 }
1125 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
1126 if (!i) return (0);
1127 to = &i->i_pd;
1128doit:
1129 oc = (t_outconnect *)t_getbytes(sizeof(*oc));
1130 oc->oc_next = 0;
1131 oc->oc_to = to;
1132 /* append it to the end of the list */
1133 /* LATER we might cache the last "oc" to make this faster. */
1134 if ((oc2 = o->o_connections))
1135 {
1136 while (oc2->oc_next) oc2 = oc2->oc_next;
1137 oc2->oc_next = oc;
1138 }
1139 else o->o_connections = oc;
1140 if (o->o_sym == &s_signal) canvas_update_dsp();
1141
1142 return (oc);
1143}
1144
1145void obj_disconnect(t_object *source, int outno, t_object *sink, int inno)
1146{
1147 t_inlet *i;
1148 t_outlet *o;
1149 t_pd *to;
1150 t_outconnect *oc, *oc2;
1151
1152 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--)
1153 if (!o) return;
1154 if (sink->ob_pd->c_firstin)
1155 {
1156 if (!inno)
1157 {
1158 to = &sink->ob_pd;
1159 goto doit;
1160 }
1161 else inno--;
1162 }
1163 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
1164 if (!i) return;
1165 to = &i->i_pd;
1166doit:
1167 if (!(oc = o->o_connections)) return;
1168 if (oc->oc_to == to)
1169 {
1170 o->o_connections = oc->oc_next;
1171 freebytes(oc, sizeof(*oc));
1172 goto done;
1173 }
1174 while (oc2 = oc->oc_next)
1175 {
1176 if (oc2->oc_to == to)
1177 {
1178 oc->oc_next = oc2->oc_next;
1179 freebytes(oc2, sizeof(*oc2));
1180 goto done;
1181 }
1182 oc = oc2;
1183 }
1184done:
1185 if (o->o_sym == &s_signal) canvas_update_dsp();
1186}
1187
1188/* ------ traversal routines for code that can't see our structures ------ */
1189
1190int obj_noutlets(t_object *x)
1191{
1192 int n;
1193 t_outlet *o;
1194 for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++;
1195 return (n);
1196}
1197
1198int obj_ninlets(t_object *x)
1199{
1200 int n;
1201 t_inlet *i;
1202 for (i = x->ob_inlet, n = 0; i; i = i->i_next) n++;
1203 if (x->ob_pd->c_firstin) n++;
1204 return (n);
1205}
1206
1207t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout)
1208{
1209 t_outlet *o = x->ob_outlet;
1210 while (nout-- && o) o = o->o_next;
1211 *op = o;
1212 if (o) return (o->o_connections);
1213 else return (0);
1214}
1215
1216t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
1217 t_object **destp, t_inlet **inletp, int *whichp)
1218{
1219 t_pd *y;
1220 y = lastconnect->oc_to;
1221 if (ISINLET(y))
1222 {
1223 int n;
1224 t_inlet *i = (t_inlet *)y, *i2;
1225 t_object *dest = i->i_owner;
1226 for (n = dest->ob_pd->c_firstin, i2 = dest->ob_inlet;
1227 i2 && i2 != i; i2 = i2->i_next) n++;
1228 *whichp = n;
1229 *destp = dest;
1230 *inletp = i;
1231 }
1232 else
1233 {
1234 *whichp = 0;
1235 *inletp = 0;
1236 *destp = ((t_object *)y);
1237 }
1238 return (lastconnect->oc_next);
1239}
1240
1241 /* this one checks that a pd is indeed a patchable object, and returns
1242 it, correctly typed, or zero if the check failed. */
1243t_object *pd_checkobject(t_pd *x)
1244{
1245 if ((*x)->c_patchable) return ((t_object *)x);
1246 else return (0);
1247}
1248
1249 /* move an inlet or outlet to the head of the list */
1250void obj_moveinletfirst(t_object *x, t_inlet *i)
1251{
1252 t_inlet *i2;
1253 if (x->ob_inlet == i) return;
1254 else for (i2 = x->ob_inlet; i2; i2 = i2->i_next)
1255 if (i2->i_next == i)
1256 {
1257 i2->i_next = i->i_next;
1258 i->i_next = x->ob_inlet;
1259 x->ob_inlet = i;
1260 return;
1261 }
1262}
1263
1264void obj_moveoutletfirst(t_object *x, t_outlet *o)
1265{
1266 t_outlet *o2;
1267 if (x->ob_outlet == o) return;
1268 else for (o2 = x->ob_outlet; o2; o2 = o2->o_next)
1269 if (o2->o_next == o)
1270 {
1271 o2->o_next = o->o_next;
1272 o->o_next = x->ob_outlet;
1273 x->ob_outlet = o;
1274 return;
1275 }
1276}
1277
1278 /* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
1279 /* LATER try to consolidate all the slightly different routines. */
1280
1281int obj_nsiginlets(t_object *x)
1282{
1283 int n;
1284 t_inlet *i;
1285 for (i = x->ob_inlet, n = 0; i; i = i->i_next)
1286 if (i->i_symfrom == &s_signal) n++;
1287 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) n++;
1288 return (n);
1289}
1290
1291 /* get the index, among signal inlets, of the mth inlet overall */
1292int obj_siginletindex(t_object *x, int m)
1293{
1294 int n = 0;
1295 t_inlet *i;
1296 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
1297 {
1298 if (!m--) return (0);
1299 n++;
1300 }
1301 for (i = x->ob_inlet; i; i = i->i_next, m--)
1302 if (i->i_symfrom == &s_signal)
1303 {
1304 if (m == 0) return (n);
1305 n++;
1306 }
1307 return (-1);
1308}
1309
1310int obj_issignalinlet(t_object *x, int m)
1311{
1312 t_inlet *i;
1313 if (x->ob_pd->c_firstin)
1314 {
1315 if (!m)
1316 return (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin);
1317 else m--;
1318 }
1319 for (i = x->ob_inlet; i && m; i = i->i_next, m--)
1320 ;
1321 return (i && (i->i_symfrom == &s_signal));
1322}
1323
1324int obj_nsigoutlets(t_object *x)
1325{
1326 int n;
1327 t_outlet *o;
1328 for (o = x->ob_outlet, n = 0; o; o = o->o_next)
1329 if (o->o_sym == &s_signal) n++;
1330 return (n);
1331}
1332
1333int obj_sigoutletindex(t_object *x, int m)
1334{
1335 int n;
1336 t_outlet *o2;
1337 for (o2 = x->ob_outlet, n = 0; o2; o2 = o2->o_next, m--)
1338 if (o2->o_sym == &s_signal)
1339 {
1340 if (m == 0) return (n);
1341 n++;
1342 }
1343 return (-1);
1344}
1345
1346int obj_issignaloutlet(t_object *x, int m)
1347{
1348 int n;
1349 t_outlet *o2;
1350 for (o2 = x->ob_outlet, n = 0; o2 && m--; o2 = o2->o_next);
1351 return (o2 && (o2->o_sym == &s_signal));
1352}
1353
1354t_sample *obj_findsignalscalar(t_object *x, int m)
1355{
1356 int n = 0;
1357 t_inlet *i;
1358 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
1359 {
1360 if (!m--)
1361 return (x->ob_pd->c_floatsignalin > 0 ?
1362 (t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
1363 n++;
1364 }
1365 for (i = x->ob_inlet; i; i = i->i_next, m--)
1366 if (i->i_symfrom == &s_signal)
1367 {
1368 if (m == 0)
1369 return (&i->i_un.iu_floatsignalvalue);
1370 n++;
1371 }
1372 return (0);
1373}
1374
1375/* and these are only used in g_io.c... */
1376
1377int inlet_getsignalindex(t_inlet *x)
1378{
1379 int n = 0;
1380 t_inlet *i;
1381 for (i = x->i_owner->ob_inlet, n = 0; i && i != x; i = i->i_next)
1382 if (i->i_symfrom == &s_signal) n++;
1383 return (n);
1384}
1385
1386int outlet_getsignalindex(t_outlet *x)
1387{
1388 int n = 0;
1389 t_outlet *o;
1390 for (o = x->o_owner->ob_outlet, n = 0; o && o != x; o = o->o_next)
1391 if (o->o_sym == &s_signal) n++;
1392 return (n);
1393}
1394
diff --git a/apps/plugins/pdbox/PDa/src/m_pd.c b/apps/plugins/pdbox/PDa/src/m_pd.c
new file mode 100644
index 0000000000..321574b5a2
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_pd.c
@@ -0,0 +1,612 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include <stdlib.h>
6#include "m_pd.h"
7#include "m_imp.h"
8
9 /* FIXME no out-of-memory testing yet! */
10
11t_pd *pd_new(t_class *c)
12{
13 t_pd *x;
14 if (!c)
15 bug ("pd_new: apparently called before setup routine");
16 x = (t_pd *)t_getbytes(c->c_size);
17 *x = c;
18 if (c->c_patchable)
19 {
20 ((t_object *)x)->ob_inlet = 0;
21 ((t_object *)x)->ob_outlet = 0;
22 }
23 return (x);
24}
25
26void pd_free(t_pd *x)
27{
28 t_class *c = *x;
29 if (c->c_freemethod) (*(t_gotfn)(c->c_freemethod))(x);
30 if (c->c_patchable)
31 {
32 while (((t_object *)x)->ob_outlet)
33 outlet_free(((t_object *)x)->ob_outlet);
34 while (((t_object *)x)->ob_inlet)
35 inlet_free(((t_object *)x)->ob_inlet);
36 if (((t_object *)x)->ob_binbuf)
37 binbuf_free(((t_object *)x)->ob_binbuf);
38 }
39 if (c->c_size) t_freebytes(x, c->c_size);
40}
41
42void gobj_save(t_gobj *x, t_binbuf *b)
43{
44 t_class *c = x->g_pd;
45 if (c->c_savefn)
46 (c->c_savefn)(x, b);
47}
48
49/* deal with several objects bound to the same symbol. If more than one, we
50actually bind a collection object to the symbol, which forwards messages sent
51to the symbol. */
52
53static t_class *bindlist_class;
54
55typedef struct _bindelem
56{
57 t_pd *e_who;
58 struct _bindelem *e_next;
59} t_bindelem;
60
61typedef struct _bindlist
62{
63 t_pd b_pd;
64 t_bindelem *b_list;
65} t_bindlist;
66
67static void bindlist_bang(t_bindlist *x)
68{
69 t_bindelem *e;
70 for (e = x->b_list; e; e = e->e_next)
71 pd_bang(e->e_who);
72}
73
74static void bindlist_float(t_bindlist *x, t_float f)
75{
76 t_bindelem *e;
77 for (e = x->b_list; e; e = e->e_next) {
78 pd_float(e->e_who, f);
79 }
80}
81
82static void bindlist_symbol(t_bindlist *x, t_symbol *s)
83{
84 t_bindelem *e;
85 for (e = x->b_list; e; e = e->e_next)
86 pd_symbol(e->e_who, s);
87}
88
89static void bindlist_pointer(t_bindlist *x, t_gpointer *gp)
90{
91 t_bindelem *e;
92 for (e = x->b_list; e; e = e->e_next)
93 pd_pointer(e->e_who, gp);
94}
95
96static void bindlist_list(t_bindlist *x, t_symbol *s,
97 int argc, t_atom *argv)
98{
99 t_bindelem *e;
100 for (e = x->b_list; e; e = e->e_next)
101 pd_list(e->e_who, s, argc, argv);
102}
103
104static void bindlist_anything(t_bindlist *x, t_symbol *s,
105 int argc, t_atom *argv)
106{
107 t_bindelem *e;
108 for (e = x->b_list; e; e = e->e_next)
109 pd_typedmess(e->e_who, s, argc, argv);
110}
111
112void m_pd_setup(void)
113{
114 bindlist_class = class_new(gensym("bindlist"), 0, 0,
115 sizeof(t_bindlist), CLASS_PD, 0);
116 class_addbang(bindlist_class, bindlist_bang);
117 class_addfloat(bindlist_class, (t_method)bindlist_float);
118 class_addsymbol(bindlist_class, bindlist_symbol);
119 class_addpointer(bindlist_class, bindlist_pointer);
120 class_addlist(bindlist_class, bindlist_list);
121 class_addanything(bindlist_class, bindlist_anything);
122}
123
124void pd_bind(t_pd *x, t_symbol *s)
125{
126 pd_checkgui(x,s);
127 if (s->s_thing)
128 {
129 if (*s->s_thing == bindlist_class)
130 {
131 t_bindlist *b = (t_bindlist *)s->s_thing;
132 t_bindelem *e = (t_bindelem *)getbytes(sizeof(t_bindelem));
133 e->e_next = b->b_list;
134 e->e_who = x;
135 b->b_list = e;
136 }
137 else
138 {
139 t_bindlist *b = (t_bindlist *)pd_new(bindlist_class);
140 t_bindelem *e1 = (t_bindelem *)getbytes(sizeof(t_bindelem));
141 t_bindelem *e2 = (t_bindelem *)getbytes(sizeof(t_bindelem));
142 b->b_list = e1;
143 e1->e_who = x;
144 e1->e_next = e2;
145 e2->e_who = s->s_thing;
146 e2->e_next = 0;
147 s->s_thing = &b->b_pd;
148 }
149 }
150 else s->s_thing = x;
151}
152
153void pd_unbind(t_pd *x, t_symbol *s)
154{
155 if (s->s_thing == x) s->s_thing = 0;
156 else if (s->s_thing && *s->s_thing == bindlist_class)
157 {
158 /* bindlists always have at least two elements... if the number
159 goes down to one, get rid of the bindlist and bind the symbol
160 straight to the remaining element. */
161
162 t_bindlist *b = (t_bindlist *)s->s_thing;
163 t_bindelem *e, *e2;
164 if ((e = b->b_list)->e_who == x)
165 {
166 b->b_list = e->e_next;
167 freebytes(e, sizeof(t_bindelem));
168 }
169 else for (e = b->b_list; e2 = e->e_next; e = e2)
170 if (e2->e_who == x)
171 {
172 e->e_next = e2->e_next;
173 freebytes(e2, sizeof(t_bindelem));
174 break;
175 }
176 if (!b->b_list->e_next)
177 {
178 s->s_thing = b->b_list->e_who;
179 freebytes(b->b_list, sizeof(t_bindelem));
180 pd_free(&b->b_pd);
181 }
182 }
183 else pd_error(x, "%s: couldn't unbind", s->s_name);
184}
185
186void zz(void) {}
187
188t_pd *pd_findbyclass(t_symbol *s, t_class *c)
189{
190 t_pd *x = 0;
191
192 if (!s->s_thing) return (0);
193 if (*s->s_thing == c) return (s->s_thing);
194 if (*s->s_thing == bindlist_class)
195 {
196 t_bindlist *b = (t_bindlist *)s->s_thing;
197 t_bindelem *e, *e2;
198 int warned = 0;
199 for (e = b->b_list; e; e = e->e_next)
200 if (*e->e_who == c)
201 {
202 if (x && !warned)
203 {
204 zz();
205 post("warning: %s: multiply defined", s->s_name);
206 warned = 1;
207 }
208 x = e->e_who;
209 }
210 }
211 return x;
212}
213
214/* stack for maintaining bindings for the #X symbol during nestable loads.
215*/
216
217typedef struct _gstack
218{
219 t_pd *g_what;
220 t_symbol *g_loadingabstraction;
221 struct _gstack *g_next;
222} t_gstack;
223
224static t_gstack *gstack_head = 0;
225static t_pd *lastpopped;
226static t_symbol *pd_loadingabstraction;
227
228int pd_setloadingabstraction(t_symbol *sym)
229{
230 t_gstack *foo = gstack_head;
231 for (foo = gstack_head; foo; foo = foo->g_next)
232 if (foo->g_loadingabstraction == sym)
233 return (1);
234 pd_loadingabstraction = sym;
235 return (0);
236}
237
238void pd_pushsym(t_pd *x)
239{
240 t_gstack *y = (t_gstack *)t_getbytes(sizeof(*y));
241 y->g_what = s__X.s_thing;
242 y->g_next = gstack_head;
243 y->g_loadingabstraction = pd_loadingabstraction;
244 pd_loadingabstraction = 0;
245 gstack_head = y;
246 s__X.s_thing = x;
247}
248
249void pd_popsym(t_pd *x)
250{
251 if (!gstack_head || s__X.s_thing != x) bug("gstack_pop");
252 else
253 {
254 t_gstack *headwas = gstack_head;
255 s__X.s_thing = headwas->g_what;
256 gstack_head = headwas->g_next;
257 t_freebytes(headwas, sizeof(*headwas));
258 lastpopped = x;
259 }
260}
261
262void pd_doloadbang(void)
263{
264 if (lastpopped)
265 pd_vmess(lastpopped, gensym("loadbang"), "");
266 lastpopped = 0;
267}
268
269void pd_bang(t_pd *x)
270{
271 (*(*x)->c_bangmethod)(x);
272}
273
274void pd_float(t_pd *x, t_float f)
275{
276 (*(*x)->c_floatmethod)(x, f);
277}
278
279void pd_pointer(t_pd *x, t_gpointer *gp)
280{
281 (*(*x)->c_pointermethod)(x, gp);
282}
283
284void pd_symbol(t_pd *x, t_symbol *s)
285{
286 (*(*x)->c_symbolmethod)(x, s);
287}
288
289void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv)
290{
291 (*(*x)->c_listmethod)(x, &s_list, argc, argv);
292}
293
294void mess_init(void);
295void obj_init(void);
296void conf_init(void);
297void glob_init(void);
298
299void pd_init(void)
300{
301 mess_init();
302 obj_init();
303 conf_init();
304 glob_init();
305}
306
307/* Copyright (c) 1997-1999 Miller Puckette.
308* For information on usage and redistribution, and for a DISCLAIMER OF ALL
309* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
310
311#include <stdlib.h>
312#include "m_pd.h"
313#include "m_imp.h"
314
315 /* FIXME no out-of-memory testing yet! */
316
317t_pd *pd_new(t_class *c)
318{
319 t_pd *x;
320 if (!c)
321 bug ("pd_new: apparently called before setup routine");
322 x = (t_pd *)t_getbytes(c->c_size);
323 *x = c;
324 if (c->c_patchable)
325 {
326 ((t_object *)x)->ob_inlet = 0;
327 ((t_object *)x)->ob_outlet = 0;
328 }
329 return (x);
330}
331
332void pd_free(t_pd *x)
333{
334 t_class *c = *x;
335 if (c->c_freemethod) (*(t_gotfn)(c->c_freemethod))(x);
336 if (c->c_patchable)
337 {
338 while (((t_object *)x)->ob_outlet)
339 outlet_free(((t_object *)x)->ob_outlet);
340 while (((t_object *)x)->ob_inlet)
341 inlet_free(((t_object *)x)->ob_inlet);
342 if (((t_object *)x)->ob_binbuf)
343 binbuf_free(((t_object *)x)->ob_binbuf);
344 }
345 if (c->c_size) t_freebytes(x, c->c_size);
346}
347
348void gobj_save(t_gobj *x, t_binbuf *b)
349{
350 t_class *c = x->g_pd;
351 if (c->c_savefn)
352 (c->c_savefn)(x, b);
353}
354
355/* deal with several objects bound to the same symbol. If more than one, we
356actually bind a collection object to the symbol, which forwards messages sent
357to the symbol. */
358
359static t_class *bindlist_class;
360
361typedef struct _bindelem
362{
363 t_pd *e_who;
364 struct _bindelem *e_next;
365} t_bindelem;
366
367typedef struct _bindlist
368{
369 t_pd b_pd;
370 t_bindelem *b_list;
371} t_bindlist;
372
373static void bindlist_bang(t_bindlist *x)
374{
375 t_bindelem *e;
376 for (e = x->b_list; e; e = e->e_next)
377 pd_bang(e->e_who);
378}
379
380static void bindlist_float(t_bindlist *x, t_float f)
381{
382 t_bindelem *e;
383 for (e = x->b_list; e; e = e->e_next) {
384 pd_float(e->e_who, f);
385 }
386}
387
388static void bindlist_symbol(t_bindlist *x, t_symbol *s)
389{
390 t_bindelem *e;
391 for (e = x->b_list; e; e = e->e_next)
392 pd_symbol(e->e_who, s);
393}
394
395static void bindlist_pointer(t_bindlist *x, t_gpointer *gp)
396{
397 t_bindelem *e;
398 for (e = x->b_list; e; e = e->e_next)
399 pd_pointer(e->e_who, gp);
400}
401
402static void bindlist_list(t_bindlist *x, t_symbol *s,
403 int argc, t_atom *argv)
404{
405 t_bindelem *e;
406 for (e = x->b_list; e; e = e->e_next)
407 pd_list(e->e_who, s, argc, argv);
408}
409
410static void bindlist_anything(t_bindlist *x, t_symbol *s,
411 int argc, t_atom *argv)
412{
413 t_bindelem *e;
414 for (e = x->b_list; e; e = e->e_next)
415 pd_typedmess(e->e_who, s, argc, argv);
416}
417
418void m_pd_setup(void)
419{
420 bindlist_class = class_new(gensym("bindlist"), 0, 0,
421 sizeof(t_bindlist), CLASS_PD, 0);
422 class_addbang(bindlist_class, bindlist_bang);
423 class_addfloat(bindlist_class, (t_method)bindlist_float);
424 class_addsymbol(bindlist_class, bindlist_symbol);
425 class_addpointer(bindlist_class, bindlist_pointer);
426 class_addlist(bindlist_class, bindlist_list);
427 class_addanything(bindlist_class, bindlist_anything);
428}
429
430void pd_bind(t_pd *x, t_symbol *s)
431{
432 pd_checkgui(x,s);
433 if (s->s_thing)
434 {
435 if (*s->s_thing == bindlist_class)
436 {
437 t_bindlist *b = (t_bindlist *)s->s_thing;
438 t_bindelem *e = (t_bindelem *)getbytes(sizeof(t_bindelem));
439 e->e_next = b->b_list;
440 e->e_who = x;
441 b->b_list = e;
442 }
443 else
444 {
445 t_bindlist *b = (t_bindlist *)pd_new(bindlist_class);
446 t_bindelem *e1 = (t_bindelem *)getbytes(sizeof(t_bindelem));
447 t_bindelem *e2 = (t_bindelem *)getbytes(sizeof(t_bindelem));
448 b->b_list = e1;
449 e1->e_who = x;
450 e1->e_next = e2;
451 e2->e_who = s->s_thing;
452 e2->e_next = 0;
453 s->s_thing = &b->b_pd;
454 }
455 }
456 else s->s_thing = x;
457}
458
459void pd_unbind(t_pd *x, t_symbol *s)
460{
461 if (s->s_thing == x) s->s_thing = 0;
462 else if (s->s_thing && *s->s_thing == bindlist_class)
463 {
464 /* bindlists always have at least two elements... if the number
465 goes down to one, get rid of the bindlist and bind the symbol
466 straight to the remaining element. */
467
468 t_bindlist *b = (t_bindlist *)s->s_thing;
469 t_bindelem *e, *e2;
470 if ((e = b->b_list)->e_who == x)
471 {
472 b->b_list = e->e_next;
473 freebytes(e, sizeof(t_bindelem));
474 }
475 else for (e = b->b_list; e2 = e->e_next; e = e2)
476 if (e2->e_who == x)
477 {
478 e->e_next = e2->e_next;
479 freebytes(e2, sizeof(t_bindelem));
480 break;
481 }
482 if (!b->b_list->e_next)
483 {
484 s->s_thing = b->b_list->e_who;
485 freebytes(b->b_list, sizeof(t_bindelem));
486 pd_free(&b->b_pd);
487 }
488 }
489 else pd_error(x, "%s: couldn't unbind", s->s_name);
490}
491
492void zz(void) {}
493
494t_pd *pd_findbyclass(t_symbol *s, t_class *c)
495{
496 t_pd *x = 0;
497
498 if (!s->s_thing) return (0);
499 if (*s->s_thing == c) return (s->s_thing);
500 if (*s->s_thing == bindlist_class)
501 {
502 t_bindlist *b = (t_bindlist *)s->s_thing;
503 t_bindelem *e, *e2;
504 int warned = 0;
505 for (e = b->b_list; e; e = e->e_next)
506 if (*e->e_who == c)
507 {
508 if (x && !warned)
509 {
510 zz();
511 post("warning: %s: multiply defined", s->s_name);
512 warned = 1;
513 }
514 x = e->e_who;
515 }
516 }
517 return x;
518}
519
520/* stack for maintaining bindings for the #X symbol during nestable loads.
521*/
522
523typedef struct _gstack
524{
525 t_pd *g_what;
526 t_symbol *g_loadingabstraction;
527 struct _gstack *g_next;
528} t_gstack;
529
530static t_gstack *gstack_head = 0;
531static t_pd *lastpopped;
532static t_symbol *pd_loadingabstraction;
533
534int pd_setloadingabstraction(t_symbol *sym)
535{
536 t_gstack *foo = gstack_head;
537 for (foo = gstack_head; foo; foo = foo->g_next)
538 if (foo->g_loadingabstraction == sym)
539 return (1);
540 pd_loadingabstraction = sym;
541 return (0);
542}
543
544void pd_pushsym(t_pd *x)
545{
546 t_gstack *y = (t_gstack *)t_getbytes(sizeof(*y));
547 y->g_what = s__X.s_thing;
548 y->g_next = gstack_head;
549 y->g_loadingabstraction = pd_loadingabstraction;
550 pd_loadingabstraction = 0;
551 gstack_head = y;
552 s__X.s_thing = x;
553}
554
555void pd_popsym(t_pd *x)
556{
557 if (!gstack_head || s__X.s_thing != x) bug("gstack_pop");
558 else
559 {
560 t_gstack *headwas = gstack_head;
561 s__X.s_thing = headwas->g_what;
562 gstack_head = headwas->g_next;
563 t_freebytes(headwas, sizeof(*headwas));
564 lastpopped = x;
565 }
566}
567
568void pd_doloadbang(void)
569{
570 if (lastpopped)
571 pd_vmess(lastpopped, gensym("loadbang"), "");
572 lastpopped = 0;
573}
574
575void pd_bang(t_pd *x)
576{
577 (*(*x)->c_bangmethod)(x);
578}
579
580void pd_float(t_pd *x, t_float f)
581{
582 (*(*x)->c_floatmethod)(x, f);
583}
584
585void pd_pointer(t_pd *x, t_gpointer *gp)
586{
587 (*(*x)->c_pointermethod)(x, gp);
588}
589
590void pd_symbol(t_pd *x, t_symbol *s)
591{
592 (*(*x)->c_symbolmethod)(x, s);
593}
594
595void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv)
596{
597 (*(*x)->c_listmethod)(x, &s_list, argc, argv);
598}
599
600void mess_init(void);
601void obj_init(void);
602void conf_init(void);
603void glob_init(void);
604
605void pd_init(void)
606{
607 mess_init();
608 obj_init();
609 conf_init();
610 glob_init();
611}
612
diff --git a/apps/plugins/pdbox/PDa/src/m_pd.h b/apps/plugins/pdbox/PDa/src/m_pd.h
new file mode 100644
index 0000000000..67c569c581
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_pd.h
@@ -0,0 +1,1300 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#ifndef __m_pd_h_
6
7#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
8extern "C" {
9#endif
10
11#define PD_VERSION 0.37 /* oops, don't use this... */ */
12#define PD_MAJOR_VERSION 0 /* ... use these two instead. */
13#define PD_MINOR_VERSION 37
14
15/* old name for "MSW" flag -- we have to take it for the sake of many old
16"nmakefiles" for externs, which will define NT and not MSW */
17#if defined(NT) && !defined(MSW)
18#define MSW
19#endif
20
21#ifdef MSW
22// #pragma warning( disable : 4091 )
23#pragma warning( disable : 4305 ) /* uncast const double to float */
24#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */
25#pragma warning( disable : 4101 ) /* unused automatic variables */
26#endif /* MSW */
27
28 /* the external storage class is "extern" in UNIX; in MSW it's ugly. */
29#ifdef MSW
30#ifdef PD_INTERNAL
31#define EXTERN __declspec(dllexport) extern
32#else
33#define EXTERN __declspec(dllimport) extern
34#endif /* PD_INTERNAL */
35#else
36#define EXTERN extern
37#endif /* MSW */
38
39 /* and depending on the compiler, hidden data structures are
40 declared differently: */
41#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ )
42#define EXTERN_STRUCT struct
43#else
44#define EXTERN_STRUCT extern struct
45#endif
46
47
48#if !defined(_SIZE_T) && !defined(_SIZE_T_)
49#include <stddef.h> /* just for size_t -- how lame! */
50#endif
51
52#define MAXPDSTRING 1000 /* use this for anything you want */
53#define MAXPDARG 5 /* max number of args we can typecheck today */
54
55 /* signed and unsigned integer types the size of a pointer: */
56#ifdef __alpha__
57typedef long t_int;
58#else
59typedef int t_int;
60#endif
61
62typedef float t_float; /* a floating-point number at most the same size */
63typedef float t_floatarg; /* floating-point type for function calls */
64
65typedef struct _symbol
66{
67 char *s_name;
68 struct _class **s_thing;
69 struct _symbol *s_next;
70} t_symbol;
71
72EXTERN_STRUCT _array;
73#define t_array struct _array /* g_canvas.h */
74
75/* pointers to glist and array elements go through a "stub" which sticks
76around after the glist or array is freed. The stub itself is deleted when
77both the glist/array is gone and the refcount is zero, ensuring that no
78gpointers are pointing here. */
79
80#define GP_NONE 0 /* the stub points nowhere (has been cut off) */
81#define GP_GLIST 1 /* the stub points to a glist element */
82#define GP_ARRAY 2 /* ... or array */
83
84typedef struct _gstub
85{
86 union
87 {
88 struct _glist *gs_glist; /* glist we're in */
89 struct _array *gs_array; /* array we're in */
90 } gs_un;
91 int gs_which; /* GP_GLIST/GP_ARRAY */
92 int gs_refcount; /* number of gpointers pointing here */
93} t_gstub;
94
95typedef struct _gpointer /* pointer to a gobj in a glist */
96{
97 union
98 {
99 struct _scalar *gp_scalar; /* scalar we're in (if glist) */
100 union word *gp_w; /* raw data (if array) */
101 } gp_un;
102 int gp_valid; /* number which must match gpointee */
103 t_gstub *gp_stub; /* stub which points to glist/array */
104} t_gpointer;
105
106typedef union word
107{
108 t_float w_float;
109 t_symbol *w_symbol;
110 t_gpointer *w_gpointer;
111 t_array *w_array;
112 struct _glist *w_list;
113 int w_index;
114} t_word;
115
116typedef enum
117{
118 A_NULL,
119 A_FLOAT,
120 A_SYMBOL,
121 A_POINTER,
122 A_SEMI,
123 A_COMMA,
124 A_DEFFLOAT,
125 A_DEFSYM,
126 A_DOLLAR,
127 A_DOLLSYM,
128 A_GIMME,
129 A_CANT
130} t_atomtype;
131
132#define A_DEFSYMBOL A_DEFSYM /* better name for this */
133
134typedef struct _atom
135{
136 t_atomtype a_type;
137 union word a_w;
138} t_atom;
139
140EXTERN_STRUCT _class;
141#define t_class struct _class
142
143EXTERN_STRUCT _outlet;
144#define t_outlet struct _outlet
145
146EXTERN_STRUCT _inlet;
147#define t_inlet struct _inlet
148
149EXTERN_STRUCT _binbuf;
150#define t_binbuf struct _binbuf
151
152EXTERN_STRUCT _clock;
153#define t_clock struct _clock
154
155EXTERN_STRUCT _outconnect;
156#define t_outconnect struct _outconnect
157
158EXTERN_STRUCT _glist;
159#define t_glist struct _glist
160#define t_canvas struct _glist /* LATER lose this */
161
162typedef t_class *t_pd; /* pure datum: nothing but a class pointer */
163
164typedef struct _gobj /* a graphical object */
165{
166 t_pd g_pd; /* pure datum header (class) */
167 struct _gobj *g_next; /* next in list */
168} t_gobj;
169
170typedef struct _scalar /* a graphical object holding data */
171{
172 t_gobj sc_gobj; /* header for graphical object */
173 t_symbol *sc_template; /* template name (LATER replace with pointer) */
174 t_word sc_vec[1]; /* indeterminate-length array of words */
175} t_scalar;
176
177typedef struct _text /* patchable object - graphical, with text */
178{
179 t_gobj te_g; /* header for graphical object */
180 t_binbuf *te_binbuf; /* holder for the text */
181 t_outlet *te_outlet; /* linked list of outlets */
182 t_inlet *te_inlet; /* linked list of inlets */
183 short te_xpix; /* x&y location (within the toplevel) */
184 short te_ypix;
185 short te_width; /* requested width in chars, 0 if auto */
186 unsigned int te_type:2; /* from defs below */
187} t_text;
188
189#define T_TEXT 0 /* just a textual comment */
190#define T_OBJECT 1 /* a MAX style patchable object */
191#define T_MESSAGE 2 /* a MAX stype message */
192#define T_ATOM 3 /* a cell to display a number or symbol */
193
194#define te_pd te_g.g_pd
195
196 /* t_object is synonym for t_text (LATER unify them) */
197
198typedef struct _text t_object;
199
200#define ob_outlet te_outlet
201#define ob_inlet te_inlet
202#define ob_binbuf te_binbuf
203#define ob_pd te_g.g_pd
204#define ob_g te_g
205
206typedef void (*t_method)(void);
207typedef void *(*t_newmethod)( void);
208typedef void (*t_gotfn)(void *x, ...);
209
210/* ---------------- pre-defined objects and symbols --------------*/
211EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */
212EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */
213EXTERN t_symbol s_pointer;
214EXTERN t_symbol s_float;
215EXTERN t_symbol s_symbol;
216EXTERN t_symbol s_bang;
217EXTERN t_symbol s_list;
218EXTERN t_symbol s_anything;
219EXTERN t_symbol s_signal;
220EXTERN t_symbol s__N;
221EXTERN t_symbol s__X;
222EXTERN t_symbol s_x;
223EXTERN t_symbol s_y;
224EXTERN t_symbol s_;
225
226/* --------- prototypes from the central message system ----------- */
227EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
228EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
229EXTERN t_symbol *gensym(char *s);
230EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
231EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
232EXTERN void nullfn(void);
233EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
234#define mess0(x, s) ((*getfn((x), (s)))((x)))
235#define mess1(x, s, a) ((*getfn((x), (s)))((x), (a)))
236#define mess2(x, s, a,b) ((*getfn((x), (s)))((x), (a),(b)))
237#define mess3(x, s, a,b,c) ((*getfn((x), (s)))((x), (a),(b),(c)))
238#define mess4(x, s, a,b,c,d) ((*getfn((x), (s)))((x), (a),(b),(c),(d)))
239#define mess5(x, s, a,b,c,d,e) ((*getfn((x), (s)))((x), (a),(b),(c),(d),(e)))
240EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
241EXTERN t_pd *pd_newest(void);
242
243/* --------------- memory management -------------------- */
244EXTERN void *getbytes(size_t nbytes);
245EXTERN void *getzbytes(size_t nbytes);
246EXTERN void *copybytes(void *src, size_t nbytes);
247EXTERN void freebytes(void *x, size_t nbytes);
248EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize);
249
250/* -------------------- atoms ----------------------------- */
251
252#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0)
253#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0)
254#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \
255 (atom)->a_w.w_gpointer = (gp))
256#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f))
257#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \
258 (atom)->a_w.w_symbol = (s))
259#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \
260 (atom)->a_w.w_index = (n))
261#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \
262 (atom)->a_w.w_symbol= (s))
263
264EXTERN t_float atom_getfloat(t_atom *a);
265EXTERN t_int atom_getint(t_atom *a);
266EXTERN t_symbol *atom_getsymbol(t_atom *a);
267EXTERN t_symbol *atom_gensym(t_atom *a);
268EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv);
269EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv);
270EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
271
272EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
273
274/* ------------------ binbufs --------------- */
275
276EXTERN t_binbuf *binbuf_new(void);
277EXTERN void binbuf_free(t_binbuf *x);
278EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y);
279
280EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
281EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
282EXTERN void binbuf_clear(t_binbuf *x);
283EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
284EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
285EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
286EXTERN void binbuf_addsemi(t_binbuf *x);
287EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
288EXTERN void binbuf_print(t_binbuf *x);
289EXTERN int binbuf_getnatom(t_binbuf *x);
290EXTERN t_atom *binbuf_getvec(t_binbuf *x);
291EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
292EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname,
293 int crflag);
294EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
295 int crflag);
296EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir,
297 int crflag);
298EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
299EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av,
300 int tonew);
301
302/* ------------------ clocks --------------- */
303
304typedef long long t_time;
305EXTERN t_clock *clock_new(void *owner, t_method fn);
306EXTERN void clock_set(t_clock *x, t_time systime);
307EXTERN void clock_delay(t_clock *x, t_time delaytime);
308EXTERN void clock_unset(t_clock *x);
309EXTERN t_time clock_getlogicaltime(void);
310EXTERN t_time clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
311EXTERN t_time clock_gettimesince(t_time prevsystime);
312EXTERN t_time clock_getsystimeafter(t_time delaytime);
313EXTERN void clock_free(t_clock *x);
314
315/* ----------------- pure data ---------------- */
316EXTERN t_pd *pd_new(t_class *cls);
317EXTERN void pd_free(t_pd *x);
318EXTERN void pd_bind(t_pd *x, t_symbol *s);
319EXTERN void pd_unbind(t_pd *x, t_symbol *s);
320EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
321EXTERN void pd_pushsym(t_pd *x);
322EXTERN void pd_popsym(t_pd *x);
323EXTERN t_symbol *pd_getfilename(void);
324EXTERN t_symbol *pd_getdirname(void);
325EXTERN void pd_bang(t_pd *x);
326EXTERN void pd_pointer(t_pd *x, t_gpointer *gp);
327EXTERN void pd_float(t_pd *x, t_float f);
328EXTERN void pd_symbol(t_pd *x, t_symbol *s);
329EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv);
330EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv);
331#define pd_class(x) (*(x))
332
333/* ----------------- pointers ---------------- */
334EXTERN void gpointer_init(t_gpointer *gp);
335EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
336EXTERN void gpointer_unset(t_gpointer *gp);
337EXTERN int gpointer_check(const t_gpointer *gp, int headok);
338
339/* ----------------- patchable "objects" -------------- */
340EXTERN_STRUCT _inlet;
341#define t_inlet struct _inlet
342EXTERN_STRUCT _outlet;
343#define t_outlet struct _outlet
344
345EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1,
346 t_symbol *s2);
347EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
348EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
349EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
350EXTERN void inlet_free(t_inlet *x);
351
352EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
353EXTERN void outlet_bang(t_outlet *x);
354EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp);
355EXTERN void outlet_float(t_outlet *x, t_float f);
356EXTERN void outlet_symbol(t_outlet *x, t_symbol *s);
357EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
358EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
359EXTERN t_symbol *outlet_getsymbol(t_outlet *x);
360EXTERN void outlet_free(t_outlet *x);
361EXTERN t_object *pd_checkobject(t_pd *x);
362
363
364/* -------------------- canvases -------------- */
365
366EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
367
368EXTERN void canvas_setargs(int argc, t_atom *argv);
369EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
370EXTERN t_symbol *canvas_getcurrentdir(void);
371EXTERN t_glist *canvas_getcurrent(void);
372EXTERN void canvas_makefilename(t_glist *c, char *file,
373 char *result,int resultsize);
374EXTERN t_symbol *canvas_getdir(t_glist *x);
375EXTERN int sys_fontwidth(int fontsize);
376EXTERN int sys_fontheight(int fontsize);
377EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
378
379/* ---------------- widget behaviors ---------------------- */
380
381EXTERN_STRUCT _widgetbehavior;
382#define t_widgetbehavior struct _widgetbehavior
383
384EXTERN_STRUCT _parentwidgetbehavior;
385#define t_parentwidgetbehavior struct _parentwidgetbehavior
386EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x);
387
388/* -------------------- classes -------------- */
389
390#define CLASS_DEFAULT 0 /* flags for new classes below */
391#define CLASS_PD 1
392#define CLASS_GOBJ 2
393#define CLASS_PATCHABLE 3
394#define CLASS_NOINLET 8
395
396#define CLASS_TYPEMASK 3
397
398
399EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod,
400 t_method freemethod, size_t size, int flags, t_atomtype arg1, ...);
401EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s,
402 t_atomtype type1, ...);
403EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
404 t_atomtype arg1, ...);
405EXTERN void class_addbang(t_class *c, t_method fn);
406EXTERN void class_addpointer(t_class *c, t_method fn);
407EXTERN void class_doaddfloat(t_class *c, t_method fn);
408EXTERN void class_addsymbol(t_class *c, t_method fn);
409EXTERN void class_addlist(t_class *c, t_method fn);
410EXTERN void class_addanything(t_class *c, t_method fn);
411EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
412EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w);
413EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w);
414EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c);
415EXTERN char *class_getname(t_class *c);
416EXTERN char *class_gethelpname(t_class *c);
417EXTERN void class_setdrawcommand(t_class *c);
418EXTERN int class_isdrawcommand(t_class *c);
419EXTERN void class_domainsignalin(t_class *c, int onset);
420#define CLASS_MAINSIGNALIN(c, type, field) \
421 class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
422
423 /* prototype for functions to save Pd's to a binbuf */
424typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
425EXTERN void class_setsavefn(t_class *c, t_savefn f);
426EXTERN t_savefn class_getsavefn(t_class *c);
427 /* prototype for functions to open properties dialogs */
428typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist);
429EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f);
430EXTERN t_propertiesfn class_getpropertiesfn(t_class *c);
431
432#ifndef PD_CLASS_DEF
433#define class_addbang(x, y) class_addbang((x), (t_method)(y))
434#define class_addpointer(x, y) class_addpointer((x), (t_method)(y))
435#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y))
436#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y))
437#define class_addlist(x, y) class_addlist((x), (t_method)(y))
438#define class_addanything(x, y) class_addanything((x), (t_method)(y))
439#endif
440
441/* ------------ printing --------------------------------- */
442EXTERN void post(char *fmt, ...);
443EXTERN void startpost(char *fmt, ...);
444EXTERN void poststring(char *s);
445EXTERN void postfloat(float f);
446EXTERN void postatom(int argc, t_atom *argv);
447EXTERN void endpost(void);
448EXTERN void error(char *fmt, ...);
449EXTERN void bug(char *fmt, ...);
450EXTERN void pd_error(void *object, char *fmt, ...);
451EXTERN void sys_logerror(char *object, char *s);
452EXTERN void sys_unixerror(char *object);
453EXTERN void sys_ouch(void);
454
455#ifdef __linux__
456EXTERN char* sys_get_path( void);
457#endif
458EXTERN void sys_addpath(const char* p);
459
460
461/* ------------ system interface routines ------------------- */
462EXTERN int sys_isreadablefile(const char *name);
463EXTERN void sys_bashfilename(const char *from, char *to);
464EXTERN void sys_unbashfilename(const char *from, char *to);
465EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
466 char *dirresult, char **nameresult, unsigned int size, int bin);
467EXTERN int sched_geteventno(void);
468EXTERN t_time sys_getrealtime(void);
469
470
471/* ------------ threading ------------------- */
472/* T.Grill - see m_sched.c */
473
474EXTERN void sys_lock(void);
475EXTERN void sys_unlock(void);
476EXTERN int sys_trylock(void);
477
478
479/* --------------- signals ----------------------------------- */
480
481#define MAXLOGSIG 32
482#define MAXSIGSIZE (1 << MAXLOGSIG)
483#ifndef FIXEDPOINT
484typedef float t_sample;
485#else
486#include "m_fixed.h"
487#endif
488
489
490typedef struct _signal
491{
492 int s_n; /* number of points in the array */
493 t_sample *s_vec; /* the array */
494 float s_sr; /* sample rate */
495 int s_refcount; /* number of times used */
496 int s_isborrowed; /* whether we're going to borrow our array */
497 struct _signal *s_borrowedfrom; /* signal to borrow it from */
498 struct _signal *s_nextfree; /* next in freelist */
499 struct _signal *s_nextused; /* next in used list */
500} t_signal;
501
502
503typedef t_int *(*t_perfroutine)(t_int *args);
504
505EXTERN t_int *plus_perform(t_int *args);
506EXTERN t_int *zero_perform(t_int *args);
507EXTERN t_int *copy_perform(t_int *args);
508
509EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
510EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
511EXTERN void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n);
512EXTERN void dsp_add_zero(t_sample *out, int n);
513
514EXTERN int sys_getblksize(void);
515EXTERN float sys_getsr(void);
516EXTERN int sys_get_inchannels(void);
517EXTERN int sys_get_outchannels(void);
518
519EXTERN void dsp_add(t_perfroutine f, int n, ...);
520EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
521EXTERN void pd_fft(float *buf, int npoints, int inverse);
522EXTERN int ilog2(int n);
523
524EXTERN void mayer_fht(t_sample *fz, int n);
525EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag);
526EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag);
527EXTERN void mayer_realfft(int n, t_sample *real);
528EXTERN void mayer_realifft(int n, t_sample *real);
529
530//EXTERN t_sample cos_table[];
531
532#define LOGCOSTABSIZE 9
533#define COSTABSIZE (1<<LOGCOSTABSIZE)
534
535EXTERN int canvas_suspend_dsp(void);
536EXTERN void canvas_resume_dsp(int oldstate);
537EXTERN void canvas_update_dsp(void);
538
539/* IOhannes { (up/downsampling) */
540typedef struct _resample
541{
542 int method; /* up/downsampling method ID */
543
544 t_int downsample; /* downsampling factor */
545 t_int upsample; /* upsampling factor */
546
547 t_sample *s_vec; /* here we hold the resampled data */
548 int s_n;
549
550 t_sample *coeffs; /* coefficients for filtering... */
551 int coefsize;
552
553 t_sample *buffer; /* buffer for filtering */
554 int bufsize;
555} t_resample;
556
557EXTERN void resample_init(t_resample *x);
558EXTERN void resample_free(t_resample *x);
559
560EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
561EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
562EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
563/* } IOhannes */
564
565/* ----------------------- utility functions for signals -------------- */
566EXTERN float mtof(float);
567EXTERN float ftom(float);
568EXTERN float rmstodb(float);
569EXTERN float powtodb(float);
570EXTERN float dbtorms(float);
571EXTERN float dbtopow(float);
572
573EXTERN float q8_sqrt(float);
574EXTERN float q8_rsqrt(float);
575#ifndef N32
576EXTERN float qsqrt(float); /* old names kept for extern compatibility */
577EXTERN float qrsqrt(float);
578#endif
579/* --------------------- data --------------------------------- */
580
581 /* graphical arrays */
582EXTERN_STRUCT _garray;
583#define t_garray struct _garray
584
585EXTERN t_class *garray_class;
586EXTERN int garray_getfloatarray(t_garray *x, int *size, t_sample **vec);
587EXTERN float garray_get(t_garray *x, t_symbol *s, t_int indx);
588EXTERN void garray_redraw(t_garray *x);
589EXTERN int garray_npoints(t_garray *x);
590EXTERN char *garray_vec(t_garray *x);
591EXTERN void garray_resize(t_garray *x, t_floatarg f);
592EXTERN void garray_usedindsp(t_garray *x);
593EXTERN void garray_setsaveit(t_garray *x, int saveit);
594EXTERN t_class *scalar_class;
595
596EXTERN t_float *value_get(t_symbol *s);
597EXTERN void value_release(t_symbol *s);
598EXTERN int value_getfloat(t_symbol *s, t_float *f);
599EXTERN int value_setfloat(t_symbol *s, t_float f);
600
601/* ------- GUI interface - functions to send strings to TK --------- */
602EXTERN void sys_vgui(char *fmt, ...);
603EXTERN void sys_gui(char *s);
604
605 /* dialog window creation and destruction */
606EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd);
607EXTERN void gfxstub_deleteforkey(void *key);
608
609extern t_class *glob_pdobject; /* object to send "pd" messages */
610
611/*------------- Max 0.26 compatibility --------------------*/
612
613/* the following reflects the new way classes are laid out, with the class
614 pointing to the messlist and not vice versa. Externs shouldn't feel it. */
615typedef t_class *t_externclass;
616
617EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine,
618 t_method freeroutine, t_symbol *name, size_t size, int tiny, \
619 t_atomtype arg1, ...);
620EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...);
621
622#define t_getbytes getbytes
623#define t_freebytes freebytes
624#define t_resizebytes resizebytes
625#define typedmess pd_typedmess
626#define vmess pd_vmess
627
628/* A definition to help gui objects straddle 0.34-0.35 changes. If this is
629defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
630
631#define PD_USE_TE_XPIX
632
633#if 0
634/* a test for NANs and denormals. Should only be necessary on i386. */
635#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
636 (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
637/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
638#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
639 (((*(unsigned int*)&(f))&0x60000000)==0x60000000))
640#else
641#define PD_BADFLOAT(f) 0
642#define PD_BIGORSMALL(f) 0
643#endif
644
645#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
646}
647#endif
648
649#define __m_pd_h_
650#endif /* __m_pd_h_ */
651/* Copyright (c) 1997-1999 Miller Puckette.
652* For information on usage and redistribution, and for a DISCLAIMER OF ALL
653* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
654
655#ifndef __m_pd_h_
656
657#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
658extern "C" {
659#endif
660
661#define PD_VERSION 0.37 /* oops, don't use this... */ */
662#define PD_MAJOR_VERSION 0 /* ... use these two instead. */
663#define PD_MINOR_VERSION 37
664
665/* old name for "MSW" flag -- we have to take it for the sake of many old
666"nmakefiles" for externs, which will define NT and not MSW */
667#if defined(NT) && !defined(MSW)
668#define MSW
669#endif
670
671#ifdef MSW
672// #pragma warning( disable : 4091 )
673#pragma warning( disable : 4305 ) /* uncast const double to float */
674#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */
675#pragma warning( disable : 4101 ) /* unused automatic variables */
676#endif /* MSW */
677
678 /* the external storage class is "extern" in UNIX; in MSW it's ugly. */
679#ifdef MSW
680#ifdef PD_INTERNAL
681#define EXTERN __declspec(dllexport) extern
682#else
683#define EXTERN __declspec(dllimport) extern
684#endif /* PD_INTERNAL */
685#else
686#define EXTERN extern
687#endif /* MSW */
688
689 /* and depending on the compiler, hidden data structures are
690 declared differently: */
691#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ )
692#define EXTERN_STRUCT struct
693#else
694#define EXTERN_STRUCT extern struct
695#endif
696
697
698#if !defined(_SIZE_T) && !defined(_SIZE_T_)
699#include <stddef.h> /* just for size_t -- how lame! */
700#endif
701
702#define MAXPDSTRING 1000 /* use this for anything you want */
703#define MAXPDARG 5 /* max number of args we can typecheck today */
704
705 /* signed and unsigned integer types the size of a pointer: */
706#ifdef __alpha__
707typedef long t_int;
708#else
709typedef int t_int;
710#endif
711
712typedef float t_float; /* a floating-point number at most the same size */
713typedef float t_floatarg; /* floating-point type for function calls */
714
715typedef struct _symbol
716{
717 char *s_name;
718 struct _class **s_thing;
719 struct _symbol *s_next;
720} t_symbol;
721
722EXTERN_STRUCT _array;
723#define t_array struct _array /* g_canvas.h */
724
725/* pointers to glist and array elements go through a "stub" which sticks
726around after the glist or array is freed. The stub itself is deleted when
727both the glist/array is gone and the refcount is zero, ensuring that no
728gpointers are pointing here. */
729
730#define GP_NONE 0 /* the stub points nowhere (has been cut off) */
731#define GP_GLIST 1 /* the stub points to a glist element */
732#define GP_ARRAY 2 /* ... or array */
733
734typedef struct _gstub
735{
736 union
737 {
738 struct _glist *gs_glist; /* glist we're in */
739 struct _array *gs_array; /* array we're in */
740 } gs_un;
741 int gs_which; /* GP_GLIST/GP_ARRAY */
742 int gs_refcount; /* number of gpointers pointing here */
743} t_gstub;
744
745typedef struct _gpointer /* pointer to a gobj in a glist */
746{
747 union
748 {
749 struct _scalar *gp_scalar; /* scalar we're in (if glist) */
750 union word *gp_w; /* raw data (if array) */
751 } gp_un;
752 int gp_valid; /* number which must match gpointee */
753 t_gstub *gp_stub; /* stub which points to glist/array */
754} t_gpointer;
755
756typedef union word
757{
758 t_float w_float;
759 t_symbol *w_symbol;
760 t_gpointer *w_gpointer;
761 t_array *w_array;
762 struct _glist *w_list;
763 int w_index;
764} t_word;
765
766typedef enum
767{
768 A_NULL,
769 A_FLOAT,
770 A_SYMBOL,
771 A_POINTER,
772 A_SEMI,
773 A_COMMA,
774 A_DEFFLOAT,
775 A_DEFSYM,
776 A_DOLLAR,
777 A_DOLLSYM,
778 A_GIMME,
779 A_CANT
780} t_atomtype;
781
782#define A_DEFSYMBOL A_DEFSYM /* better name for this */
783
784typedef struct _atom
785{
786 t_atomtype a_type;
787 union word a_w;
788} t_atom;
789
790EXTERN_STRUCT _class;
791#define t_class struct _class
792
793EXTERN_STRUCT _outlet;
794#define t_outlet struct _outlet
795
796EXTERN_STRUCT _inlet;
797#define t_inlet struct _inlet
798
799EXTERN_STRUCT _binbuf;
800#define t_binbuf struct _binbuf
801
802EXTERN_STRUCT _clock;
803#define t_clock struct _clock
804
805EXTERN_STRUCT _outconnect;
806#define t_outconnect struct _outconnect
807
808EXTERN_STRUCT _glist;
809#define t_glist struct _glist
810#define t_canvas struct _glist /* LATER lose this */
811
812typedef t_class *t_pd; /* pure datum: nothing but a class pointer */
813
814typedef struct _gobj /* a graphical object */
815{
816 t_pd g_pd; /* pure datum header (class) */
817 struct _gobj *g_next; /* next in list */
818} t_gobj;
819
820typedef struct _scalar /* a graphical object holding data */
821{
822 t_gobj sc_gobj; /* header for graphical object */
823 t_symbol *sc_template; /* template name (LATER replace with pointer) */
824 t_word sc_vec[1]; /* indeterminate-length array of words */
825} t_scalar;
826
827typedef struct _text /* patchable object - graphical, with text */
828{
829 t_gobj te_g; /* header for graphical object */
830 t_binbuf *te_binbuf; /* holder for the text */
831 t_outlet *te_outlet; /* linked list of outlets */
832 t_inlet *te_inlet; /* linked list of inlets */
833 short te_xpix; /* x&y location (within the toplevel) */
834 short te_ypix;
835 short te_width; /* requested width in chars, 0 if auto */
836 unsigned int te_type:2; /* from defs below */
837} t_text;
838
839#define T_TEXT 0 /* just a textual comment */
840#define T_OBJECT 1 /* a MAX style patchable object */
841#define T_MESSAGE 2 /* a MAX stype message */
842#define T_ATOM 3 /* a cell to display a number or symbol */
843
844#define te_pd te_g.g_pd
845
846 /* t_object is synonym for t_text (LATER unify them) */
847
848typedef struct _text t_object;
849
850#define ob_outlet te_outlet
851#define ob_inlet te_inlet
852#define ob_binbuf te_binbuf
853#define ob_pd te_g.g_pd
854#define ob_g te_g
855
856typedef void (*t_method)(void);
857typedef void *(*t_newmethod)( void);
858typedef void (*t_gotfn)(void *x, ...);
859
860/* ---------------- pre-defined objects and symbols --------------*/
861EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */
862EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */
863EXTERN t_symbol s_pointer;
864EXTERN t_symbol s_float;
865EXTERN t_symbol s_symbol;
866EXTERN t_symbol s_bang;
867EXTERN t_symbol s_list;
868EXTERN t_symbol s_anything;
869EXTERN t_symbol s_signal;
870EXTERN t_symbol s__N;
871EXTERN t_symbol s__X;
872EXTERN t_symbol s_x;
873EXTERN t_symbol s_y;
874EXTERN t_symbol s_;
875
876/* --------- prototypes from the central message system ----------- */
877EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
878EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
879EXTERN t_symbol *gensym(char *s);
880EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
881EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
882EXTERN void nullfn(void);
883EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
884#define mess0(x, s) ((*getfn((x), (s)))((x)))
885#define mess1(x, s, a) ((*getfn((x), (s)))((x), (a)))
886#define mess2(x, s, a,b) ((*getfn((x), (s)))((x), (a),(b)))
887#define mess3(x, s, a,b,c) ((*getfn((x), (s)))((x), (a),(b),(c)))
888#define mess4(x, s, a,b,c,d) ((*getfn((x), (s)))((x), (a),(b),(c),(d)))
889#define mess5(x, s, a,b,c,d,e) ((*getfn((x), (s)))((x), (a),(b),(c),(d),(e)))
890EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
891EXTERN t_pd *pd_newest(void);
892
893/* --------------- memory management -------------------- */
894EXTERN void *getbytes(size_t nbytes);
895EXTERN void *getzbytes(size_t nbytes);
896EXTERN void *copybytes(void *src, size_t nbytes);
897EXTERN void freebytes(void *x, size_t nbytes);
898EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize);
899
900/* -------------------- atoms ----------------------------- */
901
902#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0)
903#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0)
904#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \
905 (atom)->a_w.w_gpointer = (gp))
906#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f))
907#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \
908 (atom)->a_w.w_symbol = (s))
909#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \
910 (atom)->a_w.w_index = (n))
911#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \
912 (atom)->a_w.w_symbol= (s))
913
914EXTERN t_float atom_getfloat(t_atom *a);
915EXTERN t_int atom_getint(t_atom *a);
916EXTERN t_symbol *atom_getsymbol(t_atom *a);
917EXTERN t_symbol *atom_gensym(t_atom *a);
918EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv);
919EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv);
920EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
921
922EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
923
924/* ------------------ binbufs --------------- */
925
926EXTERN t_binbuf *binbuf_new(void);
927EXTERN void binbuf_free(t_binbuf *x);
928EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y);
929
930EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
931EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
932EXTERN void binbuf_clear(t_binbuf *x);
933EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
934EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
935EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
936EXTERN void binbuf_addsemi(t_binbuf *x);
937EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
938EXTERN void binbuf_print(t_binbuf *x);
939EXTERN int binbuf_getnatom(t_binbuf *x);
940EXTERN t_atom *binbuf_getvec(t_binbuf *x);
941EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
942EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname,
943 int crflag);
944EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
945 int crflag);
946EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir,
947 int crflag);
948EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
949EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av,
950 int tonew);
951
952/* ------------------ clocks --------------- */
953
954typedef long long t_time;
955EXTERN t_clock *clock_new(void *owner, t_method fn);
956EXTERN void clock_set(t_clock *x, t_time systime);
957EXTERN void clock_delay(t_clock *x, t_time delaytime);
958EXTERN void clock_unset(t_clock *x);
959EXTERN t_time clock_getlogicaltime(void);
960EXTERN t_time clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
961EXTERN t_time clock_gettimesince(t_time prevsystime);
962EXTERN t_time clock_getsystimeafter(t_time delaytime);
963EXTERN void clock_free(t_clock *x);
964
965/* ----------------- pure data ---------------- */
966EXTERN t_pd *pd_new(t_class *cls);
967EXTERN void pd_free(t_pd *x);
968EXTERN void pd_bind(t_pd *x, t_symbol *s);
969EXTERN void pd_unbind(t_pd *x, t_symbol *s);
970EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
971EXTERN void pd_pushsym(t_pd *x);
972EXTERN void pd_popsym(t_pd *x);
973EXTERN t_symbol *pd_getfilename(void);
974EXTERN t_symbol *pd_getdirname(void);
975EXTERN void pd_bang(t_pd *x);
976EXTERN void pd_pointer(t_pd *x, t_gpointer *gp);
977EXTERN void pd_float(t_pd *x, t_float f);
978EXTERN void pd_symbol(t_pd *x, t_symbol *s);
979EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv);
980EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv);
981#define pd_class(x) (*(x))
982
983/* ----------------- pointers ---------------- */
984EXTERN void gpointer_init(t_gpointer *gp);
985EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
986EXTERN void gpointer_unset(t_gpointer *gp);
987EXTERN int gpointer_check(const t_gpointer *gp, int headok);
988
989/* ----------------- patchable "objects" -------------- */
990EXTERN_STRUCT _inlet;
991#define t_inlet struct _inlet
992EXTERN_STRUCT _outlet;
993#define t_outlet struct _outlet
994
995EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1,
996 t_symbol *s2);
997EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
998EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
999EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
1000EXTERN void inlet_free(t_inlet *x);
1001
1002EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
1003EXTERN void outlet_bang(t_outlet *x);
1004EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp);
1005EXTERN void outlet_float(t_outlet *x, t_float f);
1006EXTERN void outlet_symbol(t_outlet *x, t_symbol *s);
1007EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
1008EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
1009EXTERN t_symbol *outlet_getsymbol(t_outlet *x);
1010EXTERN void outlet_free(t_outlet *x);
1011EXTERN t_object *pd_checkobject(t_pd *x);
1012
1013
1014/* -------------------- canvases -------------- */
1015
1016EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
1017
1018EXTERN void canvas_setargs(int argc, t_atom *argv);
1019EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
1020EXTERN t_symbol *canvas_getcurrentdir(void);
1021EXTERN t_glist *canvas_getcurrent(void);
1022EXTERN void canvas_makefilename(t_glist *c, char *file,
1023 char *result,int resultsize);
1024EXTERN t_symbol *canvas_getdir(t_glist *x);
1025EXTERN int sys_fontwidth(int fontsize);
1026EXTERN int sys_fontheight(int fontsize);
1027EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
1028
1029/* ---------------- widget behaviors ---------------------- */
1030
1031EXTERN_STRUCT _widgetbehavior;
1032#define t_widgetbehavior struct _widgetbehavior
1033
1034EXTERN_STRUCT _parentwidgetbehavior;
1035#define t_parentwidgetbehavior struct _parentwidgetbehavior
1036EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x);
1037
1038/* -------------------- classes -------------- */
1039
1040#define CLASS_DEFAULT 0 /* flags for new classes below */
1041#define CLASS_PD 1
1042#define CLASS_GOBJ 2
1043#define CLASS_PATCHABLE 3
1044#define CLASS_NOINLET 8
1045
1046#define CLASS_TYPEMASK 3
1047
1048
1049EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod,
1050 t_method freemethod, size_t size, int flags, t_atomtype arg1, ...);
1051EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s,
1052 t_atomtype type1, ...);
1053EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
1054 t_atomtype arg1, ...);
1055EXTERN void class_addbang(t_class *c, t_method fn);
1056EXTERN void class_addpointer(t_class *c, t_method fn);
1057EXTERN void class_doaddfloat(t_class *c, t_method fn);
1058EXTERN void class_addsymbol(t_class *c, t_method fn);
1059EXTERN void class_addlist(t_class *c, t_method fn);
1060EXTERN void class_addanything(t_class *c, t_method fn);
1061EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
1062EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w);
1063EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w);
1064EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c);
1065EXTERN char *class_getname(t_class *c);
1066EXTERN char *class_gethelpname(t_class *c);
1067EXTERN void class_setdrawcommand(t_class *c);
1068EXTERN int class_isdrawcommand(t_class *c);
1069EXTERN void class_domainsignalin(t_class *c, int onset);
1070#define CLASS_MAINSIGNALIN(c, type, field) \
1071 class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
1072
1073 /* prototype for functions to save Pd's to a binbuf */
1074typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
1075EXTERN void class_setsavefn(t_class *c, t_savefn f);
1076EXTERN t_savefn class_getsavefn(t_class *c);
1077 /* prototype for functions to open properties dialogs */
1078typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist);
1079EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f);
1080EXTERN t_propertiesfn class_getpropertiesfn(t_class *c);
1081
1082#ifndef PD_CLASS_DEF
1083#define class_addbang(x, y) class_addbang((x), (t_method)(y))
1084#define class_addpointer(x, y) class_addpointer((x), (t_method)(y))
1085#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y))
1086#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y))
1087#define class_addlist(x, y) class_addlist((x), (t_method)(y))
1088#define class_addanything(x, y) class_addanything((x), (t_method)(y))
1089#endif
1090
1091/* ------------ printing --------------------------------- */
1092EXTERN void post(char *fmt, ...);
1093EXTERN void startpost(char *fmt, ...);
1094EXTERN void poststring(char *s);
1095EXTERN void postfloat(float f);
1096EXTERN void postatom(int argc, t_atom *argv);
1097EXTERN void endpost(void);
1098EXTERN void error(char *fmt, ...);
1099EXTERN void bug(char *fmt, ...);
1100EXTERN void pd_error(void *object, char *fmt, ...);
1101EXTERN void sys_logerror(char *object, char *s);
1102EXTERN void sys_unixerror(char *object);
1103EXTERN void sys_ouch(void);
1104
1105#ifdef __linux__
1106EXTERN char* sys_get_path( void);
1107#endif
1108EXTERN void sys_addpath(const char* p);
1109
1110
1111/* ------------ system interface routines ------------------- */
1112EXTERN int sys_isreadablefile(const char *name);
1113EXTERN void sys_bashfilename(const char *from, char *to);
1114EXTERN void sys_unbashfilename(const char *from, char *to);
1115EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
1116 char *dirresult, char **nameresult, unsigned int size, int bin);
1117EXTERN int sched_geteventno(void);
1118EXTERN t_time sys_getrealtime(void);
1119
1120
1121/* ------------ threading ------------------- */
1122/* T.Grill - see m_sched.c */
1123
1124EXTERN void sys_lock(void);
1125EXTERN void sys_unlock(void);
1126EXTERN int sys_trylock(void);
1127
1128
1129/* --------------- signals ----------------------------------- */
1130
1131#define MAXLOGSIG 32
1132#define MAXSIGSIZE (1 << MAXLOGSIG)
1133#ifndef FIXEDPOINT
1134typedef float t_sample;
1135#else
1136#include "m_fixed.h"
1137#endif
1138
1139
1140typedef struct _signal
1141{
1142 int s_n; /* number of points in the array */
1143 t_sample *s_vec; /* the array */
1144 float s_sr; /* sample rate */
1145 int s_refcount; /* number of times used */
1146 int s_isborrowed; /* whether we're going to borrow our array */
1147 struct _signal *s_borrowedfrom; /* signal to borrow it from */
1148 struct _signal *s_nextfree; /* next in freelist */
1149 struct _signal *s_nextused; /* next in used list */
1150} t_signal;
1151
1152
1153typedef t_int *(*t_perfroutine)(t_int *args);
1154
1155EXTERN t_int *plus_perform(t_int *args);
1156EXTERN t_int *zero_perform(t_int *args);
1157EXTERN t_int *copy_perform(t_int *args);
1158
1159EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
1160EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
1161EXTERN void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n);
1162EXTERN void dsp_add_zero(t_sample *out, int n);
1163
1164EXTERN int sys_getblksize(void);
1165EXTERN float sys_getsr(void);
1166EXTERN int sys_get_inchannels(void);
1167EXTERN int sys_get_outchannels(void);
1168
1169EXTERN void dsp_add(t_perfroutine f, int n, ...);
1170EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
1171EXTERN void pd_fft(float *buf, int npoints, int inverse);
1172EXTERN int ilog2(int n);
1173
1174EXTERN void mayer_fht(t_sample *fz, int n);
1175EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag);
1176EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag);
1177EXTERN void mayer_realfft(int n, t_sample *real);
1178EXTERN void mayer_realifft(int n, t_sample *real);
1179
1180//EXTERN t_sample cos_table[];
1181
1182#define LOGCOSTABSIZE 9
1183#define COSTABSIZE (1<<LOGCOSTABSIZE)
1184
1185EXTERN int canvas_suspend_dsp(void);
1186EXTERN void canvas_resume_dsp(int oldstate);
1187EXTERN void canvas_update_dsp(void);
1188
1189/* IOhannes { (up/downsampling) */
1190typedef struct _resample
1191{
1192 int method; /* up/downsampling method ID */
1193
1194 t_int downsample; /* downsampling factor */
1195 t_int upsample; /* upsampling factor */
1196
1197 t_sample *s_vec; /* here we hold the resampled data */
1198 int s_n;
1199
1200 t_sample *coeffs; /* coefficients for filtering... */
1201 int coefsize;
1202
1203 t_sample *buffer; /* buffer for filtering */
1204 int bufsize;
1205} t_resample;
1206
1207EXTERN void resample_init(t_resample *x);
1208EXTERN void resample_free(t_resample *x);
1209
1210EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
1211EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
1212EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
1213/* } IOhannes */
1214
1215/* ----------------------- utility functions for signals -------------- */
1216EXTERN float mtof(float);
1217EXTERN float ftom(float);
1218EXTERN float rmstodb(float);
1219EXTERN float powtodb(float);
1220EXTERN float dbtorms(float);
1221EXTERN float dbtopow(float);
1222
1223EXTERN float q8_sqrt(float);
1224EXTERN float q8_rsqrt(float);
1225#ifndef N32
1226EXTERN float qsqrt(float); /* old names kept for extern compatibility */
1227EXTERN float qrsqrt(float);
1228#endif
1229/* --------------------- data --------------------------------- */
1230
1231 /* graphical arrays */
1232EXTERN_STRUCT _garray;
1233#define t_garray struct _garray
1234
1235EXTERN t_class *garray_class;
1236EXTERN int garray_getfloatarray(t_garray *x, int *size, t_sample **vec);
1237EXTERN float garray_get(t_garray *x, t_symbol *s, t_int indx);
1238EXTERN void garray_redraw(t_garray *x);
1239EXTERN int garray_npoints(t_garray *x);
1240EXTERN char *garray_vec(t_garray *x);
1241EXTERN void garray_resize(t_garray *x, t_floatarg f);
1242EXTERN void garray_usedindsp(t_garray *x);
1243EXTERN void garray_setsaveit(t_garray *x, int saveit);
1244EXTERN t_class *scalar_class;
1245
1246EXTERN t_float *value_get(t_symbol *s);
1247EXTERN void value_release(t_symbol *s);
1248EXTERN int value_getfloat(t_symbol *s, t_float *f);
1249EXTERN int value_setfloat(t_symbol *s, t_float f);
1250
1251/* ------- GUI interface - functions to send strings to TK --------- */
1252EXTERN void sys_vgui(char *fmt, ...);
1253EXTERN void sys_gui(char *s);
1254
1255 /* dialog window creation and destruction */
1256EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd);
1257EXTERN void gfxstub_deleteforkey(void *key);
1258
1259extern t_class *glob_pdobject; /* object to send "pd" messages */
1260
1261/*------------- Max 0.26 compatibility --------------------*/
1262
1263/* the following reflects the new way classes are laid out, with the class
1264 pointing to the messlist and not vice versa. Externs shouldn't feel it. */
1265typedef t_class *t_externclass;
1266
1267EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine,
1268 t_method freeroutine, t_symbol *name, size_t size, int tiny, \
1269 t_atomtype arg1, ...);
1270EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...);
1271
1272#define t_getbytes getbytes
1273#define t_freebytes freebytes
1274#define t_resizebytes resizebytes
1275#define typedmess pd_typedmess
1276#define vmess pd_vmess
1277
1278/* A definition to help gui objects straddle 0.34-0.35 changes. If this is
1279defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
1280
1281#define PD_USE_TE_XPIX
1282
1283#if 0
1284/* a test for NANs and denormals. Should only be necessary on i386. */
1285#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
1286 (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
1287/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
1288#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
1289 (((*(unsigned int*)&(f))&0x60000000)==0x60000000))
1290#else
1291#define PD_BADFLOAT(f) 0
1292#define PD_BIGORSMALL(f) 0
1293#endif
1294
1295#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
1296}
1297#endif
1298
1299#define __m_pd_h_
1300#endif /* __m_pd_h_ */
diff --git a/apps/plugins/pdbox/PDa/src/m_sched.c b/apps/plugins/pdbox/PDa/src/m_sched.c
new file mode 100644
index 0000000000..f40f0ff270
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_sched.c
@@ -0,0 +1,1162 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* scheduling stuff */
6
7#include "m_pd.h"
8#include "m_imp.h"
9#include "s_stuff.h"
10
11 /* LATER consider making this variable. It's now the LCM of all sample
12 rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
13#define TIMEUNITPERSEC (32.*441000.)
14
15
16/* T.Grill - enable PD global thread locking - sys_lock, sys_unlock, sys_trylock functions */
17#define THREAD_LOCKING
18#include "pthread.h"
19
20
21static int sys_quit;
22static t_time sys_time;
23static t_time sys_time_per_msec = TIMEUNITPERSEC / 1000.;
24
25int sys_schedblocksize = DEFDACBLKSIZE;
26int sys_usecsincelastsleep(void);
27int sys_sleepgrain;
28
29typedef void (*t_clockmethod)(void *client);
30
31struct _clock
32{
33 t_time c_settime;
34 void *c_owner;
35 t_clockmethod c_fn;
36 struct _clock *c_next;
37};
38
39t_clock *clock_setlist;
40
41#ifdef UNIX
42#include <unistd.h>
43#endif
44
45t_clock *clock_new(void *owner, t_method fn)
46{
47 t_clock *x = (t_clock *)getbytes(sizeof *x);
48 x->c_settime = -1;
49 x->c_owner = owner;
50 x->c_fn = (t_clockmethod)fn;
51 x->c_next = 0;
52 return (x);
53}
54
55void clock_unset(t_clock *x)
56{
57 if (x->c_settime >= 0)
58 {
59 if (x == clock_setlist) clock_setlist = x->c_next;
60 else
61 {
62 t_clock *x2 = clock_setlist;
63 while (x2->c_next != x) x2 = x2->c_next;
64 x2->c_next = x->c_next;
65 }
66 x->c_settime = -1;
67 }
68}
69
70 /* set the clock to call back at an absolute system time */
71void clock_set(t_clock *x, t_time setticks)
72{
73 if (setticks < sys_time) setticks = sys_time;
74 clock_unset(x);
75 x->c_settime = setticks;
76 if (clock_setlist && clock_setlist->c_settime <= setticks)
77 {
78 t_clock *cbefore, *cafter;
79 for (cbefore = clock_setlist, cafter = clock_setlist->c_next;
80 cbefore; cbefore = cafter, cafter = cbefore->c_next)
81 {
82 if (!cafter || cafter->c_settime > setticks)
83 {
84 cbefore->c_next = x;
85 x->c_next = cafter;
86 return;
87 }
88 }
89 }
90 else x->c_next = clock_setlist, clock_setlist = x;
91}
92
93 /* set the clock to call back after a delay in msec */
94void clock_delay(t_clock *x, t_time delaytime)
95{
96 clock_set(x, sys_time + sys_time_per_msec * delaytime);
97}
98
99 /* get current logical time. We don't specify what units this is in;
100 use clock_gettimesince() to measure intervals from time of this call.
101 This was previously, incorrectly named "clock_getsystime"; the old
102 name is aliased to the new one in m_pd.h. */
103t_time clock_getlogicaltime( void)
104{
105 return (sys_time);
106}
107 /* OBSOLETE NAME */
108t_time clock_getsystime( void) { return (sys_time); }
109
110 /* elapsed time in milliseconds since the given system time */
111t_time clock_gettimesince(t_time prevsystime)
112{
113 return ((sys_time - prevsystime)/sys_time_per_msec);
114}
115
116 /* what value the system clock will have after a delay */
117t_time clock_getsystimeafter(t_time delaytime)
118{
119 return (sys_time + sys_time_per_msec * delaytime);
120}
121
122void clock_free(t_clock *x)
123{
124 clock_unset(x);
125 freebytes(x, sizeof *x);
126}
127
128
129/* the following routines maintain a real-execution-time histogram of the
130various phases of real-time execution. */
131
132static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000};
133#define NBIN (sizeof(sys_bin)/sizeof(*sys_bin))
134#define NHIST 10
135static int sys_histogram[NHIST][NBIN];
136static t_time sys_histtime;
137static int sched_diddsp, sched_didpoll, sched_didnothing;
138
139static void sys_clearhist( void)
140{
141 unsigned int i, j;
142 for (i = 0; i < NHIST; i++)
143 for (j = 0; j < NBIN; j++) sys_histogram[i][j] = 0;
144 sys_histtime = sys_getrealtime();
145 sched_diddsp = sched_didpoll = sched_didnothing = 0;
146}
147
148void sys_printhist( void)
149{
150 unsigned int i, j;
151 for (i = 0; i < NHIST; i++)
152 {
153 int doit = 0;
154 for (j = 0; j < NBIN; j++) if (sys_histogram[i][j]) doit = 1;
155 if (doit)
156 {
157 post("%2d %8d %8d %8d %8d %8d %8d %8d %8d", i,
158 sys_histogram[i][0],
159 sys_histogram[i][1],
160 sys_histogram[i][2],
161 sys_histogram[i][3],
162 sys_histogram[i][4],
163 sys_histogram[i][5],
164 sys_histogram[i][6],
165 sys_histogram[i][7]);
166 }
167 }
168 post("dsp %d, pollgui %d, nothing %d",
169 sched_diddsp, sched_didpoll, sched_didnothing);
170}
171
172static int sys_histphase;
173
174int sys_addhist(int phase)
175{
176#ifndef FIXEDPOINT
177 int i, j, phasewas = sys_histphase;
178 t_time newtime = sys_getrealtime();
179 int msec = (newtime - sys_histtime) * 1000.;
180 for (j = NBIN-1; j >= 0; j--)
181 {
182 if (msec >= sys_bin[j])
183 {
184 sys_histogram[phasewas][j]++;
185 break;
186 }
187 }
188 sys_histtime = newtime;
189 sys_histphase = phase;
190 return (phasewas);
191#else
192 return 0;
193#endif
194}
195
196#define NRESYNC 20
197
198typedef struct _resync
199{
200 int r_ntick;
201 int r_error;
202} t_resync;
203
204static int oss_resyncphase = 0;
205static int oss_nresync = 0;
206static t_resync oss_resync[NRESYNC];
207
208
209static char *(oss_errornames[]) = {
210"unknown",
211"ADC blocked",
212"DAC blocked",
213"A/D/A sync",
214"data late"
215};
216
217void glob_audiostatus(void)
218{
219 int dev, nresync, nresyncphase, i;
220 nresync = (oss_nresync >= NRESYNC ? NRESYNC : oss_nresync);
221 nresyncphase = oss_resyncphase - 1;
222 post("audio I/O error history:");
223 post("seconds ago\terror type");
224 for (i = 0; i < nresync; i++)
225 {
226 int errtype;
227 if (nresyncphase < 0)
228 nresyncphase += NRESYNC;
229 errtype = oss_resync[nresyncphase].r_error;
230 if (errtype < 0 || errtype > 4)
231 errtype = 0;
232
233 post("%9.2f\t%s",
234 (sched_diddsp - oss_resync[nresyncphase].r_ntick)
235 * ((double)sys_schedblocksize) / sys_dacsr,
236 oss_errornames[errtype]);
237 nresyncphase--;
238 }
239}
240
241static int sched_diored;
242static int sched_dioredtime;
243static int sched_meterson;
244
245void sys_log_error(int type)
246{
247 oss_resync[oss_resyncphase].r_ntick = sched_diddsp;
248 oss_resync[oss_resyncphase].r_error = type;
249 oss_nresync++;
250 if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0;
251 if (type != ERR_NOTHING && !sched_diored &&
252 (sched_diddsp >= sched_dioredtime))
253 {
254 sys_vgui("pdtk_pd_dio 1\n");
255 sched_diored = 1;
256 }
257 sched_dioredtime =
258 sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
259}
260
261static int sched_lastinclip, sched_lastoutclip,
262 sched_lastindb, sched_lastoutdb;
263
264void glob_ping(t_pd *dummy);
265
266static void sched_pollformeters( void)
267{
268 int inclip, outclip, indb, outdb;
269 static int sched_nextmeterpolltime, sched_nextpingtime;
270
271 /* if there's no GUI but we're running in "realtime", here is
272 where we arrange to ping the watchdog every 2 seconds. */
273#ifdef __linux__
274 if (sys_nogui && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0))
275 {
276 glob_ping(0);
277 /* ping every 2 seconds */
278 sched_nextpingtime = sched_diddsp +
279 (2* sys_dacsr) /(int)sys_schedblocksize;
280 }
281#endif
282
283 if (sched_diddsp - sched_nextmeterpolltime < 0)
284 return;
285 if (sched_diored && (sched_diddsp - sched_dioredtime > 0))
286 {
287 sys_vgui("pdtk_pd_dio 0\n");
288 sched_diored = 0;
289 }
290 if (sched_meterson)
291 {
292 float inmax, outmax;
293 sys_getmeters(&inmax, &outmax);
294 indb = 0.5 + rmstodb(inmax);
295 outdb = 0.5 + rmstodb(outmax);
296 inclip = (inmax > 0.999);
297 outclip = (outmax >= 1.0);
298 }
299 else
300 {
301 indb = outdb = 0;
302 inclip = outclip = 0;
303 }
304 if (inclip != sched_lastinclip || outclip != sched_lastoutclip
305 || indb != sched_lastindb || outdb != sched_lastoutdb)
306 {
307 sys_vgui("pdtk_pd_meters %d %d %d %d\n", indb, outdb, inclip, outclip);
308 sched_lastinclip = inclip;
309 sched_lastoutclip = outclip;
310 sched_lastindb = indb;
311 sched_lastoutdb = outdb;
312 }
313 sched_nextmeterpolltime =
314 sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
315}
316
317void glob_meters(void *dummy, float f)
318{
319 if (f == 0)
320 sys_getmeters(0, 0);
321 sched_meterson = (f != 0);
322 sched_lastinclip = sched_lastoutclip = sched_lastindb = sched_lastoutdb =
323 -1;
324}
325
326#if 0
327void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
328{
329 if (argc) sys_clearhist();
330 else sys_printhist();
331}
332#endif
333
334void dsp_tick(void);
335
336static int sched_usedacs = 1;
337static t_time sched_referencerealtime, sched_referencelogicaltime;
338static t_time sys_time_per_dsp_tick;
339
340void sched_set_using_dacs(int flag)
341{
342 sched_usedacs = flag;
343 if (!flag)
344 {
345 sched_referencerealtime = sys_getrealtime();
346 sched_referencelogicaltime = clock_getlogicaltime();
347 post("schedsetuding");
348 }
349 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
350 ((double)sys_schedblocksize) / sys_dacsr;
351}
352
353 /* take the scheduler forward one DSP tick, also handling clock timeouts */
354static void sched_tick(t_time next_sys_time)
355{
356 int countdown = 5000;
357 while (clock_setlist && clock_setlist->c_settime < next_sys_time)
358 {
359 t_clock *c = clock_setlist;
360 sys_time = c->c_settime;
361 clock_unset(clock_setlist);
362 outlet_setstacklim();
363 (*c->c_fn)(c->c_owner);
364 if (!countdown--)
365 {
366 countdown = 5000;
367 sys_pollgui();
368 }
369 if (sys_quit)
370 return;
371 }
372 sys_time = next_sys_time;
373 dsp_tick();
374 sched_diddsp++;
375}
376
377/*
378Here is Pd's "main loop." This routine dispatches clock timeouts and DSP
379"ticks" deterministically, and polls for input from MIDI and the GUI. If
380we're left idle we also poll for graphics updates; but these are considered
381lower priority than the rest.
382
383The time source is normally the audio I/O subsystem via the "sys_send_dacs()"
384call. This call returns true if samples were transferred; false means that
385the audio I/O system is still busy with previous transfers.
386*/
387
388void sys_pollmidiqueue( void);
389void sys_initmidiqueue( void);
390
391int m_scheduler_pda( void)
392{
393 int idlecount = 0;
394 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
395 ((double)sys_schedblocksize) / sys_dacsr;
396
397
398 sys_clearhist();
399 if (sys_sleepgrain < 1000)
400 sys_sleepgrain = sys_schedadvance/4;
401 if (sys_sleepgrain < 100)
402 sys_sleepgrain = 100;
403 else if (sys_sleepgrain > 5000)
404 sys_sleepgrain = 5000;
405 sys_initmidiqueue();
406 while (!sys_quit)
407 {
408 int didsomething = 0;
409 int timeforward;
410
411 sys_addhist(0);
412 waitfortick:
413 if (sched_usedacs)
414 {
415 timeforward = sys_send_dacs();
416 sys_pollgui();
417 }
418 else {
419 if ((sys_getrealtime() - sched_referencerealtime)
420 > (t_time)clock_gettimesince(sched_referencelogicaltime)*1000)
421 timeforward = SENDDACS_YES;
422 else timeforward = SENDDACS_NO;
423 if (timeforward == SENDDACS_YES)
424 sys_microsleep(sys_sleepgrain);
425 }
426 if (timeforward != SENDDACS_NO) {
427 sched_tick(sys_time + sys_time_per_dsp_tick);
428 }
429 }
430 return 0;
431}
432
433
434int m_scheduler( void)
435{
436 int idlecount = 0;
437 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
438 ((double)sys_schedblocksize) / sys_dacsr;
439
440#ifdef THREAD_LOCKING
441 /* T.Grill - lock mutex */
442 sys_lock();
443#endif
444
445 sys_clearhist();
446 if (sys_sleepgrain < 1000)
447 sys_sleepgrain = sys_schedadvance/4;
448 if (sys_sleepgrain < 100)
449 sys_sleepgrain = 100;
450 else if (sys_sleepgrain > 5000)
451 sys_sleepgrain = 5000;
452 sys_initmidiqueue();
453 while (!sys_quit)
454 {
455 int didsomething = 0;
456 int timeforward;
457
458 sys_addhist(0);
459 waitfortick:
460 if (sched_usedacs)
461 {
462 timeforward = sys_send_dacs();
463
464 /* if dacs remain "idle" for 1 sec, they're hung up. */
465 if (timeforward != 0)
466 idlecount = 0;
467 else
468 {
469 idlecount++;
470 if (!(idlecount & 31))
471 {
472 static t_time idletime;
473 /* on 32nd idle, start a clock watch; every
474 32 ensuing idles, check it */
475 if (idlecount == 32)
476 idletime = sys_getrealtime();
477 else if (sys_getrealtime() - idletime > 1.)
478 {
479 post("audio I/O stuck... closing audio\n");
480 sys_close_audio();
481 sched_set_using_dacs(0);
482 goto waitfortick;
483 }
484 }
485 }
486 }
487 else
488 {
489 if (1000. * (sys_getrealtime() - sched_referencerealtime)
490 > clock_gettimesince(sched_referencelogicaltime))
491 timeforward = SENDDACS_YES;
492 else timeforward = SENDDACS_NO;
493 }
494 sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
495 sys_addhist(1);
496 if (timeforward != SENDDACS_NO)
497 sched_tick(sys_time + sys_time_per_dsp_tick);
498 if (timeforward == SENDDACS_YES)
499 didsomething = 1;
500
501 sys_addhist(2);
502 // sys_pollmidiqueue();
503 if (sys_pollgui())
504 {
505 if (!didsomething)
506 sched_didpoll++;
507 didsomething = 1;
508 }
509 sys_addhist(3);
510 /* test for idle; if so, do graphics updates. */
511 if (!didsomething)
512 {
513 sched_pollformeters();
514 sys_reportidle();
515
516#ifdef THREAD_LOCKING
517 /* T.Grill - enter idle phase -> unlock thread lock */
518 sys_unlock();
519#endif
520 if (timeforward != SENDDACS_SLEPT)
521 sys_microsleep(sys_sleepgrain);
522#ifdef THREAD_LOCKING
523 /* T.Grill - leave idle phase -> lock thread lock */
524 sys_lock();
525#endif
526
527 sys_addhist(5);
528 sched_didnothing++;
529
530 }
531 }
532
533#ifdef THREAD_LOCKING
534 /* T.Grill - done */
535 sys_unlock();
536#endif
537
538 return (0);
539}
540
541
542/* ------------ thread locking ------------------- */
543/* added by Thomas Grill */
544
545#ifdef THREAD_LOCKING
546static pthread_mutex_t sys_mutex = PTHREAD_MUTEX_INITIALIZER;
547
548void sys_lock(void)
549{
550 pthread_mutex_lock(&sys_mutex);
551}
552
553void sys_unlock(void)
554{
555 pthread_mutex_unlock(&sys_mutex);
556}
557
558int sys_trylock(void)
559{
560 return pthread_mutex_trylock(&sys_mutex);
561}
562
563#else
564
565void sys_lock(void) {}
566void sys_unlock(void) {}
567int sys_trylock(void) {}
568
569#endif
570
571
572/* ------------ soft quit ------------------- */
573/* added by Thomas Grill -
574 just set the quit flag for the scheduler loop
575 this is useful for applications using the PD shared library to signal the scheduler to terminate
576*/
577
578void sys_exit(void)
579{
580 sys_quit = 1;
581}
582/* Copyright (c) 1997-1999 Miller Puckette.
583* For information on usage and redistribution, and for a DISCLAIMER OF ALL
584* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
585
586/* scheduling stuff */
587
588#include "m_pd.h"
589#include "m_imp.h"
590#include "s_stuff.h"
591
592 /* LATER consider making this variable. It's now the LCM of all sample
593 rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
594#define TIMEUNITPERSEC (32.*441000.)
595
596
597/* T.Grill - enable PD global thread locking - sys_lock, sys_unlock, sys_trylock functions */
598#define THREAD_LOCKING
599#include "pthread.h"
600
601
602static int sys_quit;
603static t_time sys_time;
604static t_time sys_time_per_msec = TIMEUNITPERSEC / 1000.;
605
606int sys_schedblocksize = DEFDACBLKSIZE;
607int sys_usecsincelastsleep(void);
608int sys_sleepgrain;
609
610typedef void (*t_clockmethod)(void *client);
611
612struct _clock
613{
614 t_time c_settime;
615 void *c_owner;
616 t_clockmethod c_fn;
617 struct _clock *c_next;
618};
619
620t_clock *clock_setlist;
621
622#ifdef UNIX
623#include <unistd.h>
624#endif
625
626t_clock *clock_new(void *owner, t_method fn)
627{
628 t_clock *x = (t_clock *)getbytes(sizeof *x);
629 x->c_settime = -1;
630 x->c_owner = owner;
631 x->c_fn = (t_clockmethod)fn;
632 x->c_next = 0;
633 return (x);
634}
635
636void clock_unset(t_clock *x)
637{
638 if (x->c_settime >= 0)
639 {
640 if (x == clock_setlist) clock_setlist = x->c_next;
641 else
642 {
643 t_clock *x2 = clock_setlist;
644 while (x2->c_next != x) x2 = x2->c_next;
645 x2->c_next = x->c_next;
646 }
647 x->c_settime = -1;
648 }
649}
650
651 /* set the clock to call back at an absolute system time */
652void clock_set(t_clock *x, t_time setticks)
653{
654 if (setticks < sys_time) setticks = sys_time;
655 clock_unset(x);
656 x->c_settime = setticks;
657 if (clock_setlist && clock_setlist->c_settime <= setticks)
658 {
659 t_clock *cbefore, *cafter;
660 for (cbefore = clock_setlist, cafter = clock_setlist->c_next;
661 cbefore; cbefore = cafter, cafter = cbefore->c_next)
662 {
663 if (!cafter || cafter->c_settime > setticks)
664 {
665 cbefore->c_next = x;
666 x->c_next = cafter;
667 return;
668 }
669 }
670 }
671 else x->c_next = clock_setlist, clock_setlist = x;
672}
673
674 /* set the clock to call back after a delay in msec */
675void clock_delay(t_clock *x, t_time delaytime)
676{
677 clock_set(x, sys_time + sys_time_per_msec * delaytime);
678}
679
680 /* get current logical time. We don't specify what units this is in;
681 use clock_gettimesince() to measure intervals from time of this call.
682 This was previously, incorrectly named "clock_getsystime"; the old
683 name is aliased to the new one in m_pd.h. */
684t_time clock_getlogicaltime( void)
685{
686 return (sys_time);
687}
688 /* OBSOLETE NAME */
689t_time clock_getsystime( void) { return (sys_time); }
690
691 /* elapsed time in milliseconds since the given system time */
692t_time clock_gettimesince(t_time prevsystime)
693{
694 return ((sys_time - prevsystime)/sys_time_per_msec);
695}
696
697 /* what value the system clock will have after a delay */
698t_time clock_getsystimeafter(t_time delaytime)
699{
700 return (sys_time + sys_time_per_msec * delaytime);
701}
702
703void clock_free(t_clock *x)
704{
705 clock_unset(x);
706 freebytes(x, sizeof *x);
707}
708
709
710/* the following routines maintain a real-execution-time histogram of the
711various phases of real-time execution. */
712
713static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000};
714#define NBIN (sizeof(sys_bin)/sizeof(*sys_bin))
715#define NHIST 10
716static int sys_histogram[NHIST][NBIN];
717static t_time sys_histtime;
718static int sched_diddsp, sched_didpoll, sched_didnothing;
719
720static void sys_clearhist( void)
721{
722 unsigned int i, j;
723 for (i = 0; i < NHIST; i++)
724 for (j = 0; j < NBIN; j++) sys_histogram[i][j] = 0;
725 sys_histtime = sys_getrealtime();
726 sched_diddsp = sched_didpoll = sched_didnothing = 0;
727}
728
729void sys_printhist( void)
730{
731 unsigned int i, j;
732 for (i = 0; i < NHIST; i++)
733 {
734 int doit = 0;
735 for (j = 0; j < NBIN; j++) if (sys_histogram[i][j]) doit = 1;
736 if (doit)
737 {
738 post("%2d %8d %8d %8d %8d %8d %8d %8d %8d", i,
739 sys_histogram[i][0],
740 sys_histogram[i][1],
741 sys_histogram[i][2],
742 sys_histogram[i][3],
743 sys_histogram[i][4],
744 sys_histogram[i][5],
745 sys_histogram[i][6],
746 sys_histogram[i][7]);
747 }
748 }
749 post("dsp %d, pollgui %d, nothing %d",
750 sched_diddsp, sched_didpoll, sched_didnothing);
751}
752
753static int sys_histphase;
754
755int sys_addhist(int phase)
756{
757#ifndef FIXEDPOINT
758 int i, j, phasewas = sys_histphase;
759 t_time newtime = sys_getrealtime();
760 int msec = (newtime - sys_histtime) * 1000.;
761 for (j = NBIN-1; j >= 0; j--)
762 {
763 if (msec >= sys_bin[j])
764 {
765 sys_histogram[phasewas][j]++;
766 break;
767 }
768 }
769 sys_histtime = newtime;
770 sys_histphase = phase;
771 return (phasewas);
772#else
773 return 0;
774#endif
775}
776
777#define NRESYNC 20
778
779typedef struct _resync
780{
781 int r_ntick;
782 int r_error;
783} t_resync;
784
785static int oss_resyncphase = 0;
786static int oss_nresync = 0;
787static t_resync oss_resync[NRESYNC];
788
789
790static char *(oss_errornames[]) = {
791"unknown",
792"ADC blocked",
793"DAC blocked",
794"A/D/A sync",
795"data late"
796};
797
798void glob_audiostatus(void)
799{
800 int dev, nresync, nresyncphase, i;
801 nresync = (oss_nresync >= NRESYNC ? NRESYNC : oss_nresync);
802 nresyncphase = oss_resyncphase - 1;
803 post("audio I/O error history:");
804 post("seconds ago\terror type");
805 for (i = 0; i < nresync; i++)
806 {
807 int errtype;
808 if (nresyncphase < 0)
809 nresyncphase += NRESYNC;
810 errtype = oss_resync[nresyncphase].r_error;
811 if (errtype < 0 || errtype > 4)
812 errtype = 0;
813
814 post("%9.2f\t%s",
815 (sched_diddsp - oss_resync[nresyncphase].r_ntick)
816 * ((double)sys_schedblocksize) / sys_dacsr,
817 oss_errornames[errtype]);
818 nresyncphase--;
819 }
820}
821
822static int sched_diored;
823static int sched_dioredtime;
824static int sched_meterson;
825
826void sys_log_error(int type)
827{
828 oss_resync[oss_resyncphase].r_ntick = sched_diddsp;
829 oss_resync[oss_resyncphase].r_error = type;
830 oss_nresync++;
831 if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0;
832 if (type != ERR_NOTHING && !sched_diored &&
833 (sched_diddsp >= sched_dioredtime))
834 {
835 sys_vgui("pdtk_pd_dio 1\n");
836 sched_diored = 1;
837 }
838 sched_dioredtime =
839 sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
840}
841
842static int sched_lastinclip, sched_lastoutclip,
843 sched_lastindb, sched_lastoutdb;
844
845void glob_ping(t_pd *dummy);
846
847static void sched_pollformeters( void)
848{
849 int inclip, outclip, indb, outdb;
850 static int sched_nextmeterpolltime, sched_nextpingtime;
851
852 /* if there's no GUI but we're running in "realtime", here is
853 where we arrange to ping the watchdog every 2 seconds. */
854#ifdef __linux__
855 if (sys_nogui && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0))
856 {
857 glob_ping(0);
858 /* ping every 2 seconds */
859 sched_nextpingtime = sched_diddsp +
860 (2* sys_dacsr) /(int)sys_schedblocksize;
861 }
862#endif
863
864 if (sched_diddsp - sched_nextmeterpolltime < 0)
865 return;
866 if (sched_diored && (sched_diddsp - sched_dioredtime > 0))
867 {
868 sys_vgui("pdtk_pd_dio 0\n");
869 sched_diored = 0;
870 }
871 if (sched_meterson)
872 {
873 float inmax, outmax;
874 sys_getmeters(&inmax, &outmax);
875 indb = 0.5 + rmstodb(inmax);
876 outdb = 0.5 + rmstodb(outmax);
877 inclip = (inmax > 0.999);
878 outclip = (outmax >= 1.0);
879 }
880 else
881 {
882 indb = outdb = 0;
883 inclip = outclip = 0;
884 }
885 if (inclip != sched_lastinclip || outclip != sched_lastoutclip
886 || indb != sched_lastindb || outdb != sched_lastoutdb)
887 {
888 sys_vgui("pdtk_pd_meters %d %d %d %d\n", indb, outdb, inclip, outclip);
889 sched_lastinclip = inclip;
890 sched_lastoutclip = outclip;
891 sched_lastindb = indb;
892 sched_lastoutdb = outdb;
893 }
894 sched_nextmeterpolltime =
895 sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
896}
897
898void glob_meters(void *dummy, float f)
899{
900 if (f == 0)
901 sys_getmeters(0, 0);
902 sched_meterson = (f != 0);
903 sched_lastinclip = sched_lastoutclip = sched_lastindb = sched_lastoutdb =
904 -1;
905}
906
907#if 0
908void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
909{
910 if (argc) sys_clearhist();
911 else sys_printhist();
912}
913#endif
914
915void dsp_tick(void);
916
917static int sched_usedacs = 1;
918static t_time sched_referencerealtime, sched_referencelogicaltime;
919static t_time sys_time_per_dsp_tick;
920
921void sched_set_using_dacs(int flag)
922{
923 sched_usedacs = flag;
924 if (!flag)
925 {
926 sched_referencerealtime = sys_getrealtime();
927 sched_referencelogicaltime = clock_getlogicaltime();
928 post("schedsetuding");
929 }
930 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
931 ((double)sys_schedblocksize) / sys_dacsr;
932}
933
934 /* take the scheduler forward one DSP tick, also handling clock timeouts */
935static void sched_tick(t_time next_sys_time)
936{
937 int countdown = 5000;
938 while (clock_setlist && clock_setlist->c_settime < next_sys_time)
939 {
940 t_clock *c = clock_setlist;
941 sys_time = c->c_settime;
942 clock_unset(clock_setlist);
943 outlet_setstacklim();
944 (*c->c_fn)(c->c_owner);
945 if (!countdown--)
946 {
947 countdown = 5000;
948 sys_pollgui();
949 }
950 if (sys_quit)
951 return;
952 }
953 sys_time = next_sys_time;
954 dsp_tick();
955 sched_diddsp++;
956}
957
958/*
959Here is Pd's "main loop." This routine dispatches clock timeouts and DSP
960"ticks" deterministically, and polls for input from MIDI and the GUI. If
961we're left idle we also poll for graphics updates; but these are considered
962lower priority than the rest.
963
964The time source is normally the audio I/O subsystem via the "sys_send_dacs()"
965call. This call returns true if samples were transferred; false means that
966the audio I/O system is still busy with previous transfers.
967*/
968
969void sys_pollmidiqueue( void);
970void sys_initmidiqueue( void);
971
972int m_scheduler_pda( void)
973{
974 int idlecount = 0;
975 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
976 ((double)sys_schedblocksize) / sys_dacsr;
977
978
979 sys_clearhist();
980 if (sys_sleepgrain < 1000)
981 sys_sleepgrain = sys_schedadvance/4;
982 if (sys_sleepgrain < 100)
983 sys_sleepgrain = 100;
984 else if (sys_sleepgrain > 5000)
985 sys_sleepgrain = 5000;
986 sys_initmidiqueue();
987 while (!sys_quit)
988 {
989 int didsomething = 0;
990 int timeforward;
991
992 sys_addhist(0);
993 waitfortick:
994 if (sched_usedacs)
995 {
996 timeforward = sys_send_dacs();
997 sys_pollgui();
998 }
999 else {
1000 if ((sys_getrealtime() - sched_referencerealtime)
1001 > (t_time)clock_gettimesince(sched_referencelogicaltime)*1000)
1002 timeforward = SENDDACS_YES;
1003 else timeforward = SENDDACS_NO;
1004 if (timeforward == SENDDACS_YES)
1005 sys_microsleep(sys_sleepgrain);
1006 }
1007 if (timeforward != SENDDACS_NO) {
1008 sched_tick(sys_time + sys_time_per_dsp_tick);
1009 }
1010 }
1011 return 0;
1012}
1013
1014
1015int m_scheduler( void)
1016{
1017 int idlecount = 0;
1018 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
1019 ((double)sys_schedblocksize) / sys_dacsr;
1020
1021#ifdef THREAD_LOCKING
1022 /* T.Grill - lock mutex */
1023 sys_lock();
1024#endif
1025
1026 sys_clearhist();
1027 if (sys_sleepgrain < 1000)
1028 sys_sleepgrain = sys_schedadvance/4;
1029 if (sys_sleepgrain < 100)
1030 sys_sleepgrain = 100;
1031 else if (sys_sleepgrain > 5000)
1032 sys_sleepgrain = 5000;
1033 sys_initmidiqueue();
1034 while (!sys_quit)
1035 {
1036 int didsomething = 0;
1037 int timeforward;
1038
1039 sys_addhist(0);
1040 waitfortick:
1041 if (sched_usedacs)
1042 {
1043 timeforward = sys_send_dacs();
1044
1045 /* if dacs remain "idle" for 1 sec, they're hung up. */
1046 if (timeforward != 0)
1047 idlecount = 0;
1048 else
1049 {
1050 idlecount++;
1051 if (!(idlecount & 31))
1052 {
1053 static t_time idletime;
1054 /* on 32nd idle, start a clock watch; every
1055 32 ensuing idles, check it */
1056 if (idlecount == 32)
1057 idletime = sys_getrealtime();
1058 else if (sys_getrealtime() - idletime > 1.)
1059 {
1060 post("audio I/O stuck... closing audio\n");
1061 sys_close_audio();
1062 sched_set_using_dacs(0);
1063 goto waitfortick;
1064 }
1065 }
1066 }
1067 }
1068 else
1069 {
1070 if (1000. * (sys_getrealtime() - sched_referencerealtime)
1071 > clock_gettimesince(sched_referencelogicaltime))
1072 timeforward = SENDDACS_YES;
1073 else timeforward = SENDDACS_NO;
1074 }
1075 sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
1076 sys_addhist(1);
1077 if (timeforward != SENDDACS_NO)
1078 sched_tick(sys_time + sys_time_per_dsp_tick);
1079 if (timeforward == SENDDACS_YES)
1080 didsomething = 1;
1081
1082 sys_addhist(2);
1083 // sys_pollmidiqueue();
1084 if (sys_pollgui())
1085 {
1086 if (!didsomething)
1087 sched_didpoll++;
1088 didsomething = 1;
1089 }
1090 sys_addhist(3);
1091 /* test for idle; if so, do graphics updates. */
1092 if (!didsomething)
1093 {
1094 sched_pollformeters();
1095 sys_reportidle();
1096
1097#ifdef THREAD_LOCKING
1098 /* T.Grill - enter idle phase -> unlock thread lock */
1099 sys_unlock();
1100#endif
1101 if (timeforward != SENDDACS_SLEPT)
1102 sys_microsleep(sys_sleepgrain);
1103#ifdef THREAD_LOCKING
1104 /* T.Grill - leave idle phase -> lock thread lock */
1105 sys_lock();
1106#endif
1107
1108 sys_addhist(5);
1109 sched_didnothing++;
1110
1111 }
1112 }
1113
1114#ifdef THREAD_LOCKING
1115 /* T.Grill - done */
1116 sys_unlock();
1117#endif
1118
1119 return (0);
1120}
1121
1122
1123/* ------------ thread locking ------------------- */
1124/* added by Thomas Grill */
1125
1126#ifdef THREAD_LOCKING
1127static pthread_mutex_t sys_mutex = PTHREAD_MUTEX_INITIALIZER;
1128
1129void sys_lock(void)
1130{
1131 pthread_mutex_lock(&sys_mutex);
1132}
1133
1134void sys_unlock(void)
1135{
1136 pthread_mutex_unlock(&sys_mutex);
1137}
1138
1139int sys_trylock(void)
1140{
1141 return pthread_mutex_trylock(&sys_mutex);
1142}
1143
1144#else
1145
1146void sys_lock(void) {}
1147void sys_unlock(void) {}
1148int sys_trylock(void) {}
1149
1150#endif
1151
1152
1153/* ------------ soft quit ------------------- */
1154/* added by Thomas Grill -
1155 just set the quit flag for the scheduler loop
1156 this is useful for applications using the PD shared library to signal the scheduler to terminate
1157*/
1158
1159void sys_exit(void)
1160{
1161 sys_quit = 1;
1162}
diff --git a/apps/plugins/pdbox/PDa/src/makecostab.c b/apps/plugins/pdbox/PDa/src/makecostab.c
new file mode 100644
index 0000000000..9227ace16a
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/makecostab.c
@@ -0,0 +1,50 @@
1#include "m_fixed.h"
2#include <math.h>
3
4#define ILOGCOSTABSIZE 15
5#define ICOSTABSIZE (1<<ILOGCOSTABSIZE)
6
7int main(int argc,char** argv)
8{
9 int i;
10 int *fp;
11 double phase, phsinc = (2. * M_PI) / ICOSTABSIZE;
12
13 printf("#define ILOGCOSTABSIZE 15\n");
14 printf("#define ICOSTABSIZE (1<<ILOGCOSTABSIZE)\n");
15 printf("static t_sample cos_table[] = {");
16 for (i = ICOSTABSIZE + 1,phase = 0; i--; phase += phsinc) {
17 printf("%d,",ftofix(cos(phase)));
18 // post("costab %f %f",cos(phase),fixtof(*fp));
19
20 }
21 printf("0};\n");
22
23}
24
25
26#include "m_fixed.h"
27#include <math.h>
28
29#define ILOGCOSTABSIZE 15
30#define ICOSTABSIZE (1<<ILOGCOSTABSIZE)
31
32int main(int argc,char** argv)
33{
34 int i;
35 int *fp;
36 double phase, phsinc = (2. * M_PI) / ICOSTABSIZE;
37
38 printf("#define ILOGCOSTABSIZE 15\n");
39 printf("#define ICOSTABSIZE (1<<ILOGCOSTABSIZE)\n");
40 printf("static t_sample cos_table[] = {");
41 for (i = ICOSTABSIZE + 1,phase = 0; i--; phase += phsinc) {
42 printf("%d,",ftofix(cos(phase)));
43 // post("costab %f %f",cos(phase),fixtof(*fp));
44
45 }
46 printf("0};\n");
47
48}
49
50
diff --git a/apps/plugins/pdbox/PDa/src/makefile b/apps/plugins/pdbox/PDa/src/makefile
new file mode 100644
index 0000000000..6a28a95f34
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/makefile
@@ -0,0 +1,354 @@
1PREFIX = /usr/
2EXT = pd_linux
3
4# pd specific
5
6VPATH = ../obj:./
7OBJ_DIR = ../obj
8BIN_DIR = ../bin
9
10BROOT=/usr
11X11LIB = $(BROOT)/X11R6/lib
12
13DEFINES = -DPD -DUNIX
14
15pd-gui_INCLUDES = -I$(BROOT)/include/tcl8.4 -I$(BROOT)/X11R6/include
16pd-gui_LIBS = -ltk8.4 -ltcl8.4 -lX11 -ldl
17pd-gui_LDFLAGS = -L$(X11LIB)
18pd-gui_DEFINES = $(DEFINES)
19
20pd_LIBS = -lm -lpthread -ldl
21pd_LDFLAGS = -Wl,-export-dynamic
22pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
23 -DFIXEDPOINT -DUSEAPI_OSS -DDL_OPEN
24
25extra_DEFINES = $(DEFINES) -DFIXEDPOINT
26extra_INCLUDES = -I../src
27extra_LDFLAGS = -shared
28
29# IPOD toolchain
30
31ifeq ($(CC), arm-elf-gcc)
32pd_LDFLAGS += -elf2flt
33pd_LIBS = -lm -lpthread
34pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
35 -DFIXEDPOINT -DUSEAPI_OSS -D__linux__ -Dfork=getpid
36extra_DEFINES += -D__linux__ -Dfork=getpid
37endif
38
39# BLACKFIN toolchain
40
41ifeq ($(CC), bfin-uclinux-gcc)
42pd_LIBS = -lm -lpthread
43pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
44 -DFIXEDPOINT -DUSEAPI_OSS -D__linux__
45extra_DEFINES += -D__linux__
46endif
47
48# the sources
49
50pd_SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
51 g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \
52 g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \
53 g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \
54 m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \
55 m_conf.c m_glob.c m_sched.c \
56 s_main.c s_inter.c s_file.c s_print.c \
57 s_loader.c s_path.c s_entry.c s_audio.c s_midi.c \
58 d_ugen.c d_arithmetic.c d_dac.c d_misc.c \
59 d_fft.c d_mayer_fft.c d_fftroutine.c d_global.c \
60 d_resample.c d_ctl.c d_soundfile.c \
61 x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
62 x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c \
63 s_midi_oss.c s_audio_oss.c
64
65pd_SRC += d_imayer_fft.c m_fixed.c
66
67pd_OBJ = $(pd_SRC:.c=.o)
68
69pd-gui_SRC = t_main.c t_tkcmd.c
70pd-gui_OBJ = $(pd-gui_SRC:.c=.o)
71
72extra_SRC = $(shell ls ../intern/*.c) $(shell ls ../extra/*.c)
73extra_OBJ = $(extra_SRC:.c=.o)
74extra_EXT = $(extra_SRC:.c=.pd_linux)
75
76#
77# ------------------ targets ------------------------------------
78#
79
80all: $(BIN_DIR)/pd \
81 $(BIN_DIR)/pd-gui \
82 $(BIN_DIR)/pd-watchdog \
83 $(BIN_DIR)/pdsend \
84 $(BIN_DIR)/pdreceive \
85 $(BIN_DIR)/pd.tk \
86 extra
87
88pd: $(BIN_DIR)/pd
89pd-gui: $(BIN_DIR)/pd-gui
90pd-watchdog: $(BIN_DIR)/pd-watchdog
91
92static:
93 make pd_SRC="$(pd_SRC) $(extra_SRC)" DEFINES="-DPD -DUNIX -DSTATIC" \
94 pd pd-gui pd-watchdog $(BIN_DIR)/pdsend \
95 $(BIN_DIR)/pdreceive $(BIN_DIR)/pd.tk
96
97extra: $(extra_EXT)
98
99ipod:
100 make CC=arm-elf-gcc static
101
102blackfin:
103 make CC=bfin-uclinux-gcc static
104
105$(pd_OBJ) : %.o : %.c
106 $(CC) $(CFLAGS) $(pd_DEFINES) $(pd_INCLUDES) -c -o $(OBJ_DIR)/$@ $+
107
108$(pd-gui_OBJ) : %.o : %.c
109 $(CC) $(CFLAGS) $(pd-gui_DEFINES) $(pd-gui_INCLUDES) -c -o $(OBJ_DIR)/$@ $+
110
111$(extra_OBJ) : %.o : %.c
112 $(CC) $(CFLAGS) $(extra_DEFINES) $(extra_INCLUDES) -c -o $@ $*.c
113
114$(extra_EXT) : %.$(EXT) : %.o
115 $(CC) -o $@ $(extra_LDFLAGS) $+
116
117$(BIN_DIR)/pd-watchdog: s_watchdog.c
118 $(CC) $(CFLAGS) $(DEFINES) -o $@ s_watchdog.c
119
120$(BIN_DIR)/pdsend: u_pdsend.c
121 $(CC) $(CFLAGS) $(DEFINES) -o $@ u_pdsend.c
122
123$(BIN_DIR)/pdreceive: u_pdreceive.c
124 $(CC) $(CFLAGS) $(DEFINES) -o $@ u_pdreceive.c
125
126$(BIN_DIR)/pd: $(pd_OBJ)
127 cd ../obj; $(CC) $(pd_LDFLAGS) -o $@ $(pd_OBJ) $(pd_LIBS)
128
129$(BIN_DIR)/pd-gui: $(pd-gui_OBJ)
130 cd ../obj; $(CC) -o $@ $(pd-gui_OBJ) $(pd-gui_LDFLAGS) $(pd-gui_LIBS)
131
132$(BIN_DIR)/pd.tk: u_main.tk
133 echo set pd_nt 0 > $(BIN_DIR)/pd.tk
134 grep -v "set pd_nt" < u_main.tk >> $@
135
136INSTDIR = $(DESTDIR)/$(PREFIX)
137
138install: all
139# Create the directory structure
140
141 install -d $(INSTDIR)/lib/pd/bin
142 install -d $(INSTDIR)/lib/pd/extra
143 install -d $(INSTDIR)/lib/pd/intern
144 install -d $(INSTDIR)/lib/pd/doc
145 install -d $(INSTDIR)/bin
146 install -d $(INSTDIR)/include
147
148 install $(BIN_DIR)/pd-gui $(INSTDIR)/lib/pd/bin/
149 install $(BIN_DIR)/pd-watchdog $(INSTDIR)/lib/pd/bin/
150 install -m 644 $(BIN_DIR)/pd.tk $(INSTDIR)/lib/pd/bin/
151 install -m 755 $(BIN_DIR)/pd $(INSTDIR)/bin/
152 install -m 755 $(BIN_DIR)/pdsend $(INSTDIR)/bin/pdsend
153 install -m 755 $(BIN_DIR)/pdreceive $(INSTDIR)/bin/pdreceive
154 cp -r ../doc/7.stuff $(INSTDIR)/lib/pd/doc
155 cp -r ../doc/5.reference $(INSTDIR)/lib/pd/doc
156 install -m 644 m_pd.h $(INSTDIR)/include/m_pd.h
157
158# Install the externals if possible
159 cp ../extra/*.pd_linux $(INSTDIR)/lib/pd/extra
160 cp ../intern/*.pd_linux $(INSTDIR)/lib/pd/intern
161
162# Install the ICON and desktop file
163 install -d $(INSTDIR)/share/pixmaps
164 install -d $(INSTDIR)/share/applications
165 cp ../ipkg/pd-icon.png $(INSTDIR)/share/pixmaps
166 cp ../ipkg/pd.desktop $(INSTDIR)/share/applications/
167
168
169
170clean:
171 -rm -f `find ../extra/ -name "*.pd_*"`
172 -rm -f tags
173 -rm -f ../obj/* $(BIN_DIR)/* ../extra/*.{o,$(EXT)} ../intern/*.{o,$(EXT)}
174 -rm -f *~
175 -rm -f $(BIN_DIR)/pdsend $(BIN_DIR)/pdreceive
176
177
178PREFIX = /usr/
179EXT = pd_linux
180
181# pd specific
182
183VPATH = ../obj:./
184OBJ_DIR = ../obj
185BIN_DIR = ../bin
186
187BROOT=/usr
188X11LIB = $(BROOT)/X11R6/lib
189
190DEFINES = -DPD -DUNIX
191
192pd-gui_INCLUDES = -I$(BROOT)/include/tcl8.4 -I$(BROOT)/X11R6/include
193pd-gui_LIBS = -ltk8.4 -ltcl8.4 -lX11 -ldl
194pd-gui_LDFLAGS = -L$(X11LIB)
195pd-gui_DEFINES = $(DEFINES)
196
197pd_LIBS = -lm -lpthread -ldl
198pd_LDFLAGS = -Wl,-export-dynamic
199pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
200 -DFIXEDPOINT -DUSEAPI_OSS -DDL_OPEN
201
202extra_DEFINES = $(DEFINES) -DFIXEDPOINT
203extra_INCLUDES = -I../src
204extra_LDFLAGS = -shared
205
206# IPOD toolchain
207
208ifeq ($(CC), arm-elf-gcc)
209pd_LDFLAGS += -elf2flt
210pd_LIBS = -lm -lpthread
211pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
212 -DFIXEDPOINT -DUSEAPI_OSS -D__linux__ -Dfork=getpid
213extra_DEFINES += -D__linux__ -Dfork=getpid
214endif
215
216# BLACKFIN toolchain
217
218ifeq ($(CC), bfin-uclinux-gcc)
219pd_LIBS = -lm -lpthread
220pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
221 -DFIXEDPOINT -DUSEAPI_OSS -D__linux__
222extra_DEFINES += -D__linux__
223endif
224
225# the sources
226
227pd_SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
228 g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \
229 g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \
230 g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \
231 m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \
232 m_conf.c m_glob.c m_sched.c \
233 s_main.c s_inter.c s_file.c s_print.c \
234 s_loader.c s_path.c s_entry.c s_audio.c s_midi.c \
235 d_ugen.c d_arithmetic.c d_dac.c d_misc.c \
236 d_fft.c d_mayer_fft.c d_fftroutine.c d_global.c \
237 d_resample.c d_ctl.c d_soundfile.c \
238 x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
239 x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c \
240 s_midi_oss.c s_audio_oss.c
241
242pd_SRC += d_imayer_fft.c m_fixed.c
243
244pd_OBJ = $(pd_SRC:.c=.o)
245
246pd-gui_SRC = t_main.c t_tkcmd.c
247pd-gui_OBJ = $(pd-gui_SRC:.c=.o)
248
249extra_SRC = $(shell ls ../intern/*.c) $(shell ls ../extra/*.c)
250extra_OBJ = $(extra_SRC:.c=.o)
251extra_EXT = $(extra_SRC:.c=.pd_linux)
252
253#
254# ------------------ targets ------------------------------------
255#
256
257all: $(BIN_DIR)/pd \
258 $(BIN_DIR)/pd-gui \
259 $(BIN_DIR)/pd-watchdog \
260 $(BIN_DIR)/pdsend \
261 $(BIN_DIR)/pdreceive \
262 $(BIN_DIR)/pd.tk \
263 extra
264
265pd: $(BIN_DIR)/pd
266pd-gui: $(BIN_DIR)/pd-gui
267pd-watchdog: $(BIN_DIR)/pd-watchdog
268
269static:
270 make pd_SRC="$(pd_SRC) $(extra_SRC)" DEFINES="-DPD -DUNIX -DSTATIC" \
271 pd pd-gui pd-watchdog $(BIN_DIR)/pdsend \
272 $(BIN_DIR)/pdreceive $(BIN_DIR)/pd.tk
273
274extra: $(extra_EXT)
275
276ipod:
277 make CC=arm-elf-gcc static
278
279blackfin:
280 make CC=bfin-uclinux-gcc static
281
282$(pd_OBJ) : %.o : %.c
283 $(CC) $(CFLAGS) $(pd_DEFINES) $(pd_INCLUDES) -c -o $(OBJ_DIR)/$@ $+
284
285$(pd-gui_OBJ) : %.o : %.c
286 $(CC) $(CFLAGS) $(pd-gui_DEFINES) $(pd-gui_INCLUDES) -c -o $(OBJ_DIR)/$@ $+
287
288$(extra_OBJ) : %.o : %.c
289 $(CC) $(CFLAGS) $(extra_DEFINES) $(extra_INCLUDES) -c -o $@ $*.c
290
291$(extra_EXT) : %.$(EXT) : %.o
292 $(CC) -o $@ $(extra_LDFLAGS) $+
293
294$(BIN_DIR)/pd-watchdog: s_watchdog.c
295 $(CC) $(CFLAGS) $(DEFINES) -o $@ s_watchdog.c
296
297$(BIN_DIR)/pdsend: u_pdsend.c
298 $(CC) $(CFLAGS) $(DEFINES) -o $@ u_pdsend.c
299
300$(BIN_DIR)/pdreceive: u_pdreceive.c
301 $(CC) $(CFLAGS) $(DEFINES) -o $@ u_pdreceive.c
302
303$(BIN_DIR)/pd: $(pd_OBJ)
304 cd ../obj; $(CC) $(pd_LDFLAGS) -o $@ $(pd_OBJ) $(pd_LIBS)
305
306$(BIN_DIR)/pd-gui: $(pd-gui_OBJ)
307 cd ../obj; $(CC) -o $@ $(pd-gui_OBJ) $(pd-gui_LDFLAGS) $(pd-gui_LIBS)
308
309$(BIN_DIR)/pd.tk: u_main.tk
310 echo set pd_nt 0 > $(BIN_DIR)/pd.tk
311 grep -v "set pd_nt" < u_main.tk >> $@
312
313INSTDIR = $(DESTDIR)/$(PREFIX)
314
315install: all
316# Create the directory structure
317
318 install -d $(INSTDIR)/lib/pd/bin
319 install -d $(INSTDIR)/lib/pd/extra
320 install -d $(INSTDIR)/lib/pd/intern
321 install -d $(INSTDIR)/lib/pd/doc
322 install -d $(INSTDIR)/bin
323 install -d $(INSTDIR)/include
324
325 install $(BIN_DIR)/pd-gui $(INSTDIR)/lib/pd/bin/
326 install $(BIN_DIR)/pd-watchdog $(INSTDIR)/lib/pd/bin/
327 install -m 644 $(BIN_DIR)/pd.tk $(INSTDIR)/lib/pd/bin/
328 install -m 755 $(BIN_DIR)/pd $(INSTDIR)/bin/
329 install -m 755 $(BIN_DIR)/pdsend $(INSTDIR)/bin/pdsend
330 install -m 755 $(BIN_DIR)/pdreceive $(INSTDIR)/bin/pdreceive
331 cp -r ../doc/7.stuff $(INSTDIR)/lib/pd/doc
332 cp -r ../doc/5.reference $(INSTDIR)/lib/pd/doc
333 install -m 644 m_pd.h $(INSTDIR)/include/m_pd.h
334
335# Install the externals if possible
336 cp ../extra/*.pd_linux $(INSTDIR)/lib/pd/extra
337 cp ../intern/*.pd_linux $(INSTDIR)/lib/pd/intern
338
339# Install the ICON and desktop file
340 install -d $(INSTDIR)/share/pixmaps
341 install -d $(INSTDIR)/share/applications
342 cp ../ipkg/pd-icon.png $(INSTDIR)/share/pixmaps
343 cp ../ipkg/pd.desktop $(INSTDIR)/share/applications/
344
345
346
347clean:
348 -rm -f `find ../extra/ -name "*.pd_*"`
349 -rm -f tags
350 -rm -f ../obj/* $(BIN_DIR)/* ../extra/*.{o,$(EXT)} ../intern/*.{o,$(EXT)}
351 -rm -f *~
352 -rm -f $(BIN_DIR)/pdsend $(BIN_DIR)/pdreceive
353
354
diff --git a/apps/plugins/pdbox/PDa/src/s_audio.c b/apps/plugins/pdbox/PDa/src/s_audio.c
new file mode 100644
index 0000000000..4cb93307b0
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_audio.c
@@ -0,0 +1,1746 @@
1/* Copyright (c) 2003, Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* machine-independent (well, mostly!) audio layer. Stores and recalls
6 audio settings from argparse routine and from dialog window.
7*/
8
9#include "m_pd.h"
10#include "s_stuff.h"
11#include <stdio.h>
12#ifdef UNIX
13#include <unistd.h>
14#include <sys/time.h>
15#include <sys/resource.h>
16#endif
17#include <stdlib.h>
18#include <string.h>
19#include <errno.h>
20
21#define SYS_DEFAULTCH 2
22#define SYS_MAXCH 100
23#define SYS_DEFAULTSRATE 44100
24typedef long t_pa_sample;
25#define SYS_SAMPLEWIDTH sizeof(t_pa_sample)
26#define SYS_BYTESPERCHAN (DEFDACBLKSIZE * SYS_SAMPLEWIDTH)
27#define SYS_XFERSAMPS (SYS_DEFAULTCH*DEFDACBLKSIZE)
28#define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS)
29
30 /* these are set in this file when opening audio, but then may be reduced,
31 even to zero, in the system dependent open_audio routines. */
32int sys_inchannels;
33int sys_outchannels;
34int sys_advance_samples; /* scheduler advance in samples */
35int sys_blocksize = 0; /* audio I/O block size in sample frames */
36int sys_audioapi = API_DEFAULT;
37
38static int sys_meters; /* true if we're metering */
39static float sys_inmax; /* max input amplitude */
40static float sys_outmax; /* max output amplitude */
41
42 /* exported variables */
43int sys_schedadvance; /* scheduler advance in microseconds */
44float sys_dacsr;
45
46#ifdef MACOSX
47int sys_hipriority = 1;
48#else
49int sys_hipriority = 0;
50#endif
51
52t_sample *sys_soundout;
53t_sample *sys_soundin;
54
55 /* the "state" is normally one if we're open and zero otherwise;
56 but if the state is one, we still haven't necessarily opened the
57 audio hardware; see audio_isopen() below. */
58static int audio_state;
59
60 /* last requested parameters */
61static int audio_naudioindev;
62static int audio_audioindev[MAXAUDIOINDEV];
63static int audio_audiochindev[MAXAUDIOINDEV];
64static int audio_naudiooutdev;
65static int audio_audiooutdev[MAXAUDIOOUTDEV];
66static int audio_audiochoutdev[MAXAUDIOOUTDEV];
67static int audio_rate;
68static int audio_advance;
69
70static int audio_isopen(void)
71{
72 return (audio_state &&
73 ((audio_naudioindev > 0 && audio_audiochindev[0] > 0)
74 || (audio_naudiooutdev > 0 && audio_audiochoutdev[0] > 0)));
75}
76
77static void sys_get_audio_params(
78 int *pnaudioindev, int *paudioindev, int *chindev,
79 int *pnaudiooutdev, int *paudiooutdev, int *choutdev,
80 int *prate, int *padvance)
81{
82 int i;
83 *pnaudioindev = audio_naudioindev;
84 for (i = 0; i < MAXAUDIOINDEV; i++)
85 paudioindev[i] = audio_audioindev[i],
86 chindev[i] = audio_audiochindev[i];
87 *pnaudiooutdev = audio_naudiooutdev;
88 for (i = 0; i < MAXAUDIOOUTDEV; i++)
89 paudiooutdev[i] = audio_audiooutdev[i],
90 choutdev[i] = audio_audiochoutdev[i];
91 *prate = audio_rate;
92 *padvance = audio_advance;
93}
94
95static void sys_save_audio_params(
96 int naudioindev, int *audioindev, int *chindev,
97 int naudiooutdev, int *audiooutdev, int *choutdev,
98 int rate, int advance)
99{
100 int i;
101 audio_naudioindev = naudioindev;
102 for (i = 0; i < MAXAUDIOINDEV; i++)
103 audio_audioindev[i] = audioindev[i],
104 audio_audiochindev[i] = chindev[i];
105 audio_naudiooutdev = naudiooutdev;
106 for (i = 0; i < MAXAUDIOOUTDEV; i++)
107 audio_audiooutdev[i] = audiooutdev[i],
108 audio_audiochoutdev[i] = choutdev[i];
109 audio_rate = rate;
110 audio_advance = advance;
111}
112
113 /* init routines for any API which needs to set stuff up before
114 any other API gets used. This is only true of OSS so far. */
115#ifdef USEAPI_OSS
116void oss_init(void);
117#endif
118
119static void audio_init( void)
120{
121 static int initted = 0;
122 if (initted)
123 return;
124 initted = 1;
125#ifdef USEAPI_OSS
126 oss_init();
127#endif
128}
129
130 /* set channels and sample rate. */
131
132static void sys_setchsr(int chin, int chout, int sr)
133{
134 int nblk;
135 int inbytes = (chin ? chin : 2) * (DEFDACBLKSIZE*sizeof(float));
136 int outbytes = (chout ? chout : 2) * (DEFDACBLKSIZE*sizeof(float));
137
138 sys_inchannels = chin;
139 sys_outchannels = chout;
140 sys_dacsr = sr;
141 sys_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.);
142 if (sys_advance_samples < 3 * DEFDACBLKSIZE)
143 sys_advance_samples = 3 * DEFDACBLKSIZE;
144
145 if (sys_soundin)
146 free(sys_soundin);
147 sys_soundin = (t_float *)malloc(inbytes);
148 memset(sys_soundin, 0, inbytes);
149
150 if (sys_soundout)
151 free(sys_soundout);
152 sys_soundout = (t_float *)malloc(outbytes);
153 memset(sys_soundout, 0, outbytes);
154
155 if (sys_verbose)
156 post("input channels = %d, output channels = %d",
157 sys_inchannels, sys_outchannels);
158 canvas_resume_dsp(canvas_suspend_dsp());
159}
160
161/* ----------------------- public routines ----------------------- */
162
163 /* open audio devices (after cleaning up the specified device and channel
164 vectors). The audio devices are "zero based" (i.e. "0" means the first
165 one.) We also save the cleaned-up device specification so that we
166 can later re-open audio and/or show the settings on a dialog window. */
167
168void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
169 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
170 int *choutdev, int rate, int advance, int enable)
171{
172 int i, *ip;
173 int defaultchannels = SYS_DEFAULTCH;
174 int inchans, outchans;
175 if (rate < 1)
176 rate = SYS_DEFAULTSRATE;
177 audio_init();
178 /* Since the channel vector might be longer than the
179 audio device vector, or vice versa, we fill the shorter one
180 in to match the longer one. Also, if both are empty, we fill in
181 one device (the default) and two channels. */
182 if (naudioindev == -1)
183 { /* no input audio devices specified */
184 if (nchindev == -1)
185 {
186 nchindev=1;
187 chindev[0] = defaultchannels;
188 naudioindev = 1;
189 audioindev[0] = DEFAULTAUDIODEV;
190 }
191 else
192 {
193 for (i = 0; i < MAXAUDIOINDEV; i++)
194 audioindev[i] = i;
195 naudioindev = nchindev;
196 }
197 }
198 else
199 {
200 if (nchindev == -1)
201 {
202 nchindev = naudioindev;
203 for (i = 0; i < naudioindev; i++)
204 chindev[i] = defaultchannels;
205 }
206 else if (nchindev > naudioindev)
207 {
208 for (i = naudioindev; i < nchindev; i++)
209 {
210 if (i == 0)
211 audioindev[0] = DEFAULTAUDIODEV;
212 else audioindev[i] = audioindev[i-1] + 1;
213 }
214 naudioindev = nchindev;
215 }
216 else if (nchindev < naudioindev)
217 {
218 for (i = nchindev; i < naudioindev; i++)
219 {
220 if (i == 0)
221 chindev[0] = defaultchannels;
222 else chindev[i] = chindev[i-1];
223 }
224 naudioindev = nchindev;
225 }
226 }
227
228 if (naudiooutdev == -1)
229 { /* not set */
230 if (nchoutdev == -1)
231 {
232 nchoutdev=1;
233 choutdev[0]=defaultchannels;
234 naudiooutdev=1;
235 audiooutdev[0] = DEFAULTAUDIODEV;
236 }
237 else
238 {
239 for (i = 0; i < MAXAUDIOOUTDEV; i++)
240 audiooutdev[i] = i;
241 naudiooutdev = nchoutdev;
242 }
243 }
244 else
245 {
246 if (nchoutdev == -1)
247 {
248 nchoutdev = naudiooutdev;
249 for (i = 0; i < naudiooutdev; i++)
250 choutdev[i] = defaultchannels;
251 }
252 else if (nchoutdev > naudiooutdev)
253 {
254 for (i = naudiooutdev; i < nchoutdev; i++)
255 {
256 if (i == 0)
257 audiooutdev[0] = DEFAULTAUDIODEV;
258 else audiooutdev[i] = audiooutdev[i-1] + 1;
259 }
260 naudiooutdev = nchoutdev;
261 }
262 else if (nchoutdev < naudiooutdev)
263 {
264 for (i = nchoutdev; i < naudiooutdev; i++)
265 {
266 if (i == 0)
267 choutdev[0] = defaultchannels;
268 else choutdev[i] = choutdev[i-1];
269 }
270 naudiooutdev = nchoutdev;
271 }
272 }
273
274 /* count total number of input and output channels */
275 for (i = inchans = 0; i < naudioindev; i++)
276 inchans += chindev[i];
277 for (i = outchans = 0; i < naudiooutdev; i++)
278 outchans += choutdev[i];
279 /* if no input or output devices seem to have been specified,
280 this really means just disable audio, which we now do. Meanwhile,
281 we can set audio input and output devices to their defaults. */
282 if (!inchans && !outchans)
283 {
284 enable = 0;
285 naudioindev = nchindev = naudiooutdev = nchoutdev = 1;
286 audioindev[0] = audiooutdev[0] = DEFAULTAUDIODEV;
287 chindev[0] = choutdev[0] = 0;
288 }
289 sys_schedadvance = advance * 1000;
290 sys_setchsr(inchans, outchans, rate);
291 sys_log_error(ERR_NOTHING);
292
293 if (enable && (inchans > 0 || outchans > 0))
294 {
295#ifdef USEAPI_PORTAUDIO
296 if (sys_audioapi == API_PORTAUDIO)
297 {
298 int blksize = (sys_blocksize ? sys_blocksize : 64);
299 pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout,
300 blksize, sys_advance_samples/blksize,
301 (naudiooutdev > 0 ? audioindev[0] : 0),
302 (naudiooutdev > 0 ? audiooutdev[0] : 0));
303 }
304else
305#endif
306#ifdef USEAPI_JACK
307 if (sys_audioapi == API_JACK)
308 jack_open_audio((naudioindev > 0 ? chindev[0] : 0),
309 (naudiooutdev > 0 ? choutdev[0] : 0), rate);
310
311 else
312#endif
313#ifdef USEAPI_OSS
314 if (sys_audioapi == API_OSS)
315 oss_open_audio(naudioindev, audioindev, nchindev, chindev,
316 naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
317 else
318#endif
319#ifdef USEAPI_ALSA
320 /* for alsa, only one device is supported; it may
321 be open for both input and output. */
322 if (sys_audioapi == API_ALSA)
323 alsa_open_audio(naudioindev, audioindev, nchindev, chindev,
324 naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
325 else
326#endif
327#ifdef USEAPI_MMIO
328 if (sys_audioapi == API_MMIO)
329 mmio_open_audio(naudioindev, audioindev, nchindev, chindev,
330 naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
331 else
332#endif
333 post("unknown audio API specified");
334 }
335 sys_save_audio_params(naudioindev, audioindev, chindev,
336 naudiooutdev, audiooutdev, choutdev, rate, advance);
337 if (sys_inchannels == 0 && sys_outchannels == 0)
338 enable = 0;
339 audio_state = enable;
340 sys_vgui("set pd_whichapi %d\n", (audio_isopen() ? sys_audioapi : 0));
341 sched_set_using_dacs(enable);
342}
343
344void sys_close_audio(void)
345{
346 if (!audio_isopen())
347 return;
348#ifdef USEAPI_PORTAUDIO
349 if (sys_audioapi == API_PORTAUDIO)
350 pa_close_audio();
351 else
352#endif
353#ifdef USEAPI_JACK
354 if (sys_audioapi == API_JACK)
355 jack_close_audio();
356 else
357#endif
358#ifdef USEAPI_OSS
359 if (sys_audioapi == API_OSS)
360 oss_close_audio();
361 else
362#endif
363#ifdef USEAPI_ALSA
364 if (sys_audioapi == API_ALSA)
365 alsa_close_audio();
366 else
367#endif
368#ifdef USEAPI_MMIO
369 if (sys_audioapi == API_MMIO)
370 mmio_close_audio();
371 else
372#endif
373 post("sys_close_audio: unknown API %d", sys_audioapi);
374 sys_inchannels = sys_outchannels = 0;
375}
376
377 /* open audio using whatever parameters were last used */
378void sys_reopen_audio( void)
379{
380 int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
381 int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
382 int rate, advance;
383 sys_get_audio_params(&naudioindev, audioindev, chindev,
384 &naudiooutdev, audiooutdev, choutdev, &rate, &advance);
385 sys_open_audio(naudioindev, audioindev, naudioindev, chindev,
386 naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, 1);
387}
388
389int sys_send_dacs(void)
390{
391 if (sys_meters)
392 {
393 int i, n;
394 float maxsamp;
395 for (i = 0, n = sys_inchannels * DEFDACBLKSIZE, maxsamp = sys_inmax;
396 i < n; i++)
397 {
398 float f = sys_soundin[i];
399 if (f > maxsamp) maxsamp = f;
400 else if (-f > maxsamp) maxsamp = -f;
401 }
402 sys_inmax = maxsamp;
403 for (i = 0, n = sys_outchannels * DEFDACBLKSIZE, maxsamp = sys_outmax;
404 i < n; i++)
405 {
406 float f = sys_soundout[i];
407 if (f > maxsamp) maxsamp = f;
408 else if (-f > maxsamp) maxsamp = -f;
409 }
410 sys_outmax = maxsamp;
411 }
412
413#ifdef USEAPI_PORTAUDIO
414 if (sys_audioapi == API_PORTAUDIO)
415 return (pa_send_dacs());
416 else
417#endif
418#ifdef USEAPI_JACK
419 if (sys_audioapi == API_JACK)
420 return (jack_send_dacs());
421 else
422#endif
423#ifdef USEAPI_OSS
424 if (sys_audioapi == API_OSS)
425 return (oss_send_dacs());
426 else
427#endif
428#ifdef USEAPI_ALSA
429 if (sys_audioapi == API_ALSA)
430 return (alsa_send_dacs());
431 else
432#endif
433#ifdef USEAPI_MMIO
434 if (sys_audioapi == API_MMIO)
435 return (mmio_send_dacs());
436 else
437#endif
438 post("unknown API");
439 return (0);
440}
441
442float sys_getsr(void)
443{
444 return (sys_dacsr);
445}
446
447int sys_get_outchannels(void)
448{
449 return (sys_outchannels);
450}
451
452int sys_get_inchannels(void)
453{
454 return (sys_inchannels);
455}
456
457void sys_audiobuf(int n)
458{
459 /* set the size, in milliseconds, of the audio FIFO */
460 if (n < 5) n = 5;
461 else if (n > 5000) n = 5000;
462 sys_schedadvance = n * 1000;
463}
464
465void sys_getmeters(float *inmax, float *outmax)
466{
467 if (inmax)
468 {
469 sys_meters = 1;
470 *inmax = sys_inmax;
471 *outmax = sys_outmax;
472 }
473 else
474 sys_meters = 0;
475 sys_inmax = sys_outmax = 0;
476}
477
478void sys_reportidle(void)
479{
480}
481
482#define MAXNDEV 20
483#define DEVDESCSIZE 80
484
485static void audio_getdevs(char *indevlist, int *nindevs,
486 char *outdevlist, int *noutdevs, int *canmulti,
487 int maxndev, int devdescsize)
488{
489 audio_init();
490#ifdef USEAPI_OSS
491 if (sys_audioapi == API_OSS)
492 {
493 oss_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti,
494 maxndev, devdescsize);
495 }
496 else
497#endif
498#ifdef USEAPI_ALSA
499 if (sys_audioapi == API_ALSA)
500 {
501 alsa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti,
502 maxndev, devdescsize);
503 }
504 else
505#endif
506#ifdef USEAPI_PORTAUDIO
507 if (sys_audioapi == API_PORTAUDIO)
508 {
509 pa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti,
510 maxndev, devdescsize);
511 }
512 else
513#endif
514#ifdef USEAPI_MMIO
515 if (sys_audioapi == API_MMIO)
516 {
517 mmio_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti,
518 maxndev, devdescsize);
519 }
520 else
521#endif
522 {
523 /* this shouldn't happen once all the above get filled in. */
524 int i;
525 *nindevs = *noutdevs = 3;
526 for (i = 0; i < 3; i++)
527 {
528 sprintf(indevlist + i * devdescsize, "input device #%d", i+1);
529 sprintf(outdevlist + i * devdescsize, "output device #%d", i+1);
530 }
531 *canmulti = 0;
532 }
533}
534
535#ifdef MSW
536#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */
537#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */
538#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
539#endif
540
541static void sys_listaudiodevs(void )
542{
543 char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
544 int nindevs = 0, noutdevs = 0, i, canmulti = 0;
545
546 audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti,
547 MAXNDEV, DEVDESCSIZE);
548
549 if (!nindevs)
550 post("no audio input devices found");
551 else
552 {
553 post("input devices:");
554 for (i = 0; i < nindevs; i++)
555 post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
556 }
557 if (!noutdevs)
558 post("no audio output devices found");
559 else
560 {
561 post("output devices:");
562 for (i = 0; i < noutdevs; i++)
563 post("%d. %s", i + DEVONSET, outdevlist + i * DEVDESCSIZE);
564 }
565 post("API number %d\n", sys_audioapi);
566}
567
568 /* start an audio settings dialog window */
569void glob_audio_properties(t_pd *dummy, t_floatarg flongform)
570{
571 char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)];
572 /* these are the devices you're using: */
573 int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
574 int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
575 int audioindev1, audioindev2, audioindev3, audioindev4,
576 audioinchan1, audioinchan2, audioinchan3, audioinchan4,
577 audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4,
578 audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4;
579 int rate, advance;
580 /* these are all the devices on your system: */
581 char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
582 int nindevs = 0, noutdevs = 0, canmulti = 0, i;
583
584 char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
585 outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
586
587 audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti,
588 MAXNDEV, DEVDESCSIZE);
589
590 strcpy(indevliststring, "{");
591 for (i = 0; i < nindevs; i++)
592 {
593 strcat(indevliststring, "\"");
594 strcat(indevliststring, indevlist + i * DEVDESCSIZE);
595 strcat(indevliststring, "\" ");
596 }
597 strcat(indevliststring, "}");
598
599 strcpy(outdevliststring, "{");
600 for (i = 0; i < noutdevs; i++)
601 {
602 strcat(outdevliststring, "\"");
603 strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
604 strcat(outdevliststring, "\" ");
605 }
606 strcat(outdevliststring, "}");
607
608 sys_get_audio_params(&naudioindev, audioindev, chindev,
609 &naudiooutdev, audiooutdev, choutdev, &rate, &advance);
610
611 /* post("naudioindev %d naudiooutdev %d longform %f",
612 naudioindev, naudiooutdev, flongform); */
613 if (naudioindev > 1 || naudiooutdev > 1)
614 flongform = 1;
615
616
617 audioindev1 = (naudioindev > 0 && audioindev[0]>= 0 ? audioindev[0] : 0);
618 audioindev2 = (naudioindev > 1 && audioindev[1]>= 0 ? audioindev[1] : 0);
619 audioindev3 = (naudioindev > 2 && audioindev[2]>= 0 ? audioindev[2] : 0);
620 audioindev4 = (naudioindev > 3 && audioindev[3]>= 0 ? audioindev[3] : 0);
621 audioinchan1 = (naudioindev > 0 ? chindev[0] : 0);
622 audioinchan2 = (naudioindev > 1 ? chindev[1] : 0);
623 audioinchan3 = (naudioindev > 2 ? chindev[2] : 0);
624 audioinchan4 = (naudioindev > 3 ? chindev[3] : 0);
625 audiooutdev1 = (naudiooutdev > 0 && audiooutdev[0]>=0 ? audiooutdev[0] : 0);
626 audiooutdev2 = (naudiooutdev > 1 && audiooutdev[1]>=0 ? audiooutdev[1] : 0);
627 audiooutdev3 = (naudiooutdev > 2 && audiooutdev[2]>=0 ? audiooutdev[2] : 0);
628 audiooutdev4 = (naudiooutdev > 3 && audiooutdev[3]>=0 ? audiooutdev[3] : 0);
629 audiooutchan1 = (naudiooutdev > 0 ? choutdev[0] : 0);
630 audiooutchan2 = (naudiooutdev > 1 ? choutdev[1] : 0);
631 audiooutchan3 = (naudiooutdev > 2 ? choutdev[2] : 0);
632 audiooutchan4 = (naudiooutdev > 3 ? choutdev[3] : 0);
633 sprintf(buf,
634"pdtk_audio_dialog %%s \
635%s %d %d %d %d %d %d %d %d \
636%s %d %d %d %d %d %d %d %d \
637%d %d %d %d\n",
638 indevliststring,
639 audioindev1, audioindev2, audioindev3, audioindev4,
640 audioinchan1, audioinchan2, audioinchan3, audioinchan4,
641 outdevliststring,
642 audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4,
643 audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4,
644 rate, advance, canmulti, (flongform != 0));
645 gfxstub_deleteforkey(0);
646 gfxstub_new(&glob_pdobject, glob_audio_properties, buf);
647}
648
649 /* new values from dialog window */
650void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
651{
652 int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
653 int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
654 int rate, advance, audioon, i, nindev, noutdev;
655 int audioindev1, audioinchan1, audiooutdev1, audiooutchan1;
656 int newaudioindev[4], newaudioinchan[4],
657 newaudiooutdev[4], newaudiooutchan[4];
658 /* the new values the dialog came back with: */
659 int newrate = atom_getintarg(16, argc, argv);
660 int newadvance = atom_getintarg(17, argc, argv);
661 int statewas;
662
663 for (i = 0; i < 4; i++)
664 {
665 newaudioindev[i] = atom_getintarg(i, argc, argv);
666 newaudioinchan[i] = atom_getintarg(i+4, argc, argv);
667 newaudiooutdev[i] = atom_getintarg(i+8, argc, argv);
668 newaudiooutchan[i] = atom_getintarg(i+12, argc, argv);
669 }
670
671 for (i = 0, nindev = 0; i < 4; i++)
672 {
673 if (newaudioinchan[i] > 0)
674 {
675 newaudioindev[nindev] = newaudioindev[i];
676 newaudioinchan[nindev] = newaudioinchan[i];
677 /* post("in %d %d %d", nindev,
678 newaudioindev[nindev] , newaudioinchan[nindev]); */
679 nindev++;
680 }
681 }
682 for (i = 0, noutdev = 0; i < 4; i++)
683 {
684 if (newaudiooutchan[i] > 0)
685 {
686 newaudiooutdev[noutdev] = newaudiooutdev[i];
687 newaudiooutchan[noutdev] = newaudiooutchan[i];
688 /* post("out %d %d %d", noutdev,
689 newaudiooutdev[noutdev] , newaudioinchan[noutdev]); */
690 noutdev++;
691 }
692 }
693
694 sys_close_audio();
695 sys_open_audio(nindev, newaudioindev, nindev, newaudioinchan,
696 noutdev, newaudiooutdev, noutdev, newaudiooutchan,
697 newrate, newadvance, 1);
698}
699
700void sys_listdevs(void )
701{
702#ifdef USEAPI_PORTAUDIO
703 if (sys_audioapi == API_PORTAUDIO)
704 sys_listaudiodevs();
705 else
706#endif
707#ifdef USEAPI_JACK
708 if (sys_audioapi == API_JACK)
709 jack_listdevs();
710 else
711#endif
712#ifdef USEAPI_OSS
713 if (sys_audioapi == API_OSS)
714 sys_listaudiodevs();
715 else
716#endif
717#ifdef USEAPI_MMIO
718 if (sys_audioapi == API_MMIO)
719 sys_listaudiodevs();
720 else
721#endif
722#ifdef USEAPI_ALSA
723 if (sys_audioapi == API_ALSA)
724 sys_listaudiodevs();
725 else
726#endif
727 post("unknown API");
728
729 sys_listmididevs();
730}
731
732void sys_setblocksize(int n)
733{
734 if (n < 1)
735 n = 1;
736 if (n != (1 << ilog2(n)))
737 post("warning: adjusting blocksize to power of 2: %d",
738 (n = (1 << ilog2(n))));
739 sys_blocksize = n;
740}
741
742void sys_set_audio_api(int which)
743{
744 sys_audioapi = which;
745 if (sys_verbose)
746 post("sys_audioapi %d", sys_audioapi);
747}
748
749void glob_audio_setapi(void *dummy, t_floatarg f)
750{
751 int newapi = f;
752 if (newapi)
753 {
754 if (newapi == sys_audioapi)
755 {
756 if (!audio_isopen())
757 sys_reopen_audio();
758 }
759 else
760 {
761 sys_close_audio();
762 sys_audioapi = newapi;
763 /* bash device params back to default */
764 audio_naudioindev = audio_naudiooutdev = 1;
765 audio_audioindev[0] = audio_audiooutdev[0] = DEFAULTAUDIODEV;
766 audio_audiochindev[0] = audio_audiochoutdev[0] = SYS_DEFAULTCH;
767 sys_reopen_audio();
768 }
769 glob_audio_properties(0, 0);
770 }
771 else if (audio_isopen())
772 {
773 sys_close_audio();
774 audio_state = 0;
775 sched_set_using_dacs(0);
776 }
777}
778
779 /* start or stop the audio hardware */
780void sys_set_audio_state(int onoff)
781{
782 if (onoff) /* start */
783 {
784 if (!audio_isopen())
785 sys_reopen_audio();
786 }
787 else
788 {
789 if (audio_isopen())
790 {
791 sys_close_audio();
792 sched_set_using_dacs(0);
793 }
794 }
795 audio_state = onoff;
796}
797
798void sys_get_audio_apis(char *buf)
799{
800 int n = 0;
801 strcpy(buf, "{ ");
802#ifdef USEAPI_OSS
803 sprintf(buf + strlen(buf), "{OSS %d} ", API_OSS); n++;
804#endif
805#ifdef USEAPI_MMIO
806 sprintf(buf + strlen(buf), "{\"standard (MMIO)\" %d} ", API_MMIO); n++;
807#endif
808#ifdef USEAPI_ALSA
809 sprintf(buf + strlen(buf), "{ALSA %d} ", API_ALSA); n++;
810#endif
811#ifdef USEAPI_PORTAUDIO
812#ifdef MSW
813 sprintf(buf + strlen(buf),
814 "{\"ASIO (via portaudio)\" %d} ", API_PORTAUDIO);
815#else
816#ifdef OSX
817 sprintf(buf + strlen(buf),
818 "{\"standard (portaudio)\" %d} ", API_PORTAUDIO);
819#else
820 sprintf(buf + strlen(buf), "{portaudio %d} ", API_PORTAUDIO);
821#endif
822#endif
823 n++;
824#endif
825#ifdef USEAPI_JACK
826 sprintf(buf + strlen(buf), "{jack %d} ", API_JACK); n++;
827#endif
828 strcat(buf, "}");
829 /* then again, if only one API (or none) we don't offer any choice. */
830 if (n < 2)
831 strcpy(buf, "{}");
832
833}
834
835#ifdef USEAPI_ALSA
836void alsa_putzeros(int n);
837void alsa_getzeros(int n);
838void alsa_printstate( void);
839#endif
840
841 /* debugging */
842void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
843{
844 t_symbol *arg = atom_getsymbolarg(0, argc, argv);
845 if (arg == gensym("restart"))
846 {
847 int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
848 int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
849 int rate, advance;
850 sys_get_audio_params(&naudioindev, audioindev, chindev,
851 &naudiooutdev, audiooutdev, choutdev, &rate, &advance);
852 sys_close_audio();
853 sys_open_audio(naudioindev, audioindev, naudioindev, chindev,
854 naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance,
855 1);
856 }
857#ifdef USEAPI_ALSA
858 else if (arg == gensym("alsawrite"))
859 {
860 int n = atom_getintarg(1, argc, argv);
861 alsa_putzeros(n);
862 }
863 else if (arg == gensym("alsaread"))
864 {
865 int n = atom_getintarg(1, argc, argv);
866 alsa_getzeros(n);
867 }
868 else if (arg == gensym("print"))
869 {
870 alsa_printstate();
871 }
872#endif
873}
874/* Copyright (c) 2003, Miller Puckette and others.
875* For information on usage and redistribution, and for a DISCLAIMER OF ALL
876* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
877
878/* machine-independent (well, mostly!) audio layer. Stores and recalls
879 audio settings from argparse routine and from dialog window.
880*/
881
882#include "m_pd.h"
883#include "s_stuff.h"
884#include <stdio.h>
885#ifdef UNIX
886#include <unistd.h>
887#include <sys/time.h>
888#include <sys/resource.h>
889#endif
890#include <stdlib.h>
891#include <string.h>
892#include <errno.h>
893
894#define SYS_DEFAULTCH 2
895#define SYS_MAXCH 100
896#define SYS_DEFAULTSRATE 44100
897typedef long t_pa_sample;
898#define SYS_SAMPLEWIDTH sizeof(t_pa_sample)
899#define SYS_BYTESPERCHAN (DEFDACBLKSIZE * SYS_SAMPLEWIDTH)
900#define SYS_XFERSAMPS (SYS_DEFAULTCH*DEFDACBLKSIZE)
901#define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS)
902
903 /* these are set in this file when opening audio, but then may be reduced,
904 even to zero, in the system dependent open_audio routines. */
905int sys_inchannels;
906int sys_outchannels;
907int sys_advance_samples; /* scheduler advance in samples */
908int sys_blocksize = 0; /* audio I/O block size in sample frames */
909int sys_audioapi = API_DEFAULT;
910
911static int sys_meters; /* true if we're metering */
912static float sys_inmax; /* max input amplitude */
913static float sys_outmax; /* max output amplitude */
914
915 /* exported variables */
916int sys_schedadvance; /* scheduler advance in microseconds */
917float sys_dacsr;
918
919#ifdef MACOSX
920int sys_hipriority = 1;
921#else
922int sys_hipriority = 0;
923#endif
924
925t_sample *sys_soundout;
926t_sample *sys_soundin;
927
928 /* the "state" is normally one if we're open and zero otherwise;
929 but if the state is one, we still haven't necessarily opened the
930 audio hardware; see audio_isopen() below. */
931static int audio_state;
932
933 /* last requested parameters */
934static int audio_naudioindev;
935static int audio_audioindev[MAXAUDIOINDEV];
936static int audio_audiochindev[MAXAUDIOINDEV];
937static int audio_naudiooutdev;
938static int audio_audiooutdev[MAXAUDIOOUTDEV];
939static int audio_audiochoutdev[MAXAUDIOOUTDEV];
940static int audio_rate;
941static int audio_advance;
942
943static int audio_isopen(void)
944{
945 return (audio_state &&
946 ((audio_naudioindev > 0 && audio_audiochindev[0] > 0)
947 || (audio_naudiooutdev > 0 && audio_audiochoutdev[0] > 0)));
948}
949
950static void sys_get_audio_params(
951 int *pnaudioindev, int *paudioindev, int *chindev,
952 int *pnaudiooutdev, int *paudiooutdev, int *choutdev,
953 int *prate, int *padvance)
954{
955 int i;
956 *pnaudioindev = audio_naudioindev;
957 for (i = 0; i < MAXAUDIOINDEV; i++)
958 paudioindev[i] = audio_audioindev[i],
959 chindev[i] = audio_audiochindev[i];
960 *pnaudiooutdev = audio_naudiooutdev;
961 for (i = 0; i < MAXAUDIOOUTDEV; i++)
962 paudiooutdev[i] = audio_audiooutdev[i],
963 choutdev[i] = audio_audiochoutdev[i];
964 *prate = audio_rate;
965 *padvance = audio_advance;
966}
967
968static void sys_save_audio_params(
969 int naudioindev, int *audioindev, int *chindev,
970 int naudiooutdev, int *audiooutdev, int *choutdev,
971 int rate, int advance)
972{
973 int i;
974 audio_naudioindev = naudioindev;
975 for (i = 0; i < MAXAUDIOINDEV; i++)
976 audio_audioindev[i] = audioindev[i],
977 audio_audiochindev[i] = chindev[i];
978 audio_naudiooutdev = naudiooutdev;
979 for (i = 0; i < MAXAUDIOOUTDEV; i++)
980 audio_audiooutdev[i] = audiooutdev[i],
981 audio_audiochoutdev[i] = choutdev[i];
982 audio_rate = rate;
983 audio_advance = advance;
984}
985
986 /* init routines for any API which needs to set stuff up before
987 any other API gets used. This is only true of OSS so far. */
988#ifdef USEAPI_OSS
989void oss_init(void);
990#endif
991
992static void audio_init( void)
993{
994 static int initted = 0;
995 if (initted)
996 return;
997 initted = 1;
998#ifdef USEAPI_OSS
999 oss_init();
1000#endif
1001}
1002
1003 /* set channels and sample rate. */
1004
1005static void sys_setchsr(int chin, int chout, int sr)
1006{
1007 int nblk;
1008 int inbytes = (chin ? chin : 2) * (DEFDACBLKSIZE*sizeof(float));
1009 int outbytes = (chout ? chout : 2) * (DEFDACBLKSIZE*sizeof(float));
1010
1011 sys_inchannels = chin;
1012 sys_outchannels = chout;
1013 sys_dacsr = sr;
1014 sys_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.);
1015 if (sys_advance_samples < 3 * DEFDACBLKSIZE)
1016 sys_advance_samples = 3 * DEFDACBLKSIZE;
1017
1018 if (sys_soundin)
1019 free(sys_soundin);
1020 sys_soundin = (t_float *)malloc(inbytes);
1021 memset(sys_soundin, 0, inbytes);
1022
1023 if (sys_soundout)
1024 free(sys_soundout);
1025 sys_soundout = (t_float *)malloc(outbytes);
1026 memset(sys_soundout, 0, outbytes);
1027
1028 if (sys_verbose)
1029 post("input channels = %d, output channels = %d",
1030 sys_inchannels, sys_outchannels);
1031 canvas_resume_dsp(canvas_suspend_dsp());
1032}
1033
1034/* ----------------------- public routines ----------------------- */
1035
1036 /* open audio devices (after cleaning up the specified device and channel
1037 vectors). The audio devices are "zero based" (i.e. "0" means the first
1038 one.) We also save the cleaned-up device specification so that we
1039 can later re-open audio and/or show the settings on a dialog window. */
1040
1041void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
1042 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
1043 int *choutdev, int rate, int advance, int enable)
1044{
1045 int i, *ip;
1046 int defaultchannels = SYS_DEFAULTCH;
1047 int inchans, outchans;
1048 if (rate < 1)
1049 rate = SYS_DEFAULTSRATE;
1050 audio_init();
1051 /* Since the channel vector might be longer than the
1052 audio device vector, or vice versa, we fill the shorter one
1053 in to match the longer one. Also, if both are empty, we fill in
1054 one device (the default) and two channels. */
1055 if (naudioindev == -1)
1056 { /* no input audio devices specified */
1057 if (nchindev == -1)
1058 {
1059 nchindev=1;
1060 chindev[0] = defaultchannels;
1061 naudioindev = 1;
1062 audioindev[0] = DEFAULTAUDIODEV;
1063 }
1064 else
1065 {
1066 for (i = 0; i < MAXAUDIOINDEV; i++)
1067 audioindev[i] = i;
1068 naudioindev = nchindev;
1069 }
1070 }
1071 else
1072 {
1073 if (nchindev == -1)
1074 {
1075 nchindev = naudioindev;
1076 for (i = 0; i < naudioindev; i++)
1077 chindev[i] = defaultchannels;
1078 }
1079 else if (nchindev > naudioindev)
1080 {
1081 for (i = naudioindev; i < nchindev; i++)
1082 {
1083 if (i == 0)
1084 audioindev[0] = DEFAULTAUDIODEV;
1085 else audioindev[i] = audioindev[i-1] + 1;
1086 }
1087 naudioindev = nchindev;
1088 }
1089 else if (nchindev < naudioindev)
1090 {
1091 for (i = nchindev; i < naudioindev; i++)
1092 {
1093 if (i == 0)
1094 chindev[0] = defaultchannels;
1095 else chindev[i] = chindev[i-1];
1096 }
1097 naudioindev = nchindev;
1098 }
1099 }
1100
1101 if (naudiooutdev == -1)
1102 { /* not set */
1103 if (nchoutdev == -1)
1104 {
1105 nchoutdev=1;
1106 choutdev[0]=defaultchannels;
1107 naudiooutdev=1;
1108 audiooutdev[0] = DEFAULTAUDIODEV;
1109 }
1110 else
1111 {
1112 for (i = 0; i < MAXAUDIOOUTDEV; i++)
1113 audiooutdev[i] = i;
1114 naudiooutdev = nchoutdev;
1115 }
1116 }
1117 else
1118 {
1119 if (nchoutdev == -1)
1120 {
1121 nchoutdev = naudiooutdev;
1122 for (i = 0; i < naudiooutdev; i++)
1123 choutdev[i] = defaultchannels;
1124 }
1125 else if (nchoutdev > naudiooutdev)
1126 {
1127 for (i = naudiooutdev; i < nchoutdev; i++)
1128 {
1129 if (i == 0)
1130 audiooutdev[0] = DEFAULTAUDIODEV;
1131 else audiooutdev[i] = audiooutdev[i-1] + 1;
1132 }
1133 naudiooutdev = nchoutdev;
1134 }
1135 else if (nchoutdev < naudiooutdev)
1136 {
1137 for (i = nchoutdev; i < naudiooutdev; i++)
1138 {
1139 if (i == 0)
1140 choutdev[0] = defaultchannels;
1141 else choutdev[i] = choutdev[i-1];
1142 }
1143 naudiooutdev = nchoutdev;
1144 }
1145 }
1146
1147 /* count total number of input and output channels */
1148 for (i = inchans = 0; i < naudioindev; i++)
1149 inchans += chindev[i];
1150 for (i = outchans = 0; i < naudiooutdev; i++)
1151 outchans += choutdev[i];
1152 /* if no input or output devices seem to have been specified,
1153 this really means just disable audio, which we now do. Meanwhile,
1154 we can set audio input and output devices to their defaults. */
1155 if (!inchans && !outchans)
1156 {
1157 enable = 0;
1158 naudioindev = nchindev = naudiooutdev = nchoutdev = 1;
1159 audioindev[0] = audiooutdev[0] = DEFAULTAUDIODEV;
1160 chindev[0] = choutdev[0] = 0;
1161 }
1162 sys_schedadvance = advance * 1000;
1163 sys_setchsr(inchans, outchans, rate);
1164 sys_log_error(ERR_NOTHING);
1165
1166 if (enable && (inchans > 0 || outchans > 0))
1167 {
1168#ifdef USEAPI_PORTAUDIO
1169 if (sys_audioapi == API_PORTAUDIO)
1170 {
1171 int blksize = (sys_blocksize ? sys_blocksize : 64);
1172 pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout,
1173 blksize, sys_advance_samples/blksize,
1174 (naudiooutdev > 0 ? audioindev[0] : 0),
1175 (naudiooutdev > 0 ? audiooutdev[0] : 0));
1176 }
1177else
1178#endif
1179#ifdef USEAPI_JACK
1180 if (sys_audioapi == API_JACK)
1181 jack_open_audio((naudioindev > 0 ? chindev[0] : 0),
1182 (naudiooutdev > 0 ? choutdev[0] : 0), rate);
1183
1184 else
1185#endif
1186#ifdef USEAPI_OSS
1187 if (sys_audioapi == API_OSS)
1188 oss_open_audio(naudioindev, audioindev, nchindev, chindev,
1189 naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
1190 else
1191#endif
1192#ifdef USEAPI_ALSA
1193 /* for alsa, only one device is supported; it may
1194 be open for both input and output. */
1195 if (sys_audioapi == API_ALSA)
1196 alsa_open_audio(naudioindev, audioindev, nchindev, chindev,
1197 naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
1198 else
1199#endif
1200#ifdef USEAPI_MMIO
1201 if (sys_audioapi == API_MMIO)
1202 mmio_open_audio(naudioindev, audioindev, nchindev, chindev,
1203 naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
1204 else
1205#endif
1206 post("unknown audio API specified");
1207 }
1208 sys_save_audio_params(naudioindev, audioindev, chindev,
1209 naudiooutdev, audiooutdev, choutdev, rate, advance);
1210 if (sys_inchannels == 0 && sys_outchannels == 0)
1211 enable = 0;
1212 audio_state = enable;
1213 sys_vgui("set pd_whichapi %d\n", (audio_isopen() ? sys_audioapi : 0));
1214 sched_set_using_dacs(enable);
1215}
1216
1217void sys_close_audio(void)
1218{
1219 if (!audio_isopen())
1220 return;
1221#ifdef USEAPI_PORTAUDIO
1222 if (sys_audioapi == API_PORTAUDIO)
1223 pa_close_audio();
1224 else
1225#endif
1226#ifdef USEAPI_JACK
1227 if (sys_audioapi == API_JACK)
1228 jack_close_audio();
1229 else
1230#endif
1231#ifdef USEAPI_OSS
1232 if (sys_audioapi == API_OSS)
1233 oss_close_audio();
1234 else
1235#endif
1236#ifdef USEAPI_ALSA
1237 if (sys_audioapi == API_ALSA)
1238 alsa_close_audio();
1239 else
1240#endif
1241#ifdef USEAPI_MMIO
1242 if (sys_audioapi == API_MMIO)
1243 mmio_close_audio();
1244 else
1245#endif
1246 post("sys_close_audio: unknown API %d", sys_audioapi);
1247 sys_inchannels = sys_outchannels = 0;
1248}
1249
1250 /* open audio using whatever parameters were last used */
1251void sys_reopen_audio( void)
1252{
1253 int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
1254 int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
1255 int rate, advance;
1256 sys_get_audio_params(&naudioindev, audioindev, chindev,
1257 &naudiooutdev, audiooutdev, choutdev, &rate, &advance);
1258 sys_open_audio(naudioindev, audioindev, naudioindev, chindev,
1259 naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, 1);
1260}
1261
1262int sys_send_dacs(void)
1263{
1264 if (sys_meters)
1265 {
1266 int i, n;
1267 float maxsamp;
1268 for (i = 0, n = sys_inchannels * DEFDACBLKSIZE, maxsamp = sys_inmax;
1269 i < n; i++)
1270 {
1271 float f = sys_soundin[i];
1272 if (f > maxsamp) maxsamp = f;
1273 else if (-f > maxsamp) maxsamp = -f;
1274 }
1275 sys_inmax = maxsamp;
1276 for (i = 0, n = sys_outchannels * DEFDACBLKSIZE, maxsamp = sys_outmax;
1277 i < n; i++)
1278 {
1279 float f = sys_soundout[i];
1280 if (f > maxsamp) maxsamp = f;
1281 else if (-f > maxsamp) maxsamp = -f;
1282 }
1283 sys_outmax = maxsamp;
1284 }
1285
1286#ifdef USEAPI_PORTAUDIO
1287 if (sys_audioapi == API_PORTAUDIO)
1288 return (pa_send_dacs());
1289 else
1290#endif
1291#ifdef USEAPI_JACK
1292 if (sys_audioapi == API_JACK)
1293 return (jack_send_dacs());
1294 else
1295#endif
1296#ifdef USEAPI_OSS
1297 if (sys_audioapi == API_OSS)
1298 return (oss_send_dacs());
1299 else
1300#endif
1301#ifdef USEAPI_ALSA
1302 if (sys_audioapi == API_ALSA)
1303 return (alsa_send_dacs());
1304 else
1305#endif
1306#ifdef USEAPI_MMIO
1307 if (sys_audioapi == API_MMIO)
1308 return (mmio_send_dacs());
1309 else
1310#endif
1311 post("unknown API");
1312 return (0);
1313}
1314
1315float sys_getsr(void)
1316{
1317 return (sys_dacsr);
1318}
1319
1320int sys_get_outchannels(void)
1321{
1322 return (sys_outchannels);
1323}
1324
1325int sys_get_inchannels(void)
1326{
1327 return (sys_inchannels);
1328}
1329
1330void sys_audiobuf(int n)
1331{
1332 /* set the size, in milliseconds, of the audio FIFO */
1333 if (n < 5) n = 5;
1334 else if (n > 5000) n = 5000;
1335 sys_schedadvance = n * 1000;
1336}
1337
1338void sys_getmeters(float *inmax, float *outmax)
1339{
1340 if (inmax)
1341 {
1342 sys_meters = 1;
1343 *inmax = sys_inmax;
1344 *outmax = sys_outmax;
1345 }
1346 else
1347 sys_meters = 0;
1348 sys_inmax = sys_outmax = 0;
1349}
1350
1351void sys_reportidle(void)
1352{
1353}
1354
1355#define MAXNDEV 20
1356#define DEVDESCSIZE 80
1357
1358static void audio_getdevs(char *indevlist, int *nindevs,
1359 char *outdevlist, int *noutdevs, int *canmulti,
1360 int maxndev, int devdescsize)
1361{
1362 audio_init();
1363#ifdef USEAPI_OSS
1364 if (sys_audioapi == API_OSS)
1365 {
1366 oss_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti,
1367 maxndev, devdescsize);
1368 }
1369 else
1370#endif
1371#ifdef USEAPI_ALSA
1372 if (sys_audioapi == API_ALSA)
1373 {
1374 alsa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti,
1375 maxndev, devdescsize);
1376 }
1377 else
1378#endif
1379#ifdef USEAPI_PORTAUDIO
1380 if (sys_audioapi == API_PORTAUDIO)
1381 {
1382 pa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti,
1383 maxndev, devdescsize);
1384 }
1385 else
1386#endif
1387#ifdef USEAPI_MMIO
1388 if (sys_audioapi == API_MMIO)
1389 {
1390 mmio_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti,
1391 maxndev, devdescsize);
1392 }
1393 else
1394#endif
1395 {
1396 /* this shouldn't happen once all the above get filled in. */
1397 int i;
1398 *nindevs = *noutdevs = 3;
1399 for (i = 0; i < 3; i++)
1400 {
1401 sprintf(indevlist + i * devdescsize, "input device #%d", i+1);
1402 sprintf(outdevlist + i * devdescsize, "output device #%d", i+1);
1403 }
1404 *canmulti = 0;
1405 }
1406}
1407
1408#ifdef MSW
1409#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */
1410#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */
1411#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
1412#endif
1413
1414static void sys_listaudiodevs(void )
1415{
1416 char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
1417 int nindevs = 0, noutdevs = 0, i, canmulti = 0;
1418
1419 audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti,
1420 MAXNDEV, DEVDESCSIZE);
1421
1422 if (!nindevs)
1423 post("no audio input devices found");
1424 else
1425 {
1426 post("input devices:");
1427 for (i = 0; i < nindevs; i++)
1428 post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
1429 }
1430 if (!noutdevs)
1431 post("no audio output devices found");
1432 else
1433 {
1434 post("output devices:");
1435 for (i = 0; i < noutdevs; i++)
1436 post("%d. %s", i + DEVONSET, outdevlist + i * DEVDESCSIZE);
1437 }
1438 post("API number %d\n", sys_audioapi);
1439}
1440
1441 /* start an audio settings dialog window */
1442void glob_audio_properties(t_pd *dummy, t_floatarg flongform)
1443{
1444 char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)];
1445 /* these are the devices you're using: */
1446 int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
1447 int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
1448 int audioindev1, audioindev2, audioindev3, audioindev4,
1449 audioinchan1, audioinchan2, audioinchan3, audioinchan4,
1450 audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4,
1451 audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4;
1452 int rate, advance;
1453 /* these are all the devices on your system: */
1454 char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
1455 int nindevs = 0, noutdevs = 0, canmulti = 0, i;
1456
1457 char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
1458 outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
1459
1460 audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti,
1461 MAXNDEV, DEVDESCSIZE);
1462
1463 strcpy(indevliststring, "{");
1464 for (i = 0; i < nindevs; i++)
1465 {
1466 strcat(indevliststring, "\"");
1467 strcat(indevliststring, indevlist + i * DEVDESCSIZE);
1468 strcat(indevliststring, "\" ");
1469 }
1470 strcat(indevliststring, "}");
1471
1472 strcpy(outdevliststring, "{");
1473 for (i = 0; i < noutdevs; i++)
1474 {
1475 strcat(outdevliststring, "\"");
1476 strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
1477 strcat(outdevliststring, "\" ");
1478 }
1479 strcat(outdevliststring, "}");
1480
1481 sys_get_audio_params(&naudioindev, audioindev, chindev,
1482 &naudiooutdev, audiooutdev, choutdev, &rate, &advance);
1483
1484 /* post("naudioindev %d naudiooutdev %d longform %f",
1485 naudioindev, naudiooutdev, flongform); */
1486 if (naudioindev > 1 || naudiooutdev > 1)
1487 flongform = 1;
1488
1489
1490 audioindev1 = (naudioindev > 0 && audioindev[0]>= 0 ? audioindev[0] : 0);
1491 audioindev2 = (naudioindev > 1 && audioindev[1]>= 0 ? audioindev[1] : 0);
1492 audioindev3 = (naudioindev > 2 && audioindev[2]>= 0 ? audioindev[2] : 0);
1493 audioindev4 = (naudioindev > 3 && audioindev[3]>= 0 ? audioindev[3] : 0);
1494 audioinchan1 = (naudioindev > 0 ? chindev[0] : 0);
1495 audioinchan2 = (naudioindev > 1 ? chindev[1] : 0);
1496 audioinchan3 = (naudioindev > 2 ? chindev[2] : 0);
1497 audioinchan4 = (naudioindev > 3 ? chindev[3] : 0);
1498 audiooutdev1 = (naudiooutdev > 0 && audiooutdev[0]>=0 ? audiooutdev[0] : 0);
1499 audiooutdev2 = (naudiooutdev > 1 && audiooutdev[1]>=0 ? audiooutdev[1] : 0);
1500 audiooutdev3 = (naudiooutdev > 2 && audiooutdev[2]>=0 ? audiooutdev[2] : 0);
1501 audiooutdev4 = (naudiooutdev > 3 && audiooutdev[3]>=0 ? audiooutdev[3] : 0);
1502 audiooutchan1 = (naudiooutdev > 0 ? choutdev[0] : 0);
1503 audiooutchan2 = (naudiooutdev > 1 ? choutdev[1] : 0);
1504 audiooutchan3 = (naudiooutdev > 2 ? choutdev[2] : 0);
1505 audiooutchan4 = (naudiooutdev > 3 ? choutdev[3] : 0);
1506 sprintf(buf,
1507"pdtk_audio_dialog %%s \
1508%s %d %d %d %d %d %d %d %d \
1509%s %d %d %d %d %d %d %d %d \
1510%d %d %d %d\n",
1511 indevliststring,
1512 audioindev1, audioindev2, audioindev3, audioindev4,
1513 audioinchan1, audioinchan2, audioinchan3, audioinchan4,
1514 outdevliststring,
1515 audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4,
1516 audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4,
1517 rate, advance, canmulti, (flongform != 0));
1518 gfxstub_deleteforkey(0);
1519 gfxstub_new(&glob_pdobject, glob_audio_properties, buf);
1520}
1521
1522 /* new values from dialog window */
1523void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
1524{
1525 int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
1526 int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
1527 int rate, advance, audioon, i, nindev, noutdev;
1528 int audioindev1, audioinchan1, audiooutdev1, audiooutchan1;
1529 int newaudioindev[4], newaudioinchan[4],
1530 newaudiooutdev[4], newaudiooutchan[4];
1531 /* the new values the dialog came back with: */
1532 int newrate = atom_getintarg(16, argc, argv);
1533 int newadvance = atom_getintarg(17, argc, argv);
1534 int statewas;
1535
1536 for (i = 0; i < 4; i++)
1537 {
1538 newaudioindev[i] = atom_getintarg(i, argc, argv);
1539 newaudioinchan[i] = atom_getintarg(i+4, argc, argv);
1540 newaudiooutdev[i] = atom_getintarg(i+8, argc, argv);
1541 newaudiooutchan[i] = atom_getintarg(i+12, argc, argv);
1542 }
1543
1544 for (i = 0, nindev = 0; i < 4; i++)
1545 {
1546 if (newaudioinchan[i] > 0)
1547 {
1548 newaudioindev[nindev] = newaudioindev[i];
1549 newaudioinchan[nindev] = newaudioinchan[i];
1550 /* post("in %d %d %d", nindev,
1551 newaudioindev[nindev] , newaudioinchan[nindev]); */
1552 nindev++;
1553 }
1554 }
1555 for (i = 0, noutdev = 0; i < 4; i++)
1556 {
1557 if (newaudiooutchan[i] > 0)
1558 {
1559 newaudiooutdev[noutdev] = newaudiooutdev[i];
1560 newaudiooutchan[noutdev] = newaudiooutchan[i];
1561 /* post("out %d %d %d", noutdev,
1562 newaudiooutdev[noutdev] , newaudioinchan[noutdev]); */
1563 noutdev++;
1564 }
1565 }
1566
1567 sys_close_audio();
1568 sys_open_audio(nindev, newaudioindev, nindev, newaudioinchan,
1569 noutdev, newaudiooutdev, noutdev, newaudiooutchan,
1570 newrate, newadvance, 1);
1571}
1572
1573void sys_listdevs(void )
1574{
1575#ifdef USEAPI_PORTAUDIO
1576 if (sys_audioapi == API_PORTAUDIO)
1577 sys_listaudiodevs();
1578 else
1579#endif
1580#ifdef USEAPI_JACK
1581 if (sys_audioapi == API_JACK)
1582 jack_listdevs();
1583 else
1584#endif
1585#ifdef USEAPI_OSS
1586 if (sys_audioapi == API_OSS)
1587 sys_listaudiodevs();
1588 else
1589#endif
1590#ifdef USEAPI_MMIO
1591 if (sys_audioapi == API_MMIO)
1592 sys_listaudiodevs();
1593 else
1594#endif
1595#ifdef USEAPI_ALSA
1596 if (sys_audioapi == API_ALSA)
1597 sys_listaudiodevs();
1598 else
1599#endif
1600 post("unknown API");
1601
1602 sys_listmididevs();
1603}
1604
1605void sys_setblocksize(int n)
1606{
1607 if (n < 1)
1608 n = 1;
1609 if (n != (1 << ilog2(n)))
1610 post("warning: adjusting blocksize to power of 2: %d",
1611 (n = (1 << ilog2(n))));
1612 sys_blocksize = n;
1613}
1614
1615void sys_set_audio_api(int which)
1616{
1617 sys_audioapi = which;
1618 if (sys_verbose)
1619 post("sys_audioapi %d", sys_audioapi);
1620}
1621
1622void glob_audio_setapi(void *dummy, t_floatarg f)
1623{
1624 int newapi = f;
1625 if (newapi)
1626 {
1627 if (newapi == sys_audioapi)
1628 {
1629 if (!audio_isopen())
1630 sys_reopen_audio();
1631 }
1632 else
1633 {
1634 sys_close_audio();
1635 sys_audioapi = newapi;
1636 /* bash device params back to default */
1637 audio_naudioindev = audio_naudiooutdev = 1;
1638 audio_audioindev[0] = audio_audiooutdev[0] = DEFAULTAUDIODEV;
1639 audio_audiochindev[0] = audio_audiochoutdev[0] = SYS_DEFAULTCH;
1640 sys_reopen_audio();
1641 }
1642 glob_audio_properties(0, 0);
1643 }
1644 else if (audio_isopen())
1645 {
1646 sys_close_audio();
1647 audio_state = 0;
1648 sched_set_using_dacs(0);
1649 }
1650}
1651
1652 /* start or stop the audio hardware */
1653void sys_set_audio_state(int onoff)
1654{
1655 if (onoff) /* start */
1656 {
1657 if (!audio_isopen())
1658 sys_reopen_audio();
1659 }
1660 else
1661 {
1662 if (audio_isopen())
1663 {
1664 sys_close_audio();
1665 sched_set_using_dacs(0);
1666 }
1667 }
1668 audio_state = onoff;
1669}
1670
1671void sys_get_audio_apis(char *buf)
1672{
1673 int n = 0;
1674 strcpy(buf, "{ ");
1675#ifdef USEAPI_OSS
1676 sprintf(buf + strlen(buf), "{OSS %d} ", API_OSS); n++;
1677#endif
1678#ifdef USEAPI_MMIO
1679 sprintf(buf + strlen(buf), "{\"standard (MMIO)\" %d} ", API_MMIO); n++;
1680#endif
1681#ifdef USEAPI_ALSA
1682 sprintf(buf + strlen(buf), "{ALSA %d} ", API_ALSA); n++;
1683#endif
1684#ifdef USEAPI_PORTAUDIO
1685#ifdef MSW
1686 sprintf(buf + strlen(buf),
1687 "{\"ASIO (via portaudio)\" %d} ", API_PORTAUDIO);
1688#else
1689#ifdef OSX
1690 sprintf(buf + strlen(buf),
1691 "{\"standard (portaudio)\" %d} ", API_PORTAUDIO);
1692#else
1693 sprintf(buf + strlen(buf), "{portaudio %d} ", API_PORTAUDIO);
1694#endif
1695#endif
1696 n++;
1697#endif
1698#ifdef USEAPI_JACK
1699 sprintf(buf + strlen(buf), "{jack %d} ", API_JACK); n++;
1700#endif
1701 strcat(buf, "}");
1702 /* then again, if only one API (or none) we don't offer any choice. */
1703 if (n < 2)
1704 strcpy(buf, "{}");
1705
1706}
1707
1708#ifdef USEAPI_ALSA
1709void alsa_putzeros(int n);
1710void alsa_getzeros(int n);
1711void alsa_printstate( void);
1712#endif
1713
1714 /* debugging */
1715void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
1716{
1717 t_symbol *arg = atom_getsymbolarg(0, argc, argv);
1718 if (arg == gensym("restart"))
1719 {
1720 int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
1721 int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
1722 int rate, advance;
1723 sys_get_audio_params(&naudioindev, audioindev, chindev,
1724 &naudiooutdev, audiooutdev, choutdev, &rate, &advance);
1725 sys_close_audio();
1726 sys_open_audio(naudioindev, audioindev, naudioindev, chindev,
1727 naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance,
1728 1);
1729 }
1730#ifdef USEAPI_ALSA
1731 else if (arg == gensym("alsawrite"))
1732 {
1733 int n = atom_getintarg(1, argc, argv);
1734 alsa_putzeros(n);
1735 }
1736 else if (arg == gensym("alsaread"))
1737 {
1738 int n = atom_getintarg(1, argc, argv);
1739 alsa_getzeros(n);
1740 }
1741 else if (arg == gensym("print"))
1742 {
1743 alsa_printstate();
1744 }
1745#endif
1746}
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_alsa.c b/apps/plugins/pdbox/PDa/src/s_audio_alsa.c
new file mode 100644
index 0000000000..87d7cb929b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_audio_alsa.c
@@ -0,0 +1,1890 @@
1/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
2* Winfried Ritsch, Karl MacMillan, and others.
3* For information on usage and redistribution, and for a DISCLAIMER OF ALL
4* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5
6/* this file inputs and outputs audio using the ALSA API available on linux. */
7
8#include <alsa/asoundlib.h>
9
10#include "m_pd.h"
11#include "s_stuff.h"
12#include <errno.h>
13#include <stdio.h>
14#include <unistd.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/types.h>
18#include <sys/time.h>
19#include <sys/stat.h>
20#include <sys/ioctl.h>
21#include <fcntl.h>
22#include <sched.h>
23#include <sys/mman.h>
24
25typedef int16_t t_alsa_sample16;
26typedef int32_t t_alsa_sample32;
27#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16)
28#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
29#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DEFDACBLKSIZE)
30#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DEFDACBLKSIZE)
31#define ALSA_MAXDEV 1
32#define ALSA_JITTER 1024
33#define ALSA_EXTRABUFFER 2048
34#define ALSA_DEFFRAGSIZE 64
35#define ALSA_DEFNFRAG 12
36
37#ifndef INT32_MAX
38#define INT32_MAX 0x7fffffff
39#endif
40
41#if (SND_LIB_MAJOR < 1)
42#define ALSAAPI9
43#endif
44
45typedef struct _alsa_dev
46{
47 snd_pcm_t *inhandle;
48 snd_pcm_t *outhandle;
49 int innoninterleave; /* true if we're set for noninterleaved read */
50 int outnoninterleave; /* same for write */
51} t_alsa_dev;
52
53t_alsa_dev alsa_device;
54static void *alsa_snd_buf = 0;
55static void **alsa_buf_ptrs;
56static int alsa_samplewidth;
57static snd_pcm_status_t* in_status;
58static snd_pcm_status_t* out_status;
59
60static int alsa_mode;
61static int alsa_buf_samps; /* believed actual ALSA bufsize in sample frames */
62static int alsa_inchannels;
63static int alsa_outchannels;
64
65/* Defines */
66#define DEBUG(x) x
67#define DEBUG2(x) {x;}
68
69static void alsa_checkiosync( void);
70static void alsa_numbertoname(int devno, char *devname, int nchar);
71
72 /* don't assume we can turn all 31 bits when doing float-to-fix;
73 otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
74#define FMAX 0x7ffff000
75#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
76
77/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */
78
79static void check_error(int err, const char *why)
80{
81 if (err < 0)
82 fprintf(stderr, "%s: %s\n", why, snd_strerror(err));
83}
84
85/* was: alsa_open_audio(int wantinchans, int wantoutchans, int srate) */
86
87int alsa_open_audio(int naudioindev, int *audioindev, int nchindev,
88 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
89 int *choutdev, int rate)
90{
91 int err, inchans = 0, outchans = 0, subunitdir;
92 char devname[512];
93 snd_pcm_hw_params_t* hw_params;
94 snd_pcm_sw_params_t* sw_params;
95 snd_output_t* out;
96 int frag_size = (sys_blocksize ? sys_blocksize : ALSA_DEFFRAGSIZE);
97 int nfrags, i;
98 short* tmp_buf;
99 unsigned int tmp_uint;
100 snd_pcm_uframes_t tmp_snd_pcm_uframes;
101 int wantinchans, wantoutchans, devno;
102
103 if (naudioindev >= 2 || naudiooutdev >= 2)
104 post("alsa: only one input and output device allowed (extras ignored");
105 if (naudioindev >= 1 && naudiooutdev >= 1 &&
106 audioindev[0] != audiooutdev[0])
107 post("alsa: changing output device to agree with input device");
108 if (nchindev)
109 wantinchans = chindev[0];
110 else wantinchans = (naudioindev ? 2 : 0);
111 if (nchoutdev)
112 wantoutchans = choutdev[0];
113 else wantoutchans = (naudiooutdev ? 2 : 0);
114 devno = (naudioindev > 0 ? audioindev[0] :
115 (naudiooutdev > 0 ? audiooutdev[0] : 0));
116
117 alsa_numbertoname(devno, devname, 512);
118
119 if (sys_verbose)
120 post("device name %s; channels in %d, out %d", devname, wantinchans,
121 wantoutchans);
122
123 nfrags = sys_schedadvance * (float)rate / (1e6 * frag_size);
124 /* save our belief as to ALSA's buffer size for later */
125 alsa_buf_samps = nfrags * frag_size;
126
127 if (sys_verbose)
128 post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));
129
130 alsa_device.innoninterleave = alsa_device.outnoninterleave = 0;
131 if (wantinchans)
132 {
133 err = snd_pcm_open(&alsa_device.inhandle, devname,
134 SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
135
136 check_error(err, "snd_pcm_open (input)");
137 if (err < 0)
138 inchans = 0;
139 else
140 {
141 inchans = wantinchans;
142 snd_pcm_nonblock(alsa_device.inhandle, 1);
143 }
144 }
145 if (wantoutchans)
146 {
147 err = snd_pcm_open(&alsa_device.outhandle, devname,
148 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
149
150 check_error(err, "snd_pcm_open (output)");
151 if (err < 0)
152 outchans = 0;
153 else
154 {
155 outchans = wantoutchans;
156 snd_pcm_nonblock(alsa_device.outhandle, 1);
157 }
158 }
159 if (inchans)
160 {
161 if (sys_verbose)
162 post("opening sound input...");
163 err = snd_pcm_hw_params_malloc(&hw_params);
164 check_error(err, "snd_pcm_hw_params_malloc (input)");
165
166 // get the default params
167 err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params);
168 check_error(err, "snd_pcm_hw_params_any (input)");
169
170 /* try to set interleaved access */
171 err = snd_pcm_hw_params_set_access(alsa_device.inhandle,
172 hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
173 if (err < 0)
174 {
175 /* OK, so try non-interleaved */
176 err = snd_pcm_hw_params_set_access(alsa_device.inhandle,
177 hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
178 if (err >= 0)
179 {
180 post("using non-interleaved audio input");
181 alsa_device.innoninterleave = 1;
182 }
183 }
184 check_error(err, "snd_pcm_hw_params_set_access (input)");
185 // Try to set 32 bit format first
186 err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
187 SND_PCM_FORMAT_S32);
188 if (err < 0)
189 {
190 /* fprintf(stderr,
191 "PD-ALSA: 32 bit format not available - using 16\n"); */
192 err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
193 SND_PCM_FORMAT_S16);
194 check_error(err, "snd_pcm_hw_params_set_format (input)");
195 alsa_samplewidth = 2;
196 }
197 else
198 {
199 alsa_samplewidth = 4;
200 }
201 post("Sample width set to %d bytes", alsa_samplewidth);
202 // set the subformat
203 err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params,
204 SND_PCM_SUBFORMAT_STD);
205 check_error(err, "snd_pcm_hw_params_set_subformat (input)");
206 // set the number of channels
207 tmp_uint = inchans;
208 err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle,
209 hw_params, &tmp_uint);
210 check_error(err, "snd_pcm_hw_params_set_channels (input)");
211 if (tmp_uint != (unsigned)inchans)
212 post("ALSA: set input channels to %d", tmp_uint);
213 inchans = tmp_uint;
214 // set the sampling rate
215 err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params,
216 &rate, 0);
217 check_error(err, "snd_pcm_hw_params_set_rate_min (input)");
218#if 0
219 err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
220 post("input sample rate %d", err);
221#endif
222 // set the period - ie frag size
223 // post("fragsize a %d", frag_size);
224
225 /* LATER try this to get a recommended period size...
226 right now, it trips an assertion failure in ALSA lib */
227#if 0
228 post("input period was %d, min %d, max %d\n",
229 snd_pcm_hw_params_get_period_size(hw_params, 0),
230 snd_pcm_hw_params_get_period_size_min(hw_params, 0),
231 snd_pcm_hw_params_get_period_size_max(hw_params, 0));
232#endif
233#ifdef ALSAAPI9
234 err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
235 hw_params,
236 (snd_pcm_uframes_t)
237 frag_size, 0);
238#else
239 tmp_snd_pcm_uframes = frag_size;
240 err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
241 hw_params, &tmp_snd_pcm_uframes, 0);
242#endif
243 check_error(err, "snd_pcm_hw_params_set_period_size_near (input)");
244 // post("fragsize b %d", frag_size);
245 // set the number of periods - ie numfrags
246 // post("nfrags a %d", nfrags);
247#ifdef ALSAAPI9
248 err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
249 hw_params, nfrags, 0);
250#else
251 tmp_uint = nfrags;
252 err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
253 hw_params, &tmp_uint, 0);
254#endif
255 check_error(err, "snd_pcm_hw_params_set_periods_near (input)");
256 // set the buffer size
257#ifdef ALSAAPI9
258 err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
259 hw_params, nfrags * frag_size);
260#else
261 tmp_snd_pcm_uframes = nfrags * frag_size;
262 err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
263 hw_params, &tmp_snd_pcm_uframes);
264#endif
265 check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)");
266
267 err = snd_pcm_hw_params(alsa_device.inhandle, hw_params);
268 check_error(err, "snd_pcm_hw_params (input)");
269
270 snd_pcm_hw_params_free(hw_params);
271
272 err = snd_pcm_sw_params_malloc(&sw_params);
273 check_error(err, "snd_pcm_sw_params_malloc (input)");
274 err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params);
275 check_error(err, "snd_pcm_sw_params_current (input)");
276 err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
277 sw_params, nfrags * frag_size);
278 check_error(err, "snd_pcm_sw_params_set_start_threshold (input)");
279 err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
280 sw_params, 0x7fffffff);
281 check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)");
282 err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params,
283 frag_size);
284 check_error(err, "snd_pcm_sw_params_set_avail_min (input)");
285 err = snd_pcm_sw_params(alsa_device.inhandle, sw_params);
286 check_error(err, "snd_pcm_sw_params (input)");
287
288 snd_pcm_sw_params_free(sw_params);
289
290 snd_output_stdio_attach(&out, stderr, 0);
291#if 0
292 if (sys_verbose)
293 {
294 snd_pcm_dump_hw_setup(alsa_device.inhandle, out);
295 snd_pcm_dump_sw_setup(alsa_device.inhandle, out);
296 }
297#endif
298 }
299
300 if (outchans)
301 {
302 int foo;
303 if (sys_verbose)
304 post("opening sound output...");
305 err = snd_pcm_hw_params_malloc(&hw_params);
306 check_error(err, "snd_pcm_sw_params (output)");
307
308 // get the default params
309 err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params);
310 check_error(err, "snd_pcm_hw_params_any (output)");
311 // set interleaved access - FIXME deal with other access types
312 err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params,
313 SND_PCM_ACCESS_RW_INTERLEAVED);
314 check_error(err, "snd_pcm_hw_params_set_access (output)");
315
316 /* try to set interleaved access */
317 err = snd_pcm_hw_params_set_access(alsa_device.outhandle,
318 hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
319 if (err < 0)
320 {
321 /* OK, so try non-interleaved */
322 err = snd_pcm_hw_params_set_access(alsa_device.outhandle,
323 hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
324 if (err >= 0)
325 {
326 post("using non-interleaved audio");
327 alsa_device.outnoninterleave = 1;
328 }
329 }
330 check_error(err, "snd_pcm_hw_params_set_access (output)");
331
332
333 // Try to set 32 bit format first
334 err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params,
335 SND_PCM_FORMAT_S32);
336 if (err < 0)
337 {
338 err = snd_pcm_hw_params_set_format(alsa_device.outhandle,
339 hw_params,SND_PCM_FORMAT_S16);
340 check_error(err, "snd_pcm_hw_params_set_format (output)");
341 /* fprintf(stderr,
342 "PD-ALSA: 32 bit format not available - using 16\n"); */
343 alsa_samplewidth = 2;
344 }
345 else
346 {
347 alsa_samplewidth = 4;
348 }
349 // set the subformat
350 err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params,
351 SND_PCM_SUBFORMAT_STD);
352 check_error(err, "snd_pcm_hw_params_set_subformat (output)");
353 // set the number of channels
354 tmp_uint = outchans;
355 err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle,
356 hw_params, &tmp_uint);
357 check_error(err, "snd_pcm_hw_params_set_channels (output)");
358 if (tmp_uint != (unsigned)outchans)
359 post("alsa: set output channels to %d", tmp_uint);
360 outchans = tmp_uint;
361 // set the sampling rate
362 err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params,
363 &rate, 0);
364 check_error(err, "snd_pcm_hw_params_set_rate_min (output)");
365#if 0
366 err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
367 post("output sample rate %d", err);
368#endif
369 // set the period - ie frag size
370#if 0
371 post("output period was %d, min %d, max %d\n",
372 snd_pcm_hw_params_get_period_size(hw_params, 0),
373 snd_pcm_hw_params_get_period_size_min(hw_params, 0),
374 snd_pcm_hw_params_get_period_size_max(hw_params, 0));
375#endif
376 // post("fragsize c %d", frag_size);
377#ifdef ALSAAPI9
378 err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
379 hw_params,
380 (snd_pcm_uframes_t)
381 frag_size, 0);
382#else
383 tmp_snd_pcm_uframes = frag_size;
384 err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
385 hw_params, &tmp_snd_pcm_uframes, 0);
386#endif
387 // post("fragsize d %d", frag_size);
388 check_error(err, "snd_pcm_hw_params_set_period_size_near (output)");
389 // set the number of periods - ie numfrags
390#ifdef ALSAAPI9
391 err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
392 hw_params, nfrags, 0);
393#else
394 tmp_uint = nfrags;
395 err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
396 hw_params, &tmp_uint, 0);
397#endif
398 check_error(err, "snd_pcm_hw_params_set_periods_near (output)");
399 // set the buffer size
400#ifdef ALSAAPI9
401 err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
402 hw_params, nfrags * frag_size);
403#else
404 tmp_snd_pcm_uframes = nfrags * frag_size;
405 err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
406 hw_params, &tmp_snd_pcm_uframes);
407#endif
408 check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)");
409
410 err = snd_pcm_hw_params(alsa_device.outhandle, hw_params);
411 check_error(err, "snd_pcm_hw_params (output)");
412
413 snd_pcm_hw_params_free(hw_params);
414
415 err = snd_pcm_sw_params_malloc(&sw_params);
416 check_error(err, "snd_pcm_sw_params_malloc (output)");
417 err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params);
418 check_error(err, "snd_pcm_sw_params_current (output)");
419 err = snd_pcm_sw_params_set_start_threshold(alsa_device.outhandle,
420 sw_params, nfrags * frag_size);
421 check_error(err, "snd_pcm_sw_params_set_start_threshold (output)");
422 err = snd_pcm_sw_params_set_stop_threshold(alsa_device.outhandle,
423 sw_params, 0x7fffffff);
424 check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)");
425 err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params,
426 frag_size);
427 check_error(err, "snd_pcm_sw_params_set_avail_min (output)");
428 err = snd_pcm_sw_params(alsa_device.outhandle, sw_params);
429 check_error(err, "snd_pcm_sw_params (output)");
430 snd_pcm_sw_params_free(sw_params);
431
432 snd_output_stdio_attach(&out, stderr, 0);
433#if 0
434 if (sys_verbose)
435 {
436 snd_pcm_dump_hw_setup(alsa_device.outhandle, out);
437 snd_pcm_dump_sw_setup(alsa_device.outhandle, out);
438 }
439#endif
440 }
441
442 if (inchans)
443 snd_pcm_prepare(alsa_device.inhandle);
444 if (outchans)
445 snd_pcm_prepare(alsa_device.outhandle);
446
447 // if duplex we can link the channels so they start together
448 if (inchans && outchans)
449 snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle);
450
451 // set up the status variables
452 err = snd_pcm_status_malloc(&in_status);
453 check_error(err, "snd_pcm_status_malloc");
454 err = snd_pcm_status_malloc(&out_status);
455 check_error(err, "snd_pcm_status_malloc");
456
457 // set up the buffer
458 if (alsa_snd_buf)
459 free(alsa_snd_buf);
460 alsa_snd_buf = (void *)malloc(
461 sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE *
462 (outchans > inchans ? outchans : inchans));
463 memset(alsa_snd_buf, 0, sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE *
464 (outchans > inchans ? outchans : inchans));
465 /* make an array of pointers too in case we need them */
466 if (alsa_buf_ptrs)
467 free(alsa_buf_ptrs);
468 alsa_buf_ptrs = (void **)malloc(
469 sizeof(void *) * (outchans > inchans ? outchans : inchans));
470 for (i = 0; i < (outchans > inchans ? outchans : inchans); i++)
471 alsa_buf_ptrs[i] = (t_alsa_sample32 *)alsa_snd_buf + i * DEFDACBLKSIZE;
472
473 // fill the buffer with silence
474 if (outchans)
475 {
476 i = (frag_size * nfrags)/DEFDACBLKSIZE + 1;
477 while (i--)
478 {
479 if (alsa_device.outnoninterleave)
480 snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
481 DEFDACBLKSIZE);
482 else snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
483 DEFDACBLKSIZE);
484 }
485 /* confused about this: */
486 /* if ((err = snd_pcm_start(alsa_device.outhandle) < 0))
487 check_error(err, "output start failed\n"); */
488 }
489 else if (inchans)
490 {
491 if (snd_pcm_start(alsa_device.inhandle) < 0)
492 check_error(err, "input start failed\n");
493 }
494 alsa_outchannels = outchans;
495 alsa_inchannels = inchans;
496
497 return (!(inchans || outchans));
498}
499
500void alsa_close_audio(void)
501{
502 int err;
503 if (alsa_inchannels)
504 {
505 err = snd_pcm_close(alsa_device.inhandle);
506 check_error(err, "snd_pcm_close (input)");
507 }
508 if (alsa_outchannels)
509 {
510 err = snd_pcm_close(alsa_device.outhandle);
511 check_error(err, "snd_pcm_close (output)");
512 }
513}
514
515// #define DEBUG_ALSA_XFER
516
517int alsa_send_dacs(void)
518{
519 static int16_t *sp;
520 static int xferno = 0;
521 static int callno = 0;
522 static double timenow;
523 double timelast;
524 t_sample *fp, *fp1, *fp2;
525 int i, j, k, err, devno = 0;
526 int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0;
527 int result;
528 int inchannels = (sys_inchannels > alsa_inchannels ?
529 alsa_inchannels : sys_inchannels);
530 int outchannels = (sys_outchannels > alsa_outchannels ?
531 alsa_outchannels : sys_outchannels);
532 unsigned int intransfersize = DEFDACBLKSIZE;
533 unsigned int outtransfersize = DEFDACBLKSIZE;
534
535 // get the status
536 if (!inchannels && !outchannels)
537 {
538 return SENDDACS_NO;
539 }
540
541 timelast = timenow;
542 timenow = sys_getrealtime();
543
544#ifdef DEBUG_ALSA_XFER
545 if (timenow - timelast > 0.050)
546 fprintf(stderr, "(%d)",
547 (int)(1000 * (timenow - timelast))), fflush(stderr);
548#endif
549
550 callno++;
551
552 alsa_checkiosync(); /* check I/O are in sync and data not late */
553
554 if (alsa_inchannels)
555 {
556 snd_pcm_status(alsa_device.inhandle, in_status);
557 if (snd_pcm_status_get_avail(in_status) < intransfersize)
558 return SENDDACS_NO;
559 }
560 if (alsa_outchannels)
561 {
562 snd_pcm_status(alsa_device.outhandle, out_status);
563 if (snd_pcm_status_get_avail(out_status) < outtransfersize)
564 return SENDDACS_NO;
565 }
566
567 /* do output */
568 if (alsa_outchannels)
569 {
570 fp = sys_soundout;
571 if (alsa_samplewidth == 4)
572 {
573 if (alsa_device.outnoninterleave)
574 {
575 int n = outchannels * DEFDACBLKSIZE;
576 for (i = 0, fp1 = fp; i < n; i++)
577 {
578 float s1 = *fp1 * INT32_MAX;
579 ((t_alsa_sample32 *)alsa_snd_buf)[i] = CLIP32(s1);
580 }
581 n = alsa_outchannels * DEFDACBLKSIZE;
582 for (; i < n; i++)
583 ((t_alsa_sample32 *)alsa_snd_buf)[i] = 0;
584 }
585 else
586 {
587 for (i = 0, fp1 = fp; i < outchannels; i++,
588 fp1 += DEFDACBLKSIZE)
589 {
590 for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
591 j += alsa_outchannels, fp2++)
592 {
593 float s1 = *fp2 * INT32_MAX;
594 ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1);
595 }
596 }
597 }
598 }
599 else
600 {
601 for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DEFDACBLKSIZE)
602 {
603 for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
604 j += alsa_outchannels, fp2++)
605 {
606 int s = *fp2 * 32767.;
607 if (s > 32767)
608 s = 32767;
609 else if (s < -32767)
610 s = -32767;
611 ((t_alsa_sample16 *)alsa_snd_buf)[j] = s;
612 }
613 }
614 }
615
616 if (alsa_device.outnoninterleave)
617 result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
618 outtransfersize);
619 else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
620 outtransfersize);
621
622 if (result != (int)outtransfersize)
623 {
624 #ifdef DEBUG_ALSA_XFER
625 if (result >= 0 || errno == EAGAIN)
626 fprintf(stderr, "ALSA: write returned %d of %d\n",
627 result, outtransfersize);
628 else fprintf(stderr, "ALSA: write: %s\n",
629 snd_strerror(errno));
630 fprintf(stderr,
631 "inputcount %d, outputcount %d, outbufsize %d\n",
632 inputcount, outputcount,
633 (ALSA_EXTRABUFFER + sys_advance_samples)
634 * alsa_samplewidth * outchannels);
635 #endif
636 sys_log_error(ERR_DACSLEPT);
637 return (SENDDACS_NO);
638 }
639
640 /* zero out the output buffer */
641 memset(sys_soundout, 0, DEFDACBLKSIZE * sizeof(*sys_soundout) *
642 sys_outchannels);
643 if (sys_getrealtime() - timenow > 0.002)
644 {
645 #ifdef DEBUG_ALSA_XFER
646 fprintf(stderr, "output %d took %d msec\n",
647 callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
648 #endif
649 timenow = sys_getrealtime();
650 sys_log_error(ERR_DACSLEPT);
651 }
652 }
653 /* do input */
654 if (alsa_inchannels)
655 {
656 if (alsa_device.innoninterleave)
657 result = snd_pcm_readn(alsa_device.inhandle, alsa_buf_ptrs,
658 intransfersize);
659 else result = snd_pcm_readi(alsa_device.inhandle, alsa_snd_buf,
660 intransfersize);
661 if (result < (int)intransfersize)
662 {
663#ifdef DEBUG_ALSA_XFER
664 if (result < 0)
665 fprintf(stderr,
666 "snd_pcm_read %d %d: %s\n",
667 callno, xferno, snd_strerror(errno));
668 else fprintf(stderr,
669 "snd_pcm_read %d %d returned only %d\n",
670 callno, xferno, result);
671 fprintf(stderr,
672 "inputcount %d, outputcount %d, inbufsize %d\n",
673 inputcount, outputcount,
674 (ALSA_EXTRABUFFER + sys_advance_samples)
675 * alsa_samplewidth * inchannels);
676#endif
677 sys_log_error(ERR_ADCSLEPT);
678 return (SENDDACS_NO);
679 }
680 fp = sys_soundin;
681 if (alsa_samplewidth == 4)
682 {
683 if (alsa_device.innoninterleave)
684 {
685 int n = inchannels * DEFDACBLKSIZE;
686 for (i = 0, fp1 = fp; i < n; i++)
687 *fp1 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[i]
688 * (1./ INT32_MAX);
689 }
690 else
691 {
692 for (i = 0, fp1 = fp; i < inchannels;
693 i++, fp1 += DEFDACBLKSIZE)
694 {
695 for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
696 j += alsa_inchannels, fp2++)
697 *fp2 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[j]
698 * (1./ INT32_MAX);
699 }
700 }
701 }
702 else
703 {
704 for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DEFDACBLKSIZE)
705 {
706 for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
707 j += alsa_inchannels, fp2++)
708 *fp2 = (float) ((t_alsa_sample16 *)alsa_snd_buf)[j]
709 * 3.051850e-05;
710 }
711 }
712 }
713 xferno++;
714 if (sys_getrealtime() - timenow > 0.002)
715 {
716#ifdef DEBUG_ALSA_XFER
717 fprintf(stderr, "routine took %d msec\n",
718 (int)(1000 * (sys_getrealtime() - timenow)));
719#endif
720 sys_log_error(ERR_ADCSLEPT);
721 }
722 return SENDDACS_YES;
723}
724
725void alsa_printstate( void)
726{
727 int i, result;
728 snd_pcm_sframes_t indelay, outdelay;
729 if (sys_audioapi != API_ALSA)
730 {
731 error("restart-audio: implemented for ALSA only.");
732 return;
733 }
734 if (sys_inchannels)
735 {
736 result = snd_pcm_delay(alsa_device.inhandle, &indelay);
737 if (result < 0)
738 post("snd_pcm_delay 1 failed");
739 else post("in delay %d", indelay);
740 }
741 if (sys_outchannels)
742 {
743 result = snd_pcm_delay(alsa_device.outhandle, &outdelay);
744 if (result < 0)
745 post("snd_pcm_delay 2 failed");
746 else post("out delay %d", outdelay);
747 }
748 post("sum %d (%d mod 64)\n", indelay + outdelay, (indelay+outdelay)%64);
749
750 post("buf samples %d", alsa_buf_samps);
751}
752
753
754void alsa_resync( void)
755{
756 int i, result;
757 if (sys_audioapi != API_ALSA)
758 {
759 error("restart-audio: implemented for ALSA only.");
760 return;
761 }
762 memset(alsa_snd_buf, 0,
763 sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * sys_outchannels);
764 for (i = 0; i < 1000000; i++)
765 {
766 if (alsa_device.outnoninterleave)
767 result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
768 DEFDACBLKSIZE);
769 else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
770 DEFDACBLKSIZE);
771 if (result != (int)DEFDACBLKSIZE)
772 break;
773 }
774 post("%d written", i);
775}
776
777void alsa_putzeros(int n)
778{
779 int i, result;
780 memset(alsa_snd_buf, 0,
781 sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * alsa_outchannels);
782 for (i = 0; i < n; i++)
783 {
784 if (alsa_device.outnoninterleave)
785 result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
786 DEFDACBLKSIZE);
787 else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
788 DEFDACBLKSIZE);
789#if 0
790 if (result != DEFDACBLKSIZE)
791 post("result %d", result);
792#endif
793 }
794 /* post ("putzeros %d", n); */
795}
796
797void alsa_getzeros(int n)
798{
799 int i, result;
800 for (i = 0; i < n; i++)
801 {
802 result = snd_pcm_readi(alsa_device.inhandle, alsa_snd_buf,
803 DEFDACBLKSIZE);
804#if 0
805 if (result != DEFDACBLKSIZE)
806 post("result %d", result);
807#endif
808 }
809 /* post ("getzeros %d", n); */
810}
811
812 /* call this only if both input and output are open */
813static void alsa_checkiosync( void)
814{
815 int i, result, checkit = 1, giveup = 1000, alreadylogged = 0;
816 snd_pcm_sframes_t indelay, outdelay, defect;
817
818 if (!(alsa_outchannels && alsa_inchannels))
819 return;
820 while (checkit)
821 {
822 checkit = 0;
823 if (giveup-- <= 0)
824 return;
825 result = snd_pcm_delay(alsa_device.outhandle, &outdelay);
826 if (result < 0)
827 {
828 post("output snd_pcm_delay failed: %s", snd_strerror(result));
829 if (snd_pcm_status(alsa_device.outhandle, out_status) < 0)
830 post("output snd_pcm_status failed");
831 else post("astate %d",
832 snd_pcm_status_get_state(out_status));
833 return;
834 }
835 if (outdelay < 0)
836 sys_log_error(ERR_DATALATE), alreadylogged = 1;
837
838 if (sys_inchannels)
839 {
840 result = snd_pcm_delay(alsa_device.inhandle, &indelay);
841 if (result < 0)
842 {
843 post("input snd_pcm_delay failed");
844 return;
845 }
846 defect = indelay + outdelay - alsa_buf_samps;
847 if (defect < -(3 * DEFDACBLKSIZE / 2) )
848 {
849 checkit = 1;
850 alsa_putzeros(1);
851 if (!alreadylogged)
852 sys_log_error(ERR_RESYNC), alreadylogged = 1;
853 }
854 else if (defect > 0)
855 {
856 checkit = 1;
857 alsa_getzeros(1);
858 if (!alreadylogged)
859 sys_log_error(ERR_RESYNC), alreadylogged = 1;
860 }
861 /* if (alreadylogged)
862 post("in %d out %d defect %d", indelay, outdelay, defect); */
863 }
864 }
865}
866
867static int alsa_nnames = 0;
868static char **alsa_names = 0;
869
870void alsa_adddev(char *name)
871{
872 if (alsa_nnames)
873 alsa_names = (char **)t_resizebytes(alsa_names,
874 alsa_nnames * sizeof(char *),
875 (alsa_nnames+1) * sizeof(char *));
876 else alsa_names = (char **)t_getbytes(sizeof(char *));
877 alsa_names[alsa_nnames] = gensym(name)->s_name;
878 alsa_nnames++;
879}
880
881static void alsa_numbertoname(int devno, char *devname, int nchar)
882{
883 int ndev = 0, cardno = -1;
884 while (!snd_card_next(&cardno) && cardno >= 0)
885 ndev++;
886 if (devno < 2*ndev)
887 {
888 if (devno & 1)
889 snprintf(devname, nchar, "plughw:%d", devno/2);
890 else snprintf(devname, nchar, "hw:%d", devno/2);
891 }
892 else if (devno <2*ndev + alsa_nnames)
893 snprintf(devname, nchar, "%s", alsa_names[devno - 2*ndev]);
894 else snprintf(devname, nchar, "???");
895}
896
897 /* For each hardware card found, we list two devices, the "hard" and
898 "plug" one. The card scan is derived from portaudio code. */
899void alsa_getdevs(char *indevlist, int *nindevs,
900 char *outdevlist, int *noutdevs, int *canmulti,
901 int maxndev, int devdescsize)
902{
903 int ndev = 0, cardno = -1, i, j;
904 *canmulti = 0; /* only one device; must be the same for input&output */
905 while (!snd_card_next(&cardno) && cardno >= 0)
906 {
907 snd_ctl_t *ctl;
908 snd_ctl_card_info_t *info;
909 char devname[80];
910 const char *desc;
911 if (2 * ndev + 2 > maxndev)
912 break;
913 /* apparently, "cardno" is just a counter; but check that here */
914 if (ndev != cardno)
915 fprintf(stderr, "oops: ALSA cards not reported in order?\n");
916 sprintf(devname, "hw:%d", cardno );
917 /* fprintf(stderr, "\ntry %s...\n", devname); */
918 if (snd_ctl_open(&ctl, devname, 0) >= 0)
919 {
920 snd_ctl_card_info_malloc(&info);
921 snd_ctl_card_info(ctl, info);
922 desc = snd_ctl_card_info_get_name(info);
923 snd_ctl_card_info_free(info);
924 }
925 else
926 {
927 fprintf(stderr, "ALSA card scan error\n");
928 desc = "???";
929 }
930 /* fprintf(stderr, "name: %s\n", snd_ctl_card_info_get_name(info)); */
931 sprintf(indevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
932 sprintf(indevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc);
933 sprintf(outdevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
934 sprintf(outdevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc);
935 ndev++;
936 }
937 for (i = 0, j = 2*ndev; i < alsa_nnames; i++, j++)
938 {
939 if (j >= maxndev)
940 break;
941 snprintf(indevlist + j * devdescsize, devdescsize, "%s",
942 alsa_names[i]);
943 }
944 *nindevs = *noutdevs = j;
945}
946/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
947* Winfried Ritsch, Karl MacMillan, and others.
948* For information on usage and redistribution, and for a DISCLAIMER OF ALL
949* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
950
951/* this file inputs and outputs audio using the ALSA API available on linux. */
952
953#include <alsa/asoundlib.h>
954
955#include "m_pd.h"
956#include "s_stuff.h"
957#include <errno.h>
958#include <stdio.h>
959#include <unistd.h>
960#include <stdlib.h>
961#include <string.h>
962#include <sys/types.h>
963#include <sys/time.h>
964#include <sys/stat.h>
965#include <sys/ioctl.h>
966#include <fcntl.h>
967#include <sched.h>
968#include <sys/mman.h>
969
970typedef int16_t t_alsa_sample16;
971typedef int32_t t_alsa_sample32;
972#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16)
973#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
974#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DEFDACBLKSIZE)
975#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DEFDACBLKSIZE)
976#define ALSA_MAXDEV 1
977#define ALSA_JITTER 1024
978#define ALSA_EXTRABUFFER 2048
979#define ALSA_DEFFRAGSIZE 64
980#define ALSA_DEFNFRAG 12
981
982#ifndef INT32_MAX
983#define INT32_MAX 0x7fffffff
984#endif
985
986#if (SND_LIB_MAJOR < 1)
987#define ALSAAPI9
988#endif
989
990typedef struct _alsa_dev
991{
992 snd_pcm_t *inhandle;
993 snd_pcm_t *outhandle;
994 int innoninterleave; /* true if we're set for noninterleaved read */
995 int outnoninterleave; /* same for write */
996} t_alsa_dev;
997
998t_alsa_dev alsa_device;
999static void *alsa_snd_buf = 0;
1000static void **alsa_buf_ptrs;
1001static int alsa_samplewidth;
1002static snd_pcm_status_t* in_status;
1003static snd_pcm_status_t* out_status;
1004
1005static int alsa_mode;
1006static int alsa_buf_samps; /* believed actual ALSA bufsize in sample frames */
1007static int alsa_inchannels;
1008static int alsa_outchannels;
1009
1010/* Defines */
1011#define DEBUG(x) x
1012#define DEBUG2(x) {x;}
1013
1014static void alsa_checkiosync( void);
1015static void alsa_numbertoname(int devno, char *devname, int nchar);
1016
1017 /* don't assume we can turn all 31 bits when doing float-to-fix;
1018 otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
1019#define FMAX 0x7ffff000
1020#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
1021
1022/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */
1023
1024static void check_error(int err, const char *why)
1025{
1026 if (err < 0)
1027 fprintf(stderr, "%s: %s\n", why, snd_strerror(err));
1028}
1029
1030/* was: alsa_open_audio(int wantinchans, int wantoutchans, int srate) */
1031
1032int alsa_open_audio(int naudioindev, int *audioindev, int nchindev,
1033 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
1034 int *choutdev, int rate)
1035{
1036 int err, inchans = 0, outchans = 0, subunitdir;
1037 char devname[512];
1038 snd_pcm_hw_params_t* hw_params;
1039 snd_pcm_sw_params_t* sw_params;
1040 snd_output_t* out;
1041 int frag_size = (sys_blocksize ? sys_blocksize : ALSA_DEFFRAGSIZE);
1042 int nfrags, i;
1043 short* tmp_buf;
1044 unsigned int tmp_uint;
1045 snd_pcm_uframes_t tmp_snd_pcm_uframes;
1046 int wantinchans, wantoutchans, devno;
1047
1048 if (naudioindev >= 2 || naudiooutdev >= 2)
1049 post("alsa: only one input and output device allowed (extras ignored");
1050 if (naudioindev >= 1 && naudiooutdev >= 1 &&
1051 audioindev[0] != audiooutdev[0])
1052 post("alsa: changing output device to agree with input device");
1053 if (nchindev)
1054 wantinchans = chindev[0];
1055 else wantinchans = (naudioindev ? 2 : 0);
1056 if (nchoutdev)
1057 wantoutchans = choutdev[0];
1058 else wantoutchans = (naudiooutdev ? 2 : 0);
1059 devno = (naudioindev > 0 ? audioindev[0] :
1060 (naudiooutdev > 0 ? audiooutdev[0] : 0));
1061
1062 alsa_numbertoname(devno, devname, 512);
1063
1064 if (sys_verbose)
1065 post("device name %s; channels in %d, out %d", devname, wantinchans,
1066 wantoutchans);
1067
1068 nfrags = sys_schedadvance * (float)rate / (1e6 * frag_size);
1069 /* save our belief as to ALSA's buffer size for later */
1070 alsa_buf_samps = nfrags * frag_size;
1071
1072 if (sys_verbose)
1073 post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));
1074
1075 alsa_device.innoninterleave = alsa_device.outnoninterleave = 0;
1076 if (wantinchans)
1077 {
1078 err = snd_pcm_open(&alsa_device.inhandle, devname,
1079 SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
1080
1081 check_error(err, "snd_pcm_open (input)");
1082 if (err < 0)
1083 inchans = 0;
1084 else
1085 {
1086 inchans = wantinchans;
1087 snd_pcm_nonblock(alsa_device.inhandle, 1);
1088 }
1089 }
1090 if (wantoutchans)
1091 {
1092 err = snd_pcm_open(&alsa_device.outhandle, devname,
1093 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
1094
1095 check_error(err, "snd_pcm_open (output)");
1096 if (err < 0)
1097 outchans = 0;
1098 else
1099 {
1100 outchans = wantoutchans;
1101 snd_pcm_nonblock(alsa_device.outhandle, 1);
1102 }
1103 }
1104 if (inchans)
1105 {
1106 if (sys_verbose)
1107 post("opening sound input...");
1108 err = snd_pcm_hw_params_malloc(&hw_params);
1109 check_error(err, "snd_pcm_hw_params_malloc (input)");
1110
1111 // get the default params
1112 err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params);
1113 check_error(err, "snd_pcm_hw_params_any (input)");
1114
1115 /* try to set interleaved access */
1116 err = snd_pcm_hw_params_set_access(alsa_device.inhandle,
1117 hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1118 if (err < 0)
1119 {
1120 /* OK, so try non-interleaved */
1121 err = snd_pcm_hw_params_set_access(alsa_device.inhandle,
1122 hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
1123 if (err >= 0)
1124 {
1125 post("using non-interleaved audio input");
1126 alsa_device.innoninterleave = 1;
1127 }
1128 }
1129 check_error(err, "snd_pcm_hw_params_set_access (input)");
1130 // Try to set 32 bit format first
1131 err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
1132 SND_PCM_FORMAT_S32);
1133 if (err < 0)
1134 {
1135 /* fprintf(stderr,
1136 "PD-ALSA: 32 bit format not available - using 16\n"); */
1137 err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
1138 SND_PCM_FORMAT_S16);
1139 check_error(err, "snd_pcm_hw_params_set_format (input)");
1140 alsa_samplewidth = 2;
1141 }
1142 else
1143 {
1144 alsa_samplewidth = 4;
1145 }
1146 post("Sample width set to %d bytes", alsa_samplewidth);
1147 // set the subformat
1148 err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params,
1149 SND_PCM_SUBFORMAT_STD);
1150 check_error(err, "snd_pcm_hw_params_set_subformat (input)");
1151 // set the number of channels
1152 tmp_uint = inchans;
1153 err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle,
1154 hw_params, &tmp_uint);
1155 check_error(err, "snd_pcm_hw_params_set_channels (input)");
1156 if (tmp_uint != (unsigned)inchans)
1157 post("ALSA: set input channels to %d", tmp_uint);
1158 inchans = tmp_uint;
1159 // set the sampling rate
1160 err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params,
1161 &rate, 0);
1162 check_error(err, "snd_pcm_hw_params_set_rate_min (input)");
1163#if 0
1164 err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
1165 post("input sample rate %d", err);
1166#endif
1167 // set the period - ie frag size
1168 // post("fragsize a %d", frag_size);
1169
1170 /* LATER try this to get a recommended period size...
1171 right now, it trips an assertion failure in ALSA lib */
1172#if 0
1173 post("input period was %d, min %d, max %d\n",
1174 snd_pcm_hw_params_get_period_size(hw_params, 0),
1175 snd_pcm_hw_params_get_period_size_min(hw_params, 0),
1176 snd_pcm_hw_params_get_period_size_max(hw_params, 0));
1177#endif
1178#ifdef ALSAAPI9
1179 err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
1180 hw_params,
1181 (snd_pcm_uframes_t)
1182 frag_size, 0);
1183#else
1184 tmp_snd_pcm_uframes = frag_size;
1185 err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
1186 hw_params, &tmp_snd_pcm_uframes, 0);
1187#endif
1188 check_error(err, "snd_pcm_hw_params_set_period_size_near (input)");
1189 // post("fragsize b %d", frag_size);
1190 // set the number of periods - ie numfrags
1191 // post("nfrags a %d", nfrags);
1192#ifdef ALSAAPI9
1193 err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
1194 hw_params, nfrags, 0);
1195#else
1196 tmp_uint = nfrags;
1197 err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
1198 hw_params, &tmp_uint, 0);
1199#endif
1200 check_error(err, "snd_pcm_hw_params_set_periods_near (input)");
1201 // set the buffer size
1202#ifdef ALSAAPI9
1203 err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
1204 hw_params, nfrags * frag_size);
1205#else
1206 tmp_snd_pcm_uframes = nfrags * frag_size;
1207 err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
1208 hw_params, &tmp_snd_pcm_uframes);
1209#endif
1210 check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)");
1211
1212 err = snd_pcm_hw_params(alsa_device.inhandle, hw_params);
1213 check_error(err, "snd_pcm_hw_params (input)");
1214
1215 snd_pcm_hw_params_free(hw_params);
1216
1217 err = snd_pcm_sw_params_malloc(&sw_params);
1218 check_error(err, "snd_pcm_sw_params_malloc (input)");
1219 err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params);
1220 check_error(err, "snd_pcm_sw_params_current (input)");
1221 err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
1222 sw_params, nfrags * frag_size);
1223 check_error(err, "snd_pcm_sw_params_set_start_threshold (input)");
1224 err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
1225 sw_params, 0x7fffffff);
1226 check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)");
1227 err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params,
1228 frag_size);
1229 check_error(err, "snd_pcm_sw_params_set_avail_min (input)");
1230 err = snd_pcm_sw_params(alsa_device.inhandle, sw_params);
1231 check_error(err, "snd_pcm_sw_params (input)");
1232
1233 snd_pcm_sw_params_free(sw_params);
1234
1235 snd_output_stdio_attach(&out, stderr, 0);
1236#if 0
1237 if (sys_verbose)
1238 {
1239 snd_pcm_dump_hw_setup(alsa_device.inhandle, out);
1240 snd_pcm_dump_sw_setup(alsa_device.inhandle, out);
1241 }
1242#endif
1243 }
1244
1245 if (outchans)
1246 {
1247 int foo;
1248 if (sys_verbose)
1249 post("opening sound output...");
1250 err = snd_pcm_hw_params_malloc(&hw_params);
1251 check_error(err, "snd_pcm_sw_params (output)");
1252
1253 // get the default params
1254 err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params);
1255 check_error(err, "snd_pcm_hw_params_any (output)");
1256 // set interleaved access - FIXME deal with other access types
1257 err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params,
1258 SND_PCM_ACCESS_RW_INTERLEAVED);
1259 check_error(err, "snd_pcm_hw_params_set_access (output)");
1260
1261 /* try to set interleaved access */
1262 err = snd_pcm_hw_params_set_access(alsa_device.outhandle,
1263 hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1264 if (err < 0)
1265 {
1266 /* OK, so try non-interleaved */
1267 err = snd_pcm_hw_params_set_access(alsa_device.outhandle,
1268 hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
1269 if (err >= 0)
1270 {
1271 post("using non-interleaved audio");
1272 alsa_device.outnoninterleave = 1;
1273 }
1274 }
1275 check_error(err, "snd_pcm_hw_params_set_access (output)");
1276
1277
1278 // Try to set 32 bit format first
1279 err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params,
1280 SND_PCM_FORMAT_S32);
1281 if (err < 0)
1282 {
1283 err = snd_pcm_hw_params_set_format(alsa_device.outhandle,
1284 hw_params,SND_PCM_FORMAT_S16);
1285 check_error(err, "snd_pcm_hw_params_set_format (output)");
1286 /* fprintf(stderr,
1287 "PD-ALSA: 32 bit format not available - using 16\n"); */
1288 alsa_samplewidth = 2;
1289 }
1290 else
1291 {
1292 alsa_samplewidth = 4;
1293 }
1294 // set the subformat
1295 err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params,
1296 SND_PCM_SUBFORMAT_STD);
1297 check_error(err, "snd_pcm_hw_params_set_subformat (output)");
1298 // set the number of channels
1299 tmp_uint = outchans;
1300 err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle,
1301 hw_params, &tmp_uint);
1302 check_error(err, "snd_pcm_hw_params_set_channels (output)");
1303 if (tmp_uint != (unsigned)outchans)
1304 post("alsa: set output channels to %d", tmp_uint);
1305 outchans = tmp_uint;
1306 // set the sampling rate
1307 err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params,
1308 &rate, 0);
1309 check_error(err, "snd_pcm_hw_params_set_rate_min (output)");
1310#if 0
1311 err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
1312 post("output sample rate %d", err);
1313#endif
1314 // set the period - ie frag size
1315#if 0
1316 post("output period was %d, min %d, max %d\n",
1317 snd_pcm_hw_params_get_period_size(hw_params, 0),
1318 snd_pcm_hw_params_get_period_size_min(hw_params, 0),
1319 snd_pcm_hw_params_get_period_size_max(hw_params, 0));
1320#endif
1321 // post("fragsize c %d", frag_size);
1322#ifdef ALSAAPI9
1323 err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
1324 hw_params,
1325 (snd_pcm_uframes_t)
1326 frag_size, 0);
1327#else
1328 tmp_snd_pcm_uframes = frag_size;
1329 err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
1330 hw_params, &tmp_snd_pcm_uframes, 0);
1331#endif
1332 // post("fragsize d %d", frag_size);
1333 check_error(err, "snd_pcm_hw_params_set_period_size_near (output)");
1334 // set the number of periods - ie numfrags
1335#ifdef ALSAAPI9
1336 err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
1337 hw_params, nfrags, 0);
1338#else
1339 tmp_uint = nfrags;
1340 err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
1341 hw_params, &tmp_uint, 0);
1342#endif
1343 check_error(err, "snd_pcm_hw_params_set_periods_near (output)");
1344 // set the buffer size
1345#ifdef ALSAAPI9
1346 err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
1347 hw_params, nfrags * frag_size);
1348#else
1349 tmp_snd_pcm_uframes = nfrags * frag_size;
1350 err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
1351 hw_params, &tmp_snd_pcm_uframes);
1352#endif
1353 check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)");
1354
1355 err = snd_pcm_hw_params(alsa_device.outhandle, hw_params);
1356 check_error(err, "snd_pcm_hw_params (output)");
1357
1358 snd_pcm_hw_params_free(hw_params);
1359
1360 err = snd_pcm_sw_params_malloc(&sw_params);
1361 check_error(err, "snd_pcm_sw_params_malloc (output)");
1362 err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params);
1363 check_error(err, "snd_pcm_sw_params_current (output)");
1364 err = snd_pcm_sw_params_set_start_threshold(alsa_device.outhandle,
1365 sw_params, nfrags * frag_size);
1366 check_error(err, "snd_pcm_sw_params_set_start_threshold (output)");
1367 err = snd_pcm_sw_params_set_stop_threshold(alsa_device.outhandle,
1368 sw_params, 0x7fffffff);
1369 check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)");
1370 err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params,
1371 frag_size);
1372 check_error(err, "snd_pcm_sw_params_set_avail_min (output)");
1373 err = snd_pcm_sw_params(alsa_device.outhandle, sw_params);
1374 check_error(err, "snd_pcm_sw_params (output)");
1375 snd_pcm_sw_params_free(sw_params);
1376
1377 snd_output_stdio_attach(&out, stderr, 0);
1378#if 0
1379 if (sys_verbose)
1380 {
1381 snd_pcm_dump_hw_setup(alsa_device.outhandle, out);
1382 snd_pcm_dump_sw_setup(alsa_device.outhandle, out);
1383 }
1384#endif
1385 }
1386
1387 if (inchans)
1388 snd_pcm_prepare(alsa_device.inhandle);
1389 if (outchans)
1390 snd_pcm_prepare(alsa_device.outhandle);
1391
1392 // if duplex we can link the channels so they start together
1393 if (inchans && outchans)
1394 snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle);
1395
1396 // set up the status variables
1397 err = snd_pcm_status_malloc(&in_status);
1398 check_error(err, "snd_pcm_status_malloc");
1399 err = snd_pcm_status_malloc(&out_status);
1400 check_error(err, "snd_pcm_status_malloc");
1401
1402 // set up the buffer
1403 if (alsa_snd_buf)
1404 free(alsa_snd_buf);
1405 alsa_snd_buf = (void *)malloc(
1406 sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE *
1407 (outchans > inchans ? outchans : inchans));
1408 memset(alsa_snd_buf, 0, sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE *
1409 (outchans > inchans ? outchans : inchans));
1410 /* make an array of pointers too in case we need them */
1411 if (alsa_buf_ptrs)
1412 free(alsa_buf_ptrs);
1413 alsa_buf_ptrs = (void **)malloc(
1414 sizeof(void *) * (outchans > inchans ? outchans : inchans));
1415 for (i = 0; i < (outchans > inchans ? outchans : inchans); i++)
1416 alsa_buf_ptrs[i] = (t_alsa_sample32 *)alsa_snd_buf + i * DEFDACBLKSIZE;
1417
1418 // fill the buffer with silence
1419 if (outchans)
1420 {
1421 i = (frag_size * nfrags)/DEFDACBLKSIZE + 1;
1422 while (i--)
1423 {
1424 if (alsa_device.outnoninterleave)
1425 snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
1426 DEFDACBLKSIZE);
1427 else snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
1428 DEFDACBLKSIZE);
1429 }
1430 /* confused about this: */
1431 /* if ((err = snd_pcm_start(alsa_device.outhandle) < 0))
1432 check_error(err, "output start failed\n"); */
1433 }
1434 else if (inchans)
1435 {
1436 if (snd_pcm_start(alsa_device.inhandle) < 0)
1437 check_error(err, "input start failed\n");
1438 }
1439 alsa_outchannels = outchans;
1440 alsa_inchannels = inchans;
1441
1442 return (!(inchans || outchans));
1443}
1444
1445void alsa_close_audio(void)
1446{
1447 int err;
1448 if (alsa_inchannels)
1449 {
1450 err = snd_pcm_close(alsa_device.inhandle);
1451 check_error(err, "snd_pcm_close (input)");
1452 }
1453 if (alsa_outchannels)
1454 {
1455 err = snd_pcm_close(alsa_device.outhandle);
1456 check_error(err, "snd_pcm_close (output)");
1457 }
1458}
1459
1460// #define DEBUG_ALSA_XFER
1461
1462int alsa_send_dacs(void)
1463{
1464 static int16_t *sp;
1465 static int xferno = 0;
1466 static int callno = 0;
1467 static double timenow;
1468 double timelast;
1469 t_sample *fp, *fp1, *fp2;
1470 int i, j, k, err, devno = 0;
1471 int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0;
1472 int result;
1473 int inchannels = (sys_inchannels > alsa_inchannels ?
1474 alsa_inchannels : sys_inchannels);
1475 int outchannels = (sys_outchannels > alsa_outchannels ?
1476 alsa_outchannels : sys_outchannels);
1477 unsigned int intransfersize = DEFDACBLKSIZE;
1478 unsigned int outtransfersize = DEFDACBLKSIZE;
1479
1480 // get the status
1481 if (!inchannels && !outchannels)
1482 {
1483 return SENDDACS_NO;
1484 }
1485
1486 timelast = timenow;
1487 timenow = sys_getrealtime();
1488
1489#ifdef DEBUG_ALSA_XFER
1490 if (timenow - timelast > 0.050)
1491 fprintf(stderr, "(%d)",
1492 (int)(1000 * (timenow - timelast))), fflush(stderr);
1493#endif
1494
1495 callno++;
1496
1497 alsa_checkiosync(); /* check I/O are in sync and data not late */
1498
1499 if (alsa_inchannels)
1500 {
1501 snd_pcm_status(alsa_device.inhandle, in_status);
1502 if (snd_pcm_status_get_avail(in_status) < intransfersize)
1503 return SENDDACS_NO;
1504 }
1505 if (alsa_outchannels)
1506 {
1507 snd_pcm_status(alsa_device.outhandle, out_status);
1508 if (snd_pcm_status_get_avail(out_status) < outtransfersize)
1509 return SENDDACS_NO;
1510 }
1511
1512 /* do output */
1513 if (alsa_outchannels)
1514 {
1515 fp = sys_soundout;
1516 if (alsa_samplewidth == 4)
1517 {
1518 if (alsa_device.outnoninterleave)
1519 {
1520 int n = outchannels * DEFDACBLKSIZE;
1521 for (i = 0, fp1 = fp; i < n; i++)
1522 {
1523 float s1 = *fp1 * INT32_MAX;
1524 ((t_alsa_sample32 *)alsa_snd_buf)[i] = CLIP32(s1);
1525 }
1526 n = alsa_outchannels * DEFDACBLKSIZE;
1527 for (; i < n; i++)
1528 ((t_alsa_sample32 *)alsa_snd_buf)[i] = 0;
1529 }
1530 else
1531 {
1532 for (i = 0, fp1 = fp; i < outchannels; i++,
1533 fp1 += DEFDACBLKSIZE)
1534 {
1535 for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
1536 j += alsa_outchannels, fp2++)
1537 {
1538 float s1 = *fp2 * INT32_MAX;
1539 ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1);
1540 }
1541 }
1542 }
1543 }
1544 else
1545 {
1546 for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DEFDACBLKSIZE)
1547 {
1548 for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
1549 j += alsa_outchannels, fp2++)
1550 {
1551 int s = *fp2 * 32767.;
1552 if (s > 32767)
1553 s = 32767;
1554 else if (s < -32767)
1555 s = -32767;
1556 ((t_alsa_sample16 *)alsa_snd_buf)[j] = s;
1557 }
1558 }
1559 }
1560
1561 if (alsa_device.outnoninterleave)
1562 result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
1563 outtransfersize);
1564 else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
1565 outtransfersize);
1566
1567 if (result != (int)outtransfersize)
1568 {
1569 #ifdef DEBUG_ALSA_XFER
1570 if (result >= 0 || errno == EAGAIN)
1571 fprintf(stderr, "ALSA: write returned %d of %d\n",
1572 result, outtransfersize);
1573 else fprintf(stderr, "ALSA: write: %s\n",
1574 snd_strerror(errno));
1575 fprintf(stderr,
1576 "inputcount %d, outputcount %d, outbufsize %d\n",
1577 inputcount, outputcount,
1578 (ALSA_EXTRABUFFER + sys_advance_samples)
1579 * alsa_samplewidth * outchannels);
1580 #endif
1581 sys_log_error(ERR_DACSLEPT);
1582 return (SENDDACS_NO);
1583 }
1584
1585 /* zero out the output buffer */
1586 memset(sys_soundout, 0, DEFDACBLKSIZE * sizeof(*sys_soundout) *
1587 sys_outchannels);
1588 if (sys_getrealtime() - timenow > 0.002)
1589 {
1590 #ifdef DEBUG_ALSA_XFER
1591 fprintf(stderr, "output %d took %d msec\n",
1592 callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
1593 #endif
1594 timenow = sys_getrealtime();
1595 sys_log_error(ERR_DACSLEPT);
1596 }
1597 }
1598 /* do input */
1599 if (alsa_inchannels)
1600 {
1601 if (alsa_device.innoninterleave)
1602 result = snd_pcm_readn(alsa_device.inhandle, alsa_buf_ptrs,
1603 intransfersize);
1604 else result = snd_pcm_readi(alsa_device.inhandle, alsa_snd_buf,
1605 intransfersize);
1606 if (result < (int)intransfersize)
1607 {
1608#ifdef DEBUG_ALSA_XFER
1609 if (result < 0)
1610 fprintf(stderr,
1611 "snd_pcm_read %d %d: %s\n",
1612 callno, xferno, snd_strerror(errno));
1613 else fprintf(stderr,
1614 "snd_pcm_read %d %d returned only %d\n",
1615 callno, xferno, result);
1616 fprintf(stderr,
1617 "inputcount %d, outputcount %d, inbufsize %d\n",
1618 inputcount, outputcount,
1619 (ALSA_EXTRABUFFER + sys_advance_samples)
1620 * alsa_samplewidth * inchannels);
1621#endif
1622 sys_log_error(ERR_ADCSLEPT);
1623 return (SENDDACS_NO);
1624 }
1625 fp = sys_soundin;
1626 if (alsa_samplewidth == 4)
1627 {
1628 if (alsa_device.innoninterleave)
1629 {
1630 int n = inchannels * DEFDACBLKSIZE;
1631 for (i = 0, fp1 = fp; i < n; i++)
1632 *fp1 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[i]
1633 * (1./ INT32_MAX);
1634 }
1635 else
1636 {
1637 for (i = 0, fp1 = fp; i < inchannels;
1638 i++, fp1 += DEFDACBLKSIZE)
1639 {
1640 for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
1641 j += alsa_inchannels, fp2++)
1642 *fp2 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[j]
1643 * (1./ INT32_MAX);
1644 }
1645 }
1646 }
1647 else
1648 {
1649 for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DEFDACBLKSIZE)
1650 {
1651 for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
1652 j += alsa_inchannels, fp2++)
1653 *fp2 = (float) ((t_alsa_sample16 *)alsa_snd_buf)[j]
1654 * 3.051850e-05;
1655 }
1656 }
1657 }
1658 xferno++;
1659 if (sys_getrealtime() - timenow > 0.002)
1660 {
1661#ifdef DEBUG_ALSA_XFER
1662 fprintf(stderr, "routine took %d msec\n",
1663 (int)(1000 * (sys_getrealtime() - timenow)));
1664#endif
1665 sys_log_error(ERR_ADCSLEPT);
1666 }
1667 return SENDDACS_YES;
1668}
1669
1670void alsa_printstate( void)
1671{
1672 int i, result;
1673 snd_pcm_sframes_t indelay, outdelay;
1674 if (sys_audioapi != API_ALSA)
1675 {
1676 error("restart-audio: implemented for ALSA only.");
1677 return;
1678 }
1679 if (sys_inchannels)
1680 {
1681 result = snd_pcm_delay(alsa_device.inhandle, &indelay);
1682 if (result < 0)
1683 post("snd_pcm_delay 1 failed");
1684 else post("in delay %d", indelay);
1685 }
1686 if (sys_outchannels)
1687 {
1688 result = snd_pcm_delay(alsa_device.outhandle, &outdelay);
1689 if (result < 0)
1690 post("snd_pcm_delay 2 failed");
1691 else post("out delay %d", outdelay);
1692 }
1693 post("sum %d (%d mod 64)\n", indelay + outdelay, (indelay+outdelay)%64);
1694
1695 post("buf samples %d", alsa_buf_samps);
1696}
1697
1698
1699void alsa_resync( void)
1700{
1701 int i, result;
1702 if (sys_audioapi != API_ALSA)
1703 {
1704 error("restart-audio: implemented for ALSA only.");
1705 return;
1706 }
1707 memset(alsa_snd_buf, 0,
1708 sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * sys_outchannels);
1709 for (i = 0; i < 1000000; i++)
1710 {
1711 if (alsa_device.outnoninterleave)
1712 result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
1713 DEFDACBLKSIZE);
1714 else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
1715 DEFDACBLKSIZE);
1716 if (result != (int)DEFDACBLKSIZE)
1717 break;
1718 }
1719 post("%d written", i);
1720}
1721
1722void alsa_putzeros(int n)
1723{
1724 int i, result;
1725 memset(alsa_snd_buf, 0,
1726 sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * alsa_outchannels);
1727 for (i = 0; i < n; i++)
1728 {
1729 if (alsa_device.outnoninterleave)
1730 result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
1731 DEFDACBLKSIZE);
1732 else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
1733 DEFDACBLKSIZE);
1734#if 0
1735 if (result != DEFDACBLKSIZE)
1736 post("result %d", result);
1737#endif
1738 }
1739 /* post ("putzeros %d", n); */
1740}
1741
1742void alsa_getzeros(int n)
1743{
1744 int i, result;
1745 for (i = 0; i < n; i++)
1746 {
1747 result = snd_pcm_readi(alsa_device.inhandle, alsa_snd_buf,
1748 DEFDACBLKSIZE);
1749#if 0
1750 if (result != DEFDACBLKSIZE)
1751 post("result %d", result);
1752#endif
1753 }
1754 /* post ("getzeros %d", n); */
1755}
1756
1757 /* call this only if both input and output are open */
1758static void alsa_checkiosync( void)
1759{
1760 int i, result, checkit = 1, giveup = 1000, alreadylogged = 0;
1761 snd_pcm_sframes_t indelay, outdelay, defect;
1762
1763 if (!(alsa_outchannels && alsa_inchannels))
1764 return;
1765 while (checkit)
1766 {
1767 checkit = 0;
1768 if (giveup-- <= 0)
1769 return;
1770 result = snd_pcm_delay(alsa_device.outhandle, &outdelay);
1771 if (result < 0)
1772 {
1773 post("output snd_pcm_delay failed: %s", snd_strerror(result));
1774 if (snd_pcm_status(alsa_device.outhandle, out_status) < 0)
1775 post("output snd_pcm_status failed");
1776 else post("astate %d",
1777 snd_pcm_status_get_state(out_status));
1778 return;
1779 }
1780 if (outdelay < 0)
1781 sys_log_error(ERR_DATALATE), alreadylogged = 1;
1782
1783 if (sys_inchannels)
1784 {
1785 result = snd_pcm_delay(alsa_device.inhandle, &indelay);
1786 if (result < 0)
1787 {
1788 post("input snd_pcm_delay failed");
1789 return;
1790 }
1791 defect = indelay + outdelay - alsa_buf_samps;
1792 if (defect < -(3 * DEFDACBLKSIZE / 2) )
1793 {
1794 checkit = 1;
1795 alsa_putzeros(1);
1796 if (!alreadylogged)
1797 sys_log_error(ERR_RESYNC), alreadylogged = 1;
1798 }
1799 else if (defect > 0)
1800 {
1801 checkit = 1;
1802 alsa_getzeros(1);
1803 if (!alreadylogged)
1804 sys_log_error(ERR_RESYNC), alreadylogged = 1;
1805 }
1806 /* if (alreadylogged)
1807 post("in %d out %d defect %d", indelay, outdelay, defect); */
1808 }
1809 }
1810}
1811
1812static int alsa_nnames = 0;
1813static char **alsa_names = 0;
1814
1815void alsa_adddev(char *name)
1816{
1817 if (alsa_nnames)
1818 alsa_names = (char **)t_resizebytes(alsa_names,
1819 alsa_nnames * sizeof(char *),
1820 (alsa_nnames+1) * sizeof(char *));
1821 else alsa_names = (char **)t_getbytes(sizeof(char *));
1822 alsa_names[alsa_nnames] = gensym(name)->s_name;
1823 alsa_nnames++;
1824}
1825
1826static void alsa_numbertoname(int devno, char *devname, int nchar)
1827{
1828 int ndev = 0, cardno = -1;
1829 while (!snd_card_next(&cardno) && cardno >= 0)
1830 ndev++;
1831 if (devno < 2*ndev)
1832 {
1833 if (devno & 1)
1834 snprintf(devname, nchar, "plughw:%d", devno/2);
1835 else snprintf(devname, nchar, "hw:%d", devno/2);
1836 }
1837 else if (devno <2*ndev + alsa_nnames)
1838 snprintf(devname, nchar, "%s", alsa_names[devno - 2*ndev]);
1839 else snprintf(devname, nchar, "???");
1840}
1841
1842 /* For each hardware card found, we list two devices, the "hard" and
1843 "plug" one. The card scan is derived from portaudio code. */
1844void alsa_getdevs(char *indevlist, int *nindevs,
1845 char *outdevlist, int *noutdevs, int *canmulti,
1846 int maxndev, int devdescsize)
1847{
1848 int ndev = 0, cardno = -1, i, j;
1849 *canmulti = 0; /* only one device; must be the same for input&output */
1850 while (!snd_card_next(&cardno) && cardno >= 0)
1851 {
1852 snd_ctl_t *ctl;
1853 snd_ctl_card_info_t *info;
1854 char devname[80];
1855 const char *desc;
1856 if (2 * ndev + 2 > maxndev)
1857 break;
1858 /* apparently, "cardno" is just a counter; but check that here */
1859 if (ndev != cardno)
1860 fprintf(stderr, "oops: ALSA cards not reported in order?\n");
1861 sprintf(devname, "hw:%d", cardno );
1862 /* fprintf(stderr, "\ntry %s...\n", devname); */
1863 if (snd_ctl_open(&ctl, devname, 0) >= 0)
1864 {
1865 snd_ctl_card_info_malloc(&info);
1866 snd_ctl_card_info(ctl, info);
1867 desc = snd_ctl_card_info_get_name(info);
1868 snd_ctl_card_info_free(info);
1869 }
1870 else
1871 {
1872 fprintf(stderr, "ALSA card scan error\n");
1873 desc = "???";
1874 }
1875 /* fprintf(stderr, "name: %s\n", snd_ctl_card_info_get_name(info)); */
1876 sprintf(indevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
1877 sprintf(indevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc);
1878 sprintf(outdevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
1879 sprintf(outdevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc);
1880 ndev++;
1881 }
1882 for (i = 0, j = 2*ndev; i < alsa_nnames; i++, j++)
1883 {
1884 if (j >= maxndev)
1885 break;
1886 snprintf(indevlist + j * devdescsize, devdescsize, "%s",
1887 alsa_names[i]);
1888 }
1889 *nindevs = *noutdevs = j;
1890}
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_mmio.c b/apps/plugins/pdbox/PDa/src/s_audio_mmio.c
new file mode 100644
index 0000000000..44bbae855b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_audio_mmio.c
@@ -0,0 +1,1588 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized
6"wave" devices, which is how ADAT boards appear to the WAVE API. */
7
8#include "m_pd.h"
9#include "s_stuff.h"
10#include <stdio.h>
11
12#include <windows.h>
13
14#include <MMSYSTEM.H>
15
16/* ------------------------- audio -------------------------- */
17
18static void nt_close_midiin(void);
19static void nt_noresync( void);
20
21static void postflags(void);
22
23#define NAPORTS 16 /* wini hack for multiple ADDA devices */
24#define CHANNELS_PER_DEVICE 2
25#define DEFAULTCHANS 2
26#define DEFAULTSRATE 44100
27#define SAMPSIZE 2
28
29int nt_realdacblksize;
30#define DEFREALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */
31
32#define MAXBUFFER 100 /* number of buffers in use at maximum advance */
33#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */
34static int nt_naudiobuffer = DEFBUFFER;
35float sys_dacsr = DEFAULTSRATE;
36
37static int nt_whichapi = API_MMIO;
38static int nt_meters; /* true if we're metering */
39static float nt_inmax; /* max input amplitude */
40static float nt_outmax; /* max output amplitude */
41static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
42
43typedef struct _sbuf
44{
45 HANDLE hData;
46 HPSTR lpData; // pointer to waveform data memory
47 HANDLE hWaveHdr;
48 WAVEHDR *lpWaveHdr; // pointer to header structure
49} t_sbuf;
50
51t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
52HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
53static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
54
55t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
56HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
57static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
58
59static void nt_waveinerror(char *s, int err)
60{
61 char t[256];
62 waveInGetErrorText(err, t, 256);
63 fprintf(stderr, s, t);
64}
65
66static void nt_waveouterror(char *s, int err)
67{
68 char t[256];
69 waveOutGetErrorText(err, t, 256);
70 fprintf(stderr, s, t);
71}
72
73static void wave_prep(t_sbuf *bp, int setdone)
74{
75 WAVEHDR *wh;
76 short *sp;
77 int i;
78 /*
79 * Allocate and lock memory for the waveform data. The memory
80 * for waveform data must be globally allocated with
81 * GMEM_MOVEABLE and GMEM_SHARE flags.
82 */
83
84 if (!(bp->hData =
85 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
86 (DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize))))
87 printf("alloc 1 failed\n");
88
89 if (!(bp->lpData =
90 (HPSTR) GlobalLock(bp->hData)))
91 printf("lock 1 failed\n");
92
93 /* Allocate and lock memory for the header. */
94
95 if (!(bp->hWaveHdr =
96 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
97 printf("alloc 2 failed\n");
98
99 if (!(wh = bp->lpWaveHdr =
100 (WAVEHDR *) GlobalLock(bp->hWaveHdr)))
101 printf("lock 2 failed\n");
102
103 for (i = CHANNELS_PER_DEVICE * nt_realdacblksize,
104 sp = (short *)bp->lpData; i--; )
105 *sp++ = 0;
106
107 wh->lpData = bp->lpData;
108 wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize);
109 wh->dwFlags = 0;
110 wh->dwLoops = 0L;
111 wh->lpNext = 0;
112 wh->reserved = 0;
113 /* optionally (for writing) set DONE flag as if we had queued them */
114 if (setdone)
115 wh->dwFlags = WHDR_DONE;
116}
117
118static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
119
120int mmio_do_open_audio(void)
121{
122 PCMWAVEFORMAT form;
123 int i, j;
124 UINT mmresult;
125 int nad, nda;
126 static int naudioprepped = 0, nindevsprepped = 0, noutdevsprepped = 0;
127 if (sys_verbose)
128 post("%d devices in, %d devices out",
129 nt_nwavein, nt_nwaveout);
130
131 form.wf.wFormatTag = WAVE_FORMAT_PCM;
132 form.wf.nChannels = CHANNELS_PER_DEVICE;
133 form.wf.nSamplesPerSec = sys_dacsr;
134 form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE);
135 form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE;
136 form.wBitsPerSample = 8 * SAMPSIZE;
137
138 if (nt_nwavein <= 1 && nt_nwaveout <= 1)
139 nt_noresync();
140
141 if (nindevsprepped < nt_nwavein)
142 {
143 for (i = nindevsprepped; i < nt_nwavein; i++)
144 for (j = 0; j < naudioprepped; j++)
145 wave_prep(&ntsnd_invec[i][j], 0);
146 nindevsprepped = nt_nwavein;
147 }
148 if (noutdevsprepped < nt_nwaveout)
149 {
150 for (i = noutdevsprepped; i < nt_nwaveout; i++)
151 for (j = 0; j < naudioprepped; j++)
152 wave_prep(&ntsnd_outvec[i][j], 1);
153 noutdevsprepped = nt_nwaveout;
154 }
155 if (naudioprepped < nt_naudiobuffer)
156 {
157 for (j = naudioprepped; j < nt_naudiobuffer; j++)
158 {
159 for (i = 0; i < nt_nwavein; i++)
160 wave_prep(&ntsnd_invec[i][j], 0);
161 for (i = 0; i < nt_nwaveout; i++)
162 wave_prep(&ntsnd_outvec[i][j], 1);
163 }
164 naudioprepped = nt_naudiobuffer;
165 }
166 for (nad=0; nad < nt_nwavein; nad++)
167 {
168 /* Open waveform device(s), sucessively numbered, for input */
169
170 mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad,
171 (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
172
173 if (sys_verbose)
174 printf("opened adc device %d with return %d\n",
175 nt_whichadc+nad,mmresult);
176
177 if (mmresult != MMSYSERR_NOERROR)
178 {
179 nt_waveinerror("waveInOpen: %s\n", mmresult);
180 nt_nwavein = nad; /* nt_nwavein = 0 wini */
181 }
182 else
183 {
184 for (i = 0; i < nt_naudiobuffer; i++)
185 {
186 mmresult = waveInPrepareHeader(ntsnd_indev[nad],
187 ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
188 if (mmresult != MMSYSERR_NOERROR)
189 nt_waveinerror("waveinprepareheader: %s\n", mmresult);
190 mmresult = waveInAddBuffer(ntsnd_indev[nad],
191 ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
192 if (mmresult != MMSYSERR_NOERROR)
193 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
194 }
195 }
196 }
197 /* quickly start them all together */
198 for (nad = 0; nad < nt_nwavein; nad++)
199 waveInStart(ntsnd_indev[nad]);
200
201 for (nda = 0; nda < nt_nwaveout; nda++)
202 {
203 /* Open a waveform device for output in sucessiv device numbering*/
204 mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda,
205 (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
206
207 if (sys_verbose)
208 fprintf(stderr,"opened dac device %d, with return %d\n",
209 nt_whichdac +nda, mmresult);
210
211 if (mmresult != MMSYSERR_NOERROR)
212 {
213 fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda);
214 nt_waveouterror("waveOutOpen device: %s\n", mmresult);
215 nt_nwaveout = nda;
216 }
217 }
218
219 return (0);
220}
221
222void mmio_close_audio( void)
223{
224 int errcode;
225 int nda, nad;
226 if (sys_verbose)
227 post("closing audio...");
228
229 for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */
230 {
231 errcode = waveOutReset(ntsnd_outdev[nda]);
232 if (errcode != MMSYSERR_NOERROR)
233 printf("error resetting output %d: %d\n", nda, errcode);
234 errcode = waveOutClose(ntsnd_outdev[nda]);
235 if (errcode != MMSYSERR_NOERROR)
236 printf("error closing output %d: %d\n",nda , errcode);
237 }
238 nt_nwaveout = 0;
239
240 for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */
241 {
242 errcode = waveInReset(ntsnd_indev[nad]);
243 if (errcode != MMSYSERR_NOERROR)
244 printf("error resetting input: %d\n", errcode);
245 errcode = waveInClose(ntsnd_indev[nad]);
246 if (errcode != MMSYSERR_NOERROR)
247 printf("error closing input: %d\n", errcode);
248 }
249 nt_nwavein = 0;
250}
251
252
253#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
254#define DACJITTER 10
255
256static int nt_adcjitterbufsallowed = ADCJITTER;
257static int nt_dacjitterbufsallowed = DACJITTER;
258
259 /* ------------- MIDI time stamping from audio clock ------------ */
260
261#ifdef MIDI_TIMESTAMP
262
263static double nt_hibuftime;
264static double initsystime = -1;
265
266 /* call this whenever we reset audio */
267static void nt_resetmidisync(void)
268{
269 initsystime = clock_getsystime();
270 nt_hibuftime = sys_getrealtime();
271}
272
273 /* call this whenever we're idled waiting for audio to be ready.
274 The routine maintains a high and low water point for the difference
275 between real and DAC time. */
276
277static void nt_midisync(void)
278{
279 double jittersec, diff;
280
281 if (initsystime == -1) nt_resetmidisync();
282 jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
283 nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
284 * nt_realdacblksize / sys_getsr();
285 diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
286 if (diff > nt_hibuftime) nt_hibuftime = diff;
287 if (diff < nt_hibuftime - jittersec)
288 {
289 post("jitter excess %d %f", dac, diff);
290 nt_resetmidisync();
291 }
292}
293
294static double nt_midigettimefor(LARGE_INTEGER timestamp)
295{
296 /* this is broken now... used to work when "timestamp" was derived from
297 QueryPerformanceCounter() instead of the gates approved
298 timeGetSystemTime() call in the MIDI callback routine below. */
299 return (nt_tixtotime(timestamp) - nt_hibuftime);
300}
301#endif /* MIDI_TIMESTAMP */
302
303
304static int nt_fill = 0;
305#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x))
306#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x))
307#define MAXRESYNC 500
308
309#if 0 /* this is used for debugging */
310static void nt_printaudiostatus(void)
311{
312 int nad, nda;
313 for (nad = 0; nad < nt_nwavein; nad++)
314 {
315 int phase = ntsnd_inphase[nad];
316 int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
317 int firstphasedone = -1, firstphasebusy = -1;
318 for (count = 0; count < nt_naudiobuffer; count++)
319 {
320 int donethis =
321 (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
322 int donenext =
323 (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
324 if (donethis && !donenext)
325 {
326 if (firstphasebusy >= 0) goto multipleadc;
327 firstphasebusy = count;
328 }
329 if (!donethis && donenext)
330 {
331 if (firstphasedone >= 0) goto multipleadc;
332 firstphasedone = count;
333 }
334 phase2 = phase3;
335 phase3 = WRAPFWD(phase2 + 1);
336 }
337 post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy,
338 firstphasedone);
339 continue;
340 multipleadc:
341 startpost("nad %d phase %d: oops:", nad, phase);
342 for (count = 0; count < nt_naudiobuffer; count++)
343 {
344 char buf[80];
345 sprintf(buf, " %d",
346 (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
347 poststring(buf);
348 }
349 endpost();
350 }
351 for (nda = 0; nda < nt_nwaveout; nda++)
352 {
353 int phase = ntsnd_outphase[nad];
354 int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
355 int firstphasedone = -1, firstphasebusy = -1;
356 for (count = 0; count < nt_naudiobuffer; count++)
357 {
358 int donethis =
359 (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
360 int donenext =
361 (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
362 if (donethis && !donenext)
363 {
364 if (firstphasebusy >= 0) goto multipledac;
365 firstphasebusy = count;
366 }
367 if (!donethis && donenext)
368 {
369 if (firstphasedone >= 0) goto multipledac;
370 firstphasedone = count;
371 }
372 phase2 = phase3;
373 phase3 = WRAPFWD(phase2 + 1);
374 }
375 if (firstphasebusy < 0) post("nda %d phase %d all %d",
376 nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE));
377 else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy,
378 firstphasedone);
379 continue;
380 multipledac:
381 startpost("nda %d phase %d: oops:", nda, phase);
382 for (count = 0; count < nt_naudiobuffer; count++)
383 {
384 char buf[80];
385 sprintf(buf, " %d",
386 (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
387 poststring(buf);
388 }
389 endpost();
390 }
391}
392#endif /* 0 */
393
394/* this is a hack to avoid ever resyncing audio pointers in case for whatever
395reason the sync testing below gives false positives. */
396
397static int nt_resync_cancelled;
398
399static void nt_noresync( void)
400{
401 nt_resync_cancelled = 1;
402}
403
404static void nt_resyncaudio(void)
405{
406 UINT mmresult;
407 int nad, nda, count;
408 if (nt_resync_cancelled)
409 return;
410 /* for each open input device, eat all buffers which are marked
411 ready. The next one will thus be "busy". */
412 post("resyncing audio");
413 for (nad = 0; nad < nt_nwavein; nad++)
414 {
415 int phase = ntsnd_inphase[nad];
416 for (count = 0; count < MAXRESYNC; count++)
417 {
418 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
419 if (!(inwavehdr->dwFlags & WHDR_DONE)) break;
420 if (inwavehdr->dwFlags & WHDR_PREPARED)
421 waveInUnprepareHeader(ntsnd_indev[nad],
422 inwavehdr, sizeof(WAVEHDR));
423 inwavehdr->dwFlags = 0L;
424 waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
425 mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr,
426 sizeof(WAVEHDR));
427 if (mmresult != MMSYSERR_NOERROR)
428 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
429 ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1);
430 }
431 if (count == MAXRESYNC) post("resync error 1");
432 }
433 /* Each output buffer which is "ready" is filled with zeros and
434 queued. */
435 for (nda = 0; nda < nt_nwaveout; nda++)
436 {
437 int phase = ntsnd_outphase[nda];
438 for (count = 0; count < MAXRESYNC; count++)
439 {
440 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
441 if (!(outwavehdr->dwFlags & WHDR_DONE)) break;
442 if (outwavehdr->dwFlags & WHDR_PREPARED)
443 waveOutUnprepareHeader(ntsnd_outdev[nda],
444 outwavehdr, sizeof(WAVEHDR));
445 outwavehdr->dwFlags = 0L;
446 memset((char *)(ntsnd_outvec[nda][phase].lpData),
447 0, (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize));
448 waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr,
449 sizeof(WAVEHDR));
450 mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr,
451 sizeof(WAVEHDR));
452 if (mmresult != MMSYSERR_NOERROR)
453 nt_waveouterror("waveOutAddBuffer: %s\n", mmresult);
454 ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1);
455 }
456 if (count == MAXRESYNC) post("resync error 2");
457 }
458
459#ifdef MIDI_TIMESTAMP
460 nt_resetmidisync();
461#endif
462
463}
464
465#define LATE 0
466#define RESYNC 1
467#define NOTHING 2
468static int nt_errorcount;
469static int nt_resynccount;
470static double nt_nextreporttime = -1;
471
472void nt_logerror(int which)
473{
474#if 0
475 post("error %d %d", count, which);
476 if (which < NOTHING) nt_errorcount++;
477 if (which == RESYNC) nt_resynccount++;
478 if (sys_getrealtime() > nt_nextreporttime)
479 {
480 post("%d audio I/O error%s", nt_errorcount,
481 (nt_errorcount > 1 ? "s" : ""));
482 if (nt_resynccount) post("DAC/ADC sync error");
483 nt_errorcount = nt_resynccount = 0;
484 nt_nextreporttime = sys_getrealtime() - 5;
485 }
486#endif
487}
488
489/* system buffer with t_sample types for one tick */
490t_sample *sys_soundout;
491t_sample *sys_soundin;
492float sys_dacsr;
493
494int mmio_send_dacs(void)
495{
496 HMMIO hmmio;
497 UINT mmresult;
498 HANDLE hFormat;
499 int i, j;
500 short *sp1, *sp2;
501 float *fp1, *fp2;
502 int nextfill, doxfer = 0;
503 int nda, nad;
504 if (!nt_nwavein && !nt_nwaveout) return (0);
505
506
507 if (nt_meters)
508 {
509 int i, n;
510 float maxsamp;
511 for (i = 0, n = 2 * nt_nwavein * DEFDACBLKSIZE, maxsamp = nt_inmax;
512 i < n; i++)
513 {
514 float f = sys_soundin[i];
515 if (f > maxsamp) maxsamp = f;
516 else if (-f > maxsamp) maxsamp = -f;
517 }
518 nt_inmax = maxsamp;
519 for (i = 0, n = 2 * nt_nwaveout * DEFDACBLKSIZE, maxsamp = nt_outmax;
520 i < n; i++)
521 {
522 float f = sys_soundout[i];
523 if (f > maxsamp) maxsamp = f;
524 else if (-f > maxsamp) maxsamp = -f;
525 }
526 nt_outmax = maxsamp;
527 }
528
529 /* the "fill pointer" nt_fill controls where in the next
530 I/O buffers we will write and/or read. If it's zero, we
531 first check whether the buffers are marked "done". */
532
533 if (!nt_fill)
534 {
535 for (nad = 0; nad < nt_nwavein; nad++)
536 {
537 int phase = ntsnd_inphase[nad];
538 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
539 if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
540 }
541 for (nda = 0; nda < nt_nwaveout; nda++)
542 {
543 int phase = ntsnd_outphase[nda];
544 WAVEHDR *outwavehdr =
545 ntsnd_outvec[nda][phase].lpWaveHdr;
546 if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
547 }
548 for (nad = 0; nad < nt_nwavein; nad++)
549 {
550 int phase = ntsnd_inphase[nad];
551 WAVEHDR *inwavehdr =
552 ntsnd_invec[nad][phase].lpWaveHdr;
553 if (inwavehdr->dwFlags & WHDR_PREPARED)
554 waveInUnprepareHeader(ntsnd_indev[nad],
555 inwavehdr, sizeof(WAVEHDR));
556 }
557 for (nda = 0; nda < nt_nwaveout; nda++)
558 {
559 int phase = ntsnd_outphase[nda];
560 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
561 if (outwavehdr->dwFlags & WHDR_PREPARED)
562 waveOutUnprepareHeader(ntsnd_outdev[nda],
563 outwavehdr, sizeof(WAVEHDR));
564 }
565 }
566
567 /* Convert audio output to fixed-point and put it in the output
568 buffer. */
569 for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++)
570 {
571 int phase = ntsnd_outphase[nda];
572
573 for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) +
574 CHANNELS_PER_DEVICE * nt_fill;
575 i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
576 {
577 for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
578 j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
579 {
580 int x1 = 32767.f * *fp2;
581 if (x1 > 32767) x1 = 32767;
582 else if (x1 < -32767) x1 = -32767;
583 *sp2 = x1;
584 }
585 }
586 }
587 memset(sys_soundout, 0,
588 (DEFDACBLKSIZE *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
589
590 /* vice versa for the input buffer */
591
592 for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++)
593 {
594 int phase = ntsnd_inphase[nad];
595
596 for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) +
597 CHANNELS_PER_DEVICE * nt_fill;
598 i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
599 {
600 for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
601 j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
602 {
603 *fp2 = ((float)(1./32767.)) * (float)(*sp2);
604 }
605 }
606 }
607
608 nt_fill = nt_fill + DEFDACBLKSIZE;
609 if (nt_fill == nt_realdacblksize)
610 {
611 nt_fill = 0;
612
613 for (nad = 0; nad < nt_nwavein; nad++)
614 {
615 int phase = ntsnd_inphase[nad];
616 HWAVEIN device = ntsnd_indev[nad];
617 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
618 waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR));
619 mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR));
620 if (mmresult != MMSYSERR_NOERROR)
621 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
622 ntsnd_inphase[nad] = WRAPFWD(phase + 1);
623 }
624 for (nda = 0; nda < nt_nwaveout; nda++)
625 {
626 int phase = ntsnd_outphase[nda];
627 HWAVEOUT device = ntsnd_outdev[nda];
628 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
629 waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR));
630 mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR));
631 if (mmresult != MMSYSERR_NOERROR)
632 nt_waveouterror("waveOutWrite: %s\n", mmresult);
633 ntsnd_outphase[nda] = WRAPFWD(phase + 1);
634 }
635
636 /* check for DAC underflow or ADC overflow. */
637 for (nad = 0; nad < nt_nwavein; nad++)
638 {
639 int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
640 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
641 if (inwavehdr->dwFlags & WHDR_DONE) goto late;
642 }
643 for (nda = 0; nda < nt_nwaveout; nda++)
644 {
645 int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
646 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
647 if (outwavehdr->dwFlags & WHDR_DONE) goto late;
648 }
649 }
650 return (1);
651
652late:
653
654 nt_logerror(LATE);
655 nt_resyncaudio();
656 return (1);
657
658idle:
659
660 /* If more than nt_adcjitterbufsallowed ADC buffers are ready
661 on any input device, resynchronize */
662
663 for (nad = 0; nad < nt_nwavein; nad++)
664 {
665 int phase = ntsnd_inphase[nad];
666 WAVEHDR *inwavehdr =
667 ntsnd_invec[nad]
668 [WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr;
669 if (inwavehdr->dwFlags & WHDR_DONE)
670 {
671 nt_resyncaudio();
672 return (0);
673 }
674 }
675
676 /* test dac sync the same way */
677 for (nda = 0; nda < nt_nwaveout; nda++)
678 {
679 int phase = ntsnd_outphase[nda];
680 WAVEHDR *outwavehdr =
681 ntsnd_outvec[nda]
682 [WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr;
683 if (outwavehdr->dwFlags & WHDR_DONE)
684 {
685 nt_resyncaudio();
686 return (0);
687 }
688 }
689#ifdef MIDI_TIMESTAMP
690 nt_midisync();
691#endif
692 return (0);
693}
694
695/* ------------------- public routines -------------------------- */
696
697void mmio_open_audio(int naudioindev, int *audioindev,
698 int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
699 int nchoutdev, int *choutdev, int rate) /* IOhannes */
700{
701 int nbuf;
702
703 nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE);
704 nbuf = sys_advance_samples/nt_realdacblksize;
705 if (nbuf >= MAXBUFFER)
706 {
707 fprintf(stderr, "pd: audio buffering maxed out to %d\n",
708 (int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.)));
709 nbuf = MAXBUFFER;
710 }
711 else if (nbuf < 4) nbuf = 4;
712 fprintf(stderr, "%d audio buffers\n", nbuf);
713 nt_naudiobuffer = nbuf;
714 if (nt_adcjitterbufsallowed > nbuf - 2)
715 nt_adcjitterbufsallowed = nbuf - 2;
716 if (nt_dacjitterbufsallowed > nbuf - 2)
717 nt_dacjitterbufsallowed = nbuf - 2;
718
719 nt_nwavein = sys_inchannels / 2;
720 nt_nwaveout = sys_outchannels / 2;
721 nt_whichadc = (naudioindev < 1 ?
722 (nt_nwavein > 1 ? WAVE_MAPPER : -1) : audioindev[0]);
723 nt_whichdac = (naudiooutdev < 1 ?
724 (nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]);
725 if (naudiooutdev > 1 || naudioindev > 1)
726 post("separate audio device choice not supported; using sequential devices.");
727 mmio_do_open_audio();
728}
729
730
731void mmio_reportidle(void)
732{
733}
734
735#if 0
736/* list the audio and MIDI device names */
737void mmio_listdevs(void)
738{
739 UINT wRtn, ndevices;
740 unsigned int i;
741
742 ndevices = waveInGetNumDevs();
743 for (i = 0; i < ndevices; i++)
744 {
745 WAVEINCAPS wicap;
746 wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap,
747 sizeof(wicap));
748 if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn);
749 else fprintf(stderr,
750 "audio input device #%d: %s\n", i+1, wicap.szPname);
751 }
752
753 ndevices = waveOutGetNumDevs();
754 for (i = 0; i < ndevices; i++)
755 {
756 WAVEOUTCAPS wocap;
757 wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap,
758 sizeof(wocap));
759 if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn);
760 else fprintf(stderr,
761 "audio output device #%d: %s\n", i+1, wocap.szPname);
762 }
763}
764#endif
765
766void mmio_getdevs(char *indevlist, int *nindevs,
767 char *outdevlist, int *noutdevs, int *canmulti,
768 int maxndev, int devdescsize)
769{
770 int wRtn, ndev, i;
771
772 *canmulti = 2; /* supports multiple devices */
773 ndev = waveInGetNumDevs();
774 if (ndev > maxndev)
775 ndev = maxndev;
776 *nindevs = ndev;
777 for (i = 0; i < ndev; i++)
778 {
779 WAVEINCAPS wicap;
780 wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap));
781 sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname));
782 }
783
784 ndev = waveOutGetNumDevs();
785 if (ndev > maxndev)
786 ndev = maxndev;
787 *noutdevs = ndev;
788 for (i = 0; i < ndev; i++)
789 {
790 WAVEOUTCAPS wocap;
791 wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap));
792 sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname));
793 }
794}
795/* Copyright (c) 1997-1999 Miller Puckette.
796* For information on usage and redistribution, and for a DISCLAIMER OF ALL
797* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
798
799/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized
800"wave" devices, which is how ADAT boards appear to the WAVE API. */
801
802#include "m_pd.h"
803#include "s_stuff.h"
804#include <stdio.h>
805
806#include <windows.h>
807
808#include <MMSYSTEM.H>
809
810/* ------------------------- audio -------------------------- */
811
812static void nt_close_midiin(void);
813static void nt_noresync( void);
814
815static void postflags(void);
816
817#define NAPORTS 16 /* wini hack for multiple ADDA devices */
818#define CHANNELS_PER_DEVICE 2
819#define DEFAULTCHANS 2
820#define DEFAULTSRATE 44100
821#define SAMPSIZE 2
822
823int nt_realdacblksize;
824#define DEFREALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */
825
826#define MAXBUFFER 100 /* number of buffers in use at maximum advance */
827#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */
828static int nt_naudiobuffer = DEFBUFFER;
829float sys_dacsr = DEFAULTSRATE;
830
831static int nt_whichapi = API_MMIO;
832static int nt_meters; /* true if we're metering */
833static float nt_inmax; /* max input amplitude */
834static float nt_outmax; /* max output amplitude */
835static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
836
837typedef struct _sbuf
838{
839 HANDLE hData;
840 HPSTR lpData; // pointer to waveform data memory
841 HANDLE hWaveHdr;
842 WAVEHDR *lpWaveHdr; // pointer to header structure
843} t_sbuf;
844
845t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
846HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
847static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
848
849t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
850HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
851static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
852
853static void nt_waveinerror(char *s, int err)
854{
855 char t[256];
856 waveInGetErrorText(err, t, 256);
857 fprintf(stderr, s, t);
858}
859
860static void nt_waveouterror(char *s, int err)
861{
862 char t[256];
863 waveOutGetErrorText(err, t, 256);
864 fprintf(stderr, s, t);
865}
866
867static void wave_prep(t_sbuf *bp, int setdone)
868{
869 WAVEHDR *wh;
870 short *sp;
871 int i;
872 /*
873 * Allocate and lock memory for the waveform data. The memory
874 * for waveform data must be globally allocated with
875 * GMEM_MOVEABLE and GMEM_SHARE flags.
876 */
877
878 if (!(bp->hData =
879 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
880 (DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize))))
881 printf("alloc 1 failed\n");
882
883 if (!(bp->lpData =
884 (HPSTR) GlobalLock(bp->hData)))
885 printf("lock 1 failed\n");
886
887 /* Allocate and lock memory for the header. */
888
889 if (!(bp->hWaveHdr =
890 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
891 printf("alloc 2 failed\n");
892
893 if (!(wh = bp->lpWaveHdr =
894 (WAVEHDR *) GlobalLock(bp->hWaveHdr)))
895 printf("lock 2 failed\n");
896
897 for (i = CHANNELS_PER_DEVICE * nt_realdacblksize,
898 sp = (short *)bp->lpData; i--; )
899 *sp++ = 0;
900
901 wh->lpData = bp->lpData;
902 wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize);
903 wh->dwFlags = 0;
904 wh->dwLoops = 0L;
905 wh->lpNext = 0;
906 wh->reserved = 0;
907 /* optionally (for writing) set DONE flag as if we had queued them */
908 if (setdone)
909 wh->dwFlags = WHDR_DONE;
910}
911
912static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
913
914int mmio_do_open_audio(void)
915{
916 PCMWAVEFORMAT form;
917 int i, j;
918 UINT mmresult;
919 int nad, nda;
920 static int naudioprepped = 0, nindevsprepped = 0, noutdevsprepped = 0;
921 if (sys_verbose)
922 post("%d devices in, %d devices out",
923 nt_nwavein, nt_nwaveout);
924
925 form.wf.wFormatTag = WAVE_FORMAT_PCM;
926 form.wf.nChannels = CHANNELS_PER_DEVICE;
927 form.wf.nSamplesPerSec = sys_dacsr;
928 form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE);
929 form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE;
930 form.wBitsPerSample = 8 * SAMPSIZE;
931
932 if (nt_nwavein <= 1 && nt_nwaveout <= 1)
933 nt_noresync();
934
935 if (nindevsprepped < nt_nwavein)
936 {
937 for (i = nindevsprepped; i < nt_nwavein; i++)
938 for (j = 0; j < naudioprepped; j++)
939 wave_prep(&ntsnd_invec[i][j], 0);
940 nindevsprepped = nt_nwavein;
941 }
942 if (noutdevsprepped < nt_nwaveout)
943 {
944 for (i = noutdevsprepped; i < nt_nwaveout; i++)
945 for (j = 0; j < naudioprepped; j++)
946 wave_prep(&ntsnd_outvec[i][j], 1);
947 noutdevsprepped = nt_nwaveout;
948 }
949 if (naudioprepped < nt_naudiobuffer)
950 {
951 for (j = naudioprepped; j < nt_naudiobuffer; j++)
952 {
953 for (i = 0; i < nt_nwavein; i++)
954 wave_prep(&ntsnd_invec[i][j], 0);
955 for (i = 0; i < nt_nwaveout; i++)
956 wave_prep(&ntsnd_outvec[i][j], 1);
957 }
958 naudioprepped = nt_naudiobuffer;
959 }
960 for (nad=0; nad < nt_nwavein; nad++)
961 {
962 /* Open waveform device(s), sucessively numbered, for input */
963
964 mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad,
965 (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
966
967 if (sys_verbose)
968 printf("opened adc device %d with return %d\n",
969 nt_whichadc+nad,mmresult);
970
971 if (mmresult != MMSYSERR_NOERROR)
972 {
973 nt_waveinerror("waveInOpen: %s\n", mmresult);
974 nt_nwavein = nad; /* nt_nwavein = 0 wini */
975 }
976 else
977 {
978 for (i = 0; i < nt_naudiobuffer; i++)
979 {
980 mmresult = waveInPrepareHeader(ntsnd_indev[nad],
981 ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
982 if (mmresult != MMSYSERR_NOERROR)
983 nt_waveinerror("waveinprepareheader: %s\n", mmresult);
984 mmresult = waveInAddBuffer(ntsnd_indev[nad],
985 ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
986 if (mmresult != MMSYSERR_NOERROR)
987 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
988 }
989 }
990 }
991 /* quickly start them all together */
992 for (nad = 0; nad < nt_nwavein; nad++)
993 waveInStart(ntsnd_indev[nad]);
994
995 for (nda = 0; nda < nt_nwaveout; nda++)
996 {
997 /* Open a waveform device for output in sucessiv device numbering*/
998 mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda,
999 (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
1000
1001 if (sys_verbose)
1002 fprintf(stderr,"opened dac device %d, with return %d\n",
1003 nt_whichdac +nda, mmresult);
1004
1005 if (mmresult != MMSYSERR_NOERROR)
1006 {
1007 fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda);
1008 nt_waveouterror("waveOutOpen device: %s\n", mmresult);
1009 nt_nwaveout = nda;
1010 }
1011 }
1012
1013 return (0);
1014}
1015
1016void mmio_close_audio( void)
1017{
1018 int errcode;
1019 int nda, nad;
1020 if (sys_verbose)
1021 post("closing audio...");
1022
1023 for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */
1024 {
1025 errcode = waveOutReset(ntsnd_outdev[nda]);
1026 if (errcode != MMSYSERR_NOERROR)
1027 printf("error resetting output %d: %d\n", nda, errcode);
1028 errcode = waveOutClose(ntsnd_outdev[nda]);
1029 if (errcode != MMSYSERR_NOERROR)
1030 printf("error closing output %d: %d\n",nda , errcode);
1031 }
1032 nt_nwaveout = 0;
1033
1034 for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */
1035 {
1036 errcode = waveInReset(ntsnd_indev[nad]);
1037 if (errcode != MMSYSERR_NOERROR)
1038 printf("error resetting input: %d\n", errcode);
1039 errcode = waveInClose(ntsnd_indev[nad]);
1040 if (errcode != MMSYSERR_NOERROR)
1041 printf("error closing input: %d\n", errcode);
1042 }
1043 nt_nwavein = 0;
1044}
1045
1046
1047#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
1048#define DACJITTER 10
1049
1050static int nt_adcjitterbufsallowed = ADCJITTER;
1051static int nt_dacjitterbufsallowed = DACJITTER;
1052
1053 /* ------------- MIDI time stamping from audio clock ------------ */
1054
1055#ifdef MIDI_TIMESTAMP
1056
1057static double nt_hibuftime;
1058static double initsystime = -1;
1059
1060 /* call this whenever we reset audio */
1061static void nt_resetmidisync(void)
1062{
1063 initsystime = clock_getsystime();
1064 nt_hibuftime = sys_getrealtime();
1065}
1066
1067 /* call this whenever we're idled waiting for audio to be ready.
1068 The routine maintains a high and low water point for the difference
1069 between real and DAC time. */
1070
1071static void nt_midisync(void)
1072{
1073 double jittersec, diff;
1074
1075 if (initsystime == -1) nt_resetmidisync();
1076 jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
1077 nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
1078 * nt_realdacblksize / sys_getsr();
1079 diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
1080 if (diff > nt_hibuftime) nt_hibuftime = diff;
1081 if (diff < nt_hibuftime - jittersec)
1082 {
1083 post("jitter excess %d %f", dac, diff);
1084 nt_resetmidisync();
1085 }
1086}
1087
1088static double nt_midigettimefor(LARGE_INTEGER timestamp)
1089{
1090 /* this is broken now... used to work when "timestamp" was derived from
1091 QueryPerformanceCounter() instead of the gates approved
1092 timeGetSystemTime() call in the MIDI callback routine below. */
1093 return (nt_tixtotime(timestamp) - nt_hibuftime);
1094}
1095#endif /* MIDI_TIMESTAMP */
1096
1097
1098static int nt_fill = 0;
1099#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x))
1100#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x))
1101#define MAXRESYNC 500
1102
1103#if 0 /* this is used for debugging */
1104static void nt_printaudiostatus(void)
1105{
1106 int nad, nda;
1107 for (nad = 0; nad < nt_nwavein; nad++)
1108 {
1109 int phase = ntsnd_inphase[nad];
1110 int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
1111 int firstphasedone = -1, firstphasebusy = -1;
1112 for (count = 0; count < nt_naudiobuffer; count++)
1113 {
1114 int donethis =
1115 (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
1116 int donenext =
1117 (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
1118 if (donethis && !donenext)
1119 {
1120 if (firstphasebusy >= 0) goto multipleadc;
1121 firstphasebusy = count;
1122 }
1123 if (!donethis && donenext)
1124 {
1125 if (firstphasedone >= 0) goto multipleadc;
1126 firstphasedone = count;
1127 }
1128 phase2 = phase3;
1129 phase3 = WRAPFWD(phase2 + 1);
1130 }
1131 post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy,
1132 firstphasedone);
1133 continue;
1134 multipleadc:
1135 startpost("nad %d phase %d: oops:", nad, phase);
1136 for (count = 0; count < nt_naudiobuffer; count++)
1137 {
1138 char buf[80];
1139 sprintf(buf, " %d",
1140 (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
1141 poststring(buf);
1142 }
1143 endpost();
1144 }
1145 for (nda = 0; nda < nt_nwaveout; nda++)
1146 {
1147 int phase = ntsnd_outphase[nad];
1148 int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
1149 int firstphasedone = -1, firstphasebusy = -1;
1150 for (count = 0; count < nt_naudiobuffer; count++)
1151 {
1152 int donethis =
1153 (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
1154 int donenext =
1155 (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
1156 if (donethis && !donenext)
1157 {
1158 if (firstphasebusy >= 0) goto multipledac;
1159 firstphasebusy = count;
1160 }
1161 if (!donethis && donenext)
1162 {
1163 if (firstphasedone >= 0) goto multipledac;
1164 firstphasedone = count;
1165 }
1166 phase2 = phase3;
1167 phase3 = WRAPFWD(phase2 + 1);
1168 }
1169 if (firstphasebusy < 0) post("nda %d phase %d all %d",
1170 nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE));
1171 else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy,
1172 firstphasedone);
1173 continue;
1174 multipledac:
1175 startpost("nda %d phase %d: oops:", nda, phase);
1176 for (count = 0; count < nt_naudiobuffer; count++)
1177 {
1178 char buf[80];
1179 sprintf(buf, " %d",
1180 (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
1181 poststring(buf);
1182 }
1183 endpost();
1184 }
1185}
1186#endif /* 0 */
1187
1188/* this is a hack to avoid ever resyncing audio pointers in case for whatever
1189reason the sync testing below gives false positives. */
1190
1191static int nt_resync_cancelled;
1192
1193static void nt_noresync( void)
1194{
1195 nt_resync_cancelled = 1;
1196}
1197
1198static void nt_resyncaudio(void)
1199{
1200 UINT mmresult;
1201 int nad, nda, count;
1202 if (nt_resync_cancelled)
1203 return;
1204 /* for each open input device, eat all buffers which are marked
1205 ready. The next one will thus be "busy". */
1206 post("resyncing audio");
1207 for (nad = 0; nad < nt_nwavein; nad++)
1208 {
1209 int phase = ntsnd_inphase[nad];
1210 for (count = 0; count < MAXRESYNC; count++)
1211 {
1212 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
1213 if (!(inwavehdr->dwFlags & WHDR_DONE)) break;
1214 if (inwavehdr->dwFlags & WHDR_PREPARED)
1215 waveInUnprepareHeader(ntsnd_indev[nad],
1216 inwavehdr, sizeof(WAVEHDR));
1217 inwavehdr->dwFlags = 0L;
1218 waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
1219 mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr,
1220 sizeof(WAVEHDR));
1221 if (mmresult != MMSYSERR_NOERROR)
1222 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
1223 ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1);
1224 }
1225 if (count == MAXRESYNC) post("resync error 1");
1226 }
1227 /* Each output buffer which is "ready" is filled with zeros and
1228 queued. */
1229 for (nda = 0; nda < nt_nwaveout; nda++)
1230 {
1231 int phase = ntsnd_outphase[nda];
1232 for (count = 0; count < MAXRESYNC; count++)
1233 {
1234 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
1235 if (!(outwavehdr->dwFlags & WHDR_DONE)) break;
1236 if (outwavehdr->dwFlags & WHDR_PREPARED)
1237 waveOutUnprepareHeader(ntsnd_outdev[nda],
1238 outwavehdr, sizeof(WAVEHDR));
1239 outwavehdr->dwFlags = 0L;
1240 memset((char *)(ntsnd_outvec[nda][phase].lpData),
1241 0, (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize));
1242 waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr,
1243 sizeof(WAVEHDR));
1244 mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr,
1245 sizeof(WAVEHDR));
1246 if (mmresult != MMSYSERR_NOERROR)
1247 nt_waveouterror("waveOutAddBuffer: %s\n", mmresult);
1248 ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1);
1249 }
1250 if (count == MAXRESYNC) post("resync error 2");
1251 }
1252
1253#ifdef MIDI_TIMESTAMP
1254 nt_resetmidisync();
1255#endif
1256
1257}
1258
1259#define LATE 0
1260#define RESYNC 1
1261#define NOTHING 2
1262static int nt_errorcount;
1263static int nt_resynccount;
1264static double nt_nextreporttime = -1;
1265
1266void nt_logerror(int which)
1267{
1268#if 0
1269 post("error %d %d", count, which);
1270 if (which < NOTHING) nt_errorcount++;
1271 if (which == RESYNC) nt_resynccount++;
1272 if (sys_getrealtime() > nt_nextreporttime)
1273 {
1274 post("%d audio I/O error%s", nt_errorcount,
1275 (nt_errorcount > 1 ? "s" : ""));
1276 if (nt_resynccount) post("DAC/ADC sync error");
1277 nt_errorcount = nt_resynccount = 0;
1278 nt_nextreporttime = sys_getrealtime() - 5;
1279 }
1280#endif
1281}
1282
1283/* system buffer with t_sample types for one tick */
1284t_sample *sys_soundout;
1285t_sample *sys_soundin;
1286float sys_dacsr;
1287
1288int mmio_send_dacs(void)
1289{
1290 HMMIO hmmio;
1291 UINT mmresult;
1292 HANDLE hFormat;
1293 int i, j;
1294 short *sp1, *sp2;
1295 float *fp1, *fp2;
1296 int nextfill, doxfer = 0;
1297 int nda, nad;
1298 if (!nt_nwavein && !nt_nwaveout) return (0);
1299
1300
1301 if (nt_meters)
1302 {
1303 int i, n;
1304 float maxsamp;
1305 for (i = 0, n = 2 * nt_nwavein * DEFDACBLKSIZE, maxsamp = nt_inmax;
1306 i < n; i++)
1307 {
1308 float f = sys_soundin[i];
1309 if (f > maxsamp) maxsamp = f;
1310 else if (-f > maxsamp) maxsamp = -f;
1311 }
1312 nt_inmax = maxsamp;
1313 for (i = 0, n = 2 * nt_nwaveout * DEFDACBLKSIZE, maxsamp = nt_outmax;
1314 i < n; i++)
1315 {
1316 float f = sys_soundout[i];
1317 if (f > maxsamp) maxsamp = f;
1318 else if (-f > maxsamp) maxsamp = -f;
1319 }
1320 nt_outmax = maxsamp;
1321 }
1322
1323 /* the "fill pointer" nt_fill controls where in the next
1324 I/O buffers we will write and/or read. If it's zero, we
1325 first check whether the buffers are marked "done". */
1326
1327 if (!nt_fill)
1328 {
1329 for (nad = 0; nad < nt_nwavein; nad++)
1330 {
1331 int phase = ntsnd_inphase[nad];
1332 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
1333 if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
1334 }
1335 for (nda = 0; nda < nt_nwaveout; nda++)
1336 {
1337 int phase = ntsnd_outphase[nda];
1338 WAVEHDR *outwavehdr =
1339 ntsnd_outvec[nda][phase].lpWaveHdr;
1340 if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
1341 }
1342 for (nad = 0; nad < nt_nwavein; nad++)
1343 {
1344 int phase = ntsnd_inphase[nad];
1345 WAVEHDR *inwavehdr =
1346 ntsnd_invec[nad][phase].lpWaveHdr;
1347 if (inwavehdr->dwFlags & WHDR_PREPARED)
1348 waveInUnprepareHeader(ntsnd_indev[nad],
1349 inwavehdr, sizeof(WAVEHDR));
1350 }
1351 for (nda = 0; nda < nt_nwaveout; nda++)
1352 {
1353 int phase = ntsnd_outphase[nda];
1354 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
1355 if (outwavehdr->dwFlags & WHDR_PREPARED)
1356 waveOutUnprepareHeader(ntsnd_outdev[nda],
1357 outwavehdr, sizeof(WAVEHDR));
1358 }
1359 }
1360
1361 /* Convert audio output to fixed-point and put it in the output
1362 buffer. */
1363 for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++)
1364 {
1365 int phase = ntsnd_outphase[nda];
1366
1367 for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) +
1368 CHANNELS_PER_DEVICE * nt_fill;
1369 i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
1370 {
1371 for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
1372 j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
1373 {
1374 int x1 = 32767.f * *fp2;
1375 if (x1 > 32767) x1 = 32767;
1376 else if (x1 < -32767) x1 = -32767;
1377 *sp2 = x1;
1378 }
1379 }
1380 }
1381 memset(sys_soundout, 0,
1382 (DEFDACBLKSIZE *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
1383
1384 /* vice versa for the input buffer */
1385
1386 for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++)
1387 {
1388 int phase = ntsnd_inphase[nad];
1389
1390 for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) +
1391 CHANNELS_PER_DEVICE * nt_fill;
1392 i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
1393 {
1394 for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
1395 j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
1396 {
1397 *fp2 = ((float)(1./32767.)) * (float)(*sp2);
1398 }
1399 }
1400 }
1401
1402 nt_fill = nt_fill + DEFDACBLKSIZE;
1403 if (nt_fill == nt_realdacblksize)
1404 {
1405 nt_fill = 0;
1406
1407 for (nad = 0; nad < nt_nwavein; nad++)
1408 {
1409 int phase = ntsnd_inphase[nad];
1410 HWAVEIN device = ntsnd_indev[nad];
1411 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
1412 waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR));
1413 mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR));
1414 if (mmresult != MMSYSERR_NOERROR)
1415 nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
1416 ntsnd_inphase[nad] = WRAPFWD(phase + 1);
1417 }
1418 for (nda = 0; nda < nt_nwaveout; nda++)
1419 {
1420 int phase = ntsnd_outphase[nda];
1421 HWAVEOUT device = ntsnd_outdev[nda];
1422 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
1423 waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR));
1424 mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR));
1425 if (mmresult != MMSYSERR_NOERROR)
1426 nt_waveouterror("waveOutWrite: %s\n", mmresult);
1427 ntsnd_outphase[nda] = WRAPFWD(phase + 1);
1428 }
1429
1430 /* check for DAC underflow or ADC overflow. */
1431 for (nad = 0; nad < nt_nwavein; nad++)
1432 {
1433 int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
1434 WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
1435 if (inwavehdr->dwFlags & WHDR_DONE) goto late;
1436 }
1437 for (nda = 0; nda < nt_nwaveout; nda++)
1438 {
1439 int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
1440 WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
1441 if (outwavehdr->dwFlags & WHDR_DONE) goto late;
1442 }
1443 }
1444 return (1);
1445
1446late:
1447
1448 nt_logerror(LATE);
1449 nt_resyncaudio();
1450 return (1);
1451
1452idle:
1453
1454 /* If more than nt_adcjitterbufsallowed ADC buffers are ready
1455 on any input device, resynchronize */
1456
1457 for (nad = 0; nad < nt_nwavein; nad++)
1458 {
1459 int phase = ntsnd_inphase[nad];
1460 WAVEHDR *inwavehdr =
1461 ntsnd_invec[nad]
1462 [WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr;
1463 if (inwavehdr->dwFlags & WHDR_DONE)
1464 {
1465 nt_resyncaudio();
1466 return (0);
1467 }
1468 }
1469
1470 /* test dac sync the same way */
1471 for (nda = 0; nda < nt_nwaveout; nda++)
1472 {
1473 int phase = ntsnd_outphase[nda];
1474 WAVEHDR *outwavehdr =
1475 ntsnd_outvec[nda]
1476 [WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr;
1477 if (outwavehdr->dwFlags & WHDR_DONE)
1478 {
1479 nt_resyncaudio();
1480 return (0);
1481 }
1482 }
1483#ifdef MIDI_TIMESTAMP
1484 nt_midisync();
1485#endif
1486 return (0);
1487}
1488
1489/* ------------------- public routines -------------------------- */
1490
1491void mmio_open_audio(int naudioindev, int *audioindev,
1492 int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
1493 int nchoutdev, int *choutdev, int rate) /* IOhannes */
1494{
1495 int nbuf;
1496
1497 nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE);
1498 nbuf = sys_advance_samples/nt_realdacblksize;
1499 if (nbuf >= MAXBUFFER)
1500 {
1501 fprintf(stderr, "pd: audio buffering maxed out to %d\n",
1502 (int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.)));
1503 nbuf = MAXBUFFER;
1504 }
1505 else if (nbuf < 4) nbuf = 4;
1506 fprintf(stderr, "%d audio buffers\n", nbuf);
1507 nt_naudiobuffer = nbuf;
1508 if (nt_adcjitterbufsallowed > nbuf - 2)
1509 nt_adcjitterbufsallowed = nbuf - 2;
1510 if (nt_dacjitterbufsallowed > nbuf - 2)
1511 nt_dacjitterbufsallowed = nbuf - 2;
1512
1513 nt_nwavein = sys_inchannels / 2;
1514 nt_nwaveout = sys_outchannels / 2;
1515 nt_whichadc = (naudioindev < 1 ?
1516 (nt_nwavein > 1 ? WAVE_MAPPER : -1) : audioindev[0]);
1517 nt_whichdac = (naudiooutdev < 1 ?
1518 (nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]);
1519 if (naudiooutdev > 1 || naudioindev > 1)
1520 post("separate audio device choice not supported; using sequential devices.");
1521 mmio_do_open_audio();
1522}
1523
1524
1525void mmio_reportidle(void)
1526{
1527}
1528
1529#if 0
1530/* list the audio and MIDI device names */
1531void mmio_listdevs(void)
1532{
1533 UINT wRtn, ndevices;
1534 unsigned int i;
1535
1536 ndevices = waveInGetNumDevs();
1537 for (i = 0; i < ndevices; i++)
1538 {
1539 WAVEINCAPS wicap;
1540 wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap,
1541 sizeof(wicap));
1542 if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn);
1543 else fprintf(stderr,
1544 "audio input device #%d: %s\n", i+1, wicap.szPname);
1545 }
1546
1547 ndevices = waveOutGetNumDevs();
1548 for (i = 0; i < ndevices; i++)
1549 {
1550 WAVEOUTCAPS wocap;
1551 wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap,
1552 sizeof(wocap));
1553 if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn);
1554 else fprintf(stderr,
1555 "audio output device #%d: %s\n", i+1, wocap.szPname);
1556 }
1557}
1558#endif
1559
1560void mmio_getdevs(char *indevlist, int *nindevs,
1561 char *outdevlist, int *noutdevs, int *canmulti,
1562 int maxndev, int devdescsize)
1563{
1564 int wRtn, ndev, i;
1565
1566 *canmulti = 2; /* supports multiple devices */
1567 ndev = waveInGetNumDevs();
1568 if (ndev > maxndev)
1569 ndev = maxndev;
1570 *nindevs = ndev;
1571 for (i = 0; i < ndev; i++)
1572 {
1573 WAVEINCAPS wicap;
1574 wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap));
1575 sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname));
1576 }
1577
1578 ndev = waveOutGetNumDevs();
1579 if (ndev > maxndev)
1580 ndev = maxndev;
1581 *noutdevs = ndev;
1582 for (i = 0; i < ndev; i++)
1583 {
1584 WAVEOUTCAPS wocap;
1585 wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap));
1586 sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname));
1587 }
1588}
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_oss.c b/apps/plugins/pdbox/PDa/src/s_audio_oss.c
new file mode 100644
index 0000000000..efb15d1bc1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_audio_oss.c
@@ -0,0 +1,1688 @@
1/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
2* Winfried Ritsch, Karl MacMillan, and others.
3* For information on usage and redistribution, and for a DISCLAIMER OF ALL
4* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5
6/* this file inputs and outputs audio using the OSS API available on linux. */
7
8#ifdef USEAPI_OSS
9
10#include <linux/soundcard.h>
11
12#include "m_pd.h"
13#include "s_stuff.h"
14#include <errno.h>
15#include <stdio.h>
16#include <unistd.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/time.h>
21#include <sys/stat.h>
22#include <sys/ioctl.h>
23#include <fcntl.h>
24#include <sched.h>
25#include <sys/mman.h>
26
27
28/* Defines */
29#define DEBUG(x) x
30#define DEBUG2(x) {x;}
31
32#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
33#define OSS_MAXDEV 4 /* maximum number of input or output devices */
34#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
35#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
36#define OSS_DEFAULTCH 2
37#define RME_DEFAULTCH 8 /* need this even if RME undefined */
38typedef int16_t t_oss_int16;
39typedef int32_t t_oss_int32;
40#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
41#define OSS_BYTESPERCHAN(width) (DEFDACBLKSIZE * (width))
42#define OSS_XFERSAMPS(chans) (DEFDACBLKSIZE* (chans))
43#define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width))
44
45/* GLOBALS */
46static int linux_meters; /* true if we're metering */
47static float linux_inmax; /* max input amplitude */
48static float linux_outmax; /* max output amplitude */
49static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
50
51/* our device handles */
52
53typedef struct _oss_dev
54{
55 int d_fd;
56 unsigned int d_space; /* bytes available for writing/reading */
57 int d_bufsize; /* total buffer size in blocks for this device */
58 int d_dropcount; /* # of buffers to drop for resync (output only) */
59 unsigned int d_nchannels; /* number of channels for this device */
60 unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
61} t_oss_dev;
62
63static t_oss_dev linux_dacs[OSS_MAXDEV];
64static t_oss_dev linux_adcs[OSS_MAXDEV];
65static int linux_noutdevs = 0;
66static int linux_nindevs = 0;
67
68 /* exported variables */
69float sys_dacsr;
70t_sample *sys_soundout;
71t_sample *sys_soundin;
72
73 /* OSS-specific private variables */
74static int oss_blockmode = 1; /* flag to use "blockmode" */
75static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
76static char ossdsp[] = "/dev/dsp%d";
77
78 /* don't assume we can turn all 31 bits when doing float-to-fix;
79 otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
80#define FMAX 0x7ffff000
81#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
82
83
84/* ------------- private routines for all APIS ------------------- */
85
86static void linux_flush_all_underflows_to_zero(void)
87{
88/*
89 TODO: Implement similar thing for linux (GGeiger)
90
91 One day we will figure this out, I hope, because it
92 costs CPU time dearly on Intel - LT
93 */
94 /* union fpc_csr f;
95 f.fc_word = get_fpc_csr();
96 f.fc_struct.flush = 1;
97 set_fpc_csr(f.fc_word);
98 */
99}
100
101static int oss_ndev = 0;
102
103 /* find out how many OSS devices we have. Since this has to
104 open the devices to find out if they're there, we have
105 to be called before audio is actually started up. So we
106 cache the results, which in effect are the number of available
107 devices. */
108void oss_init(void)
109{
110 int fd, i;
111 static int countedthem = 0;
112 if (countedthem)
113 return;
114 for (i = 0; i < 10; i++)
115 {
116 char devname[100];
117 if (i == 0)
118 strcpy(devname, "/dev/dsp");
119 else sprintf(devname, "/dev/dsp%d", i);
120 if ( (fd = open(devname, O_WRONLY|O_NONBLOCK)) != -1)
121 {
122 oss_ndev++;
123 close(fd);
124 }
125 else break;
126 }
127 countedthem = 1;
128}
129
130
131void oss_set32bit( void)
132{
133 oss_32bit = 1;
134}
135
136
137typedef struct _multidev {
138 int fd;
139 int channels;
140 int format;
141} t_multidev;
142
143int oss_reset(int fd) {
144 int err;
145 if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0)
146 error("OSS: Could not reset");
147 return err;
148}
149
150 /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
151 but is proposed by Guenter Geiger to support extending OSS to handle
152 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
153 I'm not clear why this isn't called AFMT_S32_[SLN]E... */
154
155#ifndef AFMT_S32_BLOCKED
156#define AFMT_S32_BLOCKED 0x0000400
157#endif
158
159void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize)
160{ /* IOhannes */
161 int orig, param, nblk, fd = dev->d_fd, wantformat;
162 int nchannels = dev->d_nchannels;
163 int advwas = sys_schedadvance;
164
165 audio_buf_info ainfo;
166
167 /* IOhannes :
168 * pd is very likely to crash if different formats are used on
169 multiple soundcards
170 */
171
172 /* set resolution - first try 4 byte samples */
173 if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) &&
174 (param & AFMT_S32_BLOCKED))
175 {
176 wantformat = AFMT_S32_BLOCKED;
177 dev->d_bytespersamp = 4;
178 }
179 else
180 {
181 wantformat = AFMT_S16_NE;
182 dev->d_bytespersamp = 2;
183 }
184 param = wantformat;
185
186 if (sys_verbose)
187 post("bytes per sample = %d", dev->d_bytespersamp);
188 if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1)
189 fprintf(stderr,"OSS: Could not set DSP format\n");
190 else if (wantformat != param)
191 fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n",
192 wantformat, param);
193
194 /* sample rate */
195 orig = param = srate;
196 if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1)
197 fprintf(stderr,"OSS: Could not set sampling rate for device\n");
198 else if( orig != param )
199 fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n",
200 orig, param );
201
202 if (oss_blockmode && !skipblocksize)
203 {
204 int fragbytes, logfragsize, nfragment;
205 /* setting fragment count and size. */
206 if (!linux_fragsize)
207 {
208 linux_fragsize = OSS_DEFFRAGSIZE;
209 while (linux_fragsize > DEFDACBLKSIZE
210 && linux_fragsize * 4 > sys_advance_samples)
211 linux_fragsize = linux_fragsize/2;
212 }
213
214 /* post("adv_samples %d", sys_advance_samples); */
215 nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
216
217 fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
218 logfragsize = ilog2(fragbytes);
219
220 if (fragbytes != (1 << logfragsize))
221 post("warning: OSS takes only power of 2 blocksize; using %d",
222 (1 << logfragsize)/(dev->d_bytespersamp * nchannels));
223 if (sys_verbose)
224 post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes);
225
226 param = orig = (nfragment<<16) + logfragsize;
227 if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
228 error("OSS: Could not set or read fragment size\n");
229 if (param != orig)
230 {
231 nfragment = ((param >> 16) & 0xffff);
232 logfragsize = (param & 0xffff);
233 post("warning: actual fragments %d, blocksize %d",
234 nfragment, (1 << logfragsize));
235 }
236 if (sys_verbose)
237 post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
238 }
239 if (dac)
240 {
241 /* use "free space" to learn the buffer size. Normally you
242 should set this to your own desired value; but this seems not
243 to be implemented uniformly across different sound cards. LATER
244 we should figure out what to do if the requested scheduler advance
245 is greater than this buffer size; for now, we just print something
246 out. */
247
248 int defect;
249 if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
250 fprintf(stderr,"OSS: ioctl on output device failed");
251 dev->d_bufsize = ainfo.bytes;
252
253 defect = sys_advance_samples * (dev->d_bytespersamp * nchannels)
254 - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
255 if (defect > 0)
256 {
257 if (sys_verbose || defect > (dev->d_bufsize >> 2))
258 fprintf(stderr,
259 "OSS: requested audio buffer size %d limited to %d\n",
260 sys_advance_samples * (dev->d_bytespersamp * nchannels),
261 dev->d_bufsize);
262 sys_advance_samples =
263 (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) /
264 (dev->d_bytespersamp *nchannels);
265 }
266 }
267}
268
269static int oss_setchannels(int fd, int wantchannels, char *devname)
270{ /* IOhannes */
271 int param = wantchannels;
272
273 while (param>1) {
274 int save = param;
275 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) {
276 error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
277 } else {
278 if (param == save) return (param);
279 }
280 param=save-1;
281 }
282
283 return (0);
284}
285
286#define O_AUDIOFLAG 0 /* O_NDELAY */
287
288int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
289 int noutdev, int *outdev, int nchout, int *chout, int rate)
290{ /* IOhannes */
291 int capabilities = 0;
292 int inchannels = 0, outchannels = 0;
293 char devname[20];
294 int n, i, fd;
295 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
296 int num_devs = 0;
297 int wantmore=0;
298 int spread = 0;
299 audio_buf_info ainfo;
300
301 linux_nindevs = linux_noutdevs = 0;
302
303
304 /* mark input devices unopened */
305 for (i = 0; i < OSS_MAXDEV; i++)
306 linux_adcs[i].d_fd = -1;
307
308 /* open output devices */
309 wantmore=0;
310 if (noutdev < 0 || nindev < 0)
311 bug("linux_open_audio");
312
313 for (n = 0; n < noutdev; n++)
314 {
315 int gotchans, j, inindex = -1;
316 int thisdevice = (outdev[n] >= 0 ? outdev[n] : n-1);
317 int wantchannels = (nchout>n) ? chout[n] : wantmore;
318 fd = -1;
319 if (!wantchannels)
320 goto end_out_loop;
321
322 if (thisdevice > 1)
323 sprintf(devname, "/dev/dsp%d", thisdevice-1);
324 else sprintf(devname, "/dev/dsp");
325
326 /* search for input request for same device. Succeed only
327 if the number of channels matches. */
328 for (j = 0; j < nindev; j++)
329 if (indev[j] == thisdevice && chin[j] == wantchannels)
330 inindex = j;
331
332 /* if the same device is requested for input and output,
333 try to open it read/write */
334 if (inindex >= 0)
335 {
336 sys_setalarm(1000000);
337 if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1)
338 {
339 post("%s (read/write): %s", devname, strerror(errno));
340 post("(now will try write-only...)");
341 }
342 else
343 {
344 if (sys_verbose)
345 post("opened %s for reading and writing\n", devname);
346 linux_adcs[inindex].d_fd = fd;
347 }
348 }
349 /* if that didn't happen or if it failed, try write-only */
350 if (fd == -1)
351 {
352 sys_setalarm(1000000);
353 if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1)
354 {
355 post("%s (writeonly): %s",
356 devname, strerror(errno));
357 break;
358 }
359 if (sys_verbose)
360 post("opened %s for writing only\n", devname);
361 }
362 if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
363 error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
364
365 gotchans = oss_setchannels(fd,
366 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
367 devname);
368
369 if (sys_verbose)
370 post("opened audio output on %s; got %d channels",
371 devname, gotchans);
372
373 if (gotchans < 2)
374 {
375 /* can't even do stereo? just give up. */
376 close(fd);
377 }
378 else
379 {
380 linux_dacs[linux_noutdevs].d_nchannels = gotchans;
381 linux_dacs[linux_noutdevs].d_fd = fd;
382 oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0);
383
384 linux_noutdevs++;
385 outchannels += gotchans;
386 if (inindex >= 0)
387 {
388 linux_adcs[inindex].d_nchannels = gotchans;
389 chin[inindex] = gotchans;
390 }
391 }
392 /* LATER think about spreading large numbers of channels over
393 various dsp's and vice-versa */
394 wantmore = wantchannels - gotchans;
395 end_out_loop: ;
396 }
397
398 /* open input devices */
399 wantmore = 0;
400 for (n = 0; n < nindev; n++)
401 {
402 int gotchans=0;
403 int thisdevice = (indev[n] >= 0 ? indev[n] : n-1);
404 int wantchannels = (nchin>n)?chin[n]:wantmore;
405 int alreadyopened = 0;
406 if (!wantchannels)
407 goto end_in_loop;
408
409 if (thisdevice > 1)
410 sprintf(devname, "/dev/dsp%d", thisdevice - 1);
411 else sprintf(devname, "/dev/dsp");
412
413 sys_setalarm(1000000);
414
415 /* perhaps it's already open from the above? */
416 if (linux_dacs[n].d_fd >= 0)
417 {
418 fd = linux_dacs[n].d_fd;
419 alreadyopened = 1;
420 }
421 else
422 {
423 /* otherwise try to open it here. */
424 if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1)
425 {
426 post("%s (readonly): %s", devname, strerror(errno));
427 goto end_in_loop;
428 }
429 if (sys_verbose)
430 post("opened %s for reading only\n", devname);
431 }
432 linux_adcs[linux_nindevs].d_fd = fd;
433 gotchans = oss_setchannels(fd,
434 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
435 devname);
436 if (sys_verbose)
437 post("opened audio input device %s; got %d channels",
438 devname, gotchans);
439
440 if (gotchans < 1)
441 {
442 close(fd);
443 goto end_in_loop;
444 }
445
446 linux_adcs[linux_nindevs].d_nchannels = gotchans;
447
448 oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
449
450 inchannels += gotchans;
451 linux_nindevs++;
452
453 wantmore = wantchannels-gotchans;
454 /* LATER think about spreading large numbers of channels over
455 various dsp's and vice-versa */
456 end_in_loop: ;
457 }
458
459 /* We have to do a read to start the engine. This is
460 necessary because sys_send_dacs waits until the input
461 buffer is filled and only reads on a filled buffer.
462 This is good, because it's a way to make sure that we
463 will not block. But I wonder why we only have to read
464 from one of the devices and not all of them??? */
465
466 if (linux_nindevs)
467 {
468 if (sys_verbose)
469 fprintf(stderr,("OSS: issuing first ADC 'read' ... "));
470 read(linux_adcs[0].d_fd, buf,
471 linux_adcs[0].d_bytespersamp *
472 linux_adcs[0].d_nchannels * DEFDACBLKSIZE);
473 if (sys_verbose)
474 fprintf(stderr, "...done.\n");
475 }
476 sys_setalarm(0);
477 return (0);
478}
479
480void oss_close_audio( void)
481{
482 int i;
483 for (i=0;i<linux_nindevs;i++)
484 close(linux_adcs[i].d_fd);
485
486 for (i=0;i<linux_noutdevs;i++)
487 close(linux_dacs[i].d_fd);
488
489 linux_nindevs = linux_noutdevs = 0;
490}
491
492static int linux_dacs_write(int fd,void* buf,long bytes)
493{
494 return write(fd, buf, bytes);
495}
496
497static int linux_adcs_read(int fd,void* buf,long bytes)
498{
499 return read(fd, buf, bytes);
500}
501
502 /* query audio devices for "available" data size. */
503static void oss_calcspace(void)
504{
505 int dev;
506 audio_buf_info ainfo;
507 for (dev=0; dev < linux_noutdevs; dev++)
508 {
509 if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
510 fprintf(stderr,"OSS: ioctl on output device %d failed",dev);
511 linux_dacs[dev].d_space = ainfo.bytes;
512 }
513
514 for (dev = 0; dev < linux_nindevs; dev++)
515 {
516 if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
517 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
518 dev, linux_adcs[dev].d_fd);
519 linux_adcs[dev].d_space = ainfo.bytes;
520 }
521}
522
523void linux_audiostatus(void)
524{
525 int dev;
526 if (!oss_blockmode)
527 {
528 oss_calcspace();
529 for (dev=0; dev < linux_noutdevs; dev++)
530 fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space);
531
532 for (dev = 0; dev < linux_nindevs; dev++)
533 fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
534
535 }
536}
537
538/* this call resyncs audio output and input which will cause discontinuities
539in audio output and/or input. */
540
541static void oss_doresync( void)
542{
543 int dev, zeroed = 0, wantsize;
544 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
545 audio_buf_info ainfo;
546
547 /* 1. if any input devices are ahead (have more than 1 buffer stored),
548 drop one or more buffers worth */
549 for (dev = 0; dev < linux_nindevs; dev++)
550 {
551 if (linux_adcs[dev].d_space == 0)
552 {
553 linux_adcs_read(linux_adcs[dev].d_fd, buf,
554 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
555 linux_adcs[dev].d_bytespersamp));
556 }
557 else while (linux_adcs[dev].d_space >
558 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
559 linux_adcs[dev].d_bytespersamp))
560 {
561 linux_adcs_read(linux_adcs[dev].d_fd, buf,
562 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
563 linux_adcs[dev].d_bytespersamp));
564 if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0)
565 {
566 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
567 dev, linux_adcs[dev].d_fd);
568 break;
569 }
570 linux_adcs[dev].d_space = ainfo.bytes;
571 }
572 }
573
574 /* 2. if any output devices are behind, feed them zeros to catch them
575 up */
576 for (dev = 0; dev < linux_noutdevs; dev++)
577 {
578 while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
579 sys_advance_samples * (linux_dacs[dev].d_nchannels *
580 linux_dacs[dev].d_bytespersamp))
581 {
582 if (!zeroed)
583 {
584 unsigned int i;
585 for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels);
586 i++)
587 buf[i] = 0;
588 zeroed = 1;
589 }
590 linux_dacs_write(linux_dacs[dev].d_fd, buf,
591 OSS_XFERSIZE(linux_dacs[dev].d_nchannels,
592 linux_dacs[dev].d_bytespersamp));
593 if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
594 {
595 fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
596 dev, linux_dacs[dev].d_fd);
597 break;
598 }
599 linux_dacs[dev].d_space = ainfo.bytes;
600 }
601 }
602 /* 3. if any DAC devices are too far ahead, plan to drop the
603 number of frames which will let the others catch up. */
604 for (dev = 0; dev < linux_noutdevs; dev++)
605 {
606 if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
607 (sys_advance_samples - 1) * linux_dacs[dev].d_nchannels *
608 linux_dacs[dev].d_bytespersamp)
609 {
610 linux_dacs[dev].d_dropcount = sys_advance_samples - 1 -
611 (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) /
612 (linux_dacs[dev].d_nchannels *
613 linux_dacs[dev].d_bytespersamp) ;
614 }
615 else linux_dacs[dev].d_dropcount = 0;
616 }
617}
618
619int oss_send_dacs(void)
620{
621 t_sample *fp1, *fp2;
622 long fill;
623 int i, j, dev, rtnval = SENDDACS_YES;
624 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
625 t_oss_int16 *sp;
626 t_oss_int32 *lp;
627 /* the maximum number of samples we should have in the ADC buffer */
628 int idle = 0;
629 int thischan;
630 t_time timeref, timenow;
631
632 if (!linux_nindevs && !linux_noutdevs)
633 return (SENDDACS_NO);
634
635 if (!oss_blockmode)
636 {
637 /* determine whether we're idle. This is true if either (1)
638 some input device has less than one buffer to read or (2) some
639 output device has fewer than (sys_advance_samples) blocks buffered
640 already. */
641 oss_calcspace();
642
643 for (dev=0; dev < linux_noutdevs; dev++)
644 if (linux_dacs[dev].d_dropcount ||
645 (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space >
646 sys_advance_samples * linux_dacs[dev].d_bytespersamp *
647 linux_dacs[dev].d_nchannels))
648 idle = 1;
649 for (dev=0; dev < linux_nindevs; dev++)
650 if (linux_adcs[dev].d_space <
651 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
652 linux_adcs[dev].d_bytespersamp))
653 idle = 1;
654 }
655
656 if (idle && !oss_blockmode)
657 {
658 /* sometimes---rarely---when the ADC available-byte-count is
659 zero, it's genuine, but usually it's because we're so
660 late that the ADC has overrun its entire kernel buffer. We
661 distinguish between the two by waiting 2 msec and asking again.
662 There should be an error flag we could check instead; look for this
663 someday... */
664 for (dev = 0;dev < linux_nindevs; dev++)
665 if (linux_adcs[dev].d_space == 0)
666 {
667 audio_buf_info ainfo;
668 sys_microsleep(2000);
669 oss_calcspace();
670 if (linux_adcs[dev].d_space != 0) continue;
671
672 /* here's the bad case. Give up and resync. */
673 sys_log_error(ERR_DATALATE);
674 oss_doresync();
675 return (SENDDACS_NO);
676 }
677 /* check for slippage between devices, either because
678 data got lost in the driver from a previous late condition, or
679 because the devices aren't synced. When we're idle, no
680 input device should have more than one buffer readable and
681 no output device should have less than sys_advance_samples-1
682 */
683
684 for (dev=0; dev < linux_noutdevs; dev++)
685 if (!linux_dacs[dev].d_dropcount &&
686 (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space <
687 (sys_advance_samples - 2) *
688 (linux_dacs[dev].d_bytespersamp *
689 linux_dacs[dev].d_nchannels)))
690 goto badsync;
691 for (dev=0; dev < linux_nindevs; dev++)
692 if (linux_adcs[dev].d_space > 3 *
693 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
694 linux_adcs[dev].d_bytespersamp))
695 goto badsync;
696
697 /* return zero to tell the scheduler we're idle. */
698 return (SENDDACS_NO);
699 badsync:
700 sys_log_error(ERR_RESYNC);
701 oss_doresync();
702 return (SENDDACS_NO);
703
704 }
705
706
707 /* do output */
708
709 timeref = sys_getrealtime();
710 for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
711 {
712 int nchannels = linux_dacs[dev].d_nchannels;
713 if (linux_dacs[dev].d_dropcount)
714 linux_dacs[dev].d_dropcount--;
715 else
716 {
717 if (linux_dacs[dev].d_bytespersamp == 4)
718 {
719 for (i = DEFDACBLKSIZE * nchannels, fp1 = sys_soundout +
720 DEFDACBLKSIZE*thischan,
721 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
722 {
723 t_sample f = SCALE32(*fp1);
724 *lp = (f >= 2147483647 ? 2147483647 :
725 (f < -2147483647 ? -2147483647 : f));
726 }
727 }
728 else
729 {
730 for (i = DEFDACBLKSIZE, fp1 = sys_soundout +
731 DEFDACBLKSIZE*thischan,
732 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
733 {
734 for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE)
735 {
736 int s = SCALE16(*fp2);
737 if (s > 32767) s = 32767;
738 else if (s < -32767) s = -32767;
739 sp[j] = s;
740 }
741 }
742 }
743
744
745#if 0
746#define PR_S "%8d"
747 {
748 int nm = 64;
749 int* sp1 = buf;
750 post("dac:");
751 while (nm > 0)
752 {
753 post(PR_S PR_S PR_S PR_S PR_S PR_S PR_S PR_S,
754 sp1[0], sp1[1], sp1[2], sp1[3], sp1[4], sp1[5], sp1[6], sp1[7]);
755 nm -= 8;
756 sp1 += 8;
757 }
758 }
759#endif
760 linux_dacs_write(linux_dacs[dev].d_fd, buf,
761 OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
762
763#if 0
764 if ((timenow = sys_getrealtime()) - timeref > 200)
765 {
766 post("dacslept %d",sys_getrealtime() - timeref);
767 if (!oss_blockmode)
768 sys_log_error(ERR_DACSLEPT);
769 else rtnval = SENDDACS_SLEPT;
770 }
771#endif
772 timeref = timenow;
773 }
774 thischan += nchannels;
775 }
776 memset(sys_soundout, 0,
777 sys_outchannels * (sizeof(float) * DEFDACBLKSIZE));
778
779 /* do input */
780
781 for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
782 {
783 int nchannels = linux_adcs[dev].d_nchannels;
784 linux_adcs_read(linux_adcs[dev].d_fd, buf,
785 OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp));
786
787#if 0
788 if ((timenow = sys_getrealtime()) - timeref > 200)
789 {
790 if (!oss_blockmode)
791 sys_log_error(ERR_ADCSLEPT);
792 else
793 rtnval = SENDDACS_SLEPT;
794 }
795#endif
796 timeref = timenow;
797
798 if (linux_adcs[dev].d_bytespersamp == 4)
799 {
800 for (i = DEFDACBLKSIZE*nchannels,
801 fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
802 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
803 {
804 *fp1 = ((t_sample)(*lp))*(t_sample)(1./2147483648.);
805 }
806 }
807 else
808 {
809 for (i = DEFDACBLKSIZE,fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
810 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
811 {
812 for (j=0;j<sys_inchannels;j++)
813 fp1[j*DEFDACBLKSIZE] = INVSCALE16(sp[j]);
814 }
815 }
816 thischan += nchannels;
817 }
818 if (thischan != sys_inchannels)
819 bug("inchannels");
820 return (rtnval);
821}
822
823void oss_listdevs( void)
824{
825 post("device listing not implemented in OSS yet\n");
826}
827
828void oss_getdevs(char *indevlist, int *nindevs,
829 char *outdevlist, int *noutdevs, int *canmulti,
830 int maxndev, int devdescsize)
831{
832 int i, ndev;
833 *canmulti = 2; /* supports multiple devices */
834 if ((ndev = oss_ndev) > maxndev)
835 ndev = maxndev;
836 for (i = 0; i < ndev; i++)
837 {
838 sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1);
839 sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1);
840 }
841 *nindevs = *noutdevs = ndev;
842}
843
844#endif
845/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
846* Winfried Ritsch, Karl MacMillan, and others.
847* For information on usage and redistribution, and for a DISCLAIMER OF ALL
848* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
849
850/* this file inputs and outputs audio using the OSS API available on linux. */
851
852#ifdef USEAPI_OSS
853
854#include <linux/soundcard.h>
855
856#include "m_pd.h"
857#include "s_stuff.h"
858#include <errno.h>
859#include <stdio.h>
860#include <unistd.h>
861#include <stdlib.h>
862#include <string.h>
863#include <sys/types.h>
864#include <sys/time.h>
865#include <sys/stat.h>
866#include <sys/ioctl.h>
867#include <fcntl.h>
868#include <sched.h>
869#include <sys/mman.h>
870
871
872/* Defines */
873#define DEBUG(x) x
874#define DEBUG2(x) {x;}
875
876#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
877#define OSS_MAXDEV 4 /* maximum number of input or output devices */
878#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
879#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
880#define OSS_DEFAULTCH 2
881#define RME_DEFAULTCH 8 /* need this even if RME undefined */
882typedef int16_t t_oss_int16;
883typedef int32_t t_oss_int32;
884#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
885#define OSS_BYTESPERCHAN(width) (DEFDACBLKSIZE * (width))
886#define OSS_XFERSAMPS(chans) (DEFDACBLKSIZE* (chans))
887#define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width))
888
889/* GLOBALS */
890static int linux_meters; /* true if we're metering */
891static float linux_inmax; /* max input amplitude */
892static float linux_outmax; /* max output amplitude */
893static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
894
895/* our device handles */
896
897typedef struct _oss_dev
898{
899 int d_fd;
900 unsigned int d_space; /* bytes available for writing/reading */
901 int d_bufsize; /* total buffer size in blocks for this device */
902 int d_dropcount; /* # of buffers to drop for resync (output only) */
903 unsigned int d_nchannels; /* number of channels for this device */
904 unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
905} t_oss_dev;
906
907static t_oss_dev linux_dacs[OSS_MAXDEV];
908static t_oss_dev linux_adcs[OSS_MAXDEV];
909static int linux_noutdevs = 0;
910static int linux_nindevs = 0;
911
912 /* exported variables */
913float sys_dacsr;
914t_sample *sys_soundout;
915t_sample *sys_soundin;
916
917 /* OSS-specific private variables */
918static int oss_blockmode = 1; /* flag to use "blockmode" */
919static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
920static char ossdsp[] = "/dev/dsp%d";
921
922 /* don't assume we can turn all 31 bits when doing float-to-fix;
923 otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
924#define FMAX 0x7ffff000
925#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
926
927
928/* ------------- private routines for all APIS ------------------- */
929
930static void linux_flush_all_underflows_to_zero(void)
931{
932/*
933 TODO: Implement similar thing for linux (GGeiger)
934
935 One day we will figure this out, I hope, because it
936 costs CPU time dearly on Intel - LT
937 */
938 /* union fpc_csr f;
939 f.fc_word = get_fpc_csr();
940 f.fc_struct.flush = 1;
941 set_fpc_csr(f.fc_word);
942 */
943}
944
945static int oss_ndev = 0;
946
947 /* find out how many OSS devices we have. Since this has to
948 open the devices to find out if they're there, we have
949 to be called before audio is actually started up. So we
950 cache the results, which in effect are the number of available
951 devices. */
952void oss_init(void)
953{
954 int fd, i;
955 static int countedthem = 0;
956 if (countedthem)
957 return;
958 for (i = 0; i < 10; i++)
959 {
960 char devname[100];
961 if (i == 0)
962 strcpy(devname, "/dev/dsp");
963 else sprintf(devname, "/dev/dsp%d", i);
964 if ( (fd = open(devname, O_WRONLY|O_NONBLOCK)) != -1)
965 {
966 oss_ndev++;
967 close(fd);
968 }
969 else break;
970 }
971 countedthem = 1;
972}
973
974
975void oss_set32bit( void)
976{
977 oss_32bit = 1;
978}
979
980
981typedef struct _multidev {
982 int fd;
983 int channels;
984 int format;
985} t_multidev;
986
987int oss_reset(int fd) {
988 int err;
989 if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0)
990 error("OSS: Could not reset");
991 return err;
992}
993
994 /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
995 but is proposed by Guenter Geiger to support extending OSS to handle
996 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
997 I'm not clear why this isn't called AFMT_S32_[SLN]E... */
998
999#ifndef AFMT_S32_BLOCKED
1000#define AFMT_S32_BLOCKED 0x0000400
1001#endif
1002
1003void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize)
1004{ /* IOhannes */
1005 int orig, param, nblk, fd = dev->d_fd, wantformat;
1006 int nchannels = dev->d_nchannels;
1007 int advwas = sys_schedadvance;
1008
1009 audio_buf_info ainfo;
1010
1011 /* IOhannes :
1012 * pd is very likely to crash if different formats are used on
1013 multiple soundcards
1014 */
1015
1016 /* set resolution - first try 4 byte samples */
1017 if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) &&
1018 (param & AFMT_S32_BLOCKED))
1019 {
1020 wantformat = AFMT_S32_BLOCKED;
1021 dev->d_bytespersamp = 4;
1022 }
1023 else
1024 {
1025 wantformat = AFMT_S16_NE;
1026 dev->d_bytespersamp = 2;
1027 }
1028 param = wantformat;
1029
1030 if (sys_verbose)
1031 post("bytes per sample = %d", dev->d_bytespersamp);
1032 if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1)
1033 fprintf(stderr,"OSS: Could not set DSP format\n");
1034 else if (wantformat != param)
1035 fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n",
1036 wantformat, param);
1037
1038 /* sample rate */
1039 orig = param = srate;
1040 if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1)
1041 fprintf(stderr,"OSS: Could not set sampling rate for device\n");
1042 else if( orig != param )
1043 fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n",
1044 orig, param );
1045
1046 if (oss_blockmode && !skipblocksize)
1047 {
1048 int fragbytes, logfragsize, nfragment;
1049 /* setting fragment count and size. */
1050 if (!linux_fragsize)
1051 {
1052 linux_fragsize = OSS_DEFFRAGSIZE;
1053 while (linux_fragsize > DEFDACBLKSIZE
1054 && linux_fragsize * 4 > sys_advance_samples)
1055 linux_fragsize = linux_fragsize/2;
1056 }
1057
1058 /* post("adv_samples %d", sys_advance_samples); */
1059 nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
1060
1061 fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
1062 logfragsize = ilog2(fragbytes);
1063
1064 if (fragbytes != (1 << logfragsize))
1065 post("warning: OSS takes only power of 2 blocksize; using %d",
1066 (1 << logfragsize)/(dev->d_bytespersamp * nchannels));
1067 if (sys_verbose)
1068 post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes);
1069
1070 param = orig = (nfragment<<16) + logfragsize;
1071 if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
1072 error("OSS: Could not set or read fragment size\n");
1073 if (param != orig)
1074 {
1075 nfragment = ((param >> 16) & 0xffff);
1076 logfragsize = (param & 0xffff);
1077 post("warning: actual fragments %d, blocksize %d",
1078 nfragment, (1 << logfragsize));
1079 }
1080 if (sys_verbose)
1081 post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
1082 }
1083 if (dac)
1084 {
1085 /* use "free space" to learn the buffer size. Normally you
1086 should set this to your own desired value; but this seems not
1087 to be implemented uniformly across different sound cards. LATER
1088 we should figure out what to do if the requested scheduler advance
1089 is greater than this buffer size; for now, we just print something
1090 out. */
1091
1092 int defect;
1093 if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
1094 fprintf(stderr,"OSS: ioctl on output device failed");
1095 dev->d_bufsize = ainfo.bytes;
1096
1097 defect = sys_advance_samples * (dev->d_bytespersamp * nchannels)
1098 - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
1099 if (defect > 0)
1100 {
1101 if (sys_verbose || defect > (dev->d_bufsize >> 2))
1102 fprintf(stderr,
1103 "OSS: requested audio buffer size %d limited to %d\n",
1104 sys_advance_samples * (dev->d_bytespersamp * nchannels),
1105 dev->d_bufsize);
1106 sys_advance_samples =
1107 (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) /
1108 (dev->d_bytespersamp *nchannels);
1109 }
1110 }
1111}
1112
1113static int oss_setchannels(int fd, int wantchannels, char *devname)
1114{ /* IOhannes */
1115 int param = wantchannels;
1116
1117 while (param>1) {
1118 int save = param;
1119 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) {
1120 error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
1121 } else {
1122 if (param == save) return (param);
1123 }
1124 param=save-1;
1125 }
1126
1127 return (0);
1128}
1129
1130#define O_AUDIOFLAG 0 /* O_NDELAY */
1131
1132int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
1133 int noutdev, int *outdev, int nchout, int *chout, int rate)
1134{ /* IOhannes */
1135 int capabilities = 0;
1136 int inchannels = 0, outchannels = 0;
1137 char devname[20];
1138 int n, i, fd;
1139 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
1140 int num_devs = 0;
1141 int wantmore=0;
1142 int spread = 0;
1143 audio_buf_info ainfo;
1144
1145 linux_nindevs = linux_noutdevs = 0;
1146
1147
1148 /* mark input devices unopened */
1149 for (i = 0; i < OSS_MAXDEV; i++)
1150 linux_adcs[i].d_fd = -1;
1151
1152 /* open output devices */
1153 wantmore=0;
1154 if (noutdev < 0 || nindev < 0)
1155 bug("linux_open_audio");
1156
1157 for (n = 0; n < noutdev; n++)
1158 {
1159 int gotchans, j, inindex = -1;
1160 int thisdevice = (outdev[n] >= 0 ? outdev[n] : n-1);
1161 int wantchannels = (nchout>n) ? chout[n] : wantmore;
1162 fd = -1;
1163 if (!wantchannels)
1164 goto end_out_loop;
1165
1166 if (thisdevice > 1)
1167 sprintf(devname, "/dev/dsp%d", thisdevice-1);
1168 else sprintf(devname, "/dev/dsp");
1169
1170 /* search for input request for same device. Succeed only
1171 if the number of channels matches. */
1172 for (j = 0; j < nindev; j++)
1173 if (indev[j] == thisdevice && chin[j] == wantchannels)
1174 inindex = j;
1175
1176 /* if the same device is requested for input and output,
1177 try to open it read/write */
1178 if (inindex >= 0)
1179 {
1180 sys_setalarm(1000000);
1181 if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1)
1182 {
1183 post("%s (read/write): %s", devname, strerror(errno));
1184 post("(now will try write-only...)");
1185 }
1186 else
1187 {
1188 if (sys_verbose)
1189 post("opened %s for reading and writing\n", devname);
1190 linux_adcs[inindex].d_fd = fd;
1191 }
1192 }
1193 /* if that didn't happen or if it failed, try write-only */
1194 if (fd == -1)
1195 {
1196 sys_setalarm(1000000);
1197 if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1)
1198 {
1199 post("%s (writeonly): %s",
1200 devname, strerror(errno));
1201 break;
1202 }
1203 if (sys_verbose)
1204 post("opened %s for writing only\n", devname);
1205 }
1206 if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
1207 error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
1208
1209 gotchans = oss_setchannels(fd,
1210 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
1211 devname);
1212
1213 if (sys_verbose)
1214 post("opened audio output on %s; got %d channels",
1215 devname, gotchans);
1216
1217 if (gotchans < 2)
1218 {
1219 /* can't even do stereo? just give up. */
1220 close(fd);
1221 }
1222 else
1223 {
1224 linux_dacs[linux_noutdevs].d_nchannels = gotchans;
1225 linux_dacs[linux_noutdevs].d_fd = fd;
1226 oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0);
1227
1228 linux_noutdevs++;
1229 outchannels += gotchans;
1230 if (inindex >= 0)
1231 {
1232 linux_adcs[inindex].d_nchannels = gotchans;
1233 chin[inindex] = gotchans;
1234 }
1235 }
1236 /* LATER think about spreading large numbers of channels over
1237 various dsp's and vice-versa */
1238 wantmore = wantchannels - gotchans;
1239 end_out_loop: ;
1240 }
1241
1242 /* open input devices */
1243 wantmore = 0;
1244 for (n = 0; n < nindev; n++)
1245 {
1246 int gotchans=0;
1247 int thisdevice = (indev[n] >= 0 ? indev[n] : n-1);
1248 int wantchannels = (nchin>n)?chin[n]:wantmore;
1249 int alreadyopened = 0;
1250 if (!wantchannels)
1251 goto end_in_loop;
1252
1253 if (thisdevice > 1)
1254 sprintf(devname, "/dev/dsp%d", thisdevice - 1);
1255 else sprintf(devname, "/dev/dsp");
1256
1257 sys_setalarm(1000000);
1258
1259 /* perhaps it's already open from the above? */
1260 if (linux_dacs[n].d_fd >= 0)
1261 {
1262 fd = linux_dacs[n].d_fd;
1263 alreadyopened = 1;
1264 }
1265 else
1266 {
1267 /* otherwise try to open it here. */
1268 if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1)
1269 {
1270 post("%s (readonly): %s", devname, strerror(errno));
1271 goto end_in_loop;
1272 }
1273 if (sys_verbose)
1274 post("opened %s for reading only\n", devname);
1275 }
1276 linux_adcs[linux_nindevs].d_fd = fd;
1277 gotchans = oss_setchannels(fd,
1278 (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
1279 devname);
1280 if (sys_verbose)
1281 post("opened audio input device %s; got %d channels",
1282 devname, gotchans);
1283
1284 if (gotchans < 1)
1285 {
1286 close(fd);
1287 goto end_in_loop;
1288 }
1289
1290 linux_adcs[linux_nindevs].d_nchannels = gotchans;
1291
1292 oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
1293
1294 inchannels += gotchans;
1295 linux_nindevs++;
1296
1297 wantmore = wantchannels-gotchans;
1298 /* LATER think about spreading large numbers of channels over
1299 various dsp's and vice-versa */
1300 end_in_loop: ;
1301 }
1302
1303 /* We have to do a read to start the engine. This is
1304 necessary because sys_send_dacs waits until the input
1305 buffer is filled and only reads on a filled buffer.
1306 This is good, because it's a way to make sure that we
1307 will not block. But I wonder why we only have to read
1308 from one of the devices and not all of them??? */
1309
1310 if (linux_nindevs)
1311 {
1312 if (sys_verbose)
1313 fprintf(stderr,("OSS: issuing first ADC 'read' ... "));
1314 read(linux_adcs[0].d_fd, buf,
1315 linux_adcs[0].d_bytespersamp *
1316 linux_adcs[0].d_nchannels * DEFDACBLKSIZE);
1317 if (sys_verbose)
1318 fprintf(stderr, "...done.\n");
1319 }
1320 sys_setalarm(0);
1321 return (0);
1322}
1323
1324void oss_close_audio( void)
1325{
1326 int i;
1327 for (i=0;i<linux_nindevs;i++)
1328 close(linux_adcs[i].d_fd);
1329
1330 for (i=0;i<linux_noutdevs;i++)
1331 close(linux_dacs[i].d_fd);
1332
1333 linux_nindevs = linux_noutdevs = 0;
1334}
1335
1336static int linux_dacs_write(int fd,void* buf,long bytes)
1337{
1338 return write(fd, buf, bytes);
1339}
1340
1341static int linux_adcs_read(int fd,void* buf,long bytes)
1342{
1343 return read(fd, buf, bytes);
1344}
1345
1346 /* query audio devices for "available" data size. */
1347static void oss_calcspace(void)
1348{
1349 int dev;
1350 audio_buf_info ainfo;
1351 for (dev=0; dev < linux_noutdevs; dev++)
1352 {
1353 if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
1354 fprintf(stderr,"OSS: ioctl on output device %d failed",dev);
1355 linux_dacs[dev].d_space = ainfo.bytes;
1356 }
1357
1358 for (dev = 0; dev < linux_nindevs; dev++)
1359 {
1360 if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
1361 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
1362 dev, linux_adcs[dev].d_fd);
1363 linux_adcs[dev].d_space = ainfo.bytes;
1364 }
1365}
1366
1367void linux_audiostatus(void)
1368{
1369 int dev;
1370 if (!oss_blockmode)
1371 {
1372 oss_calcspace();
1373 for (dev=0; dev < linux_noutdevs; dev++)
1374 fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space);
1375
1376 for (dev = 0; dev < linux_nindevs; dev++)
1377 fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
1378
1379 }
1380}
1381
1382/* this call resyncs audio output and input which will cause discontinuities
1383in audio output and/or input. */
1384
1385static void oss_doresync( void)
1386{
1387 int dev, zeroed = 0, wantsize;
1388 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
1389 audio_buf_info ainfo;
1390
1391 /* 1. if any input devices are ahead (have more than 1 buffer stored),
1392 drop one or more buffers worth */
1393 for (dev = 0; dev < linux_nindevs; dev++)
1394 {
1395 if (linux_adcs[dev].d_space == 0)
1396 {
1397 linux_adcs_read(linux_adcs[dev].d_fd, buf,
1398 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1399 linux_adcs[dev].d_bytespersamp));
1400 }
1401 else while (linux_adcs[dev].d_space >
1402 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1403 linux_adcs[dev].d_bytespersamp))
1404 {
1405 linux_adcs_read(linux_adcs[dev].d_fd, buf,
1406 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1407 linux_adcs[dev].d_bytespersamp));
1408 if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0)
1409 {
1410 fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
1411 dev, linux_adcs[dev].d_fd);
1412 break;
1413 }
1414 linux_adcs[dev].d_space = ainfo.bytes;
1415 }
1416 }
1417
1418 /* 2. if any output devices are behind, feed them zeros to catch them
1419 up */
1420 for (dev = 0; dev < linux_noutdevs; dev++)
1421 {
1422 while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
1423 sys_advance_samples * (linux_dacs[dev].d_nchannels *
1424 linux_dacs[dev].d_bytespersamp))
1425 {
1426 if (!zeroed)
1427 {
1428 unsigned int i;
1429 for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels);
1430 i++)
1431 buf[i] = 0;
1432 zeroed = 1;
1433 }
1434 linux_dacs_write(linux_dacs[dev].d_fd, buf,
1435 OSS_XFERSIZE(linux_dacs[dev].d_nchannels,
1436 linux_dacs[dev].d_bytespersamp));
1437 if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
1438 {
1439 fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
1440 dev, linux_dacs[dev].d_fd);
1441 break;
1442 }
1443 linux_dacs[dev].d_space = ainfo.bytes;
1444 }
1445 }
1446 /* 3. if any DAC devices are too far ahead, plan to drop the
1447 number of frames which will let the others catch up. */
1448 for (dev = 0; dev < linux_noutdevs; dev++)
1449 {
1450 if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
1451 (sys_advance_samples - 1) * linux_dacs[dev].d_nchannels *
1452 linux_dacs[dev].d_bytespersamp)
1453 {
1454 linux_dacs[dev].d_dropcount = sys_advance_samples - 1 -
1455 (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) /
1456 (linux_dacs[dev].d_nchannels *
1457 linux_dacs[dev].d_bytespersamp) ;
1458 }
1459 else linux_dacs[dev].d_dropcount = 0;
1460 }
1461}
1462
1463int oss_send_dacs(void)
1464{
1465 t_sample *fp1, *fp2;
1466 long fill;
1467 int i, j, dev, rtnval = SENDDACS_YES;
1468 char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
1469 t_oss_int16 *sp;
1470 t_oss_int32 *lp;
1471 /* the maximum number of samples we should have in the ADC buffer */
1472 int idle = 0;
1473 int thischan;
1474 t_time timeref, timenow;
1475
1476 if (!linux_nindevs && !linux_noutdevs)
1477 return (SENDDACS_NO);
1478
1479 if (!oss_blockmode)
1480 {
1481 /* determine whether we're idle. This is true if either (1)
1482 some input device has less than one buffer to read or (2) some
1483 output device has fewer than (sys_advance_samples) blocks buffered
1484 already. */
1485 oss_calcspace();
1486
1487 for (dev=0; dev < linux_noutdevs; dev++)
1488 if (linux_dacs[dev].d_dropcount ||
1489 (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space >
1490 sys_advance_samples * linux_dacs[dev].d_bytespersamp *
1491 linux_dacs[dev].d_nchannels))
1492 idle = 1;
1493 for (dev=0; dev < linux_nindevs; dev++)
1494 if (linux_adcs[dev].d_space <
1495 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1496 linux_adcs[dev].d_bytespersamp))
1497 idle = 1;
1498 }
1499
1500 if (idle && !oss_blockmode)
1501 {
1502 /* sometimes---rarely---when the ADC available-byte-count is
1503 zero, it's genuine, but usually it's because we're so
1504 late that the ADC has overrun its entire kernel buffer. We
1505 distinguish between the two by waiting 2 msec and asking again.
1506 There should be an error flag we could check instead; look for this
1507 someday... */
1508 for (dev = 0;dev < linux_nindevs; dev++)
1509 if (linux_adcs[dev].d_space == 0)
1510 {
1511 audio_buf_info ainfo;
1512 sys_microsleep(2000);
1513 oss_calcspace();
1514 if (linux_adcs[dev].d_space != 0) continue;
1515
1516 /* here's the bad case. Give up and resync. */
1517 sys_log_error(ERR_DATALATE);
1518 oss_doresync();
1519 return (SENDDACS_NO);
1520 }
1521 /* check for slippage between devices, either because
1522 data got lost in the driver from a previous late condition, or
1523 because the devices aren't synced. When we're idle, no
1524 input device should have more than one buffer readable and
1525 no output device should have less than sys_advance_samples-1
1526 */
1527
1528 for (dev=0; dev < linux_noutdevs; dev++)
1529 if (!linux_dacs[dev].d_dropcount &&
1530 (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space <
1531 (sys_advance_samples - 2) *
1532 (linux_dacs[dev].d_bytespersamp *
1533 linux_dacs[dev].d_nchannels)))
1534 goto badsync;
1535 for (dev=0; dev < linux_nindevs; dev++)
1536 if (linux_adcs[dev].d_space > 3 *
1537 OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
1538 linux_adcs[dev].d_bytespersamp))
1539 goto badsync;
1540
1541 /* return zero to tell the scheduler we're idle. */
1542 return (SENDDACS_NO);
1543 badsync:
1544 sys_log_error(ERR_RESYNC);
1545 oss_doresync();
1546 return (SENDDACS_NO);
1547
1548 }
1549
1550
1551 /* do output */
1552
1553 timeref = sys_getrealtime();
1554 for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
1555 {
1556 int nchannels = linux_dacs[dev].d_nchannels;
1557 if (linux_dacs[dev].d_dropcount)
1558 linux_dacs[dev].d_dropcount--;
1559 else
1560 {
1561 if (linux_dacs[dev].d_bytespersamp == 4)
1562 {
1563 for (i = DEFDACBLKSIZE * nchannels, fp1 = sys_soundout +
1564 DEFDACBLKSIZE*thischan,
1565 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
1566 {
1567 t_sample f = SCALE32(*fp1);
1568 *lp = (f >= 2147483647 ? 2147483647 :
1569 (f < -2147483647 ? -2147483647 : f));
1570 }
1571 }
1572 else
1573 {
1574 for (i = DEFDACBLKSIZE, fp1 = sys_soundout +
1575 DEFDACBLKSIZE*thischan,
1576 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
1577 {
1578 for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE)
1579 {
1580 int s = SCALE16(*fp2);
1581 if (s > 32767) s = 32767;
1582 else if (s < -32767) s = -32767;
1583 sp[j] = s;
1584 }
1585 }
1586 }
1587
1588
1589#if 0
1590#define PR_S "%8d"
1591 {
1592 int nm = 64;
1593 int* sp1 = buf;
1594 post("dac:");
1595 while (nm > 0)
1596 {
1597 post(PR_S PR_S PR_S PR_S PR_S PR_S PR_S PR_S,
1598 sp1[0], sp1[1], sp1[2], sp1[3], sp1[4], sp1[5], sp1[6], sp1[7]);
1599 nm -= 8;
1600 sp1 += 8;
1601 }
1602 }
1603#endif
1604 linux_dacs_write(linux_dacs[dev].d_fd, buf,
1605 OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
1606
1607#if 0
1608 if ((timenow = sys_getrealtime()) - timeref > 200)
1609 {
1610 post("dacslept %d",sys_getrealtime() - timeref);
1611 if (!oss_blockmode)
1612 sys_log_error(ERR_DACSLEPT);
1613 else rtnval = SENDDACS_SLEPT;
1614 }
1615#endif
1616 timeref = timenow;
1617 }
1618 thischan += nchannels;
1619 }
1620 memset(sys_soundout, 0,
1621 sys_outchannels * (sizeof(float) * DEFDACBLKSIZE));
1622
1623 /* do input */
1624
1625 for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
1626 {
1627 int nchannels = linux_adcs[dev].d_nchannels;
1628 linux_adcs_read(linux_adcs[dev].d_fd, buf,
1629 OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp));
1630
1631#if 0
1632 if ((timenow = sys_getrealtime()) - timeref > 200)
1633 {
1634 if (!oss_blockmode)
1635 sys_log_error(ERR_ADCSLEPT);
1636 else
1637 rtnval = SENDDACS_SLEPT;
1638 }
1639#endif
1640 timeref = timenow;
1641
1642 if (linux_adcs[dev].d_bytespersamp == 4)
1643 {
1644 for (i = DEFDACBLKSIZE*nchannels,
1645 fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
1646 lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
1647 {
1648 *fp1 = ((t_sample)(*lp))*(t_sample)(1./2147483648.);
1649 }
1650 }
1651 else
1652 {
1653 for (i = DEFDACBLKSIZE,fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
1654 sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
1655 {
1656 for (j=0;j<sys_inchannels;j++)
1657 fp1[j*DEFDACBLKSIZE] = INVSCALE16(sp[j]);
1658 }
1659 }
1660 thischan += nchannels;
1661 }
1662 if (thischan != sys_inchannels)
1663 bug("inchannels");
1664 return (rtnval);
1665}
1666
1667void oss_listdevs( void)
1668{
1669 post("device listing not implemented in OSS yet\n");
1670}
1671
1672void oss_getdevs(char *indevlist, int *nindevs,
1673 char *outdevlist, int *noutdevs, int *canmulti,
1674 int maxndev, int devdescsize)
1675{
1676 int i, ndev;
1677 *canmulti = 2; /* supports multiple devices */
1678 if ((ndev = oss_ndev) > maxndev)
1679 ndev = maxndev;
1680 for (i = 0; i < ndev; i++)
1681 {
1682 sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1);
1683 sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1);
1684 }
1685 *nindevs = *noutdevs = ndev;
1686}
1687
1688#endif
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_pa.c b/apps/plugins/pdbox/PDa/src/s_audio_pa.c
new file mode 100644
index 0000000000..ebae9679dc
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_audio_pa.c
@@ -0,0 +1,584 @@
1/* Copyright (c) 2001 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's
6 the main way in for Mac OS and, with Michael Casey's help, also into
7 ASIO in Windows. */
8
9
10#include "m_pd.h"
11#include "s_stuff.h"
12#include <stdio.h>
13#include <stdlib.h>
14#include "portaudio.h"
15#include "pablio_pd.h"
16
17 /* LATER try to figure out how to handle default devices in portaudio;
18 the way s_audio.c handles them isn't going to work here. */
19
20#if defined(MACOSX) || defined(MSW)
21#define Pa_GetDefaultInputDevice Pa_GetDefaultInputDeviceID
22#define Pa_GetDefaultOutputDevice Pa_GetDefaultOutputDeviceID
23#endif
24
25 /* public interface declared in m_imp.h */
26
27 /* implementation */
28static PABLIO_Stream *pa_stream;
29static int pa_inchans, pa_outchans;
30static float *pa_soundin, *pa_soundout;
31
32#define MAX_PA_CHANS 32
33#define MAX_SAMPLES_PER_FRAME MAX_PA_CHANS * DEFDACBLKSIZE
34
35int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
36 t_sample *soundout, int framesperbuf, int nbuffers,
37 int indeviceno, int outdeviceno)
38{
39 PaError err;
40 static int initialized;
41 int j, devno, pa_indev = 0, pa_outdev = 0;
42
43 if (!initialized)
44 {
45 /* Initialize PortAudio */
46 int err = Pa_Initialize();
47 if ( err != paNoError )
48 {
49 fprintf( stderr,
50 "Error number %d occured initializing portaudio\n",
51 err);
52 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
53 return (1);
54 }
55 initialized = 1;
56 }
57 /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
58 if (inchans != 0 && outchans != 0 && inchans != outchans)
59 error("portaudio: number of input and output channels must match");
60 if (inchans > MAX_PA_CHANS)
61 {
62 post("input channels reduced to maximum %d", MAX_PA_CHANS);
63 inchans = MAX_PA_CHANS;
64 }
65 if (outchans > MAX_PA_CHANS)
66 {
67 post("output channels reduced to maximum %d", MAX_PA_CHANS);
68 outchans = MAX_PA_CHANS;
69 }
70
71 if (inchans > 0)
72 {
73 for (j = 0, devno = 0; j < Pa_CountDevices(); j++)
74 {
75 const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
76 if (info->maxInputChannels > 0)
77 {
78 if (devno == indeviceno)
79 {
80 pa_indev = j;
81 break;
82 }
83 devno++;
84 }
85 }
86 }
87
88 if (outchans > 0)
89 {
90 for (j = 0, devno = 0; j < Pa_CountDevices(); j++)
91 {
92 const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
93 if (info->maxOutputChannels > 0)
94 {
95 if (devno == outdeviceno)
96 {
97 pa_outdev = j;
98 break;
99 }
100 devno++;
101 }
102 }
103 }
104
105 if (sys_verbose)
106 {
107 post("input device %d, channels %d", pa_indev, inchans);
108 post("output device %d, channels %d", pa_outdev, outchans);
109 post("framesperbuf %d, nbufs %d", framesperbuf, nbuffers);
110 }
111 if (inchans && outchans)
112 err = OpenAudioStream( &pa_stream, rate, paFloat32,
113 PABLIO_READ_WRITE, inchans, framesperbuf, nbuffers,
114 pa_indev, pa_outdev);
115 else if (inchans)
116 err = OpenAudioStream( &pa_stream, rate, paFloat32,
117 PABLIO_READ, inchans, framesperbuf, nbuffers,
118 pa_indev, pa_outdev);
119 else if (outchans)
120 err = OpenAudioStream( &pa_stream, rate, paFloat32,
121 PABLIO_WRITE, outchans, framesperbuf, nbuffers,
122 pa_indev, pa_outdev);
123 else err = 0;
124 if ( err != paNoError )
125 {
126 fprintf( stderr, "Error number %d occured opening portaudio stream\n",
127 err);
128 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
129 Pa_Terminate();
130 sys_inchannels = sys_outchannels = 0;
131 return (1);
132 }
133 else if (sys_verbose)
134 post("... opened OK.");
135 pa_inchans = inchans;
136 pa_outchans = outchans;
137 pa_soundin = soundin;
138 pa_soundout = soundout;
139 return (0);
140}
141
142void pa_close_audio( void)
143{
144 if (pa_inchans || pa_outchans)
145 CloseAudioStream( pa_stream );
146 pa_inchans = pa_outchans = 0;
147}
148
149int pa_send_dacs(void)
150{
151 float samples[MAX_SAMPLES_PER_FRAME], *fp1, *fp2;
152 int i, j;
153 double timebefore;
154
155 timebefore = sys_getrealtime();
156 if ((pa_inchans && GetAudioStreamReadable(pa_stream) < DEFDACBLKSIZE) ||
157 (pa_outchans && GetAudioStreamWriteable(pa_stream) < DEFDACBLKSIZE))
158 {
159 if (pa_inchans && pa_outchans)
160 {
161 int synced = 0;
162 while (GetAudioStreamWriteable(pa_stream) > 2*DEFDACBLKSIZE)
163 {
164 for (j = 0; j < pa_outchans; j++)
165 for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
166 fp2 += pa_outchans)
167 {
168 *fp2 = 0;
169 }
170 synced = 1;
171 WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE);
172 }
173 while (GetAudioStreamReadable(pa_stream) > 2*DEFDACBLKSIZE)
174 {
175 synced = 1;
176 ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE);
177 }
178 /* if (synced)
179 post("sync"); */
180 }
181 return (SENDDACS_NO);
182 }
183 if (pa_inchans)
184 {
185 ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE);
186 for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += DEFDACBLKSIZE)
187 for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
188 fp2 += pa_inchans)
189 {
190 fp1[i] = *fp2;
191 }
192 }
193#if 0
194 {
195 static int nread;
196 if (nread == 0)
197 {
198 post("it's %f %f %f %f",
199 pa_soundin[0], pa_soundin[1], pa_soundin[2], pa_soundin[3]);
200 nread = 1000;
201 }
202 nread--;
203 }
204#endif
205 if (pa_outchans)
206 {
207 for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++,
208 fp1 += DEFDACBLKSIZE)
209 for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
210 fp2 += pa_outchans)
211 {
212 *fp2 = fp1[i];
213 fp1[i] = 0;
214 }
215 WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE);
216 }
217
218 if (sys_getrealtime() > timebefore + 0.002)
219 {
220 /* post("slept"); */
221 return (SENDDACS_SLEPT);
222 }
223 else return (SENDDACS_YES);
224}
225
226
227void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */
228{
229 int i,j;
230 int numDevices;
231 const PaDeviceInfo *pdi;
232 PaError err;
233 Pa_Initialize();
234 numDevices = Pa_CountDevices();
235 if( numDevices < 0 )
236 {
237 fprintf(stderr, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
238 err = numDevices;
239 goto error;
240 }
241 fprintf(stderr, "Audio Devices:\n");
242 for( i=0; i<numDevices; i++ )
243 {
244 pdi = Pa_GetDeviceInfo( i );
245 fprintf(stderr, "device %d:", i+1 );
246 fprintf(stderr, " %s;", pdi->name );
247 fprintf(stderr, "%d inputs, ", pdi->maxInputChannels );
248 fprintf(stderr, "%d outputs", pdi->maxOutputChannels );
249 if ( i == Pa_GetDefaultInputDevice() )
250 fprintf(stderr, " (Default Input)");
251 if ( i == Pa_GetDefaultOutputDevice() )
252 fprintf(stderr, " (Default Output)");
253 fprintf(stderr, "\n");
254 }
255
256 fprintf(stderr, "\n");
257 return;
258
259error:
260 fprintf( stderr, "An error occured while using the portaudio stream\n" );
261 fprintf( stderr, "Error number: %d\n", err );
262 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
263
264}
265
266 /* scanning for devices */
267void pa_getdevs(char *indevlist, int *nindevs,
268 char *outdevlist, int *noutdevs, int *canmulti,
269 int maxndev, int devdescsize)
270{
271 int i, nin = 0, nout = 0, ndev;
272 *canmulti = 1; /* one dev each for input and output */
273
274 Pa_Initialize();
275 ndev = Pa_CountDevices();
276 for (i = 0; i < ndev; i++)
277 {
278 const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
279 if (pdi->maxInputChannels > 0 && nin < maxndev)
280 {
281 strcpy(indevlist + nin * devdescsize, pdi->name);
282 nin++;
283 }
284 if (pdi->maxOutputChannels > 0 && nout < maxndev)
285 {
286 strcpy(outdevlist + nout * devdescsize, pdi->name);
287 nout++;
288 }
289 }
290 *nindevs = nin;
291 *noutdevs = nout;
292}
293/* Copyright (c) 2001 Miller Puckette and others.
294* For information on usage and redistribution, and for a DISCLAIMER OF ALL
295* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
296
297/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's
298 the main way in for Mac OS and, with Michael Casey's help, also into
299 ASIO in Windows. */
300
301
302#include "m_pd.h"
303#include "s_stuff.h"
304#include <stdio.h>
305#include <stdlib.h>
306#include "portaudio.h"
307#include "pablio_pd.h"
308
309 /* LATER try to figure out how to handle default devices in portaudio;
310 the way s_audio.c handles them isn't going to work here. */
311
312#if defined(MACOSX) || defined(MSW)
313#define Pa_GetDefaultInputDevice Pa_GetDefaultInputDeviceID
314#define Pa_GetDefaultOutputDevice Pa_GetDefaultOutputDeviceID
315#endif
316
317 /* public interface declared in m_imp.h */
318
319 /* implementation */
320static PABLIO_Stream *pa_stream;
321static int pa_inchans, pa_outchans;
322static float *pa_soundin, *pa_soundout;
323
324#define MAX_PA_CHANS 32
325#define MAX_SAMPLES_PER_FRAME MAX_PA_CHANS * DEFDACBLKSIZE
326
327int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
328 t_sample *soundout, int framesperbuf, int nbuffers,
329 int indeviceno, int outdeviceno)
330{
331 PaError err;
332 static int initialized;
333 int j, devno, pa_indev = 0, pa_outdev = 0;
334
335 if (!initialized)
336 {
337 /* Initialize PortAudio */
338 int err = Pa_Initialize();
339 if ( err != paNoError )
340 {
341 fprintf( stderr,
342 "Error number %d occured initializing portaudio\n",
343 err);
344 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
345 return (1);
346 }
347 initialized = 1;
348 }
349 /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
350 if (inchans != 0 && outchans != 0 && inchans != outchans)
351 error("portaudio: number of input and output channels must match");
352 if (inchans > MAX_PA_CHANS)
353 {
354 post("input channels reduced to maximum %d", MAX_PA_CHANS);
355 inchans = MAX_PA_CHANS;
356 }
357 if (outchans > MAX_PA_CHANS)
358 {
359 post("output channels reduced to maximum %d", MAX_PA_CHANS);
360 outchans = MAX_PA_CHANS;
361 }
362
363 if (inchans > 0)
364 {
365 for (j = 0, devno = 0; j < Pa_CountDevices(); j++)
366 {
367 const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
368 if (info->maxInputChannels > 0)
369 {
370 if (devno == indeviceno)
371 {
372 pa_indev = j;
373 break;
374 }
375 devno++;
376 }
377 }
378 }
379
380 if (outchans > 0)
381 {
382 for (j = 0, devno = 0; j < Pa_CountDevices(); j++)
383 {
384 const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
385 if (info->maxOutputChannels > 0)
386 {
387 if (devno == outdeviceno)
388 {
389 pa_outdev = j;
390 break;
391 }
392 devno++;
393 }
394 }
395 }
396
397 if (sys_verbose)
398 {
399 post("input device %d, channels %d", pa_indev, inchans);
400 post("output device %d, channels %d", pa_outdev, outchans);
401 post("framesperbuf %d, nbufs %d", framesperbuf, nbuffers);
402 }
403 if (inchans && outchans)
404 err = OpenAudioStream( &pa_stream, rate, paFloat32,
405 PABLIO_READ_WRITE, inchans, framesperbuf, nbuffers,
406 pa_indev, pa_outdev);
407 else if (inchans)
408 err = OpenAudioStream( &pa_stream, rate, paFloat32,
409 PABLIO_READ, inchans, framesperbuf, nbuffers,
410 pa_indev, pa_outdev);
411 else if (outchans)
412 err = OpenAudioStream( &pa_stream, rate, paFloat32,
413 PABLIO_WRITE, outchans, framesperbuf, nbuffers,
414 pa_indev, pa_outdev);
415 else err = 0;
416 if ( err != paNoError )
417 {
418 fprintf( stderr, "Error number %d occured opening portaudio stream\n",
419 err);
420 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
421 Pa_Terminate();
422 sys_inchannels = sys_outchannels = 0;
423 return (1);
424 }
425 else if (sys_verbose)
426 post("... opened OK.");
427 pa_inchans = inchans;
428 pa_outchans = outchans;
429 pa_soundin = soundin;
430 pa_soundout = soundout;
431 return (0);
432}
433
434void pa_close_audio( void)
435{
436 if (pa_inchans || pa_outchans)
437 CloseAudioStream( pa_stream );
438 pa_inchans = pa_outchans = 0;
439}
440
441int pa_send_dacs(void)
442{
443 float samples[MAX_SAMPLES_PER_FRAME], *fp1, *fp2;
444 int i, j;
445 double timebefore;
446
447 timebefore = sys_getrealtime();
448 if ((pa_inchans && GetAudioStreamReadable(pa_stream) < DEFDACBLKSIZE) ||
449 (pa_outchans && GetAudioStreamWriteable(pa_stream) < DEFDACBLKSIZE))
450 {
451 if (pa_inchans && pa_outchans)
452 {
453 int synced = 0;
454 while (GetAudioStreamWriteable(pa_stream) > 2*DEFDACBLKSIZE)
455 {
456 for (j = 0; j < pa_outchans; j++)
457 for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
458 fp2 += pa_outchans)
459 {
460 *fp2 = 0;
461 }
462 synced = 1;
463 WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE);
464 }
465 while (GetAudioStreamReadable(pa_stream) > 2*DEFDACBLKSIZE)
466 {
467 synced = 1;
468 ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE);
469 }
470 /* if (synced)
471 post("sync"); */
472 }
473 return (SENDDACS_NO);
474 }
475 if (pa_inchans)
476 {
477 ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE);
478 for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += DEFDACBLKSIZE)
479 for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
480 fp2 += pa_inchans)
481 {
482 fp1[i] = *fp2;
483 }
484 }
485#if 0
486 {
487 static int nread;
488 if (nread == 0)
489 {
490 post("it's %f %f %f %f",
491 pa_soundin[0], pa_soundin[1], pa_soundin[2], pa_soundin[3]);
492 nread = 1000;
493 }
494 nread--;
495 }
496#endif
497 if (pa_outchans)
498 {
499 for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++,
500 fp1 += DEFDACBLKSIZE)
501 for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
502 fp2 += pa_outchans)
503 {
504 *fp2 = fp1[i];
505 fp1[i] = 0;
506 }
507 WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE);
508 }
509
510 if (sys_getrealtime() > timebefore + 0.002)
511 {
512 /* post("slept"); */
513 return (SENDDACS_SLEPT);
514 }
515 else return (SENDDACS_YES);
516}
517
518
519void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */
520{
521 int i,j;
522 int numDevices;
523 const PaDeviceInfo *pdi;
524 PaError err;
525 Pa_Initialize();
526 numDevices = Pa_CountDevices();
527 if( numDevices < 0 )
528 {
529 fprintf(stderr, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
530 err = numDevices;
531 goto error;
532 }
533 fprintf(stderr, "Audio Devices:\n");
534 for( i=0; i<numDevices; i++ )
535 {
536 pdi = Pa_GetDeviceInfo( i );
537 fprintf(stderr, "device %d:", i+1 );
538 fprintf(stderr, " %s;", pdi->name );
539 fprintf(stderr, "%d inputs, ", pdi->maxInputChannels );
540 fprintf(stderr, "%d outputs", pdi->maxOutputChannels );
541 if ( i == Pa_GetDefaultInputDevice() )
542 fprintf(stderr, " (Default Input)");
543 if ( i == Pa_GetDefaultOutputDevice() )
544 fprintf(stderr, " (Default Output)");
545 fprintf(stderr, "\n");
546 }
547
548 fprintf(stderr, "\n");
549 return;
550
551error:
552 fprintf( stderr, "An error occured while using the portaudio stream\n" );
553 fprintf( stderr, "Error number: %d\n", err );
554 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
555
556}
557
558 /* scanning for devices */
559void pa_getdevs(char *indevlist, int *nindevs,
560 char *outdevlist, int *noutdevs, int *canmulti,
561 int maxndev, int devdescsize)
562{
563 int i, nin = 0, nout = 0, ndev;
564 *canmulti = 1; /* one dev each for input and output */
565
566 Pa_Initialize();
567 ndev = Pa_CountDevices();
568 for (i = 0; i < ndev; i++)
569 {
570 const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
571 if (pdi->maxInputChannels > 0 && nin < maxndev)
572 {
573 strcpy(indevlist + nin * devdescsize, pdi->name);
574 nin++;
575 }
576 if (pdi->maxOutputChannels > 0 && nout < maxndev)
577 {
578 strcpy(outdevlist + nout * devdescsize, pdi->name);
579 nout++;
580 }
581 }
582 *nindevs = nin;
583 *noutdevs = nout;
584}
diff --git a/apps/plugins/pdbox/PDa/src/s_entry.c b/apps/plugins/pdbox/PDa/src/s_entry.c
new file mode 100644
index 0000000000..23a5cb7fe3
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_entry.c
@@ -0,0 +1,102 @@
1/* In MSW, this is all there is to pd; the rest sits in a "pdlib" dll so
2that externs can link back to functions defined in pd. */
3
4#include <stdio.h>
5
6int sys_main(int argc, char **argv);
7
8 /* WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler(
9 ULONG FirstHandler,
10 PVECTORED_EXCEPTION_HANDLER VectoredHandler ); */
11
12#ifdef MSW
13#if 0
14#incldue "winbase.h"
15
16LONG NTAPI VectoredExceptionHandler(void *PEXCEPTION_POINTERS)
17{
18 fprintf(stderr, "caught exception\n");
19 return(EXCEPTION_CONTINUE_SEARCH);
20}
21
22
23int main(int argc, char **argv)
24{
25 printf("Pd entry point\n");
26 AddVectoredExceptionHandler(
27 ULONG FirstHandler,
28 PVECTORED_EXCEPTION_HANDLER VectoredHandler );
29
30
31#endif
32
33#if 1
34int main(int argc, char **argv)
35{
36 __try
37 {
38 sys_main(argc, argv);
39 }
40 __finally
41 {
42 printf("caught an exception; stopping\n");
43 }
44}
45#endif
46#else /* not MSW */
47int main(int argc, char **argv)
48{
49 return (sys_main(argc, argv));
50}
51#endif
52/* In MSW, this is all there is to pd; the rest sits in a "pdlib" dll so
53that externs can link back to functions defined in pd. */
54
55#include <stdio.h>
56
57int sys_main(int argc, char **argv);
58
59 /* WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler(
60 ULONG FirstHandler,
61 PVECTORED_EXCEPTION_HANDLER VectoredHandler ); */
62
63#ifdef MSW
64#if 0
65#incldue "winbase.h"
66
67LONG NTAPI VectoredExceptionHandler(void *PEXCEPTION_POINTERS)
68{
69 fprintf(stderr, "caught exception\n");
70 return(EXCEPTION_CONTINUE_SEARCH);
71}
72
73
74int main(int argc, char **argv)
75{
76 printf("Pd entry point\n");
77 AddVectoredExceptionHandler(
78 ULONG FirstHandler,
79 PVECTORED_EXCEPTION_HANDLER VectoredHandler );
80
81
82#endif
83
84#if 1
85int main(int argc, char **argv)
86{
87 __try
88 {
89 sys_main(argc, argv);
90 }
91 __finally
92 {
93 printf("caught an exception; stopping\n");
94 }
95}
96#endif
97#else /* not MSW */
98int main(int argc, char **argv)
99{
100 return (sys_main(argc, argv));
101}
102#endif
diff --git a/apps/plugins/pdbox/PDa/src/s_file.c b/apps/plugins/pdbox/PDa/src/s_file.c
new file mode 100644
index 0000000000..2d3c4e5580
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_file.c
@@ -0,0 +1,110 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/*
6 * this file contains file-handling routines.
7 */
8
9#include "m_pd.h"
10#include "s_stuff.h"
11#include <sys/types.h>
12#include <sys/stat.h>
13
14 /* LATER delete this? -- replaced by find_via_path() in s_path.c */
15int sys_isreadablefile(const char *s)
16{
17 struct stat statbuf;
18 int mode;
19 if (stat(s, &statbuf) < 0) return (0);
20#ifdef UNIX
21 mode = statbuf.st_mode;
22 if (S_ISDIR(mode)) return (0);
23#endif
24 return (1);
25}
26
27 /* change '/' characters to the system's native file separator */
28void sys_bashfilename(const char *from, char *to)
29{
30 char c;
31 while (c = *from++)
32 {
33#ifdef MSW
34 if (c == '/') c = '\\';
35#endif
36 *to++ = c;
37 }
38 *to = 0;
39}
40
41
42 /* change the system's native file separator to '/' characters */
43void sys_unbashfilename(const char *from, char *to)
44{
45 char c;
46 while (c = *from++)
47 {
48#ifdef MSW
49 if (c == '\\') c = '/';
50#endif
51 *to++ = c;
52 }
53 *to = 0;
54}
55
56/* Copyright (c) 1997-1999 Miller Puckette.
57* For information on usage and redistribution, and for a DISCLAIMER OF ALL
58* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
59
60/*
61 * this file contains file-handling routines.
62 */
63
64#include "m_pd.h"
65#include "s_stuff.h"
66#include <sys/types.h>
67#include <sys/stat.h>
68
69 /* LATER delete this? -- replaced by find_via_path() in s_path.c */
70int sys_isreadablefile(const char *s)
71{
72 struct stat statbuf;
73 int mode;
74 if (stat(s, &statbuf) < 0) return (0);
75#ifdef UNIX
76 mode = statbuf.st_mode;
77 if (S_ISDIR(mode)) return (0);
78#endif
79 return (1);
80}
81
82 /* change '/' characters to the system's native file separator */
83void sys_bashfilename(const char *from, char *to)
84{
85 char c;
86 while (c = *from++)
87 {
88#ifdef MSW
89 if (c == '/') c = '\\';
90#endif
91 *to++ = c;
92 }
93 *to = 0;
94}
95
96
97 /* change the system's native file separator to '/' characters */
98void sys_unbashfilename(const char *from, char *to)
99{
100 char c;
101 while (c = *from++)
102 {
103#ifdef MSW
104 if (c == '\\') c = '/';
105#endif
106 *to++ = c;
107 }
108 *to = 0;
109}
110
diff --git a/apps/plugins/pdbox/PDa/src/s_inter.c b/apps/plugins/pdbox/PDa/src/s_inter.c
new file mode 100644
index 0000000000..37c44770ed
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_inter.c
@@ -0,0 +1,2000 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* Pd side of the Pd/Pd-gui interface. Also, some system interface routines
6that didn't really belong anywhere. */
7
8#include "m_pd.h"
9#include "s_stuff.h"
10#include "m_imp.h"
11#ifdef UNIX
12#include <unistd.h>
13#include <sys/socket.h>
14#include <netinet/in.h>
15#include <netinet/tcp.h>
16#include <netdb.h>
17#include <stdlib.h>
18#include <sys/time.h>
19#include <sys/mman.h>
20#endif
21#ifdef HAVE_BSTRING_H
22#include <bstring.h>
23#endif
24#ifdef MSW
25#include <io.h>
26#include <fcntl.h>
27#include <process.h>
28#include <winsock.h>
29typedef int pid_t;
30#define EADDRINUSE WSAEADDRINUSE
31#endif
32#include <stdarg.h>
33#include <signal.h>
34#include <fcntl.h>
35#include <errno.h>
36#include <string.h>
37#include <stdio.h>
38
39#ifdef MACOSX
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <pthread.h>
43#else
44#include <stdlib.h>
45#endif
46
47#define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */
48#define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */
49
50/* T.Grill - make it a _little_ more adaptable... */
51#ifndef PDBINDIR
52#define PDBINDIR "bin/"
53#endif
54
55#ifndef WISHAPP
56#define WISHAPP "wish83.exe"
57#endif
58
59extern char pd_version[];
60
61typedef struct _fdpoll
62{
63 int fdp_fd;
64 t_fdpollfn fdp_fn;
65 void *fdp_ptr;
66} t_fdpoll;
67
68#define INBUFSIZE 4096
69
70struct _socketreceiver
71{
72 char *sr_inbuf;
73 int sr_inhead;
74 int sr_intail;
75 void *sr_owner;
76 int sr_udp;
77 t_socketnotifier sr_notifier;
78 t_socketreceivefn sr_socketreceivefn;
79};
80
81static int sys_nfdpoll;
82static t_fdpoll *sys_fdpoll;
83static int sys_maxfd;
84static int sys_guisock;
85
86static t_binbuf *inbinbuf;
87static t_socketreceiver *sys_socketreceiver;
88extern int sys_addhist(int phase);
89
90#ifdef MSW
91static LARGE_INTEGER nt_inittime;
92static double nt_freq = 0;
93
94static void sys_initntclock(void)
95{
96 LARGE_INTEGER f1;
97 LARGE_INTEGER now;
98 QueryPerformanceCounter(&now);
99 if (!QueryPerformanceFrequency(&f1))
100 {
101 fprintf(stderr, "pd: QueryPerformanceFrequency failed\n");
102 f1.QuadPart = 1;
103 }
104 nt_freq = f1.QuadPart;
105 nt_inittime = now;
106}
107
108#if 0
109 /* this is a version you can call if you did the QueryPerformanceCounter
110 call yourself. Necessary for time tagging incoming MIDI at interrupt
111 level, for instance; but we're not doing that just now. */
112
113double nt_tixtotime(LARGE_INTEGER *dumbass)
114{
115 if (nt_freq == 0) sys_initntclock();
116 return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq);
117}
118#endif
119#endif /* MSW */
120
121 /* get "real time" in seconds; take the
122 first time we get called as a reference time of zero. */
123t_time sys_getrealtime(void)
124{
125#ifdef UNIX
126 static struct timeval then;
127 struct timeval now;
128 gettimeofday(&now, 0);
129 if (then.tv_sec == 0 && then.tv_usec == 0) then = now;
130 return (now.tv_sec - then.tv_sec)*1000000 +
131 (now.tv_usec - then.tv_usec);
132#endif
133#ifdef MSW
134 LARGE_INTEGER now;
135 QueryPerformanceCounter(&now);
136 if (nt_freq == 0) sys_initntclock();
137 return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq);
138#endif
139}
140
141void sys_sockerror(char *s)
142{
143#ifdef MSW
144 int err = WSAGetLastError();
145 if (err == 10054) return;
146 else if (err == 10044)
147 {
148 fprintf(stderr,
149 "Warning: you might not have TCP/IP \"networking\" turned on\n");
150 fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n");
151 }
152#endif
153#ifdef UNIX
154 int err = errno;
155#endif
156 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
157}
158
159void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr)
160{
161 int nfd = sys_nfdpoll;
162 int size = nfd * sizeof(t_fdpoll);
163 t_fdpoll *fp;
164 sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
165 size + sizeof(t_fdpoll));
166 fp = sys_fdpoll + nfd;
167 fp->fdp_fd = fd;
168 fp->fdp_fn = fn;
169 fp->fdp_ptr = ptr;
170 sys_nfdpoll = nfd + 1;
171 if (fd >= sys_maxfd) sys_maxfd = fd + 1;
172}
173
174void sys_rmpollfn(int fd)
175{
176 int nfd = sys_nfdpoll;
177 int i, size = nfd * sizeof(t_fdpoll);
178 t_fdpoll *fp;
179 for (i = nfd, fp = sys_fdpoll; i--; fp++)
180 {
181 if (fp->fdp_fd == fd)
182 {
183 while (i--)
184 {
185 fp[0] = fp[1];
186 fp++;
187 }
188 sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
189 size - sizeof(t_fdpoll));
190 sys_nfdpoll = nfd - 1;
191 return;
192 }
193 }
194 post("warning: %d removed from poll list but not found", fd);
195}
196
197static int sys_domicrosleep(int microsec, int pollem)
198{
199 struct timeval timout;
200 int i, didsomething = 0;
201 t_fdpoll *fp;
202 timout.tv_sec = 0;
203 timout.tv_usec = microsec;
204 if (pollem)
205 {
206 fd_set readset, writeset, exceptset;
207 FD_ZERO(&writeset);
208 FD_ZERO(&readset);
209 FD_ZERO(&exceptset);
210 for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++)
211 FD_SET(fp->fdp_fd, &readset);
212 select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout);
213 for (i = 0; i < sys_nfdpoll; i++)
214 if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset))
215 {
216 (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd);
217 didsomething = 1;
218 }
219 return (didsomething);
220 }
221 else
222 {
223 select(0, 0, 0, 0, &timout);
224 return (0);
225 }
226}
227
228void sys_microsleep(int microsec)
229{
230 sys_domicrosleep(microsec, 1);
231}
232
233t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier,
234 t_socketreceivefn socketreceivefn, int udp)
235{
236 t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x));
237 x->sr_inhead = x->sr_intail = 0;
238 x->sr_owner = owner;
239 x->sr_notifier = notifier;
240 x->sr_socketreceivefn = socketreceivefn;
241 x->sr_udp = udp;
242 if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_socketreceiver");;
243 return (x);
244}
245
246void socketreceiver_free(t_socketreceiver *x)
247{
248 free(x->sr_inbuf);
249 freebytes(x, sizeof(*x));
250}
251
252 /* this is in a separately called subroutine so that the buffer isn't
253 sitting on the stack while the messages are getting passed. */
254static int socketreceiver_doread(t_socketreceiver *x)
255{
256 char messbuf[INBUFSIZE], *bp = messbuf;
257 int indx;
258 int inhead = x->sr_inhead;
259 int intail = x->sr_intail;
260 char *inbuf = x->sr_inbuf;
261 if (intail == inhead) return (0);
262 for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1))
263 {
264 /* if we hit a semi that isn't preceeded by a \, it's a message
265 boundary. LATER we should deal with the possibility that the
266 preceeding \ might itself be escaped! */
267 char c = *bp++ = inbuf[indx];
268 if (c == ';' && (!indx || inbuf[indx-1] != '\\'))
269 {
270 intail = (indx+1)&(INBUFSIZE-1);
271 binbuf_text(inbinbuf, messbuf, bp - messbuf);
272 if (sys_debuglevel & DEBUG_MESSDOWN)
273 {
274 write(2, messbuf, bp - messbuf);
275 write(2, "\n", 1);
276 }
277 x->sr_inhead = inhead;
278 x->sr_intail = intail;
279 return (1);
280 }
281 }
282 return (0);
283}
284
285static void socketreceiver_getudp(t_socketreceiver *x, int fd)
286{
287 char buf[INBUFSIZE+1];
288 int ret = recv(fd, buf, INBUFSIZE, 0);
289 if (ret < 0)
290 {
291 sys_sockerror("recv");
292 sys_rmpollfn(fd);
293 sys_closesocket(fd);
294 }
295 else if (ret > 0)
296 {
297 buf[ret] = 0;
298#if 0
299 post("%s", buf);
300#endif
301 if (buf[ret-1] != '\n')
302 {
303#if 0
304 buf[ret] = 0;
305 error("dropped bad buffer %s\n", buf);
306#endif
307 }
308 else
309 {
310 char *semi = strchr(buf, ';');
311 if (semi)
312 *semi = 0;
313 binbuf_text(inbinbuf, buf, strlen(buf));
314 outlet_setstacklim();
315 if (x->sr_socketreceivefn)
316 (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
317 else bug("socketreceiver_getudp");
318 }
319 }
320}
321
322
323
324#include <termios.h>
325#include <string.h>
326
327static struct termios stored_settings;
328EXTERN int sys_stdin;
329
330void set_keypress(void)
331{
332 struct termios new_settings;
333
334 tcgetattr(0,&stored_settings);
335
336 new_settings = stored_settings;
337
338 /* Disable canonical mode, and set buffer size to 1 byte */
339 new_settings.c_lflag &= (~ICANON);
340 new_settings.c_cc[VTIME] = 0;
341 new_settings.c_cc[VMIN] = 1;
342
343/* echo off */
344 new_settings.c_lflag &= (~ECHO);
345
346 tcsetattr(0,TCSANOW,&new_settings);
347 return;
348}
349
350void reset_keypress(void)
351{
352 if (sys_stdin)
353 tcsetattr(0,TCSANOW,&stored_settings);
354 return;
355}
356
357static t_symbol* _ss;
358
359
360void stdin_read(t_socketreceiver *x, int fd) {
361 static char input[256];
362
363 char* in;
364 int got;
365
366 got = read(fd,input,256);
367 in = input;
368 while (got-- && _ss->s_thing)
369 pd_float(_ss->s_thing,(float)*in++);
370}
371
372void socketreceiver_read(t_socketreceiver *x, int fd)
373{
374 if (x->sr_udp) /* UDP ("datagram") socket protocol */
375 socketreceiver_getudp(x, fd);
376 else /* TCP ("streaming") socket protocol */
377 {
378 char *semi;
379 int readto =
380 (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
381 int ret;
382
383 /* the input buffer might be full. If so, drop the whole thing */
384 if (readto == x->sr_inhead)
385 {
386 fprintf(stderr, "pd: dropped message from gui\n");
387 x->sr_inhead = x->sr_intail = 0;
388 readto = INBUFSIZE;
389 }
390 else
391 {
392 ret = recv(fd, x->sr_inbuf + x->sr_inhead,
393 readto - x->sr_inhead, 0);
394 if (ret < 0)
395 {
396 sys_sockerror("recv");
397 if (x == sys_socketreceiver) sys_bail(1);
398 else
399 {
400 if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
401 sys_rmpollfn(fd);
402 sys_closesocket(fd);
403 }
404 }
405 else if (ret == 0)
406 {
407 if (x == sys_socketreceiver)
408 {
409 fprintf(stderr, "pd: exiting\n");
410 sys_bail(0);
411 }
412 else
413 {
414 post("EOF on socket %d\n", fd);
415 if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
416 sys_rmpollfn(fd);
417 sys_closesocket(fd);
418 }
419 }
420 else
421 {
422 x->sr_inhead += ret;
423 if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0;
424 while (socketreceiver_doread(x))
425 {
426 outlet_setstacklim();
427 if (x->sr_socketreceivefn)
428 (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
429 else binbuf_eval(inbinbuf, 0, 0, 0);
430 }
431 }
432 }
433 }
434}
435
436void sys_closesocket(int fd)
437{
438#ifdef UNIX
439 close(fd);
440#endif
441#ifdef MSW
442 closesocket(fd);
443#endif
444}
445
446
447void sys_gui(char *s)
448{
449 int length = strlen(s), written = 0, res, histwas = sys_addhist(4);
450 if (sys_debuglevel & DEBUG_MESSUP)
451 fprintf(stderr, "%s", s);
452 if (sys_nogui)
453 return;
454 while (1)
455 {
456 res = send(sys_guisock, s + written, length, 0);
457 if (res < 0)
458 {
459 perror("pd output pipe");
460 sys_bail(1);
461 }
462 else
463 {
464 written += res;
465 if (written >= length)
466 break;
467 }
468 }
469 sys_addhist(histwas);
470}
471
472/* LATER should do a bounds check -- but how do you get printf to do that?
473 See also rtext_senditup() in this regard */
474
475void sys_vgui(char *fmt, ...)
476{
477 int result, i;
478 char buf[2048];
479 va_list ap;
480
481 va_start(ap, fmt);
482 vsprintf(buf, fmt, ap);
483 sys_gui(buf);
484 va_end(ap);
485}
486
487
488#define FIRSTPORTNUM 5400
489
490/* -------------- signal handling for UNIX -------------- */
491
492#ifdef UNIX
493typedef void (*sighandler_t)(int);
494
495static void sys_signal(int signo, sighandler_t sigfun)
496{
497 struct sigaction action;
498 action.sa_flags = 0;
499 action.sa_handler = sigfun;
500 memset(&action.sa_mask, 0, sizeof(action.sa_mask));
501#if 0 /* GG says: don't use that */
502 action.sa_restorer = 0;
503#endif
504 if (sigaction(signo, &action, 0) < 0)
505 perror("sigaction");
506}
507
508static void sys_exithandler(int n)
509{
510 static int trouble = 0;
511 if (!trouble)
512 {
513 trouble = 1;
514 fprintf(stderr, "Pd: signal %d\n", n);
515 sys_bail(1);
516
517 }
518 else _exit(1);
519}
520
521static void sys_alarmhandler(int n)
522{
523 fprintf(stderr, "Pd: system call timed out\n");
524}
525
526static void sys_huphandler(int n)
527{
528 struct timeval timout;
529 timout.tv_sec = 0;
530 timout.tv_usec = 30000;
531 select(1, 0, 0, 0, &timout);
532}
533
534void sys_setalarm(int microsec)
535{
536 struct itimerval gonzo;
537#if 0
538 fprintf(stderr, "timer %d\n", microsec);
539#endif
540 gonzo.it_interval.tv_sec = 0;
541 gonzo.it_interval.tv_usec = 0;
542 gonzo.it_value.tv_sec = 0;
543 gonzo.it_value.tv_usec = microsec;
544 if (microsec)
545 sys_signal(SIGALRM, sys_alarmhandler);
546 else sys_signal(SIGALRM, SIG_IGN);
547 setitimer(ITIMER_REAL, &gonzo, 0);
548}
549
550#endif
551
552#ifdef __linux__
553
554#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK)
555#include <sched.h>
556#endif
557
558void sys_set_priority(int higher)
559{
560#ifdef _POSIX_PRIORITY_SCHEDULING
561 struct sched_param par;
562 int p1 ,p2, p3;
563 p1 = sched_get_priority_min(SCHED_FIFO);
564 p2 = sched_get_priority_max(SCHED_FIFO);
565#ifdef USEAPI_JACK
566 p3 = (higher ? p1 + 7 : p1 + 5);
567#else
568 p3 = (higher ? p2 - 1 : p2 - 3);
569#endif
570 par.sched_priority = p3;
571 if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
572 fprintf(stderr, "priority %d scheduling enabled.\n", p3);
573#endif
574
575#ifdef _POSIX_MEMLOCK
576 if (mlockall(MCL_FUTURE) != -1)
577 fprintf(stderr, "memory locking enabled.\n");
578#endif
579
580}
581
582#endif /* __linux__ */
583
584static int sys_watchfd;
585
586#ifdef __linux__
587void glob_ping(t_pd *dummy)
588{
589 if (write(sys_watchfd, "\n", 1) < 1)
590 {
591 fprintf(stderr, "pd: watchdog process died\n");
592 sys_bail(1);
593 }
594}
595#endif
596
597static int defaultfontshit[] = {
598 8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28,
599 24, 15, 28};
600
601int sys_startgui(const char *guidir)
602{
603 pid_t childpid;
604 char cmdbuf[4*MAXPDSTRING];
605 struct sockaddr_in server;
606 int msgsock;
607 char buf[15];
608 int len = sizeof(server);
609 int ntry = 0, portno = FIRSTPORTNUM;
610 int xsock = -1;
611#ifdef MSW
612 short version = MAKEWORD(2, 0);
613 WSADATA nobby;
614#endif
615#ifdef UNIX
616 int stdinpipe[2];
617#endif
618 /* create an empty FD poll list */
619 sys_fdpoll = (t_fdpoll *)t_getbytes(0);
620 sys_nfdpoll = 0;
621 inbinbuf = binbuf_new();
622
623#ifdef UNIX
624 signal(SIGHUP, sys_huphandler);
625 signal(SIGINT, sys_exithandler);
626 signal(SIGQUIT, sys_exithandler);
627 signal(SIGILL, sys_exithandler);
628 signal(SIGIOT, sys_exithandler);
629 signal(SIGFPE, SIG_IGN);
630 /* signal(SIGILL, sys_exithandler);
631 signal(SIGBUS, sys_exithandler);
632 signal(SIGSEGV, sys_exithandler); */
633 signal(SIGPIPE, SIG_IGN);
634 signal(SIGALRM, SIG_IGN);
635 signal(SIGTERM, SIG_IGN);
636#if 0 /* GG says: don't use that */
637 signal(SIGSTKFLT, sys_exithandler);
638#endif
639#endif
640#ifdef MSW
641 if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
642#endif
643
644 if (sys_nogui)
645 {
646 /* fake the GUI's message giving cwd and font sizes; then
647 skip starting the GUI up. */
648 t_atom zz[19];
649 int i;
650#ifdef MSW
651 if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0)
652 strcpy(cmdbuf, ".");
653#endif
654#ifdef UNIX
655 if (!getcwd(cmdbuf, MAXPDSTRING))
656 strcpy(cmdbuf, ".");
657
658#endif
659 SETSYMBOL(zz, gensym(cmdbuf));
660 for (i = 1; i < 22; i++)
661 SETFLOAT(zz + i, defaultfontshit[i-1]);
662 SETFLOAT(zz+22,0);
663 glob_initfromgui(0, 0, 23, zz);
664 }
665 else
666 {
667#ifdef MSW
668 char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80];
669 int spawnret;
670
671#endif
672#ifdef MSW
673 char intarg;
674#else
675 int intarg;
676#endif
677
678 /* create a socket */
679 xsock = socket(AF_INET, SOCK_STREAM, 0);
680 if (xsock < 0) sys_sockerror("socket");
681#if 0
682 intarg = 0;
683 if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF,
684 &intarg, sizeof(intarg)) < 0)
685 post("setsockopt (SO_RCVBUF) failed\n");
686 intarg = 0;
687 if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF,
688 &intarg, sizeof(intarg)) < 0)
689 post("setsockopt (SO_RCVBUF) failed\n");
690#endif
691 intarg = 1;
692 if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY,
693 &intarg, sizeof(intarg)) < 0)
694#ifndef MSW
695 post("setsockopt (TCP_NODELAY) failed\n")
696#endif
697 ;
698
699
700 server.sin_family = AF_INET;
701 server.sin_addr.s_addr = INADDR_ANY;
702
703 /* assign server port number */
704 server.sin_port = htons((unsigned short)portno);
705
706 /* name the socket */
707 while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0)
708 {
709#ifdef MSW
710 int err = WSAGetLastError();
711#endif
712#ifdef UNIX
713 int err = errno;
714#endif
715 if ((ntry++ > 20) || (err != EADDRINUSE))
716 {
717 perror("bind");
718 fprintf(stderr,
719 "Pd needs your machine to be configured with\n");
720 fprintf(stderr,
721 "'networking' turned on (see Pd's html doc for details.)\n");
722 exit(1);
723 }
724 portno++;
725 server.sin_port = htons((unsigned short)(portno));
726 }
727
728 if (sys_verbose) fprintf(stderr, "port %d\n", portno);
729
730 sys_socketreceiver = socketreceiver_new(0, 0, 0, 0);
731
732#ifdef UNIX
733 childpid = fork();
734 if (childpid < 0)
735 {
736 if (errno) perror("sys_startgui");
737 else fprintf(stderr, "sys_startgui failed\n");
738 return (1);
739 }
740 else if (!childpid) /* we're the child */
741 {
742 seteuid(getuid()); /* lose setuid priveliges */
743#ifndef MACOSX
744 /* the wish process in Unix will make a wish shell and
745 read/write standard in and out unless we close the
746 file descriptors. Somehow this doesn't make the MAC OSX
747 version of Wish happy...*/
748 if (pipe(stdinpipe) < 0)
749 sys_sockerror("pipe");
750 else
751 {
752 if (stdinpipe[0] != 0)
753 {
754 close (0);
755 dup2(stdinpipe[0], 0);
756 close(stdinpipe[0]);
757 }
758 }
759#endif
760 if (!sys_guicmd)
761 {
762#ifdef MACOSX
763 char *homedir = getenv("HOME"), filename[250];
764 struct stat statbuf;
765 if (!homedir || strlen(homedir) > 150)
766 goto nohomedir;
767 sprintf(filename,
768 "%s/Applications/Utilities/Wish shell.app/Contents/MacOS/Wish Shell",
769 homedir);
770 if (stat(filename, &statbuf) >= 0)
771 goto foundit;
772 sprintf(filename,
773 "%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell",
774 homedir);
775 if (stat(filename, &statbuf) >= 0)
776 goto foundit;
777 nohomedir:
778 strcpy(filename,
779 "/Applications/Utilities/Wish Shell.app/Contents/MacOS/Wish Shell");
780 if (stat(filename, &statbuf) >= 0)
781 goto foundit;
782 strcpy(filename,
783 "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell");
784 foundit:
785 sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno);
786#else
787 sprintf(cmdbuf,
788"TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \
789 \"%s/pd-gui\" %d\n",
790 sys_libdir->s_name, sys_libdir->s_name, guidir, portno);
791#endif
792 sys_guicmd = cmdbuf;
793 }
794 if (sys_verbose) fprintf(stderr, "%s", sys_guicmd);
795 execl("/bin/sh", "sh", "-c", sys_guicmd, 0);
796 perror("pd: exec");
797 _exit(1);
798 }
799#endif /* UNIX */
800
801#ifdef MSW
802 /* in MSW land "guipath" is unused; we just do everything from
803 the libdir. */
804 /* fprintf(stderr, "%s\n", sys_libdir->s_name); */
805
806 strcpy(scriptbuf, "\"");
807 strcat(scriptbuf, sys_libdir->s_name);
808 strcat(scriptbuf, "/" PDBINDIR "pd.tk\"");
809 sys_bashfilename(scriptbuf, scriptbuf);
810
811 sprintf(portbuf, "%d", portno);
812
813 strcpy(wishbuf, sys_libdir->s_name);
814 strcat(wishbuf, "/" PDBINDIR WISHAPP);
815 sys_bashfilename(wishbuf, wishbuf);
816
817 spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0);
818 if (spawnret < 0)
819 {
820 perror("spawnl");
821 fprintf(stderr, "%s: couldn't load TCL\n", wishbuf);
822 exit(1);
823 }
824
825#endif /* MSW */
826 }
827
828#ifdef __linux__
829 /* now that we've spun off the child process we can promote
830 our process's priority, if we happen to be root. */
831 if (sys_hipriority)
832 {
833 if (!getuid() || !geteuid())
834 {
835 /* To prevent lockup, we fork off a watchdog process with
836 higher real-time priority than ours. The GUI has to send
837 a stream of ping messages to the watchdog THROUGH the Pd
838 process which has to pick them up from the GUI and forward
839 them. If any of these things aren't happening the watchdog
840 starts sending "stop" and "cont" signals to the Pd process
841 to make it timeshare with the rest of the system. (Version
842 0.33P2 : if there's no GUI, the watchdog pinging is done
843 from the scheduler idle routine in this process instead.) */
844
845 int pipe9[2], watchpid;
846 if (pipe(pipe9) < 0)
847 {
848 seteuid(getuid()); /* lose setuid priveliges */
849 sys_sockerror("pipe");
850 return (1);
851 }
852 watchpid = fork();
853 if (watchpid < 0)
854 {
855 seteuid(getuid()); /* lose setuid priveliges */
856 if (errno)
857 perror("sys_startgui");
858 else fprintf(stderr, "sys_startgui failed\n");
859 return (1);
860 }
861 else if (!watchpid) /* we're the child */
862 {
863 sys_set_priority(1);
864 seteuid(getuid()); /* lose setuid priveliges */
865 if (pipe9[1] != 0)
866 {
867 dup2(pipe9[0], 0);
868 close(pipe9[0]);
869 }
870 close(pipe9[1]);
871
872 sprintf(cmdbuf, "%s/pd-watchdog\n", guidir);
873 if (sys_verbose) fprintf(stderr, "%s", cmdbuf);
874 execl("/bin/sh", "sh", "-c", cmdbuf, 0);
875 perror("pd: exec");
876 _exit(1);
877 }
878 else /* we're the parent */
879 {
880 sys_set_priority(0);
881 seteuid(getuid()); /* lose setuid priveliges */
882 close(pipe9[0]);
883 sys_watchfd = pipe9[1];
884 /* We also have to start the ping loop in the GUI;
885 this is done later when the socket is open. */
886 }
887 }
888 else
889 {
890 post("realtime setting failed because not root\n");
891 sys_hipriority = 0;
892 }
893 }
894
895 seteuid(getuid()); /* lose setuid priveliges */
896#endif /* __linux__ */
897
898#ifdef MSW
899 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
900 fprintf(stderr, "pd: couldn't set high priority class\n");
901#endif
902#ifdef MACOSX
903 if (sys_hipriority)
904 {
905 struct sched_param param;
906 int policy = SCHED_RR;
907 int err;
908 param.sched_priority = 80; // adjust 0 : 100
909
910 err = pthread_setschedparam(pthread_self(), policy, &param);
911 if (err)
912 post("warning: high priority scheduling failed\n");
913 }
914#endif /* MACOSX */
915
916 if (!sys_nogui)
917 {
918 char buf[256];
919 if (sys_verbose)
920 fprintf(stderr, "Waiting for connection request... \n");
921 if (listen(xsock, 5) < 0) sys_sockerror("listen");
922
923 sys_guisock = accept(xsock, (struct sockaddr *) &server, &len);
924#ifdef OOPS
925 close(xsock);
926#endif
927 if (sys_guisock < 0) sys_sockerror("accept");
928 sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read,
929 sys_socketreceiver);
930
931 if (sys_verbose)
932 fprintf(stderr, "... connected\n");
933
934 /* here is where we start the pinging. */
935#ifdef __linux__
936 if (sys_hipriority)
937 sys_gui("pdtk_watchdog\n");
938#endif
939 sys_get_audio_apis(buf);
940 sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf);
941 }
942 if (sys_stdin) {
943 set_keypress();
944 _ss = gensym("stdin");
945 sys_addpollfn(1, (t_fdpollfn) stdin_read,NULL);
946 }
947 return (0);
948
949}
950
951
952static int sys_poll_togui(void)
953{
954 /* LATER use this to flush output buffer to gui */
955 return (0);
956}
957
958int sys_pollgui(void)
959{
960 return (sys_domicrosleep(0, 1) || sys_poll_togui());
961}
962
963
964/* T.Grill - import clean quit function */
965extern void sys_exit(void);
966
967/* This is called when something bad has happened, like a segfault.
968Call glob_quit() below to exit cleanly.
969LATER try to save dirty documents even in the bad case. */
970void sys_bail(int n)
971{
972 static int reentered = 0;
973 reset_keypress();
974 if (!reentered)
975 {
976 reentered = 1;
977#ifndef __linux /* sys_close_audio() hangs if you're in a signal? */
978 fprintf(stderr, "closing audio...\n");
979 sys_close_audio();
980 fprintf(stderr, "closing MIDI...\n");
981 sys_close_midi();
982 fprintf(stderr, "... done.\n");
983#endif
984 exit(1);
985 }
986 else _exit(n);
987}
988
989void glob_quit(void *dummy)
990{
991 sys_vgui("exit\n");
992 if (!sys_nogui)
993 {
994 close(sys_guisock);
995 sys_rmpollfn(sys_guisock);
996 }
997 reset_keypress();
998 sys_bail(0);
999}
1000
1001/* Copyright (c) 1997-1999 Miller Puckette.
1002* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1003* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1004
1005/* Pd side of the Pd/Pd-gui interface. Also, some system interface routines
1006that didn't really belong anywhere. */
1007
1008#include "m_pd.h"
1009#include "s_stuff.h"
1010#include "m_imp.h"
1011#ifdef UNIX
1012#include <unistd.h>
1013#include <sys/socket.h>
1014#include <netinet/in.h>
1015#include <netinet/tcp.h>
1016#include <netdb.h>
1017#include <stdlib.h>
1018#include <sys/time.h>
1019#include <sys/mman.h>
1020#endif
1021#ifdef HAVE_BSTRING_H
1022#include <bstring.h>
1023#endif
1024#ifdef MSW
1025#include <io.h>
1026#include <fcntl.h>
1027#include <process.h>
1028#include <winsock.h>
1029typedef int pid_t;
1030#define EADDRINUSE WSAEADDRINUSE
1031#endif
1032#include <stdarg.h>
1033#include <signal.h>
1034#include <fcntl.h>
1035#include <errno.h>
1036#include <string.h>
1037#include <stdio.h>
1038
1039#ifdef MACOSX
1040#include <sys/types.h>
1041#include <sys/stat.h>
1042#include <pthread.h>
1043#else
1044#include <stdlib.h>
1045#endif
1046
1047#define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */
1048#define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */
1049
1050/* T.Grill - make it a _little_ more adaptable... */
1051#ifndef PDBINDIR
1052#define PDBINDIR "bin/"
1053#endif
1054
1055#ifndef WISHAPP
1056#define WISHAPP "wish83.exe"
1057#endif
1058
1059extern char pd_version[];
1060
1061typedef struct _fdpoll
1062{
1063 int fdp_fd;
1064 t_fdpollfn fdp_fn;
1065 void *fdp_ptr;
1066} t_fdpoll;
1067
1068#define INBUFSIZE 4096
1069
1070struct _socketreceiver
1071{
1072 char *sr_inbuf;
1073 int sr_inhead;
1074 int sr_intail;
1075 void *sr_owner;
1076 int sr_udp;
1077 t_socketnotifier sr_notifier;
1078 t_socketreceivefn sr_socketreceivefn;
1079};
1080
1081static int sys_nfdpoll;
1082static t_fdpoll *sys_fdpoll;
1083static int sys_maxfd;
1084static int sys_guisock;
1085
1086static t_binbuf *inbinbuf;
1087static t_socketreceiver *sys_socketreceiver;
1088extern int sys_addhist(int phase);
1089
1090#ifdef MSW
1091static LARGE_INTEGER nt_inittime;
1092static double nt_freq = 0;
1093
1094static void sys_initntclock(void)
1095{
1096 LARGE_INTEGER f1;
1097 LARGE_INTEGER now;
1098 QueryPerformanceCounter(&now);
1099 if (!QueryPerformanceFrequency(&f1))
1100 {
1101 fprintf(stderr, "pd: QueryPerformanceFrequency failed\n");
1102 f1.QuadPart = 1;
1103 }
1104 nt_freq = f1.QuadPart;
1105 nt_inittime = now;
1106}
1107
1108#if 0
1109 /* this is a version you can call if you did the QueryPerformanceCounter
1110 call yourself. Necessary for time tagging incoming MIDI at interrupt
1111 level, for instance; but we're not doing that just now. */
1112
1113double nt_tixtotime(LARGE_INTEGER *dumbass)
1114{
1115 if (nt_freq == 0) sys_initntclock();
1116 return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq);
1117}
1118#endif
1119#endif /* MSW */
1120
1121 /* get "real time" in seconds; take the
1122 first time we get called as a reference time of zero. */
1123t_time sys_getrealtime(void)
1124{
1125#ifdef UNIX
1126 static struct timeval then;
1127 struct timeval now;
1128 gettimeofday(&now, 0);
1129 if (then.tv_sec == 0 && then.tv_usec == 0) then = now;
1130 return (now.tv_sec - then.tv_sec)*1000000 +
1131 (now.tv_usec - then.tv_usec);
1132#endif
1133#ifdef MSW
1134 LARGE_INTEGER now;
1135 QueryPerformanceCounter(&now);
1136 if (nt_freq == 0) sys_initntclock();
1137 return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq);
1138#endif
1139}
1140
1141void sys_sockerror(char *s)
1142{
1143#ifdef MSW
1144 int err = WSAGetLastError();
1145 if (err == 10054) return;
1146 else if (err == 10044)
1147 {
1148 fprintf(stderr,
1149 "Warning: you might not have TCP/IP \"networking\" turned on\n");
1150 fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n");
1151 }
1152#endif
1153#ifdef UNIX
1154 int err = errno;
1155#endif
1156 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
1157}
1158
1159void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr)
1160{
1161 int nfd = sys_nfdpoll;
1162 int size = nfd * sizeof(t_fdpoll);
1163 t_fdpoll *fp;
1164 sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
1165 size + sizeof(t_fdpoll));
1166 fp = sys_fdpoll + nfd;
1167 fp->fdp_fd = fd;
1168 fp->fdp_fn = fn;
1169 fp->fdp_ptr = ptr;
1170 sys_nfdpoll = nfd + 1;
1171 if (fd >= sys_maxfd) sys_maxfd = fd + 1;
1172}
1173
1174void sys_rmpollfn(int fd)
1175{
1176 int nfd = sys_nfdpoll;
1177 int i, size = nfd * sizeof(t_fdpoll);
1178 t_fdpoll *fp;
1179 for (i = nfd, fp = sys_fdpoll; i--; fp++)
1180 {
1181 if (fp->fdp_fd == fd)
1182 {
1183 while (i--)
1184 {
1185 fp[0] = fp[1];
1186 fp++;
1187 }
1188 sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
1189 size - sizeof(t_fdpoll));
1190 sys_nfdpoll = nfd - 1;
1191 return;
1192 }
1193 }
1194 post("warning: %d removed from poll list but not found", fd);
1195}
1196
1197static int sys_domicrosleep(int microsec, int pollem)
1198{
1199 struct timeval timout;
1200 int i, didsomething = 0;
1201 t_fdpoll *fp;
1202 timout.tv_sec = 0;
1203 timout.tv_usec = microsec;
1204 if (pollem)
1205 {
1206 fd_set readset, writeset, exceptset;
1207 FD_ZERO(&writeset);
1208 FD_ZERO(&readset);
1209 FD_ZERO(&exceptset);
1210 for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++)
1211 FD_SET(fp->fdp_fd, &readset);
1212 select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout);
1213 for (i = 0; i < sys_nfdpoll; i++)
1214 if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset))
1215 {
1216 (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd);
1217 didsomething = 1;
1218 }
1219 return (didsomething);
1220 }
1221 else
1222 {
1223 select(0, 0, 0, 0, &timout);
1224 return (0);
1225 }
1226}
1227
1228void sys_microsleep(int microsec)
1229{
1230 sys_domicrosleep(microsec, 1);
1231}
1232
1233t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier,
1234 t_socketreceivefn socketreceivefn, int udp)
1235{
1236 t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x));
1237 x->sr_inhead = x->sr_intail = 0;
1238 x->sr_owner = owner;
1239 x->sr_notifier = notifier;
1240 x->sr_socketreceivefn = socketreceivefn;
1241 x->sr_udp = udp;
1242 if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_socketreceiver");;
1243 return (x);
1244}
1245
1246void socketreceiver_free(t_socketreceiver *x)
1247{
1248 free(x->sr_inbuf);
1249 freebytes(x, sizeof(*x));
1250}
1251
1252 /* this is in a separately called subroutine so that the buffer isn't
1253 sitting on the stack while the messages are getting passed. */
1254static int socketreceiver_doread(t_socketreceiver *x)
1255{
1256 char messbuf[INBUFSIZE], *bp = messbuf;
1257 int indx;
1258 int inhead = x->sr_inhead;
1259 int intail = x->sr_intail;
1260 char *inbuf = x->sr_inbuf;
1261 if (intail == inhead) return (0);
1262 for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1))
1263 {
1264 /* if we hit a semi that isn't preceeded by a \, it's a message
1265 boundary. LATER we should deal with the possibility that the
1266 preceeding \ might itself be escaped! */
1267 char c = *bp++ = inbuf[indx];
1268 if (c == ';' && (!indx || inbuf[indx-1] != '\\'))
1269 {
1270 intail = (indx+1)&(INBUFSIZE-1);
1271 binbuf_text(inbinbuf, messbuf, bp - messbuf);
1272 if (sys_debuglevel & DEBUG_MESSDOWN)
1273 {
1274 write(2, messbuf, bp - messbuf);
1275 write(2, "\n", 1);
1276 }
1277 x->sr_inhead = inhead;
1278 x->sr_intail = intail;
1279 return (1);
1280 }
1281 }
1282 return (0);
1283}
1284
1285static void socketreceiver_getudp(t_socketreceiver *x, int fd)
1286{
1287 char buf[INBUFSIZE+1];
1288 int ret = recv(fd, buf, INBUFSIZE, 0);
1289 if (ret < 0)
1290 {
1291 sys_sockerror("recv");
1292 sys_rmpollfn(fd);
1293 sys_closesocket(fd);
1294 }
1295 else if (ret > 0)
1296 {
1297 buf[ret] = 0;
1298#if 0
1299 post("%s", buf);
1300#endif
1301 if (buf[ret-1] != '\n')
1302 {
1303#if 0
1304 buf[ret] = 0;
1305 error("dropped bad buffer %s\n", buf);
1306#endif
1307 }
1308 else
1309 {
1310 char *semi = strchr(buf, ';');
1311 if (semi)
1312 *semi = 0;
1313 binbuf_text(inbinbuf, buf, strlen(buf));
1314 outlet_setstacklim();
1315 if (x->sr_socketreceivefn)
1316 (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
1317 else bug("socketreceiver_getudp");
1318 }
1319 }
1320}
1321
1322
1323
1324#include <termios.h>
1325#include <string.h>
1326
1327static struct termios stored_settings;
1328EXTERN int sys_stdin;
1329
1330void set_keypress(void)
1331{
1332 struct termios new_settings;
1333
1334 tcgetattr(0,&stored_settings);
1335
1336 new_settings = stored_settings;
1337
1338 /* Disable canonical mode, and set buffer size to 1 byte */
1339 new_settings.c_lflag &= (~ICANON);
1340 new_settings.c_cc[VTIME] = 0;
1341 new_settings.c_cc[VMIN] = 1;
1342
1343/* echo off */
1344 new_settings.c_lflag &= (~ECHO);
1345
1346 tcsetattr(0,TCSANOW,&new_settings);
1347 return;
1348}
1349
1350void reset_keypress(void)
1351{
1352 if (sys_stdin)
1353 tcsetattr(0,TCSANOW,&stored_settings);
1354 return;
1355}
1356
1357static t_symbol* _ss;
1358
1359
1360void stdin_read(t_socketreceiver *x, int fd) {
1361 static char input[256];
1362
1363 char* in;
1364 int got;
1365
1366 got = read(fd,input,256);
1367 in = input;
1368 while (got-- && _ss->s_thing)
1369 pd_float(_ss->s_thing,(float)*in++);
1370}
1371
1372void socketreceiver_read(t_socketreceiver *x, int fd)
1373{
1374 if (x->sr_udp) /* UDP ("datagram") socket protocol */
1375 socketreceiver_getudp(x, fd);
1376 else /* TCP ("streaming") socket protocol */
1377 {
1378 char *semi;
1379 int readto =
1380 (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
1381 int ret;
1382
1383 /* the input buffer might be full. If so, drop the whole thing */
1384 if (readto == x->sr_inhead)
1385 {
1386 fprintf(stderr, "pd: dropped message from gui\n");
1387 x->sr_inhead = x->sr_intail = 0;
1388 readto = INBUFSIZE;
1389 }
1390 else
1391 {
1392 ret = recv(fd, x->sr_inbuf + x->sr_inhead,
1393 readto - x->sr_inhead, 0);
1394 if (ret < 0)
1395 {
1396 sys_sockerror("recv");
1397 if (x == sys_socketreceiver) sys_bail(1);
1398 else
1399 {
1400 if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
1401 sys_rmpollfn(fd);
1402 sys_closesocket(fd);
1403 }
1404 }
1405 else if (ret == 0)
1406 {
1407 if (x == sys_socketreceiver)
1408 {
1409 fprintf(stderr, "pd: exiting\n");
1410 sys_bail(0);
1411 }
1412 else
1413 {
1414 post("EOF on socket %d\n", fd);
1415 if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
1416 sys_rmpollfn(fd);
1417 sys_closesocket(fd);
1418 }
1419 }
1420 else
1421 {
1422 x->sr_inhead += ret;
1423 if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0;
1424 while (socketreceiver_doread(x))
1425 {
1426 outlet_setstacklim();
1427 if (x->sr_socketreceivefn)
1428 (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
1429 else binbuf_eval(inbinbuf, 0, 0, 0);
1430 }
1431 }
1432 }
1433 }
1434}
1435
1436void sys_closesocket(int fd)
1437{
1438#ifdef UNIX
1439 close(fd);
1440#endif
1441#ifdef MSW
1442 closesocket(fd);
1443#endif
1444}
1445
1446
1447void sys_gui(char *s)
1448{
1449 int length = strlen(s), written = 0, res, histwas = sys_addhist(4);
1450 if (sys_debuglevel & DEBUG_MESSUP)
1451 fprintf(stderr, "%s", s);
1452 if (sys_nogui)
1453 return;
1454 while (1)
1455 {
1456 res = send(sys_guisock, s + written, length, 0);
1457 if (res < 0)
1458 {
1459 perror("pd output pipe");
1460 sys_bail(1);
1461 }
1462 else
1463 {
1464 written += res;
1465 if (written >= length)
1466 break;
1467 }
1468 }
1469 sys_addhist(histwas);
1470}
1471
1472/* LATER should do a bounds check -- but how do you get printf to do that?
1473 See also rtext_senditup() in this regard */
1474
1475void sys_vgui(char *fmt, ...)
1476{
1477 int result, i;
1478 char buf[2048];
1479 va_list ap;
1480
1481 va_start(ap, fmt);
1482 vsprintf(buf, fmt, ap);
1483 sys_gui(buf);
1484 va_end(ap);
1485}
1486
1487
1488#define FIRSTPORTNUM 5400
1489
1490/* -------------- signal handling for UNIX -------------- */
1491
1492#ifdef UNIX
1493typedef void (*sighandler_t)(int);
1494
1495static void sys_signal(int signo, sighandler_t sigfun)
1496{
1497 struct sigaction action;
1498 action.sa_flags = 0;
1499 action.sa_handler = sigfun;
1500 memset(&action.sa_mask, 0, sizeof(action.sa_mask));
1501#if 0 /* GG says: don't use that */
1502 action.sa_restorer = 0;
1503#endif
1504 if (sigaction(signo, &action, 0) < 0)
1505 perror("sigaction");
1506}
1507
1508static void sys_exithandler(int n)
1509{
1510 static int trouble = 0;
1511 if (!trouble)
1512 {
1513 trouble = 1;
1514 fprintf(stderr, "Pd: signal %d\n", n);
1515 sys_bail(1);
1516
1517 }
1518 else _exit(1);
1519}
1520
1521static void sys_alarmhandler(int n)
1522{
1523 fprintf(stderr, "Pd: system call timed out\n");
1524}
1525
1526static void sys_huphandler(int n)
1527{
1528 struct timeval timout;
1529 timout.tv_sec = 0;
1530 timout.tv_usec = 30000;
1531 select(1, 0, 0, 0, &timout);
1532}
1533
1534void sys_setalarm(int microsec)
1535{
1536 struct itimerval gonzo;
1537#if 0
1538 fprintf(stderr, "timer %d\n", microsec);
1539#endif
1540 gonzo.it_interval.tv_sec = 0;
1541 gonzo.it_interval.tv_usec = 0;
1542 gonzo.it_value.tv_sec = 0;
1543 gonzo.it_value.tv_usec = microsec;
1544 if (microsec)
1545 sys_signal(SIGALRM, sys_alarmhandler);
1546 else sys_signal(SIGALRM, SIG_IGN);
1547 setitimer(ITIMER_REAL, &gonzo, 0);
1548}
1549
1550#endif
1551
1552#ifdef __linux__
1553
1554#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK)
1555#include <sched.h>
1556#endif
1557
1558void sys_set_priority(int higher)
1559{
1560#ifdef _POSIX_PRIORITY_SCHEDULING
1561 struct sched_param par;
1562 int p1 ,p2, p3;
1563 p1 = sched_get_priority_min(SCHED_FIFO);
1564 p2 = sched_get_priority_max(SCHED_FIFO);
1565#ifdef USEAPI_JACK
1566 p3 = (higher ? p1 + 7 : p1 + 5);
1567#else
1568 p3 = (higher ? p2 - 1 : p2 - 3);
1569#endif
1570 par.sched_priority = p3;
1571 if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
1572 fprintf(stderr, "priority %d scheduling enabled.\n", p3);
1573#endif
1574
1575#ifdef _POSIX_MEMLOCK
1576 if (mlockall(MCL_FUTURE) != -1)
1577 fprintf(stderr, "memory locking enabled.\n");
1578#endif
1579
1580}
1581
1582#endif /* __linux__ */
1583
1584static int sys_watchfd;
1585
1586#ifdef __linux__
1587void glob_ping(t_pd *dummy)
1588{
1589 if (write(sys_watchfd, "\n", 1) < 1)
1590 {
1591 fprintf(stderr, "pd: watchdog process died\n");
1592 sys_bail(1);
1593 }
1594}
1595#endif
1596
1597static int defaultfontshit[] = {
1598 8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28,
1599 24, 15, 28};
1600
1601int sys_startgui(const char *guidir)
1602{
1603 pid_t childpid;
1604 char cmdbuf[4*MAXPDSTRING];
1605 struct sockaddr_in server;
1606 int msgsock;
1607 char buf[15];
1608 int len = sizeof(server);
1609 int ntry = 0, portno = FIRSTPORTNUM;
1610 int xsock = -1;
1611#ifdef MSW
1612 short version = MAKEWORD(2, 0);
1613 WSADATA nobby;
1614#endif
1615#ifdef UNIX
1616 int stdinpipe[2];
1617#endif
1618 /* create an empty FD poll list */
1619 sys_fdpoll = (t_fdpoll *)t_getbytes(0);
1620 sys_nfdpoll = 0;
1621 inbinbuf = binbuf_new();
1622
1623#ifdef UNIX
1624 signal(SIGHUP, sys_huphandler);
1625 signal(SIGINT, sys_exithandler);
1626 signal(SIGQUIT, sys_exithandler);
1627 signal(SIGILL, sys_exithandler);
1628 signal(SIGIOT, sys_exithandler);
1629 signal(SIGFPE, SIG_IGN);
1630 /* signal(SIGILL, sys_exithandler);
1631 signal(SIGBUS, sys_exithandler);
1632 signal(SIGSEGV, sys_exithandler); */
1633 signal(SIGPIPE, SIG_IGN);
1634 signal(SIGALRM, SIG_IGN);
1635 signal(SIGTERM, SIG_IGN);
1636#if 0 /* GG says: don't use that */
1637 signal(SIGSTKFLT, sys_exithandler);
1638#endif
1639#endif
1640#ifdef MSW
1641 if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
1642#endif
1643
1644 if (sys_nogui)
1645 {
1646 /* fake the GUI's message giving cwd and font sizes; then
1647 skip starting the GUI up. */
1648 t_atom zz[19];
1649 int i;
1650#ifdef MSW
1651 if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0)
1652 strcpy(cmdbuf, ".");
1653#endif
1654#ifdef UNIX
1655 if (!getcwd(cmdbuf, MAXPDSTRING))
1656 strcpy(cmdbuf, ".");
1657
1658#endif
1659 SETSYMBOL(zz, gensym(cmdbuf));
1660 for (i = 1; i < 22; i++)
1661 SETFLOAT(zz + i, defaultfontshit[i-1]);
1662 SETFLOAT(zz+22,0);
1663 glob_initfromgui(0, 0, 23, zz);
1664 }
1665 else
1666 {
1667#ifdef MSW
1668 char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80];
1669 int spawnret;
1670
1671#endif
1672#ifdef MSW
1673 char intarg;
1674#else
1675 int intarg;
1676#endif
1677
1678 /* create a socket */
1679 xsock = socket(AF_INET, SOCK_STREAM, 0);
1680 if (xsock < 0) sys_sockerror("socket");
1681#if 0
1682 intarg = 0;
1683 if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF,
1684 &intarg, sizeof(intarg)) < 0)
1685 post("setsockopt (SO_RCVBUF) failed\n");
1686 intarg = 0;
1687 if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF,
1688 &intarg, sizeof(intarg)) < 0)
1689 post("setsockopt (SO_RCVBUF) failed\n");
1690#endif
1691 intarg = 1;
1692 if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY,
1693 &intarg, sizeof(intarg)) < 0)
1694#ifndef MSW
1695 post("setsockopt (TCP_NODELAY) failed\n")
1696#endif
1697 ;
1698
1699
1700 server.sin_family = AF_INET;
1701 server.sin_addr.s_addr = INADDR_ANY;
1702
1703 /* assign server port number */
1704 server.sin_port = htons((unsigned short)portno);
1705
1706 /* name the socket */
1707 while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0)
1708 {
1709#ifdef MSW
1710 int err = WSAGetLastError();
1711#endif
1712#ifdef UNIX
1713 int err = errno;
1714#endif
1715 if ((ntry++ > 20) || (err != EADDRINUSE))
1716 {
1717 perror("bind");
1718 fprintf(stderr,
1719 "Pd needs your machine to be configured with\n");
1720 fprintf(stderr,
1721 "'networking' turned on (see Pd's html doc for details.)\n");
1722 exit(1);
1723 }
1724 portno++;
1725 server.sin_port = htons((unsigned short)(portno));
1726 }
1727
1728 if (sys_verbose) fprintf(stderr, "port %d\n", portno);
1729
1730 sys_socketreceiver = socketreceiver_new(0, 0, 0, 0);
1731
1732#ifdef UNIX
1733 childpid = fork();
1734 if (childpid < 0)
1735 {
1736 if (errno) perror("sys_startgui");
1737 else fprintf(stderr, "sys_startgui failed\n");
1738 return (1);
1739 }
1740 else if (!childpid) /* we're the child */
1741 {
1742 seteuid(getuid()); /* lose setuid priveliges */
1743#ifndef MACOSX
1744 /* the wish process in Unix will make a wish shell and
1745 read/write standard in and out unless we close the
1746 file descriptors. Somehow this doesn't make the MAC OSX
1747 version of Wish happy...*/
1748 if (pipe(stdinpipe) < 0)
1749 sys_sockerror("pipe");
1750 else
1751 {
1752 if (stdinpipe[0] != 0)
1753 {
1754 close (0);
1755 dup2(stdinpipe[0], 0);
1756 close(stdinpipe[0]);
1757 }
1758 }
1759#endif
1760 if (!sys_guicmd)
1761 {
1762#ifdef MACOSX
1763 char *homedir = getenv("HOME"), filename[250];
1764 struct stat statbuf;
1765 if (!homedir || strlen(homedir) > 150)
1766 goto nohomedir;
1767 sprintf(filename,
1768 "%s/Applications/Utilities/Wish shell.app/Contents/MacOS/Wish Shell",
1769 homedir);
1770 if (stat(filename, &statbuf) >= 0)
1771 goto foundit;
1772 sprintf(filename,
1773 "%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell",
1774 homedir);
1775 if (stat(filename, &statbuf) >= 0)
1776 goto foundit;
1777 nohomedir:
1778 strcpy(filename,
1779 "/Applications/Utilities/Wish Shell.app/Contents/MacOS/Wish Shell");
1780 if (stat(filename, &statbuf) >= 0)
1781 goto foundit;
1782 strcpy(filename,
1783 "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell");
1784 foundit:
1785 sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno);
1786#else
1787 sprintf(cmdbuf,
1788"TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \
1789 \"%s/pd-gui\" %d\n",
1790 sys_libdir->s_name, sys_libdir->s_name, guidir, portno);
1791#endif
1792 sys_guicmd = cmdbuf;
1793 }
1794 if (sys_verbose) fprintf(stderr, "%s", sys_guicmd);
1795 execl("/bin/sh", "sh", "-c", sys_guicmd, 0);
1796 perror("pd: exec");
1797 _exit(1);
1798 }
1799#endif /* UNIX */
1800
1801#ifdef MSW
1802 /* in MSW land "guipath" is unused; we just do everything from
1803 the libdir. */
1804 /* fprintf(stderr, "%s\n", sys_libdir->s_name); */
1805
1806 strcpy(scriptbuf, "\"");
1807 strcat(scriptbuf, sys_libdir->s_name);
1808 strcat(scriptbuf, "/" PDBINDIR "pd.tk\"");
1809 sys_bashfilename(scriptbuf, scriptbuf);
1810
1811 sprintf(portbuf, "%d", portno);
1812
1813 strcpy(wishbuf, sys_libdir->s_name);
1814 strcat(wishbuf, "/" PDBINDIR WISHAPP);
1815 sys_bashfilename(wishbuf, wishbuf);
1816
1817 spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0);
1818 if (spawnret < 0)
1819 {
1820 perror("spawnl");
1821 fprintf(stderr, "%s: couldn't load TCL\n", wishbuf);
1822 exit(1);
1823 }
1824
1825#endif /* MSW */
1826 }
1827
1828#ifdef __linux__
1829 /* now that we've spun off the child process we can promote
1830 our process's priority, if we happen to be root. */
1831 if (sys_hipriority)
1832 {
1833 if (!getuid() || !geteuid())
1834 {
1835 /* To prevent lockup, we fork off a watchdog process with
1836 higher real-time priority than ours. The GUI has to send
1837 a stream of ping messages to the watchdog THROUGH the Pd
1838 process which has to pick them up from the GUI and forward
1839 them. If any of these things aren't happening the watchdog
1840 starts sending "stop" and "cont" signals to the Pd process
1841 to make it timeshare with the rest of the system. (Version
1842 0.33P2 : if there's no GUI, the watchdog pinging is done
1843 from the scheduler idle routine in this process instead.) */
1844
1845 int pipe9[2], watchpid;
1846 if (pipe(pipe9) < 0)
1847 {
1848 seteuid(getuid()); /* lose setuid priveliges */
1849 sys_sockerror("pipe");
1850 return (1);
1851 }
1852 watchpid = fork();
1853 if (watchpid < 0)
1854 {
1855 seteuid(getuid()); /* lose setuid priveliges */
1856 if (errno)
1857 perror("sys_startgui");
1858 else fprintf(stderr, "sys_startgui failed\n");
1859 return (1);
1860 }
1861 else if (!watchpid) /* we're the child */
1862 {
1863 sys_set_priority(1);
1864 seteuid(getuid()); /* lose setuid priveliges */
1865 if (pipe9[1] != 0)
1866 {
1867 dup2(pipe9[0], 0);
1868 close(pipe9[0]);
1869 }
1870 close(pipe9[1]);
1871
1872 sprintf(cmdbuf, "%s/pd-watchdog\n", guidir);
1873 if (sys_verbose) fprintf(stderr, "%s", cmdbuf);
1874 execl("/bin/sh", "sh", "-c", cmdbuf, 0);
1875 perror("pd: exec");
1876 _exit(1);
1877 }
1878 else /* we're the parent */
1879 {
1880 sys_set_priority(0);
1881 seteuid(getuid()); /* lose setuid priveliges */
1882 close(pipe9[0]);
1883 sys_watchfd = pipe9[1];
1884 /* We also have to start the ping loop in the GUI;
1885 this is done later when the socket is open. */
1886 }
1887 }
1888 else
1889 {
1890 post("realtime setting failed because not root\n");
1891 sys_hipriority = 0;
1892 }
1893 }
1894
1895 seteuid(getuid()); /* lose setuid priveliges */
1896#endif /* __linux__ */
1897
1898#ifdef MSW
1899 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
1900 fprintf(stderr, "pd: couldn't set high priority class\n");
1901#endif
1902#ifdef MACOSX
1903 if (sys_hipriority)
1904 {
1905 struct sched_param param;
1906 int policy = SCHED_RR;
1907 int err;
1908 param.sched_priority = 80; // adjust 0 : 100
1909
1910 err = pthread_setschedparam(pthread_self(), policy, &param);
1911 if (err)
1912 post("warning: high priority scheduling failed\n");
1913 }
1914#endif /* MACOSX */
1915
1916 if (!sys_nogui)
1917 {
1918 char buf[256];
1919 if (sys_verbose)
1920 fprintf(stderr, "Waiting for connection request... \n");
1921 if (listen(xsock, 5) < 0) sys_sockerror("listen");
1922
1923 sys_guisock = accept(xsock, (struct sockaddr *) &server, &len);
1924#ifdef OOPS
1925 close(xsock);
1926#endif
1927 if (sys_guisock < 0) sys_sockerror("accept");
1928 sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read,
1929 sys_socketreceiver);
1930
1931 if (sys_verbose)
1932 fprintf(stderr, "... connected\n");
1933
1934 /* here is where we start the pinging. */
1935#ifdef __linux__
1936 if (sys_hipriority)
1937 sys_gui("pdtk_watchdog\n");
1938#endif
1939 sys_get_audio_apis(buf);
1940 sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf);
1941 }
1942 if (sys_stdin) {
1943 set_keypress();
1944 _ss = gensym("stdin");
1945 sys_addpollfn(1, (t_fdpollfn) stdin_read,NULL);
1946 }
1947 return (0);
1948
1949}
1950
1951
1952static int sys_poll_togui(void)
1953{
1954 /* LATER use this to flush output buffer to gui */
1955 return (0);
1956}
1957
1958int sys_pollgui(void)
1959{
1960 return (sys_domicrosleep(0, 1) || sys_poll_togui());
1961}
1962
1963
1964/* T.Grill - import clean quit function */
1965extern void sys_exit(void);
1966
1967/* This is called when something bad has happened, like a segfault.
1968Call glob_quit() below to exit cleanly.
1969LATER try to save dirty documents even in the bad case. */
1970void sys_bail(int n)
1971{
1972 static int reentered = 0;
1973 reset_keypress();
1974 if (!reentered)
1975 {
1976 reentered = 1;
1977#ifndef __linux /* sys_close_audio() hangs if you're in a signal? */
1978 fprintf(stderr, "closing audio...\n");
1979 sys_close_audio();
1980 fprintf(stderr, "closing MIDI...\n");
1981 sys_close_midi();
1982 fprintf(stderr, "... done.\n");
1983#endif
1984 exit(1);
1985 }
1986 else _exit(n);
1987}
1988
1989void glob_quit(void *dummy)
1990{
1991 sys_vgui("exit\n");
1992 if (!sys_nogui)
1993 {
1994 close(sys_guisock);
1995 sys_rmpollfn(sys_guisock);
1996 }
1997 reset_keypress();
1998 sys_bail(0);
1999}
2000
diff --git a/apps/plugins/pdbox/PDa/src/s_loader.c b/apps/plugins/pdbox/PDa/src/s_loader.c
new file mode 100644
index 0000000000..83a59f3556
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_loader.c
@@ -0,0 +1,338 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#ifdef DL_OPEN
6#include <dlfcn.h>
7#endif
8#ifdef UNIX
9#include <stdlib.h>
10#include <unistd.h>
11#endif
12#ifdef MSW
13#include <io.h>
14#include <windows.h>
15#endif
16#ifdef MACOSX
17#include <mach-o/dyld.h>
18#endif
19#include <string.h>
20#include "m_pd.h"
21#include "s_stuff.h"
22#include <stdio.h>
23
24typedef void (*t_xxx)(void);
25
26static char sys_dllextent[] =
27#ifdef __FreeBSD__
28 ".pd_freebsd";
29#endif
30#ifdef IRIX
31#ifdef N32
32 ".pd_irix6";
33#else
34 ".pd_irix5";
35#endif
36#endif
37#ifdef __linux__
38 ".pd_linux";
39#endif
40#ifdef MACOSX
41 ".pd_darwin";
42#endif
43#ifdef MSW
44 ".dll";
45#endif
46
47void class_set_extern_dir(t_symbol *s);
48
49#ifdef STATIC
50int sys_load_lib(char *dirname, char *classname)
51{ return 1;}
52#else
53int sys_load_lib(char *dirname, char *classname)
54{
55 char symname[MAXPDSTRING], filename[MAXPDSTRING], dirbuf[MAXPDSTRING],
56 classname2[MAXPDSTRING], *nameptr, *lastdot;
57 void *dlobj;
58 t_xxx makeout = NULL;
59 int fd;
60#ifdef MSW
61 HINSTANCE ntdll;
62#endif
63#if 0
64 fprintf(stderr, "lib %s %s\n", dirname, classname);
65#endif
66 /* try looking in the path for (classname).(sys_dllextent) ... */
67 if ((fd = open_via_path(dirname, classname, sys_dllextent,
68 dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
69 {
70 /* next try (classname)/(classname).(sys_dllextent) ... */
71 strncpy(classname2, classname, MAXPDSTRING);
72 filename[MAXPDSTRING-2] = 0;
73 strcat(classname2, "/");
74 strncat(classname2, classname, MAXPDSTRING-strlen(classname2));
75 filename[MAXPDSTRING-1] = 0;
76 if ((fd = open_via_path(dirname, classname2, sys_dllextent,
77 dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
78 {
79 return (0);
80 }
81 }
82
83
84 close(fd);
85 class_set_extern_dir(gensym(dirbuf));
86
87 /* refabricate the pathname */
88 strncpy(filename, dirbuf, MAXPDSTRING);
89 filename[MAXPDSTRING-2] = 0;
90 strcat(filename, "/");
91 strncat(filename, nameptr, MAXPDSTRING-strlen(filename));
92 filename[MAXPDSTRING-1] = 0;
93 /* extract the setup function name */
94 if (lastdot = strrchr(nameptr, '.'))
95 *lastdot = 0;
96
97#ifdef MACOSX
98 strcpy(symname, "_");
99 strcat(symname, nameptr);
100#else
101 strcpy(symname, nameptr);
102#endif
103 /* if the last character is a tilde, replace with "_tilde" */
104 if (symname[strlen(symname) - 1] == '~')
105 strcpy(symname + (strlen(symname) - 1), "_tilde");
106 /* and append _setup to form the C setup function name */
107 strcat(symname, "_setup");
108#ifdef DL_OPEN
109 dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
110 if (!dlobj)
111 {
112 post("%s: %s", filename, dlerror());
113 class_set_extern_dir(&s_);
114 return (0);
115 }
116 makeout = (t_xxx)dlsym(dlobj, symname);
117#endif
118#ifdef MSW
119 sys_bashfilename(filename, filename);
120 ntdll = LoadLibrary(filename);
121 if (!ntdll)
122 {
123 post("%s: couldn't load", filename);
124 class_set_extern_dir(&s_);
125 return (0);
126 }
127 makeout = (t_xxx)GetProcAddress(ntdll, symname);
128#endif
129#ifdef MACOSX
130 {
131 NSObjectFileImage image;
132 void *ret;
133 NSSymbol s;
134 if ( NSCreateObjectFileImageFromFile( filename, &image) != NSObjectFileImageSuccess )
135 {
136 post("%s: couldn't load", filename);
137 class_set_extern_dir(&s_);
138 return 0;
139 }
140 ret = NSLinkModule( image, filename,
141 NSLINKMODULE_OPTION_BINDNOW + NSLINKMODULE_OPTION_PRIVATE);
142
143 s = NSLookupSymbolInModule(ret, symname);
144
145 if (s)
146 makeout = (t_xxx)NSAddressOfSymbol( s);
147 else makeout = 0;
148 }
149#endif
150
151 if (!makeout)
152 {
153 post("load_object: Symbol \"%s\" not found", symname);
154 class_set_extern_dir(&s_);
155 return 0;
156 }
157 (*makeout)();
158 class_set_extern_dir(&s_);
159 return (1);
160}
161
162#endif
163
164
165
166
167
168
169
170/* Copyright (c) 1997-1999 Miller Puckette.
171* For information on usage and redistribution, and for a DISCLAIMER OF ALL
172* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
173
174#ifdef DL_OPEN
175#include <dlfcn.h>
176#endif
177#ifdef UNIX
178#include <stdlib.h>
179#include <unistd.h>
180#endif
181#ifdef MSW
182#include <io.h>
183#include <windows.h>
184#endif
185#ifdef MACOSX
186#include <mach-o/dyld.h>
187#endif
188#include <string.h>
189#include "m_pd.h"
190#include "s_stuff.h"
191#include <stdio.h>
192
193typedef void (*t_xxx)(void);
194
195static char sys_dllextent[] =
196#ifdef __FreeBSD__
197 ".pd_freebsd";
198#endif
199#ifdef IRIX
200#ifdef N32
201 ".pd_irix6";
202#else
203 ".pd_irix5";
204#endif
205#endif
206#ifdef __linux__
207 ".pd_linux";
208#endif
209#ifdef MACOSX
210 ".pd_darwin";
211#endif
212#ifdef MSW
213 ".dll";
214#endif
215
216void class_set_extern_dir(t_symbol *s);
217
218#ifdef STATIC
219int sys_load_lib(char *dirname, char *classname)
220{ return 1;}
221#else
222int sys_load_lib(char *dirname, char *classname)
223{
224 char symname[MAXPDSTRING], filename[MAXPDSTRING], dirbuf[MAXPDSTRING],
225 classname2[MAXPDSTRING], *nameptr, *lastdot;
226 void *dlobj;
227 t_xxx makeout = NULL;
228 int fd;
229#ifdef MSW
230 HINSTANCE ntdll;
231#endif
232#if 0
233 fprintf(stderr, "lib %s %s\n", dirname, classname);
234#endif
235 /* try looking in the path for (classname).(sys_dllextent) ... */
236 if ((fd = open_via_path(dirname, classname, sys_dllextent,
237 dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
238 {
239 /* next try (classname)/(classname).(sys_dllextent) ... */
240 strncpy(classname2, classname, MAXPDSTRING);
241 filename[MAXPDSTRING-2] = 0;
242 strcat(classname2, "/");
243 strncat(classname2, classname, MAXPDSTRING-strlen(classname2));
244 filename[MAXPDSTRING-1] = 0;
245 if ((fd = open_via_path(dirname, classname2, sys_dllextent,
246 dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
247 {
248 return (0);
249 }
250 }
251
252
253 close(fd);
254 class_set_extern_dir(gensym(dirbuf));
255
256 /* refabricate the pathname */
257 strncpy(filename, dirbuf, MAXPDSTRING);
258 filename[MAXPDSTRING-2] = 0;
259 strcat(filename, "/");
260 strncat(filename, nameptr, MAXPDSTRING-strlen(filename));
261 filename[MAXPDSTRING-1] = 0;
262 /* extract the setup function name */
263 if (lastdot = strrchr(nameptr, '.'))
264 *lastdot = 0;
265
266#ifdef MACOSX
267 strcpy(symname, "_");
268 strcat(symname, nameptr);
269#else
270 strcpy(symname, nameptr);
271#endif
272 /* if the last character is a tilde, replace with "_tilde" */
273 if (symname[strlen(symname) - 1] == '~')
274 strcpy(symname + (strlen(symname) - 1), "_tilde");
275 /* and append _setup to form the C setup function name */
276 strcat(symname, "_setup");
277#ifdef DL_OPEN
278 dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
279 if (!dlobj)
280 {
281 post("%s: %s", filename, dlerror());
282 class_set_extern_dir(&s_);
283 return (0);
284 }
285 makeout = (t_xxx)dlsym(dlobj, symname);
286#endif
287#ifdef MSW
288 sys_bashfilename(filename, filename);
289 ntdll = LoadLibrary(filename);
290 if (!ntdll)
291 {
292 post("%s: couldn't load", filename);
293 class_set_extern_dir(&s_);
294 return (0);
295 }
296 makeout = (t_xxx)GetProcAddress(ntdll, symname);
297#endif
298#ifdef MACOSX
299 {
300 NSObjectFileImage image;
301 void *ret;
302 NSSymbol s;
303 if ( NSCreateObjectFileImageFromFile( filename, &image) != NSObjectFileImageSuccess )
304 {
305 post("%s: couldn't load", filename);
306 class_set_extern_dir(&s_);
307 return 0;
308 }
309 ret = NSLinkModule( image, filename,
310 NSLINKMODULE_OPTION_BINDNOW + NSLINKMODULE_OPTION_PRIVATE);
311
312 s = NSLookupSymbolInModule(ret, symname);
313
314 if (s)
315 makeout = (t_xxx)NSAddressOfSymbol( s);
316 else makeout = 0;
317 }
318#endif
319
320 if (!makeout)
321 {
322 post("load_object: Symbol \"%s\" not found", symname);
323 class_set_extern_dir(&s_);
324 return 0;
325 }
326 (*makeout)();
327 class_set_extern_dir(&s_);
328 return (1);
329}
330
331#endif
332
333
334
335
336
337
338
diff --git a/apps/plugins/pdbox/PDa/src/s_main.c b/apps/plugins/pdbox/PDa/src/s_main.c
new file mode 100644
index 0000000000..84f4cfbbc2
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_main.c
@@ -0,0 +1,1676 @@
1/* Copyright (c) 1997-1999 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* IOhannes :
6 * hacked the code to add advanced multidevice-support
7 * 1311:forum::für::umläute:2001
8 */
9
10char pd_version[] = "Pd version 0.37.4\n";
11char pd_compiletime[] = __TIME__;
12char pd_compiledate[] = __DATE__;
13
14#include "m_pd.h"
15#include "m_imp.h"
16#include "s_stuff.h"
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <limits.h>
20#include <string.h>
21#include <stdio.h>
22#include <fcntl.h>
23#include <stdlib.h>
24
25#ifdef UNIX
26#include <unistd.h>
27#endif
28#ifdef MSW
29#include <io.h>
30#include <windows.h>
31#include <winbase.h>
32#endif
33
34void pd_init(void);
35int sys_argparse(int argc, char **argv);
36void sys_findprogdir(char *progname);
37int sys_startgui(const char *guipath);
38int sys_rcfile(void);
39int m_scheduler(void);
40void sys_addhelppath(char *p);
41void alsa_adddev(char *name);
42
43int sys_debuglevel;
44int sys_verbose;
45int sys_noloadbang;
46int sys_nogui;
47int sys_stdin = 0;
48char *sys_guicmd;
49t_symbol *sys_libdir;
50static t_symbol *sys_guidir;
51static t_namelist *sys_externlist;
52static t_namelist *sys_openlist;
53static t_namelist *sys_messagelist;
54static int sys_version;
55int sys_oldtclversion; /* hack to warn g_rtext.c about old text sel */
56
57int sys_nmidiout = 1;
58#ifdef MSW
59int sys_nmidiin = 0;
60#else
61int sys_nmidiin = 1;
62#endif
63int sys_midiindevlist[MAXMIDIINDEV] = {1};
64int sys_midioutdevlist[MAXMIDIOUTDEV] = {1};
65
66static int sys_main_srate = DEFAULTSRATE;
67static int sys_main_advance = DEFAULTADVANCE;
68
69/* IOhannes { */
70
71 /* here the "-1" counts signify that the corresponding vector hasn't been
72 specified in command line arguments; sys_open_audio will detect this
73 and fill things in. */
74int sys_nsoundin = -1;
75int sys_nsoundout = -1;
76int sys_soundindevlist[MAXAUDIOINDEV];
77int sys_soundoutdevlist[MAXAUDIOOUTDEV];
78
79int sys_nchin = -1;
80int sys_nchout = -1;
81int sys_chinlist[MAXAUDIOINDEV];
82int sys_choutlist[MAXAUDIOOUTDEV];
83/* } IOhannes */
84
85
86typedef struct _fontinfo
87{
88 int fi_fontsize;
89 int fi_maxwidth;
90 int fi_maxheight;
91 int fi_hostfontsize;
92 int fi_width;
93 int fi_height;
94} t_fontinfo;
95
96 /* these give the nominal point size and maximum height of the characters
97 in the six fonts. */
98
99static t_fontinfo sys_fontlist[] = {
100 {8, 5, 9, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
101 {16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
102#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
103
104/* here are the actual font size structs on msp's systems:
105MSW:
106font 8 5 9 8 5 11
107font 10 7 13 10 6 13
108font 12 9 16 14 8 16
109font 16 10 20 16 10 18
110font 24 15 25 16 10 18
111font 36 25 42 36 22 41
112
113linux:
114font 8 5 9 8 5 9
115font 10 7 13 12 7 13
116font 12 9 16 14 9 15
117font 16 10 20 16 10 19
118font 24 15 25 24 15 24
119font 36 25 42 36 22 41
120*/
121
122static t_fontinfo *sys_findfont(int fontsize)
123{
124 unsigned int i;
125 t_fontinfo *fi;
126 for (i = 0, fi = sys_fontlist; i < (NFONT-1); i++, fi++)
127 if (fontsize < fi[1].fi_fontsize) return (fi);
128 return (sys_fontlist + (NFONT-1));
129}
130
131int sys_nearestfontsize(int fontsize)
132{
133 return (sys_findfont(fontsize)->fi_fontsize);
134}
135
136int sys_hostfontsize(int fontsize)
137{
138 return (sys_findfont(fontsize)->fi_hostfontsize);
139}
140
141int sys_fontwidth(int fontsize)
142{
143 return (sys_findfont(fontsize)->fi_width);
144}
145
146int sys_fontheight(int fontsize)
147{
148 return (sys_findfont(fontsize)->fi_height);
149}
150
151int sys_defaultfont;
152#ifdef MSW
153#define DEFAULTFONT 12
154#else
155#define DEFAULTFONT 10
156#endif
157
158static void openit(const char *dirname, const char *filename)
159{
160 char dirbuf[MAXPDSTRING], *nameptr;
161 int fd = open_via_path(dirname, filename, "", dirbuf, &nameptr,
162 MAXPDSTRING, 0);
163 if (fd)
164 {
165 close (fd);
166 glob_evalfile(0, gensym(nameptr), gensym(dirbuf));
167 }
168 else
169 error("%s: can't open", filename);
170}
171
172#define NHOSTFONT 7
173
174/* this is called from the gui process. The first argument is the cwd, and
175succeeding args give the widths and heights of known fonts. We wait until
176these are known to open files and send messages specified on the command line.
177We ask the GUI to specify the "cwd" in case we don't have a local OS to get it
178from; for instance we could be some kind of RT embedded system. However, to
179really make this make sense we would have to implement
180open(), read(), etc, calls to be served somehow from the GUI too. */
181
182void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
183{
184 char *cwd = atom_getsymbolarg(0, argc, argv)->s_name;
185 t_namelist *nl;
186 unsigned int i, j;
187 if (argc != 2 + 3 * NHOSTFONT) bug("glob_initfromgui");
188 for (i = 0; i < NFONT; i++)
189 {
190 int wantheight = sys_fontlist[i].fi_maxheight;
191 for (j = 0; j < NHOSTFONT-1; j++)
192 {
193 if (atom_getintarg(3 * (j + 1) + 3, argc, argv) > wantheight)
194 break;
195 }
196 /* j is now the "real" font index for the desired font index i. */
197 sys_fontlist[i].fi_hostfontsize = atom_getintarg(3 * j + 1, argc, argv);
198 sys_fontlist[i].fi_width = atom_getintarg(3 * j + 2, argc, argv);
199 sys_fontlist[i].fi_height = atom_getintarg(3 * j + 3, argc, argv);
200 }
201#if 0
202 for (i = 0; i < 6; i++)
203 fprintf(stderr, "font %d %d %d %d %d\n",
204 sys_fontlist[i].fi_fontsize,
205 sys_fontlist[i].fi_maxheight,
206 sys_fontlist[i].fi_hostfontsize,
207 sys_fontlist[i].fi_width,
208 sys_fontlist[i].fi_height);
209#endif
210 /* load dynamic libraries specified with "-lib" args */
211 for (nl = sys_externlist; nl; nl = nl->nl_next)
212 if (!sys_load_lib(cwd, nl->nl_string))
213 post("%s: can't load library", nl->nl_string);
214 namelist_free(sys_externlist);
215 sys_externlist = 0;
216 /* open patches specifies with "-open" args */
217 for (nl = sys_openlist; nl; nl = nl->nl_next)
218 openit(cwd, nl->nl_string);
219 namelist_free(sys_openlist);
220 sys_openlist = 0;
221 /* send messages specified with "-send" args */
222 for (nl = sys_messagelist; nl; nl = nl->nl_next)
223 {
224 t_binbuf *b = binbuf_new();
225 binbuf_text(b, nl->nl_string, strlen(nl->nl_string));
226 binbuf_eval(b, 0, 0, 0);
227 binbuf_free(b);
228 }
229 namelist_free(sys_messagelist);
230 sys_messagelist = 0;
231 sys_oldtclversion = atom_getfloatarg(1 + 3 * NHOSTFONT, argc, argv);
232}
233
234static void sys_afterargparse(void);
235
236/* this is called from main() in s_entry.c */
237int sys_main(int argc, char **argv)
238{
239#ifdef PD_DEBUG
240 fprintf(stderr, "Pd: COMPILED FOR DEBUGGING\n");
241#endif
242 pd_init();
243 sys_findprogdir(argv[0]); /* set sys_progname, guipath */
244#ifdef UNIX
245 sys_rcfile(); /* parse the startup file */
246#endif
247 if (sys_argparse(argc, argv)) /* parse cmd line */
248 return (1);
249 sys_afterargparse(); /* post-argparse settings */
250 if (sys_verbose || sys_version) fprintf(stderr, "%scompiled %s %s\n",
251 pd_version, pd_compiletime, pd_compiledate);
252 if (sys_version) /* if we were just asked our version, exit here. */
253 return (0);
254 if (sys_startgui(sys_guidir->s_name)) /* start the gui */
255 return(1);
256 /* open audio and MIDI */
257 sys_open_midi(sys_nmidiin, sys_midiindevlist,
258 sys_nmidiout, sys_midioutdevlist);
259 sys_open_audio(sys_nsoundin, sys_soundindevlist, sys_nchin, sys_chinlist,
260 sys_nsoundout, sys_soundoutdevlist, sys_nchout, sys_choutlist,
261 sys_main_srate, sys_main_advance, 1);
262 /* run scheduler until it quits */
263
264 return (m_scheduler_pda());
265 return (m_scheduler());
266}
267
268static char *(usagemessage[]) = {
269"usage: pd [-flags] [file]...\n",
270"\naudio configuration flags:\n",
271"-r <n> -- specify sample rate\n",
272"-audioindev ... -- audio in devices; e.g., \"1,3\" for first and third\n",
273"-audiooutdev ... -- audio out devices (same)\n",
274"-audiodev ... -- specify input and output together\n",
275"-inchannels ... -- audio input channels (by device, like \"2\" or \"16,8\")\n",
276"-outchannels ... -- number of audio out channels (same)\n",
277"-channels ... -- specify both input and output channels\n",
278"-audiobuf <n> -- specify size of audio buffer in msec\n",
279"-blocksize <n> -- specify audio I/O block size in sample frames\n",
280"-sleepgrain <n> -- specify number of milliseconds to sleep when idle\n",
281"-nodac -- suppress audio output\n",
282"-noadc -- suppress audio input\n",
283"-noaudio -- suppress audio input and output (-nosound is synonym) \n",
284"-listdev -- list audio and MIDI devices\n",
285
286#ifdef USEAPI_OSS
287"-oss -- use OSS audio API\n",
288"-32bit ----- allow 32 bit OSS audio (for RME Hammerfall)\n",
289#endif
290
291#ifdef USEAPI_ALSA
292"-alsa -- use ALSA audio API\n",
293"-alsaadd <name> -- add an ALSA device name to list\n",
294"-alsadev <n> ----- obsolete: use -audiodev\n",
295#endif
296
297#ifdef USEAPI_JACK
298"-jack -- use JACK audio API\n",
299#endif
300
301#ifdef USEAPI_PORTAUDIO
302#ifdef MSW
303"-asio -- use ASIO audio driver (via Portaudio)\n",
304"-pa -- synonym for -asio\n",
305#else
306"-pa -- use Portaudio API\n",
307#endif
308#endif
309
310#ifdef USEAPI_MMIO
311"-mmio -- use MMIO audio API (default for Windows)\n",
312#endif
313" (default audio API for this platform: ", API_DEFSTRING, ")\n\n",
314
315"\nMIDI configuration flags:\n",
316"-midiindev ... -- midi in device list; e.g., \"1,3\" for first and third\n",
317"-midioutdev ... -- midi out device list, same format\n",
318"-mididev ... -- specify -midioutdev and -midiindev together\n",
319"-nomidiin -- suppress MIDI input\n",
320"-nomidiout -- suppress MIDI output\n",
321"-nomidi -- suppress MIDI input and output\n",
322
323"\nother flags:\n",
324"-path <path> -- add to file search path\n",
325"-helppath <path> -- add to help file search path\n",
326"-open <file> -- open file(s) on startup\n",
327"-lib <file> -- load object library(s)\n",
328"-font <n> -- specify default font size in points\n",
329"-verbose -- extra printout on startup and when searching for files\n",
330"-version -- don't run Pd; just print out which version it is \n",
331"-d <n> -- specify debug level\n",
332"-noloadbang -- suppress all loadbangs\n",
333"-nogui -- suppress starting the GUI\n",
334"-stdin -- scan stdin for keypresses\n",
335"-guicmd \"cmd...\" -- substitute another GUI program (e.g., rsh)\n",
336"-send \"msg...\" -- send a message at startup (after patches are loaded)\n",
337#ifdef UNIX
338"-rt or -realtime -- use real-time priority\n",
339"-nrt -- don't use real-time priority\n",
340#endif
341};
342
343static void sys_parsedevlist(int *np, int *vecp, int max, char *str)
344{
345 int n = 0;
346 while (n < max)
347 {
348 if (!*str) break;
349 else
350 {
351 char *endp;
352 vecp[n] = strtol(str, &endp, 10);
353 if (endp == str)
354 break;
355 n++;
356 if (!endp)
357 break;
358 str = endp + 1;
359 }
360 }
361 *np = n;
362}
363
364static int sys_getmultidevchannels(int n, int *devlist)
365{
366 int sum = 0;
367 if (n<0)return(-1);
368 if (n==0)return 0;
369 while(n--)sum+=*devlist++;
370 return sum;
371}
372
373
374 /* this routine tries to figure out where to find the auxilliary files
375 Pd will need to run. This is either done by looking at the command line
376 invokation for Pd, or if that fails, by consulting the variable
377 INSTALL_PREFIX. In MSW, we don't try to use INSTALL_PREFIX. */
378void sys_findprogdir(char *progname)
379{
380 char sbuf[MAXPDSTRING], sbuf2[MAXPDSTRING], *sp;
381 char *lastslash;
382#ifdef UNIX
383 struct stat statbuf;
384#endif
385
386 /* find out by what string Pd was invoked; put answer in "sbuf". */
387#ifdef MSW
388 GetModuleFileName(NULL, sbuf2, sizeof(sbuf2));
389 sbuf2[MAXPDSTRING-1] = 0;
390 sys_unbashfilename(sbuf2, sbuf);
391#endif /* MSW */
392#ifdef UNIX
393 strncpy(sbuf, progname, MAXPDSTRING);
394 sbuf[MAXPDSTRING-1] = 0;
395#endif
396 lastslash = strrchr(sbuf, '/');
397 if (lastslash)
398 {
399 /* bash last slash to zero so that sbuf is directory pd was in,
400 e.g., ~/pd/bin */
401 *lastslash = 0;
402 /* go back to the parent from there, e.g., ~/pd */
403 lastslash = strrchr(sbuf, '/');
404 if (lastslash)
405 {
406 strncpy(sbuf2, sbuf, lastslash-sbuf);
407 sbuf2[lastslash-sbuf] = 0;
408 }
409 else strcpy(sbuf2, "..");
410 }
411 else
412 {
413 /* no slashes found. Try INSTALL_PREFIX. */
414#ifdef INSTALL_PREFIX
415 strcpy(sbuf2, INSTALL_PREFIX);
416#else
417 strcpy(sbuf2, ".");
418#endif
419 }
420 /* now we believe sbuf2 holds the parent directory of the directory
421 pd was found in. We now want to infer the "lib" directory and the
422 "gui" directory. In "simple" UNIX installations, the layout is
423 .../bin/pd
424 .../bin/pd-gui
425 .../doc
426 and in "complicated" UNIX installations, it's:
427 .../bin/pd
428 .../lib/pd/bin/pd-gui
429 .../lib/pd/doc
430 To decide which, we stat .../lib/pd; if that exists, we assume it's
431 the complicated layout. In MSW, it's the "simple" layout, but
432 the gui program is straight wish80:
433 .../bin/pd
434 .../bin/wish80.exe
435 .../doc
436 */
437#ifdef UNIX
438 strncpy(sbuf, sbuf2, MAXPDSTRING-30);
439 sbuf[MAXPDSTRING-30] = 0;
440 strcat(sbuf, "/lib/pd");
441 if (stat(sbuf, &statbuf) >= 0)
442 {
443 /* complicated layout: lib dir is the one we just stat-ed above */
444 sys_libdir = gensym(sbuf);
445 /* gui lives in .../lib/pd/bin */
446 strncpy(sbuf, sbuf2, MAXPDSTRING-30);
447 sbuf[MAXPDSTRING-30] = 0;
448 strcat(sbuf, "/lib/pd/bin");
449 sys_guidir = gensym(sbuf);
450 }
451 else
452 {
453 /* simple layout: lib dir is the parent */
454 sys_libdir = gensym(sbuf2);
455 /* gui lives in .../bin */
456 strncpy(sbuf, sbuf2, MAXPDSTRING-30);
457 sbuf[MAXPDSTRING-30] = 0;
458 strcat(sbuf, "/bin");
459 sys_guidir = gensym(sbuf);
460 }
461#endif
462#ifdef MSW
463 sys_libdir = gensym(sbuf2);
464 sys_guidir = &s_; /* in MSW the guipath just depends on the libdir */
465#endif
466}
467
468#ifdef MSW
469static int sys_mmio = 1;
470#else
471static int sys_mmio = 0;
472#endif
473
474int sys_argparse(int argc, char **argv)
475{
476 char sbuf[MAXPDSTRING];
477 int i;
478 argc--; argv++;
479 while ((argc > 0) && **argv == '-')
480 {
481 if (!strcmp(*argv, "-r") && argc > 1 &&
482 sscanf(argv[1], "%d", &sys_main_srate) >= 1)
483 {
484 argc -= 2;
485 argv += 2;
486 }
487 else if (!strcmp(*argv, "-inchannels"))
488 { /* IOhannes */
489 sys_parsedevlist(&sys_nchin,
490 sys_chinlist, MAXAUDIOINDEV, argv[1]);
491
492 if (!sys_nchin)
493 goto usage;
494
495 argc -= 2; argv += 2;
496 }
497 else if (!strcmp(*argv, "-outchannels"))
498 { /* IOhannes */
499 sys_parsedevlist(&sys_nchout, sys_choutlist,
500 MAXAUDIOOUTDEV, argv[1]);
501
502 if (!sys_nchout)
503 goto usage;
504
505 argc -= 2; argv += 2;
506 }
507 else if (!strcmp(*argv, "-channels"))
508 {
509 sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV,
510 argv[1]);
511 sys_parsedevlist(&sys_nchout, sys_choutlist,MAXAUDIOOUTDEV,
512 argv[1]);
513
514 if (!sys_nchout)
515 goto usage;
516
517 argc -= 2; argv += 2;
518 }
519 else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf"))
520 {
521 sys_main_advance = atoi(argv[1]);
522 argc -= 2; argv += 2;
523 }
524 else if (!strcmp(*argv, "-blocksize"))
525 {
526 sys_setblocksize(atoi(argv[1]));
527 argc -= 2; argv += 2;
528 }
529 else if (!strcmp(*argv, "-sleepgrain"))
530 {
531 sys_sleepgrain = 1000 * atoi(argv[1]);
532 argc -= 2; argv += 2;
533 }
534 else if (!strcmp(*argv, "-nodac"))
535 { /* IOhannes */
536 sys_nsoundout=0;
537 sys_nchout = 0;
538 argc--; argv++;
539 }
540 else if (!strcmp(*argv, "-noadc"))
541 { /* IOhannes */
542 sys_nsoundin=0;
543 sys_nchin = 0;
544 argc--; argv++;
545 }
546 else if (!strcmp(*argv, "-nosound") || !strcmp(*argv, "-noaudio"))
547 { /* IOhannes */
548 sys_nsoundin=sys_nsoundout = 0;
549 sys_nchin = sys_nchout = 0;
550 argc--; argv++;
551 }
552#ifdef USEAPI_OSS
553 else if (!strcmp(*argv, "-oss"))
554 {
555 sys_set_audio_api(API_OSS);
556 argc--; argv++;
557 }
558 else if (!strcmp(*argv, "-32bit"))
559 {
560 sys_set_audio_api(API_OSS);
561 oss_set32bit();
562 argc--; argv++;
563 }
564#endif
565#ifdef USEAPI_ALSA
566 else if (!strcmp(*argv, "-alsa"))
567 {
568 sys_set_audio_api(API_ALSA);
569 argc--; argv++;
570 }
571 else if (!strcmp(*argv, "-alsaadd"))
572 {
573 if (argc > 1)
574 alsa_adddev(argv[1]);
575 else goto usage;
576 argc -= 2; argv +=2;
577 }
578 /* obsolete flag for setting ALSA device number or name */
579 else if (!strcmp(*argv, "-alsadev"))
580 {
581 int devno = 0;
582 if (argv[1][0] >= '1' && argv[1][0] <= '9')
583 devno = 1 + 2 * (atoi(argv[1]) - 1);
584 else if (!strncmp(argv[1], "hw:", 3))
585 devno = 1 + 2 * atoi(argv[1]+3);
586 else if (!strncmp(argv[1], "plughw:", 7))
587 devno = 2 + 2 * atoi(argv[1]+7);
588 else goto usage;
589 sys_nsoundin = sys_nsoundout = 1;
590 sys_soundindevlist[0] = sys_soundoutdevlist[0] = devno;
591 sys_set_audio_api(API_ALSA);
592 argc -= 2; argv +=2;
593 }
594#endif
595#ifdef USEAPI_JACK
596 else if (!strcmp(*argv, "-jack"))
597 {
598 sys_set_audio_api(API_JACK);
599 argc--; argv++;
600 }
601#endif
602#ifdef USEAPI_PORTAUDIO
603 else if (!strcmp(*argv, "-pa") || !strcmp(*argv, "-portaudio")
604#ifdef MSW
605 || !strcmp(*argv, "-asio")
606#endif
607 )
608 {
609 sys_set_audio_api(API_PORTAUDIO);
610 sys_mmio = 0;
611 argc--; argv++;
612 }
613#endif
614#ifdef USEAPI_MMIO
615 else if (!strcmp(*argv, "-mmio"))
616 {
617 sys_set_audio_api(API_MMIO);
618 sys_mmio = 1;
619 argc--; argv++;
620 }
621#endif
622 else if (!strcmp(*argv, "-nomidiin"))
623 {
624 sys_nmidiin = 0;
625 argc--; argv++;
626 }
627 else if (!strcmp(*argv, "-nomidiout"))
628 {
629 sys_nmidiout = 0;
630 argc--; argv++;
631 }
632 else if (!strcmp(*argv, "-nomidi"))
633 {
634 sys_nmidiin = sys_nmidiout = 0;
635 argc--; argv++;
636 }
637 else if (!strcmp(*argv, "-midiindev"))
638 {
639 sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
640 argv[1]);
641 if (!sys_nmidiin)
642 goto usage;
643 argc -= 2; argv += 2;
644 }
645 else if (!strcmp(*argv, "-midioutdev"))
646 {
647 sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
648 argv[1]);
649 if (!sys_nmidiout)
650 goto usage;
651 argc -= 2; argv += 2;
652 }
653 else if (!strcmp(*argv, "-mididev"))
654 {
655 sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
656 argv[1]);
657 sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
658 argv[1]);
659 if (!sys_nmidiout)
660 goto usage;
661 argc -= 2; argv += 2;
662 }
663 else if (!strcmp(*argv, "-path"))
664 {
665 sys_addpath(argv[1]);
666 argc -= 2; argv += 2;
667 }
668 else if (!strcmp(*argv, "-helppath"))
669 {
670 sys_addhelppath(argv[1]);
671 argc -= 2; argv += 2;
672 }
673 else if (!strcmp(*argv, "-open") && argc > 1)
674 {
675 sys_openlist = namelist_append(sys_openlist, argv[1]);
676 argc -= 2; argv += 2;
677 }
678 else if (!strcmp(*argv, "-lib") && argc > 1)
679 {
680 sys_externlist = namelist_append(sys_externlist, argv[1]);
681 argc -= 2; argv += 2;
682 }
683 else if (!strcmp(*argv, "-font") && argc > 1)
684 {
685 sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
686 argc -= 2;
687 argv += 2;
688 }
689 else if (!strcmp(*argv, "-verbose"))
690 {
691 sys_verbose = 1;
692 argc--; argv++;
693 }
694 else if (!strcmp(*argv, "-version"))
695 {
696 sys_version = 1;
697 argc--; argv++;
698 }
699 else if (!strcmp(*argv, "-d") && argc > 1 &&
700 sscanf(argv[1], "%d", &sys_debuglevel) >= 1)
701 {
702 argc -= 2;
703 argv += 2;
704 }
705 else if (!strcmp(*argv, "-noloadbang"))
706 {
707 sys_noloadbang = 1;
708 argc--; argv++;
709 }
710 else if (!strcmp(*argv, "-nogui"))
711 {
712 sys_nogui = 1;
713 argc--; argv++;
714 }
715 else if (!strcmp(*argv, "-stdin"))
716 {
717 sys_stdin = 1;
718 argc--; argv++;
719 }
720 else if (!strcmp(*argv, "-guicmd") && argc > 1)
721 {
722 sys_guicmd = argv[1];
723 argc -= 2; argv += 2;
724 }
725 else if (!strcmp(*argv, "-send") && argc > 1)
726 {
727 sys_messagelist = namelist_append(sys_messagelist, argv[1]);
728 argc -= 2; argv += 2;
729 }
730 else if (!strcmp(*argv, "-listdev"))
731 {
732 sys_listdevs();
733 argc--; argv++;
734 }
735#ifdef UNIX
736 else if (!strcmp(*argv, "-rt") || !strcmp(*argv, "-realtime"))
737 {
738 sys_hipriority = 1;
739 argc--; argv++;
740 }
741 else if (!strcmp(*argv, "-nrt"))
742 {
743 sys_hipriority = 0;
744 argc--; argv++;
745 }
746#endif
747 else if (!strcmp(*argv, "-soundindev") ||
748 !strcmp(*argv, "-audioindev"))
749 { /* IOhannes */
750 sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
751 MAXAUDIOINDEV, argv[1]);
752 if (!sys_nsoundin)
753 goto usage;
754 argc -= 2; argv += 2;
755 }
756 else if (!strcmp(*argv, "-soundoutdev") ||
757 !strcmp(*argv, "-audiooutdev"))
758 { /* IOhannes */
759 sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
760 MAXAUDIOOUTDEV, argv[1]);
761 if (!sys_nsoundout)
762 goto usage;
763 argc -= 2; argv += 2;
764 }
765 else if (!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev"))
766 {
767 sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
768 MAXAUDIOINDEV, argv[1]);
769 sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
770 MAXAUDIOOUTDEV, argv[1]);
771 if (!sys_nsoundout)
772 goto usage;
773 argc -= 2; argv += 2;
774 }
775 else
776 {
777 unsigned int i;
778 usage:
779 for (i = 0; i < sizeof(usagemessage)/sizeof(*usagemessage); i++)
780 fprintf(stderr, "%s", usagemessage[i]);
781 return (1);
782 }
783 }
784 if (!sys_defaultfont)
785 sys_defaultfont = DEFAULTFONT;
786 for (; argc > 0; argc--, argv++)
787 sys_openlist = namelist_append(sys_openlist, *argv);
788
789
790 return (0);
791}
792
793int sys_getblksize(void)
794{
795 return (DEFDACBLKSIZE);
796}
797
798 /* stuff to do, once, after calling sys_argparse() -- which may itself
799 be called twice because of the .pdrc hack. */
800static void sys_afterargparse(void)
801{
802 char sbuf[MAXPDSTRING];
803 int i;
804 /* add "extra" library to path */
805 strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
806 sbuf[MAXPDSTRING-30] = 0;
807 strcat(sbuf, "/extra");
808 sys_addpath(sbuf);
809 strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
810 sbuf[MAXPDSTRING-30] = 0;
811 strcat(sbuf, "/intern");
812 sys_addpath(sbuf);
813 /* add "doc/5.reference" library to helppath */
814 strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
815 sbuf[MAXPDSTRING-30] = 0;
816 strcat(sbuf, "/doc/5.reference");
817 sys_addhelppath(sbuf);
818 /* correct to make audio and MIDI device lists zero based. On
819 MMIO, however, "1" really means the second device (the first one
820 is "mapper" which is was not included when the command args were
821 set up, so we leave it that way for compatibility. */
822 if (!sys_mmio)
823 {
824 for (i = 0; i < sys_nsoundin; i++)
825 sys_soundindevlist[i]--;
826 for (i = 0; i < sys_nsoundout; i++)
827 sys_soundoutdevlist[i]--;
828 }
829 for (i = 0; i < sys_nmidiin; i++)
830 sys_midiindevlist[i]--;
831 for (i = 0; i < sys_nmidiout; i++)
832 sys_midioutdevlist[i]--;
833}
834
835static void sys_addreferencepath(void)
836{
837 char sbuf[MAXPDSTRING];
838}
839/* Copyright (c) 1997-1999 Miller Puckette and others.
840* For information on usage and redistribution, and for a DISCLAIMER OF ALL
841* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
842
843/* IOhannes :
844 * hacked the code to add advanced multidevice-support
845 * 1311:forum::für::umläute:2001
846 */
847
848char pd_version[] = "Pd version 0.37.4\n";
849char pd_compiletime[] = __TIME__;
850char pd_compiledate[] = __DATE__;
851
852#include "m_pd.h"
853#include "m_imp.h"
854#include "s_stuff.h"
855#include <sys/types.h>
856#include <sys/stat.h>
857#include <limits.h>
858#include <string.h>
859#include <stdio.h>
860#include <fcntl.h>
861#include <stdlib.h>
862
863#ifdef UNIX
864#include <unistd.h>
865#endif
866#ifdef MSW
867#include <io.h>
868#include <windows.h>
869#include <winbase.h>
870#endif
871
872void pd_init(void);
873int sys_argparse(int argc, char **argv);
874void sys_findprogdir(char *progname);
875int sys_startgui(const char *guipath);
876int sys_rcfile(void);
877int m_scheduler(void);
878void sys_addhelppath(char *p);
879void alsa_adddev(char *name);
880
881int sys_debuglevel;
882int sys_verbose;
883int sys_noloadbang;
884int sys_nogui;
885int sys_stdin = 0;
886char *sys_guicmd;
887t_symbol *sys_libdir;
888static t_symbol *sys_guidir;
889static t_namelist *sys_externlist;
890static t_namelist *sys_openlist;
891static t_namelist *sys_messagelist;
892static int sys_version;
893int sys_oldtclversion; /* hack to warn g_rtext.c about old text sel */
894
895int sys_nmidiout = 1;
896#ifdef MSW
897int sys_nmidiin = 0;
898#else
899int sys_nmidiin = 1;
900#endif
901int sys_midiindevlist[MAXMIDIINDEV] = {1};
902int sys_midioutdevlist[MAXMIDIOUTDEV] = {1};
903
904static int sys_main_srate = DEFAULTSRATE;
905static int sys_main_advance = DEFAULTADVANCE;
906
907/* IOhannes { */
908
909 /* here the "-1" counts signify that the corresponding vector hasn't been
910 specified in command line arguments; sys_open_audio will detect this
911 and fill things in. */
912int sys_nsoundin = -1;
913int sys_nsoundout = -1;
914int sys_soundindevlist[MAXAUDIOINDEV];
915int sys_soundoutdevlist[MAXAUDIOOUTDEV];
916
917int sys_nchin = -1;
918int sys_nchout = -1;
919int sys_chinlist[MAXAUDIOINDEV];
920int sys_choutlist[MAXAUDIOOUTDEV];
921/* } IOhannes */
922
923
924typedef struct _fontinfo
925{
926 int fi_fontsize;
927 int fi_maxwidth;
928 int fi_maxheight;
929 int fi_hostfontsize;
930 int fi_width;
931 int fi_height;
932} t_fontinfo;
933
934 /* these give the nominal point size and maximum height of the characters
935 in the six fonts. */
936
937static t_fontinfo sys_fontlist[] = {
938 {8, 5, 9, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
939 {16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
940#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
941
942/* here are the actual font size structs on msp's systems:
943MSW:
944font 8 5 9 8 5 11
945font 10 7 13 10 6 13
946font 12 9 16 14 8 16
947font 16 10 20 16 10 18
948font 24 15 25 16 10 18
949font 36 25 42 36 22 41
950
951linux:
952font 8 5 9 8 5 9
953font 10 7 13 12 7 13
954font 12 9 16 14 9 15
955font 16 10 20 16 10 19
956font 24 15 25 24 15 24
957font 36 25 42 36 22 41
958*/
959
960static t_fontinfo *sys_findfont(int fontsize)
961{
962 unsigned int i;
963 t_fontinfo *fi;
964 for (i = 0, fi = sys_fontlist; i < (NFONT-1); i++, fi++)
965 if (fontsize < fi[1].fi_fontsize) return (fi);
966 return (sys_fontlist + (NFONT-1));
967}
968
969int sys_nearestfontsize(int fontsize)
970{
971 return (sys_findfont(fontsize)->fi_fontsize);
972}
973
974int sys_hostfontsize(int fontsize)
975{
976 return (sys_findfont(fontsize)->fi_hostfontsize);
977}
978
979int sys_fontwidth(int fontsize)
980{
981 return (sys_findfont(fontsize)->fi_width);
982}
983
984int sys_fontheight(int fontsize)
985{
986 return (sys_findfont(fontsize)->fi_height);
987}
988
989int sys_defaultfont;
990#ifdef MSW
991#define DEFAULTFONT 12
992#else
993#define DEFAULTFONT 10
994#endif
995
996static void openit(const char *dirname, const char *filename)
997{
998 char dirbuf[MAXPDSTRING], *nameptr;
999 int fd = open_via_path(dirname, filename, "", dirbuf, &nameptr,
1000 MAXPDSTRING, 0);
1001 if (fd)
1002 {
1003 close (fd);
1004 glob_evalfile(0, gensym(nameptr), gensym(dirbuf));
1005 }
1006 else
1007 error("%s: can't open", filename);
1008}
1009
1010#define NHOSTFONT 7
1011
1012/* this is called from the gui process. The first argument is the cwd, and
1013succeeding args give the widths and heights of known fonts. We wait until
1014these are known to open files and send messages specified on the command line.
1015We ask the GUI to specify the "cwd" in case we don't have a local OS to get it
1016from; for instance we could be some kind of RT embedded system. However, to
1017really make this make sense we would have to implement
1018open(), read(), etc, calls to be served somehow from the GUI too. */
1019
1020void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
1021{
1022 char *cwd = atom_getsymbolarg(0, argc, argv)->s_name;
1023 t_namelist *nl;
1024 unsigned int i, j;
1025 if (argc != 2 + 3 * NHOSTFONT) bug("glob_initfromgui");
1026 for (i = 0; i < NFONT; i++)
1027 {
1028 int wantheight = sys_fontlist[i].fi_maxheight;
1029 for (j = 0; j < NHOSTFONT-1; j++)
1030 {
1031 if (atom_getintarg(3 * (j + 1) + 3, argc, argv) > wantheight)
1032 break;
1033 }
1034 /* j is now the "real" font index for the desired font index i. */
1035 sys_fontlist[i].fi_hostfontsize = atom_getintarg(3 * j + 1, argc, argv);
1036 sys_fontlist[i].fi_width = atom_getintarg(3 * j + 2, argc, argv);
1037 sys_fontlist[i].fi_height = atom_getintarg(3 * j + 3, argc, argv);
1038 }
1039#if 0
1040 for (i = 0; i < 6; i++)
1041 fprintf(stderr, "font %d %d %d %d %d\n",
1042 sys_fontlist[i].fi_fontsize,
1043 sys_fontlist[i].fi_maxheight,
1044 sys_fontlist[i].fi_hostfontsize,
1045 sys_fontlist[i].fi_width,
1046 sys_fontlist[i].fi_height);
1047#endif
1048 /* load dynamic libraries specified with "-lib" args */
1049 for (nl = sys_externlist; nl; nl = nl->nl_next)
1050 if (!sys_load_lib(cwd, nl->nl_string))
1051 post("%s: can't load library", nl->nl_string);
1052 namelist_free(sys_externlist);
1053 sys_externlist = 0;
1054 /* open patches specifies with "-open" args */
1055 for (nl = sys_openlist; nl; nl = nl->nl_next)
1056 openit(cwd, nl->nl_string);
1057 namelist_free(sys_openlist);
1058 sys_openlist = 0;
1059 /* send messages specified with "-send" args */
1060 for (nl = sys_messagelist; nl; nl = nl->nl_next)
1061 {
1062 t_binbuf *b = binbuf_new();
1063 binbuf_text(b, nl->nl_string, strlen(nl->nl_string));
1064 binbuf_eval(b, 0, 0, 0);
1065 binbuf_free(b);
1066 }
1067 namelist_free(sys_messagelist);
1068 sys_messagelist = 0;
1069 sys_oldtclversion = atom_getfloatarg(1 + 3 * NHOSTFONT, argc, argv);
1070}
1071
1072static void sys_afterargparse(void);
1073
1074/* this is called from main() in s_entry.c */
1075int sys_main(int argc, char **argv)
1076{
1077#ifdef PD_DEBUG
1078 fprintf(stderr, "Pd: COMPILED FOR DEBUGGING\n");
1079#endif
1080 pd_init();
1081 sys_findprogdir(argv[0]); /* set sys_progname, guipath */
1082#ifdef UNIX
1083 sys_rcfile(); /* parse the startup file */
1084#endif
1085 if (sys_argparse(argc, argv)) /* parse cmd line */
1086 return (1);
1087 sys_afterargparse(); /* post-argparse settings */
1088 if (sys_verbose || sys_version) fprintf(stderr, "%scompiled %s %s\n",
1089 pd_version, pd_compiletime, pd_compiledate);
1090 if (sys_version) /* if we were just asked our version, exit here. */
1091 return (0);
1092 if (sys_startgui(sys_guidir->s_name)) /* start the gui */
1093 return(1);
1094 /* open audio and MIDI */
1095 sys_open_midi(sys_nmidiin, sys_midiindevlist,
1096 sys_nmidiout, sys_midioutdevlist);
1097 sys_open_audio(sys_nsoundin, sys_soundindevlist, sys_nchin, sys_chinlist,
1098 sys_nsoundout, sys_soundoutdevlist, sys_nchout, sys_choutlist,
1099 sys_main_srate, sys_main_advance, 1);
1100 /* run scheduler until it quits */
1101
1102 return (m_scheduler_pda());
1103 return (m_scheduler());
1104}
1105
1106static char *(usagemessage[]) = {
1107"usage: pd [-flags] [file]...\n",
1108"\naudio configuration flags:\n",
1109"-r <n> -- specify sample rate\n",
1110"-audioindev ... -- audio in devices; e.g., \"1,3\" for first and third\n",
1111"-audiooutdev ... -- audio out devices (same)\n",
1112"-audiodev ... -- specify input and output together\n",
1113"-inchannels ... -- audio input channels (by device, like \"2\" or \"16,8\")\n",
1114"-outchannels ... -- number of audio out channels (same)\n",
1115"-channels ... -- specify both input and output channels\n",
1116"-audiobuf <n> -- specify size of audio buffer in msec\n",
1117"-blocksize <n> -- specify audio I/O block size in sample frames\n",
1118"-sleepgrain <n> -- specify number of milliseconds to sleep when idle\n",
1119"-nodac -- suppress audio output\n",
1120"-noadc -- suppress audio input\n",
1121"-noaudio -- suppress audio input and output (-nosound is synonym) \n",
1122"-listdev -- list audio and MIDI devices\n",
1123
1124#ifdef USEAPI_OSS
1125"-oss -- use OSS audio API\n",
1126"-32bit ----- allow 32 bit OSS audio (for RME Hammerfall)\n",
1127#endif
1128
1129#ifdef USEAPI_ALSA
1130"-alsa -- use ALSA audio API\n",
1131"-alsaadd <name> -- add an ALSA device name to list\n",
1132"-alsadev <n> ----- obsolete: use -audiodev\n",
1133#endif
1134
1135#ifdef USEAPI_JACK
1136"-jack -- use JACK audio API\n",
1137#endif
1138
1139#ifdef USEAPI_PORTAUDIO
1140#ifdef MSW
1141"-asio -- use ASIO audio driver (via Portaudio)\n",
1142"-pa -- synonym for -asio\n",
1143#else
1144"-pa -- use Portaudio API\n",
1145#endif
1146#endif
1147
1148#ifdef USEAPI_MMIO
1149"-mmio -- use MMIO audio API (default for Windows)\n",
1150#endif
1151" (default audio API for this platform: ", API_DEFSTRING, ")\n\n",
1152
1153"\nMIDI configuration flags:\n",
1154"-midiindev ... -- midi in device list; e.g., \"1,3\" for first and third\n",
1155"-midioutdev ... -- midi out device list, same format\n",
1156"-mididev ... -- specify -midioutdev and -midiindev together\n",
1157"-nomidiin -- suppress MIDI input\n",
1158"-nomidiout -- suppress MIDI output\n",
1159"-nomidi -- suppress MIDI input and output\n",
1160
1161"\nother flags:\n",
1162"-path <path> -- add to file search path\n",
1163"-helppath <path> -- add to help file search path\n",
1164"-open <file> -- open file(s) on startup\n",
1165"-lib <file> -- load object library(s)\n",
1166"-font <n> -- specify default font size in points\n",
1167"-verbose -- extra printout on startup and when searching for files\n",
1168"-version -- don't run Pd; just print out which version it is \n",
1169"-d <n> -- specify debug level\n",
1170"-noloadbang -- suppress all loadbangs\n",
1171"-nogui -- suppress starting the GUI\n",
1172"-stdin -- scan stdin for keypresses\n",
1173"-guicmd \"cmd...\" -- substitute another GUI program (e.g., rsh)\n",
1174"-send \"msg...\" -- send a message at startup (after patches are loaded)\n",
1175#ifdef UNIX
1176"-rt or -realtime -- use real-time priority\n",
1177"-nrt -- don't use real-time priority\n",
1178#endif
1179};
1180
1181static void sys_parsedevlist(int *np, int *vecp, int max, char *str)
1182{
1183 int n = 0;
1184 while (n < max)
1185 {
1186 if (!*str) break;
1187 else
1188 {
1189 char *endp;
1190 vecp[n] = strtol(str, &endp, 10);
1191 if (endp == str)
1192 break;
1193 n++;
1194 if (!endp)
1195 break;
1196 str = endp + 1;
1197 }
1198 }
1199 *np = n;
1200}
1201
1202static int sys_getmultidevchannels(int n, int *devlist)
1203{
1204 int sum = 0;
1205 if (n<0)return(-1);
1206 if (n==0)return 0;
1207 while(n--)sum+=*devlist++;
1208 return sum;
1209}
1210
1211
1212 /* this routine tries to figure out where to find the auxilliary files
1213 Pd will need to run. This is either done by looking at the command line
1214 invokation for Pd, or if that fails, by consulting the variable
1215 INSTALL_PREFIX. In MSW, we don't try to use INSTALL_PREFIX. */
1216void sys_findprogdir(char *progname)
1217{
1218 char sbuf[MAXPDSTRING], sbuf2[MAXPDSTRING], *sp;
1219 char *lastslash;
1220#ifdef UNIX
1221 struct stat statbuf;
1222#endif
1223
1224 /* find out by what string Pd was invoked; put answer in "sbuf". */
1225#ifdef MSW
1226 GetModuleFileName(NULL, sbuf2, sizeof(sbuf2));
1227 sbuf2[MAXPDSTRING-1] = 0;
1228 sys_unbashfilename(sbuf2, sbuf);
1229#endif /* MSW */
1230#ifdef UNIX
1231 strncpy(sbuf, progname, MAXPDSTRING);
1232 sbuf[MAXPDSTRING-1] = 0;
1233#endif
1234 lastslash = strrchr(sbuf, '/');
1235 if (lastslash)
1236 {
1237 /* bash last slash to zero so that sbuf is directory pd was in,
1238 e.g., ~/pd/bin */
1239 *lastslash = 0;
1240 /* go back to the parent from there, e.g., ~/pd */
1241 lastslash = strrchr(sbuf, '/');
1242 if (lastslash)
1243 {
1244 strncpy(sbuf2, sbuf, lastslash-sbuf);
1245 sbuf2[lastslash-sbuf] = 0;
1246 }
1247 else strcpy(sbuf2, "..");
1248 }
1249 else
1250 {
1251 /* no slashes found. Try INSTALL_PREFIX. */
1252#ifdef INSTALL_PREFIX
1253 strcpy(sbuf2, INSTALL_PREFIX);
1254#else
1255 strcpy(sbuf2, ".");
1256#endif
1257 }
1258 /* now we believe sbuf2 holds the parent directory of the directory
1259 pd was found in. We now want to infer the "lib" directory and the
1260 "gui" directory. In "simple" UNIX installations, the layout is
1261 .../bin/pd
1262 .../bin/pd-gui
1263 .../doc
1264 and in "complicated" UNIX installations, it's:
1265 .../bin/pd
1266 .../lib/pd/bin/pd-gui
1267 .../lib/pd/doc
1268 To decide which, we stat .../lib/pd; if that exists, we assume it's
1269 the complicated layout. In MSW, it's the "simple" layout, but
1270 the gui program is straight wish80:
1271 .../bin/pd
1272 .../bin/wish80.exe
1273 .../doc
1274 */
1275#ifdef UNIX
1276 strncpy(sbuf, sbuf2, MAXPDSTRING-30);
1277 sbuf[MAXPDSTRING-30] = 0;
1278 strcat(sbuf, "/lib/pd");
1279 if (stat(sbuf, &statbuf) >= 0)
1280 {
1281 /* complicated layout: lib dir is the one we just stat-ed above */
1282 sys_libdir = gensym(sbuf);
1283 /* gui lives in .../lib/pd/bin */
1284 strncpy(sbuf, sbuf2, MAXPDSTRING-30);
1285 sbuf[MAXPDSTRING-30] = 0;
1286 strcat(sbuf, "/lib/pd/bin");
1287 sys_guidir = gensym(sbuf);
1288 }
1289 else
1290 {
1291 /* simple layout: lib dir is the parent */
1292 sys_libdir = gensym(sbuf2);
1293 /* gui lives in .../bin */
1294 strncpy(sbuf, sbuf2, MAXPDSTRING-30);
1295 sbuf[MAXPDSTRING-30] = 0;
1296 strcat(sbuf, "/bin");
1297 sys_guidir = gensym(sbuf);
1298 }
1299#endif
1300#ifdef MSW
1301 sys_libdir = gensym(sbuf2);
1302 sys_guidir = &s_; /* in MSW the guipath just depends on the libdir */
1303#endif
1304}
1305
1306#ifdef MSW
1307static int sys_mmio = 1;
1308#else
1309static int sys_mmio = 0;
1310#endif
1311
1312int sys_argparse(int argc, char **argv)
1313{
1314 char sbuf[MAXPDSTRING];
1315 int i;
1316 argc--; argv++;
1317 while ((argc > 0) && **argv == '-')
1318 {
1319 if (!strcmp(*argv, "-r") && argc > 1 &&
1320 sscanf(argv[1], "%d", &sys_main_srate) >= 1)
1321 {
1322 argc -= 2;
1323 argv += 2;
1324 }
1325 else if (!strcmp(*argv, "-inchannels"))
1326 { /* IOhannes */
1327 sys_parsedevlist(&sys_nchin,
1328 sys_chinlist, MAXAUDIOINDEV, argv[1]);
1329
1330 if (!sys_nchin)
1331 goto usage;
1332
1333 argc -= 2; argv += 2;
1334 }
1335 else if (!strcmp(*argv, "-outchannels"))
1336 { /* IOhannes */
1337 sys_parsedevlist(&sys_nchout, sys_choutlist,
1338 MAXAUDIOOUTDEV, argv[1]);
1339
1340 if (!sys_nchout)
1341 goto usage;
1342
1343 argc -= 2; argv += 2;
1344 }
1345 else if (!strcmp(*argv, "-channels"))
1346 {
1347 sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV,
1348 argv[1]);
1349 sys_parsedevlist(&sys_nchout, sys_choutlist,MAXAUDIOOUTDEV,
1350 argv[1]);
1351
1352 if (!sys_nchout)
1353 goto usage;
1354
1355 argc -= 2; argv += 2;
1356 }
1357 else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf"))
1358 {
1359 sys_main_advance = atoi(argv[1]);
1360 argc -= 2; argv += 2;
1361 }
1362 else if (!strcmp(*argv, "-blocksize"))
1363 {
1364 sys_setblocksize(atoi(argv[1]));
1365 argc -= 2; argv += 2;
1366 }
1367 else if (!strcmp(*argv, "-sleepgrain"))
1368 {
1369 sys_sleepgrain = 1000 * atoi(argv[1]);
1370 argc -= 2; argv += 2;
1371 }
1372 else if (!strcmp(*argv, "-nodac"))
1373 { /* IOhannes */
1374 sys_nsoundout=0;
1375 sys_nchout = 0;
1376 argc--; argv++;
1377 }
1378 else if (!strcmp(*argv, "-noadc"))
1379 { /* IOhannes */
1380 sys_nsoundin=0;
1381 sys_nchin = 0;
1382 argc--; argv++;
1383 }
1384 else if (!strcmp(*argv, "-nosound") || !strcmp(*argv, "-noaudio"))
1385 { /* IOhannes */
1386 sys_nsoundin=sys_nsoundout = 0;
1387 sys_nchin = sys_nchout = 0;
1388 argc--; argv++;
1389 }
1390#ifdef USEAPI_OSS
1391 else if (!strcmp(*argv, "-oss"))
1392 {
1393 sys_set_audio_api(API_OSS);
1394 argc--; argv++;
1395 }
1396 else if (!strcmp(*argv, "-32bit"))
1397 {
1398 sys_set_audio_api(API_OSS);
1399 oss_set32bit();
1400 argc--; argv++;
1401 }
1402#endif
1403#ifdef USEAPI_ALSA
1404 else if (!strcmp(*argv, "-alsa"))
1405 {
1406 sys_set_audio_api(API_ALSA);
1407 argc--; argv++;
1408 }
1409 else if (!strcmp(*argv, "-alsaadd"))
1410 {
1411 if (argc > 1)
1412 alsa_adddev(argv[1]);
1413 else goto usage;
1414 argc -= 2; argv +=2;
1415 }
1416 /* obsolete flag for setting ALSA device number or name */
1417 else if (!strcmp(*argv, "-alsadev"))
1418 {
1419 int devno = 0;
1420 if (argv[1][0] >= '1' && argv[1][0] <= '9')
1421 devno = 1 + 2 * (atoi(argv[1]) - 1);
1422 else if (!strncmp(argv[1], "hw:", 3))
1423 devno = 1 + 2 * atoi(argv[1]+3);
1424 else if (!strncmp(argv[1], "plughw:", 7))
1425 devno = 2 + 2 * atoi(argv[1]+7);
1426 else goto usage;
1427 sys_nsoundin = sys_nsoundout = 1;
1428 sys_soundindevlist[0] = sys_soundoutdevlist[0] = devno;
1429 sys_set_audio_api(API_ALSA);
1430 argc -= 2; argv +=2;
1431 }
1432#endif
1433#ifdef USEAPI_JACK
1434 else if (!strcmp(*argv, "-jack"))
1435 {
1436 sys_set_audio_api(API_JACK);
1437 argc--; argv++;
1438 }
1439#endif
1440#ifdef USEAPI_PORTAUDIO
1441 else if (!strcmp(*argv, "-pa") || !strcmp(*argv, "-portaudio")
1442#ifdef MSW
1443 || !strcmp(*argv, "-asio")
1444#endif
1445 )
1446 {
1447 sys_set_audio_api(API_PORTAUDIO);
1448 sys_mmio = 0;
1449 argc--; argv++;
1450 }
1451#endif
1452#ifdef USEAPI_MMIO
1453 else if (!strcmp(*argv, "-mmio"))
1454 {
1455 sys_set_audio_api(API_MMIO);
1456 sys_mmio = 1;
1457 argc--; argv++;
1458 }
1459#endif
1460 else if (!strcmp(*argv, "-nomidiin"))
1461 {
1462 sys_nmidiin = 0;
1463 argc--; argv++;
1464 }
1465 else if (!strcmp(*argv, "-nomidiout"))
1466 {
1467 sys_nmidiout = 0;
1468 argc--; argv++;
1469 }
1470 else if (!strcmp(*argv, "-nomidi"))
1471 {
1472 sys_nmidiin = sys_nmidiout = 0;
1473 argc--; argv++;
1474 }
1475 else if (!strcmp(*argv, "-midiindev"))
1476 {
1477 sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
1478 argv[1]);
1479 if (!sys_nmidiin)
1480 goto usage;
1481 argc -= 2; argv += 2;
1482 }
1483 else if (!strcmp(*argv, "-midioutdev"))
1484 {
1485 sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
1486 argv[1]);
1487 if (!sys_nmidiout)
1488 goto usage;
1489 argc -= 2; argv += 2;
1490 }
1491 else if (!strcmp(*argv, "-mididev"))
1492 {
1493 sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
1494 argv[1]);
1495 sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
1496 argv[1]);
1497 if (!sys_nmidiout)
1498 goto usage;
1499 argc -= 2; argv += 2;
1500 }
1501 else if (!strcmp(*argv, "-path"))
1502 {
1503 sys_addpath(argv[1]);
1504 argc -= 2; argv += 2;
1505 }
1506 else if (!strcmp(*argv, "-helppath"))
1507 {
1508 sys_addhelppath(argv[1]);
1509 argc -= 2; argv += 2;
1510 }
1511 else if (!strcmp(*argv, "-open") && argc > 1)
1512 {
1513 sys_openlist = namelist_append(sys_openlist, argv[1]);
1514 argc -= 2; argv += 2;
1515 }
1516 else if (!strcmp(*argv, "-lib") && argc > 1)
1517 {
1518 sys_externlist = namelist_append(sys_externlist, argv[1]);
1519 argc -= 2; argv += 2;
1520 }
1521 else if (!strcmp(*argv, "-font") && argc > 1)
1522 {
1523 sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
1524 argc -= 2;
1525 argv += 2;
1526 }
1527 else if (!strcmp(*argv, "-verbose"))
1528 {
1529 sys_verbose = 1;
1530 argc--; argv++;
1531 }
1532 else if (!strcmp(*argv, "-version"))
1533 {
1534 sys_version = 1;
1535 argc--; argv++;
1536 }
1537 else if (!strcmp(*argv, "-d") && argc > 1 &&
1538 sscanf(argv[1], "%d", &sys_debuglevel) >= 1)
1539 {
1540 argc -= 2;
1541 argv += 2;
1542 }
1543 else if (!strcmp(*argv, "-noloadbang"))
1544 {
1545 sys_noloadbang = 1;
1546 argc--; argv++;
1547 }
1548 else if (!strcmp(*argv, "-nogui"))
1549 {
1550 sys_nogui = 1;
1551 argc--; argv++;
1552 }
1553 else if (!strcmp(*argv, "-stdin"))
1554 {
1555 sys_stdin = 1;
1556 argc--; argv++;
1557 }
1558 else if (!strcmp(*argv, "-guicmd") && argc > 1)
1559 {
1560 sys_guicmd = argv[1];
1561 argc -= 2; argv += 2;
1562 }
1563 else if (!strcmp(*argv, "-send") && argc > 1)
1564 {
1565 sys_messagelist = namelist_append(sys_messagelist, argv[1]);
1566 argc -= 2; argv += 2;
1567 }
1568 else if (!strcmp(*argv, "-listdev"))
1569 {
1570 sys_listdevs();
1571 argc--; argv++;
1572 }
1573#ifdef UNIX
1574 else if (!strcmp(*argv, "-rt") || !strcmp(*argv, "-realtime"))
1575 {
1576 sys_hipriority = 1;
1577 argc--; argv++;
1578 }
1579 else if (!strcmp(*argv, "-nrt"))
1580 {
1581 sys_hipriority = 0;
1582 argc--; argv++;
1583 }
1584#endif
1585 else if (!strcmp(*argv, "-soundindev") ||
1586 !strcmp(*argv, "-audioindev"))
1587 { /* IOhannes */
1588 sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
1589 MAXAUDIOINDEV, argv[1]);
1590 if (!sys_nsoundin)
1591 goto usage;
1592 argc -= 2; argv += 2;
1593 }
1594 else if (!strcmp(*argv, "-soundoutdev") ||
1595 !strcmp(*argv, "-audiooutdev"))
1596 { /* IOhannes */
1597 sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
1598 MAXAUDIOOUTDEV, argv[1]);
1599 if (!sys_nsoundout)
1600 goto usage;
1601 argc -= 2; argv += 2;
1602 }
1603 else if (!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev"))
1604 {
1605 sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
1606 MAXAUDIOINDEV, argv[1]);
1607 sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
1608 MAXAUDIOOUTDEV, argv[1]);
1609 if (!sys_nsoundout)
1610 goto usage;
1611 argc -= 2; argv += 2;
1612 }
1613 else
1614 {
1615 unsigned int i;
1616 usage:
1617 for (i = 0; i < sizeof(usagemessage)/sizeof(*usagemessage); i++)
1618 fprintf(stderr, "%s", usagemessage[i]);
1619 return (1);
1620 }
1621 }
1622 if (!sys_defaultfont)
1623 sys_defaultfont = DEFAULTFONT;
1624 for (; argc > 0; argc--, argv++)
1625 sys_openlist = namelist_append(sys_openlist, *argv);
1626
1627
1628 return (0);
1629}
1630
1631int sys_getblksize(void)
1632{
1633 return (DEFDACBLKSIZE);
1634}
1635
1636 /* stuff to do, once, after calling sys_argparse() -- which may itself
1637 be called twice because of the .pdrc hack. */
1638static void sys_afterargparse(void)
1639{
1640 char sbuf[MAXPDSTRING];
1641 int i;
1642 /* add "extra" library to path */
1643 strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
1644 sbuf[MAXPDSTRING-30] = 0;
1645 strcat(sbuf, "/extra");
1646 sys_addpath(sbuf);
1647 strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
1648 sbuf[MAXPDSTRING-30] = 0;
1649 strcat(sbuf, "/intern");
1650 sys_addpath(sbuf);
1651 /* add "doc/5.reference" library to helppath */
1652 strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
1653 sbuf[MAXPDSTRING-30] = 0;
1654 strcat(sbuf, "/doc/5.reference");
1655 sys_addhelppath(sbuf);
1656 /* correct to make audio and MIDI device lists zero based. On
1657 MMIO, however, "1" really means the second device (the first one
1658 is "mapper" which is was not included when the command args were
1659 set up, so we leave it that way for compatibility. */
1660 if (!sys_mmio)
1661 {
1662 for (i = 0; i < sys_nsoundin; i++)
1663 sys_soundindevlist[i]--;
1664 for (i = 0; i < sys_nsoundout; i++)
1665 sys_soundoutdevlist[i]--;
1666 }
1667 for (i = 0; i < sys_nmidiin; i++)
1668 sys_midiindevlist[i]--;
1669 for (i = 0; i < sys_nmidiout; i++)
1670 sys_midioutdevlist[i]--;
1671}
1672
1673static void sys_addreferencepath(void)
1674{
1675 char sbuf[MAXPDSTRING];
1676}
diff --git a/apps/plugins/pdbox/PDa/src/s_midi.c b/apps/plugins/pdbox/PDa/src/s_midi.c
new file mode 100644
index 0000000000..4338b49432
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_midi.c
@@ -0,0 +1,1282 @@
1/* Copyright (c) 1997-1999 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* Clock functions (which should move, but where?) and MIDI queueing */
6
7#include "m_pd.h"
8#include "s_stuff.h"
9#include "m_imp.h"
10#ifdef UNIX
11#include <unistd.h>
12#include <sys/time.h>
13#ifdef HAVE_BSTRING_H
14#include <bstring.h>
15#endif
16#endif
17#ifdef MSW
18#include <winsock.h>
19#include <sys/types.h>
20#include <sys/timeb.h>
21#include <wtypes.h>
22#endif
23#include <string.h>
24#include <stdio.h>
25#include <signal.h>
26
27typedef struct _midiqelem
28{
29 double q_time;
30 int q_portno;
31 unsigned char q_onebyte;
32 unsigned char q_byte1;
33 unsigned char q_byte2;
34 unsigned char q_byte3;
35} t_midiqelem;
36
37#define MIDIQSIZE 1024
38
39t_midiqelem midi_outqueue[MIDIQSIZE];
40int midi_outhead, midi_outtail;
41t_midiqelem midi_inqueue[MIDIQSIZE];
42int midi_inhead, midi_intail;
43static double sys_midiinittime;
44
45 /* this is our current estimate for at what "system" real time the
46 current logical time's output should occur. */
47static double sys_dactimeminusrealtime;
48 /* same for input, should be schduler advance earlier. */
49static double sys_adctimeminusrealtime;
50
51static double sys_newdactimeminusrealtime = -1e20;
52static double sys_newadctimeminusrealtime = -1e20;
53static double sys_whenupdate;
54
55void sys_initmidiqueue( void)
56{
57 sys_midiinittime = clock_getlogicaltime();
58 sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0;
59}
60
61 /* this is called from the OS dependent code from time to time when we
62 think we know the delay (outbuftime) in seconds, at which the last-output
63 audio sample will go out the door. */
64void sys_setmiditimediff(double inbuftime, double outbuftime)
65{
66 double dactimeminusrealtime =
67 .001 * clock_gettimesince(sys_midiinittime)
68 - outbuftime - sys_getrealtime();
69 double adctimeminusrealtime =
70 .001 * clock_gettimesince(sys_midiinittime)
71 + inbuftime - sys_getrealtime();
72 if (dactimeminusrealtime > sys_newdactimeminusrealtime)
73 sys_newdactimeminusrealtime = dactimeminusrealtime;
74 if (adctimeminusrealtime > sys_newadctimeminusrealtime)
75 sys_newadctimeminusrealtime = adctimeminusrealtime;
76 if (sys_getrealtime() > sys_whenupdate)
77 {
78 sys_dactimeminusrealtime = sys_newdactimeminusrealtime;
79 sys_adctimeminusrealtime = sys_newadctimeminusrealtime;
80 sys_newdactimeminusrealtime = -1e20;
81 sys_newadctimeminusrealtime = -1e20;
82 sys_whenupdate = sys_getrealtime() + 1;
83 }
84}
85
86 /* return the logical time of the DAC sample we believe is currently
87 going out, based on how much "system time" has elapsed since the
88 last time sys_setmiditimediff got called. */
89static double sys_getmidioutrealtime( void)
90{
91 return (sys_getrealtime() + sys_dactimeminusrealtime);
92}
93
94static double sys_getmidiinrealtime( void)
95{
96 return (sys_getrealtime() + sys_adctimeminusrealtime);
97}
98
99static void sys_putnext( void)
100{
101 int portno = midi_outqueue[midi_outtail].q_portno;
102 if (midi_outqueue[midi_outtail].q_onebyte)
103 sys_putmidibyte(portno, midi_outqueue[midi_outtail].q_byte1);
104 else sys_putmidimess(portno, midi_outqueue[midi_outtail].q_byte1,
105 midi_outqueue[midi_outtail].q_byte2,
106 midi_outqueue[midi_outtail].q_byte3);
107 midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
108}
109
110/* #define TEST_DEJITTER */
111
112void sys_pollmidioutqueue( void)
113{
114#ifdef TEST_DEJITTER
115 static int db = 0;
116#endif
117 double midirealtime = sys_getmidioutrealtime();
118#ifdef TEST_DEJITTER
119 if (midi_outhead == midi_outtail)
120 db = 0;
121#endif
122 while (midi_outhead != midi_outtail)
123 {
124#ifdef TEST_DEJITTER
125 if (!db)
126 {
127 post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
128 (midi_outqueue[midi_outtail].q_time - midirealtime),
129 midirealtime, .001 * clock_gettimesince(sys_midiinittime),
130 sys_getrealtime(), sys_dactimeminusrealtime);
131 db = 1;
132 }
133#endif
134 if (midi_outqueue[midi_outtail].q_time <= midirealtime)
135 sys_putnext();
136 else break;
137 }
138}
139
140static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c)
141{
142 t_midiqelem *midiqelem;
143 int newhead = midi_outhead +1;
144 if (newhead == MIDIQSIZE)
145 newhead = 0;
146 /* if FIFO is full flush an element to make room */
147 if (newhead == midi_outtail)
148 sys_putnext();
149 midi_outqueue[midi_outhead].q_portno = portno;
150 midi_outqueue[midi_outhead].q_onebyte = onebyte;
151 midi_outqueue[midi_outhead].q_byte1 = a;
152 midi_outqueue[midi_outhead].q_byte2 = b;
153 midi_outqueue[midi_outhead].q_byte3 = c;
154 midi_outqueue[midi_outhead].q_time =
155 .001 * clock_gettimesince(sys_midiinittime);
156 midi_outhead = newhead;
157 sys_pollmidioutqueue();
158}
159
160#define MIDI_NOTEON 144
161#define MIDI_POLYAFTERTOUCH 160
162#define MIDI_CONTROLCHANGE 176
163#define MIDI_PROGRAMCHANGE 192
164#define MIDI_AFTERTOUCH 208
165#define MIDI_PITCHBEND 224
166
167void outmidi_noteon(int portno, int channel, int pitch, int velo)
168{
169 if (pitch < 0) pitch = 0;
170 else if (pitch > 127) pitch = 127;
171 if (velo < 0) velo = 0;
172 else if (velo > 127) velo = 127;
173 sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo);
174}
175
176void outmidi_controlchange(int portno, int channel, int ctl, int value)
177{
178 if (ctl < 0) ctl = 0;
179 else if (ctl > 127) ctl = 127;
180 if (value < 0) value = 0;
181 else if (value > 127) value = 127;
182 sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf),
183 ctl, value);
184}
185
186void outmidi_programchange(int portno, int channel, int value)
187{
188 if (value < 0) value = 0;
189 else if (value > 127) value = 127;
190 sys_queuemidimess(portno, 0,
191 MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0);
192}
193
194void outmidi_pitchbend(int portno, int channel, int value)
195{
196 if (value < 0) value = 0;
197 else if (value > 16383) value = 16383;
198 sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf),
199 (value & 127), ((value>>7) & 127));
200}
201
202void outmidi_aftertouch(int portno, int channel, int value)
203{
204 if (value < 0) value = 0;
205 else if (value > 127) value = 127;
206 sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0);
207}
208
209void outmidi_polyaftertouch(int portno, int channel, int pitch, int value)
210{
211 if (pitch < 0) pitch = 0;
212 else if (pitch > 127) pitch = 127;
213 if (value < 0) value = 0;
214 else if (value > 127) value = 127;
215 sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf),
216 pitch, value);
217}
218
219void outmidi_mclk(int portno)
220{
221 sys_queuemidimess(portno, 1, 0xf8, 0,0);
222}
223
224/* ------------------------- MIDI input queue handling ------------------ */
225typedef struct midiparser
226{
227 int mp_status;
228 int mp_gotbyte1;
229 int mp_byte1;
230} t_midiparser;
231
232#define MIDINOTEOFF 0x80 /* 2 following 'data bytes' */
233#define MIDINOTEON 0x90 /* 2 */
234#define MIDIPOLYTOUCH 0xa0 /* 2 */
235#define MIDICONTROLCHANGE 0xb0 /* 2 */
236#define MIDIPROGRAMCHANGE 0xc0 /* 1 */
237#define MIDICHANNELTOUCH 0xd0 /* 1 */
238#define MIDIPITCHBEND 0xe0 /* 2 */
239#define MIDISTARTSYSEX 0xf0 /* (until F7) */
240#define MIDITIMECODE 0xf1 /* 1 */
241#define MIDISONGPOS 0xf2 /* 2 */
242#define MIDISONGSELECT 0xf3 /* 1 */
243#define MIDIRESERVED1 0xf4 /* ? */
244#define MIDIRESERVED2 0xf5 /* ? */
245#define MIDITUNEREQUEST 0xf6 /* 0 */
246#define MIDIENDSYSEX 0xf7 /* 0 */
247#define MIDICLOCK 0xf8 /* 0 */
248#define MIDITICK 0xf9 /* 0 */
249#define MIDISTART 0xfa /* 0 */
250#define MIDICONT 0xfb /* 0 */
251#define MIDISTOP 0xfc /* 0 */
252#define MIDIACTIVESENSE 0xfe /* 0 */
253#define MIDIRESET 0xff /* 0 */
254
255 /* functions in x_midi.c */
256void inmidi_realtimein(int portno, int cmd);
257void inmidi_byte(int portno, int byte);
258void inmidi_sysex(int portno, int byte);
259void inmidi_noteon(int portno, int channel, int pitch, int velo);
260void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
261void inmidi_programchange(int portno, int channel, int value);
262void inmidi_pitchbend(int portno, int channel, int value);
263void inmidi_aftertouch(int portno, int channel, int value);
264void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
265
266static void sys_dispatchnextmidiin( void)
267{
268 static t_midiparser parser[MAXMIDIINDEV], *parserp;
269 int portno = midi_inqueue[midi_intail].q_portno,
270 byte = midi_inqueue[midi_intail].q_byte1;
271 if (!midi_inqueue[midi_intail].q_onebyte)
272 bug("sys_dispatchnextmidiin");
273 if (portno < 0 || portno >= MAXMIDIINDEV)
274 bug("sys_dispatchnextmidiin 2");
275 parserp = parser + portno;
276 outlet_setstacklim();
277
278 if (byte >= 0xf8)
279 inmidi_realtimein(portno, byte);
280 else
281 {
282 inmidi_byte(portno, byte);
283 if (byte & 0x80)
284 {
285 if (byte == MIDITUNEREQUEST || byte == MIDIRESERVED1 ||
286 byte == MIDIRESERVED2)
287 parserp->mp_status = 0;
288 else if (byte == MIDISTARTSYSEX)
289 {
290 inmidi_sysex(portno, byte);
291 parserp->mp_status = byte;
292 }
293 else if (byte == MIDIENDSYSEX)
294 {
295 inmidi_sysex(portno, byte);
296 parserp->mp_status = 0;
297 }
298 else
299 {
300 parserp->mp_status = byte;
301 }
302 parserp->mp_gotbyte1 = 0;
303 }
304 else
305 {
306 int cmd = (parserp->mp_status >= 0xf0 ? parserp->mp_status :
307 (parserp->mp_status & 0xf0));
308 int chan = (parserp->mp_status & 0xf);
309 int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1;
310 switch (cmd)
311 {
312 case MIDINOTEOFF:
313 if (gotbyte1)
314 inmidi_noteon(portno, chan, byte1, 0),
315 parserp->mp_gotbyte1 = 0;
316 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
317 break;
318 case MIDINOTEON:
319 if (gotbyte1)
320 inmidi_noteon(portno, chan, byte1, byte),
321 parserp->mp_gotbyte1 = 0;
322 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
323 break;
324 case MIDIPOLYTOUCH:
325 if (gotbyte1)
326 inmidi_polyaftertouch(portno, chan, byte1, byte),
327 parserp->mp_gotbyte1 = 0;
328 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
329 break;
330 case MIDICONTROLCHANGE:
331 if (gotbyte1)
332 inmidi_controlchange(portno, chan, byte1, byte),
333 parserp->mp_gotbyte1 = 0;
334 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
335 break;
336 case MIDIPROGRAMCHANGE:
337 inmidi_programchange(portno, chan, byte);
338 break;
339 case MIDICHANNELTOUCH:
340 inmidi_aftertouch(portno, chan, byte);
341 break;
342 case MIDIPITCHBEND:
343 if (gotbyte1)
344 inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)),
345 parserp->mp_gotbyte1 = 0;
346 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
347 break;
348 case MIDISTARTSYSEX:
349 inmidi_sysex(portno, byte);
350 break;
351
352 /* other kinds of messages are just dropped here. We'll
353 need another status byte before we start letting MIDI in
354 again (no running status across "system" messages). */
355 case MIDITIMECODE: /* 1 data byte*/
356 break;
357 case MIDISONGPOS: /* 2 */
358 break;
359 case MIDISONGSELECT: /* 1 */
360 break;
361 }
362 }
363 }
364 midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
365}
366
367void sys_pollmidiinqueue( void)
368{
369#ifdef TEST_DEJITTER
370 static int db = 0;
371#endif
372 double logicaltime = .001 * clock_gettimesince(sys_midiinittime);
373#ifdef TEST_DEJITTER
374 if (midi_inhead == midi_intail)
375 db = 0;
376#endif
377 while (midi_inhead != midi_intail)
378 {
379#ifdef TEST_DEJITTER
380 if (!db)
381 {
382 post("in del %f, logicaltime %f, RT %f adcminusRT %f",
383 (midi_inqueue[midi_intail].q_time - logicaltime),
384 logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
385 db = 1;
386 }
387#endif
388#if 0
389 if (midi_inqueue[midi_intail].q_time <= logicaltime - 0.007)
390 post("late %f",
391 1000 * (logicaltime - midi_inqueue[midi_intail].q_time));
392#endif
393 if (midi_inqueue[midi_intail].q_time <= logicaltime)
394 {
395#if 0
396 post("diff %f",
397 1000* (logicaltime - midi_inqueue[midi_intail].q_time));
398#endif
399 sys_dispatchnextmidiin();
400 }
401 else break;
402 }
403}
404
405 /* this should be called from the system dependent MIDI code when a byte
406 comes in, as a result of our calling sys_poll_midi. We stick it on a
407 timetag queue and dispatch it at the appropriate logical time. */
408
409
410void sys_midibytein(int portno, int byte)
411{
412 static int warned = 0;
413 t_midiqelem *midiqelem;
414 int newhead = midi_inhead +1;
415 if (newhead == MIDIQSIZE)
416 newhead = 0;
417 /* if FIFO is full flush an element to make room */
418 if (newhead == midi_intail)
419 {
420 if (!warned)
421 {
422 post("warning: MIDI timing FIFO overflowed");
423 warned = 1;
424 }
425 sys_dispatchnextmidiin();
426 }
427 midi_inqueue[midi_inhead].q_portno = portno;
428 midi_inqueue[midi_inhead].q_onebyte = 1;
429 midi_inqueue[midi_inhead].q_byte1 = byte;
430 midi_inqueue[midi_inhead].q_time = sys_getmidiinrealtime();
431 midi_inhead = newhead;
432 sys_pollmidiinqueue();
433}
434
435void sys_pollmidiqueue( void)
436{
437#if 0
438 static double lasttime;
439 double newtime = sys_getrealtime();
440 if (newtime - lasttime > 0.007)
441 post("delay %d", (int)(1000 * (newtime - lasttime)));
442 lasttime = newtime;
443#endif
444 sys_poll_midi(); /* OS dependent poll for MIDI input */
445 sys_pollmidioutqueue();
446 sys_pollmidiinqueue();
447}
448
449/******************** dialog window and device listing ********************/
450
451#ifdef USEAPI_OSS
452void midi_oss_init( void);
453#endif
454
455 /* last requested parameters */
456static int midi_nmidiindev;
457static int midi_midiindev[MAXMIDIINDEV];
458static int midi_nmidioutdev;
459static int midi_midioutdev[MAXMIDIOUTDEV];
460
461static void sys_get_midi_params(int *pnmidiindev, int *pmidiindev,
462 int *pnmidioutdev, int *pmidioutdev)
463{
464 int i;
465 *pnmidiindev = midi_nmidiindev;
466 for (i = 0; i < MAXMIDIINDEV; i++)
467 pmidiindev[i] = midi_midiindev[i];
468 *pnmidioutdev = midi_nmidioutdev;
469 for (i = 0; i < MAXMIDIOUTDEV; i++)
470 pmidioutdev[i] = midi_midioutdev[i];
471}
472
473static void sys_save_midi_params(
474 int nmidiindev, int *midiindev,
475 int nmidioutdev, int *midioutdev)
476{
477 int i;
478 midi_nmidiindev = nmidiindev;
479 for (i = 0; i < MAXMIDIINDEV; i++)
480 midi_midiindev[i] = midiindev[i];
481 midi_nmidioutdev = nmidioutdev;
482 for (i = 0; i < MAXMIDIOUTDEV; i++)
483 midi_midioutdev[i] = midioutdev[i];
484}
485
486void sys_open_midi(int nmidiindev, int *midiindev,
487 int nmidioutdev, int *midioutdev)
488{
489#ifdef USEAPI_OSS
490 midi_oss_init();
491#endif
492 sys_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
493 sys_save_midi_params(nmidiindev, midiindev,
494 nmidioutdev, midioutdev);
495}
496
497 /* open midi using whatever parameters were last used */
498void sys_reopen_midi( void)
499{
500 int nmidiindev, midiindev[MAXMIDIINDEV];
501 int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
502 sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
503 sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
504}
505
506#define MAXNDEV 20
507#define DEVDESCSIZE 80
508
509#ifdef MSW
510#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */
511#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */
512#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
513#endif
514
515void sys_listmididevs(void )
516{
517 char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
518 int nindevs = 0, noutdevs = 0, i;
519
520 midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
521 MAXNDEV, DEVDESCSIZE);
522
523 if (!nindevs)
524 post("no midi input devices found");
525 else
526 {
527 post("input devices:");
528 for (i = 0; i < nindevs; i++)
529 post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
530 }
531 if (!noutdevs)
532 post("no midi output devices found");
533 else
534 {
535 post("output devices:");
536 for (i = 0; i < noutdevs; i++)
537 post("%d. %s", i+DEVONSET, outdevlist + i * DEVDESCSIZE);
538 }
539}
540
541extern t_class *glob_pdobject;
542
543 /* start an midi settings dialog window */
544void glob_midi_properties(t_pd *dummy, t_floatarg flongform)
545{
546 char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)];
547 /* these are the devices you're using: */
548 int nindev, midiindev[MAXMIDIINDEV];
549 int noutdev, midioutdev[MAXMIDIOUTDEV];
550 int midiindev1, midiindev2, midiindev3, midiindev4,
551 midioutdev1, midioutdev2, midioutdev3, midioutdev4;
552
553 /* these are all the devices on your system: */
554 char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
555 int nindevs = 0, noutdevs = 0, i;
556
557 char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
558 outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
559
560 midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
561 MAXNDEV, DEVDESCSIZE);
562
563 strcpy(indevliststring, "{ {none} ");
564 for (i = 0; i < nindevs; i++)
565 {
566 strcat(indevliststring, "\"");
567 strcat(indevliststring, indevlist + i * DEVDESCSIZE);
568 strcat(indevliststring, "\" ");
569 }
570 strcat(indevliststring, "}");
571
572 strcpy(outdevliststring, "{ {none} ");
573 for (i = 0; i < noutdevs; i++)
574 {
575 strcat(outdevliststring, "\"");
576 strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
577 strcat(outdevliststring, "\" ");
578 }
579 strcat(outdevliststring, "}");
580
581 sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
582
583 if (nindev > 1 || noutdev > 1)
584 flongform = 1;
585
586 midiindev1 = (nindev > 0 && midiindev[0]>= 0 ? midiindev[0]+1 : 0);
587 midiindev2 = (nindev > 1 && midiindev[1]>= 0 ? midiindev[1]+1 : 0);
588 midiindev3 = (nindev > 2 && midiindev[2]>= 0 ? midiindev[2]+1 : 0);
589 midiindev4 = (nindev > 3 && midiindev[3]>= 0 ? midiindev[3]+1 : 0);
590 midioutdev1 = (noutdev > 0 && midioutdev[0]>=0 ? midioutdev[0]+1 : 0);
591 midioutdev2 = (noutdev > 1 && midioutdev[1]>=0 ? midioutdev[1]+1 : 0);
592 midioutdev3 = (noutdev > 2 && midioutdev[2]>=0 ? midioutdev[2]+1 : 0);
593 midioutdev4 = (noutdev > 3 && midioutdev[3]>=0 ? midioutdev[3]+1 : 0);
594
595 sprintf(buf,
596"pdtk_midi_dialog %%s \
597%s %d %d %d %d %s %d %d %d %d \
598%d\n",
599 indevliststring,
600 midiindev1, midiindev2, midiindev3, midiindev4,
601 outdevliststring,
602 midioutdev1, midioutdev2, midioutdev3, midioutdev4,
603 (flongform != 0));
604 gfxstub_deleteforkey(0);
605 gfxstub_new(&glob_pdobject, glob_midi_properties, buf);
606}
607
608 /* new values from dialog window */
609void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
610{
611 int nmidiindev, midiindev[MAXMIDIINDEV];
612 int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
613 int i, nindev, noutdev;
614 int newmidiindev[4], newmidioutdev[4];
615
616 for (i = 0; i < 4; i++)
617 {
618 newmidiindev[i] = atom_getintarg(i, argc, argv);
619 newmidioutdev[i] = atom_getintarg(i+4, argc, argv);
620 }
621
622 for (i = 0, nindev = 0; i < 4; i++)
623 {
624 if (newmidiindev[i] > 0)
625 {
626 newmidiindev[nindev] = newmidiindev[i]-1;
627 nindev++;
628 }
629 }
630 for (i = 0, noutdev = 0; i < 4; i++)
631 {
632 if (newmidioutdev[i] > 0)
633 {
634 newmidioutdev[noutdev] = newmidioutdev[i]-1;
635 noutdev++;
636 }
637 }
638
639 sys_close_midi();
640 sys_open_midi(nindev, newmidiindev, noutdev, newmidioutdev);
641}
642/* Copyright (c) 1997-1999 Miller Puckette and others.
643* For information on usage and redistribution, and for a DISCLAIMER OF ALL
644* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
645
646/* Clock functions (which should move, but where?) and MIDI queueing */
647
648#include "m_pd.h"
649#include "s_stuff.h"
650#include "m_imp.h"
651#ifdef UNIX
652#include <unistd.h>
653#include <sys/time.h>
654#ifdef HAVE_BSTRING_H
655#include <bstring.h>
656#endif
657#endif
658#ifdef MSW
659#include <winsock.h>
660#include <sys/types.h>
661#include <sys/timeb.h>
662#include <wtypes.h>
663#endif
664#include <string.h>
665#include <stdio.h>
666#include <signal.h>
667
668typedef struct _midiqelem
669{
670 double q_time;
671 int q_portno;
672 unsigned char q_onebyte;
673 unsigned char q_byte1;
674 unsigned char q_byte2;
675 unsigned char q_byte3;
676} t_midiqelem;
677
678#define MIDIQSIZE 1024
679
680t_midiqelem midi_outqueue[MIDIQSIZE];
681int midi_outhead, midi_outtail;
682t_midiqelem midi_inqueue[MIDIQSIZE];
683int midi_inhead, midi_intail;
684static double sys_midiinittime;
685
686 /* this is our current estimate for at what "system" real time the
687 current logical time's output should occur. */
688static double sys_dactimeminusrealtime;
689 /* same for input, should be schduler advance earlier. */
690static double sys_adctimeminusrealtime;
691
692static double sys_newdactimeminusrealtime = -1e20;
693static double sys_newadctimeminusrealtime = -1e20;
694static double sys_whenupdate;
695
696void sys_initmidiqueue( void)
697{
698 sys_midiinittime = clock_getlogicaltime();
699 sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0;
700}
701
702 /* this is called from the OS dependent code from time to time when we
703 think we know the delay (outbuftime) in seconds, at which the last-output
704 audio sample will go out the door. */
705void sys_setmiditimediff(double inbuftime, double outbuftime)
706{
707 double dactimeminusrealtime =
708 .001 * clock_gettimesince(sys_midiinittime)
709 - outbuftime - sys_getrealtime();
710 double adctimeminusrealtime =
711 .001 * clock_gettimesince(sys_midiinittime)
712 + inbuftime - sys_getrealtime();
713 if (dactimeminusrealtime > sys_newdactimeminusrealtime)
714 sys_newdactimeminusrealtime = dactimeminusrealtime;
715 if (adctimeminusrealtime > sys_newadctimeminusrealtime)
716 sys_newadctimeminusrealtime = adctimeminusrealtime;
717 if (sys_getrealtime() > sys_whenupdate)
718 {
719 sys_dactimeminusrealtime = sys_newdactimeminusrealtime;
720 sys_adctimeminusrealtime = sys_newadctimeminusrealtime;
721 sys_newdactimeminusrealtime = -1e20;
722 sys_newadctimeminusrealtime = -1e20;
723 sys_whenupdate = sys_getrealtime() + 1;
724 }
725}
726
727 /* return the logical time of the DAC sample we believe is currently
728 going out, based on how much "system time" has elapsed since the
729 last time sys_setmiditimediff got called. */
730static double sys_getmidioutrealtime( void)
731{
732 return (sys_getrealtime() + sys_dactimeminusrealtime);
733}
734
735static double sys_getmidiinrealtime( void)
736{
737 return (sys_getrealtime() + sys_adctimeminusrealtime);
738}
739
740static void sys_putnext( void)
741{
742 int portno = midi_outqueue[midi_outtail].q_portno;
743 if (midi_outqueue[midi_outtail].q_onebyte)
744 sys_putmidibyte(portno, midi_outqueue[midi_outtail].q_byte1);
745 else sys_putmidimess(portno, midi_outqueue[midi_outtail].q_byte1,
746 midi_outqueue[midi_outtail].q_byte2,
747 midi_outqueue[midi_outtail].q_byte3);
748 midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
749}
750
751/* #define TEST_DEJITTER */
752
753void sys_pollmidioutqueue( void)
754{
755#ifdef TEST_DEJITTER
756 static int db = 0;
757#endif
758 double midirealtime = sys_getmidioutrealtime();
759#ifdef TEST_DEJITTER
760 if (midi_outhead == midi_outtail)
761 db = 0;
762#endif
763 while (midi_outhead != midi_outtail)
764 {
765#ifdef TEST_DEJITTER
766 if (!db)
767 {
768 post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
769 (midi_outqueue[midi_outtail].q_time - midirealtime),
770 midirealtime, .001 * clock_gettimesince(sys_midiinittime),
771 sys_getrealtime(), sys_dactimeminusrealtime);
772 db = 1;
773 }
774#endif
775 if (midi_outqueue[midi_outtail].q_time <= midirealtime)
776 sys_putnext();
777 else break;
778 }
779}
780
781static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c)
782{
783 t_midiqelem *midiqelem;
784 int newhead = midi_outhead +1;
785 if (newhead == MIDIQSIZE)
786 newhead = 0;
787 /* if FIFO is full flush an element to make room */
788 if (newhead == midi_outtail)
789 sys_putnext();
790 midi_outqueue[midi_outhead].q_portno = portno;
791 midi_outqueue[midi_outhead].q_onebyte = onebyte;
792 midi_outqueue[midi_outhead].q_byte1 = a;
793 midi_outqueue[midi_outhead].q_byte2 = b;
794 midi_outqueue[midi_outhead].q_byte3 = c;
795 midi_outqueue[midi_outhead].q_time =
796 .001 * clock_gettimesince(sys_midiinittime);
797 midi_outhead = newhead;
798 sys_pollmidioutqueue();
799}
800
801#define MIDI_NOTEON 144
802#define MIDI_POLYAFTERTOUCH 160
803#define MIDI_CONTROLCHANGE 176
804#define MIDI_PROGRAMCHANGE 192
805#define MIDI_AFTERTOUCH 208
806#define MIDI_PITCHBEND 224
807
808void outmidi_noteon(int portno, int channel, int pitch, int velo)
809{
810 if (pitch < 0) pitch = 0;
811 else if (pitch > 127) pitch = 127;
812 if (velo < 0) velo = 0;
813 else if (velo > 127) velo = 127;
814 sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo);
815}
816
817void outmidi_controlchange(int portno, int channel, int ctl, int value)
818{
819 if (ctl < 0) ctl = 0;
820 else if (ctl > 127) ctl = 127;
821 if (value < 0) value = 0;
822 else if (value > 127) value = 127;
823 sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf),
824 ctl, value);
825}
826
827void outmidi_programchange(int portno, int channel, int value)
828{
829 if (value < 0) value = 0;
830 else if (value > 127) value = 127;
831 sys_queuemidimess(portno, 0,
832 MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0);
833}
834
835void outmidi_pitchbend(int portno, int channel, int value)
836{
837 if (value < 0) value = 0;
838 else if (value > 16383) value = 16383;
839 sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf),
840 (value & 127), ((value>>7) & 127));
841}
842
843void outmidi_aftertouch(int portno, int channel, int value)
844{
845 if (value < 0) value = 0;
846 else if (value > 127) value = 127;
847 sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0);
848}
849
850void outmidi_polyaftertouch(int portno, int channel, int pitch, int value)
851{
852 if (pitch < 0) pitch = 0;
853 else if (pitch > 127) pitch = 127;
854 if (value < 0) value = 0;
855 else if (value > 127) value = 127;
856 sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf),
857 pitch, value);
858}
859
860void outmidi_mclk(int portno)
861{
862 sys_queuemidimess(portno, 1, 0xf8, 0,0);
863}
864
865/* ------------------------- MIDI input queue handling ------------------ */
866typedef struct midiparser
867{
868 int mp_status;
869 int mp_gotbyte1;
870 int mp_byte1;
871} t_midiparser;
872
873#define MIDINOTEOFF 0x80 /* 2 following 'data bytes' */
874#define MIDINOTEON 0x90 /* 2 */
875#define MIDIPOLYTOUCH 0xa0 /* 2 */
876#define MIDICONTROLCHANGE 0xb0 /* 2 */
877#define MIDIPROGRAMCHANGE 0xc0 /* 1 */
878#define MIDICHANNELTOUCH 0xd0 /* 1 */
879#define MIDIPITCHBEND 0xe0 /* 2 */
880#define MIDISTARTSYSEX 0xf0 /* (until F7) */
881#define MIDITIMECODE 0xf1 /* 1 */
882#define MIDISONGPOS 0xf2 /* 2 */
883#define MIDISONGSELECT 0xf3 /* 1 */
884#define MIDIRESERVED1 0xf4 /* ? */
885#define MIDIRESERVED2 0xf5 /* ? */
886#define MIDITUNEREQUEST 0xf6 /* 0 */
887#define MIDIENDSYSEX 0xf7 /* 0 */
888#define MIDICLOCK 0xf8 /* 0 */
889#define MIDITICK 0xf9 /* 0 */
890#define MIDISTART 0xfa /* 0 */
891#define MIDICONT 0xfb /* 0 */
892#define MIDISTOP 0xfc /* 0 */
893#define MIDIACTIVESENSE 0xfe /* 0 */
894#define MIDIRESET 0xff /* 0 */
895
896 /* functions in x_midi.c */
897void inmidi_realtimein(int portno, int cmd);
898void inmidi_byte(int portno, int byte);
899void inmidi_sysex(int portno, int byte);
900void inmidi_noteon(int portno, int channel, int pitch, int velo);
901void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
902void inmidi_programchange(int portno, int channel, int value);
903void inmidi_pitchbend(int portno, int channel, int value);
904void inmidi_aftertouch(int portno, int channel, int value);
905void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
906
907static void sys_dispatchnextmidiin( void)
908{
909 static t_midiparser parser[MAXMIDIINDEV], *parserp;
910 int portno = midi_inqueue[midi_intail].q_portno,
911 byte = midi_inqueue[midi_intail].q_byte1;
912 if (!midi_inqueue[midi_intail].q_onebyte)
913 bug("sys_dispatchnextmidiin");
914 if (portno < 0 || portno >= MAXMIDIINDEV)
915 bug("sys_dispatchnextmidiin 2");
916 parserp = parser + portno;
917 outlet_setstacklim();
918
919 if (byte >= 0xf8)
920 inmidi_realtimein(portno, byte);
921 else
922 {
923 inmidi_byte(portno, byte);
924 if (byte & 0x80)
925 {
926 if (byte == MIDITUNEREQUEST || byte == MIDIRESERVED1 ||
927 byte == MIDIRESERVED2)
928 parserp->mp_status = 0;
929 else if (byte == MIDISTARTSYSEX)
930 {
931 inmidi_sysex(portno, byte);
932 parserp->mp_status = byte;
933 }
934 else if (byte == MIDIENDSYSEX)
935 {
936 inmidi_sysex(portno, byte);
937 parserp->mp_status = 0;
938 }
939 else
940 {
941 parserp->mp_status = byte;
942 }
943 parserp->mp_gotbyte1 = 0;
944 }
945 else
946 {
947 int cmd = (parserp->mp_status >= 0xf0 ? parserp->mp_status :
948 (parserp->mp_status & 0xf0));
949 int chan = (parserp->mp_status & 0xf);
950 int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1;
951 switch (cmd)
952 {
953 case MIDINOTEOFF:
954 if (gotbyte1)
955 inmidi_noteon(portno, chan, byte1, 0),
956 parserp->mp_gotbyte1 = 0;
957 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
958 break;
959 case MIDINOTEON:
960 if (gotbyte1)
961 inmidi_noteon(portno, chan, byte1, byte),
962 parserp->mp_gotbyte1 = 0;
963 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
964 break;
965 case MIDIPOLYTOUCH:
966 if (gotbyte1)
967 inmidi_polyaftertouch(portno, chan, byte1, byte),
968 parserp->mp_gotbyte1 = 0;
969 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
970 break;
971 case MIDICONTROLCHANGE:
972 if (gotbyte1)
973 inmidi_controlchange(portno, chan, byte1, byte),
974 parserp->mp_gotbyte1 = 0;
975 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
976 break;
977 case MIDIPROGRAMCHANGE:
978 inmidi_programchange(portno, chan, byte);
979 break;
980 case MIDICHANNELTOUCH:
981 inmidi_aftertouch(portno, chan, byte);
982 break;
983 case MIDIPITCHBEND:
984 if (gotbyte1)
985 inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)),
986 parserp->mp_gotbyte1 = 0;
987 else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
988 break;
989 case MIDISTARTSYSEX:
990 inmidi_sysex(portno, byte);
991 break;
992
993 /* other kinds of messages are just dropped here. We'll
994 need another status byte before we start letting MIDI in
995 again (no running status across "system" messages). */
996 case MIDITIMECODE: /* 1 data byte*/
997 break;
998 case MIDISONGPOS: /* 2 */
999 break;
1000 case MIDISONGSELECT: /* 1 */
1001 break;
1002 }
1003 }
1004 }
1005 midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
1006}
1007
1008void sys_pollmidiinqueue( void)
1009{
1010#ifdef TEST_DEJITTER
1011 static int db = 0;
1012#endif
1013 double logicaltime = .001 * clock_gettimesince(sys_midiinittime);
1014#ifdef TEST_DEJITTER
1015 if (midi_inhead == midi_intail)
1016 db = 0;
1017#endif
1018 while (midi_inhead != midi_intail)
1019 {
1020#ifdef TEST_DEJITTER
1021 if (!db)
1022 {
1023 post("in del %f, logicaltime %f, RT %f adcminusRT %f",
1024 (midi_inqueue[midi_intail].q_time - logicaltime),
1025 logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
1026 db = 1;
1027 }
1028#endif
1029#if 0
1030 if (midi_inqueue[midi_intail].q_time <= logicaltime - 0.007)
1031 post("late %f",
1032 1000 * (logicaltime - midi_inqueue[midi_intail].q_time));
1033#endif
1034 if (midi_inqueue[midi_intail].q_time <= logicaltime)
1035 {
1036#if 0
1037 post("diff %f",
1038 1000* (logicaltime - midi_inqueue[midi_intail].q_time));
1039#endif
1040 sys_dispatchnextmidiin();
1041 }
1042 else break;
1043 }
1044}
1045
1046 /* this should be called from the system dependent MIDI code when a byte
1047 comes in, as a result of our calling sys_poll_midi. We stick it on a
1048 timetag queue and dispatch it at the appropriate logical time. */
1049
1050
1051void sys_midibytein(int portno, int byte)
1052{
1053 static int warned = 0;
1054 t_midiqelem *midiqelem;
1055 int newhead = midi_inhead +1;
1056 if (newhead == MIDIQSIZE)
1057 newhead = 0;
1058 /* if FIFO is full flush an element to make room */
1059 if (newhead == midi_intail)
1060 {
1061 if (!warned)
1062 {
1063 post("warning: MIDI timing FIFO overflowed");
1064 warned = 1;
1065 }
1066 sys_dispatchnextmidiin();
1067 }
1068 midi_inqueue[midi_inhead].q_portno = portno;
1069 midi_inqueue[midi_inhead].q_onebyte = 1;
1070 midi_inqueue[midi_inhead].q_byte1 = byte;
1071 midi_inqueue[midi_inhead].q_time = sys_getmidiinrealtime();
1072 midi_inhead = newhead;
1073 sys_pollmidiinqueue();
1074}
1075
1076void sys_pollmidiqueue( void)
1077{
1078#if 0
1079 static double lasttime;
1080 double newtime = sys_getrealtime();
1081 if (newtime - lasttime > 0.007)
1082 post("delay %d", (int)(1000 * (newtime - lasttime)));
1083 lasttime = newtime;
1084#endif
1085 sys_poll_midi(); /* OS dependent poll for MIDI input */
1086 sys_pollmidioutqueue();
1087 sys_pollmidiinqueue();
1088}
1089
1090/******************** dialog window and device listing ********************/
1091
1092#ifdef USEAPI_OSS
1093void midi_oss_init( void);
1094#endif
1095
1096 /* last requested parameters */
1097static int midi_nmidiindev;
1098static int midi_midiindev[MAXMIDIINDEV];
1099static int midi_nmidioutdev;
1100static int midi_midioutdev[MAXMIDIOUTDEV];
1101
1102static void sys_get_midi_params(int *pnmidiindev, int *pmidiindev,
1103 int *pnmidioutdev, int *pmidioutdev)
1104{
1105 int i;
1106 *pnmidiindev = midi_nmidiindev;
1107 for (i = 0; i < MAXMIDIINDEV; i++)
1108 pmidiindev[i] = midi_midiindev[i];
1109 *pnmidioutdev = midi_nmidioutdev;
1110 for (i = 0; i < MAXMIDIOUTDEV; i++)
1111 pmidioutdev[i] = midi_midioutdev[i];
1112}
1113
1114static void sys_save_midi_params(
1115 int nmidiindev, int *midiindev,
1116 int nmidioutdev, int *midioutdev)
1117{
1118 int i;
1119 midi_nmidiindev = nmidiindev;
1120 for (i = 0; i < MAXMIDIINDEV; i++)
1121 midi_midiindev[i] = midiindev[i];
1122 midi_nmidioutdev = nmidioutdev;
1123 for (i = 0; i < MAXMIDIOUTDEV; i++)
1124 midi_midioutdev[i] = midioutdev[i];
1125}
1126
1127void sys_open_midi(int nmidiindev, int *midiindev,
1128 int nmidioutdev, int *midioutdev)
1129{
1130#ifdef USEAPI_OSS
1131 midi_oss_init();
1132#endif
1133 sys_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
1134 sys_save_midi_params(nmidiindev, midiindev,
1135 nmidioutdev, midioutdev);
1136}
1137
1138 /* open midi using whatever parameters were last used */
1139void sys_reopen_midi( void)
1140{
1141 int nmidiindev, midiindev[MAXMIDIINDEV];
1142 int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
1143 sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
1144 sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
1145}
1146
1147#define MAXNDEV 20
1148#define DEVDESCSIZE 80
1149
1150#ifdef MSW
1151#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */
1152#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */
1153#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
1154#endif
1155
1156void sys_listmididevs(void )
1157{
1158 char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
1159 int nindevs = 0, noutdevs = 0, i;
1160
1161 midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
1162 MAXNDEV, DEVDESCSIZE);
1163
1164 if (!nindevs)
1165 post("no midi input devices found");
1166 else
1167 {
1168 post("input devices:");
1169 for (i = 0; i < nindevs; i++)
1170 post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
1171 }
1172 if (!noutdevs)
1173 post("no midi output devices found");
1174 else
1175 {
1176 post("output devices:");
1177 for (i = 0; i < noutdevs; i++)
1178 post("%d. %s", i+DEVONSET, outdevlist + i * DEVDESCSIZE);
1179 }
1180}
1181
1182extern t_class *glob_pdobject;
1183
1184 /* start an midi settings dialog window */
1185void glob_midi_properties(t_pd *dummy, t_floatarg flongform)
1186{
1187 char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)];
1188 /* these are the devices you're using: */
1189 int nindev, midiindev[MAXMIDIINDEV];
1190 int noutdev, midioutdev[MAXMIDIOUTDEV];
1191 int midiindev1, midiindev2, midiindev3, midiindev4,
1192 midioutdev1, midioutdev2, midioutdev3, midioutdev4;
1193
1194 /* these are all the devices on your system: */
1195 char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
1196 int nindevs = 0, noutdevs = 0, i;
1197
1198 char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
1199 outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
1200
1201 midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
1202 MAXNDEV, DEVDESCSIZE);
1203
1204 strcpy(indevliststring, "{ {none} ");
1205 for (i = 0; i < nindevs; i++)
1206 {
1207 strcat(indevliststring, "\"");
1208 strcat(indevliststring, indevlist + i * DEVDESCSIZE);
1209 strcat(indevliststring, "\" ");
1210 }
1211 strcat(indevliststring, "}");
1212
1213 strcpy(outdevliststring, "{ {none} ");
1214 for (i = 0; i < noutdevs; i++)
1215 {
1216 strcat(outdevliststring, "\"");
1217 strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
1218 strcat(outdevliststring, "\" ");
1219 }
1220 strcat(outdevliststring, "}");
1221
1222 sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
1223
1224 if (nindev > 1 || noutdev > 1)
1225 flongform = 1;
1226
1227 midiindev1 = (nindev > 0 && midiindev[0]>= 0 ? midiindev[0]+1 : 0);
1228 midiindev2 = (nindev > 1 && midiindev[1]>= 0 ? midiindev[1]+1 : 0);
1229 midiindev3 = (nindev > 2 && midiindev[2]>= 0 ? midiindev[2]+1 : 0);
1230 midiindev4 = (nindev > 3 && midiindev[3]>= 0 ? midiindev[3]+1 : 0);
1231 midioutdev1 = (noutdev > 0 && midioutdev[0]>=0 ? midioutdev[0]+1 : 0);
1232 midioutdev2 = (noutdev > 1 && midioutdev[1]>=0 ? midioutdev[1]+1 : 0);
1233 midioutdev3 = (noutdev > 2 && midioutdev[2]>=0 ? midioutdev[2]+1 : 0);
1234 midioutdev4 = (noutdev > 3 && midioutdev[3]>=0 ? midioutdev[3]+1 : 0);
1235
1236 sprintf(buf,
1237"pdtk_midi_dialog %%s \
1238%s %d %d %d %d %s %d %d %d %d \
1239%d\n",
1240 indevliststring,
1241 midiindev1, midiindev2, midiindev3, midiindev4,
1242 outdevliststring,
1243 midioutdev1, midioutdev2, midioutdev3, midioutdev4,
1244 (flongform != 0));
1245 gfxstub_deleteforkey(0);
1246 gfxstub_new(&glob_pdobject, glob_midi_properties, buf);
1247}
1248
1249 /* new values from dialog window */
1250void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
1251{
1252 int nmidiindev, midiindev[MAXMIDIINDEV];
1253 int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
1254 int i, nindev, noutdev;
1255 int newmidiindev[4], newmidioutdev[4];
1256
1257 for (i = 0; i < 4; i++)
1258 {
1259 newmidiindev[i] = atom_getintarg(i, argc, argv);
1260 newmidioutdev[i] = atom_getintarg(i+4, argc, argv);
1261 }
1262
1263 for (i = 0, nindev = 0; i < 4; i++)
1264 {
1265 if (newmidiindev[i] > 0)
1266 {
1267 newmidiindev[nindev] = newmidiindev[i]-1;
1268 nindev++;
1269 }
1270 }
1271 for (i = 0, noutdev = 0; i < 4; i++)
1272 {
1273 if (newmidioutdev[i] > 0)
1274 {
1275 newmidioutdev[noutdev] = newmidioutdev[i]-1;
1276 noutdev++;
1277 }
1278 }
1279
1280 sys_close_midi();
1281 sys_open_midi(nindev, newmidiindev, noutdev, newmidioutdev);
1282}
diff --git a/apps/plugins/pdbox/PDa/src/s_midi_oss.c b/apps/plugins/pdbox/PDa/src/s_midi_oss.c
new file mode 100644
index 0000000000..1adfcd0d0c
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_midi_oss.c
@@ -0,0 +1,718 @@
1/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler,
2* Winfried Ritsch, Karl MacMillan, and others.
3* For information on usage and redistribution, and for a DISCLAIMER OF ALL
4* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5
6/* MIDI I/O for Linux using OSS */
7
8#include <stdio.h>
9#ifdef UNIX
10#include <unistd.h>
11#endif
12#include <stdlib.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <errno.h>
17#include "m_pd.h"
18#include "s_stuff.h"
19
20static int oss_nmidiin;
21static int oss_midiinfd[MAXMIDIINDEV];
22static int oss_nmidiout;
23static int oss_midioutfd[MAXMIDIOUTDEV];
24
25static void oss_midiout(int fd, int n)
26{
27 char b = n;
28 if ((write(fd, (char *) &b, 1)) != 1)
29 perror("midi write");
30}
31
32#define O_MIDIFLAG O_NDELAY
33
34void sys_do_open_midi(int nmidiin, int *midiinvec,
35 int nmidiout, int *midioutvec)
36{
37 int i;
38 for (i = 0; i < nmidiout; i++)
39 oss_midioutfd[i] = -1;
40 for (i = 0, oss_nmidiin = 0; i < nmidiin; i++)
41 {
42 int fd = -1, j, outdevindex = -1;
43 char namebuf[80];
44 int devno = midiinvec[i];
45
46 for (j = 0; j < nmidiout; j++)
47 if (midioutvec[j] == midiinvec[i])
48 outdevindex = j;
49
50 /* try to open the device for read/write. */
51 if (devno == 0 && fd < 0 && outdevindex >= 0)
52 {
53 sys_setalarm(1000000);
54 fd = open("/dev/midi", O_RDWR | O_MIDIFLAG);
55 if (sys_verbose)
56 fprintf(stderr,
57 "device 1: tried /dev/midi READ/WRITE; returned %d\n", fd);
58 if (outdevindex >= 0 && fd >= 0)
59 oss_midioutfd[outdevindex] = fd;
60 }
61 if (fd < 0 && outdevindex >= 0)
62 {
63 sys_setalarm(1000000);
64 sprintf(namebuf, "/dev/midi%2.2d", devno);
65 fd = open(namebuf, O_RDWR | O_MIDIFLAG);
66 if (sys_verbose)
67 fprintf(stderr,
68 "device %d: tried %s READ/WRITE; returned %d\n",
69 devno, namebuf, fd);
70 if (outdevindex >= 0 && fd >= 0)
71 oss_midioutfd[outdevindex] = fd;
72 }
73 if (fd < 0 && outdevindex >= 0)
74 {
75 sys_setalarm(1000000);
76 sprintf(namebuf, "/dev/midi%d", devno);
77 fd = open(namebuf, O_RDWR | O_MIDIFLAG);
78 if (sys_verbose)
79 fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n",
80 devno, namebuf, fd);
81 if (outdevindex >= 0 && fd >= 0)
82 oss_midioutfd[outdevindex] = fd;
83 }
84 if (devno == 1 && fd < 0)
85 {
86 sys_setalarm(1000000);
87 fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG);
88 if (sys_verbose)
89 fprintf(stderr,
90 "device 1: tried /dev/midi READONLY; returned %d\n", fd);
91 }
92 if (fd < 0)
93 {
94 sys_setalarm(1000000);
95 sprintf(namebuf, "/dev/midi%2.2d", devno);
96 fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
97 if (sys_verbose)
98 fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
99 devno, namebuf, fd);
100 }
101 if (fd < 0)
102 {
103 sys_setalarm(1000000);
104 sprintf(namebuf, "/dev/midi%d", devno);
105 fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
106 if (sys_verbose)
107 fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
108 devno, namebuf, fd);
109 }
110 if (fd >= 0)
111 oss_midiinfd[oss_nmidiin++] = fd;
112 else post("couldn't open MIDI input device %d", devno);
113 }
114 for (i = 0, oss_nmidiout = 0; i < nmidiout; i++)
115 {
116 int fd = oss_midioutfd[i];
117 char namebuf[80];
118 int devno = midioutvec[i];
119 if (devno == 1 && fd < 0)
120 {
121 sys_setalarm(1000000);
122 fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG);
123 if (sys_verbose)
124 fprintf(stderr,
125 "device 1: tried /dev/midi WRITEONLY; returned %d\n", fd);
126 }
127 if (fd < 0)
128 {
129 sys_setalarm(1000000);
130 sprintf(namebuf, "/dev/midi%2.2d", devno);
131 fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
132 if (sys_verbose)
133 fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
134 devno, namebuf, fd);
135 }
136 if (fd < 0)
137 {
138 sys_setalarm(1000000);
139 sprintf(namebuf, "/dev/midi%d", devno);
140 fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
141 if (sys_verbose)
142 fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
143 devno, namebuf, fd);
144 }
145 if (fd >= 0)
146 oss_midioutfd[oss_nmidiout++] = fd;
147 else post("couldn't open MIDI output device %d", devno);
148 }
149
150 if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose)
151 post("opened %d MIDI input device(s) and %d MIDI output device(s).",
152 oss_nmidiin, oss_nmidiout);
153
154 sys_setalarm(0);
155}
156
157#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\
158 ((x)==0xF2)?2:((x)<0xF4)?1:0)
159
160void sys_putmidimess(int portno, int a, int b, int c)
161{
162 if (portno >= 0 && portno < oss_nmidiout)
163 {
164 switch (md_msglen(a))
165 {
166 case 2:
167 oss_midiout(oss_midioutfd[portno],a);
168 oss_midiout(oss_midioutfd[portno],b);
169 oss_midiout(oss_midioutfd[portno],c);
170 return;
171 case 1:
172 oss_midiout(oss_midioutfd[portno],a);
173 oss_midiout(oss_midioutfd[portno],b);
174 return;
175 case 0:
176 oss_midiout(oss_midioutfd[portno],a);
177 return;
178 };
179 }
180}
181
182void sys_putmidibyte(int portno, int byte)
183{
184 if (portno >= 0 && portno < oss_nmidiout)
185 oss_midiout(oss_midioutfd[portno], byte);
186}
187
188#if 0 /* this is the "select" version which doesn't work with OSS
189 driver for emu10k1 (it doesn't implement select.) */
190void sys_poll_midi(void)
191{
192 int i, throttle = 100;
193 struct timeval timout;
194 int did = 1, maxfd = 0;
195 while (did)
196 {
197 fd_set readset, writeset, exceptset;
198 did = 0;
199 if (throttle-- < 0)
200 break;
201 timout.tv_sec = 0;
202 timout.tv_usec = 0;
203
204 FD_ZERO(&writeset);
205 FD_ZERO(&readset);
206 FD_ZERO(&exceptset);
207 for (i = 0; i < oss_nmidiin; i++)
208 {
209 if (oss_midiinfd[i] > maxfd)
210 maxfd = oss_midiinfd[i];
211 FD_SET(oss_midiinfd[i], &readset);
212 }
213 select(maxfd+1, &readset, &writeset, &exceptset, &timout);
214 for (i = 0; i < oss_nmidiin; i++)
215 if (FD_ISSET(oss_midiinfd[i], &readset))
216 {
217 char c;
218 int ret = read(oss_midiinfd[i], &c, 1);
219 if (ret <= 0)
220 fprintf(stderr, "Midi read error\n");
221 else sys_midibytein(i, (c & 0xff));
222 did = 1;
223 }
224 }
225}
226#else
227
228 /* this version uses the asynchronous "read()" ... */
229void sys_poll_midi(void)
230{
231 int i, throttle = 100;
232 struct timeval timout;
233 int did = 1, maxfd = 0;
234 while (did)
235 {
236 fd_set readset, writeset, exceptset;
237 did = 0;
238 if (throttle-- < 0)
239 break;
240 for (i = 0; i < oss_nmidiin; i++)
241 {
242 char c;
243 int ret = read(oss_midiinfd[i], &c, 1);
244 if (ret < 0)
245 {
246 if (errno != EAGAIN)
247 perror("MIDI");
248 }
249 else if (ret != 0)
250 {
251 sys_midibytein(i, (c & 0xff));
252 did = 1;
253 }
254 }
255 }
256}
257#endif
258
259void sys_close_midi()
260{
261 int i;
262 for (i = 0; i < oss_nmidiin; i++)
263 close(oss_midiinfd[i]);
264 for (i = 0; i < oss_nmidiout; i++)
265 close(oss_midioutfd[i]);
266 oss_nmidiin = oss_nmidiout = 0;
267}
268
269#define NSEARCH 10
270static int oss_nmidiindevs, oss_nmidioutdevs, oss_initted;
271
272void midi_oss_init(void)
273{
274 int i;
275 if (oss_initted)
276 return;
277 oss_initted = 1;
278 for (i = 0; i < NSEARCH; i++)
279 {
280 int fd;
281 char namebuf[80];
282
283 oss_nmidiindevs = i;
284 /* try to open the device for reading */
285 if (i == 0)
286 {
287 fd = open("/dev/midi", O_RDONLY | O_NDELAY);
288 if (fd >= 0)
289 {
290 close(fd);
291 continue;
292 }
293 }
294 sprintf(namebuf, "/dev/midi%2.2d", i);
295 fd = open(namebuf, O_RDONLY | O_NDELAY);
296 if (fd >= 0)
297 {
298 close(fd);
299 continue;
300 }
301 sprintf(namebuf, "/dev/midi%d", i);
302 fd = open(namebuf, O_RDONLY | O_NDELAY);
303 if (fd >= 0)
304 {
305 close(fd);
306 continue;
307 }
308 break;
309 }
310 for (i = 0; i < NSEARCH; i++)
311 {
312 int fd;
313 char namebuf[80];
314
315 oss_nmidioutdevs = i;
316 /* try to open the device for writing */
317 if (i == 0)
318 {
319 fd = open("/dev/midi", O_WRONLY | O_NDELAY);
320 if (fd >= 0)
321 {
322 close(fd);
323 continue;
324 }
325 }
326 sprintf(namebuf, "/dev/midi%2.2d", i);
327 fd = open(namebuf, O_WRONLY | O_NDELAY);
328 if (fd >= 0)
329 {
330 close(fd);
331 continue;
332 }
333 sprintf(namebuf, "/dev/midi%d", i);
334 fd = open(namebuf, O_WRONLY | O_NDELAY);
335 if (fd >= 0)
336 {
337 close(fd);
338 continue;
339 }
340 break;
341 }
342}
343
344void midi_getdevs(char *indevlist, int *nindevs,
345 char *outdevlist, int *noutdevs, int maxndev, int devdescsize)
346{
347 int i, ndev;
348 if ((ndev = oss_nmidiindevs) > maxndev)
349 ndev = maxndev;
350 for (i = 0; i < ndev; i++)
351 sprintf(indevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
352 *nindevs = ndev;
353
354 if ((ndev = oss_nmidioutdevs) > maxndev)
355 ndev = maxndev;
356 for (i = 0; i < ndev; i++)
357 sprintf(outdevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
358 *noutdevs = ndev;
359}
360/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler,
361* Winfried Ritsch, Karl MacMillan, and others.
362* For information on usage and redistribution, and for a DISCLAIMER OF ALL
363* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
364
365/* MIDI I/O for Linux using OSS */
366
367#include <stdio.h>
368#ifdef UNIX
369#include <unistd.h>
370#endif
371#include <stdlib.h>
372#include <sys/types.h>
373#include <sys/stat.h>
374#include <fcntl.h>
375#include <errno.h>
376#include "m_pd.h"
377#include "s_stuff.h"
378
379static int oss_nmidiin;
380static int oss_midiinfd[MAXMIDIINDEV];
381static int oss_nmidiout;
382static int oss_midioutfd[MAXMIDIOUTDEV];
383
384static void oss_midiout(int fd, int n)
385{
386 char b = n;
387 if ((write(fd, (char *) &b, 1)) != 1)
388 perror("midi write");
389}
390
391#define O_MIDIFLAG O_NDELAY
392
393void sys_do_open_midi(int nmidiin, int *midiinvec,
394 int nmidiout, int *midioutvec)
395{
396 int i;
397 for (i = 0; i < nmidiout; i++)
398 oss_midioutfd[i] = -1;
399 for (i = 0, oss_nmidiin = 0; i < nmidiin; i++)
400 {
401 int fd = -1, j, outdevindex = -1;
402 char namebuf[80];
403 int devno = midiinvec[i];
404
405 for (j = 0; j < nmidiout; j++)
406 if (midioutvec[j] == midiinvec[i])
407 outdevindex = j;
408
409 /* try to open the device for read/write. */
410 if (devno == 0 && fd < 0 && outdevindex >= 0)
411 {
412 sys_setalarm(1000000);
413 fd = open("/dev/midi", O_RDWR | O_MIDIFLAG);
414 if (sys_verbose)
415 fprintf(stderr,
416 "device 1: tried /dev/midi READ/WRITE; returned %d\n", fd);
417 if (outdevindex >= 0 && fd >= 0)
418 oss_midioutfd[outdevindex] = fd;
419 }
420 if (fd < 0 && outdevindex >= 0)
421 {
422 sys_setalarm(1000000);
423 sprintf(namebuf, "/dev/midi%2.2d", devno);
424 fd = open(namebuf, O_RDWR | O_MIDIFLAG);
425 if (sys_verbose)
426 fprintf(stderr,
427 "device %d: tried %s READ/WRITE; returned %d\n",
428 devno, namebuf, fd);
429 if (outdevindex >= 0 && fd >= 0)
430 oss_midioutfd[outdevindex] = fd;
431 }
432 if (fd < 0 && outdevindex >= 0)
433 {
434 sys_setalarm(1000000);
435 sprintf(namebuf, "/dev/midi%d", devno);
436 fd = open(namebuf, O_RDWR | O_MIDIFLAG);
437 if (sys_verbose)
438 fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n",
439 devno, namebuf, fd);
440 if (outdevindex >= 0 && fd >= 0)
441 oss_midioutfd[outdevindex] = fd;
442 }
443 if (devno == 1 && fd < 0)
444 {
445 sys_setalarm(1000000);
446 fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG);
447 if (sys_verbose)
448 fprintf(stderr,
449 "device 1: tried /dev/midi READONLY; returned %d\n", fd);
450 }
451 if (fd < 0)
452 {
453 sys_setalarm(1000000);
454 sprintf(namebuf, "/dev/midi%2.2d", devno);
455 fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
456 if (sys_verbose)
457 fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
458 devno, namebuf, fd);
459 }
460 if (fd < 0)
461 {
462 sys_setalarm(1000000);
463 sprintf(namebuf, "/dev/midi%d", devno);
464 fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
465 if (sys_verbose)
466 fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
467 devno, namebuf, fd);
468 }
469 if (fd >= 0)
470 oss_midiinfd[oss_nmidiin++] = fd;
471 else post("couldn't open MIDI input device %d", devno);
472 }
473 for (i = 0, oss_nmidiout = 0; i < nmidiout; i++)
474 {
475 int fd = oss_midioutfd[i];
476 char namebuf[80];
477 int devno = midioutvec[i];
478 if (devno == 1 && fd < 0)
479 {
480 sys_setalarm(1000000);
481 fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG);
482 if (sys_verbose)
483 fprintf(stderr,
484 "device 1: tried /dev/midi WRITEONLY; returned %d\n", fd);
485 }
486 if (fd < 0)
487 {
488 sys_setalarm(1000000);
489 sprintf(namebuf, "/dev/midi%2.2d", devno);
490 fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
491 if (sys_verbose)
492 fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
493 devno, namebuf, fd);
494 }
495 if (fd < 0)
496 {
497 sys_setalarm(1000000);
498 sprintf(namebuf, "/dev/midi%d", devno);
499 fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
500 if (sys_verbose)
501 fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
502 devno, namebuf, fd);
503 }
504 if (fd >= 0)
505 oss_midioutfd[oss_nmidiout++] = fd;
506 else post("couldn't open MIDI output device %d", devno);
507 }
508
509 if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose)
510 post("opened %d MIDI input device(s) and %d MIDI output device(s).",
511 oss_nmidiin, oss_nmidiout);
512
513 sys_setalarm(0);
514}
515
516#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\
517 ((x)==0xF2)?2:((x)<0xF4)?1:0)
518
519void sys_putmidimess(int portno, int a, int b, int c)
520{
521 if (portno >= 0 && portno < oss_nmidiout)
522 {
523 switch (md_msglen(a))
524 {
525 case 2:
526 oss_midiout(oss_midioutfd[portno],a);
527 oss_midiout(oss_midioutfd[portno],b);
528 oss_midiout(oss_midioutfd[portno],c);
529 return;
530 case 1:
531 oss_midiout(oss_midioutfd[portno],a);
532 oss_midiout(oss_midioutfd[portno],b);
533 return;
534 case 0:
535 oss_midiout(oss_midioutfd[portno],a);
536 return;
537 };
538 }
539}
540
541void sys_putmidibyte(int portno, int byte)
542{
543 if (portno >= 0 && portno < oss_nmidiout)
544 oss_midiout(oss_midioutfd[portno], byte);
545}
546
547#if 0 /* this is the "select" version which doesn't work with OSS
548 driver for emu10k1 (it doesn't implement select.) */
549void sys_poll_midi(void)
550{
551 int i, throttle = 100;
552 struct timeval timout;
553 int did = 1, maxfd = 0;
554 while (did)
555 {
556 fd_set readset, writeset, exceptset;
557 did = 0;
558 if (throttle-- < 0)
559 break;
560 timout.tv_sec = 0;
561 timout.tv_usec = 0;
562
563 FD_ZERO(&writeset);
564 FD_ZERO(&readset);
565 FD_ZERO(&exceptset);
566 for (i = 0; i < oss_nmidiin; i++)
567 {
568 if (oss_midiinfd[i] > maxfd)
569 maxfd = oss_midiinfd[i];
570 FD_SET(oss_midiinfd[i], &readset);
571 }
572 select(maxfd+1, &readset, &writeset, &exceptset, &timout);
573 for (i = 0; i < oss_nmidiin; i++)
574 if (FD_ISSET(oss_midiinfd[i], &readset))
575 {
576 char c;
577 int ret = read(oss_midiinfd[i], &c, 1);
578 if (ret <= 0)
579 fprintf(stderr, "Midi read error\n");
580 else sys_midibytein(i, (c & 0xff));
581 did = 1;
582 }
583 }
584}
585#else
586
587 /* this version uses the asynchronous "read()" ... */
588void sys_poll_midi(void)
589{
590 int i, throttle = 100;
591 struct timeval timout;
592 int did = 1, maxfd = 0;
593 while (did)
594 {
595 fd_set readset, writeset, exceptset;
596 did = 0;
597 if (throttle-- < 0)
598 break;
599 for (i = 0; i < oss_nmidiin; i++)
600 {
601 char c;
602 int ret = read(oss_midiinfd[i], &c, 1);
603 if (ret < 0)
604 {
605 if (errno != EAGAIN)
606 perror("MIDI");
607 }
608 else if (ret != 0)
609 {
610 sys_midibytein(i, (c & 0xff));
611 did = 1;
612 }
613 }
614 }
615}
616#endif
617
618void sys_close_midi()
619{
620 int i;
621 for (i = 0; i < oss_nmidiin; i++)
622 close(oss_midiinfd[i]);
623 for (i = 0; i < oss_nmidiout; i++)
624 close(oss_midioutfd[i]);
625 oss_nmidiin = oss_nmidiout = 0;
626}
627
628#define NSEARCH 10
629static int oss_nmidiindevs, oss_nmidioutdevs, oss_initted;
630
631void midi_oss_init(void)
632{
633 int i;
634 if (oss_initted)
635 return;
636 oss_initted = 1;
637 for (i = 0; i < NSEARCH; i++)
638 {
639 int fd;
640 char namebuf[80];
641
642 oss_nmidiindevs = i;
643 /* try to open the device for reading */
644 if (i == 0)
645 {
646 fd = open("/dev/midi", O_RDONLY | O_NDELAY);
647 if (fd >= 0)
648 {
649 close(fd);
650 continue;
651 }
652 }
653 sprintf(namebuf, "/dev/midi%2.2d", i);
654 fd = open(namebuf, O_RDONLY | O_NDELAY);
655 if (fd >= 0)
656 {
657 close(fd);
658 continue;
659 }
660 sprintf(namebuf, "/dev/midi%d", i);
661 fd = open(namebuf, O_RDONLY | O_NDELAY);
662 if (fd >= 0)
663 {
664 close(fd);
665 continue;
666 }
667 break;
668 }
669 for (i = 0; i < NSEARCH; i++)
670 {
671 int fd;
672 char namebuf[80];
673
674 oss_nmidioutdevs = i;
675 /* try to open the device for writing */
676 if (i == 0)
677 {
678 fd = open("/dev/midi", O_WRONLY | O_NDELAY);
679 if (fd >= 0)
680 {
681 close(fd);
682 continue;
683 }
684 }
685 sprintf(namebuf, "/dev/midi%2.2d", i);
686 fd = open(namebuf, O_WRONLY | O_NDELAY);
687 if (fd >= 0)
688 {
689 close(fd);
690 continue;
691 }
692 sprintf(namebuf, "/dev/midi%d", i);
693 fd = open(namebuf, O_WRONLY | O_NDELAY);
694 if (fd >= 0)
695 {
696 close(fd);
697 continue;
698 }
699 break;
700 }
701}
702
703void midi_getdevs(char *indevlist, int *nindevs,
704 char *outdevlist, int *noutdevs, int maxndev, int devdescsize)
705{
706 int i, ndev;
707 if ((ndev = oss_nmidiindevs) > maxndev)
708 ndev = maxndev;
709 for (i = 0; i < ndev; i++)
710 sprintf(indevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
711 *nindevs = ndev;
712
713 if ((ndev = oss_nmidioutdevs) > maxndev)
714 ndev = maxndev;
715 for (i = 0; i < ndev; i++)
716 sprintf(outdevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
717 *noutdevs = ndev;
718}
diff --git a/apps/plugins/pdbox/PDa/src/s_midi_pm.c b/apps/plugins/pdbox/PDa/src/s_midi_pm.c
new file mode 100644
index 0000000000..b167175396
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_midi_pm.c
@@ -0,0 +1,332 @@
1/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
2* Winfried Ritsch, Karl MacMillan, and others.
3* For information on usage and redistribution, and for a DISCLAIMER OF ALL
4* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5
6 this file calls portmidi to do MIDI I/O for MSW and Mac OSX.
7
8*/
9
10#include "m_pd.h"
11#include "s_stuff.h"
12#include <stdio.h>
13#ifdef UNIX
14#include <unistd.h>
15#include <sys/time.h>
16#include <sys/resource.h>
17#endif
18#include <stdlib.h>
19#include <string.h>
20#include <errno.h>
21#include "portaudio.h"
22#include "portmidi.h"
23#include "porttime.h"
24#include "pminternal.h"
25
26static PmStream *mac_midiindevlist[MAXMIDIINDEV];
27static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV];
28static int mac_nmidiindev;
29static int mac_nmidioutdev;
30
31void sys_open_midi(int nmidiin, int *midiinvec,
32 int nmidiout, int *midioutvec)
33{
34 int i = 0;
35 int n = 0;
36 PmError err;
37
38 Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
39 mac_nmidiindev = 0;
40
41 /* protect the unwary from having MIDI inputs open; they're
42 bad news if you close Pd's terminal window. see sys_nmidiin
43 in s_main.c too. */
44#ifdef MSW
45 if (nmidiin)
46 {
47 post(
48 "midi input enabled; warning, don't close the DOS window directly!");
49 }
50 else post("not using MIDI input (use 'pd -midiindev 1' to override)");
51#endif
52
53 for (i = 0; i < nmidiin; i++)
54 {
55 if (midiinvec[i] == DEFMIDIDEV)
56 midiinvec[i] = Pm_GetDefaultInputDeviceID();
57 err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev], midiinvec[i],
58 NULL, 100, NULL, NULL, NULL);
59 if (err)
60 post("could not open midi input device number %d: %s",
61 midiinvec[i], Pm_GetErrorText(err));
62 else
63 {
64 if (sys_verbose)
65 post("Midi Input opened.\n");
66 mac_nmidiindev++;
67 }
68 }
69
70 mac_nmidioutdev = 0;
71 for (i = 0; i < nmidiout; i++)
72 {
73 if (midioutvec[i] == DEFMIDIDEV)
74 midioutvec[i] = Pm_GetDefaultOutputDeviceID();
75 err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev], midioutvec[i],
76 NULL, 0, NULL, NULL, 0);
77 if (err)
78 post("could not open midi output device number %d: %s",
79 midioutvec[i], Pm_GetErrorText(err));
80 else
81 {
82 if (sys_verbose)
83 post("Midi Output opened.\n");
84 mac_nmidioutdev++;
85 }
86 }
87}
88
89void sys_close_midi( void)
90{
91 int i;
92 for (i = 0; i < mac_nmidiindev; i++)
93 Pm_Close(mac_midiindevlist[mac_nmidiindev]);
94 mac_nmidiindev = 0;
95 for (i = 0; i < mac_nmidioutdev; i++)
96 Pm_Close(mac_midioutdevlist[mac_nmidioutdev]);
97 mac_nmidioutdev = 0;
98}
99
100void sys_putmidimess(int portno, int a, int b, int c)
101{
102 PmEvent buffer;
103 fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev);
104 if (portno >= 0 && portno < mac_nmidioutdev)
105 {
106 buffer.message = Pm_Message(a, b, c);
107 buffer.timestamp = 0;
108 fprintf(stderr, "put msg\n");
109 Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
110 }
111}
112
113void sys_putmidibyte(int portno, int byte)
114{
115 post("sorry, no byte-by-byte MIDI output implemented in MAC OSX");
116}
117
118void sys_poll_midi(void)
119{
120 int i, nmess;
121 PmEvent buffer;
122 for (i = 0; i < mac_nmidiindev; i++)
123 {
124 int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1);
125 if (nmess > 0)
126 {
127 int status = Pm_MessageStatus(buffer.message);
128 int data1 = Pm_MessageData1(buffer.message);
129 int data2 = Pm_MessageData2(buffer.message);
130 int msgtype = (status >> 4) - 8;
131 switch (msgtype)
132 {
133 case 0:
134 case 1:
135 case 2:
136 case 3:
137 case 6:
138 sys_midibytein(i, status);
139 sys_midibytein(i, data1);
140 sys_midibytein(i, data2);
141 break;
142 case 4:
143 case 5:
144 sys_midibytein(i, status);
145 sys_midibytein(i, data1);
146 break;
147 case 7:
148 sys_midibytein(i, status);
149 break;
150 }
151 }
152 }
153}
154
155void sys_listmididevs(void) /* lifted from pa_devs.c in portaudio */
156{
157 int i,j;
158 for (i = 0; i < Pm_CountDevices(); i++)
159 {
160 const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
161 printf("%d: %s, %s", i, info->interf, info->name);
162 if (info->input) printf(" (input)");
163 if (info->output) printf(" (output)");
164 printf("\n");
165 }
166}
167/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
168* Winfried Ritsch, Karl MacMillan, and others.
169* For information on usage and redistribution, and for a DISCLAIMER OF ALL
170* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
171
172 this file calls portmidi to do MIDI I/O for MSW and Mac OSX.
173
174*/
175
176#include "m_pd.h"
177#include "s_stuff.h"
178#include <stdio.h>
179#ifdef UNIX
180#include <unistd.h>
181#include <sys/time.h>
182#include <sys/resource.h>
183#endif
184#include <stdlib.h>
185#include <string.h>
186#include <errno.h>
187#include "portaudio.h"
188#include "portmidi.h"
189#include "porttime.h"
190#include "pminternal.h"
191
192static PmStream *mac_midiindevlist[MAXMIDIINDEV];
193static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV];
194static int mac_nmidiindev;
195static int mac_nmidioutdev;
196
197void sys_open_midi(int nmidiin, int *midiinvec,
198 int nmidiout, int *midioutvec)
199{
200 int i = 0;
201 int n = 0;
202 PmError err;
203
204 Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
205 mac_nmidiindev = 0;
206
207 /* protect the unwary from having MIDI inputs open; they're
208 bad news if you close Pd's terminal window. see sys_nmidiin
209 in s_main.c too. */
210#ifdef MSW
211 if (nmidiin)
212 {
213 post(
214 "midi input enabled; warning, don't close the DOS window directly!");
215 }
216 else post("not using MIDI input (use 'pd -midiindev 1' to override)");
217#endif
218
219 for (i = 0; i < nmidiin; i++)
220 {
221 if (midiinvec[i] == DEFMIDIDEV)
222 midiinvec[i] = Pm_GetDefaultInputDeviceID();
223 err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev], midiinvec[i],
224 NULL, 100, NULL, NULL, NULL);
225 if (err)
226 post("could not open midi input device number %d: %s",
227 midiinvec[i], Pm_GetErrorText(err));
228 else
229 {
230 if (sys_verbose)
231 post("Midi Input opened.\n");
232 mac_nmidiindev++;
233 }
234 }
235
236 mac_nmidioutdev = 0;
237 for (i = 0; i < nmidiout; i++)
238 {
239 if (midioutvec[i] == DEFMIDIDEV)
240 midioutvec[i] = Pm_GetDefaultOutputDeviceID();
241 err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev], midioutvec[i],
242 NULL, 0, NULL, NULL, 0);
243 if (err)
244 post("could not open midi output device number %d: %s",
245 midioutvec[i], Pm_GetErrorText(err));
246 else
247 {
248 if (sys_verbose)
249 post("Midi Output opened.\n");
250 mac_nmidioutdev++;
251 }
252 }
253}
254
255void sys_close_midi( void)
256{
257 int i;
258 for (i = 0; i < mac_nmidiindev; i++)
259 Pm_Close(mac_midiindevlist[mac_nmidiindev]);
260 mac_nmidiindev = 0;
261 for (i = 0; i < mac_nmidioutdev; i++)
262 Pm_Close(mac_midioutdevlist[mac_nmidioutdev]);
263 mac_nmidioutdev = 0;
264}
265
266void sys_putmidimess(int portno, int a, int b, int c)
267{
268 PmEvent buffer;
269 fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev);
270 if (portno >= 0 && portno < mac_nmidioutdev)
271 {
272 buffer.message = Pm_Message(a, b, c);
273 buffer.timestamp = 0;
274 fprintf(stderr, "put msg\n");
275 Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
276 }
277}
278
279void sys_putmidibyte(int portno, int byte)
280{
281 post("sorry, no byte-by-byte MIDI output implemented in MAC OSX");
282}
283
284void sys_poll_midi(void)
285{
286 int i, nmess;
287 PmEvent buffer;
288 for (i = 0; i < mac_nmidiindev; i++)
289 {
290 int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1);
291 if (nmess > 0)
292 {
293 int status = Pm_MessageStatus(buffer.message);
294 int data1 = Pm_MessageData1(buffer.message);
295 int data2 = Pm_MessageData2(buffer.message);
296 int msgtype = (status >> 4) - 8;
297 switch (msgtype)
298 {
299 case 0:
300 case 1:
301 case 2:
302 case 3:
303 case 6:
304 sys_midibytein(i, status);
305 sys_midibytein(i, data1);
306 sys_midibytein(i, data2);
307 break;
308 case 4:
309 case 5:
310 sys_midibytein(i, status);
311 sys_midibytein(i, data1);
312 break;
313 case 7:
314 sys_midibytein(i, status);
315 break;
316 }
317 }
318 }
319}
320
321void sys_listmididevs(void) /* lifted from pa_devs.c in portaudio */
322{
323 int i,j;
324 for (i = 0; i < Pm_CountDevices(); i++)
325 {
326 const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
327 printf("%d: %s, %s", i, info->interf, info->name);
328 if (info->input) printf(" (input)");
329 if (info->output) printf(" (output)");
330 printf("\n");
331 }
332}
diff --git a/apps/plugins/pdbox/PDa/src/s_midi_sgi.c b/apps/plugins/pdbox/PDa/src/s_midi_sgi.c
new file mode 100644
index 0000000000..cfe8efb0c8
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_midi_sgi.c
@@ -0,0 +1,376 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include "s_stuff.h"
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <string.h>
10#ifdef HAVE_BSTRING_H
11#include <bstring.h>
12#endif
13#include <sys/types.h>
14#include <sys/time.h>
15
16#include <dmedia/audio.h>
17#include <sys/fpu.h>
18#include <dmedia/midi.h>
19int mdInit(void); /* prototype was messed up in midi.h */
20/* #include "sys/select.h" */
21
22
23 /*
24 set the special "flush zero" but (FS, bit 24) in the
25 Control Status Register of the FPU of R4k and beyond
26 so that the result of any underflowing operation will
27 be clamped to zero, and no exception of any kind will
28 be generated on the CPU.
29
30 thanks to cpirazzi@cp.esd.sgi.com (Chris Pirazzi).
31 */
32
33static void sgi_flush_all_underflows_to_zero(void)
34{
35 union fpc_csr f;
36 f.fc_word = get_fpc_csr();
37 f.fc_struct.flush = 1;
38 set_fpc_csr(f.fc_word);
39}
40
41#define NPORT 2
42
43static MDport sgi_inport[NPORT];
44static MDport sgi_outport[NPORT];
45
46void sgi_open_midi(int midiin, int midiout)
47{
48 int i;
49 int sgi_nports = mdInit();
50 if (sgi_nports < 0) sgi_nports = 0;
51 else if (sgi_nports > NPORT) sgi_nports = NPORT;
52 if (sys_verbose)
53 {
54 if (!sgi_nports)
55 {
56 post("no serial ports are configured for MIDI;");
57 post("if you want to use MIDI, try exiting Pd, typing");
58 post("'startmidi -d /dev/ttyd2' to a shell, and restarting Pd.");
59 }
60 else if (sgi_nports == 1)
61 post("Found one MIDI port on %s", mdGetName(0));
62 else if (sgi_nports == 2)
63 post("Found MIDI ports on %s and %s",
64 mdGetName(0), mdGetName(1));
65 }
66 if (midiin)
67 {
68 for (i = 0; i < sgi_nports; i++)
69 {
70 if (!(sgi_inport[i] = mdOpenInPort(mdGetName(i))))
71 error("MIDI input port %d: open failed", i+1);;
72 }
73 }
74 if (midiout)
75 {
76 for (i = 0; i < sgi_nports; i++)
77 {
78 if (!(sgi_outport[i] = mdOpenOutPort(mdGetName(i))))
79 error("MIDI output port %d: open failed", i+1);;
80 }
81 }
82 return;
83}
84
85void sys_putmidimess(int portno, int a, int b, int c)
86{
87 MDevent mdv;
88 if (portno >= NPORT || portno < 0 || !sgi_outport[portno]) return;
89 mdv.msg[0] = a;
90 mdv.msg[1] = b;
91 mdv.msg[2] = c;
92 mdv.msg[3] = 0;
93 mdv.sysexmsg = 0;
94 mdv.stamp = 0;
95 mdv.msglen = 0;
96 if (mdSend(sgi_outport[portno], &mdv, 1) < 0)
97 error("MIDI output error\n");
98 post("msg out %d %d %d", a, b, c);
99}
100
101void sys_putmidibyte(int portno, int foo)
102{
103 error("MIDI raw byte output not available on SGI");
104}
105
106void inmidi_noteon(int portno, int channel, int pitch, int velo);
107void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
108void inmidi_programchange(int portno, int channel, int value);
109void inmidi_pitchbend(int portno, int channel, int value);
110void inmidi_aftertouch(int portno, int channel, int value);
111void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
112
113void sys_poll_midi(void)
114{
115 int i;
116 MDport *mp;
117 for (i = 0, mp = sgi_inport; i < NPORT; i++, mp++)
118 {
119 int ret, status, b1, b2, nfds;
120 MDevent mdv;
121 fd_set inports;
122 struct timeval timeout;
123 timeout.tv_sec = 0;
124 timeout.tv_usec = 0;
125 if (!*mp) continue;
126 FD_ZERO(&inports);
127 FD_SET(mdGetFd(*mp), &inports);
128
129 if (select(mdGetFd(*mp)+1 , &inports, 0, 0, &timeout) < 0)
130 perror("midi select");
131 if (FD_ISSET(mdGetFd(*mp),&inports))
132 {
133 if (mdReceive(*mp, &mdv, 1) < 0)
134 error("failure receiving message\n");
135 else if (mdv.msg[0] == MD_SYSEX) mdFree(mdv.sysexmsg);
136
137 else
138 {
139 int status = mdv.msg[0];
140 int channel = (status & 0xf) + 1;
141 int b1 = mdv.msg[1];
142 int b2 = mdv.msg[2];
143 switch(status & 0xf0)
144 {
145 case MD_NOTEOFF:
146 inmidi_noteon(i, channel, b1, 0);
147 break;
148 case MD_NOTEON:
149 inmidi_noteon(i, channel, b1, b2);
150 break;
151 case MD_POLYKEYPRESSURE:
152 inmidi_polyaftertouch(i, channel, b1, b2);
153 break;
154 case MD_CONTROLCHANGE:
155 inmidi_controlchange(i, channel, b1, b2);
156 break;
157 case MD_PITCHBENDCHANGE:
158 inmidi_pitchbend(i, channel, ((b2 << 7) + b1));
159 break;
160 case MD_PROGRAMCHANGE:
161 inmidi_programchange(i, channel, b1);
162 break;
163 case MD_CHANNELPRESSURE:
164 inmidi_aftertouch(i, channel, b1);
165 break;
166 }
167 }
168 }
169 }
170}
171
172void sys_open_midi(int nmidiin, int *midiinvec,
173 int nmidiout, int *midioutvec)
174{
175 sgi_open_midi(nmidiin!=0, nmidiout!=0);
176}
177
178
179void sys_close_midi( void)
180{
181 /* ??? */
182}
183
184void sys_set_priority(int foo)
185{
186 fprintf(stderr,
187 "warning: priority boosting in IRIX not implemented yet\n");
188}
189/* Copyright (c) 1997-1999 Miller Puckette.
190* For information on usage and redistribution, and for a DISCLAIMER OF ALL
191* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
192
193#include "s_stuff.h"
194#include <stdio.h>
195#include <stdlib.h>
196#include <unistd.h>
197#include <string.h>
198#ifdef HAVE_BSTRING_H
199#include <bstring.h>
200#endif
201#include <sys/types.h>
202#include <sys/time.h>
203
204#include <dmedia/audio.h>
205#include <sys/fpu.h>
206#include <dmedia/midi.h>
207int mdInit(void); /* prototype was messed up in midi.h */
208/* #include "sys/select.h" */
209
210
211 /*
212 set the special "flush zero" but (FS, bit 24) in the
213 Control Status Register of the FPU of R4k and beyond
214 so that the result of any underflowing operation will
215 be clamped to zero, and no exception of any kind will
216 be generated on the CPU.
217
218 thanks to cpirazzi@cp.esd.sgi.com (Chris Pirazzi).
219 */
220
221static void sgi_flush_all_underflows_to_zero(void)
222{
223 union fpc_csr f;
224 f.fc_word = get_fpc_csr();
225 f.fc_struct.flush = 1;
226 set_fpc_csr(f.fc_word);
227}
228
229#define NPORT 2
230
231static MDport sgi_inport[NPORT];
232static MDport sgi_outport[NPORT];
233
234void sgi_open_midi(int midiin, int midiout)
235{
236 int i;
237 int sgi_nports = mdInit();
238 if (sgi_nports < 0) sgi_nports = 0;
239 else if (sgi_nports > NPORT) sgi_nports = NPORT;
240 if (sys_verbose)
241 {
242 if (!sgi_nports)
243 {
244 post("no serial ports are configured for MIDI;");
245 post("if you want to use MIDI, try exiting Pd, typing");
246 post("'startmidi -d /dev/ttyd2' to a shell, and restarting Pd.");
247 }
248 else if (sgi_nports == 1)
249 post("Found one MIDI port on %s", mdGetName(0));
250 else if (sgi_nports == 2)
251 post("Found MIDI ports on %s and %s",
252 mdGetName(0), mdGetName(1));
253 }
254 if (midiin)
255 {
256 for (i = 0; i < sgi_nports; i++)
257 {
258 if (!(sgi_inport[i] = mdOpenInPort(mdGetName(i))))
259 error("MIDI input port %d: open failed", i+1);;
260 }
261 }
262 if (midiout)
263 {
264 for (i = 0; i < sgi_nports; i++)
265 {
266 if (!(sgi_outport[i] = mdOpenOutPort(mdGetName(i))))
267 error("MIDI output port %d: open failed", i+1);;
268 }
269 }
270 return;
271}
272
273void sys_putmidimess(int portno, int a, int b, int c)
274{
275 MDevent mdv;
276 if (portno >= NPORT || portno < 0 || !sgi_outport[portno]) return;
277 mdv.msg[0] = a;
278 mdv.msg[1] = b;
279 mdv.msg[2] = c;
280 mdv.msg[3] = 0;
281 mdv.sysexmsg = 0;
282 mdv.stamp = 0;
283 mdv.msglen = 0;
284 if (mdSend(sgi_outport[portno], &mdv, 1) < 0)
285 error("MIDI output error\n");
286 post("msg out %d %d %d", a, b, c);
287}
288
289void sys_putmidibyte(int portno, int foo)
290{
291 error("MIDI raw byte output not available on SGI");
292}
293
294void inmidi_noteon(int portno, int channel, int pitch, int velo);
295void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
296void inmidi_programchange(int portno, int channel, int value);
297void inmidi_pitchbend(int portno, int channel, int value);
298void inmidi_aftertouch(int portno, int channel, int value);
299void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
300
301void sys_poll_midi(void)
302{
303 int i;
304 MDport *mp;
305 for (i = 0, mp = sgi_inport; i < NPORT; i++, mp++)
306 {
307 int ret, status, b1, b2, nfds;
308 MDevent mdv;
309 fd_set inports;
310 struct timeval timeout;
311 timeout.tv_sec = 0;
312 timeout.tv_usec = 0;
313 if (!*mp) continue;
314 FD_ZERO(&inports);
315 FD_SET(mdGetFd(*mp), &inports);
316
317 if (select(mdGetFd(*mp)+1 , &inports, 0, 0, &timeout) < 0)
318 perror("midi select");
319 if (FD_ISSET(mdGetFd(*mp),&inports))
320 {
321 if (mdReceive(*mp, &mdv, 1) < 0)
322 error("failure receiving message\n");
323 else if (mdv.msg[0] == MD_SYSEX) mdFree(mdv.sysexmsg);
324
325 else
326 {
327 int status = mdv.msg[0];
328 int channel = (status & 0xf) + 1;
329 int b1 = mdv.msg[1];
330 int b2 = mdv.msg[2];
331 switch(status & 0xf0)
332 {
333 case MD_NOTEOFF:
334 inmidi_noteon(i, channel, b1, 0);
335 break;
336 case MD_NOTEON:
337 inmidi_noteon(i, channel, b1, b2);
338 break;
339 case MD_POLYKEYPRESSURE:
340 inmidi_polyaftertouch(i, channel, b1, b2);
341 break;
342 case MD_CONTROLCHANGE:
343 inmidi_controlchange(i, channel, b1, b2);
344 break;
345 case MD_PITCHBENDCHANGE:
346 inmidi_pitchbend(i, channel, ((b2 << 7) + b1));
347 break;
348 case MD_PROGRAMCHANGE:
349 inmidi_programchange(i, channel, b1);
350 break;
351 case MD_CHANNELPRESSURE:
352 inmidi_aftertouch(i, channel, b1);
353 break;
354 }
355 }
356 }
357 }
358}
359
360void sys_open_midi(int nmidiin, int *midiinvec,
361 int nmidiout, int *midioutvec)
362{
363 sgi_open_midi(nmidiin!=0, nmidiout!=0);
364}
365
366
367void sys_close_midi( void)
368{
369 /* ??? */
370}
371
372void sys_set_priority(int foo)
373{
374 fprintf(stderr,
375 "warning: priority boosting in IRIX not implemented yet\n");
376}
diff --git a/apps/plugins/pdbox/PDa/src/s_path.c b/apps/plugins/pdbox/PDa/src/s_path.c
new file mode 100644
index 0000000000..26b8dfda99
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_path.c
@@ -0,0 +1,820 @@
1/* Copyright (c) 1999 Guenter Geiger and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/*
6 * This file implements the loader for linux, which includes
7 * a little bit of path handling.
8 *
9 * Generalized by MSP to provide an open_via_path function
10 * and lists of files for all purposes.
11 */
12
13/* #define DEBUG(x) x */
14#define DEBUG(x)
15void readsf_banana( void); /* debugging */
16
17#include <stdlib.h>
18#ifdef UNIX
19#include <unistd.h>
20#include <sys/stat.h>
21#endif
22#ifdef MSW
23#include <io.h>
24#endif
25
26#include <string.h>
27#include "m_pd.h"
28#include "m_imp.h"
29#include "s_stuff.h"
30#include <stdio.h>
31#include <fcntl.h>
32
33static t_namelist *pd_path, *pd_helppath;
34
35/* Utility functions */
36
37/* copy until delimiter and return position after delimiter in string */
38/* if it was the last substring, return NULL */
39
40static const char* strtokcpy(char *to, const char *from, int delim)
41{
42 int size = 0;
43
44 while (from[size] != (char)delim && from[size] != '\0')
45 size++;
46
47 strncpy(to,from,size);
48 to[size] = '\0';
49 if (from[size] == '\0') return NULL;
50 if (size) return from+size+1;
51 else return NULL;
52}
53
54/* add a colon-separated list of names to a namelist */
55
56#ifdef MSW
57#define SEPARATOR ';'
58#else
59#define SEPARATOR ':'
60#endif
61
62static t_namelist *namelist_doappend(t_namelist *listwas, const char *s)
63{
64 t_namelist *nl = listwas, *rtn = listwas, *nl2;
65 nl2 = (t_namelist *)(getbytes(sizeof(*nl)));
66 nl2->nl_next = 0;
67 nl2->nl_string = (char *)getbytes(strlen(s) + 1);
68 strcpy(nl2->nl_string, s);
69 sys_unbashfilename(nl2->nl_string, nl2->nl_string);
70 if (!nl)
71 nl = rtn = nl2;
72 else
73 {
74 while (nl->nl_next)
75 nl = nl->nl_next;
76 nl->nl_next = nl2;
77 }
78 return (rtn);
79
80}
81
82t_namelist *namelist_append(t_namelist *listwas, const char *s)
83{
84 const char *npos;
85 char temp[MAXPDSTRING];
86 t_namelist *nl = listwas, *rtn = listwas;
87
88 npos = s;
89 do
90 {
91 npos = strtokcpy(temp, npos, SEPARATOR);
92 if (! *temp) continue;
93 nl = namelist_doappend(nl, temp);
94 }
95 while (npos);
96 return (nl);
97}
98
99void namelist_free(t_namelist *listwas)
100{
101 t_namelist *nl, *nl2;
102 for (nl = listwas; nl; nl = nl2)
103 {
104 nl2 = nl->nl_next;
105 t_freebytes(nl->nl_string, strlen(nl->nl_string) + 1);
106 t_freebytes(nl, sizeof(*nl));
107 }
108}
109
110void sys_addpath(const char *p)
111{
112 pd_path = namelist_append(pd_path, p);
113}
114
115void sys_addhelppath(const char *p)
116{
117 pd_helppath = namelist_append(pd_helppath, p);
118}
119
120#ifdef MSW
121#define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
122#else
123#define MSWOPENFLAG(bin) 0
124#endif
125
126/* search for a file in a specified directory, then along the globally
127defined search path, using ext as filename extension. Exception:
128if the 'name' starts with a slash or a letter, colon, and slash in MSW,
129there is no search and instead we just try to open the file literally. The
130fd is returned, the directory ends up in the "dirresult" which must be at
131least "size" bytes. "nameresult" is set to point to the filename, which
132ends up in the same buffer as dirresult. */
133
134int open_via_path(const char *dir, const char *name, const char* ext,
135 char *dirresult, char **nameresult, unsigned int size, int bin)
136{
137 t_namelist *nl, thislist;
138 int fd = -1;
139 char listbuf[MAXPDSTRING];
140
141 if (name[0] == '/'
142#ifdef MSW
143 || (name[1] == ':' && name[2] == '/')
144#endif
145 )
146 {
147 thislist.nl_next = 0;
148 thislist.nl_string = listbuf;
149 listbuf[0] = 0;
150 }
151 else
152 {
153 thislist.nl_string = listbuf;
154 thislist.nl_next = pd_path;
155 strncpy(listbuf, dir, MAXPDSTRING);
156 listbuf[MAXPDSTRING-1] = 0;
157 sys_unbashfilename(listbuf, listbuf);
158 }
159
160 for (nl = &thislist; nl; nl = nl->nl_next)
161 {
162 if (strlen(nl->nl_string) + strlen(name) + strlen(ext) + 4 >
163 size)
164 continue;
165 strcpy(dirresult, nl->nl_string);
166 if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
167 strcat(dirresult, "/");
168 strcat(dirresult, name);
169 strcat(dirresult, ext);
170 sys_bashfilename(dirresult, dirresult);
171
172 DEBUG(post("looking for %s",dirresult));
173 /* see if we can open the file for reading */
174 if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(bin))) >= 0)
175 {
176 /* in UNIX, further check that it's not a directory */
177#ifdef UNIX
178 struct stat statbuf;
179 int ok = ((fstat(fd, &statbuf) >= 0) &&
180 !S_ISDIR(statbuf.st_mode));
181 if (!ok)
182 {
183 if (sys_verbose) post("tried %s; stat failed or directory",
184 dirresult);
185 close (fd);
186 fd = -1;
187 }
188 else
189#endif
190 {
191 char *slash;
192 if (sys_verbose) post("tried %s and succeeded", dirresult);
193 sys_unbashfilename(dirresult, dirresult);
194 slash = strrchr(dirresult, '/');
195 if (slash)
196 {
197 *slash = 0;
198 *nameresult = slash + 1;
199 }
200 else *nameresult = dirresult;
201
202 return (fd);
203 }
204 }
205 else
206 {
207 if (sys_verbose) post("tried %s and failed", dirresult);
208 }
209 }
210 *dirresult = 0;
211 *nameresult = dirresult;
212 return (-1);
213}
214
215static int do_open_via_helppath(const char *realname, t_namelist *listp)
216{
217 t_namelist *nl;
218 int fd = -1;
219 char dirresult[MAXPDSTRING], realdir[MAXPDSTRING];
220 for (nl = listp; nl; nl = nl->nl_next)
221 {
222 strcpy(dirresult, nl->nl_string);
223 strcpy(realdir, dirresult);
224 if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
225 strcat(dirresult, "/");
226 strcat(dirresult, realname);
227 sys_bashfilename(dirresult, dirresult);
228
229 DEBUG(post("looking for %s",dirresult));
230 /* see if we can open the file for reading */
231 if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(0))) >= 0)
232 {
233 /* in UNIX, further check that it's not a directory */
234#ifdef UNIX
235 struct stat statbuf;
236 int ok = ((fstat(fd, &statbuf) >= 0) &&
237 !S_ISDIR(statbuf.st_mode));
238 if (!ok)
239 {
240 if (sys_verbose) post("tried %s; stat failed or directory",
241 dirresult);
242 close (fd);
243 fd = -1;
244 }
245 else
246#endif
247 {
248 char *slash;
249 if (sys_verbose) post("tried %s and succeeded", dirresult);
250 sys_unbashfilename(dirresult, dirresult);
251 close (fd);
252 glob_evalfile(0, gensym((char*)realname), gensym(realdir));
253 return (1);
254 }
255 }
256 else
257 {
258 if (sys_verbose) post("tried %s and failed", dirresult);
259 }
260 }
261 return (0);
262}
263
264 /* LATER make this use open_via_path above. We expect the ".pd"
265 suffix here, even though we have to tear it back off for one of the
266 search attempts. */
267void open_via_helppath(const char *name, const char *dir)
268{
269 t_namelist *nl, thislist, *listp;
270 int fd = -1;
271 char dirbuf2[MAXPDSTRING], realname[MAXPDSTRING];
272
273 /* if directory is supplied, put it at head of search list. */
274 if (*dir)
275 {
276 thislist.nl_string = dirbuf2;
277 thislist.nl_next = pd_helppath;
278 strncpy(dirbuf2, dir, MAXPDSTRING);
279 dirbuf2[MAXPDSTRING-1] = 0;
280 sys_unbashfilename(dirbuf2, dirbuf2);
281 listp = &thislist;
282 }
283 else listp = pd_helppath;
284 /* 1. "objectname-help.pd" */
285 strncpy(realname, name, MAXPDSTRING-10);
286 realname[MAXPDSTRING-10] = 0;
287 if (strlen(realname) > 3 && !strcmp(realname+strlen(realname)-3, ".pd"))
288 realname[strlen(realname)-3] = 0;
289 strcat(realname, "-help.pd");
290 if (do_open_via_helppath(realname, listp))
291 return;
292 /* 2. "help-objectname.pd" */
293 strcpy(realname, "help-");
294 strncat(realname, name, MAXPDSTRING-10);
295 realname[MAXPDSTRING-1] = 0;
296 if (do_open_via_helppath(realname, listp))
297 return;
298 /* 3. "objectname.pd" */
299 if (do_open_via_helppath(name, listp))
300 return;
301 post("sorry, couldn't find help patch for \"%s\"", name);
302 return;
303}
304
305
306/* Startup file reading for linux and MACOSX. This should be replaced by
307a better mechanism. This should be integrated with the audio, MIDI, and
308path dialog system. */
309
310#ifdef UNIX
311
312#define STARTUPNAME ".pdrc"
313#define NUMARGS 1000
314
315int sys_argparse(int argc, char **argv);
316
317int sys_rcfile(void)
318{
319 FILE* file;
320 int i;
321 int k;
322 int rcargc;
323 char* rcargv[NUMARGS];
324 char* buffer;
325 char fname[MAXPDSTRING], buf[1000], *home = getenv("HOME");
326
327 /* parse a startup file */
328
329 *fname = '\0';
330
331 strncat(fname, home? home : ".", MAXPDSTRING-10);
332 strcat(fname, "/");
333
334 strcat(fname, STARTUPNAME);
335
336 if (!(file = fopen(fname, "r")))
337 return 1;
338
339 post("reading startup file: %s", fname);
340
341 rcargv[0] = "."; /* this no longer matters to sys_argparse() */
342
343 for (i = 1; i < NUMARGS-1; i++)
344 {
345 if (fscanf(file, "%999s", buf) < 0)
346 break;
347 buf[1000] = 0;
348 if (!(rcargv[i] = malloc(strlen(buf) + 1)))
349 return (1);
350 strcpy(rcargv[i], buf);
351 }
352 if (i >= NUMARGS-1)
353 fprintf(stderr, "startup file too long; extra args dropped\n");
354 rcargv[i] = 0;
355
356 rcargc = i;
357
358 /* parse the options */
359
360 fclose(file);
361 if (sys_verbose)
362 {
363 if (rcargv)
364 {
365 post("startup args from RC file:");
366 for (i = 1; i < rcargc; i++)
367 post("%s", rcargv[i]);
368 }
369 else post("no RC file arguments found");
370 }
371 if (sys_argparse(rcargc, rcargv))
372 {
373 post("error parsing RC arguments");
374 return (1);
375 }
376 return (0);
377}
378#endif /* UNIX */
379
380 /* start an audio settings dialog window */
381void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform)
382{
383 char buf[MAXPDSTRING];
384 int i;
385 t_namelist *nl;
386
387 for (nl = pd_path, i = 0; nl && i < 10; nl = nl->nl_next, i++)
388 sys_vgui("pd_set pd_path%d \"%s\"\n", i, nl->nl_string);
389 for (; i < 10; i++)
390 sys_vgui("pd_set pd_path%d \"\"\n", i);
391
392 sprintf(buf, "pdtk_path_dialog %%s\n");
393 gfxstub_new(&glob_pdobject, glob_start_path_dialog, buf);
394}
395
396 /* new values from dialog window */
397void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
398{
399 int i;
400 namelist_free(pd_path);
401 pd_path = 0;
402 for (i = 0; i < argc; i++)
403 {
404 t_symbol *s = atom_getsymbolarg(i, argc, argv);
405 if (*s->s_name)
406 sys_addpath(s->s_name);
407 }
408}
409
410
411/* Copyright (c) 1999 Guenter Geiger and others.
412* For information on usage and redistribution, and for a DISCLAIMER OF ALL
413* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
414
415/*
416 * This file implements the loader for linux, which includes
417 * a little bit of path handling.
418 *
419 * Generalized by MSP to provide an open_via_path function
420 * and lists of files for all purposes.
421 */
422
423/* #define DEBUG(x) x */
424#define DEBUG(x)
425void readsf_banana( void); /* debugging */
426
427#include <stdlib.h>
428#ifdef UNIX
429#include <unistd.h>
430#include <sys/stat.h>
431#endif
432#ifdef MSW
433#include <io.h>
434#endif
435
436#include <string.h>
437#include "m_pd.h"
438#include "m_imp.h"
439#include "s_stuff.h"
440#include <stdio.h>
441#include <fcntl.h>
442
443static t_namelist *pd_path, *pd_helppath;
444
445/* Utility functions */
446
447/* copy until delimiter and return position after delimiter in string */
448/* if it was the last substring, return NULL */
449
450static const char* strtokcpy(char *to, const char *from, int delim)
451{
452 int size = 0;
453
454 while (from[size] != (char)delim && from[size] != '\0')
455 size++;
456
457 strncpy(to,from,size);
458 to[size] = '\0';
459 if (from[size] == '\0') return NULL;
460 if (size) return from+size+1;
461 else return NULL;
462}
463
464/* add a colon-separated list of names to a namelist */
465
466#ifdef MSW
467#define SEPARATOR ';'
468#else
469#define SEPARATOR ':'
470#endif
471
472static t_namelist *namelist_doappend(t_namelist *listwas, const char *s)
473{
474 t_namelist *nl = listwas, *rtn = listwas, *nl2;
475 nl2 = (t_namelist *)(getbytes(sizeof(*nl)));
476 nl2->nl_next = 0;
477 nl2->nl_string = (char *)getbytes(strlen(s) + 1);
478 strcpy(nl2->nl_string, s);
479 sys_unbashfilename(nl2->nl_string, nl2->nl_string);
480 if (!nl)
481 nl = rtn = nl2;
482 else
483 {
484 while (nl->nl_next)
485 nl = nl->nl_next;
486 nl->nl_next = nl2;
487 }
488 return (rtn);
489
490}
491
492t_namelist *namelist_append(t_namelist *listwas, const char *s)
493{
494 const char *npos;
495 char temp[MAXPDSTRING];
496 t_namelist *nl = listwas, *rtn = listwas;
497
498 npos = s;
499 do
500 {
501 npos = strtokcpy(temp, npos, SEPARATOR);
502 if (! *temp) continue;
503 nl = namelist_doappend(nl, temp);
504 }
505 while (npos);
506 return (nl);
507}
508
509void namelist_free(t_namelist *listwas)
510{
511 t_namelist *nl, *nl2;
512 for (nl = listwas; nl; nl = nl2)
513 {
514 nl2 = nl->nl_next;
515 t_freebytes(nl->nl_string, strlen(nl->nl_string) + 1);
516 t_freebytes(nl, sizeof(*nl));
517 }
518}
519
520void sys_addpath(const char *p)
521{
522 pd_path = namelist_append(pd_path, p);
523}
524
525void sys_addhelppath(const char *p)
526{
527 pd_helppath = namelist_append(pd_helppath, p);
528}
529
530#ifdef MSW
531#define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
532#else
533#define MSWOPENFLAG(bin) 0
534#endif
535
536/* search for a file in a specified directory, then along the globally
537defined search path, using ext as filename extension. Exception:
538if the 'name' starts with a slash or a letter, colon, and slash in MSW,
539there is no search and instead we just try to open the file literally. The
540fd is returned, the directory ends up in the "dirresult" which must be at
541least "size" bytes. "nameresult" is set to point to the filename, which
542ends up in the same buffer as dirresult. */
543
544int open_via_path(const char *dir, const char *name, const char* ext,
545 char *dirresult, char **nameresult, unsigned int size, int bin)
546{
547 t_namelist *nl, thislist;
548 int fd = -1;
549 char listbuf[MAXPDSTRING];
550
551 if (name[0] == '/'
552#ifdef MSW
553 || (name[1] == ':' && name[2] == '/')
554#endif
555 )
556 {
557 thislist.nl_next = 0;
558 thislist.nl_string = listbuf;
559 listbuf[0] = 0;
560 }
561 else
562 {
563 thislist.nl_string = listbuf;
564 thislist.nl_next = pd_path;
565 strncpy(listbuf, dir, MAXPDSTRING);
566 listbuf[MAXPDSTRING-1] = 0;
567 sys_unbashfilename(listbuf, listbuf);
568 }
569
570 for (nl = &thislist; nl; nl = nl->nl_next)
571 {
572 if (strlen(nl->nl_string) + strlen(name) + strlen(ext) + 4 >
573 size)
574 continue;
575 strcpy(dirresult, nl->nl_string);
576 if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
577 strcat(dirresult, "/");
578 strcat(dirresult, name);
579 strcat(dirresult, ext);
580 sys_bashfilename(dirresult, dirresult);
581
582 DEBUG(post("looking for %s",dirresult));
583 /* see if we can open the file for reading */
584 if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(bin))) >= 0)
585 {
586 /* in UNIX, further check that it's not a directory */
587#ifdef UNIX
588 struct stat statbuf;
589 int ok = ((fstat(fd, &statbuf) >= 0) &&
590 !S_ISDIR(statbuf.st_mode));
591 if (!ok)
592 {
593 if (sys_verbose) post("tried %s; stat failed or directory",
594 dirresult);
595 close (fd);
596 fd = -1;
597 }
598 else
599#endif
600 {
601 char *slash;
602 if (sys_verbose) post("tried %s and succeeded", dirresult);
603 sys_unbashfilename(dirresult, dirresult);
604 slash = strrchr(dirresult, '/');
605 if (slash)
606 {
607 *slash = 0;
608 *nameresult = slash + 1;
609 }
610 else *nameresult = dirresult;
611
612 return (fd);
613 }
614 }
615 else
616 {
617 if (sys_verbose) post("tried %s and failed", dirresult);
618 }
619 }
620 *dirresult = 0;
621 *nameresult = dirresult;
622 return (-1);
623}
624
625static int do_open_via_helppath(const char *realname, t_namelist *listp)
626{
627 t_namelist *nl;
628 int fd = -1;
629 char dirresult[MAXPDSTRING], realdir[MAXPDSTRING];
630 for (nl = listp; nl; nl = nl->nl_next)
631 {
632 strcpy(dirresult, nl->nl_string);
633 strcpy(realdir, dirresult);
634 if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
635 strcat(dirresult, "/");
636 strcat(dirresult, realname);
637 sys_bashfilename(dirresult, dirresult);
638
639 DEBUG(post("looking for %s",dirresult));
640 /* see if we can open the file for reading */
641 if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(0))) >= 0)
642 {
643 /* in UNIX, further check that it's not a directory */
644#ifdef UNIX
645 struct stat statbuf;
646 int ok = ((fstat(fd, &statbuf) >= 0) &&
647 !S_ISDIR(statbuf.st_mode));
648 if (!ok)
649 {
650 if (sys_verbose) post("tried %s; stat failed or directory",
651 dirresult);
652 close (fd);
653 fd = -1;
654 }
655 else
656#endif
657 {
658 char *slash;
659 if (sys_verbose) post("tried %s and succeeded", dirresult);
660 sys_unbashfilename(dirresult, dirresult);
661 close (fd);
662 glob_evalfile(0, gensym((char*)realname), gensym(realdir));
663 return (1);
664 }
665 }
666 else
667 {
668 if (sys_verbose) post("tried %s and failed", dirresult);
669 }
670 }
671 return (0);
672}
673
674 /* LATER make this use open_via_path above. We expect the ".pd"
675 suffix here, even though we have to tear it back off for one of the
676 search attempts. */
677void open_via_helppath(const char *name, const char *dir)
678{
679 t_namelist *nl, thislist, *listp;
680 int fd = -1;
681 char dirbuf2[MAXPDSTRING], realname[MAXPDSTRING];
682
683 /* if directory is supplied, put it at head of search list. */
684 if (*dir)
685 {
686 thislist.nl_string = dirbuf2;
687 thislist.nl_next = pd_helppath;
688 strncpy(dirbuf2, dir, MAXPDSTRING);
689 dirbuf2[MAXPDSTRING-1] = 0;
690 sys_unbashfilename(dirbuf2, dirbuf2);
691 listp = &thislist;
692 }
693 else listp = pd_helppath;
694 /* 1. "objectname-help.pd" */
695 strncpy(realname, name, MAXPDSTRING-10);
696 realname[MAXPDSTRING-10] = 0;
697 if (strlen(realname) > 3 && !strcmp(realname+strlen(realname)-3, ".pd"))
698 realname[strlen(realname)-3] = 0;
699 strcat(realname, "-help.pd");
700 if (do_open_via_helppath(realname, listp))
701 return;
702 /* 2. "help-objectname.pd" */
703 strcpy(realname, "help-");
704 strncat(realname, name, MAXPDSTRING-10);
705 realname[MAXPDSTRING-1] = 0;
706 if (do_open_via_helppath(realname, listp))
707 return;
708 /* 3. "objectname.pd" */
709 if (do_open_via_helppath(name, listp))
710 return;
711 post("sorry, couldn't find help patch for \"%s\"", name);
712 return;
713}
714
715
716/* Startup file reading for linux and MACOSX. This should be replaced by
717a better mechanism. This should be integrated with the audio, MIDI, and
718path dialog system. */
719
720#ifdef UNIX
721
722#define STARTUPNAME ".pdrc"
723#define NUMARGS 1000
724
725int sys_argparse(int argc, char **argv);
726
727int sys_rcfile(void)
728{
729 FILE* file;
730 int i;
731 int k;
732 int rcargc;
733 char* rcargv[NUMARGS];
734 char* buffer;
735 char fname[MAXPDSTRING], buf[1000], *home = getenv("HOME");
736
737 /* parse a startup file */
738
739 *fname = '\0';
740
741 strncat(fname, home? home : ".", MAXPDSTRING-10);
742 strcat(fname, "/");
743
744 strcat(fname, STARTUPNAME);
745
746 if (!(file = fopen(fname, "r")))
747 return 1;
748
749 post("reading startup file: %s", fname);
750
751 rcargv[0] = "."; /* this no longer matters to sys_argparse() */
752
753 for (i = 1; i < NUMARGS-1; i++)
754 {
755 if (fscanf(file, "%999s", buf) < 0)
756 break;
757 buf[1000] = 0;
758 if (!(rcargv[i] = malloc(strlen(buf) + 1)))
759 return (1);
760 strcpy(rcargv[i], buf);
761 }
762 if (i >= NUMARGS-1)
763 fprintf(stderr, "startup file too long; extra args dropped\n");
764 rcargv[i] = 0;
765
766 rcargc = i;
767
768 /* parse the options */
769
770 fclose(file);
771 if (sys_verbose)
772 {
773 if (rcargv)
774 {
775 post("startup args from RC file:");
776 for (i = 1; i < rcargc; i++)
777 post("%s", rcargv[i]);
778 }
779 else post("no RC file arguments found");
780 }
781 if (sys_argparse(rcargc, rcargv))
782 {
783 post("error parsing RC arguments");
784 return (1);
785 }
786 return (0);
787}
788#endif /* UNIX */
789
790 /* start an audio settings dialog window */
791void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform)
792{
793 char buf[MAXPDSTRING];
794 int i;
795 t_namelist *nl;
796
797 for (nl = pd_path, i = 0; nl && i < 10; nl = nl->nl_next, i++)
798 sys_vgui("pd_set pd_path%d \"%s\"\n", i, nl->nl_string);
799 for (; i < 10; i++)
800 sys_vgui("pd_set pd_path%d \"\"\n", i);
801
802 sprintf(buf, "pdtk_path_dialog %%s\n");
803 gfxstub_new(&glob_pdobject, glob_start_path_dialog, buf);
804}
805
806 /* new values from dialog window */
807void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
808{
809 int i;
810 namelist_free(pd_path);
811 pd_path = 0;
812 for (i = 0; i < argc; i++)
813 {
814 t_symbol *s = atom_getsymbolarg(i, argc, argv);
815 if (*s->s_name)
816 sys_addpath(s->s_name);
817 }
818}
819
820
diff --git a/apps/plugins/pdbox/PDa/src/s_print.c b/apps/plugins/pdbox/PDa/src/s_print.c
new file mode 100644
index 0000000000..1ef0eb6926
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_print.c
@@ -0,0 +1,300 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include "m_pd.h"
6#include <stdlib.h>
7#include <stdio.h>
8#include <stdarg.h>
9#include <string.h>
10#include <errno.h>
11
12void post(char *fmt, ...)
13{
14 va_list ap;
15 t_int arg[8];
16 int i;
17 va_start(ap, fmt);
18 vfprintf(stderr, fmt, ap);
19 va_end(ap);
20 putc('\n', stderr);
21}
22
23void startpost(char *fmt, ...)
24{
25 va_list ap;
26 t_int arg[8];
27 int i;
28 va_start(ap, fmt);
29
30 for (i = 0 ; i < 8; i++) arg[i] = va_arg(ap, t_int);
31 va_end(ap);
32 fprintf(stderr, fmt, arg[0], arg[1], arg[2], arg[3],
33 arg[4], arg[5], arg[6], arg[7]);
34}
35
36void poststring(char *s)
37{
38 fprintf(stderr, " %s", s);
39}
40
41void postatom(int argc, t_atom *argv)
42{
43 int i;
44 for (i = 0; i < argc; i++)
45 {
46 char buf[80];
47 atom_string(argv+i, buf, 80);
48 poststring(buf);
49 }
50}
51
52void postfloat(float f)
53{
54 char buf[80];
55 t_atom a;
56 SETFLOAT(&a, f);
57 postatom(1, &a);
58}
59
60void endpost(void)
61{
62 fprintf(stderr, "\n");
63}
64
65void error(char *fmt, ...)
66{
67 va_list ap;
68 t_int arg[8];
69 int i;
70 va_start(ap, fmt);
71 fprintf(stderr, "error: ");
72 vfprintf(stderr, fmt, ap);
73 va_end(ap);
74 putc('\n', stderr);
75}
76
77 /* here's the good way to log errors -- keep a pointer to the
78 offending or offended object around so the user can search for it
79 later. */
80
81static void *error_object;
82static char error_string[256];
83void canvas_finderror(void *object);
84
85void pd_error(void *object, char *fmt, ...)
86{
87 va_list ap;
88 t_int arg[8];
89 int i;
90 static int saidit = 0;
91 va_start(ap, fmt);
92 vsprintf(error_string, fmt, ap);
93 va_end(ap);
94 fprintf(stderr, "error: %s\n", error_string);
95 error_object = object;
96 if (!saidit)
97 {
98 post("... you might be able to track this down from the Find menu.");
99 saidit = 1;
100 }
101}
102
103void glob_finderror(t_pd *dummy)
104{
105 if (!error_object)
106 post("no findable error yet.");
107 else
108 {
109 post("last trackable error:");
110 post("%s", error_string);
111 canvas_finderror(error_object);
112 }
113}
114
115void bug(char *fmt, ...)
116{
117 va_list ap;
118 t_int arg[8];
119 int i;
120 va_start(ap, fmt);
121
122 for (i = 0 ; i < 8; i++) arg[i] = va_arg(ap, t_int);
123 va_end(ap);
124 fprintf(stderr, "Consistency check failed: ");
125 fprintf(stderr, fmt, arg[0], arg[1], arg[2], arg[3],
126 arg[4], arg[5], arg[6], arg[7]);
127 putc('\n', stderr);
128}
129
130 /* this isn't worked out yet. */
131static char *errobject;
132static char *errstring;
133
134void sys_logerror(char *object, char *s)
135{
136 errobject = object;
137 errstring = s;
138}
139
140void sys_unixerror(char *object)
141{
142 errobject = object;
143 errstring = strerror(errno);
144}
145
146void sys_ouch(void)
147{
148 if (*errobject) error("%s: %s", errobject, errstring);
149 else error("%s", errstring);
150}
151/* Copyright (c) 1997-1999 Miller Puckette.
152* For information on usage and redistribution, and for a DISCLAIMER OF ALL
153* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
154
155#include "m_pd.h"
156#include <stdlib.h>
157#include <stdio.h>
158#include <stdarg.h>
159#include <string.h>
160#include <errno.h>
161
162void post(char *fmt, ...)
163{
164 va_list ap;
165 t_int arg[8];
166 int i;
167 va_start(ap, fmt);
168 vfprintf(stderr, fmt, ap);
169 va_end(ap);
170 putc('\n', stderr);
171}
172
173void startpost(char *fmt, ...)
174{
175 va_list ap;
176 t_int arg[8];
177 int i;
178 va_start(ap, fmt);
179
180 for (i = 0 ; i < 8; i++) arg[i] = va_arg(ap, t_int);
181 va_end(ap);
182 fprintf(stderr, fmt, arg[0], arg[1], arg[2], arg[3],
183 arg[4], arg[5], arg[6], arg[7]);
184}
185
186void poststring(char *s)
187{
188 fprintf(stderr, " %s", s);
189}
190
191void postatom(int argc, t_atom *argv)
192{
193 int i;
194 for (i = 0; i < argc; i++)
195 {
196 char buf[80];
197 atom_string(argv+i, buf, 80);
198 poststring(buf);
199 }
200}
201
202void postfloat(float f)
203{
204 char buf[80];
205 t_atom a;
206 SETFLOAT(&a, f);
207 postatom(1, &a);
208}
209
210void endpost(void)
211{
212 fprintf(stderr, "\n");
213}
214
215void error(char *fmt, ...)
216{
217 va_list ap;
218 t_int arg[8];
219 int i;
220 va_start(ap, fmt);
221 fprintf(stderr, "error: ");
222 vfprintf(stderr, fmt, ap);
223 va_end(ap);
224 putc('\n', stderr);
225}
226
227 /* here's the good way to log errors -- keep a pointer to the
228 offending or offended object around so the user can search for it
229 later. */
230
231static void *error_object;
232static char error_string[256];
233void canvas_finderror(void *object);
234
235void pd_error(void *object, char *fmt, ...)
236{
237 va_list ap;
238 t_int arg[8];
239 int i;
240 static int saidit = 0;
241 va_start(ap, fmt);
242 vsprintf(error_string, fmt, ap);
243 va_end(ap);
244 fprintf(stderr, "error: %s\n", error_string);
245 error_object = object;
246 if (!saidit)
247 {
248 post("... you might be able to track this down from the Find menu.");
249 saidit = 1;
250 }
251}
252
253void glob_finderror(t_pd *dummy)
254{
255 if (!error_object)
256 post("no findable error yet.");
257 else
258 {
259 post("last trackable error:");
260 post("%s", error_string);
261 canvas_finderror(error_object);
262 }
263}
264
265void bug(char *fmt, ...)
266{
267 va_list ap;
268 t_int arg[8];
269 int i;
270 va_start(ap, fmt);
271
272 for (i = 0 ; i < 8; i++) arg[i] = va_arg(ap, t_int);
273 va_end(ap);
274 fprintf(stderr, "Consistency check failed: ");
275 fprintf(stderr, fmt, arg[0], arg[1], arg[2], arg[3],
276 arg[4], arg[5], arg[6], arg[7]);
277 putc('\n', stderr);
278}
279
280 /* this isn't worked out yet. */
281static char *errobject;
282static char *errstring;
283
284void sys_logerror(char *object, char *s)
285{
286 errobject = object;
287 errstring = s;
288}
289
290void sys_unixerror(char *object)
291{
292 errobject = object;
293 errstring = strerror(errno);
294}
295
296void sys_ouch(void)
297{
298 if (*errobject) error("%s: %s", errobject, errstring);
299 else error("%s", errstring);
300}
diff --git a/apps/plugins/pdbox/PDa/src/s_stuff.h b/apps/plugins/pdbox/PDa/src/s_stuff.h
new file mode 100644
index 0000000000..6dc9a88c4b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_stuff.h
@@ -0,0 +1,430 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* Audio and MIDI I/O, and other scheduling and system stuff. */
6
7/* NOTE: this file describes Pd implementation details which may change
8in future releases. The public (stable) API is in m_pd.h. */
9
10/* in s_file.c */
11typedef struct _namelist
12{
13 struct _namelist *nl_next;
14 char *nl_string;
15} t_namelist;
16
17t_namelist *namelist_append(t_namelist *listwas, const char *s);
18void namelist_free(t_namelist *listwas);
19
20/* s_main.c */
21extern int sys_debuglevel;
22extern int sys_verbose;
23extern int sys_noloadbang;
24extern int sys_nogui;
25extern char *sys_guicmd;
26
27EXTERN int sys_nearestfontsize(int fontsize);
28EXTERN int sys_hostfontsize(int fontsize);
29
30extern int sys_defaultfont;
31extern t_symbol *sys_libdir; /* library directory for auxilliary files */
32
33/* s_loader.c */
34int sys_load_lib(char *dirname, char *filename);
35
36/* s_audio.c */
37
38#define SENDDACS_NO 0 /* return values for sys_send_dacs() */
39#define SENDDACS_YES 1
40#define SENDDACS_SLEPT 2
41
42#define DEFDACBLKSIZE 64
43extern int sys_schedblocksize; /* audio block size for scheduler */
44extern int sys_hipriority; /* real-time flag, true if priority boosted */
45extern t_sample *sys_soundout;
46extern t_sample *sys_soundin;
47extern int sys_inchannels;
48extern int sys_outchannels;
49extern int sys_advance_samples; /* scheduler advance in samples */
50extern int sys_blocksize; /* audio I/O block size in sample frames */
51extern float sys_dacsr;
52extern int sys_schedadvance;
53extern int sys_sleepgrain;
54void sys_open_audio(int naudioindev, int *audioindev,
55 int nchindev, int *chindev,
56 int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
57 int srate, int advance, int enable);
58void sys_close_audio(void);
59
60 /* s_midi.c */
61void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec);
62
63 /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */
64void sys_do_open_midi(int nmidiin, int *midiinvec,
65 int nmidiout, int *midioutvec);
66void sys_close_midi(void);
67void midi_getdevs(char *indevlist, int *nindevs,
68 char *outdevlist, int *noutdevs, int maxndev, int devdescsize);
69
70int sys_send_dacs(void);
71void sys_reportidle(void);
72void sys_set_priority(int higher);
73void sys_audiobuf(int nbufs);
74void sys_getmeters(float *inmax, float *outmax);
75void sys_listdevs(void);
76void sys_setblocksize(int n);
77
78/* s_midi.c */
79#define MAXMIDIINDEV 16 /* max. number of input ports */
80#define MAXMIDIOUTDEV 16 /* max. number of output ports */
81extern int sys_nmidiin;
82extern int sys_nmidiout;
83extern int sys_midiindevlist[];
84extern int sys_midioutdevlist[];
85
86EXTERN void sys_putmidimess(int portno, int a, int b, int c);
87EXTERN void sys_putmidibyte(int portno, int a);
88EXTERN void sys_poll_midi(void);
89EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
90EXTERN void sys_midibytein(int portno, int byte);
91
92/* m_sched.c */
93EXTERN void sys_log_error(int type);
94#define ERR_NOTHING 0
95#define ERR_ADCSLEPT 1
96#define ERR_DACSLEPT 2
97#define ERR_RESYNC 3
98#define ERR_DATALATE 4
99void sched_set_using_dacs(int flag);
100
101/* s_inter.c */
102
103EXTERN void sys_microsleep(int microsec);
104
105EXTERN void sys_bail(int exitcode);
106EXTERN int sys_pollgui(void);
107
108EXTERN_STRUCT _socketreceiver;
109#define t_socketreceiver struct _socketreceiver
110
111typedef void (*t_socketnotifier)(void *x);
112typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
113
114EXTERN t_socketreceiver *socketreceiver_new(void *owner,
115 t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp);
116EXTERN void socketreceiver_read(t_socketreceiver *x, int fd);
117EXTERN void sys_sockerror(char *s);
118EXTERN void sys_closesocket(int fd);
119
120typedef void (*t_fdpollfn)(void *ptr, int fd);
121EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
122EXTERN void sys_rmpollfn(int fd);
123#ifdef UNIX
124void sys_setalarm(int microsec);
125void sys_setvirtualalarm( void);
126#endif
127
128#define API_ALSA 1
129#define API_OSS 2
130#define API_MMIO 3
131#define API_PORTAUDIO 4
132#define API_JACK 5
133
134#ifdef __linux__
135#define API_DEFAULT API_OSS
136#define API_DEFSTRING "OSS"
137#endif
138#ifdef MSW
139#define API_DEFAULT API_MMIO
140#define API_DEFSTRING "MMIO"
141#endif
142#ifdef MACOSX
143#define API_DEFAULT API_PORTAUDIO
144#define API_DEFSTRING "portaudio"
145#endif
146#define DEFAULTAUDIODEV 0
147
148#define MAXAUDIOINDEV 4
149#define MAXAUDIOOUTDEV 4
150
151#define DEFMIDIDEV 0
152
153#define DEFAULTSRATE 44100
154#ifdef MSW
155#define DEFAULTADVANCE 70
156#else
157#define DEFAULTADVANCE 50
158#endif
159
160int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
161 t_sample *soundout, int framesperbuf, int nbuffers,
162 int indeviceno, int outdeviceno);
163void pa_close_audio(void);
164int pa_send_dacs(void);
165void sys_reportidle(void);
166void pa_listdevs(void);
167void pa_getdevs(char *indevlist, int *nindevs,
168 char *outdevlist, int *noutdevs, int *canmulti,
169 int maxndev, int devdescsize);
170
171int oss_open_audio(int naudioindev, int *audioindev, int nchindev,
172 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
173 int *choutdev, int rate); /* IOhannes */
174void oss_close_audio(void);
175int oss_send_dacs(void);
176void oss_reportidle(void);
177void oss_getdevs(char *indevlist, int *nindevs,
178 char *outdevlist, int *noutdevs, int *canmulti,
179 int maxndev, int devdescsize);
180
181int alsa_open_audio(int naudioindev, int *audioindev, int nchindev,
182 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
183 int *choutdev, int rate);
184void alsa_close_audio(void);
185int alsa_send_dacs(void);
186void alsa_reportidle(void);
187void alsa_getdevs(char *indevlist, int *nindevs,
188 char *outdevlist, int *noutdevs, int *canmulti,
189 int maxndev, int devdescsize);
190
191int jack_open_audio(int wantinchans, int wantoutchans, int srate);
192void jack_close_audio(void);
193int jack_send_dacs(void);
194void jack_reportidle(void);
195void jack_listdevs(void);
196
197void mmio_open_audio(int naudioindev, int *audioindev,
198 int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
199 int nchoutdev, int *choutdev, int rate);
200void mmio_close_audio( void);
201void mmio_reportidle(void);
202int mmio_send_dacs(void);
203void mmio_getdevs(char *indevlist, int *nindevs,
204 char *outdevlist, int *noutdevs, int *canmulti,
205 int maxndev, int devdescsize);
206
207void sys_listmididevs(void);
208void sys_set_audio_api(int whichapi);
209void sys_get_audio_apis(char *buf);
210extern int sys_audioapi;
211void sys_set_audio_state(int onoff);
212
213/* API dependent audio flags and settings */
214void oss_set32bit( void);
215void linux_alsa_devname(char *devname);
216/* Copyright (c) 1997-1999 Miller Puckette.
217* For information on usage and redistribution, and for a DISCLAIMER OF ALL
218* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
219
220/* Audio and MIDI I/O, and other scheduling and system stuff. */
221
222/* NOTE: this file describes Pd implementation details which may change
223in future releases. The public (stable) API is in m_pd.h. */
224
225/* in s_file.c */
226typedef struct _namelist
227{
228 struct _namelist *nl_next;
229 char *nl_string;
230} t_namelist;
231
232t_namelist *namelist_append(t_namelist *listwas, const char *s);
233void namelist_free(t_namelist *listwas);
234
235/* s_main.c */
236extern int sys_debuglevel;
237extern int sys_verbose;
238extern int sys_noloadbang;
239extern int sys_nogui;
240extern char *sys_guicmd;
241
242EXTERN int sys_nearestfontsize(int fontsize);
243EXTERN int sys_hostfontsize(int fontsize);
244
245extern int sys_defaultfont;
246extern t_symbol *sys_libdir; /* library directory for auxilliary files */
247
248/* s_loader.c */
249int sys_load_lib(char *dirname, char *filename);
250
251/* s_audio.c */
252
253#define SENDDACS_NO 0 /* return values for sys_send_dacs() */
254#define SENDDACS_YES 1
255#define SENDDACS_SLEPT 2
256
257#define DEFDACBLKSIZE 64
258extern int sys_schedblocksize; /* audio block size for scheduler */
259extern int sys_hipriority; /* real-time flag, true if priority boosted */
260extern t_sample *sys_soundout;
261extern t_sample *sys_soundin;
262extern int sys_inchannels;
263extern int sys_outchannels;
264extern int sys_advance_samples; /* scheduler advance in samples */
265extern int sys_blocksize; /* audio I/O block size in sample frames */
266extern float sys_dacsr;
267extern int sys_schedadvance;
268extern int sys_sleepgrain;
269void sys_open_audio(int naudioindev, int *audioindev,
270 int nchindev, int *chindev,
271 int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
272 int srate, int advance, int enable);
273void sys_close_audio(void);
274
275 /* s_midi.c */
276void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec);
277
278 /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */
279void sys_do_open_midi(int nmidiin, int *midiinvec,
280 int nmidiout, int *midioutvec);
281void sys_close_midi(void);
282void midi_getdevs(char *indevlist, int *nindevs,
283 char *outdevlist, int *noutdevs, int maxndev, int devdescsize);
284
285int sys_send_dacs(void);
286void sys_reportidle(void);
287void sys_set_priority(int higher);
288void sys_audiobuf(int nbufs);
289void sys_getmeters(float *inmax, float *outmax);
290void sys_listdevs(void);
291void sys_setblocksize(int n);
292
293/* s_midi.c */
294#define MAXMIDIINDEV 16 /* max. number of input ports */
295#define MAXMIDIOUTDEV 16 /* max. number of output ports */
296extern int sys_nmidiin;
297extern int sys_nmidiout;
298extern int sys_midiindevlist[];
299extern int sys_midioutdevlist[];
300
301EXTERN void sys_putmidimess(int portno, int a, int b, int c);
302EXTERN void sys_putmidibyte(int portno, int a);
303EXTERN void sys_poll_midi(void);
304EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
305EXTERN void sys_midibytein(int portno, int byte);
306
307/* m_sched.c */
308EXTERN void sys_log_error(int type);
309#define ERR_NOTHING 0
310#define ERR_ADCSLEPT 1
311#define ERR_DACSLEPT 2
312#define ERR_RESYNC 3
313#define ERR_DATALATE 4
314void sched_set_using_dacs(int flag);
315
316/* s_inter.c */
317
318EXTERN void sys_microsleep(int microsec);
319
320EXTERN void sys_bail(int exitcode);
321EXTERN int sys_pollgui(void);
322
323EXTERN_STRUCT _socketreceiver;
324#define t_socketreceiver struct _socketreceiver
325
326typedef void (*t_socketnotifier)(void *x);
327typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
328
329EXTERN t_socketreceiver *socketreceiver_new(void *owner,
330 t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp);
331EXTERN void socketreceiver_read(t_socketreceiver *x, int fd);
332EXTERN void sys_sockerror(char *s);
333EXTERN void sys_closesocket(int fd);
334
335typedef void (*t_fdpollfn)(void *ptr, int fd);
336EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
337EXTERN void sys_rmpollfn(int fd);
338#ifdef UNIX
339void sys_setalarm(int microsec);
340void sys_setvirtualalarm( void);
341#endif
342
343#define API_ALSA 1
344#define API_OSS 2
345#define API_MMIO 3
346#define API_PORTAUDIO 4
347#define API_JACK 5
348
349#ifdef __linux__
350#define API_DEFAULT API_OSS
351#define API_DEFSTRING "OSS"
352#endif
353#ifdef MSW
354#define API_DEFAULT API_MMIO
355#define API_DEFSTRING "MMIO"
356#endif
357#ifdef MACOSX
358#define API_DEFAULT API_PORTAUDIO
359#define API_DEFSTRING "portaudio"
360#endif
361#define DEFAULTAUDIODEV 0
362
363#define MAXAUDIOINDEV 4
364#define MAXAUDIOOUTDEV 4
365
366#define DEFMIDIDEV 0
367
368#define DEFAULTSRATE 44100
369#ifdef MSW
370#define DEFAULTADVANCE 70
371#else
372#define DEFAULTADVANCE 50
373#endif
374
375int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
376 t_sample *soundout, int framesperbuf, int nbuffers,
377 int indeviceno, int outdeviceno);
378void pa_close_audio(void);
379int pa_send_dacs(void);
380void sys_reportidle(void);
381void pa_listdevs(void);
382void pa_getdevs(char *indevlist, int *nindevs,
383 char *outdevlist, int *noutdevs, int *canmulti,
384 int maxndev, int devdescsize);
385
386int oss_open_audio(int naudioindev, int *audioindev, int nchindev,
387 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
388 int *choutdev, int rate); /* IOhannes */
389void oss_close_audio(void);
390int oss_send_dacs(void);
391void oss_reportidle(void);
392void oss_getdevs(char *indevlist, int *nindevs,
393 char *outdevlist, int *noutdevs, int *canmulti,
394 int maxndev, int devdescsize);
395
396int alsa_open_audio(int naudioindev, int *audioindev, int nchindev,
397 int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
398 int *choutdev, int rate);
399void alsa_close_audio(void);
400int alsa_send_dacs(void);
401void alsa_reportidle(void);
402void alsa_getdevs(char *indevlist, int *nindevs,
403 char *outdevlist, int *noutdevs, int *canmulti,
404 int maxndev, int devdescsize);
405
406int jack_open_audio(int wantinchans, int wantoutchans, int srate);
407void jack_close_audio(void);
408int jack_send_dacs(void);
409void jack_reportidle(void);
410void jack_listdevs(void);
411
412void mmio_open_audio(int naudioindev, int *audioindev,
413 int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
414 int nchoutdev, int *choutdev, int rate);
415void mmio_close_audio( void);
416void mmio_reportidle(void);
417int mmio_send_dacs(void);
418void mmio_getdevs(char *indevlist, int *nindevs,
419 char *outdevlist, int *noutdevs, int *canmulti,
420 int maxndev, int devdescsize);
421
422void sys_listmididevs(void);
423void sys_set_audio_api(int whichapi);
424void sys_get_audio_apis(char *buf);
425extern int sys_audioapi;
426void sys_set_audio_state(int onoff);
427
428/* API dependent audio flags and settings */
429void oss_set32bit( void);
430void linux_alsa_devname(char *devname);
diff --git a/apps/plugins/pdbox/PDa/src/s_watchdog.c b/apps/plugins/pdbox/PDa/src/s_watchdog.c
new file mode 100644
index 0000000000..48309c16c4
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_watchdog.c
@@ -0,0 +1,94 @@
1/* Copyright (c) 1997-2000 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* This file is compiled into the separate program, "pd-watchdog," which
6tries to prevent Pd from locking up the processor if it's at realtime
7priority. Linux only. Invoked from s_inter.c. */
8
9#include <sys/time.h>
10#include <sys/types.h>
11#include <unistd.h>
12#include <signal.h>
13#include <stdio.h>
14
15int main(int argc, char **argv)
16{
17 int happy = 1;
18 while (1)
19 {
20 struct timeval timout;
21 fd_set readset;
22 if (happy)
23 {
24 timout.tv_sec = 5;
25 timout.tv_usec = 0;
26 }
27 else
28 {
29 timout.tv_sec = 2;
30 timout.tv_usec = 0;
31 }
32 FD_ZERO(&readset);
33 FD_SET(0, &readset);
34 select(1, &readset, 0, 0, &timout);
35 if (FD_ISSET(0, &readset))
36 {
37 char buf[100];
38 happy = 1;
39 if (read(0, &buf, 100) <= 0)
40 return (0);
41 else continue;
42 }
43 happy = 0;
44 kill(getppid(), SIGHUP);
45 fprintf(stderr, "watchdog: signaling pd...\n");
46 }
47}
48/* Copyright (c) 1997-2000 Miller Puckette.
49* For information on usage and redistribution, and for a DISCLAIMER OF ALL
50* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
51
52/* This file is compiled into the separate program, "pd-watchdog," which
53tries to prevent Pd from locking up the processor if it's at realtime
54priority. Linux only. Invoked from s_inter.c. */
55
56#include <sys/time.h>
57#include <sys/types.h>
58#include <unistd.h>
59#include <signal.h>
60#include <stdio.h>
61
62int main(int argc, char **argv)
63{
64 int happy = 1;
65 while (1)
66 {
67 struct timeval timout;
68 fd_set readset;
69 if (happy)
70 {
71 timout.tv_sec = 5;
72 timout.tv_usec = 0;
73 }
74 else
75 {
76 timout.tv_sec = 2;
77 timout.tv_usec = 0;
78 }
79 FD_ZERO(&readset);
80 FD_SET(0, &readset);
81 select(1, &readset, 0, 0, &timout);
82 if (FD_ISSET(0, &readset))
83 {
84 char buf[100];
85 happy = 1;
86 if (read(0, &buf, 100) <= 0)
87 return (0);
88 else continue;
89 }
90 happy = 0;
91 kill(getppid(), SIGHUP);
92 fprintf(stderr, "watchdog: signaling pd...\n");
93 }
94}
diff --git a/apps/plugins/pdbox/PDa/src/t_main.c b/apps/plugins/pdbox/PDa/src/t_main.c
new file mode 100644
index 0000000000..7b80cb0dd6
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/t_main.c
@@ -0,0 +1,240 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* This file should be compared with the corresponding thing in the TK
6* distribution whenever updating to newer versions of TCL/TK. */
7
8/*
9 * Copyright (c) 1993 The Regents of the University of California.
10 * Copyright (c) 1994 Sun Microsystems, Inc.
11 *
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 */
15
16
17#ifndef MACOSX /* linux and IRIX only; in MACOSX we don't link this in */
18#include "tk.h"
19#include <stdlib.h>
20
21/*
22 * The following variable is a special hack that is needed in order for
23 * Sun shared libraries to be used for Tcl.
24 */
25
26extern int matherr(void);
27int *tclDummyMathPtr = (int *) matherr;
28
29/*
30 *----------------------------------------------------------------------
31 *
32 * main --
33 *
34 * This is the main program for the application.
35 *
36 * Results:
37 * None: Tk_Main never returns here, so this procedure never
38 * returns either.
39 *
40 * Side effects:
41 * Whatever the application does.
42 *
43 *----------------------------------------------------------------------
44 */
45
46void pdgui_startup(Tcl_Interp *interp);
47void pdgui_setname(char *name);
48void pdgui_setsock(int port);
49void pdgui_sethost(char *name);
50
51int
52main(int argc, char **argv)
53{
54 pdgui_setname(argv[0]);
55 if (argc >= 2)
56 {
57 pdgui_setsock(atoi(argv[1]));
58 argc--; argv++;
59 argv[0] = "Pd";
60 }
61 if (argc >= 2)
62 {
63 pdgui_sethost(argv[1]);
64 argc--; argv++;
65 argv[0] = "Pd";
66 }
67 Tk_Main(argc, argv, Tcl_AppInit);
68 return 0; /* Needed only to prevent compiler warning. */
69}
70
71
72/*
73 *----------------------------------------------------------------------
74 *
75 * Tcl_AppInit --
76 *
77 * This procedure performs application-specific initialization.
78 * Most applications, especially those that incorporate additional
79 * packages, will have their own version of this procedure.
80 * Results:
81 * Returns a standard Tcl completion code, and leaves an error
82 * message in interp->result if an error occurs.
83 *
84 * Side effects:
85 * Depends on the startup script.
86 *
87 *----------------------------------------------------------------------
88 */
89
90int
91Tcl_AppInit(interp)
92 Tcl_Interp *interp; /* Interpreter for application. */
93{
94
95 if (Tcl_Init(interp) == TCL_ERROR) {
96 return TCL_ERROR;
97 }
98 if (Tk_Init(interp) == TCL_ERROR) {
99 return TCL_ERROR;
100 }
101
102 /* setup specific to pd-gui: */
103
104 pdgui_startup(interp);
105
106 /*
107 * Specify a user-specific startup file to invoke if the application
108 * is run interactively. Typically the startup file is "~/.apprc"
109 * where "app" is the name of the application. If this line is deleted
110 * then no user-specific startup file will be run under any conditions.
111 */
112
113#if 0
114 tcl_RcFileName = "~/.pdrc";
115#endif
116
117 return TCL_OK;
118}
119
120#endif /* MACOSX */
121/* Copyright (c) 1997-1999 Miller Puckette.
122* For information on usage and redistribution, and for a DISCLAIMER OF ALL
123* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
124
125/* This file should be compared with the corresponding thing in the TK
126* distribution whenever updating to newer versions of TCL/TK. */
127
128/*
129 * Copyright (c) 1993 The Regents of the University of California.
130 * Copyright (c) 1994 Sun Microsystems, Inc.
131 *
132 * See the file "license.terms" for information on usage and redistribution
133 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
134 */
135
136
137#ifndef MACOSX /* linux and IRIX only; in MACOSX we don't link this in */
138#include "tk.h"
139#include <stdlib.h>
140
141/*
142 * The following variable is a special hack that is needed in order for
143 * Sun shared libraries to be used for Tcl.
144 */
145
146extern int matherr(void);
147int *tclDummyMathPtr = (int *) matherr;
148
149/*
150 *----------------------------------------------------------------------
151 *
152 * main --
153 *
154 * This is the main program for the application.
155 *
156 * Results:
157 * None: Tk_Main never returns here, so this procedure never
158 * returns either.
159 *
160 * Side effects:
161 * Whatever the application does.
162 *
163 *----------------------------------------------------------------------
164 */
165
166void pdgui_startup(Tcl_Interp *interp);
167void pdgui_setname(char *name);
168void pdgui_setsock(int port);
169void pdgui_sethost(char *name);
170
171int
172main(int argc, char **argv)
173{
174 pdgui_setname(argv[0]);
175 if (argc >= 2)
176 {
177 pdgui_setsock(atoi(argv[1]));
178 argc--; argv++;
179 argv[0] = "Pd";
180 }
181 if (argc >= 2)
182 {
183 pdgui_sethost(argv[1]);
184 argc--; argv++;
185 argv[0] = "Pd";
186 }
187 Tk_Main(argc, argv, Tcl_AppInit);
188 return 0; /* Needed only to prevent compiler warning. */
189}
190
191
192/*
193 *----------------------------------------------------------------------
194 *
195 * Tcl_AppInit --
196 *
197 * This procedure performs application-specific initialization.
198 * Most applications, especially those that incorporate additional
199 * packages, will have their own version of this procedure.
200 * Results:
201 * Returns a standard Tcl completion code, and leaves an error
202 * message in interp->result if an error occurs.
203 *
204 * Side effects:
205 * Depends on the startup script.
206 *
207 *----------------------------------------------------------------------
208 */
209
210int
211Tcl_AppInit(interp)
212 Tcl_Interp *interp; /* Interpreter for application. */
213{
214
215 if (Tcl_Init(interp) == TCL_ERROR) {
216 return TCL_ERROR;
217 }
218 if (Tk_Init(interp) == TCL_ERROR) {
219 return TCL_ERROR;
220 }
221
222 /* setup specific to pd-gui: */
223
224 pdgui_startup(interp);
225
226 /*
227 * Specify a user-specific startup file to invoke if the application
228 * is run interactively. Typically the startup file is "~/.apprc"
229 * where "app" is the name of the application. If this line is deleted
230 * then no user-specific startup file will be run under any conditions.
231 */
232
233#if 0
234 tcl_RcFileName = "~/.pdrc";
235#endif
236
237 return TCL_OK;
238}
239
240#endif /* MACOSX */
diff --git a/apps/plugins/pdbox/PDa/src/t_tk.h b/apps/plugins/pdbox/PDa/src/t_tk.h
new file mode 100644
index 0000000000..e1c8e4e871
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/t_tk.h
@@ -0,0 +1,20 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5void pdgui_vmess(char *fmt, ...);
6void pdgui_mess(char *s);
7
8void pdgui_evalfile(char *s);
9
10#define GUISTRING 1000
11/* Copyright (c) 1997-1999 Miller Puckette.
12* For information on usage and redistribution, and for a DISCLAIMER OF ALL
13* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
14
15void pdgui_vmess(char *fmt, ...);
16void pdgui_mess(char *s);
17
18void pdgui_evalfile(char *s);
19
20#define GUISTRING 1000
diff --git a/apps/plugins/pdbox/PDa/src/t_tkcmd.c b/apps/plugins/pdbox/PDa/src/t_tkcmd.c
new file mode 100644
index 0000000000..136412cad7
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/t_tkcmd.c
@@ -0,0 +1,796 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#ifdef UNIX /* in unix this only works first; in NT it only works last. */
6#include "tk.h"
7#endif
8
9#include "t_tk.h"
10#include <stdlib.h>
11#include <string.h>
12#include <stdio.h>
13#include <stdarg.h>
14#include <sys/types.h>
15#ifdef UNIX
16#include <unistd.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <netdb.h>
20#ifdef HAVE_BSTRING_H
21#include <bstring.h>
22#endif
23#include <sys/time.h>
24#include <errno.h>
25#endif
26#ifdef MSW
27#include <winsock.h>
28#include <io.h>
29#endif
30#ifdef MSW
31#pragma warning( disable : 4305 ) /* uncast const double to float */
32#pragma warning( disable : 4244 ) /* uncast double to float */
33#pragma warning( disable : 4101 ) /* unused local variables */
34#endif
35
36#ifdef MSW
37#include "tk.h"
38#endif
39
40void tcl_mess(char *s);
41
42/***************** the socket setup code ********************/
43
44static int portno = 5400;
45
46 /* some installations of linux don't know about "localhost" so give
47 the loopback address; NT, on the other hand, can't understand the
48 hostname "127.0.0.1". */
49char hostname[100] =
50#ifdef __linux__
51 "127.0.0.1";
52#else
53 "localhost";
54#endif
55
56void pdgui_setsock(int port)
57{
58 portno = port;
59}
60
61void pdgui_sethost(char *name)
62{
63 strncpy(hostname, name, 100);
64 hostname[99] = 0;
65}
66
67static void pdgui_sockerror(char *s)
68{
69#ifdef MSW
70 int err = WSAGetLastError();
71#endif
72#ifdef UNIX
73 int err = errno;
74#endif
75
76 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
77 tcl_mess("exit\n");
78 exit(1);
79}
80
81static int sockfd;
82
83/* The "pd_suck" command, which polls the socket.
84 FIXME: if Pd sends something bigger than SOCKSIZE we're in trouble!
85 This has to be set bigger than any array update message for instance.
86*/
87#define SOCKSIZE 20000
88
89static char pd_tkbuf[SOCKSIZE+1];
90int pd_spillbytes = 0;
91
92static void pd_readsocket(ClientData cd, int mask)
93{
94 int ngot;
95 fd_set readset, writeset, exceptset;
96 struct timeval timout;
97
98 timout.tv_sec = 0;
99 timout.tv_usec = 0;
100 FD_ZERO(&writeset);
101 FD_ZERO(&readset);
102 FD_ZERO(&exceptset);
103 FD_SET(sockfd, &readset);
104 FD_SET(sockfd, &exceptset);
105
106 if (select(sockfd+1, &readset, &writeset, &exceptset, &timout) < 0)
107 perror("select");
108 if (FD_ISSET(sockfd, &exceptset) || FD_ISSET(sockfd, &readset))
109 {
110 int ret;
111 ret = recv(sockfd, pd_tkbuf + pd_spillbytes,
112 SOCKSIZE - pd_spillbytes, 0);
113 if (ret < 0) pdgui_sockerror("socket receive error");
114 else if (ret == 0)
115 {
116 /* fprintf(stderr, "read %d\n", SOCKSIZE - pd_spillbytes); */
117 fprintf(stderr, "pd_gui: pd process exited\n");
118 tcl_mess("exit\n");
119 }
120 else
121 {
122 char *lastcr = 0, *bp = pd_tkbuf, *ep = bp + (pd_spillbytes + ret);
123 int brace = 0;
124 char lastc = 0;
125 while (bp < ep)
126 {
127 char c = *bp;
128 if (c == '}' && brace) brace--;
129 else if (c == '{') brace++;
130 else if (!brace && c == '\n' && lastc != '\\') lastcr = bp;
131 lastc = c;
132 bp++;
133 }
134 if (lastcr)
135 {
136 int xtra = pd_tkbuf + pd_spillbytes + ret - (lastcr+1);
137 char bashwas = lastcr[1];
138 lastcr[1] = 0;
139 tcl_mess(pd_tkbuf);
140 lastcr[1] = bashwas;
141 if (xtra)
142 {
143 /* fprintf(stderr, "x %d\n", xtra); */
144 memmove(pd_tkbuf, lastcr+1, xtra);
145 }
146 pd_spillbytes = xtra;
147 }
148 else
149 {
150 pd_spillbytes += ret;
151 }
152 }
153 }
154}
155
156#ifndef UNIX
157 /* if we aren't UNIX, we add a tcl command to poll the
158 socket for data. */
159static int pd_pollsocketCmd(ClientData cd, Tcl_Interp *interp,
160 int argc, char **argv)
161{
162 pd_readsocket(cd, 0);
163 return (TCL_OK);
164}
165#endif
166
167void pdgui_setupsocket(void)
168{
169 struct sockaddr_in server;
170 struct hostent *hp;
171#ifdef UNIX
172 int retry = 10;
173#else
174 int retry = 1;
175#endif
176#ifdef MSW
177 short version = MAKEWORD(2, 0);
178 WSADATA nobby;
179
180 if (WSAStartup(version, &nobby)) pdgui_sockerror("setup");
181#endif
182
183 /* create a socket */
184 sockfd = socket(AF_INET, SOCK_STREAM, 0);
185 if (sockfd < 0) pdgui_sockerror("socket");
186
187 /* connect socket using hostname provided in command line */
188 server.sin_family = AF_INET;
189
190 hp = gethostbyname(hostname);
191
192 if (hp == 0)
193 {
194 fprintf(stderr,
195 "localhost not found (inet protocol not installed?)\n");
196 exit(1);
197 }
198 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
199
200 /* assign client port number */
201 server.sin_port = htons((unsigned short)portno);
202
203 /* try to connect */
204 while (1)
205 {
206 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) >= 0)
207 goto gotit;
208 retry--;
209 if (retry <= 0)
210 break;
211 /* In UNIX there's a race condition; the child won't be
212 able to connect before the parent (pd) has shed its
213 setuid-ness. In case this is the problem, sleep and
214 retry. */
215 else
216 {
217#ifdef UNIX
218 fd_set readset, writeset, exceptset;
219 struct timeval timout;
220
221 timout.tv_sec = 0;
222 timout.tv_usec = 100000;
223 FD_ZERO(&writeset);
224 FD_ZERO(&readset);
225 FD_ZERO(&exceptset);
226 fprintf(stderr, "retrying connect...\n");
227 if (select(1, &readset, &writeset, &exceptset, &timout) < 0)
228 perror("select");
229#endif /* UNIX */
230 }
231 }
232 pdgui_sockerror("connecting stream socket");
233gotit: ;
234#ifdef UNIX
235 /* in unix we ask TK to call us back. In NT we have to poll. */
236 Tk_CreateFileHandler(sockfd, TK_READABLE | TK_EXCEPTION,
237 pd_readsocket, 0);
238#endif /* UNIX */
239}
240
241/**************************** commands ************************/
242static char *pdgui_path;
243
244/* The "pd" command, which cats its args together and throws the result
245* at the Pd interpreter.
246*/
247#define MAXWRITE 1024
248
249static int pdCmd(ClientData cd, Tcl_Interp *interp, int argc, char **argv)
250{
251 if (argc == 2)
252 {
253 int n = strlen(argv[1]);
254 if (send(sockfd, argv[1], n, 0) < n)
255 {
256 perror("stdout");
257 tcl_mess("exit\n");
258 }
259 }
260 else
261 {
262 int i;
263 char buf[MAXWRITE];
264 buf[0] = 0;
265 for (i = 1; i < argc; i++)
266 {
267 if (strlen(argv[i]) + strlen(buf) + 2 > MAXWRITE)
268 {
269 interp->result = "pd: arg list too long";
270 return (TCL_ERROR);
271 }
272 if (i > 1) strcat(buf, " ");
273 strcat(buf, argv[i]);
274 }
275 if (send(sockfd, buf, strlen(buf), 0) < 0)
276 {
277 perror("stdout");
278 tcl_mess("exit\n");
279 }
280 }
281 return (TCL_OK);
282}
283
284/*********** "c" level access to tk functions. ******************/
285
286static Tcl_Interp *tk_myinterp;
287
288void tcl_mess(char *s)
289{
290 int result;
291 result = Tcl_Eval(tk_myinterp, s);
292 if (result != TCL_OK)
293 {
294 if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
295 }
296}
297
298/* LATER should do a bounds check -- but how do you get printf to do that? */
299void tcl_vmess(char *fmt, ...)
300{
301 int result, i;
302 char buf[MAXWRITE];
303 va_list ap;
304
305 va_start(ap, fmt);
306
307 vsprintf(buf, fmt, ap);
308 result = Tcl_Eval(tk_myinterp, buf);
309 if (result != TCL_OK)
310 {
311 if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
312 }
313 va_end(ap);
314}
315
316#ifdef UNIX
317void pdgui_doevalfile(Tcl_Interp *interp, char *s)
318{
319 char buf[GUISTRING];
320 sprintf(buf, "set pd_guidir \"%s\"\n", pdgui_path);
321 tcl_mess(buf);
322 strcpy(buf, pdgui_path);
323 strcat(buf, "/bin/");
324 strcat(buf, s);
325 if (Tcl_EvalFile(interp, buf) != TCL_OK)
326 {
327 char buf2[1000];
328 sprintf(buf2, "puts [concat tcl: %s: can't open script]\n",
329 buf);
330 tcl_mess(buf2);
331 }
332}
333
334void pdgui_evalfile(char *s)
335{
336 pdgui_doevalfile(tk_myinterp, s);
337}
338#endif
339
340void pdgui_startup(Tcl_Interp *interp)
341{
342
343 /* save pointer to the main interpreter */
344 tk_myinterp = interp;
345
346
347 /* add our own TK commands */
348 Tcl_CreateCommand(interp, "pd", (Tcl_CmdProc*)pdCmd, (ClientData)NULL,
349 (Tcl_CmdDeleteProc *)NULL);
350#ifndef UNIX
351 Tcl_CreateCommand(interp, "pd_pollsocket",(Tcl_CmdProc*) pd_pollsocketCmd,
352 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
353#endif
354 pdgui_setupsocket();
355
356 /* read in the startup file */
357#if !defined(MSW) && !defined(MACOSX)
358 pdgui_evalfile("pd.tk");
359#endif
360}
361
362#ifdef UNIX
363void pdgui_setname(char *s)
364{
365 char *t;
366 char *str;
367 int n;
368 if (t = strrchr(s, '/')) str = s, n = (t-s) + 1;
369 else str = "./", n = 2;
370 if (n > GUISTRING-100) n = GUISTRING-100;
371 pdgui_path = malloc(n+9);
372
373 strncpy(pdgui_path, str, n);
374 while (strlen(pdgui_path) > 0 && pdgui_path[strlen(pdgui_path)-1] == '/')
375 pdgui_path[strlen(pdgui_path)-1] = 0;
376 if (t = strrchr(pdgui_path, '/'))
377 *t = 0;
378}
379#endif
380
381int Pdtcl_Init(Tcl_Interp *interp)
382{
383 const char *myvalue = Tcl_GetVar(interp, "argv", 0);
384 int myportno;
385 if (myvalue && (myportno = atoi(myvalue)) > 1)
386 pdgui_setsock(myportno);
387 tk_myinterp = interp;
388 pdgui_startup(interp);
389 interp->result = "loaded pdtcl_init";
390
391 return (TCL_OK);
392}
393
394int Pdtcl_SafeInit(Tcl_Interp *interp) {
395 fprintf(stderr, "Pdtcl_Safeinit 51\n");
396 return (TCL_OK);
397}
398
399/* Copyright (c) 1997-1999 Miller Puckette.
400* For information on usage and redistribution, and for a DISCLAIMER OF ALL
401* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
402
403#ifdef UNIX /* in unix this only works first; in NT it only works last. */
404#include "tk.h"
405#endif
406
407#include "t_tk.h"
408#include <stdlib.h>
409#include <string.h>
410#include <stdio.h>
411#include <stdarg.h>
412#include <sys/types.h>
413#ifdef UNIX
414#include <unistd.h>
415#include <sys/socket.h>
416#include <netinet/in.h>
417#include <netdb.h>
418#ifdef HAVE_BSTRING_H
419#include <bstring.h>
420#endif
421#include <sys/time.h>
422#include <errno.h>
423#endif
424#ifdef MSW
425#include <winsock.h>
426#include <io.h>
427#endif
428#ifdef MSW
429#pragma warning( disable : 4305 ) /* uncast const double to float */
430#pragma warning( disable : 4244 ) /* uncast double to float */
431#pragma warning( disable : 4101 ) /* unused local variables */
432#endif
433
434#ifdef MSW
435#include "tk.h"
436#endif
437
438void tcl_mess(char *s);
439
440/***************** the socket setup code ********************/
441
442static int portno = 5400;
443
444 /* some installations of linux don't know about "localhost" so give
445 the loopback address; NT, on the other hand, can't understand the
446 hostname "127.0.0.1". */
447char hostname[100] =
448#ifdef __linux__
449 "127.0.0.1";
450#else
451 "localhost";
452#endif
453
454void pdgui_setsock(int port)
455{
456 portno = port;
457}
458
459void pdgui_sethost(char *name)
460{
461 strncpy(hostname, name, 100);
462 hostname[99] = 0;
463}
464
465static void pdgui_sockerror(char *s)
466{
467#ifdef MSW
468 int err = WSAGetLastError();
469#endif
470#ifdef UNIX
471 int err = errno;
472#endif
473
474 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
475 tcl_mess("exit\n");
476 exit(1);
477}
478
479static int sockfd;
480
481/* The "pd_suck" command, which polls the socket.
482 FIXME: if Pd sends something bigger than SOCKSIZE we're in trouble!
483 This has to be set bigger than any array update message for instance.
484*/
485#define SOCKSIZE 20000
486
487static char pd_tkbuf[SOCKSIZE+1];
488int pd_spillbytes = 0;
489
490static void pd_readsocket(ClientData cd, int mask)
491{
492 int ngot;
493 fd_set readset, writeset, exceptset;
494 struct timeval timout;
495
496 timout.tv_sec = 0;
497 timout.tv_usec = 0;
498 FD_ZERO(&writeset);
499 FD_ZERO(&readset);
500 FD_ZERO(&exceptset);
501 FD_SET(sockfd, &readset);
502 FD_SET(sockfd, &exceptset);
503
504 if (select(sockfd+1, &readset, &writeset, &exceptset, &timout) < 0)
505 perror("select");
506 if (FD_ISSET(sockfd, &exceptset) || FD_ISSET(sockfd, &readset))
507 {
508 int ret;
509 ret = recv(sockfd, pd_tkbuf + pd_spillbytes,
510 SOCKSIZE - pd_spillbytes, 0);
511 if (ret < 0) pdgui_sockerror("socket receive error");
512 else if (ret == 0)
513 {
514 /* fprintf(stderr, "read %d\n", SOCKSIZE - pd_spillbytes); */
515 fprintf(stderr, "pd_gui: pd process exited\n");
516 tcl_mess("exit\n");
517 }
518 else
519 {
520 char *lastcr = 0, *bp = pd_tkbuf, *ep = bp + (pd_spillbytes + ret);
521 int brace = 0;
522 char lastc = 0;
523 while (bp < ep)
524 {
525 char c = *bp;
526 if (c == '}' && brace) brace--;
527 else if (c == '{') brace++;
528 else if (!brace && c == '\n' && lastc != '\\') lastcr = bp;
529 lastc = c;
530 bp++;
531 }
532 if (lastcr)
533 {
534 int xtra = pd_tkbuf + pd_spillbytes + ret - (lastcr+1);
535 char bashwas = lastcr[1];
536 lastcr[1] = 0;
537 tcl_mess(pd_tkbuf);
538 lastcr[1] = bashwas;
539 if (xtra)
540 {
541 /* fprintf(stderr, "x %d\n", xtra); */
542 memmove(pd_tkbuf, lastcr+1, xtra);
543 }
544 pd_spillbytes = xtra;
545 }
546 else
547 {
548 pd_spillbytes += ret;
549 }
550 }
551 }
552}
553
554#ifndef UNIX
555 /* if we aren't UNIX, we add a tcl command to poll the
556 socket for data. */
557static int pd_pollsocketCmd(ClientData cd, Tcl_Interp *interp,
558 int argc, char **argv)
559{
560 pd_readsocket(cd, 0);
561 return (TCL_OK);
562}
563#endif
564
565void pdgui_setupsocket(void)
566{
567 struct sockaddr_in server;
568 struct hostent *hp;
569#ifdef UNIX
570 int retry = 10;
571#else
572 int retry = 1;
573#endif
574#ifdef MSW
575 short version = MAKEWORD(2, 0);
576 WSADATA nobby;
577
578 if (WSAStartup(version, &nobby)) pdgui_sockerror("setup");
579#endif
580
581 /* create a socket */
582 sockfd = socket(AF_INET, SOCK_STREAM, 0);
583 if (sockfd < 0) pdgui_sockerror("socket");
584
585 /* connect socket using hostname provided in command line */
586 server.sin_family = AF_INET;
587
588 hp = gethostbyname(hostname);
589
590 if (hp == 0)
591 {
592 fprintf(stderr,
593 "localhost not found (inet protocol not installed?)\n");
594 exit(1);
595 }
596 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
597
598 /* assign client port number */
599 server.sin_port = htons((unsigned short)portno);
600
601 /* try to connect */
602 while (1)
603 {
604 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) >= 0)
605 goto gotit;
606 retry--;
607 if (retry <= 0)
608 break;
609 /* In UNIX there's a race condition; the child won't be
610 able to connect before the parent (pd) has shed its
611 setuid-ness. In case this is the problem, sleep and
612 retry. */
613 else
614 {
615#ifdef UNIX
616 fd_set readset, writeset, exceptset;
617 struct timeval timout;
618
619 timout.tv_sec = 0;
620 timout.tv_usec = 100000;
621 FD_ZERO(&writeset);
622 FD_ZERO(&readset);
623 FD_ZERO(&exceptset);
624 fprintf(stderr, "retrying connect...\n");
625 if (select(1, &readset, &writeset, &exceptset, &timout) < 0)
626 perror("select");
627#endif /* UNIX */
628 }
629 }
630 pdgui_sockerror("connecting stream socket");
631gotit: ;
632#ifdef UNIX
633 /* in unix we ask TK to call us back. In NT we have to poll. */
634 Tk_CreateFileHandler(sockfd, TK_READABLE | TK_EXCEPTION,
635 pd_readsocket, 0);
636#endif /* UNIX */
637}
638
639/**************************** commands ************************/
640static char *pdgui_path;
641
642/* The "pd" command, which cats its args together and throws the result
643* at the Pd interpreter.
644*/
645#define MAXWRITE 1024
646
647static int pdCmd(ClientData cd, Tcl_Interp *interp, int argc, char **argv)
648{
649 if (argc == 2)
650 {
651 int n = strlen(argv[1]);
652 if (send(sockfd, argv[1], n, 0) < n)
653 {
654 perror("stdout");
655 tcl_mess("exit\n");
656 }
657 }
658 else
659 {
660 int i;
661 char buf[MAXWRITE];
662 buf[0] = 0;
663 for (i = 1; i < argc; i++)
664 {
665 if (strlen(argv[i]) + strlen(buf) + 2 > MAXWRITE)
666 {
667 interp->result = "pd: arg list too long";
668 return (TCL_ERROR);
669 }
670 if (i > 1) strcat(buf, " ");
671 strcat(buf, argv[i]);
672 }
673 if (send(sockfd, buf, strlen(buf), 0) < 0)
674 {
675 perror("stdout");
676 tcl_mess("exit\n");
677 }
678 }
679 return (TCL_OK);
680}
681
682/*********** "c" level access to tk functions. ******************/
683
684static Tcl_Interp *tk_myinterp;
685
686void tcl_mess(char *s)
687{
688 int result;
689 result = Tcl_Eval(tk_myinterp, s);
690 if (result != TCL_OK)
691 {
692 if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
693 }
694}
695
696/* LATER should do a bounds check -- but how do you get printf to do that? */
697void tcl_vmess(char *fmt, ...)
698{
699 int result, i;
700 char buf[MAXWRITE];
701 va_list ap;
702
703 va_start(ap, fmt);
704
705 vsprintf(buf, fmt, ap);
706 result = Tcl_Eval(tk_myinterp, buf);
707 if (result != TCL_OK)
708 {
709 if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
710 }
711 va_end(ap);
712}
713
714#ifdef UNIX
715void pdgui_doevalfile(Tcl_Interp *interp, char *s)
716{
717 char buf[GUISTRING];
718 sprintf(buf, "set pd_guidir \"%s\"\n", pdgui_path);
719 tcl_mess(buf);
720 strcpy(buf, pdgui_path);
721 strcat(buf, "/bin/");
722 strcat(buf, s);
723 if (Tcl_EvalFile(interp, buf) != TCL_OK)
724 {
725 char buf2[1000];
726 sprintf(buf2, "puts [concat tcl: %s: can't open script]\n",
727 buf);
728 tcl_mess(buf2);
729 }
730}
731
732void pdgui_evalfile(char *s)
733{
734 pdgui_doevalfile(tk_myinterp, s);
735}
736#endif
737
738void pdgui_startup(Tcl_Interp *interp)
739{
740
741 /* save pointer to the main interpreter */
742 tk_myinterp = interp;
743
744
745 /* add our own TK commands */
746 Tcl_CreateCommand(interp, "pd", (Tcl_CmdProc*)pdCmd, (ClientData)NULL,
747 (Tcl_CmdDeleteProc *)NULL);
748#ifndef UNIX
749 Tcl_CreateCommand(interp, "pd_pollsocket",(Tcl_CmdProc*) pd_pollsocketCmd,
750 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
751#endif
752 pdgui_setupsocket();
753
754 /* read in the startup file */
755#if !defined(MSW) && !defined(MACOSX)
756 pdgui_evalfile("pd.tk");
757#endif
758}
759
760#ifdef UNIX
761void pdgui_setname(char *s)
762{
763 char *t;
764 char *str;
765 int n;
766 if (t = strrchr(s, '/')) str = s, n = (t-s) + 1;
767 else str = "./", n = 2;
768 if (n > GUISTRING-100) n = GUISTRING-100;
769 pdgui_path = malloc(n+9);
770
771 strncpy(pdgui_path, str, n);
772 while (strlen(pdgui_path) > 0 && pdgui_path[strlen(pdgui_path)-1] == '/')
773 pdgui_path[strlen(pdgui_path)-1] = 0;
774 if (t = strrchr(pdgui_path, '/'))
775 *t = 0;
776}
777#endif
778
779int Pdtcl_Init(Tcl_Interp *interp)
780{
781 const char *myvalue = Tcl_GetVar(interp, "argv", 0);
782 int myportno;
783 if (myvalue && (myportno = atoi(myvalue)) > 1)
784 pdgui_setsock(myportno);
785 tk_myinterp = interp;
786 pdgui_startup(interp);
787 interp->result = "loaded pdtcl_init";
788
789 return (TCL_OK);
790}
791
792int Pdtcl_SafeInit(Tcl_Interp *interp) {
793 fprintf(stderr, "Pdtcl_Safeinit 51\n");
794 return (TCL_OK);
795}
796
diff --git a/apps/plugins/pdbox/PDa/src/u_main.tk b/apps/plugins/pdbox/PDa/src/u_main.tk
new file mode 100644
index 0000000000..00cb25c4a2
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/u_main.tk
@@ -0,0 +1,6734 @@
1set pd_nt 1
2# (The above is 0 for unix, 1 for microsoft, and 2 for Mac OSX. The first
3# line is automatically munged by the relevant makefiles.)
4
5# Copyright (c) 1997-1999 Miller Puckette.
6# For information on usage and redistribution, and for a DISCLAIMER OF ALL
7# WARRANTIES, see the file, "LICENSE.txt," in this distribution.
8
9# changed by Thomas Musil 09.2001
10# between "pdtk_graph_dialog -- dialog window for graphs"
11# and "pdtk_array_dialog -- dialog window for arrays"
12# a new dialogbox was inserted, named:
13# "pdtk_iemgui_dialog -- dialog window for iem guis"
14#
15# all this changes are labeled with #######iemlib##########
16
17# Tearoff is set to true by default:
18set pd_tearoff 0
19set menubar 1
20
21set File "F"
22set Windows "W"
23set Edit "E"
24set Find "F"
25set Put "P"
26set Media "M"
27set Help "H"
28
29set color grey16
30set lightcolor grey24
31
32option add *font -*-helvetica-*--bold--9-*
33
34# los colores de la muerte
35
36option add *background $color
37option add *activeBackground $lightcolor
38
39option add *foreground white
40option add *activeForeground white
41
42option add *troughColor $lightcolor
43
44option add *highlightThickness 0
45option add *relief solid startupFile
46
47if {$pd_nt == 1} {
48 global pd_guidir
49 global pd_tearoff
50 set pd_gui2 [string range $argv0 0 [expr [string last \\ $argv0 ] - 1]]
51 regsub -all \\\\ $pd_gui2 / pd_gui3
52 set pd_guidir $pd_gui3/..
53 load $pd_guidir/bin/pdtcl
54 set pd_tearoff 1
55}
56
57if {$pd_nt == 2} {
58 global pd_guidir
59 global pd_tearoff
60 set pd_gui2 [string range $argv0 0 [expr [string last / $argv0 ] - 1]]
61 set pd_guidir $pd_gui2/..
62 load $pd_guidir/bin/pdtcl
63 set pd_tearoff 0
64}
65
66# hack so you can easily test-run this script in linux... define pd_guidir
67# (which is normally defined at startup in pd under linux...)
68
69if {$pd_nt == 0} {
70 if {! [info exists pd_guidir]} {
71 global pd_guidir
72 puts stderr {setting pd_guidir to '.'}
73 set pd_guidir .
74 }
75}
76
77# it's unfortunate but we seem to have to turn off global bindings
78# for Text objects to get control-s and control-t to do what we want for
79# "text" dialogs below. Also we have to get rid of tab's changing the focus.
80
81bind all <Key-Tab> ""
82bind all <<PrevWindow>> ""
83bind Text <Control-t> {}
84bind Text <Control-s> {}
85# puts stderr [bind all]
86
87################## set up main window #########################
88menu .mbar
89canvas .dummy -height 2p -width 6c
90
91frame .controls
92pack .controls .dummy -side top -fill x
93menu .mbar.file -tearoff $pd_tearoff
94.mbar add cascade -label "$File" -menu .mbar.file
95menu .mbar.find -tearoff $pd_tearoff
96.mbar add cascade -label "$Find" -menu .mbar.find
97menu .mbar.windows -postcommand [concat pdtk_fixwindowmenu] -tearoff $pd_tearoff
98menu .mbar.audio -tearoff $pd_tearoff
99if {$pd_nt != 2} {
100 .mbar add cascade -label "$Windows" -menu .mbar.windows
101 .mbar add cascade -label "$Media" -menu .mbar.audio
102} else {
103# Perhaps this is silly, but Mac HIG want "Window Help" as the last menus
104 .mbar add cascade -label "$Media" -menu .mbar.audio
105 .mbar add cascade -label "$Windows" -menu .mbar.windows
106}
107menu .mbar.help -tearoff $pd_tearoff
108.mbar add cascade -label "$Help" -menu .mbar.help
109
110set ctrls_audio_on 0
111set ctrls_meter_on 0
112set ctrls_inlevel 0
113set ctrls_outlevel 0
114
115frame .controls.switches
116checkbutton .controls.switches.audiobutton -text {compute audio} \
117 -variable ctrls_audio_on \
118 -anchor w \
119 -command {pd [concat pd dsp $ctrls_audio_on \;]}
120
121checkbutton .controls.switches.meterbutton -text {peak meters} \
122 -variable ctrls_meter_on \
123 -anchor w \
124 -command {pd [concat pd meters $ctrls_meter_on \;]}
125
126pack .controls.switches.meterbutton .controls.switches.audiobutton -side left
127
128frame .controls.inout
129frame .controls.inout.in
130label .controls.inout.in.label -text IN
131entry .controls.inout.in.level -textvariable ctrls_inlevel -width 3
132button .controls.inout.in.clip -text {CLIP} -state disabled
133pack .controls.inout.in.label .controls.inout.in.level \
134 .controls.inout.in.clip -side top -pady 2
135
136frame .controls.inout.out
137label .controls.inout.out.label -text OUT
138entry .controls.inout.out.level -textvariable ctrls_outlevel -width 3
139button .controls.inout.out.clip -text {CLIP} -state disabled
140pack .controls.inout.out.label .controls.inout.out.level \
141 .controls.inout.out.clip -side top -pady 2
142
143button .controls.dio -text "DIO\nerrors" \
144 -command {pd [concat pd audiostatus \;]}
145
146pack .controls.switches -side bottom -pady 12
147pack .controls.inout.in .controls.inout.out -side left -padx 6
148pack .controls.inout -side left -padx 14
149pack .controls.dio -side right -padx 20
150
151bind . <Control-Key> {pdtk_pd_ctrlkey %W %K 0}
152bind . <Control-Shift-Key> {pdtk_pd_ctrlkey %W %K 1}
153if {$pd_nt == 2} {
154 bind . <Mod1-Key> {pdtk_canvas_ctrlkey %W %K 0}
155 bind . <Mod1-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
156}
157
158
159wm title . "PDa"
160. configure -menu .mbar -width 200 -height 150
161
162############### set up global variables ################################
163
164set untitled_number 1
165set untitled_directory [pwd]
166set saveas_client doggy
167set pd_opendir $untitled_directory
168set pd_undoaction no
169set pd_redoaction no
170set pd_undocanvas no
171
172################ utility functions #########################
173
174proc pdtk_enquote {x} {
175 set foo [string map {"," "" ";" "" \" ""} $x]
176 set foo2 [string map {" " "\\ "} $foo]
177 concat $foo2
178}
179
180proc pdtk_debug {x} {
181 tk_messageBox -message $x -type ok
182}
183
184proc pdtk_watchdog {} {
185 pd [concat pd ping \;]
186 after 2000 {pdtk_watchdog}
187}
188
189proc pdtk_check {x message} {
190 set answer [tk_messageBox \-message $x \-type yesno \-icon question]
191 switch $answer {
192 yes {pd $message} }
193# no {tk_messageBox \-message "cancelled" \-type ok}
194}
195
196set menu_windowlist {}
197
198proc pdtk_fixwindowmenu {} {
199 global menu_windowlist
200 .mbar.windows delete 0 end
201 foreach i $menu_windowlist {
202 .mbar.windows add command -label [lindex $i 0] \
203 -command [concat menu_domenuwindow [lindex $i 1]]
204 menu_fixwindowmenu [lindex $i 1]
205 }
206}
207
208####### Odd little function to make better Mac accelerators #####
209
210proc accel_munge {acc} {
211 global pd_nt
212
213 if {$pd_nt == 2} {
214 if [string is upper [string index $acc end]] {
215 return [format "%s%s" "Shift+" \
216 [string toupper [string map {Ctrl Meta} $acc] end]]
217 } else {
218 return [string toupper [string map {Ctrl Meta} $acc] end]
219 }
220 } else {
221 return $acc
222 }
223}
224
225
226
227############### the "New" menu command ########################
228proc menu_new {} {
229 global untitled_number
230 global untitled_directory
231 pd [concat pd filename Untitled-$untitled_number $untitled_directory \;]
232 pd {
233 #N canvas;
234 #X pop 1;
235 }
236 set untitled_number [expr $untitled_number + 1]
237}
238
239################## the "Open" menu command #########################
240
241proc menu_open {} {
242 global pd_opendir
243
244 set filename [tk_getOpenFile -defaultextension .pd \
245 -filetypes { {{pd files} {.pd}} {{max files} {.pat}}} \
246 -initialdir $pd_opendir]
247
248 if {$filename != ""} {
249 set directory [string range $filename 0 \
250 [expr [string last / $filename ] - 1]]
251 set pd_opendir $directory
252 set basename [string range $filename \
253 [expr [string last / $filename ] + 1] end]
254
255# pd_debug [concat file $filename base $basename dir $directory]
256
257 pd [concat pd open [pdtk_enquote $basename] \
258 [pdtk_enquote $directory]\;]
259 }
260}
261
262################## the "Message" menu command #########################
263proc menu_send {} {
264 toplevel .sendpanel
265 entry .sendpanel.entry -textvariable send_textvariable
266 pack .sendpanel.entry -side bottom -fill both -ipadx 100
267 .sendpanel.entry select from 0
268 .sendpanel.entry select adjust end
269 bind .sendpanel.entry <KeyPress-Return> {
270 pd [concat $send_textvariable \;]
271 after 50 {destroy .sendpanel}
272 }
273 focus .sendpanel.entry
274}
275
276################## the "Quit" menu command #########################
277proc menu_really_quit {} {pd {pd quit;}}
278
279proc menu_quit {} {pd {pd quit;}}
280
281######### the "Pd" menu command, which puts the Pd window on top ########
282proc menu_pop_pd {} {raise .}
283
284######### the "audio" menu command ###############
285proc menu_audio {flag} {pd [concat pd dsp $flag \;]}
286
287######### the "documentation" menu command ###############
288
289set doc_number 1
290
291proc menu_opentext {filename} {
292 global doc_number
293 global pd_guidir
294 global pd_myversion
295 set name [format ".help%d" $doc_number]
296 toplevel $name
297 text $name.text -fg black -relief raised -bd 2 -font -*-courier-bold--normal--12-* \
298 -yscrollcommand "$name.scroll set" -background white
299 scrollbar $name.scroll -command "$name.text yview"
300 pack $name.scroll -side right -fill y
301 pack $name.text -side left -fill both -expand 1
302
303 set f [open $filename]
304 while {![eof $f]} {
305 set bigstring [read $f 1000]
306 regsub -all PD_BASEDIR $bigstring $pd_guidir bigstring2
307 regsub -all PD_VERSION $bigstring2 $pd_myversion bigstring3
308 $name.text insert end $bigstring3
309 }
310 close $f
311 set doc_number [expr $doc_number + 1]
312}
313
314set help_directory $pd_guidir/doc
315
316proc menu_documentation {} {
317 global help_directory
318 global pd_nt
319
320 set filename [tk_getOpenFile -defaultextension .pd \
321 -filetypes { {{documentation} {.pd .txt .htm}} } \
322 -initialdir $help_directory]
323
324 if {$filename != ""} {
325 if {[string first .txt $filename] >= 0} {
326 menu_opentext $filename
327 } elseif {[string first .htm $filename] >= 0} {
328 if {$pd_nt == 0} {
329 exec sh -c \
330 [format "mozilla file:%s || netscape file:%s &\n" \
331 $filename $filename]
332 } elseif {$pd_nt == 2} {
333 puts stderr [format "open %s" $filename]
334 exec sh -c \
335 [format "open %s" $filename]
336 } else {
337 exec rundll32 url.dll,FileProtocolHandler \
338 [format "file:%s" $filename] &
339 }
340 } else {
341 set help_directory [string range $filename 0 \
342 [expr [string last / $filename ] - 1]]
343 set basename [string range $filename \
344 [expr [string last / $filename ] + 1] end]
345 pd [concat pd open [pdtk_enquote $basename] \
346 [pdtk_enquote $help_directory] \;]
347 }
348 }
349}
350
351proc menu_doc_open {subdir basename} {
352 global pd_guidir
353
354 set dirname $pd_guidir/$subdir
355
356 if {[string first .txt $basename] >= 0} {
357 menu_opentext $dirname/$basename
358 } else {
359 pd [concat pd open [pdtk_enquote $basename] \
360 [pdtk_enquote $dirname] \;]
361 }
362}
363
364############# routine to add audio and help menus ###############
365
366proc menu_addstd {mbar} {
367 global pd_apilist
368# the "Audio" menu
369 $mbar.audio add command -label {audio ON} -accelerator [accel_munge "Ctrl+/"] \
370 -command {menu_audio 1}
371 $mbar.audio add command -label {audio OFF} -accelerator [accel_munge "Ctrl+."] \
372 -command {menu_audio 0}
373 for {set x 0} {$x<[llength $pd_apilist]} {incr x} {
374 $mbar.audio add radiobutton -label [lindex [lindex $pd_apilist $x] 0] \
375 -command {menu_audio 0} -variable pd_whichapi \
376 -value [lindex [lindex $pd_apilist $x] 1]\
377 -command {pd [concat pd audio-setapi $pd_whichapi \;]}
378 }
379 $mbar.audio add command -label {Audio settings...} \
380 -command {pd pd audio-properties \;}
381
382 $mbar.audio add command -label {MIDI settings...} \
383 -command {pd pd midi-properties \;}
384 $mbar.audio add command -label {Test Audio and MIDI} \
385 -command {menu_doc_open doc/7.stuff/tools testtone.pd}
386 $mbar.audio add command -label {Load Meter} \
387 -command {menu_doc_open doc/7.stuff/tools load-meter.pd}
388
389
390 $mbar.audio add checkbutton -label "Show Menubar" \
391 -indicatoron true -selectcolor grey85 \
392 -variable menubar
393
394# the "Help" menu
395 $mbar.help add command -label {About Pd} \
396 -command {menu_doc_open doc/1.manual 1.introduction.txt}
397 $mbar.help add command -label {Pure Documentation...} \
398 -command {menu_documentation}
399}
400
401#################### the "File" menu for the Pd window ##############
402
403.mbar.file add command -label New -command {menu_new} \
404 -accelerator [accel_munge "Ctrl+n"]
405.mbar.file add command -label Open -command {menu_open} \
406 -accelerator [accel_munge "Ctrl+o"]
407.mbar.file add separator
408.mbar.file add command -label Message -command {menu_send} \
409 -accelerator [accel_munge "Ctrl+m"]
410.mbar.file add command -label Path... \
411 -command {pd pd start-path-dialog \;}
412.mbar.file add separator
413.mbar.file add command -label Quit -command {menu_quit} \
414 -accelerator [accel_munge "Ctrl+q"]
415
416#################### the "Find" menu for the Pd window ##############
417.mbar.find add command -label {last error?} -command {menu_finderror}
418
419########### functions for menu functions on document windows ########
420
421proc menu_save {name} {
422 pdtk_canvas_checkgeometry $name
423 pd [concat $name menusave \;]
424}
425
426proc menu_saveas {name} {
427 pdtk_canvas_checkgeometry $name
428 pd [concat $name menusaveas \;]
429}
430
431proc menu_print {name} {
432 set filename [tk_getSaveFile -initialfile pd.ps \
433 -defaultextension .ps \
434 -filetypes { {{postscript} {.ps}} }]
435
436 if {$filename != ""} {
437 $name.c postscript -file $filename
438 }
439}
440
441proc menu_close {name} {
442 pd [concat $name menuclose \;]
443}
444
445proc menu_undo {name} {
446 global pd_undoaction
447 global pd_redoaction
448 global pd_undocanvas
449 if {$name == $pd_undocanvas && $pd_undoaction != "no"} {
450 pd [concat $name undo \;]
451 }
452}
453
454proc menu_redo {name} {
455 global pd_undoaction
456 global pd_redoaction
457 global pd_undocanvas
458 if {$name == $pd_undocanvas && $pd_redoaction != "no"} {
459 pd [concat $name redo \;]
460 }
461}
462
463proc menu_cut {name} {
464 pd [concat $name cut \;]
465}
466
467proc menu_copy {name} {
468 pd [concat $name copy \;]
469}
470
471proc menu_paste {name} {
472 pd [concat $name paste \;]
473}
474
475proc menu_duplicate {name} {
476 pd [concat $name duplicate \;]
477}
478
479proc menu_selectall {name} {
480 pd [concat $name selectall \;]
481}
482
483proc menu_texteditor {name} {
484 pd [concat $name texteditor \;]
485}
486
487proc menu_font {name} {
488 pd [concat $name menufont \;]
489}
490
491proc menu_tidyup {name} {
492 pd [concat $name tidy \;]
493}
494
495proc menu_editmode {name} {
496 pd [concat $name editmode 0 \;]
497}
498
499proc menu_object {name accel} {
500 pd [concat $name obj $accel \;]
501}
502
503proc menu_message {name accel} {
504 pd [concat $name msg $accel \;]
505}
506
507proc menu_floatatom {name accel} {
508 pd [concat $name floatatom $accel \;]
509}
510
511proc menu_symbolatom {name accel} {
512 pd [concat $name symbolatom $accel \;]
513}
514
515proc menu_comment {name accel} {
516 pd [concat $name text $accel \;]
517}
518
519proc menu_graph {name} {
520 pd [concat $name graph \;]
521}
522
523proc menu_array {name} {
524 pd [concat $name menuarray \;]
525}
526
527############iemlib##################
528proc menu_bng {name accel} {
529 pd [concat $name bng $accel \;]
530}
531
532proc menu_toggle {name accel} {
533 pd [concat $name toggle $accel \;]
534}
535
536proc menu_numbox {name accel} {
537 pd [concat $name numbox $accel \;]
538}
539
540proc menu_vslider {name accel} {
541 pd [concat $name vslider $accel \;]
542}
543
544proc menu_hslider {name accel} {
545 pd [concat $name hslider $accel \;]
546}
547
548proc menu_hradio {name accel} {
549 pd [concat $name hradio $accel \;]
550}
551
552proc menu_vradio {name accel} {
553 pd [concat $name vradio $accel \;]
554}
555
556proc menu_vumeter {name accel} {
557 pd [concat $name vumeter $accel \;]
558}
559
560proc menu_mycnv {name accel} {
561 pd [concat $name mycnv $accel \;]
562}
563
564############iemlib##################
565
566# correct edit menu, enabling or disabling undo/redo
567# LATER also cut/copy/paste
568proc menu_fixeditmenu {name} {
569 global pd_undoaction
570 global pd_redoaction
571 global pd_undocanvas
572# puts stderr [concat menu_fixeditmenu $name $pd_undocanvas $pd_undoaction]
573 if {$name == $pd_undocanvas && $pd_undoaction != "no"} {
574 $name.m.edit entryconfigure "Undo*" -state normal \
575 -label [concat "Undo " $pd_undoaction]
576 } else {
577 $name.m.edit entryconfigure "Undo*" -state disabled -label "Undo"
578 }
579 if {$name == $pd_undocanvas && $pd_redoaction != "no"} {
580 $name.m.edit entryconfigure "Redo*" -state normal\
581 -label [concat "Redo " $pd_redoaction]
582 } else {
583 $name.m.edit entryconfigure "Redo*" -state disabled
584 }
585}
586
587# message from Pd to update the currently available undo/redo action
588proc pdtk_undomenu {name undoaction redoaction} {
589 global pd_undoaction
590 global pd_redoaction
591 global pd_undocanvas
592# puts stderr [concat pdtk_undomenu $name $undoaction $redoaction]
593 set pd_undocanvas $name
594 set pd_undoaction $undoaction
595 set pd_redoaction $redoaction
596 if {$name != "nobody"} {
597# unpleasant way of avoiding a more unpleasant bug situation --atl 2002.11.25
598 menu_fixeditmenu $name
599 }
600}
601
602proc menu_windowparent {name} {
603 pd [concat $name findparent \;]
604}
605
606proc menu_findagain {name} {
607 pd [concat $name findagain \;]
608}
609
610proc menu_finderror {} {
611 pd [concat pd finderror \;]
612}
613
614proc menu_domenuwindow {i} {
615 raise $i
616}
617
618proc menu_fixwindowmenu {name} {
619 global menu_windowlist
620 global pd_tearoff
621 global menubar
622
623 if { $menubar == 1 } {
624 $name.m.windows add command
625 if $pd_tearoff {
626 $name.m.windows delete 4 end
627 } else {
628 $name.m.windows delete 3 end
629 }
630 foreach i $menu_windowlist {
631 $name.m.windows add command -label [lindex $i 0] \
632 -command [concat menu_domenuwindow [lindex $i 1]]
633 }
634 }
635}
636
637################## the "find" menu item ###################
638
639set find_canvas nobody
640set find_string ""
641set find_count 1
642
643proc find_apply {name} {
644 global find_string
645 global find_canvas
646 regsub -all \; $find_string " _semi_ " find_string2
647 regsub -all \, $find_string2 " _comma_ " find_string3
648# puts stderr [concat $find_canvas find $find_string3 \
649# \;]
650 pd [concat $find_canvas find $find_string3 \
651 \;]
652 after 50 destroy $name
653}
654
655proc find_cancel {name} {
656 after 50 destroy $name
657}
658
659proc menu_findobject {canvas} {
660 global find_string
661 global find_canvas
662 global find_count
663
664 set name [format ".find%d" $find_count]
665 set find_count [expr $find_count + 1]
666
667 set find_canvas $canvas
668
669 toplevel $name
670
671 label $name.label -text {find...}
672 pack $name.label -side top
673
674 entry $name.entry -textvariable find_string
675 pack $name.entry -side top
676
677 frame $name.buttonframe
678 pack $name.buttonframe -side bottom -fill x -pady 2m
679 button $name.buttonframe.cancel -text {Cancel}\
680 -command "find_cancel $name"
681 button $name.buttonframe.ok -text {OK}\
682 -command "find_apply $name"
683 pack $name.buttonframe.cancel -side left -expand 1
684 pack $name.buttonframe.ok -side left -expand 1
685
686 $name.entry select from 0
687 $name.entry select adjust end
688 bind $name.entry <KeyPress-Return> [ concat find_apply $name]
689 focus $name.entry
690}
691
692
693
694proc pdtk_canvas_menubar {name width height geometry editable} {
695 global pd_opendir
696 global pd_tearoff
697 global pd_nt
698
699 global File Edit Find Put Windows Media Help
700
701
702 menu $name.m.file -tearoff $pd_tearoff
703 $name.m add cascade -label "$File" -menu $name.m.file
704
705 $name.m.file add command -label New -command {menu_new} \
706 -accelerator [accel_munge "Ctrl+n"]
707
708 $name.m.file add command -label Open -command {menu_open} \
709 -accelerator [accel_munge "Ctrl+o"]
710
711 $name.m.file add separator
712 $name.m.file add command -label Message -command {menu_send} \
713 -accelerator [accel_munge "Ctrl+m"]
714
715 $name.m.file add command -label Path... \
716 -command {pd pd start-path-dialog \;}
717
718 $name.m.file add separator
719 $name.m.file add command -label Close \
720 -command [concat menu_close $name] \
721 -accelerator [accel_munge "Ctrl+w"]
722
723 $name.m.file add command -label Save -command [concat menu_save $name] \
724 -accelerator [accel_munge "Ctrl+s"]
725
726 $name.m.file add command -label "Save as..." \
727 -command [concat menu_saveas $name] \
728 -accelerator [accel_munge "Ctrl+S"]
729
730 $name.m.file add command -label Print -command [concat menu_print $name] \
731 -accelerator [accel_munge "Ctrl+p"]
732
733 $name.m.file add separator
734
735 $name.m.file add command -label Quit -command {menu_quit} \
736 -accelerator [accel_munge "Ctrl+q"]
737
738# the edit menu
739 menu $name.m.edit -postcommand [concat menu_fixeditmenu $name] -tearoff $pd_tearoff
740 $name.m add cascade -label $Edit -menu $name.m.edit
741
742 $name.m.edit add command -label Undo -command [concat menu_undo $name] \
743 -accelerator [accel_munge "Ctrl+z"]
744
745 $name.m.edit add command -label Redo -command [concat menu_redo $name] \
746 -accelerator [accel_munge "Ctrl+Z"]
747
748 $name.m.edit add separator
749
750 $name.m.edit add command -label Cut -command [concat menu_cut $name] \
751 -accelerator [accel_munge "Ctrl+x"]
752
753 $name.m.edit add command -label Copy -command [concat menu_copy $name] \
754 -accelerator [accel_munge "Ctrl+c"]
755
756 $name.m.edit add command -label Paste \
757 -command [concat menu_paste $name] \
758 -accelerator [accel_munge "Ctrl+v"]
759
760 $name.m.edit add command -label Duplicate \
761 -command [concat menu_duplicate $name] \
762 -accelerator [accel_munge "Ctrl+d"]
763
764 $name.m.edit add command -label {Select all} \
765 -command [concat menu_selectall $name] \
766 -accelerator [accel_munge "Ctrl+a"]
767
768 $name.m.edit add separator
769
770 $name.m.edit add command -label {Text Editor} \
771 -command [concat menu_texteditor $name] \
772 -accelerator [accel_munge "Ctrl+t"]
773
774 $name.m.edit add command -label Font \
775 -command [concat menu_font $name]
776
777 $name.m.edit add command -label {Tidy Up} \
778 -command [concat menu_tidyup $name]
779
780 $name.m.edit add separator
781
782############iemlib##################
783# instead of "red = #BC3C60" we take "grey85", so there is no difference,
784# if widget is selected or not.
785
786 $name.m.edit add checkbutton -label "Edit mode" \
787 -indicatoron true -selectcolor grey85 \
788 -command [concat menu_editmode $name] \
789 -accelerator [accel_munge "Ctrl+e"]
790
791 if { $editable == 0 } {
792 $name.m.edit entryconfigure "Edit mode" -indicatoron false }
793
794############iemlib##################
795
796# the put menu
797 menu $name.m.put -tearoff $pd_tearoff
798 $name.m add cascade -label $Put -menu $name.m.put
799
800 $name.m.put add command -label Object \
801 -command [concat menu_object $name 0] \
802 -accelerator [accel_munge "Ctrl+1"]
803
804 $name.m.put add command -label Message \
805 -command [concat menu_message $name 0] \
806 -accelerator [accel_munge "Ctrl+2"]
807
808 $name.m.put add command -label Number \
809 -command [concat menu_floatatom $name 0] \
810 -accelerator [accel_munge "Ctrl+3"]
811
812 $name.m.put add command -label Symbol \
813 -command [concat menu_symbolatom $name 0] \
814 -accelerator [accel_munge "Ctrl+4"]
815
816 $name.m.put add command -label Comment \
817 -command [concat menu_comment $name 0] \
818 -accelerator [accel_munge "Ctrl+5"]
819
820 $name.m.put add separator
821
822############iemlib##################
823
824 $name.m.put add command -label Bang \
825 -command [concat menu_bng $name 0] \
826 -accelerator [accel_munge "Alt+b"]
827
828 $name.m.put add command -label Toggle \
829 -command [concat menu_toggle $name 0] \
830 -accelerator [accel_munge "Alt+t"]
831
832 $name.m.put add command -label Number2 \
833 -command [concat menu_numbox $name 0] \
834 -accelerator [accel_munge "Alt+n"]
835
836 $name.m.put add command -label Vslider \
837 -command [concat menu_vslider $name 0] \
838 -accelerator [accel_munge "Alt+v"]
839
840 $name.m.put add command -label Hslider \
841 -command [concat menu_hslider $name 0] \
842 -accelerator [accel_munge "Alt+h"]
843
844 $name.m.put add command -label Vradio \
845 -command [concat menu_vradio $name 0] \
846 -accelerator [accel_munge "Alt+d"]
847
848 $name.m.put add command -label Hradio \
849 -command [concat menu_hradio $name 0] \
850 -accelerator [accel_munge "Alt+i"]
851
852 $name.m.put add command -label VU \
853 -command [concat menu_vumeter $name 0] \
854 -accelerator [accel_munge "Alt+u"]
855
856 $name.m.put add command -label Canvas \
857 -command [concat menu_mycnv $name 0] \
858 -accelerator [accel_munge "Alt+c"]
859
860############iemlib##################
861
862 $name.m.put add separator
863
864 $name.m.put add command -label Graph \
865 -command [concat menu_graph $name]
866
867 $name.m.put add command -label Array \
868 -command [concat menu_array $name]
869
870# the find menu
871 menu $name.m.find -tearoff $pd_tearoff
872 $name.m add cascade -label "$Find" -menu $name.m.find
873
874 $name.m.find add command -label {Find...} \
875 -accelerator [accel_munge "Ctrl+f"] \
876 -command [concat menu_findobject $name]
877 $name.m.find add command -label {Find Again} \
878 -accelerator [accel_munge "Ctrl+g"] \
879 -command [concat menu_findagain $name]
880 $name.m.find add command -label {Find last error} \
881 -command [concat menu_finderror]
882
883# the window menu
884 menu $name.m.windows -postcommand [concat menu_fixwindowmenu $name] \
885 -tearoff $pd_tearoff
886
887 $name.m.windows add command -label {parent window}\
888 -command [concat menu_windowparent $name]
889 $name.m.windows add command -label {Pd window} -command menu_pop_pd
890 $name.m.windows add separator
891
892# the audio menu
893 menu $name.m.audio -tearoff $pd_tearoff
894
895 if {$pd_nt != 2} {
896 $name.m add cascade -label $Windows -menu $name.m.windows
897 $name.m add cascade -label $Media -menu $name.m.audio
898 } else {
899 $name.m add cascade -label $Media -menu $name.m.audio
900 $name.m add cascade -label $Windows -menu $name.m.windows
901 }
902
903# the help menu
904 menu $name.m.help -tearoff $pd_tearoff
905 $name.m add cascade -label $Help -menu $name.m.help
906
907 menu_addstd $name.m
908}
909
910
911############# pdtk_canvas_new -- create a new canvas ###############
912proc pdtk_canvas_new {name width height geometry editable} {
913 global pd_opendir
914 global pd_tearoff
915 global pd_nt
916 global menubar
917
918 toplevel $name -menu $name.m
919# puts stderr [concat geometry: $geometry]
920 wm geometry $name $geometry
921 wm minsize $name 1 1
922
923 canvas $name.c -width $width -height $height -background white \
924 -yscrollcommand "$name.scrollvert set" \
925 -xscrollcommand "$name.scrollhort set" \
926 -scrollregion [concat 0 0 $width $height]
927
928
929 scrollbar $name.scrollvert -command "$name.c yview" -width 7
930 scrollbar $name.scrollhort -command "$name.c xview" \
931 -orient horizontal -width 7
932
933 pack $name.scrollhort -side bottom -fill x
934 pack $name.scrollvert -side right -fill y
935 pack $name.c -side left -expand 1 -fill both
936
937# the menubar
938
939 menu $name.m
940
941 if { $menubar == 1 } {
942 pdtk_canvas_menubar $name $width $height $geometry $editable
943 }
944
945# the popup menu
946 menu $name.popup -tearoff false
947 $name.popup add command -label {Properties} \
948 -command [concat popup_action $name 0]
949 $name.popup add command -label {Open} \
950 -command [concat popup_action $name 1]
951 $name.popup add command -label {Help} \
952 -command [concat popup_action $name 2]
953
954# WM protocol
955 wm protocol $name WM_DELETE_WINDOW [concat menu_close $name]
956
957# bindings.
958# this is idiotic -- how do you just sense what mod keys are down and
959# pass them on? I can't find it anywhere.
960# Here we encode shift as 1, control 2, alt 4, in agreement
961# with definitions in g_canvas.c. The third button gets "8" but we don't
962# bother with modifiers there.
963# We don't handle multiple clicks yet.
964
965 bind $name.c <Button> {pdtk_canvas_click %W %x %y %b 0}
966 bind $name.c <Shift-Button> {pdtk_canvas_click %W %x %y %b 1}
967 bind $name.c <Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 3}
968 bind $name.c <Alt-Button> {pdtk_canvas_click %W %x %y %b 4}
969 bind $name.c <Alt-Shift-Button> {pdtk_canvas_click %W %x %y %b 5}
970 bind $name.c <Alt-Control-Button> {pdtk_canvas_click %W %x %y %b 6}
971 bind $name.c <Alt-Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 7}
972 global pd_nt
973 if {$pd_nt == 2} {
974 bind $name.c <Button-2> {pdtk_canvas_click %W %x %y %b 8}
975 bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 8}
976 } else {
977 bind $name.c <Button-3> {pdtk_canvas_click %W %x %y %b 8}
978 bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 2}
979 }
980# change mac to right-click, not middle click -atl 2002.09.02
981
982 bind $name.c <ButtonRelease> {pdtk_canvas_mouseup %W %x %y %b}
983 bind $name.c <Control-Key> {pdtk_canvas_ctrlkey %W %K 0}
984 bind $name.c <Control-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
985 bind $name.c <Alt-Key> {pdtk_canvas_altkey %W %K %A}
986# bind $name.c <Mod1-Key> {puts stderr [concat mod1 %W %K %A]}
987 if {$pd_nt == 2} {
988 bind $name.c <Mod1-Key> {pdtk_canvas_ctrlkey %W %K 0}
989 bind $name.c <Mod1-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
990 }
991 bind $name.c <Key> {pdtk_canvas_key %W %K %A 0}
992 bind $name.c <Shift-Key> {pdtk_canvas_key %W %K %A 1}
993 bind $name.c <KeyRelease> {pdtk_canvas_keyup %W %K %A}
994 bind $name.c <Motion> {pdtk_canvas_motion %W %x %y 0}
995 bind $name.c <Alt-Motion> {pdtk_canvas_motion %W %x %y 4}
996 bind $name.c <Map> {pdtk_canvas_map %W}
997 bind $name.c <Unmap> {pdtk_canvas_unmap %W}
998 focus $name.c
999# puts stderr "all done"
1000# after 1 [concat raise $name]
1001}
1002
1003#################### event binding procedures ################
1004
1005#get the name of the toplevel window for a canvas; this is also
1006#the name of the canvas object in Pd.
1007
1008proc canvastosym {name} {
1009 string range $name 0 [expr [string length $name] - 3]
1010}
1011
1012set pdtk_lastcanvasconfigured ""
1013set pdtk_lastcanvasconfiguration ""
1014
1015proc pdtk_canvas_checkgeometry {topname} {
1016 set boo [winfo geometry $topname.c]
1017 set boo2 [wm geometry $topname]
1018 global pdtk_lastcanvasconfigured
1019 global pdtk_lastcanvasconfiguration
1020 if {$topname != $pdtk_lastcanvasconfigured || \
1021 $boo != $pdtk_lastcanvasconfiguration} {
1022 set pdtk_lastcanvasconfigured $topname
1023 set pdtk_lastcanvasconfiguration $boo
1024 pd $topname relocate $boo $boo2 \;
1025 }
1026}
1027
1028proc pdtk_canvas_click {name x y b f} {
1029# puts stderr [concat got $f]
1030 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b $f \;
1031}
1032
1033proc pdtk_canvas_shiftclick {name x y b} {
1034 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 1 \;
1035}
1036
1037proc pdtk_canvas_ctrlclick {name x y b} {
1038 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 2 \;
1039}
1040
1041proc pdtk_canvas_altclick {name x y b} {
1042 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 3 \;
1043}
1044
1045proc pdtk_canvas_dblclick {name x y b} {
1046 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 4 \;
1047}
1048
1049set pdtk_canvas_mouseup_name 0
1050set pdtk_canvas_mouseup_xminval 0
1051set pdtk_canvas_mouseup_xmaxval 0
1052set pdtk_canvas_mouseup_yminval 0
1053set pdtk_canvas_mouseup_ymaxval 0
1054
1055proc pdtk_canvas_mouseup {name x y b} {
1056 pd [concat [canvastosym $name] mouseup [$name canvasx $x] \
1057 [$name canvasy $y] $b \;]
1058
1059# we use the mouseup event to update scrollbar ranges and recheck the
1060# geometry of the window since I haven't taken the time to figure out
1061# how to do it right.
1062
1063 global pdtk_canvas_mouseup_name
1064 global pdtk_canvas_mouseup_xminval
1065 global pdtk_canvas_mouseup_xmaxval
1066 global pdtk_canvas_mouseup_yminval
1067 global pdtk_canvas_mouseup_ymaxval
1068
1069 set size [$name bbox all]
1070 if {$size != ""} {
1071 set xminval 0
1072 set yminval 0
1073 set xmaxval 100
1074 set ymaxval 100
1075 set x1 [lindex $size 0]
1076 set x2 [lindex $size 2]
1077 set y1 [lindex $size 1]
1078 set y2 [lindex $size 3]
1079
1080 if {$x1 < 0} {set xminval $x1}
1081 if {$y1 < 0} {set yminval $y1}
1082
1083 if {$x2 > 100} {set xmaxval $x2}
1084 if {$y2 > 100} {set ymaxval $y2}
1085
1086 if {$pdtk_canvas_mouseup_name != $name || \
1087 $pdtk_canvas_mouseup_xminval != $xminval || \
1088 $pdtk_canvas_mouseup_xmaxval != $xmaxval || \
1089 $pdtk_canvas_mouseup_yminval != $yminval || \
1090 $pdtk_canvas_mouseup_ymaxval != $ymaxval } {
1091
1092 set newsize "$xminval $yminval $xmaxval $ymaxval"
1093 $name configure -scrollregion $newsize
1094 set pdtk_canvas_mouseup_name $name
1095 set pdtk_canvas_mouseup_xminval $xminval
1096 set pdtk_canvas_mouseup_xmaxval $xmaxval
1097 set pdtk_canvas_mouseup_yminval $yminval
1098 set pdtk_canvas_mouseup_ymaxval $ymaxval
1099 }
1100
1101 }
1102 pdtk_canvas_checkgeometry [canvastosym $name]
1103}
1104
1105proc pdtk_canvas_key {name key iso shift} {
1106# puts stderr [concat down key= $key iso= $iso]
1107# .controls.switches.meterbutton configure -text $key
1108# HACK for MAC OSX -- backspace seems different; I don't understand why.
1109# invesigate this LATER...
1110 global pd_nt
1111 if {$pd_nt == 2} {
1112 if {$key == "BackSpace"} {
1113 set key 8
1114 set keynum 8
1115 }
1116 if {$key == "Delete"} {
1117 set key 8
1118 set keynum 8
1119 }
1120 }
1121 if {$key == "KP_Delete"} {
1122 set key 127
1123 set keynum 127
1124 }
1125 if {$iso != ""} {
1126 scan $iso %c keynum
1127 pd [canvastosym $name] key 1 $keynum $shift\;
1128 } else {
1129 pd [canvastosym $name] key 1 $key $shift\;
1130 }
1131}
1132
1133proc pdtk_canvas_keyup {name key iso} {
1134# puts stderr [concat up key= $key iso= $iso]
1135 if {$iso != ""} {
1136 scan $iso %c keynum
1137 pd [canvastosym $name] key 0 $keynum 0 \;
1138 } else {
1139 pd [canvastosym $name] key 0 $key 0 \;
1140 }
1141}
1142
1143proc pdtk_canvas_altkey {name key iso} {
1144# puts stderr [concat alt-key $iso]
1145############iemlib##################
1146 set topname [string trimright $name .c]
1147 if {$key == "b" || $key == "B"} {menu_bng $topname 1}
1148 if {$key == "t" || $key == "T"} {menu_toggle $topname 1}
1149 if {$key == "n" || $key == "N"} {menu_numbox $topname 1}
1150 if {$key == "v" || $key == "V"} {menu_vslider $topname 1}
1151 if {$key == "h" || $key == "H"} {menu_hslider $topname 1}
1152 if {$key == "i" || $key == "I"} {menu_hradio $topname 1}
1153 if {$key == "d" || $key == "D"} {menu_vradio $topname 1}
1154 if {$key == "u" || $key == "U"} {menu_vumeter $topname 1}
1155 if {$key == "c" || $key == "C"} {menu_mycnv $topname 1}
1156############iemlib##################
1157}
1158
1159proc pdtk_canvas_ctrlkey {name key shift} {
1160# first get rid of ".c" suffix; we'll refer to the toplevel instead
1161 set topname [string trimright $name .c]
1162# puts stderr [concat ctrl-key $key $topname]
1163
1164 if {$key == "n" || $key == "N"} {menu_new}
1165 if {$key == "o" || $key == "O"} {menu_open}
1166 if {$key == "m" || $key == "M"} {menu_send}
1167 if {$key == "q" || $key == "Q"} {
1168 if {$shift == 1} {menu_really_quit} else {menu_quit}
1169 }
1170 if {$key == "s" || $key == "S"} {
1171 if {$shift == 1} {menu_saveas $topname} else {menu_save $topname}
1172 }
1173 if {$key == "z" || $key == "Z"} {
1174 if {$shift == 1} {menu_redo $topname} else {menu_undo $topname}
1175 }
1176 if {$key == "w" || $key == "W"} {menu_close $topname}
1177 if {$key == "p" || $key == "P"} {menu_print $topname}
1178 if {$key == "x" || $key == "X"} {menu_cut $topname}
1179 if {$key == "c" || $key == "C"} {menu_copy $topname}
1180 if {$key == "v" || $key == "V"} {menu_paste $topname}
1181 if {$key == "d" || $key == "D"} {menu_duplicate $topname}
1182 if {$key == "a" || $key == "A"} {menu_selectall $topname}
1183 if {$key == "t" || $key == "T"} {menu_texteditor $topname}
1184 if {$key == "f" || $key == "F"} {menu_findobject $topname}
1185 if {$key == "g" || $key == "G"} {menu_findagain $topname}
1186 if {$key == "1"} {menu_object $topname 1}
1187 if {$key == "2"} {menu_message $topname 1}
1188 if {$key == "3"} {menu_floatatom $topname 1}
1189 if {$key == "4"} {menu_symbolatom $topname 1}
1190 if {$key == "5"} {menu_comment $topname 1}
1191 if {$key == "slash"} {menu_audio 1}
1192 if {$key == "period"} {menu_audio 0}
1193 if {$key == "e" || $key == "E"} {menu_editmode $topname}
1194}
1195
1196proc pdtk_canvas_motion {name x y mods} {
1197# puts stderr [concat [canvastosym $name] $name $x $y]
1198 pd [canvastosym $name] motion [$name canvasx $x] [$name canvasy $y] $mods \;
1199}
1200
1201# "map" event tells us when the canvas becomes visible (arg is "0") or
1202# invisible (arg is ""). Invisibility means the Window Manager has minimized
1203# us. We don't get a final "unmap" event when we destroy the window.
1204proc pdtk_canvas_map {name} {
1205# puts stderr [concat map $name]
1206 pd [canvastosym $name] map 1 \;
1207}
1208
1209proc pdtk_canvas_unmap {name} {
1210# puts stderr [concat unmap $name]
1211 pd [canvastosym $name] map 0 \;
1212}
1213
1214set saveas_dir nowhere
1215
1216############ pdtk_canvas_saveas -- run a saveas dialog ##############
1217
1218proc pdtk_canvas_saveas {name initfile initdir} {
1219 set filename [tk_getSaveFile -initialfile $initfile \
1220 -initialdir $initdir -defaultextension .pd \
1221 -filetypes { {{pd files} {.pd}} {{max files} {.pat}} }]
1222
1223 if {$filename != ""} {
1224 set directory [string range $filename 0 \
1225 [expr [string last / $filename ] - 1]]
1226 set basename [string range $filename \
1227 [expr [string last / $filename ] + 1] end]
1228 pd [concat $name savetofile [pdtk_enquote $basename] \
1229 [pdtk_enquote $directory] \;]
1230# pd [concat $name savetofile $basename $directory \;]
1231 }
1232}
1233
1234############ pdtk_canvas_dofont -- run a font and resize dialog #########
1235
1236set fontsize 0
1237set stretchval 0
1238set whichstretch 0
1239
1240proc dofont_apply {name} {
1241 global fontsize
1242 global stretchval
1243 global whichstretch
1244 set cmd [concat $name font $fontsize $stretchval $whichstretch \;]
1245# puts stderr $cmd
1246 pd $cmd
1247}
1248
1249proc dofont_cancel {name} {
1250 set cmd [concat $name cancel \;]
1251# puts stderr $cmd
1252 pd $cmd
1253}
1254
1255proc pdtk_canvas_dofont {name initsize} {
1256
1257 global fontsize
1258 set fontsize $initsize
1259
1260 global stretchval
1261 set stretchval 100
1262
1263 global whichstretch
1264 set whichstretch 1
1265
1266 toplevel $name
1267 wm title $name {FONT BOMB}
1268 wm protocol $name WM_DELETE_WINDOW [concat dofont_cancel $name]
1269
1270 frame $name.buttonframe
1271 pack $name.buttonframe -side bottom -fill x -pady 2m
1272 button $name.buttonframe.cancel -text {Cancel}\
1273 -command "dofont_cancel $name"
1274 button $name.buttonframe.ok -text {Do it}\
1275 -command "dofont_apply $name"
1276 pack $name.buttonframe.cancel -side left -expand 1
1277 pack $name.buttonframe.ok -side left -expand 1
1278
1279 frame $name.radiof
1280 pack $name.radiof -side left
1281
1282 label $name.radiof.label -text {Font Size:}
1283 pack $name.radiof.label -side top
1284
1285 radiobutton $name.radiof.radio8 -value 8 -variable fontsize -text "8"
1286 radiobutton $name.radiof.radio10 -value 10 -variable fontsize -text "10"
1287 radiobutton $name.radiof.radio12 -value 12 -variable fontsize -text "12"
1288 radiobutton $name.radiof.radio16 -value 16 -variable fontsize -text "16"
1289 radiobutton $name.radiof.radio24 -value 24 -variable fontsize -text "24"
1290 radiobutton $name.radiof.radio36 -value 36 -variable fontsize -text "36"
1291 pack $name.radiof.radio8 -side top -anchor w
1292 pack $name.radiof.radio10 -side top -anchor w
1293 pack $name.radiof.radio12 -side top -anchor w
1294 pack $name.radiof.radio16 -side top -anchor w
1295 pack $name.radiof.radio24 -side top -anchor w
1296 pack $name.radiof.radio36 -side top -anchor w
1297
1298 frame $name.stretchf
1299 pack $name.stretchf -side left
1300
1301 label $name.stretchf.label -text {Stretch:}
1302 pack $name.stretchf.label -side top
1303
1304 entry $name.stretchf.entry -textvariable stretchval -width 5
1305 pack $name.stretchf.entry -side left
1306
1307 radiobutton $name.stretchf.radio1 \
1308 -value 1 -variable whichstretch -text "X and Y"
1309 radiobutton $name.stretchf.radio2 \
1310 -value 2 -variable whichstretch -text "X only"
1311 radiobutton $name.stretchf.radio3 \
1312 -value 3 -variable whichstretch -text "Y only"
1313
1314 pack $name.stretchf.radio1 -side top -anchor w
1315 pack $name.stretchf.radio2 -side top -anchor w
1316 pack $name.stretchf.radio3 -side top -anchor w
1317
1318}
1319
1320############ pdtk_gatom_dialog -- run a gatom dialog #########
1321
1322# see graph_apply, etc., for comments about handling variable names here...
1323
1324proc gatom_escape {sym} {
1325 if {[string length $sym] == 0} {
1326 set ret "-"
1327# puts stderr [concat escape1 $sym $ret]
1328 } else {
1329 if {[string equal -length 1 $sym "-"]} {
1330 set ret [string replace $sym 0 0 "--"]
1331# puts stderr [concat escape $sym $ret]
1332 } else {
1333 if {[string equal -length 1 $sym "$"]} {
1334 set ret [string replace $sym 0 0 "#"]
1335# puts stderr [concat unescape $sym $ret]
1336 } else {
1337 set ret $sym
1338# puts stderr [concat escape $sym "no change"]
1339 }
1340 }
1341 }
1342 concat $ret
1343}
1344
1345proc gatom_unescape {sym} {
1346 if {[string equal -length 1 $sym "-"]} {
1347 set ret [string replace $sym 0 0 ""]
1348# puts stderr [concat unescape $sym $ret]
1349 } else {
1350 if {[string equal -length 1 $sym "#"]} {
1351 set ret [string replace $sym 0 0 "$"]
1352# puts stderr [concat unescape $sym $ret]
1353 } else {
1354 set ret $sym
1355# puts stderr [concat unescape $sym "no change"]
1356 }
1357 }
1358 concat $ret
1359}
1360
1361proc dogatom_apply {id} {
1362 set vid [string trimleft $id .]
1363
1364 set var_gatomwidth [concat gatomwidth_$vid]
1365 global $var_gatomwidth
1366 set var_gatomlo [concat gatomlo_$vid]
1367 global $var_gatomlo
1368 set var_gatomhi [concat gatomhi_$vid]
1369 global $var_gatomhi
1370 set var_gatomwherelabel [concat gatomwherelabel_$vid]
1371 global $var_gatomwherelabel
1372 set var_gatomlabel [concat gatomlabel_$vid]
1373 global $var_gatomlabel
1374 set var_gatomsymfrom [concat gatomsymfrom_$vid]
1375 global $var_gatomsymfrom
1376 set var_gatomsymto [concat gatomsymto_$vid]
1377 global $var_gatomsymto
1378
1379# set cmd [concat $id param $gatomwidth $gatomlo $gatomhi \;]
1380
1381 set cmd [concat $id param \
1382 [eval concat $$var_gatomwidth] \
1383 [eval concat $$var_gatomlo] \
1384 [eval concat $$var_gatomhi] \
1385 [eval gatom_escape $$var_gatomlabel] \
1386 [eval concat $$var_gatomwherelabel] \
1387 [eval gatom_escape $$var_gatomsymfrom] \
1388 [eval gatom_escape $$var_gatomsymto] \
1389 \;]
1390
1391# puts stderr $cmd
1392 pd $cmd
1393}
1394
1395proc dogatom_cancel {name} {
1396 set cmd [concat $name cancel \;]
1397# puts stderr $cmd
1398 pd $cmd
1399}
1400
1401proc dogatom_ok {name} {
1402 dogatom_apply $name
1403 dogatom_cancel $name
1404}
1405
1406proc pdtk_gatom_dialog {id initwidth initlo inithi \
1407 wherelabel label symfrom symto} {
1408
1409 set vid [string trimleft $id .]
1410
1411 set var_gatomwidth [concat gatomwidth_$vid]
1412 global $var_gatomwidth
1413 set var_gatomlo [concat gatomlo_$vid]
1414 global $var_gatomlo
1415 set var_gatomhi [concat gatomhi_$vid]
1416 global $var_gatomhi
1417 set var_gatomwherelabel [concat gatomwherelabel_$vid]
1418 global $var_gatomwherelabel
1419 set var_gatomlabel [concat gatomlabel_$vid]
1420 global $var_gatomlabel
1421 set var_gatomsymfrom [concat gatomsymfrom_$vid]
1422 global $var_gatomsymfrom
1423 set var_gatomsymto [concat gatomsymto_$vid]
1424 global $var_gatomsymto
1425
1426 set $var_gatomwidth $initwidth
1427 set $var_gatomlo $initlo
1428 set $var_gatomhi $inithi
1429 set $var_gatomwherelabel $wherelabel
1430 set $var_gatomlabel [gatom_unescape $label]
1431 set $var_gatomsymfrom [gatom_unescape $symfrom]
1432 set $var_gatomsymto [gatom_unescape $symto]
1433
1434 toplevel $id
1435 wm title $id {Atom}
1436 wm protocol $id WM_DELETE_WINDOW [concat dogatom_cancel $id]
1437
1438 frame $id.buttonframe
1439 pack $id.buttonframe -side bottom -fill x -pady 2m
1440 button $id.buttonframe.cancel -text {Cancel}\
1441 -command "dogatom_cancel $id"
1442 button $id.buttonframe.apply -text {Apply}\
1443 -command "dogatom_apply $id"
1444 button $id.buttonframe.ok -text {OK}\
1445 -command "dogatom_ok $id"
1446 pack $id.buttonframe.cancel -side left -expand 1
1447 pack $id.buttonframe.apply -side left -expand 1
1448 pack $id.buttonframe.ok -side left -expand 1
1449
1450 frame $id.paramsymto
1451 pack $id.paramsymto -side bottom
1452 label $id.paramsymto.entryname -text {send symbol}
1453 entry $id.paramsymto.entry -textvariable $var_gatomsymto -width 20
1454 pack $id.paramsymto.entryname $id.paramsymto.entry -side left
1455
1456 frame $id.paramsymfrom
1457 pack $id.paramsymfrom -side bottom
1458 label $id.paramsymfrom.entryname -text {receive symbol}
1459 entry $id.paramsymfrom.entry -textvariable $var_gatomsymfrom -width 20
1460 pack $id.paramsymfrom.entryname $id.paramsymfrom.entry -side left
1461
1462 frame $id.radio
1463 pack $id.radio -side bottom
1464 label $id.radio.label -text {show label on:}
1465 frame $id.radio.l
1466 frame $id.radio.r
1467 pack $id.radio.label -side top
1468 pack $id.radio.l $id.radio.r -side left
1469 radiobutton $id.radio.l.radio0 -value 0 \
1470 -variable $var_gatomwherelabel \
1471 -text "left"
1472 radiobutton $id.radio.l.radio1 -value 1 \
1473 -variable $var_gatomwherelabel \
1474 -text "right"
1475 radiobutton $id.radio.r.radio2 -value 2 \
1476 -variable $var_gatomwherelabel \
1477 -text "top"
1478 radiobutton $id.radio.r.radio3 -value 3 \
1479 -variable $var_gatomwherelabel \
1480 -text "bottom"
1481 pack $id.radio.l.radio0 $id.radio.l.radio1 -side top -anchor w
1482 pack $id.radio.r.radio2 $id.radio.r.radio3 -side top -anchor w
1483
1484
1485 frame $id.paramlabel
1486 pack $id.paramlabel -side bottom
1487 label $id.paramlabel.entryname -text label
1488 entry $id.paramlabel.entry -textvariable $var_gatomlabel -width 20
1489 pack $id.paramlabel.entryname $id.paramlabel.entry -side left
1490
1491 frame $id.paramhi
1492 pack $id.paramhi -side bottom
1493 label $id.paramhi.entryname -text "upper limit"
1494 entry $id.paramhi.entry -textvariable $var_gatomhi -width 8
1495 pack $id.paramhi.entryname $id.paramhi.entry -side left
1496
1497 frame $id.paramlo
1498 pack $id.paramlo -side bottom
1499 label $id.paramlo.entryname -text "lower limit"
1500 entry $id.paramlo.entry -textvariable $var_gatomlo -width 8
1501 pack $id.paramlo.entryname $id.paramlo.entry -side left
1502
1503 frame $id.params
1504 pack $id.params -side bottom
1505 label $id.params.entryname -text width
1506 entry $id.params.entry -textvariable $var_gatomwidth -width 4
1507 pack $id.params.entryname $id.params.entry -side left
1508
1509
1510
1511 bind $id.paramhi.entry <KeyPress-Return> [concat dogatom_ok $id]
1512 bind $id.paramlo.entry <KeyPress-Return> [concat dogatom_ok $id]
1513 bind $id.params.entry <KeyPress-Return> [concat dogatom_ok $id]
1514 $id.params.entry select from 0
1515 $id.params.entry select adjust end
1516 focus $id.params.entry
1517}
1518
1519############ pdtk_canvas_popup -- popup menu for canvas #########
1520
1521set popup_xpix 0
1522set popup_ypix 0
1523
1524proc popup_action {name action} {
1525 global popup_xpix popup_ypix
1526 set cmd [concat $name done-popup $action $popup_xpix $popup_ypix \;]
1527# puts stderr $cmd
1528 pd $cmd
1529}
1530
1531proc pdtk_canvas_popup {name xpix ypix canprop canopen} {
1532 global popup_xpix popup_ypix
1533 set popup_xpix $xpix
1534 set popup_ypix $ypix
1535 if {$canprop == 0} {$name.popup entryconfigure 0 -state disabled}
1536 if {$canprop == 1} {$name.popup entryconfigure 0 -state active}
1537 if {$canopen == 0} {$name.popup entryconfigure 1 -state disabled}
1538 if {$canopen == 1} {$name.popup entryconfigure 1 -state active}
1539 tk_popup $name.popup [expr $xpix + [winfo rootx $name.c]] \
1540 [expr $ypix + [winfo rooty $name.c]] 0
1541}
1542
1543############ pdtk_graph_dialog -- dialog window for graphs #########
1544
1545# the graph and array dialogs can come up in many copies; but in TK the easiest
1546# way to get data from an "entry", etc., is to set an associated variable
1547# name. This is especially true for grouped "radio buttons". So we have
1548# to synthesize variable names for each instance of the dialog. The dialog
1549# gets a TK pathname $id, from which it strips the leading "." to make a
1550# variable suffix $vid. Then you can get the actual value out by asking for
1551# [eval concat $$variablename]. There should be an easier way but I don't see
1552# it yet.
1553
1554proc graph_apply {id} {
1555# strip "." from the TK id to make a variable name suffix
1556 set vid [string trimleft $id .]
1557# for each variable, make a local variable to hold its name...
1558 set var_graph_x1 [concat graph_x1_$vid]
1559 global $var_graph_x1
1560 set var_graph_x2 [concat graph_x2_$vid]
1561 global $var_graph_x2
1562 set var_graph_xpix [concat graph_xpix_$vid]
1563 global $var_graph_xpix
1564 set var_graph_y1 [concat graph_y1_$vid]
1565 global $var_graph_y1
1566 set var_graph_y2 [concat graph_y2_$vid]
1567 global $var_graph_y2
1568 set var_graph_ypix [concat graph_ypix_$vid]
1569 global $var_graph_ypix
1570
1571 pd [concat $id dialog \
1572 [eval concat $$var_graph_x1] \
1573 [eval concat $$var_graph_y1] \
1574 [eval concat $$var_graph_x2] \
1575 [eval concat $$var_graph_y2] \
1576 [eval concat $$var_graph_xpix] \
1577 [eval concat $$var_graph_ypix] \
1578 \;]
1579}
1580
1581proc graph_cancel {id} {
1582 set cmd [concat $id cancel \;]
1583# puts stderr $cmd
1584 pd $cmd
1585}
1586
1587proc graph_ok {id} {
1588 graph_apply $id
1589 graph_cancel $id
1590}
1591
1592proc pdtk_graph_dialog {id x1 y1 x2 y2 xpix ypix} {
1593 set vid [string trimleft $id .]
1594 set var_graph_x1 [concat graph_x1_$vid]
1595 global $var_graph_x1
1596 set var_graph_x2 [concat graph_x2_$vid]
1597 global $var_graph_x2
1598 set var_graph_xpix [concat graph_xpix_$vid]
1599 global $var_graph_xpix
1600 set var_graph_y1 [concat graph_y1_$vid]
1601 global $var_graph_y1
1602 set var_graph_y2 [concat graph_y2_$vid]
1603 global $var_graph_y2
1604 set var_graph_ypix [concat graph_ypix_$vid]
1605 global $var_graph_ypix
1606
1607 set $var_graph_x1 $x1
1608 set $var_graph_x2 $x2
1609 set $var_graph_xpix $xpix
1610 set $var_graph_y1 $y1
1611 set $var_graph_y2 $y2
1612 set $var_graph_ypix $ypix
1613
1614 toplevel $id
1615 wm title $id {graph}
1616 wm protocol $id WM_DELETE_WINDOW [concat graph_cancel $id]
1617
1618 label $id.label -text {GRAPH BOUNDS}
1619 pack $id.label -side top
1620
1621 frame $id.buttonframe
1622 pack $id.buttonframe -side bottom -fill x -pady 2m
1623 button $id.buttonframe.cancel -text {Cancel}\
1624 -command "graph_cancel $id"
1625 button $id.buttonframe.apply -text {Apply}\
1626 -command "graph_apply $id"
1627 button $id.buttonframe.ok -text {OK}\
1628 -command "graph_ok $id"
1629 pack $id.buttonframe.cancel -side left -expand 1
1630 pack $id.buttonframe.apply -side left -expand 1
1631 pack $id.buttonframe.ok -side left -expand 1
1632
1633 frame $id.xrangef
1634 pack $id.xrangef -side top
1635
1636 label $id.xrangef.l1 -text "X from:"
1637 entry $id.xrangef.x1 -textvariable $var_graph_x1 -width 7
1638 label $id.xrangef.l2 -text "to:"
1639 entry $id.xrangef.x2 -textvariable $var_graph_x2 -width 7
1640 label $id.xrangef.l3 -text "screen width:"
1641 entry $id.xrangef.xpix -textvariable $var_graph_xpix -width 7
1642 pack $id.xrangef.l1 $id.xrangef.x1 \
1643 $id.xrangef.l2 $id.xrangef.x2 \
1644 $id.xrangef.l3 $id.xrangef.xpix -side left
1645
1646 frame $id.yrangef
1647 pack $id.yrangef -side top
1648
1649# dig in the following that the upper bound is labeled y1 but the variable is
1650# y2, etc. This is to deal with the inconsistent use of "upper and lower"
1651# graph bounds... in the dialog the upper Y bound is the lower valued Y pixel.
1652 label $id.yrangef.l1 -text "Y from:"
1653 entry $id.yrangef.y1 -textvariable $var_graph_y2 -width 7
1654 label $id.yrangef.l2 -text "to:"
1655 entry $id.yrangef.y2 -textvariable $var_graph_y1 -width 7
1656 label $id.yrangef.l3 -text "screen height:"
1657 entry $id.yrangef.ypix -textvariable $var_graph_ypix -width 7
1658 pack $id.yrangef.l1 $id.yrangef.y1 \
1659 $id.yrangef.l2 $id.yrangef.y2 \
1660 $id.yrangef.l3 $id.yrangef.ypix -side left
1661
1662 bind $id.xrangef.x1 <KeyPress-Return> [concat graph_ok $id]
1663 bind $id.xrangef.x2 <KeyPress-Return> [concat graph_ok $id]
1664 bind $id.xrangef.xpix <KeyPress-Return> [concat graph_ok $id]
1665 bind $id.yrangef.y1 <KeyPress-Return> [concat graph_ok $id]
1666 bind $id.yrangef.y2 <KeyPress-Return> [concat graph_ok $id]
1667 bind $id.yrangef.ypix <KeyPress-Return> [concat graph_ok $id]
1668 $id.xrangef.x2 select from 0
1669 $id.xrangef.x2 select adjust end
1670 focus $id.xrangef.x2
1671}
1672
1673# begin of change "iemlib"
1674############ pdtk_iemgui_dialog -- dialog window for iem guis #########
1675
1676set iemgui_define_min_flashhold 50
1677set iemgui_define_min_flashbreak 10
1678set iemgui_define_min_fontsize 4
1679
1680proc iemgui_clip_dim {id} {
1681 set vid [string trimleft $id .]
1682
1683 set var_iemgui_wdt [concat iemgui_wdt_$vid]
1684 global $var_iemgui_wdt
1685 set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
1686 global $var_iemgui_min_wdt
1687 set var_iemgui_hgt [concat iemgui_hgt_$vid]
1688 global $var_iemgui_hgt
1689 set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
1690 global $var_iemgui_min_hgt
1691
1692 if {[eval concat $$var_iemgui_wdt] < [eval concat $$var_iemgui_min_wdt]} {
1693 set $var_iemgui_wdt [eval concat $$var_iemgui_min_wdt]
1694 $id.dim.w_ent configure -textvariable $var_iemgui_wdt
1695 }
1696 if {[eval concat $$var_iemgui_hgt] < [eval concat $$var_iemgui_min_hgt]} {
1697 set $var_iemgui_hgt [eval concat $$var_iemgui_min_hgt]
1698 $id.dim.h_ent configure -textvariable $var_iemgui_hgt
1699 }
1700}
1701
1702proc iemgui_clip_num {id} {
1703 set vid [string trimleft $id .]
1704
1705 set var_iemgui_num [concat iemgui_num_$vid]
1706 global $var_iemgui_num
1707
1708 if {[eval concat $$var_iemgui_num] > 2000} {
1709 set $var_iemgui_num 2000
1710 $id.para.num_ent configure -textvariable $var_iemgui_num
1711 }
1712 if {[eval concat $$var_iemgui_num] < 1} {
1713 set $var_iemgui_num 1
1714 $id.para.num_ent configure -textvariable $var_iemgui_num
1715 }
1716}
1717
1718proc iemgui_sched_rng {id} {
1719 set vid [string trimleft $id .]
1720
1721 set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
1722 global $var_iemgui_min_rng
1723 set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
1724 global $var_iemgui_max_rng
1725 set var_iemgui_rng_sch [concat iemgui_rng_sch_$vid]
1726 global $var_iemgui_rng_sch
1727
1728 global iemgui_define_min_flashhold
1729 global iemgui_define_min_flashbreak
1730
1731 if {[eval concat $$var_iemgui_rng_sch] == 2} {
1732 if {[eval concat $$var_iemgui_max_rng] < [eval concat $$var_iemgui_min_rng]} {
1733 set hhh [eval concat $$var_iemgui_min_rng]
1734 set $var_iemgui_min_rng [eval concat $$var_iemgui_max_rng]
1735 set $var_iemgui_max_rng $hhh
1736 $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
1737 $id.rng.min_ent configure -textvariable $var_iemgui_min_rng }
1738 if {[eval concat $$var_iemgui_max_rng] < $iemgui_define_min_flashhold} {
1739 set $var_iemgui_max_rng $iemgui_define_min_flashhold
1740 $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
1741 }
1742 if {[eval concat $$var_iemgui_min_rng] < $iemgui_define_min_flashbreak} {
1743 set $var_iemgui_min_rng $iemgui_define_min_flashbreak
1744 $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
1745 }
1746 }
1747 if {[eval concat $$var_iemgui_rng_sch] == 1} {
1748 if {[eval concat $$var_iemgui_min_rng] == 0.0} {
1749 set $var_iemgui_min_rng 1.0
1750 $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
1751 }
1752 }
1753}
1754
1755proc iemgui_verify_rng {id} {
1756 set vid [string trimleft $id .]
1757
1758 set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
1759 global $var_iemgui_min_rng
1760 set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
1761 global $var_iemgui_max_rng
1762 set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
1763 global $var_iemgui_lin0_log1
1764
1765 if {[eval concat $$var_iemgui_lin0_log1] == 1} {
1766 if {[eval concat $$var_iemgui_max_rng] == 0.0 && [eval concat $$var_iemgui_min_rng] == 0.0} {
1767 set $var_iemgui_max_rng 1.0
1768 $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
1769 }
1770 if {[eval concat $$var_iemgui_max_rng] > 0} {
1771 if {[eval concat $$var_iemgui_min_rng] <= 0} {
1772 set $var_iemgui_min_rng [expr [eval concat $$var_iemgui_max_rng] * 0.01]
1773 $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
1774 }
1775 } else {
1776 if {[eval concat $$var_iemgui_min_rng] > 0} {
1777 set $var_iemgui_max_rng [expr [eval concat $$var_iemgui_min_rng] * 0.01]
1778 $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
1779 }
1780 }
1781 }
1782}
1783
1784proc iemgui_clip_fontsize {id} {
1785 set vid [string trimleft $id .]
1786
1787 set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
1788 global $var_iemgui_gn_fs
1789
1790 global iemgui_define_min_fontsize
1791
1792 if {[eval concat $$var_iemgui_gn_fs] < $iemgui_define_min_fontsize} {
1793 set $var_iemgui_gn_fs $iemgui_define_min_fontsize
1794 $id.gnfs.fs_ent configure -textvariable $var_iemgui_gn_fs
1795 }
1796}
1797
1798proc iemgui_set_col_example {id} {
1799 set vid [string trimleft $id .]
1800
1801 set var_iemgui_bcol [concat iemgui_bcol_$vid]
1802 global $var_iemgui_bcol
1803 set var_iemgui_fcol [concat iemgui_fcol_$vid]
1804 global $var_iemgui_fcol
1805 set var_iemgui_lcol [concat iemgui_lcol_$vid]
1806 global $var_iemgui_lcol
1807
1808 $id.col_example_choose.lb_bk configure \
1809 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
1810 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
1811 -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
1812 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]]
1813
1814 if { [eval concat $$var_iemgui_fcol] >= 0 } {
1815 $id.col_example_choose.fr_bk configure \
1816 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
1817 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
1818 -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
1819 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]]
1820 } else {
1821 $id.col_example_choose.fr_bk configure \
1822 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
1823 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
1824 -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
1825 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]]}
1826}
1827
1828proc iemgui_preset_col {id presetcol} {
1829 set vid [string trimleft $id .]
1830
1831 set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
1832 global $var_iemgui_l2_f1_b0
1833 set var_iemgui_bcol [concat iemgui_bcol_$vid]
1834 global $var_iemgui_bcol
1835 set var_iemgui_fcol [concat iemgui_fcol_$vid]
1836 global $var_iemgui_fcol
1837 set var_iemgui_lcol [concat iemgui_lcol_$vid]
1838 global $var_iemgui_lcol
1839
1840 if { [eval concat $$var_iemgui_l2_f1_b0] == 0 } { set $var_iemgui_bcol $presetcol }
1841 if { [eval concat $$var_iemgui_l2_f1_b0] == 1 } { set $var_iemgui_fcol $presetcol }
1842 if { [eval concat $$var_iemgui_l2_f1_b0] == 2 } { set $var_iemgui_lcol $presetcol }
1843 iemgui_set_col_example $id
1844}
1845
1846proc iemgui_choose_col_bkfrlb {id} {
1847 set vid [string trimleft $id .]
1848
1849 set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
1850 global $var_iemgui_l2_f1_b0
1851 set var_iemgui_bcol [concat iemgui_bcol_$vid]
1852 global $var_iemgui_bcol
1853 set var_iemgui_fcol [concat iemgui_fcol_$vid]
1854 global $var_iemgui_fcol
1855 set var_iemgui_lcol [concat iemgui_lcol_$vid]
1856 global $var_iemgui_lcol
1857
1858 if {[eval concat $$var_iemgui_l2_f1_b0] == 0} {
1859 set $var_iemgui_bcol [expr [eval concat $$var_iemgui_bcol] & 0xFCFCFC]
1860 set helpstring [tk_chooseColor -title "Background-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_bcol]]]
1861 if { $helpstring != "" } {
1862 set $var_iemgui_bcol [string replace $helpstring 0 0 "0x"]
1863 set $var_iemgui_bcol [expr [eval concat $$var_iemgui_bcol] & 0xFCFCFC] }
1864 }
1865 if {[eval concat $$var_iemgui_l2_f1_b0] == 1} {
1866 set $var_iemgui_fcol [expr [eval concat $$var_iemgui_fcol] & 0xFCFCFC]
1867 set helpstring [tk_chooseColor -title "Front-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_fcol]]]
1868 if { $helpstring != "" } {
1869 set $var_iemgui_fcol [string replace $helpstring 0 0 "0x"]
1870 set $var_iemgui_fcol [expr [eval concat $$var_iemgui_fcol] & 0xFCFCFC] }
1871 }
1872 if {[eval concat $$var_iemgui_l2_f1_b0] == 2} {
1873 set $var_iemgui_lcol [expr [eval concat $$var_iemgui_lcol] & 0xFCFCFC]
1874 set helpstring [tk_chooseColor -title "Label-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_lcol]]]
1875 if { $helpstring != "" } {
1876 set $var_iemgui_lcol [string replace $helpstring 0 0 "0x"]
1877 set $var_iemgui_lcol [expr [eval concat $$var_iemgui_lcol] & 0xFCFCFC] }
1878 }
1879 iemgui_set_col_example $id
1880}
1881
1882proc iemgui_lilo {id} {
1883 set vid [string trimleft $id .]
1884
1885 set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
1886 global $var_iemgui_lin0_log1
1887 set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
1888 global $var_iemgui_lilo0
1889 set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
1890 global $var_iemgui_lilo1
1891
1892 iemgui_sched_rng $id
1893
1894 if {[eval concat $$var_iemgui_lin0_log1] == 0} {
1895 set $var_iemgui_lin0_log1 1
1896 $id.para.lilo configure -text [eval concat $$var_iemgui_lilo1]
1897 iemgui_verify_rng $id
1898 iemgui_sched_rng $id
1899 } else {
1900 set $var_iemgui_lin0_log1 0
1901 $id.para.lilo configure -text [eval concat $$var_iemgui_lilo0]
1902 }
1903}
1904
1905proc iemgui_toggle_font {id} {
1906 set vid [string trimleft $id .]
1907
1908 set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
1909 global $var_iemgui_gn_f
1910
1911 set $var_iemgui_gn_f [expr [eval concat $$var_iemgui_gn_f] + 1]
1912 if {[eval concat $$var_iemgui_gn_f] > 2} {set $var_iemgui_gn_f 0}
1913 if {[eval concat $$var_iemgui_gn_f] == 0} {$id.gnfs.fb configure -text "courier" -font {courier 10 bold}}
1914 if {[eval concat $$var_iemgui_gn_f] == 1} {$id.gnfs.fb configure -text "helvetica" -font {helvetica 10 bold}}
1915 if {[eval concat $$var_iemgui_gn_f] == 2} {$id.gnfs.fb configure -text "times" -font {times 10 bold}}
1916}
1917
1918proc iemgui_lb {id} {
1919 set vid [string trimleft $id .]
1920
1921 set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
1922 global $var_iemgui_loadbang
1923
1924 if {[eval concat $$var_iemgui_loadbang] == 0} {
1925 set $var_iemgui_loadbang 1
1926 $id.para.lb configure -text "init"
1927 } else {
1928 set $var_iemgui_loadbang 0
1929 $id.para.lb configure -text "no init"
1930 }
1931}
1932
1933proc iemgui_stdy_jmp {id} {
1934 set vid [string trimleft $id .]
1935
1936 set var_iemgui_steady [concat iemgui_steady_$vid]
1937 global $var_iemgui_steady
1938
1939 if {[eval concat $$var_iemgui_steady]} {
1940 set $var_iemgui_steady 0
1941 $id.para.stdy_jmp configure -text "jump on click"
1942 } else {
1943 set $var_iemgui_steady 1
1944 $id.para.stdy_jmp configure -text "steady on click"
1945 }
1946}
1947
1948proc iemgui_apply {id} {
1949 set vid [string trimleft $id .]
1950
1951 set var_iemgui_wdt [concat iemgui_wdt_$vid]
1952 global $var_iemgui_wdt
1953 set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
1954 global $var_iemgui_min_wdt
1955 set var_iemgui_hgt [concat iemgui_hgt_$vid]
1956 global $var_iemgui_hgt
1957 set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
1958 global $var_iemgui_min_hgt
1959 set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
1960 global $var_iemgui_min_rng
1961 set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
1962 global $var_iemgui_max_rng
1963 set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
1964 global $var_iemgui_lin0_log1
1965 set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
1966 global $var_iemgui_lilo0
1967 set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
1968 global $var_iemgui_lilo1
1969 set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
1970 global $var_iemgui_loadbang
1971 set var_iemgui_num [concat iemgui_num_$vid]
1972 global $var_iemgui_num
1973 set var_iemgui_steady [concat iemgui_steady_$vid]
1974 global $var_iemgui_steady
1975 set var_iemgui_snd [concat iemgui_snd_$vid]
1976 global $var_iemgui_snd
1977 set var_iemgui_rcv [concat iemgui_rcv_$vid]
1978 global $var_iemgui_rcv
1979 set var_iemgui_gui_nam [concat iemgui_gui_nam_$vid]
1980 global $var_iemgui_gui_nam
1981 set var_iemgui_gn_dx [concat iemgui_gn_dx_$vid]
1982 global $var_iemgui_gn_dx
1983 set var_iemgui_gn_dy [concat iemgui_gn_dy_$vid]
1984 global $var_iemgui_gn_dy
1985 set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
1986 global $var_iemgui_gn_f
1987 set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
1988 global $var_iemgui_gn_fs
1989 set var_iemgui_bcol [concat iemgui_bcol_$vid]
1990 global $var_iemgui_bcol
1991 set var_iemgui_fcol [concat iemgui_fcol_$vid]
1992 global $var_iemgui_fcol
1993 set var_iemgui_lcol [concat iemgui_lcol_$vid]
1994 global $var_iemgui_lcol
1995
1996 iemgui_clip_dim $id
1997 iemgui_clip_num $id
1998 iemgui_sched_rng $id
1999 iemgui_verify_rng $id
2000 iemgui_sched_rng $id
2001 iemgui_clip_fontsize $id
2002
2003 if {[eval concat $$var_iemgui_snd] == ""} {set hhhsnd "empty"} else {set hhhsnd [eval concat $$var_iemgui_snd]}
2004 if {[eval concat $$var_iemgui_rcv] == ""} {set hhhrcv "empty"} else {set hhhrcv [eval concat $$var_iemgui_rcv]}
2005 if {[eval concat $$var_iemgui_gui_nam] == ""} {set hhhgui_nam "empty"
2006 } else {
2007 set hhhgui_nam [eval concat $$var_iemgui_gui_nam]}
2008
2009 if {[string index $hhhsnd 0] == "$"} {
2010 set hhhsnd [string replace $hhhsnd 0 0 #] }
2011 if {[string index $hhhrcv 0] == "$"} {
2012 set hhhrcv [string replace $hhhrcv 0 0 #] }
2013 if {[string index $hhhgui_nam 0] == "$"} {
2014 set hhhgui_nam [string replace $hhhgui_nam 0 0 #] }
2015
2016 set hhhsnd [string map {" " _} $hhhsnd]
2017 set hhhrcv [string map {" " _} $hhhrcv]
2018 set hhhgui_nam [string map {" " _} $hhhgui_nam]
2019
2020 pd [concat $id dialog \
2021 [eval concat $$var_iemgui_wdt] \
2022 [eval concat $$var_iemgui_hgt] \
2023 [eval concat $$var_iemgui_min_rng] \
2024 [eval concat $$var_iemgui_max_rng] \
2025 [eval concat $$var_iemgui_lin0_log1] \
2026 [eval concat $$var_iemgui_loadbang] \
2027 [eval concat $$var_iemgui_num] \
2028 $hhhsnd \
2029 $hhhrcv \
2030 $hhhgui_nam \
2031 [eval concat $$var_iemgui_gn_dx] \
2032 [eval concat $$var_iemgui_gn_dy] \
2033 [eval concat $$var_iemgui_gn_f] \
2034 [eval concat $$var_iemgui_gn_fs] \
2035 [eval concat $$var_iemgui_bcol] \
2036 [eval concat $$var_iemgui_fcol] \
2037 [eval concat $$var_iemgui_lcol] \
2038 [eval concat $$var_iemgui_steady] \
2039 \;]
2040}
2041
2042proc iemgui_cancel {id} {pd [concat $id cancel \;]}
2043
2044proc iemgui_ok {id} {
2045 iemgui_apply $id
2046 iemgui_cancel $id
2047}
2048
2049proc pdtk_iemgui_dialog {id mainheader \
2050 dim_header wdt min_wdt wdt_label hgt min_hgt hgt_label \
2051 rng_header min_rng min_rng_label max_rng max_rng_label rng_sched \
2052 lin0_log1 lilo0_label lilo1_label loadbang steady num_label num \
2053 snd rcv \
2054 gui_name \
2055 gn_dx gn_dy \
2056 gn_f gn_fs \
2057 bcol fcol lcol} {
2058
2059 set vid [string trimleft $id .]
2060
2061 set var_iemgui_wdt [concat iemgui_wdt_$vid]
2062 global $var_iemgui_wdt
2063 set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
2064 global $var_iemgui_min_wdt
2065 set var_iemgui_hgt [concat iemgui_hgt_$vid]
2066 global $var_iemgui_hgt
2067 set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
2068 global $var_iemgui_min_hgt
2069 set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
2070 global $var_iemgui_min_rng
2071 set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
2072 global $var_iemgui_max_rng
2073 set var_iemgui_rng_sch [concat iemgui_rng_sch_$vid]
2074 global $var_iemgui_rng_sch
2075 set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
2076 global $var_iemgui_lin0_log1
2077 set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
2078 global $var_iemgui_lilo0
2079 set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
2080 global $var_iemgui_lilo1
2081 set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
2082 global $var_iemgui_loadbang
2083 set var_iemgui_num [concat iemgui_num_$vid]
2084 global $var_iemgui_num
2085 set var_iemgui_steady [concat iemgui_steady_$vid]
2086 global $var_iemgui_steady
2087 set var_iemgui_snd [concat iemgui_snd_$vid]
2088 global $var_iemgui_snd
2089 set var_iemgui_rcv [concat iemgui_rcv_$vid]
2090 global $var_iemgui_rcv
2091 set var_iemgui_gui_nam [concat iemgui_gui_nam_$vid]
2092 global $var_iemgui_gui_nam
2093 set var_iemgui_gn_dx [concat iemgui_gn_dx_$vid]
2094 global $var_iemgui_gn_dx
2095 set var_iemgui_gn_dy [concat iemgui_gn_dy_$vid]
2096 global $var_iemgui_gn_dy
2097 set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
2098 global $var_iemgui_gn_f
2099 set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
2100 global $var_iemgui_gn_fs
2101 set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
2102 global $var_iemgui_l2_f1_b0
2103 set var_iemgui_bcol [concat iemgui_bcol_$vid]
2104 global $var_iemgui_bcol
2105 set var_iemgui_fcol [concat iemgui_fcol_$vid]
2106 global $var_iemgui_fcol
2107 set var_iemgui_lcol [concat iemgui_lcol_$vid]
2108 global $var_iemgui_lcol
2109
2110 set $var_iemgui_wdt $wdt
2111 set $var_iemgui_min_wdt $min_wdt
2112 set $var_iemgui_hgt $hgt
2113 set $var_iemgui_min_hgt $min_hgt
2114 set $var_iemgui_min_rng $min_rng
2115 set $var_iemgui_max_rng $max_rng
2116 set $var_iemgui_rng_sch $rng_sched
2117 set $var_iemgui_lin0_log1 $lin0_log1
2118 set $var_iemgui_lilo0 $lilo0_label
2119 set $var_iemgui_lilo1 $lilo1_label
2120 set $var_iemgui_loadbang $loadbang
2121 set $var_iemgui_num $num
2122 set $var_iemgui_steady $steady
2123 if {$snd == "empty"} {set $var_iemgui_snd [format ""]
2124 } else {set $var_iemgui_snd [format "%s" $snd]}
2125 if {$rcv == "empty"} {set $var_iemgui_rcv [format ""]
2126 } else {set $var_iemgui_rcv [format "%s" $rcv]}
2127 if {$gui_name == "empty"} {set $var_iemgui_gui_nam [format ""]
2128 } else {set $var_iemgui_gui_nam [format "%s" $gui_name]}
2129
2130 if {[string index [eval concat $$var_iemgui_snd] 0] == "#"} {
2131 set $var_iemgui_snd [string replace [eval concat $$var_iemgui_snd] 0 0 $] }
2132 if {[string index [eval concat $$var_iemgui_rcv] 0] == "#"} {
2133 set $var_iemgui_rcv [string replace [eval concat $$var_iemgui_rcv] 0 0 $] }
2134 if {[string index [eval concat $$var_iemgui_gui_nam] 0] == "#"} {
2135 set $var_iemgui_gui_nam [string replace [eval concat $$var_iemgui_gui_nam] 0 0 $] }
2136 set $var_iemgui_gn_dx $gn_dx
2137 set $var_iemgui_gn_dy $gn_dy
2138 set $var_iemgui_gn_f $gn_f
2139 set $var_iemgui_gn_fs $gn_fs
2140
2141 set $var_iemgui_bcol $bcol
2142 set $var_iemgui_fcol $fcol
2143 set $var_iemgui_lcol $lcol
2144
2145 set $var_iemgui_l2_f1_b0 0
2146
2147 toplevel $id
2148 wm title $id [format "%s-PROPERTIES" $mainheader]
2149 wm protocol $id WM_DELETE_WINDOW [concat iemgui_cancel $id]
2150
2151 frame $id.dim
2152 pack $id.dim -side top
2153 label $id.dim.head -text $dim_header
2154 label $id.dim.w_lab -text $wdt_label -width 6
2155 entry $id.dim.w_ent -textvariable $var_iemgui_wdt -width 5
2156 label $id.dim.dummy1 -text " " -width 10
2157 label $id.dim.h_lab -text $hgt_label -width 6
2158 entry $id.dim.h_ent -textvariable $var_iemgui_hgt -width 5
2159 pack $id.dim.head -side top
2160 pack $id.dim.w_lab $id.dim.w_ent $id.dim.dummy1 -side left
2161 if { $hgt_label != "empty" } {
2162 pack $id.dim.h_lab $id.dim.h_ent -side left}
2163
2164 frame $id.rng
2165 pack $id.rng -side top
2166 label $id.rng.head -text $rng_header
2167 label $id.rng.min_lab -text $min_rng_label -width 6
2168 entry $id.rng.min_ent -textvariable $var_iemgui_min_rng -width 9
2169 label $id.rng.dummy1 -text " " -width 1
2170 label $id.rng.max_lab -text $max_rng_label -width 8
2171 entry $id.rng.max_ent -textvariable $var_iemgui_max_rng -width 9
2172 if { $rng_header != "empty" } {
2173 pack $id.rng.head -side top
2174 if { $min_rng_label != "empty" } {
2175 pack $id.rng.min_lab $id.rng.min_ent -side left}
2176 if { $max_rng_label != "empty" } {
2177 pack $id.rng.dummy1 \
2178 $id.rng.max_lab $id.rng.max_ent -side left} }
2179
2180 if { [eval concat $$var_iemgui_lin0_log1] >= 0 || [eval concat $$var_iemgui_loadbang] >= 0 || [eval concat $$var_iemgui_num] > 0 || [eval concat $$var_iemgui_steady] >= 0 } {
2181 label $id.space1 -text "---------------------------------"
2182 pack $id.space1 -side top }
2183
2184 frame $id.para
2185 pack $id.para -side top
2186 label $id.para.dummy2 -text "" -width 1
2187 label $id.para.dummy3 -text "" -width 1
2188 if {[eval concat $$var_iemgui_lin0_log1] == 0} {
2189 button $id.para.lilo -text [eval concat $$var_iemgui_lilo0] -width 5 -command "iemgui_lilo $id" }
2190 if {[eval concat $$var_iemgui_lin0_log1] == 1} {
2191 button $id.para.lilo -text [eval concat $$var_iemgui_lilo1] -width 5 -command "iemgui_lilo $id" }
2192 if {[eval concat $$var_iemgui_loadbang] == 0} {
2193 button $id.para.lb -text "no init" -width 5 -command "iemgui_lb $id" }
2194 if {[eval concat $$var_iemgui_loadbang] == 1} {
2195 button $id.para.lb -text "init" -width 5 -command "iemgui_lb $id" }
2196 label $id.para.num_lab -text $num_label -width 9
2197 entry $id.para.num_ent -textvariable $var_iemgui_num -width 4
2198 if {[eval concat $$var_iemgui_steady] == 0} {
2199 button $id.para.stdy_jmp -text "jump on click" -width 11 -command "iemgui_stdy_jmp $id" }
2200 if {[eval concat $$var_iemgui_steady] == 1} {
2201 button $id.para.stdy_jmp -text "steady on click" -width 11 -command "iemgui_stdy_jmp $id" }
2202 if {[eval concat $$var_iemgui_lin0_log1] >= 0} {
2203 pack $id.para.lilo -side left -expand 1}
2204 if {[eval concat $$var_iemgui_loadbang] >= 0} {
2205 pack $id.para.dummy2 $id.para.lb -side left -expand 1}
2206 if {[eval concat $$var_iemgui_num] > 0} {
2207 pack $id.para.dummy3 $id.para.num_lab $id.para.num_ent -side left -expand 1}
2208 if {[eval concat $$var_iemgui_steady] >= 0} {
2209 pack $id.para.dummy3 $id.para.stdy_jmp -side left -expand 1}
2210 if { $snd != "nosndno" || $rcv != "norcvno" } {
2211 label $id.space2 -text "---------------------------------"
2212 pack $id.space2 -side top }
2213
2214 frame $id.snd
2215 pack $id.snd -side top
2216 label $id.snd.dummy1 -text "" -width 2
2217 label $id.snd.lab -text "send-symbol:" -width 12
2218 entry $id.snd.ent -textvariable $var_iemgui_snd -width 20
2219 if { $snd != "nosndno" } {
2220 pack $id.snd.dummy1 $id.snd.lab $id.snd.ent -side left}
2221
2222 frame $id.rcv
2223 pack $id.rcv -side top
2224 label $id.rcv.lab -text "receive-symbol:" -width 15
2225 entry $id.rcv.ent -textvariable $var_iemgui_rcv -width 20
2226 if { $rcv != "norcvno" } {
2227 pack $id.rcv.lab $id.rcv.ent -side left}
2228
2229 frame $id.gnam
2230 pack $id.gnam -side top
2231 label $id.gnam.head -text "--------------label:---------------"
2232 label $id.gnam.dummy1 -text "" -width 1
2233 label $id.gnam.lab -text "name:" -width 6
2234 entry $id.gnam.ent -textvariable $var_iemgui_gui_nam -width 29
2235 label $id.gnam.dummy2 -text "" -width 1
2236 pack $id.gnam.head -side top
2237 pack $id.gnam.dummy1 $id.gnam.lab $id.gnam.ent $id.gnam.dummy2 -side left
2238
2239 frame $id.gnxy
2240 pack $id.gnxy -side top
2241 label $id.gnxy.x_lab -text "x_off:" -width 6
2242 entry $id.gnxy.x_ent -textvariable $var_iemgui_gn_dx -width 5
2243 label $id.gnxy.dummy1 -text " " -width 10
2244 label $id.gnxy.y_lab -text "y_off:" -width 6
2245 entry $id.gnxy.y_ent -textvariable $var_iemgui_gn_dy -width 5
2246 pack $id.gnxy.x_lab $id.gnxy.x_ent $id.gnxy.dummy1 \
2247 $id.gnxy.y_lab $id.gnxy.y_ent -side left
2248
2249 frame $id.gnfs
2250 pack $id.gnfs -side top
2251 label $id.gnfs.f_lab -text "font:" -width 6
2252 if {[eval concat $$var_iemgui_gn_f] == 0} {
2253 button $id.gnfs.fb -text "courier" -font {courier 10 bold} -width 7 -command "iemgui_toggle_font $id" }
2254 if {[eval concat $$var_iemgui_gn_f] == 1} {
2255 button $id.gnfs.fb -text "helvetica" -font {helvetica 10 bold} -width 7 -command "iemgui_toggle_font $id" }
2256 if {[eval concat $$var_iemgui_gn_f] == 2} {
2257 button $id.gnfs.fb -text "times" -font {times 10 bold} -width 7 -command "iemgui_toggle_font $id" }
2258 label $id.gnfs.dummy1 -text "" -width 1
2259 label $id.gnfs.fs_lab -text "fontsize:" -width 8
2260 entry $id.gnfs.fs_ent -textvariable $var_iemgui_gn_fs -width 5
2261 pack $id.gnfs.f_lab $id.gnfs.fb $id.gnfs.dummy1 \
2262 $id.gnfs.fs_lab $id.gnfs.fs_ent -side left
2263
2264 label $id.col_head -text "--------------colors:--------------"
2265 pack $id.col_head -side top
2266
2267 frame $id.col_select
2268 pack $id.col_select -side top
2269 radiobutton $id.col_select.radio0 -value 0 -variable $var_iemgui_l2_f1_b0 \
2270 -text "backgd" -width 5
2271 radiobutton $id.col_select.radio1 -value 1 -variable $var_iemgui_l2_f1_b0 \
2272 -text "front" -width 5
2273 radiobutton $id.col_select.radio2 -value 2 -variable $var_iemgui_l2_f1_b0 \
2274 -text "label" -width 5
2275 if { [eval concat $$var_iemgui_fcol] >= 0 } {
2276 pack $id.col_select.radio0 $id.col_select.radio1 $id.col_select.radio2 -side left
2277 } else {pack $id.col_select.radio0 $id.col_select.radio2 -side left}
2278
2279 frame $id.col_example_choose
2280 pack $id.col_example_choose -side top
2281 button $id.col_example_choose.but -text "compose color" -width 10 \
2282 -command "iemgui_choose_col_bkfrlb $id"
2283 label $id.col_example_choose.dummy1 -text "" -width 1
2284 if { [eval concat $$var_iemgui_fcol] >= 0 } {
2285 button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
2286 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
2287 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
2288 -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
2289 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] -pady 2
2290 } else {
2291 button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
2292 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
2293 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
2294 -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
2295 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] -pady 2}
2296 button $id.col_example_choose.lb_bk -text "testlabel" -width 7 \
2297 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
2298 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
2299 -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
2300 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] -pady 2
2301
2302 pack $id.col_example_choose.but $id.col_example_choose.dummy1 \
2303 $id.col_example_choose.fr_bk $id.col_example_choose.lb_bk -side left
2304
2305 label $id.space3 -text "------or click color preset:-------"
2306 pack $id.space3 -side top
2307
2308 frame $id.bcol
2309 pack $id.bcol -side top
2310 foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 16579836 14737632 12369084 \
2311 16572640 16572608 16579784 14220504 14220540 14476540 16308476 } {
2312 button $id.bcol.c$i -background [format "#%6.6x" $hexcol] \
2313 -activebackground [format "#%6.6x" $hexcol] \
2314 -font {courier 2 normal} -padx 7 -pady 6 \
2315 -command [format "iemgui_preset_col %s %d" $id $hexcol] }
2316 pack $id.bcol.c0 $id.bcol.c1 $id.bcol.c2 $id.bcol.c3 $id.bcol.c4 \
2317 $id.bcol.c5 $id.bcol.c6 $id.bcol.c7 $id.bcol.c8 $id.bcol.c9 -side left
2318
2319 frame $id.fcol
2320 pack $id.fcol -side top
2321 foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 10526880 8158332 6316128 \
2322 16525352 16559172 15263784 1370132 2684148 3952892 16003312 } {
2323 button $id.fcol.c$i -background [format "#%6.6x" $hexcol] \
2324 -activebackground [format "#%6.6x" $hexcol] \
2325 -font {courier 2 normal} -padx 7 -pady 6 \
2326 -command [format "iemgui_preset_col %s %d" $id $hexcol] }
2327 pack $id.fcol.c0 $id.fcol.c1 $id.fcol.c2 $id.fcol.c3 $id.fcol.c4 \
2328 $id.fcol.c5 $id.fcol.c6 $id.fcol.c7 $id.fcol.c8 $id.fcol.c9 -side left
2329
2330 frame $id.lcol
2331 pack $id.lcol -side top
2332 foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 4210752 2105376 0 \
2333 9177096 5779456 7874580 2641940 17488 5256 5767248 } {
2334 button $id.lcol.c$i -background [format "#%6.6x" $hexcol] \
2335 -activebackground [format "#%6.6x" $hexcol] \
2336 -font {courier 2 normal} -padx 7 -pady 6 \
2337 -command [format "iemgui_preset_col %s %d" $id $hexcol] }
2338 pack $id.lcol.c0 $id.lcol.c1 $id.lcol.c2 $id.lcol.c3 $id.lcol.c4 \
2339 $id.lcol.c5 $id.lcol.c6 $id.lcol.c7 $id.lcol.c8 $id.lcol.c9 -side left
2340
2341
2342 label $id.space4 -text "---------------------------------"
2343 pack $id.space4 -side top
2344
2345 frame $id.cao
2346 pack $id.cao -side top
2347 button $id.cao.cancel -text {Cancel} -width 6 \
2348 -command "iemgui_cancel $id"
2349 label $id.cao.dummy1 -text "" -width 3
2350 button $id.cao.apply -text {Apply} -width 6 \
2351 -command "iemgui_apply $id"
2352 label $id.cao.dummy2 -text "" -width 3
2353 button $id.cao.ok -text {OK} -width 6 \
2354 -command "iemgui_ok $id"
2355 pack $id.cao.cancel $id.cao.dummy1 \
2356 $id.cao.apply $id.cao.dummy2 \
2357 $id.cao.ok -side left
2358
2359 label $id.space5 -text ""
2360 pack $id.space5 -side top
2361
2362 if {[info tclversion] < 8.4} {
2363 bind $id <Key-Tab> {tkTabToWindow [tk_focusNext %W]}
2364 bind $id <<PrevWindow>> {tkTabToWindow [tk_focusPrev %W]}
2365 } else {
2366 bind $id <Key-Tab> {tk::TabToWindow [tk_focusNext %W]}
2367 bind $id <<PrevWindow>> {tk::TabToWindow [tk_focusPrev %W]}
2368 }
2369
2370 bind $id.dim.w_ent <KeyPress-Return> [concat iemgui_ok $id]
2371 bind $id.dim.h_ent <KeyPress-Return> [concat iemgui_ok $id]
2372 bind $id.rng.min_ent <KeyPress-Return> [concat iemgui_ok $id]
2373 bind $id.rng.max_ent <KeyPress-Return> [concat iemgui_ok $id]
2374 bind $id.para.num_ent <KeyPress-Return> [concat iemgui_ok $id]
2375 bind $id.snd.ent <KeyPress-Return> [concat iemgui_ok $id]
2376 bind $id.rcv.ent <KeyPress-Return> [concat iemgui_ok $id]
2377 bind $id.gnam.ent <KeyPress-Return> [concat iemgui_ok $id]
2378 bind $id.gnxy.x_ent <KeyPress-Return> [concat iemgui_ok $id]
2379 bind $id.gnxy.y_ent <KeyPress-Return> [concat iemgui_ok $id]
2380 bind $id.gnfs.fs_ent <KeyPress-Return> [concat iemgui_ok $id]
2381 bind $id.cao.ok <KeyPress-Return> [concat iemgui_ok $id]
2382
2383 $id.dim.w_ent select from 0
2384 $id.dim.w_ent select adjust end
2385 focus $id.dim.w_ent
2386}
2387# end of change "iemlib"
2388
2389############ pdtk_array_dialog -- dialog window for arrays #########
2390proc array_apply {id} {
2391# strip "." from the TK id to make a variable name suffix
2392 set vid [string trimleft $id .]
2393# for each variable, make a local variable to hold its name...
2394 set var_array_name [concat array_name_$vid]
2395 global $var_array_name
2396 set var_array_n [concat array_n_$vid]
2397 global $var_array_n
2398 set var_array_saveit [concat array_saveit_$vid]
2399 global $var_array_saveit
2400 set var_array_otherflag [concat array_otherflag_$vid]
2401 global $var_array_otherflag
2402 set mofo [eval concat $$var_array_name]
2403 if {[string index $mofo 0] == "$"} {
2404 set mofo [string replace $mofo 0 0 #] }
2405
2406 pd [concat $id arraydialog $mofo \
2407 [eval concat $$var_array_n] \
2408 [eval concat $$var_array_saveit] \
2409 [eval concat $$var_array_otherflag] \
2410 \;]
2411}
2412
2413proc array_cancel {id} {
2414 set cmd [concat $id cancel \;]
2415 pd $cmd
2416}
2417
2418proc array_ok {id} {
2419 array_apply $id
2420 array_cancel $id
2421}
2422
2423proc pdtk_array_dialog {id name n saveit newone} {
2424 set vid [string trimleft $id .]
2425
2426 set var_array_name [concat array_name_$vid]
2427 global $var_array_name
2428 set var_array_n [concat array_n_$vid]
2429 global $var_array_n
2430 set var_array_saveit [concat array_saveit_$vid]
2431 global $var_array_saveit
2432 set var_array_otherflag [concat array_otherflag_$vid]
2433 global $var_array_otherflag
2434
2435 set $var_array_name $name
2436 set $var_array_n $n
2437 set $var_array_saveit $saveit
2438 set $var_array_otherflag 0
2439
2440 toplevel $id
2441 wm title $id {array}
2442 wm protocol $id WM_DELETE_WINDOW [concat array_cancel $id]
2443
2444 frame $id.name
2445 pack $id.name -side top
2446 label $id.name.label -text "name"
2447 entry $id.name.entry -textvariable $var_array_name
2448 pack $id.name.label $id.name.entry -side left
2449
2450 frame $id.n
2451 pack $id.n -side top
2452 label $id.n.label -text "size"
2453 entry $id.n.entry -textvariable $var_array_n
2454 pack $id.n.label $id.n.entry -side left
2455
2456 checkbutton $id.saveme -text {save contents} -variable $var_array_saveit \
2457 -anchor w
2458 pack $id.saveme -side top
2459
2460 if {$newone != 0} {
2461 frame $id.radio
2462 pack $id.radio -side top
2463 radiobutton $id.radio.radio0 -value 0 \
2464 -variable $var_array_otherflag \
2465 -text "in new graph"
2466 radiobutton $id.radio.radio1 -value 1 \
2467 -variable $var_array_otherflag \
2468 -text "in last graph"
2469 pack $id.radio.radio0 -side top -anchor w
2470 pack $id.radio.radio1 -side top -anchor w
2471 } else {
2472 checkbutton $id.deleteme -text {delete me} \
2473 -variable $var_array_otherflag -anchor w
2474 pack $id.deleteme -side top
2475 }
2476 frame $id.buttonframe
2477 pack $id.buttonframe -side bottom -fill x -pady 2m
2478 button $id.buttonframe.cancel -text {Cancel}\
2479 -command "array_cancel $id"
2480 if {$newone == 0} {button $id.buttonframe.apply -text {Apply}\
2481 -command "array_apply $id"}
2482 button $id.buttonframe.ok -text {OK}\
2483 -command "array_ok $id"
2484 pack $id.buttonframe.cancel -side left -expand 1
2485 if {$newone == 0} {pack $id.buttonframe.apply -side left -expand 1}
2486 pack $id.buttonframe.ok -side left -expand 1
2487
2488 bind $id.name.entry <KeyPress-Return> [concat array_ok $id]
2489 bind $id.n.entry <KeyPress-Return> [concat array_ok $id]
2490 $id.name.entry select from 0
2491 $id.name.entry select adjust end
2492 focus $id.name.entry
2493}
2494
2495############ pdtk_canvas_dialog -- dialog window for canvass #########
2496proc canvas_apply {id} {
2497# strip "." from the TK id to make a variable name suffix
2498 set vid [string trimleft $id .]
2499# for each variable, make a local variable to hold its name...
2500 set var_canvas_xscale [concat canvas_xscale_$vid]
2501 global $var_canvas_xscale
2502 set var_canvas_yscale [concat canvas_yscale_$vid]
2503 global $var_canvas_yscale
2504 set var_canvas_graphme [concat canvas_graphme_$vid]
2505 global $var_canvas_graphme
2506# set var_canvas_stretch [concat canvas_stretch_$vid]
2507# global $var_canvas_stretch
2508 pd [concat $id donecanvasdialog \
2509 [eval concat $$var_canvas_xscale] \
2510 [eval concat $$var_canvas_yscale] \
2511 [eval concat $$var_canvas_graphme] \
2512 \;]
2513}
2514
2515proc canvas_cancel {id} {
2516 set cmd [concat $id cancel \;]
2517 pd $cmd
2518}
2519
2520proc canvas_ok {id} {
2521 canvas_apply $id
2522 canvas_cancel $id
2523}
2524
2525proc pdtk_canvas_dialog {id xscale yscale graphme stretch} {
2526 set vid [string trimleft $id .]
2527
2528 set var_canvas_xscale [concat canvas_xscale_$vid]
2529 global $var_canvas_xscale
2530 set var_canvas_yscale [concat canvas_yscale_$vid]
2531 global $var_canvas_yscale
2532 set var_canvas_graphme [concat canvas_graphme_$vid]
2533 global $var_canvas_graphme
2534# set var_canvas_stretch [concat canvas_stretch_$vid]
2535# global $var_canvas_stretch
2536
2537 set $var_canvas_xscale $xscale
2538 set $var_canvas_yscale $yscale
2539 set $var_canvas_graphme $graphme
2540# set $var_canvas_stretch $stretch
2541
2542 toplevel $id
2543 wm title $id {canvas}
2544 wm protocol $id WM_DELETE_WINDOW [concat canvas_cancel $id]
2545
2546 frame $id.xscale
2547 pack $id.xscale -side top
2548 label $id.xscale.label -text "X units per pixel"
2549 entry $id.xscale.entry -textvariable $var_canvas_xscale -width 10
2550 pack $id.xscale.label $id.xscale.entry -side left
2551
2552 frame $id.yscale
2553 pack $id.yscale -side top
2554 label $id.yscale.label -text "Y units per pixel"
2555 entry $id.yscale.entry -textvariable $var_canvas_yscale -width 10
2556 pack $id.yscale.label $id.yscale.entry -side left
2557
2558 checkbutton $id.graphme -text {graph on parent} \
2559 -variable $var_canvas_graphme -anchor w
2560 pack $id.graphme -side top
2561
2562# checkbutton $id.stretch -text {stretch on resize} \
2563# -variable $var_canvas_stretch -anchor w
2564# pack $id.stretch -side top
2565
2566
2567 frame $id.buttonframe
2568 pack $id.buttonframe -side bottom -fill x -pady 2m
2569 button $id.buttonframe.cancel -text {Cancel}\
2570 -command "canvas_cancel $id"
2571 button $id.buttonframe.apply -text {Apply}\
2572 -command "canvas_apply $id"
2573 button $id.buttonframe.ok -text {OK}\
2574 -command "canvas_ok $id"
2575 pack $id.buttonframe.cancel -side left -expand 1
2576 pack $id.buttonframe.apply -side left -expand 1
2577 pack $id.buttonframe.ok -side left -expand 1
2578
2579 bind $id.xscale.entry <KeyPress-Return> [concat canvas_ok $id]
2580 bind $id.yscale.entry <KeyPress-Return> [concat canvas_ok $id]
2581 $id.xscale.entry select from 0
2582 $id.xscale.entry select adjust end
2583 focus $id.xscale.entry
2584}
2585
2586############ pdtk_data_dialog -- run a data dialog #########
2587proc dodata_send {name} {
2588# puts stderr [$name.text get 0.0 end]
2589
2590 for {set i 1} {[$name.text compare [concat $i.0 + 3 chars] < end]} \
2591 {incr i 1} {
2592# puts stderr [concat it's [$name.text get $i.0 [expr $i + 1].0]]
2593 set cmd [concat $name data [$name.text get $i.0 [expr $i + 1].0] \;]
2594# puts stderr $cmd
2595 pd $cmd
2596 }
2597 set cmd [concat $name end \;]
2598# puts stderr $cmd
2599 pd $cmd
2600}
2601
2602proc dodata_cancel {name} {
2603 set cmd [concat $name cancel \;]
2604# puts stderr $cmd
2605 pd $cmd
2606}
2607
2608proc dodata_ok {name} {
2609 dodata_send $name
2610 dodata_cancel $name
2611}
2612
2613proc pdtk_data_dialog {name stuff} {
2614
2615 toplevel $name
2616 wm title $name {Atom}
2617 wm protocol $name WM_DELETE_WINDOW [concat dodata_cancel $name]
2618
2619 frame $name.buttonframe
2620 pack $name.buttonframe -side bottom -fill x -pady 2m
2621 button $name.buttonframe.send -text {Send (Ctrl s)}\
2622 -command [concat dodata_send $name]
2623 button $name.buttonframe.ok -text {OK (Ctrl t)}\
2624 -command [concat dodata_ok $name]
2625 pack $name.buttonframe.send -side left -expand 1
2626 pack $name.buttonframe.ok -side left -expand 1
2627
2628 text $name.text -relief raised -bd 2 -height 40 -width 60 \
2629 -yscrollcommand "$name.scroll set" -font -*-courier-bold--normal--12-*
2630 scrollbar $name.scroll -command "$name.text yview"
2631 pack $name.scroll -side right -fill y
2632 pack $name.text -side left -fill both -expand 1
2633 $name.text insert end $stuff
2634 focus $name.text
2635 bind $name.text <Control-t> [concat dodata_ok $name]
2636 bind $name.text <Control-s> [concat dodata_send $name]
2637}
2638
2639############ check or uncheck the "edit" menu item ##############
2640#####################iemlib#######################
2641proc pdtk_canvas_editval {name value} {
2642 if { $value } {
2643 $name.m.edit entryconfigure "Edit mode" -indicatoron true
2644 } else {
2645 $name.m.edit entryconfigure "Edit mode" -indicatoron false
2646 }
2647}
2648#####################iemlib#######################
2649
2650############ pdtk_text_new -- create a new text object #2###########
2651proc pdtk_text_new {canvasname myname x y text font color} {
2652# if {$font < 13} {set fontname [format -*-courier-bold----%d-* $font]}
2653# if {$font >= 13} {set fontname [format -*-courier-----%d-* $font]}
2654 $canvasname create text $x $y \
2655 -font [format -*-courier-bold--normal--%d-* $font] \
2656 -tags $myname -text $text -fill $color -anchor nw
2657# pd [concat $myname size [$canvasname bbox $myname] \;]
2658}
2659
2660################ pdtk_text_set -- change the text ##################
2661proc pdtk_text_set {canvasname myname text} {
2662 $canvasname itemconfig $myname -text $text
2663# pd [concat $myname size [$canvasname bbox $myname] \;]
2664}
2665
2666############### event binding procedures for Pd window ################
2667
2668proc pdtk_pd_ctrlkey {name key shift} {
2669# puts stderr [concat key $key shift $shift]
2670# .dummy itemconfig goo -text [concat ---> control-key event $key];
2671 if {$key == "n" || $key == "N"} {menu_new}
2672 if {$key == "o" || $key == "O"} {menu_open}
2673 if {$key == "m" || $key == "M"} {menu_send}
2674 if {$key == "q" || $key == "Q"} {
2675 if {$shift == 1} {menu_really_quit} else {menu_quit}
2676 }
2677 if {$key == "slash"} {menu_audio 1}
2678 if {$key == "period"} {menu_audio 0}
2679}
2680
2681######### startup function. ##############
2682# Tell pd the current directory; this is used in case the command line
2683# asked pd to open something. Also, get character width and height for
2684# font sizes 8, 10, 12, 14, 16, and 24.
2685
2686proc pdtk_pd_startup {version apilist} {
2687 global pd_myversion pd_apilist
2688 set pd_myversion $version
2689 set pd_apilist $apilist
2690
2691 set width1 [font measure -*-courier-bold--normal--8-* x]
2692 set height1 [lindex [font metrics -*-courier-bold--normal--8-*] 5]
2693
2694 set width2 [font measure -*-courier-bold--normal--10-* x]
2695 set height2 [lindex [font metrics -*-courier-bold--normal--10-*] 5]
2696
2697 set width3 [font measure -*-courier-bold--normal--12-* x]
2698 set height3 [lindex [font metrics -*-courier-bold--normal--12-*] 5]
2699
2700 set width4 [font measure -*-courier-bold--normal--14-* x]
2701 set height4 [lindex [font metrics -*-courier-bold--normal--14-*] 5]
2702
2703 set width5 [font measure -*-courier-bold--normal--16-* x]
2704 set height5 [lindex [font metrics -*-courier-bold--normal--16-*] 5]
2705
2706 set width6 [font measure -*-courier-bold--normal--24-* x]
2707 set height6 [lindex [font metrics -*-courier-bold--normal--24-*] 5]
2708
2709 set width7 [font measure -*-courier-bold--normal--36-* x]
2710 set height7 [lindex [font metrics -*-courier-bold--normal--36-*] 5]
2711
2712 set tclpatch [info patchlevel]
2713 if {$tclpatch == "8.3.0" || \
2714 $tclpatch == "8.3.1" || \
2715 $tclpatch == "8.3.2" || \
2716 $tclpatch == "8.3.3" } {
2717 set oldtclversion 1
2718 } else {
2719 set oldtclversion 0
2720 }
2721 pd [concat pd init [pdtk_enquote [pwd]] \
2722 8 $width1 $height1 \
2723 10 $width2 $height2 \
2724 12 $width3 $height3 \
2725 14 $width4 $height4 \
2726 16 $width5 $height5 \
2727 24 $width6 $height6 \
2728 36 $width7 $height7 \
2729 $oldtclversion \;];
2730
2731 # add the audio and help menus to the Pd window. We delayed this
2732 # so that we'd know the value of "apilist".
2733 menu_addstd .mbar
2734
2735}
2736
2737##################### DSP ON/OFF, METERS, DIO ERROR ###################
2738proc pdtk_pd_dsp {value} {
2739 global ctrls_audio_on
2740 if {$value == "ON"} {set ctrls_audio_on 1} else {set ctrls_audio_on 0}
2741# puts stderr [concat its $ctrls_audio_on]
2742}
2743
2744proc pdtk_pd_meters {indb outdb inclip outclip} {
2745# puts stderr [concat meters $indb $outdb $inclip $outclip]
2746 global ctrls_inlevel ctrls_outlevel
2747 set ctrls_inlevel $indb
2748 if {$inclip == 1} {
2749 .controls.inout.in.clip configure -background red
2750 } else {
2751 .controls.inout.in.clip configure -background grey
2752 }
2753 set ctrls_outlevel $outdb
2754 if {$outclip == 1} {
2755 .controls.inout.out.clip configure -background red
2756 } else {
2757 .controls.inout.out.clip configure -background grey
2758 }
2759
2760}
2761
2762proc pdtk_pd_dio {red} {
2763# puts stderr [concat dio $red]
2764 if {$red == 1} {
2765 .controls.dio configure -background red -activebackground red
2766 } else {
2767 .controls.dio configure -background grey -activebackground lightgrey
2768 }
2769
2770}
2771
2772############# text editing from the "edit" menu ###################
2773set edit_number 1
2774
2775proc texteditor_send {name} {
2776 set topname [string trimright $name .text]
2777 for {set i 0} \
2778 {[$name compare [concat 0.0 + [expr $i + 1] chars] < end]} \
2779 {incr i 1} {
2780 set cha [$name get [concat 0.0 + $i chars]]
2781 scan $cha %c keynum
2782 pd [concat pd key 1 $keynum 0 \;]
2783 }
2784}
2785
2786proc texteditor_ok {name} {
2787 set topname [string trimright $name .text]
2788 texteditor_send $name
2789 destroy $topname
2790}
2791
2792
2793proc pdtk_pd_texteditor {stuff} {
2794 global edit_number
2795 set name [format ".text%d" $edit_number]
2796 set edit_number [expr $edit_number + 1]
2797
2798 toplevel $name
2799 wm title $name {TEXT}
2800
2801 frame $name.buttons
2802 pack $name.buttons -side bottom -fill x -pady 2m
2803 button $name.buttons.send -text {Send (Ctrl s)}\
2804 -command "texteditor_send $name.text"
2805 button $name.buttons.ok -text {OK (Ctrl t)}\
2806 -command "texteditor_ok $name.text"
2807 pack $name.buttons.send -side left -expand 1
2808 pack $name.buttons.ok -side left -expand 1
2809
2810 text $name.text -relief raised -bd 2 -height 12 -width 60 \
2811 -yscrollcommand "$name.scroll set" -font -*-courier-bold--normal--12-*
2812 scrollbar $name.scroll -command "$name.text yview"
2813 pack $name.scroll -side right -fill y
2814 pack $name.text -side left -fill both -expand 1
2815 $name.text insert end $stuff
2816 focus $name.text
2817 bind $name.text <Control-t> {texteditor_ok %W}
2818 bind $name.text <Control-s> {texteditor_send %W}
2819}
2820
2821############# open and save dialogs for objects in Pd ##########
2822
2823proc pdtk_openpanel {target} {
2824 global pd_opendir
2825 set filename [tk_getOpenFile \
2826 -initialdir $pd_opendir]
2827 if {$filename != ""} {
2828 set directory [string range $filename 0 \
2829 [expr [string last / $filename ] - 1]]
2830 set pd_opendir $directory
2831
2832 pd [concat $target symbol [pdtk_enquote $filename] \;]
2833 }
2834}
2835
2836proc pdtk_savepanel {target} {
2837 set filename [tk_getSaveFile]
2838 if {$filename != ""} {
2839 pd [concat $target symbol [pdtk_enquote $filename] \;]
2840 }
2841}
2842
2843########################### comport hack ########################
2844
2845set com1 0
2846set com2 0
2847set com3 0
2848set com4 0
2849
2850proc com1_open {} {
2851 global com1
2852 set com1 [open com1 w]
2853 .dummy itemconfig goo -text $com1
2854 fconfigure $com1 -buffering none
2855 fconfigure $com1 -mode 19200,e,8,2
2856}
2857
2858proc com1_send {str} {
2859 global com1
2860 puts -nonewline $com1 $str
2861}
2862
2863
2864############# start a polling process to watch the socket ##############
2865# this is needed for nt, and presumably for Mac as well.
2866# in UNIX this is handled by a tcl callback (set up in t_tkcmd.c)
2867
2868if {$pd_nt == 1} {
2869 proc polleofloop {} {
2870 pd_pollsocket
2871 after 20 polleofloop
2872 }
2873
2874 polleofloop
2875}
2876
2877####################### audio dialog ##################3
2878
2879proc audio_apply {id} {
2880 global audio_indev1 audio_indev2 audio_indev3 audio_indev4
2881 global audio_inchan1 audio_inchan2 audio_inchan3 audio_inchan4
2882 global audio_outdev1 audio_outdev2 audio_outdev3 audio_outdev4
2883 global audio_outchan1 audio_outchan2 audio_outchan3 audio_outchan4
2884 global audio_sr audio_advance
2885
2886 pd [concat pd audio-dialog \
2887 $audio_indev1 \
2888 $audio_indev2 \
2889 $audio_indev3 \
2890 $audio_indev4 \
2891 $audio_inchan1 \
2892 $audio_inchan2 \
2893 $audio_inchan3 \
2894 $audio_inchan4 \
2895 $audio_outdev1 \
2896 $audio_outdev2 \
2897 $audio_outdev3 \
2898 $audio_outdev4 \
2899 $audio_outchan1 \
2900 $audio_outchan2 \
2901 $audio_outchan3 \
2902 $audio_outchan4 \
2903 $audio_sr \
2904 $audio_advance \
2905 \;]
2906}
2907
2908proc audio_cancel {id} {
2909 pd [concat $id cancel \;]
2910}
2911
2912proc audio_ok {id} {
2913 audio_apply $id
2914 audio_cancel $id
2915}
2916
2917# callback from popup menu
2918proc audio_popup_action {buttonname varname devlist index} {
2919 global audio_indevlist audio_outdevlist $varname
2920 $buttonname configure -text [lindex $devlist $index]
2921# puts stderr [concat popup_action $buttonname $varname $index]
2922 set $varname $index
2923}
2924
2925# create a popup menu
2926proc audio_popup {name buttonname varname devlist} {
2927 if [winfo exists $name.popup] {destroy $name.popup}
2928 menu $name.popup -tearoff false
2929# puts stderr [concat $devlist ]
2930 for {set x 0} {$x<[llength $devlist]} {incr x} {
2931 $name.popup add command -label [lindex $devlist $x] \
2932 -command [list audio_popup_action \
2933 $buttonname $varname $devlist $x]
2934 }
2935 tk_popup $name.popup [winfo pointerx $name] [winfo pointery $name] 0
2936}
2937
2938# start a dialog window to select audio devices and settings. "multi"
2939# is 0 if only one device is allowed; 1 if one apiece may be specified for
2940# input and output; and 2 if we can select multiple devices. "longform"
2941# (which only makes sense if "multi" is 2) asks us to make controls for
2942# opening several devices; if not, we get an extra button to turn longform
2943# on and restart the dialog.
2944
2945proc pdtk_audio_dialog {id indevlist indev1 indev2 indev3 indev4 \
2946 inchan1 inchan2 inchan3 inchan4 \
2947 outdevlist outdev1 outdev2 outdev3 outdev4 \
2948 outchan1 outchan2 outchan3 outchan4 sr advance multi longform} {
2949 global audio_indev1 audio_indev2 audio_indev3 audio_indev4
2950 global audio_inchan1 audio_inchan2 audio_inchan3 audio_inchan4
2951 global audio_outdev1 audio_outdev2 audio_outdev3 audio_outdev4
2952 global audio_outchan1 audio_outchan2 audio_outchan3 audio_outchan4
2953 global audio_sr audio_advance
2954 global audio_indevlist audio_outdevlist
2955
2956 set audio_indev1 $indev1
2957 set audio_indev2 $indev2
2958 set audio_indev3 $indev3
2959 set audio_indev4 $indev4
2960 set audio_inchan1 $inchan1
2961 set audio_inchan2 $inchan2
2962 set audio_inchan3 $inchan3
2963 set audio_inchan4 $inchan4
2964 set audio_outdev1 $outdev1
2965 set audio_outdev2 $outdev2
2966 set audio_outdev3 $outdev3
2967 set audio_outdev4 $outdev4
2968 set audio_outchan1 $outchan1
2969 set audio_outchan2 $outchan2
2970 set audio_outchan3 $outchan3
2971 set audio_outchan4 $outchan4
2972 set audio_sr $sr
2973 set audio_advance $advance
2974 set audio_indevlist $indevlist
2975 set audio_outdevlist $outdevlist
2976
2977 toplevel $id
2978 wm title $id {audio}
2979 wm protocol $id WM_DELETE_WINDOW [concat audio_cancel $id]
2980
2981 frame $id.buttonframe
2982 pack $id.buttonframe -side bottom -fill x -pady 2m
2983 button $id.buttonframe.cancel -text {Cancel}\
2984 -command "audio_cancel $id"
2985 button $id.buttonframe.apply -text {Apply}\
2986 -command "audio_apply $id"
2987 button $id.buttonframe.ok -text {OK}\
2988 -command "audio_ok $id"
2989 pack $id.buttonframe.cancel -side left -expand 1
2990 pack $id.buttonframe.apply -side left -expand 1
2991 pack $id.buttonframe.ok -side left -expand 1
2992
2993 # sample rate and advance
2994 frame $id.srf
2995 pack $id.srf -side top
2996
2997 label $id.srf.l1 -text "sample rate:"
2998 entry $id.srf.x1 -textvariable audio_sr -width 7
2999 label $id.srf.l2 -text "delay (msec):"
3000 entry $id.srf.x2 -textvariable audio_advance -width 4
3001 pack $id.srf.l1 $id.srf.x1 $id.srf.l2 $id.srf.x2 -side left
3002
3003 # input device 1
3004 frame $id.in1f
3005 pack $id.in1f -side top
3006
3007 label $id.in1f.l1 -text "input device 1:"
3008 button $id.in1f.x1 -text [lindex $indevlist $audio_indev1] \
3009 -command [list audio_popup $id $id.in1f.x1 audio_indev1 $indevlist]
3010 label $id.in1f.l2 -text "channels:"
3011 entry $id.in1f.x2 -textvariable audio_inchan1 -width 3
3012 pack $id.in1f.l1 $id.in1f.x1 $id.in1f.l2 $id.in1f.x2 -side left
3013
3014 # input device 2
3015 if {$longform && $multi > 1 && [llength $indevlist] > 1} {
3016 frame $id.in2f
3017 pack $id.in2f -side top
3018
3019 label $id.in2f.l1 -text "input device 2:"
3020 button $id.in2f.x1 -text [lindex $indevlist $audio_indev2] \
3021 -command [list audio_popup $id $id.in2f.x1 audio_indev2 $indevlist]
3022 label $id.in2f.l2 -text "channels:"
3023 entry $id.in2f.x2 -textvariable audio_inchan2 -width 3
3024 pack $id.in2f.l1 $id.in2f.x1 $id.in2f.l2 $id.in2f.x2 -side left
3025 }
3026
3027 # input device 3
3028 if {$longform && $multi > 1 && [llength $indevlist] > 2} {
3029 frame $id.in3f
3030 pack $id.in3f -side top
3031
3032 label $id.in3f.l1 -text "input device 3:"
3033 button $id.in3f.x1 -text [lindex $indevlist $audio_indev3] \
3034 -command [list audio_popup $id $id.in3f.x1 audio_indev3 $indevlist]
3035 label $id.in3f.l2 -text "channels:"
3036 entry $id.in3f.x2 -textvariable audio_inchan3 -width 3
3037 pack $id.in3f.l1 $id.in3f.x1 $id.in3f.l2 $id.in3f.x2 -side left
3038 }
3039
3040 # input device 4
3041 if {$longform && $multi > 1 && [llength $indevlist] > 3} {
3042 frame $id.in4f
3043 pack $id.in4f -side top
3044
3045 label $id.in4f.l1 -text "input device 4:"
3046 button $id.in4f.x1 -text [lindex $indevlist $audio_indev4] \
3047 -command [list audio_popup $id $id.in4f.x1 audio_indev4 $indevlist]
3048 label $id.in4f.l2 -text "channels:"
3049 entry $id.in4f.x2 -textvariable audio_inchan4 -width 3
3050 pack $id.in4f.l1 $id.in4f.x1 $id.in4f.l2 $id.in4f.x2 -side left
3051 }
3052
3053 # output device 1
3054 frame $id.out1f
3055 pack $id.out1f -side top
3056
3057 if {$multi == 0} {
3058 label $id.out1f.l1 \
3059 -text "(output device same as input device) .............. "
3060 } else {
3061 label $id.out1f.l1 -text "output device 1:"
3062 button $id.out1f.x1 -text [lindex $outdevlist $audio_outdev1] \
3063 -command \
3064 [list audio_popup $id $id.out1f.x1 audio_outdev1 $outdevlist]
3065 }
3066 label $id.out1f.l2 -text "channels:"
3067 entry $id.out1f.x2 -textvariable audio_outchan1 -width 3
3068 if {$multi == 0} {
3069 pack $id.out1f.l1 $id.out1f.l2 $id.out1f.x2 -side left
3070 } else {
3071 pack $id.out1f.l1 $id.out1f.x1 $id.out1f.l2 $id.out1f.x2 -side left
3072 }
3073
3074 # output device 2
3075 if {$longform && $multi > 1 && [llength $indevlist] > 1} {
3076 frame $id.out2f
3077 pack $id.out2f -side top
3078 label $id.out2f.l1 -text "output device 2:"
3079 button $id.out2f.x1 -text [lindex $outdevlist $audio_outdev2] \
3080 -command \
3081 [list audio_popup $id $id.out2f.x1 audio_outdev2 $outdevlist]
3082 label $id.out2f.l2 -text "channels:"
3083 entry $id.out2f.x2 -textvariable audio_outchan2 -width 3
3084 pack $id.out2f.l1 $id.out2f.x1 $id.out2f.l2 $id.out2f.x2 -side left
3085 }
3086
3087 # output device 3
3088 if {$longform && $multi > 1 && [llength $indevlist] > 2} {
3089 frame $id.out3f
3090 pack $id.out3f -side top
3091 label $id.out3f.l1 -text "output device 3:"
3092 button $id.out3f.x1 -text [lindex $outdevlist $audio_outdev3] \
3093 -command \
3094 [list audio_popup $id $id.out3f.x1 audio_outdev3 $outdevlist]
3095 label $id.out3f.l2 -text "channels:"
3096 entry $id.out3f.x2 -textvariable audio_outchan3 -width 3
3097 pack $id.out3f.l1 $id.out3f.x1 $id.out3f.l2 $id.out3f.x2 -side left
3098 }
3099
3100 # output device 4
3101 if {$longform && $multi > 1 && [llength $indevlist] > 3} {
3102 frame $id.out4f
3103 pack $id.out4f -side top
3104 label $id.out4f.l1 -text "output device 4:"
3105 button $id.out4f.x1 -text [lindex $outdevlist $audio_outdev4] \
3106 -command \
3107 [list audio_popup $id $id.out4f.x1 audio_outdev4 $outdevlist]
3108 label $id.out4f.l2 -text "channels:"
3109 entry $id.out4f.x2 -textvariable audio_outchan4 -width 3
3110 pack $id.out4f.l1 $id.out4f.x1 $id.out4f.l2 $id.out4f.x2 -side left
3111 }
3112
3113 # if not the "long form" but if "multi" is 2, make a button to
3114 # restart with longform set.
3115
3116 if {$longform == 0 && $multi > 1} {
3117 frame $id.longbutton
3118 pack $id.longbutton -side top
3119 button $id.longbutton.b -text {use multiple devices} \
3120 -command {pd pd audio-properties 1 \;}
3121 pack $id.longbutton.b
3122 }
3123 bind $id.srf.x1 <KeyPress-Return> [concat audio_ok $id]
3124 bind $id.srf.x2 <KeyPress-Return> [concat audio_ok $id]
3125 bind $id.in1f.x2 <KeyPress-Return> [concat audio_ok $id]
3126 $id.srf.x1 select from 0
3127 $id.srf.x1 select adjust end
3128 focus $id.srf.x1
3129}
3130
3131####################### midi dialog ##################3
3132
3133proc midi_apply {id} {
3134 global midi_indev1 midi_indev2 midi_indev3 midi_indev4
3135 global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4
3136
3137 pd [concat pd midi-dialog \
3138 $midi_indev1 \
3139 $midi_indev2 \
3140 $midi_indev3 \
3141 $midi_indev4 \
3142 $midi_outdev1 \
3143 $midi_outdev2 \
3144 $midi_outdev3 \
3145 $midi_outdev4 \
3146 \;]
3147}
3148
3149proc midi_cancel {id} {
3150 pd [concat $id cancel \;]
3151}
3152
3153proc midi_ok {id} {
3154 midi_apply $id
3155 midi_cancel $id
3156}
3157
3158# callback from popup menu
3159proc midi_popup_action {buttonname varname devlist index} {
3160 global midi_indevlist midi_outdevlist $varname
3161 $buttonname configure -text [lindex $devlist $index]
3162# puts stderr [concat popup_action $buttonname $varname $index]
3163 set $varname $index
3164}
3165
3166# create a popup menu
3167proc midi_popup {name buttonname varname devlist} {
3168 if [winfo exists $name.popup] {destroy $name.popup}
3169 menu $name.popup -tearoff false
3170# puts stderr [concat $devlist ]
3171 for {set x 0} {$x<[llength $devlist]} {incr x} {
3172 $name.popup add command -label [lindex $devlist $x] \
3173 -command [list midi_popup_action \
3174 $buttonname $varname $devlist $x]
3175 }
3176 tk_popup $name.popup [winfo pointerx $name] [winfo pointery $name] 0
3177}
3178
3179# start a dialog window to select midi devices. "longform" asks us to make
3180# controls for opening several devices; if not, we get an extra button to
3181# turn longform on and restart the dialog.
3182
3183proc pdtk_midi_dialog {id indevlist indev1 indev2 indev3 indev4 \
3184 outdevlist outdev1 outdev2 outdev3 outdev4 longform} {
3185 global midi_indev1 midi_indev2 midi_indev3 midi_indev4
3186 global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4
3187 global midi_indevlist midi_outdevlist
3188
3189 set midi_indev1 $indev1
3190 set midi_indev2 $indev2
3191 set midi_indev3 $indev3
3192 set midi_indev4 $indev4
3193 set midi_outdev1 $outdev1
3194 set midi_outdev2 $outdev2
3195 set midi_outdev3 $outdev3
3196 set midi_outdev4 $outdev4
3197 set midi_indevlist $indevlist
3198 set midi_outdevlist $outdevlist
3199
3200 toplevel $id
3201 wm title $id {midi}
3202 wm protocol $id WM_DELETE_WINDOW [concat midi_cancel $id]
3203
3204 frame $id.buttonframe
3205 pack $id.buttonframe -side bottom -fill x -pady 2m
3206 button $id.buttonframe.cancel -text {Cancel}\
3207 -command "midi_cancel $id"
3208 button $id.buttonframe.apply -text {Apply}\
3209 -command "midi_apply $id"
3210 button $id.buttonframe.ok -text {OK}\
3211 -command "midi_ok $id"
3212 pack $id.buttonframe.cancel -side left -expand 1
3213 pack $id.buttonframe.apply -side left -expand 1
3214 pack $id.buttonframe.ok -side left -expand 1
3215
3216 # input device 1
3217 frame $id.in1f
3218 pack $id.in1f -side top
3219
3220 label $id.in1f.l1 -text "input device 1:"
3221 button $id.in1f.x1 -text [lindex $indevlist $midi_indev1] \
3222 -command [list midi_popup $id $id.in1f.x1 midi_indev1 $indevlist]
3223 pack $id.in1f.l1 $id.in1f.x1 -side left
3224
3225 # input device 2
3226 if {$longform && [llength $indevlist] > 2} {
3227 frame $id.in2f
3228 pack $id.in2f -side top
3229
3230 label $id.in2f.l1 -text "input device 2:"
3231 button $id.in2f.x1 -text [lindex $indevlist $midi_indev2] \
3232 -command [list midi_popup $id $id.in2f.x1 midi_indev2 $indevlist]
3233 pack $id.in2f.l1 $id.in2f.x1 -side left
3234 }
3235
3236 # input device 3
3237 if {$longform && [llength $indevlist] > 3} {
3238 frame $id.in3f
3239 pack $id.in3f -side top
3240
3241 label $id.in3f.l1 -text "input device 3:"
3242 button $id.in3f.x1 -text [lindex $indevlist $midi_indev3] \
3243 -command [list midi_popup $id $id.in3f.x1 midi_indev3 $indevlist]
3244 pack $id.in3f.l1 $id.in3f.x1 -side left
3245 }
3246
3247 # input device 4
3248 if {$longform && [llength $indevlist] > 4} {
3249 frame $id.in4f
3250 pack $id.in4f -side top
3251
3252 label $id.in4f.l1 -text "input device 4:"
3253 button $id.in4f.x1 -text [lindex $indevlist $midi_indev4] \
3254 -command [list midi_popup $id $id.in4f.x1 midi_indev4 $indevlist]
3255 pack $id.in4f.l1 $id.in4f.x1 -side left
3256 }
3257
3258 # output device 1
3259
3260 frame $id.out1f
3261 pack $id.out1f -side top
3262 label $id.out1f.l1 -text "output device 1:"
3263 button $id.out1f.x1 -text [lindex $outdevlist $midi_outdev1] \
3264 -command [list midi_popup $id $id.out1f.x1 midi_outdev1 $outdevlist]
3265 pack $id.out1f.l1 $id.out1f.x1 -side left
3266
3267 # output device 2
3268 if {$longform && [llength $indevlist] > 2} {
3269 frame $id.out2f
3270 pack $id.out2f -side top
3271 label $id.out2f.l1 -text "output device 2:"
3272 button $id.out2f.x1 -text [lindex $outdevlist $midi_outdev2] \
3273 -command \
3274 [list midi_popup $id $id.out2f.x1 midi_outdev2 $outdevlist]
3275 pack $id.out2f.l1 $id.out2f.x1 -side left
3276 }
3277
3278 # output device 3
3279 if {$longform && [llength $indevlist] > 3} {
3280 frame $id.out3f
3281 pack $id.out3f -side top
3282 label $id.out3f.l1 -text "output device 3:"
3283 button $id.out3f.x1 -text [lindex $outdevlist $midi_outdev3] \
3284 -command \
3285 [list midi_popup $id $id.out3f.x1 midi_outdev3 $outdevlist]
3286 pack $id.out3f.l1 $id.out3f.x1 -side left
3287 }
3288
3289 # output device 4
3290 if {$longform && [llength $indevlist] > 4} {
3291 frame $id.out4f
3292 pack $id.out4f -side top
3293 label $id.out4f.l1 -text "output device 4:"
3294 button $id.out4f.x1 -text [lindex $outdevlist $midi_outdev4] \
3295 -command \
3296 [list midi_popup $id $id.out4f.x1 midi_outdev4 $outdevlist]
3297 pack $id.out4f.l1 $id.out4f.x1 -side left
3298 }
3299
3300 # if not the "long form" make a button to
3301 # restart with longform set.
3302
3303 if {$longform == 0} {
3304 frame $id.longbutton
3305 pack $id.longbutton -side top
3306 button $id.longbutton.b -text {use multiple devices} \
3307 -command {pd pd midi-properties 1 \;}
3308 pack $id.longbutton.b
3309 }
3310}
3311
3312############ pdtk_path_dialog -- dialog window for search path #########
3313
3314proc path_apply {id} {
3315 global pd_path0 pd_path1 pd_path2 pd_path3 pd_path4
3316 global pd_path5 pd_path6 pd_path7 pd_path8 pd_path9
3317
3318 pd [concat pd path-dialog \
3319 $pd_path0 $pd_path1 $pd_path2 $pd_path3 $pd_path4 \
3320 $pd_path5 $pd_path6 $pd_path7 $pd_path8 $pd_path9 \
3321 \;]
3322}
3323
3324proc path_cancel {id} {
3325 pd [concat $id cancel \;]
3326}
3327
3328proc path_ok {id} {
3329 path_apply $id
3330 path_cancel $id
3331}
3332set pd_path0 sdfgh
3333
3334proc pdtk_path_dialog {id} {
3335 global pd_path0 pd_path1 pd_path2 pd_path3 pd_path4
3336 global pd_path5 pd_path6 pd_path7 pd_path8 pd_path9
3337
3338 toplevel $id
3339 wm title $id {PD search path for patches and other files}
3340 wm protocol $id WM_DELETE_WINDOW [concat path_cancel $id]
3341
3342 frame $id.buttonframe
3343 pack $id.buttonframe -side bottom -fill x -pady 2m
3344 button $id.buttonframe.cancel -text {Cancel}\
3345 -command "path_cancel $id"
3346 button $id.buttonframe.apply -text {Apply}\
3347 -command "path_apply $id"
3348 button $id.buttonframe.ok -text {OK}\
3349 -command "path_ok $id"
3350 pack $id.buttonframe.cancel -side left -expand 1
3351 pack $id.buttonframe.apply -side left -expand 1
3352 pack $id.buttonframe.ok -side left -expand 1
3353
3354 for {set x 0} {$x < 10} {incr x} {
3355 # input device 1
3356 entry $id.f$x -textvariable pd_path$x -width 80
3357 bind $id.f$x <KeyPress-Return> [concat path_ok $id]
3358 pack $id.f$x -side top
3359 }
3360
3361 focus $id.f0
3362}
3363
3364proc pd_set {var value} {
3365 global $var
3366 set $var $value
3367}
3368set pd_nt 1
3369# (The above is 0 for unix, 1 for microsoft, and 2 for Mac OSX. The first
3370# line is automatically munged by the relevant makefiles.)
3371
3372# Copyright (c) 1997-1999 Miller Puckette.
3373# For information on usage and redistribution, and for a DISCLAIMER OF ALL
3374# WARRANTIES, see the file, "LICENSE.txt," in this distribution.
3375
3376# changed by Thomas Musil 09.2001
3377# between "pdtk_graph_dialog -- dialog window for graphs"
3378# and "pdtk_array_dialog -- dialog window for arrays"
3379# a new dialogbox was inserted, named:
3380# "pdtk_iemgui_dialog -- dialog window for iem guis"
3381#
3382# all this changes are labeled with #######iemlib##########
3383
3384# Tearoff is set to true by default:
3385set pd_tearoff 0
3386set menubar 1
3387
3388set File "F"
3389set Windows "W"
3390set Edit "E"
3391set Find "F"
3392set Put "P"
3393set Media "M"
3394set Help "H"
3395
3396set color grey16
3397set lightcolor grey24
3398
3399option add *font -*-helvetica-*--bold--9-*
3400
3401# los colores de la muerte
3402
3403option add *background $color
3404option add *activeBackground $lightcolor
3405
3406option add *foreground white
3407option add *activeForeground white
3408
3409option add *troughColor $lightcolor
3410
3411option add *highlightThickness 0
3412option add *relief solid startupFile
3413
3414if {$pd_nt == 1} {
3415 global pd_guidir
3416 global pd_tearoff
3417 set pd_gui2 [string range $argv0 0 [expr [string last \\ $argv0 ] - 1]]
3418 regsub -all \\\\ $pd_gui2 / pd_gui3
3419 set pd_guidir $pd_gui3/..
3420 load $pd_guidir/bin/pdtcl
3421 set pd_tearoff 1
3422}
3423
3424if {$pd_nt == 2} {
3425 global pd_guidir
3426 global pd_tearoff
3427 set pd_gui2 [string range $argv0 0 [expr [string last / $argv0 ] - 1]]
3428 set pd_guidir $pd_gui2/..
3429 load $pd_guidir/bin/pdtcl
3430 set pd_tearoff 0
3431}
3432
3433# hack so you can easily test-run this script in linux... define pd_guidir
3434# (which is normally defined at startup in pd under linux...)
3435
3436if {$pd_nt == 0} {
3437 if {! [info exists pd_guidir]} {
3438 global pd_guidir
3439 puts stderr {setting pd_guidir to '.'}
3440 set pd_guidir .
3441 }
3442}
3443
3444# it's unfortunate but we seem to have to turn off global bindings
3445# for Text objects to get control-s and control-t to do what we want for
3446# "text" dialogs below. Also we have to get rid of tab's changing the focus.
3447
3448bind all <Key-Tab> ""
3449bind all <<PrevWindow>> ""
3450bind Text <Control-t> {}
3451bind Text <Control-s> {}
3452# puts stderr [bind all]
3453
3454################## set up main window #########################
3455menu .mbar
3456canvas .dummy -height 2p -width 6c
3457
3458frame .controls
3459pack .controls .dummy -side top -fill x
3460menu .mbar.file -tearoff $pd_tearoff
3461.mbar add cascade -label "$File" -menu .mbar.file
3462menu .mbar.find -tearoff $pd_tearoff
3463.mbar add cascade -label "$Find" -menu .mbar.find
3464menu .mbar.windows -postcommand [concat pdtk_fixwindowmenu] -tearoff $pd_tearoff
3465menu .mbar.audio -tearoff $pd_tearoff
3466if {$pd_nt != 2} {
3467 .mbar add cascade -label "$Windows" -menu .mbar.windows
3468 .mbar add cascade -label "$Media" -menu .mbar.audio
3469} else {
3470# Perhaps this is silly, but Mac HIG want "Window Help" as the last menus
3471 .mbar add cascade -label "$Media" -menu .mbar.audio
3472 .mbar add cascade -label "$Windows" -menu .mbar.windows
3473}
3474menu .mbar.help -tearoff $pd_tearoff
3475.mbar add cascade -label "$Help" -menu .mbar.help
3476
3477set ctrls_audio_on 0
3478set ctrls_meter_on 0
3479set ctrls_inlevel 0
3480set ctrls_outlevel 0
3481
3482frame .controls.switches
3483checkbutton .controls.switches.audiobutton -text {compute audio} \
3484 -variable ctrls_audio_on \
3485 -anchor w \
3486 -command {pd [concat pd dsp $ctrls_audio_on \;]}
3487
3488checkbutton .controls.switches.meterbutton -text {peak meters} \
3489 -variable ctrls_meter_on \
3490 -anchor w \
3491 -command {pd [concat pd meters $ctrls_meter_on \;]}
3492
3493pack .controls.switches.meterbutton .controls.switches.audiobutton -side left
3494
3495frame .controls.inout
3496frame .controls.inout.in
3497label .controls.inout.in.label -text IN
3498entry .controls.inout.in.level -textvariable ctrls_inlevel -width 3
3499button .controls.inout.in.clip -text {CLIP} -state disabled
3500pack .controls.inout.in.label .controls.inout.in.level \
3501 .controls.inout.in.clip -side top -pady 2
3502
3503frame .controls.inout.out
3504label .controls.inout.out.label -text OUT
3505entry .controls.inout.out.level -textvariable ctrls_outlevel -width 3
3506button .controls.inout.out.clip -text {CLIP} -state disabled
3507pack .controls.inout.out.label .controls.inout.out.level \
3508 .controls.inout.out.clip -side top -pady 2
3509
3510button .controls.dio -text "DIO\nerrors" \
3511 -command {pd [concat pd audiostatus \;]}
3512
3513pack .controls.switches -side bottom -pady 12
3514pack .controls.inout.in .controls.inout.out -side left -padx 6
3515pack .controls.inout -side left -padx 14
3516pack .controls.dio -side right -padx 20
3517
3518bind . <Control-Key> {pdtk_pd_ctrlkey %W %K 0}
3519bind . <Control-Shift-Key> {pdtk_pd_ctrlkey %W %K 1}
3520if {$pd_nt == 2} {
3521 bind . <Mod1-Key> {pdtk_canvas_ctrlkey %W %K 0}
3522 bind . <Mod1-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
3523}
3524
3525
3526wm title . "PDa"
3527. configure -menu .mbar -width 200 -height 150
3528
3529############### set up global variables ################################
3530
3531set untitled_number 1
3532set untitled_directory [pwd]
3533set saveas_client doggy
3534set pd_opendir $untitled_directory
3535set pd_undoaction no
3536set pd_redoaction no
3537set pd_undocanvas no
3538
3539################ utility functions #########################
3540
3541proc pdtk_enquote {x} {
3542 set foo [string map {"," "" ";" "" \" ""} $x]
3543 set foo2 [string map {" " "\\ "} $foo]
3544 concat $foo2
3545}
3546
3547proc pdtk_debug {x} {
3548 tk_messageBox -message $x -type ok
3549}
3550
3551proc pdtk_watchdog {} {
3552 pd [concat pd ping \;]
3553 after 2000 {pdtk_watchdog}
3554}
3555
3556proc pdtk_check {x message} {
3557 set answer [tk_messageBox \-message $x \-type yesno \-icon question]
3558 switch $answer {
3559 yes {pd $message} }
3560# no {tk_messageBox \-message "cancelled" \-type ok}
3561}
3562
3563set menu_windowlist {}
3564
3565proc pdtk_fixwindowmenu {} {
3566 global menu_windowlist
3567 .mbar.windows delete 0 end
3568 foreach i $menu_windowlist {
3569 .mbar.windows add command -label [lindex $i 0] \
3570 -command [concat menu_domenuwindow [lindex $i 1]]
3571 menu_fixwindowmenu [lindex $i 1]
3572 }
3573}
3574
3575####### Odd little function to make better Mac accelerators #####
3576
3577proc accel_munge {acc} {
3578 global pd_nt
3579
3580 if {$pd_nt == 2} {
3581 if [string is upper [string index $acc end]] {
3582 return [format "%s%s" "Shift+" \
3583 [string toupper [string map {Ctrl Meta} $acc] end]]
3584 } else {
3585 return [string toupper [string map {Ctrl Meta} $acc] end]
3586 }
3587 } else {
3588 return $acc
3589 }
3590}
3591
3592
3593
3594############### the "New" menu command ########################
3595proc menu_new {} {
3596 global untitled_number
3597 global untitled_directory
3598 pd [concat pd filename Untitled-$untitled_number $untitled_directory \;]
3599 pd {
3600 #N canvas;
3601 #X pop 1;
3602 }
3603 set untitled_number [expr $untitled_number + 1]
3604}
3605
3606################## the "Open" menu command #########################
3607
3608proc menu_open {} {
3609 global pd_opendir
3610
3611 set filename [tk_getOpenFile -defaultextension .pd \
3612 -filetypes { {{pd files} {.pd}} {{max files} {.pat}}} \
3613 -initialdir $pd_opendir]
3614
3615 if {$filename != ""} {
3616 set directory [string range $filename 0 \
3617 [expr [string last / $filename ] - 1]]
3618 set pd_opendir $directory
3619 set basename [string range $filename \
3620 [expr [string last / $filename ] + 1] end]
3621
3622# pd_debug [concat file $filename base $basename dir $directory]
3623
3624 pd [concat pd open [pdtk_enquote $basename] \
3625 [pdtk_enquote $directory]\;]
3626 }
3627}
3628
3629################## the "Message" menu command #########################
3630proc menu_send {} {
3631 toplevel .sendpanel
3632 entry .sendpanel.entry -textvariable send_textvariable
3633 pack .sendpanel.entry -side bottom -fill both -ipadx 100
3634 .sendpanel.entry select from 0
3635 .sendpanel.entry select adjust end
3636 bind .sendpanel.entry <KeyPress-Return> {
3637 pd [concat $send_textvariable \;]
3638 after 50 {destroy .sendpanel}
3639 }
3640 focus .sendpanel.entry
3641}
3642
3643################## the "Quit" menu command #########################
3644proc menu_really_quit {} {pd {pd quit;}}
3645
3646proc menu_quit {} {pd {pd quit;}}
3647
3648######### the "Pd" menu command, which puts the Pd window on top ########
3649proc menu_pop_pd {} {raise .}
3650
3651######### the "audio" menu command ###############
3652proc menu_audio {flag} {pd [concat pd dsp $flag \;]}
3653
3654######### the "documentation" menu command ###############
3655
3656set doc_number 1
3657
3658proc menu_opentext {filename} {
3659 global doc_number
3660 global pd_guidir
3661 global pd_myversion
3662 set name [format ".help%d" $doc_number]
3663 toplevel $name
3664 text $name.text -fg black -relief raised -bd 2 -font -*-courier-bold--normal--12-* \
3665 -yscrollcommand "$name.scroll set" -background white
3666 scrollbar $name.scroll -command "$name.text yview"
3667 pack $name.scroll -side right -fill y
3668 pack $name.text -side left -fill both -expand 1
3669
3670 set f [open $filename]
3671 while {![eof $f]} {
3672 set bigstring [read $f 1000]
3673 regsub -all PD_BASEDIR $bigstring $pd_guidir bigstring2
3674 regsub -all PD_VERSION $bigstring2 $pd_myversion bigstring3
3675 $name.text insert end $bigstring3
3676 }
3677 close $f
3678 set doc_number [expr $doc_number + 1]
3679}
3680
3681set help_directory $pd_guidir/doc
3682
3683proc menu_documentation {} {
3684 global help_directory
3685 global pd_nt
3686
3687 set filename [tk_getOpenFile -defaultextension .pd \
3688 -filetypes { {{documentation} {.pd .txt .htm}} } \
3689 -initialdir $help_directory]
3690
3691 if {$filename != ""} {
3692 if {[string first .txt $filename] >= 0} {
3693 menu_opentext $filename
3694 } elseif {[string first .htm $filename] >= 0} {
3695 if {$pd_nt == 0} {
3696 exec sh -c \
3697 [format "mozilla file:%s || netscape file:%s &\n" \
3698 $filename $filename]
3699 } elseif {$pd_nt == 2} {
3700 puts stderr [format "open %s" $filename]
3701 exec sh -c \
3702 [format "open %s" $filename]
3703 } else {
3704 exec rundll32 url.dll,FileProtocolHandler \
3705 [format "file:%s" $filename] &
3706 }
3707 } else {
3708 set help_directory [string range $filename 0 \
3709 [expr [string last / $filename ] - 1]]
3710 set basename [string range $filename \
3711 [expr [string last / $filename ] + 1] end]
3712 pd [concat pd open [pdtk_enquote $basename] \
3713 [pdtk_enquote $help_directory] \;]
3714 }
3715 }
3716}
3717
3718proc menu_doc_open {subdir basename} {
3719 global pd_guidir
3720
3721 set dirname $pd_guidir/$subdir
3722
3723 if {[string first .txt $basename] >= 0} {
3724 menu_opentext $dirname/$basename
3725 } else {
3726 pd [concat pd open [pdtk_enquote $basename] \
3727 [pdtk_enquote $dirname] \;]
3728 }
3729}
3730
3731############# routine to add audio and help menus ###############
3732
3733proc menu_addstd {mbar} {
3734 global pd_apilist
3735# the "Audio" menu
3736 $mbar.audio add command -label {audio ON} -accelerator [accel_munge "Ctrl+/"] \
3737 -command {menu_audio 1}
3738 $mbar.audio add command -label {audio OFF} -accelerator [accel_munge "Ctrl+."] \
3739 -command {menu_audio 0}
3740 for {set x 0} {$x<[llength $pd_apilist]} {incr x} {
3741 $mbar.audio add radiobutton -label [lindex [lindex $pd_apilist $x] 0] \
3742 -command {menu_audio 0} -variable pd_whichapi \
3743 -value [lindex [lindex $pd_apilist $x] 1]\
3744 -command {pd [concat pd audio-setapi $pd_whichapi \;]}
3745 }
3746 $mbar.audio add command -label {Audio settings...} \
3747 -command {pd pd audio-properties \;}
3748
3749 $mbar.audio add command -label {MIDI settings...} \
3750 -command {pd pd midi-properties \;}
3751 $mbar.audio add command -label {Test Audio and MIDI} \
3752 -command {menu_doc_open doc/7.stuff/tools testtone.pd}
3753 $mbar.audio add command -label {Load Meter} \
3754 -command {menu_doc_open doc/7.stuff/tools load-meter.pd}
3755
3756
3757 $mbar.audio add checkbutton -label "Show Menubar" \
3758 -indicatoron true -selectcolor grey85 \
3759 -variable menubar
3760
3761# the "Help" menu
3762 $mbar.help add command -label {About Pd} \
3763 -command {menu_doc_open doc/1.manual 1.introduction.txt}
3764 $mbar.help add command -label {Pure Documentation...} \
3765 -command {menu_documentation}
3766}
3767
3768#################### the "File" menu for the Pd window ##############
3769
3770.mbar.file add command -label New -command {menu_new} \
3771 -accelerator [accel_munge "Ctrl+n"]
3772.mbar.file add command -label Open -command {menu_open} \
3773 -accelerator [accel_munge "Ctrl+o"]
3774.mbar.file add separator
3775.mbar.file add command -label Message -command {menu_send} \
3776 -accelerator [accel_munge "Ctrl+m"]
3777.mbar.file add command -label Path... \
3778 -command {pd pd start-path-dialog \;}
3779.mbar.file add separator
3780.mbar.file add command -label Quit -command {menu_quit} \
3781 -accelerator [accel_munge "Ctrl+q"]
3782
3783#################### the "Find" menu for the Pd window ##############
3784.mbar.find add command -label {last error?} -command {menu_finderror}
3785
3786########### functions for menu functions on document windows ########
3787
3788proc menu_save {name} {
3789 pdtk_canvas_checkgeometry $name
3790 pd [concat $name menusave \;]
3791}
3792
3793proc menu_saveas {name} {
3794 pdtk_canvas_checkgeometry $name
3795 pd [concat $name menusaveas \;]
3796}
3797
3798proc menu_print {name} {
3799 set filename [tk_getSaveFile -initialfile pd.ps \
3800 -defaultextension .ps \
3801 -filetypes { {{postscript} {.ps}} }]
3802
3803 if {$filename != ""} {
3804 $name.c postscript -file $filename
3805 }
3806}
3807
3808proc menu_close {name} {
3809 pd [concat $name menuclose \;]
3810}
3811
3812proc menu_undo {name} {
3813 global pd_undoaction
3814 global pd_redoaction
3815 global pd_undocanvas
3816 if {$name == $pd_undocanvas && $pd_undoaction != "no"} {
3817 pd [concat $name undo \;]
3818 }
3819}
3820
3821proc menu_redo {name} {
3822 global pd_undoaction
3823 global pd_redoaction
3824 global pd_undocanvas
3825 if {$name == $pd_undocanvas && $pd_redoaction != "no"} {
3826 pd [concat $name redo \;]
3827 }
3828}
3829
3830proc menu_cut {name} {
3831 pd [concat $name cut \;]
3832}
3833
3834proc menu_copy {name} {
3835 pd [concat $name copy \;]
3836}
3837
3838proc menu_paste {name} {
3839 pd [concat $name paste \;]
3840}
3841
3842proc menu_duplicate {name} {
3843 pd [concat $name duplicate \;]
3844}
3845
3846proc menu_selectall {name} {
3847 pd [concat $name selectall \;]
3848}
3849
3850proc menu_texteditor {name} {
3851 pd [concat $name texteditor \;]
3852}
3853
3854proc menu_font {name} {
3855 pd [concat $name menufont \;]
3856}
3857
3858proc menu_tidyup {name} {
3859 pd [concat $name tidy \;]
3860}
3861
3862proc menu_editmode {name} {
3863 pd [concat $name editmode 0 \;]
3864}
3865
3866proc menu_object {name accel} {
3867 pd [concat $name obj $accel \;]
3868}
3869
3870proc menu_message {name accel} {
3871 pd [concat $name msg $accel \;]
3872}
3873
3874proc menu_floatatom {name accel} {
3875 pd [concat $name floatatom $accel \;]
3876}
3877
3878proc menu_symbolatom {name accel} {
3879 pd [concat $name symbolatom $accel \;]
3880}
3881
3882proc menu_comment {name accel} {
3883 pd [concat $name text $accel \;]
3884}
3885
3886proc menu_graph {name} {
3887 pd [concat $name graph \;]
3888}
3889
3890proc menu_array {name} {
3891 pd [concat $name menuarray \;]
3892}
3893
3894############iemlib##################
3895proc menu_bng {name accel} {
3896 pd [concat $name bng $accel \;]
3897}
3898
3899proc menu_toggle {name accel} {
3900 pd [concat $name toggle $accel \;]
3901}
3902
3903proc menu_numbox {name accel} {
3904 pd [concat $name numbox $accel \;]
3905}
3906
3907proc menu_vslider {name accel} {
3908 pd [concat $name vslider $accel \;]
3909}
3910
3911proc menu_hslider {name accel} {
3912 pd [concat $name hslider $accel \;]
3913}
3914
3915proc menu_hradio {name accel} {
3916 pd [concat $name hradio $accel \;]
3917}
3918
3919proc menu_vradio {name accel} {
3920 pd [concat $name vradio $accel \;]
3921}
3922
3923proc menu_vumeter {name accel} {
3924 pd [concat $name vumeter $accel \;]
3925}
3926
3927proc menu_mycnv {name accel} {
3928 pd [concat $name mycnv $accel \;]
3929}
3930
3931############iemlib##################
3932
3933# correct edit menu, enabling or disabling undo/redo
3934# LATER also cut/copy/paste
3935proc menu_fixeditmenu {name} {
3936 global pd_undoaction
3937 global pd_redoaction
3938 global pd_undocanvas
3939# puts stderr [concat menu_fixeditmenu $name $pd_undocanvas $pd_undoaction]
3940 if {$name == $pd_undocanvas && $pd_undoaction != "no"} {
3941 $name.m.edit entryconfigure "Undo*" -state normal \
3942 -label [concat "Undo " $pd_undoaction]
3943 } else {
3944 $name.m.edit entryconfigure "Undo*" -state disabled -label "Undo"
3945 }
3946 if {$name == $pd_undocanvas && $pd_redoaction != "no"} {
3947 $name.m.edit entryconfigure "Redo*" -state normal\
3948 -label [concat "Redo " $pd_redoaction]
3949 } else {
3950 $name.m.edit entryconfigure "Redo*" -state disabled
3951 }
3952}
3953
3954# message from Pd to update the currently available undo/redo action
3955proc pdtk_undomenu {name undoaction redoaction} {
3956 global pd_undoaction
3957 global pd_redoaction
3958 global pd_undocanvas
3959# puts stderr [concat pdtk_undomenu $name $undoaction $redoaction]
3960 set pd_undocanvas $name
3961 set pd_undoaction $undoaction
3962 set pd_redoaction $redoaction
3963 if {$name != "nobody"} {
3964# unpleasant way of avoiding a more unpleasant bug situation --atl 2002.11.25
3965 menu_fixeditmenu $name
3966 }
3967}
3968
3969proc menu_windowparent {name} {
3970 pd [concat $name findparent \;]
3971}
3972
3973proc menu_findagain {name} {
3974 pd [concat $name findagain \;]
3975}
3976
3977proc menu_finderror {} {
3978 pd [concat pd finderror \;]
3979}
3980
3981proc menu_domenuwindow {i} {
3982 raise $i
3983}
3984
3985proc menu_fixwindowmenu {name} {
3986 global menu_windowlist
3987 global pd_tearoff
3988 global menubar
3989
3990 if { $menubar == 1 } {
3991 $name.m.windows add command
3992 if $pd_tearoff {
3993 $name.m.windows delete 4 end
3994 } else {
3995 $name.m.windows delete 3 end
3996 }
3997 foreach i $menu_windowlist {
3998 $name.m.windows add command -label [lindex $i 0] \
3999 -command [concat menu_domenuwindow [lindex $i 1]]
4000 }
4001 }
4002}
4003
4004################## the "find" menu item ###################
4005
4006set find_canvas nobody
4007set find_string ""
4008set find_count 1
4009
4010proc find_apply {name} {
4011 global find_string
4012 global find_canvas
4013 regsub -all \; $find_string " _semi_ " find_string2
4014 regsub -all \, $find_string2 " _comma_ " find_string3
4015# puts stderr [concat $find_canvas find $find_string3 \
4016# \;]
4017 pd [concat $find_canvas find $find_string3 \
4018 \;]
4019 after 50 destroy $name
4020}
4021
4022proc find_cancel {name} {
4023 after 50 destroy $name
4024}
4025
4026proc menu_findobject {canvas} {
4027 global find_string
4028 global find_canvas
4029 global find_count
4030
4031 set name [format ".find%d" $find_count]
4032 set find_count [expr $find_count + 1]
4033
4034 set find_canvas $canvas
4035
4036 toplevel $name
4037
4038 label $name.label -text {find...}
4039 pack $name.label -side top
4040
4041 entry $name.entry -textvariable find_string
4042 pack $name.entry -side top
4043
4044 frame $name.buttonframe
4045 pack $name.buttonframe -side bottom -fill x -pady 2m
4046 button $name.buttonframe.cancel -text {Cancel}\
4047 -command "find_cancel $name"
4048 button $name.buttonframe.ok -text {OK}\
4049 -command "find_apply $name"
4050 pack $name.buttonframe.cancel -side left -expand 1
4051 pack $name.buttonframe.ok -side left -expand 1
4052
4053 $name.entry select from 0
4054 $name.entry select adjust end
4055 bind $name.entry <KeyPress-Return> [ concat find_apply $name]
4056 focus $name.entry
4057}
4058
4059
4060
4061proc pdtk_canvas_menubar {name width height geometry editable} {
4062 global pd_opendir
4063 global pd_tearoff
4064 global pd_nt
4065
4066 global File Edit Find Put Windows Media Help
4067
4068
4069 menu $name.m.file -tearoff $pd_tearoff
4070 $name.m add cascade -label "$File" -menu $name.m.file
4071
4072 $name.m.file add command -label New -command {menu_new} \
4073 -accelerator [accel_munge "Ctrl+n"]
4074
4075 $name.m.file add command -label Open -command {menu_open} \
4076 -accelerator [accel_munge "Ctrl+o"]
4077
4078 $name.m.file add separator
4079 $name.m.file add command -label Message -command {menu_send} \
4080 -accelerator [accel_munge "Ctrl+m"]
4081
4082 $name.m.file add command -label Path... \
4083 -command {pd pd start-path-dialog \;}
4084
4085 $name.m.file add separator
4086 $name.m.file add command -label Close \
4087 -command [concat menu_close $name] \
4088 -accelerator [accel_munge "Ctrl+w"]
4089
4090 $name.m.file add command -label Save -command [concat menu_save $name] \
4091 -accelerator [accel_munge "Ctrl+s"]
4092
4093 $name.m.file add command -label "Save as..." \
4094 -command [concat menu_saveas $name] \
4095 -accelerator [accel_munge "Ctrl+S"]
4096
4097 $name.m.file add command -label Print -command [concat menu_print $name] \
4098 -accelerator [accel_munge "Ctrl+p"]
4099
4100 $name.m.file add separator
4101
4102 $name.m.file add command -label Quit -command {menu_quit} \
4103 -accelerator [accel_munge "Ctrl+q"]
4104
4105# the edit menu
4106 menu $name.m.edit -postcommand [concat menu_fixeditmenu $name] -tearoff $pd_tearoff
4107 $name.m add cascade -label $Edit -menu $name.m.edit
4108
4109 $name.m.edit add command -label Undo -command [concat menu_undo $name] \
4110 -accelerator [accel_munge "Ctrl+z"]
4111
4112 $name.m.edit add command -label Redo -command [concat menu_redo $name] \
4113 -accelerator [accel_munge "Ctrl+Z"]
4114
4115 $name.m.edit add separator
4116
4117 $name.m.edit add command -label Cut -command [concat menu_cut $name] \
4118 -accelerator [accel_munge "Ctrl+x"]
4119
4120 $name.m.edit add command -label Copy -command [concat menu_copy $name] \
4121 -accelerator [accel_munge "Ctrl+c"]
4122
4123 $name.m.edit add command -label Paste \
4124 -command [concat menu_paste $name] \
4125 -accelerator [accel_munge "Ctrl+v"]
4126
4127 $name.m.edit add command -label Duplicate \
4128 -command [concat menu_duplicate $name] \
4129 -accelerator [accel_munge "Ctrl+d"]
4130
4131 $name.m.edit add command -label {Select all} \
4132 -command [concat menu_selectall $name] \
4133 -accelerator [accel_munge "Ctrl+a"]
4134
4135 $name.m.edit add separator
4136
4137 $name.m.edit add command -label {Text Editor} \
4138 -command [concat menu_texteditor $name] \
4139 -accelerator [accel_munge "Ctrl+t"]
4140
4141 $name.m.edit add command -label Font \
4142 -command [concat menu_font $name]
4143
4144 $name.m.edit add command -label {Tidy Up} \
4145 -command [concat menu_tidyup $name]
4146
4147 $name.m.edit add separator
4148
4149############iemlib##################
4150# instead of "red = #BC3C60" we take "grey85", so there is no difference,
4151# if widget is selected or not.
4152
4153 $name.m.edit add checkbutton -label "Edit mode" \
4154 -indicatoron true -selectcolor grey85 \
4155 -command [concat menu_editmode $name] \
4156 -accelerator [accel_munge "Ctrl+e"]
4157
4158 if { $editable == 0 } {
4159 $name.m.edit entryconfigure "Edit mode" -indicatoron false }
4160
4161############iemlib##################
4162
4163# the put menu
4164 menu $name.m.put -tearoff $pd_tearoff
4165 $name.m add cascade -label $Put -menu $name.m.put
4166
4167 $name.m.put add command -label Object \
4168 -command [concat menu_object $name 0] \
4169 -accelerator [accel_munge "Ctrl+1"]
4170
4171 $name.m.put add command -label Message \
4172 -command [concat menu_message $name 0] \
4173 -accelerator [accel_munge "Ctrl+2"]
4174
4175 $name.m.put add command -label Number \
4176 -command [concat menu_floatatom $name 0] \
4177 -accelerator [accel_munge "Ctrl+3"]
4178
4179 $name.m.put add command -label Symbol \
4180 -command [concat menu_symbolatom $name 0] \
4181 -accelerator [accel_munge "Ctrl+4"]
4182
4183 $name.m.put add command -label Comment \
4184 -command [concat menu_comment $name 0] \
4185 -accelerator [accel_munge "Ctrl+5"]
4186
4187 $name.m.put add separator
4188
4189############iemlib##################
4190
4191 $name.m.put add command -label Bang \
4192 -command [concat menu_bng $name 0] \
4193 -accelerator [accel_munge "Alt+b"]
4194
4195 $name.m.put add command -label Toggle \
4196 -command [concat menu_toggle $name 0] \
4197 -accelerator [accel_munge "Alt+t"]
4198
4199 $name.m.put add command -label Number2 \
4200 -command [concat menu_numbox $name 0] \
4201 -accelerator [accel_munge "Alt+n"]
4202
4203 $name.m.put add command -label Vslider \
4204 -command [concat menu_vslider $name 0] \
4205 -accelerator [accel_munge "Alt+v"]
4206
4207 $name.m.put add command -label Hslider \
4208 -command [concat menu_hslider $name 0] \
4209 -accelerator [accel_munge "Alt+h"]
4210
4211 $name.m.put add command -label Vradio \
4212 -command [concat menu_vradio $name 0] \
4213 -accelerator [accel_munge "Alt+d"]
4214
4215 $name.m.put add command -label Hradio \
4216 -command [concat menu_hradio $name 0] \
4217 -accelerator [accel_munge "Alt+i"]
4218
4219 $name.m.put add command -label VU \
4220 -command [concat menu_vumeter $name 0] \
4221 -accelerator [accel_munge "Alt+u"]
4222
4223 $name.m.put add command -label Canvas \
4224 -command [concat menu_mycnv $name 0] \
4225 -accelerator [accel_munge "Alt+c"]
4226
4227############iemlib##################
4228
4229 $name.m.put add separator
4230
4231 $name.m.put add command -label Graph \
4232 -command [concat menu_graph $name]
4233
4234 $name.m.put add command -label Array \
4235 -command [concat menu_array $name]
4236
4237# the find menu
4238 menu $name.m.find -tearoff $pd_tearoff
4239 $name.m add cascade -label "$Find" -menu $name.m.find
4240
4241 $name.m.find add command -label {Find...} \
4242 -accelerator [accel_munge "Ctrl+f"] \
4243 -command [concat menu_findobject $name]
4244 $name.m.find add command -label {Find Again} \
4245 -accelerator [accel_munge "Ctrl+g"] \
4246 -command [concat menu_findagain $name]
4247 $name.m.find add command -label {Find last error} \
4248 -command [concat menu_finderror]
4249
4250# the window menu
4251 menu $name.m.windows -postcommand [concat menu_fixwindowmenu $name] \
4252 -tearoff $pd_tearoff
4253
4254 $name.m.windows add command -label {parent window}\
4255 -command [concat menu_windowparent $name]
4256 $name.m.windows add command -label {Pd window} -command menu_pop_pd
4257 $name.m.windows add separator
4258
4259# the audio menu
4260 menu $name.m.audio -tearoff $pd_tearoff
4261
4262 if {$pd_nt != 2} {
4263 $name.m add cascade -label $Windows -menu $name.m.windows
4264 $name.m add cascade -label $Media -menu $name.m.audio
4265 } else {
4266 $name.m add cascade -label $Media -menu $name.m.audio
4267 $name.m add cascade -label $Windows -menu $name.m.windows
4268 }
4269
4270# the help menu
4271 menu $name.m.help -tearoff $pd_tearoff
4272 $name.m add cascade -label $Help -menu $name.m.help
4273
4274 menu_addstd $name.m
4275}
4276
4277
4278############# pdtk_canvas_new -- create a new canvas ###############
4279proc pdtk_canvas_new {name width height geometry editable} {
4280 global pd_opendir
4281 global pd_tearoff
4282 global pd_nt
4283 global menubar
4284
4285 toplevel $name -menu $name.m
4286# puts stderr [concat geometry: $geometry]
4287 wm geometry $name $geometry
4288 wm minsize $name 1 1
4289
4290 canvas $name.c -width $width -height $height -background white \
4291 -yscrollcommand "$name.scrollvert set" \
4292 -xscrollcommand "$name.scrollhort set" \
4293 -scrollregion [concat 0 0 $width $height]
4294
4295
4296 scrollbar $name.scrollvert -command "$name.c yview" -width 7
4297 scrollbar $name.scrollhort -command "$name.c xview" \
4298 -orient horizontal -width 7
4299
4300 pack $name.scrollhort -side bottom -fill x
4301 pack $name.scrollvert -side right -fill y
4302 pack $name.c -side left -expand 1 -fill both
4303
4304# the menubar
4305
4306 menu $name.m
4307
4308 if { $menubar == 1 } {
4309 pdtk_canvas_menubar $name $width $height $geometry $editable
4310 }
4311
4312# the popup menu
4313 menu $name.popup -tearoff false
4314 $name.popup add command -label {Properties} \
4315 -command [concat popup_action $name 0]
4316 $name.popup add command -label {Open} \
4317 -command [concat popup_action $name 1]
4318 $name.popup add command -label {Help} \
4319 -command [concat popup_action $name 2]
4320
4321# WM protocol
4322 wm protocol $name WM_DELETE_WINDOW [concat menu_close $name]
4323
4324# bindings.
4325# this is idiotic -- how do you just sense what mod keys are down and
4326# pass them on? I can't find it anywhere.
4327# Here we encode shift as 1, control 2, alt 4, in agreement
4328# with definitions in g_canvas.c. The third button gets "8" but we don't
4329# bother with modifiers there.
4330# We don't handle multiple clicks yet.
4331
4332 bind $name.c <Button> {pdtk_canvas_click %W %x %y %b 0}
4333 bind $name.c <Shift-Button> {pdtk_canvas_click %W %x %y %b 1}
4334 bind $name.c <Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 3}
4335 bind $name.c <Alt-Button> {pdtk_canvas_click %W %x %y %b 4}
4336 bind $name.c <Alt-Shift-Button> {pdtk_canvas_click %W %x %y %b 5}
4337 bind $name.c <Alt-Control-Button> {pdtk_canvas_click %W %x %y %b 6}
4338 bind $name.c <Alt-Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 7}
4339 global pd_nt
4340 if {$pd_nt == 2} {
4341 bind $name.c <Button-2> {pdtk_canvas_click %W %x %y %b 8}
4342 bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 8}
4343 } else {
4344 bind $name.c <Button-3> {pdtk_canvas_click %W %x %y %b 8}
4345 bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 2}
4346 }
4347# change mac to right-click, not middle click -atl 2002.09.02
4348
4349 bind $name.c <ButtonRelease> {pdtk_canvas_mouseup %W %x %y %b}
4350 bind $name.c <Control-Key> {pdtk_canvas_ctrlkey %W %K 0}
4351 bind $name.c <Control-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
4352 bind $name.c <Alt-Key> {pdtk_canvas_altkey %W %K %A}
4353# bind $name.c <Mod1-Key> {puts stderr [concat mod1 %W %K %A]}
4354 if {$pd_nt == 2} {
4355 bind $name.c <Mod1-Key> {pdtk_canvas_ctrlkey %W %K 0}
4356 bind $name.c <Mod1-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
4357 }
4358 bind $name.c <Key> {pdtk_canvas_key %W %K %A 0}
4359 bind $name.c <Shift-Key> {pdtk_canvas_key %W %K %A 1}
4360 bind $name.c <KeyRelease> {pdtk_canvas_keyup %W %K %A}
4361 bind $name.c <Motion> {pdtk_canvas_motion %W %x %y 0}
4362 bind $name.c <Alt-Motion> {pdtk_canvas_motion %W %x %y 4}
4363 bind $name.c <Map> {pdtk_canvas_map %W}
4364 bind $name.c <Unmap> {pdtk_canvas_unmap %W}
4365 focus $name.c
4366# puts stderr "all done"
4367# after 1 [concat raise $name]
4368}
4369
4370#################### event binding procedures ################
4371
4372#get the name of the toplevel window for a canvas; this is also
4373#the name of the canvas object in Pd.
4374
4375proc canvastosym {name} {
4376 string range $name 0 [expr [string length $name] - 3]
4377}
4378
4379set pdtk_lastcanvasconfigured ""
4380set pdtk_lastcanvasconfiguration ""
4381
4382proc pdtk_canvas_checkgeometry {topname} {
4383 set boo [winfo geometry $topname.c]
4384 set boo2 [wm geometry $topname]
4385 global pdtk_lastcanvasconfigured
4386 global pdtk_lastcanvasconfiguration
4387 if {$topname != $pdtk_lastcanvasconfigured || \
4388 $boo != $pdtk_lastcanvasconfiguration} {
4389 set pdtk_lastcanvasconfigured $topname
4390 set pdtk_lastcanvasconfiguration $boo
4391 pd $topname relocate $boo $boo2 \;
4392 }
4393}
4394
4395proc pdtk_canvas_click {name x y b f} {
4396# puts stderr [concat got $f]
4397 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b $f \;
4398}
4399
4400proc pdtk_canvas_shiftclick {name x y b} {
4401 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 1 \;
4402}
4403
4404proc pdtk_canvas_ctrlclick {name x y b} {
4405 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 2 \;
4406}
4407
4408proc pdtk_canvas_altclick {name x y b} {
4409 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 3 \;
4410}
4411
4412proc pdtk_canvas_dblclick {name x y b} {
4413 pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 4 \;
4414}
4415
4416set pdtk_canvas_mouseup_name 0
4417set pdtk_canvas_mouseup_xminval 0
4418set pdtk_canvas_mouseup_xmaxval 0
4419set pdtk_canvas_mouseup_yminval 0
4420set pdtk_canvas_mouseup_ymaxval 0
4421
4422proc pdtk_canvas_mouseup {name x y b} {
4423 pd [concat [canvastosym $name] mouseup [$name canvasx $x] \
4424 [$name canvasy $y] $b \;]
4425
4426# we use the mouseup event to update scrollbar ranges and recheck the
4427# geometry of the window since I haven't taken the time to figure out
4428# how to do it right.
4429
4430 global pdtk_canvas_mouseup_name
4431 global pdtk_canvas_mouseup_xminval
4432 global pdtk_canvas_mouseup_xmaxval
4433 global pdtk_canvas_mouseup_yminval
4434 global pdtk_canvas_mouseup_ymaxval
4435
4436 set size [$name bbox all]
4437 if {$size != ""} {
4438 set xminval 0
4439 set yminval 0
4440 set xmaxval 100
4441 set ymaxval 100
4442 set x1 [lindex $size 0]
4443 set x2 [lindex $size 2]
4444 set y1 [lindex $size 1]
4445 set y2 [lindex $size 3]
4446
4447 if {$x1 < 0} {set xminval $x1}
4448 if {$y1 < 0} {set yminval $y1}
4449
4450 if {$x2 > 100} {set xmaxval $x2}
4451 if {$y2 > 100} {set ymaxval $y2}
4452
4453 if {$pdtk_canvas_mouseup_name != $name || \
4454 $pdtk_canvas_mouseup_xminval != $xminval || \
4455 $pdtk_canvas_mouseup_xmaxval != $xmaxval || \
4456 $pdtk_canvas_mouseup_yminval != $yminval || \
4457 $pdtk_canvas_mouseup_ymaxval != $ymaxval } {
4458
4459 set newsize "$xminval $yminval $xmaxval $ymaxval"
4460 $name configure -scrollregion $newsize
4461 set pdtk_canvas_mouseup_name $name
4462 set pdtk_canvas_mouseup_xminval $xminval
4463 set pdtk_canvas_mouseup_xmaxval $xmaxval
4464 set pdtk_canvas_mouseup_yminval $yminval
4465 set pdtk_canvas_mouseup_ymaxval $ymaxval
4466 }
4467
4468 }
4469 pdtk_canvas_checkgeometry [canvastosym $name]
4470}
4471
4472proc pdtk_canvas_key {name key iso shift} {
4473# puts stderr [concat down key= $key iso= $iso]
4474# .controls.switches.meterbutton configure -text $key
4475# HACK for MAC OSX -- backspace seems different; I don't understand why.
4476# invesigate this LATER...
4477 global pd_nt
4478 if {$pd_nt == 2} {
4479 if {$key == "BackSpace"} {
4480 set key 8
4481 set keynum 8
4482 }
4483 if {$key == "Delete"} {
4484 set key 8
4485 set keynum 8
4486 }
4487 }
4488 if {$key == "KP_Delete"} {
4489 set key 127
4490 set keynum 127
4491 }
4492 if {$iso != ""} {
4493 scan $iso %c keynum
4494 pd [canvastosym $name] key 1 $keynum $shift\;
4495 } else {
4496 pd [canvastosym $name] key 1 $key $shift\;
4497 }
4498}
4499
4500proc pdtk_canvas_keyup {name key iso} {
4501# puts stderr [concat up key= $key iso= $iso]
4502 if {$iso != ""} {
4503 scan $iso %c keynum
4504 pd [canvastosym $name] key 0 $keynum 0 \;
4505 } else {
4506 pd [canvastosym $name] key 0 $key 0 \;
4507 }
4508}
4509
4510proc pdtk_canvas_altkey {name key iso} {
4511# puts stderr [concat alt-key $iso]
4512############iemlib##################
4513 set topname [string trimright $name .c]
4514 if {$key == "b" || $key == "B"} {menu_bng $topname 1}
4515 if {$key == "t" || $key == "T"} {menu_toggle $topname 1}
4516 if {$key == "n" || $key == "N"} {menu_numbox $topname 1}
4517 if {$key == "v" || $key == "V"} {menu_vslider $topname 1}
4518 if {$key == "h" || $key == "H"} {menu_hslider $topname 1}
4519 if {$key == "i" || $key == "I"} {menu_hradio $topname 1}
4520 if {$key == "d" || $key == "D"} {menu_vradio $topname 1}
4521 if {$key == "u" || $key == "U"} {menu_vumeter $topname 1}
4522 if {$key == "c" || $key == "C"} {menu_mycnv $topname 1}
4523############iemlib##################
4524}
4525
4526proc pdtk_canvas_ctrlkey {name key shift} {
4527# first get rid of ".c" suffix; we'll refer to the toplevel instead
4528 set topname [string trimright $name .c]
4529# puts stderr [concat ctrl-key $key $topname]
4530
4531 if {$key == "n" || $key == "N"} {menu_new}
4532 if {$key == "o" || $key == "O"} {menu_open}
4533 if {$key == "m" || $key == "M"} {menu_send}
4534 if {$key == "q" || $key == "Q"} {
4535 if {$shift == 1} {menu_really_quit} else {menu_quit}
4536 }
4537 if {$key == "s" || $key == "S"} {
4538 if {$shift == 1} {menu_saveas $topname} else {menu_save $topname}
4539 }
4540 if {$key == "z" || $key == "Z"} {
4541 if {$shift == 1} {menu_redo $topname} else {menu_undo $topname}
4542 }
4543 if {$key == "w" || $key == "W"} {menu_close $topname}
4544 if {$key == "p" || $key == "P"} {menu_print $topname}
4545 if {$key == "x" || $key == "X"} {menu_cut $topname}
4546 if {$key == "c" || $key == "C"} {menu_copy $topname}
4547 if {$key == "v" || $key == "V"} {menu_paste $topname}
4548 if {$key == "d" || $key == "D"} {menu_duplicate $topname}
4549 if {$key == "a" || $key == "A"} {menu_selectall $topname}
4550 if {$key == "t" || $key == "T"} {menu_texteditor $topname}
4551 if {$key == "f" || $key == "F"} {menu_findobject $topname}
4552 if {$key == "g" || $key == "G"} {menu_findagain $topname}
4553 if {$key == "1"} {menu_object $topname 1}
4554 if {$key == "2"} {menu_message $topname 1}
4555 if {$key == "3"} {menu_floatatom $topname 1}
4556 if {$key == "4"} {menu_symbolatom $topname 1}
4557 if {$key == "5"} {menu_comment $topname 1}
4558 if {$key == "slash"} {menu_audio 1}
4559 if {$key == "period"} {menu_audio 0}
4560 if {$key == "e" || $key == "E"} {menu_editmode $topname}
4561}
4562
4563proc pdtk_canvas_motion {name x y mods} {
4564# puts stderr [concat [canvastosym $name] $name $x $y]
4565 pd [canvastosym $name] motion [$name canvasx $x] [$name canvasy $y] $mods \;
4566}
4567
4568# "map" event tells us when the canvas becomes visible (arg is "0") or
4569# invisible (arg is ""). Invisibility means the Window Manager has minimized
4570# us. We don't get a final "unmap" event when we destroy the window.
4571proc pdtk_canvas_map {name} {
4572# puts stderr [concat map $name]
4573 pd [canvastosym $name] map 1 \;
4574}
4575
4576proc pdtk_canvas_unmap {name} {
4577# puts stderr [concat unmap $name]
4578 pd [canvastosym $name] map 0 \;
4579}
4580
4581set saveas_dir nowhere
4582
4583############ pdtk_canvas_saveas -- run a saveas dialog ##############
4584
4585proc pdtk_canvas_saveas {name initfile initdir} {
4586 set filename [tk_getSaveFile -initialfile $initfile \
4587 -initialdir $initdir -defaultextension .pd \
4588 -filetypes { {{pd files} {.pd}} {{max files} {.pat}} }]
4589
4590 if {$filename != ""} {
4591 set directory [string range $filename 0 \
4592 [expr [string last / $filename ] - 1]]
4593 set basename [string range $filename \
4594 [expr [string last / $filename ] + 1] end]
4595 pd [concat $name savetofile [pdtk_enquote $basename] \
4596 [pdtk_enquote $directory] \;]
4597# pd [concat $name savetofile $basename $directory \;]
4598 }
4599}
4600
4601############ pdtk_canvas_dofont -- run a font and resize dialog #########
4602
4603set fontsize 0
4604set stretchval 0
4605set whichstretch 0
4606
4607proc dofont_apply {name} {
4608 global fontsize
4609 global stretchval
4610 global whichstretch
4611 set cmd [concat $name font $fontsize $stretchval $whichstretch \;]
4612# puts stderr $cmd
4613 pd $cmd
4614}
4615
4616proc dofont_cancel {name} {
4617 set cmd [concat $name cancel \;]
4618# puts stderr $cmd
4619 pd $cmd
4620}
4621
4622proc pdtk_canvas_dofont {name initsize} {
4623
4624 global fontsize
4625 set fontsize $initsize
4626
4627 global stretchval
4628 set stretchval 100
4629
4630 global whichstretch
4631 set whichstretch 1
4632
4633 toplevel $name
4634 wm title $name {FONT BOMB}
4635 wm protocol $name WM_DELETE_WINDOW [concat dofont_cancel $name]
4636
4637 frame $name.buttonframe
4638 pack $name.buttonframe -side bottom -fill x -pady 2m
4639 button $name.buttonframe.cancel -text {Cancel}\
4640 -command "dofont_cancel $name"
4641 button $name.buttonframe.ok -text {Do it}\
4642 -command "dofont_apply $name"
4643 pack $name.buttonframe.cancel -side left -expand 1
4644 pack $name.buttonframe.ok -side left -expand 1
4645
4646 frame $name.radiof
4647 pack $name.radiof -side left
4648
4649 label $name.radiof.label -text {Font Size:}
4650 pack $name.radiof.label -side top
4651
4652 radiobutton $name.radiof.radio8 -value 8 -variable fontsize -text "8"
4653 radiobutton $name.radiof.radio10 -value 10 -variable fontsize -text "10"
4654 radiobutton $name.radiof.radio12 -value 12 -variable fontsize -text "12"
4655 radiobutton $name.radiof.radio16 -value 16 -variable fontsize -text "16"
4656 radiobutton $name.radiof.radio24 -value 24 -variable fontsize -text "24"
4657 radiobutton $name.radiof.radio36 -value 36 -variable fontsize -text "36"
4658 pack $name.radiof.radio8 -side top -anchor w
4659 pack $name.radiof.radio10 -side top -anchor w
4660 pack $name.radiof.radio12 -side top -anchor w
4661 pack $name.radiof.radio16 -side top -anchor w
4662 pack $name.radiof.radio24 -side top -anchor w
4663 pack $name.radiof.radio36 -side top -anchor w
4664
4665 frame $name.stretchf
4666 pack $name.stretchf -side left
4667
4668 label $name.stretchf.label -text {Stretch:}
4669 pack $name.stretchf.label -side top
4670
4671 entry $name.stretchf.entry -textvariable stretchval -width 5
4672 pack $name.stretchf.entry -side left
4673
4674 radiobutton $name.stretchf.radio1 \
4675 -value 1 -variable whichstretch -text "X and Y"
4676 radiobutton $name.stretchf.radio2 \
4677 -value 2 -variable whichstretch -text "X only"
4678 radiobutton $name.stretchf.radio3 \
4679 -value 3 -variable whichstretch -text "Y only"
4680
4681 pack $name.stretchf.radio1 -side top -anchor w
4682 pack $name.stretchf.radio2 -side top -anchor w
4683 pack $name.stretchf.radio3 -side top -anchor w
4684
4685}
4686
4687############ pdtk_gatom_dialog -- run a gatom dialog #########
4688
4689# see graph_apply, etc., for comments about handling variable names here...
4690
4691proc gatom_escape {sym} {
4692 if {[string length $sym] == 0} {
4693 set ret "-"
4694# puts stderr [concat escape1 $sym $ret]
4695 } else {
4696 if {[string equal -length 1 $sym "-"]} {
4697 set ret [string replace $sym 0 0 "--"]
4698# puts stderr [concat escape $sym $ret]
4699 } else {
4700 if {[string equal -length 1 $sym "$"]} {
4701 set ret [string replace $sym 0 0 "#"]
4702# puts stderr [concat unescape $sym $ret]
4703 } else {
4704 set ret $sym
4705# puts stderr [concat escape $sym "no change"]
4706 }
4707 }
4708 }
4709 concat $ret
4710}
4711
4712proc gatom_unescape {sym} {
4713 if {[string equal -length 1 $sym "-"]} {
4714 set ret [string replace $sym 0 0 ""]
4715# puts stderr [concat unescape $sym $ret]
4716 } else {
4717 if {[string equal -length 1 $sym "#"]} {
4718 set ret [string replace $sym 0 0 "$"]
4719# puts stderr [concat unescape $sym $ret]
4720 } else {
4721 set ret $sym
4722# puts stderr [concat unescape $sym "no change"]
4723 }
4724 }
4725 concat $ret
4726}
4727
4728proc dogatom_apply {id} {
4729 set vid [string trimleft $id .]
4730
4731 set var_gatomwidth [concat gatomwidth_$vid]
4732 global $var_gatomwidth
4733 set var_gatomlo [concat gatomlo_$vid]
4734 global $var_gatomlo
4735 set var_gatomhi [concat gatomhi_$vid]
4736 global $var_gatomhi
4737 set var_gatomwherelabel [concat gatomwherelabel_$vid]
4738 global $var_gatomwherelabel
4739 set var_gatomlabel [concat gatomlabel_$vid]
4740 global $var_gatomlabel
4741 set var_gatomsymfrom [concat gatomsymfrom_$vid]
4742 global $var_gatomsymfrom
4743 set var_gatomsymto [concat gatomsymto_$vid]
4744 global $var_gatomsymto
4745
4746# set cmd [concat $id param $gatomwidth $gatomlo $gatomhi \;]
4747
4748 set cmd [concat $id param \
4749 [eval concat $$var_gatomwidth] \
4750 [eval concat $$var_gatomlo] \
4751 [eval concat $$var_gatomhi] \
4752 [eval gatom_escape $$var_gatomlabel] \
4753 [eval concat $$var_gatomwherelabel] \
4754 [eval gatom_escape $$var_gatomsymfrom] \
4755 [eval gatom_escape $$var_gatomsymto] \
4756 \;]
4757
4758# puts stderr $cmd
4759 pd $cmd
4760}
4761
4762proc dogatom_cancel {name} {
4763 set cmd [concat $name cancel \;]
4764# puts stderr $cmd
4765 pd $cmd
4766}
4767
4768proc dogatom_ok {name} {
4769 dogatom_apply $name
4770 dogatom_cancel $name
4771}
4772
4773proc pdtk_gatom_dialog {id initwidth initlo inithi \
4774 wherelabel label symfrom symto} {
4775
4776 set vid [string trimleft $id .]
4777
4778 set var_gatomwidth [concat gatomwidth_$vid]
4779 global $var_gatomwidth
4780 set var_gatomlo [concat gatomlo_$vid]
4781 global $var_gatomlo
4782 set var_gatomhi [concat gatomhi_$vid]
4783 global $var_gatomhi
4784 set var_gatomwherelabel [concat gatomwherelabel_$vid]
4785 global $var_gatomwherelabel
4786 set var_gatomlabel [concat gatomlabel_$vid]
4787 global $var_gatomlabel
4788 set var_gatomsymfrom [concat gatomsymfrom_$vid]
4789 global $var_gatomsymfrom
4790 set var_gatomsymto [concat gatomsymto_$vid]
4791 global $var_gatomsymto
4792
4793 set $var_gatomwidth $initwidth
4794 set $var_gatomlo $initlo
4795 set $var_gatomhi $inithi
4796 set $var_gatomwherelabel $wherelabel
4797 set $var_gatomlabel [gatom_unescape $label]
4798 set $var_gatomsymfrom [gatom_unescape $symfrom]
4799 set $var_gatomsymto [gatom_unescape $symto]
4800
4801 toplevel $id
4802 wm title $id {Atom}
4803 wm protocol $id WM_DELETE_WINDOW [concat dogatom_cancel $id]
4804
4805 frame $id.buttonframe
4806 pack $id.buttonframe -side bottom -fill x -pady 2m
4807 button $id.buttonframe.cancel -text {Cancel}\
4808 -command "dogatom_cancel $id"
4809 button $id.buttonframe.apply -text {Apply}\
4810 -command "dogatom_apply $id"
4811 button $id.buttonframe.ok -text {OK}\
4812 -command "dogatom_ok $id"
4813 pack $id.buttonframe.cancel -side left -expand 1
4814 pack $id.buttonframe.apply -side left -expand 1
4815 pack $id.buttonframe.ok -side left -expand 1
4816
4817 frame $id.paramsymto
4818 pack $id.paramsymto -side bottom
4819 label $id.paramsymto.entryname -text {send symbol}
4820 entry $id.paramsymto.entry -textvariable $var_gatomsymto -width 20
4821 pack $id.paramsymto.entryname $id.paramsymto.entry -side left
4822
4823 frame $id.paramsymfrom
4824 pack $id.paramsymfrom -side bottom
4825 label $id.paramsymfrom.entryname -text {receive symbol}
4826 entry $id.paramsymfrom.entry -textvariable $var_gatomsymfrom -width 20
4827 pack $id.paramsymfrom.entryname $id.paramsymfrom.entry -side left
4828
4829 frame $id.radio
4830 pack $id.radio -side bottom
4831 label $id.radio.label -text {show label on:}
4832 frame $id.radio.l
4833 frame $id.radio.r
4834 pack $id.radio.label -side top
4835 pack $id.radio.l $id.radio.r -side left
4836 radiobutton $id.radio.l.radio0 -value 0 \
4837 -variable $var_gatomwherelabel \
4838 -text "left"
4839 radiobutton $id.radio.l.radio1 -value 1 \
4840 -variable $var_gatomwherelabel \
4841 -text "right"
4842 radiobutton $id.radio.r.radio2 -value 2 \
4843 -variable $var_gatomwherelabel \
4844 -text "top"
4845 radiobutton $id.radio.r.radio3 -value 3 \
4846 -variable $var_gatomwherelabel \
4847 -text "bottom"
4848 pack $id.radio.l.radio0 $id.radio.l.radio1 -side top -anchor w
4849 pack $id.radio.r.radio2 $id.radio.r.radio3 -side top -anchor w
4850
4851
4852 frame $id.paramlabel
4853 pack $id.paramlabel -side bottom
4854 label $id.paramlabel.entryname -text label
4855 entry $id.paramlabel.entry -textvariable $var_gatomlabel -width 20
4856 pack $id.paramlabel.entryname $id.paramlabel.entry -side left
4857
4858 frame $id.paramhi
4859 pack $id.paramhi -side bottom
4860 label $id.paramhi.entryname -text "upper limit"
4861 entry $id.paramhi.entry -textvariable $var_gatomhi -width 8
4862 pack $id.paramhi.entryname $id.paramhi.entry -side left
4863
4864 frame $id.paramlo
4865 pack $id.paramlo -side bottom
4866 label $id.paramlo.entryname -text "lower limit"
4867 entry $id.paramlo.entry -textvariable $var_gatomlo -width 8
4868 pack $id.paramlo.entryname $id.paramlo.entry -side left
4869
4870 frame $id.params
4871 pack $id.params -side bottom
4872 label $id.params.entryname -text width
4873 entry $id.params.entry -textvariable $var_gatomwidth -width 4
4874 pack $id.params.entryname $id.params.entry -side left
4875
4876
4877
4878 bind $id.paramhi.entry <KeyPress-Return> [concat dogatom_ok $id]
4879 bind $id.paramlo.entry <KeyPress-Return> [concat dogatom_ok $id]
4880 bind $id.params.entry <KeyPress-Return> [concat dogatom_ok $id]
4881 $id.params.entry select from 0
4882 $id.params.entry select adjust end
4883 focus $id.params.entry
4884}
4885
4886############ pdtk_canvas_popup -- popup menu for canvas #########
4887
4888set popup_xpix 0
4889set popup_ypix 0
4890
4891proc popup_action {name action} {
4892 global popup_xpix popup_ypix
4893 set cmd [concat $name done-popup $action $popup_xpix $popup_ypix \;]
4894# puts stderr $cmd
4895 pd $cmd
4896}
4897
4898proc pdtk_canvas_popup {name xpix ypix canprop canopen} {
4899 global popup_xpix popup_ypix
4900 set popup_xpix $xpix
4901 set popup_ypix $ypix
4902 if {$canprop == 0} {$name.popup entryconfigure 0 -state disabled}
4903 if {$canprop == 1} {$name.popup entryconfigure 0 -state active}
4904 if {$canopen == 0} {$name.popup entryconfigure 1 -state disabled}
4905 if {$canopen == 1} {$name.popup entryconfigure 1 -state active}
4906 tk_popup $name.popup [expr $xpix + [winfo rootx $name.c]] \
4907 [expr $ypix + [winfo rooty $name.c]] 0
4908}
4909
4910############ pdtk_graph_dialog -- dialog window for graphs #########
4911
4912# the graph and array dialogs can come up in many copies; but in TK the easiest
4913# way to get data from an "entry", etc., is to set an associated variable
4914# name. This is especially true for grouped "radio buttons". So we have
4915# to synthesize variable names for each instance of the dialog. The dialog
4916# gets a TK pathname $id, from which it strips the leading "." to make a
4917# variable suffix $vid. Then you can get the actual value out by asking for
4918# [eval concat $$variablename]. There should be an easier way but I don't see
4919# it yet.
4920
4921proc graph_apply {id} {
4922# strip "." from the TK id to make a variable name suffix
4923 set vid [string trimleft $id .]
4924# for each variable, make a local variable to hold its name...
4925 set var_graph_x1 [concat graph_x1_$vid]
4926 global $var_graph_x1
4927 set var_graph_x2 [concat graph_x2_$vid]
4928 global $var_graph_x2
4929 set var_graph_xpix [concat graph_xpix_$vid]
4930 global $var_graph_xpix
4931 set var_graph_y1 [concat graph_y1_$vid]
4932 global $var_graph_y1
4933 set var_graph_y2 [concat graph_y2_$vid]
4934 global $var_graph_y2
4935 set var_graph_ypix [concat graph_ypix_$vid]
4936 global $var_graph_ypix
4937
4938 pd [concat $id dialog \
4939 [eval concat $$var_graph_x1] \
4940 [eval concat $$var_graph_y1] \
4941 [eval concat $$var_graph_x2] \
4942 [eval concat $$var_graph_y2] \
4943 [eval concat $$var_graph_xpix] \
4944 [eval concat $$var_graph_ypix] \
4945 \;]
4946}
4947
4948proc graph_cancel {id} {
4949 set cmd [concat $id cancel \;]
4950# puts stderr $cmd
4951 pd $cmd
4952}
4953
4954proc graph_ok {id} {
4955 graph_apply $id
4956 graph_cancel $id
4957}
4958
4959proc pdtk_graph_dialog {id x1 y1 x2 y2 xpix ypix} {
4960 set vid [string trimleft $id .]
4961 set var_graph_x1 [concat graph_x1_$vid]
4962 global $var_graph_x1
4963 set var_graph_x2 [concat graph_x2_$vid]
4964 global $var_graph_x2
4965 set var_graph_xpix [concat graph_xpix_$vid]
4966 global $var_graph_xpix
4967 set var_graph_y1 [concat graph_y1_$vid]
4968 global $var_graph_y1
4969 set var_graph_y2 [concat graph_y2_$vid]
4970 global $var_graph_y2
4971 set var_graph_ypix [concat graph_ypix_$vid]
4972 global $var_graph_ypix
4973
4974 set $var_graph_x1 $x1
4975 set $var_graph_x2 $x2
4976 set $var_graph_xpix $xpix
4977 set $var_graph_y1 $y1
4978 set $var_graph_y2 $y2
4979 set $var_graph_ypix $ypix
4980
4981 toplevel $id
4982 wm title $id {graph}
4983 wm protocol $id WM_DELETE_WINDOW [concat graph_cancel $id]
4984
4985 label $id.label -text {GRAPH BOUNDS}
4986 pack $id.label -side top
4987
4988 frame $id.buttonframe
4989 pack $id.buttonframe -side bottom -fill x -pady 2m
4990 button $id.buttonframe.cancel -text {Cancel}\
4991 -command "graph_cancel $id"
4992 button $id.buttonframe.apply -text {Apply}\
4993 -command "graph_apply $id"
4994 button $id.buttonframe.ok -text {OK}\
4995 -command "graph_ok $id"
4996 pack $id.buttonframe.cancel -side left -expand 1
4997 pack $id.buttonframe.apply -side left -expand 1
4998 pack $id.buttonframe.ok -side left -expand 1
4999
5000 frame $id.xrangef
5001 pack $id.xrangef -side top
5002
5003 label $id.xrangef.l1 -text "X from:"
5004 entry $id.xrangef.x1 -textvariable $var_graph_x1 -width 7
5005 label $id.xrangef.l2 -text "to:"
5006 entry $id.xrangef.x2 -textvariable $var_graph_x2 -width 7
5007 label $id.xrangef.l3 -text "screen width:"
5008 entry $id.xrangef.xpix -textvariable $var_graph_xpix -width 7
5009 pack $id.xrangef.l1 $id.xrangef.x1 \
5010 $id.xrangef.l2 $id.xrangef.x2 \
5011 $id.xrangef.l3 $id.xrangef.xpix -side left
5012
5013 frame $id.yrangef
5014 pack $id.yrangef -side top
5015
5016# dig in the following that the upper bound is labeled y1 but the variable is
5017# y2, etc. This is to deal with the inconsistent use of "upper and lower"
5018# graph bounds... in the dialog the upper Y bound is the lower valued Y pixel.
5019 label $id.yrangef.l1 -text "Y from:"
5020 entry $id.yrangef.y1 -textvariable $var_graph_y2 -width 7
5021 label $id.yrangef.l2 -text "to:"
5022 entry $id.yrangef.y2 -textvariable $var_graph_y1 -width 7
5023 label $id.yrangef.l3 -text "screen height:"
5024 entry $id.yrangef.ypix -textvariable $var_graph_ypix -width 7
5025 pack $id.yrangef.l1 $id.yrangef.y1 \
5026 $id.yrangef.l2 $id.yrangef.y2 \
5027 $id.yrangef.l3 $id.yrangef.ypix -side left
5028
5029 bind $id.xrangef.x1 <KeyPress-Return> [concat graph_ok $id]
5030 bind $id.xrangef.x2 <KeyPress-Return> [concat graph_ok $id]
5031 bind $id.xrangef.xpix <KeyPress-Return> [concat graph_ok $id]
5032 bind $id.yrangef.y1 <KeyPress-Return> [concat graph_ok $id]
5033 bind $id.yrangef.y2 <KeyPress-Return> [concat graph_ok $id]
5034 bind $id.yrangef.ypix <KeyPress-Return> [concat graph_ok $id]
5035 $id.xrangef.x2 select from 0
5036 $id.xrangef.x2 select adjust end
5037 focus $id.xrangef.x2
5038}
5039
5040# begin of change "iemlib"
5041############ pdtk_iemgui_dialog -- dialog window for iem guis #########
5042
5043set iemgui_define_min_flashhold 50
5044set iemgui_define_min_flashbreak 10
5045set iemgui_define_min_fontsize 4
5046
5047proc iemgui_clip_dim {id} {
5048 set vid [string trimleft $id .]
5049
5050 set var_iemgui_wdt [concat iemgui_wdt_$vid]
5051 global $var_iemgui_wdt
5052 set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
5053 global $var_iemgui_min_wdt
5054 set var_iemgui_hgt [concat iemgui_hgt_$vid]
5055 global $var_iemgui_hgt
5056 set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
5057 global $var_iemgui_min_hgt
5058
5059 if {[eval concat $$var_iemgui_wdt] < [eval concat $$var_iemgui_min_wdt]} {
5060 set $var_iemgui_wdt [eval concat $$var_iemgui_min_wdt]
5061 $id.dim.w_ent configure -textvariable $var_iemgui_wdt
5062 }
5063 if {[eval concat $$var_iemgui_hgt] < [eval concat $$var_iemgui_min_hgt]} {
5064 set $var_iemgui_hgt [eval concat $$var_iemgui_min_hgt]
5065 $id.dim.h_ent configure -textvariable $var_iemgui_hgt
5066 }
5067}
5068
5069proc iemgui_clip_num {id} {
5070 set vid [string trimleft $id .]
5071
5072 set var_iemgui_num [concat iemgui_num_$vid]
5073 global $var_iemgui_num
5074
5075 if {[eval concat $$var_iemgui_num] > 2000} {
5076 set $var_iemgui_num 2000
5077 $id.para.num_ent configure -textvariable $var_iemgui_num
5078 }
5079 if {[eval concat $$var_iemgui_num] < 1} {
5080 set $var_iemgui_num 1
5081 $id.para.num_ent configure -textvariable $var_iemgui_num
5082 }
5083}
5084
5085proc iemgui_sched_rng {id} {
5086 set vid [string trimleft $id .]
5087
5088 set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
5089 global $var_iemgui_min_rng
5090 set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
5091 global $var_iemgui_max_rng
5092 set var_iemgui_rng_sch [concat iemgui_rng_sch_$vid]
5093 global $var_iemgui_rng_sch
5094
5095 global iemgui_define_min_flashhold
5096 global iemgui_define_min_flashbreak
5097
5098 if {[eval concat $$var_iemgui_rng_sch] == 2} {
5099 if {[eval concat $$var_iemgui_max_rng] < [eval concat $$var_iemgui_min_rng]} {
5100 set hhh [eval concat $$var_iemgui_min_rng]
5101 set $var_iemgui_min_rng [eval concat $$var_iemgui_max_rng]
5102 set $var_iemgui_max_rng $hhh
5103 $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
5104 $id.rng.min_ent configure -textvariable $var_iemgui_min_rng }
5105 if {[eval concat $$var_iemgui_max_rng] < $iemgui_define_min_flashhold} {
5106 set $var_iemgui_max_rng $iemgui_define_min_flashhold
5107 $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
5108 }
5109 if {[eval concat $$var_iemgui_min_rng] < $iemgui_define_min_flashbreak} {
5110 set $var_iemgui_min_rng $iemgui_define_min_flashbreak
5111 $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
5112 }
5113 }
5114 if {[eval concat $$var_iemgui_rng_sch] == 1} {
5115 if {[eval concat $$var_iemgui_min_rng] == 0.0} {
5116 set $var_iemgui_min_rng 1.0
5117 $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
5118 }
5119 }
5120}
5121
5122proc iemgui_verify_rng {id} {
5123 set vid [string trimleft $id .]
5124
5125 set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
5126 global $var_iemgui_min_rng
5127 set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
5128 global $var_iemgui_max_rng
5129 set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
5130 global $var_iemgui_lin0_log1
5131
5132 if {[eval concat $$var_iemgui_lin0_log1] == 1} {
5133 if {[eval concat $$var_iemgui_max_rng] == 0.0 && [eval concat $$var_iemgui_min_rng] == 0.0} {
5134 set $var_iemgui_max_rng 1.0
5135 $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
5136 }
5137 if {[eval concat $$var_iemgui_max_rng] > 0} {
5138 if {[eval concat $$var_iemgui_min_rng] <= 0} {
5139 set $var_iemgui_min_rng [expr [eval concat $$var_iemgui_max_rng] * 0.01]
5140 $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
5141 }
5142 } else {
5143 if {[eval concat $$var_iemgui_min_rng] > 0} {
5144 set $var_iemgui_max_rng [expr [eval concat $$var_iemgui_min_rng] * 0.01]
5145 $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
5146 }
5147 }
5148 }
5149}
5150
5151proc iemgui_clip_fontsize {id} {
5152 set vid [string trimleft $id .]
5153
5154 set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
5155 global $var_iemgui_gn_fs
5156
5157 global iemgui_define_min_fontsize
5158
5159 if {[eval concat $$var_iemgui_gn_fs] < $iemgui_define_min_fontsize} {
5160 set $var_iemgui_gn_fs $iemgui_define_min_fontsize
5161 $id.gnfs.fs_ent configure -textvariable $var_iemgui_gn_fs
5162 }
5163}
5164
5165proc iemgui_set_col_example {id} {
5166 set vid [string trimleft $id .]
5167
5168 set var_iemgui_bcol [concat iemgui_bcol_$vid]
5169 global $var_iemgui_bcol
5170 set var_iemgui_fcol [concat iemgui_fcol_$vid]
5171 global $var_iemgui_fcol
5172 set var_iemgui_lcol [concat iemgui_lcol_$vid]
5173 global $var_iemgui_lcol
5174
5175 $id.col_example_choose.lb_bk configure \
5176 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5177 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5178 -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
5179 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]]
5180
5181 if { [eval concat $$var_iemgui_fcol] >= 0 } {
5182 $id.col_example_choose.fr_bk configure \
5183 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5184 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5185 -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
5186 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]]
5187 } else {
5188 $id.col_example_choose.fr_bk configure \
5189 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5190 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5191 -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5192 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]]}
5193}
5194
5195proc iemgui_preset_col {id presetcol} {
5196 set vid [string trimleft $id .]
5197
5198 set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
5199 global $var_iemgui_l2_f1_b0
5200 set var_iemgui_bcol [concat iemgui_bcol_$vid]
5201 global $var_iemgui_bcol
5202 set var_iemgui_fcol [concat iemgui_fcol_$vid]
5203 global $var_iemgui_fcol
5204 set var_iemgui_lcol [concat iemgui_lcol_$vid]
5205 global $var_iemgui_lcol
5206
5207 if { [eval concat $$var_iemgui_l2_f1_b0] == 0 } { set $var_iemgui_bcol $presetcol }
5208 if { [eval concat $$var_iemgui_l2_f1_b0] == 1 } { set $var_iemgui_fcol $presetcol }
5209 if { [eval concat $$var_iemgui_l2_f1_b0] == 2 } { set $var_iemgui_lcol $presetcol }
5210 iemgui_set_col_example $id
5211}
5212
5213proc iemgui_choose_col_bkfrlb {id} {
5214 set vid [string trimleft $id .]
5215
5216 set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
5217 global $var_iemgui_l2_f1_b0
5218 set var_iemgui_bcol [concat iemgui_bcol_$vid]
5219 global $var_iemgui_bcol
5220 set var_iemgui_fcol [concat iemgui_fcol_$vid]
5221 global $var_iemgui_fcol
5222 set var_iemgui_lcol [concat iemgui_lcol_$vid]
5223 global $var_iemgui_lcol
5224
5225 if {[eval concat $$var_iemgui_l2_f1_b0] == 0} {
5226 set $var_iemgui_bcol [expr [eval concat $$var_iemgui_bcol] & 0xFCFCFC]
5227 set helpstring [tk_chooseColor -title "Background-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_bcol]]]
5228 if { $helpstring != "" } {
5229 set $var_iemgui_bcol [string replace $helpstring 0 0 "0x"]
5230 set $var_iemgui_bcol [expr [eval concat $$var_iemgui_bcol] & 0xFCFCFC] }
5231 }
5232 if {[eval concat $$var_iemgui_l2_f1_b0] == 1} {
5233 set $var_iemgui_fcol [expr [eval concat $$var_iemgui_fcol] & 0xFCFCFC]
5234 set helpstring [tk_chooseColor -title "Front-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_fcol]]]
5235 if { $helpstring != "" } {
5236 set $var_iemgui_fcol [string replace $helpstring 0 0 "0x"]
5237 set $var_iemgui_fcol [expr [eval concat $$var_iemgui_fcol] & 0xFCFCFC] }
5238 }
5239 if {[eval concat $$var_iemgui_l2_f1_b0] == 2} {
5240 set $var_iemgui_lcol [expr [eval concat $$var_iemgui_lcol] & 0xFCFCFC]
5241 set helpstring [tk_chooseColor -title "Label-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_lcol]]]
5242 if { $helpstring != "" } {
5243 set $var_iemgui_lcol [string replace $helpstring 0 0 "0x"]
5244 set $var_iemgui_lcol [expr [eval concat $$var_iemgui_lcol] & 0xFCFCFC] }
5245 }
5246 iemgui_set_col_example $id
5247}
5248
5249proc iemgui_lilo {id} {
5250 set vid [string trimleft $id .]
5251
5252 set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
5253 global $var_iemgui_lin0_log1
5254 set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
5255 global $var_iemgui_lilo0
5256 set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
5257 global $var_iemgui_lilo1
5258
5259 iemgui_sched_rng $id
5260
5261 if {[eval concat $$var_iemgui_lin0_log1] == 0} {
5262 set $var_iemgui_lin0_log1 1
5263 $id.para.lilo configure -text [eval concat $$var_iemgui_lilo1]
5264 iemgui_verify_rng $id
5265 iemgui_sched_rng $id
5266 } else {
5267 set $var_iemgui_lin0_log1 0
5268 $id.para.lilo configure -text [eval concat $$var_iemgui_lilo0]
5269 }
5270}
5271
5272proc iemgui_toggle_font {id} {
5273 set vid [string trimleft $id .]
5274
5275 set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
5276 global $var_iemgui_gn_f
5277
5278 set $var_iemgui_gn_f [expr [eval concat $$var_iemgui_gn_f] + 1]
5279 if {[eval concat $$var_iemgui_gn_f] > 2} {set $var_iemgui_gn_f 0}
5280 if {[eval concat $$var_iemgui_gn_f] == 0} {$id.gnfs.fb configure -text "courier" -font {courier 10 bold}}
5281 if {[eval concat $$var_iemgui_gn_f] == 1} {$id.gnfs.fb configure -text "helvetica" -font {helvetica 10 bold}}
5282 if {[eval concat $$var_iemgui_gn_f] == 2} {$id.gnfs.fb configure -text "times" -font {times 10 bold}}
5283}
5284
5285proc iemgui_lb {id} {
5286 set vid [string trimleft $id .]
5287
5288 set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
5289 global $var_iemgui_loadbang
5290
5291 if {[eval concat $$var_iemgui_loadbang] == 0} {
5292 set $var_iemgui_loadbang 1
5293 $id.para.lb configure -text "init"
5294 } else {
5295 set $var_iemgui_loadbang 0
5296 $id.para.lb configure -text "no init"
5297 }
5298}
5299
5300proc iemgui_stdy_jmp {id} {
5301 set vid [string trimleft $id .]
5302
5303 set var_iemgui_steady [concat iemgui_steady_$vid]
5304 global $var_iemgui_steady
5305
5306 if {[eval concat $$var_iemgui_steady]} {
5307 set $var_iemgui_steady 0
5308 $id.para.stdy_jmp configure -text "jump on click"
5309 } else {
5310 set $var_iemgui_steady 1
5311 $id.para.stdy_jmp configure -text "steady on click"
5312 }
5313}
5314
5315proc iemgui_apply {id} {
5316 set vid [string trimleft $id .]
5317
5318 set var_iemgui_wdt [concat iemgui_wdt_$vid]
5319 global $var_iemgui_wdt
5320 set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
5321 global $var_iemgui_min_wdt
5322 set var_iemgui_hgt [concat iemgui_hgt_$vid]
5323 global $var_iemgui_hgt
5324 set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
5325 global $var_iemgui_min_hgt
5326 set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
5327 global $var_iemgui_min_rng
5328 set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
5329 global $var_iemgui_max_rng
5330 set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
5331 global $var_iemgui_lin0_log1
5332 set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
5333 global $var_iemgui_lilo0
5334 set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
5335 global $var_iemgui_lilo1
5336 set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
5337 global $var_iemgui_loadbang
5338 set var_iemgui_num [concat iemgui_num_$vid]
5339 global $var_iemgui_num
5340 set var_iemgui_steady [concat iemgui_steady_$vid]
5341 global $var_iemgui_steady
5342 set var_iemgui_snd [concat iemgui_snd_$vid]
5343 global $var_iemgui_snd
5344 set var_iemgui_rcv [concat iemgui_rcv_$vid]
5345 global $var_iemgui_rcv
5346 set var_iemgui_gui_nam [concat iemgui_gui_nam_$vid]
5347 global $var_iemgui_gui_nam
5348 set var_iemgui_gn_dx [concat iemgui_gn_dx_$vid]
5349 global $var_iemgui_gn_dx
5350 set var_iemgui_gn_dy [concat iemgui_gn_dy_$vid]
5351 global $var_iemgui_gn_dy
5352 set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
5353 global $var_iemgui_gn_f
5354 set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
5355 global $var_iemgui_gn_fs
5356 set var_iemgui_bcol [concat iemgui_bcol_$vid]
5357 global $var_iemgui_bcol
5358 set var_iemgui_fcol [concat iemgui_fcol_$vid]
5359 global $var_iemgui_fcol
5360 set var_iemgui_lcol [concat iemgui_lcol_$vid]
5361 global $var_iemgui_lcol
5362
5363 iemgui_clip_dim $id
5364 iemgui_clip_num $id
5365 iemgui_sched_rng $id
5366 iemgui_verify_rng $id
5367 iemgui_sched_rng $id
5368 iemgui_clip_fontsize $id
5369
5370 if {[eval concat $$var_iemgui_snd] == ""} {set hhhsnd "empty"} else {set hhhsnd [eval concat $$var_iemgui_snd]}
5371 if {[eval concat $$var_iemgui_rcv] == ""} {set hhhrcv "empty"} else {set hhhrcv [eval concat $$var_iemgui_rcv]}
5372 if {[eval concat $$var_iemgui_gui_nam] == ""} {set hhhgui_nam "empty"
5373 } else {
5374 set hhhgui_nam [eval concat $$var_iemgui_gui_nam]}
5375
5376 if {[string index $hhhsnd 0] == "$"} {
5377 set hhhsnd [string replace $hhhsnd 0 0 #] }
5378 if {[string index $hhhrcv 0] == "$"} {
5379 set hhhrcv [string replace $hhhrcv 0 0 #] }
5380 if {[string index $hhhgui_nam 0] == "$"} {
5381 set hhhgui_nam [string replace $hhhgui_nam 0 0 #] }
5382
5383 set hhhsnd [string map {" " _} $hhhsnd]
5384 set hhhrcv [string map {" " _} $hhhrcv]
5385 set hhhgui_nam [string map {" " _} $hhhgui_nam]
5386
5387 pd [concat $id dialog \
5388 [eval concat $$var_iemgui_wdt] \
5389 [eval concat $$var_iemgui_hgt] \
5390 [eval concat $$var_iemgui_min_rng] \
5391 [eval concat $$var_iemgui_max_rng] \
5392 [eval concat $$var_iemgui_lin0_log1] \
5393 [eval concat $$var_iemgui_loadbang] \
5394 [eval concat $$var_iemgui_num] \
5395 $hhhsnd \
5396 $hhhrcv \
5397 $hhhgui_nam \
5398 [eval concat $$var_iemgui_gn_dx] \
5399 [eval concat $$var_iemgui_gn_dy] \
5400 [eval concat $$var_iemgui_gn_f] \
5401 [eval concat $$var_iemgui_gn_fs] \
5402 [eval concat $$var_iemgui_bcol] \
5403 [eval concat $$var_iemgui_fcol] \
5404 [eval concat $$var_iemgui_lcol] \
5405 [eval concat $$var_iemgui_steady] \
5406 \;]
5407}
5408
5409proc iemgui_cancel {id} {pd [concat $id cancel \;]}
5410
5411proc iemgui_ok {id} {
5412 iemgui_apply $id
5413 iemgui_cancel $id
5414}
5415
5416proc pdtk_iemgui_dialog {id mainheader \
5417 dim_header wdt min_wdt wdt_label hgt min_hgt hgt_label \
5418 rng_header min_rng min_rng_label max_rng max_rng_label rng_sched \
5419 lin0_log1 lilo0_label lilo1_label loadbang steady num_label num \
5420 snd rcv \
5421 gui_name \
5422 gn_dx gn_dy \
5423 gn_f gn_fs \
5424 bcol fcol lcol} {
5425
5426 set vid [string trimleft $id .]
5427
5428 set var_iemgui_wdt [concat iemgui_wdt_$vid]
5429 global $var_iemgui_wdt
5430 set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
5431 global $var_iemgui_min_wdt
5432 set var_iemgui_hgt [concat iemgui_hgt_$vid]
5433 global $var_iemgui_hgt
5434 set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
5435 global $var_iemgui_min_hgt
5436 set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
5437 global $var_iemgui_min_rng
5438 set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
5439 global $var_iemgui_max_rng
5440 set var_iemgui_rng_sch [concat iemgui_rng_sch_$vid]
5441 global $var_iemgui_rng_sch
5442 set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
5443 global $var_iemgui_lin0_log1
5444 set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
5445 global $var_iemgui_lilo0
5446 set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
5447 global $var_iemgui_lilo1
5448 set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
5449 global $var_iemgui_loadbang
5450 set var_iemgui_num [concat iemgui_num_$vid]
5451 global $var_iemgui_num
5452 set var_iemgui_steady [concat iemgui_steady_$vid]
5453 global $var_iemgui_steady
5454 set var_iemgui_snd [concat iemgui_snd_$vid]
5455 global $var_iemgui_snd
5456 set var_iemgui_rcv [concat iemgui_rcv_$vid]
5457 global $var_iemgui_rcv
5458 set var_iemgui_gui_nam [concat iemgui_gui_nam_$vid]
5459 global $var_iemgui_gui_nam
5460 set var_iemgui_gn_dx [concat iemgui_gn_dx_$vid]
5461 global $var_iemgui_gn_dx
5462 set var_iemgui_gn_dy [concat iemgui_gn_dy_$vid]
5463 global $var_iemgui_gn_dy
5464 set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
5465 global $var_iemgui_gn_f
5466 set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
5467 global $var_iemgui_gn_fs
5468 set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
5469 global $var_iemgui_l2_f1_b0
5470 set var_iemgui_bcol [concat iemgui_bcol_$vid]
5471 global $var_iemgui_bcol
5472 set var_iemgui_fcol [concat iemgui_fcol_$vid]
5473 global $var_iemgui_fcol
5474 set var_iemgui_lcol [concat iemgui_lcol_$vid]
5475 global $var_iemgui_lcol
5476
5477 set $var_iemgui_wdt $wdt
5478 set $var_iemgui_min_wdt $min_wdt
5479 set $var_iemgui_hgt $hgt
5480 set $var_iemgui_min_hgt $min_hgt
5481 set $var_iemgui_min_rng $min_rng
5482 set $var_iemgui_max_rng $max_rng
5483 set $var_iemgui_rng_sch $rng_sched
5484 set $var_iemgui_lin0_log1 $lin0_log1
5485 set $var_iemgui_lilo0 $lilo0_label
5486 set $var_iemgui_lilo1 $lilo1_label
5487 set $var_iemgui_loadbang $loadbang
5488 set $var_iemgui_num $num
5489 set $var_iemgui_steady $steady
5490 if {$snd == "empty"} {set $var_iemgui_snd [format ""]
5491 } else {set $var_iemgui_snd [format "%s" $snd]}
5492 if {$rcv == "empty"} {set $var_iemgui_rcv [format ""]
5493 } else {set $var_iemgui_rcv [format "%s" $rcv]}
5494 if {$gui_name == "empty"} {set $var_iemgui_gui_nam [format ""]
5495 } else {set $var_iemgui_gui_nam [format "%s" $gui_name]}
5496
5497 if {[string index [eval concat $$var_iemgui_snd] 0] == "#"} {
5498 set $var_iemgui_snd [string replace [eval concat $$var_iemgui_snd] 0 0 $] }
5499 if {[string index [eval concat $$var_iemgui_rcv] 0] == "#"} {
5500 set $var_iemgui_rcv [string replace [eval concat $$var_iemgui_rcv] 0 0 $] }
5501 if {[string index [eval concat $$var_iemgui_gui_nam] 0] == "#"} {
5502 set $var_iemgui_gui_nam [string replace [eval concat $$var_iemgui_gui_nam] 0 0 $] }
5503 set $var_iemgui_gn_dx $gn_dx
5504 set $var_iemgui_gn_dy $gn_dy
5505 set $var_iemgui_gn_f $gn_f
5506 set $var_iemgui_gn_fs $gn_fs
5507
5508 set $var_iemgui_bcol $bcol
5509 set $var_iemgui_fcol $fcol
5510 set $var_iemgui_lcol $lcol
5511
5512 set $var_iemgui_l2_f1_b0 0
5513
5514 toplevel $id
5515 wm title $id [format "%s-PROPERTIES" $mainheader]
5516 wm protocol $id WM_DELETE_WINDOW [concat iemgui_cancel $id]
5517
5518 frame $id.dim
5519 pack $id.dim -side top
5520 label $id.dim.head -text $dim_header
5521 label $id.dim.w_lab -text $wdt_label -width 6
5522 entry $id.dim.w_ent -textvariable $var_iemgui_wdt -width 5
5523 label $id.dim.dummy1 -text " " -width 10
5524 label $id.dim.h_lab -text $hgt_label -width 6
5525 entry $id.dim.h_ent -textvariable $var_iemgui_hgt -width 5
5526 pack $id.dim.head -side top
5527 pack $id.dim.w_lab $id.dim.w_ent $id.dim.dummy1 -side left
5528 if { $hgt_label != "empty" } {
5529 pack $id.dim.h_lab $id.dim.h_ent -side left}
5530
5531 frame $id.rng
5532 pack $id.rng -side top
5533 label $id.rng.head -text $rng_header
5534 label $id.rng.min_lab -text $min_rng_label -width 6
5535 entry $id.rng.min_ent -textvariable $var_iemgui_min_rng -width 9
5536 label $id.rng.dummy1 -text " " -width 1
5537 label $id.rng.max_lab -text $max_rng_label -width 8
5538 entry $id.rng.max_ent -textvariable $var_iemgui_max_rng -width 9
5539 if { $rng_header != "empty" } {
5540 pack $id.rng.head -side top
5541 if { $min_rng_label != "empty" } {
5542 pack $id.rng.min_lab $id.rng.min_ent -side left}
5543 if { $max_rng_label != "empty" } {
5544 pack $id.rng.dummy1 \
5545 $id.rng.max_lab $id.rng.max_ent -side left} }
5546
5547 if { [eval concat $$var_iemgui_lin0_log1] >= 0 || [eval concat $$var_iemgui_loadbang] >= 0 || [eval concat $$var_iemgui_num] > 0 || [eval concat $$var_iemgui_steady] >= 0 } {
5548 label $id.space1 -text "---------------------------------"
5549 pack $id.space1 -side top }
5550
5551 frame $id.para
5552 pack $id.para -side top
5553 label $id.para.dummy2 -text "" -width 1
5554 label $id.para.dummy3 -text "" -width 1
5555 if {[eval concat $$var_iemgui_lin0_log1] == 0} {
5556 button $id.para.lilo -text [eval concat $$var_iemgui_lilo0] -width 5 -command "iemgui_lilo $id" }
5557 if {[eval concat $$var_iemgui_lin0_log1] == 1} {
5558 button $id.para.lilo -text [eval concat $$var_iemgui_lilo1] -width 5 -command "iemgui_lilo $id" }
5559 if {[eval concat $$var_iemgui_loadbang] == 0} {
5560 button $id.para.lb -text "no init" -width 5 -command "iemgui_lb $id" }
5561 if {[eval concat $$var_iemgui_loadbang] == 1} {
5562 button $id.para.lb -text "init" -width 5 -command "iemgui_lb $id" }
5563 label $id.para.num_lab -text $num_label -width 9
5564 entry $id.para.num_ent -textvariable $var_iemgui_num -width 4
5565 if {[eval concat $$var_iemgui_steady] == 0} {
5566 button $id.para.stdy_jmp -text "jump on click" -width 11 -command "iemgui_stdy_jmp $id" }
5567 if {[eval concat $$var_iemgui_steady] == 1} {
5568 button $id.para.stdy_jmp -text "steady on click" -width 11 -command "iemgui_stdy_jmp $id" }
5569 if {[eval concat $$var_iemgui_lin0_log1] >= 0} {
5570 pack $id.para.lilo -side left -expand 1}
5571 if {[eval concat $$var_iemgui_loadbang] >= 0} {
5572 pack $id.para.dummy2 $id.para.lb -side left -expand 1}
5573 if {[eval concat $$var_iemgui_num] > 0} {
5574 pack $id.para.dummy3 $id.para.num_lab $id.para.num_ent -side left -expand 1}
5575 if {[eval concat $$var_iemgui_steady] >= 0} {
5576 pack $id.para.dummy3 $id.para.stdy_jmp -side left -expand 1}
5577 if { $snd != "nosndno" || $rcv != "norcvno" } {
5578 label $id.space2 -text "---------------------------------"
5579 pack $id.space2 -side top }
5580
5581 frame $id.snd
5582 pack $id.snd -side top
5583 label $id.snd.dummy1 -text "" -width 2
5584 label $id.snd.lab -text "send-symbol:" -width 12
5585 entry $id.snd.ent -textvariable $var_iemgui_snd -width 20
5586 if { $snd != "nosndno" } {
5587 pack $id.snd.dummy1 $id.snd.lab $id.snd.ent -side left}
5588
5589 frame $id.rcv
5590 pack $id.rcv -side top
5591 label $id.rcv.lab -text "receive-symbol:" -width 15
5592 entry $id.rcv.ent -textvariable $var_iemgui_rcv -width 20
5593 if { $rcv != "norcvno" } {
5594 pack $id.rcv.lab $id.rcv.ent -side left}
5595
5596 frame $id.gnam
5597 pack $id.gnam -side top
5598 label $id.gnam.head -text "--------------label:---------------"
5599 label $id.gnam.dummy1 -text "" -width 1
5600 label $id.gnam.lab -text "name:" -width 6
5601 entry $id.gnam.ent -textvariable $var_iemgui_gui_nam -width 29
5602 label $id.gnam.dummy2 -text "" -width 1
5603 pack $id.gnam.head -side top
5604 pack $id.gnam.dummy1 $id.gnam.lab $id.gnam.ent $id.gnam.dummy2 -side left
5605
5606 frame $id.gnxy
5607 pack $id.gnxy -side top
5608 label $id.gnxy.x_lab -text "x_off:" -width 6
5609 entry $id.gnxy.x_ent -textvariable $var_iemgui_gn_dx -width 5
5610 label $id.gnxy.dummy1 -text " " -width 10
5611 label $id.gnxy.y_lab -text "y_off:" -width 6
5612 entry $id.gnxy.y_ent -textvariable $var_iemgui_gn_dy -width 5
5613 pack $id.gnxy.x_lab $id.gnxy.x_ent $id.gnxy.dummy1 \
5614 $id.gnxy.y_lab $id.gnxy.y_ent -side left
5615
5616 frame $id.gnfs
5617 pack $id.gnfs -side top
5618 label $id.gnfs.f_lab -text "font:" -width 6
5619 if {[eval concat $$var_iemgui_gn_f] == 0} {
5620 button $id.gnfs.fb -text "courier" -font {courier 10 bold} -width 7 -command "iemgui_toggle_font $id" }
5621 if {[eval concat $$var_iemgui_gn_f] == 1} {
5622 button $id.gnfs.fb -text "helvetica" -font {helvetica 10 bold} -width 7 -command "iemgui_toggle_font $id" }
5623 if {[eval concat $$var_iemgui_gn_f] == 2} {
5624 button $id.gnfs.fb -text "times" -font {times 10 bold} -width 7 -command "iemgui_toggle_font $id" }
5625 label $id.gnfs.dummy1 -text "" -width 1
5626 label $id.gnfs.fs_lab -text "fontsize:" -width 8
5627 entry $id.gnfs.fs_ent -textvariable $var_iemgui_gn_fs -width 5
5628 pack $id.gnfs.f_lab $id.gnfs.fb $id.gnfs.dummy1 \
5629 $id.gnfs.fs_lab $id.gnfs.fs_ent -side left
5630
5631 label $id.col_head -text "--------------colors:--------------"
5632 pack $id.col_head -side top
5633
5634 frame $id.col_select
5635 pack $id.col_select -side top
5636 radiobutton $id.col_select.radio0 -value 0 -variable $var_iemgui_l2_f1_b0 \
5637 -text "backgd" -width 5
5638 radiobutton $id.col_select.radio1 -value 1 -variable $var_iemgui_l2_f1_b0 \
5639 -text "front" -width 5
5640 radiobutton $id.col_select.radio2 -value 2 -variable $var_iemgui_l2_f1_b0 \
5641 -text "label" -width 5
5642 if { [eval concat $$var_iemgui_fcol] >= 0 } {
5643 pack $id.col_select.radio0 $id.col_select.radio1 $id.col_select.radio2 -side left
5644 } else {pack $id.col_select.radio0 $id.col_select.radio2 -side left}
5645
5646 frame $id.col_example_choose
5647 pack $id.col_example_choose -side top
5648 button $id.col_example_choose.but -text "compose color" -width 10 \
5649 -command "iemgui_choose_col_bkfrlb $id"
5650 label $id.col_example_choose.dummy1 -text "" -width 1
5651 if { [eval concat $$var_iemgui_fcol] >= 0 } {
5652 button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
5653 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5654 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5655 -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
5656 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] -pady 2
5657 } else {
5658 button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
5659 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5660 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5661 -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5662 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] -pady 2}
5663 button $id.col_example_choose.lb_bk -text "testlabel" -width 7 \
5664 -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5665 -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
5666 -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
5667 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] -pady 2
5668
5669 pack $id.col_example_choose.but $id.col_example_choose.dummy1 \
5670 $id.col_example_choose.fr_bk $id.col_example_choose.lb_bk -side left
5671
5672 label $id.space3 -text "------or click color preset:-------"
5673 pack $id.space3 -side top
5674
5675 frame $id.bcol
5676 pack $id.bcol -side top
5677 foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 16579836 14737632 12369084 \
5678 16572640 16572608 16579784 14220504 14220540 14476540 16308476 } {
5679 button $id.bcol.c$i -background [format "#%6.6x" $hexcol] \
5680 -activebackground [format "#%6.6x" $hexcol] \
5681 -font {courier 2 normal} -padx 7 -pady 6 \
5682 -command [format "iemgui_preset_col %s %d" $id $hexcol] }
5683 pack $id.bcol.c0 $id.bcol.c1 $id.bcol.c2 $id.bcol.c3 $id.bcol.c4 \
5684 $id.bcol.c5 $id.bcol.c6 $id.bcol.c7 $id.bcol.c8 $id.bcol.c9 -side left
5685
5686 frame $id.fcol
5687 pack $id.fcol -side top
5688 foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 10526880 8158332 6316128 \
5689 16525352 16559172 15263784 1370132 2684148 3952892 16003312 } {
5690 button $id.fcol.c$i -background [format "#%6.6x" $hexcol] \
5691 -activebackground [format "#%6.6x" $hexcol] \
5692 -font {courier 2 normal} -padx 7 -pady 6 \
5693 -command [format "iemgui_preset_col %s %d" $id $hexcol] }
5694 pack $id.fcol.c0 $id.fcol.c1 $id.fcol.c2 $id.fcol.c3 $id.fcol.c4 \
5695 $id.fcol.c5 $id.fcol.c6 $id.fcol.c7 $id.fcol.c8 $id.fcol.c9 -side left
5696
5697 frame $id.lcol
5698 pack $id.lcol -side top
5699 foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 4210752 2105376 0 \
5700 9177096 5779456 7874580 2641940 17488 5256 5767248 } {
5701 button $id.lcol.c$i -background [format "#%6.6x" $hexcol] \
5702 -activebackground [format "#%6.6x" $hexcol] \
5703 -font {courier 2 normal} -padx 7 -pady 6 \
5704 -command [format "iemgui_preset_col %s %d" $id $hexcol] }
5705 pack $id.lcol.c0 $id.lcol.c1 $id.lcol.c2 $id.lcol.c3 $id.lcol.c4 \
5706 $id.lcol.c5 $id.lcol.c6 $id.lcol.c7 $id.lcol.c8 $id.lcol.c9 -side left
5707
5708
5709 label $id.space4 -text "---------------------------------"
5710 pack $id.space4 -side top
5711
5712 frame $id.cao
5713 pack $id.cao -side top
5714 button $id.cao.cancel -text {Cancel} -width 6 \
5715 -command "iemgui_cancel $id"
5716 label $id.cao.dummy1 -text "" -width 3
5717 button $id.cao.apply -text {Apply} -width 6 \
5718 -command "iemgui_apply $id"
5719 label $id.cao.dummy2 -text "" -width 3
5720 button $id.cao.ok -text {OK} -width 6 \
5721 -command "iemgui_ok $id"
5722 pack $id.cao.cancel $id.cao.dummy1 \
5723 $id.cao.apply $id.cao.dummy2 \
5724 $id.cao.ok -side left
5725
5726 label $id.space5 -text ""
5727 pack $id.space5 -side top
5728
5729 if {[info tclversion] < 8.4} {
5730 bind $id <Key-Tab> {tkTabToWindow [tk_focusNext %W]}
5731 bind $id <<PrevWindow>> {tkTabToWindow [tk_focusPrev %W]}
5732 } else {
5733 bind $id <Key-Tab> {tk::TabToWindow [tk_focusNext %W]}
5734 bind $id <<PrevWindow>> {tk::TabToWindow [tk_focusPrev %W]}
5735 }
5736
5737 bind $id.dim.w_ent <KeyPress-Return> [concat iemgui_ok $id]
5738 bind $id.dim.h_ent <KeyPress-Return> [concat iemgui_ok $id]
5739 bind $id.rng.min_ent <KeyPress-Return> [concat iemgui_ok $id]
5740 bind $id.rng.max_ent <KeyPress-Return> [concat iemgui_ok $id]
5741 bind $id.para.num_ent <KeyPress-Return> [concat iemgui_ok $id]
5742 bind $id.snd.ent <KeyPress-Return> [concat iemgui_ok $id]
5743 bind $id.rcv.ent <KeyPress-Return> [concat iemgui_ok $id]
5744 bind $id.gnam.ent <KeyPress-Return> [concat iemgui_ok $id]
5745 bind $id.gnxy.x_ent <KeyPress-Return> [concat iemgui_ok $id]
5746 bind $id.gnxy.y_ent <KeyPress-Return> [concat iemgui_ok $id]
5747 bind $id.gnfs.fs_ent <KeyPress-Return> [concat iemgui_ok $id]
5748 bind $id.cao.ok <KeyPress-Return> [concat iemgui_ok $id]
5749
5750 $id.dim.w_ent select from 0
5751 $id.dim.w_ent select adjust end
5752 focus $id.dim.w_ent
5753}
5754# end of change "iemlib"
5755
5756############ pdtk_array_dialog -- dialog window for arrays #########
5757proc array_apply {id} {
5758# strip "." from the TK id to make a variable name suffix
5759 set vid [string trimleft $id .]
5760# for each variable, make a local variable to hold its name...
5761 set var_array_name [concat array_name_$vid]
5762 global $var_array_name
5763 set var_array_n [concat array_n_$vid]
5764 global $var_array_n
5765 set var_array_saveit [concat array_saveit_$vid]
5766 global $var_array_saveit
5767 set var_array_otherflag [concat array_otherflag_$vid]
5768 global $var_array_otherflag
5769 set mofo [eval concat $$var_array_name]
5770 if {[string index $mofo 0] == "$"} {
5771 set mofo [string replace $mofo 0 0 #] }
5772
5773 pd [concat $id arraydialog $mofo \
5774 [eval concat $$var_array_n] \
5775 [eval concat $$var_array_saveit] \
5776 [eval concat $$var_array_otherflag] \
5777 \;]
5778}
5779
5780proc array_cancel {id} {
5781 set cmd [concat $id cancel \;]
5782 pd $cmd
5783}
5784
5785proc array_ok {id} {
5786 array_apply $id
5787 array_cancel $id
5788}
5789
5790proc pdtk_array_dialog {id name n saveit newone} {
5791 set vid [string trimleft $id .]
5792
5793 set var_array_name [concat array_name_$vid]
5794 global $var_array_name
5795 set var_array_n [concat array_n_$vid]
5796 global $var_array_n
5797 set var_array_saveit [concat array_saveit_$vid]
5798 global $var_array_saveit
5799 set var_array_otherflag [concat array_otherflag_$vid]
5800 global $var_array_otherflag
5801
5802 set $var_array_name $name
5803 set $var_array_n $n
5804 set $var_array_saveit $saveit
5805 set $var_array_otherflag 0
5806
5807 toplevel $id
5808 wm title $id {array}
5809 wm protocol $id WM_DELETE_WINDOW [concat array_cancel $id]
5810
5811 frame $id.name
5812 pack $id.name -side top
5813 label $id.name.label -text "name"
5814 entry $id.name.entry -textvariable $var_array_name
5815 pack $id.name.label $id.name.entry -side left
5816
5817 frame $id.n
5818 pack $id.n -side top
5819 label $id.n.label -text "size"
5820 entry $id.n.entry -textvariable $var_array_n
5821 pack $id.n.label $id.n.entry -side left
5822
5823 checkbutton $id.saveme -text {save contents} -variable $var_array_saveit \
5824 -anchor w
5825 pack $id.saveme -side top
5826
5827 if {$newone != 0} {
5828 frame $id.radio
5829 pack $id.radio -side top
5830 radiobutton $id.radio.radio0 -value 0 \
5831 -variable $var_array_otherflag \
5832 -text "in new graph"
5833 radiobutton $id.radio.radio1 -value 1 \
5834 -variable $var_array_otherflag \
5835 -text "in last graph"
5836 pack $id.radio.radio0 -side top -anchor w
5837 pack $id.radio.radio1 -side top -anchor w
5838 } else {
5839 checkbutton $id.deleteme -text {delete me} \
5840 -variable $var_array_otherflag -anchor w
5841 pack $id.deleteme -side top
5842 }
5843 frame $id.buttonframe
5844 pack $id.buttonframe -side bottom -fill x -pady 2m
5845 button $id.buttonframe.cancel -text {Cancel}\
5846 -command "array_cancel $id"
5847 if {$newone == 0} {button $id.buttonframe.apply -text {Apply}\
5848 -command "array_apply $id"}
5849 button $id.buttonframe.ok -text {OK}\
5850 -command "array_ok $id"
5851 pack $id.buttonframe.cancel -side left -expand 1
5852 if {$newone == 0} {pack $id.buttonframe.apply -side left -expand 1}
5853 pack $id.buttonframe.ok -side left -expand 1
5854
5855 bind $id.name.entry <KeyPress-Return> [concat array_ok $id]
5856 bind $id.n.entry <KeyPress-Return> [concat array_ok $id]
5857 $id.name.entry select from 0
5858 $id.name.entry select adjust end
5859 focus $id.name.entry
5860}
5861
5862############ pdtk_canvas_dialog -- dialog window for canvass #########
5863proc canvas_apply {id} {
5864# strip "." from the TK id to make a variable name suffix
5865 set vid [string trimleft $id .]
5866# for each variable, make a local variable to hold its name...
5867 set var_canvas_xscale [concat canvas_xscale_$vid]
5868 global $var_canvas_xscale
5869 set var_canvas_yscale [concat canvas_yscale_$vid]
5870 global $var_canvas_yscale
5871 set var_canvas_graphme [concat canvas_graphme_$vid]
5872 global $var_canvas_graphme
5873# set var_canvas_stretch [concat canvas_stretch_$vid]
5874# global $var_canvas_stretch
5875 pd [concat $id donecanvasdialog \
5876 [eval concat $$var_canvas_xscale] \
5877 [eval concat $$var_canvas_yscale] \
5878 [eval concat $$var_canvas_graphme] \
5879 \;]
5880}
5881
5882proc canvas_cancel {id} {
5883 set cmd [concat $id cancel \;]
5884 pd $cmd
5885}
5886
5887proc canvas_ok {id} {
5888 canvas_apply $id
5889 canvas_cancel $id
5890}
5891
5892proc pdtk_canvas_dialog {id xscale yscale graphme stretch} {
5893 set vid [string trimleft $id .]
5894
5895 set var_canvas_xscale [concat canvas_xscale_$vid]
5896 global $var_canvas_xscale
5897 set var_canvas_yscale [concat canvas_yscale_$vid]
5898 global $var_canvas_yscale
5899 set var_canvas_graphme [concat canvas_graphme_$vid]
5900 global $var_canvas_graphme
5901# set var_canvas_stretch [concat canvas_stretch_$vid]
5902# global $var_canvas_stretch
5903
5904 set $var_canvas_xscale $xscale
5905 set $var_canvas_yscale $yscale
5906 set $var_canvas_graphme $graphme
5907# set $var_canvas_stretch $stretch
5908
5909 toplevel $id
5910 wm title $id {canvas}
5911 wm protocol $id WM_DELETE_WINDOW [concat canvas_cancel $id]
5912
5913 frame $id.xscale
5914 pack $id.xscale -side top
5915 label $id.xscale.label -text "X units per pixel"
5916 entry $id.xscale.entry -textvariable $var_canvas_xscale -width 10
5917 pack $id.xscale.label $id.xscale.entry -side left
5918
5919 frame $id.yscale
5920 pack $id.yscale -side top
5921 label $id.yscale.label -text "Y units per pixel"
5922 entry $id.yscale.entry -textvariable $var_canvas_yscale -width 10
5923 pack $id.yscale.label $id.yscale.entry -side left
5924
5925 checkbutton $id.graphme -text {graph on parent} \
5926 -variable $var_canvas_graphme -anchor w
5927 pack $id.graphme -side top
5928
5929# checkbutton $id.stretch -text {stretch on resize} \
5930# -variable $var_canvas_stretch -anchor w
5931# pack $id.stretch -side top
5932
5933
5934 frame $id.buttonframe
5935 pack $id.buttonframe -side bottom -fill x -pady 2m
5936 button $id.buttonframe.cancel -text {Cancel}\
5937 -command "canvas_cancel $id"
5938 button $id.buttonframe.apply -text {Apply}\
5939 -command "canvas_apply $id"
5940 button $id.buttonframe.ok -text {OK}\
5941 -command "canvas_ok $id"
5942 pack $id.buttonframe.cancel -side left -expand 1
5943 pack $id.buttonframe.apply -side left -expand 1
5944 pack $id.buttonframe.ok -side left -expand 1
5945
5946 bind $id.xscale.entry <KeyPress-Return> [concat canvas_ok $id]
5947 bind $id.yscale.entry <KeyPress-Return> [concat canvas_ok $id]
5948 $id.xscale.entry select from 0
5949 $id.xscale.entry select adjust end
5950 focus $id.xscale.entry
5951}
5952
5953############ pdtk_data_dialog -- run a data dialog #########
5954proc dodata_send {name} {
5955# puts stderr [$name.text get 0.0 end]
5956
5957 for {set i 1} {[$name.text compare [concat $i.0 + 3 chars] < end]} \
5958 {incr i 1} {
5959# puts stderr [concat it's [$name.text get $i.0 [expr $i + 1].0]]
5960 set cmd [concat $name data [$name.text get $i.0 [expr $i + 1].0] \;]
5961# puts stderr $cmd
5962 pd $cmd
5963 }
5964 set cmd [concat $name end \;]
5965# puts stderr $cmd
5966 pd $cmd
5967}
5968
5969proc dodata_cancel {name} {
5970 set cmd [concat $name cancel \;]
5971# puts stderr $cmd
5972 pd $cmd
5973}
5974
5975proc dodata_ok {name} {
5976 dodata_send $name
5977 dodata_cancel $name
5978}
5979
5980proc pdtk_data_dialog {name stuff} {
5981
5982 toplevel $name
5983 wm title $name {Atom}
5984 wm protocol $name WM_DELETE_WINDOW [concat dodata_cancel $name]
5985
5986 frame $name.buttonframe
5987 pack $name.buttonframe -side bottom -fill x -pady 2m
5988 button $name.buttonframe.send -text {Send (Ctrl s)}\
5989 -command [concat dodata_send $name]
5990 button $name.buttonframe.ok -text {OK (Ctrl t)}\
5991 -command [concat dodata_ok $name]
5992 pack $name.buttonframe.send -side left -expand 1
5993 pack $name.buttonframe.ok -side left -expand 1
5994
5995 text $name.text -relief raised -bd 2 -height 40 -width 60 \
5996 -yscrollcommand "$name.scroll set" -font -*-courier-bold--normal--12-*
5997 scrollbar $name.scroll -command "$name.text yview"
5998 pack $name.scroll -side right -fill y
5999 pack $name.text -side left -fill both -expand 1
6000 $name.text insert end $stuff
6001 focus $name.text
6002 bind $name.text <Control-t> [concat dodata_ok $name]
6003 bind $name.text <Control-s> [concat dodata_send $name]
6004}
6005
6006############ check or uncheck the "edit" menu item ##############
6007#####################iemlib#######################
6008proc pdtk_canvas_editval {name value} {
6009 if { $value } {
6010 $name.m.edit entryconfigure "Edit mode" -indicatoron true
6011 } else {
6012 $name.m.edit entryconfigure "Edit mode" -indicatoron false
6013 }
6014}
6015#####################iemlib#######################
6016
6017############ pdtk_text_new -- create a new text object #2###########
6018proc pdtk_text_new {canvasname myname x y text font color} {
6019# if {$font < 13} {set fontname [format -*-courier-bold----%d-* $font]}
6020# if {$font >= 13} {set fontname [format -*-courier-----%d-* $font]}
6021 $canvasname create text $x $y \
6022 -font [format -*-courier-bold--normal--%d-* $font] \
6023 -tags $myname -text $text -fill $color -anchor nw
6024# pd [concat $myname size [$canvasname bbox $myname] \;]
6025}
6026
6027################ pdtk_text_set -- change the text ##################
6028proc pdtk_text_set {canvasname myname text} {
6029 $canvasname itemconfig $myname -text $text
6030# pd [concat $myname size [$canvasname bbox $myname] \;]
6031}
6032
6033############### event binding procedures for Pd window ################
6034
6035proc pdtk_pd_ctrlkey {name key shift} {
6036# puts stderr [concat key $key shift $shift]
6037# .dummy itemconfig goo -text [concat ---> control-key event $key];
6038 if {$key == "n" || $key == "N"} {menu_new}
6039 if {$key == "o" || $key == "O"} {menu_open}
6040 if {$key == "m" || $key == "M"} {menu_send}
6041 if {$key == "q" || $key == "Q"} {
6042 if {$shift == 1} {menu_really_quit} else {menu_quit}
6043 }
6044 if {$key == "slash"} {menu_audio 1}
6045 if {$key == "period"} {menu_audio 0}
6046}
6047
6048######### startup function. ##############
6049# Tell pd the current directory; this is used in case the command line
6050# asked pd to open something. Also, get character width and height for
6051# font sizes 8, 10, 12, 14, 16, and 24.
6052
6053proc pdtk_pd_startup {version apilist} {
6054 global pd_myversion pd_apilist
6055 set pd_myversion $version
6056 set pd_apilist $apilist
6057
6058 set width1 [font measure -*-courier-bold--normal--8-* x]
6059 set height1 [lindex [font metrics -*-courier-bold--normal--8-*] 5]
6060
6061 set width2 [font measure -*-courier-bold--normal--10-* x]
6062 set height2 [lindex [font metrics -*-courier-bold--normal--10-*] 5]
6063
6064 set width3 [font measure -*-courier-bold--normal--12-* x]
6065 set height3 [lindex [font metrics -*-courier-bold--normal--12-*] 5]
6066
6067 set width4 [font measure -*-courier-bold--normal--14-* x]
6068 set height4 [lindex [font metrics -*-courier-bold--normal--14-*] 5]
6069
6070 set width5 [font measure -*-courier-bold--normal--16-* x]
6071 set height5 [lindex [font metrics -*-courier-bold--normal--16-*] 5]
6072
6073 set width6 [font measure -*-courier-bold--normal--24-* x]
6074 set height6 [lindex [font metrics -*-courier-bold--normal--24-*] 5]
6075
6076 set width7 [font measure -*-courier-bold--normal--36-* x]
6077 set height7 [lindex [font metrics -*-courier-bold--normal--36-*] 5]
6078
6079 set tclpatch [info patchlevel]
6080 if {$tclpatch == "8.3.0" || \
6081 $tclpatch == "8.3.1" || \
6082 $tclpatch == "8.3.2" || \
6083 $tclpatch == "8.3.3" } {
6084 set oldtclversion 1
6085 } else {
6086 set oldtclversion 0
6087 }
6088 pd [concat pd init [pdtk_enquote [pwd]] \
6089 8 $width1 $height1 \
6090 10 $width2 $height2 \
6091 12 $width3 $height3 \
6092 14 $width4 $height4 \
6093 16 $width5 $height5 \
6094 24 $width6 $height6 \
6095 36 $width7 $height7 \
6096 $oldtclversion \;];
6097
6098 # add the audio and help menus to the Pd window. We delayed this
6099 # so that we'd know the value of "apilist".
6100 menu_addstd .mbar
6101
6102}
6103
6104##################### DSP ON/OFF, METERS, DIO ERROR ###################
6105proc pdtk_pd_dsp {value} {
6106 global ctrls_audio_on
6107 if {$value == "ON"} {set ctrls_audio_on 1} else {set ctrls_audio_on 0}
6108# puts stderr [concat its $ctrls_audio_on]
6109}
6110
6111proc pdtk_pd_meters {indb outdb inclip outclip} {
6112# puts stderr [concat meters $indb $outdb $inclip $outclip]
6113 global ctrls_inlevel ctrls_outlevel
6114 set ctrls_inlevel $indb
6115 if {$inclip == 1} {
6116 .controls.inout.in.clip configure -background red
6117 } else {
6118 .controls.inout.in.clip configure -background grey
6119 }
6120 set ctrls_outlevel $outdb
6121 if {$outclip == 1} {
6122 .controls.inout.out.clip configure -background red
6123 } else {
6124 .controls.inout.out.clip configure -background grey
6125 }
6126
6127}
6128
6129proc pdtk_pd_dio {red} {
6130# puts stderr [concat dio $red]
6131 if {$red == 1} {
6132 .controls.dio configure -background red -activebackground red
6133 } else {
6134 .controls.dio configure -background grey -activebackground lightgrey
6135 }
6136
6137}
6138
6139############# text editing from the "edit" menu ###################
6140set edit_number 1
6141
6142proc texteditor_send {name} {
6143 set topname [string trimright $name .text]
6144 for {set i 0} \
6145 {[$name compare [concat 0.0 + [expr $i + 1] chars] < end]} \
6146 {incr i 1} {
6147 set cha [$name get [concat 0.0 + $i chars]]
6148 scan $cha %c keynum
6149 pd [concat pd key 1 $keynum 0 \;]
6150 }
6151}
6152
6153proc texteditor_ok {name} {
6154 set topname [string trimright $name .text]
6155 texteditor_send $name
6156 destroy $topname
6157}
6158
6159
6160proc pdtk_pd_texteditor {stuff} {
6161 global edit_number
6162 set name [format ".text%d" $edit_number]
6163 set edit_number [expr $edit_number + 1]
6164
6165 toplevel $name
6166 wm title $name {TEXT}
6167
6168 frame $name.buttons
6169 pack $name.buttons -side bottom -fill x -pady 2m
6170 button $name.buttons.send -text {Send (Ctrl s)}\
6171 -command "texteditor_send $name.text"
6172 button $name.buttons.ok -text {OK (Ctrl t)}\
6173 -command "texteditor_ok $name.text"
6174 pack $name.buttons.send -side left -expand 1
6175 pack $name.buttons.ok -side left -expand 1
6176
6177 text $name.text -relief raised -bd 2 -height 12 -width 60 \
6178 -yscrollcommand "$name.scroll set" -font -*-courier-bold--normal--12-*
6179 scrollbar $name.scroll -command "$name.text yview"
6180 pack $name.scroll -side right -fill y
6181 pack $name.text -side left -fill both -expand 1
6182 $name.text insert end $stuff
6183 focus $name.text
6184 bind $name.text <Control-t> {texteditor_ok %W}
6185 bind $name.text <Control-s> {texteditor_send %W}
6186}
6187
6188############# open and save dialogs for objects in Pd ##########
6189
6190proc pdtk_openpanel {target} {
6191 global pd_opendir
6192 set filename [tk_getOpenFile \
6193 -initialdir $pd_opendir]
6194 if {$filename != ""} {
6195 set directory [string range $filename 0 \
6196 [expr [string last / $filename ] - 1]]
6197 set pd_opendir $directory
6198
6199 pd [concat $target symbol [pdtk_enquote $filename] \;]
6200 }
6201}
6202
6203proc pdtk_savepanel {target} {
6204 set filename [tk_getSaveFile]
6205 if {$filename != ""} {
6206 pd [concat $target symbol [pdtk_enquote $filename] \;]
6207 }
6208}
6209
6210########################### comport hack ########################
6211
6212set com1 0
6213set com2 0
6214set com3 0
6215set com4 0
6216
6217proc com1_open {} {
6218 global com1
6219 set com1 [open com1 w]
6220 .dummy itemconfig goo -text $com1
6221 fconfigure $com1 -buffering none
6222 fconfigure $com1 -mode 19200,e,8,2
6223}
6224
6225proc com1_send {str} {
6226 global com1
6227 puts -nonewline $com1 $str
6228}
6229
6230
6231############# start a polling process to watch the socket ##############
6232# this is needed for nt, and presumably for Mac as well.
6233# in UNIX this is handled by a tcl callback (set up in t_tkcmd.c)
6234
6235if {$pd_nt == 1} {
6236 proc polleofloop {} {
6237 pd_pollsocket
6238 after 20 polleofloop
6239 }
6240
6241 polleofloop
6242}
6243
6244####################### audio dialog ##################3
6245
6246proc audio_apply {id} {
6247 global audio_indev1 audio_indev2 audio_indev3 audio_indev4
6248 global audio_inchan1 audio_inchan2 audio_inchan3 audio_inchan4
6249 global audio_outdev1 audio_outdev2 audio_outdev3 audio_outdev4
6250 global audio_outchan1 audio_outchan2 audio_outchan3 audio_outchan4
6251 global audio_sr audio_advance
6252
6253 pd [concat pd audio-dialog \
6254 $audio_indev1 \
6255 $audio_indev2 \
6256 $audio_indev3 \
6257 $audio_indev4 \
6258 $audio_inchan1 \
6259 $audio_inchan2 \
6260 $audio_inchan3 \
6261 $audio_inchan4 \
6262 $audio_outdev1 \
6263 $audio_outdev2 \
6264 $audio_outdev3 \
6265 $audio_outdev4 \
6266 $audio_outchan1 \
6267 $audio_outchan2 \
6268 $audio_outchan3 \
6269 $audio_outchan4 \
6270 $audio_sr \
6271 $audio_advance \
6272 \;]
6273}
6274
6275proc audio_cancel {id} {
6276 pd [concat $id cancel \;]
6277}
6278
6279proc audio_ok {id} {
6280 audio_apply $id
6281 audio_cancel $id
6282}
6283
6284# callback from popup menu
6285proc audio_popup_action {buttonname varname devlist index} {
6286 global audio_indevlist audio_outdevlist $varname
6287 $buttonname configure -text [lindex $devlist $index]
6288# puts stderr [concat popup_action $buttonname $varname $index]
6289 set $varname $index
6290}
6291
6292# create a popup menu
6293proc audio_popup {name buttonname varname devlist} {
6294 if [winfo exists $name.popup] {destroy $name.popup}
6295 menu $name.popup -tearoff false
6296# puts stderr [concat $devlist ]
6297 for {set x 0} {$x<[llength $devlist]} {incr x} {
6298 $name.popup add command -label [lindex $devlist $x] \
6299 -command [list audio_popup_action \
6300 $buttonname $varname $devlist $x]
6301 }
6302 tk_popup $name.popup [winfo pointerx $name] [winfo pointery $name] 0
6303}
6304
6305# start a dialog window to select audio devices and settings. "multi"
6306# is 0 if only one device is allowed; 1 if one apiece may be specified for
6307# input and output; and 2 if we can select multiple devices. "longform"
6308# (which only makes sense if "multi" is 2) asks us to make controls for
6309# opening several devices; if not, we get an extra button to turn longform
6310# on and restart the dialog.
6311
6312proc pdtk_audio_dialog {id indevlist indev1 indev2 indev3 indev4 \
6313 inchan1 inchan2 inchan3 inchan4 \
6314 outdevlist outdev1 outdev2 outdev3 outdev4 \
6315 outchan1 outchan2 outchan3 outchan4 sr advance multi longform} {
6316 global audio_indev1 audio_indev2 audio_indev3 audio_indev4
6317 global audio_inchan1 audio_inchan2 audio_inchan3 audio_inchan4
6318 global audio_outdev1 audio_outdev2 audio_outdev3 audio_outdev4
6319 global audio_outchan1 audio_outchan2 audio_outchan3 audio_outchan4
6320 global audio_sr audio_advance
6321 global audio_indevlist audio_outdevlist
6322
6323 set audio_indev1 $indev1
6324 set audio_indev2 $indev2
6325 set audio_indev3 $indev3
6326 set audio_indev4 $indev4
6327 set audio_inchan1 $inchan1
6328 set audio_inchan2 $inchan2
6329 set audio_inchan3 $inchan3
6330 set audio_inchan4 $inchan4
6331 set audio_outdev1 $outdev1
6332 set audio_outdev2 $outdev2
6333 set audio_outdev3 $outdev3
6334 set audio_outdev4 $outdev4
6335 set audio_outchan1 $outchan1
6336 set audio_outchan2 $outchan2
6337 set audio_outchan3 $outchan3
6338 set audio_outchan4 $outchan4
6339 set audio_sr $sr
6340 set audio_advance $advance
6341 set audio_indevlist $indevlist
6342 set audio_outdevlist $outdevlist
6343
6344 toplevel $id
6345 wm title $id {audio}
6346 wm protocol $id WM_DELETE_WINDOW [concat audio_cancel $id]
6347
6348 frame $id.buttonframe
6349 pack $id.buttonframe -side bottom -fill x -pady 2m
6350 button $id.buttonframe.cancel -text {Cancel}\
6351 -command "audio_cancel $id"
6352 button $id.buttonframe.apply -text {Apply}\
6353 -command "audio_apply $id"
6354 button $id.buttonframe.ok -text {OK}\
6355 -command "audio_ok $id"
6356 pack $id.buttonframe.cancel -side left -expand 1
6357 pack $id.buttonframe.apply -side left -expand 1
6358 pack $id.buttonframe.ok -side left -expand 1
6359
6360 # sample rate and advance
6361 frame $id.srf
6362 pack $id.srf -side top
6363
6364 label $id.srf.l1 -text "sample rate:"
6365 entry $id.srf.x1 -textvariable audio_sr -width 7
6366 label $id.srf.l2 -text "delay (msec):"
6367 entry $id.srf.x2 -textvariable audio_advance -width 4
6368 pack $id.srf.l1 $id.srf.x1 $id.srf.l2 $id.srf.x2 -side left
6369
6370 # input device 1
6371 frame $id.in1f
6372 pack $id.in1f -side top
6373
6374 label $id.in1f.l1 -text "input device 1:"
6375 button $id.in1f.x1 -text [lindex $indevlist $audio_indev1] \
6376 -command [list audio_popup $id $id.in1f.x1 audio_indev1 $indevlist]
6377 label $id.in1f.l2 -text "channels:"
6378 entry $id.in1f.x2 -textvariable audio_inchan1 -width 3
6379 pack $id.in1f.l1 $id.in1f.x1 $id.in1f.l2 $id.in1f.x2 -side left
6380
6381 # input device 2
6382 if {$longform && $multi > 1 && [llength $indevlist] > 1} {
6383 frame $id.in2f
6384 pack $id.in2f -side top
6385
6386 label $id.in2f.l1 -text "input device 2:"
6387 button $id.in2f.x1 -text [lindex $indevlist $audio_indev2] \
6388 -command [list audio_popup $id $id.in2f.x1 audio_indev2 $indevlist]
6389 label $id.in2f.l2 -text "channels:"
6390 entry $id.in2f.x2 -textvariable audio_inchan2 -width 3
6391 pack $id.in2f.l1 $id.in2f.x1 $id.in2f.l2 $id.in2f.x2 -side left
6392 }
6393
6394 # input device 3
6395 if {$longform && $multi > 1 && [llength $indevlist] > 2} {
6396 frame $id.in3f
6397 pack $id.in3f -side top
6398
6399 label $id.in3f.l1 -text "input device 3:"
6400 button $id.in3f.x1 -text [lindex $indevlist $audio_indev3] \
6401 -command [list audio_popup $id $id.in3f.x1 audio_indev3 $indevlist]
6402 label $id.in3f.l2 -text "channels:"
6403 entry $id.in3f.x2 -textvariable audio_inchan3 -width 3
6404 pack $id.in3f.l1 $id.in3f.x1 $id.in3f.l2 $id.in3f.x2 -side left
6405 }
6406
6407 # input device 4
6408 if {$longform && $multi > 1 && [llength $indevlist] > 3} {
6409 frame $id.in4f
6410 pack $id.in4f -side top
6411
6412 label $id.in4f.l1 -text "input device 4:"
6413 button $id.in4f.x1 -text [lindex $indevlist $audio_indev4] \
6414 -command [list audio_popup $id $id.in4f.x1 audio_indev4 $indevlist]
6415 label $id.in4f.l2 -text "channels:"
6416 entry $id.in4f.x2 -textvariable audio_inchan4 -width 3
6417 pack $id.in4f.l1 $id.in4f.x1 $id.in4f.l2 $id.in4f.x2 -side left
6418 }
6419
6420 # output device 1
6421 frame $id.out1f
6422 pack $id.out1f -side top
6423
6424 if {$multi == 0} {
6425 label $id.out1f.l1 \
6426 -text "(output device same as input device) .............. "
6427 } else {
6428 label $id.out1f.l1 -text "output device 1:"
6429 button $id.out1f.x1 -text [lindex $outdevlist $audio_outdev1] \
6430 -command \
6431 [list audio_popup $id $id.out1f.x1 audio_outdev1 $outdevlist]
6432 }
6433 label $id.out1f.l2 -text "channels:"
6434 entry $id.out1f.x2 -textvariable audio_outchan1 -width 3
6435 if {$multi == 0} {
6436 pack $id.out1f.l1 $id.out1f.l2 $id.out1f.x2 -side left
6437 } else {
6438 pack $id.out1f.l1 $id.out1f.x1 $id.out1f.l2 $id.out1f.x2 -side left
6439 }
6440
6441 # output device 2
6442 if {$longform && $multi > 1 && [llength $indevlist] > 1} {
6443 frame $id.out2f
6444 pack $id.out2f -side top
6445 label $id.out2f.l1 -text "output device 2:"
6446 button $id.out2f.x1 -text [lindex $outdevlist $audio_outdev2] \
6447 -command \
6448 [list audio_popup $id $id.out2f.x1 audio_outdev2 $outdevlist]
6449 label $id.out2f.l2 -text "channels:"
6450 entry $id.out2f.x2 -textvariable audio_outchan2 -width 3
6451 pack $id.out2f.l1 $id.out2f.x1 $id.out2f.l2 $id.out2f.x2 -side left
6452 }
6453
6454 # output device 3
6455 if {$longform && $multi > 1 && [llength $indevlist] > 2} {
6456 frame $id.out3f
6457 pack $id.out3f -side top
6458 label $id.out3f.l1 -text "output device 3:"
6459 button $id.out3f.x1 -text [lindex $outdevlist $audio_outdev3] \
6460 -command \
6461 [list audio_popup $id $id.out3f.x1 audio_outdev3 $outdevlist]
6462 label $id.out3f.l2 -text "channels:"
6463 entry $id.out3f.x2 -textvariable audio_outchan3 -width 3
6464 pack $id.out3f.l1 $id.out3f.x1 $id.out3f.l2 $id.out3f.x2 -side left
6465 }
6466
6467 # output device 4
6468 if {$longform && $multi > 1 && [llength $indevlist] > 3} {
6469 frame $id.out4f
6470 pack $id.out4f -side top
6471 label $id.out4f.l1 -text "output device 4:"
6472 button $id.out4f.x1 -text [lindex $outdevlist $audio_outdev4] \
6473 -command \
6474 [list audio_popup $id $id.out4f.x1 audio_outdev4 $outdevlist]
6475 label $id.out4f.l2 -text "channels:"
6476 entry $id.out4f.x2 -textvariable audio_outchan4 -width 3
6477 pack $id.out4f.l1 $id.out4f.x1 $id.out4f.l2 $id.out4f.x2 -side left
6478 }
6479
6480 # if not the "long form" but if "multi" is 2, make a button to
6481 # restart with longform set.
6482
6483 if {$longform == 0 && $multi > 1} {
6484 frame $id.longbutton
6485 pack $id.longbutton -side top
6486 button $id.longbutton.b -text {use multiple devices} \
6487 -command {pd pd audio-properties 1 \;}
6488 pack $id.longbutton.b
6489 }
6490 bind $id.srf.x1 <KeyPress-Return> [concat audio_ok $id]
6491 bind $id.srf.x2 <KeyPress-Return> [concat audio_ok $id]
6492 bind $id.in1f.x2 <KeyPress-Return> [concat audio_ok $id]
6493 $id.srf.x1 select from 0
6494 $id.srf.x1 select adjust end
6495 focus $id.srf.x1
6496}
6497
6498####################### midi dialog ##################3
6499
6500proc midi_apply {id} {
6501 global midi_indev1 midi_indev2 midi_indev3 midi_indev4
6502 global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4
6503
6504 pd [concat pd midi-dialog \
6505 $midi_indev1 \
6506 $midi_indev2 \
6507 $midi_indev3 \
6508 $midi_indev4 \
6509 $midi_outdev1 \
6510 $midi_outdev2 \
6511 $midi_outdev3 \
6512 $midi_outdev4 \
6513 \;]
6514}
6515
6516proc midi_cancel {id} {
6517 pd [concat $id cancel \;]
6518}
6519
6520proc midi_ok {id} {
6521 midi_apply $id
6522 midi_cancel $id
6523}
6524
6525# callback from popup menu
6526proc midi_popup_action {buttonname varname devlist index} {
6527 global midi_indevlist midi_outdevlist $varname
6528 $buttonname configure -text [lindex $devlist $index]
6529# puts stderr [concat popup_action $buttonname $varname $index]
6530 set $varname $index
6531}
6532
6533# create a popup menu
6534proc midi_popup {name buttonname varname devlist} {
6535 if [winfo exists $name.popup] {destroy $name.popup}
6536 menu $name.popup -tearoff false
6537# puts stderr [concat $devlist ]
6538 for {set x 0} {$x<[llength $devlist]} {incr x} {
6539 $name.popup add command -label [lindex $devlist $x] \
6540 -command [list midi_popup_action \
6541 $buttonname $varname $devlist $x]
6542 }
6543 tk_popup $name.popup [winfo pointerx $name] [winfo pointery $name] 0
6544}
6545
6546# start a dialog window to select midi devices. "longform" asks us to make
6547# controls for opening several devices; if not, we get an extra button to
6548# turn longform on and restart the dialog.
6549
6550proc pdtk_midi_dialog {id indevlist indev1 indev2 indev3 indev4 \
6551 outdevlist outdev1 outdev2 outdev3 outdev4 longform} {
6552 global midi_indev1 midi_indev2 midi_indev3 midi_indev4
6553 global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4
6554 global midi_indevlist midi_outdevlist
6555
6556 set midi_indev1 $indev1
6557 set midi_indev2 $indev2
6558 set midi_indev3 $indev3
6559 set midi_indev4 $indev4
6560 set midi_outdev1 $outdev1
6561 set midi_outdev2 $outdev2
6562 set midi_outdev3 $outdev3
6563 set midi_outdev4 $outdev4
6564 set midi_indevlist $indevlist
6565 set midi_outdevlist $outdevlist
6566
6567 toplevel $id
6568 wm title $id {midi}
6569 wm protocol $id WM_DELETE_WINDOW [concat midi_cancel $id]
6570
6571 frame $id.buttonframe
6572 pack $id.buttonframe -side bottom -fill x -pady 2m
6573 button $id.buttonframe.cancel -text {Cancel}\
6574 -command "midi_cancel $id"
6575 button $id.buttonframe.apply -text {Apply}\
6576 -command "midi_apply $id"
6577 button $id.buttonframe.ok -text {OK}\
6578 -command "midi_ok $id"
6579 pack $id.buttonframe.cancel -side left -expand 1
6580 pack $id.buttonframe.apply -side left -expand 1
6581 pack $id.buttonframe.ok -side left -expand 1
6582
6583 # input device 1
6584 frame $id.in1f
6585 pack $id.in1f -side top
6586
6587 label $id.in1f.l1 -text "input device 1:"
6588 button $id.in1f.x1 -text [lindex $indevlist $midi_indev1] \
6589 -command [list midi_popup $id $id.in1f.x1 midi_indev1 $indevlist]
6590 pack $id.in1f.l1 $id.in1f.x1 -side left
6591
6592 # input device 2
6593 if {$longform && [llength $indevlist] > 2} {
6594 frame $id.in2f
6595 pack $id.in2f -side top
6596
6597 label $id.in2f.l1 -text "input device 2:"
6598 button $id.in2f.x1 -text [lindex $indevlist $midi_indev2] \
6599 -command [list midi_popup $id $id.in2f.x1 midi_indev2 $indevlist]
6600 pack $id.in2f.l1 $id.in2f.x1 -side left
6601 }
6602
6603 # input device 3
6604 if {$longform && [llength $indevlist] > 3} {
6605 frame $id.in3f
6606 pack $id.in3f -side top
6607
6608 label $id.in3f.l1 -text "input device 3:"
6609 button $id.in3f.x1 -text [lindex $indevlist $midi_indev3] \
6610 -command [list midi_popup $id $id.in3f.x1 midi_indev3 $indevlist]
6611 pack $id.in3f.l1 $id.in3f.x1 -side left
6612 }
6613
6614 # input device 4
6615 if {$longform && [llength $indevlist] > 4} {
6616 frame $id.in4f
6617 pack $id.in4f -side top
6618
6619 label $id.in4f.l1 -text "input device 4:"
6620 button $id.in4f.x1 -text [lindex $indevlist $midi_indev4] \
6621 -command [list midi_popup $id $id.in4f.x1 midi_indev4 $indevlist]
6622 pack $id.in4f.l1 $id.in4f.x1 -side left
6623 }
6624
6625 # output device 1
6626
6627 frame $id.out1f
6628 pack $id.out1f -side top
6629 label $id.out1f.l1 -text "output device 1:"
6630 button $id.out1f.x1 -text [lindex $outdevlist $midi_outdev1] \
6631 -command [list midi_popup $id $id.out1f.x1 midi_outdev1 $outdevlist]
6632 pack $id.out1f.l1 $id.out1f.x1 -side left
6633
6634 # output device 2
6635 if {$longform && [llength $indevlist] > 2} {
6636 frame $id.out2f
6637 pack $id.out2f -side top
6638 label $id.out2f.l1 -text "output device 2:"
6639 button $id.out2f.x1 -text [lindex $outdevlist $midi_outdev2] \
6640 -command \
6641 [list midi_popup $id $id.out2f.x1 midi_outdev2 $outdevlist]
6642 pack $id.out2f.l1 $id.out2f.x1 -side left
6643 }
6644
6645 # output device 3
6646 if {$longform && [llength $indevlist] > 3} {
6647 frame $id.out3f
6648 pack $id.out3f -side top
6649 label $id.out3f.l1 -text "output device 3:"
6650 button $id.out3f.x1 -text [lindex $outdevlist $midi_outdev3] \
6651 -command \
6652 [list midi_popup $id $id.out3f.x1 midi_outdev3 $outdevlist]
6653 pack $id.out3f.l1 $id.out3f.x1 -side left
6654 }
6655
6656 # output device 4
6657 if {$longform && [llength $indevlist] > 4} {
6658 frame $id.out4f
6659 pack $id.out4f -side top
6660 label $id.out4f.l1 -text "output device 4:"
6661 button $id.out4f.x1 -text [lindex $outdevlist $midi_outdev4] \
6662 -command \
6663 [list midi_popup $id $id.out4f.x1 midi_outdev4 $outdevlist]
6664 pack $id.out4f.l1 $id.out4f.x1 -side left
6665 }
6666
6667 # if not the "long form" make a button to
6668 # restart with longform set.
6669
6670 if {$longform == 0} {
6671 frame $id.longbutton
6672 pack $id.longbutton -side top
6673 button $id.longbutton.b -text {use multiple devices} \
6674 -command {pd pd midi-properties 1 \;}
6675 pack $id.longbutton.b
6676 }
6677}
6678
6679############ pdtk_path_dialog -- dialog window for search path #########
6680
6681proc path_apply {id} {
6682 global pd_path0 pd_path1 pd_path2 pd_path3 pd_path4
6683 global pd_path5 pd_path6 pd_path7 pd_path8 pd_path9
6684
6685 pd [concat pd path-dialog \
6686 $pd_path0 $pd_path1 $pd_path2 $pd_path3 $pd_path4 \
6687 $pd_path5 $pd_path6 $pd_path7 $pd_path8 $pd_path9 \
6688 \;]
6689}
6690
6691proc path_cancel {id} {
6692 pd [concat $id cancel \;]
6693}
6694
6695proc path_ok {id} {
6696 path_apply $id
6697 path_cancel $id
6698}
6699set pd_path0 sdfgh
6700
6701proc pdtk_path_dialog {id} {
6702 global pd_path0 pd_path1 pd_path2 pd_path3 pd_path4
6703 global pd_path5 pd_path6 pd_path7 pd_path8 pd_path9
6704
6705 toplevel $id
6706 wm title $id {PD search path for patches and other files}
6707 wm protocol $id WM_DELETE_WINDOW [concat path_cancel $id]
6708
6709 frame $id.buttonframe
6710 pack $id.buttonframe -side bottom -fill x -pady 2m
6711 button $id.buttonframe.cancel -text {Cancel}\
6712 -command "path_cancel $id"
6713 button $id.buttonframe.apply -text {Apply}\
6714 -command "path_apply $id"
6715 button $id.buttonframe.ok -text {OK}\
6716 -command "path_ok $id"
6717 pack $id.buttonframe.cancel -side left -expand 1
6718 pack $id.buttonframe.apply -side left -expand 1
6719 pack $id.buttonframe.ok -side left -expand 1
6720
6721 for {set x 0} {$x < 10} {incr x} {
6722 # input device 1
6723 entry $id.f$x -textvariable pd_path$x -width 80
6724 bind $id.f$x <KeyPress-Return> [concat path_ok $id]
6725 pack $id.f$x -side top
6726 }
6727
6728 focus $id.f0
6729}
6730
6731proc pd_set {var value} {
6732 global $var
6733 set $var $value
6734}
diff --git a/apps/plugins/pdbox/PDa/src/u_pdreceive.c b/apps/plugins/pdbox/PDa/src/u_pdreceive.c
new file mode 100644
index 0000000000..3ec097edcc
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/u_pdreceive.c
@@ -0,0 +1,650 @@
1/* Copyright (c) 2000 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
4
5/* the "pdreceive" command. This is a standalone program that receives messages
6from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
7standard output. */
8
9#include <sys/types.h>
10#include <string.h>
11#include <stdio.h>
12#include <errno.h>
13#include <stdlib.h>
14#ifdef UNIX
15#include <sys/time.h>
16#include <unistd.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <netdb.h>
20#define SOCKET_ERROR -1
21#else
22#include <winsock.h>
23#endif
24
25typedef struct _fdpoll
26{
27 int fdp_fd;
28 char *fdp_inbuf;
29 int fdp_inhead;
30 int fdp_intail;
31 int fdp_udp;
32} t_fdpoll;
33
34static int nfdpoll;
35static t_fdpoll *fdpoll;
36static int maxfd;
37static int sockfd;
38static int protocol;
39
40static void sockerror(char *s);
41static void x_closesocket(int fd);
42static void dopoll(void);
43#define BUFSIZE 4096
44
45int main(int argc, char **argv)
46{
47 int portno;
48 struct sockaddr_in server;
49 int nretry = 10;
50#ifdef MSW
51 short version = MAKEWORD(2, 0);
52 WSADATA nobby;
53#endif
54 if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
55 goto usage;
56 if (argc >= 3)
57 {
58 if (!strcmp(argv[2], "tcp"))
59 protocol = SOCK_STREAM;
60 else if (!strcmp(argv[2], "udp"))
61 protocol = SOCK_DGRAM;
62 else goto usage;
63 }
64 else protocol = SOCK_STREAM;
65#ifdef MSW
66 if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
67#endif
68 sockfd = socket(AF_INET, protocol, 0);
69 if (sockfd < 0)
70 {
71 sockerror("socket()");
72 exit(1);
73 }
74 maxfd = sockfd + 1;
75 server.sin_family = AF_INET;
76 server.sin_addr.s_addr = INADDR_ANY;
77
78#ifdef IRIX
79 /* this seems to work only in IRIX but is unnecessary in
80 Linux. Not sure what MSW needs in place of this. */
81 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
82 post("setsockopt failed\n");
83#endif
84
85 /* assign client port number */
86 server.sin_port = htons((unsigned short)portno);
87
88 /* name the socket */
89 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
90 {
91 sockerror("bind");
92 x_closesocket(sockfd);
93 return (0);
94 }
95 if (protocol == SOCK_STREAM)
96 {
97 if (listen(sockfd, 5) < 0)
98 {
99 sockerror("listen");
100 x_closesocket(sockfd);
101 exit(1);
102 }
103 }
104 /* now loop forever selecting on sockets */
105 while (1)
106 dopoll();
107
108usage:
109 fprintf(stderr, "usage: pdreceive <portnumber> [udp|tcp]\n");
110 fprintf(stderr, "(default is tcp)\n");
111 exit(1);
112}
113
114static void addport(int fd)
115{
116 int nfd = nfdpoll;
117 t_fdpoll *fp;
118 fdpoll = (t_fdpoll *)realloc(fdpoll,
119 (nfdpoll+1) * sizeof(t_fdpoll));
120 fp = fdpoll + nfdpoll;
121 fp->fdp_fd = fd;
122 nfdpoll++;
123 if (fd >= maxfd) maxfd = fd + 1;
124 fp->fdp_inhead = fp->fdp_intail = 0;
125 if (!(fp->fdp_inbuf = malloc(BUFSIZE)))
126 {
127 fprintf(stderr, "out of memory");
128 exit(1);
129 }
130 printf("number_connected %d;\n", nfdpoll);
131}
132
133static void rmport(t_fdpoll *x)
134{
135 int nfd = nfdpoll;
136 int i, size = nfdpoll * sizeof(t_fdpoll);
137 t_fdpoll *fp;
138 for (i = nfdpoll, fp = fdpoll; i--; fp++)
139 {
140 if (fp == x)
141 {
142 x_closesocket(fp->fdp_fd);
143 free(fp->fdp_inbuf);
144 while (i--)
145 {
146 fp[0] = fp[1];
147 fp++;
148 }
149 fdpoll = (t_fdpoll *)realloc(fdpoll,
150 (nfdpoll-1) * sizeof(t_fdpoll));
151 nfdpoll--;
152 printf("number_connected %d;\n", nfdpoll);
153 return;
154 }
155 }
156 fprintf(stderr, "warning: item removed from poll list but not found");
157}
158
159static void doconnect(void)
160{
161 int fd = accept(sockfd, 0, 0);
162 if (fd < 0)
163 perror("accept");
164 else addport(fd);
165}
166
167static void udpread(void)
168{
169 char buf[BUFSIZE];
170 int ret = recv(sockfd, buf, BUFSIZE, 0);
171 if (ret < 0)
172 {
173 sockerror("recv (udp)");
174 x_closesocket(sockfd);
175 exit(1);
176 }
177 else if (ret > 0)
178 {
179#ifdef UNIX
180 if (write(1, buf, ret) < ret)
181 {
182 perror("write");
183 exit(1);
184 }
185#else
186 int j;
187 for (j = 0; j < ret; j++)
188 putchar(buf[j]);
189#endif
190 }
191}
192
193static int tcpmakeoutput(t_fdpoll *x)
194{
195 char messbuf[BUFSIZE+1], *bp = messbuf;
196 int indx;
197 int inhead = x->fdp_inhead;
198 int intail = x->fdp_intail;
199 char *inbuf = x->fdp_inbuf;
200 if (intail == inhead)
201 return (0);
202 for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
203 {
204 /* search for a semicolon. */
205 char c = *bp++ = inbuf[indx];
206 if (c == ';')
207 {
208 intail = (indx+1)&(BUFSIZE-1);
209 if (inbuf[intail] == '\n')
210 intail = (intail+1)&(BUFSIZE-1);
211 *bp++ = '\n';
212#ifdef UNIX
213 write(1, messbuf, bp - messbuf);
214#else
215 {
216 int j;
217 for (j = 0; j < bp - messbuf; j++)
218 putchar(messbuf[j]);
219 }
220#endif
221 x->fdp_inhead = inhead;
222 x->fdp_intail = intail;
223 return (1);
224 }
225 }
226 return (0);
227}
228
229static void tcpread(t_fdpoll *x)
230{
231 int readto =
232 (x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
233 int ret;
234
235 /* the input buffer might be full. If so, drop the whole thing */
236 if (readto == x->fdp_inhead)
237 {
238 fprintf(stderr, "pd: dropped message from gui\n");
239 x->fdp_inhead = x->fdp_intail = 0;
240 readto = BUFSIZE;
241 }
242 else
243 {
244 ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
245 readto - x->fdp_inhead, 0);
246 if (ret < 0)
247 {
248 sockerror("recv (tcp)");
249 rmport(x);
250 }
251 else if (ret == 0)
252 rmport(x);
253 else
254 {
255 x->fdp_inhead += ret;
256 if (x->fdp_inhead >= BUFSIZE)
257 x->fdp_inhead = 0;
258 while (tcpmakeoutput(x))
259 ;
260 }
261 }
262}
263
264static void dopoll(void)
265{
266 int i;
267 t_fdpoll *fp;
268 fd_set readset, writeset, exceptset;
269 FD_ZERO(&writeset);
270 FD_ZERO(&readset);
271 FD_ZERO(&exceptset);
272
273 FD_SET(sockfd, &readset);
274 if (protocol == SOCK_STREAM)
275 {
276 for (fp = fdpoll, i = nfdpoll; i--; fp++)
277 FD_SET(fp->fdp_fd, &readset);
278 }
279 if (select(maxfd+1, &readset, &writeset, &exceptset, 0) < 0)
280 {
281 perror("select");
282 exit(1);
283 }
284 if (protocol == SOCK_STREAM)
285 {
286 for (i = 0; i < nfdpoll; i++)
287 if (FD_ISSET(fdpoll[i].fdp_fd, &readset))
288 tcpread(&fdpoll[i]);
289 if (FD_ISSET(sockfd, &readset))
290 doconnect();
291 }
292 else
293 {
294 if (FD_ISSET(sockfd, &readset))
295 udpread();
296 }
297}
298
299
300static void sockerror(char *s)
301{
302#ifdef MSW
303 int err = WSAGetLastError();
304 if (err == 10054) return;
305 else if (err == 10044)
306 {
307 fprintf(stderr,
308 "Warning: you might not have TCP/IP \"networking\" turned on\n");
309 }
310#endif
311#ifdef UNIX
312 int err = errno;
313#endif
314 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
315}
316
317static void x_closesocket(int fd)
318{
319#ifdef UNIX
320 close(fd);
321#endif
322#ifdef MSW
323 closesocket(fd);
324#endif
325}
326/* Copyright (c) 2000 Miller Puckette.
327* For information on usage and redistribution, and for a DISCLAIMER OF ALL
328* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
329
330/* the "pdreceive" command. This is a standalone program that receives messages
331from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
332standard output. */
333
334#include <sys/types.h>
335#include <string.h>
336#include <stdio.h>
337#include <errno.h>
338#include <stdlib.h>
339#ifdef UNIX
340#include <sys/time.h>
341#include <unistd.h>
342#include <sys/socket.h>
343#include <netinet/in.h>
344#include <netdb.h>
345#define SOCKET_ERROR -1
346#else
347#include <winsock.h>
348#endif
349
350typedef struct _fdpoll
351{
352 int fdp_fd;
353 char *fdp_inbuf;
354 int fdp_inhead;
355 int fdp_intail;
356 int fdp_udp;
357} t_fdpoll;
358
359static int nfdpoll;
360static t_fdpoll *fdpoll;
361static int maxfd;
362static int sockfd;
363static int protocol;
364
365static void sockerror(char *s);
366static void x_closesocket(int fd);
367static void dopoll(void);
368#define BUFSIZE 4096
369
370int main(int argc, char **argv)
371{
372 int portno;
373 struct sockaddr_in server;
374 int nretry = 10;
375#ifdef MSW
376 short version = MAKEWORD(2, 0);
377 WSADATA nobby;
378#endif
379 if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
380 goto usage;
381 if (argc >= 3)
382 {
383 if (!strcmp(argv[2], "tcp"))
384 protocol = SOCK_STREAM;
385 else if (!strcmp(argv[2], "udp"))
386 protocol = SOCK_DGRAM;
387 else goto usage;
388 }
389 else protocol = SOCK_STREAM;
390#ifdef MSW
391 if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
392#endif
393 sockfd = socket(AF_INET, protocol, 0);
394 if (sockfd < 0)
395 {
396 sockerror("socket()");
397 exit(1);
398 }
399 maxfd = sockfd + 1;
400 server.sin_family = AF_INET;
401 server.sin_addr.s_addr = INADDR_ANY;
402
403#ifdef IRIX
404 /* this seems to work only in IRIX but is unnecessary in
405 Linux. Not sure what MSW needs in place of this. */
406 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
407 post("setsockopt failed\n");
408#endif
409
410 /* assign client port number */
411 server.sin_port = htons((unsigned short)portno);
412
413 /* name the socket */
414 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
415 {
416 sockerror("bind");
417 x_closesocket(sockfd);
418 return (0);
419 }
420 if (protocol == SOCK_STREAM)
421 {
422 if (listen(sockfd, 5) < 0)
423 {
424 sockerror("listen");
425 x_closesocket(sockfd);
426 exit(1);
427 }
428 }
429 /* now loop forever selecting on sockets */
430 while (1)
431 dopoll();
432
433usage:
434 fprintf(stderr, "usage: pdreceive <portnumber> [udp|tcp]\n");
435 fprintf(stderr, "(default is tcp)\n");
436 exit(1);
437}
438
439static void addport(int fd)
440{
441 int nfd = nfdpoll;
442 t_fdpoll *fp;
443 fdpoll = (t_fdpoll *)realloc(fdpoll,
444 (nfdpoll+1) * sizeof(t_fdpoll));
445 fp = fdpoll + nfdpoll;
446 fp->fdp_fd = fd;
447 nfdpoll++;
448 if (fd >= maxfd) maxfd = fd + 1;
449 fp->fdp_inhead = fp->fdp_intail = 0;
450 if (!(fp->fdp_inbuf = malloc(BUFSIZE)))
451 {
452 fprintf(stderr, "out of memory");
453 exit(1);
454 }
455 printf("number_connected %d;\n", nfdpoll);
456}
457
458static void rmport(t_fdpoll *x)
459{
460 int nfd = nfdpoll;
461 int i, size = nfdpoll * sizeof(t_fdpoll);
462 t_fdpoll *fp;
463 for (i = nfdpoll, fp = fdpoll; i--; fp++)
464 {
465 if (fp == x)
466 {
467 x_closesocket(fp->fdp_fd);
468 free(fp->fdp_inbuf);
469 while (i--)
470 {
471 fp[0] = fp[1];
472 fp++;
473 }
474 fdpoll = (t_fdpoll *)realloc(fdpoll,
475 (nfdpoll-1) * sizeof(t_fdpoll));
476 nfdpoll--;
477 printf("number_connected %d;\n", nfdpoll);
478 return;
479 }
480 }
481 fprintf(stderr, "warning: item removed from poll list but not found");
482}
483
484static void doconnect(void)
485{
486 int fd = accept(sockfd, 0, 0);
487 if (fd < 0)
488 perror("accept");
489 else addport(fd);
490}
491
492static void udpread(void)
493{
494 char buf[BUFSIZE];
495 int ret = recv(sockfd, buf, BUFSIZE, 0);
496 if (ret < 0)
497 {
498 sockerror("recv (udp)");
499 x_closesocket(sockfd);
500 exit(1);
501 }
502 else if (ret > 0)
503 {
504#ifdef UNIX
505 if (write(1, buf, ret) < ret)
506 {
507 perror("write");
508 exit(1);
509 }
510#else
511 int j;
512 for (j = 0; j < ret; j++)
513 putchar(buf[j]);
514#endif
515 }
516}
517
518static int tcpmakeoutput(t_fdpoll *x)
519{
520 char messbuf[BUFSIZE+1], *bp = messbuf;
521 int indx;
522 int inhead = x->fdp_inhead;
523 int intail = x->fdp_intail;
524 char *inbuf = x->fdp_inbuf;
525 if (intail == inhead)
526 return (0);
527 for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
528 {
529 /* search for a semicolon. */
530 char c = *bp++ = inbuf[indx];
531 if (c == ';')
532 {
533 intail = (indx+1)&(BUFSIZE-1);
534 if (inbuf[intail] == '\n')
535 intail = (intail+1)&(BUFSIZE-1);
536 *bp++ = '\n';
537#ifdef UNIX
538 write(1, messbuf, bp - messbuf);
539#else
540 {
541 int j;
542 for (j = 0; j < bp - messbuf; j++)
543 putchar(messbuf[j]);
544 }
545#endif
546 x->fdp_inhead = inhead;
547 x->fdp_intail = intail;
548 return (1);
549 }
550 }
551 return (0);
552}
553
554static void tcpread(t_fdpoll *x)
555{
556 int readto =
557 (x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
558 int ret;
559
560 /* the input buffer might be full. If so, drop the whole thing */
561 if (readto == x->fdp_inhead)
562 {
563 fprintf(stderr, "pd: dropped message from gui\n");
564 x->fdp_inhead = x->fdp_intail = 0;
565 readto = BUFSIZE;
566 }
567 else
568 {
569 ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
570 readto - x->fdp_inhead, 0);
571 if (ret < 0)
572 {
573 sockerror("recv (tcp)");
574 rmport(x);
575 }
576 else if (ret == 0)
577 rmport(x);
578 else
579 {
580 x->fdp_inhead += ret;
581 if (x->fdp_inhead >= BUFSIZE)
582 x->fdp_inhead = 0;
583 while (tcpmakeoutput(x))
584 ;
585 }
586 }
587}
588
589static void dopoll(void)
590{
591 int i;
592 t_fdpoll *fp;
593 fd_set readset, writeset, exceptset;
594 FD_ZERO(&writeset);
595 FD_ZERO(&readset);
596 FD_ZERO(&exceptset);
597
598 FD_SET(sockfd, &readset);
599 if (protocol == SOCK_STREAM)
600 {
601 for (fp = fdpoll, i = nfdpoll; i--; fp++)
602 FD_SET(fp->fdp_fd, &readset);
603 }
604 if (select(maxfd+1, &readset, &writeset, &exceptset, 0) < 0)
605 {
606 perror("select");
607 exit(1);
608 }
609 if (protocol == SOCK_STREAM)
610 {
611 for (i = 0; i < nfdpoll; i++)
612 if (FD_ISSET(fdpoll[i].fdp_fd, &readset))
613 tcpread(&fdpoll[i]);
614 if (FD_ISSET(sockfd, &readset))
615 doconnect();
616 }
617 else
618 {
619 if (FD_ISSET(sockfd, &readset))
620 udpread();
621 }
622}
623
624
625static void sockerror(char *s)
626{
627#ifdef MSW
628 int err = WSAGetLastError();
629 if (err == 10054) return;
630 else if (err == 10044)
631 {
632 fprintf(stderr,
633 "Warning: you might not have TCP/IP \"networking\" turned on\n");
634 }
635#endif
636#ifdef UNIX
637 int err = errno;
638#endif
639 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
640}
641
642static void x_closesocket(int fd)
643{
644#ifdef UNIX
645 close(fd);
646#endif
647#ifdef MSW
648 closesocket(fd);
649#endif
650}
diff --git a/apps/plugins/pdbox/PDa/src/u_pdsend.c b/apps/plugins/pdbox/PDa/src/u_pdsend.c
new file mode 100644
index 0000000000..9f2f9232bb
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/u_pdsend.c
@@ -0,0 +1,314 @@
1/* Copyright (c) 2000 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
4
5/* the "pdsend" command. This is a standalone program that forwards messages
6from its standard input to Pd via the netsend/netreceive ("FUDI") protocol. */
7
8#include <sys/types.h>
9#include <string.h>
10#include <stdio.h>
11#include <errno.h>
12#include <stdlib.h>
13#ifdef UNIX
14#include <unistd.h>
15#include <sys/socket.h>
16#include <netinet/in.h>
17#include <netdb.h>
18#define SOCKET_ERROR -1
19#else
20#include <winsock.h>
21#endif
22
23void sockerror(char *s);
24void x_closesocket(int fd);
25#define BUFSIZE 4096
26
27int main(int argc, char **argv)
28{
29 int sockfd, portno, protocol;
30 struct sockaddr_in server;
31 struct hostent *hp;
32 char *hostname;
33 int nretry = 10;
34#ifdef MSW
35 short version = MAKEWORD(2, 0);
36 WSADATA nobby;
37#endif
38 if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
39 goto usage;
40 if (argc >= 3)
41 hostname = argv[2];
42 else hostname = "127.0.0.1";
43 if (argc >= 4)
44 {
45 if (!strcmp(argv[3], "tcp"))
46 protocol = SOCK_STREAM;
47 else if (!strcmp(argv[3], "udp"))
48 protocol = SOCK_DGRAM;
49 else goto usage;
50 }
51 else protocol = SOCK_STREAM;
52#ifdef MSW
53 if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
54#endif
55
56 sockfd = socket(AF_INET, protocol, 0);
57 if (sockfd < 0)
58 {
59 sockerror("socket()");
60 exit(1);
61 }
62 /* connect socket using hostname provided in command line */
63 server.sin_family = AF_INET;
64 hp = gethostbyname(hostname);
65 if (hp == 0)
66 {
67 fprintf(stderr, "%s: unknown host\n", hostname);
68 x_closesocket(sockfd);
69 exit(1);
70 }
71 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
72
73 /* assign client port number */
74 server.sin_port = htons((unsigned short)portno);
75
76#if 0 /* try this again for 4.0; this crashed my RH 6.2 machine!) */
77
78 /* try to connect. */
79 for (nretry = 0; nretry < (protocol == SOCK_STREAM ? 10 : 1); nretry++)
80
81 {
82 if (nretry > 0)
83 {
84 sleep (nretry < 5 ? 1 : 5);
85 fprintf(stderr, "retrying...");
86 }
87 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) >= 0)
88 goto connected;
89 sockerror("connect");
90 }
91 x_closesocket(sockfd);
92 exit(1);
93connected: ;
94#else
95 /* try to connect. */
96 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
97 {
98 sockerror("connect");
99 x_closesocket(sockfd);
100 exit(1);
101 }
102#endif
103 /* now loop reading stdin and sending it to socket */
104 while (1)
105 {
106 char buf[BUFSIZE], *bp, nsent, nsend;
107 if (!fgets(buf, BUFSIZE, stdin))
108 break;
109 nsend = strlen(buf);
110 for (bp = buf, nsent = 0; nsent < nsend;)
111 {
112 int res = send(sockfd, buf, nsend-nsent, 0);
113 if (res < 0)
114 {
115 sockerror("send");
116 goto done;
117 }
118 nsent += res;
119 bp += res;
120 }
121 }
122done:
123 if (ferror(stdin))
124 perror("stdin");
125 exit (0);
126usage:
127 fprintf(stderr, "usage: pdsend <portnumber> [host] [udp|tcp]\n");
128 fprintf(stderr, "(default is localhost and tcp)\n");
129 exit(1);
130}
131
132void sockerror(char *s)
133{
134#ifdef MSW
135 int err = WSAGetLastError();
136 if (err == 10054) return;
137 else if (err == 10044)
138 {
139 fprintf(stderr,
140 "Warning: you might not have TCP/IP \"networking\" turned on\n");
141 }
142#endif
143#ifdef UNIX
144 int err = errno;
145#endif
146 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
147}
148
149void x_closesocket(int fd)
150{
151#ifdef UNIX
152 close(fd);
153#endif
154#ifdef MSW
155 closesocket(fd);
156#endif
157}
158/* Copyright (c) 2000 Miller Puckette.
159* For information on usage and redistribution, and for a DISCLAIMER OF ALL
160* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
161
162/* the "pdsend" command. This is a standalone program that forwards messages
163from its standard input to Pd via the netsend/netreceive ("FUDI") protocol. */
164
165#include <sys/types.h>
166#include <string.h>
167#include <stdio.h>
168#include <errno.h>
169#include <stdlib.h>
170#ifdef UNIX
171#include <unistd.h>
172#include <sys/socket.h>
173#include <netinet/in.h>
174#include <netdb.h>
175#define SOCKET_ERROR -1
176#else
177#include <winsock.h>
178#endif
179
180void sockerror(char *s);
181void x_closesocket(int fd);
182#define BUFSIZE 4096
183
184int main(int argc, char **argv)
185{
186 int sockfd, portno, protocol;
187 struct sockaddr_in server;
188 struct hostent *hp;
189 char *hostname;
190 int nretry = 10;
191#ifdef MSW
192 short version = MAKEWORD(2, 0);
193 WSADATA nobby;
194#endif
195 if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
196 goto usage;
197 if (argc >= 3)
198 hostname = argv[2];
199 else hostname = "127.0.0.1";
200 if (argc >= 4)
201 {
202 if (!strcmp(argv[3], "tcp"))
203 protocol = SOCK_STREAM;
204 else if (!strcmp(argv[3], "udp"))
205 protocol = SOCK_DGRAM;
206 else goto usage;
207 }
208 else protocol = SOCK_STREAM;
209#ifdef MSW
210 if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
211#endif
212
213 sockfd = socket(AF_INET, protocol, 0);
214 if (sockfd < 0)
215 {
216 sockerror("socket()");
217 exit(1);
218 }
219 /* connect socket using hostname provided in command line */
220 server.sin_family = AF_INET;
221 hp = gethostbyname(hostname);
222 if (hp == 0)
223 {
224 fprintf(stderr, "%s: unknown host\n", hostname);
225 x_closesocket(sockfd);
226 exit(1);
227 }
228 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
229
230 /* assign client port number */
231 server.sin_port = htons((unsigned short)portno);
232
233#if 0 /* try this again for 4.0; this crashed my RH 6.2 machine!) */
234
235 /* try to connect. */
236 for (nretry = 0; nretry < (protocol == SOCK_STREAM ? 10 : 1); nretry++)
237
238 {
239 if (nretry > 0)
240 {
241 sleep (nretry < 5 ? 1 : 5);
242 fprintf(stderr, "retrying...");
243 }
244 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) >= 0)
245 goto connected;
246 sockerror("connect");
247 }
248 x_closesocket(sockfd);
249 exit(1);
250connected: ;
251#else
252 /* try to connect. */
253 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
254 {
255 sockerror("connect");
256 x_closesocket(sockfd);
257 exit(1);
258 }
259#endif
260 /* now loop reading stdin and sending it to socket */
261 while (1)
262 {
263 char buf[BUFSIZE], *bp, nsent, nsend;
264 if (!fgets(buf, BUFSIZE, stdin))
265 break;
266 nsend = strlen(buf);
267 for (bp = buf, nsent = 0; nsent < nsend;)
268 {
269 int res = send(sockfd, buf, nsend-nsent, 0);
270 if (res < 0)
271 {
272 sockerror("send");
273 goto done;
274 }
275 nsent += res;
276 bp += res;
277 }
278 }
279done:
280 if (ferror(stdin))
281 perror("stdin");
282 exit (0);
283usage:
284 fprintf(stderr, "usage: pdsend <portnumber> [host] [udp|tcp]\n");
285 fprintf(stderr, "(default is localhost and tcp)\n");
286 exit(1);
287}
288
289void sockerror(char *s)
290{
291#ifdef MSW
292 int err = WSAGetLastError();
293 if (err == 10054) return;
294 else if (err == 10044)
295 {
296 fprintf(stderr,
297 "Warning: you might not have TCP/IP \"networking\" turned on\n");
298 }
299#endif
300#ifdef UNIX
301 int err = errno;
302#endif
303 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
304}
305
306void x_closesocket(int fd)
307{
308#ifdef UNIX
309 close(fd);
310#endif
311#ifdef MSW
312 closesocket(fd);
313#endif
314}
diff --git a/apps/plugins/pdbox/PDa/src/x_acoustics.c b/apps/plugins/pdbox/PDa/src/x_acoustics.c
new file mode 100644
index 0000000000..8fc04f77d1
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_acoustics.c
@@ -0,0 +1,386 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* utility functions for signals
6*/
7
8#include "m_pd.h"
9#include <math.h>
10#define LOGTEN 2.302585092994
11
12float mtof(float f)
13{
14 if (f <= -1500) return(0);
15 else if (f > 1499) return(mtof(1499));
16 else return (8.17579891564 * exp(.0577622650 * f));
17}
18
19float ftom(float f)
20{
21 return (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
22}
23
24float powtodb(float f)
25{
26 if (f <= 0) return (0);
27 else
28 {
29 float val = 100 + 10./LOGTEN * log(f);
30 return (val < 0 ? 0 : val);
31 }
32}
33
34float rmstodb(float f)
35{
36 if (f <= 0) return (0);
37 else
38 {
39 float val = 100 + 20./LOGTEN * log(f);
40 return (val < 0 ? 0 : val);
41 }
42}
43
44float dbtopow(float f)
45{
46 if (f <= 0)
47 return(0);
48 else
49 {
50 if (f > 870)
51 f = 870;
52 return (exp((LOGTEN * 0.1) * (f-100.)));
53 }
54}
55
56float dbtorms(float f)
57{
58 if (f <= 0)
59 return(0);
60 else
61 {
62 if (f > 485)
63 f = 485;
64 }
65 return (exp((LOGTEN * 0.05) * (f-100.)));
66}
67
68/* ------------- corresponding objects ----------------------- */
69
70static t_class *mtof_class;
71
72static void *mtof_new(void)
73{
74 t_object *x = (t_object *)pd_new(mtof_class);
75 outlet_new(x, &s_float);
76 return (x);
77}
78
79static void mtof_float(t_object *x, t_float f)
80{
81 outlet_float(x->ob_outlet, mtof(f));
82}
83
84
85static t_class *ftom_class;
86
87static void *ftom_new(void)
88{
89 t_object *x = (t_object *)pd_new(ftom_class);
90 outlet_new(x, &s_float);
91 return (x);
92}
93
94static void ftom_float(t_object *x, t_float f)
95{
96 outlet_float(x->ob_outlet, ftom(f));
97}
98
99
100static t_class *rmstodb_class;
101
102static void *rmstodb_new(void)
103{
104 t_object *x = (t_object *)pd_new(rmstodb_class);
105 outlet_new(x, &s_float);
106 return (x);
107}
108
109static void rmstodb_float(t_object *x, t_float f)
110{
111 outlet_float(x->ob_outlet, rmstodb(f));
112}
113
114
115static t_class *powtodb_class;
116
117static void *powtodb_new(void)
118{
119 t_object *x = (t_object *)pd_new(powtodb_class);
120 outlet_new(x, &s_float);
121 return (x);
122}
123
124static void powtodb_float(t_object *x, t_float f)
125{
126 outlet_float(x->ob_outlet, powtodb(f));
127}
128
129
130static t_class *dbtopow_class;
131
132static void *dbtopow_new(void)
133{
134 t_object *x = (t_object *)pd_new(dbtopow_class);
135 outlet_new(x, &s_float);
136 return (x);
137}
138
139static void dbtopow_float(t_object *x, t_float f)
140{
141 outlet_float(x->ob_outlet, dbtopow(f));
142}
143
144
145static t_class *dbtorms_class;
146
147static void *dbtorms_new(void)
148{
149 t_object *x = (t_object *)pd_new(dbtorms_class);
150 outlet_new(x, &s_float);
151 return (x);
152}
153
154static void dbtorms_float(t_object *x, t_float f)
155{
156 outlet_float(x->ob_outlet, dbtorms(f));
157}
158
159
160void x_acoustics_setup(void)
161{
162 t_symbol *s = gensym("acoustics.pd");
163 mtof_class = class_new(gensym("mtof"), mtof_new, 0,
164 sizeof(t_object), 0, 0);
165 class_addfloat(mtof_class, (t_method)mtof_float);
166 class_sethelpsymbol(mtof_class, s);
167
168 ftom_class = class_new(gensym("ftom"), ftom_new, 0,
169 sizeof(t_object), 0, 0);
170 class_addfloat(ftom_class, (t_method)ftom_float);
171 class_sethelpsymbol(ftom_class, s);
172
173 powtodb_class = class_new(gensym("powtodb"), powtodb_new, 0,
174 sizeof(t_object), 0, 0);
175 class_addfloat(powtodb_class, (t_method)powtodb_float);
176 class_sethelpsymbol(powtodb_class, s);
177
178 rmstodb_class = class_new(gensym("rmstodb"), rmstodb_new, 0,
179 sizeof(t_object), 0, 0);
180 class_addfloat(rmstodb_class, (t_method)rmstodb_float);
181 class_sethelpsymbol(rmstodb_class, s);
182
183 dbtopow_class = class_new(gensym("dbtopow"), dbtopow_new, 0,
184 sizeof(t_object), 0, 0);
185 class_addfloat(dbtopow_class, (t_method)dbtopow_float);
186 class_sethelpsymbol(dbtopow_class, s);
187
188 dbtorms_class = class_new(gensym("dbtorms"), dbtorms_new, 0,
189 sizeof(t_object), 0, 0);
190 class_addfloat(dbtorms_class, (t_method)dbtorms_float);
191 class_sethelpsymbol(dbtorms_class, s);
192}
193
194/* Copyright (c) 1997-1999 Miller Puckette.
195* For information on usage and redistribution, and for a DISCLAIMER OF ALL
196* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
197
198/* utility functions for signals
199*/
200
201#include "m_pd.h"
202#include <math.h>
203#define LOGTEN 2.302585092994
204
205float mtof(float f)
206{
207 if (f <= -1500) return(0);
208 else if (f > 1499) return(mtof(1499));
209 else return (8.17579891564 * exp(.0577622650 * f));
210}
211
212float ftom(float f)
213{
214 return (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
215}
216
217float powtodb(float f)
218{
219 if (f <= 0) return (0);
220 else
221 {
222 float val = 100 + 10./LOGTEN * log(f);
223 return (val < 0 ? 0 : val);
224 }
225}
226
227float rmstodb(float f)
228{
229 if (f <= 0) return (0);
230 else
231 {
232 float val = 100 + 20./LOGTEN * log(f);
233 return (val < 0 ? 0 : val);
234 }
235}
236
237float dbtopow(float f)
238{
239 if (f <= 0)
240 return(0);
241 else
242 {
243 if (f > 870)
244 f = 870;
245 return (exp((LOGTEN * 0.1) * (f-100.)));
246 }
247}
248
249float dbtorms(float f)
250{
251 if (f <= 0)
252 return(0);
253 else
254 {
255 if (f > 485)
256 f = 485;
257 }
258 return (exp((LOGTEN * 0.05) * (f-100.)));
259}
260
261/* ------------- corresponding objects ----------------------- */
262
263static t_class *mtof_class;
264
265static void *mtof_new(void)
266{
267 t_object *x = (t_object *)pd_new(mtof_class);
268 outlet_new(x, &s_float);
269 return (x);
270}
271
272static void mtof_float(t_object *x, t_float f)
273{
274 outlet_float(x->ob_outlet, mtof(f));
275}
276
277
278static t_class *ftom_class;
279
280static void *ftom_new(void)
281{
282 t_object *x = (t_object *)pd_new(ftom_class);
283 outlet_new(x, &s_float);
284 return (x);
285}
286
287static void ftom_float(t_object *x, t_float f)
288{
289 outlet_float(x->ob_outlet, ftom(f));
290}
291
292
293static t_class *rmstodb_class;
294
295static void *rmstodb_new(void)
296{
297 t_object *x = (t_object *)pd_new(rmstodb_class);
298 outlet_new(x, &s_float);
299 return (x);
300}
301
302static void rmstodb_float(t_object *x, t_float f)
303{
304 outlet_float(x->ob_outlet, rmstodb(f));
305}
306
307
308static t_class *powtodb_class;
309
310static void *powtodb_new(void)
311{
312 t_object *x = (t_object *)pd_new(powtodb_class);
313 outlet_new(x, &s_float);
314 return (x);
315}
316
317static void powtodb_float(t_object *x, t_float f)
318{
319 outlet_float(x->ob_outlet, powtodb(f));
320}
321
322
323static t_class *dbtopow_class;
324
325static void *dbtopow_new(void)
326{
327 t_object *x = (t_object *)pd_new(dbtopow_class);
328 outlet_new(x, &s_float);
329 return (x);
330}
331
332static void dbtopow_float(t_object *x, t_float f)
333{
334 outlet_float(x->ob_outlet, dbtopow(f));
335}
336
337
338static t_class *dbtorms_class;
339
340static void *dbtorms_new(void)
341{
342 t_object *x = (t_object *)pd_new(dbtorms_class);
343 outlet_new(x, &s_float);
344 return (x);
345}
346
347static void dbtorms_float(t_object *x, t_float f)
348{
349 outlet_float(x->ob_outlet, dbtorms(f));
350}
351
352
353void x_acoustics_setup(void)
354{
355 t_symbol *s = gensym("acoustics.pd");
356 mtof_class = class_new(gensym("mtof"), mtof_new, 0,
357 sizeof(t_object), 0, 0);
358 class_addfloat(mtof_class, (t_method)mtof_float);
359 class_sethelpsymbol(mtof_class, s);
360
361 ftom_class = class_new(gensym("ftom"), ftom_new, 0,
362 sizeof(t_object), 0, 0);
363 class_addfloat(ftom_class, (t_method)ftom_float);
364 class_sethelpsymbol(ftom_class, s);
365
366 powtodb_class = class_new(gensym("powtodb"), powtodb_new, 0,
367 sizeof(t_object), 0, 0);
368 class_addfloat(powtodb_class, (t_method)powtodb_float);
369 class_sethelpsymbol(powtodb_class, s);
370
371 rmstodb_class = class_new(gensym("rmstodb"), rmstodb_new, 0,
372 sizeof(t_object), 0, 0);
373 class_addfloat(rmstodb_class, (t_method)rmstodb_float);
374 class_sethelpsymbol(rmstodb_class, s);
375
376 dbtopow_class = class_new(gensym("dbtopow"), dbtopow_new, 0,
377 sizeof(t_object), 0, 0);
378 class_addfloat(dbtopow_class, (t_method)dbtopow_float);
379 class_sethelpsymbol(dbtopow_class, s);
380
381 dbtorms_class = class_new(gensym("dbtorms"), dbtorms_new, 0,
382 sizeof(t_object), 0, 0);
383 class_addfloat(dbtorms_class, (t_method)dbtorms_float);
384 class_sethelpsymbol(dbtorms_class, s);
385}
386
diff --git a/apps/plugins/pdbox/PDa/src/x_arithmetic.c b/apps/plugins/pdbox/PDa/src/x_arithmetic.c
new file mode 100644
index 0000000000..ad309f7a68
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_arithmetic.c
@@ -0,0 +1,1792 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* arithmetic: binops ala C language. The 4 functions and relationals are
6done on floats; the logical and bitwise binops convert their
7inputs to int and their outputs back to float. */
8
9#include "m_pd.h"
10#include <math.h>
11
12
13/* MSW and OSX don't appear to have single-precision ANSI math */
14
15#define sinf sin
16#define cosf cos
17#define atanf atan
18#define atan2f atan2
19#define sqrtf sqrt
20#define logf log
21#define expf exp
22#define fabsf fabs
23#define powf pow
24
25
26typedef struct _binop
27{
28 t_object x_obj;
29 t_float x_f1;
30 t_float x_f2;
31} t_binop;
32
33/* ------------------ binop1: +, -, *, / ----------------------------- */
34
35static void *binop1_new(t_class *floatclass, t_floatarg f)
36{
37 t_binop *x = (t_binop *)pd_new(floatclass);
38 outlet_new(&x->x_obj, &s_float);
39 floatinlet_new(&x->x_obj, &x->x_f2);
40 x->x_f1 = 0;
41 x->x_f2 = f;
42 return (x);
43}
44
45/* --------------------- addition ------------------------------- */
46
47static t_class *binop1_plus_class;
48
49static void *binop1_plus_new(t_floatarg f)
50{
51 return (binop1_new(binop1_plus_class, f));
52}
53
54static void binop1_plus_bang(t_binop *x)
55{
56 outlet_float(x->x_obj.ob_outlet, x->x_f1 + x->x_f2);
57}
58
59static void binop1_plus_float(t_binop *x, t_float f)
60{
61 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) + x->x_f2);
62}
63
64/* --------------------- subtraction ------------------------------- */
65
66static t_class *binop1_minus_class;
67
68static void *binop1_minus_new(t_floatarg f)
69{
70 return (binop1_new(binop1_minus_class, f));
71}
72
73static void binop1_minus_bang(t_binop *x)
74{
75 outlet_float(x->x_obj.ob_outlet, x->x_f1 - x->x_f2);
76}
77
78static void binop1_minus_float(t_binop *x, t_float f)
79{
80 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) - x->x_f2);
81}
82
83/* --------------------- multiplication ------------------------------- */
84
85static t_class *binop1_times_class;
86
87static void *binop1_times_new(t_floatarg f)
88{
89 return (binop1_new(binop1_times_class, f));
90}
91
92static void binop1_times_bang(t_binop *x)
93{
94 outlet_float(x->x_obj.ob_outlet, x->x_f1 * x->x_f2);
95}
96
97static void binop1_times_float(t_binop *x, t_float f)
98{
99 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) * x->x_f2);
100}
101
102/* --------------------- division ------------------------------- */
103
104static t_class *binop1_div_class;
105
106static void *binop1_div_new(t_floatarg f)
107{
108 return (binop1_new(binop1_div_class, f));
109}
110
111static void binop1_div_bang(t_binop *x)
112{
113 outlet_float(x->x_obj.ob_outlet,
114 (x->x_f2 != 0 ? x->x_f1 / x->x_f2 : 0));
115}
116
117static void binop1_div_float(t_binop *x, t_float f)
118{
119 x->x_f1 = f;
120 outlet_float(x->x_obj.ob_outlet,
121 (x->x_f2 != 0 ? x->x_f1 / x->x_f2 : 0));
122}
123
124/* ------------------------ pow -------------------------------- */
125
126static t_class *binop1_pow_class;
127
128static void *binop1_pow_new(t_floatarg f)
129{
130 return (binop1_new(binop1_pow_class, f));
131}
132
133static void binop1_pow_bang(t_binop *x)
134{
135 outlet_float(x->x_obj.ob_outlet,
136 (x->x_f1 > 0 ? powf(x->x_f1, x->x_f2) : 0));
137}
138
139static void binop1_pow_float(t_binop *x, t_float f)
140{
141 x->x_f1 = f;
142 outlet_float(x->x_obj.ob_outlet,
143 (x->x_f1 > 0 ? powf(x->x_f1, x->x_f2) : 0));
144}
145
146/* ------------------------ max -------------------------------- */
147
148static t_class *binop1_max_class;
149
150static void *binop1_max_new(t_floatarg f)
151{
152 return (binop1_new(binop1_max_class, f));
153}
154
155static void binop1_max_bang(t_binop *x)
156{
157 outlet_float(x->x_obj.ob_outlet,
158 (x->x_f1 > x->x_f2 ? x->x_f1 : x->x_f2));
159}
160
161static void binop1_max_float(t_binop *x, t_float f)
162{
163 x->x_f1 = f;
164 outlet_float(x->x_obj.ob_outlet,
165 (x->x_f1 > x->x_f2 ? x->x_f1 : x->x_f2));
166}
167
168/* ------------------------ min -------------------------------- */
169
170static t_class *binop1_min_class;
171
172static void *binop1_min_new(t_floatarg f)
173{
174 return (binop1_new(binop1_min_class, f));
175}
176
177static void binop1_min_bang(t_binop *x)
178{
179 outlet_float(x->x_obj.ob_outlet,
180 (x->x_f1 < x->x_f2 ? x->x_f1 : x->x_f2));
181}
182
183static void binop1_min_float(t_binop *x, t_float f)
184{
185 x->x_f1 = f;
186 outlet_float(x->x_obj.ob_outlet,
187 (x->x_f1 < x->x_f2 ? x->x_f1 : x->x_f2));
188}
189
190/* ------------------ binop2: ==, !=, >, <, >=, <=. -------------------- */
191
192static void *binop2_new(t_class *floatclass, t_floatarg f)
193{
194 t_binop *x = (t_binop *)pd_new(floatclass);
195 outlet_new(&x->x_obj, &s_float);
196 floatinlet_new(&x->x_obj, &x->x_f2);
197 x->x_f1 = 0;
198 x->x_f2 = f;
199 return (x);
200}
201
202/* --------------------- == ------------------------------- */
203
204static t_class *binop2_ee_class;
205
206static void *binop2_ee_new(t_floatarg f)
207{
208 return (binop2_new(binop2_ee_class, f));
209}
210
211static void binop2_ee_bang(t_binop *x)
212{
213 outlet_float(x->x_obj.ob_outlet, x->x_f1 == x->x_f2);
214}
215
216static void binop2_ee_float(t_binop *x, t_float f)
217{
218 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) == x->x_f2);
219}
220
221/* --------------------- != ------------------------------- */
222
223static t_class *binop2_ne_class;
224
225static void *binop2_ne_new(t_floatarg f)
226{
227 return (binop2_new(binop2_ne_class, f));
228}
229
230static void binop2_ne_bang(t_binop *x)
231{
232 outlet_float(x->x_obj.ob_outlet, x->x_f1 != x->x_f2);
233}
234
235static void binop2_ne_float(t_binop *x, t_float f)
236{
237 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) != x->x_f2);
238}
239
240/* --------------------- > ------------------------------- */
241
242static t_class *binop2_gt_class;
243
244static void *binop2_gt_new(t_floatarg f)
245{
246 return (binop2_new(binop2_gt_class, f));
247}
248
249static void binop2_gt_bang(t_binop *x)
250{
251 outlet_float(x->x_obj.ob_outlet, x->x_f1 > x->x_f2);
252}
253
254static void binop2_gt_float(t_binop *x, t_float f)
255{
256 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) > x->x_f2);
257}
258
259/* --------------------- < ------------------------------- */
260
261static t_class *binop2_lt_class;
262
263static void *binop2_lt_new(t_floatarg f)
264{
265 return (binop2_new(binop2_lt_class, f));
266}
267
268static void binop2_lt_bang(t_binop *x)
269{
270 outlet_float(x->x_obj.ob_outlet, x->x_f1 < x->x_f2);
271}
272
273static void binop2_lt_float(t_binop *x, t_float f)
274{
275 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) < x->x_f2);
276}
277
278/* --------------------- >= ------------------------------- */
279
280static t_class *binop2_ge_class;
281
282static void *binop2_ge_new(t_floatarg f)
283{
284 return (binop2_new(binop2_ge_class, f));
285}
286
287static void binop2_ge_bang(t_binop *x)
288{
289 outlet_float(x->x_obj.ob_outlet, x->x_f1 >= x->x_f2);
290}
291
292static void binop2_ge_float(t_binop *x, t_float f)
293{
294 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) >= x->x_f2);
295}
296
297/* --------------------- <= ------------------------------- */
298
299static t_class *binop2_le_class;
300
301static void *binop2_le_new(t_floatarg f)
302{
303 return (binop2_new(binop2_le_class, f));
304}
305
306static void binop2_le_bang(t_binop *x)
307{
308 outlet_float(x->x_obj.ob_outlet, x->x_f1 <= x->x_f2);
309}
310
311static void binop2_le_float(t_binop *x, t_float f)
312{
313 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) <= x->x_f2);
314}
315
316/* ------------- binop3: &, |, &&, ||, <<, >>, %, mod, div ------------------ */
317
318static void *binop3_new(t_class *fixclass, t_floatarg f)
319{
320 t_binop *x = (t_binop *)pd_new(fixclass);
321 outlet_new(&x->x_obj, &s_float);
322 floatinlet_new(&x->x_obj, &x->x_f2);
323 x->x_f1 = 0;
324 x->x_f2 = f;
325 return (x);
326}
327
328/* --------------------------- & ---------------------------- */
329
330static t_class *binop3_ba_class;
331
332static void *binop3_ba_new(t_floatarg f)
333{
334 return (binop3_new(binop3_ba_class, f));
335}
336
337static void binop2_ba_bang(t_binop *x)
338{
339 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) & (int)(x->x_f2));
340}
341
342static void binop2_ba_float(t_binop *x, t_float f)
343{
344 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) & (int)(x->x_f2));
345}
346
347/* --------------------------- && ---------------------------- */
348
349static t_class *binop3_la_class;
350
351static void *binop3_la_new(t_floatarg f)
352{
353 return (binop3_new(binop3_la_class, f));
354}
355
356static void binop2_la_bang(t_binop *x)
357{
358 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) && (int)(x->x_f2));
359}
360
361static void binop2_la_float(t_binop *x, t_float f)
362{
363 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) && (int)(x->x_f2));
364}
365
366/* --------------------------- | ---------------------------- */
367
368static t_class *binop3_bo_class;
369
370static void *binop3_bo_new(t_floatarg f)
371{
372 return (binop3_new(binop3_bo_class, f));
373}
374
375static void binop2_bo_bang(t_binop *x)
376{
377 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) | (int)(x->x_f2));
378}
379
380static void binop2_bo_float(t_binop *x, t_float f)
381{
382 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) | (int)(x->x_f2));
383}
384
385/* --------------------------- || ---------------------------- */
386
387static t_class *binop3_lo_class;
388
389static void *binop3_lo_new(t_floatarg f)
390{
391 return (binop3_new(binop3_lo_class, f));
392}
393
394static void binop2_lo_bang(t_binop *x)
395{
396 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) || (int)(x->x_f2));
397}
398
399static void binop2_lo_float(t_binop *x, t_float f)
400{
401 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) || (int)(x->x_f2));
402}
403
404/* --------------------------- << ---------------------------- */
405
406static t_class *binop3_ls_class;
407
408static void *binop3_ls_new(t_floatarg f)
409{
410 return (binop3_new(binop3_ls_class, f));
411}
412
413static void binop2_ls_bang(t_binop *x)
414{
415 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) << (int)(x->x_f2));
416}
417
418static void binop2_ls_float(t_binop *x, t_float f)
419{
420 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) << (int)(x->x_f2));
421}
422
423/* --------------------------- >> ---------------------------- */
424
425static t_class *binop3_rs_class;
426
427static void *binop3_rs_new(t_floatarg f)
428{
429 return (binop3_new(binop3_rs_class, f));
430}
431
432static void binop2_rs_bang(t_binop *x)
433{
434 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) >> (int)(x->x_f2));
435}
436
437static void binop2_rs_float(t_binop *x, t_float f)
438{
439 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) >> (int)(x->x_f2));
440}
441
442/* --------------------------- % ---------------------------- */
443
444static t_class *binop3_pc_class;
445
446static void *binop3_pc_new(t_floatarg f)
447{
448 return (binop3_new(binop3_pc_class, f));
449}
450
451static void binop2_pc_bang(t_binop *x)
452{
453 int n2 = x->x_f2;
454 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) % (n2 ? n2 : 1));
455}
456
457static void binop2_pc_float(t_binop *x, t_float f)
458{
459 int n2 = x->x_f2;
460 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) % (n2 ? n2 : 1));
461}
462
463/* --------------------------- mod ---------------------------- */
464
465static t_class *binop3_mod_class;
466
467static void *binop3_mod_new(t_floatarg f)
468{
469 return (binop3_new(binop3_mod_class, f));
470}
471
472static void binop3_mod_bang(t_binop *x)
473{
474 int n2 = x->x_f2, result;
475 if (n2 < 0) n2 = -n2;
476 else if (!n2) n2 = 1;
477 result = ((int)(x->x_f1)) % n2;
478 if (result < 0) result += n2;
479 outlet_float(x->x_obj.ob_outlet, (t_float)result);
480}
481
482static void binop3_mod_float(t_binop *x, t_float f)
483{
484 x->x_f1 = f;
485 binop3_mod_bang(x);
486}
487
488/* --------------------------- div ---------------------------- */
489
490static t_class *binop3_div_class;
491
492static void *binop3_div_new(t_floatarg f)
493{
494 return (binop3_new(binop3_div_class, f));
495}
496
497static void binop3_div_bang(t_binop *x)
498{
499 int n1 = x->x_f1, n2 = x->x_f2, result;
500 if (n2 < 0) n2 = -n2;
501 else if (!n2) n2 = 1;
502 if (n1 < 0) n1 -= (n2-1);
503 result = n1 / n2;
504 outlet_float(x->x_obj.ob_outlet, (t_float)result);
505}
506
507static void binop3_div_float(t_binop *x, t_float f)
508{
509 x->x_f1 = f;
510 binop3_div_bang(x);
511}
512
513/* -------------------- mathematical functions ------------------ */
514
515static t_class *sin_class; /* ----------- sin --------------- */
516
517static void *sin_new(void)
518{
519 t_object *x = (t_object *)pd_new(sin_class);
520 outlet_new(x, &s_float);
521 return (x);
522}
523
524static void sin_float(t_object *x, t_float f)
525{
526 outlet_float(x->ob_outlet, sinf(f));
527}
528
529static t_class *cos_class; /* ----------- cos --------------- */
530
531static void *cos_new(void)
532{
533 t_object *x = (t_object *)pd_new(cos_class);
534 outlet_new(x, &s_float);
535 return (x);
536}
537
538static void cos_float(t_object *x, t_float f)
539{
540 outlet_float(x->ob_outlet, cosf(f));
541}
542
543static t_class *tan_class; /* ----------- tan --------------- */
544
545static void *tan_new(void)
546{
547 t_object *x = (t_object *)pd_new(tan_class);
548 outlet_new(x, &s_float);
549 return (x);
550}
551
552static void tan_float(t_object *x, t_float f)
553{
554 float c = cosf(f);
555 float t = (c == 0 ? 0 : sinf(f)/c);
556 outlet_float(x->ob_outlet, t);
557}
558
559static t_class *atan_class; /* ----------- atan --------------- */
560
561static void *atan_new(void)
562{
563 t_object *x = (t_object *)pd_new(atan_class);
564 outlet_new(x, &s_float);
565 return (x);
566}
567
568static void atan_float(t_object *x, t_float f)
569{
570 outlet_float(x->ob_outlet, atanf(f));
571}
572
573static t_class *atan2_class; /* ----------- atan2 --------------- */
574
575typedef struct _atan2
576{
577 t_object x_ob;
578 float x_y;
579} t_atan2;
580
581static void *atan2_new(void)
582{
583 t_atan2 *x = (t_atan2 *)pd_new(atan2_class);
584 floatinlet_new(&x->x_ob, &x->x_y);
585 outlet_new(&x->x_ob, &s_float);
586 return (x);
587}
588
589static void atan2_float(t_atan2 *x, t_float f)
590{
591 float r = (f == 0 && x->x_y == 0 ? 0 : atan2f(x->x_y, f));
592 outlet_float(x->x_ob.ob_outlet, r);
593}
594
595static t_class *sqrt_class; /* ----------- sqrt --------------- */
596
597static void *sqrt_new(void)
598{
599 t_object *x = (t_object *)pd_new(sqrt_class);
600 outlet_new(x, &s_float);
601 return (x);
602}
603
604static void sqrt_float(t_object *x, t_float f)
605{
606 float r = (f > 0 ? sqrtf(f) : 0);
607 outlet_float(x->ob_outlet, r);
608}
609
610static t_class *log_class; /* ----------- log --------------- */
611
612static void *log_new(void)
613{
614 t_object *x = (t_object *)pd_new(log_class);
615 outlet_new(x, &s_float);
616 return (x);
617}
618
619static void log_float(t_object *x, t_float f)
620{
621 float r = (f > 0 ? logf(f) : -1000);
622 outlet_float(x->ob_outlet, r);
623}
624
625
626static t_class *exp_class; /* ----------- exp --------------- */
627
628static void *exp_new(void)
629{
630 t_object *x = (t_object *)pd_new(exp_class);
631 outlet_new(x, &s_float);
632 return (x);
633}
634
635#define MAXLOG 87.3365
636static void exp_float(t_object *x, t_float f)
637{
638 float g;
639#ifdef MSW
640 char buf[10];
641#endif
642 if (f > MAXLOG) f = MAXLOG;
643 g = expf(f);
644 outlet_float(x->ob_outlet, g);
645}
646
647static t_class *abs_class; /* ----------- abs --------------- */
648
649static void *abs_new(void)
650{
651 t_object *x = (t_object *)pd_new(abs_class);
652 outlet_new(x, &s_float);
653 return (x);
654}
655
656static void abs_float(t_object *x, t_float f)
657{
658 outlet_float(x->ob_outlet, fabsf(f));
659}
660
661/* ------------------------ misc ------------------------ */
662
663static t_class *clip_class;
664
665typedef struct _clip
666{
667 t_object x_ob;
668 float x_f1;
669 float x_f2;
670} t_clip;
671
672static void *clip_new(t_floatarg f1, t_floatarg f2)
673{
674 t_clip *x = (t_clip *)pd_new(clip_class);
675 floatinlet_new(&x->x_ob, &x->x_f1);
676 floatinlet_new(&x->x_ob, &x->x_f2);
677 outlet_new(&x->x_ob, &s_float);
678 x->x_f1 = f1;
679 x->x_f2 = f2;
680 return (x);
681}
682
683static void clip_float(t_clip *x, t_float f)
684{
685 outlet_float(x->x_ob.ob_outlet, (f < x->x_f1 ? x->x_f1 : (
686 f > x->x_f2 ? x->x_f2 : f)));
687}
688
689static void clip_setup(void)
690{
691 clip_class = class_new(gensym("clip"), (t_newmethod)clip_new, 0,
692 sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
693 class_addfloat(clip_class, clip_float);
694}
695
696void x_arithmetic_setup(void)
697{
698 t_symbol *binop1_sym = gensym("operators");
699 t_symbol *binop23_sym = gensym("otherbinops");
700 t_symbol *math_sym = gensym("math");
701
702 binop1_plus_class = class_new(gensym("+"), (t_newmethod)binop1_plus_new, 0,
703 sizeof(t_binop), 0, A_DEFFLOAT, 0);
704 class_addbang(binop1_plus_class, binop1_plus_bang);
705 class_addfloat(binop1_plus_class, (t_method)binop1_plus_float);
706 class_sethelpsymbol(binop1_plus_class, binop1_sym);
707
708 binop1_minus_class = class_new(gensym("-"),
709 (t_newmethod)binop1_minus_new, 0,
710 sizeof(t_binop), 0, A_DEFFLOAT, 0);
711 class_addbang(binop1_minus_class, binop1_minus_bang);
712 class_addfloat(binop1_minus_class, (t_method)binop1_minus_float);
713 class_sethelpsymbol(binop1_minus_class, binop1_sym);
714
715 binop1_times_class = class_new(gensym("*"),
716 (t_newmethod)binop1_times_new, 0,
717 sizeof(t_binop), 0, A_DEFFLOAT, 0);
718 class_addbang(binop1_times_class, binop1_times_bang);
719 class_addfloat(binop1_times_class, (t_method)binop1_times_float);
720 class_sethelpsymbol(binop1_times_class, binop1_sym);
721
722 binop1_div_class = class_new(gensym("/"),
723 (t_newmethod)binop1_div_new, 0,
724 sizeof(t_binop), 0, A_DEFFLOAT, 0);
725 class_addbang(binop1_div_class, binop1_div_bang);
726 class_addfloat(binop1_div_class, (t_method)binop1_div_float);
727 class_sethelpsymbol(binop1_div_class, binop1_sym);
728
729 binop1_pow_class = class_new(gensym("pow"),
730 (t_newmethod)binop1_pow_new, 0,
731 sizeof(t_binop), 0, A_DEFFLOAT, 0);
732 class_addbang(binop1_pow_class, binop1_pow_bang);
733 class_addfloat(binop1_pow_class, (t_method)binop1_pow_float);
734 class_sethelpsymbol(binop1_pow_class, binop1_sym);
735
736 binop1_max_class = class_new(gensym("max"),
737 (t_newmethod)binop1_max_new, 0,
738 sizeof(t_binop), 0, A_DEFFLOAT, 0);
739 class_addbang(binop1_max_class, binop1_max_bang);
740 class_addfloat(binop1_max_class, (t_method)binop1_max_float);
741 class_sethelpsymbol(binop1_max_class, binop1_sym);
742
743 binop1_min_class = class_new(gensym("min"),
744 (t_newmethod)binop1_min_new, 0,
745 sizeof(t_binop), 0, A_DEFFLOAT, 0);
746 class_addbang(binop1_min_class, binop1_min_bang);
747 class_addfloat(binop1_min_class, (t_method)binop1_min_float);
748 class_sethelpsymbol(binop1_min_class, binop1_sym);
749
750 /* ------------------ binop2 ----------------------- */
751
752 binop2_ee_class = class_new(gensym("=="), (t_newmethod)binop2_ee_new, 0,
753 sizeof(t_binop), 0, A_DEFFLOAT, 0);
754 class_addbang(binop2_ee_class, binop2_ee_bang);
755 class_addfloat(binop2_ee_class, (t_method)binop2_ee_float);
756 class_sethelpsymbol(binop2_ee_class, binop23_sym);
757
758 binop2_ne_class = class_new(gensym("!="), (t_newmethod)binop2_ne_new, 0,
759 sizeof(t_binop), 0, A_DEFFLOAT, 0);
760 class_addbang(binop2_ne_class, binop2_ne_bang);
761 class_addfloat(binop2_ne_class, (t_method)binop2_ne_float);
762 class_sethelpsymbol(binop2_ne_class, binop23_sym);
763
764 binop2_gt_class = class_new(gensym(">"), (t_newmethod)binop2_gt_new, 0,
765 sizeof(t_binop), 0, A_DEFFLOAT, 0);
766 class_addbang(binop2_gt_class, binop2_gt_bang);
767 class_addfloat(binop2_gt_class, (t_method)binop2_gt_float);
768 class_sethelpsymbol(binop2_gt_class, binop23_sym);
769
770 binop2_lt_class = class_new(gensym("<"), (t_newmethod)binop2_lt_new, 0,
771 sizeof(t_binop), 0, A_DEFFLOAT, 0);
772 class_addbang(binop2_lt_class, binop2_lt_bang);
773 class_addfloat(binop2_lt_class, (t_method)binop2_lt_float);
774 class_sethelpsymbol(binop2_lt_class, binop23_sym);
775
776 binop2_ge_class = class_new(gensym(">="), (t_newmethod)binop2_ge_new, 0,
777 sizeof(t_binop), 0, A_DEFFLOAT, 0);
778 class_addbang(binop2_ge_class, binop2_ge_bang);
779 class_addfloat(binop2_ge_class, (t_method)binop2_ge_float);
780 class_sethelpsymbol(binop2_ge_class, binop23_sym);
781
782 binop2_le_class = class_new(gensym("<="), (t_newmethod)binop2_le_new, 0,
783 sizeof(t_binop), 0, A_DEFFLOAT, 0);
784 class_addbang(binop2_le_class, binop2_le_bang);
785 class_addfloat(binop2_le_class, (t_method)binop2_le_float);
786 class_sethelpsymbol(binop2_le_class, binop23_sym);
787
788 /* ------------------ binop3 ----------------------- */
789
790 binop3_ba_class = class_new(gensym("&"), (t_newmethod)binop3_ba_new, 0,
791 sizeof(t_binop), 0, A_DEFFLOAT, 0);
792 class_addbang(binop3_ba_class, binop2_ba_bang);
793 class_addfloat(binop3_ba_class, (t_method)binop2_ba_float);
794 class_sethelpsymbol(binop3_ba_class, binop23_sym);
795
796 binop3_la_class = class_new(gensym("&&"), (t_newmethod)binop3_la_new, 0,
797 sizeof(t_binop), 0, A_DEFFLOAT, 0);
798 class_addbang(binop3_la_class, binop2_la_bang);
799 class_addfloat(binop3_la_class, (t_method)binop2_la_float);
800 class_sethelpsymbol(binop3_la_class, binop23_sym);
801
802 binop3_bo_class = class_new(gensym("|"), (t_newmethod)binop3_bo_new, 0,
803 sizeof(t_binop), 0, A_DEFFLOAT, 0);
804 class_addbang(binop3_bo_class, binop2_bo_bang);
805 class_addfloat(binop3_bo_class, (t_method)binop2_bo_float);
806 class_sethelpsymbol(binop3_bo_class, binop23_sym);
807
808 binop3_lo_class = class_new(gensym("||"), (t_newmethod)binop3_lo_new, 0,
809 sizeof(t_binop), 0, A_DEFFLOAT, 0);
810 class_addbang(binop3_lo_class, binop2_lo_bang);
811 class_addfloat(binop3_lo_class, (t_method)binop2_lo_float);
812 class_sethelpsymbol(binop3_lo_class, binop23_sym);
813
814 binop3_ls_class = class_new(gensym("<<"), (t_newmethod)binop3_ls_new, 0,
815 sizeof(t_binop), 0, A_DEFFLOAT, 0);
816 class_addbang(binop3_ls_class, binop2_ls_bang);
817 class_addfloat(binop3_ls_class, (t_method)binop2_ls_float);
818 class_sethelpsymbol(binop3_ls_class, binop23_sym);
819
820 binop3_rs_class = class_new(gensym(">>"), (t_newmethod)binop3_rs_new, 0,
821 sizeof(t_binop), 0, A_DEFFLOAT, 0);
822 class_addbang(binop3_rs_class, binop2_rs_bang);
823 class_addfloat(binop3_rs_class, (t_method)binop2_rs_float);
824 class_sethelpsymbol(binop3_rs_class, binop23_sym);
825
826 binop3_pc_class = class_new(gensym("%"), (t_newmethod)binop3_pc_new, 0,
827 sizeof(t_binop), 0, A_DEFFLOAT, 0);
828 class_addbang(binop3_pc_class, binop2_pc_bang);
829 class_addfloat(binop3_pc_class, (t_method)binop2_pc_float);
830 class_sethelpsymbol(binop3_pc_class, binop23_sym);
831
832 binop3_mod_class = class_new(gensym("mod"), (t_newmethod)binop3_mod_new, 0,
833 sizeof(t_binop), 0, A_DEFFLOAT, 0);
834 class_addbang(binop3_mod_class, binop3_mod_bang);
835 class_addfloat(binop3_mod_class, (t_method)binop3_mod_float);
836 class_sethelpsymbol(binop3_mod_class, binop23_sym);
837
838 binop3_div_class = class_new(gensym("div"), (t_newmethod)binop3_div_new, 0,
839 sizeof(t_binop), 0, A_DEFFLOAT, 0);
840 class_addbang(binop3_div_class, binop3_div_bang);
841 class_addfloat(binop3_div_class, (t_method)binop3_div_float);
842 class_sethelpsymbol(binop3_div_class, binop23_sym);
843
844 /* ------------------- math functions --------------- */
845
846 sin_class = class_new(gensym("sin"), sin_new, 0,
847 sizeof(t_object), 0, 0);
848 class_addfloat(sin_class, (t_method)sin_float);
849 class_sethelpsymbol(sin_class, math_sym);
850
851 cos_class = class_new(gensym("cos"), cos_new, 0,
852 sizeof(t_object), 0, 0);
853 class_addfloat(cos_class, (t_method)cos_float);
854 class_sethelpsymbol(cos_class, math_sym);
855
856 tan_class = class_new(gensym("tan"), tan_new, 0,
857 sizeof(t_object), 0, 0);
858 class_addfloat(tan_class, (t_method)tan_float);
859 class_sethelpsymbol(tan_class, math_sym);
860
861 atan_class = class_new(gensym("atan"), atan_new, 0,
862 sizeof(t_object), 0, 0);
863 class_addfloat(atan_class, (t_method)atan_float);
864 class_sethelpsymbol(atan_class, math_sym);
865
866 atan2_class = class_new(gensym("atan2"), atan2_new, 0,
867 sizeof(t_atan2), 0, 0);
868 class_addfloat(atan2_class, (t_method)atan2_float);
869 class_sethelpsymbol(atan2_class, math_sym);
870
871 sqrt_class = class_new(gensym("sqrt"), sqrt_new, 0,
872 sizeof(t_object), 0, 0);
873 class_addfloat(sqrt_class, (t_method)sqrt_float);
874 class_sethelpsymbol(sqrt_class, math_sym);
875
876 log_class = class_new(gensym("log"), log_new, 0,
877 sizeof(t_object), 0, 0);
878 class_addfloat(log_class, (t_method)log_float);
879 class_sethelpsymbol(log_class, math_sym);
880
881 exp_class = class_new(gensym("exp"), exp_new, 0,
882 sizeof(t_object), 0, 0);
883 class_addfloat(exp_class, (t_method)exp_float);
884 class_sethelpsymbol(exp_class, math_sym);
885
886 abs_class = class_new(gensym("abs"), abs_new, 0,
887 sizeof(t_object), 0, 0);
888 class_addfloat(abs_class, (t_method)abs_float);
889 class_sethelpsymbol(abs_class, math_sym);
890
891/* ------------------------ misc ------------------------ */
892
893 clip_setup();
894}
895
896
897/* Copyright (c) 1997-1999 Miller Puckette.
898* For information on usage and redistribution, and for a DISCLAIMER OF ALL
899* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
900
901/* arithmetic: binops ala C language. The 4 functions and relationals are
902done on floats; the logical and bitwise binops convert their
903inputs to int and their outputs back to float. */
904
905#include "m_pd.h"
906#include <math.h>
907
908
909/* MSW and OSX don't appear to have single-precision ANSI math */
910
911#define sinf sin
912#define cosf cos
913#define atanf atan
914#define atan2f atan2
915#define sqrtf sqrt
916#define logf log
917#define expf exp
918#define fabsf fabs
919#define powf pow
920
921
922typedef struct _binop
923{
924 t_object x_obj;
925 t_float x_f1;
926 t_float x_f2;
927} t_binop;
928
929/* ------------------ binop1: +, -, *, / ----------------------------- */
930
931static void *binop1_new(t_class *floatclass, t_floatarg f)
932{
933 t_binop *x = (t_binop *)pd_new(floatclass);
934 outlet_new(&x->x_obj, &s_float);
935 floatinlet_new(&x->x_obj, &x->x_f2);
936 x->x_f1 = 0;
937 x->x_f2 = f;
938 return (x);
939}
940
941/* --------------------- addition ------------------------------- */
942
943static t_class *binop1_plus_class;
944
945static void *binop1_plus_new(t_floatarg f)
946{
947 return (binop1_new(binop1_plus_class, f));
948}
949
950static void binop1_plus_bang(t_binop *x)
951{
952 outlet_float(x->x_obj.ob_outlet, x->x_f1 + x->x_f2);
953}
954
955static void binop1_plus_float(t_binop *x, t_float f)
956{
957 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) + x->x_f2);
958}
959
960/* --------------------- subtraction ------------------------------- */
961
962static t_class *binop1_minus_class;
963
964static void *binop1_minus_new(t_floatarg f)
965{
966 return (binop1_new(binop1_minus_class, f));
967}
968
969static void binop1_minus_bang(t_binop *x)
970{
971 outlet_float(x->x_obj.ob_outlet, x->x_f1 - x->x_f2);
972}
973
974static void binop1_minus_float(t_binop *x, t_float f)
975{
976 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) - x->x_f2);
977}
978
979/* --------------------- multiplication ------------------------------- */
980
981static t_class *binop1_times_class;
982
983static void *binop1_times_new(t_floatarg f)
984{
985 return (binop1_new(binop1_times_class, f));
986}
987
988static void binop1_times_bang(t_binop *x)
989{
990 outlet_float(x->x_obj.ob_outlet, x->x_f1 * x->x_f2);
991}
992
993static void binop1_times_float(t_binop *x, t_float f)
994{
995 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) * x->x_f2);
996}
997
998/* --------------------- division ------------------------------- */
999
1000static t_class *binop1_div_class;
1001
1002static void *binop1_div_new(t_floatarg f)
1003{
1004 return (binop1_new(binop1_div_class, f));
1005}
1006
1007static void binop1_div_bang(t_binop *x)
1008{
1009 outlet_float(x->x_obj.ob_outlet,
1010 (x->x_f2 != 0 ? x->x_f1 / x->x_f2 : 0));
1011}
1012
1013static void binop1_div_float(t_binop *x, t_float f)
1014{
1015 x->x_f1 = f;
1016 outlet_float(x->x_obj.ob_outlet,
1017 (x->x_f2 != 0 ? x->x_f1 / x->x_f2 : 0));
1018}
1019
1020/* ------------------------ pow -------------------------------- */
1021
1022static t_class *binop1_pow_class;
1023
1024static void *binop1_pow_new(t_floatarg f)
1025{
1026 return (binop1_new(binop1_pow_class, f));
1027}
1028
1029static void binop1_pow_bang(t_binop *x)
1030{
1031 outlet_float(x->x_obj.ob_outlet,
1032 (x->x_f1 > 0 ? powf(x->x_f1, x->x_f2) : 0));
1033}
1034
1035static void binop1_pow_float(t_binop *x, t_float f)
1036{
1037 x->x_f1 = f;
1038 outlet_float(x->x_obj.ob_outlet,
1039 (x->x_f1 > 0 ? powf(x->x_f1, x->x_f2) : 0));
1040}
1041
1042/* ------------------------ max -------------------------------- */
1043
1044static t_class *binop1_max_class;
1045
1046static void *binop1_max_new(t_floatarg f)
1047{
1048 return (binop1_new(binop1_max_class, f));
1049}
1050
1051static void binop1_max_bang(t_binop *x)
1052{
1053 outlet_float(x->x_obj.ob_outlet,
1054 (x->x_f1 > x->x_f2 ? x->x_f1 : x->x_f2));
1055}
1056
1057static void binop1_max_float(t_binop *x, t_float f)
1058{
1059 x->x_f1 = f;
1060 outlet_float(x->x_obj.ob_outlet,
1061 (x->x_f1 > x->x_f2 ? x->x_f1 : x->x_f2));
1062}
1063
1064/* ------------------------ min -------------------------------- */
1065
1066static t_class *binop1_min_class;
1067
1068static void *binop1_min_new(t_floatarg f)
1069{
1070 return (binop1_new(binop1_min_class, f));
1071}
1072
1073static void binop1_min_bang(t_binop *x)
1074{
1075 outlet_float(x->x_obj.ob_outlet,
1076 (x->x_f1 < x->x_f2 ? x->x_f1 : x->x_f2));
1077}
1078
1079static void binop1_min_float(t_binop *x, t_float f)
1080{
1081 x->x_f1 = f;
1082 outlet_float(x->x_obj.ob_outlet,
1083 (x->x_f1 < x->x_f2 ? x->x_f1 : x->x_f2));
1084}
1085
1086/* ------------------ binop2: ==, !=, >, <, >=, <=. -------------------- */
1087
1088static void *binop2_new(t_class *floatclass, t_floatarg f)
1089{
1090 t_binop *x = (t_binop *)pd_new(floatclass);
1091 outlet_new(&x->x_obj, &s_float);
1092 floatinlet_new(&x->x_obj, &x->x_f2);
1093 x->x_f1 = 0;
1094 x->x_f2 = f;
1095 return (x);
1096}
1097
1098/* --------------------- == ------------------------------- */
1099
1100static t_class *binop2_ee_class;
1101
1102static void *binop2_ee_new(t_floatarg f)
1103{
1104 return (binop2_new(binop2_ee_class, f));
1105}
1106
1107static void binop2_ee_bang(t_binop *x)
1108{
1109 outlet_float(x->x_obj.ob_outlet, x->x_f1 == x->x_f2);
1110}
1111
1112static void binop2_ee_float(t_binop *x, t_float f)
1113{
1114 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) == x->x_f2);
1115}
1116
1117/* --------------------- != ------------------------------- */
1118
1119static t_class *binop2_ne_class;
1120
1121static void *binop2_ne_new(t_floatarg f)
1122{
1123 return (binop2_new(binop2_ne_class, f));
1124}
1125
1126static void binop2_ne_bang(t_binop *x)
1127{
1128 outlet_float(x->x_obj.ob_outlet, x->x_f1 != x->x_f2);
1129}
1130
1131static void binop2_ne_float(t_binop *x, t_float f)
1132{
1133 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) != x->x_f2);
1134}
1135
1136/* --------------------- > ------------------------------- */
1137
1138static t_class *binop2_gt_class;
1139
1140static void *binop2_gt_new(t_floatarg f)
1141{
1142 return (binop2_new(binop2_gt_class, f));
1143}
1144
1145static void binop2_gt_bang(t_binop *x)
1146{
1147 outlet_float(x->x_obj.ob_outlet, x->x_f1 > x->x_f2);
1148}
1149
1150static void binop2_gt_float(t_binop *x, t_float f)
1151{
1152 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) > x->x_f2);
1153}
1154
1155/* --------------------- < ------------------------------- */
1156
1157static t_class *binop2_lt_class;
1158
1159static void *binop2_lt_new(t_floatarg f)
1160{
1161 return (binop2_new(binop2_lt_class, f));
1162}
1163
1164static void binop2_lt_bang(t_binop *x)
1165{
1166 outlet_float(x->x_obj.ob_outlet, x->x_f1 < x->x_f2);
1167}
1168
1169static void binop2_lt_float(t_binop *x, t_float f)
1170{
1171 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) < x->x_f2);
1172}
1173
1174/* --------------------- >= ------------------------------- */
1175
1176static t_class *binop2_ge_class;
1177
1178static void *binop2_ge_new(t_floatarg f)
1179{
1180 return (binop2_new(binop2_ge_class, f));
1181}
1182
1183static void binop2_ge_bang(t_binop *x)
1184{
1185 outlet_float(x->x_obj.ob_outlet, x->x_f1 >= x->x_f2);
1186}
1187
1188static void binop2_ge_float(t_binop *x, t_float f)
1189{
1190 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) >= x->x_f2);
1191}
1192
1193/* --------------------- <= ------------------------------- */
1194
1195static t_class *binop2_le_class;
1196
1197static void *binop2_le_new(t_floatarg f)
1198{
1199 return (binop2_new(binop2_le_class, f));
1200}
1201
1202static void binop2_le_bang(t_binop *x)
1203{
1204 outlet_float(x->x_obj.ob_outlet, x->x_f1 <= x->x_f2);
1205}
1206
1207static void binop2_le_float(t_binop *x, t_float f)
1208{
1209 outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) <= x->x_f2);
1210}
1211
1212/* ------------- binop3: &, |, &&, ||, <<, >>, %, mod, div ------------------ */
1213
1214static void *binop3_new(t_class *fixclass, t_floatarg f)
1215{
1216 t_binop *x = (t_binop *)pd_new(fixclass);
1217 outlet_new(&x->x_obj, &s_float);
1218 floatinlet_new(&x->x_obj, &x->x_f2);
1219 x->x_f1 = 0;
1220 x->x_f2 = f;
1221 return (x);
1222}
1223
1224/* --------------------------- & ---------------------------- */
1225
1226static t_class *binop3_ba_class;
1227
1228static void *binop3_ba_new(t_floatarg f)
1229{
1230 return (binop3_new(binop3_ba_class, f));
1231}
1232
1233static void binop2_ba_bang(t_binop *x)
1234{
1235 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) & (int)(x->x_f2));
1236}
1237
1238static void binop2_ba_float(t_binop *x, t_float f)
1239{
1240 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) & (int)(x->x_f2));
1241}
1242
1243/* --------------------------- && ---------------------------- */
1244
1245static t_class *binop3_la_class;
1246
1247static void *binop3_la_new(t_floatarg f)
1248{
1249 return (binop3_new(binop3_la_class, f));
1250}
1251
1252static void binop2_la_bang(t_binop *x)
1253{
1254 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) && (int)(x->x_f2));
1255}
1256
1257static void binop2_la_float(t_binop *x, t_float f)
1258{
1259 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) && (int)(x->x_f2));
1260}
1261
1262/* --------------------------- | ---------------------------- */
1263
1264static t_class *binop3_bo_class;
1265
1266static void *binop3_bo_new(t_floatarg f)
1267{
1268 return (binop3_new(binop3_bo_class, f));
1269}
1270
1271static void binop2_bo_bang(t_binop *x)
1272{
1273 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) | (int)(x->x_f2));
1274}
1275
1276static void binop2_bo_float(t_binop *x, t_float f)
1277{
1278 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) | (int)(x->x_f2));
1279}
1280
1281/* --------------------------- || ---------------------------- */
1282
1283static t_class *binop3_lo_class;
1284
1285static void *binop3_lo_new(t_floatarg f)
1286{
1287 return (binop3_new(binop3_lo_class, f));
1288}
1289
1290static void binop2_lo_bang(t_binop *x)
1291{
1292 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) || (int)(x->x_f2));
1293}
1294
1295static void binop2_lo_float(t_binop *x, t_float f)
1296{
1297 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) || (int)(x->x_f2));
1298}
1299
1300/* --------------------------- << ---------------------------- */
1301
1302static t_class *binop3_ls_class;
1303
1304static void *binop3_ls_new(t_floatarg f)
1305{
1306 return (binop3_new(binop3_ls_class, f));
1307}
1308
1309static void binop2_ls_bang(t_binop *x)
1310{
1311 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) << (int)(x->x_f2));
1312}
1313
1314static void binop2_ls_float(t_binop *x, t_float f)
1315{
1316 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) << (int)(x->x_f2));
1317}
1318
1319/* --------------------------- >> ---------------------------- */
1320
1321static t_class *binop3_rs_class;
1322
1323static void *binop3_rs_new(t_floatarg f)
1324{
1325 return (binop3_new(binop3_rs_class, f));
1326}
1327
1328static void binop2_rs_bang(t_binop *x)
1329{
1330 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) >> (int)(x->x_f2));
1331}
1332
1333static void binop2_rs_float(t_binop *x, t_float f)
1334{
1335 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) >> (int)(x->x_f2));
1336}
1337
1338/* --------------------------- % ---------------------------- */
1339
1340static t_class *binop3_pc_class;
1341
1342static void *binop3_pc_new(t_floatarg f)
1343{
1344 return (binop3_new(binop3_pc_class, f));
1345}
1346
1347static void binop2_pc_bang(t_binop *x)
1348{
1349 int n2 = x->x_f2;
1350 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) % (n2 ? n2 : 1));
1351}
1352
1353static void binop2_pc_float(t_binop *x, t_float f)
1354{
1355 int n2 = x->x_f2;
1356 outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) % (n2 ? n2 : 1));
1357}
1358
1359/* --------------------------- mod ---------------------------- */
1360
1361static t_class *binop3_mod_class;
1362
1363static void *binop3_mod_new(t_floatarg f)
1364{
1365 return (binop3_new(binop3_mod_class, f));
1366}
1367
1368static void binop3_mod_bang(t_binop *x)
1369{
1370 int n2 = x->x_f2, result;
1371 if (n2 < 0) n2 = -n2;
1372 else if (!n2) n2 = 1;
1373 result = ((int)(x->x_f1)) % n2;
1374 if (result < 0) result += n2;
1375 outlet_float(x->x_obj.ob_outlet, (t_float)result);
1376}
1377
1378static void binop3_mod_float(t_binop *x, t_float f)
1379{
1380 x->x_f1 = f;
1381 binop3_mod_bang(x);
1382}
1383
1384/* --------------------------- div ---------------------------- */
1385
1386static t_class *binop3_div_class;
1387
1388static void *binop3_div_new(t_floatarg f)
1389{
1390 return (binop3_new(binop3_div_class, f));
1391}
1392
1393static void binop3_div_bang(t_binop *x)
1394{
1395 int n1 = x->x_f1, n2 = x->x_f2, result;
1396 if (n2 < 0) n2 = -n2;
1397 else if (!n2) n2 = 1;
1398 if (n1 < 0) n1 -= (n2-1);
1399 result = n1 / n2;
1400 outlet_float(x->x_obj.ob_outlet, (t_float)result);
1401}
1402
1403static void binop3_div_float(t_binop *x, t_float f)
1404{
1405 x->x_f1 = f;
1406 binop3_div_bang(x);
1407}
1408
1409/* -------------------- mathematical functions ------------------ */
1410
1411static t_class *sin_class; /* ----------- sin --------------- */
1412
1413static void *sin_new(void)
1414{
1415 t_object *x = (t_object *)pd_new(sin_class);
1416 outlet_new(x, &s_float);
1417 return (x);
1418}
1419
1420static void sin_float(t_object *x, t_float f)
1421{
1422 outlet_float(x->ob_outlet, sinf(f));
1423}
1424
1425static t_class *cos_class; /* ----------- cos --------------- */
1426
1427static void *cos_new(void)
1428{
1429 t_object *x = (t_object *)pd_new(cos_class);
1430 outlet_new(x, &s_float);
1431 return (x);
1432}
1433
1434static void cos_float(t_object *x, t_float f)
1435{
1436 outlet_float(x->ob_outlet, cosf(f));
1437}
1438
1439static t_class *tan_class; /* ----------- tan --------------- */
1440
1441static void *tan_new(void)
1442{
1443 t_object *x = (t_object *)pd_new(tan_class);
1444 outlet_new(x, &s_float);
1445 return (x);
1446}
1447
1448static void tan_float(t_object *x, t_float f)
1449{
1450 float c = cosf(f);
1451 float t = (c == 0 ? 0 : sinf(f)/c);
1452 outlet_float(x->ob_outlet, t);
1453}
1454
1455static t_class *atan_class; /* ----------- atan --------------- */
1456
1457static void *atan_new(void)
1458{
1459 t_object *x = (t_object *)pd_new(atan_class);
1460 outlet_new(x, &s_float);
1461 return (x);
1462}
1463
1464static void atan_float(t_object *x, t_float f)
1465{
1466 outlet_float(x->ob_outlet, atanf(f));
1467}
1468
1469static t_class *atan2_class; /* ----------- atan2 --------------- */
1470
1471typedef struct _atan2
1472{
1473 t_object x_ob;
1474 float x_y;
1475} t_atan2;
1476
1477static void *atan2_new(void)
1478{
1479 t_atan2 *x = (t_atan2 *)pd_new(atan2_class);
1480 floatinlet_new(&x->x_ob, &x->x_y);
1481 outlet_new(&x->x_ob, &s_float);
1482 return (x);
1483}
1484
1485static void atan2_float(t_atan2 *x, t_float f)
1486{
1487 float r = (f == 0 && x->x_y == 0 ? 0 : atan2f(x->x_y, f));
1488 outlet_float(x->x_ob.ob_outlet, r);
1489}
1490
1491static t_class *sqrt_class; /* ----------- sqrt --------------- */
1492
1493static void *sqrt_new(void)
1494{
1495 t_object *x = (t_object *)pd_new(sqrt_class);
1496 outlet_new(x, &s_float);
1497 return (x);
1498}
1499
1500static void sqrt_float(t_object *x, t_float f)
1501{
1502 float r = (f > 0 ? sqrtf(f) : 0);
1503 outlet_float(x->ob_outlet, r);
1504}
1505
1506static t_class *log_class; /* ----------- log --------------- */
1507
1508static void *log_new(void)
1509{
1510 t_object *x = (t_object *)pd_new(log_class);
1511 outlet_new(x, &s_float);
1512 return (x);
1513}
1514
1515static void log_float(t_object *x, t_float f)
1516{
1517 float r = (f > 0 ? logf(f) : -1000);
1518 outlet_float(x->ob_outlet, r);
1519}
1520
1521
1522static t_class *exp_class; /* ----------- exp --------------- */
1523
1524static void *exp_new(void)
1525{
1526 t_object *x = (t_object *)pd_new(exp_class);
1527 outlet_new(x, &s_float);
1528 return (x);
1529}
1530
1531#define MAXLOG 87.3365
1532static void exp_float(t_object *x, t_float f)
1533{
1534 float g;
1535#ifdef MSW
1536 char buf[10];
1537#endif
1538 if (f > MAXLOG) f = MAXLOG;
1539 g = expf(f);
1540 outlet_float(x->ob_outlet, g);
1541}
1542
1543static t_class *abs_class; /* ----------- abs --------------- */
1544
1545static void *abs_new(void)
1546{
1547 t_object *x = (t_object *)pd_new(abs_class);
1548 outlet_new(x, &s_float);
1549 return (x);
1550}
1551
1552static void abs_float(t_object *x, t_float f)
1553{
1554 outlet_float(x->ob_outlet, fabsf(f));
1555}
1556
1557/* ------------------------ misc ------------------------ */
1558
1559static t_class *clip_class;
1560
1561typedef struct _clip
1562{
1563 t_object x_ob;
1564 float x_f1;
1565 float x_f2;
1566} t_clip;
1567
1568static void *clip_new(t_floatarg f1, t_floatarg f2)
1569{
1570 t_clip *x = (t_clip *)pd_new(clip_class);
1571 floatinlet_new(&x->x_ob, &x->x_f1);
1572 floatinlet_new(&x->x_ob, &x->x_f2);
1573 outlet_new(&x->x_ob, &s_float);
1574 x->x_f1 = f1;
1575 x->x_f2 = f2;
1576 return (x);
1577}
1578
1579static void clip_float(t_clip *x, t_float f)
1580{
1581 outlet_float(x->x_ob.ob_outlet, (f < x->x_f1 ? x->x_f1 : (
1582 f > x->x_f2 ? x->x_f2 : f)));
1583}
1584
1585static void clip_setup(void)
1586{
1587 clip_class = class_new(gensym("clip"), (t_newmethod)clip_new, 0,
1588 sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
1589 class_addfloat(clip_class, clip_float);
1590}
1591
1592void x_arithmetic_setup(void)
1593{
1594 t_symbol *binop1_sym = gensym("operators");
1595 t_symbol *binop23_sym = gensym("otherbinops");
1596 t_symbol *math_sym = gensym("math");
1597
1598 binop1_plus_class = class_new(gensym("+"), (t_newmethod)binop1_plus_new, 0,
1599 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1600 class_addbang(binop1_plus_class, binop1_plus_bang);
1601 class_addfloat(binop1_plus_class, (t_method)binop1_plus_float);
1602 class_sethelpsymbol(binop1_plus_class, binop1_sym);
1603
1604 binop1_minus_class = class_new(gensym("-"),
1605 (t_newmethod)binop1_minus_new, 0,
1606 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1607 class_addbang(binop1_minus_class, binop1_minus_bang);
1608 class_addfloat(binop1_minus_class, (t_method)binop1_minus_float);
1609 class_sethelpsymbol(binop1_minus_class, binop1_sym);
1610
1611 binop1_times_class = class_new(gensym("*"),
1612 (t_newmethod)binop1_times_new, 0,
1613 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1614 class_addbang(binop1_times_class, binop1_times_bang);
1615 class_addfloat(binop1_times_class, (t_method)binop1_times_float);
1616 class_sethelpsymbol(binop1_times_class, binop1_sym);
1617
1618 binop1_div_class = class_new(gensym("/"),
1619 (t_newmethod)binop1_div_new, 0,
1620 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1621 class_addbang(binop1_div_class, binop1_div_bang);
1622 class_addfloat(binop1_div_class, (t_method)binop1_div_float);
1623 class_sethelpsymbol(binop1_div_class, binop1_sym);
1624
1625 binop1_pow_class = class_new(gensym("pow"),
1626 (t_newmethod)binop1_pow_new, 0,
1627 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1628 class_addbang(binop1_pow_class, binop1_pow_bang);
1629 class_addfloat(binop1_pow_class, (t_method)binop1_pow_float);
1630 class_sethelpsymbol(binop1_pow_class, binop1_sym);
1631
1632 binop1_max_class = class_new(gensym("max"),
1633 (t_newmethod)binop1_max_new, 0,
1634 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1635 class_addbang(binop1_max_class, binop1_max_bang);
1636 class_addfloat(binop1_max_class, (t_method)binop1_max_float);
1637 class_sethelpsymbol(binop1_max_class, binop1_sym);
1638
1639 binop1_min_class = class_new(gensym("min"),
1640 (t_newmethod)binop1_min_new, 0,
1641 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1642 class_addbang(binop1_min_class, binop1_min_bang);
1643 class_addfloat(binop1_min_class, (t_method)binop1_min_float);
1644 class_sethelpsymbol(binop1_min_class, binop1_sym);
1645
1646 /* ------------------ binop2 ----------------------- */
1647
1648 binop2_ee_class = class_new(gensym("=="), (t_newmethod)binop2_ee_new, 0,
1649 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1650 class_addbang(binop2_ee_class, binop2_ee_bang);
1651 class_addfloat(binop2_ee_class, (t_method)binop2_ee_float);
1652 class_sethelpsymbol(binop2_ee_class, binop23_sym);
1653
1654 binop2_ne_class = class_new(gensym("!="), (t_newmethod)binop2_ne_new, 0,
1655 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1656 class_addbang(binop2_ne_class, binop2_ne_bang);
1657 class_addfloat(binop2_ne_class, (t_method)binop2_ne_float);
1658 class_sethelpsymbol(binop2_ne_class, binop23_sym);
1659
1660 binop2_gt_class = class_new(gensym(">"), (t_newmethod)binop2_gt_new, 0,
1661 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1662 class_addbang(binop2_gt_class, binop2_gt_bang);
1663 class_addfloat(binop2_gt_class, (t_method)binop2_gt_float);
1664 class_sethelpsymbol(binop2_gt_class, binop23_sym);
1665
1666 binop2_lt_class = class_new(gensym("<"), (t_newmethod)binop2_lt_new, 0,
1667 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1668 class_addbang(binop2_lt_class, binop2_lt_bang);
1669 class_addfloat(binop2_lt_class, (t_method)binop2_lt_float);
1670 class_sethelpsymbol(binop2_lt_class, binop23_sym);
1671
1672 binop2_ge_class = class_new(gensym(">="), (t_newmethod)binop2_ge_new, 0,
1673 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1674 class_addbang(binop2_ge_class, binop2_ge_bang);
1675 class_addfloat(binop2_ge_class, (t_method)binop2_ge_float);
1676 class_sethelpsymbol(binop2_ge_class, binop23_sym);
1677
1678 binop2_le_class = class_new(gensym("<="), (t_newmethod)binop2_le_new, 0,
1679 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1680 class_addbang(binop2_le_class, binop2_le_bang);
1681 class_addfloat(binop2_le_class, (t_method)binop2_le_float);
1682 class_sethelpsymbol(binop2_le_class, binop23_sym);
1683
1684 /* ------------------ binop3 ----------------------- */
1685
1686 binop3_ba_class = class_new(gensym("&"), (t_newmethod)binop3_ba_new, 0,
1687 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1688 class_addbang(binop3_ba_class, binop2_ba_bang);
1689 class_addfloat(binop3_ba_class, (t_method)binop2_ba_float);
1690 class_sethelpsymbol(binop3_ba_class, binop23_sym);
1691
1692 binop3_la_class = class_new(gensym("&&"), (t_newmethod)binop3_la_new, 0,
1693 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1694 class_addbang(binop3_la_class, binop2_la_bang);
1695 class_addfloat(binop3_la_class, (t_method)binop2_la_float);
1696 class_sethelpsymbol(binop3_la_class, binop23_sym);
1697
1698 binop3_bo_class = class_new(gensym("|"), (t_newmethod)binop3_bo_new, 0,
1699 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1700 class_addbang(binop3_bo_class, binop2_bo_bang);
1701 class_addfloat(binop3_bo_class, (t_method)binop2_bo_float);
1702 class_sethelpsymbol(binop3_bo_class, binop23_sym);
1703
1704 binop3_lo_class = class_new(gensym("||"), (t_newmethod)binop3_lo_new, 0,
1705 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1706 class_addbang(binop3_lo_class, binop2_lo_bang);
1707 class_addfloat(binop3_lo_class, (t_method)binop2_lo_float);
1708 class_sethelpsymbol(binop3_lo_class, binop23_sym);
1709
1710 binop3_ls_class = class_new(gensym("<<"), (t_newmethod)binop3_ls_new, 0,
1711 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1712 class_addbang(binop3_ls_class, binop2_ls_bang);
1713 class_addfloat(binop3_ls_class, (t_method)binop2_ls_float);
1714 class_sethelpsymbol(binop3_ls_class, binop23_sym);
1715
1716 binop3_rs_class = class_new(gensym(">>"), (t_newmethod)binop3_rs_new, 0,
1717 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1718 class_addbang(binop3_rs_class, binop2_rs_bang);
1719 class_addfloat(binop3_rs_class, (t_method)binop2_rs_float);
1720 class_sethelpsymbol(binop3_rs_class, binop23_sym);
1721
1722 binop3_pc_class = class_new(gensym("%"), (t_newmethod)binop3_pc_new, 0,
1723 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1724 class_addbang(binop3_pc_class, binop2_pc_bang);
1725 class_addfloat(binop3_pc_class, (t_method)binop2_pc_float);
1726 class_sethelpsymbol(binop3_pc_class, binop23_sym);
1727
1728 binop3_mod_class = class_new(gensym("mod"), (t_newmethod)binop3_mod_new, 0,
1729 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1730 class_addbang(binop3_mod_class, binop3_mod_bang);
1731 class_addfloat(binop3_mod_class, (t_method)binop3_mod_float);
1732 class_sethelpsymbol(binop3_mod_class, binop23_sym);
1733
1734 binop3_div_class = class_new(gensym("div"), (t_newmethod)binop3_div_new, 0,
1735 sizeof(t_binop), 0, A_DEFFLOAT, 0);
1736 class_addbang(binop3_div_class, binop3_div_bang);
1737 class_addfloat(binop3_div_class, (t_method)binop3_div_float);
1738 class_sethelpsymbol(binop3_div_class, binop23_sym);
1739
1740 /* ------------------- math functions --------------- */
1741
1742 sin_class = class_new(gensym("sin"), sin_new, 0,
1743 sizeof(t_object), 0, 0);
1744 class_addfloat(sin_class, (t_method)sin_float);
1745 class_sethelpsymbol(sin_class, math_sym);
1746
1747 cos_class = class_new(gensym("cos"), cos_new, 0,
1748 sizeof(t_object), 0, 0);
1749 class_addfloat(cos_class, (t_method)cos_float);
1750 class_sethelpsymbol(cos_class, math_sym);
1751
1752 tan_class = class_new(gensym("tan"), tan_new, 0,
1753 sizeof(t_object), 0, 0);
1754 class_addfloat(tan_class, (t_method)tan_float);
1755 class_sethelpsymbol(tan_class, math_sym);
1756
1757 atan_class = class_new(gensym("atan"), atan_new, 0,
1758 sizeof(t_object), 0, 0);
1759 class_addfloat(atan_class, (t_method)atan_float);
1760 class_sethelpsymbol(atan_class, math_sym);
1761
1762 atan2_class = class_new(gensym("atan2"), atan2_new, 0,
1763 sizeof(t_atan2), 0, 0);
1764 class_addfloat(atan2_class, (t_method)atan2_float);
1765 class_sethelpsymbol(atan2_class, math_sym);
1766
1767 sqrt_class = class_new(gensym("sqrt"), sqrt_new, 0,
1768 sizeof(t_object), 0, 0);
1769 class_addfloat(sqrt_class, (t_method)sqrt_float);
1770 class_sethelpsymbol(sqrt_class, math_sym);
1771
1772 log_class = class_new(gensym("log"), log_new, 0,
1773 sizeof(t_object), 0, 0);
1774 class_addfloat(log_class, (t_method)log_float);
1775 class_sethelpsymbol(log_class, math_sym);
1776
1777 exp_class = class_new(gensym("exp"), exp_new, 0,
1778 sizeof(t_object), 0, 0);
1779 class_addfloat(exp_class, (t_method)exp_float);
1780 class_sethelpsymbol(exp_class, math_sym);
1781
1782 abs_class = class_new(gensym("abs"), abs_new, 0,
1783 sizeof(t_object), 0, 0);
1784 class_addfloat(abs_class, (t_method)abs_float);
1785 class_sethelpsymbol(abs_class, math_sym);
1786
1787/* ------------------------ misc ------------------------ */
1788
1789 clip_setup();
1790}
1791
1792
diff --git a/apps/plugins/pdbox/PDa/src/x_connective.c b/apps/plugins/pdbox/PDa/src/x_connective.c
new file mode 100644
index 0000000000..d68192ea9a
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_connective.c
@@ -0,0 +1,2904 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* connective objects */
6
7#include "m_pd.h"
8
9#include <string.h>
10#include <stdio.h>
11extern t_pd *newest;
12
13/* -------------------------- int ------------------------------ */
14static t_class *pdint_class;
15
16typedef struct _pdint
17{
18 t_object x_obj;
19 t_float x_f;
20} t_pdint;
21
22static void *pdint_new(t_floatarg f)
23{
24 t_pdint *x = (t_pdint *)pd_new(pdint_class);
25 x->x_f = f;
26 outlet_new(&x->x_obj, &s_float);
27 floatinlet_new(&x->x_obj, &x->x_f);
28 return (x);
29}
30
31static void pdint_bang(t_pdint *x)
32{
33 outlet_float(x->x_obj.ob_outlet, (t_float)(int)(x->x_f));
34}
35
36static void pdint_float(t_pdint *x, t_float f)
37{
38 outlet_float(x->x_obj.ob_outlet, (t_float)(int)(x->x_f = f));
39}
40
41void pdint_setup(void)
42{
43 pdint_class = class_new(gensym("int"), (t_newmethod)pdint_new, 0,
44 sizeof(t_pdint), 0, A_DEFFLOAT, 0);
45 class_addcreator((t_newmethod)pdint_new, gensym("i"), A_DEFFLOAT, 0);
46 class_addbang(pdint_class, pdint_bang);
47 class_addfloat(pdint_class, pdint_float);
48}
49
50/* -------------------------- float ------------------------------ */
51static t_class *pdfloat_class;
52
53typedef struct _pdfloat
54{
55 t_object x_obj;
56 t_float x_f;
57} t_pdfloat;
58
59 /* "float," "symbol," and "bang" are special because
60 they're created by short-circuited messages to the "new"
61 object which are handled specially in pd_typedmess(). */
62
63static void *pdfloat_new(t_pd *dummy, t_float f)
64{
65 t_pdfloat *x = (t_pdfloat *)pd_new(pdfloat_class);
66 x->x_f = f;
67 outlet_new(&x->x_obj, &s_float);
68 floatinlet_new(&x->x_obj, &x->x_f);
69 newest = &x->x_obj.ob_pd;
70 return (x);
71}
72
73static void *pdfloat_new2(t_floatarg f)
74{
75 return (pdfloat_new(0, f));
76}
77
78static void pdfloat_bang(t_pdfloat *x)
79{
80 outlet_float(x->x_obj.ob_outlet, x->x_f);
81}
82
83static void pdfloat_float(t_pdfloat *x, t_float f)
84{
85 outlet_float(x->x_obj.ob_outlet, x->x_f = f);
86}
87
88void pdfloat_setup(void)
89{
90 pdfloat_class = class_new(gensym("float"), (t_newmethod)pdfloat_new, 0,
91 sizeof(t_pdfloat), 0, A_FLOAT, 0);
92 class_addcreator((t_newmethod)pdfloat_new2, gensym("f"), A_DEFFLOAT, 0);
93 class_addbang(pdfloat_class, pdfloat_bang);
94 class_addfloat(pdfloat_class, (t_method)pdfloat_float);
95}
96
97/* -------------------------- symbol ------------------------------ */
98static t_class *pdsymbol_class;
99
100typedef struct _pdsymbol
101{
102 t_object x_obj;
103 t_symbol *x_s;
104} t_pdsymbol;
105
106static void *pdsymbol_new(t_pd *dummy, t_symbol *s)
107{
108 t_pdsymbol *x = (t_pdsymbol *)pd_new(pdsymbol_class);
109 x->x_s = s;
110 outlet_new(&x->x_obj, &s_symbol);
111 symbolinlet_new(&x->x_obj, &x->x_s);
112 newest = &x->x_obj.ob_pd;
113 return (x);
114}
115
116static void pdsymbol_bang(t_pdsymbol *x)
117{
118 outlet_symbol(x->x_obj.ob_outlet, x->x_s);
119}
120
121static void pdsymbol_symbol(t_pdsymbol *x, t_symbol *s)
122{
123 outlet_symbol(x->x_obj.ob_outlet, x->x_s = s);
124}
125
126static void pdsymbol_anything(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av)
127{
128 outlet_symbol(x->x_obj.ob_outlet, x->x_s = s);
129}
130
131void pdsymbol_setup(void)
132{
133 pdsymbol_class = class_new(gensym("symbol"), (t_newmethod)pdsymbol_new, 0,
134 sizeof(t_pdsymbol), 0, A_SYMBOL, 0);
135 class_addbang(pdsymbol_class, pdsymbol_bang);
136 class_addsymbol(pdsymbol_class, pdsymbol_symbol);
137 class_addanything(pdsymbol_class, pdsymbol_anything);
138}
139
140/* -------------------------- bang ------------------------------ */
141static t_class *bang_class;
142
143typedef struct _bang
144{
145 t_object x_obj;
146} t_bang;
147
148static void *bang_new(t_pd *dummy)
149{
150 t_bang *x = (t_bang *)pd_new(bang_class);
151 outlet_new(&x->x_obj, &s_bang);
152 newest = &x->x_obj.ob_pd;
153 return (x);
154}
155
156static void *bang_new2(t_bang f)
157{
158 return (bang_new(0));
159}
160
161static void bang_bang(t_bang *x)
162{
163 outlet_bang(x->x_obj.ob_outlet);
164}
165
166void bang_setup(void)
167{
168 bang_class = class_new(gensym("bang"), (t_newmethod)bang_new, 0,
169 sizeof(t_bang), 0, 0);
170 class_addcreator((t_newmethod)bang_new2, gensym("b"), 0);
171 class_addbang(bang_class, bang_bang);
172 class_addfloat(bang_class, bang_bang);
173 class_addsymbol(bang_class, bang_bang);
174 class_addlist(bang_class, bang_bang);
175 class_addanything(bang_class, bang_bang);
176}
177
178/* -------------------- send ------------------------------ */
179
180static t_class *send_class;
181
182typedef struct _send
183{
184 t_object x_obj;
185 t_symbol *x_sym;
186} t_send;
187
188static void send_bang(t_send *x)
189{
190 if (x->x_sym->s_thing) pd_bang(x->x_sym->s_thing);
191}
192
193static void send_float(t_send *x, t_float f)
194{
195 if (x->x_sym->s_thing) pd_float(x->x_sym->s_thing, f);
196}
197
198static void send_symbol(t_send *x, t_symbol *s)
199{
200 if (x->x_sym->s_thing) pd_symbol(x->x_sym->s_thing, s);
201}
202
203static void send_pointer(t_send *x, t_gpointer *gp)
204{
205 if (x->x_sym->s_thing) pd_pointer(x->x_sym->s_thing, gp);
206}
207
208static void send_list(t_send *x, t_symbol *s, int argc, t_atom *argv)
209{
210 if (x->x_sym->s_thing) pd_list(x->x_sym->s_thing, s, argc, argv);
211}
212
213static void send_anything(t_send *x, t_symbol *s, int argc, t_atom *argv)
214{
215 if (x->x_sym->s_thing) typedmess(x->x_sym->s_thing, s, argc, argv);
216}
217
218static void *send_new(t_symbol *s)
219{
220 t_send *x = (t_send *)pd_new(send_class);
221 x->x_sym = s;
222 return (x);
223}
224
225static void send_setup(void)
226{
227 send_class = class_new(gensym("send"), (t_newmethod)send_new, 0,
228 sizeof(t_send), 0, A_DEFSYM, 0);
229 class_addcreator((t_newmethod)send_new, gensym("s"), A_DEFSYM, 0);
230 class_addbang(send_class, send_bang);
231 class_addfloat(send_class, send_float);
232 class_addsymbol(send_class, send_symbol);
233 class_addpointer(send_class, send_pointer);
234 class_addlist(send_class, send_list);
235 class_addanything(send_class, send_anything);
236}
237/* -------------------- receive ------------------------------ */
238
239static t_class *receive_class;
240
241typedef struct _receive
242{
243 t_object x_obj;
244 t_symbol *x_sym;
245} t_receive;
246
247static void receive_bang(t_receive *x)
248{
249 outlet_bang(x->x_obj.ob_outlet);
250}
251
252static void receive_float(t_receive *x, t_float f)
253{
254 outlet_float(x->x_obj.ob_outlet, f);
255}
256
257static void receive_symbol(t_receive *x, t_symbol *s)
258{
259 outlet_symbol(x->x_obj.ob_outlet, s);
260}
261
262static void receive_pointer(t_receive *x, t_gpointer *gp)
263{
264 outlet_pointer(x->x_obj.ob_outlet, gp);
265}
266
267static void receive_list(t_receive *x, t_symbol *s, int argc, t_atom *argv)
268{
269 outlet_list(x->x_obj.ob_outlet, s, argc, argv);
270}
271
272static void receive_anything(t_receive *x, t_symbol *s, int argc, t_atom *argv)
273{
274 outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
275}
276
277static void *receive_new(t_symbol *s)
278{
279 t_receive *x = (t_receive *)pd_new(receive_class);
280 x->x_sym = s;
281 pd_bind(&x->x_obj.ob_pd, s);
282 outlet_new(&x->x_obj, 0);
283 return (x);
284}
285
286static void receive_free(t_receive *x)
287{
288 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
289}
290
291static void receive_setup(void)
292{
293 receive_class = class_new(gensym("receive"), (t_newmethod)receive_new,
294 (t_method)receive_free, sizeof(t_receive), CLASS_NOINLET, A_DEFSYM, 0);
295 class_addcreator((t_newmethod)receive_new, gensym("r"), A_DEFSYM, 0);
296 class_addbang(receive_class, receive_bang);
297 class_addfloat(receive_class, (t_method)receive_float);
298 class_addsymbol(receive_class, receive_symbol);
299 class_addpointer(receive_class, receive_pointer);
300 class_addlist(receive_class, receive_list);
301 class_addanything(receive_class, receive_anything);
302}
303
304/* -------------------------- select ------------------------------ */
305
306static t_class *sel1_class;
307
308typedef struct _sel1
309{
310 t_object x_obj;
311 t_atom x_atom;
312 t_outlet *x_outlet1;
313 t_outlet *x_outlet2;
314} t_sel1;
315
316static void sel1_float(t_sel1 *x, t_float f)
317{
318 if (x->x_atom.a_type == A_FLOAT && f == x->x_atom.a_w.w_float)
319 outlet_bang(x->x_outlet1);
320 else outlet_float(x->x_outlet2, f);
321}
322
323static void sel1_symbol(t_sel1 *x, t_symbol *s)
324{
325 if (x->x_atom.a_type == A_SYMBOL && s == x->x_atom.a_w.w_symbol)
326 outlet_bang(x->x_outlet1);
327 else outlet_symbol(x->x_outlet2, s);
328}
329
330static t_class *sel2_class;
331
332typedef struct _selectelement
333{
334 t_word e_w;
335 t_outlet *e_outlet;
336} t_selectelement;
337
338typedef struct _sel2
339{
340 t_object x_obj;
341 t_atomtype x_type;
342 t_int x_nelement;
343 t_selectelement *x_vec;
344 t_outlet *x_rejectout;
345} t_sel2;
346
347static void sel2_float(t_sel2 *x, t_float f)
348{
349 t_selectelement *e;
350 int nelement;
351 if (x->x_type == A_FLOAT)
352 {
353 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
354 if (e->e_w.w_float == f)
355 {
356 outlet_bang(e->e_outlet);
357 return;
358 }
359 }
360 outlet_float(x->x_rejectout, f);
361}
362
363static void sel2_symbol(t_sel2 *x, t_symbol *s)
364{
365 t_selectelement *e;
366 int nelement;
367 if (x->x_type == A_SYMBOL)
368 {
369 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
370 if (e->e_w.w_symbol == s)
371 {
372 outlet_bang(e->e_outlet);
373 return;
374 }
375 }
376 outlet_symbol(x->x_rejectout, s);
377}
378
379static void sel2_free(t_sel2 *x)
380{
381 freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
382}
383
384static void *select_new(t_symbol *s, int argc, t_atom *argv)
385{
386 t_atom a;
387 if (argc == 0)
388 {
389 argc = 1;
390 SETFLOAT(&a, 0);
391 argv = &a;
392 }
393 if (argc == 1)
394 {
395 t_sel1 *x = (t_sel1 *)pd_new(sel1_class);
396 x->x_atom = *argv;
397 x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
398 if (argv->a_type == A_FLOAT)
399 {
400 floatinlet_new(&x->x_obj, &x->x_atom.a_w.w_float);
401 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
402 }
403 else
404 {
405 symbolinlet_new(&x->x_obj, &x->x_atom.a_w.w_symbol);
406 x->x_outlet2 = outlet_new(&x->x_obj, &s_symbol);
407 }
408 return (x);
409 }
410 else
411 {
412 int n;
413 t_selectelement *e;
414 t_sel2 *x = (t_sel2 *)pd_new(sel2_class);
415 x->x_nelement = argc;
416 x->x_vec = (t_selectelement *)getbytes(argc * sizeof(*x->x_vec));
417 x->x_type = argv[0].a_type;
418 for (n = 0, e = x->x_vec; n < argc; n++, e++)
419 {
420 e->e_outlet = outlet_new(&x->x_obj, &s_bang);
421 if ((x->x_type = argv->a_type) == A_FLOAT)
422 e->e_w.w_float = atom_getfloatarg(n, argc, argv);
423 else e->e_w.w_symbol = atom_getsymbolarg(n, argc, argv);
424 }
425 x->x_rejectout = outlet_new(&x->x_obj, &s_float);
426 return (x);
427 }
428
429}
430
431void select_setup(void)
432{
433 sel1_class = class_new(gensym("select"), 0, 0,
434 sizeof(t_sel1), 0, 0);
435 class_addfloat(sel1_class, sel1_float);
436 class_addsymbol(sel1_class, sel1_symbol);
437
438 sel2_class = class_new(gensym("select"), 0, (t_method)sel2_free,
439 sizeof(t_sel2), 0, 0);
440 class_addfloat(sel2_class, sel2_float);
441 class_addsymbol(sel2_class, sel2_symbol);
442
443 class_addcreator((t_newmethod)select_new, gensym("select"), A_GIMME, 0);
444 class_addcreator((t_newmethod)select_new, gensym("sel"), A_GIMME, 0);
445}
446
447/* -------------------------- route ------------------------------ */
448
449static t_class *route_class;
450
451typedef struct _routeelement
452{
453 t_word e_w;
454 t_outlet *e_outlet;
455} t_routeelement;
456
457typedef struct _route
458{
459 t_object x_obj;
460 t_atomtype x_type;
461 t_int x_nelement;
462 t_routeelement *x_vec;
463 t_outlet *x_rejectout;
464} t_route;
465
466static void route_anything(t_route *x, t_symbol *sel, int argc, t_atom *argv)
467{
468 t_routeelement *e;
469 int nelement;
470 if (x->x_type == A_SYMBOL)
471 {
472 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
473 if (e->e_w.w_symbol == sel)
474 {
475 if (argc > 0 && argv[0].a_type == A_SYMBOL)
476 outlet_anything(e->e_outlet, argv[0].a_w.w_symbol,
477 argc-1, argv+1);
478 else outlet_list(e->e_outlet, 0, argc, argv);
479 return;
480 }
481 }
482 outlet_anything(x->x_rejectout, sel, argc, argv);
483}
484
485static void route_list(t_route *x, t_symbol *sel, int argc, t_atom *argv)
486{
487 t_routeelement *e;
488 int nelement;
489 if (x->x_type == A_FLOAT)
490 {
491 float f;
492 if (!argc) return;
493 f = atom_getfloat(argv);
494 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
495 if (e->e_w.w_float == f)
496 {
497 if (argc > 1 && argv[1].a_type == A_SYMBOL)
498 outlet_anything(e->e_outlet, argv[1].a_w.w_symbol,
499 argc-2, argv+2);
500 else outlet_list(e->e_outlet, 0, argc-1, argv+1);
501 return;
502 }
503 }
504 else /* symbol arguments */
505 {
506 if (argc > 1) /* 2 or more args: treat as "list" */
507 {
508 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
509 {
510 if (e->e_w.w_symbol == &s_list)
511 {
512 if (argc > 0 && argv[0].a_type == A_SYMBOL)
513 outlet_anything(e->e_outlet, argv[0].a_w.w_symbol,
514 argc-1, argv+1);
515 else outlet_list(e->e_outlet, 0, argc, argv);
516 return;
517 }
518 }
519 }
520 else if (argc == 0) /* no args: treat as "bang" */
521 {
522 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
523 {
524 if (e->e_w.w_symbol == &s_bang)
525 {
526 outlet_bang(e->e_outlet);
527 return;
528 }
529 }
530 }
531 else if (argv[0].a_type == A_FLOAT) /* one float arg */
532 {
533 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
534 {
535 if (e->e_w.w_symbol == &s_float)
536 {
537 outlet_float(e->e_outlet, argv[0].a_w.w_float);
538 return;
539 }
540 }
541 }
542 else
543 {
544 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
545 {
546 if (e->e_w.w_symbol == &s_symbol)
547 {
548 outlet_symbol(e->e_outlet, argv[0].a_w.w_symbol);
549 return;
550 }
551 }
552 }
553 }
554 outlet_list(x->x_rejectout, 0, argc, argv);
555}
556
557
558static void route_free(t_route *x)
559{
560 freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
561}
562
563static void *route_new(t_symbol *s, int argc, t_atom *argv)
564{
565 int n;
566 t_routeelement *e;
567 t_route *x = (t_route *)pd_new(route_class);
568 t_atom a;
569 if (argc == 0)
570 {
571 argc = 1;
572 SETFLOAT(&a, 0);
573 argv = &a;
574 }
575 x->x_type = argv[0].a_type;
576 x->x_nelement = argc;
577 x->x_vec = (t_routeelement *)getbytes(argc * sizeof(*x->x_vec));
578 for (n = 0, e = x->x_vec; n < argc; n++, e++)
579 {
580 e->e_outlet = outlet_new(&x->x_obj, &s_list);
581 if (x->x_type == A_FLOAT)
582 e->e_w.w_float = atom_getfloatarg(n, argc, argv);
583 else e->e_w.w_symbol = atom_getsymbolarg(n, argc, argv);
584 }
585 x->x_rejectout = outlet_new(&x->x_obj, &s_list);
586 return (x);
587}
588
589void route_setup(void)
590{
591 route_class = class_new(gensym("route"), (t_newmethod)route_new,
592 (t_method)route_free, sizeof(t_route), 0, A_GIMME, 0);
593 class_addlist(route_class, route_list);
594 class_addanything(route_class, route_anything);
595}
596
597/* -------------------------- pack ------------------------------ */
598
599static t_class *pack_class;
600
601typedef struct _pack
602{
603 t_object x_obj;
604 t_int x_n; /* number of args */
605 t_atom *x_vec; /* input values */
606 t_int x_nptr; /* number of pointers */
607 t_gpointer *x_gpointer; /* the pointers */
608 t_atom *x_outvec; /* space for output values */
609} t_pack;
610
611static void *pack_new(t_symbol *s, int argc, t_atom *argv)
612{
613 t_pack *x = (t_pack *)pd_new(pack_class);
614 t_atom defarg[2], *ap, *vec, *vp;
615 t_gpointer *gp;
616 int nptr = 0;
617 int i;
618 if (!argc)
619 {
620 argv = defarg;
621 argc = 2;
622 SETFLOAT(&defarg[0], 0);
623 SETFLOAT(&defarg[1], 0);
624 }
625
626 x->x_n = argc;
627 vec = x->x_vec = (t_atom *)getbytes(argc * sizeof(*x->x_vec));
628 x->x_outvec = (t_atom *)getbytes(argc * sizeof(*x->x_outvec));
629
630 for (i = argc, ap = argv; i--; ap++)
631 if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p')
632 nptr++;
633
634 gp = x->x_gpointer = (t_gpointer *)t_getbytes(nptr * sizeof (*gp));
635 x->x_nptr = nptr;
636
637 for (i = 0, vp = x->x_vec, ap = argv; i < argc; i++, ap++, vp++)
638 {
639 if (ap->a_type == A_FLOAT)
640 {
641 *vp = *ap;
642 if (i) floatinlet_new(&x->x_obj, &vp->a_w.w_float);
643 }
644 else if (ap->a_type == A_SYMBOL)
645 {
646 char c = *ap->a_w.w_symbol->s_name;
647 if (c == 's')
648 {
649 SETSYMBOL(vp, &s_symbol);
650 if (i) symbolinlet_new(&x->x_obj, &vp->a_w.w_symbol);
651 }
652 else if (c == 'p')
653 {
654 vp->a_type = A_POINTER;
655 vp->a_w.w_gpointer = gp;
656 gpointer_init(gp);
657 if (i) pointerinlet_new(&x->x_obj, gp);
658 gp++;
659 }
660 else
661 {
662 if (c != 'f') pd_error(x, "pack: %s: bad type",
663 ap->a_w.w_symbol->s_name);
664 SETFLOAT(vp, 0);
665 if (i) floatinlet_new(&x->x_obj, &vp->a_w.w_float);
666 }
667 }
668 }
669 outlet_new(&x->x_obj, &s_list);
670 return (x);
671}
672
673static void pack_bang(t_pack *x)
674{
675 int i, reentered = 0, size = x->x_n * sizeof (t_atom);
676 t_gpointer *gp;
677 t_atom *outvec;
678 for (i = x->x_nptr, gp = x->x_gpointer; i--; gp++)
679 if (!gpointer_check(gp, 1))
680 {
681 pd_error(x, "pack: stale pointer");
682 return;
683 }
684 /* reentrancy protection. The first time through use the pre-allocated
685 x_outvec; if we're reentered we have to allocate new memory. */
686 if (!x->x_outvec)
687 {
688 /* LATER figure out how to deal with reentrancy and pointers... */
689 if (x->x_nptr)
690 post("pack_bang: warning: reentry with pointers unprotected");
691 outvec = t_getbytes(size);
692 reentered = 1;
693 }
694 else
695 {
696 outvec = x->x_outvec;
697 x->x_outvec = 0;
698 }
699 memcpy(outvec, x->x_vec, size);
700 outlet_list(x->x_obj.ob_outlet, &s_list, x->x_n, outvec);
701 if (reentered)
702 t_freebytes(outvec, size);
703 else x->x_outvec = outvec;
704}
705
706static void pack_pointer(t_pack *x, t_gpointer *gp)
707{
708 if (x->x_vec->a_type == A_POINTER)
709 {
710 gpointer_unset(x->x_gpointer);
711 *x->x_gpointer = *gp;
712 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
713 pack_bang(x);
714 }
715 else pd_error(x, "pack_pointer: wrong type");
716}
717
718static void pack_float(t_pack *x, t_float f)
719{
720 if (x->x_vec->a_type == A_FLOAT)
721 {
722 x->x_vec->a_w.w_float = f;
723 pack_bang(x);
724 }
725 else pd_error(x, "pack_float: wrong type");
726}
727
728static void pack_symbol(t_pack *x, t_symbol *s)
729{
730 if (x->x_vec->a_type == A_SYMBOL)
731 {
732 x->x_vec->a_w.w_symbol = s;
733 pack_bang(x);
734 }
735 else pd_error(x, "pack_symbol: wrong type");
736}
737
738static void pack_list(t_pack *x, t_symbol *s, int ac, t_atom *av)
739{
740 obj_list(&x->x_obj, 0, ac, av);
741}
742
743static void pack_anything(t_pack *x, t_symbol *s, int ac, t_atom *av)
744{
745 t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom));
746 int i;
747 for (i = 0; i < ac; i++)
748 av2[i + 1] = av[i];
749 SETSYMBOL(av2, s);
750 obj_list(&x->x_obj, 0, ac+1, av2);
751 freebytes(av2, (ac + 1) * sizeof(t_atom));
752}
753
754static void pack_free(t_pack *x)
755{
756 t_gpointer *gp;
757 int i;
758 for (gp = x->x_gpointer, i = x->x_nptr; i--; gp++)
759 gpointer_unset(gp);
760 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
761 freebytes(x->x_outvec, x->x_n * sizeof(*x->x_outvec));
762 freebytes(x->x_gpointer, x->x_nptr * sizeof(*x->x_gpointer));
763}
764
765static void pack_setup(void)
766{
767 pack_class = class_new(gensym("pack"), (t_newmethod)pack_new,
768 (t_method)pack_free, sizeof(t_pack), 0, A_GIMME, 0);
769 class_addbang(pack_class, pack_bang);
770 class_addpointer(pack_class, pack_pointer);
771 class_addfloat(pack_class, pack_float);
772 class_addsymbol(pack_class, pack_symbol);
773 class_addlist(pack_class, pack_list);
774 class_addanything(pack_class, pack_anything);
775}
776
777/* -------------------------- unpack ------------------------------ */
778
779static t_class *unpack_class;
780
781typedef struct unpackout
782{
783 t_atomtype u_type;
784 t_outlet *u_outlet;
785} t_unpackout;
786
787typedef struct _unpack
788{
789 t_object x_obj;
790 t_int x_n;
791 t_unpackout *x_vec;
792} t_unpack;
793
794static void *unpack_new(t_symbol *s, int argc, t_atom *argv)
795{
796 t_unpack *x = (t_unpack *)pd_new(unpack_class);
797 t_atom defarg[2], *ap;
798 t_unpackout *u;
799 int i;
800 if (!argc)
801 {
802 argv = defarg;
803 argc = 2;
804 SETFLOAT(&defarg[0], 0);
805 SETFLOAT(&defarg[1], 0);
806 }
807 x->x_n = argc;
808 x->x_vec = (t_unpackout *)getbytes(argc * sizeof(*x->x_vec));
809 for (i = 0, ap = argv, u = x->x_vec; i < argc; u++, ap++, i++)
810 {
811 t_atomtype type = ap->a_type;
812 if (type == A_SYMBOL)
813 {
814 char c = *ap->a_w.w_symbol->s_name;
815 if (c == 's')
816 {
817 u->u_type = A_SYMBOL;
818 u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
819 }
820 else if (c == 'p')
821 {
822 u->u_type = A_POINTER;
823 u->u_outlet = outlet_new(&x->x_obj, &s_pointer);
824 }
825 else
826 {
827 if (c != 'f') pd_error(x, "unpack: %s: bad type",
828 ap->a_w.w_symbol->s_name);
829 u->u_type = A_FLOAT;
830 u->u_outlet = outlet_new(&x->x_obj, &s_float);
831 }
832 }
833 else
834 {
835 u->u_type = A_FLOAT;
836 u->u_outlet = outlet_new(&x->x_obj, &s_float);
837 }
838 }
839 return (x);
840}
841
842static void unpack_list(t_unpack *x, t_symbol *s, int argc, t_atom *argv)
843{
844 t_atom *ap;
845 t_unpackout *u;
846 int i;
847 if (argc > x->x_n) argc = x->x_n;
848 for (i = argc, u = x->x_vec + i, ap = argv + i; u--, ap--, i--;)
849 {
850 t_atomtype type = u->u_type;
851 if (type != ap->a_type)
852 pd_error(x, "unpack: type mismatch");
853 else if (type == A_FLOAT)
854 outlet_float(u->u_outlet, ap->a_w.w_float);
855 else if (type == A_SYMBOL)
856 outlet_symbol(u->u_outlet, ap->a_w.w_symbol);
857 else outlet_pointer(u->u_outlet, ap->a_w.w_gpointer);
858 }
859}
860
861static void unpack_anything(t_unpack *x, t_symbol *s, int ac, t_atom *av)
862{
863 t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom));
864 int i;
865 for (i = 0; i < ac; i++)
866 av2[i + 1] = av[i];
867 SETSYMBOL(av2, s);
868 unpack_list(x, 0, ac+1, av2);
869 freebytes(av2, (ac + 1) * sizeof(t_atom));
870}
871
872static void unpack_free(t_unpack *x)
873{
874 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
875}
876
877static void unpack_setup(void)
878{
879 unpack_class = class_new(gensym("unpack"), (t_newmethod)unpack_new,
880 (t_method)unpack_free, sizeof(t_unpack), 0, A_GIMME, 0);
881 class_addlist(unpack_class, unpack_list);
882 class_addanything(unpack_class, unpack_anything);
883}
884
885/* -------------------------- trigger ------------------------------ */
886
887static t_class *trigger_class;
888#define TR_BANG 0
889#define TR_FLOAT 1
890#define TR_SYMBOL 2
891#define TR_POINTER 3
892#define TR_LIST 4
893#define TR_ANYTHING 5
894
895typedef struct triggerout
896{
897 int u_type; /* outlet type from above */
898 t_outlet *u_outlet;
899} t_triggerout;
900
901typedef struct _trigger
902{
903 t_object x_obj;
904 t_int x_n;
905 t_triggerout *x_vec;
906} t_trigger;
907
908static void *trigger_new(t_symbol *s, int argc, t_atom *argv)
909{
910 t_trigger *x = (t_trigger *)pd_new(trigger_class);
911 t_atom defarg[2], *ap;
912 t_triggerout *u;
913 int i;
914 if (!argc)
915 {
916 argv = defarg;
917 argc = 2;
918 SETSYMBOL(&defarg[0], &s_bang);
919 SETSYMBOL(&defarg[1], &s_bang);
920 }
921 x->x_n = argc;
922 x->x_vec = (t_triggerout *)getbytes(argc * sizeof(*x->x_vec));
923 for (i = 0, ap = argv, u = x->x_vec; i < argc; u++, ap++, i++)
924 {
925 t_atomtype thistype = ap->a_type;
926 char c;
927 if (thistype == TR_SYMBOL) c = ap->a_w.w_symbol->s_name[0];
928 else if (thistype == TR_FLOAT) c = 'f';
929 else c = 0;
930 if (c == 'p')
931 u->u_type = TR_POINTER,
932 u->u_outlet = outlet_new(&x->x_obj, &s_pointer);
933 else if (c == 'f')
934 u->u_type = TR_FLOAT, u->u_outlet = outlet_new(&x->x_obj, &s_float);
935 else if (c == 'b')
936 u->u_type = TR_BANG, u->u_outlet = outlet_new(&x->x_obj, &s_bang);
937 else if (c == 'l')
938 u->u_type = TR_LIST, u->u_outlet = outlet_new(&x->x_obj, &s_list);
939 else if (c == 's')
940 u->u_type = TR_SYMBOL,
941 u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
942 else if (c == 'a')
943 u->u_type = TR_ANYTHING,
944 u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
945 else
946 {
947 pd_error(x, "trigger: %s: bad type", ap->a_w.w_symbol->s_name);
948 u->u_type = TR_FLOAT, u->u_outlet = outlet_new(&x->x_obj, &s_float);
949 }
950 }
951 return (x);
952}
953
954static void trigger_list(t_trigger *x, t_symbol *s, int argc, t_atom *argv)
955{
956 t_triggerout *u;
957 int i;
958 t_atom at;
959 if (!argc)
960 {
961 argc = 1;
962 SETFLOAT(&at, 0);
963 argv = &at;
964 }
965 for (i = x->x_n, u = x->x_vec + i; u--, i--;)
966 {
967 if (u->u_type == TR_FLOAT)
968 outlet_float(u->u_outlet, atom_getfloat(argv));
969 else if (u->u_type == TR_BANG)
970 outlet_bang(u->u_outlet);
971 else if (u->u_type == TR_SYMBOL)
972 outlet_symbol(u->u_outlet, atom_getsymbol(argv));
973 else if (u->u_type == TR_POINTER)
974 {
975 if (argv->a_type != TR_POINTER)
976 pd_error(x, "unpack: bad pointer");
977 else outlet_pointer(u->u_outlet, argv->a_w.w_gpointer);
978 }
979 else outlet_list(u->u_outlet, &s_list, argc, argv);
980 }
981}
982
983static void trigger_anything(t_trigger *x, t_symbol *s, int argc, t_atom *argv)
984{
985 t_triggerout *u;
986 int i;
987 for (i = x->x_n, u = x->x_vec + i; u--, i--;)
988 {
989 if (u->u_type == TR_BANG)
990 outlet_bang(u->u_outlet);
991 else if (u->u_type == TR_ANYTHING)
992 outlet_anything(u->u_outlet, s, argc, argv);
993 else pd_error(x, "trigger: can only convert 's' to 'b' or 'a'",
994 s->s_name);
995 }
996}
997
998static void trigger_bang(t_trigger *x)
999{
1000 trigger_list(x, 0, 0, 0);
1001}
1002
1003static void trigger_pointer(t_trigger *x, t_gpointer *gp)
1004{
1005 t_atom at;
1006 SETPOINTER(&at, gp);
1007 trigger_list(x, 0, 1, &at);
1008}
1009
1010static void trigger_float(t_trigger *x, t_float f)
1011{
1012 t_atom at;
1013 SETFLOAT(&at, f);
1014 trigger_list(x, 0, 1, &at);
1015}
1016
1017static void trigger_symbol(t_trigger *x, t_symbol *s)
1018{
1019 t_atom at;
1020 SETSYMBOL(&at, s);
1021 trigger_list(x, 0, 1, &at);
1022}
1023
1024static void trigger_free(t_trigger *x)
1025{
1026 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
1027}
1028
1029static void trigger_setup(void)
1030{
1031 trigger_class = class_new(gensym("trigger"), (t_newmethod)trigger_new,
1032 (t_method)trigger_free, sizeof(t_trigger), 0, A_GIMME, 0);
1033 class_addcreator((t_newmethod)trigger_new, gensym("t"), A_GIMME, 0);
1034 class_addlist(trigger_class, trigger_list);
1035 class_addbang(trigger_class, trigger_bang);
1036 class_addpointer(trigger_class, trigger_pointer);
1037 class_addfloat(trigger_class, (t_method)trigger_float);
1038 class_addsymbol(trigger_class, trigger_symbol);
1039 class_addanything(trigger_class, trigger_anything);
1040}
1041
1042/* -------------------------- spigot ------------------------------ */
1043static t_class *spigot_class;
1044
1045typedef struct _spigot
1046{
1047 t_object x_obj;
1048 float x_state;
1049} t_spigot;
1050
1051static void *spigot_new(void)
1052{
1053 t_spigot *x = (t_spigot *)pd_new(spigot_class);
1054 floatinlet_new(&x->x_obj, &x->x_state);
1055 outlet_new(&x->x_obj, 0);
1056 x->x_state = 0;
1057 return (x);
1058}
1059
1060static void spigot_bang(t_spigot *x)
1061{
1062 if (x->x_state != 0) outlet_bang(x->x_obj.ob_outlet);
1063}
1064
1065static void spigot_pointer(t_spigot *x, t_gpointer *gp)
1066{
1067 if (x->x_state != 0) outlet_pointer(x->x_obj.ob_outlet, gp);
1068}
1069
1070static void spigot_float(t_spigot *x, t_float f)
1071{
1072 if (x->x_state != 0) outlet_float(x->x_obj.ob_outlet, f);
1073}
1074
1075static void spigot_symbol(t_spigot *x, t_symbol *s)
1076{
1077 if (x->x_state != 0) outlet_symbol(x->x_obj.ob_outlet, s);
1078}
1079
1080static void spigot_list(t_spigot *x, t_symbol *s, int argc, t_atom *argv)
1081{
1082 if (x->x_state != 0) outlet_list(x->x_obj.ob_outlet, s, argc, argv);
1083}
1084
1085static void spigot_anything(t_spigot *x, t_symbol *s, int argc, t_atom *argv)
1086{
1087 if (x->x_state != 0) outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
1088}
1089
1090static void spigot_setup(void)
1091{
1092 spigot_class = class_new(gensym("spigot"), (t_newmethod)spigot_new, 0,
1093 sizeof(t_spigot), 0, A_DEFSYM, 0);
1094 class_addbang(spigot_class, spigot_bang);
1095 class_addpointer(spigot_class, spigot_pointer);
1096 class_addfloat(spigot_class, spigot_float);
1097 class_addsymbol(spigot_class, spigot_symbol);
1098 class_addlist(spigot_class, spigot_list);
1099 class_addanything(spigot_class, spigot_anything);
1100}
1101
1102/* --------------------------- moses ----------------------------- */
1103static t_class *moses_class;
1104
1105typedef struct _moses
1106{
1107 t_object x_ob;
1108 t_outlet *x_out2;
1109 float x_y;
1110} t_moses;
1111
1112static void *moses_new(t_floatarg f)
1113{
1114 t_moses *x = (t_moses *)pd_new(moses_class);
1115 floatinlet_new(&x->x_ob, &x->x_y);
1116 outlet_new(&x->x_ob, &s_float);
1117 x->x_out2 = outlet_new(&x->x_ob, &s_float);
1118 x->x_y = f;
1119 return (x);
1120}
1121
1122static void moses_float(t_moses *x, t_float f)
1123{
1124 if (f < x->x_y) outlet_float(x->x_ob.ob_outlet, f);
1125 else outlet_float(x->x_out2, f);
1126}
1127
1128static void moses_setup(void)
1129{
1130 moses_class = class_new(gensym("moses"), (t_newmethod)moses_new, 0,
1131 sizeof(t_moses), 0, A_DEFFLOAT, 0);
1132 class_addfloat(moses_class, moses_float);
1133}
1134
1135/* ----------------------- until --------------------- */
1136
1137static t_class *until_class;
1138
1139typedef struct _until
1140{
1141 t_object x_obj;
1142 int x_run;
1143 int x_count;
1144} t_until;
1145
1146static void *until_new(void)
1147{
1148 t_until *x = (t_until *)pd_new(until_class);
1149 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
1150 outlet_new(&x->x_obj, &s_bang);
1151 x->x_run = 0;
1152 return (x);
1153}
1154
1155static void until_bang(t_until *x)
1156{
1157 x->x_run = 1;
1158 x->x_count = -1;
1159 while (x->x_run && x->x_count)
1160 x->x_count--, outlet_bang(x->x_obj.ob_outlet);
1161}
1162
1163static void until_float(t_until *x, t_float f)
1164{
1165 x->x_run = 1;
1166 x->x_count = f;
1167 while (x->x_run && x->x_count)
1168 x->x_count--, outlet_bang(x->x_obj.ob_outlet);
1169}
1170
1171static void until_bang2(t_until *x)
1172{
1173 x->x_run = 0;
1174}
1175
1176static void until_setup(void)
1177{
1178 until_class = class_new(gensym("until"), (t_newmethod)until_new, 0,
1179 sizeof(t_until), 0, 0);
1180 class_addbang(until_class, until_bang);
1181 class_addfloat(until_class, until_float);
1182 class_addmethod(until_class, (t_method)until_bang2, gensym("bang2"), 0);
1183}
1184
1185/* ----------------------- makefilename --------------------- */
1186
1187static t_class *makefilename_class;
1188
1189typedef struct _makefilename
1190{
1191 t_object x_obj;
1192 t_symbol *x_format;
1193} t_makefilename;
1194
1195static void *makefilename_new(t_symbol *s)
1196{
1197 t_makefilename *x = (t_makefilename *)pd_new(makefilename_class);
1198 if (!s->s_name) s = gensym("file.%d");
1199 outlet_new(&x->x_obj, &s_symbol);
1200 x->x_format = s;
1201 return (x);
1202}
1203
1204static void makefilename_float(t_makefilename *x, t_floatarg f)
1205{
1206 char buf[MAXPDSTRING];
1207 sprintf(buf, x->x_format->s_name, (int)f);
1208 outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
1209}
1210
1211static void makefilename_symbol(t_makefilename *x, t_symbol *s)
1212{
1213 char buf[MAXPDSTRING];
1214 sprintf(buf, x->x_format->s_name, s->s_name);
1215 outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
1216}
1217
1218static void makefilename_setup(void)
1219{
1220 makefilename_class = class_new(gensym("makefilename"),
1221 (t_newmethod)makefilename_new, 0,
1222 sizeof(t_makefilename), 0, A_DEFSYM, 0);
1223 class_addfloat(makefilename_class, makefilename_float);
1224 class_addsymbol(makefilename_class, makefilename_symbol);
1225}
1226
1227/* -------------------------- swap ------------------------------ */
1228static t_class *swap_class;
1229
1230typedef struct _swap
1231{
1232 t_object x_obj;
1233 t_outlet *x_out2;
1234 t_float x_f1;
1235 t_float x_f2;
1236} t_swap;
1237
1238static void *swap_new(t_floatarg f)
1239{
1240 t_swap *x = (t_swap *)pd_new(swap_class);
1241 x->x_f2 = f;
1242 x->x_f1 = 0;
1243 outlet_new(&x->x_obj, &s_float);
1244 x->x_out2 = outlet_new(&x->x_obj, &s_float);
1245 floatinlet_new(&x->x_obj, &x->x_f2);
1246 return (x);
1247}
1248
1249static void swap_bang(t_swap *x)
1250{
1251 outlet_float(x->x_out2, x->x_f1);
1252 outlet_float(x->x_obj.ob_outlet, x->x_f2);
1253}
1254
1255static void swap_float(t_swap *x, t_float f)
1256{
1257 x->x_f1 = f;
1258 swap_bang(x);
1259}
1260
1261void swap_setup(void)
1262{
1263 swap_class = class_new(gensym("swap"), (t_newmethod)swap_new, 0,
1264 sizeof(t_swap), 0, A_DEFFLOAT, 0);
1265 class_addcreator((t_newmethod)swap_new, gensym("fswap"), A_DEFFLOAT, 0);
1266 class_addbang(swap_class, swap_bang);
1267 class_addfloat(swap_class, swap_float);
1268}
1269
1270/* -------------------------- change ------------------------------ */
1271static t_class *change_class;
1272
1273typedef struct _change
1274{
1275 t_object x_obj;
1276 t_float x_f;
1277} t_change;
1278
1279static void *change_new(t_floatarg f)
1280{
1281 t_change *x = (t_change *)pd_new(change_class);
1282 x->x_f = f;
1283 outlet_new(&x->x_obj, &s_float);
1284 return (x);
1285}
1286
1287static void change_bang(t_change *x)
1288{
1289 outlet_float(x->x_obj.ob_outlet, x->x_f);
1290}
1291
1292static void change_float(t_change *x, t_float f)
1293{
1294 if (f != x->x_f)
1295 {
1296 x->x_f = f;
1297 outlet_float(x->x_obj.ob_outlet, x->x_f);
1298 }
1299}
1300
1301static void change_set(t_change *x, t_float f)
1302{
1303 x->x_f = f;
1304}
1305
1306void change_setup(void)
1307{
1308 change_class = class_new(gensym("change"), (t_newmethod)change_new, 0,
1309 sizeof(t_change), 0, A_DEFFLOAT, 0);
1310 class_addbang(change_class, change_bang);
1311 class_addfloat(change_class, change_float);
1312 class_addmethod(change_class, (t_method)change_set, gensym("set"),
1313 A_DEFFLOAT, 0);
1314}
1315
1316/* -------------------- value ------------------------------ */
1317
1318static t_class *value_class, *vcommon_class;
1319
1320typedef struct vcommon
1321{
1322 t_pd c_pd;
1323 int c_refcount;
1324 t_float c_f;
1325} t_vcommon;
1326
1327typedef struct _value
1328{
1329 t_object x_obj;
1330 t_symbol *x_sym;
1331 t_float *x_floatstar;
1332} t_value;
1333
1334 /* get a pointer to a named floating-point variable. The variable
1335 belongs to a "vcommon" object, which is created if necessary. */
1336t_float *value_get(t_symbol *s)
1337{
1338 t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
1339 if (!c)
1340 {
1341 c = (t_vcommon *)pd_new(vcommon_class);
1342 c->c_f = 0;
1343 c->c_refcount = 0;
1344 pd_bind(&c->c_pd, s);
1345 }
1346 c->c_refcount++;
1347 return (&c->c_f);
1348}
1349
1350 /* release a variable. This only frees the "vcommon" resource when the
1351 last interested party releases it. */
1352void value_release(t_symbol *s)
1353{
1354 t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
1355 if (c)
1356 {
1357 if (!--c->c_refcount)
1358 {
1359 pd_unbind(&c->c_pd, s);
1360 pd_free(&c->c_pd);
1361 }
1362 }
1363 else bug("value_release");
1364}
1365
1366/*
1367 * value_getfloat -- obtain the float value of a "value" object
1368 * return 0 on success, 1 otherwise
1369 */
1370int
1371value_getfloat(t_symbol *s, t_float *f)
1372{
1373 t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
1374 if (!c)
1375 return (1);
1376 *f = c->c_f;
1377 return (0);
1378}
1379
1380/*
1381 * value_setfloat -- set the float value of a "value" object
1382 * return 0 on success, 1 otherwise
1383 */
1384int
1385value_setfloat(t_symbol *s, t_float f)
1386{
1387 t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
1388 if (!c)
1389 return (1);
1390 c->c_f = f;
1391 return (0);
1392}
1393
1394static void *value_new(t_symbol *s)
1395{
1396 t_value *x = (t_value *)pd_new(value_class);
1397 x->x_sym = s;
1398 x->x_floatstar = value_get(s);
1399 outlet_new(&x->x_obj, &s_float);
1400 return (x);
1401}
1402
1403static void value_bang(t_value *x)
1404{
1405 outlet_float(x->x_obj.ob_outlet, *x->x_floatstar);
1406}
1407
1408static void value_float(t_value *x, t_float f)
1409{
1410 *x->x_floatstar = f;
1411}
1412
1413static void value_ff(t_value *x)
1414{
1415 value_release(x->x_sym);
1416}
1417
1418static void value_setup(void)
1419{
1420 value_class = class_new(gensym("value"), (t_newmethod)value_new,
1421 (t_method)value_ff,
1422 sizeof(t_value), 0, A_DEFSYM, 0);
1423 class_addcreator((t_newmethod)value_new, gensym("v"), A_DEFSYM, 0);
1424 class_addbang(value_class, value_bang);
1425 class_addfloat(value_class, value_float);
1426 vcommon_class = class_new(gensym("value"), 0, 0,
1427 sizeof(t_vcommon), CLASS_PD, 0);
1428}
1429
1430/* -------------- overall setup routine for this file ----------------- */
1431
1432void x_connective_setup(void)
1433{
1434 pdint_setup();
1435 pdfloat_setup();
1436 pdsymbol_setup();
1437 bang_setup();
1438 send_setup();
1439 receive_setup();
1440 select_setup();
1441 route_setup();
1442 pack_setup();
1443 unpack_setup();
1444 trigger_setup();
1445 spigot_setup();
1446 moses_setup();
1447 until_setup();
1448 makefilename_setup();
1449 swap_setup();
1450 change_setup();
1451 value_setup();
1452}
1453/* Copyright (c) 1997-1999 Miller Puckette.
1454* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1455* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1456
1457/* connective objects */
1458
1459#include "m_pd.h"
1460
1461#include <string.h>
1462#include <stdio.h>
1463extern t_pd *newest;
1464
1465/* -------------------------- int ------------------------------ */
1466static t_class *pdint_class;
1467
1468typedef struct _pdint
1469{
1470 t_object x_obj;
1471 t_float x_f;
1472} t_pdint;
1473
1474static void *pdint_new(t_floatarg f)
1475{
1476 t_pdint *x = (t_pdint *)pd_new(pdint_class);
1477 x->x_f = f;
1478 outlet_new(&x->x_obj, &s_float);
1479 floatinlet_new(&x->x_obj, &x->x_f);
1480 return (x);
1481}
1482
1483static void pdint_bang(t_pdint *x)
1484{
1485 outlet_float(x->x_obj.ob_outlet, (t_float)(int)(x->x_f));
1486}
1487
1488static void pdint_float(t_pdint *x, t_float f)
1489{
1490 outlet_float(x->x_obj.ob_outlet, (t_float)(int)(x->x_f = f));
1491}
1492
1493void pdint_setup(void)
1494{
1495 pdint_class = class_new(gensym("int"), (t_newmethod)pdint_new, 0,
1496 sizeof(t_pdint), 0, A_DEFFLOAT, 0);
1497 class_addcreator((t_newmethod)pdint_new, gensym("i"), A_DEFFLOAT, 0);
1498 class_addbang(pdint_class, pdint_bang);
1499 class_addfloat(pdint_class, pdint_float);
1500}
1501
1502/* -------------------------- float ------------------------------ */
1503static t_class *pdfloat_class;
1504
1505typedef struct _pdfloat
1506{
1507 t_object x_obj;
1508 t_float x_f;
1509} t_pdfloat;
1510
1511 /* "float," "symbol," and "bang" are special because
1512 they're created by short-circuited messages to the "new"
1513 object which are handled specially in pd_typedmess(). */
1514
1515static void *pdfloat_new(t_pd *dummy, t_float f)
1516{
1517 t_pdfloat *x = (t_pdfloat *)pd_new(pdfloat_class);
1518 x->x_f = f;
1519 outlet_new(&x->x_obj, &s_float);
1520 floatinlet_new(&x->x_obj, &x->x_f);
1521 newest = &x->x_obj.ob_pd;
1522 return (x);
1523}
1524
1525static void *pdfloat_new2(t_floatarg f)
1526{
1527 return (pdfloat_new(0, f));
1528}
1529
1530static void pdfloat_bang(t_pdfloat *x)
1531{
1532 outlet_float(x->x_obj.ob_outlet, x->x_f);
1533}
1534
1535static void pdfloat_float(t_pdfloat *x, t_float f)
1536{
1537 outlet_float(x->x_obj.ob_outlet, x->x_f = f);
1538}
1539
1540void pdfloat_setup(void)
1541{
1542 pdfloat_class = class_new(gensym("float"), (t_newmethod)pdfloat_new, 0,
1543 sizeof(t_pdfloat), 0, A_FLOAT, 0);
1544 class_addcreator((t_newmethod)pdfloat_new2, gensym("f"), A_DEFFLOAT, 0);
1545 class_addbang(pdfloat_class, pdfloat_bang);
1546 class_addfloat(pdfloat_class, (t_method)pdfloat_float);
1547}
1548
1549/* -------------------------- symbol ------------------------------ */
1550static t_class *pdsymbol_class;
1551
1552typedef struct _pdsymbol
1553{
1554 t_object x_obj;
1555 t_symbol *x_s;
1556} t_pdsymbol;
1557
1558static void *pdsymbol_new(t_pd *dummy, t_symbol *s)
1559{
1560 t_pdsymbol *x = (t_pdsymbol *)pd_new(pdsymbol_class);
1561 x->x_s = s;
1562 outlet_new(&x->x_obj, &s_symbol);
1563 symbolinlet_new(&x->x_obj, &x->x_s);
1564 newest = &x->x_obj.ob_pd;
1565 return (x);
1566}
1567
1568static void pdsymbol_bang(t_pdsymbol *x)
1569{
1570 outlet_symbol(x->x_obj.ob_outlet, x->x_s);
1571}
1572
1573static void pdsymbol_symbol(t_pdsymbol *x, t_symbol *s)
1574{
1575 outlet_symbol(x->x_obj.ob_outlet, x->x_s = s);
1576}
1577
1578static void pdsymbol_anything(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av)
1579{
1580 outlet_symbol(x->x_obj.ob_outlet, x->x_s = s);
1581}
1582
1583void pdsymbol_setup(void)
1584{
1585 pdsymbol_class = class_new(gensym("symbol"), (t_newmethod)pdsymbol_new, 0,
1586 sizeof(t_pdsymbol), 0, A_SYMBOL, 0);
1587 class_addbang(pdsymbol_class, pdsymbol_bang);
1588 class_addsymbol(pdsymbol_class, pdsymbol_symbol);
1589 class_addanything(pdsymbol_class, pdsymbol_anything);
1590}
1591
1592/* -------------------------- bang ------------------------------ */
1593static t_class *bang_class;
1594
1595typedef struct _bang
1596{
1597 t_object x_obj;
1598} t_bang;
1599
1600static void *bang_new(t_pd *dummy)
1601{
1602 t_bang *x = (t_bang *)pd_new(bang_class);
1603 outlet_new(&x->x_obj, &s_bang);
1604 newest = &x->x_obj.ob_pd;
1605 return (x);
1606}
1607
1608static void *bang_new2(t_bang f)
1609{
1610 return (bang_new(0));
1611}
1612
1613static void bang_bang(t_bang *x)
1614{
1615 outlet_bang(x->x_obj.ob_outlet);
1616}
1617
1618void bang_setup(void)
1619{
1620 bang_class = class_new(gensym("bang"), (t_newmethod)bang_new, 0,
1621 sizeof(t_bang), 0, 0);
1622 class_addcreator((t_newmethod)bang_new2, gensym("b"), 0);
1623 class_addbang(bang_class, bang_bang);
1624 class_addfloat(bang_class, bang_bang);
1625 class_addsymbol(bang_class, bang_bang);
1626 class_addlist(bang_class, bang_bang);
1627 class_addanything(bang_class, bang_bang);
1628}
1629
1630/* -------------------- send ------------------------------ */
1631
1632static t_class *send_class;
1633
1634typedef struct _send
1635{
1636 t_object x_obj;
1637 t_symbol *x_sym;
1638} t_send;
1639
1640static void send_bang(t_send *x)
1641{
1642 if (x->x_sym->s_thing) pd_bang(x->x_sym->s_thing);
1643}
1644
1645static void send_float(t_send *x, t_float f)
1646{
1647 if (x->x_sym->s_thing) pd_float(x->x_sym->s_thing, f);
1648}
1649
1650static void send_symbol(t_send *x, t_symbol *s)
1651{
1652 if (x->x_sym->s_thing) pd_symbol(x->x_sym->s_thing, s);
1653}
1654
1655static void send_pointer(t_send *x, t_gpointer *gp)
1656{
1657 if (x->x_sym->s_thing) pd_pointer(x->x_sym->s_thing, gp);
1658}
1659
1660static void send_list(t_send *x, t_symbol *s, int argc, t_atom *argv)
1661{
1662 if (x->x_sym->s_thing) pd_list(x->x_sym->s_thing, s, argc, argv);
1663}
1664
1665static void send_anything(t_send *x, t_symbol *s, int argc, t_atom *argv)
1666{
1667 if (x->x_sym->s_thing) typedmess(x->x_sym->s_thing, s, argc, argv);
1668}
1669
1670static void *send_new(t_symbol *s)
1671{
1672 t_send *x = (t_send *)pd_new(send_class);
1673 x->x_sym = s;
1674 return (x);
1675}
1676
1677static void send_setup(void)
1678{
1679 send_class = class_new(gensym("send"), (t_newmethod)send_new, 0,
1680 sizeof(t_send), 0, A_DEFSYM, 0);
1681 class_addcreator((t_newmethod)send_new, gensym("s"), A_DEFSYM, 0);
1682 class_addbang(send_class, send_bang);
1683 class_addfloat(send_class, send_float);
1684 class_addsymbol(send_class, send_symbol);
1685 class_addpointer(send_class, send_pointer);
1686 class_addlist(send_class, send_list);
1687 class_addanything(send_class, send_anything);
1688}
1689/* -------------------- receive ------------------------------ */
1690
1691static t_class *receive_class;
1692
1693typedef struct _receive
1694{
1695 t_object x_obj;
1696 t_symbol *x_sym;
1697} t_receive;
1698
1699static void receive_bang(t_receive *x)
1700{
1701 outlet_bang(x->x_obj.ob_outlet);
1702}
1703
1704static void receive_float(t_receive *x, t_float f)
1705{
1706 outlet_float(x->x_obj.ob_outlet, f);
1707}
1708
1709static void receive_symbol(t_receive *x, t_symbol *s)
1710{
1711 outlet_symbol(x->x_obj.ob_outlet, s);
1712}
1713
1714static void receive_pointer(t_receive *x, t_gpointer *gp)
1715{
1716 outlet_pointer(x->x_obj.ob_outlet, gp);
1717}
1718
1719static void receive_list(t_receive *x, t_symbol *s, int argc, t_atom *argv)
1720{
1721 outlet_list(x->x_obj.ob_outlet, s, argc, argv);
1722}
1723
1724static void receive_anything(t_receive *x, t_symbol *s, int argc, t_atom *argv)
1725{
1726 outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
1727}
1728
1729static void *receive_new(t_symbol *s)
1730{
1731 t_receive *x = (t_receive *)pd_new(receive_class);
1732 x->x_sym = s;
1733 pd_bind(&x->x_obj.ob_pd, s);
1734 outlet_new(&x->x_obj, 0);
1735 return (x);
1736}
1737
1738static void receive_free(t_receive *x)
1739{
1740 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
1741}
1742
1743static void receive_setup(void)
1744{
1745 receive_class = class_new(gensym("receive"), (t_newmethod)receive_new,
1746 (t_method)receive_free, sizeof(t_receive), CLASS_NOINLET, A_DEFSYM, 0);
1747 class_addcreator((t_newmethod)receive_new, gensym("r"), A_DEFSYM, 0);
1748 class_addbang(receive_class, receive_bang);
1749 class_addfloat(receive_class, (t_method)receive_float);
1750 class_addsymbol(receive_class, receive_symbol);
1751 class_addpointer(receive_class, receive_pointer);
1752 class_addlist(receive_class, receive_list);
1753 class_addanything(receive_class, receive_anything);
1754}
1755
1756/* -------------------------- select ------------------------------ */
1757
1758static t_class *sel1_class;
1759
1760typedef struct _sel1
1761{
1762 t_object x_obj;
1763 t_atom x_atom;
1764 t_outlet *x_outlet1;
1765 t_outlet *x_outlet2;
1766} t_sel1;
1767
1768static void sel1_float(t_sel1 *x, t_float f)
1769{
1770 if (x->x_atom.a_type == A_FLOAT && f == x->x_atom.a_w.w_float)
1771 outlet_bang(x->x_outlet1);
1772 else outlet_float(x->x_outlet2, f);
1773}
1774
1775static void sel1_symbol(t_sel1 *x, t_symbol *s)
1776{
1777 if (x->x_atom.a_type == A_SYMBOL && s == x->x_atom.a_w.w_symbol)
1778 outlet_bang(x->x_outlet1);
1779 else outlet_symbol(x->x_outlet2, s);
1780}
1781
1782static t_class *sel2_class;
1783
1784typedef struct _selectelement
1785{
1786 t_word e_w;
1787 t_outlet *e_outlet;
1788} t_selectelement;
1789
1790typedef struct _sel2
1791{
1792 t_object x_obj;
1793 t_atomtype x_type;
1794 t_int x_nelement;
1795 t_selectelement *x_vec;
1796 t_outlet *x_rejectout;
1797} t_sel2;
1798
1799static void sel2_float(t_sel2 *x, t_float f)
1800{
1801 t_selectelement *e;
1802 int nelement;
1803 if (x->x_type == A_FLOAT)
1804 {
1805 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
1806 if (e->e_w.w_float == f)
1807 {
1808 outlet_bang(e->e_outlet);
1809 return;
1810 }
1811 }
1812 outlet_float(x->x_rejectout, f);
1813}
1814
1815static void sel2_symbol(t_sel2 *x, t_symbol *s)
1816{
1817 t_selectelement *e;
1818 int nelement;
1819 if (x->x_type == A_SYMBOL)
1820 {
1821 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
1822 if (e->e_w.w_symbol == s)
1823 {
1824 outlet_bang(e->e_outlet);
1825 return;
1826 }
1827 }
1828 outlet_symbol(x->x_rejectout, s);
1829}
1830
1831static void sel2_free(t_sel2 *x)
1832{
1833 freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
1834}
1835
1836static void *select_new(t_symbol *s, int argc, t_atom *argv)
1837{
1838 t_atom a;
1839 if (argc == 0)
1840 {
1841 argc = 1;
1842 SETFLOAT(&a, 0);
1843 argv = &a;
1844 }
1845 if (argc == 1)
1846 {
1847 t_sel1 *x = (t_sel1 *)pd_new(sel1_class);
1848 x->x_atom = *argv;
1849 x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
1850 if (argv->a_type == A_FLOAT)
1851 {
1852 floatinlet_new(&x->x_obj, &x->x_atom.a_w.w_float);
1853 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1854 }
1855 else
1856 {
1857 symbolinlet_new(&x->x_obj, &x->x_atom.a_w.w_symbol);
1858 x->x_outlet2 = outlet_new(&x->x_obj, &s_symbol);
1859 }
1860 return (x);
1861 }
1862 else
1863 {
1864 int n;
1865 t_selectelement *e;
1866 t_sel2 *x = (t_sel2 *)pd_new(sel2_class);
1867 x->x_nelement = argc;
1868 x->x_vec = (t_selectelement *)getbytes(argc * sizeof(*x->x_vec));
1869 x->x_type = argv[0].a_type;
1870 for (n = 0, e = x->x_vec; n < argc; n++, e++)
1871 {
1872 e->e_outlet = outlet_new(&x->x_obj, &s_bang);
1873 if ((x->x_type = argv->a_type) == A_FLOAT)
1874 e->e_w.w_float = atom_getfloatarg(n, argc, argv);
1875 else e->e_w.w_symbol = atom_getsymbolarg(n, argc, argv);
1876 }
1877 x->x_rejectout = outlet_new(&x->x_obj, &s_float);
1878 return (x);
1879 }
1880
1881}
1882
1883void select_setup(void)
1884{
1885 sel1_class = class_new(gensym("select"), 0, 0,
1886 sizeof(t_sel1), 0, 0);
1887 class_addfloat(sel1_class, sel1_float);
1888 class_addsymbol(sel1_class, sel1_symbol);
1889
1890 sel2_class = class_new(gensym("select"), 0, (t_method)sel2_free,
1891 sizeof(t_sel2), 0, 0);
1892 class_addfloat(sel2_class, sel2_float);
1893 class_addsymbol(sel2_class, sel2_symbol);
1894
1895 class_addcreator((t_newmethod)select_new, gensym("select"), A_GIMME, 0);
1896 class_addcreator((t_newmethod)select_new, gensym("sel"), A_GIMME, 0);
1897}
1898
1899/* -------------------------- route ------------------------------ */
1900
1901static t_class *route_class;
1902
1903typedef struct _routeelement
1904{
1905 t_word e_w;
1906 t_outlet *e_outlet;
1907} t_routeelement;
1908
1909typedef struct _route
1910{
1911 t_object x_obj;
1912 t_atomtype x_type;
1913 t_int x_nelement;
1914 t_routeelement *x_vec;
1915 t_outlet *x_rejectout;
1916} t_route;
1917
1918static void route_anything(t_route *x, t_symbol *sel, int argc, t_atom *argv)
1919{
1920 t_routeelement *e;
1921 int nelement;
1922 if (x->x_type == A_SYMBOL)
1923 {
1924 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
1925 if (e->e_w.w_symbol == sel)
1926 {
1927 if (argc > 0 && argv[0].a_type == A_SYMBOL)
1928 outlet_anything(e->e_outlet, argv[0].a_w.w_symbol,
1929 argc-1, argv+1);
1930 else outlet_list(e->e_outlet, 0, argc, argv);
1931 return;
1932 }
1933 }
1934 outlet_anything(x->x_rejectout, sel, argc, argv);
1935}
1936
1937static void route_list(t_route *x, t_symbol *sel, int argc, t_atom *argv)
1938{
1939 t_routeelement *e;
1940 int nelement;
1941 if (x->x_type == A_FLOAT)
1942 {
1943 float f;
1944 if (!argc) return;
1945 f = atom_getfloat(argv);
1946 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
1947 if (e->e_w.w_float == f)
1948 {
1949 if (argc > 1 && argv[1].a_type == A_SYMBOL)
1950 outlet_anything(e->e_outlet, argv[1].a_w.w_symbol,
1951 argc-2, argv+2);
1952 else outlet_list(e->e_outlet, 0, argc-1, argv+1);
1953 return;
1954 }
1955 }
1956 else /* symbol arguments */
1957 {
1958 if (argc > 1) /* 2 or more args: treat as "list" */
1959 {
1960 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
1961 {
1962 if (e->e_w.w_symbol == &s_list)
1963 {
1964 if (argc > 0 && argv[0].a_type == A_SYMBOL)
1965 outlet_anything(e->e_outlet, argv[0].a_w.w_symbol,
1966 argc-1, argv+1);
1967 else outlet_list(e->e_outlet, 0, argc, argv);
1968 return;
1969 }
1970 }
1971 }
1972 else if (argc == 0) /* no args: treat as "bang" */
1973 {
1974 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
1975 {
1976 if (e->e_w.w_symbol == &s_bang)
1977 {
1978 outlet_bang(e->e_outlet);
1979 return;
1980 }
1981 }
1982 }
1983 else if (argv[0].a_type == A_FLOAT) /* one float arg */
1984 {
1985 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
1986 {
1987 if (e->e_w.w_symbol == &s_float)
1988 {
1989 outlet_float(e->e_outlet, argv[0].a_w.w_float);
1990 return;
1991 }
1992 }
1993 }
1994 else
1995 {
1996 for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
1997 {
1998 if (e->e_w.w_symbol == &s_symbol)
1999 {
2000 outlet_symbol(e->e_outlet, argv[0].a_w.w_symbol);
2001 return;
2002 }
2003 }
2004 }
2005 }
2006 outlet_list(x->x_rejectout, 0, argc, argv);
2007}
2008
2009
2010static void route_free(t_route *x)
2011{
2012 freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
2013}
2014
2015static void *route_new(t_symbol *s, int argc, t_atom *argv)
2016{
2017 int n;
2018 t_routeelement *e;
2019 t_route *x = (t_route *)pd_new(route_class);
2020 t_atom a;
2021 if (argc == 0)
2022 {
2023 argc = 1;
2024 SETFLOAT(&a, 0);
2025 argv = &a;
2026 }
2027 x->x_type = argv[0].a_type;
2028 x->x_nelement = argc;
2029 x->x_vec = (t_routeelement *)getbytes(argc * sizeof(*x->x_vec));
2030 for (n = 0, e = x->x_vec; n < argc; n++, e++)
2031 {
2032 e->e_outlet = outlet_new(&x->x_obj, &s_list);
2033 if (x->x_type == A_FLOAT)
2034 e->e_w.w_float = atom_getfloatarg(n, argc, argv);
2035 else e->e_w.w_symbol = atom_getsymbolarg(n, argc, argv);
2036 }
2037 x->x_rejectout = outlet_new(&x->x_obj, &s_list);
2038 return (x);
2039}
2040
2041void route_setup(void)
2042{
2043 route_class = class_new(gensym("route"), (t_newmethod)route_new,
2044 (t_method)route_free, sizeof(t_route), 0, A_GIMME, 0);
2045 class_addlist(route_class, route_list);
2046 class_addanything(route_class, route_anything);
2047}
2048
2049/* -------------------------- pack ------------------------------ */
2050
2051static t_class *pack_class;
2052
2053typedef struct _pack
2054{
2055 t_object x_obj;
2056 t_int x_n; /* number of args */
2057 t_atom *x_vec; /* input values */
2058 t_int x_nptr; /* number of pointers */
2059 t_gpointer *x_gpointer; /* the pointers */
2060 t_atom *x_outvec; /* space for output values */
2061} t_pack;
2062
2063static void *pack_new(t_symbol *s, int argc, t_atom *argv)
2064{
2065 t_pack *x = (t_pack *)pd_new(pack_class);
2066 t_atom defarg[2], *ap, *vec, *vp;
2067 t_gpointer *gp;
2068 int nptr = 0;
2069 int i;
2070 if (!argc)
2071 {
2072 argv = defarg;
2073 argc = 2;
2074 SETFLOAT(&defarg[0], 0);
2075 SETFLOAT(&defarg[1], 0);
2076 }
2077
2078 x->x_n = argc;
2079 vec = x->x_vec = (t_atom *)getbytes(argc * sizeof(*x->x_vec));
2080 x->x_outvec = (t_atom *)getbytes(argc * sizeof(*x->x_outvec));
2081
2082 for (i = argc, ap = argv; i--; ap++)
2083 if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p')
2084 nptr++;
2085
2086 gp = x->x_gpointer = (t_gpointer *)t_getbytes(nptr * sizeof (*gp));
2087 x->x_nptr = nptr;
2088
2089 for (i = 0, vp = x->x_vec, ap = argv; i < argc; i++, ap++, vp++)
2090 {
2091 if (ap->a_type == A_FLOAT)
2092 {
2093 *vp = *ap;
2094 if (i) floatinlet_new(&x->x_obj, &vp->a_w.w_float);
2095 }
2096 else if (ap->a_type == A_SYMBOL)
2097 {
2098 char c = *ap->a_w.w_symbol->s_name;
2099 if (c == 's')
2100 {
2101 SETSYMBOL(vp, &s_symbol);
2102 if (i) symbolinlet_new(&x->x_obj, &vp->a_w.w_symbol);
2103 }
2104 else if (c == 'p')
2105 {
2106 vp->a_type = A_POINTER;
2107 vp->a_w.w_gpointer = gp;
2108 gpointer_init(gp);
2109 if (i) pointerinlet_new(&x->x_obj, gp);
2110 gp++;
2111 }
2112 else
2113 {
2114 if (c != 'f') pd_error(x, "pack: %s: bad type",
2115 ap->a_w.w_symbol->s_name);
2116 SETFLOAT(vp, 0);
2117 if (i) floatinlet_new(&x->x_obj, &vp->a_w.w_float);
2118 }
2119 }
2120 }
2121 outlet_new(&x->x_obj, &s_list);
2122 return (x);
2123}
2124
2125static void pack_bang(t_pack *x)
2126{
2127 int i, reentered = 0, size = x->x_n * sizeof (t_atom);
2128 t_gpointer *gp;
2129 t_atom *outvec;
2130 for (i = x->x_nptr, gp = x->x_gpointer; i--; gp++)
2131 if (!gpointer_check(gp, 1))
2132 {
2133 pd_error(x, "pack: stale pointer");
2134 return;
2135 }
2136 /* reentrancy protection. The first time through use the pre-allocated
2137 x_outvec; if we're reentered we have to allocate new memory. */
2138 if (!x->x_outvec)
2139 {
2140 /* LATER figure out how to deal with reentrancy and pointers... */
2141 if (x->x_nptr)
2142 post("pack_bang: warning: reentry with pointers unprotected");
2143 outvec = t_getbytes(size);
2144 reentered = 1;
2145 }
2146 else
2147 {
2148 outvec = x->x_outvec;
2149 x->x_outvec = 0;
2150 }
2151 memcpy(outvec, x->x_vec, size);
2152 outlet_list(x->x_obj.ob_outlet, &s_list, x->x_n, outvec);
2153 if (reentered)
2154 t_freebytes(outvec, size);
2155 else x->x_outvec = outvec;
2156}
2157
2158static void pack_pointer(t_pack *x, t_gpointer *gp)
2159{
2160 if (x->x_vec->a_type == A_POINTER)
2161 {
2162 gpointer_unset(x->x_gpointer);
2163 *x->x_gpointer = *gp;
2164 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
2165 pack_bang(x);
2166 }
2167 else pd_error(x, "pack_pointer: wrong type");
2168}
2169
2170static void pack_float(t_pack *x, t_float f)
2171{
2172 if (x->x_vec->a_type == A_FLOAT)
2173 {
2174 x->x_vec->a_w.w_float = f;
2175 pack_bang(x);
2176 }
2177 else pd_error(x, "pack_float: wrong type");
2178}
2179
2180static void pack_symbol(t_pack *x, t_symbol *s)
2181{
2182 if (x->x_vec->a_type == A_SYMBOL)
2183 {
2184 x->x_vec->a_w.w_symbol = s;
2185 pack_bang(x);
2186 }
2187 else pd_error(x, "pack_symbol: wrong type");
2188}
2189
2190static void pack_list(t_pack *x, t_symbol *s, int ac, t_atom *av)
2191{
2192 obj_list(&x->x_obj, 0, ac, av);
2193}
2194
2195static void pack_anything(t_pack *x, t_symbol *s, int ac, t_atom *av)
2196{
2197 t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom));
2198 int i;
2199 for (i = 0; i < ac; i++)
2200 av2[i + 1] = av[i];
2201 SETSYMBOL(av2, s);
2202 obj_list(&x->x_obj, 0, ac+1, av2);
2203 freebytes(av2, (ac + 1) * sizeof(t_atom));
2204}
2205
2206static void pack_free(t_pack *x)
2207{
2208 t_gpointer *gp;
2209 int i;
2210 for (gp = x->x_gpointer, i = x->x_nptr; i--; gp++)
2211 gpointer_unset(gp);
2212 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
2213 freebytes(x->x_outvec, x->x_n * sizeof(*x->x_outvec));
2214 freebytes(x->x_gpointer, x->x_nptr * sizeof(*x->x_gpointer));
2215}
2216
2217static void pack_setup(void)
2218{
2219 pack_class = class_new(gensym("pack"), (t_newmethod)pack_new,
2220 (t_method)pack_free, sizeof(t_pack), 0, A_GIMME, 0);
2221 class_addbang(pack_class, pack_bang);
2222 class_addpointer(pack_class, pack_pointer);
2223 class_addfloat(pack_class, pack_float);
2224 class_addsymbol(pack_class, pack_symbol);
2225 class_addlist(pack_class, pack_list);
2226 class_addanything(pack_class, pack_anything);
2227}
2228
2229/* -------------------------- unpack ------------------------------ */
2230
2231static t_class *unpack_class;
2232
2233typedef struct unpackout
2234{
2235 t_atomtype u_type;
2236 t_outlet *u_outlet;
2237} t_unpackout;
2238
2239typedef struct _unpack
2240{
2241 t_object x_obj;
2242 t_int x_n;
2243 t_unpackout *x_vec;
2244} t_unpack;
2245
2246static void *unpack_new(t_symbol *s, int argc, t_atom *argv)
2247{
2248 t_unpack *x = (t_unpack *)pd_new(unpack_class);
2249 t_atom defarg[2], *ap;
2250 t_unpackout *u;
2251 int i;
2252 if (!argc)
2253 {
2254 argv = defarg;
2255 argc = 2;
2256 SETFLOAT(&defarg[0], 0);
2257 SETFLOAT(&defarg[1], 0);
2258 }
2259 x->x_n = argc;
2260 x->x_vec = (t_unpackout *)getbytes(argc * sizeof(*x->x_vec));
2261 for (i = 0, ap = argv, u = x->x_vec; i < argc; u++, ap++, i++)
2262 {
2263 t_atomtype type = ap->a_type;
2264 if (type == A_SYMBOL)
2265 {
2266 char c = *ap->a_w.w_symbol->s_name;
2267 if (c == 's')
2268 {
2269 u->u_type = A_SYMBOL;
2270 u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
2271 }
2272 else if (c == 'p')
2273 {
2274 u->u_type = A_POINTER;
2275 u->u_outlet = outlet_new(&x->x_obj, &s_pointer);
2276 }
2277 else
2278 {
2279 if (c != 'f') pd_error(x, "unpack: %s: bad type",
2280 ap->a_w.w_symbol->s_name);
2281 u->u_type = A_FLOAT;
2282 u->u_outlet = outlet_new(&x->x_obj, &s_float);
2283 }
2284 }
2285 else
2286 {
2287 u->u_type = A_FLOAT;
2288 u->u_outlet = outlet_new(&x->x_obj, &s_float);
2289 }
2290 }
2291 return (x);
2292}
2293
2294static void unpack_list(t_unpack *x, t_symbol *s, int argc, t_atom *argv)
2295{
2296 t_atom *ap;
2297 t_unpackout *u;
2298 int i;
2299 if (argc > x->x_n) argc = x->x_n;
2300 for (i = argc, u = x->x_vec + i, ap = argv + i; u--, ap--, i--;)
2301 {
2302 t_atomtype type = u->u_type;
2303 if (type != ap->a_type)
2304 pd_error(x, "unpack: type mismatch");
2305 else if (type == A_FLOAT)
2306 outlet_float(u->u_outlet, ap->a_w.w_float);
2307 else if (type == A_SYMBOL)
2308 outlet_symbol(u->u_outlet, ap->a_w.w_symbol);
2309 else outlet_pointer(u->u_outlet, ap->a_w.w_gpointer);
2310 }
2311}
2312
2313static void unpack_anything(t_unpack *x, t_symbol *s, int ac, t_atom *av)
2314{
2315 t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom));
2316 int i;
2317 for (i = 0; i < ac; i++)
2318 av2[i + 1] = av[i];
2319 SETSYMBOL(av2, s);
2320 unpack_list(x, 0, ac+1, av2);
2321 freebytes(av2, (ac + 1) * sizeof(t_atom));
2322}
2323
2324static void unpack_free(t_unpack *x)
2325{
2326 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
2327}
2328
2329static void unpack_setup(void)
2330{
2331 unpack_class = class_new(gensym("unpack"), (t_newmethod)unpack_new,
2332 (t_method)unpack_free, sizeof(t_unpack), 0, A_GIMME, 0);
2333 class_addlist(unpack_class, unpack_list);
2334 class_addanything(unpack_class, unpack_anything);
2335}
2336
2337/* -------------------------- trigger ------------------------------ */
2338
2339static t_class *trigger_class;
2340#define TR_BANG 0
2341#define TR_FLOAT 1
2342#define TR_SYMBOL 2
2343#define TR_POINTER 3
2344#define TR_LIST 4
2345#define TR_ANYTHING 5
2346
2347typedef struct triggerout
2348{
2349 int u_type; /* outlet type from above */
2350 t_outlet *u_outlet;
2351} t_triggerout;
2352
2353typedef struct _trigger
2354{
2355 t_object x_obj;
2356 t_int x_n;
2357 t_triggerout *x_vec;
2358} t_trigger;
2359
2360static void *trigger_new(t_symbol *s, int argc, t_atom *argv)
2361{
2362 t_trigger *x = (t_trigger *)pd_new(trigger_class);
2363 t_atom defarg[2], *ap;
2364 t_triggerout *u;
2365 int i;
2366 if (!argc)
2367 {
2368 argv = defarg;
2369 argc = 2;
2370 SETSYMBOL(&defarg[0], &s_bang);
2371 SETSYMBOL(&defarg[1], &s_bang);
2372 }
2373 x->x_n = argc;
2374 x->x_vec = (t_triggerout *)getbytes(argc * sizeof(*x->x_vec));
2375 for (i = 0, ap = argv, u = x->x_vec; i < argc; u++, ap++, i++)
2376 {
2377 t_atomtype thistype = ap->a_type;
2378 char c;
2379 if (thistype == TR_SYMBOL) c = ap->a_w.w_symbol->s_name[0];
2380 else if (thistype == TR_FLOAT) c = 'f';
2381 else c = 0;
2382 if (c == 'p')
2383 u->u_type = TR_POINTER,
2384 u->u_outlet = outlet_new(&x->x_obj, &s_pointer);
2385 else if (c == 'f')
2386 u->u_type = TR_FLOAT, u->u_outlet = outlet_new(&x->x_obj, &s_float);
2387 else if (c == 'b')
2388 u->u_type = TR_BANG, u->u_outlet = outlet_new(&x->x_obj, &s_bang);
2389 else if (c == 'l')
2390 u->u_type = TR_LIST, u->u_outlet = outlet_new(&x->x_obj, &s_list);
2391 else if (c == 's')
2392 u->u_type = TR_SYMBOL,
2393 u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
2394 else if (c == 'a')
2395 u->u_type = TR_ANYTHING,
2396 u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
2397 else
2398 {
2399 pd_error(x, "trigger: %s: bad type", ap->a_w.w_symbol->s_name);
2400 u->u_type = TR_FLOAT, u->u_outlet = outlet_new(&x->x_obj, &s_float);
2401 }
2402 }
2403 return (x);
2404}
2405
2406static void trigger_list(t_trigger *x, t_symbol *s, int argc, t_atom *argv)
2407{
2408 t_triggerout *u;
2409 int i;
2410 t_atom at;
2411 if (!argc)
2412 {
2413 argc = 1;
2414 SETFLOAT(&at, 0);
2415 argv = &at;
2416 }
2417 for (i = x->x_n, u = x->x_vec + i; u--, i--;)
2418 {
2419 if (u->u_type == TR_FLOAT)
2420 outlet_float(u->u_outlet, atom_getfloat(argv));
2421 else if (u->u_type == TR_BANG)
2422 outlet_bang(u->u_outlet);
2423 else if (u->u_type == TR_SYMBOL)
2424 outlet_symbol(u->u_outlet, atom_getsymbol(argv));
2425 else if (u->u_type == TR_POINTER)
2426 {
2427 if (argv->a_type != TR_POINTER)
2428 pd_error(x, "unpack: bad pointer");
2429 else outlet_pointer(u->u_outlet, argv->a_w.w_gpointer);
2430 }
2431 else outlet_list(u->u_outlet, &s_list, argc, argv);
2432 }
2433}
2434
2435static void trigger_anything(t_trigger *x, t_symbol *s, int argc, t_atom *argv)
2436{
2437 t_triggerout *u;
2438 int i;
2439 for (i = x->x_n, u = x->x_vec + i; u--, i--;)
2440 {
2441 if (u->u_type == TR_BANG)
2442 outlet_bang(u->u_outlet);
2443 else if (u->u_type == TR_ANYTHING)
2444 outlet_anything(u->u_outlet, s, argc, argv);
2445 else pd_error(x, "trigger: can only convert 's' to 'b' or 'a'",
2446 s->s_name);
2447 }
2448}
2449
2450static void trigger_bang(t_trigger *x)
2451{
2452 trigger_list(x, 0, 0, 0);
2453}
2454
2455static void trigger_pointer(t_trigger *x, t_gpointer *gp)
2456{
2457 t_atom at;
2458 SETPOINTER(&at, gp);
2459 trigger_list(x, 0, 1, &at);
2460}
2461
2462static void trigger_float(t_trigger *x, t_float f)
2463{
2464 t_atom at;
2465 SETFLOAT(&at, f);
2466 trigger_list(x, 0, 1, &at);
2467}
2468
2469static void trigger_symbol(t_trigger *x, t_symbol *s)
2470{
2471 t_atom at;
2472 SETSYMBOL(&at, s);
2473 trigger_list(x, 0, 1, &at);
2474}
2475
2476static void trigger_free(t_trigger *x)
2477{
2478 freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
2479}
2480
2481static void trigger_setup(void)
2482{
2483 trigger_class = class_new(gensym("trigger"), (t_newmethod)trigger_new,
2484 (t_method)trigger_free, sizeof(t_trigger), 0, A_GIMME, 0);
2485 class_addcreator((t_newmethod)trigger_new, gensym("t"), A_GIMME, 0);
2486 class_addlist(trigger_class, trigger_list);
2487 class_addbang(trigger_class, trigger_bang);
2488 class_addpointer(trigger_class, trigger_pointer);
2489 class_addfloat(trigger_class, (t_method)trigger_float);
2490 class_addsymbol(trigger_class, trigger_symbol);
2491 class_addanything(trigger_class, trigger_anything);
2492}
2493
2494/* -------------------------- spigot ------------------------------ */
2495static t_class *spigot_class;
2496
2497typedef struct _spigot
2498{
2499 t_object x_obj;
2500 float x_state;
2501} t_spigot;
2502
2503static void *spigot_new(void)
2504{
2505 t_spigot *x = (t_spigot *)pd_new(spigot_class);
2506 floatinlet_new(&x->x_obj, &x->x_state);
2507 outlet_new(&x->x_obj, 0);
2508 x->x_state = 0;
2509 return (x);
2510}
2511
2512static void spigot_bang(t_spigot *x)
2513{
2514 if (x->x_state != 0) outlet_bang(x->x_obj.ob_outlet);
2515}
2516
2517static void spigot_pointer(t_spigot *x, t_gpointer *gp)
2518{
2519 if (x->x_state != 0) outlet_pointer(x->x_obj.ob_outlet, gp);
2520}
2521
2522static void spigot_float(t_spigot *x, t_float f)
2523{
2524 if (x->x_state != 0) outlet_float(x->x_obj.ob_outlet, f);
2525}
2526
2527static void spigot_symbol(t_spigot *x, t_symbol *s)
2528{
2529 if (x->x_state != 0) outlet_symbol(x->x_obj.ob_outlet, s);
2530}
2531
2532static void spigot_list(t_spigot *x, t_symbol *s, int argc, t_atom *argv)
2533{
2534 if (x->x_state != 0) outlet_list(x->x_obj.ob_outlet, s, argc, argv);
2535}
2536
2537static void spigot_anything(t_spigot *x, t_symbol *s, int argc, t_atom *argv)
2538{
2539 if (x->x_state != 0) outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
2540}
2541
2542static void spigot_setup(void)
2543{
2544 spigot_class = class_new(gensym("spigot"), (t_newmethod)spigot_new, 0,
2545 sizeof(t_spigot), 0, A_DEFSYM, 0);
2546 class_addbang(spigot_class, spigot_bang);
2547 class_addpointer(spigot_class, spigot_pointer);
2548 class_addfloat(spigot_class, spigot_float);
2549 class_addsymbol(spigot_class, spigot_symbol);
2550 class_addlist(spigot_class, spigot_list);
2551 class_addanything(spigot_class, spigot_anything);
2552}
2553
2554/* --------------------------- moses ----------------------------- */
2555static t_class *moses_class;
2556
2557typedef struct _moses
2558{
2559 t_object x_ob;
2560 t_outlet *x_out2;
2561 float x_y;
2562} t_moses;
2563
2564static void *moses_new(t_floatarg f)
2565{
2566 t_moses *x = (t_moses *)pd_new(moses_class);
2567 floatinlet_new(&x->x_ob, &x->x_y);
2568 outlet_new(&x->x_ob, &s_float);
2569 x->x_out2 = outlet_new(&x->x_ob, &s_float);
2570 x->x_y = f;
2571 return (x);
2572}
2573
2574static void moses_float(t_moses *x, t_float f)
2575{
2576 if (f < x->x_y) outlet_float(x->x_ob.ob_outlet, f);
2577 else outlet_float(x->x_out2, f);
2578}
2579
2580static void moses_setup(void)
2581{
2582 moses_class = class_new(gensym("moses"), (t_newmethod)moses_new, 0,
2583 sizeof(t_moses), 0, A_DEFFLOAT, 0);
2584 class_addfloat(moses_class, moses_float);
2585}
2586
2587/* ----------------------- until --------------------- */
2588
2589static t_class *until_class;
2590
2591typedef struct _until
2592{
2593 t_object x_obj;
2594 int x_run;
2595 int x_count;
2596} t_until;
2597
2598static void *until_new(void)
2599{
2600 t_until *x = (t_until *)pd_new(until_class);
2601 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
2602 outlet_new(&x->x_obj, &s_bang);
2603 x->x_run = 0;
2604 return (x);
2605}
2606
2607static void until_bang(t_until *x)
2608{
2609 x->x_run = 1;
2610 x->x_count = -1;
2611 while (x->x_run && x->x_count)
2612 x->x_count--, outlet_bang(x->x_obj.ob_outlet);
2613}
2614
2615static void until_float(t_until *x, t_float f)
2616{
2617 x->x_run = 1;
2618 x->x_count = f;
2619 while (x->x_run && x->x_count)
2620 x->x_count--, outlet_bang(x->x_obj.ob_outlet);
2621}
2622
2623static void until_bang2(t_until *x)
2624{
2625 x->x_run = 0;
2626}
2627
2628static void until_setup(void)
2629{
2630 until_class = class_new(gensym("until"), (t_newmethod)until_new, 0,
2631 sizeof(t_until), 0, 0);
2632 class_addbang(until_class, until_bang);
2633 class_addfloat(until_class, until_float);
2634 class_addmethod(until_class, (t_method)until_bang2, gensym("bang2"), 0);
2635}
2636
2637/* ----------------------- makefilename --------------------- */
2638
2639static t_class *makefilename_class;
2640
2641typedef struct _makefilename
2642{
2643 t_object x_obj;
2644 t_symbol *x_format;
2645} t_makefilename;
2646
2647static void *makefilename_new(t_symbol *s)
2648{
2649 t_makefilename *x = (t_makefilename *)pd_new(makefilename_class);
2650 if (!s->s_name) s = gensym("file.%d");
2651 outlet_new(&x->x_obj, &s_symbol);
2652 x->x_format = s;
2653 return (x);
2654}
2655
2656static void makefilename_float(t_makefilename *x, t_floatarg f)
2657{
2658 char buf[MAXPDSTRING];
2659 sprintf(buf, x->x_format->s_name, (int)f);
2660 outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
2661}
2662
2663static void makefilename_symbol(t_makefilename *x, t_symbol *s)
2664{
2665 char buf[MAXPDSTRING];
2666 sprintf(buf, x->x_format->s_name, s->s_name);
2667 outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
2668}
2669
2670static void makefilename_setup(void)
2671{
2672 makefilename_class = class_new(gensym("makefilename"),
2673 (t_newmethod)makefilename_new, 0,
2674 sizeof(t_makefilename), 0, A_DEFSYM, 0);
2675 class_addfloat(makefilename_class, makefilename_float);
2676 class_addsymbol(makefilename_class, makefilename_symbol);
2677}
2678
2679/* -------------------------- swap ------------------------------ */
2680static t_class *swap_class;
2681
2682typedef struct _swap
2683{
2684 t_object x_obj;
2685 t_outlet *x_out2;
2686 t_float x_f1;
2687 t_float x_f2;
2688} t_swap;
2689
2690static void *swap_new(t_floatarg f)
2691{
2692 t_swap *x = (t_swap *)pd_new(swap_class);
2693 x->x_f2 = f;
2694 x->x_f1 = 0;
2695 outlet_new(&x->x_obj, &s_float);
2696 x->x_out2 = outlet_new(&x->x_obj, &s_float);
2697 floatinlet_new(&x->x_obj, &x->x_f2);
2698 return (x);
2699}
2700
2701static void swap_bang(t_swap *x)
2702{
2703 outlet_float(x->x_out2, x->x_f1);
2704 outlet_float(x->x_obj.ob_outlet, x->x_f2);
2705}
2706
2707static void swap_float(t_swap *x, t_float f)
2708{
2709 x->x_f1 = f;
2710 swap_bang(x);
2711}
2712
2713void swap_setup(void)
2714{
2715 swap_class = class_new(gensym("swap"), (t_newmethod)swap_new, 0,
2716 sizeof(t_swap), 0, A_DEFFLOAT, 0);
2717 class_addcreator((t_newmethod)swap_new, gensym("fswap"), A_DEFFLOAT, 0);
2718 class_addbang(swap_class, swap_bang);
2719 class_addfloat(swap_class, swap_float);
2720}
2721
2722/* -------------------------- change ------------------------------ */
2723static t_class *change_class;
2724
2725typedef struct _change
2726{
2727 t_object x_obj;
2728 t_float x_f;
2729} t_change;
2730
2731static void *change_new(t_floatarg f)
2732{
2733 t_change *x = (t_change *)pd_new(change_class);
2734 x->x_f = f;
2735 outlet_new(&x->x_obj, &s_float);
2736 return (x);
2737}
2738
2739static void change_bang(t_change *x)
2740{
2741 outlet_float(x->x_obj.ob_outlet, x->x_f);
2742}
2743
2744static void change_float(t_change *x, t_float f)
2745{
2746 if (f != x->x_f)
2747 {
2748 x->x_f = f;
2749 outlet_float(x->x_obj.ob_outlet, x->x_f);
2750 }
2751}
2752
2753static void change_set(t_change *x, t_float f)
2754{
2755 x->x_f = f;
2756}
2757
2758void change_setup(void)
2759{
2760 change_class = class_new(gensym("change"), (t_newmethod)change_new, 0,
2761 sizeof(t_change), 0, A_DEFFLOAT, 0);
2762 class_addbang(change_class, change_bang);
2763 class_addfloat(change_class, change_float);
2764 class_addmethod(change_class, (t_method)change_set, gensym("set"),
2765 A_DEFFLOAT, 0);
2766}
2767
2768/* -------------------- value ------------------------------ */
2769
2770static t_class *value_class, *vcommon_class;
2771
2772typedef struct vcommon
2773{
2774 t_pd c_pd;
2775 int c_refcount;
2776 t_float c_f;
2777} t_vcommon;
2778
2779typedef struct _value
2780{
2781 t_object x_obj;
2782 t_symbol *x_sym;
2783 t_float *x_floatstar;
2784} t_value;
2785
2786 /* get a pointer to a named floating-point variable. The variable
2787 belongs to a "vcommon" object, which is created if necessary. */
2788t_float *value_get(t_symbol *s)
2789{
2790 t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
2791 if (!c)
2792 {
2793 c = (t_vcommon *)pd_new(vcommon_class);
2794 c->c_f = 0;
2795 c->c_refcount = 0;
2796 pd_bind(&c->c_pd, s);
2797 }
2798 c->c_refcount++;
2799 return (&c->c_f);
2800}
2801
2802 /* release a variable. This only frees the "vcommon" resource when the
2803 last interested party releases it. */
2804void value_release(t_symbol *s)
2805{
2806 t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
2807 if (c)
2808 {
2809 if (!--c->c_refcount)
2810 {
2811 pd_unbind(&c->c_pd, s);
2812 pd_free(&c->c_pd);
2813 }
2814 }
2815 else bug("value_release");
2816}
2817
2818/*
2819 * value_getfloat -- obtain the float value of a "value" object
2820 * return 0 on success, 1 otherwise
2821 */
2822int
2823value_getfloat(t_symbol *s, t_float *f)
2824{
2825 t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
2826 if (!c)
2827 return (1);
2828 *f = c->c_f;
2829 return (0);
2830}
2831
2832/*
2833 * value_setfloat -- set the float value of a "value" object
2834 * return 0 on success, 1 otherwise
2835 */
2836int
2837value_setfloat(t_symbol *s, t_float f)
2838{
2839 t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
2840 if (!c)
2841 return (1);
2842 c->c_f = f;
2843 return (0);
2844}
2845
2846static void *value_new(t_symbol *s)
2847{
2848 t_value *x = (t_value *)pd_new(value_class);
2849 x->x_sym = s;
2850 x->x_floatstar = value_get(s);
2851 outlet_new(&x->x_obj, &s_float);
2852 return (x);
2853}
2854
2855static void value_bang(t_value *x)
2856{
2857 outlet_float(x->x_obj.ob_outlet, *x->x_floatstar);
2858}
2859
2860static void value_float(t_value *x, t_float f)
2861{
2862 *x->x_floatstar = f;
2863}
2864
2865static void value_ff(t_value *x)
2866{
2867 value_release(x->x_sym);
2868}
2869
2870static void value_setup(void)
2871{
2872 value_class = class_new(gensym("value"), (t_newmethod)value_new,
2873 (t_method)value_ff,
2874 sizeof(t_value), 0, A_DEFSYM, 0);
2875 class_addcreator((t_newmethod)value_new, gensym("v"), A_DEFSYM, 0);
2876 class_addbang(value_class, value_bang);
2877 class_addfloat(value_class, value_float);
2878 vcommon_class = class_new(gensym("value"), 0, 0,
2879 sizeof(t_vcommon), CLASS_PD, 0);
2880}
2881
2882/* -------------- overall setup routine for this file ----------------- */
2883
2884void x_connective_setup(void)
2885{
2886 pdint_setup();
2887 pdfloat_setup();
2888 pdsymbol_setup();
2889 bang_setup();
2890 send_setup();
2891 receive_setup();
2892 select_setup();
2893 route_setup();
2894 pack_setup();
2895 unpack_setup();
2896 trigger_setup();
2897 spigot_setup();
2898 moses_setup();
2899 until_setup();
2900 makefilename_setup();
2901 swap_setup();
2902 change_setup();
2903 value_setup();
2904}
diff --git a/apps/plugins/pdbox/PDa/src/x_gui.c b/apps/plugins/pdbox/PDa/src/x_gui.c
new file mode 100644
index 0000000000..edff70e8cd
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_gui.c
@@ -0,0 +1,754 @@
1/* Copyright (c) 1997-2000 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* dialogs. LATER, deal with the situation where the object goes
6away before the panel does... */
7
8#include "m_pd.h"
9#include <stdio.h>
10#include <string.h>
11#ifdef UNIX
12#include <unistd.h>
13#endif
14
15/* --------------------- graphics responder ---------------- */
16
17/* make one of these if you want to put up a dialog window but want to be
18protected from getting deleted and then having the dialog call you back. In
19this design the calling object doesn't have to keep the address of the dialog
20window around; instead we keep a list of all open dialogs. Any object that
21might have dialogs, when it is deleted, simply checks down the dialog window
22list and breaks off any dialogs that might later have sent messages to it.
23Only when the dialog window itself closes do we delete the gfxstub object. */
24
25static t_class *gfxstub_class;
26
27typedef struct _gfxstub
28{
29 t_pd x_pd;
30 t_pd *x_owner;
31 void *x_key;
32 t_symbol *x_sym;
33 struct _gfxstub *x_next;
34} t_gfxstub;
35
36static t_gfxstub *gfxstub_list;
37
38 /* create a new one. the "key" is an address by which the owner
39 will identify it later; if the owner only wants one dialog, this
40 could just be a pointer to the owner itself. The string "cmd"
41 is a TK command to create the dialog, with "%s" embedded in
42 it so we can provide a name by which the GUI can send us back
43 messages; e.g., "pdtk_canvas_dofont %s 10". */
44
45void gfxstub_new(t_pd *owner, void *key, const char *cmd)
46{
47 char buf[MAXPDSTRING];
48 char namebuf[80];
49 t_gfxstub *x;
50 t_symbol *s;
51 /* if any exists with matching key, no need to make a
52 new one; just tell tk to send it front. */
53 for (x = gfxstub_list; x; x = x->x_next)
54 {
55 if (x->x_key == key)
56 {
57 sys_vgui("raise .gfxstub%x\n", x);
58 sys_vgui("focus .gfxstub%x\n", x);
59 return;
60 }
61 }
62 if (strlen(cmd) + 84 > MAXPDSTRING)
63 return;
64 x = (t_gfxstub *)pd_new(gfxstub_class);
65 sprintf(namebuf, ".gfxstub%x", (t_int)x);
66
67 s = gensym(namebuf);
68 pd_bind(&x->x_pd, s);
69 x->x_owner = owner;
70 x->x_sym = s;
71 x->x_key = key;
72 x->x_next = gfxstub_list;
73 gfxstub_list = x;
74 sprintf(buf, cmd, s->s_name);
75 sys_gui(buf);
76}
77
78static void gfxstub_offlist(t_gfxstub *x)
79{
80 t_gfxstub *y1, *y2;
81 if (gfxstub_list == x)
82 gfxstub_list = x->x_next;
83 else for (y1 = gfxstub_list; y2 = y1->x_next; y1 = y2)
84 if (y2 == x)
85 {
86 y1->x_next = y2->x_next;
87 break;
88 }
89}
90
91 /* if the owner disappears, we still may have to stay around until our
92 dialog window signs off. Anyway we can now tell the GUI to destroy the
93 window. */
94void gfxstub_deleteforkey(void *key)
95{
96 t_gfxstub *y;
97 int didit = 1;
98 while (didit)
99 {
100 didit = 0;
101 for (y = gfxstub_list; y; y = y->x_next)
102 {
103 if (y->x_key == key)
104 {
105 sys_vgui("destroy .gfxstub%x\n", y);
106 y->x_owner = 0;
107 gfxstub_offlist(y);
108 didit = 1;
109 break;
110 }
111 }
112 }
113}
114
115/* --------- pd messages for gfxstub (these come from the GUI) ---------- */
116
117 /* "cancel" to request that we close the dialog window. */
118static void gfxstub_cancel(t_gfxstub *x)
119{
120 gfxstub_deleteforkey(x->x_key);
121}
122
123 /* "signoff" comes from the GUI to say the dialog window closed. */
124static void gfxstub_signoff(t_gfxstub *x)
125{
126 gfxstub_offlist(x);
127 pd_free(&x->x_pd);
128}
129
130static t_binbuf *gfxstub_binbuf;
131
132 /* a series of "data" messages rebuilds a scalar */
133static void gfxstub_data(t_gfxstub *x, t_symbol *s, int argc, t_atom *argv)
134{
135 if (!gfxstub_binbuf)
136 gfxstub_binbuf = binbuf_new();
137 binbuf_add(gfxstub_binbuf, argc, argv);
138 binbuf_addsemi(gfxstub_binbuf);
139}
140 /* the "end" message terminates rebuilding the scalar */
141static void gfxstub_end(t_gfxstub *x)
142{
143 canvas_dataproperties((t_canvas *)x->x_owner,
144 (t_scalar *)x->x_key, gfxstub_binbuf);
145 binbuf_free(gfxstub_binbuf);
146 gfxstub_binbuf = 0;
147}
148
149 /* anything else is a message from the dialog window to the owner;
150 just forward it. */
151static void gfxstub_anything(t_gfxstub *x, t_symbol *s, int argc, t_atom *argv)
152{
153 if (x->x_owner)
154 pd_typedmess(x->x_owner, s, argc, argv);
155}
156
157static void gfxstub_free(t_gfxstub *x)
158{
159 pd_unbind(&x->x_pd, x->x_sym);
160}
161
162static void gfxstub_setup(void)
163{
164 gfxstub_class = class_new(gensym("gfxstub"), (t_newmethod)gfxstub_new,
165 (t_method)gfxstub_free,
166 sizeof(t_gfxstub), CLASS_PD, 0);
167 class_addanything(gfxstub_class, gfxstub_anything);
168 class_addmethod(gfxstub_class, (t_method)gfxstub_signoff,
169 gensym("signoff"), 0);
170 class_addmethod(gfxstub_class, (t_method)gfxstub_data,
171 gensym("data"), A_GIMME, 0);
172 class_addmethod(gfxstub_class, (t_method)gfxstub_end,
173 gensym("end"), 0);
174 class_addmethod(gfxstub_class, (t_method)gfxstub_cancel,
175 gensym("cancel"), 0);
176}
177
178/* -------------------------- openpanel ------------------------------ */
179
180static t_class *openpanel_class;
181
182typedef struct _openpanel
183{
184 t_object x_obj;
185 t_symbol *x_s;
186} t_openpanel;
187
188static void *openpanel_new(void)
189{
190 char buf[50];
191 t_openpanel *x = (t_openpanel *)pd_new(openpanel_class);
192 sprintf(buf, "d%x", (t_int)x);
193 x->x_s = gensym(buf);
194 pd_bind(&x->x_obj.ob_pd, x->x_s);
195 outlet_new(&x->x_obj, &s_symbol);
196 return (x);
197}
198
199static void openpanel_bang(t_openpanel *x)
200{
201 sys_vgui("pdtk_openpanel %s\n", x->x_s->s_name);
202}
203
204static void openpanel_symbol(t_openpanel *x, t_symbol *s)
205{
206 outlet_symbol(x->x_obj.ob_outlet, s);
207}
208
209static void openpanel_free(t_openpanel *x)
210{
211 pd_unbind(&x->x_obj.ob_pd, x->x_s);
212}
213
214static void openpanel_setup(void)
215{
216 openpanel_class = class_new(gensym("openpanel"),
217 (t_newmethod)openpanel_new, (t_method)openpanel_free,
218 sizeof(t_openpanel), 0, A_DEFFLOAT, 0);
219 class_addbang(openpanel_class, openpanel_bang);
220 class_addsymbol(openpanel_class, openpanel_symbol);
221}
222
223/* -------------------------- savepanel ------------------------------ */
224
225static t_class *savepanel_class;
226
227typedef struct _savepanel
228{
229 t_object x_obj;
230 t_symbol *x_s;
231} t_savepanel;
232
233static void *savepanel_new(void)
234{
235 char buf[50];
236 t_savepanel *x = (t_savepanel *)pd_new(savepanel_class);
237 sprintf(buf, "d%x", (t_int)x);
238 x->x_s = gensym(buf);
239 pd_bind(&x->x_obj.ob_pd, x->x_s);
240 outlet_new(&x->x_obj, &s_symbol);
241 return (x);
242}
243
244static void savepanel_bang(t_savepanel *x)
245{
246 sys_vgui("pdtk_savepanel %s\n", x->x_s->s_name);
247}
248
249static void savepanel_symbol(t_savepanel *x, t_symbol *s)
250{
251 outlet_symbol(x->x_obj.ob_outlet, s);
252}
253
254static void savepanel_free(t_savepanel *x)
255{
256 pd_unbind(&x->x_obj.ob_pd, x->x_s);
257}
258
259static void savepanel_setup(void)
260{
261 savepanel_class = class_new(gensym("savepanel"),
262 (t_newmethod)savepanel_new, (t_method)savepanel_free,
263 sizeof(t_savepanel), 0, A_DEFFLOAT, 0);
264 class_addbang(savepanel_class, savepanel_bang);
265 class_addsymbol(savepanel_class, savepanel_symbol);
266}
267
268/* ---------------------- key and its relatives ------------------ */
269
270static t_symbol *key_sym, *keyup_sym, *keyname_sym;
271static t_class *key_class, *keyup_class, *keyname_class;
272
273typedef struct _key
274{
275 t_object x_obj;
276} t_key;
277
278static void *key_new( void)
279{
280 t_key *x = (t_key *)pd_new(key_class);
281 outlet_new(&x->x_obj, &s_float);
282 pd_bind(&x->x_obj.ob_pd, key_sym);
283 return (x);
284}
285
286static void key_float(t_key *x, t_floatarg f)
287{
288 outlet_float(x->x_obj.ob_outlet, f);
289}
290
291static void key_free(t_key *x)
292{
293 pd_unbind(&x->x_obj.ob_pd, key_sym);
294}
295
296typedef struct _keyup
297{
298 t_object x_obj;
299} t_keyup;
300
301static void *keyup_new( void)
302{
303 t_keyup *x = (t_keyup *)pd_new(keyup_class);
304 outlet_new(&x->x_obj, &s_float);
305 pd_bind(&x->x_obj.ob_pd, keyup_sym);
306 return (x);
307}
308
309static void keyup_float(t_keyup *x, t_floatarg f)
310{
311 outlet_float(x->x_obj.ob_outlet, f);
312}
313
314static void keyup_free(t_keyup *x)
315{
316 pd_unbind(&x->x_obj.ob_pd, keyup_sym);
317}
318
319typedef struct _keyname
320{
321 t_object x_obj;
322 t_outlet *x_outlet1;
323 t_outlet *x_outlet2;
324} t_keyname;
325
326static void *keyname_new( void)
327{
328 t_keyname *x = (t_keyname *)pd_new(keyname_class);
329 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
330 x->x_outlet2 = outlet_new(&x->x_obj, &s_symbol);
331 pd_bind(&x->x_obj.ob_pd, keyname_sym);
332 return (x);
333}
334
335static void keyname_list(t_keyname *x, t_symbol *s, int ac, t_atom *av)
336{
337 outlet_symbol(x->x_outlet2, atom_getsymbolarg(1, ac, av));
338 outlet_float(x->x_outlet1, atom_getfloatarg(0, ac, av));
339}
340
341static void keyname_free(t_keyname *x)
342{
343 pd_unbind(&x->x_obj.ob_pd, keyname_sym);
344}
345
346static void key_setup(void)
347{
348 key_class = class_new(gensym("key"),
349 (t_newmethod)key_new, (t_method)key_free,
350 sizeof(t_key), CLASS_NOINLET, 0);
351 class_addfloat(key_class, key_float);
352 key_sym = gensym("#key");
353
354 keyup_class = class_new(gensym("keyup"),
355 (t_newmethod)keyup_new, (t_method)keyup_free,
356 sizeof(t_keyup), CLASS_NOINLET, 0);
357 class_addfloat(keyup_class, keyup_float);
358 keyup_sym = gensym("#keyup");
359 class_sethelpsymbol(keyup_class, gensym("key"));
360
361 keyname_class = class_new(gensym("keyname"),
362 (t_newmethod)keyname_new, (t_method)keyname_free,
363 sizeof(t_keyname), CLASS_NOINLET, 0);
364 class_addlist(keyname_class, keyname_list);
365 keyname_sym = gensym("#keyname");
366 class_sethelpsymbol(keyname_class, gensym("key"));
367}
368
369/* -------------------------- setup routine ------------------------------ */
370
371void x_gui_setup(void)
372{
373 gfxstub_setup();
374 openpanel_setup();
375 savepanel_setup();
376 key_setup();
377}
378/* Copyright (c) 1997-2000 Miller Puckette.
379* For information on usage and redistribution, and for a DISCLAIMER OF ALL
380* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
381
382/* dialogs. LATER, deal with the situation where the object goes
383away before the panel does... */
384
385#include "m_pd.h"
386#include <stdio.h>
387#include <string.h>
388#ifdef UNIX
389#include <unistd.h>
390#endif
391
392/* --------------------- graphics responder ---------------- */
393
394/* make one of these if you want to put up a dialog window but want to be
395protected from getting deleted and then having the dialog call you back. In
396this design the calling object doesn't have to keep the address of the dialog
397window around; instead we keep a list of all open dialogs. Any object that
398might have dialogs, when it is deleted, simply checks down the dialog window
399list and breaks off any dialogs that might later have sent messages to it.
400Only when the dialog window itself closes do we delete the gfxstub object. */
401
402static t_class *gfxstub_class;
403
404typedef struct _gfxstub
405{
406 t_pd x_pd;
407 t_pd *x_owner;
408 void *x_key;
409 t_symbol *x_sym;
410 struct _gfxstub *x_next;
411} t_gfxstub;
412
413static t_gfxstub *gfxstub_list;
414
415 /* create a new one. the "key" is an address by which the owner
416 will identify it later; if the owner only wants one dialog, this
417 could just be a pointer to the owner itself. The string "cmd"
418 is a TK command to create the dialog, with "%s" embedded in
419 it so we can provide a name by which the GUI can send us back
420 messages; e.g., "pdtk_canvas_dofont %s 10". */
421
422void gfxstub_new(t_pd *owner, void *key, const char *cmd)
423{
424 char buf[MAXPDSTRING];
425 char namebuf[80];
426 t_gfxstub *x;
427 t_symbol *s;
428 /* if any exists with matching key, no need to make a
429 new one; just tell tk to send it front. */
430 for (x = gfxstub_list; x; x = x->x_next)
431 {
432 if (x->x_key == key)
433 {
434 sys_vgui("raise .gfxstub%x\n", x);
435 sys_vgui("focus .gfxstub%x\n", x);
436 return;
437 }
438 }
439 if (strlen(cmd) + 84 > MAXPDSTRING)
440 return;
441 x = (t_gfxstub *)pd_new(gfxstub_class);
442 sprintf(namebuf, ".gfxstub%x", (t_int)x);
443
444 s = gensym(namebuf);
445 pd_bind(&x->x_pd, s);
446 x->x_owner = owner;
447 x->x_sym = s;
448 x->x_key = key;
449 x->x_next = gfxstub_list;
450 gfxstub_list = x;
451 sprintf(buf, cmd, s->s_name);
452 sys_gui(buf);
453}
454
455static void gfxstub_offlist(t_gfxstub *x)
456{
457 t_gfxstub *y1, *y2;
458 if (gfxstub_list == x)
459 gfxstub_list = x->x_next;
460 else for (y1 = gfxstub_list; y2 = y1->x_next; y1 = y2)
461 if (y2 == x)
462 {
463 y1->x_next = y2->x_next;
464 break;
465 }
466}
467
468 /* if the owner disappears, we still may have to stay around until our
469 dialog window signs off. Anyway we can now tell the GUI to destroy the
470 window. */
471void gfxstub_deleteforkey(void *key)
472{
473 t_gfxstub *y;
474 int didit = 1;
475 while (didit)
476 {
477 didit = 0;
478 for (y = gfxstub_list; y; y = y->x_next)
479 {
480 if (y->x_key == key)
481 {
482 sys_vgui("destroy .gfxstub%x\n", y);
483 y->x_owner = 0;
484 gfxstub_offlist(y);
485 didit = 1;
486 break;
487 }
488 }
489 }
490}
491
492/* --------- pd messages for gfxstub (these come from the GUI) ---------- */
493
494 /* "cancel" to request that we close the dialog window. */
495static void gfxstub_cancel(t_gfxstub *x)
496{
497 gfxstub_deleteforkey(x->x_key);
498}
499
500 /* "signoff" comes from the GUI to say the dialog window closed. */
501static void gfxstub_signoff(t_gfxstub *x)
502{
503 gfxstub_offlist(x);
504 pd_free(&x->x_pd);
505}
506
507static t_binbuf *gfxstub_binbuf;
508
509 /* a series of "data" messages rebuilds a scalar */
510static void gfxstub_data(t_gfxstub *x, t_symbol *s, int argc, t_atom *argv)
511{
512 if (!gfxstub_binbuf)
513 gfxstub_binbuf = binbuf_new();
514 binbuf_add(gfxstub_binbuf, argc, argv);
515 binbuf_addsemi(gfxstub_binbuf);
516}
517 /* the "end" message terminates rebuilding the scalar */
518static void gfxstub_end(t_gfxstub *x)
519{
520 canvas_dataproperties((t_canvas *)x->x_owner,
521 (t_scalar *)x->x_key, gfxstub_binbuf);
522 binbuf_free(gfxstub_binbuf);
523 gfxstub_binbuf = 0;
524}
525
526 /* anything else is a message from the dialog window to the owner;
527 just forward it. */
528static void gfxstub_anything(t_gfxstub *x, t_symbol *s, int argc, t_atom *argv)
529{
530 if (x->x_owner)
531 pd_typedmess(x->x_owner, s, argc, argv);
532}
533
534static void gfxstub_free(t_gfxstub *x)
535{
536 pd_unbind(&x->x_pd, x->x_sym);
537}
538
539static void gfxstub_setup(void)
540{
541 gfxstub_class = class_new(gensym("gfxstub"), (t_newmethod)gfxstub_new,
542 (t_method)gfxstub_free,
543 sizeof(t_gfxstub), CLASS_PD, 0);
544 class_addanything(gfxstub_class, gfxstub_anything);
545 class_addmethod(gfxstub_class, (t_method)gfxstub_signoff,
546 gensym("signoff"), 0);
547 class_addmethod(gfxstub_class, (t_method)gfxstub_data,
548 gensym("data"), A_GIMME, 0);
549 class_addmethod(gfxstub_class, (t_method)gfxstub_end,
550 gensym("end"), 0);
551 class_addmethod(gfxstub_class, (t_method)gfxstub_cancel,
552 gensym("cancel"), 0);
553}
554
555/* -------------------------- openpanel ------------------------------ */
556
557static t_class *openpanel_class;
558
559typedef struct _openpanel
560{
561 t_object x_obj;
562 t_symbol *x_s;
563} t_openpanel;
564
565static void *openpanel_new(void)
566{
567 char buf[50];
568 t_openpanel *x = (t_openpanel *)pd_new(openpanel_class);
569 sprintf(buf, "d%x", (t_int)x);
570 x->x_s = gensym(buf);
571 pd_bind(&x->x_obj.ob_pd, x->x_s);
572 outlet_new(&x->x_obj, &s_symbol);
573 return (x);
574}
575
576static void openpanel_bang(t_openpanel *x)
577{
578 sys_vgui("pdtk_openpanel %s\n", x->x_s->s_name);
579}
580
581static void openpanel_symbol(t_openpanel *x, t_symbol *s)
582{
583 outlet_symbol(x->x_obj.ob_outlet, s);
584}
585
586static void openpanel_free(t_openpanel *x)
587{
588 pd_unbind(&x->x_obj.ob_pd, x->x_s);
589}
590
591static void openpanel_setup(void)
592{
593 openpanel_class = class_new(gensym("openpanel"),
594 (t_newmethod)openpanel_new, (t_method)openpanel_free,
595 sizeof(t_openpanel), 0, A_DEFFLOAT, 0);
596 class_addbang(openpanel_class, openpanel_bang);
597 class_addsymbol(openpanel_class, openpanel_symbol);
598}
599
600/* -------------------------- savepanel ------------------------------ */
601
602static t_class *savepanel_class;
603
604typedef struct _savepanel
605{
606 t_object x_obj;
607 t_symbol *x_s;
608} t_savepanel;
609
610static void *savepanel_new(void)
611{
612 char buf[50];
613 t_savepanel *x = (t_savepanel *)pd_new(savepanel_class);
614 sprintf(buf, "d%x", (t_int)x);
615 x->x_s = gensym(buf);
616 pd_bind(&x->x_obj.ob_pd, x->x_s);
617 outlet_new(&x->x_obj, &s_symbol);
618 return (x);
619}
620
621static void savepanel_bang(t_savepanel *x)
622{
623 sys_vgui("pdtk_savepanel %s\n", x->x_s->s_name);
624}
625
626static void savepanel_symbol(t_savepanel *x, t_symbol *s)
627{
628 outlet_symbol(x->x_obj.ob_outlet, s);
629}
630
631static void savepanel_free(t_savepanel *x)
632{
633 pd_unbind(&x->x_obj.ob_pd, x->x_s);
634}
635
636static void savepanel_setup(void)
637{
638 savepanel_class = class_new(gensym("savepanel"),
639 (t_newmethod)savepanel_new, (t_method)savepanel_free,
640 sizeof(t_savepanel), 0, A_DEFFLOAT, 0);
641 class_addbang(savepanel_class, savepanel_bang);
642 class_addsymbol(savepanel_class, savepanel_symbol);
643}
644
645/* ---------------------- key and its relatives ------------------ */
646
647static t_symbol *key_sym, *keyup_sym, *keyname_sym;
648static t_class *key_class, *keyup_class, *keyname_class;
649
650typedef struct _key
651{
652 t_object x_obj;
653} t_key;
654
655static void *key_new( void)
656{
657 t_key *x = (t_key *)pd_new(key_class);
658 outlet_new(&x->x_obj, &s_float);
659 pd_bind(&x->x_obj.ob_pd, key_sym);
660 return (x);
661}
662
663static void key_float(t_key *x, t_floatarg f)
664{
665 outlet_float(x->x_obj.ob_outlet, f);
666}
667
668static void key_free(t_key *x)
669{
670 pd_unbind(&x->x_obj.ob_pd, key_sym);
671}
672
673typedef struct _keyup
674{
675 t_object x_obj;
676} t_keyup;
677
678static void *keyup_new( void)
679{
680 t_keyup *x = (t_keyup *)pd_new(keyup_class);
681 outlet_new(&x->x_obj, &s_float);
682 pd_bind(&x->x_obj.ob_pd, keyup_sym);
683 return (x);
684}
685
686static void keyup_float(t_keyup *x, t_floatarg f)
687{
688 outlet_float(x->x_obj.ob_outlet, f);
689}
690
691static void keyup_free(t_keyup *x)
692{
693 pd_unbind(&x->x_obj.ob_pd, keyup_sym);
694}
695
696typedef struct _keyname
697{
698 t_object x_obj;
699 t_outlet *x_outlet1;
700 t_outlet *x_outlet2;
701} t_keyname;
702
703static void *keyname_new( void)
704{
705 t_keyname *x = (t_keyname *)pd_new(keyname_class);
706 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
707 x->x_outlet2 = outlet_new(&x->x_obj, &s_symbol);
708 pd_bind(&x->x_obj.ob_pd, keyname_sym);
709 return (x);
710}
711
712static void keyname_list(t_keyname *x, t_symbol *s, int ac, t_atom *av)
713{
714 outlet_symbol(x->x_outlet2, atom_getsymbolarg(1, ac, av));
715 outlet_float(x->x_outlet1, atom_getfloatarg(0, ac, av));
716}
717
718static void keyname_free(t_keyname *x)
719{
720 pd_unbind(&x->x_obj.ob_pd, keyname_sym);
721}
722
723static void key_setup(void)
724{
725 key_class = class_new(gensym("key"),
726 (t_newmethod)key_new, (t_method)key_free,
727 sizeof(t_key), CLASS_NOINLET, 0);
728 class_addfloat(key_class, key_float);
729 key_sym = gensym("#key");
730
731 keyup_class = class_new(gensym("keyup"),
732 (t_newmethod)keyup_new, (t_method)keyup_free,
733 sizeof(t_keyup), CLASS_NOINLET, 0);
734 class_addfloat(keyup_class, keyup_float);
735 keyup_sym = gensym("#keyup");
736 class_sethelpsymbol(keyup_class, gensym("key"));
737
738 keyname_class = class_new(gensym("keyname"),
739 (t_newmethod)keyname_new, (t_method)keyname_free,
740 sizeof(t_keyname), CLASS_NOINLET, 0);
741 class_addlist(keyname_class, keyname_list);
742 keyname_sym = gensym("#keyname");
743 class_sethelpsymbol(keyname_class, gensym("key"));
744}
745
746/* -------------------------- setup routine ------------------------------ */
747
748void x_gui_setup(void)
749{
750 gfxstub_setup();
751 openpanel_setup();
752 savepanel_setup();
753 key_setup();
754}
diff --git a/apps/plugins/pdbox/PDa/src/x_interface.c b/apps/plugins/pdbox/PDa/src/x_interface.c
new file mode 100644
index 0000000000..f6ab350a91
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_interface.c
@@ -0,0 +1,156 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* interface objects */
6
7#include "m_pd.h"
8
9/* -------------------------- print ------------------------------ */
10static t_class *print_class;
11
12typedef struct _print
13{
14 t_object x_obj;
15 t_symbol *x_sym;
16} t_print;
17
18static void *print_new(t_symbol *s)
19{
20 t_print *x = (t_print *)pd_new(print_class);
21 if (*s->s_name) x->x_sym = s;
22 else x->x_sym = gensym("");
23 return (x);
24}
25
26static void print_bang(t_print *x)
27{
28 post("%sbang", x->x_sym->s_name);
29}
30
31static void print_pointer(t_print *x, t_gpointer *gp)
32{
33 post("%s(gpointer)", x->x_sym->s_name);
34}
35
36static void print_float(t_print *x, t_float f)
37{
38 post("%s%g", x->x_sym->s_name, f);
39}
40
41static void print_list(t_print *x, t_symbol *s, int argc, t_atom *argv)
42{
43 int i;
44 char buf[80];
45 if (argc && argv->a_type != A_SYMBOL) startpost("%s:", x->x_sym->s_name);
46 else startpost("%s%s", x->x_sym->s_name,
47 (argc > 1 ? s_list.s_name : (argc == 1 ? s_symbol.s_name :
48 s_bang.s_name)));
49 postatom(argc, argv);
50 endpost();
51}
52
53static void print_anything(t_print *x, t_symbol *s, int argc, t_atom *argv)
54{
55 int i;
56 char buf[80];
57 startpost("%s%s", x->x_sym->s_name, s->s_name);
58 postatom(argc, argv);
59 endpost();
60}
61
62static void print_setup(void)
63{
64 print_class = class_new(gensym("print"), (t_newmethod)print_new, 0,
65 sizeof(t_print), 0, A_DEFSYM, 0);
66 class_addbang(print_class, print_bang);
67 class_addfloat(print_class, print_float);
68 class_addpointer(print_class, print_pointer);
69 class_addlist(print_class, print_list);
70 class_addanything(print_class, print_anything);
71}
72
73
74
75void x_interface_setup(void)
76{
77 print_setup();
78}
79/* Copyright (c) 1997-1999 Miller Puckette.
80* For information on usage and redistribution, and for a DISCLAIMER OF ALL
81* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
82
83/* interface objects */
84
85#include "m_pd.h"
86
87/* -------------------------- print ------------------------------ */
88static t_class *print_class;
89
90typedef struct _print
91{
92 t_object x_obj;
93 t_symbol *x_sym;
94} t_print;
95
96static void *print_new(t_symbol *s)
97{
98 t_print *x = (t_print *)pd_new(print_class);
99 if (*s->s_name) x->x_sym = s;
100 else x->x_sym = gensym("");
101 return (x);
102}
103
104static void print_bang(t_print *x)
105{
106 post("%sbang", x->x_sym->s_name);
107}
108
109static void print_pointer(t_print *x, t_gpointer *gp)
110{
111 post("%s(gpointer)", x->x_sym->s_name);
112}
113
114static void print_float(t_print *x, t_float f)
115{
116 post("%s%g", x->x_sym->s_name, f);
117}
118
119static void print_list(t_print *x, t_symbol *s, int argc, t_atom *argv)
120{
121 int i;
122 char buf[80];
123 if (argc && argv->a_type != A_SYMBOL) startpost("%s:", x->x_sym->s_name);
124 else startpost("%s%s", x->x_sym->s_name,
125 (argc > 1 ? s_list.s_name : (argc == 1 ? s_symbol.s_name :
126 s_bang.s_name)));
127 postatom(argc, argv);
128 endpost();
129}
130
131static void print_anything(t_print *x, t_symbol *s, int argc, t_atom *argv)
132{
133 int i;
134 char buf[80];
135 startpost("%s%s", x->x_sym->s_name, s->s_name);
136 postatom(argc, argv);
137 endpost();
138}
139
140static void print_setup(void)
141{
142 print_class = class_new(gensym("print"), (t_newmethod)print_new, 0,
143 sizeof(t_print), 0, A_DEFSYM, 0);
144 class_addbang(print_class, print_bang);
145 class_addfloat(print_class, print_float);
146 class_addpointer(print_class, print_pointer);
147 class_addlist(print_class, print_list);
148 class_addanything(print_class, print_anything);
149}
150
151
152
153void x_interface_setup(void)
154{
155 print_setup();
156}
diff --git a/apps/plugins/pdbox/PDa/src/x_midi.c b/apps/plugins/pdbox/PDa/src/x_midi.c
new file mode 100644
index 0000000000..a71000f121
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_midi.c
@@ -0,0 +1,2626 @@
1/* Copyright (c) 1997-2001 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* MIDI. */
6
7#include "m_pd.h"
8void outmidi_noteon(int portno, int channel, int pitch, int velo);
9void outmidi_controlchange(int portno, int channel, int ctlno, int value);
10void outmidi_programchange(int portno, int channel, int value);
11void outmidi_pitchbend(int portno, int channel, int value);
12void outmidi_aftertouch(int portno, int channel, int value);
13void outmidi_polyaftertouch(int portno, int channel, int pitch, int value);
14void outmidi_mclk(int portno);
15
16/* ----------------------- midiin and sysexin ------------------------- */
17
18static t_symbol *midiin_sym, *sysexin_sym;
19
20static t_class *midiin_class, *sysexin_class;
21
22typedef struct _midiin
23{
24 t_object x_obj;
25 t_outlet *x_outlet1;
26 t_outlet *x_outlet2;
27} t_midiin;
28
29static void *midiin_new( void)
30{
31 t_midiin *x = (t_midiin *)pd_new(midiin_class);
32 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
33 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
34 pd_bind(&x->x_obj.ob_pd, midiin_sym);
35#ifndef __linux__
36 pd_error(x, "midiin: works under Linux only");
37#endif
38 return (x);
39}
40
41static void midiin_list(t_midiin *x, t_symbol *s, int ac, t_atom *av)
42{
43 outlet_float(x->x_outlet2, atom_getfloatarg(1, ac, av) + 1);
44 outlet_float(x->x_outlet1, atom_getfloatarg(0, ac, av));
45}
46
47static void midiin_free(t_midiin *x)
48{
49 pd_unbind(&x->x_obj.ob_pd, midiin_sym);
50}
51
52static void *sysexin_new( void)
53{
54 t_midiin *x = (t_midiin *)pd_new(sysexin_class);
55 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
56 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
57 pd_bind(&x->x_obj.ob_pd, sysexin_sym);
58#ifndef __linux__
59 pd_error(x, "sysexin: works under Linux only");
60#endif
61 return (x);
62}
63
64static void sysexin_free(t_midiin *x)
65{
66 pd_unbind(&x->x_obj.ob_pd, sysexin_sym);
67}
68
69static void midiin_setup(void)
70{
71 midiin_class = class_new(gensym("midiin"), (t_newmethod)midiin_new,
72 (t_method)midiin_free, sizeof(t_midiin),
73 CLASS_NOINLET, A_DEFFLOAT, 0);
74 class_addlist(midiin_class, midiin_list);
75 class_sethelpsymbol(midiin_class, gensym("midi"));
76 midiin_sym = gensym("#midiin");
77
78 sysexin_class = class_new(gensym("sysexin"), (t_newmethod)sysexin_new,
79 (t_method)sysexin_free, sizeof(t_midiin),
80 CLASS_NOINLET, A_DEFFLOAT, 0);
81 class_addlist(sysexin_class, midiin_list);
82 class_sethelpsymbol(sysexin_class, gensym("midi"));
83 sysexin_sym = gensym("#sysexin");
84}
85
86void inmidi_byte(int portno, int byte)
87{
88 t_atom at[2];
89 if (midiin_sym->s_thing)
90 {
91 SETFLOAT(at, byte);
92 SETFLOAT(at+1, portno + 1);
93 pd_list(midiin_sym->s_thing, 0, 2, at);
94 }
95}
96
97void inmidi_sysex(int portno, int byte)
98{
99 t_atom at[2];
100 if (sysexin_sym->s_thing)
101 {
102 SETFLOAT(at, byte);
103 SETFLOAT(at+1, portno + 1);
104 pd_list(sysexin_sym->s_thing, 0, 2, at);
105 }
106}
107
108/* ----------------------- notein ------------------------- */
109
110static t_symbol *notein_sym;
111
112static t_class *notein_class;
113
114typedef struct _notein
115{
116 t_object x_obj;
117 t_float x_channel;
118 t_outlet *x_outlet1;
119 t_outlet *x_outlet2;
120 t_outlet *x_outlet3;
121} t_notein;
122
123static void *notein_new(t_floatarg f)
124{
125 t_notein *x = (t_notein *)pd_new(notein_class);
126 x->x_channel = f;
127 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
128 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
129 if (f == 0) x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
130 pd_bind(&x->x_obj.ob_pd, notein_sym);
131 return (x);
132}
133
134static void notein_list(t_notein *x, t_symbol *s, int argc, t_atom *argv)
135{
136 float pitch = atom_getfloatarg(0, argc, argv);
137 float velo = atom_getfloatarg(1, argc, argv);
138 float channel = atom_getfloatarg(2, argc, argv);
139 if (x->x_channel != 0)
140 {
141 if (channel != x->x_channel) return;
142 outlet_float(x->x_outlet2, velo);
143 outlet_float(x->x_outlet1, pitch);
144 }
145 else
146 {
147 outlet_float(x->x_outlet3, channel);
148 outlet_float(x->x_outlet2, velo);
149 outlet_float(x->x_outlet1, pitch);
150 }
151}
152
153static void notein_free(t_notein *x)
154{
155 pd_unbind(&x->x_obj.ob_pd, notein_sym);
156}
157
158static void notein_setup(void)
159{
160 notein_class = class_new(gensym("notein"), (t_newmethod)notein_new,
161 (t_method)notein_free, sizeof(t_notein), CLASS_NOINLET, A_DEFFLOAT, 0);
162 class_addlist(notein_class, notein_list);
163 class_sethelpsymbol(notein_class, gensym("midi"));
164 notein_sym = gensym("#notein");
165}
166
167void inmidi_noteon(int portno, int channel, int pitch, int velo)
168{
169 if (notein_sym->s_thing)
170 {
171 t_atom at[3];
172 SETFLOAT(at, pitch);
173 SETFLOAT(at+1, velo);
174 SETFLOAT(at+2, (channel + (portno << 4) + 1));
175 pd_list(notein_sym->s_thing, &s_list, 3, at);
176 }
177}
178
179/* ----------------------- ctlin ------------------------- */
180
181static t_symbol *ctlin_sym;
182
183static t_class *ctlin_class;
184
185typedef struct _ctlin
186{
187 t_object x_obj;
188 t_float x_channel;
189 t_float x_ctlno;
190 t_outlet *x_outlet1;
191 t_outlet *x_outlet2;
192 t_outlet *x_outlet3;
193} t_ctlin;
194
195static void *ctlin_new(t_symbol *s, int argc, t_atom *argv)
196{
197 int ctlno, channel;
198 t_ctlin *x = (t_ctlin *)pd_new(ctlin_class);
199 if (!argc) ctlno = -1;
200 else ctlno = atom_getfloatarg(0, argc, argv);
201 channel = atom_getfloatarg(1, argc, argv);
202 x->x_channel = channel;
203 x->x_ctlno = ctlno;
204 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
205 if (!channel)
206 {
207 if (x->x_ctlno < 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
208 x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
209 }
210 pd_bind(&x->x_obj.ob_pd, ctlin_sym);
211 return (x);
212}
213
214static void ctlin_list(t_ctlin *x, t_symbol *s, int argc, t_atom *argv)
215{
216 t_float ctlnumber = atom_getfloatarg(0, argc, argv);
217 t_float value = atom_getfloatarg(1, argc, argv);
218 t_float channel = atom_getfloatarg(2, argc, argv);
219 if (x->x_ctlno >= 0 && x->x_ctlno != ctlnumber) return;
220 if (x->x_channel > 0 && x->x_channel != channel) return;
221 if (x->x_channel == 0) outlet_float(x->x_outlet3, channel);
222 if (x->x_ctlno < 0) outlet_float(x->x_outlet2, ctlnumber);
223 outlet_float(x->x_outlet1, value);
224}
225
226static void ctlin_free(t_ctlin *x)
227{
228 pd_unbind(&x->x_obj.ob_pd, ctlin_sym);
229}
230
231static void ctlin_setup(void)
232{
233 ctlin_class = class_new(gensym("ctlin"), (t_newmethod)ctlin_new,
234 (t_method)ctlin_free, sizeof(t_ctlin),
235 CLASS_NOINLET, A_GIMME, 0);
236 class_addlist(ctlin_class, ctlin_list);
237 class_sethelpsymbol(ctlin_class, gensym("midi"));
238 ctlin_sym = gensym("#ctlin");
239}
240
241void inmidi_controlchange(int portno, int channel, int ctlnumber, int value)
242{
243 if (ctlin_sym->s_thing)
244 {
245 t_atom at[3];
246 SETFLOAT(at, ctlnumber);
247 SETFLOAT(at+1, value);
248 SETFLOAT(at+2, (channel + (portno << 4) + 1));
249 pd_list(ctlin_sym->s_thing, &s_list, 3, at);
250 }
251}
252
253/* ----------------------- pgmin ------------------------- */
254
255static t_symbol *pgmin_sym;
256
257static t_class *pgmin_class;
258
259typedef struct _pgmin
260{
261 t_object x_obj;
262 t_float x_channel;
263 t_outlet *x_outlet1;
264 t_outlet *x_outlet2;
265} t_pgmin;
266
267static void *pgmin_new(t_floatarg f)
268{
269 t_pgmin *x = (t_pgmin *)pd_new(pgmin_class);
270 x->x_channel = f;
271 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
272 if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
273 pd_bind(&x->x_obj.ob_pd, pgmin_sym);
274 return (x);
275}
276
277static void pgmin_list(t_pgmin *x, t_symbol *s, int argc, t_atom *argv)
278{
279 float value = atom_getfloatarg(0, argc, argv);
280 float channel = atom_getfloatarg(1, argc, argv);
281 if (x->x_channel != 0)
282 {
283 if (channel != x->x_channel) return;
284 outlet_float(x->x_outlet1, value);
285 }
286 else
287 {
288 outlet_float(x->x_outlet2, channel);
289 outlet_float(x->x_outlet1, value);
290 }
291}
292
293static void pgmin_free(t_pgmin *x)
294{
295 pd_unbind(&x->x_obj.ob_pd, pgmin_sym);
296}
297
298static void pgmin_setup(void)
299{
300 pgmin_class = class_new(gensym("pgmin"), (t_newmethod)pgmin_new,
301 (t_method)pgmin_free, sizeof(t_pgmin),
302 CLASS_NOINLET, A_DEFFLOAT, 0);
303 class_addlist(pgmin_class, pgmin_list);
304 class_sethelpsymbol(pgmin_class, gensym("midi"));
305 pgmin_sym = gensym("#pgmin");
306}
307
308void inmidi_programchange(int portno, int channel, int value)
309{
310 if (pgmin_sym->s_thing)
311 {
312 t_atom at[2];
313 SETFLOAT(at, value + 1);
314 SETFLOAT(at+1, (channel + (portno << 4) + 1));
315 pd_list(pgmin_sym->s_thing, &s_list, 2, at);
316 }
317}
318
319/* ----------------------- bendin ------------------------- */
320
321static t_symbol *bendin_sym;
322
323static t_class *bendin_class;
324
325typedef struct _bendin
326{
327 t_object x_obj;
328 t_float x_channel;
329 t_outlet *x_outlet1;
330 t_outlet *x_outlet2;
331} t_bendin;
332
333static void *bendin_new(t_floatarg f)
334{
335 t_bendin *x = (t_bendin *)pd_new(bendin_class);
336 x->x_channel = f;
337 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
338 if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
339 pd_bind(&x->x_obj.ob_pd, bendin_sym);
340 return (x);
341}
342
343static void bendin_list(t_bendin *x, t_symbol *s, int argc, t_atom *argv)
344{
345 t_float value = atom_getfloatarg(0, argc, argv);
346 t_float channel = atom_getfloatarg(1, argc, argv);
347 if (x->x_channel != 0)
348 {
349 if (channel != x->x_channel) return;
350 outlet_float(x->x_outlet1, value);
351 }
352 else
353 {
354 outlet_float(x->x_outlet2, channel);
355 outlet_float(x->x_outlet1, value);
356 }
357}
358
359static void bendin_free(t_bendin *x)
360{
361 pd_unbind(&x->x_obj.ob_pd, bendin_sym);
362}
363
364static void bendin_setup(void)
365{
366 bendin_class = class_new(gensym("bendin"), (t_newmethod)bendin_new,
367 (t_method)bendin_free, sizeof(t_bendin), CLASS_NOINLET, A_DEFFLOAT, 0);
368 class_addlist(bendin_class, bendin_list);
369 class_sethelpsymbol(bendin_class, gensym("midi"));
370 bendin_sym = gensym("#bendin");
371}
372
373void inmidi_pitchbend(int portno, int channel, int value)
374{
375 if (bendin_sym->s_thing)
376 {
377 t_atom at[2];
378 SETFLOAT(at, value);
379 SETFLOAT(at+1, (channel + (portno << 4) + 1));
380 pd_list(bendin_sym->s_thing, &s_list, 2, at);
381 }
382}
383
384/* ----------------------- touchin ------------------------- */
385
386static t_symbol *touchin_sym;
387
388static t_class *touchin_class;
389
390typedef struct _touchin
391{
392 t_object x_obj;
393 t_float x_channel;
394 t_outlet *x_outlet1;
395 t_outlet *x_outlet2;
396} t_touchin;
397
398static void *touchin_new(t_floatarg f)
399{
400 t_touchin *x = (t_touchin *)pd_new(touchin_class);
401 x->x_channel = f;
402 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
403 if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
404 pd_bind(&x->x_obj.ob_pd, touchin_sym);
405 return (x);
406}
407
408static void touchin_list(t_touchin *x, t_symbol *s, int argc, t_atom *argv)
409{
410 t_float value = atom_getfloatarg(0, argc, argv);
411 t_float channel = atom_getfloatarg(1, argc, argv);
412 if (x->x_channel)
413 {
414 if (channel != x->x_channel) return;
415 outlet_float(x->x_outlet1, value);
416 }
417 else
418 {
419 outlet_float(x->x_outlet2, channel);
420 outlet_float(x->x_outlet1, value);
421 }
422}
423
424static void touchin_free(t_touchin *x)
425{
426 pd_unbind(&x->x_obj.ob_pd, touchin_sym);
427}
428
429static void touchin_setup(void)
430{
431 touchin_class = class_new(gensym("touchin"), (t_newmethod)touchin_new,
432 (t_method)touchin_free, sizeof(t_touchin),
433 CLASS_NOINLET, A_DEFFLOAT, 0);
434 class_addlist(touchin_class, touchin_list);
435 class_sethelpsymbol(touchin_class, gensym("midi"));
436 touchin_sym = gensym("#touchin");
437}
438
439void inmidi_aftertouch(int portno, int channel, int value)
440{
441 if (touchin_sym->s_thing)
442 {
443 t_atom at[2];
444 SETFLOAT(at, value);
445 SETFLOAT(at+1, (channel + (portno << 4) + 1));
446 pd_list(touchin_sym->s_thing, &s_list, 2, at);
447 }
448}
449
450/* ----------------------- polytouchin ------------------------- */
451
452static t_symbol *polytouchin_sym;
453
454static t_class *polytouchin_class;
455
456typedef struct _polytouchin
457{
458 t_object x_obj;
459 t_float x_channel;
460 t_outlet *x_outlet1;
461 t_outlet *x_outlet2;
462 t_outlet *x_outlet3;
463} t_polytouchin;
464
465static void *polytouchin_new(t_floatarg f)
466{
467 t_polytouchin *x = (t_polytouchin *)pd_new(polytouchin_class);
468 x->x_channel = f;
469 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
470 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
471 if (f == 0) x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
472 pd_bind(&x->x_obj.ob_pd, polytouchin_sym);
473 return (x);
474}
475
476static void polytouchin_list(t_polytouchin *x, t_symbol *s, int argc,
477 t_atom *argv)
478{
479 t_float pitch = atom_getfloatarg(0, argc, argv);
480 t_float value = atom_getfloatarg(1, argc, argv);
481 t_float channel = atom_getfloatarg(2, argc, argv);
482 if (x->x_channel != 0)
483 {
484 if (channel != x->x_channel) return;
485 outlet_float(x->x_outlet2, pitch);
486 outlet_float(x->x_outlet1, value);
487 }
488 else
489 {
490 outlet_float(x->x_outlet3, channel);
491 outlet_float(x->x_outlet2, pitch);
492 outlet_float(x->x_outlet1, value);
493 }
494}
495
496static void polytouchin_free(t_polytouchin *x)
497{
498 pd_unbind(&x->x_obj.ob_pd, polytouchin_sym);
499}
500
501static void polytouchin_setup(void)
502{
503 polytouchin_class = class_new(gensym("polytouchin"),
504 (t_newmethod)polytouchin_new, (t_method)polytouchin_free,
505 sizeof(t_polytouchin), CLASS_NOINLET, A_DEFFLOAT, 0);
506 class_addlist(polytouchin_class, polytouchin_list);
507 class_sethelpsymbol(polytouchin_class, gensym("midi"));
508 polytouchin_sym = gensym("#polytouchin");
509}
510
511void inmidi_polyaftertouch(int portno, int channel, int pitch, int value)
512{
513 if (polytouchin_sym->s_thing)
514 {
515 t_atom at[3];
516 SETFLOAT(at, pitch);
517 SETFLOAT(at+1, value);
518 SETFLOAT(at+2, (channel + (portno << 4) + 1));
519 pd_list(polytouchin_sym->s_thing, &s_list, 3, at);
520 }
521}
522
523/*----------------------- midiclkin--(midi F8 message )---------------------*/
524static t_symbol *midiclkin_sym;
525
526static t_class *midiclkin_class;
527
528
529typedef struct _midiclkin
530{
531 t_object x_obj;
532 t_outlet *x_outlet1;
533 t_outlet *x_outlet2;
534} t_midiclkin;
535
536static void *midiclkin_new(t_floatarg f)
537{
538 t_midiclkin *x = (t_midiclkin *)pd_new(midiclkin_class);
539 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
540 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
541 pd_bind(&x->x_obj.ob_pd, midiclkin_sym);
542 return (x);
543}
544
545static void midiclkin_list(t_midiclkin *x, t_symbol *s, int argc, t_atom *argv)
546{
547 float value = atom_getfloatarg(0, argc, argv);
548 float count = atom_getfloatarg(1, argc, argv);
549 outlet_float(x->x_outlet2, count);
550 outlet_float(x->x_outlet1, value);
551}
552
553static void midiclkin_free(t_midiclkin *x)
554{
555 pd_unbind(&x->x_obj.ob_pd, midiclkin_sym);
556}
557
558static void midiclkin_setup(void)
559{
560 midiclkin_class = class_new(gensym("midiclkin"),
561 (t_newmethod)midiclkin_new, (t_method)midiclkin_free,
562 sizeof(t_midiclkin), CLASS_NOINLET, A_DEFFLOAT, 0);
563 class_addlist(midiclkin_class, midiclkin_list);
564 class_sethelpsymbol(midiclkin_class, gensym("midi"));
565 midiclkin_sym = gensym("#midiclkin");
566}
567
568void inmidi_clk(double timing)
569{
570
571 static float prev = 0;
572 static float count = 0;
573 float cur,diff;
574
575 if (midiclkin_sym->s_thing)
576 {
577 t_atom at[2];
578 diff =timing - prev;
579 count++;
580
581 if (count == 3)
582 { /* 24 count per quoter note */
583 SETFLOAT(at, 1 );
584 count = 0;
585 }
586 else SETFLOAT(at, 0);
587
588 SETFLOAT(at+1, diff);
589 pd_list(midiclkin_sym->s_thing, &s_list, 2, at);
590 prev = timing;
591 }
592}
593
594/*----------midirealtimein (midi FA,FB,FC,FF message )-----------------*/
595
596static t_symbol *midirealtimein_sym;
597
598static t_class *midirealtimein_class;
599
600typedef struct _midirealtimein
601{
602 t_object x_obj;
603 t_outlet *x_outlet1;
604 t_outlet *x_outlet2;
605} t_midirealtimein;
606
607static void *midirealtimein_new( void)
608{
609 t_midirealtimein *x = (t_midirealtimein *)pd_new(midirealtimein_class);
610 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
611 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
612 pd_bind(&x->x_obj.ob_pd, midirealtimein_sym);
613#ifndef MSW
614 pd_error(x, "midirealtimein: works under MSW only");
615#endif
616 return (x);
617}
618
619static void midirealtimein_list(t_midirealtimein *x, t_symbol *s,
620 int argc, t_atom *argv)
621{
622 float portno = atom_getfloatarg(0, argc, argv);
623 float byte = atom_getfloatarg(1, argc, argv);
624
625 outlet_float(x->x_outlet2, portno);
626 outlet_float(x->x_outlet1, byte);
627}
628
629static void midirealtimein_free(t_midirealtimein *x)
630{
631 pd_unbind(&x->x_obj.ob_pd, midirealtimein_sym);
632}
633
634static void midirealtimein_setup(void)
635{
636 midirealtimein_class = class_new(gensym("midirealtimein"),
637 (t_newmethod)midirealtimein_new, (t_method)midirealtimein_free,
638 sizeof(t_midirealtimein), CLASS_NOINLET, A_DEFFLOAT, 0);
639 class_addlist(midirealtimein_class, midirealtimein_list);
640 class_sethelpsymbol(midirealtimein_class, gensym("midi"));
641 midirealtimein_sym = gensym("#midirealtimein");
642}
643
644void inmidi_realtimein(int portno, int SysMsg)
645{
646 if (midirealtimein_sym->s_thing)
647 {
648 t_atom at[2];
649 SETFLOAT(at, portno);
650 SETFLOAT(at+1, SysMsg);
651 pd_list(midirealtimein_sym->s_thing, &s_list, 1, at);
652 }
653}
654
655/* -------------------------- midiout -------------------------- */
656
657static t_class *midiout_class;
658
659void sys_putmidibyte(int portno, int byte);
660
661typedef struct _midiout
662{
663 t_object x_obj;
664 t_float x_portno;
665} t_midiout;
666
667static void *midiout_new(t_floatarg portno)
668{
669 t_midiout *x = (t_midiout *)pd_new(midiout_class);
670 if (portno <= 0) portno = 1;
671 x->x_portno = portno;
672 floatinlet_new(&x->x_obj, &x->x_portno);
673#ifdef __irix__
674 post("midiout: unimplemented in IRIX");
675#endif
676 return (x);
677}
678
679static void midiout_float(t_midiout *x, t_floatarg f)
680{
681 sys_putmidibyte(x->x_portno - 1, f);
682}
683
684static void midiout_setup(void)
685{
686 midiout_class = class_new(gensym("midiout"), (t_newmethod)midiout_new, 0,
687 sizeof(t_midiout), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
688 class_addfloat(midiout_class, midiout_float);
689 class_sethelpsymbol(midiout_class, gensym("midi"));
690}
691
692/* -------------------------- noteout -------------------------- */
693
694static t_class *noteout_class;
695
696typedef struct _noteout
697{
698 t_object x_obj;
699 t_float x_velo;
700 t_float x_channel;
701} t_noteout;
702
703static void *noteout_new(t_floatarg channel)
704{
705 t_noteout *x = (t_noteout *)pd_new(noteout_class);
706 x->x_velo = 0;
707 if (channel < 1) channel = 1;
708 x->x_channel = channel;
709 floatinlet_new(&x->x_obj, &x->x_velo);
710 floatinlet_new(&x->x_obj, &x->x_channel);
711 return (x);
712}
713
714static void noteout_float(t_noteout *x, t_float f)
715{
716 int binchan = x->x_channel - 1;
717 if (binchan < 0)
718 binchan = 0;
719 outmidi_noteon((binchan >> 4),
720 (binchan & 15), (int)f, (int)x->x_velo);
721}
722
723static void noteout_setup(void)
724{
725 noteout_class = class_new(gensym("noteout"), (t_newmethod)noteout_new, 0,
726 sizeof(t_noteout), 0, A_DEFFLOAT, 0);
727 class_addfloat(noteout_class, noteout_float);
728 class_sethelpsymbol(noteout_class, gensym("midi"));
729}
730
731
732/* -------------------------- ctlout -------------------------- */
733
734static t_class *ctlout_class;
735
736typedef struct _ctlout
737{
738 t_object x_obj;
739 t_float x_ctl;
740 t_float x_channel;
741} t_ctlout;
742
743static void *ctlout_new(t_floatarg ctl, t_floatarg channel)
744{
745 t_ctlout *x = (t_ctlout *)pd_new(ctlout_class);
746 x->x_ctl = ctl;
747 if (channel <= 0) channel = 1;
748 x->x_channel = channel;
749 floatinlet_new(&x->x_obj, &x->x_ctl);
750 floatinlet_new(&x->x_obj, &x->x_channel);
751 return (x);
752}
753
754static void ctlout_float(t_ctlout *x, t_float f)
755{
756 int binchan = x->x_channel - 1;
757 if (binchan < 0)
758 binchan = 0;
759 outmidi_controlchange((binchan >> 4),
760 (binchan & 15), (int)(x->x_ctl), (int)f);
761}
762
763static void ctlout_setup(void)
764{
765 ctlout_class = class_new(gensym("ctlout"), (t_newmethod)ctlout_new, 0,
766 sizeof(t_ctlout), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
767 class_addfloat(ctlout_class, ctlout_float);
768 class_sethelpsymbol(ctlout_class, gensym("midi"));
769}
770
771
772/* -------------------------- pgmout -------------------------- */
773
774static t_class *pgmout_class;
775
776typedef struct _pgmout
777{
778 t_object x_obj;
779 t_float x_channel;
780} t_pgmout;
781
782static void *pgmout_new(t_floatarg channel)
783{
784 t_pgmout *x = (t_pgmout *)pd_new(pgmout_class);
785 if (channel <= 0) channel = 1;
786 x->x_channel = channel;
787 floatinlet_new(&x->x_obj, &x->x_channel);
788 return (x);
789}
790
791static void pgmout_float(t_pgmout *x, t_floatarg f)
792{
793 int binchan = x->x_channel - 1;
794 int n = f - 1;
795 if (binchan < 0)
796 binchan = 0;
797 if (n < 0) n = 0;
798 else if (n > 127) n = 127;
799 outmidi_programchange((binchan >> 4),
800 (binchan & 15), n);
801}
802
803static void pgmout_setup(void)
804{
805 pgmout_class = class_new(gensym("pgmout"), (t_newmethod)pgmout_new, 0,
806 sizeof(t_pgmout), 0, A_DEFFLOAT, 0);
807 class_addfloat(pgmout_class, pgmout_float);
808 class_sethelpsymbol(pgmout_class, gensym("midi"));
809}
810
811
812/* -------------------------- bendout -------------------------- */
813
814static t_class *bendout_class;
815
816typedef struct _bendout
817{
818 t_object x_obj;
819 t_float x_channel;
820} t_bendout;
821
822static void *bendout_new(t_floatarg channel)
823{
824 t_bendout *x = (t_bendout *)pd_new(bendout_class);
825 if (channel <= 0) channel = 1;
826 x->x_channel = channel;
827 floatinlet_new(&x->x_obj, &x->x_channel);
828 return (x);
829}
830
831static void bendout_float(t_bendout *x, t_float f)
832{
833 int binchan = x->x_channel - 1;
834 int n = (int)f + 8192;
835 if (binchan < 0)
836 binchan = 0;
837 outmidi_pitchbend((binchan >> 4), (binchan & 15), n);
838}
839
840static void bendout_setup(void)
841{
842 bendout_class = class_new(gensym("bendout"), (t_newmethod)bendout_new, 0,
843 sizeof(t_bendout), 0, A_DEFFLOAT, 0);
844 class_addfloat(bendout_class, bendout_float);
845 class_sethelpsymbol(bendout_class, gensym("midi"));
846}
847
848/* -------------------------- touch -------------------------- */
849
850static t_class *touchout_class;
851
852typedef struct _touchout
853{
854 t_object x_obj;
855 t_float x_channel;
856} t_touchout;
857
858static void *touchout_new(t_floatarg channel)
859{
860 t_touchout *x = (t_touchout *)pd_new(touchout_class);
861 if (channel <= 0) channel = 1;
862 x->x_channel = channel;
863 floatinlet_new(&x->x_obj, &x->x_channel);
864 return (x);
865}
866
867static void touchout_float(t_touchout *x, t_float f)
868{
869 int binchan = x->x_channel - 1;
870 if (binchan < 0)
871 binchan = 0;
872 outmidi_aftertouch((binchan >> 4), (binchan & 15), (int)f);
873}
874
875static void touchout_setup(void)
876{
877 touchout_class = class_new(gensym("touchout"), (t_newmethod)touchout_new, 0,
878 sizeof(t_touchout), 0, A_DEFFLOAT, 0);
879 class_addfloat(touchout_class, touchout_float);
880 class_sethelpsymbol(touchout_class, gensym("midi"));
881}
882
883/* -------------------------- polytouch -------------------------- */
884
885static t_class *polytouchout_class;
886
887typedef struct _polytouchout
888{
889 t_object x_obj;
890 t_float x_channel;
891 t_float x_pitch;
892} t_polytouchout;
893
894static void *polytouchout_new(t_floatarg channel)
895{
896 t_polytouchout *x = (t_polytouchout *)pd_new(polytouchout_class);
897 if (channel <= 0) channel = 1;
898 x->x_channel = channel;
899 x->x_pitch = 0;
900 floatinlet_new(&x->x_obj, &x->x_pitch);
901 floatinlet_new(&x->x_obj, &x->x_channel);
902 return (x);
903}
904
905static void polytouchout_float(t_polytouchout *x, t_float n)
906{
907 int binchan = x->x_channel - 1;
908 if (binchan < 0)
909 binchan = 0;
910 outmidi_polyaftertouch((binchan >> 4), (binchan & 15), x->x_pitch, n);
911}
912
913static void polytouchout_setup(void)
914{
915 polytouchout_class = class_new(gensym("polytouchout"),
916 (t_newmethod)polytouchout_new, 0,
917 sizeof(t_polytouchout), 0, A_DEFFLOAT, 0);
918 class_addfloat(polytouchout_class, polytouchout_float);
919 class_sethelpsymbol(polytouchout_class, gensym("midi"));
920}
921
922/* -------------------------- makenote -------------------------- */
923
924static t_class *makenote_class;
925
926typedef struct _hang
927{
928 t_clock *h_clock;
929 struct _hang *h_next;
930 t_float h_pitch;
931 struct _makenote *h_owner;
932} t_hang;
933
934typedef struct _makenote
935{
936 t_object x_obj;
937 t_float x_velo;
938 t_float x_dur;
939 t_outlet *x_pitchout;
940 t_outlet *x_velout;
941 t_hang *x_hang;
942} t_makenote;
943
944static void *makenote_new(t_floatarg velo, t_floatarg dur)
945{
946 t_makenote *x = (t_makenote *)pd_new(makenote_class);
947 x->x_velo = velo;
948 x->x_dur = dur;
949 floatinlet_new(&x->x_obj, &x->x_velo);
950 floatinlet_new(&x->x_obj, &x->x_dur);
951 x->x_pitchout = outlet_new(&x->x_obj, &s_float);
952 x->x_velout = outlet_new(&x->x_obj, &s_float);
953 x->x_hang = 0;
954 return (x);
955}
956
957static void makenote_tick(t_hang *hang)
958{
959 t_makenote *x = hang->h_owner;
960 t_hang *h2, *h3;
961 outlet_float(x->x_velout, 0);
962 outlet_float(x->x_pitchout, hang->h_pitch);
963 if (x->x_hang == hang) x->x_hang = hang->h_next;
964 else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3)
965 {
966 if (h3 == hang)
967 {
968 h2->h_next = h3->h_next;
969 break;
970 }
971 }
972 clock_free(hang->h_clock);
973 freebytes(hang, sizeof(*hang));
974}
975
976static void makenote_float(t_makenote *x, t_float f)
977{
978 t_hang *hang;
979 if (!x->x_velo) return;
980 outlet_float(x->x_velout, x->x_velo);
981 outlet_float(x->x_pitchout, f);
982 hang = (t_hang *)getbytes(sizeof *hang);
983 hang->h_next = x->x_hang;
984 x->x_hang = hang;
985 hang->h_pitch = f;
986 hang->h_owner = x;
987 hang->h_clock = clock_new(hang, (t_method)makenote_tick);
988 clock_delay(hang->h_clock, (x->x_dur >= 0 ? x->x_dur : 0));
989}
990
991static void makenote_stop(t_makenote *x)
992{
993 t_hang *hang;
994 while (hang = x->x_hang)
995 {
996 outlet_float(x->x_velout, 0);
997 outlet_float(x->x_pitchout, hang->h_pitch);
998 x->x_hang = hang->h_next;
999 clock_free(hang->h_clock);
1000 freebytes(hang, sizeof(*hang));
1001 }
1002}
1003
1004static void makenote_clear(t_makenote *x)
1005{
1006 t_hang *hang;
1007 while (hang = x->x_hang)
1008 {
1009 x->x_hang = hang->h_next;
1010 clock_free(hang->h_clock);
1011 freebytes(hang, sizeof(*hang));
1012 }
1013}
1014
1015static void makenote_setup(void)
1016{
1017 makenote_class = class_new(gensym("makenote"),
1018 (t_newmethod)makenote_new, (t_method)makenote_clear,
1019 sizeof(t_makenote), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
1020 class_addfloat(makenote_class, makenote_float);
1021 class_addmethod(makenote_class, (t_method)makenote_stop, gensym("stop"),
1022 0);
1023 class_addmethod(makenote_class, (t_method)makenote_clear, gensym("clear"),
1024 0);
1025}
1026
1027/* -------------------------- stripnote -------------------------- */
1028
1029static t_class *stripnote_class;
1030
1031typedef struct _stripnote
1032{
1033 t_object x_obj;
1034 t_float x_velo;
1035 t_outlet *x_pitchout;
1036 t_outlet *x_velout;
1037} t_stripnote;
1038
1039static void *stripnote_new(void )
1040{
1041 t_stripnote *x = (t_stripnote *)pd_new(stripnote_class);
1042 floatinlet_new(&x->x_obj, &x->x_velo);
1043 x->x_pitchout = outlet_new(&x->x_obj, &s_float);
1044 x->x_velout = outlet_new(&x->x_obj, &s_float);
1045 return (x);
1046}
1047
1048static void stripnote_float(t_stripnote *x, t_float f)
1049{
1050 t_hang *hang;
1051 if (!x->x_velo) return;
1052 outlet_float(x->x_velout, x->x_velo);
1053 outlet_float(x->x_pitchout, f);
1054}
1055
1056static void stripnote_setup(void)
1057{
1058 stripnote_class = class_new(gensym("stripnote"),
1059 (t_newmethod)stripnote_new, 0, sizeof(t_stripnote), 0, 0);
1060 class_addfloat(stripnote_class, stripnote_float);
1061}
1062
1063/* -------------------------- poly -------------------------- */
1064
1065static t_class *poly_class;
1066
1067typedef struct voice
1068{
1069 float v_pitch;
1070 int v_used;
1071 unsigned long v_serial;
1072} t_voice;
1073
1074typedef struct poly
1075{
1076 t_object x_obj;
1077 int x_n;
1078 t_voice *x_vec;
1079 float x_vel;
1080 t_outlet *x_pitchout;
1081 t_outlet *x_velout;
1082 unsigned long x_serial;
1083 int x_steal;
1084} t_poly;
1085
1086static void *poly_new(float fnvoice, float fsteal)
1087{
1088 int i, n = fnvoice;
1089 t_poly *x = (t_poly *)pd_new(poly_class);
1090 t_voice *v;
1091 if (n < 1) n = 1;
1092 x->x_n = n;
1093 x->x_vec = (t_voice *)getbytes(n * sizeof(*x->x_vec));
1094 for (v = x->x_vec, i = n; i--; v++)
1095 v->v_pitch = v->v_used = v->v_serial = 0;
1096 x->x_vel = 0;
1097 x->x_steal = (fsteal != 0);
1098 floatinlet_new(&x->x_obj, &x->x_vel);
1099 outlet_new(&x->x_obj, &s_float);
1100 x->x_pitchout = outlet_new(&x->x_obj, &s_float);
1101 x->x_velout = outlet_new(&x->x_obj, &s_float);
1102 x->x_serial = 0;
1103 return (x);
1104}
1105
1106static void poly_float(t_poly *x, t_float f)
1107{
1108 int i;
1109 t_voice *v;
1110 t_voice *firston, *firstoff;
1111 unsigned int serialon, serialoff, onindex = 0, offindex = 0;
1112 if (x->x_vel > 0)
1113 {
1114 /* note on. Look for a vacant voice */
1115 for (v = x->x_vec, i = 0, firston = firstoff = 0,
1116 serialon = serialoff = 0xffffffff; i < x->x_n; v++, i++)
1117 {
1118 if (v->v_used && v->v_serial < serialon)
1119 firston = v, serialon = v->v_serial, onindex = i;
1120 else if (!v->v_used && v->v_serial < serialoff)
1121 firstoff = v, serialoff = v->v_serial, offindex = i;
1122 }
1123 if (firstoff)
1124 {
1125 outlet_float(x->x_velout, x->x_vel);
1126 outlet_float(x->x_pitchout, firstoff->v_pitch = f);
1127 outlet_float(x->x_obj.ob_outlet, offindex+1);
1128 firstoff->v_used = 1;
1129 firstoff->v_serial = x->x_serial++;
1130 }
1131 /* if none, steal one */
1132 else if (firston && x->x_steal)
1133 {
1134 outlet_float(x->x_velout, 0);
1135 outlet_float(x->x_pitchout, firston->v_pitch);
1136 outlet_float(x->x_obj.ob_outlet, onindex+1);
1137 outlet_float(x->x_velout, x->x_vel);
1138 outlet_float(x->x_pitchout, firston->v_pitch = f);
1139 outlet_float(x->x_obj.ob_outlet, onindex+1);
1140 firston->v_serial = x->x_serial++;
1141 }
1142 }
1143 else /* note off. Turn off oldest match */
1144 {
1145 for (v = x->x_vec, i = 0, firston = 0, serialon = 0xffffffff;
1146 i < x->x_n; v++, i++)
1147 if (v->v_used && v->v_pitch == f && v->v_serial < serialon)
1148 firston = v, serialon = v->v_serial, onindex = i;
1149 if (firston)
1150 {
1151 firston->v_used = 0;
1152 firston->v_serial = x->x_serial++;
1153 outlet_float(x->x_velout, 0);
1154 outlet_float(x->x_pitchout, firston->v_pitch);
1155 outlet_float(x->x_obj.ob_outlet, onindex+1);
1156 }
1157 }
1158}
1159
1160static void poly_stop(t_poly *x)
1161{
1162 int i;
1163 t_voice *v;
1164 for (i = 0, v = x->x_vec; i < x->x_n; i++, v++)
1165 if (v->v_used)
1166 {
1167 outlet_float(x->x_velout, 0L);
1168 outlet_float(x->x_pitchout, v->v_pitch);
1169 outlet_float(x->x_obj.ob_outlet, i+1);
1170 v->v_used = 0;
1171 v->v_serial = x->x_serial++;
1172 }
1173}
1174
1175static void poly_clear(t_poly *x)
1176{
1177 int i;
1178 t_voice *v;
1179 for (v = x->x_vec, i = x->x_n; i--; v++) v->v_used = v->v_serial = 0;
1180}
1181
1182static void poly_free(t_poly *x)
1183{
1184 freebytes(x->x_vec, x->x_n * sizeof (*x->x_vec));
1185}
1186
1187static void poly_setup(void)
1188{
1189 poly_class = class_new(gensym("poly"),
1190 (t_newmethod)poly_new, (t_method)poly_clear,
1191 sizeof(t_poly), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
1192 class_addfloat(poly_class, poly_float);
1193 class_addmethod(poly_class, (t_method)poly_stop, gensym("stop"), 0);
1194 class_addmethod(poly_class, (t_method)poly_clear, gensym("clear"), 0);
1195}
1196
1197/* -------------------------- bag -------------------------- */
1198
1199static t_class *bag_class;
1200
1201typedef struct _bagelem
1202{
1203 struct _bagelem *e_next;
1204 t_float e_value;
1205} t_bagelem;
1206
1207typedef struct _bag
1208{
1209 t_object x_obj;
1210 t_float x_velo;
1211 t_bagelem *x_first;
1212} t_bag;
1213
1214static void *bag_new(void )
1215{
1216 t_bag *x = (t_bag *)pd_new(bag_class);
1217 x->x_velo = 0;
1218 floatinlet_new(&x->x_obj, &x->x_velo);
1219 outlet_new(&x->x_obj, &s_float);
1220 x->x_first = 0;
1221 return (x);
1222}
1223
1224static void bag_float(t_bag *x, t_float f)
1225{
1226 t_bagelem *bagelem, *e2, *e3;
1227 if (x->x_velo != 0)
1228 {
1229 bagelem = (t_bagelem *)getbytes(sizeof *bagelem);
1230 bagelem->e_next = 0;
1231 bagelem->e_value = f;
1232 if (!x->x_first) x->x_first = bagelem;
1233 else /* LATER replace with a faster algorithm */
1234 {
1235 for (e2 = x->x_first; e3 = e2->e_next; e2 = e3)
1236 ;
1237 e2->e_next = bagelem;
1238 }
1239 }
1240 else
1241 {
1242 if (!x->x_first) return;
1243 if (x->x_first->e_value == f)
1244 {
1245 bagelem = x->x_first;
1246 x->x_first = x->x_first->e_next;
1247 freebytes(bagelem, sizeof(*bagelem));
1248 return;
1249 }
1250 for (e2 = x->x_first; e3 = e2->e_next; e2 = e3)
1251 if (e3->e_value == f)
1252 {
1253 e2->e_next = e3->e_next;
1254 freebytes(e3, sizeof(*e3));
1255 return;
1256 }
1257 }
1258}
1259
1260static void bag_flush(t_bag *x)
1261{
1262 t_bagelem *bagelem;
1263 while (bagelem = x->x_first)
1264 {
1265 outlet_float(x->x_obj.ob_outlet, bagelem->e_value);
1266 x->x_first = bagelem->e_next;
1267 freebytes(bagelem, sizeof(*bagelem));
1268 }
1269}
1270
1271static void bag_clear(t_bag *x)
1272{
1273 t_bagelem *bagelem;
1274 while (bagelem = x->x_first)
1275 {
1276 x->x_first = bagelem->e_next;
1277 freebytes(bagelem, sizeof(*bagelem));
1278 }
1279}
1280
1281static void bag_setup(void)
1282{
1283 bag_class = class_new(gensym("bag"),
1284 (t_newmethod)bag_new, (t_method)bag_clear,
1285 sizeof(t_bag), 0, 0);
1286 class_addfloat(bag_class, bag_float);
1287 class_addmethod(bag_class, (t_method)bag_flush, gensym("flush"), 0);
1288 class_addmethod(bag_class, (t_method)bag_clear, gensym("clear"), 0);
1289}
1290
1291void x_midi_setup(void)
1292{
1293 midiin_setup();
1294 midirealtimein_setup();
1295 notein_setup();
1296 ctlin_setup();
1297 pgmin_setup();
1298 bendin_setup();
1299 touchin_setup();
1300 polytouchin_setup();
1301 midiclkin_setup();
1302 midiout_setup();
1303 noteout_setup();
1304 ctlout_setup();
1305 pgmout_setup();
1306 bendout_setup();
1307 touchout_setup();
1308 polytouchout_setup();
1309 makenote_setup();
1310 stripnote_setup();
1311 poly_setup();
1312 bag_setup();
1313}
1314/* Copyright (c) 1997-2001 Miller Puckette and others.
1315* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1316* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1317
1318/* MIDI. */
1319
1320#include "m_pd.h"
1321void outmidi_noteon(int portno, int channel, int pitch, int velo);
1322void outmidi_controlchange(int portno, int channel, int ctlno, int value);
1323void outmidi_programchange(int portno, int channel, int value);
1324void outmidi_pitchbend(int portno, int channel, int value);
1325void outmidi_aftertouch(int portno, int channel, int value);
1326void outmidi_polyaftertouch(int portno, int channel, int pitch, int value);
1327void outmidi_mclk(int portno);
1328
1329/* ----------------------- midiin and sysexin ------------------------- */
1330
1331static t_symbol *midiin_sym, *sysexin_sym;
1332
1333static t_class *midiin_class, *sysexin_class;
1334
1335typedef struct _midiin
1336{
1337 t_object x_obj;
1338 t_outlet *x_outlet1;
1339 t_outlet *x_outlet2;
1340} t_midiin;
1341
1342static void *midiin_new( void)
1343{
1344 t_midiin *x = (t_midiin *)pd_new(midiin_class);
1345 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1346 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1347 pd_bind(&x->x_obj.ob_pd, midiin_sym);
1348#ifndef __linux__
1349 pd_error(x, "midiin: works under Linux only");
1350#endif
1351 return (x);
1352}
1353
1354static void midiin_list(t_midiin *x, t_symbol *s, int ac, t_atom *av)
1355{
1356 outlet_float(x->x_outlet2, atom_getfloatarg(1, ac, av) + 1);
1357 outlet_float(x->x_outlet1, atom_getfloatarg(0, ac, av));
1358}
1359
1360static void midiin_free(t_midiin *x)
1361{
1362 pd_unbind(&x->x_obj.ob_pd, midiin_sym);
1363}
1364
1365static void *sysexin_new( void)
1366{
1367 t_midiin *x = (t_midiin *)pd_new(sysexin_class);
1368 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1369 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1370 pd_bind(&x->x_obj.ob_pd, sysexin_sym);
1371#ifndef __linux__
1372 pd_error(x, "sysexin: works under Linux only");
1373#endif
1374 return (x);
1375}
1376
1377static void sysexin_free(t_midiin *x)
1378{
1379 pd_unbind(&x->x_obj.ob_pd, sysexin_sym);
1380}
1381
1382static void midiin_setup(void)
1383{
1384 midiin_class = class_new(gensym("midiin"), (t_newmethod)midiin_new,
1385 (t_method)midiin_free, sizeof(t_midiin),
1386 CLASS_NOINLET, A_DEFFLOAT, 0);
1387 class_addlist(midiin_class, midiin_list);
1388 class_sethelpsymbol(midiin_class, gensym("midi"));
1389 midiin_sym = gensym("#midiin");
1390
1391 sysexin_class = class_new(gensym("sysexin"), (t_newmethod)sysexin_new,
1392 (t_method)sysexin_free, sizeof(t_midiin),
1393 CLASS_NOINLET, A_DEFFLOAT, 0);
1394 class_addlist(sysexin_class, midiin_list);
1395 class_sethelpsymbol(sysexin_class, gensym("midi"));
1396 sysexin_sym = gensym("#sysexin");
1397}
1398
1399void inmidi_byte(int portno, int byte)
1400{
1401 t_atom at[2];
1402 if (midiin_sym->s_thing)
1403 {
1404 SETFLOAT(at, byte);
1405 SETFLOAT(at+1, portno + 1);
1406 pd_list(midiin_sym->s_thing, 0, 2, at);
1407 }
1408}
1409
1410void inmidi_sysex(int portno, int byte)
1411{
1412 t_atom at[2];
1413 if (sysexin_sym->s_thing)
1414 {
1415 SETFLOAT(at, byte);
1416 SETFLOAT(at+1, portno + 1);
1417 pd_list(sysexin_sym->s_thing, 0, 2, at);
1418 }
1419}
1420
1421/* ----------------------- notein ------------------------- */
1422
1423static t_symbol *notein_sym;
1424
1425static t_class *notein_class;
1426
1427typedef struct _notein
1428{
1429 t_object x_obj;
1430 t_float x_channel;
1431 t_outlet *x_outlet1;
1432 t_outlet *x_outlet2;
1433 t_outlet *x_outlet3;
1434} t_notein;
1435
1436static void *notein_new(t_floatarg f)
1437{
1438 t_notein *x = (t_notein *)pd_new(notein_class);
1439 x->x_channel = f;
1440 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1441 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1442 if (f == 0) x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
1443 pd_bind(&x->x_obj.ob_pd, notein_sym);
1444 return (x);
1445}
1446
1447static void notein_list(t_notein *x, t_symbol *s, int argc, t_atom *argv)
1448{
1449 float pitch = atom_getfloatarg(0, argc, argv);
1450 float velo = atom_getfloatarg(1, argc, argv);
1451 float channel = atom_getfloatarg(2, argc, argv);
1452 if (x->x_channel != 0)
1453 {
1454 if (channel != x->x_channel) return;
1455 outlet_float(x->x_outlet2, velo);
1456 outlet_float(x->x_outlet1, pitch);
1457 }
1458 else
1459 {
1460 outlet_float(x->x_outlet3, channel);
1461 outlet_float(x->x_outlet2, velo);
1462 outlet_float(x->x_outlet1, pitch);
1463 }
1464}
1465
1466static void notein_free(t_notein *x)
1467{
1468 pd_unbind(&x->x_obj.ob_pd, notein_sym);
1469}
1470
1471static void notein_setup(void)
1472{
1473 notein_class = class_new(gensym("notein"), (t_newmethod)notein_new,
1474 (t_method)notein_free, sizeof(t_notein), CLASS_NOINLET, A_DEFFLOAT, 0);
1475 class_addlist(notein_class, notein_list);
1476 class_sethelpsymbol(notein_class, gensym("midi"));
1477 notein_sym = gensym("#notein");
1478}
1479
1480void inmidi_noteon(int portno, int channel, int pitch, int velo)
1481{
1482 if (notein_sym->s_thing)
1483 {
1484 t_atom at[3];
1485 SETFLOAT(at, pitch);
1486 SETFLOAT(at+1, velo);
1487 SETFLOAT(at+2, (channel + (portno << 4) + 1));
1488 pd_list(notein_sym->s_thing, &s_list, 3, at);
1489 }
1490}
1491
1492/* ----------------------- ctlin ------------------------- */
1493
1494static t_symbol *ctlin_sym;
1495
1496static t_class *ctlin_class;
1497
1498typedef struct _ctlin
1499{
1500 t_object x_obj;
1501 t_float x_channel;
1502 t_float x_ctlno;
1503 t_outlet *x_outlet1;
1504 t_outlet *x_outlet2;
1505 t_outlet *x_outlet3;
1506} t_ctlin;
1507
1508static void *ctlin_new(t_symbol *s, int argc, t_atom *argv)
1509{
1510 int ctlno, channel;
1511 t_ctlin *x = (t_ctlin *)pd_new(ctlin_class);
1512 if (!argc) ctlno = -1;
1513 else ctlno = atom_getfloatarg(0, argc, argv);
1514 channel = atom_getfloatarg(1, argc, argv);
1515 x->x_channel = channel;
1516 x->x_ctlno = ctlno;
1517 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1518 if (!channel)
1519 {
1520 if (x->x_ctlno < 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1521 x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
1522 }
1523 pd_bind(&x->x_obj.ob_pd, ctlin_sym);
1524 return (x);
1525}
1526
1527static void ctlin_list(t_ctlin *x, t_symbol *s, int argc, t_atom *argv)
1528{
1529 t_float ctlnumber = atom_getfloatarg(0, argc, argv);
1530 t_float value = atom_getfloatarg(1, argc, argv);
1531 t_float channel = atom_getfloatarg(2, argc, argv);
1532 if (x->x_ctlno >= 0 && x->x_ctlno != ctlnumber) return;
1533 if (x->x_channel > 0 && x->x_channel != channel) return;
1534 if (x->x_channel == 0) outlet_float(x->x_outlet3, channel);
1535 if (x->x_ctlno < 0) outlet_float(x->x_outlet2, ctlnumber);
1536 outlet_float(x->x_outlet1, value);
1537}
1538
1539static void ctlin_free(t_ctlin *x)
1540{
1541 pd_unbind(&x->x_obj.ob_pd, ctlin_sym);
1542}
1543
1544static void ctlin_setup(void)
1545{
1546 ctlin_class = class_new(gensym("ctlin"), (t_newmethod)ctlin_new,
1547 (t_method)ctlin_free, sizeof(t_ctlin),
1548 CLASS_NOINLET, A_GIMME, 0);
1549 class_addlist(ctlin_class, ctlin_list);
1550 class_sethelpsymbol(ctlin_class, gensym("midi"));
1551 ctlin_sym = gensym("#ctlin");
1552}
1553
1554void inmidi_controlchange(int portno, int channel, int ctlnumber, int value)
1555{
1556 if (ctlin_sym->s_thing)
1557 {
1558 t_atom at[3];
1559 SETFLOAT(at, ctlnumber);
1560 SETFLOAT(at+1, value);
1561 SETFLOAT(at+2, (channel + (portno << 4) + 1));
1562 pd_list(ctlin_sym->s_thing, &s_list, 3, at);
1563 }
1564}
1565
1566/* ----------------------- pgmin ------------------------- */
1567
1568static t_symbol *pgmin_sym;
1569
1570static t_class *pgmin_class;
1571
1572typedef struct _pgmin
1573{
1574 t_object x_obj;
1575 t_float x_channel;
1576 t_outlet *x_outlet1;
1577 t_outlet *x_outlet2;
1578} t_pgmin;
1579
1580static void *pgmin_new(t_floatarg f)
1581{
1582 t_pgmin *x = (t_pgmin *)pd_new(pgmin_class);
1583 x->x_channel = f;
1584 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1585 if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1586 pd_bind(&x->x_obj.ob_pd, pgmin_sym);
1587 return (x);
1588}
1589
1590static void pgmin_list(t_pgmin *x, t_symbol *s, int argc, t_atom *argv)
1591{
1592 float value = atom_getfloatarg(0, argc, argv);
1593 float channel = atom_getfloatarg(1, argc, argv);
1594 if (x->x_channel != 0)
1595 {
1596 if (channel != x->x_channel) return;
1597 outlet_float(x->x_outlet1, value);
1598 }
1599 else
1600 {
1601 outlet_float(x->x_outlet2, channel);
1602 outlet_float(x->x_outlet1, value);
1603 }
1604}
1605
1606static void pgmin_free(t_pgmin *x)
1607{
1608 pd_unbind(&x->x_obj.ob_pd, pgmin_sym);
1609}
1610
1611static void pgmin_setup(void)
1612{
1613 pgmin_class = class_new(gensym("pgmin"), (t_newmethod)pgmin_new,
1614 (t_method)pgmin_free, sizeof(t_pgmin),
1615 CLASS_NOINLET, A_DEFFLOAT, 0);
1616 class_addlist(pgmin_class, pgmin_list);
1617 class_sethelpsymbol(pgmin_class, gensym("midi"));
1618 pgmin_sym = gensym("#pgmin");
1619}
1620
1621void inmidi_programchange(int portno, int channel, int value)
1622{
1623 if (pgmin_sym->s_thing)
1624 {
1625 t_atom at[2];
1626 SETFLOAT(at, value + 1);
1627 SETFLOAT(at+1, (channel + (portno << 4) + 1));
1628 pd_list(pgmin_sym->s_thing, &s_list, 2, at);
1629 }
1630}
1631
1632/* ----------------------- bendin ------------------------- */
1633
1634static t_symbol *bendin_sym;
1635
1636static t_class *bendin_class;
1637
1638typedef struct _bendin
1639{
1640 t_object x_obj;
1641 t_float x_channel;
1642 t_outlet *x_outlet1;
1643 t_outlet *x_outlet2;
1644} t_bendin;
1645
1646static void *bendin_new(t_floatarg f)
1647{
1648 t_bendin *x = (t_bendin *)pd_new(bendin_class);
1649 x->x_channel = f;
1650 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1651 if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1652 pd_bind(&x->x_obj.ob_pd, bendin_sym);
1653 return (x);
1654}
1655
1656static void bendin_list(t_bendin *x, t_symbol *s, int argc, t_atom *argv)
1657{
1658 t_float value = atom_getfloatarg(0, argc, argv);
1659 t_float channel = atom_getfloatarg(1, argc, argv);
1660 if (x->x_channel != 0)
1661 {
1662 if (channel != x->x_channel) return;
1663 outlet_float(x->x_outlet1, value);
1664 }
1665 else
1666 {
1667 outlet_float(x->x_outlet2, channel);
1668 outlet_float(x->x_outlet1, value);
1669 }
1670}
1671
1672static void bendin_free(t_bendin *x)
1673{
1674 pd_unbind(&x->x_obj.ob_pd, bendin_sym);
1675}
1676
1677static void bendin_setup(void)
1678{
1679 bendin_class = class_new(gensym("bendin"), (t_newmethod)bendin_new,
1680 (t_method)bendin_free, sizeof(t_bendin), CLASS_NOINLET, A_DEFFLOAT, 0);
1681 class_addlist(bendin_class, bendin_list);
1682 class_sethelpsymbol(bendin_class, gensym("midi"));
1683 bendin_sym = gensym("#bendin");
1684}
1685
1686void inmidi_pitchbend(int portno, int channel, int value)
1687{
1688 if (bendin_sym->s_thing)
1689 {
1690 t_atom at[2];
1691 SETFLOAT(at, value);
1692 SETFLOAT(at+1, (channel + (portno << 4) + 1));
1693 pd_list(bendin_sym->s_thing, &s_list, 2, at);
1694 }
1695}
1696
1697/* ----------------------- touchin ------------------------- */
1698
1699static t_symbol *touchin_sym;
1700
1701static t_class *touchin_class;
1702
1703typedef struct _touchin
1704{
1705 t_object x_obj;
1706 t_float x_channel;
1707 t_outlet *x_outlet1;
1708 t_outlet *x_outlet2;
1709} t_touchin;
1710
1711static void *touchin_new(t_floatarg f)
1712{
1713 t_touchin *x = (t_touchin *)pd_new(touchin_class);
1714 x->x_channel = f;
1715 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1716 if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1717 pd_bind(&x->x_obj.ob_pd, touchin_sym);
1718 return (x);
1719}
1720
1721static void touchin_list(t_touchin *x, t_symbol *s, int argc, t_atom *argv)
1722{
1723 t_float value = atom_getfloatarg(0, argc, argv);
1724 t_float channel = atom_getfloatarg(1, argc, argv);
1725 if (x->x_channel)
1726 {
1727 if (channel != x->x_channel) return;
1728 outlet_float(x->x_outlet1, value);
1729 }
1730 else
1731 {
1732 outlet_float(x->x_outlet2, channel);
1733 outlet_float(x->x_outlet1, value);
1734 }
1735}
1736
1737static void touchin_free(t_touchin *x)
1738{
1739 pd_unbind(&x->x_obj.ob_pd, touchin_sym);
1740}
1741
1742static void touchin_setup(void)
1743{
1744 touchin_class = class_new(gensym("touchin"), (t_newmethod)touchin_new,
1745 (t_method)touchin_free, sizeof(t_touchin),
1746 CLASS_NOINLET, A_DEFFLOAT, 0);
1747 class_addlist(touchin_class, touchin_list);
1748 class_sethelpsymbol(touchin_class, gensym("midi"));
1749 touchin_sym = gensym("#touchin");
1750}
1751
1752void inmidi_aftertouch(int portno, int channel, int value)
1753{
1754 if (touchin_sym->s_thing)
1755 {
1756 t_atom at[2];
1757 SETFLOAT(at, value);
1758 SETFLOAT(at+1, (channel + (portno << 4) + 1));
1759 pd_list(touchin_sym->s_thing, &s_list, 2, at);
1760 }
1761}
1762
1763/* ----------------------- polytouchin ------------------------- */
1764
1765static t_symbol *polytouchin_sym;
1766
1767static t_class *polytouchin_class;
1768
1769typedef struct _polytouchin
1770{
1771 t_object x_obj;
1772 t_float x_channel;
1773 t_outlet *x_outlet1;
1774 t_outlet *x_outlet2;
1775 t_outlet *x_outlet3;
1776} t_polytouchin;
1777
1778static void *polytouchin_new(t_floatarg f)
1779{
1780 t_polytouchin *x = (t_polytouchin *)pd_new(polytouchin_class);
1781 x->x_channel = f;
1782 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1783 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1784 if (f == 0) x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
1785 pd_bind(&x->x_obj.ob_pd, polytouchin_sym);
1786 return (x);
1787}
1788
1789static void polytouchin_list(t_polytouchin *x, t_symbol *s, int argc,
1790 t_atom *argv)
1791{
1792 t_float pitch = atom_getfloatarg(0, argc, argv);
1793 t_float value = atom_getfloatarg(1, argc, argv);
1794 t_float channel = atom_getfloatarg(2, argc, argv);
1795 if (x->x_channel != 0)
1796 {
1797 if (channel != x->x_channel) return;
1798 outlet_float(x->x_outlet2, pitch);
1799 outlet_float(x->x_outlet1, value);
1800 }
1801 else
1802 {
1803 outlet_float(x->x_outlet3, channel);
1804 outlet_float(x->x_outlet2, pitch);
1805 outlet_float(x->x_outlet1, value);
1806 }
1807}
1808
1809static void polytouchin_free(t_polytouchin *x)
1810{
1811 pd_unbind(&x->x_obj.ob_pd, polytouchin_sym);
1812}
1813
1814static void polytouchin_setup(void)
1815{
1816 polytouchin_class = class_new(gensym("polytouchin"),
1817 (t_newmethod)polytouchin_new, (t_method)polytouchin_free,
1818 sizeof(t_polytouchin), CLASS_NOINLET, A_DEFFLOAT, 0);
1819 class_addlist(polytouchin_class, polytouchin_list);
1820 class_sethelpsymbol(polytouchin_class, gensym("midi"));
1821 polytouchin_sym = gensym("#polytouchin");
1822}
1823
1824void inmidi_polyaftertouch(int portno, int channel, int pitch, int value)
1825{
1826 if (polytouchin_sym->s_thing)
1827 {
1828 t_atom at[3];
1829 SETFLOAT(at, pitch);
1830 SETFLOAT(at+1, value);
1831 SETFLOAT(at+2, (channel + (portno << 4) + 1));
1832 pd_list(polytouchin_sym->s_thing, &s_list, 3, at);
1833 }
1834}
1835
1836/*----------------------- midiclkin--(midi F8 message )---------------------*/
1837static t_symbol *midiclkin_sym;
1838
1839static t_class *midiclkin_class;
1840
1841
1842typedef struct _midiclkin
1843{
1844 t_object x_obj;
1845 t_outlet *x_outlet1;
1846 t_outlet *x_outlet2;
1847} t_midiclkin;
1848
1849static void *midiclkin_new(t_floatarg f)
1850{
1851 t_midiclkin *x = (t_midiclkin *)pd_new(midiclkin_class);
1852 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1853 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1854 pd_bind(&x->x_obj.ob_pd, midiclkin_sym);
1855 return (x);
1856}
1857
1858static void midiclkin_list(t_midiclkin *x, t_symbol *s, int argc, t_atom *argv)
1859{
1860 float value = atom_getfloatarg(0, argc, argv);
1861 float count = atom_getfloatarg(1, argc, argv);
1862 outlet_float(x->x_outlet2, count);
1863 outlet_float(x->x_outlet1, value);
1864}
1865
1866static void midiclkin_free(t_midiclkin *x)
1867{
1868 pd_unbind(&x->x_obj.ob_pd, midiclkin_sym);
1869}
1870
1871static void midiclkin_setup(void)
1872{
1873 midiclkin_class = class_new(gensym("midiclkin"),
1874 (t_newmethod)midiclkin_new, (t_method)midiclkin_free,
1875 sizeof(t_midiclkin), CLASS_NOINLET, A_DEFFLOAT, 0);
1876 class_addlist(midiclkin_class, midiclkin_list);
1877 class_sethelpsymbol(midiclkin_class, gensym("midi"));
1878 midiclkin_sym = gensym("#midiclkin");
1879}
1880
1881void inmidi_clk(double timing)
1882{
1883
1884 static float prev = 0;
1885 static float count = 0;
1886 float cur,diff;
1887
1888 if (midiclkin_sym->s_thing)
1889 {
1890 t_atom at[2];
1891 diff =timing - prev;
1892 count++;
1893
1894 if (count == 3)
1895 { /* 24 count per quoter note */
1896 SETFLOAT(at, 1 );
1897 count = 0;
1898 }
1899 else SETFLOAT(at, 0);
1900
1901 SETFLOAT(at+1, diff);
1902 pd_list(midiclkin_sym->s_thing, &s_list, 2, at);
1903 prev = timing;
1904 }
1905}
1906
1907/*----------midirealtimein (midi FA,FB,FC,FF message )-----------------*/
1908
1909static t_symbol *midirealtimein_sym;
1910
1911static t_class *midirealtimein_class;
1912
1913typedef struct _midirealtimein
1914{
1915 t_object x_obj;
1916 t_outlet *x_outlet1;
1917 t_outlet *x_outlet2;
1918} t_midirealtimein;
1919
1920static void *midirealtimein_new( void)
1921{
1922 t_midirealtimein *x = (t_midirealtimein *)pd_new(midirealtimein_class);
1923 x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
1924 x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
1925 pd_bind(&x->x_obj.ob_pd, midirealtimein_sym);
1926#ifndef MSW
1927 pd_error(x, "midirealtimein: works under MSW only");
1928#endif
1929 return (x);
1930}
1931
1932static void midirealtimein_list(t_midirealtimein *x, t_symbol *s,
1933 int argc, t_atom *argv)
1934{
1935 float portno = atom_getfloatarg(0, argc, argv);
1936 float byte = atom_getfloatarg(1, argc, argv);
1937
1938 outlet_float(x->x_outlet2, portno);
1939 outlet_float(x->x_outlet1, byte);
1940}
1941
1942static void midirealtimein_free(t_midirealtimein *x)
1943{
1944 pd_unbind(&x->x_obj.ob_pd, midirealtimein_sym);
1945}
1946
1947static void midirealtimein_setup(void)
1948{
1949 midirealtimein_class = class_new(gensym("midirealtimein"),
1950 (t_newmethod)midirealtimein_new, (t_method)midirealtimein_free,
1951 sizeof(t_midirealtimein), CLASS_NOINLET, A_DEFFLOAT, 0);
1952 class_addlist(midirealtimein_class, midirealtimein_list);
1953 class_sethelpsymbol(midirealtimein_class, gensym("midi"));
1954 midirealtimein_sym = gensym("#midirealtimein");
1955}
1956
1957void inmidi_realtimein(int portno, int SysMsg)
1958{
1959 if (midirealtimein_sym->s_thing)
1960 {
1961 t_atom at[2];
1962 SETFLOAT(at, portno);
1963 SETFLOAT(at+1, SysMsg);
1964 pd_list(midirealtimein_sym->s_thing, &s_list, 1, at);
1965 }
1966}
1967
1968/* -------------------------- midiout -------------------------- */
1969
1970static t_class *midiout_class;
1971
1972void sys_putmidibyte(int portno, int byte);
1973
1974typedef struct _midiout
1975{
1976 t_object x_obj;
1977 t_float x_portno;
1978} t_midiout;
1979
1980static void *midiout_new(t_floatarg portno)
1981{
1982 t_midiout *x = (t_midiout *)pd_new(midiout_class);
1983 if (portno <= 0) portno = 1;
1984 x->x_portno = portno;
1985 floatinlet_new(&x->x_obj, &x->x_portno);
1986#ifdef __irix__
1987 post("midiout: unimplemented in IRIX");
1988#endif
1989 return (x);
1990}
1991
1992static void midiout_float(t_midiout *x, t_floatarg f)
1993{
1994 sys_putmidibyte(x->x_portno - 1, f);
1995}
1996
1997static void midiout_setup(void)
1998{
1999 midiout_class = class_new(gensym("midiout"), (t_newmethod)midiout_new, 0,
2000 sizeof(t_midiout), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
2001 class_addfloat(midiout_class, midiout_float);
2002 class_sethelpsymbol(midiout_class, gensym("midi"));
2003}
2004
2005/* -------------------------- noteout -------------------------- */
2006
2007static t_class *noteout_class;
2008
2009typedef struct _noteout
2010{
2011 t_object x_obj;
2012 t_float x_velo;
2013 t_float x_channel;
2014} t_noteout;
2015
2016static void *noteout_new(t_floatarg channel)
2017{
2018 t_noteout *x = (t_noteout *)pd_new(noteout_class);
2019 x->x_velo = 0;
2020 if (channel < 1) channel = 1;
2021 x->x_channel = channel;
2022 floatinlet_new(&x->x_obj, &x->x_velo);
2023 floatinlet_new(&x->x_obj, &x->x_channel);
2024 return (x);
2025}
2026
2027static void noteout_float(t_noteout *x, t_float f)
2028{
2029 int binchan = x->x_channel - 1;
2030 if (binchan < 0)
2031 binchan = 0;
2032 outmidi_noteon((binchan >> 4),
2033 (binchan & 15), (int)f, (int)x->x_velo);
2034}
2035
2036static void noteout_setup(void)
2037{
2038 noteout_class = class_new(gensym("noteout"), (t_newmethod)noteout_new, 0,
2039 sizeof(t_noteout), 0, A_DEFFLOAT, 0);
2040 class_addfloat(noteout_class, noteout_float);
2041 class_sethelpsymbol(noteout_class, gensym("midi"));
2042}
2043
2044
2045/* -------------------------- ctlout -------------------------- */
2046
2047static t_class *ctlout_class;
2048
2049typedef struct _ctlout
2050{
2051 t_object x_obj;
2052 t_float x_ctl;
2053 t_float x_channel;
2054} t_ctlout;
2055
2056static void *ctlout_new(t_floatarg ctl, t_floatarg channel)
2057{
2058 t_ctlout *x = (t_ctlout *)pd_new(ctlout_class);
2059 x->x_ctl = ctl;
2060 if (channel <= 0) channel = 1;
2061 x->x_channel = channel;
2062 floatinlet_new(&x->x_obj, &x->x_ctl);
2063 floatinlet_new(&x->x_obj, &x->x_channel);
2064 return (x);
2065}
2066
2067static void ctlout_float(t_ctlout *x, t_float f)
2068{
2069 int binchan = x->x_channel - 1;
2070 if (binchan < 0)
2071 binchan = 0;
2072 outmidi_controlchange((binchan >> 4),
2073 (binchan & 15), (int)(x->x_ctl), (int)f);
2074}
2075
2076static void ctlout_setup(void)
2077{
2078 ctlout_class = class_new(gensym("ctlout"), (t_newmethod)ctlout_new, 0,
2079 sizeof(t_ctlout), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
2080 class_addfloat(ctlout_class, ctlout_float);
2081 class_sethelpsymbol(ctlout_class, gensym("midi"));
2082}
2083
2084
2085/* -------------------------- pgmout -------------------------- */
2086
2087static t_class *pgmout_class;
2088
2089typedef struct _pgmout
2090{
2091 t_object x_obj;
2092 t_float x_channel;
2093} t_pgmout;
2094
2095static void *pgmout_new(t_floatarg channel)
2096{
2097 t_pgmout *x = (t_pgmout *)pd_new(pgmout_class);
2098 if (channel <= 0) channel = 1;
2099 x->x_channel = channel;
2100 floatinlet_new(&x->x_obj, &x->x_channel);
2101 return (x);
2102}
2103
2104static void pgmout_float(t_pgmout *x, t_floatarg f)
2105{
2106 int binchan = x->x_channel - 1;
2107 int n = f - 1;
2108 if (binchan < 0)
2109 binchan = 0;
2110 if (n < 0) n = 0;
2111 else if (n > 127) n = 127;
2112 outmidi_programchange((binchan >> 4),
2113 (binchan & 15), n);
2114}
2115
2116static void pgmout_setup(void)
2117{
2118 pgmout_class = class_new(gensym("pgmout"), (t_newmethod)pgmout_new, 0,
2119 sizeof(t_pgmout), 0, A_DEFFLOAT, 0);
2120 class_addfloat(pgmout_class, pgmout_float);
2121 class_sethelpsymbol(pgmout_class, gensym("midi"));
2122}
2123
2124
2125/* -------------------------- bendout -------------------------- */
2126
2127static t_class *bendout_class;
2128
2129typedef struct _bendout
2130{
2131 t_object x_obj;
2132 t_float x_channel;
2133} t_bendout;
2134
2135static void *bendout_new(t_floatarg channel)
2136{
2137 t_bendout *x = (t_bendout *)pd_new(bendout_class);
2138 if (channel <= 0) channel = 1;
2139 x->x_channel = channel;
2140 floatinlet_new(&x->x_obj, &x->x_channel);
2141 return (x);
2142}
2143
2144static void bendout_float(t_bendout *x, t_float f)
2145{
2146 int binchan = x->x_channel - 1;
2147 int n = (int)f + 8192;
2148 if (binchan < 0)
2149 binchan = 0;
2150 outmidi_pitchbend((binchan >> 4), (binchan & 15), n);
2151}
2152
2153static void bendout_setup(void)
2154{
2155 bendout_class = class_new(gensym("bendout"), (t_newmethod)bendout_new, 0,
2156 sizeof(t_bendout), 0, A_DEFFLOAT, 0);
2157 class_addfloat(bendout_class, bendout_float);
2158 class_sethelpsymbol(bendout_class, gensym("midi"));
2159}
2160
2161/* -------------------------- touch -------------------------- */
2162
2163static t_class *touchout_class;
2164
2165typedef struct _touchout
2166{
2167 t_object x_obj;
2168 t_float x_channel;
2169} t_touchout;
2170
2171static void *touchout_new(t_floatarg channel)
2172{
2173 t_touchout *x = (t_touchout *)pd_new(touchout_class);
2174 if (channel <= 0) channel = 1;
2175 x->x_channel = channel;
2176 floatinlet_new(&x->x_obj, &x->x_channel);
2177 return (x);
2178}
2179
2180static void touchout_float(t_touchout *x, t_float f)
2181{
2182 int binchan = x->x_channel - 1;
2183 if (binchan < 0)
2184 binchan = 0;
2185 outmidi_aftertouch((binchan >> 4), (binchan & 15), (int)f);
2186}
2187
2188static void touchout_setup(void)
2189{
2190 touchout_class = class_new(gensym("touchout"), (t_newmethod)touchout_new, 0,
2191 sizeof(t_touchout), 0, A_DEFFLOAT, 0);
2192 class_addfloat(touchout_class, touchout_float);
2193 class_sethelpsymbol(touchout_class, gensym("midi"));
2194}
2195
2196/* -------------------------- polytouch -------------------------- */
2197
2198static t_class *polytouchout_class;
2199
2200typedef struct _polytouchout
2201{
2202 t_object x_obj;
2203 t_float x_channel;
2204 t_float x_pitch;
2205} t_polytouchout;
2206
2207static void *polytouchout_new(t_floatarg channel)
2208{
2209 t_polytouchout *x = (t_polytouchout *)pd_new(polytouchout_class);
2210 if (channel <= 0) channel = 1;
2211 x->x_channel = channel;
2212 x->x_pitch = 0;
2213 floatinlet_new(&x->x_obj, &x->x_pitch);
2214 floatinlet_new(&x->x_obj, &x->x_channel);
2215 return (x);
2216}
2217
2218static void polytouchout_float(t_polytouchout *x, t_float n)
2219{
2220 int binchan = x->x_channel - 1;
2221 if (binchan < 0)
2222 binchan = 0;
2223 outmidi_polyaftertouch((binchan >> 4), (binchan & 15), x->x_pitch, n);
2224}
2225
2226static void polytouchout_setup(void)
2227{
2228 polytouchout_class = class_new(gensym("polytouchout"),
2229 (t_newmethod)polytouchout_new, 0,
2230 sizeof(t_polytouchout), 0, A_DEFFLOAT, 0);
2231 class_addfloat(polytouchout_class, polytouchout_float);
2232 class_sethelpsymbol(polytouchout_class, gensym("midi"));
2233}
2234
2235/* -------------------------- makenote -------------------------- */
2236
2237static t_class *makenote_class;
2238
2239typedef struct _hang
2240{
2241 t_clock *h_clock;
2242 struct _hang *h_next;
2243 t_float h_pitch;
2244 struct _makenote *h_owner;
2245} t_hang;
2246
2247typedef struct _makenote
2248{
2249 t_object x_obj;
2250 t_float x_velo;
2251 t_float x_dur;
2252 t_outlet *x_pitchout;
2253 t_outlet *x_velout;
2254 t_hang *x_hang;
2255} t_makenote;
2256
2257static void *makenote_new(t_floatarg velo, t_floatarg dur)
2258{
2259 t_makenote *x = (t_makenote *)pd_new(makenote_class);
2260 x->x_velo = velo;
2261 x->x_dur = dur;
2262 floatinlet_new(&x->x_obj, &x->x_velo);
2263 floatinlet_new(&x->x_obj, &x->x_dur);
2264 x->x_pitchout = outlet_new(&x->x_obj, &s_float);
2265 x->x_velout = outlet_new(&x->x_obj, &s_float);
2266 x->x_hang = 0;
2267 return (x);
2268}
2269
2270static void makenote_tick(t_hang *hang)
2271{
2272 t_makenote *x = hang->h_owner;
2273 t_hang *h2, *h3;
2274 outlet_float(x->x_velout, 0);
2275 outlet_float(x->x_pitchout, hang->h_pitch);
2276 if (x->x_hang == hang) x->x_hang = hang->h_next;
2277 else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3)
2278 {
2279 if (h3 == hang)
2280 {
2281 h2->h_next = h3->h_next;
2282 break;
2283 }
2284 }
2285 clock_free(hang->h_clock);
2286 freebytes(hang, sizeof(*hang));
2287}
2288
2289static void makenote_float(t_makenote *x, t_float f)
2290{
2291 t_hang *hang;
2292 if (!x->x_velo) return;
2293 outlet_float(x->x_velout, x->x_velo);
2294 outlet_float(x->x_pitchout, f);
2295 hang = (t_hang *)getbytes(sizeof *hang);
2296 hang->h_next = x->x_hang;
2297 x->x_hang = hang;
2298 hang->h_pitch = f;
2299 hang->h_owner = x;
2300 hang->h_clock = clock_new(hang, (t_method)makenote_tick);
2301 clock_delay(hang->h_clock, (x->x_dur >= 0 ? x->x_dur : 0));
2302}
2303
2304static void makenote_stop(t_makenote *x)
2305{
2306 t_hang *hang;
2307 while (hang = x->x_hang)
2308 {
2309 outlet_float(x->x_velout, 0);
2310 outlet_float(x->x_pitchout, hang->h_pitch);
2311 x->x_hang = hang->h_next;
2312 clock_free(hang->h_clock);
2313 freebytes(hang, sizeof(*hang));
2314 }
2315}
2316
2317static void makenote_clear(t_makenote *x)
2318{
2319 t_hang *hang;
2320 while (hang = x->x_hang)
2321 {
2322 x->x_hang = hang->h_next;
2323 clock_free(hang->h_clock);
2324 freebytes(hang, sizeof(*hang));
2325 }
2326}
2327
2328static void makenote_setup(void)
2329{
2330 makenote_class = class_new(gensym("makenote"),
2331 (t_newmethod)makenote_new, (t_method)makenote_clear,
2332 sizeof(t_makenote), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
2333 class_addfloat(makenote_class, makenote_float);
2334 class_addmethod(makenote_class, (t_method)makenote_stop, gensym("stop"),
2335 0);
2336 class_addmethod(makenote_class, (t_method)makenote_clear, gensym("clear"),
2337 0);
2338}
2339
2340/* -------------------------- stripnote -------------------------- */
2341
2342static t_class *stripnote_class;
2343
2344typedef struct _stripnote
2345{
2346 t_object x_obj;
2347 t_float x_velo;
2348 t_outlet *x_pitchout;
2349 t_outlet *x_velout;
2350} t_stripnote;
2351
2352static void *stripnote_new(void )
2353{
2354 t_stripnote *x = (t_stripnote *)pd_new(stripnote_class);
2355 floatinlet_new(&x->x_obj, &x->x_velo);
2356 x->x_pitchout = outlet_new(&x->x_obj, &s_float);
2357 x->x_velout = outlet_new(&x->x_obj, &s_float);
2358 return (x);
2359}
2360
2361static void stripnote_float(t_stripnote *x, t_float f)
2362{
2363 t_hang *hang;
2364 if (!x->x_velo) return;
2365 outlet_float(x->x_velout, x->x_velo);
2366 outlet_float(x->x_pitchout, f);
2367}
2368
2369static void stripnote_setup(void)
2370{
2371 stripnote_class = class_new(gensym("stripnote"),
2372 (t_newmethod)stripnote_new, 0, sizeof(t_stripnote), 0, 0);
2373 class_addfloat(stripnote_class, stripnote_float);
2374}
2375
2376/* -------------------------- poly -------------------------- */
2377
2378static t_class *poly_class;
2379
2380typedef struct voice
2381{
2382 float v_pitch;
2383 int v_used;
2384 unsigned long v_serial;
2385} t_voice;
2386
2387typedef struct poly
2388{
2389 t_object x_obj;
2390 int x_n;
2391 t_voice *x_vec;
2392 float x_vel;
2393 t_outlet *x_pitchout;
2394 t_outlet *x_velout;
2395 unsigned long x_serial;
2396 int x_steal;
2397} t_poly;
2398
2399static void *poly_new(float fnvoice, float fsteal)
2400{
2401 int i, n = fnvoice;
2402 t_poly *x = (t_poly *)pd_new(poly_class);
2403 t_voice *v;
2404 if (n < 1) n = 1;
2405 x->x_n = n;
2406 x->x_vec = (t_voice *)getbytes(n * sizeof(*x->x_vec));
2407 for (v = x->x_vec, i = n; i--; v++)
2408 v->v_pitch = v->v_used = v->v_serial = 0;
2409 x->x_vel = 0;
2410 x->x_steal = (fsteal != 0);
2411 floatinlet_new(&x->x_obj, &x->x_vel);
2412 outlet_new(&x->x_obj, &s_float);
2413 x->x_pitchout = outlet_new(&x->x_obj, &s_float);
2414 x->x_velout = outlet_new(&x->x_obj, &s_float);
2415 x->x_serial = 0;
2416 return (x);
2417}
2418
2419static void poly_float(t_poly *x, t_float f)
2420{
2421 int i;
2422 t_voice *v;
2423 t_voice *firston, *firstoff;
2424 unsigned int serialon, serialoff, onindex = 0, offindex = 0;
2425 if (x->x_vel > 0)
2426 {
2427 /* note on. Look for a vacant voice */
2428 for (v = x->x_vec, i = 0, firston = firstoff = 0,
2429 serialon = serialoff = 0xffffffff; i < x->x_n; v++, i++)
2430 {
2431 if (v->v_used && v->v_serial < serialon)
2432 firston = v, serialon = v->v_serial, onindex = i;
2433 else if (!v->v_used && v->v_serial < serialoff)
2434 firstoff = v, serialoff = v->v_serial, offindex = i;
2435 }
2436 if (firstoff)
2437 {
2438 outlet_float(x->x_velout, x->x_vel);
2439 outlet_float(x->x_pitchout, firstoff->v_pitch = f);
2440 outlet_float(x->x_obj.ob_outlet, offindex+1);
2441 firstoff->v_used = 1;
2442 firstoff->v_serial = x->x_serial++;
2443 }
2444 /* if none, steal one */
2445 else if (firston && x->x_steal)
2446 {
2447 outlet_float(x->x_velout, 0);
2448 outlet_float(x->x_pitchout, firston->v_pitch);
2449 outlet_float(x->x_obj.ob_outlet, onindex+1);
2450 outlet_float(x->x_velout, x->x_vel);
2451 outlet_float(x->x_pitchout, firston->v_pitch = f);
2452 outlet_float(x->x_obj.ob_outlet, onindex+1);
2453 firston->v_serial = x->x_serial++;
2454 }
2455 }
2456 else /* note off. Turn off oldest match */
2457 {
2458 for (v = x->x_vec, i = 0, firston = 0, serialon = 0xffffffff;
2459 i < x->x_n; v++, i++)
2460 if (v->v_used && v->v_pitch == f && v->v_serial < serialon)
2461 firston = v, serialon = v->v_serial, onindex = i;
2462 if (firston)
2463 {
2464 firston->v_used = 0;
2465 firston->v_serial = x->x_serial++;
2466 outlet_float(x->x_velout, 0);
2467 outlet_float(x->x_pitchout, firston->v_pitch);
2468 outlet_float(x->x_obj.ob_outlet, onindex+1);
2469 }
2470 }
2471}
2472
2473static void poly_stop(t_poly *x)
2474{
2475 int i;
2476 t_voice *v;
2477 for (i = 0, v = x->x_vec; i < x->x_n; i++, v++)
2478 if (v->v_used)
2479 {
2480 outlet_float(x->x_velout, 0L);
2481 outlet_float(x->x_pitchout, v->v_pitch);
2482 outlet_float(x->x_obj.ob_outlet, i+1);
2483 v->v_used = 0;
2484 v->v_serial = x->x_serial++;
2485 }
2486}
2487
2488static void poly_clear(t_poly *x)
2489{
2490 int i;
2491 t_voice *v;
2492 for (v = x->x_vec, i = x->x_n; i--; v++) v->v_used = v->v_serial = 0;
2493}
2494
2495static void poly_free(t_poly *x)
2496{
2497 freebytes(x->x_vec, x->x_n * sizeof (*x->x_vec));
2498}
2499
2500static void poly_setup(void)
2501{
2502 poly_class = class_new(gensym("poly"),
2503 (t_newmethod)poly_new, (t_method)poly_clear,
2504 sizeof(t_poly), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
2505 class_addfloat(poly_class, poly_float);
2506 class_addmethod(poly_class, (t_method)poly_stop, gensym("stop"), 0);
2507 class_addmethod(poly_class, (t_method)poly_clear, gensym("clear"), 0);
2508}
2509
2510/* -------------------------- bag -------------------------- */
2511
2512static t_class *bag_class;
2513
2514typedef struct _bagelem
2515{
2516 struct _bagelem *e_next;
2517 t_float e_value;
2518} t_bagelem;
2519
2520typedef struct _bag
2521{
2522 t_object x_obj;
2523 t_float x_velo;
2524 t_bagelem *x_first;
2525} t_bag;
2526
2527static void *bag_new(void )
2528{
2529 t_bag *x = (t_bag *)pd_new(bag_class);
2530 x->x_velo = 0;
2531 floatinlet_new(&x->x_obj, &x->x_velo);
2532 outlet_new(&x->x_obj, &s_float);
2533 x->x_first = 0;
2534 return (x);
2535}
2536
2537static void bag_float(t_bag *x, t_float f)
2538{
2539 t_bagelem *bagelem, *e2, *e3;
2540 if (x->x_velo != 0)
2541 {
2542 bagelem = (t_bagelem *)getbytes(sizeof *bagelem);
2543 bagelem->e_next = 0;
2544 bagelem->e_value = f;
2545 if (!x->x_first) x->x_first = bagelem;
2546 else /* LATER replace with a faster algorithm */
2547 {
2548 for (e2 = x->x_first; e3 = e2->e_next; e2 = e3)
2549 ;
2550 e2->e_next = bagelem;
2551 }
2552 }
2553 else
2554 {
2555 if (!x->x_first) return;
2556 if (x->x_first->e_value == f)
2557 {
2558 bagelem = x->x_first;
2559 x->x_first = x->x_first->e_next;
2560 freebytes(bagelem, sizeof(*bagelem));
2561 return;
2562 }
2563 for (e2 = x->x_first; e3 = e2->e_next; e2 = e3)
2564 if (e3->e_value == f)
2565 {
2566 e2->e_next = e3->e_next;
2567 freebytes(e3, sizeof(*e3));
2568 return;
2569 }
2570 }
2571}
2572
2573static void bag_flush(t_bag *x)
2574{
2575 t_bagelem *bagelem;
2576 while (bagelem = x->x_first)
2577 {
2578 outlet_float(x->x_obj.ob_outlet, bagelem->e_value);
2579 x->x_first = bagelem->e_next;
2580 freebytes(bagelem, sizeof(*bagelem));
2581 }
2582}
2583
2584static void bag_clear(t_bag *x)
2585{
2586 t_bagelem *bagelem;
2587 while (bagelem = x->x_first)
2588 {
2589 x->x_first = bagelem->e_next;
2590 freebytes(bagelem, sizeof(*bagelem));
2591 }
2592}
2593
2594static void bag_setup(void)
2595{
2596 bag_class = class_new(gensym("bag"),
2597 (t_newmethod)bag_new, (t_method)bag_clear,
2598 sizeof(t_bag), 0, 0);
2599 class_addfloat(bag_class, bag_float);
2600 class_addmethod(bag_class, (t_method)bag_flush, gensym("flush"), 0);
2601 class_addmethod(bag_class, (t_method)bag_clear, gensym("clear"), 0);
2602}
2603
2604void x_midi_setup(void)
2605{
2606 midiin_setup();
2607 midirealtimein_setup();
2608 notein_setup();
2609 ctlin_setup();
2610 pgmin_setup();
2611 bendin_setup();
2612 touchin_setup();
2613 polytouchin_setup();
2614 midiclkin_setup();
2615 midiout_setup();
2616 noteout_setup();
2617 ctlout_setup();
2618 pgmout_setup();
2619 bendout_setup();
2620 touchout_setup();
2621 polytouchout_setup();
2622 makenote_setup();
2623 stripnote_setup();
2624 poly_setup();
2625 bag_setup();
2626}
diff --git a/apps/plugins/pdbox/PDa/src/x_misc.c b/apps/plugins/pdbox/PDa/src/x_misc.c
new file mode 100644
index 0000000000..394b294f62
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_misc.c
@@ -0,0 +1,642 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* misc. */
6
7#include "m_pd.h"
8#include "s_stuff.h"
9#include <math.h>
10#include <stdio.h>
11#include <string.h>
12#ifdef UNIX
13#include <sys/types.h>
14#include <sys/time.h>
15#include <sys/times.h>
16//#include <sys/param.h>
17#endif
18#ifdef MSW
19#include <wtypes.h>
20#include <time.h>
21#endif
22
23#if defined (MACOSX) || defined (__FreeBSD__)
24#define HZ CLK_TCK
25#endif
26
27/* -------------------------- random ------------------------------ */
28/* this is strictly homebrew and untested. */
29
30static t_class *random_class;
31
32typedef struct _random
33{
34 t_object x_obj;
35 t_float x_f;
36 unsigned int x_state;
37} t_random;
38
39
40static int makeseed(void)
41{
42 static unsigned int random_nextseed = 1489853723;
43 random_nextseed = random_nextseed * 435898247 + 938284287;
44 return (random_nextseed & 0x7fffffff);
45}
46
47static void *random_new(t_floatarg f)
48{
49 t_random *x = (t_random *)pd_new(random_class);
50 x->x_f = f;
51 x->x_state = makeseed();
52 floatinlet_new(&x->x_obj, &x->x_f);
53 outlet_new(&x->x_obj, &s_float);
54 return (x);
55}
56
57static void random_bang(t_random *x)
58{
59 int n = x->x_f, nval;
60 int range = (n < 1 ? 1 : n);
61 unsigned int randval = x->x_state;
62 x->x_state = randval = randval * 472940017 + 832416023;
63 nval = ((double)range) * ((double)randval)
64 * (1./4294967296.);
65 if (nval >= range) nval = range-1;
66 outlet_float(x->x_obj.ob_outlet, nval);
67}
68
69static void random_seed(t_random *x, float f, float glob)
70{
71 x->x_state = f;
72}
73
74static void random_setup(void)
75{
76 random_class = class_new(gensym("random"), (t_newmethod)random_new, 0,
77 sizeof(t_random), 0, A_DEFFLOAT, 0);
78 class_addbang(random_class, random_bang);
79 class_addmethod(random_class, (t_method)random_seed,
80 gensym("seed"), A_FLOAT, 0);
81}
82
83
84/* -------------------------- loadbang ------------------------------ */
85static t_class *loadbang_class;
86
87typedef struct _loadbang
88{
89 t_object x_obj;
90} t_loadbang;
91
92static void *loadbang_new(void)
93{
94 t_loadbang *x = (t_loadbang *)pd_new(loadbang_class);
95 outlet_new(&x->x_obj, &s_bang);
96 return (x);
97}
98
99static void loadbang_loadbang(t_loadbang *x)
100{
101 if (!sys_noloadbang)
102 outlet_bang(x->x_obj.ob_outlet);
103}
104
105static void loadbang_setup(void)
106{
107 loadbang_class = class_new(gensym("loadbang"), (t_newmethod)loadbang_new, 0,
108 sizeof(t_loadbang), 0, 0);
109 class_addmethod(loadbang_class, (t_method)loadbang_loadbang,
110 gensym("loadbang"), 0);
111}
112
113/* ------------- namecanvas (delete this later) --------------------- */
114static t_class *namecanvas_class;
115
116typedef struct _namecanvas
117{
118 t_object x_obj;
119 t_symbol *x_sym;
120 t_pd *x_owner;
121} t_namecanvas;
122
123static void *namecanvas_new(t_symbol *s)
124{
125 t_namecanvas *x = (t_namecanvas *)pd_new(namecanvas_class);
126 x->x_owner = (t_pd *)canvas_getcurrent();
127 x->x_sym = s;
128 if (*s->s_name) pd_bind(x->x_owner, s);
129 return (x);
130}
131
132static void namecanvas_free(t_namecanvas *x)
133{
134 if (*x->x_sym->s_name) pd_unbind(x->x_owner, x->x_sym);
135}
136
137static void namecanvas_setup(void)
138{
139 namecanvas_class = class_new(gensym("namecanvas"),
140 (t_newmethod)namecanvas_new, (t_method)namecanvas_free,
141 sizeof(t_namecanvas), CLASS_NOINLET, A_DEFSYM, 0);
142}
143
144/* ---------------serial ports (MSW only -- hack) ------------------------- */
145#define MAXSERIAL 100
146
147static t_class *serial_class;
148
149typedef struct _serial
150{
151 t_object x_obj;
152 int x_portno;
153 int x_open;
154} t_serial;
155
156static void serial_float(t_serial *x, t_float f)
157{
158 int n = f;
159 char message[MAXSERIAL * 4 + 100];
160 if (!x->x_open)
161 {
162 sys_vgui("com%d_open\n", x->x_portno);
163 x->x_open = 1;
164 }
165 sprintf(message, "com%d_send \"\\%3.3o\"\n", x->x_portno, n);
166 sys_gui(message);
167}
168
169static void *serial_new(t_floatarg fportno)
170{
171 int portno = fportno;
172 t_serial *x = (t_serial *)pd_new(serial_class);
173 if (!portno) portno = 1;
174 x->x_portno = portno;
175 x->x_open = 0;
176 return (x);
177}
178
179static void serial_setup(void)
180{
181 serial_class = class_new(gensym("serial"), (t_newmethod)serial_new, 0,
182 sizeof(t_serial), 0, A_DEFFLOAT, 0);
183 class_addfloat(serial_class, serial_float);
184}
185
186/* -------------------------- cputime ------------------------------ */
187
188static t_class *cputime_class;
189
190typedef struct _cputime
191{
192 t_object x_obj;
193#ifdef UNIX
194 struct tms x_setcputime;
195#endif
196#ifdef MSW
197 LARGE_INTEGER x_kerneltime;
198 LARGE_INTEGER x_usertime;
199 int x_warned;
200#endif
201} t_cputime;
202
203static void cputime_bang(t_cputime *x)
204{
205#ifdef UNIX
206 times(&x->x_setcputime);
207#endif
208#ifdef MSW
209 FILETIME ignorethis, ignorethat;
210 BOOL retval;
211 retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
212 (FILETIME *)&x->x_kerneltime, (FILETIME *)&x->x_usertime);
213 if (!retval)
214 {
215 if (!x->x_warned)
216 post("cputime is apparently not supported on your platform");
217 x->x_warned = 1;
218 x->x_kerneltime.QuadPart = 0;
219 x->x_usertime.QuadPart = 0;
220 }
221#endif
222}
223
224#define HZ 100
225static void cputime_bang2(t_cputime *x)
226{
227#ifdef UNIX
228 float elapsedcpu;
229 struct tms newcputime;
230 times(&newcputime);
231 elapsedcpu = 1000 * (
232 newcputime.tms_utime + newcputime.tms_stime -
233 x->x_setcputime.tms_utime - x->x_setcputime.tms_stime) / HZ;
234 outlet_float(x->x_obj.ob_outlet, elapsedcpu);
235#endif
236#ifdef MSW
237 float elapsedcpu;
238 FILETIME ignorethis, ignorethat;
239 LARGE_INTEGER usertime, kerneltime;
240 BOOL retval;
241
242 retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
243 (FILETIME *)&kerneltime, (FILETIME *)&usertime);
244 if (retval)
245 elapsedcpu = 0.0001 *
246 ((kerneltime.QuadPart - x->x_kerneltime.QuadPart) +
247 (usertime.QuadPart - x->x_usertime.QuadPart));
248 else elapsedcpu = 0;
249 outlet_float(x->x_obj.ob_outlet, elapsedcpu);
250#endif
251}
252
253static void *cputime_new(void)
254{
255 t_cputime *x = (t_cputime *)pd_new(cputime_class);
256 outlet_new(&x->x_obj, gensym("float"));
257
258 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
259#ifdef MSW
260 x->x_warned = 0;
261#endif
262 cputime_bang(x);
263 return (x);
264}
265
266static void cputime_setup(void)
267{
268 cputime_class = class_new(gensym("cputime"), (t_newmethod)cputime_new, 0,
269 sizeof(t_cputime), 0, 0);
270 class_addbang(cputime_class, cputime_bang);
271 class_addmethod(cputime_class, (t_method)cputime_bang2, gensym("bang2"), 0);
272}
273
274/* -------------------------- realtime ------------------------------ */
275
276static t_class *realtime_class;
277
278typedef struct _realtime
279{
280 t_object x_obj;
281 double x_setrealtime;
282} t_realtime;
283
284static void realtime_bang(t_realtime *x)
285{
286 x->x_setrealtime = sys_getrealtime();
287}
288
289static void realtime_bang2(t_realtime *x)
290{
291 outlet_float(x->x_obj.ob_outlet,
292 (sys_getrealtime() - x->x_setrealtime) * 1000.);
293}
294
295static void *realtime_new(void)
296{
297 t_realtime *x = (t_realtime *)pd_new(realtime_class);
298 outlet_new(&x->x_obj, gensym("float"));
299 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
300 realtime_bang(x);
301 return (x);
302}
303
304static void realtime_setup(void)
305{
306 realtime_class = class_new(gensym("realtime"), (t_newmethod)realtime_new, 0,
307 sizeof(t_realtime), 0, 0);
308 class_addbang(realtime_class, realtime_bang);
309 class_addmethod(realtime_class, (t_method)realtime_bang2, gensym("bang2"),
310 0);
311}
312
313void x_misc_setup(void)
314{
315 random_setup();
316 loadbang_setup();
317 namecanvas_setup();
318 serial_setup();
319 cputime_setup();
320 realtime_setup();
321}
322/* Copyright (c) 1997-1999 Miller Puckette.
323* For information on usage and redistribution, and for a DISCLAIMER OF ALL
324* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
325
326/* misc. */
327
328#include "m_pd.h"
329#include "s_stuff.h"
330#include <math.h>
331#include <stdio.h>
332#include <string.h>
333#ifdef UNIX
334#include <sys/types.h>
335#include <sys/time.h>
336#include <sys/times.h>
337//#include <sys/param.h>
338#endif
339#ifdef MSW
340#include <wtypes.h>
341#include <time.h>
342#endif
343
344#if defined (MACOSX) || defined (__FreeBSD__)
345#define HZ CLK_TCK
346#endif
347
348/* -------------------------- random ------------------------------ */
349/* this is strictly homebrew and untested. */
350
351static t_class *random_class;
352
353typedef struct _random
354{
355 t_object x_obj;
356 t_float x_f;
357 unsigned int x_state;
358} t_random;
359
360
361static int makeseed(void)
362{
363 static unsigned int random_nextseed = 1489853723;
364 random_nextseed = random_nextseed * 435898247 + 938284287;
365 return (random_nextseed & 0x7fffffff);
366}
367
368static void *random_new(t_floatarg f)
369{
370 t_random *x = (t_random *)pd_new(random_class);
371 x->x_f = f;
372 x->x_state = makeseed();
373 floatinlet_new(&x->x_obj, &x->x_f);
374 outlet_new(&x->x_obj, &s_float);
375 return (x);
376}
377
378static void random_bang(t_random *x)
379{
380 int n = x->x_f, nval;
381 int range = (n < 1 ? 1 : n);
382 unsigned int randval = x->x_state;
383 x->x_state = randval = randval * 472940017 + 832416023;
384 nval = ((double)range) * ((double)randval)
385 * (1./4294967296.);
386 if (nval >= range) nval = range-1;
387 outlet_float(x->x_obj.ob_outlet, nval);
388}
389
390static void random_seed(t_random *x, float f, float glob)
391{
392 x->x_state = f;
393}
394
395static void random_setup(void)
396{
397 random_class = class_new(gensym("random"), (t_newmethod)random_new, 0,
398 sizeof(t_random), 0, A_DEFFLOAT, 0);
399 class_addbang(random_class, random_bang);
400 class_addmethod(random_class, (t_method)random_seed,
401 gensym("seed"), A_FLOAT, 0);
402}
403
404
405/* -------------------------- loadbang ------------------------------ */
406static t_class *loadbang_class;
407
408typedef struct _loadbang
409{
410 t_object x_obj;
411} t_loadbang;
412
413static void *loadbang_new(void)
414{
415 t_loadbang *x = (t_loadbang *)pd_new(loadbang_class);
416 outlet_new(&x->x_obj, &s_bang);
417 return (x);
418}
419
420static void loadbang_loadbang(t_loadbang *x)
421{
422 if (!sys_noloadbang)
423 outlet_bang(x->x_obj.ob_outlet);
424}
425
426static void loadbang_setup(void)
427{
428 loadbang_class = class_new(gensym("loadbang"), (t_newmethod)loadbang_new, 0,
429 sizeof(t_loadbang), 0, 0);
430 class_addmethod(loadbang_class, (t_method)loadbang_loadbang,
431 gensym("loadbang"), 0);
432}
433
434/* ------------- namecanvas (delete this later) --------------------- */
435static t_class *namecanvas_class;
436
437typedef struct _namecanvas
438{
439 t_object x_obj;
440 t_symbol *x_sym;
441 t_pd *x_owner;
442} t_namecanvas;
443
444static void *namecanvas_new(t_symbol *s)
445{
446 t_namecanvas *x = (t_namecanvas *)pd_new(namecanvas_class);
447 x->x_owner = (t_pd *)canvas_getcurrent();
448 x->x_sym = s;
449 if (*s->s_name) pd_bind(x->x_owner, s);
450 return (x);
451}
452
453static void namecanvas_free(t_namecanvas *x)
454{
455 if (*x->x_sym->s_name) pd_unbind(x->x_owner, x->x_sym);
456}
457
458static void namecanvas_setup(void)
459{
460 namecanvas_class = class_new(gensym("namecanvas"),
461 (t_newmethod)namecanvas_new, (t_method)namecanvas_free,
462 sizeof(t_namecanvas), CLASS_NOINLET, A_DEFSYM, 0);
463}
464
465/* ---------------serial ports (MSW only -- hack) ------------------------- */
466#define MAXSERIAL 100
467
468static t_class *serial_class;
469
470typedef struct _serial
471{
472 t_object x_obj;
473 int x_portno;
474 int x_open;
475} t_serial;
476
477static void serial_float(t_serial *x, t_float f)
478{
479 int n = f;
480 char message[MAXSERIAL * 4 + 100];
481 if (!x->x_open)
482 {
483 sys_vgui("com%d_open\n", x->x_portno);
484 x->x_open = 1;
485 }
486 sprintf(message, "com%d_send \"\\%3.3o\"\n", x->x_portno, n);
487 sys_gui(message);
488}
489
490static void *serial_new(t_floatarg fportno)
491{
492 int portno = fportno;
493 t_serial *x = (t_serial *)pd_new(serial_class);
494 if (!portno) portno = 1;
495 x->x_portno = portno;
496 x->x_open = 0;
497 return (x);
498}
499
500static void serial_setup(void)
501{
502 serial_class = class_new(gensym("serial"), (t_newmethod)serial_new, 0,
503 sizeof(t_serial), 0, A_DEFFLOAT, 0);
504 class_addfloat(serial_class, serial_float);
505}
506
507/* -------------------------- cputime ------------------------------ */
508
509static t_class *cputime_class;
510
511typedef struct _cputime
512{
513 t_object x_obj;
514#ifdef UNIX
515 struct tms x_setcputime;
516#endif
517#ifdef MSW
518 LARGE_INTEGER x_kerneltime;
519 LARGE_INTEGER x_usertime;
520 int x_warned;
521#endif
522} t_cputime;
523
524static void cputime_bang(t_cputime *x)
525{
526#ifdef UNIX
527 times(&x->x_setcputime);
528#endif
529#ifdef MSW
530 FILETIME ignorethis, ignorethat;
531 BOOL retval;
532 retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
533 (FILETIME *)&x->x_kerneltime, (FILETIME *)&x->x_usertime);
534 if (!retval)
535 {
536 if (!x->x_warned)
537 post("cputime is apparently not supported on your platform");
538 x->x_warned = 1;
539 x->x_kerneltime.QuadPart = 0;
540 x->x_usertime.QuadPart = 0;
541 }
542#endif
543}
544
545#define HZ 100
546static void cputime_bang2(t_cputime *x)
547{
548#ifdef UNIX
549 float elapsedcpu;
550 struct tms newcputime;
551 times(&newcputime);
552 elapsedcpu = 1000 * (
553 newcputime.tms_utime + newcputime.tms_stime -
554 x->x_setcputime.tms_utime - x->x_setcputime.tms_stime) / HZ;
555 outlet_float(x->x_obj.ob_outlet, elapsedcpu);
556#endif
557#ifdef MSW
558 float elapsedcpu;
559 FILETIME ignorethis, ignorethat;
560 LARGE_INTEGER usertime, kerneltime;
561 BOOL retval;
562
563 retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
564 (FILETIME *)&kerneltime, (FILETIME *)&usertime);
565 if (retval)
566 elapsedcpu = 0.0001 *
567 ((kerneltime.QuadPart - x->x_kerneltime.QuadPart) +
568 (usertime.QuadPart - x->x_usertime.QuadPart));
569 else elapsedcpu = 0;
570 outlet_float(x->x_obj.ob_outlet, elapsedcpu);
571#endif
572}
573
574static void *cputime_new(void)
575{
576 t_cputime *x = (t_cputime *)pd_new(cputime_class);
577 outlet_new(&x->x_obj, gensym("float"));
578
579 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
580#ifdef MSW
581 x->x_warned = 0;
582#endif
583 cputime_bang(x);
584 return (x);
585}
586
587static void cputime_setup(void)
588{
589 cputime_class = class_new(gensym("cputime"), (t_newmethod)cputime_new, 0,
590 sizeof(t_cputime), 0, 0);
591 class_addbang(cputime_class, cputime_bang);
592 class_addmethod(cputime_class, (t_method)cputime_bang2, gensym("bang2"), 0);
593}
594
595/* -------------------------- realtime ------------------------------ */
596
597static t_class *realtime_class;
598
599typedef struct _realtime
600{
601 t_object x_obj;
602 double x_setrealtime;
603} t_realtime;
604
605static void realtime_bang(t_realtime *x)
606{
607 x->x_setrealtime = sys_getrealtime();
608}
609
610static void realtime_bang2(t_realtime *x)
611{
612 outlet_float(x->x_obj.ob_outlet,
613 (sys_getrealtime() - x->x_setrealtime) * 1000.);
614}
615
616static void *realtime_new(void)
617{
618 t_realtime *x = (t_realtime *)pd_new(realtime_class);
619 outlet_new(&x->x_obj, gensym("float"));
620 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
621 realtime_bang(x);
622 return (x);
623}
624
625static void realtime_setup(void)
626{
627 realtime_class = class_new(gensym("realtime"), (t_newmethod)realtime_new, 0,
628 sizeof(t_realtime), 0, 0);
629 class_addbang(realtime_class, realtime_bang);
630 class_addmethod(realtime_class, (t_method)realtime_bang2, gensym("bang2"),
631 0);
632}
633
634void x_misc_setup(void)
635{
636 random_setup();
637 loadbang_setup();
638 namecanvas_setup();
639 serial_setup();
640 cputime_setup();
641 realtime_setup();
642}
diff --git a/apps/plugins/pdbox/PDa/src/x_net.c b/apps/plugins/pdbox/PDa/src/x_net.c
new file mode 100644
index 0000000000..5094661214
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_net.c
@@ -0,0 +1,726 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* network */
6
7#include "m_pd.h"
8#include "s_stuff.h"
9
10#include <sys/types.h>
11#include <string.h>
12#ifdef UNIX
13#include <sys/socket.h>
14#include <netinet/in.h>
15#include <netinet/tcp.h>
16#include <netdb.h>
17#include <stdio.h>
18#define SOCKET_ERROR -1
19#else
20#include <winsock.h>
21#endif
22
23static t_class *netsend_class;
24
25typedef struct _netsend
26{
27 t_object x_obj;
28 int x_fd;
29 int x_protocol;
30} t_netsend;
31
32static void *netsend_new(t_floatarg udpflag)
33{
34 t_netsend *x = (t_netsend *)pd_new(netsend_class);
35 outlet_new(&x->x_obj, &s_float);
36 x->x_fd = -1;
37 x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM);
38 return (x);
39}
40
41static void netsend_connect(t_netsend *x, t_symbol *hostname,
42 t_floatarg fportno)
43{
44 struct sockaddr_in server;
45 struct hostent *hp;
46 int sockfd;
47 int portno = fportno;
48 int intarg;
49 if (x->x_fd >= 0)
50 {
51 error("netsend_connect: already connected");
52 return;
53 }
54
55 /* create a socket */
56 sockfd = socket(AF_INET, x->x_protocol, 0);
57#if 0
58 fprintf(stderr, "send socket %d\n", sockfd);
59#endif
60 if (sockfd < 0)
61 {
62 sys_sockerror("socket");
63 return;
64 }
65 /* connect socket using hostname provided in command line */
66 server.sin_family = AF_INET;
67 hp = gethostbyname(hostname->s_name);
68 if (hp == 0)
69 {
70 post("bad host?\n");
71 return;
72 }
73#if 0
74 intarg = 0;
75 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
76 &intarg, sizeof(intarg)) < 0)
77 post("setsockopt (SO_RCVBUF) failed\n");
78#endif
79 /* for stream (TCP) sockets, specify "nodelay" */
80 if (x->x_protocol == SOCK_STREAM)
81 {
82 intarg = 1;
83 if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
84 &intarg, sizeof(intarg)) < 0)
85 post("setsockopt (TCP_NODELAY) failed\n");
86 }
87 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
88
89 /* assign client port number */
90 server.sin_port = htons((u_short)portno);
91
92 post("connecting to port %d", portno);
93 /* try to connect. LATER make a separate thread to do this
94 because it might block */
95 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
96 {
97 sys_sockerror("connecting stream socket");
98 sys_closesocket(sockfd);
99 return;
100 }
101 x->x_fd = sockfd;
102 outlet_float(x->x_obj.ob_outlet, 1);
103}
104
105static void netsend_disconnect(t_netsend *x)
106{
107 if (x->x_fd >= 0)
108 {
109 sys_closesocket(x->x_fd);
110 x->x_fd = -1;
111 outlet_float(x->x_obj.ob_outlet, 0);
112 }
113}
114
115static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv)
116{
117 if (x->x_fd >= 0)
118 {
119 t_binbuf *b = binbuf_new();
120 char *buf, *bp;
121 int length, sent;
122 t_atom at;
123 binbuf_add(b, argc, argv);
124 SETSEMI(&at);
125 binbuf_add(b, 1, &at);
126 binbuf_gettext(b, &buf, &length);
127 for (bp = buf, sent = 0; sent < length;)
128 {
129 static double lastwarntime;
130 static double pleasewarn;
131 double timebefore = sys_getrealtime();
132 int res = send(x->x_fd, buf, length-sent, 0);
133 double timeafter = sys_getrealtime();
134 int late = (timeafter - timebefore > 0.005);
135 if (late || pleasewarn)
136 {
137 if (timeafter > lastwarntime + 2)
138 {
139 post("netsend blocked %d msec",
140 (int)(1000 * ((timeafter - timebefore) + pleasewarn)));
141 pleasewarn = 0;
142 lastwarntime = timeafter;
143 }
144 else if (late) pleasewarn += timeafter - timebefore;
145 }
146 if (res <= 0)
147 {
148 sys_sockerror("netsend");
149 netsend_disconnect(x);
150 break;
151 }
152 else
153 {
154 sent += res;
155 bp += res;
156 }
157 }
158 t_freebytes(buf, length);
159 binbuf_free(b);
160 }
161 else error("netsend: not connected");
162}
163
164static void netsend_free(t_netsend *x)
165{
166 netsend_disconnect(x);
167}
168
169static void netsend_setup(void)
170{
171 netsend_class = class_new(gensym("netsend"), (t_newmethod)netsend_new,
172 (t_method)netsend_free,
173 sizeof(t_netsend), 0, A_DEFFLOAT, 0);
174 class_addmethod(netsend_class, (t_method)netsend_connect,
175 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
176 class_addmethod(netsend_class, (t_method)netsend_disconnect,
177 gensym("disconnect"), 0);
178 class_addmethod(netsend_class, (t_method)netsend_send, gensym("send"),
179 A_GIMME, 0);
180}
181
182/* ----------------------------- netreceive ------------------------- */
183
184static t_class *netreceive_class;
185
186typedef struct _netreceive
187{
188 t_object x_obj;
189 t_outlet *x_msgout;
190 t_outlet *x_connectout;
191 int x_connectsocket;
192 int x_nconnections;
193 int x_udp;
194} t_netreceive;
195
196static void netreceive_notify(t_netreceive *x)
197{
198 outlet_float(x->x_connectout, --x->x_nconnections);
199}
200
201static void netreceive_doit(void *z, t_binbuf *b)
202{
203 t_atom messbuf[1024];
204 t_netreceive *x = (t_netreceive *)z;
205 int msg, natom = binbuf_getnatom(b);
206 t_atom *at = binbuf_getvec(b);
207 for (msg = 0; msg < natom;)
208 {
209 int emsg;
210 for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
211 && at[emsg].a_type != A_SEMI; emsg++)
212 ;
213 if (emsg > msg)
214 {
215 int i;
216 for (i = msg; i < emsg; i++)
217 if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
218 {
219 pd_error(x, "netreceive: got dollar sign in message");
220 goto nodice;
221 }
222 if (at[msg].a_type == A_FLOAT)
223 {
224 if (emsg > msg + 1)
225 outlet_list(x->x_msgout, 0, emsg-msg, at + msg);
226 else outlet_float(x->x_msgout, at[msg].a_w.w_float);
227 }
228 else if (at[msg].a_type == A_SYMBOL)
229 outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
230 emsg-msg-1, at + msg + 1);
231 }
232 nodice:
233 msg = emsg + 1;
234 }
235}
236
237static void netreceive_connectpoll(t_netreceive *x)
238{
239 int fd = accept(x->x_connectsocket, 0, 0);
240 if (fd < 0) post("netreceive: accept failed");
241 else
242 {
243 t_socketreceiver *y = socketreceiver_new((void *)x,
244 (t_socketnotifier)netreceive_notify,
245 (x->x_msgout ? netreceive_doit : 0), 0);
246 sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y);
247 outlet_float(x->x_connectout, ++x->x_nconnections);
248 }
249}
250
251static void *netreceive_new(t_symbol *compatflag,
252 t_floatarg fportno, t_floatarg udpflag)
253{
254 t_netreceive *x;
255 struct sockaddr_in server;
256 int sockfd, portno = fportno, udp = (udpflag != 0);
257 int old = !strcmp(compatflag->s_name , "old");
258 int intarg;
259 /* create a socket */
260 sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0);
261#if 0
262 fprintf(stderr, "receive socket %d\n", sockfd);
263#endif
264 if (sockfd < 0)
265 {
266 sys_sockerror("socket");
267 return (0);
268 }
269 server.sin_family = AF_INET;
270 server.sin_addr.s_addr = INADDR_ANY;
271
272#if 1
273 /* ask OS to allow another Pd to repoen this port after we close it. */
274 intarg = 1;
275 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
276 &intarg, sizeof(intarg)) < 0)
277 post("setsockopt (SO_REUSEADDR) failed\n");
278#endif
279#if 0
280 intarg = 0;
281 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
282 &intarg, sizeof(intarg)) < 0)
283 post("setsockopt (SO_RCVBUF) failed\n");
284#endif
285 /* Stream (TCP) sockets are set NODELAY */
286 if (!udp)
287 {
288 intarg = 1;
289 if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
290 &intarg, sizeof(intarg)) < 0)
291 post("setsockopt (TCP_NODELAY) failed\n");
292 }
293 /* assign server port number */
294 server.sin_port = htons((u_short)portno);
295
296 /* name the socket */
297 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
298 {
299 sys_sockerror("bind");
300 sys_closesocket(sockfd);
301 return (0);
302 }
303 x = (t_netreceive *)pd_new(netreceive_class);
304 if (old)
305 {
306 /* old style, nonsecure version */
307 x->x_msgout = 0;
308 }
309 else x->x_msgout = outlet_new(&x->x_obj, &s_anything);
310
311 if (udp) /* datagram protocol */
312 {
313 t_socketreceiver *y = socketreceiver_new((void *)x,
314 (t_socketnotifier)netreceive_notify,
315 (x->x_msgout ? netreceive_doit : 0), 1);
316 sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y);
317 x->x_connectout = 0;
318 }
319 else /* streaming protocol */
320 {
321 if (listen(sockfd, 5) < 0)
322 {
323 sys_sockerror("listen");
324 sys_closesocket(sockfd);
325 sockfd = -1;
326 }
327 else
328 {
329 sys_addpollfn(sockfd, (t_fdpollfn)netreceive_connectpoll, x);
330 x->x_connectout = outlet_new(&x->x_obj, &s_float);
331 }
332 }
333 x->x_connectsocket = sockfd;
334 x->x_nconnections = 0;
335 x->x_udp = udp;
336
337 return (x);
338}
339
340static void netreceive_free(t_netreceive *x)
341{
342 /* LATER make me clean up open connections */
343 if (x->x_connectsocket >= 0)
344 {
345 sys_rmpollfn(x->x_connectsocket);
346 sys_closesocket(x->x_connectsocket);
347 }
348}
349
350static void netreceive_setup(void)
351{
352 netreceive_class = class_new(gensym("netreceive"),
353 (t_newmethod)netreceive_new, (t_method)netreceive_free,
354 sizeof(t_netreceive), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
355 A_DEFSYM, 0);
356}
357
358void x_net_setup(void)
359{
360 netsend_setup();
361 netreceive_setup();
362}
363
364/* Copyright (c) 1997-1999 Miller Puckette.
365* For information on usage and redistribution, and for a DISCLAIMER OF ALL
366* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
367
368/* network */
369
370#include "m_pd.h"
371#include "s_stuff.h"
372
373#include <sys/types.h>
374#include <string.h>
375#ifdef UNIX
376#include <sys/socket.h>
377#include <netinet/in.h>
378#include <netinet/tcp.h>
379#include <netdb.h>
380#include <stdio.h>
381#define SOCKET_ERROR -1
382#else
383#include <winsock.h>
384#endif
385
386static t_class *netsend_class;
387
388typedef struct _netsend
389{
390 t_object x_obj;
391 int x_fd;
392 int x_protocol;
393} t_netsend;
394
395static void *netsend_new(t_floatarg udpflag)
396{
397 t_netsend *x = (t_netsend *)pd_new(netsend_class);
398 outlet_new(&x->x_obj, &s_float);
399 x->x_fd = -1;
400 x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM);
401 return (x);
402}
403
404static void netsend_connect(t_netsend *x, t_symbol *hostname,
405 t_floatarg fportno)
406{
407 struct sockaddr_in server;
408 struct hostent *hp;
409 int sockfd;
410 int portno = fportno;
411 int intarg;
412 if (x->x_fd >= 0)
413 {
414 error("netsend_connect: already connected");
415 return;
416 }
417
418 /* create a socket */
419 sockfd = socket(AF_INET, x->x_protocol, 0);
420#if 0
421 fprintf(stderr, "send socket %d\n", sockfd);
422#endif
423 if (sockfd < 0)
424 {
425 sys_sockerror("socket");
426 return;
427 }
428 /* connect socket using hostname provided in command line */
429 server.sin_family = AF_INET;
430 hp = gethostbyname(hostname->s_name);
431 if (hp == 0)
432 {
433 post("bad host?\n");
434 return;
435 }
436#if 0
437 intarg = 0;
438 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
439 &intarg, sizeof(intarg)) < 0)
440 post("setsockopt (SO_RCVBUF) failed\n");
441#endif
442 /* for stream (TCP) sockets, specify "nodelay" */
443 if (x->x_protocol == SOCK_STREAM)
444 {
445 intarg = 1;
446 if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
447 &intarg, sizeof(intarg)) < 0)
448 post("setsockopt (TCP_NODELAY) failed\n");
449 }
450 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
451
452 /* assign client port number */
453 server.sin_port = htons((u_short)portno);
454
455 post("connecting to port %d", portno);
456 /* try to connect. LATER make a separate thread to do this
457 because it might block */
458 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
459 {
460 sys_sockerror("connecting stream socket");
461 sys_closesocket(sockfd);
462 return;
463 }
464 x->x_fd = sockfd;
465 outlet_float(x->x_obj.ob_outlet, 1);
466}
467
468static void netsend_disconnect(t_netsend *x)
469{
470 if (x->x_fd >= 0)
471 {
472 sys_closesocket(x->x_fd);
473 x->x_fd = -1;
474 outlet_float(x->x_obj.ob_outlet, 0);
475 }
476}
477
478static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv)
479{
480 if (x->x_fd >= 0)
481 {
482 t_binbuf *b = binbuf_new();
483 char *buf, *bp;
484 int length, sent;
485 t_atom at;
486 binbuf_add(b, argc, argv);
487 SETSEMI(&at);
488 binbuf_add(b, 1, &at);
489 binbuf_gettext(b, &buf, &length);
490 for (bp = buf, sent = 0; sent < length;)
491 {
492 static double lastwarntime;
493 static double pleasewarn;
494 double timebefore = sys_getrealtime();
495 int res = send(x->x_fd, buf, length-sent, 0);
496 double timeafter = sys_getrealtime();
497 int late = (timeafter - timebefore > 0.005);
498 if (late || pleasewarn)
499 {
500 if (timeafter > lastwarntime + 2)
501 {
502 post("netsend blocked %d msec",
503 (int)(1000 * ((timeafter - timebefore) + pleasewarn)));
504 pleasewarn = 0;
505 lastwarntime = timeafter;
506 }
507 else if (late) pleasewarn += timeafter - timebefore;
508 }
509 if (res <= 0)
510 {
511 sys_sockerror("netsend");
512 netsend_disconnect(x);
513 break;
514 }
515 else
516 {
517 sent += res;
518 bp += res;
519 }
520 }
521 t_freebytes(buf, length);
522 binbuf_free(b);
523 }
524 else error("netsend: not connected");
525}
526
527static void netsend_free(t_netsend *x)
528{
529 netsend_disconnect(x);
530}
531
532static void netsend_setup(void)
533{
534 netsend_class = class_new(gensym("netsend"), (t_newmethod)netsend_new,
535 (t_method)netsend_free,
536 sizeof(t_netsend), 0, A_DEFFLOAT, 0);
537 class_addmethod(netsend_class, (t_method)netsend_connect,
538 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
539 class_addmethod(netsend_class, (t_method)netsend_disconnect,
540 gensym("disconnect"), 0);
541 class_addmethod(netsend_class, (t_method)netsend_send, gensym("send"),
542 A_GIMME, 0);
543}
544
545/* ----------------------------- netreceive ------------------------- */
546
547static t_class *netreceive_class;
548
549typedef struct _netreceive
550{
551 t_object x_obj;
552 t_outlet *x_msgout;
553 t_outlet *x_connectout;
554 int x_connectsocket;
555 int x_nconnections;
556 int x_udp;
557} t_netreceive;
558
559static void netreceive_notify(t_netreceive *x)
560{
561 outlet_float(x->x_connectout, --x->x_nconnections);
562}
563
564static void netreceive_doit(void *z, t_binbuf *b)
565{
566 t_atom messbuf[1024];
567 t_netreceive *x = (t_netreceive *)z;
568 int msg, natom = binbuf_getnatom(b);
569 t_atom *at = binbuf_getvec(b);
570 for (msg = 0; msg < natom;)
571 {
572 int emsg;
573 for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
574 && at[emsg].a_type != A_SEMI; emsg++)
575 ;
576 if (emsg > msg)
577 {
578 int i;
579 for (i = msg; i < emsg; i++)
580 if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
581 {
582 pd_error(x, "netreceive: got dollar sign in message");
583 goto nodice;
584 }
585 if (at[msg].a_type == A_FLOAT)
586 {
587 if (emsg > msg + 1)
588 outlet_list(x->x_msgout, 0, emsg-msg, at + msg);
589 else outlet_float(x->x_msgout, at[msg].a_w.w_float);
590 }
591 else if (at[msg].a_type == A_SYMBOL)
592 outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
593 emsg-msg-1, at + msg + 1);
594 }
595 nodice:
596 msg = emsg + 1;
597 }
598}
599
600static void netreceive_connectpoll(t_netreceive *x)
601{
602 int fd = accept(x->x_connectsocket, 0, 0);
603 if (fd < 0) post("netreceive: accept failed");
604 else
605 {
606 t_socketreceiver *y = socketreceiver_new((void *)x,
607 (t_socketnotifier)netreceive_notify,
608 (x->x_msgout ? netreceive_doit : 0), 0);
609 sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y);
610 outlet_float(x->x_connectout, ++x->x_nconnections);
611 }
612}
613
614static void *netreceive_new(t_symbol *compatflag,
615 t_floatarg fportno, t_floatarg udpflag)
616{
617 t_netreceive *x;
618 struct sockaddr_in server;
619 int sockfd, portno = fportno, udp = (udpflag != 0);
620 int old = !strcmp(compatflag->s_name , "old");
621 int intarg;
622 /* create a socket */
623 sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0);
624#if 0
625 fprintf(stderr, "receive socket %d\n", sockfd);
626#endif
627 if (sockfd < 0)
628 {
629 sys_sockerror("socket");
630 return (0);
631 }
632 server.sin_family = AF_INET;
633 server.sin_addr.s_addr = INADDR_ANY;
634
635#if 1
636 /* ask OS to allow another Pd to repoen this port after we close it. */
637 intarg = 1;
638 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
639 &intarg, sizeof(intarg)) < 0)
640 post("setsockopt (SO_REUSEADDR) failed\n");
641#endif
642#if 0
643 intarg = 0;
644 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
645 &intarg, sizeof(intarg)) < 0)
646 post("setsockopt (SO_RCVBUF) failed\n");
647#endif
648 /* Stream (TCP) sockets are set NODELAY */
649 if (!udp)
650 {
651 intarg = 1;
652 if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
653 &intarg, sizeof(intarg)) < 0)
654 post("setsockopt (TCP_NODELAY) failed\n");
655 }
656 /* assign server port number */
657 server.sin_port = htons((u_short)portno);
658
659 /* name the socket */
660 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
661 {
662 sys_sockerror("bind");
663 sys_closesocket(sockfd);
664 return (0);
665 }
666 x = (t_netreceive *)pd_new(netreceive_class);
667 if (old)
668 {
669 /* old style, nonsecure version */
670 x->x_msgout = 0;
671 }
672 else x->x_msgout = outlet_new(&x->x_obj, &s_anything);
673
674 if (udp) /* datagram protocol */
675 {
676 t_socketreceiver *y = socketreceiver_new((void *)x,
677 (t_socketnotifier)netreceive_notify,
678 (x->x_msgout ? netreceive_doit : 0), 1);
679 sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y);
680 x->x_connectout = 0;
681 }
682 else /* streaming protocol */
683 {
684 if (listen(sockfd, 5) < 0)
685 {
686 sys_sockerror("listen");
687 sys_closesocket(sockfd);
688 sockfd = -1;
689 }
690 else
691 {
692 sys_addpollfn(sockfd, (t_fdpollfn)netreceive_connectpoll, x);
693 x->x_connectout = outlet_new(&x->x_obj, &s_float);
694 }
695 }
696 x->x_connectsocket = sockfd;
697 x->x_nconnections = 0;
698 x->x_udp = udp;
699
700 return (x);
701}
702
703static void netreceive_free(t_netreceive *x)
704{
705 /* LATER make me clean up open connections */
706 if (x->x_connectsocket >= 0)
707 {
708 sys_rmpollfn(x->x_connectsocket);
709 sys_closesocket(x->x_connectsocket);
710 }
711}
712
713static void netreceive_setup(void)
714{
715 netreceive_class = class_new(gensym("netreceive"),
716 (t_newmethod)netreceive_new, (t_method)netreceive_free,
717 sizeof(t_netreceive), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
718 A_DEFSYM, 0);
719}
720
721void x_net_setup(void)
722{
723 netsend_setup();
724 netreceive_setup();
725}
726
diff --git a/apps/plugins/pdbox/PDa/src/x_qlist.c b/apps/plugins/pdbox/PDa/src/x_qlist.c
new file mode 100644
index 0000000000..e2c0605087
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_qlist.c
@@ -0,0 +1,690 @@
1/* Copyright (c) 1997-1999 Miller Puckette and others.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#include "m_pd.h"
6#include <string.h>
7#ifdef UNIX
8#include <unistd.h>
9#endif
10#ifdef MSW
11#include <io.h>
12#endif
13
14typedef struct _qlist
15{
16 t_object x_ob;
17 t_outlet *x_bangout;
18 void *x_binbuf;
19 int x_onset; /* playback position */
20 t_clock *x_clock;
21 float x_tempo;
22 double x_whenclockset;
23 float x_clockdelay;
24 t_symbol *x_dir;
25 t_canvas *x_canvas;
26 int x_reentered;
27} t_qlist;
28
29static void qlist_tick(t_qlist *x);
30
31static t_class *qlist_class;
32
33static void *qlist_new( void)
34{
35 t_symbol *name, *filename = 0;
36 t_qlist *x = (t_qlist *)pd_new(qlist_class);
37 x->x_binbuf = binbuf_new();
38 x->x_clock = clock_new(x, (t_method)qlist_tick);
39 outlet_new(&x->x_ob, &s_list);
40 x->x_bangout = outlet_new(&x->x_ob, &s_bang);
41 x->x_onset = 0x7fffffff;
42 x->x_tempo = 1;
43 x->x_whenclockset = 0;
44 x->x_clockdelay = 0;
45 x->x_canvas = canvas_getcurrent();
46 x->x_reentered = 0;
47 return (x);
48}
49
50static void qlist_rewind(t_qlist *x)
51{
52 x->x_onset = 0;
53 if (x->x_clock) clock_unset(x->x_clock);
54 x->x_whenclockset = 0;
55 x->x_reentered = 1;
56}
57
58static void qlist_donext(t_qlist *x, int drop, int automatic)
59{
60 t_pd *target = 0;
61 while (1)
62 {
63 int argc = binbuf_getnatom(x->x_binbuf),
64 count, onset = x->x_onset, onset2, wasreentered;
65 t_atom *argv = binbuf_getvec(x->x_binbuf);
66 t_atom *ap = argv + onset, *ap2;
67 if (onset >= argc) goto end;
68 while (ap->a_type == A_SEMI || ap->a_type == A_COMMA)
69 {
70 if (ap->a_type == A_SEMI) target = 0;
71 onset++, ap++;
72 if (onset >= argc) goto end;
73 }
74
75 if (!target && ap->a_type == A_FLOAT)
76 {
77 ap2 = ap + 1;
78 onset2 = onset + 1;
79 while (onset2 < argc && ap2->a_type == A_FLOAT)
80 onset2++, ap2++;
81 x->x_onset = onset2;
82 if (automatic)
83 {
84 clock_delay(x->x_clock,
85 x->x_clockdelay = ap->a_w.w_float * x->x_tempo);
86 x->x_whenclockset = clock_getsystime();
87 }
88 else outlet_list(x->x_ob.ob_outlet, 0, onset2-onset, ap);
89 return;
90 }
91 ap2 = ap + 1;
92 onset2 = onset + 1;
93 while (onset2 < argc &&
94 (ap2->a_type == A_FLOAT || ap2->a_type == A_SYMBOL))
95 onset2++, ap2++;
96 x->x_onset = onset2;
97 count = onset2 - onset;
98 if (!target)
99 {
100 if (ap->a_type != A_SYMBOL) continue;
101 else if (!(target = ap->a_w.w_symbol->s_thing))
102 {
103 error("qlist: %s: no such object", ap->a_w.w_symbol->s_name);
104 continue;
105 }
106 ap++;
107 onset++;
108 count--;
109 if (!count)
110 {
111 x->x_onset = onset2;
112 continue;
113 }
114 }
115 wasreentered = x->x_reentered;
116 x->x_reentered = 0;
117 if (!drop)
118 {
119 if (ap->a_type == A_FLOAT)
120 typedmess(target, &s_list, count, ap);
121 else if (ap->a_type == A_SYMBOL)
122 typedmess(target, ap->a_w.w_symbol, count-1, ap+1);
123 }
124 if (x->x_reentered)
125 return;
126 x->x_reentered = wasreentered;
127 } /* while (1); never falls through */
128
129end:
130 x->x_onset = 0x7fffffff;
131 outlet_bang(x->x_bangout);
132 x->x_whenclockset = 0;
133}
134
135static void qlist_next(t_qlist *x, t_floatarg drop)
136{
137 qlist_donext(x, drop != 0, 0);
138}
139
140static void qlist_bang(t_qlist *x)
141{
142 qlist_rewind(x);
143 qlist_donext(x, 0, 1);
144}
145
146static void qlist_tick(t_qlist *x)
147{
148 x->x_whenclockset = 0;
149 qlist_donext(x, 0, 1);
150}
151
152static void qlist_add(t_qlist *x, t_symbol *s, int ac, t_atom *av)
153{
154 t_atom a;
155 SETSEMI(&a);
156 binbuf_add(x->x_binbuf, ac, av);
157 binbuf_add(x->x_binbuf, 1, &a);
158}
159
160static void qlist_add2(t_qlist *x, t_symbol *s, int ac, t_atom *av)
161{
162 binbuf_add(x->x_binbuf, ac, av);
163}
164
165static void qlist_clear(t_qlist *x)
166{
167 qlist_rewind(x);
168 binbuf_clear(x->x_binbuf);
169}
170
171static void qlist_set(t_qlist *x, t_symbol *s, int ac, t_atom *av)
172{
173 qlist_clear(x);
174 qlist_add(x, s, ac, av);
175}
176
177static void qlist_read(t_qlist *x, t_symbol *filename, t_symbol *format)
178{
179 int cr = 0;
180 if (!strcmp(format->s_name, "cr"))
181 cr = 1;
182 else if (*format->s_name)
183 error("qlist_read: unknown flag: %s", format->s_name);
184
185 if (binbuf_read_via_path(x->x_binbuf, filename->s_name,
186 canvas_getdir(x->x_canvas)->s_name, cr))
187 error("%s: read failed", filename->s_name);
188 x->x_onset = 0x7fffffff;
189 x->x_reentered = 1;
190}
191
192static void qlist_write(t_qlist *x, t_symbol *filename, t_symbol *format)
193{
194 int cr = 0;
195 char buf[MAXPDSTRING];
196 canvas_makefilename(x->x_canvas, filename->s_name,
197 buf, MAXPDSTRING);
198 if (!strcmp(format->s_name, "cr"))
199 cr = 1;
200 else if (*format->s_name)
201 error("qlist_read: unknown flag: %s", format->s_name);
202 if (binbuf_write(x->x_binbuf, buf, "", cr))
203 error("%s: write failed", filename->s_name);
204}
205
206static void qlist_print(t_qlist *x)
207{
208 post("--------- textfile or qlist contents: -----------");
209 binbuf_print(x->x_binbuf);
210}
211
212static void qlist_tempo(t_qlist *x, t_float f)
213{
214 float newtempo;
215 if (f < 1e-20) f = 1e-20;
216 else if (f > 1e20) f = 1e20;
217 newtempo = 1./f;
218 if (x->x_whenclockset != 0)
219 {
220 float elapsed = clock_gettimesince(x->x_whenclockset);
221 float left = x->x_clockdelay - elapsed;
222 if (left < 0) left = 0;
223 left *= newtempo / x->x_tempo;
224 clock_delay(x->x_clock, left);
225 }
226 x->x_tempo = newtempo;
227}
228
229static void qlist_free(t_qlist *x)
230{
231 binbuf_free(x->x_binbuf);
232 if (x->x_clock) clock_free(x->x_clock);
233}
234
235/* -------------------- textfile ------------------------------- */
236
237static t_class *textfile_class;
238typedef t_qlist t_textfile;
239
240static void *textfile_new( void)
241{
242 t_symbol *name, *filename = 0;
243 t_textfile *x = (t_textfile *)pd_new(textfile_class);
244 x->x_binbuf = binbuf_new();
245 outlet_new(&x->x_ob, &s_list);
246 x->x_bangout = outlet_new(&x->x_ob, &s_bang);
247 x->x_onset = 0x7fffffff;
248 x->x_reentered = 0;
249 x->x_tempo = 1;
250 x->x_whenclockset = 0;
251 x->x_clockdelay = 0;
252 x->x_clock = NULL;
253 x->x_canvas = canvas_getcurrent();
254 return (x);
255}
256
257static void textfile_bang(t_textfile *x)
258{
259 int argc = binbuf_getnatom(x->x_binbuf),
260 count, onset = x->x_onset, onset2;
261 t_atom *argv = binbuf_getvec(x->x_binbuf);
262 t_atom *ap = argv + onset, *ap2;
263 while (onset < argc &&
264 (ap->a_type == A_SEMI || ap->a_type == A_COMMA))
265 onset++, ap++;
266 onset2 = onset;
267 ap2 = ap;
268 while (onset2 < argc &&
269 (ap2->a_type != A_SEMI && ap2->a_type != A_COMMA))
270 onset2++, ap2++;
271 if (onset2 > onset)
272 {
273 x->x_onset = onset2;
274 if (ap->a_type == A_SYMBOL)
275 outlet_anything(x->x_ob.ob_outlet, ap->a_w.w_symbol,
276 onset2-onset-1, ap+1);
277 else outlet_list(x->x_ob.ob_outlet, 0, onset2-onset, ap);
278 }
279 else
280 {
281 x->x_onset = 0x7fffffff;
282 outlet_bang(x->x_bangout);
283 }
284}
285
286static void textfile_rewind(t_qlist *x)
287{
288 x->x_onset = 0;
289}
290
291static void textfile_free(t_textfile *x)
292{
293 binbuf_free(x->x_binbuf);
294}
295
296/* ---------------- global setup function -------------------- */
297
298void x_qlist_setup(void )
299{
300 qlist_class = class_new(gensym("qlist"), (t_newmethod)qlist_new,
301 (t_method)qlist_free, sizeof(t_qlist), 0, 0);
302 class_addmethod(qlist_class, (t_method)qlist_rewind, gensym("rewind"), 0);
303 class_addmethod(qlist_class, (t_method)qlist_next,
304 gensym("next"), A_DEFFLOAT, 0);
305 class_addmethod(qlist_class, (t_method)qlist_set, gensym("set"),
306 A_GIMME, 0);
307 class_addmethod(qlist_class, (t_method)qlist_clear, gensym("clear"), 0);
308 class_addmethod(qlist_class, (t_method)qlist_add, gensym("add"),
309 A_GIMME, 0);
310 class_addmethod(qlist_class, (t_method)qlist_add2, gensym("add2"),
311 A_GIMME, 0);
312 class_addmethod(qlist_class, (t_method)qlist_add, gensym("append"),
313 A_GIMME, 0);
314 class_addmethod(qlist_class, (t_method)qlist_read, gensym("read"),
315 A_SYMBOL, A_DEFSYM, 0);
316 class_addmethod(qlist_class, (t_method)qlist_write, gensym("write"),
317 A_SYMBOL, A_DEFSYM, 0);
318 class_addmethod(qlist_class, (t_method)qlist_print, gensym("print"),
319 A_DEFSYM, 0);
320 class_addmethod(qlist_class, (t_method)qlist_tempo,
321 gensym("tempo"), A_FLOAT, 0);
322 class_addbang(qlist_class, qlist_bang);
323
324 textfile_class = class_new(gensym("textfile"), (t_newmethod)textfile_new,
325 (t_method)textfile_free, sizeof(t_textfile), 0, 0);
326 class_addmethod(textfile_class, (t_method)textfile_rewind, gensym("rewind"),
327 0);
328 class_addmethod(textfile_class, (t_method)qlist_set, gensym("set"),
329 A_GIMME, 0);
330 class_addmethod(textfile_class, (t_method)qlist_clear, gensym("clear"), 0);
331 class_addmethod(textfile_class, (t_method)qlist_add, gensym("add"),
332 A_GIMME, 0);
333 class_addmethod(textfile_class, (t_method)qlist_add2, gensym("add2"),
334 A_GIMME, 0);
335 class_addmethod(textfile_class, (t_method)qlist_add, gensym("append"),
336 A_GIMME, 0);
337 class_addmethod(textfile_class, (t_method)qlist_read, gensym("read"),
338 A_SYMBOL, A_DEFSYM, 0);
339 class_addmethod(textfile_class, (t_method)qlist_write, gensym("write"),
340 A_SYMBOL, A_DEFSYM, 0);
341 class_addmethod(textfile_class, (t_method)qlist_print, gensym("print"),
342 A_DEFSYM, 0);
343 class_addbang(textfile_class, textfile_bang);
344}
345
346/* Copyright (c) 1997-1999 Miller Puckette and others.
347* For information on usage and redistribution, and for a DISCLAIMER OF ALL
348* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
349
350#include "m_pd.h"
351#include <string.h>
352#ifdef UNIX
353#include <unistd.h>
354#endif
355#ifdef MSW
356#include <io.h>
357#endif
358
359typedef struct _qlist
360{
361 t_object x_ob;
362 t_outlet *x_bangout;
363 void *x_binbuf;
364 int x_onset; /* playback position */
365 t_clock *x_clock;
366 float x_tempo;
367 double x_whenclockset;
368 float x_clockdelay;
369 t_symbol *x_dir;
370 t_canvas *x_canvas;
371 int x_reentered;
372} t_qlist;
373
374static void qlist_tick(t_qlist *x);
375
376static t_class *qlist_class;
377
378static void *qlist_new( void)
379{
380 t_symbol *name, *filename = 0;
381 t_qlist *x = (t_qlist *)pd_new(qlist_class);
382 x->x_binbuf = binbuf_new();
383 x->x_clock = clock_new(x, (t_method)qlist_tick);
384 outlet_new(&x->x_ob, &s_list);
385 x->x_bangout = outlet_new(&x->x_ob, &s_bang);
386 x->x_onset = 0x7fffffff;
387 x->x_tempo = 1;
388 x->x_whenclockset = 0;
389 x->x_clockdelay = 0;
390 x->x_canvas = canvas_getcurrent();
391 x->x_reentered = 0;
392 return (x);
393}
394
395static void qlist_rewind(t_qlist *x)
396{
397 x->x_onset = 0;
398 if (x->x_clock) clock_unset(x->x_clock);
399 x->x_whenclockset = 0;
400 x->x_reentered = 1;
401}
402
403static void qlist_donext(t_qlist *x, int drop, int automatic)
404{
405 t_pd *target = 0;
406 while (1)
407 {
408 int argc = binbuf_getnatom(x->x_binbuf),
409 count, onset = x->x_onset, onset2, wasreentered;
410 t_atom *argv = binbuf_getvec(x->x_binbuf);
411 t_atom *ap = argv + onset, *ap2;
412 if (onset >= argc) goto end;
413 while (ap->a_type == A_SEMI || ap->a_type == A_COMMA)
414 {
415 if (ap->a_type == A_SEMI) target = 0;
416 onset++, ap++;
417 if (onset >= argc) goto end;
418 }
419
420 if (!target && ap->a_type == A_FLOAT)
421 {
422 ap2 = ap + 1;
423 onset2 = onset + 1;
424 while (onset2 < argc && ap2->a_type == A_FLOAT)
425 onset2++, ap2++;
426 x->x_onset = onset2;
427 if (automatic)
428 {
429 clock_delay(x->x_clock,
430 x->x_clockdelay = ap->a_w.w_float * x->x_tempo);
431 x->x_whenclockset = clock_getsystime();
432 }
433 else outlet_list(x->x_ob.ob_outlet, 0, onset2-onset, ap);
434 return;
435 }
436 ap2 = ap + 1;
437 onset2 = onset + 1;
438 while (onset2 < argc &&
439 (ap2->a_type == A_FLOAT || ap2->a_type == A_SYMBOL))
440 onset2++, ap2++;
441 x->x_onset = onset2;
442 count = onset2 - onset;
443 if (!target)
444 {
445 if (ap->a_type != A_SYMBOL) continue;
446 else if (!(target = ap->a_w.w_symbol->s_thing))
447 {
448 error("qlist: %s: no such object", ap->a_w.w_symbol->s_name);
449 continue;
450 }
451 ap++;
452 onset++;
453 count--;
454 if (!count)
455 {
456 x->x_onset = onset2;
457 continue;
458 }
459 }
460 wasreentered = x->x_reentered;
461 x->x_reentered = 0;
462 if (!drop)
463 {
464 if (ap->a_type == A_FLOAT)
465 typedmess(target, &s_list, count, ap);
466 else if (ap->a_type == A_SYMBOL)
467 typedmess(target, ap->a_w.w_symbol, count-1, ap+1);
468 }
469 if (x->x_reentered)
470 return;
471 x->x_reentered = wasreentered;
472 } /* while (1); never falls through */
473
474end:
475 x->x_onset = 0x7fffffff;
476 outlet_bang(x->x_bangout);
477 x->x_whenclockset = 0;
478}
479
480static void qlist_next(t_qlist *x, t_floatarg drop)
481{
482 qlist_donext(x, drop != 0, 0);
483}
484
485static void qlist_bang(t_qlist *x)
486{
487 qlist_rewind(x);
488 qlist_donext(x, 0, 1);
489}
490
491static void qlist_tick(t_qlist *x)
492{
493 x->x_whenclockset = 0;
494 qlist_donext(x, 0, 1);
495}
496
497static void qlist_add(t_qlist *x, t_symbol *s, int ac, t_atom *av)
498{
499 t_atom a;
500 SETSEMI(&a);
501 binbuf_add(x->x_binbuf, ac, av);
502 binbuf_add(x->x_binbuf, 1, &a);
503}
504
505static void qlist_add2(t_qlist *x, t_symbol *s, int ac, t_atom *av)
506{
507 binbuf_add(x->x_binbuf, ac, av);
508}
509
510static void qlist_clear(t_qlist *x)
511{
512 qlist_rewind(x);
513 binbuf_clear(x->x_binbuf);
514}
515
516static void qlist_set(t_qlist *x, t_symbol *s, int ac, t_atom *av)
517{
518 qlist_clear(x);
519 qlist_add(x, s, ac, av);
520}
521
522static void qlist_read(t_qlist *x, t_symbol *filename, t_symbol *format)
523{
524 int cr = 0;
525 if (!strcmp(format->s_name, "cr"))
526 cr = 1;
527 else if (*format->s_name)
528 error("qlist_read: unknown flag: %s", format->s_name);
529
530 if (binbuf_read_via_path(x->x_binbuf, filename->s_name,
531 canvas_getdir(x->x_canvas)->s_name, cr))
532 error("%s: read failed", filename->s_name);
533 x->x_onset = 0x7fffffff;
534 x->x_reentered = 1;
535}
536
537static void qlist_write(t_qlist *x, t_symbol *filename, t_symbol *format)
538{
539 int cr = 0;
540 char buf[MAXPDSTRING];
541 canvas_makefilename(x->x_canvas, filename->s_name,
542 buf, MAXPDSTRING);
543 if (!strcmp(format->s_name, "cr"))
544 cr = 1;
545 else if (*format->s_name)
546 error("qlist_read: unknown flag: %s", format->s_name);
547 if (binbuf_write(x->x_binbuf, buf, "", cr))
548 error("%s: write failed", filename->s_name);
549}
550
551static void qlist_print(t_qlist *x)
552{
553 post("--------- textfile or qlist contents: -----------");
554 binbuf_print(x->x_binbuf);
555}
556
557static void qlist_tempo(t_qlist *x, t_float f)
558{
559 float newtempo;
560 if (f < 1e-20) f = 1e-20;
561 else if (f > 1e20) f = 1e20;
562 newtempo = 1./f;
563 if (x->x_whenclockset != 0)
564 {
565 float elapsed = clock_gettimesince(x->x_whenclockset);
566 float left = x->x_clockdelay - elapsed;
567 if (left < 0) left = 0;
568 left *= newtempo / x->x_tempo;
569 clock_delay(x->x_clock, left);
570 }
571 x->x_tempo = newtempo;
572}
573
574static void qlist_free(t_qlist *x)
575{
576 binbuf_free(x->x_binbuf);
577 if (x->x_clock) clock_free(x->x_clock);
578}
579
580/* -------------------- textfile ------------------------------- */
581
582static t_class *textfile_class;
583typedef t_qlist t_textfile;
584
585static void *textfile_new( void)
586{
587 t_symbol *name, *filename = 0;
588 t_textfile *x = (t_textfile *)pd_new(textfile_class);
589 x->x_binbuf = binbuf_new();
590 outlet_new(&x->x_ob, &s_list);
591 x->x_bangout = outlet_new(&x->x_ob, &s_bang);
592 x->x_onset = 0x7fffffff;
593 x->x_reentered = 0;
594 x->x_tempo = 1;
595 x->x_whenclockset = 0;
596 x->x_clockdelay = 0;
597 x->x_clock = NULL;
598 x->x_canvas = canvas_getcurrent();
599 return (x);
600}
601
602static void textfile_bang(t_textfile *x)
603{
604 int argc = binbuf_getnatom(x->x_binbuf),
605 count, onset = x->x_onset, onset2;
606 t_atom *argv = binbuf_getvec(x->x_binbuf);
607 t_atom *ap = argv + onset, *ap2;
608 while (onset < argc &&
609 (ap->a_type == A_SEMI || ap->a_type == A_COMMA))
610 onset++, ap++;
611 onset2 = onset;
612 ap2 = ap;
613 while (onset2 < argc &&
614 (ap2->a_type != A_SEMI && ap2->a_type != A_COMMA))
615 onset2++, ap2++;
616 if (onset2 > onset)
617 {
618 x->x_onset = onset2;
619 if (ap->a_type == A_SYMBOL)
620 outlet_anything(x->x_ob.ob_outlet, ap->a_w.w_symbol,
621 onset2-onset-1, ap+1);
622 else outlet_list(x->x_ob.ob_outlet, 0, onset2-onset, ap);
623 }
624 else
625 {
626 x->x_onset = 0x7fffffff;
627 outlet_bang(x->x_bangout);
628 }
629}
630
631static void textfile_rewind(t_qlist *x)
632{
633 x->x_onset = 0;
634}
635
636static void textfile_free(t_textfile *x)
637{
638 binbuf_free(x->x_binbuf);
639}
640
641/* ---------------- global setup function -------------------- */
642
643void x_qlist_setup(void )
644{
645 qlist_class = class_new(gensym("qlist"), (t_newmethod)qlist_new,
646 (t_method)qlist_free, sizeof(t_qlist), 0, 0);
647 class_addmethod(qlist_class, (t_method)qlist_rewind, gensym("rewind"), 0);
648 class_addmethod(qlist_class, (t_method)qlist_next,
649 gensym("next"), A_DEFFLOAT, 0);
650 class_addmethod(qlist_class, (t_method)qlist_set, gensym("set"),
651 A_GIMME, 0);
652 class_addmethod(qlist_class, (t_method)qlist_clear, gensym("clear"), 0);
653 class_addmethod(qlist_class, (t_method)qlist_add, gensym("add"),
654 A_GIMME, 0);
655 class_addmethod(qlist_class, (t_method)qlist_add2, gensym("add2"),
656 A_GIMME, 0);
657 class_addmethod(qlist_class, (t_method)qlist_add, gensym("append"),
658 A_GIMME, 0);
659 class_addmethod(qlist_class, (t_method)qlist_read, gensym("read"),
660 A_SYMBOL, A_DEFSYM, 0);
661 class_addmethod(qlist_class, (t_method)qlist_write, gensym("write"),
662 A_SYMBOL, A_DEFSYM, 0);
663 class_addmethod(qlist_class, (t_method)qlist_print, gensym("print"),
664 A_DEFSYM, 0);
665 class_addmethod(qlist_class, (t_method)qlist_tempo,
666 gensym("tempo"), A_FLOAT, 0);
667 class_addbang(qlist_class, qlist_bang);
668
669 textfile_class = class_new(gensym("textfile"), (t_newmethod)textfile_new,
670 (t_method)textfile_free, sizeof(t_textfile), 0, 0);
671 class_addmethod(textfile_class, (t_method)textfile_rewind, gensym("rewind"),
672 0);
673 class_addmethod(textfile_class, (t_method)qlist_set, gensym("set"),
674 A_GIMME, 0);
675 class_addmethod(textfile_class, (t_method)qlist_clear, gensym("clear"), 0);
676 class_addmethod(textfile_class, (t_method)qlist_add, gensym("add"),
677 A_GIMME, 0);
678 class_addmethod(textfile_class, (t_method)qlist_add2, gensym("add2"),
679 A_GIMME, 0);
680 class_addmethod(textfile_class, (t_method)qlist_add, gensym("append"),
681 A_GIMME, 0);
682 class_addmethod(textfile_class, (t_method)qlist_read, gensym("read"),
683 A_SYMBOL, A_DEFSYM, 0);
684 class_addmethod(textfile_class, (t_method)qlist_write, gensym("write"),
685 A_SYMBOL, A_DEFSYM, 0);
686 class_addmethod(textfile_class, (t_method)qlist_print, gensym("print"),
687 A_DEFSYM, 0);
688 class_addbang(textfile_class, textfile_bang);
689}
690
diff --git a/apps/plugins/pdbox/PDa/src/x_time.c b/apps/plugins/pdbox/PDa/src/x_time.c
new file mode 100644
index 0000000000..580a30b36d
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/x_time.c
@@ -0,0 +1,1040 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5/* clock objects */
6
7#include "m_pd.h"
8#include <stdio.h>
9/* -------------------------- delay ------------------------------ */
10static t_class *delay_class;
11
12typedef struct _delay
13{
14 t_object x_obj;
15 t_clock *x_clock;
16 double x_deltime;
17} t_delay;
18
19static void delay_bang(t_delay *x)
20{
21 clock_delay(x->x_clock, x->x_deltime);
22}
23
24static void delay_stop(t_delay *x)
25{
26 clock_unset(x->x_clock);
27}
28
29static void delay_ft1(t_delay *x, t_floatarg g)
30{
31 if (g < 0) g = 0;
32 x->x_deltime = g;
33}
34
35static void delay_float(t_delay *x, t_float f)
36{
37 delay_ft1(x, f);
38 delay_bang(x);
39}
40
41static void delay_tick(t_delay *x)
42{
43 outlet_bang(x->x_obj.ob_outlet);
44}
45
46static void delay_free(t_delay *x)
47{
48 clock_free(x->x_clock);
49}
50
51static void *delay_new(t_floatarg f)
52{
53 t_delay *x = (t_delay *)pd_new(delay_class);
54 delay_ft1(x, f);
55 x->x_clock = clock_new(x, (t_method)delay_tick);
56 outlet_new(&x->x_obj, gensym("bang"));
57 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
58 return (x);
59}
60
61static void delay_setup(void)
62{
63 delay_class = class_new(gensym("delay"), (t_newmethod)delay_new,
64 (t_method)delay_free, sizeof(t_delay), 0, A_DEFFLOAT, 0);
65 class_addcreator((t_newmethod)delay_new, gensym("del"), A_DEFFLOAT, 0);
66 class_addbang(delay_class, delay_bang);
67 class_addmethod(delay_class, (t_method)delay_stop, gensym("stop"), 0);
68 class_addmethod(delay_class, (t_method)delay_ft1,
69 gensym("ft1"), A_FLOAT, 0);
70 class_addfloat(delay_class, (t_method)delay_float);
71}
72
73/* -------------------------- metro ------------------------------ */
74static t_class *metro_class;
75
76typedef struct _metro
77{
78 t_object x_obj;
79 t_clock *x_clock;
80 double x_deltime;
81 int x_hit;
82} t_metro;
83
84static void metro_tick(t_metro *x)
85{
86 x->x_hit = 0;
87 outlet_bang(x->x_obj.ob_outlet);
88 if (!x->x_hit) clock_delay(x->x_clock, x->x_deltime);
89}
90
91static void metro_float(t_metro *x, t_float f)
92{
93 if (f != 0) metro_tick(x);
94 else clock_unset(x->x_clock);
95 x->x_hit = 1;
96}
97
98static void metro_bang(t_metro *x)
99{
100 metro_float(x, 1);
101}
102
103static void metro_stop(t_metro *x)
104{
105 metro_float(x, 0);
106}
107
108static void metro_ft1(t_metro *x, t_floatarg g)
109{
110 if (g < 1) g = 1;
111 x->x_deltime = g;
112}
113
114static void metro_free(t_metro *x)
115{
116 clock_free(x->x_clock);
117}
118
119static void *metro_new(t_floatarg f)
120{
121 t_metro *x = (t_metro *)pd_new(metro_class);
122 metro_ft1(x, f);
123 x->x_hit = 0;
124 x->x_clock = clock_new(x, (t_method)metro_tick);
125 outlet_new(&x->x_obj, gensym("bang"));
126 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
127 return (x);
128}
129
130static void metro_setup(void)
131{
132 metro_class = class_new(gensym("metro"), (t_newmethod)metro_new,
133 (t_method)metro_free, sizeof(t_metro), 0, A_DEFFLOAT, 0);
134 class_addbang(metro_class, metro_bang);
135 class_addmethod(metro_class, (t_method)metro_stop, gensym("stop"), 0);
136 class_addmethod(metro_class, (t_method)metro_ft1, gensym("ft1"),
137 A_FLOAT, 0);
138 class_addfloat(metro_class, (t_method)metro_float);
139}
140
141/* -------------------------- line ------------------------------ */
142static t_class *line_class;
143
144typedef struct _line
145{
146 t_object x_obj;
147 t_clock *x_clock;
148 double x_targettime;
149 t_float x_targetval;
150 double x_prevtime;
151 t_float x_setval;
152 int x_gotinlet;
153 t_float x_grain;
154 double x_1overtimediff;
155 double x_in1val;
156} t_line;
157
158static void line_tick(t_line *x)
159{
160 double timenow = clock_getsystime();
161 double msectogo = - clock_gettimesince(x->x_targettime);
162 if (msectogo < 1E-9)
163 {
164 outlet_float(x->x_obj.ob_outlet, x->x_targetval);
165 }
166 else
167 {
168 outlet_float(x->x_obj.ob_outlet,
169 x->x_setval + x->x_1overtimediff * (timenow - x->x_prevtime)
170 * (x->x_targetval - x->x_setval));
171 clock_delay(x->x_clock,
172 (x->x_grain > msectogo ? msectogo : x->x_grain));
173 }
174}
175
176static void line_float(t_line *x, t_float f)
177{
178 double timenow = clock_getsystime();
179 if (x->x_gotinlet && x->x_in1val > 0)
180 {
181 if (timenow > x->x_targettime) x->x_setval = x->x_targetval;
182 else x->x_setval = x->x_setval + x->x_1overtimediff *
183 (timenow - x->x_prevtime)
184 * (x->x_targetval - x->x_setval);
185 x->x_prevtime = timenow;
186 x->x_targettime = clock_getsystimeafter(x->x_in1val);
187 x->x_targetval = f;
188 line_tick(x);
189 x->x_gotinlet = 0;
190 x->x_1overtimediff = 1./ (x->x_targettime - timenow);
191 clock_delay(x->x_clock,
192 (x->x_grain > x->x_in1val ? x->x_in1val : x->x_grain));
193
194 }
195 else
196 {
197 clock_unset(x->x_clock);
198 x->x_targetval = x->x_setval = f;
199 outlet_float(x->x_obj.ob_outlet, f);
200 }
201 x->x_gotinlet = 0;
202}
203
204static void line_ft1(t_line *x, t_floatarg g)
205{
206 x->x_in1val = g;
207 x->x_gotinlet = 1;
208}
209
210static void line_stop(t_line *x)
211{
212 x->x_targetval = x->x_setval;
213 clock_unset(x->x_clock);
214}
215
216static void line_free(t_line *x)
217{
218 clock_free(x->x_clock);
219}
220
221static void *line_new(t_floatarg f, t_floatarg grain)
222{
223 t_line *x = (t_line *)pd_new(line_class);
224 x->x_targetval = x->x_setval = f;
225 x->x_gotinlet = 0;
226 x->x_1overtimediff = 1;
227 x->x_clock = clock_new(x, (t_method)line_tick);
228 x->x_targettime = x->x_prevtime = clock_getsystime();
229 if (grain <= 0) grain = 20;
230 x->x_grain = grain;
231 outlet_new(&x->x_obj, gensym("float"));
232 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
233 return (x);
234}
235
236static void line_setup(void)
237{
238 line_class = class_new(gensym("line"), (t_newmethod)line_new,
239 (t_method)line_free, sizeof(t_line), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
240 class_addmethod(line_class, (t_method)line_ft1,
241 gensym("ft1"), A_FLOAT, 0);
242 class_addmethod(line_class, (t_method)line_stop,
243 gensym("stop"), 0);
244 class_addfloat(line_class, (t_method)line_float);
245}
246
247/* -------------------------- timer ------------------------------ */
248static t_class *timer_class;
249
250typedef struct _timer
251{
252 t_object x_obj;
253 t_time x_settime;
254} t_timer;
255
256static void timer_bang(t_timer *x)
257{
258 x->x_settime = clock_getsystime();
259}
260
261static void timer_bang2(t_timer *x)
262{
263 t_time diff = clock_gettimesince(x->x_settime);
264 outlet_float(x->x_obj.ob_outlet, diff);
265}
266
267static void *timer_new(t_floatarg f)
268{
269 t_timer *x = (t_timer *)pd_new(timer_class);
270 timer_bang(x);
271 outlet_new(&x->x_obj, gensym("float"));
272 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
273 return (x);
274}
275
276static void timer_setup(void)
277{
278 timer_class = class_new(gensym("timer"), (t_newmethod)timer_new, 0,
279 sizeof(t_timer), 0, A_DEFFLOAT, 0);
280 class_addbang(timer_class, timer_bang);
281 class_addmethod(timer_class, (t_method)timer_bang2, gensym("bang2"), 0);
282}
283
284
285/* -------------------------- pipe -------------------------- */
286
287static t_class *pipe_class;
288
289typedef struct _hang
290{
291 t_clock *h_clock;
292 struct _hang *h_next;
293 struct _pipe *h_owner;
294 t_gpointer *h_gp;
295 union word h_vec[1]; /* not the actual number. */
296} t_hang;
297
298typedef struct pipeout
299{
300 t_atom p_atom;
301 t_outlet *p_outlet;
302} t_pipeout;
303
304typedef struct _pipe
305{
306 t_object x_obj;
307 int x_n;
308 int x_nptr;
309 float x_deltime;
310 t_pipeout *x_vec;
311 t_gpointer *x_gp;
312 t_hang *x_hang;
313} t_pipe;
314
315static void *pipe_new(t_symbol *s, int argc, t_atom *argv)
316{
317 t_pipe *x = (t_pipe *)pd_new(pipe_class);
318 t_atom defarg, *ap;
319 t_pipeout *vec, *vp;
320 t_gpointer *gp;
321 int nptr = 0;
322 int i;
323 float deltime;
324 if (argc)
325 {
326 if (argv[argc-1].a_type != A_FLOAT)
327 {
328 char stupid[80];
329 atom_string(&argv[argc-1], stupid, 79);
330 post("pipe: %s: bad time delay value", stupid);
331 deltime = 0;
332 }
333 else deltime = argv[argc-1].a_w.w_float;
334 argc--;
335 }
336 else deltime = 0;
337 if (!argc)
338 {
339 argv = &defarg;
340 argc = 1;
341 SETFLOAT(&defarg, 0);
342 }
343 x->x_n = argc;
344 vec = x->x_vec = (t_pipeout *)getbytes(argc * sizeof(*x->x_vec));
345
346 for (i = argc, ap = argv; i--; ap++)
347 if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p')
348 nptr++;
349
350 gp = x->x_gp = (t_gpointer *)t_getbytes(nptr * sizeof (*gp));
351 x->x_nptr = nptr;
352
353 for (i = 0, vp = vec, ap = argv; i < argc; i++, ap++, vp++)
354 {
355 if (ap->a_type == A_FLOAT)
356 {
357 vp->p_atom = *ap;
358 vp->p_outlet = outlet_new(&x->x_obj, &s_float);
359 if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float);
360 }
361 else if (ap->a_type == A_SYMBOL)
362 {
363 char c = *ap->a_w.w_symbol->s_name;
364 if (c == 's')
365 {
366 SETSYMBOL(&vp->p_atom, &s_symbol);
367 vp->p_outlet = outlet_new(&x->x_obj, &s_symbol);
368 if (i) symbolinlet_new(&x->x_obj, &vp->p_atom.a_w.w_symbol);
369 }
370 else if (c == 'p')
371 {
372 vp->p_atom.a_type = A_POINTER;
373 vp->p_atom.a_w.w_gpointer = gp;
374 gpointer_init(gp);
375 vp->p_outlet = outlet_new(&x->x_obj, &s_pointer);
376 if (i) pointerinlet_new(&x->x_obj, gp);
377 gp++;
378 }
379 else
380 {
381 if (c != 'f') error("pack: %s: bad type",
382 ap->a_w.w_symbol->s_name);
383 SETFLOAT(&vp->p_atom, 0);
384 vp->p_outlet = outlet_new(&x->x_obj, &s_float);
385 if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float);
386 }
387 }
388 }
389 floatinlet_new(&x->x_obj, &x->x_deltime);
390 x->x_hang = 0;
391 x->x_deltime = deltime;
392 return (x);
393}
394
395static void hang_free(t_hang *h)
396{
397 t_pipe *x = h->h_owner;
398 t_gpointer *gp;
399 int i;
400 for (gp = h->h_gp, i = x->x_nptr; i--; gp++)
401 gpointer_unset(gp);
402 freebytes(h->h_gp, x->x_nptr * sizeof(*h->h_gp));
403 clock_free(h->h_clock);
404 freebytes(h, sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec));
405}
406
407static void hang_tick(t_hang *h)
408{
409 t_pipe *x = h->h_owner;
410 t_hang *h2, *h3;
411 t_pipeout *p;
412 int i;
413 union word *w;
414 if (x->x_hang == h) x->x_hang = h->h_next;
415 else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3)
416 {
417 if (h3 == h)
418 {
419 h2->h_next = h3->h_next;
420 break;
421 }
422 }
423 for (i = x->x_n, p = x->x_vec + (x->x_n - 1), w = h->h_vec + (x->x_n - 1);
424 i--; p--, w--)
425 {
426 switch (p->p_atom.a_type)
427 {
428 case A_FLOAT: outlet_float(p->p_outlet, w->w_float); break;
429 case A_SYMBOL: outlet_symbol(p->p_outlet, w->w_symbol); break;
430 case A_POINTER:
431 if (gpointer_check(w->w_gpointer, 1))
432 outlet_pointer(p->p_outlet, w->w_gpointer);
433 else post("pipe: stale pointer");
434 break;
435 }
436 }
437 hang_free(h);
438}
439
440static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av)
441{
442 t_hang *h = (t_hang *)
443 getbytes(sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec));
444 t_gpointer *gp, *gp2;
445 t_pipeout *p;
446 int i, n = x->x_n;
447 t_atom *ap;
448 t_word *w;
449 h->h_gp = (t_gpointer *)getbytes(x->x_nptr * sizeof(t_gpointer));
450 if (ac > n) ac = n;
451 for (i = 0, gp = x->x_gp, p = x->x_vec, ap = av; i < ac;
452 i++, p++, ap++)
453 {
454 switch (p->p_atom.a_type)
455 {
456 case A_FLOAT: p->p_atom.a_w.w_float = atom_getfloat(ap); break;
457 case A_SYMBOL: p->p_atom.a_w.w_symbol = atom_getsymbol(ap); break;
458 case A_POINTER:
459 gpointer_unset(gp);
460 if (ap->a_type != A_POINTER)
461 post("pipe: bad pointer");
462 else
463 {
464 *gp = *(ap->a_w.w_gpointer);
465 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
466 }
467 gp++;
468 }
469 }
470 for (i = 0, gp = x->x_gp, gp2 = h->h_gp, p = x->x_vec, w = h->h_vec;
471 i < n; i++, p++, w++)
472 {
473 if (p->p_atom.a_type == A_POINTER)
474 {
475 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
476 w->w_gpointer = gp2;
477 *gp2++ = *gp++;
478 }
479 else *w = p->p_atom.a_w;
480 }
481 h->h_next = x->x_hang;
482 x->x_hang = h;
483 h->h_owner = x;
484 h->h_clock = clock_new(h, (t_method)hang_tick);
485 clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0));
486}
487
488static void pipe_flush(t_pipe *x)
489{
490 while (x->x_hang) hang_tick(x->x_hang);
491}
492
493static void pipe_clear(t_pipe *x)
494{
495 t_hang *hang;
496 while (hang = x->x_hang)
497 {
498 x->x_hang = hang->h_next;
499 hang_free(hang);
500 }
501}
502
503static void pipe_setup(void)
504{
505 pipe_class = class_new(gensym("pipe"),
506 (t_newmethod)pipe_new, (t_method)pipe_clear,
507 sizeof(t_pipe), 0, A_GIMME, 0);
508 class_addlist(pipe_class, pipe_list);
509 class_addmethod(pipe_class, (t_method)pipe_flush, gensym("flush"), 0);
510 class_addmethod(pipe_class, (t_method)pipe_clear, gensym("clear"), 0);
511}
512
513void x_time_setup(void)
514{
515 delay_setup();
516 metro_setup();
517 line_setup();
518 timer_setup();
519 pipe_setup();
520}
521/* Copyright (c) 1997-1999 Miller Puckette.
522* For information on usage and redistribution, and for a DISCLAIMER OF ALL
523* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
524
525/* clock objects */
526
527#include "m_pd.h"
528#include <stdio.h>
529/* -------------------------- delay ------------------------------ */
530static t_class *delay_class;
531
532typedef struct _delay
533{
534 t_object x_obj;
535 t_clock *x_clock;
536 double x_deltime;
537} t_delay;
538
539static void delay_bang(t_delay *x)
540{
541 clock_delay(x->x_clock, x->x_deltime);
542}
543
544static void delay_stop(t_delay *x)
545{
546 clock_unset(x->x_clock);
547}
548
549static void delay_ft1(t_delay *x, t_floatarg g)
550{
551 if (g < 0) g = 0;
552 x->x_deltime = g;
553}
554
555static void delay_float(t_delay *x, t_float f)
556{
557 delay_ft1(x, f);
558 delay_bang(x);
559}
560
561static void delay_tick(t_delay *x)
562{
563 outlet_bang(x->x_obj.ob_outlet);
564}
565
566static void delay_free(t_delay *x)
567{
568 clock_free(x->x_clock);
569}
570
571static void *delay_new(t_floatarg f)
572{
573 t_delay *x = (t_delay *)pd_new(delay_class);
574 delay_ft1(x, f);
575 x->x_clock = clock_new(x, (t_method)delay_tick);
576 outlet_new(&x->x_obj, gensym("bang"));
577 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
578 return (x);
579}
580
581static void delay_setup(void)
582{
583 delay_class = class_new(gensym("delay"), (t_newmethod)delay_new,
584 (t_method)delay_free, sizeof(t_delay), 0, A_DEFFLOAT, 0);
585 class_addcreator((t_newmethod)delay_new, gensym("del"), A_DEFFLOAT, 0);
586 class_addbang(delay_class, delay_bang);
587 class_addmethod(delay_class, (t_method)delay_stop, gensym("stop"), 0);
588 class_addmethod(delay_class, (t_method)delay_ft1,
589 gensym("ft1"), A_FLOAT, 0);
590 class_addfloat(delay_class, (t_method)delay_float);
591}
592
593/* -------------------------- metro ------------------------------ */
594static t_class *metro_class;
595
596typedef struct _metro
597{
598 t_object x_obj;
599 t_clock *x_clock;
600 double x_deltime;
601 int x_hit;
602} t_metro;
603
604static void metro_tick(t_metro *x)
605{
606 x->x_hit = 0;
607 outlet_bang(x->x_obj.ob_outlet);
608 if (!x->x_hit) clock_delay(x->x_clock, x->x_deltime);
609}
610
611static void metro_float(t_metro *x, t_float f)
612{
613 if (f != 0) metro_tick(x);
614 else clock_unset(x->x_clock);
615 x->x_hit = 1;
616}
617
618static void metro_bang(t_metro *x)
619{
620 metro_float(x, 1);
621}
622
623static void metro_stop(t_metro *x)
624{
625 metro_float(x, 0);
626}
627
628static void metro_ft1(t_metro *x, t_floatarg g)
629{
630 if (g < 1) g = 1;
631 x->x_deltime = g;
632}
633
634static void metro_free(t_metro *x)
635{
636 clock_free(x->x_clock);
637}
638
639static void *metro_new(t_floatarg f)
640{
641 t_metro *x = (t_metro *)pd_new(metro_class);
642 metro_ft1(x, f);
643 x->x_hit = 0;
644 x->x_clock = clock_new(x, (t_method)metro_tick);
645 outlet_new(&x->x_obj, gensym("bang"));
646 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
647 return (x);
648}
649
650static void metro_setup(void)
651{
652 metro_class = class_new(gensym("metro"), (t_newmethod)metro_new,
653 (t_method)metro_free, sizeof(t_metro), 0, A_DEFFLOAT, 0);
654 class_addbang(metro_class, metro_bang);
655 class_addmethod(metro_class, (t_method)metro_stop, gensym("stop"), 0);
656 class_addmethod(metro_class, (t_method)metro_ft1, gensym("ft1"),
657 A_FLOAT, 0);
658 class_addfloat(metro_class, (t_method)metro_float);
659}
660
661/* -------------------------- line ------------------------------ */
662static t_class *line_class;
663
664typedef struct _line
665{
666 t_object x_obj;
667 t_clock *x_clock;
668 double x_targettime;
669 t_float x_targetval;
670 double x_prevtime;
671 t_float x_setval;
672 int x_gotinlet;
673 t_float x_grain;
674 double x_1overtimediff;
675 double x_in1val;
676} t_line;
677
678static void line_tick(t_line *x)
679{
680 double timenow = clock_getsystime();
681 double msectogo = - clock_gettimesince(x->x_targettime);
682 if (msectogo < 1E-9)
683 {
684 outlet_float(x->x_obj.ob_outlet, x->x_targetval);
685 }
686 else
687 {
688 outlet_float(x->x_obj.ob_outlet,
689 x->x_setval + x->x_1overtimediff * (timenow - x->x_prevtime)
690 * (x->x_targetval - x->x_setval));
691 clock_delay(x->x_clock,
692 (x->x_grain > msectogo ? msectogo : x->x_grain));
693 }
694}
695
696static void line_float(t_line *x, t_float f)
697{
698 double timenow = clock_getsystime();
699 if (x->x_gotinlet && x->x_in1val > 0)
700 {
701 if (timenow > x->x_targettime) x->x_setval = x->x_targetval;
702 else x->x_setval = x->x_setval + x->x_1overtimediff *
703 (timenow - x->x_prevtime)
704 * (x->x_targetval - x->x_setval);
705 x->x_prevtime = timenow;
706 x->x_targettime = clock_getsystimeafter(x->x_in1val);
707 x->x_targetval = f;
708 line_tick(x);
709 x->x_gotinlet = 0;
710 x->x_1overtimediff = 1./ (x->x_targettime - timenow);
711 clock_delay(x->x_clock,
712 (x->x_grain > x->x_in1val ? x->x_in1val : x->x_grain));
713
714 }
715 else
716 {
717 clock_unset(x->x_clock);
718 x->x_targetval = x->x_setval = f;
719 outlet_float(x->x_obj.ob_outlet, f);
720 }
721 x->x_gotinlet = 0;
722}
723
724static void line_ft1(t_line *x, t_floatarg g)
725{
726 x->x_in1val = g;
727 x->x_gotinlet = 1;
728}
729
730static void line_stop(t_line *x)
731{
732 x->x_targetval = x->x_setval;
733 clock_unset(x->x_clock);
734}
735
736static void line_free(t_line *x)
737{
738 clock_free(x->x_clock);
739}
740
741static void *line_new(t_floatarg f, t_floatarg grain)
742{
743 t_line *x = (t_line *)pd_new(line_class);
744 x->x_targetval = x->x_setval = f;
745 x->x_gotinlet = 0;
746 x->x_1overtimediff = 1;
747 x->x_clock = clock_new(x, (t_method)line_tick);
748 x->x_targettime = x->x_prevtime = clock_getsystime();
749 if (grain <= 0) grain = 20;
750 x->x_grain = grain;
751 outlet_new(&x->x_obj, gensym("float"));
752 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
753 return (x);
754}
755
756static void line_setup(void)
757{
758 line_class = class_new(gensym("line"), (t_newmethod)line_new,
759 (t_method)line_free, sizeof(t_line), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
760 class_addmethod(line_class, (t_method)line_ft1,
761 gensym("ft1"), A_FLOAT, 0);
762 class_addmethod(line_class, (t_method)line_stop,
763 gensym("stop"), 0);
764 class_addfloat(line_class, (t_method)line_float);
765}
766
767/* -------------------------- timer ------------------------------ */
768static t_class *timer_class;
769
770typedef struct _timer
771{
772 t_object x_obj;
773 t_time x_settime;
774} t_timer;
775
776static void timer_bang(t_timer *x)
777{
778 x->x_settime = clock_getsystime();
779}
780
781static void timer_bang2(t_timer *x)
782{
783 t_time diff = clock_gettimesince(x->x_settime);
784 outlet_float(x->x_obj.ob_outlet, diff);
785}
786
787static void *timer_new(t_floatarg f)
788{
789 t_timer *x = (t_timer *)pd_new(timer_class);
790 timer_bang(x);
791 outlet_new(&x->x_obj, gensym("float"));
792 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
793 return (x);
794}
795
796static void timer_setup(void)
797{
798 timer_class = class_new(gensym("timer"), (t_newmethod)timer_new, 0,
799 sizeof(t_timer), 0, A_DEFFLOAT, 0);
800 class_addbang(timer_class, timer_bang);
801 class_addmethod(timer_class, (t_method)timer_bang2, gensym("bang2"), 0);
802}
803
804
805/* -------------------------- pipe -------------------------- */
806
807static t_class *pipe_class;
808
809typedef struct _hang
810{
811 t_clock *h_clock;
812 struct _hang *h_next;
813 struct _pipe *h_owner;
814 t_gpointer *h_gp;
815 union word h_vec[1]; /* not the actual number. */
816} t_hang;
817
818typedef struct pipeout
819{
820 t_atom p_atom;
821 t_outlet *p_outlet;
822} t_pipeout;
823
824typedef struct _pipe
825{
826 t_object x_obj;
827 int x_n;
828 int x_nptr;
829 float x_deltime;
830 t_pipeout *x_vec;
831 t_gpointer *x_gp;
832 t_hang *x_hang;
833} t_pipe;
834
835static void *pipe_new(t_symbol *s, int argc, t_atom *argv)
836{
837 t_pipe *x = (t_pipe *)pd_new(pipe_class);
838 t_atom defarg, *ap;
839 t_pipeout *vec, *vp;
840 t_gpointer *gp;
841 int nptr = 0;
842 int i;
843 float deltime;
844 if (argc)
845 {
846 if (argv[argc-1].a_type != A_FLOAT)
847 {
848 char stupid[80];
849 atom_string(&argv[argc-1], stupid, 79);
850 post("pipe: %s: bad time delay value", stupid);
851 deltime = 0;
852 }
853 else deltime = argv[argc-1].a_w.w_float;
854 argc--;
855 }
856 else deltime = 0;
857 if (!argc)
858 {
859 argv = &defarg;
860 argc = 1;
861 SETFLOAT(&defarg, 0);
862 }
863 x->x_n = argc;
864 vec = x->x_vec = (t_pipeout *)getbytes(argc * sizeof(*x->x_vec));
865
866 for (i = argc, ap = argv; i--; ap++)
867 if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p')
868 nptr++;
869
870 gp = x->x_gp = (t_gpointer *)t_getbytes(nptr * sizeof (*gp));
871 x->x_nptr = nptr;
872
873 for (i = 0, vp = vec, ap = argv; i < argc; i++, ap++, vp++)
874 {
875 if (ap->a_type == A_FLOAT)
876 {
877 vp->p_atom = *ap;
878 vp->p_outlet = outlet_new(&x->x_obj, &s_float);
879 if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float);
880 }
881 else if (ap->a_type == A_SYMBOL)
882 {
883 char c = *ap->a_w.w_symbol->s_name;
884 if (c == 's')
885 {
886 SETSYMBOL(&vp->p_atom, &s_symbol);
887 vp->p_outlet = outlet_new(&x->x_obj, &s_symbol);
888 if (i) symbolinlet_new(&x->x_obj, &vp->p_atom.a_w.w_symbol);
889 }
890 else if (c == 'p')
891 {
892 vp->p_atom.a_type = A_POINTER;
893 vp->p_atom.a_w.w_gpointer = gp;
894 gpointer_init(gp);
895 vp->p_outlet = outlet_new(&x->x_obj, &s_pointer);
896 if (i) pointerinlet_new(&x->x_obj, gp);
897 gp++;
898 }
899 else
900 {
901 if (c != 'f') error("pack: %s: bad type",
902 ap->a_w.w_symbol->s_name);
903 SETFLOAT(&vp->p_atom, 0);
904 vp->p_outlet = outlet_new(&x->x_obj, &s_float);
905 if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float);
906 }
907 }
908 }
909 floatinlet_new(&x->x_obj, &x->x_deltime);
910 x->x_hang = 0;
911 x->x_deltime = deltime;
912 return (x);
913}
914
915static void hang_free(t_hang *h)
916{
917 t_pipe *x = h->h_owner;
918 t_gpointer *gp;
919 int i;
920 for (gp = h->h_gp, i = x->x_nptr; i--; gp++)
921 gpointer_unset(gp);
922 freebytes(h->h_gp, x->x_nptr * sizeof(*h->h_gp));
923 clock_free(h->h_clock);
924 freebytes(h, sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec));
925}
926
927static void hang_tick(t_hang *h)
928{
929 t_pipe *x = h->h_owner;
930 t_hang *h2, *h3;
931 t_pipeout *p;
932 int i;
933 union word *w;
934 if (x->x_hang == h) x->x_hang = h->h_next;
935 else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3)
936 {
937 if (h3 == h)
938 {
939 h2->h_next = h3->h_next;
940 break;
941 }
942 }
943 for (i = x->x_n, p = x->x_vec + (x->x_n - 1), w = h->h_vec + (x->x_n - 1);
944 i--; p--, w--)
945 {
946 switch (p->p_atom.a_type)
947 {
948 case A_FLOAT: outlet_float(p->p_outlet, w->w_float); break;
949 case A_SYMBOL: outlet_symbol(p->p_outlet, w->w_symbol); break;
950 case A_POINTER:
951 if (gpointer_check(w->w_gpointer, 1))
952 outlet_pointer(p->p_outlet, w->w_gpointer);
953 else post("pipe: stale pointer");
954 break;
955 }
956 }
957 hang_free(h);
958}
959
960static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av)
961{
962 t_hang *h = (t_hang *)
963 getbytes(sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec));
964 t_gpointer *gp, *gp2;
965 t_pipeout *p;
966 int i, n = x->x_n;
967 t_atom *ap;
968 t_word *w;
969 h->h_gp = (t_gpointer *)getbytes(x->x_nptr * sizeof(t_gpointer));
970 if (ac > n) ac = n;
971 for (i = 0, gp = x->x_gp, p = x->x_vec, ap = av; i < ac;
972 i++, p++, ap++)
973 {
974 switch (p->p_atom.a_type)
975 {
976 case A_FLOAT: p->p_atom.a_w.w_float = atom_getfloat(ap); break;
977 case A_SYMBOL: p->p_atom.a_w.w_symbol = atom_getsymbol(ap); break;
978 case A_POINTER:
979 gpointer_unset(gp);
980 if (ap->a_type != A_POINTER)
981 post("pipe: bad pointer");
982 else
983 {
984 *gp = *(ap->a_w.w_gpointer);
985 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
986 }
987 gp++;
988 }
989 }
990 for (i = 0, gp = x->x_gp, gp2 = h->h_gp, p = x->x_vec, w = h->h_vec;
991 i < n; i++, p++, w++)
992 {
993 if (p->p_atom.a_type == A_POINTER)
994 {
995 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
996 w->w_gpointer = gp2;
997 *gp2++ = *gp++;
998 }
999 else *w = p->p_atom.a_w;
1000 }
1001 h->h_next = x->x_hang;
1002 x->x_hang = h;
1003 h->h_owner = x;
1004 h->h_clock = clock_new(h, (t_method)hang_tick);
1005 clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0));
1006}
1007
1008static void pipe_flush(t_pipe *x)
1009{
1010 while (x->x_hang) hang_tick(x->x_hang);
1011}
1012
1013static void pipe_clear(t_pipe *x)
1014{
1015 t_hang *hang;
1016 while (hang = x->x_hang)
1017 {
1018 x->x_hang = hang->h_next;
1019 hang_free(hang);
1020 }
1021}
1022
1023static void pipe_setup(void)
1024{
1025 pipe_class = class_new(gensym("pipe"),
1026 (t_newmethod)pipe_new, (t_method)pipe_clear,
1027 sizeof(t_pipe), 0, A_GIMME, 0);
1028 class_addlist(pipe_class, pipe_list);
1029 class_addmethod(pipe_class, (t_method)pipe_flush, gensym("flush"), 0);
1030 class_addmethod(pipe_class, (t_method)pipe_clear, gensym("clear"), 0);
1031}
1032
1033void x_time_setup(void)
1034{
1035 delay_setup();
1036 metro_setup();
1037 line_setup();
1038 timer_setup();
1039 pipe_setup();
1040}
diff --git a/apps/plugins/pdbox/README.rockbox b/apps/plugins/pdbox/README.rockbox
new file mode 100644
index 0000000000..634413b965
--- /dev/null
+++ b/apps/plugins/pdbox/README.rockbox
@@ -0,0 +1,16 @@
1Library: PDa (Pure Data Anywhere)
2Imported: 2009-05-22 by Wincent Balin (GSoC), commit by Peter D'Hoye
3
4This directory structure contains the Pure Data Anywhere implementation
5
6LICENSING INFORMATION
7
8PDa is licensed under the Standard Improved BSD License and is copyrighted
9Miller Puckette and others
10
11IMPORT DETAILS
12
13PDbox is based on PDa 0.6 which is based on pd-0.37-4 (date?)
14
15[more info from Wincent Balin goes here]
16
diff --git a/apps/plugins/pdbox/SOURCES b/apps/plugins/pdbox/SOURCES
new file mode 100644
index 0000000000..8c6db8ade3
--- /dev/null
+++ b/apps/plugins/pdbox/SOURCES
@@ -0,0 +1,330 @@
1pdbox.c
2pdbox-net.c
3
4/*
5dbestfit-3.3/bmalloc.c
6dbestfit-3.3/bysize.c
7dbestfit-3.3/dmalloc.c
8*/
9
10/*
11PDa/src/g_canvas.c
12PDa/src/g_graph.c
13PDa/src/g_text.c
14*/
15/* PDa/src/g_rtext.c Does not compile */
16/*
17PDa/src/g_array.c
18PDa/src/g_template.c
19PDa/src/g_io.c
20PDa/src/g_scalar.c
21PDa/src/g_traversal.c
22PDa/src/g_guiconnect.c
23PDa/src/g_readwrite.c
24PDa/src/g_editor.c
25PDa/src/g_all_guis.c
26PDa/src/g_bang.c
27PDa/src/g_hdial.c
28PDa/src/g_hslider.c
29PDa/src/g_mycanvas.c
30PDa/src/g_numbox.c
31PDa/src/g_toggle.c
32PDa/src/g_vdial.c
33PDa/src/g_vslider.c
34PDa/src/g_vumeter.c
35PDa/src/m_pd.c
36PDa/src/m_class.c
37PDa/src/m_obj.c
38PDa/src/m_atom.c
39*/
40/*
41PDa/src/m_memory.c
42*/
43
44/* PDa/src/m_binbuf.c Does not compile, file handling stuff */
45/*
46PDa/src/m_conf.c
47PDa/src/m_glob.c
48PDa/src/m_sched.c
49*/
50/* PDa/src/s_main.c Does not compile, system reasons */
51/* PDa/src/s_inter.c Does not compile, BSD sockets */
52/* PDa/src/s_file.c Does not compile, file handling stuff */
53/* PDa/src/s_print.c Does not compile, system reasons */
54/*
55PDa/src/s_loader.c
56*/
57/* PDa/src/s_path.c Does not compile, file handling stuff */
58/*
59PDa/src/s_entry.c
60PDa/src/s_audio.c
61PDa/src/s_midi.c
62PDa/src/d_ugen.c
63PDa/src/d_arithmetic.c
64PDa/src/d_dac.c
65PDa/src/d_misc.c
66PDa/src/d_fft.c
67PDa/src/d_mayer_fft.c
68PDa/src/d_fftroutine.c
69PDa/src/d_global.c
70PDa/src/d_resample.c
71PDa/src/d_ctl.c
72*/
73/* PDa/src/d_soundfile.c Does not compile, file handling stuff */
74/*
75PDa/src/x_arithmetic.c
76PDa/src/x_connective.c
77PDa/src/x_interface.c
78PDa/src/x_midi.c
79PDa/src/x_misc.c
80PDa/src/x_time.c
81PDa/src/x_acoustics.c
82*/
83/* PDa/src/x_net.c Does not compile, BSD sockets */
84/*
85PDa/src/x_qlist.c
86PDa/src/x_gui.c
87*/
88
89/*
90PDa/src/d_imayer_fft.c
91*/
92PDa/src/m_fixed.c
93
94/*
95PDa/intern/biquad~.c
96PDa/intern/bp~.c
97PDa/intern/clip~.c
98PDa/intern/cos~.c
99PDa/intern/dbtopow~.c
100PDa/intern/dbtorms~.c
101PDa/intern/delread~.c
102PDa/intern/delwrite~.c
103PDa/intern/env~.c
104PDa/intern/ftom~.c
105PDa/intern/hip~.c
106PDa/intern/intern_setup.c
107PDa/intern/line~.c
108PDa/intern/lop~.c
109PDa/intern/mtof~.c
110PDa/intern/noise~.c
111PDa/intern/osc~.c
112PDa/intern/phasor~.c
113PDa/intern/powtodb~.c
114PDa/intern/print~.c
115PDa/intern/rmstodb~.c
116PDa/intern/rsqrt~.c
117PDa/intern/samphold~.c
118*/
119/* PDa/intern/sfread~.c Does not compile, file handling stuff */
120/* PDa/intern/sfwrite~.c Does not compile, file handling stuff */
121/*
122PDa/intern/sig~.c
123PDa/intern/snapshot~.c
124PDa/intern/sqrt~.c
125PDa/intern/tabosc4~.c
126PDa/intern/tabplay~.c
127PDa/intern/tabread.c
128PDa/intern/tabread4~.c
129PDa/intern/tabread~.c
130PDa/intern/tabreceive~.c
131PDa/intern/tabsend~.c
132PDa/intern/tabwrite.c
133PDa/intern/tabwrite~.c
134PDa/intern/threshold~.c
135PDa/intern/vcf~.c
136PDa/intern/vd~.c
137PDa/intern/vline~.c
138PDa/intern/vsnapshot~.c
139PDa/intern/wrap~.c
140*/
141
142/*
143PDa/extra/OSCroute.c
144PDa/extra/bandpass.c
145*/
146/* PDa/extra/dumpOSC.c Does not compile, file handling stuff */
147/*
148PDa/extra/equalizer.c
149PDa/extra/gcanvas.c
150PDa/extra/highpass.c
151PDa/extra/highshelf.c
152PDa/extra/hlshelf.c
153PDa/extra/image.c
154PDa/extra/lowpass.c
155PDa/extra/lowshelf.c
156PDa/extra/moog~.c
157PDa/extra/notch.c
158*/
159/* PDa/extra/sendOSC.c Does not compile, file handling stuff */
160/*
161PDa/extra/shell.c
162PDa/extra/slider.c
163PDa/extra/sliderh.c
164PDa/extra/zerox~.c
165*/
166pdbox.c
167pdbox-net.c
168
169/*
170dbestfit-3.3/bmalloc.c
171dbestfit-3.3/bysize.c
172dbestfit-3.3/dmalloc.c
173*/
174
175/*
176PDa/src/g_canvas.c
177PDa/src/g_graph.c
178PDa/src/g_text.c
179*/
180/* PDa/src/g_rtext.c Does not compile */
181/*
182PDa/src/g_array.c
183PDa/src/g_template.c
184PDa/src/g_io.c
185PDa/src/g_scalar.c
186PDa/src/g_traversal.c
187PDa/src/g_guiconnect.c
188PDa/src/g_readwrite.c
189PDa/src/g_editor.c
190PDa/src/g_all_guis.c
191PDa/src/g_bang.c
192PDa/src/g_hdial.c
193PDa/src/g_hslider.c
194PDa/src/g_mycanvas.c
195PDa/src/g_numbox.c
196PDa/src/g_toggle.c
197PDa/src/g_vdial.c
198PDa/src/g_vslider.c
199PDa/src/g_vumeter.c
200PDa/src/m_pd.c
201PDa/src/m_class.c
202PDa/src/m_obj.c
203PDa/src/m_atom.c
204*/
205/*
206PDa/src/m_memory.c
207*/
208
209/* PDa/src/m_binbuf.c Does not compile, file handling stuff */
210/*
211PDa/src/m_conf.c
212PDa/src/m_glob.c
213PDa/src/m_sched.c
214*/
215/* PDa/src/s_main.c Does not compile, system reasons */
216/* PDa/src/s_inter.c Does not compile, BSD sockets */
217/* PDa/src/s_file.c Does not compile, file handling stuff */
218/* PDa/src/s_print.c Does not compile, system reasons */
219/*
220PDa/src/s_loader.c
221*/
222/* PDa/src/s_path.c Does not compile, file handling stuff */
223/*
224PDa/src/s_entry.c
225PDa/src/s_audio.c
226PDa/src/s_midi.c
227PDa/src/d_ugen.c
228PDa/src/d_arithmetic.c
229PDa/src/d_dac.c
230PDa/src/d_misc.c
231PDa/src/d_fft.c
232PDa/src/d_mayer_fft.c
233PDa/src/d_fftroutine.c
234PDa/src/d_global.c
235PDa/src/d_resample.c
236PDa/src/d_ctl.c
237*/
238/* PDa/src/d_soundfile.c Does not compile, file handling stuff */
239/*
240PDa/src/x_arithmetic.c
241PDa/src/x_connective.c
242PDa/src/x_interface.c
243PDa/src/x_midi.c
244PDa/src/x_misc.c
245PDa/src/x_time.c
246PDa/src/x_acoustics.c
247*/
248/* PDa/src/x_net.c Does not compile, BSD sockets */
249/*
250PDa/src/x_qlist.c
251PDa/src/x_gui.c
252*/
253
254/*
255PDa/src/d_imayer_fft.c
256*/
257PDa/src/m_fixed.c
258
259/*
260PDa/intern/biquad~.c
261PDa/intern/bp~.c
262PDa/intern/clip~.c
263PDa/intern/cos~.c
264PDa/intern/dbtopow~.c
265PDa/intern/dbtorms~.c
266PDa/intern/delread~.c
267PDa/intern/delwrite~.c
268PDa/intern/env~.c
269PDa/intern/ftom~.c
270PDa/intern/hip~.c
271PDa/intern/intern_setup.c
272PDa/intern/line~.c
273PDa/intern/lop~.c
274PDa/intern/mtof~.c
275PDa/intern/noise~.c
276PDa/intern/osc~.c
277PDa/intern/phasor~.c
278PDa/intern/powtodb~.c
279PDa/intern/print~.c
280PDa/intern/rmstodb~.c
281PDa/intern/rsqrt~.c
282PDa/intern/samphold~.c
283*/
284/* PDa/intern/sfread~.c Does not compile, file handling stuff */
285/* PDa/intern/sfwrite~.c Does not compile, file handling stuff */
286/*
287PDa/intern/sig~.c
288PDa/intern/snapshot~.c
289PDa/intern/sqrt~.c
290PDa/intern/tabosc4~.c
291PDa/intern/tabplay~.c
292PDa/intern/tabread.c
293PDa/intern/tabread4~.c
294PDa/intern/tabread~.c
295PDa/intern/tabreceive~.c
296PDa/intern/tabsend~.c
297PDa/intern/tabwrite.c
298PDa/intern/tabwrite~.c
299PDa/intern/threshold~.c
300PDa/intern/vcf~.c
301PDa/intern/vd~.c
302PDa/intern/vline~.c
303PDa/intern/vsnapshot~.c
304PDa/intern/wrap~.c
305*/
306
307/*
308PDa/extra/OSCroute.c
309PDa/extra/bandpass.c
310*/
311/* PDa/extra/dumpOSC.c Does not compile, file handling stuff */
312/*
313PDa/extra/equalizer.c
314PDa/extra/gcanvas.c
315PDa/extra/highpass.c
316PDa/extra/highshelf.c
317PDa/extra/hlshelf.c
318PDa/extra/image.c
319PDa/extra/lowpass.c
320PDa/extra/lowshelf.c
321PDa/extra/moog~.c
322PDa/extra/notch.c
323*/
324/* PDa/extra/sendOSC.c Does not compile, file handling stuff */
325/*
326PDa/extra/shell.c
327PDa/extra/slider.c
328PDa/extra/sliderh.c
329PDa/extra/zerox~.c
330*/
diff --git a/apps/plugins/pdbox/dbestfit-3.3/CHANGES b/apps/plugins/pdbox/dbestfit-3.3/CHANGES
new file mode 100644
index 0000000000..f244f66f87
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/CHANGES
@@ -0,0 +1,24 @@
1Changes
2
3* (March 30 2005) Daniel
4
5 Linus Nielsen Feltzing provided a patch that corrected several minor problems
6 that prevented dbestfit from working good. Linus also tested and timed
7 dbestfit for real in a target where he replaced the pSOS-provided memory
8 subsystem.
9
10* 3.2
11
12 Made eons ago, all older changes have been forgotten.
13Changes
14
15* (March 30 2005) Daniel
16
17 Linus Nielsen Feltzing provided a patch that corrected several minor problems
18 that prevented dbestfit from working good. Linus also tested and timed
19 dbestfit for real in a target where he replaced the pSOS-provided memory
20 subsystem.
21
22* 3.2
23
24 Made eons ago, all older changes have been forgotten.
diff --git a/apps/plugins/pdbox/dbestfit-3.3/FILES b/apps/plugins/pdbox/dbestfit-3.3/FILES
new file mode 100644
index 0000000000..684a225972
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/FILES
@@ -0,0 +1,30 @@
1/bysize.c
2/bysize.h
3/bmalloc.c
4/bmalloc.h
5/dmalloc.c
6/dmalloc.h
7/FILES
8/README
9/Makefile
10/Malloc.c
11/mytest.c
12/dmytest.c
13/thoughts
14/malloc.man
15/CHANGES
16/bysize.c
17/bysize.h
18/bmalloc.c
19/bmalloc.h
20/dmalloc.c
21/dmalloc.h
22/FILES
23/README
24/Makefile
25/Malloc.c
26/mytest.c
27/dmytest.c
28/thoughts
29/malloc.man
30/CHANGES
diff --git a/apps/plugins/pdbox/dbestfit-3.3/Makefile b/apps/plugins/pdbox/dbestfit-3.3/Makefile
new file mode 100644
index 0000000000..e34b02e918
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/Makefile
@@ -0,0 +1,76 @@
1
2OBJS1 = bmalloc.o bysize.o mytest.o
3TARGET1 = mytest
4
5OBJS2 = dmalloc.o bmalloc.o bysize.o Malloc.o
6TARGET2 = mtest
7
8OBJS3 = dmalloc.o bmalloc.o bysize.o dmytest.o
9TARGET3 = dmytest
10
11CFLAGS = -g -DUNIX -DBMALLOC -Wall -pedantic -DDEBUG
12CC = gcc
13
14all: $(TARGET1) $(TARGET2) $(TARGET3)
15
16$(TARGET1): $(OBJS1)
17 $(CC) -g -o $(TARGET1) $(OBJS1)
18
19$(TARGET2): $(OBJS2)
20 $(CC) -g -o $(TARGET2) $(OBJS2)
21
22$(TARGET3): $(OBJS3)
23 $(CC) -g -o $(TARGET3) $(OBJS3)
24
25bmalloc.o: bmalloc.c
26dmalloc.o: dmalloc.c
27mytest.o: mytest.c
28dmytest.o: dmytest.c
29Malloc.o : Malloc.c
30bysize.o : bysize.c
31
32tgz:
33 @(dir=`pwd`;name=`basename $$dir`;echo Creates $$name.tar.gz; cd .. ; \
34 tar -cf $$name.tar `cat $$name/FILES | sed "s:^/:$$name/:g"` ; \
35 gzip $$name.tar ; chmod a+r $$name.tar.gz ; mv $$name.tar.gz $$name/)
36
37clean:
38 rm -f *.o *~ $(TARGET1) $(TARGET2) $(TARGET3)
39
40OBJS1 = bmalloc.o bysize.o mytest.o
41TARGET1 = mytest
42
43OBJS2 = dmalloc.o bmalloc.o bysize.o Malloc.o
44TARGET2 = mtest
45
46OBJS3 = dmalloc.o bmalloc.o bysize.o dmytest.o
47TARGET3 = dmytest
48
49CFLAGS = -g -DUNIX -DBMALLOC -Wall -pedantic -DDEBUG
50CC = gcc
51
52all: $(TARGET1) $(TARGET2) $(TARGET3)
53
54$(TARGET1): $(OBJS1)
55 $(CC) -g -o $(TARGET1) $(OBJS1)
56
57$(TARGET2): $(OBJS2)
58 $(CC) -g -o $(TARGET2) $(OBJS2)
59
60$(TARGET3): $(OBJS3)
61 $(CC) -g -o $(TARGET3) $(OBJS3)
62
63bmalloc.o: bmalloc.c
64dmalloc.o: dmalloc.c
65mytest.o: mytest.c
66dmytest.o: dmytest.c
67Malloc.o : Malloc.c
68bysize.o : bysize.c
69
70tgz:
71 @(dir=`pwd`;name=`basename $$dir`;echo Creates $$name.tar.gz; cd .. ; \
72 tar -cf $$name.tar `cat $$name/FILES | sed "s:^/:$$name/:g"` ; \
73 gzip $$name.tar ; chmod a+r $$name.tar.gz ; mv $$name.tar.gz $$name/)
74
75clean:
76 rm -f *.o *~ $(TARGET1) $(TARGET2) $(TARGET3)
diff --git a/apps/plugins/pdbox/dbestfit-3.3/Malloc.c b/apps/plugins/pdbox/dbestfit-3.3/Malloc.c
new file mode 100644
index 0000000000..25e30706fe
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/Malloc.c
@@ -0,0 +1,402 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <time.h>
5
6/* Storleken på allokeringen bestäms genom att först slumpas en position i
7"size_table" ut, sedan slumpas en storlek mellan den postionen och nästa värde
8i tabellen. Genom att ha tabellen koncentrerad med låga värden, så skapas
9flest såna. Rutinen håller på tills minnet en allokeringen nekas. Den kommer
10aldrig att ha mer än MAXIMAL_MEMORY_TO_ALLOCATE allokerat samtidigt. Maximalt
11har den MAX_ALLOCATIONS allokeringar samtidigt.
12
13Statistiskt sätt så kommer efter ett tag MAX_ALLOCATIONS/2 allokeringar finnas
14samtidigt, med varje allokering i median med värdet av halva "size_table".
15
16När minnet är slut (malloc()=NULL), frågas användaren om han ska fortsätta.
17
18Med jämna mellanrum skrivs statisktik ut på skärmen. (DISPLAY_WHEN)
19
20För att stressa systemet med fler små allokeringar, så kan man öka
21MAX_ALLOCATIONS. AMOUNT_OF_MEMORY bör få den att slå i taket fortare om man
22minskar det.
23
24Ingen initiering görs av slumptalen, så allt är upprepbart (men plocka bort
25kommentaren på srand() och det löser sig.
26
27*/
28
29/*#undef BMALLOC*/
30
31#ifdef BMALLOC
32#include "dmalloc.h"
33
34#include "bmalloc.h"
35#endif
36
37#define MAX_ALLOCATIONS 100000
38#define AMOUNT_OF_MEMORY 180000 /* bytes */
39#define MAXIMAL_MEMORY_TO_ALLOCATE 100000 /* Sätt den här högre än
40 AMOUNT_OF_MEMORY, och malloc() bör
41 returnera NULL förr eller senare */
42
43#define DISPLAY_WHEN (123456) /* When to display statistic */
44
45#define min(a, b) (((a) < (b)) ? (a) : (b))
46#define BOOL char
47#define TRUE 1
48#define FALSE 0
49
50typedef struct {
51 char *memory;
52 long size;
53 char filled_with;
54 long table_position;
55} MallocStruct;
56
57/*
58Skapar en lista med MAX_ALLOCATIONS storlek där det slumpvis allokeras
59eller reallokeras i.
60*/
61
62MallocStruct my_mallocs[MAX_ALLOCATIONS];
63
64long size_table[]={5,8,10,11,12,14,16,18,20,26,33,50,70,90,120,150,200,400,800,1000,2000,4000,8000,10000,11000,12000,13000,14000,15000,16000,17000,18000};
65#define TABLESIZE ((sizeof(size_table)-1)/sizeof(long))
66long size_allocs[TABLESIZE];
67
68int main(void)
69{
70 int i;
71 long count=-1;
72 long count_free=0, count_malloc=0, count_realloc=0;
73 long total_memory=0;
74 BOOL out_of_memory=FALSE;
75 unsigned int seed = time( NULL );
76
77#ifdef BMALLOC
78 void *thisisourheap;
79 thisisourheap = (malloc)(AMOUNT_OF_MEMORY);
80 if(!thisisourheap)
81 return -1; /* can't get memory */
82 add_pool(thisisourheap, AMOUNT_OF_MEMORY);
83#endif
84
85 seed = 1109323906;
86
87 srand( seed ); /* Initialize randomize */
88
89 printf("seed: %d\n", seed);
90
91 while (!out_of_memory) {
92 long number=rand()%MAX_ALLOCATIONS;
93 long size;
94 long table_position=rand()%TABLESIZE;
95 char fill_with=rand()&255;
96
97 count++;
98
99 size=rand()%(size_table[table_position+1]-size_table[table_position])+size_table[table_position];
100
101/* fprintf(stderr, "number %d size %d\n", number, size); */
102
103 if (my_mallocs[number].size) { /* Om allokering redan finns på den här
104 positionen, så reallokerar vi eller
105 friar. */
106 long old_size=my_mallocs[number].size;
107 if (my_mallocs[number].size && fill_with<40) {
108 free(my_mallocs[number].memory);
109 total_memory -= my_mallocs[number].size;
110 count_free++;
111 size_allocs[my_mallocs[number].table_position]--;
112 size=0;
113 my_mallocs[number].size = 0;
114 my_mallocs[number].memory = NULL;
115 } else {
116 /*
117 * realloc() part
118 *
119 */
120 char *temp;
121#if 0
122 if(my_mallocs[number].size > size) {
123 printf("*** %d is realloc()ed to %d\n",
124 my_mallocs[number].size, size);
125 }
126#endif
127 if (total_memory-old_size+size>MAXIMAL_MEMORY_TO_ALLOCATE)
128 goto output; /* for-loop */
129 temp = (char *)realloc(my_mallocs[number].memory, size);
130 if (!temp)
131 out_of_memory=TRUE;
132 else {
133 my_mallocs[number].memory = temp;
134
135 my_mallocs[number].size=size;
136 size_allocs[my_mallocs[number].table_position]--;
137 size_allocs[table_position]++;
138 total_memory -= old_size;
139 total_memory += size;
140 old_size=min(old_size, size);
141 while (--old_size>0) {
142 if (my_mallocs[number].memory[old_size]!=my_mallocs[number].filled_with)
143 fprintf(stderr, "Wrong filling!\n");
144 }
145 count_realloc++;
146 }
147 }
148 } else {
149 if (total_memory+size>MAXIMAL_MEMORY_TO_ALLOCATE) {
150 goto output; /* for-loop */
151 }
152 my_mallocs[number].memory=(char *)malloc(size); /* Allokera! */
153 if (!my_mallocs[number].memory)
154 out_of_memory=TRUE;
155 else {
156 size_allocs[table_position]++;
157 count_malloc++;
158 total_memory += size;
159 }
160 }
161
162 if(!out_of_memory) {
163 my_mallocs[number].table_position=table_position;
164 my_mallocs[number].size=size;
165 my_mallocs[number].filled_with=fill_with;
166 memset(my_mallocs[number].memory, fill_with, size);
167 }
168 output:
169 if (out_of_memory || !(count%DISPLAY_WHEN)) {
170 printf("(%d) malloc %d, realloc %d, free %d, total size %d\n", count, count_malloc, count_realloc, count_free, total_memory);
171 {
172 int count;
173 printf("[size bytes]=[number of allocations]\n");
174 for (count=0; count<TABLESIZE; count++) {
175 printf("%ld=%ld, ", size_table[count], size_allocs[count]);
176 }
177 printf("\n\n");
178 }
179 }
180 if (out_of_memory) {
181 fprintf(stderr, "Memory is out! Continue (y/n)");
182 switch (getchar()) {
183 case 'y':
184 case 'Y':
185 out_of_memory=FALSE;
186 break;
187 }
188 fprintf(stderr, "\n");
189 }
190 }
191 for(i = 0;i < MAX_ALLOCATIONS;i++) {
192 if((my_mallocs[i].memory))
193 free(my_mallocs[i].memory);
194 }
195
196 print_lists();
197
198 printf("\n");
199 return 0;
200}
201
202#include <stdio.h>
203#include <stdlib.h>
204#include <string.h>
205#include <time.h>
206
207/* Storleken på allokeringen bestäms genom att först slumpas en position i
208"size_table" ut, sedan slumpas en storlek mellan den postionen och nästa värde
209i tabellen. Genom att ha tabellen koncentrerad med låga värden, så skapas
210flest såna. Rutinen håller på tills minnet en allokeringen nekas. Den kommer
211aldrig att ha mer än MAXIMAL_MEMORY_TO_ALLOCATE allokerat samtidigt. Maximalt
212har den MAX_ALLOCATIONS allokeringar samtidigt.
213
214Statistiskt sätt så kommer efter ett tag MAX_ALLOCATIONS/2 allokeringar finnas
215samtidigt, med varje allokering i median med värdet av halva "size_table".
216
217När minnet är slut (malloc()=NULL), frågas användaren om han ska fortsätta.
218
219Med jämna mellanrum skrivs statisktik ut på skärmen. (DISPLAY_WHEN)
220
221För att stressa systemet med fler små allokeringar, så kan man öka
222MAX_ALLOCATIONS. AMOUNT_OF_MEMORY bör få den att slå i taket fortare om man
223minskar det.
224
225Ingen initiering görs av slumptalen, så allt är upprepbart (men plocka bort
226kommentaren på srand() och det löser sig.
227
228*/
229
230/*#undef BMALLOC*/
231
232#ifdef BMALLOC
233#include "dmalloc.h"
234
235#include "bmalloc.h"
236#endif
237
238#define MAX_ALLOCATIONS 100000
239#define AMOUNT_OF_MEMORY 180000 /* bytes */
240#define MAXIMAL_MEMORY_TO_ALLOCATE 100000 /* Sätt den här högre än
241 AMOUNT_OF_MEMORY, och malloc() bör
242 returnera NULL förr eller senare */
243
244#define DISPLAY_WHEN (123456) /* When to display statistic */
245
246#define min(a, b) (((a) < (b)) ? (a) : (b))
247#define BOOL char
248#define TRUE 1
249#define FALSE 0
250
251typedef struct {
252 char *memory;
253 long size;
254 char filled_with;
255 long table_position;
256} MallocStruct;
257
258/*
259Skapar en lista med MAX_ALLOCATIONS storlek där det slumpvis allokeras
260eller reallokeras i.
261*/
262
263MallocStruct my_mallocs[MAX_ALLOCATIONS];
264
265long size_table[]={5,8,10,11,12,14,16,18,20,26,33,50,70,90,120,150,200,400,800,1000,2000,4000,8000,10000,11000,12000,13000,14000,15000,16000,17000,18000};
266#define TABLESIZE ((sizeof(size_table)-1)/sizeof(long))
267long size_allocs[TABLESIZE];
268
269int main(void)
270{
271 int i;
272 long count=-1;
273 long count_free=0, count_malloc=0, count_realloc=0;
274 long total_memory=0;
275 BOOL out_of_memory=FALSE;
276 unsigned int seed = time( NULL );
277
278#ifdef BMALLOC
279 void *thisisourheap;
280 thisisourheap = (malloc)(AMOUNT_OF_MEMORY);
281 if(!thisisourheap)
282 return -1; /* can't get memory */
283 add_pool(thisisourheap, AMOUNT_OF_MEMORY);
284#endif
285
286 seed = 1109323906;
287
288 srand( seed ); /* Initialize randomize */
289
290 printf("seed: %d\n", seed);
291
292 while (!out_of_memory) {
293 long number=rand()%MAX_ALLOCATIONS;
294 long size;
295 long table_position=rand()%TABLESIZE;
296 char fill_with=rand()&255;
297
298 count++;
299
300 size=rand()%(size_table[table_position+1]-size_table[table_position])+size_table[table_position];
301
302/* fprintf(stderr, "number %d size %d\n", number, size); */
303
304 if (my_mallocs[number].size) { /* Om allokering redan finns på den här
305 positionen, så reallokerar vi eller
306 friar. */
307 long old_size=my_mallocs[number].size;
308 if (my_mallocs[number].size && fill_with<40) {
309 free(my_mallocs[number].memory);
310 total_memory -= my_mallocs[number].size;
311 count_free++;
312 size_allocs[my_mallocs[number].table_position]--;
313 size=0;
314 my_mallocs[number].size = 0;
315 my_mallocs[number].memory = NULL;
316 } else {
317 /*
318 * realloc() part
319 *
320 */
321 char *temp;
322#if 0
323 if(my_mallocs[number].size > size) {
324 printf("*** %d is realloc()ed to %d\n",
325 my_mallocs[number].size, size);
326 }
327#endif
328 if (total_memory-old_size+size>MAXIMAL_MEMORY_TO_ALLOCATE)
329 goto output; /* for-loop */
330 temp = (char *)realloc(my_mallocs[number].memory, size);
331 if (!temp)
332 out_of_memory=TRUE;
333 else {
334 my_mallocs[number].memory = temp;
335
336 my_mallocs[number].size=size;
337 size_allocs[my_mallocs[number].table_position]--;
338 size_allocs[table_position]++;
339 total_memory -= old_size;
340 total_memory += size;
341 old_size=min(old_size, size);
342 while (--old_size>0) {
343 if (my_mallocs[number].memory[old_size]!=my_mallocs[number].filled_with)
344 fprintf(stderr, "Wrong filling!\n");
345 }
346 count_realloc++;
347 }
348 }
349 } else {
350 if (total_memory+size>MAXIMAL_MEMORY_TO_ALLOCATE) {
351 goto output; /* for-loop */
352 }
353 my_mallocs[number].memory=(char *)malloc(size); /* Allokera! */
354 if (!my_mallocs[number].memory)
355 out_of_memory=TRUE;
356 else {
357 size_allocs[table_position]++;
358 count_malloc++;
359 total_memory += size;
360 }
361 }
362
363 if(!out_of_memory) {
364 my_mallocs[number].table_position=table_position;
365 my_mallocs[number].size=size;
366 my_mallocs[number].filled_with=fill_with;
367 memset(my_mallocs[number].memory, fill_with, size);
368 }
369 output:
370 if (out_of_memory || !(count%DISPLAY_WHEN)) {
371 printf("(%d) malloc %d, realloc %d, free %d, total size %d\n", count, count_malloc, count_realloc, count_free, total_memory);
372 {
373 int count;
374 printf("[size bytes]=[number of allocations]\n");
375 for (count=0; count<TABLESIZE; count++) {
376 printf("%ld=%ld, ", size_table[count], size_allocs[count]);
377 }
378 printf("\n\n");
379 }
380 }
381 if (out_of_memory) {
382 fprintf(stderr, "Memory is out! Continue (y/n)");
383 switch (getchar()) {
384 case 'y':
385 case 'Y':
386 out_of_memory=FALSE;
387 break;
388 }
389 fprintf(stderr, "\n");
390 }
391 }
392 for(i = 0;i < MAX_ALLOCATIONS;i++) {
393 if((my_mallocs[i].memory))
394 free(my_mallocs[i].memory);
395 }
396
397 print_lists();
398
399 printf("\n");
400 return 0;
401}
402
diff --git a/apps/plugins/pdbox/dbestfit-3.3/README b/apps/plugins/pdbox/dbestfit-3.3/README
new file mode 100644
index 0000000000..919875df96
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/README
@@ -0,0 +1,44 @@
1Package: dbestfit - a dynamic memory allocator
2Date: March 30, 2005
3Version: 3.3
4Author: Daniel Stenberg <daniel@haxx.se>
5
6 I wrote the dmalloc part for small allocation sizes to improve the behavior
7of the built-in (first-fit) allocator found in pSOS (around 1996).
8
9 I wrote the bmalloc part (best-fit with splay-tree sorting) just for the fun
10of it and to see how good malloc() clone I could make. The quality of my
11implementation is still left to be judged in real-world tests.
12
13TODO:
14 * Remove the final not-so-very-nice loop in dmalloc.c that checks for a block
15 with free fragments (when the list gets longer too much time might be spent
16 in that loop).
17
18 * Add semaphore protection in bmalloc.
19
20 * Make a separate application that samples the memory usage of a program
21 and is capable of replaying it (in order to test properly).
22
23Package: dbestfit - a dynamic memory allocator
24Date: March 30, 2005
25Version: 3.3
26Author: Daniel Stenberg <daniel@haxx.se>
27
28 I wrote the dmalloc part for small allocation sizes to improve the behavior
29of the built-in (first-fit) allocator found in pSOS (around 1996).
30
31 I wrote the bmalloc part (best-fit with splay-tree sorting) just for the fun
32of it and to see how good malloc() clone I could make. The quality of my
33implementation is still left to be judged in real-world tests.
34
35TODO:
36 * Remove the final not-so-very-nice loop in dmalloc.c that checks for a block
37 with free fragments (when the list gets longer too much time might be spent
38 in that loop).
39
40 * Add semaphore protection in bmalloc.
41
42 * Make a separate application that samples the memory usage of a program
43 and is capable of replaying it (in order to test properly).
44
diff --git a/apps/plugins/pdbox/dbestfit-3.3/bmalloc.c b/apps/plugins/pdbox/dbestfit-3.3/bmalloc.c
new file mode 100644
index 0000000000..f95b4f6125
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/bmalloc.c
@@ -0,0 +1,740 @@
1/*****************************************************************************
2 *
3 * Big (best-fit) Memory Allocation
4 *
5 * Author: Daniel Stenberg
6 * Date: March 5, 1997
7 * Version: 2.0
8 * Email: Daniel.Stenberg@sth.frontec.se
9 *
10 *
11 * Read 'thoughts' for theories and details in implementation.
12 *
13 * Routines meant to replace the most low level functions of an Operting
14 * System
15 *
16 * v2.0
17 * - Made all size-routines get moved out from this file. This way, the size
18 * functions can much more easily get replaced.
19 * - Improved how new memory blocks get added to the size-sorted list. When
20 * not adding new pools, there should never ever be any list traversing
21 * since all information is dynamically gathered.
22 *
23 ****************************************************************************/
24
25#include <stdio.h>
26#include <stdlib.h>
27
28#include "bysize.h"
29
30#ifndef TRUE
31#define TRUE 1
32#endif
33#ifndef FALSE
34#define FALSE 0
35#endif
36
37/* #define DEBUG */
38
39#define BMEM_ALIGN 64 /* resolution */
40
41#define BMEMERR_TOOSMALL -1
42
43/* this struct will be stored in all CHUNKS and AREAS */
44struct BlockInfo {
45 struct BlockInfo *lower; /* previous block in memory (lower address) */
46 struct BlockInfo *higher; /* next block in memory (higher address) */
47 unsigned long info; /* 31 bits size: 1 bit free boolean */
48#define INFO_FREE 1
49#define INFO_SIZE (~ INFO_FREE) /* inverted FREE bit pattern */
50
51 /* FREE+SIZE Could be written to use ordinary bitfields if using a smart
52 (like gcc) compiler in a manner like:
53 int size:31;
54 int free:1;
55
56 The 'higher' pointer COULD be removed completely if the size is used as
57 an index to the higher one. This would then REQUIRE the entire memory
58 pool to be contiguous and it needs a 'terminating' "node" or an extra
59 flag that informs about the end of the list.
60 */
61};
62
63/* the BLOCK list should be sorted in a lower to higher address order */
64struct BlockInfo *blockHead=NULL; /* nothing from the start */
65
66void print_lists(void);
67
68
69/***********************************************************************
70 *
71 * remove_block()
72 *
73 * Remove the block from the address-sorted list.
74 *
75 ***********************************************************************/
76
77void remove_block(struct BlockInfo *block)
78{
79 if(block->lower)
80 block->lower->higher = block->higher;
81 else
82 blockHead = block->higher;
83 if(block->higher)
84 block->higher->lower = block->lower;
85}
86
87/****************************************************************************
88 *
89 * add_blocktolists()
90 *
91 * Adds the specified block at the specified place in the address-sorted
92 * list and at the appropriate place in the size-sorted.
93 *
94 ***************************************************************************/
95void add_blocktolists(struct BlockInfo *block,
96 struct BlockInfo *newblock,
97 size_t newsize)
98{
99 struct BlockInfo *temp; /* temporary storage variable */
100 if(block) {
101 /* `block' is now a lower address than 'newblock' */
102
103 /*
104 * Check if the new CHUNK is wall-to-wall with the lower addressed
105 * one (if *that* is free)
106 */
107 if(block->info&INFO_FREE) {
108 if((char *)block + (block->info&INFO_SIZE) == (char *)newblock) {
109 /* yes sir, this is our lower address neighbour, enlarge that one
110 pick it out from the list and recursively add that chunk and
111 then we escape */
112
113 /* remove from size-sorted list: */
114 remove_chunksize((char*)block+sizeof(struct BlockInfo));
115
116 block->info += newsize; /* newsize is an even number and thus the FREE
117 bit is untouched */
118
119 remove_block(block); /* unlink the block address-wise */
120
121 /* recursively check our lower friend(s) */
122 add_blocktolists(block->lower, block, block->info&INFO_SIZE);
123 return;
124 }
125 }
126
127 temp = block->higher;
128
129 block->higher = newblock;
130 newblock->lower = block;
131 newblock->higher = temp;
132 if(newblock->higher)
133 newblock->higher->lower = newblock;
134 }
135 else {
136 /* this block should preceed the heading one */
137 temp = blockHead;
138
139 /* check if this is our higher addressed neighbour */
140 if((char *)newblock + newsize == (char *)temp) {
141
142 /* yes, we are wall-to-wall with the higher CHUNK */
143 if(temp->info&INFO_FREE) {
144 /* and the neighbour is even free, remove that one and enlarge
145 ourselves, call add_pool() recursively and then escape */
146
147 remove_block(temp); /* unlink 'temp' from list */
148
149 /* remove from size-sorted list: */
150 remove_chunksize((char*)temp+sizeof(struct BlockInfo) );
151
152 /* add the upper block's size on ourselves */
153 newsize += temp->info&INFO_SIZE;
154
155 /* add the new, bigger block */
156 add_blocktolists(block, newblock, newsize);
157 return;
158 }
159 }
160
161 blockHead = newblock;
162 newblock->higher = temp;
163 newblock->lower = NULL; /* there is no lower one */
164 if(newblock->higher)
165 newblock->higher->lower = newblock;
166 }
167
168 newblock->info = newsize | INFO_FREE; /* we do assume size isn't using the
169 FREE bit */
170 insert_bysize((char *)newblock+sizeof(struct BlockInfo), newsize);
171}
172
173/***********************************************************************
174 *
175 * findblockbyaddr()
176 *
177 * Find the block that is just before the input block in memory. Returns NULL
178 * if none is.
179 *
180 ***********************************************************************/
181
182static struct BlockInfo *findblockbyaddr(struct BlockInfo *block)
183{
184 struct BlockInfo *test = blockHead;
185 struct BlockInfo *lower = NULL;
186
187 while(test && (test < block)) {
188 lower = test;
189 test = test->higher;
190 }
191 return lower;
192}
193
194/***********************************************************************
195 *
196 * add_pool()
197 *
198 * This function should be the absolutely first function to call. It sets up
199 * the memory bounds of the [first] CHUNK(s). It should be possible to call
200 * this function several times to add more CHUNKs to the pool of free
201 * memory. This allows the bmalloc system to deal with a non-contigous memory
202 * area.
203 *
204 * Returns non-zero if an error occured. The memory was not added then.
205 *
206 ***********************************************************************/
207
208int add_pool(void *start,
209 size_t size)
210{
211 struct BlockInfo *newblock = (struct BlockInfo *)start;
212 struct BlockInfo *block;
213
214 if(size < BMEM_ALIGN)
215 return BMEMERR_TOOSMALL;
216
217 block = findblockbyaddr( newblock );
218 /* `block' is now a lower address than 'newblock' or NULL */
219
220 if(size&1)
221 size--; /* only add even sizes */
222
223 add_blocktolists(block, newblock, size);
224
225 return 0;
226}
227
228
229#ifdef DEBUG
230static void bmalloc_failed(size_t size)
231{
232 printf("*** " __FILE__ " Couldn't allocate %d bytes\n", size);
233 print_lists();
234}
235#else
236#define bmalloc_failed(x)
237#endif
238
239void print_lists()
240{
241 struct BlockInfo *block = blockHead;
242#if 1
243 printf("List of BLOCKS (in address order):\n");
244 while(block) {
245 printf(" START %p END %p SIZE %ld FLAG %s\n",
246 (char *)block,
247 (char *)block+(block->info&INFO_SIZE), block->info&INFO_SIZE,
248 (block->info&INFO_FREE)?"free":"used");
249 block = block->higher;
250 }
251 printf("End of BLOCKS:\n");
252#endif
253 print_sizes();
254}
255
256void *bmalloc(size_t size)
257{
258 void *mem;
259
260#ifdef DEBUG
261 {
262 static int count=0;
263 int realsize = size + sizeof(struct BlockInfo);
264 if(realsize%4096)
265 realsize = ((size / BMEM_ALIGN)+1) * BMEM_ALIGN;
266 printf("%d bmalloc(%d) [%d]\n", count++, size, realsize);
267 }
268#endif
269
270 size += sizeof(struct BlockInfo); /* add memory for our header */
271
272 if(size&(BMEM_ALIGN-1)) /* a lot faster than %BMEM_ALIGN but this MUST be
273 changed if the BLOCKSIZE is not 2^X ! */
274 size = ((size / BMEM_ALIGN)+1) * BMEM_ALIGN; /* align like this */
275
276 /* get a CHUNK from the list with this size */
277 mem = obtainbysize ( size );
278 if(mem) {
279 /* the memory block we have got is the "best-fit" and it is already
280 un-linked from the free list */
281
282 /* now do the math to get the proper block pointer */
283 struct BlockInfo *block= (struct BlockInfo *)
284 ((char *)mem - sizeof(struct BlockInfo));
285
286 block->info &= ~INFO_FREE;
287 /* not free anymore */
288
289 if( size != (block->info&INFO_SIZE)) {
290 /* split this chunk into two pieces and return the one that fits us */
291 size_t othersize = (block->info&INFO_SIZE) - size;
292
293 if(othersize > BMEM_ALIGN) {
294 /* prevent losing small pieces of memory due to weird alignments
295 of the memory pool */
296
297 block->info = size; /* set new size (leave FREE bit cleared) */
298
299 /* Add the new chunk to the lists: */
300 add_blocktolists(block,
301 (struct BlockInfo *)((char *)block + size),
302 othersize );
303 }
304 }
305
306 /* Return the memory our parent may use: */
307 return (char *)block+sizeof(struct BlockInfo);
308 }
309 else {
310 bmalloc_failed(size);
311 return NULL; /* can't find any memory, fail hard */
312 }
313 return NULL;
314}
315
316void bfree(void *ptr)
317{
318 struct BlockInfo *block = (struct BlockInfo *)
319 ((char *)ptr - sizeof(struct BlockInfo));
320 size_t size;
321
322 /* setup our initial higher and lower pointers */
323 struct BlockInfo *lower = block->lower;
324 struct BlockInfo *higher = block->higher;
325
326#ifdef DEBUG
327 static int freecount=0;
328 printf("%d bfree(%p)\n", freecount++, ptr);
329#endif
330
331 /* bind together lower addressed FREE CHUNKS */
332 if(lower && (lower->info&INFO_FREE) &&
333 ((char *)lower + (lower->info&INFO_SIZE) == (char *)block)) {
334 size = block->info&INFO_SIZE; /* original size */
335
336 /* remove from size-link: */
337 remove_chunksize((char *)lower+sizeof(struct BlockInfo));
338
339 remove_block(block); /* unlink from address list */
340 block = lower; /* new base area pointer */
341 block->info += size; /* append the new size (the FREE bit
342 will remain untouched) */
343
344 lower = lower->lower; /* new lower pointer */
345 }
346 /* bind together higher addressed FREE CHUNKS */
347 if(higher && (higher->info&INFO_FREE) &&
348 ((char *)block + (block->info&INFO_SIZE) == (char *)higher)) {
349 /* append higher size, the FREE bit won't be affected */
350 block->info += (higher->info&INFO_SIZE);
351
352 /* unlink from size list: */
353 remove_chunksize((char *)higher+sizeof(struct BlockInfo));
354 remove_block(higher); /* unlink from address list */
355 higher = higher->higher; /* the new higher link */
356 block->higher = higher; /* new higher link */
357 }
358 block->info |= INFO_FREE; /* consider this FREE! */
359
360 block->lower = lower;
361 block->higher = higher;
362
363 insert_bysize((char *)block+sizeof(struct BlockInfo), block->info&INFO_SIZE);
364
365#ifdef DEBUG
366 print_lists();
367#endif
368
369}
370
371/*****************************************************************************
372 *
373 * Big (best-fit) Memory Allocation
374 *
375 * Author: Daniel Stenberg
376 * Date: March 5, 1997
377 * Version: 2.0
378 * Email: Daniel.Stenberg@sth.frontec.se
379 *
380 *
381 * Read 'thoughts' for theories and details in implementation.
382 *
383 * Routines meant to replace the most low level functions of an Operting
384 * System
385 *
386 * v2.0
387 * - Made all size-routines get moved out from this file. This way, the size
388 * functions can much more easily get replaced.
389 * - Improved how new memory blocks get added to the size-sorted list. When
390 * not adding new pools, there should never ever be any list traversing
391 * since all information is dynamically gathered.
392 *
393 ****************************************************************************/
394
395#include <stdio.h>
396#include <stdlib.h>
397
398#include "bysize.h"
399
400#ifndef TRUE
401#define TRUE 1
402#endif
403#ifndef FALSE
404#define FALSE 0
405#endif
406
407/* #define DEBUG */
408
409#define BMEM_ALIGN 64 /* resolution */
410
411#define BMEMERR_TOOSMALL -1
412
413/* this struct will be stored in all CHUNKS and AREAS */
414struct BlockInfo {
415 struct BlockInfo *lower; /* previous block in memory (lower address) */
416 struct BlockInfo *higher; /* next block in memory (higher address) */
417 unsigned long info; /* 31 bits size: 1 bit free boolean */
418#define INFO_FREE 1
419#define INFO_SIZE (~ INFO_FREE) /* inverted FREE bit pattern */
420
421 /* FREE+SIZE Could be written to use ordinary bitfields if using a smart
422 (like gcc) compiler in a manner like:
423 int size:31;
424 int free:1;
425
426 The 'higher' pointer COULD be removed completely if the size is used as
427 an index to the higher one. This would then REQUIRE the entire memory
428 pool to be contiguous and it needs a 'terminating' "node" or an extra
429 flag that informs about the end of the list.
430 */
431};
432
433/* the BLOCK list should be sorted in a lower to higher address order */
434struct BlockInfo *blockHead=NULL; /* nothing from the start */
435
436void print_lists(void);
437
438
439/***********************************************************************
440 *
441 * remove_block()
442 *
443 * Remove the block from the address-sorted list.
444 *
445 ***********************************************************************/
446
447void remove_block(struct BlockInfo *block)
448{
449 if(block->lower)
450 block->lower->higher = block->higher;
451 else
452 blockHead = block->higher;
453 if(block->higher)
454 block->higher->lower = block->lower;
455}
456
457/****************************************************************************
458 *
459 * add_blocktolists()
460 *
461 * Adds the specified block at the specified place in the address-sorted
462 * list and at the appropriate place in the size-sorted.
463 *
464 ***************************************************************************/
465void add_blocktolists(struct BlockInfo *block,
466 struct BlockInfo *newblock,
467 size_t newsize)
468{
469 struct BlockInfo *temp; /* temporary storage variable */
470 if(block) {
471 /* `block' is now a lower address than 'newblock' */
472
473 /*
474 * Check if the new CHUNK is wall-to-wall with the lower addressed
475 * one (if *that* is free)
476 */
477 if(block->info&INFO_FREE) {
478 if((char *)block + (block->info&INFO_SIZE) == (char *)newblock) {
479 /* yes sir, this is our lower address neighbour, enlarge that one
480 pick it out from the list and recursively add that chunk and
481 then we escape */
482
483 /* remove from size-sorted list: */
484 remove_chunksize((char*)block+sizeof(struct BlockInfo));
485
486 block->info += newsize; /* newsize is an even number and thus the FREE
487 bit is untouched */
488
489 remove_block(block); /* unlink the block address-wise */
490
491 /* recursively check our lower friend(s) */
492 add_blocktolists(block->lower, block, block->info&INFO_SIZE);
493 return;
494 }
495 }
496
497 temp = block->higher;
498
499 block->higher = newblock;
500 newblock->lower = block;
501 newblock->higher = temp;
502 if(newblock->higher)
503 newblock->higher->lower = newblock;
504 }
505 else {
506 /* this block should preceed the heading one */
507 temp = blockHead;
508
509 /* check if this is our higher addressed neighbour */
510 if((char *)newblock + newsize == (char *)temp) {
511
512 /* yes, we are wall-to-wall with the higher CHUNK */
513 if(temp->info&INFO_FREE) {
514 /* and the neighbour is even free, remove that one and enlarge
515 ourselves, call add_pool() recursively and then escape */
516
517 remove_block(temp); /* unlink 'temp' from list */
518
519 /* remove from size-sorted list: */
520 remove_chunksize((char*)temp+sizeof(struct BlockInfo) );
521
522 /* add the upper block's size on ourselves */
523 newsize += temp->info&INFO_SIZE;
524
525 /* add the new, bigger block */
526 add_blocktolists(block, newblock, newsize);
527 return;
528 }
529 }
530
531 blockHead = newblock;
532 newblock->higher = temp;
533 newblock->lower = NULL; /* there is no lower one */
534 if(newblock->higher)
535 newblock->higher->lower = newblock;
536 }
537
538 newblock->info = newsize | INFO_FREE; /* we do assume size isn't using the
539 FREE bit */
540 insert_bysize((char *)newblock+sizeof(struct BlockInfo), newsize);
541}
542
543/***********************************************************************
544 *
545 * findblockbyaddr()
546 *
547 * Find the block that is just before the input block in memory. Returns NULL
548 * if none is.
549 *
550 ***********************************************************************/
551
552static struct BlockInfo *findblockbyaddr(struct BlockInfo *block)
553{
554 struct BlockInfo *test = blockHead;
555 struct BlockInfo *lower = NULL;
556
557 while(test && (test < block)) {
558 lower = test;
559 test = test->higher;
560 }
561 return lower;
562}
563
564/***********************************************************************
565 *
566 * add_pool()
567 *
568 * This function should be the absolutely first function to call. It sets up
569 * the memory bounds of the [first] CHUNK(s). It should be possible to call
570 * this function several times to add more CHUNKs to the pool of free
571 * memory. This allows the bmalloc system to deal with a non-contigous memory
572 * area.
573 *
574 * Returns non-zero if an error occured. The memory was not added then.
575 *
576 ***********************************************************************/
577
578int add_pool(void *start,
579 size_t size)
580{
581 struct BlockInfo *newblock = (struct BlockInfo *)start;
582 struct BlockInfo *block;
583
584 if(size < BMEM_ALIGN)
585 return BMEMERR_TOOSMALL;
586
587 block = findblockbyaddr( newblock );
588 /* `block' is now a lower address than 'newblock' or NULL */
589
590 if(size&1)
591 size--; /* only add even sizes */
592
593 add_blocktolists(block, newblock, size);
594
595 return 0;
596}
597
598
599#ifdef DEBUG
600static void bmalloc_failed(size_t size)
601{
602 printf("*** " __FILE__ " Couldn't allocate %d bytes\n", size);
603 print_lists();
604}
605#else
606#define bmalloc_failed(x)
607#endif
608
609void print_lists()
610{
611 struct BlockInfo *block = blockHead;
612#if 1
613 printf("List of BLOCKS (in address order):\n");
614 while(block) {
615 printf(" START %p END %p SIZE %ld FLAG %s\n",
616 (char *)block,
617 (char *)block+(block->info&INFO_SIZE), block->info&INFO_SIZE,
618 (block->info&INFO_FREE)?"free":"used");
619 block = block->higher;
620 }
621 printf("End of BLOCKS:\n");
622#endif
623 print_sizes();
624}
625
626void *bmalloc(size_t size)
627{
628 void *mem;
629
630#ifdef DEBUG
631 {
632 static int count=0;
633 int realsize = size + sizeof(struct BlockInfo);
634 if(realsize%4096)
635 realsize = ((size / BMEM_ALIGN)+1) * BMEM_ALIGN;
636 printf("%d bmalloc(%d) [%d]\n", count++, size, realsize);
637 }
638#endif
639
640 size += sizeof(struct BlockInfo); /* add memory for our header */
641
642 if(size&(BMEM_ALIGN-1)) /* a lot faster than %BMEM_ALIGN but this MUST be
643 changed if the BLOCKSIZE is not 2^X ! */
644 size = ((size / BMEM_ALIGN)+1) * BMEM_ALIGN; /* align like this */
645
646 /* get a CHUNK from the list with this size */
647 mem = obtainbysize ( size );
648 if(mem) {
649 /* the memory block we have got is the "best-fit" and it is already
650 un-linked from the free list */
651
652 /* now do the math to get the proper block pointer */
653 struct BlockInfo *block= (struct BlockInfo *)
654 ((char *)mem - sizeof(struct BlockInfo));
655
656 block->info &= ~INFO_FREE;
657 /* not free anymore */
658
659 if( size != (block->info&INFO_SIZE)) {
660 /* split this chunk into two pieces and return the one that fits us */
661 size_t othersize = (block->info&INFO_SIZE) - size;
662
663 if(othersize > BMEM_ALIGN) {
664 /* prevent losing small pieces of memory due to weird alignments
665 of the memory pool */
666
667 block->info = size; /* set new size (leave FREE bit cleared) */
668
669 /* Add the new chunk to the lists: */
670 add_blocktolists(block,
671 (struct BlockInfo *)((char *)block + size),
672 othersize );
673 }
674 }
675
676 /* Return the memory our parent may use: */
677 return (char *)block+sizeof(struct BlockInfo);
678 }
679 else {
680 bmalloc_failed(size);
681 return NULL; /* can't find any memory, fail hard */
682 }
683 return NULL;
684}
685
686void bfree(void *ptr)
687{
688 struct BlockInfo *block = (struct BlockInfo *)
689 ((char *)ptr - sizeof(struct BlockInfo));
690 size_t size;
691
692 /* setup our initial higher and lower pointers */
693 struct BlockInfo *lower = block->lower;
694 struct BlockInfo *higher = block->higher;
695
696#ifdef DEBUG
697 static int freecount=0;
698 printf("%d bfree(%p)\n", freecount++, ptr);
699#endif
700
701 /* bind together lower addressed FREE CHUNKS */
702 if(lower && (lower->info&INFO_FREE) &&
703 ((char *)lower + (lower->info&INFO_SIZE) == (char *)block)) {
704 size = block->info&INFO_SIZE; /* original size */
705
706 /* remove from size-link: */
707 remove_chunksize((char *)lower+sizeof(struct BlockInfo));
708
709 remove_block(block); /* unlink from address list */
710 block = lower; /* new base area pointer */
711 block->info += size; /* append the new size (the FREE bit
712 will remain untouched) */
713
714 lower = lower->lower; /* new lower pointer */
715 }
716 /* bind together higher addressed FREE CHUNKS */
717 if(higher && (higher->info&INFO_FREE) &&
718 ((char *)block + (block->info&INFO_SIZE) == (char *)higher)) {
719 /* append higher size, the FREE bit won't be affected */
720 block->info += (higher->info&INFO_SIZE);
721
722 /* unlink from size list: */
723 remove_chunksize((char *)higher+sizeof(struct BlockInfo));
724 remove_block(higher); /* unlink from address list */
725 higher = higher->higher; /* the new higher link */
726 block->higher = higher; /* new higher link */
727 }
728 block->info |= INFO_FREE; /* consider this FREE! */
729
730 block->lower = lower;
731 block->higher = higher;
732
733 insert_bysize((char *)block+sizeof(struct BlockInfo), block->info&INFO_SIZE);
734
735#ifdef DEBUG
736 print_lists();
737#endif
738
739}
740
diff --git a/apps/plugins/pdbox/dbestfit-3.3/bmalloc.h b/apps/plugins/pdbox/dbestfit-3.3/bmalloc.h
new file mode 100644
index 0000000000..4f77667290
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/bmalloc.h
@@ -0,0 +1,12 @@
1int add_pool(void *start, size_t size);
2void print_lists();
3
4void *bmalloc(size_t size);
5void bfree(void *ptr);
6
7int add_pool(void *start, size_t size);
8void print_lists();
9
10void *bmalloc(size_t size);
11void bfree(void *ptr);
12
diff --git a/apps/plugins/pdbox/dbestfit-3.3/bysize.c b/apps/plugins/pdbox/dbestfit-3.3/bysize.c
new file mode 100644
index 0000000000..6808406dbc
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/bysize.c
@@ -0,0 +1,848 @@
1/*****************************************************************************
2 *
3 * Size-sorted list/tree functions.
4 *
5 * Author: Daniel Stenberg
6 * Date: March 7, 1997
7 * Version: 2.0
8 * Email: Daniel.Stenberg@sth.frontec.se
9 *
10 *
11 * v2.0
12 * - Added SPLAY TREE functionality.
13 *
14 * Adds and removes CHUNKS from a list or tree.
15 *
16 ****************************************************************************/
17
18#include <stdio.h>
19#include <stdlib.h>
20
21#define SPLAY /* we use the splay version as that is much faster */
22
23#ifndef TRUE
24#define TRUE 1
25#endif
26#ifndef FALSE
27#define FALSE 0
28#endif
29
30#ifndef SPLAY /* these routines are for the non-splay version */
31
32struct ChunkInfo {
33 struct ChunkInfo *larger;
34 struct ChunkInfo *smaller;
35 size_t size;
36};
37
38/* the CHUNK list anchor */
39struct ChunkInfo *chunkHead=NULL;
40
41/***********************************************************************
42
43 findchunkbysize()
44
45 Find the chunk that is smaller than the input size. Returns
46 NULL if none is.
47
48 **********************************************************************/
49
50static struct ChunkInfo *findchunkbysize(size_t size)
51{
52 struct ChunkInfo *test = chunkHead;
53 struct ChunkInfo *smaller = NULL;
54 while(test && (test->size < size)) {
55 smaller = test;
56 test = test->larger;
57 }
58 return smaller;
59}
60
61/***********************************************************************
62
63 remove_chunksize()
64
65 Remove the chunk from the size-sorted list.
66 ***********************************************************************/
67
68void remove_chunksize(void *data)
69{
70 struct ChunkInfo *chunk = (struct ChunkInfo *)data;
71 if(chunk->smaller)
72 chunk->smaller->larger = chunk->larger;
73 else {
74 /* if this has no smaller, this is the head */
75 chunkHead = chunk->larger; /* new head */
76 }
77 if(chunk->larger)
78 chunk->larger->smaller = chunk->smaller;
79}
80
81void insert_bysize(char *data, size_t size)
82{
83 struct ChunkInfo *newchunk = (struct ChunkInfo *)data;
84 struct ChunkInfo *chunk = findchunkbysize ( size );
85
86 newchunk->size = size;
87
88 if(chunk) {
89 /* 'chunk' is smaller than size, append the new chunk ahead of this */
90 newchunk->smaller = chunk;
91 newchunk->larger = chunk->larger;
92 if(chunk->larger)
93 chunk->larger->smaller = newchunk;
94 chunk->larger = newchunk;
95 }
96 else {
97 /* smallest CHUNK around, append first in the list */
98 newchunk->larger = chunkHead;
99 newchunk->smaller = NULL;
100
101 if(chunkHead)
102 chunkHead->smaller = newchunk;
103 chunkHead = newchunk;
104 }
105}
106
107char *obtainbysize( size_t size)
108{
109 struct ChunkInfo *chunk = findchunkbysize( size );
110
111 if(!chunk) {
112 if(size <= (chunkHead->size))
113 /* there is no smaller CHUNK, use the first one (if we fit within that)
114 */
115 chunk = chunkHead;
116 }
117 else
118 /* we're on the last CHUNK that is smaller than requested, step onto
119 the bigger one */
120 chunk = chunk->larger;
121
122 if(chunk) {
123 remove_chunksize( chunk ); /* unlink size-wise */
124 return (char *)chunk;
125 }
126 else
127 return NULL;
128}
129
130void print_sizes(void)
131{
132 struct ChunkInfo *chunk = chunkHead;
133 printf("List of CHUNKS (in size order):\n");
134#if 1
135 while(chunk) {
136 printf(" START %p END %p SIZE %d\n",
137 chunk, (char *)chunk+chunk->size, chunk->size);
138 chunk = chunk->larger;
139 }
140#endif
141 printf("End of CHUNKS:\n");
142}
143
144#else /* Here follows all routines dealing with the SPLAY TREES */
145
146typedef struct tree_node Tree;
147struct tree_node {
148 Tree *smaller; /* smaller node */
149 Tree *larger; /* larger node */
150 Tree *same; /* points to a node with identical key */
151 int key; /* the "sort" key */
152};
153
154Tree *chunkHead = NULL; /* the root */
155
156#define compare(i,j) ((i)-(j))
157
158/* Set this to a key value that will *NEVER* appear otherwise */
159#define KEY_NOTUSED -1
160
161/*
162 * Splay using the key i (which may or may not be in the tree.) The starting
163 * root is t. Weight fields are maintained.
164 */
165Tree * splay (int i, Tree *t)
166{
167 Tree N, *l, *r, *y;
168 int comp;
169
170 if (t == NULL)
171 return t;
172 N.smaller = N.larger = NULL;
173 l = r = &N;
174
175 for (;;) {
176 comp = compare(i, t->key);
177 if (comp < 0) {
178 if (t->smaller == NULL)
179 break;
180 if (compare(i, t->smaller->key) < 0) {
181 y = t->smaller; /* rotate smaller */
182 t->smaller = y->larger;
183 y->larger = t;
184
185 t = y;
186 if (t->smaller == NULL)
187 break;
188 }
189 r->smaller = t; /* link smaller */
190 r = t;
191 t = t->smaller;
192 }
193 else if (comp > 0) {
194 if (t->larger == NULL)
195 break;
196 if (compare(i, t->larger->key) > 0) {
197 y = t->larger; /* rotate larger */
198 t->larger = y->smaller;
199 y->smaller = t;
200 t = y;
201 if (t->larger == NULL)
202 break;
203 }
204 l->larger = t; /* link larger */
205 l = t;
206 t = t->larger;
207 }
208 else {
209 break;
210 }
211 }
212
213 l->larger = r->smaller = NULL;
214
215 l->larger = t->smaller; /* assemble */
216 r->smaller = t->larger;
217 t->smaller = N.larger;
218 t->larger = N.smaller;
219
220 return t;
221}
222
223/* Insert key i into the tree t. Return a pointer to the resulting tree or
224 NULL if something went wrong. */
225Tree *insert(int i, Tree *t, Tree *new)
226{
227 if (new == NULL) {
228 return t;
229 }
230
231 if (t != NULL) {
232 t = splay(i,t);
233 if (compare(i, t->key)==0) {
234 /* it already exists one of this size */
235
236 new->same = t;
237 new->key = i;
238 new->smaller = t->smaller;
239 new->larger = t->larger;
240
241 t->smaller = new;
242 t->key = KEY_NOTUSED;
243
244 return new; /* new root node */
245 }
246 }
247
248 if (t == NULL) {
249 new->smaller = new->larger = NULL;
250 }
251 else if (compare(i, t->key) < 0) {
252 new->smaller = t->smaller;
253 new->larger = t;
254 t->smaller = NULL;
255 }
256 else {
257 new->larger = t->larger;
258 new->smaller = t;
259 t->larger = NULL;
260 }
261 new->key = i;
262
263 new->same = NULL; /* no identical node (yet) */
264
265 return new;
266}
267
268/* Finds and deletes the best-fit node from the tree. Return a pointer to the
269 resulting tree. best-fit means the smallest node that fits the requested
270 size. */
271Tree *removebestfit(int i, Tree *t, Tree **removed)
272{
273 Tree *x;
274
275 if (t==NULL)
276 return NULL;
277 t = splay(i,t);
278 if(compare(i, t->key) > 0) {
279 /* too small node, try the larger chain */
280 if(t->larger)
281 t=splay(t->larger->key, t);
282 else {
283 /* fail */
284 *removed = NULL;
285 return t;
286 }
287 }
288
289 if (compare(i, t->key) <= 0) { /* found it */
290
291 /* FIRST! Check if there is a list with identical sizes */
292 x = t->same;
293 if(x) {
294 /* there is, pick one from the list */
295
296 /* 'x' is the new root node */
297
298 x->key = t->key;
299 x->larger = t->larger;
300 x->smaller = t->smaller;
301 *removed = t;
302 return x; /* new root */
303 }
304
305 if (t->smaller == NULL) {
306 x = t->larger;
307 }
308 else {
309 x = splay(i, t->smaller);
310 x->larger = t->larger;
311 }
312 *removed = t;
313
314 return x;
315 }
316 else {
317 *removed = NULL; /* no match */
318 return t; /* It wasn't there */
319 }
320}
321
322
323/* Deletes the node we point out from the tree if it's there. Return a pointer
324 to the resulting tree. */
325Tree *removebyaddr(Tree *t, Tree *remove)
326{
327 Tree *x;
328
329 if (!t || !remove)
330 return NULL;
331
332 if(KEY_NOTUSED == remove->key) {
333 /* just unlink ourselves nice and quickly: */
334 remove->smaller->same = remove->same;
335 if(remove->same)
336 remove->same->smaller = remove->smaller;
337 /* voila, we're done! */
338 return t;
339 }
340
341 t = splay(remove->key,t);
342
343 /* Check if there is a list with identical sizes */
344
345 x = t->same;
346 if(x) {
347 /* 'x' is the new root node */
348
349 x->key = t->key;
350 x->larger = t->larger;
351 x->smaller = t->smaller;
352
353 return x; /* new root */
354 }
355
356 /* Remove the actualy root node: */
357
358 if (t->smaller == NULL) {
359 x = t->larger;
360 }
361 else {
362 x = splay(remove->key, t->smaller);
363 x->larger = t->larger;
364 }
365
366 return x;
367}
368
369int printtree(Tree * t, int d, char output)
370{
371 int distance=0;
372 Tree *node;
373 int i;
374 if (t == NULL)
375 return 0;
376 distance += printtree(t->larger, d+1, output);
377 for (i=0; i<d; i++)
378 if(output)
379 printf(" ");
380
381 if(output) {
382 printf("%d[%d]", t->key, i);
383 }
384
385 for(node = t->same; node; node = node->same) {
386 distance += i; /* this has the same "virtual" distance */
387
388 if(output)
389 printf(" [+]");
390 }
391 if(output)
392 puts("");
393
394 distance += i;
395 distance += printtree(t->smaller, d+1, output);
396 return distance;
397}
398
399/* Here follow the look-alike interface so that the tree-function names are
400 the same as the list-ones to enable easy interchange */
401
402void remove_chunksize(void *data)
403{
404 chunkHead = removebyaddr(chunkHead, data);
405}
406
407void insert_bysize(char *data, size_t size)
408{
409 chunkHead = insert(size, chunkHead, (Tree *)data);
410}
411
412char *obtainbysize( size_t size)
413{
414 Tree *receive;
415 chunkHead = removebestfit(size, chunkHead, &receive);
416 return (char *)receive;
417}
418
419void print_sizes(void)
420{
421 printtree(chunkHead, 0, 1);
422}
423
424#endif
425/*****************************************************************************
426 *
427 * Size-sorted list/tree functions.
428 *
429 * Author: Daniel Stenberg
430 * Date: March 7, 1997
431 * Version: 2.0
432 * Email: Daniel.Stenberg@sth.frontec.se
433 *
434 *
435 * v2.0
436 * - Added SPLAY TREE functionality.
437 *
438 * Adds and removes CHUNKS from a list or tree.
439 *
440 ****************************************************************************/
441
442#include <stdio.h>
443#include <stdlib.h>
444
445#define SPLAY /* we use the splay version as that is much faster */
446
447#ifndef TRUE
448#define TRUE 1
449#endif
450#ifndef FALSE
451#define FALSE 0
452#endif
453
454#ifndef SPLAY /* these routines are for the non-splay version */
455
456struct ChunkInfo {
457 struct ChunkInfo *larger;
458 struct ChunkInfo *smaller;
459 size_t size;
460};
461
462/* the CHUNK list anchor */
463struct ChunkInfo *chunkHead=NULL;
464
465/***********************************************************************
466
467 findchunkbysize()
468
469 Find the chunk that is smaller than the input size. Returns
470 NULL if none is.
471
472 **********************************************************************/
473
474static struct ChunkInfo *findchunkbysize(size_t size)
475{
476 struct ChunkInfo *test = chunkHead;
477 struct ChunkInfo *smaller = NULL;
478 while(test && (test->size < size)) {
479 smaller = test;
480 test = test->larger;
481 }
482 return smaller;
483}
484
485/***********************************************************************
486
487 remove_chunksize()
488
489 Remove the chunk from the size-sorted list.
490 ***********************************************************************/
491
492void remove_chunksize(void *data)
493{
494 struct ChunkInfo *chunk = (struct ChunkInfo *)data;
495 if(chunk->smaller)
496 chunk->smaller->larger = chunk->larger;
497 else {
498 /* if this has no smaller, this is the head */
499 chunkHead = chunk->larger; /* new head */
500 }
501 if(chunk->larger)
502 chunk->larger->smaller = chunk->smaller;
503}
504
505void insert_bysize(char *data, size_t size)
506{
507 struct ChunkInfo *newchunk = (struct ChunkInfo *)data;
508 struct ChunkInfo *chunk = findchunkbysize ( size );
509
510 newchunk->size = size;
511
512 if(chunk) {
513 /* 'chunk' is smaller than size, append the new chunk ahead of this */
514 newchunk->smaller = chunk;
515 newchunk->larger = chunk->larger;
516 if(chunk->larger)
517 chunk->larger->smaller = newchunk;
518 chunk->larger = newchunk;
519 }
520 else {
521 /* smallest CHUNK around, append first in the list */
522 newchunk->larger = chunkHead;
523 newchunk->smaller = NULL;
524
525 if(chunkHead)
526 chunkHead->smaller = newchunk;
527 chunkHead = newchunk;
528 }
529}
530
531char *obtainbysize( size_t size)
532{
533 struct ChunkInfo *chunk = findchunkbysize( size );
534
535 if(!chunk) {
536 if(size <= (chunkHead->size))
537 /* there is no smaller CHUNK, use the first one (if we fit within that)
538 */
539 chunk = chunkHead;
540 }
541 else
542 /* we're on the last CHUNK that is smaller than requested, step onto
543 the bigger one */
544 chunk = chunk->larger;
545
546 if(chunk) {
547 remove_chunksize( chunk ); /* unlink size-wise */
548 return (char *)chunk;
549 }
550 else
551 return NULL;
552}
553
554void print_sizes(void)
555{
556 struct ChunkInfo *chunk = chunkHead;
557 printf("List of CHUNKS (in size order):\n");
558#if 1
559 while(chunk) {
560 printf(" START %p END %p SIZE %d\n",
561 chunk, (char *)chunk+chunk->size, chunk->size);
562 chunk = chunk->larger;
563 }
564#endif
565 printf("End of CHUNKS:\n");
566}
567
568#else /* Here follows all routines dealing with the SPLAY TREES */
569
570typedef struct tree_node Tree;
571struct tree_node {
572 Tree *smaller; /* smaller node */
573 Tree *larger; /* larger node */
574 Tree *same; /* points to a node with identical key */
575 int key; /* the "sort" key */
576};
577
578Tree *chunkHead = NULL; /* the root */
579
580#define compare(i,j) ((i)-(j))
581
582/* Set this to a key value that will *NEVER* appear otherwise */
583#define KEY_NOTUSED -1
584
585/*
586 * Splay using the key i (which may or may not be in the tree.) The starting
587 * root is t. Weight fields are maintained.
588 */
589Tree * splay (int i, Tree *t)
590{
591 Tree N, *l, *r, *y;
592 int comp;
593
594 if (t == NULL)
595 return t;
596 N.smaller = N.larger = NULL;
597 l = r = &N;
598
599 for (;;) {
600 comp = compare(i, t->key);
601 if (comp < 0) {
602 if (t->smaller == NULL)
603 break;
604 if (compare(i, t->smaller->key) < 0) {
605 y = t->smaller; /* rotate smaller */
606 t->smaller = y->larger;
607 y->larger = t;
608
609 t = y;
610 if (t->smaller == NULL)
611 break;
612 }
613 r->smaller = t; /* link smaller */
614 r = t;
615 t = t->smaller;
616 }
617 else if (comp > 0) {
618 if (t->larger == NULL)
619 break;
620 if (compare(i, t->larger->key) > 0) {
621 y = t->larger; /* rotate larger */
622 t->larger = y->smaller;
623 y->smaller = t;
624 t = y;
625 if (t->larger == NULL)
626 break;
627 }
628 l->larger = t; /* link larger */
629 l = t;
630 t = t->larger;
631 }
632 else {
633 break;
634 }
635 }
636
637 l->larger = r->smaller = NULL;
638
639 l->larger = t->smaller; /* assemble */
640 r->smaller = t->larger;
641 t->smaller = N.larger;
642 t->larger = N.smaller;
643
644 return t;
645}
646
647/* Insert key i into the tree t. Return a pointer to the resulting tree or
648 NULL if something went wrong. */
649Tree *insert(int i, Tree *t, Tree *new)
650{
651 if (new == NULL) {
652 return t;
653 }
654
655 if (t != NULL) {
656 t = splay(i,t);
657 if (compare(i, t->key)==0) {
658 /* it already exists one of this size */
659
660 new->same = t;
661 new->key = i;
662 new->smaller = t->smaller;
663 new->larger = t->larger;
664
665 t->smaller = new;
666 t->key = KEY_NOTUSED;
667
668 return new; /* new root node */
669 }
670 }
671
672 if (t == NULL) {
673 new->smaller = new->larger = NULL;
674 }
675 else if (compare(i, t->key) < 0) {
676 new->smaller = t->smaller;
677 new->larger = t;
678 t->smaller = NULL;
679 }
680 else {
681 new->larger = t->larger;
682 new->smaller = t;
683 t->larger = NULL;
684 }
685 new->key = i;
686
687 new->same = NULL; /* no identical node (yet) */
688
689 return new;
690}
691
692/* Finds and deletes the best-fit node from the tree. Return a pointer to the
693 resulting tree. best-fit means the smallest node that fits the requested
694 size. */
695Tree *removebestfit(int i, Tree *t, Tree **removed)
696{
697 Tree *x;
698
699 if (t==NULL)
700 return NULL;
701 t = splay(i,t);
702 if(compare(i, t->key) > 0) {
703 /* too small node, try the larger chain */
704 if(t->larger)
705 t=splay(t->larger->key, t);
706 else {
707 /* fail */
708 *removed = NULL;
709 return t;
710 }
711 }
712
713 if (compare(i, t->key) <= 0) { /* found it */
714
715 /* FIRST! Check if there is a list with identical sizes */
716 x = t->same;
717 if(x) {
718 /* there is, pick one from the list */
719
720 /* 'x' is the new root node */
721
722 x->key = t->key;
723 x->larger = t->larger;
724 x->smaller = t->smaller;
725 *removed = t;
726 return x; /* new root */
727 }
728
729 if (t->smaller == NULL) {
730 x = t->larger;
731 }
732 else {
733 x = splay(i, t->smaller);
734 x->larger = t->larger;
735 }
736 *removed = t;
737
738 return x;
739 }
740 else {
741 *removed = NULL; /* no match */
742 return t; /* It wasn't there */
743 }
744}
745
746
747/* Deletes the node we point out from the tree if it's there. Return a pointer
748 to the resulting tree. */
749Tree *removebyaddr(Tree *t, Tree *remove)
750{
751 Tree *x;
752
753 if (!t || !remove)
754 return NULL;
755
756 if(KEY_NOTUSED == remove->key) {
757 /* just unlink ourselves nice and quickly: */
758 remove->smaller->same = remove->same;
759 if(remove->same)
760 remove->same->smaller = remove->smaller;
761 /* voila, we're done! */
762 return t;
763 }
764
765 t = splay(remove->key,t);
766
767 /* Check if there is a list with identical sizes */
768
769 x = t->same;
770 if(x) {
771 /* 'x' is the new root node */
772
773 x->key = t->key;
774 x->larger = t->larger;
775 x->smaller = t->smaller;
776
777 return x; /* new root */
778 }
779
780 /* Remove the actualy root node: */
781
782 if (t->smaller == NULL) {
783 x = t->larger;
784 }
785 else {
786 x = splay(remove->key, t->smaller);
787 x->larger = t->larger;
788 }
789
790 return x;
791}
792
793int printtree(Tree * t, int d, char output)
794{
795 int distance=0;
796 Tree *node;
797 int i;
798 if (t == NULL)
799 return 0;
800 distance += printtree(t->larger, d+1, output);
801 for (i=0; i<d; i++)
802 if(output)
803 printf(" ");
804
805 if(output) {
806 printf("%d[%d]", t->key, i);
807 }
808
809 for(node = t->same; node; node = node->same) {
810 distance += i; /* this has the same "virtual" distance */
811
812 if(output)
813 printf(" [+]");
814 }
815 if(output)
816 puts("");
817
818 distance += i;
819 distance += printtree(t->smaller, d+1, output);
820 return distance;
821}
822
823/* Here follow the look-alike interface so that the tree-function names are
824 the same as the list-ones to enable easy interchange */
825
826void remove_chunksize(void *data)
827{
828 chunkHead = removebyaddr(chunkHead, data);
829}
830
831void insert_bysize(char *data, size_t size)
832{
833 chunkHead = insert(size, chunkHead, (Tree *)data);
834}
835
836char *obtainbysize( size_t size)
837{
838 Tree *receive;
839 chunkHead = removebestfit(size, chunkHead, &receive);
840 return (char *)receive;
841}
842
843void print_sizes(void)
844{
845 printtree(chunkHead, 0, 1);
846}
847
848#endif
diff --git a/apps/plugins/pdbox/dbestfit-3.3/bysize.h b/apps/plugins/pdbox/dbestfit-3.3/bysize.h
new file mode 100644
index 0000000000..2fbf23154d
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/bysize.h
@@ -0,0 +1,8 @@
1void remove_chunksize(void *data);
2void insert_bysize(char *data, size_t size);
3char *obtainbysize( size_t size);
4void print_sizes(void);
5void remove_chunksize(void *data);
6void insert_bysize(char *data, size_t size);
7char *obtainbysize( size_t size);
8void print_sizes(void);
diff --git a/apps/plugins/pdbox/dbestfit-3.3/dmalloc.c b/apps/plugins/pdbox/dbestfit-3.3/dmalloc.c
new file mode 100644
index 0000000000..9336276883
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/dmalloc.c
@@ -0,0 +1,1380 @@
1/*****************************************************************************
2 *
3 * Dynamic Memory Allocation
4 *
5 * Author: Daniel Stenberg
6 * Date: March 10, 1997
7 * Version: 2.3
8 * Email: Daniel.Stenberg@sth.frontec.se
9 *
10 *
11 * Read 'thoughts' for theories and details of this implementation.
12 *
13 * v2.1
14 * - I once again managed to gain some memory. BLOCK allocations now only use
15 * a 4 bytes header (instead of previos 8) just as FRAGMENTS.
16 *
17 * v2.2
18 * - Re-adjusted the fragment sizes to better fit into the somewhat larger
19 * block.
20 *
21 * v2.3
22 * - Made realloc(NULL, size) work as it should. Which is like a malloc(size)
23 *
24 *****************************************************************************/
25
26#include <stdio.h>
27#include <string.h>
28
29#ifdef DEBUG
30#include <stdarg.h>
31#endif
32
33#ifdef PSOS
34#include <psos.h>
35#define SEMAPHORE /* the PSOS routines use semaphore protection */
36#else
37#include <stdlib.h> /* makes the PSOS complain on the 'size_t' typedef */
38#endif
39
40#ifdef BMALLOC
41#include "bmalloc.h"
42#endif
43
44/* Each TOP takes care of a chain of BLOCKS */
45struct MemTop {
46 struct MemBlock *chain; /* pointer to the BLOCK chain */
47 long nfree; /* total number of free FRAGMENTS in the chain */
48 short nmax; /* total number of FRAGMENTS in this kind of BLOCK */
49 size_t fragsize; /* the size of each FRAGMENT */
50
51#ifdef SEMAPHORE /* if we're protecting the list with SEMAPHORES */
52 long semaphore_id; /* semaphore used to lock this particular list */
53#endif
54
55};
56
57/* Each BLOCK takes care of an amount of FRAGMENTS */
58struct MemBlock {
59 struct MemTop *top; /* our TOP struct */
60 struct MemBlock *next; /* next BLOCK */
61 struct MemBlock *prev; /* prev BLOCK */
62
63 struct MemFrag *first; /* the first free FRAGMENT in this block */
64
65 short nfree; /* number of free FRAGMENTS in this BLOCK */
66};
67
68/* This is the data kept in all _free_ FRAGMENTS */
69struct MemFrag {
70 struct MemFrag *next; /* next free FRAGMENT */
71 struct MemFrag *prev; /* prev free FRAGMENT */
72};
73
74/* This is the data kept in all _allocated_ FRAGMENTS and BLOCKS. We add this
75 to the allocation size first thing in the ALLOC function to make room for
76 this smoothly. */
77
78struct MemInfo {
79 void *block;
80 /* which BLOCK is our father, if BLOCK_BIT is set it means this is a
81 stand-alone, large allocation and then the rest of the bits should be
82 treated as the size of the block */
83#define BLOCK_BIT 1
84};
85
86/* ---------------------------------------------------------------------- */
87/* Defines */
88/* ---------------------------------------------------------------------- */
89
90#ifdef DEBUG
91#define MEMINCR(addr,x) memchange(addr, x)
92#define MEMDECR(addr,x) memchange(addr,-(x))
93#else
94#define MEMINCR(a,x)
95#define MEMDECR(a,x)
96#endif
97
98/* The low level functions used to get memory from the OS and to return memory
99 to the OS, we may also define a stub that does the actual allocation and
100 free, these are the defined function names used in the dmalloc system
101 anyway: */
102#ifdef PSOS
103
104#ifdef DEBUG
105#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
106#define DMEM_OSFREEMEM(x) dbgfree(x)
107#else
108#define DMEM_OSALLOCMEM(size,pointer,type) rn_getseg(0,size,RN_NOWAIT,0,(void **)&pointer)
109/* Similar, but this returns the memory */
110#define DMEM_OSFREEMEM(x) rn_retseg(0, x)
111#endif
112
113/* Argument: <id> */
114#define SEMAPHOREOBTAIN(x) sm_p(x, SM_WAIT, 0)
115/* Argument: <id> */
116#define SEMAPHORERETURN(x) sm_v(x)
117/* Argument: <name> <id-variable name> */
118#define SEMAPHORECREATE(x,y) sm_create(x, 1, SM_FIFO, (ULONG *)&(y))
119
120#else
121#ifdef BMALLOC /* use our own big-memory-allocation system */
122#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)bmalloc(size)
123#define DMEM_OSFREEMEM(x) bfree(x)
124#elif DEBUG
125#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
126#define DMEM_OSFREEMEM(x) dbgfree(x)
127#else
128#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)malloc(size)
129#define DMEM_OSFREEMEM(x) free(x)
130#endif
131#endif
132
133
134/* the largest memory allocation that is made a FRAGMENT: (grab the highest
135 number from the list below) */
136#define DMEM_LARGESTSIZE 2032
137
138/* The total size of a BLOCK used for FRAGMENTS
139 In order to make this use only *1* even alignment from the big-block-
140 allocation-system (possible the bmalloc() system also written by me)
141 we need to subtract the [maximum] struct sizes that could get added all
142 the way through to the grab from the memory. */
143#define DMEM_BLOCKSIZE 4064 /* (4096 - sizeof(struct MemBlock) - 12) */
144
145/* Since the blocksize isn't an even 2^X story anymore, we make a table with
146 the FRAGMENT sizes and amounts that fills up a BLOCK nicely */
147
148/* a little 'bc' script that helps us maximize the usage:
149 - for 32-bit aligned addresses (SPARC crashes otherwise):
150 for(i=20; i<2040; i++) { a=4064/i; if(a*i >= 4060) { if(i%4==0) {i;} } }
151
152
153 I try to approximate a double of each size, starting with ~20. We don't do
154 ODD sizes since several CPU flavours dump core when accessing such
155 addresses. We try to do 32-bit aligned to make ALL kinds of CPUs to remain
156 happy with us.
157 */
158
159#if BIGBLOCKS==4060 /* previously */
160short qinfo[]= { 20, 28, 52, 116, 312, 580, 812, 2028 };
161#else
162short qinfo[]= { 20, 28, 52, 116, 312, 580, 1016, 2032};
163/* 52 and 312 only make use of 4056 bytes, but without them there are too
164 wide gaps */
165#endif
166
167#define MIN(x,y) ((x)<(y)?(x):(y))
168
169/* ---------------------------------------------------------------------- */
170/* Globals */
171/* ---------------------------------------------------------------------- */
172
173/* keeper of the chain of BLOCKS */
174static struct MemTop top[ sizeof(qinfo)/sizeof(qinfo[0]) ];
175
176/* are we experienced? */
177static char initialized = 0;
178
179/* ---------------------------------------------------------------------- */
180/* Start of the real code */
181/* ---------------------------------------------------------------------- */
182
183#ifdef DEBUG
184/************
185 * A few functions that are verbose and tells us about the current status
186 * of the dmalloc system
187 ***********/
188
189static void dmalloc_status()
190{
191 int i;
192 int used;
193 int num;
194 int totalfree=0;
195 struct MemBlock *block;
196 for(i=0; i<sizeof(qinfo)/sizeof(qinfo[0]);i++) {
197 block = top[i].chain;
198 used = 0;
199 num = 0;
200 while(block) {
201 used += top[i].nmax-block->nfree;
202 num++;
203 block = block->next;
204 }
205 printf("Q %d (FRAG %4d), USED %4d FREE %4ld (SIZE %4ld) BLOCKS %d\n",
206 i, top[i].fragsize, used, top[i].nfree,
207 top[i].nfree*top[i].fragsize, num);
208 totalfree += top[i].nfree*top[i].fragsize;
209 }
210 printf("Total unused memory stolen by dmalloc: %d\n", totalfree);
211}
212
213static void dmalloc_failed(size_t size)
214{
215 printf("*** " __FILE__ " Couldn't allocate %d bytes\n", size);
216 dmalloc_status();
217}
218#else
219#define dmalloc_failed(x)
220#endif
221
222#ifdef DEBUG
223
224#define BORDER 1200
225
226void *dbgmalloc(int size)
227{
228 char *mem;
229 size += BORDER;
230#ifdef PSOS
231 rn_getseg(0,size,RN_NOWAIT,0,(void **)&mem);
232#else
233 mem = malloc(size);
234#endif
235 if(mem) {
236 memset(mem, 0xaa, BORDER/2);
237 memset(mem+BORDER/2, 0xbb, size -BORDER);
238 memset(mem-BORDER/2+size, 0xcc, BORDER/2);
239 *(long *)mem = size;
240 mem += (BORDER/2);
241 }
242 printf("OSmalloc(%p)\n", mem);
243 return (void *)mem;
244}
245
246void checkmem(char *ptr)
247{
248 int i;
249 long size;
250 ptr -= BORDER/2;
251
252 for(i=4; i<(BORDER/2); i++)
253 if((unsigned char)ptr[i] != 0xaa) {
254 printf("########### ALERT ALERT\n");
255 break;
256 }
257 size = *(long *)ptr;
258 for(i=size-1; i>=(size - BORDER/2); i--)
259 if((unsigned char)ptr[i] != 0xcc) {
260 printf("********* POST ALERT\n");
261 break;
262 }
263}
264
265void dbgfree(char *ptr)
266{
267 long size;
268 checkmem(ptr);
269 ptr -= BORDER/2;
270 size = *(long *)ptr;
271
272 printf("OSfree(%ld)\n", size);
273#ifdef PSOS
274 rn_retseg(0, ptr);
275#else
276 free(ptr);
277#endif
278}
279
280
281#define DBG(x) syslog x
282
283void syslog(char *fmt, ...)
284{
285 va_list ap;
286 va_start(ap, fmt);
287 vfprintf(stdout, fmt, ap);
288 va_end(ap);
289}
290
291void memchange(void *a, int x)
292{
293 static int memory=0;
294 static int count=0;
295 static int max=0;
296 if(memory > max)
297 max = memory;
298 memory += x;
299 DBG(("%d. PTR %p / %d TOTAL %d MAX %d\n", ++count, a, x, memory, max));
300}
301#else
302#define DBG(x)
303#endif
304
305/****************************************************************************
306 *
307 * FragBlock()
308 *
309 * This function makes FRAGMENTS of the BLOCK sent as argument.
310 *
311 ***************************************************************************/
312
313static void FragBlock(char *memp, int size)
314{
315 struct MemFrag *frag=(struct MemFrag *)memp;
316 struct MemFrag *prev=NULL; /* no previous in the first round */
317 int count=0;
318 while((count+size) <= DMEM_BLOCKSIZE) {
319 memp += size;
320 frag->next = (struct MemFrag *)memp;
321 frag->prev = prev;
322 prev = frag;
323 frag = frag->next;
324 count += size;
325 }
326 prev->next = NULL; /* the last one has no next struct */
327}
328
329/***************************************************************************
330 *
331 * initialize();
332 *
333 * Called in the first dmalloc(). Inits a few memory things.
334 *
335 **************************************************************************/
336static void initialize(void)
337{
338 int i;
339 /* Setup the nmax and fragsize fields of the top structs */
340 for(i=0; i< sizeof(qinfo)/sizeof(qinfo[0]); i++) {
341 top[i].fragsize = qinfo[i];
342 top[i].nmax = DMEM_BLOCKSIZE/qinfo[i];
343
344#ifdef PSOS
345 /* for some reason, these aren't nulled from start: */
346 top[i].chain = NULL; /* no BLOCKS */
347 top[i].nfree = 0; /* no FRAGMENTS */
348#endif
349#ifdef SEMAPHORE
350 {
351 char name[7];
352 sprintf(name, "MEM%d", i);
353 SEMAPHORECREATE(name, top[i].semaphore_id);
354 /* doesn't matter if it failed, we continue anyway ;-( */
355 }
356#endif
357 }
358 initialized = 1;
359}
360
361/****************************************************************************
362 *
363 * FragFromBlock()
364 *
365 * This should return a fragment from the block and mark it as used
366 * accordingly.
367 *
368 ***************************************************************************/
369
370static void *FragFromBlock(struct MemBlock *block)
371{
372 /* make frag point to the first free FRAGMENT */
373 struct MemFrag *frag = block->first;
374 struct MemInfo *mem = (struct MemInfo *)frag;
375
376 /*
377 * Remove the FRAGMENT from the list and decrease the free counters.
378 */
379 block->first = frag->next; /* new first free FRAGMENT */
380
381 block->nfree--; /* BLOCK counter */
382 block->top->nfree--; /* TOP counter */
383
384 /* heal the FRAGMENT list */
385 if(frag->prev) {
386 frag->prev->next = frag->next;
387 }
388 if(frag->next) {
389 frag->next->prev = frag->prev;
390 }
391 mem->block = block; /* no block bit set here */
392
393 return ((char *)mem)+sizeof(struct MemInfo);
394}
395
396/***************************************************************************
397 *
398 * dmalloc()
399 *
400 * This needs no explanation. A malloc() look-alike.
401 *
402 **************************************************************************/
403
404void *dmalloc(size_t size)
405{
406 void *mem;
407
408 DBG(("dmalloc(%d)\n", size));
409
410 if(!initialized)
411 initialize();
412
413 /* First, we make room for the space needed in every allocation */
414 size += sizeof(struct MemInfo);
415
416 if(size < DMEM_LARGESTSIZE) {
417 /* get a FRAGMENT */
418
419 struct MemBlock *block=NULL; /* SAFE */
420 struct MemBlock *newblock=NULL; /* SAFE */
421 struct MemTop *memtop=NULL; /* SAFE */
422
423 /* Determine which queue to use */
424 int queue;
425 for(queue=0; size > qinfo[queue]; queue++)
426 ;
427 do {
428 /* This is the head master of our chain: */
429 memtop = &top[queue];
430
431 DBG(("Top info: %p %d %d %d\n",
432 memtop->chain,
433 memtop->nfree,
434 memtop->nmax,
435 memtop->fragsize));
436
437#ifdef SEMAPHORE
438 if(SEMAPHOREOBTAIN(memtop->semaphore_id))
439 return NULL; /* failed somehow */
440#endif
441
442 /* get the first BLOCK in the chain */
443 block = memtop->chain;
444
445 /* check if we have a free FRAGMENT */
446 if(memtop->nfree) {
447 /* there exists a free FRAGMENT in this chain */
448
449 /* I WANT THIS LOOP OUT OF HERE! */
450
451 /* search for the free FRAGMENT */
452 while(!block->nfree)
453 block = block->next; /* check next BLOCK */
454
455 /*
456 * Now 'block' is the first BLOCK with a free FRAGMENT
457 */
458
459 mem = FragFromBlock(block);
460
461 }
462 else {
463 /* we do *not* have a free FRAGMENT but need to get us a new BLOCK */
464
465 DMEM_OSALLOCMEM(DMEM_BLOCKSIZE + sizeof(struct MemBlock),
466 newblock,
467 struct MemBlock *);
468 if(!newblock) {
469 if(++queue < sizeof(qinfo)/sizeof(qinfo[0])) {
470 /* There are queues for bigger FRAGMENTS that we should check
471 before we fail this for real */
472#ifdef DEBUG
473 printf("*** " __FILE__ " Trying a bigger Q: %d\n", queue);
474#endif
475 mem = NULL;
476 }
477 else {
478 dmalloc_failed(size- sizeof(struct MemInfo));
479 return NULL; /* not enough memory */
480 }
481 }
482 else {
483 /* allocation of big BLOCK was successful */
484
485 MEMINCR(newblock, DMEM_BLOCKSIZE + sizeof(struct MemBlock));
486
487 memtop->chain = newblock; /* attach this BLOCK to the chain */
488 newblock->next = block; /* point to the previous first BLOCK */
489 if(block)
490 block->prev = newblock; /* point back on this new BLOCK */
491 newblock->prev = NULL; /* no previous */
492 newblock->top = memtop; /* our head master */
493
494 /* point to the new first FRAGMENT */
495 newblock->first = (struct MemFrag *)
496 ((char *)newblock+sizeof(struct MemBlock));
497
498 /* create FRAGMENTS of the BLOCK: */
499 FragBlock((char *)newblock->first, memtop->fragsize);
500
501#if defined(DEBUG) && !defined(BMALLOC)
502 checkmem((char *)newblock);
503#endif
504
505 /* fix the nfree counters */
506 newblock->nfree = memtop->nmax;
507 memtop->nfree += memtop->nmax;
508
509 /* get a FRAGMENT from the BLOCK */
510 mem = FragFromBlock(newblock);
511 }
512 }
513#ifdef SEMAPHORE
514 SEMAPHORERETURN(memtop->semaphore_id); /* let it go */
515#endif
516 } while(NULL == mem); /* if we should retry a larger FRAGMENT */
517 }
518 else {
519 /* get a stand-alone BLOCK */
520 struct MemInfo *meminfo;
521
522 if(size&1)
523 /* don't leave this with an odd size since we'll use that bit for
524 information */
525 size++;
526
527 DMEM_OSALLOCMEM(size, meminfo, struct MemInfo *);
528
529 if(meminfo) {
530 MEMINCR(meminfo, size);
531 meminfo->block = (void *)(size|BLOCK_BIT);
532 mem = (char *)meminfo + sizeof(struct MemInfo);
533 }
534 else {
535 dmalloc_failed(size);
536 mem = NULL;
537 }
538 }
539 return (void *)mem;
540}
541
542/***************************************************************************
543 *
544 * dfree()
545 *
546 * This needs no explanation. A free() look-alike.
547 *
548 **************************************************************************/
549
550void dfree(void *memp)
551{
552 struct MemInfo *meminfo = (struct MemInfo *)
553 ((char *)memp- sizeof(struct MemInfo));
554
555 DBG(("dfree(%p)\n", memp));
556
557 if(!((size_t)meminfo->block&BLOCK_BIT)) {
558 /* this is a FRAGMENT we have to deal with */
559
560 struct MemBlock *block=meminfo->block;
561 struct MemTop *memtop = block->top;
562
563#ifdef SEMAPHORE
564 SEMAPHOREOBTAIN(memtop->semaphore_id);
565#endif
566
567 /* increase counters */
568 block->nfree++;
569 memtop->nfree++;
570
571 /* is this BLOCK completely empty now? */
572 if(block->nfree == memtop->nmax) {
573 /* yes, return the BLOCK to the system */
574 if(block->prev)
575 block->prev->next = block->next;
576 else
577 memtop->chain = block->next;
578 if(block->next)
579 block->next->prev = block->prev;
580
581 memtop->nfree -= memtop->nmax; /* total counter subtraction */
582 MEMDECR(block, DMEM_BLOCKSIZE + sizeof(struct MemBlock));
583 DMEM_OSFREEMEM((void *)block); /* return the whole block */
584 }
585 else {
586 /* there are still used FRAGMENTS in the BLOCK, link this one
587 into the chain of free ones */
588 struct MemFrag *frag = (struct MemFrag *)meminfo;
589 frag->prev = NULL;
590 frag->next = block->first;
591 if(block->first)
592 block->first->prev = frag;
593 block->first = frag;
594 }
595#ifdef SEMAPHORE
596 SEMAPHORERETURN(memtop->semaphore_id);
597#endif
598 }
599 else {
600 /* big stand-alone block, just give it back to the OS: */
601 MEMDECR(&meminfo->block, (size_t)meminfo->block&~BLOCK_BIT); /* clean BLOCK_BIT */
602 DMEM_OSFREEMEM((void *)meminfo);
603 }
604}
605
606/***************************************************************************
607 *
608 * drealloc()
609 *
610 * This needs no explanation. A realloc() look-alike.
611 *
612 **************************************************************************/
613
614void *drealloc(char *ptr, size_t size)
615{
616 struct MemInfo *meminfo = (struct MemInfo *)
617 ((char *)ptr- sizeof(struct MemInfo));
618 /*
619 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
620 * NOTE: the ->size field of the meminfo will now contain the MemInfo
621 * struct size too!
622 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
623 */
624 void *mem=NULL; /* SAFE */
625 size_t prevsize;
626
627 /* NOTE that this is only valid if BLOCK_BIT isn't set: */
628 struct MemBlock *block;
629
630 DBG(("drealloc(%p, %d)\n", ptr, size));
631
632 if(NULL == ptr)
633 return dmalloc( size );
634
635 block = meminfo->block;
636
637 if(!((size_t)meminfo->block&BLOCK_BIT) &&
638 (size + sizeof(struct MemInfo) <
639 (prevsize = block->top->fragsize) )) {
640 /* This is a FRAGMENT and new size is possible to retain within the same
641 FRAGMENT */
642 if((prevsize > qinfo[0]) &&
643 /* this is not the smallest memory Q */
644 (size < (block->top-1)->fragsize))
645 /* this fits in a smaller Q */
646 ;
647 else
648 mem = ptr; /* Just return the same pointer as we got in. */
649 }
650 if(!mem) {
651 /* This is a stand-alone BLOCK or a realloc that no longer fits within
652 the same FRAGMENT */
653
654 if((size_t)meminfo->block&BLOCK_BIT) {
655 prevsize = ((size_t)meminfo->block&~BLOCK_BIT) -
656 sizeof(struct MemInfo);
657 }
658 else
659 prevsize -= sizeof(struct MemInfo);
660
661 /* No tricks involved here, just grab a new bite of memory, copy the data
662 * from the old place and free the old memory again. */
663 mem = dmalloc(size);
664 if(mem) {
665 memcpy(mem, ptr, MIN(size, prevsize) );
666 dfree(ptr);
667 }
668 }
669 return mem;
670}
671
672/***************************************************************************
673 *
674 * dcalloc()
675 *
676 * This needs no explanation. A calloc() look-alike.
677 *
678 **************************************************************************/
679/* Allocate an array of NMEMB elements each SIZE bytes long.
680 The entire array is initialized to zeros. */
681void *
682dcalloc (size_t nmemb, size_t size)
683{
684 void *result = dmalloc (nmemb * size);
685
686 if (result != NULL)
687 memset (result, 0, nmemb * size);
688
689 return result;
690}
691/*****************************************************************************
692 *
693 * Dynamic Memory Allocation
694 *
695 * Author: Daniel Stenberg
696 * Date: March 10, 1997
697 * Version: 2.3
698 * Email: Daniel.Stenberg@sth.frontec.se
699 *
700 *
701 * Read 'thoughts' for theories and details of this implementation.
702 *
703 * v2.1
704 * - I once again managed to gain some memory. BLOCK allocations now only use
705 * a 4 bytes header (instead of previos 8) just as FRAGMENTS.
706 *
707 * v2.2
708 * - Re-adjusted the fragment sizes to better fit into the somewhat larger
709 * block.
710 *
711 * v2.3
712 * - Made realloc(NULL, size) work as it should. Which is like a malloc(size)
713 *
714 *****************************************************************************/
715
716#include <stdio.h>
717#include <string.h>
718
719#ifdef DEBUG
720#include <stdarg.h>
721#endif
722
723#ifdef PSOS
724#include <psos.h>
725#define SEMAPHORE /* the PSOS routines use semaphore protection */
726#else
727#include <stdlib.h> /* makes the PSOS complain on the 'size_t' typedef */
728#endif
729
730#ifdef BMALLOC
731#include "bmalloc.h"
732#endif
733
734/* Each TOP takes care of a chain of BLOCKS */
735struct MemTop {
736 struct MemBlock *chain; /* pointer to the BLOCK chain */
737 long nfree; /* total number of free FRAGMENTS in the chain */
738 short nmax; /* total number of FRAGMENTS in this kind of BLOCK */
739 size_t fragsize; /* the size of each FRAGMENT */
740
741#ifdef SEMAPHORE /* if we're protecting the list with SEMAPHORES */
742 long semaphore_id; /* semaphore used to lock this particular list */
743#endif
744
745};
746
747/* Each BLOCK takes care of an amount of FRAGMENTS */
748struct MemBlock {
749 struct MemTop *top; /* our TOP struct */
750 struct MemBlock *next; /* next BLOCK */
751 struct MemBlock *prev; /* prev BLOCK */
752
753 struct MemFrag *first; /* the first free FRAGMENT in this block */
754
755 short nfree; /* number of free FRAGMENTS in this BLOCK */
756};
757
758/* This is the data kept in all _free_ FRAGMENTS */
759struct MemFrag {
760 struct MemFrag *next; /* next free FRAGMENT */
761 struct MemFrag *prev; /* prev free FRAGMENT */
762};
763
764/* This is the data kept in all _allocated_ FRAGMENTS and BLOCKS. We add this
765 to the allocation size first thing in the ALLOC function to make room for
766 this smoothly. */
767
768struct MemInfo {
769 void *block;
770 /* which BLOCK is our father, if BLOCK_BIT is set it means this is a
771 stand-alone, large allocation and then the rest of the bits should be
772 treated as the size of the block */
773#define BLOCK_BIT 1
774};
775
776/* ---------------------------------------------------------------------- */
777/* Defines */
778/* ---------------------------------------------------------------------- */
779
780#ifdef DEBUG
781#define MEMINCR(addr,x) memchange(addr, x)
782#define MEMDECR(addr,x) memchange(addr,-(x))
783#else
784#define MEMINCR(a,x)
785#define MEMDECR(a,x)
786#endif
787
788/* The low level functions used to get memory from the OS and to return memory
789 to the OS, we may also define a stub that does the actual allocation and
790 free, these are the defined function names used in the dmalloc system
791 anyway: */
792#ifdef PSOS
793
794#ifdef DEBUG
795#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
796#define DMEM_OSFREEMEM(x) dbgfree(x)
797#else
798#define DMEM_OSALLOCMEM(size,pointer,type) rn_getseg(0,size,RN_NOWAIT,0,(void **)&pointer)
799/* Similar, but this returns the memory */
800#define DMEM_OSFREEMEM(x) rn_retseg(0, x)
801#endif
802
803/* Argument: <id> */
804#define SEMAPHOREOBTAIN(x) sm_p(x, SM_WAIT, 0)
805/* Argument: <id> */
806#define SEMAPHORERETURN(x) sm_v(x)
807/* Argument: <name> <id-variable name> */
808#define SEMAPHORECREATE(x,y) sm_create(x, 1, SM_FIFO, (ULONG *)&(y))
809
810#else
811#ifdef BMALLOC /* use our own big-memory-allocation system */
812#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)bmalloc(size)
813#define DMEM_OSFREEMEM(x) bfree(x)
814#elif DEBUG
815#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
816#define DMEM_OSFREEMEM(x) dbgfree(x)
817#else
818#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)malloc(size)
819#define DMEM_OSFREEMEM(x) free(x)
820#endif
821#endif
822
823
824/* the largest memory allocation that is made a FRAGMENT: (grab the highest
825 number from the list below) */
826#define DMEM_LARGESTSIZE 2032
827
828/* The total size of a BLOCK used for FRAGMENTS
829 In order to make this use only *1* even alignment from the big-block-
830 allocation-system (possible the bmalloc() system also written by me)
831 we need to subtract the [maximum] struct sizes that could get added all
832 the way through to the grab from the memory. */
833#define DMEM_BLOCKSIZE 4064 /* (4096 - sizeof(struct MemBlock) - 12) */
834
835/* Since the blocksize isn't an even 2^X story anymore, we make a table with
836 the FRAGMENT sizes and amounts that fills up a BLOCK nicely */
837
838/* a little 'bc' script that helps us maximize the usage:
839 - for 32-bit aligned addresses (SPARC crashes otherwise):
840 for(i=20; i<2040; i++) { a=4064/i; if(a*i >= 4060) { if(i%4==0) {i;} } }
841
842
843 I try to approximate a double of each size, starting with ~20. We don't do
844 ODD sizes since several CPU flavours dump core when accessing such
845 addresses. We try to do 32-bit aligned to make ALL kinds of CPUs to remain
846 happy with us.
847 */
848
849#if BIGBLOCKS==4060 /* previously */
850short qinfo[]= { 20, 28, 52, 116, 312, 580, 812, 2028 };
851#else
852short qinfo[]= { 20, 28, 52, 116, 312, 580, 1016, 2032};
853/* 52 and 312 only make use of 4056 bytes, but without them there are too
854 wide gaps */
855#endif
856
857#define MIN(x,y) ((x)<(y)?(x):(y))
858
859/* ---------------------------------------------------------------------- */
860/* Globals */
861/* ---------------------------------------------------------------------- */
862
863/* keeper of the chain of BLOCKS */
864static struct MemTop top[ sizeof(qinfo)/sizeof(qinfo[0]) ];
865
866/* are we experienced? */
867static char initialized = 0;
868
869/* ---------------------------------------------------------------------- */
870/* Start of the real code */
871/* ---------------------------------------------------------------------- */
872
873#ifdef DEBUG
874/************
875 * A few functions that are verbose and tells us about the current status
876 * of the dmalloc system
877 ***********/
878
879static void dmalloc_status()
880{
881 int i;
882 int used;
883 int num;
884 int totalfree=0;
885 struct MemBlock *block;
886 for(i=0; i<sizeof(qinfo)/sizeof(qinfo[0]);i++) {
887 block = top[i].chain;
888 used = 0;
889 num = 0;
890 while(block) {
891 used += top[i].nmax-block->nfree;
892 num++;
893 block = block->next;
894 }
895 printf("Q %d (FRAG %4d), USED %4d FREE %4ld (SIZE %4ld) BLOCKS %d\n",
896 i, top[i].fragsize, used, top[i].nfree,
897 top[i].nfree*top[i].fragsize, num);
898 totalfree += top[i].nfree*top[i].fragsize;
899 }
900 printf("Total unused memory stolen by dmalloc: %d\n", totalfree);
901}
902
903static void dmalloc_failed(size_t size)
904{
905 printf("*** " __FILE__ " Couldn't allocate %d bytes\n", size);
906 dmalloc_status();
907}
908#else
909#define dmalloc_failed(x)
910#endif
911
912#ifdef DEBUG
913
914#define BORDER 1200
915
916void *dbgmalloc(int size)
917{
918 char *mem;
919 size += BORDER;
920#ifdef PSOS
921 rn_getseg(0,size,RN_NOWAIT,0,(void **)&mem);
922#else
923 mem = malloc(size);
924#endif
925 if(mem) {
926 memset(mem, 0xaa, BORDER/2);
927 memset(mem+BORDER/2, 0xbb, size -BORDER);
928 memset(mem-BORDER/2+size, 0xcc, BORDER/2);
929 *(long *)mem = size;
930 mem += (BORDER/2);
931 }
932 printf("OSmalloc(%p)\n", mem);
933 return (void *)mem;
934}
935
936void checkmem(char *ptr)
937{
938 int i;
939 long size;
940 ptr -= BORDER/2;
941
942 for(i=4; i<(BORDER/2); i++)
943 if((unsigned char)ptr[i] != 0xaa) {
944 printf("########### ALERT ALERT\n");
945 break;
946 }
947 size = *(long *)ptr;
948 for(i=size-1; i>=(size - BORDER/2); i--)
949 if((unsigned char)ptr[i] != 0xcc) {
950 printf("********* POST ALERT\n");
951 break;
952 }
953}
954
955void dbgfree(char *ptr)
956{
957 long size;
958 checkmem(ptr);
959 ptr -= BORDER/2;
960 size = *(long *)ptr;
961
962 printf("OSfree(%ld)\n", size);
963#ifdef PSOS
964 rn_retseg(0, ptr);
965#else
966 free(ptr);
967#endif
968}
969
970
971#define DBG(x) syslog x
972
973void syslog(char *fmt, ...)
974{
975 va_list ap;
976 va_start(ap, fmt);
977 vfprintf(stdout, fmt, ap);
978 va_end(ap);
979}
980
981void memchange(void *a, int x)
982{
983 static int memory=0;
984 static int count=0;
985 static int max=0;
986 if(memory > max)
987 max = memory;
988 memory += x;
989 DBG(("%d. PTR %p / %d TOTAL %d MAX %d\n", ++count, a, x, memory, max));
990}
991#else
992#define DBG(x)
993#endif
994
995/****************************************************************************
996 *
997 * FragBlock()
998 *
999 * This function makes FRAGMENTS of the BLOCK sent as argument.
1000 *
1001 ***************************************************************************/
1002
1003static void FragBlock(char *memp, int size)
1004{
1005 struct MemFrag *frag=(struct MemFrag *)memp;
1006 struct MemFrag *prev=NULL; /* no previous in the first round */
1007 int count=0;
1008 while((count+size) <= DMEM_BLOCKSIZE) {
1009 memp += size;
1010 frag->next = (struct MemFrag *)memp;
1011 frag->prev = prev;
1012 prev = frag;
1013 frag = frag->next;
1014 count += size;
1015 }
1016 prev->next = NULL; /* the last one has no next struct */
1017}
1018
1019/***************************************************************************
1020 *
1021 * initialize();
1022 *
1023 * Called in the first dmalloc(). Inits a few memory things.
1024 *
1025 **************************************************************************/
1026static void initialize(void)
1027{
1028 int i;
1029 /* Setup the nmax and fragsize fields of the top structs */
1030 for(i=0; i< sizeof(qinfo)/sizeof(qinfo[0]); i++) {
1031 top[i].fragsize = qinfo[i];
1032 top[i].nmax = DMEM_BLOCKSIZE/qinfo[i];
1033
1034#ifdef PSOS
1035 /* for some reason, these aren't nulled from start: */
1036 top[i].chain = NULL; /* no BLOCKS */
1037 top[i].nfree = 0; /* no FRAGMENTS */
1038#endif
1039#ifdef SEMAPHORE
1040 {
1041 char name[7];
1042 sprintf(name, "MEM%d", i);
1043 SEMAPHORECREATE(name, top[i].semaphore_id);
1044 /* doesn't matter if it failed, we continue anyway ;-( */
1045 }
1046#endif
1047 }
1048 initialized = 1;
1049}
1050
1051/****************************************************************************
1052 *
1053 * FragFromBlock()
1054 *
1055 * This should return a fragment from the block and mark it as used
1056 * accordingly.
1057 *
1058 ***************************************************************************/
1059
1060static void *FragFromBlock(struct MemBlock *block)
1061{
1062 /* make frag point to the first free FRAGMENT */
1063 struct MemFrag *frag = block->first;
1064 struct MemInfo *mem = (struct MemInfo *)frag;
1065
1066 /*
1067 * Remove the FRAGMENT from the list and decrease the free counters.
1068 */
1069 block->first = frag->next; /* new first free FRAGMENT */
1070
1071 block->nfree--; /* BLOCK counter */
1072 block->top->nfree--; /* TOP counter */
1073
1074 /* heal the FRAGMENT list */
1075 if(frag->prev) {
1076 frag->prev->next = frag->next;
1077 }
1078 if(frag->next) {
1079 frag->next->prev = frag->prev;
1080 }
1081 mem->block = block; /* no block bit set here */
1082
1083 return ((char *)mem)+sizeof(struct MemInfo);
1084}
1085
1086/***************************************************************************
1087 *
1088 * dmalloc()
1089 *
1090 * This needs no explanation. A malloc() look-alike.
1091 *
1092 **************************************************************************/
1093
1094void *dmalloc(size_t size)
1095{
1096 void *mem;
1097
1098 DBG(("dmalloc(%d)\n", size));
1099
1100 if(!initialized)
1101 initialize();
1102
1103 /* First, we make room for the space needed in every allocation */
1104 size += sizeof(struct MemInfo);
1105
1106 if(size < DMEM_LARGESTSIZE) {
1107 /* get a FRAGMENT */
1108
1109 struct MemBlock *block=NULL; /* SAFE */
1110 struct MemBlock *newblock=NULL; /* SAFE */
1111 struct MemTop *memtop=NULL; /* SAFE */
1112
1113 /* Determine which queue to use */
1114 int queue;
1115 for(queue=0; size > qinfo[queue]; queue++)
1116 ;
1117 do {
1118 /* This is the head master of our chain: */
1119 memtop = &top[queue];
1120
1121 DBG(("Top info: %p %d %d %d\n",
1122 memtop->chain,
1123 memtop->nfree,
1124 memtop->nmax,
1125 memtop->fragsize));
1126
1127#ifdef SEMAPHORE
1128 if(SEMAPHOREOBTAIN(memtop->semaphore_id))
1129 return NULL; /* failed somehow */
1130#endif
1131
1132 /* get the first BLOCK in the chain */
1133 block = memtop->chain;
1134
1135 /* check if we have a free FRAGMENT */
1136 if(memtop->nfree) {
1137 /* there exists a free FRAGMENT in this chain */
1138
1139 /* I WANT THIS LOOP OUT OF HERE! */
1140
1141 /* search for the free FRAGMENT */
1142 while(!block->nfree)
1143 block = block->next; /* check next BLOCK */
1144
1145 /*
1146 * Now 'block' is the first BLOCK with a free FRAGMENT
1147 */
1148
1149 mem = FragFromBlock(block);
1150
1151 }
1152 else {
1153 /* we do *not* have a free FRAGMENT but need to get us a new BLOCK */
1154
1155 DMEM_OSALLOCMEM(DMEM_BLOCKSIZE + sizeof(struct MemBlock),
1156 newblock,
1157 struct MemBlock *);
1158 if(!newblock) {
1159 if(++queue < sizeof(qinfo)/sizeof(qinfo[0])) {
1160 /* There are queues for bigger FRAGMENTS that we should check
1161 before we fail this for real */
1162#ifdef DEBUG
1163 printf("*** " __FILE__ " Trying a bigger Q: %d\n", queue);
1164#endif
1165 mem = NULL;
1166 }
1167 else {
1168 dmalloc_failed(size- sizeof(struct MemInfo));
1169 return NULL; /* not enough memory */
1170 }
1171 }
1172 else {
1173 /* allocation of big BLOCK was successful */
1174
1175 MEMINCR(newblock, DMEM_BLOCKSIZE + sizeof(struct MemBlock));
1176
1177 memtop->chain = newblock; /* attach this BLOCK to the chain */
1178 newblock->next = block; /* point to the previous first BLOCK */
1179 if(block)
1180 block->prev = newblock; /* point back on this new BLOCK */
1181 newblock->prev = NULL; /* no previous */
1182 newblock->top = memtop; /* our head master */
1183
1184 /* point to the new first FRAGMENT */
1185 newblock->first = (struct MemFrag *)
1186 ((char *)newblock+sizeof(struct MemBlock));
1187
1188 /* create FRAGMENTS of the BLOCK: */
1189 FragBlock((char *)newblock->first, memtop->fragsize);
1190
1191#if defined(DEBUG) && !defined(BMALLOC)
1192 checkmem((char *)newblock);
1193#endif
1194
1195 /* fix the nfree counters */
1196 newblock->nfree = memtop->nmax;
1197 memtop->nfree += memtop->nmax;
1198
1199 /* get a FRAGMENT from the BLOCK */
1200 mem = FragFromBlock(newblock);
1201 }
1202 }
1203#ifdef SEMAPHORE
1204 SEMAPHORERETURN(memtop->semaphore_id); /* let it go */
1205#endif
1206 } while(NULL == mem); /* if we should retry a larger FRAGMENT */
1207 }
1208 else {
1209 /* get a stand-alone BLOCK */
1210 struct MemInfo *meminfo;
1211
1212 if(size&1)
1213 /* don't leave this with an odd size since we'll use that bit for
1214 information */
1215 size++;
1216
1217 DMEM_OSALLOCMEM(size, meminfo, struct MemInfo *);
1218
1219 if(meminfo) {
1220 MEMINCR(meminfo, size);
1221 meminfo->block = (void *)(size|BLOCK_BIT);
1222 mem = (char *)meminfo + sizeof(struct MemInfo);
1223 }
1224 else {
1225 dmalloc_failed(size);
1226 mem = NULL;
1227 }
1228 }
1229 return (void *)mem;
1230}
1231
1232/***************************************************************************
1233 *
1234 * dfree()
1235 *
1236 * This needs no explanation. A free() look-alike.
1237 *
1238 **************************************************************************/
1239
1240void dfree(void *memp)
1241{
1242 struct MemInfo *meminfo = (struct MemInfo *)
1243 ((char *)memp- sizeof(struct MemInfo));
1244
1245 DBG(("dfree(%p)\n", memp));
1246
1247 if(!((size_t)meminfo->block&BLOCK_BIT)) {
1248 /* this is a FRAGMENT we have to deal with */
1249
1250 struct MemBlock *block=meminfo->block;
1251 struct MemTop *memtop = block->top;
1252
1253#ifdef SEMAPHORE
1254 SEMAPHOREOBTAIN(memtop->semaphore_id);
1255#endif
1256
1257 /* increase counters */
1258 block->nfree++;
1259 memtop->nfree++;
1260
1261 /* is this BLOCK completely empty now? */
1262 if(block->nfree == memtop->nmax) {
1263 /* yes, return the BLOCK to the system */
1264 if(block->prev)
1265 block->prev->next = block->next;
1266 else
1267 memtop->chain = block->next;
1268 if(block->next)
1269 block->next->prev = block->prev;
1270
1271 memtop->nfree -= memtop->nmax; /* total counter subtraction */
1272 MEMDECR(block, DMEM_BLOCKSIZE + sizeof(struct MemBlock));
1273 DMEM_OSFREEMEM((void *)block); /* return the whole block */
1274 }
1275 else {
1276 /* there are still used FRAGMENTS in the BLOCK, link this one
1277 into the chain of free ones */
1278 struct MemFrag *frag = (struct MemFrag *)meminfo;
1279 frag->prev = NULL;
1280 frag->next = block->first;
1281 if(block->first)
1282 block->first->prev = frag;
1283 block->first = frag;
1284 }
1285#ifdef SEMAPHORE
1286 SEMAPHORERETURN(memtop->semaphore_id);
1287#endif
1288 }
1289 else {
1290 /* big stand-alone block, just give it back to the OS: */
1291 MEMDECR(&meminfo->block, (size_t)meminfo->block&~BLOCK_BIT); /* clean BLOCK_BIT */
1292 DMEM_OSFREEMEM((void *)meminfo);
1293 }
1294}
1295
1296/***************************************************************************
1297 *
1298 * drealloc()
1299 *
1300 * This needs no explanation. A realloc() look-alike.
1301 *
1302 **************************************************************************/
1303
1304void *drealloc(char *ptr, size_t size)
1305{
1306 struct MemInfo *meminfo = (struct MemInfo *)
1307 ((char *)ptr- sizeof(struct MemInfo));
1308 /*
1309 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1310 * NOTE: the ->size field of the meminfo will now contain the MemInfo
1311 * struct size too!
1312 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1313 */
1314 void *mem=NULL; /* SAFE */
1315 size_t prevsize;
1316
1317 /* NOTE that this is only valid if BLOCK_BIT isn't set: */
1318 struct MemBlock *block;
1319
1320 DBG(("drealloc(%p, %d)\n", ptr, size));
1321
1322 if(NULL == ptr)
1323 return dmalloc( size );
1324
1325 block = meminfo->block;
1326
1327 if(!((size_t)meminfo->block&BLOCK_BIT) &&
1328 (size + sizeof(struct MemInfo) <
1329 (prevsize = block->top->fragsize) )) {
1330 /* This is a FRAGMENT and new size is possible to retain within the same
1331 FRAGMENT */
1332 if((prevsize > qinfo[0]) &&
1333 /* this is not the smallest memory Q */
1334 (size < (block->top-1)->fragsize))
1335 /* this fits in a smaller Q */
1336 ;
1337 else
1338 mem = ptr; /* Just return the same pointer as we got in. */
1339 }
1340 if(!mem) {
1341 /* This is a stand-alone BLOCK or a realloc that no longer fits within
1342 the same FRAGMENT */
1343
1344 if((size_t)meminfo->block&BLOCK_BIT) {
1345 prevsize = ((size_t)meminfo->block&~BLOCK_BIT) -
1346 sizeof(struct MemInfo);
1347 }
1348 else
1349 prevsize -= sizeof(struct MemInfo);
1350
1351 /* No tricks involved here, just grab a new bite of memory, copy the data
1352 * from the old place and free the old memory again. */
1353 mem = dmalloc(size);
1354 if(mem) {
1355 memcpy(mem, ptr, MIN(size, prevsize) );
1356 dfree(ptr);
1357 }
1358 }
1359 return mem;
1360}
1361
1362/***************************************************************************
1363 *
1364 * dcalloc()
1365 *
1366 * This needs no explanation. A calloc() look-alike.
1367 *
1368 **************************************************************************/
1369/* Allocate an array of NMEMB elements each SIZE bytes long.
1370 The entire array is initialized to zeros. */
1371void *
1372dcalloc (size_t nmemb, size_t size)
1373{
1374 void *result = dmalloc (nmemb * size);
1375
1376 if (result != NULL)
1377 memset (result, 0, nmemb * size);
1378
1379 return result;
1380}
diff --git a/apps/plugins/pdbox/dbestfit-3.3/dmalloc.h b/apps/plugins/pdbox/dbestfit-3.3/dmalloc.h
new file mode 100644
index 0000000000..053b3a114b
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/dmalloc.h
@@ -0,0 +1,16 @@
1
2void *dmalloc(size_t);
3void dfree(void *);
4void *drealloc(void *, size_t);
5
6#define malloc(x) dmalloc(x)
7#define free(x) dfree(x)
8#define realloc(x,y) drealloc(x,y)
9
10void *dmalloc(size_t);
11void dfree(void *);
12void *drealloc(void *, size_t);
13
14#define malloc(x) dmalloc(x)
15#define free(x) dfree(x)
16#define realloc(x,y) drealloc(x,y)
diff --git a/apps/plugins/pdbox/dbestfit-3.3/dmytest.c b/apps/plugins/pdbox/dbestfit-3.3/dmytest.c
new file mode 100644
index 0000000000..46d4c73efd
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/dmytest.c
@@ -0,0 +1,276 @@
1#include <stdio.h>
2#include <stdlib.h>
3
4#include "dmalloc.h"
5
6#define MAX 500
7#define MAX2 1000
8#define MAXC 2
9
10#define TESTA
11#define TESTB
12#define TESTC
13#define TESTD
14
15int main(int argc, char **argv)
16{
17 int i;
18 int memory = 0;
19
20#ifdef BMALLOC
21#define HEAP 10000
22 void *heap = (malloc)(HEAP);
23 if(!heap)
24 return -1;
25 add_pool(heap, HEAP);
26#endif
27
28 {
29#define MAXK 100
30 void *wow[MAXK];
31 wow[0]=malloc(700);
32 realloc(wow[0], 680);
33 return 0;
34
35 for(i=0; i<MAXK; i++)
36 if(!(wow[i]=malloc(412))) {
37 printf("*** Couldn't allocated memory, exiting\n");
38 return -2;
39 }
40 for(i=MAXK-1; i>=0; i-=2)
41 free(wow[i]);
42 return 0;
43 }
44
45
46#ifdef TESTD
47 {
48#define MAXS 10
49#define MAXS1 0
50 void *ptr[MAXS];
51
52 for(i=MAXS1; i< MAXS; i++) {
53 printf("%d malloc(%d)\n", i, i*55);
54 ptr[i] = malloc (i*55);
55 }
56 for(i=MAXS1; i< MAXS; i++) {
57 void *tmp;
58 printf("%d realloc(%d)\n", i, i*155);
59 tmp=realloc(ptr[i], i*155);
60 if(tmp)
61 ptr[i] = tmp;
62 }
63 for(i=MAXS1; i< MAXS; i++) {
64 printf("%d free(%d)\n", i, i*155);
65 free(ptr[i]);
66 }
67 }
68#endif
69
70#ifdef TESTC
71 {
72 void *ptr[MAXC];
73 printf("This is test C:\n");
74
75 for(i=0; i< MAXC; i++) {
76 printf("%d malloc(100)\n", i+1);
77 ptr[i] = malloc(100);
78 printf(" ...returned %p\n", ptr[i]);
79 }
80
81 for(i=0; i< MAXC; i++) {
82 printf("%d free()\n", i+1);
83 free(ptr[i]);
84 }
85
86 printf("End of test C:\n");
87 }
88#endif
89
90#ifdef TESTA
91 {
92 void *pointers[MAX];
93 printf("This is test I:\n");
94
95 for(i=0; i<MAX; i++) {
96 printf("%d attempts malloc(%d)\n", i, i*6);
97 pointers[i]=malloc(i*6);
98 if(!pointers[i]) {
99 printf("cant get more memory!");
100 return(0);
101 }
102 memory += (i*6);
103 }
104 printf("\namount: %d\n", memory);
105 memory = 0;
106 for(i=0; i<MAX; i++) {
107 printf("%d attempts realloc(%d)\n", i, i*7);
108 pointers[i]=realloc(pointers[i], i*7);
109 memory += i*7;
110 }
111 printf("\namount: %d\n", memory);
112 for(i=0; i<MAX; i++) {
113 printf("%d attempts free(%d)\n", i, i*7);
114 free(pointers[i]);
115 }
116 printf("\nend of test 1\n");
117 }
118#endif
119#ifdef TESTB
120 {
121 void *pointers2[MAX2];
122 memory = 0;
123 printf("\nTest II\n");
124 for(i=0; i< MAX2; i++) {
125/* printf("%d attempts malloc(%d)\n", i, 7); */
126 pointers2[i] = malloc(7);
127 memory += 7;
128 }
129 printf("\namount: %d\n", memory);
130 for(i=0; i< MAX2; i++) {
131 free(pointers2[i]);
132 }
133 printf("\nend of test II\n");
134
135 }
136#endif
137 return 0;
138}
139#include <stdio.h>
140#include <stdlib.h>
141
142#include "dmalloc.h"
143
144#define MAX 500
145#define MAX2 1000
146#define MAXC 2
147
148#define TESTA
149#define TESTB
150#define TESTC
151#define TESTD
152
153int main(int argc, char **argv)
154{
155 int i;
156 int memory = 0;
157
158#ifdef BMALLOC
159#define HEAP 10000
160 void *heap = (malloc)(HEAP);
161 if(!heap)
162 return -1;
163 add_pool(heap, HEAP);
164#endif
165
166 {
167#define MAXK 100
168 void *wow[MAXK];
169 wow[0]=malloc(700);
170 realloc(wow[0], 680);
171 return 0;
172
173 for(i=0; i<MAXK; i++)
174 if(!(wow[i]=malloc(412))) {
175 printf("*** Couldn't allocated memory, exiting\n");
176 return -2;
177 }
178 for(i=MAXK-1; i>=0; i-=2)
179 free(wow[i]);
180 return 0;
181 }
182
183
184#ifdef TESTD
185 {
186#define MAXS 10
187#define MAXS1 0
188 void *ptr[MAXS];
189
190 for(i=MAXS1; i< MAXS; i++) {
191 printf("%d malloc(%d)\n", i, i*55);
192 ptr[i] = malloc (i*55);
193 }
194 for(i=MAXS1; i< MAXS; i++) {
195 void *tmp;
196 printf("%d realloc(%d)\n", i, i*155);
197 tmp=realloc(ptr[i], i*155);
198 if(tmp)
199 ptr[i] = tmp;
200 }
201 for(i=MAXS1; i< MAXS; i++) {
202 printf("%d free(%d)\n", i, i*155);
203 free(ptr[i]);
204 }
205 }
206#endif
207
208#ifdef TESTC
209 {
210 void *ptr[MAXC];
211 printf("This is test C:\n");
212
213 for(i=0; i< MAXC; i++) {
214 printf("%d malloc(100)\n", i+1);
215 ptr[i] = malloc(100);
216 printf(" ...returned %p\n", ptr[i]);
217 }
218
219 for(i=0; i< MAXC; i++) {
220 printf("%d free()\n", i+1);
221 free(ptr[i]);
222 }
223
224 printf("End of test C:\n");
225 }
226#endif
227
228#ifdef TESTA
229 {
230 void *pointers[MAX];
231 printf("This is test I:\n");
232
233 for(i=0; i<MAX; i++) {
234 printf("%d attempts malloc(%d)\n", i, i*6);
235 pointers[i]=malloc(i*6);
236 if(!pointers[i]) {
237 printf("cant get more memory!");
238 return(0);
239 }
240 memory += (i*6);
241 }
242 printf("\namount: %d\n", memory);
243 memory = 0;
244 for(i=0; i<MAX; i++) {
245 printf("%d attempts realloc(%d)\n", i, i*7);
246 pointers[i]=realloc(pointers[i], i*7);
247 memory += i*7;
248 }
249 printf("\namount: %d\n", memory);
250 for(i=0; i<MAX; i++) {
251 printf("%d attempts free(%d)\n", i, i*7);
252 free(pointers[i]);
253 }
254 printf("\nend of test 1\n");
255 }
256#endif
257#ifdef TESTB
258 {
259 void *pointers2[MAX2];
260 memory = 0;
261 printf("\nTest II\n");
262 for(i=0; i< MAX2; i++) {
263/* printf("%d attempts malloc(%d)\n", i, 7); */
264 pointers2[i] = malloc(7);
265 memory += 7;
266 }
267 printf("\namount: %d\n", memory);
268 for(i=0; i< MAX2; i++) {
269 free(pointers2[i]);
270 }
271 printf("\nend of test II\n");
272
273 }
274#endif
275 return 0;
276}
diff --git a/apps/plugins/pdbox/dbestfit-3.3/malloc.man b/apps/plugins/pdbox/dbestfit-3.3/malloc.man
new file mode 100644
index 0000000000..79f6f3ea37
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/malloc.man
@@ -0,0 +1,190 @@
1MALLOC(3V) C LIBRARY FUNCTIONS MALLOC(3V)
2
3
4NAME
5 malloc, free, realloc, calloc
6
7SYNOPSIS
8 #include <malloc.h>
9
10 void *malloc(size)
11 size_t size;
12
13 void free(ptr)
14 void *ptr;
15
16 void *realloc(ptr, size)
17 void *ptr;
18 size_t size;
19
20 void *calloc(nelem, elsize)
21 size_t nelem;
22 size_t elsize;
23
24DESCRIPTION
25 These routines provide a general-purpose memory allocation
26 package. They maintain a table of free blocks for efficient
27 allocation and coalescing of free storage. When there is no
28 suitable space already free, the allocation routines call
29 rn_getseg() to get more memory from the system.
30
31 Each of the allocation routines returns a pointer to space
32 suitably aligned for storage of any type of object. Each
33 returns a NULL pointer if the request cannot be completed
34 (see DIAGNOSTICS).
35
36 malloc() returns a pointer to a block of at least size
37 bytes, which is appropriately aligned.
38
39 free() releases a previously allocated block. Its argument
40 is a pointer to a block previously allocated by malloc(),
41 calloc() or realloc().
42
43 realloc() changes the size of the block referenced by ptr to
44 size bytes and returns a pointer to the (possibly moved)
45 block. The contents will be unchanged up to the lesser of
46 the new and old sizes. If unable to honor a reallocation
47 request, realloc() leaves its first argument unaltered.
48
49 **** DMALLOC DOES NOT COMPLY WITH THE PARAGRAPH BELOW ****
50
51 For backwards compatibility, realloc() accepts a pointer to a
52 block freed since the most recent call to malloc(), cal-
53 loc() or realloc().
54
55 Note: using realloc() with a block freed before the most recent
56 call to malloc(), calloc() or realloc() is an error.
57
58 calloc() uses malloc() to allocate space for an array of
59 nelem elements of size elsize, initializes the space to
60 zeros, and returns a pointer to the initialized block. The
61 block should be freed with free().
62
63
64 malloc() and realloc() return a non- NULL pointer if size is 0,
65 and calloc() returns a non-NULL pointer if nelem or elsize is 0,
66 but these pointers should not be dereferenced.
67
68 Note: Always cast the value returned by malloc(), realloc() or
69 calloc().
70
71
72RETURN VALUES On success, malloc(), calloc() and realloc() return a
73 pointer to space suitably aligned for storage of any type of
74 object. On failure, they return NULL.
75
76 free() does not return a value.
77
78
79NOTES
80 Because malloc() and realloc() return a non-NULL pointer if size
81 is 0, and calloc() returns a non-NULL pointer if nelem or elsize
82 is 0, a zero size need not be treated as a special case if it
83 should be passed to these functions unpredictably. Also, the
84 pointer returned by these functions may be passed to subsequent
85 invocations of realloc().
86
87
88BUGS
89
90 **** DMALLOC DOES NOT COMPLY WITH THE PARAGRAPH BELOW ****
91
92 Since realloc() accepts a pointer to a block freed since the last
93 call to malloc(), calloc() or realloc(), a degradation of
94 performance results. The semantics of free() should be changed
95 so that the contents of a previously freed block are undefined.
96MALLOC(3V) C LIBRARY FUNCTIONS MALLOC(3V)
97
98
99NAME
100 malloc, free, realloc, calloc
101
102SYNOPSIS
103 #include <malloc.h>
104
105 void *malloc(size)
106 size_t size;
107
108 void free(ptr)
109 void *ptr;
110
111 void *realloc(ptr, size)
112 void *ptr;
113 size_t size;
114
115 void *calloc(nelem, elsize)
116 size_t nelem;
117 size_t elsize;
118
119DESCRIPTION
120 These routines provide a general-purpose memory allocation
121 package. They maintain a table of free blocks for efficient
122 allocation and coalescing of free storage. When there is no
123 suitable space already free, the allocation routines call
124 rn_getseg() to get more memory from the system.
125
126 Each of the allocation routines returns a pointer to space
127 suitably aligned for storage of any type of object. Each
128 returns a NULL pointer if the request cannot be completed
129 (see DIAGNOSTICS).
130
131 malloc() returns a pointer to a block of at least size
132 bytes, which is appropriately aligned.
133
134 free() releases a previously allocated block. Its argument
135 is a pointer to a block previously allocated by malloc(),
136 calloc() or realloc().
137
138 realloc() changes the size of the block referenced by ptr to
139 size bytes and returns a pointer to the (possibly moved)
140 block. The contents will be unchanged up to the lesser of
141 the new and old sizes. If unable to honor a reallocation
142 request, realloc() leaves its first argument unaltered.
143
144 **** DMALLOC DOES NOT COMPLY WITH THE PARAGRAPH BELOW ****
145
146 For backwards compatibility, realloc() accepts a pointer to a
147 block freed since the most recent call to malloc(), cal-
148 loc() or realloc().
149
150 Note: using realloc() with a block freed before the most recent
151 call to malloc(), calloc() or realloc() is an error.
152
153 calloc() uses malloc() to allocate space for an array of
154 nelem elements of size elsize, initializes the space to
155 zeros, and returns a pointer to the initialized block. The
156 block should be freed with free().
157
158
159 malloc() and realloc() return a non- NULL pointer if size is 0,
160 and calloc() returns a non-NULL pointer if nelem or elsize is 0,
161 but these pointers should not be dereferenced.
162
163 Note: Always cast the value returned by malloc(), realloc() or
164 calloc().
165
166
167RETURN VALUES On success, malloc(), calloc() and realloc() return a
168 pointer to space suitably aligned for storage of any type of
169 object. On failure, they return NULL.
170
171 free() does not return a value.
172
173
174NOTES
175 Because malloc() and realloc() return a non-NULL pointer if size
176 is 0, and calloc() returns a non-NULL pointer if nelem or elsize
177 is 0, a zero size need not be treated as a special case if it
178 should be passed to these functions unpredictably. Also, the
179 pointer returned by these functions may be passed to subsequent
180 invocations of realloc().
181
182
183BUGS
184
185 **** DMALLOC DOES NOT COMPLY WITH THE PARAGRAPH BELOW ****
186
187 Since realloc() accepts a pointer to a block freed since the last
188 call to malloc(), calloc() or realloc(), a degradation of
189 performance results. The semantics of free() should be changed
190 so that the contents of a previously freed block are undefined.
diff --git a/apps/plugins/pdbox/dbestfit-3.3/mytest.c b/apps/plugins/pdbox/dbestfit-3.3/mytest.c
new file mode 100644
index 0000000000..bf338b72ef
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/mytest.c
@@ -0,0 +1,140 @@
1
2#include <stdio.h>
3#include <stdlib.h>
4
5#include "bmalloc.h"
6
7int main(int argc, char **argv)
8{
9 void *pointers[5];
10 int i;
11 void *area;
12
13 for(i=0; i<5; i++)
14 pointers[i] = malloc(8000);
15
16 if(argc>1) {
17 switch(argv[1][0]) {
18 case '1':
19 for(i=0; i<5; i++) {
20 add_pool(pointers[i], 4000);
21 add_pool((char *)pointers[i]+4000, 4000);
22 }
23 break;
24 case '2':
25 area = malloc(20000);
26 add_pool(area, 3000);
27 add_pool((char *)area+6000, 3000);
28 add_pool((char *)area+3000, 3000);
29 add_pool((char *)area+12000, 3000);
30 add_pool((char *)area+9000, 3000);
31 break;
32 case '3':
33 {
34 void *ptr[10];
35 area = malloc(20000);
36 add_pool(area, 20000);
37
38 printf(" ** TEST USAGE\n");
39 for(i=0; i<9; i++)
40 ptr[i]=bmalloc(200);
41 print_lists();
42 for(i=0; i<9; i++)
43 bfree(ptr[i]);
44 printf(" ** END OF TEST USAGE\n");
45 }
46
47 break;
48 case '4':
49 {
50 void *ptr[10];
51 area = malloc(20000);
52 add_pool(area, 20000);
53
54 ptr[0]=bmalloc(4080);
55 print_lists();
56 bfree(ptr[0]);
57 printf(" ** END OF TEST USAGE\n");
58 }
59
60 break;
61 }
62 }
63 else
64 for(i=4; i>=0; i--)
65 add_pool(pointers[i], 8000-i*100);
66
67 print_lists();
68
69 return 0;
70}
71
72#include <stdio.h>
73#include <stdlib.h>
74
75#include "bmalloc.h"
76
77int main(int argc, char **argv)
78{
79 void *pointers[5];
80 int i;
81 void *area;
82
83 for(i=0; i<5; i++)
84 pointers[i] = malloc(8000);
85
86 if(argc>1) {
87 switch(argv[1][0]) {
88 case '1':
89 for(i=0; i<5; i++) {
90 add_pool(pointers[i], 4000);
91 add_pool((char *)pointers[i]+4000, 4000);
92 }
93 break;
94 case '2':
95 area = malloc(20000);
96 add_pool(area, 3000);
97 add_pool((char *)area+6000, 3000);
98 add_pool((char *)area+3000, 3000);
99 add_pool((char *)area+12000, 3000);
100 add_pool((char *)area+9000, 3000);
101 break;
102 case '3':
103 {
104 void *ptr[10];
105 area = malloc(20000);
106 add_pool(area, 20000);
107
108 printf(" ** TEST USAGE\n");
109 for(i=0; i<9; i++)
110 ptr[i]=bmalloc(200);
111 print_lists();
112 for(i=0; i<9; i++)
113 bfree(ptr[i]);
114 printf(" ** END OF TEST USAGE\n");
115 }
116
117 break;
118 case '4':
119 {
120 void *ptr[10];
121 area = malloc(20000);
122 add_pool(area, 20000);
123
124 ptr[0]=bmalloc(4080);
125 print_lists();
126 bfree(ptr[0]);
127 printf(" ** END OF TEST USAGE\n");
128 }
129
130 break;
131 }
132 }
133 else
134 for(i=4; i>=0; i--)
135 add_pool(pointers[i], 8000-i*100);
136
137 print_lists();
138
139 return 0;
140}
diff --git a/apps/plugins/pdbox/dbestfit-3.3/thoughts b/apps/plugins/pdbox/dbestfit-3.3/thoughts
new file mode 100644
index 0000000000..8dbd8b9979
--- /dev/null
+++ b/apps/plugins/pdbox/dbestfit-3.3/thoughts
@@ -0,0 +1,340 @@
1 =====================================
2 Memory Allocation Algorithm Theories.
3 =====================================
4
5GOAL
6 It is intended to be a 100% working memory allocation system. It should be
7 capable of replacing an ordinary Operating System's own routines. It should
8 work good in a multitasking, shared memory, non-virtual memory environment
9 without clogging the memory. Primary aimed for small machines, CPUs and
10 memory amounts.
11
12 I use a best-fit algorithm with a slight overhead in order to increase speed
13 a lot. It should remain scalable and work good with very large amount of
14 memory and free/used memory blocks too.
15
16TERMINOLOGY
17
18 FRAGMENT - small identically sized parts of a larger BLOCK, they are when
19 travered in lists etc _not_ allocated.
20 BLOCK - large memory area, if used for FRAGMENTS, they are linked in a
21 lists. One list for each FRAGMENT size supported.
22 TOP - head struct that holds information about and points to a chain
23 of BLOCKS for a particular FRAGMENT size.
24 CHUNK - a contiguous area of free memory
25
26MEMORY SYSTEM
27
28 We split the system in two parts. One part allocates small memory amounts
29 and one part allocates large memory amounts, but all allocations are done
30 "through" the small-part-system. There is an option to use only the small
31 system (and thus use the OS for large blocks) or the complete package.
32
33##############################################################################
34 SMALL SIZE ALLOCATIONS
35##############################################################################
36
37 Keywords for this system is 'Deferred Coalescing' and 'quick lists'.
38
39 ALLOC
40
41 * Small allocations are "aligned" upwards to a set of preset sizes. In the
42 current implementation I use 20, 28, 52, 116, 312, 580, 812, 2028 bytes.
43 Memory allocations of these sizes are refered to as FRAGMENTS.
44 (The reason for these specific sizes is the requirement that they must be
45 32-bit aligned and fit as good as possible within 4060 bytes.)
46
47 * Allocations larger than 2028 will get a BLOCK for that allocation only.
48
49 * Each of these sizes has it's own TOP. When a FRAGMENT is requested, a
50 larger BLOCK will be allocated and divided into many FRAGMENTS (all of the
51 same size). TOP points to a list with BLOCKS that contains FRAGMENTS of
52 the same size. Each BLOCK has a 'number of free FRAGMENTS' counter and so
53 has each TOP (for the entire chain).
54
55 * A BLOCK is around 4060 bytes plus the size of the information header. This
56 size is adjusted to make the allocation of the big block not require more
57 than 4096 bytes. (This might not be so easy to be sure of, if you don't
58 know how the big-block system works, but the BMALLOC system uses an
59 extra header of 12 bytes and the header for the FRAGMENT BLOCK is 20 bytes
60 in a general 32-bit unix environment.)
61
62 * In case the allocation of a BLOCK fails when a FRAGMENT is required, the
63 next size of FRAGMENTS will be checked for a free FRAGMENT. First when the
64 larger size lists have been tested without success it will fail for real.
65
66 FREE
67
68 * When FRAGMENTS are freed so that a BLOCK becomes non-used, it is returned
69 to the system.
70
71 * FREEing a fragment adds the buffer in a LIFO-order. That means that the
72 next request for a fragment from the same list, the last freed buffer will
73 be returned first.
74
75 REALLOC
76
77 * REALLOCATION of a FRAGMENT does first check if the new size would fit
78 within the same FRAGMENT and if it would use the same FRAGMENT size. If it
79 does and would, the same pointer is returned.
80
81 OVERHEAD
82
83 Yes, there is an overhead on small allocations (internal fragmentation).
84 Yet, I do believe that small allocations more often than larger ones are
85 used dynamically. I believe that a large overhead is not a big problem if it
86 remains only for a while. The big gain is with the extreme speed we can GET
87 and RETURN small allocations. This has yet to be proven. I am open to other
88 systems of dealing with the small ones, but I don`t believe in using the
89 same system for all sizes of allocations.
90
91 IMPROVEMENT
92
93 An addition to the above described algorithm is the `save-empty-BLOCKS-a-
94 while-afterwards`. It will be used when the last used FRAGMENT within a
95 BLOCK is freed. The BLOCK will then not get returned to the system until "a
96 few more" FRAGMENTS have been freed in case the last [few] freed FRAGMENTS
97 are allocated yet again (and thus prevent the huge overhead of making
98 FRAGMENTS in a BLOCK). The "only" drawback of such a SEBAWA concept is
99 that it would mean an even bigger overhead...
100
101 HEADERS (in allocated data)
102
103 FRAGMENTS - 32-bit pointer to its parent BLOCK (lowest bit must be 0)
104 BLOCK - 32-bit size (lowest bit must be 1 to separate this from
105 FRAGMENTS)
106
107##############################################################################
108 LARGER ALLOCATIONS
109##############################################################################
110
111 If the requested size is larger than the largest FRAGMENT size supported,
112 the allocation will be made for this memory area alone, or if a BLOCK is
113 allocated to fit lots of FRAGMENTS a large block is also desired.
114
115 * We add memory to the "system" with the add_pool() function call. It
116 specifies the start and size of the new block of memory that will be
117 used in this memory allocation system. Several add_pool() calls are
118 supported and they may or may not add contiguous memory.
119
120 * Make all blocks get allocated aligned to BLOCKSIZE (sometimes referred to
121 as 'grain size'), 64 bytes in my implementation. Reports tell us there is
122 no real gain in increasing the size of the align.
123
124 * We link *all* pieces of memory (AREAS), free or not free. We keep the list
125 in address order and thus when a FREE() occurs we know instanstly if there
126 are FREE CHUNKS wall-to-wall. No list "travels" needed. Requires some
127 extra space in every allocated BLOCK. Still needs to put the new CHUNK in
128 the right place in size-sorted list/tree. All memory areas, allocated or
129 not, contain the following header:
130 - size of this memory area
131 - FREE status
132 - pointer to the next AREA closest in memory
133 - pointer to the prev AREA closest in memory
134 (12 bytes)
135
136 * Sort all FREE CHUNKS in size-order. We use a SPLAY TREE algorithm for
137 maximum speed. Data/structs used for the size-sorting functions are kept
138 in an abstraction layer away from this since it is really not changing
139 anything (except executing speed).
140
141 ALLOC (RSIZE - requested size, aligned properly)
142
143 * Fetch a CHUNK that RSIZE fits within. If the found CHUNK is larger than
144 RSIZE, split it and return the RSIZE to the caller. Link the new CHUNK
145 into the list/tree.
146
147 FREE (AREA - piece of memory that is returned to the system)
148
149 * Since the allocated BLOCK has kept its link-pointers, we can without
150 checking any list instantly see if there are any FREE CHUNKS that are
151 wall-to-wall with the AREA (both sides). If the AREA *is* wall-to-wall
152 with one or two CHUNKS that or they are unlinked from the lists, enlarged
153 and re-linked into the lists.
154
155 REALLOC
156
157 * There IS NO realloc() of large blocks, they are performed in the higher
158 layer (dmalloc).
159
160
161##############################################################################
162 FURTHER READING
163##############################################################################
164
165 * "Dynamic Storage Allocation: A Survey and Critical Review" (Paul R. Wilson,
166 Mark S. Johnstone, Michael Neely, David Boles)
167 ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps
168
169 * "A Memory Allocator" (Doug Lea)
170 http://g.oswego.edu/dl/html/malloc.html
171 =====================================
172 Memory Allocation Algorithm Theories.
173 =====================================
174
175GOAL
176 It is intended to be a 100% working memory allocation system. It should be
177 capable of replacing an ordinary Operating System's own routines. It should
178 work good in a multitasking, shared memory, non-virtual memory environment
179 without clogging the memory. Primary aimed for small machines, CPUs and
180 memory amounts.
181
182 I use a best-fit algorithm with a slight overhead in order to increase speed
183 a lot. It should remain scalable and work good with very large amount of
184 memory and free/used memory blocks too.
185
186TERMINOLOGY
187
188 FRAGMENT - small identically sized parts of a larger BLOCK, they are when
189 travered in lists etc _not_ allocated.
190 BLOCK - large memory area, if used for FRAGMENTS, they are linked in a
191 lists. One list for each FRAGMENT size supported.
192 TOP - head struct that holds information about and points to a chain
193 of BLOCKS for a particular FRAGMENT size.
194 CHUNK - a contiguous area of free memory
195
196MEMORY SYSTEM
197
198 We split the system in two parts. One part allocates small memory amounts
199 and one part allocates large memory amounts, but all allocations are done
200 "through" the small-part-system. There is an option to use only the small
201 system (and thus use the OS for large blocks) or the complete package.
202
203##############################################################################
204 SMALL SIZE ALLOCATIONS
205##############################################################################
206
207 Keywords for this system is 'Deferred Coalescing' and 'quick lists'.
208
209 ALLOC
210
211 * Small allocations are "aligned" upwards to a set of preset sizes. In the
212 current implementation I use 20, 28, 52, 116, 312, 580, 812, 2028 bytes.
213 Memory allocations of these sizes are refered to as FRAGMENTS.
214 (The reason for these specific sizes is the requirement that they must be
215 32-bit aligned and fit as good as possible within 4060 bytes.)
216
217 * Allocations larger than 2028 will get a BLOCK for that allocation only.
218
219 * Each of these sizes has it's own TOP. When a FRAGMENT is requested, a
220 larger BLOCK will be allocated and divided into many FRAGMENTS (all of the
221 same size). TOP points to a list with BLOCKS that contains FRAGMENTS of
222 the same size. Each BLOCK has a 'number of free FRAGMENTS' counter and so
223 has each TOP (for the entire chain).
224
225 * A BLOCK is around 4060 bytes plus the size of the information header. This
226 size is adjusted to make the allocation of the big block not require more
227 than 4096 bytes. (This might not be so easy to be sure of, if you don't
228 know how the big-block system works, but the BMALLOC system uses an
229 extra header of 12 bytes and the header for the FRAGMENT BLOCK is 20 bytes
230 in a general 32-bit unix environment.)
231
232 * In case the allocation of a BLOCK fails when a FRAGMENT is required, the
233 next size of FRAGMENTS will be checked for a free FRAGMENT. First when the
234 larger size lists have been tested without success it will fail for real.
235
236 FREE
237
238 * When FRAGMENTS are freed so that a BLOCK becomes non-used, it is returned
239 to the system.
240
241 * FREEing a fragment adds the buffer in a LIFO-order. That means that the
242 next request for a fragment from the same list, the last freed buffer will
243 be returned first.
244
245 REALLOC
246
247 * REALLOCATION of a FRAGMENT does first check if the new size would fit
248 within the same FRAGMENT and if it would use the same FRAGMENT size. If it
249 does and would, the same pointer is returned.
250
251 OVERHEAD
252
253 Yes, there is an overhead on small allocations (internal fragmentation).
254 Yet, I do believe that small allocations more often than larger ones are
255 used dynamically. I believe that a large overhead is not a big problem if it
256 remains only for a while. The big gain is with the extreme speed we can GET
257 and RETURN small allocations. This has yet to be proven. I am open to other
258 systems of dealing with the small ones, but I don`t believe in using the
259 same system for all sizes of allocations.
260
261 IMPROVEMENT
262
263 An addition to the above described algorithm is the `save-empty-BLOCKS-a-
264 while-afterwards`. It will be used when the last used FRAGMENT within a
265 BLOCK is freed. The BLOCK will then not get returned to the system until "a
266 few more" FRAGMENTS have been freed in case the last [few] freed FRAGMENTS
267 are allocated yet again (and thus prevent the huge overhead of making
268 FRAGMENTS in a BLOCK). The "only" drawback of such a SEBAWA concept is
269 that it would mean an even bigger overhead...
270
271 HEADERS (in allocated data)
272
273 FRAGMENTS - 32-bit pointer to its parent BLOCK (lowest bit must be 0)
274 BLOCK - 32-bit size (lowest bit must be 1 to separate this from
275 FRAGMENTS)
276
277##############################################################################
278 LARGER ALLOCATIONS
279##############################################################################
280
281 If the requested size is larger than the largest FRAGMENT size supported,
282 the allocation will be made for this memory area alone, or if a BLOCK is
283 allocated to fit lots of FRAGMENTS a large block is also desired.
284
285 * We add memory to the "system" with the add_pool() function call. It
286 specifies the start and size of the new block of memory that will be
287 used in this memory allocation system. Several add_pool() calls are
288 supported and they may or may not add contiguous memory.
289
290 * Make all blocks get allocated aligned to BLOCKSIZE (sometimes referred to
291 as 'grain size'), 64 bytes in my implementation. Reports tell us there is
292 no real gain in increasing the size of the align.
293
294 * We link *all* pieces of memory (AREAS), free or not free. We keep the list
295 in address order and thus when a FREE() occurs we know instanstly if there
296 are FREE CHUNKS wall-to-wall. No list "travels" needed. Requires some
297 extra space in every allocated BLOCK. Still needs to put the new CHUNK in
298 the right place in size-sorted list/tree. All memory areas, allocated or
299 not, contain the following header:
300 - size of this memory area
301 - FREE status
302 - pointer to the next AREA closest in memory
303 - pointer to the prev AREA closest in memory
304 (12 bytes)
305
306 * Sort all FREE CHUNKS in size-order. We use a SPLAY TREE algorithm for
307 maximum speed. Data/structs used for the size-sorting functions are kept
308 in an abstraction layer away from this since it is really not changing
309 anything (except executing speed).
310
311 ALLOC (RSIZE - requested size, aligned properly)
312
313 * Fetch a CHUNK that RSIZE fits within. If the found CHUNK is larger than
314 RSIZE, split it and return the RSIZE to the caller. Link the new CHUNK
315 into the list/tree.
316
317 FREE (AREA - piece of memory that is returned to the system)
318
319 * Since the allocated BLOCK has kept its link-pointers, we can without
320 checking any list instantly see if there are any FREE CHUNKS that are
321 wall-to-wall with the AREA (both sides). If the AREA *is* wall-to-wall
322 with one or two CHUNKS that or they are unlinked from the lists, enlarged
323 and re-linked into the lists.
324
325 REALLOC
326
327 * There IS NO realloc() of large blocks, they are performed in the higher
328 layer (dmalloc).
329
330
331##############################################################################
332 FURTHER READING
333##############################################################################
334
335 * "Dynamic Storage Allocation: A Survey and Critical Review" (Paul R. Wilson,
336 Mark S. Johnstone, Michael Neely, David Boles)
337 ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps
338
339 * "A Memory Allocator" (Doug Lea)
340 http://g.oswego.edu/dl/html/malloc.html
diff --git a/apps/plugins/pdbox/pdbox-net.c b/apps/plugins/pdbox/pdbox-net.c
new file mode 100644
index 0000000000..5767226de3
--- /dev/null
+++ b/apps/plugins/pdbox/pdbox-net.c
@@ -0,0 +1,238 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Wincent Balin
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "plugin.h"
23#include "pdbox.h"
24
25/* Datagram pool will contains 16 datagrams. */
26#define MAX_DATAGRAMS 16
27
28/* Datagram pool. */
29struct datagram datagrams[MAX_DATAGRAMS];
30
31/* UDP message queues. */
32struct event_queue gui_to_core;
33struct event_queue core_to_gui;
34
35/* Initialize net infrastructure. */
36void net_init(void)
37{
38 unsigned int i;
39
40 /* Initialize message pool. */
41 for(i = 0; i < MAX_DATAGRAMS; i++)
42 datagrams[i].used = false;
43
44 /* Initialize and register message queues. */
45 rb->queue_init(&gui_to_core, true);
46 rb->queue_init(&core_to_gui, true);
47}
48
49/* Send datagram. */
50bool send_datagram(struct event_queue* route,
51 int port,
52 char* data,
53 size_t size)
54{
55 unsigned int i;
56
57 /* If datagram too long, abort. */
58 if(size > MAX_DATAGRAM_SIZE)
59 return false;
60
61 /* Find free datagram buffer. */
62 for(i = 0; i < MAX_DATAGRAMS; i++)
63 if(!datagrams[i].used)
64 break;
65
66 /* If no free buffer found, abort. */
67 if(i == MAX_DATAGRAMS)
68 return false;
69
70 /* Copy datagram to the buffer. */
71 rb->memcpy(datagrams[i].data, data, size);
72 datagrams[i].size = size;
73
74 /* Mark datagram buffer as used. */
75 datagrams[i].used = true;
76
77 /* Send event via route. */
78 rb->queue_post(route, port, (intptr_t) &datagrams[i]);
79
80 /* Everything went ok. */
81 return true;
82}
83
84/* Receive datagram. */
85bool receive_datagram(struct event_queue* route,
86 int port,
87 struct datagram* buffer)
88{
89 struct queue_event event;
90
91 /* If route queue empty, abort. */
92 if(rb->queue_empty(route))
93 return false;
94
95 /* Receive event. */
96 rb->queue_wait(route, &event);
97
98 /* If wrong port, abort.
99 NOTE: Event is removed from the queue in any case! */
100 if(event.id != port)
101 return false;
102
103 /* Copy datagram. */
104 rb->memcpy(buffer, (struct datagram*) event.data, sizeof(struct datagram));
105
106 /* Free datagram buffer. */
107 ((struct datagram*) event.data)->used = false;
108
109 /* Everything went ok. */
110 return true;
111}
112
113/* Destroy net infrastructure. */
114void net_destroy(void)
115{
116 /* Remove message queues. */
117 rb->queue_delete(&gui_to_core);
118 rb->queue_delete(&core_to_gui);
119}
120/***************************************************************************
121 * __________ __ ___.
122 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
123 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
124 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
125 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
126 * \/ \/ \/ \/ \/
127 * $Id$
128 *
129 * Copyright (C) 2009 Wincent Balin
130 *
131 * This program is free software; you can redistribute it and/or
132 * modify it under the terms of the GNU General Public License
133 * as published by the Free Software Foundation; either version 2
134 * of the License, or (at your option) any later version.
135 *
136 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
137 * KIND, either express or implied.
138 *
139 ****************************************************************************/
140
141#include "plugin.h"
142#include "pdbox.h"
143
144/* Datagram pool will contains 16 datagrams. */
145#define MAX_DATAGRAMS 16
146
147/* Datagram pool. */
148struct datagram datagrams[MAX_DATAGRAMS];
149
150/* UDP message queues. */
151struct event_queue gui_to_core;
152struct event_queue core_to_gui;
153
154/* Initialize net infrastructure. */
155void net_init(void)
156{
157 unsigned int i;
158
159 /* Initialize message pool. */
160 for(i = 0; i < MAX_DATAGRAMS; i++)
161 datagrams[i].used = false;
162
163 /* Initialize and register message queues. */
164 rb->queue_init(&gui_to_core, true);
165 rb->queue_init(&core_to_gui, true);
166}
167
168/* Send datagram. */
169bool send_datagram(struct event_queue* route,
170 int port,
171 char* data,
172 size_t size)
173{
174 unsigned int i;
175
176 /* If datagram too long, abort. */
177 if(size > MAX_DATAGRAM_SIZE)
178 return false;
179
180 /* Find free datagram buffer. */
181 for(i = 0; i < MAX_DATAGRAMS; i++)
182 if(!datagrams[i].used)
183 break;
184
185 /* If no free buffer found, abort. */
186 if(i == MAX_DATAGRAMS)
187 return false;
188
189 /* Copy datagram to the buffer. */
190 rb->memcpy(datagrams[i].data, data, size);
191 datagrams[i].size = size;
192
193 /* Mark datagram buffer as used. */
194 datagrams[i].used = true;
195
196 /* Send event via route. */
197 rb->queue_post(route, port, (intptr_t) &datagrams[i]);
198
199 /* Everything went ok. */
200 return true;
201}
202
203/* Receive datagram. */
204bool receive_datagram(struct event_queue* route,
205 int port,
206 struct datagram* buffer)
207{
208 struct queue_event event;
209
210 /* If route queue empty, abort. */
211 if(rb->queue_empty(route))
212 return false;
213
214 /* Receive event. */
215 rb->queue_wait(route, &event);
216
217 /* If wrong port, abort.
218 NOTE: Event is removed from the queue in any case! */
219 if(event.id != port)
220 return false;
221
222 /* Copy datagram. */
223 rb->memcpy(buffer, (struct datagram*) event.data, sizeof(struct datagram));
224
225 /* Free datagram buffer. */
226 ((struct datagram*) event.data)->used = false;
227
228 /* Everything went ok. */
229 return true;
230}
231
232/* Destroy net infrastructure. */
233void net_destroy(void)
234{
235 /* Remove message queues. */
236 rb->queue_delete(&gui_to_core);
237 rb->queue_delete(&core_to_gui);
238}
diff --git a/apps/plugins/pdbox/pdbox.c b/apps/plugins/pdbox/pdbox.c
new file mode 100644
index 0000000000..9407849352
--- /dev/null
+++ b/apps/plugins/pdbox/pdbox.c
@@ -0,0 +1,314 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Wincent Balin
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "plugin.h"
23#include "pdbox.h"
24
25/* Welcome to the PDBox plugin */
26PLUGIN_HEADER
27PLUGIN_IRAM_DECLARE
28
29/* Quit flag. */
30bool quit = false;
31
32/* Thread IDs. */
33unsigned int core_thread_id;
34unsigned int gui_thread_id;
35
36/* Stacks for threads. */
37#define STACK_SIZE 16384
38uint32_t core_stack[STACK_SIZE / sizeof(uint32_t)];
39uint32_t gui_stack[STACK_SIZE / sizeof(uint32_t)];
40
41
42/* Core thread */
43void core_thread(void)
44{
45 struct datagram ping;
46
47 /* Main loop */
48 while(!quit)
49 {
50 /* Wait for request. */
51 while(!RECEIVE_TO_CORE(&ping))
52 rb->yield();
53
54 if(memcmp("Ping!", ping.data, ping.size) == 0)
55 {
56 SEND_FROM_CORE("Pong!");
57 break;
58 }
59
60 rb->yield();
61 }
62
63 rb->thread_exit();
64}
65
66/* GUI thread */
67void gui_thread(void)
68{
69 struct datagram pong;
70
71 /* GUI loop */
72 while(!quit)
73 {
74 /* Send ping to the core. */
75 SEND_TO_CORE("Ping!");
76 rb->splash(HZ, "Sent ping.");
77
78 /* Wait for answer. */
79 while(!RECEIVE_FROM_CORE(&pong))
80 rb->yield();
81
82 /* If got a pong -- everything allright. */
83 if(memcmp("Pong!", pong.data, pong.size) == 0)
84 {
85 rb->splash(HZ, "Got pong!");
86 quit = true;
87 break;
88 }
89
90 rb->yield();
91 }
92
93 rb->thread_exit();
94}
95
96
97/* Plug-in entry point */
98enum plugin_status plugin_start(const void* parameter)
99{
100 PLUGIN_IRAM_INIT(rb)
101
102 size_t mem_size;
103 void* mem_pool;
104
105 /* Get the file name. */
106 const char* filename = (const char*) parameter;
107
108#if 0
109 /* Allocate memory; check it's size; add to the pool. */
110 mem_pool = rb->plugin_get_audio_buffer(&mem_size);
111 if(mem_size < MIN_MEM_SIZE)
112 {
113 rb->splash(HZ, "Not enough memory!");
114 return PLUGIN_ERROR;
115 }
116 add_pool(mem_pool, mem_size);
117#endif
118
119 /* Initialze net. */
120 net_init();
121
122 /* Start threads. */
123 core_thread_id =
124 rb->create_thread(&core_thread,
125 core_stack,
126 sizeof(core_stack),
127 0, /* FIXME Which flags? */
128 "PD core"
129 IF_PRIO(, MAX(PRIORITY_USER_INTERFACE / 2,
130 PRIORITY_REALTIME + 1))
131 IF_COP(, COP));
132 gui_thread_id =
133 rb->create_thread(&gui_thread,
134 gui_stack,
135 sizeof(gui_stack),
136 0, /* FIXME Which flags? */
137 "PD GUI"
138 IF_PRIO(, PRIORITY_USER_INTERFACE)
139 IF_COP(, CPU));
140
141 /* If having an error creating threads, bail out. */
142 if(core_thread_id == 0 || gui_thread_id == 0)
143 return PLUGIN_ERROR;
144
145 /* Wait for quit flag. */
146 while(!quit)
147 rb->yield();
148
149 /* Wait for threads to complete. */
150 rb->thread_wait(gui_thread_id);
151 rb->thread_wait(core_thread_id);
152
153 /* Destroy net. */
154 net_destroy();
155
156 return PLUGIN_OK;
157}
158/***************************************************************************
159 * __________ __ ___.
160 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
161 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
162 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
163 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
164 * \/ \/ \/ \/ \/
165 * $Id$
166 *
167 * Copyright (C) 2009 Wincent Balin
168 *
169 * This program is free software; you can redistribute it and/or
170 * modify it under the terms of the GNU General Public License
171 * as published by the Free Software Foundation; either version 2
172 * of the License, or (at your option) any later version.
173 *
174 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
175 * KIND, either express or implied.
176 *
177 ****************************************************************************/
178
179#include "plugin.h"
180#include "pdbox.h"
181
182/* Welcome to the PDBox plugin */
183PLUGIN_HEADER
184PLUGIN_IRAM_DECLARE
185
186/* Quit flag. */
187bool quit = false;
188
189/* Thread IDs. */
190unsigned int core_thread_id;
191unsigned int gui_thread_id;
192
193/* Stacks for threads. */
194#define STACK_SIZE 16384
195uint32_t core_stack[STACK_SIZE / sizeof(uint32_t)];
196uint32_t gui_stack[STACK_SIZE / sizeof(uint32_t)];
197
198
199/* Core thread */
200void core_thread(void)
201{
202 struct datagram ping;
203
204 /* Main loop */
205 while(!quit)
206 {
207 /* Wait for request. */
208 while(!RECEIVE_TO_CORE(&ping))
209 rb->yield();
210
211 if(memcmp("Ping!", ping.data, ping.size) == 0)
212 {
213 SEND_FROM_CORE("Pong!");
214 break;
215 }
216
217 rb->yield();
218 }
219
220 rb->thread_exit();
221}
222
223/* GUI thread */
224void gui_thread(void)
225{
226 struct datagram pong;
227
228 /* GUI loop */
229 while(!quit)
230 {
231 /* Send ping to the core. */
232 SEND_TO_CORE("Ping!");
233 rb->splash(HZ, "Sent ping.");
234
235 /* Wait for answer. */
236 while(!RECEIVE_FROM_CORE(&pong))
237 rb->yield();
238
239 /* If got a pong -- everything allright. */
240 if(memcmp("Pong!", pong.data, pong.size) == 0)
241 {
242 rb->splash(HZ, "Got pong!");
243 quit = true;
244 break;
245 }
246
247 rb->yield();
248 }
249
250 rb->thread_exit();
251}
252
253
254/* Plug-in entry point */
255enum plugin_status plugin_start(const void* parameter)
256{
257 PLUGIN_IRAM_INIT(rb)
258
259 size_t mem_size;
260 void* mem_pool;
261
262 /* Get the file name. */
263 const char* filename = (const char*) parameter;
264
265#if 0
266 /* Allocate memory; check it's size; add to the pool. */
267 mem_pool = rb->plugin_get_audio_buffer(&mem_size);
268 if(mem_size < MIN_MEM_SIZE)
269 {
270 rb->splash(HZ, "Not enough memory!");
271 return PLUGIN_ERROR;
272 }
273 add_pool(mem_pool, mem_size);
274#endif
275
276 /* Initialze net. */
277 net_init();
278
279 /* Start threads. */
280 core_thread_id =
281 rb->create_thread(&core_thread,
282 core_stack,
283 sizeof(core_stack),
284 0, /* FIXME Which flags? */
285 "PD core"
286 IF_PRIO(, MAX(PRIORITY_USER_INTERFACE / 2,
287 PRIORITY_REALTIME + 1))
288 IF_COP(, COP));
289 gui_thread_id =
290 rb->create_thread(&gui_thread,
291 gui_stack,
292 sizeof(gui_stack),
293 0, /* FIXME Which flags? */
294 "PD GUI"
295 IF_PRIO(, PRIORITY_USER_INTERFACE)
296 IF_COP(, CPU));
297
298 /* If having an error creating threads, bail out. */
299 if(core_thread_id == 0 || gui_thread_id == 0)
300 return PLUGIN_ERROR;
301
302 /* Wait for quit flag. */
303 while(!quit)
304 rb->yield();
305
306 /* Wait for threads to complete. */
307 rb->thread_wait(gui_thread_id);
308 rb->thread_wait(core_thread_id);
309
310 /* Destroy net. */
311 net_destroy();
312
313 return PLUGIN_OK;
314}
diff --git a/apps/plugins/pdbox/pdbox.h b/apps/plugins/pdbox/pdbox.h
new file mode 100644
index 0000000000..d5e9a0f74d
--- /dev/null
+++ b/apps/plugins/pdbox/pdbox.h
@@ -0,0 +1,142 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Wincent Balin
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef PDBOX_H
23#define PDBOX_H
24
25#if 0
26/* Use dbestfit. */
27#include "bmalloc.h"
28#include "dmalloc.h"
29#endif
30
31/* Minimal memory size. */
32#define MIN_MEM_SIZE (4 * 1024 * 1024)
33
34/* Maximal size of the datagram. */
35#define MAX_DATAGRAM_SIZE 255
36
37/* This structure replaces a UDP datagram. */
38struct datagram
39{
40 bool used;
41 uint8_t size;
42 char data[MAX_DATAGRAM_SIZE];
43};
44
45/* Network functions prototypes. */
46void net_init(void);
47void net_destroy(void);
48bool send_datagram(struct event_queue* route, int port,
49 char* data, size_t size);
50bool receive_datagram(struct event_queue* route, int port,
51 struct datagram* buffer);
52
53/* Network message queues. */
54extern struct event_queue gui_to_core;
55extern struct event_queue core_to_gui;
56
57/* UDP ports of the original software. */
58#define PD_CORE_PORT 3333
59#define PD_GUI_PORT 3334
60
61/* Convinience macros. */
62#define SEND_TO_CORE(data) \
63 send_datagram(&gui_to_core, PD_CORE_PORT, data, rb->strlen(data))
64#define RECEIVE_TO_CORE(buffer) \
65 receive_datagram(&gui_to_core, PD_CORE_PORT, buffer)
66#define SEND_FROM_CORE(data) \
67 send_datagram(&core_to_gui, PD_GUI_PORT, data, rb->strlen(data))
68#define RECEIVE_FROM_CORE(buffer) \
69 receive_datagram(&core_to_gui, PD_GUI_PORT, buffer)
70
71#endif
72/***************************************************************************
73 * __________ __ ___.
74 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
75 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
76 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
77 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
78 * \/ \/ \/ \/ \/
79 * $Id$
80 *
81 * Copyright (C) 2009 Wincent Balin
82 *
83 * This program is free software; you can redistribute it and/or
84 * modify it under the terms of the GNU General Public License
85 * as published by the Free Software Foundation; either version 2
86 * of the License, or (at your option) any later version.
87 *
88 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
89 * KIND, either express or implied.
90 *
91 ****************************************************************************/
92
93#ifndef PDBOX_H
94#define PDBOX_H
95
96#if 0
97/* Use dbestfit. */
98#include "bmalloc.h"
99#include "dmalloc.h"
100#endif
101
102/* Minimal memory size. */
103#define MIN_MEM_SIZE (4 * 1024 * 1024)
104
105/* Maximal size of the datagram. */
106#define MAX_DATAGRAM_SIZE 255
107
108/* This structure replaces a UDP datagram. */
109struct datagram
110{
111 bool used;
112 uint8_t size;
113 char data[MAX_DATAGRAM_SIZE];
114};
115
116/* Network functions prototypes. */
117void net_init(void);
118void net_destroy(void);
119bool send_datagram(struct event_queue* route, int port,
120 char* data, size_t size);
121bool receive_datagram(struct event_queue* route, int port,
122 struct datagram* buffer);
123
124/* Network message queues. */
125extern struct event_queue gui_to_core;
126extern struct event_queue core_to_gui;
127
128/* UDP ports of the original software. */
129#define PD_CORE_PORT 3333
130#define PD_GUI_PORT 3334
131
132/* Convinience macros. */
133#define SEND_TO_CORE(data) \
134 send_datagram(&gui_to_core, PD_CORE_PORT, data, rb->strlen(data))
135#define RECEIVE_TO_CORE(buffer) \
136 receive_datagram(&gui_to_core, PD_CORE_PORT, buffer)
137#define SEND_FROM_CORE(data) \
138 send_datagram(&core_to_gui, PD_GUI_PORT, data, rb->strlen(data))
139#define RECEIVE_FROM_CORE(buffer) \
140 receive_datagram(&core_to_gui, PD_GUI_PORT, buffer)
141
142#endif
diff --git a/apps/plugins/pdbox/pdbox.make b/apps/plugins/pdbox/pdbox.make
new file mode 100644
index 0000000000..f1b1e7efef
--- /dev/null
+++ b/apps/plugins/pdbox/pdbox.make
@@ -0,0 +1,62 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10PDBOXSRCDIR := $(APPSDIR)/plugins/pdbox
11PDBOXBUILDDIR := $(BUILDDIR)/apps/plugins/pdbox
12
13ROCKS += $(PDBOXBUILDDIR)/pdbox.rock
14
15PDBOXSRC := $(call preprocess, $(PDBOXSRCDIR)/SOURCES)
16PDBOXOBJ := $(call c2obj, $(PDBOXSRC))
17
18# add source files to OTHERSRC to get automatic dependencies
19OTHERSRC += $(PDBOXSRC)
20
21$(PDBOXBUILDDIR)/pdbox.rock: $(PDBOXOBJ)
22
23PDBOXFLAGS = $(PLUGINFLAGS) \
24 -DFIXEDPOINT -DSTATIC -DPD \
25 -I$(PDBOXSRCDIR) -I$(PDBOXSRCDIR)/PDa/src \
26 -DBMALLOC -I$(PDBOXSRCDIR)/dbestfit-3.3
27
28# Compile PDBox with extra flags (adapted from ZXBox)
29$(PDBOXBUILDDIR)/%.o: $(PDBOXSRCDIR)/%.c $(PDBOXSRCDIR)/pdbox.make
30 $(SILENT)mkdir -p $(dir $@)
31 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(PDBOXFLAGS) -c $< -o $@
32# __________ __ ___.
33# Open \______ \ ____ ____ | | _\_ |__ _______ ___
34# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
35# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
36# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
37# \/ \/ \/ \/ \/
38# $Id$
39#
40
41PDBOXSRCDIR := $(APPSDIR)/plugins/pdbox
42PDBOXBUILDDIR := $(BUILDDIR)/apps/plugins/pdbox
43
44ROCKS += $(PDBOXBUILDDIR)/pdbox.rock
45
46PDBOXSRC := $(call preprocess, $(PDBOXSRCDIR)/SOURCES)
47PDBOXOBJ := $(call c2obj, $(PDBOXSRC))
48
49# add source files to OTHERSRC to get automatic dependencies
50OTHERSRC += $(PDBOXSRC)
51
52$(PDBOXBUILDDIR)/pdbox.rock: $(PDBOXOBJ)
53
54PDBOXFLAGS = $(PLUGINFLAGS) \
55 -DFIXEDPOINT -DSTATIC -DPD \
56 -I$(PDBOXSRCDIR) -I$(PDBOXSRCDIR)/PDa/src \
57 -DBMALLOC -I$(PDBOXSRCDIR)/dbestfit-3.3
58
59# Compile PDBox with extra flags (adapted from ZXBox)
60$(PDBOXBUILDDIR)/%.o: $(PDBOXSRCDIR)/%.c $(PDBOXSRCDIR)/pdbox.make
61 $(SILENT)mkdir -p $(dir $@)
62 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(PDBOXFLAGS) -c $< -o $@
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index fdb700f69d..3bbc4f160b 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -14,8 +14,9 @@ gb,viewers/rockboy,6
14gbc,viewers/rockboy,6 14gbc,viewers/rockboy,6
15sgb,viewers/rockboy,6 15sgb,viewers/rockboy,6
16m3u,viewers/iriverify,- 16m3u,viewers/iriverify,-
17mid,viewers/midi,7 17mid,viewers/midi,7
18rmi,viewers/midi,7 18rmi,viewers/midi,7
19pd,apps/pdbox,2
19rsp,viewers/searchengine,8 20rsp,viewers/searchengine,8
20sok,games/sokoban,1 21sok,games/sokoban,1
21pgn,games/chessbox,1 22pgn,games/chessbox,1