Release 4.2.1 tarball

This commit is contained in:
Gary Scavone
2013-09-29 23:40:35 +02:00
committed by Stephen Sinclair
parent 11cf5faa0a
commit 21b93795e7
1041 changed files with 23984 additions and 16348 deletions

View File

@@ -8,9 +8,9 @@
<img src="princeton.gif"> &nbsp; <img src="ccrma.gif"> &nbsp; <img src="mcgill.gif"><P>
<a class="qindex" href="index.html">Home</a> &nbsp; <a class="qindex" href="information.html">Information</a> &nbsp; <a class="qindex" href="classes.html">Classes</a> &nbsp; <a class="qindex" href="download.html">Download</a> &nbsp; <a class="qindex" href="usage.html">Usage</a> &nbsp; <a class="qindex" href="maillist.html">Mail List</a> &nbsp; <a class="qindex" href="system.html">Requirements</a> &nbsp; <a class="qindex" href="links.html">Links</a> &nbsp; <a class="qindex" href="tutorial.html">Tutorial</a></CENTER>
<HR>
<!-- Generated by Doxygen 1.3.4 -->
<!-- Generated by Doxygen 1.4.4 -->
<h1><a class="anchor" name="skini">Synthesis toolKit Instrument Network Interface (SKINI)</a></h1>This describes the latest (version 1.1) implementation of SKINI for the Synthesis ToolKit in C++ (STK) by Perry R. Cook.<p>
<div class="fragment"><pre> Too good to be <span class="keyword">true</span>?
<div class="fragment"><pre class="fragment"> Too good to be <span class="keyword">true</span>?
Have control and read it too?
A SKINI haiku.
</pre></div><p>
@@ -28,24 +28,21 @@ Why SKINI?</a></h2>
SKINI was designed to be extensable and hackable for a number of applications: imbedded synthesis in a game or VR simulation, scoring and mixing tasks, real-time and non-real time applications which could benefit from controllable sound synthesis, JAVA controlled synthesis, or eventually maybe JAVA synthesis, etc. SKINI is not intended to be "the mother of scorefiles," but since the entire system is based on text representations of names, floats, and ints, converters from one scorefile language to SKINI, or back, should be easily created.<p>
I am basically a bottom-up designer with an awareness of top-down design ideas, so SKINI above all reflects the needs of my particular research and creative projects as they have arisen and developed. SKINI 1.1 represents a profound advance beyond versions 0.8 and 0.9 (the first versions), future SKINI's might reflect some changes. Compatibility with prior scorefiles will be attempted, but there aren't that many scorefiles out there yet.<h2><a class="anchor" name="messages">
SKINI Messages</a></h2>
A basic SKINI message is a line of text. There are only three required fields, the message type (an ASCII name), the time (either delta or absolute), and the channel number. Don't freak out and think that this is MIDI channel 0-15 (which is supported), because the channel number is scanned as a long int. Channels could be socket numbers, machine IDs, serial numbers, or even unique tags for each event in a synthesis. Other fields might be used, as specified in the SKINI.tbl file. This is described in more detail later.<p>
A basic SKINI message is a line of text. There are only three required fields, the message type (an ASCII name), the time (either delta or absolute), and the channel number. Don't freak out and think that this is MIDI channel 0-15 (which is supported), because the channel number is scanned as a long int. Channels could be socket numbers, machine IDs, serial numbers, or even unique tags for each event in a synthesis. Other fields might be used, as specified in the <code>SKINI.tbl</code> file. This is described in more detail later.<p>
Fields in a SKINI line are delimited by spaces, commas, or tabs. The SKINI parser only operates on a line at a time, so a newline means the message is over. Multiple messages are NOT allowed directly on a single line (by use of the ; for example in C). This could be supported, but it isn't in version 1.1.<p>
Message types include standard MIDI types like NoteOn, NoteOff, ControlChange, etc. MIDI extension message types (messages which look better than MIDI but actually get turned into MIDI-like messages) include LipTension, StringDamping, etc. Non-MIDI message types include SetPath (sets a path for file use later), and OpenReadFile (for streaming, mixing, and applying effects to soundfiles along with synthesis, for example). Other non-MIDI message types include Trilling, HammerOn, etc. (these translate to gestures, behaviors, and contexts for use by intellegent players and instruments using SKINI). Where possible I will still use these as MIDI extension messages, so foot switches, etc. can be used to control them in real time.<p>
All fields other than type, time, and channel are optional, and the types and useage of the additional fields is defined in the file SKINI.tbl.<p>
The other important file used by SKINI is <a class="el" href="SKINI_8msg.html">SKINI.msg</a>, which is a set of #defines to make C code more readable, and to allow reasonably quick re-mapping of control numbers, etc.. All of these defined symbols are assigned integer values. For Java, the #defines could be replaced by declaration and assignment statements, preserving the look and behavior of the rest of the code.<h2><a class="anchor" name="cfiles">
Message types include standard MIDI types like NoteOn, NoteOff, ControlChange, etc. MIDI extension message types (messages which look better than MIDI but actually get turned into MIDI-like messages) include LipTension, StringDamping, etc. Non-MIDI message types include SetPath (sets a path for file use later), and OpenReadFile (for streaming, mixing, and applying effects to soundfiles along with synthesis, for example). Other non-MIDI message types include Trilling, HammerOn, etc. (these translate to gestures, behaviors, and contexts for use by intelligent players and instruments using SKINI). Where possible I will still use these as MIDI extension messages, so foot switches, etc. can be used to control them in real time.<p>
All fields other than type, time, and channel are optional, and the types and useage of the additional fields is defined in the file <code>SKINI.tbl</code>.<p>
The other important file used by SKINI is <code>SKINI.msg</code>, which is a set of defines to make C code more readable, and to allow reasonably quick re-mapping of control numbers, etc.. All of these defined symbols are assigned integer values. For Java, the defines could be replaced by declaration and assignment statements, preserving the look and behavior of the rest of the code.<h2><a class="anchor" name="cfiles">
Files Used To Implement SKINI</a></h2>
Skini.cpp is a C++ object which can either open a SKINI file and successively read and parse lines of text as SKINI strings, or accept strings from another object and parse them. The latter functionality would be used by a socket, pipe, or other connection receiving SKINI messages a line at a time, usually in real time, but not restricted to real time.<p>
<a class="el" href="SKINI_8msg.html">SKINI.msg</a> should be included by anything wanting to use the Skini.cpp object. This is not mandatory, but use of the __SK_blah_ symbols which are defined in the .msg file will help to ensure clarity and consistency when messages are added and changed.<p>
SKINI.tbl is used only by the SKINI parser object (Skini.cpp). In the file SKINI.tbl, an array of structures is declared and assigned values which instruct the parser as to what the message types are, and what the fields mean for those message types. This table is compiled and linked into applications using SKINI, but could be dynamically loaded and changed in a future version of SKINI.<h2><a class="anchor" name="parser">
<a class="el" href="classSkini.html">Skini</a> is a C++ class which can either open a SKINI file and successively read and parse lines of text as SKINI strings, or accept strings from another object and parse them. The latter functionality would be used by a socket, pipe, or other connection receiving SKINI messages a line at a time, usually in real time, but not restricted to real time.<p>
<code>SKINI.msg</code> should be included by anything wanting to use the <a class="el" href="classSkini.html">Skini</a> object. This is not mandatory, but use of the __SK_blah_ symbols which are defined in the .msg file will help to ensure clarity and consistency when messages are added and changed.<p>
<code>SKINI.tbl</code> is used only by the <a class="el" href="classSkini.html">Skini</a> parser object (Skini.cpp). In the file <code>SKINI.tbl</code>, an array of structures is declared and assigned values which instruct the parser as to what the message types are, and what the fields mean for those message types. This table is compiled and linked into applications using SKINI, but could be dynamically loaded and changed in a future version of SKINI.<h2><a class="anchor" name="parser">
SKINI Messages and the SKINI Parser:</a></h2>
The parser isn't all that smart, but neither am I. Here are the basic rules governing a valid SKINI message:<p>
<ul>
<li>If the first (non-delimiter ... see below) character in a SKINI string is '/' that line is treated as a comment and echoed to stdout.</li></ul>
<p>
<ul>
<li>If there are no characters on a line, that line is treated as blank and echoed to stdout. Tabs and spaces are treated as non-characters.</li></ul>
<p>
<ul>
<li>Spaces, commas, and tabs delimit the fields in a SKINI message line. (We might allow for multiple messages per line later using the semicolon, but probably not. A series of lines with deltaTimes of 0.0 denotes simultaneous events. For read-ability, multiple messages per line doesn't help much, so it's unlikely to be supported later).</li></ul>
<p>
<ul>
@@ -58,44 +55,44 @@ The parser isn't all that smart, but neither am I. Here are the basic rules gove
<li>The third field must be an integer channel number. Don't go crazy and think that this is just MIDI channel 0-15 (which is supported). The channel number is scanned as a long int. Channels 0-15 are in general to be treated as MIDI channels. After that it's wide open. Channels could be socket numbers, machine IDs, serial numbers, or even unique tags for each event in a synthesis. A -1 channel can be used as don't care, omni, or other functions depending on your needs and taste.</li></ul>
<p>
<ul>
<li>All remaining fields are specified in the SKINI.tbl file. In general, there are maximum two more fields, which are either SK_INT (long), SK_DBL (double float), or SK_STR (string). The latter is the mechanism by which more arguments can be specified on the line, but the object using SKINI must take that string apart (retrived by using getRemainderString()) and scan it. Any excess fields are stashed in remainderString.</li></ul>
<li>All remaining fields are specified in the <code>SKINI.tbl</code> file. In general, there are maximum two more fields, which are either SK_INT (long), SK_DBL (double float), or SK_STR (string). The latter is the mechanism by which more arguments can be specified on the line, but the object using SKINI must take that string apart (retrived by using getRemainderString()) and scan it. Any excess fields are stashed in remainderString.</li></ul>
<h2><a class="anchor" name="file">
A Short SKINI File:</a></h2>
<div class="fragment"><pre> <span class="comment">/* Howdy!!! Welcome to SKINI, by P. Cook 1999</span>
<span class="comment"></span>
<span class="comment"> NoteOn 0.000082 2 55 82</span>
<span class="comment"> NoteOff 1.000000 2 55 0</span>
<span class="comment"> NoteOn 0.000082 2 69 82</span>
<span class="comment"> StringDetune 0.100000 2 10</span>
<span class="comment"> StringDetune 0.100000 2 30</span>
<span class="comment"> StringDetune 0.100000 2 50</span>
<span class="comment"> NoteOn 0.000000 2 69 82</span>
<span class="comment"> StringDetune 0.100000 2 40</span>
<span class="comment"> StringDetune 0.100000 2 22</span>
<span class="comment"> StringDetune 0.100000 2 12</span>
<span class="comment"> //</span>
<span class="comment"> StringDamping 0.000100 2 0.0</span>
<span class="comment"> NoteOn 0.000082 2 55 82</span>
<span class="comment"> NoteOn 0.200000 2 62 82</span>
<span class="comment"> NoteOn 0.100000 2 71 82</span>
<span class="comment"> NoteOn 0.200000 2 79 82</span>
<span class="comment"> NoteOff 1.000000 2 55 82</span>
<span class="comment"> NoteOff 0.000000 2 62 82</span>
<span class="comment"> NoteOff 0.000000 2 71 82</span>
<span class="comment"> NoteOff 0.000000 2 79 82</span>
<span class="comment"> StringDamping =4.000000 2 0.0</span>
<span class="comment"> NoteOn 0.000082 2 55 82</span>
<span class="comment"> NoteOn 0.200000 2 62 82</span>
<span class="comment"> NoteOn 0.100000 2 71 82</span>
<span class="comment"> NoteOn 0.200000 2 79 82</span>
<span class="comment"> NoteOff 1.000000 2 55 82</span>
<span class="comment"> NoteOff 0.000000 2 62 82</span>
<span class="comment"> NoteOff 0.000000 2 71 82</span>
<span class="comment"> NoteOff 0.000000 2 79 82</span>
<div class="fragment"><pre class="fragment"> Howdy!!! Welcome to SKINI, by P. Cook 1999
NoteOn 0.000082 2 55 82
NoteOff 1.000000 2 55 0
NoteOn 0.000082 2 69 82
StringDetune 0.100000 2 10
StringDetune 0.100000 2 30
StringDetune 0.100000 2 50
NoteOn 0.000000 2 69 82
StringDetune 0.100000 2 40
StringDetune 0.100000 2 22
StringDetune 0.100000 2 12
<span class="comment">//</span>
StringDamping 0.000100 2 0.0
NoteOn 0.000082 2 55 82
NoteOn 0.200000 2 62 82
NoteOn 0.100000 2 71 82
NoteOn 0.200000 2 79 82
NoteOff 1.000000 2 55 82
NoteOff 0.000000 2 62 82
NoteOff 0.000000 2 71 82
NoteOff 0.000000 2 79 82
StringDamping =4.000000 2 0.0
NoteOn 0.000082 2 55 82
NoteOn 0.200000 2 62 82
NoteOn 0.100000 2 71 82
NoteOn 0.200000 2 79 82
NoteOff 1.000000 2 55 82
NoteOff 0.000000 2 62 82
NoteOff 0.000000 2 71 82
NoteOff 0.000000 2 79 82
</pre></div><h2><a class="anchor" name="table">
The SKINI.tbl File and Message Parsing:</a></h2>
The SKINI.tbl file contains an array of structures which are accessed by the parser object Skini.cpp. The struct is:<p>
<div class="fragment"><pre><span class="keyword">struct </span>SKINISpec {
The <code>SKINI.tbl</code> file contains an array of structures which are accessed by the parser object Skini.cpp. The struct is:<p>
<div class="fragment"><pre class="fragment"><span class="keyword">struct </span>SKINISpec {
<span class="keywordtype">char</span> messageString[32];
<span class="keywordtype">long</span> type;
<span class="keywordtype">long</span> data2;
@@ -103,7 +100,7 @@ The SKINI.tbl file contains an array of structures which are accessed by the par
};
</pre></div><p>
so an assignment of one of these structs looks like:<p>
<div class="fragment"><pre> MessageStr$ ,type, data2, data3,
<div class="fragment"><pre class="fragment"> MessageStr$ ,type, data2, data3,
</pre></div><p>
<code>type</code> is the message type sent back from the SKINI line parser.<p>
<code>data&lt;n&gt;</code> is either:<p>
@@ -117,10 +114,19 @@ so an assignment of one of these structs looks like:<p>
<li>SK_DBL : double precision floating point. SKINI uses these in the MIDI context for note numbers with micro tuning, velocities, controller values, etc.</li></ul>
<p>
<ul>
<li>SK_STR : only valid in final field. This allows (nearly) arbitrary message types to be supported by simply scanning the string to EndOfLine and then passing it to a more intellegent handler. For example, MIDI SYSEX (system exclusive) messages of up to 256 bytes can be read as space-delimited integers into the 1K SK_STR buffer. Longer bulk dumps, soundfiles, etc. should be handled as a new message type pointing to a FileName, <a class="el" href="classSocket.html">Socket</a>, or something else stored in the SK_STR field, or as a new type of multi-line message.</li></ul>
<li>SK_STR : only valid in final field. This allows (nearly) arbitrary message types to be supported by simply scanning the string to EOL (End Of Line) and then passing it to a more intelligent handler. For example, MIDI SYSEX (system exclusive) messages can be read as space-delimited integers into the SK_STR buffer. Longer bulk dumps, soundfiles, etc. should be handled as a new message type pointing to a FileName, <a class="el" href="classSocket.html">Socket</a>, or something else stored in the SK_STR field, or as a new type of multi-line message.</li></ul>
<p>
Here's a couple of lines from the SKINI.tbl file<p>
<div class="fragment"><pre> {<span class="stringliteral">"NoteOff"</span> , __SK_NoteOff_, SK_DBL, SK_DBL},
Each individual SKINI message is parsed and saved to a <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> structure of the form: <div class="fragment"><pre class="fragment"> <span class="keyword">struct </span>Message {
<span class="keywordtype">long</span> type; !&lt; The message type, as defined in SKINI.msg.
<span class="keywordtype">long</span> channel; !&lt; The message channel (not limited to 16!).
StkFloat time; !&lt; The message time stamp in seconds (delta or absolute).
std::vector&lt;StkFloat&gt; floatValues; !&lt; The message values read as floats (values are type-specific).
std::vector&lt;long&gt; intValues; !&lt; The message values read as ints (number and values are type-specific).
std::string remainder; !&lt; Any remaining message data, read as ascii text.
};
</pre></div><p>
Here's a couple of lines from the <code>SKINI.tbl</code> file<p>
<div class="fragment"><pre class="fragment"> {<span class="stringliteral">"NoteOff"</span> , __SK_NoteOff_, SK_DBL, SK_DBL},
{<span class="stringliteral">"NoteOn"</span> , __SK_NoteOn_, SK_DBL, SK_DBL},
{<span class="stringliteral">"ControlChange"</span> , __SK_ControlChange_, SK_INT, SK_DBL},
@@ -129,17 +135,17 @@ Here's a couple of lines from the SKINI.tbl file<p>
{<span class="stringliteral">"StringDamping"</span> , __SK_ControlChange_, __SK_StringDamping_, SK_DBL},
{<span class="stringliteral">"StringDetune"</span> , __SK_ControlChange_, __SK_StringDetune_, SK_DBL},
</pre></div><p>
The first three are basic MIDI messages. The first two would cause the parser, after recognizing a match of the string "NoteOff" or "NoteOn", to set the message type to 128 or 144 (__SK_NoteOff_ and __SK_NoteOn_ are #defined in the file <a class="el" href="SKINI_8msg.html">SKINI.msg</a> to be the MIDI byte value, without channel, of the actual MIDI messages for NoteOn and NoteOff). The parser would then set the time or delta time (this is always done and is therefore not described in the SKINI Message Struct). The next two fields would be scanned as double-precision floats and assigned to the byteTwo and byteThree variables of the SKINI parser. The remainder of the line is stashed in the remainderString variable.<p>
The first three are basic MIDI messages. The first two would cause the parser, after recognizing a match of the string "NoteOff" or "NoteOn", to set the message type to 128 or 144 (__SK_NoteOff_ and __SK_NoteOn_ are defined in the file <code>SKINI.msg</code> to be the MIDI byte value, without channel, of the actual MIDI messages for NoteOn and NoteOff). The parser would then set the time or delta time (this is always done and is therefore not described in the SKINI Message Struct). The next two fields would be scanned either as double-precision <code>floats</code> or as <code>long ints</code>, depending on the format specified in <code>SKINI.tbl</code>, and saved to the corresponding C++ vector variables in the <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> structure (either <code>floatValues</code> or <code>intValues</code>). Floating-point values are also cast to <code>ints</code> (and vice-versa) and stored to their respective variables. For example, an expected integer value of 64 will also be saved as 64.0 in the corresponding <code>floatValues</code> variable of the <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> structure. The remainder of the line is stashed in the remainderString variable.<p>
The ControlChange spec is basically the same as NoteOn and NoteOff, but the second data byte is set to an integer (for checking later as to what MIDI control is being changed).<p>
The Volume spec is a MIDI Extension message, which behaves like a ControlChange message with the controller number set explicitly to the value for MIDI Volume (7). Thus the following two lines would accomplish the same changing of MIDI volume on channel 2:<p>
<div class="fragment"><pre> ControlChange 0.000000 2 7 64.1
<div class="fragment"><pre class="fragment"> ControlChange 0.000000 2 7 64.1
Volume 0.000000 2 64.1
</pre></div><p>
I like the 2nd line better, thus my motivation for SKINI in the first place.<p>
I like the second line better, thus my motivation for SKINI in the first place.<p>
The StringDamping and StringDetune messages behave the same as the Volume message, but use Control Numbers which aren't specifically nailed-down in MIDI. Note that these Control Numbers are carried around as long ints, so we're not limited to 0-127. If, however, you want to use a MIDI controller to play an instrument, using controller numbers in the 0-127 range might make sense.<h2><a class="anchor" name="using">
Using SKINI:</a></h2>
Here's a simple example of code which uses the SKINI object to read a SKINI file and control a single instrument.<p>
<div class="fragment"><pre> <a class="code" href="classSkini.html">Skini</a> score;
Here's a simple example of code which uses the <a class="el" href="classSkini.html">Skini</a> object to read a SKINI file and control a single instrument.<p>
<div class="fragment"><pre class="fragment"> <a class="code" href="classSkini.html">Skini</a> score;
<a class="code" href="structSkini_1_1Message.html">Skini::Message</a> message;
instrument = <span class="keyword">new</span> <a class="code" href="classMandolin.html">Mandolin</a>(50.0);
score.<a class="code" href="classSkini.html#a2">setFile</a>( argv[1] );
@@ -147,15 +153,15 @@ Here's a simple example of code which uses the SKINI object to read a SKINI file
tempDouble = message.<a class="code" href="structSkini_1_1Message.html#o2">time</a>;
<span class="keywordflow">if</span> (tempDouble &lt; 0) {
tempDouble = - tempDouble;
tempDouble = tempDouble - output.<a class="code" href="classWvOut.html#a6">getTime</a>();
tempDouble = tempDouble - output.<a class="code" href="classWvOut.html#a3">getTime</a>();
<span class="keywordflow">if</span> (tempDouble &lt; 0) {
printf(<span class="stringliteral">"Bad News Here!!! Backward Absolute Time Required.\n"</span>);
tempDouble = 0.0;
}
}
tempLong = (<span class="keywordtype">long</span>) ( tempDouble * <a class="code" href="classStk.html#e0">Stk::sampleRate</a>() );
tempLong = (long) ( tempDouble * <a class="code" href="classStk.html#e0">Stk::sampleRate</a>() );
<span class="keywordflow">for</span> ( i=0; i&lt;tempLong; i++ ) {
output.<a class="code" href="classWvOut.html#a9">tick</a>( instrument-&gt;<a class="code" href="classInstrmnt.html#a8">tick</a>() );
output.<a class="code" href="classWvOut.html#a6">tick</a>( instrument-&gt;<a class="code" href="classInstrmnt.html#a8">tick</a>() );
}
tempDouble3 = message.<a class="code" href="structSkini_1_1Message.html#o3">floatValues</a>[1] * NORM_MIDI;
@@ -175,18 +181,17 @@ Here's a simple example of code which uses the SKINI object to read a SKINI file
}
<span class="keywordflow">else</span> <span class="keywordflow">if</span> ( message.<a class="code" href="structSkini_1_1Message.html#o0">type</a> == __SK_ControlChange_ ) {
tempLong = message.<a class="code" href="structSkini_1_1Message.html#o4">intValues</a>[0];
instrument-&gt;<a class="code" href="classInstrmnt.html#a11">controlChange</a>( tempLong, tempDouble3 );
instrument-&gt;<a class="code" href="classInstrmnt.html#a10">controlChange</a>( tempLong, tempDouble3 );
}
}
</pre></div><p>
When a SKINI score is passed to a <a class="el" href="classSkini.html">Skini</a> object using the <a class="el" href="classSkini.html#a2">Skini::setFile()</a> function, valid messages are read from the file and returned using the <a class="el" href="classSkini.html#a3">Skini::nextMessage()</a> function.<p>
A <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> structure contains all the information parsed from a single SKINI message. A returned message type of zero indicates either an invalid message or the end of a scorefile.<p>
The "time" member of a <a class="el" href="structSkini_1_1Message.html">Skini::Message</a> is the deltaTime until the current message should occur. If this is greater than 0, synthesis occurs until the deltaTime has elapsed. If deltaTime is less than zero, the time is interpreted as absolute time and the output device is queried as to what time it is now. That is used to form a deltaTime, and if it's positive we synthesize. If it's negative, we print an error, pretend this never happened and we hang around hoping to eventually catch up.<p>
The rest of the code sorts out message types NoteOn, NoteOff (including NoteOn with velocity 0), and ControlChange. The code implicitly takes into account the integer type of the control number, but all other data is treated as double float. <HR>
<table>
<tr><td><A HREF="http://ccrma.stanford.edu/software/stk/"><I>The Synthesis ToolKit in C++ (STK)</I></A></td></tr>
<tr><td>&copy;1995-2004 Perry R. Cook and Gary P. Scavone. All Rights Reserved.</td></tr>
<tr><td>&copy;1995-2005 Perry R. Cook and Gary P. Scavone. All Rights Reserved.</td></tr>
</table>
</BODY>