diff --git a/configure.ac b/configure.ac index 855a6b030c..48137361da 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ ##### Prelude ##### AC_PREREQ(2.59) -AC_INIT([pd], [0.55.2]) +AC_INIT([pd], [0.56.0]) AC_CONFIG_SRCDIR(src/m_pd.c) AC_CONFIG_AUX_DIR([m4/config]) AC_CONFIG_MACRO_DIR([m4/generated]) diff --git a/doc/1.manual/resources/2.1.10.png b/doc/1.manual/resources/2.1.10.png index 749cade95c..e9c0f4b297 100644 Binary files a/doc/1.manual/resources/2.1.10.png and b/doc/1.manual/resources/2.1.10.png differ diff --git a/doc/1.manual/resources/2.1.11.png b/doc/1.manual/resources/2.1.11.png index 4d1ddc8a4e..749cade95c 100644 Binary files a/doc/1.manual/resources/2.1.11.png and b/doc/1.manual/resources/2.1.11.png differ diff --git a/doc/1.manual/resources/2.1.12.png b/doc/1.manual/resources/2.1.12.png index c2274efb36..4d1ddc8a4e 100644 Binary files a/doc/1.manual/resources/2.1.12.png and b/doc/1.manual/resources/2.1.12.png differ diff --git a/doc/1.manual/resources/2.1.13.png b/doc/1.manual/resources/2.1.13.png index 0b086a93d0..c2274efb36 100644 Binary files a/doc/1.manual/resources/2.1.13.png and b/doc/1.manual/resources/2.1.13.png differ diff --git a/doc/1.manual/resources/2.1.14.png b/doc/1.manual/resources/2.1.14.png index ceb0768d62..0b086a93d0 100644 Binary files a/doc/1.manual/resources/2.1.14.png and b/doc/1.manual/resources/2.1.14.png differ diff --git a/doc/1.manual/resources/2.1.15.png b/doc/1.manual/resources/2.1.15.png new file mode 100644 index 0000000000..ceb0768d62 Binary files /dev/null and b/doc/1.manual/resources/2.1.15.png differ diff --git a/doc/1.manual/resources/2.1.8.png b/doc/1.manual/resources/2.1.8.png index 3c678eb946..5ed1f05683 100644 Binary files a/doc/1.manual/resources/2.1.8.png and b/doc/1.manual/resources/2.1.8.png differ diff --git a/doc/1.manual/resources/2.1.9.png b/doc/1.manual/resources/2.1.9.png index e9c0f4b297..3c678eb946 100644 Binary files a/doc/1.manual/resources/2.1.9.png and b/doc/1.manual/resources/2.1.9.png differ diff --git a/doc/1.manual/resources/chapter2.htm b/doc/1.manual/resources/chapter2.htm index d7e2582ea1..bb92a901b2 100644 --- a/doc/1.manual/resources/chapter2.htm +++ b/doc/1.manual/resources/chapter2.htm @@ -123,16 +123,29 @@

2.1.1. The main window, canvases, and printo
Fig. 2.1.7 The log level popup menu
-

Errors are mostly printed by objects and displayed in the Pd window in red color. +

Errors are mostly printed by objects and displayed in the Pd window in red color. You can find error sources for the corresponding line with Ctrl+click -as shown in here). +or through the context menu on right click as shown below. Alternatively, you can use the +"Find Last Error" entry in the Find menu for this. + +

Note that you can also find objects printing regular log outputs via right click or +Ctrl+click in many cases (a cursor change will signalize this option +when hovering the log lines). + +

In cases of objects that couldn't be created, the context menu also contains a +"Find externals" option that will open deken with a prefilled search field. + +

+ find error +
Fig. 2.1.8Find error source via right click
+
-

If the Pd window is focused, the font size for menus and printout can be changed +

If the Pd window is focused, the font size for menus and printout can be changed using the "Font" dialog entry in the Edit menu.

-edit menu -
Fig. 2.1.8 The Edit menu
+edit menu +
Fig. 2.1.9 The Edit menu

Make your adjustments in the Font dialog window and increase the size if you are @@ -140,8 +153,8 @@

2.1.1. The main window, canvases, and printo that only works for Pd documents.
-font settings -
Fig. 2.1.9 The Font settings dialog
+font settings +
Fig. 2.1.10 The Font settings dialog

Pd documents (called "patches" or "canvases") have their own main window and any number of @@ -159,8 +172,8 @@

2.1.1. The main window, canvases, and printo Note that the Zoom setting is not saved in the patch though.
-zoomed in and out -
Fig. 2.1.10 A patch in standard and zoomed state
+zoomed in and out +
Fig. 2.1.11 A patch in standard and zoomed state

In the Edit menu, you can also clear all messages printed in the Pd window with @@ -179,8 +192,8 @@

2.1.2. Object boxes

and presented with a dashed border before creation.
-dashed box -
Fig. 2.1.11 An uncreated object box
+dashed box +
Fig. 2.1.12 An uncreated object box

You only create a particular object after you entered text into the @@ -191,8 +204,8 @@

2.1.2. Object boxes

"+ 13".
-object box -
Fig. 2.1.12 A created object box
+object box +
Fig. 2.1.13 A created object box

Here, the "+" specifies the class of the object. In this case the @@ -220,8 +233,8 @@

2.1.2. Object boxes

synthesizes a pure tone:
-simple MIDI synthesizer -
Fig. 2.1.13 A simple MIDI synthesizer
+simple MIDI synthesizer +
Fig. 2.1.14 A simple MIDI synthesizer

This patch mixes control objects ([notein], [stripnote], @@ -281,8 +294,8 @@

2.1.3. Message and GUI boxes

connected object box, which adds 13 to it.
-Different box shapes -
Fig. 2.1.14 Different box shapes
+Different box shapes +
Fig. 2.1.15 Different box shapes

The third box here is a GUI ("graphical user interface") box. Pd has @@ -381,8 +394,8 @@

2.2.1. Edit and run mode

they can't be resized in edit mode with the mouse cursor.

If you are predominantly editing a patch, but would like to quickly switch to -run mode just to click on something like a message, you can press and hold the -Ctrl to temporarily switch to edit mode until you release it. +run mode just to click on something like a message, you can press and hold +Ctrl to temporarily switch to run mode until you release it.

In the Edit menu you also find "Undo" and "Redo" operations, which revert and recreate changes you've done in your patch while in edit mode. Note that you can @@ -997,39 +1010,47 @@

2.4.1. Message types (selectors) and numerica and start with decimal digits.

Number atoms are always of type float, meaning that Pd does not have an -integer number type. Numbers in Pd may also be written in exponential -notation, such as "4.5e+06", which means 4.5*106, resulting in -4'500'000. Negative exponents also work, such as 1.5e-06, which -means 1.5*10−6 and results in 0.0000015. +integer number type. Numbers in Pd are formatted with the '%g' pattern from +the 'sprintf' function, with a precision of '6'. This allows formatting numbers +with and without exponential (or scientific) notation. One example of this notation +is "4.5e+06", which means 4.5*106, resulting in 4'500'000. +Negative exponents also work, such as 1.5e-06, which means 1.5*10−6 +and results in 0.0000015.

Depending on their value, numbers are displayed either in decimal or exponential -notation. You'll only see up to three zeros after the decimal point before the -first non-zero digit. For instance, "0.0001". If you add another zero, Pd turns it +notation. For negative exponential notation, the exponent number needs to be '-5' +or lower. This means you'll only see up to three zeros after the decimal point before +the first non-zero digit. For instance, "0.0001". If you add another zero, Pd turns it into exponential notation for display, so "0.00001" becomes "1e-05". Conversely, if you type "1e-04", Pd converts it to "0.0001" for display. -

Other than this, Pd only displays 6 significant digits. This means that you can have -"100000", but adding another zero will switch the representation to "1e+06". Similarly, -typing "1e+05" results in "100000". +

As for positive exponent numbers, the scientific notation is only used if the +exponent value is '6' or higher. '6' is also the default numeric precision, so Pd +only displays 6 significant digits. This means that you can have "100000", but +adding another zero will switch the representation to "1e+06". Similarly, typing +"1e+05" results in "100000". -

Having 6 significant digits means that numbers are rounded. You can display -"0.000123456", which has 6 significant digits, but adding another digit as in -"0.0001234567" forces Pd to round it to "0.000123457". Now, adding another zero -before the first significant digit turns this into exponential notation as -"1.23456e-05", keeping the display of the 6 significant digits. Similarly to -the earlier example, "1.234567e-05" becomes "1.23457e-05". The 7th significant +

Having a 6 digit precision means that numbers are rounded. The 7th significant digit is rounded in a way that "0.9999994" or less becomes "0.999999" and -"0.9999995" or higher becomes "1". +"0.9999995" or higher becomes "1". You can display "0.000123456", which has 6 +significant digits, but adding another digit as in "0.0001234567" forces Pd to +round it to "0.000123457". If instead you add another zero before the first +significant digit, it turns it into exponential notation as "1.23456e-05", +keeping the display of the 6 significant digits. Similarly to the earlier example, +"1.234567e-05" becomes "1.23457e-05". + +

Trailing zeros are not displayed in Pd, and no decimal point is shown if there's +no fractional part of the number. So if you type 1., it becomes "1".

Don't mistake the display precision and rounding with the actual floating point precision though. If compiled for single precision, numbers in Pd are handled as 32-bit floats, which allows you to represent any integer with 7 digits or less, even though Pd will only display 6. -

Note that the display resolution remains the same when Pure Data is compiled for double -precision, even though the resolution is much higher in Pd64. Since Pure Data has no -integer data type, the range of representable integer numbers depends on the float -precision. The integer range is shown below for single and double precision. +

Note that the display resolution remains the same when Pure Data is compiled for +double precision, even though the resolution is much higher in Pd64. Since Pure Data +has no integer data type, the range of representable integer numbers depends on the +float precision. The integer range is shown below for single and double precision.

@@ -1104,15 +1125,14 @@

2.4.2. Depth first message passing

infinite loop -
Fig. 2.4.7 An infinite loop (stack overflow)
+
Fig. 2.4.7 An infinite loop (stack overflow)

Here, the left-hand [+ 1] can't finish processing until the right-hand one has been sent the result "2", which can't finish processing until the left-hand one has been sent "3", and so on. This generates a "stack overflow" error (meaning there's -an infinite loop) in the Pd window that you can Ctrl+click -on (as described earlier) to select the causing object. Note that you can also use the -"Find Last Error" entry in the Find menu for this. +an infinite loop) in the Pd window that you can interact with (as described +earlier) to select the causing object.

find error source @@ -1287,8 +1307,8 @@

2.5.1. Sample rate and format

you have all the dynamic range you could want. However, depending on your hardware, audio I/O is usually limited to 16 or 24 bits. Inputs all appear between the values of -1 and 1; and output values will be clipped to that range. -Pd assumes a sample rate of 44100 unless you override this (in Pd's command line -or in the "audio setup" dialog). +Pd runs at a sample rate of 48000 unless you override this (in Pd's command line +or in an "audio setup" or "preferences" dialog window).

Pd can read or write samples to files either in 16-bit or 24-bit fixed point or in 32-bit floating point, in 'wave', 'aiff', 'caf', and 'next' formats via @@ -1298,13 +1318,13 @@

2.5.1. Sample rate and format

2.5.2. Tilde objects and audio connections

Audio computations in Pd are carried out by "tilde objects" such as -[osc~], whose names conventionally end with a tilde character -(which resembles a sinusoid, symbolizing their function in handling audio signals). -Tilde objects can intercommunicate via audio connections. When audio computation is -turned on or when you change the audio network while audio is on, Pd sorts all the -tilde objects into a linear order for running; this linear list is then by default -run down in blocks of 64 samples each at 44100 Hz. this means the audio network runs -every 1.45 milliseconds. +[osc~], whose names conventionally end with a tilde character (which +resembles a sinusoid, symbolizing their function in handling audio signals). +Tilde objects can intercommunicate via audio connections. When audio computation +is turned on or when you change the audio network while audio is on, Pd sorts +all the tilde objects into a linear order for running; this linear list is then +by default run down in blocks of 64 samples each at 48000 Hz. The +audio network then runs every 1-1/3 (about 1.33) milliseconds.

Inlets or outlets are configured in Pd either for messages or audio. You can't connect an audio outlet to a non-audio inlet. An object's leftmost inlet may accept @@ -1466,7 +1486,7 @@

2.6.1. Audio and messages

Audio and message processing are interleaved in Pd. Audio processing is scheduled every block (64 samples by default) at Pd's sample rate, which -is 44100 Hz by default and results in a period of approximately 1.45 +is 48000 Hz by default and results in a period of approximately 1.33 milliseconds. You may turn DSP computation on and off in a patch by sending the messages "dsp 1" and "dsp 0" to "pd". diff --git a/doc/1.manual/resources/chapter5.htm b/doc/1.manual/resources/chapter5.htm index 4b392b7db4..09752a724b 100644 --- a/doc/1.manual/resources/chapter5.htm +++ b/doc/1.manual/resources/chapter5.htm @@ -25,6 +25,62 @@

Chapter 5: Current status

5.1. Release notes

+

0.56-0

+ +

The dafault sample rate is now 48000. (All the same sample rates as before +are still supported).

+ +

Reworked text editing mechanism for object/message/gatom/comment boxes and +applied it also for text fields in scalars (aka "data structures"). It is now +reasonably feasible to use data structures to hold messages or sequences of +messages. Also methods "get" and "set" added to the pointer object make it much +easier to traverse the contents of a scalar; and "nearest" and extended "next" +messages that make it easier to search for a scalar or scan through a list of +them. A variant of the pointer object called "vpointer" allows to access the +same pointer by name from more than one place, like the value object for +numnbers. There are several other useful additions such as the ability to drag +scalars around without having to swap the window into edit mode.

+ +

Multichannel support for delread~, etc., tabread~, etc., sig~, snapshot~, +and print~, all thanks to +Christof Ressi

+ +

a phase argument to block~ allows you to explicitly offset block segmentation +(also Christof)

+ +

Ticks and labels on graphs are now saved with the graph, and run-time +messages added to show/hide the name, and make editable or not (Hannes).

+ +

A new "colors" message to "pd" allows changing the foreground, background, and +selection colors. Colors are specified X-style, so "white", "black", etc., are +OK but you can also say "#ffffff" for white, ##ff0000" for bright red, and +so on. This is not yet incorporated in Pd's preferences as it certainly +should be.

+ +

updates to the "deken" ("find externals") mechanism.

+ +

Menus cleanup (Hannes)

+ +

It's now possible to edit the text contents of a GOP with hidden text from +its properties dialog.

+ +

New "-devicename" argument to set jack's MID and audio device names +(-jackname still works for jack audio devices but not for MIDI as before).

+ +

New option for the "bag" object to prevent multiple entries of the same +value, and a "bang" message to output without clearning, plus a "query" message +to look at contents without expelling them.

+ +

The "random" object takes a "float" message that both sets the range and +generates an output.

+ +

Shebang support: it's optionally allowed to put a header like "#/bin/pd" in a +patch file so that you can click on it and have that start Pd.

+ +

New "vis" message to Pd to start/stop the gui.

+ +

Improvements to mouse handling in MacOS (Ben Wesch).

+

0.55-2

Bug fixes in jack - 16+ channels crashed in linux; auto-connect improved to diff --git a/doc/2.control.examples/16.more.arrays.pd b/doc/2.control.examples/16.more.arrays.pd index 1fd18bd411..e50a9aef9e 100644 --- a/doc/2.control.examples/16.more.arrays.pd +++ b/doc/2.control.examples/16.more.arrays.pd @@ -1,19 +1,18 @@ -#N canvas 358 50 930 745 12; +#N canvas 158 37 1074 752 12; #X text 105 13 MORE ON ARRAYS; -#X obj 644 398 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 1; -#X msg 644 425 \; array98 vis \$1; +#X obj 522 231 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 1; +#X msg 522 258 \; array98 vis \$1; #X msg 548 683 \; array98 style \$1; -#X floatatom 536 454 4 1 10 0 - - - 0; -#X floatatom 738 511 5 0 0 0 - - - 0; -#X msg 738 537 \; array98 color \$1; -#X msg 738 481 9, f 2; -#X msg 769 481 900; +#X floatatom 529 460 4 1 10 0 - - - 0; +#X floatatom 741 512 5 0 0 0 - - - 0; +#X msg 741 538 \; array98 color \$1; +#X msg 741 482 9, f 2; +#X msg 770 482 900; #X text 36 138 set array values from index 0; #X text 309 129 sets two values from index 3, f 17; #X text 30 39 Arrays have methods to set their values explicitly. Below you can set their "bounds" rectangles \, rename them (but if you have two with the same name this won't necessarily do what you want) and add markings. To set values by message \, send a list whose first element gives the index to start at. Indices count up from zero., f 66; #X msg 28 166 \; array98 0 -1 1 -1 1 -1 1 -1; -#X text 516 399 show/hide arrays:; -#X text 783 511 set color; +#X text 786 512 set color; #X floatatom 548 653 5 0 0 0 - - - 0; #X msg 302 166 \; array97 3 -0.5 0.5; #X msg 27 234 \; array97 rename george; @@ -22,11 +21,13 @@ #X msg 29 416 \; array97 xticks 0 1 1; #X msg 222 415 \; array97 yticks 0 0.1 5; #X msg 304 515 \; array97 ylabel -0.1 -1 0 1; -#X msg 766 424 \; array97 vis \$1; +#X msg 523 325 \; array97 vis \$1; #N canvas 162 212 568 393 locality 0; #N canvas 0 22 450 278 (subpatch) 0; #X array \$0-array 10 float 3; #A 0 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5; +#A color 0; +#A width 2; #X coords 0 1 10 -1 200 140 1; #X restore 68 112 graph; #X obj 401 170 send \$0-array; @@ -51,40 +52,57 @@ #X text 26 285 setting the bounds rectangle; #X text 103 476 adding labels: give a y value and a bunch of x values or vice versa, f 37; #X text 25 363 adding x and y labels: give a point to put a tick \, the interval between ticks \, and the number of ticks overall per large tick; -#X obj 766 398 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 1; +#X obj 523 299 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 1; #X obj 548 587 vradio 19 1 0 3 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0; #X text 572 587 Point (0); #X text 572 606 Polygon (1); #X text 572 626 Bezier (2); #X text 542 557 set display style:; -#X obj 549 37 cnv 19 298 148 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; +#X obj 694 206 cnv 19 298 148 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; #N canvas 0 50 450 250 (subpatch) 0; -#X array array97 5 float 1; +#X array array97 5 float 9; #A 0 0.486666 0.126666 0.566675 -0.5 0.5; -#X array array98 7 float 1; +#A color 0; +#A width 1; +#X array array98 7 float 9; #A 0 -1 1 -1 1 -1 1 -1; +#A color 900; +#A width 1; #X coords 0 1 7 -1 300 150 1 0 0; -#X restore 548 36 graph; -#X text 507 329 For last \, there are methods to change the visual appearance of arrays (and you can use a canvas [cnv] to set background color as in this example):, f 52; -#X msg 680 481 444; +#X restore 693 205 graph; +#X text 507 130 For last \, there are methods to change the visual appearance of arrays (and you can use a canvas [cnv] to set background color as in this example):, f 67; +#X msg 683 482 444; #X msg 255 305 \; array97 bounds 0 1 7 -1; -#X msg 712 481 0, f 2; -#X text 574 449 line width, f 5; +#X msg 715 482 0, f 2; +#X text 562 461 line width; #X msg 418 683 \; array97 style \$1; -#X msg 536 491 \; array97 width \$1 \; array98 width \$1; +#X msg 529 491 \; array97 width \$1 \; array98 width \$1; #X text 102 679 open subpatch for local array names -->, f 21; -#X text 507 211 You can put more than one array in a single "graph" (which is Pd's name for the bounding rectangle \, and is a synonym for "canvas".) In this case you need to click on an exact point of one of the arrays to drag and change values. Note that arrays' sizes need not match the bounds of the containing graph. But if you have only one array in a graph and resize it \, the graph is automatically reset to match its bounds., f 52; +#X text 507 22 You can put more than one array in a single "graph" (which is Pd's name for the bounding rectangle \, and is a synonym for "canvas".) In this case you need to click on an exact point of one of the arrays to drag and change values. Note that arrays' sizes need not match the bounds of the containing graph. But if you have only one array in a graph and resize it \, the graph is automatically reset to match its bounds., f 67; #X msg 20 515 \; array97 xlabel -1.075 0 1 2 3 4 5 6 7; +#X obj 672 378 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 1; +#X obj 830 378 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 1; +#X msg 672 405 \; array98 visname \$1; +#X msg 830 404 \; array97 visname \$1; +#X text 510 198 show/hide arrays:; +#X text 568 395 show/hide array names:, f 12; +#X obj 904 639 tgl 19 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X msg 904 669 \; array98 keep \$1; +#X text 906 591 Change "save contents" flag, f 14; +#X text 885 476 Colors are set in the same way as othe data structures. The first digit is Red \, the second is Green and the third is Blue., f 22; #X connect 1 0 2 0; -#X connect 4 0 49 0; +#X connect 4 0 48 0; #X connect 5 0 6 0; #X connect 7 0 5 0; #X connect 8 0 5 0; -#X connect 15 0 3 0; -#X connect 15 0 48 0; -#X connect 25 0 29 0; -#X connect 26 0 29 0; -#X connect 35 0 23 0; -#X connect 36 0 15 0; -#X connect 44 0 5 0; -#X connect 46 0 5 0; +#X connect 14 0 3 0; +#X connect 14 0 47 0; +#X connect 24 0 28 0; +#X connect 25 0 28 0; +#X connect 34 0 22 0; +#X connect 35 0 14 0; +#X connect 43 0 5 0; +#X connect 45 0 5 0; +#X connect 52 0 54 0; +#X connect 53 0 55 0; +#X connect 58 0 59 0; diff --git a/doc/3.audio.examples/A04.line2.pd b/doc/3.audio.examples/A04.line2.pd index 9a00a03a77..b574a539c3 100644 --- a/doc/3.audio.examples/A04.line2.pd +++ b/doc/3.audio.examples/A04.line2.pd @@ -5,16 +5,16 @@ #X obj 247 382 line~; #X obj 247 351 r to-line; #N canvas 0 22 450 278 (subpatch) 0; -#X array product 44100 float 0; -#X coords 0 1.02 44100 -1.02 200 130 1; +#X array product 48000 float 0; +#X coords 0 1.02 48000 -1.02 200 130 1; #X restore 543 368 graph; #N canvas 0 22 450 278 (subpatch) 0; -#X array oscillator 44100 float 0; -#X coords 0 1.02 44100 -1.02 200 130 1 0 0; +#X array oscillator 48000 float 0; +#X coords 0 1.02 48000 -1.02 200 130 1 0 0; #X restore 543 38 graph; #N canvas 0 22 450 278 (subpatch) 0; -#X array line-output 44100 float 0; -#X coords 0 1.02 44100 -1.02 200 130 1; +#X array line-output 48000 float 0; +#X coords 0 1.02 48000 -1.02 200 130 1; #X restore 543 203 graph; #X obj 229 476 *~ 0.1; #X obj 337 434 tabwrite~ line-output; diff --git a/doc/3.audio.examples/B07.sampler.scratch.pd b/doc/3.audio.examples/B07.sampler.scratch.pd index d7603880e3..c2084f31c2 100644 --- a/doc/3.audio.examples/B07.sampler.scratch.pd +++ b/doc/3.audio.examples/B07.sampler.scratch.pd @@ -26,7 +26,7 @@ #X text 515 368 --- 44103 samples ---; #X obj 66 23 cnv 5 5 25 empty empty Scratch\ Machine 15 13 0 16 #dfdfdf #202020 0; #X text 490 517 message to read a soundfile into the table., f 27; -#X msg 91 357 0 \, 44100 1000; +#X msg 91 357 0 \, 48000 1000; #X obj 72 419 +~ 1; #X text 39 70 This patch implements a simples scratch machine with [tabread4~] \, which reads audio samples out of a floating-point array \, often called a "sample table." The input is the index of the sample to read. The output is calculated using 4-point cubic interpolation \, which is adequate for most purposes. Because of the interpolation scheme \, [tabread4~]'s input cannot be less than one or greater than the table length minus two., f 96; #X text 490 397 (one second plus three extra for 4-point interpolation), f 28; diff --git a/doc/3.audio.examples/B10.sampler.sliding.loop.pd b/doc/3.audio.examples/B10.sampler.sliding.loop.pd index 8d31e29e18..f9d3e5e44e 100644 --- a/doc/3.audio.examples/B10.sampler.sliding.loop.pd +++ b/doc/3.audio.examples/B10.sampler.sliding.loop.pd @@ -7,7 +7,7 @@ #X obj 435 399 adc~ 1; #N canvas 0 0 450 300 (subpatch) 0; #X array graph19 22050 float 0; -#X coords 0 44100 22049 0 200 130 1 0 0; +#X coords 0 48000 22049 0 200 130 1 0 0; #X restore 536 65 graph; #X obj 270 367 line~; #X floatatom 270 291 8 0 0 0 - - - 0; @@ -65,7 +65,7 @@ #X restore 389 312 pd init; #X text 560 198 ----- 0.5 second -----; #X text 742 184 0; -#X text 742 56 44100; +#X text 742 56 48000; #X text 42 69 In this patch we can loop in any "window" of the input sample. The "read point" gives the starting point of the window and "chunk" is its size (both in milliseconds). Try \, for example \, frequency 4 \, chunk size 250 \, and vary the read point from -250 to 1000 \, listening to the result.; #X floatatom 198 241 8 0 0 0 - - - 0; #X connect 1 0 9 0; diff --git a/doc/3.audio.examples/B14.sampler.rockafella.pd b/doc/3.audio.examples/B14.sampler.rockafella.pd index 058b8b9feb..0a81d6a4e5 100644 --- a/doc/3.audio.examples/B14.sampler.rockafella.pd +++ b/doc/3.audio.examples/B14.sampler.rockafella.pd @@ -1,4 +1,4 @@ -#N canvas 426 38 906 742 12; +#N canvas 567 79 906 742 12; #X declare -stdpath ./; #X floatatom 41 141 6 0 1000 0 - \$0-size - 0; #X obj 173 495 *~; @@ -42,7 +42,6 @@ #X obj 420 407 *~ 0.5; #X obj 420 452 cos~; #X obj 307 365 r~ read-pt; -#X obj 273 395 *~ 44100; #X obj 273 287 r chunk-size; #X obj 273 421 +~ 1; #X obj 420 344 r~ phase2; @@ -59,12 +58,11 @@ #X obj 79 149 f \$0; #X obj 79 121 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; #X obj 79 277 declare -stdpath ./; -#X msg 79 176 \; \$1-cents 0 \; \$1-precession 20 \; \$1-size 250; +#X msg 79 176 \; \$1-size 250 \; \$1-precession 20 \; \$1-cents 0; #X connect 1 0 3 0; #X connect 2 0 5 0; #X connect 3 0 2 0; #X restore 67 580 pd init; -#X text 539 474 We've delayed multiplying sample location by the sample rate (44100) until the last moment \, so that calculations using "read-pt" and "chunk size" can be in the same units (seconds.), f 46; #X obj 556 155 expr (pow(2 \, $f1/1200) - $f3) / $f2; #X text 623 187 (ratio - precession) / size; #X floatatom 263 176 5 0 0 0 - - - 0; @@ -73,7 +71,6 @@ #X obj 324 517 loadbang; #X msg 324 544 ../sound/voice.wav; #X obj 118 386 r \$0-SR; -#X obj 47 386 *~ 44100; #X obj 342 395 r \$0-SR; #X obj 273 445 tabread4~ \$0-sample; #X obj 47 442 tabread4~ \$0-sample; @@ -86,11 +83,9 @@ #X text 428 67 <-- loop length (ms), f 11; #X text 87 141 <-- chunk size (ms); #X floatatom 323 169 7 0 0 0 - - - 0; -#N canvas 406 326 961 523 smaple-table 1; -#N canvas 0 0 450 300 (subpatch) 0; -#X array \$0-sample 62079 float 2; -#X coords 0 1.02 62079 -1.02 273 194 1 0 0; -#X restore 619 227 graph; +#X text 556 559 The sample now is loaded in the subpatch [pd sample-table]. As for the loaded samples \, we offer more options and also allow you to choose a sample from your hard drive. Also note that now we query the sample rate from the file and used it instead of hard code it., f 41; +#X text 454 694 <------ Open the [pd sample-table] for more details.; +#N canvas 410 248 964 511 sample-table 0; #X obj 453 362 adc~ 1; #X obj 108 251 soundfiler; #X obj 415 110 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; @@ -119,57 +114,58 @@ #X obj 452 232 f 3000; #X msg 452 293 resize \$1; #X obj 467 264 s \$0-loop-length; -#X obj 216 101 openpanel; -#X obj 216 66 inlet; -#X msg 634 59 0 \, 426375 4834.18; -#X obj 634 83 line~; -#X obj 634 107 tabread4~ \$0-sample; -#X obj 634 131 out~; -#X connect 1 0 20 0; -#X connect 2 0 5 0; -#X connect 2 1 6 0; -#X connect 3 0 20 0; -#X connect 3 0 26 0; -#X connect 3 0 23 0; -#X connect 5 0 8 0; -#X connect 6 0 7 0; -#X connect 7 0 10 0; -#X connect 7 0 11 0; -#X connect 8 0 9 0; -#X connect 9 0 12 0; -#X connect 10 0 8 1; -#X connect 15 0 18 0; -#X connect 16 0 17 1; -#X connect 17 0 19 0; -#X connect 18 0 17 0; -#X connect 18 1 16 0; -#X connect 19 0 2 0; -#X connect 21 0 3 0; -#X connect 23 0 24 0; -#X connect 26 0 27 0; -#X connect 26 0 28 0; -#X connect 27 0 25 0; -#X connect 29 0 18 0; -#X connect 30 0 29 0; -#X connect 31 0 32 0; -#X connect 32 0 33 0; -#X connect 33 0 34 0; -#X restore 335 693 pd smaple-table; -#X text 556 559 The sample now is loaded in the subpatch [pd sample-table]. As for the loaded samples \, we offer more options and also allow you to choose a sample from your hard drive. Also note that now we query the sample rate from the file and used it instead of hard code it., f 41; -#X text 454 694 <------ Open the [pd sample-table] for more details.; +#X obj 196 101 openpanel; +#X obj 196 66 inlet; +#X obj 632 169 cnv 19 270 190 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; +#N canvas 0 0 450 300 (subpatch) 0; +#X array \$0-sample 67569 float 2; +#A color 0; +#A width 2; +#X coords 0 1.02 67569 -1.02 272 192 1 0 0; +#X restore 631 168 graph; +#X connect 0 0 19 0; +#X connect 1 0 4 0; +#X connect 1 1 5 0; +#X connect 2 0 19 0; +#X connect 2 0 25 0; +#X connect 2 0 22 0; +#X connect 4 0 7 0; +#X connect 5 0 6 0; +#X connect 6 0 9 0; +#X connect 6 0 10 0; +#X connect 7 0 8 0; +#X connect 8 0 11 0; +#X connect 9 0 7 1; +#X connect 14 0 17 0; +#X connect 15 0 16 1; +#X connect 16 0 18 0; +#X connect 17 0 16 0; +#X connect 17 1 15 0; +#X connect 18 0 1 0; +#X connect 20 0 2 0; +#X connect 22 0 23 0; +#X connect 25 0 26 0; +#X connect 25 0 27 0; +#X connect 26 0 24 0; +#X connect 28 0 17 0; +#X connect 29 0 28 0; +#X restore 335 693 pd sample-table; +#X text 539 474 We've delayed multiplying sample location by the sample rate (assumed to be 48000) until the last moment \, so that calculations using "read-pt" and "chunk size" can be in the same units (seconds.), f 46; +#X obj 47 386 *~ 48000; +#X obj 273 395 *~ 48000; #X connect 0 0 25 0; #X connect 1 0 24 0; #X connect 2 0 33 0; -#X connect 3 0 63 0; +#X connect 3 0 77 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X connect 7 0 4 1; #X connect 7 0 5 1; #X connect 7 0 14 0; -#X connect 9 0 55 0; +#X connect 9 0 53 0; #X connect 12 0 13 0; -#X connect 13 0 55 0; -#X connect 13 1 55 1; +#X connect 13 0 53 0; +#X connect 13 1 53 1; #X connect 14 0 15 0; #X connect 15 0 16 0; #X connect 16 0 1 1; @@ -180,47 +176,47 @@ #X connect 22 0 23 0; #X connect 24 0 17 0; #X connect 25 0 8 0; -#X connect 26 0 49 0; +#X connect 26 0 48 0; #X connect 27 0 4 0; -#X connect 28 0 66 0; +#X connect 28 0 63 0; #X connect 29 0 18 0; -#X connect 31 0 55 0; -#X connect 31 1 55 2; +#X connect 31 0 53 0; +#X connect 31 1 53 2; #X connect 32 0 31 0; -#X connect 33 0 50 0; -#X connect 33 0 57 0; +#X connect 33 0 49 0; +#X connect 33 0 55 0; #X connect 34 0 24 1; -#X connect 35 0 42 0; +#X connect 35 0 78 0; #X connect 36 0 37 0; #X connect 37 0 35 0; #X connect 38 0 39 0; #X connect 39 0 40 0; #X connect 40 0 34 1; #X connect 41 0 35 1; -#X connect 42 0 44 0; -#X connect 43 0 36 0; -#X connect 44 0 65 0; -#X connect 45 0 38 0; -#X connect 45 0 37 1; -#X connect 45 0 36 1; +#X connect 42 0 36 0; +#X connect 43 0 62 0; +#X connect 44 0 38 0; +#X connect 44 0 37 1; +#X connect 44 0 36 1; +#X connect 45 0 46 0; #X connect 46 0 47 0; -#X connect 47 0 48 0; -#X connect 48 0 50 0; -#X connect 48 1 50 1; -#X connect 48 1 49 1; -#X connect 49 0 19 0; -#X connect 50 0 75 0; -#X connect 55 0 29 0; -#X connect 57 0 30 0; -#X connect 60 0 61 0; -#X connect 61 0 76 0; -#X connect 62 0 63 1; -#X connect 63 0 28 0; -#X connect 64 0 42 1; -#X connect 65 0 34 0; -#X connect 66 0 1 0; -#X connect 67 0 76 0; -#X connect 68 0 76 0; -#X connect 69 0 76 1; -#X connect 71 0 76 2; -#X connect 75 0 26 0; +#X connect 47 0 49 0; +#X connect 47 1 49 1; +#X connect 47 1 48 1; +#X connect 48 0 19 0; +#X connect 49 0 72 0; +#X connect 53 0 29 0; +#X connect 55 0 30 0; +#X connect 58 0 59 0; +#X connect 59 0 75 0; +#X connect 60 0 77 1; +#X connect 61 0 78 1; +#X connect 62 0 34 0; +#X connect 63 0 1 0; +#X connect 64 0 75 0; +#X connect 65 0 75 0; +#X connect 66 0 75 1; +#X connect 68 0 75 2; +#X connect 72 0 26 0; +#X connect 77 0 28 0; +#X connect 78 0 43 0; diff --git a/doc/3.audio.examples/B15.tabread4~-onset.pd b/doc/3.audio.examples/B15.tabread4~-onset.pd index e4ba32a8d9..589a70683d 100644 --- a/doc/3.audio.examples/B15.tabread4~-onset.pd +++ b/doc/3.audio.examples/B15.tabread4~-onset.pd @@ -1,4 +1,4 @@ -#N canvas 453 60 682 628 12; +#N canvas 939 47 682 628 12; #X declare -stdpath ./; #X obj 68 518 output~; #X obj 415 434 samplerate~; @@ -24,9 +24,9 @@ #X obj 421 557 array define \$0-tab 200000; #X text 28 58 None of this is needed if you have Pd compiled for double precision \, but in the case you have Pd compiled to work on 32-bit audio samples (a.k.a single precision) you do not have enough precision for use as indices into an array of more than about 32K samples. This is because the mantissa of a 32-bit floating point number has only 24 bits \, out of which you would be using 16 bits or more to address a sample more than 32K into the array \, so there would remain 8 or fewer bits to supply the fraction. In the most extreme situation possible \, the sample could contain a Nyquist frequency sinusoid and the output would then have only about 8 bits of accuracy!, f 89; #X msg 426 385 \; pd dsp 1 \, fast-forward 4000; -#X text 28 181 You can use the "onset" inlet to [tabread4~] to get good accuracy reading longer arrays. The [tabread4~] object adds the index and the "main" (signal) inlet in double precision. So if \, for example \, the onset inlet could specify an integer exactly up to about 8 million (190 seconds at 44100 Hz) \, and the signal inlet could act as a displacement., f 89; #X obj 308 386 sig~; #X obj 46 19 cnv 5 5 25 empty empty [tabread4~]\ Onset\ to\ Improve\ Accuracy\ in\ Single\ Precision 15 13 0 16 #dfdfdf #202020 0; +#X text 28 181 You can use the "onset" inlet to [tabread4~] to get good accuracy reading longer arrays. The [tabread4~] object adds the index and the "main" (signal) inlet in double precision. So if \, for example \, the onset inlet could specify an integer exactly up to about 8 million (174 seconds at 48000 Hz) \, and the signal inlet could act as a displacement., f 89; #X connect 1 0 2 0; #X connect 2 0 5 0; #X connect 4 0 0 0; @@ -35,12 +35,12 @@ #X connect 8 0 9 0; #X connect 8 0 6 0; #X connect 9 0 4 0; -#X connect 10 0 25 0; +#X connect 10 0 24 0; #X connect 11 0 10 0; #X connect 12 0 8 0; #X connect 13 0 10 0; #X connect 20 0 1 0; #X connect 20 0 3 0; #X connect 20 0 23 0; -#X connect 25 0 6 1; -#X connect 25 0 9 1; +#X connect 24 0 6 1; +#X connect 24 0 9 1; diff --git a/doc/3.audio.examples/C01.nyquist.pd b/doc/3.audio.examples/C01.nyquist.pd index 4d9f1a9c84..05295001d1 100644 --- a/doc/3.audio.examples/C01.nyquist.pd +++ b/doc/3.audio.examples/C01.nyquist.pd @@ -2,10 +2,11 @@ #X declare -stdpath ./; #N canvas 0 0 450 300 (subpatch) 0; #X array table24 259 float 0; +#A color 0; +#A width 1; #X coords 0 1.02 258 -1.02 258 130 1 0 0; #X restore 201 413 graph; #X obj 42 333 line~; -#X msg 42 274 500 \, 1423 4000; #X floatatom 53 301 5 0 0 0 - - - 0; #X text 26 568 Synthesis techniques vary in their tendency to make foldover. For higher pitched sounds you'll want to try out relatively foldover-resistant ones., f 61; #X obj 42 406 output~; @@ -32,7 +33,6 @@ #X text 397 345 clear; #X obj 42 366 tabosc4~ table24; #X text 98 62 WARNING: PLAY THIS QUIETLY TO AVOID UNPLEASANTNESS AND POSSIBLE EAR DAMAGE., f 39; -#X text 36 113 Foldover occurs when you synthesize frequencies greater than the Nyquist frequency (half the sample rate). In this example \, the fundamental only reaches 1423 \, but the tables contain high partials. As the partials sweep upward you hear them reflect off the Nyquist frequency. Also \, partials can come into contact with each other causing beating. The value of 1423 was chosen to make the beating effect especially strong if you're running at a sample rate of 44100 (the usual one.); #X obj 33 496 declare -stdpath ./; #X obj 325 287 bng 19 250 50 0 empty empty empty 0 -6 0 8 #dfdfdf #000000 #000000; #X obj 350 317 bng 19 250 50 0 empty empty empty 0 -6 0 8 #dfdfdf #000000 #000000; @@ -40,11 +40,13 @@ #X text 194 264 waveforms -->; #X obj 53 18 cnv 5 5 25 empty empty The\ Nyquist\ Theorem\ and\ Foldover 15 13 0 16 #dfdfdf #202020 0; #X text 95 300 <-- try other frequencies, f 13; -#X connect 1 0 12 0; +#X msg 42 274 500 \, 1550 4000; +#X text 36 113 Foldover occurs when you synthesize frequencies greater than the Nyquist frequency (half the sample rate). In this example \, the fundamental only reaches 1549 \, but the tables contain high partials. As the partials sweep upward you hear them reflect off the Nyquist frequency. Also \, partials can come into contact with each other causing beating. The value of 1549 was chosen to make the beating effect especially strong if you're running at a sample rate of 48000 (the default one.); +#X connect 1 0 11 0; #X connect 2 0 1 0; -#X connect 3 0 1 0; -#X connect 6 0 7 0; -#X connect 12 0 5 0; -#X connect 16 0 7 1; -#X connect 17 0 7 2; -#X connect 18 0 7 3; +#X connect 5 0 6 0; +#X connect 11 0 4 0; +#X connect 14 0 6 1; +#X connect 15 0 6 2; +#X connect 16 0 6 3; +#X connect 20 0 1 0; diff --git a/doc/3.audio.examples/D02.adsr.pd b/doc/3.audio.examples/D02.adsr.pd index 76746e612d..0164d8a458 100644 --- a/doc/3.audio.examples/D02.adsr.pd +++ b/doc/3.audio.examples/D02.adsr.pd @@ -1,8 +1,8 @@ #N canvas 616 48 576 708 12; #X declare -stdpath ./; #N canvas 0 0 450 300 (subpatch) 0; -#X array adsr-output 44100 float 0; -#X coords 0 1.02 44100 -0.02 200 130 1 0 0; +#X array adsr-output 48000 float 0; +#X coords 0 1.02 48000 -0.02 200 130 1 0 0; #X restore 269 429 graph; #X text 289 565 ------ 1 second ------; #X obj 64 199 r trigger; diff --git a/doc/3.audio.examples/E01.spectrum.pd b/doc/3.audio.examples/E01.spectrum.pd index bc6f5ff80c..14257cc609 100644 --- a/doc/3.audio.examples/E01.spectrum.pd +++ b/doc/3.audio.examples/E01.spectrum.pd @@ -1,11 +1,15 @@ -#N canvas 444 62 733 767 12; +#N canvas 716 72 733 767 12; #X declare -stdpath ./; #N canvas 0 0 450 300 (subpatch) 0; #X array E01-signal 882 float 0; +#A color 0; +#A width 1; #X coords 0 6 882 -6 247 147 1 0 0; #X restore 424 49 graph; #N canvas 0 0 450 300 (subpatch) 0; #X array E01-spectrum 90 float 0; +#A color 0; +#A width 1; #X coords 0 4300 89 -40 255 130 1 0 0; #X restore 419 290 graph; #N canvas 310 109 526 363 fft 0; @@ -112,10 +116,10 @@ #X obj 198 260 tgl 19 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; #X text 223 259 <-- graph repeatedly; #X text 221 313 <-- graph once; -#X text 38 493 This next series of patches demonstrates various kinds of modulation: AM \, waveshaping \, and FM. We will need a tool for graphing spectra which is introduced here. In this patch the signal to be analyzed is a simple sum of up to six partials of a fundamental frequency \, which is 172 Hz (close to F below middle C \, if your sample rate happens to be 44100 Hz). The fundamental is chosen to agree with the analysis patch ([pd FFT]) and is computed within [pd init]., f 95; #X text 38 572 The partials are the multipliers in the [*] objects and go from 0 through 5 \, where 0 means DC (or 0 Hz frequency) \, 1 is the fundamental \, and so on. The toggle switches allow you to turn them on and off separately. You have to press the "click to graph" button to update the two graphs or use the toggle button to graph repeatedly., f 95; #X obj 198 285 metro 500; #X obj 126 63 r fundamental; +#X text 38 493 This next series of patches demonstrates various kinds of modulation: AM \, waveshaping \, and FM. We will need a tool for graphing spectra which is introduced here. In this patch the signal to be analyzed is a simple sum of up to six partials of a fundamental frequency \, which is 187.5 Hz (close to F# below middle C \, if your sample rate happens to be 48000 Hz). The fundamental is chosen to agree with the analysis patch ([pd FFT]) and is computed within [pd init]., f 95; #X connect 4 0 2 1; #X connect 4 0 6 0; #X connect 14 0 15 0; @@ -151,6 +155,6 @@ #X connect 54 0 45 0; #X connect 54 0 46 0; #X connect 54 0 47 0; -#X connect 55 0 60 0; -#X connect 60 0 4 0; -#X connect 61 0 54 0; +#X connect 55 0 59 0; +#X connect 59 0 4 0; +#X connect 60 0 54 0; diff --git a/doc/3.audio.examples/E03.octave.divider.pd b/doc/3.audio.examples/E03.octave.divider.pd index fbb88e0f5d..fa2ac238a7 100644 --- a/doc/3.audio.examples/E03.octave.divider.pd +++ b/doc/3.audio.examples/E03.octave.divider.pd @@ -24,7 +24,7 @@ #X text 265 193 ---- 44103 samples ----; #X obj 66 115 +~ 1; #X obj 66 63 phasor~ 1; -#X obj 66 88 *~ 44100; +#X obj 66 88 *~ 48000; #X obj 66 144 tabread4~ E03-table; #X obj 66 170 outlet~; #X text 112 235 one-second sample reader loop. You can replace this with an [adc~] if you want to go live., f 46; diff --git a/doc/3.audio.examples/F02.just.say.pd b/doc/3.audio.examples/F02.just.say.pd index b17e4d1d86..77d076c87b 100644 --- a/doc/3.audio.examples/F02.just.say.pd +++ b/doc/3.audio.examples/F02.just.say.pd @@ -2,8 +2,8 @@ #X declare -stdpath ./; #X obj 128 402 cos~; #N canvas 0 22 450 278 (subpatch) 0; -#X array env-output 44100 float 0; -#X coords 0 1.02 44100 -1.02 200 130 1; +#X array env-output 48000 float 0; +#X coords 0 1.02 48000 -1.02 200 130 1; #X restore 416 91 graph; #X obj 71 296 -~ 0.5; #X obj 128 344 *~; diff --git a/doc/3.audio.examples/G04.control.blocksize.pd b/doc/3.audio.examples/G04.control.blocksize.pd index 2c63750dbe..34f29c2f2f 100644 --- a/doc/3.audio.examples/G04.control.blocksize.pd +++ b/doc/3.audio.examples/G04.control.blocksize.pd @@ -29,7 +29,6 @@ #X obj 250 377 random 60; #X obj 250 260 loadbang; #X obj 250 403 + 30; -#X text 58 78 In situations where a delay read feeds back to a delay write \, the minimum possible delay you can achieve is one block \, which by default is 64 samples \, or 1.45 msec at 44100 Hz. You can shorten the minimum delay by changing the block size. Do this in a subpatch (open it to see how)., f 62; #X obj 148 539 output~; #X obj 148 457 vline~; #X text 58 159 Here we use this principle to make a harpsichord-like sound by sending pulses into a recirculating delay line (which imitates the travel of the wave up and down the harpsichord string.) This is related to Karplus-Strong synthesis \, but the idea is probably much older than their paper., f 62; @@ -45,15 +44,16 @@ #X text 267 495 <-- here is the delay feedback loop; #X obj 250 344 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; #X obj 93 28 cnv 5 5 25 empty empty Controlling\ Delays\ with\ [block~] 15 13 0 16 #dfdfdf #202020 0; -#X connect 0 0 8 0; +#X text 58 78 In situations where a delay read feeds back to a delay write \, the minimum possible delay you can achieve is one block \, which by default is 64 samples \, or 1.33 msec at 48000 Hz. You can shorten the minimum delay by changing the block size. Do this in a subpatch (open it to see how)., f 62; +#X connect 0 0 7 0; #X connect 1 0 0 1; #X connect 2 0 1 0; -#X connect 3 0 21 0; +#X connect 3 0 20 0; #X connect 4 0 6 0; -#X connect 5 0 19 0; +#X connect 5 0 18 0; #X connect 6 0 2 0; -#X connect 9 0 0 0; -#X connect 17 0 9 0; -#X connect 19 0 3 0; -#X connect 21 0 17 0; -#X connect 21 0 4 0; +#X connect 8 0 0 0; +#X connect 16 0 8 0; +#X connect 18 0 3 0; +#X connect 20 0 16 0; +#X connect 20 0 4 0; diff --git a/doc/3.audio.examples/H10.measurement.pd b/doc/3.audio.examples/H10.measurement.pd index dfabeddda2..67192dbe75 100644 --- a/doc/3.audio.examples/H10.measurement.pd +++ b/doc/3.audio.examples/H10.measurement.pd @@ -15,7 +15,7 @@ #X text 502 63 2; #X floatatom 291 308 5 0 10000 0 - \$0-freq - 0; #X floatatom 300 351 4 0 999 0 - \$0-q - 0; -#X obj 69 327 filter-graph1 100 44100; +#X obj 69 327 filter-graph1 100 48000; #X obj 282 381 bp~; #X text 100 364 index; #X text 93 298 <-- compute; @@ -36,11 +36,11 @@ #X text 55 139 [filter-graph1] takes as arguments the number of points to graph and the frequency range \, while [filter-graph2] takes as arguments the name of a table to hold the (frequency dependent) gain \, and another \, if specified \, for the phase., f 51; #X text 505 398 0; #X text 517 212 0 Hz; -#X text 700 212 44100 Hz; +#X text 700 212 48000 Hz; #X text 503 199 0; #X obj 82 419 filter-graph2 \$0-amp \$0-phase; #X text 517 417 0 Hz; -#X text 700 417 44100 Hz; +#X text 700 417 48000 Hz; #X obj 29 25 cnv 5 5 25 empty empty Measuring\ Filter\ Frequency/Phase\ Response 15 13 0 16 #dfdfdf #202020 0; #X text 55 225 You can edit this patch to replace [bp~] with any other filter you're curious about. Try \, for instance \, [vcf~] and [bob~]., f 51; #X connect 5 0 10 0; diff --git a/doc/3.audio.examples/H14.all.pass.pd b/doc/3.audio.examples/H14.all.pass.pd index 876f4fc047..bb37b276d4 100644 --- a/doc/3.audio.examples/H14.all.pass.pd +++ b/doc/3.audio.examples/H14.all.pass.pd @@ -1,6 +1,6 @@ #N canvas 347 132 779 445 12; #X floatatom 63 262 5 0 0 0 - - - 0; -#X obj 63 230 filter-graph1 100 44100; +#X obj 63 230 filter-graph1 100 48000; #X floatatom 371 281 3 -99 99 0 - \$0-pole - 0; #X obj 276 301 rpole~; #X obj 371 304 / 100; @@ -33,10 +33,10 @@ #X text 471 31 2; #X text 474 366 0; #X text 486 180 0 Hz; -#X text 669 180 44100 Hz; +#X text 669 180 48000 Hz; #X text 472 167 0; #X text 486 385 0 Hz; -#X text 669 385 44100 Hz; +#X text 669 385 48000 Hz; #X obj 76 329 filter-graph2 \$0-amp \$0-phase; #X obj 98 33 cnv 5 5 25 empty empty All-Pass\ Filters 15 13 0 16 #dfdfdf #202020 0; #X connect 0 0 22 0; diff --git a/doc/3.audio.examples/J07.oversampling.pd b/doc/3.audio.examples/J07.oversampling.pd index d8a6a6a5ab..2a5141e4b1 100644 --- a/doc/3.audio.examples/J07.oversampling.pd +++ b/doc/3.audio.examples/J07.oversampling.pd @@ -1,6 +1,6 @@ #N canvas 568 60 532 632 12; #X declare -stdpath ./; -#N canvas 514 169 716 525 16x 0; +#N canvas 759 129 716 525 16x 0; #X obj 35 254 *~ 0.125; #X obj 35 279 rzero~ -1; #X obj 35 304 rzero~ -1; @@ -9,54 +9,54 @@ #X obj 228 47 block~ 1024 1 16; #X obj 35 26 inlet; #X obj 35 363 outlet~; -#X obj 35 134 rpole~ 0.87467; -#X obj 35 108 *~ 0.12532; -#X obj 35 160 *~ 0.01668; #X obj 294 323 buttercoef3; #X floatatom 294 247 7 0 0 0 - - - 0; #X obj 294 297 / 16; #X floatatom 294 460 7 0 0 0 - - - 0; -#X obj 294 272 / 22050; #X floatatom 308 438 7 0 0 0 - - - 0; #X floatatom 323 416 7 0 0 0 - - - 0; #X floatatom 338 394 7 0 0 0 - - - 0; #X floatatom 353 372 7 0 0 0 - - - 0; #X floatatom 368 350 7 0 0 0 - - - 0; -#X obj 35 187 cpole~ 0.9293 0.10812; -#X obj 35 223 cpole~ 0.9293 -0.10812; #X msg 294 222 15000; #X text 344 221 desired cutoff frequency; #X text 359 266 divide by nyquist frequency of this subpatch \, which is 22050*16 because of the 16-times oversampling., f 36; #X text 288 190 Here is how to calculate the filter coefficients:; -#X text 163 93 These objects make a 3-pole \, 3-zero Butterworth low-pass filter with cutoff at 15kHz (assuming 16x44100 sample rate). The filter was designed using the [buttercoef3] abstraction introduced in patch H13.butterworth.pd in this series.; +#X text 163 93 These objects make a 3-pole \, 3-zero Butterworth low-pass filter with cutoff at 15kHz (assuming 16x48000 sample rate). The filter was designed using the [buttercoef3] abstraction introduced in patch H13.butterworth.pd in this series.; #X text 424 372 (same \, other [cpole~]); #X text 428 352 coef for [cpole~] imaginary part; #X text 397 396 coef for [cpole~] real part; #X text 381 417 coef for [rpole~]; #X text 367 438 normalizer for [cpole~]; #X text 350 461 normalizer for [rpole~]; +#X obj 35 108 *~ 0.115705; +#X obj 35 160 *~ 0.0141602; +#X obj 35 187 cpole~ 0.935322 0.0998846; +#X obj 35 223 cpole~ 0.935322 -0.0998846; +#X obj 35 134 rpole~ 0.884295; +#X obj 294 272 / 24000; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 3 0; #X connect 3 0 7 0; -#X connect 4 0 9 0; +#X connect 4 0 28 0; #X connect 6 0 4 0; -#X connect 8 0 10 0; -#X connect 9 0 8 0; -#X connect 10 0 21 0; -#X connect 11 0 14 0; -#X connect 11 1 16 0; -#X connect 11 2 17 0; -#X connect 11 3 18 0; -#X connect 11 4 19 0; -#X connect 11 5 20 0; -#X connect 12 0 15 0; -#X connect 13 0 11 0; -#X connect 15 0 13 0; -#X connect 21 0 22 0; -#X connect 21 1 22 1; -#X connect 22 0 0 0; -#X connect 23 0 12 0; +#X connect 8 0 11 0; +#X connect 8 1 12 0; +#X connect 8 2 13 0; +#X connect 8 3 14 0; +#X connect 8 4 15 0; +#X connect 8 5 16 0; +#X connect 9 0 33 0; +#X connect 10 0 8 0; +#X connect 17 0 9 0; +#X connect 28 0 32 0; +#X connect 29 0 30 0; +#X connect 30 0 31 0; +#X connect 30 1 31 1; +#X connect 31 0 0 0; +#X connect 32 0 29 0; +#X connect 33 0 10 0; #X restore 131 334 pd 16x; #X floatatom 265 297 8 0 0 0 - - - 0; #X obj 265 334 phasor~; diff --git a/doc/3.audio.examples/butterworth3~.pd b/doc/3.audio.examples/butterworth3~.pd index 5c068a42d2..0d8a7e573a 100644 --- a/doc/3.audio.examples/butterworth3~.pd +++ b/doc/3.audio.examples/butterworth3~.pd @@ -9,13 +9,11 @@ #X obj 171 598 czero~; #X obj 197 634 czero~; #X obj 171 566 /~; -#X obj 385 350 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 -#000000 0 50; +#X obj 385 350 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 50; #X obj 47 332 *~; #X obj 141 508 /~; #X obj 161 229 samplerate~; #X obj 161 255 / 2; -#X obj 115 283 / 22050; #X obj 115 230 f \$1; #X obj 115 256 t f b; #X obj 115 162 inlet; @@ -24,7 +22,6 @@ #X obj 261 194 loadbang; #X obj 297 231 samplerate~; #X obj 297 257 / 2; -#X obj 251 285 / 22050; #X obj 251 257 t f b; #X obj 251 162 inlet; #X obj 47 162 inlet~; @@ -37,17 +34,14 @@ #X text 229 140 hp freq; #X text 362 142 hi/lo norm; #X text 477 139 clear; -#X text 24 11 3-pole \, 3-zero butterworth lp/hp/shelving filter. Args: -lp freq \, hp freq \, normalize-hi. Inlets: input signal \, lo freq -\, hi freq \, hi norm \, reset., f 74; +#X text 24 11 3-pole \, 3-zero butterworth lp/hp/shelving filter. Args: lp freq \, hp freq \, normalize-hi. Inlets: input signal \, lo freq \, hi freq \, hi norm \, reset., f 74; #X text 24 66 For high-pass: set LP freq =0 and hi/lo to 1, f 74; -#X text 24 45 For low-pass: set HP freq >= SR/2 and hi/lo to 0, f -74; -#X text 24 88 Shelving: HP and LP specify shelving band. Gain difference -is about HP/LP cubed (so HP=2LP should give about 18 dB \, for example.) -, f 74; +#X text 24 45 For low-pass: set HP freq >= SR/2 and hi/lo to 0, f 74; +#X text 24 88 Shelving: HP and LP specify shelving band. Gain difference is about HP/LP cubed (so HP=2LP should give about 18 dB \, for example.), f 74; #X obj 115 315 buttercoef3; #X obj 208 491 buttercoef3; +#X obj 115 283 / 24000; +#X obj 251 285 / 24000; #X connect 0 0 3 0; #X connect 1 0 2 0; #X connect 1 1 2 1; @@ -59,47 +53,47 @@ is about HP/LP cubed (so HP=2LP should give about 18 dB \, for example.) #X connect 4 0 6 0; #X connect 4 0 7 0; #X connect 4 0 8 0; -#X connect 5 0 16 0; +#X connect 5 0 15 0; #X connect 6 0 9 0; #X connect 7 0 8 0; #X connect 7 1 8 1; -#X connect 8 0 29 0; +#X connect 8 0 27 0; #X connect 9 0 7 0; -#X connect 10 0 41 1; -#X connect 10 0 42 1; +#X connect 10 0 39 1; +#X connect 10 0 40 1; #X connect 11 0 0 0; #X connect 12 0 6 0; #X connect 13 0 14 0; -#X connect 14 0 15 1; -#X connect 15 0 41 0; -#X connect 16 0 17 0; +#X connect 14 0 41 1; +#X connect 15 0 16 0; +#X connect 16 0 41 0; +#X connect 16 1 13 0; #X connect 17 0 15 0; -#X connect 17 1 13 0; -#X connect 18 0 16 0; -#X connect 19 0 31 0; -#X connect 20 0 31 0; -#X connect 21 0 30 0; -#X connect 22 0 23 0; -#X connect 23 0 24 1; -#X connect 24 0 42 0; -#X connect 25 0 24 0; -#X connect 25 1 22 0; -#X connect 26 0 30 0; -#X connect 27 0 11 0; -#X connect 28 0 4 0; -#X connect 30 0 25 0; -#X connect 31 0 10 0; -#X connect 41 0 11 1; -#X connect 41 1 3 1; -#X connect 41 2 0 1; -#X connect 41 3 1 2; -#X connect 41 3 2 2; -#X connect 41 4 1 3; -#X connect 41 5 2 3; -#X connect 42 0 12 1; -#X connect 42 1 9 1; -#X connect 42 2 6 1; -#X connect 42 3 7 2; -#X connect 42 3 8 2; -#X connect 42 4 7 3; -#X connect 42 5 8 3; +#X connect 18 0 29 0; +#X connect 19 0 29 0; +#X connect 20 0 28 0; +#X connect 21 0 22 0; +#X connect 22 0 42 1; +#X connect 23 0 42 0; +#X connect 23 1 21 0; +#X connect 24 0 28 0; +#X connect 25 0 11 0; +#X connect 26 0 4 0; +#X connect 28 0 23 0; +#X connect 29 0 10 0; +#X connect 39 0 11 1; +#X connect 39 1 3 1; +#X connect 39 2 0 1; +#X connect 39 3 1 2; +#X connect 39 3 2 2; +#X connect 39 4 1 3; +#X connect 39 5 2 3; +#X connect 40 0 12 1; +#X connect 40 1 9 1; +#X connect 40 2 6 1; +#X connect 40 3 7 2; +#X connect 40 3 8 2; +#X connect 40 4 7 3; +#X connect 40 5 8 3; +#X connect 41 0 39 0; +#X connect 42 0 40 0; diff --git a/doc/4.data.structures/08.file.pd b/doc/4.data.structures/08.file.pd index ec12ec94f9..5fbb7d0d00 100644 --- a/doc/4.data.structures/08.file.pd +++ b/doc/4.data.structures/08.file.pd @@ -1,6 +1,6 @@ #N struct template8 float x float y float z float q array bazoo template8-element; #N struct template8-element float x float y float w; -#N canvas 196 38 638 453 12; +#N canvas 150 45 638 453 12; #N canvas 224 314 480 261 template8 0; #X obj 55 207 plot bazoo 700 3 10 20 20; #X obj 36 39 struct template8 float x float y float z float q array bazoo template8-element; @@ -18,7 +18,7 @@ #X text 44 113 data \; template template8 \; float x \; float y \; float z \; float q \; array bazoo template8-element \; \; template template8-element \; float x \; float y \; float w \; \;; #X text 24 23 Besides the "clear" and "scalar" messages to the subpatch (explained before) \, we can send the "write" and "read" messages to save to and load from a .txt file (reading reinitializes and replaces data.) The file format is similar to the data displayed when you right click on the scalar for its properties \, compare them. Here's the header of the file:, f 84; #X text 48 324 The header starts with the 'data' message and includes the template name and its field names. This Scalar has an array field and the element's template is also defined. This header is also present in the properties of scalars \, the rest of the properties shows field values for the template and the array's values. The file also shows this after the header \, but the it lists the data for all scalars (which are three in this example)., f 76; -#N canvas 855 59 471 418 data8 1; +#N canvas 798 59 471 418 data8 1; #X scalar template8 103 181 -66 85 \; 0 0 0 \; 30 0 0 \; 0 111 8 \; -47 22 0 \; 0 0 0 \; 0 70 0 \; 0 70 70 \; 70 70 0 \; 0 70 0 \; \;; #X scalar template8 329 142 -78 802 \; -46 88 0 \; 0 0 4 \; 67 59 0 \; 0 76 12 \; -46 18 12 \; \;; #X scalar template8 233 300 88 80 \; 0 0 0 \; 40 0 4 \; 60 50 0 \; 100 30 3 \; 200 0 0 \; \;; diff --git a/doc/4.data.structures/09.sequencer.pd b/doc/4.data.structures/09.sequencer.pd index 4107cd772d..0e081de6bc 100644 --- a/doc/4.data.structures/09.sequencer.pd +++ b/doc/4.data.structures/09.sequencer.pd @@ -1,4 +1,4 @@ -#N struct template-event float x float y float color array pitch template-pitch array amp template-amp; +#N struct template-event float x float y float color array pitch template-pitch 1 array amp template-amp 1; #N struct template-pitch float x float y float w; #N struct template-amp float x float y float w; #N canvas 237 49 531 432 12; @@ -100,56 +100,55 @@ #X connect 9 1 10 1; #X connect 10 0 8 0; #X restore 392 456 pd voice-routing; -#N canvas 209 70 586 628 sequence 0; -#X obj 136 189 inlet; -#X obj 297 397 *; -#X obj 308 574 outlet; -#X obj 227 422 pointer; -#X obj 297 367 -; -#X obj 331 369 r delay-multiplier; -#X obj 227 376 delay; -#X obj 315 257 get template-event x y; -#X msg 364 325 0; -#X obj 136 261 trigger bang pointer; -#X msg 58 236 next; -#X obj 136 221 pointer; -#X obj 227 455 t b p; -#X obj 308 444 pack pointer float, f 23; -#X text 321 472 pointer (delayed) and y-value; -#X obj 308 505 list prepend next; -#X obj 308 529 list trim; -#X obj 315 289 t f f; -#X floatatom 331 397 9 0 0 0 - - - 0; -#X msg 227 341 stop; -#X obj 364 297 r reset; -#X text 21 108 When [delay] sends a bang \, the pointer is packed with the pitch information and a 'next' selector is prepended for the [clone] object in the parent window. We then ask for the next event \, which calls the next pointer in the sequence., f 76; +#N canvas 209 70 586 657 sequence 0; +#X obj 136 229 inlet; +#X obj 287 437 *; +#X obj 298 614 outlet; +#X obj 287 407 -; +#X obj 321 409 r delay-multiplier; +#X obj 137 416 delay; +#X obj 305 297 get template-event x y; +#X msg 354 365 0; +#X obj 136 301 trigger bang pointer; +#X msg 58 276 next; +#X obj 137 495 t b p; +#X obj 298 484 pack pointer float, f 23; +#X text 311 512 pointer (delayed) and y-value; +#X obj 298 545 list prepend next; +#X obj 298 569 list trim; +#X obj 305 329 t f f; +#X floatatom 321 437 9 0 0 0 - - - 0; +#X msg 157 381 stop; +#X obj 354 337 r reset; #X text 21 16 Here we carry out the actual sequencing. We get a pointer to the scalar and get its x/y coordinates. The y-value is treated as a base pitch value (and is summed to the y-values of the pitch array inside [clone]). The x-value is taken as a time stamp - so we get the time difference from it and the last event \, multiply it by a "delay-multiplier" value that depends on the "tempo" parameter and send this to a [delay] object., f 76; -#X text 396 527 prepend 'next' for [clone], f 14; -#X connect 0 0 11 0; -#X connect 1 0 6 1; -#X connect 3 0 12 0; -#X connect 4 0 1 0; -#X connect 5 0 1 1; -#X connect 5 0 18 0; -#X connect 6 0 3 0; -#X connect 7 0 17 0; -#X connect 7 1 13 1; -#X connect 8 0 4 1; -#X connect 9 0 6 0; -#X connect 9 1 3 1; -#X connect 9 1 7 0; -#X connect 10 0 11 0; -#X connect 11 0 9 0; -#X connect 12 0 10 0; -#X connect 12 1 13 0; -#X connect 13 0 15 0; -#X connect 15 0 16 0; -#X connect 16 0 2 0; -#X connect 17 0 4 1; -#X connect 17 1 4 0; -#X connect 19 0 6 0; -#X connect 20 0 8 0; -#X connect 20 0 19 0; +#X text 386 567 prepend 'next' for [clone], f 14; +#X obj 136 261 vpointer seq; +#X obj 137 457 vpointer seq; +#X text 21 108 When [delay] sends a bang \, the pointer is packed with the pitch information and a 'next' selector is prepended for the [clone] object in the parent window. We then ask for the next event \, which calls the next pointer in the sequence. Note that we're using [vpointer] objects instead of [pointer]. The only difference is that we can give it a name and objects that share a name refer to the same pointer., f 76; +#X connect 0 0 21 0; +#X connect 1 0 5 1; +#X connect 3 0 1 0; +#X connect 4 0 1 1; +#X connect 4 0 16 0; +#X connect 5 0 22 0; +#X connect 6 0 15 0; +#X connect 6 1 11 1; +#X connect 7 0 3 1; +#X connect 8 0 5 0; +#X connect 8 1 6 0; +#X connect 9 0 21 0; +#X connect 10 0 9 0; +#X connect 10 1 11 0; +#X connect 11 0 13 0; +#X connect 13 0 14 0; +#X connect 14 0 2 0; +#X connect 15 0 3 1; +#X connect 15 1 3 0; +#X connect 17 0 5 0; +#X connect 18 0 7 0; +#X connect 18 0 17 0; +#X connect 21 0 8 0; +#X connect 22 0 10 0; #X restore 86 333 pd sequence; #X text 98 404 (synthesis); #X msg 140 215 \; reset bang \; pd-data sort; diff --git a/doc/4.data.structures/10.interaction.pd b/doc/4.data.structures/10.interaction.pd index a32a524a51..a9351d8dec 100644 --- a/doc/4.data.structures/10.interaction.pd +++ b/doc/4.data.structures/10.interaction.pd @@ -1,11 +1,11 @@ #N struct template9 float x float y float w float h float q; -#N canvas 223 50 652 591 12; -#X floatatom 279 333 4 0 0 0 - - - 0; -#N canvas 895 64 388 446 data9 1; +#N canvas 182 49 664 749 12; +#X floatatom 295 523 4 0 0 0 - - - 0; +#N canvas 852 53 388 446 data9 1; #X scalar template9 19 186 73 25 9 \;; #X scalar template9 293 328 38 32 66 \;; #X scalar template9 202 32 46 71 78 \;; -#X scalar template9 50 321 49 46 220 \;; +#X scalar template9 42 300 55 81 207 \;; #X scalar template9 140 183 28 72 634 \;; #X scalar template9 250 125 46 11 48 \;; #X scalar template9 26 62 70 11 903 \;; @@ -23,10 +23,8 @@ #X scalar template9 143 332 49 77 649 \;; #X scalar template9 288 91 72 19 325 \;; #X coords 0 446 1 445 0 0 0; -#X restore 508 286 pd data9; -#N canvas 282 376 705 419 template9 0; -#X obj 393 207 filledpolygon q 0 1 0 0 w 0 w h 0 h; -#X obj 394 234 drawnumber q 0 0 0; +#X restore 524 484 pd data9; +#N canvas 407 339 705 419 template9 0; #X obj 171 124 struct template9 float x float y float w float h float q; #X obj 171 268 outlet; #X obj 182 159 print struct-template9; @@ -35,37 +33,41 @@ #X obj 171 199 route select change displace; #X obj 299 229 unpack p; #X text 153 316 Note: later we'll see how to deal with arrays in data structures. Unfortunately \, at least until now \, you can't have messages like 'change' when clicking and dragging an array element value., f 65; -#X connect 2 0 4 0; -#X connect 2 0 7 0; -#X connect 7 0 3 0; -#X connect 7 1 3 0; -#X connect 7 2 8 0; -#X connect 8 0 3 0; -#X restore 279 236 pd template9; -#X obj 279 305 get template9 x y w h q; -#X floatatom 397 333 4 0 0 0 - - - 0; -#X floatatom 358 333 4 0 0 0 - - - 0; -#X floatatom 318 333 4 0 0 0 - - - 0; -#X floatatom 437 333 4 0 0 0 - - - 0; -#X msg 279 513 \; set-x set \$1; -#X msg 318 475 \; set-y set \$1; -#X msg 358 437 \; set-w set \$1; -#X msg 397 398 \; set-h set \$1; -#X msg 437 359 \; set-q set \$1; -#X floatatom 79 255 5 0 0 0 - set-x - 0; -#X obj 79 292 set template9 x; -#X obj 79 350 set template9 y; -#X obj 79 408 set template9 w; -#X obj 79 465 set template9 h; -#X obj 79 522 set template9 q; -#X floatatom 79 326 5 0 0 0 - set-y - 0; -#X floatatom 79 384 5 0 0 0 - set-w - 0; -#X floatatom 79 442 5 0 0 0 - set-h - 0; -#X floatatom 79 499 5 0 0 0 - set-q - 0; -#X text 375 236 <-- open for details; -#X text 46 17 The [struct] object outputs a pointers in different interaction situations as in the case of any selected object of 'template9' or when you click and change any parameter. This patch demonstrates catching these interactions., f 79; -#X text 46 64 When in run mode (that is not in edit mode) you can click on any corner of the rectangles in the [pd data9] window to drag and change its size or click on the numbers and drag to change the color number. You'll then see the parameters come out of the [get] object \, which outputs the 5 parameters from the [struct]. You can also set the number boxes connected to the [set] objects so you're able to change them., f 79; -#X text 46 156 If you go into edit mode in the [pd data9] window \, you can also select a scalar (note the blue "selection" rectangle) and drag it. The 5 parameters should also show up under the [get] object. The blue "selection" rectangle also notices when the object that got selected gets moved or resized via the [set] object., f 79; +#X obj 394 234 drawnumber q 0 0 0; +#X obj 393 207 filledpolygon -d q 0 1 0 0 w 0 w h 0 h; +#X connect 0 0 2 0; +#X connect 0 0 5 0; +#X connect 5 0 1 0; +#X connect 5 1 1 0; +#X connect 5 2 6 0; +#X connect 6 0 1 0; +#X restore 295 440 pd template9; +#X obj 295 495 get template9 x y w h q; +#X floatatom 413 523 4 0 0 0 - - - 0; +#X floatatom 374 523 4 0 0 0 - - - 0; +#X floatatom 334 523 4 0 0 0 - - - 0; +#X floatatom 453 523 4 0 0 0 - - - 0; +#X msg 295 703 \; set-x set \$1; +#X msg 334 665 \; set-y set \$1; +#X msg 374 627 \; set-w set \$1; +#X msg 413 588 \; set-h set \$1; +#X msg 453 549 \; set-q set \$1; +#X floatatom 95 445 5 0 0 0 - set-x - 0; +#X obj 95 482 set template9 x; +#X obj 95 540 set template9 y; +#X obj 95 598 set template9 w; +#X obj 95 655 set template9 h; +#X obj 95 712 set template9 q; +#X floatatom 95 516 5 0 0 0 - set-y - 0; +#X floatatom 95 574 5 0 0 0 - set-w - 0; +#X floatatom 95 632 5 0 0 0 - set-h - 0; +#X floatatom 95 689 5 0 0 0 - set-q - 0; +#X text 391 440 <-- open for details; +#X text 44 12 The [struct] object outputs a pointer in different interaction situations with scalars \, such as clicking on it \, changing a field value \, selecting it and displacing it. This patch demonstrates catching some of these interactions with the [filledpolygon] and [drawnumber] objects., f 79; +#X text 44 203 The [get] object receives the pointer and outputs the values of all requested fields. In this case we get all the 5 parameters from the [struct]. You can also set the number boxes connected to the [set] objects so you're able to change them., f 79; +#X text 44 72 When in run mode (that is not in edit mode) you can resize the [fillepolygon] object by clicking on any corner of the rectangles besides the bottom left one. You can see when you can do it when the arrow points upwards \, showing you can resize it. The top left corner resizes vertically \, the bottom right resizes horizontaly \, and the top right resizes both vertically and horizontaly. When doing so \, you can see in the Pd window that [struct] sent a "click" message and "change" messages to reflect changing the values of 'w' (width) and 'h' (height) fields. You can also click on the number and change its value \, which sets the 'q' (color) field and see the same messages being printed., f 79; +#X text 44 264 If you go into edit mode in the [pd data9] window \, you can also select a scalar (note the blue "selection" rectangle). When you deselect \, [struct] also outputs a "deselect" message. The [filledpolygon] object is created with the '-d' flag \, which means you can click on it and displace it \, in which case you'll also see the "displace" message sent by [struct]. Without this flag \, you can only displace it in the edit mode after you select it., f 79; +#X text 44 353 The click message outputs 5 parameters \, the 2 first ones are the click position within the object. The remaining 3 report modifications. The first one outputs "1" if you click pressing "shift" \, the second one resports "1" for "alt" and the third one reports "1" for double clicking., f 79; #X connect 0 0 8 0; #X connect 2 0 3 0; #X connect 2 0 14 1; diff --git a/doc/4.data.structures/12.onoff.pd b/doc/4.data.structures/12.onoff.pd index fe4358f06f..476fe165c8 100644 --- a/doc/4.data.structures/12.onoff.pd +++ b/doc/4.data.structures/12.onoff.pd @@ -1,17 +1,17 @@ #N struct template11 float x float y float a float b float n; #N canvas 290 38 621 540 12; #N canvas 243 114 724 522 template11 0; -#X obj 441 148 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; -#X obj 441 25 inlet; -#X obj 69 458 outlet; -#X text 164 148 show/hide this drawing instruction --> globally via the inlet, f 38; -#X text 124 208 draw a "circle" of radius a \, visible when b != 0 (inlet is deactivated), f 49; -#X text 129 360 this is a square that is always visible; -#X obj 69 105 struct template11 float x float y float a float b float n, f 33; -#X text 24 47 Template demonstrating turning a drawing instruction on and off. Field values are x/y coordinates \, 'a' (radius) \, 'b' (visibility) and 'n' (object number)., f 53; -#X obj 123 252 filledcurve -v b 900 900 8 a(0:100)(0:100) 0 a(0:100)(0:71) a(0:100)(0:71) 0 a(0:100)(0:100) a(0:100)(0:-71) a(0:100)(0:71) a(0:100)(0:-100) 0 a(0:100)(0:-71) a(0:100)(0:-71) 0 a(0:100)(0:-100) a(0:100)(0:71) a(0:100)(0:-71) a(0:100)(0:100) 0; -#X obj 441 173 drawnumber b -10 -28 0 b=; -#X obj 126 386 drawpolygon 0 2 20 20 20 -20 -20 -20 -20 20 20 20; +#X obj 451 176 tgl 15 0 empty empty empty 0 -6 0 8 #dfdfdf #000000 #000000 0 1; +#X obj 451 35 inlet; +#X obj 79 478 outlet; +#X text 174 173 show/hide this drawing instruction --> globally via the inlet, f 38; +#X text 134 236 draw a "circle" of radius a \, visible when b != 0 (inlet is deactivated), f 49; +#X text 139 388 this is a square that is always visible; +#X obj 79 125 struct template11 float x float y float a float b float n, f 33; +#X text 34 67 Template demonstrating turning a drawing instruction on and off. Field values are x/y coordinates \, 'a' (radius) \, 'b' (visibility) and 'n' (object number)., f 53; +#X obj 133 280 filledcurve -v b 900 900 8 a(0:100)(0:100) 0 a(0:100)(0:71) a(0:100)(0:71) 0 a(0:100)(0:100) a(0:100)(0:-71) a(0:100)(0:71) a(0:100)(0:-100) 0 a(0:100)(0:-71) a(0:100)(0:-71) 0 a(0:100)(0:-100) a(0:100)(0:71) a(0:100)(0:-71) a(0:100)(0:100) 0; +#X obj 451 201 drawnumber b -10 -28 0 b=; +#X obj 136 414 drawpolygon 0 2 20 20 20 -20 -20 -20 -20 20 20 20; #X connect 0 0 9 0; #X connect 1 0 0 0; #X connect 6 0 2 0; diff --git a/doc/4.data.structures/14.beat-patterns.pd b/doc/4.data.structures/14.beat-patterns.pd index a707f65b9f..78a8454a08 100644 --- a/doc/4.data.structures/14.beat-patterns.pd +++ b/doc/4.data.structures/14.beat-patterns.pd @@ -1,6 +1,6 @@ #N struct rect float x float y float w float h; -#N canvas 276 83 397 213 12; -#N canvas 226 371 435 231 rect 0; +#N canvas 200 116 397 213 12; +#N canvas 158 373 435 231 rect 0; #X obj 211 156 pointer; #X msg 211 125 traverse pd-test \, bang; #X obj 80 69 filledpolygon 0 0 0 0 0 0 h w h w 0 0 0; @@ -11,7 +11,7 @@ #X connect 1 0 0 0; #X connect 5 0 3 0; #X restore 115 121 pd rect; -#N canvas 700 38 649 658 output 1; +#N canvas 618 38 649 658 output 1; #X scalar rect 57 179 2 10 \;; #X scalar rect 82 179 1 10 \;; #X scalar rect 107 179 1 10 \;; @@ -347,7 +347,7 @@ #X text 304 72 show the proportions.; #X coords 0 658 1 657 0 0 0; #X restore 114 149 pd output; -#N canvas 386 64 875 580 generator 0; +#N canvas 303 158 875 580 generator 0; #X obj 664 101 r start; #X obj 664 169 pointer; #X msg 98 31 \; pd-output clear; diff --git a/doc/4.data.structures/16.FFT-plot.pd b/doc/4.data.structures/16.FFT-plot.pd index 68524cfa21..0bd5857285 100644 --- a/doc/4.data.structures/16.FFT-plot.pd +++ b/doc/4.data.structures/16.FFT-plot.pd @@ -1,6 +1,6 @@ #N canvas 447 38 549 567 12; #X declare -stdpath ./; -#N canvas 136 407 1188 313 peaks-list 1; +#N canvas 92 407 1188 313 peaks-list 1; #X coords 0 313 1 312 0 0 0; #X restore 409 365 pd peaks-list; #X text 345 367 display:; @@ -50,7 +50,7 @@ #X obj 151 212 / 1000; #X obj 119 201 *; #X obj 26 17 inlet; -#N canvas 441 320 449 241 record 1; +#N canvas 441 320 449 241 record 0; #X obj 37 37 inlet; #X obj 53 145 adc~ 1; #X text 191 91 (set array size to 3 seconds); @@ -121,6 +121,8 @@ #X obj 351 69 cnv 19 451 88 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; #N canvas 0 50 450 300 (subpatch) 0; #X array \$0-sample 62079 float 2; +#A color 0; +#A width 2; #X coords 0 1 62079 -1 453 90 1 0 0; #X restore 350 68 graph; #X connect 0 0 1 0; diff --git a/doc/4.data.structures/17.partialtracer.pd b/doc/4.data.structures/17.partialtracer.pd index 8f4ff98095..8e94449aea 100644 --- a/doc/4.data.structures/17.partialtracer.pd +++ b/doc/4.data.structures/17.partialtracer.pd @@ -1,6 +1,6 @@ #N canvas 368 38 736 636 12; #X declare -stdpath ./; -#N canvas 86 373 1216 368 trace-list 1; +#N canvas 64 373 1216 368 trace-list 1; #X coords 0 92 1 91.75 0 0 0; #X restore 567 541 pd trace-list; #N canvas 375 90 539 284 trace-template 0; @@ -111,6 +111,8 @@ #X obj 351 69 cnv 19 451 88 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; #N canvas 0 50 450 300 (subpatch) 0; #X array \$0-sample 110250 float 2; +#A color 0; +#A width 2; #X coords 0 1 110250 -1 453 90 1 0 0; #X restore 350 68 graph; #X connect 0 0 7 0; @@ -309,7 +311,7 @@ #X obj 180 206 / 44.1; #X obj 180 231 s osc-speed-set; #X floatatom 161 292 8 0 0 0 - - - 0; -#X text 346 146 Note that sample rate for this patch is fixed at 44100 So run Pd at this rate and load files with this same rate., f 36; +#X text 346 146 Note that sample rate for this patch is fixed at 48000 So run Pd at this rate and load files with this same rate., f 36; #X floatatom 307 227 5 0 0 0 - - - 0; #X msg 242 472 clear; #X obj 153 326 t b f; @@ -317,7 +319,7 @@ #X obj 445 405 r window-size; #X msg 325 418 set 2 \$1 \, bang; #X msg 445 433 set 1 \$1 \, bang; -#X obj 325 471 list store \$0-sample 2048 0 44100; +#X obj 325 471 list store \$0-sample 2048 0 48000; #X connect 0 0 6 0; #X connect 1 0 3 1; #X connect 2 0 4 1; diff --git a/doc/5.reference/acoustics-tilde-help.pd b/doc/5.reference/acoustics-tilde-help.pd index 8d96f3e3aa..5ce6ccc9c3 100644 --- a/doc/5.reference/acoustics-tilde-help.pd +++ b/doc/5.reference/acoustics-tilde-help.pd @@ -84,36 +84,25 @@ #X text 459 448 Power unit; #X text 550 250 Power unit; #X obj 544 159 set-dsp-tgl; -#N canvas 791 106 373 442 multichannel 0; -#X obj 86 163 snake~ in, f 10; -#X obj 86 271 snake~ out; -#X obj 185 360 snapshot~; -#X floatatom 185 399 6 0 0 0 - - - 0; -#X obj 86 360 snapshot~; -#X floatatom 86 399 6 0 0 0 - - - 0; -#X floatatom 86 106 5 0 0 0 - - - 0; -#X floatatom 153 106 5 0 0 0 - - - 0; -#X msg 199 217 \; pd dsp \$1; -#X text 231 180 DSP on/off; -#X obj 199 176 set-dsp-tgl; +#N canvas 791 106 372 414 multichannel 0; +#X obj 79 310 snapshot~; +#X floatatom 79 126 5 0 0 0 - - - 0; +#X floatatom 146 126 5 0 0 0 - - - 0; +#X msg 209 203 \; pd dsp \$1; +#X text 241 166 DSP on/off; +#X obj 209 162 set-dsp-tgl; #X text 70 25 All of these objects work with multichannel signals \, where the operation is performed in all existing channels., f 33; -#X obj 86 228 mtof~; -#X obj 86 133 sig~ 60; -#X obj 153 133 sig~ 69; -#X obj 185 293 r \$0-metro; -#X connect 0 0 12 0; -#X connect 1 0 4 0; -#X connect 1 1 2 0; -#X connect 2 0 3 0; -#X connect 4 0 5 0; -#X connect 6 0 13 0; -#X connect 7 0 14 0; -#X connect 10 0 8 0; -#X connect 12 0 1 0; -#X connect 13 0 0 0; -#X connect 14 0 0 1; -#X connect 15 0 2 0; -#X connect 15 0 4 0; +#X obj 79 208 mtof~; +#X obj 115 264 r \$0-metro; +#X listbox 79 344 14 0 0 0 - - - 0; +#X obj 79 163 sig~ 60 69; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 10 1; +#X connect 5 0 3 0; +#X connect 7 0 0 0; +#X connect 8 0 0 0; +#X connect 10 0 7 0; #X restore 336 515 pd multichannel; #X text 185 500 mutichannel signal support ----------->, f 20; #X text 467 608 updated for Pd version 0.54; diff --git a/doc/5.reference/adc~_dac~-help.pd b/doc/5.reference/adc~_dac~-help.pd index cd59965b7c..d566111fd5 100644 --- a/doc/5.reference/adc~_dac~-help.pd +++ b/doc/5.reference/adc~_dac~-help.pd @@ -1,4 +1,4 @@ -#N canvas 496 29 526 618 12; +#N canvas 512 34 526 618 12; #X obj 96 207 adc~ 5; #X text 146 207 (input from channel 5 only); #X obj 96 237 dac~ 1 2 5 23; @@ -54,20 +54,19 @@ #X text 51 453 If more than one [dac~] outputs to the same channel \, the signals are added. Duplicate [adc~] objects output duplicate signals.; #X text 309 588 updated for Pd version 0.54; #N canvas 399 110 852 452 multichannel 0; -#X obj 481 208 snake~ in; -#X obj 481 127 osc~ 440; -#X obj 541 166 osc~ 660; -#X obj 481 276 *~; -#X obj 588 229 hsl 162 19 0 1 0 0 empty empty empty -2 -10 0 12 #dfdfdf #000000 #000000 0 1; -#X obj 585 262 pow 4; -#X msg 585 286 \$1 10; -#X obj 585 310 line~; +#X obj 471 137 osc~ 440; +#X obj 545 136 osc~ 660; +#X obj 471 236 *~; +#X obj 594 193 hsl 162 19 0 1 0 0 empty empty empty -2 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 591 226 pow 4; +#X msg 591 250 \$1 10; +#X obj 591 274 line~; #X msg 684 313 \; pd dsp \$1; #X obj 684 276 set-dsp-tgl; #X text 715 280 DSP on/off; -#X text 642 115 The [*~] object also supports multichannel signals. Use the slider to control the output volume., f 23; -#X text 644 229 volume; -#X obj 481 315 dac~ 1; +#X text 620 115 The [*~] object also supports multichannel signals. Use the slider to control the output volume., f 29; +#X text 650 193 volume; +#X obj 471 335 dac~ 1; #X obj 160 159 snake~ out; #X obj 160 191 env~; #X obj 227 191 env~; @@ -82,23 +81,28 @@ #X text 22 253 Below \, [adc~ -m 3 5] outputs a three-channel signal that consists of input channels five \, six and seven! Note that in this case the "set" message sets the number of channels and starting channel number \, as in the creation arguments., f 58; #X text 162 335 <-- 2 channels (1 \, 2); #X text 173 367 <-- 3 channels (5 \, 6 \, 7); -#X text 459 366 There is no corresponding "-m" flag since [dac~] infers its channel counts from the signals connected to it. Hence \, the "set" message can only reset the starting channel independently for all the inlets., f 52; -#X connect 0 0 3 0; -#X connect 1 0 0 0; -#X connect 2 0 0 1; -#X connect 3 0 13 0; +#X text 412 371 There is no corresponding "-m" flag since [dac~] infers its channel counts from the signals connected to it. Hence \, the "set" message can only reset the starting channel independently for all the inlets.; +#X msg 505 303 set 2; +#X obj 471 198 snake~ in 2; +#X msg 493 275 set 1; +#X connect 0 0 29 0; +#X connect 1 0 29 1; +#X connect 2 0 12 0; +#X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 6 0; -#X connect 6 0 7 0; -#X connect 7 0 3 1; -#X connect 9 0 8 0; -#X connect 14 0 15 0; -#X connect 14 1 16 0; +#X connect 6 0 2 1; +#X connect 8 0 7 0; +#X connect 13 0 14 0; +#X connect 13 1 15 0; +#X connect 14 0 16 0; #X connect 15 0 17 0; -#X connect 16 0 18 0; -#X connect 20 0 19 0; -#X connect 21 0 19 0; -#X connect 23 0 14 0; +#X connect 19 0 18 0; +#X connect 20 0 18 0; +#X connect 22 0 13 0; +#X connect 28 0 12 0; +#X connect 29 0 2 0; +#X connect 30 0 12 0; #X restore 321 538 pd multichannel; #X text 98 516 The [adc~] and [dac~] objects support multichannel signals \, see --->, f 37; #X text 229 373 The "set" message to either [dac~] or [adc~] resets the independent channel(s)., f 28; diff --git a/doc/5.reference/bag-help.pd b/doc/5.reference/bag-help.pd index 9ca199163b..2c6b184516 100644 --- a/doc/5.reference/bag-help.pd +++ b/doc/5.reference/bag-help.pd @@ -1,50 +1,298 @@ -#N canvas 588 23 509 442 12; -#X msg 68 237 60 64; -#X msg 117 237 60 0; -#X msg 161 237 62 64; -#X msg 209 237 62 0; -#X text 236 355 Output is in the printout window.; -#X msg 224 287 clear; -#X msg 217 262 flush; -#X text 27 154 The collection may have many copies of the same value. You can output the collection (and empty it) with a "flush" message \, or just empty it with "clear." You can use this to mimic a sustain pedal \, for example., f 66; -#X obj 161 354 print bag; -#X obj 161 324 bag; -#X text 15 408 see also:; -#X obj 136 409 makenote; -#X obj 24 16 bag; -#X obj 92 409 poly; -#X text 287 408 updated for Pd version 0.33; -#N canvas 666 144 576 286 reference 0; +#N canvas 409 63 554 643 12; +#X msg 123 274 60 0; +#X msg 221 274 62 0; +#X text 196 549 Output is in the printout window., f 17; +#X obj 123 555 print bag; +#X text 17 608 see also:; +#X obj 138 609 makenote; +#X obj 33 11 bag; +#X obj 94 609 poly; +#N canvas 606 95 571 508 reference 0; #X obj 8 42 cnv 5 550 5 empty empty INLETS: 8 18 0 13 #202020 #000000 0; #X obj 8 75 cnv 1 550 1 empty empty 1st: 8 12 0 13 #9f9f9f #000000 0; -#X obj 8 188 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; -#X obj 8 225 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; -#X obj 7 259 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X obj 8 149 cnv 1 550 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; -#X text 106 84 float -; +#X obj 8 260 cnv 2 550 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; +#X obj 8 384 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; +#X obj 7 480 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X obj 8 219 cnv 1 550 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; +#X text 116 83 float -; #X obj 28 12 bag; #X text 60 11 - collection of numbers; -#X text 106 104 flush -; -#X text 106 123 clear -; -#X text 108 160 float - flag: true (nonzero) or false (zero)., f 57; -#X text 107 198 float - the stored values on flush message., f 49; -#X text 126 232 NONE; -#X text 163 123 clear stored values from the bag (no output).; -#X text 163 104 output stored values and clear the bag.; -#X text 163 84 value to store or delete depending on the flag.; -#X restore 330 16 pd reference; -#X text 428 15 <= click; -#X obj 9 49 cnv 1 490 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 9 394 cnv 1 490 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X text 27 62 The [bag] object adds a value to or removes it from a collection of numbers depending on the flag. The left inlet takes the value and the right inlet takes the flag. If the flag is true (nonzero) \, the value is added to the collection and removed otherwise. The example here takes a list input \, which gets spread at inlets (as is common in Pd)., f 66; -#X text 247 237 <-- add or delete elements; -#X text 261 262 <-- output them; -#X text 269 287 <-- start over; -#X text 57 16 - collection of numbers; -#X connect 0 0 9 0; -#X connect 1 0 9 0; -#X connect 2 0 9 0; -#X connect 3 0 9 0; -#X connect 5 0 9 0; +#X text 116 103 flush -; +#X text 116 122 clear -; +#X text 173 122 clear stored values from the bag (no output)., f 47; +#X text 173 103 output stored values and clear the bag., f 47; +#X text 173 83 value to store or delete depending on the flag.; +#X text 123 141 bang -; +#X obj 8 324 cnv 1 550 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; +#X obj 8 290 cnv 1 550 1 empty empty 1st: 8 12 0 13 #9f9f9f #000000 0; +#X text 110 297 float - the stored values on bang or flush message.; +#X text 53 161 unique -; +#X text 173 141 output stored values but don't clear them., f 47; +#X text 173 160 set <1> or clear <0> "unique" flag., f 47; +#X text 117 230 float - store flag: true (nonzero) or false (zero)., f 57; +#X text 60 180 count -; +#X text 173 179 count the number of stored values that correspond to the given float (output is on the 2nd outlet)., f 49; +#X text 111 332 float -; +#X text 174 333 output count value on "count" message.; +#X text 118 351 bang -; +#X text 174 352 reports duplicate in "unique" mode.; +#X obj 8 412 cnv 1 550 1 empty empty flags: 8 12 0 13 #9f9f9f #000000 0; +#X obj 8 444 cnv 1 550 1 empty empty args: 8 12 0 13 #7c7c7c #000000 0; +#X text 121 418 '-u': flag to prevent multiple copies of same value.; +#X text 208 452 none, f 7; +#X restore 348 11 pd reference; +#X text 446 10 <= click; +#X obj 9 44 cnv 1 535 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X text 259 274 <-- add or delete elements; +#X text 66 11 - collection of numbers; +#X obj 141 525 print bag-outlet2; +#X obj 123 495 bag; +#X obj 75 381 bng 20 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X listbox 123 328 7 0 0 0 - - - 0; +#X obj 10 599 cnv 1 535 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X msg 69 274 60 127; +#X msg 165 274 62 127; +#X text 63 358 output; +#X msg 204 311 clear; +#X msg 212 339 flush; +#X msg 221 370 count 60; +#X msg 222 438 unique \$1; +#X obj 222 414 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X text 249 312 <-- clear; +#X text 260 338 <-- clear and output; +#X text 29 103 The first inlet is a number to add or delete. If the second inlet is nonzero \, the number is added to the collection \, otherwise it is removed. A list can also be given \, which distributes the values into the inlets as usual in Pd., f 69; +#X text 29 169 By default \, the collection may have many copies of the same number \, but if set to unique mode (via the "unique" message or "-u" flag) \, duplicates are dropped and a "bang" is sent out the second outlet., f 69; +#X text 29 219 You can output the collection with a bang \, output and empty it with a "flush" message \, or just empty it with "clear"., f 69; +#X text 299 424 set or clear "unique" flag. A bang is set to the right outlet when there's a repeated input., f 31; +#X text 29 55 The [bag] object maintains a variable-length collection of numbers \, for instance to implement a MIDI-style sustain pedal or an arpeggiator., f 69; +#N canvas 275 116 567 592 sustain 0; +#X obj 183 295 stripnote; +#X obj 153 266 route 0 1; +#X obj 328 278 sel 0; +#X obj 218 325 pack; +#X msg 328 306 flush; +#X obj 297 424 f; +#X obj 218 351 t l l f; +#X msg 241 473 \$1 0; +#X obj 153 236 list prepend 0; +#X obj 153 205 pack f f; +#X obj 327 196 tgl 23 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 327 166 loadbang; +#X text 356 201 Sustain; +#X obj 241 419 bag -u; +#X obj 97 160 makenote 127 250; +#X msg 97 96 60; +#X floatatom 97 127 5 0 0 0 - - - 0; +#X obj 46 93 + 60; +#X obj 46 66 random 12; +#X obj 46 24 bng 21 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X text 151 94 send a repeated note, f 8; +#X listbox 216 505 10 0 0 0 - - - 0; +#X text 78 17 generate random notes, f 12; +#X msg 328 343 unique 0; +#X msg 332 378 unique 1; +#X text 126 94 <--; +#X text 35 292 use [stripnote] to filter note offs \, which are flushed when the sustain toggle is set to off., f 15; +#X text 250 24 This is a way to implement a sustain pedal. The unique flag is set here by default to manage repeated notes \, where it sends a note off before repeating the note. If you set it to "unique 0" \, then the note offs are stacked and all of them are sent when the sustain pedal is turned off., f 39; +#X text 396 342 stack note offs; +#X text 400 367 retrigger by sending a note off before repeating the note, f 20; +#X obj 216 542 print Sustain; +#X connect 0 0 3 0; +#X connect 0 1 3 1; +#X connect 1 0 21 0; +#X connect 1 1 0 0; +#X connect 2 0 4 0; +#X connect 3 0 6 0; +#X connect 4 0 13 0; +#X connect 5 0 7 0; +#X connect 6 0 21 0; +#X connect 6 1 13 0; +#X connect 6 2 5 1; +#X connect 7 0 21 0; +#X connect 8 0 1 0; +#X connect 9 0 8 0; +#X connect 10 0 2 0; +#X connect 10 0 8 1; +#X connect 11 0 10 0; +#X connect 13 0 7 0; +#X connect 13 1 5 0; +#X connect 14 0 9 0; +#X connect 14 1 9 1; +#X connect 15 0 16 0; +#X connect 16 0 14 0; +#X connect 17 0 16 0; +#X connect 18 0 17 0; +#X connect 19 0 18 0; +#X connect 21 0 30 0; +#X connect 23 0 13 0; +#X connect 24 0 13 0; +#X restore 435 515 pd sustain; +#N canvas 495 128 736 651 arpeggiator 0; +#X obj 549 190 text define notes; +#X msg 549 150 clear; +#X obj 437 100 t b b l b; +#X obj 487 222 text insert notes; +#X msg 447 150 sort; +#X obj 58 360 text get notes; +#X obj 58 302 f; +#X obj 439 258 text size notes; +#X obj 100 324 mod; +#X obj 100 299 + 1; +#X obj 439 292 > 0; +#X obj 439 322 change; +#X obj 58 139 tgl 19 0 empty metro empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 133 526 line~; +#X msg 133 498 \$1 10; +#X obj 58 460 mtof; +#X obj 58 532 *~; +#X msg 115 161 tempo \$1 permin; +#X floatatom 255 108 5 0 0 0 - bpm - 0; +#X obj 177 224 expr 1/$f1; +#X floatatom 177 198 4 0 0 0 - mul - 0; +#X obj 58 206 metro; +#X obj 255 258 expr 60000/$f1; +#X obj 191 374 *; +#X obj 177 252 t b f; +#X obj 241 366 hsl 162 19 0.25 1 0 0 empty dur empty -2 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 238 413 t b f; +#X obj 58 426 makenote 1; +#X obj 191 451 *; +#X obj 58 562 output~; +#X obj 58 488 tabosc4~ wave, f 8; +#X obj 58 392 route float; +#X obj 487 150 bag -u; +#X msg 437 36 40 127 \, 45 127 \, 49 127 \, 52 127; +#X msg 460 67 40 0 \, 45 0 \, 49 0 \, 52 0; +#X text 458 13 play and hold a chord; +#X text 629 67 release it; +#N canvas 281 271 450 300 init 0; +#X obj 129 65 loadbang; +#X obj 138 222 array define wave 2051; +#X msg 129 95 \; bpm 120 \; mul 4 \; dur 0.75 \; wave sinesum 2048 1 0.5 0.33333 0.25 0.2 0.166667 \, normalize, f 26; +#X connect 0 0 2 0; +#X restore 238 557 pd init; +#X floatatom 58 332 3 0 0 0 - - - 0; +#X text 219 106 BPM; +#X text 146 198 mul; +#X obj 439 350 s metro; +#X floatatom 238 390 5 0 0 0 - - - 0; +#X text 55 19 Below we have a way to sequence through notes stored in a [text] object with a [metro] object. The notes are stored to the right with the help of [bag]., f 40; +#X msg 83 258 -1; +#X msg 118 258 1; +#X text 79 238 down; +#X text 121 238 up; +#X text 358 444 Above \, we clear the [text] contents every time we play a new note and use [bag] to output all of its contents with a bang message. Then the contents of the sequence are sorted and the size of the sequence is queried to use as the module of the sequence counter., f 46; +#X floatatom 255 323 5 0 0 0 - - - 0; +#X text 296 323 ms; +#X floatatom 191 404 4 0 0 0 - - - 0; +#X floatatom 191 478 7 0 0 0 - - - 0; +#X text 247 478 duration; +#X text 282 390 relative duration; +#X connect 1 0 0 0; +#X connect 2 0 4 0; +#X connect 2 0 7 0; +#X connect 2 1 32 0; +#X connect 2 2 32 0; +#X connect 2 3 1 0; +#X connect 4 0 0 0; +#X connect 5 0 31 0; #X connect 6 0 9 0; +#X connect 6 0 38 0; +#X connect 7 0 10 0; +#X connect 7 0 8 1; +#X connect 8 0 6 1; #X connect 9 0 8 0; +#X connect 10 0 11 0; +#X connect 11 0 41 0; +#X connect 12 0 21 0; +#X connect 13 0 16 1; +#X connect 14 0 13 0; +#X connect 15 0 30 0; +#X connect 16 0 29 0; +#X connect 17 0 21 0; +#X connect 18 0 17 0; +#X connect 18 0 22 0; +#X connect 19 0 21 1; +#X connect 19 0 24 0; +#X connect 20 0 19 0; +#X connect 21 0 6 0; +#X connect 22 0 49 0; +#X connect 23 0 51 0; +#X connect 24 0 23 0; +#X connect 24 1 23 1; +#X connect 25 0 42 0; +#X connect 26 0 28 0; +#X connect 26 1 28 1; +#X connect 27 0 15 0; +#X connect 27 1 14 0; +#X connect 28 0 27 2; +#X connect 28 0 52 0; +#X connect 30 0 16 0; +#X connect 31 0 27 0; +#X connect 32 0 3 0; +#X connect 33 0 2 0; +#X connect 34 0 2 0; +#X connect 38 0 5 0; +#X connect 42 0 26 0; +#X connect 44 0 9 1; +#X connect 45 0 9 1; +#X connect 49 0 23 0; +#X connect 51 0 28 0; +#X restore 408 565 pd arpeggiator; +#N canvas 720 261 466 441 active-voices 0; +#X obj 163 269 bag; +#X obj 123 230 t b b a b; +#X msg 202 279 0; +#X obj 163 296 b; +#X floatatom 123 376 5 0 0 0 - - - 0; +#X obj 239 301 + 1; +#X obj 202 331 v n; +#X obj 123 342 v n; +#X listbox 123 195 10 0 0 0 - - - 0; +#X obj 218 121 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 76 121 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 123 121 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 170 121 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X msg 76 147 72 \$1; +#X msg 123 147 74 \$1; +#X msg 170 147 77 \$1; +#X msg 218 147 81 \$1; +#X text 268 120 <-- emulate note on/off messages, f 20; +#X text 67 45 This example shows how to use [bag] to tell us the number of active voices in it., f 43; +#X text 175 376 Number of currently on voices; +#X connect 0 0 3 0; +#X connect 1 0 7 0; +#X connect 1 1 0 0; +#X connect 1 2 0 0; +#X connect 1 3 2 0; +#X connect 2 0 6 0; +#X connect 3 0 6 0; +#X connect 5 0 6 0; +#X connect 6 0 5 0; +#X connect 7 0 4 0; +#X connect 8 0 1 0; +#X connect 9 0 16 0; +#X connect 10 0 13 0; +#X connect 11 0 14 0; +#X connect 12 0 15 0; +#X connect 13 0 8 0; +#X connect 14 0 8 0; +#X connect 15 0 8 0; +#X connect 16 0 8 0; +#X restore 394 539 pd active-voices; +#X text 325 607 updated for Pd version 0.56; +#X text 405 487 Examples:; +#X text 287 369 <-- query how many 60s are in the collection (the count is sent to the second output), f 30; +#X connect 0 0 16 0; +#X connect 1 0 16 0; +#X connect 14 0 3 0; +#X connect 14 1 13 0; +#X connect 15 0 14 0; +#X connect 16 0 14 0; +#X connect 18 0 16 0; +#X connect 19 0 16 0; +#X connect 21 0 14 0; +#X connect 22 0 14 0; +#X connect 23 0 14 0; +#X connect 24 0 14 0; +#X connect 25 0 24 0; diff --git a/doc/5.reference/bang~-help.pd b/doc/5.reference/bang~-help.pd index 52193fd3ae..0ceacae982 100644 --- a/doc/5.reference/bang~-help.pd +++ b/doc/5.reference/bang~-help.pd @@ -26,7 +26,7 @@ #X text 453 14 <= click; #X obj 8 322 cnv 1 520 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 32 61 After each DSP block cycle \, [bang~] outputs a bang (at the same logical time as the DSP cycle.) This is primarily useful for sampling the outputs of analysis algorithms., f 61; -#X text 32 120 By default \, the block size is 64 samples at a 44100 sample rate (this about 1.45 ms.) You can change the sample rate in audio settings and the block size with the [block~] or [switch~] object. Note that the minimum block size [bang~] can handle is 64!, f 49; +#X text 32 120 By default \, the block size is 64 samples at a 48000 sample rate (about 1.33 ms.) You can change the sample rate in audio settings and the block size with the [block~] or [switch~] object. Note that the minimum block size [bang~] can handle is 64!, f 49; #X text 239 232 [bang~] only outputs when DSP is on., f 20; #X obj 148 336 metro; #X obj 196 336 bang; diff --git a/doc/5.reference/binops-tilde-help.pd b/doc/5.reference/binops-tilde-help.pd index 1f51ccd193..f8581ab0a2 100644 --- a/doc/5.reference/binops-tilde-help.pd +++ b/doc/5.reference/binops-tilde-help.pd @@ -1,4 +1,4 @@ -#N canvas 311 33 841 580 12; +#N canvas 311 34 841 580 12; #X obj 22 164 +~; #X obj 102 164 -~; #X obj 22 18 +~; @@ -7,10 +7,10 @@ #X obj 117 18 /~; #X obj 148 18 max~; #X obj 186 18 min~; -#X obj 668 420 +~ 5; +#X obj 688 420 +~ 5; #X text 25 534 see also:; #X obj 110 523 +; -#X floatatom 693 394 5 0 0 0 - - - 0; +#X floatatom 713 394 5 0 0 0 - - - 0; #X obj 162 551 cos~; #X obj 382 524 abs~; #X obj 222 18 log~; @@ -99,71 +99,49 @@ #X msg 723 214 \; pd dsp \$1; #X obj 723 177 set-dsp-tgl; #X text 754 181 DSP on/off; -#N canvas 677 196 565 489 multichannel 0; -#X obj 247 193 snake~ in; -#X obj 373 193 snake~ in; +#N canvas 677 196 543 461 multichannel 0; #X obj 355 251 +~; -#X obj 86 193 snake~ in; -#X obj 86 301 snake~ out; -#X obj 98 341 r bang; -#X obj 164 390 snapshot~; -#X floatatom 164 429 6 0 0 0 - - - 0; -#X obj 86 390 snapshot~; -#X floatatom 86 429 6 0 0 0 - - - 0; -#X obj 355 301 snake~ out; -#X obj 367 341 r bang; -#X obj 433 390 snapshot~; -#X floatatom 433 429 6 0 0 0 - - - 0; -#X obj 355 390 snapshot~; -#X floatatom 355 429 6 0 0 0 - - - 0; -#X floatatom 86 136 5 0 0 0 - - - 0; -#X floatatom 146 136 5 0 0 0 - - - 0; -#X floatatom 247 136 5 0 0 0 - - - 0; -#X floatatom 307 136 5 0 0 0 - - - 0; -#X obj 307 163 sig~ 5; -#X floatatom 373 136 5 0 0 0 - - - 0; -#X floatatom 433 136 5 0 0 0 - - - 0; -#X obj 433 163 sig~ 9; -#X obj 247 163 sig~ 3; -#X obj 373 163 sig~ 2; +#X obj 98 301 r bang; +#X obj 86 350 snapshot~; +#X obj 367 301 r bang; +#X obj 355 350 snapshot~; +#X floatatom 86 156 5 0 0 0 - - - 0; +#X floatatom 146 156 5 0 0 0 - - - 0; +#X floatatom 267 166 5 0 0 0 - - - 0; +#X floatatom 320 166 5 0 0 0 - - - 0; +#X floatatom 373 166 5 0 0 0 - - - 0; +#X floatatom 426 166 5 0 0 0 - - - 0; #X obj 86 258 +~ 5; #X floatatom 111 228 5 0 0 0 - - - 0; -#X obj 86 163 sig~ 2; -#X obj 146 163 sig~ 5; #X text 128 255 value summed to all channels, f 16; #X text 37 13 All of these objects work with multichannel signals. If both inputs have the same amount of channels \, then operations are done at each corresponding channels. In case the numbers mismatch \, the input with less channels wraps around and copy the first channels until reaching the number of channels of the other input. This is especially useful when you have a single channel value (or a float) to apply an operation to every channel in a multisignal connection., f 69; -#X connect 0 0 2 0; -#X connect 1 0 2 1; -#X connect 2 0 10 0; -#X connect 3 0 26 0; -#X connect 4 0 8 0; -#X connect 4 1 6 0; -#X connect 5 0 6 0; -#X connect 5 0 8 0; -#X connect 6 0 7 0; -#X connect 8 0 9 0; -#X connect 10 0 14 0; -#X connect 10 1 12 0; -#X connect 11 0 12 0; -#X connect 11 0 14 0; -#X connect 12 0 13 0; -#X connect 14 0 15 0; -#X connect 16 0 28 0; -#X connect 17 0 29 0; -#X connect 18 0 24 0; -#X connect 19 0 20 0; -#X connect 20 0 0 1; -#X connect 21 0 25 0; -#X connect 22 0 23 0; -#X connect 23 0 1 1; -#X connect 24 0 0 0; -#X connect 25 0 1 0; -#X connect 26 0 4 0; -#X connect 27 0 26 1; -#X connect 28 0 3 0; -#X connect 29 0 3 1; -#X restore 670 465 pd multichannel; -#X text 519 450 mutichannel signal support ----------->, f 20; +#X obj 86 193 sig~ 2 5, f 9; +#X listbox 86 394 10 0 0 0 - - - 0; +#X msg 202 362 \; pd dsp \$1; +#X obj 202 325 set-dsp-tgl; +#X text 233 329 DSP on/off; +#X obj 267 203 sig~ 3 5; +#X obj 373 203 sig~ 2 9; +#X listbox 355 389 10 0 0 0 - - - 0; +#X connect 0 0 4 0; +#X connect 1 0 2 0; +#X connect 2 0 16 0; +#X connect 3 0 4 0; +#X connect 4 0 22 0; +#X connect 5 0 15 0; +#X connect 6 0 15 1; +#X connect 7 0 20 0; +#X connect 8 0 20 1; +#X connect 9 0 21 0; +#X connect 10 0 21 1; +#X connect 11 0 2 0; +#X connect 12 0 11 1; +#X connect 15 0 11 0; +#X connect 18 0 17 0; +#X connect 20 0 0 0; +#X connect 21 0 0 1; +#X restore 660 465 pd multichannel; +#X text 509 450 mutichannel signal support ----------->, f 20; #X text 35 307 These objects perform the 4 arithmetic functions ([+~] \, etc) \, output the minimum or maximum of two numbers ([min~] \, [max~]) \, or perform logarithms and exponentiation ([log~] \, [pow~])., f 62; #X text 35 422 [pow~] raises a signal to a numeric power given by the right inlet or a creation argument. The inputs may be positive \, zero \, or negative. WARNING: it's easy to generate "infinity" \, but there' a protection against NaNs (they become 0)., f 62; #X text 627 550 updated for Pd version 0.54; diff --git a/doc/5.reference/clip~-help.pd b/doc/5.reference/clip~-help.pd index 738993db34..87cd67d7e4 100644 --- a/doc/5.reference/clip~-help.pd +++ b/doc/5.reference/clip~-help.pd @@ -1,4 +1,4 @@ -#N canvas 445 81 518 450 12; +#N canvas 431 58 518 450 12; #X obj 36 168 clip~ -0.5 0.5; #X obj 58 252 metro 500; #X obj 12 16 clip~; @@ -41,24 +41,22 @@ #X obj 36 72 osc~ 500; #X obj 153 208 set-dsp-tgl; #X text 184 212 DSP on/off; -#N canvas 440 63 597 629 multichannel 0; +#N canvas 620 128 597 629 multichannel 0; #X text 59 25 [clip~] works with multichannel signals \, where the operation is performed in all existing channels., f 41; #X obj 72 135 snake~ in, f 10; -#X obj 72 243 snake~ out; -#X obj 171 332 snapshot~; -#X floatatom 171 371 6 0 0 0 - - - 0; -#X obj 72 332 snapshot~; -#X floatatom 72 371 6 0 0 0 - - - 0; +#X floatatom 139 360 6 0 0 0 - - - 0; +#X obj 72 291 snapshot~; +#X floatatom 72 360 6 0 0 0 - - - 0; #X msg 347 141 \; pd dsp \$1; #X text 379 104 DSP on/off; #X obj 347 100 set-dsp-tgl; -#X obj 72 200 clip~ -0.5 0.5; -#X obj 72 405 vsl 19 162 -1 1 0 0 empty empty empty 0 -9 0 12 #dfdfdf #000000 #000000 0 1; -#X obj 171 405 vsl 19 162 -1 1 0 0 empty empty empty 0 -9 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 72 180 clip~ -0.5 0.5; +#X obj 72 394 vsl 19 162 -1 1 0 0 empty empty empty 0 -9 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 139 394 vsl 19 162 -1 1 0 0 empty empty empty 0 -9 0 12 #dfdfdf #000000 #000000 0 1; #X obj 72 105 osc~ 0.5; #X obj 139 105 osc~ 0.25; -#X obj 171 265 metro 25; -#X obj 171 236 loadbang; +#X obj 109 253 metro 25; +#X obj 109 224 loadbang; #X obj 319 480 min~; #X obj 347 549 max~; #X obj 344 444 snake~ in, f 10; @@ -71,30 +69,29 @@ #X obj 319 334 osc~ 0.5; #X obj 386 334 osc~ 0.25; #X text 292 208 Note you can also implement [clip~] by combining [min~] and [max~]. This way you can provide signals not only to provide minimum and maximum clip values but they can also be multichannel signals., f 37; -#X connect 1 0 10 0; -#X connect 2 0 5 0; -#X connect 2 1 3 0; -#X connect 3 0 4 0; -#X connect 4 0 12 0; -#X connect 5 0 6 0; -#X connect 6 0 11 0; -#X connect 9 0 7 0; -#X connect 10 0 2 0; -#X connect 13 0 1 0; -#X connect 14 0 1 1; -#X connect 15 0 3 0; -#X connect 15 0 5 0; -#X connect 16 0 15 0; -#X connect 17 0 18 0; -#X connect 19 0 17 1; -#X connect 20 0 18 1; -#X connect 21 0 19 0; -#X connect 22 0 19 1; -#X connect 23 0 20 0; -#X connect 24 0 20 1; -#X connect 25 0 17 0; -#X connect 26 0 25 0; -#X connect 27 0 25 1; +#X obj 72 325 unpack f f; +#X connect 1 0 8 0; +#X connect 2 0 10 0; +#X connect 3 0 27 0; +#X connect 4 0 9 0; +#X connect 7 0 5 0; +#X connect 8 0 3 0; +#X connect 11 0 1 0; +#X connect 12 0 1 1; +#X connect 13 0 3 0; +#X connect 14 0 13 0; +#X connect 15 0 16 0; +#X connect 17 0 15 1; +#X connect 18 0 16 1; +#X connect 19 0 17 0; +#X connect 20 0 17 1; +#X connect 21 0 18 0; +#X connect 22 0 18 1; +#X connect 23 0 15 0; +#X connect 24 0 23 0; +#X connect 25 0 23 1; +#X connect 27 0 4 0; +#X connect 27 1 2 0; #X restore 273 356 pd multichannel; #X text 122 341 mutichannel signal support ----------->, f 20; #X text 298 412 updated for Pd version 0.54; diff --git a/doc/5.reference/clone-abs-d.pd b/doc/5.reference/clone-abs-d.pd new file mode 100644 index 0000000000..e934ca91e9 --- /dev/null +++ b/doc/5.reference/clone-abs-d.pd @@ -0,0 +1,16 @@ +#N canvas 176 159 527 425 12; +#X obj 212 332 outlet~; +#X obj 122 138 savestate; +#X obj 182 168 f; +#X obj 212 292 sig~; +#X obj 212 87 inlet; +#X floatatom 212 253 5 0 0 0 - - - 0; +#X text 261 152 A simple patch to show how each copy of the abstraction saves its own state with the [savestate] object., f 29; +#X connect 1 0 5 0; +#X connect 1 1 2 0; +#X connect 2 0 1 0; +#X connect 2 0 5 0; +#X connect 3 0 0 0; +#X connect 4 0 5 0; +#X connect 4 0 2 1; +#X connect 5 0 3 0; diff --git a/doc/5.reference/clone-help.pd b/doc/5.reference/clone-help.pd index 2dc31e729b..87b41d7420 100644 --- a/doc/5.reference/clone-help.pd +++ b/doc/5.reference/clone-help.pd @@ -1,22 +1,22 @@ -#N canvas 305 29 787 709 12; +#N canvas 265 41 787 709 12; #X declare -stdpath ./; -#X floatatom 223 250 5 57 83 0 - - - 0; -#X obj 223 290 t b f, f 9; -#X obj 223 316 f; -#X msg 401 334 next \$1; -#X msg 409 383 this \$1; -#X msg 420 431 set \$1; -#X msg 429 479 all \$1; -#X text 464 308 "next" forwards a message to the next instance (incrementing and repeating circularly)., f 31; -#X text 472 362 "this" forwards a message to the previous instance sent to by "this" or "next", f 30; -#X obj 223 548 output~; +#X floatatom 226 250 5 57 83 0 - - - 0; +#X obj 226 290 t b f, f 9; +#X obj 226 316 f; +#X msg 404 334 next \$1; +#X msg 412 383 this \$1; +#X msg 419 431 set \$1; +#X msg 432 479 all \$1; +#X text 467 308 "next" forwards a message to the next instance (incrementing and repeating circularly)., f 37; +#X text 475 363 "this" forwards a message to the previous instance sent to by "this" or "next", f 42; +#X obj 226 548 output~; #X obj 30 8 clone; -#X obj 223 378 pack f f; -#X listbox 223 406 5 0 0 0 - - - 0; -#X obj 100 560 declare -stdpath ./, f 11; +#X obj 226 378 pack f f; +#X listbox 226 406 5 0 0 0 - - - 0; +#X obj 40 572 declare -stdpath ./; #X obj 6 37 cnv 1 775 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 6 668 cnv 1 775 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 252 316 + 1; +#X obj 255 316 + 1; #N canvas 696 57 567 608 reference 0; #X obj 8 43 cnv 5 550 5 empty empty INLETS: 8 18 0 13 #202020 #000000 0; #X obj 8 76 cnv 1 550 1 empty empty 'n': 8 12 0 13 #9f9f9f #000000 0; @@ -57,16 +57,15 @@ #X text 84 304 (number and type depends on the abstraction); #X restore 592 8 pd reference; #X text 685 8 <= click; -#X text 268 245 A list beginning with a number dispatches the rest of the list as a message to a copy of the abstraction defined by the first number., f 69; -#X text 91 519 click to open --> (first copy only), f 17; +#X text 271 245 A list beginning with a number dispatches the rest of the list as a message to a copy of the abstraction defined by the first number., f 69; +#X text 94 519 click to open --> (first copy only), f 17; #X text 78 9 - make multiple copies of an abstraction; -#X text 565 677 updated for Pd version 0.54; #X text 15 678 see also:; #X obj 87 679 inlet; #X obj 135 679 snake~; -#X text 438 576 mutichannel signal support ----------->, f 20; -#X floatatom 420 409 5 0 3 0 - - - 0; -#N canvas 461 86 828 543 multichannel 0; +#X text 468 576 mutichannel signal support ----------->, f 20; +#X floatatom 419 409 5 0 3 0 - - - 0; +#N canvas 452 86 828 543 multichannel 0; #X obj 361 338 output~; #X obj 361 296 snake~ out; #X msg 361 221 next \$1; @@ -111,55 +110,87 @@ #X connect 20 0 19 0; #X connect 20 1 19 1; #X connect 21 0 20 0; -#X restore 589 591 pd multichannel; -#X obj 223 352 mod 4; -#X msg 44 455 vis 2 0; -#X msg 108 456 vis 2 1; -#X floatatom 429 457 4 57 83 0 - - - 0; -#X floatatom 409 361 5 0 3 0 - - - 0; -#X floatatom 401 312 5 0 3 0 - - - 0; -#X text 367 518 <-- file name and number of copies; -#X obj 223 518 clone clone-abs-a 4; -#X floatatom 317 289 5 0 0 0 - - - 0; -#X msg 317 329 resize \$1; -#X text 480 419 "set" sets the "next" and "this" counter, f 22; -#X text 486 467 "all" sends a message to all instances, f 21; -#X text 364 286 <-- resize the number of instances; +#X restore 619 591 pd multichannel; +#X obj 226 352 mod 4; +#X msg 47 462 vis 2 0; +#X msg 111 463 vis 2 1; +#X floatatom 432 457 4 57 83 0 - - - 0; +#X floatatom 412 361 5 0 3 0 - - - 0; +#X floatatom 404 312 5 0 3 0 - - - 0; +#X text 370 518 <-- file name and number of copies; +#X obj 226 518 clone clone-abs-a 4; +#X floatatom 320 289 5 0 0 0 - - - 0; +#X msg 320 329 resize \$1; +#X text 475 408 "set" sets the "next" and "this" counter, f 15; +#X text 489 457 "all" sends a message to all instances, f 13; +#X text 367 286 <-- resize the number of instances; #X text 24 46 [clone] creates any number of copies of an abstraction (a patch loaded as an object in another patch). By default "\$1" is set to the instance number within each copy (counted from 0 unless overridden by the "-s" flag). You can prevent '\$1' from reflecting the instance number with the "-x" flag. Arguments must be filename and number of copies \, additional arguments are passed to the copies and appear as \$2 and onward (or \$1 and onward with the "-x" flag)., f 104; -#X listbox 353 546 7 0 0 0 - - - 0; -#X text 410 546 control data is preceded by instance number; +#X listbox 356 546 7 0 0 0 - - - 0; +#X text 413 546 control data is preceded by instance number; #X obj 193 679 poly; #X text 80 623 Note: for backwards compatibility \, you can also invoke this as "clone 16 clone-abstraction" (for instance) \, swapping the abstraction name and the number of voices., f 91; -#X text 54 417 Open or close copy number 2:, f 14; -#X floatatom 165 354 5 0 3 0 - - - 0; -#X text 24 255 Check [poly]'s help for a polyphonic synth example with [clone] and a list input., f 25; -#X text 25 340 Just a float sends an empty list to the instance \, which becomes a bang!, f 19; +#X text 57 424 Open or close copy number 2:, f 14; +#X floatatom 172 365 5 0 3 0 - - - 0; +#X text 26 347 Just a float sends an empty list to the instance \, which becomes a bang!, f 19; #X text 23 121 [clone]'s inlets/outlets correspond to those of the contained patch and may be control and/or signal inlets/outlets. This example has one control inlet. It also has a signal and another control outlet. You can click on the [clone] object to see the first of the cloned instances. At least one control inlet is present even if the abstraction has none \, so [clone] can receive the 'vis' and 'resize' messages. The way control inlets/outlets forward messages is shown below., f 104; #X text 23 197 Signal inlets can get non float control messages via their 2nd outlet in the same way \, but signals are sent to all the instances. See [pd multichannel] example for more details on how signal distribution works in [clone]., f 104; -#X obj 74 303 poly; #X obj 236 678 notein; +#X text 22 261 Check [poly]'s help for a polyphonic synth example with [clone] and a list input, f 22; +#X obj 147 311 poly; +#X text 626 419 Example on how to use [clone] with [savestate], f 17; +#N canvas 689 137 421 453 savestate 0; +#X obj 131 244 clone clone-abs-d 4; +#A set 0; +#A saved 0; +#A set 1; +#A saved 0; +#A set 2; +#A saved 0; +#A set 3; +#A saved 0; +#A set 3; +#X msg 131 173 0 0 \, 1 10 \, 2 20 \, 3 30; +#X obj 154 312 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X obj 131 347 snapshot~; +#X floatatom 131 382 5 0 0 0 - - - 0; +#X obj 154 281 loadbang; +#X msg 149 207 0 0 \, 1 11 \, 2 22 \, 3 33; +#X text 79 45 When using a [savestate] object inside the abstraction \, each copy saves its own state separately. In this example we set values for all instances and they get saved. The output is then the sum of all values (60 or 66)., f 38; +#X msg 268 346 \; pd dsp \$1; +#X obj 268 311 set-dsp-tgl; +#X text 267 287 DSP on/off; +#X connect 0 0 3 0; +#X connect 1 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 5 0 2 0; +#X connect 6 0 0 0; +#X connect 9 0 8 0; +#X restore 650 473 pd savestate; +#X text 555 677 updated for Pd version 0.56-0; +#X obj 293 678 savestate; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 1 1 11 1; -#X connect 2 0 29 0; -#X connect 3 0 36 0; -#X connect 4 0 36 0; -#X connect 5 0 36 0; -#X connect 6 0 36 0; +#X connect 2 0 28 0; +#X connect 3 0 35 0; +#X connect 4 0 35 0; +#X connect 5 0 35 0; +#X connect 6 0 35 0; #X connect 11 0 12 0; -#X connect 12 0 36 0; +#X connect 12 0 35 0; #X connect 16 0 2 1; -#X connect 27 0 5 0; -#X connect 29 0 11 0; -#X connect 29 0 16 0; -#X connect 30 0 36 0; -#X connect 31 0 36 0; -#X connect 32 0 6 0; -#X connect 33 0 4 0; -#X connect 34 0 3 0; -#X connect 36 0 9 0; -#X connect 36 1 43 0; -#X connect 37 0 38 0; -#X connect 37 0 29 1; -#X connect 38 0 36 0; -#X connect 48 0 36 0; +#X connect 26 0 5 0; +#X connect 28 0 11 0; +#X connect 28 0 16 0; +#X connect 29 0 35 0; +#X connect 30 0 35 0; +#X connect 31 0 6 0; +#X connect 32 0 4 0; +#X connect 33 0 3 0; +#X connect 35 0 9 0; +#X connect 35 1 42 0; +#X connect 36 0 37 0; +#X connect 36 0 28 1; +#X connect 37 0 35 0; +#X connect 47 0 35 0; diff --git a/doc/5.reference/cos~-help.pd b/doc/5.reference/cos~-help.pd index 2d0f43dd55..a4987616c7 100644 --- a/doc/5.reference/cos~-help.pd +++ b/doc/5.reference/cos~-help.pd @@ -1,4 +1,4 @@ -#N canvas 383 32 523 567 12; +#N canvas 383 34 523 567 12; #X declare -stdpath ./; #X obj 23 12 cos~; #X obj 86 358 snapshot~; @@ -66,41 +66,29 @@ #X connect 14 0 6 0; #X restore 364 475 pd phasemod; #X obj 104 323 r bang; -#N canvas 788 169 396 460 multichannel 0; -#X obj 86 173 snake~ in; -#X obj 86 261 snake~ out; -#X obj 98 301 r bang; -#X obj 164 350 snapshot~; -#X floatatom 164 389 13 0 0 0 - - - 0; -#X obj 86 350 snapshot~; -#X floatatom 86 389 9 0 0 0 - - - 0; -#X floatatom 86 106 5 0 0 0 - - - 0; -#X floatatom 156 106 5 0 0 0 - - - 0; -#X obj 266 260 metro 100; -#X obj 266 233 loadbang; -#X obj 266 291 s bang; -#X obj 86 133 sig~ 0.5; -#X obj 156 133 sig~ 0.75; -#X obj 86 218 cos~; -#X text 65 29 [cos~] works with multichannel signals \, here's an example., f 31; +#N canvas 695 116 398 422 multichannel 0; +#X obj 77 311 snapshot~; +#X floatatom 77 112 5 0 0 0 - - - 0; +#X floatatom 165 112 5 0 0 0 - - - 0; +#X obj 132 230 metro 100; +#X obj 132 203 loadbang; +#X obj 132 271 s bang; +#X obj 77 209 cos~; +#X text 93 30 [cos~] works with multichannel signals \, here's an example., f 31; #X msg 263 179 \; pd dsp \$1; #X obj 263 143 set-dsp-tgl; #X text 294 147 DSP on/off; -#X connect 0 0 14 0; -#X connect 1 0 5 0; -#X connect 1 1 3 0; -#X connect 2 0 3 0; -#X connect 2 0 5 0; -#X connect 3 0 4 0; -#X connect 5 0 6 0; -#X connect 7 0 12 0; -#X connect 8 0 13 0; -#X connect 9 0 11 0; -#X connect 10 0 9 0; -#X connect 12 0 0 0; -#X connect 13 0 0 1; -#X connect 14 0 1 0; -#X connect 17 0 16 0; +#X listbox 77 348 20 0 0 0 - - - 0; +#X obj 77 154 sig~ 0.5 0.75; +#X connect 0 0 11 0; +#X connect 1 0 12 0; +#X connect 2 0 12 1; +#X connect 3 0 5 0; +#X connect 3 0 0 0; +#X connect 4 0 3 0; +#X connect 6 0 0 0; +#X connect 9 0 8 0; +#X connect 12 0 6 0; #X restore 365 373 pd multichannel; #X text 214 358 mutichannel signal support ----------->, f 20; #X obj 254 532 wrap~; diff --git a/doc/5.reference/delay-help.pd b/doc/5.reference/delay-help.pd index 5d4fa5f759..9125173ffb 100644 --- a/doc/5.reference/delay-help.pd +++ b/doc/5.reference/delay-help.pd @@ -64,7 +64,7 @@ #N canvas 570 48 709 670 examples 0; #X obj 131 169 delay 1 60 permin; #X obj 49 328 delay 1 1 sec; -#X obj 527 172 delay 1 44100 samp; +#X obj 527 172 delay 1 48000 samp; #X obj 153 328 delay 2 2 persec; #X obj 277 328 delay 0.0166667 1 min; #X obj 131 116 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; @@ -79,11 +79,11 @@ #X obj 153 378 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X obj 277 378 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X obj 527 124 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X text 481 22 Here we have yet another way yo set a one second delay \, but it depends on the sample-rate that Pd is running. We're then assuming a 44100 samplerate, f 31; +#X text 481 22 Here we have yet another way you can set a one second delay \, but it depends on the sample rate that Pd is running. We're assuming a 48000 sample rate, f 31; #X obj 527 216 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X obj 527 275 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X obj 527 378 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X obj 527 339 delay 44100 1 samp; +#X obj 527 339 delay 48000 1 samp; #X obj 110 444 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X obj 195 559 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X obj 195 524 delay 0; diff --git a/doc/5.reference/delay-tilde-objects-help.pd b/doc/5.reference/delay-tilde-objects-help.pd index dbf3999173..eb3f3f406c 100644 --- a/doc/5.reference/delay-tilde-objects-help.pd +++ b/doc/5.reference/delay-tilde-objects-help.pd @@ -1,98 +1,141 @@ -#N canvas 224 47 949 559 12; +#N canvas 167 52 949 575 12; #X declare -stdpath ./; #X text 750 224 creation argument: name of delay line, f 18; #X obj 44 65 delread4~; #X obj 754 274 vd~; #X obj 612 231 delread4~ \$0-delay; -#X obj 39 314 delwrite~ \$0-delay 1000; +#X obj 39 324 delwrite~ \$0-delay 1000; #X obj 612 199 line~; #X obj 39 243 osc~ 440; #X obj 612 268 output~; #X obj 612 171 pack f 1000; #X obj 761 151 declare -stdpath ./; #X msg 63 279 clear; -#X text 214 307 1st argument: name of delay line, f 42; +#X text 214 303 1st argument: name of delay line, f 42; #X obj 43 15 delwrite~; #X text 115 15 - writes a signal in a delay line; #X obj 50 40 delread~; #X text 115 40 - read a signal from a delay line; -#X text 250 397 1st argument: name of delay line, f 33; -#X text 250 417 2nd argument: (initial) delay time in ms; -#X obj 85 443 output~; +#X text 258 411 1st argument: name of delay line, f 40; +#X obj 85 452 output~; #X text 597 77 The delay time is always at least one sample and at most the length of the delay line (specified by a corresponding delwrite~)., f 46; -#X obj 627 435 ../3.audio.examples/G05.execution.order; -#X text 123 376 input (delay time in ms); -#X msg 49 376 500; -#X text 732 527 updated for Pd version 0.52; -#X text 214 329 2nd argument: length of delay line in msec (the maximum delay time in read objects), f 42; +#X text 123 386 input (delay time in ms); +#X msg 49 386 500; +#X text 214 323 2nd argument: length of delay line in msec (the maximum delay time in read objects), f 47; #X text 119 64 - read from a delay line with 4-point interpolation (for variable delay times), f 40; #X text 656 198 signal input (variable delay time in ms); #X obj 491 70 vd~; -#X obj 96 528 fexpr~; -#X text 22 528 see also:; -#X obj 9 514 cnv 1 935 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X obj 96 538 fexpr~; +#X text 22 538 see also:; +#X obj 9 524 cnv 1 935 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 7 102 cnv 1 570 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 488 21 <= click; -#N canvas 733 91 574 497 reference 0; +#N canvas 675 103 575 529 reference 0; #X obj 8 52 cnv 5 550 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; -#X obj 8 111 cnv 2 550 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; -#X obj 8 145 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; -#X obj 7 211 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X text 161 120 NONE, f 45; -#X text 117 153 symbol -; +#X obj 8 133 cnv 2 550 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; +#X obj 8 167 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; +#X obj 7 253 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X text 173 142 NONE, f 45; +#X text 129 175 symbol -; #X obj 43 22 delwrite~; -#X text 106 66 signal -; -#X text 173 66 signal input into the delay time., f 44; -#X text 113 84 clear -; -#X text 173 84 clear the delay time., f 44; -#X text 185 153 delay line name., f 47; -#X text 124 171 float -; -#X text 185 171 length of delay line in msec (the maximum delay time in read objects)., f 47; -#X obj 8 307 cnv 5 550 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; -#X obj 8 375 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; -#X obj 8 414 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; -#X obj 7 471 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X text 107 424 symbol -; -#X text 175 424 delay line name., f 29; -#X text 114 443 float -; -#X obj 43 275 delread~; -#X text 113 322 float -; -#X obj 113 275 delread4~; +#X text 118 66 signal -; +#X text 185 66 signal input into the delay time., f 44; +#X text 125 84 clear -; +#X text 185 84 clear the delay time., f 44; +#X text 197 175 delay line name., f 47; +#X text 136 193 float -; +#X text 197 193 length of delay line in msec (the maximum delay time in read objects)., f 47; +#X obj 8 337 cnv 5 550 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; +#X obj 8 405 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; +#X obj 8 444 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; +#X obj 7 501 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X text 107 454 symbol -; +#X text 175 454 delay line name., f 29; +#X text 114 473 float -; +#X obj 43 305 delread~; +#X text 113 352 float -; +#X obj 113 305 delread4~; #X text 117 22 - write in a delay line.; -#X text 192 275 - read from a delay line.; -#X text 107 384 signal -; -#X text 173 322 delay time in ms (for [delread~])., f 44; -#X text 106 342 signal -; -#X text 173 342 delay time in ms (for [delread4~])., f 44; -#X text 173 384 delayed signal., f 44; -#X text 175 443 initial delay time in ms for [delread~] (default 0).; +#X text 192 305 - read from a delay line.; +#X text 107 414 signal -; +#X text 173 352 delay time in ms (for [delread~])., f 44; +#X text 106 372 signal -; +#X text 173 372 delay time in ms (for [delread4~])., f 44; +#X text 173 414 delayed signal., f 44; +#X text 175 473 initial delay time in ms for [delread~] (default 0).; +#X text 136 227 float -; +#X text 197 227 set number of channels., f 47; +#X text 48 102 channels -; +#X text 185 102 set number of input channels., f 44; #X restore 394 21 pd reference; #X floatatom 39 209 5 0 0 0 - - - 0; -#X obj 85 407 delread~ \$0-delay 500; -#X msg 85 376 1000; +#X msg 85 386 1000; #X msg 612 144 500; #X msg 648 144 1000; #X obj 576 3 cnv 1 1 100 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 406 70 --> a.k.a.:; #X text 597 12 [delread4~] implements a 4-point interpolating delay tap. The delay in milliseconds of the tap is specified by an incoming signal for variable delay times., f 46; -#X text 568 349 In case [delwrite~] runs later in the DSP loop than the [delread~] or [delread4~] objects \, the delay is constrained below by one vector length (usually 64 samples.) Open the file below as an example on how to control this to obtain very short delays., f 51; -#X text 750 295 delread4~ ('vd' for 'variable delay'), f 19; #X text 784 275 -- old name of; -#X text 588 468 See also other examples in the "G" section for more fun with delays \, such as feedback delays., f 46; -#X obj 155 529 send~; +#X obj 155 539 send~; #X text 30 112 The [delread~] and [delread4~] objects read from a delay line allocated in a [delwrite~] object with the same name. You can use more than one [delread~] and/or [delread4~] objects for the same [delwrite~] object. If the specified delay time in [delread~]/[delread4~] is longer than the size of the delay line or less than zero it is clipped to the length of the delay line., f 76; -#X text 246 450 Note that in this help file we're using delay names with "\$0" (the patch ID number used to force locality in Pd)., f 40; +#X text 246 458 Note that in this help file we're using delay names with "\$0" (the patch ID number used to force locality in Pd)., f 40; #X text 121 188 Usually \, [delread~]/[delread4~] must have the same block size \, overlap and upsampling factors as the corresponding [delwrite~] object \, otherwise you might get unexpected results \, unless you really know what you're doing. This example patch uses the default block size of 64 samples but you can change it with:, f 63; #X obj 518 269 block~; #X text 113 280 <-- set all samples of delay line to zero.; +#X text 712 537 updated for Pd version 0.56-0; +#X text 750 295 [delread4~] ('vd' for 'variable delay'), f 21; +#N canvas 136 126 450 300 Execution-order 0; +#X obj 98 132 ../3.audio.examples/G05.execution.order; +#X text 39 46 In case [delwrite~] runs later in the DSP loop than the [delread~] or [delread4~] objects \, the delay is constrained below by one vector length (usually 64 samples.) Open the file below as an example on how to control this to obtain very short delays., f 51; +#X text 59 165 See also other examples in the "G" section for more fun with delays \, such as feedback delays., f 46; +#X restore 777 420 pd Execution-order; +#X text 604 346 Above we have the delay time ramping from one value to another during 1 second \, which alters the pitch for this period., f 41; +#X text 674 419 Important -->; +#N canvas 575 202 513 527 multichannel 0; +#X obj 99 441 snapshot~; +#X obj 122 403 metro 250; +#X obj 122 374 loadbang; +#X text 340 408 see also:; +#X obj 387 436 clone; +#X obj 330 436 snake~; +#X msg 102 193 channels 1; +#X msg 117 218 channels 2; +#X text 216 200 set number of channels., f 12; +#X text 191 199 <--; +#X msg 337 190 \; pd dsp \$1; +#X obj 337 155 set-dsp-tgl; +#X text 368 159 DSP on/off; +#X listbox 99 475 21 0 0 0 - - - 0; +#X obj 79 162 snake~ in 2; +#X obj 79 131 osc~ 440; +#X obj 153 131 noise~; +#X text 219 270 <-- 3rd argument sets number of channels, f 21; +#X obj 79 270 delwrite~ cat 500 2; +#X obj 99 335 delread~ cat; +#X text 33 27 This example shows how to set number of channels as the 3rd argument to [delwrite~] \, so it can take a multichannel signal. You can also change the number of channels with the 'channels' message. A matching [delread~] or [delread4~] will simply take the existing number of channels., f 62; +#X connect 0 0 13 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 6 0 18 0; +#X connect 7 0 18 0; +#X connect 11 0 10 0; +#X connect 14 0 18 0; +#X connect 15 0 14 0; +#X connect 16 0 14 1; +#X connect 19 0 0 0; +#X restore 789 476 pd multichannel; +#X text 638 461 mutichannel signal support ----------->, f 20; +#X obj 85 422 delread~ \$0-delay 500 1; +#X text 258 428 2nd argument: (initial) delay time in ms (default 0); +#X text 214 355 3rd argument: number of channels (default 1), f 47; #X connect 3 0 7 0; #X connect 5 0 3 0; #X connect 6 0 4 0; #X connect 8 0 5 0; #X connect 10 0 4 0; -#X connect 22 0 35 0; -#X connect 34 0 6 0; -#X connect 35 0 18 0; -#X connect 36 0 35 0; -#X connect 37 0 8 0; -#X connect 38 0 8 0; +#X connect 20 0 52 0; +#X connect 31 0 6 0; +#X connect 32 0 52 0; +#X connect 33 0 8 0; +#X connect 34 0 8 0; +#X connect 52 0 17 0; diff --git a/doc/5.reference/draw-shapes-help.pd b/doc/5.reference/draw-shapes-help.pd index 6c51f2b4f1..bb5714d6cb 100644 --- a/doc/5.reference/draw-shapes-help.pd +++ b/doc/5.reference/draw-shapes-help.pd @@ -1,12 +1,12 @@ #N struct drawshapes-template float x float y float weasel float dog float cat; -#N canvas 603 165 589 245 12; +#N canvas 580 151 589 245 12; #X text 20 206 see also:; #X obj 164 207 plot; #X obj 21 10 drawpolygon; #X obj 21 34 drawcurve; #X obj 116 11 filledpolygon; #X obj 117 34 filledcurve; -#N canvas 376 181 944 504 drawshapes-template 0; +#N canvas 271 214 944 504 drawshapes-template 0; #X msg 41 299 1; #X msg 74 299 0; #X msg 514 19 1; @@ -41,12 +41,11 @@ #X scalar drawshapes-template 67 84 72 200 28 \;; #X coords 0 365 1 364 0 0 0; #X restore 280 157 pd drawshapes-data; -#X text 370 208 updated for Pd version 0.51.; #X text 222 13 - draw shapes for data structures, f 17; #X obj 204 207 set; #X obj 96 207 drawtext; #X obj 8 67 cnv 1 570 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#N canvas 714 72 573 494 reference 0; +#N canvas 671 82 573 462 reference 0; #X obj 6 60 cnv 5 550 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; #X obj 6 106 cnv 2 550 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; #X obj 6 144 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; @@ -81,3 +80,4 @@ #X obj 238 207 get; #X text 109 130 explanation is here -->; #X text 73 79 Use these objects to draw straight and curved shapes according in a scalar., f 62; +#X text 370 208 updated for Pd version 0.56; diff --git a/doc/5.reference/expr-help.pd b/doc/5.reference/expr-help.pd index 957169a469..ba1f2aa9ac 100644 --- a/doc/5.reference/expr-help.pd +++ b/doc/5.reference/expr-help.pd @@ -1,4 +1,4 @@ -#N canvas 416 76 745 701 12; +#N canvas 423 57 745 701 12; #X declare -stdpath ./; #N canvas 455 177 911 525 Arrays 0; #X floatatom 123 393 4 0 9 0 - - - 0; @@ -326,46 +326,33 @@ #X restore 130 350 pd Power-functions; #N canvas 241 137 849 422 Trigonometric-functions 0; #X floatatom 34 54 5 0 0 0 - - - 0; -#X floatatom 34 113 5 0 0 0 - - - 0; #X floatatom 34 145 5 0 0 0 - - - 0; -#X floatatom 34 202 5 0 0 0 - - - 0; #X floatatom 33 233 5 0 0 0 - - - 0; -#X floatatom 33 290 5 0 0 0 - - - 0; #X obj 34 82 expr sin($f1); #X obj 34 173 expr cos($f1); #X obj 33 261 expr tan($f1); #X floatatom 194 54 5 0 0 0 - - - 0; -#X floatatom 194 113 5 0 0 0 - - - 0; #X floatatom 194 145 5 0 0 0 - - - 0; -#X floatatom 194 202 5 0 0 0 - - - 0; #X obj 194 82 expr asin($f1); #X obj 194 173 expr acos($f1); #X text 83 52 sine; #X text 85 145 cosine; #X text 84 233 tangent; #X floatatom 195 229 5 0 0 0 - - - 0; -#X floatatom 195 286 5 0 0 0 - - - 0; #X text 261 52 arc sine; #X text 256 145 arc cosine; #X text 256 229 arc tangent; #X floatatom 387 53 5 0 0 0 - - - 0; -#X floatatom 387 112 5 0 0 0 - - - 0; #X floatatom 387 144 5 0 0 0 - - - 0; -#X floatatom 387 201 5 0 0 0 - - - 0; #X floatatom 388 228 5 0 0 0 - - - 0; -#X floatatom 388 285 5 0 0 0 - - - 0; #X floatatom 264 329 5 0 0 0 - - - 0; -#X floatatom 264 386 5 0 0 0 - - - 0; +#X floatatom 264 386 10 0 0 0 - - - 0; #X obj 264 357 expr atan2($f1 \, $f2); #X floatatom 401 329 5 0 0 0 - - - 0; -#X text 426 357 arc tangent of 2 variables; #X obj 195 257 expr atan($f1); #X floatatom 617 53 5 0 0 0 - - - 0; -#X floatatom 617 112 5 0 0 0 - - - 0; #X floatatom 617 144 5 0 0 0 - - - 0; -#X floatatom 617 201 5 0 0 0 - - - 0; #X floatatom 618 228 5 0 0 0 - - - 0; -#X floatatom 618 285 5 0 0 0 - - - 0; #X text 741 66 inverse hyperbolic sine, f 10; #X obj 617 81 expr asinh($f1); #X obj 617 172 expr acosh($f1); @@ -379,33 +366,48 @@ #X text 502 167 hyperbolic cosine, f 10; #X text 501 76 hyperbolic sine, f 10; #X text 112 12 All trigonometric functions expect the input in radians (except the arc or inverse ones)., f 89; -#X connect 0 0 6 0; -#X connect 2 0 7 0; -#X connect 4 0 8 0; -#X connect 6 0 1 0; -#X connect 7 0 3 0; -#X connect 8 0 5 0; -#X connect 9 0 13 0; -#X connect 11 0 14 0; -#X connect 13 0 10 0; -#X connect 14 0 12 0; -#X connect 18 0 34 0; -#X connect 23 0 47 0; -#X connect 25 0 48 0; -#X connect 27 0 49 0; -#X connect 29 0 31 0; -#X connect 31 0 30 0; -#X connect 32 0 31 1; -#X connect 34 0 19 0; -#X connect 35 0 42 0; -#X connect 37 0 43 0; -#X connect 39 0 44 0; -#X connect 42 0 36 0; -#X connect 43 0 38 0; -#X connect 44 0 40 0; -#X connect 47 0 24 0; -#X connect 48 0 26 0; -#X connect 49 0 28 0; +#X floatatom 618 285 10 0 0 0 - - - 0; +#X floatatom 33 290 10 0 0 0 - - - 0; +#X floatatom 195 286 10 0 0 0 - - - 0; +#X floatatom 388 285 10 0 0 0 - - - 0; +#X floatatom 34 202 10 0 0 0 - - - 0; +#X floatatom 194 202 10 0 0 0 - - - 0; +#X floatatom 387 201 10 0 0 0 - - - 0; +#X floatatom 617 201 10 0 0 0 - - - 0; +#X floatatom 34 113 10 0 0 0 - - - 0; +#X floatatom 194 113 10 0 0 0 - - - 0; +#X floatatom 387 112 10 0 0 0 - - - 0; +#X floatatom 617 112 10 0 0 0 - - - 0; +#X text 308 327 y; +#X text 444 328 x; +#X text 426 357 arc tangent of 2 coordinates (y-vertical / x-horizontal), f 28; +#X connect 0 0 3 0; +#X connect 1 0 4 0; +#X connect 2 0 5 0; +#X connect 3 0 49 0; +#X connect 4 0 45 0; +#X connect 5 0 42 0; +#X connect 6 0 8 0; +#X connect 7 0 9 0; +#X connect 8 0 50 0; +#X connect 9 0 46 0; +#X connect 13 0 24 0; +#X connect 17 0 34 0; +#X connect 18 0 35 0; +#X connect 19 0 36 0; +#X connect 20 0 22 0; +#X connect 22 0 21 0; +#X connect 23 0 22 1; +#X connect 24 0 43 0; +#X connect 25 0 29 0; +#X connect 26 0 30 0; +#X connect 27 0 31 0; +#X connect 29 0 52 0; +#X connect 30 0 48 0; +#X connect 31 0 41 0; +#X connect 34 0 51 0; +#X connect 35 0 47 0; +#X connect 36 0 44 0; #X restore 130 379 pd Trigonometric-functions; #N canvas 365 241 592 281 Store-function 0; #X text 40 26 The store function is defined with "=" \, and it can store the result of any operation into a variable or table index.; @@ -549,7 +551,6 @@ #X floatatom 793 483 4 0 0 0 - - - 0; #X floatatom 845 483 4 0 0 0 - - - 0; #X obj 638 397 expr strcmp($s1 \, "hello") \; strcmp($s1 \, "HELLO") \; strcasecmp($s1 \, "HELLO") \; strncmp($s1 \, "heWorld" \, 2) \; strncasecmp($s1 \, "HEWORLD" \, 2); -#X text 249 37 Note that functions that ouput symbols only work in [expr]; #X symbolatom 223 446 15 0 0 0 - - - 0; #X obj 386 404 expr strlen($s2) \; strlen("hello"); #X symbolatom 386 377 10 0 0 0 - - - 0; @@ -671,13 +672,14 @@ #X connect 46 0 3 0; #X restore 719 157 pd symbol(); #X obj 48 378 expr strcat("hello " \, "world") \; strcat("hello " \, "world " \, "again") \; strncat("hello " \, "world" \, 2); +#X text 249 37 Note that functions that output symbols only work in [expr]; #X connect 0 0 2 0; #X connect 1 0 35 0; #X connect 2 0 3 0; #X connect 9 0 8 0; #X connect 12 0 14 0; #X connect 14 0 13 0; -#X connect 18 0 62 0; +#X connect 18 0 61 0; #X connect 19 0 9 0; #X connect 21 0 23 0; #X connect 23 0 22 0; @@ -694,18 +696,18 @@ #X connect 42 2 39 0; #X connect 42 3 40 0; #X connect 42 4 41 0; -#X connect 45 0 5 0; -#X connect 45 1 27 0; -#X connect 46 0 45 0; -#X connect 47 0 55 0; -#X connect 47 1 56 0; -#X connect 48 0 47 0; -#X connect 49 0 50 0; -#X connect 50 0 57 0; -#X connect 50 1 58 0; -#X connect 62 0 6 0; -#X connect 62 1 11 0; -#X connect 62 2 44 0; +#X connect 44 0 5 0; +#X connect 44 1 27 0; +#X connect 45 0 44 0; +#X connect 46 0 54 0; +#X connect 46 1 55 0; +#X connect 47 0 46 0; +#X connect 48 0 49 0; +#X connect 49 0 56 0; +#X connect 49 1 57 0; +#X connect 61 0 6 0; +#X connect 61 1 11 0; +#X connect 61 2 43 0; #X restore 130 553 pd string-functions; #N canvas 202 125 850 540 Other-numeric-functions 0; #X floatatom 54 26 5 0 0 0 - - - 0; @@ -1313,7 +1315,6 @@ #X restore 561 91 pd reference; #X text 338 328 <-- 1st inlet is an audio signal vector/block; #X text 256 440 'n' index for '$x#' is from 0 to minus "vector size - 1".; -#X text 256 457 'n' index for '$x#' is from -1 to minus "vector size - 1".; #X text 474 57 <-- Open HTML reference; #X obj 85 608 abs; #X obj 116 608 abs~; @@ -1406,6 +1407,7 @@ #X connect 42 0 38 0; #X restore 580 489 pd [value] & var(); #X text 213 607 - unary/binary operators; +#X text 256 457 'n' index for '$y#' is from -1 to minus "vector size - 1".; #X connect 15 0 14 2; #X connect 16 0 14 1; #X connect 17 0 14 0; diff --git a/doc/5.reference/fft~-help.pd b/doc/5.reference/fft~-help.pd index 0b3a6bdd85..02f61fbdea 100644 --- a/doc/5.reference/fft~-help.pd +++ b/doc/5.reference/fft~-help.pd @@ -1,6 +1,6 @@ -#N canvas 485 49 711 489 12; +#N canvas 296 47 711 489 12; #X floatatom 27 176 7 0 0 0 - - - 0; -#X obj 27 123 * 44100; +#X obj 27 123 * 48000; #X floatatom 27 93 4 0 0 0 - - - 0; #X obj 27 241 osc~; #X obj 21 33 fft~; @@ -73,44 +73,33 @@ #X obj 178 111 set-dsp-tgl; #X text 178 88 DSP on/off; #X text 289 212 The real FFT outputs N/2+1 real parts and N/2-1 imaginary parts. The other outputs are zero. At DC and Nyquist there's no imaginary part \, but the second through Nth output is as a real and imaginary pair \, which can be thought of as the cosine and sin component strengths., f 57; -#N canvas 697 141 386 484 multichannel 0; -#X obj 80 143 snake~ in; +#N canvas 742 138 386 451 multichannel 0; #X obj 80 186 rfft~; #X obj 79 234 rifft~; -#X obj 79 300 snake~ out; -#X obj 157 389 snapshot~; -#X floatatom 157 428 6 0 0 0 - - - 0; -#X obj 79 389 snapshot~; -#X floatatom 79 428 6 0 0 0 - - - 0; -#X obj 177 261 block~ 512; -#X obj 80 111 sig~ 5; -#X obj 140 111 sig~ 15; +#X obj 148 333 snapshot~; +#X obj 252 233 block~ 512; #X obj 79 266 /~ 512; -#X floatatom 80 81 5 0 0 0 - - - 0; -#X floatatom 140 81 5 0 0 0 - - - 0; -#X obj 179 316 loadbang; -#X obj 179 340 metro 100; -#X msg 212 191 \; pd dsp \$1; -#X obj 212 156 set-dsp-tgl; -#X text 245 160 DSP on/off; -#X text 83 27 These objects have multichannel support., f 21; +#X floatatom 80 101 5 0 0 0 - - - 0; +#X floatatom 140 101 5 0 0 0 - - - 0; +#X obj 148 259 loadbang; +#X obj 148 283 metro 100; +#X msg 225 150 \; pd dsp \$1; +#X obj 225 115 set-dsp-tgl; +#X text 258 119 DSP on/off; +#X text 115 35 These objects have multichannel support., f 22; +#X obj 80 143 sig~ 5 15; +#X listbox 148 375 13 0 0 0 - - - 0; #X connect 0 0 1 0; -#X connect 1 0 2 0; -#X connect 1 1 2 1; -#X connect 2 0 11 0; -#X connect 3 0 6 0; -#X connect 3 1 4 0; -#X connect 4 0 5 0; -#X connect 6 0 7 0; -#X connect 9 0 0 0; -#X connect 10 0 0 1; -#X connect 11 0 3 0; -#X connect 12 0 9 0; -#X connect 13 0 10 0; -#X connect 14 0 15 0; -#X connect 15 0 4 0; -#X connect 15 0 6 0; -#X connect 17 0 16 0; +#X connect 0 1 1 1; +#X connect 1 0 4 0; +#X connect 2 0 14 0; +#X connect 4 0 2 0; +#X connect 5 0 13 0; +#X connect 6 0 13 1; +#X connect 7 0 8 0; +#X connect 8 0 2 0; +#X connect 10 0 9 0; +#X connect 13 0 0 0; #X restore 520 403 pd multichannel; #X text 369 388 mutichannel signal support ----------->, f 20; #X text 495 457 updated for Pd version 0.54; diff --git a/doc/5.reference/file-help.pd b/doc/5.reference/file-help.pd index 832f8fca8a..9179b71b41 100644 --- a/doc/5.reference/file-help.pd +++ b/doc/5.reference/file-help.pd @@ -1,4 +1,4 @@ -#N canvas 437 23 566 697 12; +#N canvas 498 46 566 697 12; #X text 441 70 details:; #X text 439 53 click for; #N canvas 190 61 1062 654 handle 0; @@ -365,23 +365,21 @@ #X restore 442 222 pd which; #X obj 27 148 file mkdir; #X text 155 149 - create a directory; -#N canvas 593 65 525 590 mkdir 0; +#N canvas 587 38 525 599 mkdir 0; #X obj 42 387 file mkdir; -#X symbolatom 42 470 64 0 0 0 - - - 0; -#X obj 42 504 print mkdir; -#X obj 109 438 print ERR:mkdir; +#X symbolatom 42 471 64 0 0 0 - - - 0; +#X obj 42 505 print mkdir; +#X obj 109 440 print ERR:mkdir; #X msg 62 261 symbol \$1/subdir/another/sub/directory; #X msg 83 303 symbol .; #X text 33 81 parent directories are created as needed.; #X text 33 101 it is not an error \, if the requested directory already exists (and is a directory).; -#X text 148 153 create a new directory; -#X text 157 215 create a deep directory; +#X text 67 151 create a new directory; +#X text 93 208 create a deep directory; #X text 164 305 (re)create an existing directory; -#X text 134 412 on error \, a bang is sent to the 2nd outlet; -#X text 136 497 on success \, the name of the created directory is sent to the 1st outlet, f 36; +#X text 134 413 on error \, a bang is sent to the 2nd outlet; +#X text 136 498 on success \, the name of the created directory is sent to the 1st outlet, f 36; #X msg 87 351 creationmode 0o700; -#X obj 62 236 savepanel 1; -#X obj 42 176 savepanel 1; #X obj 37 16 file mkdir; #X text 120 16 - create directories; #X text 34 63 This ensures that a given directory exists by creating it.; @@ -407,7 +405,7 @@ #X restore 424 15 pd reference; #X obj 42 149 bng 19 250 50 0 empty empty empty -35 10 0 10 #dfdfdf #000000 #000000; #X obj 62 211 bng 19 250 50 0 empty empty empty -35 10 0 10 #dfdfdf #000000 #000000; -#X obj 109 413 bng 19 250 50 0 empty empty empty -35 10 0 10 #dfdfdf #000000 #000000; +#X obj 109 414 bng 19 250 50 0 empty empty empty -35 10 0 10 #dfdfdf #000000 #000000; #N canvas 596 129 736 450 flags 0; #X text 209 100 less verbose (quiet); #X text 209 130 more verbose (loud); @@ -431,18 +429,20 @@ #X connect 2 0 18 0; #X connect 3 0 2 0; #X connect 11 0 14 0; -#X restore 195 551 pd flags; +#X restore 195 552 pd flags; +#X obj 42 176 savepanel; +#X obj 62 236 savepanel; #X connect 0 0 1 0; -#X connect 0 1 23 0; +#X connect 0 1 21 0; #X connect 1 0 2 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 13 0 0 0; -#X connect 14 0 4 0; -#X connect 15 0 0 0; -#X connect 21 0 15 0; -#X connect 22 0 14 0; -#X connect 23 0 3 0; +#X connect 19 0 23 0; +#X connect 20 0 24 0; +#X connect 21 0 3 0; +#X connect 23 0 0 0; +#X connect 24 0 4 0; #X restore 442 148 pd mkdir; #X obj 27 451 file delete; #X text 155 452 - delete files and directories; diff --git a/doc/5.reference/gui-boxes-help.pd b/doc/5.reference/gui-boxes-help.pd index 605e3ac991..85e6099283 100644 --- a/doc/5.reference/gui-boxes-help.pd +++ b/doc/5.reference/gui-boxes-help.pd @@ -1,11 +1,11 @@ -#N canvas 204 23 1017 701 12; +#N canvas 293 91 1017 701 12; #X floatatom 270 474 5 0 0 0 - - - 0; #X symbolatom 257 41 10 0 0 0 - - - 0; #X floatatom 56 41 5 0 0 0 - - - 0; -#X text 799 240 more details:; -#X symbolatom 614 231 15 0 0 0 - - - 0; -#X msg 630 171 set hi; -#X msg 614 143 symbol hello\ world; +#X text 799 205 more details:; +#X symbolatom 614 210 15 0 0 0 - - - 0; +#X msg 630 154 set hi; +#X msg 614 126 symbol hello\ world; #N canvas 400 139 417 455 properties 0; #N canvas 672 44 484 606 width 0; #X floatatom 281 505 1 0 0 0 - - - 0; @@ -158,18 +158,18 @@ #X symbolatom 185 186 20 0 0 0 label - - 36; #X restore 240 277 pd size; #X text 171 77 <-- right click for properties; -#X restore 800 264 pd properties; +#X restore 800 229 pd properties; #X text 31 534 more details:; #X listbox 490 41 20 0 0 0 - - - 0; -#X text 687 168 set only - don't output; -#X msg 559 360 1 2 3 foo 5; -#X listbox 559 564 22 0 0 0 - - - 0; -#X msg 573 399 list wombat weasel wallaby; -#X text 654 353 messages beginning with a number are implicitly understood as lists, f 35; -#X msg 611 465 set 4 dog 5 6 donkey; -#X text 766 460 "set" message changes contents but doesn't output them, f 30; +#X text 687 151 set only - don't output; +#X msg 559 324 1 2 3 foo 5; +#X listbox 559 511 22 0 0 0 - - - 0; +#X msg 573 363 list wombat weasel wallaby; +#X text 654 317 messages beginning with a number are implicitly understood as lists, f 35; +#X msg 611 424 set 4 dog 5 6 donkey; +#X text 766 419 "set" message changes contents but doesn't output them, f 30; #X text 793 671 updated for Pd version 0.52; -#X text 732 619 more details:; +#X text 749 559 more details:; #N canvas 715 193 459 477 properties 0; #N canvas 804 145 512 490 width 0; #X msg 132 130 symbol short; @@ -250,8 +250,8 @@ #X connect 14 0 8 0; #X restore 227 248 pd limits; #X text 206 76 <-- right click for properties; -#X restore 838 618 pd properties; -#X text 725 549 you can drag the numbers up and down individually \, and/or double click to edit just one element., f 36; +#X restore 855 558 pd properties; +#X text 725 496 you can drag the numbers up and down individually \, and/or double click to edit just one element., f 36; #X text 33 671 see also:; #X obj 109 672 all_guis; #X text 640 40 - list box; @@ -297,28 +297,30 @@ #X text 150 532 bang - output value.; #X restore 819 36 pd reference; #X obj 270 435 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X obj 593 433 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X obj 644 201 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X obj 593 394 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X obj 644 182 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X obj 270 513 print number box; -#X obj 559 593 print list box; -#X text 559 89 Symbol atom boxes are like number boxes but hold a symbol instead of a number:, f 58; -#X obj 614 264 print symbol box; -#X text 558 316 List boxes hold arbitrary combinations of numbers and symbols:, f 38; -#X text 618 433 output list; -#X text 762 141 set and output a symbol value; -#X text 668 200 output symbol; -#X msg 625 504 set; -#X text 662 497 set to an empty list (normally treated as a bang in Pd), f 30; +#X obj 559 540 print list box; +#X text 559 82 Symbol atom boxes are like number boxes but hold a symbol instead of a number:, f 58; +#X obj 614 240 print symbol box; +#X text 558 280 List boxes hold arbitrary combinations of numbers and symbols:, f 38; +#X text 618 394 output list; +#X text 762 124 set and output a symbol value; +#X text 668 181 output symbol; +#X msg 625 463 set; +#X text 662 456 set to an empty list (normally treated as a bang in Pd), f 30; #X text 135 475 click and drag -->; #X text 315 474 (or shift+click and drag); #X text 16 364 If the objects receive a proper message (like a float message for the number box below) \, they get displayed and pass through. A "set" message updates but doesn't output. A bang outputs its holding value. See the Number atom box below:, f 71; #X text 44 572 The number atom box object toggles between 0 and a non zero value If you click on a number box while pressing "control" (in Linux or Windows) or "command" (Mac). The non zero value is the last non zero value that the box holds (by default \, this value is "1")., f 66; -#X text 774 388 lists starting with a symbol must be preceded by the "list" selector to disambiguate them, f 30; +#X text 774 352 lists starting with a symbol must be preceded by the "list" selector to disambiguate them, f 30; #X text 16 317 You can also change a numeric value upward or downward by clicking and dragging. Shift-click changes the value in hundredths instead of units. This works for both number boxes and individual numbers in a list box., f 71; #X text 16 82 These GUI (Graphical User Interface) objects display and send atoms or lists. An atom is a single element message (symbol or float). A list is composed of more than one atom and can hold floats and/or symbols. These objects may be created by selecting "number" (etc.) from the "put" menu. The contents can be changed while the patch is in "run" mode (as opposed to "edit" mode) \, so these are useful as controls and displays in a finished patch., f 71; #X text 16 185 Clicking on the object activates it (indicated via a thicker border). Clicking outside the box deactivates it. When active \, you can hit enter to output the current value (this can be done multiple times). You can also type new values (using backspace to correct typing is allowed) and hit enter to validate and output them. You can cancel the typing action by reclicking on the object (to keep it activated) or outside it (to deactivate it). Double-clicking activates a text editor so that you can navigate with arrows and use backspace/delete or click and drag to select contents to cut/copy/paste (then also hit enter when done)., f 71; #X msg 227 435 1234; #X msg 300 435 set 4532; +#X obj 185 671 makefilename; +#X text 553 594 Note that floats are represented in the number and list boxes with the '%g' format and its default precision \, check the help file of [makefilename] for details., f 61; #X connect 0 0 35 0; #X connect 4 0 38 0; #X connect 5 0 4 0; diff --git a/doc/5.reference/help-intro.pd b/doc/5.reference/help-intro.pd index fac5a7f515..399412ae58 100644 --- a/doc/5.reference/help-intro.pd +++ b/doc/5.reference/help-intro.pd @@ -1,4 +1,4 @@ -#N canvas 419 23 590 723 12; +#N canvas 419 34 590 723 12; #X declare; #X obj 54 2364 delay; #X obj 54 2416 metro; @@ -507,3 +507,4 @@ #X obj 76 226 all_guis; #X text 143 225 <--; #X text 183 7473 - these used to be cheap 8 bits versions of square root functions but now are the same as srqt~] and [rsqrt~] (so just use them instead), f 51; +#X obj 114 6648 vpointer; diff --git a/doc/5.reference/line~-help.pd b/doc/5.reference/line~-help.pd index 88db24c73d..6a5eca6348 100644 --- a/doc/5.reference/line~-help.pd +++ b/doc/5.reference/line~-help.pd @@ -1,27 +1,27 @@ -#N canvas 507 38 517 678 12; -#X obj 78 503 snapshot~; +#N canvas 507 38 665 711 12; +#X obj 156 493 snapshot~; #X obj 31 15 line~; -#X obj 78 441 line~; -#X floatatom 78 536 8 0 0 0 - - - 0; -#X msg 50 207 1 1000; -#X msg 91 313 2; -#X msg 77 260 stop; -#X msg 86 290 0; -#X text 16 643 see also:; -#X obj 94 644 line; +#X obj 156 431 line~; +#X floatatom 156 525 8 0 0 0 - - - 0; +#X msg 118 197 1 1000; +#X msg 172 303 2; +#X msg 155 250 stop; +#X msg 164 280 0; +#X text 16 673 see also:; +#X obj 94 674 line; #X text 85 14 - audio ramp generator; -#X text 304 642 updated for Pd version 0.33; -#X obj 140 644 vline~; -#X floatatom 110 400 5 0 0 0 - - - 0; -#X text 125 295 a single number jumps to value immediately if no value is priorly sent to the right outlet, f 45; -#X text 152 393 right inlet sets next ramp time (cleared when ramp starts!), f 31; -#X text 117 207 a pair of numbers starts a ramp (first value: destination \, second: ramp time), f 38; -#X msg 62 230 0 5000; -#X obj 145 472 metro 100; -#X obj 145 445 loadbang; -#X msg 281 485 \; pd dsp \$1; -#X obj 8 46 cnv 1 500 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X text 427 13 <= click; +#X text 454 672 updated for Pd version 0.33; +#X obj 140 674 vline~; +#X floatatom 188 390 5 0 0 0 - - - 0; +#X text 206 285 a single number jumps to value immediately if no value is priorly sent to the right outlet, f 45; +#X text 230 383 right inlet sets next ramp time (cleared when ramp starts!), f 31; +#X text 185 197 a pair of numbers starts a ramp (first value: destination \, second: ramp time), f 38; +#X msg 130 220 0 5000; +#X obj 223 462 metro 100; +#X obj 223 435 loadbang; +#X msg 406 487 \; pd dsp \$1; +#X obj 8 46 cnv 1 650 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X text 557 13 <= click; #N canvas 742 179 579 267 reference 0; #X obj 9 41 cnv 5 550 5 empty empty INLETS: 8 18 0 13 #202020 #000000 0; #X obj 9 169 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; @@ -36,15 +36,15 @@ #X text 80 11 - audio ramp generator; #X text 126 178 signal - ramp values.; #X text 141 212 NONE; -#X restore 333 13 pd reference; -#X obj 8 629 cnv 1 500 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X msg 106 351 0 \, 1 1000; -#X text 185 344 setting start \, target and duration with two messages., f 28; -#X obj 281 449 set-dsp-tgl; -#X text 312 453 DSP on/off; -#X text 37 568 Note that the [line~] object cannot start and stop ramps in the middle of an audio block. For that \, you can use [vline~] \, which also has a delay parameter to schedule different line ramps., f 63; -#X text 28 60 The [line~] object generates linear ramps whose levels and timing are determined by messages you send it. Note that the right inlet value (for ramp time in milliseconds) is cleared when the object receives a value in the left inlet (unlike other objects in Pd). Thus \, if you don't reset a time in the right inlet before sending [line~] a float \, it jumps immediately to the target value. You can also use a list of two floats to distribute the values over the inlets (as usual in Pd) \, which keeps resetting the time ramp., f 66; -#X text 115 261 "stop" message freezes [line~] at its current value; +#X restore 463 13 pd reference; +#X msg 184 341 0 \, 1 1000; +#X text 263 334 setting start \, target and duration with two messages., f 28; +#X obj 406 451 set-dsp-tgl; +#X text 437 455 DSP on/off; +#X text 28 62 The [line~] object generates linear ramps whose levels and timing are determined by messages you send it. Note that the right inlet value (for ramp time in milliseconds) is cleared when the object receives a value in the left inlet (unlike other objects in Pd). Thus \, if you don't reset a time in the right inlet before sending [line~] a float \, it jumps immediately to the target value. You can also use a list of two floats to distribute the values over the inlets (as usual in Pd) \, which keeps resetting the time ramp., f 85; +#X text 193 251 "stop" message freezes [line~] at its current value; +#X obj 8 659 cnv 1 650 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X text 41 562 Note that the [line~] is always bound to audio block boundaries. This means it always starts a ramp in the beginning of an audio block and finishes it at the end of an audio block as well. If you want better precision with ramps that are shorter than an audio block or ramps that start and stop in the middle of an audio blocks you can use [vline~] \, which also has a delay parameter to schedule different ramps., f 85; #X connect 0 0 3 0; #X connect 2 0 0 0; #X connect 4 0 2 0; @@ -55,5 +55,5 @@ #X connect 17 0 2 0; #X connect 18 0 0 0; #X connect 19 0 18 0; -#X connect 25 0 2 0; -#X connect 27 0 20 0; +#X connect 24 0 2 0; +#X connect 26 0 20 0; diff --git a/doc/5.reference/list-help.pd b/doc/5.reference/list-help.pd index 49e8e89470..48a921477e 100644 --- a/doc/5.reference/list-help.pd +++ b/doc/5.reference/list-help.pd @@ -1,38 +1,33 @@ -#N canvas 403 50 607 569 12; +#N canvas 486 60 607 563 12; #X obj 24 12 list; -#N canvas 581 25 529 694 about-lists 0; -#X obj 95 661 print message; -#X msg 85 455 list x.wav 44100; -#X msg 95 632 read \$1 \$2; -#X msg 95 484 set x.wav 44100; -#X msg 128 595 set \, add2 read \, adddollar 1 \, adddollar 2; -#X msg 105 514 x.wav 44100; -#X obj 128 569 loadbang; -#X text 216 572 reset message as it was; -#X text 213 455 good; -#X text 212 486 bad; -#X text 198 514 ugly; -#X msg 294 476 list 44100 x.wav; -#X msg 307 501 44100 x.wav; -#X obj 294 527 print number-first; -#X text 288 448 these two are equivalent:; -#X msg 412 662 message; -#X text 247 626 for more details on setting messages and \$1 variables \, check the help file of message boxes:, f 36; +#N canvas 581 38 529 678 about-lists 0; +#X obj 110 632 print message; +#X msg 100 463 list x.wav 48000; +#X msg 110 599 read \$1 \$2; +#X msg 110 492 set x.wav 48000; +#X msg 120 522 x.wav 48000; +#X text 228 463 good; +#X text 227 494 bad; +#X text 213 522 ugly; +#X msg 314 490 list 48000 x.wav; +#X msg 327 515 48000 x.wav; +#X obj 314 547 print number-first; +#X text 319 450 these two are equivalent:, f 13; +#X msg 303 622 message; #X text 22 12 Messages in Pd are somewhat artificially divided into two classes. First are data-holding messages (bang \, float \, symbol \, list and pointer) which are the primary way of communicating between objects. Second is "everything else" (you could call them out-of-band messages \, metamessages or generic messages) \, which are provided for specific functionalities in complex objects and describe changes in configuration \, read and write files \, quit Pd \, etc. It's not clear whether this was a good design choice \, but it's entrenched., f 68; #X text 22 130 The distinction becomes visible \, and ugly \, when the leading item in a data-holding message is a symbol. In this case \, to disambiguate it from the other sort \, the message has a selector \, "list" or "symbol" prepended to it. Underneath \, there is always a selector in front of data messages \, but it is implied if the first data item is a number (a 'float' selector is implied for a single number and a 'list' selector is implied for lists that start with a number)., f 68; #X text 22 235 Conceptually \, a float and a symbol are 1 element lists. Conversely \, a list with one element is converted to a float or symbol. Similarly a bang is a zero element list and an empty list becomes a bang. You can find this behaviour throughout the functions of [list]., f 68; -#X text 22 298 In the example below \, the top message sets \$1 to "x.wav" and \$2 to 44100 in the "read" message. The lower message box outputs the message "read x.wav 44100". The "set" message changes the content of the message box itself (click on the longer message box below to repair the damage.) The "ugly" message is neither "list" nor "set" but a 'x.wav' message \, so the first element of the message is 44100 and there's no second element \, this is why it's "ugly" and an error is given that the '\$2' argument is out of range (which becomes 0). A bang is the same as an empty list so both '\$1' and '\$2' are out of range., f 68; -#X obj 118 542 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; -#X text 142 542 uglier; +#X text 22 298 In the example below \, the top message sets \$1 to "x.wav" and \$2 to 48000 in the "read" message. The lower message box outputs the message "read x.wav 48000". The "set" message changes the content of the message box itself (click on the longer message box below to repair the damage.) The "ugly" message is neither "list" nor "set" but a 'x.wav' message \, so the first element of the message is 48000 and there's no second element \, this is why it's "ugly" and an error is given that the '\$2' argument is out of range (which becomes 0). A bang is the same as an empty list so both '\$1' and '\$2' are out of range., f 68; +#X obj 133 550 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X text 157 550 uglier; +#X text 240 584 for more details on \$1 variables \, check the help file of message boxes:, f 33; #X connect 1 0 2 0; #X connect 2 0 0 0; #X connect 3 0 2 0; #X connect 4 0 2 0; -#X connect 5 0 2 0; -#X connect 6 0 4 0; -#X connect 11 0 13 0; -#X connect 12 0 13 0; -#X connect 21 0 2 0; +#X connect 8 0 10 0; +#X connect 9 0 10 0; +#X connect 17 0 2 0; #X restore 176 381 pd about-lists; #X obj 28 130 list append; #X obj 28 155 list prepend; diff --git a/doc/5.reference/makefilename-help.pd b/doc/5.reference/makefilename-help.pd index 907c947642..fbc669284a 100644 --- a/doc/5.reference/makefilename-help.pd +++ b/doc/5.reference/makefilename-help.pd @@ -1,8 +1,8 @@ -#N canvas 418 68 626 475 12; +#N canvas 398 67 626 475 12; #X floatatom 24 182 5 0 0 0 - - - 0; #X msg 392 182 symbol meat; #X msg 405 209 symbol hair; -#X obj 23 17 makefilename; +#X obj 20 17 makefilename; #X msg 56 234 set %d-zebra; #X symbolatom 43 296 14 0 0 0 - - - 0; #X obj 43 328 print Integer; @@ -32,45 +32,46 @@ #X connect 7 0 8 0; #X connect 10 0 5 0; #X restore 392 354 pd multiple_substitutions; -#N canvas 696 229 479 517 possible_types_&_syntax 0; -#N canvas 640 222 489 460 %c 0; -#X obj 147 214 list fromsymbol; -#X floatatom 147 313 5 0 0 0 - - - 0; -#X symbolatom 147 167 7 0 0 0 - - - 0; -#X symbolatom 147 388 7 0 0 0 - - - 0; -#X msg 164 248 64; -#X text 200 247 <= click (at symbol); -#X msg 174 278 123; -#X text 210 277 <= click (left curly); -#X text 71 27 %c - character:; -#X text 209 167 <=; -#X text 232 167 type a character to convert to float, f 23; -#X obj 147 350 makefilename [%c]; -#X text 69 61 This pattern allows you to convert from a float to a character (symbols are converted to 0) and insert it into a symbol. By the way \, you can also perform the opposite conversion (from a character to a float) by using the [list fromsymbol] object., f 53; +#N canvas 581 181 492 633 possible_types_&_syntax 0; +#N canvas 732 231 414 489 %c 0; +#X obj 100 249 list fromsymbol; +#X floatatom 100 368 5 0 0 0 - - - 0; +#X symbolatom 100 202 5 0 0 0 - - - 0; +#X symbolatom 100 443 7 0 0 0 - - - 0; +#X msg 117 283 64; +#X msg 127 333 123; +#X text 35 19 %c - character:; +#X text 166 202 type a character to convert to float, f 19; +#X obj 100 405 makefilename [%c]; +#X text 141 202 <--; +#X text 33 131 By the way \, you can also perform the opposite conversion (from a character symbol to a float) by using the [list fromsymbol] object., f 48; +#X text 153 282 <-- this is the '@' (at sign) character, f 20; +#X text 163 332 <-- (left curly); +#X text 33 53 This format specifier allows you to convert from a float (actually integers from 0 to 255) to a character symbol. A symbol input is converted to '0' (and this is also true for any other specifier besides '%s' and '%p')., f 48; #X connect 0 0 1 0; -#X connect 1 0 11 0; +#X connect 1 0 8 0; #X connect 2 0 0 0; #X connect 4 0 1 0; -#X connect 6 0 1 0; -#X connect 11 0 3 0; -#X restore 80 69 pd %c; -#N canvas 787 150 510 527 %d/%i 0; -#X floatatom 244 368 0 0 0 0 - - - 0; -#X symbolatom 94 464 12 0 0 0 - - - 0; +#X connect 5 0 1 0; +#X connect 8 0 3 0; +#X restore 80 98 pd %c; +#N canvas 787 150 532 561 %d/%i 0; +#X floatatom 244 398 10 0 0 0 - - - 0; +#X symbolatom 94 494 15 0 0 0 - - - 0; #X text 56 35 %d or %i - signed decimal integer:; -#X symbolatom 244 464 12 0 0 0 - - - 0; -#X msg 244 153 127; -#X msg 258 185 -255; -#X msg 269 221 1; -#X msg 275 251 -1; -#X obj 94 416 makefilename [%d]; -#X msg 194 189 12.9; -#X msg 286 288 1e+06; -#X msg 294 322 -1e+07; -#X text 54 64 Both '%d' and '%i' are the same. This pattern allows you to insert a signed (negative or positive) decimal integer into a symbol (symbols are converted to 0). Floats are truncated.; -#X obj 244 416 makefilename [%i]; +#X symbolatom 244 494 15 0 0 0 - - - 0; +#X msg 244 183 127; +#X msg 258 215 -255; +#X msg 269 251 1; +#X msg 275 281 -1; +#X obj 94 446 makefilename [%d]; +#X msg 194 219 12.9; +#X msg 294 352 -1e+07; +#X obj 244 446 makefilename [%i]; +#X msg 286 318 2e+09; +#X text 54 64 Both '%d' and '%i' are the same. This format specifier allows you to insert a signed (negative or positive) decimal integer into a symbol. Note that floats with a decimal point are truncated., f 61; #X connect 0 0 8 0; -#X connect 0 0 13 0; +#X connect 0 0 11 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 6 0 0 0; @@ -78,113 +79,98 @@ #X connect 8 0 1 0; #X connect 9 0 0 0; #X connect 10 0 0 0; -#X connect 11 0 0 0; -#X connect 13 0 3 0; -#X restore 59 97 pd %d/%i; -#N canvas 762 278 567 409 %e/%E 0; -#X floatatom 269 239 10 0 0 0 - - - 0; -#X symbolatom 119 335 18 0 0 0 - - - 0; -#X symbolatom 269 335 18 0 0 0 - - - 0; -#X obj 119 287 makefilename [%e]; -#X msg 269 164 1.23456; -#X msg 241 136 2.345e-05; -#X msg 298 199 -18; -#X text 54 26 %e or %E - scientific notation using "e" or "E" character:; -#X obj 269 287 makefilename [%E]; -#X text 53 53 This pattern allows you to insert a number with scientific notation into a symbol (symbols are converted to 0). The '%e' or '%E' pattern specify respectively whether the exponential character is lower (e) or upper (E) case., f 71; +#X connect 11 0 3 0; +#X connect 12 0 0 0; +#X restore 59 126 pd %d/%i; +#N canvas 751 239 511 507 %e/%E 0; +#X floatatom 256 264 10 0 0 0 - - - 0; +#X symbolatom 106 360 18 0 0 0 - - - 0; +#X symbolatom 256 360 18 0 0 0 - - - 0; +#X obj 106 312 makefilename [%e]; +#X msg 256 189 1.23456; +#X msg 228 161 2.345e-05; +#X msg 285 224 -18; +#X obj 256 312 makefilename [%E]; +#X text 62 16 %e or %E - float numbers in scientific notation:; +#X text 65 406 Note that there's a default precision of 6 digits after the decimal point and before 'e'/'E'. You can change this precision as shown later. Also note that trailing zeros (zeros to the right of the decimal point) are always shown. This means you're always aware of the given precision., f 52; +#X msg 187 161 1; +#X text 61 43 This format specifier allows you to insert a float number with scientific notation into a symbol. The '%e' or '%E' pattern specify respectively whether the exponential character is lower (e) or upper (E) case. Also \, it prints 'NAN' and 'INF' in all CAPS for %E \, while '%e' uses lowercase., f 53; #X connect 0 0 3 0; -#X connect 0 0 8 0; +#X connect 0 0 7 0; #X connect 3 0 1 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 6 0 0 0; -#X connect 8 0 2 0; -#X restore 59 125 pd %e/%E; -#X text 127 68 - character; -#X text 127 96 - signed decimal integer; -#X text 128 152 - decimal floating point; -#N canvas 787 279 483 431 %f 0; -#X symbolatom 166 358 18 0 0 0 - - - 0; -#X floatatom 166 268 8 0 0 0 - - - 0; -#X msg 166 164 1.234; -#X msg 180 196 -18; -#X msg 135 132 2.3e-05; -#X msg 191 231 0.997; -#X text 70 29 %f - decimal floating point:; -#X obj 166 310 makefilename [%f]; -#X text 68 63 This pattern allows you to format a float into a symbol (symbols are converted to 0)., f 43; -#X connect 1 0 7 0; -#X connect 2 0 1 0; -#X connect 3 0 1 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X connect 7 0 0 0; -#X restore 80 153 pd %f; -#N canvas 521 79 612 539 %g/%G 0; -#X floatatom 304 368 10 0 0 0 - - - 0; -#X symbolatom 154 464 18 0 0 0 - - - 0; -#X symbolatom 304 464 18 0 0 0 - - - 0; -#X msg 332 250 1.23456; -#X obj 154 416 makefilename [%g]; -#X msg 349 321 0.99999; -#X msg 304 222 2.345e-05; -#X msg 346 282 1.1e+08; -#X msg 278 191 -1800; -#X msg 240 191 179; -#X text 36 20 %g or %G - numbers with or without scientific notation:; -#X obj 304 416 makefilename [%G]; -#X text 34 53 This pattern allows you to insert a number with or without scientific notation into a symbol (symbols are converted to 0). The '%g' or '%G' pattern specify respectively whether the exponential character is lower (e) or upper (E) case. The scientific notation is only used if there's not enough digit resolution. The default precision is 6 digits and we'll see how to change that later., f 78; -#X text 34 130 Also \, the decimal point is not included on whole numbers. This means that \, unlike '%e' or '%E' \, not at all numbers are converted to scientific notation., f 78; -#X connect 0 0 4 0; +#X connect 7 0 2 0; +#X connect 10 0 0 0; +#X restore 59 154 pd %e/%E; +#X text 127 97 - character; +#X text 127 125 - signed decimal integer; +#X text 128 181 - decimal floating point; +#N canvas 784 131 579 621 %g/%G 0; +#X floatatom 258 450 12 0 0 0 - - - 0; +#X symbolatom 258 546 18 0 0 0 - - - 0; +#X msg 257 303 1.23456; +#X msg 278 335 2.345e-05; +#X msg 300 364 1.1e+08; +#X msg 170 275 -1800; +#X msg 132 275 179; +#X obj 258 498 makefilename [%G]; +#X msg 303 403 0.999999; +#X text 38 24 %g or %G - floats with or without scientific notation:, f 68; +#X symbolatom 108 546 18 0 0 0 - - - 0; +#X obj 108 498 makefilename [%g]; +#X msg 221 275 0.000123456; +#X text 34 201 Note that this is the format pattern used by Pd to display numbers in comments \, message boxes and also GUI boxes and iemgui's [nbx] (with the same default precision of 6 significant digits)., f 69; +#X text 34 55 Unlike %f' and '%e'/'%E' \, this format specifier doesn't show trailing zeros. Therefore \, values without significant digits after the decimal point come out looking like integers (as there's not dot at the end). The scientific notation is used in negative form if the exponent value is lower than '-4'. For the positive form \, it's used only if the exponent is equal to or higher than the precision value (again this is '6' by default and can be changed later). The '%g' or '%G' pattern specify respectively whether the exponential character is lower (e) or upper (E) case. Also \, it prints 'NAN' and 'INF' in all CAPS for %G \, while '%g' uses lowercase., f 69; +#X connect 0 0 7 0; #X connect 0 0 11 0; +#X connect 2 0 0 0; #X connect 3 0 0 0; -#X connect 4 0 1 0; +#X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 6 0 0 0; -#X connect 7 0 0 0; +#X connect 7 0 1 0; #X connect 8 0 0 0; -#X connect 9 0 0 0; -#X connect 11 0 2 0; -#X restore 59 181 pd %g/%G; -#X text 128 124 - decimal floating point in scientific notation; -#X text 128 180 - numbers with or without scientific notation; -#N canvas 836 149 529 506 %o 0; -#X floatatom 208 337 0 0 0 0 - - - 0; -#X symbolatom 208 433 14 0 0 0 - - - 0; -#X msg 219 190 1; -#X msg 230 220 -1; -#X msg 127 232 1.9; -#X msg 172 154 9; -#X msg 208 154 16; -#X msg 253 291 1e+12; -#X msg 243 255 1e+09; +#X connect 11 0 10 0; +#X connect 12 0 0 0; +#X restore 59 210 pd %g/%G; +#X text 128 153 - decimal floating point in scientific notation; +#N canvas 836 149 414 466 %o 0; +#X floatatom 136 301 8 0 0 0 - - - 0; +#X symbolatom 136 397 14 0 0 0 - - - 0; +#X msg 147 174 1; +#X msg 55 216 1.9; +#X msg 100 138 9; +#X msg 136 138 16; +#X msg 174 252 1e+12; +#X msg 164 216 1e+09; #X text 52 27 %o - unsigned octal:; -#X obj 208 385 makefilename [%o]; -#X text 53 59 This pattern allows you to insert an unsigned (only positive) octal integer into a symbol (symbols are converted to 0). Floats are truncated. Note that since this is an unsigned format \, sending negative numbers doesn't work., f 61; -#X connect 0 0 10 0; +#X obj 136 349 makefilename [%o]; +#X text 53 59 This format specifier allows you to insert an unsigned (only positive) octal integer into a symbol. Floats are truncated., f 42; +#X connect 0 0 9 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 6 0 0 0; #X connect 7 0 0 0; -#X connect 8 0 0 0; -#X connect 10 0 1 0; -#X restore 80 209 pd %o; -#X text 126 208 - unsigned octal; -#N canvas 788 215 489 431 %s 0; -#X symbolatom 129 133 7 0 0 0 - - - 0; -#X symbolatom 167 356 10 0 0 0 - - - 0; -#X obj 167 308 makefilename [%s]; -#X floatatom 167 166 5 0 0 0 - - - 0; -#X msg 197 205 symbol dog; -#X msg 206 243 -1; -#X msg 249 243 1.9; -#X msg 249 273 1e-07; -#X text 186 133 <= send it a symbol; -#X text 214 165 <= send it a float; -#X text 73 65 This pattern allows you to insert a symbol \, but note it also works for float messages., f 49; -#X text 76 31 %s - symbol string:; +#X connect 9 0 1 0; +#X restore 80 238 pd %o; +#X text 126 237 - unsigned octal; +#N canvas 788 215 458 430 %s 0; +#X symbolatom 110 146 7 0 0 0 - - - 0; +#X symbolatom 148 369 10 0 0 0 - - - 0; +#X obj 148 321 makefilename [%s]; +#X floatatom 148 179 10 0 0 0 - - - 0; +#X msg 178 218 symbol dog; +#X msg 187 256 -1; +#X msg 230 256 1.9; +#X msg 230 286 1e-07; +#X text 62 28 %s - symbol string:; +#X text 229 178 <-- send it a float; +#X text 167 146 <-- send it a symbol; +#X text 59 62 This format specifier allows you to insert a symbol \, but note it also works for float messages. You can set a precision as shown later \, but there's no default precision., f 52; #X connect 0 0 2 0; #X connect 2 0 1 0; #X connect 3 0 2 0; @@ -192,341 +178,317 @@ #X connect 5 0 2 0; #X connect 6 0 2 0; #X connect 7 0 2 0; -#X restore 80 237 pd %s; -#X text 126 264 - signed decimal integer; -#N canvas 766 264 519 474 %u 0; -#X floatatom 185 337 0 0 0 0 - - - 0; -#X symbolatom 185 415 12 0 0 0 - - - 0; -#X msg 185 152 127; -#X msg 199 184 -255; -#X msg 210 220 1; -#X msg 216 250 -1; -#X msg 135 188 12.9; +#X restore 80 266 pd %s; +#X text 126 293 - signed decimal integer; +#N canvas 784 259 405 451 %u 0; +#X floatatom 150 293 9 0 0 0 - - - 0; +#X symbolatom 150 371 14 0 0 0 - - - 0; +#X msg 150 138 127; +#X msg 164 170 -255; +#X msg 175 206 1; +#X msg 100 174 12.9; #X text 45 25 %u - unsigned decimal integer:; -#X obj 185 376 makefilename [%u]; -#X msg 227 287 1e+09; -#X text 43 60 This pattern is the same as "%d" or "%i" \, but it is unsigned (only positive) \, hence it allows you to insert a decimal integer into a symbol (symbols are converted to 0). Floats are truncated to integers. Note that since this is an unsigned format \, sending negative numbers doesn't work.; -#X connect 0 0 8 0; +#X obj 150 332 makefilename [%u]; +#X msg 192 243 1e+12; +#X text 43 59 This format specifier is the same as "%d" or "%i" \, but it is unsigned (only positive). Floats are truncated to integers., f 44; +#X connect 0 0 7 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 4 0 0 0; #X connect 5 0 0 0; -#X connect 6 0 0 0; -#X connect 8 0 1 0; -#X connect 9 0 0 0; -#X restore 80 265 pd %u; -#X text 127 292 - unsigned hexadecimal; -#N canvas 781 226 510 490 %x/%X 0; -#X floatatom 262 338 0 0 0 0 - - - 0; -#X symbolatom 112 434 12 0 0 0 - - - 0; -#X symbolatom 262 434 12 0 0 0 - - - 0; -#X msg 262 153 127; -#X msg 287 221 1; -#X msg 293 251 -1; -#X msg 304 288 1e+09; -#X obj 112 386 makefilename [%x]; -#X msg 276 185 255; -#X msg 212 189 9.9; -#X text 70 11 %x or %X - unsigned hexadecimal:; -#X obj 262 386 makefilename [%X]; -#X text 61 46 This pattern allows you to insert a signed (only positive) hexadecimal integer into a symbol (symbols are converted to 0). Floats are truncated. The '%x' or '%X' pattern specify respectively whether the the characters are lower or upper case. Note that since this is an unsigned format \, sending negative numbers doesn't work., f 61; -#X connect 0 0 7 0; -#X connect 0 0 11 0; +#X connect 7 0 1 0; +#X connect 8 0 0 0; +#X restore 80 294 pd %u; +#N canvas 781 226 439 467 %x/%X 0; +#X floatatom 211 304 9 0 0 0 - - - 0; +#X symbolatom 61 400 12 0 0 0 - - - 0; +#X symbolatom 211 400 12 0 0 0 - - - 0; +#X msg 211 149 127; +#X msg 236 217 1; +#X msg 253 254 1e+09; +#X obj 61 352 makefilename [%x]; +#X msg 225 181 255; +#X msg 161 185 9.9; +#X text 40 11 %x or %X - unsigned hexadecimal:; +#X obj 211 352 makefilename [%X]; +#X text 31 46 This format specifier allows you to insert a signed (only positive) hexadecimal integer into a symbol. Floats are truncated. The '%x' or '%X' specify respectively whether the the characters are lower or upper case., f 51; +#X connect 0 0 6 0; +#X connect 0 0 10 0; #X connect 3 0 0 0; #X connect 4 0 0 0; #X connect 5 0 0 0; -#X connect 6 0 0 0; -#X connect 7 0 1 0; +#X connect 6 0 1 0; +#X connect 7 0 0 0; #X connect 8 0 0 0; -#X connect 9 0 0 0; -#X connect 11 0 2 0; -#X restore 59 293 pd %x/%X; +#X connect 10 0 2 0; +#X restore 59 322 pd %x/%X; #N canvas 921 253 483 354 %p 0; #X symbolatom 164 163 10 0 0 0 - - - 0; #X symbolatom 164 259 14 0 0 0 - - - 0; #X obj 164 210 makefilename [%p]; #X text 57 44 %p - pointer representation:; -#X text 54 77 This pattern formats to a platform specific pointer representation of an incoming symbol (floats are cast to int and also converted)., f 53; +#X text 54 77 This format specifier formats to a platform specific pointer representation of an incoming symbol (floats are cast to int and also converted)., f 53; #X connect 0 0 2 0; #X connect 2 0 1 0; -#X restore 80 321 pd %p; -#X text 126 320 - pointer representation; -#X text 163 414 flags:; -#N canvas 216 23 794 593 + 0; -#X floatatom 150 188 0 0 0 0 - - - 0; -#X symbolatom 150 263 12 0 0 0 - - - 0; -#X msg 109 105 127; -#X msg 150 105 -255; -#X msg 168 137 1e+06; -#X msg 220 137 -1e+07; -#X obj 150 225 makefilename [%+d]; -#X floatatom 167 431 10 0 0 0 - - - 0; -#X symbolatom 167 514 18 0 0 0 - - - 0; -#X msg 169 326 1.23456; -#X msg 94 326 2.345e-05; -#X msg 196 391 -18; -#X msg 183 358 1.999e+07; -#X obj 167 466 makefilename [%+e]; -#X symbolatom 516 191 18 0 0 0 - - - 0; -#X floatatom 516 103 8 0 0 0 - - - 0; -#X msg 530 61 -18; -#X msg 450 30 2.3e-05; -#X obj 516 143 makefilename [%+f]; -#X msg 516 29 257; -#X floatatom 540 424 10 0 0 0 - - - 0; -#X symbolatom 540 511 18 0 0 0 - - - 0; -#X msg 568 306 1.23456; -#X msg 585 377 0.99999; -#X msg 540 278 2.345e-05; -#X msg 582 338 1.1e+08; -#X msg 514 247 -1800; -#X msg 476 247 179; -#X obj 540 463 makefilename [%+G]; -#X text 65 38 The "+" flag prepends a plus sign for positive signed numeric types (%d/%i/%e/%E/%f/%g/%G):, f 47; +#X restore 80 350 pd %p; +#X text 126 349 - pointer representation; +#N canvas 447 135 841 548 # 0; +#X floatatom 176 168 0 0 0 0 - - - 0; +#X symbolatom 176 231 14 0 0 0 - - - 0; +#X msg 176 126 1; +#X msg 108 126 9; +#X msg 144 126 16; +#X msg 211 126 1e+09; +#X obj 176 199 makefilename [%#o]; +#X floatatom 223 394 8 0 0 0 - - - 0; +#X symbolatom 223 467 14 0 0 0 - - - 0; +#X msg 223 352 1; +#X msg 155 352 9; +#X msg 191 352 16; +#X msg 258 352 1e+09; +#X symbolatom 82 467 14 0 0 0 - - - 0; +#X obj 82 429 makefilename [%#x]; +#X obj 223 429 makefilename [%#X]; +#X floatatom 585 152 10 0 0 0 - - - 0; +#X symbolatom 435 248 18 0 0 0 - - - 0; +#X symbolatom 585 248 18 0 0 0 - - - 0; +#X msg 585 105 -1800; +#X msg 547 105 179; +#X obj 585 200 makefilename [%G]; +#X msg 638 106 1e+08; +#X text 83 285 For "%x" and "%X" \, the number is preceded by "0x" (if %x) or "0X" (if %X)., f 32; +#X obj 435 200 makefilename [%#+g]; +#X text 403 25 For %g and %G \, the decimal point and trailing zeroes are not removed. Note that this flag can be combined with '+' or 'space' flags., f 46; +#X text 53 45 The '#' (hash) flag presents an alternate form of some numeric types. For "%o" \, the number is preceded by a "0"., f 41; +#X floatatom 578 399 8 0 0 0 - - - 0; +#X symbolatom 578 472 17 0 0 0 - - - 0; +#X msg 578 357 1; +#X msg 507 357 9; +#X msg 543 357 16; +#X symbolatom 437 472 16 0 0 0 - - - 0; +#X obj 437 434 makefilename [%a]; +#X obj 578 434 makefilename [%#a]; +#X msg 612 357 1.5; +#X text 426 295 For "%a" and "%A" \, the number has a decimal point even if there is no fractional part., f 43; #X connect 0 0 6 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 6 0 1 0; -#X connect 7 0 13 0; -#X connect 9 0 7 0; -#X connect 10 0 7 0; -#X connect 11 0 7 0; -#X connect 12 0 7 0; -#X connect 13 0 8 0; -#X connect 15 0 18 0; -#X connect 16 0 15 0; -#X connect 17 0 15 0; -#X connect 18 0 14 0; -#X connect 19 0 15 0; -#X connect 20 0 28 0; -#X connect 22 0 20 0; -#X connect 23 0 20 0; -#X connect 24 0 20 0; -#X connect 25 0 20 0; -#X connect 26 0 20 0; -#X connect 27 0 20 0; -#X connect 28 0 21 0; -#X restore 216 415 pd +; -#N canvas 537 79 756 491 # 0; -#X floatatom 148 115 0 0 0 0 - - - 0; -#X symbolatom 148 178 14 0 0 0 - - - 0; -#X msg 148 73 1; -#X msg 80 73 9; -#X msg 116 73 16; -#X msg 183 73 1e+09; -#X obj 148 146 makefilename [%#o]; -#X floatatom 196 326 0 0 0 0 - - - 0; -#X symbolatom 196 399 14 0 0 0 - - - 0; -#X msg 196 284 1; -#X msg 128 284 9; -#X msg 164 284 16; -#X msg 231 284 1e+09; -#X symbolatom 55 399 14 0 0 0 - - - 0; -#X obj 55 361 makefilename [%#x]; -#X obj 196 361 makefilename [%#X]; -#X text 25 22 The '#' flag presents an alternate form of some numeric types. For "%o" \, the number is preceded by a "0".; -#X floatatom 565 237 10 0 0 0 - - - 0; -#X symbolatom 415 333 18 0 0 0 - - - 0; -#X symbolatom 565 333 18 0 0 0 - - - 0; -#X msg 565 190 -1800; -#X msg 527 190 179; -#X obj 415 285 makefilename [%#g]; -#X obj 565 285 makefilename [%G]; -#X msg 618 191 1e+08; -#X text 44 222 For "%x" and "%X" \, the number is preceded by "0x" (if %x) or "0X" (if %X)., f 43; -#X text 419 123 For %g and %G \, the decimal point and trailing zeroes are not removed., f 36; -#X connect 0 0 6 0; -#X connect 2 0 0 0; -#X connect 3 0 0 0; -#X connect 4 0 0 0; -#X connect 5 0 0 0; -#X connect 6 0 1 0; -#X connect 7 0 14 0; #X connect 7 0 15 0; +#X connect 7 0 14 0; #X connect 9 0 7 0; #X connect 10 0 7 0; #X connect 11 0 7 0; #X connect 12 0 7 0; #X connect 14 0 13 0; #X connect 15 0 8 0; -#X connect 17 0 22 0; -#X connect 17 0 23 0; -#X connect 20 0 17 0; -#X connect 21 0 17 0; -#X connect 22 0 18 0; -#X connect 23 0 19 0; +#X connect 16 0 21 0; +#X connect 16 0 24 0; +#X connect 19 0 16 0; +#X connect 20 0 16 0; +#X connect 21 0 18 0; +#X connect 22 0 16 0; #X connect 24 0 17 0; -#X restore 271 415 pd #; -#X text 50 20 This is a listing of possible printf pattern types. Open subpatches for more details and examples., f 51; -#X text 163 444 width:; -#N canvas 542 148 928 523 width 0; -#X floatatom 102 171 0 0 0 0 - - - 0; -#X symbolatom 102 235 12 0 0 0 - - - 0; -#X obj 102 203 makefilename [%5d]; -#X msg 102 114 1; -#X msg 138 114 -1000; -#X msg 64 114 10; -#X floatatom 194 387 0 0 0 0 - - - 0; -#X symbolatom 194 463 12 0 0 0 - - - 0; -#X msg 194 352 1; -#X symbolatom 282 235 12 0 0 0 - - - 0; -#X obj 282 203 makefilename [%5s]; -#X symbolatom 282 171 10 0 0 0 - - - 0; -#X msg 295 143 symbol abcde; -#X msg 261 92 symbol a; -#X msg 282 117 symbol abc; -#X msg 150 139 -1e+06; -#X msg 156 352 31; -#X msg 234 352 1e+06; -#X obj 194 426 makefilename [%05x]; -#X text 39 286 The width field takes an optional preceding '0' flag that fills the extra characters with zeroes instead of spaces.; -#X floatatom 539 176 0 0 0 0 - - - 0; -#X symbolatom 539 240 12 0 0 0 - - - 0; -#X msg 539 119 1; -#X msg 575 119 -1000; -#X msg 501 119 10; -#X msg 587 144 -1e+06; -#X obj 539 208 makefilename [%+5d]; -#X floatatom 707 175 0 0 0 0 - - - 0; -#X symbolatom 707 239 12 0 0 0 - - - 0; -#X msg 707 118 1; -#X msg 743 118 -1000; -#X msg 669 118 10; -#X msg 755 143 -1e+06; -#X obj 707 207 makefilename [%+05d]; -#X floatatom 556 372 0 0 0 0 - - - 0; -#X symbolatom 556 436 12 0 0 0 - - - 0; -#X msg 556 315 1; -#X msg 604 340 -1e+06; -#X floatatom 724 371 0 0 0 0 - - - 0; -#X symbolatom 724 435 12 0 0 0 - - - 0; -#X msg 724 314 1; -#X msg 772 339 -1e+06; -#X text 498 63 You can combine the width field with the preceding +/# flags where pertinent., f 40; -#X msg 592 315 100; -#X msg 760 314 100; -#X msg 686 314 31; -#X msg 518 315 31; -#X obj 556 404 makefilename [%#5x]; -#X obj 724 403 makefilename [%#08X]; -#X text 24 18 The width field takes an integer that sets the number of minimum characters and adds spaces to fill them. This works for all types but floating point numbers ('%f' and '%e'/'%E'). In the case of '%g'/'%G' \, the width field is valid only for the integer output., f 62; -#X connect 0 0 2 0; -#X connect 2 0 1 0; -#X connect 3 0 0 0; -#X connect 4 0 0 0; -#X connect 5 0 0 0; -#X connect 6 0 18 0; -#X connect 8 0 6 0; -#X connect 10 0 9 0; -#X connect 11 0 10 0; -#X connect 12 0 11 0; -#X connect 13 0 11 0; -#X connect 14 0 11 0; -#X connect 15 0 0 0; -#X connect 16 0 6 0; -#X connect 17 0 6 0; -#X connect 18 0 7 0; -#X connect 20 0 26 0; -#X connect 22 0 20 0; -#X connect 23 0 20 0; -#X connect 24 0 20 0; -#X connect 25 0 20 0; -#X connect 26 0 21 0; #X connect 27 0 33 0; +#X connect 27 0 34 0; #X connect 29 0 27 0; #X connect 30 0 27 0; #X connect 31 0 27 0; -#X connect 32 0 27 0; -#X connect 33 0 28 0; -#X connect 34 0 47 0; -#X connect 36 0 34 0; -#X connect 37 0 34 0; -#X connect 38 0 48 0; -#X connect 40 0 38 0; -#X connect 41 0 38 0; -#X connect 43 0 34 0; -#X connect 44 0 38 0; -#X connect 45 0 38 0; -#X connect 46 0 34 0; -#X connect 47 0 35 0; -#X connect 48 0 39 0; -#X restore 216 445 pd width; -#X text 135 474 precision:; -#N canvas 551 477 448 268 precision 0; -#N canvas 842 141 470 564 strings 0; -#X symbolatom 219 496 0 0 0 0 - - - 0; -#X symbolatom 219 418 10 0 0 0 - - - 0; -#X obj 219 458 makefilename [%3.4s]; -#X symbolatom 231 223 0 0 0 0 - - - 0; -#X symbolatom 231 154 10 0 0 0 - - - 0; -#X obj 231 189 makefilename [%.4s]; -#X msg 231 115 symbol abcde; -#X msg 127 115 symbol abcd; -#X text 61 260 In this case \, the width field can be preceded to set a minimum of characters filled with spaces., f 48; -#X msg 141 316 symbol ab; -#X msg 219 316 symbol abc; -#X msg 246 383 symbol abcde; -#X msg 234 350 symbol abcd; -#X text 54 33 For symbol srtrings (%s) \, the precision sets a maximum character limit. Below \, we have a maximum of 4 characters \, hence \, the symbol "abcde" gets truncated., f 53; -#X connect 1 0 2 0; +#X connect 33 0 32 0; +#X connect 34 0 28 0; +#X connect 35 0 27 0; +#X restore 312 489 pd #; +#X text 154 518 width:; +#N canvas 499 154 928 523 width 0; +#X floatatom 102 181 9 0 0 0 - - - 0; +#X symbolatom 102 245 12 0 0 0 - - - 0; +#X msg 102 124 1; +#X msg 138 124 -1000; +#X msg 64 124 10; +#X symbolatom 108 473 12 0 0 0 - - - 0; +#X msg 108 371 1; +#X symbolatom 282 245 12 0 0 0 - - - 0; +#X symbolatom 282 181 10 0 0 0 - - - 0; +#X msg 295 153 symbol abcde; +#X msg 261 102 symbol a; +#X msg 282 127 symbol abc; +#X msg 150 149 -1e+06; +#X msg 70 371 31; +#X msg 148 371 1e+06; +#X floatatom 530 151 0 0 0 0 - - - 0; +#X symbolatom 530 215 13 0 0 0 - - - 0; +#X msg 492 94 10; +#X floatatom 698 150 0 0 0 0 - - - 0; +#X symbolatom 698 214 13 0 0 0 - - - 0; +#X msg 698 93 1; +#X msg 734 93 -1000; +#X msg 660 93 10; +#X msg 746 118 -1e+06; +#X symbolatom 547 439 12 0 0 0 - - - 0; +#X msg 547 290 1; +#X msg 595 315 -1e+06; +#X symbolatom 715 439 14 0 0 0 - - - 0; +#X msg 715 289 1; +#X msg 763 314 -1e+06; +#X msg 583 290 100; +#X msg 751 289 100; +#X msg 677 289 31; +#X msg 509 290 31; +#X obj 102 213 makefilename [%5d]; +#X msg 566 94 -100; +#X floatatom 108 406 9 0 0 0 - - - 0; +#X floatatom 547 362 9 0 0 0 - - - 0; +#X floatatom 715 362 9 0 0 0 - - - 0; +#X obj 282 213 makefilename [%-5s]; +#X obj 108 445 makefilename [%05x]; +#X text 45 289 The width field can alternatively take the optional preceding '0' flag \, which fills the extra characters with leading zeroes instead of spaces., f 52; +#X text 489 30 You can also combine the width field with the preceding +/space/# flags where pertinent., f 46; +#X obj 698 182 makefilename [%\ -5d]; +#X obj 547 401 makefilename [%#5x]; +#X obj 715 401 makefilename [%#08X]; +#X symbolatom 318 477 12 0 0 0 - - - 0; +#X msg 231 364 1; +#X msg 271 364 1e+06; +#X obj 318 449 makefilename [%05s]; +#X msg 317 363 symbol a; +#X msg 338 388 symbol abc; +#X listbox 318 422 10 0 0 0 - - - 0; +#X obj 530 183 makefilename [%+-5g]; +#X msg 530 94 1.1; +#X msg 578 119 -1.234e+06; +#X text 36 13 The width field takes an integer that sets the number of minimum characters and adds spaces to fill them (justifying the format to the right). This works for all types but the floating point numbers '%f' and '%e'/'%E' ('%g'/'%G' works). An optional '-' flag justifies to the left., f 55; +#X connect 0 0 34 0; #X connect 2 0 0 0; -#X connect 4 0 5 0; +#X connect 3 0 0 0; +#X connect 4 0 0 0; +#X connect 6 0 36 0; +#X connect 8 0 39 0; +#X connect 9 0 8 0; +#X connect 10 0 8 0; +#X connect 11 0 8 0; +#X connect 12 0 0 0; +#X connect 13 0 36 0; +#X connect 14 0 36 0; +#X connect 15 0 53 0; +#X connect 17 0 15 0; +#X connect 18 0 43 0; +#X connect 20 0 18 0; +#X connect 21 0 18 0; +#X connect 22 0 18 0; +#X connect 23 0 18 0; +#X connect 25 0 37 0; +#X connect 26 0 37 0; +#X connect 28 0 38 0; +#X connect 29 0 38 0; +#X connect 30 0 37 0; +#X connect 31 0 38 0; +#X connect 32 0 38 0; +#X connect 33 0 37 0; +#X connect 34 0 1 0; +#X connect 35 0 15 0; +#X connect 36 0 40 0; +#X connect 37 0 44 0; +#X connect 38 0 45 0; +#X connect 39 0 7 0; +#X connect 40 0 5 0; +#X connect 43 0 19 0; +#X connect 44 0 24 0; +#X connect 45 0 27 0; +#X connect 47 0 52 0; +#X connect 48 0 52 0; +#X connect 49 0 46 0; +#X connect 50 0 52 0; +#X connect 51 0 52 0; +#X connect 52 0 49 0; +#X connect 53 0 16 0; +#X connect 54 0 15 0; +#X connect 55 0 15 0; +#X restore 207 519 pd width; +#X text 126 548 precision:; +#N canvas 502 451 448 268 precision 0; +#N canvas 842 141 470 564 strings 0; +#X symbolatom 214 521 8 0 0 0 - - - 0; +#X symbolatom 214 443 10 0 0 0 - - - 0; +#X symbolatom 193 223 8 0 0 0 - - - 0; +#X symbolatom 193 154 10 0 0 0 - - - 0; +#X obj 193 189 makefilename [%.4s]; +#X msg 193 115 symbol abcde; +#X msg 89 115 symbol abcd; +#X msg 136 341 symbol ab; +#X msg 214 341 symbol abc; +#X msg 241 408 symbol abcde; +#X msg 229 375 symbol abcd; +#X text 40 28 For symbol srtrings (%s) \, the precision sets a maximum character limit. Below \, we have a maximum of 4 characters \, hence \, the symbol "abcde" gets truncated. There's no default precision by the way., f 58; +#X obj 214 483 makefilename [%-3.4s]; +#X text 61 260 In this case \, the width field can be preceded to set a minimum of characters filled with spaces. The example below also makes use of the optional '-' flag to justify it to the left., f 48; +#X connect 1 0 12 0; +#X connect 3 0 4 0; +#X connect 4 0 2 0; #X connect 5 0 3 0; -#X connect 6 0 4 0; -#X connect 7 0 4 0; +#X connect 6 0 3 0; +#X connect 7 0 1 0; +#X connect 8 0 1 0; #X connect 9 0 1 0; #X connect 10 0 1 0; -#X connect 11 0 1 0; -#X connect 12 0 1 0; +#X connect 12 0 0 0; #X restore 159 133 pd strings; -#N canvas 788 237 558 412 integers 0; -#X symbolatom 126 293 0 0 0 0 - - - 0; -#X obj 126 249 makefilename [%.4d]; -#X symbolatom 287 288 0 0 0 0 - - - 0; -#X floatatom 287 205 5 0 0 0 - - - 0; -#X msg 287 172 -3; -#X obj 287 249 makefilename [%04d]; -#X msg 325 173 3; -#X text 78 40 For integer types ('%d'/'%i'/'%o'/'%u'/'%x'/'%X'/'%p') \, the precision field does not set a maximum number of characters. Instead \, it sets a fixed number of digits and adds zeroes to the left as a fill. This is slightly different than setting a width field with a '0' flag. The difference is only observed for numbers of different sign as below. Note how the width field will suppress a zero to include a "-" character., f 61; -#X connect 1 0 0 0; -#X connect 3 0 5 0; +#N canvas 793 252 531 363 integers 0; +#X symbolatom 99 278 10 0 0 0 - - - 0; +#X floatatom 260 190 7 0 0 0 - - - 0; +#X msg 260 157 -3; +#X msg 298 158 3; +#X symbolatom 260 278 10 0 0 0 - - - 0; +#X obj 99 234 makefilename [%.4d]; +#X obj 260 234 makefilename [%04d]; +#X text 51 25 For integer types ('%d'/'%i'/'%o'/'%u'/'%x'/'%X') \, the precision field does not set a maximum number of characters. Instead \, it sets a fixed number of digits and adds zeroes to the left as a fill. This is slightly different than setting a width field with a '0' flag. The difference is only observed for numbers of different signs as below (and without the "+" flag). Note how the width field will suppress a zero to include a minus (-) character., f 64; +#X connect 1 0 5 0; +#X connect 1 0 6 0; +#X connect 2 0 1 0; #X connect 3 0 1 0; -#X connect 4 0 3 0; -#X connect 5 0 2 0; -#X connect 6 0 3 0; +#X connect 5 0 0 0; +#X connect 6 0 4 0; #X restore 159 167 pd integers; -#N canvas 420 154 679 595 floats 0; -#X floatatom 284 256 10 0 0 0 - - - 0; -#X symbolatom 285 451 18 0 0 0 - - - 0; -#X symbolatom 301 353 18 0 0 0 - - - 0; -#X obj 285 403 makefilename [%e]; -#X msg 286 152 1.23456; -#X msg 258 118 2.345e-05; -#X msg 313 219 -18; -#X obj 301 305 makefilename [%.2E]; -#X msg 300 184 1.999e+07; -#X symbolatom 93 451 18 0 0 0 - - - 0; -#X floatatom 93 256 14 0 0 0 - - - 0; -#X symbolatom 113 353 18 0 0 0 - - - 0; -#X msg 93 152 1.234; -#X obj 113 305 makefilename [%.2f]; -#X obj 93 403 makefilename [%f]; -#X symbolatom 454 451 18 0 0 0 - - - 0; -#X floatatom 454 256 13 0 0 0 - - - 0; -#X symbolatom 494 353 18 0 0 0 - - - 0; -#X msg 454 152 1.234; -#X msg 468 184 -1800; -#X obj 454 403 makefilename [%g]; -#X obj 494 305 makefilename [%.3g]; -#X msg 479 219 0.000123456; -#X msg 118 219 0.000123456; -#X msg 107 184 -1800; -#X msg 62 118 2.345e-05; -#X msg 423 118 2.345e-05; -#X text 68 507 For '%g' \, the precision field sets the maximum number of significant digits \, not counting leading zeros. Note that there's a default of 6 digits. Also note that this affects the resolution and can cause the number to be rounded., f 78; -#X text 61 16 In the case of '%f' \, the precision field sets the maximum number of digits to the right of the decimal point. Note that there's a default of 6 digits. Also note that this affects the resolution and can cause the number to be rounded. In scientific notation \, the precision also defines the number of digits to the right of the decimal point., f 78; +#N canvas 485 142 869 683 floats 0; +#X floatatom 463 291 10 0 0 0 - - - 0; +#X symbolatom 464 486 18 0 0 0 - - - 0; +#X symbolatom 480 388 18 0 0 0 - - - 0; +#X obj 464 438 makefilename [%e]; +#X msg 465 187 1.23456; +#X msg 437 153 2.345e-05; +#X msg 492 254 -18; +#X obj 480 340 makefilename [%.2E]; +#X msg 479 219 1.999e+07; +#X symbolatom 272 486 18 0 0 0 - - - 0; +#X floatatom 272 291 14 0 0 0 - - - 0; +#X symbolatom 292 388 18 0 0 0 - - - 0; +#X msg 272 187 1.234; +#X obj 292 340 makefilename [%.2f]; +#X obj 272 438 makefilename [%f]; +#X symbolatom 633 486 18 0 0 0 - - - 0; +#X floatatom 633 291 13 0 0 0 - - - 0; +#X symbolatom 673 388 18 0 0 0 - - - 0; +#X msg 633 187 1.234; +#X msg 647 219 -1800; +#X obj 633 438 makefilename [%g]; +#X obj 673 340 makefilename [%.3g]; +#X msg 658 254 0.000123456; +#X msg 297 254 0.000123456; +#X msg 286 219 -1800; +#X msg 241 153 2.345e-05; +#X msg 602 153 0.0001234; +#X symbolatom 83 489 18 0 0 0 - - - 0; +#X floatatom 83 294 14 0 0 0 - - - 0; +#X symbolatom 103 391 18 0 0 0 - - - 0; +#X msg 83 190 1.234; +#X msg 108 257 0.000123456; +#X msg 97 222 -1800; +#X msg 52 156 2.345e-05; +#X obj 83 441 makefilename [%a]; +#X obj 103 343 makefilename [%.2A]; +#X text 141 44 In the case of '%f' and '%e'/'%E' \, the precision field sets the maximum number of digits to the right of the decimal point. The same is actually true for '%a'/'%A' \, but it's the number of hexadecimal digits instead. Note that there's a default of 6 digits. Also note that this affects the resolution and can cause the number to be rounded., f 82; +#X text 151 542 For '%g'/%G' \, the precision field sets the maximum number of significant digits \, not counting leading zeros. Note that there's a default of 6 digits. Also note that this affects the resolution and can cause the number to be rounded. This setting also specifies how it chooses to show the scientific notation when positive \, as the exponent value needs to be needs to equal to or higher than the precision number (for negative values \, the scientific notation is always chosen if the exponent is less the '-4')., f 87; #X connect 0 0 3 0; #X connect 0 0 7 0; #X connect 3 0 1 0; @@ -551,42 +513,215 @@ #X connect 24 0 10 0; #X connect 25 0 10 0; #X connect 26 0 16 0; +#X connect 28 0 34 0; +#X connect 28 0 35 0; +#X connect 30 0 28 0; +#X connect 31 0 28 0; +#X connect 32 0 28 0; +#X connect 33 0 28 0; +#X connect 34 0 27 0; +#X connect 35 0 29 0; #X restore 159 201 pd floats; #X text 41 23 The precision field behaves differently according to the type (strings \, integers of floats). The syntax of this field is specified by a "." and is followed by the precision number. See subpatches below for the examples., f 51; -#X restore 216 475 pd precision; -#X text 127 236 - string; -#X text 33 366 The types can be preceded by optional fields \, which can be combined and included in the order below:; +#X restore 207 549 pd precision; +#X text 127 265 - string; +#X text 128 209 - floats with or without scientific notation; +#N canvas 265 81 794 593 + 0; +#X floatatom 110 188 11 0 0 0 - - - 0; +#X symbolatom 110 263 12 0 0 0 - - - 0; +#X msg 69 105 127; +#X msg 110 105 -255; +#X msg 128 137 1e+06; +#X msg 180 137 -1e+07; +#X obj 110 225 makefilename [%+d]; +#X floatatom 141 433 10 0 0 0 - - - 0; +#X symbolatom 141 516 18 0 0 0 - - - 0; +#X msg 143 328 1.23456; +#X msg 68 328 2.345e-05; +#X msg 170 393 -18; +#X msg 157 360 1.999e+07; +#X obj 141 468 makefilename [%+e]; +#X symbolatom 526 191 18 0 0 0 - - - 0; +#X floatatom 526 103 8 0 0 0 - - - 0; +#X msg 540 61 -18; +#X msg 460 30 2.3e-05; +#X msg 526 29 257; +#X floatatom 560 424 10 0 0 0 - - - 0; +#X symbolatom 560 511 18 0 0 0 - - - 0; +#X msg 588 306 1.23456; +#X msg 605 377 0.99999; +#X msg 560 278 2.345e-05; +#X msg 602 338 1.1e+08; +#X msg 534 247 -1800; +#X msg 496 247 179; +#X floatatom 307 207 11 0 0 0 - - - 0; +#X symbolatom 307 282 12 0 0 0 - - - 0; +#X msg 266 124 127; +#X msg 307 124 -255; +#X msg 325 156 1e+06; +#X msg 377 156 -1e+07; +#X obj 307 244 makefilename [%\ d]; +#X text 58 18 The "+" flag prepends a plus sign for positive signed numeric types (%d/%i/%e/%E/%f/%g/%G). The space (which can be used if escaped by a backslash) uses a space for positive values., f 47; +#X floatatom 328 438 10 0 0 0 - - - 0; +#X symbolatom 328 521 18 0 0 0 - - - 0; +#X msg 330 333 1.23456; +#X msg 255 333 2.345e-05; +#X msg 357 398 -18; +#X msg 344 365 1.999e+07; +#X obj 328 473 makefilename [%\ e]; +#X obj 526 143 makefilename [%+f]; +#X obj 560 463 makefilename [%\ G]; +#X connect 0 0 6 0; +#X connect 2 0 0 0; +#X connect 3 0 0 0; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 6 0 1 0; +#X connect 7 0 13 0; +#X connect 9 0 7 0; +#X connect 10 0 7 0; +#X connect 11 0 7 0; +#X connect 12 0 7 0; +#X connect 13 0 8 0; +#X connect 15 0 42 0; +#X connect 16 0 15 0; +#X connect 17 0 15 0; +#X connect 18 0 15 0; +#X connect 19 0 43 0; +#X connect 21 0 19 0; +#X connect 22 0 19 0; +#X connect 23 0 19 0; +#X connect 24 0 19 0; +#X connect 25 0 19 0; +#X connect 26 0 19 0; +#X connect 27 0 33 0; +#X connect 29 0 27 0; +#X connect 30 0 27 0; +#X connect 31 0 27 0; +#X connect 32 0 27 0; +#X connect 33 0 28 0; +#X connect 35 0 41 0; +#X connect 37 0 35 0; +#X connect 38 0 35 0; +#X connect 39 0 35 0; +#X connect 40 0 35 0; +#X connect 41 0 36 0; +#X connect 42 0 14 0; +#X connect 43 0 20 0; +#X restore 207 489 pd + & space; +#X text 33 438 The types can be preceded by optional fields. The sequence syntax is . See details below:; +#X text 273 520 (and '-'/'0' flags); +#X text 146 488 flags*:; +#N canvas 778 67 614 727 modifiers 0; +#X text 27 31 The type modifiers (aka length specifiers) are placed before the format specifier and adjust how the data is to be interpreted regarding its size. This is only for integer and float types., f 75; +#X text 27 82 For integer types (%d \, %i \, %x \, %o \, '%u'/'%x'/'%X') \, the default is 32-bit precision. You can only represent integers correctly with this precision if you're using Pd compiled for 64 bits (aka Pd64). This is because Pd uses 32 bit floats otherwise \, which can only represent integers up to 2^24., f 75; +#X text 27 161 For float types (%a/%A \, %f \, %e/%E and %g/%G) the default is 64-bit precision \, but it gets truncated to 32-bit if you're using the single precision version of Pd. Again \, you can only truly represent these values in double precision if you're using Pd64., f 75; +#X floatatom 147 441 7 0 0 0 - - - 0; +#X symbolatom 147 511 7 0 0 0 - - - 0; +#X floatatom 327 441 7 0 0 0 - - - 0; +#X symbolatom 327 511 8 0 0 0 - - - 0; +#X text 210 503 8-bit unsigned, f 9; +#X text 396 513 16-bit signed; +#X text 96 563 By the way \, the range precision for signed integers according to its bits size is -2ˆ(bits-1) to 2ˆ(bits-1) -1 \, whereas for unsigned is 0 to 2ˆ(bits) -1 - for example \, for 32 bits we have:, f 61; +#X text 128 643 Signed: -2³¹ (-2.147.483.648) to 2³¹ - 1 (2.147.483.647), f 57; +#X text 27 229 The 'h' length modifier is used for integers to specify shorter precisions. You should probably not need this anyway since this is better suited for representing and matching this specifier to a data type and in Pd these can't be shorter than 32-bit. A single 'h' specifies 16-bit precision and 'hh' is 8-bit precision., f 75; +#X text 27 313 On the other hand \, the 'l' modifier specifies a higher precision of 64-bit for integers \, which Pd can't represent even in Pd64 as the maximum integer is 2^53 in this case., f 75; +#X text 128 663 Unsigned: 0 to -2³² - 1 (4.294.967.295), f 57; +#X text 27 368 The 'L' modifier is for float types and specifies a higher precision than 64-bits \, but Pd has a limit of 64-bits in Pd64 and 32 bits in single precision - hence \, it's pointless to use it., f 75; +#X obj 147 471 makefilename %hhu!; +#X obj 327 471 makefilename %hi!; +#X connect 3 0 15 0; +#X connect 5 0 16 0; +#X connect 15 0 4 0; +#X connect 16 0 6 0; +#X restore 226 398 pd modifiers; +#X text 111 399 type modifiers:; +#X text 50 20 This is a listing of possible printf format types. Open subpatches for more details and examples., f 50; +#X text 100 585 * the apostrophe (') flag is not supported; +#X text 128 70 - floats in hexadecimal; +#N canvas 784 131 547 495 %a/%A 0; +#X floatatom 258 360 12 0 0 0 - - - 0; +#X symbolatom 258 456 18 0 0 0 - - - 0; +#X msg 257 213 1.23456; +#X msg 278 245 2.345e-05; +#X msg 300 274 1.1e+08; +#X msg 170 185 -1800; +#X msg 132 185 179; +#X msg 303 313 0.999999; +#X symbolatom 108 456 18 0 0 0 - - - 0; +#X msg 221 185 0.000123456; +#X obj 258 408 makefilename [%A]; +#X obj 108 408 makefilename [%a]; +#X text 38 24 %a/%A - hexadecimal floating-point, f 68; +#X text 34 55 This format specifier allows you to represent a floating point number in hexadecimal form. The '%a' or '%A' specify respectively whether the the characters are lower or upper case. Also \, it prints 'NAN' and 'INF' in all CAPS for %A \, while '%a' uses lowercase. The number is preceded with "0x" (if %a) or "0X" (if %A). The 'p' character represents the power of 2 exponent (so it separates the fractional hexadecimal part from the exponent in base 2)., f 67; +#X connect 0 0 10 0; +#X connect 0 0 11 0; +#X connect 2 0 0 0; +#X connect 3 0 0 0; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 6 0 0 0; +#X connect 7 0 0 0; +#X connect 9 0 0 0; +#X connect 10 0 1 0; +#X connect 11 0 8 0; +#X restore 59 71 pd %a/%A; +#X text 127 321 - unsigned integer in hexadecimal; +#N canvas 705 257 464 487 %f/%F 0; +#X symbolatom 248 392 18 0 0 0 - - - 0; +#X floatatom 248 305 8 0 0 0 - - - 0; +#X msg 248 201 1.234; +#X msg 262 233 -18; +#X msg 217 170 2.3e-05; +#X msg 273 268 0.997; +#X obj 248 347 makefilename [%f]; +#X msg 173 170 1; +#X symbolatom 85 392 18 0 0 0 - - - 0; +#X obj 85 305 expr pow(-1 \, 2.3); +#X obj 85 272 bng 21 250 50 0 empty empty empty 0 -8 0 10 #dfdfdf #000000 #000000; +#X text 30 61 This format specifier allows you to format a float into a symbol without scientific notation. Note that there's a default precision of 6 digits after the decimal point. You can change this precision as shown later. As in 'e'/'E' \, trailing zeros are always shown. The '%F' variant just prints 'NAN' and 'INF' in all CAPS \, while '%f' uses lowercase.; +#X text 29 30 %f/%F - decimal floating point:; +#X obj 85 347 makefilename [%F]; +#X connect 1 0 6 0; +#X connect 2 0 1 0; +#X connect 3 0 1 0; +#X connect 4 0 1 0; +#X connect 5 0 1 0; +#X connect 6 0 0 0; +#X connect 7 0 1 0; +#X connect 9 0 6 0; +#X connect 9 0 13 0; +#X connect 10 0 9 0; +#X connect 13 0 8 0; +#X restore 59 182 pd %f/%F; #X restore 392 379 pd possible_types_&_syntax; -#X text 412 442 updated for Pd version 0.51; #X msg 48 209 set cat\ %d.wav; #X obj 43 263 makefilename dog\ %d.aif; #X obj 392 249 makefilename dog\ %s.aif; #X text 388 154 SUBSTITUTING A SYMBOL:; #X text 39 154 SUBSTITUTING AN INTEGER NUMBER:; -#X text 163 299 (Note you can use backlashes to escape and insert a space character in the symbol), f 28; -#N canvas 676 114 567 259 reference 0; +#N canvas 676 114 558 284 reference 0; #X obj 8 52 cnv 5 540 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; -#X obj 7 233 cnv 5 540 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X obj 7 263 cnv 5 540 5 empty empty empty 8 18 0 13 #202020 #000000 0; #X obj 7 134 cnv 5 540 5 empty empty OUTLET: 8 18 0 13 #202020 #000000 0; #X obj 46 19 makefilename; #X text 144 19 - format a "name" with a variable field; #X text 121 148 symbol - formatted symbol., f 47; #X obj 7 179 cnv 5 540 5 empty empty ARGUMENT: 8 18 0 13 #202020 #000000 0; -#X text 104 192 1) symbol -; +#X text 52 213 1) symbol -; #X text 156 64 float - input to variable field., f 38; -#X text 188 192 format string with specifiers ('%c' \, '%d' \, '%i \, %e \, %E \, %f \, %g \, %G \, %o \, %s \, %u \, %x \, %X and %p)., f 48; #X text 149 83 symbol - input to variable field., f 39; #X text 107 103 set - format string with specifiers.; +#X text 136 213 format string with specifiers ('%a' \, '%A' \, '%c' \, '%d' \, '%i \, %e \, %E \, %f \, %g \, %G \, %o \, %s \, %u \, %x \, %X and %p)., f 54; #X restore 456 17 pd reference; #X text 548 17 <= click; #X obj 7 53 cnv 1 610 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 6 428 cnv 1 610 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X text 21 65 The [makefilename] object generates name symbols according to a format string \, for use as a series of filenames \, table names \, or whatnot. You can plug in a variable number or symbol by using different types in the string ("such as %s" \, "%c" \, "%d" \, "%X and others - see subpatch below with possible types). Each object can have only one variable pattern \, but you can cascade objects for multiple substitutions., f 82; #X text 67 182 <-- numbers replace "%d" in string; #X text 164 208 <-- "set" message replaces format, f 18; #X text 221 262 <-- argument is format string, f 15; #X text 272 366 More details -->; -#X text 121 17 - format a symbol "name" with a variable field; +#X text 116 17 - format a symbol "name" with a variable field; #X text 18 442 see also:; #X obj 94 443 symbol; #X text 495 210 <-- symbols replace "%s", f 12; @@ -595,14 +730,17 @@ #X text 67 395 <-- number converted to symbol; #X text 151 442 and string functions in; #X obj 324 442 expr; -#X connect 0 0 13 0; -#X connect 0 0 31 0; -#X connect 1 0 14 0; -#X connect 2 0 14 0; -#X connect 4 0 13 0; +#X text 163 299 (Note you can use backslashes to escape and insert a space character in the symbol), f 29; +#X text 21 65 The [makefilename] object generates symbols according to a format string \, for use as a series of filenames \, table names \, or whatnot. You can plug in a variable number or symbol by using different types in the string ("such as %s" \, "%c" \, "%d" \, "%X and others - see subpatch below with all possible types). Each object can have only one variable pattern \, but you can cascade objects for multiple substitutions., f 82; +#X text 398 442 updated for Pd version 0.56-0; +#X connect 0 0 12 0; +#X connect 0 0 28 0; +#X connect 1 0 13 0; +#X connect 2 0 13 0; +#X connect 4 0 12 0; #X connect 5 0 6 0; #X connect 7 0 8 0; -#X connect 12 0 13 0; -#X connect 13 0 5 0; -#X connect 14 0 7 0; -#X connect 31 0 32 0; +#X connect 11 0 12 0; +#X connect 12 0 5 0; +#X connect 13 0 7 0; +#X connect 28 0 29 0; diff --git a/doc/5.reference/message-help.pd b/doc/5.reference/message-help.pd index be53f6fbe0..828156a234 100644 --- a/doc/5.reference/message-help.pd +++ b/doc/5.reference/message-help.pd @@ -1,4 +1,4 @@ -#N canvas 248 23 1043 711 12; +#N canvas 248 38 1043 711 12; #X msg 123 267 walk the dog; #X obj 100 312 print; #X obj 600 338 receive my-receiver-name; @@ -36,31 +36,6 @@ #X connect 13 0 0 0; #X connect 14 0 0 0; #X restore 784 481 pd changing-messages; -#N canvas 866 231 495 492 more-on-selectors 0; -#X msg 118 262 4; -#X msg 118 196 bang; -#X text 74 197 bang; -#X text 68 232 Symbol; -#X text 183 302 (implicit); -#X text 76 315 List; -#X text 148 261 (implicit); -#X text 71 263 float; -#X msg 181 380 turn on; -#X msg 181 412 open file4.aif; -#X text 60 158 Special selectors:; -#X msg 181 442 stop; -#X msg 247 380 turn off; -#X text 45 383 Messages with other selectors:, f 16; -#X msg 118 232 symbol hi; -#X msg 118 302 1 hi 3 5; -#X msg 118 328 list one 2; -#X text 220 442 (just a selector); -#X text 319 380 selector "turn"; -#X text 294 411 selector "open"; -#X text 40 19 A message selector is the first symbol in a message and defines its data type. The special types are: float \, symbol \, list \, bang and pointer (this one used for data structures only). The "float" selector doesn't need to be specified for number and neither does "list" if its first element is a number. Other message selectors can be anything else. If a message contains only one symbol \, like "stop" \, it is considered a selector with no actual message attached.; -#X text 163 196 <-- can't have arguments; -#X text 194 230 <-- can have only one argument; -#X restore 236 456 pd more-on-selectors; #X text 630 64 You can separate multiple messages by commas., f 26; #X obj 826 95 print; #X msg 826 65 1 \, 2 \, 3 \, 4; @@ -220,7 +195,6 @@ #X connect 32 0 30 0; #X connect 33 0 32 0; #X restore 372 625 pd dollar-variables; -#X text 94 449 Open subpatch for more on selectors:, f 18; #X text 352 602 more on dollar variables:; #X text 226 261 a message with 'walk' selector, f 15; #X text 420 287 (number box); @@ -255,26 +229,55 @@ #X text 22 353 When an object receives a message \, it checks for the selector. The [float] object receives a float message to store and output it \, but it doesn't work with the selector "doesn't"! A number box also understands a float message and passes it through. What comes out of control objects and number/symbol/list boxes are all just messages as well!, f 74; #X text 641 519 open subpatch to see how to deal with '\$0' -->, f 24; #X text 144 313 <-- object (different border); -#X text 389 457 <-- click; +#X text 407 455 <-- click; #X text 293 567 <-- click and drag; #X obj 272 680 all_guis; #X text 86 11 - a clickable message box; #X msg 51 12; +#X obj 344 680 makefilename; +#N canvas 344 215 533 612 more-on-selectors 0; +#X msg 118 262 4; +#X msg 118 196 bang; +#X text 74 197 bang; +#X text 68 232 Symbol; +#X text 183 302 (implicit); +#X text 76 315 List; +#X text 148 261 (implicit); +#X text 71 263 float; +#X msg 181 380 turn on; +#X msg 181 412 open file4.aif; +#X text 60 158 Special selectors:; +#X msg 181 442 stop; +#X msg 247 380 turn off; +#X text 45 383 Messages with other selectors:, f 16; +#X msg 118 232 symbol hi; +#X msg 118 302 1 hi 3 5; +#X msg 118 328 list one 2; +#X text 220 442 (just a selector); +#X text 319 380 selector "turn"; +#X text 294 411 selector "open"; +#X text 40 19 A message selector is the first symbol in a message and defines its data type. The special types are: float \, symbol \, list \, bang and pointer (this one used for data structures only). The "float" selector doesn't need to be specified for number and neither does "list" if its first element is a number. Other message selectors can be anything else. If a message contains only one symbol \, like "stop" \, it is considered a selector with no actual message attached.; +#X text 163 196 <-- can't have arguments; +#X text 194 230 <-- can have only one argument; +#X text 46 513 Note on numeric precision. floats are represented in messages with the '%g' format and its default precision \, check the help file of [makefilename] for details., f 61; +#X restore 244 449 pd more-on-selectors and numeric precision; +#X f 22; +#X text 75 447 Details on selectors and numeric precision:, f 23; #X connect 0 0 1 0; #X connect 2 0 3 0; -#X connect 3 0 13 0; -#X connect 4 0 14 0; +#X connect 3 0 12 0; +#X connect 4 0 13 0; #X connect 5 0 4 0; -#X connect 11 0 10 0; -#X connect 16 0 15 0; +#X connect 10 0 9 0; +#X connect 15 0 14 0; +#X connect 19 0 1 0; #X connect 20 0 1 0; -#X connect 21 0 1 0; -#X connect 24 0 26 0; -#X connect 25 0 24 0; -#X connect 26 0 27 0; -#X connect 29 0 30 0; -#X connect 31 0 24 0; +#X connect 23 0 25 0; +#X connect 24 0 23 0; +#X connect 25 0 26 0; +#X connect 28 0 29 0; +#X connect 30 0 23 0; +#X connect 32 0 33 0; #X connect 33 0 34 0; -#X connect 34 0 35 0; +#X connect 35 0 36 0; #X connect 36 0 37 0; -#X connect 37 0 38 0; diff --git a/doc/5.reference/midi-help.pd b/doc/5.reference/midi-help.pd index 18dee2019a..fb6d60532e 100644 --- a/doc/5.reference/midi-help.pd +++ b/doc/5.reference/midi-help.pd @@ -345,7 +345,7 @@ #X text 734 316 ***; #X text 546 418 ** Known bug: [bendin] and [bendout] are inconsistent ([bendin] outputs values from 0 to 16383 and [bendout] takes values from -8192 to 8191) - this won't change., f 70; #X text 546 465 *** Program change values in [pgmin] and [pgmout] are indexed from 1 \, which means that the possible values are from 1 to 128 (not 0 to 127)!, f 70; -#X text 546 357 * Release velocity is not supported \, [noteout] only sends Note On velocities and for [notein] a release velocity becomes 0 (commonly interpreted as a "note off"). Tru "note off" messages are still supported via [midiin] and [midiout]., f 70; +#X text 546 357 * Release velocity is not supported \, [noteout] only sends Note On velocities and for [notein] a release velocity becomes 0 (commonly interpreted as a "note off"). True "note off" messages are still supported via [midiin] and [midiout]., f 70; #X msg 836 602 128 68 100; #X text 16 578 raw MIDI byte by byte except real-time messages (sysex supported), f 28; #X text 357 637 <-- Open for MPE support; diff --git a/doc/5.reference/pd-messages.pd b/doc/5.reference/pd-messages.pd index 30cf677468..4b83da4bd7 100644 --- a/doc/5.reference/pd-messages.pd +++ b/doc/5.reference/pd-messages.pd @@ -40,8 +40,10 @@ #X msg 176 268 5000; #X text 216 266 <-- time amount to render (5 seconds), f 19; #N canvas 0 22 450 278 (subpatch) 0; -#X array fast-forward 441000 float 2; -#X coords 0 1 441000 -1 250 120 1 0 0; +#X array fast-forward 480000 float 2; +#A color 0; +#A width 2; +#X coords 0 1 480000 -1 250 120 1 0 0; #X restore 411 209 graph; #X text 399 415 tells pd to 'fast-forward' and render the given amount of time in ms, f 37; #X obj 389 493 osc~ 0.25; @@ -60,13 +62,13 @@ #X connect 24 0 6 0; #X connect 28 0 10 1; #X restore 777 294 pd fast-forward; -#N canvas 469 143 828 532 other-messages 0; +#N canvas 117 192 909 550 other-messages 0; #X msg 472 154 \; pd quit; #X obj 112 192 pdcontrol; #X msg 112 164 dir; #X obj 471 119 s pd; #X msg 471 92 quit; -#X msg 634 236 \; pd verifyquit; +#X msg 677 283 \; pd verifyquit; #X obj 86 426 pdcontrol; #X msg 86 398 dir; #X obj 567 18 cnv 15 170 100 empty empty empty 20 12 0 14 #f88c7c #404040 0; @@ -83,22 +85,25 @@ #X coords 0 1 100 -1 180 45 1; #X restore 543 148 graph; #X text 577 31 WARNING: the "quit" message quits and closes Pd!!!, f 20; -#X text 459 219 This message quits Pd but verifies if there are unsaved changes \, so it's safer!, f 22; -#X msg 445 450 \; pd perf \$1; -#X obj 445 411 tgl 22 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; -#X text 437 304 The 'perf 1' message turns "performance" mode on \, and 'perf 0' turns it off. In performance mode \, a "close this window?" message appears when you try to close an unmodified patch. Also \, a "really quit?" message appears when you try to quit Pd and no changes have been made to the patch., f 49; +#X msg 485 474 \; pd perf \$1; +#X obj 485 435 tgl 22 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X text 442 331 The 'perf 1' message turns "performance" mode on \, and 'perf 0' turns it off. In performance mode \, a "close this window?" message appears when you try to close an unmodified patch. Also \, a "really quit?" message appears when you try to quit Pd and no changes have been made to the patch., f 58; #X msg 112 222 \; pd open clone-abs-a.pd \$1; #X text 37 74 The "open" message opens a Pd file and takes two symbols \, the first is the Pd filename and the second is the directory where it lives. You can use this to open desired patches from within a patch - a.k.a" dynamic patching" (see next section on parent patch)., f 53; #X text 39 282 The "menunew" message generates a new empty Pd file (but doesn't save it to disk unless you save the file.) It takes two symbols \, the first is the Pd filename and the second is the directory where it will be saved. This is also another form of dynamic patching (see next section on parent patch)., f 51; #X text 460 24 And here are some more messages:, f 12; -#X text 562 419 Note that even in this mode the "quit" message to Pd will still mercilessly quit the Pd application., f 29; +#X text 586 446 Note that even in this mode the "quit" message to Pd will still mercilessly quit the Pd application., f 29; #X msg 86 456 \; pd menunew new-patch.pd \$1; -#X connect 1 0 22 0; +#X msg 593 283 \; pd exit; +#X text 436 208 The 'exit' message is equally dangerous \, but it 'politely' asks the scheduler to quit \, closing properly all canvases. The 'verifyquit' message quits Pd but verifies if there are unsaved changes \, so it's safer!; +#X text 453 291 ALSO DANGEROUS -->; +#X text 784 289 (SAFER); +#X connect 1 0 21 0; #X connect 2 0 1 0; #X connect 4 0 3 0; -#X connect 6 0 27 0; +#X connect 6 0 26 0; #X connect 7 0 6 0; -#X connect 20 0 19 0; +#X connect 19 0 18 0; #X restore 779 345 pd other-messages; #X text 22 627 see also:; #X obj 139 628 samplerate~; @@ -337,7 +342,6 @@ #N canvas 0 22 450 278 (subpatch) 0; #X coords 0 1 100 -1 421 54 1; #X restore 523 427 graph; -#X text 780 627 updated for Pd version 0.54; #X obj 310 628 pdcontrol; #N canvas 543 122 589 553 dsp-start/stop 0; #X obj 93 119 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; @@ -364,6 +368,7 @@ #X obj 456 628 pd~; #X text 35 376 Objects that change their behavior according to the set compatibility have that information in their help files.; #X text 572 222 Pd sends you bangs when DSP is turned on or off \, see -->, f 28; +#X text 760 627 updated for Pd version 0.56-0; #X connect 0 0 27 0; #X connect 12 0 11 0; #X connect 28 0 25 0; diff --git a/doc/5.reference/pointer-help.pd b/doc/5.reference/pointer-help.pd index 7061c339b0..635ebd4d78 100644 --- a/doc/5.reference/pointer-help.pd +++ b/doc/5.reference/pointer-help.pd @@ -1,54 +1,49 @@ #N struct template2 float x float y; #N struct template1 float x float y float z; -#N canvas 542 23 703 715 12; -#X text 20 675 see also:; -#X obj 53 10 pointer; -#N canvas 379 131 422 137 pointer-template1 0; +#N struct pointer-template3 float x float y float z array array1 pointer-template3-element 1 text list1; +#N struct pointer-template3-element float x float y text list2; +#N canvas 402 52 849 726 12; +#X text 11 694 see also:; +#X obj 31 11 pointer; +#N canvas 489 160 422 137 pointer-template1 0; #X obj 74 76 filledpolygon z 0 1 0 0 20 0 20 30 0 30; #X obj 60 23 struct template1 float x float y float z; -#X restore 449 526 pd pointer-template1; +#X restore 675 138 pd pointer-template1; #N canvas 566 400 413 122 pointer-template2 0; #X obj 40 67 filledcurve 909 0 0 0 0 30 30 60 0 30 -30 0 0; #X obj 60 21 struct template2 float x float y; -#X restore 449 549 pd pointer-template2; -#X obj 95 661 get; -#X obj 128 661 set; -#X obj 161 661 append; -#X obj 215 661 getsize; -#X obj 96 685 setsize; -#X obj 156 685 element; -#N canvas 186 180 312 185 pointer-data 1; -#X scalar template2 20 97 \;; +#X restore 675 161 pd pointer-template2; +#X obj 185 695 get; +#X obj 214 695 set; +#X obj 134 695 append; +#X obj 243 695 getsize; +#X obj 300 695 setsize; +#X obj 356 695 element; +#N canvas 72 176 312 185 pointer-data 1; +#X scalar template2 21 97 \;; #X scalar template1 80 17 90 \;; #X scalar template1 120 117 9 \;; -#X restore 449 504 pd pointer-data; -#X obj 69 459 pointer; -#X msg 23 184 traverse pd-pointer-data; -#X msg 69 236 next; -#X obj 69 484 print out1; -#X obj 160 484 print out2; -#X msg 47 556 next; -#X msg 94 556 traverse pd-pointer-data; -#X obj 94 613 print template1; -#X obj 219 613 print template2; -#X obj 344 613 print other; -#X obj 469 613 print bangout; -#X text 213 183 sets to the "head" of the list; -#X msg 97 305 vnext 1; -#X msg 116 376 send pointer-help; -#X text 76 210 output current value; -#X obj 493 367 r pointer-help; -#X obj 493 392 print pointer-help; -#X text 157 298 output the next object (if arg is 0) or the next selected -object (if arg is 1 -- but the window must be visible for the "selection" -to make sense)., f 74; -#X msg 123 425 send-window vis \$1; -#X obj 123 401 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 -#000000 0 1; -#X text 256 425 send a message to the canvas containing the scalar -; -#X msg 105 337 delete; -#N canvas 764 193 602 411 equal_message 0; +#X restore 675 116 pd pointer-data; +#X obj 91 624 pointer, f 12; +#X msg 26 215 traverse pd-pointer-data; +#X msg 59 273 next; +#X obj 91 649 print out1; +#X obj 171 648 print out2; +#X msg 500 266 next; +#X msg 544 272 traverse pd-pointer-data; +#X obj 500 381 print template1; +#X obj 562 355 print template2; +#X obj 624 330 print other; +#X obj 705 304 print bangout; +#X text 209 214 sets to the "head" of the list; +#X msg 141 533 send pointer-help; +#X text 67 241 output current value; +#X obj 402 532 r pointer-help; +#X obj 402 557 print pointer-help; +#X msg 143 586 send-window vis \$1; +#X obj 143 562 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 1; +#X msg 91 354 delete; +#N canvas 488 103 559 398 equal_message 0; #X obj 304 212 pointer; #X msg 304 146 traverse pd-pointer-data \, bang; #X msg 314 183 next; @@ -63,10 +58,7 @@ to make sense)., f 74; #X obj 304 327 print not-equal; #X text 321 277 you can also use template symbols, f 17; #X obj 304 115 loadbang; -#X text 34 21 The "equal" message allows one to compare an incoming -pointer with the stored pointer. On success \, the pointer is sent -to its corresponding outlet. On fail \, a bang is sent through the -rightmost outlet., f 71; +#X text 34 21 The "equal" message allows one to compare an incoming pointer with the stored pointer. On success \, the pointer is sent to its corresponding outlet. On fail \, a bang is sent through the rightmost outlet., f 71; #X connect 0 0 7 1; #X connect 1 0 0 0; #X connect 2 0 0 0; @@ -79,123 +71,207 @@ rightmost outlet., f 71; #X connect 7 2 10 0; #X connect 7 3 11 0; #X connect 13 0 1 0; -#X restore 499 458 pd equal_message; -#X text 487 678 updated for Pd version 0.51; -#X obj 160 460 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf -#000000 #000000; -#X text 184 459 bang at end of list; -#X obj 275 661 trigger; -#X obj 215 685 unpack; -#X obj 275 685 pack; -#X obj 337 661 pipe; -#X text 115 10 - store the location of a scalar in a list; -#X obj 11 43 cnv 1 685 1 empty empty empty 8 12 0 13 #000000 #000000 -0; -#X text 610 8 <= click; -#N canvas 708 63 575 630 reference 0; -#X obj 29 18 pointer; -#X text 91 18 - store the location of a scalar in a list.; -#X text 44 290 send -; -#X obj 8 52 cnv 5 550 5 empty empty INLETS: 8 18 0 13 #202020 #000000 -0; -#X obj 8 400 cnv 2 550 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 -0; -#X obj 8 519 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 -0; -#X obj 7 596 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 -0; -#X obj 7 360 cnv 1 550 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 -0; -#X obj 7 85 cnv 1 550 1 empty empty 1st: 8 12 0 13 #7c7c7c #000000 -0; -#X text 107 90 bang - output the current value., f 62; -#X text 107 140 next -; -#X text 156 140 move and output next pointer or "bang" to right outlet -if we reach the end of the list., f 55; -#X text 44 213 vnext -; -#X text 93 259 delete -; -#X text 156 258 delete the current object and output the next (or send -a "bang" to the right outlet if it was the last one)., f 55; -#X text 16 309 send-window -; -#X text 156 308 send any message to the canvas containing the scalar. -, f 55; -#X text 30 328 equal -; -#X text 156 327 compare an incoming pointer with the stored pointer. -, f 55; -#X text 83 370 pointer - store the pointer value (no output)., f 49 -; -#X text 85 404 'n' number of outlets depend on creation arguments; -#X obj 7 427 cnv 1 550 1 empty empty 'n': 8 12 0 13 #7c7c7c #000000 -0; -#X text 17 544 1) list -; -#X obj 7 457 cnv 1 550 1 empty empty 'n'+1: 8 12 0 13 #7c7c7c #000000 -0; -#X text 111 433 pointer - pointers of matching templates.; -#X text 111 463 pointer - pointers for non matching templates.; -#X obj 7 488 cnv 1 550 1 empty empty rightmost: 8 12 0 13 #7c7c7c #000000 -0; -#X text 156 212 outputs the next object (if 0) or the next selected -object (if 1) or "bang" to right outlet if we reach the end of the -list.., f 55; -#X text 156 290 send pointer to a receive name given by the symbol. -, f 55; -#X text 16 108 traverse -; -#X text 85 544 template names. The number of templates creates 'n' -corresponding outlets plus an extra outlet for non matching templates. -If no argument is given \, only one outlet is created besides rightmost. -, f 65; -#X text 131 494 bang - when reaching the end of a list.; -#X text 156 108 sets to the a canvas' "head" of the list \, the symbol -needs to be in the format 'pd-canvasname'., f 55; -#X text 93 175 rewind -; -#X text 156 174 goes back to the head of the list and output its pointer -(unless the end of list was reached); -#X restore 516 9 pd reference; -#X obj 11 649 cnv 1 685 1 empty empty empty 8 12 0 13 #000000 #000000 -0; -#X obj 94 587 pointer template1 template2, f 54; -#X text 20 52 [pointer] is a storage object like [float] \, except -that the thing stored is the location of a scalar somewhere. You can -send a value to [pointer] (perhaps from another [pointer] object). -The right inlet takes pointers and simply stores them. A bang in the -left inlet outputs the pointer \, and a pointer in the left both sets -and outputs the value., f 94; -#X text 115 229 move forward one item and output its pointer \, or -send a "bang" to the right outlet if we reach the end of the list. -, f 63; -#X text 158 331 delete the current object and output the next one (or -send a "bang" to right outlet if it was the last one in the list), -f 67; -#X text 23 514 Optional arguments to [pointer] allow you to select -according to the template of the scalar being output:; -#X obj 53 210 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 -#000000; -#X text 245 376 send pointer to a receive name -->; -#X text 350 459 Pointer equality -->; -#X text 20 114 The value of a [pointer] can either indicate a real -scalar \, or else the "head" (before the first element) of the list -\, which allows you to point to an empty list (and append a scalar -to the beginning of the list). Pointers are "safe": if you delete a -scalar \, pointers to it are marked as invalid., f 94; -#X msg 81 270 rewind; -#X text 136 262 goes back to the head of the list and output its pointer -(unless the end of list was reached); +#X restore 653 420 pd equal_message; +#X obj 198 618 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X text 760 8 <= click; +#N canvas 646 39 613 725 reference 0; +#X obj 29 15 pointer; +#X text 93 311 send -; +#X obj 8 47 cnv 5 595 5 empty empty INLETS: 8 18 0 13 #202020 #000000 0; +#X obj 8 446 cnv 2 595 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; +#X obj 7 565 cnv 2 595 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; +#X obj 7 709 cnv 5 595 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X obj 7 406 cnv 1 595 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; +#X obj 7 79 cnv 1 595 1 empty empty 1st: 8 12 0 13 #7c7c7c #000000 0; +#X text 156 83 bang - output the current value., f 61; +#X text 93 208 vnext -; +#X text 142 280 delete -; +#X text 205 278 delete the current object and output the next (or send a "bang" to the right outlet if it was the last one)., f 54; +#X text 65 330 send-window -; +#X text 205 328 send any message to the canvas containing the scalar., f 54; +#X text 79 349 equal -; +#X text 205 347 compare an incoming pointer with the stored pointer., f 54; +#X text 135 412 pointer - store the pointer value (no output).; +#X text 85 450 'n' number of outlets depend on creation arguments; +#X obj 7 473 cnv 1 595 1 empty empty 'n': 8 12 0 13 #7c7c7c #000000 0; +#X text 61 616 1) list -; +#X obj 7 503 cnv 1 595 1 empty empty 'n'+1: 8 12 0 13 #7c7c7c #000000 0; +#X text 135 479 pointer - pointers of matching templates.; +#X text 135 509 pointer - pointers for non matching templates.; +#X obj 7 534 cnv 1 595 1 empty empty rightmost: 8 12 0 13 #7c7c7c #000000 0; +#X text 205 310 send pointer to a receive name given by the symbol., f 54; +#X text 65 102 traverse -; +#X text 132 603 template names. The number of templates creates 'n' corresponding outlets plus an extra outlet for non matching templates. If no argument is given \, only one outlet is created besides rightmost., f 65; +#X text 155 540 bang - when reaching the end of a list.; +#X text 205 101 sets to the a canvas' "head" of the list \, the symbol needs to be in the format 'pd-canvasname'., f 54; +#X text 142 368 rewind -; +#X obj 91 16 vpointer; +#X text 205 134 move and output next pointer or "bang" to right outlet if we reach the end of the list. Optional "count" to specify number of items forward \, "template" to filter for a specific template \, and "selected" \, nonzero to specify filtering for a selected item., f 54; +#X text 205 209 short for "next 1 - ., f 54; +#X text 51 261 [ ...; +#X text 10 253 set ; +#X text 23 228 get [field2...] -; +#X text 205 228 get one or more field values. The result appears as a list out the rightmost outlet., f 54; +#X text 205 366 goes back to the head of the list and output its pointer (only if pointer is currently set), f 54; +#X text 37 151 [template] [selected] -; +#X text 11 134 next [count]; +#X text 151 14 - store the location of a scalar.; +#X text 205 260 set value of one or more field., f 54; +#X obj 7 591 cnv 1 595 1 empty empty for\ [pointer] 8 12 0 13 #7c7c7c #000000 0; +#X obj 7 655 cnv 1 595 1 empty empty for\ [vpointer] 8 12 0 13 #7c7c7c #000000 0; +#X text 158 661 1) symbol - shared name between [vpointers]; +#X text 172 680 2) list - as above for [pointer], f 41; +#X restore 666 9 pd reference; +#X obj 7 682 cnv 1 835 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X obj 500 305 pointer template1 template2; +#X text 101 260 move forward one item and output its pointer \, or send a "bang" to the right outlet if we reach the end of the list., f 40; +#X text 144 341 delete the current object and output the next one (or send a "bang" to right outlet if it was the last one in the list), f 42; +#X text 500 211 Optional arguments to [pointer] allow you to select according to the template of the scalar being output:, f 37; +#X obj 44 241 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X msg 74 316 rewind; +#X obj 95 12 vpointer; +#X text 162 12 reference or access scalar objects; +#X text 16 128 The value of a [pointer] can be either a real scalar \, or else the "head" (before the first element) of the list \, which allows you to point to an empty list (for instance to append a scalar to the beginning of the list). Pointers are "safe": if you delete a scalar \, pointers to it (and to any other scalar in the same window) are marked as invalid., f 86; +#X obj 594 597 vpointer pointer-name; +#X obj 594 624 vpointer pointer-name template1; +#X msg 103 397 nearest 40 50; +#X text 468 420 testing pointer equality; +#N canvas 295 104 924 658 set_and_get 0; +#N canvas 214 369 545 328 pointer-template3 0; +#X obj 87 124 filledpolygon 900 0 1 0 0 20 0 20 30 0 30; +#X obj 86 156 drawtext list1 25 0 0 list1=; +#X msg 117 253 \; pd-set_and_get scalar pointer-template3 50 50 \\\;; +#X obj 83 203 plot array1 0 1 25 20; +#X obj 87 48 struct pointer-template3 float x float y float z array array1 pointer-template3-element list list1; +#X restore 608 579 pd pointer-template3; +#N canvas 721 494 507 191 pointer-template3-element 0; +#X obj 68 49 struct pointer-template3-element float x float y list list2; +#X obj 129 121 drawtext list2 25 0 0 list2=; +#X restore 609 609 pd pointer-template3-element; +#X msg 48 260 traverse pd-set_and_get \, next \, get list1, f 30; +#X obj 48 306 pointer; +#X listbox 94 336 17 0 0 0 - - - 0; +#X obj 142 511 pointer; +#X listbox 188 539 16 0 0 0 - - - 0; +#X obj 142 452 hradio 20 1 0 3 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0; +#X msg 142 482 traverse pd-set_and_get \, next \, get array1 \$1 list2; +#X obj 596 375 pointer; +#X msg 596 330 traverse pd-set_and_get \, next \, set list1 1 \$1 3 four five, f 30; +#X floatatom 596 291 5 0 0 0 - - - 0; +#X obj 597 503 pointer; +#X floatatom 597 419 5 20 500 0 - - - 0; +#X scalar pointer-template3 80 26 0 \; 0 0 \; 1 2 3 \; 53 67 \; not my circus \; 112 34 \; not my monkeys \; \; x is 80 \;; +#X obj 304 306 pointer; +#X listbox 350 333 20 0 0 0 - - - 0; +#X msg 304 260 traverse pd-set_and_get \, next \, get x y list1, f 30; +#X obj 594 248 pointer; +#X floatatom 594 164 5 -20 80 0 - - - 0; +#X msg 594 197 traverse pd-set_and_get \, next \, set array1 1 y \$1, f 30; +#X text 638 163 set list1; +#X text 643 285 change an array element, f 14; +#X msg 597 452 traverse pd-set_and_get \, next \, set x \$1 list1 x is \$1, f 30; +#X text 42 159 The "get" and "set" messages can get or set one or more values (numbers \, symbols \, or lists) into or out of a scalar. The arguments to "get" are the names of the fields desired \, for instance "list1" in the examples below. (Note that the "traverse" and "next" messages are to set the pointer to the single scalar that is in this window)., f 67; +#X text 49 372 You can get data out of array elements using a single "get" message by naming the field of the array ("array1" here below). The element number (\$1 \, set by the radio button) and finally the field name of the array element ("list2")., f 64; +#X text 642 418 set both 'x' and list1; +#X text 93 579 Here are the templates. The object belongs to "template3" and has x \, y \, "list1" \, and "array1" as fields. Array1 has elements whose template \, "pointer-template3-element" \, has x \, y \, and "list2" fields., f 71; +#X text 497 18 To set one or more fields \, send "set" with a field name and a value \, which may be repeated as desired. To set a field within an array \, name the array \, the element number \, and the field of the array element like the example below. (You can enter sub-arrays recursively too). If you set a text field the remaining arguments of the message become the new text (so that should be the last thing you set in this message)., f 56; +#X connect 2 0 3 0; +#X connect 3 1 4 0; +#X connect 5 1 6 0; +#X connect 7 0 8 0; +#X connect 8 0 5 0; +#X connect 10 0 9 0; +#X connect 11 0 10 0; +#X connect 13 0 23 0; +#X connect 15 1 16 0; +#X connect 17 0 15 0; +#X connect 19 0 20 0; +#X connect 20 0 18 0; +#X connect 23 0 12 0; +#X restore 653 470 pd set_and_get; +#X text 127 309 go back to the head of the list containing current pointer, f 31; +#X msg 112 428 equal; +#X text 156 427 test equality of two pointers; +#X text 538 444 more on "next"; +#N canvas 323 183 658 493 next_message 0; +#X floatatom 247 420 5 0 0 0 - - - 0; +#X floatatom 335 420 5 0 0 0 - - - 0; +#X msg 35 22 traverse pd-pointer-data \, next; +#X floatatom 115 420 5 0 0 0 - - - 0; +#X floatatom 159 420 5 0 0 0 - - - 0; +#X floatatom 203 420 5 0 0 0 - - - 0; +#X obj 115 317 pointer template1 template2, f 57; +#X obj 115 361 get template1 x y z, f 13; +#X msg 162 277 next; +#X text 261 14 start and get next scalar (outputs first in window if any), f 32; +#X msg 74 63 traverse pd-pointer-data \, next 2; +#X text 314 66 "next 2" to go forward 2 scalars; +#X text 316 100 "next 2 template1" to go forward to second scalar whose template is template1, f 43; +#X msg 115 102 traverse pd-pointer-data \, next 2 template1, f 25; +#X obj 247 367 get template2 x y, f 13; +#X obj 115 450 bng 20 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X msg 144 159 traverse pd-pointer-data \, next 1 - 1, f 25; +#X text 344 145 third argument nonzero to search for a selected element. (The window must be visible for this to work). Here \, the template "-" means "match any template"., f 40; +#X msg 159 221 traverse pd-pointer-data \, vnext 1; +#X text 203 275 "next" is equivalent to "next 1 - 0".; +#X text 407 213 "vnext" is short for "next 1 -" \, a nonzero argument means search for next selected object., f 32; +#X obj 247 450 bng 20 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X obj 511 373 bng 20 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X obj 379 373 bng 20 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X connect 0 0 21 0; +#X connect 2 0 6 0; +#X connect 3 0 15 0; +#X connect 6 0 7 0; +#X connect 6 1 14 0; +#X connect 6 2 23 0; +#X connect 6 3 22 0; +#X connect 7 0 3 0; +#X connect 7 1 4 0; +#X connect 7 2 5 0; +#X connect 8 0 6 0; +#X connect 10 0 6 0; +#X connect 13 0 6 0; +#X connect 14 0 0 0; +#X connect 14 1 1 0; +#X connect 16 0 6 0; +#X connect 18 0 6 0; +#X restore 653 445 pd next_message; +#X text 222 617 output of "get" message or bang on end-of-list; +#X obj 83 695 struct; +#X msg 124 457 get x y; +#X text 184 454 get fields of a scalar; +#X floatatom 134 483 5 20 300 0 - - - 0; +#X text 200 507 set them; +#X msg 134 507 set x \$1; +#X text 475 470 more on "set" and "get"; +#X text 669 67 templates used in this example:, f 16; +#X text 205 392 find and output the scalar nearest to (x \, y), f 26; +#X text 277 586 send a message to the containing canvas; +#X text 16 51 [pointer] manages a reference to a scalar object (as defined by a [struct] object). The right inlet takes a pointer and stores it. A bang outputs it \, and a pointer to the main inlet does both. "set" and "get" messages allow accessing or modifying the scalar. "traverse" \, "next" \, and "nearest" allow initializing the reference or moving it from scalar to scalar within a window., f 86; +#X text 637 694 updated for Pd version 0.56; +#X obj 6 46 cnv 1 835 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X text 269 528 send pointer to a receive name ---->, f 18; +#X text 573 518 A [vpointer] is like [pointer] \, with an added first argument that names them - [vpointer] objects that share a name refer to the same pointer., f 36; #X connect 11 0 14 0; -#X connect 11 1 35 0; +#X connect 11 1 31 0; +#X connect 11 1 15 0; #X connect 12 0 11 0; #X connect 13 0 11 0; -#X connect 16 0 46 0; -#X connect 17 0 46 0; +#X connect 16 0 35 0; +#X connect 17 0 35 0; #X connect 23 0 11 0; -#X connect 24 0 11 0; -#X connect 26 0 27 0; +#X connect 25 0 26 0; +#X connect 27 0 11 0; +#X connect 28 0 27 0; #X connect 29 0 11 0; -#X connect 30 0 29 0; -#X connect 32 0 11 0; -#X connect 35 0 15 0; -#X connect 46 0 18 0; -#X connect 46 1 19 0; -#X connect 46 2 20 0; -#X connect 46 3 21 0; -#X connect 51 0 11 0; -#X connect 55 0 11 0; +#X connect 35 0 18 0; +#X connect 35 1 19 0; +#X connect 35 2 20 0; +#X connect 35 3 21 0; +#X connect 39 0 11 0; +#X connect 40 0 11 0; +#X connect 46 0 11 0; +#X connect 50 0 11 0; +#X connect 56 0 11 0; +#X connect 58 0 60 0; +#X connect 60 0 11 0; diff --git a/doc/5.reference/poly-help.pd b/doc/5.reference/poly-help.pd index c2b6a21df9..95a93974c4 100644 --- a/doc/5.reference/poly-help.pd +++ b/doc/5.reference/poly-help.pd @@ -1,23 +1,23 @@ -#N canvas 459 95 567 557 12; +#N canvas 459 83 575 630 12; #X declare -stdpath ./; -#X text 16 519 see also:; +#X text 17 593 see also:; #X obj 29 16 poly; -#X obj 94 519 makenote; -#X obj 99 319 poly 4 1; -#X msg 211 285 stop; -#X msg 203 259 clear; +#X obj 95 594 makenote; +#X obj 111 402 poly 4 1; +#X msg 210 304 stop; +#X msg 204 275 clear; #X text 68 16 - MIDI-style polyphonic voice allocator; -#X listbox 92 379 13 0 0 0 - - - 0; -#X obj 92 349 pack f f f; -#X text 248 260 clear memory; -#X text 249 286 flush hanging note on messages; +#X listbox 104 460 13 0 0 0 - - - 0; +#X obj 104 430 pack f f f; +#X text 249 276 clear memory; +#X text 248 305 flush hanging note on messages; #X obj 9 50 cnv 1 550 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#N canvas 800 147 484 391 reference 0; +#N canvas 699 162 467 445 reference 0; #X obj 8 52 cnv 5 450 5 empty empty INLETS: 8 18 0 13 #202020 #000000 0; -#X obj 8 192 cnv 2 450 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; -#X obj 8 313 cnv 2 450 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; -#X obj 7 370 cnv 5 450 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X obj 7 155 cnv 1 450 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; +#X obj 8 236 cnv 2 450 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; +#X obj 8 357 cnv 2 450 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; +#X obj 7 424 cnv 5 450 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X obj 7 199 cnv 1 450 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; #X obj 7 85 cnv 1 450 1 empty empty 1st: 8 12 0 13 #7c7c7c #000000 0; #X obj 27 18 poly; #X text 66 18 - MIDI-style polyphonic voice allocator.; @@ -26,99 +26,99 @@ #X text 187 111 clear memory., f 32; #X text 138 129 stop -; #X text 187 129 flush hanging note on messages., f 32; -#X text 132 162 float - set velocity value., f 40; -#X obj 7 246 cnv 1 450 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; -#X obj 7 216 cnv 1 450 1 empty empty 1st: 8 12 0 13 #7c7c7c #000000 0; -#X text 132 224 float - the voice number., f 40; -#X obj 7 276 cnv 1 450 1 empty empty 3rd: 8 12 0 13 #7c7c7c #000000 0; -#X text 111 323 1) float - number of voices (default 1)., f 43; -#X text 111 341 2) float - non-zero sets to voice stealing.; -#X text 131 284 float - note velocity., f 40; -#X text 131 254 float - note pitch., f 40; +#X text 132 206 float - set velocity value., f 40; +#X obj 7 290 cnv 1 450 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; +#X obj 7 260 cnv 1 450 1 empty empty 1st: 8 12 0 13 #7c7c7c #000000 0; +#X text 132 268 float - the voice number., f 40; +#X obj 7 320 cnv 1 450 1 empty empty 3rd: 8 12 0 13 #7c7c7c #000000 0; +#X text 62 379 1) float - number of voices (default 1)., f 43; +#X text 131 328 float - note velocity., f 40; +#X text 131 298 float - note pitch., f 40; +#X text 75 150 steal -; +#X text 68 170 resize -; +#X text 188 170 set number of voices., f 32; +#X text 187 150 turn voice stealing on/off., f 32; +#X text 62 397 2) float - non-zero sets to voice stealing (default 0).; #X restore 383 17 pd reference; #X text 477 17 <= click; -#X obj 9 506 cnv 1 550 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 194 205 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; -#X text 237 230 <-- emulating note on/off messages; -#X obj 52 205 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; -#X obj 99 205 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; -#X obj 146 205 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; -#X obj 92 408 route 1 2 3 4, f 39; -#X listbox 92 436 7 0 0 0 - - - 0; -#X obj 92 463 print v1; -#X listbox 159 436 7 0 0 0 - - - 0; -#X listbox 227 436 7 0 0 0 - - - 0; -#X listbox 294 436 7 0 0 0 - - - 0; -#X obj 159 463 print v2; -#X obj 227 463 print v3; -#X obj 294 463 print v4; -#N canvas 662 49 425 614 clone 0; -#X text 33 19 You'll usually want [poly] to control a single polyhonic synth. The "route" method shown in the parent patch would then imply that you'd have the same subpatch or abstraction taking the note message., f 48; -#X listbox 181 370 13 0 0 0 - - - 0; -#X obj 181 338 pack f f f; -#X obj 181 438 output~; +#X obj 10 577 cnv 1 550 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X text 248 227 <-- emulating note on/off messages; +#X obj 104 489 route 1 2 3 4, f 39; +#X listbox 104 517 7 0 0 0 - - - 0; +#X obj 104 544 print v1; +#X listbox 171 517 7 0 0 0 - - - 0; +#X listbox 239 517 7 0 0 0 - - - 0; +#X listbox 306 517 7 0 0 0 - - - 0; +#X obj 171 544 print v2; +#X obj 239 544 print v3; +#X obj 306 544 print v4; +#N canvas 707 76 425 614 clone 0; +#X listbox 191 378 13 0 0 0 - - - 0; +#X obj 191 348 pack f f f; +#X obj 191 448 output~; #X obj 60 436 declare -stdpath ./, f 11; -#X obj 181 402 clone -s 1 clone-abs-c 4; -#X obj 181 304 poly 4 1; -#X text 65 532 In [clone] \, we use the "-s" flag to set the starting copy number to 1 \, so it matches the voice numbers from [poly] \, which is indexed by 1 as well., f 43; -#X obj 181 256 makenote 55 1500; -#X msg 111 188 60; -#X msg 144 188 62; -#X msg 181 188 65; -#X msg 222 188 69; -#X floatatom 181 226 5 0 0 0 - - - 0; -#X obj 119 256 notein; -#X text 33 102 An approach that is more useful in this case is using [clone] to load an abstraction \, see below. Here we use [makenote] but you can also try your MIDI keyboard input with [notein]., f 48; -#X connect 1 0 5 0; -#X connect 2 0 1 0; -#X connect 5 0 3 0; -#X connect 6 0 2 0; -#X connect 6 1 2 1; -#X connect 6 2 2 2; -#X connect 8 0 6 0; -#X connect 8 1 6 1; -#X connect 9 0 13 0; -#X connect 10 0 13 0; -#X connect 11 0 13 0; -#X connect 12 0 13 0; -#X connect 13 0 8 0; -#X connect 14 0 6 0; -#X connect 14 1 6 1; -#X restore 444 449 pd clone; -#X text 166 319 <-- first argument \, number of voices second; -#X text 195 335 argument selects voice stealing; -#X text 339 521 updated for Pd version 0.54-1; -#X obj 221 519 clone; -#X obj 163 518 notein; +#X obj 191 412 clone -s 1 clone-abs-c 4; +#X obj 191 314 poly 4 1; +#X obj 191 255 makenote 55 1500; +#X msg 158 189 60; +#X msg 191 189 62; +#X msg 228 189 65; +#X msg 269 189 69; +#X floatatom 191 227 5 0 0 0 - - - 0; +#X obj 203 283 notein; +#X text 33 102 An approach that is more useful in this case is to use [clone] to load copies of an abstraction \, see below. Here we use [makenote] but you can also try your MIDI keyboard input with [notein]., f 50; +#X text 65 532 In [clone] \, we use the "-s" flag to set the starting copy number to 1 \, so it matches the voice numbers from [poly] (which is indexed from 1)., f 43; +#X text 33 19 You'll usually want [poly] to control many copies (or multiple voices) of the same polyphonic synth patch. The "route" method shown in the parent patch would then imply that you'd have the same subpatch or abstraction taking the note message., f 50; +#X msg 109 260 resize \$1; +#X floatatom 109 237 5 1 100 0 - - - 0; +#X text 24 238 set number of voices, f 10; +#X connect 0 0 4 0; +#X connect 1 0 0 0; +#X connect 4 0 2 0; +#X connect 5 0 1 0; +#X connect 5 1 1 1; +#X connect 5 2 1 2; +#X connect 6 0 5 0; +#X connect 6 1 5 1; +#X connect 7 0 11 0; +#X connect 8 0 11 0; +#X connect 9 0 11 0; +#X connect 10 0 11 0; +#X connect 11 0 6 0; +#X connect 12 0 5 0; +#X connect 12 1 5 1; +#X connect 16 0 4 0; +#X connect 16 0 5 0; +#X connect 17 0 16 0; +#X restore 445 533 pd clone; +#X text 207 418 argument selects voice stealing; +#X obj 222 594 clone; +#X obj 164 594 notein; #X text 40 62 The [poly] object takes pitch in the left inlet and velocity in the right inlet \, but the example here takes a list input \, which gets spread at inlets (as is common in Pd). The output is voice number (left outlet) \, pitch (mid outlet) and velocity (right outlet)., f 68; #X text 39 125 You can pack the output and use the [route] object to route messages to different voices (as below) or feed it [clone] (see example in [pd clone]). The [poly] object can be configured to do voice stealing with the 2nd argument (the default is 'no stealing')., f 68; -#X msg 52 231 72 \$1; -#X msg 99 231 74 \$1; -#X msg 146 231 77 \$1; -#X msg 194 231 81 \$1; #N canvas 661 49 444 661 monophonic 0; -#X obj 163 454 output~; -#X obj 171 240 notein; -#X obj 163 354 osc~; -#X obj 163 393 *~; -#X obj 163 318 mtof; -#X obj 209 416 pow~ 4; -#X obj 209 311 / 127; -#X obj 209 377 line~; -#X msg 209 341 \$1 150; -#X obj 137 274 poly 1 1; -#X obj 232 131 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; -#X obj 90 131 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; -#X obj 137 131 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; -#X obj 184 131 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; -#X msg 90 157 72 \$1; -#X msg 184 157 77 \$1; -#X msg 232 157 81 \$1; -#X listbox 137 207 10 0 0 0 - - - 0; -#X msg 137 157 74 \$1; -#X text 33 19 If you set [poly] to a single voice you can make it manage a monophonic synth control a single polyhonic synth. Without this minimum management you may end up getting undesired note off messages from releasing keys that were previously pressed instead from the currently pressed one., f 50; -#X text 59 542 Note however that some monophonic synths may have a more sophisticated management where it goes back to the previously pressed key (if you're still pressing it) \, but [poly] can only manage this in a much simpler way., f 45; -#X text 228 233 you can also try your MIDI keyboard., f 19; +#X obj 163 472 output~; +#X obj 171 258 notein; +#X obj 163 372 osc~; +#X obj 163 411 *~; +#X obj 163 336 mtof; +#X obj 209 434 pow~ 4; +#X obj 209 329 / 127; +#X obj 209 395 line~; +#X msg 209 359 \$1 150; +#X obj 137 292 poly 1 1; +#X obj 232 149 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 90 149 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 137 149 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 184 149 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X msg 90 175 72 \$1; +#X msg 184 175 77 \$1; +#X msg 232 175 81 \$1; +#X listbox 137 225 10 0 0 0 - - - 0; +#X msg 137 175 74 \$1; +#X text 59 560 Note however that some monophonic synths may have a more sophisticated management where it goes back to the previously pressed key (if you're still pressing it) \, but [poly] can only manage this in a much simpler way., f 45; +#X text 228 251 you can also try your MIDI keyboard., f 19; +#X text 33 19 If you set [poly] to a single voice and voice stealing you can make it manage a monophonic synth. Without this minimum management you may end up getting undesired note off messages from releasing keys that were previously pressed instead of the note offs from the currently sounding key pressed for last., f 51; #X connect 1 0 9 0; #X connect 1 1 9 1; #X connect 2 0 3 0; @@ -139,27 +139,51 @@ #X connect 16 0 17 0; #X connect 17 0 9 0; #X connect 18 0 17 0; -#X restore 444 419 pd monophonic; +#X restore 445 503 pd monophonic; +#X text 178 402 <-- first argument \, number of voices. Second; +#X msg 223 360 steal \$1; +#X obj 223 336 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X text 290 361 voice stealing on/off; +#X msg 33 352 resize \$1; +#X floatatom 33 329 5 1 100 0 - - - 0; +#X text 23 294 set number of voices, f 10; +#X listbox 373 517 7 0 0 0 - - - 0; +#X text 340 593 updated for Pd version 0.56-0; +#X listbox 110 276 10 0 0 0 - - - 0; +#X obj 205 202 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 63 202 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 110 202 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X obj 157 202 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 64; +#X msg 63 228 72 \$1; +#X msg 110 228 74 \$1; +#X msg 157 228 77 \$1; +#X msg 205 228 81 \$1; #X connect 3 0 8 0; #X connect 3 1 8 1; #X connect 3 2 8 2; #X connect 4 0 3 0; #X connect 5 0 3 0; -#X connect 7 0 20 0; +#X connect 7 0 16 0; #X connect 8 0 7 0; -#X connect 15 0 40 0; -#X connect 17 0 37 0; -#X connect 18 0 38 0; -#X connect 19 0 39 0; -#X connect 20 0 21 0; -#X connect 20 1 23 0; -#X connect 20 2 24 0; -#X connect 20 3 25 0; -#X connect 21 0 22 0; -#X connect 23 0 26 0; -#X connect 24 0 27 0; -#X connect 25 0 28 0; -#X connect 37 0 3 0; -#X connect 38 0 3 0; -#X connect 39 0 3 0; -#X connect 40 0 3 0; +#X connect 16 0 17 0; +#X connect 16 1 19 0; +#X connect 16 2 20 0; +#X connect 16 3 21 0; +#X connect 16 4 39 0; +#X connect 17 0 18 0; +#X connect 19 0 22 0; +#X connect 20 0 23 0; +#X connect 21 0 24 0; +#X connect 33 0 3 0; +#X connect 34 0 33 0; +#X connect 36 0 3 0; +#X connect 37 0 36 0; +#X connect 41 0 3 0; +#X connect 42 0 49 0; +#X connect 43 0 46 0; +#X connect 44 0 47 0; +#X connect 45 0 48 0; +#X connect 46 0 41 0; +#X connect 47 0 41 0; +#X connect 48 0 41 0; +#X connect 49 0 41 0; diff --git a/doc/5.reference/print~-help.pd b/doc/5.reference/print~-help.pd index e9d9f77207..b0c2e91456 100644 --- a/doc/5.reference/print~-help.pd +++ b/doc/5.reference/print~-help.pd @@ -1,11 +1,10 @@ -#N canvas 516 27 533 356 12; +#N canvas 516 38 534 514 12; #X msg 120 187 2; #X obj 57 126 phasor~ 1000; #X text 119 155 bang prints one vector; #X obj 25 14 print~; -#X text 317 315 Updated for Pd version 0.33; -#X text 21 316 see also:; -#X obj 93 317 print; +#X text 21 474 see also:; +#X obj 93 475 print; #X msg 355 177 \; pd dsp \$1; #N canvas 657 103 573 246 reference 0; #X obj 18 52 cnv 5 550 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; @@ -13,17 +12,17 @@ #X obj 18 178 cnv 2 550 2 empty empty ARGUMENT: 8 12 0 13 #202020 #000000 0; #X obj 17 215 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; #X text 146 151 NONE, f 5; -#X text 89 67 signal - signal block to print on terminal window.; #X obj 39 15 print~; -#X text 104 88 bang - print one block on terminal window.; -#X text 98 108 float - sets and prints number of blocks on terminal window.; +#X text 124 88 bang - print one block on terminal window.; +#X text 118 108 float - sets and prints number of blocks on terminal window.; #X text 126 189 1) symbol - symbol prefix (default: "print~").; #X text 92 15 - print out one or more "blocks".; +#X text 89 67 signal(s) - input to print on terminal window.; #X restore 359 13 pd reference; #X text 457 14 <= click; #X obj 9 47 cnv 1 520 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 9 307 cnv 1 520 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 144 317 block~; +#X obj 9 465 cnv 1 520 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X obj 144 475 block~; #X obj 94 155 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X text 41 66 The [print~] object takes a signal input and prints one or more blocks (or 'vectors') out when you send it a bang or a number. By default a block is 64 samples long., f 63; #X obj 94 260 print~ phasor; @@ -33,8 +32,20 @@ #X text 78 14 - print out one or more "blocks"; #X obj 355 142 set-dsp-tgl; #X text 386 146 DSP on/off; -#X connect 0 0 16 0; -#X connect 1 0 15 0; -#X connect 13 0 15 0; -#X connect 16 0 15 0; -#X connect 20 0 7 0; +#X text 317 473 Updated for Pd version 0.56; +#X obj 199 475 snapshot~; +#X obj 76 347 snake~ in; +#X obj 76 315 noise~; +#X obj 136 316 osc~ 1; +#X obj 98 386 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X obj 76 423 print~ Multichannel-Connections; +#X text 219 320 Multichannel connections are supported \, in which case we have blocks for each channel described as "channel 1" \, "channel 2" and so on..., f 29; +#X connect 0 0 15 0; +#X connect 1 0 14 0; +#X connect 12 0 14 0; +#X connect 15 0 14 0; +#X connect 19 0 6 0; +#X connect 23 0 27 0; +#X connect 24 0 23 0; +#X connect 25 0 23 1; +#X connect 26 0 27 0; diff --git a/doc/5.reference/random-help.pd b/doc/5.reference/random-help.pd index 87ca9ebb3a..22a534089a 100644 --- a/doc/5.reference/random-help.pd +++ b/doc/5.reference/random-help.pd @@ -1,41 +1,38 @@ -#N canvas 531 40 481 416 12; -#X floatatom 137 244 5 0 0 0 - - - 0; -#X floatatom 84 302 4 0 0 0 - - - 0; -#X msg 103 209 seed 123; -#X text 108 176 bang for output; -#X text 180 245 inlet to reset the range; -#X text 151 274 argument to initialize the range; -#X text 276 378 updated for Pd version 0.33; +#N canvas 531 40 518 431 12; +#X floatatom 175 255 5 0 0 0 - - - 0; +#X floatatom 122 313 4 0 0 0 - - - 0; +#X msg 149 223 seed 123; +#X text 189 285 argument to initialize the range; #X obj 27 13 random; #X text 81 12 - pseudo random integers; -#X text 9 379 see also:; -#X obj 82 378 expr; -#X obj 10 42 cnv 1 460 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#N canvas 722 116 574 286 reference 0; +#X text 15 391 see also:; +#X obj 88 390 expr; +#X obj 10 45 cnv 1 500 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#N canvas 598 137 574 306 reference 0; #X obj 8 52 cnv 5 550 5 empty empty INLETS: 8 18 0 13 #202020 #000000 0; -#X obj 8 184 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; -#X obj 8 221 cnv 2 550 2 empty empty ARGUMENT: 8 12 0 13 #202020 #000000 0; -#X obj 7 258 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X obj 8 145 cnv 1 550 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; +#X obj 8 204 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; +#X obj 8 241 cnv 2 550 2 empty empty ARGUMENT: 8 12 0 13 #202020 #000000 0; +#X obj 7 278 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X obj 8 165 cnv 1 550 1 empty empty 2nd: 8 12 0 13 #7c7c7c #000000 0; #X obj 8 85 cnv 1 550 1 empty empty 1st: 8 12 0 13 #7c7c7c #000000 0; #X obj 40 16 random; #X text 94 15 - pseudo random integers.; -#X text 98 92 bang - generate a random integer number., f 62; -#X text 147 113 set a seed value for repeatable random numbers., f 55; -#X text 143 155 float - set the range., f 49; -#X text 143 194 float - the generated random number., f 49; -#X text 143 232 1) float - initial range value (default 1)., f 49; -#X text 42 113 seed -; -#X restore 290 12 pd reference; -#X text 384 12 <= click; -#X obj 10 361 cnv 1 460 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 84 274 random 5; -#X obj 84 177 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X obj 84 330 print random; -#X text 175 209 set the seed \, see -->; -#X obj 121 378 noise~; -#X obj 172 378 array random; -#X text 24 117 WARNING: Nothing is known about the quality of this pseudo random number generator. It isn't any standard one!, f 60; +#X text 108 92 bang - generate a random integer number., f 60; +#X text 157 134 set a seed value for repeatable random numbers., f 53; +#X text 143 175 float - set the range., f 49; +#X text 143 214 float - the generated random number., f 49; +#X text 143 252 1) float - initial range value (default 1)., f 49; +#X text 52 134 seed -; +#X text 101 112 float - set the range and output a random value., f 61; +#X restore 331 12 pd reference; +#X text 425 12 <= click; +#X obj 122 285 random 5; +#X obj 122 164 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X obj 122 341 print random; +#X text 221 223 set the seed \, see -->; +#X obj 127 390 noise~; +#X obj 178 390 array random; +#X text 38 115 WARNING: Nothing is known about the quality of this pseudo random number generator. It isn't any standard one!, f 60; #N canvas 725 64 467 460 more 0; #X text 54 196 If you don't supply a seed each [random] object gets its own seed., f 52; #X floatatom 83 381 4 0 0 0 - - - 0; @@ -58,11 +55,18 @@ #X connect 7 0 10 0; #X connect 9 0 10 0; #X connect 10 0 6 0; -#X restore 333 204 pd more about seed; +#X restore 379 218 pd more about seed; #X f 10; -#X text 24 60 [random] outputs pseudo random integers from 0 to N-1 where N is the creation argument (5 in the example below.) You can specify a seed if you wish in order reproduce the sequence.; -#X connect 0 0 15 1; -#X connect 1 0 17 0; -#X connect 2 0 15 0; -#X connect 15 0 1 0; -#X connect 16 0 15 0; +#X text 38 60 [random] outputs pseudo random integers from 0 to N-1 where N is the creation argument (5 in the example below.) You can specify a seed if you wish in order reproduce the sequence.; +#X text 146 163 bang to output a random number; +#X floatatom 136 192 5 1 100 0 - - - 0; +#X text 176 190 number to set range and output; +#X text 218 256 inlet to set the range; +#X text 292 389 updated for Pd version 0.56-0; +#X obj 10 374 cnv 1 500 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X connect 0 0 11 1; +#X connect 1 0 13 0; +#X connect 2 0 11 0; +#X connect 11 0 1 0; +#X connect 12 0 11 0; +#X connect 21 0 11 0; diff --git a/doc/5.reference/readsf~-help.pd b/doc/5.reference/readsf~-help.pd index e06e5db7f9..2be56ced73 100644 --- a/doc/5.reference/readsf~-help.pd +++ b/doc/5.reference/readsf~-help.pd @@ -1,89 +1,117 @@ -#N canvas 425 55 707 760 12; +#N canvas 425 44 707 760 12; #X declare -stdpath ./; #X obj 475 555 print didit; #X floatatom 93 550 6 0 0 0 - - - 0; -#X msg 187 446 print; +#X msg 192 445 print; #X obj 96 725 soundfiler; #X text 17 724 see also:; #X obj 33 11 readsf~; #X obj 150 516 output~; #X obj 185 725 writesf~; #X obj 475 525 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X obj 534 356 declare -stdpath ./; #X obj 3 41 cnv 1 695 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 623 10 <= click; -#N canvas 651 73 586 410 reference 0; -#X obj 8 52 cnv 5 565 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; -#X obj 8 208 cnv 2 565 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; -#X obj 8 309 cnv 2 565 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; -#X obj 7 383 cnv 5 565 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X obj 7 273 cnv 1 565 1 empty empty rightmost: 8 12 0 13 #7c7c7c #000000 0; -#X obj 7 236 cnv 1 565 1 empty empty n: 8 12 0 13 #7c7c7c #000000 0; +#N canvas 661 99 613 559 reference 0; +#X obj 8 52 cnv 5 590 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; +#X obj 8 237 cnv 2 590 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; +#X obj 8 386 cnv 2 590 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; +#X obj 7 524 cnv 5 590 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X obj 7 350 cnv 1 590 1 empty empty rightmost: 8 12 0 13 #7c7c7c #000000 0; +#X obj 7 313 cnv 1 590 1 empty empty n: 8 12 0 13 #7c7c7c #000000 0; #X obj 30 18 readsf~; #X text 78 66 open -; -#X text 120 155 float -; -#X text 177 155 nonzero starts playback \, zero stops., f 54; -#X text 121 176 print - prints information on Pd's terminal window., f 62; -#X text 122 245 signal -; -#X text 187 245 channel output of a given file., f 46; -#X text 137 281 bang - when finishing playing file., f 54; -#X text 86 332 1) float - sets number of output channels (default 1 \, max 64)., f 62; -#X text 82 213 ('n' number of outlets specified by argument); -#X text 120 115 start -; -#X text 127 135 stop -; -#X text 177 135 stop playback., f 54; +#X text 120 184 float -; +#X text 177 184 nonzero starts playback \, zero stops., f 54; +#X text 121 205 print - prints information on Pd's terminal window., f 62; +#X text 122 322 signal -; +#X text 187 322 channel output of a given file., f 46; +#X text 137 358 bang - when finishing playing file., f 54; +#X text 108 473 1) float - sets number of output channels (default 1 \, max 64)., f 62; +#X text 82 242 ('n' number of outlets specified by argument); +#X text 120 144 start -; +#X text 127 164 stop -; +#X text 177 164 stop playback., f 54; #X text 88 19 - soundfile playback from disk.; -#X text 177 115 start playback., f 54; -#X text 86 351 2) float - per channel buffer size in bytes (default/min 262144)., f 65; +#X text 177 144 start playback., f 54; +#X text 108 492 2) float - per channel buffer size in bytes (default/min 262144)., f 65; #X text 177 66 (needed before start playback) sets a filename and optionally: samples onset \, header size to skip \, number of channels \, bytes per sample \, and endianness., f 54; +#X obj 8 270 cnv 1 590 1 empty empty 1st: 8 12 0 13 #9f9f9f #000000 0; +#X text 102 279 signals -; +#X text 175 279 a multichannel output if invoked with the -m flag.; +#X text 43 124 channels -; +#X text 177 124 sets number of output channels iinvoked with the -m flag.; +#X obj 8 413 cnv 1 590 1 empty empty flags: 8 12 0 13 #9f9f9f #000000 0; +#X obj 8 460 cnv 1 590 1 empty empty arguments: 8 12 0 13 #9f9f9f #000000 0; +#X text 135 421 -m:; +#X text 164 420 creates a multichannel signal with number of input channels given as the 1st argument., f 54; #X restore 529 11 pd reference; #X floatatom 284 550 6 0 0 0 - - - 0; #X text 502 466 Arguments:, f 20; -#X obj 144 386 tgl 19 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 144 380 tgl 19 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; #X floatatom 144 413 3 0 0 0 - - - 0; -#X text 167 386 nonzero starts playback \, zero stops it; -#X msg 120 325 start; -#X msg 132 355 stop; -#X text 165 325 start playback; -#X text 171 355 stop playback; +#X text 171 374 nonzero starts playback \, zero stops it, f 24; +#X msg 120 321 start; +#X msg 131 349 stop; +#X text 165 321 start playback; +#X text 170 349 stop playback; #X text 91 11 - soundfile playback from disk; #X obj 3 713 cnv 1 695 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 93 523 env~; #X obj 284 523 env~; #X text 348 518 "bang" when file reaches the end., f 16; -#X msg 93 295 open ../sound/bell.aiff 0 200 2 2 b; -#X msg 185 413 open ../sound/bell.aiff 22050 \, 1; +#X msg 93 291 open ../sound/bell.aiff 0 200 2 2 b; #X text 502 484 - number of channels - per channel buffer size in bytes, f 20; #X obj 93 479 readsf~ 2 262144, f 55; #X text 21 51 The [readsf~] object streams a soundfile from the hard disk. That is \, it doesn't fully load it into the memory \, but into a small local buffer first. The "open" message starts filling this buffer but a playback only starts when you send a "1" or "start" message. A "0" or "stop" message stops it. You may get audio dropouts if you "start" right after the "open" message \, so you should wait a few milliseconds between "open" and "start" to ensure that the buffer is filled in time. You can also increase the default buffer size as the 2nd argument \, but it shouldn't really be necessary. The 1st argument initializes the number of channel outputs., f 94; -#X text 425 405 open at half a second into the file and start right away. Since it's mono \, we only have the left output., f 35; +#X text 414 407 open at half a second into the file and start right away. Since it's mono \, we only have the left output., f 35; #X text 21 155 The 'wave' \, 'aiff' \, 'caf' \, and 'next' formats are supported \, although only uncompressed 2- or 3-byte integer ("pcm") and 4- or 8-byte floating point samples are accepted., f 94; -#X text 236 445 print info on Pd window; +#X text 240 438 print info on Pd window, f 12; #X text 40 593 NOTE: check also [soundfiler] \, which allows you to load a file into memory by filling it into an array. This also gives you more playback possibilities with table reading objects., f 89; #X obj 258 725 openpanel; #X text 21 189 HINT: The 'open' message can take "~" to define the home directory. Also note you can use [openpanel] to find sound files., f 94; -#X text 476 724 updated for Pd version 0.55-1; #X text 40 643 ALSO NOTE: As of Pd 0.55-1 \, [readsf~]'s "open" method searches in the canvas environment \, just like [soundfiler] and similar objects. This means you can now use paths added via [declare] (which wasn't possible before)., f 89; -#X obj 30 268 openpanel; -#X msg 30 295 open \$1; -#X obj 30 239 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; -#X text 352 286 (By overriding the header here \, we force this mono file to be played as a stereo twice as fast), f 41; -#X text 131 237 The open message takes filename and optionally: onset in samples \, header size to skip \, channels number \, bytes per sample and endianness.; -#X connect 2 0 30 0; +#X obj 30 264 openpanel; +#X msg 30 291 open \$1; +#X obj 30 237 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X text 352 282 (By overriding the header here \, we force this mono file to be played as a stereo twice as fast), f 41; +#X text 131 233 The open message takes filename and optionally: onset in samples \, header size to skip \, channels number \, bytes per sample and endianness.; +#X text 394 344 mutichannel signal support ----->, f 20; +#N canvas 768 186 512 477 multichannel 0; +#X obj 89 245 readsf~ -m 2, f 17; +#X obj 89 332 output~; +#X obj 89 280 snake~ out; +#X text 118 35 A '-m' flag turns the output into a multichannel signal connection with the given number of channels., f 36; +#X msg 125 180 channels 1; +#X msg 113 139 start; +#X msg 135 210 channels 2; +#X text 226 172 The channels message is able to change the number of channels in the connection dynamically, f 31; +#X obj 82 423 declare -stdpath ./, f 20; +#X msg 89 103 open ../sound/stereo.wav; +#X connect 0 0 2 0; +#X connect 2 0 1 0; +#X connect 2 1 1 1; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 6 0 0 0; +#X connect 9 0 0 0; +#X restore 503 364 pd multichannel; +#X text 476 724 updated for Pd version 0.56; +#X msg 185 415 open ../sound/stereo.wav 24000; +#X connect 2 0 28 0; #X connect 8 0 0 0; -#X connect 15 0 16 0; -#X connect 16 0 30 0; -#X connect 18 0 30 0; -#X connect 19 0 30 0; -#X connect 24 0 1 0; -#X connect 25 0 13 0; -#X connect 27 0 30 0; -#X connect 28 0 30 0; -#X connect 30 0 6 0; -#X connect 30 0 24 0; -#X connect 30 1 25 0; -#X connect 30 1 6 1; -#X connect 30 2 8 0; -#X connect 40 0 41 0; -#X connect 41 0 30 0; -#X connect 42 0 40 0; +#X connect 14 0 15 0; +#X connect 15 0 28 0; +#X connect 17 0 28 0; +#X connect 18 0 28 0; +#X connect 23 0 1 0; +#X connect 24 0 12 0; +#X connect 26 0 28 0; +#X connect 28 0 6 0; +#X connect 28 0 23 0; +#X connect 28 1 24 0; +#X connect 28 1 6 1; +#X connect 28 2 8 0; +#X connect 37 0 38 0; +#X connect 38 0 28 0; +#X connect 39 0 37 0; +#X connect 45 0 28 0; diff --git a/doc/5.reference/savestate-ex1.pd b/doc/5.reference/savestate-ex1.pd index 59c969861e..b3baf7c8b6 100644 --- a/doc/5.reference/savestate-ex1.pd +++ b/doc/5.reference/savestate-ex1.pd @@ -19,7 +19,6 @@ #X obj 139 160 s \$0-bw; #X obj 382 191 r \$0-bw; #X obj 326 357 s \$0-set-bw; -#X obj 287 385 s \$0-set-hz; #X obj 29 49 r \$0-set-bw; #X text 307 34 This is an abstraction used by the [savestate] help file., f 29; #X obj 130 49 r \$0-set-freq; @@ -27,8 +26,9 @@ #X obj 54 176 r \$0-freq; #X obj 365 165 r \$0-freq; #X text 391 214 Here we build and send a single list of parameters we want to save. The next example shows how you can store more than a single list., f 32; +#X obj 287 385 s \$0-set-freq; #X connect 0 0 6 0; -#X connect 1 0 24 0; +#X connect 1 0 23 0; #X connect 3 0 13 0; #X connect 3 0 17 0; #X connect 4 0 5 0; @@ -42,12 +42,12 @@ #X connect 10 0 11 0; #X connect 11 0 12 0; #X connect 11 1 9 0; -#X connect 12 0 20 0; +#X connect 12 0 27 0; #X connect 12 1 19 0; #X connect 13 0 6 1; #X connect 18 0 10 1; -#X connect 21 0 3 0; -#X connect 23 0 1 0; -#X connect 25 0 8 0; -#X connect 26 0 9 1; +#X connect 20 0 3 0; +#X connect 22 0 1 0; +#X connect 24 0 8 0; +#X connect 25 0 9 1; #X coords 0 -1 1 1 125 70 1 125 75; diff --git a/doc/5.reference/savestate-help.pd b/doc/5.reference/savestate-help.pd index 6b6967d0a5..68c1f9b40b 100644 --- a/doc/5.reference/savestate-help.pd +++ b/doc/5.reference/savestate-help.pd @@ -1,5 +1,4 @@ #N canvas 332 51 824 646 12; -#X text 587 615 updated for Pd version 0.49.; #X text 44 509 The abstraction may itself be modified at will without disturbing the saved states of its copies in any calling patches \, as long as the usage of the saved and restored lists is kept compatible., f 49; #X obj 39 13 savestate; #N canvas 689 98 622 256 reference 0; @@ -44,7 +43,6 @@ #X text 493 262 amp; #X text 527 291 freq; #X text 426 58 The saved messages are output when the object is recreated \, but before connections to the parent patch are made. Check the example below on how to [loadbang] to send messages to objects elsewhere in the owning patch. The example also shows how to store more than one list in a [savestate] object., f 51; -#X text 438 327 Note that abstractions within [clone] objects are not handled! Instead \, you can have a [clone] object inside your abstraction and use [savestate] to send data to the copies of the cloned abstraction. The last example below shows how to use multiple [savestate] objects in an abstraction., f 51; #X listbox 451 561 12 0 0 0 - - - 0; #X listbox 540 532 12 0 0 0 - - - 0; #X listbox 638 561 12 0 0 0 - - - 0; @@ -62,13 +60,17 @@ #X text 27 58 The [savestate] object is used inside abstractions to save their state as they are used in a calling (parent) patch. When the parent patch (such as this one \, which calls the example abstractions) is saved \, the included [savestate] object inside the abstractions sends a 'bang' message out its right outlet \, with which the abstraction may respond by presenting one or more 'list' messages back to the [savestate] object., f 52; #X text 27 192 These lists are saved as part of the calling patch. If the calling patch is reopened later \, the lists are sent out the left outlet of the [savestate] object. The abstraction can then use them to restore its state., f 52; #X obj 7 602 cnv 1 805 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X connect 7 0 10 0; -#X connect 8 0 10 1; -#X connect 12 0 14 0; -#X connect 12 1 15 0; -#X connect 13 0 16 0; -#X connect 13 1 17 0; -#X connect 32 0 24 0; -#X connect 32 1 25 0; -#X connect 33 0 26 0; -#X connect 33 1 27 0; +#X text 448 337 The last example below shows how to use multiple [savestate] objects in an abstraction. Check the help file of [clone] for an example on how to use [savestate] with [clone]., f 49; +#X text 16 613 see also:; +#X obj 93 613 clone; +#X text 587 614 updated for Pd version 0.56-0; +#X connect 6 0 9 0; +#X connect 7 0 9 1; +#X connect 11 0 13 0; +#X connect 11 1 14 0; +#X connect 12 0 15 0; +#X connect 12 1 16 0; +#X connect 30 0 22 0; +#X connect 30 1 23 0; +#X connect 31 0 24 0; +#X connect 31 1 25 0; diff --git a/doc/5.reference/send-receive-tilde-help.pd b/doc/5.reference/send-receive-tilde-help.pd index e666378383..079b964b95 100644 --- a/doc/5.reference/send-receive-tilde-help.pd +++ b/doc/5.reference/send-receive-tilde-help.pd @@ -1,4 +1,4 @@ -#N canvas 407 23 591 644 12; +#N canvas 407 34 591 644 12; #X floatatom 334 412 5 0 0 0 - - - 0; #X obj 46 235 sig~ 50; #X obj 334 382 snapshot~; @@ -53,20 +53,15 @@ #X obj 4 74 cnv 1 580 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 225 211 \$0 needs to be expanded from objects., f 23; #X obj 426 349 r~ signal; -#N canvas 695 29 499 591 multi-channel 0; +#N canvas 695 34 499 591 multi-channel 0; #X floatatom 71 99 5 0 0 0 - - - 0; -#X floatatom 145 99 5 0 0 0 - - - 0; -#X obj 111 409 snapshot~; -#X floatatom 111 435 8 0 0 0 - - - 0; -#X obj 192 409 snapshot~; -#X obj 214 371 metro 250; -#X obj 214 342 loadbang; -#X floatatom 192 435 8 0 0 0 - - - 0; +#X floatatom 152 99 5 0 0 0 - - - 0; +#X obj 111 399 snapshot~; +#X obj 134 361 metro 250; +#X obj 134 332 loadbang; #X text 352 366 see also:; #X obj 399 394 clone; #X obj 71 219 send~ cat 2; -#X obj 71 129 snake~ in 2; -#X obj 111 343 snake~ out 2; #X obj 342 394 snake~; #X obj 111 293 receive~ cat; #X text 210 289 <-- receive outputs the same number of channels, f 23; @@ -75,26 +70,24 @@ #X text 43 18 This example shows how to set number of channels as the 2nd argument to [send~] \, so it can take a multichannel signal. You can also change the number of channels with the 'channels' message., f 52; #X text 208 167 set number of channels., f 12; #X text 157 219 <-- 2nd argument sets number of channels, f 21; -#X text 193 98 <-- change values; +#X text 200 98 <-- change values; #X text 183 166 <--; #X msg 344 183 \; pd dsp \$1; #X obj 344 148 set-dsp-tgl; #X text 375 152 DSP on/off; #X text 43 479 Note: you can use "set" messages to switch a [receive~] between multichannel [send~] objects with different numbers of channels \, but this can only be done while DSP is off. When DSP is on the [send~] channel counts stays fixed!, f 55; -#X connect 0 0 11 0; -#X connect 1 0 11 1; -#X connect 2 0 3 0; -#X connect 4 0 7 0; -#X connect 5 0 4 0; -#X connect 5 0 2 0; -#X connect 6 0 5 0; -#X connect 11 0 10 0; -#X connect 12 0 2 0; -#X connect 12 1 4 0; -#X connect 14 0 12 0; -#X connect 16 0 10 0; -#X connect 17 0 10 0; -#X connect 24 0 23 0; +#X obj 71 129 sig~ 1.1 2.2; +#X listbox 111 433 11 0 0 0 - - - 0; +#X connect 0 0 22 0; +#X connect 1 0 22 1; +#X connect 2 0 23 0; +#X connect 3 0 2 0; +#X connect 4 0 3 0; +#X connect 9 0 2 0; +#X connect 11 0 7 0; +#X connect 12 0 7 0; +#X connect 19 0 18 0; +#X connect 22 0 7 0; #X restore 340 480 pd multi-channel; #X text 89 481 see multi channel example here -->; #X text 162 13 - one-to-many nonlocal signal(s) connection; diff --git a/doc/5.reference/sig~-help.pd b/doc/5.reference/sig~-help.pd index 293e57fea2..2359bbdd14 100644 --- a/doc/5.reference/sig~-help.pd +++ b/doc/5.reference/sig~-help.pd @@ -1,48 +1,79 @@ -#N canvas 512 61 488 451 12; -#X obj 90 330 snapshot~; -#X floatatom 90 364 6 0 0 0 - - - 0; +#N canvas 541 86 488 451 12; +#X obj 60 322 snapshot~; +#X floatatom 60 356 6 0 0 0 - - - 0; #X obj 27 13 sig~; -#X obj 90 201 sig~; -#X floatatom 90 169 6 0 0 0 - - - 0; -#X obj 112 276 metro 200; -#X text 266 416 updated for Pd version 0.33; -#X text 140 169 <= Scroll to set value, f 12; -#X obj 112 245 loadbang; +#X obj 60 197 sig~; +#X floatatom 60 165 6 0 0 0 - - - 0; +#X obj 82 268 metro 200; +#X text 110 165 <= Scroll to set value, f 12; +#X obj 82 237 loadbang; #X text 353 176 DSP on/off; -#X obj 206 290 sig~ 10; -#X obj 206 330 snapshot~; -#X floatatom 206 256 6 0 0 0 - - - 0; -#X floatatom 206 364 6 0 0 0 - - - 0; -#X text 271 282 An argument initializes the signal value., f 23; +#X obj 171 282 sig~ 10; +#X obj 171 322 snapshot~; +#X floatatom 171 248 6 0 0 0 - - - 0; +#X floatatom 171 356 6 0 0 0 - - - 0; #X msg 319 207 \; pd dsp \$1; #X text 14 416 see also:; #X obj 90 415 snapshot~; #X obj 7 43 cnv 1 475 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 6 401 cnv 1 475 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#N canvas 667 102 424 185 reference 0; -#X obj 8 45 cnv 5 400 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; -#X obj 8 87 cnv 2 400 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; -#X obj 7 152 cnv 5 400 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X obj 8 116 cnv 2 400 2 empty empty ARGUMENT: 8 12 0 13 #202020 #000000 0; +#N canvas 702 137 438 224 reference 0; +#X obj 8 45 cnv 5 400 5 empty empty INLETS: 8 18 0 13 #202020 #000000 0; +#X obj 8 117 cnv 2 400 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; +#X obj 7 182 cnv 5 400 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X obj 8 146 cnv 2 400 2 empty empty ARGUMENT: 8 12 0 13 #202020 #000000 0; #X obj 31 13 sig~; #X text 67 13 - convert numbers to signals; -#X text 109 58 float - number to convert to signal.; -#X text 102 93 signal - converted signal.; -#X text 104 123 1) float - initially converted value.; +#X text 109 88 float - number to convert to signal.; +#X text 104 153 1) list - initially converted values.; +#X text 102 123 signal(s) - converted signal(s).; +#X obj 8 80 cnv 1 400 1 empty empty 'n': 8 12 0 13 #9f9f9f #000000 0; +#X text 75 54 (number depends on number of arguments); #X restore 315 14 pd reference; #X text 409 14 <= click; #X text 63 13 - convert numbers to signals; -#X text 47 57 [sig~] object converts numbers to an audio signal. In this example \, the [snapshot~] converts back again., f 54; #X obj 319 170 set-dsp-tgl; #X obj 169 415 vline~; #X text 47 95 You can only convert one float per block \, for a more sophisticated conversion in between blocks you can use [vline~]; +#X text 228 281 <--; +#X text 47 57 [sig~] object converts numbers to an audio signal. In this example \, the [snapshot~] converts it back again., f 54; +#X text 254 282 An argument initializes the signal value. More arguments generate multichannel signals \, see below:, f 30; +#N canvas 776 153 425 445 multichannel 0; +#X obj 120 360 snapshot~; +#X floatatom 120 203 5 0 0 0 - - - 0; +#X obj 142 306 metro 200; +#X obj 142 275 loadbang; +#X obj 120 235 sig~ 1 2 3 4, f 21; +#X floatatom 168 203 5 0 0 0 - - - 0; +#X floatatom 216 203 5 0 0 0 - - - 0; +#X floatatom 264 203 5 0 0 0 - - - 0; +#X msg 79 138 4 3 2 1; +#X listbox 79 162 16 0 0 0 - - - 0; +#X listbox 120 391 16 0 0 0 - - - 0; +#X text 43 23 More than one argument initializes numeric values in a multichannel signal connection \, where the number of signals depends on the number of arguments. Inlets for float input are created for all channels and a list input also spreads the values into inlets as it's common in Pd., f 49; +#X text 301 285 DSP on/off; +#X msg 267 316 \; pd dsp \$1; +#X obj 267 279 set-dsp-tgl; +#X connect 0 0 10 0; +#X connect 1 0 4 0; +#X connect 2 0 0 0; +#X connect 3 0 2 0; +#X connect 4 0 0 0; +#X connect 5 0 4 1; +#X connect 6 0 4 2; +#X connect 7 0 4 3; +#X connect 8 0 9 0; +#X connect 9 0 4 0; +#X connect 14 0 13 0; +#X restore 336 334 pd multichannel; +#X text 266 416 updated for Pd version 0.56; #X connect 0 0 1 0; #X connect 3 0 0 0; #X connect 4 0 3 0; #X connect 5 0 0 0; -#X connect 5 0 11 0; -#X connect 8 0 5 0; -#X connect 10 0 11 0; -#X connect 11 0 13 0; -#X connect 12 0 10 0; -#X connect 24 0 15 0; +#X connect 5 0 10 0; +#X connect 7 0 5 0; +#X connect 9 0 10 0; +#X connect 10 0 12 0; +#X connect 11 0 9 0; +#X connect 21 0 13 0; diff --git a/doc/5.reference/snake-tilde-help.pd b/doc/5.reference/snake-tilde-help.pd index 133e44912e..3073034836 100644 --- a/doc/5.reference/snake-tilde-help.pd +++ b/doc/5.reference/snake-tilde-help.pd @@ -1,12 +1,12 @@ -#N canvas 528 24 520 463 12; -#X floatatom 276 365 5 0 0 0 - - - 0; -#X obj 276 335 snapshot~; -#X obj 358 290 metro 200; +#N canvas 528 34 520 463 12; +#X floatatom 266 365 5 0 0 0 - - - 0; +#X obj 266 335 snapshot~; +#X obj 348 290 metro 200; #X text 9 423 see also:; -#X obj 358 258 loadbang; -#X floatatom 196 175 5 0 0 0 - - - 0; -#X floatatom 358 365 5 0 0 0 - - - 0; -#X obj 358 335 snapshot~; +#X obj 348 258 loadbang; +#X floatatom 186 177 5 0 0 0 - - - 0; +#X floatatom 348 365 5 0 0 0 - - - 0; +#X obj 348 335 snapshot~; #N canvas 693 101 575 495 reference 0; #X obj 8 136 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; #X obj 6 177 cnv 2 550 2 empty empty ARGUMENT: 8 12 0 13 #202020 #000000 0; @@ -35,40 +35,40 @@ #X obj 5 53 cnv 1 510 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 5 405 cnv 1 510 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 308 423 updated for Pd version 0.54; -#X floatatom 250 176 5 0 0 0 - - - 0; -#X floatatom 305 176 5 0 0 0 - - - 0; +#X floatatom 240 178 5 0 0 0 - - - 0; +#X floatatom 295 178 5 0 0 0 - - - 0; #X text 88 8 - combine or split multichannel signals, f 21; -#X floatatom 196 365 5 0 0 0 - - - 0; -#X obj 196 335 snapshot~; +#X floatatom 186 365 5 0 0 0 - - - 0; +#X obj 186 335 snapshot~; #X obj 235 424 send~; #X obj 81 424 inlet~; #X obj 137 424 clone; #X obj 30 15 snake~; -#X obj 196 245 snake~ in 3, f 16; -#X obj 196 281 snake~ out 3, f 16; +#X obj 186 245 snake~ in 3, f 16; +#X obj 186 281 snake~ out 3, f 16; #X obj 183 424 throw~; #X msg 55 282 \; pd dsp \$1; #X obj 55 247 set-dsp-tgl; #X text 54 223 DSP on/off; -#X text 45 64 Sound engineers call multi-channel audio cables "snakes." The [snake~] object can be invoked as [snake~ in] to create a muiltichannel signal from a set of single-channel ones \, or [snake~ out] to extract the channels in a multi-channel signal. Typing just [snake~] defaults to [snake~ in]. In either case \, a numeric argument sets the number of channels., f 59; -#X obj 196 210 sig~ 1; -#X obj 250 210 sig~ 2; -#X obj 305 210 sig~ 3; +#X obj 186 210 sig~ 1; +#X obj 240 210 sig~ 2; +#X obj 295 210 sig~ 3; +#X text 27 67 Sound engineers call multi-channel audio cables "snakes". The [snake~] object can be invoked as [snake~ in] to create a multichannel signal from a set of single-channel ones \, or [snake~ out] to extract the channels in a multi-channel signal. Typing just [snake~] defaults to [snake~ in]. In either case \, a numeric argument sets the number of channels., f 63; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 2 0 7 0; #X connect 2 0 17 0; #X connect 4 0 2 0; -#X connect 5 0 29 0; +#X connect 5 0 28 0; #X connect 7 0 6 0; -#X connect 13 0 30 0; -#X connect 14 0 31 0; +#X connect 13 0 29 0; +#X connect 14 0 30 0; #X connect 17 0 16 0; #X connect 22 0 23 0; #X connect 23 0 17 0; #X connect 23 1 1 0; #X connect 23 2 7 0; #X connect 26 0 25 0; -#X connect 29 0 22 0; -#X connect 30 0 22 1; -#X connect 31 0 22 2; +#X connect 28 0 22 0; +#X connect 29 0 22 1; +#X connect 30 0 22 2; diff --git a/doc/5.reference/snapshot~-help.pd b/doc/5.reference/snapshot~-help.pd index 46df149b2b..8932ba49f3 100644 --- a/doc/5.reference/snapshot~-help.pd +++ b/doc/5.reference/snapshot~-help.pd @@ -1,9 +1,8 @@ -#N canvas 532 29 631 467 12; +#N canvas 509 59 631 467 12; #X obj 78 344 snapshot~; #X obj 32 19 snapshot~; #X text 112 19 - convert a signal to a number on demand; #X obj 78 261 osc~ 0.1; -#X text 393 429 updated for Pd version 0.37; #X text 147 261 signal in to take snapshots of; #X text 28 162 A 'set' message is provided for the (rare) situations where you might make a known change to the signal input \, and then read snapshot's value before any ensuing signal computation., f 81; #X floatatom 78 371 7 0 0 0 - - - 0; @@ -14,14 +13,14 @@ #X obj 18 122 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; #X obj 18 159 cnv 2 550 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; #X obj 17 196 cnv 5 550 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X text 131 66 bang -; -#X text 166 170 NONE, f 9; +#X text 116 66 bang -; +#X text 223 169 NONE, f 9; #X obj 39 20 snapshot~; -#X text 119 20 - convert a signal to a number on demand; -#X text 183 66 convert a signal to a float., f 46; -#X text 82 86 set -; -#X text 183 86 set a float value for the next DSP block., f 46; -#X text 126 132 float - the converted signal at every bang., f 54; +#X text 168 66 convert a signal to a float., f 46; +#X text 116 132 float/list - the converted signal(s) at every bang., f 54; +#X text 119 20 - convert a signal connection to a numbers on demand; +#X text 74 86 set -; +#X text 168 86 set a float value for each channel the next DSP block.; #X restore 435 19 pd reference; #X text 533 19 <= click; #X obj 10 51 cnv 1 610 1 empty empty empty 8 12 0 13 #000000 #000000 0; @@ -29,16 +28,45 @@ #X obj 124 429 sig~; #X obj 10 414 cnv 1 610 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 113 286 <-- take one snapshot; -#X text 28 63 The [snapshot~] object takes a signal and converts it to a control value whenever it receives a bang in its left inlet. This object is particularly useful for monitoring outputs., f 81; #X text 27 122 In the example below \, a [snapshot~] object prints out the values of a low frequency cosine wave every time it is sent a bang message., f 83; #X obj 89 286 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; -#X text 135 372 This output updates each time bang is clicked above; +#X text 140 366 This output updates each time bang is clicked above, f 26; #X text 190 314 <-- set value (which is reset next DSP block); -#X msg 411 255 \; pd dsp \$1; -#X obj 411 220 set-dsp-tgl; -#X text 442 224 DSP on/off; -#X connect 0 0 7 0; -#X connect 3 0 0 0; +#X msg 430 249 \; pd dsp \$1; +#X obj 430 214 set-dsp-tgl; +#X text 461 218 DSP on/off; +#X text 383 350 mutichannel signal support:, f 20; +#N canvas 677 196 453 447 multichannel 0; +#X obj 92 342 snapshot~; +#X obj 92 194 snake~ in 2; +#X obj 92 158 noise~; +#X listbox 92 375 20 0 0 0 - - - 0; +#X msg 299 171 \; pd dsp \$1; +#X obj 299 136 set-dsp-tgl; +#X text 330 140 DSP on/off; +#X msg 111 238 set 4 5 \, bang; +#X obj 129 305 metro 250; +#X obj 166 158 osc~ 0.01; +#X obj 129 276 tgl 19 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 58 262 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X text 90 45 The object has support for multichannel connections \, in which case it outputs a list of floats for each channel input., f 40; +#X text 219 225 the set message also takes floats for each input channel, f 21; +#X text 209 295 you can use [metro] for conversion at a constant rate, f 25; +#X connect 0 0 3 0; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 5 0 4 0; +#X connect 7 0 0 0; #X connect 8 0 0 0; -#X connect 19 0 0 0; -#X connect 23 0 22 0; +#X connect 9 0 1 1; +#X connect 10 0 8 0; +#X connect 11 0 0 0; +#X restore 452 372 pd multichannel; +#X text 28 63 The [snapshot~] object takes a signal and converts it to a control value whenever it receives a bang in its left inlet. This object is particularly useful for monitoring outputs and has support for multichannel connections., f 81; +#X text 393 429 updated for Pd version 0.56; +#X obj 170 429 print~; +#X connect 0 0 6 0; +#X connect 3 0 0 0; +#X connect 7 0 0 0; +#X connect 17 0 0 0; +#X connect 21 0 20 0; diff --git a/doc/5.reference/soundfiler-help.pd b/doc/5.reference/soundfiler-help.pd index 43bae5d81c..f11c25cbe5 100644 --- a/doc/5.reference/soundfiler-help.pd +++ b/doc/5.reference/soundfiler-help.pd @@ -1,4 +1,4 @@ -#N canvas 206 180 1042 654 12; +#N canvas 193 60 1042 654 12; #X obj 60 320 soundfiler; #X floatatom 60 349 7 0 0 0 - - - 12; #X obj 391 608 tabwrite~; @@ -49,9 +49,7 @@ #X connect 2 0 3 0; #X connect 4 0 2 0; #X connect 5 0 1 0; -#X restore 747 392 pd Dealing_with_"\$0"; -#X text 577 255 Note that if no array name is given to read to \, no samples are read but you get the number of samples in the file on the left outlet and the info on the right outlet anyway., f 62; -#X text 577 443 Both 'read' and 'write' messages also take optional flags for configuration. In the basic example to the left we have the '-resize' flag in the read message that resizes the array to the file size. See more about flags and advanced examples in the subpatch below., f 62; +#X restore 752 421 pd Dealing_with_"\$0"; #X obj 6 576 cnv 1 1025 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 606 608 openpanel; #X obj 679 608 savepanel; @@ -63,43 +61,55 @@ #X array sample 88200 float 2; #X coords 0 1 88200 -1 250 100 1 0 0; #X restore 284 247 graph; -#X text 28 61 The [soundfiler] object loads files into arrays and also saves arrays into files. The soundfiles may contain uncompressed 2- or 3-byte integer ("pcm") or 4- or 8-byte floating point samples in wave \, aiff \, caf and next formats. Also \, [soundfiler] deals with ascii text files., f 72; -#X text 577 312 Also note that the number of channels is limited to 64 for both reading and writing., f 62; -#X text 580 365 Open subpatch to see how to deal with '\$0'; -#X text 799 602 updated for Pd version 0.55-0; -#X text 29 396 A 'read' message takes a filename and one or more arrays to load it into (when the file has more than one channel). The number of channels of the soundfile need not match the number of arrays given to read (extras channels are dropped and unsupplied channels are zeroed out in the extra arrays). The 'write' message takes a filename to save to and one or more arrays (one for each channel). Note that both 'read' and 'write' messages can expand "~" to the home directory., f 73; -#X text 29 499 Also note: Loading a soundfile into an array might be useful for more flexible playing strategies with table reading objects in the 'see section' below. For a simpler alternative that streams a soundfile directly from your hard drive \, see [readsf~]., f 73; +#X text 593 394 Open subpatch to see how to deal with '\$0'; #X msg 83 271 write ~/test.wav sample; -#X text 577 74 At loading or writting a file \, the left outlet outputs the number of samples and the right outlet sends information as a list \, namely: Sample Rate \, Header Size \, Number of Channels \, Bytes per Sample and Endianness ("b" for "big" or "l" for "little")., f 62; -#N canvas 189 207 1235 596 read-write-flags 0; -#X obj 629 464 soundfiler; -#X text 27 15 Flags for 'read' message:, f 73; -#X text 18 417 Flags for 'write' message:, f 69; -#X text 48 117 [soundfiler] can figure out which of the known soundfile formats the file belongs to or override all header and type information using the "-raw" flag \, which causes all header and type information to be ignored. Endianness is "l" ("little") for Intel machines or "b" ("big") for older PPC Macintoshes. You can give "n" (natural) to take the byte order your machine prefers., f 70; -#X text 27 204 -ascii (read a file containing ascii numbers), f 73; -#X text 48 221 This may only be combined with '-resize'. Newlines in the file are ignored \, non-numeric fields are replaced by zero. If multiple arrays are specified \, the first elements of each array should come first in the file \, followed by all the second elements and so on (interleaved)., f 70; -#X text 27 32 -wave \, -aiff \, -caf \, -next (soundfile format), f 73; -#X text 891 169 read from an ascii file; -#X listbox 696 522 17 0 0 0 - - - 0; -#X msg 612 138 read -resize -raw 128 2 2 b ../sound/bell.aiff array1 array2; -#X msg 638 192 read -ascii -resize table.txt array1 array2; -#X floatatom 629 522 6 0 0 0 - - - 0; -#X obj 573 58 openpanel; -#X obj 573 23 bng 23 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; -#X obj 657 301 savepanel; -#X obj 657 266 bng 23 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; -#X text 18 522 -rate (sample rate \, default Pd's running sample rate), f 71; -#X text 18 468 -skip (number of points to skip in array \, default 0), f 69; -#X text 27 49 -skip (sample frames to skip in the file as an offset), f 73; -#X text 27 100 -raw (header size \, channels \, bytes per sample \, endianness), f 73; -#X text 18 434 -wave \, -aiff \, -caf \, -next \, -ascii (soundfile format \, default: 'wave'), f 69; -#X text 18 451 -big \, -little (sample endianness \, default 'little'), f 69; -#X msg 657 329 write \$1 array1 array2; -#X msg 573 86 read -resize \$1 array1 array2; -#X msg 594 113 read -maxsize 44100 -aiff ../sound/bell.aiff array1 array2; -#X text 833 89 set max size and extension; -#X msg 629 169 read -ascii -resize table.txt array1; -#N canvas 683 221 473 479 more-writting-examples 0; +#N canvas 66 180 1200 556 read-write-flags 0; +#X obj 632 456 soundfiler; +#X text 25 13 Flags for 'read' message:, f 73; +#X text 16 380 Flags for 'write' message:, f 69; +#X text 46 215 [soundfiler] can figure out which of the known soundfile formats the file belongs to or override all header and type information using the "-raw" flag \, which causes all header and type information to be ignored. Endianness is "l" ("little") for Intel machines or "b" ("big") for older PPC Macintoshes. You can give "n" (natural) to take the byte order your machine prefers., f 70; +#X text 25 33 -wave \, -aiff \, -caf \, -next (soundfile format), f 73; +#X text 894 168 read from an ascii file; +#X listbox 699 494 17 0 0 0 - - - 0; +#X msg 615 141 read -resize -raw 128 2 2 b ../sound/bell.aiff array1 array2; +#X msg 641 196 read -ascii -resize table.txt array1 array2; +#X floatatom 632 494 6 0 0 0 - - - 0; +#X obj 572 49 openpanel; +#X obj 572 19 bng 23 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X obj 660 294 savepanel; +#X obj 660 259 bng 23 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X text 16 488 -rate (sample rate \, default Pd's running sample rate), f 71; +#X text 16 434 -skip (number of points to skip in array \, default 0), f 69; +#X text 25 50 -skip (sample frames to skip in the file as an offset), f 73; +#X text 25 193 -raw (header size \, channels \, bytes per sample \, endianness), f 73; +#X text 16 400 -wave \, -aiff \, -caf \, -next \, -ascii (soundfile format \, default: 'wave'), f 69; +#X text 16 417 -big \, -little (sample endianness \, default 'little'), f 69; +#X msg 572 78 read -resize \$1 array1 array2; +#X msg 632 168 read -ascii -resize table.txt array1; +#X text 686 261 Write a stereo fie; +#X obj 852 242 cnv 19 323 118 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; +#X obj 852 386 cnv 19 323 118 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; +#N canvas 0 22 450 300 (subpatch) 0; +#X array array1 87741 float 2; +#X coords 0 1 87741 -1 325 120 1 0 0; +#X restore 851 241 graph; +#N canvas 0 22 450 300 (subpatch) 0; +#X array array2 87741 float 2; +#X coords 0 1 87741 -1 325 120 1 0 0; +#X restore 851 385 graph; +#N canvas 460 493 480 224 8-byte 0; +#X text 19 62 The precision of the 8-byte samples is based on the precision of the Pure Data build. If Pd is single precision (using 32-bit float internally) \, the written samples will be cast from 4-byte float to 8-byte double when writing to a file with -bytes 8 argument. In this case it's better to write with 4-byte float samples for a smaller file with the same precision., f 63; +#X text 19 159 if Pd is double-precision \, writing 8-byte float samples will be full precision as Pd uses 64-bit float internally., f 63; +#X text 19 19 Writing 8-byte (ie. 64-bit) floating point samples are supported for the .wave \, .aiff/.aifc and .caf file types.; +#X restore 441 470 pd 8-byte float; +#X text 16 506 -normalize (normalize file to '1' \, note that arrays whose values exceed the -1 to 1 range are automatically normalized), f 71; +#X text 614 519 # samples; +#X text 699 520 info: sample rate \, header size \, channels \, bytes \, endianness; +#X text 1048 134 read overriding the file's header, f 17; +#X text 16 451 -nframes (maximum points to write \, default from skip point to end of array), f 83; +#X text 16 469 -bytes (bytes per sample: 2 \, 3 \, 4 \, or 8 default: 2); +#X text 599 20 Choose file to read from; +#N canvas 683 221 473 479 more-write-examples 0; #X obj 41 442 outlet; #X text 148 166 write a mono file and set number of samples, f 22; #X obj 69 177 savepanel; @@ -107,71 +117,62 @@ #X obj 41 69 savepanel; #X obj 41 34 bng 23 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; #X obj 99 278 bng 23 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; -#X text 120 29 Write a stereo file with a 2 byte resolution and in the 'next' format (so when typing into the savepannel dialog you should not set the file extension), f 47; #X msg 41 104 write -next -bytes 2 \$1 array1 array2; #X obj 99 319 savepanel; -#X text 130 273 write to an ascii file (you don't set the file extension to '.txt' because of the ascii flag), f 46; #X msg 99 355 write -nframes 3 -skip 2 -ascii \$1 array1; -#X msg 69 212 write -skip 22050 -nframes 44100 \$1 array1; -#X connect 2 0 12 0; +#X msg 69 212 write -skip 22050 -nframes 48000 \$1 array1; +#X text 120 29 write a stereo file with a 2 byte resolution and in the 'next' format (so when typing into the savepannel dialog you should not set the file extension), f 47; +#X text 130 273 write an ascii file ('.txt' extension is automatically added with the ascii flag), f 46; +#X connect 2 0 10 0; #X connect 3 0 2 0; -#X connect 4 0 8 0; +#X connect 4 0 7 0; #X connect 5 0 4 0; -#X connect 6 0 9 0; -#X connect 8 0 0 0; -#X connect 9 0 11 0; -#X connect 11 0 0 0; -#X connect 12 0 0 0; -#X restore 663 384 pd more-writting-examples; -#X text 683 268 Write a stereo fie; -#X text 605 24 Choose file to save to or read from in your hard disk; -#X obj 863 249 cnv 19 323 118 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; -#X obj 863 393 cnv 19 323 118 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; -#N canvas 0 22 450 300 (subpatch) 0; -#X array array1 78003 float 2; -#X coords 0 1 78003 -1 325 120 1 0 0; -#X restore 862 248 graph; -#N canvas 0 22 450 300 (subpatch) 0; -#X array array2 78003 float 2; -#X coords 0 1 78003 -1 325 120 1 0 0; -#X restore 862 392 graph; -#N canvas 460 493 480 224 8-byte 0; -#X text 19 62 The precision of the 8-byte samples is based on the precision of the Pure Data build. If Pd is single precision (using 32-bit float internally) \, the written samples will be cast from 4-byte float to 8-byte double when writing to a file with -bytes 8 argument. In this case it's better to write with 4-byte float samples for a smaller file with the same precision., f 63; -#X text 19 159 if Pd is double-precision \, writing 8-byte float samples will be full precision as Pd uses 64-bit float internally., f 63; -#X text 19 19 Writing 8-byte (ie. 64-bit) floating point samples are supported for the .wave \, .aiff/.aifc and .caf file types.; -#X restore 440 503 pd 8-byte float; -#X text 18 540 -normalize (normalize file to '1' \, note that arrays whose values exceed the -1 to 1 range are automatically normalized), f 71; -#X text 611 547 # samples; -#X text 696 548 info: sample rate \, header size \, channels \, bytes \, endianness; -#X text 27 83 -maxsize (maximum number of samples to resize to *), f 73; -#X text 27 66 -resize (resizes arrays to the size of the sound file *), f 73; -#X text 1043 131 read overriding the file's header, f 17; -#X text 17 288 * When loading a file \, [soundfiler] populates the array until reaching its size. If the sound file is smaller \, the remaining points are zeroed out. The -resize flag resizes the array to the sample size \, while the -maxsize flag sets a maximum size to clip to even if used in conjunction with the '-resize' flag (also \, errors are given to warn you about the truncation). The -maxsize was needed for historical reasons when its default value used to be rather small (4 million). The default now is much bigger \, hence \, this flag can just be ignored., f 78; -#X text 18 485 -nframes (maximum points to write \, default from skip point to end of array), f 83; -#X text 18 503 -bytes (bytes per sample: 2 \, 3 \, 4 \, or 8 default: 2); -#X connect 0 0 11 0; -#X connect 0 1 8 0; +#X connect 6 0 8 0; +#X connect 7 0 0 0; +#X connect 8 0 9 0; #X connect 9 0 0 0; #X connect 10 0 0 0; -#X connect 12 0 23 0; +#X restore 666 377 pd more-write-examples; +#X text 25 302 -ascii (read a file containing ascii numbers), f 73; +#X text 46 319 This may only be combined with '-resize'. Spaces or newlines are valid separators. Non-numeric fields get replaced by zero. For multiple arrays \, data should be interleaved (first elements of each array \, then second elements \, etc). The file must only contain ASCII characters., f 70; +#X text 25 68 -resize (resizes arrays to the sound file's size \, otherwise the extra samples are zeroed out or the array is filled until reaching its size), f 73; +#X text 25 101 -maxsize (Deprecated *) (maximum number of samples to resize to), f 73; +#X text 46 120 * Historically \, the default maximum size used to be only 4 million samples \, so this was needed to increase it and allow loading larger files with -resize. This isn't needed anymore as the current default value is as high as your system can handle., f 70; +#X msg 660 322 write \$1 array1 array2; +#X msg 595 110 read -resize ../sound/stereo.wav array1 array2; +#X connect 0 0 9 0; +#X connect 0 1 6 0; +#X connect 7 0 0 0; +#X connect 8 0 0 0; +#X connect 10 0 20 0; +#X connect 11 0 10 0; +#X connect 12 0 41 0; #X connect 13 0 12 0; -#X connect 14 0 22 0; -#X connect 15 0 14 0; -#X connect 22 0 0 0; -#X connect 23 0 0 0; -#X connect 24 0 0 0; -#X connect 26 0 0 0; -#X connect 27 0 0 0; -#X restore 784 529 pd read-write-flags; -#X text 577 157 When loading a file \, the left outlet sends the number of samples the file contains if the array is equal or greater in size. If you're loading a file that is bigger than the array size \, the number or samples gets clipped to the array size (you probably want to use the -resize flag in this case to automatically resize the array size to the file size)., f 62; +#X connect 20 0 0 0; +#X connect 21 0 0 0; +#X connect 35 0 0 0; +#X connect 41 0 0 0; +#X connect 42 0 0 0; +#X restore 753 533 pd read-write-flags; #X text 120 13 - import/export sound or ascii files to/from arrays; #N canvas 0 22 450 278 (subpatch) 0; #X array array_x 10 float 3; #A 0 0 0 0 0 0 0 0 0 0 0; #X coords 0 1 10 -1 90 40 1 0 0; #X restore 116 598 graph; +#X text 28 61 The [soundfiler] object loads files into arrays and also saves arrays into files. The soundfiles may contain uncompressed 2- or 3-byte integer ("pcm") or 4- or 8-byte floating point samples in wave \, aiff \, caf and next formats. [soundfiler] can also handle ascii text files., f 72; +#X text 579 462 'read' and 'write' messages both support optional flags. In the basic example on the left \, we have the '-resize' flag in the read message that resizes the array to the file size. See more about flags and advanced examples in the subpatch below., f 62; +#X text 29 396 A 'read' message takes a filename and one or more arrays to load it into (when the file has more than one channel). The number of channels of the soundfile need not match the number of arrays given to read (extras channels are dropped and unsupplied channels are zeroed out in the extra arrays)., f 73; +#X text 30 476 The 'write' message takes a filename to save to and one or more arrays (one for each channel)., f 73; +#X text 578 62 Also note: Loading a soundfile into an array might be useful for more flexible playing strategies with table reading objects in the 'see also' section below. For a simpler alternative that streams a soundfile directly from your hard drive \, see [readsf~]., f 62; +#X text 30 516 Note that both 'read' and 'write' messages can expand "~" to the home directory., f 73; +#X text 579 140 When loading or writing a file \, the left outlet outputs the file's number of samples. If you're loading a file that is bigger than the array size \, the number or samples gets clipped to the array size (you probably want to use the -resize flag in this case to automatically resize the array size to the file size)., f 62; +#X text 579 234 The right outlet sends information as a list \, namely: Sample Rate \, Header Size \, Number of Channels \, Bytes per Sample and Endianness: "b" (for "big") or "l" (for "little")., f 62; +#X text 579 289 If no array name is given to read to \, no samples are read but you get the number of samples in the file on the left outlet and the files' info on the right outlet anyway., f 62; +#X text 579 346 Important: The number of channels is limited to 64 for both reading and writing., f 62; +#X text 823 607 updated for Pd version 0.56; #X connect 0 0 1 0; #X connect 0 1 11 0; #X connect 15 0 0 0; #X connect 16 0 0 0; -#X connect 36 0 0 0; +#X connect 29 0 0 0; diff --git a/doc/5.reference/struct-help.pd b/doc/5.reference/struct-help.pd index 5b943cce7c..1fe5da24ab 100644 --- a/doc/5.reference/struct-help.pd +++ b/doc/5.reference/struct-help.pd @@ -6,39 +6,39 @@ #N canvas 570 245 463 166 help-template2 0; #X obj 120 26 struct struct-2 float y; #X text 26 74 Here is one which specifies only the floating point "y". It's used for the elements of the array shown in the other template.; -#X restore 325 217 pd help-template2; -#X text 381 322 updated for Pd version 0.35; +#X restore 326 217 pd help-template2; #X obj 24 15 struct; -#X text 21 322 see also:; -#X obj 95 323 drawpolygon; -#X obj 186 323 drawtext; -#X obj 256 323 plot; +#X text 23 322 see also:; +#X obj 97 323 drawpolygon; +#X obj 188 323 drawtext; +#X obj 258 323 plot; #X obj 6 47 cnv 1 590 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 6 303 cnv 1 590 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#N canvas 747 80 625 351 reference 0; +#N canvas 550 145 625 344 reference 0; #X obj 8 52 cnv 5 600 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; #X obj 8 164 cnv 2 600 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; #X obj 8 237 cnv 2 600 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; -#X obj 7 314 cnv 5 600 5 empty empty empty 8 18 0 13 #202020 #000000 0; -#X text 91 261 1) list -; +#X obj 7 320 cnv 5 600 5 empty empty empty 8 18 0 13 #202020 #000000 0; +#X text 87 261 1) list -; #X text 84 177 anything -; #X text 167 176 messages notifying when there are interactions with objects of the structure ('select' \, 'deselect' \, 'click' \, 'displace' and 'change').; #X obj 29 16 struct x; #X text 98 17 - define a data structure template.; -#X text 165 261 template name plus types and names of given fields. (Array fields also need the array's template name. They may also have a third float argument to initialize array size).; -#X text 84 71 add [name value]... -; -#X text 312 69 add a scalar for this template to the named window (prefixed with 'pd' as in 'pd-data') \, optionally initializing float or symbol fields as in 'x 10 y 50'., f 41; +#X text 161 261 template name plus types and names of given fields. (Array fields also need the array's template name. They may also have a third float argument to initialize array size).; +#X text 41 84 add [name value]... -; +#X text 269 82 add a scalar for this template to the named window (prefixed with 'pd' as in 'pd-data') \, optionally initializing float or symbol fields as in 'x 10 y 50'., f 44; #X restore 491 16 pd reference; #X text 426 16 click =>; -#X obj 297 323 text; -#X text 97 205 open subpatch for examples -->; -#X obj 209 350 get; -#X obj 241 350 set; -#X obj 88 350 getsize; -#X obj 149 350 setsize; -#X obj 326 350 element; -#X obj 274 350 scalar; -#X obj 24 350 pointer; +#X obj 299 323 text; +#X text 97 204 open subpatch for examples -->; +#X obj 197 350 get; +#X obj 229 350 set; +#X obj 76 350 getsize; +#X obj 137 350 setsize; +#X obj 314 350 element; +#X obj 262 350 scalar; +#X obj 15 350 pointer; #X text 83 16 - define a data structure template; #X text 52 254 NOTE: In early days \, the [template] object was used instead of [struct] \, but it is now deprecated and you should use [struct] instead., f 72; #X text 48 64 A [struct] object is used to define a Data Structure template and its fields. There should be one [struct] object in each Pd window you are using as a data structure template. The arguments specify the types and names of the fields. The data types are: "float" \, "symbol" \, "text" and "array". Each type needs a field name. Array fields take an extra argument that specifies the template that the array elements should belong to \, and an optional float arqument to initialize the number of elements., f 71; +#X text 389 321 updated for Pd version 0.56; diff --git a/doc/5.reference/tabplay~-help.pd b/doc/5.reference/tabplay~-help.pd index 18b59973fd..2d064f52dc 100644 --- a/doc/5.reference/tabplay~-help.pd +++ b/doc/5.reference/tabplay~-help.pd @@ -6,13 +6,13 @@ #X obj 574 139 soundfiler; #X obj 177 454 soundfiler; #X obj 325 454 tabread4~; -#X msg 90 226 0 44100; -#X msg 84 201 44100; +#X msg 90 226 0 48000; +#X msg 84 201 48000; #X text 101 176 "bang" or 0 plays whole sample; -#X text 131 200 play starting at 44100th sample; -#X text 148 224 play starting at beginning for 44100 samples; -#X msg 95 251 44100 1000; -#X text 173 250 play from 44100 through 45099 (1000 samples); +#X text 131 200 play starting at 48000th sample; +#X text 148 224 play starting at beginning for 48000 samples; +#X msg 95 251 48000 1000; +#X text 173 250 play from 48000 through 45099 (1000 samples); #X text 654 454 updated for Pd version 0.43; #X msg 102 276 stop; #X text 138 277 stop playing (outputs zeros when stopped); diff --git a/doc/5.reference/tabread4~-help.pd b/doc/5.reference/tabread4~-help.pd index 734922c4fd..644553790b 100644 --- a/doc/5.reference/tabread4~-help.pd +++ b/doc/5.reference/tabread4~-help.pd @@ -101,51 +101,42 @@ #X msg 457 244 \; pd dsp \$1; #X obj 457 209 set-dsp-tgl; #X text 374 212 DSP on/off; -#N canvas 749 203 563 414 multichannel 0; -#X obj 68 270 snake~ out, f 12; -#X obj 69 151 sig~; -#X floatatom 69 125 6 0 10 0 - - - 0; -#X obj 68 347 snapshot~; -#X floatatom 68 376 8 0 0 0 - - - 0; -#X obj 89 304 r bang; -#X obj 149 347 snapshot~; -#X floatatom 149 376 8 0 0 0 - - - 0; -#X msg 117 150 set array99 array100; -#X msg 130 181 set array100 array99; -#X obj 68 222 tabread4~ array99 array100; -#X text 51 12 [tabread4~] generates multichannel signals if you give it more than one argument. Each channel then corresponds to an argument/table. The "set" message can also replace more than one table name. Note that the arrays do not need to be of the same length., f 67; -#X obj 72 96 hsl 162 19 0 10 0 0 empty empty empty -2 -8 0 10 #dfdfdf #000000 #000000 0 1; -#X obj 310 150 cnv 19 198 98 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; -#X obj 310 276 cnv 19 198 98 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; +#N canvas 660 239 563 414 multichannel 0; +#X obj 57 169 sig~; +#X floatatom 57 143 6 0 10 0 - - - 0; +#X obj 56 324 snapshot~; +#X obj 77 282 r bang; +#X msg 105 168 set array99 array100; +#X msg 118 199 set array100 array99; +#X obj 56 240 tabread4~ array99 array100; +#X text 49 20 [tabread4~] generates multichannel signals if you give it more than one argument. Each channel then corresponds to an argument/table. The "set" message can also replace more than one table name. Note that the arrays do not need to be of the same length., f 67; +#X obj 60 114 hsl 162 19 0 10 0 0 empty empty empty -2 -8 0 10 #dfdfdf #000000 #000000 0 1; +#X obj 308 158 cnv 19 198 98 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; +#X obj 308 284 cnv 19 198 98 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; #N canvas 0 22 450 300 (subpatch) 0; #X array array99 10 float 3; #A 0 2.824 1.366 3.094 1.636 0.610006 4.552 1.906 0.826005 3.364 1.96001; #X coords 0 5.2 10 -0.2 200 100 1 0 0; -#X restore 310 149 graph; +#X restore 308 157 graph; #N canvas 0 22 450 300 (subpatch) 0; #X array array100 10 float 3; #A 0 0.502 0.771999 1.096 1.582 2.122 2.662 3.20199 3.57999 3.95799 4.44399; #X coords 0 5.2 10 -0.2 200 100 1 0 0; -#X restore 309 276 graph; -#X connect 0 0 3 0; -#X connect 0 1 6 0; -#X connect 1 0 10 0; -#X connect 2 0 1 0; -#X connect 3 0 4 0; -#X connect 5 0 3 0; +#X restore 307 284 graph; +#X listbox 56 359 18 0 0 0 - - - 0; +#X connect 0 0 6 0; +#X connect 1 0 0 0; +#X connect 2 0 13 0; +#X connect 3 0 2 0; +#X connect 4 0 6 0; #X connect 5 0 6 0; -#X connect 6 0 7 0; -#X connect 8 0 10 0; -#X connect 9 0 10 0; -#X connect 10 0 0 0; -#X connect 12 0 2 0; -#X restore 697 364 pd multichannel; -#X text 546 349 mutichannel signal support ----------->, f 20; +#X connect 6 0 2 0; +#X connect 8 0 1 0; +#X restore 681 367 pd multichannel; #X obj 128 402 metro 200; #X obj 128 375 loadbang; #X obj 128 430 s bang; #X obj 56 378 r bang; -#X text 89 147 incoming signal is index. Indices should range from 1 to (size-2) so that the 4-point interpolation is meaningful (from 1 to 8 in this example)., f 52; #X text 212 255 set table onset to improve the accuracy of indexing (useful if you have Pd compiled for single precision), f 31; #X text 157 210 "set" message lets you switch between arrays, f 22; #X text 102 260 onset ->; @@ -260,15 +251,17 @@ #X text 335 423 -->; #X text 572 409 open for player --> examples, f 10; #X obj 229 487 tabread4; +#X text 91 146 The incoming signal is the index \, which is clipped to and must be in the range from 1 to (size-2) so that the 4-point interpolation is meaningful (from 1 to 8 in this example)., f 56; +#X text 546 349 mutichannel signal support -------->, f 18; #X connect 0 0 3 0; #X connect 1 0 14 0; #X connect 2 0 1 0; -#X connect 9 0 41 0; +#X connect 9 0 39 0; #X connect 14 0 0 0; #X connect 15 0 14 0; #X connect 18 0 2 0; #X connect 27 0 26 0; -#X connect 31 0 33 0; -#X connect 32 0 31 0; -#X connect 34 0 0 0; -#X connect 41 0 14 1; +#X connect 30 0 32 0; +#X connect 31 0 30 0; +#X connect 33 0 0 0; +#X connect 39 0 14 1; diff --git a/doc/5.reference/tabread~-help.pd b/doc/5.reference/tabread~-help.pd index 5cdc4b28d9..6c10574623 100644 --- a/doc/5.reference/tabread~-help.pd +++ b/doc/5.reference/tabread~-help.pd @@ -1,4 +1,4 @@ -#N canvas 375 23 813 491 12; +#N canvas 359 58 813 491 12; #X obj 31 347 snapshot~; #X obj 31 149 sig~; #X floatatom 31 123 6 0 10 0 - - - 0; @@ -53,8 +53,8 @@ #X connect 11 0 13 0; #X connect 12 0 11 0; #X connect 14 0 12 0; -#X restore 619 366 pd Dealing_with_"\$0"; -#X text 613 332 open subpatch to see how to deal with '\$0', f 22; +#X restore 631 366 pd Dealing_with_"\$0"; +#X text 625 332 open subpatch to see how to deal with '\$0', f 22; #N canvas 698 164 581 232 reference 0; #X obj 18 52 cnv 5 550 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; #X obj 18 118 cnv 2 550 2 empty empty OUTLET: 8 12 0 13 #202020 #000000 0; @@ -99,19 +99,27 @@ #X msg 224 334 \; pd dsp \$1; #X obj 224 299 set-dsp-tgl; #X text 255 303 DSP on/off; +#X obj 125 319 metro 200; +#X obj 125 291 loadbang; +#X obj 125 350 s bang; +#X obj 53 304 r bang; +#X text 591 445 updated for Pd version 0.54; +#X text 55 67 [tabread~] looks up values from named arrays. Incoming values are truncated to the next lower integer \, and values out of bounds get the nearest (first or last) point., f 87; +#X obj 466 148 cnv 19 298 148 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; +#N canvas 0 22 450 300 (subpatch) 0; +#X array tabread-ex 10 float 2; +#X coords 0 5.2 10 -0.2 300 150 1 0 0; +#X restore 465 147 graph; +#X text 359 339 mutichannel signal support ------>, f 20; #N canvas 685 183 564 407 multichannel 0; -#X obj 68 257 snake~ out, f 12; -#X obj 69 138 sig~; -#X floatatom 69 112 6 0 10 0 - - - 0; -#X obj 68 212 tabread~ array77 array88; -#X msg 124 137 set array77 array88; -#X msg 137 168 set array88 array77; -#X obj 68 334 snapshot~; -#X floatatom 68 363 8 0 0 0 - - - 0; -#X obj 89 291 r bang; -#X obj 149 334 snapshot~; -#X floatatom 149 363 8 0 0 0 - - - 0; -#X text 51 21 [tabread~] generates multichannel signals if you give it more than one argument. Each channel then corresponds to an argument/table. The "set" message can also replace more than one table name. Note that the arrays do not need to be of the same length., f 66; +#X obj 62 145 sig~; +#X floatatom 62 119 6 0 10 0 - - - 0; +#X obj 61 219 tabread~ array77 array88; +#X msg 117 144 set array77 array88; +#X msg 130 175 set array88 array77; +#X obj 61 302 snapshot~; +#X obj 82 264 r bang; +#X text 61 21 [tabread~] generates multichannel signals if you give it more than one argument. Each channel then corresponds to an argument/table. The "set" message can also replace more than one table name. Note that the arrays do not need to be of the same length., f 66; #X obj 311 137 cnv 19 198 98 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; #X obj 310 264 cnv 19 198 98 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; #N canvas 0 22 450 300 (subpatch) 0; @@ -124,36 +132,21 @@ #A 0 0.502 0.771999 1.096 1.582 2.122 2.662 3.20199 3.57999 3.95799 4.44399; #X coords 0 5.2 10 -0.2 200 100 1 0 0; #X restore 309 263 graph; -#X connect 0 0 6 0; -#X connect 0 1 9 0; -#X connect 1 0 3 0; -#X connect 2 0 1 0; -#X connect 3 0 0 0; -#X connect 4 0 3 0; -#X connect 5 0 3 0; -#X connect 6 0 7 0; -#X connect 8 0 6 0; -#X connect 8 0 9 0; -#X connect 9 0 10 0; -#X restore 486 356 pd multichannel; -#X text 335 341 mutichannel signal support ----------->, f 20; -#X obj 125 319 metro 200; -#X obj 125 291 loadbang; -#X obj 125 350 s bang; -#X obj 53 304 r bang; -#X text 591 445 updated for Pd version 0.54; -#X text 55 67 [tabread~] looks up values from named arrays. Incoming values are truncated to the next lower integer \, and values out of bounds get the nearest (first or last) point., f 87; -#X obj 466 148 cnv 19 298 148 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; -#N canvas 0 22 450 300 (subpatch) 0; -#X array tabread-ex 10 float 2; -#X coords 0 5.2 10 -0.2 300 150 1 0 0; -#X restore 465 147 graph; +#X listbox 61 341 16 0 0 0 - - - 0; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X connect 2 0 5 0; +#X connect 3 0 2 0; +#X connect 4 0 2 0; +#X connect 5 0 12 0; +#X connect 6 0 5 0; +#X restore 478 363 pd multichannel; #X connect 0 0 3 0; #X connect 1 0 18 0; #X connect 2 0 1 0; #X connect 17 0 18 0; #X connect 18 0 0 0; #X connect 29 0 28 0; -#X connect 33 0 35 0; -#X connect 34 0 33 0; -#X connect 36 0 0 0; +#X connect 31 0 33 0; +#X connect 32 0 31 0; +#X connect 34 0 0 0; diff --git a/doc/5.reference/text-help.pd b/doc/5.reference/text-help.pd index 7ad4f269a9..cc33527394 100644 --- a/doc/5.reference/text-help.pd +++ b/doc/5.reference/text-help.pd @@ -1,8 +1,8 @@ -#N canvas 624 123 485 238 12; +#N canvas 589 61 485 286 12; #X text 32 16 comment; -#X text 273 201 updated for Pd version 0.52; +#X text 273 251 updated for Pd version 0.52; #X obj 3 44 cnv 1 475 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 3 186 cnv 1 475 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X obj 3 236 cnv 1 475 1 empty empty empty 8 12 0 13 #000000 #000000 0; #N canvas 879 173 375 183 reference 0; #X obj 8 45 cnv 5 350 5 empty empty INLETS: 8 18 0 13 #202020 #000000 0; #X obj 8 87 cnv 2 350 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; @@ -17,3 +17,6 @@ #X text 402 16 <= click; #X text 16 60 This is Pd's help window for comments \, which don't do anything \, have no inlet/outlets or arguments. As other objects in Pd \, you can resize the line length by adjusting the size in edit mode. If you use semicolons \; lines \; get \; broken., f 63; #X text 100 16 - write text for comments; +#X text 13 252 see also:; +#X obj 90 252 makefilename; +#X text 16 172 Note that floats are parsed not as symbols are represented with the '%g' format and its default precision \, check the help file of [makefilename] for details on how that works., f 63; diff --git a/doc/5.reference/text-object-help.pd b/doc/5.reference/text-object-help.pd index ca1907baea..5934ca4aea 100644 --- a/doc/5.reference/text-object-help.pd +++ b/doc/5.reference/text-object-help.pd @@ -1,5 +1,5 @@ #N struct text-struct float x float y text z; -#N canvas 802 50 541 585 12; +#N canvas 472 81 541 585 12; #X obj 92 552 list; #X obj 29 16 text; #X text 15 552 see also:; @@ -490,7 +490,6 @@ #X text 597 53 If the search pattern (the incoming list) has more elements than we have specified search elements \, extra search patterns match succeeding elements starting from the last one give as an argument. So for example if there are no arguments we look for matches to any number of elements starting from the beginning of the message in the text., f 42; #X text 531 407 Here we ask for element 2 to equal 3 and elements starting at 0 to be 'near' the following arguments., f 41; #X text 562 488 element 2 is 3 and element 0 nearest 3; -#X text 605 516 here messages 0 and 2 tie over 2.4 (1 and 4 are equally far from it) so message 0 whose second element is closer to 1 wins., f 42; #X text 607 578 Here message 2 wins because its element 0 is nearer to 3 \, notwithstanding that its element 1 is farther from 1, f 40; #X text 215 359 here we ask to match both element 0 and 3 exactly. In element 3 we're testing symbols for equality., f 50; #X obj 112 653 text search text-search > 0, f 33; @@ -498,6 +497,7 @@ #X msg 20 587 range 2 3; #X text 24 536 narrow between 2 and 4, f 7; #X text 13 457 Match a message for which the search key is greater than the element zero of that message. The message getting closest to the key wins. You can also use the 'range' message to narrow the search \, which takes an offset and number of messages., f 68; +#X text 605 516 here messages 0 and 2 tie over 2.5 (1 and 4 are equally far from it) so message 0 whose second element is closer to 1 wins., f 42; #X connect 4 0 0 0; #X connect 5 0 4 1; #X connect 6 0 4 0; @@ -515,15 +515,15 @@ #X connect 20 0 18 0; #X connect 21 0 18 0; #X connect 22 0 18 0; -#X connect 24 0 54 0; -#X connect 25 0 54 0; -#X connect 26 0 54 0; +#X connect 24 0 53 0; +#X connect 25 0 53 0; +#X connect 26 0 53 0; #X connect 27 0 28 0; #X connect 29 0 27 0; #X connect 30 0 27 0; #X connect 31 0 27 0; -#X connect 54 0 23 0; -#X connect 56 0 54 0; +#X connect 53 0 23 0; +#X connect 55 0 53 0; #X restore 354 411 pd search; #X text 58 435 sequencer/message-sender; #X obj 242 435 text sequence; @@ -826,7 +826,7 @@ #X connect 23 0 21 0; #X connect 24 0 3 0; #X restore 354 290 pd insert; -#N canvas 888 354 766 438 text-and-data-structures 1; +#N canvas 704 354 766 438 text-and-data-structures 0; #X floatatom 82 189 5 0 0 0 - - - 0; #X msg 47 158 0; #X msg 122 158 2; @@ -842,7 +842,7 @@ #X text 77 29 fields 'x/y' for coordinates and 'z' for text; #X obj 68 224 drawpolygon 0 4 0 -10 0 55 140 55 140 -10 0 -10; #X restore 463 58 pd text-struct; -#N canvas 598 439 226 165 text-data 1; +#N canvas 598 439 226 165 text-data 0; #X scalar text-struct 20 20 \; 10 20 300 \\\; a b c d \\\; 100 200 292 \\\; \;; #X text 13 86 We have one datum (above) whose "z" field is text., f 25; #X restore 462 30 pd text-data; diff --git a/doc/5.reference/throw~-catch~-help.pd b/doc/5.reference/throw~-catch~-help.pd index a0d272e244..61d9f08732 100644 --- a/doc/5.reference/throw~-catch~-help.pd +++ b/doc/5.reference/throw~-catch~-help.pd @@ -1,12 +1,12 @@ -#N canvas 476 32 518 614 12; +#N canvas 476 34 518 632 12; #X floatatom 126 477 5 0 0 0 - - - 0; #X obj 126 447 snapshot~; #X obj 34 15 throw~; #X obj 34 39 catch~; #X obj 38 392 metro 200; #X obj 230 447 snapshot~; -#X obj 100 584 send~; -#X text 27 583 see also:; +#X obj 100 596 send~; +#X text 27 595 see also:; #X floatatom 230 477 5 0 0 0 - - - 0; #X obj 38 364 loadbang; #X msg 379 384 \; pd dsp 1; @@ -20,7 +20,7 @@ #N canvas 525 216 510 156 execution-order 0; #X obj 115 95 ../3.audio.examples/G05.execution.order; #X text 46 30 You have to get the throw~ sorted before the catch~ or else you'll never get less than a block's delay. You can use the strategy given in the example below to control this.; -#X restore 346 455 pd execution-order; +#X restore 346 445 pd execution-order; #N canvas 611 127 576 445 reference 0; #X obj 8 53 cnv 5 550 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; #X obj 8 114 cnv 2 550 2 empty empty OUTLETS: 8 12 0 13 #202020 #000000 0; @@ -47,44 +47,41 @@ #X restore 329 26 pd reference; #X text 426 27 <= click; #X obj 4 68 cnv 1 510 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 4 568 cnv 1 510 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X obj 146 584 tabsend~; +#X obj 4 580 cnv 1 510 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X obj 146 596 tabsend~; #X text 324 238 You can redirect [throw~] via a "set" message., f 16; #X text 268 189 <- \$0 needs to be expanded from objects., f 23; -#N canvas 680 88 505 390 multichannel 0; -#X obj 304 247 metro 200; -#X obj 193 284 snapshot~; -#X floatatom 193 314 5 0 0 0 - - - 0; -#X obj 304 219 loadbang; -#X obj 273 284 snapshot~; -#X floatatom 273 314 5 0 0 0 - - - 0; -#X floatatom 44 208 5 0 0 0 - - - 0; -#X floatatom 118 207 5 0 0 0 - - - 0; +#N canvas 680 88 505 417 multichannel 0; +#X obj 247 251 metro 200; +#X obj 214 289 snapshot~; +#X obj 247 223 loadbang; +#X floatatom 49 190 5 0 0 0 - - - 0; +#X floatatom 130 189 5 0 0 0 - - - 0; #X text 47 11 A [catch~] object may be directed to output multichannel signals via its second optional argument. A [throw~] object automatically uses as many channels as its input signal provides. If the matching [catch~] has fewer channels than that the extras are ignored. If the [throw~] object has fewer than the catch the extra output channels are left unchanged.; -#X obj 44 244 snake~ in 2; -#X obj 192 223 snake~ out 2; -#X text 274 354 see also:; -#X obj 352 355 snake~; -#X obj 410 355 clone; -#X msg 192 129 channels 1; -#X msg 206 158 channels 2; -#X text 298 130 message to set number of channels, f 18; -#X obj 44 282 throw~ bus3; -#X obj 192 187 catch~ bus3 2; +#X text 267 371 see also:; +#X obj 345 372 snake~; +#X obj 403 372 clone; +#X msg 213 134 channels 1; +#X msg 227 163 channels 2; +#X text 319 135 message to set number of channels, f 18; +#X obj 49 264 throw~ bus3; +#X obj 213 192 catch~ bus3 2; +#X obj 49 226 sig~ 1.1 2.2; +#X listbox 214 323 14 0 0 0 - - - 0; +#X msg 369 257 \; pd dsp 1; +#X text 401 224 DSP on/off; +#X obj 369 219 set-dsp-tgl; #X connect 0 0 1 0; -#X connect 0 0 4 0; -#X connect 1 0 2 0; -#X connect 3 0 0 0; -#X connect 4 0 5 0; -#X connect 6 0 9 0; -#X connect 7 0 9 1; -#X connect 9 0 17 0; -#X connect 10 0 1 0; -#X connect 10 1 4 0; -#X connect 14 0 18 0; -#X connect 15 0 18 0; -#X connect 18 0 10 0; -#X restore 346 481 pd multichannel; +#X connect 1 0 15 0; +#X connect 2 0 0 0; +#X connect 3 0 14 0; +#X connect 4 0 14 1; +#X connect 9 0 13 0; +#X connect 10 0 13 0; +#X connect 13 0 1 0; +#X connect 14 0 12 0; +#X connect 18 0 16 0; +#X restore 346 471 pd multichannel; #X obj 379 346 set-dsp-tgl; #X msg 230 242 set \$1-bus2; #X msg 242 272 set bus1; @@ -94,10 +91,10 @@ #X obj 230 333 throw~ bus1; #X obj 160 246 sig~ 25; #X obj 62 251 sig~ 50; -#X text 277 583 updated for Pd version 0.55-0; +#X text 277 595 updated for Pd version 0.55-0; #X msg 257 302 set; #X text 290 303 unset; -#X text 66 511 A pair of [throw~]/[catch~] objects must have matching block sizes \, but they may be in different windows or even different patches., f 54; +#X text 66 518 A pair of [throw~]/[catch~] objects must have matching block sizes \, but they may be in different windows or even different patches., f 54; #X text 38 81 A [throw~] object copies its input to a local buffer which a [catch~] object of the same name reads from. Any number of [throw~] objects can add into one [catch~] object (but two [catch~] objects cannot share the same name). The [throw~] object takes "set" messages with address names to switch between different [catch~] objects (just 'set' unsets the object).; #X connect 1 0 0 0; #X connect 4 0 1 0; diff --git a/doc/5.reference/timer-help.pd b/doc/5.reference/timer-help.pd index 6bd97638d1..b6404d8272 100644 --- a/doc/5.reference/timer-help.pd +++ b/doc/5.reference/timer-help.pd @@ -26,7 +26,7 @@ #X text 127 354 output elapsed time. You can click multiple times since it was last reset., f 25; #X obj 183 593 text sequence; #X text 111 412 elapsed time in the specified time units, f 20; -#X text 39 476 Note you need to reset the elapsed time to zero when you change the tempo message when the object is runnng \, otherwise you get funny results because the change takes effect immediately and gets applied to the remaining part of the elapsed time., f 75; +#X text 39 476 Note you need to reset the elapsed time to zero when you change the tempo message when the object is running \, otherwise you get funny results because the change takes effect immediately and gets applied to the remaining part of the elapsed time., f 75; #N canvas 700 98 489 311 reference 0; #X obj 18 52 cnv 5 450 5 empty empty INLET: 8 18 0 13 #202020 #000000 0; #X obj 18 229 cnv 2 450 2 empty empty ARGUMENTS: 8 12 0 13 #202020 #000000 0; diff --git a/doc/5.reference/trigonometric-help.pd b/doc/5.reference/trigonometric-help.pd index 1e5039b8a0..5559626d14 100644 --- a/doc/5.reference/trigonometric-help.pd +++ b/doc/5.reference/trigonometric-help.pd @@ -1,4 +1,4 @@ -#N canvas 364 23 593 484 12; +#N canvas 496 86 593 484 12; #X floatatom 159 250 4 0 0 0 - - - 0; #X floatatom 122 341 8 0 0 0 - - - 0; #X floatatom 122 250 4 0 0 0 - - - 0; @@ -50,20 +50,19 @@ #X text 97 418 float -; #X text 109 170 float - input value to the function and output result.; #X text 110 533 1) float -; -#X text 155 457 right side input ('y' coordinate)., f 56; -#X text 153 418 left side input ('x' coordinate)., f 56; #X text 188 533 initialize right inlet (default 0).; #X text 23 16 Trigonometric functions:; #X text 71 47 - calculate sine (input in radians)., f 66; #X text 71 70 - calculate cosine (input in radians)., f 66; #X text 71 93 - calculate tangent (input in radians)., f 66; #X text 71 117 - calculate arc-tangent (input in radians)., f 66; -#X text 71 328 - calculate arc-tangent from coordinate pairs (x \, y)., f 66; +#X text 155 457 right side input ('x' coordinate)., f 56; +#X text 153 418 left side input ('y' coordinate)., f 56; +#X text 71 328 - calculate arc-tangent from coordinate pairs (y \, x)., f 66; #X restore 419 21 pd reference; #X text 517 20 <= click; #X obj 6 56 cnv 1 585 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 6 395 cnv 1 585 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X text 238 267 The arc tangent ([atan]) takes two forms. The [atan2] version takes a coordinate pair (x \, y) and gives you an an angle in radians between -pi and pi. It also takes a bang message in the left inlet to evaluate the operation with the previously set values., f 47; #X text 396 115 <-- convert to radians, f 11; #X text 374 444 updated for Pd version 0.54; #X text 198 20 - trigonometric functions; @@ -73,6 +72,9 @@ #X text 398 409 (etc.) - binary operators; #X text 50 443 (etc.) - other binary operators; #X text 359 85 <-- degrees; +#X text 129 226 Y; +#X text 167 226 X; +#X text 234 262 The arc tangent ([atan]) takes two forms. The [atan2] version takes a coordinate pair (y-vertical / x-horizontal) and gives you an angle in radians between -pi and pi. It also takes a bang message in the left inlet to evaluate the operation with the values that were previously set., f 43; #X connect 0 0 15 0; #X connect 2 0 23 0; #X connect 4 0 14 0; diff --git a/doc/5.reference/unops-tilde-help.pd b/doc/5.reference/unops-tilde-help.pd index e7d357a471..650070ce9b 100644 --- a/doc/5.reference/unops-tilde-help.pd +++ b/doc/5.reference/unops-tilde-help.pd @@ -1,4 +1,4 @@ -#N canvas 374 48 688 626 12; +#N canvas 350 48 688 626 12; #X text 19 579 see also:; #N canvas 736 152 572 306 reference 0; #X text 75 39 - calculate absolute value function., f 66; @@ -90,36 +90,25 @@ #X connect 7 0 2 0; #X connect 9 0 8 0; #X restore 519 482 pd compatibility; -#N canvas 648 122 373 442 multichannel 0; -#X obj 86 163 snake~ in, f 10; -#X obj 86 271 snake~ out; -#X obj 185 360 snapshot~; -#X floatatom 185 399 6 0 0 0 - - - 0; -#X obj 86 360 snapshot~; -#X floatatom 86 399 6 0 0 0 - - - 0; -#X floatatom 86 106 5 0 0 0 - - - 0; -#X floatatom 153 106 5 0 0 0 - - - 0; -#X obj 86 228 abs~; -#X msg 199 217 \; pd dsp \$1; -#X text 231 180 DSP on/off; -#X obj 199 176 set-dsp-tgl; -#X obj 185 293 r bang; -#X obj 153 133 sig~ -5; -#X text 70 25 All of these objects work with multichannel signals \, where the operation is performed in all existing channels., f 33; -#X obj 86 133 sig~ -2; -#X connect 0 0 8 0; -#X connect 1 0 4 0; -#X connect 1 1 2 0; -#X connect 2 0 3 0; -#X connect 4 0 5 0; -#X connect 6 0 15 0; -#X connect 7 0 13 0; -#X connect 8 0 1 0; -#X connect 11 0 9 0; -#X connect 12 0 2 0; -#X connect 12 0 4 0; -#X connect 13 0 0 1; -#X connect 15 0 0 0; +#N canvas 793 183 357 405 multichannel 0; +#X obj 71 300 snapshot~; +#X floatatom 71 136 5 0 0 0 - - - 0; +#X floatatom 138 136 5 0 0 0 - - - 0; +#X obj 71 208 abs~; +#X msg 194 235 \; pd dsp \$1; +#X text 226 198 DSP on/off; +#X obj 194 194 set-dsp-tgl; +#X obj 96 255 r bang; +#X text 70 25 All of these objects work with multichannel signals \, where the operation is performed in all existing channels., f 32; +#X listbox 71 344 12 0 0 0 - - - 0; +#X obj 71 173 sig~ -2 -5; +#X connect 0 0 9 0; +#X connect 1 0 10 0; +#X connect 2 0 10 1; +#X connect 3 0 0 0; +#X connect 6 0 4 0; +#X connect 7 0 0 0; +#X connect 10 0 3 0; #X restore 500 421 pd multichannel; #X text 349 406 mutichannel signal support ----------->, f 20; #X text 103 393 <-- shift-drag here to get non-integers to try, f 23; diff --git a/doc/5.reference/vline~-help.pd b/doc/5.reference/vline~-help.pd index 3f62713f57..d9ef604d92 100644 --- a/doc/5.reference/vline~-help.pd +++ b/doc/5.reference/vline~-help.pd @@ -1,27 +1,22 @@ -#N canvas 358 23 616 705 12; -#X obj 98 600 snapshot~; -#X floatatom 98 630 8 0 0 0 - - - 0; -#X msg 78 339 1 1000; -#X msg 127 472 stop; -#X msg 116 389 0; -#X text 20 674 see also:; -#X obj 96 675 line; -#X obj 142 675 line~; +#N canvas 469 51 616 763 12; +#X obj 114 617 snapshot~; +#X floatatom 114 647 8 0 0 0 - - - 0; +#X msg 143 489 stop; +#X msg 114 376 0; +#X text 19 726 see also:; +#X obj 95 727 line; +#X obj 141 727 line~; #X obj 27 15 vline~; #X text 84 15 - high-precision audio ramp generator; -#X obj 98 565 vline~; -#X text 133 336 ramp up; -#X msg 98 363 0 1000; -#X text 151 364 ramp down; -#X text 127 411 ramp up \, jump down \, ramp up again; -#X text 149 388 jump down; -#X msg 121 437 1 1000 \, 0 0 2000 \, 1 1000 3000; -#X text 339 430 note: times (2000 \, 3000) are cumulative \, not incremental., f 29; -#X text 403 673 updated for Pd version 0.47; -#X floatatom 137 538 5 0 0 0 - - - 0; -#X floatatom 133 504 5 0 0 0 - - - 0; -#X text 176 496 middle inlet sets next ramp time (cleared when ramp starts!), f 32; -#X text 179 534 right inlet sets next delay time (cleared when ramp starts!), f 32; +#X obj 114 582 vline~; +#X text 127 326 ramp up; +#X msg 96 350 0 1000; +#X text 149 351 ramp down; +#X text 147 375 jump down; +#X text 402 726 updated for Pd version 0.47; +#X floatatom 153 555 5 0 0 0 - - - 0; +#X floatatom 149 521 5 0 0 0 - - - 0; +#X text 195 551 right inlet sets next delay time (cleared when ramp starts!), f 32; #X obj 11 44 cnv 1 600 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 526 14 <= click; #N canvas 708 145 583 306 reference 0; @@ -41,31 +36,180 @@ #X text 141 99 stop - stops the ramp.; #X text 133 173 float - sets delay time.; #X restore 432 14 pd reference; -#X obj 11 665 cnv 1 600 1 empty empty empty 8 12 0 13 #000000 #000000 0; -#X text 170 471 "stop" message freezes [vline~] at its current value; -#X text 226 588 !!! BUG: [vline~] objects inside reblocked subpatches can have slightly incorrect timing !!!, f 42; -#X msg 440 371 \; pd dsp \$1; -#X obj 440 336 set-dsp-tgl; -#X text 471 340 DSP on/off; -#X obj 193 675 sig~; -#X obj 446 528 metro 100; -#X obj 446 502 loadbang; -#X obj 446 554 s bang; -#X obj 35 565 r bang; -#X text 24 53 The [vline~] object \, like [line~] \, generates linear ramps whose levels and timing are determined by messages you send it. It takes a target value \, a time interval in milliseconds and an initial delay (also in ms)., f 81; -#X text 24 102 Ramps may start and stop between blocks and even between audio samples (in which case the output is interpolated accordingly). This feature can also be used to convert floats to signals in between blocks in a more sophisticated manner than [sig~] \, and you can also convert more than one float to a signal within a block., f 81; -#X text 24 165 Note that the middle and right inlet (that sets the time and delay) get cleared after the ramp starts (unlike other inlets in Pd). Thus \, if you send [vline~] a float without priorly resetting a ramp time and delay \, it jumps immediately to the target value. A list up to three floats distributes the values over the inlets \, as usual in Pd. In the same way \, a list of two values will not have a delay time if no delay time was priorly set in the rightmost inlet., f 81; -#X text 24 258 Any number of future ramps may be scheduled and [vline~] will remember them and execute them in order. You can do that by sending different lists in single messagebox. They must be specified in increasing order of initial delay however \, since a segment cancels all planned segments at any future time., f 81; +#X obj 10 710 cnv 1 600 1 empty empty empty 8 12 0 13 #000000 #000000 0; +#X text 184 488 "stop" message freezes [vline~] at its current value; +#X msg 466 352 \; pd dsp \$1; +#X obj 466 317 set-dsp-tgl; +#X text 497 321 DSP on/off; +#X obj 192 727 sig~; +#X text 25 164 Like [line~] \, note that the middle and right inlet (that sets the time and delay) get cleared after the ramp starts (this is unlike other inlets in Pd). Thus \, if you resend [vline~] a float without priorly resetting a ramp time and delay \, it jumps immediately to the target value. A list up to three floats distributes the values over the inlets \, as usual in Pd., f 80; +#X text 25 243 Any number of future ramps may be scheduled and [vline~] will remember them and execute them in order. You can do that by sending different lists in single messagebox. They must be specified in increasing order of initial delay however \, since a segment cancels all planned segments at any future time., f 80; +#X text 192 513 middle inlet sets next ramp time (cleared when ramp starts!), f 32; +#X text 290 614 Open subpacth for mores details and information, f 24; +#N canvas 505 109 896 726 details 0; +#X text 28 154 !!! BUG: [vline~] objects inside reblocked subpatches can have slightly incorrect timing !!!; +#N canvas 644 207 469 412 conversion 0; +#X obj 142 302 vline~; +#X obj 132 229 bng 20 250 50 0 empty empty empty 17 7 0 10 #dcdcdc #000000 #000000; +#X obj 239 241 random 100; +#X obj 239 297 sig~; +#X floatatom 239 269 5 0 0 0 - - - 0; +#X obj 239 335 print~ SIG; +#X obj 132 333 print~ VLINE; +#X obj 239 211 metro 1 1 samps; +#X obj 239 175 tgl 19 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000 0 1; +#X text 266 173 <-- start metronome, f 9; +#X text 60 230 click -->; +#X text 54 24 With immediate jumps (0 length lines) you can use [vline~] to sort of convert floats to signals with more precision than [sig~] \, by making transitions in the middle of a block \, and you can also convert more than one float to a signal within a block. In the example below we convert floats to signals for every sample. Note that [sig~] will only catch the value of the last received float and keep it., f 50; +#X connect 0 0 6 0; +#X connect 1 0 5 0; +#X connect 1 0 6 0; +#X connect 2 0 4 0; +#X connect 3 0 5 0; +#X connect 4 0 0 0; +#X connect 4 0 3 0; +#X connect 7 0 2 0; +#X connect 8 0 7 0; +#X restore 286 101 pd conversion; +#N canvas 728 131 507 450 impulse 0; +#X obj 308 337 vline~; +#X msg 340 229 1; +#X obj 341 274 delay 1 1 samp; +#X msg 341 302 0; +#X obj 290 374 print~; +#X obj 290 151 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X obj 308 194 t b b; +#X obj 164 184 samplerate~; +#X floatatom 164 243 12 0 0 0 - - - 0; +#X obj 164 214 expr 1000/$f1; +#X obj 116 222 f; +#X obj 97 180 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X msg 117 292 1 \, 0 0 \$1; +#X obj 117 327 vline~; +#X obj 99 364 print~; +#X obj 164 157 loadbang; +#X text 50 16 The example below uses [vline~] to generate an impulse \, which is a single sample with a value of '1' followed by zeros again. We do this by having an immediate jump and then having another immediate jump back to zero delayed by a sample. On the left we use the delay schedule and calculate the delay of one sample in ms. On the right we use [delay] to delay the message by a sample externally., f 56; +#X connect 0 0 4 0; +#X connect 1 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 0 0; +#X connect 5 0 4 0; +#X connect 5 0 6 0; +#X connect 6 0 2 0; +#X connect 6 1 1 0; +#X connect 7 0 9 0; +#X connect 9 0 8 0; +#X connect 9 0 10 1; +#X connect 10 0 12 0; +#X connect 11 0 10 0; +#X connect 11 0 14 0; +#X connect 12 0 13 0; +#X connect 13 0 14 0; +#X connect 15 0 7 0; +#X restore 286 41 pd impulse; +#X text 136 32 Example on how to generate an impulse, f 19; +#X text 52 87 Example on how to use [vline~] to convert floats to samples with more precision than [sig~], f 31; +#X obj 536 167 vline~; +#X obj 521 209 print~; +#X obj 521 100 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X obj 613 443 vline~; +#X obj 565 483 print~; +#X obj 565 331 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X obj 613 374 delay 1 1 samp; +#X msg 580 406 0; +#X msg 613 405 1 0.5 0 \, 0 0.5 0.5; +#X msg 536 131 0 \, 1 0.5 0; +#X text 634 104 Here we first have an immediate jump to 0 and start a new ramp from it to 1 in 0.5 ms., f 23; +#X text 634 166 Note that the ramp up doesn't start at 0 but at the 1st increment step., f 23; +#X obj 167 330 tgl 19 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 271 355 samplerate~; +#X floatatom 271 414 12 0 0 0 - - - 0; +#X obj 271 385 expr 1000/$f1; +#X obj 130 394 b; +#X obj 167 411 vline~; +#X obj 167 463 print~; +#X obj 167 375 pack f 10 f; +#X obj 271 328 loadbang; +#X text 261 439 one sample delay; +#X text 490 30 This is more problematic when you try to set a start point to a ramp \, like you can do with [line~]., f 45; +#X text 517 259 Below we deal with this situation by delaying the following ramps after the start point by one sample with [delay]., f 39; +#X obj 220 587 pack f 10; +#X obj 195 631 list; +#X obj 97 554 trigger bang float; +#X obj 97 584 delay 1 1 samp; +#X obj 97 521 tgl 19 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 195 674 vline~; +#X text 143 519 Another strategy is to use [delay]; +#N canvas 799 303 452 511 sub-sample-accuracy 0; +#X obj 162 341 vline~; +#X obj 114 381 print~; +#X obj 114 287 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; +#X msg 162 301 0 \, 64 1.45125 \, 0 0 1.45125; +#X text 73 32 Below we can compare a sub sample delay and see the effect on the output. The object is generating an integer increment ramp over the span of an audio block (considering a sample rate of 44.1Khz)., f 43; +#X msg 146 139 0; +#X msg 162 167 0.5; +#X msg 172 200 1; +#X text 204 158 Test different delay times, f 14; +#X floatatom 162 233 5 0 0 0 - - - 0; +#X obj 162 270 delay 1 1 samp; +#X text 106 433 We can see that a half sample delay interpolates the result., f 36; #X connect 0 0 1 0; -#X connect 2 0 10 0; -#X connect 3 0 10 0; -#X connect 4 0 10 0; -#X connect 10 0 0 0; -#X connect 12 0 10 0; -#X connect 16 0 10 0; -#X connect 19 0 10 2; -#X connect 20 0 10 1; -#X connect 30 0 29 0; -#X connect 33 0 35 0; -#X connect 34 0 33 0; -#X connect 36 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 0 0; +#X connect 5 0 9 0; +#X connect 6 0 9 0; +#X connect 7 0 9 0; +#X connect 9 0 2 0; +#X connect 9 0 10 0; +#X connect 10 0 3 0; +#X restore 645 659 pd sub-sample-accuracy; +#X text 28 188 Another known issue: Unlike [line~] \, [vline~] immediately jumps to the first increment when triggered. This is a knowingly unfortunate design (aka bug) and probably ok for most cases. Since ramps are always one sample too short \, a line of 1 sample duration is the same as a 0 length (immediate jump). This may eventually be fixed \, but for the meantime you can add a one sample delay when starting a ramp \, if you really need it to start at the current value., f 57; +#X text 493 539 Sub-sample accuracy: In the above example \, we don't see our ramp reach the value of '1' \, which would be the end of the first ramp and the start of the next one. This is because this point lies in between samples and [vline~] has sub-sample accuracy \, in which it interpolates accordingly. Check another example below., f 51; +#X connect 5 0 6 0; +#X connect 7 0 6 0; +#X connect 7 0 14 0; +#X connect 8 0 9 0; +#X connect 10 0 12 0; +#X connect 10 0 9 0; +#X connect 10 0 11 0; +#X connect 11 0 13 0; +#X connect 12 0 8 0; +#X connect 13 0 8 0; +#X connect 14 0 5 0; +#X connect 17 0 21 0; +#X connect 17 0 24 0; +#X connect 18 0 20 0; +#X connect 20 0 19 0; +#X connect 20 0 24 2; +#X connect 21 0 23 0; +#X connect 22 0 23 0; +#X connect 24 0 22 0; +#X connect 25 0 18 0; +#X connect 29 0 30 1; +#X connect 30 0 34 0; +#X connect 31 0 32 0; +#X connect 31 1 29 0; +#X connect 32 0 30 0; +#X connect 33 0 31 0; +#X restore 472 621 pd details; +#X text 25 56 The [vline~] object generates linear ramps like [line~] \, but with more time resolution \, where amps may start and stop within blocks and even between audio samples (in which case the output is interpolated accordingly). It takes a target value \, a time interval in milliseconds to reach it and an initial delay (also in ms). This object can also convert float to signals with more preciosion than [sig~] (see [pd details] below). Unlike [line~] \, it starts incrementing right away (also see [pd details] below)., f 80; +#X msg 129 427 1 1000 \, 0 0 2000 \, 1 1000 3000 \, 0 0 4000; +#X obj 117 676 hsl 162 19 0 1 0 0 empty empty empty -2 -10 0 12 #dfdfdf #000000 #000000 0 1; +#X obj 33 582 metro 10; +#X obj 33 555 loadbang; +#X msg 76 326 1 1000; +#X text 124 403 ramp up \, wait \, jump down \, wait \, ramp up again \, jump down again, f 62; +#X text 138 452 note: times (2000 \, 3000 \, 4000) are cumulative \, not incremental., f 63; +#X connect 0 0 1 0; +#X connect 1 0 34 0; +#X connect 2 0 9 0; +#X connect 3 0 9 0; +#X connect 9 0 0 0; +#X connect 11 0 9 0; +#X connect 15 0 9 2; +#X connect 16 0 9 1; +#X connect 24 0 23 0; +#X connect 33 0 9 0; +#X connect 35 0 0 0; +#X connect 36 0 35 0; +#X connect 37 0 9 0; diff --git a/doc/5.reference/writesf~-help.pd b/doc/5.reference/writesf~-help.pd index 6f5083066d..1a8485af77 100644 --- a/doc/5.reference/writesf~-help.pd +++ b/doc/5.reference/writesf~-help.pd @@ -14,9 +14,8 @@ #X text 87 116 The "open" message may take flag-style arguments as follows:; #X obj 45 12 writesf~; #X text 275 306 create a 24-bit integer soundfile; -#X text 286 332 create a 32-bit floating point soundfile; +#X text 286 332 create a 32-bit floating point soundfile, f 24; #X text 122 157 -big \, -little (sample endianness), f 42; -#X text 233 475 The creation argument is the number of channels (1 to 64)., f 29; #X obj 217 447 noise~; #X obj 7 43 cnv 1 620 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X text 533 11 <= click; @@ -28,7 +27,6 @@ #X text 44 106 open -; #X text 86 179 print - prints information on Pd's terminal window., f 64; #X obj 33 14 writesf~; -#X text 120 285 1) float - sets number of channels (default 1 \, max 64).; #X text 142 106 takes a filename and optional flags: -wave \, -aiff \, -caf \, -next \, - big \, -little \, -bytes \, -rate ; #X obj 7 209 cnv 1 550 1 empty empty n: 8 12 0 13 #7c7c7c #000000 0; #X obj 7 80 cnv 1 550 1 empty empty 1st: 8 12 0 13 #7c7c7c #000000 0; @@ -37,20 +35,21 @@ #X text 93 159 stop -; #X text 142 159 stop streaming audio, f 56; #X text 92 55 'n' number of inlets specified by argument.; -#X text 79 87 signal - signal to write to a channel., f 65; -#X text 79 215 signal - signal to write to a channel., f 65; -#X text 147 247 NONE; +#X text 161 248 NONE; #X text 99 13 - record audio signals to a soundfile; +#X text 58 87 signal(s) - signal(s) to write to a file., f 65; +#X text 59 215 signal(s) - signal(s) to write to a file., f 65; +#X text 120 285 1) float - sets number of inputs (default 1 \, max 64).; #X restore 439 12 pd reference; #X text 122 139 -wave \, -aiff \, -caf \, -next (file extension); #X obj 7 608 cnv 1 620 1 empty empty empty 8 12 0 13 #000000 #000000 0; #X obj 22 343 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; #X text 15 56 [writesf~] creates a subthread whose task is to write audio streams to disk. You need not provide any disk access time between "open" and "start" \, but between "stop" and the next "open" you must give the object time to flush all the output to disk., f 85; #X text 111 11 - record audio signals to a soundfile; -#X msg 400 410 \; pd dsp \$1; -#X obj 400 375 set-dsp-tgl; -#X text 431 379 DSP on/off; -#X text 42 548 The soundfile is uncompressed 2- or 3-byte integer ("pcm") or 4- or 8-byte floating point. The soundfile format is determined by the file extension (ie. "foo.wav" \, "foo.aiff" \, "foo.caf" \, "foo.snd")., f 80; +#X msg 487 372 \; pd dsp \$1; +#X obj 487 337 set-dsp-tgl; +#X text 518 341 DSP on/off; +#X text 42 548 The soundfile is uncompressed 2- or 3-byte integer ("pcm") or 4- or 8-byte floating point. The soundfile format is determined by the file extension (ie. "foo.wav" \, "foo.aiff" \, "foo.caf" \, "foo.snd")., f 74; #N canvas 809 273 480 224 8-byte 0; #X text 19 62 The precision of the 8-byte samples is based on the precision of the Pure Data build. If Pd is single precision (using 32-bit float internally) \, the written samples will be cast from 4-byte float to 8-byte double when writing to a file with -bytes 8 argument. In this case it's better to write with 4-byte float samples for a smaller file with the same precision., f 63; #X text 19 159 If Pd is double-precision \, writing 8-byte float samples will be full precision as Pd uses 64-bit float internally., f 63; @@ -69,18 +68,45 @@ #X msg 52 249 open \$1; #X obj 52 191 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000; #X text 124 239 choose where to save; +#X text 355 417 mutichannel signal support ------>, f 20; +#N canvas 769 164 422 533 multichannel 0; +#X msg 184 364 start; +#X msg 233 392 stop; +#X obj 233 307 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X obj 233 338 del 1500; +#X msg 160 265 open ~/MC.wav; +#X obj 118 181 snake~ in 2; +#X obj 118 152 osc~ 440; +#X obj 192 152 noise~; +#X obj 118 205 *~ 0.1; +#X obj 233 364 bng 19 250 50 0 empty empty empty 17 7 0 10 #dfdfdf #000000 #000000; +#X text 54 27 Multichannel inputs just work! It inserts the number of channels it contains into the output file. Multiple inputs can take one or more channels and the total number of output channels is the sum of all of them., f 45; +#X obj 160 433 writesf~, f 9; +#X connect 0 0 11 0; +#X connect 1 0 11 0; +#X connect 2 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 9 0; +#X connect 4 0 11 0; +#X connect 5 0 8 0; +#X connect 6 0 5 0; +#X connect 7 0 5 1; +#X connect 8 0 11 0; +#X connect 9 0 1 0; +#X restore 476 440 pd multichannel; +#X text 233 475 The creation argument is the number of inputs (default 1 \, maximum 64)., f 35; #X connect 0 0 6 0; #X connect 1 0 6 0; #X connect 2 0 6 0; #X connect 3 0 2 0; #X connect 9 0 6 0; -#X connect 18 0 6 1; -#X connect 24 0 1 0; -#X connect 24 0 3 0; -#X connect 28 0 27 0; +#X connect 17 0 6 1; +#X connect 23 0 1 0; +#X connect 23 0 3 0; +#X connect 27 0 26 0; +#X connect 34 0 6 0; #X connect 35 0 6 0; #X connect 36 0 6 0; -#X connect 37 0 6 0; -#X connect 41 0 42 0; -#X connect 42 0 6 0; -#X connect 43 0 41 0; +#X connect 40 0 41 0; +#X connect 41 0 6 0; +#X connect 42 0 40 0; diff --git a/doc/7.stuff/soundfile-tools/4.looper.pd b/doc/7.stuff/soundfile-tools/4.looper.pd index c44a8ce5dc..038d584474 100644 --- a/doc/7.stuff/soundfile-tools/4.looper.pd +++ b/doc/7.stuff/soundfile-tools/4.looper.pd @@ -199,7 +199,7 @@ #X text 129 32 looping sample player.; #N canvas 581 112 275 258 length 0; #X obj 48 24 inlet; -#X obj 49 104 * 44100; +#X obj 49 104 * 48000; #X obj 48 49 min 60; #X obj 62 78 s output-length; #X obj 43 220 s maxoutsize; diff --git a/doc/7.stuff/soundfile-tools/5.reverb.pd b/doc/7.stuff/soundfile-tools/5.reverb.pd index 246b871e33..368741f157 100644 --- a/doc/7.stuff/soundfile-tools/5.reverb.pd +++ b/doc/7.stuff/soundfile-tools/5.reverb.pd @@ -58,7 +58,7 @@ #X obj 233 141 tabplay~ \$0-input, f 9; #X msg 220 59 bang \; pd dsp 1; #X obj 220 26 r \$0-run; -#X obj 47 215 + 44100; +#X obj 47 215 + 48000; #X connect 0 0 2 0; #X connect 1 0 0 0; #X connect 1 0 20 0; diff --git a/doc/Makefile.am b/doc/Makefile.am index b950570462..a1264130ae 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -34,6 +34,7 @@ nobase_dist_libpd_DATA = \ ./1.manual/resources/2.1.12.png \ ./1.manual/resources/2.1.13.png \ ./1.manual/resources/2.1.14.png \ + ./1.manual/resources/2.1.15.png \ ./1.manual/resources/2.1.2.png \ ./1.manual/resources/2.1.3.png \ ./1.manual/resources/2.1.4.png \ @@ -353,6 +354,7 @@ nobase_dist_libpd_DATA = \ ./5.reference/clone-abs-a.pd \ ./5.reference/clone-abs-b.pd \ ./5.reference/clone-abs-c.pd \ + ./5.reference/clone-abs-d.pd \ ./5.reference/clone-help.pd \ ./5.reference/cnv-help.pd \ ./5.reference/cos~-help.pd \ @@ -526,6 +528,7 @@ nobase_dist_libpd_DATA = \ ./8.topics/slop-tilde-1-curves.png \ ./8.topics/slop-tilde.htm \ ./sound/bell.aiff \ + ./sound/stereo.wav \ ./sound/voice.wav \ ./sound/voice2.wav \ $(empty) diff --git a/doc/sound/bell.aiff b/doc/sound/bell.aiff index 4b2a49aecc..5b2fb3aa13 100644 Binary files a/doc/sound/bell.aiff and b/doc/sound/bell.aiff differ diff --git a/doc/sound/stereo.wav b/doc/sound/stereo.wav new file mode 100644 index 0000000000..9eb6b89f3e Binary files /dev/null and b/doc/sound/stereo.wav differ diff --git a/doc/sound/voice.wav b/doc/sound/voice.wav index 8b7f1acc73..c3b075d42b 100644 Binary files a/doc/sound/voice.wav and b/doc/sound/voice.wav differ diff --git a/doc/sound/voice2.wav b/doc/sound/voice2.wav index d5d944b162..94117dc647 100644 Binary files a/doc/sound/voice2.wav and b/doc/sound/voice2.wav differ diff --git a/extra/fiddle~/fiddle~.c b/extra/fiddle~/fiddle~.c index 50016565a4..97498a1d17 100644 --- a/extra/fiddle~/fiddle~.c +++ b/extra/fiddle~/fiddle~.c @@ -34,16 +34,9 @@ #pragma warning (disable: 4305 4244) #endif -/* this #ifdef does nothing, but its there... */ -#ifdef _WIN32 -#define flog log -#define fexp exp -#define fsqrt sqrt -#else -#define flog log -#define fexp exp -#define fsqrt sqrt -#endif +#define LOG log +#define EXP exp +#define SQRT sqrt char fiddle_version[] = "fiddle version 1.1 TEST4"; @@ -101,12 +94,6 @@ static fts_symbol_t *dsp_symbol = 0; #include "m_pd.h" #endif /* PD */ -#ifdef MSP -#define flog log -#define fexp exp -#define fsqrt sqrt -#endif /* MSP */ - #ifdef MSP #include "ext.h" #include "z_dsp.h" @@ -473,7 +460,7 @@ void sigfiddle_doit(t_sigfiddle *x) fp1[1] = 0.7071f * (im - re); fp1[4] = fp2[0] + fp3[1]; fp1[5] = fp2[1] - fp3[0]; - + fp1 += 8, fp2 += 2, fp3 += 2; re= FILT1 * ( fp2[ -2] -fp2[ 1] -fp3[ -2] +fp3[ 1]) + FILT2 * ( fp2[ -3] -fp2[ 2] -fp3[ -3] +fp3[ 2]) + @@ -491,7 +478,7 @@ void sigfiddle_doit(t_sigfiddle *x) fp1[1] = 0.7071f * (im - re); fp1[4] = fp2[0] - fp3[1]; fp1[5] = fp2[1] + fp3[0]; - + fp1 += 8, fp2 += 2, fp3 += 2; } #if 0 @@ -519,7 +506,7 @@ void sigfiddle_doit(t_sigfiddle *x) if (total_power > 1e-9f) { total_db = (100.f - DBFUDGE) + LOGTODB * log(total_power/n); - total_loudness = fsqrt(fsqrt(total_power)); + total_loudness = SQRT(SQRT(total_power)); if (total_db < 0) total_db = 0; } else total_db = total_loudness = 0; @@ -557,7 +544,7 @@ void sigfiddle_doit(t_sigfiddle *x) { t_float height = fp[2], h1 = fp[-2], h2 = fp[6]; t_float totalfreq, pfreq, f1, f2, m, var, stdev; - + if (height < h1 || height < h2 || h1 < 0.00001f*total_power || h2 < 0.00001f*total_power) continue; @@ -589,7 +576,7 @@ void sigfiddle_doit(t_sigfiddle *x) #endif continue; } - stdev = fsqrt(var); + stdev = SQRT(var); if (totalfreq < 4) { if (x->x_nprint) post("oops: was %d, freq %f, m %f, stdev %f h %f", @@ -599,7 +586,7 @@ void sigfiddle_doit(t_sigfiddle *x) pk1->p_width = stdev; pk1->p_pow = height; - pk1->p_loudness = fsqrt(fsqrt(height)); + pk1->p_loudness = SQRT(SQRT(height)); pk1->p_fp = fp; pk1->p_freq = totalfreq; npeak++; @@ -637,7 +624,7 @@ void sigfiddle_doit(t_sigfiddle *x) for (i = 0, fp1 = histogram; i < maxbin; i++) *fp1++ = 0; for (i = 0, pk1 = peaklist; i < npeak; i++, pk1++) { - t_float pit = BPERO_OVER_LOG2 * flog(pk1->p_freq) - 96.0; + t_float pit = BPERO_OVER_LOG2 * LOG(pk1->p_freq) - 96.0; t_float binbandwidth = FACTORTOBINS * pk1->p_width/pk1->p_freq; t_float putbandwidth = (binbandwidth < 2 ? 2 : binbandwidth); t_float weightbandwidth = (binbandwidth < 1.0 ? 1.0 : binbandwidth); @@ -767,7 +754,7 @@ void sigfiddle_doit(t_sigfiddle *x) t_float cumpow = 0, cumstrength = 0, freqnum = 0, freqden = 0; int npartials = 0, nbelow8 = 0; /* guessed-at frequency in bins */ - t_float putfreq = fexp((1.0 / BPERO_OVER_LOG2) * + t_float putfreq = EXP((1.0 / BPERO_OVER_LOG2) * (histvec[i].h_index + 96.0f)); for (j = 0; j < npeak; j++) { @@ -788,12 +775,12 @@ void sigfiddle_doit(t_sigfiddle *x) npartials++; if (pnum < 8) nbelow8++; cumpow += peaklist[j].p_pow; - cumstrength += fsqrt(fsqrt(peaklist[j].p_pow)); + cumstrength += SQRT(SQRT(peaklist[j].p_pow)); stdev = (peaklist[j].p_width > MINBW ? peaklist[j].p_width : MINBW); weight = 1.0f / ((stdev*fipnum) * (stdev*fipnum)); freqden += weight; - freqnum += weight * peaklist[j].p_freq/fipnum; + freqnum += weight * peaklist[j].p_freq/fipnum; #if 1 if (x->x_nprint) { @@ -1710,7 +1697,7 @@ void sigfiddle_tick(t_sigfiddle *x) /* callback function for the clock MSP*/ if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch); } -void sigfiddle_bang(t_sigfiddle *x) +void sigfiddle_bang(t_sigfiddle *x) { int i; t_pitchhist *ph; @@ -1827,7 +1814,7 @@ void msp_fft(t_float *buf, long np, long inv) // a more ambitious person would either do an in-place conversion // or rewrite the fft algorithm */ - + real = rp = msp_ffttemp; imag = ip = real + MAXPOINTS; src = buf; diff --git a/extra/pd~/pd~-help.pd b/extra/pd~/pd~-help.pd index a6c7b9ba68..bebc596de6 100644 --- a/extra/pd~/pd~-help.pd +++ b/extra/pd~/pd~-help.pd @@ -67,7 +67,7 @@ #X msg 373 504 1; #X text 359 536 hide/show window; #X text 403 504 * <-----------------; -#X obj 92 596 pd~ -ninsig 2 -noutsig 2 -fifo 20 -sr 44100, f 24; +#X obj 92 596 pd~ -ninsig 2 -noutsig 2 -fifo 20 -sr 48000, f 24; #X text 271 602 <-- see [pd reference] for creation flag's descriptions.; #X msg 126 434 0; #X msg 166 434 1; diff --git a/extra/sigmund~/sigmund~-help.pd b/extra/sigmund~/sigmund~-help.pd index 365d9db875..42a5132451 100644 --- a/extra/sigmund~/sigmund~-help.pd +++ b/extra/sigmund~/sigmund~-help.pd @@ -24,9 +24,9 @@ #X msg 425 532 \; pd dsp \$1; #X text 457 500 DSP on/off; #X obj 425 495 ../../doc/5.reference/set-dsp-tgl; -#X msg 30 287 clear \, list insignal 1024 0 44100; -#X msg 50 319 clear \, list insignal 512 0 44100; -#X msg 64 349 list insignal 512 512 44100; +#X msg 30 287 clear \, list insignal 1024 0 48000; +#X msg 50 319 clear \, list insignal 512 0 48000; +#X msg 64 349 list insignal 512 512 48000; #X text 106 178 - optional debug flag (print debugging info if nonzero); #X text 22 212 Note that in this mode you can't have 'notes' output! Also note that if you're getting tracks output you may want to 'clear' the tracks before starting a new analysis from the beginning of the table., f 73; #X obj 49 501 cnv 19 198 138 empty empty empty 20 12 0 12 #e0e0e0 #404040 0; diff --git a/libpd/Makefile b/libpd/Makefile index e46d351b9c..63b4639554 100644 --- a/libpd/Makefile +++ b/libpd/Makefile @@ -76,6 +76,9 @@ MORECFLAGS = # additional linker flags to override to add more (like "-g"). MORELDFLAGS = +# additional source files you might want +MORESRC = + CFLAGS = $(CPPFLAGS) $(PLATFORM_CFLAGS) $(CODECFLAGS) $(MORECFLAGS) LDFLAGS = $(PLATFORM_LDFLAGS) $(MORELDFLAGS) @@ -101,7 +104,7 @@ EXTRASRC = bob~.c bonk~.c choice.c fiddle~.c loop~.c lrshift~.c pique.c \ LIBPDSRC = s_libpdmidi.c x_libpdreceive.c z_hooks.c z_libpd.c \ z_print_util.c z_queued.c z_ringbuffer.c -SRC = $(PDSRC) $(EXTRASRC) $(LIBPDSRC) +SRC = $(PDSRC) $(EXTRASRC) $(LIBPDSRC) $(MORESRC) OBJ = $(SRC:.c=.o) diff --git a/mac/stuff/pd.entitlements b/mac/stuff/pd.entitlements index 1850b99006..7042363412 100644 --- a/mac/stuff/pd.entitlements +++ b/mac/stuff/pd.entitlements @@ -2,6 +2,8 @@ + com.apple.security.cs.allow-jit + com.apple.security.cs.disable-library-validation com.apple.security.device.audio-input diff --git a/msw/build-wxp-32.sh b/msw/build-wxp-32.sh index c3ffc842a6..318153e4fc 100755 --- a/msw/build-wxp-32.sh +++ b/msw/build-wxp-32.sh @@ -36,6 +36,10 @@ cp -a $HOME/bis/work/pd-versions/tcltk-$tkversion . /home/msp/pd/msw/msw-app.sh \ --builddir .. --tk tcltk-$tkversion $pdversion +# 0.56 and onward - separately copy in thread lib which was thrown out of +# the prototype because it conflicted with something else +cp -p ~/pd/msw/libwinpthread-1.dll32 pd-$pdversion/bin/libwinpthread-1.dll + # make zip archive zip -r -q /tmp/pd-$pdversion.msw.zip pd-$pdversion diff --git a/msw/libwinpthread-1.dll32 b/msw/libwinpthread-1.dll32 new file mode 100755 index 0000000000..c4f332769d Binary files /dev/null and b/msw/libwinpthread-1.dll32 differ diff --git a/msw/pdprototype.tgz b/msw/pdprototype.tgz index 86b1e5ee02..e97e425fbb 100644 Binary files a/msw/pdprototype.tgz and b/msw/pdprototype.tgz differ diff --git a/po/Makefile.am b/po/Makefile.am index f027b3894d..dd44a61572 100644 --- a/po/Makefile.am +++ b/po/Makefile.am @@ -89,6 +89,7 @@ ALL_LINGUAS = \ pa pl pt_br pt_pt \ ru \ sq sv \ + ta \ uk \ vi \ zh_tw \ diff --git a/po/az.po b/po/az.po index f650a13bfd..07e9cf4252 100644 --- a/po/az.po +++ b/po/az.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.43\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2004-03-12 22:22+0200\n" "Last-Translator: Metin Amiroff \n" "Language-Team: Azerbaijani \n" @@ -305,6 +305,9 @@ msgstr "Ön işarə:" msgid "Y range: from" msgstr "" +msgid "Object:" +msgstr "" + msgid "Data Properties" msgstr "" @@ -883,12 +886,25 @@ msgstr "" msgid "Unable to rename downloaded file to '%s'" msgstr "" +#, fuzzy +msgid "Search URLs:" +msgstr "Mətni Axtar..." + +msgid "Additional search URLs" +msgstr "" + +msgid "Ephemeral search URLs" +msgstr "" + msgid "Create" msgstr "" msgid "Check" msgstr "" +msgid "Deken Installation Target" +msgstr "" + msgid "Installation options:" msgstr "" @@ -959,6 +975,19 @@ msgstr "TAR fayllar" msgid "All Files" msgstr "barcha fayllar" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "" + +msgid "Replacing library with incompatible architecture!" +msgstr "" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "" @@ -1149,11 +1178,11 @@ msgstr "" msgid "Installing to non-existent directory failed" msgstr "" -#, tcl-format -msgid "Unable to install to '%s'" +msgid "Directory does not exist!" msgstr "" -msgid "Directory does not exist!" +#, tcl-format +msgid "Unable to install to '%s'" msgstr "" msgid "Directory is not writable!" @@ -1194,6 +1223,10 @@ msgstr "" msgid "[deken] Platform detected: %s" msgstr "" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "" + #, fuzzy, tcl-format msgid "Searching on %s..." msgstr "Mətni Axtar..." @@ -1846,6 +1879,16 @@ msgstr "" msgid "Print..." msgstr "_Yüklə..." +msgid "single precision" +msgstr "" + +msgid "double precision" +msgstr "" + +#, tcl-format +msgid "%dbit-floats" +msgstr "" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "" @@ -1858,6 +1901,15 @@ msgstr "_Haqqında" msgid "couldn't read \"%s\" document" msgstr "" +msgid "New" +msgstr "Yeni" + +msgid "Open" +msgstr "Aç" + +msgid "Open Recent" +msgstr "" + msgid "Save" msgstr "Qeyd Et" @@ -1865,63 +1917,56 @@ msgstr "Qeyd Et" msgid "Save As..." msgstr "Fərqli Qeyd Et" -msgid "Paste Replace" -msgstr "" - -#, fuzzy -msgid "Duplicate" -msgstr "Tarix" +msgid "Quit" +msgstr "Çıx" #, fuzzy -msgid "Zoom In" -msgstr "Altda" +msgid "Undo" +msgstr "Uqanda" #, fuzzy -msgid "Zoom Out" -msgstr "Altda" - -msgid "Tidy Up" -msgstr "" +msgid "Redo" +msgstr "Səbəb" -msgid "(Dis)Connect Selection" +msgid "Cut" msgstr "" -msgid "Triggerize" +msgid "Paste Replace" msgstr "" #, fuzzy -msgid "Edit Mode" -msgstr "Təfərruatlar" +msgid "Select All" +msgstr "Hamısı Sil" #, fuzzy -msgid "Undo" -msgstr "Uqanda" +msgid "Duplicate" +msgstr "Tarix" -#, fuzzy -msgid "Redo" -msgstr "Səbəb" +msgid "Tidy Up" +msgstr "" -msgid "New" -msgstr "Yeni" +msgid "(Dis)Connect Selection" +msgstr "" -msgid "Open" -msgstr "Aç" +msgid "Triggerize" +msgstr "" #, fuzzy -msgid "Message..." -msgstr "İsmarış" - -msgid "Cut" -msgstr "" +msgid "Zoom In" +msgstr "Altda" #, fuzzy -msgid "Select All" -msgstr "Hamısı Sil" +msgid "Zoom Out" +msgstr "Altda" #, fuzzy msgid "Clear Console" msgstr "Siyahını təmizlə" +#, fuzzy +msgid "Edit Mode" +msgstr "Təfərruatlar" + msgid "Object" msgstr "" @@ -1993,10 +2038,18 @@ msgstr "Fayl Yolla" msgid "Previous Window" msgstr "Fayl Yolla" +#, fuzzy +msgid "Close subwindows" +msgstr "Bu səkmə/pəncərəni bağla" + #, fuzzy msgid "Parent Window" msgstr "Fayl Yolla" +#, fuzzy +msgid "Message..." +msgstr "İsmarış" + msgid "HTML Manual..." msgstr "" @@ -2053,12 +2106,6 @@ msgstr "" msgid "Tabbed preferences" msgstr "Seçimlər..." -msgid "Open Recent" -msgstr "" - -msgid "Quit" -msgstr "Çıx" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "" @@ -2089,6 +2136,9 @@ msgstr "" msgid "Audio off" msgstr "" +msgid "Find source" +msgstr "" + msgid "Pd" msgstr "" @@ -2166,10 +2216,6 @@ msgstr "" #~ msgid "for:" #~ msgstr "Qapı:" -#, fuzzy -#~ msgid "Close this window??" -#~ msgstr "Bu səkmə/pəncərəni bağla" - #, fuzzy #~ msgid "Filters" #~ msgstr "Fayl" diff --git a/po/bg.po b/po/bg.po index 76c73894ad..ebae4f3e29 100644 --- a/po/bg.po +++ b/po/bg.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.43\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2022-10-30 07:04+0000\n" "Last-Translator: Max Neupert \n" "Language-Team: Bulgarian \n" "Language-Team: German \n" @@ -19,7 +19,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 3.4.4\n" +"X-Generator: Weblate 5.12-dev\n" msgid "linear" msgstr "linear" @@ -294,6 +294,9 @@ msgstr "Abstand:" msgid "Y range: from" msgstr "Y-Spanne, von" +msgid "Object:" +msgstr "Objekt:" + msgid "Data Properties" msgstr "Daten-Eigenschaften" @@ -613,7 +616,7 @@ msgid "MIDI preferences" msgstr "MIDI" msgid "deken preferences" -msgstr "Deken-Einstellungen" +msgstr "Paketverwaltung" msgid "misc preferences" msgstr "sonstiges" @@ -845,12 +848,24 @@ msgstr "Konnte überschüssige Datei '%s' nicht entfernen" msgid "Unable to rename downloaded file to '%s'" msgstr "Konnte heruntergeladene Datei nicht in '%s' umbenennen" +msgid "Search URLs:" +msgstr "Such-URLs:" + +msgid "Additional search URLs" +msgstr "Zusätzliche Such-URLs" + +msgid "Ephemeral search URLs" +msgstr "Temporäre such URLs" + msgid "Create" msgstr "Erstellen" msgid "Check" msgstr "Überprüfen" +msgid "Deken Installation Target" +msgstr "Deken Installationsverzeichnis" + msgid "Installation options:" msgstr "Installationsoptionen:" @@ -920,6 +935,21 @@ msgstr "TAR-Archive" msgid "All Files" msgstr "Alle Dateien" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "Installiere inkompatible Architektur von '%s'." + +msgid "Replacing library with incompatible architecture!" +msgstr "Ersetze Bibliothek mit inkompatibler Architektur!" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" +"Wollen Sie die Bibliothek '%1$s' in '%2$s' mit einer Version ersetzen, die " +"inkompatibel zu Ihrem Computer ist?" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "Entferne vorherige Version von '%s'" @@ -1115,13 +1145,13 @@ msgstr "" msgid "Installing to non-existent directory failed" msgstr "Die Installation in ein nicht-existierendes Verzeichnis schlug fehl" +msgid "Directory does not exist!" +msgstr "Verzeichnis existiert nicht!" + #, tcl-format msgid "Unable to install to '%s'" msgstr "Fehler beim Installieren nach '%s'" -msgid "Directory does not exist!" -msgstr "Verzeichnis existiert nicht!" - msgid "Directory is not writable!" msgstr "Verzeichnis ist nicht schreibbar!" @@ -1160,6 +1190,10 @@ msgstr "[deken] Pd-Paketmanager vom Pfad %s geladen." msgid "[deken] Platform detected: %s" msgstr "[deken] Paketarchitektur erkannt: %s" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "Konnte kein Menü finden, um '%s' hinzuzufügen" + #, tcl-format msgid "Searching on %s..." msgstr "Suche auf %s..." @@ -1827,6 +1861,16 @@ msgstr "(Standardsprache: %s)" msgid "Print..." msgstr "Drucken..." +msgid "single precision" +msgstr "einfache Genauigkeit" + +msgid "double precision" +msgstr "doppelte Genauigkeit" + +#, tcl-format +msgid "%dbit-floats" +msgstr "%dbit Zahlen" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "'%s' wird ignoriert: existiert nicht" @@ -1838,24 +1882,42 @@ msgstr "Über Pd" msgid "couldn't read \"%s\" document" msgstr "konnte das Dokument \"%s\" nicht lesen" +msgid "New" +msgstr "Neu" + +msgid "Open" +msgstr "Öffnen" + +msgid "Open Recent" +msgstr "Letzte Dateien öffnen" + msgid "Save" msgstr "Speichern" msgid "Save As..." msgstr "Speichern als..." +msgid "Quit" +msgstr "Beenden" + +msgid "Undo" +msgstr "Rückgängig" + +msgid "Redo" +msgstr "Wiederherstellen" + +msgid "Cut" +msgstr "Ausschneiden" + msgid "Paste Replace" msgstr "Objekte ersetzen" +msgid "Select All" +msgstr "Alles auswählen" + msgid "Duplicate" msgstr "Duplizieren" -msgid "Zoom In" -msgstr "Vergrößern" - -msgid "Zoom Out" -msgstr "Verkleinern" - msgid "Tidy Up" msgstr "Aufräumen" @@ -1865,33 +1927,18 @@ msgstr "Auswahl verbinden/trennen" msgid "Triggerize" msgstr "Trigger hinzufügen" -msgid "Edit Mode" -msgstr "Editiermodus" - -msgid "Undo" -msgstr "Rückgängig" - -msgid "Redo" -msgstr "Wiederherstellen" - -msgid "New" -msgstr "Neu" - -msgid "Open" -msgstr "Öffnen" - -msgid "Message..." -msgstr "Message..." - -msgid "Cut" -msgstr "Ausschneiden" +msgid "Zoom In" +msgstr "Vergrößern" -msgid "Select All" -msgstr "Alles auswählen" +msgid "Zoom Out" +msgstr "Verkleinern" msgid "Clear Console" msgstr "Konsole löschen" +msgid "Edit Mode" +msgstr "Editiermodus" + msgid "Object" msgstr "Objekt" @@ -1955,9 +2002,15 @@ msgstr "Nächstes Fenster" msgid "Previous Window" msgstr "Vorheriges Fenster" +msgid "Close subwindows" +msgstr "Unterfenster schließen" + msgid "Parent Window" msgstr "Übergeordnetes Fenster" +msgid "Message..." +msgstr "Message..." + msgid "HTML Manual..." msgstr "HTML-Anleitung..." @@ -2010,12 +2063,6 @@ msgstr "Alle Einstellungen zurücksetzen..." msgid "Tabbed preferences" msgstr "Einstellungen mit Tabs" -msgid "Open Recent" -msgstr "Letzte Dateien öffnen" - -msgid "Quit" -msgstr "Beenden" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "Änderungen in '%s' speichern?" @@ -2048,6 +2095,9 @@ msgstr "Audio ein" msgid "Audio off" msgstr "Audio aus" +msgid "Find source" +msgstr "Gehe zum Ursprung" + msgid "Pd" msgstr "Pd" @@ -2268,9 +2318,6 @@ msgstr "überspringe '%s': kein Pd-File" #~ msgid "Discard changes to this window??" #~ msgstr "Änderungen an diesem Fenster verwerfen?" -#~ msgid "Close this window??" -#~ msgstr "Dieses Fenster schließen?" - #~ msgid "Input device 4:" #~ msgstr "Eingabegerät 4:" diff --git a/po/el.po b/po/el.po index 6512aab344..8eb58da671 100644 --- a/po/el.po +++ b/po/el.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.43\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2009-09-13 01:51+0200\n" "Last-Translator: Γεώργιος Κερατζάκης \n" "Language-Team: Greek \n" "Language-Team: English \n" @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 3.4.4\n" +"X-Generator: Weblate 5.12-dev\n" msgid "linear" msgstr "linear" @@ -286,6 +286,9 @@ msgstr "Margin:" msgid "Y range: from" msgstr "Y range: from" +msgid "Object:" +msgstr "Object:" + msgid "Data Properties" msgstr "Data Properties" @@ -601,7 +604,7 @@ msgid "MIDI preferences" msgstr "MIDI" msgid "deken preferences" -msgstr "Deken" +msgstr "packages" msgid "misc preferences" msgstr "Misc" @@ -827,12 +830,24 @@ msgstr "Unable to remove stray file '%s'" msgid "Unable to rename downloaded file to '%s'" msgstr "Unable to rename downloaded file to '%s'" +msgid "Search URLs:" +msgstr "Search URLs:" + +msgid "Additional search URLs" +msgstr "Additional search URLs" + +msgid "Ephemeral search URLs" +msgstr "Ephemeral search URLs" + msgid "Create" msgstr "Create" msgid "Check" msgstr "Check" +msgid "Deken Installation Target" +msgstr "Deken Installation Target" + msgid "Installation options:" msgstr "Installation options:" @@ -902,6 +917,21 @@ msgstr "TAR Files" msgid "All Files" msgstr "All Files" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "Installing incompatible architecture of '%s'." + +msgid "Replacing library with incompatible architecture!" +msgstr "Replacing library with incompatible architecture!" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "Uninstalling previous installation of '%s'" @@ -1091,13 +1121,13 @@ msgstr "Cancelling download of '%s': No installation directory given." msgid "Installing to non-existent directory failed" msgstr "Installing to non-existant directory failed" +msgid "Directory does not exist!" +msgstr "Directory does not exist!" + #, tcl-format msgid "Unable to install to '%s'" msgstr "Unable to install to '%s'" -msgid "Directory does not exist!" -msgstr "Directory does not exist!" - msgid "Directory is not writable!" msgstr "Directory is not writable!" @@ -1136,6 +1166,10 @@ msgstr "[deken] deken-plugin.tcl (Pd externals search) loaded from %s." msgid "[deken] Platform detected: %s" msgstr "[deken] Platform detected: %s" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "Could not find a menu for adding '%s'" + #, tcl-format msgid "Searching on %s..." msgstr "Searching on %s..." @@ -1803,6 +1837,16 @@ msgstr "(default language: %s)" msgid "Print..." msgstr "Print..." +msgid "single precision" +msgstr "single precision" + +msgid "double precision" +msgstr "double precision" + +#, tcl-format +msgid "%dbit-floats" +msgstr "%dbit-floats" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "ignoring '%s': doesn't exist" @@ -1814,24 +1858,42 @@ msgstr "About Pd" msgid "couldn't read \"%s\" document" msgstr "couldn't read \"%s\" document" +msgid "New" +msgstr "New" + +msgid "Open" +msgstr "Open" + +msgid "Open Recent" +msgstr "Open Recent" + msgid "Save" msgstr "Save" msgid "Save As..." msgstr "Save As..." +msgid "Quit" +msgstr "Quit" + +msgid "Undo" +msgstr "Undo" + +msgid "Redo" +msgstr "Redo" + +msgid "Cut" +msgstr "Cut" + msgid "Paste Replace" msgstr "Paste Replace" +msgid "Select All" +msgstr "Select All" + msgid "Duplicate" msgstr "Duplicate" -msgid "Zoom In" -msgstr "Zoom In" - -msgid "Zoom Out" -msgstr "Zoom Out" - msgid "Tidy Up" msgstr "Tidy Up" @@ -1841,33 +1903,18 @@ msgstr "(Dis)Connect Selection" msgid "Triggerize" msgstr "Triggerize" -msgid "Edit Mode" -msgstr "Edit Mode" - -msgid "Undo" -msgstr "Undo" - -msgid "Redo" -msgstr "Redo" - -msgid "New" -msgstr "New" - -msgid "Open" -msgstr "Open" - -msgid "Message..." -msgstr "Message..." - -msgid "Cut" -msgstr "Cut" +msgid "Zoom In" +msgstr "Zoom In" -msgid "Select All" -msgstr "Select All" +msgid "Zoom Out" +msgstr "Zoom Out" msgid "Clear Console" msgstr "Clear Console" +msgid "Edit Mode" +msgstr "Edit Mode" + msgid "Object" msgstr "Object" @@ -1931,9 +1978,15 @@ msgstr "Next Window" msgid "Previous Window" msgstr "Previous Window" +msgid "Close subwindows" +msgstr "Close subwindows" + msgid "Parent Window" msgstr "Parent Window" +msgid "Message..." +msgstr "Message..." + msgid "HTML Manual..." msgstr "HTML Manual..." @@ -1986,12 +2039,6 @@ msgstr "Forget All..." msgid "Tabbed preferences" msgstr "Tabbed preferences" -msgid "Open Recent" -msgstr "Open Recent" - -msgid "Quit" -msgstr "Quit" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "Do you want to save the changes you made in '%s'?" @@ -2024,6 +2071,9 @@ msgstr "Audio on" msgid "Audio off" msgstr "Audio off" +msgid "Find source" +msgstr "Find source" + msgid "Pd" msgstr "Pd" diff --git a/po/en_ca.po b/po/en_ca.po index 6d0c5340c2..033ba6a9e2 100644 --- a/po/en_ca.po +++ b/po/en_ca.po @@ -7,17 +7,17 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.43\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" -"PO-Revision-Date: 2024-07-08 17:16+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" +"PO-Revision-Date: 2025-05-26 23:57+0000\n" "Last-Translator: umläute \n" "Language-Team: English (Canada) \n" -"Language: en_CA\n" +"Language: en_ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 3.4.4\n" +"X-Generator: Weblate 5.12-dev\n" msgid "linear" msgstr "linear" @@ -287,6 +287,9 @@ msgstr "Margin:" msgid "Y range: from" msgstr "Y range: from" +msgid "Object:" +msgstr "Object:" + msgid "Data Properties" msgstr "Data Properties" @@ -602,7 +605,7 @@ msgid "MIDI preferences" msgstr "MIDI" msgid "deken preferences" -msgstr "Deken" +msgstr "packages" msgid "misc preferences" msgstr "Misc" @@ -828,12 +831,24 @@ msgstr "Unable to remove stray file '%s'" msgid "Unable to rename downloaded file to '%s'" msgstr "Unable to rename downloaded file to '%s'" +msgid "Search URLs:" +msgstr "Search URLs:" + +msgid "Additional search URLs" +msgstr "Additional search URLs" + +msgid "Ephemeral search URLs" +msgstr "Ephemeral search URLs" + msgid "Create" msgstr "Create" msgid "Check" msgstr "Check" +msgid "Deken Installation Target" +msgstr "Deken Installation Target" + msgid "Installation options:" msgstr "Installation options:" @@ -903,6 +918,21 @@ msgstr "TAR Files" msgid "All Files" msgstr "All Files" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "Installing incompatible architecture of '%s'." + +msgid "Replacing library with incompatible architecture!" +msgstr "Replacing library with incompatible architecture!" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "Uninstalling previous installation of '%s'" @@ -1092,13 +1122,13 @@ msgstr "Cancelling download of '%s': No installation directory given." msgid "Installing to non-existent directory failed" msgstr "Installing to non-existent directory failed" +msgid "Directory does not exist!" +msgstr "Directory does not exist!" + #, tcl-format msgid "Unable to install to '%s'" msgstr "Unable to install to '%s'" -msgid "Directory does not exist!" -msgstr "Directory does not exist!" - msgid "Directory is not writable!" msgstr "Directory is not writable!" @@ -1137,6 +1167,10 @@ msgstr "[deken] deken-plugin.tcl (Pd externals search) loaded from %s." msgid "[deken] Platform detected: %s" msgstr "[deken] Platform detected: %s" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "Could not find a menu for adding '%s'" + #, tcl-format msgid "Searching on %s..." msgstr "Searching on %s..." @@ -1804,6 +1838,16 @@ msgstr "(default language: %s)" msgid "Print..." msgstr "Print..." +msgid "single precision" +msgstr "single precision" + +msgid "double precision" +msgstr "double precision" + +#, tcl-format +msgid "%dbit-floats" +msgstr "%dbit-floats" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "ignoring '%s': doesn't exist" @@ -1815,24 +1859,42 @@ msgstr "About Pd" msgid "couldn't read \"%s\" document" msgstr "couldn't read \"%s\" document" +msgid "New" +msgstr "New" + +msgid "Open" +msgstr "Open" + +msgid "Open Recent" +msgstr "Open Recent" + msgid "Save" msgstr "Save" msgid "Save As..." msgstr "Save As..." +msgid "Quit" +msgstr "Quit" + +msgid "Undo" +msgstr "Undo" + +msgid "Redo" +msgstr "Redo" + +msgid "Cut" +msgstr "Cut" + msgid "Paste Replace" msgstr "Paste Replace" +msgid "Select All" +msgstr "Select All" + msgid "Duplicate" msgstr "Duplicate" -msgid "Zoom In" -msgstr "Zoom In" - -msgid "Zoom Out" -msgstr "Zoom Out" - msgid "Tidy Up" msgstr "Tidy Up" @@ -1842,33 +1904,18 @@ msgstr "(Dis)Connect Selection" msgid "Triggerize" msgstr "Triggerize" -msgid "Edit Mode" -msgstr "Edit Mode" - -msgid "Undo" -msgstr "Undo" - -msgid "Redo" -msgstr "Redo" - -msgid "New" -msgstr "New" - -msgid "Open" -msgstr "Open" - -msgid "Message..." -msgstr "Message..." - -msgid "Cut" -msgstr "Cut" +msgid "Zoom In" +msgstr "Zoom In" -msgid "Select All" -msgstr "Select All" +msgid "Zoom Out" +msgstr "Zoom Out" msgid "Clear Console" msgstr "Clear Console" +msgid "Edit Mode" +msgstr "Edit Mode" + msgid "Object" msgstr "Object" @@ -1932,9 +1979,15 @@ msgstr "Next Window" msgid "Previous Window" msgstr "Previous Window" +msgid "Close subwindows" +msgstr "Close subwindows" + msgid "Parent Window" msgstr "Parent Window" +msgid "Message..." +msgstr "Message..." + msgid "HTML Manual..." msgstr "HTML Manual..." @@ -1987,12 +2040,6 @@ msgstr "Forget All..." msgid "Tabbed preferences" msgstr "Tabbed preferences" -msgid "Open Recent" -msgstr "Open Recent" - -msgid "Quit" -msgstr "Quit" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "Do you want to save the changes you made in '%s'?" @@ -2025,6 +2072,9 @@ msgstr "Audio on" msgid "Audio off" msgstr "Audio off" +msgid "Find source" +msgstr "Find source" + msgid "Pd" msgstr "Pd" diff --git a/po/eo.po b/po/eo.po index 2edbc91cd6..4116dad844 100644 --- a/po/eo.po +++ b/po/eo.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.54.1\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2024-08-28 18:54+0200\n" "Last-Translator: phlostically \n" "Language-Team: Esperanto \n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" +"PO-Revision-Date: 2025-05-26 23:57+0000\n" +"Last-Translator: umläute \n" "Language-Team: Spanish \n" "Language: es\n" @@ -22,7 +22,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 3.4.4\n" +"X-Generator: Weblate 5.12-dev\n" msgid "linear" msgstr "Lineal" @@ -295,6 +295,9 @@ msgstr "Margen:" msgid "Y range: from" msgstr "Rango Y: de" +msgid "Object:" +msgstr "Objeto:" + msgid "Data Properties" msgstr "Propiedades de los datos" @@ -699,7 +702,7 @@ msgstr "" #, tcl-format msgid "using font: %1$s %2$s" -msgstr "se utilizaá la fuente: %1$s %2$s" +msgstr "Utilizando fuente: %1$s %2$s" #, tcl-format msgid "'%1$s' already loaded, ignoring: '%2$s'" @@ -840,12 +843,24 @@ msgstr "No se pudo eliminar el archivo suelto '%s'" msgid "Unable to rename downloaded file to '%s'" msgstr "No se pudo renombrar el archivo descargado a '%s'" +msgid "Search URLs:" +msgstr "Buscar URLs" + +msgid "Additional search URLs" +msgstr "Búsqueda adicional de URLs" + +msgid "Ephemeral search URLs" +msgstr "URL de búsqueda efímeras" + msgid "Create" msgstr "Crear" msgid "Check" msgstr "Probar" +msgid "Deken Installation Target" +msgstr "Ruta de destino de instalación de Deken" + msgid "Installation options:" msgstr "Opciones de instalación:" @@ -916,6 +931,21 @@ msgstr "Archivos TAR" msgid "All Files" msgstr "Todos los archivos" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "Instalando arquitectura incompatible de '%s'." + +msgid "Replacing library with incompatible architecture!" +msgstr "Reemplazando librería con arquitectura incompatible!!!" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" +"Desea reemplazar la librería '%1$s' en '%2$s' con una versión que es " +"incompatible con su computadora?" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "Desinstalando la instalación preexistente de '%s'" @@ -1110,13 +1140,13 @@ msgstr "" msgid "Installing to non-existent directory failed" msgstr "Falló la installación al directorio no existente" +msgid "Directory does not exist!" +msgstr "¡El directorio no existe!" + #, tcl-format msgid "Unable to install to '%s'" msgstr "No se pudo instalar '%s'" -msgid "Directory does not exist!" -msgstr "¡El directorio no existe!" - msgid "Directory is not writable!" msgstr "¡El directorio no permite escritura!" @@ -1155,6 +1185,10 @@ msgstr "[deken] deken-plugin.tcl (búsqueda de externos para Pd) cargado de %s." msgid "[deken] Platform detected: %s" msgstr "[deken] plataforma detectada: %s" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "No se pudo encontrar un menú para agregar '%s'" + #, tcl-format msgid "Searching on %s..." msgstr "Buscando %s..." @@ -1821,6 +1855,16 @@ msgstr "(Idioma predeterminado: %s)" msgid "Print..." msgstr "Imprimir..." +msgid "single precision" +msgstr "precisión simple" + +msgid "double precision" +msgstr "precisión doble" + +#, tcl-format +msgid "%dbit-floats" +msgstr "flotante %d-bits" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "ignorando '%s': el archivo no existe" @@ -1832,24 +1876,42 @@ msgstr "Sobre Pd" msgid "couldn't read \"%s\" document" msgstr "no se pudo leer el documento \"%s\"" +msgid "New" +msgstr "Nuevo" + +msgid "Open" +msgstr "Abrir" + +msgid "Open Recent" +msgstr "Abrir recientes" + msgid "Save" msgstr "Guardar" msgid "Save As..." msgstr "Guardar como..." +msgid "Quit" +msgstr "Salir" + +msgid "Undo" +msgstr "Deshacer" + +msgid "Redo" +msgstr "Rehacer" + +msgid "Cut" +msgstr "Cortar" + msgid "Paste Replace" msgstr "Pegar y reemplazar" +msgid "Select All" +msgstr "Seleccionar todo" + msgid "Duplicate" msgstr "Duplicar" -msgid "Zoom In" -msgstr "Acercar" - -msgid "Zoom Out" -msgstr "Alejar" - msgid "Tidy Up" msgstr "Ordenar" @@ -1859,33 +1921,18 @@ msgstr "(Des)Conectar selección" msgid "Triggerize" msgstr "Triggerizar" -msgid "Edit Mode" -msgstr "Modo edición" - -msgid "Undo" -msgstr "Deshacer" - -msgid "Redo" -msgstr "Rehacer" - -msgid "New" -msgstr "Nuevo" - -msgid "Open" -msgstr "Abrir" - -msgid "Message..." -msgstr "Mensaje..." - -msgid "Cut" -msgstr "Cortar" +msgid "Zoom In" +msgstr "Acercar" -msgid "Select All" -msgstr "Seleccionar todo" +msgid "Zoom Out" +msgstr "Alejar" msgid "Clear Console" msgstr "Limpiar consola" +msgid "Edit Mode" +msgstr "Modo edición" + msgid "Object" msgstr "Objeto" @@ -1949,9 +1996,15 @@ msgstr "Ventana siguiente" msgid "Previous Window" msgstr "Ventana anterior" +msgid "Close subwindows" +msgstr "Cerrar sub-ventanas" + msgid "Parent Window" msgstr "Ventana contenedora" +msgid "Message..." +msgstr "Mensaje..." + msgid "HTML Manual..." msgstr "Manual HTML..." @@ -2004,12 +2057,6 @@ msgstr "Olvidar..." msgid "Tabbed preferences" msgstr "Preferencias por pestañas" -msgid "Open Recent" -msgstr "Abrir recientes" - -msgid "Quit" -msgstr "Salir" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "¿Desea guardar los cambios realizados en '%s'?" @@ -2042,6 +2089,9 @@ msgstr "Audio encendido" msgid "Audio off" msgstr "Audio apagado" +msgid "Find source" +msgstr "Encontrar origen" + msgid "Pd" msgstr "Pd" diff --git a/po/eu.po b/po/eu.po index 77cfe6123b..b78a408984 100644 --- a/po/eu.po +++ b/po/eu.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.43\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2022-10-30 07:04+0000\n" "Last-Translator: Max Neupert \n" "Language-Team: Basque \n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" +"PO-Revision-Date: 2025-05-26 23:57+0000\n" +"Last-Translator: umläute \n" "Language-Team: French \n" "Language: fr\n" @@ -20,7 +20,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Poedit 3.4.4\n" +"X-Generator: Weblate 5.12-dev\n" msgid "linear" msgstr "linéaire" @@ -291,6 +291,9 @@ msgstr "Marges :" msgid "Y range: from" msgstr "Intervalle Y : de" +msgid "Object:" +msgstr "Objet :" + msgid "Data Properties" msgstr "Propriétés des données" @@ -837,12 +840,24 @@ msgstr "Impossible d'effacer le ficher temporaire '%s'" msgid "Unable to rename downloaded file to '%s'" msgstr "Impossible de donner au fichier téléchargé le nom '%s'" +msgid "Search URLs:" +msgstr "URL de recherche :" + +msgid "Additional search URLs" +msgstr "URL de recherche supplémentaires" + +msgid "Ephemeral search URLs" +msgstr "URL de recherche éphémères" + msgid "Create" msgstr "Créer" msgid "Check" msgstr "Vérifier" +msgid "Deken Installation Target" +msgstr "Destination d'installation pour Deken" + msgid "Installation options:" msgstr "Options d'installation :" @@ -917,6 +932,21 @@ msgstr "Fichiers TAR" msgid "All Files" msgstr "Tous les fichiers" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "Installation d'une architecture incompatible avec '%s'." + +msgid "Replacing library with incompatible architecture!" +msgstr "Remplacement d'une bibliothèque par une architecture incompatible !" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" +"Voulez-vous remplacer la bibliothèque '%1$s' dans '%2$s' par une version " +"incompatible avec votre ordinateur ?" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "Désinstallation de la version précédente de '%s'" @@ -1121,13 +1151,13 @@ msgstr "" msgid "Installing to non-existent directory failed" msgstr "L'installation a échoué : le répertoire n'existe pas" +msgid "Directory does not exist!" +msgstr "Le répertoire n'existe pas !" + #, tcl-format msgid "Unable to install to '%s'" msgstr "Échec de l'installation de %s" -msgid "Directory does not exist!" -msgstr "Le répertoire n'existe pas !" - msgid "Directory is not writable!" msgstr "Le répertoire n'est pas accessible en écriture !" @@ -1166,6 +1196,10 @@ msgstr "[deken] deken-plugin.tcl (recherche d'externals Pd) chargé depuis %s." msgid "[deken] Platform detected: %s" msgstr "[deken] Plateforme détectée : %s" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "Impossible de trouver un menu où ajouter '%s'" + #, tcl-format msgid "Searching on %s..." msgstr "Recherche de %s..." @@ -1834,6 +1868,16 @@ msgstr "(langue par défaut : %s)" msgid "Print..." msgstr "Imprimer..." +msgid "single precision" +msgstr "simple précision" + +msgid "double precision" +msgstr "double précision" + +#, tcl-format +msgid "%dbit-floats" +msgstr "%dbit flottants" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "ignorer '%s' : n'existe pas" @@ -1845,24 +1889,42 @@ msgstr "À propos de Pd" msgid "couldn't read \"%s\" document" msgstr "impossible de lire le document \"%s\"" +msgid "New" +msgstr "Nouveau" + +msgid "Open" +msgstr "Ouvrir" + +msgid "Open Recent" +msgstr "Ouvrir un élément récent" + msgid "Save" msgstr "Enregistrer" msgid "Save As..." msgstr "Enregistrer sous..." +msgid "Quit" +msgstr "Quitter" + +msgid "Undo" +msgstr "Défaire" + +msgid "Redo" +msgstr "Refaire" + +msgid "Cut" +msgstr "Couper" + msgid "Paste Replace" msgstr "Coller Remplacer" +msgid "Select All" +msgstr "Tout sélectionner" + msgid "Duplicate" msgstr "Dupliquer" -msgid "Zoom In" -msgstr "Zoomer" - -msgid "Zoom Out" -msgstr "Dézoomer" - msgid "Tidy Up" msgstr "Aligner" @@ -1872,33 +1934,18 @@ msgstr "(Dé)Connecter la sélection" msgid "Triggerize" msgstr "Triggeriser" -msgid "Edit Mode" -msgstr "Mode édition" - -msgid "Undo" -msgstr "Défaire" - -msgid "Redo" -msgstr "Refaire" - -msgid "New" -msgstr "Nouveau" - -msgid "Open" -msgstr "Ouvrir" - -msgid "Message..." -msgstr "Message..." - -msgid "Cut" -msgstr "Couper" +msgid "Zoom In" +msgstr "Zoomer" -msgid "Select All" -msgstr "Tout sélectionner" +msgid "Zoom Out" +msgstr "Dézoomer" msgid "Clear Console" msgstr "Effacer la console" +msgid "Edit Mode" +msgstr "Mode édition" + msgid "Object" msgstr "Objet" @@ -1962,9 +2009,15 @@ msgstr "Fenêtre suivante" msgid "Previous Window" msgstr "Fenêtre précédente" +msgid "Close subwindows" +msgstr "Fermer les sous-patchs" + msgid "Parent Window" msgstr "Fenêtre parente" +msgid "Message..." +msgstr "Message..." + msgid "HTML Manual..." msgstr "Manuel HTML..." @@ -2017,12 +2070,6 @@ msgstr "Tout oublier..." msgid "Tabbed preferences" msgstr "Préférences en onglet" -msgid "Open Recent" -msgstr "Ouvrir un élément récent" - -msgid "Quit" -msgstr "Quitter" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "Enregistrer les modifications de '%s' ?" @@ -2055,6 +2102,9 @@ msgstr "Audio On" msgid "Audio off" msgstr "Audio Off" +msgid "Find source" +msgstr "Localiser la source" + msgid "Pd" msgstr "Pd" diff --git a/po/gu.po b/po/gu.po index 4fe5d5e459..10ad3ba204 100644 --- a/po/gu.po +++ b/po/gu.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data-0.43\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2005-09-14 12:49+0530\n" "Last-Translator: Ankit Patel \n" "Language-Team: Gujarati \n" -"Language-Team: Hebrew \n" +"Language-Team: Hebrew \n" "Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && " "n % 10 == 0) ? 2 : 3));\n" -"X-Generator: Weblate 5.8.2\n" +"X-Generator: Weblate 5.12-dev\n" msgid "linear" msgstr "קווי" @@ -286,6 +286,9 @@ msgstr "גבול:" msgid "Y range: from" msgstr "טווח Y: התחלה" +msgid "Object:" +msgstr "עצם:" + msgid "Data Properties" msgstr "מאפייני נתונים" @@ -827,12 +830,24 @@ msgstr "לא ניתן להסיר את הקובץ התועה ‚%s’" msgid "Unable to rename downloaded file to '%s'" msgstr "לא ניתן לשנות את שם הקובץ שירד לשם ‚%s’" +msgid "Search URLs:" +msgstr "כתובות חיפוש:" + +msgid "Additional search URLs" +msgstr "כתובות חיפוש נוספות" + +msgid "Ephemeral search URLs" +msgstr "כתובות חיפוש מתחלפות" + msgid "Create" msgstr "יצירה" msgid "Check" msgstr "בדיקה" +msgid "Deken Installation Target" +msgstr "יעד התקנת Deken" + msgid "Installation options:" msgstr "אפשרויות התקנה:" @@ -902,6 +917,19 @@ msgstr "קובצי Tar" msgid "All Files" msgstr "כל הקבצים" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "מתבצעת התקנה של ארכיטקטורת ‚%s’ שאינה נתמכת." + +msgid "Replacing library with incompatible architecture!" +msgstr "הספרייה מוחלפת בארכיטקטורה לא תואמת!" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "להחליף את הספרייה ‚%1$s’ בספרייה ‚%2$s’ עם גרסה שאינה תואמת למחשב שלך?" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "התקנות קודמות של ‚%s’ נמחקות" @@ -1091,13 +1119,13 @@ msgstr "ההורדה של ‚%s’ מבוטלת: לא סופקה תיקיית ה msgid "Installing to non-existent directory failed" msgstr "התקנה לתיקייה שאינה קיימת נכשלה" +msgid "Directory does not exist!" +msgstr "התיקייה לא קיימת!" + #, tcl-format msgid "Unable to install to '%s'" msgstr "לא ניתן להתקין אל ‚%s’" -msgid "Directory does not exist!" -msgstr "התיקייה לא קיימת!" - msgid "Directory is not writable!" msgstr "התיקייה נעולה לכתיבה!" @@ -1136,6 +1164,10 @@ msgstr "[deken] deken-plugin.tcl (חיפוש חיצוניות של Pd) נטען msgid "[deken] Platform detected: %s" msgstr "[deken] התגלתה פלטפורמה: %s" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "לא ניתן למצוא תפריט להוספת ‚%s’" + #, tcl-format msgid "Searching on %s..." msgstr "מתבצע חיפוש ב־%s…" @@ -1801,6 +1833,16 @@ msgstr "(שפת ברירת המחדל: %s)" msgid "Print..." msgstr "הדפסה…" +msgid "single precision" +msgstr "דיוק יחיד" + +msgid "double precision" +msgstr "דיוק כפול" + +#, tcl-format +msgid "%dbit-floats" +msgstr "נק׳ צפה ב־%d סיביות" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "התעלמות מ־‚%s’: לא קיים" @@ -1812,24 +1854,42 @@ msgstr "על Pd" msgid "couldn't read \"%s\" document" msgstr "לא ניתן לקרוא את המסמך „%s”" +msgid "New" +msgstr "חדש" + +msgid "Open" +msgstr "פתיחה" + +msgid "Open Recent" +msgstr "לפתוח אחרונים" + msgid "Save" msgstr "שמירה" msgid "Save As..." msgstr "שמירה בשם…" +msgid "Quit" +msgstr "יציאה" + +msgid "Undo" +msgstr "החזרה" + +msgid "Redo" +msgstr "ביצוע חוזר" + +msgid "Cut" +msgstr "גזירה" + msgid "Paste Replace" msgstr "הדבקה והחלפה" +msgid "Select All" +msgstr "בחירה בהכול" + msgid "Duplicate" msgstr "שכפול" -msgid "Zoom In" -msgstr "התקרבות" - -msgid "Zoom Out" -msgstr "התרחקות" - msgid "Tidy Up" msgstr "סדר וניקיון" @@ -1839,33 +1899,18 @@ msgstr "חיבור/ניתוק בחירה" msgid "Triggerize" msgstr "הפיכה לגורם הפעלה" -msgid "Edit Mode" -msgstr "מצב עריכה" - -msgid "Undo" -msgstr "החזרה" - -msgid "Redo" -msgstr "ביצוע חוזר" - -msgid "New" -msgstr "חדש" - -msgid "Open" -msgstr "פתיחה" - -msgid "Message..." -msgstr "הודעה…" - -msgid "Cut" -msgstr "גזירה" +msgid "Zoom In" +msgstr "התקרבות" -msgid "Select All" -msgstr "בחירה בהכול" +msgid "Zoom Out" +msgstr "התרחקות" msgid "Clear Console" msgstr "מחיקת מסוף" +msgid "Edit Mode" +msgstr "מצב עריכה" + msgid "Object" msgstr "עצם" @@ -1929,9 +1974,15 @@ msgstr "החלון הבא" msgid "Previous Window" msgstr "החלון הקודם" +msgid "Close subwindows" +msgstr "סגירת תת־חלונות" + msgid "Parent Window" msgstr "חלון ההורה" +msgid "Message..." +msgstr "הודעה…" + msgid "HTML Manual..." msgstr "מדריך HTML…" @@ -1984,12 +2035,6 @@ msgstr "שיכחה של הכול…" msgid "Tabbed preferences" msgstr "העדפות בלשוניות" -msgid "Open Recent" -msgstr "לפתוח אחרונים" - -msgid "Quit" -msgstr "יציאה" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "לשמור את השינויים שבוצעו אל ‚%s’?" @@ -2022,6 +2067,9 @@ msgstr "שמע פעיל" msgid "Audio off" msgstr "שמע כבוי" +msgid "Find source" +msgstr "איתור מקור" + msgid "Pd" msgstr "Pd" diff --git a/po/hi.po b/po/hi.po index 8f94600d54..8c71ebc041 100644 --- a/po/hi.po +++ b/po/hi.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.43\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2005-05-04 12:50+0530\n" "Last-Translator: Rajesh Ranjan \n" "Language-Team: Hindi \n" "Language-Team: Hungarian \n" "Language-Team: Indonesian \n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" +"PO-Revision-Date: 2025-05-26 23:57+0000\n" +"Last-Translator: umläute \n" "Language-Team: Italian \n" "Language: it\n" @@ -19,7 +19,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 3.4.4\n" +"X-Generator: Weblate 5.12-dev\n" msgid "linear" msgstr "lineare" @@ -291,6 +291,9 @@ msgstr "Margine:" msgid "Y range: from" msgstr "Intervallo Y: da" +msgid "Object:" +msgstr "Oggetto:" + msgid "Data Properties" msgstr "Proprietà Dati" @@ -835,12 +838,27 @@ msgstr "Impossibile rimuovere il file randagio '%s'" msgid "Unable to rename downloaded file to '%s'" msgstr "Impossibile rinominare il file scaricato in '%s'" +#, fuzzy +msgid "Search URLs:" +msgstr "Risultati della Ricerca" + +#, fuzzy +msgid "Additional search URLs" +msgstr "%s aggiunto ai percorsi di ricerca" + +msgid "Ephemeral search URLs" +msgstr "" + msgid "Create" msgstr "Crea" msgid "Check" msgstr "Controlla" +#, fuzzy +msgid "Deken Installation Target" +msgstr "Installazione non riuscita!" + msgid "Installation options:" msgstr "Opzioni di installazione:" @@ -911,6 +929,19 @@ msgstr "File TAR" msgid "All Files" msgstr "Tutti i file" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "" + +msgid "Replacing library with incompatible architecture!" +msgstr "" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "Disinstallazione della precedente installazione di '%s'" @@ -1109,13 +1140,13 @@ msgstr "" msgid "Installing to non-existent directory failed" msgstr "Installazione su una cartella non esistente fallita" +msgid "Directory does not exist!" +msgstr "La cartella non esiste!" + #, tcl-format msgid "Unable to install to '%s'" msgstr "Impossibile installare in '%s'" -msgid "Directory does not exist!" -msgstr "La cartella non esiste!" - msgid "Directory is not writable!" msgstr "Non è possibile scrivere nella cartella!" @@ -1154,6 +1185,10 @@ msgstr "[deken] deken-plugin.tcl (ricerca di externals di Pd) caricato da %s." msgid "[deken] Platform detected: %s" msgstr "[deken] Piattaforma identificata: %s" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "" + #, tcl-format msgid "Searching on %s..." msgstr "Ricerca su %s..." @@ -1822,6 +1857,16 @@ msgstr "Lingua di default: %s" msgid "Print..." msgstr "Stampa..." +msgid "single precision" +msgstr "" + +msgid "double precision" +msgstr "doppia precisione" + +#, tcl-format +msgid "%dbit-floats" +msgstr "%dbit-floats" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "ignoro '%s': non esiste" @@ -1833,24 +1878,42 @@ msgstr "Informazioni su Pd" msgid "couldn't read \"%s\" document" msgstr "impossibile leggere il documento \"%s\"" +msgid "New" +msgstr "Nuovo File" + +msgid "Open" +msgstr "Apri File..." + +msgid "Open Recent" +msgstr "Apri recenti" + msgid "Save" msgstr "Salva" msgid "Save As..." msgstr "Salva con nome..." +msgid "Quit" +msgstr "Esci" + +msgid "Undo" +msgstr "Annulla" + +msgid "Redo" +msgstr "Ripristina" + +msgid "Cut" +msgstr "Taglia" + msgid "Paste Replace" msgstr "Incolla e Sostituisci" +msgid "Select All" +msgstr "Seleziona tutto" + msgid "Duplicate" msgstr "Duplica" -msgid "Zoom In" -msgstr "Zoom Avanti" - -msgid "Zoom Out" -msgstr "Zoom Indietro" - msgid "Tidy Up" msgstr "Allinea elementi" @@ -1860,33 +1923,18 @@ msgstr "(Dis)Connetti Selezionati" msgid "Triggerize" msgstr "Triggerizza" -msgid "Edit Mode" -msgstr "Modalità modifica" - -msgid "Undo" -msgstr "Annulla" - -msgid "Redo" -msgstr "Ripristina" - -msgid "New" -msgstr "Nuovo File" - -msgid "Open" -msgstr "Apri File..." - -msgid "Message..." -msgstr "Messaggio..." - -msgid "Cut" -msgstr "Taglia" +msgid "Zoom In" +msgstr "Zoom Avanti" -msgid "Select All" -msgstr "Seleziona tutto" +msgid "Zoom Out" +msgstr "Zoom Indietro" msgid "Clear Console" msgstr "Pulisci console" +msgid "Edit Mode" +msgstr "Modalità modifica" + msgid "Object" msgstr "Oggetto" @@ -1950,9 +1998,16 @@ msgstr "Finestra Successiva" msgid "Previous Window" msgstr "Finestra Precedente" +#, fuzzy +msgid "Close subwindows" +msgstr "Chiudere questa finestra??" + msgid "Parent Window" msgstr "Finestra parent" +msgid "Message..." +msgstr "Messaggio..." + msgid "HTML Manual..." msgstr "Manuale HTML..." @@ -2005,12 +2060,6 @@ msgstr "Rimuovi Tutte..." msgid "Tabbed preferences" msgstr "Preferenze Tab" -msgid "Open Recent" -msgstr "Apri recenti" - -msgid "Quit" -msgstr "Esci" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "Salvare le modifiche apportate a '%s'?" @@ -2043,6 +2092,10 @@ msgstr "Audio attivo" msgid "Audio off" msgstr "Audio inattivo" +#, fuzzy +msgid "Find source" +msgstr "Trova l'ultimo errore" + msgid "Pd" msgstr "Pd" @@ -2144,9 +2197,6 @@ msgstr "ignoro '%s': non sembra un file Pd" #~ msgid "Signal" #~ msgstr "Segnali" -#~ msgid "Close this window??" -#~ msgstr "Chiudere questa finestra??" - #~ msgid "Output device 4:" #~ msgstr "Dispositivo di uscita 4:" diff --git a/po/ja.po b/po/ja.po index 9c900eb637..4eeb80bcfb 100644 --- a/po/ja.po +++ b/po/ja.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.53.0\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2024-07-08 17:20+0200\n" "Last-Translator: umläute \n" "Language-Team: Japanese \n" "Language-Team: Korean \n" "Language-Team: Dutch \n" "Language-Team: Punjabi \n" "Language-Team: Polish \n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" +"PO-Revision-Date: 2025-05-26 23:57+0000\n" +"Last-Translator: umläute \n" "Language-Team: Portuguese (Brazil) \n" -"Language: pt_BR\n" +"Language: pt_br\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Poedit 3.4.4\n" +"X-Generator: Weblate 5.12-dev\n" msgid "linear" msgstr "linear" @@ -289,6 +289,9 @@ msgstr "Margem:" msgid "Y range: from" msgstr "Registro de Y: de" +msgid "Object:" +msgstr "Objeto:" + msgid "Data Properties" msgstr "Propriedades da Estrutura de Dados" @@ -831,12 +834,26 @@ msgstr "Incapaz de remover arquivo 'stray' '%s'" msgid "Unable to rename downloaded file to '%s'" msgstr "Incapaz de renomear arquivo baixado de '%s'" +msgid "Search URLs:" +msgstr "Procurar URLs:" + +#, fuzzy +msgid "Additional search URLs" +msgstr "%s adicionado aos caminhos de busca" + +msgid "Ephemeral search URLs" +msgstr "" + msgid "Create" msgstr "Criar" msgid "Check" msgstr "Checar" +#, fuzzy +msgid "Deken Installation Target" +msgstr "Instalação falhou!" + msgid "Installation options:" msgstr "Opções de instalação:" @@ -906,6 +923,19 @@ msgstr "Arquivos TAR" msgid "All Files" msgstr "Todos os Arquivos" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "" + +msgid "Replacing library with incompatible architecture!" +msgstr "" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "Desinstalando instalação prévia de '%s'" @@ -1098,13 +1128,13 @@ msgstr "Cancelando download de '%s': Nenhum diretório de instalação fornecido msgid "Installing to non-existent directory failed" msgstr "Falha ao instalar em um diretório não existente" +msgid "Directory does not exist!" +msgstr "Diretório não existe!" + #, tcl-format msgid "Unable to install to '%s'" msgstr "Incapaz de instalar em '%s'" -msgid "Directory does not exist!" -msgstr "Diretório não existe!" - msgid "Directory is not writable!" msgstr "Directório não é 'gravável'!" @@ -1143,6 +1173,10 @@ msgstr "[deken] deken-plugin.tcl (busca de externals Pd) carregado de %s." msgid "[deken] Platform detected: %s" msgstr "[deken] platforma detectada: %s" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "" + #, tcl-format msgid "Searching on %s..." msgstr "Procurando em %s..." @@ -1812,6 +1846,16 @@ msgstr "(idioma padrão: %s)" msgid "Print..." msgstr "Imprimir..." +msgid "single precision" +msgstr "precisão simples" + +msgid "double precision" +msgstr "precisão double" + +#, tcl-format +msgid "%dbit-floats" +msgstr "%dbit-floats" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "ignorando '%s': não existe" @@ -1823,24 +1867,42 @@ msgstr "Sobre o Pd" msgid "couldn't read \"%s\" document" msgstr "não foi possível ler o documento \"%s\"" +msgid "New" +msgstr "Novo" + +msgid "Open" +msgstr "Abrir" + +msgid "Open Recent" +msgstr "Abrir Recente" + msgid "Save" msgstr "Salvar" msgid "Save As..." msgstr "Salvar Como..." +msgid "Quit" +msgstr "Sair" + +msgid "Undo" +msgstr "Desfazer" + +msgid "Redo" +msgstr "Refazer" + +msgid "Cut" +msgstr "Cortar" + msgid "Paste Replace" msgstr "Colar Substituir" +msgid "Select All" +msgstr "Selecionar Tudo" + msgid "Duplicate" msgstr "Duplicar" -msgid "Zoom In" -msgstr "Ampliar Zoom" - -msgid "Zoom Out" -msgstr "Reduzir Zoom" - msgid "Tidy Up" msgstr "Organizar" @@ -1850,33 +1912,18 @@ msgstr "(Des)Conectar Seleção" msgid "Triggerize" msgstr "Triggerize" -msgid "Edit Mode" -msgstr "Modo de Edição" - -msgid "Undo" -msgstr "Desfazer" - -msgid "Redo" -msgstr "Refazer" - -msgid "New" -msgstr "Novo" - -msgid "Open" -msgstr "Abrir" - -msgid "Message..." -msgstr "Mensagem..." - -msgid "Cut" -msgstr "Cortar" +msgid "Zoom In" +msgstr "Ampliar Zoom" -msgid "Select All" -msgstr "Selecionar Tudo" +msgid "Zoom Out" +msgstr "Reduzir Zoom" msgid "Clear Console" msgstr "Limpar Console" +msgid "Edit Mode" +msgstr "Modo de Edição" + msgid "Object" msgstr "Objeto" @@ -1940,9 +1987,15 @@ msgstr "Próxima Janela" msgid "Previous Window" msgstr "Janela Anterior" +msgid "Close subwindows" +msgstr "" + msgid "Parent Window" msgstr "Janela Mãe" +msgid "Message..." +msgstr "Mensagem..." + msgid "HTML Manual..." msgstr "Manual em HTML..." @@ -1995,12 +2048,6 @@ msgstr "Esquecer Todas..." msgid "Tabbed preferences" msgstr "Preferências em abas" -msgid "Open Recent" -msgstr "Abrir Recente" - -msgid "Quit" -msgstr "Sair" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "Você deseja salvar as alterações feitas em '%s'?" @@ -2033,6 +2080,10 @@ msgstr "Áudio ligado" msgid "Audio off" msgstr "Áudio desligado" +#, fuzzy +msgid "Find source" +msgstr "Encontrar Último Erro" + msgid "Pd" msgstr "Pd" diff --git a/po/pt_pt.po b/po/pt_pt.po index 30a3efcc35..dad9678ae9 100644 --- a/po/pt_pt.po +++ b/po/pt_pt.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.43\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2024-07-08 17:33+0200\n" "Last-Translator: ssantos \n" "Language-Team: Portuguese (Portugal) \n" "Language-Team: Russian \n" "Language-Team: Albanian \n" "Language-Team: Swedish , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: Pure Data 0.55.0\n" +"Report-Msgid-Bugs-To: pd-dev@iem.at\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" +"PO-Revision-Date: 2025-06-16 02:48+0000\n" +"Last-Translator: தமிழ்நேரம் \n" +"Language-Team: Tamil \n" +"Language: ta\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12-dev\n" + +msgid "linear" +msgstr "நேரியல்" + +msgid "logarithmic" +msgstr "மடக்கை" + +msgid "new-only" +msgstr "புதியது மட்டுமே" + +msgid "new&old" +msgstr "புதிய & பழைய" + +msgid "no scale" +msgstr "அளவு இல்லை" + +msgid "scale" +msgstr "அளவு" + +#, tcl-format +msgid "Discard changes to '%s'?" +msgstr "'%s' இல் மாற்றங்களை நிராகரிக்கவா?" + +msgid "Undo clear" +msgstr "தெளிவுபடுத்துங்கள்" + +msgid "Undo connect" +msgstr "இணைக்கவும்" + +msgid "Undo cut" +msgstr "வெட்டு செயல்தவிர்க்கவும்" + +msgid "Undo disconnect" +msgstr "துண்டிக்கவும்" + +msgid "Undo duplicate" +msgstr "நகல் செயல்தவிர்க்கவும்" + +msgid "Undo motion" +msgstr "இயக்கத்தை செயல்தவிர்க்கவும்" + +msgid "Undo paste" +msgstr "ஒட்டவும்" + +msgid "Undo typing" +msgstr "தட்டச்சு செய்வதை செயல்தவிர்க்கவும்" + +msgid "Redo clear" +msgstr "மீண்டும் தெளிவாக" + +msgid "Redo connect" +msgstr "மீண்டும் இணைக்கவும்" + +msgid "Redo cut" +msgstr "மீண்டும் வெட்டு" + +msgid "Redo disconnect" +msgstr "மீண்டும் துண்டிக்கவும்" + +msgid "Redo duplicate" +msgstr "மீண்டும் நகல்" + +msgid "Redo motion" +msgstr "மீண்டும் இயக்கம்" + +msgid "Redo paste" +msgstr "சுற்று பேச்ட்" + +msgid "Redo typing" +msgstr "மீண்டும் தட்டச்சு" + +msgid "no Pd settings to clear" +msgstr "அழிக்க பி.டி அமைப்புகள் இல்லை" + +msgid "removed .pdsettings file" +msgstr "அகற்றப்பட்டது .pdsettings கோப்பு" + +msgid "couldn't delete .pdsettings file" +msgstr ".ptsettings கோப்பை நீக்க முடியவில்லை" + +msgid "failed to erase Pd settings" +msgstr "பி.டி அமைப்புகளை அழிக்கத் தவறிவிட்டது" + +msgid "erased Pd settings" +msgstr "பி.டி அமைப்புகள் அழிக்கப்பட்டன" + +msgid "no Pd settings to erase" +msgstr "அழிக்க பி.டி அமைப்புகள் இல்லை" + +msgid "skipping loading preferences... Pd seems to have crashed on startup" +msgstr "ஏற்றுதல் விருப்பங்களைத் தவிர்ப்பது... தொடக்கத்தில் பிடி தொங்கிவிட்டது" + +msgid "(re-save preferences to reinstate them)" +msgstr "(அவற்றை மீண்டும் நிலைநிறுத்த விருப்பங்களை மீண்டும் சேமிக்கவும்)" + +msgid "File" +msgstr "கோப்பு" + +msgid "Edit" +msgstr "தொகு" + +msgid "Put" +msgstr "போடு" + +msgid "Find" +msgstr "கண்டுபிடி" + +msgid "Media" +msgstr "ஊடகம்" + +msgid "Window" +msgstr "சாளரம்" + +msgid "Help" +msgstr "உதவி" + +msgid "Show &Hidden Files and Directories" +msgstr "மறைக்கப்பட்ட கோப்புகள் மற்றும் கோப்பகங்களைக் காட்டு" + +msgid "Copy" +msgstr "நகலெடு" + +msgid "Paste" +msgstr "ஒட்டு" + +msgid "Array Properties" +msgstr "வரிசை பண்புகள்" + +msgid "Array" +msgstr "வரிசை" + +msgid "Name:" +msgstr "பெயர்:" + +msgid "Size:" +msgstr "அளவு:" + +msgid "Save contents" +msgstr "உள்ளடக்கங்களை சேமிக்கவும்" + +msgid "Draw as:" +msgstr "இவ்வாறு வரையவும்:" + +msgid "Polygon" +msgstr "பலகோணம்" + +msgid "Points" +msgstr "பிரிவகம்" + +msgid "Bezier curve" +msgstr "பெசியர் வளைவு" + +msgid "Put array into:" +msgstr "வரிசையை வைக்கவும்:" + +msgid "New graph" +msgstr "புதிய வரைபடம்" + +msgid "Last graph" +msgstr "கடைசி வரைபடம்" + +msgid "Options" +msgstr "விருப்பங்கள்" + +msgid "Open List View..." +msgstr "திறந்த பட்டியல் பார்வை ..." + +msgid "Delete array" +msgstr "வரிசையை நீக்கு" + +msgid "Cancel" +msgstr "ரத்துசெய்" + +msgid "Apply" +msgstr "இடு" + +msgid "OK" +msgstr "சரி" + +msgid "no device" +msgstr "சாதனம் இல்லை" + +msgid "(same as input device)..." +msgstr "(உள்ளீட்டு சாதனம் போன்றது) ..." + +msgid "Channels:" +msgstr "சேனல்கள்:" + +msgid "Input Devices" +msgstr "உள்ளீட்டு சாதனங்கள்" + +msgid "Output Devices" +msgstr "வெளியீட்டு சாதனங்கள்" + +msgid "Use Multiple Devices" +msgstr "பல சாதனங்களைப் பயன்படுத்துங்கள்" + +msgid "Audio System" +msgstr "ஆடியோ அமைப்பு" + +msgid "Settings" +msgstr "அமைப்புகள்" + +msgid "Sample rate:" +msgstr "மாதிரி வீதம்:" + +msgid "Delay (msec):" +msgstr "நேரந்தவறுகை (MSEC):" + +msgid "48k" +msgstr "48 கே" + +msgid "44.1k" +msgstr "44.1 கே" + +msgid "96k" +msgstr "உங்கள் பூனை" + +msgid "Block size:" +msgstr "தொகுதி அளவு:" + +msgid "Use callbacks" +msgstr "கால்பேக்குகளைப் பயன்படுத்தவும்" + +msgid "Audio Settings" +msgstr "ஆடியோ அமைப்புகள்" + +msgid "Save All Settings" +msgstr "எல்லா அமைப்புகளையும் சேமிக்கவும்" + +msgid "WARNING: unknown graphme flags received in pdtk_canvas_dialog" +msgstr "எச்சரிக்கை: PDTK_CANVAS_DIALOG இல் பெறப்பட்ட அறியப்படாத வரைபடக் கொடிகள்" + +msgid "Canvas Properties" +msgstr "கேன்வாச் பண்புகள்" + +msgid "Scale" +msgstr "அளவு" + +msgid "X units per pixel:" +msgstr "பிக்சலுக்கு ஃச் அலகுகள்:" + +msgid "Y units per pixel:" +msgstr "பிக்சலுக்கு ஒய் அலகுகள்:" + +msgid "Appearance on parent patch" +msgstr "பெற்றோர் பேட்சில் தோற்றம்" + +msgid "Graph-On-Parent" +msgstr "வரைபடம்-பெற்றோர்" + +msgid "Hide object name and arguments" +msgstr "பொருள் பெயர் மற்றும் வாதங்களை மறைக்கவும்" + +msgid "Range and size" +msgstr "வரம்பு மற்றும் அளவு" + +msgid "X range: from" +msgstr "ஃச் வரம்பு: இருந்து" + +msgid "to" +msgstr "பெறுநர்" + +msgid "Margin:" +msgstr "விளிம்பு:" + +msgid "Y range: from" +msgstr "ஒய் வரம்பு: இருந்து" + +msgid "Object:" +msgstr "பொருள்:" + +msgid "Data Properties" +msgstr "தரவு பண்புகள்" + +msgid "Send" +msgstr "அனுப்பு" + +msgid "Done" +msgstr "முடிந்தது" + +#, tcl-format +msgid "Found '%1$s' in %2$s" +msgstr "%2$s இல் ' %1$s' காணப்பட்டது" + +#, tcl-format +msgid "Couldn't find '%1$s' in %2$s" +msgstr "%2$s இல் ' %1$s' கண்டுபிடிக்க முடியவில்லை" + +#, tcl-format +msgid "Search in %s for:" +msgstr "இதற்கு %s இல் தேடுங்கள்:" + +#, tcl-format +msgid "Showed last '%1$s' in %2$s" +msgstr "%2$s இல் கடைசி ' %1$s' காட்டப்பட்டது" + +#, tcl-format +msgid "Showing '%1$d' out of %2$d items in %3$s" +msgstr "%3$s இல் %2$d உருப்படிகளில் ' %1$d' ஐக் காட்டுகிறது" + +msgid "Pd window" +msgstr "பி.டி சாளரம்" + +msgid "Match whole word only" +msgstr "முழு வார்த்தையையும் மட்டுமே பொருத்துங்கள்" + +msgid "Close" +msgstr "மூடு" + +#, tcl-format +msgid "%s Font" +msgstr "%s எழுத்துரு" + +msgid "Font" +msgstr "எழுத்துரு" + +msgid "Font Size" +msgstr "எழுத்துரு அளவு" + +msgid "Stretch" +msgstr "நீட்டிக்க" + +msgid "X and Y" +msgstr "ஃச் மற்றும் ஒய்" + +msgid "X only" +msgstr "ஃச் மட்டும்" + +msgid "Y only" +msgstr "ஒய் மட்டும்" + +msgid "GUI Box Properties" +msgstr "GUI பெட்டி பண்புகள்" + +msgid "Messages" +msgstr "செய்திகள்" + +msgid "Send symbol:" +msgstr "சின்னத்தை அனுப்பு:" + +msgid "Receive symbol:" +msgstr "சின்னத்தைப் பெறுங்கள்:" + +msgid "auto" +msgstr "தானி" + +msgid "Width:" +msgstr "அகலம்:" + +msgid "Limits" +msgstr "வரம்புகள்" + +msgid "Lower:" +msgstr "கீழ்:" + +msgid "Upper:" +msgstr "மேல்:" + +msgid "Label" +msgstr "சிட்டை" + +msgid "Left" +msgstr "இடது" + +msgid "Right" +msgstr "வலது" + +msgid "Top" +msgstr "மேலே" + +msgid "Bottom" +msgstr "கீழே" + +msgid "Background color" +msgstr "பின்னணி நிறம்" + +msgid "Foreground color" +msgstr "முன்புற நிறம்" + +msgid "Label color" +msgstr "சிட்டை நிறம்" + +msgid "Bang" +msgstr "பேங்" + +msgid "Flash Time (msec)" +msgstr "ஃபிளாச் நேரம் (MSEC)" + +msgid "Min:" +msgstr "நிமிடம்:" + +msgid "Max:" +msgstr "அதிகபட்சம்:" + +msgid "Toggle" +msgstr "மாற்று" + +msgid "Non Zero Value" +msgstr "பூச்சியமற்ற மதிப்பு" + +msgid "Value:" +msgstr "மதிப்பு:" + +msgid "Number2" +msgstr "எண் 2" + +msgid "Width (digits):" +msgstr "அகலம் (இலக்கங்கள்):" + +msgid "Height:" +msgstr "உயரம்:" + +msgid "Output Range" +msgstr "வெளியீட்டு வரம்பு" + +msgid "Log height:" +msgstr "பதிவு உயரம்:" + +msgid "Vslider" +msgstr "செசறுக்கி" + +msgid "Hslider" +msgstr "கிசறுக்கி" + +msgid "Vradio" +msgstr "Vraday" + +msgid "Num cells:" +msgstr "எண் செல்கள்:" + +msgid "Hradio" +msgstr "இராடியோ" + +msgid "VU Meter" +msgstr "மீட்டர்" + +msgid "Canvas" +msgstr "கேன்வாச்" + +msgid "Visible Rectangle (pix)" +msgstr "புலப்படும் செவ்வகம் (பிக்ச்)" + +#, tcl-format +msgid "%s Properties" +msgstr "%s பண்புகள்" + +msgid "Parameters" +msgstr "அளவுருக்கள்" + +msgid "Init" +msgstr "தெடக்கம்" + +msgid "No init" +msgstr "துவக்கம் இல்லை" + +msgid "Jump on click" +msgstr "சொடுக்கு செய்யவும்" + +msgid "Steady on click" +msgstr "கிளிக்கில் நிலையானது" + +msgid "X offset:" +msgstr "ஃச் ஆஃப்செட்:" + +msgid "Y offset:" +msgstr "ஒய் ஆஃப்செட்:" + +msgid "Colors" +msgstr "நிறங்கள்" + +msgid "Background" +msgstr "பின்னணி" + +msgid "Front" +msgstr "முன்" + +msgid "Compose color" +msgstr "வண்ணத்தை இயற்றுங்கள்" + +msgid "Test label" +msgstr "சோதனை சிட்டை" + +msgid "Send a Pd message" +msgstr "ஒரு பி.டி செய்தியை அனுப்பவும்" + +msgid "(use arrow keys for history)" +msgstr "(வரலாற்றுக்கு அம்பு விசைகளைப் பயன்படுத்தவும்)" + +msgid "no input devices" +msgstr "உள்ளீட்டு சாதனங்கள் இல்லை" + +msgid "In Ports:" +msgstr "துறைமுகங்களில்:" + +msgid "Out Ports:" +msgstr "வெளியே துறைமுகங்கள்:" + +msgid "MIDI system" +msgstr "மிடி அமைப்பு" + +msgid "MIDI Settings" +msgstr "மிடி அமைப்புகள்" + +msgid "ALSA MIDI Settings" +msgstr "அல்சா மிடி அமைப்புகள்" + +msgid "Pd search path for objects, help, audio, text and other files" +msgstr "பொருள்கள், உதவி, ஆடியோ, உரை மற்றும் பிற கோப்புகளுக்கான பி.டி தேடல் பாதை" + +msgid "Use standard paths" +msgstr "நிலையான பாதைகளைப் பயன்படுத்துங்கள்" + +msgid "Verbose" +msgstr "வாய்மொழி" + +msgid "Pd Documents Directory" +msgstr "பி.டி ஆவணங்கள் அடைவு" + +msgid "Browse" +msgstr "உலாவு" + +msgid "Reset" +msgstr "மீட்டமை" + +msgid "Disable" +msgstr "முடக்கு" + +msgid "Externals Install Directory" +msgstr "வெளிப்புறங்கள் கோப்பகத்தை நிறுவுகின்றன" + +msgid "Clear" +msgstr "தெளிவான" + +msgid "path preferences" +msgstr "பாதை விருப்பத்தேர்வுகள்" + +msgid "Choose Pd documents directory:" +msgstr "PD ஆவணங்கள் கோப்பகத்தைத் தேர்வுசெய்க:" + +msgid "Install externals to directory:" +msgstr "கோப்பகத்திற்கு வெளிப்புறங்களை நிறுவவும்:" + +msgid "Add a new path" +msgstr "புதிய பாதையைச் சேர்க்கவும்" + +#, tcl-format +msgid "Edit existing path [%s]" +msgstr "இருக்கும் பாதையைத் திருத்தவும் [%s]" + +msgid "Patch Windows" +msgstr "இணைப்பு சன்னல்கள்" + +msgid "Zoom New Windows" +msgstr "புதிய சாளரங்களை பெரிதாக்கவும்" + +msgid "GUI Settings" +msgstr "GUI அமைப்புகள்" + +msgid "Preference layout (reopen the preferences to see the effect)" +msgstr "விருப்பத்தேர்வு தளவமைப்பு (விளைவைக் காண விருப்பங்களை மீண்டும் திறக்கவும்)" + +msgid "Use tabs" +msgstr "தாவல்களைப் பயன்படுத்தவும்" + +msgid "Single page" +msgstr "ஒற்றை பக்கம்" + +msgid "Patching helpers" +msgstr "உதவியாளர்களை ஒட்டுதல்" + +msgid "Highlight active cord while connecting" +msgstr "இணைக்கும்போது செயலில் உள்ள தண்டு முன்னிலைப்படுத்தவும்" + +msgid "Preferences" +msgstr "விருப்பத்தேர்வுகள்" + +msgid "startup preferences" +msgstr "தொடக்க விருப்பத்தேர்வுகள்" + +msgid "audio preferences" +msgstr "ஆடியோ விருப்பத்தேர்வுகள்" + +msgid "MIDI preferences" +msgstr "மிடி விருப்பத்தேர்வுகள்" + +msgid "deken preferences" +msgstr "போர்வை விருப்பத்தேர்வுகள்" + +msgid "misc preferences" +msgstr "தவறான விருப்பத்தேர்வுகள்" + +msgid "Add new library" +msgstr "புதிய நூலகத்தைச் சேர்க்கவும்" + +msgid "Edit library" +msgstr "நூலகத்தைத் திருத்து" + +msgid "Settings below require a restart of Pd!" +msgstr "கீழே உள்ள அமைப்புகளுக்கு பி.டி.யின் மறுதொடக்கம் தேவை!" + +msgid "Pd libraries to load on startup" +msgstr "தொடக்கத்தில் ஏற்ற பி.டி நூலகங்கள்" + +msgid "GUI Options" +msgstr "GUI விருப்பங்கள்" + +msgid "language" +msgstr "மொழி" + +msgid "Menu language" +msgstr "பட்டி மொழி" + +msgid "float (32bit)" +msgstr "மிதவை (32 பிட்)" + +msgid "double (64bit) EXPERIMENTAL" +msgstr "இரட்டை (64 பிட்) சோதனை" + +msgid "double (64bit)" +msgstr "இரட்டை (64 பிட்)" + +msgid "float size" +msgstr "மிதவை அளவு" + +msgid "Numeric precision of Pd-core" +msgstr "PD- கோரின் எண் துல்லியம்" + +msgid "Startup Options" +msgstr "தொடக்க விருப்பங்கள்" + +msgid "Defeat real-time scheduling" +msgstr "நிகழ்நேர திட்டமிடலை தோற்கடிக்கவும்" + +msgid "Startup Flags:" +msgstr "தொடக்க கொடிகள்:" + +msgid "Help Browser" +msgstr "உலாவிக்கு உதவுங்கள்" + +msgid "Associated Files" +msgstr "தொடர்புடைய கோப்புகள்" + +msgid "Pd Files" +msgstr "பி.டி கோப்புகள்" + +msgid "Max Patch Files" +msgstr "அதிகபட்ச இணைப்பு கோப்புகள்" + +msgid "Max Text Files" +msgstr "அதிகபட்ச உரை கோப்புகள்" + +msgid "Max Patch Files (.pat)" +msgstr "அதிகபட்ச ஒட்டு கோப்புகள் (.Pat)" + +msgid "Max Text Files (.mxt)" +msgstr "அதிகபட்ச உரை கோப்புகள் (.mxt)" + +#, tcl-format +msgid "detected font: %s" +msgstr "எழுத்துருக்களைக் கண்டறியவும்: %s" + +#, tcl-format +msgid "WARNING: font family '%1$s' not found, using default (%2$s)" +msgstr "" +"எச்சரிக்கை: எழுத்துரு குடும்பம் '%1$s' காணப்படவில்லை, இயல்புநிலையைப் பயன்படுத்தி (%2$s)" + +#, tcl-format +msgid "WARNING: font weight '%1$s' not found, using default (%2$s)" +msgstr "" +"எச்சரிக்கை: எழுத்துரு எடை '%1$s' காணப்படவில்லை, இயல்புநிலையைப் பயன்படுத்தி (%2$s)" + +#, tcl-format +msgid "using font: %1$s %2$s" +msgstr "எழுத்துருவைப் பயன்படுத்துதல்: %1$s %2$s" + +#, tcl-format +msgid "'%1$s' already loaded, ignoring: '%2$s'" +msgstr "'%1$s' ஏற்கனவே ஏற்றப்பட்டுள்ளது, புறக்கணிக்கிறது: '%2$s'" + +#, tcl-format +msgid "Loading plugin: %s" +msgstr "சொருகி ஏற்றுகிறது: %s" + +#, tcl-format +msgid "UNHANDLED ERROR: %s" +msgstr "தடையற்ற பிழை: %s" + +#, tcl-format +msgid "FAILED TO LOAD %s" +msgstr "%s ஐ ஏற்றுவதில் தோல்வி" + +#, tcl-format +msgid "Failed to read plugin %s ...skipping!" +msgstr "சொருகி %s படிக்கத் தவறிவிட்டது ... தவிர்க்கவும்!" + +#, tcl-format +msgid "Failed to find plugins in %s ...skipping!" +msgstr "%s இல் செருகுநிரல்களைக் கண்டுபிடிப்பதில் தோல்வி ... தவிர்க்கிறது!" + +msgid "Pd startup failure" +msgstr "பி.டி தொடக்க தோல்வி" + +msgid "Failed to start Pd-core" +msgstr "பி.டி.கரு தொடங்க முடியவில்லை" + +msgid "(Tcl) MISSING CLOSE-BRACE '}': " +msgstr "(டி.சி.எல்) நெருங்கிய அடைப்புக்குறி '}' ஐக் காணவில்லை: " + +msgid "(Tcl) INVALID COMMAND NAME: " +msgstr "(டி.சி.எல்) தவறான கட்டளை பெயர்: " + +msgid "(Tcl) UNHANDLED ERROR: " +msgstr "(டி.சி.எல்) தடையற்ற பிழை: " + +#, tcl-format +msgid "[deken] installed version [%1$s] > %2$s...skipping!" +msgstr "[டெக்கன்] நிறுவப்பட்ட பதிப்பு [ %1$s]> %2$s ... தவிர்க்கவும்!" + +#, tcl-format +msgid "[deken] installed version [%1$s] < %2$s...overwriting!" +msgstr "[டெக்கன்] நிறுவப்பட்ட பதிப்பு [ %1$s] < %2$s ... மேலெழுதும்!" + +#, tcl-format +msgid "[deken] installed version [%1$s] == %2$s...skipping!" +msgstr "[டெக்கன்] நிறுவப்பட்ட பதிப்பு [ %1$s] == %2$s ... ச்கிப்பிங்!" + +#, tcl-format +msgid "installing deken package '%s'" +msgstr "டெக்கன் தொகுப்பு '%s' ஐ நிறுவுதல்" + +#, tcl-format +msgid "ignoring '%s': doesn't look like a deken package" +msgstr "'%s' ஐ புறக்கணித்து: டெக்கன் தொகுப்பு போல் தெரியவில்லை" + +#, tcl-format +msgid "Installing '%s'" +msgstr "'%s' நிறுவுதல்" + +#, tcl-format +msgid "Successfully unzipped %1$s into %2$s." +msgstr "%1$s ஐ %2$s க்கு வெற்றிகரமாக அவிழ்த்து விடுங்கள்." + +msgid "Unable to extract package automatically." +msgstr "தொகுப்பை தானாக பிரித்தெடுக்க முடியவில்லை." + +msgid "Please perform the following steps manually:" +msgstr "தயவுசெய்து பின்வரும் படிகளை கைமுறையாகச் செய்யுங்கள்:" + +#, tcl-format +msgid "1. Unzip %s." +msgstr "1. UNZIP %s." + +msgid "You might need to change the file-extension from .dek to .zip" +msgstr "நீங்கள் .dek இலிருந்து .zip க்கு கோப்பு நீட்டிப்பை மாற்ற வேண்டியிருக்கும்" + +#, tcl-format +msgid "2. Copy the contents into %s." +msgstr "2. உள்ளடக்கங்களை %s ஆக நகலெடுக்கவும்." + +#, tcl-format +msgid "3. Remove %s. (optional)" +msgstr "3. %s களை அகற்று. (விரும்பினால்)" + +#, tcl-format +msgid "Removing '%s'" +msgstr "'%s' நீக்குதல்" + +#, tcl-format +msgid "Uninstalling %1$s from %2$s failed!" +msgstr "%2$s இலிருந்து %1$s ஐ நிறுவல் நீக்கியது தோல்வியடைந்தது!" + +#, tcl-format +msgid "Skipping SHA256 verification of '%s'." +msgstr "'%s' இன் SHA256 சரிபார்ப்பைத் தவிர்க்கிறது." + +#, tcl-format +msgid "SHA256 verification of '%s'" +msgstr "'%s' இன் SHA256 சரிபார்ப்பு" + +#, tcl-format +msgid "Unable to fetch reference SHA256 for '%s'." +msgstr "'%s' க்கான குறிப்பு SHA256 ஐப் பெற முடியவில்லை." + +#, tcl-format +msgid "File checksum looks invalid: '%s'." +msgstr "கோப்பு செக்சம் தவறானது: '%s'." + +#, tcl-format +msgid "Reference checksum looks invalid: '%s'." +msgstr "குறிப்பு செக்சம் தவறானது: '%s'." + +#, tcl-format +msgid "Unable to perform SHA256 verification for '%s'." +msgstr "'%s' க்கு SHA256 சரிபார்ப்பைச் செய்ய முடியவில்லை." + +#, tcl-format +msgid "Unable to download from %1$s [%2$s]" +msgstr "%1$s இலிருந்து பதிவிறக்கம் செய்ய முடியவில்லை [ %2$s]" + +#, tcl-format +msgid "Unable to download from '%s'!" +msgstr "'%s' இலிருந்து பதிவிறக்கம் செய்ய முடியவில்லை!" + +msgid "Download failed" +msgstr "பதிவிறக்கம் தோல்வியடைந்தது" + +#, tcl-format +msgid "Unable to remove stray file '%s'" +msgstr "தவறான கோப்பை '%s' அகற்ற முடியவில்லை" + +#, tcl-format +msgid "Unable to rename downloaded file to '%s'" +msgstr "பதிவிறக்கம் செய்யப்பட்ட கோப்பை '%s' என்று மறுபெயரிட முடியவில்லை" + +msgid "Search URLs:" +msgstr "URLS ஐத் தேடுங்கள்:" + +msgid "Additional search URLs" +msgstr "கூடுதல் தேடல் முகவரி கள்" + +msgid "Ephemeral search URLs" +msgstr "இடைக்கால தேடல் முகவரி கள்" + +msgid "Create" +msgstr "உருவாக்கு" + +msgid "Check" +msgstr "சரிபார்" + +msgid "Deken Installation Target" +msgstr "நிறுவல் இலக்கு சிதைவு" + +msgid "Installation options:" +msgstr "நிறுவல் விருப்பங்கள்:" + +msgid "Try to verify the libraries' checksum before (re)installing them" +msgstr "அவற்றை நிறுவுவதற்கு முன் (மறு) நூலகங்களின் செக்சம் சரிபார்க்க முயற்சிக்கவும்" + +msgid "Try to remove libraries before (re)installing them" +msgstr "நூலகங்களை நிறுவுவதற்கு முன் (மறு) அகற்ற முயற்சிக்கவும்" + +msgid "Show README of newly installed libraries (if present)" +msgstr "புதிதாக நிறுவப்பட்ட நூலகங்களின் README ஐக் காட்டு (இருந்தால்)" + +msgid "Keep package files after installation" +msgstr "நிறுவலுக்குப் பிறகு தொகுப்பு கோப்புகளை வைத்திருங்கள்" + +msgid "Add newly installed libraries to Pd's search path" +msgstr "பி.டி.யின் தேடல் பாதையில் புதிதாக நிறுவப்பட்ட நூலகங்களைச் சேர்க்கவும்" + +msgid "Platform settings:" +msgstr "இயங்குதள அமைப்புகள்:" + +#, tcl-format +msgid "Default platform: %s" +msgstr "இயல்புநிலை தளம்: %s" + +msgid "User-defined platform:" +msgstr "பயனர் வரையறுக்கப்பட்ட தளம்:" + +msgid "Hide foreign architectures" +msgstr "வெளிநாட்டு கட்டமைப்புகளை மறைக்கவும்" + +msgid "" +"Only show the newest version of a library\n" +"(treats other versions like foreign architectures)" +msgstr "" +"நூலகத்தின் புதிய பதிப்பை மட்டுமே காண்பி\n" +" (வெளிநாட்டு கட்டமைப்புகள் போன்ற பிற பதிப்புகளுக்கு சிகிச்சையளிக்கிறது)" + +#, tcl-format +msgid "Deken %s Preferences" +msgstr "போர்வை %s விருப்பத்தேர்வுகள்" + +#, tcl-format +msgid "Platform re-detected: %s" +msgstr "இயங்குதளம் மீண்டும் கண்டறியப்பட்டது: %s" + +#, tcl-format +msgid "SHA256 verification of '%s' failed!" +msgstr "'%s' இன் SHA256 சரிபார்ப்பு தோல்வியடைந்தது!" + +msgid "SHA256 verification failed" +msgstr "SHA256 சரிபார்ப்பு தோல்வியடைந்தது" + +#, tcl-format +msgid "Checksum mismatch for '%s'" +msgstr "'%s' க்கான செக்சம் பொருந்தாத தன்மை" + +msgid "Deken Packages" +msgstr "போர்வை தொகுப்புகள்" + +msgid "ZIP Files" +msgstr "சிப் கோப்புகள்" + +msgid "TAR Files" +msgstr "தார் கோப்புகள்" + +msgid "All Files" +msgstr "அனைத்து கோப்புகள்" + +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "'%s' இன் பொருந்தாத கட்டமைப்பை நிறுவுதல்." + +msgid "Replacing library with incompatible architecture!" +msgstr "பொருந்தாத கட்டிடக்கலையுடன் நூலகத்தை மாற்றுதல்!" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" +"உங்கள் கணினியுடன் பொருந்தாத ஒரு பதிப்போடு '%2$s' இல் '%1$s' நூலகத்தை மாற்ற " +"விரும்புகிறீர்களா?" + +#, tcl-format +msgid "Uninstalling previous installation of '%s'" +msgstr "'%s' இன் முந்தைய நிறுவலை நிறுவல் நீக்குகிறது" + +#, tcl-format +msgid "Temporarily moving %1$s into %2$s failed." +msgstr "தற்காலிகமாக %1$s ஐ %2$s க்கு நகர்த்துவது தோல்வியடைந்தது." + +#, tcl-format +msgid "Installing package '%s'" +msgstr "தொகுப்பு '%s'" + +msgid "Installation completed!" +msgstr "நிறுவல் முடிந்தது!" + +#, tcl-format +msgid "Successfully installed '%s'!" +msgstr "'%s' வெற்றிகரமாக நிறுவப்பட்டது!" + +msgid "Installation failed!" +msgstr "நிறுவல் தோல்வியடைந்தது!" + +#, tcl-format +msgid "Failed to install '%s'!" +msgstr "'%s' ஐ நிறுவுவதில் தோல்வி!" + +msgid "Package installation failed" +msgstr "தொகுப்பு நிறுவல் தோல்வியடைந்தது" + +#, tcl-format +msgid "" +"Failed to completely remove %1$s.\n" +"Please manually remove the directory %2$s after quitting Pd." +msgstr "" +"%1$s ஐ முழுமையாக அகற்றுவதில் தோல்வி.\n" +" பி.டி.க்கு வெளியேறிய பிறகு %2$s கோப்பகத்தை கைமுறையாக அகற்றவும்." + +#, tcl-format +msgid "Unable to add %s to search paths" +msgstr "தேடல் பாதைகளுக்கு %s ஐ சேர்க்க முடியவில்லை" + +#, tcl-format +msgid "Add %s to the Pd search paths?" +msgstr "பி.டி தேடல் பாதைகளில் %s ஐச் சேர்க்கவா?" + +#, tcl-format +msgid "Added %s to search paths" +msgstr "தேடல் பாதைகளுக்கு %s சேர்க்கப்பட்டது" + +msgid "No packages selected for installation." +msgstr "நிறுவலுக்கு தொகுப்புகள் எதுவும் தேர்ந்தெடுக்கப்படவில்லை." + +#, tcl-format +msgid "Processed %d packages selected for installation." +msgstr "நிறுவலுக்கு தேர்ந்தெடுக்கப்பட்ட %d தொகுப்புகள்." + +msgid "Show all" +msgstr "அனைத்தையும் காட்டு" + +msgid "Search" +msgstr "தேடல்" + +#, tcl-format +msgid "Install (%d)" +msgstr "நிறுவவும் (%d)" + +msgid "Install" +msgstr "நிறுவவும்" + +#, tcl-format +msgid "%s%% of download completed" +msgstr "பதிவிறக்கத்தின்%s %% முடிந்தது" + +msgid "Enter an exact library or object name." +msgstr "சரியான நூலகம் அல்லது பொருள் பெயரை உள்ளிடவும்." + +msgid "e.g. 'freeverb~'" +msgstr "எ.கா. 'ஃப்ரீவெர்ப் ~'" + +msgid "Use the '*' wildcard to match any number of characters." +msgstr "எந்தவொரு எழுத்துக்களையும் பொருத்த '*' வைல்டு கார்டைப் பயன்படுத்தவும்." + +msgid "e.g. '*-plugin' will match 'deken-plugin' (and more)." +msgstr "எ.கா. '*-plugin' 'டெக்கன்-ப்ளூசின்' (மேலும் பல) பொருந்தும்." + +msgid "You can restrict the search to only-libraries or only-objects." +msgstr "நீங்கள் தேடலை-நூலகங்கள் அல்லது மட்டுமே பொருள்களுக்கு மட்டுமே கட்டுப்படுத்தலாம்." + +msgid "To get a list of all available externals, try an empty search." +msgstr "" +"கிடைக்கக்கூடிய அனைத்து வெளிப்புறங்களின் பட்டியலையும் பெற, வெற்று தேடலை முயற்சிக்கவும்." + +msgid "Right-clicking a search result will give you more options..." +msgstr "" +"ஒரு தேடல் முடிவை வலது சொடுக்கு செய்வது உங்களுக்கு கூடுதல் விருப்பங்களைத் தரும் ..." + +msgid "You can also search for libraries & objects via your web browser:" +msgstr "உங்கள் வலை உலாவி வழியாக நூலகங்கள் மற்றும் பொருள்களையும் தேடலாம்:" + +msgid "Find externals" +msgstr "வெளிப்புறங்களைக் கண்டறியவும்" + +msgid "Install DEK file..." +msgstr "டெக் கோப்பை நிறுவவும் ..." + +msgid "Preferences..." +msgstr "விருப்பத்தேர்வுகள் ..." + +msgid "Search for: " +msgstr "தேடு: " + +msgid "libraries" +msgstr "நூலகங்கள்" + +msgid "objects" +msgstr "பொருள்கள்" + +msgid "both" +msgstr "இரண்டும்" + +msgid "translations" +msgstr "மொழிபெயர்ப்புகள்" + +msgid "Only install externals uploaded by people you trust." +msgstr "நீங்கள் நம்பும் நபர்களால் பதிவேற்றிய வெளிப்புறங்களை மட்டுமே நிறுவவும்." + +msgid "Disabling tabbed view: incompatible Tcl/Tk detected" +msgstr "தாவலாக்கப்பட்ட பார்வையை முடக்குதல்: பொருந்தாத TCL/TK கண்டறியப்பட்டது" + +msgid "Library" +msgstr "நூலகம்" + +msgid "Version" +msgstr "பதிப்பு" + +msgid "Description" +msgstr "விவரம்" + +msgid "Uploader" +msgstr "பதிவேற்றுபவர்" + +msgid "Date" +msgstr "திகதி" + +msgid "Search Results" +msgstr "தேடல் முடிவுகள்" + +msgid "Log" +msgstr "பதிவு" + +#, tcl-format +msgid "Searching for \"%s\"..." +msgstr "\"%s\" ஐத் தேடுகிறது ..." + +#, tcl-format +msgid "online? %s" +msgstr "ஆன்லைனில்? %s" + +msgid "Unable to perform search. Are you online?" +msgstr "தேடலை செய்ய முடியவில்லை. நீங்கள் ஆன்லைனில் இருக்கிறீர்களா?" + +#, tcl-format +msgid "Found %1$d usable packages (of %2$d packages in total)." +msgstr "%1$d பயன்படுத்தக்கூடிய தொகுப்புகள் (மொத்தம் %2$d தொகுப்புகள்) காணப்படுகின்றன." + +msgid "It appears that there are no matching packages for your architecture." +msgstr "உங்கள் கட்டமைப்பிற்கு பொருந்தக்கூடிய தொகுப்புகள் எதுவும் இல்லை என்று தெரிகிறது." + +msgid "No matching externals found." +msgstr "பொருந்தக்கூடிய வெளிப்புறங்கள் எதுவும் காணப்படவில்லை." + +msgid "Try using the full name e.g. 'freeverb~'." +msgstr "முழு பெயரைப் பயன்படுத்த முயற்சிக்கவும் எ.கா. 'ஃப்ரீவெர்ப் ~'." + +msgid "Or use wildcards like 'freeverb*'." +msgstr "அல்லது 'ஃப்ரீவெர்ப்*' போன்ற வைல்டு கார்டுகளைப் பயன்படுத்தவும்." + +msgid "Please select a (writable) installation directory!" +msgstr "தயவுசெய்து ஒரு (எழுதக்கூடிய) நிறுவல் கோப்பகத்தைத் தேர்ந்தெடுக்கவும்!" + +#, tcl-format +msgid "Install %1$s to %2$s?" +msgstr "%1$s முதல் %2$s ஐ நிறுவவா?" + +#, tcl-format +msgid "Cancelling download of '%s': No installation directory given." +msgstr "'%s' இன் பதிவிறக்கத்தை ரத்து செய்தல்: நிறுவல் அடைவு இல்லை." + +msgid "Installing to non-existent directory failed" +msgstr "இல்லாத கோப்பகத்தை நிறுவுவது தோல்வியடைந்தது" + +msgid "Directory does not exist!" +msgstr "அடைவு இல்லை!" + +#, tcl-format +msgid "Unable to install to '%s'" +msgstr "'%s' க்கு நிறுவ முடியவில்லை" + +msgid "Directory is not writable!" +msgstr "அடைவு எழுத முடியாதது அல்ல!" + +#, tcl-format +msgid "Downloading '%s'" +msgstr "'%s' பதிவிறக்குதல்" + +#, tcl-format +msgid "Commencing download of '%1$s' into '%2$s'..." +msgstr "'%1$s' இன் பதிவிறக்கத்தைத் தொடங்குகிறது '%2$s' ..." + +msgid "aborting." +msgstr "கருக்கலைப்பு." + +#, tcl-format +msgid "Downloading '%s' failed" +msgstr "'%s' பதிவிறக்குவது தோல்வியடைந்தது" + +msgid "Download failed!" +msgstr "பதிவிறக்கம் தோல்வியடைந்தது!" + +msgid "Download completed! Verifying..." +msgstr "பதிவிறக்கம் முடிந்தது! சரிபார்க்கிறது ..." + +msgid "Ignoring checksum mismatch" +msgstr "செக்சம் பொருந்தாத தன்மையை புறக்கணித்தல்" + +msgid "Ignoring checksum errors" +msgstr "செக்சம் பிழைகளை புறக்கணித்தல்" + +#, tcl-format +msgid "[deken] deken-plugin.tcl (Pd externals search) loaded from %s." +msgstr "[deken] deken-plugin.tcl (Pd externals search) loaded இருந்து %s." + +#, tcl-format +msgid "[deken] Platform detected: %s" +msgstr "[டெக்கன்] இயங்குதளம் கண்டறியப்பட்டது: %s" + +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "'%s' சேர்ப்பதற்கான மெனுவைக் கண்டுபிடிக்க முடியவில்லை" + +#, tcl-format +msgid "Searching on %s..." +msgstr "%s இல் தேடுகிறது ..." + +#, tcl-format +msgid "Searching on %1$s returned %2$d results" +msgstr "%1$s ஐத் தேடுவது %2$d முடிவுகளைத் தருகிறது" + +msgid "No usable servers for searching found..." +msgstr "தேடுவதற்கு பயன்படுத்தக்கூடிய சேவையகங்கள் எதுவும் இல்லை ..." + +#, tcl-format +msgid "Uploaded by %1$s @ %2$s" +msgstr "%1$s @ %2$s ஆல் பதிவேற்றப்பட்டது" + +#, tcl-format +msgid "Searching for '%s' failed!" +msgstr "'%s' ஐத் தேடுவது தோல்வியடைந்தது!" + +msgid "Search failed" +msgstr "தேடல் தோல்வியடைந்தது" + +msgid "Unable to perform search." +msgstr "தேடலை செய்ய முடியவில்லை." + +msgid "Select package for installation" +msgstr "நிறுவலுக்கான தொகுப்பைத் தேர்ந்தெடுக்கவும்" + +msgid "Deselect package" +msgstr "தொகுப்பு தேர்வு" + +msgid "Open package webpage" +msgstr "தொகுப்பு வலைப்பக்கத்தைத் திறக்கவும்" + +msgid "Copy package URL" +msgstr "தொகுப்பு முகவரி ஐ நகலெடுக்கவும்" + +msgid "Copy SHA256 checksum URL" +msgstr "SHA256 செக்சம் முகவரி ஐ நகலெடுக்கவும்" + +msgid "Copy OpenGPG signature URL" +msgstr "OpenPGP கையொப்பம் முகவரி ஐ நகலெடுக்கவும்" + +#, tcl-format +msgid "Uninstall '%s'" +msgstr "'%s' ஐ நிறுவல் நீக்குதல்" + +#, tcl-format +msgid "" +"Do you want Pd to use the existing documents directory for patches and " +"external libraries?\n" +"\n" +"Location: %s\n" +"\n" +"You can change or disable this later in the Path preferences." +msgstr "" +"திட்டுகள் மற்றும் வெளிப்புற நூலகங்களுக்கு தற்போதுள்ள ஆவணங்கள் கோப்பகத்தைப் பயன்படுத்த பி.டி " +"விரும்புகிறீர்களா?\n" +"\n" +" இடம்: %s\n" +"\n" +" இதை நீங்கள் பின்னர் பாதை விருப்பங்களில் மாற்றலாம் அல்லது முடக்கலாம்." + +#, tcl-format +msgid "" +"Do you want Pd to create a documents directory for patches and external " +"libraries?\n" +"\n" +"Location: %s\n" +"\n" +"You can change or disable this later in the Path preferences." +msgstr "" +"திட்டுகள் மற்றும் வெளிப்புற நூலகங்களுக்கான ஆவணங்களின் கோப்பகத்தை பி.டி உருவாக்க " +"விரும்புகிறீர்களா?\n" +"\n" +" இடம்: %s\n" +"\n" +" இதை நீங்கள் பின்னர் பாதை விருப்பங்களில் மாற்றலாம் அல்லது முடக்கலாம்." + +#, tcl-format +msgid "" +"Pd documents directory cannot be found:\n" +"\n" +"%s\n" +"\n" +"Choose a new location?" +msgstr "" +"பி.டி ஆவணங்கள் கோப்பகத்தைக் கண்டுபிடிக்க முடியவில்லை:\n" +"\n" +" %s\n" +"\n" +" புதிய இருப்பிடத்தைத் தேர்வு செய்யவா?" + +#, tcl-format +msgid "couldn't create Pd documents directory: %s" +msgstr "பி.டி ஆவணங்கள் கோப்பகத்தை உருவாக்க முடியவில்லை: %s" + +#, tcl-format +msgid "couldn't create \"externals\" directory in: %s" +msgstr "\"வெளிப்புறங்கள்\" கோப்பகத்தை உருவாக்க முடியவில்லை: %s" + +msgid "refusing to delete empty domain" +msgstr "வெற்று களத்தை நீக்க மறுக்கிறது" + +#, tcl-format +msgid "Couldn't create preferences \"%1$s\" in %2$s" +msgstr "%2$s இல் \" %1$s\" விருப்பங்களை உருவாக்க முடியவில்லை" + +msgid "The language can only be set during startup." +msgstr "தொடக்கத்தின் போது மட்டுமே மொழியை அமைக்க முடியும்." + +msgid "Afar" +msgstr "அஃபார்" + +msgid "Abkhazian" +msgstr "அப்காசியான்" + +msgid "Avestan" +msgstr "அவெச்டன்" + +msgid "Afrikaans" +msgstr "ஆப்பிரிக்கா" + +msgid "Akan" +msgstr "அகான்" + +msgid "Amharic" +msgstr "அம்ஆரிக்" + +msgid "Aragonese" +msgstr "ஆர்கோனீச்" + +msgid "Arabic" +msgstr "அரபு" + +msgid "Assamese" +msgstr "அச்சாமீச்" + +msgid "Avaric" +msgstr "அவேரிக்" + +msgid "Aymara" +msgstr "அய்மாரா" + +msgid "Azerbaijani" +msgstr "அசர்பைசானி" + +msgid "Bashkir" +msgstr "பச்கிர்" + +msgid "Belarusian" +msgstr "பெலாருசியன்" + +msgid "Bulgarian" +msgstr "பல்கேரியன்" + +msgid "Bihari" +msgstr "பிஆரி" + +msgid "Bislama" +msgstr "பிச்லாமா" + +msgid "Bambara" +msgstr "பம்பாரா" + +msgid "Bengali" +msgstr "பெங்காலி" + +msgid "Tibetan" +msgstr "திபெத்திய" + +msgid "Breton" +msgstr "பிரெட்டன்" + +msgid "Bosnian" +msgstr "போச்னிய" + +msgid "Catalan" +msgstr "கற்றலான்" + +msgid "Chechen" +msgstr "செச்சென்" + +msgid "Chamorro" +msgstr "சாமோரோ" + +msgid "Corsican" +msgstr "கார்சிகன்" + +msgid "Cree" +msgstr "க்ரீ" + +msgid "Czech" +msgstr "செக்" + +msgid "Chuvash" +msgstr "சுவாச்" + +msgid "Welsh" +msgstr "வேல்ச்" + +msgid "Danish" +msgstr "டேனிச்" + +msgid "German" +msgstr "செர்மன்" + +msgid "German (Austria)" +msgstr "செர்மன் (ஆச்திரியா)" + +msgid "Dhivehi" +msgstr "திவேஇ" + +msgid "Dzongkha" +msgstr "பூடானி" + +msgid "Ewe" +msgstr "ஈவ்" + +msgid "Greek" +msgstr "கிரேக்கம்" + +msgid "English" +msgstr "ஆங்கிலம்" + +msgid "English (Canada)" +msgstr "ஆங்கிலம் (கனடா)" + +msgid "English (UK)" +msgstr "ஆங்கிலம் (யுகே)" + +msgid "English (USA)" +msgstr "ஆங்கிலம் (அமெரிக்கா)" + +msgid "Esperanto" +msgstr "எச்பெராண்டோ" + +msgid "Spanish" +msgstr "ச்பானிச்" + +msgid "Estonian" +msgstr "எச்டோனிய" + +msgid "Basque" +msgstr "பாச்க்" + +msgid "Persian" +msgstr "பெர்சியன்" + +msgid "Fulah" +msgstr "ஃபுலா" + +msgid "Finnish" +msgstr "பின்னிச்" + +msgid "Fijian" +msgstr "ஃபிசியன்" + +msgid "Faroese" +msgstr "பரோச்" + +msgid "French" +msgstr "பிரஞ்சு" + +msgid "Frisian" +msgstr "ஃபிரிசியன்" + +msgid "Irish" +msgstr "ஐரிச்" + +msgid "Gaelic" +msgstr "கேலிக்" + +msgid "Galician" +msgstr "காலிசியன்" + +msgid "Guarani" +msgstr "க்வாரனி" + +msgid "Gujarati" +msgstr "குசராத்தி" + +msgid "Manx" +msgstr "மேங்க்ச்" + +msgid "Hausa" +msgstr "ஔசா" + +msgid "Hebrew" +msgstr "எபிரேய" + +msgid "Hindi" +msgstr "இந்தி" + +msgid "Hiri Motu" +msgstr "இரி மோட்டு" + +msgid "Croatian" +msgstr "குரோசியன்" + +msgid "Haitian" +msgstr "ஆய்டியன்" + +msgid "Hungarian" +msgstr "அங்கேரியன்" + +msgid "Armenian" +msgstr "ஆர்மீனியன்" + +msgid "Herero" +msgstr "எரேரோ" + +msgid "Interlingua" +msgstr "இன்டர்லிங்வா" + +msgid "Indonesian" +msgstr "இந்தோனேசிய" + +msgid "Occidental" +msgstr "தற்செயலானது" + +msgid "Igbo" +msgstr "இக்போ" + +msgid "Nuosu" +msgstr "நுஒசு" + +msgid "Inupiaq" +msgstr "இனுபியாக்" + +msgid "Ido" +msgstr "இடோ" + +msgid "Icelandic" +msgstr "ஐச்லாந்திய" + +msgid "Italian" +msgstr "இத்தாலிய" + +msgid "Inuktitut" +msgstr "இனுகிடூட்" + +msgid "Japanese" +msgstr "சப்பானியர்கள்" + +msgid "Javanese" +msgstr "சாவானீச்" + +msgid "Georgian" +msgstr "சார்சியன்" + +msgid "Kongo" +msgstr "காங்கோ" + +msgid "Gikuyu" +msgstr "கிகுயு" + +msgid "Kwanyama" +msgstr "குவான்யாமா" + +msgid "Kazakh" +msgstr "கசாக்" + +msgid "Greenlandic" +msgstr "கிரீன்லாந்திக்" + +msgid "Kannada" +msgstr "கன்னடா" + +msgid "Korean" +msgstr "கொரிய" + +msgid "Kanuri" +msgstr "கனுரி" + +msgid "Kashmiri" +msgstr "காச்மிரி" + +msgid "Kurdish" +msgstr "குர்திச்" + +msgid "Komi" +msgstr "கொமி" + +msgid "Cornish" +msgstr "கார்னிச்" + +msgid "Kyrgyz" +msgstr "கிர்கிச்" + +msgid "Latin" +msgstr "லத்தீன்" + +msgid "Luxembourgish" +msgstr "லக்சம்போர்கிச்" + +msgid "Luganda" +msgstr "லுகாண்டா" + +msgid "Limburgish" +msgstr "லிம்பர்கிச்" + +msgid "Lingala" +msgstr "லிங்காலா" + +msgid "Lao" +msgstr "லாவோ" + +msgid "Lithuanian" +msgstr "லிதுவேனியன்" + +msgid "Luba-Katanga" +msgstr "லுபா-கடாங்கா" + +msgid "Latvian" +msgstr "லாட்வியன்" + +msgid "Malagasy" +msgstr "மலகாசி" + +msgid "Marshallese" +msgstr "மார்செலீச்" + +msgid "Maori" +msgstr "மௌரி" + +msgid "Macedonian" +msgstr "மாசிடோனியன்" + +msgid "Malayalam" +msgstr "மலையாளம்" + +msgid "Mongolian" +msgstr "மங்கோலியன்" + +msgid "Marathi" +msgstr "மராத்தி" + +msgid "Malay" +msgstr "மலாய்" + +msgid "Maltese" +msgstr "மால்டிச்" + +msgid "Burmese" +msgstr "பர்மீச்" + +msgid "Nauru" +msgstr "நவ்ரூ" + +msgid "Nepali" +msgstr "நேபாளி" + +msgid "Ndonga" +msgstr "தோங்கா" + +msgid "Dutch" +msgstr "டச்சு" + +msgid "Norwegian Nynorsk" +msgstr "நார்வேசியன் நியூநார்ச்க்" + +msgid "Navaho" +msgstr "நவாஓ" + +msgid "Nyanja" +msgstr "நயன்சா" + +msgid "Occitan" +msgstr "ஒக்கிடன்" + +msgid "Ojibwe" +msgstr "ஓசிப்வே" + +msgid "Oromo" +msgstr "ஒரோமோ" + +msgid "Odia" +msgstr "ஒடியா" + +msgid "Ossetian" +msgstr "ஓச்சேடியன்" + +msgid "Panjabi" +msgstr "பன்சாபி" + +msgid "Pali" +msgstr "பாலி" + +msgid "Polish" +msgstr "போலீச்" + +msgid "Pashto" +msgstr "பச்தோ" + +msgid "Portuguese" +msgstr "போர்த்துகீசியம்" + +msgid "Portuguese (Brazil)" +msgstr "போர்த்துகீசியம் (பிரேசில்)" + +msgid "Portuguese (Portugal)" +msgstr "போர்த்துகீசியம் (போர்ச்சுகல்)" + +msgid "Quechua" +msgstr "க்வெச்சுவா" + +msgid "Romansh" +msgstr "ரோமான்ச்" + +msgid "Rundi" +msgstr "ருண்டி" + +msgid "Romanian" +msgstr "ருமேனிய" + +msgid "Russian" +msgstr "ரச்ய" + +msgid "Kinyarwanda" +msgstr "கின்யாருவான்டா" + +msgid "Sanskrit" +msgstr "செங்கிருதம்" + +msgid "Sardinian" +msgstr "சார்தீனியன்" + +msgid "Sindhi" +msgstr "சிந்தி" + +msgid "Sango" +msgstr "சாங்கோ" + +msgid "Sinhala" +msgstr "சிங்களம்" + +msgid "Slovak" +msgstr "ச்லோவாக்" + +msgid "Slovenian" +msgstr "ச்லோவேனியன்" + +msgid "Samoan" +msgstr "சமோவான்" + +msgid "Shona" +msgstr "சோனா" + +msgid "Somali" +msgstr "சோமாலி" + +msgid "Albanian" +msgstr "அல்பேனிய" + +msgid "Serbian" +msgstr "செர்பிய" + +msgid "Swati" +msgstr "ச்வாடீ" + +msgid "Sundanese" +msgstr "சுந்தானியர்கள்" + +msgid "Swedish" +msgstr "ச்வீடிச்" + +msgid "Swahili" +msgstr "ச்வாஇலி" + +msgid "Tamil" +msgstr "தமிழ்" + +msgid "Telugu" +msgstr "தெலுங்கு" + +msgid "Tajik" +msgstr "தசிக்" + +msgid "Thai" +msgstr "தாய்" + +msgid "Tigrinya" +msgstr "டிக்ரின்யா" + +msgid "Turkmen" +msgstr "துருக்மென்" + +msgid "Tagalog" +msgstr "டாக்லாக்" + +msgid "Tswana" +msgstr "ச்வானா" + +msgid "Tongan" +msgstr "டோங்கான்" + +msgid "Turkish" +msgstr "துருக்கிய" + +msgid "Tsonga" +msgstr "சோங்கா" + +msgid "Tatar" +msgstr "டாடர்" + +msgid "Twi" +msgstr "ட்வி" + +msgid "Tahitian" +msgstr "தஇதியன்" + +msgid "Uyghur" +msgstr "உய்குர்" + +msgid "Ukrainian" +msgstr "உக்ரேனிய" + +msgid "Urdu" +msgstr "உருது" + +msgid "Uzbek" +msgstr "உச்பெக்" + +msgid "Venda" +msgstr "வென்டா" + +msgid "Vietnamese" +msgstr "வியட்நாமிய" + +msgid "Volapük" +msgstr "ஒலாபூக்" + +msgid "Walloon" +msgstr "ஒவாலூன்" + +msgid "Wolof" +msgstr "ஓலோஃப்" + +msgid "Xhosa" +msgstr "ஓசா" + +msgid "Yiddish" +msgstr "யெட்டிச்" + +msgid "Yoruba" +msgstr "யோருபா" + +msgid "Zhuang" +msgstr "சுவாங்" + +msgid "Chinese (Traditional)" +msgstr "சீன (பாரம்பரிய)" + +msgid "Zulu" +msgstr "சுலு" + +msgid "(no translation)" +msgstr "(மொழிபெயர்ப்பு இல்லை)" + +#, tcl-format +msgid "(default language: %s)" +msgstr "(இயல்புநிலை மொழி: %s)" + +msgid "Print..." +msgstr "அச்சிடுக ..." + +msgid "single precision" +msgstr "ஒற்றை துல்லியம்" + +msgid "double precision" +msgstr "இரட்டை துல்லியம்" + +#, tcl-format +msgid "%dbit-floats" +msgstr "%dbit-flotats" + +#, tcl-format +msgid "ignoring '%s': doesn't exist" +msgstr "'%s' ஐ புறக்கணித்து: இல்லை" + +msgid "About Pd" +msgstr "பி.டி பற்றி" + +#, tcl-format +msgid "couldn't read \"%s\" document" +msgstr "\"%s\" ஆவணத்தைப் படிக்க முடியவில்லை" + +msgid "New" +msgstr "புதிய" + +msgid "Open" +msgstr "திற" + +msgid "Open Recent" +msgstr "அண்மைக் கால திறப்பு" + +msgid "Save" +msgstr "சேமி" + +msgid "Save As..." +msgstr "எனச் சேமி..." + +msgid "Quit" +msgstr "வெளியேறு" + +msgid "Undo" +msgstr "செயல்தவிர்" + +msgid "Redo" +msgstr "மீண்டும்செய்" + +msgid "Cut" +msgstr "வெட்டு" + +msgid "Paste Replace" +msgstr "மாற்றவும்" + +msgid "Select All" +msgstr "அனைத்தையும் தெரிவுசெய்" + +msgid "Duplicate" +msgstr "நகல்" + +msgid "Tidy Up" +msgstr "நேர்த்தியாக" + +msgid "(Dis)Connect Selection" +msgstr "(Dis) தேர்வை இணைக்கவும்" + +msgid "Triggerize" +msgstr "தூண்டுதல்" + +msgid "Zoom In" +msgstr "பெரிதாக்கு" + +msgid "Zoom Out" +msgstr "சிறிதாக்கு" + +msgid "Clear Console" +msgstr "தெளிவான கன்சோல்" + +msgid "Edit Mode" +msgstr "திருத்து பயன்முறை" + +msgid "Object" +msgstr "பொருள்" + +msgid "Message" +msgstr "செய்தி" + +msgid "Number" +msgstr "எண்" + +msgid "List" +msgstr "பட்டியல்" + +msgid "Symbol" +msgstr "அடையாளம்" + +msgid "Comment" +msgstr "கருத்து" + +msgid "Graph" +msgstr "வரைபடம்" + +msgid "Find..." +msgstr "கண்டுபிடி ..." + +msgid "Find Again" +msgstr "மீண்டும் கண்டுபிடி" + +msgid "Find Last Error" +msgstr "கடைசி பிழையைக் கண்டறியவும்" + +msgid "DSP On" +msgstr "டிஎச்பி ஆன்" + +msgid "DSP Off" +msgstr "டி.எச்.பி ஆஃப்" + +msgid "Test Audio and MIDI..." +msgstr "ஆடியோ மற்றும் மிடி சோதனை ..." + +msgid "Load Meter" +msgstr "சுமை மீட்டர்" + +msgid "Audio Settings..." +msgstr "ஆடியோ அமைப்புகள் ..." + +msgid "MIDI Settings..." +msgstr "மிடி அமைப்புகள் ..." + +msgid "Minimize" +msgstr "குறைக்கவும்" + +msgid "Zoom" +msgstr "பெரிதாக்கு" + +msgid "Bring All to Front" +msgstr "அனைத்தையும் முன்னால் கொண்டு வாருங்கள்" + +msgid "Next Window" +msgstr "அடுத்த சாளரம்" + +msgid "Previous Window" +msgstr "முந்தைய சாளரம்" + +msgid "Close subwindows" +msgstr "துணைப்பிரிவை மூடு" + +msgid "Parent Window" +msgstr "பெற்றோர் சாளரம்" + +msgid "Message..." +msgstr "செய்தி ..." + +msgid "HTML Manual..." +msgstr "உஉகுமொ கையேடு ..." + +msgid "Browser..." +msgstr "உலாவி ..." + +msgid "List of objects..." +msgstr "பொருட்களின் பட்டியல் ..." + +msgid "puredata.info" +msgstr "puredata.info" + +msgid "Check for updates" +msgstr "புதுப்பிப்புகளை சரிபார்க்கவும்" + +msgid "Report a bug" +msgstr "ஒரு பிழையைப் புகாரளிக்கவும்" + +msgid "Clear Menu" +msgstr "தெளிவான பட்டியல்" + +msgid "" +"Delete all preferences?\n" +"(takes effect when Pd is restarted)" +msgstr "" +"எல்லா விருப்பங்களையும் நீக்கவா?\n" +" (பி.டி. மறுதொடக்கம் செய்யப்படும்போது நடைமுறைக்கு வருகிறது)" + +msgid "removed GUI settings" +msgstr "GUI அமைப்புகள் அகற்றப்பட்டன" + +msgid "no Pd-GUI settings to clear" +msgstr "அழிக்க PD-GUI அமைப்புகள் இல்லை" + +msgid "Edit Preferences..." +msgstr "விருப்பங்களைத் திருத்து ..." + +msgid "Save All Preferences" +msgstr "எல்லா விருப்பங்களையும் சேமிக்கவும்" + +msgid "Save to..." +msgstr "சேமி இங்கு..." + +msgid "Load from..." +msgstr "இருந்து ஏற்றவும் ..." + +msgid "Forget All..." +msgstr "அனைத்தையும் மறந்து விடுங்கள் ..." + +msgid "Tabbed preferences" +msgstr "தாவலாக்கப்பட்ட விருப்பத்தேர்வுகள்" + +#, tcl-format +msgid "Do you want to save the changes you made in '%s'?" +msgstr "'%s' இல் நீங்கள் செய்த மாற்றங்களைச் சேமிக்க விரும்புகிறீர்களா?" + +msgid "Properties" +msgstr "பண்புகள்" + +#, tcl-format +msgid "Accept changes to '%s'?" +msgstr "'%s' இல் மாற்றங்களை ஏற்றுக்கொள்கிறீர்களா?" + +msgid "" +"Accepting will update the contents in the associated object. You still have " +"to save the patch to make the changes persistent." +msgstr "" +"ஏற்றுக்கொள்வது தொடர்புடைய பொருளில் உள்ள உள்ளடக்கங்களை புதுப்பிக்கும். மாற்றங்களை தொடர்ந்து " +"செய்ய நீங்கள் இன்னும் பேட்சை சேமிக்க வேண்டும்." + +#, tcl-format +msgid "dropped %d lines from the Pd window" +msgstr "பி.டி சாளரத்திலிருந்து %d கோடுகள் கைவிடப்பட்டன" + +#, tcl-format +msgid "the Pd window filtered %d lines" +msgstr "PD சாளரம் %d வரிகளை வடிகட்டியது" + +msgid "Audio on" +msgstr "ஆடியோ ஆன்" + +msgid "Audio off" +msgstr "ஆடியோ ஆஃப்" + +msgid "Find source" +msgstr "மூலத்தைக் கண்டறியவும்" + +msgid "Pd" +msgstr "பி.டி." + +msgid "EXPERIMENTAL double (64bit) precision" +msgstr "சோதனை இரட்டை (64 பிட்) துல்லியம்" + +#, tcl-format +msgid "%dbit-floats EXPERIMENTAL" +msgstr "%dbit-flotats சோதனை" + +msgid "DSP" +msgstr "டி.எச்.பி." + +msgid "Audio I/O error" +msgstr "ஆடியோ I/O பிழை" + +msgid "Log:" +msgstr "பதிவு:" + +msgid "fatal" +msgstr "அபாயகரமான" + +msgid "error" +msgstr "பிழை" + +msgid "normal" +msgstr "சாதாரண" + +msgid "debug" +msgstr "பிழைத்திருத்தம்" + +msgid "all" +msgstr "அனைத்தும்" + +msgid "y1" +msgstr "y1" + +msgid "New..." +msgstr "புதியது ..." + +msgid "Edit..." +msgstr "திருத்து ..." + +msgid "Delete" +msgstr "நீக்கு" + +#, tcl-format +msgid "ignoring '%s': doesn't look like a Pd file" +msgstr "'%s' ஐ புறக்கணித்து: PD கோப்பு போல் தெரியவில்லை" diff --git a/po/template.pot b/po/template.pot index f9f9a3b22b..eda97769de 100644 --- a/po/template.pot +++ b/po/template.pot @@ -5,9 +5,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: Pure Data 0.55.0\n" +"Project-Id-Version: Pure Data 0.55.2\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -284,6 +284,9 @@ msgstr "" msgid "Y range: from" msgstr "" +msgid "Object:" +msgstr "" + msgid "Data Properties" msgstr "" @@ -825,12 +828,24 @@ msgstr "" msgid "Unable to rename downloaded file to '%s'" msgstr "" +msgid "Search URLs:" +msgstr "" + +msgid "Additional search URLs" +msgstr "" + +msgid "Ephemeral search URLs" +msgstr "" + msgid "Create" msgstr "" msgid "Check" msgstr "" +msgid "Deken Installation Target" +msgstr "" + msgid "Installation options:" msgstr "" @@ -898,6 +913,19 @@ msgstr "" msgid "All Files" msgstr "" +#, tcl-format +msgid "Installing incompatible architecture of '%s'." +msgstr "" + +msgid "Replacing library with incompatible architecture!" +msgstr "" + +#, tcl-format +msgid "" +"Do you want to replace the library '%1$s' in '%2$s' with a version that is " +"incompatible with your computer?" +msgstr "" + #, tcl-format msgid "Uninstalling previous installation of '%s'" msgstr "" @@ -1085,11 +1113,11 @@ msgstr "" msgid "Installing to non-existent directory failed" msgstr "" -#, tcl-format -msgid "Unable to install to '%s'" +msgid "Directory does not exist!" msgstr "" -msgid "Directory does not exist!" +#, tcl-format +msgid "Unable to install to '%s'" msgstr "" msgid "Directory is not writable!" @@ -1130,6 +1158,10 @@ msgstr "" msgid "[deken] Platform detected: %s" msgstr "" +#, tcl-format +msgid "Could not find a menu for adding '%s'" +msgstr "" + #, tcl-format msgid "Searching on %s..." msgstr "" @@ -1780,6 +1812,16 @@ msgstr "" msgid "Print..." msgstr "" +msgid "single precision" +msgstr "" + +msgid "double precision" +msgstr "" + +#, tcl-format +msgid "%dbit-floats" +msgstr "" + #, tcl-format msgid "ignoring '%s': doesn't exist" msgstr "" @@ -1791,60 +1833,63 @@ msgstr "" msgid "couldn't read \"%s\" document" msgstr "" -msgid "Save" +msgid "New" msgstr "" -msgid "Save As..." +msgid "Open" msgstr "" -msgid "Paste Replace" +msgid "Open Recent" msgstr "" -msgid "Duplicate" +msgid "Save" msgstr "" -msgid "Zoom In" +msgid "Save As..." msgstr "" -msgid "Zoom Out" +msgid "Quit" msgstr "" -msgid "Tidy Up" +msgid "Undo" msgstr "" -msgid "(Dis)Connect Selection" +msgid "Redo" msgstr "" -msgid "Triggerize" +msgid "Cut" msgstr "" -msgid "Edit Mode" +msgid "Paste Replace" msgstr "" -msgid "Undo" +msgid "Select All" msgstr "" -msgid "Redo" +msgid "Duplicate" msgstr "" -msgid "New" +msgid "Tidy Up" msgstr "" -msgid "Open" +msgid "(Dis)Connect Selection" msgstr "" -msgid "Message..." +msgid "Triggerize" msgstr "" -msgid "Cut" +msgid "Zoom In" msgstr "" -msgid "Select All" +msgid "Zoom Out" msgstr "" msgid "Clear Console" msgstr "" +msgid "Edit Mode" +msgstr "" + msgid "Object" msgstr "" @@ -1908,9 +1953,15 @@ msgstr "" msgid "Previous Window" msgstr "" +msgid "Close subwindows" +msgstr "" + msgid "Parent Window" msgstr "" +msgid "Message..." +msgstr "" + msgid "HTML Manual..." msgstr "" @@ -1961,12 +2012,6 @@ msgstr "" msgid "Tabbed preferences" msgstr "" -msgid "Open Recent" -msgstr "" - -msgid "Quit" -msgstr "" - #, tcl-format msgid "Do you want to save the changes you made in '%s'?" msgstr "" @@ -1997,6 +2042,9 @@ msgstr "" msgid "Audio off" msgstr "" +msgid "Find source" +msgstr "" + msgid "Pd" msgstr "" diff --git a/po/uk.po b/po/uk.po index 0b974ac0eb..ac87d30a61 100644 --- a/po/uk.po +++ b/po/uk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Pure Data 0.53.0\n" "Report-Msgid-Bugs-To: pd-dev@iem.at\n" -"POT-Creation-Date: 2024-08-28 18:42+0200\n" +"POT-Creation-Date: 2025-06-02 09:07+0200\n" "PO-Revision-Date: 2024-07-08 17:41+0200\n" "Last-Translator: umläute \n" "Language-Team: Ukrainian \n" "Language-Team: Vietnamese \n" "Language-Team: Chinese (Traditional) v_n; + void *owner = v->v_vec[0].d_owner; + if (!argc) /* "unset" the arrayvec */ { for (i = 0; i < v->v_n; i++) { @@ -85,16 +92,33 @@ static void arrayvec_set(t_arrayvec *v, int argc, t_atom *argv) } return; } - for (i = 0; i < v->v_n && i < argc; i++) + /* first unset all gpointers */ + for (i = 0; i < v->v_n; i++) + gpointer_unset(&v->v_vec[i].d_gp); + /* resize if necessary */ + if (argc != oldsize) + { + v->v_vec = (t_dsparray *)resizebytes(v->v_vec, + oldsize * sizeof(*v->v_vec), argc * sizeof(*v->v_vec)); + v->v_n = argc; + /* init new elements */ + for (i = oldsize; i < v->v_n; i++) + { + gpointer_init(&v->v_vec[i].d_gp); + v->v_vec[i].d_owner = owner; + v->v_vec[i].d_phase = MAX_PHASE; + } + } + /* set array names */ + for (i = 0; i < v->v_n; i++) { - gpointer_unset(&v->v_vec[i].d_gp); /* reset the pointer */ if (argv[i].a_type != A_SYMBOL) - pd_error(v->v_vec[i].d_owner, + pd_error(owner, "expected symbolic array name, got number instead"), v->v_vec[i].d_symbol = &s_; else { - v->v_vec[i].d_phase = 0x7fffffff; + v->v_vec[i].d_phase = MAX_PHASE; v->v_vec[i].d_symbol = argv[i].a_w.w_symbol; } } @@ -119,7 +143,7 @@ static void arrayvec_init(t_arrayvec *v, void *x, int rawargc, t_atom *rawargv) for (i = 0; i < v->v_n; i++) { v->v_vec[i].d_owner = x; - v->v_vec[i].d_phase = 0x7fffffff; + v->v_vec[i].d_phase = MAX_PHASE; gpointer_init(&v->v_vec[i].d_gp); } arrayvec_set(v, argc, argv); @@ -187,11 +211,11 @@ static t_int *tabwrite_tilde_perform(t_int *w) if (phase >= endphase) { tabwrite_tilde_redraw(d->d_symbol); - phase = 0x7fffffff; + phase = MAX_PHASE; } d->d_phase = phase; } - else d->d_phase = 0x7fffffff; + else d->d_phase = MAX_PHASE; noop: return (w+4); } @@ -199,17 +223,20 @@ static t_int *tabwrite_tilde_perform(t_int *w) static void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s, int argc, t_atom *argv) { + int nchans = x->x_v.v_n; arrayvec_set(&x->x_v, argc, argv); + if (x->x_v.v_n != nchans) /* channels have changed! */ + canvas_update_dsp(); } static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp) { - int i, nchans = (sp[0]->s_nchans < x->x_v.v_n ? - sp[0]->s_nchans : x->x_v.v_n); + int i, length = sp[0]->s_length; + int nchans = sp[0]->s_nchans < x->x_v.v_n ? sp[0]->s_nchans : x->x_v.v_n; arrayvec_testvec(&x->x_v); for (i = 0; i < nchans; i++) - dsp_add(tabwrite_tilde_perform, 3, x->x_v.v_vec+i, - sp[0]->s_vec + i * sp[0]->s_length, (t_int)sp[0]->s_length); + dsp_add(tabwrite_tilde_perform, 3, x->x_v.v_vec + i, + sp[0]->s_vec + i * length, (t_int)length); } static void tabwrite_tilde_start(t_tabwrite_tilde *x, t_floatarg f) @@ -228,10 +255,10 @@ static void tabwrite_tilde_stop(t_tabwrite_tilde *x) { int i; for (i = 0; i < x->x_v.v_n; i++) - if (x->x_v.v_vec[i].d_phase != 0x7fffffff) + if (x->x_v.v_vec[i].d_phase != MAX_PHASE) { tabwrite_tilde_redraw(x->x_v.v_vec[i].d_symbol); - x->x_v.v_vec[i].d_phase = 0x7fffffff; + x->x_v.v_vec[i].d_phase = MAX_PHASE; } } @@ -288,12 +315,12 @@ static t_int *tabplay_tilde_perform(t_int *w) t_tabplay_tilde *x = (t_tabplay_tilde *)(w[1]); t_dsparray *d = (t_dsparray *)(w[2]); t_sample *out = (t_sample *)(w[3]); - t_word *wp; int n = (int)(w[4]), phase = d->d_phase, endphase, nxfer, n3; - t_word *buf; + t_word *buf, *wp; if (!dsparray_get_array(d, &endphase, &buf, 0) || phase >= endphase) goto zero; + if (endphase > x->x_limit) endphase = x->x_limit; nxfer = endphase - phase; @@ -307,10 +334,10 @@ static t_int *tabplay_tilde_perform(t_int *w) if (phase >= endphase) { int i, playing = 0; - d->d_phase = 0x7fffffff; + d->d_phase = MAX_PHASE; /* set the clock when all channels have run out */ for (i = 0; i < x->x_v.v_n; i++) - if (x->x_v.v_vec[i].d_phase < 0x7fffffff) + if (x->x_v.v_vec[i].d_phase < MAX_PHASE) playing = 1; if (!playing) clock_delay(x->x_clock, 0); @@ -328,17 +355,20 @@ static t_int *tabplay_tilde_perform(t_int *w) static void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s, int argc, t_atom *argv) { + int nchans = x->x_v.v_n; arrayvec_set(&x->x_v, argc, argv); + if (x->x_v.v_n != nchans) /* update number of output channels! */ + canvas_update_dsp(); } static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp) { - int i; - signal_setmultiout(&sp[0], x->x_v.v_n); + int i, length = sp[0]->s_length, nchans = x->x_v.v_n; + signal_setmultiout(&sp[0], nchans); arrayvec_testvec(&x->x_v); - for (i = 0; i < x->x_v.v_n; i++) - dsp_add(tabplay_tilde_perform, 4, x, &x->x_v.v_vec[i], - sp[0]->s_vec + i * sp[0]->s_length, (t_int)sp[0]->s_length); + for (i = 0; i < nchans; i++) + dsp_add(tabplay_tilde_perform, 4, x, x->x_v.v_vec + i, + sp[0]->s_vec + i * length, (t_int)length); } static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s, @@ -349,7 +379,7 @@ static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s, int i; if (start < 0) start = 0; if (length <= 0) - x->x_limit = 0x7fffffff; + x->x_limit = MAX_PHASE; else x->x_limit = (int)(start + length); for (i = 0; i < x->x_v.v_n; i++) @@ -360,7 +390,7 @@ static void tabplay_tilde_stop(t_tabplay_tilde *x) { int i; for (i = 0; i < x->x_v.v_n; i++) - x->x_v.v_vec[i].d_phase = 0x7fffffff; + x->x_v.v_vec[i].d_phase = MAX_PHASE; } static void tabplay_tilde_tick(t_tabplay_tilde *x) @@ -417,7 +447,11 @@ static t_int *tabread_tilde_perform(t_int *w) t_word *buf; if (!dsparray_get_array(d, &maxindex, &buf, 0)) - goto zero; + { + while (n--) *out++ = 0; + return (w+5); + } + maxindex -= 1; for (i = 0; i < n; i++) @@ -429,29 +463,30 @@ static t_int *tabread_tilde_perform(t_int *w) index = maxindex; *out++ = buf[index].w_float; } - return (w+5); - zero: - while (n--) *out++ = 0; - return (w+5); } static void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s, int argc, t_atom *argv) { + int nchans = x->x_v.v_n; arrayvec_set(&x->x_v, argc, argv); + if (x->x_v.v_n != nchans) /* update number of output channels! */ + canvas_update_dsp(); } static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp) { - int i; - signal_setmultiout(&sp[1], x->x_v.v_n); + int i, length = sp[0]->s_length; + /* the number of output channels is the maximum of the + arrayvec channels and the input signal channels */ + int nchans = sp[0]->s_nchans > x->x_v.v_n ? sp[0]->s_nchans : x->x_v.v_n; + signal_setmultiout(&sp[1], nchans); arrayvec_testvec(&x->x_v); - for (i = 0; i < x->x_v.v_n; i++) - dsp_add(tabread_tilde_perform, 4, &x->x_v.v_vec[i], - sp[0]->s_vec + (i%(sp[0]->s_nchans)) * sp[0]->s_length, - sp[1]->s_vec + i * sp[0]->s_length, (t_int)sp[0]->s_length); - + for (i = 0; i < nchans; i++) + dsp_add(tabread_tilde_perform, 4, x->x_v.v_vec + (i % x->x_v.v_n), + sp[0]->s_vec + (i % sp[0]->s_nchans) * length, + sp[1]->s_vec + i * length, (t_int)length); } static void tabread_tilde_free(t_tabread_tilde *x) @@ -544,20 +579,27 @@ static t_int *tabread4_tilde_perform(t_int *w) static void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s, int argc, t_atom *argv) { + int nchans = x->x_v.v_n; arrayvec_set(&x->x_v, argc, argv); + if (x->x_v.v_n != nchans) /* update number of output channels! */ + canvas_update_dsp(); } static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp) { int i, length = sp[0]->s_length; - signal_setmultiout(&sp[2], x->x_v.v_n); + /* the number of output channels is the maximum of the + arrayvec channels and the input signal channels */ + int nchans = x->x_v.v_n; + if (sp[0]->s_nchans > nchans) nchans = sp[0]->s_nchans; + if (sp[1]->s_nchans > nchans) nchans = sp[1]->s_nchans; + signal_setmultiout(&sp[2], nchans); arrayvec_testvec(&x->x_v); - for (i = 0; i < x->x_v.v_n; i++) - dsp_add(tabread4_tilde_perform, 5, &x->x_v.v_vec[i], + for (i = 0; i < nchans; i++) + dsp_add(tabread4_tilde_perform, 5, x->x_v.v_vec + (i % x->x_v.v_n), sp[0]->s_vec + (i % sp[0]->s_nchans) * length, sp[1]->s_vec + (i % sp[1]->s_nchans) * length, sp[2]->s_vec + i * length, (t_int)length); - } static void tabread4_tilde_free(t_tabread4_tilde *x) @@ -606,9 +648,8 @@ static t_int *tabsend_perform(t_int *w) t_tabsend *x = (t_tabsend *)(w[1]); t_dsparray *d = (t_dsparray *)(w[2]); t_sample *in = (t_sample *)(w[3]); - int n = (int)w[4], maxindex; + int n = (int)w[4], maxindex, phase = d->d_phase; t_word *dest; - int phase = d->d_phase; if (!dsparray_get_array(d, &maxindex, &dest, 0)) goto bad; @@ -634,22 +675,24 @@ static t_int *tabsend_perform(t_int *w) static void tabsend_set(t_tabsend *x, t_symbol *s, int argc, t_atom *argv) { + int nchans = x->x_v.v_n; arrayvec_set(&x->x_v, argc, argv); + if (x->x_v.v_n != nchans) /* channels have changed! */ + canvas_update_dsp(); } static void tabsend_dsp(t_tabsend *x, t_signal **sp) { - int i, nchans = (sp[0]->s_nchans < x->x_v.v_n ? - sp[0]->s_nchans : x->x_v.v_n); - int length = sp[0]->s_length; + int i, length = sp[0]->s_length; + int nchans = sp[0]->s_nchans < x->x_v.v_n ? sp[0]->s_nchans : x->x_v.v_n; int tickspersec = sp[0]->s_sr/length; if (tickspersec < 1) tickspersec = 1; x->x_graphperiod = tickspersec; arrayvec_testvec(&x->x_v); for (i = 0; i < nchans; i++) - dsp_add(tabsend_perform, 4, x, x->x_v.v_vec+i, - sp[0]->s_vec + i * sp[0]->s_length, (t_int)sp[0]->s_length); + dsp_add(tabsend_perform, 4, x, x->x_v.v_vec + i, + sp[0]->s_vec + i * length, (t_int)length); } static void tabsend_free(t_tabsend *x) @@ -715,17 +758,20 @@ static t_int *tabreceive_perform(t_int *w) static void tabreceive_set(t_tabreceive *x, t_symbol *s, int argc, t_atom *argv) { + int nchans = x->x_v.v_n; arrayvec_set(&x->x_v, argc, argv); + if (x->x_v.v_n != nchans) /* update number of output channels! */ + canvas_update_dsp(); } static void tabreceive_dsp(t_tabreceive *x, t_signal **sp) { - int i; - signal_setmultiout(&sp[0], x->x_v.v_n); + int i, length = sp[0]->s_length, nchans = x->x_v.v_n; + signal_setmultiout(&sp[0], nchans); arrayvec_testvec(&x->x_v); - for (i = 0; i < x->x_v.v_n; i++) - dsp_add(tabreceive_perform, 3, &x->x_v.v_vec[i], - sp[0]->s_vec + i * sp[0]->s_length, (t_int)sp[0]->s_length); + for (i = 0; i < nchans; i++) + dsp_add(tabreceive_perform, 3, x->x_v.v_vec + i, + sp[0]->s_vec + i * length, (t_int)length); } static void tabreceive_free(t_tabreceive *x) diff --git a/src/d_ctl.c b/src/d_ctl.c index 9802f958ad..eca4541963 100644 --- a/src/d_ctl.c +++ b/src/d_ctl.c @@ -15,31 +15,57 @@ static t_class *sig_tilde_class; typedef struct _sig { t_object x_obj; - t_float x_f; + t_atom *x_vec; + int x_n; } t_sig; -static void sig_tilde_float(t_sig *x, t_float f) +static void sig_tilde_float(t_sig *x, t_floatarg f) { - x->x_f = f; + x->x_vec[0].a_w.w_float = f; } static void sig_tilde_dsp(t_sig *x, t_signal **sp) { - dsp_add_scalarcopy(&x->x_f, sp[0]->s_vec, (t_int)sp[0]->s_n); + int i; + signal_setmultiout(sp, x->x_n); + for (i = 0; i < x->x_n; i++) + dsp_add_scalarcopy(&x->x_vec[i].a_w.w_float, + sp[0]->s_vec + i * sp[0]->s_n, (t_int)sp[0]->s_n); } -static void *sig_tilde_new(t_floatarg f) +static void *sig_tilde_new(t_symbol *s, int argc, t_atom *argv) { + int i; t_sig *x = (t_sig *)pd_new(sig_tilde_class); - x->x_f = f; + if (argc > 0) + { + x->x_vec = (t_atom *)getbytes(argc * sizeof(*x->x_vec)); + for (i = 0; i < argc; i++) + SETFLOAT(x->x_vec + i, atom_getfloat(argv + i)); + x->x_n = argc; + } + else + { + x->x_vec = (t_atom *)getbytes(sizeof(*x->x_vec)); + SETFLOAT(x->x_vec, 0); + x->x_n = 1; + } + for (i = 1; i < x->x_n; i++) + floatinlet_new(&x->x_obj, &x->x_vec[i].a_w.w_float); outlet_new(&x->x_obj, gensym("signal")); return (x); } +static void sig_tilde_free(t_sig *x) +{ + freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec)); +} + static void sig_tilde_setup(void) { - sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0, - sizeof(t_sig), 0, A_DEFFLOAT, 0); + sig_tilde_class = class_new(gensym("sig~"), + (t_newmethod)sig_tilde_new, (t_method)sig_tilde_free, + sizeof(t_sig), CLASS_MULTICHANNEL, A_GIMME, 0); class_addfloat(sig_tilde_class, (t_method)sig_tilde_float); class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), A_CANT, 0); @@ -388,52 +414,80 @@ static t_class *snapshot_tilde_class; typedef struct _snapshot { t_object x_obj; - t_sample x_value; t_float x_f; + int x_n; + t_atom *x_vec; } t_snapshot; static void *snapshot_tilde_new(void) { t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class); - x->x_value = 0; - outlet_new(&x->x_obj, &s_float); + x->x_vec = getbytes(sizeof(t_atom)); + SETFLOAT(x->x_vec, 0); + x->x_n = 1; x->x_f = 0; + outlet_new(&x->x_obj, &s_float); return (x); } +static void snapshot_tilde_free(t_snapshot *x) +{ + freebytes(x->x_vec, x->x_n * sizeof(t_atom)); +} + static t_int *snapshot_tilde_perform(t_int *w) { t_sample *in = (t_sample *)(w[1]); - t_sample *out = (t_sample *)(w[2]); - *out = *in; - return (w+3); + t_atom *out = (t_atom *)(w[2]); + int nchans = (int)(w[3]); + int n = (int)(w[4]), i; + for (i = 0; i < nchans; i++) + SETFLOAT(out + i, in[i * n]); + return (w+5); } static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp) { - dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1), - &x->x_value); + int i, nchans = sp[0]->s_nchans; + if (nchans != x->x_n) + { + x->x_vec = (t_atom *)resizebytes(x->x_vec, + x->x_n * sizeof(t_atom), nchans * sizeof(t_atom)); + for (i = x->x_n; i < nchans; i++) + SETFLOAT(x->x_vec + i, 0); + x->x_n = nchans; + } + dsp_add(snapshot_tilde_perform, 4, sp[0]->s_vec + (sp[0]->s_n-1), + x->x_vec, (t_int)nchans, (t_int)sp[0]->s_n); } static void snapshot_tilde_bang(t_snapshot *x) { - outlet_float(x->x_obj.ob_outlet, x->x_value); + outlet_list(x->x_obj.ob_outlet, &s_list, x->x_n, x->x_vec); } -static void snapshot_tilde_set(t_snapshot *x, t_floatarg f) +static void snapshot_tilde_set(t_snapshot *x, t_symbol *s, int argc, t_atom *argv) { - x->x_value = f; + int i; + if (argc > 0) + { + for (i = 0; i < argc && i < x->x_n; i++) + SETFLOAT(x->x_vec + i, atom_getfloat(argv + i)); + } + else /* emulate previous A_DEFFLOAT behavior */ + SETFLOAT(x->x_vec, 0); } static void snapshot_tilde_setup(void) { - snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0, - sizeof(t_snapshot), 0, 0); + snapshot_tilde_class = class_new(gensym("snapshot~"), + snapshot_tilde_new, (t_method)snapshot_tilde_free, + sizeof(t_snapshot), CLASS_MULTICHANNEL, 0); CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f); class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp, gensym("dsp"), A_CANT, 0); class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set, - gensym("set"), A_DEFFLOAT, 0); + gensym("set"), A_GIMME, 0); class_addbang(snapshot_tilde_class, snapshot_tilde_bang); } diff --git a/src/d_delay.c b/src/d_delay.c index ca47f8e694..43bb8de568 100644 --- a/src/d_delay.c +++ b/src/d_delay.c @@ -14,6 +14,7 @@ static t_class *sigdelwrite_class; typedef struct delwritectl { int c_n; + int c_nchans; t_sample *c_vec; int c_phase; } t_delwritectl; @@ -27,6 +28,7 @@ typedef struct _sigdelwrite int x_sortno; /* DSP sort number at which this was last put on chain */ int x_rsortno; /* DSP sort # for first delread or write in chain */ int x_vecsize; /* vector size for delread~ to use */ + int x_nchans; t_float x_sr; t_float x_f; } t_sigdelwrite; @@ -40,12 +42,15 @@ static void sigdelwrite_update(t_sigdelwrite *x) /* added by Mathieu Bouchard */ if (nsamps < 1) nsamps = 1; nsamps += ((- nsamps) & (SAMPBLK - 1)); nsamps += x->x_vecsize; - if (x->x_cspace.c_n != nsamps) + if (x->x_cspace.c_n != nsamps || x->x_cspace.c_nchans != x->x_nchans) { + int oldsize = (x->x_cspace.c_n + XTRASAMPS) * x->x_cspace.c_nchans; + int newsize = (nsamps + XTRASAMPS) * x->x_nchans; x->x_cspace.c_vec = (t_sample *)resizebytes(x->x_cspace.c_vec, - (x->x_cspace.c_n + XTRASAMPS) * sizeof(t_sample), - (nsamps + XTRASAMPS) * sizeof(t_sample)); + oldsize * sizeof(t_sample), newsize * sizeof(t_sample)); + memset(x->x_cspace.c_vec, 0, newsize * sizeof(t_sample)); x->x_cspace.c_n = nsamps; + x->x_cspace.c_nchans = x->x_nchans; x->x_cspace.c_phase = XTRASAMPS; #if 0 post("delay line resized to %d samples", nsamps); @@ -53,13 +58,6 @@ static void sigdelwrite_update(t_sigdelwrite *x) /* added by Mathieu Bouchard */ } } -static void sigdelwrite_clear (t_sigdelwrite *x) /* added by Orm Finnendahl */ -{ - if (x->x_cspace.c_n > 0) - memset(x->x_cspace.c_vec, 0, sizeof(t_sample)*(x->x_cspace.c_n + XTRASAMPS)); -} - - /* routine to check that all delwrites/delreads/vds have same vecsize */ static void sigdelwrite_check(t_sigdelwrite *x, int vecsize, t_float sr) { @@ -89,7 +87,7 @@ static void sigdelwrite_check(t_sigdelwrite *x, int vecsize, t_float sr) #endif } -static void *sigdelwrite_new(t_symbol *s, t_floatarg msec) +static void *sigdelwrite_new(t_symbol *s, t_floatarg msec, t_floatarg nchans) { t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class); if (!*s->s_name) s = gensym("delwrite~"); @@ -97,68 +95,113 @@ static void *sigdelwrite_new(t_symbol *s, t_floatarg msec) x->x_sym = s; x->x_deltime = msec; x->x_cspace.c_n = 0; + x->x_cspace.c_nchans = 1; x->x_cspace.c_vec = getbytes(XTRASAMPS * sizeof(t_sample)); x->x_sortno = 0; x->x_vecsize = 0; + x->x_nchans = nchans > 0 ? nchans : 1; x->x_sr = 0; x->x_f = 0; return (x); } +static void sigdelwrite_clear (t_sigdelwrite *x) /* added by Orm Finnendahl */ +{ + if (x->x_cspace.c_n > 0) + memset(x->x_cspace.c_vec, 0, + (x->x_cspace.c_n + XTRASAMPS) * x->x_cspace.c_nchans * sizeof(t_sample)); +} + +static void sigdelwrite_channels(t_sigdelwrite *x, t_floatarg nchans) +{ + x->x_nchans = nchans > 0 ? nchans : 1; + canvas_update_dsp(); +} + static t_int *sigdelwrite_perform(t_int *w) { t_sample *in = (t_sample *)(w[1]); t_delwritectl *c = (t_delwritectl *)(w[2]); - int n = (int)(w[3]); - int phase = c->c_phase, nsamps = c->c_n; - t_sample *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS); - phase += n; - - while (n--) + int nchans = (int)(w[3]); + int n = (int)(w[4]); + int i, phase, nsamps = c->c_n; + for (i = 0; i < c->c_nchans; i++) { - t_sample f = *in++; - if (PD_BIGORSMALL(f)) - f = 0; - *bp++ = f; - if (bp == ep) - { - vp[0] = ep[-4]; - vp[1] = ep[-3]; - vp[2] = ep[-2]; - vp[3] = ep[-1]; - bp = vp + XTRASAMPS; - phase -= nsamps; - } + t_sample *vp = c->c_vec + i * (nsamps + XTRASAMPS), *bp, *ep; + int k = n; + phase = c->c_phase; + bp = vp + phase; + ep = vp + (nsamps + XTRASAMPS); + phase += k; + + if (i < nchans) + while (k--) + { + t_sample f = *in++; + if (PD_BIGORSMALL(f)) + f = 0; + *bp++ = f; + if (bp == ep) + { + vp[0] = ep[-4]; + vp[1] = ep[-3]; + vp[2] = ep[-2]; + vp[3] = ep[-1]; + bp = vp + XTRASAMPS; + phase -= nsamps; + } + } + else /* fill missing channel with silence */ + while (k--) + { + *bp++ = 0; + if (bp == ep) + { + vp[0] = ep[-4]; + vp[1] = ep[-3]; + vp[2] = ep[-2]; + vp[3] = ep[-1]; + bp = vp + XTRASAMPS; + phase -= nsamps; + } + } } + /* store phase from last iteration */ c->c_phase = phase; - return (w+4); + return (w+5); } static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp) { - dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, (t_int)sp[0]->s_n); x->x_sortno = ugen_getsortno(); - sigdelwrite_check(x, sp[0]->s_n, sp[0]->s_sr); + sigdelwrite_check(x, sp[0]->s_length, sp[0]->s_sr); sigdelwrite_update(x); + /* NB: do not pass a direct pointer to the delay buffer because + it might get resized by another object, see sigdelwrite_update() */ + dsp_add(sigdelwrite_perform, 4, sp[0]->s_vec, + &x->x_cspace, (t_int)sp[0]->s_nchans, (t_int)sp[0]->s_length); } static void sigdelwrite_free(t_sigdelwrite *x) { pd_unbind(&x->x_obj.ob_pd, x->x_sym); freebytes(x->x_cspace.c_vec, - (x->x_cspace.c_n + XTRASAMPS) * sizeof(t_sample)); + (x->x_cspace.c_n + XTRASAMPS) * x->x_cspace.c_nchans * sizeof(t_sample)); } static void sigdelwrite_setup(void) { sigdelwrite_class = class_new(gensym("delwrite~"), (t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free, - sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0); + sizeof(t_sigdelwrite), CLASS_MULTICHANNEL, + A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0); CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f); class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp, gensym("dsp"), A_CANT, 0); class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_clear, - gensym("clear"), 0); + gensym("clear"), 0); + class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_channels, + gensym("channels"), A_FLOAT, 0); class_sethelpsymbol(sigdelwrite_class, gensym("delay-tilde-objects")); } @@ -210,9 +253,11 @@ static t_int *sigdelread_perform(t_int *w) t_sample *out = (t_sample *)(w[1]); t_delwritectl *c = (t_delwritectl *)(w[2]); int delsamps = *(int *)(w[3]); - int n = (int)(w[4]); + int chn = (int)(w[4]); + int n = (int)(w[5]); int phase = c->c_phase - delsamps, nsamps = c->c_n; - t_sample *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS); + t_sample *vp = c->c_vec + chn * (nsamps + XTRASAMPS), + *bp, *ep = vp + (nsamps + XTRASAMPS); if (phase < 0) phase += nsamps; bp = vp + phase; @@ -221,37 +266,48 @@ static t_int *sigdelread_perform(t_int *w) *out++ = *bp++; if (bp == ep) bp -= nsamps; } - return (w+5); + return (w+6); } static void sigdelread_dsp(t_sigdelread *x, t_signal **sp) { t_sigdelwrite *delwriter = (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class); + int i, length = sp[0]->s_length; x->x_sr = sp[0]->s_sr * 0.001; - x->x_n = sp[0]->s_n; + x->x_n = length; if (delwriter) { - sigdelwrite_check(delwriter, sp[0]->s_n, sp[0]->s_sr); + signal_setmultiout(&sp[0], delwriter->x_nchans); + sigdelwrite_check(delwriter, length, sp[0]->s_sr); sigdelwrite_update(delwriter); x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ? 0 : delwriter->x_vecsize); sigdelread_float(x, x->x_deltime); - dsp_add(sigdelread_perform, 4, - sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, (t_int)sp[0]->s_n); + /* NB: do not pass a direct pointer to the delay buffer because + it might get resized by another object, see sigdelwrite_update() */ + for (i = 0; i < delwriter->x_nchans; i++) + dsp_add(sigdelread_perform, 5, + sp[0]->s_vec + i * length, &delwriter->x_cspace, + &x->x_delsamps, (t_int)i, (t_int)length); /* check block size - but only if delwriter has been initialized */ - if (delwriter->x_cspace.c_n > 0 && sp[0]->s_n > delwriter->x_cspace.c_n) + if (delwriter->x_cspace.c_n > 0 && length > delwriter->x_cspace.c_n) pd_error(x, "delread~ %s: blocksize larger than delwrite~ buffer", x->x_sym->s_name); } - else if (*x->x_sym->s_name) - pd_error(x, "delread~: %s: no such delwrite~",x->x_sym->s_name); + else + { + if (*x->x_sym->s_name) + pd_error(x, "delread~: %s: no such delwrite~", x->x_sym->s_name); + signal_setmultiout(&sp[0], 1); + dsp_add_zero(sp[0]->s_vec, length); + } } static void sigdelread_setup(void) { sigdelread_class = class_new(gensym("delread~"), (t_newmethod)sigdelread_new, 0, - sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0); + sizeof(t_sigdelread), CLASS_MULTICHANNEL, A_DEFSYM, A_DEFFLOAT, 0); class_addmethod(sigdelread_class, (t_method)sigdelread_dsp, gensym("dsp"), A_CANT, 0); class_addfloat(sigdelread_class, (t_method)sigdelread_float); @@ -288,22 +344,25 @@ static t_int *sigvd_perform(t_int *w) t_sample *out = (t_sample *)(w[2]); t_delwritectl *ctl = (t_delwritectl *)(w[3]); t_sigvd *x = (t_sigvd *)(w[4]); - int n = (int)(w[5]); + int chn = (int)(w[5]); + int n = (int)(w[6]); int nsamps = ctl->c_n; + t_sample sr = x->x_sr; t_sample limit = nsamps - n; t_sample fn = n-1; - t_sample *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase; + t_sample *vp = ctl->c_vec + chn * (nsamps + XTRASAMPS), + *bp, *wp = vp + ctl->c_phase; t_sample zerodel = x->x_zerodel; if (limit < 0) /* blocksize is larger than delread~ buffer size */ { while (n--) *out++ = 0; - return (w+6); + return (w+7); } while (n--) { - t_sample delsamps = x->x_sr * *in++ - zerodel, frac; + t_sample delsamps = sr * (*in++) - zerodel, frac; int idelsamps; t_sample a, b, c, d, cminusb; if (!(delsamps >= 1.00001f)) /* too small or NAN */ @@ -327,35 +386,50 @@ static t_int *sigvd_perform(t_int *w) ) ); } - return (w+6); + return (w+7); } static void sigvd_dsp(t_sigvd *x, t_signal **sp) { t_sigdelwrite *delwriter = (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class); + int i, length = sp[0]->s_length, nchans; x->x_sr = sp[0]->s_sr * 0.001; if (delwriter) { - sigdelwrite_check(delwriter, sp[0]->s_n, sp[0]->s_sr); + /* The output channel count is the maximum of the phase input channels + and the delwrite~ channels. The smaller one simply wraps around. */ + nchans = sp[0]->s_nchans > delwriter->x_nchans ? + sp[0]->s_nchans : delwriter->x_nchans; + signal_setmultiout(&sp[1], nchans); + sigdelwrite_check(delwriter, length, sp[0]->s_sr); sigdelwrite_update(delwriter); x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ? 0 : delwriter->x_vecsize); - dsp_add(sigvd_perform, 5, - sp[0]->s_vec, sp[1]->s_vec, - &delwriter->x_cspace, x, (t_int)sp[0]->s_n); + /* NB: do not pass a direct pointer to the delay buffer because + it might get resized by another object, see sigdelwrite_update() */ + for (i = 0; i < nchans; i++) + dsp_add(sigvd_perform, 6, + sp[0]->s_vec + (i % sp[0]->s_nchans) * length, + sp[1]->s_vec + i * length, &delwriter->x_cspace, + x, (t_int)(i % delwriter->x_nchans), (t_int)length); /* check block size - but only if delwriter has been initialized */ - if (delwriter->x_cspace.c_n > 0 && sp[0]->s_n > delwriter->x_cspace.c_n) + if (delwriter->x_cspace.c_n > 0 && length > delwriter->x_cspace.c_n) pd_error(x, "delread4~ %s: blocksize larger than delwrite~ buffer", x->x_sym->s_name); } - else if (*x->x_sym->s_name) - pd_error(x, "delread4~: %s: no such delwrite~",x->x_sym->s_name); + else + { + if (*x->x_sym->s_name) + pd_error(x, "delread4~: %s: no such delwrite~",x->x_sym->s_name); + signal_setmultiout(&sp[1], 1); + dsp_add_zero(sp[1]->s_vec, length); + } } static void sigvd_setup(void) { sigvd_class = class_new(gensym("delread4~"), (t_newmethod)sigvd_new, 0, - sizeof(t_sigvd), 0, A_DEFSYM, 0); + sizeof(t_sigvd), CLASS_MULTICHANNEL, A_DEFSYM, 0); class_addcreator((t_newmethod)sigvd_new, gensym("vd~"), A_DEFSYM, 0); class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), A_CANT, 0); CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f); diff --git a/src/d_filter.c b/src/d_filter.c index 89420f406f..401f5f46c1 100644 --- a/src/d_filter.c +++ b/src/d_filter.c @@ -31,7 +31,7 @@ static void *sighip_new(t_floatarg f) t_sighip *x = (t_sighip *)pd_new(sighip_class); inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); outlet_new(&x->x_obj, &s_signal); - x->x_sr = 44100; + x->x_sr = DEFAULTSRATE; x->x_cspace.c_x = 0; sighip_ft1(x, f); x->x_f = 0; @@ -270,7 +270,7 @@ static void *sigbp_new(t_floatarg f, t_floatarg q) inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2")); outlet_new(&x->x_obj, &s_signal); - x->x_sr = 44100; + x->x_sr = DEFAULTSRATE; x->x_cspace.c_x1 = 0; x->x_cspace.c_x2 = 0; sigbp_docoef(x, f, q); diff --git a/src/d_math.c b/src/d_math.c index c8ba172db6..082fb078db 100644 --- a/src/d_math.c +++ b/src/d_math.c @@ -35,26 +35,49 @@ static void *clip_new(t_floatarg lo, t_floatarg hi) return (x); } +#define CLIP_DO(f, lo, hi) \ + ((f) < (lo) ? (lo) : (f) > (hi) ? (hi) : (f)) + static t_int *clip_perform(t_int *w) { t_clip *x = (t_clip *)(w[1]); t_sample *in = (t_sample *)(w[2]); t_sample *out = (t_sample *)(w[3]); int n = (int)(w[4]); + t_sample lo = x->x_lo, hi = x->x_hi; while (n--) { t_sample f = *in++; - if (f < x->x_lo) f = x->x_lo; - if (f > x->x_hi) f = x->x_hi; - *out++ = f; + *out++ = CLIP_DO(f, lo, hi); + } + return (w+5); +} + +static t_int *clip_perform8(t_int *w) +{ + t_clip *x = (t_clip *)(w[1]); + t_sample *in = (t_sample *)(w[2]); + t_sample *out = (t_sample *)(w[3]); + int n = (int)(w[4]); + t_sample lo = x->x_lo, hi = x->x_hi; + for (; n; n -= 8, in += 8, out += 8) + { + t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + out[0] = CLIP_DO(f0, lo, hi); out[1] = CLIP_DO(f1, lo, hi); + out[2] = CLIP_DO(f2, lo, hi); out[3] = CLIP_DO(f3, lo, hi); + out[4] = CLIP_DO(f4, lo, hi); out[5] = CLIP_DO(f5, lo, hi); + out[6] = CLIP_DO(f6, lo, hi); out[7] = CLIP_DO(f7, lo, hi); } return (w+5); } static void clip_dsp(t_clip *x, t_signal **sp) { + t_int n = SIGTOTAL(sp[0]); signal_setmultiout(&sp[1], sp[0]->s_nchans); - dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, SIGTOTAL(sp[0])); + dsp_add(((n & 7) ? clip_perform : clip_perform8), 4, x, + sp[0]->s_vec, sp[1]->s_vec, n); } static void clip_setup(void) @@ -185,14 +208,34 @@ static t_int *sigrsqrt_perform(t_int *w) return (w + 4); } +static t_int *sigrsqrt_perform8(t_int *w) +{ + t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; + int n = (int)w[3]; + for (; n; n -= 8, in += 8, out += 8) + { + t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + out[0] = f0 <= 0 ? 0 : 1./sqrt(f0); + out[1] = f1 <= 0 ? 0 : 1./sqrt(f1); + out[2] = f2 <= 0 ? 0 : 1./sqrt(f2); + out[3] = f3 <= 0 ? 0 : 1./sqrt(f3); + out[4] = f4 <= 0 ? 0 : 1./sqrt(f4); + out[5] = f5 <= 0 ? 0 : 1./sqrt(f5); + out[6] = f6 <= 0 ? 0 : 1./sqrt(f6); + out[7] = f7 <= 0 ? 0 : 1./sqrt(f7); + } + return (w + 4); +} + static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp) { + t_int n = SIGTOTAL(sp[0]); signal_setmultiout(&sp[1], sp[0]->s_nchans); if (pd_compatibilitylevel < 55) - dsp_add(sigrsqrt_perform_quick, 3, sp[0]->s_vec, sp[1]->s_vec, - SIGTOTAL(sp[0])); - else dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, - SIGTOTAL(sp[0])); + dsp_add(sigrsqrt_perform_quick, 3, sp[0]->s_vec, sp[1]->s_vec, n); + else dsp_add(((n & 7) ? sigrsqrt_perform : sigrsqrt_perform8), 3, + sp[0]->s_vec, sp[1]->s_vec, n); } void sigrsqrt_setup(void) @@ -263,14 +306,34 @@ t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */ return (w + 4); } +static t_int *sigsqrt_perform8(t_int *w) +{ + t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; + int n = (int)w[3]; + for (; n; n -= 8, in += 8, out += 8) + { + t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + out[0] = f0 < 0 ? 0 : sqrt(f0); + out[1] = f1 < 0 ? 0 : sqrt(f1); + out[2] = f2 < 0 ? 0 : sqrt(f2); + out[3] = f3 < 0 ? 0 : sqrt(f3); + out[4] = f4 < 0 ? 0 : sqrt(f4); + out[5] = f5 < 0 ? 0 : sqrt(f5); + out[6] = f6 < 0 ? 0 : sqrt(f6); + out[7] = f7 < 0 ? 0 : sqrt(f7); + } + return (w + 4); +} + static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp) { + t_int n = SIGTOTAL(sp[0]); signal_setmultiout(&sp[1], sp[0]->s_nchans); if (pd_compatibilitylevel < 55) - dsp_add(sigsqrt_perform_quick, 3, sp[0]->s_vec, sp[1]->s_vec, - SIGTOTAL(sp[0])); - else dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, - SIGTOTAL(sp[0])); + dsp_add(sigsqrt_perform_quick, 3, sp[0]->s_vec, sp[1]->s_vec, n); + else dsp_add(((n & 7) ? sigsqrt_perform : sigsqrt_perform8), 3, + sp[0]->s_vec, sp[1]->s_vec, n); } void sigsqrt_setup(void) @@ -301,18 +364,39 @@ static void *sigwrap_new(void) return (x); } -static t_int *sigwrap_perform(t_int *w) +#define WRAP_CHECK(f) \ + (((f) > (t_sample)INT_MAX || (f) < (t_sample)INT_MIN) ? 0. : (f)) + +#define WRAP_DO(f) \ + ((int)(f) <= (f) ? (f) - (int)(f) : (f) - ((int)(f) - 1)) + +t_int *sigwrap_perform(t_int *w) { t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; int n = (int)w[3]; while (n--) { - int k; t_sample f = *in++; - f = (f>INT_MAX || fs_nchans); - dsp_add((pd_compatibilitylevel < 48 ? - sigwrap_old_perform : sigwrap_perform), - 3, sp[0]->s_vec, sp[1]->s_vec, SIGTOTAL(sp[0])); + if (pd_compatibilitylevel < 48) + dsp_add(sigwrap_old_perform, 3, sp[0]->s_vec, sp[1]->s_vec, n); + else dsp_add(((n & 7) ? sigwrap_perform : sigwrap_perform8), 3, + sp[0]->s_vec, sp[1]->s_vec, n); } void sigwrap_setup(void) @@ -711,6 +797,8 @@ static void *abs_tilde_new(void) return (x); } +#define ABS_DO(f) ((f) >= 0 ? (f) : -(f)) + t_int *abs_tilde_perform(t_int *w) { t_sample *in1 = (t_sample *)(w[1]); @@ -719,16 +807,34 @@ t_int *abs_tilde_perform(t_int *w) while (n--) { t_sample f = *in1++; - *out++ = (f >= 0 ? f : -f); + *out++ = ABS_DO(f); + } + return (w+4); +} + +t_int *abs_tilde_perform8(t_int *w) +{ + t_sample *in = (t_sample *)(w[1]); + t_sample *out = (t_sample *)(w[2]); + int n = (int)(w[3]); + for (; n; n -= 8, in += 8, out += 8) + { + t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + out[0] = ABS_DO(f0); out[1] = ABS_DO(f1); + out[2] = ABS_DO(f2); out[3] = ABS_DO(f3); + out[4] = ABS_DO(f4); out[5] = ABS_DO(f5); + out[6] = ABS_DO(f6); out[7] = ABS_DO(f7); } return (w+4); } static void abs_tilde_dsp(t_abs_tilde *x, t_signal **sp) { + t_int n = SIGTOTAL(sp[0]); signal_setmultiout(&sp[1], sp[0]->s_nchans); - dsp_add(abs_tilde_perform, 3, - sp[0]->s_vec, sp[1]->s_vec, SIGTOTAL(sp[0])); + dsp_add(((n & 7) ? abs_tilde_perform : abs_tilde_perform8), 3, + sp[0]->s_vec, sp[1]->s_vec, n); } static void abs_tilde_setup(void) diff --git a/src/d_misc.c b/src/d_misc.c index fe4bd9e3f1..f63c778e61 100644 --- a/src/d_misc.c +++ b/src/d_misc.c @@ -23,24 +23,35 @@ static t_int *print_perform(t_int *w) { t_print *x = (t_print *)(w[1]); t_sample *in = (t_sample *)(w[2]); - int n = (int)(w[3]); + int nchans = (int)(w[3]); + int n = (int)(w[4]); if (x->x_count) { - int i=0; + int i, j; startpost("%s:", x->x_sym->s_name); - for(i=0; i 1) + { + endpost(); + startpost("channel %d:", j + 1); + } + for (i = 0; i < n; i++) { + if (i % 8 == 0) + endpost(); + startpost("%.4g ", in[j * n + i]); + } } endpost(); x->x_count--; } - return (w+4); + return (w+5); } static void print_dsp(t_print *x, t_signal **sp) { - dsp_add(print_perform, 3, x, sp[0]->s_vec, (t_int)sp[0]->s_n); + dsp_add(print_perform, 4, x, sp[0]->s_vec, + (t_int)sp[0]->s_nchans, (t_int)sp[0]->s_n); } static void print_float(t_print *x, t_float f) @@ -66,7 +77,7 @@ static void *print_new(t_symbol *s) static void print_setup(void) { print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0, - sizeof(t_print), 0, A_DEFSYM, 0); + sizeof(t_print), CLASS_MULTICHANNEL, A_DEFSYM, 0); CLASS_MAINSIGNALIN(print_class, t_print, x_f); class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), A_CANT, 0); class_addbang(print_class, print_bang); diff --git a/src/d_soundfile.c b/src/d_soundfile.c index 19f1603fee..4af76c0948 100644 --- a/src/d_soundfile.c +++ b/src/d_soundfile.c @@ -439,7 +439,7 @@ int open_soundfile_via_canvas(t_canvas *canvas, const char *filename, static void soundfile_xferin_sample(const t_soundfile *sf, int nvecs, t_sample **vecs, size_t framesread, unsigned char *buf, size_t nframes) { - int nchannels = (sf->sf_nchannels < nvecs ? sf->sf_nchannels : nvecs), i; + int i, nchannels = (sf->sf_nchannels < nvecs ? sf->sf_nchannels : nvecs); size_t j; unsigned char *sp, *sp2; t_sample *fp; @@ -848,16 +848,15 @@ static void soundfile_finishwrite(void *obj, const char *filename, object_sferror(obj, "[soundfiler] write", filename, errno, sf); } -static void soundfile_xferout_sample(const t_soundfile *sf, +static void soundfile_xferout_sample(const t_soundfile *sf, int nvecs, t_sample **vecs, unsigned char *buf, size_t nframes, size_t onsetframes, t_sample normalfactor) { - int i; + int i, nchannels = (sf->sf_nchannels < nvecs ? sf->sf_nchannels : nvecs); size_t j; unsigned char *sp, *sp2; t_sample *fp; - for (i = 0, sp = buf; i < sf->sf_nchannels; i++, - sp += sf->sf_bytespersample) + for (i = 0, sp = buf; i < nchannels; i++, sp += sf->sf_bytespersample) { if (sf->sf_bytespersample == 2) { @@ -982,18 +981,21 @@ static void soundfile_xferout_sample(const t_soundfile *sf, } } } + /* zero out other channels */ + for (i = nchannels; i < sf->sf_nchannels; i++, sp += sf->sf_bytespersample) + for (j = 0, sp2 = sp; j < nframes; j++, sp2 += sf->sf_bytesperframe) + memset(sp2, 0, sf->sf_bytespersample); } -static void soundfile_xferout_words(const t_soundfile *sf, t_word **vecs, - unsigned char *buf, size_t nframes, size_t onsetframes, +static void soundfile_xferout_words(const t_soundfile *sf, int nvecs, + t_word **vecs, unsigned char *buf, size_t nframes, size_t onsetframes, t_sample normalfactor) { - int i; + int i, nchannels = (sf->sf_nchannels < nvecs ? sf->sf_nchannels : nvecs); size_t j; unsigned char *sp, *sp2; t_word *wp; - for (i = 0, sp = buf; i < sf->sf_nchannels; - i++, sp += sf->sf_bytespersample) + for (i = 0, sp = buf; i < nchannels; i++, sp += sf->sf_bytespersample) { if (sf->sf_bytespersample == 2) { @@ -1118,6 +1120,10 @@ static void soundfile_xferout_words(const t_soundfile *sf, t_word **vecs, } } } + /* zero out other channels */ + for (i = nchannels; i < sf->sf_nchannels; i++, sp += sf->sf_bytespersample) + for (j = 0, sp2 = sp; j < nframes; j++, sp2 += sf->sf_bytesperframe) + memset(sp2, 0, sf->sf_bytespersample); } /* ----- soundfiler - reads and writes soundfiles to/from "garrays" ----- */ @@ -1645,7 +1651,7 @@ size_t soundfiler_dowrite(void *obj, t_canvas *canvas, ssize_t byteswritten; thiswrite = (thiswrite > bufframes ? bufframes : thiswrite); datasize = sf->sf_bytesperframe * thiswrite; - soundfile_xferout_words(sf, vectors, (unsigned char *)sampbuf, + soundfile_xferout_words(sf, argc, vectors, (unsigned char *)sampbuf, thiswrite, wa.wa_onsetframes, normfactor); byteswritten = write(sf->sf_fd, sampbuf, datasize); if (byteswritten < 0 || (size_t)byteswritten < datasize) @@ -1751,8 +1757,10 @@ typedef struct _readsf t_clock *x_clock; char *x_buf; /**< soundfile buffer */ int x_bufsize; /**< buffer size in bytes */ - int x_noutlets; /**< number of audio outlets */ - t_sample *(x_outvec[MAXSFCHANS]); /**< audio vectors */ + int x_nchannels; /**< number of channels */ + int x_ninlets; /**< number of inlets (for writesf~) */ + int x_multi; /**< multichannel mode (for readsf~) */ + t_sample *x_vec[MAXSFCHANS]; /**< audio vectors */ int x_vecsize; /**< vector size for transfers */ t_outlet *x_bangout; /**< bang-on-done outlet */ t_soundfile_state x_state; /**< opened, running, or idle */ @@ -2095,12 +2103,22 @@ static void *readsf_child_main(void *zz) static void readsf_tick(t_readsf *x); -static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize) +static void *readsf_new(t_symbol *s, int argc, t_atom *argv) { t_readsf *x; - int nchannels = fnchannels, bufsize = fbufsize, i; + int nchannels, bufsize, i, multi = 0; char *buf; + /* [-m] [nchans] [bufsize] */ + if (argc && argv[0].a_type == A_SYMBOL && + !strcmp(argv[0].a_w.w_symbol->s_name, "-m")) /* multichannel */ + { + multi = 1; + argc--; argv++; + } + nchannels = atom_getfloatarg(0, argc, argv); + bufsize = atom_getfloatarg(1, argc, argv + 1); + if (nchannels < 1) nchannels = 1; else if (nchannels > MAXSFCHANS) @@ -2114,10 +2132,12 @@ static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize) if (!buf) return 0; x = (t_readsf *)pd_new(readsf_class); - - for (i = 0; i < nchannels; i++) + if (multi) /* create a single (multichannel) outlet */ outlet_new(&x->x_obj, gensym("signal")); - x->x_noutlets = nchannels; + else /* create one outlet for each channel */ + for (i = 0; i < nchannels; i++) + outlet_new(&x->x_obj, gensym("signal")); + x->x_nchannels = nchannels; x->x_bangout = outlet_new(&x->x_obj, &s_bang); pthread_mutex_init(&x->x_mutex, 0); pthread_cond_init(&x->x_requestcondition, 0); @@ -2126,6 +2146,7 @@ static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize) x->x_state = STATE_IDLE; x->x_clock = clock_new(x, (t_method)readsf_tick); x->x_canvas = canvas_getcurrent(); + x->x_multi = multi; soundfile_clear(&x->x_sf); x->x_sf.sf_bytespersample = 2; x->x_sf.sf_nchannels = 1; @@ -2149,7 +2170,7 @@ static void readsf_tick(t_readsf *x) static t_int *readsf_perform(t_int *w) { t_readsf *x = (t_readsf *)(w[1]); - int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i; + int vecsize = x->x_vecsize, nchans = x->x_nchannels, i; size_t j; t_sample *fp; if (x->x_state == STATE_STREAM) @@ -2188,7 +2209,7 @@ static t_int *readsf_perform(t_int *w) sf.sf_bytesperframe; if (xfersize) { - soundfile_xferin_sample(&sf, noutlets, x->x_outvec, 0, + soundfile_xferin_sample(&sf, nchans, x->x_vec, 0, (unsigned char *)(x->x_buf + x->x_fifotail), xfersize); vecsize -= xfersize; } @@ -2196,13 +2217,13 @@ static t_int *readsf_perform(t_int *w) /* send bang and zero out the (rest of the) output */ clock_delay(x->x_clock, 0); x->x_state = STATE_IDLE; - for (i = 0; i < noutlets; i++) - for (j = vecsize, fp = x->x_outvec[i] + xfersize; j--;) + for (i = 0; i < nchans; i++) + for (j = vecsize, fp = x->x_vec[i] + xfersize; j--;) *fp++ = 0; return w + 2; } - soundfile_xferin_sample(&sf, noutlets, x->x_outvec, 0, + soundfile_xferin_sample(&sf, nchans, x->x_vec, 0, (unsigned char *)(x->x_buf + x->x_fifotail), vecsize); x->x_fifotail += wantbytes; @@ -2217,8 +2238,8 @@ static t_int *readsf_perform(t_int *w) } else { - for (i = 0; i < noutlets; i++) - for (j = vecsize, fp = x->x_outvec[i]; j--;) + for (i = 0; i < nchans; i++) + for (j = vecsize, fp = x->x_vec[i]; j--;) *fp++ = 0; } return w + 2; @@ -2338,14 +2359,47 @@ static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv) post("flags: %s", sf_typeargs); } +static void readsf_channels(t_readsf *x, t_floatarg f) +{ + if (x->x_multi) + { + int nchans = (int)f; + if (nchans < 1) + nchans = 1; + else if (nchans > MAXSFCHANS) + nchans = MAXSFCHANS; + /* NB: x_nchannels is never read on the child thread, so we can + safely change it without locking a mutex. */ + if (nchans != x->x_nchannels) + { + x->x_nchannels = nchans; + canvas_update_dsp(); + } + } + else pd_error(x, + "readsf~: 'channels' message only works in multichannel mode"); +} + static void readsf_dsp(t_readsf *x, t_signal **sp) { - int i, noutlets = x->x_noutlets; + int i, nchans = x->x_nchannels; pthread_mutex_lock(&x->x_mutex); - x->x_vecsize = sp[0]->s_n; + x->x_vecsize = sp[0]->s_length; x->x_sigperiod = x->x_fifosize / (x->x_sf.sf_bytesperframe * x->x_vecsize); - for (i = 0; i < noutlets; i++) - x->x_outvec[i] = sp[i]->s_vec; + if (x->x_multi) /* multichannel mode */ + { + signal_setmultiout(&sp[0], nchans); + for (i = 0; i < nchans; i++) + x->x_vec[i] = sp[0]->s_vec + i * x->x_vecsize; + } + else /* singlechannel mode */ + { + for (i = 0; i < nchans; i++) + { + signal_setmultiout(&sp[i], 1); + x->x_vec[i] = sp[i]->s_vec; + } + } pthread_mutex_unlock(&x->x_mutex); dsp_add(readsf_perform, 1, x); } @@ -2387,7 +2441,7 @@ static void readsf_setup(void) { readsf_class = class_new(gensym("readsf~"), (t_newmethod)readsf_new, (t_method)readsf_free, - sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + sizeof(t_readsf), CLASS_MULTICHANNEL, A_GIMME, 0); class_addfloat(readsf_class, (t_method)readsf_float); class_addmethod(readsf_class, (t_method)readsf_start, gensym("start"), 0); class_addmethod(readsf_class, (t_method)readsf_stop, gensym("stop"), 0); @@ -2395,6 +2449,8 @@ static void readsf_setup(void) gensym("dsp"), A_CANT, 0); class_addmethod(readsf_class, (t_method)readsf_open, gensym("open"), A_GIMME, 0); + class_addmethod(readsf_class, (t_method)readsf_channels, + gensym("channels"), A_FLOAT, 0); class_addmethod(readsf_class, (t_method)readsf_print, gensym("print"), 0); } @@ -2662,7 +2718,6 @@ static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize) t_writesf *x; int nchannels = fnchannels, bufsize = fbufsize, i; char *buf; - if (nchannels < 1) nchannels = 1; else if (nchannels > MAXSFCHANS) @@ -2678,9 +2733,10 @@ static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize) x = (t_writesf *)pd_new(writesf_class); for (i = 1; i < nchannels; i++) - inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + signalinlet_new(&x->x_obj, 0); x->x_f = 0; + x->x_nchannels = x->x_ninlets = nchannels; pthread_mutex_init(&x->x_mutex, 0); pthread_cond_init(&x->x_requestcondition, 0); pthread_cond_init(&x->x_answercondition, 0); @@ -2743,7 +2799,7 @@ static t_int *writesf_perform(t_int *w) return w + 2; } - soundfile_xferout_sample(&sf, x->x_outvec, + soundfile_xferout_sample(&sf, x->x_nchannels, x->x_vec, (unsigned char *)(x->x_buf + x->x_fifohead), vecsize, 0, 1.); x->x_fifohead += wantbytes; @@ -2820,6 +2876,7 @@ static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv) } x->x_filename = wa.wa_filesym->s_name; x->x_sf.sf_type = wa.wa_type; + x->x_sf.sf_nchannels = x->x_nchannels; if (wa.wa_samplerate > 0) x->x_sf.sf_samplerate = wa.wa_samplerate; else if (x->x_insamplerate > 0) @@ -2851,13 +2908,22 @@ static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv) static void writesf_dsp(t_writesf *x, t_signal **sp) { - int i, ninlets = x->x_sf.sf_nchannels; + int i, j, nchans, ninlets = x->x_ninlets; + t_sample **vp = x->x_vec; pthread_mutex_lock(&x->x_mutex); x->x_vecsize = sp[0]->s_n; x->x_sigperiod = (x->x_fifosize / - (16 * x->x_sf.sf_bytesperframe * x->x_vecsize)); - for (i = 0; i < ninlets; i++) - x->x_outvec[i] = sp[i]->s_vec; + (16 * x->x_sf.sf_bytesperframe * x->x_vecsize)); + /* set and count channels */ + for (i = 0, nchans = 0; i < ninlets; i++) + { + for (j = 0; j < sp[i]->s_nchans && nchans < MAXSFCHANS; j++, nchans++) + *vp++ = sp[i]->s_vec + j * x->x_vecsize; + } + if (nchans != x->x_sf.sf_nchannels && x->x_state != STATE_IDLE) + logpost(x, PD_NORMAL, + "writesf~: warning: channel count changed while streaming"); + x->x_nchannels = nchans; x->x_insamplerate = sp[0]->s_sr; pthread_mutex_unlock(&x->x_mutex); dsp_add(writesf_perform, 1, x); @@ -2908,7 +2974,7 @@ static void writesf_setup(void) { writesf_class = class_new(gensym("writesf~"), (t_newmethod)writesf_new, (t_method)writesf_free, - sizeof(t_writesf), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + sizeof(t_writesf), CLASS_MULTICHANNEL, A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(writesf_class, (t_method)writesf_start, gensym("start"), 0); class_addmethod(writesf_class, (t_method)writesf_stop, gensym("stop"), 0); class_addmethod(writesf_class, (t_method)writesf_dsp, diff --git a/src/d_soundfile_aiff.c b/src/d_soundfile_aiff.c index 51eb1e9dc6..45f6fadca8 100644 --- a/src/d_soundfile_aiff.c +++ b/src/d_soundfile_aiff.c @@ -277,8 +277,8 @@ static int aiff_isheader(const char *buf, size_t size) /** loop through chunks to find comm and data */ static int aiff_readheader(t_soundfile *sf) { - int nchannels = 1, bytespersample = 2, samplerate = 44100, bigendian = 1, - swap = !sys_isbigendian(), isaiffc = 0, commfound = 0; + int nchannels = 1, bytespersample = 2, samplerate = DEFAULTSRATE, + bigendian = 1, swap = !sys_isbigendian(), isaiffc = 0, commfound = 0; off_t headersize = AIFFHEADSIZE; size_t bytelimit = AIFFMAXBYTES; union diff --git a/src/d_soundfile_caf.c b/src/d_soundfile_caf.c index 95c72eb989..e8ef06bc83 100644 --- a/src/d_soundfile_caf.c +++ b/src/d_soundfile_caf.c @@ -193,8 +193,8 @@ static int caf_isheader(const char *buf, size_t size) static int caf_readheader(t_soundfile *sf) { - int nchannels = 1, bytespersample = 2, samplerate = 44100, bigendian = 1, - fmtflags, swap = !sys_isbigendian(); + int nchannels = 1, bytespersample = 2, samplerate = DEFAULTSRATE, + bigendian = 1, fmtflags, swap = !sys_isbigendian(); off_t headersize = CAFHEADSIZE + CAFDESCSIZE; ssize_t bytelimit = CAFMAXBYTES; union diff --git a/src/d_soundfile_wave.c b/src/d_soundfile_wave.c index 8da8f7d1c0..f36a1c5137 100644 --- a/src/d_soundfile_wave.c +++ b/src/d_soundfile_wave.c @@ -220,8 +220,8 @@ static int wave_isheader(const char *buf, size_t size) static int wave_readheader(t_soundfile *sf) { - int nchannels = 1, bytespersample = 2, samplerate = 44100, bigendian = 0, - swap = (bigendian != sys_isbigendian()), formatfound = 1; + int nchannels = 1, bytespersample = 2, samplerate = DEFAULTSRATE, + bigendian = 0, swap = (bigendian != sys_isbigendian()), formatfound = 1; off_t headersize = WAVEHEADSIZE; size_t bytelimit = WAVEMAXBYTES; union diff --git a/src/d_ugen.c b/src/d_ugen.c index f750b4ab62..ddeb069ccf 100644 --- a/src/d_ugen.c +++ b/src/d_ugen.c @@ -136,7 +136,7 @@ typedef struct _block int x_overlap; int x_phase; /* from 0 to period-1; when zero we run the block */ int x_period; /* submultiple of containing canvas */ - int x_frequency; /* supermultiple of comtaining canvas */ + int x_frequency; /* supermultiple of containing canvas */ int x_count; /* number of times parent block has called us */ int x_chainonset; /* beginning of code in DSP chain */ int x_blocklength; /* length of dspchain for this block */ @@ -146,14 +146,15 @@ typedef struct _block char x_reblock; /* true if inlets and outlets are reblocking */ int x_upsample; /* upsampling-factor */ int x_downsample; /* downsampling-factor */ + int x_offset; /* offset block calculation */ int x_return; /* stop right after this block (for one-shots) */ } t_block; static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap, - t_floatarg fupsample); + t_floatarg fupsample, t_floatarg foffset); static void *block_new(t_floatarg fvecsize, t_floatarg foverlap, - t_floatarg fupsample) + t_floatarg fupsample, t_floatarg foffset) { t_block *x = (t_block *)pd_new(block_class); x->x_phase = 0; @@ -161,16 +162,17 @@ static void *block_new(t_floatarg fvecsize, t_floatarg foverlap, x->x_frequency = 1; x->x_switched = 0; x->x_switchon = 1; - block_set(x, fvecsize, foverlap, fupsample); + block_set(x, fvecsize, foverlap, fupsample, foffset); return (x); } static void block_set(t_block *x, t_floatarg fcalcsize, t_floatarg foverlap, - t_floatarg fupsample) + t_floatarg fupsample, t_floatarg foffset) { int upsample, downsample; int calcsize = fcalcsize; int overlap = foverlap; + int offset = foffset; int dspstate = canvas_suspend_dsp(); if (overlap < 1) overlap = 1; @@ -181,12 +183,12 @@ static void block_set(t_block *x, t_floatarg fcalcsize, t_floatarg foverlap, upsample = downsample = 1; else if (fupsample >= 1) { upsample = fupsample; - downsample = 1; + downsample = 1; } else { downsample = 1.0 / fupsample; - upsample = 1; + upsample = 1; } if (overlap != (1 << ilog2(overlap))) { @@ -204,10 +206,16 @@ static void block_set(t_block *x, t_floatarg fcalcsize, t_floatarg foverlap, upsample = 1; } + if (offset > calcsize) + offset %= calcsize; + else if (offset < 0) + offset = 0; + x->x_calcsize = calcsize; x->x_overlap = overlap; x->x_upsample = upsample; x->x_downsample = downsample; + x->x_offset = offset; canvas_resume_dsp(dspstate); } @@ -244,9 +252,9 @@ int canvas_getsignallength(t_canvas *x) } static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap, - t_floatarg fupsample) + t_floatarg fupsample, t_floatarg foffset) { - t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); + t_block *x = (t_block *)block_new(fvecsize, foverlap, fupsample, foffset); x->x_switched = 1; x->x_switchon = 0; return (x); @@ -337,11 +345,11 @@ static void block_dsp(t_block *x, t_signal **sp) void block_tilde_setup(void) { block_class = class_new(gensym("block~"), (t_newmethod)block_new, 0, - sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); class_addcreator((t_newmethod)switch_new, gensym("switch~"), - A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(block_class, (t_method)block_set, gensym("set"), - A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), A_CANT, 0); class_addfloat(block_class, block_float); class_addbang(block_class, block_bang); @@ -1063,7 +1071,7 @@ void ugen_done_graph(t_dspcontext *dc) t_dspcontext *parent_context = dc->dc_parentcontext; t_float parent_srate; int parent_vecsize, parent_overlap; - int period, frequency, calcsize; + int period, frequency, calcsize, offset; t_float srate; int chainblockbegin; /* DSP chain onset before block prolog code */ int chainblockend; /* and after block epilog code */ @@ -1127,16 +1135,22 @@ void ugen_done_graph(t_dspcontext *dc) upsample = blk->x_upsample; if (downsample > parent_vecsize) downsample = parent_vecsize; - period = (calcsize * downsample)/ + period = (calcsize * downsample) / (parent_vecsize * realoverlap * upsample); - frequency = (parent_vecsize * realoverlap * upsample)/ + frequency = (parent_vecsize * realoverlap * upsample) / (calcsize * downsample); srate = parent_srate * realoverlap * upsample / downsample; if (period < 1) period = 1; if (frequency < 1) frequency = 1; + if (blk->x_offset) + /* NB: add one full period to avoid negative phase values! */ + offset = period - (((blk->x_offset * downsample) / + (parent_vecsize * realoverlap * upsample)) % period); + else + offset = 0; blk->x_frequency = frequency; blk->x_period = period; - blk->x_phase = THIS->u_phase & (period - 1); + blk->x_phase = (THIS->u_phase + offset) & (period - 1); if (! parent_context || (realoverlap != 1) || (calcsize != parent_vecsize) || (downsample != 1) || (upsample != 1)) @@ -1151,6 +1165,7 @@ void ugen_done_graph(t_dspcontext *dc) calcsize = parent_vecsize; downsample = upsample = 1; period = frequency = 1; + offset = 0; if (!parent_context) reblock = 1; switched = 0; } @@ -1204,11 +1219,11 @@ void ugen_done_graph(t_dspcontext *dc) if (pd_class(zz) == vinlet_class) vinlet_dspprolog((struct _vinlet *)zz, - dc->dc_iosigs, calcsize, THIS->u_phase, period, + dc->dc_iosigs, calcsize, THIS->u_phase + offset, period, frequency, downsample, upsample, reblock, switched); else if (pd_class(zz) == voutlet_class) voutlet_dspprolog((struct _voutlet *)zz, - outsigs, calcsize, THIS->u_phase, period, frequency, + outsigs, calcsize, THIS->u_phase + offset, period, frequency, downsample, upsample, reblock, switched); } chainblockbegin = THIS->u_dspchainsize; @@ -1284,7 +1299,7 @@ void ugen_done_graph(t_dspcontext *dc) t_signal **iosigs = dc->dc_iosigs; if (iosigs) iosigs += dc->dc_ninlets; voutlet_dspepilog((struct _voutlet *)zz, - iosigs, calcsize, THIS->u_phase, period, frequency, + iosigs, calcsize, THIS->u_phase + offset, period, frequency, downsample, upsample, reblock, switched); } } diff --git a/src/g_all_guis.c b/src/g_all_guis.c index e7200e4747..e1505a30ef 100644 --- a/src/g_all_guis.c +++ b/src/g_all_guis.c @@ -926,10 +926,11 @@ static void iemgui_draw_iolets(t_iemgui*x, t_glist*glist, int old_snd_rcv_flags) sprintf(tag, "%pOUT%d", x, 0); pdgui_vmess(0, "crs", canvas, "delete", tag); if(!x->x_fsf.x_snd_able) { - pdgui_vmess(0, "crr iiii rs rS", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos, ypos + x->x_h + zoom - ioh, xpos + iow, ypos + x->x_h, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 2, tags); /* keep label above outlet */ pdgui_vmess(0, "crss", canvas, "lower", tag, tag_label); @@ -939,10 +940,11 @@ static void iemgui_draw_iolets(t_iemgui*x, t_glist*glist, int old_snd_rcv_flags) sprintf(tag, "%pIN%d", x, 0); pdgui_vmess(0, "crs", canvas, "delete", tag); if(!x->x_fsf.x_rcv_able) { - pdgui_vmess(0, "crr iiii rs rS", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos, ypos, xpos + iow, ypos - zoom + ioh, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 2, tags); /* keep label above inlet */ pdgui_vmess(0, "crss", canvas, "lower", tag, tag_label); diff --git a/src/g_array.c b/src/g_array.c index e7f620819d..e42a3e7256 100644 --- a/src/g_array.c +++ b/src/g_array.c @@ -6,6 +6,7 @@ #include /* for read/write to files */ #include "m_pd.h" #include "g_canvas.h" +#include "g_undo.h" #include #ifndef M_PI @@ -16,6 +17,22 @@ #define ARRAYPAGESIZE 1000 /* this should match the page size in u_main.tk */ /* } jsarlo */ + +/* helpers */ + +/* the GUI sends empty names as '-', + * and names starting with '-' are prefixed with dash as well + * so here we undo this + */ +static t_symbol *garray_unescapit(t_symbol *s) +{ + if (*s->s_name == '-') + return (gensym(s->s_name+1)); + return s; +} + + + /* --------- "pure" arrays with scalars for elements. --------------- */ /* Pure arrays have no a priori graphical capabilities. @@ -87,11 +104,6 @@ void array_free(t_array *x) t_template *scalartemplate = template_findbyname(x->a_templatesym); gstub_cutoff(x->a_stub); word_freevec((t_word *)x->a_vec, scalartemplate, x->a_n); - for (i = 0; i < x->a_n; i++) - { - t_word *wp = (t_word *)(x->a_vec + x->a_elemsize * i); - word_free(wp, scalartemplate); - } freebytes(x->a_vec, x->a_elemsize * x->a_n); freebytes(x, sizeof *x); } @@ -377,23 +389,65 @@ void garray_properties(t_garray *x) a->a_n, x->x_saveit + 2 * filestyle, 0); } +static void garray_deleteit(t_garray *x) { + int wasused = x->x_usedindsp; + glist_delete(x->x_glist, &x->x_gobj); + if (wasused) + canvas_update_dsp(); +} + /* this is called back from the dialog window to create a garray. The otherflag requests that we find an existing graph to put it in. */ void glist_arraydialog(t_glist *parent, t_symbol *name, t_floatarg size, t_floatarg fflags, t_floatarg otherflag) { + const char *undo_name = "add array"; t_glist *gl; t_garray *a; int flags = fflags; + t_atom undo[4]; + + name = garray_unescapit(name); + if(!*name->s_name) { + pd_error(0, "glist: cannot create array without a name"); + return; + } + if (size < 1) size = 1; + if (otherflag == 0 || (!(gl = glist_findgraph(parent)))) + { + undo_name = "create"; + canvas_undo_add(parent, UNDO_SEQUENCE_START, undo_name, 0); gl = glist_addglist(parent, &s_, 0, 1, size, -1, 0, 0, 0, 0); + if (!canvas_undo_get(glist_getcanvas(parent))->u_doing) + canvas_undo_add(glist_getcanvas(parent), UNDO_CREATE, "create", + (void *)canvas_undo_set_create(glist_getcanvas(parent))); + } else { + canvas_undo_add(parent, UNDO_SEQUENCE_START, undo_name, 0); + } a = graph_array(gl, name, &s_float, size, flags); + + SETSYMBOL(undo+0, name); + SETFLOAT (undo+1, size); + SETSYMBOL(undo+2, gensym("float")); + SETFLOAT (undo+3, fflags); + pd_undo_set_objectstate(parent, (t_pd*)gl, gensym("array"), 1, undo, 4, undo); + canvas_undo_add(parent, UNDO_SEQUENCE_END, undo_name, 0); + + glist_redraw(gl); canvas_dirty(parent, 1); } +/* remove a named array from a graph */ +void glist_removearray(t_glist *x, t_symbol *name) { + t_garray*a = (t_garray*)pd_findbyclass(name, garray_class); + if (a && x == a->x_glist) + garray_deleteit(a); +} + /* this is called from the properties dialog window for an existing array */ void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize, t_floatarg fflags, t_floatarg deleteit) @@ -406,15 +460,26 @@ void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize, t_float stylewas = template_getfloat( template_findbyname(x->x_scalar->sc_template), gensym("style"), x->x_scalar->sc_vec, 1); - if (deleteit != 0) - { - int wasused = x->x_usedindsp; - glist_delete(x->x_glist, &x->x_gobj); - if (wasused) - canvas_update_dsp(); + + name = garray_unescapit(name); + if(!*name->s_name) { + pd_error(0, "array: cannot create array without a name"); + return; } - else + + if (deleteit != 0) { + const char *undo_name = "add array"; + t_atom undo[4]; + t_glist *gl = x->x_glist; + garray_deleteit(x); + SETSYMBOL(undo+0, name); + SETFLOAT (undo+1, fsize); + SETSYMBOL(undo+2, gensym("float")); + SETFLOAT (undo+3, fflags); + pd_undo_set_objectstate(glist_getcanvas(gl), (t_pd*)gl, gensym("array"), 4, undo, 1, undo); + glist_redraw(gl); + } else { long size; t_array *a = garray_getarray(x); t_template *scalartemplate; @@ -449,6 +514,8 @@ void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize, gobj_vis(&x->x_glist->gl_gobj, x->x_glist->gl_owner, 0); gobj_vis(&x->x_glist->gl_gobj, x->x_glist->gl_owner, 1); } + /* see garray_rename() */ + garray_getarray(x)->a_valid = ++glist_valid; canvas_update_dsp(); } size = fsize; @@ -737,6 +804,17 @@ static void garray_save(t_gobj *z, t_binbuf *b) x->x_name, array->a_n, &s_float, x->x_saveit + 2 * filestyle + 8*x->x_hidename); garray_savecontentsto(x, b); + + if (pd_compatibilitylevel >= 52) { + t_float fval; + style = template_getfloat( + scalartemplate, gensym("color"), x->x_scalar->sc_vec, 1); + binbuf_addv(b, "ssi;", gensym("#A"), gensym("color"), style); + + fval = template_getfloat( + scalartemplate, gensym("linewidth"), x->x_scalar->sc_vec, 1); + binbuf_addv(b, "ssf;", gensym("#A"), gensym("width"), fval); + } } const t_widgetbehavior garray_widgetbehavior = @@ -851,10 +929,14 @@ int garray_getfloatarray(t_garray *x, int *size, t_float **vec) void garray_setsaveit(t_garray *x, int saveit) { if (x->x_saveit && !saveit) - post("warning: array %s: clearing save-in-patch flag", + logpost(x->x_glist, PD_NORMAL, "warning: array %s: clearing save-in-patch flag", x->x_name->s_name); x->x_saveit = saveit; } +static void garray_saveit(t_garray *x, t_floatarg f) +{ + garray_setsaveit(x, (int)f); +} /*------------------- Pd messages ------------------------ */ static void garray_const(t_garray *x, t_floatarg g) @@ -1067,6 +1149,7 @@ static void garray_style(t_garray *x, t_floatarg fstyle) scalartemplate, gensym("style"), x->x_scalar->sc_vec, 1); if (style != stylewas) { + t_float width; t_array *a = garray_getarray(x); if (!a) { @@ -1077,10 +1160,16 @@ static void garray_style(t_garray *x, t_floatarg fstyle) garray_fittograph(x, a->a_n, style); template_setfloat(scalartemplate, gensym("style"), x->x_scalar->sc_vec, (t_float)style, 0); - #if 1 + + width = template_getfloat( + scalartemplate, gensym("linewidth"), x->x_scalar->sc_vec, 1); + if (style == PLOTSTYLE_POINTS && width < 2) + width = 2; + if (width < 1) + width = 1; template_setfloat(scalartemplate, gensym("linewidth"), x->x_scalar->sc_vec, - ((style == PLOTSTYLE_POINTS) ? 2 : 1), 1); - #endif + width, 1); + garray_redraw(x); } } @@ -1149,6 +1238,7 @@ static void garray_vis_msg(t_garray *x, t_floatarg fvis) /* change the name of a garray. */ static void garray_rename(t_garray *x, t_symbol *s) { + int wasused = x->x_usedindsp; /* jsarlo { */ if (x->x_listviewing) { @@ -1157,7 +1247,13 @@ static void garray_rename(t_garray *x, t_symbol *s) /* } jsarlo */ pd_unbind(&x->x_gobj.g_pd, x->x_realname); pd_bind(&x->x_gobj.g_pd, x->x_realname = x->x_name = s); - garray_redraw(x); + glist_redraw(x->x_glist); + /* Invalidate any existing gpointers into this array. This will + trigger an error message in table DSP objects that are currently + bound to this array, see dsparray_get_array() in d_array.c */ + garray_getarray(x)->a_valid = ++glist_valid; + if (wasused) + canvas_update_dsp(); } static void garray_read(t_garray *x, t_symbol *filename) @@ -1263,7 +1359,14 @@ static void garray_edit(t_garray *x, t_floatarg f) { x->x_edit = (int)f; } - +static void garray_visname(t_garray *x, t_floatarg f) +{ + int hidewas = x->x_hidename; + x->x_hidename = !((int)f); + if (hidewas != x->x_hidename) { + glist_redraw(x->x_glist); + } +} static void garray_print(t_garray *x) { t_array *array = garray_getarray(x); @@ -1297,8 +1400,12 @@ void g_array_setup(void) A_FLOAT, 0); class_addmethod(garray_class, (t_method)garray_vis_msg, gensym("vis"), A_FLOAT, 0); + class_addmethod(garray_class, (t_method)garray_visname, gensym("visname"), + A_FLOAT, 0); class_addmethod(garray_class, (t_method)garray_rename, gensym("rename"), A_SYMBOL, 0); + class_addmethod(garray_class, (t_method)garray_saveit, gensym("keep"), + A_FLOAT, 0); class_addmethod(garray_class, (t_method)garray_read, gensym("read"), A_SYMBOL, A_NULL); class_addmethod(garray_class, (t_method)garray_write, gensym("write"), diff --git a/src/g_canvas.c b/src/g_canvas.c index 0f254d4daa..0bccb96fd3 100644 --- a/src/g_canvas.c +++ b/src/g_canvas.c @@ -548,6 +548,7 @@ static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv) } +void canvas_startmotion(t_canvas *x); /* make a new glist and add it to this glist. It will appear as a "graph", not a text object. */ t_glist *glist_addglist(t_glist *g, t_symbol *sym, @@ -587,6 +588,20 @@ t_glist *glist_addglist(t_glist *g, t_symbol *sym, } if (x1 == x2 || y1 == y2) x1 = 0, x2 = 100, y1 = 1, y2 = -1; + + if (menu && px1 >= px2 && py1 >= py2) + { + /* when creating the graph from menu (even indirectly via garray) + position it near the mouse. + */ + int xpos = (int)px1, ypos = (int)py2; + glist_getnextxy(g, &xpos, &ypos); + px1 = (t_float)xpos; + px2 = px1 + GLIST_DEFGRAPHWIDTH; + py1 = (t_float)ypos; + py2 = py1 + GLIST_DEFGRAPHHEIGHT; + } + if (px1 >= px2 || py1 >= py2) px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH, py2 = 20 + GLIST_DEFGRAPHHEIGHT; @@ -618,6 +633,21 @@ t_glist *glist_addglist(t_glist *g, t_symbol *sym, if (!menu) pd_pushsym(&x->gl_pd); glist_add(g, &x->gl_gobj); + + /* when creating the graph from menu (even indirectly via garray) + switch to edit-mode and stick it to the mouse-pointer + so user can position it whereever they want + */ + if(menu) { + pd_vmess((t_pd*)g, gensym("editmode"), "i", 1); + glist_noselect(g); + glist_select(g, (t_gobj*)x); + if(x->gl_editor) { + /* poor man's replacement for glist_nograb() */ + x->gl_editor->e_grab = 0; + } + canvas_startmotion(g); + } return (x); } @@ -772,7 +802,7 @@ void canvas_drawredrect(t_canvas *x, int doit) pdgui_vmess(0, "crr iiiiiiiiii rr ri rr rr", glist_getcanvas(x), "create", "line", x1,y1, x1,y2, x2,y2, x2,y1, x1,y1, - "-fill", "#ff8080", + "-fill", THISGUI->i_gopcolor->s_name, "-width", x->gl_zoom, "-capstyle", "projecting", "-tags", "GOP"); /* better: "-tags", 1, &"GOP" */ @@ -850,7 +880,7 @@ void glist_menu_open(t_glist *x) gobj_vis(&x->gl_gobj, gl2, 0); /* and blow away all rtexts in parent window -- we can do this because rtexts that are still needed will be recreated - on demand by glist_findrtext() */ + on demand by glist_getrtext() */ if (gl2->gl_editor) while (gl2->gl_editor->e_rtext) rtext_free(gl2->gl_editor->e_rtext); @@ -858,8 +888,11 @@ void glist_menu_open(t_glist *x) if (x->gl_editor) canvas_destroy_editor(x); x->gl_havewindow = 1; - /* redraw ourself in parent window (blanked out this time) */ - gobj_vis(&x->gl_gobj, gl2, 1); + /* redraw entire parent window because new rtexts when + they reappear need to recreate the texts with their new + tags. Also the GOP itseld will now appear as a blank + rectangle. */ + canvas_redraw(gl2); } } canvas_vis(x, 1); @@ -950,10 +983,13 @@ static void canvas_drawlines(t_canvas *x) while ((oc = linetraverser_next(&t))) { sprintf(tag, "l%p", oc); - pdgui_vmess(0, "crr iiii ri rS", + pdgui_vmess(0, "crr iiii ri rr rS", glist_getcanvas(x), "create", "line", t.tr_lx1,t.tr_ly1, t.tr_lx2,t.tr_ly2, - "-width", (outlet_getsymbol(t.tr_outlet) == &s_signal ? 2:1) * x->gl_zoom, + "-width", (outlet_getsymbol(t.tr_outlet) == &s_signal ? 2:1) + * x->gl_zoom, + "-fill", THISGUI->i_foregroundcolor->s_name, + "-tags", 2, tags); } } @@ -1972,6 +2008,7 @@ static void canvas_f(t_canvas *x, t_symbol *s, int argc, t_atom *argv) } if (!x->gl_list) return; + /* apply the format to the most recently created object */ for (g = x->gl_list; (g2 = g->g_next); g = g2) ; if ((ob = pd_checkobject(&g->g_pd))) @@ -2171,6 +2208,10 @@ void g_canvas_newpdinstance(void) THISGUI->i_reloadingabstraction = 0; THISGUI->i_dspstate = 0; THISGUI->i_dollarzero = 1000; + THISGUI->i_foregroundcolor = gensym("black"); + THISGUI->i_backgroundcolor = gensym("white"); + THISGUI->i_selectcolor = gensym("blue"); + THISGUI->i_gopcolor = gensym("red"); g_editor_newpdinstance(); g_template_newpdinstance(); } @@ -2235,3 +2276,58 @@ void glob_open(t_pd *ignore, t_symbol *name, t_symbol *dir, t_floatarg f) if (!glob_evalfile(ignore, name, dir)) pdgui_vmess("::pdwindow::busyrelease", 0); } + +/* close visible subwindows */ +static void glist_closesubsfor(t_glist *glist) +{ + t_gobj *g; + for (g = glist->gl_list; g; g = g->g_next) + { + if (g->g_pd == canvas_class) + { + t_glist *gl2 = (t_glist *)g; + if (gl2->gl_havewindow) + canvas_vis(gl2, 0); + glist_closesubsfor(gl2); + } + } +} + +/* close all visible non-root windows */ +void glob_closesubs(t_pd *ignore) +{ + t_glist *gl; + for (gl = pd_this->pd_canvaslist; gl; gl = gl->gl_next) + glist_closesubsfor(gl); + /* if there's anyone open, move it to front */ + for (gl = pd_getcanvaslist(); gl; gl = gl->gl_next) + if (strcmp(gl->gl_name->s_name, "_float_template") && + strcmp(gl->gl_name->s_name, "_float_array_template") && + strcmp(gl->gl_name->s_name, "_text_template")) + canvas_vis(gl, 1); +} + +static void glist_dorevis(t_glist *glist) +{ + t_gobj *g; + if (glist->gl_havewindow) + { + canvas_vis(glist, 0); + canvas_vis(glist, 1); + } + for (g = glist->gl_list; g; g = g->g_next) + if (g->g_pd == canvas_class) + glist_dorevis((t_glist *)g); +} + +void glob_colors(void *dummy, t_symbol *fg, t_symbol *bg, t_symbol *sel, + t_symbol *gop) +{ + t_glist *gl; + THISGUI->i_foregroundcolor = fg; + THISGUI->i_backgroundcolor = bg; + THISGUI->i_selectcolor = sel; + THISGUI->i_gopcolor = (*gop->s_name ? gop : sel); + for (gl = pd_this->pd_canvaslist; gl; gl = gl->gl_next) + glist_dorevis(gl); +} diff --git a/src/g_canvas.h b/src/g_canvas.h index 1424b3c79d..84a5a39d02 100644 --- a/src/g_canvas.h +++ b/src/g_canvas.h @@ -129,7 +129,7 @@ typedef struct _editor unsigned int e_lastmoved: 1; /* one if mouse has moved since click */ unsigned int e_textdirty: 1; /* one if e_textedfor has changed */ unsigned int e_selectedline: 1; /* one if a line is selected */ - t_clock *e_clock; /* clock to filter GUI move messages */ + unsigned int e_waittodrag: 1; /* one if first move for a mouse drag */ int e_xnew; /* xpos for next move event */ int e_ynew; /* ypos, similarly */ } t_editor; @@ -283,7 +283,9 @@ struct _instancecanvas /* per-instance stuff for canvases */ t_glist *i_reloadingabstraction; /* abstrction we're reloading */ int i_dspstate; /* whether DSP is running */ int i_dollarzero; /* counter for $0 */ - t_float i_graph_lastxpix, i_graph_lastypix; /* state for dragging */ + t_float i_graph_lastxpix, i_graph_lastypix; /* state for dragging */ + t_symbol *i_foregroundcolor, *i_backgroundcolor; /* color of fg & bg */ + t_symbol *i_selectcolor, *i_gopcolor; /* ...selection and GOP */ }; void g_editor_newpdinstance(void); @@ -541,7 +543,7 @@ EXTERN t_canvasenvironment *canvas_getenv(const t_canvas *x); EXTERN void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir); EXTERN void canvas_loadbang(t_canvas *x); EXTERN int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos, - int *x1p, int *y1p, int *x2p, int *y2p); + int *x1p, int *y1p, int *x2p, int *y2p, int extrapix); EXTERN int canvas_setdeleting(t_canvas *x, int flag); #define LB_LOAD 0 /* "loadbang" actions - 0 for original meaning */ @@ -623,7 +625,7 @@ EXTERN void scalar_addrtexts(t_scalar *y, t_glist *gl); EXTERN int scalar_click(t_gobj *z, struct _glist *owner, int xpix, int ypix, int shift, int alt, int dbl, int doit); -EXTERN int scalar_doclick(t_word *data, t_template *template, t_scalar *sc, +EXTERN int scalar_doclick(t_word *data, t_template *pdtemplate, t_scalar *sc, t_array *ap, struct _glist *owner, t_float xloc, t_float yloc, int xpix, int ypix, int shift, int alt, int dbl, int doit); @@ -655,7 +657,7 @@ EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp, int loud); EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, t_symbol *s, int loud); -void template_notifyforscalar(t_template *template, t_glist *owner, +void template_notifyforscalar(t_template *x, t_glist *owner, t_scalar *sc, t_symbol *s, int argc, t_atom *argv); EXTERN t_template *gtemplate_get(t_pdstruct *x); @@ -672,7 +674,7 @@ EXTERN void fielddesc_setcoord(t_fielddesc *f, t_template *tmpl, EXTERN t_float fielddesc_cvttocoord(t_fielddesc *f, t_float val); EXTERN t_float fielddesc_cvtfromcoord(t_fielddesc *f, t_float coord); -EXTERN int drawtext_gettype(t_gobj *z, t_template *template, int *onsetp); +EXTERN int drawtext_gettype(t_gobj *z, t_template *pdtemplate, int *onsetp); EXTERN t_template *drawtext_gettemplate(t_gobj *z); /* ----------------------- guiconnects, g_guiconnect.c --------- */ diff --git a/src/g_clone.c b/src/g_clone.c index ff47d692cd..d51a9ad2d5 100644 --- a/src/g_clone.c +++ b/src/g_clone.c @@ -151,6 +151,7 @@ static void clone_setn(t_clone *, t_floatarg); static void clone_in_resize(t_in *x, t_floatarg f) { int i, oldn = x->i_owner->x_n; + int dspstate = canvas_suspend_dsp(); /* We need to send closebangs to old instances. Currently, this is done in clone_freeinstance(), but later we would rather do it here, see comment in clone_loadbang() */ @@ -160,6 +161,7 @@ static void clone_in_resize(t_in *x, t_floatarg f) /* send loadbangs to new instances */ for (i = oldn; i < x->i_owner->x_n; i++) canvas_loadbang(x->i_owner->x_vec[i].c_gl); + canvas_resume_dsp(dspstate); } static void clone_out_anything(t_outproxy *x, t_symbol *s, int argc, t_atom *argv) @@ -227,12 +229,145 @@ static void clone_freeinstance(t_clone *x, int which) /* see comment in clone_loadbang() */ canvas_closebang(c->c_gl); pd_free(&c->c_gl->gl_pd); - t_freebytes(c->c_vec, x->x_nout * sizeof(*c->c_vec)); + freebytes(c->c_vec, x->x_nout * sizeof(*c->c_vec)); +} + +void canvas_statesavers_doit(t_glist *x, t_binbuf *b); + + /* Remake all cloned abstractions except for 'except'. + This function is used in glist_doreload() in g_editor.c. + It is always called with DSP switched off. */ +int clone_reload(t_pd *z, t_canvas *except) +{ + int i, j; + t_clone *x = (t_clone *)z; + /* check if inlets/outlets have changed. If so, + canvas_doreload() will remake the whole object. */ + int nin = obj_ninlets(&except->gl_obj); + int nout = obj_noutlets(&except->gl_obj); + if (nin != x->x_nin || nout != x->x_nout) + return 0; + for (i = 0; i < nin; i++) + if (x->x_invec[i].i_signal + != obj_issignalinlet(&except->gl_obj, i)) + return 0; + for (i = 0; i < nout; i++) + if (x->x_outvec[i].o_signal + != obj_issignaloutlet(&except->gl_obj, i)) + return 0; + + canvas_setcurrent(x->x_canvas); + for (i = 0; i < x->x_n; i++) + { + if (x->x_vec[i].c_gl != except) + { + t_canvas *c; + t_binbuf *b; + SETFLOAT(x->x_argv, x->x_startvoice + i); + if (!(c = clone_makeone(x->x_s, x->x_argc - x->x_suppressvoice, + x->x_argv + x->x_suppressvoice))) + { + pd_error(x, "clone: couldn't create '%s'", x->x_s->s_name); + canvas_unsetcurrent(x->x_canvas); + return 0; /* abort reload */ + } + /* save state */ + b = binbuf_new(); + canvas_statesavers_doit(x->x_vec[i].c_gl, b); + clone_freeinstance(x, i); + clone_initinstance(x, i, c); + if (binbuf_getnatom(b) > 0) /* restore state */ + { + /* NB: #A is currently bound to 'c' */ + t_binbuf *b2 = binbuf_new(); + binbuf_restore(b2, binbuf_getnatom(b), binbuf_getvec(b)); + binbuf_eval(b2, 0, 0, 0); + binbuf_free(b2); + } + canvas_loadbang(c); + binbuf_free(b); + } + else + { + /* update outgoing connections, in case an outlet has + been deleted and re-added. */ + for (j = 0; j < nout; j++) + { + t_outproxy *out = &x->x_vec[i].c_vec[j]; + obj_disconnect(&except->gl_obj, j, + (t_object *)(out), 0); + obj_connect(&except->gl_obj, j, + (t_object *)(out), 0); + } + } + } + canvas_unsetcurrent(x->x_canvas); + return 1; +} + +void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir, t_canvas *except); + + /* Continue abstraction reloading inside a clone object. See glist_doreload(). */ +void clone_doreload(t_pd *z, t_symbol *name, t_symbol *dir, t_canvas *except) +{ + int i; + t_clone *x = (t_clone *)z; + for (i = 0; i < x->x_n; i++) + glist_doreload(x->x_vec[i].c_gl, name, dir, except); +} + + /* only for state saving */ +static void clone_set(t_clone *x, t_floatarg f) +{ + /* no bound checking! See clone_saved() */ + x->x_phase = (int)f; +} + +static void clone_save(t_clone *x, t_binbuf *b) +{ + int i; + binbuf_addv(b, "ssii", &s__X, gensym("obj"), + (int)x->x_obj.te_xpix, (int)x->x_obj.te_ypix); + binbuf_addbinbuf(b, x->x_obj.ob_binbuf); + if (x->x_obj.te_width) + binbuf_addv(b, ",si", gensym("f"), (int)x->x_obj.te_width); + binbuf_addsemi(b); + if (x->x_n > 0) + { + /* allow cloned abstractions to save their state. + NB: we use a temporary binbuf for canvas_statesavers_doit(), + so that we can omit the "set" message if there is no state. */ + t_binbuf *b2 = binbuf_new(); + int savedstate = 0; + for (i = 0; i < x->x_n; i++) + { + canvas_statesavers_doit(x->x_vec[i].c_gl, b2); + if (binbuf_getnatom(b2) > 0) + { + /* set target for "saved" message(s) and add to binbuf */ + binbuf_addv(b, "ssi;", gensym("#A"), gensym("set"), i); + binbuf_add(b, binbuf_getnatom(b2), binbuf_getvec(b2)); + binbuf_resize(b2, 0); + savedstate = 1; + } + } + if (savedstate) /* reset phase */ + binbuf_addv(b, "ssi;", gensym("#A"), gensym("set"), x->x_n - 1); + binbuf_free(b2); + } +} + + /* restore saved state */ +static void clone_saved(t_clone *x, t_symbol *s, int argc, t_atom *argv) +{ + /* ignore excess "set" messages, in case we have been resized + before saving and now we are back at the original size. */ + if (x->x_phase >= 0 && x->x_phase < x->x_n) + pd_typedmess(&x->x_vec[x->x_phase].c_gl->gl_pd, s, argc, argv); } static void clone_setn(t_clone *x, t_floatarg f) { - int dspstate = canvas_suspend_dsp(); int nwas = x->x_n, wantn = f, i, j; if (!nwas) { @@ -253,7 +388,7 @@ static void clone_setn(t_clone *x, t_floatarg f) x->x_argv + x->x_suppressvoice))) { pd_error(x, "clone: couldn't create '%s'", x->x_s->s_name); - goto done; + return; } x->x_vec = (t_copy *)t_resizebytes(x->x_vec, i * sizeof(t_copy), (i+1) * sizeof(t_copy)); @@ -268,8 +403,6 @@ static void clone_setn(t_clone *x, t_floatarg f) wantn * sizeof(t_copy)); x->x_n = wantn; } -done: - canvas_resume_dsp(dspstate); } static void clone_click(t_clone *x, t_floatarg xpos, t_floatarg ypos, @@ -575,6 +708,8 @@ static void *clone_new(t_symbol *s, int argc, t_atom *argv) canvas_resume_dsp(dspstate); if (voicetovis >= 0 && voicetovis < x->x_n) canvas_vis(x->x_vec[voicetovis].c_gl, 1); + /* bash #A back to our clone object! */ + gensym("#A")->s_thing = (t_pd *)x; return (x); usage: pd_error(0, "usage: clone [-s starting-number] [arguments]"); @@ -619,8 +754,13 @@ void clone_setup(void) A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); class_addmethod(clone_class, (t_method)clone_loadbang, gensym("loadbang"), A_FLOAT, 0); - class_addmethod(clone_class, (t_method)clone_dsp, - gensym("dsp"), A_CANT, 0); + class_addmethod(clone_class, (t_method)clone_set, gensym("set"), + A_FLOAT, 0); + class_addmethod(clone_class, (t_method)clone_saved, gensym("saved"), + A_GIMME, 0); + class_addmethod(clone_class, (t_method)clone_dsp, gensym("dsp"), + A_CANT, 0); + class_setsavefn(clone_class, (t_savefn)clone_save); clone_in_class = class_new(gensym("clone-inlet"), 0, 0, sizeof(t_in), CLASS_PD, 0); diff --git a/src/g_editor.c b/src/g_editor.c index c2856939fa..7fe64d4cdf 100644 --- a/src/g_editor.c +++ b/src/g_editor.c @@ -61,7 +61,7 @@ void canvas_setgraph(t_glist *x, int flag, int nogoprect); /* ------------------------ managing the selection ----------------- */ void glist_deselectline(t_glist *x); -static void _editor_selectlinecolor(t_glist*x, const char*color) +static void _editor_selectlinecolor(t_glist *x, const char*color) { char tag[128]; sprintf(tag, "l%p", x->gl_editor->e_selectline_tag); @@ -83,7 +83,7 @@ void glist_selectline(t_glist *x, t_outconnect *oc, int index1, x->gl_editor->e_selectline_index2 = index2; x->gl_editor->e_selectline_inno = inno; x->gl_editor->e_selectline_tag = oc; - _editor_selectlinecolor(x, "blue"); + _editor_selectlinecolor(x, THISGUI->i_selectcolor->s_name); } } @@ -92,7 +92,7 @@ void glist_deselectline(t_glist *x) if (x->gl_editor) { x->gl_editor->e_selectedline = 0; - _editor_selectlinecolor(x, "black"); + _editor_selectlinecolor(x, THISGUI->i_foregroundcolor->s_name); } } @@ -1632,12 +1632,13 @@ int canvas_undo_font(t_canvas *x, void *z, int action) int clone_match(t_pd *z, t_symbol *name, t_symbol *dir); static void canvas_cut(t_canvas *x); +int clone_reload(t_pd *z, t_canvas *except); +int clone_doreload(t_pd *z, t_symbol *name, t_symbol *dir, t_canvas *except); /* recursively check for abstractions to reload as result of a save. Don't reload the one we just saved ("except") though. */ /* LATER try to do the same trick for externs. */ -static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir, - t_gobj *except) +void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir, t_canvas *except) { t_gobj *g; int hadwindow = gl->gl_havewindow; @@ -1649,16 +1650,17 @@ static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir, { /* remake the object if it's an abstraction that appears to have been loaded from the file we just saved */ - int remakeit = (g != except && pd_class(&g->g_pd) == canvas_class && + int remakeit = (g != &except->gl_gobj && pd_class(&g->g_pd) == canvas_class && canvas_isabstraction((t_canvas *)g) && ((t_canvas *)g)->gl_name == name && canvas_getdir((t_canvas *)g) == dir); - /* also remake it if it's a "clone" with that name */ + /* check if it's a "clone" with that name */ if (pd_class(&g->g_pd) == clone_class && clone_match(&g->g_pd, name, dir)) { - /* LATER try not to remake the one that equals "except" */ - remakeit = 1; + /* try to reload "clone" object, otherwise remake it */ + if (!clone_reload(&g->g_pd, (t_canvas *)except)) + remakeit = 1; } if (remakeit) { @@ -1690,15 +1692,20 @@ static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir, glist_noselect(gl); } - /* now iterate over all the sub-patches... */ + /* now iterate over all the sub-patches and also abstractions and clones, + but only the ones that don't match! */ for (g = gl->gl_list; g; g = g->g_next) { - if (g != except && pd_class(&g->g_pd) == canvas_class && + if (g == &except->gl_gobj) + continue; + if (pd_class(&g->g_pd) == canvas_class && (!canvas_isabstraction((t_canvas *)g) || ((t_canvas *)g)->gl_name != name || - canvas_getdir((t_canvas *)g) != dir) - ) + canvas_getdir((t_canvas *)g) != dir)) glist_doreload((t_canvas *)g, name, dir, except); + else if (pd_class(&g->g_pd) == clone_class && + !clone_match(&g->g_pd, name, dir)) + clone_doreload(&g->g_pd, name, dir, except); } if (!hadwindow && gl->gl_havewindow) canvas_vis(glist_getcanvas(gl), 0); @@ -1716,7 +1723,7 @@ void canvas_reload(t_symbol *name, t_symbol *dir, t_glist *except) THISGUI->i_reloadingabstraction = except; /* find all root canvases */ for (x = pd_getcanvaslist(); x; x = x->gl_next) - glist_doreload(x, name, dir, &except->gl_gobj); + glist_doreload(x, name, dir, except); THISGUI->i_reloadingabstraction = 0; if(b) { @@ -1758,13 +1765,14 @@ void canvas_setcursor(t_canvas *x, unsigned int cursornum) /* check if a point lies in a gobj. */ int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos, - int *x1p, int *y1p, int *x2p, int *y2p) + int *x1p, int *y1p, int *x2p, int *y2p, int extrapix) { int x1, y1, x2, y2; if (!gobj_shouldvis(y, x)) return (0); gobj_getrect(y, x, &x1, &y1, &x2, &y2); - if (xpos >= x1 && xpos <= x2 && ypos >= y1 && ypos <= y2) + if (xpos >= x1-extrapix && xpos <= x2+extrapix + && ypos >= y1-extrapix && ypos <= y2+extrapix) { *x1p = x1; *y1p = y1; @@ -1784,7 +1792,16 @@ static t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos, *x1p = -0x7fffffff; for (y = x->gl_list; y; y = y->g_next) { - if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2) + if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2, 0) + && (x1 > *x1p)) + *x1p = x1, *y1p = y1, *x2p = x2, *y2p = y2, rval = y; + } + /* if none, try again with fatter boxes so that we can click on + inlets or outlets from slightly outside the box */ + if (!rval) + for (y = x->gl_list; y; y = y->g_next) + { + if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2, 4) && (x1 > *x1p)) *x1p = x1, *y1p = y1, *x2p = x2, *y2p = y2, rval = y; } @@ -1795,9 +1812,10 @@ static t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos, { t_selection *sel; for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) - if (canvas_hitbox(x, sel->sel_what, xpos, ypos, &x1, &y1, &x2, &y2)) - *x1p = x1, *y1p = y1, *x2p = x2, *y2p = y2, - rval = sel->sel_what; + if (canvas_hitbox(x, sel->sel_what, xpos, ypos, + &x1, &y1, &x2, &y2, 0)) + *x1p = x1, *y1p = y1, *x2p = x2, *y2p = y2, + rval = sel->sel_what; } return (rval); } @@ -1813,7 +1831,6 @@ static t_editor *editor_new(t_glist *owner) x->e_glist = owner; sprintf(buf, ".x%lx", (t_int)owner); x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf)); - x->e_clock = 0; return (x); } @@ -1823,8 +1840,7 @@ static void editor_free(t_editor *x, t_glist *y) guiconnect_notarget(x->e_guiconnect, 1000); binbuf_free(x->e_connectbuf); binbuf_free(x->e_deleted); - if (x->e_clock) - clock_free(x->e_clock); + sys_unqueuegui(x); freebytes((void *)x, sizeof(*x)); } @@ -1896,10 +1912,18 @@ void canvas_vis(t_canvas *x, t_floatarg f) (int)(x->gl_screeny1)); } - pdgui_vmess("pdtk_canvas_new", "^ ii si", x, - (int)(x->gl_screenx2 - x->gl_screenx1), + /* if color isn't white, pass color as extra argument to + pdtk_canvas_new; but if it's just white don't pass it in + case we're talking to an older GUI version (so that + pureVST can work with Pd 0.55 as its GUI) */ + if (strcmp(THISGUI->i_backgroundcolor->s_name, "white")) + pdgui_vmess("pdtk_canvas_new", "^ ii si s", x, + (int)(x->gl_screenx2 - x->gl_screenx1), (int)(x->gl_screeny2 - x->gl_screeny1), - winpos, x->gl_edit); + winpos, x->gl_edit, THISGUI->i_backgroundcolor->s_name); + else pdgui_vmess("pdtk_canvas_new", "^ ii si", x, + (int)(x->gl_screenx2 - x->gl_screenx1), + (int)(x->gl_screeny2 - x->gl_screeny1), winpos, x->gl_edit); numparents = 0; while (c->gl_owner && !c->gl_isclone) { @@ -2020,6 +2044,15 @@ void canvas_properties(t_gobj*z, t_glist*unused) int isgraph = glist_isgraph(x); t_float x1=0., y1=-1., x2=1., y2=1.; t_float xscale=0., yscale=0.; + char *textbuf = 0; + int textsize; + if (x->gl_owner && canvas_isabstraction(x)) + { + binbuf_gettext(x->gl_obj.te_binbuf, &textbuf, &textsize); + textbuf = (char *)resizebytes(textbuf, textsize, textsize+1); + textbuf[textsize] = 0; + } + pdgui_vmess("::dialog_canvas::set_text", "s", (textbuf ? textbuf : "")); if(isgraph) { x1=x->gl_x1; y1=x->gl_y1; @@ -2036,10 +2069,13 @@ void canvas_properties(t_gobj*z, t_glist*unused) (int)x->gl_pixwidth, (int)x->gl_pixheight, (int)x->gl_xmargin, (int)x->gl_ymargin); + /* if any arrays are in the graph, put out their dialogs too */ for (y = x->gl_list; y; y = y->g_next) if (pd_class(&y->g_pd) == garray_class) garray_properties((t_garray *)y); + if (textbuf) + freebytes(textbuf, textsize+1); } /* called from the gui when "OK" is selected on the canvas properties @@ -2050,6 +2086,40 @@ static void canvas_donecanvasdialog(t_glist *x, t_float xperpix, yperpix, x1, y1, x2, y2, xpix, ypix, xmargin, ymargin; int graphme, redraw = 0, fromgui; + if (x->gl_owner && argc > 12) + { + t_gobj *y = &x->gl_obj.ob_g; + t_binbuf *b = binbuf_new(); + char *textbuf; + int textsize; + binbuf_add(b, argc-12, argv+12); + binbuf_gettext(b, &textbuf, &textsize); + binbuf_print(b); + binbuf_free(b); + canvas_undo_add(x->gl_owner, UNDO_SEQUENCE_START, "typing", 0); + + glist_noselect(x->gl_owner); + canvas_undo_add(x->gl_owner, UNDO_ARRANGE, "arrange", + canvas_undo_set_arrange(x->gl_owner, y, 1)); + + /* store the current connections of the owner */ + glist_noselect(x->gl_owner); + glist_select(x->gl_owner, y); + canvas_stowconnections(glist_getcanvas(x->gl_owner)); + + /* change the text (this will restore the connections we just stowed away) */ + glist_noselect(x->gl_owner); + text_setto(&x->gl_obj, x->gl_owner, textbuf, textsize); + + canvas_fixlinesfor(x->gl_owner, &x->gl_obj); + glist_settexted(x->gl_owner, 0); + + canvas_undo_add(x->gl_owner, UNDO_SEQUENCE_END, "typing", 0); + freebytes(textbuf, textsize); + canvas_dirty(x->gl_owner, 1); + return; + } + xperpix = atom_getfloatarg(0, argc, argv); yperpix = atom_getfloatarg(1, argc, argv); graphme = (int)(atom_getfloatarg(2, argc, argv)); @@ -2122,6 +2192,8 @@ static void canvas_donecanvasdialog(t_glist *x, /* LATER avoid doing 2 redraws here (possibly one inside setgraph) */ canvas_setgraph(x, graphme, 0); canvas_dirty(x, 1); + if (x->gl_owner && x->gl_owner->gl_havewindow) + canvas_redraw(x->gl_owner); if (x->gl_havewindow) canvas_redraw(x); else if (!x->gl_isclone && glist_isvisible(x->gl_owner)) @@ -2141,7 +2213,7 @@ static void canvas_done_popup(t_canvas *x, t_float which, for (y = x->gl_list; y; y = y->g_next) { int x1, y1, x2, y2; - if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2)) + if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2, 0)) { if (which == 0) /* properties */ { @@ -2361,7 +2433,7 @@ static void canvas_doclick(t_canvas *x, int xpix, int ypix, int mod, int doit) click location against their particular assortments of hot points. */ if ((hitbox->g_pd == scalar_class || - canvas_hitbox(x, hitbox, xpix, ypix, &x1, &y1, &x2, &y2)) + canvas_hitbox(x, hitbox, xpix, ypix, &x1, &y1, &x2, &y2, 0)) && (clickreturned = gobj_click(hitbox, x, xpix, ypix, shiftmod, ((mod & CTRLMOD) && (!x->gl_edit)) || altmod, doubleclick, doit))) @@ -2404,8 +2476,8 @@ static void canvas_doclick(t_canvas *x, int xpix, int ypix, int mod, int doit) else { int noutlet; - int out_activeminh = (OHEIGHT + 1) * x->gl_zoom; - int out_activemaxh = (y2 - y1) / 4; + int out_activeminh = OHEIGHT * x->gl_zoom; + int out_activemaxh = (y2 - y1) / 8; int out_activeheight = OHEIGHT * 2 * x->gl_zoom; if (out_activeheight > out_activemaxh) out_activeheight = out_activemaxh; @@ -2491,6 +2563,7 @@ static void canvas_doclick(t_canvas *x, int xpix, int ypix, int mod, int doit) glist_select(x, hitbox); } x->gl_editor->e_onmotion = MA_MOVE; + x->gl_editor->e_waittodrag = 1; } } else canvas_setcursor(x, CURSOR_EDITMODE_NOTHING); @@ -3228,10 +3301,20 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av) CURSOR_RUNMODE_NOTHING :CURSOR_EDITMODE_NOTHING); } -static void delay_move(t_canvas *x) +static void delay_move(t_gobj *client, t_glist *glist) { - int incx = (x->gl_editor->e_xnew - x->gl_editor->e_xwas)/x->gl_zoom, - incy = (x->gl_editor->e_ynew - x->gl_editor->e_ywas)/x->gl_zoom; + t_canvas *x = (t_canvas *)client; + int incx = x->gl_editor->e_xnew - x->gl_editor->e_xwas, + incy = x->gl_editor->e_ynew - x->gl_editor->e_ywas; + /* insist on at elast 2 pixel displacement to avoid accidental + displacements of objects you only meant to select */ + if (x->gl_editor->e_waittodrag && + incx > -2 && incx < 2 && incy > -2 && incy < 2) + return; + incx /= x->gl_zoom; + incy /= x->gl_zoom; + + x->gl_editor->e_waittodrag = 0; if (incx || incy) canvas_displaceselection(x, incx, incy); x->gl_editor->e_xwas += incx * x->gl_zoom; @@ -3258,10 +3341,7 @@ void canvas_motion(t_canvas *x, t_floatarg xpos, t_floatarg ypos, glist_setlastxy(x, xpos, ypos); if (x->gl_editor->e_onmotion == MA_MOVE) { - if (!x->gl_editor->e_clock) - x->gl_editor->e_clock = clock_new(x, (t_method)delay_move); - clock_unset(x->gl_editor->e_clock); - clock_delay(x->gl_editor->e_clock, 5); + sys_queuegui(x, glist_getcanvas(x), delay_move); x->gl_editor->e_xnew = xpos; x->gl_editor->e_ynew = ypos; } @@ -3338,6 +3418,7 @@ void canvas_startmotion(t_canvas *x) glist_getnextxy(x, &xval, &yval); if (xval == 0 && yval == 0) return; x->gl_editor->e_onmotion = MA_MOVE; + x->gl_editor->e_waittodrag = 0; x->gl_editor->e_xwas = xval; x->gl_editor->e_ywas = yval; } diff --git a/src/g_graph.c b/src/g_graph.c index d33c26aff2..eaff3fae89 100644 --- a/src/g_graph.c +++ b/src/g_graph.c @@ -800,33 +800,23 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis) t_float upix, lpix; if (y2 < y1) upix = y1, lpix = y2; - else upix = y2, lpix = y1; - for (i = 0, f = x->gl_xtick.k_point; - f < 0.99 * x->gl_x2 + 0.01*x->gl_x1; i++, - f += x->gl_xtick.k_inc) - { - int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4); - _graph_create_line4(x, - (int)glist_xtopixels(x, f), (int)upix, - (int)glist_xtopixels(x, f), (int)upix - tickpix, - tags2); - _graph_create_line4(x, - (int)glist_xtopixels(x, f), (int)lpix, - (int)glist_xtopixels(x, f), (int)lpix + tickpix, - tags2); - } - for (i = 1, f = x->gl_xtick.k_point - x->gl_xtick.k_inc; - f > 0.99 * x->gl_x1 + 0.01*x->gl_x2; - i++, f -= x->gl_xtick.k_inc) + else + upix = y2, lpix = y1; + + for (i = (int)((x->gl_x1 - x->gl_xtick.k_point) / x->gl_xtick.k_inc) + (x->gl_xtick.k_pointgl_x1); + i <= (int)((x->gl_x2 - x->gl_xtick.k_point) / x->gl_xtick.k_inc) - (x->gl_xtick.k_point>x->gl_x2); + i++) { + t_float fx = x->gl_xtick.k_point + (i * x->gl_xtick.k_inc); int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4); + int ix = (int)glist_xtopixels(x, x->gl_xtick.k_point + (i * x->gl_xtick.k_inc)); _graph_create_line4(x, - (int)glist_xtopixels(x, f), (int)upix, - (int)glist_xtopixels(x, f), (int)upix - tickpix, + ix, (int)upix, + ix, (int)upix - tickpix, tags2); _graph_create_line4(x, - (int)glist_xtopixels(x, f), (int)lpix, - (int)glist_xtopixels(x, f), (int)lpix + tickpix, + ix, (int)lpix, + ix, (int)lpix + tickpix, tags2); } } @@ -837,33 +827,23 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis) t_float ubound, lbound; if (x->gl_y2 < x->gl_y1) ubound = x->gl_y1, lbound = x->gl_y2; - else ubound = x->gl_y2, lbound = x->gl_y1; - for (i = 0, f = x->gl_ytick.k_point; - f < 0.99 * ubound + 0.01 * lbound; - i++, f += x->gl_ytick.k_inc) - { - int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4); - _graph_create_line4(x, - x1, (int)glist_ytopixels(x, f), - x1 + tickpix, (int)glist_ytopixels(x, f), - tags2); - _graph_create_line4(x, - x2, (int)glist_ytopixels(x, f), - x2 - tickpix, (int)glist_ytopixels(x, f), - tags2); - } - for (i = 1, f = x->gl_ytick.k_point - x->gl_ytick.k_inc; - f > 0.99 * lbound + 0.01 * ubound; - i++, f -= x->gl_ytick.k_inc) + else + ubound = x->gl_y2, lbound = x->gl_y1; + for (i = (int)((lbound - x->gl_ytick.k_point) / x->gl_ytick.k_inc) + (x->gl_ytick.k_pointgl_ytick.k_point) / x->gl_ytick.k_inc) - (x->gl_ytick.k_point>ubound); + i++) { + t_float fy = x->gl_ytick.k_point + (i * x->gl_ytick.k_inc); int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4); + int iy = (int)glist_ytopixels(x, fy); + _graph_create_line4(x, - x1, (int)glist_ytopixels(x, f), - x1 + tickpix, (int)glist_ytopixels(x, f), + x1, iy, + x1 + tickpix, iy, tags2); _graph_create_line4(x, - x2, (int)glist_ytopixels(x, f), - x2 - tickpix, (int)glist_ytopixels(x, f), + x2, iy, + x2 - tickpix, iy, tags2); } } @@ -1000,11 +980,13 @@ static void graph_select(t_gobj *z, t_glist *glist, int state) sprintf(tag, "%sR", rtext_gettag(y)); pdgui_vmess(0, "crs rr", glist, "itemconfigure", tag, - "-fill", (state? "blue" : "black")); + "-fill", (state? THISGUI->i_selectcolor->s_name : + THISGUI->i_foregroundcolor->s_name)); sprintf(tag, "graph%lx", (t_int)z); pdgui_vmess(0, "crs rr", glist_getcanvas(glist), "itemconfigure", tag, - "-fill", (state? "blue" : "black")); + "-fill", (state? THISGUI->i_selectcolor->s_name : + THISGUI->i_foregroundcolor->s_name)); } } @@ -1088,7 +1070,7 @@ static int graph_click(t_gobj *z, struct _glist *glist, { int x1, y1, x2, y2; /* check if the object wants to be clicked */ - if (canvas_hitbox(x, y, xpix, ypix, &x1, &y1, &x2, &y2) + if (canvas_hitbox(x, y, xpix, ypix, &x1, &y1, &x2, &y2, 0) && (clickreturned = gobj_click(y, x, xpix, ypix, shift, alt, dbl, doit))) break; @@ -1128,6 +1110,7 @@ t_glist *glist_findgraph(t_glist *x) extern void canvas_menuarray(t_glist *canvas); +void glist_removearray(t_glist *x, t_symbol *name); /* in emscripten, the function signatures must match exactly (including the return type), so we need a (void)-returning wrapper around graph_array() to be used as canvas-method @@ -1135,9 +1118,13 @@ extern void canvas_menuarray(t_glist *canvas); static void _graph_array(t_glist *gl, t_symbol *s, t_symbol *templateargsym, t_floatarg fsize, t_floatarg fflags) { - graph_array(gl, s, templateargsym, fsize, fflags); + if(templateargsym == gensym("")) { + glist_removearray(gl, s); + glist_redraw(gl); + } else { + graph_array(gl, s, templateargsym, fsize, fflags); + } } - void g_graph_setup_class(t_class *c) { class_setwidget(c, &graph_widgetbehavior); @@ -1152,7 +1139,7 @@ void g_graph_setup_class(t_class *c) class_addmethod(c, (t_method)graph_ylabel, gensym("ylabel"), A_GIMME, 0); class_addmethod(c, (t_method)_graph_array, gensym("array"), - A_SYMBOL, A_FLOAT, A_SYMBOL, A_DEFFLOAT, A_NULL); + A_SYMBOL, A_DEFFLOAT, A_DEFSYMBOL, A_DEFFLOAT, A_NULL); class_addmethod(c, (t_method)canvas_menuarray, gensym("menuarray"), A_NULL); class_addmethod(c, (t_method)glist_sort, diff --git a/src/g_radio.c b/src/g_radio.c index bcc79cc2c1..6acd2ee8f1 100644 --- a/src/g_radio.c +++ b/src/g_radio.c @@ -44,10 +44,11 @@ static void radio_draw_io(t_radio* x, t_glist* glist, int old_snd_rcv_flags) if(!x->x_gui.x_fsf.x_snd_able) { int height = x->x_gui.x_h * ((x->x_orientation == horizontal)? 1: x->x_number); - pdgui_vmess(0, "crr iiii rs rS", canvas, "create", "rectangle", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos, ypos + height + zoom - ioh, xpos + iow, ypos + height, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 2, tags); /* keep buttons above outlet */ @@ -58,10 +59,11 @@ static void radio_draw_io(t_radio* x, t_glist* glist, int old_snd_rcv_flags) pdgui_vmess(0, "crs", canvas, "delete", tag); if(!x->x_gui.x_fsf.x_rcv_able) { - pdgui_vmess(0, "crr iiii rs rS", canvas, "create", "rectangle", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos, ypos, xpos + iow, ypos - zoom + ioh, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 2, tags); /* keep buttons above inlet */ diff --git a/src/g_readwrite.c b/src/g_readwrite.c index 30de95ce9e..54666e6380 100644 --- a/src/g_readwrite.c +++ b/src/g_readwrite.c @@ -715,6 +715,7 @@ static void canvas_saveto(t_canvas *x, t_binbuf *b) binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"), srcno, t.tr_outno, sinkno, t.tr_inno); } + /* unless everything is the default (as in ordinary subpatches) print out a "coords" message to set up the coordinate systems */ if (x->gl_isgraph || x->gl_x1 || x->gl_y1 || @@ -737,6 +738,36 @@ static void canvas_saveto(t_canvas *x, t_binbuf *b) (t_float)x->gl_pixwidth, (t_float)x->gl_pixheight, (t_float)x->gl_isgraph); } + + /* graph ticks and labels */ + if (x->gl_isgraph) + { + if (x->gl_xtick.k_lperb) { + binbuf_addv(b, "ssffi;", gensym("#X"), gensym("xticks"), + x->gl_xtick.k_point, x->gl_xtick.k_inc, x->gl_xtick.k_lperb); + } + if (x->gl_ytick.k_lperb) { + binbuf_addv(b, "ssffi;", gensym("#X"), gensym("yticks"), + x->gl_ytick.k_point, x->gl_ytick.k_inc, x->gl_ytick.k_lperb); + } + + if(x->gl_nxlabels>0) { + int i; + binbuf_addv(b, "ssf", gensym("#X"), gensym("xlabel"), x->gl_xlabely); + for(i=0; igl_nxlabels; i++) { + binbuf_addv(b, "s", x->gl_xlabel[i]); + } + binbuf_addv(b, ";"); + } + if(x->gl_nylabels>0) { + int i; + binbuf_addv(b, "ssf", gensym("#X"), gensym("ylabel"), x->gl_ylabelx); + for(i=0; igl_nylabels; i++) { + binbuf_addv(b, "s", x->gl_ylabel[i]); + } + binbuf_addv(b, ";"); + } + } } /* call this recursively to collect all the template names for @@ -818,11 +849,11 @@ static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir, { /* if not an abstraction, reset title bar and directory */ if (!x->gl_owner) -{ + { canvas_rename(x, filename, dir); /* update window list in case Save As changed the window name */ canvas_updatewindowlist(); -} + } post("saved to: %s/%s", dir->s_name, filename->s_name); canvas_dirty(x, 0); canvas_reload(filename, dir, x); diff --git a/src/g_rtext.c b/src/g_rtext.c index cf955d4ea7..4bfe3df6f8 100644 --- a/src/g_rtext.c +++ b/src/g_rtext.c @@ -36,6 +36,7 @@ struct _rtext t_word *x_words; /* ... and if so, associated data */ t_gobj *x_drawtext; /* ... and the drawing instruction */ t_glist *x_glist; /* glist owner belongs to */ + t_symbol *x_color; /* X11-style name of color to draw */ char x_tag[50]; /* tag for gui */ struct _rtext *x_next; /* next in editor list */ int x_xpix; /* (x,y) origin in pixels */ @@ -55,6 +56,7 @@ static t_rtext *rtext_add(t_glist *glist, t_rtext *last) x->x_words = 0; x->x_drawtext = 0; x->x_glist = glist; + x->x_color = THISGUI->i_foregroundcolor; x->x_selstart = x->x_selend = x->x_active = 0; x->x_buf = 0; x->x_bufsize = 0; @@ -133,6 +135,15 @@ void rtext_free(t_rtext *x) freebytes(x, sizeof *x); } +void rtext_setcolor(t_rtext *x, int color) +{ + char buf[80]; + pd_snprintf(buf, 80, "#%06x", color); + buf[79] = 0; + x->x_color = gensym(buf); +} + + static void rtext_findscreenlocation(t_rtext *x) { int x2, y2; @@ -585,7 +596,8 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp, tempbuf, guifontsize, (x->x_text && glist_isselected(x->x_glist, &x->x_text->te_g)? - "blue" : "black")); + THISGUI->i_selectcolor->s_name : + x->x_color->s_name)); } else if (action == SEND_UPDATE) { @@ -636,6 +648,8 @@ void rtext_retext(t_rtext *x) x->x_buf = resizebytes(x->x_buf, x->x_bufsize, x->x_bufsize+1); x->x_buf[x->x_bufsize] = 0; rtext_findscreenlocation(x); + /* force dimension recalculation after text conversion */ + x->x_pixwidth = x->x_pixheight = -1; rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); } @@ -687,7 +701,8 @@ void rtext_select(t_rtext *x, int state) { pdgui_vmess(0, "crs rr", glist_getcanvas(x->x_glist), "itemconfigure", x->x_tag, - "-fill", (state? "blue" : "black")); + "-fill", (state? THISGUI->i_selectcolor->s_name: + THISGUI->i_foregroundcolor->s_name)); } void rtext_activate(t_rtext *x, int state) diff --git a/src/g_scalar.c b/src/g_scalar.c index b5b3be8139..88329bcf95 100644 --- a/src/g_scalar.c +++ b/src/g_scalar.c @@ -131,66 +131,6 @@ void gpointer_init(t_gpointer *gp) gp->gp_un.gp_scalar = 0; } -/********* random utility function to find a binbuf in a datum */ - -/* get the template for the object pointer to. Assumes we've already checked -freshness. */ - -t_symbol *gpointer_gettemplatesym(const t_gpointer *gp) -{ - t_gstub *gs = gp->gp_stub; - if (gs->gs_which == GP_GLIST) - { - t_scalar *sc = gp->gp_un.gp_scalar; - if (sc) - return (sc->sc_template); - else return (0); - } - else - { - t_array *a = gs->gs_un.gs_array; - return (a->a_templatesym); - } -} - -t_binbuf *pointertobinbuf(t_pd *x, t_gpointer *gp, t_symbol *s, - const char *fname) -{ - t_symbol *templatesym = gpointer_gettemplatesym(gp), *arraytype; - t_template *template; - int onset, type; - t_binbuf *b; - t_gstub *gs = gp->gp_stub; - t_word *vec; - if (!templatesym) - { - pd_error(x, "%s: bad pointer", fname); - return (0); - } - if (!(template = template_findbyname(templatesym))) - { - pd_error(x, "%s: couldn't find template %s", fname, - templatesym->s_name); - return (0); - } - if (!template_find_field(template, s, &onset, &type, &arraytype)) - { - pd_error(x, "%s: %s.%s: no such field", fname, - templatesym->s_name, s->s_name); - return (0); - } - if (type != DT_TEXT) - { - pd_error(x, "%s: %s.%s: not a list", fname, - templatesym->s_name, s->s_name); - return (0); - } - if (gs->gs_which == GP_ARRAY) - vec = gp->gp_un.gp_w; - else vec = gp->gp_un.gp_scalar->sc_vec; - return (vec[onset].w_binbuf); -} - void word_init(t_word *wp, t_template *template, t_gpointer *gp) { int i, nitems = template->t_n; @@ -500,7 +440,7 @@ static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy) SETPOINTER(&at[0], &gp); SETFLOAT(&at[1], (t_float)dx); SETFLOAT(&at[2], (t_float)dy); - template_notify(template, gensym("displace"), 2, at); + template_notify(template, gensym("displace"), 3, at); scalar_redraw(x, glist); } @@ -583,7 +523,7 @@ int scalar_doclick(t_word *data, t_template *template, t_scalar *sc, t_float xloc, t_float yloc, int xpix, int ypix, int shift, int alt, int dbl, int doit) { - int hit = 0; + int hit = 0, notified = 0; t_canvas *templatecanvas = template_findcanvas(template); t_gobj *y; for (y = templatecanvas->gl_list; y; y = y->g_next) @@ -594,7 +534,7 @@ int scalar_doclick(t_word *data, t_template *template, t_scalar *sc, data, template, sc, ap, xloc, yloc, xpix, ypix, shift, alt, dbl, doit))) { - if (doit) + if (doit && !notified) { t_atom at[6]; SETFLOAT(at, 0); /* unused - later bashed to the gpointer */ @@ -605,8 +545,13 @@ int scalar_doclick(t_word *data, t_template *template, t_scalar *sc, SETFLOAT(at+5, dbl); template_notifyforscalar(template, owner, sc, gensym("click"), 6, at); + notified = 1; } - return (hit); + /* hit might be -1 (see curve_click()) indicating "scalar + was notified" but keep looking for something to start dragging + so continue the search until hit is positive. */ + if (hit > 0) + return (hit); } } return (0); diff --git a/src/g_slider.c b/src/g_slider.c index a8ee30f3fa..ae0a1d2d8a 100644 --- a/src/g_slider.c +++ b/src/g_slider.c @@ -62,10 +62,11 @@ static void slider_draw_io(t_slider* x, t_glist* glist, int old_snd_rcv_flags) pdgui_vmess(0, "crs", canvas, "delete", tag); if(!x->x_gui.x_fsf.x_snd_able) { - pdgui_vmess(0, "crr iiii rs rS", canvas, "create", "rectangle", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos - lmargin, ypos + x->x_gui.x_h + bmargin + zoom - ioh, xpos - lmargin + iow, ypos + x->x_gui.x_h + bmargin, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 2, tags); /* keep knob above outlet */ @@ -76,10 +77,11 @@ static void slider_draw_io(t_slider* x, t_glist* glist, int old_snd_rcv_flags) pdgui_vmess(0, "crs", canvas, "delete", tag); if(!x->x_gui.x_fsf.x_rcv_able) { - pdgui_vmess(0, "crr iiii rs rS", canvas, "create", "rectangle", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos - lmargin, ypos - tmargin, xpos - lmargin + iow, ypos - tmargin - zoom + ioh, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 2, tags); /* keep knob above inlet */ diff --git a/src/g_template.c b/src/g_template.c index 6c12335dee..d769edde56 100644 --- a/src/g_template.c +++ b/src/g_template.c @@ -1497,12 +1497,17 @@ static int curve_click(t_gobj *z, t_glist *glist, { /* if we're in the bounding rect and the draggable flag is set we can drag the whole object; othrwise we don't - do anything. But we still return 1 if we're in the rectangle - so that the struct object can notify the patch of the click. */ + do anything. But we still return -1 if we're in the rectangle + so that the struct object can notify the patch of the click. + The "-1" tells scalar_doclick() to call template_notifyforscalar() + but scalar_click() then returns 0 so that the search for a click + will continue. This way, all polygons that got clicked on will + get notified up to and until someone gets bonked on a hot point, + at which point the search stops. */ if (xpix < x1 || xpix > x2 || ypix < y1 || ypix > y2) return (0); if (!(x->x_flags & DRAGGABLE)) - return (1); + return (-1); } if (doit) { @@ -2400,7 +2405,7 @@ static int array_doclick_element(t_array *array, t_glist *glist, (t_word *)((char *)(array->a_vec) + i * elemsize), elemtemplate, 0, array, glist, usexloc, useyloc, - xpix, ypix, shift, alt, dbl, doit))) + xpix, ypix, shift, alt, dbl, doit)) > 0) return (hit); } return (0); @@ -2905,6 +2910,8 @@ static void drawtext_activate(t_gobj *z, t_glist *glist, post("drawtext_activate %d", state); } +void rtext_setcolor(t_rtext *x, int color); + static void drawtext_vis(t_gobj *z, t_glist *glist, t_word *data, t_template *template, t_scalar *sc, t_float basex, t_float basey, int vis) @@ -2946,6 +2953,7 @@ static void drawtext_vis(t_gobj *z, t_glist *glist, "-font", 3, fontatoms, "-tags", 2, tags); /* draw text */ + rtext_setcolor(rtext, color); drawtext_gettext(z, data, &textbuf, &textlen); rtext_retextforscalar(rtext, textbuf, textlen, xloc + glist_fontwidth(glist) * strlen(x->x_label->s_name), yloc); diff --git a/src/g_text.c b/src/g_text.c index 2afb87d2a0..93ef603295 100644 --- a/src/g_text.c +++ b/src/g_text.c @@ -140,9 +140,8 @@ static void canvas_objtext(t_glist *gl, int xpix, int ypix, int width, if (!pd_this->pd_newest) x = 0; else if (!(x = pd_checkobject(pd_this->pd_newest))) - { - canvas_error_couldntcreate(0, b, "... didn't return a patchable object"); - } + canvas_error_couldntcreate(0, b, + "... didn't return a patchable object"); } else x = 0; if (!x) @@ -1133,7 +1132,8 @@ static void gatom_vis(t_gobj *z, t_glist *glist, int vis) 3, tags, (double)x1, (double)y1, canvas_realizedollar(x->a_glist, x->a_label)->s_name, - gatom_fontsize(x) * glist_getzoom(glist), "black"); + gatom_fontsize(x) * glist_getzoom(glist), + THISGUI->i_foregroundcolor->s_name); } else pdgui_vmess(0, "crs", glist_getcanvas(glist), "delete", buf); @@ -1338,7 +1338,8 @@ static void text_select(t_gobj *z, t_glist *glist, int state) glist, "itemconfigure", buf, - "-fill", (state? "blue" : "black")); + "-fill", (state? THISGUI->i_selectcolor->s_name : + THISGUI->i_foregroundcolor->s_name)); } } @@ -1520,11 +1521,12 @@ void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime, tags[0] = tagbuf; tags[1] = "outlet"; if (firsttime) - pdgui_vmess(0, "crr iiii rS rr", + pdgui_vmess(0, "crr iiii rS rr rr", glist_getcanvas(glist), "create", "rectangle", onset, y2 - oh + glist->gl_zoom, onset + iow, y2, "-tags", (int)(sizeof(tags)/sizeof(*tags)), tags, - "-fill", "black"); + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name); else pdgui_vmess(0, "crs iiii", glist_getcanvas(glist), "coords", tagbuf, @@ -1539,12 +1541,13 @@ void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime, tags[0] = tagbuf; tags[1] = "inlet"; if (firsttime) - pdgui_vmess(0, "crr iiii rS rr", + pdgui_vmess(0, "crr iiii rS rr rr", glist_getcanvas(glist), "create", "rectangle", onset, y1, onset + iow, y1 + ih - glist->gl_zoom, "-tags", (int)(sizeof(tags)/sizeof(*tags)), tags, - "-fill", "black"); + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name); else pdgui_vmess(0, "crs iiii", glist_getcanvas(glist), "coords", tagbuf, @@ -1567,11 +1570,12 @@ void text_drawborder(t_text *x, t_glist *glist, char *pattern = ((pd_class(&x->te_pd) == text_class) ? "-" : "\"\""); char *tags[] = {tagR, "obj"}; if (firsttime) - pdgui_vmess(0, "crr iiiiiiiiii rr ri rr rS", + pdgui_vmess(0, "crr iiiiiiiiii rr ri rr rr rS", glist_getcanvas(glist), "create", "line", x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, "-dash", pattern, "-width", glist->gl_zoom, + "-fill", THISGUI->i_foregroundcolor->s_name, "-capstyle", "projecting", "-tags", 2, tags); else @@ -1591,11 +1595,12 @@ void text_drawborder(t_text *x, t_glist *glist, if (corner > 10*glist->gl_zoom) corner = 10*glist->gl_zoom; /* looks bad if too big */ if (firsttime) - pdgui_vmess(0, "crr iiiiiiiiiiiiii ri rr rS", + pdgui_vmess(0, "crr iiiiiiiiiiiiii ri rr rr rS", glist_getcanvas(glist), "create", "line", x1, y1, x2+corner, y1, x2, y1+corner, x2, y2-corner, x2+corner, y2, x1, y2, x1, y1, "-width", glist->gl_zoom, + "-fill", THISGUI->i_foregroundcolor->s_name, "-capstyle", "projecting", "-tags", 2, tags); else @@ -1613,11 +1618,12 @@ void text_drawborder(t_text *x, t_glist *glist, char *tags[] = {tagR, "atom"}; corner = ((y2-y1)/4); if (firsttime) - pdgui_vmess(0, "crr iiiiiiiiiiii ri rr rS", + pdgui_vmess(0, "crr iiiiiiiiiiii ri rr rr rS", glist_getcanvas(glist), "create", "line", x1p, y1p, x2-corner, y1p, x2, y1p+corner, x2, y2, x1p, y2, x1p, y1p, "-width", glist->gl_zoom+grabbed, + "-fill", THISGUI->i_foregroundcolor->s_name, "-capstyle", "projecting", "-tags", 2, tags); else @@ -1638,12 +1644,13 @@ void text_drawborder(t_text *x, t_glist *glist, char *tags[] = {tagR, "atom"}; corner = ((y2-y1)/4); if (firsttime) - pdgui_vmess(0, "crr iiiiiiiiiiiiii ri rr rS", + pdgui_vmess(0, "crr iiiiiiiiiiiiii ri rr rr rS", glist_getcanvas(glist), "create", "line", x1p, y1p, x2-corner, y1p, x2, y1p+corner, x2, y2-corner, x2-corner, y2, x1p, y2, x1p, y1p, "-width", glist->gl_zoom+grabbed, + "-fill", THISGUI->i_foregroundcolor->s_name, "-capstyle", "projecting", "-tags", 2, tags); else @@ -1664,9 +1671,10 @@ void text_drawborder(t_text *x, t_glist *glist, { char *tags[] = {tagR, "commentbar"}; if (firsttime) - pdgui_vmess(0, "crr iiii rS", + pdgui_vmess(0, "crr iiii rr rS", glist_getcanvas(glist), "create", "line", x2, y1, x2, y2, + "-fill", THISGUI->i_foregroundcolor->s_name, "-tags", 2, tags); else pdgui_vmess(0, "crs iiii", @@ -1769,6 +1777,13 @@ void text_setto(t_text *x, t_glist *glist, const char *buf, int bufsize) (void *)canvas_undo_set_recreate(glist_getcanvas(glist), &x->te_g, pos)); binbuf_text(x->te_binbuf, buf, bufsize); + + /* retext, so we see the binbuf representation + * rather than the literal text. + * otherwise, we are in for a surprise when the + * patch is reloaded/copied/duplicated/... + */ + glist_retext(glist, x); } } diff --git a/src/g_traversal.c b/src/g_traversal.c index 21310a1e30..4d3b5b43b9 100644 --- a/src/g_traversal.c +++ b/src/g_traversal.c @@ -18,6 +18,7 @@ append - add an element to a list #include #include "m_pd.h" #include "g_canvas.h" +#include "m_private_utils.h" /* templates are named using the name-bashing by which canvases bind thenselves, with a leading "pd-". LATER see if we can have templates @@ -78,12 +79,12 @@ t_gpointer *pcommon_get(t_symbol *s) gpointer_init(&c->c_gp); c->c_refcount = 0; pd_bind(&c->c_pd, s); - post("new pcommon"); } c->c_refcount++; return (&c->c_gp); } + /* release a variable. This only frees the "vcommon" resource when the last interested party releases it. */ void pcommon_release(t_symbol *s) @@ -102,6 +103,55 @@ void pcommon_release(t_symbol *s) else bug("pointer_release"); } + /* set current pointer to 'gobj' and output it. gobj must either + point to a scalar or be zero. */ +static void ptrobj_setandoutput(t_ptrobj *x, t_gobj *gobj) +{ + if (gobj) + { + t_typedout *to; + int n; + t_scalar *sc = (t_scalar *)gobj; + t_symbol *templatesym = sc->sc_template; + + x->x_gpp->gp_un.gp_scalar = sc; + for (n = x->x_ntypedout, to = x->x_typedout; n--; to++) + { + if (to->to_type == templatesym) + { + outlet_pointer(to->to_outlet, x->x_gpp); + return; + } + } + outlet_pointer(x->x_otherout, x->x_gpp); + } + else + { + gpointer_unset(x->x_gpp); + outlet_bang(x->x_bangout); + } +} + +/* get the template for the object pointer to. Assumes we've already checked +freshness. */ + +static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp) +{ + t_gstub *gs = gp->gp_stub; + if (gs->gs_which == GP_GLIST) + { + t_scalar *sc = gp->gp_un.gp_scalar; + if (sc) + return (sc->sc_template); + else return (0); + } + else + { + t_array *a = gs->gs_un.gs_array; + return (a->a_templatesym); + } +} + static void pcommon_pointer(t_pcommon *x, t_gpointer *gp) { gpointer_unset(&x->c_gp); @@ -136,12 +186,274 @@ static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv) return (x); } -static void ptrobj_set(t_ptrobj *x, t_gpointer *gp) +/* we need a def for incorrectly setting an atom to a binbuf - just use +anything that isn't A_FLOAT or A_SYMBOL: */ + +#define A_BINBUF A_CANT +#define TRAVERSAL_NGETBYTE 100 /* bigger that this we use alloc, not alloca */ + +static void ptrobj_doget(t_ptrobj *x, int argc, t_atom *argv) { - gpointer_unset(x->x_gpp); - *x->x_gpp = *gp; - if (gp->gp_stub) - gp->gp_stub->gs_refcount++; + int nout, i; + t_atom *at; + for (i = nout = 0; i < argc; i++) + if (argv->a_type == A_BINBUF) + nout += binbuf_getnatom(argv[i].a_w.w_binbuf); + else nout++; + ALLOCA(t_atom, at, nout, TRAVERSAL_NGETBYTE); + for (i = nout = 0; i < argc; i++) + { + if (argv[i].a_type == A_BINBUF) + { + int ncopy = binbuf_getnatom(argv[i].a_w.w_binbuf), j; + t_atom *copyvec = binbuf_getvec(argv[i].a_w.w_binbuf); + for (j = 0; j < ncopy; j++) + at[nout++] = copyvec[j]; + } + else at[nout++] = argv[i]; + } + outlet_list(x->x_bangout, 0, nout, at); + FREEA(t_atom, at, nout, TRAVERSAL_NGETBYTE); +} + +static void ptrobj_get(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv) +{ + int narg, nout = 0; + t_template *template; + t_atom *outvec; + t_word *vec; + + /* "get ..." + if the field is an array, is of the form + [index2 subname2 ...] + to allow arbitrary-depth array traversal. Other fields are + single symbols to name them. You can "get" arbitrarily many values + in a single message, except that only the last one (or the only one) + can be a list. Output is list of all the requested fields.*/ + + if (!argc) + return; + if (!gpointer_check(x->x_gpp, 0)) + { + pd_error(x, "pointer_set: stale or empty pointer"); + return; + } + if (!(template = template_findbyname(gpointer_gettemplatesym(x->x_gpp)))) + { + pd_error(x, "pointer_set: couldn't find template %s", + gpointer_gettemplatesym(x->x_gpp)->s_name); + return; + } + ALLOCA(t_atom, outvec, argc, TRAVERSAL_NGETBYTE); + if (x->x_gpp->gp_stub->gs_which == GP_ARRAY) + vec = x->x_gpp->gp_un.gp_w; + else vec = x->x_gpp->gp_un.gp_scalar->sc_vec; + for (narg = 0; narg < argc; ) + { + t_template *elemtemplate = template; + int onset, type, indx, elemsize, nitems; + t_symbol *arraytype; + t_array *array; + if (argv[narg].a_type != A_SYMBOL) + { + pd_error(x, "pointer_get: non-symbol field name:"); + postatom(argc-narg, argv+narg); + goto fail; + } + if (!template_find_field(elemtemplate, argv[narg].a_w.w_symbol, + &onset, &type, &arraytype)) + { + pd_error(x, "pointer_get: %s.%s: no such field", + elemtemplate->t_sym->s_name, argv[narg].a_w.w_symbol->s_name); + goto fail; + } + while (type == DT_ARRAY) + { + if (narg + 2 >= argc || argv[narg+1].a_type != A_FLOAT || + argv[narg+2].a_type != A_SYMBOL) + { + pd_error(x, + "pointer_get: array %s.%s needs index and subfield name", + elemtemplate->t_sym->s_name, + argv[narg].a_w.w_symbol->s_name); + goto fail; + } + if (!(elemtemplate = template_findbyname(arraytype))) + { + pd_error(x, "pointer_get: couldn't find template %s", + arraytype->s_name); + goto fail; + } + array = *(t_array **)(((char *)vec) + onset); + if (!template_find_field(elemtemplate, argv[narg+2].a_w.w_symbol, + &onset, &type, &arraytype)) + { + pd_error(x, "pointer_get: %s.%s: no such field", + elemtemplate->t_sym->s_name, + argv[narg+2].a_w.w_symbol->s_name); + goto fail; + } + elemsize = elemtemplate->t_n * sizeof(t_word); + + nitems = array->a_n; + indx = argv[narg+1].a_w.w_float; + if (indx < 0) + indx = 0; + if (indx >= nitems) + indx = nitems-1; + + vec = (t_word *)((char *)(array->a_vec) + indx * elemsize); + narg += 2; + } + if (type == DT_FLOAT) + SETFLOAT(&outvec[nout], + ((t_word *)(((char *)vec) + onset))->w_float); + else if (type == DT_SYMBOL) + SETSYMBOL(&outvec[nout], + ((t_word *)(((char *)vec) + onset))->w_symbol); + else outvec[nout].a_type = A_BINBUF, + outvec[nout].a_w.w_binbuf = + ((t_word *)(((char *)vec) + onset))->w_binbuf; + narg++; + nout++; + } + ptrobj_doget(x, nout, outvec); +fail: + FREEA(t_atom, outvec, argc, TRAVERSAL_NGETBYTE); +} + +static void ptrobj_set(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv) +{ + int narg; + t_template *template; + t_word *vec; + + /* original form: "set sets our pointer. */ + if (argc == 1 && argv->a_type == A_POINTER) + { + gpointer_unset(x->x_gpp); + *x->x_gpp = *(argv->a_w.w_gpointer); + if (x->x_gpp->gp_stub) + x->x_gpp->gp_stub->gs_refcount++; + return; + } + /* otherwise, it's a second-form message, "set ..." + if the field is an array, is of the form + [index2 subname2 ...] + to allow arbitrary-depth array traversal. Other fields are + single symbols to name them. You can "set" arbitrarily many values + in a single message, except that if you set a field that happens to + be a list, the whole rest of the message is the new list. */ + + if (!gpointer_check(x->x_gpp, 0)) + { + pd_error(x, "pointer_set: stale or empty pointer"); + return; + } + if (!(template = template_findbyname(gpointer_gettemplatesym(x->x_gpp)))) + { + pd_error(x, "pointer_set: couldn't find template %s", + gpointer_gettemplatesym(x->x_gpp)->s_name); + return; + } + if (x->x_gpp->gp_stub->gs_which == GP_ARRAY) + vec = x->x_gpp->gp_un.gp_w; + else vec = x->x_gpp->gp_un.gp_scalar->sc_vec; + for (narg = 0; narg < argc; ) + { + t_template *elemtemplate = template; + int onset, type, indx, elemsize, nitems; + t_symbol *arraytype; + t_array *array; + if (argv[narg].a_type != A_SYMBOL) + { + pd_error(x, "pointer_set: non-symbol field name:"); + postatom(argc-narg, argv+narg); + return; + } + if (!template_find_field(elemtemplate, argv[narg].a_w.w_symbol, + &onset, &type, &arraytype)) + { + pd_error(x, "pointer_set: %s.%s: no such field", + elemtemplate->t_sym->s_name, argv[narg].a_w.w_symbol->s_name); + return; + } + while (type == DT_ARRAY) + { + if (narg + 3 >= argc || argv[narg+1].a_type != A_FLOAT || + argv[narg+2].a_type != A_SYMBOL) + { + pd_error(x, + "pointer_set: array %s.%s needs index and subfield name", + elemtemplate->t_sym->s_name, + argv[narg].a_w.w_symbol->s_name); + return; + } + if (!(elemtemplate = + template_findbyname(arraytype))) + { + pd_error(x, "pointer_set: couldn't find template %s", + arraytype->s_name); + return; + } + array = *(t_array **)(((char *)vec) + onset); + if (!template_find_field(elemtemplate, argv[narg+2].a_w.w_symbol, + &onset, &type, &arraytype)) + { + pd_error(x, "pointer_set: %s.%s: no such field", + elemtemplate->t_sym->s_name, + argv[narg+2].a_w.w_symbol->s_name); + return; + } + elemsize = elemtemplate->t_n * sizeof(t_word); + + nitems = array->a_n; + indx = argv[narg+1].a_w.w_float; + if (indx < 0) + indx = 0; + if (indx >= nitems) + indx = nitems-1; + + vec = (t_word *)((char *)(array->a_vec) + indx * elemsize); + narg += 2; + } + if (type == DT_FLOAT) + { + if (narg + 1 >= argc || argv[narg+1].a_type != A_FLOAT) + { + pd_error(x, "pointer_set: %s.%s: needs float argument", + elemtemplate->t_sym->s_name, + argv[narg].a_w.w_symbol->s_name); + return; + } + else ((t_word *)(((char *)vec) + onset))->w_float = + argv[narg+1].a_w.w_float; + } + else if (type == DT_SYMBOL) + { + if (narg + 1 >= argc || argv[narg+1].a_type != A_SYMBOL) + { + pd_error(x, "pointer_set: %s.%s: needs symbol argument", + elemtemplate->t_sym->s_name, + argv[narg+1].a_w.w_symbol->s_name); + return; + } + else ((t_word *)(((char *)vec) + onset))->w_symbol = + argv[narg].a_w.w_symbol; + } + else if (type == DT_TEXT) + { + t_binbuf *b = ((t_word *)(((char *)vec) + onset))->w_binbuf; + binbuf_clear(b); + binbuf_restore(b, argc - narg - 1, argv + narg+1); + goto done; + } + else bug("pointer_set"); + narg += 2; + } +done: + scalar_redraw(x->x_gpp->gp_un.gp_scalar, + x->x_gpp->gp_stub->gs_un.gs_glist); } static void ptrobj_traverse(t_ptrobj *x, t_symbol *s) @@ -151,14 +463,16 @@ static void ptrobj_traverse(t_ptrobj *x, t_symbol *s) else pd_error(x, "pointer: list '%s' not found", s->s_name); } -static void ptrobj_vnext(t_ptrobj *x, t_float f) +static void ptrobj_donext(t_ptrobj *x, int skip, t_symbol *templatesym, + int wantselected) { t_gobj *gobj; t_gpointer *gp = x->x_gpp; t_gstub *gs = gp->gp_stub; t_glist *glist; - int wantselected = (f != 0); - + int count; + if (!strcmp(templatesym->s_name, "-")) + templatesym = gensym(""); if (!gs) { pd_error(x, "pointer next: no current pointer"); @@ -182,41 +496,73 @@ static void ptrobj_vnext(t_ptrobj *x, t_float f) return; } gobj = &gp->gp_un.gp_scalar->sc_gobj; - - if (!gobj) gobj = glist->gl_list; - else gobj = gobj->g_next; - while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) || - (wantselected && !glist_isselected(glist, gobj)))) - gobj = gobj->g_next; - - if (gobj) + for (count = 0; count < skip; count++) { - t_typedout *to; - int n; - t_scalar *sc = (t_scalar *)gobj; - t_symbol *templatesym = sc->sc_template; - - gp->gp_un.gp_scalar = sc; - for (n = x->x_ntypedout, to = x->x_typedout; n--; to++) + do { - if (to->to_type == templatesym) - { - outlet_pointer(to->to_outlet, x->x_gpp); - return; - } + if (!gobj) + gobj = glist->gl_list; + else gobj = gobj->g_next; } - outlet_pointer(x->x_otherout, x->x_gpp); - } - else - { - gpointer_unset(gp); - outlet_bang(x->x_bangout); - } + while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) || + (wantselected && !glist_isselected(glist, gobj)) || + (*templatesym->s_name) && + templatesym != ((t_scalar *)gobj)->sc_template)) ; + if (!gobj) + break; + } + ptrobj_setandoutput(x, gobj); +} + +static void ptrobj_next(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv) +{ + ptrobj_donext(x, (argc ? atom_getfloat(argv) : 1), + template_getbindsym(atom_getsymbolarg(1, argc, argv)), + (atom_getfloatarg(2, argc, argv) != 0)); } -static void ptrobj_next(t_ptrobj *x) +static void ptrobj_vnext(t_ptrobj *x, t_float f) +{ + ptrobj_donext(x, 1, gensym(""), (f != 0)); +} + +static void ptrobj_nearest(t_ptrobj *x, t_floatarg xval, t_floatarg yval) { - ptrobj_vnext(x, 0); + t_gobj *gobj, *bestgobj = 0; + t_gstub *gs = x->x_gpp->gp_stub; + t_float bestdiff = 1e35; + t_glist *glist; + if (!gs) + { + pd_error(x, "pointer nearest: no current pointer"); + return; + } + if (gs->gs_which != GP_GLIST) + { + pd_error(x, "pointer nearest: initial pointer is an array"); + return; + } + glist = gs->gs_un.gs_glist; + if (glist->gl_valid != x->x_gpp->gp_valid) + { + pd_error(x, "pointer nearest: stale pointer"); + return; + } + glist = x->x_gpp->gp_stub->gs_un.gs_glist; + for (gobj = glist->gl_list; gobj; gobj = gobj->g_next) + if (pd_class(&gobj->g_pd) == scalar_class) + { + t_float thisx, thisy; + scalar_getbasexy((t_scalar *)gobj, &thisx, &thisy); + t_float diff = (thisx-xval)*(thisx-xval) + (thisy-yval)*(thisy-yval); + if (diff < bestdiff) + { + bestgobj = gobj; + bestdiff = diff; + } + } + if (bestgobj) + ptrobj_setandoutput(x, bestgobj); } static void ptrobj_delete(t_ptrobj *x) @@ -263,33 +609,8 @@ static void ptrobj_delete(t_ptrobj *x) gobj = gobj->g_next; glist_delete(glist, old); gp->gp_valid = glist->gl_valid; - if (gobj) - { - t_typedout *to; - int n; - t_scalar *sc = (t_scalar *)gobj; - t_symbol *templatesym = sc->sc_template; - - gp->gp_un.gp_scalar = sc; - for (n = x->x_ntypedout, to = x->x_typedout; n--; to++) - { - if (to->to_type == templatesym) - { - outlet_pointer(to->to_outlet, x->x_gpp); - return; - } - } - outlet_pointer(x->x_otherout, x->x_gpp); - } - else - { - gpointer_unset(gp); - outlet_bang(x->x_bangout); - } } -t_symbol *gpointer_gettemplatesym(const t_gpointer *gp); - static void ptrobj_equal(t_ptrobj *x, t_gpointer *gp) { t_symbol *templatesym; @@ -435,8 +756,11 @@ static void ptrobj_setup(void) class_addcreator((t_newmethod)ptrobj_new, gensym("vpointer"), A_GIMME, 0); class_addmethod(ptrobj_class, (t_method)ptrobj_set, gensym("set"), - A_POINTER, 0); - class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), 0); + A_GIMME, 0); + class_addmethod(ptrobj_class, (t_method)ptrobj_get, gensym("get"), + A_GIMME, 0); + class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), + A_GIMME, 0); class_addmethod(ptrobj_class, (t_method)ptrobj_send, gensym("send"), A_SYMBOL, 0); class_addmethod(ptrobj_class, (t_method)ptrobj_traverse, gensym("traverse"), @@ -450,6 +774,8 @@ static void ptrobj_setup(void) gensym("send-window"), A_GIMME, 0); class_addmethod(ptrobj_class, (t_method)ptrobj_rewind, gensym("rewind"), 0); + class_addmethod(ptrobj_class, (t_method)ptrobj_nearest, + gensym("nearest"), A_FLOAT, A_FLOAT, 0); class_addpointer(ptrobj_class, ptrobj_pointer); class_addbang(ptrobj_class, ptrobj_bang); @@ -551,7 +877,8 @@ static void get_pointer(t_get *x, t_gpointer *gp) { int onset, type; t_symbol *arraytype; - if (template_find_field(template, vp->gv_sym, &onset, &type, &arraytype)) + if (template_find_field(template, vp->gv_sym, + &onset, &type, &arraytype)) { if (type == DT_FLOAT) outlet_float(vp->gv_outlet, @@ -1284,3 +1611,43 @@ void g_traversal_setup(void) setsize_setup(); append_setup(); } + +/********* misc utility function to find a binbuf in a datum *****/ + +t_binbuf *pointertobinbuf(t_pd *x, t_gpointer *gp, t_symbol *s, + const char *fname) +{ + t_symbol *templatesym = gpointer_gettemplatesym(gp), *arraytype; + t_template *template; + int onset, type; + t_binbuf *b; + t_gstub *gs = gp->gp_stub; + t_word *vec; + if (!templatesym) + { + pd_error(x, "%s: bad pointer", fname); + return (0); + } + if (!(template = template_findbyname(templatesym))) + { + pd_error(x, "%s: couldn't find template %s", fname, + templatesym->s_name); + return (0); + } + if (!template_find_field(template, s, &onset, &type, &arraytype)) + { + pd_error(x, "%s: %s.%s: no such field", fname, + templatesym->s_name, s->s_name); + return (0); + } + if (type != DT_TEXT) + { + pd_error(x, "%s: %s.%s: not a list", fname, + templatesym->s_name, s->s_name); + return (0); + } + if (gs->gs_which == GP_ARRAY) + vec = gp->gp_un.gp_w; + else vec = gp->gp_un.gp_scalar->sc_vec; + return (vec[onset].w_binbuf); +} diff --git a/src/g_vumeter.c b/src/g_vumeter.c index a0bed06d55..a8b0e862f2 100644 --- a/src/g_vumeter.c +++ b/src/g_vumeter.c @@ -102,17 +102,19 @@ static void vu_draw_io(t_vu* x, t_glist* glist, int old_snd_rcv_flags) if(!snd_able) { sprintf(tag_n, "%pOUT%d", x, 0); - pdgui_vmess(0, "crr iiii rs rS", canvas, "create", "rectangle", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos - hmargin, ypos + x->x_gui.x_h + vmargin + zoom - ioh, xpos - hmargin + iow, ypos + x->x_gui.x_h + vmargin, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 3, tags); sprintf(tag_n, "%pOUT%d", x, 1); - pdgui_vmess(0, "crr iiii rs rS", canvas, "create", "rectangle", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos + x->x_gui.x_w + hmargin - iow, ypos + x->x_gui.x_h + vmargin + zoom - ioh, xpos + x->x_gui.x_w + hmargin, ypos + x->x_gui.x_h + vmargin, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 3, tags); /* keep label above outlets */ pdgui_vmess(0, "crss", canvas, "lower", tag, tag_label); @@ -123,17 +125,19 @@ static void vu_draw_io(t_vu* x, t_glist* glist, int old_snd_rcv_flags) if(!x->x_gui.x_fsf.x_rcv_able) { sprintf(tag_n, "%pIN%d", x, 0); - pdgui_vmess(0, "crr iiii rs rS", canvas, "create", "rectangle", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos - hmargin, ypos - vmargin, xpos - hmargin + iow, ypos - vmargin - zoom + ioh, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 3, tags); sprintf(tag_n, "%pIN%d", x, 1); - pdgui_vmess(0, "crr iiii rs rS", canvas, "create", "rectangle", + pdgui_vmess(0, "crr iiii rs rs rS", canvas, "create", "rectangle", xpos + x->x_gui.x_w + hmargin - iow, ypos - vmargin, xpos + x->x_gui.x_w + hmargin, ypos - vmargin - zoom + ioh, - "-fill", "black", + "-fill", THISGUI->i_foregroundcolor->s_name, + "-outline", THISGUI->i_foregroundcolor->s_name, "-tags", 3, tags); /* keep label above inlets */ pdgui_vmess(0, "crss", canvas, "lower", tag, tag_label); @@ -467,6 +471,8 @@ static void vu_ft1(t_vu *x, t_floatarg peak) { int i; int old = x->x_peak; + if (PD_BADFLOAT(peak)) + return; if(peak <= IEM_VU_MINDB) x->x_peak = 0; else if(peak >= IEM_VU_MAXDB) diff --git a/src/m_glob.c b/src/m_glob.c index f9785245b6..fe9219ac4b 100644 --- a/src/m_glob.c +++ b/src/m_glob.c @@ -44,6 +44,9 @@ void glob_open(t_pd *ignore, t_symbol *name, t_symbol *dir, t_floatarg f); void glob_fastforward(t_pd *ignore, t_floatarg f); void glob_settracing(void *dummy, t_floatarg f); void glob_vis(void *dummy, t_symbol *s); +void glob_closesubs(void *dummy); +void glob_colors(void *dummy, t_symbol *fg, t_symbol *bg, t_symbol *sel, + t_symbol *gop); static void glob_helpintro(t_pd *dummy) { @@ -93,6 +96,7 @@ static void glob_perf(t_pd *dummy, t_float f) sys_perf = (f != 0); } + void max_default(t_pd *x, t_symbol *s, int argc, t_atom *argv) { int i; @@ -200,6 +204,10 @@ void glob_init(void) gensym("watchdog"), 0); class_addmethod(glob_pdobject, (t_method)glob_vis, gensym("vis"), A_DEFSYM, 0); + class_addmethod(glob_pdobject, (t_method)glob_closesubs, + gensym("close-subwindows"), 0); + class_addmethod(glob_pdobject, (t_method)glob_colors, + gensym("colors"), A_SYMBOL, A_SYMBOL, A_SYMBOL, A_DEFSYMBOL, 0); class_addanything(glob_pdobject, max_default); pd_bind(&glob_pdobject, gensym("pd")); } diff --git a/src/m_obj.c b/src/m_obj.c index f58bfc3293..f542c032c2 100644 --- a/src/m_obj.c +++ b/src/m_obj.c @@ -182,7 +182,7 @@ static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv) inlet_symbol(x, atom_getsymbol(argv)); else if (x->i_symfrom == &s_signal && zgetfn(x->i_dest, gensym("fwd"))) inlet_fwd(x, &s_list, argc, argv); - else post("class %s", class_getname(*x->i_dest)), inlet_wrong(x, &s_list); + else inlet_wrong(x, &s_list); } static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv) diff --git a/src/m_pd.c b/src/m_pd.c index 7c27a08dd9..4e2c5c5adf 100644 --- a/src/m_pd.c +++ b/src/m_pd.c @@ -6,6 +6,8 @@ #include "m_imp.h" #include "g_canvas.h" /* just for LB_LOAD */ +#include + /* FIXME no out-of-memory testing yet! */ t_pd *pd_new(t_class *c) @@ -221,6 +223,42 @@ t_pd *pd_findbyclass(t_symbol *s, const t_class *c) return x; } +t_pd *pd_findbyclassname(t_symbol *s, const t_symbol *classname) +{ + t_pd *x = 0; + + if (!s->s_thing) return (0); +#ifdef PDINSTANCE + /* NB: the class name symbol is shared between instances + so we can't rely on pointer identity! */ + if (!strcmp((*s->s_thing)->c_name->s_name, classname->s_name)) + return (s->s_thing); +#else + if ((*s->s_thing)->c_name == classname) return (s->s_thing); +#endif + if (*s->s_thing == bindlist_class) + { + t_bindlist *b = (t_bindlist *)s->s_thing; + t_bindelem *e, *e2; + int warned = 0; + for (e = b->b_list; e; e = e->e_next) + #ifdef PDINSTANCE /* see above */ + if (!strcmp((*e->e_who)->c_name->s_name, classname->s_name)) + #else + if ((*e->e_who)->c_name == classname) + #endif + { + if (x && !warned) + { + post("warning: %s: multiply defined", s->s_name); + warned = 1; + } + x = e->e_who; + } + } + return x; +} + /* stack for maintaining bindings for the #X symbol during nestable loads. */ @@ -306,7 +344,8 @@ void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv) { #ifdef VST_CLEANSER int i; - vst_cleanser(&s); + if (s) + vst_cleanser(&s); for (i = 0; i < argc; i++) if (argv[i].a_type == A_SYMBOL) vst_cleanser(&argv[i].a_w.w_symbol); diff --git a/src/m_pd.h b/src/m_pd.h index c09018b0a9..9d895b6245 100644 --- a/src/m_pd.h +++ b/src/m_pd.h @@ -9,9 +9,9 @@ extern "C" { #endif #define PD_MAJOR_VERSION 0 -#define PD_MINOR_VERSION 55 -#define PD_BUGFIX_VERSION 2 -#define PD_TEST_VERSION "" +#define PD_MINOR_VERSION 56 +#define PD_BUGFIX_VERSION 0 +#define PD_TEST_VERSION "test1" /* compile-time version check: #if PD_VERSION_CODE < PD_VERSION(0, 56, 0) @@ -128,6 +128,7 @@ typedef unsigned __int64 uint64_t; EXTERN int pd_compatibilitylevel; /* e.g., 43 for pd 0.43 compatibility */ +#define DEFAULTSRATE 48000 /* default audio sample rate */ #define MAXPDSTRING 1000 /* use this for anything you want */ #define MAXPDARG 5 /* max number of args we can typecheck today */ @@ -236,6 +237,9 @@ typedef struct _atom union word a_w; } t_atom; +EXTERN_STRUCT _pdinstance; +#define t_pdinstance struct _pdinstance + EXTERN_STRUCT _class; #define t_class struct _class @@ -440,6 +444,7 @@ EXTERN void pd_free(t_pd *x); EXTERN void pd_bind(t_pd *x, t_symbol *s); EXTERN void pd_unbind(t_pd *x, t_symbol *s); EXTERN t_pd *pd_findbyclass(t_symbol *s, const t_class *c); +EXTERN t_pd *pd_findbyclassname(t_symbol *s, const t_symbol *classname); EXTERN void pd_pushsym(t_pd *x); EXTERN void pd_popsym(t_pd *x); EXTERN void pd_bang(t_pd *x); @@ -672,11 +677,23 @@ EXTERN int sys_close(int fd); EXTERN FILE *sys_fopen(const char *filename, const char *mode); EXTERN int sys_fclose(FILE *stream); -/* ------------ threading ------------------- */ +/* ------------- threading ------------------- */ + +/* NB: do not use this in externals because it may deadlock! + * For a safe alternative see pd_queue_mess() */ EXTERN void sys_lock(void); EXTERN void sys_unlock(void); EXTERN int sys_trylock(void); +typedef void (*t_messfn)(t_pd *obj, void *data); +/* send a message to a Pd object from another (helper) thread. + * 'fn' will be called on the scheduler thread with 'obj' and 'data'. + * If the message has been canceled, the 'obj' argument is NULL, see + * pd_queue_cancel() below. NB: do not forget to free the 'data' object! */ +EXTERN void pd_queue_mess(struct _pdinstance *instance, t_pd *obj, void *data, t_messfn fn); +/* cancel all pending messages for the given object; + * typically called in the object destructor AFTER joining the helper thread. */ +EXTERN void pd_queue_cancel(t_pd *obj); /* --------------- signals ----------------------------------- */ @@ -1029,7 +1046,6 @@ struct _pdinstance int pd_islocked; #endif }; -#define t_pdinstance struct _pdinstance EXTERN t_pdinstance pd_maininstance; /* m_pd.c */ diff --git a/src/m_sched.c b/src/m_sched.c index 719be5cc3b..5e5ffd1aa5 100644 --- a/src/m_sched.c +++ b/src/m_sched.c @@ -357,6 +357,8 @@ int sched_get_using_audio(void) return sched_useaudio; } +void messqueue_dispatch(); + /* take the scheduler forward one DSP tick, also handling clock timeouts */ void sched_tick(void) { @@ -380,6 +382,7 @@ void sched_tick(void) return; } pd_this->pd_systime = next_sys_time; + messqueue_dispatch(); dsp_tick(); sched_counter++; } diff --git a/src/pd.rc b/src/pd.rc index d2d8fde967..4b396e6e8e 100644 --- a/src/pd.rc +++ b/src/pd.rc @@ -1,7 +1,7 @@ id ICON "../tcl/pd.ico" 1 VERSIONINFO -FILEVERSION 0,55,2,0 -PRODUCTVERSION 0,55,2,0 +FILEVERSION 0,56,0,0 +PRODUCTVERSION 0,56,0,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -9,12 +9,12 @@ BEGIN BEGIN VALUE "CompanyName", "puredata.info" VALUE "FileDescription", "Pure Data Application" - VALUE "FileVersion", "0.55-2" + VALUE "FileVersion", "0.56-0test1" VALUE "InternalName", "pd.exe" VALUE "LegalCopyright", "Miller Puckette, et al." VALUE "OriginalFilename", "pd.exe" VALUE "ProductName", "Pure Data" - VALUE "ProductVersion", "0.55-2" + VALUE "ProductVersion", "0.56-0test1" END END diff --git a/src/s_audio_jack.c b/src/s_audio_jack.c index 6de205e1c5..f029e21e1a 100644 --- a/src/s_audio_jack.c +++ b/src/s_audio_jack.c @@ -44,8 +44,7 @@ static int jack_isopening = 0; static jack_port_t *input_port[MAX_JACK_PORTS]; static jack_port_t *output_port[MAX_JACK_PORTS]; static jack_client_t *jack_client = NULL; -static char * desired_client_name = NULL; -static const char *jack_client_names[MAX_CLIENTS]; +const char *jack_client_names[MAX_CLIENTS]; static volatile int jack_dio_error; static volatile int jack_didshutdown; static t_audiocallback jack_callback; @@ -219,7 +218,8 @@ typedef struct _jclient { int output; struct _jclient *next; } t_jclient; -static const char** jack_get_clients(void) + +static const char **jack_get_clients(void) { int jack_physicalsource = -1; int jack_physicalsink = -1; @@ -256,7 +256,8 @@ static const char** jack_get_clients(void) tmp_client_name[ match_info.rm_eo - match_info.rm_so ] = '\0'; /* check if we already have this port */ - for(tmp_client=available_clients; tmp_client; tmp_client=tmp_client->next) + for (tmp_client=available_clients; tmp_client; + tmp_client=tmp_client->next) { last_client = tmp_client; if(strcmp(tmp_client_name, tmp_client->name) == 0) { @@ -281,7 +282,7 @@ static const char** jack_get_clients(void) /* remember the capabilities of this client; * we keep input and output separate, * so we can distinguish between physical inputs and outputs - * (e.g. a client that has physical outputs but no physical inputs) + * (e.g. a client with physical outputs but no physical inputs) */ if(port && jack_port_flags) { int flags = jack_port_flags(port); @@ -304,21 +305,24 @@ static const char** jack_get_clients(void) tmp_client = tmp_client->next) { #if 0 - printf("JACK client#%d: '%s' source:%d sink:%d\n", num_clients, tmp_client->name, tmp_client->output, tmp_client->input); + printf("JACK client#%d: '%s' source:%d sink:%d\n", num_clients, + tmp_client->name, tmp_client->output, tmp_client->input); #endif jack_client_names[num_clients] = tmp_client->name; tmp_client->name = 0; /* so we don't free it later */ if(tmp_client->input) { if(jack_defaultsink < 0) jack_defaultsink = num_clients; - if ((jack_physicalsink < 0) && (tmp_client->input & JackPortIsPhysical)) - jack_physicalsink = num_clients; + if ((jack_physicalsink < 0) && (tmp_client->input & + JackPortIsPhysical)) + jack_physicalsink = num_clients; } if(tmp_client->output) { if(jack_defaultsource < 0) jack_defaultsource = num_clients; - if ((jack_physicalsource < 0) && (tmp_client->output & JackPortIsPhysical)) - jack_physicalsource = num_clients; + if ((jack_physicalsource < 0) && (tmp_client->output & + JackPortIsPhysical)) + jack_physicalsource = num_clients; } num_clients++; } @@ -454,10 +458,8 @@ int jack_open_audio(int inchans, int outchans, t_audiocallback callback) /* try to become a client of the JACK server. (If no JACK server exists, jack_client_open() don't start one up by default. It's not clear whether or not this is desirable; see long Pd list thread started by - yvan volochine, June 2013) */ - if (!desired_client_name || !strlen(desired_client_name)) - jack_client_name("pure_data"); - jack_client = jack_client_open (desired_client_name, JackNoStartServer, + yvan volochine, June 2013) */ + jack_client = jack_client_open(sys_devicename, JackNoStartServer, &status, NULL); if (status & JackFailure) { pd_error(0, "JACK: couldn't connect to server, is JACK running?"); @@ -466,10 +468,8 @@ int jack_open_audio(int inchans, int outchans, t_audiocallback callback) /* jack spits out enough messages already, do not warn */ STUFF->st_inchannels = STUFF->st_outchannels = 0; return 1; - } - if (status & JackNameNotUnique) - jack_client_name(jack_get_client_name(jack_client)); - logpost(NULL, PD_VERBOSE, "JACK: registered as '%s'", desired_client_name); + } + logpost(NULL, PD_VERBOSE, "JACK: registered as '%s'", jack_get_client_name(jack_client)); STUFF->st_inchannels = inchans; STUFF->st_outchannels = outchans; @@ -740,18 +740,6 @@ void jack_autoconnect(int v) jack_should_autoconnect = v; } -void jack_client_name(const char *name) -{ - if (desired_client_name) { - free(desired_client_name); - desired_client_name = NULL; - } - if (name) { - desired_client_name = (char*)getbytes(strlen(name) + 1); - strcpy(desired_client_name, name); - } -} - int jack_get_blocksize(void) { return jack_blocksize; diff --git a/src/s_audio_mmio.c b/src/s_audio_mmio.c index eb60f2624a..df712a637a 100644 --- a/src/s_audio_mmio.c +++ b/src/s_audio_mmio.c @@ -707,7 +707,7 @@ int mmio_open_audio(int naudioindev, int *audioindev, if (nbuf >= MAXBUFFER) { fprintf(stderr, "pd: audio buffering maxed out to %d\n", - (int)(MAXBUFFER * ((nt_blocksize * 1000.)/44100.))); + (int)(MAXBUFFER * ((nt_blocksize * 1000.)/DEFAULTSRATE))); nbuf = MAXBUFFER; } else if (nbuf < 4) nbuf = 4; diff --git a/src/s_audio_oss.c b/src/s_audio_oss.c index d98d097b83..8b4e4ed172 100644 --- a/src/s_audio_oss.c +++ b/src/s_audio_oss.c @@ -163,7 +163,8 @@ void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize, linux_fragsize = linux_fragsize/2; } /* post("adv_samples %d", oss_advance_samples); */ - nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize; + nfragment = (sys_schedadvance * (DEFAULTSRATE * 1.e-6)) + / linux_fragsize; fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels); logfragsize = ilog2(fragbytes); diff --git a/src/s_inter.c b/src/s_inter.c index 5717649d99..6560733fb3 100644 --- a/src/s_inter.c +++ b/src/s_inter.c @@ -125,6 +125,16 @@ typedef struct _guiqueue struct _guiqueue *gq_next; } t_guiqueue; +#if PDTHREADS +typedef struct _messqueue +{ + t_pd *m_obj; + void *m_data; + t_messfn m_fn; + struct _messqueue *m_next; +} t_messqueue; +#endif + struct _instanceinter { int i_nfdpoll; @@ -150,6 +160,9 @@ struct _instanceinter #endif #if PDTHREADS pthread_mutex_t i_mutex; + pthread_mutex_t i_messqueue_mutex; + t_messqueue *i_messqueue_head; + t_messqueue *i_messqueue_tail; #endif unsigned char i_recvbuf[NET_MAXPACKETSIZE]; @@ -1904,6 +1917,7 @@ void s_inter_newpdinstance(void) INTER = getbytes(sizeof(*INTER)); #if PDTHREADS pthread_mutex_init(&INTER->i_mutex, NULL); + pthread_mutex_init(&INTER->i_messqueue_mutex, NULL); pd_this->pd_islocked = 0; #endif #ifdef _WIN32 @@ -1926,6 +1940,16 @@ void s_inter_free(t_instanceinter *inter) } #if PDTHREADS pthread_mutex_destroy(&inter->i_mutex); + /* flush message queue */ + while (inter->i_messqueue_head) + { + t_messqueue *m = inter->i_messqueue_head, *next = m->m_next; + /* m_fn is responsible for freeing m_data */ + m->m_fn(NULL, m->m_data); + freebytes(m, sizeof(*m)); + inter->i_messqueue_head = next; + } + pthread_mutex_destroy(&inter->i_messqueue_mutex); #endif freebytes(inter, sizeof(*inter)); } @@ -2016,6 +2040,55 @@ int sys_trylock(void) #endif } +void pd_queue_mess(struct _pdinstance *instance, t_pd *obj, void *data, t_messfn fn) +{ + t_instanceinter *inter = instance->pd_inter; + t_messqueue *m = (t_messqueue *)getbytes(sizeof(*m)); + m->m_obj = obj; + m->m_data = data; + m->m_fn = fn; + m->m_next = 0; + pthread_mutex_lock(&inter->i_messqueue_mutex); + if (inter->i_messqueue_tail) /* add to tail */ + inter->i_messqueue_tail = (inter->i_messqueue_tail->m_next = m); + else /* empty queue */ + inter->i_messqueue_head = inter->i_messqueue_tail = m; + pthread_mutex_unlock(&inter->i_messqueue_mutex); +} + +void pd_queue_cancel(t_pd *obj) +{ + t_messqueue *m; + pthread_mutex_lock(&INTER->i_messqueue_mutex); + for (m = INTER->i_messqueue_head; m; m = m->m_next) + { + if (m->m_obj == obj) + m->m_obj = NULL; /* mark as canceled */ + } + pthread_mutex_unlock(&INTER->i_messqueue_mutex); +} + +void messqueue_dispatch(void) +{ + t_messqueue *m, *next; + /* first unlink all messages */ + pthread_mutex_lock(&INTER->i_messqueue_mutex); + m = INTER->i_messqueue_head; + INTER->i_messqueue_head = INTER->i_messqueue_tail = NULL; + pthread_mutex_unlock(&INTER->i_messqueue_mutex); + /* then dispatch (without lock!) */ + while (m) + { + /* NB: if the message has been canceled, m_obj is NULL; + we still need to call m_fn because it is responsible + for freeing the data! */ + next = m->m_next; + m->m_fn(m->m_obj, m->m_data); + freebytes(m, sizeof(*m)); + m = next; + } +} + #else /* PDTHREADS */ #ifdef TEST_LOCKING /* run standalone Pd with this to find deadlocks */ @@ -2038,4 +2111,14 @@ void sys_unlock(void) {} void pd_globallock(void) {} void pd_globalunlock(void) {} + /* doesn't really make sense without threads... */ +void pd_queue_mess(struct _pdinstance instance, t_pd *obj, void *data, t_messfn fn) +{ + fn(obj, data); +} + +void pd_queue_cancel(t_pd *obj) {} + +void messqueue_dispatch(void) {} + #endif /* PDTHREADS */ diff --git a/src/s_main.c b/src/s_main.c index 16f5bc9d00..2213abb015 100644 --- a/src/s_main.c +++ b/src/s_main.c @@ -53,6 +53,7 @@ void alsa_adddev(const char *name); #endif int sys_oktoloadfiles(int done); void sys_doneglobinit( void); +char sys_devicename[MAXPDSTRING] = "Pure Data"; int sys_debuglevel; int sys_verbose; @@ -482,6 +483,7 @@ static char *(usagemessage[]) = { "-callback -- use callbacks if possible\n", "-nocallback -- use polling-mode (true by default)\n", "-listdev -- list audio and MIDI devices\n", +"-devicename -- device name for this pd session used by audio and midi APIs\n", #ifdef USEAPI_OSS "-oss -- use OSS audio API\n", @@ -887,8 +889,7 @@ int sys_argparse(int argc, const char **argv) { if (argc < 2) goto usage; - as.a_api = API_JACK; - jack_client_name(argv[1]); + pd_snprintf(sys_devicename, MAXPDSTRING-1, argv[1]); argc -= 2; argv +=2; } #else @@ -970,6 +971,13 @@ int sys_argparse(int argc, const char **argv) sys_listplease = 1; argc--; argv++; } + else if (!strcmp(*argv, "-devicename")) + { + if (argc < 2) + goto usage; + pd_snprintf(sys_devicename, MAXPDSTRING-1, argv[1]); + argc -= 2; argv +=2; + } else if (!strcmp(*argv, "-soundindev") || !strcmp(*argv, "-audioindev")) { diff --git a/src/s_midi_alsa.c b/src/s_midi_alsa.c index 7a01116447..f812a25272 100644 --- a/src/s_midi_alsa.c +++ b/src/s_midi_alsa.c @@ -105,7 +105,7 @@ void sys_alsa_do_open_midi(int nmidiin, int *midiinvec, snd_seq_client_info_malloc(&alsainfo); snd_seq_get_client_info(midi_handle, alsainfo); - snd_seq_client_info_set_name(alsainfo,"Pure Data"); + snd_seq_client_info_set_name(alsainfo,sys_devicename); client = snd_seq_client_info_get_client(alsainfo); snd_seq_set_client_info(midi_handle, alsainfo); snd_seq_client_info_free(alsainfo); diff --git a/src/s_stuff.h b/src/s_stuff.h index 2e2297226f..00d2f3ad80 100644 --- a/src/s_stuff.h +++ b/src/s_stuff.h @@ -50,6 +50,7 @@ EXTERN int sys_havetkproc(void); /* TK is up; we can post to Pd window */ EXTERN int sys_havegui(void); /* also have font metrics and can draw */ extern const char *sys_guicmd; extern int sys_batch; +extern char sys_devicename[]; EXTERN int sys_nearestfontsize(int fontsize); @@ -143,7 +144,6 @@ typedef struct _audiosettings #define DEFMIDIDEV 0 -#define DEFAULTSRATE 44100 #if defined(_WIN32) #define DEFAULTADVANCE 80 #elif defined(__APPLE__) diff --git a/src/x_connective.c b/src/x_connective.c index ccee25d905..61cd5ad935 100644 --- a/src/x_connective.c +++ b/src/x_connective.c @@ -9,6 +9,8 @@ #include #include #include +#include + #ifdef _WIN32 # include /* MSVC or mingw on windows */ #elif defined(__linux__) || defined(__APPLE__) || defined(HAVE_ALLOCA_H) @@ -1279,10 +1281,11 @@ typedef struct _makefilename { t_object x_obj; t_symbol *x_format; + int x_long; t_printtype x_accept; } t_makefilename; -static const char* _formatscan(const char*str, t_printtype*typ) { +static const char* _formatscan(t_makefilename *x, const char*str, t_printtype*typ) { int infmt=0; for (; *str; str++) { if (!infmt && *str=='%') { @@ -1294,13 +1297,16 @@ static const char* _formatscan(const char*str, t_printtype*typ) { infmt=0; continue; } - if (strchr("-.#0123456789",*str)!=0) + if (strchr("+- #.0123456789hlL",*str)!=0) { + if (*str=='l') + x->x_long = 1; continue; + } if (*str=='s') { *typ = STRING; return str; } - if (strchr("fgGeEaA",*str)!=0) { + if (strchr("fFgGeEaA",*str)!=0) { *typ = FLOAT; return str; } @@ -1327,12 +1333,13 @@ static void makefilename_scanformat(t_makefilename *x) const char *str; t_printtype typ; if (!x->x_format) return; + x->x_long = 0; str = x->x_format->s_name; - str = _formatscan(str, &typ); + str = _formatscan(x, str, &typ); x->x_accept = typ; if (str && (NONE != typ)) { /* try again, to see if there's another format specifier (which we forbid) */ - str = _formatscan(str, &typ); + str = _formatscan(x, str, &typ); if (NONE != typ) { pd_error(x, "makefilename: invalid format string '%s' (too many format specifiers)", x->x_format->s_name); x->x_format = 0; @@ -1355,6 +1362,7 @@ static void *makefilename_new(t_symbol *s) static void makefilename_float(t_makefilename *x, t_floatarg f) { +#define CLAMP(var, min, max) (var>(t_float)max)?max:(var<(t_float)min)?min:var char buf[MAXPDSTRING]; if(!x->x_format) { pd_error(x, "makefilename: invalid format string"); @@ -1364,12 +1372,26 @@ static void makefilename_float(t_makefilename *x, t_floatarg f) case NONE: sprintf(buf, "%s", x->x_format->s_name); break; - case INT: - sprintf(buf, x->x_format->s_name, (int)f); + case INT: { + if (x->x_long) { + long int i = CLAMP(f, LONG_MIN, LONG_MAX); + sprintf(buf, x->x_format->s_name, i); + } else { + int i = CLAMP(f, INT_MIN, INT_MAX); + sprintf(buf, x->x_format->s_name, i); + } break; - case UINT: - sprintf(buf, x->x_format->s_name, (unsigned int)f); + } + case UINT: { + if (x->x_long) { + unsigned long int i = CLAMP(f, 0, ULONG_MAX); + sprintf(buf, x->x_format->s_name, i); + } else { + unsigned int i = CLAMP(f, 0, UINT_MAX); + sprintf(buf, x->x_format->s_name, i); + } break; + } case POINTER: sprintf(buf, x->x_format->s_name, (t_int)f); break; diff --git a/src/x_midi.c b/src/x_midi.c index 08828a75b1..086cde48b9 100644 --- a/src/x_midi.c +++ b/src/x_midi.c @@ -5,6 +5,8 @@ /* MIDI. */ #include "m_pd.h" +#include "string.h" + void outmidi_noteon(int portno, int channel, int pitch, int velo); void outmidi_controlchange(int portno, int channel, int ctlno, int value); void outmidi_programchange(int portno, int channel, int value); @@ -978,6 +980,8 @@ static void stripnote_setup(void) /* -------------------------- poly -------------------------- */ +/* -------------------------- poly -------------------------- */ + static t_class *poly_class; typedef struct voice @@ -1019,6 +1023,15 @@ static void *poly_new(t_float fnvoice, t_float fsteal) return (x); } +static void poly_flushvoice(t_poly *x, t_voice *v, int index) +{ + outlet_float(x->x_velout, 0); + outlet_float(x->x_pitchout, v->v_pitch); + outlet_float(x->x_obj.ob_outlet, index); + v->v_used = 0; + v->v_serial = x->x_serial++; +} + static void poly_float(t_poly *x, t_float f) { int i; @@ -1032,9 +1045,11 @@ static void poly_float(t_poly *x, t_float f) serialon = serialoff = 0xffffffff; i < x->x_n; v++, i++) { if (v->v_used && v->v_serial < serialon) - firston = v, serialon = (unsigned int)v->v_serial, onindex = i; + firston = v, serialon = (unsigned int)v->v_serial, + onindex = i; else if (!v->v_used && v->v_serial < serialoff) - firstoff = v, serialoff = (unsigned int)v->v_serial, offindex = i; + firstoff = v, serialoff = (unsigned int)v->v_serial, + offindex = i; } if (firstoff) { @@ -1047,12 +1062,11 @@ static void poly_float(t_poly *x, t_float f) /* if none, steal one */ else if (firston && x->x_steal) { - outlet_float(x->x_velout, 0); - outlet_float(x->x_pitchout, firston->v_pitch); - outlet_float(x->x_obj.ob_outlet, onindex+1); + poly_flushvoice(x, firston, onindex+1); outlet_float(x->x_velout, x->x_vel); outlet_float(x->x_pitchout, firston->v_pitch = f); outlet_float(x->x_obj.ob_outlet, onindex+1); + firston->v_used = 1; firston->v_serial = x->x_serial++; } } @@ -1061,15 +1075,10 @@ static void poly_float(t_poly *x, t_float f) for (v = x->x_vec, i = 0, firston = 0, serialon = 0xffffffff; i < x->x_n; v++, i++) if (v->v_used && v->v_pitch == f && v->v_serial < serialon) - firston = v, serialon = (unsigned int)v->v_serial, onindex = i; + firston = v, serialon = (unsigned int)v->v_serial, + onindex = i; if (firston) - { - firston->v_used = 0; - firston->v_serial = x->x_serial++; - outlet_float(x->x_velout, 0); - outlet_float(x->x_pitchout, firston->v_pitch); - outlet_float(x->x_obj.ob_outlet, onindex+1); - } + poly_flushvoice(x, firston, onindex+1); } } @@ -1079,13 +1088,7 @@ static void poly_stop(t_poly *x) t_voice *v; for (i = 0, v = x->x_vec; i < x->x_n; i++, v++) if (v->v_used) - { - outlet_float(x->x_velout, 0L); - outlet_float(x->x_pitchout, v->v_pitch); - outlet_float(x->x_obj.ob_outlet, i+1); - v->v_used = 0; - v->v_serial = x->x_serial++; - } + poly_flushvoice(x, v, i+1); } static void poly_clear(t_poly *x) @@ -1095,6 +1098,38 @@ static void poly_clear(t_poly *x) for (v = x->x_vec, i = x->x_n; i--; v++) v->v_used = v->v_serial = 0; } +static void poly_resize(t_poly *x, t_float fnvoice) +{ + t_voice *v; + int i, n = fnvoice; + if (n < 1) n = 1; + if (n == x->x_n) return; + + if (n < x->x_n) + { + /* flush excess voices */ + for (i = n, v = x->x_vec + n; i < x->x_n; i++, v++) + if (v->v_used) + poly_flushvoice(x, v, i+1); + } + + x->x_vec = resizebytes(x->x_vec, x->x_n * sizeof(*x->x_vec), + n * sizeof(*x->x_vec)); + + if (n > x->x_n) + { + for (i = x->x_n, v = x->x_vec + x->x_n; i < n; i++, v++) + v->v_pitch = v->v_used = v->v_serial = 0; + } + + x->x_n = n; +} + +static void poly_steal(t_poly *x, t_float f) +{ + x->x_steal = (f != 0); +} + static void poly_free(t_poly *x) { freebytes(x->x_vec, x->x_n * sizeof (*x->x_vec)); @@ -1108,6 +1143,10 @@ static void poly_setup(void) class_addfloat(poly_class, poly_float); class_addmethod(poly_class, (t_method)poly_stop, gensym("stop"), 0); class_addmethod(poly_class, (t_method)poly_clear, gensym("clear"), 0); + class_addmethod(poly_class, (t_method)poly_resize, gensym("resize"), + A_FLOAT, 0); + class_addmethod(poly_class, (t_method)poly_steal, gensym("steal"), + A_FLOAT, 0); } /* -------------------------- bag -------------------------- */ @@ -1123,34 +1162,67 @@ typedef struct _bagelem typedef struct _bag { t_object x_obj; + t_outlet *x_auxout; /* for count and/or bang-on-already-present */ t_float x_velo; t_bagelem *x_first; + int x_unique; /* true if limiting to one entry per value */ + int x_reenter; /* reentrancy protection */ } t_bag; -static void *bag_new(void) +static void *bag_new(t_symbol *flag) { t_bag *x = (t_bag *)pd_new(bag_class); - x->x_velo = 0; + x->x_velo = x->x_reenter = 0; + if (!strcmp(flag->s_name, "-u")) + x->x_unique = 1; + else + { + if (*flag->s_name) + pd_error(x, "bag %s: unknown flag", flag->s_name); + x->x_unique = 0; + } floatinlet_new(&x->x_obj, &x->x_velo); outlet_new(&x->x_obj, &s_float); + x->x_auxout = outlet_new(&x->x_obj, &s_list); x->x_first = 0; return (x); } -static void bag_float(t_bag *x, t_float f) +static t_bagelem *bag_newelem(t_float f) +{ + t_bagelem *bagelem = (t_bagelem *)getbytes(sizeof *bagelem); + bagelem->e_next = 0; + bagelem->e_value = f; + return (bagelem); +} + +static void bag_float(t_bag *x, t_floatarg f) { - t_bagelem *bagelem, *e2, *e3; + t_bagelem *e2, *e3; + if (x->x_reenter) + { + pd_error(x, "bag: sorry, unable to reenter"); + return; + } if (x->x_velo != 0) { - bagelem = (t_bagelem *)getbytes(sizeof *bagelem); - bagelem->e_next = 0; - bagelem->e_value = f; - if (!x->x_first) x->x_first = bagelem; - else /* LATER replace with a faster algorithm */ + if (!x->x_first) + x->x_first = bag_newelem(f); + else if (x->x_unique) + { + for (e2 = e3 = x->x_first; e2; e3 = e2, e2 = e2->e_next) + if (e2->e_value == f) + { + outlet_bang(x->x_auxout); + return; + } + e3->e_next = bag_newelem(f); + } + else { for (e2 = x->x_first; (e3 = e2->e_next); e2 = e3) ; - e2->e_next = bagelem; + e2->e_next = bag_newelem(f); } } else @@ -1158,7 +1230,7 @@ static void bag_float(t_bag *x, t_float f) if (!x->x_first) return; if (x->x_first->e_value == f) { - bagelem = x->x_first; + t_bagelem *bagelem = x->x_first; x->x_first = x->x_first->e_next; freebytes(bagelem, sizeof(*bagelem)); return; @@ -1173,20 +1245,23 @@ static void bag_float(t_bag *x, t_float f) } } -static void bag_flush(t_bag *x) +static void bag_bang(t_bag *x) { t_bagelem *bagelem; - while ((bagelem = x->x_first)) - { + x->x_reenter = 1; + for (bagelem = x->x_first; bagelem; bagelem = bagelem->e_next) outlet_float(x->x_obj.ob_outlet, bagelem->e_value); - x->x_first = bagelem->e_next; - freebytes(bagelem, sizeof(*bagelem)); - } + x->x_reenter = 0; } static void bag_clear(t_bag *x) { t_bagelem *bagelem; + if (x->x_reenter) + { + pd_error(x, "bag: sorry, unable to reenter"); + return; + } while ((bagelem = x->x_first)) { x->x_first = bagelem->e_next; @@ -1194,14 +1269,43 @@ static void bag_clear(t_bag *x) } } +static void bag_flush(t_bag *x) +{ + bag_bang(x); + bag_clear(x); +} + + /* output number of items matching pitch */ +static void bag_count(t_bag *x, t_float fpit) +{ + t_bagelem *bagelem; + int count = 0; + for (bagelem = x->x_first; bagelem; bagelem = bagelem->e_next) + if (bagelem->e_value == fpit) + count++; + outlet_float(x->x_auxout, (t_floatarg)count); +} + + /* change unique flag - note that this won't clean up duplicates that + are already in the bag. */ +static void bag_unique(t_bag *x, t_float f) +{ + x->x_unique = (f != 0); +} + static void bag_setup(void) { bag_class = class_new(gensym("bag"), (t_newmethod)bag_new, (t_method)bag_clear, - sizeof(t_bag), 0, 0); + sizeof(t_bag), 0, A_DEFSYM, 0); + class_addbang(bag_class, bag_bang); class_addfloat(bag_class, bag_float); class_addmethod(bag_class, (t_method)bag_flush, gensym("flush"), 0); class_addmethod(bag_class, (t_method)bag_clear, gensym("clear"), 0); + class_addmethod(bag_class, (t_method)bag_count, gensym("count"), + A_FLOAT, 0); + class_addmethod(bag_class, (t_method)bag_unique, gensym("unique"), + A_FLOAT, 0); } void x_midi_setup(void) diff --git a/src/x_misc.c b/src/x_misc.c index 6ec4c981b7..3a959bd58a 100644 --- a/src/x_misc.c +++ b/src/x_misc.c @@ -76,6 +76,13 @@ static void random_bang(t_random *x) outlet_float(x->x_obj.ob_outlet, nval); } + +static void random_float(t_random *x, t_floatarg f) +{ + x->x_f = f; + random_bang(x); +} + static void random_seed(t_random *x, t_float f, t_float glob) { x->x_state = f; @@ -86,6 +93,7 @@ static void random_setup(void) random_class = class_new(gensym("random"), (t_newmethod)random_new, 0, sizeof(t_random), 0, A_DEFFLOAT, 0); class_addbang(random_class, random_bang); + class_addfloat(random_class, random_float); class_addmethod(random_class, (t_method)random_seed, gensym("seed"), A_FLOAT, 0); } diff --git a/src/z_libpd.c b/src/z_libpd.c index a90490e483..698e01854d 100644 --- a/src/z_libpd.c +++ b/src/z_libpd.c @@ -80,7 +80,9 @@ static int s_initialized = 0; int libpd_init(void) { if (s_initialized) return -1; // only allow init once (for now) s_initialized = 1; +#ifndef __EMSCRIPTEN__ signal(SIGFPE, SIG_IGN); +#endif libpd_start_message(32); // allocate array for message assembly sys_externalschedlib = 0; sys_printtostderr = 0; diff --git a/src/z_libpd.h b/src/z_libpd.h index f656554a33..d70fb3a064 100644 --- a/src/z_libpd.h +++ b/src/z_libpd.h @@ -530,18 +530,18 @@ EXTERN int libpd_poll_gui(void); /// create a new pd instance and set as current /// note: use this in place of pdinstance_new() -/// returns new instance or NULL when libpd is not compiled with PDINSTANCE +/// returns new instance or NULL when libpd is compiled without PDINSTANCE EXTERN t_pdinstance *libpd_new_instance(void); /// set the current pd instance /// subsequent libpd calls will affect this instance only /// note: use this in place of pd_setinstance() -/// does nothing when libpd is not compiled with PDINSTANCE +/// does nothing when libpd is compiled without PDINSTANCE EXTERN void libpd_set_instance(t_pdinstance *pd); /// free a pd instance and set main instance as current /// note: use this in place of pdinstance_free() -/// does nothing when libpd is not compiled with PDINSTANCE +/// does nothing when libpd is compiled without PDINSTANCE EXTERN void libpd_free_instance(t_pdinstance *pd); /// get the current pd instance @@ -551,7 +551,7 @@ EXTERN t_pdinstance *libpd_this_instance(void); EXTERN t_pdinstance *libpd_main_instance(void); /// get the number of pd instances, including the main instance -/// returns number or 1 when libpd is not compiled with PDINSTANCE +/// returns number or 1 when libpd is compiled without PDINSTANCE EXTERN int libpd_num_instances(void); /// per-instance data free hook signature diff --git a/tcl/dialog_array.tcl b/tcl/dialog_array.tcl index d4d5ab85df..5ba398f6b4 100644 --- a/tcl/dialog_array.tcl +++ b/tcl/dialog_array.tcl @@ -394,7 +394,7 @@ proc ::dialog_array::create_dialog {mytoplevel newone} { wm group $mytoplevel . wm resizable $mytoplevel 0 0 wm transient $mytoplevel $::focused_window - $mytoplevel configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog $mytoplevel $mytoplevel configure -padx 0 -pady 0 ::pd_bindings::dialog_bindings $mytoplevel "array" diff --git a/tcl/dialog_audio.tcl b/tcl/dialog_audio.tcl index 2106dd9d6b..9dcd379ec7 100644 --- a/tcl/dialog_audio.tcl +++ b/tcl/dialog_audio.tcl @@ -391,7 +391,7 @@ proc ::dialog_audio::create {mytoplevel} { wm resizable $mytoplevel 0 0 wm transient $mytoplevel wm minsize $mytoplevel 380 320 - $mytoplevel configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog $mytoplevel $mytoplevel configure -padx 10 -pady 5 ::pd_bindings::dialog_bindings $mytoplevel "audio" diff --git a/tcl/dialog_canvas.tcl b/tcl/dialog_canvas.tcl index 3d7a9651e0..a9851d5699 100644 --- a/tcl/dialog_canvas.tcl +++ b/tcl/dialog_canvas.tcl @@ -16,7 +16,20 @@ array set hidetext_button {} ############# pdtk_canvas_dialog -- dialog window for canvases ################# +proc ::dialog_canvas::set_text {text} { + global ::dialog_canvas_text + set ::dialog_canvas_text [subst -nocommands -novariables ${text}] + set ::dialog_canvas_text_before $::dialog_canvas_text +} + proc ::dialog_canvas::apply {mytoplevel} { + global ::dialog_canvas_text + if [string compare $::dialog_canvas_text $::dialog_canvas_text_before] { + set appendme $::dialog_canvas_text + } else { + set appendme "" + } + pdsend "$mytoplevel donecanvasdialog \ [$mytoplevel.scale.x.entry get] \ [$mytoplevel.scale.y.entry get] \ @@ -28,7 +41,8 @@ proc ::dialog_canvas::apply {mytoplevel} { [$mytoplevel.range.x.size_entry get] \ [$mytoplevel.range.y.size_entry get] \ [$mytoplevel.range.x.margin_entry get] \ - [$mytoplevel.range.y.margin_entry get] 1" + [$mytoplevel.range.y.margin_entry get] 1 \ + $appendme" } proc ::dialog_canvas::cancel {mytoplevel} { @@ -95,7 +109,7 @@ proc ::dialog_canvas::checkcommand {mytoplevel} { } } -proc ::dialog_canvas::pdtk_canvas_dialog {mytoplevel xscale yscale graphmeflags \ +proc ::dialog_canvas::pdtk_canvas_dialog {mytoplevel xscale yscale graphmeflags \ xfrom yfrom xto yto \ xsize ysize xmargin ymargin} { if {[winfo exists $mytoplevel]} { @@ -145,7 +159,7 @@ proc ::dialog_canvas::create_dialog {mytoplevel} { if { [winfo exists $::focused_window] } { wm transient $mytoplevel $::focused_window } - $mytoplevel configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog $mytoplevel $mytoplevel configure -padx 0 -pady 0 ::pd_bindings::dialog_bindings $mytoplevel "canvas" @@ -220,6 +234,12 @@ proc ::dialog_canvas::create_dialog {mytoplevel} { -command "::dialog_canvas::ok $mytoplevel" -default active pack $mytoplevel.buttons.ok -side left -expand 1 -fill x -padx 15 -ipadx 10 + if [string length $::dialog_canvas_text] { + labelframe $mytoplevel.text -text [_ "Object:" ] + pack $mytoplevel.text -side top -anchor s -fill x -padx 2m + entry $mytoplevel.text.entry -textvariable ::dialog_canvas_text + pack $mytoplevel.text.entry -side right -expand 1 -fill x + } # live checkbutton & entry Return updates on OSX if {$::windowingsystem eq "aqua"} { diff --git a/tcl/dialog_data.tcl b/tcl/dialog_data.tcl index 03b4601ff9..bb3e3d5170 100644 --- a/tcl/dialog_data.tcl +++ b/tcl/dialog_data.tcl @@ -35,7 +35,7 @@ proc ::dialog_data::pdtk_data_dialog {mytoplevel stuff} { wm title $mytoplevel [_ "Data Properties"] wm group $mytoplevel $::focused_window wm transient $mytoplevel $::focused_window - $mytoplevel configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog $mytoplevel $mytoplevel configure -padx 0 -pady 0 frame $mytoplevel.buttonframe diff --git a/tcl/dialog_find.tcl b/tcl/dialog_find.tcl index e6083cf369..fe16ee7237 100644 --- a/tcl/dialog_find.tcl +++ b/tcl/dialog_find.tcl @@ -199,7 +199,7 @@ proc ::dialog_find::create_dialog {mytoplevel} { wm group .find . wm resizable .find 0 0 wm transient .find - .find configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog .find .find configure -padx 10 -pady 5 ::pd_bindings::dialog_bindings .find "find" diff --git a/tcl/dialog_font.tcl b/tcl/dialog_font.tcl index 6eb228d6bf..4fc6ccfda6 100644 --- a/tcl/dialog_font.tcl +++ b/tcl/dialog_font.tcl @@ -160,7 +160,7 @@ proc ::dialog_font::pdtk_canvas_dofont {gfxstub initsize} { proc ::dialog_font::create_dialog {gfxstub} { toplevel .font -class DialogWindow - .font configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog .font .font configure -padx 10 -pady 5 wm group .font . wm title .font [_ "Font"] diff --git a/tcl/dialog_gatom.tcl b/tcl/dialog_gatom.tcl index c1ecbfeaf1..1290c77ceb 100644 --- a/tcl/dialog_gatom.tcl +++ b/tcl/dialog_gatom.tcl @@ -103,7 +103,7 @@ proc ::dialog_gatom::create_dialog {mytoplevel} { wm group $mytoplevel . wm resizable $mytoplevel 0 0 wm transient $mytoplevel $::focused_window - $mytoplevel configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog $mytoplevel $mytoplevel configure -padx 0 -pady 0 ::pd_bindings::dialog_bindings $mytoplevel "gatom" diff --git a/tcl/dialog_iemgui.tcl b/tcl/dialog_iemgui.tcl index df01c2e001..67285ef344 100644 --- a/tcl/dialog_iemgui.tcl +++ b/tcl/dialog_iemgui.tcl @@ -403,7 +403,7 @@ proc ::dialog_iemgui::pdtk_iemgui_dialog {mytoplevel mainheader dim_header_UNUSE wm group $mytoplevel . wm resizable $mytoplevel 0 0 wm transient $mytoplevel $::focused_window - $mytoplevel configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog $mytoplevel $mytoplevel configure -padx 0 -pady 0 ::pd_bindings::dialog_bindings $mytoplevel "iemgui" diff --git a/tcl/dialog_message.tcl b/tcl/dialog_message.tcl index 7aab5130a5..29f53052e3 100644 --- a/tcl/dialog_message.tcl +++ b/tcl/dialog_message.tcl @@ -63,7 +63,7 @@ proc ::dialog_message::create_dialog {mytoplevel} { wm geometry .message =400x80+150+150 wm resizable .message 1 0 wm minsize .message 250 80 - .message configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog .message .message configure -padx 10 -pady 5 ::pd_bindings::dialog_bindings .message "message" diff --git a/tcl/dialog_midi.tcl b/tcl/dialog_midi.tcl index 0f571be6e4..1c44913a16 100644 --- a/tcl/dialog_midi.tcl +++ b/tcl/dialog_midi.tcl @@ -326,7 +326,7 @@ proc ::dialog_midi::create {id} { wm resizable $id 0 0 wm transient $id wm minsize $id 240 260 - $id configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog $id $id configure -padx 10 -pady 5 ::pd_bindings::dialog_bindings $id "midi" diff --git a/tcl/helpbrowser.tcl b/tcl/helpbrowser.tcl index 1b86afcf0a..107afb49b2 100644 --- a/tcl/helpbrowser.tcl +++ b/tcl/helpbrowser.tcl @@ -1,5 +1,5 @@ -package provide helpbrowser 0.2 +package provide helpbrowser 0.3 namespace eval ::helpbrowser:: { variable libdirlist @@ -16,7 +16,7 @@ namespace eval ::helpbrowser:: { ################## help browser and support functions ######################### proc ::helpbrowser::open_helpbrowser {} { - if {[winfo exists .helpbrowser.frame]} { + if {[winfo exists .helpbrowser.c.f]} { wm deiconify .helpbrowser raise .helpbrowser } else { @@ -27,27 +27,30 @@ proc ::helpbrowser::open_helpbrowser {} { bind .helpbrowser <$::modifier-Key-w> "wm withdraw .helpbrowser" if {$::windowingsystem eq "aqua"} { - .helpbrowser configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog .helpbrowser } - # set the maximum number of child columns to create - set ::helpbrowser::maxcols 5 + # set the maximum number of parent columns to create + set ::helpbrowser::maxcols 4 - # TODO wrap frame in a canvas with a horz scrollbar, - # currently we simply add cols to the left until we reach max cols + # only make x-axis scrollable wm resizable .helpbrowser 0 1 + wm withdraw .helpbrowser ::helpbrowser::make_frame .helpbrowser - # hit up, down, or Tab after browser opens to focus on first listbox - bind .helpbrowser "focus .helpbrowser.frame.root0" - bind .helpbrowser "focus .helpbrowser.frame.root0" + # hit up, down, or tab after browser opens to focus on first listbox + bind .helpbrowser "focus .helpbrowser.c.f.root0" + bind .helpbrowser "focus .helpbrowser.c.f.root0" # ignore undo bindings? # on macOS, this posts a ".helpbrowser: no such object" error - bind .helpbrowser "break" - bind .helpbrowser "break" + bind .helpbrowser <$::modifier-Key-z> "break" + bind .helpbrowser <$::modifier-Key-Z> "break" + # re-adjust size based on backing canvas + wm minsize .helpbrowser [winfo reqwidth .helpbrowser.c] [winfo reqheight .helpbrowser.c] position_over_window .helpbrowser .pdwindow + raise .helpbrowser } } @@ -55,7 +58,7 @@ proc ::helpbrowser::open_helpbrowser {} { proc ::helpbrowser::check_destroy {level} { set winlist list set winlevel 0 - foreach child [winfo children .helpbrowser.frame] { + foreach child [winfo children .helpbrowser.c.f] { regexp \\d+ $child winlevel if {$winlevel >= $level} { lappend winlist $child @@ -64,7 +67,7 @@ proc ::helpbrowser::check_destroy {level} { } # check for [file readable]? # requires Tcl 8.5 but probably deals with special chars better: - # destroy {*}[lrange [winfo children .helpbrowser.frame] [expr {2 * $count}] end] + # destroy {*}[lrange [winfo children .helpbrowser.c.f] [expr {2 * $count}] end] if {[catch { eval destroy $winlist } errorMessage]} { ::pdwindow::error "helpbrowser: error destroying listbox\n" } @@ -72,10 +75,49 @@ proc ::helpbrowser::check_destroy {level} { # create the base frame and root listbox, build path references proc ::helpbrowser::make_frame {mytoplevel} { - frame $mytoplevel.frame - pack $mytoplevel.frame -side top -fill both -expand 1 + scrollbar $mytoplevel.sx -command [list $mytoplevel.c xview] \ + -orient horizontal -takefocus 0 + canvas $mytoplevel.c -xscrollcommand [list $mytoplevel.sx set] \ + -highlightthickness 0 + frame $mytoplevel.c.f + bind $mytoplevel { + .helpbrowser.c xview scroll [expr {- (%D)}] units + } + bind .helpbrowser { + # for some reason state gets hidden when minimized? + if {"%W" eq ".helpbrowser"} { + .helpbrowser.c itemconfigure "canvaswindow" -state normal + } + } + bind $mytoplevel.c.f { + if {"%W" eq ".helpbrowser.c.f"} { + .helpbrowser.c configure -scrollregion [list 0 0 \ + [winfo reqwidth .helpbrowser.c.f] \ + [winfo height .helpbrowser.c]] \ + -height [winfo reqheight .helpbrowser.c.f] + } + } + bind $mytoplevel { + if {"%W" eq ".helpbrowser"} { + # the canvas will resize from the grid getting resized, but + # the item will not + .helpbrowser.c itemconfigure "canvaswindow" -height \ + [winfo height .helpbrowser.c] + } + } + $mytoplevel.c create window 0 0 -window $mytoplevel.c.f -anchor nw \ + -tags "canvaswindow" + grid $mytoplevel.c -sticky ns -column 0 -row 0 + grid $mytoplevel.sx -sticky ew -column 0 -row 1 + grid rowconfigure $mytoplevel 0 -weight 1 + grid columnconfigure $mytoplevel 0 -weight 1 build_references make_rootlistbox + + # fit canvas size to frame + update idletasks + $mytoplevel.c configure -width [winfo reqwidth .helpbrowser.c.f] -height \ + [winfo reqheight .helpbrowser.c.f.root0] } # make the root listbox of the help browser using the pre-built lists @@ -85,12 +127,17 @@ proc ::helpbrowser::make_rootlistbox {{select true}} { variable helplist # exportselection 0 looks good, but selection gets easily out-of-sync - set current_listbox [listbox "[set b .helpbrowser.frame.root0]" -yscrollcommand "$b-scroll set" \ - -highlightbackground white -highlightthickness 5 \ - -highlightcolor white -selectborderwidth 0 \ - -height 20 -width 24 -exportselection 0 -bd 0] - pack $current_listbox [scrollbar "$b-scroll" -command [list $current_listbox yview]] \ - -side left -fill both -expand 1 + set current_listbox [listbox "[set b .helpbrowser.c.f.root0]" \ + -yscrollcommand "$b-scroll set" \ + -highlightbackground white -highlightthickness 5 \ + -highlightcolor white -selectborderwidth 0 \ + -height 20 -width 24 -exportselection 0 -bd 0] + + grid $current_listbox -column 0 -row 0 -sticky ns + grid [scrollbar "$b-scroll" -command [list $current_listbox yview]] \ + -sticky ns -row 0 -column 1 + grid rowconfigure .helpbrowser.c.f 0 -weight 1 + # first show the directories (for easier navigation) foreach item [lsort $libdirlist] { $current_listbox insert end $item @@ -123,7 +170,7 @@ proc ::helpbrowser::refresh {} { variable refresh if {[winfo exists .helpbrowser]} { # refresh in place - destroy .helpbrowser.frame + destroy .helpbrowser.c .helpbrowser.sx ::helpbrowser::make_frame .helpbrowser if {[winfo viewable .helpbrowser]} { focus .helpbrowser @@ -136,6 +183,10 @@ proc ::helpbrowser::refresh {} { proc ::helpbrowser::scroll_destroy {window level} { $window xview 0 check_destroy $level + if {$level <= $::helpbrowser::maxcols} { + update idletasks + .helpbrowser.c configure -width [winfo width .helpbrowser.c.f] + } } # try to open a file or dir @@ -218,12 +269,14 @@ proc ::helpbrowser::make_liblistbox {dir {select true}} { check_destroy 1 # exportselection 0 looks good, but selection gets easily out-of-sync - set current_listbox [listbox "[set b .helpbrowser.frame.root1]" -yscrollcommand "$b-scroll set" \ - -highlightbackground white -highlightthickness 5 \ - -highlightcolor white -selectborderwidth 0 \ - -height 20 -width 24 -exportselection 0 -bd 0] - pack $current_listbox [scrollbar "$b-scroll" -command [list $current_listbox yview]] \ - -side left -fill both -expand 1 + set current_listbox [listbox "[set b .helpbrowser.c.f.root1]" \ + -yscrollcommand "$b-scroll set" \ + -highlightbackground white -highlightthickness 5 \ + -highlightcolor white -selectborderwidth 0 \ + -height 20 -width 24 -exportselection 0 -bd 0] + grid $current_listbox -row 0 -column 2 -sticky ns + grid [scrollbar "$b-scroll" -command [list $current_listbox yview]] \ + -sticky ns -row 0 -column 3 foreach item [lsort -dictionary [glob -directory $dir -nocomplain -types {d} -- *]] { if {[glob -directory $item -nocomplain -types {f} -- $doctypes] ne "" || [glob -directory $item -nocomplain -types {d} -- *] ne ""} { @@ -257,14 +310,16 @@ proc ::helpbrowser::make_liblistbox {dir {select true}} { bind $current_listbox \ "::helpbrowser::scroll_destroy %W 3" + # force display update + update idletasks + # select first entry & update next col if {$select && [$current_listbox size] != "0"} { $current_listbox selection set 0 dir_navigate_key "$dir" 2 $current_listbox false } - # force display update - update idletasks + .helpbrowser.c configure -width [winfo width .helpbrowser.c.f] return $current_listbox } @@ -275,13 +330,17 @@ proc ::helpbrowser::make_doclistbox {dir count {select true}} { check_destroy $count # exportselection 0 looks good, but selection gets easily out-of-sync - set current_listbox [listbox "[set b .helpbrowser.frame.root$count]" \ + set current_listbox [listbox "[set b .helpbrowser.c.f.root$count]" \ -yscrollcommand "$b-scroll set" \ -highlightbackground white -highlightthickness 5 \ -highlightcolor white -selectborderwidth 0 \ -height 20 -width 24 -exportselection 0 -bd 0] - pack $current_listbox [scrollbar "$b-scroll" -command "$current_listbox yview"] \ - -side left -fill both -expand 1 + set column [expr {$count * 2}] + grid $current_listbox -row 0 -column $column -sticky ns + incr column + grid [scrollbar "$b-scroll" -command [list $current_listbox yview]] \ + -sticky ns -row 0 -column $column + foreach item [lsort -dictionary [glob -directory $dir -nocomplain -types {d} -- *]] { $current_listbox insert end "[file tail $item]/" } @@ -290,7 +349,6 @@ proc ::helpbrowser::make_doclistbox {dir count {select true}} { $current_listbox insert end [file tail $item] } incr count - bind $current_listbox \ "::helpbrowser::dir_navigate {$dir} $count %W %x %y" bind $current_listbox \ @@ -307,23 +365,26 @@ proc ::helpbrowser::make_doclistbox {dir count {select true}} { "::helpbrowser::dir_navigate_key {$dir} $count %W false; break" bind $current_listbox \ "::helpbrowser::scroll_destroy %W [expr $count + 1]" - # select first entry & update next col if {$select && [$current_listbox size] != "0"} { $current_listbox selection set 0 dir_navigate_key "$dir" $count $current_listbox false } - # force display update update idletasks + if {$count <= $::helpbrowser::maxcols} { + .helpbrowser.c configure -width [winfo width .helpbrowser.c.f] + } else { + .helpbrowser.c xview moveto 1.0 + } return $current_listbox } # clear current selection & navigate one column to the left proc ::helpbrowser::dir_left {count window} { $window selection clear 0 end - focus .helpbrowser.frame.root$count + focus .helpbrowser.c.f.root$count } # navigate from one column to the right or update the second columns content @@ -333,7 +394,6 @@ proc ::helpbrowser::dir_navigate_key {dir count window {move true}} { if {[set newdir [$window get active]] eq {}} { return } - if {$count > $maxcols} {return} set dir_to_open [file join $dir $newdir] if {[file isdirectory $dir_to_open]} { set lbox [make_doclistbox $dir_to_open $count $move] @@ -343,18 +403,11 @@ proc ::helpbrowser::dir_navigate_key {dir count window {move true}} { # open current file, open directories too if we're on the last col proc ::helpbrowser::dir_return {dir count window} { - variable maxcols if {[set newdir [$window get active]] eq {}} { return } set dir_to_open [file join $dir $newdir] - if {$count <= $maxcols} { - if {[file isfile $dir_to_open]} { - open_path $dir $newdir - } - } else { - open_path $dir $newdir - } + open_path $dir $newdir } # navigate into an actual directory @@ -363,7 +416,6 @@ proc ::helpbrowser::dir_navigate {dir count window x y} { if {[set newdir [$window get [$window index "@$x,$y"]]] eq {}} { return } - if {$count > $maxcols} {return} set dir_to_open [file join $dir $newdir] if {[file isdirectory $dir_to_open]} { make_doclistbox $dir_to_open $count false diff --git a/tcl/pd-gui.tcl b/tcl/pd-gui.tcl index 79750ecc7f..f5d4712dec 100755 --- a/tcl/pd-gui.tcl +++ b/tcl/pd-gui.tcl @@ -110,6 +110,7 @@ namespace import ::dialog_array::pdtk_array_listview_closeWindow # should all have been properly initialized by the time startup plugins are # loaded. +set PD_APPLICATION_NAME "Pd" set PD_MAJOR_VERSION 0 set PD_MINOR_VERSION 0 set PD_BUGFIX_VERSION 0 @@ -220,7 +221,7 @@ array set childwindows {} ;# all child windows based on mytoplevel IDs array set parentwindows {} ;# topmost parent window ID based on mytoplevel IDs # variables for holding the menubar to allow for configuration by plugins -set ::pdwindow_menubar ".menubar" +set ::pdwindow_menubar ".pdmenu" set ::patch_menubar ".menubar" set ::dialog_menubar "" diff --git a/tcl/pd_bindings.tcl b/tcl/pd_bindings.tcl index e661cbecc0..61da364901 100644 --- a/tcl/pd_bindings.tcl +++ b/tcl/pd_bindings.tcl @@ -145,6 +145,18 @@ proc ::pd_bindings::global_bindings {} { bind all {::pd_bindings::sendkey %W 0 %K %A 0 %k} bind all {::pd_bindings::sendkey %W 1 %K %A 1 %k} bind all {::pd_bindings::sendkey %W 0 %K %A 1 %k} + + if {$::windowingsystem eq "x11"} { + # from http://wiki.tcl.tk/3893 + bind all \ + {event generate [focus -displayof %W] -delta 1} + bind all \ + {event generate [focus -displayof %W] -delta -1} + bind all \ + {event generate [focus -displayof %W] -delta 1} + bind all \ + {event generate [focus -displayof %W] -delta -1} + } } # bindings for .pdwindow are found in ::pdwindow::pdwindow_bindings in pdwindow.tcl @@ -221,17 +233,17 @@ proc ::pd_bindings::patch_bindings {mytoplevel} { bind $tkcanvas \ "pdtk_canvas_mouse %W %x %y %b 1" bind $tkcanvas <$::modifier-ButtonPress-1> \ - "pdtk_canvas_mouse %W %x %y %b 2" + "::pd_bindings::handle_modifier_click %W %x %y %b 2" bind $tkcanvas <$::modifier-Shift-ButtonPress-1> \ - "pdtk_canvas_mouse %W %x %y %b 3" + "::pd_bindings::handle_modifier_click %W %x %y %b 3" bind $tkcanvas <$alt-ButtonPress-1> \ "pdtk_canvas_mouse %W %x %y %b 4" bind $tkcanvas <$alt-Shift-ButtonPress-1> \ "pdtk_canvas_mouse %W %x %y %b 5" bind $tkcanvas <$::modifier-$alt-ButtonPress-1> \ - "pdtk_canvas_mouse %W %x %y %b 6" + "::pd_bindings::handle_modifier_click %W %x %y %b 6" bind $tkcanvas <$::modifier-$alt-Shift-ButtonPress-1> \ - "pdtk_canvas_mouse %W %x %y %b 7" + "::pd_bindings::handle_modifier_click %W %x %y %b 7" bind $tkcanvas \ "pdtk_canvas_mouseup %W %x %y %b 0" @@ -250,17 +262,6 @@ proc ::pd_bindings::patch_bindings {mytoplevel} { bind $tkcanvas <$::modifier-$alt-Shift-ButtonRelease-1> \ "pdtk_canvas_mouseup %W %x %y %b 7" - if {$::windowingsystem eq "x11"} { - # from http://wiki.tcl.tk/3893 - bind all \ - {event generate [focus -displayof %W] -delta 1} - bind all \ - {event generate [focus -displayof %W] -delta -1} - bind all \ - {event generate [focus -displayof %W] -delta 1} - bind all \ - {event generate [focus -displayof %W] -delta -1} - } bind $tkcanvas {::pdtk_canvas::scroll %W y %D} bind $tkcanvas {::pdtk_canvas::scroll %W x %D} catch { @@ -322,6 +323,19 @@ proc ::pd_bindings::patch_bindings {mytoplevel} { #------------------------------------------------------------------------------# # event handlers +# handle modifier clicks with focus management +proc ::pd_bindings::handle_modifier_click {window x y button modifier} { + # force focus on macOS if we're clicking in a different window + if {$::windowingsystem eq "aqua"} { + set mytoplevel [winfo toplevel $window] + if {$mytoplevel ne $::focused_window} { + focus -force $window + ::pd_bindings::window_focusin $mytoplevel + } + } + pdtk_canvas_mouse $window $x $y $button $modifier +} + # do tasks when changing focus (Window menu, scrollbars, etc.) proc ::pd_bindings::window_focusin {mytoplevel} { # focused_window is used throughout for sending bindings, menu commands, diff --git a/tcl/pd_connect.tcl b/tcl/pd_connect.tcl index 131db5bdeb..4fd6231ab3 100644 --- a/tcl/pd_connect.tcl +++ b/tcl/pd_connect.tcl @@ -151,7 +151,7 @@ proc ::pd_connect::set_pid {pid} { proc ::pd_connect::nuke_pd {} { if {$::connect_pid ne ""} { if {$::windowingsystem eq "win32"} { - exec taskkill /pid $::connect_pid + exec taskkill /f /pid $::connect_pid } else { exec kill $::connect_pid } diff --git a/tcl/pd_deken.tcl b/tcl/pd_deken.tcl index 2ba46a7c55..6afa827db3 100644 --- a/tcl/pd_deken.tcl +++ b/tcl/pd_deken.tcl @@ -43,6 +43,9 @@ if { [catch {package require autoproxy} ] } {} else { package require pdwindow 0.1 package require pd_menucommands 0.1 package require pd_guiprefs +package require scrollboxwindow +package require scrollbox + namespace eval ::deken:: { variable version @@ -52,17 +55,14 @@ namespace eval ::deken:: { variable hideforeignarch variable hideoldversions - # whether to use http:// or https:// - variable protocol - # results: {{title} {cmd} {description} {url} {ctxmenu}} variable results # selected: {library} {cmd} ... variable selected {} } - namespace eval ::deken::preferences { variable installpath + variable installpath_x variable userinstallpath # automatically detected platform variable platform @@ -79,31 +79,31 @@ namespace eval ::deken::utilities { } ## (if ::deken::version is defined and is higher than our own version) proc ::deken::versioncheck {version} { if { [info exists ::deken::version ] } { - set v0 [split $::deken::version "."] - set v1 [split $version "."] - foreach x $v0 y $v1 { - if { $x > $y } { - set msg [format [_ "\[deken\] installed version \[%1\$s\] > %2\$s...skipping!" ] $::deken::version $version ] + set v0 [split ${::deken::version} "."] + set v1 [split ${version} "."] + foreach x ${v0} y ${v1} { + if { ${x} > ${y} } { + set msg [format [_ "\[deken\] installed version \[%1\$s\] > %2\$s...skipping!" ] ${::deken::version} ${version} ] ::pdwindow::debug "${msg}\n" return 0 } - if { $x < $y } { - set msg [format [_ "\[deken\] installed version \[%1\$s\] < %2\$s...overwriting!" ] $::deken::version $version ] - ::pdwindow::debug "$msg\n" - set ::deken::version $version + if { ${x} < ${y} } { + set msg [format [_ "\[deken\] installed version \[%1\$s\] < %2\$s...overwriting!" ] ${::deken::version} ${version} ] + ::pdwindow::debug "${msg}\n" + set ::deken::version ${version} return 1 } } - set msg [format [_ "\[deken\] installed version \[%1\$s\] == %2\$s...skipping!" ] $::deken::version $version ] + set msg [format [_ "\[deken\] installed version \[%1\$s\] == %2\$s...skipping!" ] ${::deken::version} ${version} ] ::pdwindow::debug "${msg}\n" return 0 } - set ::deken::version $version + set ::deken::version ${version} return 1 } ## put the current version of this package here: -if { [::deken::versioncheck 0.9.18] } { +if { [::deken::versioncheck 0.10.6] } { namespace eval ::deken:: { namespace export open_searchui @@ -123,6 +123,7 @@ namespace eval ::deken:: { namespace export register } namespace eval ::deken::search:: { } +namespace eval ::deken::search::dekenserver { } ## FIXXXXME only initialize vars if not yet set set ::deken::backends {} @@ -139,6 +140,7 @@ set ::deken::searchtype name set ::deken::statustimer {} set ::deken::progresstimer {} set ::deken::preferences::installpath {} +set ::deken::preferences::installpath_x {} set ::deken::preferences::userinstallpath {} set ::deken::preferences::platform {} set ::deken::preferences::userplatform {} @@ -150,10 +152,15 @@ set ::deken::preferences::add_to_path {} set ::deken::preferences::add_to_path_temp {} set ::deken::preferences::keep_package {} set ::deken::preferences::verify_sha256 {} - -set ::deken::platform(os) $::tcl_platform(os) -set ::deken::platform(machine) $::tcl_platform(machine) -set ::deken::platform(bits) [ expr [ string length [ format %X -1 ] ] * 4 ] +set ::deken::preferences::use_url_primary 1 +set ::deken::preferences::use_urls_secondary 0 +set ::deken::preferences::urls_secondary {} +set ::deken::preferences::use_urls_ephemeral 0 +set ::deken::preferences::urls_ephemeral {} + +set ::deken::platform(os) ${::tcl_platform(os)} +set ::deken::platform(machine) [string tolower ${::tcl_platform(machine)}] +set ::deken::platform(bits) [ expr {[ string length [ format %X -1 ] ] * 4} ] set ::deken::platform(floatsize) 32 # architectures that can be substituted for each other @@ -166,8 +173,8 @@ set ::deken::architecture_substitutes(armv6) [list "armv6l" "arm"] set ::deken::architecture_substitutes(armv6l) [list "armv6" "arm"] set ::deken::architecture_substitutes(armv7) [list "armv7l" "armv6l" "armv6" "arm"] set ::deken::architecture_substitutes(armv7l) [list "armv7" "armv6l" "armv6" "arm"] -set ::deken::architecture_substitutes(PowerPC) [list "ppc"] -set ::deken::architecture_substitutes(ppc) [list "PowerPC"] +set ::deken::architecture_substitutes(powerpc) [list "ppc"] +set ::deken::architecture_substitutes(ppc) [list "powerpc"] set ::deken::architecture_normalize(x86_64) "amd64" set ::deken::architecture_normalize(i686) "i386" @@ -175,17 +182,17 @@ set ::deken::architecture_normalize(i586) "i386" set ::deken::architecture_normalize(i486) "i386" set ::deken::architecture_normalize(armv6l) "armv6" set ::deken::architecture_normalize(armv7l) "armv7" -set ::deken::architecture_normalize(PowerPC) "ppc" +set ::deken::architecture_normalize(powerpc) "ppc" # normalize W32 OSs -if { [ string match "Windows *" "$::deken::platform(os)" ] > 0 } { +if { [ string match "Windows *" "${::deken::platform(os)}" ] > 0 } { # we are not interested in the w32 flavour, so we just use 'Windows' for all of them set ::deken::platform(os) "Windows" } # normalize W32 CPUs -if { "Windows" eq "$::deken::platform(os)" } { +if { "Windows" eq "${::deken::platform(os)}" } { # in redmond, intel only produces 32bit CPUs,... - if { "intel" eq "$::deken::platform(machine)" } { set ::deken::platform(machine) "i686" } + if { "intel" eq "${::deken::platform(machine)}" } { set ::deken::platform(machine) "i686" } # ... and all 64bit CPUs are manufactured by amd #if { "amd64" eq "$::deken::platform(machine)" } { set ::deken::platform(machine) "x86_64" } } @@ -194,13 +201,6 @@ catch { set ::deken::platform(machine) $::deken::architecture_normalize($::deken::platform(machine)) } - -set ::deken::protocol "http" -if { ! [catch {package present tls} stdout] } { - set ::deken::protocol "https" -} - - # ###################################################################### # ################ compatibility ####################################### # ###################################################################### @@ -209,9 +209,9 @@ if { ! [catch {package present tls} stdout] } { if {[info commands lreverse] == ""} { proc lreverse list { set res {} - set i [llength $list] - while {$i} { - lappend res [lindex $list [incr i -1]] + set i [llength ${list}] + while {${i}} { + lappend res [lindex ${list} [incr i -1]] } set res } ;# RS @@ -220,68 +220,117 @@ if {[info commands lreverse] == ""} { # ###################################################################### # ################ utilities ########################################## # ###################################################################### +proc ::deken::utilities::setdefault {key value} { + upvar ${key} k + if { [info exists k] } { + set k + } else { + set k ${value} + } +} proc ::deken::utilities::bool {value {fallback 0}} { - catch {set fallback [expr bool($value) ] } stdout - return $fallback + catch {set fallback [expr {bool(${value})} ] } stdout + return ${fallback} +} +proc ::deken::utilities::int {value {fallback 0}} { + catch {set fallback [expr {int(${value})} ] } stdout + return ${fallback} } - proc ::deken::utilities::tristate {value {offset 0} {fallback 0} } { - catch {set fallback [expr (int($value) + int($offset))% 3 ]} stdout - return $fallback + catch {set fallback [expr {(int(${value}) + int(${offset}))% 3} ]} stdout + return ${fallback} +} + +proc ::deken::utilities::list_unique {lst} { + array set cache {} + set result {} + foreach element ${lst} { + if { ! [info exists cache(${element})]} { + lappend result ${element} + } + set cache(${element}) 1 + } + return ${result} +} +proc ::deken::utilities::lists_intersect {args} { + set numlists [llength ${args}] + if {${numlists} < 1} {return {}} + + set cache("") 0 + set elements {} + foreach lst ${args} { + set lst [::deken::utilities::list_unique ${lst}] + foreach element ${lst} { + if { ! [info exists cache(${element})]} { + lappend elements ${element} + } + incr cache(${element}) + } + } + # ${elements} holds a list of unique elements (as they appeared) + # so filter out those that were not in all lists + set cache("") 0 + set result {} + foreach element ${elements} { + if { ${numlists} == $cache(${element}) } { + lappend result ${element} + } + } + return ${result} } proc ::deken::utilities::expandpath {path} { set map "@PD_PATH@" - lappend map $::sys_libdir - string map $map $path + lappend map ${::sys_libdir} + string map ${map} ${path} } proc ::deken::utilities::get_tmpfilename {{path ""} {ext ""} {prefix dekentmp}} { for {set i 0} {true} {incr i} { set tmpfile [file join ${path} ${prefix}.${i}${ext}] - if {![file exists $tmpfile]} { - return $tmpfile + if {![file exists ${tmpfile}]} { + return ${tmpfile} } } } proc ::deken::utilities::get_tmpdir {} { - proc _iswdir {d} { "expr" [file isdirectory $d] * [file writable $d] } + proc _iswdir {d} { return [expr {[file isdirectory ${d}] * [file writable ${d}]}] } set tmpdir "" # TRASH_FOLDER: very old Macintosh. Mac OS X doesn't have this. # TMPDIR: unices # TMP, TEMP: windows # TEPMDIR: for symmetry :-) foreach {d} {TRASH_FOLDER TMPDIR TEMPDIR TEMP TMP} { - if { [info exists ::env($d) ] } { - set tmpdir $::env($d) - if {[_iswdir $tmpdir]} {return $tmpdir} + if { [info exists ::env(${d}) ] } { + set tmpdir $::env(${d}) + if {[_iswdir ${tmpdir}]} {return ${tmpdir}} } } set tmpdir "/tmp" - if {[_iswdir $tmpdir]} {return $tmpdir} + if {[_iswdir ${tmpdir}]} {return ${tmpdir}} set tmpdir [pwd] - if {[_iswdir $tmpdir]} {return $tmpdir} + if {[_iswdir ${tmpdir}]} {return ${tmpdir}} } proc ::deken::utilities::is_writabledir {path} { set fs [file separator] set access [list RDWR CREAT EXCL TRUNC] - set tmpfile [::deken::utilities::get_tmpfilename $path] + set tmpfile [::deken::utilities::get_tmpfilename ${path}] # try creating tmpfile - if {![catch {open $tmpfile $access} channel]} { - close $channel - file delete $tmpfile + if {![catch {open ${tmpfile} ${access}} channel]} { + close ${channel} + file delete ${tmpfile} return true } return false } proc ::deken::utilities::get_writabledir {paths} { - foreach p $paths { - set xp [ ::deken::utilities::expandpath $p ] - if { [ ::deken::utilities::is_writabledir $xp ] } { return $p } + foreach p ${paths} { + set xp [ ::deken::utilities::expandpath ${p} ] + if { [ ::deken::utilities::is_writabledir ${xp} ] } { return ${p} } } return } @@ -291,22 +340,22 @@ proc ::deken::utilities::rmrecursive {path} { # to delete single items (rather than just unlinking the parent directory) set errors 0 set myname [lindex [info level 0] 0] - set children [glob -nocomplain -directory $path -types hidden *] - lappend children {*}[glob -nocomplain -directory $path *] + set children [glob -nocomplain -directory ${path} -types hidden *] + lappend children {*}[glob -nocomplain -directory ${path} *] foreach child $children[set children {}] { - if {[file tail $child] in {. ..}} { + if {[file tail ${child}] in {. ..}} { continue } - if {[file isdirectory $child]} { - if {[file type $child] ne "link"} { - incr errors [$myname $child] + if {[file isdirectory ${child}]} { + if {[file type ${child}] ne "link"} { + incr errors [${myname} ${child}] } } - if { [ catch { file delete -force $child } ] } { + if { [ catch { file delete -force ${child} } ] } { incr errors } } - return $errors + return ${errors} } # http://rosettacode.org/wiki/URL_decoding#Tcl @@ -314,8 +363,8 @@ proc ::deken::utilities::urldecode {str} { set specialMap {"[" "%5B" "]" "%5D"} set seqRE {%([0-9a-fA-F]{2})} set replacement {[format "%c" [scan "\1" "%2x"]]} - set modStr [regsub -all $seqRE [string map $specialMap $str] $replacement] - encoding convertfrom utf-8 [subst -nobackslashes -novariables $modStr] + set modStr [regsub -all ${seqRE} [string map ${specialMap} ${str}] ${replacement}] + encoding convertfrom utf-8 [subst -nobackslashes -novariables ${modStr}] } proc ::deken::utilities::verbose {level message} { @@ -324,7 +373,7 @@ proc ::deken::utilities::verbose {level message} { proc ::deken::utilities::debug {message} { set winid ${::deken::winid} if {[winfo exists ${winid}.tab.info]} { - ::deken::post $message debug + ::deken::post ${message} debug } else { ::pdwindow::debug "\[deken\] ${message}\n" } @@ -334,17 +383,17 @@ if { [catch {package require tkdnd} ] } { proc ::deken::utilities::dnd_init {windowid} { } } else { proc ::deken::utilities::dnd_init {windowid} { - ::tkdnd::drop_target register $windowid DND_Files - bind $windowid <> {::deken::utilities::dnd_drop_files %D} + ::tkdnd::drop_target register ${windowid} DND_Files + bind ${windowid} <> {::deken::utilities::dnd_drop_files %D} } proc ::deken::utilities::dnd_drop_files {files} { - foreach f $files { + foreach f ${files} { if { [regexp -all -nocase "\.(zip|dek|tgz|tar\.gz)$" ${f} ] } { - set msg [format [_ "installing deken package '%s'" ] $f] + set msg [format [_ "installing deken package '%s'" ] ${f}] ::deken::statuspost ${msg} - ::deken::install_package_from_file $f + ::deken::install_package_from_file ${f} } else { - set msg [format [_ "ignoring '%s': doesn't look like a deken package" ] $f] + set msg [format [_ "ignoring '%s': doesn't look like a deken package" ] ${f}] ::deken::statuspost ${msg} } } @@ -352,113 +401,198 @@ proc ::deken::utilities::dnd_drop_files {files} { } } -if { [catch {package require zipfile::decode} ] } { -proc ::deken::utilities::unzipper {zipfile {path .}} { - ## this is w32 only - if {$::tcl_platform(platform) ne "windows"} { return 0 } - - ## create script-file - set vbsscript [::deken::utilities::get_tmpfilename [::deken::utilities::get_tmpdir] ".vbs" ] - set script { -On Error Resume Next -Set fso = CreateObject("Scripting.FileSystemObject") - -'The location of the zip file. -ZipFile = fso.GetAbsolutePathName(WScript.Arguments.Item(0)) -'The folder the contents should be extracted to. -ExtractTo = fso.GetAbsolutePathName(WScript.Arguments.Item(1)) - -'If the extraction location does not exist create it. -If NOT fso.FolderExists(ExtractTo) Then - fso.CreateFolder(ExtractTo) -End If - -'Extract the contents of the zip file. -set objShell = CreateObject("Shell.Application") -set FilesInZip=objShell.NameSpace(ZipFile).items -objShell.NameSpace(ExtractTo).CopyHere(FilesInZip) -'In case of an error, exit -If Err.Number <> 0 Then - Err.Clear - WScript.Quit 1 -End If - -Set fso = Nothing -Set objShell = Nothing - } - if {![catch {set fileId [open $vbsscript "w"]}]} { - puts $fileId $script - close $fileId - } - - if {![file exists $vbsscript]} { - ## still no script, give up - return 0 +namespace eval ::deken::utilities::unzipper:: { + # we put a number of unzip methods in this namespace. + # they are tried in in alphabetical(!) order + + + # zipfs from Tcl>=8.7 (it seems this only works with Tcl>=9.0) + catch { + zipfs root + proc builtin_zipfs {zipfile path} { + if { [catch { + set base [file join [zipfs root] deken] + if { [catch { + package require Tcl 8 + # yikes! Tcl8.7 uses 'zipfs mount ' + zipfs mount ${base} ${zipfile} + } ] } { + # and Tcl9 uses 'zipfs mount ' + zipfs mount ${zipfile} ${base} + } + foreach x [glob [file join ${base} *]] { + file copy -force -- ${x} ${path} + } + zipfs unmount ${base} + } stdout ] } { + ::deken::utilities::debug "unzipper::zipfs: ${stdout}" + return 0 + } + return 1 + } } - ## try to call the script - ## (and windows requires the file to have a .zip extension!!!) - if { [ catch { - set zipfilezip ${zipfile}.zip - file rename ${zipfile} ${zipfilezip} - exec cscript "${vbsscript}" "${zipfilezip}" . - file rename ${zipfilezip} ${zipfile} - } stdout ] } { - catch { file rename ${zipfilezip} ${zipfile} } - catch { file delete "${vbsscript}" } - ::deken::utilities::debug "VBS-unzip($vbsscript): $stdout" - return 0 + + # ::zipfile::decode from tcllib + catch { + package require zipfile::decode + proc tcllib_zipfile {zipfile path} { + if { [catch { + ::zipfile::decode::unzipfile "${zipfile}" "${path}" + ::zipfile::decode::open "${zipfile}" + set zdict [::zipfile::decode::archive] + ::zipfile::decode::close + foreach zfile [::zipfile::decode::files ${zdict}] { + set zfile [file join ${path} ${zfile}] + catch { + if { ! [file attributes ${zfile} -permissions] } { + if [file isdirectory ${zfile} ] { + set perms 0700 + } else { + set perms 0600 + } + file attributes ${zfile} -permissions ${perms} + } + } + } + } stdout ] } { + ::deken::utilities::debug "unzipper::zipfile::decode: ${stdout}" + return 0 + } + return 1 + } + } + + proc untar {zipfile path} { + if { [catch { + exec tar -xf "${zipfile}" -C "${path}" + } stdout ] } { + ::deken::utilities::debug "unzipper::tar ${stdout}" + return 0 + } + return 1 + } + + proc unzip {zipfile path} { + set result 0 + if { [catch { + exec unzip -uo "${zipfile}" -d "${path}" + set result 1 + } stdout ] } { + ::deken::utilities::debug "unzipper::unzip ${stdout}" + } + return ${result} + } + + if {$::tcl_platform(platform) eq "windows"} { + ## VisualBasic is w32 only + proc windows_visualbasic {zipfile path} { + ## create script-file + set vbsscript [::deken::utilities::get_tmpfilename [::deken::utilities::get_tmpdir] ".vbs" ] + set script { + On Error Resume Next + Set fso = CreateObject("Scripting.FileSystemObject") + + 'The location of the zip file. + ZipFile = fso.GetAbsolutePathName(WScript.Arguments.Item(0)) + 'The folder the contents should be extracted to. + ExtractTo = fso.GetAbsolutePathName(WScript.Arguments.Item(1)) + + 'If the extraction location does not exist create it. + If NOT fso.FolderExists(ExtractTo) Then + fso.CreateFolder(ExtractTo) + End If + + 'Extract the contents of the zip file. + set objShell = CreateObject("Shell.Application") + set FilesInZip=objShell.NameSpace(ZipFile).items + objShell.NameSpace(ExtractTo).CopyHere(FilesInZip) + 'In case of an error, exit + If Err.Number <> 0 Then + Err.Clear + WScript.Quit 1 + End If + + Set fso = Nothing + Set objShell = Nothing + } + if {![catch {set fileId [open ${vbsscript} "w"]}]} { + puts ${fileId} ${script} + close ${fileId} + } + + if {![file exists ${vbsscript}]} { + ## still no script, give up + return 0 + } + ## try to call the script + ## (and windows requires the file to have a .zip extension!!!) + if { [ catch { + set zipfilezip ${zipfile}.zip + file rename ${zipfile} ${zipfilezip} + exec cscript "${vbsscript}" "${zipfilezip}" . + file rename ${zipfilezip} ${zipfile} + } stdout ] } { + catch { file rename ${zipfilezip} ${zipfile} } + catch { file delete "${vbsscript}" } + ::deken::utilities::debug "unzipper::VBS-unzip(${vbsscript}): ${stdout}" + return 0 + } + catch { file delete "${vbsscript}" } + return 1 + } } - catch { file delete "${vbsscript}" } - return 1 } -} else { # successfully imported zipfile::decode + proc ::deken::utilities::unzipper {zipfile {path .}} { - if { [catch { - ::zipfile::decode::unzipfile "${zipfile}" "${path}" - } stdout ] } { - ::deken::utilities::debug "unzip: $stdout" - return 0 + set unzippers [lsort -dictionary [info procs ::deken::utilities::unzipper::*]] + foreach unzip ${unzippers} { + set result 0 + catch { + set result [ ${unzip} ${zipfile} ${path} ] + } + if {${result} ne 0} { + return 1 + } } - return 1 -} + return 0 } proc ::deken::utilities::extract {installdir filename fullpkgfile {keep_package 1}} { if { ! [ file isdirectory "${installdir}" ] } { return 0 } - ::deken::statuspost [format [_ "Installing '%s'" ] $filename ] debug + ::deken::statuspost [format [_ "Installing '%s'" ] ${filename} ] debug set PWD [ pwd ] - cd $installdir + cd ${installdir} set success 1 - if { [ string match *.dek $fullpkgfile ] } then { - if { ! [ ::deken::utilities::unzipper $fullpkgfile $installdir ] } { - if { [ catch { exec unzip -uo $fullpkgfile } stdout ] } { - ::deken::utilities::debug "$stdout" + if { [ string match *.dek ${fullpkgfile} ] } then { + if { ! [ ::deken::utilities::unzipper ${fullpkgfile} ${installdir} ] } { + if { [ catch { exec unzip -uo ${fullpkgfile} } stdout ] } { + ::deken::utilities::debug "${stdout}" set success 0 } } - } elseif { [ string match *.zip $fullpkgfile ] } then { - if { ! [ ::deken::utilities::unzipper $fullpkgfile $installdir ] } { - if { [ catch { exec unzip -uo $fullpkgfile } stdout ] } { - ::deken::utilities::debug "$stdout" + } elseif { [ string match *.zip ${fullpkgfile} ] } then { + if { ! [ ::deken::utilities::unzipper ${fullpkgfile} ${installdir} ] } { + if { [ catch { exec unzip -uo ${fullpkgfile} } stdout ] } { + ::deken::utilities::debug "${stdout}" set success 0 } } - } elseif { [ string match *.tar.* $fullpkgfile ] - || [ string match *.tgz $fullpkgfile ] + } elseif { [ string match *.tar.* ${fullpkgfile} ] + || [ string match *.tgz ${fullpkgfile} ] } then { - if { [ catch { exec tar xf $fullpkgfile } stdout ] } { - ::deken::utilities::debug "$stdout" + if { [ catch { exec tar xf ${fullpkgfile} } stdout ] } { + ::deken::utilities::debug "${stdout}" set success 0 } } - cd $PWD + cd ${PWD} - if { $success > 0 } { - ::deken::post [format [_ "Successfully unzipped %1\$s into %2\$s."] $filename $installdir ] debug + if { ${success} > 0 } { + ::deken::post [format [_ "Successfully unzipped %1\$s into %2\$s."] ${filename} ${installdir} ] debug if { ! "${keep_package}" } { - catch { file delete $fullpkgfile } + catch { file delete ${fullpkgfile} } } } else { # Open both the fullpkgfile folder and the zipfile itself @@ -469,24 +603,24 @@ proc ::deken::utilities::extract {installdir filename fullpkgfile {keep_package set msg "" append msg [_ "Please perform the following steps manually:" ] append msg "\n" - append msg [format [_ "1. Unzip %s." ] $fullpkgfile ] + append msg [format [_ "1. Unzip %s." ] ${fullpkgfile} ] append msg "\n" - if { [string match "*.dek" $fullpkgfile] } { + if { [string match "*.dek" ${fullpkgfile}] } { append msg " " append msg [_ "You might need to change the file-extension from .dek to .zip" ] append msg "\n" } - append msg [format [_ "2. Copy the contents into %s." ] $installdir] + append msg [format [_ "2. Copy the contents into %s." ] ${installdir}] append msg "\n" - append msg [format [_ "3. Remove %s. (optional)" ] $fullpkgfile ] + append msg [format [_ "3. Remove %s. (optional)" ] ${fullpkgfile} ] append msg "\n" - ::deken::post "$msg" + ::deken::post "${msg}" - pd_menucommands::menu_openfile $fullpkgfile - pd_menucommands::menu_openfile $installdir + pd_menucommands::menu_openfile ${fullpkgfile} + pd_menucommands::menu_openfile ${installdir} } - return $success + return ${success} } proc ::deken::utilities::uninstall {path library} { @@ -498,93 +632,112 @@ proc ::deken::utilities::uninstall {path library} { file delete -force "${fullpath}" } stdout ] } { set msg [format [_ "Uninstalling %1\$s from %2\$s failed!"] ${library} ${path}] - ::deken::utilities::debug "$msg\n $stdout" + ::deken::utilities::debug "${msg}\n ${stdout}" return 0 } } return 1 } +namespace eval ::deken::utilities::sha256:: { + # we put a number of sha256sum methods in this namespace + # they are tried in alphabetical order -proc ::deken::utilities::sha256_sha256sum {filename} { - set hash {} - catch { set hash [lindex [exec sha256sum $filename] 0] } - return $hash -} -proc ::deken::utilities::sha256_shasum {filename} { - set hash {} - catch { set hash [lindex [exec shasum -a 256 $filename] 0] } - return $hash -} -proc ::deken::utilities::sha256_powershell {filename} { - set batscript [::deken::utilities::get_tmpfilename [::deken::utilities::get_tmpdir] ".bat" ] - set script { -@echo off -powershell -Command " & {Get-FileHash -Algorithm SHA256 -LiteralPath \"%1\" | Select-Object -ExpandProperty Hash}" + proc sha256sum {filename} { + set hash {} + catch { set hash [lindex [exec sha256sum ${filename}] 0] } + return ${hash} } - if {![catch {set fileId [open $batscript "w"]}]} { - puts $fileId $script - close $fileId + proc shasum {filename} { + set hash {} + catch { set hash [lindex [exec shasum -a 256 ${filename}] 0] } + return ${hash} } + if {$::tcl_platform(platform) eq "windows"} { + proc winpowershell {filename} { + set batscript [::deken::utilities::get_tmpfilename [::deken::utilities::get_tmpdir] ".bat" ] + set script { + @echo off + powershell -Command " & {Get-FileHash -Algorithm SHA256 -LiteralPath \"%1\" | Select-Object -ExpandProperty Hash}" + } + if {![catch {set fileId [open ${batscript} "w"]}]} { + puts ${fileId} ${script} + close ${fileId} + } - if {![file exists $batscript]} { - ## still no script, give up - return "" - } + if {![file exists ${batscript}]} { + ## still no script, give up + return "" + } - if { [ catch { - set hash [exec "${batscript}" "${filename}"] - } stdout ] } { - # ouch, couldn't run powershell script - ::deken::utilities::verbose 1 "sha256.ps1 error: $stdout" - set hash "" - } + if { [ catch { + set hash [exec "${batscript}" "${filename}"] + } stdout ] } { + # ouch, couldn't run powershell script + ::deken::utilities::verbose 1 "sha256.ps1 error: ${stdout}" + set hash "" + } - catch { file delete "${batscript}" } + catch { file delete "${batscript}" } - return $hash -} -proc ::deken::utilities::sha256_msw {filename} { - set hash {} - catch { set hash [join [exec certUtil -hashfile $filename SHA256 | findstr /v "hash"] ""] } - return $hash -} -if { [catch {package require sha256} ] } { proc ::deken::utilities::sha256_tcllib {filename} {} } else { -proc ::deken::utilities::sha256_tcllib {filename} { - set hash {} - catch { set hash [::sha2::sha256 -hex -filename $filename] } - return $hash -} + return ${hash} + } + proc windows {filename} { + set hash {} + catch { + regexp {([a-fA-F0-9]{64})} [exec certUtil -hashfile ${filename} SHA256] hash + } + return ${hash} + } + } + catch { + package require sha256 + proc ZZZtcllib {filename} { + # the tcllib implementation comes last, as it is really slow... + set hash {} + catch { set hash [::sha2::sha256 -hex -filename ${filename}] } + return ${hash} + } + } } proc ::deken::utilities::verify_sha256 {url pkgfile} { - set msg [format [_ "Skipping SHA256 verification of '%s'." ] $url ] - ::deken::statuspost $msg + set msg [format [_ "Skipping SHA256 verification of '%s'." ] ${url} ] + ::deken::statuspost ${msg} return -100 } +foreach impl [lsort -dictionary [info procs ::deken::utilities::sha256::*]] { + # skip any $impl that does not return a valid sha256 (or even throws an error) + if { [catch { + if { [${impl} ${::argv0}] eq "" } { + continue + } + }] } { + continue + } + + # short name for the actually used interpreter + interp alias {} ::deken::utilities::sha256 {} ${impl} -foreach impl {sha256sum shasum powershell msw tcllib} { - if { [::deken::utilities::sha256_${impl} $::argv0] ne "" } { - set ::deken::utilities::sha256_implementation ::deken::utilities::sha256_${impl} proc ::deken::utilities::verify_sha256 {url pkgfile} { - ::deken::statuspost [format [_ "SHA256 verification of '%s'" ] $pkgfile ] debug + ::deken::statuspost [format [_ "SHA256 verification of '%s'" ] ${pkgfile} ] debug ::deken::syncgui set retval 1 set isremote 1 set hashfile "" - # check if $url really is a local file - if { [file normalize $url] eq $url } { - # $url is really an absolute filename + # check if ${url} really is a local file + if { [file normalize ${url}] eq ${url} } { + # ${url} is really an absolute filename # use it, if it exists set hashfile "${url}.sha256" set isremote 0 if { [file isfile ${hashfile} ] && [file readable ${hashfile}] } { } else { - set msg [format [_ "Unable to fetch reference SHA256 for '%s'." ] $url ] - ::deken::utilities::verbose 0 $msg - ::deken::statuspost $msg warn 0 + set msg [format [_ "Unable to fetch reference SHA256 for '%s'." ] ${url} ] + ::deken::utilities::verbose 0 ${msg} + ::deken::statuspost ${msg} warn 0 return -10 } } else { @@ -594,9 +747,9 @@ foreach impl {sha256sum shasum powershell msw tcllib} { } stdout ] } { ::deken::utilities::verbose 0 "${stdout}" # unable to download - set msg [format [_ "Unable to fetch reference SHA256 for '%s'." ] $url ] - ::deken::utilities::verbose 0 $msg - ::deken::statuspost $msg warn 0 + set msg [format [_ "Unable to fetch reference SHA256 for '%s'." ] ${url} ] + ::deken::utilities::verbose 0 ${msg} + ::deken::statuspost ${msg} warn 0 return -10 } } @@ -605,26 +758,33 @@ foreach impl {sha256sum shasum powershell msw tcllib} { } if { [ catch { - set fp [open $hashfile r] - set reference [string trim [string tolower [read $fp] ] ] - close $fp - if { $isremote } { - catch { file delete $hashfile } + set fp [open ${hashfile} r] + set reference [string trim [string tolower [read ${fp}] ] ] + close ${fp} + if { ${isremote} } { + catch { file delete ${hashfile} } } # get hash of file - set hash [${::deken::utilities::sha256_implementation} $pkgfile ] - set hash [string trim [string tolower $hash ] ] + set hash [::deken::utilities::sha256 ${pkgfile} ] + set hash [string trim [string tolower ${hash} ] ] + + if { ${hash} == "" } { + set msg [format [_ "Skipping SHA256 verification of '%s'." ] ${url} ] + ::deken::statuspost ${msg} + return -100 + } + # check if hash is sane - if { [string length $hash] != 64 || ! [string is xdigit $hash] } { - ::deken::statuspost [format [_ "File checksum looks invalid: '%s'." ] $hash] warn 0 + if { [string length ${hash}] != 64 || ! [string is xdigit ${hash}] } { + ::deken::statuspost [format [_ "File checksum looks invalid: '%s'." ] ${hash}] warn 0 } # check if reference is sane - if { [string length $reference] != 64 || ! [string is xdigit $reference] } { + if { [string length ${reference}] != 64 || ! [string is xdigit ${reference}] } { # this is more grave than the sanity check for the file hash # (since for the file hash we depend on the user's machine being able to # produce a proper SHA256 hash) - ::deken::statuspost [format [_ "Reference checksum looks invalid: '%s'." ] $reference] error 0 + ::deken::statuspost [format [_ "Reference checksum looks invalid: '%s'." ] ${reference}] error 0 } if { [string first ${reference} ${hash}] >= 0 } { @@ -636,84 +796,87 @@ foreach impl {sha256sum shasum powershell msw tcllib} { } stdout ] } { ::deken::utilities::verbose 0 "${stdout}" # unable to verify - set msg [format [_ "Unable to perform SHA256 verification for '%s'." ] $url ] - ::deken::utilities::verbose 0 $msg - ::deken::statuspost $msg warn 0 + set msg [format [_ "Unable to perform SHA256 verification for '%s'." ] ${url} ] + ::deken::utilities::verbose 0 ${msg} + ::deken::statuspost ${msg} warn 0 set retval -20 } return ${retval} } -# it seems we found a working sha256 implementation, don't try the other ones... -break -} + # it seems we found a working sha256 implementation, don't try the other ones... + break } proc ::deken::utilities::httpuseragent {} { set httpagent [::http::config -useragent] - set pdversion "Pd/$::PD_MAJOR_VERSION.$::PD_MINOR_VERSION.$::PD_BUGFIX_VERSION$::PD_TEST_VERSION" + set appname "Pd" + if {[info exists ::PD_APPLICATION_NAME]} { + set appname ${::PD_APPLICATION_NAME} + } + set pdversion "${appname}/${::PD_MAJOR_VERSION}.${::PD_MINOR_VERSION}.${::PD_BUGFIX_VERSION}${::PD_TEST_VERSION}" set platformstring [::deken::platform2string] set tclversion "Tcl/[info patchlevel]" - ::http::config -useragent "Deken/${::deken::version} ($platformstring) ${pdversion} $tclversion" - return $httpagent + ::http::config -useragent "Deken/${::deken::version} (${platformstring}) ${pdversion} ${tclversion}" + return ${httpagent} } # download a file to a location # http://wiki.tcl.tk/15303 proc ::deken::utilities::download_file {url outputfilename {progressproc {}}} { - set URL [string map {{[} "%5b" {]} "%5d"} $url] - set downloadfilename [::deken::utilities::get_tmpfilename [file dirname $outputfilename] ] - set f [open $downloadfilename w] - fconfigure $f -translation binary + set URL [string map {{[} "%5b" {]} "%5d"} ${url}] + set downloadfilename [::deken::utilities::get_tmpfilename [file dirname ${outputfilename}] ] + set f [open ${downloadfilename} w] + fconfigure ${f} -translation binary set httpagent [::deken::utilities::httpuseragent] if { [catch { - if { $progressproc eq {} } { - set httpresult [::http::geturl $URL -binary true -channel $f] + if { ${progressproc} eq {} } { + set httpresult [::http::geturl ${URL} -binary true -channel ${f}] } else { - set httpresult [::http::geturl $URL -binary true -progress ${progressproc} -channel $f] + set httpresult [::http::geturl ${URL} -binary true -progress ${progressproc} -channel ${f}] } - set ncode [::http::ncode $httpresult] - if {$ncode != 200} { + set ncode [::http::ncode ${httpresult}] + if {${ncode} != 200} { ## FIXXME: we probably should handle redirects correctly (following them...) - set err [::http::code $httpresult] - set msg [format [_ "Unable to download from %1\$s \[%2\$s\]" ] $url $err ] - ::deken::post "$msg" debug + set err [::http::code ${httpresult}] + set msg [format [_ "Unable to download from %1\$s \[%2\$s\]" ] ${url} ${err} ] + ::deken::post "${msg}" debug set outputfilename "" } - ::http::cleanup $httpresult + ::http::cleanup ${httpresult} } stdout ] } { - set msg [format [_ "Unable to download from '%s'!" ] $url ] + set msg [format [_ "Unable to download from '%s'!" ] ${url} ] tk_messageBox \ -title [_ "Download failed" ] \ - -message "${msg}\n$stdout" \ + -message "${msg}\n${stdout}" \ -icon error -type ok \ - -parent $::deken::winid + -parent ${::deken::winid} set outputfilename "" } - ::http::config -useragent $httpagent + ::http::config -useragent ${httpagent} - flush $f - close $f + flush ${f} + close ${f} - if { "$outputfilename" != "" } { - catch { file delete $outputfilename } - if {[file exists $outputfilename]} { - ::deken::utilities::debug [format [_ "Unable to remove stray file '%s'" ] $outputfilename ] + if { "${outputfilename}" != "" } { + catch { file delete ${outputfilename} } + if {[file exists ${outputfilename}]} { + ::deken::utilities::debug [format [_ "Unable to remove stray file '%s'" ] ${outputfilename} ] set outputfilename "" } } - if { $outputfilename != "" && "$outputfilename" != "$downloadfilename" } { - if {[catch { file rename $downloadfilename $outputfilename}]} { - ::deken::utilities::debug [format [_ "Unable to rename downloaded file to '%s'" ] $outputfilename ] + if { ${outputfilename} != "" && "${outputfilename}" != "${downloadfilename}" } { + if {[catch { file rename ${downloadfilename} ${outputfilename}}]} { + ::deken::utilities::debug [format [_ "Unable to rename downloaded file to '%s'" ] ${outputfilename} ] set outputfilename "" } } - if { "$outputfilename" eq "" } { - file delete $downloadfilename + if { "${outputfilename}" eq "" } { + file delete ${downloadfilename} } - return $outputfilename + return ${outputfilename} } @@ -722,56 +885,61 @@ proc ::deken::utilities::download_file {url outputfilename {progressproc {}}} { # v1:: [\[)} # return: list [list ...] proc ::deken::utilities::parse_filename {filename} { - set pkgname $filename + set pkgname ${filename} set archs [list] set version "" - if { [ string match "*.dek" $filename ] } { + if { [ string match "*.dek" ${filename} ] } { ## deken filename v1: [v]()().dek set archstring "" - regexp {^([^\[\]\(\)]+)((\[[^\[\]\(\)]+\])*)((\([^\[\]\(\)]+\))*)\.dek$} $filename _ pkgname optionstring _ archstring - foreach {o _} [lreplace [split $optionstring {[]}] 0 0] { - if {![string first v ${o}]} { - set version [string range $o 1 end] - } else { # ignoring unknown option... + if { ! [regexp {^([^\[\]\(\)]+)((\[[^\[\]\(\)]+\])*)((\([^\[\]\(\)]+\))*).*\.dek$} ${filename} _ pkgname optionstring _ archstring] } { + # oops, somewhat unparseable (e.g. a copy) + + } else { + foreach {o _} [lreplace [split ${optionstring} {[]}] 0 0] { + if {![string first v ${o}]} { + set version [string range ${o} 1 end] + } else { # ignoring unknown option... + return [list {} {} {}] + } } + foreach {a _} [lreplace [split ${archstring} "()"] 0 0] { lappend archs ${a} } } - foreach {a _} [lreplace [split $archstring "()"] 0 0] { lappend archs $a } - } elseif { [ regexp {(.*)-externals\..*} $filename _ basename] } { + } elseif { [ regexp {(.*)-externals\..*} ${filename} _ basename] } { ## deken filename v0 - set pkgname $basename + set pkgname ${basename} # basename [-v-]?{()} ## strip off the archs - set baselist [split $basename () ] + set baselist [split ${basename} () ] # get pkgname + version - set pkgver [lindex $baselist 0] - if { ! [ regexp "(.*)-v(.*)-" $pkgver _ pkgname version ] } { - set pkgname $pkgver + set pkgver [lindex ${baselist} 0] + if { ! [ regexp "(.*)-v(.*)-" ${pkgver} _ pkgname version ] } { + set pkgname ${pkgver} set version "" } # get archs - foreach {a _} [lreplace $baselist 0 0] { + foreach {a _} [lreplace ${baselist} 0 0] { # in filename.v0 the semantics of the last arch field ("bits") was unclear # since this format predates float64 builds, we just force it to 32 - regsub -- {-[0-9]+$} $a {-32} a - lappend archs $a + regsub -- {-[0-9]+$} ${a} {-32} a + lappend archs ${a} } - if { "x$archs$version" == "x" } { + if { "x${archs}${version}" == "x" } { # try again as -v - if { ! [ regexp "(.*)-v(.*)" $pkgver _ pkgname version ] } { - set pkgname $pkgver + if { ! [ regexp "(.*)-v(.*)" ${pkgver} _ pkgname version ] } { + set pkgname ${pkgver} set version "" } } } - list $pkgname $version $archs + return [list ${pkgname} ${version} ${archs}] } # split filename extension from deken-packagefilename proc ::deken::utilities::get_filenameextension {filename} { - if { [ regexp {.*(\.tar\.[^.]*)$} $filename _ ext ] } { - return $ext + if { [ regexp {.*(\.tar\.[^.]*)$} ${filename} _ ext ] } { + return ${ext} } - return [file extension $filename] + return [file extension ${filename}] } @@ -780,6 +948,65 @@ proc ::deken::utilities::get_filenameextension {filename} { # ################ preferences ######################################### # ###################################################################### +proc ::deken::preferences::create_sources_entry {toplevel} { + # 3 panels + # - [ ] primary server + # - [ ] secondary URLs (list editable) + # (all URLs are searched if checked) + # - [ ] ephemeral URLs (list multiselectable) + # (if checked, and URLs are selected, only these are searched) + # (if checked, and no URLs are selected, all are searched) + set frame [::deken::preferences::newwidget ${toplevel}.servers] + labelframe ${frame} -text [_ "Search URLs:" ] -padx 5 -pady 5 -borderwidth 1 + set numframes 0 + + if {1} { + set f [::deken::preferences::newwidget ${frame}.primary] + # primary URL + labelframe ${f} -borderwidth 0 + checkbutton ${f}.use -text "${::deken::search::dekenserver::url_primary}" \ + -variable ::deken::preferences::use_url_primary + ${f} configure -labelwidget ${f}.use + pack ${f} -anchor "w" -fill both -expand 1 -side top + pack ${f}.use -anchor "w" -side left + incr numframes + } + + if {0} { + set f [::deken::preferences::newwidget ${frame}.secondary] + # secondary URLs + labelframe ${f} -borderwidth 0 + checkbutton ${f}.use \ + -variable ::deken::preferences::use_urls_secondary + button ${f}.open \ + -command [list ::deken::preferences::urls2_frame_create ${toplevel}] \ + -text [_ "Additional search URLs" ] + ${f} configure -labelwidget ${f}.use + pack ${f} -anchor "w" -fill both -expand 1 -side left + pack ${f}.use -anchor "w" -side left + pack ${f}.open -anchor "w" -side left + incr numframes + } + + if {0} { + set f [::deken::preferences::newwidget ${frame}.ephemeral] + # ephemeral URLs + labelframe ${f} -borderwidth 0 + checkbutton ${f}.use \ + -variable ::deken::preferences::use_urls_ephemeral + button ${f}.open -text [_ "Ephemeral search URLs" ] + ${f} configure -labelwidget ${f}.use + pack ${f} -anchor "w" -fill both -expand 1 -side left + pack ${f}.use -anchor "w" -side left + pack ${f}.open -anchor "w" -side left + incr numframes + } + if { ${numframes} > 1 } { + return ${frame} + } + return "" +} + proc ::deken::preferences::newwidget {basename} { # calculate a widget name that has not yet been taken set i 0 @@ -787,22 +1014,43 @@ proc ::deken::preferences::newwidget {basename} { return ${basename}${i} } +proc ::deken::preferences::urls2_frame_create {toplevel} { + set title [_ "Additional search URLs"] + set win ${toplevel}.urls2 + destroy $win + toplevel $win + wm title $win "deken: ${title}" + ::scrollbox::make ${win} ${::deken::preferences::urls_secondary} {} {} + #::deken::preferences::make_applybutton_frame ${win} \ + # [list ::deken::preferences::urls2_frame_apply ${win}] + + set cmd [list ::scrollboxwindow::apply ${win} ::deken::preferences::set_urls_secondary] + ::deken::preferences::make_applybutton_frame ${win} \ + "${cmd}; destroy ${win}" + + bind ${win} [list after idle [list ::deken::preferences::cancel $win]] + +} +proc ::deken::preferences::set_urls_secondary {urls} { + set ::deken::preferences::urls_secondary ${urls} +} + proc ::deken::preferences::create_pathpad {toplevel row {padx 2} {pady 2}} { set pad [::deken::preferences::newwidget ${toplevel}.pad] - frame $pad -relief groove -borderwidth 2 -width 2 -height 2 + frame ${pad} -relief groove -borderwidth 2 -width 2 -height 2 grid ${pad} -sticky ew -row ${row} -column 0 -columnspan 3 -padx ${padx} -pady ${pady} } proc ::deken::preferences::create_packpad {toplevel {padx 2} {pady 2} } { set mypad [::deken::preferences::newwidget ${toplevel}.pad] - frame $mypad - pack $mypad -padx ${padx} -pady ${pady} -expand 1 -fill "y" + frame ${mypad} + pack ${mypad} -padx ${padx} -pady ${pady} -expand 1 -fill "y" - return $mypad + return ${mypad} } proc ::deken::preferences::userpath_doit { winid } { - set installdir [::deken::do_prompt_installdir ${::deken::preferences::userinstallpath} $winid] + set installdir [::deken::do_prompt_installdir ${::deken::preferences::userinstallpath} ${winid}] if { "${installdir}" != "" } { set ::deken::preferences::userinstallpath "${installdir}" } @@ -819,8 +1067,8 @@ proc ::deken::preferences::path_doit {rdb ckb path {mkdir true}} { if { ! [file exists ${path}] } { ${ckb} configure -text [_ "Create"] - if { $mkdir } { - catch { file mkdir $path } + if { ${mkdir} } { + catch { file mkdir ${path} } } } @@ -834,260 +1082,361 @@ proc ::deken::preferences::path_doit {rdb ckb path {mkdir true}} { } } +proc ::deken::preferences::update_displaypath {var value} { + set ${var} ${value} +} proc ::deken::preferences::create_pathentry {toplevel row var path {generic false}} { # only add absolute paths to the pathentries - set xpath [ ::deken::utilities::expandpath $path ] - if {! $generic} { - if { [file pathtype $xpath] != "absolute"} { return } + set xpath [ ::deken::utilities::expandpath ${path} ] + if {! ${generic}} { + if { [file pathtype ${xpath}] != "absolute"} { return } } set rdb [::deken::preferences::newwidget ${toplevel}.path] set chk [::deken::preferences::newwidget ${toplevel}.doit] set pad [::deken::preferences::newwidget ${toplevel}.pad] - radiobutton ${rdb} -value ${path} -text "${path}" -variable $var + radiobutton ${rdb} -value ${path} -text "${path}" -variable ${var} \ + -command [list ::deken::preferences::update_displaypath ${var}_x ${path}] frame ${pad} - button ${chk} -text "..." -command "::deken::preferences::path_doit ${rdb} ${chk} ${xpath}" + button ${chk} -text [_ "Browse" ] -command "::deken::preferences::path_doit ${rdb} ${chk} ${xpath}" grid ${rdb} -sticky "w" -row ${row} -column 2 grid ${pad} -sticky "" -row ${row} -column 1 -padx 10 grid ${chk} -sticky nsew -row ${row} -column 0 - if {! $generic} { + if {! ${generic}} { ::deken::preferences::path_doit ${rdb} ${chk} ${xpath} false } - list ${rdb} ${chk} + return [list ${rdb} ${chk}] } -proc ::deken::preferences::create {winid} { - # urgh...we want to know when the window gets drawn, - # so we can query the size of the pathentries canvas - # in order to get the scrolling-region right!!! - # this seems to be so wrong... - bind $winid "::deken::preferences::mapped %W" - ::deken::bind_globalshortcuts $winid - - set ::deken::preferences::installpath $::deken::installpath - set ::deken::preferences::hideforeignarch $::deken::hideforeignarch - set ::deken::preferences::hideoldversions $::deken::hideoldversions - if { $::deken::userplatform == "" } { - set ::deken::preferences::platform DEFAULT - set ::deken::preferences::userplatform [ ::deken::platform2string ] - } else { - set ::deken::preferences::platform USER - set ::deken::preferences::userplatform $::deken::userplatform - } - - set ::deken::preferences::installpath USER - set ::deken::preferences::userinstallpath $::deken::installpath - - set ::deken::preferences::show_readme $::deken::show_readme - set ::deken::preferences::keep_package $::deken::keep_package - set ::deken::preferences::verify_sha256 $::deken::verify_sha256 - set ::deken::preferences::remove_on_install $::deken::remove_on_install - set ::deken::preferences::add_to_path $::deken::add_to_path - set ::deken::preferences::add_to_path_temp $::deken::preferences::add_to_path - - # this dialog allows us to select: - # - which directory to extract to - # - including all (writable) elements from $::sys_staticpath - # and option to create each of them - # - a directory chooser - # - whether to delete directories before re-extracting - # - whether to filter-out non-matching architectures - labelframe $winid.installdir -text [_ "Install externals to directory:" ] -padx 5 -pady 5 -borderwidth 1 - canvas $winid.installdir.cnv \ +proc ::deken::preferences::fill_frame {winid} { + ::deken::preferences::create ${winid} +} +proc ::deken::preferences::create_pathframe {cnv winid} { + canvas ${cnv}.cnv \ -confine true - scrollbar $winid.installdir.scrollv \ - -command "$winid.installdir.cnv yview" - scrollbar $winid.installdir.scrollh \ + scrollbar ${cnv}.scrollv \ + -command "${cnv}.cnv yview" + scrollbar ${cnv}.scrollh \ -orient horizontal \ - -command "$winid.installdir.cnv xview" - $winid.installdir.cnv configure \ + -command "${cnv}.cnv xview" + ${cnv}.cnv configure \ -xscrollincrement 0 \ - -xscrollcommand " $winid.installdir.scrollh set" - $winid.installdir.cnv configure \ + -xscrollcommand " ${cnv}.scrollh set" + ${cnv}.cnv configure \ -yscrollincrement 0 \ - -yscrollcommand " $winid.installdir.scrollv set" \ + -yscrollcommand " ${cnv}.scrollv set" \ - pack $winid.installdir.cnv -side left -fill both -expand 1 - pack $winid.installdir.scrollv -side right -fill "y" - pack $winid.installdir.scrollh -side bottom -fill "x" -before $winid.installdir.cnv - pack $winid.installdir -fill both + pack ${cnv}.cnv -side left -fill both -expand 1 + pack ${cnv}.scrollv -side right -fill "y" + pack ${cnv}.scrollh -side bottom -fill "x" -before ${cnv}.cnv - set pathsframe [frame $winid.installdir.cnv.f] + set pathsframe [frame ${cnv}.cnv.f] set row 0 ### dekenpath: directory-chooser # FIXME: should we ask user to add chosen directory to PATH? set pathdoit [::deken::preferences::create_pathentry ${pathsframe} ${row} ::deken::preferences::installpath "USER" true] incr row - [lindex $pathdoit 0] configure \ + [lindex ${pathdoit} 0] configure \ -foreground blue \ -value "USER" \ -textvariable ::deken::preferences::userinstallpath \ - -variable ::deken::preferences::installpath - [lindex $pathdoit 1] configure \ - -text "..." \ - -command "::deken::preferences::userpath_doit $winid" - ::deken::preferences::create_pathpad ${pathsframe} ${row} - incr row + -variable ::deken::preferences::installpath \ + -command {::deken::preferences::update_displaypath ::deken::preferences::installpath_x ${::deken::preferences::userinstallpath}} + + [lindex ${pathdoit} 1] configure \ + -text [_ "Browse" ] \ + -command "::deken::preferences::userpath_doit ${winid}" ### dekenpath: default directories if {[namespace exists ::pd_docsdir] && [::pd_docsdir::externals_path_is_valid]} { - foreach p [::pd_docsdir::get_externals_path] { - ::deken::preferences::create_pathentry ${pathsframe} ${row} ::deken::preferences::installpath $p + set xpath [::pd_docsdir::get_externals_path] + if { [llength ${xpath}] } { + ::deken::preferences::create_pathpad ${pathsframe} ${row} + incr row + } + + foreach p ${xpath} { + ::deken::preferences::create_pathentry ${pathsframe} ${row} ::deken::preferences::installpath ${p} incr row } + } + if { [llength ${::sys_staticpath}] } { ::deken::preferences::create_pathpad ${pathsframe} ${row} incr row } set extradir [file join ${::sys_libdir} extra ] - foreach p $::sys_staticpath { - if { [file normalize $p] == $extradir } { + foreach p ${::sys_staticpath} { + if { [file normalize ${p}] == ${extradir} } { set p [file join @PD_PATH@ extra] } - ::deken::preferences::create_pathentry ${pathsframe} ${row} ::deken::preferences::installpath $p + ::deken::preferences::create_pathentry ${pathsframe} ${row} ::deken::preferences::installpath ${p} incr row } - ::deken::preferences::create_pathpad ${pathsframe} ${row} - incr row - foreach p $::sys_searchpath { - ::deken::preferences::create_pathentry ${pathsframe} ${row} ::deken::preferences::installpath $p + if {[llength ${::sys_searchpath}]} { + ::deken::preferences::create_pathpad ${pathsframe} ${row} incr row } - pack $pathsframe -fill "x" - $winid.installdir.cnv create window 0 0 -anchor "nw" -window $pathsframe + foreach p ${::sys_searchpath} { + ::deken::preferences::create_pathentry ${pathsframe} ${row} ::deken::preferences::installpath ${p} + incr row + } + + pack ${pathsframe} -fill "x" + ${cnv}.cnv create window 0 0 -anchor "nw" -window ${pathsframe} +} +proc ::deken::preferences::create_pathwindow {parentwin} { + set winid ${parentwin}.pathwindow + if {[winfo exists ${winid}]} { + wm deiconify ${winid} + raise ${winid} + } else { + toplevel ${winid} -class DialogWindow + bind ${winid} {after idle {::deken::preferences::cancel %W}} + wm title ${winid} [_ "Deken Installation Target"] + + frame ${winid}.frame + pack ${winid}.frame -side top -padx 6 -pady 3 -fill both -expand true + + ::deken::preferences::create_pathframe ${winid}.frame ${parentwin} + + frame ${winid}.bframe + pack ${winid}.bframe -side bottom -fill "x" -pady 2m + button ${winid}.bframe.close -text [_ "Close" ] \ + -command [list ::deken::preferences::cancel ${winid}] + pack ${winid}.bframe.close -side right -expand 1 -fill "x" -padx 15 -ipadx 10 + } +} + + + +proc ::deken::preferences::create {winid} { + # urgh...we want to know when the window gets drawn, + # so we can query the size of the pathentries canvas + # in order to get the scrolling-region right!!! + # this seems to be so wrong... + bind ${winid} "::deken::preferences::mapped %W" + ::deken::bind_globalshortcuts ${winid} + + set ::deken::preferences::installpath ${::deken::installpath} + set ::deken::preferences::installpath_x ${::deken::installpath} + set ::deken::preferences::hideforeignarch ${::deken::hideforeignarch} + set ::deken::preferences::hideoldversions ${::deken::hideoldversions} + if { ${::deken::userplatform} == "" } { + set ::deken::preferences::platform DEFAULT + set ::deken::preferences::userplatform [ ::deken::platform2string ] + } else { + set ::deken::preferences::platform USER + set ::deken::preferences::userplatform ${::deken::userplatform} + } + + set ::deken::preferences::installpath USER + set ::deken::preferences::userinstallpath ${::deken::installpath} + + set ::deken::preferences::show_readme ${::deken::show_readme} + set ::deken::preferences::keep_package ${::deken::keep_package} + set ::deken::preferences::verify_sha256 ${::deken::verify_sha256} + set ::deken::preferences::remove_on_install ${::deken::remove_on_install} + set ::deken::preferences::add_to_path ${::deken::add_to_path} + set ::deken::preferences::add_to_path_temp ${::deken::preferences::add_to_path} + + set ::deken::preferences::urls_secondary ${::deken::search::dekenserver::urls_secondary} + set ::deken::preferences::urls_ephemeral ${::deken::search::dekenserver::urls_ephemeral} + + set ::deken::preferences::use_url_primary ${::deken::search::dekenserver::use_url_primary} + set ::deken::preferences::use_urls_secondary ${::deken::search::dekenserver::use_urls_secondary} + set ::deken::preferences::use_urls_ephemeral ${::deken::search::dekenserver::use_urls_ephemeral} + + + # this dialog allows us to select: + # - which directory to extract to + # - including all (writable) elements from ${::sys_staticpath} + # and option to create each of them + # - a directory chooser + # - whether to delete directories before re-extracting + # - whether to filter-out non-matching architectures + labelframe ${winid}.installdir -text [_ "Install externals to directory:" ] \ + -borderwidth 1 -padx 5 -pady 5 + if { 1 } { + set readonly_color [lindex [${winid} configure -background] end] + pack ${winid}.installdir -fill x -anchor s + # -padx {2m 4m} -pady 2m + + frame ${winid}.installdir.path + pack ${winid}.installdir.path -fill x + entry ${winid}.installdir.path.entry -textvariable ::deken::preferences::installpath_x \ + -takefocus 0 -state readonly -readonlybackground $readonly_color + button ${winid}.installdir.path.browse -text [_ "Browse"] \ + -command [list ::deken::preferences::create_pathwindow ${winid}] + pack ${winid}.installdir.path.browse -side right -fill x -ipadx 8 + pack ${winid}.installdir.path.entry -side right -expand 1 -fill x + # scroll to right for long paths + ${winid}.installdir.path.entry xview moveto 1 + } else { + ::deken::preferences::create_pathframe ${winid}.installdir ${winid} + } + pack ${winid}.installdir -fill both + ## installation options - labelframe $winid.install -text [_ "Installation options:" ] -padx 5 -pady 5 -borderwidth 1 - pack $winid.install -side top -fill "x" -anchor "w" + labelframe ${winid}.install -text [_ "Installation options:" ] -padx 5 -pady 5 -borderwidth 1 + pack ${winid}.install -side top -fill "x" -anchor "w" - checkbutton $winid.install.verify256 -text [_ "Try to verify the libraries' checksum before (re)installing them"] \ + checkbutton ${winid}.install.verify256 -text [_ "Try to verify the libraries' checksum before (re)installing them"] \ -variable ::deken::preferences::verify_sha256 - pack $winid.install.verify256 -anchor "w" + pack ${winid}.install.verify256 -anchor "w" - checkbutton $winid.install.remove -text [_ "Try to remove libraries before (re)installing them"] \ + checkbutton ${winid}.install.remove -text [_ "Try to remove libraries before (re)installing them"] \ -variable ::deken::preferences::remove_on_install - pack $winid.install.remove -anchor "w" + pack ${winid}.install.remove -anchor "w" - checkbutton $winid.install.readme -text [_ "Show README of newly installed libraries (if present)"] \ + checkbutton ${winid}.install.readme -text [_ "Show README of newly installed libraries (if present)"] \ -variable ::deken::preferences::show_readme - pack $winid.install.readme -anchor "w" + pack ${winid}.install.readme -anchor "w" - checkbutton $winid.install.keeppackage -text [_ "Keep package files after installation"] \ + checkbutton ${winid}.install.keeppackage -text [_ "Keep package files after installation"] \ -variable ::deken::preferences::keep_package - pack $winid.install.keeppackage -anchor "w" + pack ${winid}.install.keeppackage -anchor "w" - checkbutton $winid.install.add_to_path -text [_ "Add newly installed libraries to Pd's search path"] \ + checkbutton ${winid}.install.add_to_path -text [_ "Add newly installed libraries to Pd's search path"] \ -variable ::deken::preferences::add_to_path - catch { $winid.install.add_to_path configure \ + catch { ${winid}.install.add_to_path configure \ -tristatevalue 1 \ -onvalue 2 \ -command {set ::deken::preferences::add_to_path \ [set ::deken::preferences::add_to_path_temp \ - [::deken::utilities::tristate $::deken::preferences::add_to_path_temp 1 0]]} + [::deken::utilities::tristate ${::deken::preferences::add_to_path_temp} 1 0]]} set msg "- Always add to search path\n- Never add to search path\n- Prompt before adding" - bind $winid.install.add_to_path "::deken::balloon::show $winid.install_balloon %X \[winfo rooty %W\] \{$msg\} 0 30" - bind $winid.install.add_to_path [list ::deken::balloon::hide $winid.install_balloon] + bind ${winid}.install.add_to_path "::deken::balloon::show ${winid}.install_balloon %X \[winfo rooty %W\] \{${msg}\} 0 30" + bind ${winid}.install.add_to_path [list ::deken::balloon::hide ${winid}.install_balloon] } stdout - pack $winid.install.add_to_path -anchor "w" + pack ${winid}.install.add_to_path -anchor "w" ## platform filter settings - labelframe $winid.platform -text [_ "Platform settings:" ] -padx 5 -pady 5 -borderwidth 1 - pack $winid.platform -side top -fill "x" -anchor "w" + labelframe ${winid}.platform -text [_ "Platform settings:" ] -padx 5 -pady 5 -borderwidth 1 + pack ${winid}.platform -side top -fill "x" -anchor "w" # default architecture vs user-defined arch - radiobutton $winid.platform.default -value "DEFAULT" \ + radiobutton ${winid}.platform.default -value "DEFAULT" \ -text [format [_ "Default platform: %s" ] [::deken::platform2string ] ] \ -variable ::deken::preferences::platform \ - -command "$winid.platform.userarch.entry configure -state disabled" - pack $winid.platform.default -anchor "w" + -command "${winid}.platform.userarch.entry configure -state disabled" + pack ${winid}.platform.default -anchor "w" - frame $winid.platform.userarch - radiobutton $winid.platform.userarch.radio -value "USER" \ + frame ${winid}.platform.userarch + radiobutton ${winid}.platform.userarch.radio -value "USER" \ -text [_ "User-defined platform:" ] \ -variable ::deken::preferences::platform \ - -command "$winid.platform.userarch.entry configure -state normal" - entry $winid.platform.userarch.entry -textvariable ::deken::preferences::userplatform - if { "$::deken::preferences::platform" == "DEFAULT" } { - $winid.platform.userarch.entry configure -state disabled + -command "${winid}.platform.userarch.entry configure -state normal" + entry ${winid}.platform.userarch.entry -textvariable ::deken::preferences::userplatform + if { "${::deken::preferences::platform}" == "DEFAULT" } { + ${winid}.platform.userarch.entry configure -state disabled } - pack $winid.platform.userarch -anchor "w" - pack $winid.platform.userarch.radio -side left - pack $winid.platform.userarch.entry -side right -fill "x" + pack ${winid}.platform.userarch -anchor "w" + pack ${winid}.platform.userarch.radio -side left + pack ${winid}.platform.userarch.entry -side right -fill "x" # hide non-matching architecture? - ::deken::preferences::create_packpad $winid.platform 2 10 + ::deken::preferences::create_packpad ${winid}.platform 2 10 - checkbutton $winid.platform.hide_foreign -text [_ "Hide foreign architectures"] \ + checkbutton ${winid}.platform.hide_foreign -text [_ "Hide foreign architectures"] \ -variable ::deken::preferences::hideforeignarch - pack $winid.platform.hide_foreign -anchor "w" - checkbutton $winid.platform.only_newest -text [_ "Only show the newest version of a library\n(treats other versions like foreign architectures)"] \ + pack ${winid}.platform.hide_foreign -anchor "w" + checkbutton ${winid}.platform.only_newest -text [_ "Only show the newest version of a library\n(treats other versions like foreign architectures)"] \ -variable ::deken::preferences::hideoldversions -justify "left" - pack $winid.platform.only_newest -anchor "w" - + pack ${winid}.platform.only_newest -anchor "w" - # Use two frames for the buttons, since we want them both bottom and right - frame $winid.nb - pack $winid.nb -side bottom -fill "x" -pady 2m - - # buttons - frame $winid.nb.buttonframe - pack $winid.nb.buttonframe -side right -fill "x" -padx 2m - - button $winid.nb.buttonframe.cancel -text [_ "Cancel"] \ - -command "::deken::preferences::cancel $winid" - pack $winid.nb.buttonframe.cancel -side left -expand 1 -fill "x" -padx 15 -ipadx 10 - if {$::windowingsystem ne "aqua"} { - button $winid.nb.buttonframe.apply -text [_ "Apply"] \ - -command "::deken::preferences::apply $winid" - pack $winid.nb.buttonframe.apply -side left -expand 1 -fill "x" -padx 15 -ipadx 10 + # search URLs + set sourceframe [::deken::preferences::create_sources_entry ${winid}] + if { ${sourceframe} ne {} } { + pack ${sourceframe} -anchor "w" -fill both -expand 1 } - button $winid.nb.buttonframe.ok -text [_ "OK"] \ - -command "::deken::preferences::ok $winid" - pack $winid.nb.buttonframe.ok -side left -expand 1 -fill "x" -padx 15 -ipadx 10 } proc ::deken::preferences::mapped {winid} { - set cnv $winid.installdir.cnv + set cnv ${winid}.installdir.cnv catch { - set bbox [$cnv bbox all] - if { "$bbox" != "" } { - $cnv configure -scrollregion $bbox + set bbox [${cnv} bbox all] + if { "${bbox}" != "" } { + ${cnv} configure -scrollregion ${bbox} } } stdout } +proc ::deken::preferences::make_applybutton_frame {winid okproc {cancelproc {}} {applyproc {}}} { + # the Apply/OK/Cancel buttons + if {${::windowingsystem} eq "aqua"} { + # no "Apply" on macOS... + set applyproc {} + } + if { ${cancelproc} eq {} } { + set cancelproc [list destroy ${winid}] + } + + # Use two frames for the buttons, since we want them both bottom and right + frame ${winid}.nb + pack ${winid}.nb -side bottom -fill "x" -pady 2m + + # buttons + frame ${winid}.nb.buttonframe + pack ${winid}.nb.buttonframe -side right -fill "x" -padx 2m + + button ${winid}.nb.buttonframe.cancel -text [_ "Cancel"] \ + -command ${cancelproc} + pack ${winid}.nb.buttonframe.cancel -side left -expand 1 -fill "x" -padx 15 -ipadx 10 + + if { ${applyproc} ne {} } { + button ${winid}.nb.buttonframe.apply -text [_ "Apply"] \ + -command ${applyproc} + pack ${winid}.nb.buttonframe.apply -side left -expand 1 -fill "x" -padx 15 -ipadx 10 + } + if { ${okproc} ne {} } { + button ${winid}.nb.buttonframe.ok -text [_ "OK"] \ + -command ${okproc} + pack ${winid}.nb.buttonframe.ok -side left -expand 1 -fill "x" -padx 15 -ipadx 10 + } +} + proc ::deken::preferences::show {{winid .deken_preferences}} { - if {[winfo exists $winid]} { - wm deiconify $winid - raise $winid + if {[winfo exists ${winid}]} { + wm deiconify ${winid} + raise ${winid} } else { - toplevel $winid -class DialogWindow - wm title $winid [format [_ "Deken %s Preferences"] $::deken::version] + toplevel ${winid} -class DialogWindow + wm title ${winid} [format [_ "Deken %s Preferences"] ${::deken::version}] + + frame ${winid}.frame + pack ${winid}.frame -side top -padx 6 -pady 3 -fill both -expand true - frame $winid.frame - pack $winid.frame -side top -padx 6 -pady 3 -fill both -expand true + bind ${winid} {after idle {::deken::preferences::cancel %W}} + ::deken::preferences::create ${winid}.frame - ::deken::preferences::create $winid.frame + + # the Apply/OK/Cancel buttons + ::deken::preferences::make_applybutton_frame ${winid} \ + [list ::deken::preferences::ok ${winid}] \ + [list ::deken::preferences::cancel ${winid}] \ + [list ::deken::preferences::apply ${winid}] } } proc ::deken::preferences::apply {winid} { set installpath "${::deken::preferences::installpath}" - if { "$installpath" == "USER" } { + if { "${installpath}" == "USER" } { set installpath "${::deken::preferences::userinstallpath}" } - ::deken::set_installpath "$installpath" + ::deken::set_installpath "${installpath}" set plat "" if { "${::deken::preferences::platform}" == "USER" } { set plat "${::deken::preferences::userplatform}" @@ -1099,14 +1448,21 @@ proc ::deken::preferences::apply {winid} { "${::deken::preferences::add_to_path}" \ "${::deken::preferences::keep_package}" \ "${::deken::preferences::verify_sha256}" + + ::deken::set_search_urls \ + ${::deken::preferences::use_url_primary} \ + ${::deken::preferences::use_urls_secondary} \ + ${::deken::preferences::urls_secondary} \ + ${::deken::preferences::use_urls_ephemeral} \ + ${::deken::preferences::urls_ephemeral} } proc ::deken::preferences::cancel {winid} { ## FIXXME properly close the window/frame (for reuse in a tabbed pane) - destroy .deken_preferences + destroy ${winid} } proc ::deken::preferences::ok {winid} { - ::deken::preferences::apply $winid - ::deken::preferences::cancel $winid + ::deken::preferences::apply ${winid} + ::deken::preferences::cancel ${winid} } # ###################################################################### @@ -1116,26 +1472,35 @@ proc ::deken::preferences::ok {winid} { if { [ catch { set ::deken::installpath [::pd_guiprefs::read dekenpath] } stdout ] } { # this is a Pd without the new GUI-prefs proc ::deken::set_installpath {installdir} { - set ::deken::installpath $installdir + set ::deken::installpath ${installdir} } proc ::deken::set_platform_options {platform hideforeignarch {hideoldversions 0}} { - set ::deken::userplatform $platform - set ::deken::hideforeignarch [::deken::utilities::bool $hideforeignarch ] - set ::deken::hideoldversions [::deken::utilities::bool $hideoldversions ] + set ::deken::userplatform ${platform} + set ::deken::hideforeignarch [::deken::utilities::bool ${hideforeignarch} ] + set ::deken::hideoldversions [::deken::utilities::bool ${hideoldversions} ] } proc ::deken::set_install_options {remove readme add keep verify256} { - set ::deken::remove_on_install [::deken::utilities::bool $remove] - set ::deken::show_readme [::deken::utilities::bool $readme] - set ::deken::add_to_path [::deken::utilities::tristate $add 0 0] - set ::deken::keep_package [::deken::utilities::bool $keep] - set ::deken::verify_sha256 [::deken::utilities::bool $verify256] + set ::deken::remove_on_install [::deken::utilities::bool ${remove}] + set ::deken::show_readme [::deken::utilities::bool ${readme}] + set ::deken::add_to_path [::deken::utilities::tristate ${add} 0 0] + set ::deken::keep_package [::deken::utilities::bool ${keep}] + set ::deken::verify_sha256 [::deken::utilities::bool ${verify256}] + } + proc ::deken::set_search_urls {use_primary use_secondaries secondaries use_ephemerals ephemerals} { + set ::deken::search::dekenserver::use_url_primary [::deken::utilities::bool ${use_primary}] + + set ::deken::search::dekenserver::use_urls_secondary [::deken::utilities::bool ${use_secondaries}] + set ::deken::search::dekenserver::urls_secondary ${secondaries} + + set ::deken::search::dekenserver::use_urls_ephemeral [::deken::utilities::bool ${use_ephemerals}] + set ::deken::search::dekenserver::urls_ephemeral ${ephemerals} } } else { catch {set ::deken::installpath [lindex ${::deken::installpath} 0]} # Pd has a generic preferences system, that we can use proc ::deken::set_installpath {installdir} { - set ::deken::installpath $installdir - ::pd_guiprefs::write dekenpath [list $installdir] + set ::deken::installpath ${installdir} + ::pd_guiprefs::write dekenpath [list ${installdir}] } # user requested platform (empty = DEFAULT) set ::deken::userplatform [::pd_guiprefs::read deken_platform] @@ -1148,17 +1513,17 @@ if { [ catch { set ::deken::installpath [::pd_guiprefs::read dekenpath] } stdout set ::deken::hideforeignarch [::deken::utilities::bool [::pd_guiprefs::read deken_hide_foreign_archs] 1] set ::deken::hideoldversions [::deken::utilities::bool [::pd_guiprefs::read deken_hide_old_versions] 1] proc ::deken::set_platform_options {platform hideforeignarch {hideoldversions 0}} { - set ::deken::userplatform $platform - if { $platform == "" } { + set ::deken::userplatform ${platform} + if { ${platform} == "" } { set platformlist [list] } else { - set platformlist [list $platform] + set platformlist [list ${platform}] } - set ::deken::hideforeignarch [::deken::utilities::bool $hideforeignarch ] - set ::deken::hideoldversions [::deken::utilities::bool $hideoldversions ] - ::pd_guiprefs::write deken_platform $platformlist - ::pd_guiprefs::write deken_hide_foreign_archs $::deken::hideforeignarch - ::pd_guiprefs::write deken_hide_old_versions $::deken::hideoldversions + set ::deken::hideforeignarch [::deken::utilities::bool ${hideforeignarch} ] + set ::deken::hideoldversions [::deken::utilities::bool ${hideoldversions} ] + ::pd_guiprefs::write deken_platform ${platformlist} + ::pd_guiprefs::write deken_hide_foreign_archs ${::deken::hideforeignarch} + ::pd_guiprefs::write deken_hide_old_versions ${::deken::hideoldversions} } set ::deken::remove_on_install [::deken::utilities::bool [::pd_guiprefs::read deken_remove_on_install] 1] set ::deken::show_readme [::deken::utilities::bool [::pd_guiprefs::read deken_show_readme] 1] @@ -1167,16 +1532,37 @@ if { [ catch { set ::deken::installpath [::pd_guiprefs::read dekenpath] } stdout set ::deken::add_to_path [::deken::utilities::tristate [::pd_guiprefs::read deken_add_to_path] ] proc ::deken::set_install_options {remove readme path keep verify256} { - set ::deken::remove_on_install [::deken::utilities::bool $remove] - set ::deken::show_readme [::deken::utilities::bool $readme] - set ::deken::add_to_path [::deken::utilities::tristate $path] - set ::deken::keep_package [::deken::utilities::bool $keep] - set ::deken::verify_sha256 [::deken::utilities::bool $verify256] - ::pd_guiprefs::write deken_remove_on_install "$::deken::remove_on_install" - ::pd_guiprefs::write deken_show_readme "$::deken::show_readme" - ::pd_guiprefs::write deken_add_to_path "$::deken::add_to_path" - ::pd_guiprefs::write deken_keep_package "$::deken::keep_package" - ::pd_guiprefs::write deken_verify_sha256 "$::deken::verify_sha256" + set ::deken::remove_on_install [::deken::utilities::bool ${remove}] + set ::deken::show_readme [::deken::utilities::bool ${readme}] + set ::deken::add_to_path [::deken::utilities::tristate ${path}] + set ::deken::keep_package [::deken::utilities::bool ${keep}] + set ::deken::verify_sha256 [::deken::utilities::bool ${verify256}] + ::pd_guiprefs::write deken_remove_on_install "${::deken::remove_on_install}" + ::pd_guiprefs::write deken_show_readme "${::deken::show_readme}" + ::pd_guiprefs::write deken_add_to_path "${::deken::add_to_path}" + ::pd_guiprefs::write deken_keep_package "${::deken::keep_package}" + ::pd_guiprefs::write deken_verify_sha256 "${::deken::verify_sha256}" + } + set ::deken::search::dekenserver::use_url_primary [::deken::utilities::bool [pd_guiprefs::read dekensearch_useprimaryurl] 1] + set ::deken::search::dekenserver::use_urls_secondary [::deken::utilities::bool [pd_guiprefs::read dekensearch_usesecondaryurls] 0] + set ::deken::search::dekenserver::urls_secondary [pd_guiprefs::read dekensearch_secondaryurls] + set ::deken::search::dekenserver::use_urls_ephemeral [::deken::utilities::bool [pd_guiprefs::read dekensearch_useephemeralurls] 0] + set ::deken::search::dekenserver::urls_ephemeral [pd_guiprefs::read dekensearch_ephemeralurls] + + proc ::deken::set_search_urls {use_primary use_secondaries secondaries use_ephemerals ephemerals} { + set ::deken::search::dekenserver::use_url_primary [::deken::utilities::bool ${use_primary}] + + set ::deken::search::dekenserver::use_urls_secondary [::deken::utilities::bool ${use_secondaries}] + set ::deken::search::dekenserver::urls_secondary ${secondaries} + + set ::deken::search::dekenserver::use_urls_ephemeral [::deken::utilities::bool ${use_ephemerals}] + set ::deken::search::dekenserver::urls_ephemeral ${ephemerals} + + ::pd_guiprefs::write dekensearch_useprimaryurl "${::deken::search::dekenserver::use_url_primary}" + ::pd_guiprefs::write dekensearch_usesecondaryurls "${::deken::search::dekenserver::use_urls_secondary}" + ::pd_guiprefs::write dekensearch_secondaryurls "${::deken::search::dekenserver::urls_secondary}" + ::pd_guiprefs::write dekensearch_useephemeralurls "${::deken::search::dekenserver::use_urls_ephemeral}" + ::pd_guiprefs::write dekensearch_ephemeralurls "${::deken::search::dekenserver::urls_ephemeral}" } } @@ -1192,7 +1578,7 @@ proc ::deken::normalize_result {title {timestamp ""} args} { ## normalize a search-result - # the function parameters are guaranteed to be a stable API (with the exception or args) + # the function parameters are guaranteed to be a stable API (with the exception of ) # but the value returned by this function is an implementation detail # the primary line displayed for the search-result # - <cmd> the full command to run to install the library @@ -1205,7 +1591,7 @@ proc ::deken::normalize_result {title # - <timestamp> the upload date of the package # - <args> RESERVED FOR FUTURE USE (this is a variadic placeholder. do not use!) - list "" $title $cmd $match $subtitle $statusline $contextcmd $pkgname $version $uploader $timestamp + return [list "" ${title} ${cmd} ${match} ${subtitle} ${statusline} ${contextcmd} ${pkgname} ${version} ${uploader} ${timestamp}] } @@ -1213,26 +1599,26 @@ proc ::deken::normalize_result {title # returns an empty string if nothing was found proc ::deken::find_installpath {{ignoreprefs false}} { set installpath "" - if { [ info exists ::deken::installpath ] && !$ignoreprefs } { + if { [ info exists ::deken::installpath ] && !${ignoreprefs} } { ## any previous choice? - return $::deken::installpath + return ${::deken::installpath} } - if { "$installpath" == "" } { + if { "${installpath}" == "" } { ## search the default paths - set installpath [ ::deken::utilities::get_writabledir $::sys_staticpath ] + set installpath [ ::deken::utilities::get_writabledir ${::sys_staticpath} ] } - if { "$installpath" == "" } { - # let's use the first of $::sys_staticpath, if it does not exist yet - set userdir [lindex $::sys_staticpath 0] + if { "${installpath}" == "" } { + # let's use the first of ${::sys_staticpath}, if it does not exist yet + set userdir [lindex ${::sys_staticpath} 0] if { ! [file exists ${userdir} ] } { - set installpath $userdir + set installpath ${userdir} } } - return $installpath + return ${installpath} } proc ::deken::platform2string {{verbose 0}} { - if { $verbose } { + if { ${verbose} } { return $::deken::platform(os)-$::deken::platform(machine)-float$::deken::platform(floatsize) } else { return $::deken::platform(os)-$::deken::platform(machine)-$::deken::platform(floatsize) @@ -1241,12 +1627,13 @@ proc ::deken::platform2string {{verbose 0}} { # allow overriding deken platform from Pd-core proc ::deken::set_platform {os machine bits floatsize} { - set bits [expr int($bits)] - set floatsize [expr int($floatsize)] - if { $os != $::deken::platform(os) || - $machine != $::deken::platform(machine) || - $bits != $::deken::platform(bits) || - $floatsize != $::deken::platform(floatsize) + set machine [string tolower ${machine}] + set bits [::deken::utilities::int ${bits} $::deken::platform(bits)] + set floatsize [::deken::utilities::int ${floatsize} $::deken::platform(floatsize)] + if { ${os} != $::deken::platform(os) || + ${machine} != $::deken::platform(machine) || + ${bits} != $::deken::platform(bits) || + ${floatsize} != $::deken::platform(floatsize) } { set ::deken::platform(os) ${os} set ::deken::platform(machine) ${machine} @@ -1269,27 +1656,27 @@ proc ::deken::versioncompare {a b} { # sidenote: in practice the version we get here are of the form "<date>/<library>/<version>/<date>" # we probably should only use this version-comparision for the <version> part, # and use 'string compare' for the other parts - foreach x [regexp -all -inline {\d+|\D+} [string map {~ \t} $a]] y [regexp -all -inline {\d+|\D+} [string map {~ \t} $b]] { - if { "$x" == "" } { set x " " } - if { "$y" == "" } { set y " " } + foreach x [regexp -all -inline {\d+|\D+} [string map {~ \t} ${a}]] y [regexp -all -inline {\d+|\D+} [string map {~ \t} ${b}]] { + if { "${x}" == "" } { set x " " } + if { "${y}" == "" } { set y " " } if { [catch { - set c [dict get {1 0 {0 1} -1 {1 0} 1} [lsort -indices -dictionary -unique [list $x $y]]] + set c [dict get {1 0 {0 1} -1 {1 0} 1} [lsort -indices -dictionary -unique [list ${x} ${y}]]] } stdout ] } { # Tcl<8.5 (as found the PowerPC builds) lacks 'dict' and 'lsort -indices' if { [catch { # "string compare" does not sort numerically - set c [expr 2 * ($x > $y) + ($x == $y) - 1] + set c [expr {2 * (${x} > ${y}) + (${x} == ${y}) - 1}] } stdout] } { - set c [string compare $x $y] + set c [string compare ${x} ${y}] } } - if { $c != "0" } {return $c} + if { ${c} != "0" } {return ${c}} } return 0 } proc ::deken::verify_sha256_gui {url pkgfile} { - ## verify that the SHA256 of the $pkgfile matches that from $url + ## verify that the SHA256 of the ${pkgfile} matches that from ${url} ## in case of failure, this displays a dialog asking the user how to proceed ## (if the preferences indicate we require checking) ## returns @@ -1304,24 +1691,24 @@ proc ::deken::verify_sha256_gui {url pkgfile} { ## - -20 an exception occurred while verifying ## - three digits: ## - -100 no sha256 verifier implemented - set err_msg [format [_ "SHA256 verification of '%s' failed!" ] $pkgfile ] + set err_msg [format [_ "SHA256 verification of '%s' failed!" ] ${pkgfile} ] set err_title [_ "SHA256 verification failed" ] - set err_status [format [_ "Checksum mismatch for '%s'" ] $url] + set err_status [format [_ "Checksum mismatch for '%s'" ] ${url}] while 1 { set hash_ok [::deken::utilities::verify_sha256 ${url} ${pkgfile}] if { ${hash_ok} } { return ${hash_ok} } - ::deken::statuspost $err_status warn 0 - if { ! $::deken::verify_sha256 } { + ::deken::statuspost ${err_status} warn 0 + if { ! ${::deken::verify_sha256} } { return -1 } set result [tk_messageBox \ -title ${err_title} \ -message ${err_msg} \ -icon error -type abortretryignore \ - -parent $::deken::winid] + -parent ${::deken::winid}] switch -- ${result} { abort { return 0 @@ -1340,7 +1727,7 @@ proc ::deken::install_package_from_file {{pkgfile ""}} { lappend types [list [_ "ZIP Files" ] .zip] if {$::tcl_platform(platform) ne "windows"} { lappend types [list [_ "TAR Files" ] {.tgz} ] - if {$::windowingsystem eq "aqua"} { + if {${::windowingsystem} eq "aqua"} { # stupid bug on macOS>=12: an extension with two dots crashes the fileselector lappend types [list [_ "TAR Files" ] {.gz} ] } else { @@ -1349,23 +1736,23 @@ proc ::deken::install_package_from_file {{pkgfile ""}} { } lappend types [list [_ "All Files" ] * ] if { "${pkgfile}" eq ""} { - set pkgfile [tk_getOpenFile -defaultextension dek -filetypes $types] + set pkgfile [tk_getOpenFile -defaultextension dek -filetypes ${types}] } if { "${pkgfile}" eq "" } { return } # user picked one # perform checks and install it - set pkgfile [file normalize $pkgfile] + set pkgfile [file normalize ${pkgfile}] set result [::deken::verify_sha256_gui ${pkgfile} ${pkgfile}] - if { ! $result } { + if { ! ${result} } { return } ::deken::install_package ${pkgfile} "" "" 1 } proc ::deken::install_package {fullpkgfile {filename ""} {installdir ""} {keep 1}} { # fullpkgfile: the file to extract - # filename : the package file name (usually the basename of $fullpkgfile) + # filename : the package file name (usually the basename of ${fullpkgfile}) # but might be different depending on the download) # installdir : where to put stuff into # keep : whether to remove the fullpkgfile after successful extraction @@ -1373,65 +1760,94 @@ proc ::deken::install_package {fullpkgfile {filename ""} {installdir ""} {keep 1 set filename [file tail ${fullpkgfile}] } set installdir [::deken::ensure_installdir ${installdir} ${filename}] - set parsedname [::deken::utilities::parse_filename $filename] - set extname [lindex $parsedname 0] - set extpath [file join $installdir $extname] + set parsedname [::deken::utilities::parse_filename ${filename}] + foreach {extname version archs} ${parsedname} {break} + set showextname ${extname} + set deldir "" + set extpath [file join ${installdir} ${extname}] + if { ${extname} eq {} } { + # cannot remove previous installation, as we couldn't guess the library name + set showextname ${filename} + } else { + set match [::deken::architecture_match "${archs}" ] + if { ! ${match} } { + set msg [_ "Installing incompatible architecture of '%s'." ${showextname} ] + ::deken::post "${msg}" warn + if { "${::deken::remove_on_install}" && [file exists ${extpath}] } { + set result [tk_messageBox \ + -title [_ "Replacing library with incompatible architecture!" ] \ + -message [_ "Do you want to replace the library '%1\$s' in '%2\$s' with a version that is incompatible with your computer?" ${showextname} ${installdir}] \ + -icon error -type yesnocancel \ + -parent ${::deken::winid}] + switch -- "${result}" { + cancel {return} + yes { } + no { + set installdir [::deken::do_prompt_installdir ${installdir}] + if { "${installdir}" == "" } { + return + } + set extpath [file join ${installdir} ${extname}] + } + } + } + } - set deldir "" - if { "$::deken::remove_on_install" } { - ::deken::statuspost [format [_ "Uninstalling previous installation of '%s'" ] $extname ] info - - if { ! [::deken::utilities::uninstall $installdir $extname] } { - # ouch uninstalling failed. - # on msw, lets assume this is because some of the files in the folder are locked. - # so move the folder out of the way and proceed - set deldir [::deken::utilities::get_tmpfilename $installdir] - if { [ catch { - file mkdir $deldir - file rename [file join ${installdir} ${extname}] [file join ${deldir} ${extname}] - } ] } { - ::deken::utilities::debug [format [_ "Temporarily moving %1\$s into %2\$s failed." ] $extname $deldir ] - set deldir "" + if { "${::deken::remove_on_install}" } { + ::deken::statuspost [format [_ "Uninstalling previous installation of '%s'" ] ${showextname} ] info + + if { ! [::deken::utilities::uninstall ${installdir} ${extname}] } { + # ouch uninstalling failed. + # on msw, lets assume this is because some of the files in the folder are locked. + # so move the folder out of the way and proceed + set deldir [::deken::utilities::get_tmpfilename ${installdir}] + if { [ catch { + file mkdir ${deldir} + file rename [file join ${installdir} ${extname}] [file join ${deldir} ${extname}] + } ] } { + ::deken::utilities::debug [format [_ "Temporarily moving %1\$s into %2\$s failed." ] ${showextname} ${deldir} ] + set deldir "" + } } } } - ::deken::statuspost [format [_ "Installing package '%s'" ] $extname ] {} 0 + ::deken::statuspost [format [_ "Installing package '%s'" ] ${showextname} ] {} 0 ::deken::syncgui ::deken::progress 0 - if { [::deken::utilities::extract $installdir $filename $fullpkgfile $keep] > 0 } { + if { [::deken::utilities::extract ${installdir} ${filename} ${fullpkgfile} ${keep}] > 0 } { ::deken::progressstatus [_ "Installation completed!" ] - set msg [format [_ "Successfully installed '%s'!" ] $extname ] + set msg [format [_ "Successfully installed '%s'!" ] ${showextname} ] ::deken::statuspost "${msg}" {} 0 ::deken::post "" - ::pdwindow::post "\[deken\] $msg\n" + ::pdwindow::post "\[deken\] ${msg}\n" set install_failed 0 } else { ::deken::progressstatus [_ "Installation failed!" ] - set msg [format [_ "Failed to install '%s'!" ] $extname ] + set msg [format [_ "Failed to install '%s'!" ] ${showextname} ] ::deken::statuspost ${msg} error 0 tk_messageBox \ -title [_ "Package installation failed" ] \ -message "${msg}" \ -icon error -type ok \ - -parent $::deken::winid + -parent ${::deken::winid} set install_failed 1 } - if { "$deldir" != "" } { + if { "${deldir}" != "" } { # try getting rid of the directory to be deleted # we already tried once (and failed), so this time we iterate over each file - set rmerrors [::deken::utilities::rmrecursive $deldir] + set rmerrors [::deken::utilities::rmrecursive ${deldir}] # and if there are still files around, ask the user to delete them. - if { $rmerrors > 0 } { + if { ${rmerrors} > 0 } { set result [tk_messageBox \ - -message [format [_ "Failed to completely remove %1\$s.\nPlease manually remove the directory %2\$s after quitting Pd." ] $extname $deldir] \ + -message [format [_ "Failed to completely remove %1\$s.\nPlease manually remove the directory %2\$s after quitting Pd." ] ${showextname} ${deldir}] \ -icon warning -type okcancel -default ok \ - -parent $::deken::winid] - switch -- $result { + -parent ${::deken::winid}] + switch -- ${result} { ok { - ::pd_menucommands::menu_openfile $deldir + ::pd_menucommands::menu_openfile ${deldir} } } } @@ -1440,42 +1856,49 @@ proc ::deken::install_package {fullpkgfile {filename ""} {installdir ""} {keep 1 if { ${install_failed} } { return } - if { "$::deken::show_readme" } { + if { ${extname} eq {} } { + # failed to properly parse packagefile, so we do not know the libraryname + # therefore we cannot actually show the readme nor add the path + return + } + + + if { "${::deken::show_readme}" } { foreach ext {pd html pdf txt} { - set r [file join $extpath "README.deken.$ext"] - if {[file exists $r]} { - if { "$ext" == "pd" } { - set directory [file normalize [file dirname $r]] - set basename [file tail $r] - pdsend "pd open [enquote_path $basename] [enquote_path $directory]" + set r [file join ${extpath} "README.deken.${ext}"] + if {[file exists ${r}]} { + if { "${ext}" == "pd" } { + set directory [file normalize [file dirname ${r}]] + set basename [file tail ${r}] + pdsend "pd open [enquote_path ${basename}] [enquote_path ${directory}]" } else { - pd_menucommands::menu_openfile $r + pd_menucommands::menu_openfile ${r} } break } } } - if { "$::deken::add_to_path" } { + if { "${::deken::add_to_path}" } { # add to the search paths? bail if the version of pd doesn't support it if {[uplevel 1 info procs add_to_searchpaths] eq ""} {return} - if {![file exists $extpath]} { - ::deken::utilities::debug [format [_ "Unable to add %s to search paths"] $extname] + if {![file exists ${extpath}]} { + ::deken::utilities::debug [format [_ "Unable to add %s to search paths"] ${extname}] return } set result yes - if { $::deken::add_to_path > 1 } { + if { ${::deken::add_to_path} > 1 } { set result yes } else { set result [tk_messageBox \ - -message [format [_ "Add %s to the Pd search paths?" ] $extname] \ + -message [format [_ "Add %s to the Pd search paths?" ] ${extname}] \ -icon question -type yesno -default yes \ - -parent $::deken::winid] + -parent ${::deken::winid}] } switch -- "${result}" { yes { - add_to_searchpaths [file join $installdir $extname] - ::deken::utilities::debug [format [_ "Added %s to search paths"] $extname] + add_to_searchpaths [file join ${installdir} ${extname}] + ::deken::utilities::debug [format [_ "Added %s to search paths"] ${extname}] # if this version of pd supports it, try refreshing the helpbrowser if {[uplevel 1 info procs ::helpbrowser::refresh] ne ""} { ::helpbrowser::refresh @@ -1490,27 +1913,30 @@ proc ::deken::install_package {fullpkgfile {filename ""} {installdir ""} {keep 1 ##### GUI ######## proc ::deken::bind_globalshortcuts {toplevel} { - set closescript "destroy $toplevel" - bind $toplevel <$::modifier-Key-w> $closescript + # this should probably only be called if toplevel is indeed a toplevel + if { ${toplevel} eq [winfo toplevel ${toplevel}] } { + bind ${toplevel} <${::modifier}-Key-w> [list destroy ${toplevel}] + bind ${toplevel} <Escape> [list after idle [list destroy ${toplevel}]] + } } proc ::deken::status {{msg ""} {timeout 5000}} { - after cancel $::deken::statustimer - if {"" ne $msg} { - set ::deken::statustext "$msg" - if { $timeout != "0" } { - set ::deken::statustimer [after $timeout [list set "::deken::statustext" ""]] + after cancel ${::deken::statustimer} + if {"" ne ${msg}} { + set ::deken::statustext "${msg}" + if { ${timeout} != "0" } { + set ::deken::statustimer [after ${timeout} [list set "::deken::statustext" ""]] } } else { set ::deken::statustext "" } } proc ::deken::progressstatus {{msg ""} {timeout 5000}} { - after cancel $::deken::progresstimer - if {"" ne $msg} { - set ::deken::progresstext "$msg" - if { $timeout != "0" } { - set ::deken::progresstimer [after $timeout [list set "::deken::progresstext" ""]] + after cancel ${::deken::progresstimer} + if {"" ne ${msg}} { + set ::deken::progresstext "${msg}" + if { ${timeout} != "0" } { + set ::deken::progresstimer [after ${timeout} [list set "::deken::progresstext" ""]] } } else { set ::deken::progresstext "" @@ -1521,108 +1947,108 @@ proc ::deken::syncgui {} { } proc ::deken::scrollup {} { variable infoid - if { [winfo exists $infoid] } { - $infoid see 0.0 + if { [winfo exists ${infoid}] } { + ${infoid} see 0.0 } } proc ::deken::post {msg args} { variable infoid - if { [winfo exists $infoid] } { - $infoid insert end "$msg\n" $args - $infoid see end + if { [winfo exists ${infoid}] } { + ${infoid} insert end "${msg}\n" ${args} + ${infoid} see end } } proc ::deken::statuspost {msg {tag info} {timeout 5000}} { - post $msg $tag - status $msg $timeout + post ${msg} ${tag} + status ${msg} ${timeout} } proc ::deken::clearpost {} { variable infoid - if { [winfo exists $infoid] } { - $infoid delete 1.0 end + if { [winfo exists ${infoid}] } { + ${infoid} delete 1.0 end } set ::deken::selected {} } proc ::deken::post_result {msg {tag ""}} { variable resultsid - if { [winfo exists $resultsid] } { - $resultsid insert end "$msg\n" $tag - $resultsid see end + if { [winfo exists ${resultsid}] } { + ${resultsid} insert end "${msg}\n" ${tag} + ${resultsid} see end } } proc ::deken::bind_resulttag {tagname key cmd} { variable resultsid - if { [winfo exists $resultsid] } { - $resultsid tag bind $tagname $key $cmd + if { [winfo exists ${resultsid}] } { + ${resultsid} tag bind ${tagname} ${key} ${cmd} } } proc ::deken::highlightable_resulttag {tagname} { variable resultsid - if { [winfo exists $resultsid] } { - ::deken::bind_resulttag $tagname <Enter> \ - "$resultsid tag add highlight [ $resultsid tag ranges $tagname ]" - ::deken::bind_resulttag $tagname <Leave> \ - "$resultsid tag remove highlight [ $resultsid tag ranges $tagname ]" + if { [winfo exists ${resultsid}] } { + ::deken::bind_resulttag ${tagname} <Enter> \ + "${resultsid} tag add highlight [ ${resultsid} tag ranges ${tagname} ]" + ::deken::bind_resulttag ${tagname} <Leave> \ + "${resultsid} tag remove highlight [ ${resultsid} tag ranges ${tagname} ]" # make sure that the 'highlight' tag is topmost - $resultsid tag raise sel - $resultsid tag raise highlight + ${resultsid} tag raise sel + ${resultsid} tag raise highlight } } proc ::deken::bind_contextmenu {resultsid tagname cmd} { - if { [winfo exists $resultsid] } { - if {$::windowingsystem eq "aqua"} { - $resultsid tag bind $tagname <2> $cmd + if { [winfo exists ${resultsid}] } { + if {${::windowingsystem} eq "aqua"} { + ${resultsid} tag bind ${tagname} <2> ${cmd} } else { - $resultsid tag bind $tagname <3> $cmd + ${resultsid} tag bind ${tagname} <3> ${cmd} } } } proc ::deken::menu_installselected {resultsid} { set counter 0 - foreach {k v} $::deken::selected { - if { $v ne {} } { - eval $v + foreach {k v} ${::deken::selected} { + if { ${v} ne {} } { + eval ${v} incr counter } } - if { $counter == 0 } { + if { ${counter} == 0 } { ::deken::statuspost [_ "No packages selected for installation."] - } elseif { $counter > 1 } { - ::deken::statuspost [format [_ "Processed %d packages selected for installation."] $counter ] + } elseif { ${counter} > 1 } { + ::deken::statuspost [format [_ "Processed %d packages selected for installation."] ${counter} ] } # clear the selection set ::deken::selected {} - ::deken::clear_selection $resultsid - ::deken::update_installbutton $::deken::winid + ::deken::clear_selection ${resultsid} + ::deken::update_installbutton ${::deken::winid} } proc ::deken::menu_uninstall_package {winid pkgname installpath} { - ::deken::show_tab $winid info - ::deken::statuspost [format [_ "Uninstalling previous installation of '%s'" ] $pkgname ] info - ::deken::utilities::uninstall $installpath $pkgname + ::deken::show_tab ${winid} info + ::deken::statuspost [format [_ "Uninstalling previous installation of '%s'" ] ${pkgname} ] info + ::deken::utilities::uninstall ${installpath} ${pkgname} } proc ::deken::do_prompt_installdir {path {winid {}}} { set msg [_ "Install externals to directory:"] - if { $winid eq {} } { - set winid $::deken::winid + if { ${winid} eq {} } { + set winid ${::deken::winid} } - if {[winfo exists $winid]} { - tk_chooseDirectory -title "${msg}" -initialdir ${path} -parent $winid + if {[winfo exists ${winid}]} { + tk_chooseDirectory -title "${msg}" -initialdir ${path} -parent ${winid} } else { tk_chooseDirectory -title "${msg}" -initialdir ${path} } } proc ::deken::prompt_installdir {} { - set installdir [::deken::do_prompt_installdir $::fileopendir] - if { "$installdir" != "" } { - ::deken::set_installpath $installdir + set installdir [::deken::do_prompt_installdir ${::fileopendir}] + if { "${installdir}" != "" } { + ::deken::set_installpath ${installdir} return 1 } return 0 @@ -1630,26 +2056,26 @@ proc ::deken::prompt_installdir {} { proc ::deken::update_searchbutton {winid} { - if { [$winid.searchbit.entry get] == "" } { - $winid.searchbit.button configure -text [_ "Show all" ] + if { [${winid}.searchbit.entry get] == "" } { + ${winid}.searchbit.button configure -text [_ "Show all" ] } else { - $winid.searchbit.button configure -text [_ "Search" ] + ${winid}.searchbit.button configure -text [_ "Search" ] } } proc ::deken::update_installbutton {winid} { set installbutton ${winid}.status.install - if { ! [winfo exists $installbutton] } { return } + if { ! [winfo exists ${installbutton}] } { return } set counter 0 - foreach {a b} $::deken::selected { - if {$b ne {} } { + foreach {a b} ${::deken::selected} { + if {${b} ne {} } { incr counter } } - if { $counter > 0 } { - $installbutton configure -state normal -text [format [_ "Install (%d)" ] $counter] + if { ${counter} > 0 } { + ${installbutton} configure -state normal -text [format [_ "Install (%d)" ] ${counter}] } else { - $installbutton configure -state disabled -text [_ "Install" ] + ${installbutton} configure -state disabled -text [_ "Install" ] } } @@ -1659,30 +2085,30 @@ proc ::deken::progress {x} { # this function gets called when the menu is clicked proc ::deken::open_searchui {winid} { - if {[winfo exists $winid]} { - wm deiconify $winid - raise $winid + if {[winfo exists ${winid}]} { + wm deiconify ${winid} + raise ${winid} } else { variable resultsid variable infoid - ::deken::create_dialog $winid - ::deken::bind_globalshortcuts $winid - foreach dndid [list $winid.tab $winid.results] { - if { [winfo exists $dndid] } { - ::deken::utilities::dnd_init $dndid + ::deken::create_dialog ${winid} + ::deken::bind_globalshortcuts ${winid} + foreach dndid [list ${winid}.tab ${winid}.results] { + if { [winfo exists ${dndid}] } { + ::deken::utilities::dnd_init ${dndid} } } - $infoid tag configure error -foreground red - $infoid tag configure warn -foreground orange - $infoid tag configure info -foreground black - $infoid tag configure debug -foreground grey - $infoid tag configure dekenurl -foreground blue - $infoid tag bind dekenurl <1> "pd_menucommands::menu_openfile https://deken.puredata.info/" - $infoid tag bind dekenurl <Enter> "$infoid tag configure dekenurl -underline 1" - $infoid tag bind dekenurl <Leave> "$infoid tag configure dekenurl -underline 0" - $resultsid tag configure highlight -foreground blue - $resultsid tag configure archmatch - $resultsid tag configure noarchmatch -foreground grey + ${infoid} tag configure error -foreground red + ${infoid} tag configure warn -foreground orange + ${infoid} tag configure info -foreground black + ${infoid} tag configure debug -foreground grey + ${infoid} tag configure dekenurl -foreground blue + ${infoid} tag bind dekenurl <1> "pd_menucommands::menu_openfile https://deken.puredata.info/" + ${infoid} tag bind dekenurl <Enter> "${infoid} tag configure dekenurl -underline 1" + ${infoid} tag bind dekenurl <Leave> "${infoid} tag configure dekenurl -underline 0" + ${resultsid} tag configure highlight -foreground blue + ${resultsid} tag configure archmatch + ${resultsid} tag configure noarchmatch -foreground grey } ::deken::clearpost ::deken::post [_ "Enter an exact library or object name."] info @@ -1703,59 +2129,59 @@ proc ::deken::open_searchui {winid} { # build the externals search dialog window proc ::deken::create_dialog {winid} { variable resultsid - toplevel $winid -class DialogWindow - set ::deken::winid $winid + toplevel ${winid} -class DialogWindow + set ::deken::winid ${winid} set title [_ "Find externals"] - wm title $winid "deken - $title" - wm geometry $winid 670x550 - wm minsize $winid 230 360 - wm transient $winid - $winid configure -padx 10 -pady 5 + wm title ${winid} "deken - ${title}" + wm geometry ${winid} 670x550 + wm minsize ${winid} 230 360 + wm transient ${winid} + ${winid} configure -padx 10 -pady 5 set m ${winid}_menu - destroy $m - menu $m - menu $m.file - $m add cascade -label [_ [string totitle "file"]] -underline 0 -menu $m.file - $m.file add command -label [_ "Install DEK file..." ] -command "::deken::install_package_from_file" - menu $m.edit - $m add cascade -label [_ [string totitle "edit"]] -underline 0 -menu $m.edit - $m.edit add command -label [_ "Preferences..." ] -command "::deken::preferences::show" - - $winid configure -menu $m - - frame $winid.searchbit - pack $winid.searchbit -side top -fill "x" - - entry $winid.searchbit.entry -font 18 -relief sunken -highlightthickness 1 -highlightcolor blue - pack $winid.searchbit.entry -side left -padx 6 -fill "x" -expand true - bind $winid.searchbit.entry <Key-Return> "::deken::initiate_search $winid" - bind $winid.searchbit.entry <KeyRelease> "::deken::update_searchbutton $winid" - focus $winid.searchbit.entry - button $winid.searchbit.button -text [_ "Show all"] -default active -command "::deken::initiate_search $winid" - pack $winid.searchbit.button -side right -padx 6 -pady 3 -ipadx 10 - - frame $winid.objlib - pack $winid.objlib -side top -fill "x" - label $winid.objlib.label -text [_ "Search for: "] - radiobutton $winid.objlib.libraries -text [_ "libraries"] -variable ::deken::searchtype -value libraries - radiobutton $winid.objlib.objects -text [_ "objects"] -variable ::deken::searchtype -value objects - radiobutton $winid.objlib.both -text [_ "both"] -variable ::deken::searchtype -value name + destroy ${m} + menu ${m} + menu ${m}.file + ${m} add cascade -label [_ [string totitle "file"]] -underline 0 -menu ${m}.file + ${m}.file add command -label [_ "Install DEK file..." ] -command "::deken::install_package_from_file" + menu ${m}.edit + ${m} add cascade -label [_ [string totitle "edit"]] -underline 0 -menu ${m}.edit + ${m}.edit add command -label [_ "Preferences..." ] -command "::deken::preferences::show" + + ${winid} configure -menu ${m} + + frame ${winid}.searchbit + pack ${winid}.searchbit -side top -fill "x" + + entry ${winid}.searchbit.entry -font 18 -relief sunken -highlightthickness 1 -highlightcolor blue + pack ${winid}.searchbit.entry -side left -padx 6 -fill "x" -expand true + bind ${winid}.searchbit.entry <Key-Return> "::deken::initiate_search ${winid}" + bind ${winid}.searchbit.entry <KeyRelease> "::deken::update_searchbutton ${winid}" + focus ${winid}.searchbit.entry + button ${winid}.searchbit.button -text [_ "Show all"] -default active -command "::deken::initiate_search ${winid}" + pack ${winid}.searchbit.button -side right -padx 6 -pady 3 -ipadx 10 + + frame ${winid}.objlib + pack ${winid}.objlib -side top -fill "x" + label ${winid}.objlib.label -text [_ "Search for: "] + radiobutton ${winid}.objlib.libraries -text [_ "libraries"] -variable ::deken::searchtype -value libraries + radiobutton ${winid}.objlib.objects -text [_ "objects"] -variable ::deken::searchtype -value objects + radiobutton ${winid}.objlib.both -text [_ "both"] -variable ::deken::searchtype -value name foreach x {label libraries objects both} { - pack $winid.objlib.$x -side left -padx 6 + pack ${winid}.objlib.${x} -side left -padx 6 } # for Pd that supports it, add a 'translation' radio if {[uplevel 2 info procs add_to_helppaths] ne ""} { - radiobutton $winid.objlib.translations -text [_ "translations"] -variable ::deken::searchtype -value translations - pack $winid.objlib.translations -side left -padx 6 + radiobutton ${winid}.objlib.translations -text [_ "translations"] -variable ::deken::searchtype -value translations + pack ${winid}.objlib.translations -side left -padx 6 } - frame $winid.warning - pack $winid.warning -side top -fill "x" - label $winid.warning.label -text [_ "Only install externals uploaded by people you trust."] - pack $winid.warning.label -side left -padx 6 + frame ${winid}.warning + pack ${winid}.warning -side top -fill "x" + label ${winid}.warning.label -text [_ "Only install externals uploaded by people you trust."] + pack ${winid}.warning.label -side left -padx 6 if { [catch { - if {$::windowingsystem eq "aqua" + if {${::windowingsystem} eq "aqua" && [::deken::versioncompare 8.6 [info patchlevel]] < 0 && [::deken::versioncompare 8.6.12 [info patchlevel]] > 0 } { @@ -1763,85 +2189,85 @@ proc ::deken::create_dialog {winid} { error [_ "Disabling tabbed view: incompatible Tcl/Tk detected"] } - ttk::notebook $winid.tab - pack $winid.tab -side top -padx 6 -pady 3 -fill both -expand true + ttk::notebook ${winid}.tab + pack ${winid}.tab -side top -padx 6 -pady 3 -fill both -expand true - text $winid.tab.info -takefocus 0 -cursor hand2 -height 100 -yscrollcommand "$winid.tab.info.ys set" - scrollbar $winid.tab.info.ys -orient vertical -command "$winid.tab.info yview" - pack $winid.tab.info.ys -side right -fill "y" + text ${winid}.tab.info -takefocus 0 -cursor hand2 -height 100 -yscrollcommand "${winid}.tab.info.ys set" + scrollbar ${winid}.tab.info.ys -orient vertical -command "${winid}.tab.info yview" + pack ${winid}.tab.info.ys -side right -fill "y" if { [catch { - set treeid $winid.tab.results - ttk::treeview $treeid \ + set treeid ${winid}.tab.results + ttk::treeview ${treeid} \ -height 10 \ -selectmode browse \ -columns {version title uploader date} \ -displaycolumns {version uploader date} \ - -yscrollcommand "$winid.tab.results.ys set" - $treeid heading #0 -text [_ "Library" ] -anchor center -command "::deken::treeresults::columnsort $treeid" - $treeid heading version -text [_ "Version" ] -anchor center -command "::deken::treeresults::columnsort $treeid version" - $treeid heading title -text [_ "Description" ] -anchor center -command "::deken::treeresults::columnsort $treeid title" - $treeid heading uploader -text [_ "Uploader" ] -anchor center -command "::deken::treeresults::columnsort $treeid uploader" - $treeid heading date -text [_ "Date" ] -anchor center -command "::deken::treeresults::columnsort $treeid date" - $treeid column #0 -stretch 0 - $treeid tag configure library -background lightgrey - $treeid tag configure noarchmatch -foreground lightgrey - $treeid tag configure selpkg -background lightblue - - bind $treeid <<TreeviewSelect>> "::deken::treeresults::selection_changed %W" - bind $treeid <<TreeviewOpen>> "::deken::treeresults::selection_skip %W 1" - bind $treeid <<TreeviewClose>> "::deken::treeresults::selection_skip %W 1" - bind $treeid <Motion> "::deken::treeresults::motionevent %W %x %y" - bind $treeid <Leave> "::deken::treeresults::leaveevent %W" - bind $treeid <Double-ButtonRelease-1> "::deken::treeresults::doubleclick %W %x %y" - - proc ::deken::show_results {resultsid} { ::deken::treeresults::show $resultsid} - proc ::deken::clear_results {resultsid} { ::deken::treeresults::clear $resultsid} - proc ::deken::clear_selection {resultsid} { ::deken::treeresults::clear_selection $resultsid } - - scrollbar $winid.tab.results.ys -orient vertical -command "$winid.tab.results yview" - pack $winid.tab.results.ys -side right -fill "y" + -yscrollcommand "${winid}.tab.results.ys set" + ${treeid} heading #0 -text [_ "Library" ] -anchor center -command "::deken::treeresults::columnsort ${treeid}" + ${treeid} heading version -text [_ "Version" ] -anchor center -command "::deken::treeresults::columnsort ${treeid} version" + ${treeid} heading title -text [_ "Description" ] -anchor center -command "::deken::treeresults::columnsort ${treeid} title" + ${treeid} heading uploader -text [_ "Uploader" ] -anchor center -command "::deken::treeresults::columnsort ${treeid} uploader" + ${treeid} heading date -text [_ "Date" ] -anchor center -command "::deken::treeresults::columnsort ${treeid} date" + ${treeid} column #0 -stretch 0 + ${treeid} tag configure library -background lightgrey + ${treeid} tag configure noarchmatch -foreground lightgrey + ${treeid} tag configure selpkg -background lightblue + + bind ${treeid} <<TreeviewSelect>> "::deken::treeresults::selection_changed %W" + bind ${treeid} <<TreeviewOpen>> "::deken::treeresults::selection_skip %W 1" + bind ${treeid} <<TreeviewClose>> "::deken::treeresults::selection_skip %W 1" + bind ${treeid} <Motion> "::deken::treeresults::motionevent %W %x %y" + bind ${treeid} <Leave> "::deken::treeresults::leaveevent %W" + bind ${treeid} <Double-ButtonRelease-1> "::deken::treeresults::doubleclick %W %x %y" + + proc ::deken::show_results {resultsid} { ::deken::treeresults::show ${resultsid}} + proc ::deken::clear_results {resultsid} { ::deken::treeresults::clear ${resultsid}} + proc ::deken::clear_selection {resultsid} { ::deken::treeresults::clear_selection ${resultsid} } + + scrollbar ${winid}.tab.results.ys -orient vertical -command "${winid}.tab.results yview" + pack ${winid}.tab.results.ys -side right -fill "y" } ] } { - text $winid.tab.results -takefocus 0 -cursor hand2 -height 100 -yscrollcommand "$winid.tab.results.ys set" - scrollbar $winid.tab.results.ys -orient vertical -command "$winid.tab.results yview" - pack $winid.tab.results.ys -side right -fill "y" + text ${winid}.tab.results -takefocus 0 -cursor hand2 -height 100 -yscrollcommand "${winid}.tab.results.ys set" + scrollbar ${winid}.tab.results.ys -orient vertical -command "${winid}.tab.results yview" + pack ${winid}.tab.results.ys -side right -fill "y" } - $winid.tab add $winid.tab.results -text [_ "Search Results"] - $winid.tab add $winid.tab.info -text [_ "Log"] - ::deken::show_tab $winid info + ${winid}.tab add ${winid}.tab.results -text [_ "Search Results"] + ${winid}.tab add ${winid}.tab.info -text [_ "Log"] + ::deken::show_tab ${winid} info variable infoid - set resultsid $winid.tab.results - set infoid $winid.tab.info + set resultsid ${winid}.tab.results + set infoid ${winid}.tab.info } ] } { - text $winid.results -takefocus 0 -cursor hand2 -height 100 -yscrollcommand "$winid.results.ys set" - scrollbar $winid.results.ys -orient vertical -command "$winid.results yview" - pack $winid.results.ys -side right -fill "y" - pack $winid.results -side top -padx 6 -pady 3 -fill both -expand true + text ${winid}.results -takefocus 0 -cursor hand2 -height 100 -yscrollcommand "${winid}.results.ys set" + scrollbar ${winid}.results.ys -orient vertical -command "${winid}.results yview" + pack ${winid}.results.ys -side right -fill "y" + pack ${winid}.results -side top -padx 6 -pady 3 -fill both -expand true } - frame $winid.progress - pack $winid.progress -side top -fill "x" + frame ${winid}.progress + pack ${winid}.progress -side top -fill "x" if { ! [ catch { - ttk::progressbar $winid.progress.bar -orient horizontal -length 640 -maximum 100 -mode determinate -variable ::deken::progressvar } stdout ] } { - pack $winid.progress.bar -side top -fill "x" - proc ::deken::progress {x} { set ::deken::progressvar $x } + ttk::progressbar ${winid}.progress.bar -orient horizontal -length 640 -maximum 100 -mode determinate -variable ::deken::progressvar } stdout ] } { + pack ${winid}.progress.bar -side top -fill "x" + proc ::deken::progress {x} { set ::deken::progressvar ${x} } label ${winid}.progress.label -textvariable ::deken::progresstext -padx 0 -borderwidth 0 place ${winid}.progress.label -in ${winid}.progress.bar -x 1 } - frame $winid.status - pack $winid.status -side bottom -fill "x" -pady 3 - label $winid.status.label -textvariable ::deken::statustext -relief sunken -anchor "w" - pack $winid.status.label -side bottom -fill "x" + frame ${winid}.status + pack ${winid}.status -side bottom -fill "x" -pady 3 + label ${winid}.status.label -textvariable ::deken::statustext -relief sunken -anchor "w" + pack ${winid}.status.label -side bottom -fill "x" - button $winid.status.install -text [_ "Install" ] \ + button ${winid}.status.install -text [_ "Install" ] \ -state disabled \ - -command "::deken::menu_installselected $resultsid" + -command "::deken::menu_installselected ${resultsid}" - pack $winid.status.install -side right -padx 6 -pady 3 -ipadx 10 + pack ${winid}.status.install -side right -padx 6 -pady 3 -ipadx 10 } proc ::deken::show_tab {winid tab} { @@ -1851,18 +2277,18 @@ proc ::deken::show_tab {winid tab} { } proc ::deken::open_search_xxx {searchtype xxx} { - set winid $::deken::winid - ::deken::open_searchui $winid + set winid ${::deken::winid} + ::deken::open_searchui ${winid} ::deken::clearpost set searchterm {} - if { $::deken::searchtype eq "${searchtype}" } { - append searchterm [$winid.searchbit.entry get] + if { ${::deken::searchtype} eq "${searchtype}" } { + append searchterm [${winid}.searchbit.entry get] } if { ${searchterm} ne {} } { append searchterm " " } - foreach xx $xxx { - foreach x $xx { - lappend searchterm $x + foreach xx ${xxx} { + foreach x ${xx} { + lappend searchterm ${x} } } @@ -1870,30 +2296,30 @@ proc ::deken::open_search_xxx {searchtype xxx} { ${winid}.searchbit.entry insert end ${searchterm} set ::deken::searchtype "${searchtype}" - ::deken::update_searchbutton $winid + ::deken::update_searchbutton ${winid} } proc ::deken::open_search_objects {args} { - ::deken::open_search_xxx "objects" $args + ::deken::open_search_xxx "objects" ${args} } proc ::deken::open_search_libraries {args} { - ::deken::open_search_xxx "libraries" $args + ::deken::open_search_xxx "libraries" ${args} } proc ::deken::open_search_translations {args} { - ::deken::open_search_xxx "translations" $args + ::deken::open_search_xxx "translations" ${args} } proc ::deken::open_search_missing_libraries {args} { # LATER this should only display not-installed libraries - ::deken::open_search_xxx "libraries" $args + ::deken::open_search_xxx "libraries" ${args} } proc ::deken::initiate_search {winid} { - set searchterm [$winid.searchbit.entry get] + set searchterm [${winid}.searchbit.entry get] # let the user know what we're doing - ::deken::show_tab $winid info + ::deken::show_tab ${winid} info ::deken::clearpost ::deken::statuspost [format [_ "Searching for \"%s\"..." ] ${searchterm} ] @@ -1902,28 +2328,28 @@ proc ::deken::initiate_search {winid} { if { [ catch { set results [::deken::search_for ${searchterm}] } stdout ] } { - ::deken::utilities::debug [format [_ "online? %s" ] $stdout ] + ::deken::utilities::debug [format [_ "online? %s" ] ${stdout} ] ::deken::statuspost [_ "Unable to perform search. Are you online?" ] error } else { # delete all text in the results variable resultsid - ::deken::clear_results $resultsid + ::deken::clear_results ${resultsid} set ::deken::selected {} - set ::deken::results $results + set ::deken::results ${results} set matchcount 0 - foreach r $results { - foreach {_ _ match} $r {break} - if { $match } { + foreach r ${results} { + foreach {_ _ match} ${r} {break} + if { ${match} } { incr matchcount } } - if {[llength $results] != 0} { - ::deken::show_results $resultsid - set msg [format [_ "Found %1\$d usable packages (of %2\$d packages in total)." ] $matchcount [llength $results]] + if {[llength ${results}] != 0} { + ::deken::show_results ${resultsid} + set msg [format [_ "Found %1\$d usable packages (of %2\$d packages in total)." ] ${matchcount} [llength ${results}]] ::deken::statuspost [format {"%s": %s} ${searchterm} ${msg}] - if { $matchcount } { - ::deken::show_tab $winid results + if { ${matchcount} } { + ::deken::show_tab ${winid} results } else { ::deken::post [_ "It appears that there are no matching packages for your architecture." ] warn } @@ -1943,19 +2369,19 @@ namespace eval ::deken::textresults:: { # display a single found entry in a simple text widget proc ::deken::textresults::show_result {resultsid counter result showmatches} { - foreach {title cmd match comment status contextcmd pkgname} $result {break} - set tag ch$counter - set tags [list $tag [expr ${match}?"archmatch":"noarchmatch" ] ] - if { "$pkgname" ne "" } {lappend tags "/$pkgname"} + foreach {title cmd match comment status contextcmd pkgname} ${result} {break} + set tag ch${counter} + set tags [list ${tag} [expr {${match}?"archmatch":"noarchmatch"} ] ] + if { "${pkgname}" ne "" } {lappend tags "/${pkgname}"} - if {($match == $showmatches)} { - set comment [string map {"\n" "\n\t"} $comment] - ::deken::post_result "$title\n\t$comment\n" $tags - ::deken::highlightable_resulttag $tag - ::deken::bind_resulttag $tag <Enter> "+::deken::status {$status}" - ::deken::bind_resulttag $tag <1> "$cmd" - if { "" ne $contextcmd } { - ::deken::bind_contextmenu $resultsid $tag $contextcmd + if {(${match} == ${showmatches})} { + set comment [string map {"\n" "\n\t"} ${comment}] + ::deken::post_result "${title}\n\t${comment}\n" ${tags} + ::deken::highlightable_resulttag ${tag} + ::deken::bind_resulttag ${tag} <Enter> "+::deken::status {${status}}" + ::deken::bind_resulttag ${tag} <1> "${cmd}" + if { "" ne ${contextcmd} } { + ::deken::bind_contextmenu ${resultsid} ${tag} ${contextcmd} } } } @@ -1964,27 +2390,27 @@ proc ::deken::textresults::show_result {resultsid counter result showmatches} { proc ::deken::textresults::show {resultsid} { set counter 0 # build the list UI of results - foreach r $::deken::results { - ::deken::textresults::show_result $resultsid $counter $r 1 + foreach r ${::deken::results} { + ::deken::textresults::show_result ${resultsid} ${counter} ${r} 1 incr counter } if { "${::deken::hideforeignarch}" } { # skip display of non-matching archs } else { set counter 0 - foreach r $::deken::results { - ::deken::textresults::show_result $resultsid $counter $r 0 + foreach r ${::deken::results} { + ::deken::textresults::show_result ${resultsid} ${counter} ${r} 0 incr counter } } - if { [winfo exists $resultsid] } { - $resultsid see 0.0 + if { [winfo exists ${resultsid}] } { + ${resultsid} see 0.0 } } proc ::deken::textresults::clear {resultsid} { - if { [winfo exists $resultsid] } { - $resultsid delete 1.0 end + if { [winfo exists ${resultsid}] } { + ${resultsid} delete 1.0 end } } @@ -1992,14 +2418,14 @@ proc ::deken::textresults::selectpackage {resultsid pkgname installcmd} { # set/unset the selection in a "dict" set state {} set counter 1 - foreach {k v} $::deken::selected { - if { $k eq $pkgname } { - if { $v ne $installcmd } { + foreach {k v} ${::deken::selected} { + if { ${k} eq ${pkgname} } { + if { ${v} ne ${installcmd} } { set state 1 - lset ::deken::selected $counter $installcmd + lset ::deken::selected ${counter} ${installcmd} } else { set state 0 - lset ::deken::selected $counter {} + lset ::deken::selected ${counter} {} } break } @@ -2007,27 +2433,27 @@ proc ::deken::textresults::selectpackage {resultsid pkgname installcmd} { } if { ${state} eq {} } { # not found in the dict; just add it - lappend ::deken::selected $pkgname $installcmd + lappend ::deken::selected ${pkgname} ${installcmd} set state 1 } # set/unset the visual representation (via tags) set counter 0 - foreach {a b} [$resultsid tag ranges /$pkgname] {$resultsid tag remove sel $a $b} - if { $state } { - foreach r $::deken::results { - if { [lindex $r 1] eq ${installcmd} } { - foreach {a b} [$resultsid tag ranges ch$counter] {$resultsid tag add sel $a $b} + foreach {a b} [${resultsid} tag ranges /${pkgname}] {${resultsid} tag remove sel ${a} ${b}} + if { ${state} } { + foreach r ${::deken::results} { + if { [lindex ${r} 1] eq ${installcmd} } { + foreach {a b} [${resultsid} tag ranges ch${counter}] {${resultsid} tag add sel ${a} ${b}} } incr counter } } - ::deken::update_installbutton [winfo toplevel $resultsid] + ::deken::update_installbutton [winfo toplevel ${resultsid}] } proc ::deken::textresults::clear_selection {resultsid} { - if { [winfo exists $resultsid] } { - foreach {a b} [${resultsid} tag ranges sel] {${resultsid} tag remove sel $a $b} + if { [winfo exists ${resultsid}] } { + foreach {a b} [${resultsid} tag ranges sel] {${resultsid} tag remove sel ${a} ${b}} } } @@ -2065,38 +2491,38 @@ array set ::deken::treeresults::activecell {} proc ::deken::treeresults::columnsort {treeid {col "#0"}} { # do we want to sort increasing or decreasing? variable colsort - if {! [info exists colsort($col) ] } { - set colsort($col) 1 + if {! [info exists colsort(${col}) ] } { + set colsort(${col}) 1 } - set colsort($col) [expr ! $colsort($col)] + set colsort(${col}) [expr { ! $colsort(${col}) }] set dir -increasing - if { $colsort($col) } { + if { $colsort(${col}) } { set dir -decreasing } # do the actual sorting - if { $col eq "#0" } { + if { ${col} eq "#0" } { set sortable {} - foreach lib [$treeid children {}] { - lappend sortable [list [$treeid item $lib -text] $lib] + foreach lib [${treeid} children {}] { + lappend sortable [list [${treeid} item ${lib} -text] ${lib}] } set pkgs {} - foreach x [lsort -nocase $dir -index 0 $sortable] { - lappend pkgs [lindex $x 1] + foreach x [lsort -nocase ${dir} -index 0 ${sortable}] { + lappend pkgs [lindex ${x} 1] } - $treeid children {} $pkgs + ${treeid} children {} ${pkgs} } else { - foreach lib [$treeid children {}] { + foreach lib [${treeid} children {}] { set sortable {} - foreach pkg [$treeid children $lib] { - lappend sortable [list [$treeid set $pkg $col] $pkg] + foreach pkg [${treeid} children ${lib}] { + lappend sortable [list [${treeid} set ${pkg} ${col}] ${pkg}] } set pkgs {} - foreach x [lsort -nocase $dir -index 0 -command ::deken::versioncompare $sortable] { - lappend pkgs [lindex $x 1] + foreach x [lsort -nocase ${dir} -index 0 -command ::deken::versioncompare ${sortable}] { + lappend pkgs [lindex ${x} 1] } - $treeid children $lib $pkgs + ${treeid} children ${lib} ${pkgs} } } @@ -2105,224 +2531,224 @@ proc ::deken::treeresults::columnsort {treeid {col "#0"}} { set label_decr "\u2b06" set dirsym "${label_incr}" - if { $dir eq "-decreasing" } { + if { ${dir} eq "-decreasing" } { set dirsym "${label_decr}" } # clear all the increasing/decreasing indicators from the headings - foreach c [$treeid cget -columns] { - $treeid heading $c -text [regsub "(${label_decr}|${label_incr})$" [$treeid heading $c -text] {}] + foreach c [${treeid} cget -columns] { + ${treeid} heading ${c} -text [regsub "(${label_decr}|${label_incr})$" [${treeid} heading ${c} -text] {}] } set c "#0" - $treeid heading $c -text [regsub "(${label_decr}|${label_incr})$" [$treeid heading $c -text] {}] + ${treeid} heading ${c} -text [regsub "(${label_decr}|${label_incr})$" [${treeid} heading ${c} -text] {}] # and finally set the increasing/decreasing indicator for the sorted column - $treeid heading $col -text [$treeid heading $col -text]$dirsym + ${treeid} heading ${col} -text [${treeid} heading ${col} -text]${dirsym} } proc ::deken::treeresults::focusbyindex {treeid index} { # make sure that the entry <index> is visible - $treeid yview $index + ${treeid} yview ${index} } proc ::deken::treeresults::getselected {treeid} { set sel {} - foreach id [$treeid children {}] { - set data [$treeid item $id -values] + foreach id [${treeid} children {}] { + set data [${treeid} item ${id} -values] if { "${data}" eq {} } { continue } - lappend sel [linsert $data 0 [$treeid item $id -text]] + lappend sel [linsert ${data} 0 [${treeid} item ${id} -text]] } - return $sel + return ${sel} } proc ::deken::treeresults::selection_skip {treeid {state 1}} { # expanding/collapsing a node results in a selection message # so we set a flag to skip it variable skipclick - if { ! [info exists skipclick($treeid)] } { - set skipclick($treeid) 0 + if { ! [info exists skipclick(${treeid})] } { + set skipclick(${treeid}) 0 } - set skip $skipclick($treeid) - set skipclick($treeid) $state - return $skip + set skip $skipclick(${treeid}) + set skipclick(${treeid}) ${state} + return ${skip} } proc ::deken::treeresults::selection_changed {treeid} { - if { [::deken::treeresults::selection_skip $treeid 0] } { return } + if { [::deken::treeresults::selection_skip ${treeid} 0] } { return } - $treeid tag remove selpkg - foreach sel [$treeid selection] { - set lib [$treeid parent $sel] - if { $lib eq {} } { + ${treeid} tag remove selpkg + foreach sel [${treeid} selection] { + set lib [${treeid} parent ${sel}] + if { ${lib} eq {} } { # library node - set lib $sel - if { [$treeid item $sel -values] eq {} } { + set lib ${sel} + if { [${treeid} item ${sel} -values] eq {} } { # currently no data, find the best match! set children {} - foreach child [$treeid children $lib] { - set data [$treeid item $child -values] - if {[lindex $data 4]} { - lappend children [list [lindex $data 0] $child] + foreach child [${treeid} children ${lib}] { + set data [${treeid} item ${child} -values] + if {[lindex ${data} 4]} { + lappend children [list [lindex ${data} 0] ${child}] } } - set children [lsort -decreasing -index 0 -command ::deken::versioncompare $children] + set children [lsort -decreasing -index 0 -command ::deken::versioncompare ${children}] set sel {} - foreach child $children { - foreach {version sel} $child {break} + foreach child ${children} { + foreach {version sel} ${child} {break} break } - if { $sel != {}} { - $treeid item $lib -values [$treeid item $sel -values] - $treeid tag add selpkg $sel + if { ${sel} != {}} { + ${treeid} item ${lib} -values [${treeid} item ${sel} -values] + ${treeid} tag add selpkg ${sel} } } else { - $treeid item $lib -values {} + ${treeid} item ${lib} -values {} } } else { # package (leaf) - set data [$treeid item $sel -values] - if { $data eq [$treeid item $lib -values] } { + set data [${treeid} item ${sel} -values] + if { ${data} eq [${treeid} item ${lib} -values] } { # we were already selected, so deselect us - $treeid item $lib -values {} + ${treeid} item ${lib} -values {} } else { - $treeid item $lib -values $data - $treeid tag add selpkg $sel + ${treeid} item ${lib} -values ${data} + ${treeid} tag add selpkg ${sel} } } } ## fixup the selection - set bound [bind $treeid <<TreeviewSelect>>] - bind $treeid <<TreeviewSelect>> {} + set bound [bind ${treeid} <<TreeviewSelect>>] + bind ${treeid} <<TreeviewSelect>> {} # unselect the old ones, and select the new ones - $treeid selection remove [$treeid selection] + ${treeid} selection remove [${treeid} selection] set counter 0 set ::deken::selected {} - foreach id [$treeid children {}] { - set data [$treeid item $id -values] - if { $data eq {} } { continue } - $treeid selection add $id - lappend ::deken::selected [$treeid item $id -text] [lindex $data 5] + foreach id [${treeid} children {}] { + set data [${treeid} item ${id} -values] + if { ${data} eq {} } { continue } + ${treeid} selection add ${id} + lappend ::deken::selected [${treeid} item ${id} -text] [lindex ${data} 5] } - ::deken::update_installbutton [winfo toplevel $treeid] - after idle "bind $treeid <<TreeviewSelect>> \{$bound\}" + ::deken::update_installbutton [winfo toplevel ${treeid}] + after idle "bind ${treeid} <<TreeviewSelect>> \{${bound}\}" } proc ::deken::treeresults::presorter {A B} { # <a>, <b>: [<pkgname> <version> <title> <uploader> <timestamp> <match> <cmd> <contextcmd>] # compare to library lists: <pkgname> (ascending), <match> (descending), <version> (descending), <date> (descending) - foreach {a_name a_ver _ _ a_time a_match} $A {break} - foreach {b_name b_ver _ _ b_time b_match} $B {break} + foreach {a_name a_ver _ _ a_time a_match} ${A} {break} + foreach {b_name b_ver _ _ b_time b_match} ${B} {break} - if {$a_name < $b_name} { return 1 } elseif {$a_name > $b_name} { return -1 } + if {${a_name} < ${b_name}} { return 1 } elseif {${a_name} > ${b_name}} { return -1 } - if {$a_match < $b_match} { return -1 } elseif {$a_match > $b_match} { return 1 } + if {${a_match} < ${b_match}} { return -1 } elseif {${a_match} > ${b_match}} { return 1 } - set v [::deken::versioncompare $a_ver $b_ver] - if { $v != "0" } {return $v} + set v [::deken::versioncompare ${a_ver} ${b_ver}] + if { ${v} != "0" } {return ${v}} - if {$a_time < $b_time} { return -1 } elseif {$a_time > $b_time} { return 1 } + if {${a_time} < ${b_time}} { return -1 } elseif {${a_time} > ${b_time}} { return 1 } return 0 } proc ::deken::treeresults::motionevent {treeid x y} { - set item [$treeid identify item $x $y] - set data [$treeid item $item -values] - if {! [info exists ::deken::treeresults::activecell($treeid) ] } { - set ::deken::treeresults::activecell($treeid) {} + set item [${treeid} identify item ${x} ${y}] + set data [${treeid} item ${item} -values] + if {! [info exists ::deken::treeresults::activecell(${treeid}) ] } { + set ::deken::treeresults::activecell(${treeid}) {} } - set title [lindex $data 1] - set status [lindex $data 7] - set subtitle [lindex $data 8] + set title [lindex ${data} 1] + set status [lindex ${data} 7] + set subtitle [lindex ${data} 8] # the status bar - if { "$status" != "" } { - ::deken::status $status + if { "${status}" != "" } { + ::deken::status ${status} } # the balloon - if { $::deken::treeresults::activecell($treeid) != $item } { - set ::deken::treeresults::activecell($treeid) $item - set X [expr "[winfo rootx $treeid] + 10"] - set Y [expr "[winfo rooty $treeid] + $y + 10"] + if { $::deken::treeresults::activecell(${treeid}) != ${item} } { + set ::deken::treeresults::activecell(${treeid}) ${item} + set X [expr {[winfo rootx ${treeid}] + 10}] + set Y [expr {[winfo rooty ${treeid}] + ${y} + 10}] - ::deken::balloon::show ${treeid}_balloon $X $Y [string trim "$title\n$subtitle"] + ::deken::balloon::show ${treeid}_balloon ${X} ${Y} [string trim "${title}\n${subtitle}"] } } proc ::deken::treeresults::leaveevent {treeid} { - set ::deken::treeresults::activecell($treeid) {} + set ::deken::treeresults::activecell(${treeid}) {} ::deken::balloon::hide ${treeid}_balloon } proc ::deken::treeresults::doubleclick {treeid x y} { - set item [$treeid identify item $x $y] - set installitem $item - if { [$treeid bbox $item] eq {} } { + set item [${treeid} identify item ${x} ${y}] + set installitem ${item} + if { [${treeid} bbox ${item}] eq {} } { set installitem {} } - if { $installitem eq {} } { + if { ${installitem} eq {} } { # the user double-clicked on a column heading - set column [$treeid identify column $x $y] - if { $column eq "#0" } { + set column [${treeid} identify column ${x} ${y}] + if { ${column} eq "#0" } { # we don't want to sort by column#0 # instead we open/close the items set have_open 0 set have_close 0 - foreach lib [$treeid children {}] { - if { [$treeid item $lib -open] } { + foreach lib [${treeid} children {}] { + if { [${treeid} item ${lib} -open] } { incr have_open } else { incr have_close } } - set do_open [expr $have_close > $have_open] - foreach lib [$treeid children {}] { - $treeid item $lib -open $do_open + set do_open [expr {${have_close} > ${have_open}}] + foreach lib [${treeid} children {}] { + ${treeid} item ${lib} -open ${do_open} } return } - set column [$treeid column $column -id] + set column [${treeid} column ${column} -id] # do we want to sort increasing or decreasing? variable colsort - if {! [info exists colsort($column) ] } { - set colsort($column) 1 + if {! [info exists colsort(${column}) ] } { + set colsort(${column}) 1 } set dir -increasing - if { $colsort($column) } { + if { $colsort(${column}) } { set dir -decreasing } set sortable {} - foreach lib [$treeid children {}] { - foreach pkg [$treeid children $lib] { - lappend sortable [list [$treeid set $pkg $column] $lib] + foreach lib [${treeid} children {}] { + foreach pkg [${treeid} children ${lib}] { + lappend sortable [list [${treeid} set ${pkg} ${column}] ${lib}] break } } set pkgs {} - foreach x [lsort -nocase $dir -index 0 -command ::deken::versioncompare $sortable] { - lappend pkgs [lindex $x 1] + foreach x [lsort -nocase ${dir} -index 0 -command ::deken::versioncompare ${sortable}] { + lappend pkgs [lindex ${x} 1] } - $treeid children {} $pkgs - if { $item eq {} } { + ${treeid} children {} ${pkgs} + if { ${item} eq {} } { # yikes: if we are not scrolled down, the double-click will trigger columnsort twice # so we do an extra round here... - ::deken::treeresults::columnsort $treeid $column + ::deken::treeresults::columnsort ${treeid} ${column} } return } - set data [$treeid item $item -values] - set cmd [lindex $data 5] - if { $cmd != "" } { + set data [${treeid} item ${item} -values] + set cmd [lindex ${data} 5] + if { ${cmd} != "" } { ::deken::post "" - eval $cmd + eval ${cmd} } } @@ -2330,49 +2756,49 @@ proc ::deken::treeresults::doubleclick {treeid x y} { proc ::deken::treeresults::show {treeid} { # shown: library, version, title, uploader, date set libraries {} - foreach r $::deken::results { - foreach {title cmd match subtitle statusline contextcmd pkgname version uploader timestamp} $r {break} + foreach r ${::deken::results} { + foreach {title cmd match subtitle statusline contextcmd pkgname version uploader timestamp} ${r} {break} if { "${::deken::hideforeignarch}" } { if { ! ${match} } { continue } } - lappend libraries [list $pkgname $version $title $uploader $timestamp $match $cmd $contextcmd $statusline $subtitle] + lappend libraries [list ${pkgname} ${version} ${title} ${uploader} ${timestamp} ${match} ${cmd} ${contextcmd} ${statusline} ${subtitle}] } # sort the libraries - set libraries [lsort -decreasing -command ::deken::treeresults::presorter $libraries] + set libraries [lsort -decreasing -command ::deken::treeresults::presorter ${libraries}] set lastlib {} set index {} ##foreach v {"#0" version title uploader date} { - ## set width($v) 0 + ## set width(${v}) 0 ##} #puts [time { - foreach lib $libraries { - set l [lindex $lib 0] - set data [lrange $lib 1 end] - if {$l ne $lastlib} { - set lastlib $l - set index [$treeid insert {} end -text $l -open 0 -tags {library}] - ##set w [font measure {-underline false} -displayof $treeid $l] - ##if {$w > $width(#0)} {set width(#0) $w} + foreach lib ${libraries} { + set l [lindex ${lib} 0] + set data [lrange ${lib} 1 end] + if {${l} ne ${lastlib}} { + set lastlib ${l} + set index [${treeid} insert {} end -text ${l} -open 0 -tags {library}] + ##set w [font measure {-underline false} -displayof ${treeid} ${l}] + ##if {${w} > $width(#0)} {set width(#0) ${w}} } set archtag noarchmatch - if { [lindex $lib 5] } { + if { [lindex ${lib} 5] } { set archtag archmatch } - set x [$treeid insert $index end -values $data -tags [list package $archtag]] + set x [${treeid} insert ${index} end -values ${data} -tags [list package ${archtag}]] ##set vidx 0 ##foreach v {version title uploader date} { - ## set w [font measure {-underline false} -displayof $treeid [lindex $data $vidx]] + ## set w [font measure {-underline false} -displayof ${treeid} [lindex ${data} ${vidx}]] ## incr vidx - ## if { $w > $width($v) } {set width($v) $w } + ## if { ${w} > $width(${v}) } {set width($v) ${w} } ##} - $treeid tag add $x $x - ::deken::bind_contextmenu $treeid $x [lindex $lib 7] + ${treeid} tag add ${x} ${x} + ::deken::bind_contextmenu ${treeid} ${x} [lindex ${lib} 7] } #}] @@ -2386,40 +2812,40 @@ proc ::deken::treeresults::show {treeid} { ## as opposed to ~1.2ms for not calculating them) ## #foreach v {version title uploader date} { - # incr width($v) 10 - # $treeid column $v -width $width($v) + # incr width(${v}) 10 + # ${treeid} column ${v} -width $width(${v}) #} } proc ::deken::treeresults::clear {resultsid} { - $resultsid delete [$resultsid children {}] + ${resultsid} delete [${resultsid} children {}] } proc ::deken::treeresults::clear_selection {treeid} { - if { ! [winfo exists $treeid] } { return } + if { ! [winfo exists ${treeid}] } { return } - set bound [bind $treeid <<TreeviewSelect>>] - bind $treeid <<TreeviewSelect>> {} + set bound [bind ${treeid} <<TreeviewSelect>>] + bind ${treeid} <<TreeviewSelect>> {} # unselect the old ones, and select the new ones - $treeid selection remove [$treeid selection] - $treeid tag remove selpkg - foreach item [$treeid children {}] { - $treeid item $item -values {} + ${treeid} selection remove [${treeid} selection] + ${treeid} tag remove selpkg + foreach item [${treeid} children {}] { + ${treeid} item ${item} -values {} } - after idle "bind $treeid <<TreeviewSelect>> \{$bound\}" + after idle "bind ${treeid} <<TreeviewSelect>> \{${bound}\}" } ######################################################## proc ::deken::show_results {resultsid} { - ::deken::textresults::show $resultsid + ::deken::textresults::show ${resultsid} } proc ::deken::clear_results {resultsid} { - ::deken::textresults::clear $resultsid + ::deken::textresults::clear ${resultsid} } proc ::deken::clear_selection {resultsid} { - ::deken::textresults::clear_selection $resultsid + ::deken::textresults::clear_selection ${resultsid} } ######################################################## @@ -2431,28 +2857,28 @@ namespace eval ::deken::balloon { } proc ::deken::balloon::show {winid x y msg {x_offset 0} {y_offset 0}} { - set ::deken::balloon::message($winid) $msg - if {![winfo exist $winid]} { + set ::deken::balloon::message(${winid}) ${msg} + if {![winfo exist ${winid}]} { toplevel ${winid} wm overrideredirect ${winid} 1 label ${winid}.label \ -highlightthick 0 -relief solid -borderwidth 1 \ - -textvariable ::deken::balloon::message($winid) + -textvariable ::deken::balloon::message(${winid}) pack ${winid}.label -expand 1 -fill x } - if { $msg == {} } { + if { ${msg} == {} } { wm withdraw ${winid} return } - set g [format +%d+%d [expr $x + $x_offset] [expr $y + $y_offset]] + set g [format +%d+%d [expr {${x} + ${x_offset}}] [expr {${y} + ${y_offset}}]] # This is probably overdoing it, but better too much than too little - wm geometry ${winid} $g + wm geometry ${winid} ${g} wm deiconify ${winid} - wm geometry ${winid} $g + wm geometry ${winid} ${g} raise ${winid} - after idle "[list wm geometry $winid $g]; raise $winid" + after idle "[list wm geometry ${winid} ${g}]; raise ${winid}" } proc ::deken::balloon::hide {winid} { if {[winfo exist ${winid}]} { @@ -2464,16 +2890,16 @@ proc ::deken::balloon::hide {winid} { proc ::deken::ask_installdir {{installdir ""} {extname ""}} { while {1} { - if { "$installdir" == "" } { + if { "${installdir}" == "" } { set result [tk_messageBox \ -message [_ "Please select a (writable) installation directory!"] \ -icon warning -type retrycancel -default retry \ - -parent $::deken::winid] + -parent ${::deken::winid}] switch -- "${result}" { cancel {return} retry { if {[::deken::prompt_installdir]} { - set installdir $::deken::installpath + set installdir ${::deken::installpath} } else { continue } @@ -2481,26 +2907,26 @@ proc ::deken::ask_installdir {{installdir ""} {extname ""}} { } } else { set result [tk_messageBox \ - -message [format [_ "Install %1\$s to %2\$s?" ] $extname $installdir] \ + -message [format [_ "Install %1\$s to %2\$s?" ] ${extname} ${installdir}] \ -icon question -type yesnocancel -default yes \ - -parent $::deken::winid] + -parent ${::deken::winid}] switch -- "${result}" { cancel {return} yes { } no { - set prevpath $::deken::installpath + set prevpath ${::deken::installpath} if {[::deken::prompt_installdir]} { set keepprevpath 1 - set installdir $::deken::installpath + set installdir ${::deken::installpath} # if docsdir is set & the install path is valid, # saying "no" is temporary to ensure the docsdir # hierarchy remains, use the Path dialog to override if {[namespace exists ::pd_docsdir] && [::pd_docsdir::path_is_valid] && - [file writable [file normalize $prevpath]] } { + [file writable [file normalize ${prevpath}]] } { set keepprevpath 0 } - if {$keepprevpath} { - set ::deken::installpath $prevpath + if {${keepprevpath}} { + set ::deken::installpath ${prevpath} } } else { continue @@ -2509,18 +2935,18 @@ proc ::deken::ask_installdir {{installdir ""} {extname ""}} { } } - if { "$installdir" != "" } { + if { "${installdir}" != "" } { # try creating the installdir...just in case - catch { file mkdir $installdir } + catch { file mkdir ${installdir} } } # check whether this is a writable directory - set installdir [ ::deken::utilities::get_writabledir [list $installdir ] ] - if { "$installdir" != "" } { + set installdir [ ::deken::utilities::get_writabledir [list ${installdir} ] ] + if { "${installdir}" != "" } { # stop looping if we've found our dir break } } - return $installdir + return ${installdir} } proc ::deken::ensure_installdir {{installdir ""} {extname ""}} { @@ -2528,22 +2954,22 @@ proc ::deken::ensure_installdir {{installdir ""} {extname ""}} { ### if ::deken::installpath is set, use the first writable item ### if not, get a writable item from one of the searchpaths ### if this still doesn't help, ask the user - if { "$installdir" != "" } {return $installdir} + if { "${installdir}" != "" } {return ${installdir}} set installdir [::deken::find_installpath] - if { "$installdir" != "" } {return $installdir} + if { "${installdir}" != "" } {return ${installdir}} if {[namespace exists ::pd_docsdir] && [::pd_docsdir::externals_path_is_valid]} { # if the docspath is set, try the externals subdir set installdir [::pd_docsdir::get_externals_path] } - if { "$installdir" != "" } {return $installdir} + if { "${installdir}" != "" } {return ${installdir}} # ask the user (and remember the decision) ::deken::prompt_installdir - set installdir [ ::deken::utilities::get_writabledir [list $::deken::installpath ] ] + set installdir [ ::deken::utilities::get_writabledir [list ${::deken::installpath} ] ] - return [::deken::ask_installdir [::deken::utilities::expandpath $installdir ] $extname] + return [::deken::ask_installdir [::deken::utilities::expandpath ${installdir} ] ${extname}] } # handle a clicked link @@ -2554,79 +2980,92 @@ proc ::deken::install_link {URL filename} { ### if this still doesn't help, ask the user variable winid set installbutton ${winid}.status.install - if {[winfo exists $installbutton]} { - $installbutton configure -state disabled + if {[winfo exists ${installbutton}]} { + ${installbutton} configure -state disabled } - ::deken::show_tab $winid info + ::deken::show_tab ${winid} info set installdir [::deken::ensure_installdir "" ${filename}] if { "${installdir}" == "" } { - ::deken::utilities::debug [format [_ "Cancelling download of '%s': No installation directory given." ] $filename] - ::deken::statuspost [format [_ "Installing to non-existent directory failed" ] $filename] error + ::deken::utilities::debug [format [_ "Cancelling download of '%s': No installation directory given." ] ${filename}] + ::deken::statuspost [format [_ "Installing to non-existent directory failed" ] ${filename}] error return } - if { ! [file exists $installdir] } { - ::deken::post [format [_ "Unable to install to '%s'" ] $installdir ] error + if { ! [file exists ${installdir}] } { + catch { file mkdir ${installdir} } + } + if { ! [file isdirectory ${installdir}] } { set msg [_ "Directory does not exist!" ] - ::deken::post "\t$msg" error + ::deken::post [format [_ "Unable to install to '%s'" ] ${installdir} ] error + ::deken::post "\t${msg}" error + set installdir [::deken::do_prompt_installdir ${installdir}] + if { "${installdir}" == "" } { + #::deken::update_installbutton ${winid} + return + } + } + if { ! [file isdirectory ${installdir}] } { + ::deken::post [format [_ "Unable to install to '%s'" ] ${installdir} ] error + set msg [_ "Directory does not exist!" ] + ::deken::post "\t${msg}" error return } - if { [::deken::utilities::get_writabledir [list $installdir]] == "" } { - ::deken::post [format [_ "Unable to install to '%s'" ] $installdir ] error + if { [::deken::utilities::get_writabledir [list ${installdir}]] == "" } { + ::deken::post [format [_ "Unable to install to '%s'" ] ${installdir} ] error set msg [_ "Directory is not writable!" ] - ::deken::post "\t$msg" error + ::deken::post "\t${msg}" error return } - set parsedfilename [::deken::utilities::parse_filename $filename] - set fullpkgfile [::deken::utilities::get_tmpfilename $installdir [::deken::utilities::get_filenameextension $filename] "[lindex $parsedfilename 0]\[[lindex $parsedfilename 1]\]" ] - ::deken::statuspost [format [_ "Downloading '%s'" ] $filename] info 0 - ::deken::utilities::debug [format [_ "Commencing download of '%1\$s' into '%2\$s'..." ] $URL $installdir] + set parsedfilename [::deken::utilities::parse_filename ${filename}] + set fullpkgfile [::deken::utilities::get_tmpfilename ${installdir} [::deken::utilities::get_filenameextension ${filename}] "[lindex ${parsedfilename} 0]\[[lindex ${parsedfilename} 1]\]" ] + ::deken::statuspost [format [_ "Downloading '%s'" ] ${filename}] info 0 + ::deken::utilities::debug [format [_ "Commencing download of '%1\$s' into '%2\$s'..." ] ${URL} ${installdir}] ::deken::syncgui - set fullpkgfile [::deken::utilities::download_file $URL $fullpkgfile "::deken::download_progress"] - if { "$fullpkgfile" eq "" } { + set fullpkgfile [::deken::utilities::download_file ${URL} ${fullpkgfile} "::deken::download_progress"] + if { "${fullpkgfile}" eq "" } { ::deken::utilities::debug [_ "aborting."] - ::deken::statuspost [format [_ "Downloading '%s' failed" ] $filename] error + ::deken::statuspost [format [_ "Downloading '%s' failed" ] ${filename}] error ::deken::progressstatus [_ "Download failed!" ] ::deken::progress 0 return } set msg [_ "Download completed! Verifying..." ] - ::deken::progressstatus $msg - ::deken::post "$msg" info + ::deken::progressstatus ${msg} + ::deken::post "${msg}" info set result [::deken::verify_sha256_gui ${URL} ${fullpkgfile}] - if { ! $result } { + if { ! ${result} } { # verification failed - if { ! "$::deken::keep_package" } { - catch { file delete $fullpkgfile } + if { ! "${::deken::keep_package}" } { + catch { file delete ${fullpkgfile} } } ::deken::progress 0 return } - if { $result < 0 } { + if { ${result} < 0 } { # verification failed, but we ignore it - if { $result > -10 } { + if { ${result} > -10 } { ::deken::statuspost [_ "Ignoring checksum mismatch" ] info 0 - } elseif { $result > -100 } { + } elseif { ${result} > -100 } { ::deken::statuspost [_ "Ignoring checksum errors" ] info 0 } } ::deken::install_package ${fullpkgfile} ${filename} ${installdir} ${::deken::keep_package} - ::deken::update_installbutton $winid + ::deken::update_installbutton ${winid} } # print the download progress to the results window proc ::deken::download_progress {token total current} { - if { $total > 0 } { - ::deken::progress [expr {round(100 * (1.0 * $current / $total))}] + if { ${total} > 0 } { + ::deken::progress [expr {round(100 * (1.0 * ${current} / ${total}))}] } } # test for platform match with our current platform proc ::deken::architecture_match {archs} { if { "translations" eq "${::deken::searchtype}" } { - foreach arch $archs { + foreach arch ${archs} { if { "i18n" eq "${arch}" } { return 1 } @@ -2637,24 +3076,28 @@ proc ::deken::architecture_match {archs} { return 0 } # if there are no architecture sections this must be arch-independent - if { ! [llength $archs] } { return 1} + if { ! [llength ${archs}] } { return 1} set OS "$::deken::platform(os)" set MACHINE "$::deken::platform(machine)" set BITS "$::deken::platform(bits)" set FLOATSIZE "$::deken::platform(floatsize)" - if { "$::deken::userplatform" != "" } { + if { "${::deken::userplatform}" != "" } { ## FIXXME what if the user-supplied input isn't valid? - regexp -- {(.*)-(.*)-(.*)} $::deken::userplatform _ OS MACHINE FLOATSIZE + regexp -- {(.*)-(.*)-(.*)} ${::deken::userplatform} _ OS MACHINE FLOATSIZE } # strip the little-endian indicator from arm-archs, it's the default - regexp -- {(armv[0-9]*)[lL]} $MACHINE _ MACHINE + regexp -- {(armv[0-9]*)[lL]} ${MACHINE} _ MACHINE + set MACHINE [string tolower ${MACHINE}] + set OS [string tolower ${OS}] # check each architecture in our list against the current one - foreach arch $archs { - if { [ regexp -- {(.*)-(.*)-(.*)} $arch _ os machine floatsize ] } { + foreach arch ${archs} { + if { [ regexp -- {(.*)-(.*)-(.*)} ${arch} _ os machine floatsize ] } { # normalize arm-architectures by stripping away sub-architectures # TODO: leave any big-endian indicator in place - regexp -- {(armv[0-9]*)[^0-9]*} $machine _ machine + regexp -- {(armv[0-9]*)[^0-9]*} ${machine} _ machine + set machine [string tolower ${machine}] + set os [string tolower ${os}] if { ("${os}" eq "${OS}") && (("${floatsize}" eq "${FLOATSIZE}") || ("${floatsize}" eq "0"))} { ## so OS and floatsize match... ## check whether the CPU matches as well @@ -2673,31 +3116,32 @@ proc ::deken::architecture_match {archs} { proc ::deken::search_for {term} { set result [list] - foreach searcher $::deken::backends { + foreach searcher ${::deken::backends} { if {[catch { - foreach r [ $searcher $term ] { - if { "" eq [lindex $r 0] } { + foreach r [ ${searcher} ${term} ] { + if { "" eq [lindex ${r} 0] } { # data is already normalized } else { # legacy data format - foreach {title cmd match comment status} $r {break} - set r [::deken::normalize_result $title $cmd $match $comment $status] + foreach {title cmd match comment status} ${r} {break} + set r [::deken::normalize_result ${title} ${cmd} ${match} ${comment} ${status}] } - lappend result [lrange $r 1 end] + lappend result [lrange ${r} 1 end] } } stdout] } { - ::deken::utilities::debug "$searcher: $stdout" + ::deken::utilities::debug "${searcher:} ${stdout}" } } - return $result + return ${result} } proc ::deken::initialize {} { + set label [_ "Find externals"] # console message to let them know we're loaded ## but only if we are being called as a plugin (not as built-in) - if { "" != "$::current_plugin_loadpath" } { - ::pdwindow::debug [format [_ "\[deken\] deken-plugin.tcl (Pd externals search) loaded from %s." ] $::current_plugin_loadpath ] + if { "" != "${::current_plugin_loadpath}" } { + ::pdwindow::debug [format [_ "\[deken\] deken-plugin.tcl (Pd externals search) loaded from %s." ] ${::current_plugin_loadpath} ] ::pdwindow::debug "\n" } set msg [format [_ "\[deken\] Platform detected: %s" ] [::deken::platform2string 1] ] @@ -2707,15 +3151,47 @@ proc ::deken::initialize {} { set ::deken::installpath [::deken::find_installpath] - # create an entry for our search in the "help" menu (or reuse an existing one) - set mymenu .menubar.help - if { [catch { - $mymenu entryconfigure [_ "Find externals"] -command {::deken::open_searchui $::deken::winid} - } _ ] } { - $mymenu add separator - $mymenu add command -label [_ "Find externals"] -command {::deken::open_searchui $::deken::winid} + # create an entry for our search in the menu (or reuse an existing one) + + # check which menus are there (for the pdwindow) + set helpmenu {} + set toolsmenu {} + + set pdmenu [.pdwindow cget -menu] + for {set m 0} {$m <= [$pdmenu index end]} {incr m} { + set _m [$pdmenu entrycget $m -menu] + switch -glob $_m { + *.tools { set toolsmenu $_m } + *.help { set helpmenu $_m } + } + } + + # if there's a 'tools' menu, use that, otherwise use the 'help' menu + if { [winfo exists ${toolsmenu}]} { + # we got Tools->, so if there's Help->Find externals... entry, drop it + catch { + $helpmenu delete ${label} + } + set mymenu ${toolsmenu} + } else { + set mymenu ${helpmenu} } - # bind all <$::modifier-Key-s> {::deken::open_helpbrowser .helpbrowser2} + if { [winfo exists ${mymenu}] } { + if { [catch { + # if there's already an entry, make sure to use our 'open_searchui' rather than the built-in + ${mymenu} entryconfigure ${label} -command {::deken::open_searchui ${::deken::winid}} + } _ ] } { + # otherwise create a new menu entry + if { ${mymenu} eq ".menubar.help" } { + ${mymenu} add separator + } + ${mymenu} add command -label ${label} -command {::deken::open_searchui ${::deken::winid}} + } + } else { + set msg [_ "Could not find a menu for adding '%s'" ${label}] + ::pdwindow::fatal "\[deken\] ${msg}\n" + } + # bind all <${::modifier}-Key-s> {::deken::open_helpbrowser .helpbrowser2} } @@ -2740,7 +3216,7 @@ proc ::deken::register {fun} { # - <args>... additional args (ignored) # the library <name> must be non-empty (and empty value is reserved for normalized results) - set ::deken::backends [linsert $::deken::backends 0 $fun] + set ::deken::backends [linsert ${::deken::backends} 0 ${fun}] } @@ -2771,7 +3247,7 @@ proc ::deken::register {fun} { # registration -## to register a new search function, call `::deken::register $myfun` +## to register a new search function, call `::deken::register ${myfun}` # namespace ## you are welcome to use the ::deken::search:: namespace @@ -2780,37 +3256,84 @@ proc ::deken::register {fun} { ## #################################################################### ## searching puredata.info -namespace eval ::deken::search::dekenserver { } +namespace eval ::deken::search::dekenserver { + # deken servers to use + variable url_primary + variable urls_secondary + variable urls_ephemeral + # should we actually use them? + variable use_url_primary + variable use_urls_secondary + variable use_urls_ephemeral +} + +# the main deken-url +::deken::utilities::setdefault ::deken::search::dekenserver::use_url_primary 1 +set ::deken::search::dekenserver::url_primary "http://deken.puredata.info/search" +if { ! [catch {package present tls} stdout] } { + set ::deken::search::dekenserver::url_primary "https://deken.puredata.info/search" +} +catch {set ::deken::search::dekenserver::url_primary $::env(DEKENSERVER)} +catch {set ::deken::search::dekenserver::url_primary $::env(DEKEN_SEARCH_URL)} + + +# additional (fixed) deken-servers +::deken::utilities::setdefault ::deken::search::dekenserver::use_urls_secondary 0 +::deken::utilities::setdefault ::deken::search::dekenserver::urls_secondary {} + +# additional (ephemeral) deken-servers +::deken::utilities::setdefault ::deken::search::dekenserver::use_urls_ephemeral 0 +## those we expect +::deken::utilities::setdefault ::deken::search::dekenserver::urls_ephemeral {} +## those that are there +array set ::deken::search::dekenserver::urls_ephemeral_existing {} + proc ::deken::search::dekenserver::search {term} { - set dekenurl "${::deken::protocol}://deken.puredata.info/search" - catch {set dekenurl $::env(DEKENSERVER)} stdout - catch {set dekenurl $::env(DEKEN_SEARCH_URL)} stdout - set urls [list $dekenurl] + set tmpurls {} + foreach {k v} [array get ::deken::search::dekenserver::urls_ephemeral_existing] { + lappend tmpurls ${v} + } + # all the search URLs + set urls {} + if { ${::deken::search::dekenserver::use_url_primary} } { + lappend urls ${::deken::search::dekenserver::url_primary} + } + if { ${::deken::search::dekenserver::use_urls_secondary} } { + set urls [concat ${urls} ${::deken::search::dekenserver::urls_secondary}] + } + if { ${::deken::search::dekenserver::use_urls_ephemeral} } { + set urls [concat \ + ${urls} \ + [::deken::utilities::lists_intersect ${::deken::search::dekenserver::urls_ephemeral} ${tmpurls}] \ + ] + } + + # remove duplicate entries + set urls [::deken::utilities::list_unique ${urls}] # search all the urls array set results {} set urlcount 0 - foreach s $urls { + foreach s ${urls} { # skip empty urls - if { $s eq {} } { continue } - ::deken::post [format [_ "Searching on %s..."] $s ] debug + if { ${s} eq {} } { continue } + ::deken::post [format [_ "Searching on %s..."] ${s} ] debug set resultcount 0 # get the results from the given url, and add them to our results set - foreach r [::deken::search::dekenserver::search_server $term $s] { - set results($r) {} + foreach r [::deken::search::dekenserver::search_server ${term} ${s}] { + set results(${r}) {} incr resultcount } - ::deken::post [format [_ "Searching on %1\$s returned %2\$d results"] $s $resultcount] debug + ::deken::post [format [_ "Searching on %1\$s returned %2\$d results"] ${s} ${resultcount}] debug incr urlcount } - - if { $urlcount == 0 } { - ::deken::post [format [_ "No usable servers for searching found..."] $s ] debug + if { ${urlcount} == 0 } { + ::deken::post [format [_ "No usable servers for searching found..."] ${urls} ] debug } set splitCont [array names results] - if { [llength $splitCont] == 0 } { - return $splitCont + if { [llength ${splitCont}] == 0 } { + return ${splitCont} } set searchresults [list] @@ -2819,31 +3342,31 @@ proc ::deken::search::dekenserver::search {term} { set latestrelease0 [dict create] set latestrelease1 [dict create] set newestversion [dict create] - foreach ele $splitCont { - set ele [ string trim $ele ] - if { "" ne $ele } { - foreach {name URL creator date} [ split $ele "\t" ] {break} - set filename [ file tail $URL ] - foreach {pkgname version archs} [ ::deken::utilities::parse_filename $filename ] {break} - - #if { $version eq "0.0.extended" } { set date "0000-00-00 00:02:00" } + foreach ele ${splitCont} { + set ele [ string trim ${ele} ] + if { "" ne ${ele} } { + foreach {name URL creator date} [ split ${ele} "\t" ] {break} + set filename [ file tail ${URL} ] + foreach {pkgname version archs} [ ::deken::utilities::parse_filename ${filename} ] {break} + + #if { ${version} eq "0.0.extended" } { set date "0000-00-00 00:02:00" } set olddate {} - set match [::deken::architecture_match "$archs" ] + set match [::deken::architecture_match "${archs}" ] if { ${match} } { - catch { set olddate [dict get ${latestrelease1} $pkgname] } + catch { set olddate [dict get ${latestrelease1} ${pkgname}] } set oldversion {} - catch { set oldversion [dict get ${newestversion} $pkgname]} - if { [::deken::versioncompare $version $oldversion] > 0 } { - dict set newestversion $pkgname $version + catch { set oldversion [dict get ${newestversion} ${pkgname}]} + if { [::deken::versioncompare ${version} ${oldversion}] > 0 } { + dict set newestversion ${pkgname} ${version} } } else { - catch { set olddate [dict get ${latestrelease0} $pkgname] } + catch { set olddate [dict get ${latestrelease0} ${pkgname}] } } - if { $date > $olddate } { - dict set latestrelease${match} $pkgname $date + if { ${date} > ${olddate} } { + dict set latestrelease${match} ${pkgname} ${date} } } } @@ -2854,54 +3377,54 @@ proc ::deken::search::dekenserver::search {term} { } set vsep "\u0001" - foreach ele $splitCont { - set ele [ string trim $ele ] - if { "" ne $ele } { - foreach {name URL creator date} [ split $ele "\t" ] {break} - set decURL [::deken::utilities::urldecode $URL] - set filename [ file tail $URL ] - set cmd [list ::deken::install_link $decURL $filename] - set pkgverarch [ ::deken::utilities::parse_filename $filename ] - set pkgname [lindex $pkgverarch 0] - set version [lindex $pkgverarch 1] - set archs [lindex $pkgverarch 2] - - set match [::deken::architecture_match "$archs" ] - set comment [format [_ "Uploaded by %1\$s @ %2\$s" ] $creator $date ] - set status $URL + foreach ele ${splitCont} { + set ele [ string trim ${ele} ] + if { "" ne ${ele} } { + foreach {name URL creator date} [ split ${ele} "\t" ] {break} + set decURL [::deken::utilities::urldecode ${URL}] + set filename [ file tail ${URL} ] + set cmd [list ::deken::install_link ${decURL} ${filename}] + set pkgverarch [ ::deken::utilities::parse_filename ${filename} ] + set pkgname [lindex ${pkgverarch} 0] + set version [lindex ${pkgverarch} 1] + set archs [lindex ${pkgverarch} 2] + + set match [::deken::architecture_match "${archs}" ] + set comment [format [_ "Uploaded by %1\$s @ %2\$s" ] ${creator} ${date} ] + set status ${URL} set sortprefix "0000-00-00 00:01:00" if { ${match} == 0 } { - catch { set sortprefix [dict get ${latestrelease0} $pkgname] } + catch { set sortprefix [dict get ${latestrelease0} ${pkgname}] } } else { if { "${::deken::hideoldversions}" } { # If this version is not the newest one, mark it as unmatched catch { - set oldversion [dict get ${newestversion} $pkgname] - if { [::deken::versioncompare $version $oldversion] < 0 } { + set oldversion [dict get ${newestversion} ${pkgname}] + if { [::deken::versioncompare ${version} ${oldversion}] < 0 } { set match 0 } } } } - catch { set sortprefix [dict get ${latestrelease1} $pkgname] } + catch { set sortprefix [dict get ${latestrelease1} ${pkgname}] } # the ${vsep} should sort before all other characters that might appear in version strings, # as it unsures that "1.2" sorts before "1.2-1" # the space (or some other character that sorts after "\t") after the ${version} is important, # as it ensures that "0.2~1" sorts before "1.2" set sortname "${sortprefix}${vsep}${pkgname}${vsep}${version} ${vsep}${date}" - set contextcmd [list ::deken::search::dekenserver::contextmenu %W %x %y $pkgname $URL] - set res [list $sortname $filename $name $cmd $match $comment $status $contextcmd $pkgname $version $creator $date] - lappend searchresults $res + set contextcmd [list ::deken::search::dekenserver::contextmenu %W %x %y ${pkgname} ${URL}] + set res [list ${sortname} ${filename} ${name} ${cmd} ${match} ${comment} ${status} ${contextcmd} ${pkgname} ${version} ${creator} ${date}] + lappend searchresults ${res} } } set sortedresult [] - foreach r [lsort -command ::deken::versioncompare -decreasing -index 0 $searchresults ] { - foreach {sortname filename title cmd match comment status menus pkgname version creator date} $r { - lappend sortedresult [::deken::normalize_result $title $cmd $match $comment $status $menus $pkgname $version $creator $date] + foreach r [lsort -command ::deken::versioncompare -decreasing -index 0 ${searchresults} ] { + foreach {sortname filename title cmd match comment status menus pkgname version creator date} ${r} { + lappend sortedresult [::deken::normalize_result ${title} ${cmd} ${match} ${comment} ${status} ${menus} ${pkgname} ${version} ${creator} ${date}] break } } - return $sortedresult + return ${sortedresult} } proc ::deken::search::dekenserver::search_server {term dekenurl} { @@ -2910,9 +3433,9 @@ proc ::deken::search::dekenserver::search_server {term dekenurl} { # special handling of searching for all translations (so we ONLY get translations) set term {*} } - foreach x $term {lappend queryterm ${::deken::searchtype} $x} - if { [ catch {set queryterm [::http::formatQuery {*}$queryterm ] } stdout ] } { - set queryterm [ join $term "&${::deken::searchtype}=" ] + foreach x ${term} {lappend queryterm ${::deken::searchtype} ${x}} + if { [ catch {set queryterm [::http::formatQuery {*}${queryterm} ] } stdout ] } { + set queryterm [ join ${term} "&${::deken::searchtype}=" ] set queryterm "${::deken::searchtype}=${queryterm}" } @@ -2925,30 +3448,30 @@ proc ::deken::search::dekenserver::search_server {term dekenurl} { if { [catch { set token [::http::geturl "${dekenurl}?${queryterm}"] } stdout ] } { - set msg [format [_ "Searching for '%s' failed!" ] $term ] + set msg [format [_ "Searching for '%s' failed!" ] ${term} ] tk_messageBox \ -title [_ "Search failed" ] \ - -message "${msg}\n$stdout" \ + -message "${msg}\n(${dekenurl})\n${stdout}" \ -icon error -type ok \ - -parent $::deken::winid + -parent ${::deken::winid} return } # restore http settings - ::http::config -accept $httpaccept - ::http::config -useragent $httpagent + ::http::config -accept ${httpaccept} + ::http::config -useragent ${httpagent} - set ncode [::http::ncode $token] - if { $ncode != 200 } { - set err [::http::code $token] + set ncode [::http::ncode ${token}] + if { ${ncode} != 200 } { + set err [::http::code ${token}] set msg [_ "Unable to perform search."] - ::deken::utilities::debug "$msg\n ${err}" + ::deken::utilities::debug "${msg}\n ${err}" return {} } - set contents [::http::data $token] - ::http::cleanup $token + set contents [::http::data ${token}] + ::http::cleanup ${token} - return [split $contents "\n"] + return [split ${contents} "\n"] } proc ::deken::search::dekenserver::contextmenu {widget theX theY pkgname URL} { @@ -2958,41 +3481,41 @@ proc ::deken::search::dekenserver::contextmenu {widget theX theY pkgname URL} { catch { # don't show the select/install entries when using a treeview - $resultsid identify item 0 0 + ${resultsid} identify item 0 0 set with_installmenu 0 } set m .dekenresults_contextMenu - destroy $m - menu $m + destroy ${m} + menu ${m} - set saveURL [string map {"[" "%5B" "]" "%5D"} $URL] + set saveURL [string map {"[" "%5B" "]" "%5D"} ${URL}] - if { $with_installmenu } { - set decURL [::deken::utilities::urldecode $URL] - set filename [ file tail $URL ] - set pkgverarch [ ::deken::utilities::parse_filename $filename ] - set pkgname [lindex $pkgverarch 0] + if { ${with_installmenu} } { + set decURL [::deken::utilities::urldecode ${URL}] + set filename [ file tail ${URL} ] + set pkgverarch [ ::deken::utilities::parse_filename ${filename} ] + set pkgname [lindex ${pkgverarch} 0] - set cmd [list ::deken::install_link $decURL $filename] + set cmd [list ::deken::install_link ${decURL} ${filename}] set selcount 0 set selected 0 - foreach {k v} $::deken::selected { + foreach {k v} ${::deken::selected} { if { ${v} != {} } {incr selcount} - if { ($k eq $pkgname) && ($v eq $cmd) } { + if { (${k} eq ${pkgname}) && (${v} eq ${cmd}) } { set selected 1 break } } set msg [_ "Select package for installation" ] - if { $selected } { + if { ${selected} } { set msg [_ "Deselect package" ] } - $m add command -label "${msg}" -command "::deken::textresults::selectpackage $resultsid $pkgname {$cmd}" - $m add separator + ${m} add command -label "${msg}" -command "::deken::textresults::selectpackage ${resultsid} ${pkgname} {${cmd}}" + ${m} add separator } set infoq "url=${URL}" @@ -3000,19 +3523,19 @@ proc ::deken::search::dekenserver::contextmenu {widget theX theY pkgname URL} { set infoq [::http::formatQuery url ${URL}] } - $m add command -label [_ "Open package webpage" ] -command "pd_menucommands::menu_openfile \{https://deken.puredata.info/info?$infoq\}" - $m add command -label [_ "Copy package URL" ] -command "clipboard clear; clipboard append $saveURL" - $m add command -label [_ "Copy SHA256 checksum URL" ] -command "clipboard clear; clipboard append ${saveURL}.sha256" - $m add command -label [_ "Copy OpenGPG signature URL" ] -command "clipboard clear; clipboard append ${saveURL}.asc" + ${m} add command -label [_ "Open package webpage" ] -command "pd_menucommands::menu_openfile \{https://deken.puredata.info/info?${infoq}\}" + ${m} add command -label [_ "Copy package URL" ] -command "clipboard clear; clipboard append ${saveURL}" + ${m} add command -label [_ "Copy SHA256 checksum URL" ] -command "clipboard clear; clipboard append ${saveURL}.sha256" + ${m} add command -label [_ "Copy OpenGPG signature URL" ] -command "clipboard clear; clipboard append ${saveURL}.asc" set installpath [::deken::find_installpath] - if { "$installpath" ne {} } { - if { [file isdir [file join $installpath $pkgname]] } { - $m add separator - $m add command -label [format [_ "Uninstall '%s'" ] $pkgname] -command [list ::deken::menu_uninstall_package $winid $pkgname $installpath] + if { "${installpath}" ne {} } { + if { [file isdir [file join ${installpath} ${pkgname}]] } { + ${m} add separator + ${m} add command -label [format [_ "Uninstall '%s'" ] ${pkgname}] -command [list ::deken::menu_uninstall_package ${winid} ${pkgname} ${installpath}] } } - tk_popup $m [expr [winfo rootx $widget] + $theX] [expr [winfo rooty $widget] + $theY] + tk_popup ${m} [expr {[winfo rootx ${widget}] + ${theX}}] [expr {[winfo rooty ${widget}] + ${theY}}] } diff --git a/tcl/pd_menucommands.tcl b/tcl/pd_menucommands.tcl index 20de4ed8dd..3b5973ed4a 100644 --- a/tcl/pd_menucommands.tcl +++ b/tcl/pd_menucommands.tcl @@ -237,7 +237,26 @@ proc ::pd_menucommands::set_filenewdir {mytoplevel} { # parse the textfile for the About Pd page proc ::pd_menucommands::menu_aboutpd {} { - set versionstring "Pd $::PD_MAJOR_VERSION.$::PD_MINOR_VERSION.$::PD_BUGFIX_VERSION$::PD_TEST_VERSION" + set versionstring "$::PD_APPLICATION_NAME $::PD_MAJOR_VERSION.$::PD_MINOR_VERSION.$::PD_BUGFIX_VERSION$::PD_TEST_VERSION" + + # add the architecture to the version-string + set precision "" + if { [info exists ::deken::platform(floatsize)] } { + switch -- ${::deken::platform(floatsize)} { + 32 { set precision [_ "single precision"] } + 64 { set precision [_ "double precision"] } + "" { set precision ""} + default { set precision [_ "%dbit-floats" ${::deken::platform(floatsize)}]} + } + } + if { ${precision} ne "" } { + set precision " - $precision" + } + + if {[info exists ::deken::platform(os)]} { + set versionstring "$versionstring ($::deken::platform(os)/$::deken::platform(machine)${precision})" + } + set filename [file join $::sys_guidir about.txt] if {![file exists $filename]} { ::pdwindow::error [_ "ignoring '%s': doesn't exist" $filename] @@ -252,7 +271,7 @@ proc ::pd_menucommands::menu_aboutpd {} { toplevel .aboutpd -class TextWindow wm title .aboutpd [_ "About Pd"] wm group .aboutpd . - .aboutpd configure -menu $::dialog_menubar + ::pd_menus::menubar_for_dialog .aboutpd text .aboutpd.text -relief flat -borderwidth 0 -highlightthickness 0 \ -yscrollcommand ".aboutpd.scroll set" -background white scrollbar .aboutpd.scroll -command ".aboutpd.text yview" @@ -264,9 +283,9 @@ proc ::pd_menucommands::menu_aboutpd {} { set textfile [open $filename] while {![eof $textfile]} { set bigstring [read $textfile 1000] - regsub -all PD_BASEDIR $bigstring $::sys_libdir bigstring2 - regsub -all PD_VERSION $bigstring2 $versionstring bigstring3 - .aboutpd.text insert end $bigstring3 + regsub -all PD_BASEDIR $bigstring $::sys_libdir bigstring + regsub -all PD_VERSION $bigstring $versionstring bigstring + .aboutpd.text insert end $bigstring } close $textfile } stderr ] } { diff --git a/tcl/pd_menus.tcl b/tcl/pd_menus.tcl index e08eb5a13c..89e1a2ed98 100644 --- a/tcl/pd_menus.tcl +++ b/tcl/pd_menus.tcl @@ -14,8 +14,10 @@ package require pd_connect # opposite of the 'bind' commands in pd_bindings.tcl namespace eval ::pd_menus:: { - variable accelerator - variable menubar ".menubar" + variable accelerator "Ctrl" + if {[tk windowingsystem] eq "aqua"} { + set accelerator "Cmd" + } namespace export create_menubar namespace export configure_for_pdwindow @@ -30,163 +32,124 @@ namespace eval ::pd_menus:: { # proc ::pd_menus::create_menubar {} { variable accelerator - variable menubar + # a menu for PatchWindows + menu $::patch_menubar + # a menu for the PdWindow + menu $::pdwindow_menubar + # a shared menu for preferences + build_preferences_menu .preferences + # a shared menu for recentfiles + ::pd_menus::update_openrecent_menu .openrecent 0 + if {$::windowingsystem eq "aqua"} { - set accelerator "Cmd" - } else { - set accelerator "Ctrl" + create_apple_menu $::patch_menubar + create_apple_menu $::pdwindow_menubar + } + + foreach mymenu "file edit" { + [format build_%s_menu $mymenu] [menu $::patch_menubar.$mymenu] 1 + $::patch_menubar add cascade -label [_ [string totitle $mymenu]] \ + -underline 0 -menu $::patch_menubar.$mymenu + [format build_%s_menu $mymenu] [menu $::pdwindow_menubar.$mymenu] 0 + $::pdwindow_menubar add cascade -label [_ [string totitle $mymenu]] \ + -underline 0 -menu $::pdwindow_menubar.$mymenu } - menu $menubar - if {$::windowingsystem eq "aqua"} {create_apple_menu $menubar} - set menulist "file edit put find media window help" - foreach mymenu $menulist { + + build_put_menu [menu $::patch_menubar.put] + $::patch_menubar add cascade -label [_ Put] \ + -underline 0 -menu $::patch_menubar.put + + foreach mymenu "find media window tools help" { if {$mymenu eq "find"} { set underlined 3 } { set underlined 0 } - menu $menubar.$mymenu - $menubar add cascade -label [_ [string totitle $mymenu]] \ - -underline $underlined -menu $menubar.$mymenu - [format build_%s_menu $mymenu] $menubar.$mymenu + # some GUI-plugins do expect that common menus are available under + # ${::patch_menubar}.${mymenu} (e.g. ".menubar.help") + set m [menu $::patch_menubar.$mymenu] + [format build_%s_menu $mymenu] ${m} + $::patch_menubar add cascade -label [_ [string totitle $mymenu]] \ + -underline $underlined -menu $m + $::pdwindow_menubar add cascade -label [_ [string totitle $mymenu]] \ + -underline $underlined -menu $m } - if {$::windowingsystem eq "win32"} {create_system_menu $menubar} - . configure -menu $menubar + + if {$::windowingsystem eq "win32"} {create_system_menu $::patch_menubar} + . configure -menu $::patch_menubar } proc ::pd_menus::configure_for_pdwindow {} { - variable menubar - # these are meaningless for the Pd window, so disable them - # File menu - $menubar.file entryconfigure [_ "Close"] -state disabled - $menubar.file entryconfigure [_ "Save"] -state disabled - $menubar.file entryconfigure [_ "Save As..."] -state normal - $menubar.file entryconfigure [_ "Print..."] -state disabled - - # Edit menu - $menubar.edit entryconfigure [_ "Paste Replace"] -state disabled - $menubar.edit entryconfigure [_ "Duplicate"] -state disabled - $menubar.edit entryconfigure [_ "Font"] -state normal - $menubar.edit entryconfigure [_ "Zoom In"] -state disabled - $menubar.edit entryconfigure [_ "Zoom Out"] -state disabled - $menubar.edit entryconfigure [_ "Tidy Up"] -state disabled - $menubar.edit entryconfigure [_ "(Dis)Connect Selection"] -state disabled - $menubar.edit entryconfigure [_ "Triggerize"] -state disabled - $menubar.edit entryconfigure [_ "Edit Mode"] -state disabled pdtk_canvas_editmode .pdwindow 0 - # Undo/Redo change names, they need to have the asterisk (*) after - $menubar.edit entryconfigure 0 -state disabled -label [_ "Undo"] - $menubar.edit entryconfigure 1 -state disabled -label [_ "Redo"] - # disable everything on the Put menu - for {set i 0} {$i <= [$menubar.put index end]} {incr i} { - # catch errors that happen when trying to disable separators - catch {$menubar.put entryconfigure $i -state disabled } - } # Help menu if {$::windowingsystem eq "aqua"} { - ::pd_menus::reenable_help_items_aqua $menubar + ::pd_menus::reenable_help_items_aqua $::patch_menubar } } proc ::pd_menus::configure_for_canvas {mytoplevel} { - variable menubar - # File menu - $menubar.file entryconfigure [_ "Close"] -state normal - $menubar.file entryconfigure [_ "Save"] -state normal - $menubar.file entryconfigure [_ "Save As..."] -state normal - $menubar.file entryconfigure [_ "Print..."] -state normal - # Edit menu - $menubar.edit entryconfigure [_ "Paste Replace"] -state normal - $menubar.edit entryconfigure [_ "Duplicate"] -state normal - $menubar.edit entryconfigure [_ "Font"] -state normal - $menubar.edit entryconfigure [_ "Zoom In"] -state normal - $menubar.edit entryconfigure [_ "Zoom Out"] -state normal - $menubar.edit entryconfigure [_ "Tidy Up"] -state normal - $menubar.edit entryconfigure [_ "(Dis)Connect Selection"] -state normal - $menubar.edit entryconfigure [_ "Triggerize"] -state normal - $menubar.edit entryconfigure [_ "Edit Mode"] -state normal pdtk_canvas_editmode $mytoplevel $::editmode($mytoplevel) - # Put menu - for {set i 0} {$i <= [$menubar.put index end]} {incr i} { - # catch errors that happen when trying to disable separators - if {[$menubar.put type $i] ne "separator"} { - $menubar.put entryconfigure $i -state normal - } - } update_undo_on_menu $mytoplevel $::undo_actions($mytoplevel) $::redo_actions($mytoplevel) # Help menu if {$::windowingsystem eq "aqua"} { - ::pd_menus::reenable_help_items_aqua $menubar + ::pd_menus::reenable_help_items_aqua $::patch_menubar } } proc ::pd_menus::configure_for_dialog {mytoplevel} { - variable menubar - # these are meaningless for the dialog panels, so disable them except for - # the ones that make sense in the Find dialog panel and it's canvas - # File menu - $menubar.file entryconfigure [_ "Close"] -state disabled - if {$mytoplevel eq ".find"} { - # these bindings are passed through Find to it's target search window - $menubar.file entryconfigure [_ "Save As..."] -state disabled - if {$mytoplevel ne ".pdwindow"} { - # these don't do anything in the pdwindow - $menubar.file entryconfigure [_ "Save"] -state disabled - $menubar.file entryconfigure [_ "Print..."] -state disabled - } - } else { - $menubar.file entryconfigure [_ "Save"] -state disabled - $menubar.file entryconfigure [_ "Save As..."] -state disabled - $menubar.file entryconfigure [_ "Print..."] -state disabled - } - - # Edit menu - $menubar.edit entryconfigure [_ "Font"] -state disabled - $menubar.edit entryconfigure [_ "Paste Replace"] -state disabled - $menubar.edit entryconfigure [_ "Duplicate"] -state disabled - $menubar.edit entryconfigure [_ "Zoom In"] -state disabled - $menubar.edit entryconfigure [_ "Zoom Out"] -state disabled - $menubar.edit entryconfigure [_ "Tidy Up"] -state disabled - $menubar.edit entryconfigure [_ "(Dis)Connect Selection"] -state disabled - $menubar.edit entryconfigure [_ "Triggerize"] -state disabled - $menubar.edit entryconfigure [_ "Edit Mode"] -state disabled pdtk_canvas_editmode $mytoplevel 0 - # Undo/Redo change names, they need to have the asterisk (*) after - $menubar.edit entryconfigure 0 -state disabled -label [_ "Undo"] - $menubar.edit entryconfigure 1 -state disabled -label [_ "Redo"] - # disable everything on the Put menu - for {set i 0} {$i <= [$menubar.put index end]} {incr i} { - # catch errors that happen when trying to disable separators - catch {$menubar.put entryconfigure $i -state disabled } - } + # Help menu if {$::windowingsystem eq "aqua"} { - ::pd_menus::reenable_help_items_aqua $menubar + ::pd_menus::reenable_help_items_aqua $::patch_menubar + } +} + +proc ::pd_menus::menubar_for_dialog {mytoplevel} { + set menubar $::dialog_menubar + if {$::windowingsystem eq "aqua"} { + set menubar $::pdwindow_menubar } + $mytoplevel configure -menu $menubar } # ------------------------------------------------------------------------------ # menu building functions -proc ::pd_menus::build_file_menu {mymenu} { - # run the platform-specific build_file_menu_* procs first, and config them - [format build_file_menu_%s $::windowingsystem] $mymenu - $mymenu entryconfigure [_ "New"] -command {::pd_menucommands::scheduleAction menu_new} - $mymenu entryconfigure [_ "Open"] -command {::pd_menucommands::scheduleAction menu_open} - $mymenu entryconfigure [_ "Save"] -command {::pd_menucommands::scheduleAction menu_send $::focused_window menusave} - $mymenu entryconfigure [_ "Save As..."] -command {::pd_menucommands::scheduleAction menu_send $::focused_window menusaveas} - #$mymenu entryconfigure [_ "Revert*"] -command {::pd_menucommands::scheduleAction menu_revert $::focused_window} - $mymenu entryconfigure [_ "Close"] -command {::pd_menucommands::scheduleAction ::pd_bindings::window_close $::focused_window} - $mymenu entryconfigure [_ "Message..."] -command {::pd_menucommands::scheduleAction menu_message_dialog} - $mymenu entryconfigure [_ "Print..."] -command {::pd_menucommands::scheduleAction menu_print $::focused_window} - # update recent files - if {[llength $::recentfiles_list] > 0} { - ::pd_menus::update_recentfiles_menu false +proc ::pd_menus::build_file_menu {mymenu {patchwindow true}} { + variable accelerator + $mymenu add command -label [_ "New"] -accelerator "$accelerator+N" -command {::pd_menucommands::scheduleAction menu_new} + $mymenu add command -label [_ "Open"] -accelerator "$accelerator+O" -command {::pd_menucommands::scheduleAction menu_open} + + $mymenu add cascade -label [_ "Open Recent"] -menu .openrecent + $mymenu add separator + $mymenu add command -label [_ "Close"] -accelerator "$accelerator+W" -command {::pd_menucommands::scheduleAction ::pd_bindings::window_close $::focused_window} + if { $patchwindow } { + $mymenu add command -label [_ "Save"] -accelerator "$accelerator+S" -command {::pd_menucommands::scheduleAction menu_send $::focused_window menusave} + } + $mymenu add command -label [_ "Save As..."] -accelerator "Shift+$accelerator+S" -command {::pd_menucommands::scheduleAction menu_send $::focused_window menusaveas} + #$mymenu add command -label [_ "Save All"] + #$mymenu add command -label [_ "Revert to Saved"] -command {::pd_menucommands::scheduleAction menu_revert $::focused_window} + $mymenu add separator + if {$::windowingsystem ne "aqua"} { + $mymenu add cascade -label [_ "Preferences"] -menu .preferences + } + if { $patchwindow } { + $mymenu add command -label [_ "Print..."] -accelerator "$accelerator+P" -command {::pd_menucommands::scheduleAction menu_print $::focused_window} + } + $mymenu add separator + if {$::windowingsystem ne "aqua"} { + $mymenu add command -label [_ "Quit"] -accelerator "$accelerator+Q" \ + -command {::pd_connect::menu_quit} } + + # update recent files + ::pd_menus::update_recentfiles_menu false } -proc ::pd_menus::build_edit_menu {mymenu} { +proc ::pd_menus::build_edit_menu {mymenu {patchwindow true}} { variable accelerator + if { $patchwindow } { $mymenu add command -label [_ "Undo"] -accelerator "$accelerator+Z" \ -command {::pd_menucommands::scheduleAction menu_undo} $mymenu add command -label [_ "Redo"] -accelerator "Shift+$accelerator+Z" \ @@ -198,25 +161,28 @@ proc ::pd_menus::build_edit_menu {mymenu} { -command {::pd_menucommands::scheduleAction menu_send $::focused_window copy} $mymenu add command -label [_ "Paste"] -accelerator "$accelerator+V" \ -command {::pd_menucommands::scheduleAction menu_send $::focused_window paste} - $mymenu add command -label [_ "Duplicate"] -accelerator "$accelerator+D" \ - -command {::pd_menucommands::scheduleAction menu_send $::focused_window duplicate} $mymenu add command -label [_ "Paste Replace" ] \ -command {::pd_menucommands::scheduleAction menu_send $::focused_window paste-replace} + $mymenu add separator $mymenu add command -label [_ "Select All"] -accelerator "$accelerator+A" \ -command {::pd_menucommands::scheduleAction menu_send $::focused_window selectall} $mymenu add separator - $mymenu add command -label [_ "Font"] \ - -command {::pd_menucommands::scheduleAction menu_font_dialog} - $mymenu add command -label [_ "Zoom In"] -accelerator "$accelerator++" \ - -command {::pd_menucommands::scheduleAction menu_send_float $::focused_window zoom 2} - $mymenu add command -label [_ "Zoom Out"] -accelerator "$accelerator+-" \ - -command {::pd_menucommands::scheduleAction menu_send_float $::focused_window zoom 1} + $mymenu add command -label [_ "Duplicate"] -accelerator "$accelerator+D" \ + -command {::pd_menucommands::scheduleAction menu_send $::focused_window duplicate} $mymenu add command -label [_ "Tidy Up"] -accelerator "$accelerator+Shift+R" \ -command {::pd_menucommands::scheduleAction menu_send $::focused_window tidy} $mymenu add command -label [_ "(Dis)Connect Selection"] -accelerator "$accelerator+K" \ -command {::pd_menucommands::scheduleAction menu_send $::focused_window connect_selection} $mymenu add command -label [_ "Triggerize"] -accelerator "$accelerator+T" \ -command {::pd_menucommands::scheduleAction menu_send $::focused_window triggerize} + $mymenu add separator + $mymenu add command -label [_ "Font"] \ + -command {::pd_menucommands::scheduleAction menu_font_dialog} + $mymenu add command -label [_ "Zoom In"] -accelerator "$accelerator++" \ + -command {::pd_menucommands::scheduleAction menu_send_float $::focused_window zoom 2} + $mymenu add command -label [_ "Zoom Out"] -accelerator "$accelerator+-" \ + -command {::pd_menucommands::scheduleAction menu_send_float $::focused_window zoom 1} + $mymenu add separator $mymenu add command -label [_ "Clear Console"] \ -accelerator "Shift+$accelerator+L" -command {::pd_menucommands::scheduleAction menu_clear_console} $mymenu add separator @@ -224,6 +190,26 @@ proc ::pd_menus::build_edit_menu {mymenu} { $mymenu add check -label [_ "Edit Mode"] -accelerator "$accelerator+E" \ -variable ::editmode_button \ -command {::pd_menucommands::scheduleAction menu_editmode $::editmode_button} + + } else { + $mymenu add command -label [_ "Cut"] -accelerator "$accelerator+X" \ + -state disabled \ + -command {::pd_menucommands::scheduleAction menu_send $::focused_window cut} + $mymenu add command -label [_ "Copy"] -accelerator "$accelerator+C" \ + -command {::pd_menucommands::scheduleAction menu_send $::focused_window copy} + $mymenu add command -label [_ "Paste"] -accelerator "$accelerator+V" \ + -state disabled \ + -command {::pd_menucommands::scheduleAction menu_send $::focused_window paste} + $mymenu add separator + $mymenu add command -label [_ "Select All"] -accelerator "$accelerator+A" \ + -command {::pd_menucommands::scheduleAction menu_send $::focused_window selectall} + $mymenu add separator + $mymenu add command -label [_ "Font"] \ + -command {::pd_menucommands::scheduleAction menu_font_dialog} + $mymenu add separator + $mymenu add command -label [_ "Clear Console"] \ + -accelerator "Shift+$accelerator+L" -command {::pd_menucommands::scheduleAction menu_clear_console} + } } proc ::pd_menus::build_put_menu {mymenu} { @@ -269,12 +255,14 @@ proc ::pd_menus::build_put_menu {mymenu} { -command {::pd_menucommands::scheduleAction menu_send $::focused_window menuarray} } -proc ::pd_menus::build_find_menu {mymenu} { +proc ::pd_menus::build_find_menu {mymenu {patchwindow true}} { variable accelerator $mymenu add command -label [_ "Find..."] -accelerator "$accelerator+F" \ -command {::pd_menucommands::scheduleAction menu_find_dialog} + if { $patchwindow } { $mymenu add command -label [_ "Find Again"] -accelerator "$accelerator+G" \ -command {::pd_menucommands::scheduleAction menu_send $::focused_window findagain} + } $mymenu add command -label [_ "Find Last Error"] \ -command {::pd_menucommands::scheduleAction pdsend {pd finderror}} } @@ -340,6 +328,8 @@ proc ::pd_menus::build_window_menu {mymenu} { -command {::pd_menucommands::scheduleAction menu_raisepreviouswindow} \ -accelerator [_ "$accelerator+Page Up"] } + $mymenu add command -label [_ "Close subwindows"] \ + -command {pdsend "pd close-subwindows"} $mymenu add separator $mymenu add command -label [_ "Pd window"] -command {::pd_menucommands::scheduleAction menu_raise_pdwindow} \ -accelerator "$accelerator+R" @@ -348,6 +338,14 @@ proc ::pd_menus::build_window_menu {mymenu} { $mymenu add separator } +proc ::pd_menus::build_tools_menu {mymenu} { + variable accelerator + + $mymenu add command -label [_ "Message..."] \ + -accelerator "$accelerator+Shift+M" \ + -command {::pd_menucommands::scheduleAction menu_message_dialog} +} + proc ::pd_menus::build_help_menu {mymenu} { variable accelerator if {$::windowingsystem ne "aqua"} { @@ -376,33 +374,27 @@ proc ::pd_menus::build_help_menu {mymenu} { # undo/redo menu items proc ::pd_menus::update_undo_on_menu {mytoplevel undo redo} { - variable menubar if {$undo eq "no"} { set undo "" } if {$redo eq "no"} { set redo "" } if {$undo ne ""} { - $menubar.edit entryconfigure 0 -state normal \ + $::patch_menubar.edit entryconfigure 0 -state normal \ -label [_ "Undo $undo"] } else { - $menubar.edit entryconfigure 0 -state disabled -label [_ "Undo"] + $::patch_menubar.edit entryconfigure 0 -state disabled -label [_ "Undo"] } if {$redo ne ""} { - $menubar.edit entryconfigure 1 -state normal \ + $::patch_menubar.edit entryconfigure 1 -state normal \ -label [_ "Redo $redo"] } else { - $menubar.edit entryconfigure 1 -state disabled -label [_ "Redo"] + $::patch_menubar.edit entryconfigure 1 -state disabled -label [_ "Redo"] } } # ------------------------------------------------------------------------------ # update the menu entries for opening recent files (write arg should always be true except the first time when pd is opened) proc ::pd_menus::update_recentfiles_menu {{write true}} { - variable menubar - switch -- $::windowingsystem { - "aqua" {::pd_menus::update_openrecent_menu_aqua .openrecent $write} - "win32" {::pd_menus::update_recentfiles_on_menu $menubar.file $write} - "x11" {::pd_menus::update_recentfiles_on_menu $menubar.file $write} - } + ::pd_menus::update_openrecent_menu .openrecent $write } proc ::pd_menus::clear_recentfiles_menu {} { @@ -411,55 +403,36 @@ proc ::pd_menus::clear_recentfiles_menu {} { ::pd_menus::update_recentfiles_menu } -proc ::pd_menus::update_openrecent_menu_aqua {mymenu {write}} { - if {! [winfo exists $mymenu]} {menu $mymenu} - $mymenu delete 0 end +proc ::pd_menus::update_openrecent_menu {mymenu {write}} { + if {! [winfo exists $mymenu]} { + menu $mymenu + } + $mymenu delete 0 end - # now the list is last first so we just add + set i 1 foreach filename $::recentfiles_list { - $mymenu add command -label [file tail $filename] \ - -command "::pd_menucommands::scheduleAction open_file {$filename}" + set label [file tail $filename] + if {$::windowingsystem ne "aqua"} { + set label "$i. $label" + } + $mymenu add command \ + -label $label -underline 0 \ + -command [list ::pd_menucommands::scheduleAction open_file ${filename}] + incr i } - # clear button - $mymenu add separator + $mymenu add separator $mymenu add command -label [_ "Clear Menu"] \ -command {::pd_menucommands::scheduleAction ::pd_menus::clear_recentfiles_menu} - # write to config file - if {$write == true} { ::pd_guiprefs::write_recentfiles } -} -# ------------------------------------------------------------------------------ -# this expects to be run on the File menu, and to insert above the last separator -proc ::pd_menus::update_recentfiles_on_menu {mymenu {write}} { - set lastitem [$mymenu index end] - set i 1 - while {[$mymenu type [expr $lastitem-$i]] ne "separator"} {incr i} - set bottom_separator [expr $lastitem-$i] - incr i - - while {[$mymenu type [expr $lastitem-$i]] ne "separator"} {incr i} - set top_separator [expr $lastitem-$i] - if {$top_separator < [expr $bottom_separator-1]} { - $mymenu delete [expr $top_separator+1] [expr $bottom_separator-1] - } - # insert the list from the end because we insert each element on the top - set i [llength $::recentfiles_list] - while {[incr i -1] > -1} { - set filename [lindex $::recentfiles_list $i] - set j [expr $i + 1] - if {$::windowingsystem eq "aqua"} { - set label [file tail $filename] - } else { - set label [concat "$j. " [file tail $filename]] - } - $mymenu insert [expr $top_separator+1] command \ - -label $label -command "::pd_menucommands::scheduleAction open_file {$filename}" -underline 0 + if {[llength $::recentfiles_list] == 0} { + $mymenu entryconfigure end -state disabled } # write to config file if {$write == true} { ::pd_guiprefs::write_recentfiles } } + # ------------------------------------------------------------------------------ # lots of crazy recursion to update the Window menu @@ -571,7 +544,7 @@ proc ::pd_menus::forgetpreferences {} { } } -proc ::pd_menus::create_preferences_menu {mymenu} { +proc ::pd_menus::build_preferences_menu {mymenu} { menu $mymenu $mymenu add command -label [_ "Edit Preferences..."] \ -command {menu_preference_dialog} @@ -599,40 +572,12 @@ proc ::pd_menus::create_apple_menu {mymenu} { menu $mymenu.apple $mymenu.apple add command -label [_ "About Pd"] -command {::pd_menucommands::scheduleAction menu_aboutpd} $mymenu.apple add separator - create_preferences_menu $mymenu.apple.preferences $mymenu.apple add cascade -label [_ "Preferences"] \ - -menu $mymenu.apple.preferences + -menu .preferences # this needs to be last for things to function properly $mymenu add cascade -label "Apple" -menu $mymenu.apple } -proc ::pd_menus::build_file_menu_aqua {mymenu} { - variable accelerator - $mymenu add command -label [_ "New"] -accelerator "$accelerator+N" - $mymenu add command -label [_ "Open"] -accelerator "$accelerator+O" - # this is now done in main ::pd_menus::build_file_menu - #::pd_menus::update_openrecent_menu_aqua .openrecent - $mymenu add cascade -label [_ "Open Recent"] -menu .openrecent - $mymenu add separator - $mymenu add command -label [_ "Close"] -accelerator "$accelerator+W" - $mymenu add command -label [_ "Save"] -accelerator "$accelerator+S" - $mymenu add command -label [_ "Save As..."] -accelerator "$accelerator+Shift+S" - #$mymenu add command -label [_ "Save All"] - #$mymenu add command -label [_ "Revert to Saved"] - $mymenu add separator - $mymenu add command -label [_ "Message..."] -accelerator "$accelerator+Shift+M" - $mymenu add separator - $mymenu add command -label [_ "Print..."] -accelerator "$accelerator+P" -} - -# the "Edit", "Put", and "Find" menus do not have cross-platform differences - -proc ::pd_menus::build_media_menu_aqua {mymenu} { -} - -proc ::pd_menus::build_window_menu_aqua {mymenu} { -} - # FIXME: remove this when it is no longer necessary # there is a Tk Cocoa bug where Help menu items after separators may be # disabled after windows are cycled, as of Nov 2020 this is fixed via a fresh @@ -645,40 +590,6 @@ proc ::pd_menus::reenable_help_items_aqua {mymenu} { #} } -# ------------------------------------------------------------------------------ -# menu building functions for UNIX/X11 - -proc ::pd_menus::build_file_menu_x11 {mymenu} { - variable accelerator - $mymenu add command -label [_ "New"] -accelerator "$accelerator+N" - $mymenu add command -label [_ "Open"] -accelerator "$accelerator+O" - $mymenu add separator - $mymenu add command -label [_ "Save"] -accelerator "$accelerator+S" - $mymenu add command -label [_ "Save As..."] -accelerator "Shift+$accelerator+S" - # $mymenu add command -label "Revert" - $mymenu add separator - $mymenu add command -label [_ "Message..."] -accelerator "$accelerator+Shift+M" - create_preferences_menu $mymenu.preferences - $mymenu add cascade -label [_ "Preferences"] -menu $mymenu.preferences - $mymenu add command -label [_ "Print..."] -accelerator "$accelerator+P" - $mymenu add separator - # the recent files get inserted in here by update_recentfiles_on_menu - $mymenu add separator - $mymenu add command -label [_ "Close"] -accelerator "$accelerator+W" - $mymenu add command -label [_ "Quit"] -accelerator "$accelerator+Q" \ - -command {::pd_connect::menu_quit} -} - -# the "Edit", "Put", and "Find" menus do not have cross-platform differences - -proc ::pd_menus::build_media_menu_x11 {mymenu} { -} - -proc ::pd_menus::build_window_menu_x11 {mymenu} { -} - -# the "Help" does not have cross-platform differences - # ------------------------------------------------------------------------------ # menu building functions for Windows/Win32 @@ -694,34 +605,3 @@ proc ::pd_menus::create_system_menu {mymenubar} { # http://wiki.tcl.tk/1006 # TODO add Edit Mode here } - -proc ::pd_menus::build_file_menu_win32 {mymenu} { - variable accelerator - $mymenu add command -label [_ "New"] -accelerator "$accelerator+N" - $mymenu add command -label [_ "Open"] -accelerator "$accelerator+O" - $mymenu add separator - $mymenu add command -label [_ "Save"] -accelerator "$accelerator+S" - $mymenu add command -label [_ "Save As..."] -accelerator "Shift+$accelerator+S" - # $mymenu add command -label "Revert" - $mymenu add separator - $mymenu add command -label [_ "Message..."] -accelerator "$accelerator+Shift+M" - create_preferences_menu $mymenu.preferences - $mymenu add cascade -label [_ "Preferences"] -menu $mymenu.preferences - $mymenu add command -label [_ "Print..."] -accelerator "$accelerator+P" - $mymenu add separator - # the recent files get inserted in here by update_recentfiles_on_menu - $mymenu add separator - $mymenu add command -label [_ "Close"] -accelerator "$accelerator+W" - $mymenu add command -label [_ "Quit"] -accelerator "$accelerator+Q" \ - -command {::pd_connect::menu_quit} -} - -# the "Edit", "Put", and "Find" menus do not have cross-platform differences - -proc ::pd_menus::build_media_menu_win32 {mymenu} { -} - -proc ::pd_menus::build_window_menu_win32 {mymenu} { -} - -# the "Help" does not have cross-platform differences diff --git a/tcl/pdtk_canvas.tcl b/tcl/pdtk_canvas.tcl index e32392de82..f57181e16f 100644 --- a/tcl/pdtk_canvas.tcl +++ b/tcl/pdtk_canvas.tcl @@ -98,7 +98,8 @@ proc pdtk_canvas_place_window {width height geometry} { #------------------------------------------------------------------------------# # canvas new/saveas -proc pdtk_canvas_new {mytoplevel width height geometry editable} { +proc pdtk_canvas_new {mytoplevel width height geometry editable \ + {bgcolor "white"} } { if { "" eq $geometry } { # no position set: this is a new window (rather than one loaded from file) # we set a flag here, so we can query (and report) the actual geometry, @@ -134,7 +135,7 @@ proc pdtk_canvas_new {mytoplevel width height geometry editable} { -highlightthickness 0 -scrollregion [list 0 0 $width $height] \ -xscrollcommand "$mytoplevel.xscroll set" \ -yscrollcommand "$mytoplevel.yscroll set" \ - -background white + -background $bgcolor scrollbar $mytoplevel.xscroll -orient horizontal -command "$tkcanvas xview" scrollbar $mytoplevel.yscroll -orient vertical -command "$tkcanvas yview" pack $tkcanvas -side left -expand 1 -fill both diff --git a/tcl/pdwindow.tcl b/tcl/pdwindow.tcl index 5fd93fc8c5..d168eb69c7 100644 --- a/tcl/pdwindow.tcl +++ b/tcl/pdwindow.tcl @@ -223,7 +223,7 @@ proc ::pdwindow::save_logbuffer_to_file {} { set filename [tk_getSaveFile -initialfile "pdwindow.txt" -defaultextension .txt -parent .pdwindow] if {$filename eq ""} return; # they clicked cancel set f [open $filename w] - puts $f "Pd $::PD_MAJOR_VERSION.$::PD_MINOR_VERSION-$::PD_BUGFIX_VERSION$::PD_TEST_VERSION on $::tcl_platform(os) $::tcl_platform(machine)" + puts $f "$::PD_APPLICATION_NAME $::PD_MAJOR_VERSION.$::PD_MINOR_VERSION-$::PD_BUGFIX_VERSION$::PD_TEST_VERSION on $::tcl_platform(os) $::tcl_platform(machine)" puts $f "--------------------------------------------------------------------------------" foreach logentry $logbuffer { foreach {object_id level message} $logentry { @@ -336,7 +336,10 @@ proc ::pdwindow::message_contextmenu {widget theX theY obj} { #--create the window-----------------------------------------------------------# proc ::pdwindow::update_title {w} { + # leave the next line for the translations set title [_ "Pd" ] + # override with the default application name + set title [_ "${::PD_APPLICATION_NAME}" ] set version "${::PD_MAJOR_VERSION}.${::PD_MINOR_VERSION}.${::PD_BUGFIX_VERSION}${::PD_TEST_VERSION}" set fulltitle "${title} ${version}" if { [info exists ::deken::platform(floatsize)] } { @@ -477,5 +480,5 @@ proc ::pdwindow::create_window_finalize {} { # this needs to happen *after* the main menu is created, otherwise the default Wish # menu is not replaced by the custom Apple menu on OSX proc ::pdwindow::configure_menubar {} { - .pdwindow configure -menu .menubar + .pdwindow configure -menu $::pdwindow_menubar } diff --git a/tcl/pkgIndex.tcl b/tcl/pkgIndex.tcl index 87d465c734..8c607ebd0c 100644 --- a/tcl/pkgIndex.tcl +++ b/tcl/pkgIndex.tcl @@ -22,7 +22,7 @@ package ifneeded dialog_message 0.1 [list source [file join $dir dialog_message. package ifneeded dialog_midi 0.1 [list source [file join $dir dialog_midi.tcl]] package ifneeded dialog_path 0.1 [list source [file join $dir dialog_path.tcl]] package ifneeded dialog_startup 0.1 [list source [file join $dir dialog_startup.tcl]] -package ifneeded helpbrowser 0.2 [list source [file join $dir helpbrowser.tcl]] +package ifneeded helpbrowser 0.3 [list source [file join $dir helpbrowser.tcl]] package ifneeded opt_parser 0.1 [list source [file join $dir opt_parser.tcl]] package ifneeded pd_bindings 0.1 [list source [file join $dir pd_bindings.tcl]] package ifneeded pd_connect 0.1 [list source [file join $dir pd_connect.tcl]] diff --git a/tcl/preferencewindow.tcl b/tcl/preferencewindow.tcl index d977cef54f..37b9c71c6c 100644 --- a/tcl/preferencewindow.tcl +++ b/tcl/preferencewindow.tcl @@ -75,7 +75,6 @@ proc ::preferencewindow::fail {args} { # winid -- the window id to use # title -- top-level title for the dialog # width, height -- initial width and height dimensions for the window, also minimum size -# resizable -- 0 or 1, set to 1 for dialog to be resizeable proc ::preferencewindow::create {winid title {dimen {0 0}}} { wm deiconify .pdwindow raise .pdwindow diff --git a/tcl/scrollboxwindow.tcl b/tcl/scrollboxwindow.tcl index 2b0ac7c0e3..60172eb8e7 100644 --- a/tcl/scrollboxwindow.tcl +++ b/tcl/scrollboxwindow.tcl @@ -58,8 +58,8 @@ proc ::scrollboxwindow::ok {mytoplevel commit_method } { # resizable -- 0 or 1, set to 1 for dialog to be resizeable proc ::scrollboxwindow::make {mytoplevel listdata add_method edit_method commit_method title width height resizable } { ::preferencewindow::create ${mytoplevel} ${title} [list $width $height] - if {$resizable == 0} { - wm resizable $winid 0 0 + if {${resizable} == 0} { + wm resizable ${mytoplevel} 0 0 } set my [::preferencewindow::add_frame ${mytoplevel} "${title}" ] @@ -67,7 +67,6 @@ proc ::scrollboxwindow::make {mytoplevel listdata add_method edit_method commit_ ::preferencewindow::add_apply ${mytoplevel} "::scrollboxwindow::apply ${my} ${commit_method}" ::preferencewindow::add_apply ${mytoplevel} {pdsend "pd save-preferences"} - # Add the scrollbox widget ::scrollbox::make ${my} ${listdata} ${add_method} ${edit_method} }