Smoke uses objects called music magnitudes to represent the basic "units of measure" of musical sound: duration, pitch, amplitude, etc. MusicMagnitude objects are characterized by their identity, class, species, and value (e.g., the pitch object that represents 'c3' has its object identity, the class SymbolicPitch, the species Pitch, and the value 'c3' [a string]). MusicMagnitude behaviors distinguish between class membership and species in a multiple-inheritance-like scheme that allows the object representing "440.0 Hz" to have pitch-like and limited-precision-real-number-like behaviors. This means that its behavior can depend on what it represents (a pitch), or how its value is stored (a floating-point number).
The mixed-mode music magnitude arithmetic is defined using the technique of species-based coercion, i.e., class Pitch knows whether a note name or Hertz value is more general. This provides capabilities similar to those of systems that use the techniques of multiple inheritance and multiple polymorphism (such as C++ and the Common Lisp Object System), but in a much simpler and scalable manner. All meaningful coercion messages (e.g., (440.0 Hz asMIDIKeyNumber)), and mixed-mode operations (e.g., (1/4 beat + 80 msec)) are defined.
The basic model classes include Pitch, Loudness, and Duration; exemplary extensions include Length, Sharpness, Weight, and Breath for composition- or notation-specific magnitudes. The handling of time as a parameter is finessed via the abstraction of duration. All times are durations of events or delays, so that no "real" or "absolute" time object is needed. Duration objects can have simple numerical or symbolic values, or they can be conditions (e.g., the duration until some event X occurs), Boolean expressions of other durations, or arbitrary blocks of Smalltalk-80 code.
Functions of one or more variables are yet another type of signal-like music magnitude. The MODE Function class hierarchy includes (e.g.,) line segment, exponential segment, spline segment and Fourier summation functions.
In the verbose SmOKe format music magnitudes, events and event lists are created by instance creation messages sent to the appropriate classes. The first three expressions in the examples below create various music magnitudes and coerce them into other representations.
The terse form for music magnitude creation uses post-operators (unary messages) such as 440 hz or 250 msec, as shown in the examples below.
Users can extend the music magnitude framework with their own classes that refine the existing models of define totally new kinds of musical metrics.
Basic MusicMagnitude Models
Durations
SecondDuration -- 1 sec
MSecondDuration -- 100 msec (milliseconds)
USecondDuration -- 100000 usec (microseconds)
RatioDuration -- 1/4 beat (relative fractions of some tempo scale)
ConditionalDuration -- until: [ :t | boolean-block]
Pitches
HertzPitch -- 440.0 hz
MIDIPitch -- 60 pitch -- (or 60 key) can be non-integer for microtonal tunings (use #asFracMIDI)
SymbolicPitch -- 'c#3' pitch -- several different pitch spellings supported
RatioPitch -- 11/9 of: anotherPitch -- used for fraction-oriented tunings
Amplitude/Loudness Objects
DBLoudness -- -3 dB -- can be negative relative to 0 dB or positive-valued
RatioLoudness -- 0.7071 ampl (or 0.7071 loudness) -- range of 0.0 to 1.0
SymbolicLoudness -- 'fff' ampl
MIDIVelocity -- 96 velocity
Other Music Magnitudes
OrdinalMagnitudes -- have order but no explicit value
PField -- name/slot/value -- used for note lists
See also magnitude accessors in LayoutManagers
MusicMagnitude Examples
Verbose MusicMagnitude Creation and Coercion Messages
(Duration value: 1/16) asMsec "Answers Duration 62 msec."
(Pitch value: 60) asHertz "Answers Pitch 261.623 Hz."
(Amplitude value: 'ff') asMIDI "Answers MIDI key velocity 100."
Terse MusicMagnitude Creation using post-operators
440 Hz "a HertzPitch"
'c#3' pitch "a SymbolicPitch"
'cs3' pitch "a SymbolicPitch"
60 pitch "a MIDIPtch"
60 key "a MIDIPtch"
250 msec "a MSecondDuration"
1/4 beat "a RatioDuration"
-16 dB "a DBLoudness"
'fff' ampl "a SymbolicLoudness"
0.1 ampl "a RatioLoudness"
MusicMagnitude Coercion Examples
440 Hz asSymbol "--> 'a3' pitch"
(1/4 beat) asMsec "--> 250 msec"
#mf ampl asMIDI "--> 70 vel"
-16 dB asRatio value "--> 0.158489"
0.1 ampl asMIDI "--> 12 vel"
Duration Coercion Example--create a 1/8 beat duration and coerce it into a couple of other representations, printing the result to the Smalltalk transcript. To execute this, double-click just inside the open-bracket to select the entire expression and use the pop-up menu or command key (control-d) to "do it."
[ | me |
me := Duration value: 1/8.
Transcript cr; show: me printString, ' = ',
me asSec printString, ' = ',
me asUsec printString; cr] d
Pitch Coercion Example--create a named pitch (middle C) and print it to the transcript as Hz and as a MIDI key number.
[ | me |
me := Pitch value: 'c3'.
Transcript show: me printString, ' = ',
me asHertz printString, ' = ',
me asMIDI printString; cr.
"me inspect"] d
Amplitude Coercion Example--create a named dynamic value and print it as an amplitude ratio and a MIDI velocity.
[ | me |
me := Amplitude value: #mf.
Transcript show: me printString, ' = ',
me asRatio printString, ' = ',
me asDB printString, ' = ',
me asMIDI printString; cr.
"me inspect"] d
Mixed-mode Arithmetic--demonstrate adding beats and msec, or note names and Hertz values. Select and print these.
[(1/2 beat) + 100 msec] " (0.6 beat")
['a4' pitch + 25 Hz] " (465.0 Hz)"
[('a4' pitch + 100 Hz) asMIDI] " (73 key)"
[('a4' pitch + 100 Hz) asFracMIDI] " (72.5455 key)"
['mp' ampl + 3 dB] " (-4.6 dB)"
Microtonality
Alberto de Campo's microtonal extensions allow MIDI pitches to be floating-point numbers (e.g., MIDI key 60.25) and named pitches to have "remainder" values (e.g., c3 + 25 cents) as in the following examples.
[438 Hz asSymbol] "rounds to nearest chromatic note, a3."
[443.5 Hz asMIDI] "ditto."
[265 Hz asFracMIDI] "converts to float chromatics; can be rounded, used
for MIDI pitch bend or for precise synthesis in Hz."
[61.26 key asHertz] "float chromatics can also be used directly; for
microtonal scales this is clearer than Hz (to me at least)."
[260.0 Hz asFracSymbol] "is rounded, but keeps track of offsets in
an inst var (fracPitch); survives conversions etc."
Note that asMIDI and asSymbol can now be used to round pitches to chromatics, while the messages asFracMIDI and asFracSymbol keep the full microtonal precision.
Conditional Durations
Conditional durations allow one to have state-dependent events lists.
[ConditionalDuration exampleWithRands]
[ConditionalDuration until: [ :x | x > 5]]
Extending Siren's MusicMagnitude Models
Developers and composers can extend the core Smoke representation by adding new magnitude models (abstract species classes with instance creation methods, post-fix operators and a generality table) and concrete magnitudes (with units, coercion methods, and print/store). This is relatively easy and can be very useful for a composition that uses a new model for its structure.