tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / midi / SoftSynth.cpp
blob905aa3dd2f87b34647445aad80d52e078a4a2ed4
1 /*
2 * Copyright 2006-2014, Haiku.
4 * Copyright (c) 2004-2005 Matthijs Hollemans
5 * Copyright (c) 2003 Jerome Leveque
6 * Distributed under the terms of the MIT License.
8 * Authors:
9 * Jérôme Duval
10 * Jérôme Leveque
11 * Matthijs Hollemans
12 * Pete Goodeve
15 #include <MidiRoster.h>
16 #include <MidiConsumer.h>
17 #include <File.h>
18 #include <FindDirectory.h>
19 #include <Path.h>
20 #include <string.h>
21 #include <stdlib.h>
23 #include "debug.h"
24 #include "MidiGlue.h" // for MAKE_BIGTIME
25 #include "SoftSynth.h"
27 using namespace BPrivate;
29 struct ReverbSettings {
30 double room, damp, width, level;
31 } gReverbSettings[] = {
32 {0.0, 0.0, 0.0, 0.0}, // B_REVERB_NONE
33 {0.2, 0.0, 0.5, 0.9}, // B_REVERB_CLOSET
34 {0.5, 0.0, 0.9, 0.9}, // B_REVERB_GARAGE
35 {0.7, 0.25, 0.9, 0.95}, // B_REVERB_BALLROOM
36 {0.99, 0.3, 1.0, 1.0}, // B_REVERB_CAVERN
37 {1.03, 0.6, 1.0, 1.0} // B_REVERB_DUNGEON
41 BSoftSynth::BSoftSynth()
42 : fInitCheck(false),
43 fSynth(NULL),
44 fSettings(NULL),
45 fSoundPlayer(NULL),
46 fMonitor(NULL),
47 fMonitorSize(0),
48 fMonitorChans(-1)
50 fInstrumentsFile = NULL;
51 SetDefaultInstrumentsFile();
53 fSampleRate = 44100;
54 fInterpMode = B_LINEAR_INTERPOLATION;
55 fMaxVoices = 256;
56 fLimiterThreshold = 7;
57 fReverbEnabled = true;
58 fReverbMode = B_REVERB_BALLROOM;
62 BSoftSynth::~BSoftSynth()
64 // Note: it is possible that we don't get deleted. When BSynth is
65 // created, it is assigned to the global variable be_synth. While
66 // BSynth is alive, it keeps a copy of BSoftSynth around too. Not
67 // a big deal, but the Midi Kit will complain (on stdout) that we
68 // didn't release our endpoints.
70 delete[] fMonitor;
71 Unload();
75 bool
76 BSoftSynth::InitCheck()
78 if (!fSynth)
79 _Init();
80 return fInitCheck;
84 void
85 BSoftSynth::Unload(void)
87 _Done();
88 free(fInstrumentsFile);
89 fInstrumentsFile = NULL;
93 bool
94 BSoftSynth::IsLoaded(void) const
96 return fInstrumentsFile != NULL;
100 status_t
101 BSoftSynth::SetDefaultInstrumentsFile()
103 // We first search for a setting file (or symlink to it)
104 // in the user settings directory
105 char buffer[512];
106 BPath path;
107 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
108 path.Append("midi");
109 BFile file(path.Path(), B_READ_ONLY);
110 if (file.InitCheck() == B_OK
111 && file.Read(buffer, sizeof(buffer)) > 0) {
112 char soundFont[512];
113 sscanf(buffer, "# Midi Settings\n soundfont = %s\n",
114 soundFont);
115 return SetInstrumentsFile(soundFont);
119 // TODO: Use the first soundfont found in the synth directory
120 // instead of hardcoding
121 if (find_directory(B_SYNTH_DIRECTORY, &path, false, NULL) == B_OK) {
122 path.Append("TimGM6mb.sf2");
123 return SetInstrumentsFile(path.Path());
126 // TODO: Write the settings file
128 return B_ERROR;
132 status_t
133 BSoftSynth::SetInstrumentsFile(const char* path)
135 if (path == NULL)
136 return B_BAD_VALUE;
138 if (!BEntry(path).Exists())
139 return B_FILE_NOT_FOUND;
141 if (IsLoaded())
142 Unload();
144 fInstrumentsFile = strdup(path);
145 return B_OK;
149 status_t
150 BSoftSynth::LoadAllInstruments()
152 InitCheck();
153 return B_OK;
157 status_t
158 BSoftSynth::LoadInstrument(int16 instrument)
160 UNIMPLEMENTED
161 return B_OK;
165 status_t
166 BSoftSynth::UnloadInstrument(int16 instrument)
168 UNIMPLEMENTED
169 return B_OK;
173 status_t
174 BSoftSynth::RemapInstrument(int16 from, int16 to)
176 UNIMPLEMENTED
177 return B_OK;
181 void
182 BSoftSynth::FlushInstrumentCache(bool startStopCache)
184 // TODO: we may decide not to support this function because it's weird!
186 UNIMPLEMENTED
190 void
191 BSoftSynth::SetVolume(double volume)
193 if (InitCheck())
194 if (volume >= 0.0) {
195 fluid_synth_set_gain(fSynth, volume);
200 double
201 BSoftSynth::Volume(void) const
203 return fluid_synth_get_gain(fSynth);
207 status_t
208 BSoftSynth::SetSamplingRate(int32 rate)
210 if (rate == 22050 || rate == 44100 || rate == 48000) {
211 fSampleRate = rate;
212 return B_OK;
215 return B_BAD_VALUE;
219 int32
220 BSoftSynth::SamplingRate() const
222 return fSampleRate;
226 status_t
227 BSoftSynth::SetInterpolation(interpolation_mode mode)
229 // not used because our synth uses the same format than the soundplayer
230 fInterpMode = mode;
231 return B_OK;
235 interpolation_mode
236 BSoftSynth::Interpolation() const
238 return fInterpMode;
242 status_t
243 BSoftSynth::EnableReverb(bool enabled)
245 fReverbEnabled = enabled;
246 fluid_synth_set_reverb_on(fSynth, enabled);
247 return B_OK;
251 bool
252 BSoftSynth::IsReverbEnabled() const
254 return fReverbEnabled;
258 void
259 BSoftSynth::SetReverb(reverb_mode mode)
261 if (mode < B_REVERB_NONE || mode > B_REVERB_DUNGEON)
262 return;
264 fReverbMode = mode;
265 if (fSynth) {
266 // We access the table using "mode - 1" because B_REVERB_NONE == 1
267 ReverbSettings *rvb = &gReverbSettings[mode - 1];
268 fluid_synth_set_reverb(fSynth, rvb->room, rvb->damp, rvb->width,
269 rvb->level);
274 reverb_mode
275 BSoftSynth::Reverb() const
277 return fReverbMode;
281 status_t
282 BSoftSynth::SetMaxVoices(int32 max)
284 if (max > 0 && max <= 4096) {
285 fMaxVoices = max;
286 return B_OK;
289 return B_BAD_VALUE;
293 int16
294 BSoftSynth::MaxVoices(void) const
296 return fMaxVoices;
300 status_t
301 BSoftSynth::SetLimiterThreshold(int32 threshold)
303 // not used
304 if (threshold > 0 && threshold <= 32) {
305 fLimiterThreshold = threshold;
306 return B_OK;
309 return B_BAD_VALUE;
313 int16
314 BSoftSynth::LimiterThreshold(void) const
316 return fLimiterThreshold;
320 void
321 BSoftSynth::Pause(void)
323 UNIMPLEMENTED
327 void
328 BSoftSynth::Resume(void)
330 UNIMPLEMENTED
334 void
335 BSoftSynth::NoteOff(
336 uchar channel, uchar note, uchar velocity, uint32 time)
338 if (InitCheck()) {
339 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
340 fluid_synth_noteoff(fSynth, channel - 1, note); // velocity isn't used in FS
345 void
346 BSoftSynth::NoteOn(
347 uchar channel, uchar note, uchar velocity, uint32 time)
349 if (InitCheck()) {
350 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
351 fluid_synth_noteon(fSynth, channel - 1, note, velocity);
356 void
357 BSoftSynth::KeyPressure(
358 uchar channel, uchar note, uchar pressure, uint32 time)
360 if (InitCheck()) {
361 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
362 // unavailable
367 void
368 BSoftSynth::ControlChange(
369 uchar channel, uchar controlNumber, uchar controlValue, uint32 time)
371 if (InitCheck()) {
372 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
373 fluid_synth_cc(fSynth, channel - 1, controlNumber, controlValue);
378 void
379 BSoftSynth::ProgramChange(
380 uchar channel, uchar programNumber, uint32 time)
382 if (InitCheck()) {
383 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
384 fluid_synth_program_change(fSynth, channel - 1, programNumber);
389 void
390 BSoftSynth::ChannelPressure(uchar channel, uchar pressure, uint32 time)
392 if (InitCheck()) {
393 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
394 //unavailable
399 void
400 BSoftSynth::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
402 if (InitCheck()) {
403 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
404 // fluid_synth only accepts an int
405 fluid_synth_pitch_bend(fSynth, channel - 1,
406 ((uint32)(msb & 0x7f) << 7) | (lsb & 0x7f));
411 void
412 BSoftSynth::SystemExclusive(void* data, size_t length, uint32 time)
414 if (InitCheck()) {
415 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
416 // unsupported
421 void
422 BSoftSynth::SystemCommon(
423 uchar status, uchar data1, uchar data2, uint32 time)
425 if (InitCheck()) {
426 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
427 // unsupported
432 void
433 BSoftSynth::SystemRealTime(uchar status, uint32 time)
435 if (InitCheck()) {
436 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
437 // unsupported
442 void
443 BSoftSynth::TempoChange(int32 beatsPerMinute, uint32 time)
445 if (InitCheck()) {
446 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
447 // unsupported
452 void
453 BSoftSynth::AllNotesOff(bool justChannel, uint32 time)
455 if (InitCheck()) {
456 snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
458 // from BMidi::AllNotesOff
459 for (uchar channel = 1; channel <= 16; ++channel) {
460 fluid_synth_cc(fSynth, channel - 1, B_ALL_NOTES_OFF, 0);
462 if (!justChannel) {
463 for (uchar note = 0; note <= 0x7F; ++note) {
464 fluid_synth_noteoff(fSynth, channel - 1, note);
472 void
473 BSoftSynth::_Init()
475 status_t err;
476 fInitCheck = false;
478 _Done();
480 fSettings = new_fluid_settings();
481 fluid_settings_setnum(fSettings, (char*)"synth.sample-rate", fSampleRate);
482 fluid_settings_setint(fSettings, (char*)"synth.polyphony", fMaxVoices);
484 fSynth = new_fluid_synth(fSettings);
485 if (!fSynth)
486 return;
488 err = fluid_synth_sfload(fSynth, fInstrumentsFile, 1);
489 if (err < B_OK) {
490 fprintf(stderr, "error in fluid_synth_sfload\n");
491 return;
494 SetReverb(fReverbMode);
496 media_raw_audio_format format = media_raw_audio_format::wildcard;
497 format.channel_count = 2;
498 format.frame_rate = fSampleRate;
499 format.format = media_raw_audio_format::B_AUDIO_FLOAT;
501 fSoundPlayer = new BSoundPlayer(&format, "Soft Synth", &PlayBuffer, NULL, this);
502 err = fSoundPlayer->InitCheck();
503 if (err != B_OK) {
504 fprintf(stderr, "error in BSoundPlayer\n");
505 return;
508 fSoundPlayer->SetHasData(true);
509 fSoundPlayer->Start();
511 fInitCheck = true;
515 void
516 BSoftSynth::_Done()
518 if (fSoundPlayer) {
519 fSoundPlayer->SetHasData(false);
520 fSoundPlayer->Stop();
521 delete fSoundPlayer;
522 fSoundPlayer = NULL;
524 if (fSynth) {
525 delete_fluid_synth(fSynth);
526 fSynth = NULL;
528 if (fSettings) {
529 delete_fluid_settings(fSettings);
530 fSettings = NULL;
535 void
536 BSoftSynth::PlayBuffer(void* cookie, void* data, size_t size,
537 const media_raw_audio_format& format)
539 BSoftSynth* synth = (BSoftSynth*)cookie;
541 if (synth->fMonitorSize == 0) {
542 synth->fMonitor = (float*)new void*[size];
543 synth->fMonitorSize = size;
544 synth->fMonitorChans = format.channel_count;
547 // we use float samples
548 if (synth->fSynth) {
549 fluid_synth_write_float(
550 synth->fSynth, size / sizeof(float) / format.channel_count,
551 data, 0, format.channel_count,
552 data, 1, format.channel_count);
554 memcpy(synth->fMonitor, data, size);