To use this demo script, read through the text selecting the blocks enclosed in square brackets. The single character after the close-square-bracket (d,p, i, or db) denotes whether you should "do," "print," "inspect," or "debug" the block. (Typically, CTRL-D means do-it, CTRL-P means print-it, and CTRL-Q means inspect-it.) To look at the code for the complex examples below, simply "debug-it" and single-step into the demo method.
For the function and event list examples below, note that the "open" method edits the receiver by default; if you hold down
If you're new to reading Smalltalk, look at the workbook section on "Learning to Read Smalltalk." If you're setting up Siren for the first time, see the section above on "Siren Set-up and Testing" and make certain you know how to use the Siren Utility panel and the Siren Transport view.
Set-up
Configure and test the MIDI and sound I/O drivers using the utility panel.
Load the test data with the "Load All" button in the utility pane.
See also the section above on "Siren Set-up."
MusicMagnitudes
Print these to see what kinds of music magnitude representations and operations are supported.
['a4' pitch asMIDI] p
Pitch expressions ("N" is short-hand for PitchClass)
Event Creation Messages
Create a `generic' event using a class instance creation message.
Create one with added properties.
Terse format: concatenation (with ',') of music magnitudes
Event Lists
Verbose form using a class instance creation message;
(EventList newNamed: #Chord1)
Play a scale created with a class message.
Create 64 random events with parameters in the given ranges, play it on the default output voice, or edit it.
Create an event list of 20 notes with semi-random values and play it on a MIDI output voice.
Event lists don't have to have pitches at all, as in the word,
Play two-voice "counterpoint" on the note list score file voices.
Here's another example of creating a simple melody
You can also create event lists with snippets of code such as the following whole-tone scale.
Event lists can also be nested into arbitrary structures, as in the following group of four sub-groups
Smalltalk methods can also process event lists, as in this code to increase the durations of the last notes in each of the groups from the previous example.
...or the following to take the scale and make it slow down
Storage and Persistency
Siren Scheduler
Reset
Here's how to use the event scheduler explicitly.
Flush and close down the scheduler
Action events have arbitrary blocks of Smalltalk code as their "actions." This example creates a list of action events that flash random screen rectangles.
Complex Multimedia Example
Functions and Control
If you like thicker function plots, do this,
Basic ramp up/down (linear and exponential flavors)
ADSR-like envelopes
Open a view with a linear envelope, an exponential envelope, a spline curve, and a sum-of-sines function
One can apply a function to any property of an event list, as in the example below, which makes a crescendo/decrescendo using an exponential triangle function.
[ | list fcn |
Send function data values out as regular OSC messages
Load a SHARC sample and create a wave table from it.
EventGenerators
A cluster is the simplest event generator.
Chord object can give you an event list.
Create and play a simple drum roll--another 1-D event generator.
Create and edit a low 6 second stochastic cloud with 5 events per second.
[ | c |
Play a 6-second cloud that goes from low to high and soft to loud.
Select notes frmo a given scale
Play a selection cloud that makes a transition from one triad to another.
The extended DynamicSelectionCloud uses a multi-part pitch set of the format (time -> chord) (time -> chord) ... as in the following example.
Mark Lentczner's bell peals ring the changes.
EventModifiers
One can apply functions to the properties of event lists, as in the following example, which creates a drum roll and applies a crescendo modifier to it.
MIDI Control
Open MIDI, play notes based on the mouse position (x --> dur; y --> pitch) until mouse down.
Demonstrate program change by setting up an organ instrument to play on.
Down-load a general MIDI patch for a 16-voice percussion ensemble.
Reset the GM map
Demonstrate control commands by playing a note and making a crescendo with the volume pedal.
Demonstrate pitch-bend by playing two notes and bending them.
ANO
Close down and clean up.
Voices and I/O
[CsoundVoice randomExampleToFileAndEdit]
[(EventList randomExample: 20) playOn: MIDIVoice default]
These use the CSL OSC servers
These examples loop endlessly, so you have to interrupt or flush the scheduler to stop them
As an example that mixes styles, the following expression plays a long low FM note and then uses Siren function objects to send continuous controls to make the note glissando down and pan from left to right.
The Siren Graphics Framework
Display rectangles in a display list view -- test zoom and scroll.
An alternative layout (which I prefer) places the zoom bars on the top and right. look at,
Display random strings
Show the result of the IndentedListLayoutManager
Music Notations
Open a sequence view on a random event list.
Try the picth-time layout
Open a pitch/time view on a *very long* 3-stream event list.
A more complete example is Hauer-Steffens notation, which has a clef and staff lines as in common-practise notation.
Read in a sound from a file
Now try the external interface examples, then the SWIG Loris and CSL APIs.
Create a swept sine wave and take its fft.
Read a file (T'ang dynasty speech) and show the spectrogram
Low-level sample processing: sum a sine and a sawtooth
As a final example, one can apply a function to a sound as an envelope, as in this block,
[((SampledSound sineDur: 1.0 rate: 44100 freq: 220 chans: 1)
Using the Loris Interface and Tools
For normal usage, set-up with this
Test with this (prints the Loris version string)
To load a sound file and run it, saving the result as SDIF and opening a display (read this method to see how to use the Loris API)
Using the CSL Models
Set-up
First test; print a random number
To oest a CSL graph; play a simple note
Test FM
Test processors: filtered noise
Play a sound sample
Play 25 oscillators with random-walk freq and position.
If you have a MIDI fader box, try the following demo
[SirenSession openUtility] d
You can browse the test data with the left-side menu buttons in the transport panel, do,
[SirenSession openTransport] d
[440 Hz asSymbol] p "--> 'a3' pitch"
[(1/4 beat) asMsec] p "--> 250 msec"
[#mf ampl asMIDI] p "--> 70 vel"
[-16 dB asRatio value] p "--> 0.158489"
[('a4' pitch + 100 Hz) asMIDI] p
[('a4' pitch + 100 Hz) asFracMIDI] p
['mp' ampl + 3 dB] p
[('mp' ampl + 3 dB) asMIDI] p
[(1/2 beat) + 100 msec] p
[N C sharp sharp] p
[N C augmentedFourth] p
[N C diminishedThirteenth] p
[N do flat intervalBetween: N sol] p
[PitchClass D flat melodicMinorScale notes] p
[(PitchClassChord new fromString: 'C aug9 dim5') notes] p
[(HungarianMinor root: N fa) asPitchesInOctave: 2] p
MusicEvent duration: 1/4 pitch: 'c3' ampl: 'mf'
(MusicEvent dur: 1/4 pitch: 'c3') color: #green; accent: #sfz
[440 Hz, (1/4 beat), 44 dB] i
(#c4 pitch, 0.21 sec, 64 velocity) voice: IOVoice default
a chord is simply a set of events at the same time.
add: ((1/2 beat), 'd3' pitch, 'mf' ampl) at: 0;
add: ((1/2 beat), 'fs3' pitch, 'mf' ampl) at: 0;
add: ((1/2 beat), 'a4' pitch, 'mf' ampl) at: 0
[(EventList scaleExampleFrom: 48 to: 60 in: 1500) open] d
[(EventList randomExample: 64 "make 64 notes"
from: ((#duration: -> (50 to: 200)), "duration range in msec"
(#pitch: -> (36 to: 60)), "pitch range in MIDI keys"
(#ampl: -> (48 to: 120)), "amplitude range in MIDI velocities"
(#voice: -> (1 to: 1))) "play all on voice 1"
) open] d
[(EventList randomExample: 20) playOn: MIDIVoice default] d
[EventList named: 'phrase1'
fromSelectors: #(duration: loudness: phoneme:) "3 parameters"
values: (Array with: #(595 545 545 540 570 800 540) "3 value arrays"
with: #(0.8 0.4 0.5 0.3 0.2 0.7 0.1)
with: #(#dun #kel #kam #mer #ge #sprae #che)).
(EventList named: 'phrase1') inspect]
[ | vox list |
vox := CsoundVoice onFileNamed: 'test.cs'.
list := (EventList newNamed: #pRand)
addAll: (EventList randomExample: 20);
addAll: (EventList randomExample: 20).
vox play: list.
vox close.
(Filename named: 'test.cs') open] d
[(EventList named: 'melody'
fromSelectors: #(pitch: duration: ampl:)
values: (Array with: #(c d e f g)
with: #(4 8 8 4 4) reciprocal
with: #(1))) open] d
[ | elist |
elist := EventList newAnonymous.
1 to: 12 do:
[ :index |
elist add: (1/4 beat, (index * 2 + 36) key, 'mf' ampl)].
elist open ] d
[ (EventList newNamed: 'Hierarchical/4Groups')
add: (EventList randomExample: 8
from: ((#duration: -> (60 to: 120)), (#pitch: -> (36 to: 40)), (#ampl: -> #(110)))) at: 0;
add: (EventList randomExample: 8
from: ((#duration: -> (60 to: 120)), (#pitch: -> (40 to: 44)), (#ampl: -> #(100)))) at: 1;
add: (EventList randomExample: 8
from: ((#duration: -> (60 to: 120)), (#pitch: -> (44 to: 48)), (#ampl: -> #(80)))) at: 2;
add: (EventList randomExample: 8
from: ((#duration: -> (60 to: 120)), (#pitch: -> (48 to: 52)), (#ampl: -> #(70)))) at: 3;
open ] d
[ (EventList named: 'Hierarchical/4Groups') eventsDo:
[ :sublist | | evnt | "Remember: this is hierarchical, to the events are the sub-groups"
evnt := sublist events last event. "get the first note of each group"
evnt duration: evnt duration * 8]. "multiply the duration by 4"
(EventList named: #groups) open ] d
[ | elist |
elist := EventList scaleExampleFrom: 60 to: 36 in: 1500.
1 to: elist size do:
[ :index | | assoc |
assoc := elist events at: index.
assoc key: (assoc key * (1 + (index / elist events size)))].
elist open ] d
"SirenSession eventList: 'piece1/mvmnt1/part1' put: EventList new"
"SirenSession eventList: 'piece1/mvmnt1/part1'"
[EventScheduler initialize]
[EventScheduler instance addClient: (EventList randomExample: 20) in: (500 msec).
EventScheduler instance run] d
[EventScheduler instance interrupt; flush] d
[ActionEvent playExample] d
[ | el |
el := (Cloud dur: 6 "Create a 6-second stochastic cloud"
pitch: (48 to: 60) "choose pitches in this range"
ampl: (40 to: 70) "choose amplitudes in this range"
voice: #(1) "leave the 1 nil for now"
density: 5) eventList. "play 5 notes per sec. and get the events"
1 to: el events size do: "Now plug different voices in to the events"
[ :ind | "ind is the counter"
(el events at: ind) event voice:
(ind odd "alternate between two voices"
ifTrue: [MIDIVoice default]
ifFalse: [OSCVoice default])].
"add some animation events"
el addAll: ActionEvent listExample.
el open] d "and play the merged event list"
[FunctionView lineWidth: 2]
[(LinearFunction from: #((0 0) (0.5 1) (1 0))) at: 0.25] p
[(ExponentialFunction from: #((0 0 5) (0.5 1 -5) (1 0))) at: 0.25 ] p
[(LinearFunction from: #((0 0) (0.1 1) (0.16 0.7) (0.8 0.4) (1 0))) edit]
[(ExponentialFunction from: #((0 0 5) (0.1 1 -3) (0.8 0.4 -2) (1 0))) edit]
[FunctionView multiFunctionExample]
list := EventList newNamed: #test3.
(0 to: 4000 by: 100) do: "4 seconds, 10 notes per second"
[ :index | "add the same note"
list add: (MusicEvent dur: 100 pitch: 36 ampl: 120) at: index].
fcn := ExponentialFunction from: #((0 0.05 2) (0.5 1 -2) (1 0.05)).
list applyFunction: fcn to: #loudness.
list inspect] d
[OSCVoice functionExample] db
[(Function from: (((SHARCInstrument fromDir: 'tuba') samples at: #c3) asWavetable: 1024)) edit: 1024] d
[(Cluster dur: 2.0
pitchSet: #(48 50 52 54 56)
ampl: 100
voice: 1) open] d
[((Chord majorTetradOn: 'f4' inversion: 0) duration: 1.0) open] d
[((Roll length: 2000 rhythm: 50 note: 60) ampl: 80) open] d
c := (Cloud dur: 6 "lasts 6 sec."
pitch: (48 to: 60) "with pitches in this range"
ampl: (80 to: 120) "and amplitudes in this range"
voice: (1 to: 1) "select from these voices"
density: 5) eventList. "play 5 notes per sec. and get the event list"
c open] d
[(DynamicCloud dur: 6
pitch: #((30 to: 44) (50 to: 50)) "given starting and ending selection ranges"
ampl: #((20 to: 40) (90 to: 120))
voice: (1 to: 4)
density: 15) open] d
[(SelectionCloud dur: 4
pitch: ((NeapolitanMinor root: N do) asPitchesInOctave: 4)
ampl: #(80 40 120)
voice: #(1)
density: 12) open] d
[(DynamicSelectionCloud dur: 6
pitch: #( #(48 50 52) #(72 74 76) ) "starting and ending pitch sets"
ampl: #(60 80 120)
voice: #(1)
density: 12) open] d
[ | score chords list | "generate the tetrads from the selected scale; scramble the order"
chords := ((NeapolitanMinor root: N do) generateChordsPoly: 4 inOctave: 2) scrambled.
list := OrderedCollection new.
1 to: 7 do:
[ :ind | "shift every other one up 2 octaves"
ind even ifTrue: [list add: ((ind - 1) * 3 -> ((chords at: ind) collect: [ :no | no + 24]))]
ifFalse: [list add: ((ind - 1) * 3 -> (chords at: ind))]].
score := (ExtDynamicSelectionCloud dur: 8 "now make a cloud from these"
pitch: list
ampl: 60
voice: nil
density: 10) eventList.
score eventsDo: [ :ev | "plug in the properties for FM"
ev inst: '/i1/pn'.
ev modIndex: 2.0.
ev ratio: 1.02.
ev pos: 0.0].
SirenSession eventList: 'EvGens/dsCloud1' put: score.
score open] d
[(Peal upon: #(60 65 68)) open] d
[ | roll decresc |
roll := ((Roll length: 3000 rhythm: 150 note: 60) ampl: 120) eventList.
decresc := Swell new function: (ExponentialFunction from: #((0 1 4) (1 0))).
decresc applyTo: roll.
roll open]
[MIDIPort testMouseMIDI] d
[MIDIPort testProgramChange] d
[MIDIPort setupTunedPercussion. MIDIPort testAScale] d
[MIDIPort resetEnsemble]
[MIDIPort testControlContinuous] d
[MIDIPort testBend] d
[MIDIPort allNotesOff]
[MIDIPort cleanUp]
[SuperColliderVoice randomExampleToFileAndEdit]
[OSCVoice midiScaleExample]
[OSCVoice fmExample1]
[OSCVoice sndExample1]
[OSCVoice fmExample2. 5 wait.
OSCVoice sndExample2. 5 wait.
OSCVoice fmExample4]
[EventScheduler flush]
[OSCVoice fmExample3]
[DisplayList rectangleExample]
[DisplayListView open4SquareOn: (DisplayList rectanglesX: 2000 byY: 2000)]
[DisplayList stringExample]
[DisplayListView colorClassListExample]
[DisplayListView classTreeExample]
[TimeSequenceView randomExample] d
[PitchTimeView randomExample] d
[PitchTimeView openOnEventList: (EventList scaleExampleFrom: 48 to: 84 in: 5)] d
[PitchTimeView randomExampleLong] d
[HauerSteffensView randomExample] d
[(EventList scaleExampleFrom: 40 to: 66 in: 5) edit] d
[SoundView openOn: SampledSound sawtooth] d
[(SampledSound sweepDur: 10.0 rate: 44100 from: 10 to: 400 chans: 1) edit] d
[(SampledSound fromFile: 'unbelichtet.aiff') edit] d
[Spectrum sweepExample display] d
[Spectrum fileExample display] db
[ | sin saw |
sin := SampledSound sineDur: 1.0 rate: 44100 freq: 10 chans: 1.
saw := SampledSound sawtoothDur: 1.0 rate: 44100 freq: 100 chans: 1.
sin scaleBy: 0.8.
saw scaleBy: 0.1.
1 to: sin size do: "loop to do vector math on sound samples"
[ :index |
sin at: index put: ((sin at: index) + (saw at: index))].
sin edit] d
scaledByFunction: (ExponentialFunction default)) edit] d
[Siren.Loris.Loris initializeModule] d
[Siren.Loris.Loris version] p
[LorisSound example: '1.2a1.aiff' resolution: 70] db
[LorisSound fromSDIF: 'horns1c.sdif'] d
[Siren.CSL.CSL initializeModule] d
[Siren.CSL.CSL fRand ] p
[CSLGraph testSimpleGraph] d
[CSLGraph testFM]
[CSLGraph testStaticFilter]
[CSLGraph testDynamicFilter]
[CSLGraph testSoundFile]
[CSLGraph testOscillatorBank]
[CSLGraph testMIDIOscillatorBank]