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
This commit is contained in:
mahlzeit
2004-06-25 13:17:18 +00:00
parent 7383f6963f
commit b1902a09ef
5 changed files with 75 additions and 88 deletions
+42 -74
View File
@@ -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);
}
}
+5 -9
View File
@@ -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
+24 -1
View File
@@ -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();
+3
View File
@@ -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;
+1 -4
View File
@@ -28,13 +28,10 @@
<li>Play and Stop are now one and the same button.</li>
<li>There is no Open File... function.</li>
<li>You cannot set the Quality of the sound (always 44100 Hz).</li>
<li>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 :-)</li>
</ul>
<p>If people really <i>really</i> want these missing features, then feel free to add them :-)</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>
</html>