Added preliminary support for using TiMidity++ as softsynth.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11678 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
mahlzeit
2005-03-11 16:48:12 +00:00
parent 5040785e7d
commit d1c4420ee5
2 changed files with 201 additions and 30 deletions
+146 -29
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004 Matthijs Hollemans
* Copyright (c) 2004-2005 Matthijs Hollemans
* Copyright (c) 2003 Jerome Leveque
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -21,12 +21,16 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <MidiRoster.h>
#include <MidiConsumer.h>
#include <MidiProducer.h>
#include <FindDirectory.h>
#include <Path.h>
#include <string.h>
#include <stdlib.h>
#include "debug.h"
#include "MidiGlue.h" // for MAKE_BIGTIME
#include "SoftSynth.h"
using namespace BPrivate;
@@ -45,13 +49,29 @@ BSoftSynth::BSoftSynth()
reverbEnabled = true;
reverbMode = B_REVERB_BALLROOM;
volumeScale = 1.0;
Init();
}
//------------------------------------------------------------------------------
BSoftSynth::~BSoftSynth()
{
// Note: it is possible that we don't get deleted. When BSynth is
// created, it is assigned to the global variable be_synth. While
// BSynth is alive, it keeps a copy of BSoftSynth around too. Not
// a big deal, but the Midi Kit will complain (on stdout) that we
// didn't release our endpoints.
Unload();
Done();
}
//------------------------------------------------------------------------------
bool BSoftSynth::InitCheck(void) const
{
return initCheck;
}
//------------------------------------------------------------------------------
@@ -90,14 +110,10 @@ status_t BSoftSynth::SetDefaultInstrumentsFile()
status_t BSoftSynth::SetInstrumentsFile(const char* path)
{
if (path == NULL)
{
return B_BAD_VALUE;
}
if (IsLoaded())
{
Unload();
}
instrumentsFile = strdup(path);
return B_OK;
@@ -298,8 +314,12 @@ void BSoftSynth::Resume(void)
void BSoftSynth::NoteOff(
uchar channel, uchar note, uchar velocity, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SprayNoteOff(
channel - 1, note, velocity, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
@@ -307,8 +327,11 @@ void BSoftSynth::NoteOff(
void BSoftSynth::NoteOn(
uchar channel, uchar note, uchar velocity, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SprayNoteOn(channel - 1, note, velocity, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
@@ -316,8 +339,12 @@ void BSoftSynth::NoteOn(
void BSoftSynth::KeyPressure(
uchar channel, uchar note, uchar pressure, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SprayKeyPressure(
channel - 1, note, pressure, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
@@ -325,8 +352,12 @@ void BSoftSynth::KeyPressure(
void BSoftSynth::ControlChange(
uchar channel, uchar controlNumber, uchar controlValue, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SprayControlChange(
channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
@@ -334,32 +365,46 @@ void BSoftSynth::ControlChange(
void BSoftSynth::ProgramChange(
uchar channel, uchar programNumber, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SprayProgramChange(
channel - 1, programNumber, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
void BSoftSynth::ChannelPressure(uchar channel, uchar pressure, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SprayChannelPressure(
channel - 1, pressure, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
void BSoftSynth::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
void BSoftSynth::SystemExclusive(void* data, size_t length, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SpraySystemExclusive(data, length, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
@@ -367,32 +412,104 @@ void BSoftSynth::SystemExclusive(void* data, size_t length, uint32 time)
void BSoftSynth::SystemCommon(
uchar status, uchar data1, uchar data2, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
void BSoftSynth::SystemRealTime(uchar status, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SpraySystemRealTime(status, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
void BSoftSynth::TempoChange(int32 beatsPerMinute, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
producer->SprayTempoChange(beatsPerMinute, MAKE_BIGTIME(time));
}
}
//------------------------------------------------------------------------------
void BSoftSynth::AllNotesOff(bool justChannel, uint32 time)
{
snooze_until(time * (bigtime_t) 1000, B_SYSTEM_TIMEBASE);
UNIMPLEMENTED
if (InitCheck())
{
snooze_until(MAKE_BIGTIME(time), B_SYSTEM_TIMEBASE);
// from BMidi::AllNotesOff
for (uchar channel = 1; channel <= 16; ++channel)
{
producer->SprayControlChange(channel, B_ALL_NOTES_OFF, 0, time);
if (!justChannel)
{
for (uchar note = 0; note <= 0x7F; ++note)
{
producer->SprayNoteOff(channel, note, 0, time);
}
}
}
}
}
//------------------------------------------------------------------------------
void BSoftSynth::Init()
{
initCheck = 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();
producer = NULL;
}
//------------------------------------------------------------------------------
+55 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004 Matthijs Hollemans
* Copyright (c) 2004-2005 Matthijs Hollemans
* Copyright (c) 2003 Jerome Leveque
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -24,15 +24,50 @@
#ifndef _SOFT_SYNTH_H
#define _SOFT_SYNTH_H
/*
WORK IN PROGRESS!
This version of SoftSynth is a wrapper for Michael Pfeiffer's port
of TiMidity++ 2.11.3/3 (http://www.bebits.com/app/2736).
It works, but not good enough yet. Playback from MidiPlayer sounds
a lot worse than using TiMidity in standalone mode. Either TiMidity's
MidiConsumer doesn't work properly or the Midi Kit messes things up;
I haven't investigated yet.
To try it out, download TiMidity and the sound files (30MB):
http://bepdf.sourceforge.net/download/midi/TiMidity++-2.11.3_3.x86.zip
http://bepdf.sourceforge.net/download/midi/eawpats11_full_beos.zip
Follow the instructions in the archive to install. Then double-click
"Start TiMidity Server" to launch TiMidity. The server will publish a
consumer endpoint. You can verify this with PatchBay.
Build the Haiku Midi Kit. Put libmidi.so and libmidi2.so in ~/config/lib.
Quit the BeOS midi_server. Launch the Haiku midi_server.
Build the Haiku MidiPlayer (or use the BeOS MidiPlayer). Start it and
choose a MIDI file. If all went fine, you will hear TiMidity play back
the song. Just not very well. :-)
Note: You can still use the Midi Kit if you don't install TiMidity,
but the software synth will simply make no sound.
*/
#include <Midi.h>
#include <Synth.h>
class BMidiConsumer;
class BMidiLocalProducer;
namespace BPrivate {
class BSoftSynth
{
public:
bool InitCheck(void) const;
void Unload(void);
bool IsLoaded(void) const;
@@ -89,6 +124,10 @@ private:
BSoftSynth();
~BSoftSynth();
void Init();
void Done();
bool initCheck;
char* instrumentsFile;
int32 sampleRate;
interpolation_mode interpMode;
@@ -97,6 +136,21 @@ private:
reverb_mode reverbMode;
bool reverbEnabled;
double volumeScale;
/*
Note: Maybe this isn't the most efficient way to do things.
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;
BMidiLocalProducer* producer;
};
} // namespace BPrivate