an untested work in progress of BSoftSynth using fluidsynth (it's a try out and could be reverted if we feel like it)
libfluidsynth.so isn't on the image yet git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17844 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
SubDir HAIKU_TOP src kits midi ;
|
SubDir HAIKU_TOP src kits midi ;
|
||||||
|
|
||||||
UsePrivateHeaders midi ;
|
UsePrivateHeaders midi ;
|
||||||
|
UseLibraryHeaders fluidsynth ;
|
||||||
|
|
||||||
SharedLibrary libmidi.so :
|
SharedLibrary libmidi.so :
|
||||||
Midi.cpp
|
Midi.cpp
|
||||||
@@ -16,4 +17,6 @@ SharedLibrary libmidi.so :
|
|||||||
:
|
:
|
||||||
be
|
be
|
||||||
midi2
|
midi2
|
||||||
|
media
|
||||||
|
libfluidsynth.so
|
||||||
;
|
;
|
||||||
|
|||||||
+197
-217
@@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#include <MidiRoster.h>
|
#include <MidiRoster.h>
|
||||||
#include <MidiConsumer.h>
|
#include <MidiConsumer.h>
|
||||||
#include <MidiProducer.h>
|
|
||||||
#include <FindDirectory.h>
|
#include <FindDirectory.h>
|
||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -35,25 +34,25 @@
|
|||||||
|
|
||||||
using namespace BPrivate;
|
using namespace BPrivate;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
BSoftSynth::BSoftSynth()
|
BSoftSynth::BSoftSynth()
|
||||||
|
: fSynth(NULL),
|
||||||
|
fSettings(NULL),
|
||||||
|
fSoundPlayer(NULL)
|
||||||
{
|
{
|
||||||
instrumentsFile = NULL;
|
fInstrumentsFile = NULL;
|
||||||
SetDefaultInstrumentsFile();
|
SetDefaultInstrumentsFile();
|
||||||
|
|
||||||
sampleRate = 22050;
|
fSampleRate = 44100;
|
||||||
interpMode = B_LINEAR_INTERPOLATION;
|
fInterpMode = B_LINEAR_INTERPOLATION;
|
||||||
maxVoices = 28;
|
fMaxVoices = 256;
|
||||||
limiterThreshold = 7;
|
fLimiterThreshold = 7;
|
||||||
reverbEnabled = true;
|
fReverbEnabled = true;
|
||||||
reverbMode = B_REVERB_BALLROOM;
|
fReverbMode = B_REVERB_BALLROOM;
|
||||||
volumeScale = 1.0;
|
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
BSoftSynth::~BSoftSynth()
|
BSoftSynth::~BSoftSynth()
|
||||||
{
|
{
|
||||||
@@ -67,37 +66,36 @@ BSoftSynth::~BSoftSynth()
|
|||||||
Done();
|
Done();
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool BSoftSynth::InitCheck(void) const
|
bool
|
||||||
|
BSoftSynth::InitCheck(void) const
|
||||||
{
|
{
|
||||||
return initCheck;
|
return fInitCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::Unload(void)
|
void
|
||||||
|
BSoftSynth::Unload(void)
|
||||||
{
|
{
|
||||||
/* TODO: purge samples from memory */
|
/* TODO: purge samples from memory */
|
||||||
|
|
||||||
free(instrumentsFile);
|
free(fInstrumentsFile);
|
||||||
instrumentsFile = NULL;
|
fInstrumentsFile = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool BSoftSynth::IsLoaded(void) const
|
bool
|
||||||
|
BSoftSynth::IsLoaded(void) const
|
||||||
{
|
{
|
||||||
return instrumentsFile != NULL;
|
return fInstrumentsFile != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::SetDefaultInstrumentsFile()
|
status_t
|
||||||
|
BSoftSynth::SetDefaultInstrumentsFile()
|
||||||
{
|
{
|
||||||
BPath path;
|
BPath path;
|
||||||
if (B_OK == find_directory(B_SYNTH_DIRECTORY, &path, false, NULL))
|
if (B_OK == find_directory(B_SYNTH_DIRECTORY, &path, false, NULL)) {
|
||||||
{
|
|
||||||
path.Append(B_BIG_SYNTH_FILE);
|
path.Append(B_BIG_SYNTH_FILE);
|
||||||
return SetInstrumentsFile(path.Path());
|
return SetInstrumentsFile(path.Path());
|
||||||
}
|
}
|
||||||
@@ -105,9 +103,9 @@ status_t BSoftSynth::SetDefaultInstrumentsFile()
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::SetInstrumentsFile(const char* path)
|
status_t
|
||||||
|
BSoftSynth::SetInstrumentsFile(const char* path)
|
||||||
{
|
{
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -115,13 +113,13 @@ status_t BSoftSynth::SetInstrumentsFile(const char* path)
|
|||||||
if (IsLoaded())
|
if (IsLoaded())
|
||||||
Unload();
|
Unload();
|
||||||
|
|
||||||
instrumentsFile = strdup(path);
|
fInstrumentsFile = strdup(path);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::LoadAllInstruments()
|
status_t
|
||||||
|
BSoftSynth::LoadAllInstruments()
|
||||||
{
|
{
|
||||||
/* TODO: Should load all of the instruments from the sample bank. */
|
/* TODO: Should load all of the instruments from the sample bank. */
|
||||||
|
|
||||||
@@ -129,387 +127,369 @@ status_t BSoftSynth::LoadAllInstruments()
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::LoadInstrument(int16 instrument)
|
status_t
|
||||||
|
BSoftSynth::LoadInstrument(int16 instrument)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED
|
UNIMPLEMENTED
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::UnloadInstrument(int16 instrument)
|
status_t
|
||||||
|
BSoftSynth::UnloadInstrument(int16 instrument)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED
|
UNIMPLEMENTED
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::RemapInstrument(int16 from, int16 to)
|
status_t
|
||||||
|
BSoftSynth::RemapInstrument(int16 from, int16 to)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED
|
UNIMPLEMENTED
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::FlushInstrumentCache(bool startStopCache)
|
void
|
||||||
|
BSoftSynth::FlushInstrumentCache(bool startStopCache)
|
||||||
{
|
{
|
||||||
// TODO: we may decide not to support this function because it's weird!
|
// TODO: we may decide not to support this function because it's weird!
|
||||||
|
|
||||||
UNIMPLEMENTED
|
UNIMPLEMENTED
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::SetVolume(double volume)
|
void
|
||||||
|
BSoftSynth::SetVolume(double volume)
|
||||||
{
|
{
|
||||||
if (volume >= 0.0)
|
if (volume >= 0.0) {
|
||||||
{
|
fluid_synth_set_gain(fSynth, volume);
|
||||||
volumeScale = volume;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
double BSoftSynth::Volume(void) const
|
double
|
||||||
|
BSoftSynth::Volume(void) const
|
||||||
{
|
{
|
||||||
return volumeScale;
|
return fluid_synth_get_gain(fSynth);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::SetSamplingRate(int32 rate)
|
status_t
|
||||||
|
BSoftSynth::SetSamplingRate(int32 rate)
|
||||||
{
|
{
|
||||||
// TODO: According to the BeBook, we should round rate to the nearest
|
if (rate == 22050 || rate == 44100 || rate == 48000) {
|
||||||
// acceptable value. However, this function may change depending on the
|
fSampleRate = rate;
|
||||||
// softsynth back-end we'll use.
|
Init();
|
||||||
|
|
||||||
if (rate == 11025 || rate == 22050 || rate == 44100)
|
|
||||||
{
|
|
||||||
sampleRate = rate;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int32 BSoftSynth::SamplingRate() const
|
int32
|
||||||
|
BSoftSynth::SamplingRate() const
|
||||||
{
|
{
|
||||||
return sampleRate;
|
return fSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::SetInterpolation(interpolation_mode mode)
|
status_t
|
||||||
|
BSoftSynth::SetInterpolation(interpolation_mode mode)
|
||||||
{
|
{
|
||||||
// TODO: this function could change depending on the synth back-end.
|
// not used because our synth uses the same format than the soundplayer
|
||||||
|
fInterpMode = mode;
|
||||||
interpMode = mode;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
interpolation_mode BSoftSynth::Interpolation() const
|
interpolation_mode
|
||||||
|
BSoftSynth::Interpolation() const
|
||||||
{
|
{
|
||||||
return interpMode;
|
return fInterpMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::EnableReverb(bool enabled)
|
status_t
|
||||||
|
BSoftSynth::EnableReverb(bool enabled)
|
||||||
{
|
{
|
||||||
reverbEnabled = enabled;
|
fReverbEnabled = enabled;
|
||||||
|
fluid_synth_set_reverb_on(fSynth, enabled);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool BSoftSynth::IsReverbEnabled() const
|
bool
|
||||||
|
BSoftSynth::IsReverbEnabled() const
|
||||||
{
|
{
|
||||||
return reverbEnabled;
|
return fReverbEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::SetReverb(reverb_mode mode)
|
void
|
||||||
|
BSoftSynth::SetReverb(reverb_mode mode)
|
||||||
{
|
{
|
||||||
// TODO: this function could change depending on the synth back-end.
|
// TODO: this function could change depending on the synth back-end.
|
||||||
|
|
||||||
reverbMode = mode;
|
fReverbMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
reverb_mode BSoftSynth::Reverb() const
|
reverb_mode
|
||||||
|
BSoftSynth::Reverb() const
|
||||||
{
|
{
|
||||||
return reverbMode;
|
return fReverbMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::SetMaxVoices(int32 max)
|
status_t
|
||||||
|
BSoftSynth::SetMaxVoices(int32 max)
|
||||||
{
|
{
|
||||||
// TODO: this function could change depending on the synth back-end.
|
if (max > 0 && max <= 4096) {
|
||||||
|
fMaxVoices = max;
|
||||||
if (max > 0 && max <= 32)
|
Init();
|
||||||
{
|
|
||||||
maxVoices = max;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int16 BSoftSynth::MaxVoices(void) const
|
int16
|
||||||
|
BSoftSynth::MaxVoices(void) const
|
||||||
{
|
{
|
||||||
return maxVoices;
|
return fMaxVoices;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
status_t BSoftSynth::SetLimiterThreshold(int32 threshold)
|
status_t
|
||||||
|
BSoftSynth::SetLimiterThreshold(int32 threshold)
|
||||||
{
|
{
|
||||||
// TODO: this function could change depending on the synth back-end.
|
// not used
|
||||||
|
if (threshold > 0 && threshold <= 32) {
|
||||||
if (threshold > 0 && threshold <= 32)
|
fLimiterThreshold = threshold;
|
||||||
{
|
|
||||||
limiterThreshold = threshold;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int16 BSoftSynth::LimiterThreshold(void) const
|
int16
|
||||||
|
BSoftSynth::LimiterThreshold(void) const
|
||||||
{
|
{
|
||||||
return limiterThreshold;
|
return fLimiterThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::Pause(void)
|
void
|
||||||
|
BSoftSynth::Pause(void)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED
|
UNIMPLEMENTED
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::Resume(void)
|
void
|
||||||
|
BSoftSynth::Resume(void)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED
|
UNIMPLEMENTED
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::NoteOff(
|
void
|
||||||
|
BSoftSynth::NoteOff(
|
||||||
uchar channel, uchar note, uchar velocity, uint32 time)
|
uchar channel, uchar note, uchar velocity, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SprayNoteOff(
|
fluid_synth_noteoff(fSynth, channel - 1, note); // velocity isn't used in FS
|
||||||
channel - 1, note, velocity, MAKE_BIGTIME(time));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::NoteOn(
|
void
|
||||||
|
BSoftSynth::NoteOn(
|
||||||
uchar channel, uchar note, uchar velocity, uint32 time)
|
uchar channel, uchar note, uchar velocity, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SprayNoteOn(channel - 1, note, velocity, MAKE_BIGTIME(time));
|
fluid_synth_noteon(fSynth, channel - 1, note, velocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::KeyPressure(
|
void
|
||||||
|
BSoftSynth::KeyPressure(
|
||||||
uchar channel, uchar note, uchar pressure, uint32 time)
|
uchar channel, uchar note, uchar pressure, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SprayKeyPressure(
|
// unavailable
|
||||||
channel - 1, note, pressure, MAKE_BIGTIME(time));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::ControlChange(
|
void
|
||||||
|
BSoftSynth::ControlChange(
|
||||||
uchar channel, uchar controlNumber, uchar controlValue, uint32 time)
|
uchar channel, uchar controlNumber, uchar controlValue, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SprayControlChange(
|
fluid_synth_cc(fSynth, channel - 1, controlNumber, controlValue);
|
||||||
channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::ProgramChange(
|
void
|
||||||
|
BSoftSynth::ProgramChange(
|
||||||
uchar channel, uchar programNumber, uint32 time)
|
uchar channel, uchar programNumber, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SprayProgramChange(
|
fluid_synth_program_change(fSynth, channel - 1, programNumber);
|
||||||
channel - 1, programNumber, MAKE_BIGTIME(time));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::ChannelPressure(uchar channel, uchar pressure, uint32 time)
|
void
|
||||||
|
BSoftSynth::ChannelPressure(uchar channel, uchar pressure, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SprayChannelPressure(
|
//unavailable
|
||||||
channel - 1, pressure, MAKE_BIGTIME(time));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
|
void
|
||||||
|
BSoftSynth::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time));
|
// fluid_synth only accepts an int
|
||||||
|
fluid_synth_pitch_bend(fSynth, channel - 1, ((uint32)(msb & 0x7f) << 8) | (lsb & 0x7f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::SystemExclusive(void* data, size_t length, uint32 time)
|
void
|
||||||
|
BSoftSynth::SystemExclusive(void* data, size_t length, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SpraySystemExclusive(data, length, MAKE_BIGTIME(time));
|
// unsupported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::SystemCommon(
|
void
|
||||||
|
BSoftSynth::SystemCommon(
|
||||||
uchar status, uchar data1, uchar data2, uint32 time)
|
uchar status, uchar data1, uchar data2, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time));
|
// unsupported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::SystemRealTime(uchar status, uint32 time)
|
void
|
||||||
|
BSoftSynth::SystemRealTime(uchar status, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SpraySystemRealTime(status, MAKE_BIGTIME(time));
|
// unsupported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::TempoChange(int32 beatsPerMinute, uint32 time)
|
void
|
||||||
|
BSoftSynth::TempoChange(int32 beatsPerMinute, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
producer->SprayTempoChange(beatsPerMinute, MAKE_BIGTIME(time));
|
// unsupported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::AllNotesOff(bool justChannel, uint32 time)
|
void
|
||||||
|
BSoftSynth::AllNotesOff(bool justChannel, uint32 time)
|
||||||
{
|
{
|
||||||
if (InitCheck())
|
if (InitCheck()) {
|
||||||
{
|
|
||||||
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
|
||||||
|
|
||||||
// from BMidi::AllNotesOff
|
// from BMidi::AllNotesOff
|
||||||
for (uchar channel = 1; channel <= 16; ++channel)
|
for (uchar channel = 1; channel <= 16; ++channel) {
|
||||||
{
|
fluid_synth_cc(fSynth, channel - 1, B_ALL_NOTES_OFF, 0);
|
||||||
producer->SprayControlChange(channel, B_ALL_NOTES_OFF, 0, time);
|
|
||||||
|
|
||||||
if (!justChannel)
|
if (!justChannel) {
|
||||||
{
|
for (uchar note = 0; note <= 0x7F; ++note) {
|
||||||
for (uchar note = 0; note <= 0x7F; ++note)
|
fluid_synth_noteoff(fSynth, channel - 1, note);
|
||||||
{
|
|
||||||
producer->SprayNoteOff(channel, note, 0, time);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::Init()
|
void
|
||||||
|
BSoftSynth::Init()
|
||||||
{
|
{
|
||||||
initCheck = false;
|
fInitCheck = false;
|
||||||
|
|
||||||
producer = new BMidiLocalProducer("TiMidity feeder");
|
|
||||||
|
|
||||||
int32 id = 0;
|
|
||||||
while ((consumer = BMidiRoster::NextConsumer(&id)) != NULL)
|
|
||||||
{
|
|
||||||
if (strcmp(consumer->Name(), "TiMidity input") == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
consumer->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (consumer == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "[midi] TiMidity consumer not found\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (producer->Connect(consumer) != B_OK)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "[midi] Could not connect to TiMidity\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
initCheck = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void BSoftSynth::Done()
|
|
||||||
{
|
|
||||||
if (consumer != NULL)
|
|
||||||
{
|
|
||||||
producer->Disconnect(consumer);
|
|
||||||
consumer->Release();
|
|
||||||
consumer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
producer->Release();
|
Done();
|
||||||
producer = NULL;
|
|
||||||
|
fSettings = new_fluid_settings();
|
||||||
|
fluid_settings_setnum(fSettings, "synth.sample-rate", fSampleRate);
|
||||||
|
fluid_settings_setint(fSettings, "synth.polyphony", fMaxVoices);
|
||||||
|
|
||||||
|
fSynth = new_fluid_synth(fSettings);
|
||||||
|
|
||||||
|
media_raw_audio_format format;
|
||||||
|
format.channel_count = 2;
|
||||||
|
format.frame_rate = fSampleRate;
|
||||||
|
format.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||||
|
|
||||||
|
fSoundPlayer = new BSoundPlayer(&format, "softsynth", &PlayBuffer, NULL, this);
|
||||||
|
status_t err = fSoundPlayer->InitCheck();
|
||||||
|
if (err != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fSoundPlayer->SetHasData(true);
|
||||||
|
fSoundPlayer->Start();
|
||||||
|
|
||||||
|
fInitCheck = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BSoftSynth::Done()
|
||||||
|
{
|
||||||
|
if (fSoundPlayer) {
|
||||||
|
fSoundPlayer->SetHasData(false);
|
||||||
|
fSoundPlayer->Stop();
|
||||||
|
delete fSoundPlayer;
|
||||||
|
}
|
||||||
|
if (fSynth)
|
||||||
|
delete_fluid_synth(fSynth);
|
||||||
|
if (fSettings)
|
||||||
|
delete_fluid_settings(fSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BSoftSynth::PlayBuffer(void * cookie, void * data, size_t size, const media_raw_audio_format & format)
|
||||||
|
{
|
||||||
|
BSoftSynth *synth = (BSoftSynth *)cookie;
|
||||||
|
|
||||||
|
// we use float samples
|
||||||
|
|
||||||
|
fluid_synth_write_float(synth->fSynth, size / sizeof(float) / format.channel_count,
|
||||||
|
data, 0, sizeof(float) * format.channel_count,
|
||||||
|
(char *)data + sizeof(float), 0, sizeof(float) * format.channel_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|||||||
+19
-26
@@ -57,8 +57,11 @@
|
|||||||
#include <Midi.h>
|
#include <Midi.h>
|
||||||
#include <Synth.h>
|
#include <Synth.h>
|
||||||
|
|
||||||
|
#include <SoundPlayer.h>
|
||||||
|
|
||||||
|
#include <fluidsynth.h>
|
||||||
|
|
||||||
class BMidiConsumer;
|
class BMidiConsumer;
|
||||||
class BMidiLocalProducer;
|
|
||||||
class BMidiSynth;
|
class BMidiSynth;
|
||||||
class BSynth;
|
class BSynth;
|
||||||
|
|
||||||
@@ -68,10 +71,10 @@ class BSoftSynth
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool InitCheck(void) const;
|
bool InitCheck() const;
|
||||||
|
|
||||||
void Unload(void);
|
void Unload();
|
||||||
bool IsLoaded(void) const;
|
bool IsLoaded() const;
|
||||||
|
|
||||||
status_t SetDefaultInstrumentsFile();
|
status_t SetDefaultInstrumentsFile();
|
||||||
status_t SetInstrumentsFile(const char* path);
|
status_t SetInstrumentsFile(const char* path);
|
||||||
@@ -128,31 +131,21 @@ private:
|
|||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void Done();
|
void Done();
|
||||||
|
static void PlayBuffer(void * cookie, void * data, size_t size, const media_raw_audio_format & format);
|
||||||
|
|
||||||
bool initCheck;
|
bool fInitCheck;
|
||||||
char* instrumentsFile;
|
char* fInstrumentsFile;
|
||||||
int32 sampleRate;
|
int32 fSampleRate;
|
||||||
interpolation_mode interpMode;
|
interpolation_mode fInterpMode;
|
||||||
int16 maxVoices;
|
int16 fMaxVoices;
|
||||||
int16 limiterThreshold;
|
int16 fLimiterThreshold;
|
||||||
reverb_mode reverbMode;
|
reverb_mode fReverbMode;
|
||||||
bool reverbEnabled;
|
bool fReverbEnabled;
|
||||||
double volumeScale;
|
|
||||||
|
|
||||||
/*
|
fluid_synth_t *fSynth;
|
||||||
Note: Maybe this isn't the most efficient way to do things.
|
fluid_settings_t* fSettings;
|
||||||
Now a producer connects to BMidiSynth, which is a consumer.
|
|
||||||
That consumer directly calls our NoteOff() etc, methods.
|
|
||||||
We create a new producer and connect it to TiMidity's consumer.
|
|
||||||
It would save some indirection if BMidiSynth's consumer would
|
|
||||||
be a proxy for TiMidity's. (I don't think that is possible,
|
|
||||||
because BMidiSynth is a BMidi object which always creates a
|
|
||||||
new consumer regardless. In any case, notes have to travel
|
|
||||||
a long way before they reach TiMidity.
|
|
||||||
*/
|
|
||||||
|
|
||||||
BMidiConsumer* consumer;
|
BSoundPlayer *fSoundPlayer;
|
||||||
BMidiLocalProducer* producer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace BPrivate
|
} // namespace BPrivate
|
||||||
|
|||||||
Reference in New Issue
Block a user