*** empty log message ***
[chuck-blob.git] / v2 / skini.cpp
blobe509068200380601906a10dc7c8bf6ff570507b9
1 /***************************************************/
2 /*! \class Skini
3 \brief STK SKINI parsing class
5 This class parses SKINI formatted text
6 messages. It can be used to parse individual
7 messages or it can be passed an entire file.
8 The SKINI specification is Perry's and his
9 alone, but it's all text so it shouldn't be too
10 hard to figure out.
12 SKINI (Synthesis toolKit Instrument Network
13 Interface) is like MIDI, but allows for
14 floating-point control changes, note numbers,
15 etc. The following example causes a sharp
16 middle C to be played with a velocity of 111.132:
18 noteOn 60.01 111.132
20 See also SKINI.txt.
22 by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
24 /***************************************************/
26 #include "Skini.h"
27 //#include "SKINI.tbl"
29 Skini :: Skini()
33 Skini :: ~Skini()
37 bool Skini :: setFile( std::string fileName )
39 if ( file_.is_open() ) {
40 //errorString_ << "Skini::setFile: already reaading a file!";
41 //handleError( StkError::WARNING );
42 return false;
45 file_.open( fileName.c_str() );
46 if ( !file_ ) {
47 // errorString_ << "Skini::setFile: unable to open file (" << fileName << ")";
48 // handleError( StkError::WARNING );
49 return false;
52 return true;
55 long Skini :: nextMessage( Message& message )
57 if ( !file_.is_open() ) return 0;
59 std::string line;
60 bool done = false;
61 while ( !done ) {
62 // Read a line from the file and skip over invalid messages.
63 if ( std::getline( file_, line ).eof() ) {
64 // errorString_ << "// End of Score. Thanks for using SKINI!!";
65 // handleError( StkError::STATUS );
66 file_.close();
67 message.type = 0;
68 done = true;
70 else if ( parseString( line, message ) > 0 ) done = true;
73 return message.type;
77 bool Skini :: write_message( long type, float time, long channel, float data1, float data2 )
79 if( !file_.is_open() ) return 0;
81 char messageString[32];
82 char * message = new char[64];
84 // find message string from type
85 int iSkini = 0;
86 while ( iSkini < __SK_MaxMsgTypes_ ) {
87 if ( type == skini_msgs[iSkini].type )
89 strcpy( messageString, skini_msgs[iSkini].messageString );
90 break;
92 iSkini++;
95 // make up some code that makes sense to you if not to the compiler
96 printf( message, "%s %f %i %f %f\n", messageString, time, channel, data1, data2 );
97 file_.write( message, 64 * sizeof(char) );
98 return true;
102 void Skini :: close_file()
104 if( file_.is_open() )
105 file_.close();
109 void Skini :: tokenize( const std::string& str,
110 std::vector<std::string>& tokens,
111 const std::string& delimiters )
113 // Skip delimiters at beginning.
114 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
115 // Find first "non-delimiter".
116 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
118 while (std::string::npos != pos || std::string::npos != lastPos) {
119 // Found a token, add it to the vector.
120 tokens.push_back(str.substr(lastPos, pos - lastPos));
121 // Skip delimiters. Note the "not_of"
122 lastPos = str.find_first_not_of(delimiters, pos);
123 // Find next "non-delimiter"
124 pos = str.find_first_of(delimiters, lastPos);
128 long Skini :: parseString( std::string& line, Message& message )
130 message.type = 0;
131 if ( line.empty() ) return message.type;
133 // Check for comment lines.
134 std::string::size_type lastPos = line.find_first_not_of(" ,\t", 0);
135 std::string::size_type pos = line.find_first_of("/", lastPos);
136 if ( std::string::npos != pos ) {
137 // errorString_ << "// Comment Line: " << line;
138 // handleError( StkError::STATUS );
139 return message.type;
142 // Tokenize the string.
143 std::vector<std::string> tokens;
144 this->tokenize( line, tokens, " ,\t");
146 // Valid SKINI messages must have at least three fields (type, time,
147 // and channel).
148 if ( tokens.size() < 3 ) return message.type;
150 // Determine message type.
151 int iSkini = 0;
152 while ( iSkini < __SK_MaxMsgTypes_ ) {
153 if ( tokens[0] == skini_msgs[iSkini].messageString ) break;
154 iSkini++;
157 if ( iSkini >= __SK_MaxMsgTypes_ ) {
158 // errorString_ << "Skini::parseString: couldn't parse this line:\n " << line;
159 // handleError( StkError::WARNING );
160 return message.type;
163 // Found the type.
164 message.type = skini_msgs[iSkini].type;
166 // Parse time field.
167 if ( tokens[1][0] == '=' ) {
168 tokens[1].erase( tokens[1].begin() );
169 if ( tokens[1].empty() ) {
170 // errorString_ << "Skini::parseString: couldn't parse time field in line:\n " << line;
171 // handleError( StkError::WARNING );
172 return message.type = 0;
174 message.time = (float) -atof( tokens[1].c_str() );
176 else
177 message.time = (float) atof( tokens[1].c_str() );
179 // Parse the channel field.
180 message.channel = atoi( tokens[2].c_str() );
182 // Parse the remaining fields (maximum of 2 more).
183 int iValue = 0;
184 long dataType = skini_msgs[iSkini].data2;
185 while ( dataType != NOPE ) {
187 if ( tokens.size() <= (unsigned int) (iValue+3) ) {
188 // errorString_ << "Skini::parseString: inconsistency between type table and parsed line:\n " << line;
189 // handleError( StkError::WARNING );
190 return message.type = 0;
193 switch ( dataType ) {
195 case SK_INT:
196 message.intValues[iValue] = atoi( tokens[iValue+3].c_str() );
197 message.floatValues[iValue] = (float) message.intValues[iValue];
198 break;
200 case SK_DBL:
201 message.floatValues[iValue] = atof( tokens[iValue+3].c_str() );
202 message.intValues[iValue] = (long) message.floatValues[iValue];
203 break;
205 case SK_STR: // Must be the last field.
206 message.remainder = tokens[iValue+3];
207 return message.type;
210 if ( ++iValue == 1 )
211 dataType = skini_msgs[iSkini].data3;
212 else
213 dataType = NOPE;
216 return message.type;
219 std::string Skini :: whatsThisType(long type)
221 std::string typeString;
223 for ( int i=0; i<__SK_MaxMsgTypes_; i++ ) {
224 if ( type == skini_msgs[i].type ) {
225 typeString = skini_msgs[i].messageString;
226 break;
229 return typeString;
232 std::string Skini :: whatsThisController( long number )
234 std::string controller;
236 for ( int i=0; i<__SK_MaxMsgTypes_; i++) {
237 if ( skini_msgs[i].type == __SK_ControlChange_ &&
238 number == skini_msgs[i].data2) {
239 controller = skini_msgs[i].messageString;
240 break;
243 return controller;
247 struct SkiniSpec skini_msgs[__SK_MaxMsgTypes_] =
249 {"NoteOff" , __SK_NoteOff_, SK_DBL, SK_DBL},
250 {"NoteOn" , __SK_NoteOn_, SK_DBL, SK_DBL},
251 {"PolyPressure" , __SK_PolyPressure_, SK_DBL, SK_DBL},
252 {"ControlChange" , __SK_ControlChange_, SK_INT, SK_DBL},
253 {"ProgramChange" , __SK_ProgramChange_, SK_DBL, NOPE},
254 {"AfterTouch" , __SK_AfterTouch_, SK_DBL, NOPE},
255 {"ChannelPressure" ,__SK_ChannelPressure_, SK_DBL, NOPE},
256 {"PitchWheel" , __SK_PitchWheel_, SK_DBL, NOPE},
257 {"PitchBend" , __SK_PitchBend_, SK_DBL, NOPE},
258 {"PitchChange" , __SK_PitchChange_, SK_DBL, NOPE},
260 {"Clock" , __SK_Clock_, NOPE, NOPE},
261 {"Undefined" , 249, NOPE, NOPE},
262 {"SongStart" , __SK_SongStart_, NOPE, NOPE},
263 {"Continue" , __SK_Continue_, NOPE, NOPE},
264 {"SongStop" , __SK_SongStop_, NOPE, NOPE},
265 {"Undefined" , 253, NOPE, NOPE},
266 {"ActiveSensing" , __SK_ActiveSensing_, NOPE, NOPE},
267 {"SystemReset" , __SK_SystemReset_, NOPE, NOPE},
269 {"Volume" , __SK_ControlChange_, __SK_Volume_ , SK_DBL},
270 {"ModWheel" , __SK_ControlChange_, __SK_ModWheel_ , SK_DBL},
271 {"Modulation" , __SK_ControlChange_, __SK_Modulation_ , SK_DBL},
272 {"Breath" , __SK_ControlChange_, __SK_Breath_ , SK_DBL},
273 {"FootControl" , __SK_ControlChange_, __SK_FootControl_ , SK_DBL},
274 {"Portamento" , __SK_ControlChange_, __SK_Portamento_ , SK_DBL},
275 {"Balance" , __SK_ControlChange_, __SK_Balance_ , SK_DBL},
276 {"Pan" , __SK_ControlChange_, __SK_Pan_ , SK_DBL},
277 {"Sustain" , __SK_ControlChange_, __SK_Sustain_ , SK_DBL},
278 {"Damper" , __SK_ControlChange_, __SK_Damper_ , SK_DBL},
279 {"Expression" , __SK_ControlChange_, __SK_Expression_ , SK_DBL},
281 {"NoiseLevel" , __SK_ControlChange_, __SK_NoiseLevel_ , SK_DBL},
282 {"PickPosition" , __SK_ControlChange_, __SK_PickPosition_ , SK_DBL},
283 {"StringDamping" , __SK_ControlChange_, __SK_StringDamping_ , SK_DBL},
284 {"StringDetune" , __SK_ControlChange_, __SK_StringDetune_ , SK_DBL},
285 {"BodySize" , __SK_ControlChange_, __SK_BodySize_ , SK_DBL},
286 {"BowPressure" , __SK_ControlChange_, __SK_BowPressure_ , SK_DBL},
287 {"BowPosition" , __SK_ControlChange_, __SK_BowPosition_ , SK_DBL},
288 {"BowBeta" , __SK_ControlChange_, __SK_BowBeta_ , SK_DBL},
290 {"ReedStiffness" , __SK_ControlChange_, __SK_ReedStiffness_ , SK_DBL},
291 {"ReedRestPos" , __SK_ControlChange_, __SK_ReedRestPos_ , SK_DBL},
292 {"FluteEmbouchure" , __SK_ControlChange_, __SK_FluteEmbouchure_ , SK_DBL},
293 {"LipTension" , __SK_ControlChange_, __SK_LipTension_ , SK_DBL},
294 {"StrikePosition" , __SK_ControlChange_, __SK_StrikePosition_ , SK_DBL},
295 {"StickHardness" , __SK_ControlChange_, __SK_StickHardness_ , SK_DBL},
297 {"TrillDepth" , __SK_ControlChange_, __SK_TrillDepth_ , SK_DBL},
298 {"TrillSpeed" , __SK_ControlChange_, __SK_TrillSpeed_ , SK_DBL},
300 {"Strumming" , __SK_ControlChange_, __SK_Strumming_ , 127 },
301 {"NotStrumming" , __SK_ControlChange_, __SK_Strumming_ , 0 },
303 {"PlayerSkill" , __SK_ControlChange_, __SK_PlayerSkill_ , SK_DBL},
305 {"Chord" , __SK_Chord_ , SK_DBL, SK_STR},
306 {"ChordOff" , __SK_ChordOff_ , SK_DBL, NOPE},
308 {"ShakerInst" , __SK_ControlChange_, __SK_ShakerInst_ , SK_DBL},
309 {"Maraca" , __SK_ControlChange_, __SK_ShakerInst_ , 0 },
310 {"Sekere" , __SK_ControlChange_, __SK_ShakerInst_ , 1 },
311 {"Cabasa" , __SK_ControlChange_, __SK_ShakerInst_ , 2 },
312 {"Bamboo" , __SK_ControlChange_, __SK_ShakerInst_ , 3 },
313 {"Waterdrp" , __SK_ControlChange_, __SK_ShakerInst_ , 4 },
314 {"Tambourn" , __SK_ControlChange_, __SK_ShakerInst_ , 5 },
315 {"Sleighbl" , __SK_ControlChange_, __SK_ShakerInst_ , 6 },
316 {"Guiro" , __SK_ControlChange_, __SK_ShakerInst_ , 7 },
318 {"OpenFile" , 256, SK_STR, NOPE},
319 {"SetPath" , 257, SK_STR, NOPE},
321 {"FilePath" , __SK_SINGER_FilePath_ , SK_STR, NOPE},
322 {"Frequency" , __SK_SINGER_Frequency_ , SK_STR, NOPE},
323 {"NoteName" , __SK_SINGER_NoteName_ , SK_STR, NOPE},
324 {"VocalShape" , __SK_SINGER_Shape_ , SK_STR, NOPE},
325 {"Glottis" , __SK_SINGER_Glot_ , SK_STR, NOPE},
326 {"VoicedUnVoiced" , __SK_SINGER_VoicedUnVoiced_, SK_DBL, SK_STR},
327 {"Synthesize" , __SK_SINGER_Synthesize_ , SK_STR, NOPE},
328 {"Silence" , __SK_SINGER_Silence_ , SK_STR, NOPE},
329 {"RndVibAmt" , __SK_SINGER_RndVibAmt_ , SK_STR, NOPE},
330 {"VibratoAmt" , __SK_ControlChange_ ,__SK_SINGER_VibratoAmt_,SK_DBL},
331 {"VibFreq" , __SK_ControlChange_ ,__SK_SINGER_VibFreq_ ,SK_DBL}
333 // end of skini.tbl