-
Notifications
You must be signed in to change notification settings - Fork 0
/
lang_doc.py
914 lines (909 loc) · 199 KB
/
lang_doc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
null = None; true = True; false = False;
#\#/#\#/#\#/#\#/#\#/#\#/#\#/#\#/#\#/#\#/
funct_doc = {
"set": {
"summary": "Store information in the Time State",
"doc": "Store information in the Time State for the current time for either the current or any other thread. If called multiple times without an intervening call to `sleep`, `sync`, `set` or `cue`, the last value set will prevail. The value will remain in the Time State until overwritten by another call to `set`, or until Sonic Pi quits.\nMay be used within a `time_warp` to set past/future events. Does not affect time.",
"examples": " set :foo, 1 #=> Stores the value 1 with key :foo\",\n\n \"\n\nset :foo, 3 # Set :foo to 3\n\nget[:foo] #=> returns 3\",\n\n \"\n\nin_thread do\n\n set :foo, 3 # Set :foo to 3\n\nend\n\nin_thread do\n\n puts get[:foo] #=> always returns 3 (no race conditions here!)\n\nend\n\n"
},
"cue": {
"summary": "Cue other threads",
"doc": "Send a heartbeat synchronisation message containing the (virtual) timestamp of the current thread. Useful for syncing up external threads via the `sync` fn. Any opts which are passed are given to the thread which syncs on the `cue_id`. The values of the opts must be immutable. Currently numbers, symbols, booleans, nil and frozen strings, or vectors/rings/frozen arrays/maps of immutable values are supported.",
"examples": " in_thread do\n\n sync :foo # this parks the current thread waiting for a foo cue message to be received.\n\n sample :ambi_lunar_land\n\n end\n\n sleep 5\n\n cue :foo # We send a cue message from the main thread.\n\n # This then unblocks the thread above and we then hear the sample\",\n\n \"\n\n in_thread do # Start a metronome thread\n\n loop do # Loop forever:\n\n cue :tick # sending tick heartbeat messages\n\n sleep 0.5 # and sleeping for 0.5 beats between ticks\n\n end\n\n end\n\n # We can now play sounds using the metronome.\n\n loop do # In the main thread, just loop\n\n sync :tick # waiting for :tick cue messages\n\n sample :drum_heavy_kick # after which play the drum kick sample\n\n end\",\n\n \"\n\n in_thread do # Start a metronome thread\n\n loop do # Loop forever:\n\n cue [:foo, :bar, :baz].choose # sending one of three tick heartbeat messages randomly\n\n sleep 0.5 # and sleeping for 0.5 beats between ticks\n\n end\n\n end\n\n # We can now play sounds using the metronome:\n\n in_thread do\n\n loop do # In the main thread, just loop\n\n sync :foo # waiting for :foo cue messages\n\n sample :elec_beep # after which play the elec beep sample\n\n end\n\n end\n\n in_thread do\n\n loop do # In the main thread, just loop\n\n sync :bar # waiting for :bar cue messages\n\n sample :elec_flip # after which play the elec flip sample\n\n end\n\n end\n\n in_thread do\n\n loop do # In the main thread, just loop\n\n sync :baz # waiting for :baz cue messages\n\n sample :elec_blup # after which play the elec blup sample\n\n end\n\n end\",\n\n \"\n\n in_thread do\n\n loop do\n\n cue :tick, foo: 64 # sending tick heartbeat messages with a value :foo\n\n sleep 0.5\n\n end\n\n end\n\n # The value for :foo can now be used in synced threads\n\n loop do\n\n values = sync :tick\n\n play values[:foo] # play the note value from :foo\n\n end"
},
"get": {
"summary": "Get information from the Time State",
"doc": "Retrieve information from Time State set prior to the current time from either the current or any other thread. If called multiple times will always return the same value unless a call to `sleep`, `sync`, `set` or `cue` is interleaved. Also, calls to `get` will always return the same value across Runs for deterministic behaviour - which means you may safely use it in your compositions for repeatable music. If no value is stored with the relevant key, will return `nil`.\nMay be used within a `time_warp` to retrieve past events. If in a time warp, `get` can not be called from a future position. Does not advance time.",
"examples": " get :foo #=> returns the last value set as :foo, or nil\",\n\n \"\n\nset :foo, 3\n\nget[:foo] #=> returns 3\",\n\n \"\n\nin_thread do\n\n set :foo, 3\n\nend\n\nin_thread do\n\n puts get[:foo] #=> always returns 3 (no race conditions here!)\n\nend\n\n"
},
"with_swing": {
"summary": "Add swing to successive calls to do/end block",
"doc": "Runs block within a `time_warp` except for once every `pulse` consecutive runs (defaulting to 4). When used for rhythmical purposes this results in one in every `pulse` calls of the block being 'on beat' and the rest shifted forward or backwards in time by `shift` beats.",
"examples": "live_loop :foo do\n\n with_swing 0.1 do\n\n sample :elec_beep # plays the :elec_beep sample late except for every 4th time\n\n end\n\n sleep 0.25\n\nend\n\n\",\n\n \"\n\nlive_loop :foo do\n\n with_swing -0.1 do\n\n sample :elec_beep # plays the :elec_beep sample slightly early\n\n end # except for every 4th time\n\n sleep 0.25\n\nend\n\n\",\n\n \"\n\nlive_loop :foo do\n\n with_swing -0.1, pulse: 8 do\n\n sample :elec_beep # plays the :elec_beep sample slightly early\n\n end # except for every 8th time\n\n sleep 0.25\n\nend\n\n\",\n\n \"\n\n# Use unique tick names if you plan on using with_swing\n\n# more than once in any given live_loop or thread.\n\nlive_loop :foo do\n\n with_swing 0.14, tick: :a do\n\n sample :elec_beep # plays the :elec_beep sample slightly late\n\n end # except for every 4th time\n\n with_swing -0.1, tick: :b do\n\n sample :elec_beep, rate: 2 # plays the :elec_beep sample at double rate\n\n end # slightly early except for every 4th time\n\n sleep 0.25\n\nend\",\n\n \"\n\nlive_loop :foo do\n\n with_swing 0.1 do\n\n cue :tick # send out cue messages with swing timing\n\n end\n\n sleep 0.25\n\nend\n\nlive_loop :bar do\n\n sync :tick\n\n sample :elec_beep # sync on the swing cue messages to bring the swing into\n\n # another live loop (sync will match the timing and clock of\n\n # the sending live loop)\n\nend\n\n"
},
"run_file": {
"summary": "Evaluate the contents of the file as a new Run",
"doc": "Reads the full contents of the file with `path` and executes it in a new Run. This works as if the code in the file was in a buffer and Run button was pressed.",
"examples": "run_file \\\"~/path/to/sonic-pi-code.rb\\\" #=> will run the contents of this file"
},
"run_code": {
"summary": "Evaluate the code passed as a String as a new Run",
"doc": "Executes the code passed as a string in a new Run. This works as if the code was in a buffer and Run button was pressed.",
"examples": "run_code \\\"sample :ambi_lunar_land\\\" #=> will play the :ambi_lunar_land sample\",\n\n \"# Works with any amount of code:\n\nrun_code \\\"8.times do\\nplay 60\\nsleep 1\\nend\\\" # will play 60 8 times"
},
"eval_file": {
"summary": "Evaluate the contents of the file inline in the current thread like a function.",
"doc": "Reads the full contents of the file with `path` and executes within the current thread like a function call.",
"examples": "eval_file \\\"~/path/to/sonic-pi-code.rb\\\" #=> will run the contents of this file"
},
"use_osc_logging": {
"summary": "Enable and disable OSC logging",
"doc": "Enable or disable log messages created on OSC functions. This does not disable the OSC functions themselves, it just stops them from being printed to the log",
"examples": "use_osc_logging true # Turn on OSC logging\nuse_osc_logging false # Disable OSC logging"
},
"with_osc_logging": {
"summary": "Block-level enable and disable OSC logging",
"doc": "Similar to use_osc_logging except only applies to code within supplied `do`/`end` block. Previous OSC log value is restored after block.",
"examples": " # Turn on OSC logging:\n\n use_osc_logging true\n\n osc \\\"/foo\\\" # message is printed to log\n\n with_osc_logging false do\n\n #OSC logging is now disabled\n\n osc \\\"/foo\\\" # OSC message *is* sent but not displayed in log\n\n end\n\n sleep 1\n\n # Debug is re-enabled\n\n osc \\\"/foo\\\" # message is displayed in log\n\n "
},
"use_osc": {
"summary": "Set the default hostname and port number for outgoing OSC messages.",
"doc": "Sets the destination host and port that `osc` will send messages to. If no port number is specified - will default to port 4560 (Sonic Pi's default OSC listening port).\nOSC (Open Sound Control) is a simple way of passing messages between two separate programs on the same computer or even on different computers via a local network or even the internet. `use_osc` allows you to specify which computer (`hostname`) and program (`port`) to send messages to.\nIt is possible to send messages to the same computer by using the host name `\\\"localhost\\\"`\nThis is a thread-local setting - therefore each thread (or live loop) can have their own separate `use_osc` values.\nNote that calls to `osc_send` will ignore these values.\n",
"examples": " # Send a simple OSC message to another program on the same machine\n\nuse_osc \\\"localhost\\\", 7000 # Specify port 7000 on this machine\n\nosc \\\"/foo/bar\\\" # Send an OSC message with path \\\"/foo/bar\\\"\n\n # and no arguments\n\n\",\n\n\" # Send an OSC messages with arguments to another program on the same machine\n\nuse_osc \\\"localhost\\\", 7000 # Specify port 7000 on this machine\n\nosc \\\"/foo/bar\\\" 1, 3.89, \\\"baz\\\" # Send an OSC message with path \\\"/foo/bar\\\"\n\n # and three arguments:\n\n # 1) The whole number (integer) 1\n\n # 2) The fractional number (float) 3,89\n\n # 3) The string \\\"baz\\\"\n\n\",\n\n\" # Send an OSC messages with arguments to another program on a different machine\n\nuse_osc \\\"10.0.1.5\\\", 7000 # Specify port 7000 on the machine with address 10.0.1.5\n\nosc \\\"/foo/bar\\\" 1, 3.89, \\\"baz\\\" # Send an OSC message with path \\\"/foo/bar\\\"\n\n # and three arguments:\n\n # 1) The whole number (integer) 1\n\n # 2) The fractional number (float) 3,89\n\n # 3) The string \\\"baz\\\"\n\n\",\n\n\" # use_osc only affects calls to osc until the next call to use_osc\n\nuse_osc \\\"localhost\\\", 7000 # Specify port 7000 on this machine\n\nosc \\\"/foo/bar\\\" # Send an OSC message to port 7000\n\nosc \\\"/foo/baz\\\" # Send another OSC message to port 7000\n\nuse_osc \\\"localhost\\\", 7005 # Specify port 7000 on this machine\n\nosc \\\"/foo/bar\\\" # Send an OSC message to port 7005\n\nosc \\\"/foo/baz\\\" # Send another OSC message to port 7005\n\n\",\n\n\" # threads may have their own use_osc value\n\nuse_osc \\\"localhost\\\", 7000 # Specify port 7000 on this machine\n\nlive_loop :foo do\n\n osc \\\"/foo/bar\\\" # Thread inherits outside use_osc values\n\n sleep 1 # and therefore sends OSC messages to port 7000\n\nend\n\nlive_loop :bar do\n\n use_osc \\\"localhost\\\", 7005 # Override OSC hostname and port for just this\n\n # thread (live loop :bar). Live loop :foo is\n\n # unaffected.\n\n osc \\\"/foo/bar\\\" # Send OSC messages to port 7005\n\n sleep 1\n\nend\n\nuse_osc \\\"localhost\\\", 7010 # Specify port 7010\n\nosc \\\"/foo/baz\\\" # Send another OSC message to port 7010\n\n # Note that neither live loops :foo or :bar\n\n # are affected (their use_osc values are\n\n # independent and isolated.\n\n"
},
"with_osc": {
"summary": "Block-level setting for the default hostname and port number of outgoing OSC messages.",
"doc": "Sets the destination host and port that `osc` will send messages to for the given do/end block.",
"examples": "\n\nuse_osc \\\"localhost\\\", 7000 # Specify port 7010\n\nosc \\\"/foo/baz\\\" # Send an OSC message to port 7000\n\nwith_osc \\\"localhost\\\", 7010 do # set hostname and port for the duration\n\n # of this do/end block\n\n osc \\\"/foo/baz\\\" # Send an OSC message to port 7010\n\nend\n\nosc \\\"/foo/baz\\\" # Send an OSC message to port 7000\n\n # as old setting is restored outside\n\n # do/end block\n\n"
},
"osc_send": {
"summary": "Send an OSC message to a specific host and port",
"doc": "Similar to `osc` except ignores any `use_osc` settings and sends the OSC message directly to the specified `hostname` and `port`.\nSee `osc` for more information.",
"examples": "\n\nosc_send \\\"localhost\\\", 7000, \\\"/foo/baz\\\" # Send an OSC message to port 7000 on the same machine\n\n\",\n\n\"\n\nuse_osc \\\"localhost\\\", 7010 # set hostname and port\n\nosc \\\"/foo/baz\\\" # Send an OSC message to port 7010\n\nosc_send \\\"localhost\\\", 7000, \\\"/foo/baz\\\" # Send an OSC message to port 7000\n\n # (ignores use_osc settings)\n\n"
},
"osc": {
"summary": "Send an OSC message (Open Sound Control)",
"doc": "Sends an OSC message to the current host and port specified by `use_osc` or `with_osc`.\nOSC (Open Sound Control) is a simple way of passing messages between two separate programs on the same computer or even on different computers via a local network or even the internet. `osc` enables you to send well-timed OSC messages from within Sonic Pi. `osc` will ensure that the OSC message is sent at the correct time using the same timing system shared with the synthesis functionality via `sample`, `synth` and friends. `osc` even works seamlessly within `time_warp` - see examples.\nA typical OSC message has two parts: a descriptive `path` which looks simalar to a URL (website address), and an optional list of `arguments` that are either numbers or strings.\nFor example, a hypothetical synth program might accept this OSC message:\n`/set/filter lowpass 80 0.5`\nwhere `/set/filter` is the path, and `lowpass`, `80`, and `0.5` are three\narguments. This can be sent from within Sonic Pi by writing:\n`osc \\\"/set/filter\\\", \\\"lowpass\\\", 80, 0.5`\nHowever, in order to send the OSC message you must first specify where to send it to. This is achieved by specifying both the host (the machine's internet address) and the port that the remote OSC server is listening on. This is configured using `use_osc` or `with_osc`. So, if our synth program was running on a machine on the local network with IP address `10.0.1.5` on port `5100` we could send our OSC message to it with the following:\n`use_osc \\\"10.0.1.5\\\", 5100`\n`osc \\\"/set/filter\\\", \\\"lowpass\\\", 80, 0.5`\nNote, by default, Sonic Pi listens for OSC messages on port `4560`, so you may send messages to an external machine running Sonic Pi if you know the IP address of that external machine. Any OSC messages received on port `4559` are automatically converted to standard cue events and displayed in the GUI's cue log. This also means that you can use `sync` to wait for the next incoming OSC message with a given path (see example).\nFinally, it is also very useful to send OSC messages to aother programs on the same computer. This can be achieved by specifying \\\"localhost\\\" as the hostname and the port as normal (depending on which port the other program is listening on).\nSee `osc_send` for a version which allows you to specify the hostname and port directly (ignoring any values set via `use_osc` or `with_osc`).\nFor further information see the OSC spec: [http://opensoundcontrol.org/spec-1_0](http://opensoundcontrol.org/spec-1_0)\n",
"examples": " # Send a simple OSC message to another program on the same machine\n\nuse_osc \\\"localhost\\\", 7000 # Specify port 7000 on this machine\n\nosc \\\"/foo/bar\\\" # Send an OSC message with path \\\"/foo/bar\\\"\n\n # and no arguments\n\n\",\n\n\" # Send an OSC messages with arguments to another program on the same machine\n\nuse_osc \\\"localhost\\\", 7000 # Specify port 7000 on this machine\n\nosc \\\"/foo/bar\\\", 1, 3.89, \\\"baz\\\" # Send an OSC message with path \\\"/foo/bar\\\"\n\n # and three arguments:\n\n # 1) The whole number (integer) 1\n\n # 2) The fractional number (float) 3.89\n\n # 3) The string \\\"baz\\\"\n\n\",\n\n\" # Send an OSC messages with arguments to another program on a different machine\n\nuse_osc \\\"10.0.1.5\\\", 7000 # Specify port 7000 on the machine with address 10.0.1.5\n\nosc \\\"/foo/bar\\\", 1, 3.89, \\\"baz\\\" # Send an OSC message with path \\\"/foo/bar\\\"\n\n # and three arguments:\n\n # 1) The whole number (integer) 1\n\n # 2) The fractional number (float) 3.89\n\n # 3) The string \\\"baz\\\"\n\n\",\n\n\" # OSC messages honour the timing system\n\nosc \\\"/foo/bar\\\" # Send an OSC message with path /foo/bar at *exactly* the\n\nplay 60 # same time as note 60 is played\n\nsleep 1 # Wait for 1 beat\n\nosc \\\"/baz/quux\\\" # Send an OSC message with path /baz/quux at *exactly* the\n\nplay 72 # same time as note 72 is played\n\n\",\n\n\" # Send a incrementing OSC counter\n\nlive_loop :foo do # Start a live loop called :foo\n\n osc \\\"/counter\\\", tick # Send an OSC message with the path /counter\n\n # with successive whole numbers (0, 1, 2, 3.. etc.)\n\n # each time round the live loop\n\n sleep 1 # Repeat the live loop every 1 beat\n\nend\n\n\",\n\n\" # OSC messages can be sent from within time_warp\n\ntime_warp 0.5 do\n\n osc \\\"/foo/bar\\\" # Send an OSC message with path /foo/bar at 0.5 beats\n\nend\n\nsleep 1 # Wait for 1 beat\n\ntime_warp -0.1 do\n\n osc \\\"/baz/quux\\\" # Send an OSC message with path /baz/quux at 0.9 beats\n\nend\n\n"
},
"reset": {
"summary": "Reset all thread locals",
"doc": "All settings such as the current synth, BPM, random stream and tick values will be reset to the values inherited from the parent thread. Consider using `clear` to reset all these values to their defaults.",
"examples": "# Basic Reset\n\nuse_synth :blade\n\nuse_octave 3\n\nputs \\\"before\\\" #=> \\\"before\\\"\n\nputs current_synth #=> :blade\n\nputs current_octave #=> 3\n\nputs rand #=> 0.75006103515625\n\nputs tick #=> 0\n\nreset\n\nputs \\\"after\\\" #=> \\\"after\\\"\n\nputs current_synth #=> :beep\n\nputs current_octave #=> 0\n\nputs rand #=> 0.75006103515625\n\nputs tick #=> 0\",\n\n\"Reset remembers defaults from when the thread was created:\n\nuse_synth :blade\n\nuse_octave 3\n\nputs \\\"before\\\" #=> \\\"before\\\"\n\nputs current_synth #=> :blade\n\nputs current_octave #=> 3\n\nputs rand #=> 0.75006103515625\n\nputs tick #=> 0\n\nat do\n\n use_synth :tb303\n\n puts rand #=> 0.9287109375\n\n reset\n\n puts \\\"thread\\\" #=> \\\"thread\\\"\n\n # The call to reset ensured that the current\n\n # synth was returned to the the state at the\n\n # time this thread was started. Thus any calls\n\n # to use_synth between this line and the start\n\n # of the thread are ignored\n\n puts current_synth #=> :blade\n\n puts current_octave #=> 3\n\n # The call to reset ensured\n\n # that the random stream was reset\n\n # to the same state as it was when\n\n # the current thread was started\n\n puts rand #=> 0.9287109375\n\n puts tick #=> 0\n\nend"
},
"clear": {
"summary": "Clear all thread locals to defaults",
"doc": "All settings such as the current synth, BPM, random stream and tick values will be reset to their defaults. Consider using `reset` to reset all these values to those inherited from the parent thread.",
"examples": "Clear wipes out the threads locals\n\nuse_synth :blade\n\nuse_octave 3\n\nputs \\\"before\\\" #=> \\\"before\\\"\n\nputs current_synth #=> :blade\n\nputs current_octave #=> 3\n\nputs rand #=> 0.75006103515625\n\nputs tick #=> 0\n\nat do\n\n use_synth :tb303\n\n puts rand #=> 0.9287109375\n\n clear\n\n puts \\\"thread\\\" #=> \\\"thread\\\"\n\n # The clear reset the current synth to the default\n\n # of :beep. We are therefore ignoring any inherited\n\n # synth settings. It is as if the thread was a completely\n\n # new Run.\n\n puts current_synth #=> :beep\n\n # The current octave defaults back to 0\n\n puts current_octave #=> 0\n\n # The random stream defaults back to the standard\n\n # stream used by every new Run.\n\n puts rand #=> 0.75006103515625\n\n puts tick #=> 0\n\nend"
},
"time_warp": {
"summary": "Shift time forwards or backwards for the given block",
"doc": "The code within the given block is executed with the specified delta time shift specified in beats. For example, if the delta value is 0.1 then all code within the block is executed with a 0.1 beat delay. Negative values are allowed which means you can move a block of code *backwards in time*. For example a delta value of -0.1 will execute the code in the block 0.1 beats ahead of time. The time before the block started is restored after the execution of the block.\nGiven a list of times, run the block once after waiting each given time. If passed an optional params list, will pass each param individually to each block call. If size of params list is smaller than the times list, the param values will act as rings (rotate through). If the block is given 1 arg, the times are fed through. If the block is given 2 args, both the times and the params are fed through. A third block arg will receive the index of the time.\nNote that the code within the block is executed synchronously with the code before and after, so all thread locals will be modified inline - as is the case for `with_fx`. However, as time is always restored to the value before `time_warp` started, you can use it to schedule events for the future in a similar fashion to a thread (via `at` or `in_thread`) without having to use an entirely fresh and distinct set of thread locals - see examples.\nAlso, note that you cannot travel backwards in time beyond the `current_sched_ahead_time`.\nIf the `time_warp` block is within a `density` block, the delta time is not affected (although all the other times such as sleep and phase durations will be affected) - see example.\n`time_warp` is ahead-of-time scheduling within the current thread. See `at` for just-in-time scheduling using multiple isolated threads.",
"examples": "# shift forwards in timeplay 70 #=> plays at time 0\n\nsleep 1\n\nplay 75 #=> plays at time 1\n\ntime_warp 0.1 do\n\n # time shifts forward by 0.1 beats\n\n play 80 #=> plays at 1.1\n\n sleep 0.5\n\n play 80 #=> plays at 1.6\n\nend # time shifts back by 0.6 beats\n\n # we now honour the original sleep 1 and the\n\n # sleep 0.5 within the time_warp block is\n\n # ignored including the 0.1 shift offset\n\nplay 70 #=> plays at 1\",\n\n \"# shift backwards in time\n\nplay 70 #=> plays at time 0\n\nsleep 1\n\nplay 75 #=> plays at time 1\n\ntime_warp -0.1 do\n\n # time shifts backwards by 0.1 beats\n\n play 80 #=> plays at 0.9\n\n sleep 0.5\n\n play 80 #=> plays at 1.4\n\n # time shifts forward by 0.1 beats\n\nend\n\n # we now honour the original sleep 1 and the\n\n # sleep 0.5 within the time_warp block is\n\n # ignored, including the -0.1 offset\n\nplay 70 #=> plays at 1\",\n\n \"# Ticks count linearly through time_warp\n\nputs tick #=> prints 0 (at time 0)\n\nsleep 1\n\ntime_warp 2 do\n\n puts tick #=> prints 1 (at time 3)\n\nend\n\nsleep 0.5\n\nputs tick #=> prints 2 (at time 1.5)\",\n\n \"# Comparing time_warp with at\n\nputs tick #=> prints 0 (at time 0)\n\nsleep 0.5\n\nputs tick #=> prints 1 (at time 0.5)\n\ntime_warp 2 do\n\n puts tick #=> prints 2 (at time 2.5)\n\n sleep 0.5\n\n puts tick #=> prints 3 (at time 3)\n\nend\n\nat 3 do # the at will reset all thread locals\n\n puts tick #=> prints 0 (At time 3.5)\n\n sleep 0.5\n\n puts tick #=> prints 1 (At time 4)\n\nend\n\nsleep 0.5\n\nputs tick #=> prints 4 (at time 1)\",\n\n \"# Time Warp within Density\n\ndensity 2 do # Typically this will double the BPM and affect all times\n\n # in addition to looping the internal block twice\n\n time_warp 0.5 do # However, this time is *not* affected and will remain 0.5\n\n with_fx :slicer, phase: 0.5 do # This phase duration *is* affected and will be 0.25\n\n play 60\n\n sleep 1 # This time *will* be affected by the density and be 0.5\n\n end\n\n end\n\nend\n\n\",\n\n \" # Time Warp with lists of times\n\ntime_warp [0, 1, 2, 3] do\n\n puts \\\"hello\\\" # Will print \\\"hello\\\" at 0, 1, 2, and 3 seconds\n\nend\n\n # Notice that the run completes before all the\n\n # messages have been delivered. This is because it\n\n # schedules all the messages at once so the program\n\n # can complete immediately. This is unlike at which\n\n # would appear to behave similarly, but would wait\n\n # for all messages to be delivered (on time) before\n\n # allowing the program to complete. \",\n\n\"time_warp [1, 2, 4] do # plays a note after waiting 1 beat,\n\n play 75 # then after 1 more beat,\n\n end # then after 2 more beats (4 beats total)\n\n \",\n\n \"\n\n time_warp [1, 2, 3], [75, 76, 77] do |n| # plays 3 different notes\n\n play n\n\n end\n\n \",\n\n \"\n\n time_warp [1, 2, 3],\n\n [{:amp=>0.5}, {:amp=> 0.8}] do |p| # alternate soft and loud\n\n sample :drum_cymbal_open, p # cymbal hits three times\n\n end\n\n \",\n\n \"\n\n time_warp [0, 1, 2] do |t| # when no params are given to at, the times are fed through to the block\n\n puts t #=> prints 0, 1, then 2\n\n end\n\n \",\n\n \"\n\n time_warp [0, 1, 2], [:a, :b] do |t, b| # If you specify the block with 2 args, it will pass through both the time and the param\n\n puts [t, b] #=> prints out [0, :a], [1, :b], then [2, :a]\n\n end\n\n \",\n\n \"\n\n time_warp [0, 0.5, 2] do |t, idx| # If you specify the block with 2 args, and no param list to at, it will pass through both the time and the index\n\n puts [t, idx] #=> prints out [0, 0], [0.5, 1], then [2, 2]\n\n end\n\n \",\n\n \"\n\n time_warp [0, 0.5, 2], [:a, :b] do |t, b, idx| # If you specify the block with 3 args, it will pass through the time, the param and the index\n\n puts [t, b, idx] #=> prints out [0, :a, 0], [0.5, :b, 1], then [2, :a, 2]\n\n end\n\n \",\n\n \" # time_warp consumes & interferes with the outer random stream\n\nputs \\\"main: \\\", rand # 0.75006103515625\n\nrand_back\n\ntime_warp 1 do # the random stream inside the at block is the\n\n # same as the one in the outer block\n\n puts \\\"time_warp:\\\", rand # 0.75006103515625\n\n puts \\\"time_warp:\\\", rand # 0.733917236328125\n\n rand_back # undo last call to rand\n\nend\n\nsleep 2\n\nputs \\\"main: \\\", rand # value is now 0.733917236328125 again\n\n\",\n\n\"\n\n # Each block run inherits the same thread locals from the previous one.\n\n # This means things like the thread local counters can flow through\n\n # time warp iterations:\n\ntime_warp [0, 2] do\n\n # first time round (after 1 beat) prints:\n\n puts tick # 0\n\n puts tick # 1\n\nend\n\n # second time round (after 2 beats) prints:\n\n # 2\n\n # 3\n\n"
},
"tick_set": {
"summary": "Set tick to a specific value",
"doc": "Set the default tick to the specified `value`. If a `key` is referenced, set that tick to `value` instead. Next call to `look` will return `value`.",
"examples": " tick_set 40 # set default tick to 40\n\n puts look #=> 40\",\n\n \"\n\n tick_set :foo, 40 # set tick :foo to 40\n\n puts look(:foo) #=> 40 (tick :foo is now 40)\n\n puts look #=> 0 (default tick is unaffected)\n\n "
},
"tick_reset": {
"summary": "Reset tick to 0",
"doc": "Reset default tick to 0. If a `key` is referenced, set that tick to 0 instead. Same as calling tick_set(0)",
"examples": " # increment default tick a few times\n\n tick\n\n tick\n\n tick\n\n puts look #=> 2 (default tick is now 2)\n\n tick_set 0 # default tick is now 0\n\n puts look #=> 0 (default tick is now 0\n\n \",\n\n \"\n\n # increment tick :foo a few times\n\n tick :foo\n\n tick :foo\n\n tick :foo\n\n puts look(:foo) #=> 2 (tick :foo is now 2)\n\n tick_set 0 # default tick is now 0\n\n puts look(:foo) #=> 2 (tick :foo is still 2)\n\n tick_set :foo, 0 # reset tick :foo\n\n puts look(:foo) #=> 0 (tick :foo is now 0)"
},
"tick_reset_all": {
"summary": "Reset all ticks",
"doc": "Reset all ticks - default and keyed",
"examples": " tick # increment default tick and tick :foo\n\n tick\n\n tick :foo\n\n tick :foo\n\n tick :foo\n\n puts look #=> 1\n\n puts look(:foo) #=> 2\n\n tick_reset_all\n\n puts look #=> 0\n\n puts look(:foo) #=> 0\n\n "
},
"tick": {
"summary": "Increment a tick and return value",
"doc": "Increment the default tick by 1 and return value. Successive calls to `tick` will continue to increment the default tick. If a `key` is specified, increment that specific tick. If an increment `value` is specified, increment key by that value rather than 1. Ticks are `in_thread` and `live_loop` local, so incrementing a tick only affects the current thread's version of that tick. See `tick_reset` and `tick_set` for directly manipulating the tick vals.",
"examples": " puts tick #=> 0\n\n puts tick #=> 1\n\n puts tick #=> 2\n\n puts tick #=> 3\n\n \",\n\n \"\n\n puts tick(:foo) #=> 0 # named ticks have their own counts\n\n puts tick(:foo) #=> 1\n\n puts tick(:foo) #=> 2\n\n puts tick(:bar) #=> 0 # tick :bar is independent of tick :foo\n\n \",\n\n \"\n\n # You can tick by more than increments of 1\n\n # using the step: opt\n\n puts tick #=> 0\n\n puts tick #=> 1\n\n puts tick #=> 2\n\n puts tick(step: 2) #=> 4\n\n puts tick(step: 2) #=> 6\n\n puts tick(step: 10) #=> 16\n\n puts tick #=> 17\n\n \",\n\n \" # Each_live loop has its own separate ticks\n\n live_loop :fast_tick do\n\n puts tick # the fast_tick live_loop's tick will\n\n sleep 2 # be updated every 2 seconds\n\n end\n\n live_loop :slow_tick do\n\n puts tick # the slow_tick live_loop's tick is\n\n sleep 4 # totally independent from the fast_tick\n\n # live loop and will be updated every 4\n\n # seconds\n\n end\n\n \",\n\n \"\n\n live_loop :regular_tick do\n\n puts tick # the regular_tick live_loop's tick will\n\n sleep 1 # be updated every second\n\n end\n\n live_loop :random_reset_tick do\n\n if one_in 3 # randomly reset tick\n\n tick_reset\n\n puts \\\"reset tick!\\\"\n\n end\n\n puts tick # this live_loop's tick is totally\n\n sleep 1 # independent and the reset only affects\n\n # this tick.\n\n end\n\n \",\n\n \"\n\n # Ticks work directly on lists, and will tick through each element\n\n # However, once they get to the end, they'll return nil\n\n live_loop :scale do\n\n play [:c, :d, :e, :f, :g].tick # play all notes just once, then rests\n\n sleep 1\n\n end\n\n \",\n\n \"\n\n # Normal ticks interact directly with list ticks\n\n live_loop :odd_scale do\n\n tick # Increment the default tick\n\n play [:c, :d, :e, :f, :g, :a].tick # this now play every *other* note just once,\n\n # then rests\n\n sleep 1\n\n end\n\n \",\n\n \"\n\n # Ticks work wonderfully with rings\n\n # as the ring ensures the tick wraps\n\n # round internally always returning a\n\n # value\n\n live_loop :looped_scale do\n\n play (ring :c, :d, :e, :f, :g).tick # play all notes just once, then repeats\n\n sleep 1\n\n end\n\n \",\n\n \"\n\n # Ticks work wonderfully with scales\n\n # which are also rings\n\n live_loop :looped_scale do\n\n play (scale :e3, :minor_pentatonic).tick # play all notes just once, then repeats\n\n sleep 0.25\n\n end\n\n "
},
"look": {
"summary": "Obtain value of a tick",
"doc": "Read and return value of default tick. If a `key` is specified, read the value of that specific tick. Ticks are `in_thread` and `live_loop` local, so the tick read will be the tick of the current thread calling `look`.",
"examples": " puts look #=> 0\n\n puts look #=> 0\n\n puts look #=> 0 # look doesn't advance the tick, it just returns the current value\n\n \",\n\n \"\n\n puts look #=> 0 # A look is always 0 before the first tick\n\n tick # advance the tick\n\n puts look #=> 0 # Note: a look is still 0 after the first tick.\n\n tick\n\n puts look #=> 1\n\n puts look #=> 1 # making multiple calls to look doesn't affect tick value\n\n tick\n\n puts look #=> 2\n\n \",\n\n \"\n\n tick(:foo)\n\n tick(:foo)\n\n puts look(:foo) #=> 1 (keyed look :foo has been advanced)\n\n puts look #=> 0 (default look hasn't been advanced)\n\n puts look(:bar) #=> 0 (other keyed looks haven't been advanced either)\n\n \",\n\n \"\n\n # You can call look on lists and rings\n\n live_loop :foo do\n\n tick # advance the default tick\n\n use_synth :beep\n\n play (scale :e3, :minor_pentatonic).look # look into the default tick to play all notes in sequence\n\n sleep 0.5\n\n use_synth :square\n\n play (ring :e1, :e2, :e3).look, release: 0.25 # use the same look on another ring\n\n sleep 0.25\n\n end\n\n \",\n\n\"\n\n# Returns numbers unchanged if single argument\n\nputs look(0) #=> 0\n\nputs look(4) #=> 4\n\nputs look(-4) #=> -4\n\nputs look(20.3) #=> 20.3"
},
"stop": {
"summary": "Stop current thread or run",
"doc": "Stops the current thread or if not in a thread, stops the current run. Does not stop any running synths triggered previously in the run/thread or kill any existing sub-threads.",
"examples": " sample :loop_amen #=> this sample is played until completion\n\n sleep 0.5\n\n stop #=> signal to stop executing this run\n\n sample :loop_garzul #=> this never executes\n\n \",\n\n \"\n\n in_thread do\n\n play 60 #=> this note plays\n\n stop\n\n sleep 0.5 #=> this sleep never happens\n\n play 72 #=> this play never happens\n\n end\n\n play 80 #=> this plays as the stop only affected the above thread\",\n\n \"\n\n # Stopping live loops\n\n live_loop :foo\n\n sample :bd_haus\n\n sleep 1\n\n stop # live loop :foo will now stop and no longer loop\n\n end\n\n live_loop :bar # live loop :bar will continue looping\n\n sample :elec_blip\n\n sleep 0.25\n\n end"
},
"on": {
"summary": "Optionally evaluate block",
"doc": "Optionally evaluate the block depending on the truthiness of the supplied condition. The truthiness rules are as follows: all values are seen as true except for: false, nil and 0. Lambdas will be automatically called and the truthiness of their results used.",
"examples": "\n\non true do\n\n play 70 #=> will play 70 as true is truthy\n\nend\",\n\n\"\n\non 1 do\n\n play 70 #=> will play 70 as 1 is truthy\n\nend\",\n\n\"\n\non 0 do\n\n play 70 #=> will *not* play 70 as 0 is not truthy\n\nend\",\n\n\"\n\non false do\n\n play 70 #=> will *not* play 70 as false is not truthy\n\nend\",\n\n\"\n\non nil do\n\n play 70 #=> will *not* play 70 as nil is not truthy\n\nend\",\n\n\"\n\non lambda{true} do\n\n play 70 #=> will play 70 as the lambda returns a truthy value\n\nend\",\n\n\"\n\non lambda{false} do\n\n play 70 #=> will *not* play 70 as the lambda does not return a truthy value\n\nend\",\n\n\"\n\non lambda{[true, false].choose} do\n\n play 70 #=> will maybe play 70 depending on the choice in the lambda\n\nend"
},
"bools": {
"summary": "Create a ring of boolean values",
"doc": "Create a new ring of booleans values from 1s and 0s, which can be easier to write and manipulate in a live setting.",
"examples": "(bools 1, 0) #=> (ring true, false)\",\n\n \"(bools 1, 0, true, false, nil) #=> (ring true, false, true, false, false)"
},
"stretch": {
"summary": "Stretch a sequence of values",
"doc": "Stretches a list of values each value repeated count times. Always returns a ring regardless of the type of the list that is stretched. To preserve type, consider using `.stretch` i.e. `(ramp 1, 2, 3).stretch(2) #=> (ramp 1, 1, 2, 2, 3, 3)`",
"examples": "(stretch [1,2], 3) #=> (ring 1, 1, 1, 2, 2, 2)\",\n\n \"(stretch [:e2, :c3], 1, [:c2, :d3], 2) #=> (ring :e2, :c3, :c2, :c2, :d3, :d3)"
},
"knit": {
"summary": "Knit a sequence of repeated values",
"doc": "Knits a series of value, count pairs to create a ring buffer where each value is repeated count times.",
"examples": "(knit 1, 5) #=> (ring 1, 1, 1, 1, 1)\",\n\n \"(knit :e2, 2, :c2, 3) #=> (ring :e2, :e2, :c2, :c2, :c2)"
},
"spread": {
"summary": "Euclidean distribution for beats",
"doc": "Creates a new ring of boolean values which space a given number of accents as evenly as possible throughout a bar. This is an implementation of the process described in 'The Euclidean Algorithm Generates Traditional Musical Rhythms' (Toussaint 2005).",
"examples": "(spread 3, 8) #=> (ring true, false, false, true, false, false, true, false) a spacing of 332\",\n\n \"(spread 3, 8, rotate: 1) #=> (ring true, false, false, true, false, true, false, false) a spacing of 323\",\n\n \"\n\n # Easily create interesting polyrhythmic beats\n\n live_loop :euclid_beat do\n\n sample :elec_bong, amp: 1.5 if (spread 3, 8).tick # Spread 3 bongs over 8\n\n sample :perc_snap, amp: 0.8 if (spread 7, 11).look # Spread 7 snaps over 11\n\n sample :bd_haus, amp: 2 if (spread 1, 4).look # Spread 1 bd over 4\n\n sleep 0.125\n\n end\n\n \",\n\n \"\n\n # Spread descriptions from\n\n # 'The Euclidean Algorithm Generates Traditional Musical Rhythms' (Toussaint 2005).\n\n (spread 2, 5) # A thirteenth century Persian rhythm called Khafif-e-ramal.\n\n (spread 3, 4) # The archetypal pattern of the Cumbria from Columbia, as well\n\n # as a Calypso rhythm from Trinidad\n\n (spread 3, 5) # When started on the second onset, is another thirteenth\n\n # century Persian rhythm by the name of Khafif-e-ramal, as well\n\n # as a Romanian folk-dance rhythm.\n\n (spread 3, 7) # A ruchenitza rhythm used in a Bulgarian folk-dance.\n\n (spread 3, 8) # The Cuban tresillo pattern\n\n (spread 4, 7) # Another Ruchenitza Bulgarian folk-dance rhythm\n\n (spread 4, 9) # The Aksak rhythm of Turkey.\n\n (spread 4, 11) # The metric pattern used by Frank Zappa in his piece Outside Now\n\n (spread 5, 6) # Yields the York-Samai pattern, a popular Arab rhythm, when\n\n # started on the second onset.\n\n (spread 5, 7) # The Nawakhat pattern, another popular Arab rhythm.\n\n (spread 5, 8) # The Cuban cinquillo pattern.\n\n (spread 5, 9) # A popular Arab rhythm called Agsag-Samai.\n\n (spread 5, 11) # The metric pattern used by Moussorgsky in Pictures at an\n\n # Exhibition\n\n (spread 5, 12) # The Venda clapping pattern of a South African children's\n\n # song.\n\n (spread 5, 16) # The Bossa-Nova rhythm necklace of Brazil.\n\n (spread 7, 8) # A typical rhythm played on the Bendir (frame drum)\n\n (spread 7, 12) # A common West African bell pattern.\n\n (spread 7, 16) # A Samba rhythm necklace from Brazil.\n\n (spread 9, 16) # A rhythm necklace used in the Central African Republic.\n\n (spread 11, 24) # A rhythm necklace of the Aka Pygmies of Central Africa.\n\n (spread 13, 24) # Another rhythm necklace of the Aka Pygmies of the upper\n\n # Sangha.\n\n "
},
"range": {
"summary": "Create a ring buffer with the specified start, finish and step size",
"doc": "Create a new ring buffer from the range arguments (start, finish and step size). Step size defaults to `1`. Indexes wrap around positively and negatively",
"examples": "(range 1, 5) #=> (ring 1, 2, 3, 4)\",\n\n \"(range 1, 5, inclusive: true) #=> (ring 1, 2, 3, 4, 5)\",\n\n \"(range 1, 5, step: 2) #=> (ring 1, 3)\",\n\n \"(range 1, -5, step: 2) #=> (ring 1, -1, -3)\",\n\n \"(range 1, -5, step: 2)[-1] #=> -3"
},
"line": {
"summary": "Create a ring buffer representing a straight line",
"doc": "Create a ring buffer representing a straight line between start and finish of steps elements. Steps defaults to `4`. Indexes wrap around positively and negatively. Similar to `range`.",
"examples": "(line 0, 4, steps: 4) #=> (ring 0.0, 1.0, 2.0, 3.0)\",\n\n \"(line 5, 0, steps: 5) #=> (ring 5.0, 4.0, 3.0, 2.0, 1.0)\",\n\n \"(line 0, 3, inclusive: true) #=> (ring 0.0, 1.0, 2.0, 3.0)"
},
"halves": {
"summary": "Create a ring of successive halves",
"doc": "Create a ring containing the results of successive halving of the `start` value. If `num_halves` is negative, will return a ring of `doubles`.",
"examples": "(halves 60, 2) #=> (ring 60, 30)\",\n\n \"(halves 120, 3) #=> (ring 120, 60, 30)\",\n\n \"(halves 120, 5) #=> (ring 120, 60, 30, 15, 7.5)\",\n\n \"(halves 30, -5) #=> (ring 30, 60, 120, 240, 480)"
},
"doubles": {
"summary": "Create a ring of successive doubles",
"doc": "Create a ring containing the results of successive doubling of the `start` value. If `num_doubles` is negative, will return a ring of `halves`.",
"examples": "(doubles 60, 2) #=> (ring 60, 120)\",\n\n \"(doubles 1.5, 3) #=> (ring 1.5, 3, 6)\",\n\n \"(doubles 1.5, 5) #=> (ring 1.5, 3, 6, 12, 24)\",\n\n \"(doubles 100, -4) #=> (ring 100, 50, 25, 12.5)"
},
"vector": {
"summary": "Create a vector",
"doc": "Create a new immutable vector from args. Out of range indexes return nil.",
"examples": "(vector 1, 2, 3)[0] #=> 1\",\n\n \"(vector 1, 2, 3)[1] #=> 2\",\n\n \"(vector 1, 2, 3)[2] #=> 3\",\n\n \"(vector 1, 2, 3)[3] #=> nil\",\n\n \"(vector 1, 2, 3)[1000] #=> nil\",\n\n \"(vector 1, 2, 3)[-1] #=> nil\",\n\n \"(vector 1, 2, 3)[-1000] #=> nil"
},
"ring": {
"summary": "Create a ring buffer",
"doc": "Create a new immutable ring buffer from args. Indexes wrap around positively and negatively",
"examples": "(ring 1, 2, 3)[0] #=> 1\",\n\n \"(ring 1, 2, 3)[1] #=> 2\",\n\n \"(ring 1, 2, 3)[3] #=> 1\",\n\n \"(ring 1, 2, 3)[-1] #=> 3"
},
"map": {
"summary": "Create an immutable map",
"doc": "Create a new immutable key/value map from args.",
"examples": "(map foo: 1, bar: 2)[:foo] #=> 1\",\n\n \"(map foo: 1, bar: 2)[:bar] #=> 2\",\n\n \"(map foo: 1, bar: 2)[:quux] #=> nil"
},
"ramp": {
"summary": "Create a ramp vector",
"doc": "Create a new immutable ramp vector from args. Indexes always return first or last value if out of bounds.",
"examples": "(ramp 1, 2, 3)[0] #=> 1\",\n\n \"(ramp 1, 2, 3)[1] #=> 2\",\n\n \"(ramp 1, 2, 3)[2] #=> 3\",\n\n \"(ramp 1, 2, 3)[3] #=> 3\",\n\n \"(ramp 1, 2, 3)[1000] #=> 3\",\n\n \"(ramp 1, 2, 3)[-1] #=> 1\",\n\n \"(ramp 1, 2, 3)[-1000] #=> 1"
},
"choose": {
"summary": "Random list selection",
"doc": "Pick n elements from list or ring. Unlike shuffle, after each element has been picked, it is 'returned' to the list so it may be picked again. This means there may be duplicates in the result. If n is greater than the size of the ring/list then duplicates are guaranteed to be in the result.\nIf `n` isn't supplied it defaults to a size of 1.\nIf no arguments are given, will return a lambda function which when called takes an argument which will be a list to be picked from. This is useful for choosing random `onset:` vals for samples.\nAlways returns a list-like thing (either an array or ring)",
"examples": "puts [1, 2, 3, 4, 5].pick(3) #=> [4, 4, 3]\",\n\n\"\n\nputs (ring 1, 2, 3, 4, 5).pick(3) #=> (ring 4, 4, 3)\",\n\n\"\n\nputs (ring 1, 2).pick(5) #=> (ring 2, 2, 1, 1, 1)\",\n\n\"\n\nputs (ring 1, 2, 3).pick #=> (ring 3)\",\n\n\"\n\n# Using pick for random sample onsets\n\nlive_loop :foo do\n\n sample :loop_amen, onset: pick # pick a random onset value each time\n\n sleep 0.125\n\nend"
},
"inc": {
"summary": "Increment",
"doc": "Increment a number by `1`. Equivalent to `n + 1`",
"examples": "inc 1 # returns 2\",\n\n \"inc -1 # returns 0"
},
"dec": {
"summary": "Decrement",
"doc": "Decrement a number by `1`. Equivalent to `n - 1`",
"examples": "dec 1 # returns 0\",\n\n \"dec -1 # returns -2"
},
"loop": {
"summary": "Repeat do/end block forever",
"doc": "Given a do/end block, repeats it forever. Note that once the program enters the loop - it will not move on but will instead stay within the loop. Plain loops like this are like black holes - instead of sucking in the light they suck in the program.\nThe loop must either `sleep` or `sync` each time round otherwise it will stop and throw an error. This is to stop the loop from spinning out of control and locking the system.\nFor a more powerful, flexible loop built for live coding see `live_loop`.",
"examples": "play 70 # note 70 is played\n\nloop do\n\n play 50 # This loop will repeat notes 50 and 62 forever\n\n sleep 1\n\n play 62\n\n sleep 2\n\nend\n\nplay 80 # This is *never* played as the program is trapped in the loop above"
},
"live_loop": {
"summary": "A loop for live coding",
"doc": "Loop the do/end block forever. However, unlike a basic loop, a live_loop has two special properties. Firstly it runs in a thread - so you can have any number of live loops running at the same time (concurrently). Secondly, you can change the behaviour of a live loop whilst it is still running without needing to stop it. Live loops are therefore the secret to live coding with Sonic Pi.\nAs live loops are excecuted within a named in_thread, they behave similarly. See the in_thread documentation for all the details. However, it's worth mentioning a few important points here. Firstly, only one live loop with a given name can run at any one time. Therefore, if you define two or more `live_loop`s called `:foo` only one will be running. Another important aspect of `live_loop`s is that they manage their own thread locals set with the `use_*` and `with_*` fns. This means that each `live_loop` can have its own separate default synth, BPM and sample defaults. When a `live_loop` is *first* created, it inherits the thread locals from the parent thread, but once it has started, the only way to change them is by re-defining the do/end body of the `live_loop`. See the examples below for details. Finally, as mentioned above, provided their names are different, you may have many `live_loop`s executing at once.\nA typical way of live coding with live loops is to define a number of them in a buffer, hit Run to start them and then to modify their do/end blocks and then hit Run again. This will not create any more thread, but instead just modify the behaviour of the existing threads. The changes will *not* happen immediately. Instead, they will only happen the next time round the loop. This is because the behaviour of each live loop is implemented with a standard function. When a live loop is updated, the function definition is also updated. Each time round the live loop, the function is called, so the new behviour is only observed next time round the loop.\nAlso sends a `cue` with the same name each time the `live_loop` repeats. This may be used to `sync` with other threads and `live_loop`s.\nIf the `live_loop` block is given a parameter, this is given the result of the last run of the loop (with initial value either being `0` or an init arg). This allows you to 'thread' values across loops.\nFinally, it is possible to delay the initial trigger of the live_loop on creation with both the `delay:` and `sync:` opts. See their respective docstrings. If both `delay:` and `sync:` are specified, on initial live_loop creation first the delay will be honoured and then the sync.\n",
"examples": "## Define and start a simple live loop\n\nlive_loop :ping do # Create a live loop called :ping\n\n sample :elec_ping # This live loops plays the :elec_ping sample\n\n sleep 1 # Then sleeps for 1 beat before repeating\n\nend\n\n \",\n\n \"\n\n## Every live loop must sleep or sync\n\nlive_loop :ping do # Create a live loop called :ping\n\n sample :elec_ping # This live loops plays the :elec_ping sample\n\n # However, because the do/end lock of the live loop does not\n\n # contain any calls to sleep or sync, the live loop stops at\n\n # the end of the first loop with a 'Did not sleep' error.\n\nend\",\n\n \"\n\n## Multiple live loops will play at the same time\n\nlive_loop :foo do # Start a live loop called :foo\n\n play 70\n\n sleep 1\n\nend\n\nlive_loop :bar do # Start another live loop called :bar\n\n sample :bd_haus # Both :foo and :bar will be playing\n\n sleep 0.5 # at the same time.\n\nend\n\n\",\n\n \"\n\n## Live loops inherit external use_* thread locals\n\nuse_bpm 30\n\nlive_loop :foo do\n\n play 70 # live loop :foo now has a BPM of 30\n\n sleep 1 # This sleep will be for 2 seconds\n\nend\n\n\",\n\n \"\n\n## Live loops can have their own thread locals\n\nlive_loop :foo do\n\n use_bpm 30 # Set the BPM of live loop :foo to 30\n\n play 70\n\n sleep 1 # This sleep will be for 2 seconds\n\nend\n\nlive_loop :bar do\n\n use_bpm 120 # Set the BPM of live loop :bar to 120\n\n play 82\n\n sleep 1 # This sleep will be for 0.5 seconds\n\nend\n\n\",\n\n \"\n\n## Live loops can pass values between iterations\n\nlive_loop :foo do |a| # pass a param (a) to the block (inits to 0)\n\n puts a # prints out all the integers\n\n sleep 1\n\n a += 1 # increment a by 1 (last value is passed back into the loop)\n\nend\n\n \",\n\n \"\n\n## Live loop names must be unique\n\nlive_loop :foo do # Start a live loop called :foo\n\n play 70\n\n sleep 1\n\nend\n\nlive_loop :foo do # Attempt to start another also called :foo\n\n sample :bd_haus # With a different do/end block\n\n sleep 0.5 # This will not start another live loop\n\n # but instead replace the behaviour of the first.\n\nend # There will only be one live loop running playing\n\n # The bass drum\n\n\",\n\n \"\n\n## You can sync multiple live loops together\n\nlive_loop :foo, sync: :bar do # Wait for a :bar cue event before starting :foo\n\n play 70 # Live loop :foo is therefore blocked and does\n\n sleep 1 # not make a sound initially\n\nend\n\nsleep 4 # Wait for 4 beats\n\nlive_loop :bar do # Start a live loop called :foo which will emit a :bar\n\n sample :bd_haus # cue message therefore releasing the :foo live loop.\n\n sleep 0.5 # Live loop :foo therefore starts and also inherits the\n\nend # logical time of live loop :bar.\n\n # This pattern is also useful to re-sync live loops after\n\n # errors are made. For example, when modifying live loop :foo\n\n # it is possible to introduce a runtime error which will stop\n\n # :foo but not :bar (as they are separate, isolated threads).\n\n # Once the error has been fixed and the code is re-run, :foo\n\n # will automatically wait for :bar to loop round and restart\n\n # in sync with the correct virtual clock."
},
"block_duration": {
"summary": "Return block duration",
"doc": "Given a block, runs it and returns the amount of time that has passed. This time is in seconds and is not scaled to the current BPM. Any threads spawned in the block are not accounted for.",
"examples": "dur = block_duration do\n\n play 50\n\n sleep 1\n\n play 62\n\n sleep 2\n\nend\n\nputs dur #=> Returns 3 as 3 seconds have passed within the block\",\n\n\"use_bpm 120\n\ndur = block_duration do\n\n play 50\n\n sleep 1\n\n play 62\n\n sleep 2\n\nend\n\nputs dur #=> Returns 1.5 as 1.5 seconds have passed within the block\n\n # (due to the BPM being 120)"
},
"block_slept": {
"summary": "Determine if block contains sleep time",
"doc": "Given a block, runs it and returns whether or not the block contained sleeps or syncs",
"examples": "slept = block_slept? do\n\n play 50\n\n sleep 1\n\n play 62\n\n sleep 2\n\nend\n\nputs slept #=> Returns true as there were sleeps in the block\",\n\n\"\n\nin_thread do\n\n sleep 1\n\n cue :foo # trigger a cue on a different thread\n\nend\n\nslept = block_slept? do\n\n sync :foo # wait for the cue before playing the note\n\n play 62\n\nend\n\nputs slept #=> Returns true as the block contained a sync.\",\n\n\"\n\nslept = block_slept? do\n\n play 50\n\n play 62\n\nend\n\nputs slept #=> Returns false as there were no sleeps in the block"
},
"at": {
"summary": "Asynchronous Time. Run a block at the given time(s)",
"doc": "Given a list of times, run the block once after waiting each given time. If passed an optional params list, will pass each param individually to each block call. If size of params list is smaller than the times list, the param values will act as rings (rotate through). If the block is given 1 arg, the times are fed through. If the block is given 2 args, both the times and the params are fed through. A third block arg will receive the index of the time.\nNote, all code within the block is executed in its own thread. Therefore despite inheriting all thread locals such as the random stream and ticks, modifications will be isolated to the block and will not affect external code.\n`at` is just-in-time scheduling using multiple isolated threads. See `time_warp` for ahead-of-time scheduling within the current thread.",
"examples": " at 4 do\n\n sample :ambi_choir # play sample after waiting for 4 beats\n\n end\n\n \",\n\n \"\n\n at [1, 2, 4] do # plays a note after waiting 1 beat,\n\n play 75 # then after 1 more beat,\n\n end # then after 2 more beats (4 beats total)\n\n \",\n\n \"\n\n at [1, 2, 3], [75, 76, 77] do |n| # plays 3 different notes\n\n play n\n\n end\n\n \",\n\n \"\n\n at [1, 2, 3],\n\n [{:amp=>0.5}, {:amp=> 0.8}] do |p| # alternate soft and loud\n\n sample :drum_cymbal_open, p # cymbal hits three times\n\n end\n\n \",\n\n \"\n\n at [0, 1, 2] do |t| # when no params are given to at, the times are fed through to the block\n\n puts t #=> prints 0, 1, then 2\n\n end\n\n \",\n\n \"\n\n at [0, 1, 2], [:a, :b] do |t, b| #If you specify the block with 2 args, it will pass through both the time and the param\n\n puts [t, b] #=> prints out [0, :a], [1, :b], then [2, :a]\n\n end\n\n \",\n\n \"\n\n at [0, 0.5, 2] do |t, idx| #If you specify the block with 2 args, and no param list to at, it will pass through both the time and the index\n\n puts [t, idx] #=> prints out [0, 0], [0.5, 1], then [2, 2]\n\n end\n\n \",\n\n \"\n\n at [0, 0.5, 2], [:a, :b] do |t, b, idx| #If you specify the block with 3 args, it will pass through the time, the param and the index\n\n puts [t, b, idx] #=> prints out [0, :a, 0], [0.5, :b, 1], then [2, :a, 2]\n\n end\n\n \",\n\n \" # at does not consume & interfere with the outer random stream\n\nputs \\\"main: \\\", rand # 0.75006103515625\n\nrand_back\n\nat 1 do # the random stream inside the at block is separate and\n\n # isolated from the outer stream.\n\n puts \\\"at:\\\", rand # 0.9287109375\n\n puts \\\"at:\\\", rand # 0.1043701171875\n\nend\n\nsleep 2\n\nputs \\\"main: \\\", rand # value is still 0.75006103515625\n\n\",\n\n\"\n\n # Each block run within at has its own isolated random stream:\n\nat [1, 2] do\n\n # first time round (after 1 beat) prints:\n\n puts rand # 0.9287109375\n\n puts rand # 0.1043701171875\n\nend\n\n # second time round (after 2 beats) prints:\n\n # 0.1043701171875\n\n # 0.764617919921875\n\n"
},
"version": {
"summary": "Get current version information",
"doc": "Return information representing the current version of Sonic Pi. This information may be further inspected with `version.major`, `version.minor`, `version.patch` and `version.dev`",
"examples": " puts version # => Prints out the current version such as v2.0.1\",\n\n \"\n\n puts version.major # => Prints out the major version number such as 2\",\n\n \"\n\n puts version.minor # => Prints out the minor version number such as 0\",\n\n \"\n\n puts version.patch # => Prints out the patch level for this version such as 0"
},
"spark_graph": {
"summary": "Returns a string representing a list of numeric values as a spark graph/bar chart",
"doc": "Given a list of numeric values, this method turns them into a string of bar heights. Useful for quickly graphing the shape of an array. Remember to use puts so you can see the output. See `spark` for a simple way of printing a spark graph.",
"examples": "puts (spark_graph (range 1, 5)) #=> ▁▃▅█\",\n\n \"puts (spark_graph (range 1, 5).shuffle) #=> ▃█▅▁"
},
"spark": {
"summary": "Print a string representing a list of numeric values as a spark graph/bar chart",
"doc": "Given a list of numeric values, this method turns them into a string of bar heights and prints them out. Useful for quickly graphing the shape of an array.",
"examples": "spark (range 1, 5) #=> ▁▃▅█\",\n\n \"spark (range 1, 5).shuffle #=> ▃█▅▁"
},
"defonce": {
"summary": "Define a named value only once",
"doc": "Allows you to assign the result of some code to a name, with the property that the code will only execute once - therefore stopping re-definitions. This is useful for defining values that you use in your compositions but you don't want to reset every time you press run. You may force the block to execute again regardless of whether or not it has executed once already by using the override option (see examples).",
"examples": " defonce :foo do # Define a new function called foo\n\n sleep 1 # Sleep for a beat in the function definition. Note that this amount\n\n # of time in seconds will depend on the current BPM of the live_loop\n\n # or thread calling this function.\n\n puts \\\"hello\\\" # Print hello\n\n 10 # Return a value of 10\n\n end\n\n # Call foo on its own\n\n puts foo # The run sleeps for a beat and prints \\\"hello\\\" before returning 10\n\n # Try it again:\n\n puts foo # This time the run doesn't sleep or print anything out. However, 10 is still returned.\n\n defonce :foo do # Try redefining foo\n\n puts \\\"you can't redefine me\\\"\n\n 15\n\n end\n\n puts foo # We still don't see any printing or sleeping, and the result is still 10\n\n # You can use foo anywhere you would use normal code.\n\n # For example, in a block:\n\n 3.times do\n\n play foo # play 10\n\n end\",\n\n \"\n\n defonce :bar do\n\n 50\n\n end\n\n play bar # plays 50\n\n defonce :bar do # This redefinition doesn't work due to the behaviour of defonce\n\n 70\n\n end\n\n play bar # Still plays 50\n\n defonce :bar, override: true do # Force definition to take place with override option\n\n 80\n\n end\n\n play bar # plays 80"
},
"ndefine": {
"summary": "Define a new function",
"doc": "Does nothing. Use to stop a define from actually defining. Simpler than wrapping whole define in a comment block or commenting each individual line out."
},
"define": {
"summary": "Define a new function",
"doc": "Allows you to group a bunch of code and give it your own name for future re-use. Functions are very useful for structuring your code. They are also the gateway into live coding as you may redefine a function whilst a thread is calling it, and the next time the thread calls your function, it will use the latest definition.",
"examples": " # Define a new function called foo\n\n define :foo do\n\n play 50\n\n sleep 1\n\n end\n\n # Call foo on its own\n\n foo\n\n # You can use foo anywhere you would use normal code.\n\n # For example, in a block:\n\n 3.times do\n\n foo\n\n end"
},
"comment": {
"summary": "Block level commenting",
"doc": "Does not evaluate any of the code within the block. However, any optional args passed before the block *will* be evaluated although they will be ignored. See `uncomment` for switching commenting off without having to remove the comment form.",
"examples": " comment do # starting a block level comment:\n\n play 50 # not played\n\n sleep 1 # no sleep happens\n\n play 62 # not played\n\n end"
},
"uncomment": {
"summary": "Block level comment ignoring",
"doc": "Evaluates all of the code within the block. Use to reverse the effect of the comment without having to explicitly remove it.",
"examples": " uncomment do # starting a block level comment:\n\n play 50 # played\n\n sleep 1 # sleep happens\n\n play 62 # played\n\n end"
},
"print": {
"summary": "Display a message in the output pane",
"doc": "Displays the information you specify as a string inside the output pane. This can be a number, symbol, or a string itself. Useful for debugging. Synonym for `puts`.",
"examples": "print \\\"hello there\\\" #=> will print the string \\\"hello there\\\" to the output pane\",\n\n \"print 5 #=> will print the number 5 to the output pane\",\n\n \"print foo #=> will print the contents of foo to the output pane"
},
"puts": {
"summary": "Display a message in the output pane",
"doc": "Displays the information you specify as a string inside the output pane. This can be a number, symbol, or a string itself. Useful for debugging. Synonym for `print`.",
"examples": "print \\\"hello there\\\" #=> will print the string \\\"hello there\\\" to the output pane\",\n\n \"print 5 #=> will print the number 5 to the output pane\",\n\n \"print foo #=> will print the contents of foo to the output pane"
},
"vt": {
"summary": "Get virtual time",
"doc": "Get the virtual time of the current thread.",
"examples": " puts vt # prints 0\n\n sleep 1\n\n puts vt # prints 1"
},
"factor": {
"summary": "Factor test",
"doc": "Test to see if factor is indeed a factor of `val`. In other words, can `val` be divided exactly by factor.",
"examples": "\n\n factor?(10, 2) # true - 10 is a multiple of 2 (2 * 5 = 10)\n\n \",\n\n \"\n\n factor?(11, 2) #false - 11 is not a multiple of 2\n\n \",\n\n \"\n\n factor?(2, 0.5) #true - 2 is a multiple of 0.5 (0.5 * 4 = 2) "
},
"quantise": {
"summary": "Quantise a value to resolution",
"doc": "Round value to the nearest multiple of step resolution.",
"examples": "\n\n quantise(10, 1) # 10 is already a multiple of 1, so returns 10\" ,\n\n \"\n\n quantise(10, 1.1) # Returns 9.9 which is 1.1 * 9\",\n\n \"\n\n quantise(13.3212, 0.1) # 13.3\",\n\n \"\n\n quantise(13.3212, 0.2) # 13.4\",\n\n \"\n\n quantise(13.3212, 0.3) # 13.2\",\n\n \"\n\n quantise(13.3212, 0.5) # 13.5"
},
"dice": {
"summary": "Random dice throw",
"doc": "Throws a dice with the specified num_sides (defaults to `6`) and returns the score as a number between `1` and `num_sides`.",
"examples": " dice # will return a number between 1 and 6 inclusively\n\n # (with an even probability distribution).\",\n\n \"\n\n dice 3 # will return a number between 1 and 3 inclusively"
},
"one_in": {
"summary": "Random true value with specified probability",
"doc": "Returns `true` or `false` with a specified probability - it will return true every one in num times where num is the param you specify",
"examples": " one_in 2 # will return true with a probability of 1/2, false with probability 1/2\",\n\n \"\n\n one_in 3 # will return true with a probability of 1/3, false with a probability of 2/3\",\n\n \"\n\n one_in 100 # will return true with a probability of 1/100, false with a probability of 99/100"
},
"rdist": {
"summary": "Random number in centred distribution",
"doc": "Returns a random number within the range with width around centre. If optional arg `step:` is used, the result is quantised by step.",
"examples": "\n\n print rdist(1, 0) #=> will print a number between -1 and 1\n\n \",\n\n \"\n\n print rdist(1) #=> centre defaults to 0 so this is the same as rdist(1, 0)\n\n \",\n\n \"\n\n loop do\n\n play :c3, pan: rdist(1) #=> Will play :c3 with random L/R panning\n\n sleep 0.125\n\n end"
},
"rrand": {
"summary": "Generate a random float between two numbers",
"doc": "Given two numbers, this produces a float between the supplied min and max values exclusively. Both min and max need to be supplied. For random integers, see `rrand_i`. If optional arg `step:` is used, the result is quantised by step.",
"examples": " print rrand(0, 10) #=> will print a number like 8.917730007820797 to the output pane\",\n\n \"\n\n loop do\n\n play rrand(60, 72) #=> Will play a random non-integer midi note between C4 (60) and C5 (72) such as 67.3453 or 71.2393\n\n sleep 0.125\n\n end"
},
"rrand_i": {
"summary": "Generate a random whole number between two points inclusively",
"doc": "Given two numbers, this produces a whole number between the min and max you supplied inclusively. Both min and max need to be supplied. For random floats, see `rrand`",
"examples": " print rrand_i(0, 10) #=> will print a random number between 0 and 10 (e.g. 4, 0 or 10) to the output pane\",\n\n \"\n\n loop do\n\n play rrand_i(60, 72) #=> Will play a random midi note between C4 (60) and C5 (72)\n\n sleep 0.125\n\n end"
},
"rand": {
"summary": "Generate a random float below a value",
"doc": "Given a max number, produces a float between `0` and the supplied max value. If max is a range, produces a float within the range. With no args returns a random value between `0` and `1`.",
"examples": " print rand(0.5) #=> will print a number like 0.375030517578125 to the output pane"
},
"rand_i": {
"summary": "Generate a random whole number below a value (exclusive)",
"doc": "Given a max number, produces a whole number between `0` and the supplied max value exclusively. If max is a range produces an int within the range. With no args returns either `0` or `1`",
"examples": " print rand_i(5) #=> will print either 0, 1, 2, 3, or 4 to the output pane"
},
"rand_look": {
"summary": "Generate a random number without consuming a rand",
"doc": "Given a max number, produces a number between `0` and the supplied max value exclusively. If max is a range produces an int within the range. With no args returns a value between `0` and `1`.\nDoes not consume a random value from the stream. Therefore, multiple sequential calls to `rand_look` will all return the same value.",
"examples": " print rand_look(0.5) #=> will print a number like 0.375030517578125 to the output pane\",\n\n \"\n\n print rand_look(0.5) #=> will print a number like 0.375030517578125 to the output pane\n\n print rand_look(0.5) #=> will print the same number again\n\n print rand_look(0.5) #=> will print the same number again\n\n print rand(0.5) #=> will print a different random number\n\n print rand_look(0.5) #=> will print the same number as the previous line again."
},
"rand_i_look": {
"summary": "Generate a random whole number without consuming a rand",
"doc": "Given a max number, produces a whole number between `0` and the supplied max value exclusively. If max is a range produces an int within the range. With no args returns either `0` or `1`.\nDoes not consume a random value from the stream. Therefore, multiple sequential calls to `rand_i_look` will all return the same value.",
"examples": "print rand_i_look(5) #=> will print either 0, 1, 2, 3, or 4 to the output pane\",\n\n \"\n\nprint rand_i_look(5) #=> will print either 0, 1, 2, 3, or 4 to the output pane\n\nprint rand_i_look(5) #=> will print the same number again\n\nprint rand_i_look(5) #=> will print the same number again\n\nprint rand_i(5) #=> will print either 0, 1, 2, 3, or 4 to the output pane\n\nprint rand_i_look(5) #=> will print the same number as the previous statement"
},
"rand_back": {
"summary": "Roll back random generator",
"doc": "Roll the random generator back essentially 'undoing' the last call to `rand`. You may specify an amount to roll back allowing you to skip back n calls to `rand`.",
"examples": " # Basic rand stream rollback\n\n puts rand # prints 0.75006103515625\n\n rand_back # roll random stream back one\n\n # the result of the next call to rand will be\n\n # exactly the same as the previous call\n\n puts rand # prints 0.75006103515625 again!\n\n puts rand # prints 0.733917236328125\",\n\n \"\n\n # Jumping back multiple places in the rand stream\n\n puts rand # prints 0.75006103515625\n\n puts rand # prints 0.733917236328125\n\n puts rand # prints 0.464202880859375\n\n puts rand # prints 0.24249267578125\n\n rand_back(3) # roll random stream back three places\n\n # the result of the next call to rand will be\n\n # exactly the same as the result 3 calls to\n\n # rand ago.\n\n puts rand # prints 0.733917236328125 again!\n\n puts rand # prints 0.464202880859375"
},
"rand_skip": {
"summary": "Jump forward random generator",
"doc": "Jump the random generator forward essentially skipping the next call to `rand`. You may specify an amount to jump allowing you to skip n calls to `rand`.",
"examples": " # Basic rand stream skip\n\n puts rand # prints 0.75006103515625\n\n rand_skip # jump random stream forward one\n\n # typically the next rand is 0.733917236328125\n\n puts rand # prints 0.464202880859375\",\n\n \"\n\n # Jumping forward multiple places in the rand stream\n\n puts rand # prints 0.75006103515625\n\n puts rand # prints 0.733917236328125\n\n puts rand # prints 0.464202880859375\n\n puts rand # prints 0.24249267578125\n\n rand_reset # reset the random stream\n\n puts rand # prints 0.75006103515625\n\n rand_skip(2) # jump random stream forward three places\n\n # the result of the next call to rand will be\n\n # exactly the same as if rand had been called\n\n # three times\n\n puts rand 0.24249267578125"
},
"rand_reset": {
"summary": "Reset rand generator to last seed",
"doc": "Resets the random stream to the last specified seed. See `use_random_seed` for changing the seed.",
"examples": " puts rand # prints 0.75006103515625\n\n puts rand # prints 0.733917236328125\n\n puts rand # prints 0.464202880859375\n\n puts rand # prints 0.24249267578125\n\n rand_reset # reset the random stream\n\n puts rand # prints 0.75006103515625\n\n "
},
"shuffle": {
"summary": "Randomise order of a list",
"doc": "Returns a new list with the same elements as the original but with their order shuffled. Also works for strings",
"examples": "\n\n shuffle [1, 2, 3, 4] #=> Would return something like: [3, 4, 2, 1] \",\n\n \"\n\n shuffle \\\"foobar\\\" #=> Would return something like: \\\"roobfa\\\""
},
"use_random_seed": {
"summary": "Set random seed generator to known seed",
"doc": "Resets the random number generator to the specified seed. All subsequently generated random numbers and randomisation functions such as `shuffle` and `choose` will use this new generator and the current generator is discarded. Use this to change the sequence of random numbers in your piece in a way that can be reproduced. Especially useful if combined with iteration. See examples.",
"examples": " ## Basic usage\n\n use_random_seed 1 # reset random seed to 1\n\n puts rand # => 0.417022004702574\n\n use_random_seed 1 # reset random seed back to 1\n\n puts rand #=> 0.417022004702574\n\n \",\n\n \"\n\n ## Generating melodies\n\n notes = (scale :eb3, :minor_pentatonic) # Create a set of notes to choose from.\n\n # Scales work well for this\n\n with_fx :reverb do\n\n live_loop :repeating_melody do # Create a live loop\n\n use_random_seed 300 # Set the random seed to a known value every\n\n # time around the loop. This seed is the key\n\n # to our melody. Try changing the number to\n\n # something else. Different numbers produce\n\n # different melodies\n\n 8.times do # Now iterate a number of times. The size of\n\n # the iteration will be the length of the\n\n # repeating melody.\n\n play notes.choose, release: 0.1 # 'Randomly' choose a note from our ring of\n\n # notes. See how this isn't actually random\n\n # but uses a reproducible method! These notes\n\n # are therefore repeated over and over...\n\n sleep 0.125\n\n end\n\n end\n\n end\n\n "
},
"with_random_seed": {
"summary": "Specify random seed for code block",
"doc": "Resets the random number generator to the specified seed for the specified code block. All generated random numbers and randomisation functions such as `shuffle` and `choose` within the code block will use this new generator. Once the code block has completed, the original generator is restored and the code block generator is discarded. Use this to change the sequence of random numbers in your piece in a way that can be reproduced. Especially useful if combined with iteration. See examples.",
"examples": " use_random_seed 1 # reset random seed to 1\n\n puts rand # => 0.417022004702574\n\n puts rand #=> 0.7203244934421581\n\n use_random_seed 1 # reset it back to 1\n\n puts rand # => 0.417022004702574\n\n with_random_seed 1 do # reset seed back to 1 just for this block\n\n puts rand # => 0.417022004702574\n\n puts rand #=> 0.7203244934421581\n\n end\n\n puts rand # => 0.7203244934421581\n\n # notice how the original generator is restored\",\n\n \"\n\n ## Generating melodies\n\n notes = (scale :eb3, :minor_pentatonic, num_octaves: 2) # Create a set of notes to choose from.\n\n # Scales work well for this\n\n with_fx :reverb do\n\n live_loop :repeating_melody do # Create a live loop\n\n with_random_seed 300 do # Set the random seed to a known value every\n\n # time around the loop. This seed is the key\n\n # to our melody. Try changing the number to\n\n # something else. Different numbers produce\n\n # different melodies\n\n 8.times do # Now iterate a number of times. The size of\n\n # the iteration will be the length of the\n\n # repeating melody.\n\n play notes.choose, release: 0.1 # 'Randomly' choose a note from our ring of\n\n # notes. See how this isn't actually random\n\n # but uses a reproducible method! These notes\n\n # are therefore repeated over and over...\n\n sleep 0.125\n\n end\n\n end\n\n play notes.choose, amp: 1.5, release: 0.5 # Note that this line is outside of\n\n # the with_random_seed block and therefore\n\n # the randomisation never gets reset and this\n\n # part of the melody never repeats.\n\n end\n\n end\n\n "
},
"use_random_source": {
"summary": "Change how random numbers are chosen",
"doc": "Sets the random number source to be one of `:white`, `:pink`, `:light_pink`, `:dark_pink` or `:perlin`.\n`:white` is totally random - between 0 and 1, you can expect an even spread of values around 0.1, 0.2, 0.3 etc. This means that jumping around within the range (including large jumps) is expected.\n`:pink` is more likely to produce values in the middle of the range and less likely to produce values at the extremes. Between 0 and 1 you expect to see a concentration of values around 0.5. This can make random melodies a little bit more smooth.\n`:perlin` is a special kind of noise which produces gradients, a bit like a mountain landscape. Large jumps are much less likely and you will tend to see lots of smooth motion going either up or down\n`:light_pink` is halfway between white noise and pink noise - more random and jumpy\n`:dark_pink` is halfway between pink noise and brown noise - less jumpy with smoother slopes\nYou can see the 'buckets' that the numbers between 0 and 1 fall into with the following code:\nrand_type :white\nputs 10000.times.collect { rand.round(1) }.tally.sort\nrand_type :pink\nputs 10000.times.collect { rand.round(1) }.tally.sort\nrand_type :perlin\nputs 10000.times.collect { rand.round(1) }.tally.sort\n",
"examples": " use_random_source :white # use white noise as the distribution (default)\n\n rand_reset # reset random seed\n\n puts rand # => 0.75006103515625\n\n puts rand # => 0.733917236328125\n\n puts rand # => 0.464202880859375\n\n rand_reset # reset it again\n\n use_random_source :pink # use pink noise as the distribution\n\n puts rand # => 0.47808837890625\n\n puts rand # => 0.56011962890625\n\n rand_reset # reset it\n\n use_random_source :perlin # use perlin noise as the distribution\n\n puts rand # => 0.546478271484375\n\n puts rand # => 0.573150634765625\n\n with_random_source :white do # use white noise just for this block\n\n puts rand # => 0.464202880859375\n\n end\n\n puts rand # => 0.597015380859375\n\n # notice how the last generator (perlin) is restored"
},
"with_random_source": {
"summary": "Specify random distribution for code block",
"doc": "Resets the random number generator to the specified noise type for the specified code block. All generated random numbers and randomisation functions such as `shuffle` and `choose` within the code block will use this new generator. Once the code block has completed, the original generator is restored and the code block generator is discarded. Use this to change the sequence of random numbers in your piece in a way that can be reproduced. Especially useful if combined with iteration. See examples.",
"examples": " use_random_source :white # use white noise as the distribution (default)\n\n rand_reset # reset random seed\n\n puts rand # => 0.75006103515625\n\n puts rand # => 0.733917236328125\n\n puts rand # => 0.464202880859375\n\n rand_reset # reset it again\n\n use_random_source :pink # use pink noise as the distribution\n\n puts rand # => 0.47808837890625\n\n puts rand # => 0.56011962890625\n\n rand_reset # reset it\n\n use_random_source :perlin # use perlin noise as the distribution\n\n puts rand # => 0.546478271484375\n\n puts rand # => 0.573150634765625\n\n with_random_source :white do # use white noise just for this block\n\n puts rand # => 0.464202880859375\n\n end\n\n puts rand # => 0.597015380859375\n\n # notice how the last generator (perlin) is restored"
},
"use_cue_logging": {
"summary": "Enable and disable cue logging",
"doc": "Enable or disable log messages created on cues. This does not disable the cues themselves, it just stops them from being printed to the log",
"examples": "use_cue_logging true # Turn on cue messages\nuse_cue_logging false # Disable cue messages"
},
"with_cue_logging": {
"summary": "Block-level enable and disable cue logging",
"doc": "Similar to use_cue_logging except only applies to code within supplied `do`/`end` block. Previous cue log value is restored after block.",
"examples": " # Turn on debugging:\n\n use_cue_logging true\n\n cue :foo # cue message is printed to log\n\n with_cue_logging false do\n\n #Cue logging is now disabled\n\n cue :bar # cue *is* sent but not displayed in log\n\n end\n\n sleep 1\n\n # Debug is re-enabled\n\n cue :quux # cue is displayed in log\n\n "
},
"use_bpm": {
"summary": "Set the tempo",
"doc": "Sets the tempo in bpm (beats per minute) for everything afterwards. Affects all subsequent calls to `sleep` and all temporal synth arguments which will be scaled to match the new bpm. If you wish to bypass scaling in calls to sleep, see the fn `rt`. Also, if you wish to bypass time scaling in synth args see `use_arg_bpm_scaling`. See also `with_bpm` for a block scoped version of `use_bpm`.\nFor dance music here's a rough guide for which BPM to aim for depending on your genre:\n* Dub: 60-90 bpm\n* Hip-hop: 60-100 bpm\n* Downtempo: 90-120 bpm\n* House: 115-130 bpm\n* Techno/trance: 120-140 bpm\n* Dubstep: 135-145 bpm\n* Drum and bass: 160-180 bpm",
"examples": " # default tempo is 60 bpm\n\n 4.times do\n\n play 50, attack: 0.5, release: 0.25 # attack is 0.5s and release is 0.25s\n\n sleep 1 # sleep for 1 second\n\n end\n\n sleep 2 # sleep for 2 seconds\n\n # Let's make it go faster...\n\n use_bpm 120 # double the bpm\n\n 4.times do\n\n play 62, attack: 0.5, release: 0.25 # attack is scaled to 0.25s and release is now 0.125s\n\n sleep 1 # actually sleeps for 0.5 seconds\n\n end\n\n sleep 2 # sleep for 1 second\n\n # Let's make it go even faster...\n\n use_bpm 240 # bpm is 4x original speed!\n\n 8.times do\n\n play 62, attack: 0.5, release: 0.25 # attack is scaled to 0.125s and release is now 0.0625s\n\n sleep 1 # actually sleeps for 0.25 seconds\n\n end\n\n "
},
"with_bpm": {
"summary": "Set the tempo for the code block",
"doc": "Sets the tempo in bpm (beats per minute) for everything in the given block. Affects all containing calls to `sleep` and all temporal synth arguments which will be scaled to match the new bpm. See also `use_bpm`\nFor dance music here's a rough guide for which BPM to aim for depending on your genre:\n* Dub: 60-90 bpm\n* Hip-hop: 60-100 bpm\n* Downtempo: 90-120 bpm\n* House: 115-130 bpm\n* Techno/trance: 120-140 bpm\n* Dubstep: 135-145 bpm\n* Drum and bass: 160-180 bpm\n",
"examples": " # default tempo is 60 bpm\n\n 4.times do\n\n sample :drum_bass_hard\n\n sleep 1 # sleeps for 1 second\n\n end\n\n sleep 5 # sleeps for 5 seconds\n\n # with_bpm sets a tempo for everything between do ... end (a block)\n\n # Hear how it gets faster?\n\n with_bpm 120 do # set bpm to be twice as fast\n\n 4.times do\n\n sample :drum_bass_hard\n\n sleep 1 # now sleeps for 0.5 seconds\n\n end\n\n end\n\n sleep 5\n\n # bpm goes back to normal\n\n 4.times do\n\n sample :drum_bass_hard\n\n sleep 1 # sleeps for 1 second\n\n end"
},
"with_bpm_mul": {
"summary": "Set new tempo as a multiple of current tempo for block",
"doc": "Sets the tempo in bpm (beats per minute) for everything in the given block as a multiplication of the current tempo. Affects all containing calls to `sleep` and all temporal synth arguments which will be scaled to match the new bpm. See also `with_bpm`",
"examples": " use_bpm 60 # Set the BPM to 60\n\n play 50\n\n sleep 1 # Sleeps for 1 second\n\n play 62\n\n sleep 2 # Sleeps for 2 seconds\n\n with_bpm_mul 0.5 do # BPM is now (60 * 0.5) == 30\n\n play 50\n\n sleep 1 # Sleeps for 2 seconds\n\n play 62\n\n end\n\n sleep 1 # BPM is now back to 60, therefore sleep is 1 second\n\n "
},
"use_bpm_mul": {
"summary": "Set new tempo as a multiple of current tempo",
"doc": "Sets the tempo in bpm (beats per minute) as a multiplication of the current tempo. Affects all containing calls to `sleep` and all temporal synth arguments which will be scaled to match the new bpm. See also `use_bpm`",
"examples": " use_bpm 60 # Set the BPM to 60\n\n play 50\n\n sleep 1 # Sleeps for 1 seconds\n\n play 62\n\n sleep 2 # Sleeps for 2 seconds\n\n use_bpm_mul 0.5 # BPM is now (60 * 0.5) == 30\n\n play 50\n\n sleep 1 # Sleeps for 2 seconds\n\n play 62\n\n "
},
"density": {
"summary": "Squash and repeat time",
"doc": "Runs the block `d` times with the bpm for the block also multiplied by `d`. Great for repeating sections a number of times faster yet keeping within a fixed time. If `d` is less than 1, then time will be stretched accordingly and the block will take longer to complete.",
"examples": " use_bpm 60 # Set the BPM to 60\n\n density 2 do # BPM for block is now 120\n\n # block is called 2.times\n\n sample :bd_haus # sample is played twice\n\n sleep 0.5 # sleep is 0.25s\n\n end\",\n\n \"\n\n density 2 do |idx| # You may also pass a param to the block similar to n.times\n\n puts idx # prints out 0, 1\n\n sleep 0.5 # sleep is 0.25s\n\n end\n\n \",\n\n \"\n\n density 0.5 do # Specifying a density val of < 1 will stretch out time\n\n # A density of 0.5 will double the length of the block's\n\n # execution time.\n\n play 80, release: 1 # plays note 80 with 2s release\n\n sleep 0.5 # sleep is 1s\n\n end\n\n "
},
"current_time": {
"summary": "Get current (logically quantized) time",
"doc": "Returns the current logical time. This is a 'wall-clock' time which should typically be pretty similar to Time.now but quantised to a nearby sleep point in the thread. May be quite different to Time.now within a time_warp!\nUnlike `Time.now`, Multiple calls to `current_time` with no interleaved calls to `sleep` or `sync` will return the same value.",
"examples": " puts current_time # 2017-03-19 23:37:57 +0000\",\n\n\"\n\n# The difference between current_time and Time.now\n\n# See that Time.now is continuous and current_time is discrete\n\n#\n\n# {run: 19, time: 0.0}\n\nputs \\\"A\\\", Time.now.to_f # ├─ \\\"A\\\" 1489966042.761211\n\nputs \\\"B\\\", __system_thread_locals.get(:sonic_pi_spider_time).to_f # ├─ \\\"B\\\" 1489966042.760181\n\nputs \\\"C\\\", Time.now.to_f # ├─ \\\"C\\\" 1489966042.761235\n\nputs \\\"D\\\", __system_thread_locals.get(:sonic_pi_spider_time).to_f # ├─ \\\"D\\\" 1489966042.760181\n\nputs \\\"E\\\", __system_thread_locals.get(:sonic_pi_spider_time).to_f # └─ \\\"E\\\" 1489966042.760181\n\n"
},
"current_random_seed": {
"summary": "Get current random seed",
"doc": "Returns the current random seed.\nThis can be set via the fns `use_random_seed` and `with_random_seed`. It is incremented every time you use the random number generator via fns such as `choose` and `rand`.",
"examples": " puts current_random_seed # Print out the current random seed\",\n\n\"\n\n## Resetting the seed back to a known place\n\nputs rand #=> 0.75006103515625\n\nputs rand #=> 0.733917236328125\n\na = current_random_seed # Grab the current seed\n\nputs rand #=> 0.464202880859375\n\nputs rand #=> 0.24249267578125\n\nuse_random_seed a # Restore the seed\n\n # we'll now get the same random values:\n\nputs rand #=> 0.464202880859375\n\nputs rand #=> 0.24249267578125\n\n"
},
"current_bpm": {
"summary": "Get current tempo",
"doc": "Returns the current tempo as a bpm value.\nThis can be set via the fns `use_bpm`, `with_bpm`, `use_sample_bpm` and `with_sample_bpm`.",
"examples": " puts current_bpm # Print out the current bpm"
},
"current_beat_duration": {
"summary": "Duration of current beat",
"doc": "Get the duration of the current beat in seconds. This is the actual length of time which will elapse with `sleep 1`.\nAffected by calls to `use_bpm`, `with_bpm`, `use_sample_bpm` and `with_sample_bpm`.",
"examples": " use_bpm 60\n\n puts current_beat_duration #=> 1\n\n use_bpm 120\n\n puts current_beat_duration #=> 0.5"
},
"beat": {
"summary": "Get current beat",
"doc": "Returns the beat value for the current thread/live_loop. Beats are advanced only by calls to `sleep` and `sync`. Beats are distinct from virtual time (the value obtained by calling `vt`) in that it has no notion of rate. It is just essentially a counter for sleeps. After a `sync`, the beat is overridden with the beat value from the thread which called `cue`.",
"examples": " use_bpm 120 # The current BPM makes no difference\n\n puts beat #=> 0\n\n sleep 1\n\n puts beat #=> 1\n\n use_bpm 2000\n\n sleep 2\n\n puts beat #=> 3"
},
"rt": {
"summary": "Real time conversion",
"doc": "Real time representation. Returns the amount of beats for the value in real-time seconds. Useful for bypassing any bpm scaling",
"examples": " use_bpm 120 # modifies all time to be half\n\n play 50\n\n sleep 1 # actually sleeps for half of a second\n\n play 62\n\n sleep rt(1) # bypasses bpm scaling and sleeps for a second\n\n play 72"
},
"bt": {
"summary": "Beat time conversion",
"doc": "Beat time representation. Scales the time to the current BPM. Useful for adding bpm scaling",
"examples": " use_bpm 120 # Set the BPM to be double the default\n\n puts bt(1) # 0.5\n\n use_bpm 60 # BPM is now default\n\n puts bt(1) # 1\n\n use_bpm 30 # BPM is now half the default\n\n puts bt(1) # 2\n\n"
},
"set_sched_ahead_time": {
"summary": "Set sched ahead time globally",
"doc": "Specify how many seconds ahead of time the synths should be triggered. This represents the amount of time between pressing 'Run' and hearing audio. A larger time gives the system more room to work with and can reduce performance issues in playing fast sections on slower platforms. However, a larger time also increases latency between modifying code and hearing the result whilst live coding.",
"examples": "set_sched_ahead_time! 1 # Code will now run approximately 1 second ahead of audio."
},
"use_sched_ahead_time": {
"summary": "Set sched ahead time for the current thread",
"doc": "Specify how many seconds ahead of time the synths should be triggered. This represents the amount of time between pressing 'Run' and hearing audio. A larger time gives the system more room to work with and can reduce performance issues in playing fast sections on slower platforms. However, a larger time also increases latency between modifying code and hearing the result whilst live coding.\nSee `set_sched_ahead_time!` for a global version of this function. Note, `use_sched_ahead_time` will override any value set with `set_sched_ahead_time!` for the current thread.\nSee `use_real_time` for a simple way of setting the schedule ahead time to 0.",
"examples": "use_sched_ahead_time 1 # Code will now run approximately 1 second ahead of audio.\n# Each thread can have its own sched ahead time\n\nlive_loop :foo do\n\n use_sched_ahead_time 1\n\n play 70 # Note 70 will be played with 1 second latency\n\n sleep 1\n\nend\n\nlive_loop :foo do\n\n use_sched_ahead_time 0.5 # Note 70 will be played with 0.5 second latency\n\n play 82\n\n sleep 1\n\nend\n\n"
},
"use_real_time": {
"summary": "Set sched ahead time to 0 for the current thread",
"doc": "Set sched ahead time to 0 for the current thread. Shorthand for `use_sched_ahead_time 0`.\nSee `use_sched_ahead_time` for a version of this function which allows you to set the schedule ahead time to any arbitrary value. Note, `use_real_time` will override any value set with `set_sched_ahead_time!` for the current thread.\n",
"examples": "use_real_time 1 # Code will now run approximately 1 second ahead of audio."
},
"with_real_time": {
"summary": "Sets sched ahead time to 0 within the block for the current thread",
"doc": "Sets sched ahead time to 0 within the block for the current thread. Shorthand for `with_sched_ahead_time 0`.\nSee `with_sched_ahead_time` for a version of this function which allows you to set the schedule ahead time to any arbitrary value. Note, `with_real_time` will override any value set with `set_sched_ahead_time!` for the current thread.\n",
"examples": "use_real_time 1 # Code will now run approximately 1 second ahead of audio."
},
"with_sched_ahead_time": {
"summary": "Block-level set sched ahead time for the current thread",
"doc": "Specify how many seconds ahead of time the synths should be triggered for the block. See `use_sched_ahead_time` for further information.\nSee `set_sched_ahead_time!` for a global version of this function. Note, `with_sched_ahead_time` will override any value set with `set_sched_ahead_time!` for the given block within the current thread.\nSee `with_real_time` for a simple way of setting the schedule ahead time to 0.",
"examples": "with_sched_ahead_time 1 do\n\n play 70 # Sound will happen with a latency of 1\n\nend\n\nplay 70 # Sound will happen with the default latency (0.5s)\n\n"
},
"current_sched_ahead_time": {
"summary": "Get current sched ahead time",
"doc": "Returns the current schedule ahead time.\nThis can be set via the fn `set_sched_ahead_time!`.",
"examples": "set_sched_ahead_time! 0.5\n\nputs current_sched_ahead_time # Prints 0.5"
},
"sleep": {
"summary": "Wait for beat duration",
"doc": "Wait for a number of beats before triggering the next command. Beats are converted to seconds by scaling to the current bpm setting.",
"examples": " # Without calls to sleep, all sounds would happen at once:\n\n play 50 # This is actually a chord with all notes played simultaneously\n\n play 55\n\n play 62\n\n sleep 1 # Create a gap, to allow a moment's pause for reflection...\n\n play 50 # Let's try the chord again, but this time with sleeps:\n\n sleep 0.5 # With the sleeps, we turn a chord into an arpeggio\n\n play 55\n\n sleep 0.5\n\n play 62\",\n\n \"\n\n # The amount of time sleep pauses for is scaled to match the current bpm. The default bpm is 60. Let's double it:\n\n use_bpm 120\n\n play 50\n\n sleep 1 # This actually sleeps for 0.5 seconds as we're now at double speed\n\n play 55\n\n sleep 1\n\n play 62\n\n # Let's go down to half speed:\n\n use_bpm 30\n\n play 50\n\n sleep 1 # This now sleeps for 2 seconds as we're now at half speed.\n\n play 55\n\n sleep 1\n\n play 62\n\n "
},
"wait": {
"summary": "Wait for duration",
"doc": "Synonym for `sleep` - see `sleep`"
},
"sync_bpm": {
"summary": "Sync and inherit BPM from other threads ",
"doc": "An alias for `sync` with the `bpm_sync:` opt set to true.",
"examples": "See examples for sync"
},
"sync": {
"summary": "Sync with other threads",
"doc": "Pause/block the current thread until a `cue` heartbeat with a matching `cue_id` is received. When a matching `cue` message is received, unblock the current thread, and continue execution with the virtual time set to match the thread that sent the `cue` heartbeat. The current thread is therefore synced to the `cue` thread. If multiple cue ids are passed as arguments, it will `sync` on the first matching `cue_id`. The BPM of the cueing thread can optionally be inherited by using the bpm_sync: opt.",
"examples": " in_thread do\n\n sync :foo # this parks the current thread waiting for a foo sync message to be received.\n\n sample :ambi_lunar_land\n\n end\n\n sleep 5\n\n cue :foo # We send a sync message from the main thread.\n\n # This then unblocks the thread above and we then hear the sample\",\n\n \"\n\n in_thread do # Start a metronome thread\n\n loop do # Loop forever:\n\n cue :tick # sending tick heartbeat messages\n\n sleep 0.5 # and sleeping for 0.5 beats between ticks\n\n end\n\n end\n\n # We can now play sounds using the metronome.\n\n loop do # In the main thread, just loop\n\n sync :tick # waiting for :tick sync messages\n\n sample :drum_heavy_kick # after which play the drum kick sample\n\n end\",\n\n \"\n\n sync :foo, :bar # Wait for either a :foo or :bar cue \",\n\n \"\n\n in_thread do # Start a metronome thread\n\n loop do # Loop forever:\n\n cue [:foo, :bar, :baz].choose # sending one of three tick heartbeat messages randomly\n\n sleep 0.5 # and sleeping for 0.5 beats between ticks\n\n end\n\n end\n\n # We can now play sounds using the metronome:\n\n in_thread do\n\n loop do # In the main thread, just loop\n\n sync :foo # waiting for :foo sync messages\n\n sample :elec_beep # after which play the elec beep sample\n\n end\n\n end\n\n in_thread do\n\n loop do # In the main thread, just loop\n\n sync :bar # waiting for :bar sync messages\n\n sample :elec_flip # after which play the elec flip sample\n\n end\n\n end\n\n in_thread do\n\n loop do # In the main thread, just loop\n\n sync :baz # waiting for :baz sync messages\n\n sample :elec_blup # after which play the elec blup sample\n\n end\n\n end"
},
"in_thread": {
"summary": "Run code block at the same time",
"doc": "Execute a given block (between `do` ... `end`) in a new thread. Use for playing multiple 'parts' at once. Each new thread created inherits all the use/with defaults of the parent thread such as the time, current synth, bpm, default synth args, etc. Despite inheriting defaults from the parent thread, any modifications of the defaults in the new thread will *not* affect the parent thread. Threads may be named with the `name:` optional arg. Named threads will print their name in the logging pane when they print their activity. If you attempt to create a new named thread with a name that is already in use by another executing thread, no new thread will be created.\nIt is possible to delay the initial trigger of the thread on creation with both the `delay:` and `sync:` opts. See their respective docstrings. If both `delay:` and `sync:` are specified, on initial thread creation first the delay will be honoured and then the sync.\n",
"examples": " loop do # If you write two loops one after another like this,\n\n play 50 # then only the first loop will execute as the loop acts\n\n sleep 1 # like a trap not letting the flow of control out\n\n end\n\n loop do # This code is never executed.\n\n play 55\n\n sleep 0.5\n\n end \",\n\n \"\n\n # In order to play two loops at the same time, the first loops need to\n\n # be in a thread (note that it's probably more idiomatic to use live_loop\n\n # when performing):\n\n # By wrapping our loop in an in_thread block, we split the\n\n # control flow into two parts. One flows into the loop (a) and\n\n # the other part flows immediately after the in_thread block (b).\n\n # both parts of the control flow execute at exactly the same time.\n\n in_thread do\n\n # (a)\n\n loop do\n\n # (a)\n\n play 50\n\n sleep 1\n\n end\n\n end\n\n # (b)\n\n loop do # This loop is executed thanks to the thread above\n\n play 55\n\n sleep 0.5\n\n end\",\n\n \"\n\n use_bpm 120 # Set the bpm to be double rate\n\n use_synth :dsaw # Set the current synth to be :dsaw\n\n in_thread do # Create a new thread\n\n play 50 # Play note 50 at time 0\n\n use_synth :fm # Switch to fm synth (only affects this thread)\n\n sleep 1 # sleep for 0.5 seconds (as we're double rate)\n\n play 38 # Play note 38 at time 0.5\n\n end\n\n play 62 # Play note 62 at time 0 (with dsaw synth)\n\n sleep 2 # sleep 1s\n\n play 67 # Play note 67 at time 1s (also with dsaw synth)\n\n \",\n\n \"\n\n in_thread(name: :foo) do # Here we've created a named thread\n\n loop do\n\n sample :drum_bass_hard\n\n sleep 1\n\n end\n\n end\n\n in_thread(name: :foo) do # This thread isn't created as the name is\n\n loop do # the same as the previous thread which is\n\n sample :elec_chime # still executing.\n\n sleep 0.5\n\n end\n\n end\",\n\n \"\n\n # Named threads work well with functions for live coding:\n\n define :foo do # Create a function foo\n\n play 50 # which does something simple\n\n sleep 1 # and sleeps for some time\n\n end\n\n in_thread(name: :main) do # Create a named thread\n\n loop do # which loops forever\n\n foo # calling our function\n\n end\n\n end\n\n # We are now free to modify the contents of :foo and re-run the entire buffer.\n\n # We'll hear the effect immediately without having to stop and re-start the code.\n\n # This is because our fn has been redefined, (which our thread will pick up) and\n\n # due to the thread being named, the second re-run will not create a new similarly\n\n # named thread. This is a nice pattern for live coding and is the basis of live_loop.\n\n \",\n\n \"\n\n #Delaying the start of a thread\n\n in_thread delay: 1 do\n\n sample :ambi_lunar_land # this sample is not triggered at time 0 but after 1 beat\n\n end\n\n play 80 # Note 80 is played at time 0\n\n "
},
"assert_error": {
"summary": "Ensure block throws an error",
"doc": "Runs the block and ensures that it raises the correct Exception. Useful for asserting that an Exception will be raised. You may specify the particular Exception class, which defaults to `Exception`.",
"examples": "assert_error do\n\n play 70\n\nend # Will throw an exception: \\\"Assert error failed!\\\" as the block\n\n # contains no errors.\n\n\",\n\n \"\n\nassert_error do\n\n 1 / 0\n\nend # Will not throw an exception as the block contains an error.\",\n\n \"\n\nassert_error ZeroDivisionError do\n\n 1 / 0\n\nend # Will not throw an exception as the block contains a ZeroDivisionError.\",\n\n \"\n\nassert_error ThreadError do\n\n 1 / 0\n\nend # Will throw an exception as the block contains a ZeroDivisionError rather than\n\n # a ThreadError."
},
"assert_not": {
"summary": "Ensure arg is not valid",
"doc": "Raises an exception if the argument is not either nil or false.",
"examples": "# Simple assertions\n\nassert_not false # As false is either nil or false, this assertion passes\n\nassert_not nil # As nil is either nil or false, this assertion passes\n\nassert_not 1 == 5 # These numbers are not equal\n\nassert true # This will raise an exception\n\n\",\n\n\"\n\n# Communicating error messages\n\nassert_not true , \\\"oops\\\" # This will raise an exception containing the message \\\"oops\\\"\n\n"
},
"assert": {
"summary": "Ensure arg is valid",
"doc": "Raises an exception if the argument is either nil or false.",
"examples": "# Simple assertions\n\nassert true # As true is neither nil or false, this assertion passes\n\nassert 1 # Similarly, 1 passes\n\nassert \\\"foo\\\" # As do string\n\nassert false # This will raise an exception\n\n\",\n\n\"\n\n# Communicating error messages\n\nassert false, \\\"oops\\\" # This will raise an exception containing the message \\\"oops\\\"\n\n\",\n\n\"\n\n# More interesting assertions\n\nassert (1 + 1) == 2 # Ensure that arithmetic is sane!\n\nassert [:a, :b, :c].size == 3 # ensure lists can be correctly counted\n\n"
},
"assert_not_equal": {
"summary": "Ensure args are not equal",
"doc": "Raises an exception if both arguments are qual.",
"examples": "# Simple assertions\n\nassert_not_equal 1, 3\n\nassert_not_equal 1, -1\n\nassert_not_equal 1, :foo\n\n\",\n\n\"\n\n# Add messages to the exceptions\n\nassert_not_equal 3, 3, \\\"something is seriously wrong!\\\"\n\n"
},
"assert_equal": {
"summary": "Ensure args are equal",
"doc": "Raises an exception if both arguments aren't equal.",
"examples": "# Simple assertions\n\nassert_equal 1, 1\n\n\",\n\n\"\n\n# More interesting assertions\n\nassert_equal 1 + 1, 2 # Ensure that arithmetic is sane!\n\nassert_equal [:a, :b, :c].size, 3 # ensure lists can be correctly counted\n\n\",\n\n\"\n\n# Add messages to the exceptions\n\nassert_equal 3, 5, \\\"something is seriously wrong!\\\"\n\n"
},
"assert_similar": {
"summary": "Ensure args are similar",
"doc": "Raises an exception if both arguments aren't similar.\nCurrently similarity is only defined for numbers - all other types are compared for equality with assert_equal.\nUseful for testing in cases where floating point imprecision stops you from being able to use `assert_equal`. ",
"examples": "# Simple assertions\n\nassert_similar 1, 1 #=> True\n\n\",\n\n\"\n\n# Handles floating point imprecision\n\nassert_similar(4.9999999999, 5.0) #=> True"
},
"load_buffer": {
"summary": "Load the contents of a file to the current buffer",
"doc": "Given a path to a file, will read the contents and load it into the current buffer. This will replace any previous content.",
"examples": "load_buffer \\\"~/sonic-pi-tracks/phat-beats.rb\\\" # will replace content of current buffer with contents of the file"
},
"load_example": {
"summary": "Load a built-in example",
"doc": "Given a keyword representing an example, will load it into the current buffer. This will replace any previous content.",
"examples": "load_example :rerezzed # will replace content of current buffer with the rerezzed example"
},
"use_timing_guarantees": {
"summary": "Inhibit synth triggers if too late",
"doc": "If set to true, synths will not trigger if it is too late. If false, some synth triggers may be late.",
"examples": "use_timing_guarantees true\n\nsample :loop_amen #=> if time is behind by any margin, this will not trigger\",\n\n \"\n\nuse_timing_guarantees false\n\nsample :loop_amen #=> unless time is too far behind, this will trigger even when late."
},
"with_timing_guarantees": {
"summary": "Block-scoped inhibition of synth triggers if too late",
"doc": "For the given block, if set to true, synths will not trigger if it is too late. If false, some synth triggers may be late. After the block has completed, the previous value is restored.",
"examples": "with_timing_guarantees true do\n\n sample :loop_amen #=> if time is behind by any margin, this will not trigger\n\nend\",\n\n\"\n\nwith_timing_guarantees false do\n\n sample :loop_amen #=> unless time is too far behind, this will trigger even when late.\n\nend"
},
"use_sample_bpm": {
"summary": "Sample-duration-based bpm modification",
"doc": "Modify bpm so that sleeping for 1 will sleep for the duration of the sample.",
"examples": "use_sample_bpm :loop_amen #Set bpm based on :loop_amen durationlive_loop :dnb do\n\n sample :bass_dnb_f\n\n sample :loop_amen\n\n sleep 1 #`sleep`ing for 1 actually sleeps for duration of :loop_amen\n\nend\",\n\n \"\n\nuse_sample_bpm :loop_amen, num_beats: 4 # Set bpm based on :loop_amen duration\n\n # but also specify that the sample duration\n\n # is actually 4 beats long.\n\nlive_loop :dnb do\n\n sample :bass_dnb_f\n\n sample :loop_amen\n\n sleep 4 #`sleep`ing for 4 actually sleeps for duration of :loop_amen\n\n # as we specified that the sample consisted of\n\n # 4 beats\n\nend"
},
"with_sample_bpm": {
"summary": "Block-scoped sample-duration-based bpm modification",
"doc": "Block-scoped modification of bpm so that sleeping for 1 will sleep for the duration of the sample.",
"examples": "live_loop :dnb do\n\n with_sample_bpm :loop_amen do #Set bpm based on :loop_amen duration\n\n sample :bass_dnb_f\n\n sample :loop_amen\n\n sleep 1 #`sleep`ing for 1 sleeps for duration of :loop_amen\n\n end\n\nend\",\n\n \"live_loop :dnb do\n\n with_sample_bpm :loop_amen, num_beats: 4 do # Set bpm based on :loop_amen duration\n\n # but also specify that the sample duration\n\n # is actually 4 beats long.\n\n sample :bass_dnb_f\n\n sample :loop_amen\n\n sleep 4 #`sleep`ing for 4 sleeps for duration of :loop_amen\n\n # as we specified that the sample consisted of\n\n # 4 beats\n\n end\n\nend"
},
"use_arg_bpm_scaling": {
"summary": "Enable and disable BPM scaling",
"doc": "Turn synth argument bpm scaling on or off for the current thread. This is on by default. Note, using `rt` for args will result in incorrect times when used after turning arg bpm scaling off.",
"examples": "use_bpm 120\n\nplay 50, release: 2 # release is actually 1 due to bpm scaling\n\nsleep 2 # actually sleeps for 1 second\n\nuse_arg_bpm_scaling false\n\nplay 50, release: 2 # release is now 2\n\nsleep 2 # still sleeps for 1 second\",\n\n \" # Interaction with rt\n\nuse_bpm 120\n\nplay 50, release: rt(2) # release is 2 seconds\n\nsleep rt(2) # sleeps for 2 seconds\n\nuse_arg_bpm_scaling false\n\nplay 50, release: rt(2) # ** Warning: release is NOT 2 seconds! **\n\nsleep rt(2) # still sleeps for 2 seconds"
},
"with_arg_bpm_scaling": {
"summary": "Block-level enable and disable BPM scaling",
"doc": "Turn synth argument bpm scaling on or off for the supplied block. Note, using `rt` for args will result in incorrect times when used within this block.",
"examples": "use_bpm 120play 50, release: 2 # release is actually 1 due to bpm scaling\n\nwith_arg_bpm_scaling false do\n\n play 50, release: 2 # release is now 2\n\nend\",\n\n \" # Interaction with rt\n\nuse_bpm 120\n\nplay 50, release: rt(2) # release is 2 seconds\n\nsleep rt(2) # sleeps for 2 seconds\n\nwith_arg_bpm_scaling false do\n\n play 50, release: rt(2) # ** Warning: release is NOT 2 seconds! **\n\n sleep rt(2) # still sleeps for 2 seconds\n\nend"
},
"set_audio_latency": {
"summary": "Globally modify audio latency",
"doc": "On some systems with certain configurations (such as wireless speakers, and even a typical Windows environment with the default audio drivers) the audio latency can be large. If all the user is doing is generating audio via calls such as `play`, `synth` and `sample`, then this latency essentially adds to the schedule ahead time and for the most part can be ignored. However, if the user is combining audio with external MIDI/OSC triggered events, this latency can result in a noticeable offset. This function allows you to address this offset by moving the audio events forwards and backwards in time.\nSo, for example, if your audio system has an audio latency of 150ms, you can compensate for this by setting Sonic Pi's latency to be a negative value: `set_audio_latency! -150`.",
"examples": "set_audio_latency! 100 # Audio events will now be scheduled 100ms # after the schedule ahead time\",\n\n \"set_audio_latency! -200 # Audio events will now be scheduled 200ms\n\n # before the schedule ahead time"
},
"set_recording_bit_depth": {
"summary": "Set the bit depth for recording wav files",
"doc": "When you hit the record button, Sonic Pi saves all the audio you can hear into a wav file. By default, this file uses a resolution of 16 bits which is the same as CD audio and good enough for most use cases. However, when working with professional equipment, it is common to want to work with even higher quality files such as 24 bits and even 32 bits. This function allows you to switch the default from 16 to one of 8, 16, 24 or 32.",
"examples": "\n\nset_recording_bit_depth! 24 # Set recording bit depth to 24"
},
"set_control_delta": {
"summary": "Set control delta globally",
"doc": "Specify how many seconds between successive modifications (i.e. trigger then controls) of a specific node on a specific thread. Set larger if you are missing control messages sent extremely close together in time.",
"examples": "\n\nset_control_delta! 0.1 # Set control delta to 0.1\n\ns = play 70, release: 8, note_slide: 8 # Play a note and set the slide time\n\ncontrol s, note: 82 # immediately start sliding note.\n\n # This control message might not be\n\n # correctly handled as it is sent at the\n\n # same virtual time as the trigger.\n\n # If you don't hear a slide, try increasing the\n\n # control delta until you do."
},
"use_debug": {
"summary": "Enable and disable debug",
"doc": "Enable or disable messages created on synth triggers. If this is set to false, the synths will be silent until debug is turned back on. Silencing debug messages can reduce output noise and also increase performance on slower platforms. See `with_debug` for setting the debug value only for a specific `do`/`end` block.",
"examples": "use_debug true # Turn on debug messages\nuse_debug false # Disable debug messages"
},
"with_debug": {
"summary": "Block-level enable and disable debug",
"doc": "Similar to use_debug except only applies to code within supplied `do`/`end` block. Previous debug value is restored after block.",
"examples": "# Turn on debugging:\n\nuse_debug true\n\nplay 80 # Debug message is sent\n\nwith_debug false do\n\n #Debug is now disabled\n\n play 50 # Debug message is not sent\n\n sleep 1\n\n play 72 # Debug message is not sent\n\nend\n\n# Debug is re-enabled\n\nplay 90 # Debug message is sent\n\n"
},
"use_arg_checks": {
"summary": "Enable and disable arg checks",
"doc": "When triggering synths, each argument is checked to see if it is sensible. When argument checking is enabled and an argument isn't sensible, you'll see an error in the debug pane. This setting allows you to explicitly enable and disable the checking mechanism. See with_arg_checks for enabling/disabling argument checking only for a specific `do`/`end` block.",
"examples": "play 50, release: 5 # Args are checked\n\nuse_arg_checks false\n\nplay 50, release: 5 # Args are not checked"
},
"with_arg_checks": {
"summary": "Block-level enable and disable arg checks",
"doc": "Similar to `use_arg_checks` except only applies to code within supplied `do`/`end` block. Previous arg check value is restored after block.",
"examples": "# Turn on arg checking:\n\nuse_arg_checks true\n\nplay 80, cutoff: 100 # Args are checked\n\nwith_arg_checks false do\n\n #Arg checking is now disabled\n\n play 50, release: 3 # Args are not checked\n\n sleep 1\n\n play 72 # Arg is not checked\n\nend\n\n# Arg checking is re-enabled\n\nplay 90 # Args are checked\n\n"
},
"use_synth": {
"summary": "Switch current synth",
"doc": "Switch the current synth to `synth_name`. Affects all further calls to `play`. See `with_synth` for changing the current synth only for a specific `do`/`end` block.",
"examples": "play 50 # Plays with default synth\n\nuse_synth :mod_sine\n\nplay 50 # Plays with mod_sine synth"
},
"with_synth": {
"summary": "Block-level synth switching",
"doc": "Switch the current synth to `synth_name` but only for the duration of the `do`/`end` block. After the `do`/`end` block has completed, the previous synth is restored.",
"examples": "play 50 # Plays with default synth\n\nsleep 2\n\nuse_synth :supersaw\n\nplay 50 # Plays with supersaw synth\n\nsleep 2\n\nwith_synth :saw_beep do\n\n play 50 # Plays with saw_beep synth\n\nend\n\nsleep 2\n\n# Previous synth is restored\n\nplay 50 # Plays with supersaw synth\n\n"
},
"recording_start": {
"summary": "Start recording",
"doc": "Start recording all sound to a `.wav` file stored in a temporary directory."
},
"recording_stop": {
"summary": "Stop recording",
"doc": "Stop current recording."
},
"recording_save": {
"summary": "Save recording",
"doc": "Save previous recording to the specified location"
},
"recording_delete": {
"doc": "After using `recording_start` and `recording_stop`, a temporary file is created until you decide to use `recording_save`. If you've decided you don't want to save it you can use this method to delete the temporary file straight away, otherwise the operating system will take care of deleting it later."
},
"reset_mixer": {
"summary": "Reset main mixer",
"doc": "The main mixer is the final mixer that all sound passes through. This fn resets it to its default set - undoing any changes made via set_mixer_control!",
"examples": "set_mixer_control! lpf: 70 # LPF cutoff value of main mixer is now 70\n\nsample :loop_amen # :loop_amen sample is played with low cutoff\n\nsleep 3\n\nreset_mixer! # mixer is now reset to default values\n\nsample :loop_amen # :loop_amen sample is played with normal cutoff"
},
"set_mixer_control": {
"summary": "Control main mixer",
"doc": "The main mixer is the final mixer that all sound passes through. This fn gives you control over the main mixer allowing you to manipulate all the sound playing through Sonic Pi at once. For example, you can sweep a lpf or hpf over the entire sound. You can reset the controls back to their defaults with `reset_mixer!`.",
"examples": "set_mixer_control! lpf: 30, lpf_slide: 16 # slide the global lpf to 30 over 16 beats."
},
"synth": {
"summary": "Trigger specific synth",
"doc": "Trigger specified synth with given opts. Bypasses `current_synth` value, yet still honours `current_synth_defaults`. When using `synth`, the note is no longer an explicit argument but an opt with the key `note:`.\nIf note: opt is `nil`, `:r` or `:rest`, play is ignored and treated as a rest. Also, if the `on:` opt is specified and returns `false`, or `nil` then play is similarly ignored and treated as a rest.\nIf the synth name is `nil` behaviour is identical to that of `play` in that the `current_synth` will determine the actual synth triggered.\nIf a block is given, it is assumed to take one arg which will be the controllable synth node and the body of the block is run in an implicit `in_thread`. This allows for asynchronous control of the synth without interfering with time. For synchronous control capture the result of `synth` as a variable and use that.\nNote that the default opts listed are only a guide to the most common opts across all the synths. Not all synths support all the default opts and each synth typically supports many more opts specific to that synth. For example, the `:tb303` synth supports 45 unique opts. For a full list of a synth's opts see its documentation in the Help system. This can be accessed directly by clicking on the name of the synth and using the shortcut `C-i`",
"examples": "\n\nuse_synth :beep # Set current synth to :beep\n\nplay 60 # Play note 60 with opt defaults\n\nsynth :dsaw, note: 60 # Bypass current synth and play :dsaw\n\n # with note 60 and opt defaults \",\n\n\"\n\nsynth :fm, note: 60, amp: 0.5 # Play note 60 of the :fm synth with an amplitude of 0.5\",\n\n \"\n\nuse_synth_defaults release: 5\n\nsynth :dsaw, note: 50 # Play note 50 of the :dsaw synth with a release of 5\",\n\n\"# You can play chords with the notes: opt:\n\nsynth :dsaw, notes: (chord :e3, :minor)\",\n\n\"\n\n# on: vs if\n\nnotes = (scale :e3, :minor_pentatonic, num_octaves: 2)\n\nlive_loop :rhyth do\n\n 8.times do\n\n trig = (spread 3, 7).tick(:rhyth)\n\n synth :tri, on: trig, note: notes.tick, release: 0.1 # Here, we're calling notes.tick\n\n # every time we attempt to play the synth\n\n # so the notes rise faster than rhyth2\n\n sleep 0.125\n\n end\n\nend\n\nlive_loop :rhyth2 do\n\n 8.times do\n\n trig = (spread 3, 7).tick(:rhyth)\n\n synth :saw, note: notes.tick, release: 0.1 if trig # Here, we're calling notes.tick\n\n # only when the spread says to play\n\n # so the notes rise slower than rhyth\n\n sleep 0.125\n\n end\n\nend\n\n\",\n\n\" # controlling a synth synchronously\n\ns = synth :beep, note: :e3, release: 4\n\nsleep 1\n\ncontrol s, note: :e5\n\nsleep 0.5\n\nsynth :dsaw, note: :e3 # This is triggered after 1.5s from start\",\n\n\" # Controlling a synth asynchronously\n\nsynth :beep, note: :e3, release: 4 do |s|\n\n sleep 1 # This block is run in an implicit in_thread\n\n control s, note: :e5 # and therefore is asynchronous\n\nend\n\nsleep 0.5\n\nsynth :dsaw, note: :e3 # This is triggered after 0.5s from start"
},
"play": {
"summary": "Play current synth",
"doc": "Play note with current synth. Accepts a set of standard options which include control of an amplitude envelope with `attack:`, `decay:`, `sustain:` and `release:` phases. These phases are triggered in order, so the duration of the sound is attack + decay + sustain + release times. The duration of the sound does not affect any other notes. Code continues executing whilst the sound is playing through its envelope phases.\nIf `duration:` is supplied and `sustain:` isn't, it causes `sustain:` to be set so that all four phases add up to the duration.\nAccepts optional args for modification of the synth being played. See each synth's documentation for synth-specific opts. See `use_synth` and `with_synth` for changing the current synth.\nIf note is `nil`, `:r` or `:rest`, play is ignored and treated as a rest. Also, if the `on:` opt is specified and returns `false`, or `nil` then play is similarly ignored and treated as a rest.\nNote that the default opts listed are only a guide to the most common opts across all the synths. Not all synths support all the default opts and each synth typically supports many more opts specific to that synth. For example, the `:tb303` synth supports 45 unique opts. For a full list of a synth's opts see its documentation in the Help system.\n",
"examples": "play 50 # Plays note 50 on the current synth\",\n\n \"play 50, attack: 1 # Plays note 50 with a fade-in time of 1s\",\n\n \"play 62, pan: -1, release: 3 # Play note 62 in the left ear with a fade-out time of 3s.\",\n\n \" # controlling a synth synchronously\n\ns = play :e3, release: 4\n\nsleep 1\n\ncontrol s, note: :e5\n\nsleep 0.5\n\nuse_synth :dsaw\n\nplay :e3 # This is triggered after 1.5s from start\",\n\n\" # Controlling a synth asynchronously\n\nplay :e3, release: 4 do |s|\n\n sleep 1 # This block is run in an implicit in_thread\n\n control s, note: :e5 # and therefore is asynchronous\n\nend\n\nsleep 0.5\n\nuse_synth :dsaw\n\nplay :e3 # This is triggered after 0.5s from start"
},
"play_pattern": {
"summary": "Play pattern of notes",
"doc": "Play list of notes with the current synth one after another with a sleep of 1\nAccepts optional args for modification of the synth being played. See each synth's documentation for synth-specific opts. See use_synth and with_synth for changing the current synth.",
"examples": "play_pattern [40, 41, 42] # Same as:\n\n # play 40\n\n # sleep 1\n\n # play 41\n\n # sleep 1\n\n # play 42\n\n\",\n\n \"play_pattern [:d3, :c1, :Eb5] # You can use keyword notes\",\n\n \"play_pattern [:d3, :c1, :Eb5], amp: 0.5, cutoff: 90 # Supports the same arguments as play:"
},
"play_pattern_timed": {
"summary": "Play pattern of notes with specific times",
"doc": "Play each note in a list of notes one after another with specified times between them. The notes should be a list of MIDI numbers, symbols such as :E4 or chords such as chord(:A3, :major) - identical to the first parameter of the play function. The times should be a list of times between the notes in beats.\nIf the list of times is smaller than the number of gaps between notes, the list is repeated again. If the list of times is longer than the number of gaps between notes, then some of the times are ignored. See examples for more detail.\nAccepts optional args for modification of the synth being played. See each synth's documentation for synth-specific opts. See `use_synth` and `with_synth` for changing the current synth.",
"examples": "play_pattern_timed [40, 42, 44, 46], [1, 2, 3]\n\n# same as:\n\nplay 40\n\nsleep 1\n\nplay 42\n\nsleep 2\n\nplay 44\n\nsleep 3\n\nplay 46\",\n\n \"play_pattern_timed [40, 42, 44, 46, 49], [1, 0.5]\n\n# same as:\n\nplay 40\n\nsleep 1\n\nplay 42\n\nsleep 0.5\n\nplay 44\n\nsleep 1\n\nplay 46\n\nsleep 0.5\n\nplay 49\",\n\n \"play_pattern_timed [40, 42, 44, 46], [0.5]\n\n# same as:\n\nplay 40\n\nsleep 0.5\n\nplay 42\n\nsleep 0.5\n\nplay 44\n\nsleep 0.5\n\nplay 46\",\n\n \"play_pattern_timed [40, 42, 44], [1, 2, 3, 4, 5]\n\n#same as:\n\nplay 40\n\nsleep 1\n\nplay 42\n\nsleep 2\n\nplay 44"
},
"play_chord": {
"summary": "Play notes simultaneously",
"doc": "Play a list of notes at the same time.\nAccepts optional args for modification of the synth being played. See each synth's documentation for synth-specific opts. See `use_synth` and `with_synth` for changing the current synth.",
"examples": "play_chord [40, 45, 47]\n\n# same as:\n\nplay 40\n\nplay 45\n\nplay 47\",\n\n \"play_chord [40, 45, 47], amp: 0.5\n\n# same as:\n\nplay 40, amp: 0.5\n\nplay 45, amp: 0.5\n\nplay 47, amp: 0.5\",\n\n \"play_chord chord(:e3, :minor)"
},
"use_merged_synth_defaults": {
"summary": "Merge synth defaults",
"doc": "Specify synth arg values to be used by any following call to play. Merges the specified values with any previous defaults, rather than replacing them.",
"examples": "play 50 #=> Plays note 50\n\nuse_merged_synth_defaults amp: 0.5\n\nplay 50 #=> Plays note 50 with amp 0.5\n\nuse_merged_synth_defaults cutoff: 80\n\nplay 50 #=> Plays note 50 with amp 0.5 and cutoff 80\n\nuse_merged_synth_defaults amp: 0.7\n\nplay 50 #=> Plays note 50 with amp 0.7 and cutoff 80\n\n\",\n\n \"use_synth_defaults amp: 0.5, cutoff: 80, pan: -1\n\nuse_merged_synth_defaults amp: 0.7\n\nplay 50 #=> Plays note 50 with amp 0.7, cutoff 80 and pan -1"
},
"with_merged_synth_defaults": {
"summary": "Block-level merge synth defaults",
"doc": "Specify synth arg values to be used by any following call to play within the specified `do`/`end` block. Merges the specified values with any previous synth defaults, rather than replacing them. After the `do`/`end` block has completed, previous defaults (if any) are restored.",
"examples": "with_merged_synth_defaults amp: 0.5, pan: 1 do\n\n play 50 # => plays note 50 with amp 0.5 and pan 1\n\nend\",\n\n \"play 50 #=> plays note 50\n\nwith_merged_synth_defaults amp: 0.5 do\n\n play 50 #=> plays note 50 with amp 0.5\n\n with_merged_synth_defaults pan: -1 do\n\n with_merged_synth_defaults amp: 0.7 do\n\n play 50 #=> plays note 50 with amp 0.7 and pan -1\n\n end\n\n end\n\n play 50 #=> plays note 50 with amp 0.5\n\nend"
},
"use_synth_defaults": {
"summary": "Use new synth defaults",
"doc": "Specify new default values to be used by all subsequent calls to `play`. Will remove and override any previous defaults.",
"examples": "play 50 # plays note 50 with default arguments\n\nuse_synth_defaults amp: 0.5, cutoff: 70\n\nplay 50 # plays note 50 with an amp of 0.5, cutoff of 70 and defaults for rest of args\n\nuse_synth_defaults cutoff: 90\n\nplay 50 # plays note 50 with a cutoff of 90 and defaults for rest of args - note that amp is no longer 0.5\n\n"
},
"use_sample_defaults": {
"summary": "Use new sample defaults",
"doc": "Specify new default values to be used by all subsequent calls to `sample`. Will remove and override any previous defaults.",
"examples": "sample :loop_amen # plays amen break with default arguments\n\nuse_sample_defaults amp: 0.5, cutoff: 70\n\nsample :loop_amen # plays amen break with an amp of 0.5, cutoff of 70 and defaults for rest of args\n\nuse_sample_defaults cutoff: 90\n\nsample :loop_amen # plays amen break with a cutoff of 90 and defaults for rest of args - note that amp is no longer 0.5\n\n"
},
"use_merged_sample_defaults": {
"summary": "Merge new sample defaults",
"doc": "Specify new default values to be used by all subsequent calls to `sample`. Merges the specified values with any previous defaults, rather than replacing them.",
"examples": "sample :loop_amen # plays amen break with default arguments\n\nuse_merged_sample_defaults amp: 0.5, cutoff: 70\n\nsample :loop_amen # plays amen break with an amp of 0.5, cutoff of 70 and defaults for rest of args\n\nuse_merged_sample_defaults cutoff: 90\n\nsample :loop_amen # plays amen break with a cutoff of 90 and and an amp of 0.5 with defaults for rest of args\n\n"
},
"with_sample_defaults": {
"summary": "Block-level use new sample defaults",
"doc": "Specify new default values to be used by all subsequent calls to `sample` within the `do`/`end` block. After the `do`/`end` block has completed, the previous sampled defaults (if any) are restored. For the contents of the block, will remove and override any previous defaults.",
"examples": "sample :loop_amen # plays amen break with default arguments\n\nuse_sample_defaults amp: 0.5, cutoff: 70\n\nsample :loop_amen # plays amen break with an amp of 0.5, cutoff of 70 and defaults for rest of args\n\nwith_sample_defaults cutoff: 90 do\n\n sample :loop_amen # plays amen break with a cutoff of 90 and defaults for rest of args - note that amp is no longer 0.5\n\nend\n\nsample :loop_amen # plays amen break with a cutoff of 70 and amp is 0.5 again as the previous defaults are restored."
},
"with_merged_sample_defaults": {
"summary": "Block-level use merged sample defaults",
"doc": "Specify new default values to be used by all subsequent calls to `sample` within the `do`/`end` block. Merges the specified values with any previous sample defaults, rather than replacing them. After the `do`/`end` block has completed, the previous sampled defaults (if any) are restored.",
"examples": "sample :loop_amen # plays amen break with default arguments\n\nuse_merged_sample_defaults amp: 0.5, cutoff: 70\n\nsample :loop_amen # plays amen break with an amp of 0.5, cutoff of 70 and defaults for rest of args\n\nwith_merged_sample_defaults cutoff: 90 do\n\n sample :loop_amen # plays amen break with a cutoff of 90 and amp of 0.5\n\nend\n\nsample :loop_amen # plays amen break with a cutoff of 70 and amp is 0.5 again as the previous defaults are restored."
},
"with_synth_defaults": {
"summary": "Block-level use new synth defaults",
"doc": "Specify new default values to be used by all calls to `play` within the `do`/`end` block. After the `do`/`end` block has completed the previous synth defaults (if any) are restored.",
"examples": "play 50 # plays note 50 with default arguments\n\nuse_synth_defaults amp: 0.5, pan: -1\n\nplay 50 # plays note 50 with an amp of 0.5, pan of -1 and defaults for rest of args\n\nwith_synth_defaults amp: 0.6, cutoff: 80 do\n\n play 50 # plays note 50 with an amp of 0.6, cutoff of 80 and defaults for rest of args (including pan)\n\nend\n\nplay 60 # plays note 60 with an amp of 0.5, pan of -1 and defaults for rest of args\n\n"
},
"with_fx": {
"summary": "Use Studio FX",
"doc": "This applies the named effect (FX) to everything within a given `do`/`end` block. Effects may take extra parameters to modify their behaviour. See FX help for parameter details.\nFor advanced control, it is also possible to modify the parameters of an effect within the body of the block. If you define the block with a single argument, the argument becomes a reference to the current effect and can be used to control its parameters (see examples).",
"examples": "# Basic usage\n\nwith_fx :distortion do # Use the distortion effect with default parameters\n\n play 50 # => plays note 50 with distortion\n\n sleep 1\n\n sample :loop_amen # => plays the loop_amen sample with distortion too\n\nend\",\n\n \"# Specify effect parameters\n\nwith_fx :level, amp: 0.3 do # Use the level effect with the amp parameter set to 0.3\n\n play 50\n\n sleep 1\n\n sample :loop_amen\n\nend\",\n\n \"\n\n# Controlling the effect parameters within the block\n\nwith_fx :reverb, mix: 0.1 do |fx|\n\n # here we set the reverb level quite low to start with (0.1)\n\n # and we can change it later by using the 'fx' reference we've set up\n\n play 60 # plays note 60 with a little bit of reverb\n\n sleep 2\n\n control fx, mix: 0.5 # change the parameters of the effect to add more reverb\n\n play 60 # again note 60 but with more reverb\n\n sleep 2\n\n control fx, mix: 1 # change the parameters of the effect to add more reverb\n\n play 60 # plays note 60 with loads of reverb\n\n sleep 2\n\nend\",\n\n \"\n\n# Repeat the block 16 times internally\n\nwith_fx :reverb, reps: 16 do\n\n play (scale :e3, :minor_pentatonic), release: 0.1\n\n sleep 0.125\n\nend\n\n# The above is a shorthand for this:\n\nwith_fx :reverb do\n\n 16.times do\n\n play (scale :e3, :minor_pentatonic), release: 0.1\n\n sleep 0.125\n\n end\n\nend\n\n"
},
"current_synth": {
"summary": "Get current synth",
"doc": "Returns the current synth name.\nThis can be set via the fns `use_synth` and `with_synth`.",
"examples": "puts current_synth # Print out the current synth name"
},
"current_synth_defaults": {
"summary": "Get current synth defaults",
"doc": "Returns the current synth defaults. This is a map of synth arg names to values.\nThis can be set via the fns `use_synth_defaults`, `with_synth_defaults`, `use_merged_synth_defaults` and `with_merged_synth_defaults`.",
"examples": "use_synth_defaults amp: 0.5, cutoff: 80\n\nplay 50 # Plays note 50 with amp 0.5 and cutoff 80\n\nputs current_synth_defaults #=> Prints {amp: 0.5, cutoff: 80}"
},
"current_sample_defaults": {
"summary": "Get current sample defaults",
"doc": "Returns the current sample defaults. This is a map of synth arg names to either values or functions.\nThis can be set via the fns `use_sample_defaults`, `with_sample_defaults`, `use_merged_sample_defaults` and `with_merged_sample_defaults`.",
"examples": "use_sample_defaults amp: 0.5, cutoff: 80\n\nsample :loop_amen # Plays amen break with amp 0.5 and cutoff 80\n\nputs current_sample_defaults #=> Prints {amp: 0.5, cutoff: 80}"
},
"current_volume": {
"summary": "Get current volume",
"doc": "Returns the current volume.\nThis can be set via the fn `set_volume!`.",
"examples": "puts current_volume # Print out the current volume\",\n\n \"set_volume! 2\n\nputs current_volume #=> 2"
},
"current_debug": {
"summary": "Get current debug status",
"doc": "Returns the current debug setting (`true` or `false`).\nThis can be set via the fns `use_debug` and `with_debug`.",
"examples": "puts current_debug # Print out the current debug setting"
},
"current_arg_checks": {
"summary": "Get current arg checking status",
"doc": "Returns the current arg checking setting (`true` or `false`).\nThis can be set via the fns `use_arg_checks` and `with_arg_checks`.",
"examples": "puts current_arg_checks # Print out the current arg check setting"
},
"set_volume": {
"summary": "Set Volume globally",
"doc": "Set the main system volume to `vol`. Accepts a value between `0` and `5` inclusive. Vols greater or smaller than the allowed values are trimmed to keep them within range. Default is `1`.",
"examples": "set_volume! 2 # Set the main system volume to 2\",\n\n \"set_volume! -1 # Out of range, so sets main system volume to 0\",\n\n \"set_volume! 7 # Out of range, so sets main system volume to 5"
},
"sample_loaded": {
"summary": "Test if sample was pre-loaded",
"doc": "Given a path to a `.wav`, `.wave`, `.aif`, `.aiff`, `.ogg`, `.oga` or `.flac` file, returns `true` if the sample has already been loaded.",
"examples": "load_sample :elec_blip # :elec_blip is now loaded and ready to play as a sample\n\nputs sample_loaded? :elec_blip # prints true because it has been pre-loaded\n\nputs sample_loaded? :misc_burp # prints false because it has not been loaded"
},
"load_sample": {
"summary": "Pre-load first matching sample",
"doc": "Given a path to a `.wav`, `.wave`, `.aif`, `.aiff`, `.ogg`, `.oga` or `.flac` file, pre-loads the sample into memory.\nYou may also specify the same set of source and filter pre-args available to `sample` itself. `load_sample` will then load all matching samples. See `sample`'s docs for more information.\" ",
"examples": "load_sample :elec_blip # :elec_blip is now loaded and ready to play as a sample\n\nsample :elec_blip # No delay takes place when attempting to trigger it\",\n\n\"# Using source and filter pre-args\n\ndir = \\\"/path/to/sample/dir\\\"\n\nload_sample dir # loads first matching sample in \\\"/path/to/sample/dir\\\"\n\nload_sample dir, 1 # loads sample with index 1 in \\\"/path/to/sample/dir\\\"\n\nload_sample dir, :foo # loads sample with name \\\"foo\\\" in \\\"/path/to/sample/dir\\\"\n\nload_sample dir, \\\"quux\\\" # loads first sample with file name containing \\\"quux\\\" in \\\"/path/to/sample/dir\\\"\n\nload_sample dir, /[Bb]ar/ # loads first sample which matches regex /[Bb]ar/ in \\\"/path/to/sample/dir\\\"\n\n"
},
"load_samples": {
"summary": "Pre-load all matching samples",
"doc": "Given a directory containing multiple `.wav`, `.wave`, `.aif`, `.aiff`, `.ogg`, `.oga` or `.flac` files, pre-loads all the samples into memory.\nYou may also specify the same set of source and filter pre-args available to `sample` itself. `load_sample` will load all matching samples (not just the sample `sample` would play given the same opts) - see `sample`'s docs for more information.\" ",
"examples": " load_sample :elec_blip # :elec_blip is now loaded and ready to play as a sample\n\n sample :elec_blip # No delay takes place when attempting to trigger it\",\n\n \"# Using source and filter pre-args\n\n dir = \\\"/path/to/sample/dir\\\"\n\n load_sample dir # loads all samples in \\\"/path/to/sample/dir\\\"\n\n load_sample dir, 1 # loads sample with index 1 in \\\"/path/to/sample/dir\\\"\n\n load_sample dir, :foo # loads sample with name \\\"foo\\\" in \\\"/path/to/sample/dir\\\"\n\n load_sample dir, \\\"quux\\\" # loads all samples with file names containing \\\"quux\\\" in \\\"/path/to/sample/dir\\\"\n\n load_sample dir, /[Bb]ar/ # loads all samples which match regex /[Bb]ar/ in \\\"/path/to/sample/dir\\\"\n\n "
},
"sample_info": {
"summary": "Get sample information",
"doc": "Alias for the `load_sample` method. Loads sample if necessary and returns sample information.",
"examples": "see load_sample"
},
"sample_buffer": {
"summary": "Get sample data",
"doc": "Alias for the `load_sample` method. Loads sample if necessary and returns buffer information.",
"examples": "see load_sample"
},
"sample_duration": {
"summary": "Get duration of sample in beats",
"doc": "Given the name of a loaded sample, or a path to a `.wav`, `.wave`, `.aif`, `.aiff`, `.ogg`, `.oga` or `.flac` file returns the length of time in beats that the sample would play for. `sample_duration` understands and accounts for all the opts you can pass to `sample` which have an effect on the playback duration such as `rate:`. The time returned is scaled to the current BPM.\n*Note:* avoid using `sample_duration` to set the sleep time in `live_loop`s, prefer stretching the sample with the `beat_stretch:` opt or changing the BPM instead. See the examples below for details.",
"examples": "# Simple use\n\nputs sample_duration(:loop_garzul) # returns 8.0 because this sample is 8 seconds long\n\n\",\n\n\"\n\n# The result is scaled to the current BPM\n\nuse_bpm 120\n\nputs sample_duration(:loop_garzul) # => 16.0\n\nuse_bpm 90\n\nputs sample_duration(:loop_garzul) # => 12.0\n\nuse_bpm 21\n\nputs sample_duration(:loop_garzul) # => 2.8\n\n\",\n\n\"\n\n# Avoid using sample_duration to set the sleep time in live_loops\n\nlive_loop :avoid_this do # It is possible to use sample_duration to drive the frequency of a live loop.\n\n with_fx :slicer do # However, if you're using a rhythmical sample such as a drum beat and it isn't\n\n sample :loop_amen # in the same BPM as the current BPM, then the FX such as this slicer will be\n\n sleep sample_duration(:loop_amen) # badly out of sync. This is because the slicer slices at the current BPM and\n\n end # this live_loop is looping at a different BPM (that of the sample)\n\nend\n\nlive_loop :prefer_this do # Instead prefer to set the BPM of the live_loop to match the sample. It has\n\n use_sample_bpm :loop_amen # two benefits. Now our sleep is a nice and simple 1 (as it's one beat).\n\n with_fx :slicer do # Also, our slicer now works with the beat and sounds much better.\n\n sample :loop_amen\n\n sleep 1\n\n end\n\nend\n\nlive_loop :or_this do # Alternatively we can beat_stretch the sample to match the current BPM. This has the\n\n with_fx :slicer do # side effect of changing the rate of the sample (and hence the pitch). However, the\n\n sample :loop_amen, beat_stretch: 1 # FX works nicely in time and the sleep time is also a simple 1.\n\n sleep 1\n\n end\n\nend\n\n\",\n\n\"\n\n# The standard sample opts are also honoured\n\n # Playing a sample at standard speed will return standard length\n\nsample_duration :loop_garzul, rate: 1 # => 8.0\n\n # Playing a sample at half speed will double duration\n\nsample_duration :loop_garzul, rate: 0.5 # => 16.0\n\n # Playing a sample at double speed will halve duration\n\nsample_duration :loop_garzul, rate: 2 # => 4.0\n\n # Playing a sample backwards at double speed will halve duration\n\nsample_duration :loop_garzul, rate: -2 # => 4.0\n\n # Without an explicit sustain: opt attack: just affects amplitude not duration\n\nsample_duration :loop_garzul, attack: 1 # => 8.0\n\nsample_duration :loop_garzul, attack: 100 # => 8.0\n\nsample_duration :loop_garzul, attack: 0 # => 8.0\n\n # Without an explicit sustain: opt release: just affects amplitude not duration\n\nsample_duration :loop_garzul, release: 1 # => 8.0\n\nsample_duration :loop_garzul, release: 100 # => 8.0\n\nsample_duration :loop_garzul, release: 0 # => 8.0\n\n # Without an explicit sustain: opt decay: just affects amplitude not duration\n\nsample_duration :loop_garzul, decay: 1 # => 8.0\n\nsample_duration :loop_garzul, decay: 100 # => 8.0\n\nsample_duration :loop_garzul, decay: 0 # => 8.0\n\n # With an explicit sustain: opt, if the attack + decay + sustain + release envelope\n\n # duration is less than the sample duration time, the envelope will shorten the\n\n # sample time.\n\nsample_duration :loop_garzul, sustain: 0, attack: 0.5 # => 0.5\n\nsample_duration :loop_garzul, sustain: 0, decay: 0.1 # => 0.1\n\nsample_duration :loop_garzul, sustain: 0, release: 1 # => 1.0\n\nsample_duration :loop_garzul, sustain: 2, attack: 0.5, release: 1 # => 3.5\n\n # If the envelope duration is longer than the sample it will not affect the\n\n # sample duration\n\nsample_duration :loop_garzul, sustain: 0, attack: 8, release: 3 # => 8\n\n # All other opts are taken into account before the comparison with the envelope opts.\n\nsample_duration :loop_garzul, rate: 10 # => 0.8\n\nsample_duration :loop_garzul, sustain: 0, attack: 0.9, rate: 10 # => 0.8 (The duration of the sample is less than the envelope length so wins)\n\n # The rpitch: opt will modify the rate to shift the pitch of the sample up and down\n\n # and therefore affects duration.\n\nsample_duration :loop_garzul, rpitch: 12 # => 4.0\n\nsample_duration :loop_garzul, rpitch: -12 # => 16\n\n # The rpitch: and rate: opts combine together.\n\nsample_duration :loop_garzul, rpitch: 12, rate: 2 # => 2.0\n\n # The beat_stretch: opt stretches the sample so that its duration matches the value.\n\n # It also combines with rate:\n\nsample_duration :loop_garzul, beat_stretch: 3 # => 3.0\n\nsample_duration :loop_garzul, beat_stretch: 3, rate: 0.5 # => 6.0\n\n # The pitch_stretch: opt acts identically to beat_stretch when just considering sample\n\n # duration.\n\nsample_duration :loop_garzul, pitch_stretch: 3 # => 3.0\n\nsample_duration :loop_garzul, pitch_stretch: 3, rate: 0.5 # => 6.0\n\n # The start: and finish: opts can also shorten the sample duration and also combine\n\n # with other opts such as rate:\n\nsample_duration :loop_garzul, start: 0.5 # => 4.0\n\nsample_duration :loop_garzul, start: 0.5, finish: 0.75 # => 2.0\n\nsample_duration :loop_garzul, finish: 0.5, start: 0.75 # => 2.0\n\nsample_duration :loop_garzul, rate: 2, finish: 0.5, start: 0.75 # => 1.0\n\n\",\n\n\"\n\n# Triggering samples one after another\n\nsample :loop_amen # start the :loop_amen sample\n\nsleep sample_duration(:loop_amen) # wait for the duration of :loop_amen before\n\nsample :loop_amen # starting it again\n\n"
},
"sample_paths": {
"summary": "Sample Pack Filter Resolution",
"doc": "Accepts the same pre-args and opts as `sample` and returns a ring of matched sample paths.",
"examples": "sample_paths \\\"/path/to/samples/\\\" #=> ring of all top-level samples in /path/to/samples\",\n\n\"\n\nsample_paths \\\"/path/to/samples/**\\\" #=> ring of all nested samples in /path/to/samples\",\n\n\"\n\nsample_paths \\\"/path/to/samples/\\\", \\\"foo\\\" #=> ring of all samples in /path/to/samples\n\n containing the string \\\"foo\\\" in their filename."
},
"sample": {
"summary": "Trigger sample",
"doc": "Play back a recorded sound file (sample). Sonic Pi comes with lots of great samples included (see the section under help) but you can also load and play `.wav`, `.wave`, `.aif`, `.aiff`, `.ogg`, `.oga` or `.flac` files from anywhere on your computer too. To play a built-in sample use the corresponding keyword such as `sample :bd_haus`. To play any file on your computer use a full path such as `sample \\\"/path/to/sample.wav\\\"`.\nThere are many opts for manipulating the playback. For example, the `rate:` opt affects both the speed and the pitch of the playback. To control the rate of the sample in a pitch-meaningful way take a look at the `rpitch:` opt.\nThe sampler synth has three separate envelopes - one for amplitude, one for a low pass filter and another for a high pass filter. These work very similar to the standard synth envelopes except for two major differences. Firstly, the envelope times do not stretch or shrink to match the BPM. Secondly, the sustain time by default stretches to make the envelope fit the length of the sample. This is explained in detail in the tutorial.\nSamples are loaded on-the-fly when first requested (and subsequently remembered). If the sample loading process takes longer than the schedule ahead time, the sample trigger will be skipped rather than be played late and out of time. To avoid this you may preload any samples you wish to work with using `load_sample` or `load_samples`.\nIt is possible to set the `start:` and `finish:` positions within the sample to play only a sub-section of it. These values can be automatically chosen based on an onset detection algorithm which will essentially isolate each individual drum or synth hit in the sample and let you access each one by an integer index (floats will be rounded to the nearest integer value). See the `onset:` docstring and examples for more information.\nFinally, the sampler supports a powerful filtering system to make it easier to work with large folders of samples. The filter commands must be used before the first standard opt. There are six kinds of filter parameters you may use:\n1. Folder strings - `\\\"/foo/bar\\\"` - which will add all samples within the folder to the set of candidates.\n2. Recursive folder strings - `\\\"/foo/bar/**\\\"` - Folder strings ending with `**` will add all samples contained within all subfolders (searched recursively).\n3. Sample strings - `\\\"/path/to/sample.wav\\\"` - which will add the specific sample to the set of candidates.\n4. Other strings - `\\\"foobar\\\"` - which will filter the candidates based on whether the filename contains the string.\n5. Regular expressions - `/b[aA]z.*/` - which will filter the candidates based on whether the regular expression matches the filename.\n6. Keywords - `:quux` - will filter the candidates based on whether the keyword is a direct match of the filename (without extension).\n7. Numbers - `0` - will select the candidate with that index (wrapping round like a ring if necessary).\n8. Lists of the above - `[\\\"/foo/bar\\\", \\\"baz\\\", /0-9.*/]` - will recurse down and work through the internal filter parameters as if they were in the top level.\n9. Lambdas - `lambda {|s| [s.choose] }` - the ultimate power tool for filters. Allows you to create a custom fn which receives a list of candidates as an arg and which should return a new list of candidates (this may be smaller, larger, re-ordered it's up to you).\nBy combining commands which add to the candidates and then filtering those candidates it is possible to work with folders full of samples in very powerful ways. Note that the specific ordering of filter parameters is irrelevant with the exception of the numbers - in which case the last number is the index. All the candidates will be gathered first before the filters are applied.\n",
"examples": "# Play a built-in sample\n\nsample :loop_amen # Plays the Amen break\",\n\n \"\n\n# Play two samples at the same time\n\n# with incredible timing accuracy\n\nsample :loop_amen\n\nsample :ambi_lunar_land # Note, for timing guarantees select the pref:\n\n # Studio -> Synths and FX -> Enforce timing guarantees\",\n\n \"\n\n# Create a simple repeating bass drum\n\nlive_loop :bass do\n\n sample :bd_haus\n\n sleep 0.5\n\nend\",\n\n \"\n\n# Create a more complex rhythm with multiple live loops:\n\nlive_loop :rhythm do\n\n sample :tabla_ghe3 if (spread 5, 7).tick\n\n sleep 0.125\n\nend\n\nlive_loop :bd, sync: :rhythm do\n\n sample :bd_haus, lpf: 90, amp: 2\n\n sleep 0.5\n\nend\",\n\n \"\n\n# Change the playback speed of the sample using rate:\n\nsample :loop_amen, rate: 0.5 # Play the Amen break at half speed\n\n # for old school hip-hop\",\n\n \"\n\n# Speed things up\n\nsample :loop_amen, rate: 1.5 # Play the Amen break at 1.5x speed\n\n # for a jungle/gabba sound\",\n\n \"\n\n# Go backwards\n\nsample :loop_amen, rate: -1 # Negative rates play the sample backwards\",\n\n \"\n\n# Fast rewind\n\nsample :loop_amen, rate: -3 # Play backwards at 3x speed for a fast rewind effect\",\n\n \"\n\n# Start mid sample\n\nsample :loop_amen, start: 0.5 # Start playback half way through\",\n\n \"\n\n# Finish mid sample\n\nsample :loop_amen, finish: 0.5 # Finish playback half way through\",\n\n \"\n\n# Play part of a sample\n\nsample :loop_amen, start: 0.125, finish: 0.25 # Play the second eighth of the sample\",\n\n \"\n\n# Finishing before the start plays backwards\n\nsample :loop_amen, start: 0.25, finish: 0.125 # Play the second eighth of the sample backwards\",\n\n \"\n\n# Play a section of a sample at quarter speed backwards\n\nsample :loop_amen, start: 0.125, finish: 0.25, rate: -0.25 # Play the second eighth of the\n\n # amen break backwards at a\n\n # quarter speed\",\n\n \"\n\n# Control a sample synchronously\n\ns = sample :loop_amen, lpf: 70\n\nsleep 0.5\n\ncontrol s, lpf: 130\n\nsleep 0.5\n\nsynth :dsaw, note: :e3 # This is triggered 1s from start\",\n\n\" # Controlling a sample asynchronously\n\nsample :loop_amen, lpf: 70 do |s|\n\n sleep 1 # This block is run in an implicit in_thread\n\n control s, lpf: 130 # and therefore is asynchronous\n\nend\n\nsleep 0.5\n\nsynth :dsaw, note: :e3 # This is triggered 0.5s from start\",\n\n \"\n\n# Play with slices\n\nsample :loop_garzul, slice: 0 # => play the first 16th of the sample\n\nsleep 0.5\n\n4.times do\n\n sample :loop_garzul, slice: 1 # => play the second 16th of the sample 4 times\n\n sleep 0.125\n\nend\n\nsample :loop_garzul, slice: 4, num_slices: 4, rate: -1 # => play the final quarter backwards\n\n\",\n\n \"\n\n# Build a simple beat slicer\n\nuse_sample_bpm :loop_amen # Set the BPM to match the amen break sample\n\nlive_loop :beat_slicer do\n\n n = 8 # Specify number of slices\n\n # (try changing to 2, 4, 6, 16 or 32)\n\n s = rand_i n # Choose a random slice within range\n\n sample :loop_amen, slice: s, num_slices: n # Play the specific part of the sample\n\n sleep 1.0/n # Sleep for the duration of the slice\n\nend\",\n\n \"\n\n# Play with the built-in low pass filter, high pass filter and compressor\n\nsample :loop_amen, lpf: 80, hpf: 70, compress: 1, pre_amp: 10 # Make the amen break sound punchy.\",\n\n \"\n\n# Use the cutoff filter envelopes\n\nsample :loop_garzul, lpf_attack: 8 # Sweep the low pass filter up over 8 beats\n\nsleep 8\n\nsample :loop_garzul, hpf_attack: 8 # Sweep the high pass filter down over 8 beats\",\n\n \"\n\n# Sample stretching\n\nputs sample_duration :loop_industrial # => 0.88347\n\nputs sample_duration :loop_industrial, beat_stretch: 1 # => 1\n\nlive_loop :industrial do\n\n sample :loop_industrial, beat_stretch: 1 # Stretch the sample to make it 1 beat long\n\n sleep 1 # This now loops perfectly.\n\n # However, note that stretching/shrinking\n\n # also modifies the pitch.\n\nend\",\n\n \"\n\n# Sample shrinking\n\nputs sample_duration :loop_garzul # => 8\n\nputs sample_duration :loop_garzul, beat_stretch: 6 # => 6\n\nlive_loop :garzul do\n\n sample :loop_garzul, beat_stretch: 6 # As :loop_garzul is longer than 6 beats\n\n # it is shrunk to fit. This increases the\n\n # pitch.\n\n sleep 6\n\nend\",\n\n \"\n\n# Sample stretching matches the BPM\n\nuse_bpm 30 # Set the BPM to 30\n\nputs sample_duration :loop_garzul # => 4.0 (at 30 BPM the sample lasts for 4 beats)\n\nputs sample_duration :loop_garzul, beat_stretch: 6 # => 6.0\n\nlive_loop :garzul do\n\n sample :loop_garzul, beat_stretch: 6 # The sample is stretched to match 6 beats at 30 BPM\n\n sleep 6\n\nend\",\n\n \"\n\n# External samples\n\nsample \\\"/path/to/sample.wav\\\" # Play any Wav, Aif, Ogg, Oga, or FLAC sample on your computer\n\n # by simply passing a string representing the full\n\n # path\",\n\n \"\n\n# Sample pack filtering\n\ndir = \\\"/path/to/dir/of/samples\\\" # You can easily work with a directory of samples\n\nsample dir # Play the first sample in the directory\n\n # (it is sorted alphabetically)\n\nsample dir, 1 # Play the second sample in the directory\n\nsample dir, 99 # Play the 100th sample in the directory, or if there\n\n # are fewer, treat the directory like a ring and keep\n\n # wrapping the index round until a sample is found.\n\n # For example, if there are 90 samples, the 10th sample\n\n # is played (index 9).\n\nsample dir, \\\"120\\\" # Play the first sample in the directory that contains\n\n # the substring \\\"120\\\".\n\n # For example, this may be \\\"beat1_120_rave.wav\\\"\n\nsample dir, \\\"120\\\", 1 # Play the second sample in the directory that contains\n\n # the substring \\\"120\\\".\n\n # For example, this may be \\\"beat2_120_rave.wav\\\"\n\nsample dir, /beat[0-9]/ # Play the first sample in the directory that matches\n\n # the regular expression /beat[0-9]/.\n\n # For example, this may be \\\"beat0_100_trance.wav\\\"\n\n # You may use the full power of Ruby's regular expression\n\n # system here: http://ruby-doc.org/core-2.1.1/Regexp.html\n\nsample dir, /beat[0-9]0/, \\\"100\\\" # Play the first sample in the directory that both matches\n\n # the regular expression /beat[0-9]0/ and contains the\n\n # the substring \\\"100\\\".\n\n # For example, this may be \\\"beat10_100_rave.wav\\\"\",\n\n \"\n\n# Filtering built-in samples\n\n # If you don't pass a directory source, you can filter over\n\n # the built-in samples.\n\nsample \\\"tabla_\\\" # Play the first built-in sample that contains the substring\n\n # \\\"tabla\\\"\n\nsample \\\"tabla_\\\", 2 # Play the third built-in sample that contains the substring\n\n # \\\"tabla\\\"\",\n\n \"\n\n# Play with whole directories of samples\n\nload_samples \\\"tabla_\\\" # You may pass any of the source/filter options to load_samples\n\n # to load all matching samples. This will load all the built-in\n\n # samples containing the substring \\\"tabla_\\\"\n\nlive_loop :tabla do\n\n sample \\\"tabla_\\\", tick # Treat the matching samples as a ring and tick through them\n\n sleep 0.125\n\nend\",\n\n \"\n\n# Specify multiple sources\n\ndir1 = \\\"/path/to/sample/directory\\\"\n\ndir2 = \\\"/path/to/other/sample/directory\\\"\n\nsample dir1, dir2, \\\"foo\\\" # Match the first sample that contains the string \\\"foo\\\" out of\n\n # all the samples in dir1 and dir2 combined.\n\n # Note that the sources must be listed before any filters.\",\n\n \"\n\n# List contents recursively\n\ndir = \\\"/path/to/sample/directory\\\" # By default the list of all top-level samples within the directory\n\n # is considered.\n\ndir_recursive = \\\"/path/to/sample/directory/**\\\" # However, if you finish your directory string with ** then if that\n\n # directory contains other directories then the samples within the\n\n # subdirectories and their subsubdirectories in turn are considered.\n\nsample dir, 0 # Play the first top-level sample in the directory\n\nsample dir_recursive, 0 # Play the first sample found after combining all samples found in\n\n # the directory and all directories within it recursively.\n\n # Note that if there are many sub directories this may take some time\n\n # to execute. However, the result is cached so subsequent calls will\n\n # be fast.\",\n\n \"\n\n# Bespoke filters\n\nfilter = lambda do |candidates| # If the built-in String, Regexp and index filters are not sufficient\n\n [candidates.choose] # you may write your own. They need to be a function which takes a list\n\nend # of paths to samples and return a list of samples. This one returns a\n\n # list of a single randomly selected sample.\n\n8.times do\n\n sample \\\"drum_\\\", filter # Play 8 randomly selected samples from the built-in sample set that also\n\n sleep 0.25 # contain the substring \\\"drum_\\\"\n\nend\",\n\n \"\n\n# Basic Onset Detection\n\nsample :loop_tabla, start: 0, finish: 0.00763 # If you know the right start: and finish: values, you can extract a\n\n # single drum hit from a longer sample. However, finding these values\n\n # can be very time consuming.\n\nsleep 1\n\n # Instead of specifying the start: and finish: values manually you can\n\n # use the onset: option to find them for you using an integer index.\n\nsample :loop_tabla, onset: 0 # onset: 0 will set the start: and finish: values so that the first\n\n # percussive sound (something that shifts from quiet to loud quickly)\n\n # is picked out.\n\nsleep 1\n\nsample :loop_tabla, onset: 1 # We can easily find the second percussive sound in the sample with\n\n # onset: 1\",\n\n \"\n\n# Ticking through onsets\n\n # The onsets are actually a ring so the index will wrap around. This\n\n # means that if there are only 8 onsets in a sample, specifying an\n\n # onset of 100 will still return one of the 8 onsets. This means we\n\n # can use tick to work through each onset in sequence. This allows us\n\n # to redefine the rhythm and tempo of a sample\n\nlive_loop :tabla do\n\n use_bpm 50 # We can choose our own BPM here - it doesn't need to match the sample\n\n sample :loop_tabla, onset: tick # tick through each onset in sequence\n\n sleep [0.125, 0.25].choose # randomly choose a delay between onset triggers\n\nend\n\n\",\n\n \"\n\n# Random Onset Triggering\n\n # We can easily pick a random onset using the pick fn\n\nuse_bpm 50\n\nlive_loop :tabla do\n\n sample :loop_tabla, onset: pick # Each time round the live loop we now trigger a random onset\n\n sleep [0.125, 0.25].choose # creating an infinite stream of randomly selected drums\n\nend\n\n \",\n\n \"\n\n# Repeatable Random Onsets\n\n # Instead of an infinite stream of choices, we can combine iteration\n\n # and use_random_seed to create repeatable riffs:\n\nlive_loop :tabla do\n\n use_random_seed 30000 # every 8 times, reset the random seed, this resets the riff\n\n 8.times do\n\n sample :loop_tabla, onset: pick\n\n sleep [0.125, 0.25].choose\n\n end\n\nend\n\n\",\n\n \"\n\n# Random Onset Duration\n\n # Each onset has a variable length (determined by the sample contents).\n\n # Therefore, if you wish to ensure each onset has a specific length it\n\n # is necessary to use the sample's amplitude envelope.\n\n # As the sample's envelope automatically changes the sustain: value to\n\n # match the duration - you also need to override this with a value of 0.\n\nlive_loop :tabla do\n\n sample :loop_tabla, onset: pick, sustain: 0, release: 0.1 # Each drum onset will now be no longer than 0.1. Note that the envelope\n\n # for a sample only determines the maximum duration of a sample trigger.\n\n # If the actual audible duration of the onset is smaller than 0.1 then\n\n # it will *not* be extended.\n\n sleep [0.125, 0.25].choose\n\nend\n\n\",\n\n \"\n\n# Onset lambdas\n\n # The onset index can be a lambda as well as an integer. If a lambda is\n\n # given, it will be passed a ring of all of the onsets as an argument.\n\n # This will be a ring of maps:\n\nl = lambda {|c| puts c ; c[0]} # define a lambda which accepts a single argument, prints it and\n\n # returns the first value. This particular example is essentially\n\n # the same as using onset: 0 with the side effect of also printing out\n\n # the full ring of onsets:\n\nsample :loop_tabla, onset: l # (ring {:start=>0.0, :finish=>0.0076}, {:start=>0.0076, :finish 0.015}...)\n\n # We are therefore free to define this lambda to do anything we want.\n\n # This gives us very powerful control over the choice of onset. It is\n\n # unlikely you will use this frequently, but it is a powerful tool\n\n # that's there when you need it.\n\n\",\n\n \"\n\nsample :loop_tabla, onset: 1 # Plays the 2nd onset (the first onset would have index 0)\n\n # Will override opts with: {start: 0.0151, finish: 0.0304}\n\n # (these values are specific to the :loop_tabla sample and\n\n # will vary for different samples)\n\n\",\n\n \"\n\nsample :loop_tabla, onset: 1, slice: 0, num_slices: 1 # Plays the 2nd onset. This behaves the same as not specifying\n\n # a slice as we select the first of one slices.\n\n # Will override opts with: {start: 0.0151, finish: 0.0304}\n\n # (these values are specific to the :loop_tabla sample and\n\n # will vary for different samples)\n\n\",\n\n \"\n\nsample :loop_tabla, onset: 1, slice: 0, num_slices: 2 # This plays the first half of the 2nd onset.\n\n # This is because we split that onset into two slices and\n\n # play just the first slice (with index 0).\n\n # Will override opts with: {start: 0.0151, finish: 0.0227}\n\n # (these values are specific to the :loop_tabla sample and\n\n # will vary for different samples)\n\n\",\n\n \"\n\nsample :loop_tabla, onset: 1, slice: 0, num_slices: 4 # This plays the first quarter of the 2nd onset.\n\n # This is because we split that onset into four slices and\n\n # play just the first slice (with index 0).\n\n # Will override opts with: {start: 0.0151, finish: 0.0189}\n\n # (these values are specific to the :loop_tabla sample and\n\n # will vary for different samples)\n\nsample :loop_tabla, onset: 1, slice: 0, num_slices: 4, finish: 0.5 # Will play the first 1/8th of the 2nd onset.\n\n # This is because we split that specific onset into 4 slices\n\n # and then only play the first half of the first slice.\n\n # Will override opts with: {start: 0.0151, finish: 0.017}\n\n # (these values are specific to the :loop_tabla sample and\n\n # will vary for different samples)\n\nsample :loop_tabla, onset: 1, slice: 0, num_slices: 4, finish: 0.0, start: 0.5 # Will play the first 1/8th of the 2nd onset backwards..\n\n # This is because we split that specific onset into 4 slices\n\n # and then only play from the first half of the first slice\n\n # back to the beginning.\n\n # Will override opts with: {start: 0.017, finish: 0.0151}\n\n # (these values are specific to the :loop_tabla sample and\n\n # will vary for different samples)\n\n"
},
"status": {
"summary": "Get server status",
"doc": "This returns a Hash of information about the synthesis environment. Mostly used for debugging purposes.",
"examples": "puts status # Returns something similar to:\n\n # {\n\n # :ugens=>10,\n\n # :synths=>1,\n\n # :groups=>7,\n\n # :sdefs=>61,\n\n # :avg_cpu=>0.20156468451023102,\n\n # :peak_cpu=>0.36655542254447937,\n\n # :nom_samp_rate=>44100.0,\n\n # :act_samp_rate=>44099.9998411752,\n\n # :audio_busses=>2,\n\n # :control_busses=>0\n\n # }\n\n"
},
"control": {
"summary": "Control running synth",
"doc": "Control a running synth node by passing new parameters to it. A synth node represents a running synth and can be obtained by assigning the return value of a call to play or sample or by specifying a parameter to the do/end block of an FX. You may modify any of the parameters you can set when triggering the synth, sample or FX. See documentation for opt details. If the synth to control is a chord, then control will change all the notes of that chord group at once to a new target set of notes - see example. Also, you may use the on: opt to conditionally trigger the control - see the docs for the `synth` and `sample` fns for more information.\nIf no synth to control is specified, then the last synth triggered by the current (or parent) thread will be controlled - see example below.",
"examples": "## Basic control\n\nmy_node = play 50, release: 5, cutoff: 60 # play note 50 with release of 5 and cutoff of 60. Assign return value to variable my_node\n\nsleep 1 # Sleep for a second\n\ncontrol my_node, cutoff: 70 # Now modify cutoff from 60 to 70, sound is still playing\n\nsleep 1 # Sleep for another second\n\ncontrol my_node, cutoff: 90 # Now modify cutoff from 70 to 90, sound is still playing\",\n\n \"\n\n## Combining control with slide opts allows you to create nice transitions.\n\ns = synth :prophet, note: :e1, cutoff: 70, cutoff_slide: 8, release: 8 # start synth and specify slide time for cutoff opt\n\ncontrol s, cutoff: 130 # Change the cutoff value with a control.\n\n # Cutoff will now slide over 8 beats from 70 to 130\",\n\n \"\n\n## Use a short slide time and many controls to create a sliding melody\n\nnotes = (scale :e3, :minor_pentatonic, num_octaves: 2).shuffle # get a random ordering of a scale\n\ns = synth :beep, note: :e3, sustain: 8, note_slide: 0.05 # Start our synth running with a long sustain and short note slide time\n\n64.times do\n\n control s, note: notes.tick # Keep quickly changing the note by ticking through notes repeatedly\n\n sleep 0.125\n\nend\n\n\",\n\n \"\n\n## Controlling FX\n\nwith_fx :bitcrusher, sample_rate: 1000, sample_rate_slide: 8 do |bc| # Start FX but also use the handy || goalposts\n\n # to grab a handle on the running FX. We can call\n\n # our handle anything we want. Here we've called it bc\n\n sample :loop_garzul, rate: 1\n\n control bc, sample_rate: 5000 # We can use our handle bc now just like we used s in the\n\n # previous example to modify the FX as it runs.\n\nend\",\n\n \"\n\n## Controlling chords\n\ncg = play (chord :e4, :minor), sustain: 2 # start a chord\n\nsleep 1\n\ncontrol cg, notes: (chord :c3, :major) # transition to new chord.\n\n # Each note in the original chord is mapped onto\n\n # the equivalent in the new chord.\n\n\",\n\n \"\n\n## Sliding between chords\n\ncg = play (chord :e4, :minor), sustain: 4, note_slide: 3 # start a chord\n\nsleep 1\n\ncontrol cg, notes: (chord :c3, :major) # slide to new chord.\n\n # Each note in the original chord is mapped onto\n\n # the equivalent in the new chord.\n\n\",\n\n \"\n\n## Sliding from a larger to smaller chord\n\ncg = play (chord :e3, :m13), sustain: 4, note_slide: 3 # start a chord with 7 notes\n\nsleep 1\n\ncontrol cg, notes: (chord :c3, :major) # slide to new chord with fewer notes (3)\n\n # Each note in the original chord is mapped onto\n\n # the equivalent in the new chord using ring-like indexing.\n\n # This means that the 4th note in the original chord will\n\n # be mapped onto the 1st note in the second chord and so-on.\n\n\",\n\n \"\n\n## Sliding from a smaller to larger chord\n\ncg = play (chord :c3, :major), sustain: 4, note_slide: 3 # start a chord with 3 notes\n\nsleep 1\n\ncontrol cg, notes: (chord :e3, :m13) # slide to new chord with more notes (7)\n\n # Each note in the original chord is mapped onto\n\n # the equivalent in the new chord.\n\n # This means that the 4th note in the new chord\n\n # will not sound as there is no 4th note in the\n\n # original chord.\n\n\",\n\n \"\n\n## Changing the slide rate\n\ns = synth :prophet, note: :e1, release: 8, cutoff: 70, cutoff_slide: 8 # Start a synth playing with a long cutoff slide\n\nsleep 1 # wait a beat\n\ncontrol s, cutoff: 130 # change the cutoff so it starts sliding slowly\n\nsleep 3 # wait for 3 beats\n\ncontrol s, cutoff_slide: 1 # Change the cutoff_slide - the cutoff now slides more quickly to 130\n\n # it will now take 1 beat to slide from its *current* value\n\n # (somewhere between 70 and 130) to 130\n\n\",\n\n \"\n\n## Controlling the last triggered synth\n\nsynth :prophet, note: :e1, release: 8 # Every time a synth is triggered, Sonic Pi automatically remembers the node\n\nsleep 1\n\n16.times do\n\n control note: (octs :e1, 3).tick # This means we don't need to use an explicit variable to control the synth\n\n sleep 0.125 # we last triggered.\n\nend\",\n\n \"\n\n## Controlling multiple synths without variables\n\nsynth :beep, release: 4 # Trigger a beep synth\n\nsleep 0.1\n\ncontrol note: :e5 # Control last triggered synth (:beep)\n\nsleep 0.5\n\nsynth :dsaw, release: 4 # Next, trigger a dsaw synth\n\nsleep 0.1\n\ncontrol note: :e4 # Control last triggered synth (:dsaw)\n\n"
},
"kill": {
"summary": "Kill synth",
"doc": "Kill a running synth sound or sample. In order to kill a sound, you need to have stored a reference to it in a variable.",
"examples": "# store a reference to a running synth in a variable called foo:\n\nfoo = play 50, release: 4\n\nsleep 1\n\n# foo is still playing, but we can kill it early:\n\nkill foo\n\n\",\n\n \"bar = sample :loop_amen\n\nsleep 0.5\n\nkill bar"
},
"sample_names": {
"summary": "Get sample names",
"doc": "Return a ring of sample names for the specified group"
},
"all_sample_names": {
"summary": "Get all sample names",
"doc": "Return a list of all the sample names available"
},
"sample_groups": {
"summary": "Get all sample groups",
"doc": "Return a list of all the sample groups available"
},
"synth_names": {
"summary": "Get all synth names",
"doc": "Return a list of all the synths available"
},
"fx_names": {
"summary": "Get all FX names",
"doc": "Return a list of all the FX available"
},
"load_synthdefs": {
"summary": "Load external synthdefs",
"doc": "Load all pre-compiled synth designs in the specified directory. The binary files containing synth designs need to have the extension `.scsyndef`. This is useful if you wish to use your own SuperCollider synthesiser designs within Sonic Pi.\nYou may not trigger external synthdefs unless you enable the following GUI preference:\n```\nStudio -> Synths and FX -> Enable external synths and FX\n```\nAlso, if you wish your synth to work with Sonic Pi's automatic stereo sound infrastructure *you need to ensure your synth outputs a stereo signal* to an audio bus with an index specified by a synth arg named `out_bus`. For example, the following synth would work nicely:\n(\nSynthDef(\\\\piTest\n{|freq = 200, amp = 1, out_bus = 0 |\nOut.ar(out_bus\nSinOsc.ar([freq,freq],0,0.5)* Line.kr(1, 0, 5, amp, doneAction: 2))}\n).writeDefFile(\\\"/Users/sam/Desktop/\\\")\n)\n",
"examples": "load_synthdefs \\\"~/Desktop/my_noises\\\" # Load all synthdefs in my_noises folder"
}
}
opts_doc = {
"your_key": "Your value",
"another_key": "Another value",
"key": "All these opts are passed through to the thread which syncs",
"shift": "How much time to delay/forward the block. Greater values produce more emphasised swing. Defaults to 0.1 beats.",
"pulse": "How often to apply the swing. Defaults to 4.",
"tick": "A key for the tick with which to count pulses. Override this if you have more than one `with_swing` block in your `live_loop` or thread to stop them interfering with each other.",
"offset": "Offset to add to index returned. Useful when calling look on lists, rings and vectors to offset the returned value",
"step": "Step size of value to quantise to.",
"rotate": "rotate to the next strong beat allowing for easy permutations of the original rhythmic grouping (see example)",
"inclusive": "boolean value representing whether or not to include finish value in line",
"steps": "number of slices or segments along the line",
"skip": "Number of rands to skip over with each successive pick",
"init": "initial value for optional block arg",
"auto_cue": "enable or disable automatic cue (default is true)",
"delay": "Initial delay in beats before the thread starts. Default is 0.",
"sync": "Initial sync symbol. Will sync with this symbol before the thread starts.",
"sync_bpm": "Initial sync symbol. Will sync with this symbol before the live_loop starts. Live loop will also inherit the BPM of the thread which cued the symbol.",
"seed": "override initial random generator seed before starting loop.",
"override": "If set to true, re-definitions are allowed and this acts like define",
"bpm_sync": "Inherit the BPM of the cueing thread. Default is false",
"name": "Make this thread a named thread with name. If a thread with this name already exists, a new thread will not be created.",
"amp": "Amplitude of playback.",
"amp_slide": "The duration in beats for amplitude changes to take place",
"pan": "Stereo position of audio. -1 is left ear only, 1 is right ear only, and values in between position the sound accordingly. Default is 0.",
"pan_slide": "The duration in beats for the pan value to change",
"attack": "Time to reach full volume. Default is 0.",
"decay": "Duration of the decay phase of the envelope.",
"sustain": "Time to stay at full volume. Default is to stretch to length of sample (minus attack and release times).",
"release": "Time (from the end of the sample) to go from full amplitude to 0. Default is 0.",
"attack_level": "Amplitude level reached after attack phase and immediately before decay phase",
"decay_level": "Amplitude level reached after decay phase and immediately before sustain phase. Defaults to sustain_level unless explicitly set",
"sustain_level": "Amplitude level reached after decay phase and immediately before release phase.",
"env_curve": "Select the shape of the curve between levels in the envelope. 1=linear, 2=exponential, 3=sine, 4=welch, 6=squared, 7=cubed",
"slide": "Default slide time in beats for all slide opts. Individually specified slide opts will override this value.",
"pitch": "Pitch adjustment in semitones. 1 is up a semitone, 12 is up an octave, -12 is down an octave etc. Maximum upper limit of 24 (up 2 octaves). Lower limit of -72 (down 6 octaves). Decimal numbers can be used for fine tuning.",
"on": "If specified and false/nil/0 will stop the sample from being played. Ensures all opts are evaluated.",
"num_beats": "The number of beats within the sample. By default this is 1.",
"pre_amp": "Amplitude multiplier which takes place immediately before any internal FX such as the low pass filter, compressor or pitch modification. Use this opt if you want to overload the compressor.",
"hpf": "Cutoff value of the built-in high pass filter (hpf) in MIDI notes. Unless specified, the hpf is *not* added to the signal chain.",
"lpf": "Cutoff value of the built-in low pass filter (lpf) in MIDI notes. Unless specified, the lpf is *not* added to the signal chain.",
"hpf_bypass": "Bypass the global hpf. 0=no bypass, 1=bypass. Default 0.",
"lpf_bypass": "Bypass the global lpf. 0=no bypass, 1=bypass. Default 0.",
"limiter_bypass": "Bypass the final limiter. 0=no bypass, 1=bypass. Default 0.",
"leak_dc_bypass": "Bypass the final DC leak correction FX. 0=no bypass, 1=bypass. Default 0.",
"reps": "Number of times to repeat the block in an iteration.",
"kill_delay": "Amount of time to wait after all synths triggered by the block have completed before stopping and freeing the effect synthesiser.",
"rate": "Rate with which to play back the sample. Higher rates mean an increase in pitch and a decrease in duration. Default is 1.",
"start": "Position in sample as a fraction between 0 and 1 to start playback. Default is 0.",
"finish": "Position in sample as a fraction between 0 and 1 to end playback. Default is 1.",
"beat_stretch": "Stretch (or shrink) the sample to last for exactly the specified number of beats. Please note - this does *not* keep the pitch constant and is essentially the same as modifying the rate directly.",
"pitch_stretch": "Stretch (or shrink) the sample to last for exactly the specified number of beats. This attempts to keep the pitch constant using the `pitch:` opt. Note, it's very likely you'll need to experiment with the `window_size:`, `pitch_dis:` and `time_dis:` opts depending on the sample and the amount you'd like to stretch/shrink from original size.",
"rpitch": "Rate modified pitch. Multiplies the rate by the appropriate ratio to shift up or down the specified amount in MIDI notes. Please note - this does *not* keep the duration and rhythmical rate constant and is essentially the same as modifying the rate directly.",
"onset": "Analyse the sample with an onset detection algorithm and automatically set or override the `start:` and `finish:` opts to play the nth onset only. Allows you to treat a rhythm sample as a palette of individual drum/synth hits. If `start:` or `finish:` opts are used in addition to `onset:` then they will work within the onset rather than the whole sample. Floats are rounded to the nearest whole number.",
"slice": "Divides the sample duration evenly into `num_slices:` sections (defaults to 16) and set the `start:` and `finish:` opts to play the nth slice only. If `start:` or `finish:` opts are used in addition to `slice:` then they will work within the slice rather than the whole sample. Use the envelope opts to remove any clicks introduced if the slice boundary is in the middle of a sound. Also consider `onset:` as an alternative to `slice:`. If `onset:` is also used then the slices will be within the onset rather than the whole sample. Floats are rounded to the nearest whole number.",
"num_slices": "Number of slices to divide the sample into when using the `slice:` opt. Defaults to 16. Floats are rounded to the nearest whole number.",
"norm": "Normalise the audio (make quieter parts of the sample louder and louder parts quieter) - this is similar to the normaliser FX. This may emphasise any clicks caused by clipping.",
"lpf_init_level": "The initial low pass filter envelope value as a MIDI note. This envelope is bypassed if no lpf env opts are specified. Default value is to match the `lpf_min:` opt.",
"lpf_attack_level": "The peak lpf cutoff (value of cutoff at peak of attack) as a MIDI note. Default value is to match the `lpf_decay_level:` opt.",
"lpf_decay_level": "The level of lpf cutoff after the decay phase as a MIDI note. Default value is to match the `lpf_sustain_level:` opt.",
"lpf_sustain_level": "The sustain cutoff (value of lpf cutoff at sustain time) as a MIDI note. Default value is to match the `lpf_release_level:` opt.",
"lpf_release_level": "The final value of the low pass filter envelope as a MIDI note. This envelope is bypassed if no lpf env opts are specified. Default value is to match the `lpf:` opt.",
"lpf_attack": "Attack time for lpf cutoff filter. Amount of time (in beats) for sound to reach full cutoff value. Default value is set to match amp envelope's attack value.",
"lpf_decay": "Decay time for lpf cutoff filter. Amount of time (in beats) for sound to move from full cutoff value (cutoff attack level) to the cutoff sustain level. Default value is set to match amp envelope's decay value.",
"lpf_sustain": "Amount of time for lpf cutoff value to remain at sustain level in beats. When -1 (the default) will auto-stretch.",
"lpf_release": "Amount of time (in beats) for sound to move from lpf cutoff sustain value to lpf cutoff min value. Default value is set to match amp envelope's release value.",
"lpf_min": "Starting value of the lpf cutoff envelope. Default is 30.",
"lpf_env_curve": "Select the shape of the curve between levels in the lpf cutoff envelope. 1=linear, 2=exponential, 3=sine, 4=welch, 6=squared, 7=cubed.",
"hpf_init_level": "The initial high pass filter envelope value as a MIDI note. This envelope is bypassed if no hpf env opts are specified. Default value is set to 130.",
"hpf_attack_level": "The peak hpf cutoff (value of cutoff at peak of attack) as a MIDI note. Default value is to match the `hpf_decay_level:` opt.",
"hpf_decay_level": "The level of hpf cutoff after the decay phase as a MIDI note. Default value is to match the `hpf_sustain_level:` opt.",
"hpf_sustain_level": "The sustain cutoff (value of hpf cutoff at sustain time) as a MIDI note. Default value is to match the `hpf_release_level:` opt.",
"hpf_release_level": "The sustain hpf cutoff (value of hpf cutoff at sustain time) as a MIDI note. Default value is to match the `hpf:` opt.",
"hpf_attack": "Attack time for hpf cutoff filter. Amount of time (in beats) for sound to reach full cutoff value. Default value is set to match amp envelope's attack value.",
"hpf_decay": "Decay time for hpf cutoff filter. Amount of time (in beats) for sound to move from full cutoff value (cutoff attack level) to the cutoff sustain level. Default value is set to match amp envelope's decay value.",
"hpf_sustain": "Amount of time for hpf cutoff value to remain at sustain level in beats. When -1 (the default) will auto-stretch.",
"hpf_release": "Amount of time (in beats) for sound to move from hpf cutoff sustain value to hpf cutoff min value. Default value is set to match amp envelope's release value.",
"hpf_env_curve": "Select the shape of the curve between levels in the hpf cutoff envelope. 1=linear, 2=exponential, 3=sine, 4=welch, 6=squared, 7=cubed.",
"hpf_max": "Maximum value of the high pass filter envelope. Default is 200.",
"window_size": "Pitch shift-specific opt - only honoured if the `pitch:` opt is used. Pitch shift works by chopping the input into tiny slices, then playing these slices at a higher or lower rate. If we make the slices small enough and overlap them, it sounds like the original sound with the pitch changed. The window_size is the length of the slices and is measured in seconds. It needs to be around 0.2 (200ms) or greater for pitched sounds like guitar or bass, and needs to be around 0.02 (20ms) or lower for percussive sounds like drum loops. You can experiment with this to get the best sound for your input.",
"pitch_dis": "Pitch shift-specific opt - only honoured if the `pitch:` opt is used. Pitch dispersion - how much random variation in pitch to add. Using a low value like 0.001 can help to \\\"soften up\\\" the metallic sounds, especially on drum loops. To be really technical, pitch_dispersion is the maximum random deviation of the pitch from the pitch ratio (which is set by the `pitch:` opt).",
"time_dis": "Pitch shift-specific opt - only honoured if the `pitch:` opt is used. Time dispersion - how much random delay before playing each grain (measured in seconds). Again, low values here like 0.001 can help to soften up metallic sounds introduced by the effect. Large values are also fun as they can make soundscapes and textures from the input, although you will most likely lose the rhythm of the original. NB - This won't have an effect if it's larger than window_size.",
"compress": "Enable the compressor. This sits at the end of the internal FX chain immediately before the `amp:` opt. Therefore to drive the compressor use the `pre_amp:` opt which will amplify the signal before it hits any internal FX. The compressor compresses the dynamic range of the incoming signal. Equivalent to automatically turning the amp down when the signal gets too loud and then back up again when it's quiet. Useful for ensuring the containing signal doesn't overwhelm other aspects of the sound. Also a general purpose hard-knee dynamic range processor which can be tuned via the opts to both expand and compress the signal.",
"threshold": "Threshold value determining the break point between slope_below and slope_above. Only valid if the compressor is enabled by turning on the `compress:` opt.",
"slope_below": "Slope of the amplitude curve below the threshold. A value of 1 means that the output of signals with amplitude below the threshold will be unaffected. Greater values will magnify and smaller values will attenuate the signal. Only valid if the compressor is enabled by turning on the `compress:` opt.",
"slope_above": "Slope of the amplitude curve above the threshold. A value of 1 means that the output of signals with amplitude above the threshold will be unaffected. Greater values will magnify and smaller values will attenuate the signal. Only valid if the compressor is enabled by turning on the `compress:` opt.",
"clamp_time": "Time taken for the amplitude adjustments to kick in fully (in seconds). This is usually pretty small (not much more than 10 milliseconds). Also known as the time of the attack phase. Only valid if the compressor is enabled by turning on the `compress:` opt.",
"relax_time": "Time taken for the amplitude adjustments to be released. Usually a little longer than clamp_time. If both times are too short, you can get some (possibly unwanted) artefacts. Also known as the time of the release phase. Only valid if the compressor is enabled by turning on the `compress:` opt.",
"path": "Path of the sample to play. Typically this opt is rarely used instead of the more powerful source/filter system. However it can be useful when working with pre-made opt maps."
}
synth_doc = {}
synth_opts_doc = {}