From 1827f1ab9bf44490cf24779e0eab8533845b4a77 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sat, 29 Jun 2013 21:46:10 +0200 Subject: New inter-thread message system. --- src/Makefile.am | 4 + src/Makefile.am.drumgizmo | 2 + src/drumgizmo.cc | 219 ++++++++++++++++------------------------------ src/drumgizmo.h | 44 ++-------- src/drumkitloader.cc | 2 +- src/message.h | 19 ++++ src/messagehandler.cc | 88 +++++++++++++++++++ src/messagehandler.h | 66 ++++++++++++++ src/messagereceiver.cc | 79 +++++++++++++++++ src/messagereceiver.h | 74 ++++++++++++++++ 10 files changed, 413 insertions(+), 184 deletions(-) create mode 100644 src/messagehandler.cc create mode 100644 src/messagehandler.h create mode 100644 src/messagereceiver.cc create mode 100644 src/messagereceiver.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 35d052b..75c209c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,8 @@ EXTRA_DIST = \ instrument.h \ instrumentparser.h \ message.h \ + messagehandler.h \ + messagereceiver.h \ midimapparser.h \ midimapper.h \ mutex.h \ @@ -42,6 +44,8 @@ EXTRA_DIST = \ events.cc \ instrument.cc \ instrumentparser.cc \ + messagehandler.cc \ + messagereceiver.cc \ midimapparser.cc \ midimapper.cc \ mutex.cc \ diff --git a/src/Makefile.am.drumgizmo b/src/Makefile.am.drumgizmo index 428d2a7..b1ad862 100644 --- a/src/Makefile.am.drumgizmo +++ b/src/Makefile.am.drumgizmo @@ -11,6 +11,8 @@ DRUMGIZMO_SOURCES = \ $(top_srcdir)/src/events.cc \ $(top_srcdir)/src/instrument.cc \ $(top_srcdir)/src/instrumentparser.cc \ + $(top_srcdir)/src/messagehandler.cc \ + $(top_srcdir)/src/messagereceiver.cc \ $(top_srcdir)/src/midimapparser.cc \ $(top_srcdir)/src/midimapper.cc \ $(top_srcdir)/src/mutex.cc \ diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index b6ac98f..135975d 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -41,7 +41,8 @@ #include "configuration.h" DrumGizmo::DrumGizmo(AudioOutputEngine *o, AudioInputEngine *i) - : loader(this), oe(o), ie(i) + : MessageReceiver(MSGRCV_ENGINE), + loader(this), oe(o), ie(i) { loader.run(); // Start drumkit loader thread. } @@ -59,78 +60,6 @@ DrumGizmo::~DrumGizmo() loader.stop(); } -/* - * Add a message to the GUI message queue. - */ -void DrumGizmo::sendGUIMessage(Message *msg) -{ - MutexAutolock l(gui_message_mutex); - gui_message_queue.push_back(msg); -} - -/* - * Receive message from the engine. The caller takes over the memory. - */ -Message *DrumGizmo::receiveGUIMessage() -{ - MutexAutolock l(gui_message_mutex); - Message *msg = NULL; - if(gui_message_queue.size()) { - msg = gui_message_queue.front(); - gui_message_queue.pop_front(); - } - return msg; -} - -/* - * Receive message from the engine without removing it from the queue. - */ -Message *DrumGizmo::peekGUIMessage() -{ - MutexAutolock l(gui_message_mutex); - Message *msg = NULL; - if(gui_message_queue.size()) { - msg = gui_message_queue.front(); - } - return msg; -} - -/* - * Add a message to the GUI message queue. - */ -void DrumGizmo::sendEngineMessage(Message *msg) -{ - MutexAutolock l(engine_message_mutex); - engine_message_queue.push_back(msg); -} - -/* - * Receive message from the engine. The caller takes over the memory. - */ -Message *DrumGizmo::receiveEngineMessage() -{ - MutexAutolock l(engine_message_mutex); - Message *msg = NULL; - if(engine_message_queue.size()) { - msg = engine_message_queue.front(); - engine_message_queue.pop_front(); - } - return msg; -} - -/* - * Receive message from the engine without removing it from the queue. - */ -Message *DrumGizmo::peekEngineMessage() -{ - MutexAutolock l(engine_message_mutex); - Message *msg = NULL; - if(engine_message_queue.size()) { - msg = engine_message_queue.front(); - } - return msg; -} - std::string DrumGizmo::drumkitfile() { return kitfile; @@ -181,86 +110,88 @@ bool DrumGizmo::init(bool preload) return true; } -void DrumGizmo::handleEngineEvents() +void DrumGizmo::handleMessage(Message *msg) { - Message *msg = receiveEngineMessage(); - if(msg) { - DEBUG(msg, "got message."); - switch(msg->type()) { - case Message::LoadDrumKit: - { - DEBUG(msg, "got LoadDrumKitMessage message."); - LoadDrumKitMessage *m = (LoadDrumKitMessage*)msg; - loadkit(m->drumkitfile); - //init(true); - } - break; - case Message::LoadMidimap: - DEBUG(msg, "got LoadMidimapMessage message."); - if(!ie->isMidiEngine()) break; - { + DEBUG(msg, "got message."); + switch(msg->type()) { + case Message::RegisterUIMessage: + { + DEBUG(msg, "got RegisterUIMessage message."); + RegisterUIMessage *m = (RegisterUIMessage*)msg; + ui = m->messagehandler; + } + break; + case Message::LoadDrumKit: + { + DEBUG(msg, "got LoadDrumKitMessage message."); + LoadDrumKitMessage *m = (LoadDrumKitMessage*)msg; + loadkit(m->drumkitfile); + //init(true); + } + break; + case Message::LoadMidimap: + DEBUG(msg, "got LoadMidimapMessage message."); + if(!ie->isMidiEngine()) break; + { + AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; + LoadMidimapMessage *m = (LoadMidimapMessage*)msg; + bool ret = aim->loadMidiMap(m->midimapfile, kit.instruments); + + LoadStatusMessageMidimap *ls = new LoadStatusMessageMidimap(); + ls->success = ret; + msghandler.sendMessage(MSGRCV_UI, ls); + } + break; + case Message::EngineSettingsMessage: + { + DEBUG(msg, "--------------- Send: EngineSettingsMessage ------------ \n"); + + bool mmap_loaded = false; + std::string mmapfile; + if(ie->isMidiEngine()) { AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; - LoadMidimapMessage *m = (LoadMidimapMessage*)msg; - bool ret = aim->loadMidiMap(m->midimapfile, kit.instruments); - - LoadStatusMessageMidimap *ls = new LoadStatusMessageMidimap(); - ls->success = ret; - sendGUIMessage(ls); - } - break; - case Message::EngineSettingsMessage: - { - DEBUG(msg, "--------------- Send: EngineSettingsMessage --------------- \n"); - - bool mmap_loaded = false; - std::string mmapfile; - if(ie->isMidiEngine()) { - AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; - mmapfile = aim->midimapFile(); - mmap_loaded = aim->isValid(); - - } - - EngineSettingsMessage *msg = new EngineSettingsMessage(); - msg->midimapfile = mmapfile; - msg->midimap_loaded = mmap_loaded; - msg->drumkitfile = drumkitfile(); - msg->drumkit_loaded = loader.isDone(); - msg->enable_velocity_modifier = Conf::enable_velocity_modifier; - msg->velocity_modifier_falloff = Conf::velocity_modifier_falloff; - msg->velocity_modifier_weight = Conf::velocity_modifier_weight; - msg->enable_velocity_randomiser = Conf::enable_velocity_randomiser; - msg->velocity_randomiser_weight = Conf::velocity_randomiser_weight; - sendGUIMessage(msg); + mmapfile = aim->midimapFile(); + mmap_loaded = aim->isValid(); } - break; - case Message::ChangeSettingMessage: - { - ChangeSettingMessage *ch = (ChangeSettingMessage*)msg; - switch(ch->name) { - case ChangeSettingMessage::enable_velocity_modifier: - Conf::enable_velocity_modifier = ch->value; - break; - case ChangeSettingMessage::velocity_modifier_weight: - Conf::velocity_modifier_weight = ch->value; - break; - case ChangeSettingMessage::velocity_modifier_falloff: - Conf::velocity_modifier_falloff = ch->value; - break; - } + + EngineSettingsMessage *msg = new EngineSettingsMessage(); + msg->midimapfile = mmapfile; + msg->midimap_loaded = mmap_loaded; + msg->drumkitfile = drumkitfile(); + msg->drumkit_loaded = loader.isDone(); + msg->enable_velocity_modifier = Conf::enable_velocity_modifier; + msg->velocity_modifier_falloff = Conf::velocity_modifier_falloff; + msg->velocity_modifier_weight = Conf::velocity_modifier_weight; + msg->enable_velocity_randomiser = Conf::enable_velocity_randomiser; + msg->velocity_randomiser_weight = Conf::velocity_randomiser_weight; + msghandler.sendMessage(MSGRCV_UI, msg); + } + break; + case Message::ChangeSettingMessage: + { + ChangeSettingMessage *ch = (ChangeSettingMessage*)msg; + switch(ch->name) { + case ChangeSettingMessage::enable_velocity_modifier: + Conf::enable_velocity_modifier = ch->value; + break; + case ChangeSettingMessage::velocity_modifier_weight: + Conf::velocity_modifier_weight = ch->value; + break; + case ChangeSettingMessage::velocity_modifier_falloff: + Conf::velocity_modifier_falloff = ch->value; + break; } - break; - default: - break; } - delete msg; + break; + default: + break; } } bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) { // Handle engine messages, at most one in each iteration: - handleEngineEvents(); + handleMessages(1); ie->pre(); oe->pre(nsamples); @@ -609,7 +540,7 @@ bool DrumGizmo::setConfigString(std::string cfg) */ LoadDrumKitMessage *msg = new LoadDrumKitMessage(); msg->drumkitfile = newkit; - sendEngineMessage(msg); + msghandler.sendMessage(MSGRCV_ENGINE, msg); } std::string newmidimap = p.value("midimapfile"); @@ -617,7 +548,7 @@ bool DrumGizmo::setConfigString(std::string cfg) //midimapfile = newmidimap; LoadMidimapMessage *msg = new LoadMidimapMessage(); msg->midimapfile = newmidimap; - sendEngineMessage(msg); + msghandler.sendMessage(MSGRCV_ENGINE, msg); } return true; diff --git a/src/drumgizmo.h b/src/drumgizmo.h index ffb9b07..31c192c 100644 --- a/src/drumgizmo.h +++ b/src/drumgizmo.h @@ -43,9 +43,11 @@ #include "message.h" +#include "messagereceiver.h" + #define MAX_NUM_CHANNELS 512 -class DrumGizmo { +class DrumGizmo : public MessageReceiver { public: DrumGizmo(AudioOutputEngine *outputengine, AudioInputEngine *inputengine); @@ -69,50 +71,14 @@ public: std::string kitfile; - /* - * Receive message from the engine. The caller takes over the memory. - */ - Message *receiveGUIMessage(); - - /* - * Receive message from the engine without removing it from the queue. - */ - Message *peekGUIMessage(); - - /* - * Add a message to the GUI message queue. - */ - void sendEngineMessage(Message *msg); - - /* - * Receive message from the engine. The caller takes over the memory. - */ - Message *receiveEngineMessage(); - - /* - * Receive message from the engine without removing it from the queue. - */ - Message *peekEngineMessage(); - - /* - * Add a message to the GUI message queue. - */ - void sendGUIMessage(Message *msg); + void handleMessage(Message *msg); private: - void handleEngineEvents(); - - Mutex gui_message_mutex; - std::list gui_message_queue; - - Mutex engine_message_mutex; - std::list engine_message_queue; - DrumKitLoader loader; Mutex mutex; bool is_running; - + AudioOutputEngine *oe; AudioInputEngine *ie; diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc index 41b56a1..a7a8989 100644 --- a/src/drumkitloader.cc +++ b/src/drumkitloader.cc @@ -191,7 +191,7 @@ void DrumKitLoader::thread_main() ls->number_of_files = count; ls->numer_of_files_loaded = loaded; ls->current_file = af->filename; - drumgizmo->sendGUIMessage(ls); + msghandler.sendMessage(MSGRCV_UI, ls); a++; diff --git a/src/message.h b/src/message.h index 4ce65ef..d51c263 100644 --- a/src/message.h +++ b/src/message.h @@ -27,6 +27,10 @@ #ifndef __DRUMGIZMO_MESSAGE_H__ #define __DRUMGIZMO_MESSAGE_H__ +#include + +class MessageHandler; + class Message { public: typedef enum { @@ -39,15 +43,24 @@ public: LoadMidimap, // Signal engine to load midimap. EngineSettingsMessage, // Request or receive engine settings. ChangeSettingMessage, // Update named setting in engine. + RegisterUIMessage, // Register new UI message handler } type_t; + typedef enum { + NormalProcessing, // Just add to the queue + FilterMultiple, // Ignore top message if it has the same type. + // SyncWait, // Block the send call until the message has been handled by the receiver. + } processing_mode_t; + virtual ~Message() {} virtual type_t type() = 0; + virtual processing_mode_t processing_mode() { return NormalProcessing; } }; class LoadStatusMessage : public Message { public: type_t type() { return Message::LoadStatus; } + processing_mode_t processing_mode() { return FilterMultiple; } unsigned int number_of_files; unsigned int numer_of_files_loaded; std::string current_file; @@ -106,4 +119,10 @@ public: float value; }; +class RegisterUIMessage : public Message { +public: + type_t type() { return Message::RegisterUIMessage; } + MessageHandler *messagehandler; +}; + #endif/*__DRUMGIZMO_MESSAGE_H__*/ diff --git a/src/messagehandler.cc b/src/messagehandler.cc new file mode 100644 index 0000000..a5a71f1 --- /dev/null +++ b/src/messagehandler.cc @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * messagehandler.cc + * + * Fri Jun 14 20:30:43 CEST 2013 + * Copyright 2013 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DrumGizmo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "messagehandler.h" + +#include + +#include "messagereceiver.h" + +// Global messagehandler: +MessageHandler msghandler; + +MessageHandler::MessageHandler() +{ +} + +void MessageHandler::addReceiver(message_receiver_id_t id, + MessageReceiver *receiver) +{ + MutexAutolock l(mutex); + + receivers[id] = receiver; +} + +void MessageHandler::removeReceiver(MessageReceiver *receiver) +{ + MutexAutolock l(mutex); + + std::map::iterator i = + receivers.begin(); + while(i != receivers.end()) { + if(i->second == receiver) { + receivers.erase(i); + break; + } + i++; + } +} + +bool MessageHandler::sendMessage(message_receiver_id_t id, Message* msg) +{ + MutexAutolock l(mutex); + + if(receivers.find(id) == receivers.end()) { + WARN(msghandler, "Could not find id %d\n", id); + delete msg; + return false; + } + + DEBUG(msghandler, "Sending message to id %d\n", id); + + MessageReceiver *receiver = receivers[id]; + + if(msg->processing_mode() == Message::FilterMultiple) { + Message *pmsg; + while( (pmsg = receiver->peekMessage()) != NULL) { + if(pmsg->type() != Message::LoadStatus) break; + delete msg; + msg = receiver->receiveMessage(); + } + } + + receiver->sendMessage(msg); + return true; +} diff --git a/src/messagehandler.h b/src/messagehandler.h new file mode 100644 index 0000000..9812777 --- /dev/null +++ b/src/messagehandler.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * messagehandler.h + * + * Fri Jun 14 20:30:43 CEST 2013 + * Copyright 2013 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DrumGizmo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __DRUMGIZMO_MESSAGEHANDLER_H__ +#define __DRUMGIZMO_MESSAGEHANDLER_H__ + +#include + +#include "message.h" +#include "mutex.h" + +typedef enum { + MSGRCV_ENGINE = 1, + MSGRCV_UI = 2, + MSGRCV_LOADER = 3, +} message_receiver_id_t; + +class MessageReceiver; + +class MessageHandler { +public: + MessageHandler(); + + void addReceiver(message_receiver_id_t id, MessageReceiver *receiver); + void removeReceiver(MessageReceiver *receiver); + + /** + * Send Message to receiver with specified id. + * @return Return true if id is registered. Return false if id is not + * currently registered. + */ + bool sendMessage(message_receiver_id_t id, Message* msg); + +private: + std::map receivers; + + Mutex mutex; +}; + +// Global MessageHandler; +extern MessageHandler msghandler; + +#endif/*__DRUMGIZMO_MESSAGEHANDLER_H__*/ diff --git a/src/messagereceiver.cc b/src/messagereceiver.cc new file mode 100644 index 0000000..f391aad --- /dev/null +++ b/src/messagereceiver.cc @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * messagereceiver.cc + * + * Sun Jun 16 12:09:06 CEST 2013 + * Copyright 2013 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DrumGizmo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "messagereceiver.h" + +#include + +MessageReceiver::MessageReceiver(message_receiver_id_t id) +{ + msghandler.addReceiver(id, this); +} + +MessageReceiver::~MessageReceiver() +{ + msghandler.removeReceiver(this); +} + +void MessageReceiver::sendMessage(Message *msg) +{ + MutexAutolock l(message_mutex); + + message_queue.push_back(msg); +} + +Message *MessageReceiver::receiveMessage() +{ + MutexAutolock l(message_mutex); + Message *msg = NULL; + if(message_queue.size()) { + msg = message_queue.front(); + message_queue.pop_front(); + } + return msg; +} + +Message *MessageReceiver::peekMessage() +{ + MutexAutolock l(message_mutex); + Message *msg = NULL; + if(message_queue.size()) { + msg = message_queue.front(); + } + return msg; +} + +void MessageReceiver::handleMessages(size_t max) +{ + bool process_all = false; + if(max == 0) process_all = true; + + while((process_all || max--) && peekMessage()) { + Message *msg = receiveMessage(); + handleMessage(msg); + delete msg; + } +} diff --git a/src/messagereceiver.h b/src/messagereceiver.h new file mode 100644 index 0000000..4185f29 --- /dev/null +++ b/src/messagereceiver.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * messagereceiver.h + * + * Sun Jun 16 12:09:06 CEST 2013 + * Copyright 2013 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DrumGizmo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __DRUMGIZMO_MESSAGERECEIVER_H__ +#define __DRUMGIZMO_MESSAGERECEIVER_H__ + +#include + +#include "mutex.h" +#include "message.h" +#include "messagehandler.h" + +class MessageReceiver { +public: + MessageReceiver(message_receiver_id_t id); + ~MessageReceiver(); + + /** + * Receive message from the message queue. + */ + Message *receiveMessage(); + + /** + * Receive message from the message queue without removing it. + */ + Message *peekMessage(); + + /** + * Add a message to the message queue. + */ + void sendMessage(Message *msg); + + /** + * Handle messages from the event queue. + * @param max_number_of_events the maximum number of events to be handled in + * this call. 0 means all. + */ + void handleMessages(size_t max_number_of_events = 0); + + /** + * Handler to be implemented in child classes. + * Handles a single event. + */ + virtual void handleMessage(Message *msg) = 0; + +private: + Mutex message_mutex; + std::list message_queue; +}; + +#endif/*__DRUMGIZMO_MESSAGERECEIVER_H__*/ -- cgit v1.2.3