1 /* 2 * Copyright 2003-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jérôme Leveque 7 * Matthijs Hollemans 8 * Jérôme Duval 9 */ 10 11 #include <MidiRoster.h> 12 #include <MidiConsumer.h> 13 #include <FindDirectory.h> 14 #include <Path.h> 15 #include <string.h> 16 #include <stdlib.h> 17 18 #include "debug.h" 19 #include "MidiGlue.h" // for MAKE_BIGTIME 20 #include "SoftSynth.h" 21 22 using namespace BPrivate; 23 24 25 BSoftSynth::BSoftSynth() 26 : fSynth(NULL), 27 fSettings(NULL), 28 fSoundPlayer(NULL) 29 { 30 fInstrumentsFile = NULL; 31 SetDefaultInstrumentsFile(); 32 33 fSampleRate = 44100; 34 fInterpMode = B_LINEAR_INTERPOLATION; 35 fMaxVoices = 256; 36 fLimiterThreshold = 7; 37 fReverbEnabled = true; 38 fReverbMode = B_REVERB_BALLROOM; 39 } 40 41 42 BSoftSynth::~BSoftSynth() 43 { 44 // Note: it is possible that we don't get deleted. When BSynth is 45 // created, it is assigned to the global variable be_synth. While 46 // BSynth is alive, it keeps a copy of BSoftSynth around too. Not 47 // a big deal, but the Midi Kit will complain (on stdout) that we 48 // didn't release our endpoints. 49 50 Unload(); 51 } 52 53 54 bool 55 BSoftSynth::InitCheck() 56 { 57 if (!fSynth) 58 _Init(); 59 return fInitCheck; 60 } 61 62 63 void 64 BSoftSynth::Unload(void) 65 { 66 _Done(); 67 free(fInstrumentsFile); 68 fInstrumentsFile = NULL; 69 } 70 71 72 bool 73 BSoftSynth::IsLoaded(void) const 74 { 75 return fInstrumentsFile != NULL; 76 } 77 78 79 status_t 80 BSoftSynth::SetDefaultInstrumentsFile() 81 { 82 BPath path; 83 if (B_OK == find_directory(B_SYNTH_DIRECTORY, &path, false, NULL)) { 84 path.Append(B_BIG_SYNTH_FILE); 85 return SetInstrumentsFile(path.Path()); 86 } 87 88 return B_ERROR; 89 } 90 91 92 status_t 93 BSoftSynth::SetInstrumentsFile(const char* path) 94 { 95 if (path == NULL) 96 return B_BAD_VALUE; 97 98 if (IsLoaded()) 99 Unload(); 100 101 fInstrumentsFile = strdup(path); 102 return B_OK; 103 } 104 105 106 status_t 107 BSoftSynth::LoadAllInstruments() 108 { 109 InitCheck(); 110 return B_OK; 111 } 112 113 114 status_t 115 BSoftSynth::LoadInstrument(int16 instrument) 116 { 117 UNIMPLEMENTED 118 return B_OK; 119 } 120 121 122 status_t 123 BSoftSynth::UnloadInstrument(int16 instrument) 124 { 125 UNIMPLEMENTED 126 return B_OK; 127 } 128 129 130 status_t 131 BSoftSynth::RemapInstrument(int16 from, int16 to) 132 { 133 UNIMPLEMENTED 134 return B_OK; 135 } 136 137 138 void 139 BSoftSynth::FlushInstrumentCache(bool startStopCache) 140 { 141 // TODO: we may decide not to support this function because it's weird! 142 143 UNIMPLEMENTED 144 } 145 146 147 void 148 BSoftSynth::SetVolume(double volume) 149 { 150 if (volume >= 0.0) { 151 fluid_synth_set_gain(fSynth, volume); 152 } 153 } 154 155 156 double 157 BSoftSynth::Volume(void) const 158 { 159 return fluid_synth_get_gain(fSynth); 160 } 161 162 163 status_t 164 BSoftSynth::SetSamplingRate(int32 rate) 165 { 166 if (rate == 22050 || rate == 44100 || rate == 48000) { 167 fSampleRate = rate; 168 return B_OK; 169 } 170 171 return B_BAD_VALUE; 172 } 173 174 175 int32 176 BSoftSynth::SamplingRate() const 177 { 178 return fSampleRate; 179 } 180 181 182 status_t 183 BSoftSynth::SetInterpolation(interpolation_mode mode) 184 { 185 // not used because our synth uses the same format than the soundplayer 186 fInterpMode = mode; 187 return B_OK; 188 } 189 190 191 interpolation_mode 192 BSoftSynth::Interpolation() const 193 { 194 return fInterpMode; 195 } 196 197 198 status_t 199 BSoftSynth::EnableReverb(bool enabled) 200 { 201 fReverbEnabled = enabled; 202 fluid_synth_set_reverb_on(fSynth, enabled); 203 return B_OK; 204 } 205 206 207 bool 208 BSoftSynth::IsReverbEnabled() const 209 { 210 return fReverbEnabled; 211 } 212 213 214 void 215 BSoftSynth::SetReverb(reverb_mode mode) 216 { 217 // TODO: this function could change depending on the synth back-end. 218 219 fReverbMode = mode; 220 } 221 222 223 reverb_mode 224 BSoftSynth::Reverb() const 225 { 226 return fReverbMode; 227 } 228 229 230 status_t 231 BSoftSynth::SetMaxVoices(int32 max) 232 { 233 if (max > 0 && max <= 4096) { 234 fMaxVoices = max; 235 return B_OK; 236 } 237 238 return B_BAD_VALUE; 239 } 240 241 242 int16 243 BSoftSynth::MaxVoices(void) const 244 { 245 return fMaxVoices; 246 } 247 248 249 status_t 250 BSoftSynth::SetLimiterThreshold(int32 threshold) 251 { 252 // not used 253 if (threshold > 0 && threshold <= 32) { 254 fLimiterThreshold = threshold; 255 return B_OK; 256 } 257 258 return B_BAD_VALUE; 259 } 260 261 262 int16 263 BSoftSynth::LimiterThreshold(void) const 264 { 265 return fLimiterThreshold; 266 } 267 268 269 void 270 BSoftSynth::Pause(void) 271 { 272 UNIMPLEMENTED 273 } 274 275 276 void 277 BSoftSynth::Resume(void) 278 { 279 UNIMPLEMENTED 280 } 281 282 283 void 284 BSoftSynth::NoteOff( 285 uchar channel, uchar note, uchar velocity, uint32 time) 286 { 287 if (InitCheck()) { 288 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 289 fluid_synth_noteoff(fSynth, channel - 1, note); // velocity isn't used in FS 290 } 291 } 292 293 294 void 295 BSoftSynth::NoteOn( 296 uchar channel, uchar note, uchar velocity, uint32 time) 297 { 298 if (InitCheck()) { 299 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 300 fluid_synth_noteon(fSynth, channel - 1, note, velocity); 301 } 302 } 303 304 305 void 306 BSoftSynth::KeyPressure( 307 uchar channel, uchar note, uchar pressure, uint32 time) 308 { 309 if (InitCheck()) { 310 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 311 // unavailable 312 } 313 } 314 315 316 void 317 BSoftSynth::ControlChange( 318 uchar channel, uchar controlNumber, uchar controlValue, uint32 time) 319 { 320 if (InitCheck()) { 321 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 322 fluid_synth_cc(fSynth, channel - 1, controlNumber, controlValue); 323 } 324 } 325 326 327 void 328 BSoftSynth::ProgramChange( 329 uchar channel, uchar programNumber, uint32 time) 330 { 331 if (InitCheck()) { 332 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 333 fluid_synth_program_change(fSynth, channel - 1, programNumber); 334 } 335 } 336 337 338 void 339 BSoftSynth::ChannelPressure(uchar channel, uchar pressure, uint32 time) 340 { 341 if (InitCheck()) { 342 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 343 //unavailable 344 } 345 } 346 347 348 void 349 BSoftSynth::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) 350 { 351 if (InitCheck()) { 352 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 353 // fluid_synth only accepts an int 354 fluid_synth_pitch_bend(fSynth, channel - 1, ((uint32)(msb & 0x7f) << 8) | (lsb & 0x7f)); 355 } 356 } 357 358 359 void 360 BSoftSynth::SystemExclusive(void* data, size_t length, uint32 time) 361 { 362 if (InitCheck()) { 363 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 364 // unsupported 365 } 366 } 367 368 369 void 370 BSoftSynth::SystemCommon( 371 uchar status, uchar data1, uchar data2, uint32 time) 372 { 373 if (InitCheck()) { 374 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 375 // unsupported 376 } 377 } 378 379 380 void 381 BSoftSynth::SystemRealTime(uchar status, uint32 time) 382 { 383 if (InitCheck()) { 384 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 385 // unsupported 386 } 387 } 388 389 390 void 391 BSoftSynth::TempoChange(int32 beatsPerMinute, uint32 time) 392 { 393 if (InitCheck()) { 394 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 395 // unsupported 396 } 397 } 398 399 400 void 401 BSoftSynth::AllNotesOff(bool justChannel, uint32 time) 402 { 403 if (InitCheck()) { 404 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE); 405 406 // from BMidi::AllNotesOff 407 for (uchar channel = 1; channel <= 16; ++channel) { 408 fluid_synth_cc(fSynth, channel - 1, B_ALL_NOTES_OFF, 0); 409 410 if (!justChannel) { 411 for (uchar note = 0; note <= 0x7F; ++note) { 412 fluid_synth_noteoff(fSynth, channel - 1, note); 413 } 414 } 415 } 416 } 417 } 418 419 420 void 421 BSoftSynth::_Init() 422 { 423 status_t err; 424 fInitCheck = false; 425 426 _Done(); 427 428 fSettings = new_fluid_settings(); 429 fluid_settings_setnum(fSettings, "synth.sample-rate", fSampleRate); 430 fluid_settings_setint(fSettings, "synth.polyphony", fMaxVoices); 431 432 fSynth = new_fluid_synth(fSettings); 433 if (!fSynth) 434 return; 435 436 err = fluid_synth_sfload(fSynth, fInstrumentsFile, 1); 437 if (err < B_OK) 438 return; 439 440 media_raw_audio_format format = media_raw_audio_format::wildcard; 441 format.channel_count = 2; 442 format.frame_rate = fSampleRate; 443 format.format = media_raw_audio_format::B_AUDIO_FLOAT; 444 445 fSoundPlayer = new BSoundPlayer(&format, "Soft Synth", &PlayBuffer, NULL, this); 446 err = fSoundPlayer->InitCheck(); 447 if (err != B_OK) 448 return; 449 450 fSoundPlayer->SetHasData(true); 451 fSoundPlayer->Start(); 452 453 fInitCheck = true; 454 } 455 456 457 void 458 BSoftSynth::_Done() 459 { 460 if (fSoundPlayer) { 461 fSoundPlayer->SetHasData(false); 462 fSoundPlayer->Stop(); 463 delete fSoundPlayer; 464 fSoundPlayer = NULL; 465 } 466 if (fSynth) { 467 delete_fluid_synth(fSynth); 468 fSynth = NULL; 469 } 470 if (fSettings) { 471 delete_fluid_settings(fSettings); 472 fSettings = NULL; 473 } 474 } 475 476 477 void 478 BSoftSynth::PlayBuffer(void * cookie, void * data, size_t size, const media_raw_audio_format & format) 479 { 480 BSoftSynth *synth = (BSoftSynth *)cookie; 481 482 // we use float samples 483 484 if (synth->fSynth) 485 fluid_synth_write_float(synth->fSynth, size / sizeof(float) / format.channel_count, 486 data, 0, format.channel_count, 487 data, 1, format.channel_count); 488 } 489 490