- Added version number.

- Added the Live Input menu, although it doesn't do anything yet.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8159 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
mahlzeit
2004-06-25 12:16:48 +00:00
parent 9310e248b4
commit f124b49e87
5 changed files with 149 additions and 21 deletions
+1
View File
@@ -13,4 +13,5 @@ App MidiPlayer :
LinkSharedOSLibs MidiPlayer : LinkSharedOSLibs MidiPlayer :
be be
midi midi
midi2
; ;
+1 -1
View File
@@ -47,7 +47,7 @@ void MidiPlayerApp::AboutRequested()
{ {
(new BAlert( (new BAlert(
NULL, NULL,
"Haiku MIDI Player\n\n" "Haiku MIDI Player 1.0.0 beta\n\n"
"This tiny program\n" "This tiny program\n"
"Knows how to play thousands of\n" "Knows how to play thousands of\n"
"Cheesy sounding songs", "Cheesy sounding songs",
+120 -15
View File
@@ -20,6 +20,7 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include <MidiRoster.h>
#include <StorageKit.h> #include <StorageKit.h>
#include "MidiPlayerApp.h" #include "MidiPlayerApp.h"
@@ -42,6 +43,7 @@ MidiPlayerWindow::MidiPlayerWindow()
windowX = -1; windowX = -1;
windowY = -1; windowY = -1;
threadId = -1; threadId = -1;
inputId = -1;
be_synth->SetSamplingRate(44100); be_synth->SetSamplingRate(44100);
@@ -86,6 +88,10 @@ void MidiPlayerWindow::MessageReceived(BMessage* msg)
case MSG_SHOW_SCOPE: case MSG_SHOW_SCOPE:
OnShowScope(); OnShowScope();
break; break;
case MSG_INPUT_CHANGED:
OnInputChanged(msg);
break;
case MSG_REVERB_NONE: case MSG_REVERB_NONE:
OnReverb(B_REVERB_NONE); OnReverb(B_REVERB_NONE);
@@ -137,9 +143,77 @@ void MidiPlayerWindow::FrameMoved(BPoint origin)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void MidiPlayerWindow::MenusBeginning()
{
for (int32 t = inputPopUp->CountItems() - 1; t > 0; --t)
{
delete inputPopUp->RemoveItem(t);
}
bool seenInput = false;
if (inputId == -1)
{
inputOff->SetMarked(true);
seenInput = true;
}
int32 id = 0;
BMidiEndpoint* endp;
while ((endp = BMidiRoster::NextEndpoint(&id)) != NULL)
{
if (endp->IsProducer())
{
BMessage* msg = new BMessage;
msg->what = MSG_INPUT_CHANGED;
msg->AddInt32("id", id);
BMenuItem* item = new BMenuItem(endp->Name(), msg);
inputPopUp->AddItem(item);
if (inputId == id)
{
item->SetMarked(true);
seenInput = true;
}
}
endp->Release();
}
if (!seenInput) // endpoint no longer exists
{
inputOff->SetMarked(true);
}
}
//------------------------------------------------------------------------------
void MidiPlayerWindow::CreateInputMenu()
{
inputPopUp = new BPopUpMenu("inputPopUp");
BMessage* msg = new BMessage;
msg->what = MSG_INPUT_CHANGED;
msg->AddInt32("id", -1);
inputOff = new BMenuItem("Off", msg);
inputPopUp->AddItem(inputOff);
inputMenu = new BMenuField(
BRect(0, 0, 128, 17), "inputMenu", "Live Input:", inputPopUp,
B_FOLLOW_LEFT | B_FOLLOW_TOP);
inputMenu->SetDivider(55);
inputMenu->ResizeToPreferred();
}
//------------------------------------------------------------------------------
void MidiPlayerWindow::CreateReverbMenu() void MidiPlayerWindow::CreateReverbMenu()
{ {
BPopUpMenu* menu = new BPopUpMenu("reverbPopUp"); BPopUpMenu* reverbPopUp = new BPopUpMenu("reverbPopUp");
reverbNone = new BMenuItem( reverbNone = new BMenuItem(
"None", new BMessage(MSG_REVERB_NONE)); "None", new BMessage(MSG_REVERB_NONE));
@@ -159,18 +233,18 @@ void MidiPlayerWindow::CreateReverbMenu()
reverbDungeon = new BMenuItem( reverbDungeon = new BMenuItem(
"Dungeon", new BMessage(MSG_REVERB_DUNGEON)); "Dungeon", new BMessage(MSG_REVERB_DUNGEON));
menu->AddItem(reverbNone); reverbPopUp->AddItem(reverbNone);
menu->AddItem(reverbCloset); reverbPopUp->AddItem(reverbCloset);
menu->AddItem(reverbGarage); reverbPopUp->AddItem(reverbGarage);
menu->AddItem(reverbIgor); reverbPopUp->AddItem(reverbIgor);
menu->AddItem(reverbCavern); reverbPopUp->AddItem(reverbCavern);
menu->AddItem(reverbDungeon); reverbPopUp->AddItem(reverbDungeon);
reverbMenu = new BMenuField( reverbMenu = new BMenuField(
BRect(0, 0, 128, 17), "reverbMenu", "Reverb:", menu, BRect(0, 0, 128, 17), "reverbMenu", "Reverb:", reverbPopUp,
B_FOLLOW_LEFT | B_FOLLOW_TOP); B_FOLLOW_LEFT | B_FOLLOW_TOP);
reverbMenu->SetDivider(50); reverbMenu->SetDivider(55);
reverbMenu->ResizeToPreferred(); reverbMenu->ResizeToPreferred();
} }
@@ -187,6 +261,7 @@ void MidiPlayerWindow::CreateViews()
showScope->SetValue(B_CONTROL_ON); showScope->SetValue(B_CONTROL_ON);
showScope->ResizeToPreferred(); showScope->ResizeToPreferred();
CreateInputMenu();
CreateReverbMenu(); CreateReverbMenu();
volumeSlider = new BSlider( volumeSlider = new BSlider(
@@ -197,7 +272,7 @@ void MidiPlayerWindow::CreateViews()
volumeSlider->UseFillColor(true, &col); volumeSlider->UseFillColor(true, &col);
volumeSlider->SetModificationMessage(new BMessage(MSG_VOLUME)); volumeSlider->SetModificationMessage(new BMessage(MSG_VOLUME));
volumeSlider->ResizeToPreferred(); volumeSlider->ResizeToPreferred();
volumeSlider->ResizeTo(_W(scopeView) - 37, _H(volumeSlider)); volumeSlider->ResizeTo(_W(scopeView) - 42, _H(volumeSlider));
playButton = new BButton( playButton = new BButton(
BRect(0, 1, 80, 1), "playButton", "Play", new BMessage(MSG_PLAY_STOP), BRect(0, 1, 80, 1), "playButton", "Play", new BMessage(MSG_PLAY_STOP),
@@ -226,13 +301,14 @@ void MidiPlayerWindow::CreateViews()
float width = 8 + _W(scopeView) + 8; float width = 8 + _W(scopeView) + 8;
float height = float height =
+ 8 + _H(scopeView) 8 + _H(scopeView)
+ 8 + _H(showScope) + 8 + _H(showScope)
+ 4 + _H(reverbMenu) + 4 + _H(inputMenu)
+ _H(reverbMenu)
+ 2 + _H(volumeSlider) + 2 + _H(volumeSlider)
+ 10 + _H(divider) + 10 + _H(divider)
+ 6 + _H(playButton) + 6 + _H(playButton)
+ 10; + 16;
ResizeTo(width, height); ResizeTo(width, height);
@@ -241,6 +317,7 @@ void MidiPlayerWindow::CreateViews()
background->AddChild(scopeView); background->AddChild(scopeView);
background->AddChild(showScope); background->AddChild(showScope);
background->AddChild(reverbMenu); background->AddChild(reverbMenu);
background->AddChild(inputMenu);
background->AddChild(volumeLabel); background->AddChild(volumeLabel);
background->AddChild(volumeSlider); background->AddChild(volumeSlider);
background->AddChild(divider); background->AddChild(divider);
@@ -250,14 +327,17 @@ void MidiPlayerWindow::CreateViews()
scopeView->MoveTo(8, y); scopeView->MoveTo(8, y);
y += _H(scopeView) + 8; y += _H(scopeView) + 8;
showScope->MoveTo(8 + 50, y); showScope->MoveTo(8 + 55, y);
y += _H(showScope) + 4; y += _H(showScope) + 4;
inputMenu->MoveTo(8, y);
y += _H(inputMenu);
reverbMenu->MoveTo(8, y); reverbMenu->MoveTo(8, y);
y += _H(reverbMenu) + 2; y += _H(reverbMenu) + 2;
volumeLabel->MoveTo(8, y); volumeLabel->MoveTo(8, y);
volumeSlider->MoveTo(8 + 44, y); volumeSlider->MoveTo(8 + 49, y);
y += _H(volumeSlider) + 10; y += _H(volumeSlider) + 10;
divider->MoveTo(8, y); divider->MoveTo(8, y);
@@ -287,6 +367,8 @@ void MidiPlayerWindow::InitControls()
showScope->SetValue(scopeEnabled ? B_CONTROL_ON : B_CONTROL_OFF); showScope->SetValue(scopeEnabled ? B_CONTROL_ON : B_CONTROL_OFF);
scopeView->SetEnabled(scopeEnabled); scopeView->SetEnabled(scopeEnabled);
inputOff->SetMarked(true);
reverbNone->SetMarked(reverb == B_REVERB_NONE); reverbNone->SetMarked(reverb == B_REVERB_NONE);
reverbCloset->SetMarked(reverb == B_REVERB_CLOSET); reverbCloset->SetMarked(reverb == B_REVERB_CLOSET);
reverbGarage->SetMarked(reverb == B_REVERB_GARAGE); reverbGarage->SetMarked(reverb == B_REVERB_GARAGE);
@@ -486,6 +568,29 @@ void MidiPlayerWindow::OnShowScope()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void MidiPlayerWindow::OnInputChanged(BMessage* msg)
{
int32 newId;
if (msg->FindInt32("id", &newId) == B_OK)
{
inputId = newId;
// if (!instrLoaded)
// be_synth->LoadInstruments(all)
// if id != -1
// if playing -> Stop() // AARGH, need thread!
// connect SynthBridge (from MidiUtil) to producer endpoint
// else if SynthBridge still connected
// disconnect SynthBridge
// NOTE: we should also disconnect SynthBridge when launching
// a MIDI file!!! (successfull or not)
}
}
//------------------------------------------------------------------------------
void MidiPlayerWindow::OnReverb(reverb_mode mode) void MidiPlayerWindow::OnReverb(reverb_mode mode)
{ {
reverb = mode; reverb = mode;
+8
View File
@@ -32,6 +32,7 @@ enum
{ {
MSG_PLAY_STOP = 1000, MSG_PLAY_STOP = 1000,
MSG_SHOW_SCOPE, MSG_SHOW_SCOPE,
MSG_INPUT_CHANGED,
MSG_REVERB_NONE, MSG_REVERB_NONE,
MSG_REVERB_CLOSET, MSG_REVERB_CLOSET,
MSG_REVERB_GARAGE, MSG_REVERB_GARAGE,
@@ -53,11 +54,13 @@ public:
virtual bool QuitRequested(); virtual bool QuitRequested();
virtual void MessageReceived(BMessage* msg); virtual void MessageReceived(BMessage* msg);
virtual void FrameMoved(BPoint origin); virtual void FrameMoved(BPoint origin);
virtual void MenusBeginning();
private: private:
typedef BWindow super; typedef BWindow super;
void CreateInputMenu();
void CreateReverbMenu(); void CreateReverbMenu();
void CreateViews(); void CreateViews();
void CenterOnScreen(); void CenterOnScreen();
@@ -76,12 +79,16 @@ private:
void OnPlayStop(); void OnPlayStop();
void OnShowScope(); void OnShowScope();
void OnInputChanged(BMessage* msg);
void OnReverb(reverb_mode mode); void OnReverb(reverb_mode mode);
void OnVolume(); void OnVolume();
void OnDrop(BMessage* msg); void OnDrop(BMessage* msg);
ScopeView* scopeView; ScopeView* scopeView;
BCheckBox* showScope; BCheckBox* showScope;
BMenuField* inputMenu;
BPopUpMenu* inputPopUp;
BMenuItem* inputOff;
BMenuField* reverbMenu; BMenuField* reverbMenu;
BMenuItem* reverbNone; BMenuItem* reverbNone;
BMenuItem* reverbCloset; BMenuItem* reverbCloset;
@@ -101,6 +108,7 @@ private:
BMidiSynthFile synth; BMidiSynthFile synth;
entry_ref ref; entry_ref ref;
thread_id threadId; thread_id threadId;
int32 inputId;
}; };
#endif // MIDI_PLAYER_WINDOW_H #endif // MIDI_PLAYER_WINDOW_H
+19 -5
View File
@@ -4,23 +4,37 @@
</head> </head>
<body> <body>
<h1>Haiku MIDI Player</h1> <h1>Haiku MIDI Player 1.0.0 beta</h1>
<p>This is a simple application to play MIDI songs.</p> <p>This is a simple application to play MIDI songs.</p>
<p>Differences with the BeOS R5 MidiPlayer:</p> <p>To play a MIDI song, you can:</p>
<ul>
<li>double-click it, or</li>
<li>drag it on the MidiPlayer icon, or</li>
<li>drag it into the MidiPlayer window, or</li>
<li>type "MidiPlayer song.mid" in Terminal.</li>
</ul>
<p>Hopefully, most of the options will be obvious, although Live Input may require a few lines of explanation.</p>
<p>The <b>Live Input</b> feature enables you to attach other applications to the Haiku software synthesizer, for example a virtual MIDI keyboard. MidiPlayer looks at the MIDI roster for compatible producer endpoints. If none are found, Live Input is not available.</p>
<h3>Differences with the BeOS R5 MidiPlayer:</h3>
<ul> <ul>
<li>User interface looks slightly different (better?)</li> <li>User interface looks slightly different (better?)</li>
<li>Play and Stop are now one and the same button.</li> <li>Play and Stop are now one and the same button.</li>
<li>There is no Open File... button. You open MIDI songs by dragging them into the window.</li> <li>There is no Open File... function.</li>
<li>There is no Live Input feature.</li>
<li>You cannot set the Quality of the sound (always 44100 Hz).</li> <li>You cannot set the Quality of the sound (always 44100 Hz).</li>
</ul> </ul>
<p>If people really <i>really</i> want these missing features, then feel free to add them :-)</p> <p>If people really <i>really</i> want these missing features, then feel free to add them :-)</p>
<p>Note: The code can be a little tricky at times, since it uses fire-and-forget threads to load new songs and to stop playback. The reason for this is the scope: we want to keep repainting the scope view even when fading out a song (because this looks cool), but fading blocks the calling thread. If we were to block the window's looper, then the scope wouldn't repaint during the fade-out. So we fade using a separate thread instead. Unfortunately, this makes the code much less clean as it introduces several race conditions. Yech. See the source for more details.</p> <h3>Implementation notes</h3>
<p>The code can be a little tricky at times, since it uses fire-and-forget threads to load new songs and to stop playback. The reason for this is the scope: we want to keep repainting the ScopeView even when fading out a song (because this looks cool), but fading blocks the calling thread. If we were to block the window's looper, then the scope wouldn't repaint during the fade-out. So we fade using a separate thread instead. Unfortunately, this makes the code much less clean as it introduces several race conditions. Yech. See the source for more details.</p>
</body> </body>
</html> </html>