From b1902a09ef38a67811b7facad91de6453f177daf Mon Sep 17 00:00:00 2001 From: mahlzeit Date: Fri, 25 Jun 2004 13:17:18 +0000 Subject: [PATCH] Removed the nasty threads because they made my head hurt. Old code is tagged with "with_cool_scope". git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8164 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/midiplayer/MidiPlayerWindow.cpp | 116 ++++++++--------------- src/apps/midiplayer/MidiPlayerWindow.h | 14 +-- src/apps/midiplayer/ScopeView.cpp | 25 ++++- src/apps/midiplayer/ScopeView.h | 3 + src/apps/midiplayer/readme.html | 5 +- 5 files changed, 75 insertions(+), 88 deletions(-) diff --git a/src/apps/midiplayer/MidiPlayerWindow.cpp b/src/apps/midiplayer/MidiPlayerWindow.cpp index fab3354f3a..0f12a0b660 100644 --- a/src/apps/midiplayer/MidiPlayerWindow.cpp +++ b/src/apps/midiplayer/MidiPlayerWindow.cpp @@ -42,7 +42,6 @@ MidiPlayerWindow::MidiPlayerWindow() volume = 75; windowX = -1; windowY = -1; - threadId = -1; inputId = -1; be_synth->SetSamplingRate(44100); @@ -63,16 +62,8 @@ MidiPlayerWindow::~MidiPlayerWindow() bool MidiPlayerWindow::QuitRequested() { - // There is a race condition when you quit MidiPlayer while we're still - // fading out, because fading happens in a separate thread. In this odd - // case, we simply won't let the user quit the app :-) - - if (threadId == -1) - { - be_app->PostMessage(B_QUIT_REQUESTED); - return true; - } - return false; + be_app->PostMessage(B_QUIT_REQUESTED); + return true; } //------------------------------------------------------------------------------ @@ -430,99 +421,53 @@ void MidiPlayerWindow::SaveSettings() //------------------------------------------------------------------------------ -int32 MidiPlayerWindow::_LoadThread(void* data) +void MidiPlayerWindow::LoadFile(entry_ref* ref) { - return ((MidiPlayerWindow*) data)->LoadThread(); -} - -//------------------------------------------------------------------------------ - -int32 MidiPlayerWindow::LoadThread() -{ - // We do this in a separate fire-and-forget thread, just in case a song - // was already playing. The call to StopSynth() will block, and we need - // to keep the window's looper free for repainting the ScopeView during - // the fade out. The R5 MidiPlayer does that too and it looks neat. - if (playing) { + scopeView->SetPlaying(false); + scopeView->Invalidate(); + StopSynth(); } synth.UnloadFile(); - if (synth.LoadFile(&ref) == B_OK) + if (synth.LoadFile(ref) == B_OK) { // Ideally, we would call SetVolume() in InitControls(), // but for some reason that doesn't work: BMidiSynthFile // will use the default volume instead. So we do it here. synth.SetVolume(volume / 100.0f); - Lock(); playButton->SetEnabled(true); playButton->SetLabel("Stop"); scopeView->SetHaveFile(true); + scopeView->SetPlaying(true); scopeView->Invalidate(); - Unlock(); StartSynth(); } else { - Lock(); playButton->SetEnabled(false); playButton->SetLabel("Play"); scopeView->SetHaveFile(false); + scopeView->SetPlaying(false); scopeView->Invalidate(); - Unlock(); (new BAlert( NULL, "Could not load song", "Okay", NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(); } - - threadId = -1; - return 0; -} - -//------------------------------------------------------------------------------ - -int32 MidiPlayerWindow::_StopThread(void* data) -{ - return ((MidiPlayerWindow*) data)->StopThread(); -} - -//------------------------------------------------------------------------------ - -int32 MidiPlayerWindow::StopThread() -{ - Lock(); - playButton->SetEnabled(false); - Unlock(); - - StopSynth(); - - Lock(); - playButton->SetEnabled(true); - playButton->SetLabel("Play"); - Unlock(); - - threadId = -1; - return 0; } //------------------------------------------------------------------------------ void MidiPlayerWindow::StartSynth() { - // When playback of the song ends, we don't automatically go back into - // "stopped" mode. It is possible to do this with synth.SetFileHook(), - // but that made the code kinda messy (with all the threads and stuff). - // Note: SetFileHook(NULL) crashes the softsynth. In any case, should - // we ever add this in, remember to call SetFileHook() *after* Start() - // or it won't work. - synth.Start(); + synth.SetFileHook(_StopHook, (int32) this); playing = true; } @@ -540,19 +485,44 @@ void MidiPlayerWindow::StopSynth() //------------------------------------------------------------------------------ +void MidiPlayerWindow::_StopHook(int32 arg) +{ + ((MidiPlayerWindow*) arg)->StopHook(); +} + +//------------------------------------------------------------------------------ + +void MidiPlayerWindow::StopHook() +{ + Lock(); // we may be called from the synth's thread + + playing = false; + + scopeView->SetPlaying(false); + scopeView->Invalidate(); + playButton->SetEnabled(true); + playButton->SetLabel("Play"); + + Unlock(); +} + +//------------------------------------------------------------------------------ + void MidiPlayerWindow::OnPlayStop() { if (playing) { - threadId = spawn_thread( - _StopThread, "StopThread", B_NORMAL_PRIORITY, this); + playButton->SetEnabled(false); - resume_thread(threadId); + StopSynth(); } else { - StartSynth(); playButton->SetLabel("Stop"); + scopeView->SetPlaying(true); + scopeView->Invalidate(); + + StartSynth(); } } @@ -579,7 +549,7 @@ void MidiPlayerWindow::OnInputChanged(BMessage* msg) // be_synth->LoadInstruments(all) // if id != -1 - // if playing -> Stop() // AARGH, need thread! + // if playing -> Stop() // connect SynthBridge (from MidiUtil) to producer endpoint // else if SynthBridge still connected // disconnect SynthBridge @@ -611,12 +581,10 @@ void MidiPlayerWindow::OnVolume() void MidiPlayerWindow::OnDrop(BMessage* msg) { + entry_ref ref; if (msg->FindRef("refs", &ref) == B_OK) { - threadId = spawn_thread( - _LoadThread, "LoadThread", B_NORMAL_PRIORITY, this); - - resume_thread(threadId); + LoadFile(&ref); } } diff --git a/src/apps/midiplayer/MidiPlayerWindow.h b/src/apps/midiplayer/MidiPlayerWindow.h index 358161512e..d305fcc76a 100644 --- a/src/apps/midiplayer/MidiPlayerWindow.h +++ b/src/apps/midiplayer/MidiPlayerWindow.h @@ -68,15 +68,13 @@ private: void LoadSettings(); void SaveSettings(); - static int32 _LoadThread(void* data); - int32 LoadThread(); - - static int32 _StopThread(void* data); - int32 StopThread(); - + void LoadFile(entry_ref* ref); void StartSynth(); void StopSynth(); + static void _StopHook(int32 arg); + void StopHook(); + void OnPlayStop(); void OnShowScope(); void OnInputChanged(BMessage* msg); @@ -101,14 +99,12 @@ private: bool playing; bool scopeEnabled; + int32 inputId; reverb_mode reverb; int32 volume; float windowX; float windowY; BMidiSynthFile synth; - entry_ref ref; - thread_id threadId; - int32 inputId; }; #endif // MIDI_PLAYER_WINDOW_H diff --git a/src/apps/midiplayer/ScopeView.cpp b/src/apps/midiplayer/ScopeView.cpp index a186dc80fc..ba9c514044 100644 --- a/src/apps/midiplayer/ScopeView.cpp +++ b/src/apps/midiplayer/ScopeView.cpp @@ -33,6 +33,7 @@ ScopeView::ScopeView() { SetViewColor(0, 0, 0); + playing = false; enabled = true; haveFile = false; @@ -87,6 +88,10 @@ void ScopeView::Draw(BRect updateRect) { DrawDisabled(); } + else if (!playing) + { + DrawStopped(); + } else { DrawPlaying(); @@ -95,6 +100,13 @@ void ScopeView::Draw(BRect updateRect) //------------------------------------------------------------------------------ +void ScopeView::SetPlaying(bool flag) +{ + playing = flag; +} + +//------------------------------------------------------------------------------ + void ScopeView::SetEnabled(bool flag) { enabled = flag; @@ -124,7 +136,7 @@ int32 ScopeView::Thread() while (!finished) { - if (enabled && haveFile) + if (enabled && playing && haveFile) { if (LockLooperWithTimeout(50000) == B_OK) { @@ -172,6 +184,17 @@ void ScopeView::DrawDisabled() //------------------------------------------------------------------------------ +void ScopeView::DrawStopped() +{ + SetHighColor(0, 130, 0); + + StrokeLine( + BPoint(0, Bounds().Height() / 2), + BPoint(Bounds().Width(), Bounds().Height() / 2)); +} + +//------------------------------------------------------------------------------ + void ScopeView::DrawPlaying() { int32 width = (int32) Bounds().Width(); diff --git a/src/apps/midiplayer/ScopeView.h b/src/apps/midiplayer/ScopeView.h index 28bf09c461..a0451d2af3 100644 --- a/src/apps/midiplayer/ScopeView.h +++ b/src/apps/midiplayer/ScopeView.h @@ -36,6 +36,7 @@ public: virtual void DetachedFromWindow(); virtual void Draw(BRect updateRect); + void SetPlaying(bool flag); void SetEnabled(bool flag); void SetHaveFile(bool flag); @@ -48,9 +49,11 @@ private: void DrawNoFile(); void DrawDisabled(); + void DrawStopped(); void DrawPlaying(); bool finished; + bool playing; bool enabled; bool haveFile; int32 sampleCount; diff --git a/src/apps/midiplayer/readme.html b/src/apps/midiplayer/readme.html index cb5b302eda..d336f580cb 100644 --- a/src/apps/midiplayer/readme.html +++ b/src/apps/midiplayer/readme.html @@ -28,13 +28,10 @@
  • Play and Stop are now one and the same button.
  • There is no Open File... function.
  • You cannot set the Quality of the sound (always 44100 Hz).
  • +
  • While the song fades out, the scope temporarily freezes; the R5 MidiPlayer kept repainting during the fade-out (which, admittedly, looks better). At one point, the Haiku MidiPlayer did that too but the code made my head hurt, so I pulled it out again :-)
  • If people really really want these missing features, then feel free to add them :-)

    -

    Implementation notes

    - -

    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.

    -