diff --git a/src/contrib/mp3decoder/Mp3Decoder.cpp b/src/contrib/mp3decoder/Mp3Decoder.cpp index 3c44703d6..68a4cabdc 100644 --- a/src/contrib/mp3decoder/Mp3Decoder.cpp +++ b/src/contrib/mp3decoder/Mp3Decoder.cpp @@ -68,6 +68,7 @@ Mp3Decoder::Mp3Decoder() } Mp3Decoder::~Mp3Decoder() { + delete decoder; } unsigned long Mp3Decoder::GetID3HeaderLength(unsigned char * buffer) { diff --git a/src/contrib/waveout/WaveOut.cpp b/src/contrib/waveout/WaveOut.cpp index 93c18ff22..334bfd7b5 100644 --- a/src/contrib/waveout/WaveOut.cpp +++ b/src/contrib/waveout/WaveOut.cpp @@ -53,10 +53,30 @@ WaveOut::WaveOut() } WaveOut::~WaveOut() { - this->Stop(); } void WaveOut::Destroy() { + { + boost::recursive_mutex::scoped_lock lock(this->outputDeviceMutex); + + /* reset playback immediately. this will invalidate all pending + buffers */ + if (this->waveHandle != NULL) { + waveOutReset(this->waveHandle); + } + + /* stop the thread so nothing else is processed */ + this->StopWaveOutThread(); + + /* close it down after the threadproc has finished */ + if (this->waveHandle != NULL) { + waveOutClose(this->waveHandle); + this->waveHandle = NULL; + } + } + + this->ClearBufferQueue(); + delete this; } @@ -79,28 +99,25 @@ void WaveOut::SetVolume(double volume) { } void WaveOut::Stop() { - boost::recursive_mutex::scoped_lock lock(this->outputDeviceMutex); + { + boost::recursive_mutex::scoped_lock lock(this->outputDeviceMutex); - /* reset waveout first. if we don't do this, it seems like it'll still - try to send events to the thread, and fail with a runtime exception. */ - if (this->waveHandle != NULL) { - waveOutReset(this->waveHandle); + if (this->waveHandle != NULL) { + waveOutReset(this->waveHandle); + } } - /* stop the thread so nothing else is processed */ - this->StopWaveOutThread(); + this->ClearBufferQueue(); +} - /* dealloc the handle, we'll create a new one later if we need to... */ - if (this->waveHandle != NULL) { - waveOutClose(this->waveHandle); - this->waveHandle = NULL; - } +void WaveOut::ClearBufferQueue() { + boost::recursive_mutex::scoped_lock lock(this->bufferQueueMutex); /* notify and free any pending buffers, the Player in the core will be waiting for all pending buffers to be processed. */ if (this->queuedBuffers.size() > 0) { BufferList::iterator it = this->queuedBuffers.begin(); - for (; it != this->queuedBuffers.end(); ++it) { + for (; it != this->queuedBuffers.end(); it++) { notifyBufferProcessed((*it).get()); } @@ -110,14 +127,13 @@ void WaveOut::Stop() { void WaveOut::OnBufferWrittenToOutput(WaveOutBuffer *buffer) { boost::recursive_mutex::scoped_lock lock(this->bufferQueueMutex); - - notifyBufferProcessed(buffer); - + /* removed the buffer. it should be at the front of the queue. */ BufferList::iterator it = this->queuedBuffers.begin(); - for( ; it != this->queuedBuffers.end(); ++it) { + for( ; it != this->queuedBuffers.end(); it++) { if (it->get() == buffer) { - it = this->queuedBuffers.erase(it); + notifyBufferProcessed(buffer); + this->queuedBuffers.erase(it); return; } } diff --git a/src/contrib/waveout/WaveOut.h b/src/contrib/waveout/WaveOut.h index e311bcf6b..3eacc3b40 100644 --- a/src/contrib/waveout/WaveOut.h +++ b/src/contrib/waveout/WaveOut.h @@ -65,6 +65,7 @@ class WaveOut : public IOutput { void SetFormat(IBuffer *buffer); void StartWaveOutThread(); void StopWaveOutThread(); + void ClearBufferQueue(); protected: friend class WaveOutBuffer; diff --git a/src/core/playback/Transport.cpp b/src/core/playback/Transport.cpp index b7e8249d2..c4242b3f0 100644 --- a/src/core/playback/Transport.cpp +++ b/src/core/playback/Transport.cpp @@ -82,7 +82,6 @@ void Transport::Start(const std::string& url) { musik::debug::info(TAG, "we were asked to start the track at " + url); Player* newPlayer = new Player(url); - newPlayer->SetVolume(this->volume); musik::debug::info(TAG, "Player created successfully"); this->StartWithPlayer(newPlayer); @@ -108,6 +107,7 @@ void Transport::StartWithPlayer(Player* newPlayer) { musik::debug::info(TAG, "play()"); this->active.push_front(newPlayer); + newPlayer->SetVolume(this->volume); newPlayer->Play(); } @@ -193,7 +193,8 @@ void Transport::SetPosition(double seconds) { boost::recursive_mutex::scoped_lock lock(this->stateMutex); if (!this->active.empty()) { - return this->active.front()->SetPosition(seconds); + this->active.front()->SetPosition(seconds); + this->TimeChanged(seconds); } } diff --git a/src/core/playback/Transport.h b/src/core/playback/Transport.h index 291538204..48ccf2b4e 100644 --- a/src/core/playback/Transport.h +++ b/src/core/playback/Transport.h @@ -47,6 +47,7 @@ namespace musik { namespace core { namespace audio { sigslot::signal2 StreamEvent; sigslot::signal1 PlaybackEvent; sigslot::signal0<> VolumeChanged; + sigslot::signal1 TimeChanged; typedef enum { PlaybackStopped, diff --git a/src/core/sdk/IBuffer.h b/src/core/sdk/IBuffer.h index e80e5cb4a..332a0fe93 100644 --- a/src/core/sdk/IBuffer.h +++ b/src/core/sdk/IBuffer.h @@ -39,58 +39,13 @@ namespace musik { namespace core { namespace audio { class IBuffer { public: - ////////////////////////////////////////// - ///\brief - ///Get the samplerate of the buffer - ////////////////////////////////////////// virtual long SampleRate() const = 0; - - ////////////////////////////////////////// - ///\brief - ///Set the buffers samplerate - ////////////////////////////////////////// virtual void SetSampleRate(long sampleRate) = 0; - - ////////////////////////////////////////// - ///\brief - ///Get the number of channels of the buffer - ////////////////////////////////////////// virtual int Channels() const = 0; - - ////////////////////////////////////////// - ///\brief - ///Set the number of channels of the buffer - ////////////////////////////////////////// virtual void SetChannels(int channels) = 0; - - ////////////////////////////////////////// - ///\brief - ///Get the pointer to the real buffer. - /// - ///The pointer may change when you set any of the buffers - ///properties like samplerate, samples and channels - ////////////////////////////////////////// virtual float* BufferPointer() const = 0; - - ////////////////////////////////////////// - ///\brief - ///Get the number of samples in the buffer - /// - ///To clairify, one sample = one sample for each channel - ///and that means that one sample = sizeof(float)*channels bytes big - ////////////////////////////////////////// virtual long Samples() const = 0; - - ////////////////////////////////////////// - ///\brief - ///Set the number of samples in the buffer - ////////////////////////////////////////// virtual void SetSamples(long samples) = 0; - - ////////////////////////////////////////// - ///\brief - ///How many bytes does this object take - ////////////////////////////////////////// virtual long Bytes() const = 0; }; diff --git a/src/core/sdk/IBufferProvider.h b/src/core/sdk/IBufferProvider.h index 86ed7eb36..8fe7742cc 100644 --- a/src/core/sdk/IBufferProvider.h +++ b/src/core/sdk/IBufferProvider.h @@ -38,19 +38,12 @@ namespace musik { namespace core { namespace audio { - ////////////////////////////////////////// - ///\brief - ///Interface for the audio::Player to make IOuput plugins be able to make callbacks - ////////////////////////////////////////// class IBufferProvider { public: virtual ~IBufferProvider() = 0 { } - ////////////////////////////////////////// - ///\brief - ///Release used by the output to notify the player a buffer has finished - ///processing. - ////////////////////////////////////////// + /* the output calls this interface to let the provider know + it's done with the Buffer, so it can be recycled or released */ virtual void OnBufferProcessed(IBuffer *buffer) = 0; }; diff --git a/src/musikbox/Main.cpp b/src/musikbox/Main.cpp index 424cfb192..71f0240f5 100644 --- a/src/musikbox/Main.cpp +++ b/src/musikbox/Main.cpp @@ -163,6 +163,7 @@ int main(int argc, char* argv[]) #ifdef __PDCURSES__ PDC_set_title("musikbox ♫"); + PDC_set_function_key(FUNCTION_KEY_SHUT_DOWN, 4); #endif { diff --git a/src/musikbox/app/util/GlobalHotkeys.cpp b/src/musikbox/app/util/GlobalHotkeys.cpp index 1a86cfb4f..01b1831d1 100755 --- a/src/musikbox/app/util/GlobalHotkeys.cpp +++ b/src/musikbox/app/util/GlobalHotkeys.cpp @@ -24,6 +24,7 @@ bool GlobalHotkeys::Handle(int64 ch) { else if (state == Transport::PlaybackPlaying) { this->transport.Pause(); } + return true; } if (kn == "ALT_I") { this->transport.SetVolume(this->transport.Volume() + 0.05); /* 5% */ @@ -35,20 +36,25 @@ bool GlobalHotkeys::Handle(int64 ch) { } else if (kn == "ALT_J") { this->playback.Previous(); + return true; } else if (kn == "ALT_L") { this->playback.Next(); + return true; } else if (kn == "ALT_U") { double time = this->transport.Position(); this->transport.SetPosition(time - 10.0f); + return true; } else if (kn == "ALT_O") { double time = this->transport.Position(); this->transport.SetPosition(time + 10.0f); + return true; } else if (kn == "^R") { library->Indexer()->Synchronize(true); + return true; } return false; diff --git a/src/musikbox/app/window/TransportWindow.cpp b/src/musikbox/app/window/TransportWindow.cpp index 5f4b402d2..661350d9c 100755 --- a/src/musikbox/app/window/TransportWindow.cpp +++ b/src/musikbox/app/window/TransportWindow.cpp @@ -32,7 +32,7 @@ using namespace boost::chrono; #define REFRESH_TRANSPORT_READOUT 1001 #define REFRESH_INTERVAL_MS 1000 -#define SCHEDULE_REFRESH(x) \ +#define DEBOUNCE_REFRESH(x) \ this->RemoveMessage(REFRESH_TRANSPORT_READOUT); \ this->PostMessage(REFRESH_TRANSPORT_READOUT, 0, 0, x); @@ -45,6 +45,7 @@ TransportWindow::TransportWindow(LibraryPtr library, Transport& transport) this->transport = &transport; this->transport->StreamEvent.connect(this, &TransportWindow::OnTransportStreamEvent); this->transport->VolumeChanged.connect(this, &TransportWindow::OnTransportVolumeChanged); + this->transport->TimeChanged.connect(this, &TransportWindow::OnTransportTimeChanged); this->paused = false; } @@ -61,7 +62,7 @@ void TransportWindow::ProcessMessage(IMessage &message) { if (type == REFRESH_TRANSPORT_READOUT) { this->Update(); - SCHEDULE_REFRESH(REFRESH_INTERVAL_MS) + DEBOUNCE_REFRESH(REFRESH_INTERVAL_MS) } } @@ -69,18 +70,22 @@ void TransportWindow::OnTransportStreamEvent(int eventType, std::string url) { if (eventType == Transport::StreamPlaying) { this->trackQuery.reset(new SingleTrackQuery(url)); this->library->Enqueue(this->trackQuery); - SCHEDULE_REFRESH(0) + DEBOUNCE_REFRESH(0); } } void TransportWindow::OnTransportVolumeChanged() { - SCHEDULE_REFRESH(0) + DEBOUNCE_REFRESH(0) +} + +void TransportWindow::OnTransportTimeChanged(double time) { + DEBOUNCE_REFRESH(0) } void TransportWindow::OnQueryCompleted(QueryPtr query) { if (query == this->trackQuery && query->GetStatus() == QueryBase::Finished) { this->currentTrack = this->trackQuery->GetResult(); - SCHEDULE_REFRESH(0) + DEBOUNCE_REFRESH(0) } } diff --git a/src/musikbox/app/window/TransportWindow.h b/src/musikbox/app/window/TransportWindow.h index f950ec99b..65cfe410f 100755 --- a/src/musikbox/app/window/TransportWindow.h +++ b/src/musikbox/app/window/TransportWindow.h @@ -25,6 +25,7 @@ class TransportWindow : public Window, public sigslot::has_slots<> { private: void OnTransportStreamEvent(int eventType, std::string url); void OnTransportVolumeChanged(); + void OnTransportTimeChanged(double time); void OnQueryCompleted(QueryPtr query); bool paused; diff --git a/src/musikbox/cursespp/SimpleScrollAdapter.cpp b/src/musikbox/cursespp/SimpleScrollAdapter.cpp index 92850df0f..31a43238f 100755 --- a/src/musikbox/cursespp/SimpleScrollAdapter.cpp +++ b/src/musikbox/cursespp/SimpleScrollAdapter.cpp @@ -11,10 +11,6 @@ typedef IScrollAdapter::EntryPtr EntryPtr; SimpleScrollAdapter::SimpleScrollAdapter() { - /* the adapters can have a maximum size. as we remove elements from - the back, we don't want to re-index everything. instead, we'll use - this offset for future calculations when searching for items. */ - this->removedOffset = 0; this->maxEntries = MAX_ENTRY_COUNT; } diff --git a/src/musikbox/cursespp/SimpleScrollAdapter.h b/src/musikbox/cursespp/SimpleScrollAdapter.h index 0f97f4d7e..8ede4b6b0 100755 --- a/src/musikbox/cursespp/SimpleScrollAdapter.h +++ b/src/musikbox/cursespp/SimpleScrollAdapter.h @@ -20,6 +20,5 @@ class SimpleScrollAdapter : public ScrollAdapterBase { typedef EntryList::iterator Iterator; EntryList entries; - size_t removedOffset; size_t maxEntries; };