1 /* 2 * Copyright (c) 2004-2005 Matthijs Hollemans 3 * Copyright (c) 2003 Jerome Leveque 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include <MidiRoster.h> 25 #include <MidiConsumer.h> 26 #include <MidiProducer.h> 27 #include <FindDirectory.h> 28 #include <Path.h> 29 #include <string.h> 30 #include <stdlib.h> 31 32 #include "debug.h" 33 #include "MidiGlue.h" // for MAKE_BIGTIME 34 #include "SoftSynth.h" 35 36 using namespace BPrivate; 37 38 //------------------------------------------------------------------------------ 39 40 BSoftSynth::BSoftSynth() 41 { 42 instrumentsFile = NULL; 43 SetDefaultInstrumentsFile(); 44 45 sampleRate = 22050; 46 interpMode = B_LINEAR_INTERPOLATION; 47 maxVoices = 28; 48 limiterThreshold = 7; 49 reverbEnabled = true; 50 reverbMode = B_REVERB_BALLROOM; 51 volumeScale = 1.0; 52 53 Init(); 54 } 55 56 //------------------------------------------------------------------------------ 57 58 BSoftSynth::~BSoftSynth() 59 { 60 // Note: it is possible that we don't get deleted. When BSynth is 61 // created, it is assigned to the global variable be_synth. While 62 // BSynth is alive, it keeps a copy of BSoftSynth around too. Not 63 // a big deal, but the Midi Kit will complain (on stdout) that we 64 // didn't release our endpoints. 65 66 Unload(); 67 Done(); 68 } 69 70 //------------------------------------------------------------------------------ 71 72 bool BSoftSynth::InitCheck(void) const 73 { 74 return initCheck; 75 } 76 77 //------------------------------------------------------------------------------ 78 79 void BSoftSynth::Unload(void) 80 { 81 /* TODO: purge samples from memory */ 82 83 free(instrumentsFile); 84 instrumentsFile = NULL; 85 } 86 87 //------------------------------------------------------------------------------ 88 89 bool BSoftSynth::IsLoaded(void) const 90 { 91 return instrumentsFile != NULL; 92 } 93 94 //------------------------------------------------------------------------------ 95 96 status_t BSoftSynth::SetDefaultInstrumentsFile() 97 { 98 BPath path; 99 if (B_OK == find_directory(B_SYNTH_DIRECTORY, &path, false, NULL)) 100 { 101 path.Append(B_BIG_SYNTH_FILE); 102 return SetInstrumentsFile(path.Path()); 103 } 104 105 return B_ERROR; 106 } 107 108 //------------------------------------------------------------------------------ 109 110 status_t BSoftSynth::SetInstrumentsFile(const char* path) 111 { 112 if (path == NULL) 113 return B_BAD_VALUE; 114 115 if (IsLoaded()) 116 Unload(); 117 118 instrumentsFile = strdup(path); 119 return B_OK; 120 } 121 122 //------------------------------------------------------------------------------ 123 124 status_t BSoftSynth::LoadAllInstruments() 125 { 126 /* TODO: Should load all of the instruments from the sample bank. */ 127 128 UNIMPLEMENTED 129 return B_OK; 130 } 131 132 //------------------------------------------------------------------------------ 133 134 status_t BSoftSynth::LoadInstrument(int16 instrument) 135 { 136 UNIMPLEMENTED 137 return B_OK; 138 } 139 140 //------------------------------------------------------------------------------ 141 142 status_t BSoftSynth::UnloadInstrument(int16 instrument) 143 { 144 UNIMPLEMENTED 145 return B_OK; 146 } 147 148 //------------------------------------------------------------------------------ 149 150 status_t BSoftSynth::RemapInstrument(int16 from, int16 to) 151 { 152 UNIMPLEMENTED 153 return B_OK; 154 } 155 156 //------------------------------------------------------------------------------ 157 158 void BSoftSynth::FlushInstrumentCache(bool startStopCache) 159 { 160 // TODO: we may decide not to support this function because it's weird! 161 162 UNIMPLEMENTED 163 } 164 165 //------------------------------------------------------------------------------ 166 167 void BSoftSynth::SetVolume(double volume) 168 { 169 if (volume >= 0.0) 170 { 171 volumeScale = volume; 172 } 173 } 174 175 //------------------------------------------------------------------------------ 176 177 double BSoftSynth::Volume(void) const 178 { 179 return volumeScale; 180 } 181 182 //------------------------------------------------------------------------------ 183 184 status_t BSoftSynth::SetSamplingRate(int32 rate) 185 { 186 // TODO: According to the BeBook, we should round rate to the nearest 187 // acceptable value. However, this function may change depending on the 188 // softsynth back-end we'll use. 189 190 if (rate == 11025 || rate == 22050 || rate == 44100) 191 { 192 sampleRate = rate; 193 return B_OK; 194 } 195 196 return B_BAD_VALUE; 197 } 198 199 //------------------------------------------------------------------------------ 200 201 int32 BSoftSynth::SamplingRate() const 202 { 203 return sampleRate; 204 } 205 206 //------------------------------------------------------------------------------ 207 208 status_t BSoftSynth::SetInterpolation(interpolation_mode mode) 209 { 210 // TODO: this function could change depending on the synth back-end. 211 212 interpMode = mode; 213 return B_OK; 214 } 215 216 //------------------------------------------------------------------------------ 217 218 interpolation_mode BSoftSynth::Interpolation() const 219 { 220 return interpMode; 221 } 222 223 //------------------------------------------------------------------------------ 224 225 status_t BSoftSynth::EnableReverb(bool enabled) 226 { 227 reverbEnabled = enabled; 228 return B_OK; 229 } 230 231 //------------------------------------------------------------------------------ 232 233 bool BSoftSynth::IsReverbEnabled() const 234 { 235 return reverbEnabled; 236 } 237 238 //------------------------------------------------------------------------------ 239 240 void BSoftSynth::SetReverb(reverb_mode mode) 241 { 242 // TODO: this function could change depending on the synth back-end. 243 244 reverbMode = mode; 245 } 246 247 //------------------------------------------------------------------------------ 248 249 reverb_mode BSoftSynth::Reverb() const 250 { 251 return reverbMode; 252 } 253 254 //------------------------------------------------------------------------------ 255 256 status_t BSoftSynth::SetMaxVoices(int32 max) 257 { 258 // TODO: this function could change depending on the synth back-end. 259 260 if (max > 0 && max <= 32) 261 { 262 maxVoices = max; 263 return B_OK; 264 } 265 266 return B_BAD_VALUE; 267 } 268 269 //------------------------------------------------------------------------------ 270 271 int16 BSoftSynth::MaxVoices(void) const 272 { 273 return maxVoices; 274 } 275 276 //------------------------------------------------------------------------------ 277 278 status_t BSoftSynth::SetLimiterThreshold(int32 threshold) 279 { 280 // TODO: this function could change depending on the synth back-end. 281 282 if (threshold > 0 && threshold <= 32) 283 { 284 limiterThreshold = threshold; 285 return B_OK; 286 } 287 288 return B_BAD_VALUE; 289 } 290 291 //------------------------------------------------------------------------------ 292 293 int16 BSoftSynth::LimiterThreshold(void) const 294 { 295 return limiterThreshold; 296 } 297 298 //------------------------------------------------------------------------------ 299 300 void BSoftSynth::Pause(void) 301 { 302 UNIMPLEMENTED 303 } 304 305 //------------------------------------------------------------------------------ 306 307 void BSoftSynth::Resume(void) 308 { 309 UNIMPLEMENTED 310 } 311 312 //------------------------------------------------------------------------------ 313 314 void BSoftSynth::NoteOff( 315 uchar channel, uchar note, uchar velocity, uint32 time) 316 { 317 if (InitCheck()) 318 { 319 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 320 producer->SprayNoteOff( 321 channel - 1, note, velocity, MAKE_BIGTIME(time)); 322 } 323 } 324 325 //------------------------------------------------------------------------------ 326 327 void BSoftSynth::NoteOn( 328 uchar channel, uchar note, uchar velocity, uint32 time) 329 { 330 if (InitCheck()) 331 { 332 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 333 producer->SprayNoteOn(channel - 1, note, velocity, MAKE_BIGTIME(time)); 334 } 335 } 336 337 //------------------------------------------------------------------------------ 338 339 void BSoftSynth::KeyPressure( 340 uchar channel, uchar note, uchar pressure, uint32 time) 341 { 342 if (InitCheck()) 343 { 344 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 345 producer->SprayKeyPressure( 346 channel - 1, note, pressure, MAKE_BIGTIME(time)); 347 } 348 } 349 350 //------------------------------------------------------------------------------ 351 352 void BSoftSynth::ControlChange( 353 uchar channel, uchar controlNumber, uchar controlValue, uint32 time) 354 { 355 if (InitCheck()) 356 { 357 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 358 producer->SprayControlChange( 359 channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time)); 360 } 361 } 362 363 //------------------------------------------------------------------------------ 364 365 void BSoftSynth::ProgramChange( 366 uchar channel, uchar programNumber, uint32 time) 367 { 368 if (InitCheck()) 369 { 370 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 371 producer->SprayProgramChange( 372 channel - 1, programNumber, MAKE_BIGTIME(time)); 373 } 374 } 375 376 //------------------------------------------------------------------------------ 377 378 void BSoftSynth::ChannelPressure(uchar channel, uchar pressure, uint32 time) 379 { 380 if (InitCheck()) 381 { 382 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 383 producer->SprayChannelPressure( 384 channel - 1, pressure, MAKE_BIGTIME(time)); 385 } 386 } 387 388 //------------------------------------------------------------------------------ 389 390 void BSoftSynth::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) 391 { 392 if (InitCheck()) 393 { 394 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 395 producer->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time)); 396 } 397 } 398 399 //------------------------------------------------------------------------------ 400 401 void BSoftSynth::SystemExclusive(void* data, size_t length, uint32 time) 402 { 403 if (InitCheck()) 404 { 405 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 406 producer->SpraySystemExclusive(data, length, MAKE_BIGTIME(time)); 407 } 408 } 409 410 //------------------------------------------------------------------------------ 411 412 void BSoftSynth::SystemCommon( 413 uchar status, uchar data1, uchar data2, uint32 time) 414 { 415 if (InitCheck()) 416 { 417 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 418 producer->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time)); 419 } 420 } 421 422 //------------------------------------------------------------------------------ 423 424 void BSoftSynth::SystemRealTime(uchar status, uint32 time) 425 { 426 if (InitCheck()) 427 { 428 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 429 producer->SpraySystemRealTime(status, MAKE_BIGTIME(time)); 430 } 431 } 432 433 //------------------------------------------------------------------------------ 434 435 void BSoftSynth::TempoChange(int32 beatsPerMinute, uint32 time) 436 { 437 if (InitCheck()) 438 { 439 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 440 producer->SprayTempoChange(beatsPerMinute, MAKE_BIGTIME(time)); 441 } 442 } 443 444 //------------------------------------------------------------------------------ 445 446 void BSoftSynth::AllNotesOff(bool justChannel, uint32 time) 447 { 448 if (InitCheck()) 449 { 450 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 451 452 // from BMidi::AllNotesOff 453 for (uchar channel = 1; channel <= 16; ++channel) 454 { 455 producer->SprayControlChange(channel, B_ALL_NOTES_OFF, 0, time); 456 457 if (!justChannel) 458 { 459 for (uchar note = 0; note <= 0x7F; ++note) 460 { 461 producer->SprayNoteOff(channel, note, 0, time); 462 } 463 } 464 } 465 } 466 } 467 468 //------------------------------------------------------------------------------ 469 470 void BSoftSynth::Init() 471 { 472 initCheck = false; 473 474 producer = new BMidiLocalProducer("TiMidity feeder"); 475 476 int32 id = 0; 477 while ((consumer = BMidiRoster::NextConsumer(&id)) != NULL) 478 { 479 if (strcmp(consumer->Name(), "TiMidity input") == 0) 480 break; 481 482 consumer->Release(); 483 } 484 485 if (consumer == NULL) 486 { 487 fprintf(stderr, "[midi] TiMidity consumer not found\n"); 488 return; 489 } 490 491 if (producer->Connect(consumer) != B_OK) 492 { 493 fprintf(stderr, "[midi] Could not connect to TiMidity\n"); 494 return; 495 } 496 497 initCheck = true; 498 } 499 500 //------------------------------------------------------------------------------ 501 502 void BSoftSynth::Done() 503 { 504 if (consumer != NULL) 505 { 506 producer->Disconnect(consumer); 507 consumer->Release(); 508 consumer = NULL; 509 } 510 511 producer->Release(); 512 producer = NULL; 513 } 514 515 //------------------------------------------------------------------------------ 516