From 98fe0e7056e6697396249531785d3899f94d79be Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 10 Jun 2006 01:52:02 +0000 Subject: More juggling git-svn-id: http://svn.drobilla.net/lad/grauph@15 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/AlsaMidiDriver.cpp | 373 --------- src/engine/AlsaMidiDriver.h | 127 --- src/engine/Array.h | 109 --- src/engine/AudioDriver.h | 50 -- src/engine/AudioInputNode.cpp | 49 -- src/engine/AudioInputNode.h | 45 - src/engine/AudioOutputNode.cpp | 50 -- src/engine/AudioOutputNode.h | 44 - src/engine/BridgeNode.cpp | 159 ---- src/engine/BridgeNode.h | 90 -- src/engine/Buffer.cpp | 297 ------- src/engine/Buffer.h | 91 -- src/engine/ClientBroadcaster.cpp | 331 -------- src/engine/ClientBroadcaster.h | 101 --- src/engine/Connection.cpp | 45 - src/engine/Connection.h | 66 -- src/engine/ConnectionBase.cpp | 96 --- src/engine/ConnectionBase.h | 105 --- src/engine/ControlInputNode.cpp | 49 -- src/engine/ControlInputNode.h | 44 - src/engine/ControlOutputNode.cpp | 48 -- src/engine/ControlOutputNode.h | 45 - src/engine/Controller.h | 82 -- src/engine/DSSIPlugin.cpp | 340 -------- src/engine/DSSIPlugin.cpp.orig | 207 ----- src/engine/DSSIPlugin.h | 109 --- src/engine/DSSIPlugin.h.orig | 84 -- src/engine/Driver.h | 112 --- src/engine/Event.cpp | 48 -- src/engine/Event.h | 71 -- src/engine/EventSource.h | 52 -- src/engine/InputPort.cpp | 352 -------- src/engine/InputPort.h | 88 -- src/engine/InternalNode.h | 70 -- src/engine/JackAudioDriver.cpp | 373 --------- src/engine/JackAudioDriver.h | 176 ---- src/engine/JackMidiDriver.cpp | 217 ----- src/engine/JackMidiDriver.h | 123 --- src/engine/LADSPAPlugin.cpp | 274 ------ src/engine/LADSPAPlugin.h | 69 -- src/engine/LV2Plugin.cpp | 275 ------ src/engine/LV2Plugin.h | 76 -- src/engine/LashDriver.cpp | 159 ---- src/engine/LashDriver.h | 57 -- src/engine/List.h | 416 --------- src/engine/Maid.cpp | 46 - src/engine/Maid.h | 65 -- src/engine/MaidObject.h | 38 - src/engine/Makefile.am | 259 ------ src/engine/MidiControlNode.cpp | 133 --- src/engine/MidiControlNode.h | 72 -- src/engine/MidiDriver.h | 78 -- src/engine/MidiInputNode.cpp | 49 -- src/engine/MidiInputNode.h | 43 - src/engine/MidiMessage.h | 51 -- src/engine/MidiNoteNode.cpp | 304 ------- src/engine/MidiNoteNode.h | 87 -- src/engine/MidiOutputNode.cpp | 49 -- src/engine/MidiOutputNode.h | 43 - src/engine/MidiTriggerNode.cpp | 124 --- src/engine/MidiTriggerNode.h | 64 -- src/engine/Node.h | 120 --- src/engine/NodeBase.cpp | 171 ---- src/engine/NodeBase.h | 105 --- src/engine/NodeFactory.cpp | 707 ---------------- src/engine/NodeFactory.h | 93 --- src/engine/OSCClient.cpp | 503 ----------- src/engine/OSCClient.h | 131 --- src/engine/OSCReceiver.cpp | 926 --------------------- src/engine/OSCReceiver.h | 124 --- src/engine/OSCResponder.cpp | 88 -- src/engine/OSCResponder.h | 61 -- src/engine/ObjectSender.cpp | 207 ----- src/engine/ObjectSender.h | 55 -- src/engine/ObjectStore.cpp | 109 --- src/engine/ObjectStore.h | 61 -- src/engine/Om.cpp | 36 - src/engine/Om.h | 42 - src/engine/OmApp.cpp | 231 ----- src/engine/OmApp.h | 99 --- src/engine/OmInProcess.cpp | 74 -- src/engine/OmObject.h | 115 --- src/engine/OutputPort.cpp | 51 -- src/engine/OutputPort.h | 64 -- src/engine/Patch.cpp | 356 -------- src/engine/Patch.h | 136 --- src/engine/Plugin.h | 149 ---- src/engine/PluginLibrary.h | 100 --- src/engine/Port.cpp | 56 -- src/engine/Port.h | 80 -- src/engine/PortBase.cpp | 133 --- src/engine/PortBase.h | 87 -- src/engine/PortInfo.h | 153 ---- src/engine/PostProcessor.cpp | 122 --- src/engine/PostProcessor.h | 78 -- src/engine/QueuedEngineInterface.cpp | 299 ------- src/engine/QueuedEngineInterface.h | 145 ---- src/engine/QueuedEvent.h | 86 -- src/engine/QueuedEventSource.cpp | 201 ----- src/engine/QueuedEventSource.h | 83 -- src/engine/Responder.h | 63 -- src/engine/TransportNode.cpp | 155 ---- src/engine/TransportNode.h | 48 -- src/engine/Tree.h | 155 ---- src/engine/TreeImplementation.h | 410 --------- src/engine/cmdline.c | 150 ---- src/engine/cmdline.ggo | 7 - src/engine/cmdline.h | 45 - src/engine/events.h | 62 -- src/engine/events/ActivateEvent.cpp | 52 -- src/engine/events/ActivateEvent.h | 41 - src/engine/events/AddNodeEvent.cpp | 128 --- src/engine/events/AddNodeEvent.h | 63 -- src/engine/events/AllNotesOffEvent.cpp | 67 -- src/engine/events/AllNotesOffEvent.h | 50 -- src/engine/events/ClearPatchEvent.cpp | 114 --- src/engine/events/ClearPatchEvent.h | 54 -- src/engine/events/ConnectionEvent.cpp | 240 ------ src/engine/events/ConnectionEvent.h | 107 --- src/engine/events/CreatePatchEvent.cpp | 150 ---- src/engine/events/CreatePatchEvent.h | 64 -- src/engine/events/DSSIConfigureEvent.cpp | 73 -- src/engine/events/DSSIConfigureEvent.h | 49 -- src/engine/events/DSSIControlEvent.cpp | 68 -- src/engine/events/DSSIControlEvent.h | 51 -- src/engine/events/DSSIProgramEvent.cpp | 77 -- src/engine/events/DSSIProgramEvent.h | 49 -- src/engine/events/DSSIUpdateEvent.cpp | 80 -- src/engine/events/DSSIUpdateEvent.h | 54 -- src/engine/events/DeactivateEvent.cpp | 54 -- src/engine/events/DeactivateEvent.h | 42 - src/engine/events/DestroyEvent.cpp | 168 ---- src/engine/events/DestroyEvent.h | 68 -- src/engine/events/DisablePatchEvent.cpp | 70 -- src/engine/events/DisablePatchEvent.h | 52 -- src/engine/events/DisconnectNodeEvent.cpp | 140 ---- src/engine/events/DisconnectNodeEvent.h | 68 -- src/engine/events/DisconnectPortEvent.cpp | 145 ---- src/engine/events/DisconnectPortEvent.h | 70 -- src/engine/events/DisconnectionEvent.cpp | 295 ------- src/engine/events/DisconnectionEvent.h | 106 --- src/engine/events/EnablePatchEvent.cpp | 82 -- src/engine/events/EnablePatchEvent.h | 56 -- src/engine/events/LashRestoreDoneEvent.h | 54 -- src/engine/events/LoadPluginsEvent.cpp | 44 - src/engine/events/LoadPluginsEvent.h | 40 - src/engine/events/Makefile.am | 67 -- src/engine/events/MidiLearnEvent.cpp | 88 -- src/engine/events/MidiLearnEvent.h | 84 -- src/engine/events/NoteOffEvent.cpp | 78 -- src/engine/events/NoteOffEvent.h | 52 -- src/engine/events/NoteOnEvent.cpp | 89 -- src/engine/events/NoteOnEvent.h | 54 -- src/engine/events/PingQueuedEvent.h | 44 - src/engine/events/RegisterClientEvent.cpp | 53 -- src/engine/events/RegisterClientEvent.h | 53 -- src/engine/events/RenameEvent.cpp | 123 --- src/engine/events/RenameEvent.h | 66 -- src/engine/events/RequestAllObjectsEvent.cpp | 55 -- src/engine/events/RequestAllObjectsEvent.h | 50 -- src/engine/events/RequestMetadataEvent.cpp | 80 -- src/engine/events/RequestMetadataEvent.h | 56 -- src/engine/events/RequestPluginsEvent.cpp | 55 -- src/engine/events/RequestPluginsEvent.h | 51 -- src/engine/events/RequestPortValueEvent.cpp | 81 -- src/engine/events/RequestPortValueEvent.h | 56 -- src/engine/events/SetMetadataEvent.cpp | 79 -- src/engine/events/SetMetadataEvent.h | 53 -- src/engine/events/SetPortValueEvent.cpp | 104 --- src/engine/events/SetPortValueEvent.h | 56 -- src/engine/events/SetPortValueQueuedEvent.cpp | 116 --- src/engine/events/SetPortValueQueuedEvent.h | 57 -- src/engine/events/UnregisterClientEvent.cpp | 45 - src/engine/events/UnregisterClientEvent.h | 53 -- src/engine/instantiations.cpp | 49 -- src/engine/main.cpp | 153 ---- src/engine/midi.h | 135 --- src/engine/tests/Makefile.am | 27 - src/engine/tests/list_test.cpp | 93 --- src/engine/tests/node_tree_test.cpp | 94 --- src/engine/tests/old_node_tree_test.cpp | 72 -- src/engine/tests/queue_test.cpp | 47 -- src/engine/tuning.h | 39 - src/engine/util.h | 73 -- src/libs/engine/AlsaMidiDriver.cpp | 373 +++++++++ src/libs/engine/AlsaMidiDriver.h | 127 +++ src/libs/engine/Array.h | 109 +++ src/libs/engine/AudioDriver.h | 50 ++ src/libs/engine/AudioInputNode.cpp | 49 ++ src/libs/engine/AudioInputNode.h | 45 + src/libs/engine/AudioOutputNode.cpp | 50 ++ src/libs/engine/AudioOutputNode.h | 44 + src/libs/engine/BridgeNode.cpp | 159 ++++ src/libs/engine/BridgeNode.h | 90 ++ src/libs/engine/Buffer.cpp | 297 +++++++ src/libs/engine/Buffer.h | 91 ++ src/libs/engine/ClientBroadcaster.cpp | 331 ++++++++ src/libs/engine/ClientBroadcaster.h | 101 +++ src/libs/engine/Connection.cpp | 45 + src/libs/engine/Connection.h | 66 ++ src/libs/engine/ConnectionBase.cpp | 96 +++ src/libs/engine/ConnectionBase.h | 105 +++ src/libs/engine/ControlInputNode.cpp | 49 ++ src/libs/engine/ControlInputNode.h | 44 + src/libs/engine/ControlOutputNode.cpp | 48 ++ src/libs/engine/ControlOutputNode.h | 45 + src/libs/engine/Controller.h | 82 ++ src/libs/engine/DSSIPlugin.cpp | 340 ++++++++ src/libs/engine/DSSIPlugin.cpp.orig | 207 +++++ src/libs/engine/DSSIPlugin.h | 109 +++ src/libs/engine/DSSIPlugin.h.orig | 84 ++ src/libs/engine/Driver.h | 112 +++ src/libs/engine/Event.cpp | 48 ++ src/libs/engine/Event.h | 71 ++ src/libs/engine/EventSource.h | 52 ++ src/libs/engine/InputPort.cpp | 352 ++++++++ src/libs/engine/InputPort.h | 88 ++ src/libs/engine/InternalNode.h | 70 ++ src/libs/engine/JackAudioDriver.cpp | 373 +++++++++ src/libs/engine/JackAudioDriver.h | 176 ++++ src/libs/engine/JackMidiDriver.cpp | 217 +++++ src/libs/engine/JackMidiDriver.h | 123 +++ src/libs/engine/LADSPAPlugin.cpp | 274 ++++++ src/libs/engine/LADSPAPlugin.h | 69 ++ src/libs/engine/LV2Plugin.cpp | 275 ++++++ src/libs/engine/LV2Plugin.h | 76 ++ src/libs/engine/LashDriver.cpp | 159 ++++ src/libs/engine/LashDriver.h | 57 ++ src/libs/engine/List.h | 416 +++++++++ src/libs/engine/Maid.cpp | 46 + src/libs/engine/Maid.h | 65 ++ src/libs/engine/MaidObject.h | 38 + src/libs/engine/Makefile.am | 259 ++++++ src/libs/engine/MidiControlNode.cpp | 133 +++ src/libs/engine/MidiControlNode.h | 72 ++ src/libs/engine/MidiDriver.h | 78 ++ src/libs/engine/MidiInputNode.cpp | 49 ++ src/libs/engine/MidiInputNode.h | 43 + src/libs/engine/MidiMessage.h | 51 ++ src/libs/engine/MidiNoteNode.cpp | 304 +++++++ src/libs/engine/MidiNoteNode.h | 87 ++ src/libs/engine/MidiOutputNode.cpp | 49 ++ src/libs/engine/MidiOutputNode.h | 43 + src/libs/engine/MidiTriggerNode.cpp | 124 +++ src/libs/engine/MidiTriggerNode.h | 64 ++ src/libs/engine/Node.h | 120 +++ src/libs/engine/NodeBase.cpp | 171 ++++ src/libs/engine/NodeBase.h | 105 +++ src/libs/engine/NodeFactory.cpp | 707 ++++++++++++++++ src/libs/engine/NodeFactory.h | 93 +++ src/libs/engine/OSCClient.cpp | 503 +++++++++++ src/libs/engine/OSCClient.h | 131 +++ src/libs/engine/OSCReceiver.cpp | 926 +++++++++++++++++++++ src/libs/engine/OSCReceiver.h | 124 +++ src/libs/engine/OSCResponder.cpp | 88 ++ src/libs/engine/OSCResponder.h | 61 ++ src/libs/engine/ObjectSender.cpp | 207 +++++ src/libs/engine/ObjectSender.h | 55 ++ src/libs/engine/ObjectStore.cpp | 109 +++ src/libs/engine/ObjectStore.h | 61 ++ src/libs/engine/Om.cpp | 36 + src/libs/engine/Om.h | 42 + src/libs/engine/OmApp.cpp | 231 +++++ src/libs/engine/OmApp.h | 99 +++ src/libs/engine/OmInProcess.cpp | 74 ++ src/libs/engine/OmObject.h | 115 +++ src/libs/engine/OutputPort.cpp | 51 ++ src/libs/engine/OutputPort.h | 64 ++ src/libs/engine/Patch.cpp | 356 ++++++++ src/libs/engine/Patch.h | 136 +++ src/libs/engine/Plugin.h | 149 ++++ src/libs/engine/PluginLibrary.h | 100 +++ src/libs/engine/Port.cpp | 56 ++ src/libs/engine/Port.h | 80 ++ src/libs/engine/PortBase.cpp | 133 +++ src/libs/engine/PortBase.h | 87 ++ src/libs/engine/PortInfo.h | 153 ++++ src/libs/engine/PostProcessor.cpp | 122 +++ src/libs/engine/PostProcessor.h | 78 ++ src/libs/engine/QueuedEngineInterface.cpp | 299 +++++++ src/libs/engine/QueuedEngineInterface.h | 145 ++++ src/libs/engine/QueuedEvent.h | 86 ++ src/libs/engine/QueuedEventSource.cpp | 201 +++++ src/libs/engine/QueuedEventSource.h | 83 ++ src/libs/engine/Responder.h | 63 ++ src/libs/engine/TransportNode.cpp | 155 ++++ src/libs/engine/TransportNode.h | 48 ++ src/libs/engine/Tree.h | 155 ++++ src/libs/engine/TreeImplementation.h | 410 +++++++++ src/libs/engine/cmdline.c | 150 ++++ src/libs/engine/cmdline.ggo | 7 + src/libs/engine/cmdline.h | 45 + src/libs/engine/events.h | 62 ++ src/libs/engine/events/ActivateEvent.cpp | 52 ++ src/libs/engine/events/ActivateEvent.h | 41 + src/libs/engine/events/AddNodeEvent.cpp | 128 +++ src/libs/engine/events/AddNodeEvent.h | 63 ++ src/libs/engine/events/AllNotesOffEvent.cpp | 67 ++ src/libs/engine/events/AllNotesOffEvent.h | 50 ++ src/libs/engine/events/ClearPatchEvent.cpp | 114 +++ src/libs/engine/events/ClearPatchEvent.h | 54 ++ src/libs/engine/events/ConnectionEvent.cpp | 240 ++++++ src/libs/engine/events/ConnectionEvent.h | 107 +++ src/libs/engine/events/CreatePatchEvent.cpp | 150 ++++ src/libs/engine/events/CreatePatchEvent.h | 64 ++ src/libs/engine/events/DSSIConfigureEvent.cpp | 73 ++ src/libs/engine/events/DSSIConfigureEvent.h | 49 ++ src/libs/engine/events/DSSIControlEvent.cpp | 68 ++ src/libs/engine/events/DSSIControlEvent.h | 51 ++ src/libs/engine/events/DSSIProgramEvent.cpp | 77 ++ src/libs/engine/events/DSSIProgramEvent.h | 49 ++ src/libs/engine/events/DSSIUpdateEvent.cpp | 80 ++ src/libs/engine/events/DSSIUpdateEvent.h | 54 ++ src/libs/engine/events/DeactivateEvent.cpp | 54 ++ src/libs/engine/events/DeactivateEvent.h | 42 + src/libs/engine/events/DestroyEvent.cpp | 168 ++++ src/libs/engine/events/DestroyEvent.h | 68 ++ src/libs/engine/events/DisablePatchEvent.cpp | 70 ++ src/libs/engine/events/DisablePatchEvent.h | 52 ++ src/libs/engine/events/DisconnectNodeEvent.cpp | 140 ++++ src/libs/engine/events/DisconnectNodeEvent.h | 68 ++ src/libs/engine/events/DisconnectPortEvent.cpp | 145 ++++ src/libs/engine/events/DisconnectPortEvent.h | 70 ++ src/libs/engine/events/DisconnectionEvent.cpp | 295 +++++++ src/libs/engine/events/DisconnectionEvent.h | 106 +++ src/libs/engine/events/EnablePatchEvent.cpp | 82 ++ src/libs/engine/events/EnablePatchEvent.h | 56 ++ src/libs/engine/events/LashRestoreDoneEvent.h | 54 ++ src/libs/engine/events/LoadPluginsEvent.cpp | 44 + src/libs/engine/events/LoadPluginsEvent.h | 40 + src/libs/engine/events/Makefile.am | 67 ++ src/libs/engine/events/MidiLearnEvent.cpp | 88 ++ src/libs/engine/events/MidiLearnEvent.h | 84 ++ src/libs/engine/events/NoteOffEvent.cpp | 78 ++ src/libs/engine/events/NoteOffEvent.h | 52 ++ src/libs/engine/events/NoteOnEvent.cpp | 89 ++ src/libs/engine/events/NoteOnEvent.h | 54 ++ src/libs/engine/events/PingQueuedEvent.h | 44 + src/libs/engine/events/RegisterClientEvent.cpp | 53 ++ src/libs/engine/events/RegisterClientEvent.h | 53 ++ src/libs/engine/events/RenameEvent.cpp | 123 +++ src/libs/engine/events/RenameEvent.h | 66 ++ src/libs/engine/events/RequestAllObjectsEvent.cpp | 55 ++ src/libs/engine/events/RequestAllObjectsEvent.h | 50 ++ src/libs/engine/events/RequestMetadataEvent.cpp | 80 ++ src/libs/engine/events/RequestMetadataEvent.h | 56 ++ src/libs/engine/events/RequestPluginsEvent.cpp | 55 ++ src/libs/engine/events/RequestPluginsEvent.h | 51 ++ src/libs/engine/events/RequestPortValueEvent.cpp | 81 ++ src/libs/engine/events/RequestPortValueEvent.h | 56 ++ src/libs/engine/events/SetMetadataEvent.cpp | 79 ++ src/libs/engine/events/SetMetadataEvent.h | 53 ++ src/libs/engine/events/SetPortValueEvent.cpp | 104 +++ src/libs/engine/events/SetPortValueEvent.h | 56 ++ src/libs/engine/events/SetPortValueQueuedEvent.cpp | 116 +++ src/libs/engine/events/SetPortValueQueuedEvent.h | 57 ++ src/libs/engine/events/UnregisterClientEvent.cpp | 45 + src/libs/engine/events/UnregisterClientEvent.h | 53 ++ src/libs/engine/instantiations.cpp | 49 ++ src/libs/engine/main.cpp | 153 ++++ src/libs/engine/midi.h | 135 +++ src/libs/engine/tests/Makefile.am | 27 + src/libs/engine/tests/list_test.cpp | 93 +++ src/libs/engine/tests/node_tree_test.cpp | 94 +++ src/libs/engine/tests/old_node_tree_test.cpp | 72 ++ src/libs/engine/tests/queue_test.cpp | 47 ++ src/libs/engine/tuning.h | 39 + src/libs/engine/util.h | 73 ++ src/progs/om/Makefile.am | 259 ++++++ 369 files changed, 21405 insertions(+), 21146 deletions(-) delete mode 100644 src/engine/AlsaMidiDriver.cpp delete mode 100644 src/engine/AlsaMidiDriver.h delete mode 100644 src/engine/Array.h delete mode 100644 src/engine/AudioDriver.h delete mode 100644 src/engine/AudioInputNode.cpp delete mode 100644 src/engine/AudioInputNode.h delete mode 100644 src/engine/AudioOutputNode.cpp delete mode 100644 src/engine/AudioOutputNode.h delete mode 100644 src/engine/BridgeNode.cpp delete mode 100644 src/engine/BridgeNode.h delete mode 100644 src/engine/Buffer.cpp delete mode 100644 src/engine/Buffer.h delete mode 100644 src/engine/ClientBroadcaster.cpp delete mode 100644 src/engine/ClientBroadcaster.h delete mode 100644 src/engine/Connection.cpp delete mode 100644 src/engine/Connection.h delete mode 100644 src/engine/ConnectionBase.cpp delete mode 100644 src/engine/ConnectionBase.h delete mode 100644 src/engine/ControlInputNode.cpp delete mode 100644 src/engine/ControlInputNode.h delete mode 100644 src/engine/ControlOutputNode.cpp delete mode 100644 src/engine/ControlOutputNode.h delete mode 100644 src/engine/Controller.h delete mode 100644 src/engine/DSSIPlugin.cpp delete mode 100644 src/engine/DSSIPlugin.cpp.orig delete mode 100644 src/engine/DSSIPlugin.h delete mode 100644 src/engine/DSSIPlugin.h.orig delete mode 100644 src/engine/Driver.h delete mode 100644 src/engine/Event.cpp delete mode 100644 src/engine/Event.h delete mode 100644 src/engine/EventSource.h delete mode 100644 src/engine/InputPort.cpp delete mode 100644 src/engine/InputPort.h delete mode 100644 src/engine/InternalNode.h delete mode 100644 src/engine/JackAudioDriver.cpp delete mode 100644 src/engine/JackAudioDriver.h delete mode 100644 src/engine/JackMidiDriver.cpp delete mode 100644 src/engine/JackMidiDriver.h delete mode 100644 src/engine/LADSPAPlugin.cpp delete mode 100644 src/engine/LADSPAPlugin.h delete mode 100644 src/engine/LV2Plugin.cpp delete mode 100644 src/engine/LV2Plugin.h delete mode 100644 src/engine/LashDriver.cpp delete mode 100644 src/engine/LashDriver.h delete mode 100644 src/engine/List.h delete mode 100644 src/engine/Maid.cpp delete mode 100644 src/engine/Maid.h delete mode 100644 src/engine/MaidObject.h delete mode 100644 src/engine/Makefile.am delete mode 100644 src/engine/MidiControlNode.cpp delete mode 100644 src/engine/MidiControlNode.h delete mode 100644 src/engine/MidiDriver.h delete mode 100644 src/engine/MidiInputNode.cpp delete mode 100644 src/engine/MidiInputNode.h delete mode 100644 src/engine/MidiMessage.h delete mode 100644 src/engine/MidiNoteNode.cpp delete mode 100644 src/engine/MidiNoteNode.h delete mode 100644 src/engine/MidiOutputNode.cpp delete mode 100644 src/engine/MidiOutputNode.h delete mode 100644 src/engine/MidiTriggerNode.cpp delete mode 100644 src/engine/MidiTriggerNode.h delete mode 100644 src/engine/Node.h delete mode 100644 src/engine/NodeBase.cpp delete mode 100644 src/engine/NodeBase.h delete mode 100644 src/engine/NodeFactory.cpp delete mode 100644 src/engine/NodeFactory.h delete mode 100644 src/engine/OSCClient.cpp delete mode 100644 src/engine/OSCClient.h delete mode 100644 src/engine/OSCReceiver.cpp delete mode 100644 src/engine/OSCReceiver.h delete mode 100644 src/engine/OSCResponder.cpp delete mode 100644 src/engine/OSCResponder.h delete mode 100644 src/engine/ObjectSender.cpp delete mode 100644 src/engine/ObjectSender.h delete mode 100644 src/engine/ObjectStore.cpp delete mode 100644 src/engine/ObjectStore.h delete mode 100644 src/engine/Om.cpp delete mode 100644 src/engine/Om.h delete mode 100644 src/engine/OmApp.cpp delete mode 100644 src/engine/OmApp.h delete mode 100644 src/engine/OmInProcess.cpp delete mode 100644 src/engine/OmObject.h delete mode 100644 src/engine/OutputPort.cpp delete mode 100644 src/engine/OutputPort.h delete mode 100644 src/engine/Patch.cpp delete mode 100644 src/engine/Patch.h delete mode 100644 src/engine/Plugin.h delete mode 100644 src/engine/PluginLibrary.h delete mode 100644 src/engine/Port.cpp delete mode 100644 src/engine/Port.h delete mode 100644 src/engine/PortBase.cpp delete mode 100644 src/engine/PortBase.h delete mode 100644 src/engine/PortInfo.h delete mode 100644 src/engine/PostProcessor.cpp delete mode 100644 src/engine/PostProcessor.h delete mode 100644 src/engine/QueuedEngineInterface.cpp delete mode 100644 src/engine/QueuedEngineInterface.h delete mode 100644 src/engine/QueuedEvent.h delete mode 100644 src/engine/QueuedEventSource.cpp delete mode 100644 src/engine/QueuedEventSource.h delete mode 100644 src/engine/Responder.h delete mode 100644 src/engine/TransportNode.cpp delete mode 100644 src/engine/TransportNode.h delete mode 100644 src/engine/Tree.h delete mode 100644 src/engine/TreeImplementation.h delete mode 100644 src/engine/cmdline.c delete mode 100644 src/engine/cmdline.ggo delete mode 100644 src/engine/cmdline.h delete mode 100644 src/engine/events.h delete mode 100644 src/engine/events/ActivateEvent.cpp delete mode 100644 src/engine/events/ActivateEvent.h delete mode 100644 src/engine/events/AddNodeEvent.cpp delete mode 100644 src/engine/events/AddNodeEvent.h delete mode 100644 src/engine/events/AllNotesOffEvent.cpp delete mode 100644 src/engine/events/AllNotesOffEvent.h delete mode 100644 src/engine/events/ClearPatchEvent.cpp delete mode 100644 src/engine/events/ClearPatchEvent.h delete mode 100644 src/engine/events/ConnectionEvent.cpp delete mode 100644 src/engine/events/ConnectionEvent.h delete mode 100644 src/engine/events/CreatePatchEvent.cpp delete mode 100644 src/engine/events/CreatePatchEvent.h delete mode 100644 src/engine/events/DSSIConfigureEvent.cpp delete mode 100644 src/engine/events/DSSIConfigureEvent.h delete mode 100644 src/engine/events/DSSIControlEvent.cpp delete mode 100644 src/engine/events/DSSIControlEvent.h delete mode 100644 src/engine/events/DSSIProgramEvent.cpp delete mode 100644 src/engine/events/DSSIProgramEvent.h delete mode 100644 src/engine/events/DSSIUpdateEvent.cpp delete mode 100644 src/engine/events/DSSIUpdateEvent.h delete mode 100644 src/engine/events/DeactivateEvent.cpp delete mode 100644 src/engine/events/DeactivateEvent.h delete mode 100644 src/engine/events/DestroyEvent.cpp delete mode 100644 src/engine/events/DestroyEvent.h delete mode 100644 src/engine/events/DisablePatchEvent.cpp delete mode 100644 src/engine/events/DisablePatchEvent.h delete mode 100644 src/engine/events/DisconnectNodeEvent.cpp delete mode 100644 src/engine/events/DisconnectNodeEvent.h delete mode 100644 src/engine/events/DisconnectPortEvent.cpp delete mode 100644 src/engine/events/DisconnectPortEvent.h delete mode 100644 src/engine/events/DisconnectionEvent.cpp delete mode 100644 src/engine/events/DisconnectionEvent.h delete mode 100644 src/engine/events/EnablePatchEvent.cpp delete mode 100644 src/engine/events/EnablePatchEvent.h delete mode 100644 src/engine/events/LashRestoreDoneEvent.h delete mode 100644 src/engine/events/LoadPluginsEvent.cpp delete mode 100644 src/engine/events/LoadPluginsEvent.h delete mode 100644 src/engine/events/Makefile.am delete mode 100644 src/engine/events/MidiLearnEvent.cpp delete mode 100644 src/engine/events/MidiLearnEvent.h delete mode 100644 src/engine/events/NoteOffEvent.cpp delete mode 100644 src/engine/events/NoteOffEvent.h delete mode 100644 src/engine/events/NoteOnEvent.cpp delete mode 100644 src/engine/events/NoteOnEvent.h delete mode 100644 src/engine/events/PingQueuedEvent.h delete mode 100644 src/engine/events/RegisterClientEvent.cpp delete mode 100644 src/engine/events/RegisterClientEvent.h delete mode 100644 src/engine/events/RenameEvent.cpp delete mode 100644 src/engine/events/RenameEvent.h delete mode 100644 src/engine/events/RequestAllObjectsEvent.cpp delete mode 100644 src/engine/events/RequestAllObjectsEvent.h delete mode 100644 src/engine/events/RequestMetadataEvent.cpp delete mode 100644 src/engine/events/RequestMetadataEvent.h delete mode 100644 src/engine/events/RequestPluginsEvent.cpp delete mode 100644 src/engine/events/RequestPluginsEvent.h delete mode 100644 src/engine/events/RequestPortValueEvent.cpp delete mode 100644 src/engine/events/RequestPortValueEvent.h delete mode 100644 src/engine/events/SetMetadataEvent.cpp delete mode 100644 src/engine/events/SetMetadataEvent.h delete mode 100644 src/engine/events/SetPortValueEvent.cpp delete mode 100644 src/engine/events/SetPortValueEvent.h delete mode 100644 src/engine/events/SetPortValueQueuedEvent.cpp delete mode 100644 src/engine/events/SetPortValueQueuedEvent.h delete mode 100644 src/engine/events/UnregisterClientEvent.cpp delete mode 100644 src/engine/events/UnregisterClientEvent.h delete mode 100644 src/engine/instantiations.cpp delete mode 100644 src/engine/main.cpp delete mode 100644 src/engine/midi.h delete mode 100644 src/engine/tests/Makefile.am delete mode 100644 src/engine/tests/list_test.cpp delete mode 100644 src/engine/tests/node_tree_test.cpp delete mode 100644 src/engine/tests/old_node_tree_test.cpp delete mode 100644 src/engine/tests/queue_test.cpp delete mode 100644 src/engine/tuning.h delete mode 100644 src/engine/util.h create mode 100644 src/libs/engine/AlsaMidiDriver.cpp create mode 100644 src/libs/engine/AlsaMidiDriver.h create mode 100644 src/libs/engine/Array.h create mode 100644 src/libs/engine/AudioDriver.h create mode 100644 src/libs/engine/AudioInputNode.cpp create mode 100644 src/libs/engine/AudioInputNode.h create mode 100644 src/libs/engine/AudioOutputNode.cpp create mode 100644 src/libs/engine/AudioOutputNode.h create mode 100644 src/libs/engine/BridgeNode.cpp create mode 100644 src/libs/engine/BridgeNode.h create mode 100644 src/libs/engine/Buffer.cpp create mode 100644 src/libs/engine/Buffer.h create mode 100644 src/libs/engine/ClientBroadcaster.cpp create mode 100644 src/libs/engine/ClientBroadcaster.h create mode 100644 src/libs/engine/Connection.cpp create mode 100644 src/libs/engine/Connection.h create mode 100644 src/libs/engine/ConnectionBase.cpp create mode 100644 src/libs/engine/ConnectionBase.h create mode 100644 src/libs/engine/ControlInputNode.cpp create mode 100644 src/libs/engine/ControlInputNode.h create mode 100644 src/libs/engine/ControlOutputNode.cpp create mode 100644 src/libs/engine/ControlOutputNode.h create mode 100644 src/libs/engine/Controller.h create mode 100644 src/libs/engine/DSSIPlugin.cpp create mode 100644 src/libs/engine/DSSIPlugin.cpp.orig create mode 100644 src/libs/engine/DSSIPlugin.h create mode 100644 src/libs/engine/DSSIPlugin.h.orig create mode 100644 src/libs/engine/Driver.h create mode 100644 src/libs/engine/Event.cpp create mode 100644 src/libs/engine/Event.h create mode 100644 src/libs/engine/EventSource.h create mode 100644 src/libs/engine/InputPort.cpp create mode 100644 src/libs/engine/InputPort.h create mode 100644 src/libs/engine/InternalNode.h create mode 100644 src/libs/engine/JackAudioDriver.cpp create mode 100644 src/libs/engine/JackAudioDriver.h create mode 100644 src/libs/engine/JackMidiDriver.cpp create mode 100644 src/libs/engine/JackMidiDriver.h create mode 100644 src/libs/engine/LADSPAPlugin.cpp create mode 100644 src/libs/engine/LADSPAPlugin.h create mode 100644 src/libs/engine/LV2Plugin.cpp create mode 100644 src/libs/engine/LV2Plugin.h create mode 100644 src/libs/engine/LashDriver.cpp create mode 100644 src/libs/engine/LashDriver.h create mode 100644 src/libs/engine/List.h create mode 100644 src/libs/engine/Maid.cpp create mode 100644 src/libs/engine/Maid.h create mode 100644 src/libs/engine/MaidObject.h create mode 100644 src/libs/engine/Makefile.am create mode 100644 src/libs/engine/MidiControlNode.cpp create mode 100644 src/libs/engine/MidiControlNode.h create mode 100644 src/libs/engine/MidiDriver.h create mode 100644 src/libs/engine/MidiInputNode.cpp create mode 100644 src/libs/engine/MidiInputNode.h create mode 100644 src/libs/engine/MidiMessage.h create mode 100644 src/libs/engine/MidiNoteNode.cpp create mode 100644 src/libs/engine/MidiNoteNode.h create mode 100644 src/libs/engine/MidiOutputNode.cpp create mode 100644 src/libs/engine/MidiOutputNode.h create mode 100644 src/libs/engine/MidiTriggerNode.cpp create mode 100644 src/libs/engine/MidiTriggerNode.h create mode 100644 src/libs/engine/Node.h create mode 100644 src/libs/engine/NodeBase.cpp create mode 100644 src/libs/engine/NodeBase.h create mode 100644 src/libs/engine/NodeFactory.cpp create mode 100644 src/libs/engine/NodeFactory.h create mode 100644 src/libs/engine/OSCClient.cpp create mode 100644 src/libs/engine/OSCClient.h create mode 100644 src/libs/engine/OSCReceiver.cpp create mode 100644 src/libs/engine/OSCReceiver.h create mode 100644 src/libs/engine/OSCResponder.cpp create mode 100644 src/libs/engine/OSCResponder.h create mode 100644 src/libs/engine/ObjectSender.cpp create mode 100644 src/libs/engine/ObjectSender.h create mode 100644 src/libs/engine/ObjectStore.cpp create mode 100644 src/libs/engine/ObjectStore.h create mode 100644 src/libs/engine/Om.cpp create mode 100644 src/libs/engine/Om.h create mode 100644 src/libs/engine/OmApp.cpp create mode 100644 src/libs/engine/OmApp.h create mode 100644 src/libs/engine/OmInProcess.cpp create mode 100644 src/libs/engine/OmObject.h create mode 100644 src/libs/engine/OutputPort.cpp create mode 100644 src/libs/engine/OutputPort.h create mode 100644 src/libs/engine/Patch.cpp create mode 100644 src/libs/engine/Patch.h create mode 100644 src/libs/engine/Plugin.h create mode 100644 src/libs/engine/PluginLibrary.h create mode 100644 src/libs/engine/Port.cpp create mode 100644 src/libs/engine/Port.h create mode 100644 src/libs/engine/PortBase.cpp create mode 100644 src/libs/engine/PortBase.h create mode 100644 src/libs/engine/PortInfo.h create mode 100644 src/libs/engine/PostProcessor.cpp create mode 100644 src/libs/engine/PostProcessor.h create mode 100644 src/libs/engine/QueuedEngineInterface.cpp create mode 100644 src/libs/engine/QueuedEngineInterface.h create mode 100644 src/libs/engine/QueuedEvent.h create mode 100644 src/libs/engine/QueuedEventSource.cpp create mode 100644 src/libs/engine/QueuedEventSource.h create mode 100644 src/libs/engine/Responder.h create mode 100644 src/libs/engine/TransportNode.cpp create mode 100644 src/libs/engine/TransportNode.h create mode 100644 src/libs/engine/Tree.h create mode 100644 src/libs/engine/TreeImplementation.h create mode 100644 src/libs/engine/cmdline.c create mode 100644 src/libs/engine/cmdline.ggo create mode 100644 src/libs/engine/cmdline.h create mode 100644 src/libs/engine/events.h create mode 100644 src/libs/engine/events/ActivateEvent.cpp create mode 100644 src/libs/engine/events/ActivateEvent.h create mode 100644 src/libs/engine/events/AddNodeEvent.cpp create mode 100644 src/libs/engine/events/AddNodeEvent.h create mode 100644 src/libs/engine/events/AllNotesOffEvent.cpp create mode 100644 src/libs/engine/events/AllNotesOffEvent.h create mode 100644 src/libs/engine/events/ClearPatchEvent.cpp create mode 100644 src/libs/engine/events/ClearPatchEvent.h create mode 100644 src/libs/engine/events/ConnectionEvent.cpp create mode 100644 src/libs/engine/events/ConnectionEvent.h create mode 100644 src/libs/engine/events/CreatePatchEvent.cpp create mode 100644 src/libs/engine/events/CreatePatchEvent.h create mode 100644 src/libs/engine/events/DSSIConfigureEvent.cpp create mode 100644 src/libs/engine/events/DSSIConfigureEvent.h create mode 100644 src/libs/engine/events/DSSIControlEvent.cpp create mode 100644 src/libs/engine/events/DSSIControlEvent.h create mode 100644 src/libs/engine/events/DSSIProgramEvent.cpp create mode 100644 src/libs/engine/events/DSSIProgramEvent.h create mode 100644 src/libs/engine/events/DSSIUpdateEvent.cpp create mode 100644 src/libs/engine/events/DSSIUpdateEvent.h create mode 100644 src/libs/engine/events/DeactivateEvent.cpp create mode 100644 src/libs/engine/events/DeactivateEvent.h create mode 100644 src/libs/engine/events/DestroyEvent.cpp create mode 100644 src/libs/engine/events/DestroyEvent.h create mode 100644 src/libs/engine/events/DisablePatchEvent.cpp create mode 100644 src/libs/engine/events/DisablePatchEvent.h create mode 100644 src/libs/engine/events/DisconnectNodeEvent.cpp create mode 100644 src/libs/engine/events/DisconnectNodeEvent.h create mode 100644 src/libs/engine/events/DisconnectPortEvent.cpp create mode 100644 src/libs/engine/events/DisconnectPortEvent.h create mode 100644 src/libs/engine/events/DisconnectionEvent.cpp create mode 100644 src/libs/engine/events/DisconnectionEvent.h create mode 100644 src/libs/engine/events/EnablePatchEvent.cpp create mode 100644 src/libs/engine/events/EnablePatchEvent.h create mode 100644 src/libs/engine/events/LashRestoreDoneEvent.h create mode 100644 src/libs/engine/events/LoadPluginsEvent.cpp create mode 100644 src/libs/engine/events/LoadPluginsEvent.h create mode 100644 src/libs/engine/events/Makefile.am create mode 100644 src/libs/engine/events/MidiLearnEvent.cpp create mode 100644 src/libs/engine/events/MidiLearnEvent.h create mode 100644 src/libs/engine/events/NoteOffEvent.cpp create mode 100644 src/libs/engine/events/NoteOffEvent.h create mode 100644 src/libs/engine/events/NoteOnEvent.cpp create mode 100644 src/libs/engine/events/NoteOnEvent.h create mode 100644 src/libs/engine/events/PingQueuedEvent.h create mode 100644 src/libs/engine/events/RegisterClientEvent.cpp create mode 100644 src/libs/engine/events/RegisterClientEvent.h create mode 100644 src/libs/engine/events/RenameEvent.cpp create mode 100644 src/libs/engine/events/RenameEvent.h create mode 100644 src/libs/engine/events/RequestAllObjectsEvent.cpp create mode 100644 src/libs/engine/events/RequestAllObjectsEvent.h create mode 100644 src/libs/engine/events/RequestMetadataEvent.cpp create mode 100644 src/libs/engine/events/RequestMetadataEvent.h create mode 100644 src/libs/engine/events/RequestPluginsEvent.cpp create mode 100644 src/libs/engine/events/RequestPluginsEvent.h create mode 100644 src/libs/engine/events/RequestPortValueEvent.cpp create mode 100644 src/libs/engine/events/RequestPortValueEvent.h create mode 100644 src/libs/engine/events/SetMetadataEvent.cpp create mode 100644 src/libs/engine/events/SetMetadataEvent.h create mode 100644 src/libs/engine/events/SetPortValueEvent.cpp create mode 100644 src/libs/engine/events/SetPortValueEvent.h create mode 100644 src/libs/engine/events/SetPortValueQueuedEvent.cpp create mode 100644 src/libs/engine/events/SetPortValueQueuedEvent.h create mode 100644 src/libs/engine/events/UnregisterClientEvent.cpp create mode 100644 src/libs/engine/events/UnregisterClientEvent.h create mode 100644 src/libs/engine/instantiations.cpp create mode 100644 src/libs/engine/main.cpp create mode 100644 src/libs/engine/midi.h create mode 100644 src/libs/engine/tests/Makefile.am create mode 100644 src/libs/engine/tests/list_test.cpp create mode 100644 src/libs/engine/tests/node_tree_test.cpp create mode 100644 src/libs/engine/tests/old_node_tree_test.cpp create mode 100644 src/libs/engine/tests/queue_test.cpp create mode 100644 src/libs/engine/tuning.h create mode 100644 src/libs/engine/util.h create mode 100644 src/progs/om/Makefile.am (limited to 'src') diff --git a/src/engine/AlsaMidiDriver.cpp b/src/engine/AlsaMidiDriver.cpp deleted file mode 100644 index decd2471..00000000 --- a/src/engine/AlsaMidiDriver.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "AlsaMidiDriver.h" -#include -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "util/types.h" -#include "OmApp.h" -#include "Maid.h" -#include "AudioDriver.h" -#include "PortInfo.h" -#include "MidiMessage.h" -#include "PortBase.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif -using std::cout; using std::cerr; using std::endl; - -namespace Om { - - -//// AlsaMidiPort //// - -AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, PortBase* port) -: DriverPort(), - ListNode(this), - m_driver(driver), - m_patch_port(port), - m_port_id(0), - m_midi_pool(new unsigned char*[port->buffer_size()]), - m_events(1024) -{ - assert(port->parent() != NULL); - assert(port->poly() == 1); - - if (port->port_info()->is_input()) { - if ((m_port_id = snd_seq_create_simple_port(driver->seq_handle(), port->path().c_str(), - SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, - SND_SEQ_PORT_TYPE_APPLICATION)) < 0) - { - cerr << "[AlsaMidiPort] Error creating sequencer port." << endl; - exit(EXIT_FAILURE); - } - } else { - if ((m_port_id = snd_seq_create_simple_port(driver->seq_handle(), port->path().c_str(), - SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, - SND_SEQ_PORT_TYPE_APPLICATION)) < 0) - { - cerr << "[AlsaMidiPort] Error creating sequencer port." << endl; - exit(EXIT_FAILURE); - } - } - - /* Allocate event pool. This pool is used when preparing a block from the queue - * of Alsa events. The buffer member of the MidiMessage's in the patch port's - * buffer will be set directly to an element in this pool, then next cycle they - * will be overwritten (eliminating the need for any allocation/freeing). */ - for (size_t i=0; i < port->buffer_size(); ++i) - m_midi_pool[i] = new unsigned char[MAX_MIDI_EVENT_SIZE]; - - port->buffer(0)->clear(); - port->fixed_buffers(true); -} - - -AlsaMidiPort::~AlsaMidiPort() -{ - snd_seq_delete_simple_port(m_driver->seq_handle(), m_port_id); - - // Free event pool - for (size_t i=0; i < m_patch_port->buffer_size(); ++i) - delete[] m_midi_pool[i]; - - delete[] m_midi_pool; -} - - -void -AlsaMidiPort::add_to_driver() -{ - m_driver->add_port(this); -} - - -void -AlsaMidiPort::remove_from_driver() -{ - m_driver->remove_port(this); -} - - -void -AlsaMidiPort::set_name(const string& name) -{ - snd_seq_port_info_t* info = NULL; - snd_seq_port_info_malloc(&info); - snd_seq_get_port_info(m_driver->seq_handle(), m_port_id, info); - snd_seq_port_info_set_name(info, name.c_str()); - snd_seq_set_port_info(m_driver->seq_handle(), m_port_id, info); - snd_seq_port_info_free(info); -} - - -void -AlsaMidiPort::event(snd_seq_event_t* const ev) -{ - // Abuse the tick field to hold the timestamp - ev->time.tick = om->audio_driver()->time_stamp(); - - // Fix noteons with velocity 0 (required for DSSI spec) - if (ev->type == SND_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0) - ev->type = SND_SEQ_EVENT_NOTEOFF; - - m_events.push(*ev); -} - - -/** Generates a flat array of MIDI events for patching. - * - * Prepares all events that occurred during the time interval passed - * (which ideally are the events from the previous cycle with an exact - * 1 cycle delay) and creates a flat port buffer for this cycle. - */ -void -AlsaMidiPort::prepare_block(const samplecount block_start, const samplecount block_end) -{ - assert(block_end >= block_start); - - snd_seq_event_t* ev = NULL; - MidiMessage* message = NULL; - size_t num_events = 0; - size_t event_size = 0; // decoded length of Alsa event in bytes - int timestamp = 0; - - while (!m_events.is_empty() && m_events.front().time.tick < block_end) { - assert(num_events < m_patch_port->buffer_size()); - ev = &m_events.front(); - message = &m_patch_port->buffer(0)->data()[num_events]; - - timestamp = ev->time.tick - block_start; - if (timestamp < 0) { - // FIXME: remove this (obviously not realtime safe) - cerr << "[AlsaMidiPort] Missed event by " << -timestamp << " samples!" << endl; - timestamp = 0; - } - assert(timestamp < (int)(block_end - block_start)); - - // Reset decoder so we don't get running status - snd_midi_event_reset_decode(m_driver->event_coder()); - - // FIXME: is this realtime safe? - if ((event_size = snd_midi_event_decode(m_driver->event_coder(), - m_midi_pool[num_events], MAX_MIDI_EVENT_SIZE, ev)) > 0) { - message->size = event_size; - message->time = timestamp; - message->buffer = m_midi_pool[num_events]; - ++num_events; - } else { - cerr << "[AlsaMidiPort] Unable to decode MIDI event" << endl; - } - - m_events.pop(); - } - - m_patch_port->buffer(0)->filled_size(num_events); - m_patch_port->tied_port()->buffer(0)->filled_size(num_events); -} - - - -//// AlsaMidiDriver //// - - -bool AlsaMidiDriver::m_midi_thread_exit_flag = true; - - -AlsaMidiDriver::AlsaMidiDriver() -: m_seq_handle(NULL), - m_event_coder(NULL), - m_is_activated(false) -{ - if (snd_seq_open(&m_seq_handle, "hw", SND_SEQ_OPEN_INPUT, 0) < 0) { - cerr << "[AlsaMidiDriver] Error opening ALSA sequencer." << endl; - exit(EXIT_FAILURE); - } else { - cout << "[AlsaMidiDriver] Successfully opened ALSA sequencer." << endl; - } - - if (snd_midi_event_new(3, &m_event_coder)) { - cerr << "[AlsaMidiDriver] Failed to initialize ALSA MIDI event coder!"; - exit(EXIT_FAILURE); - } else { - snd_midi_event_reset_encode(m_event_coder); - snd_midi_event_reset_decode(m_event_coder); - } - - snd_seq_set_client_name(m_seq_handle, "Om"); -} - - -AlsaMidiDriver::~AlsaMidiDriver() -{ - deactivate(); - snd_midi_event_free(m_event_coder); - snd_seq_close(m_seq_handle); -} - - -/** Launch and start the MIDI thread. - */ -void -AlsaMidiDriver::activate() -{ - // Just exit if already running - if (m_midi_thread_exit_flag == false) - return; - - bool success = false; - m_midi_thread_exit_flag = false; - - //if (om->audio_driver()->is_realtime()) { - pthread_attr_t attr; - pthread_attr_init(&attr); - - if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { - cerr << "[AlsaMidiDriver] Unable to set realtime scheduling for MIDI thread." << endl; - } - - sched_param param; - param.sched_priority = 10; - - pthread_attr_setstacksize(&attr, 1500000); - - if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) - || pthread_attr_setschedparam(&attr, ¶m)) - cout << "[AlsaMidiDriver] Unable to set SCHED_FIFO priority " - << param.sched_priority << endl; - - if (!pthread_create(&m_process_thread, &attr, process_midi_in, this)) { - cout << "[AlsaMidiDriver] Started realtime MIDI thread (SCHED_FIFO, priority " - << param.sched_priority << ")" << endl; - success = true; - } else { - cerr << "[AlsaMidiDriver] Unable to start realtime MIDI thread." << endl; - } - pthread_attr_destroy(&attr); - //} - - if (!success) { - // FIXME: check for success - pthread_create(&m_process_thread, NULL, process_midi_in, this); - cout << "[AlsaMidiDriver] Started non-realtime MIDI thread." << endl; - } - -#ifdef HAVE_LASH - lash_driver->set_alsa_client_id(snd_seq_client_id(m_seq_handle)); -#endif - - m_is_activated = true; -} - - -/** Terminate the MIDI thread. - */ -void -AlsaMidiDriver::deactivate() -{ - if (m_is_activated) { - m_midi_thread_exit_flag = true; - pthread_cancel(m_process_thread); - pthread_join(m_process_thread, NULL); - m_is_activated = false; - } -} - - -/** Build flat arrays of events for DSSI plugins for each Port. - */ -void -AlsaMidiDriver::prepare_block(const samplecount block_start, const samplecount block_end) -{ - for (List::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i) - (*i)->prepare_block(block_start, block_end); -} - - -/** Add an Alsa MIDI port. - * - * Realtime safe, this is to be called at the beginning of a process cycle to - * insert (and actually begin using) a new port. - * - * See create_port() and remove_port(). - */ -void -AlsaMidiDriver::add_port(AlsaMidiPort* port) -{ - if (port->patch_port()->port_info()->is_input()) - m_in_ports.push_back(port); - else - m_out_ports.push_back(port); -} - - -/** Remove an Alsa MIDI port. - * - * Realtime safe. This is to be called at the beginning of a process cycle to - * remove the port from the lists read by the audio thread, so the port - * will no longer be used and can be removed afterwards. - * - * It is the callers responsibility to delete the returned port. - */ -AlsaMidiPort* -AlsaMidiDriver::remove_port(AlsaMidiPort* port) -{ - if (port->patch_port()->port_info()->is_input()) { - for (List::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i) - if ((*i) == (AlsaMidiPort*)port) - return m_in_ports.remove(i)->elem(); - } else { - for (List::iterator i = m_out_ports.begin(); i != m_out_ports.end(); ++i) - if ((*i) == port) - return m_out_ports.remove(i)->elem(); - } - - cerr << "[AlsaMidiDriver::remove_input] WARNING: Failed to find Jack port to remove!" << endl; - return NULL; -} - - -/** MIDI thread. - */ -void* -AlsaMidiDriver::process_midi_in(void* alsa_driver) -{ - AlsaMidiDriver* ad = (AlsaMidiDriver*)alsa_driver; - - snd_seq_event_t* ev; - - int npfd = snd_seq_poll_descriptors_count(ad->m_seq_handle, POLLIN); - struct pollfd pfd; - snd_seq_poll_descriptors(ad->m_seq_handle, &pfd, npfd, POLLIN); - - while ( ! m_midi_thread_exit_flag) - if (poll(&pfd, npfd, 100000) > 0) - while (snd_seq_event_input(ad->m_seq_handle, &ev) > 0) - for (List::iterator i = ad->m_in_ports.begin(); i != ad->m_in_ports.end(); ++i) - if ((*i)->port_id() == ev->dest.port) - (*i)->event(ev); - - cout << "[AlsaMidiDriver] Exiting MIDI thread." << endl; - - return NULL; -} - - -} // namespace Om - diff --git a/src/engine/AlsaMidiDriver.h b/src/engine/AlsaMidiDriver.h deleted file mode 100644 index 5acbbfbf..00000000 --- a/src/engine/AlsaMidiDriver.h +++ /dev/null @@ -1,127 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ALSAMIDIDRIVER_H -#define ALSAMIDIDRIVER_H - -#include -#include "List.h" -#include "util/Queue.h" -#include "MidiDriver.h" - -namespace Om { - -class Node; -class SetPortValueEvent; -class AlsaMidiDriver; -template class PortBase; - -static const int MAX_MIDI_EVENT_SIZE = 3; - - -/** Representation of an ALSA MIDI port. - * - * \ingroup engine - */ -class AlsaMidiPort : public DriverPort, public ListNode -{ -public: - AlsaMidiPort(AlsaMidiDriver* driver, PortBase* port); - virtual ~AlsaMidiPort(); - - void event(snd_seq_event_t* const ev); - - void prepare_block(const samplecount block_start, const samplecount block_end); - - void add_to_driver(); - void remove_from_driver(); - void set_name(const string& name); - - int port_id() const { return m_port_id; } - PortBase* patch_port() const { return m_patch_port; } - -private: - // Prevent copies (undefined) - AlsaMidiPort(const AlsaMidiPort&); - AlsaMidiPort& operator=(const AlsaMidiPort&); - - AlsaMidiDriver* m_driver; - PortBase* m_patch_port; - int m_port_id; - unsigned char** m_midi_pool; ///< Pool of raw MIDI events for MidiMessage::buffer - Queue m_events; -}; - - -/** Alsa MIDI driver. - * - * This driver reads Alsa MIDI events and dispatches them to the appropriate - * AlsaMidiPort for processing. - * - * \ingroup engine - */ -class AlsaMidiDriver : public MidiDriver -{ -public: - AlsaMidiDriver(); - ~AlsaMidiDriver(); - - void activate(); - void deactivate(); - - bool is_activated() const { return m_is_activated; } - - void prepare_block(const samplecount block_start, const samplecount block_end); - - DriverPort* create_port(PortBase* patch_port) - { return new AlsaMidiPort(this, patch_port); } - - snd_seq_t* seq_handle() const { return m_seq_handle; } - snd_midi_event_t* event_coder() const { return m_event_coder; } - -private: - - // Prevent copies (undefined) - AlsaMidiDriver(const AlsaMidiDriver&); - AlsaMidiDriver& operator=(const AlsaMidiDriver&); - - List m_in_ports; - List m_out_ports; - - friend class AlsaMidiPort; - - // Functions for AlsaMidiPort - void add_port(AlsaMidiPort* port); - AlsaMidiPort* remove_port(AlsaMidiPort* port); - - void add_output(ListNode* port); - ListNode* remove_output(AlsaMidiPort* port); - - // MIDI thread - static void* process_midi_in(void* me); - - snd_seq_t* m_seq_handle; - snd_midi_event_t* m_event_coder; - pthread_t m_process_thread; - bool m_is_activated; - static bool m_midi_thread_exit_flag; -}; - - -} // namespace Om - - -#endif // ALSAMIDIDRIVER_H diff --git a/src/engine/Array.h b/src/engine/Array.h deleted file mode 100644 index 6b56ecc5..00000000 --- a/src/engine/Array.h +++ /dev/null @@ -1,109 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ARRAY_H -#define ARRAY_H - -#include "MaidObject.h" -#include -#include -#include "util/types.h" - - -/** An array. - * - * Has a stack-like push_back() too, for find_process_order... - */ -template -class Array : public MaidObject -{ -public: - Array(size_t size = 0) : m_size(size), m_top(0), m_elems(NULL) { - if (size > 0) - m_elems = new T[size]; - } - - Array(size_t size, T initial_value) : m_size(size), m_top(0), m_elems(NULL) { - if (size > 0) { - m_elems = new T[size]; - for (size_t i=0; i < size; ++i) - m_elems[i] = initial_value; - } - } - - Array(size_t size, const Array* contents) : m_size(size), m_top(size+1) { - m_elems = new T[size]; - if (size <= contents->size()) - memcpy(m_elems, contents->m_elems, size * sizeof(T)); - else - memcpy(m_elems, contents->m_elems, contents->size() * sizeof(T)); - } - - ~Array() { - free(); - } - - void alloc(size_t num_elems) { - assert(num_elems > 0); - - delete[] m_elems; - m_size = num_elems; - m_top = 0; - - m_elems = new T[num_elems]; - } - - void alloc(size_t num_elems, T initial_value) { - assert(num_elems > 0); - - delete[] m_elems; - m_size = num_elems; - m_top = 0; - - m_elems = new T[num_elems]; - for (size_t i=0; i < m_size; ++i) - m_elems[i] = initial_value; - } - - void free() { - delete[] m_elems; - m_size = 0; - m_top = 0; - } - - void push_back(T n) { - assert(m_top < m_size); - m_elems[m_top++] = n; - } - - inline size_t size() const { return m_size; } - - inline T& operator[](size_t i) const { assert(i < m_size); return m_elems[i]; } - - inline T& at(size_t i) const { assert(i < m_size); return m_elems[i]; } - -private: - // Disallow copies (undefined) - Array(const Array& copy); - Array& operator=(const Array& copy); - - size_t m_size; - size_t m_top; // points to empty element above "top" element - T* m_elems; -}; - - -#endif // ARRAY_H diff --git a/src/engine/AudioDriver.h b/src/engine/AudioDriver.h deleted file mode 100644 index 056aeab4..00000000 --- a/src/engine/AudioDriver.h +++ /dev/null @@ -1,50 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef AUDIODRIVER_H -#define AUDIODRIVER_H - -#include "Driver.h" -#include "util/types.h" -#include "List.h" - -namespace Om { - -class Patch; -class AudioDriver; -template class PortBase; - - -/** Audio driver abstract base class. - * - * \ingroup engine - */ -class AudioDriver : public Driver -{ -public: - - virtual void set_root_patch(Patch* patch) = 0; - virtual Patch* root_patch() = 0; - - virtual samplecount buffer_size() const = 0; - virtual samplecount sample_rate() const = 0; - virtual samplecount time_stamp() const = 0; -}; - - -} // namespace Om - -#endif // AUDIODRIVER_H diff --git a/src/engine/AudioInputNode.cpp b/src/engine/AudioInputNode.cpp deleted file mode 100644 index 8a3594cb..00000000 --- a/src/engine/AudioInputNode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "AudioInputNode.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Plugin.h" -#include "PortInfo.h" -#include "Patch.h" - -namespace Om { - - -AudioInputNode::AudioInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: BridgeNode(path, poly, parent, srate, buffer_size) -{ - OutputPort* internal_port = new OutputPort(this, "in", 0, m_poly, - new PortInfo("in", AUDIO, OUTPUT), m_buffer_size); - InputPort* external_port = new InputPort(parent, m_name, 0, m_poly, - new PortInfo(m_name, AUDIO, INPUT), m_buffer_size); - external_port->tie(internal_port); - m_external_port = external_port; - internal_port->set_value(0, 0); - - m_num_ports = 1; - m_ports.alloc(m_num_ports); - m_ports.at(0) = internal_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("audio_input"); - m_plugin.name("Om Patch Audio Input Node"); -} - - -} // namespace Om - diff --git a/src/engine/AudioInputNode.h b/src/engine/AudioInputNode.h deleted file mode 100644 index 894ec082..00000000 --- a/src/engine/AudioInputNode.h +++ /dev/null @@ -1,45 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef AUDIOINPUTNODE_H -#define AUDIOINPUTNODE_H - -#include -#include "util/types.h" -#include "BridgeNode.h" - -using std::string; - -namespace Om { - -class Patch; -template class InputPort; - - -/** Audio input BridgeNode. - * - * \ingroup engine - */ -class AudioInputNode : public BridgeNode -{ -public: - AudioInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); -}; - - -} // namespace Om - -#endif // AUDIOINPUTNODE_H diff --git a/src/engine/AudioOutputNode.cpp b/src/engine/AudioOutputNode.cpp deleted file mode 100644 index d9a925f8..00000000 --- a/src/engine/AudioOutputNode.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "AudioOutputNode.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Plugin.h" -#include "Patch.h" -#include "PortInfo.h" -#include - -namespace Om { - - -AudioOutputNode::AudioOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: BridgeNode(path, poly, parent, srate, buffer_size) -{ - OutputPort* external_port = new OutputPort(parent, m_name, 0, m_poly, - new PortInfo(m_name, AUDIO, OUTPUT), m_buffer_size); - InputPort* internal_port = new InputPort(this, "out", 0, m_poly, - new PortInfo("out", AUDIO, INPUT), m_buffer_size); - internal_port->tie(external_port); - m_external_port = external_port; - internal_port->set_value(0, 0); - - m_num_ports = 1; - m_ports.alloc(m_num_ports); - m_ports.at(0) = internal_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("audio_output"); - m_plugin.name("Om Patch Audio Output Node"); -} - - -} // namespace Om - diff --git a/src/engine/AudioOutputNode.h b/src/engine/AudioOutputNode.h deleted file mode 100644 index 6399cfc6..00000000 --- a/src/engine/AudioOutputNode.h +++ /dev/null @@ -1,44 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef AUDIOOUTPUTNODE_H -#define AUDIOOUTPUTNODE_H - -#include -#include "util/types.h" -#include "BridgeNode.h" - -using std::string; - -namespace Om { - -template class OutputPort; - - -/** Audio output BridgeNode. - * - * \ingroup engine - */ -class AudioOutputNode : public BridgeNode -{ -public: - AudioOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); -}; - - -} // namespace Om - -#endif // AUDIOOUTPUTNODE_H diff --git a/src/engine/BridgeNode.cpp b/src/engine/BridgeNode.cpp deleted file mode 100644 index 776bcc92..00000000 --- a/src/engine/BridgeNode.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BridgeNode.h" -//#include "ClientBroadcaster.h" -#include "Plugin.h" -#include "Patch.h" -#include "Om.h" -#include "OmApp.h" -#include "Maid.h" -#include "Driver.h" -#include "PortInfo.h" -#include - -namespace Om { - -template -BridgeNode::BridgeNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: InternalNode(path, - (parent->parent_patch() == NULL || poly != parent->parent_patch()->poly()) ? 1 : poly, - //poly, - parent, srate, buffer_size), - m_driver_port(NULL), - m_listnode(NULL), - m_external_port(NULL) -{ - //cerr << "Creating bridge node " << path << " - polyphony: " << m_poly << endl; - m_listnode = new ListNode(this); -} -template -BridgeNode::BridgeNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); -template -BridgeNode::BridgeNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); - - -template -BridgeNode::~BridgeNode() -{ - delete m_driver_port; -} -template BridgeNode::~BridgeNode(); -template BridgeNode::~BridgeNode(); - - -template -void -BridgeNode::activate() -{ - assert(om->template driver() != NULL); - assert(m_external_port != NULL); // Derived classes must create this - assert(parent_patch() != NULL); - - if (parent_patch()->parent() == NULL && om != NULL) - m_driver_port = om->template driver()->create_port(m_external_port); - - InternalNode::activate(); -} - - -template -void -BridgeNode::deactivate() -{ - if (m_is_added) - remove_from_patch(); - - InternalNode::deactivate(); - - if (m_driver_port != NULL) { - delete m_driver_port; - m_driver_port = NULL; - } -} - - -template -void -BridgeNode::add_to_patch() -{ - assert(parent_patch() != NULL); - - parent_patch()->add_bridge_node(m_listnode); - - InternalNode::add_to_patch(); - - // Activate driver port now in the audio thread (not before when created, to avoid race issues) - if (m_driver_port != NULL) - m_driver_port->add_to_driver(); -} - - -template -void -BridgeNode::remove_from_patch() -{ - assert(parent_patch() != NULL); - - if (m_is_added) { - if (m_driver_port != NULL) - m_driver_port->remove_from_driver(); - ListNode* ln = NULL; - ln = parent_patch()->remove_bridge_node(this); - - om->maid()->push(ln); - m_listnode = NULL; - - } - InternalNode::remove_from_patch(); -} - - -template -void -BridgeNode::set_path(const Path& new_path) -{ - InternalNode::set_path(new_path); - - m_external_port->set_path(new_path); - - if (m_driver_port != NULL) - m_driver_port->set_name(path().c_str()); -} - - -#if 0 -template -void -BridgeNode::send_creation_messages(ClientInterface* client) const -{ - InternalNode::send_creation_messages(client); - om->client_broadcaster()->send_new_port_to(client, m_external_port); - - // Send metadata - for (map::const_iterator i = metadata().begin(); i != metadata().end(); ++i) - om->client_broadcaster()->send_metadata_update_to(client, path(), (*i).first, (*i).second); - - // Send control value (if necessary) - //if (m_external_port->port_info()->is_control()) - // om->client_broadcaster()->send_control_change_to(client, path(), - // ((PortBase*)m_external_port)->buffer(0)->value_at(0)); -} -#endif - - -} // namespace Om - diff --git a/src/engine/BridgeNode.h b/src/engine/BridgeNode.h deleted file mode 100644 index 99fad912..00000000 --- a/src/engine/BridgeNode.h +++ /dev/null @@ -1,90 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef BRIDGENODE_H -#define BRIDGENODE_H - -#include -#include "InternalNode.h" -#include "PortBase.h" -using std::string; - -template class ListNode; - -namespace Om { - -class DriverPort; -namespace Shared { - class ClientInterface; -} using Shared::ClientInterface; - - -/** A Node to represent input/output Ports on a Patch. - * - * This node acts as both a Node and a Port (it is the only Node type that - * returns non-null for as_port()). The node is a normal Node in a Patch, - * the Port is a Port on that Patch (port->parent == node->parent). - * - * This class handles all DriverPort functionality as well (if this Node - * is on a top level Patch). - * - * Both input and output nodes are handled in this class. - * - * This node will force itself to monophonic (regardless of the poly parameter - * passed to constructor) if the parent of the patch it's representing a port - * on has a different polyphony than the patch (since connecting mismatched - * polyphonies is impossible). - * - * \ingroup engine - */ -template -class BridgeNode : public InternalNode -{ -public: - virtual ~BridgeNode(); - - Port* as_port() { return m_external_port; } - - void activate(); - void deactivate(); - void add_to_patch(); - void remove_from_patch(); - //void send_creation_messages(ClientInterface* client) const; - - void set_path(const Path& new_path); - -protected: - // Disallow copies (undefined) - BridgeNode(const BridgeNode&); - BridgeNode& operator=(const BridgeNode&); - - BridgeNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); - - /** Driver port, used if this is on a top level Patch */ - DriverPort* m_driver_port; - - ListNode* m_listnode; - - PortBase* m_external_port; -}; - - -template class BridgeNode; -template class BridgeNode; - -} // namespace Om - -#endif // BRIDGENODE_H diff --git a/src/engine/Buffer.cpp b/src/engine/Buffer.cpp deleted file mode 100644 index 963b14a5..00000000 --- a/src/engine/Buffer.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Buffer.h" -#include -#include -#include -#include "MidiMessage.h" -using std::cerr; using std::endl; - -/* TODO: Be sure these functions are vectorized by GCC when it's vectorizer - * stops sucking. Probably a good idea to inline them as well */ - -namespace Om { - - -template -Buffer::Buffer(size_t size) -: m_size(size), - m_filled_size(0), - m_is_joined(false), - m_state(OK), - m_set_value(0), - m_data(NULL), - m_local_data(NULL) -{ - assert(m_size > 0); - allocate(); -} -template Buffer::Buffer(size_t size); -template Buffer::Buffer(size_t size); - - -/** Allocate and use a locally managed buffer (data). - */ -template -void -Buffer::allocate() -{ - assert(!m_is_joined); - assert(m_data == NULL); - assert(m_local_data == NULL); - assert(m_size > 0); - - const int ret = posix_memalign((void**)&m_local_data, 16, m_size * sizeof(T)); - if (ret != 0) { - cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl; - exit(EXIT_FAILURE); - } - - assert(ret == 0); - assert(m_local_data != NULL); - m_data = m_local_data; - - set(0, 0, m_size-1); -} -template void Buffer::allocate(); -template void Buffer::allocate(); - - -/** Free locally allocated buffer. - */ -template -void -Buffer::deallocate() -{ - assert(!m_is_joined); - free(m_local_data); - if (m_data == m_local_data) - m_data = NULL; - m_local_data = NULL; -} -template void Buffer::deallocate(); -template void Buffer::deallocate(); - - -/** Empty (ie zero) the buffer. - */ -template -void -Buffer::clear() -{ - set(0, 0, m_size-1); - m_state = OK; - m_filled_size = 0; -} -template void Buffer::clear(); -template void Buffer::clear(); - - -/** Set value of buffer to @a val after @a start_sample. - * - * The Buffer will handle setting the intial portion of the buffer to the - * value on the next cycle automatically (if @a start_sample is > 0), as - * long as pre_process() is called every cycle. - */ -template -void -Buffer::set(T val, size_t start_sample) -{ - assert(start_sample < m_size); - - set(val, start_sample, m_size-1); - - if (start_sample > 0) - m_state = HALF_SET_CYCLE_1; - - m_set_value = val; -} -template void Buffer::set(sample val, size_t start_sample); -template void Buffer::set(MidiMessage val, size_t start_sample); - - -/** Set a block of buffer to @a val. - * - * @a start_sample and @a end_sample define the inclusive range to be set. - */ -template -void -Buffer::set(T val, size_t start_sample, size_t end_sample) -{ - assert(start_sample >= 0); - assert(end_sample >= start_sample); - assert(end_sample < m_size); - assert(m_data != NULL); - - for (size_t i=start_sample; i <= end_sample; ++i) - m_data[i] = val; -} -template void Buffer::set(sample val, size_t start_sample, size_t end_sample); -template void Buffer::set(MidiMessage val, size_t start_sample, size_t end_sample); - - -/** Scale a block of buffer by @a val. - * - * @a start_sample and @a end_sample define the inclusive range to be set. - */ -template -void -Buffer::scale(T val, size_t start_sample, size_t end_sample) -{ - assert(start_sample >= 0); - assert(end_sample >= start_sample); - assert(end_sample < m_size); - assert(m_data != NULL); - - for (size_t i=start_sample; i <= end_sample; ++i) - m_data[i] *= val; -} -template void Buffer::scale(sample val, size_t start_sample, size_t end_sample); - - -/** Copy a block of @a src into buffer. - * - * @a start_sample and @a end_sample define the inclusive range to be set. - * This function only copies the same range in one buffer to another. - */ -template -void -Buffer::copy(const Buffer* src, size_t start_sample, size_t end_sample) -{ - assert(start_sample >= 0); - assert(end_sample >= start_sample); - assert(end_sample < m_size); - assert(src != NULL); - assert(src->data() != NULL); - assert(m_data != NULL); - - const T* const src_data = src->data(); - - for (size_t i=start_sample; i <= end_sample; ++i) - m_data[i] = src_data[i]; -} -template void Buffer::copy(const Buffer* const src, size_t start_sample, size_t end_sample); -template void Buffer::copy(const Buffer* const src, size_t start_sample, size_t end_sample); - - -/** Accumulate a block of @a src into @a dst. - * - * @a start_sample and @a end_sample define the inclusive range to be accumulated. - * This function only adds the same range in one buffer to another. - */ -template -void -Buffer::accumulate(const Buffer* const src, size_t start_sample, size_t end_sample) -{ - assert(start_sample >= 0); - assert(end_sample >= start_sample); - assert(end_sample < m_size); - assert(src != NULL); - assert(src->data() != NULL); - assert(m_data != NULL); - - const T* const src_data = src->data(); - - for (size_t i=start_sample; i <= end_sample; ++i) - m_data[i] += src_data[i]; - -} -template void Buffer::accumulate(const Buffer* const src, size_t start_sample, size_t end_sample); - - -/** Use another buffer's data instead of the local one. - * - * This buffer will essentially be identical to @a buf after this call. - */ -template -void -Buffer::join(Buffer* buf) -{ - assert(buf->size() == m_size); - - m_data = buf->m_data; - m_filled_size = buf->filled_size(); - m_is_joined = true; - - assert(m_filled_size <= m_size); -} -template void Buffer::join(Buffer* buf); -template void Buffer::join(Buffer* buf); - - -template -void -Buffer::unjoin() -{ - m_is_joined = false; - m_data = m_local_data; -} -template void Buffer::unjoin(); -template void Buffer::unjoin(); - - -template<> -void -Buffer::prepare(samplecount nframes) -{ - // FIXME: nframes parameter doesn't actually work, - // writing starts from 0 every time - assert(m_size == 1 || nframes == m_size); - - switch (m_state) { - case HALF_SET_CYCLE_1: - m_state = HALF_SET_CYCLE_2; - break; - case HALF_SET_CYCLE_2: - set(m_set_value, 0, m_size-1); - m_state = OK; - break; - default: - break; - } -} - - -////// DriverBuffer //////// - -template -DriverBuffer::DriverBuffer(size_t size) -: Buffer(size) -{ - Buffer::deallocate(); // FIXME: allocate then immediately deallocate, dirty - Buffer::m_data = NULL; -} -template DriverBuffer::DriverBuffer(size_t size); -template DriverBuffer::DriverBuffer(size_t size); - - -/** Set the buffer (data) used. - * - * This is only to be used by Drivers (to provide zero-copy processing). - */ -template -void -DriverBuffer::set_data(T* data) -{ - assert(!m_is_joined); - m_data = data; -} -template void DriverBuffer::set_data(sample* data); -template void DriverBuffer::set_data(MidiMessage* data); - - -} // namespace Om diff --git a/src/engine/Buffer.h b/src/engine/Buffer.h deleted file mode 100644 index 13d62727..00000000 --- a/src/engine/Buffer.h +++ /dev/null @@ -1,91 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef BUFFER_H -#define BUFFER_H - -#include -#include -#include "util/types.h" - -namespace Om { - - -template -class Buffer -{ -public: - Buffer(size_t size); - - void clear(); - void set(T val, size_t start_sample); - void set(T val, size_t start_sample, size_t end_sample); - void scale(T val, size_t start_sample, size_t end_sample); - void copy(const Buffer* src, size_t start_sample, size_t end_sample); - void accumulate(const Buffer* src, size_t start_sample, size_t end_sample); - - void join(Buffer* buf); - void unjoin(); - - inline T& value_at(size_t offset) { assert(offset < m_size); return m_data[offset]; } - - void prepare(samplecount nframes); - - void filled_size(size_t size) { m_filled_size = size; } - size_t filled_size() const { return m_filled_size; } - bool is_joined() const { return m_is_joined; } - size_t size() const { return m_size; } - T* data() const { return m_data; } - -protected: - enum BufferState { OK, HALF_SET_CYCLE_1, HALF_SET_CYCLE_2 }; - - void allocate(); - void deallocate(); - - size_t m_size; ///< Allocated buffer size - size_t m_filled_size; ///< Usable buffer size (for MIDI ports etc) - bool m_is_joined; ///< Whether or not @ref m_data is shares with another Buffer - BufferState m_state; ///< State of buffer for setting values next cycle - T m_set_value; ///< Value set by @ref set (may need to be set next cycle) - - T* m_data; ///< Buffer to be returned by data() (not equal to m_local_data if joined) - T* m_local_data; ///< Locally allocated buffer -}; - - -/** Less robust Buffer for Driver's use. - * - * Does not allocate an array by default, and allows direct setting of - * data pointer for zero-copy processing. - */ -template -class DriverBuffer : public Buffer -{ -public: - DriverBuffer(size_t size); - - void set_data(T* data); - -private: - using Buffer::m_data; - using Buffer::m_is_joined; -}; - - -} // namespace Om - -#endif // BUFFER_H diff --git a/src/engine/ClientBroadcaster.cpp b/src/engine/ClientBroadcaster.cpp deleted file mode 100644 index f8823233..00000000 --- a/src/engine/ClientBroadcaster.cpp +++ /dev/null @@ -1,331 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ClientBroadcaster.h" -#include -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "ObjectStore.h" -#include "NodeFactory.h" -#include "util.h" -#include "Patch.h" -#include "Node.h" -#include "PortInfo.h" -#include "Plugin.h" -#include "PortBase.h" -#include "Connection.h" -#include "AudioDriver.h" -#include "ObjectSender.h" -#include "interface/ClientKey.h" -#include "interface/ClientInterface.h" -#include "OSCClient.h" -using std::cout; using std::cerr; using std::endl; -using Om::Shared::ClientInterface; - -namespace Om { - - -/** Register a client to receive messages over the notification band. - */ -void -ClientBroadcaster::register_client(const ClientKey key, CountedPtr client) -{ - assert(key.type() == ClientKey::OSC_URL); - assert(key.uri() != ""); - - bool found = false; - for (ClientList::iterator i = _clients.begin(); i != _clients.end(); ++i) - if ((*i).first == key) - found = true; - - if (!found) { - _clients.push_back(pair >(key, client)); - cout << "[ClientBroadcaster] Registered client " << key.uri() - << " (" << _clients.size() << " clients)" << endl; - } else { - cout << "[ClientBroadcaster] Client already registered." << endl; - } -} - - -/** Remove a client from the list of registered clients. - * - * The removed client is returned (not deleted). It is the caller's - * responsibility to delete the returned pointer, if it's not NULL. - * - * @return true if client was found and removed (and refcount decremented). - */ -bool -ClientBroadcaster::unregister_client(const ClientKey& key) -{ - cerr << "FIXME: unregister broken\n"; - return false; - -#if 0 - if (responder == NULL) - return NULL; - - // FIXME: remove filthy cast - const string url = lo_address_get_url(((OSCResponder*)responder)->source()); - ClientInterface* r = NULL; - - for (ClientList::iterator i = _clients.begin(); i != _clients.end(); ++i) { - if ((*i).second->url() == url) { - r = *i; - _clients.erase(i); - break; - } - } - - if (r != NULL) - cout << "[OSC] Unregistered client " << r->url() << " (" << _clients.size() << " clients)" << endl; - else - cerr << "[OSC] ERROR: Unable to find client to unregister!" << endl; - - return r; -#endif -} - - - -/** Looks up the client with the given @a source address (which is used as the - * unique identifier for registered clients). - * - * (A responder is passed to remove the dependency on liblo addresses in request - * events, in anticipation of libom and multiple ways of responding to clients). - */ -CountedPtr -ClientBroadcaster::client(const ClientKey& key) -{ - for (ClientList::iterator i = _clients.begin(); i != _clients.end(); ++i) - if ((*i).first == key) - return (*i).second; - - cerr << "[ClientBroadcaster] Failed to find client." << endl; - - return NULL; -} - - -void -ClientBroadcaster::send_error(const string& msg) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->error(msg); -} - - - -void -ClientBroadcaster::send_plugins_to(ClientInterface* client) -{ - om->node_factory()->lock_plugin_list(); - - const list& plugs = om->node_factory()->plugins(); - const Plugin* plugin; - - lo_timetag tt; - lo_timetag_now(&tt); - lo_bundle b = lo_bundle_new(tt); - lo_message m = lo_message_new(); - list msgs; - - lo_message_add_int32(m, plugs.size()); - lo_bundle_add_message(b, "/om/num_plugins", m); - msgs.push_back(m); - - for (list::const_iterator j = plugs.begin(); j != plugs.end(); ++j) { - plugin = (*j); - m = lo_message_new(); - - lo_message_add_string(m, plugin->type_string()); - lo_message_add_string(m, plugin->uri().c_str()); - lo_message_add_string(m, plugin->name().c_str()); - lo_bundle_add_message(b, "/om/plugin", m); - msgs.push_back(m); - if (lo_bundle_length(b) > 1024) { - // FIXME FIXME FIXME dirty, dirty cast - lo_send_bundle(((OSCClient*)client)->address(), b); - lo_bundle_free(b); - b = lo_bundle_new(tt); - } - } - - if (lo_bundle_length(b) > 0) { - // FIXME FIXME FIXME dirty, dirty cast - lo_send_bundle(((OSCClient*)client)->address(), b); - lo_bundle_free(b); - } else { - lo_bundle_free(b); - } - for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i) - lo_message_free(*i); - - om->node_factory()->unlock_plugin_list(); -} - - -void -ClientBroadcaster::send_node(const Node* node) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - ObjectSender::send_node((*i).second.get(), node); -} - - -void -ClientBroadcaster::send_port(const Port* port) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - ObjectSender::send_port((*i).second.get(), port); -} - - -void -ClientBroadcaster::send_destroyed(const string& path) -{ - assert(path != "/"); - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->object_destroyed(path); -} - -void -ClientBroadcaster::send_patch_cleared(const string& patch_path) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->patch_cleared(patch_path); -} - -void -ClientBroadcaster::send_connection(const Connection* const c) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->connection(c->src_port()->path(), c->dst_port()->path()); -} - - -void -ClientBroadcaster::send_disconnection(const string& src_port_path, const string& dst_port_path) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->disconnection(src_port_path, dst_port_path); -} - - -void -ClientBroadcaster::send_patch_enable(const string& patch_path) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->patch_enabled(patch_path); -} - - -void -ClientBroadcaster::send_patch_disable(const string& patch_path) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->patch_disabled(patch_path); -} - - -/** Send notification of a metadata update. - * - * Like control changes, does not send update to client that set the metadata, if applicable. - */ -void -ClientBroadcaster::send_metadata_update(const string& node_path, const string& key, const string& value) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->metadata_update(node_path, key, value); -} - - -/** Send notification of a control change. - * - * If responder is specified, the notification will not be send to the address of - * that responder (to avoid sending redundant information back to clients and - * forcing clients to ignore things to avoid feedback loops etc). - */ -void -ClientBroadcaster::send_control_change(const string& port_path, float value) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->control_change(port_path, value); -} - - -void -ClientBroadcaster::send_program_add(const string& node_path, int bank, int program, const string& name) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->program_add(node_path, bank, program, name); -} - - -void -ClientBroadcaster::send_program_remove(const string& node_path, int bank, int program) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->program_remove(node_path, bank, program); -} - - -/** Send a patch. - * - * Sends all objects underneath Patch - contained Nodes, etc. - */ -void -ClientBroadcaster::send_patch(const Patch* const p) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - ObjectSender::send_patch((*i).second.get(), p); -} - - -/** Sends notification of an OmObject's renaming - */ -void -ClientBroadcaster::send_rename(const string& old_path, const string& new_path) -{ - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - (*i).second->object_renamed(old_path, new_path); -} - - -/** Sends all OmObjects known to the engine. - */ -void -ClientBroadcaster::send_all_objects() -{ - cerr << "FIXME: send_all" << endl; - - //for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - // (*i).second->send_all_objects(); -} - -/* -void -ClientBroadcaster::send_node_creation_messages(const Node* const node) -{ - // This is pretty stupid :/ in and out and back again! - for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) - node->send_creation_messages((*i).second); -} -*/ - -} // namespace Om diff --git a/src/engine/ClientBroadcaster.h b/src/engine/ClientBroadcaster.h deleted file mode 100644 index b0a60f57..00000000 --- a/src/engine/ClientBroadcaster.h +++ /dev/null @@ -1,101 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CLIENTBROADCASTER_H -#define CLIENTBROADCASTER_H - -#include -#include -#include -#include -#include -#include -#include "util/types.h" -#include "interface/ClientInterface.h" -#include "util/CountedPtr.h" - -using std::list; using std::string; using std::pair; - -namespace Om { - -class Node; -class Port; -class PortInfo; -class Plugin; -class Patch; -class Connection; -class Responder; -namespace Shared { class ClientKey; } -using Shared::ClientKey; -using Shared::ClientInterface; - -/** Broadcaster for all clients. - * - * This sends messages to all client simultaneously through the opaque - * ClientInterface. The clients may be OSC driver, in process, theoretically - * anything that implements ClientInterface. - * - * This also serves as the database of all registered clients. - * - * \ingroup engine - */ -class ClientBroadcaster -{ -public: - void register_client(const ClientKey key, CountedPtr client); - bool unregister_client(const ClientKey& key); - - CountedPtr client(const ClientKey& key); - - // Notification band: - - //void send_client_registration(const string& url, int client_id); - - // Error that isn't the direct result of a request - void send_error(const string& msg); - - void send_plugins_to(ClientInterface* client); - - //void send_node_creation_messages(const Node* const node); - - void send_patch(const Patch* const p); - void send_node(const Node* const node); - void send_port(const Port* port); - void send_destroyed(const string& path); - void send_patch_cleared(const string& patch_path); - void send_connection(const Connection* const connection); - void send_disconnection(const string& src_port_path, const string& dst_port_path); - void send_rename(const string& old_path, const string& new_path); - void send_all_objects(); - void send_patch_enable(const string& patch_path); - void send_patch_disable(const string& patch_path); - void send_metadata_update(const string& node_path, const string& key, const string& value); - void send_control_change(const string& port_path, float value); - void send_program_add(const string& node_path, int bank, int program, const string& name); - void send_program_remove(const string& node_path, int bank, int program); - -private: - typedef list > > ClientList; - //list > _clients; - ClientList _clients; -}; - - - -} // namespace Om - -#endif // CLIENTBROADCASTER_H - diff --git a/src/engine/Connection.cpp b/src/engine/Connection.cpp deleted file mode 100644 index d1592009..00000000 --- a/src/engine/Connection.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Connection.h" -#include "util.h" -#include "Node.h" -#include "Om.h" -#include "Port.h" - -namespace Om { - - -/** Constructor for a connection from a node's output port. - * - * This handles both polyphonic and monophonic nodes, transparently to the - * user (InputPort). - */ -Connection::Connection(Port* const src_port, Port* const dst_port) -: m_src_port(src_port), - m_dst_port(dst_port), - m_is_poly_to_mono( (src_port->parent_node()->poly() > dst_port->parent_node()->poly()) ), - m_pending_disconnection(false) -{ - assert(src_port != NULL); - assert(dst_port != NULL); - - assert((src_port->parent_node()->poly() == dst_port->parent_node()->poly()) - || (src_port->parent_node()->poly() == 1 || dst_port->parent_node()->poly() == 1)); -} - -} // namespace Om - diff --git a/src/engine/Connection.h b/src/engine/Connection.h deleted file mode 100644 index 769c2047..00000000 --- a/src/engine/Connection.h +++ /dev/null @@ -1,66 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CONNECTION_H -#define CONNECTION_H - -#include -#include "MaidObject.h" -#include "util/types.h" - -namespace Om { - -class Port; - - -/** Represents a single inbound connection for an InputPort. - * - * This can be a group of ports (ie coming from a polyphonic Node) or - * a single Port. This class exists basically as an abstraction of mixing - * down polyphonic inputs, so InputPort can just deal with mixing down - * multiple connections (oblivious to the polyphonic situation of the - * connection itself). - * - * \ingroup engine - */ -class Connection : public MaidObject -{ -public: - virtual ~Connection() {} - - Port* src_port() const { return m_src_port; } - Port* dst_port() const { return m_dst_port; } - - /** Used by some (recursive) events to prevent double disconnections */ - bool pending_disconnection() { return m_pending_disconnection; } - void pending_disconnection(bool b) { m_pending_disconnection = b; } - -protected: - // Disallow copies (undefined) - Connection(const Connection&); - - Connection(Port* const src_port, Port* const dst_port); - - Port* const m_src_port; - Port* const m_dst_port; - bool m_is_poly_to_mono; - bool m_pending_disconnection; -}; - - -} // namespace Om - -#endif // CONNECTION_H diff --git a/src/engine/ConnectionBase.cpp b/src/engine/ConnectionBase.cpp deleted file mode 100644 index c8936818..00000000 --- a/src/engine/ConnectionBase.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ConnectionBase.h" -#include "util.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Node.h" -#include "Om.h" -#include "Port.h" - -namespace Om { - - -/** Constructor for a connection from a node's output port. - * - * This handles both polyphonic and monophonic nodes, transparently to the - * user (InputPort). - */ -template -ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port) -: Connection(src_port, dst_port), - m_local_buffer(NULL), - m_is_poly_to_mono( (src_port->parent_node()->poly() > dst_port->parent_node()->poly()) ), - m_buffer_size(src_port->buffer_size()), - m_pending_disconnection(false) -{ - assert((src_port->parent_node()->poly() == dst_port->parent_node()->poly()) - || (src_port->parent_node()->poly() == 1 || dst_port->parent_node()->poly() == 1)); - - if (m_is_poly_to_mono) // Poly -> Mono connection, need a buffer to mix in to - m_local_buffer = new Buffer(m_buffer_size); -} -template ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); -template ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); - - -template -ConnectionBase::~ConnectionBase() -{ - delete m_local_buffer; -} -template ConnectionBase::~ConnectionBase(); -template ConnectionBase::~ConnectionBase(); - - -template -void -ConnectionBase::prepare_buffers() -{ - /* Thought: A poly output port can be connected to multiple mono input - * ports, which means this mix down would have to happen many times. - * Adding a method to OutputPort that mixes down all it's outputs into - * a buffer (if it hasn't been done already this cycle) and returns that - * would avoid having to mix multiple times. Probably not a very common - * case, but it would be faster anyway. */ - - if (m_is_poly_to_mono) { - m_local_buffer->copy(src_port()->buffer(0), 0, m_buffer_size-1); - - // Mix all the source's voices down into local buffer starting at the second - // voice (buffer is already set to first voice above) - for (size_t j=1; j < src_port()->poly(); ++j) - m_local_buffer->accumulate(src_port()->buffer(j), 0, m_buffer_size-1); - - // Scale the buffer down. - if (src_port()->poly() > 1) - m_local_buffer->scale(1.0f/(float)src_port()->poly(), 0, m_buffer_size-1); - } -} -template void ConnectionBase::prepare_buffers(); - - -// FIXME: MIDI mixing not implemented -template <> -void -ConnectionBase::prepare_buffers() -{ -} - - -} // namespace Om - diff --git a/src/engine/ConnectionBase.h b/src/engine/ConnectionBase.h deleted file mode 100644 index 72acae2e..00000000 --- a/src/engine/ConnectionBase.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CONNECTIONBASE_H -#define CONNECTIONBASE_H - -#include "util/types.h" -#include "OutputPort.h" -#include "Connection.h" - -namespace Om { - -class MidiMessage; -class Port; -template class InputPort; - - -/** A Connection with a type. - * - * \ingroup engine - */ -template -class ConnectionBase : public Connection -{ -public: - ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); - virtual ~ConnectionBase(); - - void prepare_buffers(); - - inline OutputPort* src_port() const { return (OutputPort*)m_src_port; } - inline InputPort* dst_port() const { return (InputPort*)m_dst_port; } - - /** Used by some (recursive) events to prevent double disconnections */ - bool pending_disconnection() { return m_pending_disconnection; } - void pending_disconnection(bool b) { m_pending_disconnection = b; } - - /** Get the buffer for a particular voice. - * A ConnectionBase is smart - it knows the destination port respondering the - * buffer, and will return accordingly (ie the same buffer for every voice - * in a mono->poly connection). - */ - inline Buffer* buffer(size_t voice) const; - -private: - // Disallow copies (undefined) - ConnectionBase(const ConnectionBase& copy); - ConnectionBase& operator=(const ConnectionBase&); - - Buffer* m_local_buffer; ///< Only used for poly->mono connections - bool m_is_poly_to_mono; - size_t m_buffer_size; - bool m_pending_disconnection; -}; - - -template <> -inline Buffer* -ConnectionBase::buffer(size_t voice) const -{ - PortBase* const src_port = (PortBase*)m_src_port; - - if (m_is_poly_to_mono) { - return m_local_buffer; - } else { - if (src_port->poly() == 1) - return src_port->buffer(0); - else - return src_port->buffer(voice); - } -} - - -template <> -inline Buffer* -ConnectionBase::buffer(size_t voice) const -{ - // No such thing as polyphonic MIDI ports - assert(m_src_port->poly() == 1); - assert(m_dst_port->poly() == 1); - - PortBase* const src_port = (PortBase*)m_src_port; - return src_port->buffer(0); -} - - -template class ConnectionBase; -template class ConnectionBase; - -} // namespace Om - -#endif // CONNECTIONBASE_H diff --git a/src/engine/ControlInputNode.cpp b/src/engine/ControlInputNode.cpp deleted file mode 100644 index d4d83558..00000000 --- a/src/engine/ControlInputNode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ControlInputNode.h" -#include "util/types.h" -#include "Patch.h" -#include "OutputPort.h" -#include "InputPort.h" -#include "Plugin.h" -#include "PortInfo.h" - -namespace Om { - - -ControlInputNode::ControlInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: BridgeNode(path, poly, parent, srate, buffer_size) -{ - OutputPort* internal_port = new OutputPort(this, "in", 0, m_poly, - new PortInfo("in", CONTROL, OUTPUT), 1); - InputPort* external_port = new InputPort(parent, m_name, 0, m_poly, - new PortInfo(m_name, CONTROL, INPUT), 1); - external_port->tie(internal_port); - m_external_port = external_port; - - m_num_ports = 1; - m_ports.alloc(m_num_ports); - m_ports.at(0) = internal_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("control_input"); - m_plugin.name("Om Patch Control Input Node"); -} - - -} // namespace Om - diff --git a/src/engine/ControlInputNode.h b/src/engine/ControlInputNode.h deleted file mode 100644 index 0be82af0..00000000 --- a/src/engine/ControlInputNode.h +++ /dev/null @@ -1,44 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CONTROLINPUTNODE_H -#define CONTROLINPUTNODE_H - -#include -#include "util/types.h" -#include "BridgeNode.h" - -using std::string; - -namespace Om { - -template class InputPort; - - -/** Control input BridgeNode. - * - * \ingroup engine - */ -class ControlInputNode : public BridgeNode -{ -public: - ControlInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); -}; - - -} // namespace Om - -#endif // CONTROLINPUTNODE_H diff --git a/src/engine/ControlOutputNode.cpp b/src/engine/ControlOutputNode.cpp deleted file mode 100644 index 7e1f3e2a..00000000 --- a/src/engine/ControlOutputNode.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ControlOutputNode.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "PortInfo.h" -#include "Plugin.h" -#include "Patch.h" - -namespace Om { - - -ControlOutputNode::ControlOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: BridgeNode(path, poly, parent, srate, buffer_size) -{ - OutputPort* external_port = new OutputPort(parent, m_name, 0, m_poly, - new PortInfo(m_name, CONTROL, OUTPUT), 1); - InputPort* internal_port = new InputPort(this, "out", 0, m_poly, - new PortInfo("out", CONTROL, INPUT), 1); - internal_port->tie(external_port); - m_external_port = external_port; - - m_num_ports = 1; - m_ports.alloc(m_num_ports); - m_ports.at(0) = internal_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("control_output"); - m_plugin.name("Om Patch Control Output Node"); -} - - -} // namespace Om - diff --git a/src/engine/ControlOutputNode.h b/src/engine/ControlOutputNode.h deleted file mode 100644 index 64fd9ce6..00000000 --- a/src/engine/ControlOutputNode.h +++ /dev/null @@ -1,45 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CONTROLOUTPUTNODE_H -#define CONTROLOUTPUTNODE_H - -#include -#include "util/types.h" -#include "BridgeNode.h" - -using std::string; - -namespace Om { - -class Port; -template class OutputPort; - - -/** Control output BridgeNode. - * - * \ingroup engine - */ -class ControlOutputNode : public BridgeNode -{ -public: - ControlOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); -}; - - -} // namespace Om - -#endif // CONTROLOUTPUTNODE_H diff --git a/src/engine/Controller.h b/src/engine/Controller.h deleted file mode 100644 index facfb4c2..00000000 --- a/src/engine/Controller.h +++ /dev/null @@ -1,82 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CONTROLLER_H -#define CONTROLLER_H - -namespace Om { - - -/** Public interface to Om engine shared library. - * - * This is an interface to all the audio-processing related functionality - * only. OSC communication, LASH session management, etc, are not part of - * this library. - */ -class Controller { -public: - void init(); - void quit(); - - void load_plugins(); - - void activate_engine(); - void deactivate_engine(); - - void create_patch(const char* path, unsigned int polyphony); - void clear_patch(const char* path); - void enable_patch(const char* path); - void disable_patch(const char* path); - void rename(const char* old_path, const char* new_path); - - void create_node(const char* path, - const char* type, - const char* library_name, - const char* library_label, - unsigned int polyphony); - - void destroy(const char* path); - - void connect(const char* src_port_path, const char* dst_port_path); - void disconnect(const char* src_port_path, const char* dst_port_path); - void disconnect_all(const char* path); - - void set_port_value(const char* path, float value); - void set_port_value_voice(const char* path, unsigned int voice); - void set_port_value_slow(const char* path, float value); - - void note_on(const char* node_path, - unsigned char note_num, - unsigned char velocity); - - void note_off(const char* node_path, - unsigned char note_num); - - void all_notes_off(const char* node_path); - void midi_learn(const char* node_path); - - void get_metadata(); - void set_metadata(); - void responder_plugins(); - void responder_all_objects(); - void responder_port_value(); -}; - - -} // namespace Om - -#endif // CONTROLLER_H - diff --git a/src/engine/DSSIPlugin.cpp b/src/engine/DSSIPlugin.cpp deleted file mode 100644 index e8525b7b..00000000 --- a/src/engine/DSSIPlugin.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DSSIPlugin.h" -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "ClientBroadcaster.h" -#include "interface/ClientInterface.h" -#include "InputPort.h" -#include "PortInfo.h" - -using namespace std; - -namespace Om { - - -DSSIPlugin::DSSIPlugin(const string& name, size_t poly, Patch* parent, DSSI_Descriptor* descriptor, samplerate srate, size_t buffer_size) -: LADSPAPlugin(name, 1, parent, descriptor->LADSPA_Plugin, srate, buffer_size), - m_dssi_descriptor(descriptor), - m_ui_addr(NULL), - m_bank(-1), - m_program(-1), - m_midi_in_port(NULL), - m_alsa_events(new snd_seq_event_t[m_buffer_size]), - m_alsa_encoder(NULL) -{ - if (has_midi_input()) - m_num_ports = descriptor->LADSPA_Plugin->PortCount + 1; - - snd_midi_event_new(3, &m_alsa_encoder); -} - - -DSSIPlugin::~DSSIPlugin() -{ - if (m_ui_addr != NULL) - lo_address_free(m_ui_addr); - - snd_midi_event_free(m_alsa_encoder); - delete [] m_alsa_events; -} - - -/** This needs to be overridden here because LADSPAPlugin::instantiate() - * allocates the port array, and we want to add the MIDI input port to that - * array. - */ -bool -DSSIPlugin::instantiate() -{ - if (!LADSPAPlugin::instantiate()) - return false; - - if (has_midi_input()) { - assert(m_num_ports == m_descriptor->PortCount + 1); - assert(m_ports.size() == m_descriptor->PortCount + 1); - - m_midi_in_port = new InputPort(this, "MIDI In", m_num_ports-1, 1, - new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); - m_ports.at(m_num_ports-1) = m_midi_in_port; - } - - return true; -} - - -void -DSSIPlugin::activate() -{ - LADSPAPlugin::activate(); - - update_programs(false); - set_default_program(); - - snd_midi_event_reset_encode(m_alsa_encoder); -} - - -void -DSSIPlugin::set_ui_url(const string& url) -{ - if (m_ui_addr != NULL) - lo_address_free(m_ui_addr); - - m_ui_url = url; - m_ui_addr = lo_address_new_from_url(url.c_str()); - char* base_path = lo_url_get_path(url.c_str()); - m_ui_base_path = base_path; - free(base_path); - cerr << "Set UI base path to " << m_ui_base_path << endl; -} - - -void -DSSIPlugin::set_control(size_t port_num, sample val) -{ - assert(port_num < m_descriptor->PortCount); - ((PortBase*)m_ports.at(port_num))->set_value(val, 0); -} - - -void -DSSIPlugin::configure(const string& key, const string& val) -{ - m_dssi_descriptor->configure(m_instances[0], key.c_str(), val.c_str()); - m_configures[key] = val; - update_programs(true); -} - - -void -DSSIPlugin::program(int bank, int program) -{ - if (m_dssi_descriptor->select_program) - m_dssi_descriptor->select_program(m_instances[0], bank, program); - - m_bank = bank; - m_program = program; -} - - -void -DSSIPlugin::convert_events() -{ - assert(has_midi_input()); - assert(m_midi_in_port != NULL); - - Buffer& buffer = *m_midi_in_port->buffer(0); - m_encoded_events = 0; - - for (size_t i = 0; i < buffer.filled_size(); ++i) { - snd_midi_event_encode(m_alsa_encoder, buffer.value_at(i).buffer, - buffer.value_at(i).size, - &m_alsa_events[m_encoded_events]); - m_alsa_events[m_encoded_events].time.tick = buffer.value_at(i).time; - if (m_alsa_events[m_encoded_events].type != SND_SEQ_EVENT_NONE) - ++m_encoded_events; - } -} - - -bool -DSSIPlugin::has_midi_input() const -{ - return (m_dssi_descriptor->run_synth || m_dssi_descriptor->run_multiple_synths); -} - - -void -DSSIPlugin::run(size_t nframes) -{ - NodeBase::run(nframes); - - if (m_dssi_descriptor->run_synth) { - convert_events(); - m_dssi_descriptor->run_synth(m_instances[0], nframes, - m_alsa_events, m_encoded_events); - } else if (m_dssi_descriptor->run_multiple_synths) { - convert_events(); - // I hate this stupid function - snd_seq_event_t* events[1] = { m_alsa_events }; - long unsigned events_sizes[1] = { m_encoded_events }; - m_dssi_descriptor->run_multiple_synths(1, m_instances, nframes, - events, events_sizes); - } else { - LADSPAPlugin::run(nframes); - } -} - - -void -DSSIPlugin::send_control(int port_num, float value) -{ - string path = m_ui_base_path + "/control"; - lo_send(m_ui_addr, path.c_str(), "if", port_num, value); -} - - -void -DSSIPlugin::send_program(int bank, int value) -{ - string path = m_ui_base_path + "/program"; - lo_send(m_ui_addr, path.c_str(), "ii", bank, value); -} - - -void -DSSIPlugin::send_configure(const string& key, const string& val) -{ - string path = m_ui_base_path + "/configure"; - lo_send(m_ui_addr, path.c_str(), "ss", key.c_str(), val.c_str()); -} - - -void -DSSIPlugin::send_show() -{ - string path = m_ui_base_path + "/show"; - lo_send(m_ui_addr, path.c_str(), NULL); -} - - -void -DSSIPlugin::send_hide() -{ - string path = m_ui_base_path + "/hide"; - lo_send(m_ui_addr, path.c_str(), NULL); -} - - -void -DSSIPlugin::send_quit() -{ - string path = m_ui_base_path + "/quit"; - lo_send(m_ui_addr, path.c_str(), NULL); -} - - -void -DSSIPlugin::send_update() -{ - // send "configure"s - for (map::iterator i = m_configures.begin(); i != m_configures.end(); ++i) - send_configure((*i).first, (*i).second); - - // send "program" - send_program(m_bank, m_program); - - // send "control"s - for (size_t i=0; i < m_ports.size(); ++i) - if (m_ports[i]->port_info()->is_control()) - send_control(m_ports[i]->num(), ((PortBase*)m_ports[i])->buffer(0)->value_at(0)); - - // send "show" FIXME: not to spec - send_show(); -} - - -bool -DSSIPlugin::update_programs(bool send_events) -{ - // remember all old banks and programs - set > to_be_deleted; - map::const_iterator iter; - Bank::const_iterator iter2; - for (iter = m_banks.begin(); iter != m_banks.end(); ++iter) { - for (iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) { - to_be_deleted.insert(make_pair(iter->first, iter2->first)); - } - } - - // iterate over all programs - if (m_dssi_descriptor->get_program) { - for (int i = 0; true; ++i) { - const DSSI_Program_Descriptor* descriptor = - m_dssi_descriptor->get_program(m_instances[0], i); - if (!descriptor) - break; - - iter = m_banks.find(descriptor->Bank); - if (iter == m_banks.end() || - iter->second.find(descriptor->Program) == iter->second.end() || - iter->second.find(descriptor->Program)->second != descriptor->Name) { - m_banks[descriptor->Bank][descriptor->Program] = descriptor->Name; - if (send_events) { - om->client_broadcaster()->send_program_add(path(), descriptor->Bank, - descriptor->Program, - descriptor->Name); - } - to_be_deleted.erase(make_pair(descriptor->Bank, descriptor->Program)); - } - } - } - - // remove programs that has disappeared from the plugin - set >::const_iterator set_iter; - for (set_iter = to_be_deleted.begin(); - set_iter != to_be_deleted.end(); ++set_iter) { - m_banks[set_iter->first].erase(set_iter->second); - if (send_events) - om->client_broadcaster()->send_program_remove(path(), set_iter->first, set_iter->second); - if (m_banks[set_iter->first].size() == 0) - m_banks.erase(set_iter->first); - } - - return true; -} - - -void -DSSIPlugin::set_default_program() -{ - map::const_iterator iter = m_banks.begin(); - if (iter != m_banks.end()) { - Bank::const_iterator iter2 = iter->second.begin(); - if (iter2 != iter->second.end()) - program(iter->first, iter2->first); - } -} - - -const map& -DSSIPlugin::get_programs() const -{ - return m_banks; -} - - -/* -void -DSSIPlugin::send_creation_messages(ClientInterface* client) const -{ - LADSPAPlugin::send_creation_messages(client); - - for (map::const_iterator i = get_programs().begin(); - i != get_programs().end(); ++i) { - - for (Bank::const_iterator j = i->second.begin(); j != i->second.end(); ++j) - client->program_add(path(), - i->first, j->first, j->second); - } -} -*/ - -} // namespace Om diff --git a/src/engine/DSSIPlugin.cpp.orig b/src/engine/DSSIPlugin.cpp.orig deleted file mode 100644 index 7c8060f0..00000000 --- a/src/engine/DSSIPlugin.cpp.orig +++ /dev/null @@ -1,207 +0,0 @@ -/* This file is part of Om. Copyright (C) 2005 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DSSIPlugin.h" -#include -#include "Om.h" -#include "OmApp.h" -#include "config.h" -#include "Patch.h" -#include "PortBase.h" -#include "InputPort.h" -#include "PortInfo.h" - -using std::map; - -namespace Om { - - -DSSIPlugin::DSSIPlugin(const string& name, uint poly, Patch* parent, DSSI_Descriptor* descriptor, samplerate srate, size_t buffer_size) -: LADSPAPlugin(name, 1, parent, descriptor->LADSPA_Plugin, srate, buffer_size), - m_ui_addr(NULL), - m_bank(-1), - m_program(-1), - m_dssi_descriptor(descriptor) -{ - m_num_ports = descriptor->LADSPA_Plugin->PortCount + 1; - m_ports.alloc(m_num_ports); - - m_midi_in_port = new InputPort(this, "MIDI In", m_num_ports-1, 1, - new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); - - m_ports.at(m_num_ports-1) = m_midi_in_port; -} - - -DSSIPlugin::~DSSIPlugin() -{ - if (m_ui_addr != NULL) - lo_address_free(m_ui_addr); -} - - -void -DSSIPlugin::activate() -{ - LADSPAPlugin::activate(); -} - - -void -DSSIPlugin::set_ui_url(const string& url) -{ - if (m_ui_addr != NULL) - lo_address_free(m_ui_addr); - - m_ui_url = url; - m_ui_addr = lo_address_new_from_url(url.c_str()); - char* base_path = lo_url_get_path(url.c_str()); - m_ui_base_path = base_path; - free(base_path); - cerr << "Set UI base path to " << m_ui_base_path << endl; -} - - -void -DSSIPlugin::set_control(uint port_num, sample val) -{ - assert(port_num < m_descriptor->PortCount); - ((PortBase*)m_ports.at(port_num))->set_value(0, val); -} - - -void -DSSIPlugin::configure(const string& key, const string& val) -{ - m_dssi_descriptor->configure(m_instances[0], key.c_str(), val.c_str()); - m_configures[key] = val; -} - - -void -DSSIPlugin::program(int bank, int program) -{ - if (m_dssi_descriptor->select_program) - m_dssi_descriptor->select_program(m_instances[0], bank, program); - - m_bank = bank; - m_program = program; -} - - -void -DSSIPlugin::run(size_t nframes) -{ - NodeBase::run(nframes); - - /*if (m_dssi_descriptor->run_synth) { - m_dssi_descriptor->run_synth(m_instances[0], nframes, - parent_patch()->dssi_events_array(), parent_patch()->dssi_events_size()); - } else if (m_dssi_descriptor->run_multiple_synths) { // I hate this stupid function - snd_seq_event_t* events[1] = { parent_patch()->dssi_events_array() }; - long unsigned events_sizes[1] = { parent_patch()->dssi_events_size() }; - m_dssi_descriptor->run_multiple_synths(1, m_instances, nframes, - events, events_sizes); - } else { - LADSPAPlugin::run(nframes); - } - */ - - if (m_dssi_descriptor->run_synth) { - m_dssi_descriptor->run_synth(m_instances[0], nframes, - (snd_seq_event_t*)m_midi_in_port->buffer(0), m_midi_in_port->get_valid_buffer_size()); - /*} else if (m_dssi_descriptor->run_multiple_synths) { // I hate this stupid function - snd_seq_event_t* events[1] = { parent_patch()->dssi_events_array() }; - long unsigned events_sizes[1] = { parent_patch()->dssi_events_size() }; - m_dssi_descriptor->run_multiple_synths(1, m_instances, nframes, - events, events_sizes);*/ - } else { - LADSPAPlugin::run(nframes); - } - - -} - - -void -DSSIPlugin::send_control(int port_num, float value) -{ - string path = m_ui_base_path + "/control"; - lo_send(m_ui_addr, path.c_str(), "if", port_num, value); -} - - -void -DSSIPlugin::send_program(int bank, int value) -{ - string path = m_ui_base_path + "/program"; - lo_send(m_ui_addr, path.c_str(), "ii", bank, value); -} - - -void -DSSIPlugin::send_configure(const string& key, const string& val) -{ - string path = m_ui_base_path + "/configure"; - lo_send(m_ui_addr, path.c_str(), "ss", key.c_str(), val.c_str()); -} - - -void -DSSIPlugin::send_show() -{ - string path = m_ui_base_path + "/show"; - lo_send(m_ui_addr, path.c_str(), NULL); -} - - -void -DSSIPlugin::send_hide() -{ - string path = m_ui_base_path + "/hide"; - lo_send(m_ui_addr, path.c_str(), NULL); -} - - -void -DSSIPlugin::send_quit() -{ - string path = m_ui_base_path + "/quit"; - lo_send(m_ui_addr, path.c_str(), NULL); -} - - -void -DSSIPlugin::send_update() -{ - // send "configure"s - for (map::iterator i = m_configures.begin(); i != m_configures.end(); ++i) - send_configure((*i).first, (*i).second); - - // send "program" - send_program(m_bank, m_program); - - // send "control"s - for (size_t i=0; i < m_ports.size(); ++i) - if (m_ports[i]->port_info()->is_control()) - send_control(m_ports[i]->num(), ((PortBase*)m_ports[i])->get_value(0, 0)); - - // send "show" FIXME: not to spec - send_show(); -} - - -} // namespace Om diff --git a/src/engine/DSSIPlugin.h b/src/engine/DSSIPlugin.h deleted file mode 100644 index d546a8fe..00000000 --- a/src/engine/DSSIPlugin.h +++ /dev/null @@ -1,109 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DSSIPLUGIN_H -#define DSSIPLUGIN_H - -#include -#include -#include -#include "LADSPAPlugin.h" - -namespace Om { - -class MidiMessage; -template class InputPort; -namespace Shared { - class ClientInterface; -} using Shared::ClientInterface; - - -/** An instance of a DSSI plugin. - */ -class DSSIPlugin : public LADSPAPlugin -{ -public: - - typedef map Bank; - - DSSIPlugin(const string& name, size_t poly, Patch* parent, DSSI_Descriptor* descriptor, samplerate srate, size_t buffer_size); - ~DSSIPlugin(); - - bool instantiate(); - - void activate(); - - void set_ui_url(const string& url); - void send_update(); - - void set_control(size_t port_num, sample val); - void configure(const string& key, const string& val); - void program(int bank, int program); - - void run(size_t nframes); - - bool update_programs(bool send_events); - void set_default_program(); - const map& get_programs() const; - - //void send_creation_messages(ClientInterface* client) const; - - const Plugin* plugin() const { return m_plugin; } - void plugin(const Plugin* const pi) { m_plugin = pi; } - -private: - // Prevent copies (undefined) - DSSIPlugin(const DSSIPlugin& copy); - DSSIPlugin& operator=(const DSSIPlugin& copy); - - bool has_midi_input() const; - - // DSSI GUI messages - void send_control(int port_num, float value); - void send_program(int bank, int value); - void send_configure(const string& key, const string& val); - void send_show(); - void send_hide(); - void send_quit(); - - // Conversion to ALSA MIDI events - void convert_events(); - - - DSSI_Descriptor* m_dssi_descriptor; - - string m_ui_url; - string m_ui_base_path; - lo_address m_ui_addr; - - // Current values - int m_bank; - int m_program; - map m_configures; - map m_banks; - - InputPort* m_midi_in_port; - snd_seq_event_t* m_alsa_events; - unsigned long m_encoded_events; - snd_midi_event_t* m_alsa_encoder; -}; - - -} // namespace Om - - -#endif // DSSIPLUGIN_H - diff --git a/src/engine/DSSIPlugin.h.orig b/src/engine/DSSIPlugin.h.orig deleted file mode 100644 index 816c65a7..00000000 --- a/src/engine/DSSIPlugin.h.orig +++ /dev/null @@ -1,84 +0,0 @@ -/* This file is part of Om. Copyright (C) 2005 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DSSIPLUGIN_H -#define DSSIPLUGIN_H - -#include -#include -#include "LADSPAPlugin.h" - -namespace Om { - -class MidiMessage; -template class InputPort; - - -/** An instance of a DSSI plugin. - */ -class DSSIPlugin : public LADSPAPlugin -{ -public: - DSSIPlugin(const string& name, uint poly, Patch* parent, DSSI_Descriptor* descriptor, samplerate srate, size_t buffer_size); - ~DSSIPlugin(); - - void activate(); - - void set_ui_url(const string& url); - void send_update(); - - void set_control(uint port_num, sample val); - void configure(const string& key, const string& val); - void program(int bank, int program); - - void run(size_t nframes); - - const Plugin* const plugin() const { return m_plugin; } - void plugin(const Plugin* const pi) { m_plugin = pi; } - -private: - // Prevent copies - DSSIPlugin(const DSSIPlugin& copy) : LADSPAPlugin(copy) { exit(EXIT_FAILURE); } - DSSIPlugin& operator=(const DSSIPlugin& copy) { exit(EXIT_FAILURE); } - - // DSSI GUI messages - void send_control(int port_num, float value); - void send_program(int bank, int value); - void send_configure(const string& key, const string& val); - void send_show(); - void send_hide(); - void send_quit(); - - string m_ui_url; - string m_ui_base_path; - lo_address m_ui_addr; - - // Current values - int m_bank; - int m_program; - map m_configures; - - DSSI_Descriptor* m_dssi_descriptor; - - InputPort* m_midi_in_port; -}; - - -} // namespace Om - - -#endif // DSSIPLUGIN_H - diff --git a/src/engine/Driver.h b/src/engine/Driver.h deleted file mode 100644 index be882d8d..00000000 --- a/src/engine/Driver.h +++ /dev/null @@ -1,112 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DRIVER_H -#define DRIVER_H - -#include -using std::string; - -namespace Om { - -template class PortBase; - - -/** Representation of a system (outside Om, ie hardware) audio port. - * - * This is the class through which the rest of the engine manages everything - * related to driver ports. Derived classes are expected to have a pointer to - * their driver (to be able to perform the operation necessary). - * - * \ingroup engine - */ -class DriverPort { -public: - virtual ~DriverPort() {} - - /** Add this port to driver at the beginning of a process cycle (realtime safe) */ - virtual void add_to_driver() = 0; - - /** Remove this port at the beginning of a process cycle (realtime safe) */ - virtual void remove_from_driver() = 0; - - /** Set the name of the system port */ - virtual void set_name(const string& name) = 0; - -protected: - DriverPort() {} -}; - - -/** Driver abstract base class. - * - * A Driver is, from the perspective of OmObjects (nodes, patches, ports) an - * interface for managing system ports. An implementation of Driver basically - * needs to manage DriverPorts, and handle writing/reading data to/from them. - * - * The template parameter T is the type of data this driver manages (ie the - * data type of the bridge ports it will handle). - * - * \ingroup engine - */ -template -class Driver -{ -public: - virtual ~Driver() {} - - virtual void activate() = 0; - virtual void deactivate() = 0; - - virtual bool is_activated() const = 0; - - /** Create a port ready to be inserted with add_input (non realtime). - * - * May return NULL if the Driver can not drive the port for some reason. - */ - virtual DriverPort* create_port(PortBase* patch_port) = 0; -}; - - -#if 0 -/** Dummy audio driver. - * - * Not abstract, all functions are dummies. One of these will be allocated and - * "used" if no working AUDIO driver is loaded. (Doing it this way as opposed to - * just making Driver have dummy functions makes sure any existing Driver - * derived class actually implements the required functions). - * - * \ingroup engine - */ -class DummyDriver : public Driver -{ -public: - ~DummyDriver() {} - - void activate() {} - void deactivate() {} - - void enable() {} - void disable() {} - - DriverPort* create_port(PortBase* patch_port) { return NULL; } -}; -#endif - - -} // namespace Om - -#endif // DRIVER_H diff --git a/src/engine/Event.cpp b/src/engine/Event.cpp deleted file mode 100644 index 7d590e76..00000000 --- a/src/engine/Event.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Event.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "AudioDriver.h" - -namespace Om { - -// It'd be nice if this was inlined.. -Event::Event(CountedPtr responder) -: m_responder(responder), - m_executed(false) -{ - m_time_stamp = om->audio_driver()->time_stamp(); -} - - -/** Construct an event with no responder. - * - * For internal events only, attempting to access the responder will - * cause a NULL pointer dereference. - */ -Event::Event() -: m_responder(NULL), - m_executed(false) -{ - m_time_stamp = om->audio_driver()->time_stamp(); -} - - -} // namespace Om - diff --git a/src/engine/Event.h b/src/engine/Event.h deleted file mode 100644 index a6d06f83..00000000 --- a/src/engine/Event.h +++ /dev/null @@ -1,71 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef EVENT_H -#define EVENT_H - -#include -#include "util/CountedPtr.h" -#include "util/types.h" -#include "MaidObject.h" -#include "Responder.h" - -namespace Om { - - - -/** Base class for all events (both realtime and QueuedEvent). - * - * This is for time-critical events like note ons. There is no non-realtime - * pre-execute method as in QueuedEvent's, any lookups etc need to be done in the - * realtime execute() method. - * - * QueuedEvent extends this class with a pre_process() method for any work that needs - * to be done before processing in the realtime audio thread. - * - * \ingroup engine - */ -class Event : public MaidObject -{ -public: - virtual ~Event() {} - - /** Execute event, MUST be realtime safe */ - virtual void execute(samplecount offset) { assert(!m_executed); m_executed = true; } - - /** Perform any actions after execution (ie send OSC response to client). - * No realtime requirement. */ - virtual void post_process() {} - - inline samplecount time_stamp() { return m_time_stamp; } - -protected: - Event(CountedPtr responder); - Event(); - - // Prevent copies - Event(const Event&); - Event& operator=(const Event&); - - CountedPtr m_responder; - samplecount m_time_stamp; - bool m_executed; -}; - - -} // namespace Om - -#endif // EVENT_H diff --git a/src/engine/EventSource.h b/src/engine/EventSource.h deleted file mode 100644 index b038f427..00000000 --- a/src/engine/EventSource.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef EVENTSOURCE_H -#define EVENTSOURCE_H - -namespace Om { - -class Event; -class QueuedEvent; - - -/** Source for events to run in the audio thread. - * - * The AudioDriver gets events from an EventSource in the process callback - * (realtime audio thread) and executes them, then they are sent to the - * PostProcessor and finalised (post-processing thread). - */ -class EventSource -{ -public: - - virtual ~EventSource() {} - - virtual Event* pop_earliest_event_before(const samplecount time) = 0; - - virtual void start() = 0; - - virtual void stop() = 0; - -protected: - EventSource() {} -}; - - -} // namespace Om - -#endif // EVENTSOURCE_H - diff --git a/src/engine/InputPort.cpp b/src/engine/InputPort.cpp deleted file mode 100644 index 3837da1b..00000000 --- a/src/engine/InputPort.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "InputPort.h" -#include -#include -#include -#include "ConnectionBase.h" -#include "OutputPort.h" -#include "PortInfo.h" -#include "Node.h" -#include "Om.h" -#include "util.h" - -using std::cerr; using std::cout; using std::endl; - - -namespace Om { - - -template -InputPort::InputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size) -: PortBase(node, name, index, poly, port_info, buffer_size) -{ - assert(port_info->is_input() && !port_info->is_output()); -} -template InputPort::InputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); -template InputPort::InputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); - - -/** Add a connection. Realtime safe. - * - * The buffer of this port will be set directly to the connection's buffer - * if there is only one connection, since no mixing needs to take place. - */ -template -void -InputPort::add_connection(ListNode*>* const c) -{ - m_connections.push_back(c); - - bool modify_buffers = !m_fixed_buffers; - if (modify_buffers && m_is_tied) - modify_buffers = !m_tied_port->fixed_buffers(); - - if (modify_buffers) { - if (m_connections.size() == 1) { - // Use buffer directly to avoid copying - for (size_t i=0; i < m_poly; ++i) { - m_buffers.at(i)->join(c->elem()->buffer(i)); - if (m_is_tied) - m_tied_port->buffer(i)->join(m_buffers.at(i)); - assert(m_buffers.at(i)->data() == c->elem()->buffer(i)->data()); - } - } else if (m_connections.size() == 2) { - // Used to directly use single connection buffer, now there's two - // so have to use local ones again and mix down - for (size_t i=0; i < m_poly; ++i) { - m_buffers.at(i)->unjoin(); - if (m_is_tied) - m_tied_port->buffer(i)->join(m_buffers.at(i)); - } - } - update_buffers(); - } - - assert( ! m_is_tied || m_tied_port != NULL); - assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); -} -template void InputPort::add_connection(ListNode*>* const c); -template void InputPort::add_connection(ListNode*>* const c); - - -/** Remove a connection. Realtime safe. - */ -template -ListNode*>* -InputPort::remove_connection(const OutputPort* const src_port) -{ - bool modify_buffers = !m_fixed_buffers; - if (modify_buffers && m_is_tied) - modify_buffers = !m_tied_port->fixed_buffers(); - - typedef typename List*>::iterator ConnectionBaseListIterator; - bool found = false; - ListNode*>* connection = NULL; - for (ConnectionBaseListIterator i = m_connections.begin(); i != m_connections.end(); ++i) { - if ((*i)->src_port()->path() == src_port->path()) { - connection = m_connections.remove(i); - found = true; - } - } - - if ( ! found) { - cerr << "WARNING: [InputPort::remove_connection] Connection not found !" << endl; - exit(EXIT_FAILURE); - } else { - if (m_connections.size() == 0) { - for (size_t i=0; i < m_poly; ++i) { - // Use a local buffer - if (modify_buffers && m_buffers.at(i)->is_joined()) - m_buffers.at(i)->unjoin(); - m_buffers.at(i)->clear(); // Write silence - if (m_is_tied) - m_tied_port->buffer(i)->join(m_buffers.at(i)); - } - } else if (modify_buffers && m_connections.size() == 1) { - // Share a buffer - for (size_t i=0; i < m_poly; ++i) { - m_buffers.at(i)->join((*m_connections.begin())->buffer(i)); - if (m_is_tied) - m_tied_port->buffer(i)->join(m_buffers.at(i)); - } - } - } - - if (modify_buffers) - update_buffers(); - - assert( ! m_is_tied || m_tied_port != NULL); - assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); - - return connection; -} -template ListNode*>* -InputPort::remove_connection(const OutputPort* const src_port); -template ListNode*>* -InputPort::remove_connection(const OutputPort* const src_port); - - -/** Update any changed buffers with the plugin this is a port on. - * - * This calls ie the LADSPA connect_port function when buffers have been changed - * due to a connection or disconnection. - */ -template -void -InputPort::update_buffers() -{ - for (size_t i=0; i < m_poly; ++i) - InputPort::parent_node()->set_port_buffer(i, m_index, m_buffers.at(i)->data()); -} -template void InputPort::update_buffers(); -template void InputPort::update_buffers(); - - -/** Returns whether this port is connected to the passed port. - */ -template -bool -InputPort::is_connected_to(const OutputPort* const port) const -{ - typedef typename List*>::const_iterator ConnectionBaseListIterator; - for (ConnectionBaseListIterator i = m_connections.begin(); i != m_connections.end(); ++i) - if ((*i)->src_port() == port) - return true; - - return false; -} -template bool InputPort::is_connected_to(const OutputPort* const port) const; -template bool InputPort::is_connected_to(const OutputPort* const port) const; - - -/** "Ties" this port to an OutputPort, so they share the same buffer. - * - * This is used by OutputNode and InputNode to provide two different ports - * (internal and external) that share a buffer. - */ -template -void -InputPort::tie(OutputPort* const port) -{ - assert((Port*)port != (Port*)this); - assert(port->poly() == this->poly()); - assert(!m_is_tied); - assert(m_tied_port == NULL); - - if (Port::parent_node() != NULL) { - assert(m_poly == port->poly()); - - for (size_t i=0; i < m_poly; ++i) - port->buffer(i)->join(m_buffers.at(i)); - } - m_is_tied = true; - m_tied_port = port; - port->set_tied_port(this); - - assert(m_buffers.at(0)->data() == port->buffer(0)->data()); - - //cerr << "*** Tied " << this->path() << " <-> " << port->path() << endl; -} -template void InputPort::tie(OutputPort* const port); -template void InputPort::tie(OutputPort* const port); - - -/** Prepare buffer for access, mixing if necessary. Realtime safe. - * FIXME: nframes parameter not used, - */ -template<> -void -InputPort::prepare_buffers(size_t nframes) -{ - assert(!m_is_tied || m_tied_port != NULL); - - typedef List*>::iterator ConnectionBaseListIterator; - bool do_mixdown = true; - - if (m_connections.size() == 0) return; - - for (ConnectionBaseListIterator c = m_connections.begin(); c != m_connections.end(); ++c) - (*c)->prepare_buffers(); - - // If only one connection, buffer is (maybe) used directly (no copying) - if (m_connections.size() == 1) { - // Buffer changed since connection - if (m_buffers.at(0)->data() != (*m_connections.begin())->buffer(0)->data()) { - if (m_fixed_buffers || (m_is_tied && m_tied_port->fixed_buffers())) { - // can't change buffer, must copy - do_mixdown = true; - } else { - // zero-copy - assert(m_buffers.at(0)->is_joined()); - m_buffers.at(0)->join((*m_connections.begin())->buffer(0)); - do_mixdown = false; - } - } else { - do_mixdown = false; - } - update_buffers(); - } - - if (!do_mixdown) { - assert(m_buffers.at(0)->data() == (*m_connections.begin())->buffer(0)->data()); - return; - } - - assert(!m_is_tied || m_tied_port != NULL); - assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); - - for (size_t voice=0; voice < m_poly; ++voice) { - m_buffers.at(voice)->copy((*m_connections.begin())->buffer(voice), 0, m_buffer_size-1); - - if (m_connections.size() > 1) { - // Copy first connection - ConnectionBaseListIterator c = m_connections.begin(); - - // Add all other connections - for (++c; c != m_connections.end(); ++c) - m_buffers.at(voice)->accumulate((*c)->buffer(voice), 0, m_buffer_size-1); - } - } -} - - -/** Prepare buffer for access, realtime safe. - * - * MIDI mixing not yet implemented. - */ -template <> -void -InputPort::prepare_buffers(size_t nframes) -{ - assert(!m_is_tied || m_tied_port != NULL); - - const size_t num_ins = m_connections.size(); - bool do_mixdown = true; - - assert(num_ins == 0 || num_ins == 1); - - typedef List*>::iterator ConnectionBaseListIterator; - assert(m_poly == 1); - - for (ConnectionBaseListIterator c = m_connections.begin(); c != m_connections.end(); ++c) - (*c)->prepare_buffers(); - - - // If only one connection, buffer is used directly (no copying) - if (num_ins == 1) { - // Buffer changed since connection - if (m_buffers.at(0) != (*m_connections.begin())->buffer(0)) { - if (m_fixed_buffers || (m_is_tied && m_tied_port->fixed_buffers())) { - // can't change buffer, must copy - do_mixdown = true; - } else { - // zero-copy - assert(m_buffers.at(0)->is_joined()); - m_buffers.at(0)->join((*m_connections.begin())->buffer(0)); - if (m_is_tied) - m_tied_port->buffer(0)->join(m_buffers.at(0)); - do_mixdown = false; - } - update_buffers(); - } else { - do_mixdown = false; - } - assert(!m_is_tied || m_tied_port != NULL); - assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); - assert(!m_is_tied || m_buffers.at(0)->filled_size() == m_tied_port->buffer(0)->filled_size()); - assert(do_mixdown || m_buffers.at(0)->filled_size() == - (*m_connections.begin())->src_port()->buffer(0)->filled_size()); - } - - // Get valid buffer size from inbound connections, unless a port on a top-level - // patch (which will be fed by the MidiDriver) - if (m_parent->parent() != NULL) { - if (num_ins == 1) { - m_buffers.at(0)->filled_size( - (*m_connections.begin())->src_port()->buffer(0)->filled_size()); - - if (m_is_tied) - m_tied_port->buffer(0)->filled_size(m_buffers.at(0)->filled_size()); - - assert(m_buffers.at(0)->filled_size() == - (*m_connections.begin())->src_port()->buffer(0)->filled_size()); - } else { - // Mixing not implemented - m_buffers.at(0)->clear(); - } - } - - assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); - - if (!do_mixdown || m_buffers.at(0)->filled_size() == 0 || num_ins == 0) - return; - - //cerr << path() << " - Copying MIDI buffer" << endl; - - // Be sure buffers are the same as tied port's, if joined - assert(!m_is_tied || m_tied_port != NULL); - assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); - - if (num_ins > 0) - for (size_t i=0; i < m_buffers.at(0)->filled_size(); ++i) - m_buffers.at(0)[i] = (*m_connections.begin())->buffer(0)[i]; -} - - -} // namespace Om - diff --git a/src/engine/InputPort.h b/src/engine/InputPort.h deleted file mode 100644 index 0e5d9d68..00000000 --- a/src/engine/InputPort.h +++ /dev/null @@ -1,88 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef INPUTPORT_H -#define INPUTPORT_H - -#include -#include -#include -#include "PortBase.h" -#include "List.h" -#include "MidiMessage.h" -using std::string; - -namespace Om { - -template class ConnectionBase; -template class OutputPort; -class Node; - - -/** An input port on a Node or Patch. - * - * All ports have a Buffer, but the actual contents (data) of that buffer may be - * set directly to the incoming connection's buffer if there's only one inbound - * connection, to eliminate the need to copy/mix. - * - * If a port has multiple connections, they will be mixed down into the local - * buffer and it will be used. - * - * \ingroup engine - */ -template -class InputPort : public PortBase -{ -public: - InputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); - virtual ~InputPort() {} - - void add_connection(ListNode*>* const c); - ListNode*>* remove_connection(const OutputPort* const src_port); - - void prepare_buffers(size_t nframes); - - void tie(OutputPort* const port); - - bool is_connected() const { return (m_connections.size() > 0); } - bool is_connected_to(const OutputPort* const port) const; - -private: - // Prevent copies (Undefined) - InputPort(const InputPort& copy); - InputPort& operator=(const InputPort&); - - void update_buffers(); - - List*> m_connections; - - // This is just stupid... - using PortBase::m_is_tied; - using PortBase::m_tied_port; - using PortBase::m_buffers; - using PortBase::m_poly; - using PortBase::m_index; - using PortBase::m_buffer_size; - using PortBase::m_fixed_buffers; -}; - - -template class InputPort; -template class InputPort; - -} // namespace Om - -#endif // INPUTPORT_H diff --git a/src/engine/InternalNode.h b/src/engine/InternalNode.h deleted file mode 100644 index fea2d3ad..00000000 --- a/src/engine/InternalNode.h +++ /dev/null @@ -1,70 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef INTERNALNODE_H -#define INTERNALNODE_H - -#include -#include "NodeBase.h" -#include "Plugin.h" - -namespace Om { - -class Patch; - - -/** Base class for Internal (builtin) nodes - * - * \ingroup engine - */ -class InternalNode : public NodeBase -{ -public: - InternalNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) - : NodeBase(path, poly, parent, srate, buffer_size), - m_is_added(false) - { - m_plugin.lib_path("/Om"); - } - - virtual ~InternalNode() {} - - virtual void deactivate() { if (m_is_added) remove_from_patch(); NodeBase::deactivate(); } - - virtual void run(size_t nframes) { NodeBase::run(nframes); } - - virtual void add_to_patch() { assert(!m_is_added); m_is_added = true; } - virtual void remove_from_patch() { assert(m_is_added); m_is_added = false; } - - //virtual void send_creation_messages(ClientInterface* client) const - //{ NodeBase::send_creation_messages(client); } - - virtual const Plugin* plugin() const { return &m_plugin; } - virtual void plugin(const Plugin* const) { exit(EXIT_FAILURE); } - -protected: - // Disallow copies (undefined) - InternalNode(const InternalNode&); - InternalNode& operator=(const InternalNode&); - - Plugin m_plugin; - bool m_is_added; -}; - - -} // namespace Om - -#endif // INTERNALNODE_H diff --git a/src/engine/JackAudioDriver.cpp b/src/engine/JackAudioDriver.cpp deleted file mode 100644 index 0f5e3b1a..00000000 --- a/src/engine/JackAudioDriver.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "JackAudioDriver.h" -#include "config.h" -#include "tuning.h" -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "util.h" -#include "Event.h" -#include "QueuedEvent.h" -#include "EventSource.h" -#include "PostProcessor.h" -#include "util/Queue.h" -#include "Node.h" -#include "Patch.h" -#include "Port.h" -#include "PortInfo.h" -#include "MidiDriver.h" -#include "List.h" -#include "PortBase.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif - -using std::cout; using std::cerr; using std::endl; - - -namespace Om { - - -//// JackAudioPort //// - -JackAudioPort::JackAudioPort(JackAudioDriver* driver, PortBase* patch_port) -: DriverPort(), - ListNode(this), - m_driver(driver), - m_jack_port(NULL), - m_jack_buffer(NULL), - m_patch_port(patch_port) -{ - assert(patch_port->tied_port() != NULL); - assert(patch_port->poly() == 1); - - m_jack_port = jack_port_register(m_driver->jack_client(), - patch_port->path().c_str(), JACK_DEFAULT_AUDIO_TYPE, - (patch_port->port_info()->is_input()) ? JackPortIsInput : JackPortIsOutput, - 0); - - m_jack_buffer = new DriverBuffer(driver->buffer_size()); - - patch_port->fixed_buffers(true); -} - - -JackAudioPort::~JackAudioPort() -{ - jack_port_unregister(m_driver->jack_client(), m_jack_port); -} - - -void -JackAudioPort::add_to_driver() -{ - m_driver->add_port(this); -} - - -void -JackAudioPort::remove_from_driver() -{ - m_driver->remove_port(this); -} - -void -JackAudioPort::prepare_buffer(jack_nframes_t nframes) -{ - // Technically this doesn't need to be done every time for output ports - m_jack_buffer->set_data((jack_default_audio_sample_t*) - jack_port_get_buffer(m_jack_port, nframes)); - - assert(m_patch_port->tied_port() != NULL); - - // FIXME: fixed_buffers switch on/off thing can be removed once this shit - // gets figured out and assertions can go away - m_patch_port->fixed_buffers(false); - m_patch_port->buffer(0)->join(m_jack_buffer); - m_patch_port->tied_port()->buffer(0)->join(m_jack_buffer); - - m_patch_port->fixed_buffers(true); - - assert(m_patch_port->buffer(0)->data() == m_patch_port->tied_port()->buffer(0)->data()); - assert(m_patch_port->buffer(0)->data() == m_jack_buffer->data()); -} - - -//// JackAudioDriver //// - -JackAudioDriver::JackAudioDriver() -: m_client(NULL), - m_buffer_size(0), - m_sample_rate(0), - m_is_activated(false), - m_local_client(true), - m_root_patch(NULL), - m_start_of_current_cycle(0), - m_start_of_last_cycle(0) -{ - m_client = jack_client_new("Om"); - if (m_client == NULL) { - cerr << "[JackAudioDriver] Unable to connect to Jack. Exiting." << endl; - exit(EXIT_FAILURE); - } - - jack_on_shutdown(m_client, shutdown_cb, this); - - m_buffer_size = jack_get_buffer_size(m_client); - m_sample_rate = jack_get_sample_rate(m_client); - - jack_set_sample_rate_callback(m_client, sample_rate_cb, this); - jack_set_buffer_size_callback(m_client, buffer_size_cb, this); -} - -JackAudioDriver::JackAudioDriver(jack_client_t* jack_client) -: m_client(jack_client), - m_buffer_size(jack_get_buffer_size(jack_client)), - m_sample_rate(jack_get_sample_rate(jack_client)), - m_is_activated(false), - m_local_client(false), - m_start_of_current_cycle(0), - m_start_of_last_cycle(0) -{ - jack_on_shutdown(m_client, shutdown_cb, this); - - jack_set_sample_rate_callback(m_client, sample_rate_cb, this); - jack_set_buffer_size_callback(m_client, buffer_size_cb, this); -} - - -JackAudioDriver::~JackAudioDriver() -{ - deactivate(); - - if (m_local_client) - jack_client_close(m_client); -} - - -void -JackAudioDriver::activate() -{ - if (m_is_activated) { - cerr << "[JackAudioDriver] Jack driver already activated." << endl; - return; - } - - jack_set_process_callback(m_client, process_cb, this); - - m_is_activated = true; - - if (jack_activate(m_client)) { - cerr << "[JackAudioDriver] Could not activate Jack client, aborting." << endl; - exit(EXIT_FAILURE); - } else { - cout << "[JackAudioDriver] Activated Jack client." << endl; -#ifdef HAVE_LASH - lash_driver->set_jack_client_name("Om"); // FIXME: unique name -#endif - } -} - - -void -JackAudioDriver::deactivate() -{ - if (m_is_activated) { - // FIXME - reinterpret_cast(om->osc_receiver())->stop(); - - jack_deactivate(m_client); - m_is_activated = false; - - for (List::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - jack_port_unregister(m_client, (*i)->jack_port()); - - m_ports.clear(); - - cout << "[JackAudioDriver] Deactivated Jack client." << endl; - - om->post_processor()->stop(); - } -} - - -/** Add a Jack port. - * - * Realtime safe, this is to be called at the beginning of a process cycle to - * insert (and actually begin using) a new port. - * - * See create_port() and remove_port(). - */ -void -JackAudioDriver::add_port(JackAudioPort* port) -{ - m_ports.push_back(port); -} - - -/** Remove a Jack port. - * - * Realtime safe. This is to be called at the beginning of a process cycle to - * remove the port from the lists read by the audio thread, so the port - * will no longer be used and can be removed afterwards. - * - * It is the callers responsibility to delete the returned port. - */ -JackAudioPort* -JackAudioDriver::remove_port(JackAudioPort* port) -{ - for (List::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - if ((*i) == port) - return m_ports.remove(i)->elem(); - - cerr << "[JackAudioDriver::remove_port] WARNING: Failed to find Jack port to remove!" << endl; - return NULL; -} - - -DriverPort* -JackAudioDriver::create_port(PortBase* patch_port) -{ - if (patch_port->buffer_size() == m_buffer_size) - return new JackAudioPort(this, patch_port); - else - return NULL; -} - - -/** Process all the pending events for this cycle. - * - * Called from the realtime thread once every process cycle. - */ -void -JackAudioDriver::process_events(jack_nframes_t block_start, jack_nframes_t block_end) -{ - Event* ev = NULL; - - /* Limit the maximum number of queued events to process per cycle. This - * makes the process callback truly realtime-safe by preventing being - * choked by events coming in faster than they can be processed. - * FIXME: run the math on this and figure out a good value */ - const int MAX_SLOW_EVENTS = m_buffer_size / 100; - - int num_events_processed = 0; - int offset = 0; - - // Process the "slow" events first, because it's possible some of the - // RT events depend on them - - // FIXME - while ((ev = reinterpret_cast(om->osc_receiver()) - ->pop_earliest_event_before(block_end)) != NULL) { - ev->execute(0); // QueuedEvents are not sample accurate - om->post_processor()->push(ev); - if (++num_events_processed > MAX_SLOW_EVENTS) - break; - } - - while (!om->event_queue()->is_empty() - && om->event_queue()->front()->time_stamp() < block_end) { - ev = om->event_queue()->pop(); - offset = ev->time_stamp() - block_start; - if (offset < 0) offset = 0; // this can happen if we miss a cycle - ev->execute(offset); - om->post_processor()->push(ev); - ++num_events_processed; - } - - if (num_events_processed > 0) - om->post_processor()->signal(); -} - - - -/**** Jack Callbacks ****/ - - - -/** Jack process callback, drives entire audio thread. - * - * \callgraph - */ -int -JackAudioDriver::m_process_cb(jack_nframes_t nframes) -{ - // FIXME: support nframes != buffer_size, even though that never damn well happens - assert(nframes == m_buffer_size); - - // Note that jack can elect to not call this function for a cycle, if things aren't - // keeping up - m_start_of_current_cycle = jack_last_frame_time(m_client); - m_start_of_last_cycle = m_start_of_current_cycle - nframes; - - assert(m_start_of_current_cycle - m_start_of_last_cycle == nframes); - - m_transport_state = jack_transport_query(m_client, &m_position); - - process_events(m_start_of_last_cycle, m_start_of_current_cycle); - om->midi_driver()->prepare_block(m_start_of_last_cycle, m_start_of_current_cycle); - - // Set buffers of patch ports to Jack port buffers (zero-copy processing) - for (List::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - (*i)->prepare_buffer(nframes); - - // Run root patch - assert(m_root_patch != NULL); - m_root_patch->run(nframes); - - return 0; -} - - -void -JackAudioDriver::m_shutdown_cb() -{ - cout << "[JackAudioDriver] Jack shutdown. Exiting." << endl; - om->quit(); -} - - -int -JackAudioDriver::m_sample_rate_cb(jack_nframes_t nframes) -{ - if (m_is_activated) { - cerr << "[JackAudioDriver] Om does not support changing sample rate on the fly (yet). Aborting." << endl; - exit(EXIT_FAILURE); - } else { - m_sample_rate = nframes; - } - return 0; -} - - -int -JackAudioDriver::m_buffer_size_cb(jack_nframes_t nframes) -{ - if (m_is_activated) { - cerr << "[JackAudioDriver] Om does not support chanding buffer size on the fly (yet). Aborting." << endl; - exit(EXIT_FAILURE); - } else { - m_buffer_size = nframes; - } - return 0; -} - - -} // namespace Om - diff --git a/src/engine/JackAudioDriver.h b/src/engine/JackAudioDriver.h deleted file mode 100644 index c55d392f..00000000 --- a/src/engine/JackAudioDriver.h +++ /dev/null @@ -1,176 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef JACKAUDIODRIVER_H -#define JACKAUDIODRIVER_H - -#include -#include -#include "List.h" -#include "AudioDriver.h" -#include "Buffer.h" - -namespace Om { - -class Patch; -class Port; -template class PortBase; -class JackAudioDriver; -typedef jack_default_audio_sample_t jack_sample_t; - - -/** Used internally by JackAudioDriver to represent a Jack port. - * - * A Jack port always has a one-to-one association with a Patch port. - */ -class JackAudioPort : public DriverPort, public ListNode -{ -public: - JackAudioPort(JackAudioDriver* driver, PortBase* patch_port); - ~JackAudioPort(); - - void add_to_driver(); - void remove_from_driver(); - void set_name(const string& name) { jack_port_set_name(m_jack_port, name.c_str()); }; - - void prepare_buffer(jack_nframes_t nframes); - - jack_port_t* jack_port() const { return m_jack_port; } - DriverBuffer* buffer() const { return m_jack_buffer; } - void jack_buffer(jack_sample_t* s) { m_jack_buffer->set_data(s); } - PortBase* patch_port() const { return m_patch_port; } - -private: - // Prevent copies (undefined) - JackAudioPort(const JackAudioPort&); - JackAudioPort& operator=(const JackAudioPort&); - - JackAudioDriver* m_driver; - jack_port_t* m_jack_port; - DriverBuffer* m_jack_buffer; - PortBase* m_patch_port; -}; - - - -/** The Jack AudioDriver. - * - * The process callback here drives the entire audio thread by "pulling" - * events from queues, processing them, running the patches, and passing - * events along to the PostProcessor. - * - * \ingroup engine - */ -class JackAudioDriver : public AudioDriver -{ -public: - JackAudioDriver(); - JackAudioDriver(jack_client_t *jack_client); - ~JackAudioDriver(); - - void activate(); - void deactivate(); - void enable(); - void disable(); - - void process_events(jack_nframes_t block_start, jack_nframes_t block_end); - - DriverPort* create_port(PortBase* patch_port); - - Patch* root_patch() { return m_root_patch; } - void set_root_patch(Patch* patch) { m_root_patch = patch; } - - /** Transport state for this frame. - * Intended to only be called from the audio thread. */ - inline const jack_position_t* position() { return &m_position; } - inline const jack_transport_state_t transport_state() { return m_transport_state; } - - bool is_realtime() { return jack_is_realtime(m_client); } - - jack_client_t* jack_client() const { return m_client; } - samplecount buffer_size() const { return m_buffer_size; } - samplecount sample_rate() const { return m_sample_rate; } - bool is_activated() const { return m_is_activated; } - - samplecount time_stamp() const { return jack_frame_time(m_client); } - -private: - // Prevent copies (undefined) - JackAudioDriver(const JackAudioDriver&); - JackAudioDriver& operator=(const JackAudioDriver&); - - friend class JackAudioPort; - - // Functions for JackAudioPort - void add_port(JackAudioPort* port); - JackAudioPort* remove_port(JackAudioPort* port); - - // These are the static versions of the callbacks, they call - // the non-static ones below - inline static int process_cb(jack_nframes_t nframes, void* const jack_driver); - inline static void shutdown_cb(void* const jack_driver); - inline static int buffer_size_cb(jack_nframes_t nframes, void* const jack_driver); - inline static int sample_rate_cb(jack_nframes_t nframes, void* const jack_driver); - - // Non static callbacks - int m_process_cb(jack_nframes_t nframes); - void m_shutdown_cb(); - int m_buffer_size_cb(jack_nframes_t nframes); - int m_sample_rate_cb(jack_nframes_t nframes); - - jack_client_t* m_client; - jack_nframes_t m_buffer_size; - jack_nframes_t m_sample_rate; - bool m_is_activated; - bool m_local_client; ///< Whether m_client should be closed on destruction - jack_position_t m_position; - jack_transport_state_t m_transport_state; - - List m_ports; - - Patch* m_root_patch; - - jack_nframes_t m_start_of_current_cycle; - jack_nframes_t m_start_of_last_cycle; -}; - - -inline int JackAudioDriver::process_cb(jack_nframes_t nframes, void* jack_driver) -{ - return ((JackAudioDriver*)jack_driver)->m_process_cb(nframes); -} - -inline void JackAudioDriver::shutdown_cb(void* jack_driver) -{ - return ((JackAudioDriver*)jack_driver)->m_shutdown_cb(); -} - - -inline int JackAudioDriver::buffer_size_cb(jack_nframes_t nframes, void* jack_driver) -{ - return ((JackAudioDriver*)jack_driver)->m_buffer_size_cb(nframes); -} - - -inline int JackAudioDriver::sample_rate_cb(jack_nframes_t nframes, void* jack_driver) -{ - return ((JackAudioDriver*)jack_driver)->m_sample_rate_cb(nframes); -} - - -} // namespace Om - -#endif // JACKAUDIODRIVER_H diff --git a/src/engine/JackMidiDriver.cpp b/src/engine/JackMidiDriver.cpp deleted file mode 100644 index 40054b8a..00000000 --- a/src/engine/JackMidiDriver.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "JackMidiDriver.h" -#include -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "util/types.h" -#include "midi.h" -#include "OmApp.h" -#include "Maid.h" -#include "AudioDriver.h" -#include "MidiInputNode.h" -#include "PortInfo.h" -#include "MidiMessage.h" -#include "PortBase.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif -using std::cout; using std::cerr; using std::endl; - -namespace Om { - - -//// JackMidiPort //// - -JackMidiPort::JackMidiPort(JackMidiDriver* driver, PortBase* patch_port) -: DriverPort(), - ListNode(this), - m_driver(driver), - m_jack_port(NULL), - m_patch_port(patch_port) -{ - assert(patch_port->poly() == 1); - - m_jack_port = jack_port_register(m_driver->jack_client(), - patch_port->path().c_str(), JACK_DEFAULT_MIDI_TYPE, - (patch_port->port_info()->is_input()) ? JackPortIsInput : JackPortIsOutput, - 0); - - patch_port->buffer(0)->clear(); - patch_port->fixed_buffers(true); -} - - -JackMidiPort::~JackMidiPort() -{ - jack_port_unregister(m_driver->jack_client(), m_jack_port); -} - - -void -JackMidiPort::add_to_driver() -{ - m_driver->add_port(this); -} - - -void -JackMidiPort::remove_from_driver() -{ - m_driver->remove_port(this); -} - - -/** Prepare events for a block. - * - * This is basically trivial (as opposed to AlsaMidiPort) since Jack MIDI - * data is in-band with the audio thread. - * - * Prepares all events that occurred during the time interval passed - * (which ideally are the events from the previous cycle with an exact - * 1 cycle delay). - */ -void -JackMidiPort::prepare_block(const samplecount block_start, const samplecount block_end) -{ - assert(block_end >= block_start); - - const samplecount nframes = block_end - block_start; - void* jack_buffer = jack_port_get_buffer(m_jack_port, nframes); - const jack_nframes_t event_count = jack_midi_port_get_info(jack_buffer, nframes)->event_count; - - assert(event_count < m_patch_port->buffer_size()); - - // Copy events from Jack port buffer into patch port buffer - for (jack_nframes_t i=0; i < event_count; ++i) { - jack_midi_event_t* ev = (jack_midi_event_t*)&m_patch_port->buffer(0)->value_at(i); - jack_midi_event_get(ev, jack_buffer, i, nframes); - - // Convert note ons with velocity 0 to proper note offs - if (ev->buffer[0] == MIDI_CMD_NOTE_ON && ev->buffer[2] == 0) - ev->buffer[0] = MIDI_CMD_NOTE_OFF; - - // MidiMessage and jack_midi_event_t* are the same thing :/ - MidiMessage* const message = &m_patch_port->buffer(0)->data()[i]; - message->time = ev->time; - message->size = ev->size; - message->buffer = ev->buffer; - } - - //cerr << "Jack MIDI got " << event_count << " events." << endl; - - m_patch_port->buffer(0)->filled_size(event_count); - m_patch_port->tied_port()->buffer(0)->filled_size(event_count); -} - - - -//// JackMidiDriver //// - - -bool JackMidiDriver::m_midi_thread_exit_flag = true; - - -JackMidiDriver::JackMidiDriver(jack_client_t* client) -: m_client(client), - m_is_activated(false), - m_is_enabled(false) -{ -} - - -JackMidiDriver::~JackMidiDriver() -{ - deactivate(); -} - - -/** Launch and start the MIDI thread. - */ -void -JackMidiDriver::activate() -{ - m_is_activated = true; -} - - -/** Terminate the MIDI thread. - */ -void -JackMidiDriver::deactivate() -{ - m_is_activated = false; -} - - -/** Build flat arrays of events for DSSI plugins for each Port. - */ -void -JackMidiDriver::prepare_block(const samplecount block_start, const samplecount block_end) -{ - for (List::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i) - (*i)->prepare_block(block_start, block_end); -} - - -/** Add an Jack MIDI port. - * - * Realtime safe, this is to be called at the beginning of a process cycle to - * insert (and actually begin using) a new port. - * - * See create_port() and remove_port(). - */ -void -JackMidiDriver::add_port(JackMidiPort* port) -{ - if (port->patch_port()->port_info()->is_input()) - m_in_ports.push_back(port); - else - m_out_ports.push_back(port); -} - - -/** Remove an Jack MIDI port. - * - * Realtime safe. This is to be called at the beginning of a process cycle to - * remove the port from the lists read by the audio thread, so the port - * will no longer be used and can be removed afterwards. - * - * It is the callers responsibility to delete the returned port. - */ -JackMidiPort* -JackMidiDriver::remove_port(JackMidiPort* port) -{ - if (port->patch_port()->port_info()->is_input()) { - for (List::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i) - if ((*i) == (JackMidiPort*)port) - return m_in_ports.remove(i)->elem(); - } else { - for (List::iterator i = m_out_ports.begin(); i != m_out_ports.end(); ++i) - if ((*i) == port) - return m_out_ports.remove(i)->elem(); - } - - cerr << "[JackMidiDriver::remove_input] WARNING: Failed to find Jack port to remove!" << endl; - return NULL; -} - - -} // namespace Om - diff --git a/src/engine/JackMidiDriver.h b/src/engine/JackMidiDriver.h deleted file mode 100644 index 950d382f..00000000 --- a/src/engine/JackMidiDriver.h +++ /dev/null @@ -1,123 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef JACKMIDIDRIVER_H -#define JACKMIDIDRIVER_H - -#include -#include -#include "config.h" -#include "List.h" -#include "util/Queue.h" -#include "MidiDriver.h" - -namespace Om { - -class Node; -class SetPortValueEvent; -class JackMidiDriver; -template class PortBase; - - -/** Representation of an JACK MIDI port. - * - * \ingroup engine - */ -class JackMidiPort : public DriverPort, public ListNode -{ -public: - JackMidiPort(JackMidiDriver* driver, PortBase* port); - virtual ~JackMidiPort(); - - void prepare_block(const samplecount block_start, const samplecount block_end); - - void add_to_driver(); - void remove_from_driver(); - void set_name(const string& name) { jack_port_set_name(m_jack_port, name.c_str()); }; - - PortBase* patch_port() const { return m_patch_port; } - -private: - // Prevent copies (undefined) - JackMidiPort(const JackMidiPort&); - JackMidiPort& operator=(const JackMidiPort&); - - JackMidiDriver* m_driver; - jack_port_t* m_jack_port; - PortBase* m_patch_port; -}; - - -/** Jack MIDI driver. - * - * This driver reads Jack MIDI events and dispatches them to the appropriate - * JackMidiPort for processing. - * - * \ingroup engine - */ -class JackMidiDriver : public MidiDriver -{ -public: - JackMidiDriver(jack_client_t* client); - ~JackMidiDriver(); - - void activate(); - void deactivate(); - void enable() { m_is_enabled = true; } - void disable() { m_is_enabled = false; } - - bool is_activated() const { return m_is_activated; } - bool is_enabled() const { return m_is_enabled; } - - void prepare_block(const samplecount block_start, const samplecount block_end); - - JackMidiPort* create_port(PortBase* patch_port) - { return new JackMidiPort(this, patch_port); } - - jack_client_t* jack_client() { return m_client; } - -private: - // Prevent copies (undefined) - JackMidiDriver(const JackMidiDriver&); - JackMidiDriver& operator=(const JackMidiDriver&); - - List m_in_ports; - List m_out_ports; - - friend class JackMidiPort; - - // Functions for JackMidiPort - void add_port(JackMidiPort* port); - JackMidiPort* remove_port(JackMidiPort* port); - - void add_output(ListNode* port); - ListNode* remove_output(JackMidiPort* port); - - // MIDI thread - static void* process_midi_in(void* me); - - jack_client_t* m_client; - pthread_t m_process_thread; - bool m_is_activated; - bool m_is_enabled; - static bool m_midi_thread_exit_flag; -}; - - -} // namespace Om - - -#endif // JACKMIDIDRIVER_H diff --git a/src/engine/LADSPAPlugin.cpp b/src/engine/LADSPAPlugin.cpp deleted file mode 100644 index ddeb0be4..00000000 --- a/src/engine/LADSPAPlugin.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "LADSPAPlugin.h" -#include -#include -#include "float.h" -#include -#include -#include "InputPort.h" -#include "OutputPort.h" -#include "PortInfo.h" -#include "Plugin.h" - -namespace Om { - - -/** Partially construct a LADSPAPlugin. - * - * Object is not usable until instantiate() is called with success. - * (It _will_ crash!) - */ -LADSPAPlugin::LADSPAPlugin(const string& path, size_t poly, Patch* parent, const LADSPA_Descriptor* descriptor, samplerate srate, size_t buffer_size) -: NodeBase(path, poly, parent, srate, buffer_size), - m_descriptor(descriptor), - m_instances(NULL) -{ - assert(m_descriptor != NULL); - - // Note that this may be changed by an overriding DSSIPlugin - // ie do not assume m_ports is all LADSPA plugin ports - m_num_ports = m_descriptor->PortCount; -} - - -/** Instantiate self from LADSPA plugin descriptor. - * - * Implemented as a seperate function (rather than in the constructor) to - * allow graceful error-catching of broken plugins. - * - * Returns whether or not plugin was successfully instantiated. If return - * value is false, this object may not be used. - */ -bool -LADSPAPlugin::instantiate() -{ - m_ports.alloc(m_num_ports); - - m_instances = new LADSPA_Handle[m_poly]; - - size_t port_buffer_size = 0; - - for (size_t i=0; i < m_poly; ++i) { - m_instances[i] = m_descriptor->instantiate(m_descriptor, m_srate); - if (m_instances[i] == NULL) { - cerr << "Failed to instantiate plugin!" << endl; - return false; - } - } - - string port_name; - string port_path; - - Port* port = NULL; - - for (size_t j=0; j < m_descriptor->PortCount; ++j) { - port_name = m_descriptor->PortNames[j]; - string::size_type slash_index; - - // Name mangling, to guarantee port names are unique - for (size_t k=0; k < m_descriptor->PortCount; ++k) { - assert(m_descriptor->PortNames[k] != NULL); - if (k != j && port_name == m_descriptor->PortNames[k]) { // clash - if (LADSPA_IS_PORT_CONTROL(m_descriptor->PortDescriptors[j])) - port_name += " (CR)"; - else - port_name += " (AR)"; - } - // Replace all slashes with "-" (so they don't screw up paths) - while ((slash_index = port_name.find("/")) != string::npos) - port_name[slash_index] = '-'; - } - - port_path = path() + "/" + port_name; - - if (LADSPA_IS_PORT_CONTROL(m_descriptor->PortDescriptors[j])) - port_buffer_size = 1; - else if (LADSPA_IS_PORT_AUDIO(m_descriptor->PortDescriptors[j])) - port_buffer_size = m_buffer_size; - - assert (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[j]) - || LADSPA_IS_PORT_OUTPUT(m_descriptor->PortDescriptors[j])); - - if (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[j])) { - port = new InputPort(this, port_name, j, m_poly, - new PortInfo(port_path, m_descriptor->PortDescriptors[j], - m_descriptor->PortRangeHints[j].HintDescriptor), port_buffer_size); - m_ports.at(j) = port; - } else if (LADSPA_IS_PORT_OUTPUT(m_descriptor->PortDescriptors[j])) { - port = new OutputPort(this, port_name, j, m_poly, - new PortInfo(port_path, m_descriptor->PortDescriptors[j], - m_descriptor->PortRangeHints[j].HintDescriptor), port_buffer_size); - m_ports.at(j) = port; - } - - assert(m_ports.at(j) != NULL); - - PortInfo* pi = port->port_info(); - get_port_vals(j, pi); - - // Set default control val - if (pi->is_control()) - ((PortBase*)port)->set_value(pi->default_val(), 0); - else - ((PortBase*)port)->set_value(0.0f, 0); - } - - return true; -} - - -LADSPAPlugin::~LADSPAPlugin() -{ - for (size_t i=0; i < m_poly; ++i) - m_descriptor->cleanup(m_instances[i]); - - delete[] m_instances; -} - - -void -LADSPAPlugin::activate() -{ - NodeBase::activate(); - - PortBase* port = NULL; - - for (size_t i=0; i < m_poly; ++i) { - for (unsigned long j=0; j < m_descriptor->PortCount; ++j) { - port = static_cast*>(m_ports.at(j)); - set_port_buffer(i, j, ((PortBase*)m_ports.at(j))->buffer(i)->data()); - if (port->port_info()->is_control()) - port->set_value(port->port_info()->default_val(), 0); - else if (port->port_info()->is_audio()) - port->set_value(0.0f, 0); - } - if (m_descriptor->activate != NULL) - m_descriptor->activate(m_instances[i]); - } -} - - -void -LADSPAPlugin::deactivate() -{ - NodeBase::deactivate(); - - for (size_t i=0; i < m_poly; ++i) - if (m_descriptor->deactivate != NULL) - m_descriptor->deactivate(m_instances[i]); -} - - -void -LADSPAPlugin::run(size_t nframes) -{ - NodeBase::run(nframes); // mixes down input ports - for (size_t i=0; i < m_poly; ++i) - m_descriptor->run(m_instances[i], nframes); -} - - -void -LADSPAPlugin::set_port_buffer(size_t voice, size_t port_num, void* buf) -{ - assert(voice < m_poly); - - // Could be a MIDI port after this - if (port_num < m_descriptor->PortCount) { - m_descriptor->connect_port(m_instances[voice], port_num, (sample*)buf); - } -} - - -// Based on code stolen from jack-rack -void -LADSPAPlugin::get_port_vals(ulong port_index, PortInfo* info) -{ - LADSPA_Data upper = 0.0f; - LADSPA_Data lower = 0.0f; - LADSPA_Data normal = 0.0f; - LADSPA_PortRangeHintDescriptor hint_descriptor = m_descriptor->PortRangeHints[port_index].HintDescriptor; - - /* set upper and lower, possibly adjusted to the sample rate */ - if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) { - upper = m_descriptor->PortRangeHints[port_index].UpperBound * m_srate; - lower = m_descriptor->PortRangeHints[port_index].LowerBound * m_srate; - } else { - upper = m_descriptor->PortRangeHints[port_index].UpperBound; - lower = m_descriptor->PortRangeHints[port_index].LowerBound; - } - - if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { - /* FLT_EPSILON is defined as the different between 1.0 and the minimum - * float greater than 1.0. So, if lower is < FLT_EPSILON, it will be 1.0 - * and the logarithmic control will have a base of 1 and thus not change - */ - if (lower < FLT_EPSILON) lower = FLT_EPSILON; - } - - - if (LADSPA_IS_HINT_HAS_DEFAULT(hint_descriptor)) { - - if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint_descriptor)) { - normal = lower; - } else if (LADSPA_IS_HINT_DEFAULT_LOW(hint_descriptor)) { - if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { - normal = exp(log(lower) * 0.75 + log(upper) * 0.25); - } else { - normal = lower * 0.75 + upper * 0.25; - } - } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint_descriptor)) { - if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { - normal = exp(log(lower) * 0.5 + log(upper) * 0.5); - } else { - normal = lower * 0.5 + upper * 0.5; - } - } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint_descriptor)) { - if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { - normal = exp(log(lower) * 0.25 + log(upper) * 0.75); - } else { - normal = lower * 0.25 + upper * 0.75; - } - } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint_descriptor)) { - normal = upper; - } else if (LADSPA_IS_HINT_DEFAULT_0(hint_descriptor)) { - normal = 0.0; - } else if (LADSPA_IS_HINT_DEFAULT_1(hint_descriptor)) { - normal = 1.0; - } else if (LADSPA_IS_HINT_DEFAULT_100(hint_descriptor)) { - normal = 100.0; - } else if (LADSPA_IS_HINT_DEFAULT_440(hint_descriptor)) { - normal = 440.0; - } - } else { // No default hint - if (LADSPA_IS_HINT_BOUNDED_BELOW(hint_descriptor)) { - normal = lower; - } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) { - normal = upper; - } - } - - info->min_val(lower); - info->default_val(normal); - info->max_val(upper); -} - - -} // namespace Om - diff --git a/src/engine/LADSPAPlugin.h b/src/engine/LADSPAPlugin.h deleted file mode 100644 index dc1ba5e1..00000000 --- a/src/engine/LADSPAPlugin.h +++ /dev/null @@ -1,69 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef LADSPAPLUGIN_H -#define LADSPAPLUGIN_H - -#include -#include -#include "util/types.h" -#include "NodeBase.h" -#include "Plugin.h" - -namespace Om { - -class PortInfo; - - -/** An instance of a LADSPA plugin. - * - * \ingroup engine - */ -class LADSPAPlugin : public NodeBase -{ -public: - LADSPAPlugin(const string& name, size_t poly, Patch* parent, const LADSPA_Descriptor* descriptor, samplerate srate, size_t buffer_size); - virtual ~LADSPAPlugin(); - - virtual bool instantiate(); - - void activate(); - void deactivate(); - - void run(size_t nframes); - - void set_port_buffer(size_t voice, size_t port_num, void* buf); - - const Plugin* plugin() const { return m_plugin; } - void plugin(const Plugin* const pi) { m_plugin = pi; } - -protected: - // Prevent copies (undefined) - LADSPAPlugin(const LADSPAPlugin& copy); - LADSPAPlugin& operator=(const LADSPAPlugin&); - - void get_port_vals(ulong port_index, PortInfo* info); - - const LADSPA_Descriptor* m_descriptor; - LADSPA_Handle* m_instances; - - const Plugin* m_plugin; -}; - - -} // namespace Om - -#endif // LADSPAPLUGIN_H diff --git a/src/engine/LV2Plugin.cpp b/src/engine/LV2Plugin.cpp deleted file mode 100644 index 1c74bca9..00000000 --- a/src/engine/LV2Plugin.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "LV2Plugin.h" -#include -#include -#include "float.h" -#include -#include -#include "InputPort.h" -#include "OutputPort.h" -#include "PortInfo.h" -#include "Plugin.h" - -namespace Om { - - -/** Partially construct a LV2Plugin. - * - * Object is not usable until instantiate() is called with success. - * (It _will_ crash!) - */ -LV2Plugin::LV2Plugin(const string& name, - size_t poly, - Patch* parent, - const SLV2Plugin* plugin, - samplerate srate, - size_t buffer_size) -: NodeBase(name, poly, parent, srate, buffer_size), - m_lv2_plugin(plugin), - m_instances(NULL) -{ - assert(m_lv2_plugin); - - // Note that this may be changed by an overriding DSSIPlugin - // ie do not assume m_ports is all LV2 plugin ports - m_num_ports = slv2_plugin_get_num_ports(m_lv2_plugin); -} - - -/** Instantiate self from LV2 plugin descriptor. - * - * Implemented as a seperate function (rather than in the constructor) to - * allow graceful error-catching of broken plugins. - * - * Returns whether or not plugin was successfully instantiated. If return - * value is false, this object may not be used. - */ -bool -LV2Plugin::instantiate() -{ - m_ports.alloc(m_num_ports); - - m_instances = new SLV2Instance*[m_poly]; - - size_t port_buffer_size = 0; - - for (size_t i=0; i < m_poly; ++i) { - m_instances[i] = slv2_plugin_instantiate(m_lv2_plugin, m_srate, NULL); - if (m_instances[i] == NULL) { - cerr << "Failed to instantiate plugin!" << endl; - return false; - } - } - - string port_name; - string port_path; - - Port* port = NULL; - - for (size_t j=0; j < m_num_ports; ++j) { - // LV2 shortnames are guaranteed to be unique - port_name = (char*)slv2_port_get_symbol(m_lv2_plugin, j); - - string::size_type slash_index; - - // Replace all slashes with "-" (so they don't screw up paths) - while ((slash_index = port_name.find("/")) != string::npos) - port_name[slash_index] = '-'; - - port_path = path() + "/" + port_name; - - // Assumes there is only the 4 classes - - SLV2PortClass port_class = slv2_port_get_class(m_lv2_plugin, j); - const bool is_control = (port_class == SLV2_CONTROL_RATE_INPUT - || port_class == SLV2_CONTROL_RATE_OUTPUT); - const bool is_input = (port_class == SLV2_CONTROL_RATE_INPUT - || port_class == SLV2_AUDIO_RATE_INPUT); - - if (is_control) - port_buffer_size = 1; - else - port_buffer_size = m_buffer_size; - - PortType type = is_control ? CONTROL : AUDIO; - PortDirection direction = is_input ? INPUT : OUTPUT; - - if (is_input) { - port = new InputPort(this, port_name, j, m_poly, - new PortInfo(port_path, type, direction), port_buffer_size); - m_ports.at(j) = port; - } else /* output */ { - port = new OutputPort(this, port_name, j, m_poly, - new PortInfo(port_path, type, direction), port_buffer_size); - m_ports.at(j) = port; - } - - assert(m_ports.at(j) != NULL); - - PortInfo* pi = port->port_info(); - get_port_vals(j, pi); - - // Set default control val - if (pi->is_control()) - ((PortBase*)port)->set_value(pi->default_val(), 0); - else - ((PortBase*)port)->set_value(0.0f, 0); - } - return true; -} - - -LV2Plugin::~LV2Plugin() -{ - for (size_t i=0; i < m_poly; ++i) - slv2_instance_free(m_instances[i]); - - delete[] m_instances; -} - - -void -LV2Plugin::activate() -{ - NodeBase::activate(); - - PortBase* port = NULL; - - for (size_t i=0; i < m_poly; ++i) { - for (unsigned long j=0; j < m_num_ports; ++j) { - port = static_cast*>(m_ports.at(j)); - set_port_buffer(i, j, ((PortBase*)m_ports.at(j))->buffer(i)->data()); - if (port->port_info()->is_control()) - port->set_value(port->port_info()->default_val(), 0); - else if (port->port_info()->is_audio()) - port->set_value(0.0f, 0); - } - slv2_instance_activate(m_instances[i]); - } -} - - -void -LV2Plugin::deactivate() -{ - NodeBase::deactivate(); - - for (size_t i=0; i < m_poly; ++i) - slv2_instance_deactivate(m_instances[i]); -} - - -void -LV2Plugin::run(size_t nframes) -{ - NodeBase::run(nframes); // mixes down input ports - for (size_t i=0; i < m_poly; ++i) - slv2_instance_run(m_instances[i], nframes); -} - - -void -LV2Plugin::set_port_buffer(size_t voice, size_t port_num, void* buf) -{ - assert(voice < m_poly); - - // Could be a MIDI port after this - if (port_num < m_num_ports) { - slv2_instance_connect_port(m_instances[voice], port_num, buf); - } -} - - -// Based on code stolen from jack-rack -void -LV2Plugin::get_port_vals(ulong port_index, PortInfo* info) -{ -#if 0 - LV2_Data upper = 0.0f; - LV2_Data lower = 0.0f; - LV2_Data normal = 0.0f; - LV2_PortRangeHintDescriptor hint_descriptor = m_descriptor->PortRangeHints[port_index].HintDescriptor; - - /* set upper and lower, possibly adjusted to the sample rate */ - if (LV2_IS_HINT_SAMPLE_RATE(hint_descriptor)) { - upper = m_descriptor->PortRangeHints[port_index].UpperBound * m_srate; - lower = m_descriptor->PortRangeHints[port_index].LowerBound * m_srate; - } else { - upper = m_descriptor->PortRangeHints[port_index].UpperBound; - lower = m_descriptor->PortRangeHints[port_index].LowerBound; - } - - if (LV2_IS_HINT_LOGARITHMIC(hint_descriptor)) { - /* FLT_EPSILON is defined as the different between 1.0 and the minimum - * float greater than 1.0. So, if lower is < FLT_EPSILON, it will be 1.0 - * and the logarithmic control will have a base of 1 and thus not change - */ - if (lower < FLT_EPSILON) lower = FLT_EPSILON; - } - - - if (LV2_IS_HINT_HAS_DEFAULT(hint_descriptor)) { - - if (LV2_IS_HINT_DEFAULT_MINIMUM(hint_descriptor)) { - normal = lower; - } else if (LV2_IS_HINT_DEFAULT_LOW(hint_descriptor)) { - if (LV2_IS_HINT_LOGARITHMIC(hint_descriptor)) { - normal = exp(log(lower) * 0.75 + log(upper) * 0.25); - } else { - normal = lower * 0.75 + upper * 0.25; - } - } else if (LV2_IS_HINT_DEFAULT_MIDDLE(hint_descriptor)) { - if (LV2_IS_HINT_LOGARITHMIC(hint_descriptor)) { - normal = exp(log(lower) * 0.5 + log(upper) * 0.5); - } else { - normal = lower * 0.5 + upper * 0.5; - } - } else if (LV2_IS_HINT_DEFAULT_HIGH(hint_descriptor)) { - if (LV2_IS_HINT_LOGARITHMIC(hint_descriptor)) { - normal = exp(log(lower) * 0.25 + log(upper) * 0.75); - } else { - normal = lower * 0.25 + upper * 0.75; - } - } else if (LV2_IS_HINT_DEFAULT_MAXIMUM(hint_descriptor)) { - normal = upper; - } else if (LV2_IS_HINT_DEFAULT_0(hint_descriptor)) { - normal = 0.0; - } else if (LV2_IS_HINT_DEFAULT_1(hint_descriptor)) { - normal = 1.0; - } else if (LV2_IS_HINT_DEFAULT_100(hint_descriptor)) { - normal = 100.0; - } else if (LV2_IS_HINT_DEFAULT_440(hint_descriptor)) { - normal = 440.0; - } - } else { // No default hint - if (LV2_IS_HINT_BOUNDED_BELOW(hint_descriptor)) { - normal = lower; - } else if (LV2_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) { - normal = upper; - } - } - - info->min_val(lower); - info->default_val(normal); - info->max_val(upper); -#endif -} - - -} // namespace Om - diff --git a/src/engine/LV2Plugin.h b/src/engine/LV2Plugin.h deleted file mode 100644 index c3d3038a..00000000 --- a/src/engine/LV2Plugin.h +++ /dev/null @@ -1,76 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef LV2PLUGIN_H -#define LV2PLUGIN_H - -#include -#include -#include "util/types.h" -#include "NodeBase.h" -#include "Plugin.h" - -namespace Om { - -class PortInfo; - - -/** An instance of a LV2 plugin. - * - * \ingroup engine - */ -class LV2Plugin : public NodeBase -{ -public: - LV2Plugin(const string& name, - size_t poly, - Patch* parent, - const SLV2Plugin* plugin, - samplerate srate, - size_t buffer_size); - - virtual ~LV2Plugin(); - - virtual bool instantiate(); - - void activate(); - void deactivate(); - - void run(size_t nframes); - - void set_port_buffer(size_t voice, size_t port_num, void* buf); - - const Plugin* plugin() const { return m_om_plugin; } - void plugin(const Plugin* const p) { m_om_plugin = p; } - -protected: - // Prevent copies (undefined) - LV2Plugin(const LV2Plugin& copy); - LV2Plugin& operator=(const LV2Plugin&); - - void get_port_vals(ulong port_index, PortInfo* info); - - const SLV2Plugin* m_lv2_plugin; - SLV2Instance** m_instances; - - const Plugin* m_om_plugin; -}; - - -} // namespace Om - -#endif // LV2PLUGIN_H - diff --git a/src/engine/LashDriver.cpp b/src/engine/LashDriver.cpp deleted file mode 100644 index f42f87f2..00000000 --- a/src/engine/LashDriver.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "LashDriver.h" -#include "config.h" -#include -#include -#include -#include "OmApp.h" - -using std::cerr; using std::cout; using std::endl; -using std::string; - -namespace Om { - - -LashDriver::LashDriver(OmApp* app, lash_args_t* args) -: m_app(app), - m_client(NULL), - m_alsa_client_id(0) // FIXME: appropriate sentinel? -{ - m_client = lash_init(args, PACKAGE_NAME, - /*LASH_Config_Data_Set|LASH_Config_File*/0, LASH_PROTOCOL(2, 0)); - if (m_client == NULL) { - cerr << "[LashDriver] Failed to connect to LASH. Session management will not function." << endl; - } else { - cout << "[LashDriver] Lash initialised" << endl; - lash_event_t* event = lash_event_new_with_type(LASH_Client_Name); - lash_event_set_string(event, "Om"); - lash_send_event(m_client, event); - } -} - - -/** Set the Jack client name to be sent to LASH. - * The name isn't actually send until restore_finished() is called. - */ -void -LashDriver::set_jack_client_name(const char* name) -{ - m_jack_client_name = name; - lash_jack_client_name(m_client, m_jack_client_name.c_str()); -} - - -/** Set the Alsa client ID to be sent to LASH. - * The name isn't actually send until restore_finished() is called. - */ -void -LashDriver::set_alsa_client_id(int id) -{ - m_alsa_client_id = id; - lash_alsa_client_id(m_client, m_alsa_client_id); -} - - -/** Notify LASH of our port names so it can restore connections. - * The Alsa client ID and Jack client name MUST be set before calling - * this function. - */ -void -LashDriver::restore_finished() -{ - assert(m_jack_client_name != ""); - assert(m_alsa_client_id != 0); - - cerr << "LASH RESTORE FINISHED " << m_jack_client_name << " - " << m_alsa_client_id << endl; - - lash_jack_client_name(m_client, m_jack_client_name.c_str()); - lash_alsa_client_id(m_client, m_alsa_client_id); -} - - -void -LashDriver::process_events() -{ - assert(m_client != NULL); - - lash_event_t* ev = NULL; - lash_config_t* conf = NULL; - - // Process events - while ((ev = lash_get_event(m_client)) != NULL) { - handle_event(ev); - lash_event_destroy(ev); - } - - // Process configs - while ((conf = lash_get_config(m_client)) != NULL) { - handle_config(conf); - lash_config_destroy(conf); - } -} - - -void -LashDriver::handle_event(lash_event_t* ev) -{ - LASH_Event_Type type = lash_event_get_type(ev); - const char* c_str = lash_event_get_string(ev); - string str = (c_str == NULL) ? "" : c_str; - - //cout << "[LashDriver] LASH Event. Type = " << type << ", string = " << str << "**********" << endl; - - /*if (type == LASH_Save_File) { - //cout << "[LashDriver] LASH Save File - " << str << endl; - m_app->store_window_location(); - m_app->state_manager()->save(str.append("/locations")); - lash_send_event(m_client, lash_event_new_with_type(LASH_Save_File)); - } else if (type == LASH_Restore_File) { - //cout << "[LashDriver] LASH Restore File - " << str << endl; - m_app->state_manager()->load(str.append("/locations")); - m_app->update_state(); - lash_send_event(m_client, lash_event_new_with_type(LASH_Restore_File)); - } else if (type == LASH_Save_Data_Set) { - //cout << "[LashDriver] LASH Save Data Set - " << endl; - - // Tell LASH we're done - lash_send_event(m_client, lash_event_new_with_type(LASH_Save_Data_Set)); - } else*/ - if (type == LASH_Quit) { - //stop_thread(); - m_client = NULL; - m_app->quit(); - } else { - cerr << "[LashDriver] WARNING: Unhandled lash event, type " << static_cast(type) << endl; - } -} - - -void -LashDriver::handle_config(lash_config_t* conf) -{ - const char* key = NULL; - const void* val = NULL; - size_t val_size = 0; - - //cout << "[LashDriver] LASH Config. Key = " << key << endl; - - key = lash_config_get_key(conf); - val = lash_config_get_value(conf); - val_size = lash_config_get_value_size(conf); -} - - -} // namespace Om diff --git a/src/engine/LashDriver.h b/src/engine/LashDriver.h deleted file mode 100644 index dedf1c6b..00000000 --- a/src/engine/LashDriver.h +++ /dev/null @@ -1,57 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef LASHDRIVER_H -#define LASHDRIVER_H - -#include -#include -#include -using std::string; - -namespace Om { - -class OmApp; - - -/** Handles all support for LASH session management. - */ -class LashDriver -{ -public: - LashDriver(OmApp* app, lash_args_t* args); - - bool enabled() { return (m_client != NULL && lash_enabled(m_client)); } - void process_events(); - void set_jack_client_name(const char* name); - void set_alsa_client_id(int id); - void restore_finished(); - -private: - OmApp* m_app; - lash_client_t* m_client; - - int m_alsa_client_id; - string m_jack_client_name; - - void handle_event(lash_event_t* conf); - void handle_config(lash_config_t* conf); -}; - - -} // namespace Om - -#endif // LASHDRIVER_H diff --git a/src/engine/List.h b/src/engine/List.h deleted file mode 100644 index cc51bc5d..00000000 --- a/src/engine/List.h +++ /dev/null @@ -1,416 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef LIST_H -#define LIST_H - -#include -#include "util/types.h" -#include "MaidObject.h" - - -/** A node in a List. - * - * This class is (unusually) exposed to the user to allow list operations - * to be realtime safe (ie so events can allocate list nodes in other threads - * and then insert them in the realtime thread. - */ -template -class ListNode : public MaidObject -{ -public: - ListNode(T elem) : m_elem(elem), m_next(NULL), m_prev(NULL) {} - virtual ~ListNode() {} - - ListNode* next() const { return m_next; } - void next(ListNode* ln) { m_next = ln; } - ListNode* prev() const { return m_prev; } - void prev(ListNode* ln) { m_prev = ln; } - T& elem() { return m_elem;} - const T& elem() const { return m_elem; } - -private: - // Prevent copies (undefined) - ListNode(const ListNode& copy); - ListNode& operator=(const ListNode& copy); - - T m_elem; - ListNode* m_next; - ListNode* m_prev; -}; - - - -/** A realtime safe, (partially) thread safe doubly linked list. - * - * Elements can be added safely while another thread is reading the list. See - * documentation for specific functions for realtime/thread safeness. - */ -template -class List : public MaidObject -{ -public: - List() : m_head(NULL), m_tail(NULL), m_size(0), m_end_iter(this), m_const_end_iter(this) - { - m_end_iter.m_listnode = NULL; - m_end_iter.m_next = NULL; - m_const_end_iter.m_listnode = NULL; - m_const_end_iter.m_next = NULL; - } - ~List(); - - void push_back(ListNode* elem); - ListNode* remove(const T elem); - - void clear(); - size_t size() const { return m_size; } - - class iterator; - - /** Realtime safe const iterator for a List. */ - class const_iterator - { - public: - const_iterator(const List* const list); - const_iterator(const iterator& i) - : m_list(i.m_list), m_listnode(i.m_listnode), m_next(i.m_next) {} - - inline const T& operator*(); - inline const_iterator& operator++(); - inline bool operator!=(const const_iterator& iter) const; - inline bool operator!=(const iterator& iter) const; - - friend class List; - - private: - const List* const m_list; - const ListNode* m_listnode; - const ListNode* m_next; // use this instead of m_listnode->next() to allow deleting - }; - - - /** Realtime safe iterator for a List. */ - class iterator - { - public: - iterator(List* const list); - - inline T& operator*(); - inline iterator& operator++(); - inline bool operator!=(const iterator& iter) const; - inline bool operator!=(const const_iterator& iter) const; - - friend class List; - friend class List::const_iterator; - - private: - const List* m_list; - ListNode* m_listnode; - ListNode* m_next; // use this instead of m_listnode->next() to allow deleting - }; - - - ListNode* remove(const iterator iter); - - iterator begin(); - const iterator end() const; - - const_iterator begin() const; - //const_iterator end() const; - -private: - // Prevent copies (undefined) - List(const List& copy); - List& operator=(const List& copy); - - ListNode* m_head; - ListNode* m_tail; - size_t m_size; - iterator m_end_iter; - const_iterator m_const_end_iter; -}; - - - - -template -List::~List() -{ - clear(); -} - - -/** Clear the list, deleting all ListNodes contained (but NOT their contents!) - * - * Not realtime safe. - */ -template -void -List::clear() -{ - if (m_head == NULL) return; - - ListNode* node = m_head; - ListNode* next = NULL; - - while (node != NULL) { - next = node->next(); - delete node; - node = next; - } - m_tail = m_head = NULL; - m_size = 0; -} - - -/** Add an element to the list. - * - * This method can be called while another thread is reading the list. - * Realtime safe. - */ -template -void -List::push_back(ListNode* const ln) -{ - assert(ln != NULL); - - ln->next(NULL); - // FIXME: atomicity? relevant? - if (m_head == NULL) { - ln->prev(NULL); - m_head = m_tail = ln; - } else { - ln->prev(m_tail); - m_tail->next(ln); - m_tail = ln; - } - ++m_size; -} - - -/** Remove an element from the list. - * - * This function is realtime safe - it is the caller's responsibility to - * delete the returned ListNode, or there will be a leak. - */ -template -ListNode* -List::remove(const T elem) -{ - // FIXME: atomicity? - ListNode* n = m_head; - while (n != NULL) { - if (n->elem() == elem) - break; - n = n->next(); - } - if (n != NULL) { - if (n == m_head) m_head = m_head->next(); - if (n == m_tail) m_tail = m_tail->prev(); - if (n->prev() != NULL) - n->prev()->next(n->next()); - if (n->next() != NULL) - n->next()->prev(n->prev()); - --m_size; - if (m_size == 0) m_head = m_tail = NULL; // FIXME: Shouldn't be necessary - return n; - } - return NULL; -} - - -/** Remove an element from the list using an iterator. - * - * This function is realtime safe - it is the caller's responsibility to - * delete the returned ListNode, or there will be a leak. - */ -template -ListNode* -List::remove(const iterator iter) -{ - ListNode* n = iter.m_listnode; - if (n != NULL) { - if (n == m_head) m_head = m_head->next(); - if (n == m_tail) m_tail = m_tail->prev(); - if (n->prev() != NULL) - n->prev()->next(n->next()); - if (n->next() != NULL) - n->next()->prev(n->prev()); - --m_size; - if (m_size == 0) m_head = m_tail = NULL; // FIXME: Shouldn't be necessary - return n; - } - return NULL; -} - - -//// Iterator stuff //// - -template -List::iterator::iterator(List* list) -: m_list(list), - m_listnode(NULL), - m_next(NULL) -{ -} - - -template -T& -List::iterator::operator*() -{ - assert(m_listnode != NULL); - return m_listnode->elem(); -} - - -template -inline typename List::iterator& -List::iterator::operator++() -{ - assert(m_listnode != NULL); - m_listnode = m_next; - if (m_next != NULL) - m_next = m_next->next(); - else - m_next = NULL; - - return *this; -} - - -template -inline bool -List::iterator::operator!=(const iterator& iter) const -{ - return (m_listnode != iter.m_listnode); -} - - -template -inline bool -List::iterator::operator!=(const const_iterator& iter) const -{ - return (m_listnode != iter.m_listnode); -} - - -template -inline typename List::iterator -List::begin() -{ - typename List::iterator iter(this); - iter.m_listnode = m_head; - if (m_head != NULL) - iter.m_next = m_head->next(); - else - iter.m_next = NULL; - return iter; -} - - -template -inline const typename List::iterator -List::end() const -{ - /*typename List::iterator iter(this); - iter.m_listnode = NULL; - iter.m_next = NULL; - return iter;*/ - return m_end_iter; -} - - - -/// const_iterator stuff /// - - -template -List::const_iterator::const_iterator(const List* const list) -: m_list(list), - m_listnode(NULL), - m_next(NULL) -{ -} - - -template -const T& -List::const_iterator::operator*() -{ - assert(m_listnode != NULL); - return m_listnode->elem(); -} - - -template -inline typename List::const_iterator& -List::const_iterator::operator++() -{ - assert(m_listnode != NULL); - m_listnode = m_next; - if (m_next != NULL) - m_next = m_next->next(); - else - m_next = NULL; - - return *this; -} - - -template -inline bool -List::const_iterator::operator!=(const const_iterator& iter) const -{ - return (m_listnode != iter.m_listnode); -} - - -template -inline bool -List::const_iterator::operator!=(const iterator& iter) const -{ - return (m_listnode != iter.m_listnode); -} - - -template -inline typename List::const_iterator -List::begin() const -{ - typename List::const_iterator iter(this); - iter.m_listnode = m_head; - if (m_head != NULL) - iter.m_next = m_head->next(); - else - iter.m_next = NULL; - return iter; -} - -#if 0 -template -inline typename List::const_iterator -List::end() const -{ - /*typename List::const_iterator iter(this); - iter.m_listnode = NULL; - iter.m_next = NULL; - return iter;*/ - return m_const_end_iter; -} -#endif - -#endif // LIST_H diff --git a/src/engine/Maid.cpp b/src/engine/Maid.cpp deleted file mode 100644 index 3bebdedb..00000000 --- a/src/engine/Maid.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Maid.h" -#include "MaidObject.h" - - -Maid::Maid(size_t size) -: m_objects(size) -{ -} - - -Maid::~Maid() -{ - cleanup(); -} - - -/** Free all the objects in the queue (passed by push()). - */ -void -Maid::cleanup() -{ - MaidObject* obj = NULL; - - while (!m_objects.is_empty()) { - obj = m_objects.pop(); - delete obj; - } -} - - diff --git a/src/engine/Maid.h b/src/engine/Maid.h deleted file mode 100644 index 75412186..00000000 --- a/src/engine/Maid.h +++ /dev/null @@ -1,65 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MAID_H -#define MAID_H - -#include "MaidObject.h" -#include "util/Queue.h" - - -/** Explicitly driven garbage collector. - * - * This is how realtime parts of the code can schedule the deletion of - * objects - push() is realtime safe. - * - * cleanup() is meant to be called periodically to free memory, often - * enough to prevent the queue from overdflowing. This is done by the - * main thread, in OmApp. - * - * \ingroup engine - */ -class Maid -{ -public: - Maid(size_t size); - ~Maid(); - - inline void push(MaidObject* obj); - - void cleanup(); - -private: - // Prevent copies - Maid(const Maid&); - Maid& operator=(const Maid&); - - Queue m_objects; -}; - - -/** Push an event to be deleted. Realtime safe. - */ -inline void -Maid::push(MaidObject* obj) -{ - if (obj != NULL) - m_objects.push(obj); -} - - -#endif // MAID_H - diff --git a/src/engine/MaidObject.h b/src/engine/MaidObject.h deleted file mode 100644 index d0060520..00000000 --- a/src/engine/MaidObject.h +++ /dev/null @@ -1,38 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MAIDOBJECT_H -#define MAIDOBJECT_H - - -/** An object that can be passed to the maid for deletion. - * - * \ingroup engine - */ -class MaidObject -{ -public: - MaidObject() {} - virtual ~MaidObject() {} - -private: - // Prevent copies - MaidObject(const MaidObject&); - MaidObject& operator=(const MaidObject&); -}; - - -#endif // MAIDOBJECT_H diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am deleted file mode 100644 index ae0b3e53..00000000 --- a/src/engine/Makefile.am +++ /dev/null @@ -1,259 +0,0 @@ -SUBDIRS = tests -DIST_SUBDIRS = events - -AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @SLV2_CFLAGS@ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/engine/events -fno-exceptions -fno-rtti - -MAINTAINERCLEANFILES = Makefile.in - -common_SOURCES = \ - util.h \ - tuning.h \ - Node.h \ - NodeBase.h \ - NodeBase.cpp \ - InternalNode.h \ - Patch.h \ - Patch.cpp \ - NodeFactory.h \ - NodeFactory.cpp \ - Om.h \ - Om.cpp \ - OmApp.h \ - OmApp.cpp \ - JackAudioDriver.h \ - JackAudioDriver.cpp \ - OSCReceiver.h \ - OSCReceiver.cpp \ - Responder.h \ - OSCResponder.h \ - OSCResponder.cpp \ - ClientKey.h \ - ClientBroadcaster.h \ - ClientBroadcaster.cpp \ - ObjectSender.h \ - ObjectSender.cpp \ - OSCClient.h \ - OSCClient.cpp \ - Buffer.h \ - Buffer.cpp \ - Port.h \ - Port.cpp \ - PortBase.h \ - PortBase.cpp \ - InputPort.h \ - InputPort.cpp \ - OutputPort.h \ - OutputPort.cpp \ - MidiMessage.h \ - MidiNoteNode.h \ - MidiNoteNode.cpp \ - MidiTriggerNode.h \ - MidiTriggerNode.cpp \ - MidiControlNode.h \ - MidiControlNode.cpp \ - BridgeNode.h \ - BridgeNode.cpp \ - ControlInputNode.h \ - ControlInputNode.cpp \ - ControlOutputNode.h \ - ControlOutputNode.cpp \ - AudioInputNode.h \ - AudioInputNode.cpp \ - AudioOutputNode.h \ - AudioOutputNode.cpp \ - MidiInputNode.h \ - MidiInputNode.cpp \ - MidiOutputNode.h \ - MidiOutputNode.cpp \ - Event.h \ - Event.cpp \ - QueuedEvent.h \ - EventSource.h \ - QueuedEventSource.h \ - QueuedEventSource.cpp \ - QueuedEngineInterface.h \ - QueuedEngineInterface.cpp \ - OmObject.h \ - Maid.h \ - Maid.cpp \ - MaidObject.h \ - Tree.h \ - ClientRecord.h \ - PortInfo.h \ - PluginLibrary.h \ - Plugin.h \ - Array.h \ - List.h \ - PostProcessor.h \ - PostProcessor.cpp \ - Connection.h \ - Connection.cpp \ - ConnectionBase.h \ - ConnectionBase.cpp \ - ObjectStore.h \ - ObjectStore.cpp \ - TransportNode.h \ - TransportNode.cpp \ - Driver.h \ - AudioDriver.h \ - MidiDriver.h \ - midi.h \ - ../common/util/Semaphore.h \ - ../common/util/types.h \ - ../common/util/Path.h \ - ../common/util/Queue.h \ - ../common/interface/ClientInterface.h \ - ../common/interface/EngineInterface.h \ - instantiations.cpp - -# Events -common_SOURCES += \ - events/RegisterClientEvent.h \ - events/RegisterClientEvent.cpp \ - events/UnregisterClientEvent.h \ - events/UnregisterClientEvent.cpp \ - events/PingQueuedEvent.h \ - events/ActivateEvent.h \ - events/ActivateEvent.cpp \ - events/DeactivateEvent.h \ - events/DeactivateEvent.cpp \ - events/SetPortValueEvent.h \ - events/SetPortValueEvent.cpp \ - events/SetPortValueQueuedEvent.h \ - events/SetPortValueQueuedEvent.cpp \ - events/NoteOnEvent.h \ - events/NoteOnEvent.cpp \ - events/NoteOffEvent.h \ - events/NoteOffEvent.cpp \ - events/AllNotesOffEvent.h \ - events/AllNotesOffEvent.cpp \ - events/ConnectionEvent.h \ - events/ConnectionEvent.cpp \ - events/DisconnectionEvent.h \ - events/DisconnectionEvent.cpp \ - events/DisconnectNodeEvent.h \ - events/DisconnectNodeEvent.cpp \ - events/DisconnectPortEvent.h \ - events/DisconnectPortEvent.cpp \ - events/DestroyEvent.h \ - events/DestroyEvent.cpp \ - events/AddNodeEvent.h \ - events/AddNodeEvent.cpp \ - events/SetMetadataEvent.h \ - events/SetMetadataEvent.cpp \ - events/RequestMetadataEvent.h \ - events/RequestMetadataEvent.cpp \ - events/RequestPortValueEvent.h \ - events/RequestPortValueEvent.cpp \ - events/RequestAllObjectsEvent.h \ - events/RequestAllObjectsEvent.cpp \ - events/RequestPluginsEvent.h \ - events/RequestPluginsEvent.cpp \ - events/CreatePatchEvent.h \ - events/CreatePatchEvent.cpp \ - events/LoadPluginsEvent.h \ - events/LoadPluginsEvent.cpp \ - events/EnablePatchEvent.h \ - events/EnablePatchEvent.cpp \ - events/DisablePatchEvent.h \ - events/DisablePatchEvent.cpp \ - events/ClearPatchEvent.h \ - events/ClearPatchEvent.cpp \ - events/RenameEvent.h \ - events/RenameEvent.cpp \ - events/MidiLearnEvent.h \ - events/MidiLearnEvent.cpp - -if WITH_JACK_MIDI -common_SOURCES += \ - JackMidiDriver.h \ - JackMidiDriver.cpp -endif - -if WITH_ALSA_MIDI -common_SOURCES += \ - AlsaMidiDriver.h \ - AlsaMidiDriver.cpp -endif - -if WITH_LADSPA -common_SOURCES += \ - LADSPAPlugin.h \ - LADSPAPlugin.cpp -endif - -if WITH_DSSI -common_SOURCES += \ - DSSIPlugin.h \ - DSSIPlugin.cpp \ - events/DSSIConfigureEvent.cpp \ - events/DSSIConfigureEvent.h \ - events/DSSIControlEvent.cpp \ - events/DSSIControlEvent.h \ - events/DSSIProgramEvent.cpp \ - events/DSSIProgramEvent.h \ - events/DSSIUpdateEvent.cpp \ - events/DSSIUpdateEvent.h -endif - -if WITH_LV2 -common_SOURCES += \ - LV2Plugin.h \ - LV2Plugin.cpp -endif - -if WITH_LASH -common_SOURCES += \ - LashDriver.h \ - LashDriver.cpp \ - LashRestoreDoneEvent.h -endif - - -# -# Non-installed library to link stand-alone and in-process build against -# - -noinst_LTLIBRARIES = libom.la -libom_la_SOURCES = $(common_SOURCES) - - - -# -# Stand-alone engine -# -if BUILD_ENGINE - -bin_PROGRAMS = om -om_DEPENDENCIES = libom.la -om_LDADD = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -lrt libom.la - -om_SOURCES = \ - main.cpp \ - cmdline.h \ - cmdline.c - -endif # BUILD_ENGINE - - - -# -# Jack internal client -# -if BUILD_IN_PROCESS_ENGINE - - -# FIXME: broken - - -# FIXME: Figure out how to get this properly -omdir = $(prefix)/lib/jack - -om_la_CFLAGS = -fPIC -om_LTLIBRARIES = om.la -om_la_LDFLAGS = -module -avoid-version @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -om_la_SOURCES = OmInProcess.cpp - -endif # BUILD_IN_PROCESS_ENGINE - - diff --git a/src/engine/MidiControlNode.cpp b/src/engine/MidiControlNode.cpp deleted file mode 100644 index 2116c828..00000000 --- a/src/engine/MidiControlNode.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MidiControlNode.h" -#include -#include "Om.h" -#include "OmApp.h" -#include "PostProcessor.h" -#include "MidiLearnEvent.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "PortInfo.h" -#include "Plugin.h" -#include "util.h" -#include "midi.h" - - -namespace Om { - - -MidiControlNode::MidiControlNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: InternalNode(path, 1, parent, srate, buffer_size), - m_learning(false) -{ - m_num_ports = 7; - m_ports.alloc(m_num_ports); - - m_midi_in_port = new InputPort(this, "MIDI In", 0, 1, - new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); - m_ports.at(0) = m_midi_in_port; - - m_param_port = new InputPort(this, "Controller Number", 1, 1, - new PortInfo("Controller Number", CONTROL, INPUT, INTEGER, 60, 0, 127), 1); - m_ports.at(1) = m_param_port; - m_log_port = new InputPort(this, "Logarithmic", 2, 1, - new PortInfo("Logarithmic", CONTROL, INPUT, TOGGLE, 0, 0, 1), 1); - m_ports.at(2) = m_log_port; - - m_min_port = new InputPort(this, "Min", 3, 1, - new PortInfo("Min", CONTROL, INPUT, NONE, 0, 0, 65535), 1); - m_ports.at(3) = m_min_port; - - m_max_port = new InputPort(this, "Max", 4, 1, - new PortInfo("Max", CONTROL, INPUT, NONE, 1, 0, 65535), 1); - m_ports.at(4) = m_max_port; - - m_audio_port = new OutputPort(this, "Out (AR)", 5, 1, - new PortInfo("Out (AR)", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); - m_ports.at(5) = m_audio_port; - - m_control_port = new OutputPort(this, "Out (CR)", 6, 1, - new PortInfo("Out (CR)", CONTROL, OUTPUT, 0, 0, 1), 1); - m_ports.at(6) = m_control_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("midi_control_in"); - m_plugin.name("Om Control Node (MIDI)"); -} - - -void -MidiControlNode::run(size_t nframes) -{ - InternalNode::run(nframes); - - MidiMessage ev; - - for (size_t i=0; i < m_midi_in_port->buffer(0)->filled_size(); ++i) { - ev = m_midi_in_port->buffer(0)->value_at(i); - - if ((ev.buffer[0] & 0xF0) == MIDI_CMD_CONTROL) - control(ev.buffer[1], ev.buffer[2], ev.time); - } -} - - -void -MidiControlNode::control(uchar control_num, uchar val, samplecount offset) -{ - assert(offset < m_buffer_size); - - sample scaled_value; - - const sample nval = (val / 127.0f); // normalized [0, 1] - - if (m_learning) { - assert(m_learn_event != NULL); - m_param_port->set_value(control_num, offset); - assert(m_param_port->buffer(0)->value_at(0) == control_num); - m_learn_event->set_value(control_num); - m_learn_event->execute(offset); - om->post_processor()->push(m_learn_event); - om->post_processor()->signal(); - m_learning = false; - m_learn_event = NULL; - } - - if (m_log_port->buffer(0)->value_at(0) > 0.0f) { - // haaaaack, stupid negatives and logarithms - sample log_offset = 0; - if (m_min_port->buffer(0)->value_at(0) < 0) - log_offset = fabs(m_min_port->buffer(0)->value_at(0)); - const sample min = log(m_min_port->buffer(0)->value_at(0)+1+log_offset); - const sample max = log(m_max_port->buffer(0)->value_at(0)+1+log_offset); - scaled_value = expf(nval * (max - min) + min) - 1 - log_offset; - } else { - const sample min = m_min_port->buffer(0)->value_at(0); - const sample max = m_max_port->buffer(0)->value_at(0); - scaled_value = ((nval) * (max - min)) + min; - } - - if (control_num == m_param_port->buffer(0)->value_at(0)) { - m_control_port->set_value(scaled_value, offset); - m_audio_port->set_value(scaled_value, offset); - } -} - - -} // namespace Om - diff --git a/src/engine/MidiControlNode.h b/src/engine/MidiControlNode.h deleted file mode 100644 index b40e7631..00000000 --- a/src/engine/MidiControlNode.h +++ /dev/null @@ -1,72 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MIDICONTROLNODE_H -#define MIDICONTROLNODE_H - -#include -#include "NodeBase.h" -#include "InternalNode.h" -using std::string; - -namespace Om { - -class MidiLearnResponseEvent; -class MidiMessage; -template class InputPort; -template class OutputPort; - - -/** MIDI control input node. - * - * Creating one of these nodes is how a user makes "MIDI Bindings". Note that - * this node will always be monophonic, the poly parameter is ignored. - * - * \ingroup engine - */ -class MidiControlNode : public InternalNode -{ -public: - MidiControlNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); - - void run(size_t nframes); - - void control(uchar control_num, uchar val, samplecount offset); - - void learn(MidiLearnResponseEvent* ev) { m_learning = true; m_learn_event = ev; } - -private: - // Disallow copies (undefined) - MidiControlNode(const MidiControlNode& copy); - MidiControlNode& operator=(const MidiControlNode&); - - bool m_learning; - - InputPort* m_midi_in_port; - InputPort* m_param_port; - InputPort* m_log_port; - InputPort* m_min_port; - InputPort* m_max_port; - OutputPort* m_control_port; - OutputPort* m_audio_port; - - MidiLearnResponseEvent* m_learn_event; -}; - - -} // namespace Om - -#endif // MIDICONTROLNODE_H diff --git a/src/engine/MidiDriver.h b/src/engine/MidiDriver.h deleted file mode 100644 index b8fd71ca..00000000 --- a/src/engine/MidiDriver.h +++ /dev/null @@ -1,78 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MIDIDRIVER_H -#define MIDIDRIVER_H - -#include "Driver.h" -#include -using std::cout; using std::endl; - -namespace Om { - -class MidiMessage; - - -/** Midi driver abstract base class. - * - * \ingroup engine - */ -class MidiDriver : public Driver -{ -public: - /** Prepare events (however neccessary) for the specified block (realtime safe) */ - virtual void prepare_block(const samplecount block_start, const samplecount block_end) = 0; -}; - - - -/** Dummy MIDIDriver. - * - * Not abstract, all functions are dummies. One of these will be allocated and - * "used" if no working MIDI driver is loaded. (Doing it this way as opposed to - * just making MidiDriver have dummy functions makes sure any existing MidiDriver - * derived class actually implements the required functions). - * - * \ingroup engine - */ -class DummyMidiDriver : public MidiDriver -{ -public: - DummyMidiDriver() { - cout << "[DummyMidiDriver] Started Dummy MIDI driver." << endl; - } - - ~DummyMidiDriver() {} - - void activate() {} - void deactivate() {} - - bool is_activated() const { return false; } - bool is_enabled() const { return false; } - - void enable() {} - void disable() {} - - DriverPort* create_port(PortBase* patch_port) { return NULL; } - - void prepare_block(const samplecount block_start, const samplecount block_end) {} -}; - - - -} // namespace Om - -#endif // MIDIDRIVER_H diff --git a/src/engine/MidiInputNode.cpp b/src/engine/MidiInputNode.cpp deleted file mode 100644 index 25310807..00000000 --- a/src/engine/MidiInputNode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MidiInputNode.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Plugin.h" -#include "PortInfo.h" -#include "Patch.h" -#include "MidiMessage.h" - -namespace Om { - - -MidiInputNode::MidiInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: BridgeNode(path, 1, parent, srate, buffer_size) -{ - OutputPort* internal_port = new OutputPort(this, "in", 0, m_poly, - new PortInfo("in", MIDI, OUTPUT), m_buffer_size); - InputPort* external_port = new InputPort(parent, m_name, 0, m_poly, - new PortInfo(m_name, MIDI, INPUT), m_buffer_size); - external_port->tie(internal_port); - m_external_port = external_port; - - m_num_ports = 1; - m_ports.alloc(m_num_ports); - m_ports.at(0) = internal_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("midi_input"); - m_plugin.name("Om Patch MIDI Input Node"); -} - - -} // namespace Om - diff --git a/src/engine/MidiInputNode.h b/src/engine/MidiInputNode.h deleted file mode 100644 index 0986a267..00000000 --- a/src/engine/MidiInputNode.h +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MIDIINPUTNODE_H -#define MIDIINPUTNODE_H - -#include -#include "BridgeNode.h" - -using std::string; - -namespace Om { - -class MidiMessage; - - -/** MIDI input BridgeNode. - * - * \ingroup engine - */ -class MidiInputNode : public BridgeNode -{ -public: - MidiInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); -}; - - -} // namespace Om - -#endif // MIDIINPUTNODE_H diff --git a/src/engine/MidiMessage.h b/src/engine/MidiMessage.h deleted file mode 100644 index 8dcb3e67..00000000 --- a/src/engine/MidiMessage.h +++ /dev/null @@ -1,51 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MIDIMESSAGE_H -#define MIDIMESSAGE_H - -namespace Om { - - -/** Midi Message (the type a MIDI port connects to). - * - * For the time being (ie while it's still possible) this is binary - * compatible with jack_default_midi_event_t. Don't mess that up without - * dealing with all the repercussions (in the MidiDriver's). - * - * Note that with the current implementation one of these is NOT valid - * across process cycles (since the buffer is just a pointer to the bufferr - * given to us by Jack itself. In other words, if one of these needs to be - * stored, it needs to be deep copied. Less copying anyway.. :/ - */ -struct MidiMessage -{ -public: - MidiMessage() : time(0), size(0), buffer(NULL) {} - - // Really just to allow setting to zero for generic algos - MidiMessage(const int& i) : time(0), size(0), buffer(NULL) {} - - samplecount time; - size_t size; - unsigned char* buffer; -}; - - -} // namespace Om - - -#endif // MIDIMESSAGE_H diff --git a/src/engine/MidiNoteNode.cpp b/src/engine/MidiNoteNode.cpp deleted file mode 100644 index 9dc32f4a..00000000 --- a/src/engine/MidiNoteNode.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MidiNoteNode.h" -#include -#include -#include "MidiMessage.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "PortInfo.h" -#include "Plugin.h" -#include "Array.h" -#include "Om.h" -#include "OmApp.h" -#include "AudioDriver.h" -#include "util.h" -#include "midi.h" - -using std::cerr; using std::cout; using std::endl; - - -namespace Om { - - -MidiNoteNode::MidiNoteNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: InternalNode(path, poly, parent, srate, buffer_size), - m_voices(new Voice[poly]), - m_sustain(false) -{ - m_num_ports = 5; - m_ports.alloc(m_num_ports); - - m_midi_in_port = new InputPort(this, "MIDI In", 0, 1, - new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); - m_ports.at(0) = m_midi_in_port; - - m_freq_port = new OutputPort(this, "Frequency", 1, poly, - new PortInfo("Frequency", AUDIO, OUTPUT, 440, 0, 99999), m_buffer_size); - m_ports.at(1) = m_freq_port; - - m_vel_port = new OutputPort(this, "Velocity", 2, poly, - new PortInfo("Velocity", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); - m_ports.at(2) = m_vel_port; - - m_gate_port = new OutputPort(this, "Gate", 3, poly, - new PortInfo("Gate", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); - m_ports.at(3) = m_gate_port; - - m_trig_port = new OutputPort(this, "Trigger", 4, poly, - new PortInfo("Trigger", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); - m_ports.at(4) = m_trig_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("note_in"); - m_plugin.name("Om Note Node (MIDI, OSC)"); -} - - -MidiNoteNode::~MidiNoteNode() -{ - delete[] m_voices; -} - - -void -MidiNoteNode::run(size_t nframes) -{ - InternalNode::run(nframes); - - MidiMessage ev; - - for (size_t i=0; i < m_midi_in_port->buffer(0)->filled_size(); ++i) { - ev = m_midi_in_port->buffer(0)->value_at(i); - - switch (ev.buffer[0] & 0xF0) { - case MIDI_CMD_NOTE_ON: - if (ev.buffer[2] == 0) - note_off(ev.buffer[1], ev.time); - else - note_on(ev.buffer[1], ev.buffer[2], ev.time); - break; - case MIDI_CMD_NOTE_OFF: - note_off(ev.buffer[1], ev.time); - break; - case MIDI_CMD_CONTROL: - switch (ev.buffer[1]) { - case MIDI_CTL_ALL_NOTES_OFF: - case MIDI_CTL_ALL_SOUNDS_OFF: - all_notes_off(ev.time); - break; - case MIDI_CTL_SUSTAIN: - if (ev.buffer[2] > 63) - sustain_on(); - else - sustain_off(ev.time); - break; - case MIDI_CMD_BENDER: - - break; - } - default: - break; - } - } -} - - -void -MidiNoteNode::note_on(uchar note_num, uchar velocity, samplecount offset) -{ - const jack_nframes_t time_stamp = om->audio_driver()->time_stamp(); - - assert(offset < m_buffer_size); - assert(note_num <= 127); - - Key* key = &m_keys[note_num]; - Voice* voice = NULL; - size_t voice_num = 0; - - // Look for free voices - for (size_t i=0; i < m_poly; ++i) { - if (m_voices[i].state == Voice::Voice::FREE) { - voice = &m_voices[i]; - voice_num = i; - break; - } - } - - // If we didn't find a free one, steal the oldest - if (voice == NULL) { - voice_num = 0; - voice = &m_voices[0]; - jack_nframes_t oldest_time = m_voices[0].time; - for (size_t i=1; i < m_poly; ++i) { - if (m_voices[i].time < oldest_time) { - voice = &m_voices[i]; - voice_num = i; - oldest_time = voice->time; - } - } - } - assert(voice != NULL); - assert(voice == &m_voices[voice_num]); - - //cerr << "[MidiNoteNode] Note on. Key " << (int)note_num << ", Voice " << voice_num << endl; - - // Update stolen key, if applicable - if (voice->state == Voice::Voice::ACTIVE) { - assert(m_keys[voice->note].voice == voice_num); - assert(m_keys[voice->note].state == Key::ON_ASSIGNED); - m_keys[voice->note].state = Key::Key::ON_UNASSIGNED; - //cerr << "[MidiNoteNode] Stole voice " << voice_num << endl; - } - - // Store key information for later reallocation on note off - key->state = Key::Key::ON_ASSIGNED; - key->voice = voice_num; - key->time = time_stamp; - - // Trigger voice - voice->state = Voice::Voice::ACTIVE; - voice->note = note_num; - voice->time = time_stamp; - - assert(m_keys[voice->note].state == Key::Key::ON_ASSIGNED); - assert(m_keys[voice->note].voice == voice_num); - - // one-sample jitter hack to avoid having to deal with trigger sample "next time" - if (offset == (samplecount)(m_buffer_size-1)) - --offset; - - m_freq_port->buffer(voice_num)->set(note_to_freq(note_num), offset); - m_vel_port->buffer(voice_num)->set(velocity/127.0, offset); - m_gate_port->buffer(voice_num)->set(1.0f, offset); - - // trigger (one sample) - m_trig_port->buffer(voice_num)->set(1.0f, offset, offset); - m_trig_port->buffer(voice_num)->set(0.0f, offset+1); - - assert(key->state == Key::Key::ON_ASSIGNED); - assert(voice->state == Voice::Voice::ACTIVE); - assert(key->voice == voice_num); - assert(m_voices[key->voice].note == note_num); -} - - -void -MidiNoteNode::note_off(uchar note_num, samplecount offset) -{ - assert(offset < m_buffer_size); - - Key* key = &m_keys[note_num]; - - if (key->state == Key::ON_ASSIGNED) { - // Assigned key, turn off voice and key - assert(m_voices[key->voice].state == Voice::ACTIVE); - assert(m_voices[key->voice].note == note_num); - key->state = Key::OFF; - - if ( ! m_sustain) - free_voice(key->voice, offset); - else - m_voices[key->voice].state = Voice::HOLDING; - } - - key->state = Key::OFF; -} - - -void -MidiNoteNode::free_voice(size_t voice, samplecount offset) -{ - // Find a key to reassign to the freed voice (the newest, if there is one) - Key* replace_key = NULL; - uchar replace_key_num = 0; - - for (uchar i = 0; i <= 127; ++i) { - if (m_keys[i].state == Key::ON_UNASSIGNED) { - if (replace_key == NULL || m_keys[i].time > replace_key->time) { - replace_key = &m_keys[i]; - replace_key_num = i; - } - } - } - - if (replace_key != NULL) { // Found a key to assign to freed voice - assert(&m_keys[replace_key_num] == replace_key); - assert(replace_key->state == Key::ON_UNASSIGNED); - - // Change the freq but leave the gate high and don't retrigger - m_freq_port->buffer(voice)->set(note_to_freq(replace_key_num), offset); - - replace_key->state = Key::ON_ASSIGNED; - replace_key->voice = voice; - m_keys[m_voices[voice].note].state = Key::ON_UNASSIGNED; - m_voices[voice].note = replace_key_num; - m_voices[voice].state = Voice::ACTIVE; - } else { - // No new note for voice, deactivate (set gate low) - //cerr << "[MidiNoteNode] Note off. Key " << (int)note_num << ", Voice " << voice << " Killed" << endl; - m_gate_port->buffer(voice)->set(0.0f, offset); - m_voices[voice].state = Voice::FREE; - } -} - - -void -MidiNoteNode::all_notes_off(samplecount offset) -{ - //cerr << "Note off starting at sample " << offset << endl; - assert(offset < m_buffer_size); - - // FIXME: set all keys to Key::OFF? - - for (size_t i=0; i < m_poly; ++i) { - m_gate_port->buffer(i)->set(0.0f, offset); - m_voices[i].state = Voice::FREE; - } -} - - -float -MidiNoteNode::note_to_freq(int num) -{ - static const float A4 = 440.0f; - if (num >= 0 && num <= 119) - return A4 * powf(2.0f, (float)(num - 57.0f) / 12.0f); - return 1.0f; // Some LADSPA plugins don't like freq=0 -} - - -void -MidiNoteNode::sustain_on() -{ - m_sustain = true; -} - - -void -MidiNoteNode::sustain_off(samplecount offset) -{ - m_sustain = false; - - for (size_t i=0; i < m_poly; ++i) - if (m_voices[i].state == Voice::HOLDING) - free_voice(i, offset); -} - - -} // namespace Om - diff --git a/src/engine/MidiNoteNode.h b/src/engine/MidiNoteNode.h deleted file mode 100644 index bf302144..00000000 --- a/src/engine/MidiNoteNode.h +++ /dev/null @@ -1,87 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MIDINOTENODE_H -#define MIDINOTENODE_H - -#include -#include "InternalNode.h" -#include "util/types.h" - -using std::string; - -namespace Om { - -class MidiMessage; -template class InputPort; -template class OutputPort; - - -/** MIDI note input node. - * - * For pitched instruments like keyboard, etc. - * - * \ingroup engine - */ -class MidiNoteNode : public InternalNode -{ -public: - MidiNoteNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); - ~MidiNoteNode(); - - void run(size_t nframes); - - void note_on(uchar note_num, uchar velocity, samplecount offset); - void note_off(uchar note_num, samplecount offset); - void all_notes_off(samplecount offset); - - void sustain_on(); - void sustain_off(samplecount offset); - -private: - - /** Key, one for each key on the keyboard */ - struct Key { - enum State { OFF, ON_ASSIGNED, ON_UNASSIGNED }; - Key() : state(OFF), voice(0), time(0) {} - State state; size_t voice; samplecount time; - }; - - /** Voice, one of these always exists for each voice */ - struct Voice { - enum State { FREE, ACTIVE, HOLDING }; - Voice() : state(FREE), note(0) {} - State state; uchar note; samplecount time; - }; - - float note_to_freq(int num); - void free_voice(size_t voice, samplecount offset); - - Voice* m_voices; - Key m_keys[128]; - bool m_sustain; ///< Whether or not hold pedal is depressed - - InputPort* m_midi_in_port; - OutputPort* m_freq_port; - OutputPort* m_vel_port; - OutputPort* m_gate_port; - OutputPort* m_trig_port; -}; - - -} // namespace Om - -#endif // MIDINOTENODE_H diff --git a/src/engine/MidiOutputNode.cpp b/src/engine/MidiOutputNode.cpp deleted file mode 100644 index 33023cc6..00000000 --- a/src/engine/MidiOutputNode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MidiOutputNode.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Plugin.h" -#include "PortInfo.h" -#include "Patch.h" -#include "MidiMessage.h" - -namespace Om { - - -MidiOutputNode::MidiOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: BridgeNode(path, 1, parent, srate, buffer_size) -{ - OutputPort* external_port = new OutputPort(parent, m_name, 0, m_poly, - new PortInfo(m_name, MIDI, OUTPUT), m_buffer_size); - InputPort* internal_port = new InputPort(this, "out", 0, m_poly, - new PortInfo("out", MIDI, INPUT), m_buffer_size); - internal_port->tie(external_port); - m_external_port = external_port; - - m_num_ports = 1; - m_ports.alloc(m_num_ports); - m_ports.at(0) = internal_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("midi_output"); - m_plugin.name("Om Patch MIDI Output Node"); -} - - -} // namespace Om - diff --git a/src/engine/MidiOutputNode.h b/src/engine/MidiOutputNode.h deleted file mode 100644 index 06d8a892..00000000 --- a/src/engine/MidiOutputNode.h +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MIDIOUTPUTNODE_H -#define MIDIOUTPUTNODE_H - -#include -#include "BridgeNode.h" - -using std::string; - -namespace Om { - -class MidiMessage; - - -/** MIDI output BridgeNode. - * - * \ingroup engine - */ -class MidiOutputNode : public BridgeNode -{ -public: - MidiOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); -}; - - -} // namespace Om - -#endif // MIDIOUTPUTNODE_H diff --git a/src/engine/MidiTriggerNode.cpp b/src/engine/MidiTriggerNode.cpp deleted file mode 100644 index 4fda80e7..00000000 --- a/src/engine/MidiTriggerNode.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MidiTriggerNode.h" -#include -#include "InputPort.h" -#include "OutputPort.h" -#include "PortInfo.h" -#include "Plugin.h" -#include "util.h" -#include "midi.h" - -namespace Om { - - -MidiTriggerNode::MidiTriggerNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: InternalNode(path, 1, parent, srate, buffer_size) -{ - m_num_ports = 5; - m_ports.alloc(m_num_ports); - - m_midi_in_port = new InputPort(this, "MIDI In", 0, 1, - new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); - m_ports.at(0) = m_midi_in_port; - - m_note_port = new InputPort(this, "Note Number", 1, 1, - new PortInfo("Note Number", CONTROL, INPUT, INTEGER, 60, 0, 127), 1); - m_ports.at(1) = m_note_port; - - m_gate_port = new OutputPort(this, "Gate", 2, 1, - new PortInfo("Gate", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); - m_ports.at(2) = m_gate_port; - - m_trig_port = new OutputPort(this, "Trigger", 3, 1, - new PortInfo("Trigger", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); - m_ports.at(3) = m_trig_port; - - m_vel_port = new OutputPort(this, "Velocity", 4, poly, - new PortInfo("Velocity", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); - m_ports.at(4) = m_vel_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("trigger_in"); - m_plugin.name("Om Trigger Node (MIDI, OSC)"); -} - - -void -MidiTriggerNode::run(size_t nframes) -{ - InternalNode::run(nframes); - - MidiMessage ev; - - for (size_t i=0; i < m_midi_in_port->buffer(0)->filled_size(); ++i) { - ev = m_midi_in_port->buffer(0)->value_at(i); - - switch (ev.buffer[0] & 0xF0) { - case MIDI_CMD_NOTE_ON: - if (ev.buffer[2] == 0) - note_off(ev.buffer[1], ev.time); - else - note_on(ev.buffer[1], ev.buffer[2], ev.time); - break; - case MIDI_CMD_NOTE_OFF: - note_off(ev.buffer[1], ev.time); - break; - case MIDI_CMD_CONTROL: - if (ev.buffer[1] == MIDI_CTL_ALL_NOTES_OFF - || ev.buffer[1] == MIDI_CTL_ALL_SOUNDS_OFF) - m_gate_port->buffer(0)->set(0.0f, ev.time); - default: - break; - } - } -} - - -void -MidiTriggerNode::note_on(uchar note_num, uchar velocity, samplecount offset) -{ - //std::cerr << "Note on starting at sample " << offset << std::endl; - assert(offset < m_buffer_size); - - const sample filter_note = m_note_port->buffer(0)->value_at(0); - if (filter_note >= 0.0 && filter_note < 127.0 && (note_num == (uchar)filter_note)){ - - // See comments in MidiNoteNode::note_on (FIXME) - if (offset == (samplecount)(m_buffer_size-1)) - --offset; - - m_gate_port->buffer(0)->set(1.0f, offset); - m_trig_port->buffer(0)->set(1.0f, offset, offset); - m_trig_port->buffer(0)->set(0.0f, offset+1); - m_vel_port->buffer(0)->set(velocity/127.0f, offset); - } -} - - -void -MidiTriggerNode::note_off(uchar note_num, samplecount offset) -{ - assert(offset < m_buffer_size); - - if (note_num == lrintf(m_note_port->buffer(0)->value_at(0))) - m_gate_port->buffer(0)->set(0.0f, offset); -} - - -} // namespace Om - diff --git a/src/engine/MidiTriggerNode.h b/src/engine/MidiTriggerNode.h deleted file mode 100644 index 2f91c631..00000000 --- a/src/engine/MidiTriggerNode.h +++ /dev/null @@ -1,64 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef MIDITRIGGERNODE_H -#define MIDITRIGGERNODE_H - -#include -#include "InternalNode.h" - -using std::string; - -namespace Om { - -class MidiMessage; -template class InputPort; -template class OutputPort; - - -/** MIDI trigger input node. - * - * Just has a gate, for drums etc. A control port is used to select - * which note number is responded to. - * - * Note that this node is always monophonic, the poly parameter is ignored. - * (Should that change?) - * - * \ingroup engine - */ -class MidiTriggerNode : public InternalNode -{ -public: - MidiTriggerNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); - - void run(size_t nframes); - - void note_on(uchar note_num, uchar velocity, samplecount offset); - void note_off(uchar note_num, samplecount offset); - -private: - InputPort* m_midi_in_port; - InputPort* m_note_port; - OutputPort* m_gate_port; - OutputPort* m_trig_port; - OutputPort* m_vel_port; -}; - - -} // namespace Om - -#endif // MIDITRIGGERNODE_H diff --git a/src/engine/Node.h b/src/engine/Node.h deleted file mode 100644 index d169e772..00000000 --- a/src/engine/Node.h +++ /dev/null @@ -1,120 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef NODE_H -#define NODE_H - -#include -#include "util/types.h" -#include "OmObject.h" -#include "Array.h" - -using std::string; - -template class List; - -namespace Om { - -class Port; -template class OutputPort; -class Plugin; -class Patch; -namespace Shared { - class ClientInterface; -} - - -/** A Node (or "module") in a Patch (which is also a Node). - * - * A Node is a unit with input/output ports, a run() method, and some other - * things. - * - * This is a pure abstract base class for any Node, it contains no - * implementation details/data whatsoever. This is the interface you need to - * implement to add a new Node type to Om. - * - * \ingroup engine - */ -class Node : public OmObject -{ -public: - Node(OmObject* parent, const string& name) : OmObject(parent, name) {} - virtual ~Node() {} - - Node* as_node() { return static_cast(this); } - - /** Activate this Node. - * - * This function will be called in a non-realtime thread before it is - * inserted in to a patch. Any non-realtime actions that need to be - * done before the Node is ready for use should be done here. - */ - virtual void activate() = 0; - virtual void deactivate() = 0; - virtual bool activated() = 0; - - virtual void run(size_t nframes) = 0; - - virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) = 0; - - // FIXME: Only used by client senders. Remove? - virtual const Array& ports() const = 0; - - virtual size_t num_ports() const = 0; - virtual size_t poly() const = 0; - - /** Used by the process order finding algorithm (ie during connections) */ - virtual bool traversed() const = 0; - virtual void traversed(bool b) = 0; - - /** Nodes that are connected to this Node's inputs. - * (This Node depends on them) - */ - virtual List* providers() = 0; - virtual void providers(List* l) = 0; - - /** Nodes are are connected to this Node's outputs. - * (They depend on this Node) - */ - virtual List* dependants() = 0; - virtual void dependants(List* l) = 0; - - /** The Patch this Node belongs to. */ - virtual Patch* parent_patch() const = 0; - - /** Information about what 'plugin' this Node is an instance of. - * Not the best name - not all nodes come from plugins (ie Patch) - */ - virtual const Plugin* plugin() const = 0; - virtual void plugin(const Plugin* const pi) = 0; - - /** Add self to a Patch. - * - * This function must be realtime-safe! Any non-realtime actions that - * need to be done before adding to a patch can be done in activate(). - */ - virtual void add_to_patch() = 0; - - virtual void remove_from_patch() = 0; - - /** Send any necessary notification to client on node creation. */ - //virtual void send_creation_messages(Shared::ClientInterface* client) const = 0; -}; - - -} // namespace Om - -#endif // NODE_H diff --git a/src/engine/NodeBase.cpp b/src/engine/NodeBase.cpp deleted file mode 100644 index b1628539..00000000 --- a/src/engine/NodeBase.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "NodeBase.h" -#include -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "util.h" -#include "Array.h" -#include "Plugin.h" -#include "ClientBroadcaster.h" -#include "Port.h" -#include "List.h" -#include "Patch.h" -#include "ObjectStore.h" - -using std::cout; using std::cerr; using std::endl; - -namespace Om { - - -NodeBase::NodeBase(const string& name, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: Node(parent, name), - m_poly(poly), - m_srate(srate), - m_buffer_size(buffer_size), - m_activated(false), - m_num_ports(0), - m_traversed(false), - m_providers(new List()), - m_dependants(new List()) -{ - assert(m_poly > 0); - assert(m_parent == NULL || (m_poly == parent->internal_poly() || m_poly == 1)); -} - - -NodeBase::~NodeBase() -{ - assert(!m_activated); - - delete m_providers; - delete m_dependants; - - for (size_t i=0; i < m_ports.size(); ++i) - delete m_ports.at(i); -} - - -void -NodeBase::activate() -{ - assert(!m_activated); - m_activated = true; -} - - -void -NodeBase::deactivate() -{ - assert(m_activated); - m_activated = false; -} - - -/* -void -NodeBase::send_creation_messages(ClientInterface* client) const -{ - cerr << "FIXME: send_creation\n"; - //om->client_broadcaster()->send_node_to(client, this); -} -*/ - -void -NodeBase::add_to_store() -{ - om->object_store()->add(this); - for (size_t i=0; i < num_ports(); ++i) - om->object_store()->add(m_ports.at(i)); -} - - -void -NodeBase::remove_from_store() -{ - // Remove self - TreeNode* node = om->object_store()->remove(path()); - if (node != NULL) { - assert(om->object_store()->find(path()) == NULL); - delete node; - } - - // Remove ports - for (size_t i=0; i < m_num_ports; ++i) { - node = om->object_store()->remove(m_ports.at(i)->path()); - if (node != NULL) { - assert(om->object_store()->find(m_ports.at(i)->path()) == NULL); - delete node; - } - } -} - - -/** Runs the Node for the specified number of frames (block size) - */ -void -NodeBase::run(size_t nframes) -{ - assert(m_activated); - // Mix down any ports with multiple inputs - Port* p; - for (size_t i=0; i < m_ports.size(); ++i) { - p = m_ports.at(i); - p->prepare_buffers(nframes); - } -} - - -/** Rename this Node. - * - * This is responsible for updating the ObjectStore so the Node can be - * found at it's new path, as well as all it's children. - */ -void -NodeBase::set_path(const Path& new_path) -{ - const Path old_path = path(); - //cerr << "Renaming " << old_path << " -> " << new_path << endl; - - TreeNode* treenode = NULL; - - // Reinsert ports - for (size_t i=0; i < m_num_ports; ++i) { - treenode = om->object_store()->remove(old_path +"/"+ m_ports.at(i)->name()); - assert(treenode != NULL); - assert(treenode->node() == m_ports.at(i)); - treenode->key(new_path +"/" + m_ports.at(i)->name()); - om->object_store()->add(treenode); - } - - // Rename and reinsert self - treenode = om->object_store()->remove(old_path); - assert(treenode != NULL); - assert(treenode->node() == this); - OmObject::set_path(new_path); - treenode->key(new_path); - om->object_store()->add(treenode); - - - assert(om->object_store()->find(new_path) == this); -} - - -} // namespace Om - diff --git a/src/engine/NodeBase.h b/src/engine/NodeBase.h deleted file mode 100644 index 796abbca..00000000 --- a/src/engine/NodeBase.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef NODEBASE_H -#define NODEBASE_H - -#include -#include -#include "Node.h" -using std::string; - -namespace Om { - -class Plugin; -class Patch; -namespace Shared { - class ClientInterface; -} using Shared::ClientInterface; - - -/** Common implementation stuff for Node. - * - * Pretty much just attributes and getters/setters are here. - * - * \ingroup engine - */ -class NodeBase : public Node -{ -public: - NodeBase(const string& name, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); - - virtual ~NodeBase(); - - virtual void activate(); - virtual void deactivate(); - bool activated() { return m_activated; } - - virtual void run(size_t nframes); - - virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) {} - - virtual void add_to_patch() {} - virtual void remove_from_patch() {} - - void add_to_store(); - void remove_from_store(); - - //void send_creation_messages(ClientInterface* client) const; - - size_t num_ports() const { return m_num_ports; } - size_t poly() const { return m_poly; } - bool traversed() const { return m_traversed; } - void traversed(bool b) { m_traversed = b; } - - const Array& ports() const { return m_ports; } - - virtual List* providers() { return m_providers; } - virtual void providers(List* l) { m_providers = l; } - - virtual List* dependants() { return m_dependants; } - virtual void dependants(List* l) { m_dependants = l; } - - Patch* parent_patch() const { return (m_parent == NULL) ? NULL : m_parent->as_patch(); } - - virtual const Plugin* plugin() const { exit(EXIT_FAILURE); } - virtual void plugin(const Plugin* const pi) { exit(EXIT_FAILURE); } - - void set_path(const Path& new_path); - -protected: - // Disallow copies (undefined) - NodeBase(const NodeBase&); - NodeBase& operator=(const NodeBase&); - - size_t m_poly; - - samplerate m_srate; - size_t m_buffer_size; - bool m_activated; - - size_t m_num_ports; // number of ports PER VOICE - Array m_ports; - - bool m_traversed; - List* m_providers; // Nodes connected to this one's input ports - List* m_dependants; // Nodes this one's output ports are connected to -}; - - -} // namespace Om - -#endif // NODEBASE_H diff --git a/src/engine/NodeFactory.cpp b/src/engine/NodeFactory.cpp deleted file mode 100644 index 176d3f47..00000000 --- a/src/engine/NodeFactory.cpp +++ /dev/null @@ -1,707 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "NodeFactory.h" -#include "config.h" -#include -#include -#include -#include -#include -#include -#include "AudioDriver.h" -#include "MidiNoteNode.h" -#include "MidiTriggerNode.h" -#include "MidiControlNode.h" -#include "AudioInputNode.h" -#include "AudioOutputNode.h" -#include "ControlInputNode.h" -#include "ControlOutputNode.h" -#include "MidiInputNode.h" -#include "MidiOutputNode.h" -#include "TransportNode.h" -#include "PluginLibrary.h" -#include "Plugin.h" -#include "Patch.h" -#include "Om.h" -#include "OmApp.h" -#ifdef HAVE_SLV2 -#include "LV2Plugin.h" -#include -#endif -#ifdef HAVE_LADSPA -#include "LADSPAPlugin.h" -#endif -#ifdef HAVE_DSSI -#include "DSSIPlugin.h" -#endif - -using std::string; -using std::cerr; using std::cout; using std::endl; - - -namespace Om { - - -/* I am perfectly aware that the vast majority of this class is a - * vomit inducing nightmare at the moment ;) - */ - - - -NodeFactory::NodeFactory() -: m_has_loaded(false) -{ - pthread_mutex_init(&m_plugin_list_mutex, NULL); - - // Add builtin plugin types to m_internal_plugins list - // FIXME: ewwww, definitely a better way to do this! - //Plugin* pi = NULL; - - Patch* parent = new Patch("dummy", 1, NULL, 1, 1, 1); - - Node* n = NULL; - n = new AudioInputNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new AudioOutputNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new ControlInputNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new ControlOutputNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new MidiInputNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new MidiOutputNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new MidiNoteNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new MidiTriggerNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new MidiControlNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - n = new TransportNode("foo", 1, parent, 1, 1); - m_internal_plugins.push_back(new Plugin(n->plugin())); - delete n; - - - delete parent; -} - - -NodeFactory::~NodeFactory() -{ - for (list::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) - delete (*i); - - for (list::iterator i = m_libraries.begin(); i != m_libraries.end(); ++i) { - (*i)->close(); - delete (*i); - } -} - - -void -NodeFactory::load_plugins() -{ - // Only load if we havn't already, so every client connecting doesn't cause - // this (expensive!) stuff to happen. Not the best solution - would be nice - // if clients could refresh plugins list for whatever reason :/ - if (!m_has_loaded) { - pthread_mutex_lock(&m_plugin_list_mutex); - - m_plugins.clear(); - m_plugins = m_internal_plugins; - -#if HAVE_SLV2 - load_lv2_plugins(); -#endif -#if HAVE_DSSI - load_dssi_plugins(); -#endif -#if HAVE_LADSPA - load_ladspa_plugins(); -#endif - - m_has_loaded = true; - - pthread_mutex_unlock(&m_plugin_list_mutex); - } -} - - -/** Loads a plugin. - * - * Calls the load_*_plugin functions to actually do things, just a wrapper. - */ -Node* -NodeFactory::load_plugin(const Plugin* a_plugin, const string& name, size_t poly, Patch* parent) -{ - assert(parent != NULL); - assert(poly == 1 || poly == parent->internal_poly()); - assert(a_plugin); - - pthread_mutex_lock(&m_plugin_list_mutex); - - Node* r = NULL; - Plugin* plugin = NULL; - - // Attempt to find the plugin in loaded DB - if (a_plugin->type() != Plugin::Internal) { - list::iterator i; - if (a_plugin->plug_label().length() == 0) { - for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { - if (a_plugin->uri() == (*i)->uri()) { - plugin = *i; - break; - } - } - } else { - for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { - if (a_plugin->uri() == (*i)->uri()) { - plugin = *i; - break; - } - } - } - - if (plugin == NULL) - return NULL; - } - - switch (a_plugin->type()) { -#if HAVE_SLV2 - case Plugin::LV2: - r = load_lv2_plugin(plugin->uri(), name, poly, parent); - break; -#endif -#if HAVE_DSSI - case Plugin::DSSI: - r = load_dssi_plugin(plugin->uri(), name, poly, parent); - break; -#endif -#if HAVE_LADSPA - case Plugin::LADSPA: - r = load_ladspa_plugin(plugin->uri(), name, poly, parent); - break; -#endif - case Plugin::Internal: - r = load_internal_plugin(a_plugin->uri(), name, poly, parent); - break; - default: - cerr << "[NodeFactory] WARNING: Unknown plugin type." << endl; - } - - pthread_mutex_unlock(&m_plugin_list_mutex); - - return r; -} - - -/** Loads an internal plugin. - */ -Node* -NodeFactory::load_internal_plugin(const string& uri, const string& name, size_t poly, Patch* parent) -{ - assert(parent != NULL); - assert(poly == 1 || poly == parent->internal_poly()); - assert(uri.length() > 3); - assert(uri.substr(0, 3) == "om:"); - - string plug_label = uri.substr(3); - - if (plug_label == "midi_input") { - MidiInputNode* tn = new MidiInputNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return tn; - } else if (plug_label == "midi_output") { - MidiOutputNode* tn = new MidiOutputNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return tn; - } else if (plug_label == "audio_input") { - AudioInputNode* in = new AudioInputNode(name, poly, parent, - om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return in; - } else if (plug_label == "control_input") { - ControlInputNode* in = new ControlInputNode(name, poly, parent, - om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return in; - } else if (plug_label == "audio_output") { - AudioOutputNode* on = new AudioOutputNode(name, poly, parent, - om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return on; - } else if (plug_label == "control_output") { - ControlOutputNode* on = new ControlOutputNode(name, poly, parent, - om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return on; - } else if (plug_label == "note_in" || plug_label == "midi_note_in") { - MidiNoteNode* mn = new MidiNoteNode(name, poly, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return mn; - } else if (plug_label == "trigger_in" || plug_label == "midi_trigger_in") { - MidiTriggerNode* mn = new MidiTriggerNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return mn; - } else if (plug_label == "midi_control_in") { - MidiControlNode* mn = new MidiControlNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return mn; - } else if (plug_label == "transport") { - TransportNode* tn = new TransportNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - return tn; - } else { - cerr << "Unknown internal plugin type '" << plug_label << "'" << endl; - } - - return NULL; -} - - -#ifdef HAVE_SLV2 - -/** Loads information about all LV2 plugins into internal plugin database. - */ -void -NodeFactory::load_lv2_plugins() -{ - SLV2List plugins = slv2_list_new(); - slv2_list_load_all(plugins); - - //cerr << "[NodeFactory] Found " << slv2_list_get_length(plugins) << " LV2 plugins." << endl; - - for (unsigned long i=0; i < slv2_list_get_length(plugins); ++i) { - - SLV2Plugin* lv2_plug = slv2_list_get_plugin_by_index(plugins, i); - - - //om_plug->library(plugin_library); - - const char* uri = (const char*)slv2_plugin_get_uri(lv2_plug); - //cerr << "LV2 plugin: " << uri << endl; - - bool found = false; - for (list::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) { - if (!strcmp((*i)->uri().c_str(), uri)) { - cerr << "Warning: Duplicate LV2 plugin (" << uri << ").\nUsing " - << (*i)->lib_path() << " version." << endl; - found = true; - break; - } - } - if (!found) { - //printf("[NodeFactory] Found LV2 plugin %s\n", uri); - Plugin* om_plug = new Plugin(); - om_plug->type(Plugin::LV2); - om_plug->slv2_plugin(lv2_plug); - om_plug->uri(uri); - // FIXME FIXME FIXME temporary hack - om_plug->library(NULL); - om_plug->lib_path("FIXMEpath"); - om_plug->plug_label("FIXMElabel"); - unsigned char* name = slv2_plugin_get_name(lv2_plug); - om_plug->name((char*)name); - free(name); - om_plug->type(Plugin::LV2); - m_plugins.push_back(om_plug); - } - } - - slv2_list_free(plugins); -} - - -/** Loads a LV2 plugin. - * Returns 'poly' independant plugins as a Node* - */ -Node* -NodeFactory::load_lv2_plugin(const string& plug_uri, - const string& node_name, - size_t poly, - Patch* parent) -{ - // Find (Om) Plugin - Plugin* plugin = NULL; - list::iterator i; - for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { - plugin = (*i); - if ((*i)->uri() == plug_uri) break; - } - - Node* n = NULL; - - if (plugin) { - n = new Om::LV2Plugin(node_name, poly, parent, plugin->slv2_plugin(), - om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - bool success = ((LV2Plugin*)n)->instantiate(); - if (!success) { - delete n; - n = NULL; - } - n->plugin(plugin); - } - - return n; -} - -#endif // HAVE_SLV2 - - -#if HAVE_DSSI - -/** Loads information about all DSSI plugins into internal plugin database. - */ -void -NodeFactory::load_dssi_plugins() -{ - // FIXME: too much code duplication with load_ladspa_plugin - - char* env_dssi_path = getenv("DSSI_PATH"); - string dssi_path; - if (!env_dssi_path) { - cerr << "[NodeFactory] DSSI_PATH is empty. Assuming /usr/lib/dssi:/usr/local/lib/dssi:~/.dssi" << endl; - dssi_path = string("/usr/lib/dssi:/usr/local/lib/dssi:").append( - getenv("HOME")).append("/.dssi"); - } else { - dssi_path = env_dssi_path; - } - - DSSI_Descriptor_Function df = NULL; - DSSI_Descriptor* descriptor = NULL; - - string dir; - string full_lib_name; - - // Yep, this should use an sstream alright.. - while (dssi_path != "") { - dir = dssi_path.substr(0, dssi_path.find(':')); - if (dssi_path.find(':') != string::npos) - dssi_path = dssi_path.substr(dssi_path.find(':')+1); - else - dssi_path = ""; - - DIR* pdir = opendir(dir.c_str()); - if (pdir == NULL) { - //cerr << "[NodeFactory] Unreadable directory in DSSI_PATH: " << dir.c_str() << endl; - continue; - } - - struct dirent* pfile; - while ((pfile = readdir(pdir))) { - - if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, "..")) - continue; - - full_lib_name = dir +"/"+ pfile->d_name; - - // Load descriptor function - // Loaded with LAZY here, will be loaded with NOW on node loading - void* handle = dlopen(full_lib_name.c_str(), RTLD_LAZY); - if (handle == NULL) - continue; - - df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor"); - if (df == NULL) { - // Not a DSSI plugin library - dlclose(handle); - continue; - } - - PluginLibrary* plugin_library = new PluginLibrary(full_lib_name); - m_libraries.push_back(plugin_library); - - const LADSPA_Descriptor* ld = NULL; - - for (unsigned long i=0; (descriptor = (DSSI_Descriptor*)df(i)) != NULL; ++i) { - ld = descriptor->LADSPA_Plugin; - assert(ld != NULL); - Plugin* plugin = new Plugin(); - assert(plugin_library != NULL); - plugin->library(plugin_library); - plugin->lib_path(dir + "/" + pfile->d_name); - plugin->plug_label(ld->Label); - plugin->name(ld->Name); - plugin->type(Plugin::DSSI); - plugin->id(ld->UniqueID); - - bool found = false; - for (list::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) { - if ((*i)->uri() == plugin->uri()) { - cerr << "Warning: Duplicate DSSI plugin (" << plugin->lib_name() << ":" - << plugin->plug_label() << ")" << " found.\nUsing " << (*i)->lib_path() - << " version." << endl; - found = true; - break; - } - } - if (!found) - m_plugins.push_back(plugin); - else - delete plugin; - } - - df = NULL; - descriptor = NULL; - dlclose(handle); - } - closedir(pdir); - } -} - - -/** Creates a Node by instancing a DSSI plugin. - */ -Node* -NodeFactory::load_dssi_plugin(const string& uri, - const string& name, size_t poly, Patch* parent) -{ - // FIXME: awful code duplication here - - assert(uri != ""); - assert(name != ""); - assert(poly > 0); - - DSSI_Descriptor_Function df = NULL; - const Plugin* plugin = NULL; - Node* n = NULL; - void* handle = NULL; - - // Attempt to find the lib - list::iterator i; - for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { - plugin = (*i); - if (plugin->uri() == uri) break; - } - - assert(plugin->id() != 0); - - if (i == m_plugins.end()) { - cerr << "Did not find DSSI plugin " << uri << " in database." << endl; - return NULL; - } else { - assert(plugin != NULL); - plugin->library()->open(); - handle = plugin->library()->handle(); - assert(handle != NULL); - - // Load descriptor function - dlerror(); - df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor"); - if (df == NULL || dlerror() != NULL) { - cerr << "Looks like this isn't a DSSI plugin." << endl; - return NULL; - } - } - - // Attempt to find the plugin in lib - DSSI_Descriptor* descriptor = NULL; - for (unsigned long i=0; (descriptor = (DSSI_Descriptor*)df(i)) != NULL; ++i) { - if (descriptor->LADSPA_Plugin != NULL - && descriptor->LADSPA_Plugin->UniqueID == plugin->id()) { - break; - } - } - - if (descriptor == NULL) { - cerr << "Could not find plugin \"" << plugin->id() << "\" in " << plugin->lib_name() << endl; - return NULL; - } - - n = new DSSIPlugin(name, poly, parent, descriptor, - om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - bool success = ((DSSIPlugin*)n)->instantiate(); - if (!success) { - delete n; - n = NULL; - } - - n->plugin(plugin); - - return n; -} -#endif // HAVE_DSSI - - -#ifdef HAVE_LADSPA -/** Loads information about all LADSPA plugins into internal plugin database. - */ -void -NodeFactory::load_ladspa_plugins() -{ - char* env_ladspa_path = getenv("LADSPA_PATH"); - string ladspa_path; - if (!env_ladspa_path) { - cerr << "[NodeFactory] LADSPA_PATH is empty. Assuming /usr/lib/ladspa:/usr/local/lib/ladspa:~/.ladspa" << endl; - ladspa_path = string("/usr/lib/ladspa:/usr/local/lib/ladspa:").append( - getenv("HOME")).append("/.ladspa"); - } else { - ladspa_path = env_ladspa_path; - } - - LADSPA_Descriptor_Function df = NULL; - LADSPA_Descriptor* descriptor = NULL; - - string dir; - string full_lib_name; - - // Yep, this should use an sstream alright.. - while (ladspa_path != "") { - dir = ladspa_path.substr(0, ladspa_path.find(':')); - if (ladspa_path.find(':') != string::npos) - ladspa_path = ladspa_path.substr(ladspa_path.find(':')+1); - else - ladspa_path = ""; - - DIR* pdir = opendir(dir.c_str()); - if (pdir == NULL) { - //cerr << "[NodeFactory] Unreadable directory in LADSPA_PATH: " << dir.c_str() << endl; - continue; - } - - struct dirent* pfile; - while ((pfile = readdir(pdir))) { - - if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, "..")) - continue; - - full_lib_name = dir +"/"+ pfile->d_name; - - // Load descriptor function - // Loaded with LAZY here, will be loaded with NOW on node loading - void* handle = dlopen(full_lib_name.c_str(), RTLD_LAZY); - if (handle == NULL) - continue; - - df = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor"); - if (df == NULL) { - dlclose(handle); - continue; - } - - PluginLibrary* plugin_library = new PluginLibrary(full_lib_name); - m_libraries.push_back(plugin_library); - - for (unsigned long i=0; (descriptor = (LADSPA_Descriptor*)df(i)) != NULL; ++i) { - Plugin* plugin = new Plugin(); - assert(plugin_library != NULL); - plugin->library(plugin_library); - plugin->lib_path(dir + "/" + pfile->d_name); - plugin->plug_label(descriptor->Label); - plugin->name(descriptor->Name); - plugin->type(Plugin::LADSPA); - plugin->id(descriptor->UniqueID); - - bool found = false; - for (list::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) { - if ((*i)->uri() == plugin->uri()) { - cerr << "Warning: Duplicate LADSPA plugin " << plugin->uri() - << " found.\nChoosing " << (*i)->lib_path() - << " over " << plugin->lib_path() << endl; - found = true; - break; - } - } - if (!found) - m_plugins.push_back(plugin); - else - delete plugin; - } - - df = NULL; - descriptor = NULL; - dlclose(handle); - } - closedir(pdir); - } -} - - -/** Loads a LADSPA plugin. - * Returns 'poly' independant plugins as a Node* - */ -Node* -NodeFactory::load_ladspa_plugin(const string& uri, - const string& name, size_t poly, Patch* parent) -{ - assert(uri != ""); - assert(name != ""); - assert(poly > 0); - - LADSPA_Descriptor_Function df = NULL; - Plugin* plugin = NULL; - Node* n = NULL; - void* plugin_lib = NULL; - - // Attempt to find the lib - list::iterator i; - for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { - plugin = (*i); - if (plugin->uri() == uri) break; - } - - assert(plugin->id() != 0); - - if (i == m_plugins.end()) { - cerr << "Did not find LADSPA plugin " << uri << " in database." << endl; - return NULL; - } else { - assert(plugin != NULL); - plugin->library()->open(); - plugin_lib = plugin->library()->handle(); - assert(plugin_lib != NULL); - - // Load descriptor function - dlerror(); - df = (LADSPA_Descriptor_Function)dlsym(plugin_lib, "ladspa_descriptor"); - if (df == NULL || dlerror() != NULL) { - cerr << "Looks like this isn't a LADSPA plugin." << endl; - return NULL; - } - } - - // Attempt to find the plugin in lib - LADSPA_Descriptor* descriptor = NULL; - for (unsigned long i=0; (descriptor = (LADSPA_Descriptor*)df(i)) != NULL; ++i) { - if (descriptor->UniqueID == plugin->id()) { - break; - } - } - - if (descriptor == NULL) { - cerr << "Could not find plugin \"" << plugin->id() << "\" in " << plugin->lib_path() << endl; - return NULL; - } - - n = new LADSPAPlugin(name, poly, parent, descriptor, - om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); - bool success = ((LADSPAPlugin*)n)->instantiate(); - if (!success) { - delete n; - n = NULL; - } - - n->plugin(plugin); - - return n; -} - - -#endif // HAVE_LADSPA - - -} // namespace Om diff --git a/src/engine/NodeFactory.h b/src/engine/NodeFactory.h deleted file mode 100644 index ed6a35dc..00000000 --- a/src/engine/NodeFactory.h +++ /dev/null @@ -1,93 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef NODEFACTORY_H -#define NODEFACTORY_H - -#include "config.h" -#include -#include -#include -#include - -using std::string; using std::list; - -namespace Om { - -class Node; -class PortInfo; -class Patch; -class PluginLibrary; -class Plugin; - - -/** Loads plugins and creates Nodes from them. - * - * NodeFactory's responsibility is to get enough information to allow the - * loading of a plugin possible (ie finding/opening shared libraries etc) - * - * The constructor of various Node types (ie LADSPAPlugin) are responsible - * for actually creating a Node instance of the plugin. - * - * \ingroup engine - */ -class NodeFactory -{ -public: - NodeFactory(); - ~NodeFactory(); - - void load_plugins(); - Node* load_plugin(const Plugin* info, const string& name, size_t poly, Patch* parent); - - const list& plugins() { return m_plugins; } - - void lock_plugin_list() { pthread_mutex_lock(&m_plugin_list_mutex); } - void unlock_plugin_list() { pthread_mutex_unlock(&m_plugin_list_mutex); } - -private: -#ifdef HAVE_LADSPA - void load_ladspa_plugins(); - Node* load_ladspa_plugin(const string& plugin_uri, const string& name, size_t poly, Patch* parent); -#endif - -#ifdef HAVE_SLV2 - void load_lv2_plugins(); - Node* load_lv2_plugin(const string& plugin_uri, const string& name, size_t poly, Patch* parent); -#endif - -#ifdef HAVE_DSSI - void load_dssi_plugins(); - Node* load_dssi_plugin(const string& plugin_uri, const string& name, size_t poly, Patch* parent); -#endif - - Node* load_internal_plugin(const string& plug_label, const string& name, size_t poly, Patch* parent); - - list m_libraries; - list m_internal_plugins; - list m_plugins; - - /** Used to protect the list while load_plugins is building it. */ - pthread_mutex_t m_plugin_list_mutex; - - bool m_has_loaded; -}; - - -} // namespace Om - -#endif // NODEFACTORY_H diff --git a/src/engine/OSCClient.cpp b/src/engine/OSCClient.cpp deleted file mode 100644 index 332a2144..00000000 --- a/src/engine/OSCClient.cpp +++ /dev/null @@ -1,503 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OSCClient.h" -#include -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "ObjectStore.h" -#include "NodeFactory.h" -#include "util.h" -#include "Patch.h" -#include "Node.h" -#include "PortInfo.h" -#include "Plugin.h" -#include "PortBase.h" -#include "Connection.h" -#include "AudioDriver.h" -#include "interface/ClientInterface.h" -#include "Responder.h" - -using std::cout; using std::cerr; using std::endl; - -namespace Om { - - -/*! \page client_osc_namespace Client OSC Namespace Documentation - * - *

These are all the messages sent from the engine to the client. Om - * communication takes place over two distinct bands: control band and - * notification band.

- *

The control band is where clients send commands, and receive a simple - * response, either OK or an error.

- *

All notifications of engine state (ie new nodes) are sent over the - * notification band which is seperate from the control band. The - * reasoning behind this is that many clients may be connected at the same - * time - a client may receive notifications that are not a direct consequence - * of some message it sent.

- *

The notification band can be thought of as a stream of events representing - * the changing engine state. For example, It is possible for a client to send - * commands and receive aknowledgements, and not listen to the notification band - * at all; or (in the near future anyway) for a client to use UDP for the control - * band (for speed), and TCP for the notification band (for reliability and - * order guarantees).

- * \n\n - */ - - -/* Documentation for namespace portion implemented in Responder.cpp */ - -/** \page client_osc_namespace - * \n - *

Notification Band

- */ - -/** \page client_osc_namespace - *

\b /om/response/ok - Respond successfully to a user command - * \arg \b responder-id (int) - Responder ID this is a response to - *

\n \n - */ - -/** \page client_osc_namespace - *

\b /om/response/error - Respond negatively to a user command - * \arg \b responder-id (int) - Request ID this is a response to - * \arg \b message (string) - Error message (natural language text) - *

\n \n - */ - - - -/** \page client_osc_namespace - * \n - *

Notification Band

- */ - -/** \page client_osc_namespace - *

\b /om/error - Notification that an error has occurred - * \arg \b message (string) - Error message (natural language text) - * - * \li This is for notification of errors that aren't a direct response to a - * user command, ie "unexpected" errors.

\n \n - */ -void -OSCClient::error(const string& msg) -{ - lo_send(_address, "/om/error", "s", msg.c_str()); -} - - -/** \page client_osc_namespace - *

\b /om/num_plugins - * \arg \b num (int) - Number of plugins engine has loaded - * \li This is sent before sending the list of plugins, so the client is aware - * of how many plugins (/om/plugin messages) to expect.

\n \n - */ - - -/** \page client_osc_namespace - *

\b /om/num_plugins - * \arg \b num (int) - Number of plugins engine has loaded - * \li This is sent before sending the list of plugins, so the client is aware - * of how many plugins (/om/plugin messages) to expect.

\n \n - */ -void -OSCClient::num_plugins(uint32_t num) -{ - lo_message m = lo_message_new(); - lo_message_add_int32(m, num); - lo_send_message(_address, "/om/num_plugins", m); -} - - -/** \page client_osc_namespace - *

\b /om/plugin - Notification of the existance of a plugin - * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal") - * \arg \b uri (string) - URI of the plugin (see engine namespace documentation) \n - * \arg \b lib-name (string) - Name of shared library plugin resides in (ie "cmt.so") - * \arg \b plug-label (string) - Label of the plugin (ie "dahdsr_iaoa") - * \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope") - *

\n \n - */ -/* -void -OSCClient::plugins() -{ - om->node_factory()->lock_plugin_list(); - - const list& plugs = om->node_factory()->plugins(); - const Plugin* plugin; - - lo_timetag tt; - lo_timetag_now(&tt); - lo_bundle b = lo_bundle_new(tt); - lo_message m = lo_message_new(); - list msgs; - - lo_message_add_int32(m, plugs.size()); - lo_bundle_add_message(b, "/om/num_plugins", m); - msgs.push_back(m); - - for (list::const_iterator j = plugs.begin(); j != plugs.end(); ++j) { - plugin = (*j); - m = lo_message_new(); - - lo_message_add_string(m, plugin->type_string()); - lo_message_add_string(m, plugin->uri().c_str()); - lo_message_add_string(m, plugin->plug_label().c_str()); - lo_message_add_string(m, plugin->name().c_str()); - lo_bundle_add_message(b, "/om/plugin", m); - msgs.push_back(m); - if (lo_bundle_length(b) > 1024) { - lo_send_bundle(_address, b); - lo_bundle_free(b); - b = lo_bundle_new(tt); - } - } - - if (lo_bundle_length(b) > 0) { - lo_send_bundle(_address, b); - lo_bundle_free(b); - } else { - lo_bundle_free(b); - } - for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i) - lo_message_free(*i); - - om->node_factory()->unlock_plugin_list(); -} -*/ - -/** \page client_osc_namespace - *

\b /om/new_node - Notification of a new node's creation. - * \arg \b plug-uri (string) - URI of the plugin new node is an instance of - * \arg \b path (string) - Path of the new node - * \arg \b polyphonic (integer-boolean) - Node is polyphonic (1 = yes, 0 = no) - * \arg \b num-ports (integer) - Number of ports (number of new_port messages to expect) - * \li New nodes are sent as a bundle. The first message in the bundle will be - * this one (/om/new_node), followed by a series of /om/new_port commands, - * followed by /om/new_node_end.

\n \n - */ -void OSCClient::new_node(const string& plugin_type, - const string& plugin_uri, - const string& node_path, - bool is_polyphonic, - uint32_t num_ports) -{ - lo_send(_address, "/om/new_node", "sssii", plugin_type.c_str(), plugin_uri.c_str(), - node_path.c_str(), is_polyphonic ? 1 : 0, num_ports); -#if 0 - /* - lo_timetag tt; - lo_timetag_now(&tt); - lo_bundle b = lo_bundle_new(tt); - lo_message m = lo_message_new(); - list msgs; - - lo_message_add_string(m, plugin_type.c_str()); - lo_message_add_string(m, plugin_uri.c_str()); - lo_message_add_string(m, node_path.c_str()); - lo_message_add_int32(m, is_polyphonic ? 1 : 0); - lo_message_add_int32(m, num_ports); - - lo_bundle_add_message(b, "/om/new_node", m); - msgs.push_back(m); -*/ - - - /* - const Array& ports = node->ports(); - Port* port; - PortInfo* info; - for (size_t j=0; j < ports.size(); ++j) { - port = ports.at(j); - info = port->port_info(); - - assert(port != NULL); - assert(info != NULL); - - m = lo_message_new(); - lo_message_add_string(m, port->path().c_str()); - lo_message_add_string(m, info->type_string().c_str()); - lo_message_add_string(m, info->direction_string().c_str()); - lo_message_add_string(m, info->hint_string().c_str()); - lo_message_add_float(m, info->default_val()); - lo_message_add_float(m, info->min_val()); - lo_message_add_float(m, info->max_val()); - lo_bundle_add_message(b, "/om/new_port", m); - msgs.push_back(m); - - // If the bundle is getting very large, send it and start - // a new one - if (lo_bundle_length(b) > 1024) { - lo_send_bundle(_address, b); - lo_bundle_free(b); - b = lo_bundle_new(tt); - } - } -*/ - /*m = lo_message_new(); - //lo_bundle_add_message(b, "/om/new_node_end", m); - //msgs.push_back(m); - - lo_send_bundle(_address, b); - lo_bundle_free(b); - - for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i) - lo_message_free(*i); - - usleep(100); -*/ - /* - const map& data = node->metadata(); - // Send node metadata - for (map::const_iterator i = data.begin(); i != data.end(); ++i) - metadata_update(node->path(), (*i).first, (*i).second); - - - // Send port metadata - for (size_t j=0; j < ports.size(); ++j) { - port = ports.at(j); - const map& data = port->metadata(); - for (map::const_iterator i = data.begin(); i != data.end(); ++i) - metadata_update(port->path(), (*i).first, (*i).second); - } - - // Send control values - for (size_t i=0; i < node->ports().size(); ++i) { - PortBase* port = (PortBase*)node->ports().at(i); - if (port->port_info()->is_input() && port->port_info()->is_control()) - control_change(port->path(), port->buffer(0)->value_at(0)); - } - */ -#endif -} - - - -/** \page client_osc_namespace - *

\b /om/new_port - Notification of a new port's creation. - * \arg \b path (string) - Path of new port - * \arg \b data-type (string) - Type of port (CONTROL or AUDIO) - * \arg \b direction ("is-output") (integer) - Direction of data flow (Input = 0, Output = 1) - * - * \li Note that in the event of loading a patch, this message could be - * followed immediately by a control change, meaning the default-value is - * not actually the current value of the port. - * \li The minimum and maximum values are suggestions only, they are not - * enforced in any way, and going outside them is perfectly fine. Also note - * that the port ranges in om_gtk are not these ones! Those ranges are set - * as metadata.

\n \n - */ -void -OSCClient::new_port(const string& path, - const string& data_type, - bool is_output) -{ - //PortInfo* info = port->port_info(); - - lo_send(_address, "/om/new_port", "ssi", path.c_str(), data_type.c_str(), is_output); - - // Send metadata - /*const map& data = port->metadata(); - for (map::const_iterator i = data.begin(); i != data.end(); ++i) - metadata_update(port->path(), (*i).first, (*i).second);*/ -} - - -/** \page client_osc_namespace - *

\b /om/destroyed - Notification an object has been destroyed - * \arg \b path (string) - Path of object (which no longer exists)

\n \n - */ -void -OSCClient::object_destroyed(const string& path) -{ - assert(path != "/"); - - lo_send(_address, "/om/destroyed", "s", path.c_str()); -} - - -/** \page client_osc_namespace - *

\b /om/patch_cleared - Notification a patch has been cleared (all children destroyed) - * \arg \b path (string) - Path of patch (which is now empty)

\n \n - */ -void -OSCClient::patch_cleared(const string& patch_path) -{ - lo_send(_address, "/om/patch_cleared", "s", patch_path.c_str()); -} - - -/** \page client_osc_namespace - *

\b /om/patch_enabled - Notification a patch's DSP processing has been enabled. - * \arg \b path (string) - Path of enabled patch

\n \n - */ -void -OSCClient::patch_enabled(const string& patch_path) -{ - lo_send(_address, "/om/patch_enabled", "s", patch_path.c_str()); -} - - -/** \page client_osc_namespace - *

\b /om/patch_disabled - Notification a patch's DSP processing has been disabled. - * \arg \b path (string) - Path of disabled patch

\n \n - */ -void -OSCClient::patch_disabled(const string& patch_path) -{ - lo_send(_address, "/om/patch_disabled", "s", patch_path.c_str()); -} - - -/** \page client_osc_namespace - *

\b /om/new_connection - Notification a new connection has been made. - * \arg \b src-path (string) - Path of the source port - * \arg \b dst-path (string) - Path of the destination port

\n \n - */ -void -OSCClient::connection(const string& src_port_path, const string& dst_port_path) -{ - lo_send(_address, "/om/new_connection", "ss", src_port_path.c_str(), dst_port_path.c_str()); -} - - -/** \page client_osc_namespace - *

\b /om/disconnection - Notification a connection has been unmade. - * \arg \b src-path (string) - Path of the source port - * \arg \b dst-path (string) - Path of the destination port

\n \n - */ -void -OSCClient::disconnection(const string& src_port_path, const string& dst_port_path) -{ - lo_send(_address, "/om/disconnection", "ss", src_port_path.c_str(), dst_port_path.c_str()); -} - - -/** \page client_osc_namespace - *

\b /om/metadata/update - Notification of a piece of metadata. - * \arg \b path (string) - Path of the object associated with metadata (can be a node, patch, or port) - * \arg \b key (string) - * \arg \b value (string)

\n \n - */ -void -OSCClient::metadata_update(const string& path, const string& key, const string& value) -{ - lo_send(_address, "/om/metadata/update", "sss", path.c_str(), key.c_str(), value.c_str()); -} - - -/** \page client_osc_namespace - *

\b /om/control_change - Notification the value of a port has changed - * \arg \b path (string) - Path of port - * \arg \b value (float) - New value of port - * - * \li This will only send updates for values set by clients of course - not values - * changing because of connections to other ports!

\n \n - */ -void -OSCClient::control_change(const string& port_path, float value) -{ - lo_send(_address, "/om/control_change", "sf", port_path.c_str(), value); -} - - -/** \page client_osc_namespace - *

\b /om/plugin - Notification of the existance of a plugin - * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")

\n \n - * \arg \b uri (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")

\n \n - * \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope") - */ -void -OSCClient::new_plugin(const string& type, const string& uri, const string& name) -{ - lo_message m = lo_message_new(); - lo_message_add_string(m, type.c_str()); - lo_message_add_string(m, uri.c_str()); - lo_message_add_string(m, name.c_str()); - lo_send_message(_address, "/om/plugin", m); -} - - -/** \page client_osc_namespace - *

\b /om/new_patch - Notification of a new patch - * \arg \b path (string) - Path of new patch - * \arg \b poly (int) - Polyphony of new patch (\em not a boolean like new_node)

\n \n - */ -void -OSCClient::new_patch(const string& path, uint32_t poly) -{ - lo_send(_address, "/om/new_patch", "si", path.c_str(), poly); - - /* - if (p->process()) - patch_enabled(p->path()); - - // Send metadata - const map& data = p->metadata(); - for (map::const_iterator i = data.begin(); i != data.end(); ++i) { - metadata_update(p->path(), (*i).first, (*i).second); - } - */ -} - - -/** \page client_osc_namespace - *

\b /om/object_renamed - Notification of an object's renaming - * \arg \b old-path (string) - Old path of object - * \arg \b new-path (string) - New path of object

\n \n - */ -void -OSCClient::object_renamed(const string& old_path, const string& new_path) -{ - lo_send(_address, "/om/object_renamed", "ss", old_path.c_str(), new_path.c_str()); -} - - -/** Sends all OmObjects known to the engine. - */ -/* -void -OSCClient::all_objects() -{ - for (Tree::iterator i = om->object_store()->objects().begin(); - i != om->object_store()->objects().end(); ++i) - if ((*i)->as_node() != NULL && (*i)->parent() == NULL) - (*i)->as_node()->send_creation_messages(this); -} -*/ - -/** Sends information about a program associated with a DSSI plugin node. - */ -void -OSCClient::program_add(const string& node_path, uint32_t bank, uint32_t program, const string& name) -{ - lo_send(_address, "/om/program_add", "siis", - node_path.c_str(), bank, program, name.c_str()); -} - - -void -OSCClient::program_remove(const string& node_path, uint32_t bank, uint32_t program) -{ - lo_send(_address, "/om/program_remove", "sii", - node_path.c_str(), bank, program); -} - - -} // namespace Om diff --git a/src/engine/OSCClient.h b/src/engine/OSCClient.h deleted file mode 100644 index db14c696..00000000 --- a/src/engine/OSCClient.h +++ /dev/null @@ -1,131 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OSCCLIENT_H -#define OSCCLIENT_H - -#include -#include -#include -#include -#include -#include "util/types.h" -#include "interface/ClientInterface.h" - -using std::list; using std::string; -using std::cerr; - -namespace Om { - - -/** Implements ClientInterface for OSC clients (sends OSC messages). - * - * \ingroup engine - */ -class OSCClient : public Shared::ClientInterface -{ -public: - OSCClient(const string& url) - : _url(url), - _address(lo_address_new_from_url(url.c_str())) - {} - - virtual ~OSCClient() - { lo_address_free(_address); } - - const string& url() const { return _url; } - const lo_address address() const { return _address; } - - //void plugins(); // FIXME remove - - - - /* *** ClientInterface Implementation Below *** */ - - - //void client_registration(const string& url, int client_id); - - // need a liblo feature to make this possible :/ - void bundle_begin() {} - void bundle_end() {} - - void num_plugins(uint32_t num); - - void error(const string& msg); - - virtual void new_plugin(const string& type, - const string& uri, - const string& name); - - virtual void new_patch(const string& path, uint32_t poly); - - virtual void new_node(const string& plugin_type, - const string& plugin_uri, - const string& node_path, - bool is_polyphonic, - uint32_t num_ports); - - virtual void new_port(const string& path, - const string& data_type, - bool is_output); - - virtual void patch_enabled(const string& path); - - virtual void patch_disabled(const string& path); - - virtual void patch_cleared(const string& path); - - virtual void object_destroyed(const string& path); - - virtual void object_renamed(const string& old_path, - const string& new_path); - - virtual void connection(const string& src_port_path, - const string& dst_port_path); - - virtual void disconnection(const string& src_port_path, - const string& dst_port_path); - - virtual void metadata_update(const string& subject_path, - const string& predicate, - const string& value); - - virtual void control_change(const string& port_path, - float value); - - virtual void program_add(const string& node_path, - uint32_t bank, - uint32_t program, - const string& program_name); - - virtual void program_remove(const string& node_path, - uint32_t bank, - uint32_t program); - -private: - // Prevent copies (undefined) - OSCClient(const OSCClient&); - OSCClient& operator=(const OSCClient&); - - string _url; - lo_address _address; -}; - - -} // namespace Om - -#endif // OSCCLIENT_H - diff --git a/src/engine/OSCReceiver.cpp b/src/engine/OSCReceiver.cpp deleted file mode 100644 index 8edab8b1..00000000 --- a/src/engine/OSCReceiver.cpp +++ /dev/null @@ -1,926 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OSCReceiver.h" -#include -#include -#include -#include -#include "util/types.h" -#include "Om.h" -#include "OmApp.h" -#include "util/Queue.h" -#include "util/CountedPtr.h" -#include "QueuedEventSource.h" -#include "interface/ClientKey.h" -#include "interface/ClientInterface.h" -#include "OSCClient.h" -#include "OSCResponder.h" -#include "ClientBroadcaster.h" -#include "Plugin.h" - -using std::cerr; using std::cout; using std::endl; - -namespace Om { - -using Shared::ClientKey; - - -/*! \page engine_osc_namespace Engine OSC Namespace Documentation - * - *

These are the commands the engine recognizes. A client can control every - * aspect of the engine entirely with these commands.

- * - *

All commands on this page are in the "control band". If a client needs to - * know about the state of the engine, it must listen to the "notification band". - * See the "Client OSC Namespace Documentation" for details. - */ - - -OSCReceiver::OSCReceiver(size_t queue_size, const char* const port) -: QueuedEngineInterface(queue_size), - _port(port), - _is_activated(false), - _st(NULL), - _osc_responder(NULL) -{ - _st = lo_server_thread_new(port, error_cb); - - if (_st == NULL) { - cerr << "[OSC] Could not start OSC server. Aborting." << endl; - exit(EXIT_FAILURE); - } else { - char* lo_url = lo_server_thread_get_url(_st); - cout << "[OSC] Started OSC server at " << lo_url << endl; - free(lo_url); - } - - // For debugging, print all incoming OSC messages - lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL); - - // Set response address for this message. - // It's important this is first and returns nonzero. - lo_server_thread_add_method(_st, NULL, NULL, set_response_address_cb, this); - - // Commands - lo_server_thread_add_method(_st, "/om/ping", "i", ping_cb, this); - lo_server_thread_add_method(_st, "/om/ping_slow", "i", ping_slow_cb, this); - lo_server_thread_add_method(_st, "/om/engine/quit", "i", quit_cb, this); - //lo_server_thread_add_method(_st, "/om/engine/register_client", "is", register_client_cb, this); - lo_server_thread_add_method(_st, "/om/engine/register_client", "i", register_client_cb, this); - lo_server_thread_add_method(_st, "/om/engine/unregister_client", "i", unregister_client_cb, this); - lo_server_thread_add_method(_st, "/om/engine/load_plugins", "i", load_plugins_cb, this); - lo_server_thread_add_method(_st, "/om/engine/activate", "i", engine_activate_cb, this); - lo_server_thread_add_method(_st, "/om/engine/deactivate", "i", engine_deactivate_cb, this); - lo_server_thread_add_method(_st, "/om/synth/create_patch", "isi", create_patch_cb, this); - lo_server_thread_add_method(_st, "/om/synth/enable_patch", "is", enable_patch_cb, this); - lo_server_thread_add_method(_st, "/om/synth/disable_patch", "is", disable_patch_cb, this); - lo_server_thread_add_method(_st, "/om/synth/clear_patch", "is", clear_patch_cb, this); - lo_server_thread_add_method(_st, "/om/synth/create_node", "issssi", create_node_cb, this); - lo_server_thread_add_method(_st, "/om/synth/create_node", "isssi", create_node_by_uri_cb, this); - lo_server_thread_add_method(_st, "/om/synth/destroy", "is", destroy_cb, this); - lo_server_thread_add_method(_st, "/om/synth/rename", "iss", rename_cb, this); - lo_server_thread_add_method(_st, "/om/synth/connect", "iss", connect_cb, this); - lo_server_thread_add_method(_st, "/om/synth/disconnect", "iss", disconnect_cb, this); - lo_server_thread_add_method(_st, "/om/synth/disconnect_all", "is", disconnect_all_cb, this); - lo_server_thread_add_method(_st, "/om/synth/set_port_value", "isf", set_port_value_cb, this); - lo_server_thread_add_method(_st, "/om/synth/set_port_value", "isif", set_port_value_voice_cb, this); - lo_server_thread_add_method(_st, "/om/synth/set_port_value_slow", "isf", set_port_value_slow_cb, this); - lo_server_thread_add_method(_st, "/om/synth/note_on", "isii", note_on_cb, this); - lo_server_thread_add_method(_st, "/om/synth/note_off", "isi", note_off_cb, this); - lo_server_thread_add_method(_st, "/om/synth/all_notes_off", "isi", all_notes_off_cb, this); - lo_server_thread_add_method(_st, "/om/synth/midi_learn", "is", midi_learn_cb, this); -#ifdef HAVE_LASH - lo_server_thread_add_method(_st, "/om/lash/restore_finished", "i", lash_restore_done_cb, this); -#endif - - lo_server_thread_add_method(_st, "/om/metadata/request", "isss", metadata_get_cb, this); - lo_server_thread_add_method(_st, "/om/metadata/set", "isss", metadata_set_cb, this); - - // Queries - lo_server_thread_add_method(_st, "/om/request/plugins", "i", request_plugins_cb, this); - lo_server_thread_add_method(_st, "/om/request/all_objects", "i", request_all_objects_cb, this); - lo_server_thread_add_method(_st, "/om/request/port_value", "is", request_port_value_cb, this); - - // DSSI support -#ifdef HAVE_DSSI - // XXX WARNING: notice this is a catch-all - lo_server_thread_add_method(_st, NULL, NULL, dssi_cb, this); -#endif - - lo_server_thread_add_method(_st, NULL, NULL, unknown_cb, NULL); -} - - -OSCReceiver::~OSCReceiver() -{ - deactivate(); - - if (_st != NULL) { - lo_server_thread_free(_st); - _st = NULL; - } -} - - -void -OSCReceiver::start() -{ - QueuedEventSource::start(); - - if (!_is_activated) { - lo_server_thread_start(_st); - _is_activated = true; - } - - /* Waiting on the next liblo release - pthread_t lo_thread = lo_server_thread_get_thread(_st); - - sched_param sp; - sp.sched_priority = 20; - int result = pthread_setschedparam(lo_thread, SCHED_FIFO, &sp); - if (!result) - cout << "[OSC] Set OSC thread to realtime scheduling (SCHED_FIFO, priority " - << sp.sched_priority << ")" << endl; - else - cout << "[OSC] Unable to set OSC thread to realtime scheduling (" - << strerror(result) << endl; - */ -} - - -void -OSCReceiver::stop() -{ - if (_is_activated) { - lo_server_thread_stop(_st); - cout << "[OSCReceiver] Stopped OSC server thread" << endl; - _is_activated = false; - } - QueuedEventSource::stop(); -} - - -/** Create a new responder for this message, if necessary. - * - * This is based on the fact that the current responder is stored in a ref - * counted pointer, and events just take a reference to that. Thus, events - * may delete their responder if we've since switched to a new one, or the - * same one can stay around and serve a series of events. Reference counting - * is pretty sweet, eh? - * - * If this message came from the same source as the last message, no allocation - * of responders or lo_addresses or any of it needs to be done. Unfortunately - * the only way to check is by comparing URLs, because liblo addresses suck. - * - * Really, this entire thing is a basically just a crafty way of partially - * working around the fact that liblo addresses really suck. Oh well. - */ -int -OSCReceiver::set_response_address_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data) -{ - OSCReceiver* const me = reinterpret_cast(user_data); - - //cerr << "SET RESPONSE\n"; - - if (argc < 1 || types[0] != 'i') // Not a valid Om message - return 0; // Save liblo the trouble - - //cerr << "** valid msg\n"; - - const int id = argv[0]->i; - - // Need to respond - if (id != -1) { - const lo_address addr = lo_message_get_source(msg); - char* const url = lo_address_get_url(addr); - - //cerr << "** need to respond\n"; - - // Currently have an OSC responder, check if it's still okay - if (me->_responder == me->_osc_responder) { - //cerr << "** osc responder\n"; - - if (!strcmp(url, me->_osc_responder->url())) { - // Nice one, same address - //cerr << "** Using cached response address, hooray" << endl; - } else { - // Shitty deal, make a new one - //cerr << "** Setting response address to " << url << "(2)" << endl; - me->_osc_responder = CountedPtr(new OSCResponder(id, url)); - me->set_responder(me->_osc_responder); - // (responder takes ownership of url, no leak) - } - - // Otherwise we have a NULL responder, definitely need to set a new one - } else { - //cerr << "** null responder\n"; - me->_osc_responder = CountedPtr(new OSCResponder(id, url)); - me->set_responder(me->_osc_responder); - //cerr << "** Setting response address to " << url << "(2)" << endl; - } - - // Don't respond - } else { - me->disable_responses(); - //cerr << "** Not responding." << endl; - } - - // If this returns 0 no OSC commands will work - return 1; -} - - -void -OSCReceiver::error_cb(int num, const char* msg, const char* path) -{ - cerr << "liblo server error " << num << " in path \"" << "\" - " << msg << endl; -} - - -/** \page engine_osc_namespace - *

\b /om/ping - Immediately sends a successful response to the given response id. - * \arg \b response-id (integer)

\n \n - */ -int -OSCReceiver::m_ping_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - _responder->respond_ok(); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/ping_slow - Sends response after going through the ("slow") event queue. - * \arg \b response-id (integer) - * - * \li See the documentation for /om/synth/set_port_value_slow for an explanation of how - * this differs from /om/ping. This is useful to send after sending a large cluster of - * events as a sentinel and wait on it's response, to know when the events are all - * finished processing.

\n \n - */ -int -OSCReceiver::m_ping_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - ping(); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/engine/quit - Terminates the engine. - * \arg \b response-id (integer) - * - * \li Note that there is NO order guarantees with this command at all. You could - * send 10 messages then quit, and the quit reply could come immediately and the - * 10 messages would never get executed.

\n \n - */ -int -OSCReceiver::m_quit_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - - quit(); - - return 0; -} - -/** \page engine_osc_namespace - *

\b /om/engine/register_client - Registers a new client with the engine - * \arg \b response-id (integer) - * - * The incoming address will be used for the new registered client. If you - * want to register a different specific address, use the URL version. - */ -int -OSCReceiver::m_register_client_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - lo_address addr = lo_message_get_source(msg); - - char* const url = lo_address_get_url(addr); - CountedPtr client(new OSCClient((const char*)url)); - register_client(ClientKey(ClientKey::OSC_URL, (const char*)url), client); - free(url); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/engine/unregister_client - Unregisters a client - * \arg \b response-id (integer)

\n \n - */ -int -OSCReceiver::m_unregister_client_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - lo_address addr = lo_message_get_source(msg); - - char* url = lo_address_get_url(addr); - unregister_client(ClientKey(ClientKey::OSC_URL, url)); - free(url); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/engine/load_plugins - Locates all available plugins, making them available for use. - * \arg \b response-id (integer)

\n \n - */ -int -OSCReceiver::m_load_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - load_plugins(); - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/engine/activate - Activate the engine (MIDI, audio, everything) - * \arg \b response-id (integer)

- * - * \li Note that you must send this message first if you want the engine to do - * anything at all - including respond to your messages! \n \n - */ -int -OSCReceiver::m_engine_activate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - activate(); - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/engine/deactivate - Deactivate the engine completely. - * \arg \b response-id (integer)

\n \n - */ -int -OSCReceiver::m_engine_deactivate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - deactivate(); - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/create_patch - Creates a new, empty, toplevel patch. - * \arg \b response-id (integer) - * \arg \b patch-path (string) - Patch path (complete, ie /master/parent/new_patch) - * \arg \b poly (integer) - Patch's (internal) polyphony

\n \n - */ -int -OSCReceiver::m_create_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* patch_path = &argv[1]->s; - const int poly = argv[2]->i; - - create_patch(patch_path, poly); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/rename - Rename an Object (only Nodes, for now) - * \arg \b response-id (integer) - * \arg \b path - Object's path - * \arg \b name - New name for object

\n \n - */ -int -OSCReceiver::m_rename_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* object_path = &argv[1]->s; - const char* name = &argv[2]->s; - - rename(object_path, name); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/enable_patch - Enable DSP processing of a patch - * \arg \b response-id (integer) - * \arg \b patch-path - Patch's path - */ -int -OSCReceiver::m_enable_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* patch_path = &argv[1]->s; - - enable_patch(patch_path); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/disable_patch - Disable DSP processing of a patch - * \arg \b response-id (integer) - * \arg \b patch-path - Patch's path - */ -int -OSCReceiver::m_disable_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* patch_path = &argv[1]->s; - - disable_patch(patch_path); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/clear_patch - Remove all nodes from a patch - * \arg \b response-id (integer) - * \arg \b patch-path - Patch's path - */ -int -OSCReceiver::m_clear_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* patch_path = &argv[1]->s; - - clear_patch(patch_path); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/create_node - Add a node into a given patch (load a plugin by URI) - * \arg \b response-id (integer) - * \arg \b node-path (string) - Full path of the new node (ie. /patch2/subpatch/newnode) - * \arg \b type (string) - Plugin type ("Internal", "LV2", "DSSI", "LADSPA") - * \arg \b plug-uri (string) - URI of the plugin to load - * \arg \b poly (integer-boolean) - Whether node is polyphonic (0 = false, 1 = true)

\n \n - */ -int -OSCReceiver::m_create_node_by_uri_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* node_path = &argv[1]->s; - const char* type = &argv[2]->s; - const char* plug_uri = &argv[3]->s; - const int poly = argv[4]->i; - - // FIXME: make sure poly is valid - - create_node(node_path, type, plug_uri, (poly == 1)); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/create_node - Add a node into a given patch (load a plugin by libname, label) - * \arg \b response-id (integer) - * \arg \b node-path (string) - Full path of the new node (ie. /patch2/subpatch/newnode) - * \arg \b type (string) - Plugin type ("LADSPA" or "Internal") - * \arg \b lib-name (string) - Name of library where plugin resides (eg "cmt.so") - * \arg \b plug-label (string) - Label (ID) of plugin (eg "sine_fcaa") - * \arg \b poly (integer-boolean) - Whether node is polyphonic (0 = false, 1 = true) - * - * \li This is only here to provide backwards compatibility for old patches that store plugin - * references (particularly LADSPA) as libname, label. - *

\n \n - */ -int -OSCReceiver::m_create_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - /* - - const char* node_path = &argv[1]->s; - const char* type = &argv[2]->s; - const char* lib_name = &argv[3]->s; - const char* plug_label = &argv[4]->s; - const int poly = argv[5]->i; - */ - cerr << "LOAD NODE BY LIB LABEL\n"; - return 0; - #if 0 - // FIXME Event-ize - - Plugin* plugin = new Plugin(); - plugin->set_type(type); - plugin->lib_name(lib_name); - plugin->plug_label(plug_label); - - if (poly != 0 && poly != 1) { - OSCResponder(addr).respond_error("Invalid poly parameter in create_node"); - return 0; - } - - add_node(node_path, plugin, (poly == 1)); - - return 0; - #endif -} - - -/** \page engine_osc_namespace - *

\b /om/synth/destroy - Removes (destroys) a Patch or a Node - * \arg \b response-id (integer) - * \arg \b node-path (string) - Full path of the object

\n \n - */ -int -OSCReceiver::m_destroy_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* node_path = &argv[1]->s; - - destroy(node_path); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/connect - Connects two ports (must be in the same patch) - * \arg \b response-id (integer) - * \arg \b src-port-path (string) - Full path of source port - * \arg \b dst-port-path (string) - Full path of destination port

\n \n - */ -int -OSCReceiver::m_connect_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* src_port_path = &argv[1]->s; - const char* dst_port_path = &argv[2]->s; - - connect(src_port_path, dst_port_path); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/disconnect - Disconnects two ports. - * \arg \b response-id (integer) - * \arg \b src-port-path (string) - Full path of source port - * \arg \b dst-port-path (string) - Full path of destination port

\n \n - */ -int -OSCReceiver::m_disconnect_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* src_port_path = &argv[1]->s; - const char* dst_port_path = &argv[2]->s; - - disconnect(src_port_path, dst_port_path); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/disconnect_all - Disconnect all connections to/from a node. - * \arg \b response-id (integer) - * \arg \b node-path (string) - Full path of node.

\n \n - */ -int -OSCReceiver::m_disconnect_all_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* node_path = &argv[1]->s; - - disconnect_all(node_path); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/set_port_value - Sets the value of a port for all voices (both AR and CR) - * \arg \b response-id (integer) - * \arg \b port-path (string) - Name of port - * \arg \b value (float) - Value to set port to - */ -int -OSCReceiver::m_set_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* port_path = &argv[1]->s; - const float value = argv[2]->f; - - set_port_value(port_path, value); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/set_port_value - Sets the value of a port for a specific voice (both AR and CR) - * \arg \b response-id (integer) - * \arg \b port-path (string) - Name of port - * \arg \b voice (integer) - Voice to set port value for - * \arg \b value (float) - Value to set port to - */ -int -OSCReceiver::m_set_port_value_voice_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* port_path = &argv[1]->s; - const int voice = argv[2]->i; - const float value = argv[3]->f; - - set_port_value(port_path, voice, value); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/set_port_value_slow - Sets the value of a port for all voices (as a QueuedEvent) - * \arg \b response-id (integer) - * \arg \b port-path (string) - Name of port - * \arg \b value (float) - Value to set port to - * - * \li This version exists so you can send it immediately after a QueuedEvent it may depend on (ie a - * node creation) and be sure it happens after the event (a normal set_port_value could beat the - * slow event and arrive out of order).

\n \n - */ -int -OSCReceiver::m_set_port_value_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* port_path = &argv[1]->s; - const float value = argv[2]->f; - - set_port_value_queued(port_path, value); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/note_on - Triggers a note-on, just as if it came from MIDI - * \arg \b response-id (integer) - * \arg \b node-path (string) - Patch of Node to trigger (must be a trigger or note node) - * \arg \b note-num (int) - MIDI style note number (0-127) - * \arg \b velocity (int) - MIDI style velocity (0-127)

\n \n - */ -int -OSCReceiver::m_note_on_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - /* - - const char* node_path = &argv[1]->s; - const uchar note_num = argv[2]->i; - const uchar velocity = argv[3]->i; - */ - cerr << "FIXME: OSC note on\n"; - //note_on(node_path, note_num, velocity); - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/note_off - Triggers a note-off, just as if it came from MIDI - * \arg \b response-id (integer) - * \arg \b node-path (string) - Patch of Node to trigger (must be a trigger or note node) - * \arg \b note-num (int) - MIDI style note number (0-127)

\n \n - */ -int -OSCReceiver::m_note_off_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - /* - - const char* patch_path = &argv[1]->s; - const uchar note_num = argv[2]->i; - */ - cerr << "FIXME: OSC note off\n"; - //note_off(patch_path, note_num); - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/all_notes_off - Triggers a note-off for all voices, just as if it came from MIDI - * \arg \b response-id (integer) - * \arg \b patch-path (string) - Patch of patch to send event to

\n \n - */ -int -OSCReceiver::m_all_notes_off_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - /* - - const char* patch_path = &argv[1]->s; - */ - cerr << "FIXME: OSC all notes off\n"; - //all_notes_off(patch_path); - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/synth/midi_learn - Initiate MIDI learn for a given (MIDI Control) Node - * \arg \b response-id (integer) - * \arg \b node-path (string) - Patch of the Node that should learn the next MIDI event. - * - * \li This of course will only do anything for MIDI control nodes. The node will learn the next MIDI - * event that arrives at it's MIDI input port - no behind the scenes voodoo happens here. It is planned - * that a plugin specification supporting arbitrary OSC commands for plugins will exist one day, and this - * method will go away completely.

\n \n - */ -int -OSCReceiver::m_midi_learn_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* patch_path = &argv[1]->s; - - midi_learn(patch_path); - - return 0; -} - - -#ifdef HAVE_LASH -/** \page engine_osc_namespace - *

\b /om/lash/restore_done - Notify LASH restoring is finished and connections can be made. - * \arg \b response-id (integer) - */ -int -OSCReceiver::m_lash_restore_done_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - lash_retore_done(); - - return 0; -} -#endif // HAVE_LASH - - -/** \page engine_osc_namespace - *

\b /om/metadata/set - Sets a piece of metadata, associated with a synth-space object (node, etc) - * \arg \b response-id (integer) - * \arg \b object-path (string) - Full path of object to associate metadata with - * \arg \b key (string) - Key (index) for new piece of metadata - * \arg \b value (string) - Value of new piece of metadata - */ -int -OSCReceiver::m_metadata_set_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* node_path = &argv[1]->s; - const char* key = &argv[2]->s; - const char* value = &argv[3]->s; - - set_metadata(node_path, key, value); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/metadata/responder - Requests the engine send a piece of metadata, associated with a synth-space object (node, etc) - * \arg \b response-id (integer) - * \arg \b object-path (string) - Full path of object metadata is associated with - * \arg \b key (string) - Key (index) for piece of metadata - * - * \li Reply will be sent to client registered with the source address of this message.

\n \n - */ -int -OSCReceiver::m_metadata_get_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - /* - const char* node_path = &argv[1]->s; - const char* key = &argv[2]->s; - */ - cerr << "FIXME: OSC metadata request\n"; - // FIXME: Equivalent? - /* - RequestMetadataEvent* ev = new RequestMetadataEvent( - new OSCResponder(ClientKey(addr)), - node_path, key); - - */ - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/responder/plugins - Requests the engine send a list of all known plugins. - * \arg \b response-id (integer) - * - * \li Reply will be sent to client registered with the source address of this message.

\n \n - */ -int -OSCReceiver::m_request_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - cerr << "REQUEST PLUGINS\n"; - - // FIXME - request_plugins(); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/responder/all_objects - Requests the engine send information about \em all objects (patches, nodes, etc) - * \arg \b response-id (integer) - * - * \li Reply will be sent to client registered with the source address of this message.

\n \n - */ -int -OSCReceiver::m_request_all_objects_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - request_all_objects(); - - return 0; -} - - -/** \page engine_osc_namespace - *

\b /om/responder/port_value - Requests the engine send the value of a port. - * \arg \b response-id (integer) - * \arg \b port-path (string) - Full path of port to send the value of

\n \n - * - * \li Reply will be sent to client registered with the source address of this message.

\n \n - */ -int -OSCReceiver::m_request_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* port_path = &argv[1]->s; - - request_port_value(port_path); - - return 0; -} - - -#ifdef HAVE_DSSI -int -OSCReceiver::m_dssi_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ -#if 0 - string node_path(path); - - if (node_path.substr(0, 5) != "/dssi") - return 1; - - string command = node_path.substr(node_path.find_last_of("/")+1); - node_path = node_path.substr(5); // chop off leading "/dssi/" - node_path = node_path.substr(0, node_path.find_last_of("/")); // chop off command at end - - //cout << "DSSI: Got message " << command << " for node " << node_path << endl; - - QueuedEvent* ev = NULL; - - if (command == "update" && !strcmp(types, "s")) - ev = new DSSIUpdateEvent(NULL, node_path, &argv[0]->s); - else if (command == "control" && !strcmp(types, "if")) - ev = new DSSIControlEvent(NULL, node_path, argv[0]->i, argv[1]->f); - else if (command == "configure" && ~strcmp(types, "ss")) - ev = new DSSIConfigureEvent(NULL, node_path, &argv[0]->s, &argv[1]->s); - else if (command == "program" && ~strcmp(types, "ii")) - ev = new DSSIProgramEvent(NULL, node_path, argv[0]->i, argv[1]->i); - - if (ev != NULL) - push(ev); - else - cerr << "[OSCReceiver] Unknown DSSI command received: " << path << endl; -#endif - return 0; -} -#endif - - -// Static Callbacks // - - -// Display incoming OSC messages (for debugging purposes) -int -OSCReceiver::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data) -{ - printf("[OSCMsg] %s\n", path); - - for (int i=0; i < argc; ++i) { - printf(" '%c' ", types[i]); - lo_arg_pp(lo_type(types[i]), argv[i]); - printf("\n"); - } - printf("\n"); - - return 1; // not handled -} - - -int -OSCReceiver::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data) -{ - cerr << "Unknown command " << path << " (" << types << "), sending error.\n"; - - string error_msg = "Unknown command: "; - error_msg.append(path).append(" ").append(types); - - om->client_broadcaster()->send_error(error_msg); - - return 0; -} - - -} // namespace Om diff --git a/src/engine/OSCReceiver.h b/src/engine/OSCReceiver.h deleted file mode 100644 index b80c25c3..00000000 --- a/src/engine/OSCReceiver.h +++ /dev/null @@ -1,124 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OSCRECEIVER_H -#define OSCRECEIVER_H - -#include "config.h" -#include -#include -#include "QueuedEngineInterface.h" -#include "OSCResponder.h" -using std::string; - -namespace Om { - -class JackDriver; -class NodeFactory; -class Patch; - - -/* Some boilerplate killing macros... */ -#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg - -/* Defines a static handler to be passed to lo_add_method, which is a trivial - * wrapper around a non-static method that does the real work. Makes a whoole - * lot of ugly boiler plate go away */ -#define LO_HANDLER(name) \ -int m_##name##_cb (LO_HANDLER_ARGS);\ -inline static int name##_cb(LO_HANDLER_ARGS, void* osc_receiver)\ -{ return ((OSCReceiver*)osc_receiver)->m_##name##_cb(path, types, argv, argc, msg); } - - - -/** Receives OSC messages from liblo. - * - * This inherits from QueuedEngineInterface and calls it's own functions - * via OSC. It's not actually a directly callable EngineInterface (it's - * callable via OSC...) so it is-implemented-as-a (privately inherits) - * QueuedEngineInterface. - * - * \ingroup engine - */ -class OSCReceiver : private QueuedEngineInterface -{ -public: - OSCReceiver(size_t queue_size, const char* const port); - ~OSCReceiver(); - - void start(); - void stop(); - -private: - // Prevent copies (undefined) - OSCReceiver(const OSCReceiver&); - OSCReceiver& operator=(const OSCReceiver&); - - static void error_cb(int num, const char* msg, const char* path); - static int set_response_address_cb(LO_HANDLER_ARGS, void* osc_receiver); - static int generic_cb(LO_HANDLER_ARGS, void* osc_receiver); - static int unknown_cb(LO_HANDLER_ARGS, void* osc_receiver); - - LO_HANDLER(quit); - LO_HANDLER(ping); - LO_HANDLER(ping_slow); - LO_HANDLER(register_client); - LO_HANDLER(unregister_client); - LO_HANDLER(load_plugins); - LO_HANDLER(engine_activate); - LO_HANDLER(engine_deactivate); - LO_HANDLER(create_patch); - LO_HANDLER(rename); - LO_HANDLER(create_node); - LO_HANDLER(create_node_by_uri); - LO_HANDLER(enable_patch); - LO_HANDLER(disable_patch); - LO_HANDLER(clear_patch); - LO_HANDLER(destroy); - LO_HANDLER(connect); - LO_HANDLER(disconnect); - LO_HANDLER(disconnect_all); - LO_HANDLER(set_port_value); - LO_HANDLER(set_port_value_voice); - LO_HANDLER(set_port_value_slow); - LO_HANDLER(note_on); - LO_HANDLER(note_off); - LO_HANDLER(all_notes_off); - LO_HANDLER(midi_learn); - LO_HANDLER(metadata_get); - LO_HANDLER(metadata_set); - LO_HANDLER(request_plugins); - LO_HANDLER(request_all_objects); - LO_HANDLER(request_port_value); -#ifdef HAVE_DSSI - LO_HANDLER(dssi); -#endif -#ifdef HAVE_LASH - LO_HANDLER(lash_restore_done); -#endif - - const char* const _port; - bool _is_activated; - lo_server_thread _st; - - /** Cached OSC responder (for most recent incoming message) */ - CountedPtr _osc_responder; -}; - - -} // namespace Om - -#endif // OSCRECEIVER_H diff --git a/src/engine/OSCResponder.cpp b/src/engine/OSCResponder.cpp deleted file mode 100644 index 82e6b55d..00000000 --- a/src/engine/OSCResponder.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OSCResponder.h" -#include "Om.h" -#include "OmApp.h" -#include "ClientBroadcaster.h" -#include "interface/ClientKey.h" -#include -#include -#include -#include - -using std::cout; using std::cerr; using std::endl; - -namespace Om { - - -/** Construct an OSCResponder from \a addr. - * Takes ownership of @a url. - */ -OSCResponder::OSCResponder(int32_t id, char* url) -: Responder() -, _id(id) -, _url(url) -, _addr(NULL) -{ - // If ID is -1 this shouldn't have even been created - assert(id != -1); -} - - -OSCResponder::~OSCResponder() -{ - //cerr << "DELETING " << _url << " RESPONDER\n"; - - if (_addr) - lo_address_free(_addr); -} - - -CountedPtr -OSCResponder::find_client() -{ - return om->client_broadcaster()->client(ClientKey(ClientKey::OSC_URL, _url)); -} - - -void -OSCResponder::respond_ok() -{ - _addr = lo_address_new_from_url(_url); - - //cerr << "OK " << _id << endl; - if (lo_send(_addr, "/om/response/ok", "i", _id) < 0) { - cerr << "Unable to send response " << _id << "! (" - << lo_address_errstr(_addr) << ")" << endl; - } -} - - -void -OSCResponder::respond_error(const string& msg) -{ - _addr = lo_address_new_from_url(_url); - - //cerr << "ERR " << _id << endl; - if (lo_send(_addr, "/om/response/error", "is",_id, msg.c_str()) < 0) { - cerr << "Unable to send response " << _id << "! (" - << lo_address_errstr(_addr) << endl; - } -} - -} // namespace OM - diff --git a/src/engine/OSCResponder.h b/src/engine/OSCResponder.h deleted file mode 100644 index f579df98..00000000 --- a/src/engine/OSCResponder.h +++ /dev/null @@ -1,61 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OSCRESPONDER_H -#define OSCRESPONDER_H - -#include -#include -#include -#include "Responder.h" - -namespace Om { - - -/** Responder for (liblo) OSC clients. - * - * OSC Clients use request IDs to be able to associate replies with sent - * events. If the ID is -1, a response will not be sent (and the overhead - * of searching for the client's record will be skipped). Any other integer - * is a valid response ID and will be responded to. - * - * Creation of the lo_address is deferred until needed to avoid bogging down - * the receiving thread as much as possible. - */ -class OSCResponder : public Responder -{ -public: - OSCResponder(int32_t id, char* url); - ~OSCResponder(); - - CountedPtr find_client(); - - void respond_ok(); - void respond_error(const string& msg); - - const char* url() const { return _url; } - -private: - int32_t _id; - char* const _url; - lo_address _addr; -}; - - -} // namespace Om - -#endif // OSCRESPONDER_H - diff --git a/src/engine/ObjectSender.cpp b/src/engine/ObjectSender.cpp deleted file mode 100644 index 3db6915d..00000000 --- a/src/engine/ObjectSender.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ObjectSender.h" -#include "interface/ClientInterface.h" -#include "Om.h" -#include "OmApp.h" -#include "ObjectStore.h" -#include "Patch.h" -#include "Node.h" -#include "Port.h" -#include "PortInfo.h" -#include "PortBase.h" -#include "Connection.h" -#include "NodeFactory.h" - -namespace Om { - -/** Send all currently existing objects to client. - */ -void -ObjectSender::send_all(ClientInterface* client) -{ - for (Tree::iterator i = om->object_store()->objects().begin(); - i != om->object_store()->objects().end(); ++i) - if ((*i)->as_patch() != NULL && (*i)->parent() == NULL) - send_patch(client, (*i)->as_patch()); - //(*i)->as_node()->send_creation_messages(client); - -} - - -void -ObjectSender::send_patch(ClientInterface* client, const Patch* patch) -{ - client->new_patch(patch->path(), patch->internal_poly()); - - for (List::const_iterator j = patch->nodes().begin(); - j != patch->nodes().end(); ++j) { - Node* const node = (*j); - Port* const port = node->as_port(); // NULL unless a bridge node - send_node(client, node); - - usleep(100); - - // If this is a bridge (input/output) node, send the patch control value as well - if (port && port->port_info()->is_control()) - client->control_change(port->path(), - ((PortBase*)port)->buffer(0)->value_at(0)); - } - - for (List::const_iterator j = patch->connections().begin(); - j != patch->connections().end(); ++j) - client->connection((*j)->src_port()->path(), (*j)->dst_port()->path()); - - // Send port information - /*for (size_t i=0; i < m_ports.size(); ++i) { - Port* const port = m_ports.at(i); - - // Send metadata - const map& data = port->metadata(); - for (map::const_iterator i = data.begin(); i != data.end(); ++i) - om->client_broadcaster()->send_metadata_update_to(client, port->path(), (*i).first, (*i).second); - - if (port->port_info()->is_control()) - om->client_broadcaster()->send_control_change_to(client, port->path(), - ((PortBase*)port)->buffer(0)->value_at(0)); - }*/ -} - - -void -ObjectSender::send_node(ClientInterface* client, const Node* node) -{ - int polyphonic = - (node->poly() > 1 - && node->poly() == node->parent_patch()->internal_poly() - ? 1 : 0); - - assert(node->plugin()->uri().length() > 0); - assert(node->path().length() > 0); - - client->bundle_begin(); - - // FIXME: bundleify - - const Array& ports = node->ports(); - - client->new_node(node->plugin()->type_string(), node->plugin()->uri(), - node->path(), polyphonic, ports.size()); - - // Send ports - for (size_t j=0; j < ports.size(); ++j) { - Port* const port = ports.at(j); - PortInfo* const info = port->port_info(); - - assert(port); - assert(info); - - client->new_port(port->path(), info->type_string(), info->is_output()); - - /*m = lo_message_new(); - lo_message_add_string(m, port->path().c_str()); - lo_message_add_string(m, info->type_string().c_str()); - lo_message_add_string(m, info->direction_string().c_str()); - lo_message_add_string(m, info->hint_string().c_str()); - lo_message_add_float(m, info->default_val()); - lo_message_add_float(m, info->min_val()); - lo_message_add_float(m, info->max_val()); - lo_bundle_add_message(b, "/om/new_port", m); - msgs.push_back(m);*/ - - // If the bundle is getting very large, send it and start - // a new one - /*if (lo_bundle_length(b) > 1024) { - lo_send_bundle(_address, b); - lo_bundle_free(b); - b = lo_bundle_new(tt); - }*/ - } - - client->bundle_end(); -} - - -void -ObjectSender::send_port(ClientInterface* client, const Port* port) -{ - PortInfo* info = port->port_info(); - - client->new_port(port->path(), info->type_string(), info->is_output()); - - // Send metadata - const map& data = port->metadata(); - for (map::const_iterator j = data.begin(); j != data.end(); ++j) - client->metadata_update(port->path(), (*j).first, (*j).second); -} - - -void -ObjectSender::send_plugins(ClientInterface* client) -{ - om->node_factory()->lock_plugin_list(); - - const list& plugs = om->node_factory()->plugins(); - -/* - lo_timetag tt; - lo_timetag_now(&tt); - lo_bundle b = lo_bundle_new(tt); - lo_message m = lo_message_new(); - list msgs; - - lo_message_add_int32(m, plugs.size()); - lo_bundle_add_message(b, "/om/num_plugins", m); - msgs.push_back(m); -*/ - for (list::const_iterator j = plugs.begin(); j != plugs.end(); ++j) { - const Plugin* const p = *j; - client->new_plugin(p->type_string(), p->uri(), p->name()); - } -/* - plugin = (*j); - m = lo_message_new(); - - lo_message_add_string(m, plugin->type_string()); - lo_message_add_string(m, plugin->uri().c_str()); - lo_message_add_string(m, plugin->name().c_str()); - lo_bundle_add_message(b, "/om/plugin", m); - msgs.push_back(m); - if (lo_bundle_length(b) > 1024) { - // FIXME FIXME FIXME dirty, dirty cast - lo_send_bundle(((OSCClient*)client)->address(), b); - lo_bundle_free(b); - b = lo_bundle_new(tt); - } - }*/ -/* - if (lo_bundle_length(b) > 0) { - // FIXME FIXME FIXME dirty, dirty cast - lo_send_bundle(((OSCClient*)client)->address(), b); - lo_bundle_free(b); - } else { - lo_bundle_free(b); - } - for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i) - lo_message_free(*i); -*/ - om->node_factory()->unlock_plugin_list(); -} - - -} // namespace Om - diff --git a/src/engine/ObjectSender.h b/src/engine/ObjectSender.h deleted file mode 100644 index f97f1f9e..00000000 --- a/src/engine/ObjectSender.h +++ /dev/null @@ -1,55 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OBJECTSENDER_H -#define OBJECTSENDER_H - -namespace Om { - -namespace Shared { - class ClientInterface; -} using Shared::ClientInterface; - -class Patch; -class Node; -class Port; - - -/** Utility class for sending OmObjects to clients through ClientInterface. - * - * While ClientInterface is the direct low level message-based interface - * (protocol), this is used from the engine to easily send proper Objects - * with these messages (which is done in a few different parts of the code). - * - * Basically a serializer, except to calls on ClientInterface rather than - * eg a byte stream. - */ -class ObjectSender { -public: - - // FIXME: Make all object parameters const - - static void send_all(ClientInterface* client); - static void send_patch(ClientInterface* client, const Patch* patch); - static void send_node(ClientInterface* client, const Node* node); - static void send_port(ClientInterface* client, const Port* port); - static void send_plugins(ClientInterface* client); -}; - -} // namespace Om - -#endif // OBJECTSENDER_H - diff --git a/src/engine/ObjectStore.cpp b/src/engine/ObjectStore.cpp deleted file mode 100644 index a1cf1287..00000000 --- a/src/engine/ObjectStore.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ObjectStore.h" -#include "Om.h" -#include "OmApp.h" -#include "Patch.h" -#include "Node.h" -#include "Port.h" -#include "List.h" -#include "util/Path.h" -#include "Tree.h" - -namespace Om { - - -/** Find the Patch at the given path. - */ -Patch* -ObjectStore::find_patch(const Path& path) -{ - OmObject* const object = find(path); - return (object == NULL) ? NULL : object->as_patch(); -} - - -/** Find the Node at the given path. - */ -Node* -ObjectStore::find_node(const Path& path) -{ - OmObject* const object = find(path); - return (object == NULL) ? NULL : object->as_node(); -} - - -/** Find the Port at the given path. - */ -Port* -ObjectStore::find_port(const Path& path) -{ - OmObject* const object = find(path); - return (object == NULL) ? NULL : object->as_port(); -} - - -/** Find the Object at the given path. - */ -OmObject* -ObjectStore::find(const Path& path) -{ - return m_objects.find(path); -} - - -/** Add an object to the store. Not realtime safe. - */ -void -ObjectStore::add(OmObject* o) -{ - //cerr << "[ObjectStore] Adding " << o->path() << endl; - m_objects.insert(new TreeNode(o->path(), o)); -} - - -/** Add an object to the store. Not realtime safe. - */ -void -ObjectStore::add(TreeNode* tn) -{ - //cerr << "[ObjectStore] Adding " << tn->key() << endl; - m_objects.insert(tn); -} - - -/** Remove a patch from the store. - * - * It it the caller's responsibility to delete the returned ListNode. - * - * @returns TreeNode containing object removed on success, NULL if not found. - */ -TreeNode* -ObjectStore::remove(const string& path) -{ - TreeNode* const removed = m_objects.remove(path); - - if (removed == NULL) - cerr << "[ObjectStore] WARNING: Removing " << path << " failed." << endl; - //else - // cerr << "[ObjectStore] Removed " << path << endl; - - return removed; -} - - -} // namespace Om diff --git a/src/engine/ObjectStore.h b/src/engine/ObjectStore.h deleted file mode 100644 index 8c71c002..00000000 --- a/src/engine/ObjectStore.h +++ /dev/null @@ -1,61 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef OBJECTSTORE_H -#define OBJECTSTORE_H - -#include -#include "util/Path.h" -#include "Tree.h" -using std::string; - -namespace Om { - -class Patch; -class Node; -class Port; -class OmObject; - - -/** Storage for all OmObjects (tree of OmObject's sorted by path). - * - * All looking up in pre_process() methods (and anything else that isn't in-band - * with the audio thread) should use this (to read and modify the OmObject - * tree). - */ -class ObjectStore -{ -public: - Patch* find_patch(const Path& path); - Node* find_node(const Path& path); - Port* find_port(const Path& path); - OmObject* find(const Path& path); - - void add(OmObject* o); - void add(TreeNode* o); - TreeNode* remove(const string& key); - - const Tree& objects() { return m_objects; } - -private: - Tree m_objects; -}; - - -} // namespace Om - -#endif // OBJECTSTORE diff --git a/src/engine/Om.cpp b/src/engine/Om.cpp deleted file mode 100644 index c04a7464..00000000 --- a/src/engine/Om.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "OmApp.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif - -/** Om namespace. - * - * Everything internal to the Om engine lives in this namespace. Generally - * none of this code is used by clients - as special (possibly temporary) - * exceptions, some classes in src/common are used by clients but are part - * of the Om namespace. - */ -namespace Om -{ - OmApp* om = 0; -#ifdef HAVE_LASH - LashDriver* lash_driver = 0; -#endif -} diff --git a/src/engine/Om.h b/src/engine/Om.h deleted file mode 100644 index 2fe3fd8c..00000000 --- a/src/engine/Om.h +++ /dev/null @@ -1,42 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OM_H -#define OM_H - -// FIXME: this dependency has to go -#include "config.h" - - -/* Things all over the place access various bits of Om through this. - * This was a bad design decision, it just evolved this way :/ - * I may refactor it eventually, but it works. - */ - -/** \defgroup engine Engine - */ -namespace Om -{ -#ifdef HAVE_LASH - class LashDriver; - extern LashDriver* lash_driver; -#endif - class OmApp; - extern OmApp* om; -} - -#endif // OM_H - diff --git a/src/engine/OmApp.cpp b/src/engine/OmApp.cpp deleted file mode 100644 index ea7df1df..00000000 --- a/src/engine/OmApp.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Om.h" -#include "OmApp.h" -#include "config.h" -#include "tuning.h" -#include -#include -#include -#include "Event.h" -#include "util/Queue.h" -#include "JackAudioDriver.h" -#include "NodeFactory.h" -#include "OSCReceiver.h" -#include "ClientBroadcaster.h" -#include "Patch.h" -#include "ObjectStore.h" -#include "MaidObject.h" -#include "Maid.h" -#include "MidiDriver.h" -#include "QueuedEventSource.h" -#include "PostProcessor.h" -#include "CreatePatchEvent.h" -#include "EnablePatchEvent.h" -#ifdef HAVE_JACK_MIDI -#include "JackMidiDriver.h" -#endif -#ifdef HAVE_ALSA_MIDI -#include "AlsaMidiDriver.h" -#endif -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif -using std::cout; using std::cerr; using std::endl; - -namespace Om { - - -OmApp::OmApp(const char* port) -: m_maid(new Maid(maid_queue_size)), - m_audio_driver(new JackAudioDriver()), -#ifdef HAVE_JACK_MIDI - m_midi_driver(new JackMidiDriver(((JackAudioDriver*)m_audio_driver)->jack_client())), -#elif HAVE_ALSA_MIDI - m_midi_driver(new AlsaMidiDriver()), -#else - m_midi_driver(new DummyMidiDriver()), -#endif - m_osc_receiver(new OSCReceiver(pre_processor_queue_size, port)), - m_client_broadcaster(new ClientBroadcaster()), - m_object_store(new ObjectStore()), - m_node_factory(new NodeFactory()), - m_event_queue(new Queue(event_queue_size)), -// m_pre_processor(new QueuedEventSource(pre_processor_queue_size)), - m_post_processor(new PostProcessor(post_processor_queue_size)), - m_quit_flag(false), - m_activated(false) -{ - mlock(m_audio_driver, sizeof(JackAudioDriver)); - mlock(m_object_store, sizeof(ObjectStore)); - mlock(m_osc_receiver, sizeof(OSCReceiver)); -#ifdef HAVE_ALSA_MIDI - mlock(m_midi_driver, sizeof(AlsaMidiDriver)); -#else - mlock(m_midi_driver, sizeof(DummyMidiDriver)); -#endif - - m_osc_receiver->start(); - m_post_processor->start(); -} - - -OmApp::OmApp(const char* port, AudioDriver* audio_driver) -: m_maid(new Maid(maid_queue_size)), - m_audio_driver(audio_driver), -#ifdef HAVE_JACK_MIDI - m_midi_driver(new JackMidiDriver(((JackAudioDriver*)m_audio_driver)->jack_client())), -#elif HAVE_ALSA_MIDI - m_midi_driver(new AlsaMidiDriver()), -#else - m_midi_driver(new DummyMidiDriver()), -#endif - m_osc_receiver(new OSCReceiver(pre_processor_queue_size, port)), - m_client_broadcaster(new ClientBroadcaster()), - m_object_store(new ObjectStore()), - m_node_factory(new NodeFactory()), - m_event_queue(new Queue(event_queue_size)), - //m_pre_processor(new QueuedEventSource(pre_processor_queue_size)), - m_post_processor(new PostProcessor(post_processor_queue_size)), - m_quit_flag(false), - m_activated(false) -{ - mlock(m_audio_driver, sizeof(JackAudioDriver)); - mlock(m_object_store, sizeof(ObjectStore)); - mlock(m_osc_receiver, sizeof(OSCReceiver)); -#ifdef HAVE_ALSA_MIDI - mlock(m_midi_driver, sizeof(AlsaMidiDriver)); -#else - mlock(m_midi_driver, sizeof(DummyMidiDriver)); -#endif - - m_osc_receiver->start(); - m_post_processor->start(); -} - - -OmApp::~OmApp() -{ - deactivate(); - - for (Tree::iterator i = m_object_store->objects().begin(); - i != m_object_store->objects().end(); ++i) { - if ((*i)->parent() == NULL) - delete (*i); - } - - delete m_object_store; - delete m_client_broadcaster; - delete m_osc_receiver; - delete m_node_factory; - delete m_midi_driver; - delete m_audio_driver; - - delete m_maid; - - munlockall(); -} - - -/* driver() template specializations. - * Due to the lack of RTTI, this needs to be implemented manually like this. - * If more types/drivers start getting added, it may be worth it to enable - * RTTI and put all the drivers into a map with typeid's as the key. That's - * more elegant and extensible, but this is faster and simpler - for now. - */ -template<> -Driver* OmApp::driver() { return m_midi_driver; } -template<> -Driver* OmApp::driver() { return m_audio_driver; } - - -int -OmApp::main() -{ - // Loop until quit flag is set (by OSCReceiver) - while ( ! m_quit_flag) { - nanosleep(&main_rate, NULL); -#ifdef HAVE_LASH - // Process any pending LASH events - if (lash_driver->enabled()) - lash_driver->process_events(); -#endif - // Run the maid (garbage collector) - m_maid->cleanup(); - } - cout << "[Main] Done main loop." << endl; - - if (m_activated) - deactivate(); - - sleep(1); - cout << "[Main] Om exiting..." << endl; - - return 0; -} - - -void -OmApp::activate() -{ - if (m_activated) - return; - - // Create root patch - CreatePatchEvent create_ev(CountedPtr(new Responder()), "/", 1); - create_ev.pre_process(); - create_ev.execute(0); - create_ev.post_process(); - EnablePatchEvent enable_ev(CountedPtr(new Responder()), "/"); - enable_ev.pre_process(); - enable_ev.execute(0); - enable_ev.post_process(); - - assert(m_audio_driver->root_patch() != NULL); - - m_audio_driver->activate(); -#ifdef HAVE_ALSA_MIDI - m_midi_driver->activate(); -#endif - m_activated = true; -} - - -void -OmApp::deactivate() -{ - if (!m_activated) - return; - - m_audio_driver->root_patch()->process(false); - - for (Tree::iterator i = m_object_store->objects().begin(); - i != m_object_store->objects().end(); ++i) - if ((*i)->as_node() != NULL && (*i)->as_node()->parent() == NULL) - (*i)->as_node()->deactivate(); - - if (m_midi_driver != NULL) - m_midi_driver->deactivate(); - - m_osc_receiver->stop(); - m_audio_driver->deactivate(); - - m_activated = false; -} - - -} // namespace Om diff --git a/src/engine/OmApp.h b/src/engine/OmApp.h deleted file mode 100644 index 0fe49b81..00000000 --- a/src/engine/OmApp.h +++ /dev/null @@ -1,99 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OMAPP_H -#define OMAPP_H - -template class Queue; -class Maid; - -namespace Om { - -class AudioDriver; -class MidiDriver; -class NodeFactory; -class OSCReceiver; -class ClientBroadcaster; -class Patch; -class ObjectStore; -class EventSource; -class PostProcessor; -class Event; -class QueuedEvent; -template class Driver; - - -/** The main class for Om, the whole app lives in here - * - * This class should not exist. - * - * \ingroup engine - */ -class OmApp -{ -public: - OmApp(const char* const port); - OmApp(const char* const port, AudioDriver* audio_driver); - ~OmApp(); - - int main(); - - /** Set the quit flag that should kill all threads and exit cleanly. - * Note that it will take some time. */ - void quit() { m_quit_flag = true; } - - void activate(); - void deactivate(); - - Maid* maid() const { return m_maid; } - AudioDriver* audio_driver() const { return m_audio_driver; } - MidiDriver* midi_driver() const { return m_midi_driver; } - OSCReceiver* osc_receiver() const { return m_osc_receiver; } - ClientBroadcaster* client_broadcaster() const { return m_client_broadcaster; } - ObjectStore* object_store() const { return m_object_store; } - NodeFactory* node_factory() const { return m_node_factory; } - Queue* event_queue() const { return m_event_queue; } - //EventSource* pre_processor() const { return m_pre_processor; } - PostProcessor* post_processor() const { return m_post_processor; } - - /** Return the active driver for the given (template parameter) type. - * This is a hook for BridgeNode. See OmApp.cpp for specializations. */ - template Driver* driver(); - -private: - // Prevent copies - OmApp(const OmApp&); - OmApp& operator=(const OmApp&); - - Maid* m_maid; - AudioDriver* m_audio_driver; - MidiDriver* m_midi_driver; - OSCReceiver* m_osc_receiver; - ClientBroadcaster* m_client_broadcaster; - ObjectStore* m_object_store; - NodeFactory* m_node_factory; - Queue* m_event_queue; - //EventSource* m_pre_processor; - PostProcessor* m_post_processor; - - bool m_quit_flag; - bool m_activated; -}; - - -} // namespace Om - -#endif // OMAPP_H diff --git a/src/engine/OmInProcess.cpp b/src/engine/OmInProcess.cpp deleted file mode 100644 index 971a1316..00000000 --- a/src/engine/OmInProcess.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Mario Lang. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "Om.h" -#include "OmApp.h" -#include "OSCReceiver.h" -#include "JackAudioDriver.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif - -extern "C" -{ - int jack_initialize(jack_client_t* client, const char* load_init); - void jack_finish(void* arg); -} - - -void* -run_main(void* arg) -{ - Om::om->main(); -#ifdef HAVE_LASH - - delete Om::lash_driver; -#endif - - delete Om::om; - return 0; -} - - -pthread_t main_thread; - - -int -jack_initialize(jack_client_t* client, const char* load_init) -{ - if ((Om::om = new Om::OmApp(load_init, new Om::JackAudioDriver(client))) != NULL) { - pthread_create(&main_thread, NULL, run_main, NULL); - return 0; // Success - } else { - return 1; - } -} - - -void -jack_finish(void* arg) -{ - void* ret; - Om::om->quit(); - pthread_join(main_thread, &ret); -} - diff --git a/src/engine/OmObject.h b/src/engine/OmObject.h deleted file mode 100644 index 606a3dba..00000000 --- a/src/engine/OmObject.h +++ /dev/null @@ -1,115 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OMOBJECT_H -#define OMOBJECT_H - -#include -#include -#include -#include -#include "MaidObject.h" -#include "util/Path.h" - -using std::string; using std::map; - -namespace Om { - -class Patch; -class Node; -class Port; - - -/** An object in the "synth space" of Om - Patch, Node, Port, etc. - * - * Each of these is a MaidObject and so can be deleted in a realtime safe - * way from anywhere, and they all have a map of metadata for clients to store - * arbitrary values in (which the engine puts no significance to whatsoever). - * - * \ingroup engine - */ -class OmObject : public MaidObject -{ -public: - OmObject(OmObject* parent, const string& name) - : m_parent(parent), m_name(name) - { - assert(parent == NULL || m_name.length() > 0); - assert(parent == NULL || m_name.find("/") == string::npos); - //assert(((string)path()).find("//") == string::npos); - } - - virtual ~OmObject() {} - - // Ghetto home-brew RTTI - virtual Patch* as_patch() { return NULL; } - virtual Node* as_node() { return NULL; } - virtual Port* as_port() { return NULL; } - - OmObject* parent() const { return m_parent; } - - inline const string& name() const { return m_name; } - - virtual void set_path(const Path& new_path) { - m_name = new_path.name(); - assert(m_name.find("/") == string::npos); - } - - void set_metadata(const string& key, const string& value) { m_metadata[key] = value; } - const string& get_metadata(const string& key) { - static const string empty_string = ""; - map::iterator i = m_metadata.find(key); - if (i != m_metadata.end()) - return (*i).second; - else - return empty_string; - } - - const map& metadata() const { return m_metadata; } - - inline const Path path() const { - if (m_parent == NULL) - return Path(string("/").append(m_name)); - else if (m_parent->path() == "/") - return Path(string("/").append(m_name)); - else - return Path(m_parent->path() +"/"+ m_name); - } - - /** Patch and Node override this to recursively add their children. */ - virtual void add_to_store() = 0; - - /** Patch and Node override this to recursively remove their children. */ - virtual void remove_from_store() = 0; - -protected: - OmObject() {} - - OmObject* m_parent; - string m_name; - -private: - // Prevent copies (undefined) - OmObject(const OmObject&); - OmObject& operator=(const OmObject& copy); - - map m_metadata; -}; - - -} // namespace Om - -#endif // OMOBJECT_H diff --git a/src/engine/OutputPort.cpp b/src/engine/OutputPort.cpp deleted file mode 100644 index bf971919..00000000 --- a/src/engine/OutputPort.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OutputPort.h" -#include "InputPort.h" -#include "PortInfo.h" -#include - -namespace Om { - -template -OutputPort::OutputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size) -: PortBase(node, name, index, poly, port_info, buffer_size) -{ - assert(port_info->is_output() && !port_info->is_input()); -} -template OutputPort::OutputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); -template OutputPort::OutputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); - - -template -void -OutputPort::set_tied_port(InputPort* port) -{ - assert(!m_is_tied); - assert(m_tied_port == NULL); - assert(static_cast*>(port) != static_cast*>(this)); - assert(port != NULL); - - m_is_tied = true; - m_tied_port = (PortBase*)port; -} -template void OutputPort::set_tied_port(InputPort* port); -template void OutputPort::set_tied_port(InputPort* port); - - -} // namespace Om - diff --git a/src/engine/OutputPort.h b/src/engine/OutputPort.h deleted file mode 100644 index 90488a7f..00000000 --- a/src/engine/OutputPort.h +++ /dev/null @@ -1,64 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OUTPUTPORT_H -#define OUTPUTPORT_H - -#include -#include -#include "PortBase.h" -#include "util/types.h" - -namespace Om { - -template class InputPort; - - -/** An output port. - * - * Output ports always have a locally allocated buffer, and buffer() will - * always return that buffer. (This is very different from InputPort) - * - * This class actually adds no functionality to Port whatsoever right now, - * it will in the future when more advanced port types exist, and it makes - * things clearer throughout the engine. - * - * \ingroup engine - */ -template -class OutputPort : public PortBase -{ -public: - OutputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); - virtual ~OutputPort() {} - - void set_tied_port(InputPort* port); - -private: - // Prevent copies (undefined) - OutputPort(const OutputPort& copy); - OutputPort& operator=(const OutputPort&); - - using PortBase::m_is_tied; - using PortBase::m_tied_port; -}; - - -template class OutputPort; - -} // namespace Om - -#endif // OUTPUTPORT_H diff --git a/src/engine/Patch.cpp b/src/engine/Patch.cpp deleted file mode 100644 index be938cae..00000000 --- a/src/engine/Patch.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include "Node.h" -#include "Patch.h" -#include "Plugin.h" -#include "Port.h" -#include "PortInfo.h" -#include "ClientBroadcaster.h" -#include "InternalNode.h" -#include "Connection.h" -#include "Om.h" -#include "OmApp.h" -#include "PortBase.h" -#include "ObjectStore.h" -#include "interface/ClientInterface.h" - -using std::cerr; using std::cout; using std::endl; - -namespace Om { - - -Patch::Patch(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size, size_t internal_poly) -: NodeBase(path, poly, parent, srate, buffer_size), - m_internal_poly(internal_poly), - m_process_order(NULL), - m_process(false) -{ - assert(internal_poly >= 1); - - m_plugin.type(Plugin::Patch); - m_plugin.lib_path(""); - m_plugin.plug_label("om_patch"); - m_plugin.name("Om patch"); - - //std::cerr << "Creating patch " << m_name << ", poly = " << poly - // << ", internal poly = " << internal_poly << std::endl; -} - - -Patch::~Patch() -{ - assert(!m_activated); - - for (List::iterator i = m_connections.begin(); i != m_connections.end(); ++i) { - delete (*i); - delete m_connections.remove(i); - } - - for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) { - assert(!(*i)->activated()); - delete (*i); - delete m_nodes.remove(i); - } - - delete m_process_order; -} - - -void -Patch::activate() -{ - NodeBase::activate(); - - for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) - (*i)->activate(); - - assert(m_activated); -} - - -void -Patch::deactivate() -{ - if (m_activated) { - - NodeBase::deactivate(); - - for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) { - if ((*i)->activated()) - (*i)->deactivate(); - assert(!(*i)->activated()); - } - } - assert(!m_activated); -} - - -void -Patch::process(bool b) -{ - if (!b) { - // Write output buffers to 0 - for (List::iterator i = m_bridge_nodes.begin(); i != m_bridge_nodes.end(); ++i) { - assert((*i)->as_port() != NULL); - if ((*i)->as_port()->port_info()->is_output()) - (*i)->as_port()->clear_buffers(); - } - } - m_process = b; -} - - -/** Run the patch for the specified number of frames. - * - * Calls all Nodes in the order m_process_order specifies. - */ -inline void -Patch::run(size_t nframes) -{ - if (m_process_order == NULL || !m_process) - return; - - // Prepare all ports - for (List::iterator i = m_bridge_nodes.begin(); i != m_bridge_nodes.end(); ++i) - (*i)->as_port()->prepare_buffers(nframes); - - // Run all nodes - for (size_t i=0; i < m_process_order->size(); ++i) { - // Could be a gap due to a node removal event (see RemoveNodeEvent.cpp) - // If you're thinking this isn't very nice, you're right. - if (m_process_order->at(i) != NULL) - m_process_order->at(i)->run(nframes); - } -} - - -/** Returns the number of ports. - * - * Needs to override the NodeBase implementation since a Patch's ports are really - * just it's input and output nodes' ports. - */ -size_t -Patch::num_ports() const -{ - return m_bridge_nodes.size(); -} - - -#if 0 -void -Patch::send_creation_messages(ClientInterface* client) const -{ - cerr << "FIXME: creation\n"; - - om->client_broadcaster()->send_patch_to(client, this); - - for (List::const_iterator j = m_nodes.begin(); j != m_nodes.end(); ++j) { - Node* node = (*j); - Port* port = node->as_port(); // NULL unless a bridge node - node->send_creation_messages(client); - - usleep(100); - - // If this is a bridge (input/output) node, send the patch control value as well - if (port != NULL && port->port_info()->is_control()) - om->client_broadcaster()->send_control_change_to(client, port->path(), - ((PortBase*)port)->buffer(0)->value_at(0)); - } - - for (List::const_iterator j = m_connections.begin(); j != m_connections.end(); ++j) { - om->client_broadcaster()->send_connection_to(client, *j); - } - - // Send port information - /*for (size_t i=0; i < m_ports.size(); ++i) { - Port* const port = m_ports.at(i); - - // Send metadata - const map& data = port->metadata(); - for (map::const_iterator i = data.begin(); i != data.end(); ++i) - om->client_broadcaster()->send_metadata_update_to(client, port->path(), (*i).first, (*i).second); - - if (port->port_info()->is_control()) - om->client_broadcaster()->send_control_change_to(client, port->path(), - ((PortBase*)port)->buffer(0)->value_at(0)); - }*/ -} -#endif - - -void -Patch::add_to_store() -{ - // Add self and ports - NodeBase::add_to_store(); - - // Add nodes - for (List::iterator j = m_nodes.begin(); j != m_nodes.end(); ++j) - (*j)->add_to_store(); -} - - -void -Patch::remove_from_store() -{ - // Remove self and ports - NodeBase::remove_from_store(); - - // Remove nodes - for (List::iterator j = m_nodes.begin(); j != m_nodes.end(); ++j) { - (*j)->remove_from_store(); - assert(om->object_store()->find((*j)->path()) == NULL); - } -} - - -// Patch specific stuff - - -void -Patch::add_node(ListNode* ln) -{ - assert(ln != NULL); - assert(ln->elem() != NULL); - assert(ln->elem()->parent_patch() == this); - assert(ln->elem()->poly() == m_internal_poly || ln->elem()->poly() == 1); - - m_nodes.push_back(ln); -} - - -ListNode* -Patch::remove_node(const string& name) -{ - for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) - if ((*i)->name() == name) - return m_nodes.remove(i); - - return NULL; -} - - -/** Remove a connection. Realtime safe. - */ -ListNode* -Patch::remove_connection(const Port* src_port, const Port* dst_port) -{ - bool found = false; - ListNode* connection = NULL; - for (List::iterator i = m_connections.begin(); i != m_connections.end(); ++i) { - if ((*i)->src_port() == src_port && (*i)->dst_port() == dst_port) { - connection = m_connections.remove(i); - found = true; - } - } - - if ( ! found) - cerr << "WARNING: [Patch::remove_connection] Connection not found !" << endl; - - return connection; -} - - -/** Remove a bridge_node. Realtime safe. - */ -ListNode* -Patch::remove_bridge_node(const InternalNode* node) -{ - bool found = false; - ListNode* bridge_node = NULL; - for (List::iterator i = m_bridge_nodes.begin(); i != m_bridge_nodes.end(); ++i) { - if ((*i) == node) { - bridge_node = m_bridge_nodes.remove(i); - found = true; - } - } - - if ( ! found) - cerr << "WARNING: [Patch::remove_bridge_node] InternalNode not found !" << endl; - - return bridge_node; -} - - -/** Find the process order for this Patch. - * - * The process order is a flat list that the patch will execute in order - * when it's run() method is called. Return value is a newly allocated list - * which the caller is reponsible to delete. Note that this function does - * NOT actually set the process order, it is returned so it can be inserted - * at the beginning of an audio cycle (by various Events). - * - * This function is not realtime safe, due to the use of the List iterator - */ -Array* -Patch::build_process_order() const -{ - Node* node = NULL; - Array* const process_order = new Array(m_nodes.size()); - - for (List::const_iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) - (*i)->traversed(false); - - // Traverse backwards starting at outputs - for (List::const_iterator i = m_bridge_nodes.begin(); i != m_bridge_nodes.end(); ++i) { - node = (*i); - assert(node->as_port() != NULL); - - // If the output node has been disconnected and has no connections left, don't traverse - // into it so it's not in the process order (and can be removed w/o flaming segfault death) - if (node->as_port()->port_info()->is_output() && node->providers()->size() > 0) - build_process_order_recursive(node, process_order); - } - - // Add any nodes that weren't hit by the traversal (disjoint nodes) - for (List::const_iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) { - node = (*i); - if ( ! node->traversed()) { - process_order->push_back(*i); - node->traversed(true); - } - } - - assert(process_order->size() == m_nodes.size()); - - return process_order; -} - - -/** Rename this Patch. - * - * This is responsible for updating the ObjectStore so the Patch can be - * found at it's new path, as well as all it's children. - */ -void -Patch::set_path(const Path& new_path) -{ - const Path old_path = path(); - - // Update nodes - for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) - (*i)->set_path(new_path.base_path() + (*i)->name()); - - // Update self - NodeBase::set_path(new_path); -} - - -} // namespace Om diff --git a/src/engine/Patch.h b/src/engine/Patch.h deleted file mode 100644 index e2a1ed48..00000000 --- a/src/engine/Patch.h +++ /dev/null @@ -1,136 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PATCH_H -#define PATCH_H - -#include -#include -#include "NodeBase.h" -#include "Plugin.h" -#include "List.h" - -using std::string; - -template class Array; - -namespace Om { - -class Connection; -class InternalNode; -namespace Shared { - class ClientInterface; -} using Shared::ClientInterface; - - -/** A group of nodes in a graph, possibly polyphonic. - * - * Note that this is also a Node, just one which contains Nodes. - * Therefore infinite subpatching is possible, of polyphonic - * patches of polyphonic nodes etc. etc. - * - * \ingroup engine - */ -class Patch : public NodeBase -{ -public: - Patch(const string& name, size_t poly, Patch* parent, samplerate srate, size_t buffer_size, size_t local_poly); - virtual ~Patch(); - - Patch* as_patch() { return static_cast(this); } - - void activate(); - void deactivate(); - - void run(size_t nframes); - - size_t num_ports() const; - - //void send_creation_messages(ClientInterface* client) const; - - void add_to_store(); - void remove_from_store(); - - void set_path(const Path& new_path); - - // Patch specific stuff not inherited from Node - - void add_node(ListNode* tn); - ListNode* remove_node(const string& name); - - List& nodes() { return m_nodes; } - List& connections() { return m_connections; } - - const List& nodes() const { return m_nodes; } - const List& connections() const { return m_connections; } - - void add_bridge_node(ListNode* n) { m_bridge_nodes.push_back(n); } - ListNode* remove_bridge_node(const InternalNode* n); - - void add_connection(ListNode* c) { m_connections.push_back(c); } - ListNode* remove_connection(const Port* src_port, const Port* dst_port); - - Array* process_order() { return m_process_order; } - void process_order(Array* po) { m_process_order = po; } - - Array* build_process_order() const; - inline void build_process_order_recursive(Node* n, Array* order) const; - - /** Whether to run this patch's DSP in the audio thread */ - bool process() const { return m_process; } - void process(bool b); - - size_t internal_poly() const { return m_internal_poly; } - - const Plugin* plugin() const { return &m_plugin; } - void plugin(const Plugin* const) { exit(EXIT_FAILURE); } - -private: - // Prevent copies (undefined) - Patch(const Patch&); - Patch& operator=(const Patch&); - - size_t m_internal_poly; - Array* m_process_order; - List m_connections; - List m_bridge_nodes; ///< Inputs and outputs - List m_nodes; - bool m_process; - - Plugin m_plugin; -}; - - - -/** Private helper for build_process_order */ -inline void -Patch::build_process_order_recursive(Node* n, Array* order) const -{ - if (n == NULL || n->traversed()) return; - n->traversed(true); - assert(order != NULL); - - for (List::iterator i = n->providers()->begin(); i != n->providers()->end(); ++i) - if ( ! (*i)->traversed() ) - build_process_order_recursive((*i), order); - - order->push_back(n); -} - - -} // namespace Om - -#endif // PATCH_H diff --git a/src/engine/Plugin.h b/src/engine/Plugin.h deleted file mode 100644 index d350b1e8..00000000 --- a/src/engine/Plugin.h +++ /dev/null @@ -1,149 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PLUGIN_H -#define PLUGIN_H - -#include "config.h" - -#include -#include -#include -#include -#ifdef HAVE_SLV2 -#include -#endif -using std::string; -using std::cerr; using std::endl; - - -namespace Om { - -class PluginLibrary; - - -/** Representation of a plugin (of various types). - * - * A Node is an instance of this, conceptually. - * FIXME: This whole thing is a filthy mess and needs a rewrite. Probably - * with derived classes for each plugin type. - */ -class Plugin -{ -public: - enum Type { LV2, LADSPA, DSSI, Internal, Patch }; - - Plugin() : m_type(Internal), m_lib_path("/Om"), - m_id(0), m_library(NULL) - { -#ifdef HAVE_SLV2 - m_slv2_plugin = NULL; -#endif - } - - Plugin(const Plugin* const copy) { - // Copying only allowed for Internal plugins. Bit of a hack, but - // allows the PluginInfo to be defined in the Node class which keeps - // things localized and convenient (FIXME?) - if (copy->m_type != Internal) - exit(EXIT_FAILURE); - m_type = copy->m_type; - m_lib_path = copy->m_lib_path; - m_plug_label = copy->m_plug_label; - m_name = copy->m_name; - m_library = copy->m_library; - } - - Type type() const { return m_type; } - void type(Type t) { m_type = t; } - const string& lib_path() const { return m_lib_path; } - void lib_path(const string& s) { m_lib_path = s; } - string lib_name() const { return m_lib_path.substr(m_lib_path.find_last_of("/")); } - const string& plug_label() const { return m_plug_label; } - void plug_label(const string& s) { m_plug_label = s; } - const string& name() const { return m_name; } - void name(const string& s) { m_name = s; } - unsigned long id() const { return m_id; } - void id(unsigned long i) { m_id = i; } - void uri(const string& s) { m_uri = s; } - const string uri() const - { - char id_str[11]; - snprintf(id_str, 11, "%lu", m_id); - - if (m_uri.length() > 0) { - return m_uri; - } else if (m_type == Internal) { - return string("om:") + m_plug_label; - } else if (m_type == LADSPA) { - return string("ladspa:").append(id_str); - } else if (m_type == DSSI) { - return string("dssi:") + lib_name() +":"+ m_plug_label; - } else { - return ""; - } - } - - PluginLibrary* library() const { return m_library; } - void library(PluginLibrary* const library) { m_library = library; } - - const char* type_string() const { - if (m_type == LADSPA) return "LADSPA"; - else if (m_type == LV2) return "LV2"; - else if (m_type == DSSI) return "DSSI"; - else if (m_type == Internal) return "Internal"; - else if (m_type == Patch) return "Patch"; - else return ""; - } - - void set_type(const string& type_string) { - if (type_string == "LADSPA") m_type = LADSPA; - else if (type_string == "LV2") m_type = LV2; - else if (type_string == "DSSI") m_type = DSSI; - else if (type_string == "Internal") m_type = Internal; - else if (type_string == "Patch") m_type = Patch; - } - - // FIXME: ew -#ifdef HAVE_SLV2 - SLV2Plugin* slv2_plugin() { return m_slv2_plugin; } - void slv2_plugin(const SLV2Plugin* p) { m_slv2_plugin = p; } - -#endif -private: - // Disallow copies (undefined) - Plugin(const Plugin&); - Plugin& operator=(const Plugin&); - - Type m_type; - string m_uri; ///< LV2 only - string m_lib_path; ///< LADSPA/DSSI only - string m_plug_label; ///< LADSPA/DSSI only - string m_name; ///< LADSPA/DSSI only - unsigned long m_id; ///< LADSPA/DSSI only - - PluginLibrary* m_library; - -#ifdef HAVE_SLV2 - SLV2Plugin* m_slv2_plugin; -#endif -}; - - -} // namespace Om - -#endif // PLUGIN_H - diff --git a/src/engine/PluginLibrary.h b/src/engine/PluginLibrary.h deleted file mode 100644 index 53279d8a..00000000 --- a/src/engine/PluginLibrary.h +++ /dev/null @@ -1,100 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef PLUGINLIBRARY_H -#define PLUGINLIBRARY_H - -#include -#include -#include -using std::string; -using std::cerr; using std::endl; - - -namespace Om { - - -/** Representation of a shared library containing at least one Plugin. - * - * In the NodeFactory, this represents one loaded shared library instance, - * which is what handle() returns. - */ -class PluginLibrary -{ -public: - /** Construct a new PluginLibrary. - * - * Path is assumed to be the path of a valid shared library that can be - * successfully dlopen'ed. - */ - PluginLibrary(const string& path) - : m_path(path), m_handle(NULL) - {} - - ~PluginLibrary() - { - close(); - } - - /** Load and resolve all symbols in this shared library - * (dlopen with RTLD_NOW). - * - * It is okay to call this many times, the library will only be opened - * once. - */ - void open() - { - if (m_handle == NULL) { - dlerror(); - m_handle = dlopen(m_path.c_str(), RTLD_NOW); - if (m_handle == NULL) - cerr << "[PluginLibrary] Warning: Error opening shared library " - << m_path << "(" << dlerror() << ")" << endl; - } - } - - /** Close the dynamic library. - * - * This can be called on an already closed PluginLibrary without problems. - */ - void close() - { - if (m_handle != NULL) { - dlerror(); - if (dlclose(m_handle)) - cerr << "[PluginLibrary] Error closing shared library " << m_path - << "(" << dlerror() << ")" << endl; - } - m_handle = NULL; - } - - void* handle() const { return m_handle; } - -private: - // Disallow copies (undefined) - PluginLibrary(const PluginLibrary&); - PluginLibrary& operator=(const PluginLibrary&); - - string m_path; - void* m_handle; -}; - - -} // namespace Om - -#endif // PLUGINLIBRARY_H - diff --git a/src/engine/Port.cpp b/src/engine/Port.cpp deleted file mode 100644 index 987d232d..00000000 --- a/src/engine/Port.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Port.h" -#include "Node.h" -#include "PortInfo.h" -#include "Om.h" -#include "OmApp.h" -#include "ObjectStore.h" - -namespace Om { - -Port::Port(Node* const node, const string& name, size_t index, size_t poly, PortInfo* port_info) -: OmObject(node, name), - m_index(index), - m_poly(poly), - m_port_info(port_info) -{ - assert(node != NULL); - assert(port_info != NULL); - assert(m_poly > 0); -} - - -void -Port::add_to_store() -{ - om->object_store()->add(this); -} - - -void -Port::remove_from_store() -{ - // Remove self - TreeNode* node = om->object_store()->remove(path()); - assert(node != NULL); - assert(om->object_store()->find(path()) == NULL); - delete node; -} - - -} // namespace Om diff --git a/src/engine/Port.h b/src/engine/Port.h deleted file mode 100644 index f51d7382..00000000 --- a/src/engine/Port.h +++ /dev/null @@ -1,80 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PORT_H -#define PORT_H - -#include -#include -#include "util/types.h" -#include "OmObject.h" - -using std::string; - -namespace Om { - -class Node; -class PortInfo; - - -/** A port on a Node. - * - * This is a non-template abstract base class, which basically exists so - * things can pass around Port pointers and not have to worry about type, - * templates, etc. - * - * \ingroup engine - */ -class Port : public OmObject -{ -public: - virtual ~Port() {} - - Port* as_port() { return this; } - - PortInfo* port_info() const { return m_port_info; } - void port_info(PortInfo* pi) { m_port_info = pi; } - - void add_to_store(); - void remove_from_store(); - - /** Called once per process cycle */ - virtual void prepare_buffers(size_t nframes) = 0; - - /** Empty buffer contents completely (ie silence) */ - virtual void clear_buffers() = 0; - - Node* parent_node() const { return m_parent->as_node(); } - bool is_sample() const { return false; } - size_t num() const { return m_index; } - size_t poly() const { return m_poly; } - -protected: - Port(Node* const node, const string& name, size_t index, size_t poly, PortInfo* port_info); - - // Prevent copies (undefined) - Port(const Port&); - Port& operator=(const Port&); - - size_t m_index; - size_t m_poly; - PortInfo* m_port_info; -}; - - -} // namespace Om - -#endif // PORT_H diff --git a/src/engine/PortBase.cpp b/src/engine/PortBase.cpp deleted file mode 100644 index 3d8dbc67..00000000 --- a/src/engine/PortBase.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "PortBase.h" -#include -#include -#include -#include -#include -#include "util.h" -#include "Node.h" -#include "PortInfo.h" -#include "MidiMessage.h" - -namespace Om { - - -/** Constructor for a Port. - */ -template -PortBase::PortBase(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size) -: Port(node, name, index, poly, port_info), - m_buffer_size(buffer_size), - m_fixed_buffers(false), - m_is_tied(false), - m_tied_port(NULL) -{ - allocate_buffers(); - clear_buffers(); - - assert(m_buffers.size() > 0); -} -template -PortBase::PortBase(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); -template -PortBase::PortBase(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); - - -template -PortBase::~PortBase() -{ - for (size_t i=0; i < m_poly; ++i) - delete m_buffers.at(i); - - delete m_port_info; -} -template PortBase::~PortBase(); -template PortBase::~PortBase(); - - -/** Set the port's value for all voices. - */ -template<> -void -PortBase::set_value(sample val, size_t offset) -{ - if (m_port_info->is_control()) - offset = 0; - assert(offset < m_buffer_size); - - for (size_t v=0; v < m_poly; ++v) - m_buffers.at(v)->set(val, offset); -} - -/** Set the port's value for a specific voice. - */ -template<> -void -PortBase::set_value(size_t voice, sample val, size_t offset) -{ - if (m_port_info->is_control()) - offset = 0; - assert(offset < m_buffer_size); - - m_buffers.at(voice)->set(val, offset); -} - - -template -void -PortBase::allocate_buffers() -{ - m_buffers.alloc(m_poly); - - for (size_t i=0; i < m_poly; ++i) - m_buffers.at(i) = new Buffer(m_buffer_size); -} -template void PortBase::allocate_buffers(); -template void PortBase::allocate_buffers(); - - -template<> -void -PortBase::prepare_buffers(size_t nframes) -{ - for (size_t i=0; i < m_poly; ++i) - m_buffers.at(i)->prepare(nframes); -} - - -template<> -void -PortBase::prepare_buffers(size_t nframes) -{ -} - - -template -void -PortBase::clear_buffers() -{ - for (size_t i=0; i < m_poly; ++i) - m_buffers.at(i)->clear(); -} -template void PortBase::clear_buffers(); -template void PortBase::clear_buffers(); - - -} // namespace Om - diff --git a/src/engine/PortBase.h b/src/engine/PortBase.h deleted file mode 100644 index 9962538e..00000000 --- a/src/engine/PortBase.h +++ /dev/null @@ -1,87 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PORTBASE_H -#define PORTBASE_H - -#include -#include "util/types.h" -#include "Array.h" -#include "Port.h" -#include "Buffer.h" - -using std::string; - -namespace Om { - -class MidiMessage; -class Node; - - -/** A port (with a type). - * - * This is basically just a buffer and a bunch of flags and helper methods. - * All the interesting functionality of ports is in InputPort. - * - * \ingroup engine - */ -template -class PortBase : public Port -{ -public: - virtual ~PortBase(); - - void set_value(size_t voice, T val, size_t offset); - void set_value(T val, size_t offset); - - Buffer* buffer(size_t voice) const { return m_buffers.at(voice); } - - virtual void prepare_buffers(size_t nframes); - virtual void clear_buffers(); - - PortBase* tied_port() const { return m_tied_port; } - void untie() { m_is_tied = false; m_tied_port = NULL; } - - size_t buffer_size() const { return m_buffer_size; } - - /** Used by drivers to prevent port from changing buffers */ - void fixed_buffers(bool b) { m_fixed_buffers = b; } - bool fixed_buffers() { return m_fixed_buffers; } - -protected: - PortBase(Node* const node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); - - // Prevent copies (undefined) - PortBase(const PortBase& copy); - PortBase& operator=(const Port&); - - void allocate_buffers(); - - size_t m_buffer_size; - bool m_fixed_buffers; - bool m_is_tied; - PortBase* m_tied_port; - - Array*> m_buffers; -}; - - -template class PortBase; -template class PortBase; - -} // namespace Om - -#endif // PORTBASE_H diff --git a/src/engine/PortInfo.h b/src/engine/PortInfo.h deleted file mode 100644 index 3fa4215a..00000000 --- a/src/engine/PortInfo.h +++ /dev/null @@ -1,153 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef PORTINFO_H -#define PORTINFO_H - -#include -#include -#include - -using std::string; - -namespace Om { - - -enum PortType { CONTROL, AUDIO, MIDI }; -enum PortDirection { INPUT = 0, OUTPUT = 1 }; // FIXME: dupe of ClientInterface::PortDirection -enum PortHint { NONE, INTEGER, TOGGLE, LOGARITHMIC }; - - -/** Information about a Port. - * - * I'm not sure this actually has a reason for existing anymore. This is the - * model for a Port, but no other OmObjects need a model, soo.... - * - * \ingroup engine - */ -class PortInfo -{ -public: - PortInfo(const string& port_name, PortType type, PortDirection dir, PortHint hint, float default_val, float min, float max) - : m_name(port_name), - m_type(type), - m_direction(dir), - m_hint(hint), - m_default_val(default_val), - m_min_val(min), - m_max_val(max) - {} - - PortInfo(const string& port_name, PortType type, PortDirection dir, float default_val, float min, float max) - : m_name(port_name), - m_type(type), - m_direction(dir), - m_hint(NONE), - m_default_val(default_val), - m_min_val(min), - m_max_val(max) - {} - - PortInfo(const string& port_name, PortType type, PortDirection dir, PortHint hint = NONE) - : m_name(port_name), - m_type(type), - m_direction(dir), - m_hint(hint), - m_default_val(0.0f), - m_min_val(0.0f), - m_max_val(1.0f) - {} - - PortInfo(const string& port_name, LADSPA_PortDescriptor d, LADSPA_PortRangeHintDescriptor hint) - : m_name(port_name), - m_default_val(1.0f), - m_min_val(0.0f), - m_max_val(1.0f) - { - if (LADSPA_IS_PORT_AUDIO(d)) m_type = AUDIO; - else if (LADSPA_IS_PORT_CONTROL(d)) m_type = CONTROL; - else exit(EXIT_FAILURE); - - if (LADSPA_IS_PORT_INPUT(d)) m_direction = INPUT; - else if (LADSPA_IS_PORT_OUTPUT(d)) m_direction = OUTPUT; - else exit(EXIT_FAILURE); - - if (LADSPA_IS_HINT_TOGGLED(hint)) { - m_hint = TOGGLE; m_min_val = 0; m_max_val = 1; m_default_val = 0; - } else if (LADSPA_IS_HINT_LOGARITHMIC(hint)) - m_hint = LOGARITHMIC; - else if (LADSPA_IS_HINT_INTEGER(hint)) - m_hint = INTEGER; - else - m_hint = NONE; - } - - PortType type() const { return m_type; } - void type(PortType t) { m_type = t; } - float min_val() const { return m_min_val; } - void min_val(float f) { m_min_val = f; } - float default_val() const { return m_default_val; } - void default_val(float f) { m_default_val = f; } - float max_val() const { return m_max_val; } - void max_val(float f) { m_max_val = f; } - PortDirection direction() const { return m_direction; } - - string type_string() { - switch (m_type) { - case CONTROL: return "CONTROL"; break; - case AUDIO: return "AUDIO"; break; - case MIDI: return "MIDI"; break; - default: return "UNKNOWN"; - } - } - string direction_string() { if (m_direction == INPUT) return "INPUT"; else return "OUTPUT"; } - string hint_string() { if (m_hint == INTEGER) return "INTEGER"; - else if (m_hint == LOGARITHMIC) return "LOGARITHMIC"; - else if (m_hint == TOGGLE) return "TOGGLE"; - else return "NONE"; } - - bool is_control() const { return (m_type == CONTROL); } - bool is_audio() const { return (m_type == AUDIO); } - bool is_midi() const { return (m_type == MIDI); } - bool is_input() const { return (m_direction == INPUT); } - bool is_output() const { return (m_direction == OUTPUT); } - - bool is_logarithmic() const { return (m_hint == LOGARITHMIC); } - bool is_integer() const { return (m_hint == INTEGER); } - bool is_toggle() const { return (m_hint == TOGGLE); } - - const string& name() const { return m_name; } - void name(const string& n) { m_name = n; } - -private: - // Prevent copies (undefined) - PortInfo(const PortInfo&); - PortInfo& operator=(const PortInfo&); - - string m_name; - PortType m_type; - PortDirection m_direction; - PortHint m_hint; - float m_default_val; - float m_min_val; - float m_max_val; -}; - - -} // namespace Om - -#endif // PORTINFO_H diff --git a/src/engine/PostProcessor.cpp b/src/engine/PostProcessor.cpp deleted file mode 100644 index 65b92015..00000000 --- a/src/engine/PostProcessor.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "PostProcessor.h" -#include -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "Event.h" -#include "util/Queue.h" -#include "Maid.h" - - -using std::cerr; using std::cout; using std::endl; - -namespace Om { - -bool PostProcessor::m_process_thread_exit_flag = false; - - -PostProcessor::PostProcessor(size_t queue_size) -: m_events(queue_size), - m_thread_exists(false), - m_semaphore(0) -{ -} - - -PostProcessor::~PostProcessor() -{ - stop(); -} - - -/** Start the process thread. - */ -void -PostProcessor::start() -{ - cout << "[PostProcessor] Starting." << endl; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, 1500000); - - pthread_create(&m_process_thread, &attr, process_events, this); - m_thread_exists = true; -} - - -/** Stop the process thread. - */ -void -PostProcessor::stop() -{ - if (m_thread_exists) { - m_process_thread_exit_flag = true; - pthread_cancel(m_process_thread); - pthread_join(m_process_thread, NULL); - m_thread_exists = false; - } -} - - -/** Signal the PostProcessor to process all pending events. - */ -void -PostProcessor::signal() -{ - m_semaphore.post(); -} - - -void* -PostProcessor::process_events(void* osc_processer) -{ - PostProcessor* me = (PostProcessor*)osc_processer; - return me->m_process_events(); -} - - -/** OSC message processing thread. - */ -void* -PostProcessor::m_process_events() -{ - Event* ev = NULL; - - while (true) { - m_semaphore.wait(); - - if (m_process_thread_exit_flag) - break; - - while (!m_events.is_empty()) { - ev = m_events.pop(); - assert(ev != NULL); - ev->post_process(); - om->maid()->push(ev); - } - } - - cout << "[PostProcessor] Exiting post processor thread." << endl; - - return NULL; -} - -} // namespace Om diff --git a/src/engine/PostProcessor.h b/src/engine/PostProcessor.h deleted file mode 100644 index 843569d8..00000000 --- a/src/engine/PostProcessor.h +++ /dev/null @@ -1,78 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef POSTPROCESSOR_H -#define POSTPROCESSOR_H - -#include -#include "util/types.h" -#include "util/Queue.h" -#include "util/Semaphore.h" - -namespace Om { - -class Event; - - -/** Processor for Events after leaving the audio thread. - * - * The audio thread pushes events to this when it is done with them (which - * is realtime-safe), which signals the processing thread through a semaphore - * to handle the event and pass it on to the Maid. - * - * \ingroup engine - */ -class PostProcessor -{ -public: - PostProcessor(size_t queue_size); - ~PostProcessor(); - - void start(); - void stop(); - - inline void push(Event* const ev); - void signal(); - -private: - // Prevent copies - PostProcessor(const PostProcessor&); - PostProcessor& operator=(const PostProcessor&); - - Queue m_events; - - static void* process_events(void* me); - void* m_process_events(); - - pthread_t m_process_thread; - bool m_thread_exists; - static bool m_process_thread_exit_flag; - Semaphore m_semaphore; -}; - - -/** Push an event on to the process queue, realtime-safe, not thread-safe. - */ -inline void -PostProcessor::push(Event* const ev) -{ - m_events.push(ev); -} - - -} // namespace Om - -#endif // POSTPROCESSOR_H diff --git a/src/engine/QueuedEngineInterface.cpp b/src/engine/QueuedEngineInterface.cpp deleted file mode 100644 index 0734eb7a..00000000 --- a/src/engine/QueuedEngineInterface.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "QueuedEngineInterface.h" -#include "QueuedEventSource.h" -#include "events.h" -#include "Om.h" -#include "util/Queue.h" -#include "OmApp.h" - -namespace Om { - -QueuedEngineInterface::QueuedEngineInterface(size_t queue_size) -: QueuedEventSource(queue_size) -, _responder(CountedPtr(new Responder())) // NULL responder -{ -} - - -/** Set the Responder to send responses to commands with, once the commands - * are preprocessed and ready to be executed (or not). - * - * Ownership of @a responder is taken. - */ -void -QueuedEngineInterface::set_responder(CountedPtr responder) -{ - //cerr << "SET\n"; - _responder = responder; -} - - -void -QueuedEngineInterface::disable_responses() -{ - static CountedPtr null_responder(new Responder()); - //cerr << "DISABLE\n"; - set_responder(null_responder); -} - - -/* *** EngineInterface implementation below here *** */ - - -void -QueuedEngineInterface::register_client(ClientKey key, CountedPtr client) -{ - RegisterClientEvent* ev = new RegisterClientEvent(_responder, key, client); - push(ev); -} - - -void -QueuedEngineInterface::unregister_client(ClientKey key) -{ - UnregisterClientEvent* ev = new UnregisterClientEvent(_responder, key); - push(ev); -} - - - -// Engine commands -void -QueuedEngineInterface::load_plugins() -{ - LoadPluginsEvent* ev = new LoadPluginsEvent(_responder); - push(ev); - -} - - -void -QueuedEngineInterface::activate() -{ - ActivateEvent* ev = new ActivateEvent(_responder); - push(ev); -} - - -void -QueuedEngineInterface::deactivate() -{ - DeactivateEvent* ev = new DeactivateEvent(_responder); - push(ev); -} - - -void -QueuedEngineInterface::quit() -{ - _responder->respond_ok(); - om->quit(); -} - - - -// Object commands - -void -QueuedEngineInterface::create_patch(const string& path, - uint32_t poly) -{ - CreatePatchEvent* ev = new CreatePatchEvent(_responder, path, poly); - push(ev); - -} - - -void -QueuedEngineInterface::create_node(const string& path, - const string& plugin_type, - const string& plugin_uri, - bool polyphonic) -{ - // FIXME: ew - - Plugin* plugin = new Plugin(); - plugin->set_type(plugin_type); - plugin->uri(plugin_uri); - - AddNodeEvent* ev = new AddNodeEvent(_responder, - path, plugin, polyphonic); - push(ev); -} - - -void -QueuedEngineInterface::rename(const string& old_path, - const string& new_name) -{ - RenameEvent* ev = new RenameEvent(_responder, old_path, new_name); - push(ev); -} - - -void -QueuedEngineInterface::destroy(const string& path) -{ - DestroyEvent* ev = new DestroyEvent(_responder, path); - push(ev); -} - - -void -QueuedEngineInterface::clear_patch(const string& patch_path) -{ -} - - -void -QueuedEngineInterface::enable_patch(const string& patch_path) -{ - EnablePatchEvent* ev = new EnablePatchEvent(_responder, patch_path); - push(ev); -} - - -void -QueuedEngineInterface::disable_patch(const string& patch_path) -{ - DisablePatchEvent* ev = new DisablePatchEvent(_responder, patch_path); - push(ev); -} - - -void -QueuedEngineInterface::connect(const string& src_port_path, - const string& dst_port_path) -{ - ConnectionEvent* ev = new ConnectionEvent(_responder, src_port_path, dst_port_path); - push(ev); - -} - - -void -QueuedEngineInterface::disconnect(const string& src_port_path, - const string& dst_port_path) -{ - DisconnectionEvent* ev = new DisconnectionEvent(_responder, src_port_path, dst_port_path); - push(ev); -} - - -void -QueuedEngineInterface::disconnect_all(const string& node_path) -{ - DisconnectNodeEvent* ev = new DisconnectNodeEvent(_responder, node_path); - push(ev); -} - - -void -QueuedEngineInterface::set_port_value(const string& port_path, - float value) -{ - SetPortValueEvent* ev = new SetPortValueEvent(_responder, port_path, value); - om->event_queue()->push(ev); -} - - -void -QueuedEngineInterface::set_port_value(const string& port_path, - uint32_t voice, - float value) -{ - SetPortValueEvent* ev = new SetPortValueEvent(_responder, voice, port_path, value); - om->event_queue()->push(ev); -} - - -void -QueuedEngineInterface::set_port_value_queued(const string& port_path, - float value) -{ - SetPortValueQueuedEvent* ev = new SetPortValueQueuedEvent(_responder, port_path, value); - push(ev); -} - - -void -QueuedEngineInterface::set_program(const string& node_path, - uint32_t bank, - uint32_t program) -{ - push(new DSSIProgramEvent(_responder, node_path, bank, program)); -} - - -void -QueuedEngineInterface::midi_learn(const string& node_path) -{ - MidiLearnEvent* ev = new MidiLearnEvent(_responder, node_path); - push(ev); -} - - -void -QueuedEngineInterface::set_metadata(const string& path, - const string& predicate, - const string& value) -{ - SetMetadataEvent* ev = new SetMetadataEvent(_responder, - path, predicate, value); - - push(ev); -} - - -// Requests // - -void -QueuedEngineInterface::ping() -{ - PingQueuedEvent* ev = new PingQueuedEvent(_responder); - push(ev); -} - - -void -QueuedEngineInterface::request_port_value(const string& port_path) -{ - RequestPortValueEvent* ev = new RequestPortValueEvent(_responder, port_path); - push(ev); -} - - -void -QueuedEngineInterface::request_plugins() -{ - RequestPluginsEvent* ev = new RequestPluginsEvent(_responder); - push(ev); -} - - -void -QueuedEngineInterface::request_all_objects() -{ - RequestAllObjectsEvent* ev = new RequestAllObjectsEvent(_responder); - push(ev); -} - - -} // namespace Om - - diff --git a/src/engine/QueuedEngineInterface.h b/src/engine/QueuedEngineInterface.h deleted file mode 100644 index cc9c575f..00000000 --- a/src/engine/QueuedEngineInterface.h +++ /dev/null @@ -1,145 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef QUEUEDENGINEINTERFACE_H -#define QUEUEDENGINEINTERFACE_H - -#include -#include -#include -#include "util/CountedPtr.h" -#include "interface/ClientInterface.h" -#include "interface/ClientKey.h" -#include "QueuedEventSource.h" -#include "Responder.h" -using std::string; - -namespace Om { - -using Shared::ClientKey; -using Shared::ClientInterface; - - -/** A queued (preprocessed) event source / interface. - * - * This is the bridge between the EngineInterface presented to the client, and - * the EventSource that needs to be presented to the AudioDriver. - * - * This is sort of a state machine, \ref set_responder sets the Responder that - * will be used to send the response from all future function calls. Stateless - * protocols like UDP/OSC can use this to set a different response address for - * each event (eg incoming UDP port), but engine/client interfaces that don't - * need to change an 'address' constantly can just set it once on initialisation. - * Blocking control interfaces can be made by setting a Responder which signals - * the caller when the 'response' is 'sent'. - * - * If you do not register a responder, you have no way of knowing if your calls - * are successful. - * - * FIXME: this isn't really "queued" entirely, since some events aren't queued - * events and get pushed directly into the realtime event queue. Should that - * be separated into a different interface/client? - */ -class QueuedEngineInterface : public Om::QueuedEventSource -{ -public: - QueuedEngineInterface(size_t queue_size); - virtual ~QueuedEngineInterface() {} - - virtual void set_responder(CountedPtr responder); - virtual void disable_responses(); - - // Client registration - virtual void register_client(ClientKey key, CountedPtr client); - virtual void unregister_client(ClientKey key); - - - // Engine commands - virtual void load_plugins(); - virtual void activate(); - virtual void deactivate(); - virtual void quit(); - - // Object commands - - virtual void create_patch(const string& path, - uint32_t poly); - - virtual void create_node(const string& path, - const string& plugin_type, - const string& plugin_uri, - bool polyphonic); - - virtual void rename(const string& old_path, - const string& new_name); - - virtual void destroy(const string& path); - - virtual void clear_patch(const string& patch_path); - - virtual void enable_patch(const string& patch_path); - - virtual void disable_patch(const string& patch_path); - - virtual void connect(const string& src_port_path, - const string& dst_port_path); - - virtual void disconnect(const string& src_port_path, - const string& dst_port_path); - - virtual void disconnect_all(const string& node_path); - - virtual void set_port_value(const string& port_path, - float val); - - virtual void set_port_value(const string& port_path, - uint32_t voice, - float val); - - virtual void set_port_value_queued(const string& port_path, - float val); - - virtual void set_program(const string& node_path, - uint32_t bank, - uint32_t program); - - virtual void midi_learn(const string& node_path); - - virtual void set_metadata(const string& path, - const string& predicate, - const string& value); - - // Requests // - - virtual void ping(); - - virtual void request_port_value(const string& port_path); - - virtual void request_plugins(); - - virtual void request_all_objects(); - -protected: - - /** Where responses to current messages will go. */ - CountedPtr _responder; -}; - - -} // namespace Om - -#endif // QUEUEDENGINEINTERFACE_H - diff --git a/src/engine/QueuedEvent.h b/src/engine/QueuedEvent.h deleted file mode 100644 index 16560aaa..00000000 --- a/src/engine/QueuedEvent.h +++ /dev/null @@ -1,86 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef QUEUEDEVENT_H -#define QUEUEDEVENT_H - -#include "Event.h" - -namespace Om { - -class Responder; -class QueuedEventSource; - - -/** An Event with a not-time-critical preprocessing stage. - * - * These events are events that aren't able to be executed immediately by the - * Jack thread (because they allocate memory or whatever). They are pushed - * on to the QueuedEventQueue where they are preprocessed then pushed on - * to the realtime Event Queue when they are ready. - * - * Lookups for these events should go in the pre_process() method, since they are - * not time critical and shouldn't waste time in the audio thread doing - * lookups they can do beforehand. (This applies for any expensive operation that - * could be done before the execute() method). - * - * \ingroup engine - */ -class QueuedEvent : public Event -{ -public: - /** Process this event into a realtime-suitable event. - */ - virtual void pre_process() { - assert(m_pre_processed == false); - m_pre_processed = true; - } - - virtual void execute(samplecount offset) { - assert(m_pre_processed); - Event::execute(offset); - } - - virtual void post_process() {} - - /** If this event blocks the prepare phase of other slow events */ - bool is_blocking() { return m_blocking; } - - bool is_prepared() { return m_pre_processed; } - -protected: - // Prevent copies - QueuedEvent(const QueuedEvent& copy); - QueuedEvent& operator=(const QueuedEvent&); - - QueuedEvent(CountedPtr responder, bool blocking = false, QueuedEventSource* source=NULL) - : Event(responder), m_pre_processed(false), m_blocking(blocking), m_source(source) - {} - - // NULL event base (for internal events) - QueuedEvent() - : Event(), m_pre_processed(false), m_blocking(false), m_source(NULL) - {} - - bool m_pre_processed; - bool m_blocking; - QueuedEventSource* m_source; -}; - - -} // namespace Om - -#endif // QUEUEDEVENT_H diff --git a/src/engine/QueuedEventSource.cpp b/src/engine/QueuedEventSource.cpp deleted file mode 100644 index 953eb5b1..00000000 --- a/src/engine/QueuedEventSource.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "QueuedEventSource.h" -#include "QueuedEvent.h" -#include -#include -using std::cout; using std::cerr; using std::endl; - - -namespace Om { - - -QueuedEventSource::QueuedEventSource(size_t size) -: m_front(0), - m_back(0), - m_prepared_back(0), - m_size(size+1), - m_thread_exists(false), - m_prepare_thread_exit_flag(false), - m_semaphore(0) -{ - m_events = (QueuedEvent**)calloc(m_size, sizeof(QueuedEvent*)); - - pthread_mutex_init(&m_blocking_mutex, NULL); - pthread_cond_init(&m_blocking_cond, NULL); - - mlock(m_events, m_size * sizeof(QueuedEvent*)); -} - - -QueuedEventSource::~QueuedEventSource() -{ - stop(); - - free(m_events); - pthread_mutex_destroy(&m_blocking_mutex); - pthread_cond_destroy(&m_blocking_cond); -} - - -/** Start the prepare thread. - */ -void -QueuedEventSource::start() -{ - if (m_thread_exists) { - cerr << "[QueuedEventSource] Thread already launched?" << endl; - return; - } else { - cout << "[QueuedEventSource] Launching thread." << endl; - } - - m_prepare_thread_exit_flag = false; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, 1500000); - - pthread_create(&m_prepare_thread, &attr, &QueuedEventSource::prepare_loop, this); - pthread_attr_destroy(&attr); - - m_thread_exists = true; -} - - -/** Destroy the prepare thread. - */ -void -QueuedEventSource::stop() -{ - if (m_thread_exists) { - m_prepare_thread_exit_flag = true; - pthread_cancel(m_prepare_thread); - pthread_join(m_prepare_thread, NULL); - m_thread_exists = false; - cout << "[QueuedEventSource] Stopped thread." << endl; - } -} - - -/** Push an unprepared event onto the queue. - */ -void -QueuedEventSource::push(QueuedEvent* const ev) -{ - assert(!ev->is_prepared()); - - if (m_events[m_back] != NULL) { - cerr << "[QueuedEventSource] Error: Queue is full! Event is lost, please report!" << endl; - delete ev; - } else { - m_events[m_back] = ev; - m_back = (m_back + 1) % m_size; - m_semaphore.post(); - } -} - - -/** Pops the prepared event at the front of the queue, if it exists. - * - * This method will only pop events that have been prepared, and are - * stamped before the time passed. In other words, it may return NULL - * even if there are events pending in the queue. The events returned are - * actually QueuedEvent*s, but after this they are "normal" events and the - * engine deals with them just like a realtime in-band event. - */ -Event* -QueuedEventSource::pop_earliest_event_before(const samplecount time) -{ - QueuedEvent* front_event = m_events[m_front]; - - // Pop - if (front_event != NULL && front_event->time_stamp() < time && front_event->is_prepared()) { - m_events[m_front] = NULL; - m_front = (m_front + 1) % m_size; - return front_event; - } else { - return NULL; - } -} - - -// Private // - - - -/** Signal that the blocking event is finished. - * - * When this is called preparing will resume. This will be called by - * blocking events in their post_process() method. - */ -void -QueuedEventSource::unblock() -{ - /* FIXME: Make this a semaphore, and have events signal at the end of their - * execute() methods so the preprocessor can start preparing events immediately - * instead of waiting for the postprocessor to get around to finalizing the event? */ - pthread_mutex_lock(&m_blocking_mutex); - pthread_cond_signal(&m_blocking_cond); - pthread_mutex_unlock(&m_blocking_mutex); -} - - -void* -QueuedEventSource::m_prepare_loop() -{ - QueuedEvent* ev = NULL; - - while (true) { - m_semaphore.wait(); - - if (m_prepare_thread_exit_flag) - break; // exit signalled - - ev = m_events[m_prepared_back]; - assert(ev != NULL); - - if (ev == NULL) { - cerr << "[QueuedEventSource] ERROR: Signalled, but event is NULL." << endl; - continue; - } - - assert(ev != NULL); - assert(!ev->is_prepared()); - - if (ev->is_blocking()) - pthread_mutex_lock(&m_blocking_mutex); - - ev->pre_process(); - - m_prepared_back = (m_prepared_back+1) % m_size; - - // If a blocking event, wait for event to finish passing through - // the audio cycle before preparing the next event - if (ev->is_blocking()) { - pthread_cond_wait(&m_blocking_cond, &m_blocking_mutex); - pthread_mutex_unlock(&m_blocking_mutex); - } - } - - cout << "[QueuedEventSource] Exiting slow event queue thread." << endl; - return NULL; -} - - -} // namespace Om - diff --git a/src/engine/QueuedEventSource.h b/src/engine/QueuedEventSource.h deleted file mode 100644 index 002fc642..00000000 --- a/src/engine/QueuedEventSource.h +++ /dev/null @@ -1,83 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef QUEUEDEVENTSOURCE_H -#define QUEUEDEVENTSOURCE_H - -#include -#include -#include "util/types.h" -#include "util/Semaphore.h" -#include "EventSource.h" - -namespace Om { - -class Event; -class QueuedEvent; - - -/** Queue of events that need processing before reaching the audio thread. - * - * Implemented as a deque (ringbuffer) in a circular array. Pushing and - * popping are threadsafe, as long as a single thread pushes and a single - * thread pops (ie this data structure is threadsafe, but the push and pop - * methods themselves are not). - */ -class QueuedEventSource : public EventSource -{ -public: - QueuedEventSource(size_t size); - ~QueuedEventSource(); - - Event* pop_earliest_event_before(const samplecount time); - - void unblock(); - - void start(); - void stop(); - -protected: - void push(QueuedEvent* const ev); - -private: - // Prevent copies (undefined) - QueuedEventSource(const QueuedEventSource&); - QueuedEventSource& operator=(const QueuedEventSource&); - - // Note that it's crucially important which functions access which of these - // variables, to maintain threadsafeness. - - size_t m_front; ///< Front of queue - size_t m_back; ///< Back of entire queue (1 past index of back element) - size_t m_prepared_back; ///< Back of prepared section (1 past index of back prepared element) - const size_t m_size; - QueuedEvent** m_events; - - bool m_thread_exists; - bool m_prepare_thread_exit_flag; - pthread_t m_prepare_thread; - Semaphore m_semaphore; ///< Counting semaphor for driving prepare thread - pthread_mutex_t m_blocking_mutex; - pthread_cond_t m_blocking_cond; - - static void* prepare_loop(void* q) { return ((QueuedEventSource*)q)->m_prepare_loop(); } - void* m_prepare_loop(); -}; - - -} // namespace Om - -#endif // QUEUEDEVENTSOURCE_H diff --git a/src/engine/Responder.h b/src/engine/Responder.h deleted file mode 100644 index cf16a20a..00000000 --- a/src/engine/Responder.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef RESPONDER_H -#define RESPONDER_H - -#include -#include -#include "util/CountedPtr.h" -#include "interface/ClientInterface.h" -using std::string; - -namespace Om { - -using Shared::ClientInterface; - - -/** Class to handle responding to clients. - * - * This is an abstract base class to fully abstract the details of client - * communication from the internals of the engine. - * - * Note that this class only handles sending responses to commands from - * clients, (ie OK or an error), not notifications (ie new node, - * disconnection) - that's what ClientInterface is for. If a command is - * a request, \ref find_client can find the corresponding ClientInterface - * for this client to send the reply to. - * - * ClientInterface and Responder are seperate because responding might not - * actually get exposed to the client interface (eg in simulated blocking - * interfaces that wait for responses before returning). - */ -class Responder -{ -public: - Responder() {} - virtual ~Responder() {} - - virtual CountedPtr find_client() - { return CountedPtr(NULL); } - - virtual void respond_ok() {} - virtual void respond_error(const string& msg) {} -}; - - -} // namespace Om - -#endif // RESPONDER_H - diff --git a/src/engine/TransportNode.cpp b/src/engine/TransportNode.cpp deleted file mode 100644 index f5183d56..00000000 --- a/src/engine/TransportNode.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "TransportNode.h" -#include -#include "OutputPort.h" -#include "Plugin.h" -#include "JackAudioDriver.h" -#include "Port.h" -#include "util.h" -#include "Om.h" -#include "OmApp.h" -#include "PortInfo.h" - -namespace Om { - - -TransportNode::TransportNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) -: InternalNode(path, 1, parent, srate, buffer_size) -{ - m_num_ports = 10; - m_ports.alloc(m_num_ports); - - OutputPort* spb_port = new OutputPort(this, "Seconds per Beat", 0, 1, - new PortInfo("Seconds per Beat", CONTROL, OUTPUT, 0, 0, 1), 1); - m_ports.at(0) = spb_port; - - OutputPort* bpb_port = new OutputPort(this, "Beats per Bar", 1, 1, - new PortInfo("Beats per Bar", CONTROL, OUTPUT, 0, 0, 1), 1); - m_ports.at(1) = bpb_port; - - OutputPort* bar_port = new OutputPort(this, "Bar", 3, 1, - new PortInfo("Bar", CONTROL, OUTPUT, 0, 0, 1), buffer_size); - m_ports.at(2) = bar_port; - - OutputPort* beat_port = new OutputPort(this, "Beat", 3, 1, - new PortInfo("Beat", CONTROL, OUTPUT, 0, 0, 1), buffer_size); - m_ports.at(3) = beat_port; - - OutputPort* frame_port = new OutputPort(this, "Frame", 3, 1, - new PortInfo("Frame", CONTROL, OUTPUT, 0, 0, 1), buffer_size); - m_ports.at(4) = frame_port; - - OutputPort* hour_port = new OutputPort(this, "Hour", 3, 1, - new PortInfo("Hour", CONTROL, OUTPUT, 0, 0, 1), buffer_size); - m_ports.at(5) = hour_port; - - OutputPort* minute_port = new OutputPort(this, "Minute", 3, 1, - new PortInfo("Minute", CONTROL, OUTPUT, 0, 0, 1), buffer_size); - m_ports.at(6) = minute_port; - - OutputPort* second_port = new OutputPort(this, "Second", 3, 1, - new PortInfo("Second", CONTROL, OUTPUT, 0, 0, 1), buffer_size); - m_ports.at(7) = second_port; - - OutputPort* trg_port = new OutputPort(this, "Beat Tick", 2, 1, - new PortInfo("Beat Tick", AUDIO, OUTPUT, 0, 0, 1), buffer_size); - m_ports.at(8) = trg_port; - - OutputPort* bar_trig_port = new OutputPort(this, "Bar Tick", 3, 1, - new PortInfo("Bar Tick", AUDIO, OUTPUT, 0, 0, 1), buffer_size); - m_ports.at(9) = bar_trig_port; - - m_plugin.type(Plugin::Internal); - m_plugin.plug_label("transport"); - m_plugin.name("Om Transport Node (BROKEN)"); -} - - -void -TransportNode::run(size_t nframes) -{ - NodeBase::run(nframes); -#if 0 - - // FIXME: this will die horribly with any driver other than jack (in theory) - const jack_position_t* const position = ((JackAudioDriver*)om->audio_driver())->position(); - jack_transport_state_t state = ((JackAudioDriver*)om->audio_driver())->transport_state(); - double bpm = position->beats_per_minute; - float bpb = position->beats_per_bar; - float spb = 60.0 / bpm; - - //cerr << "bpm = " << bpm << endl; - //cerr << "spb = " << spb << endl; - - if (position->valid & JackPositionBBT) { - cerr << "bar: " << position->bar << endl; - cerr << "beat: " << position->beat << endl; - cerr << "tick: " << position->tick << endl; - } else { - cerr << "No BBT" << endl; - } - - if (position->valid & JackBBTFrameOffset) { - cerr << "bbt_offset: " << position->bbt_offset << endl; - } else { - cerr << "No BBT offset" << endl; - } - - if (position->valid & JackPositionTimecode) { - double time = position->frame_time; - cerr << "Seconds: " << time << " : " << endl; - /*time /= 60.0; - cerr << "Minutes: " << time << " : "; - time /= 60.0; - cerr << "Hours: " << time << " : ";*/ - } else { - cerr << "No timecode." << endl; - } - - - ((OutputPort*)m_ports.at(0))->buffer(0)->set(spb, 0, 0); - ((OutputPort*)m_ports.at(1))->buffer(0)->set(bpb, 0, 0); - - // fill the trigger buffers with zeros - ((OutputPort*)m_ports.at(2))->buffer(0)->set(0.0f, 0, nframes - 1); - ((OutputPort*)m_ports.at(3))->buffer(0)->set(0.0f, 0, nframes - 1); - - // if the transport is rolling, add triggers at the right frame positions - if ((position->valid & JackTransportBBT) && (state == JackTransportRolling)) { - double frames_per_beat = position->frame_rate * spb; - double first_beat = (1.0f - position->tick / position->ticks_per_beat) * frames_per_beat; - int first_beat_no = position->beat; - if (first_beat >= frames_per_beat) { - first_beat -= frames_per_beat; - --first_beat_no; - } - for ( ; first_beat < nframes; first_beat += frames_per_beat) { - ((OutputPort*)m_ports.at(2))->buffer(0)->set(1.0f, size_t(first_beat)); - if (first_beat_no % int(bpb) == 0) { - ((OutputPort*)m_ports.at(3))->buffer(0)->set(1.0f, size_t(first_beat)); - ++first_beat_no; - } - } - } - #endif -} - - -} // namespace Om - diff --git a/src/engine/TransportNode.h b/src/engine/TransportNode.h deleted file mode 100644 index 15b1059c..00000000 --- a/src/engine/TransportNode.h +++ /dev/null @@ -1,48 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef TRANSPORTNODE_H -#define TRANSPORTNODE_H - - -#include -#include -#include "InternalNode.h" - -namespace Om { - -using std::string; - - -/** Transport Node, brings timing information into patches. - * - * This node uses the Jack transport API to get information about BPM, time - * signature, etc.. all sample accurate. Using this you can do - * tempo-synced effects or even synthesis, etc. - */ -class TransportNode : public InternalNode -{ -public: - TransportNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); - - void run(size_t nframes); -}; - - -} // namespace Om - -#endif // TRANSPORTNODE_H diff --git a/src/engine/Tree.h b/src/engine/Tree.h deleted file mode 100644 index 033d48b7..00000000 --- a/src/engine/Tree.h +++ /dev/null @@ -1,155 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef NODETREE_H -#define NODETREE_H - -#include -#include -#include "MaidObject.h" -using std::string; - -template class Tree; - - -/** A node in a Tree. - */ -template -class TreeNode : public MaidObject -{ -public: - TreeNode(const string& key) - : m_parent(NULL), m_left_child(NULL), m_right_child(NULL), - m_key(key), m_node(NULL) {} - - TreeNode(const string& key, T n) - : m_parent(NULL), m_left_child(NULL), m_right_child(NULL), - m_key(key), m_node(n) {} - - ~TreeNode() { - assert(m_parent == NULL || m_parent->left_child() != this); - assert(m_parent == NULL || m_parent->right_child() != this); - assert(m_left_child == NULL || m_left_child->parent() != this); - assert(m_right_child == NULL || m_right_child->parent() != this); - m_parent = m_left_child = m_right_child = NULL; - } - - string key() const { return m_key; } - void key(const string& key) { m_key = key; } - TreeNode* parent() const { return m_parent; } - void parent(TreeNode* n) { m_parent = n; } - TreeNode* left_child() const { return m_left_child; } - void left_child(TreeNode* n) { m_left_child = n; } - TreeNode* right_child() const { return m_right_child; } - void right_child(TreeNode* n) { m_right_child = n; } - - bool is_leaf() { return (m_left_child == NULL && m_right_child == NULL); } - bool is_left_child() { return (m_parent != NULL && m_parent->left_child() == this); } - bool is_right_child() { return (m_parent != NULL && m_parent->right_child() == this); } - - T node() { return m_node; } - - friend class Tree; - -protected: - // Prevent copies (undefined) - TreeNode(const TreeNode&); - TreeNode& operator=(const TreeNode&); - - TreeNode* m_parent; - TreeNode* m_left_child; - TreeNode* m_right_child; - string m_key; - T m_node; -}; - - -/** The tree all objects are stored in. - * - * Textbook naive (unbalanced) Binary Search Tree. Slightly different - * from a usual BST implementation in that the "Node" classes (TreeNode) are - * exposed to the user. This is so QueuedEvent's can create the TreeNode in - * another thread, and the realtime jack thread can insert them (without having - * to allocating a TreeNode which is a no-no). - * - * It's also a more annoying implementation because there's no leaf type (since - * a leaf object would have to be deleted on insert). - * - * Tree::iterator is not realtime safe, but the insert/remove/find methods - * of Tree do not use them. - */ -template -class Tree -{ -public: - Tree() : m_root(0), m_size(0) {} - ~Tree(); - - void insert(TreeNode* const n); - TreeNode* remove(const string& key); - T find(const string& key) const; - TreeNode* find_treenode(const string& key) const; - - size_t size() const { return m_size; } - - /** NON realtime safe iterator for a Tree. */ - class iterator - { - public: - iterator(const Tree* tree, size_t size); - ~iterator(); - - T operator*() const; - iterator& operator++(); - bool operator!=(const iterator& iter) const; - - friend class Tree; - - iterator(const iterator& copy); - iterator& operator=(const iterator& copy); - - private: - int m_depth; - size_t m_size; - TreeNode** m_stack; - const Tree* m_tree; - }; - - iterator begin() const; - iterator end() const; - -private: - // Prevent copies (undefined) - Tree(const Tree&); - Tree& operator=(const Tree&); - - void m_set_all_traversed_recursive(TreeNode* root, bool b); - - TreeNode* m_find_smallest(TreeNode* root); - TreeNode* m_find_largest(TreeNode* root); - - TreeNode* m_root; - size_t m_size; -}; - - -/* This needs to be done so the templates are defined and can get instantiated - * automatically by the compilter. - */ -//#include "TreeImplementation.h" - - -#endif // NODETREE_H diff --git a/src/engine/TreeImplementation.h b/src/engine/TreeImplementation.h deleted file mode 100644 index a61ec407..00000000 --- a/src/engine/TreeImplementation.h +++ /dev/null @@ -1,410 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Tree.h" -#include -#include -#include -using std::cerr; using std::endl; - - -/* FIXME: this is all in horrible need of a rewrite. */ - - -/** Destroy the tree. - * - * Note that this does not delete any TreeNodes still inside the tree, - * that is the user's responsibility. - */ -template -Tree::~Tree() -{ -} - - -/** Insert a node into the tree. Realtime safe. - * - * @a n will be inserted using the key() field for searches. - * n->key() must not be the empty string. - */ -template -void -Tree::insert(TreeNode* const n) -{ - assert(n != NULL); - assert(n->left_child() == NULL); - assert(n->right_child() == NULL); - assert(n->parent() == NULL); - assert(n->key().length() > 0); - assert(find_treenode(n->key()) == NULL); - - if (m_root == NULL) { - m_root = n; - } else { - bool left = false; // which child to insert at - bool right = false; - TreeNode* i = m_root; - while (true) { - assert(i != NULL); - if (n->key() <= i->key()) { - if (i->left_child() == NULL) { - left = true; - break; - } else { - i = i->left_child(); - } - } else { - if (i->right_child() == NULL) { - right = true; - break; - } else { - i = i->right_child(); - } - } - } - - assert(i != NULL); - assert(left || right); - assert( ! (left && right) ); - - if (left) { - assert(i->left_child() == NULL); - i->left_child(n); - } else if (right) { - assert(i->right_child() == NULL); - i->right_child(n); - } - n->parent(i); - } - ++m_size; -} - - -/** Remove a node from the tree. - * - * Realtime safe, caller is responsible to delete returned value. - * - * @return NULL if object with @a key is not in tree. - */ -template -TreeNode* -Tree::remove(const string& key) -{ - TreeNode* node = find_treenode(key); - TreeNode* n = node; - TreeNode* swap = NULL; - T temp_node; - string temp_key; - - if (node == NULL) - return NULL; - - // Node is not even in tree - if (node->parent() == NULL && m_root != node) - return NULL; - // FIXME: What if the node is in a different tree? Check for this? - -#ifndef NDEBUG - const T& remove_node = node->node(); // for error checking -#endif // NDEBUG - - // n has two children - if (n->left_child() != NULL && n->right_child() != NULL) { - if (rand()%2) - swap = m_find_largest(n->left_child()); - else - swap = m_find_smallest(n->right_child()); - - // Swap node's elements - temp_node = swap->m_node; - swap->m_node = n->m_node; - n->m_node = temp_node; - - // Swap node's keys - temp_key = swap->m_key; - swap->m_key = n->m_key; - n->m_key = temp_key; - - n = swap; - assert(n != NULL); - } - - // be sure we swapped correctly (ie right node is getting removed) - assert(n->node() == remove_node); - - // n now has at most one child - assert(n->left_child() == NULL || n->right_child() == NULL); - - if (n->is_leaf()) { - if (n->is_left_child()) - n->parent()->left_child(NULL); - else if (n->is_right_child()) - n->parent()->right_child(NULL); - - if (m_root == n) m_root = NULL; - } else { // has a single child - TreeNode* child = NULL; - if (n->left_child() != NULL) - child = n->left_child(); - else if (n->right_child() != NULL) - child = n->right_child(); - else - exit(EXIT_FAILURE); - - assert(child != n); - assert(child != NULL); - assert(n->parent() != n); - - if (n->is_left_child()) { - assert(n->parent() != child); - n->parent()->left_child(child); - child->parent(n->parent()); - } else if (n->is_right_child()) { - assert(n->parent() != child); - n->parent()->right_child(child); - child->parent(n->parent()); - } else { - child->parent(NULL); - } - if (m_root == n) m_root = child; - } - - // Be sure node is cut off completely - assert(n != NULL); - assert(n->parent() == NULL || n->parent()->left_child() != n); - assert(n->parent() == NULL || n->parent()->right_child() != n); - assert(n->left_child() == NULL || n->left_child()->parent() != n); - assert(n->right_child() == NULL || n->right_child()->parent() != n); - assert(m_root != n); - - n->parent(NULL); - n->left_child(NULL); - n->right_child(NULL); - - --m_size; - - if (m_size == 0) m_root = NULL; - - // Be sure right node is being removed - assert(n->node() == remove_node); - - return n; -} - - -template -T -Tree::find(const string& name) const -{ - TreeNode* tn = find_treenode(name); - - return (tn == NULL) ? NULL : tn->node(); -} - - -template -TreeNode* -Tree::find_treenode(const string& name) const -{ - TreeNode* i = m_root; - int cmp = 0; - - while (i != NULL) { - cmp = name.compare(i->key()); - if (cmp < 0) - i = i->left_child(); - else if (cmp > 0) - i = i->right_child(); - else - break; - } - - return i; -} - - -/// Private /// -template -void -Tree::m_set_all_traversed_recursive(TreeNode* root, bool b) -{ - assert(root != NULL); - - // Preorder traversal - root->node()->traversed(b); - if (root->left_child() != NULL) - m_set_all_traversed_recursive(root->left_child(), b); - if (root->right_child() != NULL) - m_set_all_traversed_recursive(root->right_child(), b); -} - - -/** Finds the smallest (key) node in the subtree rooted at "root" - */ -template -TreeNode* -Tree::m_find_smallest(TreeNode* root) -{ - TreeNode* r = root; - - while (r->left_child() != NULL) - r = r->left_child(); - - return r; -} - - -/** Finds the largest (key) node in the subtree rooted at "root". - */ -template -TreeNode* -Tree::m_find_largest(TreeNode* root) -{ - TreeNode* r = root; - - while (r->right_child() != NULL) - r = r->right_child(); - - return r; - -} - - - -//// Iterator Stuff //// - - - -template -Tree::iterator::iterator(const Tree *tree, size_t size) -: m_depth(-1), - m_size(size), - m_stack(NULL), - m_tree(tree) -{ - if (size > 0) - m_stack = new TreeNode*[size]; -} - - -template -Tree::iterator::~iterator() -{ - delete[] m_stack; -} - - -/* FIXME: Make these next two not memcpy (possibly have to force a single - * iterator existing at any given time) for speed. - */ - -// Copy constructor (for the typical for loop usage) -template -Tree::iterator::iterator(const Tree::iterator& copy) -: m_depth(copy.m_depth), - m_size(copy.m_size), - m_tree(copy.m_tree) -{ - if (m_size > 0) { - m_stack = new TreeNode*[m_size]; - memcpy(m_stack, copy.m_stack, m_size * sizeof(TreeNode*)); - } -} - - -// Assignment operator -template -typename Tree::iterator& -Tree::iterator::operator=(const Tree::iterator& copy) { - m_depth = copy.m_depth; - m_size = copy.m_size; - m_tree = copy.m_tree; - - if (m_size > 0) { - m_stack = new TreeNode*[m_size]; - memcpy(m_stack, copy.m_stack, m_size * sizeof(TreeNode*)); - } - return *this; -} - - -template -T -Tree::iterator::operator*() const -{ - assert(m_depth >= 0); - return m_stack[m_depth]->node(); -} - - -template -typename Tree::iterator& -Tree::iterator::operator++() -{ - assert(m_depth >= 0); - - TreeNode* tn = m_stack[m_depth]; - --m_depth; - - tn = tn->right_child(); - while (tn != NULL) { - ++m_depth; - m_stack[m_depth] = tn; - tn = tn->left_child(); - } - - return *this; -} - - -template -bool -Tree::iterator::operator!=(const Tree::iterator& iter) const -{ - // (DeMorgan's Law) - return (m_tree != iter.m_tree || m_depth != iter.m_depth); -} - - -template -typename Tree::iterator -Tree::begin() const -{ - typename Tree::iterator iter(this, m_size); - iter.m_depth = -1; - - TreeNode *ptr = m_root; - while (ptr != NULL) { - iter.m_depth++; - iter.m_stack[iter.m_depth] = ptr; - ptr = ptr->left_child(); - } - - return iter; -} - - -template -typename Tree::iterator -Tree::end() const -{ - typename Tree::iterator iter(this, 0); - iter.m_depth = -1; - - return iter; -} - - diff --git a/src/engine/cmdline.c b/src/engine/cmdline.c deleted file mode 100644 index 6b7ddf6a..00000000 --- a/src/engine/cmdline.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - File autogenerated by gengetopt version 2.10 - generated with the following command: - gengetopt - - The developers of gengetopt consider the fixed text that goes in all - gengetopt output files to be in the public domain: - we make no copyright claims on it. -*/ - - -#include -#include -#include - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "getopt.h" - -#include "cmdline.h" - -void -cmdline_parser_print_version (void) -{ - printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); -} - -void -cmdline_parser_print_help (void) -{ - cmdline_parser_print_version (); - printf("\n" - "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); - printf(" -h --help Print help and exit\n"); - printf(" -V --version Print version and exit\n"); - printf(" -pSTRING --port=STRING OSC port to listen on (default='16180')\n"); - printf(" -i --in-jackd Run engine as in-process JACK client (default=off)\n"); -} - - -static char *gengetopt_strdup (const char *s); - -/* gengetopt_strdup() */ -/* strdup.c replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) -{ - char *result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; -} - -int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) -{ - int c; /* Character of the parsed option. */ - int missing_required_options = 0; - - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->port_given = 0 ; - args_info->in_jackd_given = 0 ; -#define clear_args() { \ - args_info->port_arg = gengetopt_strdup("16180") ;\ - args_info->in_jackd_flag = 0;\ -} - - clear_args(); - - optarg = 0; - optind = 1; - opterr = 1; - optopt = '?'; - - while (1) - { - int option_index = 0; - char *stop_char; - - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "port", 1, NULL, 'p' }, - { "in-jackd", 0, NULL, 'i' }, - { NULL, 0, NULL, 0 } - }; - - stop_char = 0; - c = getopt_long (argc, argv, "hVp:i", long_options, &option_index); - - if (c == -1) break; /* Exit from `while (1)' loop. */ - - switch (c) - { - case 'h': /* Print help and exit. */ - clear_args (); - cmdline_parser_print_help (); - exit (EXIT_SUCCESS); - - case 'V': /* Print version and exit. */ - clear_args (); - cmdline_parser_print_version (); - exit (EXIT_SUCCESS); - - case 'p': /* OSC port to listen on. */ - if (args_info->port_given) - { - fprintf (stderr, "%s: `--port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->port_given = 1; - args_info->port_arg = gengetopt_strdup (optarg); - break; - - case 'i': /* Run engine as in-process JACK client. */ - if (args_info->in_jackd_given) - { - fprintf (stderr, "%s: `--in-jackd' (`-i') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->in_jackd_given = 1; - args_info->in_jackd_flag = !(args_info->in_jackd_flag); - break; - - - case 0: /* Long option with no short option */ - - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - exit (EXIT_FAILURE); - - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); - abort (); - } /* switch */ - } /* while */ - - - if ( missing_required_options ) - exit (EXIT_FAILURE); - - return 0; -} diff --git a/src/engine/cmdline.ggo b/src/engine/cmdline.ggo deleted file mode 100644 index 8c006ca7..00000000 --- a/src/engine/cmdline.ggo +++ /dev/null @@ -1,7 +0,0 @@ -# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) - -package "Om - An OSC controlled realtime modular synthesizer" - -option "port" p "OSC port to listen on" string default="16180" no -option "in-jackd" i "Run engine as in-process JACK client" flag off - diff --git a/src/engine/cmdline.h b/src/engine/cmdline.h deleted file mode 100644 index fe36a969..00000000 --- a/src/engine/cmdline.h +++ /dev/null @@ -1,45 +0,0 @@ -/* cmdline.h */ - -/* File autogenerated by gengetopt version 2.10 */ - -#ifndef CMDLINE_H -#define CMDLINE_H - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef CMDLINE_PARSER_PACKAGE -#define CMDLINE_PARSER_PACKAGE "Om - An OSC controlled realtime modular synthesizer" -#endif - -#ifndef CMDLINE_PARSER_VERSION -#define CMDLINE_PARSER_VERSION VERSION -#endif - -struct gengetopt_args_info -{ - char * port_arg; /* OSC port to listen on (default='16180'). */ - int in_jackd_flag; /* Run engine as in-process JACK client (default=off). */ - - int help_given ; /* Whether help was given. */ - int version_given ; /* Whether version was given. */ - int port_given ; /* Whether port was given. */ - int in_jackd_given ; /* Whether in-jackd was given. */ - -} ; - -int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); - -void cmdline_parser_print_help(void); -void cmdline_parser_print_version(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CMDLINE_H */ diff --git a/src/engine/events.h b/src/engine/events.h deleted file mode 100644 index f1bc5f58..00000000 --- a/src/engine/events.h +++ /dev/null @@ -1,62 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef EVENTS_H -#define EVENTS_H - -#include "config.h" - -#include "ActivateEvent.h" -#include "DeactivateEvent.h" -#include "EnablePatchEvent.h" -#include "DisablePatchEvent.h" -#include "ClearPatchEvent.h" -#include "SetPortValueEvent.h" -#include "SetPortValueQueuedEvent.h" -#include "ConnectionEvent.h" -#include "DisconnectionEvent.h" -#include "AddNodeEvent.h" -#include "CreatePatchEvent.h" -#include "DestroyEvent.h" -#include "SetMetadataEvent.h" -#include "RequestMetadataEvent.h" -#include "RequestPortValueEvent.h" -#include "RequestAllObjectsEvent.h" -#include "RequestPluginsEvent.h" -#include "LoadPluginsEvent.h" -#include "NoteOnEvent.h" -#include "NoteOffEvent.h" -#include "AllNotesOffEvent.h" -#include "DisconnectNodeEvent.h" -#include "RegisterClientEvent.h" -#include "UnregisterClientEvent.h" -#include "RenameEvent.h" -#include "PingQueuedEvent.h" -#include "MidiLearnEvent.h" - -#ifdef HAVE_LASH -#include "LashRestoreDoneEvent.h" -#endif - -#ifdef HAVE_DSSI -#include "DSSIUpdateEvent.h" -#include "DSSIControlEvent.h" -#include "DSSIConfigureEvent.h" -#include "DSSIProgramEvent.h" -#endif - -#endif // EVENTS_H - diff --git a/src/engine/events/ActivateEvent.cpp b/src/engine/events/ActivateEvent.cpp deleted file mode 100644 index 671b26d5..00000000 --- a/src/engine/events/ActivateEvent.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ActivateEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" - -namespace Om { - - -ActivateEvent::ActivateEvent(CountedPtr responder) -: QueuedEvent(responder) -{ -} - - -void -ActivateEvent::pre_process() -{ - QueuedEvent::pre_process(); - - if (om != NULL) - om->activate(); -} - - -void -ActivateEvent::post_process() -{ - if (om != NULL) - m_responder->respond_ok(); - else - m_responder->respond_error("Not ready to activate yet."); -} - - -} // namespace Om - diff --git a/src/engine/events/ActivateEvent.h b/src/engine/events/ActivateEvent.h deleted file mode 100644 index 280b5523..00000000 --- a/src/engine/events/ActivateEvent.h +++ /dev/null @@ -1,41 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ACTIVATEEVENT_H -#define ACTIVATEEVENT_H - -#include "QueuedEvent.h" - -namespace Om { - - -/** Activates the engine. - * - * \ingroup engine - */ -class ActivateEvent : public QueuedEvent -{ -public: - ActivateEvent(CountedPtr responder); - - void pre_process(); - void post_process(); -}; - - -} // namespace Om - -#endif // ACTIVATEEVENT_H diff --git a/src/engine/events/AddNodeEvent.cpp b/src/engine/events/AddNodeEvent.cpp deleted file mode 100644 index 2b31ef4a..00000000 --- a/src/engine/events/AddNodeEvent.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "AddNodeEvent.h" -#include "Responder.h" -#include "Patch.h" -#include "Node.h" -#include "Tree.h" -#include "Plugin.h" -#include "Om.h" -#include "OmApp.h" -#include "Patch.h" -#include "NodeFactory.h" -#include "ClientBroadcaster.h" -#include "Maid.h" -#include "util/Path.h" -#include "ObjectStore.h" -#include "util/Path.h" -#include "Port.h" - -namespace Om { - - -AddNodeEvent::AddNodeEvent(CountedPtr responder, const string& path, Plugin* plugin, bool poly) -: QueuedEvent(responder), - m_path(path), - m_plugin(plugin), - m_poly(poly), - m_patch(NULL), - m_node(NULL), - m_process_order(NULL), - m_node_already_exists(false) -{ -} - - -AddNodeEvent::~AddNodeEvent() -{ - delete m_plugin; -} - - -void -AddNodeEvent::pre_process() -{ - if (om->object_store()->find(m_path) != NULL) { - m_node_already_exists = true; - QueuedEvent::pre_process(); - return; - } - - m_patch = om->object_store()->find_patch(m_path.parent()); - - if (m_patch != NULL) { - if (m_poly) - m_node = om->node_factory()->load_plugin(m_plugin, m_path.name(), m_patch->internal_poly(), m_patch); - else - m_node = om->node_factory()->load_plugin(m_plugin, m_path.name(), 1, m_patch); - - if (m_node != NULL) { - m_node->activate(); - - // This can be done here because the audio thread doesn't touch the - // node tree - just the process order array - m_patch->add_node(new ListNode(m_node)); - m_node->add_to_store(); - - if (m_patch->process()) - m_process_order = m_patch->build_process_order(); - } - } - QueuedEvent::pre_process(); -} - - -void -AddNodeEvent::execute(samplecount offset) -{ - QueuedEvent::execute(offset); - - if (m_node != NULL) { - m_node->add_to_patch(); - - if (m_patch->process_order() != NULL) - om->maid()->push(m_patch->process_order()); - m_patch->process_order(m_process_order); - } -} - - -void -AddNodeEvent::post_process() -{ - string msg; - if (m_node_already_exists) { - msg = string("Could not create node - ").append(m_path);// + " already exists."; - m_responder->respond_error(msg); - } else if (m_patch == NULL) { - msg = "Could not find patch '" + m_path.parent() +"' for add_node."; - m_responder->respond_error(msg); - } else if (m_node == NULL) { - msg = "Unable to load node "; - msg.append(m_path).append(" (you're missing the plugin \"").append( - m_plugin->lib_name()).append(":").append(m_plugin->plug_label()).append("\")");; - m_responder->respond_error(msg); - } else { - m_responder->respond_ok(); - //om->client_broadcaster()->send_node_creation_messages(m_node); - om->client_broadcaster()->send_node(m_node); - } -} - - -} // namespace Om - diff --git a/src/engine/events/AddNodeEvent.h b/src/engine/events/AddNodeEvent.h deleted file mode 100644 index fe0236ba..00000000 --- a/src/engine/events/AddNodeEvent.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ADDNODEEVENT_H -#define ADDNODEEVENT_H - -#include "QueuedEvent.h" -#include "util/Path.h" -#include -using std::string; - -template class Array; -template class TreeNode; - -namespace Om { - -class Patch; -class Node; -class Plugin; - - -/** An event to load a Node and insert it into a Patch. - * - * \ingroup engine - */ -class AddNodeEvent : public QueuedEvent -{ -public: - AddNodeEvent(CountedPtr responder, const string& path, Plugin* plugin, bool poly); - ~AddNodeEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_patch_name; - Path m_path; - Plugin* m_plugin; - bool m_poly; - Patch* m_patch; - Node* m_node; - Array* m_process_order; // Patch's new process order - bool m_node_already_exists; -}; - - -} // namespace Om - -#endif // ADDNODEEVENT_H diff --git a/src/engine/events/AllNotesOffEvent.cpp b/src/engine/events/AllNotesOffEvent.cpp deleted file mode 100644 index aa3a00f1..00000000 --- a/src/engine/events/AllNotesOffEvent.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "AllNotesOffEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ObjectStore.h" - -namespace Om { - - -/** Note off with patch explicitly passed - triggered by MIDI. - */ -AllNotesOffEvent::AllNotesOffEvent(CountedPtr responder, Patch* patch) -: Event(responder), - m_patch(patch) -{ -} - - -/** Note off event with lookup - triggered by OSC. - */ -AllNotesOffEvent::AllNotesOffEvent(CountedPtr responder, const string& patch_path) -: Event(responder), - m_patch(NULL), - m_patch_path(patch_path) -{ -} - - -void -AllNotesOffEvent::execute(samplecount offset) -{ - if (m_patch == NULL && m_patch_path != "") - m_patch = om->object_store()->find_patch(m_patch_path); - - //if (m_patch != NULL) - // for (List::iterator j = m_patch->midi_in_nodes().begin(); j != m_patch->midi_in_nodes().end(); ++j) - // (*j)->all_notes_off(offset); -} - - -void -AllNotesOffEvent::post_process() -{ - if (m_patch != NULL) - m_responder->respond_ok(); -} - - -} // namespace Om - - diff --git a/src/engine/events/AllNotesOffEvent.h b/src/engine/events/AllNotesOffEvent.h deleted file mode 100644 index ea23301b..00000000 --- a/src/engine/events/AllNotesOffEvent.h +++ /dev/null @@ -1,50 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ALLNOTESOFFEVENT_H -#define ALLNOTESOFFEVENT_H - -#include "Event.h" -#include -using std::string; - -namespace Om { - -class Patch; - - -/** A note off event for all active voices. - * - * \ingroup engine - */ -class AllNotesOffEvent : public Event -{ -public: - AllNotesOffEvent(CountedPtr responder, Patch* patch); - AllNotesOffEvent(CountedPtr responder, const string& patch_path); - - void execute(samplecount offset); - void post_process(); - -private: - Patch* m_patch; - string m_patch_path; -}; - - -} // namespace Om - -#endif // ALLNOTESOFFEVENT_H diff --git a/src/engine/events/ClearPatchEvent.cpp b/src/engine/events/ClearPatchEvent.cpp deleted file mode 100644 index 8b8fc223..00000000 --- a/src/engine/events/ClearPatchEvent.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ClearPatchEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "Patch.h" -#include "ClientBroadcaster.h" -#include "util.h" -#include "ObjectStore.h" -#include "Port.h" -#include "Maid.h" -#include "Node.h" -#include "Connection.h" -#include "QueuedEventSource.h" - -namespace Om { - - -ClearPatchEvent::ClearPatchEvent(CountedPtr responder, const string& patch_path) -: QueuedEvent(responder, true), - m_patch_path(patch_path), - m_patch(NULL), - m_process(false) -{ -} - - -void -ClearPatchEvent::pre_process() -{ - m_patch = om->object_store()->find_patch(m_patch_path); - - if (m_patch != NULL) { - - m_process = m_patch->process(); - - for (List::const_iterator i = m_patch->nodes().begin(); i != m_patch->nodes().end(); ++i) - (*i)->remove_from_store(); - } - - QueuedEvent::pre_process(); -} - - -void -ClearPatchEvent::execute(samplecount offset) -{ - if (m_patch != NULL) { - m_patch->process(false); - - for (List::const_iterator i = m_patch->nodes().begin(); i != m_patch->nodes().end(); ++i) - (*i)->remove_from_patch(); - - if (m_patch->process_order() != NULL) { - om->maid()->push(m_patch->process_order()); - m_patch->process_order(NULL); - } - } - - QueuedEvent::execute(offset); -} - - -void -ClearPatchEvent::post_process() -{ - if (m_patch != NULL) { - // Delete all nodes - for (List::iterator i = m_patch->nodes().begin(); i != m_patch->nodes().end(); ++i) { - (*i)->deactivate(); - delete *i; - } - m_patch->nodes().clear(); - - // Delete all connections - for (List::iterator i = m_patch->connections().begin(); i != m_patch->connections().end(); ++i) - delete *i; - m_patch->connections().clear(); - - // Restore patch's run state - m_patch->process(m_process); - - // Make sure everything's sane - assert(m_patch->nodes().size() == 0); - assert(m_patch->connections().size() == 0); - - // Reply - m_responder->respond_ok(); - om->client_broadcaster()->send_patch_cleared(m_patch_path); - } else { - m_responder->respond_error(string("Patch ") + m_patch_path + " not found"); - } - - m_source->unblock(); -} - - -} // namespace Om - diff --git a/src/engine/events/ClearPatchEvent.h b/src/engine/events/ClearPatchEvent.h deleted file mode 100644 index c6e531a8..00000000 --- a/src/engine/events/ClearPatchEvent.h +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CLEARPATCHEVENT_H -#define CLEARPATCHEVENT_H - -#include -#include "QueuedEvent.h" -#include "Array.h" - -using std::string; - -namespace Om { - -class Patch; - - -/** Delete all nodes from a patch. - * - * \ingroup engine - */ -class ClearPatchEvent : public QueuedEvent -{ -public: - ClearPatchEvent(CountedPtr responder, const string& patch_path); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_patch_path; - Patch* m_patch; - bool m_process; -}; - - -} // namespace Om - - -#endif // CLEARPATCHEVENT_H diff --git a/src/engine/events/ConnectionEvent.cpp b/src/engine/events/ConnectionEvent.cpp deleted file mode 100644 index fe3b991e..00000000 --- a/src/engine/events/ConnectionEvent.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ConnectionEvent.h" -#include -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ConnectionBase.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Patch.h" -#include "ClientBroadcaster.h" -#include "Port.h" -#include "PortInfo.h" -#include "Maid.h" -#include "ObjectStore.h" -#include "util/Path.h" - -using std::string; -namespace Om { - - -//// ConnectionEvent //// - - -ConnectionEvent::ConnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path) -: QueuedEvent(responder), - m_src_port_path(src_port_path), - m_dst_port_path(dst_port_path), - m_patch(NULL), - m_src_port(NULL), - m_dst_port(NULL), - m_typed_event(NULL), - m_error(NO_ERROR) -{ -} - - -ConnectionEvent::~ConnectionEvent() -{ - delete m_typed_event; -} - - -void -ConnectionEvent::pre_process() -{ - if (m_src_port_path.parent().parent() != m_dst_port_path.parent().parent()) { - m_error = PARENT_PATCH_DIFFERENT; - QueuedEvent::pre_process(); - return; - } - - /*m_patch = om->object_store()->find_patch(m_src_port_path.parent().parent()); - - if (m_patch == NULL) { - m_error = PORT_NOT_FOUND; - QueuedEvent::pre_process(); - return; - }*/ - - Port* port1 = om->object_store()->find_port(m_src_port_path); - Port* port2 = om->object_store()->find_port(m_dst_port_path); - - if (port1 == NULL || port2 == NULL) { - m_error = PORT_NOT_FOUND; - QueuedEvent::pre_process(); - return; - } - - if (port1->port_info()->type() != port2->port_info()->type()) { - m_error = TYPE_MISMATCH; - QueuedEvent::pre_process(); - return; - } - - if (port1->port_info()->is_output() && port2->port_info()->is_input()) { - m_src_port = port1; - m_dst_port = port2; - } else if (port2->port_info()->is_output() && port1->port_info()->is_input()) { - m_src_port = port2; - m_dst_port = port1; - } else { - m_error = TYPE_MISMATCH; - QueuedEvent::pre_process(); - return; - } - - // Create the typed event to actually do the work - const PortType type = port1->port_info()->type(); - if (type == AUDIO || type == CONTROL) { - m_typed_event = new TypedConnectionEvent(m_responder, - (OutputPort*)m_src_port, (InputPort*)m_dst_port); - } else if (type == MIDI) { - m_typed_event = new TypedConnectionEvent(m_responder, - (OutputPort*)m_src_port, (InputPort*)m_dst_port); - } else { - m_error = TYPE_MISMATCH; - QueuedEvent::pre_process(); - return; - } - - m_typed_event->pre_process(); - - QueuedEvent::pre_process(); -} - - -void -ConnectionEvent::execute(samplecount offset) -{ - QueuedEvent::execute(offset); - - if (m_error == NO_ERROR) - m_typed_event->execute(offset); -} - - -void -ConnectionEvent::post_process() -{ - if (m_error == NO_ERROR) { - m_typed_event->post_process(); - } else { - // FIXME: better error messages - string msg = "Unable to make connection "; - msg.append(m_src_port_path + " -> " + m_dst_port_path); - m_responder->respond_error(msg); - } -} - - - -//// TypedConnectionEvent //// - - -template -TypedConnectionEvent::TypedConnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port) -: QueuedEvent(responder), - m_src_port(src_port), - m_dst_port(dst_port), - m_patch(NULL), - m_process_order(NULL), - m_connection(NULL), - m_port_listnode(NULL), - m_succeeded(true) -{ - assert(src_port != NULL); - assert(dst_port != NULL); -} - -template -TypedConnectionEvent::~TypedConnectionEvent() -{ - // FIXME: haaaack, prevent a double delete - // this class is unusable by anything other than ConnectionEvent because of this - //m_responder = NULL; -} - - -template -void -TypedConnectionEvent::pre_process() -{ - Node* const src_node = m_src_port->parent_node(); - Node* const dst_node = m_dst_port->parent_node(); - - m_patch = src_node->parent_patch(); - - if (src_node == NULL || dst_node == NULL) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - - if (src_node->parent() != m_patch || dst_node->parent() != m_patch) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - - m_connection = new ConnectionBase(m_src_port, m_dst_port); - m_port_listnode = new ListNode*>(m_connection); - m_patch_listnode = new ListNode(m_connection); - - dst_node->providers()->push_back(new ListNode(src_node)); - src_node->dependants()->push_back(new ListNode(dst_node)); - - if (m_patch->process()) - m_process_order = m_patch->build_process_order(); -} - - -template -void -TypedConnectionEvent::execute(samplecount offset) -{ - if (m_succeeded) { - // These must be inserted here, since they're actually used by the audio thread - m_dst_port->add_connection(m_port_listnode); - m_patch->add_connection(m_patch_listnode); - if (m_patch->process_order() != NULL) - om->maid()->push(m_patch->process_order()); - m_patch->process_order(m_process_order); - } -} - - -template -void -TypedConnectionEvent::post_process() -{ - if (m_succeeded) { - assert(m_connection != NULL); - - m_responder->respond_ok(); - - om->client_broadcaster()->send_connection(m_connection); - } else { - m_responder->respond_error("Unable to make connection."); - } -} - - -} // namespace Om - diff --git a/src/engine/events/ConnectionEvent.h b/src/engine/events/ConnectionEvent.h deleted file mode 100644 index 8aaf2292..00000000 --- a/src/engine/events/ConnectionEvent.h +++ /dev/null @@ -1,107 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CONNECTIONEVENT_H -#define CONNECTIONEVENT_H - -#include -#include "QueuedEvent.h" -#include "util/Path.h" -#include "util/types.h" -using std::string; - -template class ListNode; -template class Array; - -namespace Om { - -class Patch; -class Node; -class Connection; -class MidiMessage; -class Port; -template class ConnectionBase; -template class InputPort; -template class OutputPort; -template class TypedConnectionEvent; // helper, defined below - - -/** Make a Connection between two Ports. - * - * \ingroup engine - */ -class ConnectionEvent : public QueuedEvent -{ -public: - ConnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path); - ~ConnectionEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - - enum ErrorType { NO_ERROR, PARENT_PATCH_DIFFERENT, PORT_NOT_FOUND, TYPE_MISMATCH }; - - Path m_src_port_path; - Path m_dst_port_path; - - Patch* m_patch; - Port* m_src_port; - Port* m_dst_port; - - QueuedEvent* m_typed_event; - - ErrorType m_error; -}; - - -/** Templated ConnectionEvent. - * - * Intended to be called from ConnectionEvent so callers (ie OSCReceiver) - * can use ConnectionEvent without knowing anything about types (which - * they can't, since all they have is Port paths). - */ -template -class TypedConnectionEvent : public QueuedEvent -{ -public: - TypedConnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port); - ~TypedConnectionEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - OutputPort* m_src_port; - InputPort* m_dst_port; - - Patch* m_patch; - Array* m_process_order; ///< New process order for Patch - ConnectionBase* m_connection; - ListNode* m_patch_listnode; - ListNode*>* m_port_listnode; - - bool m_succeeded; -}; - - - -} // namespace Om - -#endif // CONNECTIONEVENT_H diff --git a/src/engine/events/CreatePatchEvent.cpp b/src/engine/events/CreatePatchEvent.cpp deleted file mode 100644 index 9f0ae7f2..00000000 --- a/src/engine/events/CreatePatchEvent.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "CreatePatchEvent.h" -#include "Responder.h" -#include "Patch.h" -#include "Node.h" -#include "Tree.h" -#include "Plugin.h" -#include "Om.h" -#include "OmApp.h" -#include "Maid.h" -#include "ClientBroadcaster.h" -#include "AudioDriver.h" -#include "util/Path.h" -#include "ObjectStore.h" - -namespace Om { - - -CreatePatchEvent::CreatePatchEvent(CountedPtr responder, const string& path, int poly) -: QueuedEvent(responder), - m_path(path), - m_patch(NULL), - m_parent(NULL), - m_process_order(NULL), - m_poly(poly), - m_error(NO_ERROR) -{ -} - - -void -CreatePatchEvent::pre_process() -{ - if (om->object_store()->find(m_path) != NULL) { - m_error = OBJECT_EXISTS; - QueuedEvent::pre_process(); - return; - } - - if (m_poly < 1) { - m_error = INVALID_POLY; - QueuedEvent::pre_process(); - return; - } - - if (m_path != "/") { - m_parent = om->object_store()->find_patch(m_path.parent()); - if (m_parent == NULL) { - m_error = PARENT_NOT_FOUND; - QueuedEvent::pre_process(); - return; - } - } - - size_t poly = 1; - if (m_parent != NULL && m_poly > 1 && m_poly == static_cast(m_parent->internal_poly())) - poly = m_poly; - - m_patch = new Patch(m_path.name(), poly, m_parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size(), m_poly); - - if (m_parent != NULL) { - m_parent->add_node(new ListNode(m_patch->as_node())); - - if (m_parent->process()) - m_process_order = m_parent->build_process_order(); - } - - m_patch->activate(); - - // Insert into ObjectStore - m_patch->add_to_store(); - - QueuedEvent::pre_process(); -} - - -void -CreatePatchEvent::execute(samplecount offset) -{ - QueuedEvent::execute(offset); - - if (m_patch != NULL) { - if (m_parent == NULL) { - assert(m_path == "/"); - assert(m_patch->parent_patch() == NULL); - om->audio_driver()->set_root_patch(m_patch); - } else { - assert(m_parent != NULL); - assert(m_path != "/"); - - m_patch->add_to_patch(); - - if (m_parent->process_order() != NULL) - om->maid()->push(m_parent->process_order()); - m_parent->process_order(m_process_order); - } - } -} - - -void -CreatePatchEvent::post_process() -{ - if (m_responder.get()) { - if (m_error == NO_ERROR) { - - m_responder->respond_ok(); - - // Don't want to send nodes that have been added since prepare() - //om->client_broadcaster()->send_node_creation_messages(m_patch); - - // Patches are always empty on creation, so this is fine - om->client_broadcaster()->send_patch(m_patch); - - } else if (m_error == OBJECT_EXISTS) { - string msg = "Unable to create patch: "; - msg += m_path += " already exists."; - m_responder->respond_error(msg); - } else if (m_error == PARENT_NOT_FOUND) { - string msg = "Unable to create patch: Parent "; - msg += m_path.parent() += " not found."; - m_responder->respond_error(msg); - } else if (m_error == INVALID_POLY) { - string msg = "Unable to create patch "; - msg.append(m_path).append(": ").append("Invalid polyphony respondered."); - m_responder->respond_error(msg); - } else { - m_responder->respond_error("Unable to load patch."); - } - } -} - - -} // namespace Om - diff --git a/src/engine/events/CreatePatchEvent.h b/src/engine/events/CreatePatchEvent.h deleted file mode 100644 index 507d03c7..00000000 --- a/src/engine/events/CreatePatchEvent.h +++ /dev/null @@ -1,64 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CREATEPATCHEVENT_H -#define CREATEPATCHEVENT_H - -#include "util/Path.h" -#include "QueuedEvent.h" -#include -using std::string; - -template class Array; -template class TreeNode; - -namespace Om { - -class Patch; -class Node; -class Plugin; - - -/** Creates a new Patch. - * - * \ingroup engine - */ -class CreatePatchEvent : public QueuedEvent -{ -public: - CreatePatchEvent(CountedPtr responder, const string& path, int poly); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - enum ErrorType { NO_ERROR, OBJECT_EXISTS, PARENT_NOT_FOUND, INVALID_POLY }; - - Path m_path; - Patch* m_patch; - Patch* m_parent; - Array* m_process_order; - TreeNode* m_patch_treenode; - int m_poly; - ErrorType m_error; -}; - - -} // namespace Om - - -#endif // CREATEPATCHEVENT_H diff --git a/src/engine/events/DSSIConfigureEvent.cpp b/src/engine/events/DSSIConfigureEvent.cpp deleted file mode 100644 index 2ade4671..00000000 --- a/src/engine/events/DSSIConfigureEvent.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DSSIConfigureEvent.h" -#include "Om.h" -#include "OmApp.h" -#include "Node.h" -#include "ClientBroadcaster.h" -#include "Plugin.h" -#include "ObjectStore.h" - -namespace Om { - - -DSSIConfigureEvent::DSSIConfigureEvent(CountedPtr responder, const string& node_path, const string& key, const string& val) -: QueuedEvent(responder), - m_node_path(node_path), - m_key(key), - m_val(val), - m_node(NULL) -{ -} - - -void -DSSIConfigureEvent::pre_process() -{ - Node* node = om->object_store()->find_node(m_node_path); - - if (node != NULL && node->plugin()->type() == Plugin::DSSI) { - m_node = (DSSIPlugin*)node; - m_node->configure(m_key, m_val); - } - - QueuedEvent::pre_process(); -} - - -void -DSSIConfigureEvent::execute(samplecount offset) -{ - // Nothing. -} - - -void -DSSIConfigureEvent::post_process() -{ - if (m_node == NULL) { - cerr << "Unable to find DSSI node " << m_node_path << endl; - } else { - string key = "dssi-configure--"; - key += m_key; - om->client_broadcaster()->send_metadata_update(m_node_path, key, m_val); - } -} - - -} // namespace Om - diff --git a/src/engine/events/DSSIConfigureEvent.h b/src/engine/events/DSSIConfigureEvent.h deleted file mode 100644 index 00b4a134..00000000 --- a/src/engine/events/DSSIConfigureEvent.h +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DSSICONFIGUREEVENT_H -#define DSSICONFIGUREEVENT_H - -#include "QueuedEvent.h" -#include "DSSIPlugin.h" - -namespace Om { - - -/** Change of a 'configure' key/value pair for a DSSI plugin. - * - * \ingroup engine - */ -class DSSIConfigureEvent : public QueuedEvent -{ -public: - DSSIConfigureEvent(CountedPtr responder, const string& node_path, const string& key, const string& val); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_node_path; - string m_key; - string m_val; - DSSIPlugin* m_node; -}; - - -} // namespace Om - -#endif // DSSICONFIGUREEVENT_H diff --git a/src/engine/events/DSSIControlEvent.cpp b/src/engine/events/DSSIControlEvent.cpp deleted file mode 100644 index ea3e70ac..00000000 --- a/src/engine/events/DSSIControlEvent.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DSSIControlEvent.h" -#include "Om.h" -#include "OmApp.h" -#include "Node.h" -#include "Plugin.h" -#include "ObjectStore.h" - -namespace Om { - - -DSSIControlEvent::DSSIControlEvent(CountedPtr responder, const string& node_path, int port_num, sample val) -: QueuedEvent(responder), - m_node_path(node_path), - m_port_num(port_num), - m_val(val), - m_node(NULL) -{ -} - - -void -DSSIControlEvent::pre_process() -{ - Node* node = om->object_store()->find_node(m_node_path); - - if (node->plugin()->type() != Plugin::DSSI) - m_node = NULL; - else - m_node = (DSSIPlugin*)node; - - QueuedEvent::pre_process(); -} - - -void -DSSIControlEvent::execute(samplecount offset) -{ - if (m_node != NULL) - m_node->set_control(m_port_num, m_val); -} - - -void -DSSIControlEvent::post_process() -{ - if (m_node == NULL) - std::cerr << "Unable to find DSSI node " << m_node_path << std::endl; -} - - -} // namespace Om - diff --git a/src/engine/events/DSSIControlEvent.h b/src/engine/events/DSSIControlEvent.h deleted file mode 100644 index 30a5279e..00000000 --- a/src/engine/events/DSSIControlEvent.h +++ /dev/null @@ -1,51 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DSSICONTROLEVENT_H -#define DSSICONTROLEVENT_H - -#include "QueuedEvent.h" -#include "DSSIPlugin.h" - -namespace Om { - - -/** A control change event for a DSSI plugin. - * - * This does essentially the same thing as a SetPortValueEvent. - * - * \ingroup engine - */ -class DSSIControlEvent : public QueuedEvent -{ -public: - DSSIControlEvent(CountedPtr responder, const string& node_path, int port_num, sample val); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_node_path; - int m_port_num; - float m_val; - DSSIPlugin* m_node; -}; - - -} // namespace Om - -#endif // DSSICONTROLEVENT_H diff --git a/src/engine/events/DSSIProgramEvent.cpp b/src/engine/events/DSSIProgramEvent.cpp deleted file mode 100644 index eb68ef77..00000000 --- a/src/engine/events/DSSIProgramEvent.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DSSIProgramEvent.h" -#include -#include -#include "Om.h" -#include "OmApp.h" -#include "Node.h" -#include "ClientBroadcaster.h" -#include "Plugin.h" -#include "ObjectStore.h" -using std::cout; using std::cerr; using std::endl; - - -namespace Om { - - -DSSIProgramEvent::DSSIProgramEvent(CountedPtr responder, const string& node_path, int bank, int program) -: QueuedEvent(responder), - m_node_path(node_path), - m_bank(bank), - m_program(program), - m_node(NULL) -{ -} - - -void -DSSIProgramEvent::pre_process() -{ - Node* node = om->object_store()->find_node(m_node_path); - - if (node != NULL && node->plugin()->type() == Plugin::DSSI) - m_node = (DSSIPlugin*)node; - - QueuedEvent::pre_process(); -} - - -void -DSSIProgramEvent::execute(samplecount offset) -{ - if (m_node != NULL) - m_node->program(m_bank, m_program); -} - - -void -DSSIProgramEvent::post_process() -{ - if (m_node == NULL) { - cerr << "Unable to find DSSI node " << m_node_path << endl; - } else { - // sends program as metadata in the form bank/program - char* temp_buf = new char[16]; - snprintf(temp_buf, 16, "%d/%d", m_bank, m_program); - om->client_broadcaster()->send_metadata_update(m_node_path, "dssi-program", temp_buf); - } -} - - -} // namespace Om - diff --git a/src/engine/events/DSSIProgramEvent.h b/src/engine/events/DSSIProgramEvent.h deleted file mode 100644 index 152f3cb1..00000000 --- a/src/engine/events/DSSIProgramEvent.h +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DSSIPROGRAMEVENT_H -#define DSSIPROGRAMEVENT_H - -#include "QueuedEvent.h" -#include "DSSIPlugin.h" - -namespace Om { - - -/** A program change for a DSSI plugin. - * - * \ingroup engine - */ -class DSSIProgramEvent : public QueuedEvent -{ -public: - DSSIProgramEvent(CountedPtr responder, const string& node_path, int bank, int program); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_node_path; - int m_bank; - int m_program; - DSSIPlugin* m_node; -}; - - -} // namespace Om - -#endif // DSSIPROGRAMEVENT_H diff --git a/src/engine/events/DSSIUpdateEvent.cpp b/src/engine/events/DSSIUpdateEvent.cpp deleted file mode 100644 index 5650dd63..00000000 --- a/src/engine/events/DSSIUpdateEvent.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DSSIUpdateEvent.h" -#include -#include "Node.h" -#include "ObjectStore.h" -#include "Om.h" -#include "OmApp.h" -#include "DSSIPlugin.h" -#include "Plugin.h" - -using std::cerr; using std::endl; - -namespace Om { - - -DSSIUpdateEvent::DSSIUpdateEvent(CountedPtr responder, const string& path, const string& url) -: QueuedEvent(responder), - m_path(path), - m_url(url), - m_node(NULL) -{ -} - - -void -DSSIUpdateEvent::pre_process() -{ - Node* node = om->object_store()->find_node(m_path); - - if (node == NULL || node->plugin()->type() != Plugin::DSSI) { - m_node = NULL; - QueuedEvent::pre_process(); - return; - } else { - m_node = (DSSIPlugin*)node; - } - - QueuedEvent::pre_process(); -} - - -void -DSSIUpdateEvent::execute(samplecount offset) -{ - if (m_node != NULL) { - m_node->set_ui_url(m_url); - } - - QueuedEvent::execute(offset); -} - - -void -DSSIUpdateEvent::post_process() -{ - cerr << "DSSI update event: " << m_url << endl; - - if (m_node != NULL) { - m_node->send_update(); - } -} - - -} // namespace Om - diff --git a/src/engine/events/DSSIUpdateEvent.h b/src/engine/events/DSSIUpdateEvent.h deleted file mode 100644 index cdd8851e..00000000 --- a/src/engine/events/DSSIUpdateEvent.h +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DSSIUPDATEEVENT_H -#define DSSIUPDATEEVENT_H - -#include "QueuedEvent.h" -#include - -using std::string; - -namespace Om { - -class DSSIPlugin; - - -/** A DSSI "update" responder for a DSSI plugin/node. - * - * This sends all information about the plugin to the UI (over OSC). - * - * \ingroup engine - */ -class DSSIUpdateEvent : public QueuedEvent -{ -public: - DSSIUpdateEvent(CountedPtr responder, const string& path, const string& url); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_path; - string m_url; - DSSIPlugin* m_node; -}; - - -} // namespace Om - -#endif // DSSIUPDATEEVENT_H diff --git a/src/engine/events/DeactivateEvent.cpp b/src/engine/events/DeactivateEvent.cpp deleted file mode 100644 index 48bff55a..00000000 --- a/src/engine/events/DeactivateEvent.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DeactivateEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" - -namespace Om { - - -DeactivateEvent::DeactivateEvent(CountedPtr responder) -: QueuedEvent(responder) -{ -} - - -void -DeactivateEvent::pre_process() -{ - QueuedEvent::pre_process(); -} - - -void -DeactivateEvent::execute(samplecount offset) -{ - QueuedEvent::execute(offset); -} - - -void -DeactivateEvent::post_process() -{ - m_responder->respond_ok(); - om->deactivate(); -} - - -} // namespace Om - diff --git a/src/engine/events/DeactivateEvent.h b/src/engine/events/DeactivateEvent.h deleted file mode 100644 index 8401f332..00000000 --- a/src/engine/events/DeactivateEvent.h +++ /dev/null @@ -1,42 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DEACTIVATEEVENT_H -#define DEACTIVATEEVENT_H - -#include "QueuedEvent.h" - -namespace Om { - - -/** Deactivates the engine. - * - * \ingroup engine - */ -class DeactivateEvent : public QueuedEvent -{ -public: - DeactivateEvent(CountedPtr responder); - - void pre_process(); - void execute(samplecount offset); - void post_process(); -}; - - -} // namespace Om - -#endif // DEACTIVATEEVENT_H diff --git a/src/engine/events/DestroyEvent.cpp b/src/engine/events/DestroyEvent.cpp deleted file mode 100644 index 3988195a..00000000 --- a/src/engine/events/DestroyEvent.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DestroyEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "Patch.h" -#include "Tree.h" -#include "Node.h" -#include "Plugin.h" -#include "InternalNode.h" -#include "DisconnectNodeEvent.h" -#include "DisconnectPortEvent.h" -#include "ClientBroadcaster.h" -#include "Maid.h" -#include "ObjectStore.h" -#include "util/Path.h" -#include "QueuedEventSource.h" -#include "Port.h" - -namespace Om { - - -DestroyEvent::DestroyEvent(CountedPtr responder, const string& path, bool lock_mutex) -: QueuedEvent(responder, true), - m_path(path), - m_node(NULL), - m_patch_listnode(NULL), - m_store_treenode(NULL), - m_process_order(NULL), - m_disconnect_event(NULL), - m_parent_disconnect_event(NULL) -{ -} - - -DestroyEvent::DestroyEvent(CountedPtr responder, Node* node, bool lock_mutex) -: QueuedEvent(responder, true), - m_path(node->path()), - m_node(node), - m_patch_listnode(NULL), - m_store_treenode(NULL), - m_process_order(NULL), - m_disconnect_event(NULL), - m_parent_disconnect_event(NULL) -{ -} - - -DestroyEvent::~DestroyEvent() -{ - delete m_disconnect_event; - delete m_parent_disconnect_event; -} - - -void -DestroyEvent::pre_process() -{ - if (m_node == NULL) { - OmObject* const obj = om->object_store()->find_node(m_path); - - if (obj != NULL && obj->as_node() != NULL) - m_node = obj->as_node(); - } - - if (m_node != NULL && m_path != "/") { - assert(m_node->parent_patch() != NULL); - m_patch_listnode = m_node->parent_patch()->remove_node(m_path.name()); - if (m_patch_listnode != NULL) { - assert(m_patch_listnode->elem() == m_node); - - m_node->remove_from_store(); - - if (m_node->providers()->size() != 0 || m_node->dependants()->size() != 0) { - m_disconnect_event = new DisconnectNodeEvent(m_node); - m_disconnect_event->pre_process(); - } - - // Create a recursive disconnect event for the parent port, if a bridge node - Port* parent_port = m_patch_listnode->elem()->as_port(); - if (parent_port != NULL) { // Bridge node - m_parent_disconnect_event = new DisconnectPortEvent(parent_port); - m_parent_disconnect_event->pre_process(); - } - - if (m_node->parent_patch()->process()) { - m_process_order = m_node->parent_patch()->build_process_order(); - // Remove node to be removed from the process order so it isn't executed by - // Patch::run and can safely be destroyed - //for (size_t i=0; i < m_process_order->size(); ++i) - // if (m_process_order->at(i) == m_node) - // m_process_order->at(i) = NULL; // ew, gap - -#ifdef DEBUG - // Be sure node is removed from process order, so it can be destroyed - for (size_t i=0; i < m_process_order->size(); ++i) - assert(m_process_order->at(i) != m_node); -#endif - } - } - } - - QueuedEvent::pre_process(); -} - - -void -DestroyEvent::execute(samplecount offset) -{ - QueuedEvent::execute(offset); - - if (m_patch_listnode != NULL) { - m_node->remove_from_patch(); - - if (m_disconnect_event != NULL) - m_disconnect_event->execute(offset); - if (m_parent_disconnect_event != NULL) - m_parent_disconnect_event->execute(offset); - - if (m_node->parent_patch()->process_order() != NULL) - om->maid()->push(m_node->parent_patch()->process_order()); - m_node->parent_patch()->process_order(m_process_order); - } -} - - -void -DestroyEvent::post_process() -{ - m_source->unblock(); - - if (m_node == NULL) { - if (m_path == "/") - m_responder->respond_error("You can not destroy the root patch (/)"); - else - m_responder->respond_error("Could not find node to destroy"); - } else if (m_patch_listnode != NULL) { - m_node->deactivate(); - m_responder->respond_ok(); - if (m_disconnect_event != NULL) - m_disconnect_event->post_process(); - if (m_parent_disconnect_event != NULL) - m_parent_disconnect_event->post_process(); - om->client_broadcaster()->send_destroyed(m_path); - om->maid()->push(m_patch_listnode); - om->maid()->push(m_node); - } else { - m_responder->respond_error("Unable to destroy object"); - } -} - - -} // namespace Om diff --git a/src/engine/events/DestroyEvent.h b/src/engine/events/DestroyEvent.h deleted file mode 100644 index fc579bf4..00000000 --- a/src/engine/events/DestroyEvent.h +++ /dev/null @@ -1,68 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DESTROYEVENT_H -#define DESTROYEVENT_H - -#include "util/Path.h" -#include "QueuedEvent.h" -#include - -using std::string; - -template class Array; -template class ListNode; -template class TreeNode; - -namespace Om { - -class OmObject; -class Patch; -class Node; -class Plugin; -class DisconnectNodeEvent; -class DisconnectPortEvent; - - -/** An event to remove and delete a Node. - * - * \ingroup engine - */ -class DestroyEvent : public QueuedEvent -{ -public: - DestroyEvent(CountedPtr responder, const string& path, bool lock_mutex = true); - DestroyEvent(CountedPtr responder, Node* node, bool lock_mutex = true); - ~DestroyEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - Path m_path; - Node* m_node; - ListNode* m_patch_listnode; - TreeNode* m_store_treenode; - Array* m_process_order; // Patch's new process order - DisconnectNodeEvent* m_disconnect_event; - DisconnectPortEvent* m_parent_disconnect_event; // used for input/output nodes -}; - - -} // namespace Om - -#endif // DESTROYEVENT_H diff --git a/src/engine/events/DisablePatchEvent.cpp b/src/engine/events/DisablePatchEvent.cpp deleted file mode 100644 index a772e6e9..00000000 --- a/src/engine/events/DisablePatchEvent.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DisablePatchEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "Patch.h" -#include "ClientBroadcaster.h" -#include "util.h" -#include "ObjectStore.h" -#include "Port.h" - -namespace Om { - - -DisablePatchEvent::DisablePatchEvent(CountedPtr responder, const string& patch_path) -: QueuedEvent(responder), - m_patch_path(patch_path), - m_patch(NULL) -{ -} - - -void -DisablePatchEvent::pre_process() -{ - m_patch = om->object_store()->find_patch(m_patch_path); - - QueuedEvent::pre_process(); -} - - -void -DisablePatchEvent::execute(samplecount offset) -{ - if (m_patch != NULL) - m_patch->process(false); - - QueuedEvent::execute(offset); -} - - -void -DisablePatchEvent::post_process() -{ - if (m_patch != NULL) { - m_responder->respond_ok(); - om->client_broadcaster()->send_patch_disable(m_patch_path); - } else { - m_responder->respond_error(string("Patch ") + m_patch_path + " not found"); - } -} - - -} // namespace Om - diff --git a/src/engine/events/DisablePatchEvent.h b/src/engine/events/DisablePatchEvent.h deleted file mode 100644 index f38f14af..00000000 --- a/src/engine/events/DisablePatchEvent.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DISABLEPATCHEVENT_H -#define DISABLEPATCHEVENT_H - -#include -#include "QueuedEvent.h" - -using std::string; - -namespace Om { - -class Patch; - - -/** Disables a Patch's DSP processing. - * - * \ingroup engine - */ -class DisablePatchEvent : public QueuedEvent -{ -public: - DisablePatchEvent(CountedPtr responder, const string& patch_path); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_patch_path; - Patch* m_patch; -}; - - -} // namespace Om - - -#endif // DISABLEPATCHEVENT_H diff --git a/src/engine/events/DisconnectNodeEvent.cpp b/src/engine/events/DisconnectNodeEvent.cpp deleted file mode 100644 index 17367dd4..00000000 --- a/src/engine/events/DisconnectNodeEvent.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DisconnectNodeEvent.h" -#include -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "Maid.h" -#include "List.h" -#include "Node.h" -#include "ConnectionBase.h" -#include "DisconnectionEvent.h" -#include "Port.h" -#include "Array.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Patch.h" -#include "ClientBroadcaster.h" -#include "util.h" -#include "ObjectStore.h" -#include "util/Path.h" - -using std::cerr; using std::endl; - -namespace Om { - - -DisconnectNodeEvent::DisconnectNodeEvent(CountedPtr responder, const string& node_path) -: QueuedEvent(responder), - m_node_path(node_path), - m_patch(NULL), - m_node(NULL), - m_succeeded(true), - m_lookup(true) -{ -} - - -/** Internal version, disconnects parent port as well (in the case of InputNode, etc). - */ -DisconnectNodeEvent::DisconnectNodeEvent(Node* node) -: QueuedEvent(), - m_node_path(""), - m_patch(node->parent_patch()), - m_node(node), - m_succeeded(true), - m_lookup(false) -{ -} - - -DisconnectNodeEvent::~DisconnectNodeEvent() -{ - for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) - delete (*i); -} - - -void -DisconnectNodeEvent::pre_process() -{ - typedef List::const_iterator ConnectionListIterator; - - // cerr << "Preparing disconnection event...\n"; - - if (m_lookup) { - m_patch = om->object_store()->find_patch(m_node_path.parent()); - - if (m_patch == NULL) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - - m_node = om->object_store()->find_node(m_node_path); - - if (m_node == NULL) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - } - - Connection* c = NULL; - for (ConnectionListIterator i = m_patch->connections().begin(); i != m_patch->connections().end(); ++i) { - c = (*i); - if ((c->src_port()->parent_node() == m_node || c->dst_port()->parent_node() == m_node) && !c->pending_disconnection()) { - DisconnectionEvent* ev = new DisconnectionEvent(CountedPtr(new Responder()), c->src_port(), c->dst_port()); - ev->pre_process(); - m_disconnection_events.push_back(new ListNode(ev)); - c->pending_disconnection(true); - } - } - - m_succeeded = true; - QueuedEvent::pre_process(); -} - - -void -DisconnectNodeEvent::execute(samplecount offset) -{ - if (m_succeeded) { - for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) - (*i)->execute(offset); - } - - QueuedEvent::execute(offset); -} - - -void -DisconnectNodeEvent::post_process() -{ - if (m_succeeded) { - m_responder->respond_ok(); - for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) - (*i)->post_process(); - } else { - m_responder->respond_error("Unable to disconnect all ports."); - } -} - - -} // namespace Om - diff --git a/src/engine/events/DisconnectNodeEvent.h b/src/engine/events/DisconnectNodeEvent.h deleted file mode 100644 index a82fbaec..00000000 --- a/src/engine/events/DisconnectNodeEvent.h +++ /dev/null @@ -1,68 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DISCONNECTNODEEVENT_H -#define DISCONNECTNODEEVENT_H - -#include -#include "util/Path.h" -#include "QueuedEvent.h" -#include "List.h" -using std::string; - -namespace Om { - -class DisconnectionEvent; -class Patch; -class Node; -class Connection; -template class ConnectionBase; -class Port; -template class InputPort; -template class OutputPort; - - -/** An event to disconnect all connections to a Node. - * - * \ingroup engine - */ -class DisconnectNodeEvent : public QueuedEvent -{ -public: - DisconnectNodeEvent(CountedPtr responder, const string& node_path); - DisconnectNodeEvent(Node* node); - ~DisconnectNodeEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - Path m_node_path; - Patch* m_patch; - Node* m_node; - List m_disconnection_events; - - bool m_succeeded; - bool m_lookup; - bool m_disconnect_parent; -}; - - -} // namespace Om - - -#endif // DISCONNECTNODEEVENT_H diff --git a/src/engine/events/DisconnectPortEvent.cpp b/src/engine/events/DisconnectPortEvent.cpp deleted file mode 100644 index a4c213d5..00000000 --- a/src/engine/events/DisconnectPortEvent.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DisconnectPortEvent.h" -#include -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "Maid.h" -#include "List.h" -#include "Node.h" -#include "Connection.h" -#include "DisconnectionEvent.h" -#include "Port.h" -#include "Array.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Patch.h" -#include "ClientBroadcaster.h" -#include "util.h" -#include "ObjectStore.h" -#include "util/Path.h" - -using std::cerr; using std::endl; - -namespace Om { - - -DisconnectPortEvent::DisconnectPortEvent(CountedPtr responder, const string& port_path) -: QueuedEvent(responder), - m_port_path(port_path), - m_patch(NULL), - m_port(NULL), - m_process_order(NULL), - m_succeeded(true), - m_lookup(true) -{ -} - - -DisconnectPortEvent::DisconnectPortEvent(Port* port) -: QueuedEvent(), - m_port_path(""), - m_patch((port->parent_node() == NULL) ? NULL : port->parent_node()->parent_patch()), - m_port(port), - m_process_order(NULL), - m_succeeded(true), - m_lookup(false) -{ - //cerr << "DisconnectPortEvent()\n"; -} - - -DisconnectPortEvent::~DisconnectPortEvent() -{ - for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) - delete (*i); -} - - -void -DisconnectPortEvent::pre_process() -{ - // cerr << "Preparing disconnection event...\n"; - - if (m_lookup) { - m_patch = om->object_store()->find_patch(m_port_path.parent().parent()); - - if (m_patch == NULL) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - - m_port = om->object_store()->find_port(m_port_path); - - if (m_port == NULL) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - } - - if (m_patch == NULL) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - - Connection* c = NULL; - for (List::const_iterator i = m_patch->connections().begin(); i != m_patch->connections().end(); ++i) { - c = (*i); - if ((c->src_port() == m_port || c->dst_port() == m_port) && !c->pending_disconnection()) { - DisconnectionEvent* ev = new DisconnectionEvent(CountedPtr(new Responder()), c->src_port(), c->dst_port()); - ev->pre_process(); - m_disconnection_events.push_back(new ListNode(ev)); - c->pending_disconnection(true); - } - } - - m_succeeded = true; - QueuedEvent::pre_process(); -} - - -void -DisconnectPortEvent::execute(samplecount offset) -{ - if (m_succeeded) { - for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) - (*i)->execute(offset); - } - - QueuedEvent::execute(offset); -} - - -void -DisconnectPortEvent::post_process() -{ - if (m_succeeded) { - m_responder->respond_ok(); - for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) - (*i)->post_process(); - } else { - m_responder->respond_error("Unable to disconnect port."); - } -} - - -} // namespace Om - diff --git a/src/engine/events/DisconnectPortEvent.h b/src/engine/events/DisconnectPortEvent.h deleted file mode 100644 index e8de4120..00000000 --- a/src/engine/events/DisconnectPortEvent.h +++ /dev/null @@ -1,70 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DISCONNECTPORTEVENT_H -#define DISCONNECTPORTEVENT_H - -#include -#include "util/Path.h" -#include "QueuedEvent.h" -#include "List.h" - -template class Array; - -namespace Om { - - -class Patch; -class Node; -class Connection; -class Port; -class DisconnectionEvent; - -using std::string; - - -/** An event to disconnect all connections to a Port. - * - * \ingroup engine - */ -class DisconnectPortEvent : public QueuedEvent -{ -public: - DisconnectPortEvent(CountedPtr responder, const string& port_path); - DisconnectPortEvent(Port* port); - ~DisconnectPortEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - Path m_port_path; - Patch* m_patch; - Port* m_port; - List m_disconnection_events; - - Array* m_process_order; // Patch's new process order - - bool m_succeeded; - bool m_lookup; -}; - - -} // namespace Om - - -#endif // DISCONNECTPORTEVENT_H diff --git a/src/engine/events/DisconnectionEvent.cpp b/src/engine/events/DisconnectionEvent.cpp deleted file mode 100644 index e7d06eab..00000000 --- a/src/engine/events/DisconnectionEvent.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "DisconnectionEvent.h" -#include -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ConnectionBase.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Patch.h" -#include "ClientBroadcaster.h" -#include "Port.h" -#include "PortInfo.h" -#include "Maid.h" -#include "ObjectStore.h" -#include "util/Path.h" - -using std::string; -namespace Om { - - -//// DisconnectionEvent //// - - -DisconnectionEvent::DisconnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path) -: QueuedEvent(responder), - m_src_port_path(src_port_path), - m_dst_port_path(dst_port_path), - m_patch(NULL), - m_src_port(NULL), - m_dst_port(NULL), - m_lookup(true), - m_typed_event(NULL), - m_error(NO_ERROR) -{ -} - - -DisconnectionEvent::DisconnectionEvent(CountedPtr responder, Port* const src_port, Port* const dst_port) -: QueuedEvent(responder), - m_src_port_path(src_port->path()), - m_dst_port_path(dst_port->path()), - m_patch(src_port->parent_node()->parent_patch()), - m_src_port(src_port), - m_dst_port(dst_port), - m_lookup(false), - m_typed_event(NULL), - m_error(NO_ERROR) -{ - assert(src_port->port_info()->is_output()); - assert(dst_port->port_info()->is_input()); - assert(src_port->port_info()->type() == dst_port->port_info()->type()); - assert(src_port->parent_node()->parent_patch() - == dst_port->parent_node()->parent_patch()); -} - -DisconnectionEvent::~DisconnectionEvent() -{ - delete m_typed_event; -} - - -void -DisconnectionEvent::pre_process() -{ - if (m_lookup) { - if (m_src_port_path.parent().parent() != m_dst_port_path.parent().parent()) { - m_error = PARENT_PATCH_DIFFERENT; - QueuedEvent::pre_process(); - return; - } - - /*m_patch = om->object_store()->find_patch(m_src_port_path.parent().parent()); - - if (m_patch == NULL) { - m_error = PORT_NOT_FOUND; - QueuedEvent::pre_process(); - return; - }*/ - - Port* port1 = om->object_store()->find_port(m_src_port_path); - Port* port2 = om->object_store()->find_port(m_dst_port_path); - - if (port1 == NULL || port2 == NULL) { - m_error = PORT_NOT_FOUND; - QueuedEvent::pre_process(); - return; - } - - if (port1->port_info()->type() != port2->port_info()->type()) { - m_error = TYPE_MISMATCH; - QueuedEvent::pre_process(); - return; - } - - if (port1->port_info()->is_output() && port2->port_info()->is_input()) { - m_src_port = port1; - m_dst_port = port2; - } else if (port2->port_info()->is_output() && port1->port_info()->is_input()) { - m_src_port = port2; - m_dst_port = port1; - } else { - m_error = TYPE_MISMATCH; - QueuedEvent::pre_process(); - return; - } - } - - // Create the typed event to actually do the work - const PortType type = m_src_port->port_info()->type(); - if (type == AUDIO || type == CONTROL) { - m_typed_event = new TypedDisconnectionEvent(m_responder, - (OutputPort*)m_src_port, (InputPort*)m_dst_port); - } else if (type == MIDI) { - m_typed_event = new TypedDisconnectionEvent(m_responder, - (OutputPort*)m_src_port, (InputPort*)m_dst_port); - } else { - m_error = TYPE_MISMATCH; - QueuedEvent::pre_process(); - return; - } - - m_typed_event->pre_process(); - - QueuedEvent::pre_process(); -} - - -void -DisconnectionEvent::execute(samplecount offset) -{ - QueuedEvent::execute(offset); - - if (m_error == NO_ERROR) - m_typed_event->execute(offset); -} - - -void -DisconnectionEvent::post_process() -{ - if (m_error == NO_ERROR) { - m_typed_event->post_process(); - } else { - // FIXME: better error messages - string msg = "Unable to make connection "; - msg.append(m_src_port_path + " -> " + m_dst_port_path); - m_responder->respond_error(msg); - } -} - - - -//// TypedDisconnectionEvent //// - - -template -TypedDisconnectionEvent::TypedDisconnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port) -: QueuedEvent(responder), - m_src_port(src_port), - m_dst_port(dst_port), - m_patch(NULL), - m_process_order(NULL), - m_succeeded(true) -{ - assert(src_port != NULL); - assert(dst_port != NULL); -} - -template -TypedDisconnectionEvent::~TypedDisconnectionEvent() -{ - // FIXME: haaaack, prevent a double delete - // this class is unusable by anything other than DisconnectionEvent because of this - //m_responder = NULL; -} - - -template -void -TypedDisconnectionEvent::pre_process() -{ - if (!m_dst_port->is_connected_to(m_src_port)) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - - Node* const src_node = m_src_port->parent_node(); - Node* const dst_node = m_dst_port->parent_node(); - - m_patch = src_node->parent_patch(); - - if (src_node == NULL || dst_node == NULL) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - - if (src_node->parent() != m_patch || dst_node->parent() != m_patch) { - m_succeeded = false; - QueuedEvent::pre_process(); - return; - } - - bool removed = false; - - for (List::iterator i = dst_node->providers()->begin(); i != dst_node->providers()->end(); ++i) - if ((*i) == src_node) { - delete dst_node->providers()->remove(i); - removed = true; - break; - } - assert(removed); - removed = false; - - for (List::iterator i = src_node->dependants()->begin(); i != src_node->dependants()->end(); ++i) - if ((*i) == dst_node) { - delete src_node->dependants()->remove(i); - removed = true; - break; - } - assert(removed); - - if (m_patch->process()) - m_process_order = m_patch->build_process_order(); - - m_succeeded = true; - QueuedEvent::pre_process(); -} - - -template -void -TypedDisconnectionEvent::execute(samplecount offset) -{ - if (m_succeeded) { - - ListNode*>* const port_connection - = m_dst_port->remove_connection(m_src_port); - - if (port_connection != NULL) { - ListNode* const patch_connection - = m_patch->remove_connection(m_src_port, m_dst_port); - - assert((Connection*)port_connection->elem() == patch_connection->elem()); - - // Clean up both the list node and the connection itself... - om->maid()->push(port_connection); - om->maid()->push(patch_connection); - om->maid()->push(port_connection->elem()); - - if (m_patch->process_order() != NULL) - om->maid()->push(m_patch->process_order()); - m_patch->process_order(m_process_order); - } else { - m_succeeded = false; // Ports weren't connected - } - } - QueuedEvent::execute(offset); -} - - -template -void -TypedDisconnectionEvent::post_process() -{ - if (m_succeeded) { - - m_responder->respond_ok(); - - om->client_broadcaster()->send_disconnection(m_src_port->path(), m_dst_port->path()); - } else { - m_responder->respond_error("Unable to disconnect ports."); - } -} - - -} // namespace Om - diff --git a/src/engine/events/DisconnectionEvent.h b/src/engine/events/DisconnectionEvent.h deleted file mode 100644 index bbb70f3c..00000000 --- a/src/engine/events/DisconnectionEvent.h +++ /dev/null @@ -1,106 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DISCONNECTIONEVENT_H -#define DISCONNECTIONEVENT_H - -#include -#include "util/Path.h" -#include "QueuedEvent.h" -#include "util/types.h" -using std::string; - -template class ListNode; -template class Array; - -namespace Om { - -class Patch; -class Node; -class Connection; -class MidiMessage; -class Port; -template class ConnectionBase; -template class InputPort; -template class OutputPort; -template class TypedDisconnectionEvent; // helper, defined below - - -/** Make a Connection between two Ports. - * - * \ingroup engine - */ -class DisconnectionEvent : public QueuedEvent -{ -public: - DisconnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path); - DisconnectionEvent(CountedPtr responder, Port* const src_port, Port* const dst_port); - ~DisconnectionEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - - enum ErrorType { NO_ERROR, PARENT_PATCH_DIFFERENT, PORT_NOT_FOUND, TYPE_MISMATCH }; - - Path m_src_port_path; - Path m_dst_port_path; - - Patch* m_patch; - Port* m_src_port; - Port* m_dst_port; - - bool m_lookup; - QueuedEvent* m_typed_event; - - ErrorType m_error; -}; - - -/** Templated DisconnectionEvent. - * - * Intended to be called from DisconnectionEvent so callers (ie OSCReceiver) - * can use DisconnectionEvent without knowing anything about types (which - * they can't, since all they have is Port paths). - */ -template -class TypedDisconnectionEvent : public QueuedEvent -{ -public: - TypedDisconnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port); - ~TypedDisconnectionEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - OutputPort* m_src_port; - InputPort* m_dst_port; - - Patch* m_patch; - Array* m_process_order; ///< New process order for Patch - - bool m_succeeded; -}; - - - -} // namespace Om - -#endif // DISCONNECTIONEVENT_H diff --git a/src/engine/events/EnablePatchEvent.cpp b/src/engine/events/EnablePatchEvent.cpp deleted file mode 100644 index 6af3b844..00000000 --- a/src/engine/events/EnablePatchEvent.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "EnablePatchEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "Patch.h" -#include "util.h" -#include "ClientBroadcaster.h" -#include "ObjectStore.h" - -namespace Om { - - -EnablePatchEvent::EnablePatchEvent(CountedPtr responder, const string& patch_path) -: QueuedEvent(responder), - m_patch_path(patch_path), - m_patch(NULL), - m_process_order(NULL) -{ -} - - -void -EnablePatchEvent::pre_process() -{ - m_patch = om->object_store()->find_patch(m_patch_path); - - if (m_patch != NULL) { - /* Any event that requires a new process order will set the patch's - * process order to NULL if it is executed when the patch is not - * active. So, if the PO is NULL, calculate it here */ - if (m_patch->process_order() == NULL) - m_process_order = m_patch->build_process_order(); - } - - QueuedEvent::pre_process(); -} - - -void -EnablePatchEvent::execute(samplecount offset) -{ - if (m_patch != NULL) { - m_patch->process(true); - - if (m_patch->process_order() == NULL) - m_patch->process_order(m_process_order); - } - - QueuedEvent::execute(offset); -} - - -void -EnablePatchEvent::post_process() -{ - if (m_patch != NULL) { - m_responder->respond_ok(); - om->client_broadcaster()->send_patch_enable(m_patch_path); - } else { - m_responder->respond_error(string("Patch ") + m_patch_path + " not found"); - } -} - - -} // namespace Om - diff --git a/src/engine/events/EnablePatchEvent.h b/src/engine/events/EnablePatchEvent.h deleted file mode 100644 index f3d22e69..00000000 --- a/src/engine/events/EnablePatchEvent.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ENABLEPATCHEVENT_H -#define ENABLEPATCHEVENT_H - -#include -#include "QueuedEvent.h" - -using std::string; - -template class Array; - -namespace Om { - -class Patch; -class Node; - - -/** Enables a patch's DSP processing. - * - * \ingroup engine - */ -class EnablePatchEvent : public QueuedEvent -{ -public: - EnablePatchEvent(CountedPtr responder, const string& patch_path); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_patch_path; - Patch* m_patch; - Array* m_process_order; // Patch's new process order -}; - - -} // namespace Om - - -#endif // ENABLEPATCHEVENT_H diff --git a/src/engine/events/LashRestoreDoneEvent.h b/src/engine/events/LashRestoreDoneEvent.h deleted file mode 100644 index dfc5b120..00000000 --- a/src/engine/events/LashRestoreDoneEvent.h +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef LASHRESTOREDONEEVENT_H -#define LASHRESTOREDONEEVENT_H - -#include "QueuedEvent.h" -#include "LashDriver.h" -#include "util/types.h" - -#include -using std::cerr; - -namespace Om { - -class Port; - - -/** Notification from a client that the LASH session is finished restoring. - * - * This is a bit of a hack, but needed to defer notifying LASH of our - * existance until all ports are created. - * - * \ingroup engine - */ -class LashRestoreDoneEvent : public QueuedEvent -{ -public: - LashRestoreDoneEvent(CountedPtr responder) : QueuedEvent(responder) {} - - void post_process() - { - m_responder->respond_ok(); - lash_driver->restore_finished(); - } -}; - - -} // namespace Om - -#endif // LASHRESTOREDONEEVENT_H diff --git a/src/engine/events/LoadPluginsEvent.cpp b/src/engine/events/LoadPluginsEvent.cpp deleted file mode 100644 index 656e9010..00000000 --- a/src/engine/events/LoadPluginsEvent.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "LoadPluginsEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "NodeFactory.h" - -namespace Om { - - -LoadPluginsEvent::LoadPluginsEvent(CountedPtr responder) -: QueuedEvent(responder) -{ -} - - -void -LoadPluginsEvent::post_process() -{ - // Why is this done here and not in pre_process()??? - om->node_factory()->load_plugins(); - m_responder->respond_ok(); - - //cerr << "Load plugins post finished\n"; -} - - -} // namespace Om - diff --git a/src/engine/events/LoadPluginsEvent.h b/src/engine/events/LoadPluginsEvent.h deleted file mode 100644 index b69dbb38..00000000 --- a/src/engine/events/LoadPluginsEvent.h +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef LOADPLUGINSEVENT_H -#define LOADPLUGINSEVENT_H - -#include "QueuedEvent.h" - -namespace Om { - - -/** Loads all plugins into the internal plugin database (in NodeFactory). - * - * \ingroup engine - */ -class LoadPluginsEvent : public QueuedEvent -{ -public: - LoadPluginsEvent(CountedPtr responder); - - void post_process(); -}; - - -} // namespace Om - -#endif // LOADPLUGINSEVENT_H diff --git a/src/engine/events/Makefile.am b/src/engine/events/Makefile.am deleted file mode 100644 index 5b29e12b..00000000 --- a/src/engine/events/Makefile.am +++ /dev/null @@ -1,67 +0,0 @@ -MAINTAINERCLEANFILES = Makefile.in - -EXTRA_DIST = \ - events/RegisterClientEvent.h \ - events/RegisterClientEvent.cpp \ - events/UnregisterClientEvent.h \ - events/UnregisterClientEvent.cpp \ - events/PingQueuedEvent.h \ - events/ActivateEvent.h \ - events/ActivateEvent.cpp \ - events/DeactivateEvent.h \ - events/DeactivateEvent.cpp \ - events/SetPortValueEvent.h \ - events/SetPortValueEvent.cpp \ - events/SetPortValueQueuedEvent.h \ - events/SetPortValueQueuedEvent.cpp \ - events/NoteOnEvent.h \ - events/NoteOnEvent.cpp \ - events/NoteOffEvent.h \ - events/NoteOffEvent.cpp \ - events/AllNotesOffEvent.h \ - events/AllNotesOffEvent.cpp \ - events/ConnectionEvent.h \ - events/ConnectionEvent.cpp \ - events/DisconnectionEvent.h \ - events/DisconnectionEvent.cpp \ - events/DisconnectNodeEvent.h \ - events/DisconnectNodeEvent.cpp \ - events/DisconnectPortEvent.h \ - events/DisconnectPortEvent.cpp \ - events/DestroyEvent.h \ - events/DestroyEvent.cpp \ - events/AddNodeEvent.h \ - events/AddNodeEvent.cpp \ - events/SetMetadataEvent.h \ - events/SetMetadataEvent.cpp \ - events/RequestMetadataEvent.h \ - events/RequestMetadataEvent.cpp \ - events/RequestPortValueEvent.h \ - events/RequestPortValueEvent.cpp \ - events/RequestAllObjectsEvent.h \ - events/RequestAllObjectsEvent.cpp \ - events/RequestPluginsEvent.h \ - events/RequestPluginsEvent.cpp \ - events/CreatePatchEvent.h \ - events/CreatePatchEvent.cpp \ - events/LoadPluginsEvent.h \ - events/LoadPluginsEvent.cpp \ - events/EnablePatchEvent.h \ - events/EnablePatchEvent.cpp \ - events/DisablePatchEvent.h \ - events/DisablePatchEvent.cpp \ - events/ClearPatchEvent.h \ - events/ClearPatchEvent.cpp \ - events/RenameEvent.h \ - events/RenameEvent.cpp \ - events/MidiLearnEvent.h \ - events/MidiLearnEvent.cpp \ - DSSIConfigureEvent.cpp \ - DSSIConfigureEvent.h \ - DSSIControlEvent.cpp \ - DSSIControlEvent.h \ - DSSIProgramEvent.cpp \ - DSSIProgramEvent.h \ - DSSIUpdateEvent.cpp \ - DSSIUpdateEvent.h - diff --git a/src/engine/events/MidiLearnEvent.cpp b/src/engine/events/MidiLearnEvent.cpp deleted file mode 100644 index 63ad82fc..00000000 --- a/src/engine/events/MidiLearnEvent.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MidiLearnEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ObjectStore.h" -#include "Node.h" -#include "MidiControlNode.h" -#include "ClientBroadcaster.h" - -namespace Om { - - -// MidiLearnResponseEvent - -void -MidiLearnResponseEvent::post_process() -{ - om->client_broadcaster()->send_control_change(m_port_path, m_value); -} - - - -// MidiLearnEvent - -MidiLearnEvent::MidiLearnEvent(CountedPtr responder, const string& node_path) -: QueuedEvent(responder), - m_node_path(node_path), - m_node(NULL), - m_response_event(NULL) -{ -} - - -void -MidiLearnEvent::pre_process() -{ - m_node = om->object_store()->find_node(m_node_path); - m_response_event = new MidiLearnResponseEvent(m_node_path + "/Controller Number"); - - QueuedEvent::pre_process(); -} - - -void -MidiLearnEvent::execute(samplecount offset) -{ - QueuedEvent::execute(offset); - - // FIXME: this isn't very good at all. - if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal - && m_node->plugin()->plug_label() == "midi_control_in") { - ((MidiControlNode*)m_node)->learn(m_response_event); - } -} - - -void -MidiLearnEvent::post_process() -{ - if (m_node != NULL) { - m_responder->respond_ok(); - } else { - string msg = "Did not find node '"; - msg.append(m_node_path).append("' for MIDI learn."); - m_responder->respond_error(msg); - } -} - - -} // namespace Om - - diff --git a/src/engine/events/MidiLearnEvent.h b/src/engine/events/MidiLearnEvent.h deleted file mode 100644 index 793e675a..00000000 --- a/src/engine/events/MidiLearnEvent.h +++ /dev/null @@ -1,84 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MIDILEARNEVENT_H -#define MIDILEARNEVENT_H - -#include "QueuedEvent.h" -#include "MidiControlNode.h" -#include "util/types.h" -#include -using std::string; - -namespace Om { - -class Node; -class ControlChangeEvent; - - -/** Response event for a MIDI learn. - * - * This is a trivial event that sends a control change in it's post_process - * method (used by MidiLearnEvent to notify clients when the learn happens) - */ -class MidiLearnResponseEvent : public Event -{ -public: - MidiLearnResponseEvent(const string& port_path) - : Event(CountedPtr(NULL)), - m_port_path(port_path), - m_value(0.0f) - {} - - void set_value(sample val) { m_value = val; } - void post_process(); - -private: - string m_port_path; - sample m_value; -}; - - - -/** A MIDI learn event. - * - * This creates a MidiLearnResponseEvent and passes it to the learning node, which - * will push it to the post-processor once the learn happens in order to reply - * to the client with the new port (learned controller) value. - * - * \ingroup engine - */ -class MidiLearnEvent : public QueuedEvent -{ -public: - MidiLearnEvent(CountedPtr responder, const string& node_path); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_node_path; - Node* m_node; - - /// Event to respond with when learned - MidiLearnResponseEvent* m_response_event; -}; - - -} // namespace Om - -#endif // MIDILEARNEVENT_H diff --git a/src/engine/events/NoteOffEvent.cpp b/src/engine/events/NoteOffEvent.cpp deleted file mode 100644 index fde2e520..00000000 --- a/src/engine/events/NoteOffEvent.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "NoteOffEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ObjectStore.h" -#include "Node.h" -#include "MidiNoteNode.h" -#include "MidiTriggerNode.h" - -namespace Om { - - -/** Note off with patch explicitly passed - triggered by MIDI. - */ -NoteOffEvent::NoteOffEvent(CountedPtr responder, Node* node, uchar note_num) -: Event(responder), - m_node(node), - m_note_num(note_num) -{ -} - - -/** Note off event with lookup - triggered by OSC. - */ -NoteOffEvent::NoteOffEvent(CountedPtr responder, const string& node_path, uchar note_num) -: Event(responder), - m_node(NULL), - m_node_path(node_path), - m_note_num(note_num) -{ -} - - -void -NoteOffEvent::execute(samplecount offset) -{ - if (m_node == NULL && m_node_path != "") - m_node = om->object_store()->find_node(m_node_path); - - // FIXME: this isn't very good at all. - if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal) { - if (m_node->plugin()->plug_label() == "note_in") - ((MidiNoteNode*)m_node)->note_off(m_note_num, offset); - else if (m_node->plugin()->plug_label() == "trigger_in") - ((MidiTriggerNode*)m_node)->note_off(m_note_num, offset); - } -} - - -void -NoteOffEvent::post_process() -{ - if (m_node != NULL) - m_responder->respond_ok(); - else - m_responder->respond_error("Did not find node for note_off"); -} - - -} // namespace Om - - diff --git a/src/engine/events/NoteOffEvent.h b/src/engine/events/NoteOffEvent.h deleted file mode 100644 index edd0b373..00000000 --- a/src/engine/events/NoteOffEvent.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef NOTEOFFEVENT_H -#define NOTEOFFEVENT_H - -#include "Event.h" -#include "util/types.h" -#include -using std::string; - -namespace Om { - -class Node; - - -/** A note off event. - * - * \ingroup engine - */ -class NoteOffEvent : public Event -{ -public: - NoteOffEvent(CountedPtr responder, Node* node, uchar note_num); - NoteOffEvent(CountedPtr responder, const string& node_path, uchar note_num); - - void execute(samplecount offset); - void post_process(); - -private: - Node* m_node; - string m_node_path; - uchar m_note_num; -}; - - -} // namespace Om - -#endif // NOTEOFFEVENT_H diff --git a/src/engine/events/NoteOnEvent.cpp b/src/engine/events/NoteOnEvent.cpp deleted file mode 100644 index 9688af79..00000000 --- a/src/engine/events/NoteOnEvent.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "NoteOnEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ObjectStore.h" -#include "Node.h" -#include "MidiNoteNode.h" -#include "MidiTriggerNode.h" -#include "Plugin.h" - -namespace Om { - - -/** Note on with Patch explicitly passed. - * - * Used to be triggered by MIDI. Not used anymore. - */ -NoteOnEvent::NoteOnEvent(CountedPtr responder, Node* patch, uchar note_num, uchar velocity) -: Event(responder), - m_node(patch), - m_note_num(note_num), - m_velocity(velocity), - m_is_osc_triggered(false) -{ -} - - -/** Note on with Node lookup. - * - * Triggered by OSC. - */ -NoteOnEvent::NoteOnEvent(CountedPtr responder, const string& node_path, uchar note_num, uchar velocity) -: Event(responder), - m_node(NULL), - m_node_path(node_path), - m_note_num(note_num), - m_velocity(velocity), - m_is_osc_triggered(true) -{ -} - - -void -NoteOnEvent::execute(samplecount offset) -{ - // Lookup if neccessary - if (m_is_osc_triggered) - m_node = om->object_store()->find_node(m_node_path); - - // FIXME: this isn't very good at all. - if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal) { - if (m_node->plugin()->plug_label() == "note_in") - ((MidiNoteNode*)m_node)->note_on(m_note_num, m_velocity, offset); - else if (m_node->plugin()->plug_label() == "trigger_in") - ((MidiTriggerNode*)m_node)->note_on(m_note_num, m_velocity, offset); - } -} - - -void -NoteOnEvent::post_process() -{ - if (m_is_osc_triggered) { - if (m_node != NULL) - m_responder->respond_ok(); - else - m_responder->respond_error("Did not find node for note_on"); - } -} - - -} // namespace Om - diff --git a/src/engine/events/NoteOnEvent.h b/src/engine/events/NoteOnEvent.h deleted file mode 100644 index 1e09e450..00000000 --- a/src/engine/events/NoteOnEvent.h +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef NOTEONEVENT_H -#define NOTEONEVENT_H - -#include "Event.h" -#include "util/types.h" -#include -using std::string; - -namespace Om { - -class Node; - - -/** A note on event. - * - * \ingroup engine - */ -class NoteOnEvent : public Event -{ -public: - NoteOnEvent(CountedPtr responder, Node* patch, uchar note_num, uchar velocity); - NoteOnEvent(CountedPtr responder, const string& node_path, uchar note_num, uchar velocity); - - void execute(samplecount offset); - void post_process(); - -private: - Node* m_node; - string m_node_path; - uchar m_note_num; - uchar m_velocity; - bool m_is_osc_triggered; -}; - - -} // namespace Om - -#endif // NOTEONEVENT_H diff --git a/src/engine/events/PingQueuedEvent.h b/src/engine/events/PingQueuedEvent.h deleted file mode 100644 index cfba7058..00000000 --- a/src/engine/events/PingQueuedEvent.h +++ /dev/null @@ -1,44 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PINGQUEUEDEVENT_H -#define PINGQUEUEDEVENT_H - -#include "QueuedEvent.h" -#include "util/types.h" -#include "Responder.h" - -namespace Om { - -class Port; - - -/** A "blocking" ping that travels through the event queue before responding. - * - * \ingroup engine - */ -class PingQueuedEvent : public QueuedEvent -{ -public: - PingQueuedEvent(CountedPtr responder) : QueuedEvent(responder) {} - - void post_process() { m_responder->respond_ok(); } -}; - - -} // namespace Om - -#endif // PINGQUEUEDEVENT_H diff --git a/src/engine/events/RegisterClientEvent.cpp b/src/engine/events/RegisterClientEvent.cpp deleted file mode 100644 index ca7dd1f6..00000000 --- a/src/engine/events/RegisterClientEvent.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "RegisterClientEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ClientBroadcaster.h" - -namespace Om { - - -RegisterClientEvent::RegisterClientEvent(CountedPtr responder, - ClientKey key, - CountedPtr client) -: QueuedEvent(responder) -, _key(key) -, _client(client) -{ -} - - -void -RegisterClientEvent::pre_process() -{ - om->client_broadcaster()->register_client(_key, _client); - - QueuedEvent::pre_process(); -} - - -void -RegisterClientEvent::post_process() -{ - m_responder->respond_ok(); -} - - -} // namespace Om - diff --git a/src/engine/events/RegisterClientEvent.h b/src/engine/events/RegisterClientEvent.h deleted file mode 100644 index f4b6b60f..00000000 --- a/src/engine/events/RegisterClientEvent.h +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef REGISTERCLIENTEVENT_H -#define REGISTERCLIENTEVENT_H - -#include "QueuedEvent.h" -#include "interface/ClientKey.h" -#include "interface/ClientInterface.h" -#include -using std::string; -using Om::Shared::ClientInterface; -using Om::Shared::ClientKey; - -namespace Om { - - -/** Registers a new client with the OSC system, so it can receive updates. - * - * \ingroup engine - */ -class RegisterClientEvent : public QueuedEvent -{ -public: - RegisterClientEvent(CountedPtr responder, - ClientKey key, - CountedPtr client); - - void pre_process(); - void post_process(); - -private: - ClientKey _key; - CountedPtr _client; -}; - - -} // namespace Om - -#endif // REGISTERCLIENTEVENT_H diff --git a/src/engine/events/RenameEvent.cpp b/src/engine/events/RenameEvent.cpp deleted file mode 100644 index e2e98dd0..00000000 --- a/src/engine/events/RenameEvent.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "RenameEvent.h" -#include "Responder.h" -#include "Patch.h" -#include "Node.h" -#include "Tree.h" -#include "Om.h" -#include "OmApp.h" -#include "ClientBroadcaster.h" -#include "util/Path.h" -#include "ObjectStore.h" - -namespace Om { - - -RenameEvent::RenameEvent(CountedPtr responder, const string& path, const string& name) -: QueuedEvent(responder), - m_old_path(path), - m_name(name), - m_new_path(m_old_path.parent().base_path() + name), - m_parent_patch(NULL), - m_store_treenode(NULL), - m_error(NO_ERROR) -{ - /* - if (m_old_path.parent() == "/") - m_new_path = string("/") + m_name; - else - m_new_path = m_old_path.parent() +"/"+ m_name;*/ -} - - -RenameEvent::~RenameEvent() -{ -} - - -void -RenameEvent::pre_process() -{ - if (m_name.find("/") != string::npos) { - m_error = INVALID_NAME; - QueuedEvent::pre_process(); - return; - } - - if (om->object_store()->find(m_new_path)) { - m_error = OBJECT_EXISTS; - QueuedEvent::pre_process(); - return; - } - - OmObject* obj = om->object_store()->find(m_old_path); - - if (obj == NULL) { - m_error = OBJECT_NOT_FOUND; - QueuedEvent::pre_process(); - return; - } - - // Renaming only works for Nodes and Patches (which are Nodes) - if (obj->as_node() == NULL) { - m_error = OBJECT_NOT_RENAMABLE; - QueuedEvent::pre_process(); - return; - } - - if (obj != NULL) { - obj->set_path(m_new_path); - assert(obj->path() == m_new_path); - } - - QueuedEvent::pre_process(); -} - - -void -RenameEvent::execute(samplecount offset) -{ - //cout << "Executing rename event..."; - QueuedEvent::execute(offset); -} - - -void -RenameEvent::post_process() -{ - string msg = "Unable to rename object - "; - - if (m_error == NO_ERROR) { - m_responder->respond_ok(); - om->client_broadcaster()->send_rename(m_old_path, m_new_path); - } else { - if (m_error == OBJECT_EXISTS) - msg.append("Object already exists at ").append(m_new_path); - else if (m_error == OBJECT_NOT_FOUND) - msg.append("Could not find object ").append(m_old_path); - else if (m_error == OBJECT_NOT_RENAMABLE) - msg.append(m_old_path).append(" is not renamable"); - else if (m_error == INVALID_NAME) - msg.append(m_name).append(" is not a valid name"); - - m_responder->respond_error(msg); - } -} - - -} // namespace Om diff --git a/src/engine/events/RenameEvent.h b/src/engine/events/RenameEvent.h deleted file mode 100644 index c1c9fe91..00000000 --- a/src/engine/events/RenameEvent.h +++ /dev/null @@ -1,66 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef RENAMEEVENT_H -#define RENAMEEVENT_H - -#include "QueuedEvent.h" -#include "util/Path.h" -#include -using std::string; - -template class TreeNode; -template class ListNode; - -namespace Om { - -class OmObject; -class Patch; -class Node; -class Plugin; -class DisconnectNodeEvent; -class DisconnectPortEvent; - - -/** An event to change the name of an OmObject. - * - * \ingroup engine - */ -class RenameEvent : public QueuedEvent -{ -public: - RenameEvent(CountedPtr responder, const string& path, const string& name); - ~RenameEvent(); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - enum ErrorType { NO_ERROR, OBJECT_NOT_FOUND, OBJECT_EXISTS, OBJECT_NOT_RENAMABLE, INVALID_NAME }; - - Path m_old_path; - string m_name; - Path m_new_path; - Patch* m_parent_patch; - TreeNode* m_store_treenode; - ErrorType m_error; -}; - - -} // namespace Om - -#endif // RENAMEEVENT_H diff --git a/src/engine/events/RequestAllObjectsEvent.cpp b/src/engine/events/RequestAllObjectsEvent.cpp deleted file mode 100644 index ef40a0de..00000000 --- a/src/engine/events/RequestAllObjectsEvent.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "RequestAllObjectsEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ObjectSender.h" - -namespace Om { - - -RequestAllObjectsEvent::RequestAllObjectsEvent(CountedPtr responder) -: QueuedEvent(responder), - m_client(CountedPtr(NULL)) -{ -} - - -void -RequestAllObjectsEvent::pre_process() -{ - m_client = m_responder->find_client(); - - QueuedEvent::pre_process(); -} - - -void -RequestAllObjectsEvent::post_process() -{ - if (m_client) { - m_responder->respond_ok(); - ObjectSender::send_all(m_client.get()); - } else { - m_responder->respond_error("Invalid URL"); - } -} - - -} // namespace Om - diff --git a/src/engine/events/RequestAllObjectsEvent.h b/src/engine/events/RequestAllObjectsEvent.h deleted file mode 100644 index df63a577..00000000 --- a/src/engine/events/RequestAllObjectsEvent.h +++ /dev/null @@ -1,50 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef REQUESTALLOBJECTSEVENT_H -#define REQUESTALLOBJECTSEVENT_H - -#include -#include "QueuedEvent.h" -using std::string; - -namespace Om { - -namespace Shared { - class ClientInterface; -} using Shared::ClientInterface; - - -/** A request from a client to send notification of all objects (ie refresh). - * - * \ingroup engine - */ -class RequestAllObjectsEvent : public QueuedEvent -{ -public: - RequestAllObjectsEvent(CountedPtr responder); - - void pre_process(); - void post_process(); - -private: - CountedPtr m_client; -}; - - -} // namespace Om - -#endif // REQUESTALLOBJECTSEVENT_H diff --git a/src/engine/events/RequestMetadataEvent.cpp b/src/engine/events/RequestMetadataEvent.cpp deleted file mode 100644 index 10e1007c..00000000 --- a/src/engine/events/RequestMetadataEvent.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "RequestMetadataEvent.h" -#include -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "OmObject.h" -#include "ObjectStore.h" -#include "interface/ClientInterface.h" -#include "ClientBroadcaster.h" -using std::string; - -namespace Om { - - -RequestMetadataEvent::RequestMetadataEvent(CountedPtr responder, const string& node_path, const string& key) -: QueuedEvent(responder), - m_path(node_path), - m_key(key), - m_value(""), - m_object(NULL), - m_client(CountedPtr(NULL)) -{ -} - - -void -RequestMetadataEvent::pre_process() -{ - m_client = m_responder->find_client(); - - if (m_client) { - m_object = om->object_store()->find(m_path); - if (m_object == NULL) { - QueuedEvent::pre_process(); - return; - } - } - - m_value = m_object->get_metadata(m_key); - - QueuedEvent::pre_process(); -} - - -void -RequestMetadataEvent::post_process() -{ - if (m_client) { - if (m_value == "") { - string msg = "Unable to find object "; - msg += m_path; - m_responder->respond_error(msg); - } else { - m_responder->respond_ok(); - m_client->metadata_update(m_path, m_key, m_value); - } - } else { - m_responder->respond_error("Unknown client"); - } -} - - -} // namespace Om - diff --git a/src/engine/events/RequestMetadataEvent.h b/src/engine/events/RequestMetadataEvent.h deleted file mode 100644 index e4243eb3..00000000 --- a/src/engine/events/RequestMetadataEvent.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef REQUESTMETADATAEVENT_H -#define REQUESTMETADATAEVENT_H - -#include -#include "QueuedEvent.h" - -using std::string; - -namespace Om { - -class OmObject; -namespace Shared { - class ClientInterface; -} using Shared::ClientInterface; - - -/** A request from a client for a piece of metadata. - * - * \ingroup engine - */ -class RequestMetadataEvent : public QueuedEvent -{ -public: - RequestMetadataEvent(CountedPtr responder, const string& path, const string& key); - - void pre_process(); - void post_process(); - -private: - string m_path; - string m_key; - string m_value; - OmObject* m_object; - CountedPtr m_client; -}; - - -} // namespace Om - -#endif // REQUESTMETADATAEVENT_H diff --git a/src/engine/events/RequestPluginsEvent.cpp b/src/engine/events/RequestPluginsEvent.cpp deleted file mode 100644 index 89dbefd5..00000000 --- a/src/engine/events/RequestPluginsEvent.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "RequestPluginsEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ClientBroadcaster.h" - -namespace Om { - - -RequestPluginsEvent::RequestPluginsEvent(CountedPtr responder) -: QueuedEvent(responder), - m_client(CountedPtr(NULL)) -{ -} - - -void -RequestPluginsEvent::pre_process() -{ - m_client = m_responder->find_client(); - - QueuedEvent::pre_process(); -} - - -void -RequestPluginsEvent::post_process() -{ - if (m_client) { - om->client_broadcaster()->send_plugins_to(m_client.get()); - m_responder->respond_ok(); - } else { - m_responder->respond_error("Invalid URL"); - } -} - - -} // namespace Om - diff --git a/src/engine/events/RequestPluginsEvent.h b/src/engine/events/RequestPluginsEvent.h deleted file mode 100644 index 83447fb3..00000000 --- a/src/engine/events/RequestPluginsEvent.h +++ /dev/null @@ -1,51 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef REQUESTPLUGINSEVENT_H -#define REQUESTPLUGINSEVENT_H - -#include -#include "QueuedEvent.h" -using std::string; - -namespace Om { - -class Responder; -namespace Shared { - class ClientInterface; -} using Shared::ClientInterface; - - -/** A request from a client to send notification of all objects (ie refresh). - * - * \ingroup engine - */ -class RequestPluginsEvent : public QueuedEvent -{ -public: - RequestPluginsEvent(CountedPtr responder); - - void pre_process(); - void post_process(); - -private: - CountedPtr m_client; -}; - - -} // namespace Om - -#endif // REQUESTPLUGINSEVENT_H diff --git a/src/engine/events/RequestPortValueEvent.cpp b/src/engine/events/RequestPortValueEvent.cpp deleted file mode 100644 index e4d3985e..00000000 --- a/src/engine/events/RequestPortValueEvent.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "RequestPortValueEvent.h" -#include -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "interface/ClientInterface.h" -#include "PortBase.h" -#include "PortInfo.h" -#include "ObjectStore.h" -#include "ClientBroadcaster.h" - -using std::string; - -namespace Om { - - -RequestPortValueEvent::RequestPortValueEvent(CountedPtr responder, const string& port_path) -: QueuedEvent(responder), - m_port_path(port_path), - m_port(NULL), - m_value(0.0), - m_client(CountedPtr(NULL)) -{ -} - - -void -RequestPortValueEvent::pre_process() -{ - m_client = m_responder->find_client(); - m_port = om->object_store()->find_port(m_port_path); - - QueuedEvent::pre_process(); -} - - -void -RequestPortValueEvent::execute(samplecount offset) -{ - if (m_port != NULL && m_port->port_info()->is_audio() || m_port->port_info()->is_control()) - m_value = ((PortBase*)m_port)->buffer(0)->value_at(offset); - else - m_port = NULL; // triggers error response - - QueuedEvent::execute(offset); -} - - -void -RequestPortValueEvent::post_process() -{ - string msg; - if (m_port) { - m_responder->respond_error("Unable to find port for get_value responder."); - } else if (m_client) { - m_responder->respond_ok(); - m_client->control_change(m_port_path, m_value); - } else { - m_responder->respond_error("Invalid URL"); - } -} - - -} // namespace Om - diff --git a/src/engine/events/RequestPortValueEvent.h b/src/engine/events/RequestPortValueEvent.h deleted file mode 100644 index d970ee9c..00000000 --- a/src/engine/events/RequestPortValueEvent.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef REQUESTPORTVALUEEVENT_H -#define REQUESTPORTVALUEEVENT_H - -#include -#include "QueuedEvent.h" -#include "util/types.h" - -using std::string; - -namespace Om { - -class Port; -namespace Shared { class ClientInterface; } -using Shared::ClientInterface; - - -/** A request from a client to send the value of a port. - * - * \ingroup engine - */ -class RequestPortValueEvent : public QueuedEvent -{ -public: - RequestPortValueEvent(CountedPtr responder, const string& port_path); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_port_path; - Port* m_port; - sample m_value; - CountedPtr m_client; -}; - - -} // namespace Om - -#endif // REQUESTPORTVALUEEVENT_H diff --git a/src/engine/events/SetMetadataEvent.cpp b/src/engine/events/SetMetadataEvent.cpp deleted file mode 100644 index 614f7ca9..00000000 --- a/src/engine/events/SetMetadataEvent.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "SetMetadataEvent.h" -#include -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ClientBroadcaster.h" -#include "OmObject.h" -#include "ObjectStore.h" - -using std::string; - -namespace Om { - - -SetMetadataEvent::SetMetadataEvent(CountedPtr responder, const string& path, const string& key, const string& value) -: QueuedEvent(responder), - m_path(path), - m_key(key), - m_value(value), - m_object(NULL) -{ -} - - -void -SetMetadataEvent::pre_process() -{ - m_object = om->object_store()->find(m_path); - if (m_object == NULL) { - QueuedEvent::pre_process(); - return; - } - - m_object->set_metadata(m_key, m_value); - - QueuedEvent::pre_process(); -} - - -void -SetMetadataEvent::execute(samplecount offset) -{ - // Do nothing - - QueuedEvent::execute(offset); -} - - -void -SetMetadataEvent::post_process() -{ - if (m_object == NULL) { - string msg = "Unable to find object "; - msg += m_path; - m_responder->respond_error(msg); - } else { - m_responder->respond_ok(); - om->client_broadcaster()->send_metadata_update(m_path, m_key, m_value); - } -} - - -} // namespace Om diff --git a/src/engine/events/SetMetadataEvent.h b/src/engine/events/SetMetadataEvent.h deleted file mode 100644 index ef471033..00000000 --- a/src/engine/events/SetMetadataEvent.h +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SETMETADATAEVENT_H -#define SETMETADATAEVENT_H - -#include -#include "QueuedEvent.h" - -using std::string; - -namespace Om { - -class OmObject; - - -/** An event to set a piece of metadata for an OmObject. - * - * \ingroup engine - */ -class SetMetadataEvent : public QueuedEvent -{ -public: - SetMetadataEvent(CountedPtr responder, const string& path, const string& key, const string& value); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - string m_path; - string m_key; - string m_value; - OmObject* m_object; -}; - - -} // namespace Om - -#endif // SETMETADATAEVENT_H diff --git a/src/engine/events/SetPortValueEvent.cpp b/src/engine/events/SetPortValueEvent.cpp deleted file mode 100644 index 964cd9ca..00000000 --- a/src/engine/events/SetPortValueEvent.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "SetPortValueEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "PortBase.h" -#include "PortInfo.h" -#include "ClientBroadcaster.h" -#include "Node.h" -#include "ObjectStore.h" - -namespace Om { - - -/** Voice-specific control setting - */ -SetPortValueEvent::SetPortValueEvent(CountedPtr responder, size_t voice_num, const string& port_path, sample val) -: Event(responder), - m_voice_num(voice_num), - m_port_path(port_path), - m_val(val), - m_port(NULL), - m_error(NO_ERROR) -{ -} - - -SetPortValueEvent::SetPortValueEvent(CountedPtr responder, const string& port_path, sample val) -: Event(responder), - m_voice_num(-1), - m_port_path(port_path), - m_val(val), - m_port(NULL), - m_error(NO_ERROR) -{ -} - - -void -SetPortValueEvent::execute(samplecount offset) -{ - if (m_port == NULL) - m_port = om->object_store()->find_port(m_port_path); - - if (m_port == NULL) { - m_error = PORT_NOT_FOUND; - } else if (!m_port->port_info()->is_audio() && !m_port->port_info()->is_control()) { - m_error = TYPE_MISMATCH; - } else { - if (m_voice_num == -1) - ((PortBase*)m_port)->set_value(m_val, offset); - else - ((PortBase*)m_port)->set_value(m_voice_num, m_val, offset); - //((PortBase*)m_port)->buffer(m_voice_num)->set(m_val, offset); // FIXME: check range - } -} - - -void -SetPortValueEvent::post_process() -{ - if (m_error == NO_ERROR) { - assert(m_port != NULL); - - m_responder->respond_ok(); - om->client_broadcaster()->send_control_change(m_port_path, m_val); - - // Send patch port control change, if this is a bridge port - Port* parent_port = m_port->parent_node()->as_port(); - if (parent_port != NULL) { - assert(parent_port->port_info()->is_control() || parent_port->port_info()->is_audio()); - om->client_broadcaster()->send_control_change(parent_port->path(), m_val); - } - - } else if (m_error == PORT_NOT_FOUND) { - string msg = "Unable to find port "; - msg.append(m_port_path).append(" for set_port_value"); - m_responder->respond_error(msg); - - } else if (m_error == TYPE_MISMATCH) { - string msg = "Attempt to set "; - msg.append(m_port_path).append(" to incompatible type"); - m_responder->respond_error(msg); - } -} - - -} // namespace Om - diff --git a/src/engine/events/SetPortValueEvent.h b/src/engine/events/SetPortValueEvent.h deleted file mode 100644 index 0a9614b9..00000000 --- a/src/engine/events/SetPortValueEvent.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SETPORTVALUEEVENT_H -#define SETPORTVALUEEVENT_H - -#include -#include "Event.h" -#include "util/types.h" -using std::string; - -namespace Om { - -class Port; - - -/** An event to change the value of a port. - * - * \ingroup engine - */ -class SetPortValueEvent : public Event -{ -public: - SetPortValueEvent(CountedPtr responder, const string& port_path, sample val); - SetPortValueEvent(CountedPtr responder, size_t voice_num, const string& port_path, sample val); - - void execute(samplecount offset); - void post_process(); - -private: - enum ErrorType { NO_ERROR, PORT_NOT_FOUND, TYPE_MISMATCH }; - - int m_voice_num; - string m_port_path; - float m_val; - Port* m_port; - ErrorType m_error; -}; - - -} // namespace Om - -#endif // SETPORTVALUEEVENT_H diff --git a/src/engine/events/SetPortValueQueuedEvent.cpp b/src/engine/events/SetPortValueQueuedEvent.cpp deleted file mode 100644 index e73c0486..00000000 --- a/src/engine/events/SetPortValueQueuedEvent.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "SetPortValueQueuedEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "PortBase.h" -#include "PortInfo.h" -#include "ClientBroadcaster.h" -#include "Plugin.h" -#include "Node.h" -#include "ObjectStore.h" - -namespace Om { - - -/** Voice-specific control setting - */ -SetPortValueQueuedEvent::SetPortValueQueuedEvent(CountedPtr responder, size_t voice_num, const string& port_path, sample val) -: QueuedEvent(responder), - m_voice_num(voice_num), - m_port_path(port_path), - m_val(val), - m_port(NULL), - m_error(NO_ERROR) -{ -} - - -SetPortValueQueuedEvent::SetPortValueQueuedEvent(CountedPtr responder, const string& port_path, sample val) -: QueuedEvent(responder), - m_voice_num(-1), - m_port_path(port_path), - m_val(val), - m_port(NULL), - m_error(NO_ERROR) -{ -} - - -void -SetPortValueQueuedEvent::pre_process() -{ - if (m_port == NULL) - m_port = om->object_store()->find_port(m_port_path); - - if (m_port == NULL) { - m_error = PORT_NOT_FOUND; - } else if (!m_port->port_info()->is_audio() && !m_port->port_info()->is_control()) { - m_error = TYPE_MISMATCH; - } - - QueuedEvent::pre_process(); -} - - -void -SetPortValueQueuedEvent::execute(samplecount offset) -{ - QueuedEvent::execute(offset); - - if (m_error == NO_ERROR) { - assert(m_port != NULL); - if (m_voice_num == -1) - ((PortBase*)m_port)->set_value(m_val, offset); - else - ((PortBase*)m_port)->buffer(m_voice_num)->set(m_val, offset); // FIXME: check range - } -} - - -void -SetPortValueQueuedEvent::post_process() -{ - if (m_error == NO_ERROR) { - assert(m_port != NULL); - - m_responder->respond_ok(); - om->client_broadcaster()->send_control_change(m_port_path, m_val); - - // Send patch port control change, if this is a bridge port - Port* parent_port = m_port->parent_node()->as_port(); - if (parent_port != NULL) { - assert(parent_port->port_info()->is_control() || parent_port->port_info()->is_audio()); - om->client_broadcaster()->send_control_change(parent_port->path(), m_val); - } - - } else if (m_error == PORT_NOT_FOUND) { - string msg = "Unable to find port "; - msg.append(m_port_path).append(" for set_port_value_slow"); - m_responder->respond_error(msg); - - } else if (m_error == TYPE_MISMATCH) { - string msg = "Attempt to set "; - msg.append(m_port_path).append(" to incompatible type"); - m_responder->respond_error(msg); - } -} - - -} // namespace Om - diff --git a/src/engine/events/SetPortValueQueuedEvent.h b/src/engine/events/SetPortValueQueuedEvent.h deleted file mode 100644 index b92beacf..00000000 --- a/src/engine/events/SetPortValueQueuedEvent.h +++ /dev/null @@ -1,57 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SETPORTVALUEQUEUEDEVENT_H -#define SETPORTVALUEQUEUEDEVENT_H - -#include "QueuedEvent.h" -#include "util/types.h" -#include -using std::string; - -namespace Om { - -class Port; - - -/** An event to change the value of a port. - * - * \ingroup engine - */ -class SetPortValueQueuedEvent : public QueuedEvent -{ -public: - SetPortValueQueuedEvent(CountedPtr responder, const string& port_path, sample val); - SetPortValueQueuedEvent(CountedPtr responder, size_t voice_num, const string& port_path, sample val); - - void pre_process(); - void execute(samplecount offset); - void post_process(); - -private: - enum ErrorType { NO_ERROR, PORT_NOT_FOUND, TYPE_MISMATCH }; - - int m_voice_num; - string m_port_path; - float m_val; - Port* m_port; - ErrorType m_error; -}; - - -} // namespace Om - -#endif // SETPORTVALUEQUEUEDEVENT_H diff --git a/src/engine/events/UnregisterClientEvent.cpp b/src/engine/events/UnregisterClientEvent.cpp deleted file mode 100644 index ef5a9979..00000000 --- a/src/engine/events/UnregisterClientEvent.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "UnregisterClientEvent.h" -#include "Responder.h" -#include "Om.h" -#include "OmApp.h" -#include "ClientBroadcaster.h" -#include "interface/ClientInterface.h" - -namespace Om { - - -UnregisterClientEvent::UnregisterClientEvent(CountedPtr responder, ClientKey key) -: QueuedEvent(responder) -, _key(key) -{ -} - - -void -UnregisterClientEvent::post_process() -{ - if (om->client_broadcaster()->unregister_client(_key)) - m_responder->respond_ok(); - else - m_responder->respond_error("Unable to unregister client"); -} - - -} // namespace Om - diff --git a/src/engine/events/UnregisterClientEvent.h b/src/engine/events/UnregisterClientEvent.h deleted file mode 100644 index fdbdb314..00000000 --- a/src/engine/events/UnregisterClientEvent.h +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef UNREGISTERCLIENTEVENT_H -#define UNREGISTERCLIENTEVENT_H - -#include "QueuedEvent.h" -#include "interface/ClientKey.h" -#include -using std::string; - -namespace Om { - -namespace Shared { - class ClientInterface; - class ClientKey; -} -using Shared::ClientInterface; -using Shared::ClientKey; - - -/** Unregisters an OSC client so it no longer receives notifications. - * - * \ingroup engine - */ -class UnregisterClientEvent : public QueuedEvent -{ -public: - UnregisterClientEvent(CountedPtr responder, ClientKey key); - - void post_process(); - -private: - ClientKey _key; -}; - - -} // namespace Om - -#endif // UNREGISTERCLIENTEVENT_H diff --git a/src/engine/instantiations.cpp b/src/engine/instantiations.cpp deleted file mode 100644 index e2b0088d..00000000 --- a/src/engine/instantiations.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * Explicit template instantiations. - * - * Need to do this to avoid undefined references, because GCC doesn't seem to - * know how to recursively instantiate templates. Cleaner to do it all here - * than pollute everything with it. :/ - */ - -#include "Tree.h" -#include "TreeImplementation.h" -#include "OmObject.h" -#include "Node.h" - - -/* Tree */ -template class Tree; -template class TreeNode; - -template Tree::Tree(); -template Tree::~Tree(); -template void Tree::insert(TreeNode* const n); -template TreeNode* Tree::remove(const string& key); -template Om::OmObject* Tree::find(const string& key) const; -template TreeNode* Tree::find_treenode(const string& key) const; - -template Tree::iterator Tree::begin() const; -template Tree::iterator Tree::end() const; - -template Tree::iterator::~iterator(); -template Om::OmObject* Tree::iterator::operator*() const; -template Tree::iterator& Tree::iterator::operator++(); -template bool Tree::iterator::operator!=(const iterator& iter) const; - diff --git a/src/engine/main.cpp b/src/engine/main.cpp deleted file mode 100644 index a69c7e76..00000000 --- a/src/engine/main.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include "config.h" -#include "util.h" -#include "cmdline.h" -#include "Om.h" -#include "OmApp.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif -#ifdef BUILD_IN_PROCESS_ENGINE -#include -#include -#endif - -using std::cout; using std::endl; using std::cerr; - - -void -catch_int(int) -{ - signal(SIGINT, catch_int); - signal(SIGTERM, catch_int); - - std::cout << "[Main] Om interrupted." << std::endl; - Om::om->quit(); -} - - -#ifdef BUILD_IN_PROCESS_ENGINE - -jack_client_t* jack_client; -jack_intclient_t jack_intclient; - - -void -unload_in_process_engine(int) -{ - jack_status_t status; - int ret = EXIT_SUCCESS; - - cout << "Unloading..."; - status = jack_internal_client_unload(jack_client, jack_intclient); - if (status & JackFailure) { - cout << "failed" << endl; - ret = EXIT_FAILURE; - } else { - cout << "done" << endl; - } - jack_client_close(jack_client); - exit(ret); -} - - -int -load_in_process_engine(const char* port) -{ - int ret = EXIT_SUCCESS; - - jack_status_t status; - - if ((jack_client = jack_client_open("om_load", JackNoStartServer, - &status)) != NULL) { - jack_intclient = - jack_internal_client_load(jack_client, "Om", - (jack_options_t)(JackLoadName|JackLoadInit), - &status, "om", port); - if (status == 0) { - cout << "Engine loaded" << endl; - signal(SIGINT, unload_in_process_engine); - signal(SIGTERM, unload_in_process_engine); - - while (1) { - sleep(1); - } - } else if (status & JackFailure) { - cerr << "Could not load om.so" << endl; - ret = EXIT_FAILURE; - } - - jack_client_close(jack_client); - } else { - cerr << "jack_client_open failed" << endl; - ret = EXIT_FAILURE; - } -} - -#endif // BUILD_IN_PROCESS_ENGINE - - -int -main(int argc, char** argv) -{ -#ifdef HAVE_LASH - lash_args_t* lash_args = lash_extract_args(&argc, &argv); -#endif - - int ret = EXIT_SUCCESS; - - /* Parse command line options */ - gengetopt_args_info args_info; - if (cmdline_parser (argc, argv, &args_info) != 0) - return EXIT_FAILURE; - - - if (args_info.in_jackd_flag) { -#ifdef BUILD_IN_PROCESS_ENGINE - ret = load_in_process_engine(args_info.port_arg); -#else - cerr << "In-process Jack client support not enabled in this build." << endl; - ret = EXIT_FAILURE; -#endif // JACK_IN_PROCESS_ENGINE - } else { - signal(SIGINT, catch_int); - signal(SIGTERM, catch_int); - - Om::set_denormal_flags(); - - Om::om = new Om::OmApp(args_info.port_arg); - -#ifdef HAVE_LASH - Om::lash_driver = new Om::LashDriver(Om::om, lash_args); -#endif - - Om::om->main(); - -#ifdef HAVE_LASH - delete Om::lash_driver; -#endif - - delete Om::om; - } - - return ret; -} - diff --git a/src/engine/midi.h b/src/engine/midi.h deleted file mode 100644 index 6575ede7..00000000 --- a/src/engine/midi.h +++ /dev/null @@ -1,135 +0,0 @@ -/* Definitions to ease working with raw MIDI. - * - * Stolen from Alsa's asounddef.h - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef MIDI_H -#define MIDI_H - - -/** - * \defgroup midi MIDI Definitions - * MIDI command and controller number definitions. - * \{ - */ - -// Commands: - -#define MIDI_CMD_NOTE_OFF 0x80 /**< note off */ -#define MIDI_CMD_NOTE_ON 0x90 /**< note on */ -#define MIDI_CMD_NOTE_PRESSURE 0xA0 /**< key pressure */ -#define MIDI_CMD_CONTROL 0xB0 /**< control change */ -#define MIDI_CMD_PGM_CHANGE 0xC0 /**< program change */ -#define MIDI_CMD_CHANNEL_PRESSURE 0xD0 /**< channel pressure */ -#define MIDI_CMD_BENDER 0xE0 /**< pitch bender */ - -#define MIDI_CMD_COMMON_SYSEX 0xF0 /**< sysex (system exclusive) begin */ -#define MIDI_CMD_COMMON_MTC_QUARTER 0xF1 /**< MTC quarter frame */ -#define MIDI_CMD_COMMON_SONG_POS 0xF2 /**< song position */ -#define MIDI_CMD_COMMON_SONG_SELECT 0xF3 /**< song select */ -#define MIDI_CMD_COMMON_TUNE_REQUEST 0xF6 /**< tune request */ -#define MIDI_CMD_COMMON_SYSEX_END 0xF7 /**< end of sysex */ -#define MIDI_CMD_COMMON_CLOCK 0xF8 /**< clock */ -#define MIDI_CMD_COMMON_START 0xFA /**< start */ -#define MIDI_CMD_COMMON_CONTINUE 0xFB /**< continue */ -#define MIDI_CMD_COMMON_STOP 0xFC /**< stop */ -#define MIDI_CMD_COMMON_SENSING 0xFE /**< active sensing */ -#define MIDI_CMD_COMMON_RESET 0xFF /**< reset */ - - -// Controllers: - -#define MIDI_CTL_MSB_BANK 0x00 /**< Bank selection */ -#define MIDI_CTL_MSB_MODWHEEL 0x01 /**< Modulation */ -#define MIDI_CTL_MSB_BREATH 0x02 /**< Breath */ -#define MIDI_CTL_MSB_FOOT 0x04 /**< Foot */ -#define MIDI_CTL_MSB_PORTAMENTO_TIME 0x05 /**< Portamento time */ -#define MIDI_CTL_MSB_DATA_ENTRY 0x06 /**< Data entry */ -#define MIDI_CTL_MSB_MAIN_VOLUME 0x07 /**< Main volume */ -#define MIDI_CTL_MSB_BALANCE 0x08 /**< Balance */ -#define MIDI_CTL_MSB_PAN 0x0A /**< Panpot */ -#define MIDI_CTL_MSB_EXPRESSION 0x0B /**< Expression */ -#define MIDI_CTL_MSB_EFFECT1 0x0C /**< Effect1 */ -#define MIDI_CTL_MSB_EFFECT2 0x0D /**< Effect2 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE1 0x10 /**< General purpose 1 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE2 0x11 /**< General purpose 2 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE3 0x12 /**< General purpose 3 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE4 0x13 /**< General purpose 4 */ -#define MIDI_CTL_LSB_BANK 0x20 /**< Bank selection */ -#define MIDI_CTL_LSB_MODWHEEL 0x21 /**< Modulation */ -#define MIDI_CTL_LSB_BREATH 0x22 /**< Breath */ -#define MIDI_CTL_LSB_FOOT 0x24 /**< Foot */ -#define MIDI_CTL_LSB_PORTAMENTO_TIME 0x25 /**< Portamento time */ -#define MIDI_CTL_LSB_DATA_ENTRY 0x26 /**< Data entry */ -#define MIDI_CTL_LSB_MAIN_VOLUME 0x27 /**< Main volume */ -#define MIDI_CTL_LSB_BALANCE 0x28 /**< Balance */ -#define MIDI_CTL_LSB_PAN 0x2A /**< Panpot */ -#define MIDI_CTL_LSB_EXPRESSION 0x2B /**< Expression */ -#define MIDI_CTL_LSB_EFFECT1 0x2C /**< Effect1 */ -#define MIDI_CTL_LSB_EFFECT2 0x2D /**< Effect2 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE1 0x30 /**< General purpose 1 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE2 0x31 /**< General purpose 2 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE3 0x32 /**< General purpose 3 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE4 0x33 /**< General purpose 4 */ -#define MIDI_CTL_SUSTAIN 0x40 /**< Sustain pedal */ -#define MIDI_CTL_PORTAMENTO 0x41 /**< Portamento */ -#define MIDI_CTL_SOSTENUTO 0x42 /**< Sostenuto */ -#define MIDI_CTL_SUSTENUTO 0x42 /**< Sostenuto (a typo in the older version) */ -#define MIDI_CTL_SOFT_PEDAL 0x43 /**< Soft pedal */ -#define MIDI_CTL_LEGATO_FOOTSWITCH 0x44 /**< Legato foot switch */ -#define MIDI_CTL_HOLD2 0x45 /**< Hold2 */ -#define MIDI_CTL_SC1_SOUND_VARIATION 0x46 /**< SC1 Sound Variation */ -#define MIDI_CTL_SC2_TIMBRE 0x47 /**< SC2 Timbre */ -#define MIDI_CTL_SC3_RELEASE_TIME 0x48 /**< SC3 Release Time */ -#define MIDI_CTL_SC4_ATTACK_TIME 0x49 /**< SC4 Attack Time */ -#define MIDI_CTL_SC5_BRIGHTNESS 0x4A /**< SC5 Brightness */ -#define MIDI_CTL_SC6 0x4B /**< SC6 */ -#define MIDI_CTL_SC7 0x4C /**< SC7 */ -#define MIDI_CTL_SC8 0x4D /**< SC8 */ -#define MIDI_CTL_SC9 0x4E /**< SC9 */ -#define MIDI_CTL_SC10 0x4F /**< SC10 */ -#define MIDI_CTL_GENERAL_PURPOSE5 0x50 /**< General purpose 5 */ -#define MIDI_CTL_GENERAL_PURPOSE6 0x51 /**< General purpose 6 */ -#define MIDI_CTL_GENERAL_PURPOSE7 0x52 /**< General purpose 7 */ -#define MIDI_CTL_GENERAL_PURPOSE8 0x53 /**< General purpose 8 */ -#define MIDI_CTL_PORTAMENTO_CONTROL 0x54 /**< Portamento control */ -#define MIDI_CTL_E1_REVERB_DEPTH 0x5B /**< E1 Reverb Depth */ -#define MIDI_CTL_E2_TREMOLO_DEPTH 0x5C /**< E2 Tremolo Depth */ -#define MIDI_CTL_E3_CHORUS_DEPTH 0x5D /**< E3 Chorus Depth */ -#define MIDI_CTL_E4_DETUNE_DEPTH 0x5E /**< E4 Detune Depth */ -#define MIDI_CTL_E5_PHASER_DEPTH 0x5F /**< E5 Phaser Depth */ -#define MIDI_CTL_DATA_INCREMENT 0x60 /**< Data Increment */ -#define MIDI_CTL_DATA_DECREMENT 0x61 /**< Data Decrement */ -#define MIDI_CTL_NONREG_PARM_NUM_LSB 0x62 /**< Non-registered parameter number */ -#define MIDI_CTL_NONREG_PARM_NUM_MSB 0x63 /**< Non-registered parameter number */ -#define MIDI_CTL_REGIST_PARM_NUM_LSB 0x64 /**< Registered parameter number */ -#define MIDI_CTL_REGIST_PARM_NUM_MSB 0x65 /**< Registered parameter number */ -#define MIDI_CTL_ALL_SOUNDS_OFF 0x78 /**< All sounds off */ -#define MIDI_CTL_RESET_CONTROLLERS 0x79 /**< Reset Controllers */ -#define MIDI_CTL_LOCAL_CONTROL_SWITCH 0x7A /**< Local control switch */ -#define MIDI_CTL_ALL_NOTES_OFF 0x7B /**< All notes off */ -#define MIDI_CTL_OMNI_OFF 0x7C /**< Omni off */ -#define MIDI_CTL_OMNI_ON 0x7D /**< Omni on */ -#define MIDI_CTL_MONO1 0x7E /**< Mono1 */ -#define MIDI_CTL_MONO2 0x7F /**< Mono2 */ -//@} - - -/** \} */ - -#endif /* MIDI_H */ diff --git a/src/engine/tests/Makefile.am b/src/engine/tests/Makefile.am deleted file mode 100644 index 54f6ad1f..00000000 --- a/src/engine/tests/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -if BUILD_UNIT_TESTS - -AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ -I../../common -common_ldadd = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ -lrt -node_tree_test_LDADD = $(common_ldadd) -queue_test_LDADD = $(common_ldadd) - -bin_PROGRAMS = node_tree_test queue_test list_test path_test - -list_test_SOURCES = \ - ../List.h \ - list_test.cpp - -path_test_SOURCES = \ - ../../common/Path.h \ - path_test.cpp - -node_tree_test_SOURCES = \ - node_tree_test.cpp \ - ../Tree.h \ - ../TreeImplementation.h - -queue_test_SOURCES = \ - queue_test.cpp \ - ../../common/Queue.h - -endif # BUILD_UNIT_TESTS diff --git a/src/engine/tests/list_test.cpp b/src/engine/tests/list_test.cpp deleted file mode 100644 index d2f91c9d..00000000 --- a/src/engine/tests/list_test.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "../List.h" -#include -#include - -using std::cout; using std::endl; - - -int main() -{ - List l; - - l.push_back(new ListNode(1)); - l.push_back(new ListNode(2)); - l.push_back(new ListNode(3)); - l.push_back(new ListNode(4)); - l.push_back(new ListNode(5)); - l.push_back(new ListNode(6)); - l.push_back(new ListNode(7)); - l.push_back(new ListNode(8)); - - cout << "List:" << endl; - for (List::iterator i = l.begin(); i != l.end(); ++i) { - cout << *i << endl; - } - cout << endl; - - - for (List::iterator i = l.begin(); i != l.end(); ++i) { - if ((*i) == 4) - l.remove(i); - } - - std::cerr << "Removed 4 (by iterator)...\n"; - for (List::iterator i = l.begin(); i != l.end(); ++i) { - cout << *i << endl; - } - cout << endl; - - l.remove(1); - - std::cerr << "Removed 1 (head) (by value)...\n"; - for (List::iterator i = l.begin(); i != l.end(); ++i) { - cout << *i << endl; - } - cout << endl; - - for (List::iterator i = l.begin(); i != l.end(); ++i) { - if ((*i) == 2) - l.remove(i); - } - - std::cerr << "Removed 2 (head) (by iterator)...\n"; - for (List::iterator i = l.begin(); i != l.end(); ++i) { - cout << *i << endl; - } - cout << endl; - - l.remove(5); - - std::cerr << "Removed 5 (by value)...\n"; - for (List::iterator i = l.begin(); i != l.end(); ++i) { - cout << *i << endl; - } - cout << endl; - - l.remove(8); - - std::cerr << "Removed 8 (tail) (by value)...\n"; - for (List::iterator i = l.begin(); i != l.end(); ++i) { - cout << *i << endl; - } - cout << endl; - - for (List::iterator i = l.begin(); i != l.end(); ++i) { - if ((*i) == 7) - l.remove(i); - } - - std::cerr << "Removed 7 (tail) (by iterator)...\n"; - for (List::iterator i = l.begin(); i != l.end(); ++i) { - cout << *i << endl; - } - cout << endl; - - List r; - r.push_back(new ListNode(9)); - r.remove(9); - std::cerr << "Should not see ANY numbers:\n"; - for (List::iterator i = r.begin(); i != r.end(); ++i) { - cout << *i << endl; - } - return 0; -} diff --git a/src/engine/tests/node_tree_test.cpp b/src/engine/tests/node_tree_test.cpp deleted file mode 100644 index 2bce9b97..00000000 --- a/src/engine/tests/node_tree_test.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include -#include -#include "../Tree.h" -#include "../TreeImplementation.h" - -using std::vector; -using std::cout; using std::cerr; using std::endl; - -static const uint NUM_NODES = 20; - -int -main() -{ - cout << "\n\n\n\n"; - - Tree tree; - vector names; - vector in_tree; // arrays - uint num_in_tree = 0; - - - string name; - - for (uint i=0; i < NUM_NODES; ++i) { - name = (char)(i+'A'); - TreeNode* n = new TreeNode(name, name); - tree.insert(n); - names.push_back(name); - in_tree.push_back(true); - ++num_in_tree; - } - - cout << "Added " << NUM_NODES << " nodes." << endl; - cout << "Tree size: " << tree.size() << endl << endl; - - cout << "Tree contents: " << endl; - for (Tree::iterator i = tree.begin(); i != tree.end(); ++i) { - cout << (*i) << ", "; - } - cout << endl; - - - while (true) { - bool insert; - int num = rand() % NUM_NODES; - - if (num_in_tree == 0) - insert = true; - else if (num_in_tree == NUM_NODES) - insert = false; - else { - while (true) { - insert = rand() % 2; - num = rand() % NUM_NODES; - if ((insert && !in_tree[num]) || (!insert && in_tree[num])) - break; - } - } - - string name = names[num]; - - if (insert) { - assert(in_tree[num] == false); - cout << "\nInserting '" << name << "'" << endl; - tree.insert(new TreeNode(name, name)); - in_tree[num] = true; - ++num_in_tree; - cout << "Tree size: " << tree.size() << endl; - assert(num_in_tree == tree.size()); - } else { - assert(in_tree[num] == true); - cout << "\nRemoving '" << name << "'" << endl; - TreeNode* removed = tree.remove(name); - assert(removed != NULL); - assert(removed->node() == name); - assert(removed->key() == name); - delete removed; - in_tree[num] = false; - assert(names[num] == name); - --num_in_tree; - cout << "Tree size: " << tree.size() << endl; - assert(num_in_tree == tree.size()); - } - assert(num_in_tree == tree.size()); - cout << "Tree contents: " << endl; - for (Tree::iterator i = tree.begin(); i != tree.end(); ++i) { - cout << (*i) << ", "; - } - cout << endl; - } - - return 0; -} diff --git a/src/engine/tests/old_node_tree_test.cpp b/src/engine/tests/old_node_tree_test.cpp deleted file mode 100644 index 3b5ed485..00000000 --- a/src/engine/tests/old_node_tree_test.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include "../NodeTree.h" -#include "../NodeBase.h" - -using std::cout; using std::cerr; using std::endl; - -int main() -{ - cout << "\n\n\n\n"; - - NodeBase* n = NULL; - TreeNode* tn = NULL; - TreeNode* baz = NULL; - TreeNode* quuux = NULL; - TreeNode* bar = NULL; - - NodeTree tree; - n = new NodeBase("foo", 0, 0, 0); - tn = new TreeNode(n); - tree.insert(tn); - n = new NodeBase("bar", 0, 0, 0); - bar = new TreeNode(n); - tree.insert(bar); - n = new NodeBase("baz", 0, 0, 0); - baz = new TreeNode(n); - tree.insert(baz); - n = new NodeBase("quux", 0, 0, 0); - tn = new TreeNode(n); - tree.insert(tn); - n = new NodeBase("quuux", 0, 0, 0); - quuux = new TreeNode(n); - tree.insert(quuux); - n = new NodeBase("quuuux", 0, 0, 0); - tn = new TreeNode(n); - tree.insert(tn); - - - cout << "Added 6 nodes." << endl; - cout << "Tree size: " << tree.size() << endl << endl; - - cout << "Iterating: " << endl; - for (NodeTree::iterator i = tree.begin(); i != tree.end(); ++i) { - cout << (*i)->name() << endl; - } - - cout << endl << "Search 'foo' - " << tree.find("foo")->name() << endl; - cout << endl << "Search 'bar' - " << tree.find("bar")->name() << endl; - cout << endl << "Search 'baz' - " << tree.find("baz")->name() << endl; - cout << endl << "Search 'quux' - " << tree.find("quux")->name() << endl; - cout << endl << "Search 'quuux' - " << tree.find("quuux")->name() << endl; - cout << endl << "Search 'quuuux' - " << tree.find("quuuux")->name() << endl; - cout << endl << "Search 'dave' - " << tree.find("dave") << endl; - cout << endl << "Search 'fo' - " << tree.find("fo") << endl << endl; - - cout << "Removing 'baz'." << endl; - tree.remove(baz); - - cout << "Iterating: " << endl; - for (NodeTree::iterator i = tree.begin(); i != tree.end(); ++i) { - cout << (*i)->name() << endl; - } - - cout << "Removing 'bar' (the root): " << endl; - tree.remove(bar); - - cout << "Iterating: " << endl; - for (NodeTree::iterator i = tree.begin(); i != tree.end(); ++i) { - cout << (*i)->name() << endl; - } - - return 0; -} diff --git a/src/engine/tests/queue_test.cpp b/src/engine/tests/queue_test.cpp deleted file mode 100644 index 3381a329..00000000 --- a/src/engine/tests/queue_test.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include "../../common/Queue.h" - -using std::string; using std::cerr; using std::cout; using std::endl; - - -int main() -{ - Queue q(10); - - cout << "New queue. Should be empty: " << q.is_empty() << endl; - cout << "Capacity: " << q.capacity() << endl; - cout << "Fill: " << q.fill() << endl; - - for (uint i=0; i < 5; ++i) { - q.push(i); - assert(!q.is_full()); - q.pop(); - } - cout << "Pushed and popped 5 elements. Queue should be empty: " << q.is_empty() << endl; - cout << "Fill: " << q.fill() << endl; - - for (uint i=10; i < 20; ++i) { - q.push(i); - } - cout << "Pushed 10 elements. Queue should be full: " << q.is_full() << endl; - cout << "Fill: " << q.fill() << endl; - - cout << "The digits 10->19 should print: " << endl; - while (!q.is_empty()) { - int foo = q.pop(); - cout << "Popped: " << foo << endl; - } - cout << "Queue should be empty: " << q.is_empty() << endl; - cout << "Fill: " << q.fill() << endl; - - cout << "Attempting to add eleven elements to queue of size 10. Only first 10 should succeed:" << endl; - for (uint i=20; i <= 39; ++i) { - cout << i; - cout << " - Fill: " << q.fill(); - cout << ", is full: " << q.is_full(); - cout << ", succeeded: " << q.push(i) << endl; - } - - return 0; -} diff --git a/src/engine/tuning.h b/src/engine/tuning.h deleted file mode 100644 index aeec81da..00000000 --- a/src/engine/tuning.h +++ /dev/null @@ -1,39 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TUNING_H -#define TUNING_H - -#include -#include - -namespace Om { - -// FIXME: put this in a Config class - -static const size_t event_queue_size = 1024; -static const size_t pre_processor_queue_size = 1024; -static const size_t post_processor_queue_size = 1024; -static const size_t maid_queue_size = 1024; - -// This controls both the LASH event processing rate and the Maid cleanup rate -// (both of which are driven from the main thread) -static const timespec main_rate = { 0, 500000000 }; // 1/2 second - - -} // namespace Om - -#endif // TUNING_H diff --git a/src/engine/util.h b/src/engine/util.h deleted file mode 100644 index 9cf4bf7f..00000000 --- a/src/engine/util.h +++ /dev/null @@ -1,73 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef UTIL_H -#define UTIL_H - -#include -#include - -#include -#ifdef __SSE__ -#include -#endif - -using std::cerr; using std::endl; - -namespace Om { - -/** Set flags to disable denormal processing. - */ -inline void -set_denormal_flags() -{ -#ifdef __SSE__ - unsigned long a, b, c, d; - - asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); - if (d & 1<<25) { /* It has SSE support */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - - asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (0)); - if (b == 0x756e6547) { /* It's an Intel */ - int stepping, model, family, extfamily; - - family = (a >> 8) & 0xf; - extfamily = (a >> 20) & 0xff; - model = (a >> 4) & 0xf; - stepping = a & 0xf; - if (family == 15 && extfamily == 0 && model == 0 && stepping < 7) { - return; - } - } - asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); - if (d & 1<<26) { /* bit 26, SSE2 support */ - _mm_setcsr(_mm_getcsr() | 0x40); - //cerr << "Set SSE denormal fix flag." << endl; - } - } else { - cerr << "This code has been built with SSE support, but your processor does" - << " not support the SSE instruction set." << endl << "Exiting." << endl; - exit(EXIT_FAILURE); - } -#endif - // Set 387 control register via standard C99 interface - fesetround(FE_TOWARDZERO); -} - -} // namespace Om - -#endif // UTIL_H diff --git a/src/libs/engine/AlsaMidiDriver.cpp b/src/libs/engine/AlsaMidiDriver.cpp new file mode 100644 index 00000000..decd2471 --- /dev/null +++ b/src/libs/engine/AlsaMidiDriver.cpp @@ -0,0 +1,373 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AlsaMidiDriver.h" +#include +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "util/types.h" +#include "OmApp.h" +#include "Maid.h" +#include "AudioDriver.h" +#include "PortInfo.h" +#include "MidiMessage.h" +#include "PortBase.h" +#ifdef HAVE_LASH +#include "LashDriver.h" +#endif +using std::cout; using std::cerr; using std::endl; + +namespace Om { + + +//// AlsaMidiPort //// + +AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, PortBase* port) +: DriverPort(), + ListNode(this), + m_driver(driver), + m_patch_port(port), + m_port_id(0), + m_midi_pool(new unsigned char*[port->buffer_size()]), + m_events(1024) +{ + assert(port->parent() != NULL); + assert(port->poly() == 1); + + if (port->port_info()->is_input()) { + if ((m_port_id = snd_seq_create_simple_port(driver->seq_handle(), port->path().c_str(), + SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, + SND_SEQ_PORT_TYPE_APPLICATION)) < 0) + { + cerr << "[AlsaMidiPort] Error creating sequencer port." << endl; + exit(EXIT_FAILURE); + } + } else { + if ((m_port_id = snd_seq_create_simple_port(driver->seq_handle(), port->path().c_str(), + SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, + SND_SEQ_PORT_TYPE_APPLICATION)) < 0) + { + cerr << "[AlsaMidiPort] Error creating sequencer port." << endl; + exit(EXIT_FAILURE); + } + } + + /* Allocate event pool. This pool is used when preparing a block from the queue + * of Alsa events. The buffer member of the MidiMessage's in the patch port's + * buffer will be set directly to an element in this pool, then next cycle they + * will be overwritten (eliminating the need for any allocation/freeing). */ + for (size_t i=0; i < port->buffer_size(); ++i) + m_midi_pool[i] = new unsigned char[MAX_MIDI_EVENT_SIZE]; + + port->buffer(0)->clear(); + port->fixed_buffers(true); +} + + +AlsaMidiPort::~AlsaMidiPort() +{ + snd_seq_delete_simple_port(m_driver->seq_handle(), m_port_id); + + // Free event pool + for (size_t i=0; i < m_patch_port->buffer_size(); ++i) + delete[] m_midi_pool[i]; + + delete[] m_midi_pool; +} + + +void +AlsaMidiPort::add_to_driver() +{ + m_driver->add_port(this); +} + + +void +AlsaMidiPort::remove_from_driver() +{ + m_driver->remove_port(this); +} + + +void +AlsaMidiPort::set_name(const string& name) +{ + snd_seq_port_info_t* info = NULL; + snd_seq_port_info_malloc(&info); + snd_seq_get_port_info(m_driver->seq_handle(), m_port_id, info); + snd_seq_port_info_set_name(info, name.c_str()); + snd_seq_set_port_info(m_driver->seq_handle(), m_port_id, info); + snd_seq_port_info_free(info); +} + + +void +AlsaMidiPort::event(snd_seq_event_t* const ev) +{ + // Abuse the tick field to hold the timestamp + ev->time.tick = om->audio_driver()->time_stamp(); + + // Fix noteons with velocity 0 (required for DSSI spec) + if (ev->type == SND_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0) + ev->type = SND_SEQ_EVENT_NOTEOFF; + + m_events.push(*ev); +} + + +/** Generates a flat array of MIDI events for patching. + * + * Prepares all events that occurred during the time interval passed + * (which ideally are the events from the previous cycle with an exact + * 1 cycle delay) and creates a flat port buffer for this cycle. + */ +void +AlsaMidiPort::prepare_block(const samplecount block_start, const samplecount block_end) +{ + assert(block_end >= block_start); + + snd_seq_event_t* ev = NULL; + MidiMessage* message = NULL; + size_t num_events = 0; + size_t event_size = 0; // decoded length of Alsa event in bytes + int timestamp = 0; + + while (!m_events.is_empty() && m_events.front().time.tick < block_end) { + assert(num_events < m_patch_port->buffer_size()); + ev = &m_events.front(); + message = &m_patch_port->buffer(0)->data()[num_events]; + + timestamp = ev->time.tick - block_start; + if (timestamp < 0) { + // FIXME: remove this (obviously not realtime safe) + cerr << "[AlsaMidiPort] Missed event by " << -timestamp << " samples!" << endl; + timestamp = 0; + } + assert(timestamp < (int)(block_end - block_start)); + + // Reset decoder so we don't get running status + snd_midi_event_reset_decode(m_driver->event_coder()); + + // FIXME: is this realtime safe? + if ((event_size = snd_midi_event_decode(m_driver->event_coder(), + m_midi_pool[num_events], MAX_MIDI_EVENT_SIZE, ev)) > 0) { + message->size = event_size; + message->time = timestamp; + message->buffer = m_midi_pool[num_events]; + ++num_events; + } else { + cerr << "[AlsaMidiPort] Unable to decode MIDI event" << endl; + } + + m_events.pop(); + } + + m_patch_port->buffer(0)->filled_size(num_events); + m_patch_port->tied_port()->buffer(0)->filled_size(num_events); +} + + + +//// AlsaMidiDriver //// + + +bool AlsaMidiDriver::m_midi_thread_exit_flag = true; + + +AlsaMidiDriver::AlsaMidiDriver() +: m_seq_handle(NULL), + m_event_coder(NULL), + m_is_activated(false) +{ + if (snd_seq_open(&m_seq_handle, "hw", SND_SEQ_OPEN_INPUT, 0) < 0) { + cerr << "[AlsaMidiDriver] Error opening ALSA sequencer." << endl; + exit(EXIT_FAILURE); + } else { + cout << "[AlsaMidiDriver] Successfully opened ALSA sequencer." << endl; + } + + if (snd_midi_event_new(3, &m_event_coder)) { + cerr << "[AlsaMidiDriver] Failed to initialize ALSA MIDI event coder!"; + exit(EXIT_FAILURE); + } else { + snd_midi_event_reset_encode(m_event_coder); + snd_midi_event_reset_decode(m_event_coder); + } + + snd_seq_set_client_name(m_seq_handle, "Om"); +} + + +AlsaMidiDriver::~AlsaMidiDriver() +{ + deactivate(); + snd_midi_event_free(m_event_coder); + snd_seq_close(m_seq_handle); +} + + +/** Launch and start the MIDI thread. + */ +void +AlsaMidiDriver::activate() +{ + // Just exit if already running + if (m_midi_thread_exit_flag == false) + return; + + bool success = false; + m_midi_thread_exit_flag = false; + + //if (om->audio_driver()->is_realtime()) { + pthread_attr_t attr; + pthread_attr_init(&attr); + + if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { + cerr << "[AlsaMidiDriver] Unable to set realtime scheduling for MIDI thread." << endl; + } + + sched_param param; + param.sched_priority = 10; + + pthread_attr_setstacksize(&attr, 1500000); + + if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) + || pthread_attr_setschedparam(&attr, ¶m)) + cout << "[AlsaMidiDriver] Unable to set SCHED_FIFO priority " + << param.sched_priority << endl; + + if (!pthread_create(&m_process_thread, &attr, process_midi_in, this)) { + cout << "[AlsaMidiDriver] Started realtime MIDI thread (SCHED_FIFO, priority " + << param.sched_priority << ")" << endl; + success = true; + } else { + cerr << "[AlsaMidiDriver] Unable to start realtime MIDI thread." << endl; + } + pthread_attr_destroy(&attr); + //} + + if (!success) { + // FIXME: check for success + pthread_create(&m_process_thread, NULL, process_midi_in, this); + cout << "[AlsaMidiDriver] Started non-realtime MIDI thread." << endl; + } + +#ifdef HAVE_LASH + lash_driver->set_alsa_client_id(snd_seq_client_id(m_seq_handle)); +#endif + + m_is_activated = true; +} + + +/** Terminate the MIDI thread. + */ +void +AlsaMidiDriver::deactivate() +{ + if (m_is_activated) { + m_midi_thread_exit_flag = true; + pthread_cancel(m_process_thread); + pthread_join(m_process_thread, NULL); + m_is_activated = false; + } +} + + +/** Build flat arrays of events for DSSI plugins for each Port. + */ +void +AlsaMidiDriver::prepare_block(const samplecount block_start, const samplecount block_end) +{ + for (List::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i) + (*i)->prepare_block(block_start, block_end); +} + + +/** Add an Alsa MIDI port. + * + * Realtime safe, this is to be called at the beginning of a process cycle to + * insert (and actually begin using) a new port. + * + * See create_port() and remove_port(). + */ +void +AlsaMidiDriver::add_port(AlsaMidiPort* port) +{ + if (port->patch_port()->port_info()->is_input()) + m_in_ports.push_back(port); + else + m_out_ports.push_back(port); +} + + +/** Remove an Alsa MIDI port. + * + * Realtime safe. This is to be called at the beginning of a process cycle to + * remove the port from the lists read by the audio thread, so the port + * will no longer be used and can be removed afterwards. + * + * It is the callers responsibility to delete the returned port. + */ +AlsaMidiPort* +AlsaMidiDriver::remove_port(AlsaMidiPort* port) +{ + if (port->patch_port()->port_info()->is_input()) { + for (List::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i) + if ((*i) == (AlsaMidiPort*)port) + return m_in_ports.remove(i)->elem(); + } else { + for (List::iterator i = m_out_ports.begin(); i != m_out_ports.end(); ++i) + if ((*i) == port) + return m_out_ports.remove(i)->elem(); + } + + cerr << "[AlsaMidiDriver::remove_input] WARNING: Failed to find Jack port to remove!" << endl; + return NULL; +} + + +/** MIDI thread. + */ +void* +AlsaMidiDriver::process_midi_in(void* alsa_driver) +{ + AlsaMidiDriver* ad = (AlsaMidiDriver*)alsa_driver; + + snd_seq_event_t* ev; + + int npfd = snd_seq_poll_descriptors_count(ad->m_seq_handle, POLLIN); + struct pollfd pfd; + snd_seq_poll_descriptors(ad->m_seq_handle, &pfd, npfd, POLLIN); + + while ( ! m_midi_thread_exit_flag) + if (poll(&pfd, npfd, 100000) > 0) + while (snd_seq_event_input(ad->m_seq_handle, &ev) > 0) + for (List::iterator i = ad->m_in_ports.begin(); i != ad->m_in_ports.end(); ++i) + if ((*i)->port_id() == ev->dest.port) + (*i)->event(ev); + + cout << "[AlsaMidiDriver] Exiting MIDI thread." << endl; + + return NULL; +} + + +} // namespace Om + diff --git a/src/libs/engine/AlsaMidiDriver.h b/src/libs/engine/AlsaMidiDriver.h new file mode 100644 index 00000000..5acbbfbf --- /dev/null +++ b/src/libs/engine/AlsaMidiDriver.h @@ -0,0 +1,127 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ALSAMIDIDRIVER_H +#define ALSAMIDIDRIVER_H + +#include +#include "List.h" +#include "util/Queue.h" +#include "MidiDriver.h" + +namespace Om { + +class Node; +class SetPortValueEvent; +class AlsaMidiDriver; +template class PortBase; + +static const int MAX_MIDI_EVENT_SIZE = 3; + + +/** Representation of an ALSA MIDI port. + * + * \ingroup engine + */ +class AlsaMidiPort : public DriverPort, public ListNode +{ +public: + AlsaMidiPort(AlsaMidiDriver* driver, PortBase* port); + virtual ~AlsaMidiPort(); + + void event(snd_seq_event_t* const ev); + + void prepare_block(const samplecount block_start, const samplecount block_end); + + void add_to_driver(); + void remove_from_driver(); + void set_name(const string& name); + + int port_id() const { return m_port_id; } + PortBase* patch_port() const { return m_patch_port; } + +private: + // Prevent copies (undefined) + AlsaMidiPort(const AlsaMidiPort&); + AlsaMidiPort& operator=(const AlsaMidiPort&); + + AlsaMidiDriver* m_driver; + PortBase* m_patch_port; + int m_port_id; + unsigned char** m_midi_pool; ///< Pool of raw MIDI events for MidiMessage::buffer + Queue m_events; +}; + + +/** Alsa MIDI driver. + * + * This driver reads Alsa MIDI events and dispatches them to the appropriate + * AlsaMidiPort for processing. + * + * \ingroup engine + */ +class AlsaMidiDriver : public MidiDriver +{ +public: + AlsaMidiDriver(); + ~AlsaMidiDriver(); + + void activate(); + void deactivate(); + + bool is_activated() const { return m_is_activated; } + + void prepare_block(const samplecount block_start, const samplecount block_end); + + DriverPort* create_port(PortBase* patch_port) + { return new AlsaMidiPort(this, patch_port); } + + snd_seq_t* seq_handle() const { return m_seq_handle; } + snd_midi_event_t* event_coder() const { return m_event_coder; } + +private: + + // Prevent copies (undefined) + AlsaMidiDriver(const AlsaMidiDriver&); + AlsaMidiDriver& operator=(const AlsaMidiDriver&); + + List m_in_ports; + List m_out_ports; + + friend class AlsaMidiPort; + + // Functions for AlsaMidiPort + void add_port(AlsaMidiPort* port); + AlsaMidiPort* remove_port(AlsaMidiPort* port); + + void add_output(ListNode* port); + ListNode* remove_output(AlsaMidiPort* port); + + // MIDI thread + static void* process_midi_in(void* me); + + snd_seq_t* m_seq_handle; + snd_midi_event_t* m_event_coder; + pthread_t m_process_thread; + bool m_is_activated; + static bool m_midi_thread_exit_flag; +}; + + +} // namespace Om + + +#endif // ALSAMIDIDRIVER_H diff --git a/src/libs/engine/Array.h b/src/libs/engine/Array.h new file mode 100644 index 00000000..6b56ecc5 --- /dev/null +++ b/src/libs/engine/Array.h @@ -0,0 +1,109 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ARRAY_H +#define ARRAY_H + +#include "MaidObject.h" +#include +#include +#include "util/types.h" + + +/** An array. + * + * Has a stack-like push_back() too, for find_process_order... + */ +template +class Array : public MaidObject +{ +public: + Array(size_t size = 0) : m_size(size), m_top(0), m_elems(NULL) { + if (size > 0) + m_elems = new T[size]; + } + + Array(size_t size, T initial_value) : m_size(size), m_top(0), m_elems(NULL) { + if (size > 0) { + m_elems = new T[size]; + for (size_t i=0; i < size; ++i) + m_elems[i] = initial_value; + } + } + + Array(size_t size, const Array* contents) : m_size(size), m_top(size+1) { + m_elems = new T[size]; + if (size <= contents->size()) + memcpy(m_elems, contents->m_elems, size * sizeof(T)); + else + memcpy(m_elems, contents->m_elems, contents->size() * sizeof(T)); + } + + ~Array() { + free(); + } + + void alloc(size_t num_elems) { + assert(num_elems > 0); + + delete[] m_elems; + m_size = num_elems; + m_top = 0; + + m_elems = new T[num_elems]; + } + + void alloc(size_t num_elems, T initial_value) { + assert(num_elems > 0); + + delete[] m_elems; + m_size = num_elems; + m_top = 0; + + m_elems = new T[num_elems]; + for (size_t i=0; i < m_size; ++i) + m_elems[i] = initial_value; + } + + void free() { + delete[] m_elems; + m_size = 0; + m_top = 0; + } + + void push_back(T n) { + assert(m_top < m_size); + m_elems[m_top++] = n; + } + + inline size_t size() const { return m_size; } + + inline T& operator[](size_t i) const { assert(i < m_size); return m_elems[i]; } + + inline T& at(size_t i) const { assert(i < m_size); return m_elems[i]; } + +private: + // Disallow copies (undefined) + Array(const Array& copy); + Array& operator=(const Array& copy); + + size_t m_size; + size_t m_top; // points to empty element above "top" element + T* m_elems; +}; + + +#endif // ARRAY_H diff --git a/src/libs/engine/AudioDriver.h b/src/libs/engine/AudioDriver.h new file mode 100644 index 00000000..056aeab4 --- /dev/null +++ b/src/libs/engine/AudioDriver.h @@ -0,0 +1,50 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef AUDIODRIVER_H +#define AUDIODRIVER_H + +#include "Driver.h" +#include "util/types.h" +#include "List.h" + +namespace Om { + +class Patch; +class AudioDriver; +template class PortBase; + + +/** Audio driver abstract base class. + * + * \ingroup engine + */ +class AudioDriver : public Driver +{ +public: + + virtual void set_root_patch(Patch* patch) = 0; + virtual Patch* root_patch() = 0; + + virtual samplecount buffer_size() const = 0; + virtual samplecount sample_rate() const = 0; + virtual samplecount time_stamp() const = 0; +}; + + +} // namespace Om + +#endif // AUDIODRIVER_H diff --git a/src/libs/engine/AudioInputNode.cpp b/src/libs/engine/AudioInputNode.cpp new file mode 100644 index 00000000..8a3594cb --- /dev/null +++ b/src/libs/engine/AudioInputNode.cpp @@ -0,0 +1,49 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AudioInputNode.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Plugin.h" +#include "PortInfo.h" +#include "Patch.h" + +namespace Om { + + +AudioInputNode::AudioInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: BridgeNode(path, poly, parent, srate, buffer_size) +{ + OutputPort* internal_port = new OutputPort(this, "in", 0, m_poly, + new PortInfo("in", AUDIO, OUTPUT), m_buffer_size); + InputPort* external_port = new InputPort(parent, m_name, 0, m_poly, + new PortInfo(m_name, AUDIO, INPUT), m_buffer_size); + external_port->tie(internal_port); + m_external_port = external_port; + internal_port->set_value(0, 0); + + m_num_ports = 1; + m_ports.alloc(m_num_ports); + m_ports.at(0) = internal_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("audio_input"); + m_plugin.name("Om Patch Audio Input Node"); +} + + +} // namespace Om + diff --git a/src/libs/engine/AudioInputNode.h b/src/libs/engine/AudioInputNode.h new file mode 100644 index 00000000..894ec082 --- /dev/null +++ b/src/libs/engine/AudioInputNode.h @@ -0,0 +1,45 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef AUDIOINPUTNODE_H +#define AUDIOINPUTNODE_H + +#include +#include "util/types.h" +#include "BridgeNode.h" + +using std::string; + +namespace Om { + +class Patch; +template class InputPort; + + +/** Audio input BridgeNode. + * + * \ingroup engine + */ +class AudioInputNode : public BridgeNode +{ +public: + AudioInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); +}; + + +} // namespace Om + +#endif // AUDIOINPUTNODE_H diff --git a/src/libs/engine/AudioOutputNode.cpp b/src/libs/engine/AudioOutputNode.cpp new file mode 100644 index 00000000..d9a925f8 --- /dev/null +++ b/src/libs/engine/AudioOutputNode.cpp @@ -0,0 +1,50 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AudioOutputNode.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Plugin.h" +#include "Patch.h" +#include "PortInfo.h" +#include + +namespace Om { + + +AudioOutputNode::AudioOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: BridgeNode(path, poly, parent, srate, buffer_size) +{ + OutputPort* external_port = new OutputPort(parent, m_name, 0, m_poly, + new PortInfo(m_name, AUDIO, OUTPUT), m_buffer_size); + InputPort* internal_port = new InputPort(this, "out", 0, m_poly, + new PortInfo("out", AUDIO, INPUT), m_buffer_size); + internal_port->tie(external_port); + m_external_port = external_port; + internal_port->set_value(0, 0); + + m_num_ports = 1; + m_ports.alloc(m_num_ports); + m_ports.at(0) = internal_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("audio_output"); + m_plugin.name("Om Patch Audio Output Node"); +} + + +} // namespace Om + diff --git a/src/libs/engine/AudioOutputNode.h b/src/libs/engine/AudioOutputNode.h new file mode 100644 index 00000000..6399cfc6 --- /dev/null +++ b/src/libs/engine/AudioOutputNode.h @@ -0,0 +1,44 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef AUDIOOUTPUTNODE_H +#define AUDIOOUTPUTNODE_H + +#include +#include "util/types.h" +#include "BridgeNode.h" + +using std::string; + +namespace Om { + +template class OutputPort; + + +/** Audio output BridgeNode. + * + * \ingroup engine + */ +class AudioOutputNode : public BridgeNode +{ +public: + AudioOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); +}; + + +} // namespace Om + +#endif // AUDIOOUTPUTNODE_H diff --git a/src/libs/engine/BridgeNode.cpp b/src/libs/engine/BridgeNode.cpp new file mode 100644 index 00000000..776bcc92 --- /dev/null +++ b/src/libs/engine/BridgeNode.cpp @@ -0,0 +1,159 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BridgeNode.h" +//#include "ClientBroadcaster.h" +#include "Plugin.h" +#include "Patch.h" +#include "Om.h" +#include "OmApp.h" +#include "Maid.h" +#include "Driver.h" +#include "PortInfo.h" +#include + +namespace Om { + +template +BridgeNode::BridgeNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: InternalNode(path, + (parent->parent_patch() == NULL || poly != parent->parent_patch()->poly()) ? 1 : poly, + //poly, + parent, srate, buffer_size), + m_driver_port(NULL), + m_listnode(NULL), + m_external_port(NULL) +{ + //cerr << "Creating bridge node " << path << " - polyphony: " << m_poly << endl; + m_listnode = new ListNode(this); +} +template +BridgeNode::BridgeNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); +template +BridgeNode::BridgeNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); + + +template +BridgeNode::~BridgeNode() +{ + delete m_driver_port; +} +template BridgeNode::~BridgeNode(); +template BridgeNode::~BridgeNode(); + + +template +void +BridgeNode::activate() +{ + assert(om->template driver() != NULL); + assert(m_external_port != NULL); // Derived classes must create this + assert(parent_patch() != NULL); + + if (parent_patch()->parent() == NULL && om != NULL) + m_driver_port = om->template driver()->create_port(m_external_port); + + InternalNode::activate(); +} + + +template +void +BridgeNode::deactivate() +{ + if (m_is_added) + remove_from_patch(); + + InternalNode::deactivate(); + + if (m_driver_port != NULL) { + delete m_driver_port; + m_driver_port = NULL; + } +} + + +template +void +BridgeNode::add_to_patch() +{ + assert(parent_patch() != NULL); + + parent_patch()->add_bridge_node(m_listnode); + + InternalNode::add_to_patch(); + + // Activate driver port now in the audio thread (not before when created, to avoid race issues) + if (m_driver_port != NULL) + m_driver_port->add_to_driver(); +} + + +template +void +BridgeNode::remove_from_patch() +{ + assert(parent_patch() != NULL); + + if (m_is_added) { + if (m_driver_port != NULL) + m_driver_port->remove_from_driver(); + ListNode* ln = NULL; + ln = parent_patch()->remove_bridge_node(this); + + om->maid()->push(ln); + m_listnode = NULL; + + } + InternalNode::remove_from_patch(); +} + + +template +void +BridgeNode::set_path(const Path& new_path) +{ + InternalNode::set_path(new_path); + + m_external_port->set_path(new_path); + + if (m_driver_port != NULL) + m_driver_port->set_name(path().c_str()); +} + + +#if 0 +template +void +BridgeNode::send_creation_messages(ClientInterface* client) const +{ + InternalNode::send_creation_messages(client); + om->client_broadcaster()->send_new_port_to(client, m_external_port); + + // Send metadata + for (map::const_iterator i = metadata().begin(); i != metadata().end(); ++i) + om->client_broadcaster()->send_metadata_update_to(client, path(), (*i).first, (*i).second); + + // Send control value (if necessary) + //if (m_external_port->port_info()->is_control()) + // om->client_broadcaster()->send_control_change_to(client, path(), + // ((PortBase*)m_external_port)->buffer(0)->value_at(0)); +} +#endif + + +} // namespace Om + diff --git a/src/libs/engine/BridgeNode.h b/src/libs/engine/BridgeNode.h new file mode 100644 index 00000000..99fad912 --- /dev/null +++ b/src/libs/engine/BridgeNode.h @@ -0,0 +1,90 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BRIDGENODE_H +#define BRIDGENODE_H + +#include +#include "InternalNode.h" +#include "PortBase.h" +using std::string; + +template class ListNode; + +namespace Om { + +class DriverPort; +namespace Shared { + class ClientInterface; +} using Shared::ClientInterface; + + +/** A Node to represent input/output Ports on a Patch. + * + * This node acts as both a Node and a Port (it is the only Node type that + * returns non-null for as_port()). The node is a normal Node in a Patch, + * the Port is a Port on that Patch (port->parent == node->parent). + * + * This class handles all DriverPort functionality as well (if this Node + * is on a top level Patch). + * + * Both input and output nodes are handled in this class. + * + * This node will force itself to monophonic (regardless of the poly parameter + * passed to constructor) if the parent of the patch it's representing a port + * on has a different polyphony than the patch (since connecting mismatched + * polyphonies is impossible). + * + * \ingroup engine + */ +template +class BridgeNode : public InternalNode +{ +public: + virtual ~BridgeNode(); + + Port* as_port() { return m_external_port; } + + void activate(); + void deactivate(); + void add_to_patch(); + void remove_from_patch(); + //void send_creation_messages(ClientInterface* client) const; + + void set_path(const Path& new_path); + +protected: + // Disallow copies (undefined) + BridgeNode(const BridgeNode&); + BridgeNode& operator=(const BridgeNode&); + + BridgeNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); + + /** Driver port, used if this is on a top level Patch */ + DriverPort* m_driver_port; + + ListNode* m_listnode; + + PortBase* m_external_port; +}; + + +template class BridgeNode; +template class BridgeNode; + +} // namespace Om + +#endif // BRIDGENODE_H diff --git a/src/libs/engine/Buffer.cpp b/src/libs/engine/Buffer.cpp new file mode 100644 index 00000000..963b14a5 --- /dev/null +++ b/src/libs/engine/Buffer.cpp @@ -0,0 +1,297 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Buffer.h" +#include +#include +#include +#include "MidiMessage.h" +using std::cerr; using std::endl; + +/* TODO: Be sure these functions are vectorized by GCC when it's vectorizer + * stops sucking. Probably a good idea to inline them as well */ + +namespace Om { + + +template +Buffer::Buffer(size_t size) +: m_size(size), + m_filled_size(0), + m_is_joined(false), + m_state(OK), + m_set_value(0), + m_data(NULL), + m_local_data(NULL) +{ + assert(m_size > 0); + allocate(); +} +template Buffer::Buffer(size_t size); +template Buffer::Buffer(size_t size); + + +/** Allocate and use a locally managed buffer (data). + */ +template +void +Buffer::allocate() +{ + assert(!m_is_joined); + assert(m_data == NULL); + assert(m_local_data == NULL); + assert(m_size > 0); + + const int ret = posix_memalign((void**)&m_local_data, 16, m_size * sizeof(T)); + if (ret != 0) { + cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl; + exit(EXIT_FAILURE); + } + + assert(ret == 0); + assert(m_local_data != NULL); + m_data = m_local_data; + + set(0, 0, m_size-1); +} +template void Buffer::allocate(); +template void Buffer::allocate(); + + +/** Free locally allocated buffer. + */ +template +void +Buffer::deallocate() +{ + assert(!m_is_joined); + free(m_local_data); + if (m_data == m_local_data) + m_data = NULL; + m_local_data = NULL; +} +template void Buffer::deallocate(); +template void Buffer::deallocate(); + + +/** Empty (ie zero) the buffer. + */ +template +void +Buffer::clear() +{ + set(0, 0, m_size-1); + m_state = OK; + m_filled_size = 0; +} +template void Buffer::clear(); +template void Buffer::clear(); + + +/** Set value of buffer to @a val after @a start_sample. + * + * The Buffer will handle setting the intial portion of the buffer to the + * value on the next cycle automatically (if @a start_sample is > 0), as + * long as pre_process() is called every cycle. + */ +template +void +Buffer::set(T val, size_t start_sample) +{ + assert(start_sample < m_size); + + set(val, start_sample, m_size-1); + + if (start_sample > 0) + m_state = HALF_SET_CYCLE_1; + + m_set_value = val; +} +template void Buffer::set(sample val, size_t start_sample); +template void Buffer::set(MidiMessage val, size_t start_sample); + + +/** Set a block of buffer to @a val. + * + * @a start_sample and @a end_sample define the inclusive range to be set. + */ +template +void +Buffer::set(T val, size_t start_sample, size_t end_sample) +{ + assert(start_sample >= 0); + assert(end_sample >= start_sample); + assert(end_sample < m_size); + assert(m_data != NULL); + + for (size_t i=start_sample; i <= end_sample; ++i) + m_data[i] = val; +} +template void Buffer::set(sample val, size_t start_sample, size_t end_sample); +template void Buffer::set(MidiMessage val, size_t start_sample, size_t end_sample); + + +/** Scale a block of buffer by @a val. + * + * @a start_sample and @a end_sample define the inclusive range to be set. + */ +template +void +Buffer::scale(T val, size_t start_sample, size_t end_sample) +{ + assert(start_sample >= 0); + assert(end_sample >= start_sample); + assert(end_sample < m_size); + assert(m_data != NULL); + + for (size_t i=start_sample; i <= end_sample; ++i) + m_data[i] *= val; +} +template void Buffer::scale(sample val, size_t start_sample, size_t end_sample); + + +/** Copy a block of @a src into buffer. + * + * @a start_sample and @a end_sample define the inclusive range to be set. + * This function only copies the same range in one buffer to another. + */ +template +void +Buffer::copy(const Buffer* src, size_t start_sample, size_t end_sample) +{ + assert(start_sample >= 0); + assert(end_sample >= start_sample); + assert(end_sample < m_size); + assert(src != NULL); + assert(src->data() != NULL); + assert(m_data != NULL); + + const T* const src_data = src->data(); + + for (size_t i=start_sample; i <= end_sample; ++i) + m_data[i] = src_data[i]; +} +template void Buffer::copy(const Buffer* const src, size_t start_sample, size_t end_sample); +template void Buffer::copy(const Buffer* const src, size_t start_sample, size_t end_sample); + + +/** Accumulate a block of @a src into @a dst. + * + * @a start_sample and @a end_sample define the inclusive range to be accumulated. + * This function only adds the same range in one buffer to another. + */ +template +void +Buffer::accumulate(const Buffer* const src, size_t start_sample, size_t end_sample) +{ + assert(start_sample >= 0); + assert(end_sample >= start_sample); + assert(end_sample < m_size); + assert(src != NULL); + assert(src->data() != NULL); + assert(m_data != NULL); + + const T* const src_data = src->data(); + + for (size_t i=start_sample; i <= end_sample; ++i) + m_data[i] += src_data[i]; + +} +template void Buffer::accumulate(const Buffer* const src, size_t start_sample, size_t end_sample); + + +/** Use another buffer's data instead of the local one. + * + * This buffer will essentially be identical to @a buf after this call. + */ +template +void +Buffer::join(Buffer* buf) +{ + assert(buf->size() == m_size); + + m_data = buf->m_data; + m_filled_size = buf->filled_size(); + m_is_joined = true; + + assert(m_filled_size <= m_size); +} +template void Buffer::join(Buffer* buf); +template void Buffer::join(Buffer* buf); + + +template +void +Buffer::unjoin() +{ + m_is_joined = false; + m_data = m_local_data; +} +template void Buffer::unjoin(); +template void Buffer::unjoin(); + + +template<> +void +Buffer::prepare(samplecount nframes) +{ + // FIXME: nframes parameter doesn't actually work, + // writing starts from 0 every time + assert(m_size == 1 || nframes == m_size); + + switch (m_state) { + case HALF_SET_CYCLE_1: + m_state = HALF_SET_CYCLE_2; + break; + case HALF_SET_CYCLE_2: + set(m_set_value, 0, m_size-1); + m_state = OK; + break; + default: + break; + } +} + + +////// DriverBuffer //////// + +template +DriverBuffer::DriverBuffer(size_t size) +: Buffer(size) +{ + Buffer::deallocate(); // FIXME: allocate then immediately deallocate, dirty + Buffer::m_data = NULL; +} +template DriverBuffer::DriverBuffer(size_t size); +template DriverBuffer::DriverBuffer(size_t size); + + +/** Set the buffer (data) used. + * + * This is only to be used by Drivers (to provide zero-copy processing). + */ +template +void +DriverBuffer::set_data(T* data) +{ + assert(!m_is_joined); + m_data = data; +} +template void DriverBuffer::set_data(sample* data); +template void DriverBuffer::set_data(MidiMessage* data); + + +} // namespace Om diff --git a/src/libs/engine/Buffer.h b/src/libs/engine/Buffer.h new file mode 100644 index 00000000..13d62727 --- /dev/null +++ b/src/libs/engine/Buffer.h @@ -0,0 +1,91 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BUFFER_H +#define BUFFER_H + +#include +#include +#include "util/types.h" + +namespace Om { + + +template +class Buffer +{ +public: + Buffer(size_t size); + + void clear(); + void set(T val, size_t start_sample); + void set(T val, size_t start_sample, size_t end_sample); + void scale(T val, size_t start_sample, size_t end_sample); + void copy(const Buffer* src, size_t start_sample, size_t end_sample); + void accumulate(const Buffer* src, size_t start_sample, size_t end_sample); + + void join(Buffer* buf); + void unjoin(); + + inline T& value_at(size_t offset) { assert(offset < m_size); return m_data[offset]; } + + void prepare(samplecount nframes); + + void filled_size(size_t size) { m_filled_size = size; } + size_t filled_size() const { return m_filled_size; } + bool is_joined() const { return m_is_joined; } + size_t size() const { return m_size; } + T* data() const { return m_data; } + +protected: + enum BufferState { OK, HALF_SET_CYCLE_1, HALF_SET_CYCLE_2 }; + + void allocate(); + void deallocate(); + + size_t m_size; ///< Allocated buffer size + size_t m_filled_size; ///< Usable buffer size (for MIDI ports etc) + bool m_is_joined; ///< Whether or not @ref m_data is shares with another Buffer + BufferState m_state; ///< State of buffer for setting values next cycle + T m_set_value; ///< Value set by @ref set (may need to be set next cycle) + + T* m_data; ///< Buffer to be returned by data() (not equal to m_local_data if joined) + T* m_local_data; ///< Locally allocated buffer +}; + + +/** Less robust Buffer for Driver's use. + * + * Does not allocate an array by default, and allows direct setting of + * data pointer for zero-copy processing. + */ +template +class DriverBuffer : public Buffer +{ +public: + DriverBuffer(size_t size); + + void set_data(T* data); + +private: + using Buffer::m_data; + using Buffer::m_is_joined; +}; + + +} // namespace Om + +#endif // BUFFER_H diff --git a/src/libs/engine/ClientBroadcaster.cpp b/src/libs/engine/ClientBroadcaster.cpp new file mode 100644 index 00000000..f8823233 --- /dev/null +++ b/src/libs/engine/ClientBroadcaster.cpp @@ -0,0 +1,331 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ClientBroadcaster.h" +#include +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "ObjectStore.h" +#include "NodeFactory.h" +#include "util.h" +#include "Patch.h" +#include "Node.h" +#include "PortInfo.h" +#include "Plugin.h" +#include "PortBase.h" +#include "Connection.h" +#include "AudioDriver.h" +#include "ObjectSender.h" +#include "interface/ClientKey.h" +#include "interface/ClientInterface.h" +#include "OSCClient.h" +using std::cout; using std::cerr; using std::endl; +using Om::Shared::ClientInterface; + +namespace Om { + + +/** Register a client to receive messages over the notification band. + */ +void +ClientBroadcaster::register_client(const ClientKey key, CountedPtr client) +{ + assert(key.type() == ClientKey::OSC_URL); + assert(key.uri() != ""); + + bool found = false; + for (ClientList::iterator i = _clients.begin(); i != _clients.end(); ++i) + if ((*i).first == key) + found = true; + + if (!found) { + _clients.push_back(pair >(key, client)); + cout << "[ClientBroadcaster] Registered client " << key.uri() + << " (" << _clients.size() << " clients)" << endl; + } else { + cout << "[ClientBroadcaster] Client already registered." << endl; + } +} + + +/** Remove a client from the list of registered clients. + * + * The removed client is returned (not deleted). It is the caller's + * responsibility to delete the returned pointer, if it's not NULL. + * + * @return true if client was found and removed (and refcount decremented). + */ +bool +ClientBroadcaster::unregister_client(const ClientKey& key) +{ + cerr << "FIXME: unregister broken\n"; + return false; + +#if 0 + if (responder == NULL) + return NULL; + + // FIXME: remove filthy cast + const string url = lo_address_get_url(((OSCResponder*)responder)->source()); + ClientInterface* r = NULL; + + for (ClientList::iterator i = _clients.begin(); i != _clients.end(); ++i) { + if ((*i).second->url() == url) { + r = *i; + _clients.erase(i); + break; + } + } + + if (r != NULL) + cout << "[OSC] Unregistered client " << r->url() << " (" << _clients.size() << " clients)" << endl; + else + cerr << "[OSC] ERROR: Unable to find client to unregister!" << endl; + + return r; +#endif +} + + + +/** Looks up the client with the given @a source address (which is used as the + * unique identifier for registered clients). + * + * (A responder is passed to remove the dependency on liblo addresses in request + * events, in anticipation of libom and multiple ways of responding to clients). + */ +CountedPtr +ClientBroadcaster::client(const ClientKey& key) +{ + for (ClientList::iterator i = _clients.begin(); i != _clients.end(); ++i) + if ((*i).first == key) + return (*i).second; + + cerr << "[ClientBroadcaster] Failed to find client." << endl; + + return NULL; +} + + +void +ClientBroadcaster::send_error(const string& msg) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->error(msg); +} + + + +void +ClientBroadcaster::send_plugins_to(ClientInterface* client) +{ + om->node_factory()->lock_plugin_list(); + + const list& plugs = om->node_factory()->plugins(); + const Plugin* plugin; + + lo_timetag tt; + lo_timetag_now(&tt); + lo_bundle b = lo_bundle_new(tt); + lo_message m = lo_message_new(); + list msgs; + + lo_message_add_int32(m, plugs.size()); + lo_bundle_add_message(b, "/om/num_plugins", m); + msgs.push_back(m); + + for (list::const_iterator j = plugs.begin(); j != plugs.end(); ++j) { + plugin = (*j); + m = lo_message_new(); + + lo_message_add_string(m, plugin->type_string()); + lo_message_add_string(m, plugin->uri().c_str()); + lo_message_add_string(m, plugin->name().c_str()); + lo_bundle_add_message(b, "/om/plugin", m); + msgs.push_back(m); + if (lo_bundle_length(b) > 1024) { + // FIXME FIXME FIXME dirty, dirty cast + lo_send_bundle(((OSCClient*)client)->address(), b); + lo_bundle_free(b); + b = lo_bundle_new(tt); + } + } + + if (lo_bundle_length(b) > 0) { + // FIXME FIXME FIXME dirty, dirty cast + lo_send_bundle(((OSCClient*)client)->address(), b); + lo_bundle_free(b); + } else { + lo_bundle_free(b); + } + for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i) + lo_message_free(*i); + + om->node_factory()->unlock_plugin_list(); +} + + +void +ClientBroadcaster::send_node(const Node* node) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + ObjectSender::send_node((*i).second.get(), node); +} + + +void +ClientBroadcaster::send_port(const Port* port) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + ObjectSender::send_port((*i).second.get(), port); +} + + +void +ClientBroadcaster::send_destroyed(const string& path) +{ + assert(path != "/"); + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->object_destroyed(path); +} + +void +ClientBroadcaster::send_patch_cleared(const string& patch_path) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->patch_cleared(patch_path); +} + +void +ClientBroadcaster::send_connection(const Connection* const c) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->connection(c->src_port()->path(), c->dst_port()->path()); +} + + +void +ClientBroadcaster::send_disconnection(const string& src_port_path, const string& dst_port_path) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->disconnection(src_port_path, dst_port_path); +} + + +void +ClientBroadcaster::send_patch_enable(const string& patch_path) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->patch_enabled(patch_path); +} + + +void +ClientBroadcaster::send_patch_disable(const string& patch_path) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->patch_disabled(patch_path); +} + + +/** Send notification of a metadata update. + * + * Like control changes, does not send update to client that set the metadata, if applicable. + */ +void +ClientBroadcaster::send_metadata_update(const string& node_path, const string& key, const string& value) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->metadata_update(node_path, key, value); +} + + +/** Send notification of a control change. + * + * If responder is specified, the notification will not be send to the address of + * that responder (to avoid sending redundant information back to clients and + * forcing clients to ignore things to avoid feedback loops etc). + */ +void +ClientBroadcaster::send_control_change(const string& port_path, float value) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->control_change(port_path, value); +} + + +void +ClientBroadcaster::send_program_add(const string& node_path, int bank, int program, const string& name) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->program_add(node_path, bank, program, name); +} + + +void +ClientBroadcaster::send_program_remove(const string& node_path, int bank, int program) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->program_remove(node_path, bank, program); +} + + +/** Send a patch. + * + * Sends all objects underneath Patch - contained Nodes, etc. + */ +void +ClientBroadcaster::send_patch(const Patch* const p) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + ObjectSender::send_patch((*i).second.get(), p); +} + + +/** Sends notification of an OmObject's renaming + */ +void +ClientBroadcaster::send_rename(const string& old_path, const string& new_path) +{ + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + (*i).second->object_renamed(old_path, new_path); +} + + +/** Sends all OmObjects known to the engine. + */ +void +ClientBroadcaster::send_all_objects() +{ + cerr << "FIXME: send_all" << endl; + + //for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + // (*i).second->send_all_objects(); +} + +/* +void +ClientBroadcaster::send_node_creation_messages(const Node* const node) +{ + // This is pretty stupid :/ in and out and back again! + for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i) + node->send_creation_messages((*i).second); +} +*/ + +} // namespace Om diff --git a/src/libs/engine/ClientBroadcaster.h b/src/libs/engine/ClientBroadcaster.h new file mode 100644 index 00000000..b0a60f57 --- /dev/null +++ b/src/libs/engine/ClientBroadcaster.h @@ -0,0 +1,101 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CLIENTBROADCASTER_H +#define CLIENTBROADCASTER_H + +#include +#include +#include +#include +#include +#include +#include "util/types.h" +#include "interface/ClientInterface.h" +#include "util/CountedPtr.h" + +using std::list; using std::string; using std::pair; + +namespace Om { + +class Node; +class Port; +class PortInfo; +class Plugin; +class Patch; +class Connection; +class Responder; +namespace Shared { class ClientKey; } +using Shared::ClientKey; +using Shared::ClientInterface; + +/** Broadcaster for all clients. + * + * This sends messages to all client simultaneously through the opaque + * ClientInterface. The clients may be OSC driver, in process, theoretically + * anything that implements ClientInterface. + * + * This also serves as the database of all registered clients. + * + * \ingroup engine + */ +class ClientBroadcaster +{ +public: + void register_client(const ClientKey key, CountedPtr client); + bool unregister_client(const ClientKey& key); + + CountedPtr client(const ClientKey& key); + + // Notification band: + + //void send_client_registration(const string& url, int client_id); + + // Error that isn't the direct result of a request + void send_error(const string& msg); + + void send_plugins_to(ClientInterface* client); + + //void send_node_creation_messages(const Node* const node); + + void send_patch(const Patch* const p); + void send_node(const Node* const node); + void send_port(const Port* port); + void send_destroyed(const string& path); + void send_patch_cleared(const string& patch_path); + void send_connection(const Connection* const connection); + void send_disconnection(const string& src_port_path, const string& dst_port_path); + void send_rename(const string& old_path, const string& new_path); + void send_all_objects(); + void send_patch_enable(const string& patch_path); + void send_patch_disable(const string& patch_path); + void send_metadata_update(const string& node_path, const string& key, const string& value); + void send_control_change(const string& port_path, float value); + void send_program_add(const string& node_path, int bank, int program, const string& name); + void send_program_remove(const string& node_path, int bank, int program); + +private: + typedef list > > ClientList; + //list > _clients; + ClientList _clients; +}; + + + +} // namespace Om + +#endif // CLIENTBROADCASTER_H + diff --git a/src/libs/engine/Connection.cpp b/src/libs/engine/Connection.cpp new file mode 100644 index 00000000..d1592009 --- /dev/null +++ b/src/libs/engine/Connection.cpp @@ -0,0 +1,45 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Connection.h" +#include "util.h" +#include "Node.h" +#include "Om.h" +#include "Port.h" + +namespace Om { + + +/** Constructor for a connection from a node's output port. + * + * This handles both polyphonic and monophonic nodes, transparently to the + * user (InputPort). + */ +Connection::Connection(Port* const src_port, Port* const dst_port) +: m_src_port(src_port), + m_dst_port(dst_port), + m_is_poly_to_mono( (src_port->parent_node()->poly() > dst_port->parent_node()->poly()) ), + m_pending_disconnection(false) +{ + assert(src_port != NULL); + assert(dst_port != NULL); + + assert((src_port->parent_node()->poly() == dst_port->parent_node()->poly()) + || (src_port->parent_node()->poly() == 1 || dst_port->parent_node()->poly() == 1)); +} + +} // namespace Om + diff --git a/src/libs/engine/Connection.h b/src/libs/engine/Connection.h new file mode 100644 index 00000000..769c2047 --- /dev/null +++ b/src/libs/engine/Connection.h @@ -0,0 +1,66 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONNECTION_H +#define CONNECTION_H + +#include +#include "MaidObject.h" +#include "util/types.h" + +namespace Om { + +class Port; + + +/** Represents a single inbound connection for an InputPort. + * + * This can be a group of ports (ie coming from a polyphonic Node) or + * a single Port. This class exists basically as an abstraction of mixing + * down polyphonic inputs, so InputPort can just deal with mixing down + * multiple connections (oblivious to the polyphonic situation of the + * connection itself). + * + * \ingroup engine + */ +class Connection : public MaidObject +{ +public: + virtual ~Connection() {} + + Port* src_port() const { return m_src_port; } + Port* dst_port() const { return m_dst_port; } + + /** Used by some (recursive) events to prevent double disconnections */ + bool pending_disconnection() { return m_pending_disconnection; } + void pending_disconnection(bool b) { m_pending_disconnection = b; } + +protected: + // Disallow copies (undefined) + Connection(const Connection&); + + Connection(Port* const src_port, Port* const dst_port); + + Port* const m_src_port; + Port* const m_dst_port; + bool m_is_poly_to_mono; + bool m_pending_disconnection; +}; + + +} // namespace Om + +#endif // CONNECTION_H diff --git a/src/libs/engine/ConnectionBase.cpp b/src/libs/engine/ConnectionBase.cpp new file mode 100644 index 00000000..c8936818 --- /dev/null +++ b/src/libs/engine/ConnectionBase.cpp @@ -0,0 +1,96 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ConnectionBase.h" +#include "util.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Node.h" +#include "Om.h" +#include "Port.h" + +namespace Om { + + +/** Constructor for a connection from a node's output port. + * + * This handles both polyphonic and monophonic nodes, transparently to the + * user (InputPort). + */ +template +ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port) +: Connection(src_port, dst_port), + m_local_buffer(NULL), + m_is_poly_to_mono( (src_port->parent_node()->poly() > dst_port->parent_node()->poly()) ), + m_buffer_size(src_port->buffer_size()), + m_pending_disconnection(false) +{ + assert((src_port->parent_node()->poly() == dst_port->parent_node()->poly()) + || (src_port->parent_node()->poly() == 1 || dst_port->parent_node()->poly() == 1)); + + if (m_is_poly_to_mono) // Poly -> Mono connection, need a buffer to mix in to + m_local_buffer = new Buffer(m_buffer_size); +} +template ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); +template ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); + + +template +ConnectionBase::~ConnectionBase() +{ + delete m_local_buffer; +} +template ConnectionBase::~ConnectionBase(); +template ConnectionBase::~ConnectionBase(); + + +template +void +ConnectionBase::prepare_buffers() +{ + /* Thought: A poly output port can be connected to multiple mono input + * ports, which means this mix down would have to happen many times. + * Adding a method to OutputPort that mixes down all it's outputs into + * a buffer (if it hasn't been done already this cycle) and returns that + * would avoid having to mix multiple times. Probably not a very common + * case, but it would be faster anyway. */ + + if (m_is_poly_to_mono) { + m_local_buffer->copy(src_port()->buffer(0), 0, m_buffer_size-1); + + // Mix all the source's voices down into local buffer starting at the second + // voice (buffer is already set to first voice above) + for (size_t j=1; j < src_port()->poly(); ++j) + m_local_buffer->accumulate(src_port()->buffer(j), 0, m_buffer_size-1); + + // Scale the buffer down. + if (src_port()->poly() > 1) + m_local_buffer->scale(1.0f/(float)src_port()->poly(), 0, m_buffer_size-1); + } +} +template void ConnectionBase::prepare_buffers(); + + +// FIXME: MIDI mixing not implemented +template <> +void +ConnectionBase::prepare_buffers() +{ +} + + +} // namespace Om + diff --git a/src/libs/engine/ConnectionBase.h b/src/libs/engine/ConnectionBase.h new file mode 100644 index 00000000..72acae2e --- /dev/null +++ b/src/libs/engine/ConnectionBase.h @@ -0,0 +1,105 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONNECTIONBASE_H +#define CONNECTIONBASE_H + +#include "util/types.h" +#include "OutputPort.h" +#include "Connection.h" + +namespace Om { + +class MidiMessage; +class Port; +template class InputPort; + + +/** A Connection with a type. + * + * \ingroup engine + */ +template +class ConnectionBase : public Connection +{ +public: + ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); + virtual ~ConnectionBase(); + + void prepare_buffers(); + + inline OutputPort* src_port() const { return (OutputPort*)m_src_port; } + inline InputPort* dst_port() const { return (InputPort*)m_dst_port; } + + /** Used by some (recursive) events to prevent double disconnections */ + bool pending_disconnection() { return m_pending_disconnection; } + void pending_disconnection(bool b) { m_pending_disconnection = b; } + + /** Get the buffer for a particular voice. + * A ConnectionBase is smart - it knows the destination port respondering the + * buffer, and will return accordingly (ie the same buffer for every voice + * in a mono->poly connection). + */ + inline Buffer* buffer(size_t voice) const; + +private: + // Disallow copies (undefined) + ConnectionBase(const ConnectionBase& copy); + ConnectionBase& operator=(const ConnectionBase&); + + Buffer* m_local_buffer; ///< Only used for poly->mono connections + bool m_is_poly_to_mono; + size_t m_buffer_size; + bool m_pending_disconnection; +}; + + +template <> +inline Buffer* +ConnectionBase::buffer(size_t voice) const +{ + PortBase* const src_port = (PortBase*)m_src_port; + + if (m_is_poly_to_mono) { + return m_local_buffer; + } else { + if (src_port->poly() == 1) + return src_port->buffer(0); + else + return src_port->buffer(voice); + } +} + + +template <> +inline Buffer* +ConnectionBase::buffer(size_t voice) const +{ + // No such thing as polyphonic MIDI ports + assert(m_src_port->poly() == 1); + assert(m_dst_port->poly() == 1); + + PortBase* const src_port = (PortBase*)m_src_port; + return src_port->buffer(0); +} + + +template class ConnectionBase; +template class ConnectionBase; + +} // namespace Om + +#endif // CONNECTIONBASE_H diff --git a/src/libs/engine/ControlInputNode.cpp b/src/libs/engine/ControlInputNode.cpp new file mode 100644 index 00000000..d4d83558 --- /dev/null +++ b/src/libs/engine/ControlInputNode.cpp @@ -0,0 +1,49 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ControlInputNode.h" +#include "util/types.h" +#include "Patch.h" +#include "OutputPort.h" +#include "InputPort.h" +#include "Plugin.h" +#include "PortInfo.h" + +namespace Om { + + +ControlInputNode::ControlInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: BridgeNode(path, poly, parent, srate, buffer_size) +{ + OutputPort* internal_port = new OutputPort(this, "in", 0, m_poly, + new PortInfo("in", CONTROL, OUTPUT), 1); + InputPort* external_port = new InputPort(parent, m_name, 0, m_poly, + new PortInfo(m_name, CONTROL, INPUT), 1); + external_port->tie(internal_port); + m_external_port = external_port; + + m_num_ports = 1; + m_ports.alloc(m_num_ports); + m_ports.at(0) = internal_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("control_input"); + m_plugin.name("Om Patch Control Input Node"); +} + + +} // namespace Om + diff --git a/src/libs/engine/ControlInputNode.h b/src/libs/engine/ControlInputNode.h new file mode 100644 index 00000000..0be82af0 --- /dev/null +++ b/src/libs/engine/ControlInputNode.h @@ -0,0 +1,44 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONTROLINPUTNODE_H +#define CONTROLINPUTNODE_H + +#include +#include "util/types.h" +#include "BridgeNode.h" + +using std::string; + +namespace Om { + +template class InputPort; + + +/** Control input BridgeNode. + * + * \ingroup engine + */ +class ControlInputNode : public BridgeNode +{ +public: + ControlInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); +}; + + +} // namespace Om + +#endif // CONTROLINPUTNODE_H diff --git a/src/libs/engine/ControlOutputNode.cpp b/src/libs/engine/ControlOutputNode.cpp new file mode 100644 index 00000000..7e1f3e2a --- /dev/null +++ b/src/libs/engine/ControlOutputNode.cpp @@ -0,0 +1,48 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ControlOutputNode.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "PortInfo.h" +#include "Plugin.h" +#include "Patch.h" + +namespace Om { + + +ControlOutputNode::ControlOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: BridgeNode(path, poly, parent, srate, buffer_size) +{ + OutputPort* external_port = new OutputPort(parent, m_name, 0, m_poly, + new PortInfo(m_name, CONTROL, OUTPUT), 1); + InputPort* internal_port = new InputPort(this, "out", 0, m_poly, + new PortInfo("out", CONTROL, INPUT), 1); + internal_port->tie(external_port); + m_external_port = external_port; + + m_num_ports = 1; + m_ports.alloc(m_num_ports); + m_ports.at(0) = internal_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("control_output"); + m_plugin.name("Om Patch Control Output Node"); +} + + +} // namespace Om + diff --git a/src/libs/engine/ControlOutputNode.h b/src/libs/engine/ControlOutputNode.h new file mode 100644 index 00000000..64fd9ce6 --- /dev/null +++ b/src/libs/engine/ControlOutputNode.h @@ -0,0 +1,45 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONTROLOUTPUTNODE_H +#define CONTROLOUTPUTNODE_H + +#include +#include "util/types.h" +#include "BridgeNode.h" + +using std::string; + +namespace Om { + +class Port; +template class OutputPort; + + +/** Control output BridgeNode. + * + * \ingroup engine + */ +class ControlOutputNode : public BridgeNode +{ +public: + ControlOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); +}; + + +} // namespace Om + +#endif // CONTROLOUTPUTNODE_H diff --git a/src/libs/engine/Controller.h b/src/libs/engine/Controller.h new file mode 100644 index 00000000..facfb4c2 --- /dev/null +++ b/src/libs/engine/Controller.h @@ -0,0 +1,82 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONTROLLER_H +#define CONTROLLER_H + +namespace Om { + + +/** Public interface to Om engine shared library. + * + * This is an interface to all the audio-processing related functionality + * only. OSC communication, LASH session management, etc, are not part of + * this library. + */ +class Controller { +public: + void init(); + void quit(); + + void load_plugins(); + + void activate_engine(); + void deactivate_engine(); + + void create_patch(const char* path, unsigned int polyphony); + void clear_patch(const char* path); + void enable_patch(const char* path); + void disable_patch(const char* path); + void rename(const char* old_path, const char* new_path); + + void create_node(const char* path, + const char* type, + const char* library_name, + const char* library_label, + unsigned int polyphony); + + void destroy(const char* path); + + void connect(const char* src_port_path, const char* dst_port_path); + void disconnect(const char* src_port_path, const char* dst_port_path); + void disconnect_all(const char* path); + + void set_port_value(const char* path, float value); + void set_port_value_voice(const char* path, unsigned int voice); + void set_port_value_slow(const char* path, float value); + + void note_on(const char* node_path, + unsigned char note_num, + unsigned char velocity); + + void note_off(const char* node_path, + unsigned char note_num); + + void all_notes_off(const char* node_path); + void midi_learn(const char* node_path); + + void get_metadata(); + void set_metadata(); + void responder_plugins(); + void responder_all_objects(); + void responder_port_value(); +}; + + +} // namespace Om + +#endif // CONTROLLER_H + diff --git a/src/libs/engine/DSSIPlugin.cpp b/src/libs/engine/DSSIPlugin.cpp new file mode 100644 index 00000000..e8525b7b --- /dev/null +++ b/src/libs/engine/DSSIPlugin.cpp @@ -0,0 +1,340 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DSSIPlugin.h" +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "ClientBroadcaster.h" +#include "interface/ClientInterface.h" +#include "InputPort.h" +#include "PortInfo.h" + +using namespace std; + +namespace Om { + + +DSSIPlugin::DSSIPlugin(const string& name, size_t poly, Patch* parent, DSSI_Descriptor* descriptor, samplerate srate, size_t buffer_size) +: LADSPAPlugin(name, 1, parent, descriptor->LADSPA_Plugin, srate, buffer_size), + m_dssi_descriptor(descriptor), + m_ui_addr(NULL), + m_bank(-1), + m_program(-1), + m_midi_in_port(NULL), + m_alsa_events(new snd_seq_event_t[m_buffer_size]), + m_alsa_encoder(NULL) +{ + if (has_midi_input()) + m_num_ports = descriptor->LADSPA_Plugin->PortCount + 1; + + snd_midi_event_new(3, &m_alsa_encoder); +} + + +DSSIPlugin::~DSSIPlugin() +{ + if (m_ui_addr != NULL) + lo_address_free(m_ui_addr); + + snd_midi_event_free(m_alsa_encoder); + delete [] m_alsa_events; +} + + +/** This needs to be overridden here because LADSPAPlugin::instantiate() + * allocates the port array, and we want to add the MIDI input port to that + * array. + */ +bool +DSSIPlugin::instantiate() +{ + if (!LADSPAPlugin::instantiate()) + return false; + + if (has_midi_input()) { + assert(m_num_ports == m_descriptor->PortCount + 1); + assert(m_ports.size() == m_descriptor->PortCount + 1); + + m_midi_in_port = new InputPort(this, "MIDI In", m_num_ports-1, 1, + new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); + m_ports.at(m_num_ports-1) = m_midi_in_port; + } + + return true; +} + + +void +DSSIPlugin::activate() +{ + LADSPAPlugin::activate(); + + update_programs(false); + set_default_program(); + + snd_midi_event_reset_encode(m_alsa_encoder); +} + + +void +DSSIPlugin::set_ui_url(const string& url) +{ + if (m_ui_addr != NULL) + lo_address_free(m_ui_addr); + + m_ui_url = url; + m_ui_addr = lo_address_new_from_url(url.c_str()); + char* base_path = lo_url_get_path(url.c_str()); + m_ui_base_path = base_path; + free(base_path); + cerr << "Set UI base path to " << m_ui_base_path << endl; +} + + +void +DSSIPlugin::set_control(size_t port_num, sample val) +{ + assert(port_num < m_descriptor->PortCount); + ((PortBase*)m_ports.at(port_num))->set_value(val, 0); +} + + +void +DSSIPlugin::configure(const string& key, const string& val) +{ + m_dssi_descriptor->configure(m_instances[0], key.c_str(), val.c_str()); + m_configures[key] = val; + update_programs(true); +} + + +void +DSSIPlugin::program(int bank, int program) +{ + if (m_dssi_descriptor->select_program) + m_dssi_descriptor->select_program(m_instances[0], bank, program); + + m_bank = bank; + m_program = program; +} + + +void +DSSIPlugin::convert_events() +{ + assert(has_midi_input()); + assert(m_midi_in_port != NULL); + + Buffer& buffer = *m_midi_in_port->buffer(0); + m_encoded_events = 0; + + for (size_t i = 0; i < buffer.filled_size(); ++i) { + snd_midi_event_encode(m_alsa_encoder, buffer.value_at(i).buffer, + buffer.value_at(i).size, + &m_alsa_events[m_encoded_events]); + m_alsa_events[m_encoded_events].time.tick = buffer.value_at(i).time; + if (m_alsa_events[m_encoded_events].type != SND_SEQ_EVENT_NONE) + ++m_encoded_events; + } +} + + +bool +DSSIPlugin::has_midi_input() const +{ + return (m_dssi_descriptor->run_synth || m_dssi_descriptor->run_multiple_synths); +} + + +void +DSSIPlugin::run(size_t nframes) +{ + NodeBase::run(nframes); + + if (m_dssi_descriptor->run_synth) { + convert_events(); + m_dssi_descriptor->run_synth(m_instances[0], nframes, + m_alsa_events, m_encoded_events); + } else if (m_dssi_descriptor->run_multiple_synths) { + convert_events(); + // I hate this stupid function + snd_seq_event_t* events[1] = { m_alsa_events }; + long unsigned events_sizes[1] = { m_encoded_events }; + m_dssi_descriptor->run_multiple_synths(1, m_instances, nframes, + events, events_sizes); + } else { + LADSPAPlugin::run(nframes); + } +} + + +void +DSSIPlugin::send_control(int port_num, float value) +{ + string path = m_ui_base_path + "/control"; + lo_send(m_ui_addr, path.c_str(), "if", port_num, value); +} + + +void +DSSIPlugin::send_program(int bank, int value) +{ + string path = m_ui_base_path + "/program"; + lo_send(m_ui_addr, path.c_str(), "ii", bank, value); +} + + +void +DSSIPlugin::send_configure(const string& key, const string& val) +{ + string path = m_ui_base_path + "/configure"; + lo_send(m_ui_addr, path.c_str(), "ss", key.c_str(), val.c_str()); +} + + +void +DSSIPlugin::send_show() +{ + string path = m_ui_base_path + "/show"; + lo_send(m_ui_addr, path.c_str(), NULL); +} + + +void +DSSIPlugin::send_hide() +{ + string path = m_ui_base_path + "/hide"; + lo_send(m_ui_addr, path.c_str(), NULL); +} + + +void +DSSIPlugin::send_quit() +{ + string path = m_ui_base_path + "/quit"; + lo_send(m_ui_addr, path.c_str(), NULL); +} + + +void +DSSIPlugin::send_update() +{ + // send "configure"s + for (map::iterator i = m_configures.begin(); i != m_configures.end(); ++i) + send_configure((*i).first, (*i).second); + + // send "program" + send_program(m_bank, m_program); + + // send "control"s + for (size_t i=0; i < m_ports.size(); ++i) + if (m_ports[i]->port_info()->is_control()) + send_control(m_ports[i]->num(), ((PortBase*)m_ports[i])->buffer(0)->value_at(0)); + + // send "show" FIXME: not to spec + send_show(); +} + + +bool +DSSIPlugin::update_programs(bool send_events) +{ + // remember all old banks and programs + set > to_be_deleted; + map::const_iterator iter; + Bank::const_iterator iter2; + for (iter = m_banks.begin(); iter != m_banks.end(); ++iter) { + for (iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) { + to_be_deleted.insert(make_pair(iter->first, iter2->first)); + } + } + + // iterate over all programs + if (m_dssi_descriptor->get_program) { + for (int i = 0; true; ++i) { + const DSSI_Program_Descriptor* descriptor = + m_dssi_descriptor->get_program(m_instances[0], i); + if (!descriptor) + break; + + iter = m_banks.find(descriptor->Bank); + if (iter == m_banks.end() || + iter->second.find(descriptor->Program) == iter->second.end() || + iter->second.find(descriptor->Program)->second != descriptor->Name) { + m_banks[descriptor->Bank][descriptor->Program] = descriptor->Name; + if (send_events) { + om->client_broadcaster()->send_program_add(path(), descriptor->Bank, + descriptor->Program, + descriptor->Name); + } + to_be_deleted.erase(make_pair(descriptor->Bank, descriptor->Program)); + } + } + } + + // remove programs that has disappeared from the plugin + set >::const_iterator set_iter; + for (set_iter = to_be_deleted.begin(); + set_iter != to_be_deleted.end(); ++set_iter) { + m_banks[set_iter->first].erase(set_iter->second); + if (send_events) + om->client_broadcaster()->send_program_remove(path(), set_iter->first, set_iter->second); + if (m_banks[set_iter->first].size() == 0) + m_banks.erase(set_iter->first); + } + + return true; +} + + +void +DSSIPlugin::set_default_program() +{ + map::const_iterator iter = m_banks.begin(); + if (iter != m_banks.end()) { + Bank::const_iterator iter2 = iter->second.begin(); + if (iter2 != iter->second.end()) + program(iter->first, iter2->first); + } +} + + +const map& +DSSIPlugin::get_programs() const +{ + return m_banks; +} + + +/* +void +DSSIPlugin::send_creation_messages(ClientInterface* client) const +{ + LADSPAPlugin::send_creation_messages(client); + + for (map::const_iterator i = get_programs().begin(); + i != get_programs().end(); ++i) { + + for (Bank::const_iterator j = i->second.begin(); j != i->second.end(); ++j) + client->program_add(path(), + i->first, j->first, j->second); + } +} +*/ + +} // namespace Om diff --git a/src/libs/engine/DSSIPlugin.cpp.orig b/src/libs/engine/DSSIPlugin.cpp.orig new file mode 100644 index 00000000..7c8060f0 --- /dev/null +++ b/src/libs/engine/DSSIPlugin.cpp.orig @@ -0,0 +1,207 @@ +/* This file is part of Om. Copyright (C) 2005 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DSSIPlugin.h" +#include +#include "Om.h" +#include "OmApp.h" +#include "config.h" +#include "Patch.h" +#include "PortBase.h" +#include "InputPort.h" +#include "PortInfo.h" + +using std::map; + +namespace Om { + + +DSSIPlugin::DSSIPlugin(const string& name, uint poly, Patch* parent, DSSI_Descriptor* descriptor, samplerate srate, size_t buffer_size) +: LADSPAPlugin(name, 1, parent, descriptor->LADSPA_Plugin, srate, buffer_size), + m_ui_addr(NULL), + m_bank(-1), + m_program(-1), + m_dssi_descriptor(descriptor) +{ + m_num_ports = descriptor->LADSPA_Plugin->PortCount + 1; + m_ports.alloc(m_num_ports); + + m_midi_in_port = new InputPort(this, "MIDI In", m_num_ports-1, 1, + new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); + + m_ports.at(m_num_ports-1) = m_midi_in_port; +} + + +DSSIPlugin::~DSSIPlugin() +{ + if (m_ui_addr != NULL) + lo_address_free(m_ui_addr); +} + + +void +DSSIPlugin::activate() +{ + LADSPAPlugin::activate(); +} + + +void +DSSIPlugin::set_ui_url(const string& url) +{ + if (m_ui_addr != NULL) + lo_address_free(m_ui_addr); + + m_ui_url = url; + m_ui_addr = lo_address_new_from_url(url.c_str()); + char* base_path = lo_url_get_path(url.c_str()); + m_ui_base_path = base_path; + free(base_path); + cerr << "Set UI base path to " << m_ui_base_path << endl; +} + + +void +DSSIPlugin::set_control(uint port_num, sample val) +{ + assert(port_num < m_descriptor->PortCount); + ((PortBase*)m_ports.at(port_num))->set_value(0, val); +} + + +void +DSSIPlugin::configure(const string& key, const string& val) +{ + m_dssi_descriptor->configure(m_instances[0], key.c_str(), val.c_str()); + m_configures[key] = val; +} + + +void +DSSIPlugin::program(int bank, int program) +{ + if (m_dssi_descriptor->select_program) + m_dssi_descriptor->select_program(m_instances[0], bank, program); + + m_bank = bank; + m_program = program; +} + + +void +DSSIPlugin::run(size_t nframes) +{ + NodeBase::run(nframes); + + /*if (m_dssi_descriptor->run_synth) { + m_dssi_descriptor->run_synth(m_instances[0], nframes, + parent_patch()->dssi_events_array(), parent_patch()->dssi_events_size()); + } else if (m_dssi_descriptor->run_multiple_synths) { // I hate this stupid function + snd_seq_event_t* events[1] = { parent_patch()->dssi_events_array() }; + long unsigned events_sizes[1] = { parent_patch()->dssi_events_size() }; + m_dssi_descriptor->run_multiple_synths(1, m_instances, nframes, + events, events_sizes); + } else { + LADSPAPlugin::run(nframes); + } + */ + + if (m_dssi_descriptor->run_synth) { + m_dssi_descriptor->run_synth(m_instances[0], nframes, + (snd_seq_event_t*)m_midi_in_port->buffer(0), m_midi_in_port->get_valid_buffer_size()); + /*} else if (m_dssi_descriptor->run_multiple_synths) { // I hate this stupid function + snd_seq_event_t* events[1] = { parent_patch()->dssi_events_array() }; + long unsigned events_sizes[1] = { parent_patch()->dssi_events_size() }; + m_dssi_descriptor->run_multiple_synths(1, m_instances, nframes, + events, events_sizes);*/ + } else { + LADSPAPlugin::run(nframes); + } + + +} + + +void +DSSIPlugin::send_control(int port_num, float value) +{ + string path = m_ui_base_path + "/control"; + lo_send(m_ui_addr, path.c_str(), "if", port_num, value); +} + + +void +DSSIPlugin::send_program(int bank, int value) +{ + string path = m_ui_base_path + "/program"; + lo_send(m_ui_addr, path.c_str(), "ii", bank, value); +} + + +void +DSSIPlugin::send_configure(const string& key, const string& val) +{ + string path = m_ui_base_path + "/configure"; + lo_send(m_ui_addr, path.c_str(), "ss", key.c_str(), val.c_str()); +} + + +void +DSSIPlugin::send_show() +{ + string path = m_ui_base_path + "/show"; + lo_send(m_ui_addr, path.c_str(), NULL); +} + + +void +DSSIPlugin::send_hide() +{ + string path = m_ui_base_path + "/hide"; + lo_send(m_ui_addr, path.c_str(), NULL); +} + + +void +DSSIPlugin::send_quit() +{ + string path = m_ui_base_path + "/quit"; + lo_send(m_ui_addr, path.c_str(), NULL); +} + + +void +DSSIPlugin::send_update() +{ + // send "configure"s + for (map::iterator i = m_configures.begin(); i != m_configures.end(); ++i) + send_configure((*i).first, (*i).second); + + // send "program" + send_program(m_bank, m_program); + + // send "control"s + for (size_t i=0; i < m_ports.size(); ++i) + if (m_ports[i]->port_info()->is_control()) + send_control(m_ports[i]->num(), ((PortBase*)m_ports[i])->get_value(0, 0)); + + // send "show" FIXME: not to spec + send_show(); +} + + +} // namespace Om diff --git a/src/libs/engine/DSSIPlugin.h b/src/libs/engine/DSSIPlugin.h new file mode 100644 index 00000000..d546a8fe --- /dev/null +++ b/src/libs/engine/DSSIPlugin.h @@ -0,0 +1,109 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DSSIPLUGIN_H +#define DSSIPLUGIN_H + +#include +#include +#include +#include "LADSPAPlugin.h" + +namespace Om { + +class MidiMessage; +template class InputPort; +namespace Shared { + class ClientInterface; +} using Shared::ClientInterface; + + +/** An instance of a DSSI plugin. + */ +class DSSIPlugin : public LADSPAPlugin +{ +public: + + typedef map Bank; + + DSSIPlugin(const string& name, size_t poly, Patch* parent, DSSI_Descriptor* descriptor, samplerate srate, size_t buffer_size); + ~DSSIPlugin(); + + bool instantiate(); + + void activate(); + + void set_ui_url(const string& url); + void send_update(); + + void set_control(size_t port_num, sample val); + void configure(const string& key, const string& val); + void program(int bank, int program); + + void run(size_t nframes); + + bool update_programs(bool send_events); + void set_default_program(); + const map& get_programs() const; + + //void send_creation_messages(ClientInterface* client) const; + + const Plugin* plugin() const { return m_plugin; } + void plugin(const Plugin* const pi) { m_plugin = pi; } + +private: + // Prevent copies (undefined) + DSSIPlugin(const DSSIPlugin& copy); + DSSIPlugin& operator=(const DSSIPlugin& copy); + + bool has_midi_input() const; + + // DSSI GUI messages + void send_control(int port_num, float value); + void send_program(int bank, int value); + void send_configure(const string& key, const string& val); + void send_show(); + void send_hide(); + void send_quit(); + + // Conversion to ALSA MIDI events + void convert_events(); + + + DSSI_Descriptor* m_dssi_descriptor; + + string m_ui_url; + string m_ui_base_path; + lo_address m_ui_addr; + + // Current values + int m_bank; + int m_program; + map m_configures; + map m_banks; + + InputPort* m_midi_in_port; + snd_seq_event_t* m_alsa_events; + unsigned long m_encoded_events; + snd_midi_event_t* m_alsa_encoder; +}; + + +} // namespace Om + + +#endif // DSSIPLUGIN_H + diff --git a/src/libs/engine/DSSIPlugin.h.orig b/src/libs/engine/DSSIPlugin.h.orig new file mode 100644 index 00000000..816c65a7 --- /dev/null +++ b/src/libs/engine/DSSIPlugin.h.orig @@ -0,0 +1,84 @@ +/* This file is part of Om. Copyright (C) 2005 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DSSIPLUGIN_H +#define DSSIPLUGIN_H + +#include +#include +#include "LADSPAPlugin.h" + +namespace Om { + +class MidiMessage; +template class InputPort; + + +/** An instance of a DSSI plugin. + */ +class DSSIPlugin : public LADSPAPlugin +{ +public: + DSSIPlugin(const string& name, uint poly, Patch* parent, DSSI_Descriptor* descriptor, samplerate srate, size_t buffer_size); + ~DSSIPlugin(); + + void activate(); + + void set_ui_url(const string& url); + void send_update(); + + void set_control(uint port_num, sample val); + void configure(const string& key, const string& val); + void program(int bank, int program); + + void run(size_t nframes); + + const Plugin* const plugin() const { return m_plugin; } + void plugin(const Plugin* const pi) { m_plugin = pi; } + +private: + // Prevent copies + DSSIPlugin(const DSSIPlugin& copy) : LADSPAPlugin(copy) { exit(EXIT_FAILURE); } + DSSIPlugin& operator=(const DSSIPlugin& copy) { exit(EXIT_FAILURE); } + + // DSSI GUI messages + void send_control(int port_num, float value); + void send_program(int bank, int value); + void send_configure(const string& key, const string& val); + void send_show(); + void send_hide(); + void send_quit(); + + string m_ui_url; + string m_ui_base_path; + lo_address m_ui_addr; + + // Current values + int m_bank; + int m_program; + map m_configures; + + DSSI_Descriptor* m_dssi_descriptor; + + InputPort* m_midi_in_port; +}; + + +} // namespace Om + + +#endif // DSSIPLUGIN_H + diff --git a/src/libs/engine/Driver.h b/src/libs/engine/Driver.h new file mode 100644 index 00000000..be882d8d --- /dev/null +++ b/src/libs/engine/Driver.h @@ -0,0 +1,112 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DRIVER_H +#define DRIVER_H + +#include +using std::string; + +namespace Om { + +template class PortBase; + + +/** Representation of a system (outside Om, ie hardware) audio port. + * + * This is the class through which the rest of the engine manages everything + * related to driver ports. Derived classes are expected to have a pointer to + * their driver (to be able to perform the operation necessary). + * + * \ingroup engine + */ +class DriverPort { +public: + virtual ~DriverPort() {} + + /** Add this port to driver at the beginning of a process cycle (realtime safe) */ + virtual void add_to_driver() = 0; + + /** Remove this port at the beginning of a process cycle (realtime safe) */ + virtual void remove_from_driver() = 0; + + /** Set the name of the system port */ + virtual void set_name(const string& name) = 0; + +protected: + DriverPort() {} +}; + + +/** Driver abstract base class. + * + * A Driver is, from the perspective of OmObjects (nodes, patches, ports) an + * interface for managing system ports. An implementation of Driver basically + * needs to manage DriverPorts, and handle writing/reading data to/from them. + * + * The template parameter T is the type of data this driver manages (ie the + * data type of the bridge ports it will handle). + * + * \ingroup engine + */ +template +class Driver +{ +public: + virtual ~Driver() {} + + virtual void activate() = 0; + virtual void deactivate() = 0; + + virtual bool is_activated() const = 0; + + /** Create a port ready to be inserted with add_input (non realtime). + * + * May return NULL if the Driver can not drive the port for some reason. + */ + virtual DriverPort* create_port(PortBase* patch_port) = 0; +}; + + +#if 0 +/** Dummy audio driver. + * + * Not abstract, all functions are dummies. One of these will be allocated and + * "used" if no working AUDIO driver is loaded. (Doing it this way as opposed to + * just making Driver have dummy functions makes sure any existing Driver + * derived class actually implements the required functions). + * + * \ingroup engine + */ +class DummyDriver : public Driver +{ +public: + ~DummyDriver() {} + + void activate() {} + void deactivate() {} + + void enable() {} + void disable() {} + + DriverPort* create_port(PortBase* patch_port) { return NULL; } +}; +#endif + + +} // namespace Om + +#endif // DRIVER_H diff --git a/src/libs/engine/Event.cpp b/src/libs/engine/Event.cpp new file mode 100644 index 00000000..7d590e76 --- /dev/null +++ b/src/libs/engine/Event.cpp @@ -0,0 +1,48 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Event.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "AudioDriver.h" + +namespace Om { + +// It'd be nice if this was inlined.. +Event::Event(CountedPtr responder) +: m_responder(responder), + m_executed(false) +{ + m_time_stamp = om->audio_driver()->time_stamp(); +} + + +/** Construct an event with no responder. + * + * For internal events only, attempting to access the responder will + * cause a NULL pointer dereference. + */ +Event::Event() +: m_responder(NULL), + m_executed(false) +{ + m_time_stamp = om->audio_driver()->time_stamp(); +} + + +} // namespace Om + diff --git a/src/libs/engine/Event.h b/src/libs/engine/Event.h new file mode 100644 index 00000000..a6d06f83 --- /dev/null +++ b/src/libs/engine/Event.h @@ -0,0 +1,71 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EVENT_H +#define EVENT_H + +#include +#include "util/CountedPtr.h" +#include "util/types.h" +#include "MaidObject.h" +#include "Responder.h" + +namespace Om { + + + +/** Base class for all events (both realtime and QueuedEvent). + * + * This is for time-critical events like note ons. There is no non-realtime + * pre-execute method as in QueuedEvent's, any lookups etc need to be done in the + * realtime execute() method. + * + * QueuedEvent extends this class with a pre_process() method for any work that needs + * to be done before processing in the realtime audio thread. + * + * \ingroup engine + */ +class Event : public MaidObject +{ +public: + virtual ~Event() {} + + /** Execute event, MUST be realtime safe */ + virtual void execute(samplecount offset) { assert(!m_executed); m_executed = true; } + + /** Perform any actions after execution (ie send OSC response to client). + * No realtime requirement. */ + virtual void post_process() {} + + inline samplecount time_stamp() { return m_time_stamp; } + +protected: + Event(CountedPtr responder); + Event(); + + // Prevent copies + Event(const Event&); + Event& operator=(const Event&); + + CountedPtr m_responder; + samplecount m_time_stamp; + bool m_executed; +}; + + +} // namespace Om + +#endif // EVENT_H diff --git a/src/libs/engine/EventSource.h b/src/libs/engine/EventSource.h new file mode 100644 index 00000000..b038f427 --- /dev/null +++ b/src/libs/engine/EventSource.h @@ -0,0 +1,52 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EVENTSOURCE_H +#define EVENTSOURCE_H + +namespace Om { + +class Event; +class QueuedEvent; + + +/** Source for events to run in the audio thread. + * + * The AudioDriver gets events from an EventSource in the process callback + * (realtime audio thread) and executes them, then they are sent to the + * PostProcessor and finalised (post-processing thread). + */ +class EventSource +{ +public: + + virtual ~EventSource() {} + + virtual Event* pop_earliest_event_before(const samplecount time) = 0; + + virtual void start() = 0; + + virtual void stop() = 0; + +protected: + EventSource() {} +}; + + +} // namespace Om + +#endif // EVENTSOURCE_H + diff --git a/src/libs/engine/InputPort.cpp b/src/libs/engine/InputPort.cpp new file mode 100644 index 00000000..3837da1b --- /dev/null +++ b/src/libs/engine/InputPort.cpp @@ -0,0 +1,352 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "InputPort.h" +#include +#include +#include +#include "ConnectionBase.h" +#include "OutputPort.h" +#include "PortInfo.h" +#include "Node.h" +#include "Om.h" +#include "util.h" + +using std::cerr; using std::cout; using std::endl; + + +namespace Om { + + +template +InputPort::InputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size) +: PortBase(node, name, index, poly, port_info, buffer_size) +{ + assert(port_info->is_input() && !port_info->is_output()); +} +template InputPort::InputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); +template InputPort::InputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); + + +/** Add a connection. Realtime safe. + * + * The buffer of this port will be set directly to the connection's buffer + * if there is only one connection, since no mixing needs to take place. + */ +template +void +InputPort::add_connection(ListNode*>* const c) +{ + m_connections.push_back(c); + + bool modify_buffers = !m_fixed_buffers; + if (modify_buffers && m_is_tied) + modify_buffers = !m_tied_port->fixed_buffers(); + + if (modify_buffers) { + if (m_connections.size() == 1) { + // Use buffer directly to avoid copying + for (size_t i=0; i < m_poly; ++i) { + m_buffers.at(i)->join(c->elem()->buffer(i)); + if (m_is_tied) + m_tied_port->buffer(i)->join(m_buffers.at(i)); + assert(m_buffers.at(i)->data() == c->elem()->buffer(i)->data()); + } + } else if (m_connections.size() == 2) { + // Used to directly use single connection buffer, now there's two + // so have to use local ones again and mix down + for (size_t i=0; i < m_poly; ++i) { + m_buffers.at(i)->unjoin(); + if (m_is_tied) + m_tied_port->buffer(i)->join(m_buffers.at(i)); + } + } + update_buffers(); + } + + assert( ! m_is_tied || m_tied_port != NULL); + assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); +} +template void InputPort::add_connection(ListNode*>* const c); +template void InputPort::add_connection(ListNode*>* const c); + + +/** Remove a connection. Realtime safe. + */ +template +ListNode*>* +InputPort::remove_connection(const OutputPort* const src_port) +{ + bool modify_buffers = !m_fixed_buffers; + if (modify_buffers && m_is_tied) + modify_buffers = !m_tied_port->fixed_buffers(); + + typedef typename List*>::iterator ConnectionBaseListIterator; + bool found = false; + ListNode*>* connection = NULL; + for (ConnectionBaseListIterator i = m_connections.begin(); i != m_connections.end(); ++i) { + if ((*i)->src_port()->path() == src_port->path()) { + connection = m_connections.remove(i); + found = true; + } + } + + if ( ! found) { + cerr << "WARNING: [InputPort::remove_connection] Connection not found !" << endl; + exit(EXIT_FAILURE); + } else { + if (m_connections.size() == 0) { + for (size_t i=0; i < m_poly; ++i) { + // Use a local buffer + if (modify_buffers && m_buffers.at(i)->is_joined()) + m_buffers.at(i)->unjoin(); + m_buffers.at(i)->clear(); // Write silence + if (m_is_tied) + m_tied_port->buffer(i)->join(m_buffers.at(i)); + } + } else if (modify_buffers && m_connections.size() == 1) { + // Share a buffer + for (size_t i=0; i < m_poly; ++i) { + m_buffers.at(i)->join((*m_connections.begin())->buffer(i)); + if (m_is_tied) + m_tied_port->buffer(i)->join(m_buffers.at(i)); + } + } + } + + if (modify_buffers) + update_buffers(); + + assert( ! m_is_tied || m_tied_port != NULL); + assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + + return connection; +} +template ListNode*>* +InputPort::remove_connection(const OutputPort* const src_port); +template ListNode*>* +InputPort::remove_connection(const OutputPort* const src_port); + + +/** Update any changed buffers with the plugin this is a port on. + * + * This calls ie the LADSPA connect_port function when buffers have been changed + * due to a connection or disconnection. + */ +template +void +InputPort::update_buffers() +{ + for (size_t i=0; i < m_poly; ++i) + InputPort::parent_node()->set_port_buffer(i, m_index, m_buffers.at(i)->data()); +} +template void InputPort::update_buffers(); +template void InputPort::update_buffers(); + + +/** Returns whether this port is connected to the passed port. + */ +template +bool +InputPort::is_connected_to(const OutputPort* const port) const +{ + typedef typename List*>::const_iterator ConnectionBaseListIterator; + for (ConnectionBaseListIterator i = m_connections.begin(); i != m_connections.end(); ++i) + if ((*i)->src_port() == port) + return true; + + return false; +} +template bool InputPort::is_connected_to(const OutputPort* const port) const; +template bool InputPort::is_connected_to(const OutputPort* const port) const; + + +/** "Ties" this port to an OutputPort, so they share the same buffer. + * + * This is used by OutputNode and InputNode to provide two different ports + * (internal and external) that share a buffer. + */ +template +void +InputPort::tie(OutputPort* const port) +{ + assert((Port*)port != (Port*)this); + assert(port->poly() == this->poly()); + assert(!m_is_tied); + assert(m_tied_port == NULL); + + if (Port::parent_node() != NULL) { + assert(m_poly == port->poly()); + + for (size_t i=0; i < m_poly; ++i) + port->buffer(i)->join(m_buffers.at(i)); + } + m_is_tied = true; + m_tied_port = port; + port->set_tied_port(this); + + assert(m_buffers.at(0)->data() == port->buffer(0)->data()); + + //cerr << "*** Tied " << this->path() << " <-> " << port->path() << endl; +} +template void InputPort::tie(OutputPort* const port); +template void InputPort::tie(OutputPort* const port); + + +/** Prepare buffer for access, mixing if necessary. Realtime safe. + * FIXME: nframes parameter not used, + */ +template<> +void +InputPort::prepare_buffers(size_t nframes) +{ + assert(!m_is_tied || m_tied_port != NULL); + + typedef List*>::iterator ConnectionBaseListIterator; + bool do_mixdown = true; + + if (m_connections.size() == 0) return; + + for (ConnectionBaseListIterator c = m_connections.begin(); c != m_connections.end(); ++c) + (*c)->prepare_buffers(); + + // If only one connection, buffer is (maybe) used directly (no copying) + if (m_connections.size() == 1) { + // Buffer changed since connection + if (m_buffers.at(0)->data() != (*m_connections.begin())->buffer(0)->data()) { + if (m_fixed_buffers || (m_is_tied && m_tied_port->fixed_buffers())) { + // can't change buffer, must copy + do_mixdown = true; + } else { + // zero-copy + assert(m_buffers.at(0)->is_joined()); + m_buffers.at(0)->join((*m_connections.begin())->buffer(0)); + do_mixdown = false; + } + } else { + do_mixdown = false; + } + update_buffers(); + } + + if (!do_mixdown) { + assert(m_buffers.at(0)->data() == (*m_connections.begin())->buffer(0)->data()); + return; + } + + assert(!m_is_tied || m_tied_port != NULL); + assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + + for (size_t voice=0; voice < m_poly; ++voice) { + m_buffers.at(voice)->copy((*m_connections.begin())->buffer(voice), 0, m_buffer_size-1); + + if (m_connections.size() > 1) { + // Copy first connection + ConnectionBaseListIterator c = m_connections.begin(); + + // Add all other connections + for (++c; c != m_connections.end(); ++c) + m_buffers.at(voice)->accumulate((*c)->buffer(voice), 0, m_buffer_size-1); + } + } +} + + +/** Prepare buffer for access, realtime safe. + * + * MIDI mixing not yet implemented. + */ +template <> +void +InputPort::prepare_buffers(size_t nframes) +{ + assert(!m_is_tied || m_tied_port != NULL); + + const size_t num_ins = m_connections.size(); + bool do_mixdown = true; + + assert(num_ins == 0 || num_ins == 1); + + typedef List*>::iterator ConnectionBaseListIterator; + assert(m_poly == 1); + + for (ConnectionBaseListIterator c = m_connections.begin(); c != m_connections.end(); ++c) + (*c)->prepare_buffers(); + + + // If only one connection, buffer is used directly (no copying) + if (num_ins == 1) { + // Buffer changed since connection + if (m_buffers.at(0) != (*m_connections.begin())->buffer(0)) { + if (m_fixed_buffers || (m_is_tied && m_tied_port->fixed_buffers())) { + // can't change buffer, must copy + do_mixdown = true; + } else { + // zero-copy + assert(m_buffers.at(0)->is_joined()); + m_buffers.at(0)->join((*m_connections.begin())->buffer(0)); + if (m_is_tied) + m_tied_port->buffer(0)->join(m_buffers.at(0)); + do_mixdown = false; + } + update_buffers(); + } else { + do_mixdown = false; + } + assert(!m_is_tied || m_tied_port != NULL); + assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + assert(!m_is_tied || m_buffers.at(0)->filled_size() == m_tied_port->buffer(0)->filled_size()); + assert(do_mixdown || m_buffers.at(0)->filled_size() == + (*m_connections.begin())->src_port()->buffer(0)->filled_size()); + } + + // Get valid buffer size from inbound connections, unless a port on a top-level + // patch (which will be fed by the MidiDriver) + if (m_parent->parent() != NULL) { + if (num_ins == 1) { + m_buffers.at(0)->filled_size( + (*m_connections.begin())->src_port()->buffer(0)->filled_size()); + + if (m_is_tied) + m_tied_port->buffer(0)->filled_size(m_buffers.at(0)->filled_size()); + + assert(m_buffers.at(0)->filled_size() == + (*m_connections.begin())->src_port()->buffer(0)->filled_size()); + } else { + // Mixing not implemented + m_buffers.at(0)->clear(); + } + } + + assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + + if (!do_mixdown || m_buffers.at(0)->filled_size() == 0 || num_ins == 0) + return; + + //cerr << path() << " - Copying MIDI buffer" << endl; + + // Be sure buffers are the same as tied port's, if joined + assert(!m_is_tied || m_tied_port != NULL); + assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + + if (num_ins > 0) + for (size_t i=0; i < m_buffers.at(0)->filled_size(); ++i) + m_buffers.at(0)[i] = (*m_connections.begin())->buffer(0)[i]; +} + + +} // namespace Om + diff --git a/src/libs/engine/InputPort.h b/src/libs/engine/InputPort.h new file mode 100644 index 00000000..0e5d9d68 --- /dev/null +++ b/src/libs/engine/InputPort.h @@ -0,0 +1,88 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef INPUTPORT_H +#define INPUTPORT_H + +#include +#include +#include +#include "PortBase.h" +#include "List.h" +#include "MidiMessage.h" +using std::string; + +namespace Om { + +template class ConnectionBase; +template class OutputPort; +class Node; + + +/** An input port on a Node or Patch. + * + * All ports have a Buffer, but the actual contents (data) of that buffer may be + * set directly to the incoming connection's buffer if there's only one inbound + * connection, to eliminate the need to copy/mix. + * + * If a port has multiple connections, they will be mixed down into the local + * buffer and it will be used. + * + * \ingroup engine + */ +template +class InputPort : public PortBase +{ +public: + InputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); + virtual ~InputPort() {} + + void add_connection(ListNode*>* const c); + ListNode*>* remove_connection(const OutputPort* const src_port); + + void prepare_buffers(size_t nframes); + + void tie(OutputPort* const port); + + bool is_connected() const { return (m_connections.size() > 0); } + bool is_connected_to(const OutputPort* const port) const; + +private: + // Prevent copies (Undefined) + InputPort(const InputPort& copy); + InputPort& operator=(const InputPort&); + + void update_buffers(); + + List*> m_connections; + + // This is just stupid... + using PortBase::m_is_tied; + using PortBase::m_tied_port; + using PortBase::m_buffers; + using PortBase::m_poly; + using PortBase::m_index; + using PortBase::m_buffer_size; + using PortBase::m_fixed_buffers; +}; + + +template class InputPort; +template class InputPort; + +} // namespace Om + +#endif // INPUTPORT_H diff --git a/src/libs/engine/InternalNode.h b/src/libs/engine/InternalNode.h new file mode 100644 index 00000000..fea2d3ad --- /dev/null +++ b/src/libs/engine/InternalNode.h @@ -0,0 +1,70 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef INTERNALNODE_H +#define INTERNALNODE_H + +#include +#include "NodeBase.h" +#include "Plugin.h" + +namespace Om { + +class Patch; + + +/** Base class for Internal (builtin) nodes + * + * \ingroup engine + */ +class InternalNode : public NodeBase +{ +public: + InternalNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) + : NodeBase(path, poly, parent, srate, buffer_size), + m_is_added(false) + { + m_plugin.lib_path("/Om"); + } + + virtual ~InternalNode() {} + + virtual void deactivate() { if (m_is_added) remove_from_patch(); NodeBase::deactivate(); } + + virtual void run(size_t nframes) { NodeBase::run(nframes); } + + virtual void add_to_patch() { assert(!m_is_added); m_is_added = true; } + virtual void remove_from_patch() { assert(m_is_added); m_is_added = false; } + + //virtual void send_creation_messages(ClientInterface* client) const + //{ NodeBase::send_creation_messages(client); } + + virtual const Plugin* plugin() const { return &m_plugin; } + virtual void plugin(const Plugin* const) { exit(EXIT_FAILURE); } + +protected: + // Disallow copies (undefined) + InternalNode(const InternalNode&); + InternalNode& operator=(const InternalNode&); + + Plugin m_plugin; + bool m_is_added; +}; + + +} // namespace Om + +#endif // INTERNALNODE_H diff --git a/src/libs/engine/JackAudioDriver.cpp b/src/libs/engine/JackAudioDriver.cpp new file mode 100644 index 00000000..0f5e3b1a --- /dev/null +++ b/src/libs/engine/JackAudioDriver.cpp @@ -0,0 +1,373 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "JackAudioDriver.h" +#include "config.h" +#include "tuning.h" +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "util.h" +#include "Event.h" +#include "QueuedEvent.h" +#include "EventSource.h" +#include "PostProcessor.h" +#include "util/Queue.h" +#include "Node.h" +#include "Patch.h" +#include "Port.h" +#include "PortInfo.h" +#include "MidiDriver.h" +#include "List.h" +#include "PortBase.h" +#ifdef HAVE_LASH +#include "LashDriver.h" +#endif + +using std::cout; using std::cerr; using std::endl; + + +namespace Om { + + +//// JackAudioPort //// + +JackAudioPort::JackAudioPort(JackAudioDriver* driver, PortBase* patch_port) +: DriverPort(), + ListNode(this), + m_driver(driver), + m_jack_port(NULL), + m_jack_buffer(NULL), + m_patch_port(patch_port) +{ + assert(patch_port->tied_port() != NULL); + assert(patch_port->poly() == 1); + + m_jack_port = jack_port_register(m_driver->jack_client(), + patch_port->path().c_str(), JACK_DEFAULT_AUDIO_TYPE, + (patch_port->port_info()->is_input()) ? JackPortIsInput : JackPortIsOutput, + 0); + + m_jack_buffer = new DriverBuffer(driver->buffer_size()); + + patch_port->fixed_buffers(true); +} + + +JackAudioPort::~JackAudioPort() +{ + jack_port_unregister(m_driver->jack_client(), m_jack_port); +} + + +void +JackAudioPort::add_to_driver() +{ + m_driver->add_port(this); +} + + +void +JackAudioPort::remove_from_driver() +{ + m_driver->remove_port(this); +} + +void +JackAudioPort::prepare_buffer(jack_nframes_t nframes) +{ + // Technically this doesn't need to be done every time for output ports + m_jack_buffer->set_data((jack_default_audio_sample_t*) + jack_port_get_buffer(m_jack_port, nframes)); + + assert(m_patch_port->tied_port() != NULL); + + // FIXME: fixed_buffers switch on/off thing can be removed once this shit + // gets figured out and assertions can go away + m_patch_port->fixed_buffers(false); + m_patch_port->buffer(0)->join(m_jack_buffer); + m_patch_port->tied_port()->buffer(0)->join(m_jack_buffer); + + m_patch_port->fixed_buffers(true); + + assert(m_patch_port->buffer(0)->data() == m_patch_port->tied_port()->buffer(0)->data()); + assert(m_patch_port->buffer(0)->data() == m_jack_buffer->data()); +} + + +//// JackAudioDriver //// + +JackAudioDriver::JackAudioDriver() +: m_client(NULL), + m_buffer_size(0), + m_sample_rate(0), + m_is_activated(false), + m_local_client(true), + m_root_patch(NULL), + m_start_of_current_cycle(0), + m_start_of_last_cycle(0) +{ + m_client = jack_client_new("Om"); + if (m_client == NULL) { + cerr << "[JackAudioDriver] Unable to connect to Jack. Exiting." << endl; + exit(EXIT_FAILURE); + } + + jack_on_shutdown(m_client, shutdown_cb, this); + + m_buffer_size = jack_get_buffer_size(m_client); + m_sample_rate = jack_get_sample_rate(m_client); + + jack_set_sample_rate_callback(m_client, sample_rate_cb, this); + jack_set_buffer_size_callback(m_client, buffer_size_cb, this); +} + +JackAudioDriver::JackAudioDriver(jack_client_t* jack_client) +: m_client(jack_client), + m_buffer_size(jack_get_buffer_size(jack_client)), + m_sample_rate(jack_get_sample_rate(jack_client)), + m_is_activated(false), + m_local_client(false), + m_start_of_current_cycle(0), + m_start_of_last_cycle(0) +{ + jack_on_shutdown(m_client, shutdown_cb, this); + + jack_set_sample_rate_callback(m_client, sample_rate_cb, this); + jack_set_buffer_size_callback(m_client, buffer_size_cb, this); +} + + +JackAudioDriver::~JackAudioDriver() +{ + deactivate(); + + if (m_local_client) + jack_client_close(m_client); +} + + +void +JackAudioDriver::activate() +{ + if (m_is_activated) { + cerr << "[JackAudioDriver] Jack driver already activated." << endl; + return; + } + + jack_set_process_callback(m_client, process_cb, this); + + m_is_activated = true; + + if (jack_activate(m_client)) { + cerr << "[JackAudioDriver] Could not activate Jack client, aborting." << endl; + exit(EXIT_FAILURE); + } else { + cout << "[JackAudioDriver] Activated Jack client." << endl; +#ifdef HAVE_LASH + lash_driver->set_jack_client_name("Om"); // FIXME: unique name +#endif + } +} + + +void +JackAudioDriver::deactivate() +{ + if (m_is_activated) { + // FIXME + reinterpret_cast(om->osc_receiver())->stop(); + + jack_deactivate(m_client); + m_is_activated = false; + + for (List::iterator i = m_ports.begin(); i != m_ports.end(); ++i) + jack_port_unregister(m_client, (*i)->jack_port()); + + m_ports.clear(); + + cout << "[JackAudioDriver] Deactivated Jack client." << endl; + + om->post_processor()->stop(); + } +} + + +/** Add a Jack port. + * + * Realtime safe, this is to be called at the beginning of a process cycle to + * insert (and actually begin using) a new port. + * + * See create_port() and remove_port(). + */ +void +JackAudioDriver::add_port(JackAudioPort* port) +{ + m_ports.push_back(port); +} + + +/** Remove a Jack port. + * + * Realtime safe. This is to be called at the beginning of a process cycle to + * remove the port from the lists read by the audio thread, so the port + * will no longer be used and can be removed afterwards. + * + * It is the callers responsibility to delete the returned port. + */ +JackAudioPort* +JackAudioDriver::remove_port(JackAudioPort* port) +{ + for (List::iterator i = m_ports.begin(); i != m_ports.end(); ++i) + if ((*i) == port) + return m_ports.remove(i)->elem(); + + cerr << "[JackAudioDriver::remove_port] WARNING: Failed to find Jack port to remove!" << endl; + return NULL; +} + + +DriverPort* +JackAudioDriver::create_port(PortBase* patch_port) +{ + if (patch_port->buffer_size() == m_buffer_size) + return new JackAudioPort(this, patch_port); + else + return NULL; +} + + +/** Process all the pending events for this cycle. + * + * Called from the realtime thread once every process cycle. + */ +void +JackAudioDriver::process_events(jack_nframes_t block_start, jack_nframes_t block_end) +{ + Event* ev = NULL; + + /* Limit the maximum number of queued events to process per cycle. This + * makes the process callback truly realtime-safe by preventing being + * choked by events coming in faster than they can be processed. + * FIXME: run the math on this and figure out a good value */ + const int MAX_SLOW_EVENTS = m_buffer_size / 100; + + int num_events_processed = 0; + int offset = 0; + + // Process the "slow" events first, because it's possible some of the + // RT events depend on them + + // FIXME + while ((ev = reinterpret_cast(om->osc_receiver()) + ->pop_earliest_event_before(block_end)) != NULL) { + ev->execute(0); // QueuedEvents are not sample accurate + om->post_processor()->push(ev); + if (++num_events_processed > MAX_SLOW_EVENTS) + break; + } + + while (!om->event_queue()->is_empty() + && om->event_queue()->front()->time_stamp() < block_end) { + ev = om->event_queue()->pop(); + offset = ev->time_stamp() - block_start; + if (offset < 0) offset = 0; // this can happen if we miss a cycle + ev->execute(offset); + om->post_processor()->push(ev); + ++num_events_processed; + } + + if (num_events_processed > 0) + om->post_processor()->signal(); +} + + + +/**** Jack Callbacks ****/ + + + +/** Jack process callback, drives entire audio thread. + * + * \callgraph + */ +int +JackAudioDriver::m_process_cb(jack_nframes_t nframes) +{ + // FIXME: support nframes != buffer_size, even though that never damn well happens + assert(nframes == m_buffer_size); + + // Note that jack can elect to not call this function for a cycle, if things aren't + // keeping up + m_start_of_current_cycle = jack_last_frame_time(m_client); + m_start_of_last_cycle = m_start_of_current_cycle - nframes; + + assert(m_start_of_current_cycle - m_start_of_last_cycle == nframes); + + m_transport_state = jack_transport_query(m_client, &m_position); + + process_events(m_start_of_last_cycle, m_start_of_current_cycle); + om->midi_driver()->prepare_block(m_start_of_last_cycle, m_start_of_current_cycle); + + // Set buffers of patch ports to Jack port buffers (zero-copy processing) + for (List::iterator i = m_ports.begin(); i != m_ports.end(); ++i) + (*i)->prepare_buffer(nframes); + + // Run root patch + assert(m_root_patch != NULL); + m_root_patch->run(nframes); + + return 0; +} + + +void +JackAudioDriver::m_shutdown_cb() +{ + cout << "[JackAudioDriver] Jack shutdown. Exiting." << endl; + om->quit(); +} + + +int +JackAudioDriver::m_sample_rate_cb(jack_nframes_t nframes) +{ + if (m_is_activated) { + cerr << "[JackAudioDriver] Om does not support changing sample rate on the fly (yet). Aborting." << endl; + exit(EXIT_FAILURE); + } else { + m_sample_rate = nframes; + } + return 0; +} + + +int +JackAudioDriver::m_buffer_size_cb(jack_nframes_t nframes) +{ + if (m_is_activated) { + cerr << "[JackAudioDriver] Om does not support chanding buffer size on the fly (yet). Aborting." << endl; + exit(EXIT_FAILURE); + } else { + m_buffer_size = nframes; + } + return 0; +} + + +} // namespace Om + diff --git a/src/libs/engine/JackAudioDriver.h b/src/libs/engine/JackAudioDriver.h new file mode 100644 index 00000000..c55d392f --- /dev/null +++ b/src/libs/engine/JackAudioDriver.h @@ -0,0 +1,176 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef JACKAUDIODRIVER_H +#define JACKAUDIODRIVER_H + +#include +#include +#include "List.h" +#include "AudioDriver.h" +#include "Buffer.h" + +namespace Om { + +class Patch; +class Port; +template class PortBase; +class JackAudioDriver; +typedef jack_default_audio_sample_t jack_sample_t; + + +/** Used internally by JackAudioDriver to represent a Jack port. + * + * A Jack port always has a one-to-one association with a Patch port. + */ +class JackAudioPort : public DriverPort, public ListNode +{ +public: + JackAudioPort(JackAudioDriver* driver, PortBase* patch_port); + ~JackAudioPort(); + + void add_to_driver(); + void remove_from_driver(); + void set_name(const string& name) { jack_port_set_name(m_jack_port, name.c_str()); }; + + void prepare_buffer(jack_nframes_t nframes); + + jack_port_t* jack_port() const { return m_jack_port; } + DriverBuffer* buffer() const { return m_jack_buffer; } + void jack_buffer(jack_sample_t* s) { m_jack_buffer->set_data(s); } + PortBase* patch_port() const { return m_patch_port; } + +private: + // Prevent copies (undefined) + JackAudioPort(const JackAudioPort&); + JackAudioPort& operator=(const JackAudioPort&); + + JackAudioDriver* m_driver; + jack_port_t* m_jack_port; + DriverBuffer* m_jack_buffer; + PortBase* m_patch_port; +}; + + + +/** The Jack AudioDriver. + * + * The process callback here drives the entire audio thread by "pulling" + * events from queues, processing them, running the patches, and passing + * events along to the PostProcessor. + * + * \ingroup engine + */ +class JackAudioDriver : public AudioDriver +{ +public: + JackAudioDriver(); + JackAudioDriver(jack_client_t *jack_client); + ~JackAudioDriver(); + + void activate(); + void deactivate(); + void enable(); + void disable(); + + void process_events(jack_nframes_t block_start, jack_nframes_t block_end); + + DriverPort* create_port(PortBase* patch_port); + + Patch* root_patch() { return m_root_patch; } + void set_root_patch(Patch* patch) { m_root_patch = patch; } + + /** Transport state for this frame. + * Intended to only be called from the audio thread. */ + inline const jack_position_t* position() { return &m_position; } + inline const jack_transport_state_t transport_state() { return m_transport_state; } + + bool is_realtime() { return jack_is_realtime(m_client); } + + jack_client_t* jack_client() const { return m_client; } + samplecount buffer_size() const { return m_buffer_size; } + samplecount sample_rate() const { return m_sample_rate; } + bool is_activated() const { return m_is_activated; } + + samplecount time_stamp() const { return jack_frame_time(m_client); } + +private: + // Prevent copies (undefined) + JackAudioDriver(const JackAudioDriver&); + JackAudioDriver& operator=(const JackAudioDriver&); + + friend class JackAudioPort; + + // Functions for JackAudioPort + void add_port(JackAudioPort* port); + JackAudioPort* remove_port(JackAudioPort* port); + + // These are the static versions of the callbacks, they call + // the non-static ones below + inline static int process_cb(jack_nframes_t nframes, void* const jack_driver); + inline static void shutdown_cb(void* const jack_driver); + inline static int buffer_size_cb(jack_nframes_t nframes, void* const jack_driver); + inline static int sample_rate_cb(jack_nframes_t nframes, void* const jack_driver); + + // Non static callbacks + int m_process_cb(jack_nframes_t nframes); + void m_shutdown_cb(); + int m_buffer_size_cb(jack_nframes_t nframes); + int m_sample_rate_cb(jack_nframes_t nframes); + + jack_client_t* m_client; + jack_nframes_t m_buffer_size; + jack_nframes_t m_sample_rate; + bool m_is_activated; + bool m_local_client; ///< Whether m_client should be closed on destruction + jack_position_t m_position; + jack_transport_state_t m_transport_state; + + List m_ports; + + Patch* m_root_patch; + + jack_nframes_t m_start_of_current_cycle; + jack_nframes_t m_start_of_last_cycle; +}; + + +inline int JackAudioDriver::process_cb(jack_nframes_t nframes, void* jack_driver) +{ + return ((JackAudioDriver*)jack_driver)->m_process_cb(nframes); +} + +inline void JackAudioDriver::shutdown_cb(void* jack_driver) +{ + return ((JackAudioDriver*)jack_driver)->m_shutdown_cb(); +} + + +inline int JackAudioDriver::buffer_size_cb(jack_nframes_t nframes, void* jack_driver) +{ + return ((JackAudioDriver*)jack_driver)->m_buffer_size_cb(nframes); +} + + +inline int JackAudioDriver::sample_rate_cb(jack_nframes_t nframes, void* jack_driver) +{ + return ((JackAudioDriver*)jack_driver)->m_sample_rate_cb(nframes); +} + + +} // namespace Om + +#endif // JACKAUDIODRIVER_H diff --git a/src/libs/engine/JackMidiDriver.cpp b/src/libs/engine/JackMidiDriver.cpp new file mode 100644 index 00000000..40054b8a --- /dev/null +++ b/src/libs/engine/JackMidiDriver.cpp @@ -0,0 +1,217 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "JackMidiDriver.h" +#include +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "util/types.h" +#include "midi.h" +#include "OmApp.h" +#include "Maid.h" +#include "AudioDriver.h" +#include "MidiInputNode.h" +#include "PortInfo.h" +#include "MidiMessage.h" +#include "PortBase.h" +#ifdef HAVE_LASH +#include "LashDriver.h" +#endif +using std::cout; using std::cerr; using std::endl; + +namespace Om { + + +//// JackMidiPort //// + +JackMidiPort::JackMidiPort(JackMidiDriver* driver, PortBase* patch_port) +: DriverPort(), + ListNode(this), + m_driver(driver), + m_jack_port(NULL), + m_patch_port(patch_port) +{ + assert(patch_port->poly() == 1); + + m_jack_port = jack_port_register(m_driver->jack_client(), + patch_port->path().c_str(), JACK_DEFAULT_MIDI_TYPE, + (patch_port->port_info()->is_input()) ? JackPortIsInput : JackPortIsOutput, + 0); + + patch_port->buffer(0)->clear(); + patch_port->fixed_buffers(true); +} + + +JackMidiPort::~JackMidiPort() +{ + jack_port_unregister(m_driver->jack_client(), m_jack_port); +} + + +void +JackMidiPort::add_to_driver() +{ + m_driver->add_port(this); +} + + +void +JackMidiPort::remove_from_driver() +{ + m_driver->remove_port(this); +} + + +/** Prepare events for a block. + * + * This is basically trivial (as opposed to AlsaMidiPort) since Jack MIDI + * data is in-band with the audio thread. + * + * Prepares all events that occurred during the time interval passed + * (which ideally are the events from the previous cycle with an exact + * 1 cycle delay). + */ +void +JackMidiPort::prepare_block(const samplecount block_start, const samplecount block_end) +{ + assert(block_end >= block_start); + + const samplecount nframes = block_end - block_start; + void* jack_buffer = jack_port_get_buffer(m_jack_port, nframes); + const jack_nframes_t event_count = jack_midi_port_get_info(jack_buffer, nframes)->event_count; + + assert(event_count < m_patch_port->buffer_size()); + + // Copy events from Jack port buffer into patch port buffer + for (jack_nframes_t i=0; i < event_count; ++i) { + jack_midi_event_t* ev = (jack_midi_event_t*)&m_patch_port->buffer(0)->value_at(i); + jack_midi_event_get(ev, jack_buffer, i, nframes); + + // Convert note ons with velocity 0 to proper note offs + if (ev->buffer[0] == MIDI_CMD_NOTE_ON && ev->buffer[2] == 0) + ev->buffer[0] = MIDI_CMD_NOTE_OFF; + + // MidiMessage and jack_midi_event_t* are the same thing :/ + MidiMessage* const message = &m_patch_port->buffer(0)->data()[i]; + message->time = ev->time; + message->size = ev->size; + message->buffer = ev->buffer; + } + + //cerr << "Jack MIDI got " << event_count << " events." << endl; + + m_patch_port->buffer(0)->filled_size(event_count); + m_patch_port->tied_port()->buffer(0)->filled_size(event_count); +} + + + +//// JackMidiDriver //// + + +bool JackMidiDriver::m_midi_thread_exit_flag = true; + + +JackMidiDriver::JackMidiDriver(jack_client_t* client) +: m_client(client), + m_is_activated(false), + m_is_enabled(false) +{ +} + + +JackMidiDriver::~JackMidiDriver() +{ + deactivate(); +} + + +/** Launch and start the MIDI thread. + */ +void +JackMidiDriver::activate() +{ + m_is_activated = true; +} + + +/** Terminate the MIDI thread. + */ +void +JackMidiDriver::deactivate() +{ + m_is_activated = false; +} + + +/** Build flat arrays of events for DSSI plugins for each Port. + */ +void +JackMidiDriver::prepare_block(const samplecount block_start, const samplecount block_end) +{ + for (List::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i) + (*i)->prepare_block(block_start, block_end); +} + + +/** Add an Jack MIDI port. + * + * Realtime safe, this is to be called at the beginning of a process cycle to + * insert (and actually begin using) a new port. + * + * See create_port() and remove_port(). + */ +void +JackMidiDriver::add_port(JackMidiPort* port) +{ + if (port->patch_port()->port_info()->is_input()) + m_in_ports.push_back(port); + else + m_out_ports.push_back(port); +} + + +/** Remove an Jack MIDI port. + * + * Realtime safe. This is to be called at the beginning of a process cycle to + * remove the port from the lists read by the audio thread, so the port + * will no longer be used and can be removed afterwards. + * + * It is the callers responsibility to delete the returned port. + */ +JackMidiPort* +JackMidiDriver::remove_port(JackMidiPort* port) +{ + if (port->patch_port()->port_info()->is_input()) { + for (List::iterator i = m_in_ports.begin(); i != m_in_ports.end(); ++i) + if ((*i) == (JackMidiPort*)port) + return m_in_ports.remove(i)->elem(); + } else { + for (List::iterator i = m_out_ports.begin(); i != m_out_ports.end(); ++i) + if ((*i) == port) + return m_out_ports.remove(i)->elem(); + } + + cerr << "[JackMidiDriver::remove_input] WARNING: Failed to find Jack port to remove!" << endl; + return NULL; +} + + +} // namespace Om + diff --git a/src/libs/engine/JackMidiDriver.h b/src/libs/engine/JackMidiDriver.h new file mode 100644 index 00000000..950d382f --- /dev/null +++ b/src/libs/engine/JackMidiDriver.h @@ -0,0 +1,123 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef JACKMIDIDRIVER_H +#define JACKMIDIDRIVER_H + +#include +#include +#include "config.h" +#include "List.h" +#include "util/Queue.h" +#include "MidiDriver.h" + +namespace Om { + +class Node; +class SetPortValueEvent; +class JackMidiDriver; +template class PortBase; + + +/** Representation of an JACK MIDI port. + * + * \ingroup engine + */ +class JackMidiPort : public DriverPort, public ListNode +{ +public: + JackMidiPort(JackMidiDriver* driver, PortBase* port); + virtual ~JackMidiPort(); + + void prepare_block(const samplecount block_start, const samplecount block_end); + + void add_to_driver(); + void remove_from_driver(); + void set_name(const string& name) { jack_port_set_name(m_jack_port, name.c_str()); }; + + PortBase* patch_port() const { return m_patch_port; } + +private: + // Prevent copies (undefined) + JackMidiPort(const JackMidiPort&); + JackMidiPort& operator=(const JackMidiPort&); + + JackMidiDriver* m_driver; + jack_port_t* m_jack_port; + PortBase* m_patch_port; +}; + + +/** Jack MIDI driver. + * + * This driver reads Jack MIDI events and dispatches them to the appropriate + * JackMidiPort for processing. + * + * \ingroup engine + */ +class JackMidiDriver : public MidiDriver +{ +public: + JackMidiDriver(jack_client_t* client); + ~JackMidiDriver(); + + void activate(); + void deactivate(); + void enable() { m_is_enabled = true; } + void disable() { m_is_enabled = false; } + + bool is_activated() const { return m_is_activated; } + bool is_enabled() const { return m_is_enabled; } + + void prepare_block(const samplecount block_start, const samplecount block_end); + + JackMidiPort* create_port(PortBase* patch_port) + { return new JackMidiPort(this, patch_port); } + + jack_client_t* jack_client() { return m_client; } + +private: + // Prevent copies (undefined) + JackMidiDriver(const JackMidiDriver&); + JackMidiDriver& operator=(const JackMidiDriver&); + + List m_in_ports; + List m_out_ports; + + friend class JackMidiPort; + + // Functions for JackMidiPort + void add_port(JackMidiPort* port); + JackMidiPort* remove_port(JackMidiPort* port); + + void add_output(ListNode* port); + ListNode* remove_output(JackMidiPort* port); + + // MIDI thread + static void* process_midi_in(void* me); + + jack_client_t* m_client; + pthread_t m_process_thread; + bool m_is_activated; + bool m_is_enabled; + static bool m_midi_thread_exit_flag; +}; + + +} // namespace Om + + +#endif // JACKMIDIDRIVER_H diff --git a/src/libs/engine/LADSPAPlugin.cpp b/src/libs/engine/LADSPAPlugin.cpp new file mode 100644 index 00000000..ddeb0be4 --- /dev/null +++ b/src/libs/engine/LADSPAPlugin.cpp @@ -0,0 +1,274 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "LADSPAPlugin.h" +#include +#include +#include "float.h" +#include +#include +#include "InputPort.h" +#include "OutputPort.h" +#include "PortInfo.h" +#include "Plugin.h" + +namespace Om { + + +/** Partially construct a LADSPAPlugin. + * + * Object is not usable until instantiate() is called with success. + * (It _will_ crash!) + */ +LADSPAPlugin::LADSPAPlugin(const string& path, size_t poly, Patch* parent, const LADSPA_Descriptor* descriptor, samplerate srate, size_t buffer_size) +: NodeBase(path, poly, parent, srate, buffer_size), + m_descriptor(descriptor), + m_instances(NULL) +{ + assert(m_descriptor != NULL); + + // Note that this may be changed by an overriding DSSIPlugin + // ie do not assume m_ports is all LADSPA plugin ports + m_num_ports = m_descriptor->PortCount; +} + + +/** Instantiate self from LADSPA plugin descriptor. + * + * Implemented as a seperate function (rather than in the constructor) to + * allow graceful error-catching of broken plugins. + * + * Returns whether or not plugin was successfully instantiated. If return + * value is false, this object may not be used. + */ +bool +LADSPAPlugin::instantiate() +{ + m_ports.alloc(m_num_ports); + + m_instances = new LADSPA_Handle[m_poly]; + + size_t port_buffer_size = 0; + + for (size_t i=0; i < m_poly; ++i) { + m_instances[i] = m_descriptor->instantiate(m_descriptor, m_srate); + if (m_instances[i] == NULL) { + cerr << "Failed to instantiate plugin!" << endl; + return false; + } + } + + string port_name; + string port_path; + + Port* port = NULL; + + for (size_t j=0; j < m_descriptor->PortCount; ++j) { + port_name = m_descriptor->PortNames[j]; + string::size_type slash_index; + + // Name mangling, to guarantee port names are unique + for (size_t k=0; k < m_descriptor->PortCount; ++k) { + assert(m_descriptor->PortNames[k] != NULL); + if (k != j && port_name == m_descriptor->PortNames[k]) { // clash + if (LADSPA_IS_PORT_CONTROL(m_descriptor->PortDescriptors[j])) + port_name += " (CR)"; + else + port_name += " (AR)"; + } + // Replace all slashes with "-" (so they don't screw up paths) + while ((slash_index = port_name.find("/")) != string::npos) + port_name[slash_index] = '-'; + } + + port_path = path() + "/" + port_name; + + if (LADSPA_IS_PORT_CONTROL(m_descriptor->PortDescriptors[j])) + port_buffer_size = 1; + else if (LADSPA_IS_PORT_AUDIO(m_descriptor->PortDescriptors[j])) + port_buffer_size = m_buffer_size; + + assert (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[j]) + || LADSPA_IS_PORT_OUTPUT(m_descriptor->PortDescriptors[j])); + + if (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[j])) { + port = new InputPort(this, port_name, j, m_poly, + new PortInfo(port_path, m_descriptor->PortDescriptors[j], + m_descriptor->PortRangeHints[j].HintDescriptor), port_buffer_size); + m_ports.at(j) = port; + } else if (LADSPA_IS_PORT_OUTPUT(m_descriptor->PortDescriptors[j])) { + port = new OutputPort(this, port_name, j, m_poly, + new PortInfo(port_path, m_descriptor->PortDescriptors[j], + m_descriptor->PortRangeHints[j].HintDescriptor), port_buffer_size); + m_ports.at(j) = port; + } + + assert(m_ports.at(j) != NULL); + + PortInfo* pi = port->port_info(); + get_port_vals(j, pi); + + // Set default control val + if (pi->is_control()) + ((PortBase*)port)->set_value(pi->default_val(), 0); + else + ((PortBase*)port)->set_value(0.0f, 0); + } + + return true; +} + + +LADSPAPlugin::~LADSPAPlugin() +{ + for (size_t i=0; i < m_poly; ++i) + m_descriptor->cleanup(m_instances[i]); + + delete[] m_instances; +} + + +void +LADSPAPlugin::activate() +{ + NodeBase::activate(); + + PortBase* port = NULL; + + for (size_t i=0; i < m_poly; ++i) { + for (unsigned long j=0; j < m_descriptor->PortCount; ++j) { + port = static_cast*>(m_ports.at(j)); + set_port_buffer(i, j, ((PortBase*)m_ports.at(j))->buffer(i)->data()); + if (port->port_info()->is_control()) + port->set_value(port->port_info()->default_val(), 0); + else if (port->port_info()->is_audio()) + port->set_value(0.0f, 0); + } + if (m_descriptor->activate != NULL) + m_descriptor->activate(m_instances[i]); + } +} + + +void +LADSPAPlugin::deactivate() +{ + NodeBase::deactivate(); + + for (size_t i=0; i < m_poly; ++i) + if (m_descriptor->deactivate != NULL) + m_descriptor->deactivate(m_instances[i]); +} + + +void +LADSPAPlugin::run(size_t nframes) +{ + NodeBase::run(nframes); // mixes down input ports + for (size_t i=0; i < m_poly; ++i) + m_descriptor->run(m_instances[i], nframes); +} + + +void +LADSPAPlugin::set_port_buffer(size_t voice, size_t port_num, void* buf) +{ + assert(voice < m_poly); + + // Could be a MIDI port after this + if (port_num < m_descriptor->PortCount) { + m_descriptor->connect_port(m_instances[voice], port_num, (sample*)buf); + } +} + + +// Based on code stolen from jack-rack +void +LADSPAPlugin::get_port_vals(ulong port_index, PortInfo* info) +{ + LADSPA_Data upper = 0.0f; + LADSPA_Data lower = 0.0f; + LADSPA_Data normal = 0.0f; + LADSPA_PortRangeHintDescriptor hint_descriptor = m_descriptor->PortRangeHints[port_index].HintDescriptor; + + /* set upper and lower, possibly adjusted to the sample rate */ + if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) { + upper = m_descriptor->PortRangeHints[port_index].UpperBound * m_srate; + lower = m_descriptor->PortRangeHints[port_index].LowerBound * m_srate; + } else { + upper = m_descriptor->PortRangeHints[port_index].UpperBound; + lower = m_descriptor->PortRangeHints[port_index].LowerBound; + } + + if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { + /* FLT_EPSILON is defined as the different between 1.0 and the minimum + * float greater than 1.0. So, if lower is < FLT_EPSILON, it will be 1.0 + * and the logarithmic control will have a base of 1 and thus not change + */ + if (lower < FLT_EPSILON) lower = FLT_EPSILON; + } + + + if (LADSPA_IS_HINT_HAS_DEFAULT(hint_descriptor)) { + + if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint_descriptor)) { + normal = lower; + } else if (LADSPA_IS_HINT_DEFAULT_LOW(hint_descriptor)) { + if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { + normal = exp(log(lower) * 0.75 + log(upper) * 0.25); + } else { + normal = lower * 0.75 + upper * 0.25; + } + } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint_descriptor)) { + if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { + normal = exp(log(lower) * 0.5 + log(upper) * 0.5); + } else { + normal = lower * 0.5 + upper * 0.5; + } + } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint_descriptor)) { + if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { + normal = exp(log(lower) * 0.25 + log(upper) * 0.75); + } else { + normal = lower * 0.25 + upper * 0.75; + } + } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint_descriptor)) { + normal = upper; + } else if (LADSPA_IS_HINT_DEFAULT_0(hint_descriptor)) { + normal = 0.0; + } else if (LADSPA_IS_HINT_DEFAULT_1(hint_descriptor)) { + normal = 1.0; + } else if (LADSPA_IS_HINT_DEFAULT_100(hint_descriptor)) { + normal = 100.0; + } else if (LADSPA_IS_HINT_DEFAULT_440(hint_descriptor)) { + normal = 440.0; + } + } else { // No default hint + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint_descriptor)) { + normal = lower; + } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) { + normal = upper; + } + } + + info->min_val(lower); + info->default_val(normal); + info->max_val(upper); +} + + +} // namespace Om + diff --git a/src/libs/engine/LADSPAPlugin.h b/src/libs/engine/LADSPAPlugin.h new file mode 100644 index 00000000..dc1ba5e1 --- /dev/null +++ b/src/libs/engine/LADSPAPlugin.h @@ -0,0 +1,69 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LADSPAPLUGIN_H +#define LADSPAPLUGIN_H + +#include +#include +#include "util/types.h" +#include "NodeBase.h" +#include "Plugin.h" + +namespace Om { + +class PortInfo; + + +/** An instance of a LADSPA plugin. + * + * \ingroup engine + */ +class LADSPAPlugin : public NodeBase +{ +public: + LADSPAPlugin(const string& name, size_t poly, Patch* parent, const LADSPA_Descriptor* descriptor, samplerate srate, size_t buffer_size); + virtual ~LADSPAPlugin(); + + virtual bool instantiate(); + + void activate(); + void deactivate(); + + void run(size_t nframes); + + void set_port_buffer(size_t voice, size_t port_num, void* buf); + + const Plugin* plugin() const { return m_plugin; } + void plugin(const Plugin* const pi) { m_plugin = pi; } + +protected: + // Prevent copies (undefined) + LADSPAPlugin(const LADSPAPlugin& copy); + LADSPAPlugin& operator=(const LADSPAPlugin&); + + void get_port_vals(ulong port_index, PortInfo* info); + + const LADSPA_Descriptor* m_descriptor; + LADSPA_Handle* m_instances; + + const Plugin* m_plugin; +}; + + +} // namespace Om + +#endif // LADSPAPLUGIN_H diff --git a/src/libs/engine/LV2Plugin.cpp b/src/libs/engine/LV2Plugin.cpp new file mode 100644 index 00000000..1c74bca9 --- /dev/null +++ b/src/libs/engine/LV2Plugin.cpp @@ -0,0 +1,275 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "LV2Plugin.h" +#include +#include +#include "float.h" +#include +#include +#include "InputPort.h" +#include "OutputPort.h" +#include "PortInfo.h" +#include "Plugin.h" + +namespace Om { + + +/** Partially construct a LV2Plugin. + * + * Object is not usable until instantiate() is called with success. + * (It _will_ crash!) + */ +LV2Plugin::LV2Plugin(const string& name, + size_t poly, + Patch* parent, + const SLV2Plugin* plugin, + samplerate srate, + size_t buffer_size) +: NodeBase(name, poly, parent, srate, buffer_size), + m_lv2_plugin(plugin), + m_instances(NULL) +{ + assert(m_lv2_plugin); + + // Note that this may be changed by an overriding DSSIPlugin + // ie do not assume m_ports is all LV2 plugin ports + m_num_ports = slv2_plugin_get_num_ports(m_lv2_plugin); +} + + +/** Instantiate self from LV2 plugin descriptor. + * + * Implemented as a seperate function (rather than in the constructor) to + * allow graceful error-catching of broken plugins. + * + * Returns whether or not plugin was successfully instantiated. If return + * value is false, this object may not be used. + */ +bool +LV2Plugin::instantiate() +{ + m_ports.alloc(m_num_ports); + + m_instances = new SLV2Instance*[m_poly]; + + size_t port_buffer_size = 0; + + for (size_t i=0; i < m_poly; ++i) { + m_instances[i] = slv2_plugin_instantiate(m_lv2_plugin, m_srate, NULL); + if (m_instances[i] == NULL) { + cerr << "Failed to instantiate plugin!" << endl; + return false; + } + } + + string port_name; + string port_path; + + Port* port = NULL; + + for (size_t j=0; j < m_num_ports; ++j) { + // LV2 shortnames are guaranteed to be unique + port_name = (char*)slv2_port_get_symbol(m_lv2_plugin, j); + + string::size_type slash_index; + + // Replace all slashes with "-" (so they don't screw up paths) + while ((slash_index = port_name.find("/")) != string::npos) + port_name[slash_index] = '-'; + + port_path = path() + "/" + port_name; + + // Assumes there is only the 4 classes + + SLV2PortClass port_class = slv2_port_get_class(m_lv2_plugin, j); + const bool is_control = (port_class == SLV2_CONTROL_RATE_INPUT + || port_class == SLV2_CONTROL_RATE_OUTPUT); + const bool is_input = (port_class == SLV2_CONTROL_RATE_INPUT + || port_class == SLV2_AUDIO_RATE_INPUT); + + if (is_control) + port_buffer_size = 1; + else + port_buffer_size = m_buffer_size; + + PortType type = is_control ? CONTROL : AUDIO; + PortDirection direction = is_input ? INPUT : OUTPUT; + + if (is_input) { + port = new InputPort(this, port_name, j, m_poly, + new PortInfo(port_path, type, direction), port_buffer_size); + m_ports.at(j) = port; + } else /* output */ { + port = new OutputPort(this, port_name, j, m_poly, + new PortInfo(port_path, type, direction), port_buffer_size); + m_ports.at(j) = port; + } + + assert(m_ports.at(j) != NULL); + + PortInfo* pi = port->port_info(); + get_port_vals(j, pi); + + // Set default control val + if (pi->is_control()) + ((PortBase*)port)->set_value(pi->default_val(), 0); + else + ((PortBase*)port)->set_value(0.0f, 0); + } + return true; +} + + +LV2Plugin::~LV2Plugin() +{ + for (size_t i=0; i < m_poly; ++i) + slv2_instance_free(m_instances[i]); + + delete[] m_instances; +} + + +void +LV2Plugin::activate() +{ + NodeBase::activate(); + + PortBase* port = NULL; + + for (size_t i=0; i < m_poly; ++i) { + for (unsigned long j=0; j < m_num_ports; ++j) { + port = static_cast*>(m_ports.at(j)); + set_port_buffer(i, j, ((PortBase*)m_ports.at(j))->buffer(i)->data()); + if (port->port_info()->is_control()) + port->set_value(port->port_info()->default_val(), 0); + else if (port->port_info()->is_audio()) + port->set_value(0.0f, 0); + } + slv2_instance_activate(m_instances[i]); + } +} + + +void +LV2Plugin::deactivate() +{ + NodeBase::deactivate(); + + for (size_t i=0; i < m_poly; ++i) + slv2_instance_deactivate(m_instances[i]); +} + + +void +LV2Plugin::run(size_t nframes) +{ + NodeBase::run(nframes); // mixes down input ports + for (size_t i=0; i < m_poly; ++i) + slv2_instance_run(m_instances[i], nframes); +} + + +void +LV2Plugin::set_port_buffer(size_t voice, size_t port_num, void* buf) +{ + assert(voice < m_poly); + + // Could be a MIDI port after this + if (port_num < m_num_ports) { + slv2_instance_connect_port(m_instances[voice], port_num, buf); + } +} + + +// Based on code stolen from jack-rack +void +LV2Plugin::get_port_vals(ulong port_index, PortInfo* info) +{ +#if 0 + LV2_Data upper = 0.0f; + LV2_Data lower = 0.0f; + LV2_Data normal = 0.0f; + LV2_PortRangeHintDescriptor hint_descriptor = m_descriptor->PortRangeHints[port_index].HintDescriptor; + + /* set upper and lower, possibly adjusted to the sample rate */ + if (LV2_IS_HINT_SAMPLE_RATE(hint_descriptor)) { + upper = m_descriptor->PortRangeHints[port_index].UpperBound * m_srate; + lower = m_descriptor->PortRangeHints[port_index].LowerBound * m_srate; + } else { + upper = m_descriptor->PortRangeHints[port_index].UpperBound; + lower = m_descriptor->PortRangeHints[port_index].LowerBound; + } + + if (LV2_IS_HINT_LOGARITHMIC(hint_descriptor)) { + /* FLT_EPSILON is defined as the different between 1.0 and the minimum + * float greater than 1.0. So, if lower is < FLT_EPSILON, it will be 1.0 + * and the logarithmic control will have a base of 1 and thus not change + */ + if (lower < FLT_EPSILON) lower = FLT_EPSILON; + } + + + if (LV2_IS_HINT_HAS_DEFAULT(hint_descriptor)) { + + if (LV2_IS_HINT_DEFAULT_MINIMUM(hint_descriptor)) { + normal = lower; + } else if (LV2_IS_HINT_DEFAULT_LOW(hint_descriptor)) { + if (LV2_IS_HINT_LOGARITHMIC(hint_descriptor)) { + normal = exp(log(lower) * 0.75 + log(upper) * 0.25); + } else { + normal = lower * 0.75 + upper * 0.25; + } + } else if (LV2_IS_HINT_DEFAULT_MIDDLE(hint_descriptor)) { + if (LV2_IS_HINT_LOGARITHMIC(hint_descriptor)) { + normal = exp(log(lower) * 0.5 + log(upper) * 0.5); + } else { + normal = lower * 0.5 + upper * 0.5; + } + } else if (LV2_IS_HINT_DEFAULT_HIGH(hint_descriptor)) { + if (LV2_IS_HINT_LOGARITHMIC(hint_descriptor)) { + normal = exp(log(lower) * 0.25 + log(upper) * 0.75); + } else { + normal = lower * 0.25 + upper * 0.75; + } + } else if (LV2_IS_HINT_DEFAULT_MAXIMUM(hint_descriptor)) { + normal = upper; + } else if (LV2_IS_HINT_DEFAULT_0(hint_descriptor)) { + normal = 0.0; + } else if (LV2_IS_HINT_DEFAULT_1(hint_descriptor)) { + normal = 1.0; + } else if (LV2_IS_HINT_DEFAULT_100(hint_descriptor)) { + normal = 100.0; + } else if (LV2_IS_HINT_DEFAULT_440(hint_descriptor)) { + normal = 440.0; + } + } else { // No default hint + if (LV2_IS_HINT_BOUNDED_BELOW(hint_descriptor)) { + normal = lower; + } else if (LV2_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) { + normal = upper; + } + } + + info->min_val(lower); + info->default_val(normal); + info->max_val(upper); +#endif +} + + +} // namespace Om + diff --git a/src/libs/engine/LV2Plugin.h b/src/libs/engine/LV2Plugin.h new file mode 100644 index 00000000..c3d3038a --- /dev/null +++ b/src/libs/engine/LV2Plugin.h @@ -0,0 +1,76 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LV2PLUGIN_H +#define LV2PLUGIN_H + +#include +#include +#include "util/types.h" +#include "NodeBase.h" +#include "Plugin.h" + +namespace Om { + +class PortInfo; + + +/** An instance of a LV2 plugin. + * + * \ingroup engine + */ +class LV2Plugin : public NodeBase +{ +public: + LV2Plugin(const string& name, + size_t poly, + Patch* parent, + const SLV2Plugin* plugin, + samplerate srate, + size_t buffer_size); + + virtual ~LV2Plugin(); + + virtual bool instantiate(); + + void activate(); + void deactivate(); + + void run(size_t nframes); + + void set_port_buffer(size_t voice, size_t port_num, void* buf); + + const Plugin* plugin() const { return m_om_plugin; } + void plugin(const Plugin* const p) { m_om_plugin = p; } + +protected: + // Prevent copies (undefined) + LV2Plugin(const LV2Plugin& copy); + LV2Plugin& operator=(const LV2Plugin&); + + void get_port_vals(ulong port_index, PortInfo* info); + + const SLV2Plugin* m_lv2_plugin; + SLV2Instance** m_instances; + + const Plugin* m_om_plugin; +}; + + +} // namespace Om + +#endif // LV2PLUGIN_H + diff --git a/src/libs/engine/LashDriver.cpp b/src/libs/engine/LashDriver.cpp new file mode 100644 index 00000000..f42f87f2 --- /dev/null +++ b/src/libs/engine/LashDriver.cpp @@ -0,0 +1,159 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "LashDriver.h" +#include "config.h" +#include +#include +#include +#include "OmApp.h" + +using std::cerr; using std::cout; using std::endl; +using std::string; + +namespace Om { + + +LashDriver::LashDriver(OmApp* app, lash_args_t* args) +: m_app(app), + m_client(NULL), + m_alsa_client_id(0) // FIXME: appropriate sentinel? +{ + m_client = lash_init(args, PACKAGE_NAME, + /*LASH_Config_Data_Set|LASH_Config_File*/0, LASH_PROTOCOL(2, 0)); + if (m_client == NULL) { + cerr << "[LashDriver] Failed to connect to LASH. Session management will not function." << endl; + } else { + cout << "[LashDriver] Lash initialised" << endl; + lash_event_t* event = lash_event_new_with_type(LASH_Client_Name); + lash_event_set_string(event, "Om"); + lash_send_event(m_client, event); + } +} + + +/** Set the Jack client name to be sent to LASH. + * The name isn't actually send until restore_finished() is called. + */ +void +LashDriver::set_jack_client_name(const char* name) +{ + m_jack_client_name = name; + lash_jack_client_name(m_client, m_jack_client_name.c_str()); +} + + +/** Set the Alsa client ID to be sent to LASH. + * The name isn't actually send until restore_finished() is called. + */ +void +LashDriver::set_alsa_client_id(int id) +{ + m_alsa_client_id = id; + lash_alsa_client_id(m_client, m_alsa_client_id); +} + + +/** Notify LASH of our port names so it can restore connections. + * The Alsa client ID and Jack client name MUST be set before calling + * this function. + */ +void +LashDriver::restore_finished() +{ + assert(m_jack_client_name != ""); + assert(m_alsa_client_id != 0); + + cerr << "LASH RESTORE FINISHED " << m_jack_client_name << " - " << m_alsa_client_id << endl; + + lash_jack_client_name(m_client, m_jack_client_name.c_str()); + lash_alsa_client_id(m_client, m_alsa_client_id); +} + + +void +LashDriver::process_events() +{ + assert(m_client != NULL); + + lash_event_t* ev = NULL; + lash_config_t* conf = NULL; + + // Process events + while ((ev = lash_get_event(m_client)) != NULL) { + handle_event(ev); + lash_event_destroy(ev); + } + + // Process configs + while ((conf = lash_get_config(m_client)) != NULL) { + handle_config(conf); + lash_config_destroy(conf); + } +} + + +void +LashDriver::handle_event(lash_event_t* ev) +{ + LASH_Event_Type type = lash_event_get_type(ev); + const char* c_str = lash_event_get_string(ev); + string str = (c_str == NULL) ? "" : c_str; + + //cout << "[LashDriver] LASH Event. Type = " << type << ", string = " << str << "**********" << endl; + + /*if (type == LASH_Save_File) { + //cout << "[LashDriver] LASH Save File - " << str << endl; + m_app->store_window_location(); + m_app->state_manager()->save(str.append("/locations")); + lash_send_event(m_client, lash_event_new_with_type(LASH_Save_File)); + } else if (type == LASH_Restore_File) { + //cout << "[LashDriver] LASH Restore File - " << str << endl; + m_app->state_manager()->load(str.append("/locations")); + m_app->update_state(); + lash_send_event(m_client, lash_event_new_with_type(LASH_Restore_File)); + } else if (type == LASH_Save_Data_Set) { + //cout << "[LashDriver] LASH Save Data Set - " << endl; + + // Tell LASH we're done + lash_send_event(m_client, lash_event_new_with_type(LASH_Save_Data_Set)); + } else*/ + if (type == LASH_Quit) { + //stop_thread(); + m_client = NULL; + m_app->quit(); + } else { + cerr << "[LashDriver] WARNING: Unhandled lash event, type " << static_cast(type) << endl; + } +} + + +void +LashDriver::handle_config(lash_config_t* conf) +{ + const char* key = NULL; + const void* val = NULL; + size_t val_size = 0; + + //cout << "[LashDriver] LASH Config. Key = " << key << endl; + + key = lash_config_get_key(conf); + val = lash_config_get_value(conf); + val_size = lash_config_get_value_size(conf); +} + + +} // namespace Om diff --git a/src/libs/engine/LashDriver.h b/src/libs/engine/LashDriver.h new file mode 100644 index 00000000..dedf1c6b --- /dev/null +++ b/src/libs/engine/LashDriver.h @@ -0,0 +1,57 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LASHDRIVER_H +#define LASHDRIVER_H + +#include +#include +#include +using std::string; + +namespace Om { + +class OmApp; + + +/** Handles all support for LASH session management. + */ +class LashDriver +{ +public: + LashDriver(OmApp* app, lash_args_t* args); + + bool enabled() { return (m_client != NULL && lash_enabled(m_client)); } + void process_events(); + void set_jack_client_name(const char* name); + void set_alsa_client_id(int id); + void restore_finished(); + +private: + OmApp* m_app; + lash_client_t* m_client; + + int m_alsa_client_id; + string m_jack_client_name; + + void handle_event(lash_event_t* conf); + void handle_config(lash_config_t* conf); +}; + + +} // namespace Om + +#endif // LASHDRIVER_H diff --git a/src/libs/engine/List.h b/src/libs/engine/List.h new file mode 100644 index 00000000..cc51bc5d --- /dev/null +++ b/src/libs/engine/List.h @@ -0,0 +1,416 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LIST_H +#define LIST_H + +#include +#include "util/types.h" +#include "MaidObject.h" + + +/** A node in a List. + * + * This class is (unusually) exposed to the user to allow list operations + * to be realtime safe (ie so events can allocate list nodes in other threads + * and then insert them in the realtime thread. + */ +template +class ListNode : public MaidObject +{ +public: + ListNode(T elem) : m_elem(elem), m_next(NULL), m_prev(NULL) {} + virtual ~ListNode() {} + + ListNode* next() const { return m_next; } + void next(ListNode* ln) { m_next = ln; } + ListNode* prev() const { return m_prev; } + void prev(ListNode* ln) { m_prev = ln; } + T& elem() { return m_elem;} + const T& elem() const { return m_elem; } + +private: + // Prevent copies (undefined) + ListNode(const ListNode& copy); + ListNode& operator=(const ListNode& copy); + + T m_elem; + ListNode* m_next; + ListNode* m_prev; +}; + + + +/** A realtime safe, (partially) thread safe doubly linked list. + * + * Elements can be added safely while another thread is reading the list. See + * documentation for specific functions for realtime/thread safeness. + */ +template +class List : public MaidObject +{ +public: + List() : m_head(NULL), m_tail(NULL), m_size(0), m_end_iter(this), m_const_end_iter(this) + { + m_end_iter.m_listnode = NULL; + m_end_iter.m_next = NULL; + m_const_end_iter.m_listnode = NULL; + m_const_end_iter.m_next = NULL; + } + ~List(); + + void push_back(ListNode* elem); + ListNode* remove(const T elem); + + void clear(); + size_t size() const { return m_size; } + + class iterator; + + /** Realtime safe const iterator for a List. */ + class const_iterator + { + public: + const_iterator(const List* const list); + const_iterator(const iterator& i) + : m_list(i.m_list), m_listnode(i.m_listnode), m_next(i.m_next) {} + + inline const T& operator*(); + inline const_iterator& operator++(); + inline bool operator!=(const const_iterator& iter) const; + inline bool operator!=(const iterator& iter) const; + + friend class List; + + private: + const List* const m_list; + const ListNode* m_listnode; + const ListNode* m_next; // use this instead of m_listnode->next() to allow deleting + }; + + + /** Realtime safe iterator for a List. */ + class iterator + { + public: + iterator(List* const list); + + inline T& operator*(); + inline iterator& operator++(); + inline bool operator!=(const iterator& iter) const; + inline bool operator!=(const const_iterator& iter) const; + + friend class List; + friend class List::const_iterator; + + private: + const List* m_list; + ListNode* m_listnode; + ListNode* m_next; // use this instead of m_listnode->next() to allow deleting + }; + + + ListNode* remove(const iterator iter); + + iterator begin(); + const iterator end() const; + + const_iterator begin() const; + //const_iterator end() const; + +private: + // Prevent copies (undefined) + List(const List& copy); + List& operator=(const List& copy); + + ListNode* m_head; + ListNode* m_tail; + size_t m_size; + iterator m_end_iter; + const_iterator m_const_end_iter; +}; + + + + +template +List::~List() +{ + clear(); +} + + +/** Clear the list, deleting all ListNodes contained (but NOT their contents!) + * + * Not realtime safe. + */ +template +void +List::clear() +{ + if (m_head == NULL) return; + + ListNode* node = m_head; + ListNode* next = NULL; + + while (node != NULL) { + next = node->next(); + delete node; + node = next; + } + m_tail = m_head = NULL; + m_size = 0; +} + + +/** Add an element to the list. + * + * This method can be called while another thread is reading the list. + * Realtime safe. + */ +template +void +List::push_back(ListNode* const ln) +{ + assert(ln != NULL); + + ln->next(NULL); + // FIXME: atomicity? relevant? + if (m_head == NULL) { + ln->prev(NULL); + m_head = m_tail = ln; + } else { + ln->prev(m_tail); + m_tail->next(ln); + m_tail = ln; + } + ++m_size; +} + + +/** Remove an element from the list. + * + * This function is realtime safe - it is the caller's responsibility to + * delete the returned ListNode, or there will be a leak. + */ +template +ListNode* +List::remove(const T elem) +{ + // FIXME: atomicity? + ListNode* n = m_head; + while (n != NULL) { + if (n->elem() == elem) + break; + n = n->next(); + } + if (n != NULL) { + if (n == m_head) m_head = m_head->next(); + if (n == m_tail) m_tail = m_tail->prev(); + if (n->prev() != NULL) + n->prev()->next(n->next()); + if (n->next() != NULL) + n->next()->prev(n->prev()); + --m_size; + if (m_size == 0) m_head = m_tail = NULL; // FIXME: Shouldn't be necessary + return n; + } + return NULL; +} + + +/** Remove an element from the list using an iterator. + * + * This function is realtime safe - it is the caller's responsibility to + * delete the returned ListNode, or there will be a leak. + */ +template +ListNode* +List::remove(const iterator iter) +{ + ListNode* n = iter.m_listnode; + if (n != NULL) { + if (n == m_head) m_head = m_head->next(); + if (n == m_tail) m_tail = m_tail->prev(); + if (n->prev() != NULL) + n->prev()->next(n->next()); + if (n->next() != NULL) + n->next()->prev(n->prev()); + --m_size; + if (m_size == 0) m_head = m_tail = NULL; // FIXME: Shouldn't be necessary + return n; + } + return NULL; +} + + +//// Iterator stuff //// + +template +List::iterator::iterator(List* list) +: m_list(list), + m_listnode(NULL), + m_next(NULL) +{ +} + + +template +T& +List::iterator::operator*() +{ + assert(m_listnode != NULL); + return m_listnode->elem(); +} + + +template +inline typename List::iterator& +List::iterator::operator++() +{ + assert(m_listnode != NULL); + m_listnode = m_next; + if (m_next != NULL) + m_next = m_next->next(); + else + m_next = NULL; + + return *this; +} + + +template +inline bool +List::iterator::operator!=(const iterator& iter) const +{ + return (m_listnode != iter.m_listnode); +} + + +template +inline bool +List::iterator::operator!=(const const_iterator& iter) const +{ + return (m_listnode != iter.m_listnode); +} + + +template +inline typename List::iterator +List::begin() +{ + typename List::iterator iter(this); + iter.m_listnode = m_head; + if (m_head != NULL) + iter.m_next = m_head->next(); + else + iter.m_next = NULL; + return iter; +} + + +template +inline const typename List::iterator +List::end() const +{ + /*typename List::iterator iter(this); + iter.m_listnode = NULL; + iter.m_next = NULL; + return iter;*/ + return m_end_iter; +} + + + +/// const_iterator stuff /// + + +template +List::const_iterator::const_iterator(const List* const list) +: m_list(list), + m_listnode(NULL), + m_next(NULL) +{ +} + + +template +const T& +List::const_iterator::operator*() +{ + assert(m_listnode != NULL); + return m_listnode->elem(); +} + + +template +inline typename List::const_iterator& +List::const_iterator::operator++() +{ + assert(m_listnode != NULL); + m_listnode = m_next; + if (m_next != NULL) + m_next = m_next->next(); + else + m_next = NULL; + + return *this; +} + + +template +inline bool +List::const_iterator::operator!=(const const_iterator& iter) const +{ + return (m_listnode != iter.m_listnode); +} + + +template +inline bool +List::const_iterator::operator!=(const iterator& iter) const +{ + return (m_listnode != iter.m_listnode); +} + + +template +inline typename List::const_iterator +List::begin() const +{ + typename List::const_iterator iter(this); + iter.m_listnode = m_head; + if (m_head != NULL) + iter.m_next = m_head->next(); + else + iter.m_next = NULL; + return iter; +} + +#if 0 +template +inline typename List::const_iterator +List::end() const +{ + /*typename List::const_iterator iter(this); + iter.m_listnode = NULL; + iter.m_next = NULL; + return iter;*/ + return m_const_end_iter; +} +#endif + +#endif // LIST_H diff --git a/src/libs/engine/Maid.cpp b/src/libs/engine/Maid.cpp new file mode 100644 index 00000000..3bebdedb --- /dev/null +++ b/src/libs/engine/Maid.cpp @@ -0,0 +1,46 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Maid.h" +#include "MaidObject.h" + + +Maid::Maid(size_t size) +: m_objects(size) +{ +} + + +Maid::~Maid() +{ + cleanup(); +} + + +/** Free all the objects in the queue (passed by push()). + */ +void +Maid::cleanup() +{ + MaidObject* obj = NULL; + + while (!m_objects.is_empty()) { + obj = m_objects.pop(); + delete obj; + } +} + + diff --git a/src/libs/engine/Maid.h b/src/libs/engine/Maid.h new file mode 100644 index 00000000..75412186 --- /dev/null +++ b/src/libs/engine/Maid.h @@ -0,0 +1,65 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MAID_H +#define MAID_H + +#include "MaidObject.h" +#include "util/Queue.h" + + +/** Explicitly driven garbage collector. + * + * This is how realtime parts of the code can schedule the deletion of + * objects - push() is realtime safe. + * + * cleanup() is meant to be called periodically to free memory, often + * enough to prevent the queue from overdflowing. This is done by the + * main thread, in OmApp. + * + * \ingroup engine + */ +class Maid +{ +public: + Maid(size_t size); + ~Maid(); + + inline void push(MaidObject* obj); + + void cleanup(); + +private: + // Prevent copies + Maid(const Maid&); + Maid& operator=(const Maid&); + + Queue m_objects; +}; + + +/** Push an event to be deleted. Realtime safe. + */ +inline void +Maid::push(MaidObject* obj) +{ + if (obj != NULL) + m_objects.push(obj); +} + + +#endif // MAID_H + diff --git a/src/libs/engine/MaidObject.h b/src/libs/engine/MaidObject.h new file mode 100644 index 00000000..d0060520 --- /dev/null +++ b/src/libs/engine/MaidObject.h @@ -0,0 +1,38 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MAIDOBJECT_H +#define MAIDOBJECT_H + + +/** An object that can be passed to the maid for deletion. + * + * \ingroup engine + */ +class MaidObject +{ +public: + MaidObject() {} + virtual ~MaidObject() {} + +private: + // Prevent copies + MaidObject(const MaidObject&); + MaidObject& operator=(const MaidObject&); +}; + + +#endif // MAIDOBJECT_H diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am new file mode 100644 index 00000000..ae0b3e53 --- /dev/null +++ b/src/libs/engine/Makefile.am @@ -0,0 +1,259 @@ +SUBDIRS = tests +DIST_SUBDIRS = events + +AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @SLV2_CFLAGS@ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/engine/events -fno-exceptions -fno-rtti + +MAINTAINERCLEANFILES = Makefile.in + +common_SOURCES = \ + util.h \ + tuning.h \ + Node.h \ + NodeBase.h \ + NodeBase.cpp \ + InternalNode.h \ + Patch.h \ + Patch.cpp \ + NodeFactory.h \ + NodeFactory.cpp \ + Om.h \ + Om.cpp \ + OmApp.h \ + OmApp.cpp \ + JackAudioDriver.h \ + JackAudioDriver.cpp \ + OSCReceiver.h \ + OSCReceiver.cpp \ + Responder.h \ + OSCResponder.h \ + OSCResponder.cpp \ + ClientKey.h \ + ClientBroadcaster.h \ + ClientBroadcaster.cpp \ + ObjectSender.h \ + ObjectSender.cpp \ + OSCClient.h \ + OSCClient.cpp \ + Buffer.h \ + Buffer.cpp \ + Port.h \ + Port.cpp \ + PortBase.h \ + PortBase.cpp \ + InputPort.h \ + InputPort.cpp \ + OutputPort.h \ + OutputPort.cpp \ + MidiMessage.h \ + MidiNoteNode.h \ + MidiNoteNode.cpp \ + MidiTriggerNode.h \ + MidiTriggerNode.cpp \ + MidiControlNode.h \ + MidiControlNode.cpp \ + BridgeNode.h \ + BridgeNode.cpp \ + ControlInputNode.h \ + ControlInputNode.cpp \ + ControlOutputNode.h \ + ControlOutputNode.cpp \ + AudioInputNode.h \ + AudioInputNode.cpp \ + AudioOutputNode.h \ + AudioOutputNode.cpp \ + MidiInputNode.h \ + MidiInputNode.cpp \ + MidiOutputNode.h \ + MidiOutputNode.cpp \ + Event.h \ + Event.cpp \ + QueuedEvent.h \ + EventSource.h \ + QueuedEventSource.h \ + QueuedEventSource.cpp \ + QueuedEngineInterface.h \ + QueuedEngineInterface.cpp \ + OmObject.h \ + Maid.h \ + Maid.cpp \ + MaidObject.h \ + Tree.h \ + ClientRecord.h \ + PortInfo.h \ + PluginLibrary.h \ + Plugin.h \ + Array.h \ + List.h \ + PostProcessor.h \ + PostProcessor.cpp \ + Connection.h \ + Connection.cpp \ + ConnectionBase.h \ + ConnectionBase.cpp \ + ObjectStore.h \ + ObjectStore.cpp \ + TransportNode.h \ + TransportNode.cpp \ + Driver.h \ + AudioDriver.h \ + MidiDriver.h \ + midi.h \ + ../common/util/Semaphore.h \ + ../common/util/types.h \ + ../common/util/Path.h \ + ../common/util/Queue.h \ + ../common/interface/ClientInterface.h \ + ../common/interface/EngineInterface.h \ + instantiations.cpp + +# Events +common_SOURCES += \ + events/RegisterClientEvent.h \ + events/RegisterClientEvent.cpp \ + events/UnregisterClientEvent.h \ + events/UnregisterClientEvent.cpp \ + events/PingQueuedEvent.h \ + events/ActivateEvent.h \ + events/ActivateEvent.cpp \ + events/DeactivateEvent.h \ + events/DeactivateEvent.cpp \ + events/SetPortValueEvent.h \ + events/SetPortValueEvent.cpp \ + events/SetPortValueQueuedEvent.h \ + events/SetPortValueQueuedEvent.cpp \ + events/NoteOnEvent.h \ + events/NoteOnEvent.cpp \ + events/NoteOffEvent.h \ + events/NoteOffEvent.cpp \ + events/AllNotesOffEvent.h \ + events/AllNotesOffEvent.cpp \ + events/ConnectionEvent.h \ + events/ConnectionEvent.cpp \ + events/DisconnectionEvent.h \ + events/DisconnectionEvent.cpp \ + events/DisconnectNodeEvent.h \ + events/DisconnectNodeEvent.cpp \ + events/DisconnectPortEvent.h \ + events/DisconnectPortEvent.cpp \ + events/DestroyEvent.h \ + events/DestroyEvent.cpp \ + events/AddNodeEvent.h \ + events/AddNodeEvent.cpp \ + events/SetMetadataEvent.h \ + events/SetMetadataEvent.cpp \ + events/RequestMetadataEvent.h \ + events/RequestMetadataEvent.cpp \ + events/RequestPortValueEvent.h \ + events/RequestPortValueEvent.cpp \ + events/RequestAllObjectsEvent.h \ + events/RequestAllObjectsEvent.cpp \ + events/RequestPluginsEvent.h \ + events/RequestPluginsEvent.cpp \ + events/CreatePatchEvent.h \ + events/CreatePatchEvent.cpp \ + events/LoadPluginsEvent.h \ + events/LoadPluginsEvent.cpp \ + events/EnablePatchEvent.h \ + events/EnablePatchEvent.cpp \ + events/DisablePatchEvent.h \ + events/DisablePatchEvent.cpp \ + events/ClearPatchEvent.h \ + events/ClearPatchEvent.cpp \ + events/RenameEvent.h \ + events/RenameEvent.cpp \ + events/MidiLearnEvent.h \ + events/MidiLearnEvent.cpp + +if WITH_JACK_MIDI +common_SOURCES += \ + JackMidiDriver.h \ + JackMidiDriver.cpp +endif + +if WITH_ALSA_MIDI +common_SOURCES += \ + AlsaMidiDriver.h \ + AlsaMidiDriver.cpp +endif + +if WITH_LADSPA +common_SOURCES += \ + LADSPAPlugin.h \ + LADSPAPlugin.cpp +endif + +if WITH_DSSI +common_SOURCES += \ + DSSIPlugin.h \ + DSSIPlugin.cpp \ + events/DSSIConfigureEvent.cpp \ + events/DSSIConfigureEvent.h \ + events/DSSIControlEvent.cpp \ + events/DSSIControlEvent.h \ + events/DSSIProgramEvent.cpp \ + events/DSSIProgramEvent.h \ + events/DSSIUpdateEvent.cpp \ + events/DSSIUpdateEvent.h +endif + +if WITH_LV2 +common_SOURCES += \ + LV2Plugin.h \ + LV2Plugin.cpp +endif + +if WITH_LASH +common_SOURCES += \ + LashDriver.h \ + LashDriver.cpp \ + LashRestoreDoneEvent.h +endif + + +# +# Non-installed library to link stand-alone and in-process build against +# + +noinst_LTLIBRARIES = libom.la +libom_la_SOURCES = $(common_SOURCES) + + + +# +# Stand-alone engine +# +if BUILD_ENGINE + +bin_PROGRAMS = om +om_DEPENDENCIES = libom.la +om_LDADD = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -lrt libom.la + +om_SOURCES = \ + main.cpp \ + cmdline.h \ + cmdline.c + +endif # BUILD_ENGINE + + + +# +# Jack internal client +# +if BUILD_IN_PROCESS_ENGINE + + +# FIXME: broken + + +# FIXME: Figure out how to get this properly +omdir = $(prefix)/lib/jack + +om_la_CFLAGS = -fPIC +om_LTLIBRARIES = om.la +om_la_LDFLAGS = -module -avoid-version @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ +om_la_SOURCES = OmInProcess.cpp + +endif # BUILD_IN_PROCESS_ENGINE + + diff --git a/src/libs/engine/MidiControlNode.cpp b/src/libs/engine/MidiControlNode.cpp new file mode 100644 index 00000000..2116c828 --- /dev/null +++ b/src/libs/engine/MidiControlNode.cpp @@ -0,0 +1,133 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MidiControlNode.h" +#include +#include "Om.h" +#include "OmApp.h" +#include "PostProcessor.h" +#include "MidiLearnEvent.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "PortInfo.h" +#include "Plugin.h" +#include "util.h" +#include "midi.h" + + +namespace Om { + + +MidiControlNode::MidiControlNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: InternalNode(path, 1, parent, srate, buffer_size), + m_learning(false) +{ + m_num_ports = 7; + m_ports.alloc(m_num_ports); + + m_midi_in_port = new InputPort(this, "MIDI In", 0, 1, + new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); + m_ports.at(0) = m_midi_in_port; + + m_param_port = new InputPort(this, "Controller Number", 1, 1, + new PortInfo("Controller Number", CONTROL, INPUT, INTEGER, 60, 0, 127), 1); + m_ports.at(1) = m_param_port; + m_log_port = new InputPort(this, "Logarithmic", 2, 1, + new PortInfo("Logarithmic", CONTROL, INPUT, TOGGLE, 0, 0, 1), 1); + m_ports.at(2) = m_log_port; + + m_min_port = new InputPort(this, "Min", 3, 1, + new PortInfo("Min", CONTROL, INPUT, NONE, 0, 0, 65535), 1); + m_ports.at(3) = m_min_port; + + m_max_port = new InputPort(this, "Max", 4, 1, + new PortInfo("Max", CONTROL, INPUT, NONE, 1, 0, 65535), 1); + m_ports.at(4) = m_max_port; + + m_audio_port = new OutputPort(this, "Out (AR)", 5, 1, + new PortInfo("Out (AR)", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); + m_ports.at(5) = m_audio_port; + + m_control_port = new OutputPort(this, "Out (CR)", 6, 1, + new PortInfo("Out (CR)", CONTROL, OUTPUT, 0, 0, 1), 1); + m_ports.at(6) = m_control_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("midi_control_in"); + m_plugin.name("Om Control Node (MIDI)"); +} + + +void +MidiControlNode::run(size_t nframes) +{ + InternalNode::run(nframes); + + MidiMessage ev; + + for (size_t i=0; i < m_midi_in_port->buffer(0)->filled_size(); ++i) { + ev = m_midi_in_port->buffer(0)->value_at(i); + + if ((ev.buffer[0] & 0xF0) == MIDI_CMD_CONTROL) + control(ev.buffer[1], ev.buffer[2], ev.time); + } +} + + +void +MidiControlNode::control(uchar control_num, uchar val, samplecount offset) +{ + assert(offset < m_buffer_size); + + sample scaled_value; + + const sample nval = (val / 127.0f); // normalized [0, 1] + + if (m_learning) { + assert(m_learn_event != NULL); + m_param_port->set_value(control_num, offset); + assert(m_param_port->buffer(0)->value_at(0) == control_num); + m_learn_event->set_value(control_num); + m_learn_event->execute(offset); + om->post_processor()->push(m_learn_event); + om->post_processor()->signal(); + m_learning = false; + m_learn_event = NULL; + } + + if (m_log_port->buffer(0)->value_at(0) > 0.0f) { + // haaaaack, stupid negatives and logarithms + sample log_offset = 0; + if (m_min_port->buffer(0)->value_at(0) < 0) + log_offset = fabs(m_min_port->buffer(0)->value_at(0)); + const sample min = log(m_min_port->buffer(0)->value_at(0)+1+log_offset); + const sample max = log(m_max_port->buffer(0)->value_at(0)+1+log_offset); + scaled_value = expf(nval * (max - min) + min) - 1 - log_offset; + } else { + const sample min = m_min_port->buffer(0)->value_at(0); + const sample max = m_max_port->buffer(0)->value_at(0); + scaled_value = ((nval) * (max - min)) + min; + } + + if (control_num == m_param_port->buffer(0)->value_at(0)) { + m_control_port->set_value(scaled_value, offset); + m_audio_port->set_value(scaled_value, offset); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/MidiControlNode.h b/src/libs/engine/MidiControlNode.h new file mode 100644 index 00000000..b40e7631 --- /dev/null +++ b/src/libs/engine/MidiControlNode.h @@ -0,0 +1,72 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIDICONTROLNODE_H +#define MIDICONTROLNODE_H + +#include +#include "NodeBase.h" +#include "InternalNode.h" +using std::string; + +namespace Om { + +class MidiLearnResponseEvent; +class MidiMessage; +template class InputPort; +template class OutputPort; + + +/** MIDI control input node. + * + * Creating one of these nodes is how a user makes "MIDI Bindings". Note that + * this node will always be monophonic, the poly parameter is ignored. + * + * \ingroup engine + */ +class MidiControlNode : public InternalNode +{ +public: + MidiControlNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); + + void run(size_t nframes); + + void control(uchar control_num, uchar val, samplecount offset); + + void learn(MidiLearnResponseEvent* ev) { m_learning = true; m_learn_event = ev; } + +private: + // Disallow copies (undefined) + MidiControlNode(const MidiControlNode& copy); + MidiControlNode& operator=(const MidiControlNode&); + + bool m_learning; + + InputPort* m_midi_in_port; + InputPort* m_param_port; + InputPort* m_log_port; + InputPort* m_min_port; + InputPort* m_max_port; + OutputPort* m_control_port; + OutputPort* m_audio_port; + + MidiLearnResponseEvent* m_learn_event; +}; + + +} // namespace Om + +#endif // MIDICONTROLNODE_H diff --git a/src/libs/engine/MidiDriver.h b/src/libs/engine/MidiDriver.h new file mode 100644 index 00000000..b8fd71ca --- /dev/null +++ b/src/libs/engine/MidiDriver.h @@ -0,0 +1,78 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIDIDRIVER_H +#define MIDIDRIVER_H + +#include "Driver.h" +#include +using std::cout; using std::endl; + +namespace Om { + +class MidiMessage; + + +/** Midi driver abstract base class. + * + * \ingroup engine + */ +class MidiDriver : public Driver +{ +public: + /** Prepare events (however neccessary) for the specified block (realtime safe) */ + virtual void prepare_block(const samplecount block_start, const samplecount block_end) = 0; +}; + + + +/** Dummy MIDIDriver. + * + * Not abstract, all functions are dummies. One of these will be allocated and + * "used" if no working MIDI driver is loaded. (Doing it this way as opposed to + * just making MidiDriver have dummy functions makes sure any existing MidiDriver + * derived class actually implements the required functions). + * + * \ingroup engine + */ +class DummyMidiDriver : public MidiDriver +{ +public: + DummyMidiDriver() { + cout << "[DummyMidiDriver] Started Dummy MIDI driver." << endl; + } + + ~DummyMidiDriver() {} + + void activate() {} + void deactivate() {} + + bool is_activated() const { return false; } + bool is_enabled() const { return false; } + + void enable() {} + void disable() {} + + DriverPort* create_port(PortBase* patch_port) { return NULL; } + + void prepare_block(const samplecount block_start, const samplecount block_end) {} +}; + + + +} // namespace Om + +#endif // MIDIDRIVER_H diff --git a/src/libs/engine/MidiInputNode.cpp b/src/libs/engine/MidiInputNode.cpp new file mode 100644 index 00000000..25310807 --- /dev/null +++ b/src/libs/engine/MidiInputNode.cpp @@ -0,0 +1,49 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MidiInputNode.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Plugin.h" +#include "PortInfo.h" +#include "Patch.h" +#include "MidiMessage.h" + +namespace Om { + + +MidiInputNode::MidiInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: BridgeNode(path, 1, parent, srate, buffer_size) +{ + OutputPort* internal_port = new OutputPort(this, "in", 0, m_poly, + new PortInfo("in", MIDI, OUTPUT), m_buffer_size); + InputPort* external_port = new InputPort(parent, m_name, 0, m_poly, + new PortInfo(m_name, MIDI, INPUT), m_buffer_size); + external_port->tie(internal_port); + m_external_port = external_port; + + m_num_ports = 1; + m_ports.alloc(m_num_ports); + m_ports.at(0) = internal_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("midi_input"); + m_plugin.name("Om Patch MIDI Input Node"); +} + + +} // namespace Om + diff --git a/src/libs/engine/MidiInputNode.h b/src/libs/engine/MidiInputNode.h new file mode 100644 index 00000000..0986a267 --- /dev/null +++ b/src/libs/engine/MidiInputNode.h @@ -0,0 +1,43 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIDIINPUTNODE_H +#define MIDIINPUTNODE_H + +#include +#include "BridgeNode.h" + +using std::string; + +namespace Om { + +class MidiMessage; + + +/** MIDI input BridgeNode. + * + * \ingroup engine + */ +class MidiInputNode : public BridgeNode +{ +public: + MidiInputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); +}; + + +} // namespace Om + +#endif // MIDIINPUTNODE_H diff --git a/src/libs/engine/MidiMessage.h b/src/libs/engine/MidiMessage.h new file mode 100644 index 00000000..8dcb3e67 --- /dev/null +++ b/src/libs/engine/MidiMessage.h @@ -0,0 +1,51 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIDIMESSAGE_H +#define MIDIMESSAGE_H + +namespace Om { + + +/** Midi Message (the type a MIDI port connects to). + * + * For the time being (ie while it's still possible) this is binary + * compatible with jack_default_midi_event_t. Don't mess that up without + * dealing with all the repercussions (in the MidiDriver's). + * + * Note that with the current implementation one of these is NOT valid + * across process cycles (since the buffer is just a pointer to the bufferr + * given to us by Jack itself. In other words, if one of these needs to be + * stored, it needs to be deep copied. Less copying anyway.. :/ + */ +struct MidiMessage +{ +public: + MidiMessage() : time(0), size(0), buffer(NULL) {} + + // Really just to allow setting to zero for generic algos + MidiMessage(const int& i) : time(0), size(0), buffer(NULL) {} + + samplecount time; + size_t size; + unsigned char* buffer; +}; + + +} // namespace Om + + +#endif // MIDIMESSAGE_H diff --git a/src/libs/engine/MidiNoteNode.cpp b/src/libs/engine/MidiNoteNode.cpp new file mode 100644 index 00000000..9dc32f4a --- /dev/null +++ b/src/libs/engine/MidiNoteNode.cpp @@ -0,0 +1,304 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MidiNoteNode.h" +#include +#include +#include "MidiMessage.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "PortInfo.h" +#include "Plugin.h" +#include "Array.h" +#include "Om.h" +#include "OmApp.h" +#include "AudioDriver.h" +#include "util.h" +#include "midi.h" + +using std::cerr; using std::cout; using std::endl; + + +namespace Om { + + +MidiNoteNode::MidiNoteNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: InternalNode(path, poly, parent, srate, buffer_size), + m_voices(new Voice[poly]), + m_sustain(false) +{ + m_num_ports = 5; + m_ports.alloc(m_num_ports); + + m_midi_in_port = new InputPort(this, "MIDI In", 0, 1, + new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); + m_ports.at(0) = m_midi_in_port; + + m_freq_port = new OutputPort(this, "Frequency", 1, poly, + new PortInfo("Frequency", AUDIO, OUTPUT, 440, 0, 99999), m_buffer_size); + m_ports.at(1) = m_freq_port; + + m_vel_port = new OutputPort(this, "Velocity", 2, poly, + new PortInfo("Velocity", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); + m_ports.at(2) = m_vel_port; + + m_gate_port = new OutputPort(this, "Gate", 3, poly, + new PortInfo("Gate", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); + m_ports.at(3) = m_gate_port; + + m_trig_port = new OutputPort(this, "Trigger", 4, poly, + new PortInfo("Trigger", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); + m_ports.at(4) = m_trig_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("note_in"); + m_plugin.name("Om Note Node (MIDI, OSC)"); +} + + +MidiNoteNode::~MidiNoteNode() +{ + delete[] m_voices; +} + + +void +MidiNoteNode::run(size_t nframes) +{ + InternalNode::run(nframes); + + MidiMessage ev; + + for (size_t i=0; i < m_midi_in_port->buffer(0)->filled_size(); ++i) { + ev = m_midi_in_port->buffer(0)->value_at(i); + + switch (ev.buffer[0] & 0xF0) { + case MIDI_CMD_NOTE_ON: + if (ev.buffer[2] == 0) + note_off(ev.buffer[1], ev.time); + else + note_on(ev.buffer[1], ev.buffer[2], ev.time); + break; + case MIDI_CMD_NOTE_OFF: + note_off(ev.buffer[1], ev.time); + break; + case MIDI_CMD_CONTROL: + switch (ev.buffer[1]) { + case MIDI_CTL_ALL_NOTES_OFF: + case MIDI_CTL_ALL_SOUNDS_OFF: + all_notes_off(ev.time); + break; + case MIDI_CTL_SUSTAIN: + if (ev.buffer[2] > 63) + sustain_on(); + else + sustain_off(ev.time); + break; + case MIDI_CMD_BENDER: + + break; + } + default: + break; + } + } +} + + +void +MidiNoteNode::note_on(uchar note_num, uchar velocity, samplecount offset) +{ + const jack_nframes_t time_stamp = om->audio_driver()->time_stamp(); + + assert(offset < m_buffer_size); + assert(note_num <= 127); + + Key* key = &m_keys[note_num]; + Voice* voice = NULL; + size_t voice_num = 0; + + // Look for free voices + for (size_t i=0; i < m_poly; ++i) { + if (m_voices[i].state == Voice::Voice::FREE) { + voice = &m_voices[i]; + voice_num = i; + break; + } + } + + // If we didn't find a free one, steal the oldest + if (voice == NULL) { + voice_num = 0; + voice = &m_voices[0]; + jack_nframes_t oldest_time = m_voices[0].time; + for (size_t i=1; i < m_poly; ++i) { + if (m_voices[i].time < oldest_time) { + voice = &m_voices[i]; + voice_num = i; + oldest_time = voice->time; + } + } + } + assert(voice != NULL); + assert(voice == &m_voices[voice_num]); + + //cerr << "[MidiNoteNode] Note on. Key " << (int)note_num << ", Voice " << voice_num << endl; + + // Update stolen key, if applicable + if (voice->state == Voice::Voice::ACTIVE) { + assert(m_keys[voice->note].voice == voice_num); + assert(m_keys[voice->note].state == Key::ON_ASSIGNED); + m_keys[voice->note].state = Key::Key::ON_UNASSIGNED; + //cerr << "[MidiNoteNode] Stole voice " << voice_num << endl; + } + + // Store key information for later reallocation on note off + key->state = Key::Key::ON_ASSIGNED; + key->voice = voice_num; + key->time = time_stamp; + + // Trigger voice + voice->state = Voice::Voice::ACTIVE; + voice->note = note_num; + voice->time = time_stamp; + + assert(m_keys[voice->note].state == Key::Key::ON_ASSIGNED); + assert(m_keys[voice->note].voice == voice_num); + + // one-sample jitter hack to avoid having to deal with trigger sample "next time" + if (offset == (samplecount)(m_buffer_size-1)) + --offset; + + m_freq_port->buffer(voice_num)->set(note_to_freq(note_num), offset); + m_vel_port->buffer(voice_num)->set(velocity/127.0, offset); + m_gate_port->buffer(voice_num)->set(1.0f, offset); + + // trigger (one sample) + m_trig_port->buffer(voice_num)->set(1.0f, offset, offset); + m_trig_port->buffer(voice_num)->set(0.0f, offset+1); + + assert(key->state == Key::Key::ON_ASSIGNED); + assert(voice->state == Voice::Voice::ACTIVE); + assert(key->voice == voice_num); + assert(m_voices[key->voice].note == note_num); +} + + +void +MidiNoteNode::note_off(uchar note_num, samplecount offset) +{ + assert(offset < m_buffer_size); + + Key* key = &m_keys[note_num]; + + if (key->state == Key::ON_ASSIGNED) { + // Assigned key, turn off voice and key + assert(m_voices[key->voice].state == Voice::ACTIVE); + assert(m_voices[key->voice].note == note_num); + key->state = Key::OFF; + + if ( ! m_sustain) + free_voice(key->voice, offset); + else + m_voices[key->voice].state = Voice::HOLDING; + } + + key->state = Key::OFF; +} + + +void +MidiNoteNode::free_voice(size_t voice, samplecount offset) +{ + // Find a key to reassign to the freed voice (the newest, if there is one) + Key* replace_key = NULL; + uchar replace_key_num = 0; + + for (uchar i = 0; i <= 127; ++i) { + if (m_keys[i].state == Key::ON_UNASSIGNED) { + if (replace_key == NULL || m_keys[i].time > replace_key->time) { + replace_key = &m_keys[i]; + replace_key_num = i; + } + } + } + + if (replace_key != NULL) { // Found a key to assign to freed voice + assert(&m_keys[replace_key_num] == replace_key); + assert(replace_key->state == Key::ON_UNASSIGNED); + + // Change the freq but leave the gate high and don't retrigger + m_freq_port->buffer(voice)->set(note_to_freq(replace_key_num), offset); + + replace_key->state = Key::ON_ASSIGNED; + replace_key->voice = voice; + m_keys[m_voices[voice].note].state = Key::ON_UNASSIGNED; + m_voices[voice].note = replace_key_num; + m_voices[voice].state = Voice::ACTIVE; + } else { + // No new note for voice, deactivate (set gate low) + //cerr << "[MidiNoteNode] Note off. Key " << (int)note_num << ", Voice " << voice << " Killed" << endl; + m_gate_port->buffer(voice)->set(0.0f, offset); + m_voices[voice].state = Voice::FREE; + } +} + + +void +MidiNoteNode::all_notes_off(samplecount offset) +{ + //cerr << "Note off starting at sample " << offset << endl; + assert(offset < m_buffer_size); + + // FIXME: set all keys to Key::OFF? + + for (size_t i=0; i < m_poly; ++i) { + m_gate_port->buffer(i)->set(0.0f, offset); + m_voices[i].state = Voice::FREE; + } +} + + +float +MidiNoteNode::note_to_freq(int num) +{ + static const float A4 = 440.0f; + if (num >= 0 && num <= 119) + return A4 * powf(2.0f, (float)(num - 57.0f) / 12.0f); + return 1.0f; // Some LADSPA plugins don't like freq=0 +} + + +void +MidiNoteNode::sustain_on() +{ + m_sustain = true; +} + + +void +MidiNoteNode::sustain_off(samplecount offset) +{ + m_sustain = false; + + for (size_t i=0; i < m_poly; ++i) + if (m_voices[i].state == Voice::HOLDING) + free_voice(i, offset); +} + + +} // namespace Om + diff --git a/src/libs/engine/MidiNoteNode.h b/src/libs/engine/MidiNoteNode.h new file mode 100644 index 00000000..bf302144 --- /dev/null +++ b/src/libs/engine/MidiNoteNode.h @@ -0,0 +1,87 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIDINOTENODE_H +#define MIDINOTENODE_H + +#include +#include "InternalNode.h" +#include "util/types.h" + +using std::string; + +namespace Om { + +class MidiMessage; +template class InputPort; +template class OutputPort; + + +/** MIDI note input node. + * + * For pitched instruments like keyboard, etc. + * + * \ingroup engine + */ +class MidiNoteNode : public InternalNode +{ +public: + MidiNoteNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); + ~MidiNoteNode(); + + void run(size_t nframes); + + void note_on(uchar note_num, uchar velocity, samplecount offset); + void note_off(uchar note_num, samplecount offset); + void all_notes_off(samplecount offset); + + void sustain_on(); + void sustain_off(samplecount offset); + +private: + + /** Key, one for each key on the keyboard */ + struct Key { + enum State { OFF, ON_ASSIGNED, ON_UNASSIGNED }; + Key() : state(OFF), voice(0), time(0) {} + State state; size_t voice; samplecount time; + }; + + /** Voice, one of these always exists for each voice */ + struct Voice { + enum State { FREE, ACTIVE, HOLDING }; + Voice() : state(FREE), note(0) {} + State state; uchar note; samplecount time; + }; + + float note_to_freq(int num); + void free_voice(size_t voice, samplecount offset); + + Voice* m_voices; + Key m_keys[128]; + bool m_sustain; ///< Whether or not hold pedal is depressed + + InputPort* m_midi_in_port; + OutputPort* m_freq_port; + OutputPort* m_vel_port; + OutputPort* m_gate_port; + OutputPort* m_trig_port; +}; + + +} // namespace Om + +#endif // MIDINOTENODE_H diff --git a/src/libs/engine/MidiOutputNode.cpp b/src/libs/engine/MidiOutputNode.cpp new file mode 100644 index 00000000..33023cc6 --- /dev/null +++ b/src/libs/engine/MidiOutputNode.cpp @@ -0,0 +1,49 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MidiOutputNode.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Plugin.h" +#include "PortInfo.h" +#include "Patch.h" +#include "MidiMessage.h" + +namespace Om { + + +MidiOutputNode::MidiOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: BridgeNode(path, 1, parent, srate, buffer_size) +{ + OutputPort* external_port = new OutputPort(parent, m_name, 0, m_poly, + new PortInfo(m_name, MIDI, OUTPUT), m_buffer_size); + InputPort* internal_port = new InputPort(this, "out", 0, m_poly, + new PortInfo("out", MIDI, INPUT), m_buffer_size); + internal_port->tie(external_port); + m_external_port = external_port; + + m_num_ports = 1; + m_ports.alloc(m_num_ports); + m_ports.at(0) = internal_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("midi_output"); + m_plugin.name("Om Patch MIDI Output Node"); +} + + +} // namespace Om + diff --git a/src/libs/engine/MidiOutputNode.h b/src/libs/engine/MidiOutputNode.h new file mode 100644 index 00000000..06d8a892 --- /dev/null +++ b/src/libs/engine/MidiOutputNode.h @@ -0,0 +1,43 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIDIOUTPUTNODE_H +#define MIDIOUTPUTNODE_H + +#include +#include "BridgeNode.h" + +using std::string; + +namespace Om { + +class MidiMessage; + + +/** MIDI output BridgeNode. + * + * \ingroup engine + */ +class MidiOutputNode : public BridgeNode +{ +public: + MidiOutputNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); +}; + + +} // namespace Om + +#endif // MIDIOUTPUTNODE_H diff --git a/src/libs/engine/MidiTriggerNode.cpp b/src/libs/engine/MidiTriggerNode.cpp new file mode 100644 index 00000000..4fda80e7 --- /dev/null +++ b/src/libs/engine/MidiTriggerNode.cpp @@ -0,0 +1,124 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MidiTriggerNode.h" +#include +#include "InputPort.h" +#include "OutputPort.h" +#include "PortInfo.h" +#include "Plugin.h" +#include "util.h" +#include "midi.h" + +namespace Om { + + +MidiTriggerNode::MidiTriggerNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: InternalNode(path, 1, parent, srate, buffer_size) +{ + m_num_ports = 5; + m_ports.alloc(m_num_ports); + + m_midi_in_port = new InputPort(this, "MIDI In", 0, 1, + new PortInfo("MIDI In", MIDI, INPUT), m_buffer_size); + m_ports.at(0) = m_midi_in_port; + + m_note_port = new InputPort(this, "Note Number", 1, 1, + new PortInfo("Note Number", CONTROL, INPUT, INTEGER, 60, 0, 127), 1); + m_ports.at(1) = m_note_port; + + m_gate_port = new OutputPort(this, "Gate", 2, 1, + new PortInfo("Gate", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); + m_ports.at(2) = m_gate_port; + + m_trig_port = new OutputPort(this, "Trigger", 3, 1, + new PortInfo("Trigger", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); + m_ports.at(3) = m_trig_port; + + m_vel_port = new OutputPort(this, "Velocity", 4, poly, + new PortInfo("Velocity", AUDIO, OUTPUT, 0, 0, 1), m_buffer_size); + m_ports.at(4) = m_vel_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("trigger_in"); + m_plugin.name("Om Trigger Node (MIDI, OSC)"); +} + + +void +MidiTriggerNode::run(size_t nframes) +{ + InternalNode::run(nframes); + + MidiMessage ev; + + for (size_t i=0; i < m_midi_in_port->buffer(0)->filled_size(); ++i) { + ev = m_midi_in_port->buffer(0)->value_at(i); + + switch (ev.buffer[0] & 0xF0) { + case MIDI_CMD_NOTE_ON: + if (ev.buffer[2] == 0) + note_off(ev.buffer[1], ev.time); + else + note_on(ev.buffer[1], ev.buffer[2], ev.time); + break; + case MIDI_CMD_NOTE_OFF: + note_off(ev.buffer[1], ev.time); + break; + case MIDI_CMD_CONTROL: + if (ev.buffer[1] == MIDI_CTL_ALL_NOTES_OFF + || ev.buffer[1] == MIDI_CTL_ALL_SOUNDS_OFF) + m_gate_port->buffer(0)->set(0.0f, ev.time); + default: + break; + } + } +} + + +void +MidiTriggerNode::note_on(uchar note_num, uchar velocity, samplecount offset) +{ + //std::cerr << "Note on starting at sample " << offset << std::endl; + assert(offset < m_buffer_size); + + const sample filter_note = m_note_port->buffer(0)->value_at(0); + if (filter_note >= 0.0 && filter_note < 127.0 && (note_num == (uchar)filter_note)){ + + // See comments in MidiNoteNode::note_on (FIXME) + if (offset == (samplecount)(m_buffer_size-1)) + --offset; + + m_gate_port->buffer(0)->set(1.0f, offset); + m_trig_port->buffer(0)->set(1.0f, offset, offset); + m_trig_port->buffer(0)->set(0.0f, offset+1); + m_vel_port->buffer(0)->set(velocity/127.0f, offset); + } +} + + +void +MidiTriggerNode::note_off(uchar note_num, samplecount offset) +{ + assert(offset < m_buffer_size); + + if (note_num == lrintf(m_note_port->buffer(0)->value_at(0))) + m_gate_port->buffer(0)->set(0.0f, offset); +} + + +} // namespace Om + diff --git a/src/libs/engine/MidiTriggerNode.h b/src/libs/engine/MidiTriggerNode.h new file mode 100644 index 00000000..2f91c631 --- /dev/null +++ b/src/libs/engine/MidiTriggerNode.h @@ -0,0 +1,64 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef MIDITRIGGERNODE_H +#define MIDITRIGGERNODE_H + +#include +#include "InternalNode.h" + +using std::string; + +namespace Om { + +class MidiMessage; +template class InputPort; +template class OutputPort; + + +/** MIDI trigger input node. + * + * Just has a gate, for drums etc. A control port is used to select + * which note number is responded to. + * + * Note that this node is always monophonic, the poly parameter is ignored. + * (Should that change?) + * + * \ingroup engine + */ +class MidiTriggerNode : public InternalNode +{ +public: + MidiTriggerNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); + + void run(size_t nframes); + + void note_on(uchar note_num, uchar velocity, samplecount offset); + void note_off(uchar note_num, samplecount offset); + +private: + InputPort* m_midi_in_port; + InputPort* m_note_port; + OutputPort* m_gate_port; + OutputPort* m_trig_port; + OutputPort* m_vel_port; +}; + + +} // namespace Om + +#endif // MIDITRIGGERNODE_H diff --git a/src/libs/engine/Node.h b/src/libs/engine/Node.h new file mode 100644 index 00000000..d169e772 --- /dev/null +++ b/src/libs/engine/Node.h @@ -0,0 +1,120 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NODE_H +#define NODE_H + +#include +#include "util/types.h" +#include "OmObject.h" +#include "Array.h" + +using std::string; + +template class List; + +namespace Om { + +class Port; +template class OutputPort; +class Plugin; +class Patch; +namespace Shared { + class ClientInterface; +} + + +/** A Node (or "module") in a Patch (which is also a Node). + * + * A Node is a unit with input/output ports, a run() method, and some other + * things. + * + * This is a pure abstract base class for any Node, it contains no + * implementation details/data whatsoever. This is the interface you need to + * implement to add a new Node type to Om. + * + * \ingroup engine + */ +class Node : public OmObject +{ +public: + Node(OmObject* parent, const string& name) : OmObject(parent, name) {} + virtual ~Node() {} + + Node* as_node() { return static_cast(this); } + + /** Activate this Node. + * + * This function will be called in a non-realtime thread before it is + * inserted in to a patch. Any non-realtime actions that need to be + * done before the Node is ready for use should be done here. + */ + virtual void activate() = 0; + virtual void deactivate() = 0; + virtual bool activated() = 0; + + virtual void run(size_t nframes) = 0; + + virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) = 0; + + // FIXME: Only used by client senders. Remove? + virtual const Array& ports() const = 0; + + virtual size_t num_ports() const = 0; + virtual size_t poly() const = 0; + + /** Used by the process order finding algorithm (ie during connections) */ + virtual bool traversed() const = 0; + virtual void traversed(bool b) = 0; + + /** Nodes that are connected to this Node's inputs. + * (This Node depends on them) + */ + virtual List* providers() = 0; + virtual void providers(List* l) = 0; + + /** Nodes are are connected to this Node's outputs. + * (They depend on this Node) + */ + virtual List* dependants() = 0; + virtual void dependants(List* l) = 0; + + /** The Patch this Node belongs to. */ + virtual Patch* parent_patch() const = 0; + + /** Information about what 'plugin' this Node is an instance of. + * Not the best name - not all nodes come from plugins (ie Patch) + */ + virtual const Plugin* plugin() const = 0; + virtual void plugin(const Plugin* const pi) = 0; + + /** Add self to a Patch. + * + * This function must be realtime-safe! Any non-realtime actions that + * need to be done before adding to a patch can be done in activate(). + */ + virtual void add_to_patch() = 0; + + virtual void remove_from_patch() = 0; + + /** Send any necessary notification to client on node creation. */ + //virtual void send_creation_messages(Shared::ClientInterface* client) const = 0; +}; + + +} // namespace Om + +#endif // NODE_H diff --git a/src/libs/engine/NodeBase.cpp b/src/libs/engine/NodeBase.cpp new file mode 100644 index 00000000..b1628539 --- /dev/null +++ b/src/libs/engine/NodeBase.cpp @@ -0,0 +1,171 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NodeBase.h" +#include +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "util.h" +#include "Array.h" +#include "Plugin.h" +#include "ClientBroadcaster.h" +#include "Port.h" +#include "List.h" +#include "Patch.h" +#include "ObjectStore.h" + +using std::cout; using std::cerr; using std::endl; + +namespace Om { + + +NodeBase::NodeBase(const string& name, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: Node(parent, name), + m_poly(poly), + m_srate(srate), + m_buffer_size(buffer_size), + m_activated(false), + m_num_ports(0), + m_traversed(false), + m_providers(new List()), + m_dependants(new List()) +{ + assert(m_poly > 0); + assert(m_parent == NULL || (m_poly == parent->internal_poly() || m_poly == 1)); +} + + +NodeBase::~NodeBase() +{ + assert(!m_activated); + + delete m_providers; + delete m_dependants; + + for (size_t i=0; i < m_ports.size(); ++i) + delete m_ports.at(i); +} + + +void +NodeBase::activate() +{ + assert(!m_activated); + m_activated = true; +} + + +void +NodeBase::deactivate() +{ + assert(m_activated); + m_activated = false; +} + + +/* +void +NodeBase::send_creation_messages(ClientInterface* client) const +{ + cerr << "FIXME: send_creation\n"; + //om->client_broadcaster()->send_node_to(client, this); +} +*/ + +void +NodeBase::add_to_store() +{ + om->object_store()->add(this); + for (size_t i=0; i < num_ports(); ++i) + om->object_store()->add(m_ports.at(i)); +} + + +void +NodeBase::remove_from_store() +{ + // Remove self + TreeNode* node = om->object_store()->remove(path()); + if (node != NULL) { + assert(om->object_store()->find(path()) == NULL); + delete node; + } + + // Remove ports + for (size_t i=0; i < m_num_ports; ++i) { + node = om->object_store()->remove(m_ports.at(i)->path()); + if (node != NULL) { + assert(om->object_store()->find(m_ports.at(i)->path()) == NULL); + delete node; + } + } +} + + +/** Runs the Node for the specified number of frames (block size) + */ +void +NodeBase::run(size_t nframes) +{ + assert(m_activated); + // Mix down any ports with multiple inputs + Port* p; + for (size_t i=0; i < m_ports.size(); ++i) { + p = m_ports.at(i); + p->prepare_buffers(nframes); + } +} + + +/** Rename this Node. + * + * This is responsible for updating the ObjectStore so the Node can be + * found at it's new path, as well as all it's children. + */ +void +NodeBase::set_path(const Path& new_path) +{ + const Path old_path = path(); + //cerr << "Renaming " << old_path << " -> " << new_path << endl; + + TreeNode* treenode = NULL; + + // Reinsert ports + for (size_t i=0; i < m_num_ports; ++i) { + treenode = om->object_store()->remove(old_path +"/"+ m_ports.at(i)->name()); + assert(treenode != NULL); + assert(treenode->node() == m_ports.at(i)); + treenode->key(new_path +"/" + m_ports.at(i)->name()); + om->object_store()->add(treenode); + } + + // Rename and reinsert self + treenode = om->object_store()->remove(old_path); + assert(treenode != NULL); + assert(treenode->node() == this); + OmObject::set_path(new_path); + treenode->key(new_path); + om->object_store()->add(treenode); + + + assert(om->object_store()->find(new_path) == this); +} + + +} // namespace Om + diff --git a/src/libs/engine/NodeBase.h b/src/libs/engine/NodeBase.h new file mode 100644 index 00000000..796abbca --- /dev/null +++ b/src/libs/engine/NodeBase.h @@ -0,0 +1,105 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NODEBASE_H +#define NODEBASE_H + +#include +#include +#include "Node.h" +using std::string; + +namespace Om { + +class Plugin; +class Patch; +namespace Shared { + class ClientInterface; +} using Shared::ClientInterface; + + +/** Common implementation stuff for Node. + * + * Pretty much just attributes and getters/setters are here. + * + * \ingroup engine + */ +class NodeBase : public Node +{ +public: + NodeBase(const string& name, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); + + virtual ~NodeBase(); + + virtual void activate(); + virtual void deactivate(); + bool activated() { return m_activated; } + + virtual void run(size_t nframes); + + virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) {} + + virtual void add_to_patch() {} + virtual void remove_from_patch() {} + + void add_to_store(); + void remove_from_store(); + + //void send_creation_messages(ClientInterface* client) const; + + size_t num_ports() const { return m_num_ports; } + size_t poly() const { return m_poly; } + bool traversed() const { return m_traversed; } + void traversed(bool b) { m_traversed = b; } + + const Array& ports() const { return m_ports; } + + virtual List* providers() { return m_providers; } + virtual void providers(List* l) { m_providers = l; } + + virtual List* dependants() { return m_dependants; } + virtual void dependants(List* l) { m_dependants = l; } + + Patch* parent_patch() const { return (m_parent == NULL) ? NULL : m_parent->as_patch(); } + + virtual const Plugin* plugin() const { exit(EXIT_FAILURE); } + virtual void plugin(const Plugin* const pi) { exit(EXIT_FAILURE); } + + void set_path(const Path& new_path); + +protected: + // Disallow copies (undefined) + NodeBase(const NodeBase&); + NodeBase& operator=(const NodeBase&); + + size_t m_poly; + + samplerate m_srate; + size_t m_buffer_size; + bool m_activated; + + size_t m_num_ports; // number of ports PER VOICE + Array m_ports; + + bool m_traversed; + List* m_providers; // Nodes connected to this one's input ports + List* m_dependants; // Nodes this one's output ports are connected to +}; + + +} // namespace Om + +#endif // NODEBASE_H diff --git a/src/libs/engine/NodeFactory.cpp b/src/libs/engine/NodeFactory.cpp new file mode 100644 index 00000000..176d3f47 --- /dev/null +++ b/src/libs/engine/NodeFactory.cpp @@ -0,0 +1,707 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NodeFactory.h" +#include "config.h" +#include +#include +#include +#include +#include +#include +#include "AudioDriver.h" +#include "MidiNoteNode.h" +#include "MidiTriggerNode.h" +#include "MidiControlNode.h" +#include "AudioInputNode.h" +#include "AudioOutputNode.h" +#include "ControlInputNode.h" +#include "ControlOutputNode.h" +#include "MidiInputNode.h" +#include "MidiOutputNode.h" +#include "TransportNode.h" +#include "PluginLibrary.h" +#include "Plugin.h" +#include "Patch.h" +#include "Om.h" +#include "OmApp.h" +#ifdef HAVE_SLV2 +#include "LV2Plugin.h" +#include +#endif +#ifdef HAVE_LADSPA +#include "LADSPAPlugin.h" +#endif +#ifdef HAVE_DSSI +#include "DSSIPlugin.h" +#endif + +using std::string; +using std::cerr; using std::cout; using std::endl; + + +namespace Om { + + +/* I am perfectly aware that the vast majority of this class is a + * vomit inducing nightmare at the moment ;) + */ + + + +NodeFactory::NodeFactory() +: m_has_loaded(false) +{ + pthread_mutex_init(&m_plugin_list_mutex, NULL); + + // Add builtin plugin types to m_internal_plugins list + // FIXME: ewwww, definitely a better way to do this! + //Plugin* pi = NULL; + + Patch* parent = new Patch("dummy", 1, NULL, 1, 1, 1); + + Node* n = NULL; + n = new AudioInputNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new AudioOutputNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new ControlInputNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new ControlOutputNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new MidiInputNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new MidiOutputNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new MidiNoteNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new MidiTriggerNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new MidiControlNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + n = new TransportNode("foo", 1, parent, 1, 1); + m_internal_plugins.push_back(new Plugin(n->plugin())); + delete n; + + + delete parent; +} + + +NodeFactory::~NodeFactory() +{ + for (list::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) + delete (*i); + + for (list::iterator i = m_libraries.begin(); i != m_libraries.end(); ++i) { + (*i)->close(); + delete (*i); + } +} + + +void +NodeFactory::load_plugins() +{ + // Only load if we havn't already, so every client connecting doesn't cause + // this (expensive!) stuff to happen. Not the best solution - would be nice + // if clients could refresh plugins list for whatever reason :/ + if (!m_has_loaded) { + pthread_mutex_lock(&m_plugin_list_mutex); + + m_plugins.clear(); + m_plugins = m_internal_plugins; + +#if HAVE_SLV2 + load_lv2_plugins(); +#endif +#if HAVE_DSSI + load_dssi_plugins(); +#endif +#if HAVE_LADSPA + load_ladspa_plugins(); +#endif + + m_has_loaded = true; + + pthread_mutex_unlock(&m_plugin_list_mutex); + } +} + + +/** Loads a plugin. + * + * Calls the load_*_plugin functions to actually do things, just a wrapper. + */ +Node* +NodeFactory::load_plugin(const Plugin* a_plugin, const string& name, size_t poly, Patch* parent) +{ + assert(parent != NULL); + assert(poly == 1 || poly == parent->internal_poly()); + assert(a_plugin); + + pthread_mutex_lock(&m_plugin_list_mutex); + + Node* r = NULL; + Plugin* plugin = NULL; + + // Attempt to find the plugin in loaded DB + if (a_plugin->type() != Plugin::Internal) { + list::iterator i; + if (a_plugin->plug_label().length() == 0) { + for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { + if (a_plugin->uri() == (*i)->uri()) { + plugin = *i; + break; + } + } + } else { + for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { + if (a_plugin->uri() == (*i)->uri()) { + plugin = *i; + break; + } + } + } + + if (plugin == NULL) + return NULL; + } + + switch (a_plugin->type()) { +#if HAVE_SLV2 + case Plugin::LV2: + r = load_lv2_plugin(plugin->uri(), name, poly, parent); + break; +#endif +#if HAVE_DSSI + case Plugin::DSSI: + r = load_dssi_plugin(plugin->uri(), name, poly, parent); + break; +#endif +#if HAVE_LADSPA + case Plugin::LADSPA: + r = load_ladspa_plugin(plugin->uri(), name, poly, parent); + break; +#endif + case Plugin::Internal: + r = load_internal_plugin(a_plugin->uri(), name, poly, parent); + break; + default: + cerr << "[NodeFactory] WARNING: Unknown plugin type." << endl; + } + + pthread_mutex_unlock(&m_plugin_list_mutex); + + return r; +} + + +/** Loads an internal plugin. + */ +Node* +NodeFactory::load_internal_plugin(const string& uri, const string& name, size_t poly, Patch* parent) +{ + assert(parent != NULL); + assert(poly == 1 || poly == parent->internal_poly()); + assert(uri.length() > 3); + assert(uri.substr(0, 3) == "om:"); + + string plug_label = uri.substr(3); + + if (plug_label == "midi_input") { + MidiInputNode* tn = new MidiInputNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return tn; + } else if (plug_label == "midi_output") { + MidiOutputNode* tn = new MidiOutputNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return tn; + } else if (plug_label == "audio_input") { + AudioInputNode* in = new AudioInputNode(name, poly, parent, + om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return in; + } else if (plug_label == "control_input") { + ControlInputNode* in = new ControlInputNode(name, poly, parent, + om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return in; + } else if (plug_label == "audio_output") { + AudioOutputNode* on = new AudioOutputNode(name, poly, parent, + om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return on; + } else if (plug_label == "control_output") { + ControlOutputNode* on = new ControlOutputNode(name, poly, parent, + om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return on; + } else if (plug_label == "note_in" || plug_label == "midi_note_in") { + MidiNoteNode* mn = new MidiNoteNode(name, poly, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return mn; + } else if (plug_label == "trigger_in" || plug_label == "midi_trigger_in") { + MidiTriggerNode* mn = new MidiTriggerNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return mn; + } else if (plug_label == "midi_control_in") { + MidiControlNode* mn = new MidiControlNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return mn; + } else if (plug_label == "transport") { + TransportNode* tn = new TransportNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + return tn; + } else { + cerr << "Unknown internal plugin type '" << plug_label << "'" << endl; + } + + return NULL; +} + + +#ifdef HAVE_SLV2 + +/** Loads information about all LV2 plugins into internal plugin database. + */ +void +NodeFactory::load_lv2_plugins() +{ + SLV2List plugins = slv2_list_new(); + slv2_list_load_all(plugins); + + //cerr << "[NodeFactory] Found " << slv2_list_get_length(plugins) << " LV2 plugins." << endl; + + for (unsigned long i=0; i < slv2_list_get_length(plugins); ++i) { + + SLV2Plugin* lv2_plug = slv2_list_get_plugin_by_index(plugins, i); + + + //om_plug->library(plugin_library); + + const char* uri = (const char*)slv2_plugin_get_uri(lv2_plug); + //cerr << "LV2 plugin: " << uri << endl; + + bool found = false; + for (list::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) { + if (!strcmp((*i)->uri().c_str(), uri)) { + cerr << "Warning: Duplicate LV2 plugin (" << uri << ").\nUsing " + << (*i)->lib_path() << " version." << endl; + found = true; + break; + } + } + if (!found) { + //printf("[NodeFactory] Found LV2 plugin %s\n", uri); + Plugin* om_plug = new Plugin(); + om_plug->type(Plugin::LV2); + om_plug->slv2_plugin(lv2_plug); + om_plug->uri(uri); + // FIXME FIXME FIXME temporary hack + om_plug->library(NULL); + om_plug->lib_path("FIXMEpath"); + om_plug->plug_label("FIXMElabel"); + unsigned char* name = slv2_plugin_get_name(lv2_plug); + om_plug->name((char*)name); + free(name); + om_plug->type(Plugin::LV2); + m_plugins.push_back(om_plug); + } + } + + slv2_list_free(plugins); +} + + +/** Loads a LV2 plugin. + * Returns 'poly' independant plugins as a Node* + */ +Node* +NodeFactory::load_lv2_plugin(const string& plug_uri, + const string& node_name, + size_t poly, + Patch* parent) +{ + // Find (Om) Plugin + Plugin* plugin = NULL; + list::iterator i; + for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { + plugin = (*i); + if ((*i)->uri() == plug_uri) break; + } + + Node* n = NULL; + + if (plugin) { + n = new Om::LV2Plugin(node_name, poly, parent, plugin->slv2_plugin(), + om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + bool success = ((LV2Plugin*)n)->instantiate(); + if (!success) { + delete n; + n = NULL; + } + n->plugin(plugin); + } + + return n; +} + +#endif // HAVE_SLV2 + + +#if HAVE_DSSI + +/** Loads information about all DSSI plugins into internal plugin database. + */ +void +NodeFactory::load_dssi_plugins() +{ + // FIXME: too much code duplication with load_ladspa_plugin + + char* env_dssi_path = getenv("DSSI_PATH"); + string dssi_path; + if (!env_dssi_path) { + cerr << "[NodeFactory] DSSI_PATH is empty. Assuming /usr/lib/dssi:/usr/local/lib/dssi:~/.dssi" << endl; + dssi_path = string("/usr/lib/dssi:/usr/local/lib/dssi:").append( + getenv("HOME")).append("/.dssi"); + } else { + dssi_path = env_dssi_path; + } + + DSSI_Descriptor_Function df = NULL; + DSSI_Descriptor* descriptor = NULL; + + string dir; + string full_lib_name; + + // Yep, this should use an sstream alright.. + while (dssi_path != "") { + dir = dssi_path.substr(0, dssi_path.find(':')); + if (dssi_path.find(':') != string::npos) + dssi_path = dssi_path.substr(dssi_path.find(':')+1); + else + dssi_path = ""; + + DIR* pdir = opendir(dir.c_str()); + if (pdir == NULL) { + //cerr << "[NodeFactory] Unreadable directory in DSSI_PATH: " << dir.c_str() << endl; + continue; + } + + struct dirent* pfile; + while ((pfile = readdir(pdir))) { + + if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, "..")) + continue; + + full_lib_name = dir +"/"+ pfile->d_name; + + // Load descriptor function + // Loaded with LAZY here, will be loaded with NOW on node loading + void* handle = dlopen(full_lib_name.c_str(), RTLD_LAZY); + if (handle == NULL) + continue; + + df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor"); + if (df == NULL) { + // Not a DSSI plugin library + dlclose(handle); + continue; + } + + PluginLibrary* plugin_library = new PluginLibrary(full_lib_name); + m_libraries.push_back(plugin_library); + + const LADSPA_Descriptor* ld = NULL; + + for (unsigned long i=0; (descriptor = (DSSI_Descriptor*)df(i)) != NULL; ++i) { + ld = descriptor->LADSPA_Plugin; + assert(ld != NULL); + Plugin* plugin = new Plugin(); + assert(plugin_library != NULL); + plugin->library(plugin_library); + plugin->lib_path(dir + "/" + pfile->d_name); + plugin->plug_label(ld->Label); + plugin->name(ld->Name); + plugin->type(Plugin::DSSI); + plugin->id(ld->UniqueID); + + bool found = false; + for (list::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) { + if ((*i)->uri() == plugin->uri()) { + cerr << "Warning: Duplicate DSSI plugin (" << plugin->lib_name() << ":" + << plugin->plug_label() << ")" << " found.\nUsing " << (*i)->lib_path() + << " version." << endl; + found = true; + break; + } + } + if (!found) + m_plugins.push_back(plugin); + else + delete plugin; + } + + df = NULL; + descriptor = NULL; + dlclose(handle); + } + closedir(pdir); + } +} + + +/** Creates a Node by instancing a DSSI plugin. + */ +Node* +NodeFactory::load_dssi_plugin(const string& uri, + const string& name, size_t poly, Patch* parent) +{ + // FIXME: awful code duplication here + + assert(uri != ""); + assert(name != ""); + assert(poly > 0); + + DSSI_Descriptor_Function df = NULL; + const Plugin* plugin = NULL; + Node* n = NULL; + void* handle = NULL; + + // Attempt to find the lib + list::iterator i; + for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { + plugin = (*i); + if (plugin->uri() == uri) break; + } + + assert(plugin->id() != 0); + + if (i == m_plugins.end()) { + cerr << "Did not find DSSI plugin " << uri << " in database." << endl; + return NULL; + } else { + assert(plugin != NULL); + plugin->library()->open(); + handle = plugin->library()->handle(); + assert(handle != NULL); + + // Load descriptor function + dlerror(); + df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor"); + if (df == NULL || dlerror() != NULL) { + cerr << "Looks like this isn't a DSSI plugin." << endl; + return NULL; + } + } + + // Attempt to find the plugin in lib + DSSI_Descriptor* descriptor = NULL; + for (unsigned long i=0; (descriptor = (DSSI_Descriptor*)df(i)) != NULL; ++i) { + if (descriptor->LADSPA_Plugin != NULL + && descriptor->LADSPA_Plugin->UniqueID == plugin->id()) { + break; + } + } + + if (descriptor == NULL) { + cerr << "Could not find plugin \"" << plugin->id() << "\" in " << plugin->lib_name() << endl; + return NULL; + } + + n = new DSSIPlugin(name, poly, parent, descriptor, + om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + bool success = ((DSSIPlugin*)n)->instantiate(); + if (!success) { + delete n; + n = NULL; + } + + n->plugin(plugin); + + return n; +} +#endif // HAVE_DSSI + + +#ifdef HAVE_LADSPA +/** Loads information about all LADSPA plugins into internal plugin database. + */ +void +NodeFactory::load_ladspa_plugins() +{ + char* env_ladspa_path = getenv("LADSPA_PATH"); + string ladspa_path; + if (!env_ladspa_path) { + cerr << "[NodeFactory] LADSPA_PATH is empty. Assuming /usr/lib/ladspa:/usr/local/lib/ladspa:~/.ladspa" << endl; + ladspa_path = string("/usr/lib/ladspa:/usr/local/lib/ladspa:").append( + getenv("HOME")).append("/.ladspa"); + } else { + ladspa_path = env_ladspa_path; + } + + LADSPA_Descriptor_Function df = NULL; + LADSPA_Descriptor* descriptor = NULL; + + string dir; + string full_lib_name; + + // Yep, this should use an sstream alright.. + while (ladspa_path != "") { + dir = ladspa_path.substr(0, ladspa_path.find(':')); + if (ladspa_path.find(':') != string::npos) + ladspa_path = ladspa_path.substr(ladspa_path.find(':')+1); + else + ladspa_path = ""; + + DIR* pdir = opendir(dir.c_str()); + if (pdir == NULL) { + //cerr << "[NodeFactory] Unreadable directory in LADSPA_PATH: " << dir.c_str() << endl; + continue; + } + + struct dirent* pfile; + while ((pfile = readdir(pdir))) { + + if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, "..")) + continue; + + full_lib_name = dir +"/"+ pfile->d_name; + + // Load descriptor function + // Loaded with LAZY here, will be loaded with NOW on node loading + void* handle = dlopen(full_lib_name.c_str(), RTLD_LAZY); + if (handle == NULL) + continue; + + df = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor"); + if (df == NULL) { + dlclose(handle); + continue; + } + + PluginLibrary* plugin_library = new PluginLibrary(full_lib_name); + m_libraries.push_back(plugin_library); + + for (unsigned long i=0; (descriptor = (LADSPA_Descriptor*)df(i)) != NULL; ++i) { + Plugin* plugin = new Plugin(); + assert(plugin_library != NULL); + plugin->library(plugin_library); + plugin->lib_path(dir + "/" + pfile->d_name); + plugin->plug_label(descriptor->Label); + plugin->name(descriptor->Name); + plugin->type(Plugin::LADSPA); + plugin->id(descriptor->UniqueID); + + bool found = false; + for (list::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) { + if ((*i)->uri() == plugin->uri()) { + cerr << "Warning: Duplicate LADSPA plugin " << plugin->uri() + << " found.\nChoosing " << (*i)->lib_path() + << " over " << plugin->lib_path() << endl; + found = true; + break; + } + } + if (!found) + m_plugins.push_back(plugin); + else + delete plugin; + } + + df = NULL; + descriptor = NULL; + dlclose(handle); + } + closedir(pdir); + } +} + + +/** Loads a LADSPA plugin. + * Returns 'poly' independant plugins as a Node* + */ +Node* +NodeFactory::load_ladspa_plugin(const string& uri, + const string& name, size_t poly, Patch* parent) +{ + assert(uri != ""); + assert(name != ""); + assert(poly > 0); + + LADSPA_Descriptor_Function df = NULL; + Plugin* plugin = NULL; + Node* n = NULL; + void* plugin_lib = NULL; + + // Attempt to find the lib + list::iterator i; + for (i = m_plugins.begin(); i != m_plugins.end(); ++i) { + plugin = (*i); + if (plugin->uri() == uri) break; + } + + assert(plugin->id() != 0); + + if (i == m_plugins.end()) { + cerr << "Did not find LADSPA plugin " << uri << " in database." << endl; + return NULL; + } else { + assert(plugin != NULL); + plugin->library()->open(); + plugin_lib = plugin->library()->handle(); + assert(plugin_lib != NULL); + + // Load descriptor function + dlerror(); + df = (LADSPA_Descriptor_Function)dlsym(plugin_lib, "ladspa_descriptor"); + if (df == NULL || dlerror() != NULL) { + cerr << "Looks like this isn't a LADSPA plugin." << endl; + return NULL; + } + } + + // Attempt to find the plugin in lib + LADSPA_Descriptor* descriptor = NULL; + for (unsigned long i=0; (descriptor = (LADSPA_Descriptor*)df(i)) != NULL; ++i) { + if (descriptor->UniqueID == plugin->id()) { + break; + } + } + + if (descriptor == NULL) { + cerr << "Could not find plugin \"" << plugin->id() << "\" in " << plugin->lib_path() << endl; + return NULL; + } + + n = new LADSPAPlugin(name, poly, parent, descriptor, + om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size()); + bool success = ((LADSPAPlugin*)n)->instantiate(); + if (!success) { + delete n; + n = NULL; + } + + n->plugin(plugin); + + return n; +} + + +#endif // HAVE_LADSPA + + +} // namespace Om diff --git a/src/libs/engine/NodeFactory.h b/src/libs/engine/NodeFactory.h new file mode 100644 index 00000000..ed6a35dc --- /dev/null +++ b/src/libs/engine/NodeFactory.h @@ -0,0 +1,93 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef NODEFACTORY_H +#define NODEFACTORY_H + +#include "config.h" +#include +#include +#include +#include + +using std::string; using std::list; + +namespace Om { + +class Node; +class PortInfo; +class Patch; +class PluginLibrary; +class Plugin; + + +/** Loads plugins and creates Nodes from them. + * + * NodeFactory's responsibility is to get enough information to allow the + * loading of a plugin possible (ie finding/opening shared libraries etc) + * + * The constructor of various Node types (ie LADSPAPlugin) are responsible + * for actually creating a Node instance of the plugin. + * + * \ingroup engine + */ +class NodeFactory +{ +public: + NodeFactory(); + ~NodeFactory(); + + void load_plugins(); + Node* load_plugin(const Plugin* info, const string& name, size_t poly, Patch* parent); + + const list& plugins() { return m_plugins; } + + void lock_plugin_list() { pthread_mutex_lock(&m_plugin_list_mutex); } + void unlock_plugin_list() { pthread_mutex_unlock(&m_plugin_list_mutex); } + +private: +#ifdef HAVE_LADSPA + void load_ladspa_plugins(); + Node* load_ladspa_plugin(const string& plugin_uri, const string& name, size_t poly, Patch* parent); +#endif + +#ifdef HAVE_SLV2 + void load_lv2_plugins(); + Node* load_lv2_plugin(const string& plugin_uri, const string& name, size_t poly, Patch* parent); +#endif + +#ifdef HAVE_DSSI + void load_dssi_plugins(); + Node* load_dssi_plugin(const string& plugin_uri, const string& name, size_t poly, Patch* parent); +#endif + + Node* load_internal_plugin(const string& plug_label, const string& name, size_t poly, Patch* parent); + + list m_libraries; + list m_internal_plugins; + list m_plugins; + + /** Used to protect the list while load_plugins is building it. */ + pthread_mutex_t m_plugin_list_mutex; + + bool m_has_loaded; +}; + + +} // namespace Om + +#endif // NODEFACTORY_H diff --git a/src/libs/engine/OSCClient.cpp b/src/libs/engine/OSCClient.cpp new file mode 100644 index 00000000..332a2144 --- /dev/null +++ b/src/libs/engine/OSCClient.cpp @@ -0,0 +1,503 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OSCClient.h" +#include +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "ObjectStore.h" +#include "NodeFactory.h" +#include "util.h" +#include "Patch.h" +#include "Node.h" +#include "PortInfo.h" +#include "Plugin.h" +#include "PortBase.h" +#include "Connection.h" +#include "AudioDriver.h" +#include "interface/ClientInterface.h" +#include "Responder.h" + +using std::cout; using std::cerr; using std::endl; + +namespace Om { + + +/*! \page client_osc_namespace Client OSC Namespace Documentation + * + *

These are all the messages sent from the engine to the client. Om + * communication takes place over two distinct bands: control band and + * notification band.

+ *

The control band is where clients send commands, and receive a simple + * response, either OK or an error.

+ *

All notifications of engine state (ie new nodes) are sent over the + * notification band which is seperate from the control band. The + * reasoning behind this is that many clients may be connected at the same + * time - a client may receive notifications that are not a direct consequence + * of some message it sent.

+ *

The notification band can be thought of as a stream of events representing + * the changing engine state. For example, It is possible for a client to send + * commands and receive aknowledgements, and not listen to the notification band + * at all; or (in the near future anyway) for a client to use UDP for the control + * band (for speed), and TCP for the notification band (for reliability and + * order guarantees).

+ * \n\n + */ + + +/* Documentation for namespace portion implemented in Responder.cpp */ + +/** \page client_osc_namespace + * \n + *

Notification Band

+ */ + +/** \page client_osc_namespace + *

\b /om/response/ok - Respond successfully to a user command + * \arg \b responder-id (int) - Responder ID this is a response to + *

\n \n + */ + +/** \page client_osc_namespace + *

\b /om/response/error - Respond negatively to a user command + * \arg \b responder-id (int) - Request ID this is a response to + * \arg \b message (string) - Error message (natural language text) + *

\n \n + */ + + + +/** \page client_osc_namespace + * \n + *

Notification Band

+ */ + +/** \page client_osc_namespace + *

\b /om/error - Notification that an error has occurred + * \arg \b message (string) - Error message (natural language text) + * + * \li This is for notification of errors that aren't a direct response to a + * user command, ie "unexpected" errors.

\n \n + */ +void +OSCClient::error(const string& msg) +{ + lo_send(_address, "/om/error", "s", msg.c_str()); +} + + +/** \page client_osc_namespace + *

\b /om/num_plugins + * \arg \b num (int) - Number of plugins engine has loaded + * \li This is sent before sending the list of plugins, so the client is aware + * of how many plugins (/om/plugin messages) to expect.

\n \n + */ + + +/** \page client_osc_namespace + *

\b /om/num_plugins + * \arg \b num (int) - Number of plugins engine has loaded + * \li This is sent before sending the list of plugins, so the client is aware + * of how many plugins (/om/plugin messages) to expect.

\n \n + */ +void +OSCClient::num_plugins(uint32_t num) +{ + lo_message m = lo_message_new(); + lo_message_add_int32(m, num); + lo_send_message(_address, "/om/num_plugins", m); +} + + +/** \page client_osc_namespace + *

\b /om/plugin - Notification of the existance of a plugin + * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal") + * \arg \b uri (string) - URI of the plugin (see engine namespace documentation) \n + * \arg \b lib-name (string) - Name of shared library plugin resides in (ie "cmt.so") + * \arg \b plug-label (string) - Label of the plugin (ie "dahdsr_iaoa") + * \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope") + *

\n \n + */ +/* +void +OSCClient::plugins() +{ + om->node_factory()->lock_plugin_list(); + + const list& plugs = om->node_factory()->plugins(); + const Plugin* plugin; + + lo_timetag tt; + lo_timetag_now(&tt); + lo_bundle b = lo_bundle_new(tt); + lo_message m = lo_message_new(); + list msgs; + + lo_message_add_int32(m, plugs.size()); + lo_bundle_add_message(b, "/om/num_plugins", m); + msgs.push_back(m); + + for (list::const_iterator j = plugs.begin(); j != plugs.end(); ++j) { + plugin = (*j); + m = lo_message_new(); + + lo_message_add_string(m, plugin->type_string()); + lo_message_add_string(m, plugin->uri().c_str()); + lo_message_add_string(m, plugin->plug_label().c_str()); + lo_message_add_string(m, plugin->name().c_str()); + lo_bundle_add_message(b, "/om/plugin", m); + msgs.push_back(m); + if (lo_bundle_length(b) > 1024) { + lo_send_bundle(_address, b); + lo_bundle_free(b); + b = lo_bundle_new(tt); + } + } + + if (lo_bundle_length(b) > 0) { + lo_send_bundle(_address, b); + lo_bundle_free(b); + } else { + lo_bundle_free(b); + } + for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i) + lo_message_free(*i); + + om->node_factory()->unlock_plugin_list(); +} +*/ + +/** \page client_osc_namespace + *

\b /om/new_node - Notification of a new node's creation. + * \arg \b plug-uri (string) - URI of the plugin new node is an instance of + * \arg \b path (string) - Path of the new node + * \arg \b polyphonic (integer-boolean) - Node is polyphonic (1 = yes, 0 = no) + * \arg \b num-ports (integer) - Number of ports (number of new_port messages to expect) + * \li New nodes are sent as a bundle. The first message in the bundle will be + * this one (/om/new_node), followed by a series of /om/new_port commands, + * followed by /om/new_node_end.

\n \n + */ +void OSCClient::new_node(const string& plugin_type, + const string& plugin_uri, + const string& node_path, + bool is_polyphonic, + uint32_t num_ports) +{ + lo_send(_address, "/om/new_node", "sssii", plugin_type.c_str(), plugin_uri.c_str(), + node_path.c_str(), is_polyphonic ? 1 : 0, num_ports); +#if 0 + /* + lo_timetag tt; + lo_timetag_now(&tt); + lo_bundle b = lo_bundle_new(tt); + lo_message m = lo_message_new(); + list msgs; + + lo_message_add_string(m, plugin_type.c_str()); + lo_message_add_string(m, plugin_uri.c_str()); + lo_message_add_string(m, node_path.c_str()); + lo_message_add_int32(m, is_polyphonic ? 1 : 0); + lo_message_add_int32(m, num_ports); + + lo_bundle_add_message(b, "/om/new_node", m); + msgs.push_back(m); +*/ + + + /* + const Array& ports = node->ports(); + Port* port; + PortInfo* info; + for (size_t j=0; j < ports.size(); ++j) { + port = ports.at(j); + info = port->port_info(); + + assert(port != NULL); + assert(info != NULL); + + m = lo_message_new(); + lo_message_add_string(m, port->path().c_str()); + lo_message_add_string(m, info->type_string().c_str()); + lo_message_add_string(m, info->direction_string().c_str()); + lo_message_add_string(m, info->hint_string().c_str()); + lo_message_add_float(m, info->default_val()); + lo_message_add_float(m, info->min_val()); + lo_message_add_float(m, info->max_val()); + lo_bundle_add_message(b, "/om/new_port", m); + msgs.push_back(m); + + // If the bundle is getting very large, send it and start + // a new one + if (lo_bundle_length(b) > 1024) { + lo_send_bundle(_address, b); + lo_bundle_free(b); + b = lo_bundle_new(tt); + } + } +*/ + /*m = lo_message_new(); + //lo_bundle_add_message(b, "/om/new_node_end", m); + //msgs.push_back(m); + + lo_send_bundle(_address, b); + lo_bundle_free(b); + + for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i) + lo_message_free(*i); + + usleep(100); +*/ + /* + const map& data = node->metadata(); + // Send node metadata + for (map::const_iterator i = data.begin(); i != data.end(); ++i) + metadata_update(node->path(), (*i).first, (*i).second); + + + // Send port metadata + for (size_t j=0; j < ports.size(); ++j) { + port = ports.at(j); + const map& data = port->metadata(); + for (map::const_iterator i = data.begin(); i != data.end(); ++i) + metadata_update(port->path(), (*i).first, (*i).second); + } + + // Send control values + for (size_t i=0; i < node->ports().size(); ++i) { + PortBase* port = (PortBase*)node->ports().at(i); + if (port->port_info()->is_input() && port->port_info()->is_control()) + control_change(port->path(), port->buffer(0)->value_at(0)); + } + */ +#endif +} + + + +/** \page client_osc_namespace + *

\b /om/new_port - Notification of a new port's creation. + * \arg \b path (string) - Path of new port + * \arg \b data-type (string) - Type of port (CONTROL or AUDIO) + * \arg \b direction ("is-output") (integer) - Direction of data flow (Input = 0, Output = 1) + * + * \li Note that in the event of loading a patch, this message could be + * followed immediately by a control change, meaning the default-value is + * not actually the current value of the port. + * \li The minimum and maximum values are suggestions only, they are not + * enforced in any way, and going outside them is perfectly fine. Also note + * that the port ranges in om_gtk are not these ones! Those ranges are set + * as metadata.

\n \n + */ +void +OSCClient::new_port(const string& path, + const string& data_type, + bool is_output) +{ + //PortInfo* info = port->port_info(); + + lo_send(_address, "/om/new_port", "ssi", path.c_str(), data_type.c_str(), is_output); + + // Send metadata + /*const map& data = port->metadata(); + for (map::const_iterator i = data.begin(); i != data.end(); ++i) + metadata_update(port->path(), (*i).first, (*i).second);*/ +} + + +/** \page client_osc_namespace + *

\b /om/destroyed - Notification an object has been destroyed + * \arg \b path (string) - Path of object (which no longer exists)

\n \n + */ +void +OSCClient::object_destroyed(const string& path) +{ + assert(path != "/"); + + lo_send(_address, "/om/destroyed", "s", path.c_str()); +} + + +/** \page client_osc_namespace + *

\b /om/patch_cleared - Notification a patch has been cleared (all children destroyed) + * \arg \b path (string) - Path of patch (which is now empty)

\n \n + */ +void +OSCClient::patch_cleared(const string& patch_path) +{ + lo_send(_address, "/om/patch_cleared", "s", patch_path.c_str()); +} + + +/** \page client_osc_namespace + *

\b /om/patch_enabled - Notification a patch's DSP processing has been enabled. + * \arg \b path (string) - Path of enabled patch

\n \n + */ +void +OSCClient::patch_enabled(const string& patch_path) +{ + lo_send(_address, "/om/patch_enabled", "s", patch_path.c_str()); +} + + +/** \page client_osc_namespace + *

\b /om/patch_disabled - Notification a patch's DSP processing has been disabled. + * \arg \b path (string) - Path of disabled patch

\n \n + */ +void +OSCClient::patch_disabled(const string& patch_path) +{ + lo_send(_address, "/om/patch_disabled", "s", patch_path.c_str()); +} + + +/** \page client_osc_namespace + *

\b /om/new_connection - Notification a new connection has been made. + * \arg \b src-path (string) - Path of the source port + * \arg \b dst-path (string) - Path of the destination port

\n \n + */ +void +OSCClient::connection(const string& src_port_path, const string& dst_port_path) +{ + lo_send(_address, "/om/new_connection", "ss", src_port_path.c_str(), dst_port_path.c_str()); +} + + +/** \page client_osc_namespace + *

\b /om/disconnection - Notification a connection has been unmade. + * \arg \b src-path (string) - Path of the source port + * \arg \b dst-path (string) - Path of the destination port

\n \n + */ +void +OSCClient::disconnection(const string& src_port_path, const string& dst_port_path) +{ + lo_send(_address, "/om/disconnection", "ss", src_port_path.c_str(), dst_port_path.c_str()); +} + + +/** \page client_osc_namespace + *

\b /om/metadata/update - Notification of a piece of metadata. + * \arg \b path (string) - Path of the object associated with metadata (can be a node, patch, or port) + * \arg \b key (string) + * \arg \b value (string)

\n \n + */ +void +OSCClient::metadata_update(const string& path, const string& key, const string& value) +{ + lo_send(_address, "/om/metadata/update", "sss", path.c_str(), key.c_str(), value.c_str()); +} + + +/** \page client_osc_namespace + *

\b /om/control_change - Notification the value of a port has changed + * \arg \b path (string) - Path of port + * \arg \b value (float) - New value of port + * + * \li This will only send updates for values set by clients of course - not values + * changing because of connections to other ports!

\n \n + */ +void +OSCClient::control_change(const string& port_path, float value) +{ + lo_send(_address, "/om/control_change", "sf", port_path.c_str(), value); +} + + +/** \page client_osc_namespace + *

\b /om/plugin - Notification of the existance of a plugin + * \arg \b type (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")

\n \n + * \arg \b uri (string) - Type if plugin ("LADSPA", "DSSI", or "Internal")

\n \n + * \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope") + */ +void +OSCClient::new_plugin(const string& type, const string& uri, const string& name) +{ + lo_message m = lo_message_new(); + lo_message_add_string(m, type.c_str()); + lo_message_add_string(m, uri.c_str()); + lo_message_add_string(m, name.c_str()); + lo_send_message(_address, "/om/plugin", m); +} + + +/** \page client_osc_namespace + *

\b /om/new_patch - Notification of a new patch + * \arg \b path (string) - Path of new patch + * \arg \b poly (int) - Polyphony of new patch (\em not a boolean like new_node)

\n \n + */ +void +OSCClient::new_patch(const string& path, uint32_t poly) +{ + lo_send(_address, "/om/new_patch", "si", path.c_str(), poly); + + /* + if (p->process()) + patch_enabled(p->path()); + + // Send metadata + const map& data = p->metadata(); + for (map::const_iterator i = data.begin(); i != data.end(); ++i) { + metadata_update(p->path(), (*i).first, (*i).second); + } + */ +} + + +/** \page client_osc_namespace + *

\b /om/object_renamed - Notification of an object's renaming + * \arg \b old-path (string) - Old path of object + * \arg \b new-path (string) - New path of object

\n \n + */ +void +OSCClient::object_renamed(const string& old_path, const string& new_path) +{ + lo_send(_address, "/om/object_renamed", "ss", old_path.c_str(), new_path.c_str()); +} + + +/** Sends all OmObjects known to the engine. + */ +/* +void +OSCClient::all_objects() +{ + for (Tree::iterator i = om->object_store()->objects().begin(); + i != om->object_store()->objects().end(); ++i) + if ((*i)->as_node() != NULL && (*i)->parent() == NULL) + (*i)->as_node()->send_creation_messages(this); +} +*/ + +/** Sends information about a program associated with a DSSI plugin node. + */ +void +OSCClient::program_add(const string& node_path, uint32_t bank, uint32_t program, const string& name) +{ + lo_send(_address, "/om/program_add", "siis", + node_path.c_str(), bank, program, name.c_str()); +} + + +void +OSCClient::program_remove(const string& node_path, uint32_t bank, uint32_t program) +{ + lo_send(_address, "/om/program_remove", "sii", + node_path.c_str(), bank, program); +} + + +} // namespace Om diff --git a/src/libs/engine/OSCClient.h b/src/libs/engine/OSCClient.h new file mode 100644 index 00000000..db14c696 --- /dev/null +++ b/src/libs/engine/OSCClient.h @@ -0,0 +1,131 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OSCCLIENT_H +#define OSCCLIENT_H + +#include +#include +#include +#include +#include +#include "util/types.h" +#include "interface/ClientInterface.h" + +using std::list; using std::string; +using std::cerr; + +namespace Om { + + +/** Implements ClientInterface for OSC clients (sends OSC messages). + * + * \ingroup engine + */ +class OSCClient : public Shared::ClientInterface +{ +public: + OSCClient(const string& url) + : _url(url), + _address(lo_address_new_from_url(url.c_str())) + {} + + virtual ~OSCClient() + { lo_address_free(_address); } + + const string& url() const { return _url; } + const lo_address address() const { return _address; } + + //void plugins(); // FIXME remove + + + + /* *** ClientInterface Implementation Below *** */ + + + //void client_registration(const string& url, int client_id); + + // need a liblo feature to make this possible :/ + void bundle_begin() {} + void bundle_end() {} + + void num_plugins(uint32_t num); + + void error(const string& msg); + + virtual void new_plugin(const string& type, + const string& uri, + const string& name); + + virtual void new_patch(const string& path, uint32_t poly); + + virtual void new_node(const string& plugin_type, + const string& plugin_uri, + const string& node_path, + bool is_polyphonic, + uint32_t num_ports); + + virtual void new_port(const string& path, + const string& data_type, + bool is_output); + + virtual void patch_enabled(const string& path); + + virtual void patch_disabled(const string& path); + + virtual void patch_cleared(const string& path); + + virtual void object_destroyed(const string& path); + + virtual void object_renamed(const string& old_path, + const string& new_path); + + virtual void connection(const string& src_port_path, + const string& dst_port_path); + + virtual void disconnection(const string& src_port_path, + const string& dst_port_path); + + virtual void metadata_update(const string& subject_path, + const string& predicate, + const string& value); + + virtual void control_change(const string& port_path, + float value); + + virtual void program_add(const string& node_path, + uint32_t bank, + uint32_t program, + const string& program_name); + + virtual void program_remove(const string& node_path, + uint32_t bank, + uint32_t program); + +private: + // Prevent copies (undefined) + OSCClient(const OSCClient&); + OSCClient& operator=(const OSCClient&); + + string _url; + lo_address _address; +}; + + +} // namespace Om + +#endif // OSCCLIENT_H + diff --git a/src/libs/engine/OSCReceiver.cpp b/src/libs/engine/OSCReceiver.cpp new file mode 100644 index 00000000..8edab8b1 --- /dev/null +++ b/src/libs/engine/OSCReceiver.cpp @@ -0,0 +1,926 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OSCReceiver.h" +#include +#include +#include +#include +#include "util/types.h" +#include "Om.h" +#include "OmApp.h" +#include "util/Queue.h" +#include "util/CountedPtr.h" +#include "QueuedEventSource.h" +#include "interface/ClientKey.h" +#include "interface/ClientInterface.h" +#include "OSCClient.h" +#include "OSCResponder.h" +#include "ClientBroadcaster.h" +#include "Plugin.h" + +using std::cerr; using std::cout; using std::endl; + +namespace Om { + +using Shared::ClientKey; + + +/*! \page engine_osc_namespace Engine OSC Namespace Documentation + * + *

These are the commands the engine recognizes. A client can control every + * aspect of the engine entirely with these commands.

+ * + *

All commands on this page are in the "control band". If a client needs to + * know about the state of the engine, it must listen to the "notification band". + * See the "Client OSC Namespace Documentation" for details. + */ + + +OSCReceiver::OSCReceiver(size_t queue_size, const char* const port) +: QueuedEngineInterface(queue_size), + _port(port), + _is_activated(false), + _st(NULL), + _osc_responder(NULL) +{ + _st = lo_server_thread_new(port, error_cb); + + if (_st == NULL) { + cerr << "[OSC] Could not start OSC server. Aborting." << endl; + exit(EXIT_FAILURE); + } else { + char* lo_url = lo_server_thread_get_url(_st); + cout << "[OSC] Started OSC server at " << lo_url << endl; + free(lo_url); + } + + // For debugging, print all incoming OSC messages + lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL); + + // Set response address for this message. + // It's important this is first and returns nonzero. + lo_server_thread_add_method(_st, NULL, NULL, set_response_address_cb, this); + + // Commands + lo_server_thread_add_method(_st, "/om/ping", "i", ping_cb, this); + lo_server_thread_add_method(_st, "/om/ping_slow", "i", ping_slow_cb, this); + lo_server_thread_add_method(_st, "/om/engine/quit", "i", quit_cb, this); + //lo_server_thread_add_method(_st, "/om/engine/register_client", "is", register_client_cb, this); + lo_server_thread_add_method(_st, "/om/engine/register_client", "i", register_client_cb, this); + lo_server_thread_add_method(_st, "/om/engine/unregister_client", "i", unregister_client_cb, this); + lo_server_thread_add_method(_st, "/om/engine/load_plugins", "i", load_plugins_cb, this); + lo_server_thread_add_method(_st, "/om/engine/activate", "i", engine_activate_cb, this); + lo_server_thread_add_method(_st, "/om/engine/deactivate", "i", engine_deactivate_cb, this); + lo_server_thread_add_method(_st, "/om/synth/create_patch", "isi", create_patch_cb, this); + lo_server_thread_add_method(_st, "/om/synth/enable_patch", "is", enable_patch_cb, this); + lo_server_thread_add_method(_st, "/om/synth/disable_patch", "is", disable_patch_cb, this); + lo_server_thread_add_method(_st, "/om/synth/clear_patch", "is", clear_patch_cb, this); + lo_server_thread_add_method(_st, "/om/synth/create_node", "issssi", create_node_cb, this); + lo_server_thread_add_method(_st, "/om/synth/create_node", "isssi", create_node_by_uri_cb, this); + lo_server_thread_add_method(_st, "/om/synth/destroy", "is", destroy_cb, this); + lo_server_thread_add_method(_st, "/om/synth/rename", "iss", rename_cb, this); + lo_server_thread_add_method(_st, "/om/synth/connect", "iss", connect_cb, this); + lo_server_thread_add_method(_st, "/om/synth/disconnect", "iss", disconnect_cb, this); + lo_server_thread_add_method(_st, "/om/synth/disconnect_all", "is", disconnect_all_cb, this); + lo_server_thread_add_method(_st, "/om/synth/set_port_value", "isf", set_port_value_cb, this); + lo_server_thread_add_method(_st, "/om/synth/set_port_value", "isif", set_port_value_voice_cb, this); + lo_server_thread_add_method(_st, "/om/synth/set_port_value_slow", "isf", set_port_value_slow_cb, this); + lo_server_thread_add_method(_st, "/om/synth/note_on", "isii", note_on_cb, this); + lo_server_thread_add_method(_st, "/om/synth/note_off", "isi", note_off_cb, this); + lo_server_thread_add_method(_st, "/om/synth/all_notes_off", "isi", all_notes_off_cb, this); + lo_server_thread_add_method(_st, "/om/synth/midi_learn", "is", midi_learn_cb, this); +#ifdef HAVE_LASH + lo_server_thread_add_method(_st, "/om/lash/restore_finished", "i", lash_restore_done_cb, this); +#endif + + lo_server_thread_add_method(_st, "/om/metadata/request", "isss", metadata_get_cb, this); + lo_server_thread_add_method(_st, "/om/metadata/set", "isss", metadata_set_cb, this); + + // Queries + lo_server_thread_add_method(_st, "/om/request/plugins", "i", request_plugins_cb, this); + lo_server_thread_add_method(_st, "/om/request/all_objects", "i", request_all_objects_cb, this); + lo_server_thread_add_method(_st, "/om/request/port_value", "is", request_port_value_cb, this); + + // DSSI support +#ifdef HAVE_DSSI + // XXX WARNING: notice this is a catch-all + lo_server_thread_add_method(_st, NULL, NULL, dssi_cb, this); +#endif + + lo_server_thread_add_method(_st, NULL, NULL, unknown_cb, NULL); +} + + +OSCReceiver::~OSCReceiver() +{ + deactivate(); + + if (_st != NULL) { + lo_server_thread_free(_st); + _st = NULL; + } +} + + +void +OSCReceiver::start() +{ + QueuedEventSource::start(); + + if (!_is_activated) { + lo_server_thread_start(_st); + _is_activated = true; + } + + /* Waiting on the next liblo release + pthread_t lo_thread = lo_server_thread_get_thread(_st); + + sched_param sp; + sp.sched_priority = 20; + int result = pthread_setschedparam(lo_thread, SCHED_FIFO, &sp); + if (!result) + cout << "[OSC] Set OSC thread to realtime scheduling (SCHED_FIFO, priority " + << sp.sched_priority << ")" << endl; + else + cout << "[OSC] Unable to set OSC thread to realtime scheduling (" + << strerror(result) << endl; + */ +} + + +void +OSCReceiver::stop() +{ + if (_is_activated) { + lo_server_thread_stop(_st); + cout << "[OSCReceiver] Stopped OSC server thread" << endl; + _is_activated = false; + } + QueuedEventSource::stop(); +} + + +/** Create a new responder for this message, if necessary. + * + * This is based on the fact that the current responder is stored in a ref + * counted pointer, and events just take a reference to that. Thus, events + * may delete their responder if we've since switched to a new one, or the + * same one can stay around and serve a series of events. Reference counting + * is pretty sweet, eh? + * + * If this message came from the same source as the last message, no allocation + * of responders or lo_addresses or any of it needs to be done. Unfortunately + * the only way to check is by comparing URLs, because liblo addresses suck. + * + * Really, this entire thing is a basically just a crafty way of partially + * working around the fact that liblo addresses really suck. Oh well. + */ +int +OSCReceiver::set_response_address_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data) +{ + OSCReceiver* const me = reinterpret_cast(user_data); + + //cerr << "SET RESPONSE\n"; + + if (argc < 1 || types[0] != 'i') // Not a valid Om message + return 0; // Save liblo the trouble + + //cerr << "** valid msg\n"; + + const int id = argv[0]->i; + + // Need to respond + if (id != -1) { + const lo_address addr = lo_message_get_source(msg); + char* const url = lo_address_get_url(addr); + + //cerr << "** need to respond\n"; + + // Currently have an OSC responder, check if it's still okay + if (me->_responder == me->_osc_responder) { + //cerr << "** osc responder\n"; + + if (!strcmp(url, me->_osc_responder->url())) { + // Nice one, same address + //cerr << "** Using cached response address, hooray" << endl; + } else { + // Shitty deal, make a new one + //cerr << "** Setting response address to " << url << "(2)" << endl; + me->_osc_responder = CountedPtr(new OSCResponder(id, url)); + me->set_responder(me->_osc_responder); + // (responder takes ownership of url, no leak) + } + + // Otherwise we have a NULL responder, definitely need to set a new one + } else { + //cerr << "** null responder\n"; + me->_osc_responder = CountedPtr(new OSCResponder(id, url)); + me->set_responder(me->_osc_responder); + //cerr << "** Setting response address to " << url << "(2)" << endl; + } + + // Don't respond + } else { + me->disable_responses(); + //cerr << "** Not responding." << endl; + } + + // If this returns 0 no OSC commands will work + return 1; +} + + +void +OSCReceiver::error_cb(int num, const char* msg, const char* path) +{ + cerr << "liblo server error " << num << " in path \"" << "\" - " << msg << endl; +} + + +/** \page engine_osc_namespace + *

\b /om/ping - Immediately sends a successful response to the given response id. + * \arg \b response-id (integer)

\n \n + */ +int +OSCReceiver::m_ping_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + _responder->respond_ok(); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/ping_slow - Sends response after going through the ("slow") event queue. + * \arg \b response-id (integer) + * + * \li See the documentation for /om/synth/set_port_value_slow for an explanation of how + * this differs from /om/ping. This is useful to send after sending a large cluster of + * events as a sentinel and wait on it's response, to know when the events are all + * finished processing.

\n \n + */ +int +OSCReceiver::m_ping_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + ping(); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/engine/quit - Terminates the engine. + * \arg \b response-id (integer) + * + * \li Note that there is NO order guarantees with this command at all. You could + * send 10 messages then quit, and the quit reply could come immediately and the + * 10 messages would never get executed.

\n \n + */ +int +OSCReceiver::m_quit_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + + quit(); + + return 0; +} + +/** \page engine_osc_namespace + *

\b /om/engine/register_client - Registers a new client with the engine + * \arg \b response-id (integer) + * + * The incoming address will be used for the new registered client. If you + * want to register a different specific address, use the URL version. + */ +int +OSCReceiver::m_register_client_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + lo_address addr = lo_message_get_source(msg); + + char* const url = lo_address_get_url(addr); + CountedPtr client(new OSCClient((const char*)url)); + register_client(ClientKey(ClientKey::OSC_URL, (const char*)url), client); + free(url); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/engine/unregister_client - Unregisters a client + * \arg \b response-id (integer)

\n \n + */ +int +OSCReceiver::m_unregister_client_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + lo_address addr = lo_message_get_source(msg); + + char* url = lo_address_get_url(addr); + unregister_client(ClientKey(ClientKey::OSC_URL, url)); + free(url); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/engine/load_plugins - Locates all available plugins, making them available for use. + * \arg \b response-id (integer)

\n \n + */ +int +OSCReceiver::m_load_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + load_plugins(); + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/engine/activate - Activate the engine (MIDI, audio, everything) + * \arg \b response-id (integer)

+ * + * \li Note that you must send this message first if you want the engine to do + * anything at all - including respond to your messages! \n \n + */ +int +OSCReceiver::m_engine_activate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + activate(); + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/engine/deactivate - Deactivate the engine completely. + * \arg \b response-id (integer)

\n \n + */ +int +OSCReceiver::m_engine_deactivate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + deactivate(); + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/create_patch - Creates a new, empty, toplevel patch. + * \arg \b response-id (integer) + * \arg \b patch-path (string) - Patch path (complete, ie /master/parent/new_patch) + * \arg \b poly (integer) - Patch's (internal) polyphony

\n \n + */ +int +OSCReceiver::m_create_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* patch_path = &argv[1]->s; + const int poly = argv[2]->i; + + create_patch(patch_path, poly); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/rename - Rename an Object (only Nodes, for now) + * \arg \b response-id (integer) + * \arg \b path - Object's path + * \arg \b name - New name for object

\n \n + */ +int +OSCReceiver::m_rename_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* object_path = &argv[1]->s; + const char* name = &argv[2]->s; + + rename(object_path, name); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/enable_patch - Enable DSP processing of a patch + * \arg \b response-id (integer) + * \arg \b patch-path - Patch's path + */ +int +OSCReceiver::m_enable_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* patch_path = &argv[1]->s; + + enable_patch(patch_path); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/disable_patch - Disable DSP processing of a patch + * \arg \b response-id (integer) + * \arg \b patch-path - Patch's path + */ +int +OSCReceiver::m_disable_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* patch_path = &argv[1]->s; + + disable_patch(patch_path); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/clear_patch - Remove all nodes from a patch + * \arg \b response-id (integer) + * \arg \b patch-path - Patch's path + */ +int +OSCReceiver::m_clear_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* patch_path = &argv[1]->s; + + clear_patch(patch_path); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/create_node - Add a node into a given patch (load a plugin by URI) + * \arg \b response-id (integer) + * \arg \b node-path (string) - Full path of the new node (ie. /patch2/subpatch/newnode) + * \arg \b type (string) - Plugin type ("Internal", "LV2", "DSSI", "LADSPA") + * \arg \b plug-uri (string) - URI of the plugin to load + * \arg \b poly (integer-boolean) - Whether node is polyphonic (0 = false, 1 = true)

\n \n + */ +int +OSCReceiver::m_create_node_by_uri_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* node_path = &argv[1]->s; + const char* type = &argv[2]->s; + const char* plug_uri = &argv[3]->s; + const int poly = argv[4]->i; + + // FIXME: make sure poly is valid + + create_node(node_path, type, plug_uri, (poly == 1)); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/create_node - Add a node into a given patch (load a plugin by libname, label) + * \arg \b response-id (integer) + * \arg \b node-path (string) - Full path of the new node (ie. /patch2/subpatch/newnode) + * \arg \b type (string) - Plugin type ("LADSPA" or "Internal") + * \arg \b lib-name (string) - Name of library where plugin resides (eg "cmt.so") + * \arg \b plug-label (string) - Label (ID) of plugin (eg "sine_fcaa") + * \arg \b poly (integer-boolean) - Whether node is polyphonic (0 = false, 1 = true) + * + * \li This is only here to provide backwards compatibility for old patches that store plugin + * references (particularly LADSPA) as libname, label. + *

\n \n + */ +int +OSCReceiver::m_create_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + /* + + const char* node_path = &argv[1]->s; + const char* type = &argv[2]->s; + const char* lib_name = &argv[3]->s; + const char* plug_label = &argv[4]->s; + const int poly = argv[5]->i; + */ + cerr << "LOAD NODE BY LIB LABEL\n"; + return 0; + #if 0 + // FIXME Event-ize + + Plugin* plugin = new Plugin(); + plugin->set_type(type); + plugin->lib_name(lib_name); + plugin->plug_label(plug_label); + + if (poly != 0 && poly != 1) { + OSCResponder(addr).respond_error("Invalid poly parameter in create_node"); + return 0; + } + + add_node(node_path, plugin, (poly == 1)); + + return 0; + #endif +} + + +/** \page engine_osc_namespace + *

\b /om/synth/destroy - Removes (destroys) a Patch or a Node + * \arg \b response-id (integer) + * \arg \b node-path (string) - Full path of the object

\n \n + */ +int +OSCReceiver::m_destroy_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* node_path = &argv[1]->s; + + destroy(node_path); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/connect - Connects two ports (must be in the same patch) + * \arg \b response-id (integer) + * \arg \b src-port-path (string) - Full path of source port + * \arg \b dst-port-path (string) - Full path of destination port

\n \n + */ +int +OSCReceiver::m_connect_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* src_port_path = &argv[1]->s; + const char* dst_port_path = &argv[2]->s; + + connect(src_port_path, dst_port_path); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/disconnect - Disconnects two ports. + * \arg \b response-id (integer) + * \arg \b src-port-path (string) - Full path of source port + * \arg \b dst-port-path (string) - Full path of destination port

\n \n + */ +int +OSCReceiver::m_disconnect_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* src_port_path = &argv[1]->s; + const char* dst_port_path = &argv[2]->s; + + disconnect(src_port_path, dst_port_path); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/disconnect_all - Disconnect all connections to/from a node. + * \arg \b response-id (integer) + * \arg \b node-path (string) - Full path of node.

\n \n + */ +int +OSCReceiver::m_disconnect_all_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* node_path = &argv[1]->s; + + disconnect_all(node_path); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/set_port_value - Sets the value of a port for all voices (both AR and CR) + * \arg \b response-id (integer) + * \arg \b port-path (string) - Name of port + * \arg \b value (float) - Value to set port to + */ +int +OSCReceiver::m_set_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* port_path = &argv[1]->s; + const float value = argv[2]->f; + + set_port_value(port_path, value); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/set_port_value - Sets the value of a port for a specific voice (both AR and CR) + * \arg \b response-id (integer) + * \arg \b port-path (string) - Name of port + * \arg \b voice (integer) - Voice to set port value for + * \arg \b value (float) - Value to set port to + */ +int +OSCReceiver::m_set_port_value_voice_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* port_path = &argv[1]->s; + const int voice = argv[2]->i; + const float value = argv[3]->f; + + set_port_value(port_path, voice, value); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/set_port_value_slow - Sets the value of a port for all voices (as a QueuedEvent) + * \arg \b response-id (integer) + * \arg \b port-path (string) - Name of port + * \arg \b value (float) - Value to set port to + * + * \li This version exists so you can send it immediately after a QueuedEvent it may depend on (ie a + * node creation) and be sure it happens after the event (a normal set_port_value could beat the + * slow event and arrive out of order).

\n \n + */ +int +OSCReceiver::m_set_port_value_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* port_path = &argv[1]->s; + const float value = argv[2]->f; + + set_port_value_queued(port_path, value); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/note_on - Triggers a note-on, just as if it came from MIDI + * \arg \b response-id (integer) + * \arg \b node-path (string) - Patch of Node to trigger (must be a trigger or note node) + * \arg \b note-num (int) - MIDI style note number (0-127) + * \arg \b velocity (int) - MIDI style velocity (0-127)

\n \n + */ +int +OSCReceiver::m_note_on_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + /* + + const char* node_path = &argv[1]->s; + const uchar note_num = argv[2]->i; + const uchar velocity = argv[3]->i; + */ + cerr << "FIXME: OSC note on\n"; + //note_on(node_path, note_num, velocity); + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/note_off - Triggers a note-off, just as if it came from MIDI + * \arg \b response-id (integer) + * \arg \b node-path (string) - Patch of Node to trigger (must be a trigger or note node) + * \arg \b note-num (int) - MIDI style note number (0-127)

\n \n + */ +int +OSCReceiver::m_note_off_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + /* + + const char* patch_path = &argv[1]->s; + const uchar note_num = argv[2]->i; + */ + cerr << "FIXME: OSC note off\n"; + //note_off(patch_path, note_num); + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/all_notes_off - Triggers a note-off for all voices, just as if it came from MIDI + * \arg \b response-id (integer) + * \arg \b patch-path (string) - Patch of patch to send event to

\n \n + */ +int +OSCReceiver::m_all_notes_off_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + /* + + const char* patch_path = &argv[1]->s; + */ + cerr << "FIXME: OSC all notes off\n"; + //all_notes_off(patch_path); + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/synth/midi_learn - Initiate MIDI learn for a given (MIDI Control) Node + * \arg \b response-id (integer) + * \arg \b node-path (string) - Patch of the Node that should learn the next MIDI event. + * + * \li This of course will only do anything for MIDI control nodes. The node will learn the next MIDI + * event that arrives at it's MIDI input port - no behind the scenes voodoo happens here. It is planned + * that a plugin specification supporting arbitrary OSC commands for plugins will exist one day, and this + * method will go away completely.

\n \n + */ +int +OSCReceiver::m_midi_learn_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* patch_path = &argv[1]->s; + + midi_learn(patch_path); + + return 0; +} + + +#ifdef HAVE_LASH +/** \page engine_osc_namespace + *

\b /om/lash/restore_done - Notify LASH restoring is finished and connections can be made. + * \arg \b response-id (integer) + */ +int +OSCReceiver::m_lash_restore_done_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + lash_retore_done(); + + return 0; +} +#endif // HAVE_LASH + + +/** \page engine_osc_namespace + *

\b /om/metadata/set - Sets a piece of metadata, associated with a synth-space object (node, etc) + * \arg \b response-id (integer) + * \arg \b object-path (string) - Full path of object to associate metadata with + * \arg \b key (string) - Key (index) for new piece of metadata + * \arg \b value (string) - Value of new piece of metadata + */ +int +OSCReceiver::m_metadata_set_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* node_path = &argv[1]->s; + const char* key = &argv[2]->s; + const char* value = &argv[3]->s; + + set_metadata(node_path, key, value); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/metadata/responder - Requests the engine send a piece of metadata, associated with a synth-space object (node, etc) + * \arg \b response-id (integer) + * \arg \b object-path (string) - Full path of object metadata is associated with + * \arg \b key (string) - Key (index) for piece of metadata + * + * \li Reply will be sent to client registered with the source address of this message.

\n \n + */ +int +OSCReceiver::m_metadata_get_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + /* + const char* node_path = &argv[1]->s; + const char* key = &argv[2]->s; + */ + cerr << "FIXME: OSC metadata request\n"; + // FIXME: Equivalent? + /* + RequestMetadataEvent* ev = new RequestMetadataEvent( + new OSCResponder(ClientKey(addr)), + node_path, key); + + */ + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/responder/plugins - Requests the engine send a list of all known plugins. + * \arg \b response-id (integer) + * + * \li Reply will be sent to client registered with the source address of this message.

\n \n + */ +int +OSCReceiver::m_request_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + cerr << "REQUEST PLUGINS\n"; + + // FIXME + request_plugins(); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/responder/all_objects - Requests the engine send information about \em all objects (patches, nodes, etc) + * \arg \b response-id (integer) + * + * \li Reply will be sent to client registered with the source address of this message.

\n \n + */ +int +OSCReceiver::m_request_all_objects_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + request_all_objects(); + + return 0; +} + + +/** \page engine_osc_namespace + *

\b /om/responder/port_value - Requests the engine send the value of a port. + * \arg \b response-id (integer) + * \arg \b port-path (string) - Full path of port to send the value of

\n \n + * + * \li Reply will be sent to client registered with the source address of this message.

\n \n + */ +int +OSCReceiver::m_request_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* port_path = &argv[1]->s; + + request_port_value(port_path); + + return 0; +} + + +#ifdef HAVE_DSSI +int +OSCReceiver::m_dssi_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ +#if 0 + string node_path(path); + + if (node_path.substr(0, 5) != "/dssi") + return 1; + + string command = node_path.substr(node_path.find_last_of("/")+1); + node_path = node_path.substr(5); // chop off leading "/dssi/" + node_path = node_path.substr(0, node_path.find_last_of("/")); // chop off command at end + + //cout << "DSSI: Got message " << command << " for node " << node_path << endl; + + QueuedEvent* ev = NULL; + + if (command == "update" && !strcmp(types, "s")) + ev = new DSSIUpdateEvent(NULL, node_path, &argv[0]->s); + else if (command == "control" && !strcmp(types, "if")) + ev = new DSSIControlEvent(NULL, node_path, argv[0]->i, argv[1]->f); + else if (command == "configure" && ~strcmp(types, "ss")) + ev = new DSSIConfigureEvent(NULL, node_path, &argv[0]->s, &argv[1]->s); + else if (command == "program" && ~strcmp(types, "ii")) + ev = new DSSIProgramEvent(NULL, node_path, argv[0]->i, argv[1]->i); + + if (ev != NULL) + push(ev); + else + cerr << "[OSCReceiver] Unknown DSSI command received: " << path << endl; +#endif + return 0; +} +#endif + + +// Static Callbacks // + + +// Display incoming OSC messages (for debugging purposes) +int +OSCReceiver::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data) +{ + printf("[OSCMsg] %s\n", path); + + for (int i=0; i < argc; ++i) { + printf(" '%c' ", types[i]); + lo_arg_pp(lo_type(types[i]), argv[i]); + printf("\n"); + } + printf("\n"); + + return 1; // not handled +} + + +int +OSCReceiver::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data) +{ + cerr << "Unknown command " << path << " (" << types << "), sending error.\n"; + + string error_msg = "Unknown command: "; + error_msg.append(path).append(" ").append(types); + + om->client_broadcaster()->send_error(error_msg); + + return 0; +} + + +} // namespace Om diff --git a/src/libs/engine/OSCReceiver.h b/src/libs/engine/OSCReceiver.h new file mode 100644 index 00000000..b80c25c3 --- /dev/null +++ b/src/libs/engine/OSCReceiver.h @@ -0,0 +1,124 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OSCRECEIVER_H +#define OSCRECEIVER_H + +#include "config.h" +#include +#include +#include "QueuedEngineInterface.h" +#include "OSCResponder.h" +using std::string; + +namespace Om { + +class JackDriver; +class NodeFactory; +class Patch; + + +/* Some boilerplate killing macros... */ +#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg + +/* Defines a static handler to be passed to lo_add_method, which is a trivial + * wrapper around a non-static method that does the real work. Makes a whoole + * lot of ugly boiler plate go away */ +#define LO_HANDLER(name) \ +int m_##name##_cb (LO_HANDLER_ARGS);\ +inline static int name##_cb(LO_HANDLER_ARGS, void* osc_receiver)\ +{ return ((OSCReceiver*)osc_receiver)->m_##name##_cb(path, types, argv, argc, msg); } + + + +/** Receives OSC messages from liblo. + * + * This inherits from QueuedEngineInterface and calls it's own functions + * via OSC. It's not actually a directly callable EngineInterface (it's + * callable via OSC...) so it is-implemented-as-a (privately inherits) + * QueuedEngineInterface. + * + * \ingroup engine + */ +class OSCReceiver : private QueuedEngineInterface +{ +public: + OSCReceiver(size_t queue_size, const char* const port); + ~OSCReceiver(); + + void start(); + void stop(); + +private: + // Prevent copies (undefined) + OSCReceiver(const OSCReceiver&); + OSCReceiver& operator=(const OSCReceiver&); + + static void error_cb(int num, const char* msg, const char* path); + static int set_response_address_cb(LO_HANDLER_ARGS, void* osc_receiver); + static int generic_cb(LO_HANDLER_ARGS, void* osc_receiver); + static int unknown_cb(LO_HANDLER_ARGS, void* osc_receiver); + + LO_HANDLER(quit); + LO_HANDLER(ping); + LO_HANDLER(ping_slow); + LO_HANDLER(register_client); + LO_HANDLER(unregister_client); + LO_HANDLER(load_plugins); + LO_HANDLER(engine_activate); + LO_HANDLER(engine_deactivate); + LO_HANDLER(create_patch); + LO_HANDLER(rename); + LO_HANDLER(create_node); + LO_HANDLER(create_node_by_uri); + LO_HANDLER(enable_patch); + LO_HANDLER(disable_patch); + LO_HANDLER(clear_patch); + LO_HANDLER(destroy); + LO_HANDLER(connect); + LO_HANDLER(disconnect); + LO_HANDLER(disconnect_all); + LO_HANDLER(set_port_value); + LO_HANDLER(set_port_value_voice); + LO_HANDLER(set_port_value_slow); + LO_HANDLER(note_on); + LO_HANDLER(note_off); + LO_HANDLER(all_notes_off); + LO_HANDLER(midi_learn); + LO_HANDLER(metadata_get); + LO_HANDLER(metadata_set); + LO_HANDLER(request_plugins); + LO_HANDLER(request_all_objects); + LO_HANDLER(request_port_value); +#ifdef HAVE_DSSI + LO_HANDLER(dssi); +#endif +#ifdef HAVE_LASH + LO_HANDLER(lash_restore_done); +#endif + + const char* const _port; + bool _is_activated; + lo_server_thread _st; + + /** Cached OSC responder (for most recent incoming message) */ + CountedPtr _osc_responder; +}; + + +} // namespace Om + +#endif // OSCRECEIVER_H diff --git a/src/libs/engine/OSCResponder.cpp b/src/libs/engine/OSCResponder.cpp new file mode 100644 index 00000000..82e6b55d --- /dev/null +++ b/src/libs/engine/OSCResponder.cpp @@ -0,0 +1,88 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OSCResponder.h" +#include "Om.h" +#include "OmApp.h" +#include "ClientBroadcaster.h" +#include "interface/ClientKey.h" +#include +#include +#include +#include + +using std::cout; using std::cerr; using std::endl; + +namespace Om { + + +/** Construct an OSCResponder from \a addr. + * Takes ownership of @a url. + */ +OSCResponder::OSCResponder(int32_t id, char* url) +: Responder() +, _id(id) +, _url(url) +, _addr(NULL) +{ + // If ID is -1 this shouldn't have even been created + assert(id != -1); +} + + +OSCResponder::~OSCResponder() +{ + //cerr << "DELETING " << _url << " RESPONDER\n"; + + if (_addr) + lo_address_free(_addr); +} + + +CountedPtr +OSCResponder::find_client() +{ + return om->client_broadcaster()->client(ClientKey(ClientKey::OSC_URL, _url)); +} + + +void +OSCResponder::respond_ok() +{ + _addr = lo_address_new_from_url(_url); + + //cerr << "OK " << _id << endl; + if (lo_send(_addr, "/om/response/ok", "i", _id) < 0) { + cerr << "Unable to send response " << _id << "! (" + << lo_address_errstr(_addr) << ")" << endl; + } +} + + +void +OSCResponder::respond_error(const string& msg) +{ + _addr = lo_address_new_from_url(_url); + + //cerr << "ERR " << _id << endl; + if (lo_send(_addr, "/om/response/error", "is",_id, msg.c_str()) < 0) { + cerr << "Unable to send response " << _id << "! (" + << lo_address_errstr(_addr) << endl; + } +} + +} // namespace OM + diff --git a/src/libs/engine/OSCResponder.h b/src/libs/engine/OSCResponder.h new file mode 100644 index 00000000..f579df98 --- /dev/null +++ b/src/libs/engine/OSCResponder.h @@ -0,0 +1,61 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OSCRESPONDER_H +#define OSCRESPONDER_H + +#include +#include +#include +#include "Responder.h" + +namespace Om { + + +/** Responder for (liblo) OSC clients. + * + * OSC Clients use request IDs to be able to associate replies with sent + * events. If the ID is -1, a response will not be sent (and the overhead + * of searching for the client's record will be skipped). Any other integer + * is a valid response ID and will be responded to. + * + * Creation of the lo_address is deferred until needed to avoid bogging down + * the receiving thread as much as possible. + */ +class OSCResponder : public Responder +{ +public: + OSCResponder(int32_t id, char* url); + ~OSCResponder(); + + CountedPtr find_client(); + + void respond_ok(); + void respond_error(const string& msg); + + const char* url() const { return _url; } + +private: + int32_t _id; + char* const _url; + lo_address _addr; +}; + + +} // namespace Om + +#endif // OSCRESPONDER_H + diff --git a/src/libs/engine/ObjectSender.cpp b/src/libs/engine/ObjectSender.cpp new file mode 100644 index 00000000..3db6915d --- /dev/null +++ b/src/libs/engine/ObjectSender.cpp @@ -0,0 +1,207 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectSender.h" +#include "interface/ClientInterface.h" +#include "Om.h" +#include "OmApp.h" +#include "ObjectStore.h" +#include "Patch.h" +#include "Node.h" +#include "Port.h" +#include "PortInfo.h" +#include "PortBase.h" +#include "Connection.h" +#include "NodeFactory.h" + +namespace Om { + +/** Send all currently existing objects to client. + */ +void +ObjectSender::send_all(ClientInterface* client) +{ + for (Tree::iterator i = om->object_store()->objects().begin(); + i != om->object_store()->objects().end(); ++i) + if ((*i)->as_patch() != NULL && (*i)->parent() == NULL) + send_patch(client, (*i)->as_patch()); + //(*i)->as_node()->send_creation_messages(client); + +} + + +void +ObjectSender::send_patch(ClientInterface* client, const Patch* patch) +{ + client->new_patch(patch->path(), patch->internal_poly()); + + for (List::const_iterator j = patch->nodes().begin(); + j != patch->nodes().end(); ++j) { + Node* const node = (*j); + Port* const port = node->as_port(); // NULL unless a bridge node + send_node(client, node); + + usleep(100); + + // If this is a bridge (input/output) node, send the patch control value as well + if (port && port->port_info()->is_control()) + client->control_change(port->path(), + ((PortBase*)port)->buffer(0)->value_at(0)); + } + + for (List::const_iterator j = patch->connections().begin(); + j != patch->connections().end(); ++j) + client->connection((*j)->src_port()->path(), (*j)->dst_port()->path()); + + // Send port information + /*for (size_t i=0; i < m_ports.size(); ++i) { + Port* const port = m_ports.at(i); + + // Send metadata + const map& data = port->metadata(); + for (map::const_iterator i = data.begin(); i != data.end(); ++i) + om->client_broadcaster()->send_metadata_update_to(client, port->path(), (*i).first, (*i).second); + + if (port->port_info()->is_control()) + om->client_broadcaster()->send_control_change_to(client, port->path(), + ((PortBase*)port)->buffer(0)->value_at(0)); + }*/ +} + + +void +ObjectSender::send_node(ClientInterface* client, const Node* node) +{ + int polyphonic = + (node->poly() > 1 + && node->poly() == node->parent_patch()->internal_poly() + ? 1 : 0); + + assert(node->plugin()->uri().length() > 0); + assert(node->path().length() > 0); + + client->bundle_begin(); + + // FIXME: bundleify + + const Array& ports = node->ports(); + + client->new_node(node->plugin()->type_string(), node->plugin()->uri(), + node->path(), polyphonic, ports.size()); + + // Send ports + for (size_t j=0; j < ports.size(); ++j) { + Port* const port = ports.at(j); + PortInfo* const info = port->port_info(); + + assert(port); + assert(info); + + client->new_port(port->path(), info->type_string(), info->is_output()); + + /*m = lo_message_new(); + lo_message_add_string(m, port->path().c_str()); + lo_message_add_string(m, info->type_string().c_str()); + lo_message_add_string(m, info->direction_string().c_str()); + lo_message_add_string(m, info->hint_string().c_str()); + lo_message_add_float(m, info->default_val()); + lo_message_add_float(m, info->min_val()); + lo_message_add_float(m, info->max_val()); + lo_bundle_add_message(b, "/om/new_port", m); + msgs.push_back(m);*/ + + // If the bundle is getting very large, send it and start + // a new one + /*if (lo_bundle_length(b) > 1024) { + lo_send_bundle(_address, b); + lo_bundle_free(b); + b = lo_bundle_new(tt); + }*/ + } + + client->bundle_end(); +} + + +void +ObjectSender::send_port(ClientInterface* client, const Port* port) +{ + PortInfo* info = port->port_info(); + + client->new_port(port->path(), info->type_string(), info->is_output()); + + // Send metadata + const map& data = port->metadata(); + for (map::const_iterator j = data.begin(); j != data.end(); ++j) + client->metadata_update(port->path(), (*j).first, (*j).second); +} + + +void +ObjectSender::send_plugins(ClientInterface* client) +{ + om->node_factory()->lock_plugin_list(); + + const list& plugs = om->node_factory()->plugins(); + +/* + lo_timetag tt; + lo_timetag_now(&tt); + lo_bundle b = lo_bundle_new(tt); + lo_message m = lo_message_new(); + list msgs; + + lo_message_add_int32(m, plugs.size()); + lo_bundle_add_message(b, "/om/num_plugins", m); + msgs.push_back(m); +*/ + for (list::const_iterator j = plugs.begin(); j != plugs.end(); ++j) { + const Plugin* const p = *j; + client->new_plugin(p->type_string(), p->uri(), p->name()); + } +/* + plugin = (*j); + m = lo_message_new(); + + lo_message_add_string(m, plugin->type_string()); + lo_message_add_string(m, plugin->uri().c_str()); + lo_message_add_string(m, plugin->name().c_str()); + lo_bundle_add_message(b, "/om/plugin", m); + msgs.push_back(m); + if (lo_bundle_length(b) > 1024) { + // FIXME FIXME FIXME dirty, dirty cast + lo_send_bundle(((OSCClient*)client)->address(), b); + lo_bundle_free(b); + b = lo_bundle_new(tt); + } + }*/ +/* + if (lo_bundle_length(b) > 0) { + // FIXME FIXME FIXME dirty, dirty cast + lo_send_bundle(((OSCClient*)client)->address(), b); + lo_bundle_free(b); + } else { + lo_bundle_free(b); + } + for (list::const_iterator i = msgs.begin(); i != msgs.end(); ++i) + lo_message_free(*i); +*/ + om->node_factory()->unlock_plugin_list(); +} + + +} // namespace Om + diff --git a/src/libs/engine/ObjectSender.h b/src/libs/engine/ObjectSender.h new file mode 100644 index 00000000..f97f1f9e --- /dev/null +++ b/src/libs/engine/ObjectSender.h @@ -0,0 +1,55 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OBJECTSENDER_H +#define OBJECTSENDER_H + +namespace Om { + +namespace Shared { + class ClientInterface; +} using Shared::ClientInterface; + +class Patch; +class Node; +class Port; + + +/** Utility class for sending OmObjects to clients through ClientInterface. + * + * While ClientInterface is the direct low level message-based interface + * (protocol), this is used from the engine to easily send proper Objects + * with these messages (which is done in a few different parts of the code). + * + * Basically a serializer, except to calls on ClientInterface rather than + * eg a byte stream. + */ +class ObjectSender { +public: + + // FIXME: Make all object parameters const + + static void send_all(ClientInterface* client); + static void send_patch(ClientInterface* client, const Patch* patch); + static void send_node(ClientInterface* client, const Node* node); + static void send_port(ClientInterface* client, const Port* port); + static void send_plugins(ClientInterface* client); +}; + +} // namespace Om + +#endif // OBJECTSENDER_H + diff --git a/src/libs/engine/ObjectStore.cpp b/src/libs/engine/ObjectStore.cpp new file mode 100644 index 00000000..a1cf1287 --- /dev/null +++ b/src/libs/engine/ObjectStore.cpp @@ -0,0 +1,109 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectStore.h" +#include "Om.h" +#include "OmApp.h" +#include "Patch.h" +#include "Node.h" +#include "Port.h" +#include "List.h" +#include "util/Path.h" +#include "Tree.h" + +namespace Om { + + +/** Find the Patch at the given path. + */ +Patch* +ObjectStore::find_patch(const Path& path) +{ + OmObject* const object = find(path); + return (object == NULL) ? NULL : object->as_patch(); +} + + +/** Find the Node at the given path. + */ +Node* +ObjectStore::find_node(const Path& path) +{ + OmObject* const object = find(path); + return (object == NULL) ? NULL : object->as_node(); +} + + +/** Find the Port at the given path. + */ +Port* +ObjectStore::find_port(const Path& path) +{ + OmObject* const object = find(path); + return (object == NULL) ? NULL : object->as_port(); +} + + +/** Find the Object at the given path. + */ +OmObject* +ObjectStore::find(const Path& path) +{ + return m_objects.find(path); +} + + +/** Add an object to the store. Not realtime safe. + */ +void +ObjectStore::add(OmObject* o) +{ + //cerr << "[ObjectStore] Adding " << o->path() << endl; + m_objects.insert(new TreeNode(o->path(), o)); +} + + +/** Add an object to the store. Not realtime safe. + */ +void +ObjectStore::add(TreeNode* tn) +{ + //cerr << "[ObjectStore] Adding " << tn->key() << endl; + m_objects.insert(tn); +} + + +/** Remove a patch from the store. + * + * It it the caller's responsibility to delete the returned ListNode. + * + * @returns TreeNode containing object removed on success, NULL if not found. + */ +TreeNode* +ObjectStore::remove(const string& path) +{ + TreeNode* const removed = m_objects.remove(path); + + if (removed == NULL) + cerr << "[ObjectStore] WARNING: Removing " << path << " failed." << endl; + //else + // cerr << "[ObjectStore] Removed " << path << endl; + + return removed; +} + + +} // namespace Om diff --git a/src/libs/engine/ObjectStore.h b/src/libs/engine/ObjectStore.h new file mode 100644 index 00000000..8c71c002 --- /dev/null +++ b/src/libs/engine/ObjectStore.h @@ -0,0 +1,61 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef OBJECTSTORE_H +#define OBJECTSTORE_H + +#include +#include "util/Path.h" +#include "Tree.h" +using std::string; + +namespace Om { + +class Patch; +class Node; +class Port; +class OmObject; + + +/** Storage for all OmObjects (tree of OmObject's sorted by path). + * + * All looking up in pre_process() methods (and anything else that isn't in-band + * with the audio thread) should use this (to read and modify the OmObject + * tree). + */ +class ObjectStore +{ +public: + Patch* find_patch(const Path& path); + Node* find_node(const Path& path); + Port* find_port(const Path& path); + OmObject* find(const Path& path); + + void add(OmObject* o); + void add(TreeNode* o); + TreeNode* remove(const string& key); + + const Tree& objects() { return m_objects; } + +private: + Tree m_objects; +}; + + +} // namespace Om + +#endif // OBJECTSTORE diff --git a/src/libs/engine/Om.cpp b/src/libs/engine/Om.cpp new file mode 100644 index 00000000..c04a7464 --- /dev/null +++ b/src/libs/engine/Om.cpp @@ -0,0 +1,36 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "OmApp.h" +#ifdef HAVE_LASH +#include "LashDriver.h" +#endif + +/** Om namespace. + * + * Everything internal to the Om engine lives in this namespace. Generally + * none of this code is used by clients - as special (possibly temporary) + * exceptions, some classes in src/common are used by clients but are part + * of the Om namespace. + */ +namespace Om +{ + OmApp* om = 0; +#ifdef HAVE_LASH + LashDriver* lash_driver = 0; +#endif +} diff --git a/src/libs/engine/Om.h b/src/libs/engine/Om.h new file mode 100644 index 00000000..2fe3fd8c --- /dev/null +++ b/src/libs/engine/Om.h @@ -0,0 +1,42 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OM_H +#define OM_H + +// FIXME: this dependency has to go +#include "config.h" + + +/* Things all over the place access various bits of Om through this. + * This was a bad design decision, it just evolved this way :/ + * I may refactor it eventually, but it works. + */ + +/** \defgroup engine Engine + */ +namespace Om +{ +#ifdef HAVE_LASH + class LashDriver; + extern LashDriver* lash_driver; +#endif + class OmApp; + extern OmApp* om; +} + +#endif // OM_H + diff --git a/src/libs/engine/OmApp.cpp b/src/libs/engine/OmApp.cpp new file mode 100644 index 00000000..ea7df1df --- /dev/null +++ b/src/libs/engine/OmApp.cpp @@ -0,0 +1,231 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Om.h" +#include "OmApp.h" +#include "config.h" +#include "tuning.h" +#include +#include +#include +#include "Event.h" +#include "util/Queue.h" +#include "JackAudioDriver.h" +#include "NodeFactory.h" +#include "OSCReceiver.h" +#include "ClientBroadcaster.h" +#include "Patch.h" +#include "ObjectStore.h" +#include "MaidObject.h" +#include "Maid.h" +#include "MidiDriver.h" +#include "QueuedEventSource.h" +#include "PostProcessor.h" +#include "CreatePatchEvent.h" +#include "EnablePatchEvent.h" +#ifdef HAVE_JACK_MIDI +#include "JackMidiDriver.h" +#endif +#ifdef HAVE_ALSA_MIDI +#include "AlsaMidiDriver.h" +#endif +#ifdef HAVE_LASH +#include "LashDriver.h" +#endif +using std::cout; using std::cerr; using std::endl; + +namespace Om { + + +OmApp::OmApp(const char* port) +: m_maid(new Maid(maid_queue_size)), + m_audio_driver(new JackAudioDriver()), +#ifdef HAVE_JACK_MIDI + m_midi_driver(new JackMidiDriver(((JackAudioDriver*)m_audio_driver)->jack_client())), +#elif HAVE_ALSA_MIDI + m_midi_driver(new AlsaMidiDriver()), +#else + m_midi_driver(new DummyMidiDriver()), +#endif + m_osc_receiver(new OSCReceiver(pre_processor_queue_size, port)), + m_client_broadcaster(new ClientBroadcaster()), + m_object_store(new ObjectStore()), + m_node_factory(new NodeFactory()), + m_event_queue(new Queue(event_queue_size)), +// m_pre_processor(new QueuedEventSource(pre_processor_queue_size)), + m_post_processor(new PostProcessor(post_processor_queue_size)), + m_quit_flag(false), + m_activated(false) +{ + mlock(m_audio_driver, sizeof(JackAudioDriver)); + mlock(m_object_store, sizeof(ObjectStore)); + mlock(m_osc_receiver, sizeof(OSCReceiver)); +#ifdef HAVE_ALSA_MIDI + mlock(m_midi_driver, sizeof(AlsaMidiDriver)); +#else + mlock(m_midi_driver, sizeof(DummyMidiDriver)); +#endif + + m_osc_receiver->start(); + m_post_processor->start(); +} + + +OmApp::OmApp(const char* port, AudioDriver* audio_driver) +: m_maid(new Maid(maid_queue_size)), + m_audio_driver(audio_driver), +#ifdef HAVE_JACK_MIDI + m_midi_driver(new JackMidiDriver(((JackAudioDriver*)m_audio_driver)->jack_client())), +#elif HAVE_ALSA_MIDI + m_midi_driver(new AlsaMidiDriver()), +#else + m_midi_driver(new DummyMidiDriver()), +#endif + m_osc_receiver(new OSCReceiver(pre_processor_queue_size, port)), + m_client_broadcaster(new ClientBroadcaster()), + m_object_store(new ObjectStore()), + m_node_factory(new NodeFactory()), + m_event_queue(new Queue(event_queue_size)), + //m_pre_processor(new QueuedEventSource(pre_processor_queue_size)), + m_post_processor(new PostProcessor(post_processor_queue_size)), + m_quit_flag(false), + m_activated(false) +{ + mlock(m_audio_driver, sizeof(JackAudioDriver)); + mlock(m_object_store, sizeof(ObjectStore)); + mlock(m_osc_receiver, sizeof(OSCReceiver)); +#ifdef HAVE_ALSA_MIDI + mlock(m_midi_driver, sizeof(AlsaMidiDriver)); +#else + mlock(m_midi_driver, sizeof(DummyMidiDriver)); +#endif + + m_osc_receiver->start(); + m_post_processor->start(); +} + + +OmApp::~OmApp() +{ + deactivate(); + + for (Tree::iterator i = m_object_store->objects().begin(); + i != m_object_store->objects().end(); ++i) { + if ((*i)->parent() == NULL) + delete (*i); + } + + delete m_object_store; + delete m_client_broadcaster; + delete m_osc_receiver; + delete m_node_factory; + delete m_midi_driver; + delete m_audio_driver; + + delete m_maid; + + munlockall(); +} + + +/* driver() template specializations. + * Due to the lack of RTTI, this needs to be implemented manually like this. + * If more types/drivers start getting added, it may be worth it to enable + * RTTI and put all the drivers into a map with typeid's as the key. That's + * more elegant and extensible, but this is faster and simpler - for now. + */ +template<> +Driver* OmApp::driver() { return m_midi_driver; } +template<> +Driver* OmApp::driver() { return m_audio_driver; } + + +int +OmApp::main() +{ + // Loop until quit flag is set (by OSCReceiver) + while ( ! m_quit_flag) { + nanosleep(&main_rate, NULL); +#ifdef HAVE_LASH + // Process any pending LASH events + if (lash_driver->enabled()) + lash_driver->process_events(); +#endif + // Run the maid (garbage collector) + m_maid->cleanup(); + } + cout << "[Main] Done main loop." << endl; + + if (m_activated) + deactivate(); + + sleep(1); + cout << "[Main] Om exiting..." << endl; + + return 0; +} + + +void +OmApp::activate() +{ + if (m_activated) + return; + + // Create root patch + CreatePatchEvent create_ev(CountedPtr(new Responder()), "/", 1); + create_ev.pre_process(); + create_ev.execute(0); + create_ev.post_process(); + EnablePatchEvent enable_ev(CountedPtr(new Responder()), "/"); + enable_ev.pre_process(); + enable_ev.execute(0); + enable_ev.post_process(); + + assert(m_audio_driver->root_patch() != NULL); + + m_audio_driver->activate(); +#ifdef HAVE_ALSA_MIDI + m_midi_driver->activate(); +#endif + m_activated = true; +} + + +void +OmApp::deactivate() +{ + if (!m_activated) + return; + + m_audio_driver->root_patch()->process(false); + + for (Tree::iterator i = m_object_store->objects().begin(); + i != m_object_store->objects().end(); ++i) + if ((*i)->as_node() != NULL && (*i)->as_node()->parent() == NULL) + (*i)->as_node()->deactivate(); + + if (m_midi_driver != NULL) + m_midi_driver->deactivate(); + + m_osc_receiver->stop(); + m_audio_driver->deactivate(); + + m_activated = false; +} + + +} // namespace Om diff --git a/src/libs/engine/OmApp.h b/src/libs/engine/OmApp.h new file mode 100644 index 00000000..0fe49b81 --- /dev/null +++ b/src/libs/engine/OmApp.h @@ -0,0 +1,99 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OMAPP_H +#define OMAPP_H + +template class Queue; +class Maid; + +namespace Om { + +class AudioDriver; +class MidiDriver; +class NodeFactory; +class OSCReceiver; +class ClientBroadcaster; +class Patch; +class ObjectStore; +class EventSource; +class PostProcessor; +class Event; +class QueuedEvent; +template class Driver; + + +/** The main class for Om, the whole app lives in here + * + * This class should not exist. + * + * \ingroup engine + */ +class OmApp +{ +public: + OmApp(const char* const port); + OmApp(const char* const port, AudioDriver* audio_driver); + ~OmApp(); + + int main(); + + /** Set the quit flag that should kill all threads and exit cleanly. + * Note that it will take some time. */ + void quit() { m_quit_flag = true; } + + void activate(); + void deactivate(); + + Maid* maid() const { return m_maid; } + AudioDriver* audio_driver() const { return m_audio_driver; } + MidiDriver* midi_driver() const { return m_midi_driver; } + OSCReceiver* osc_receiver() const { return m_osc_receiver; } + ClientBroadcaster* client_broadcaster() const { return m_client_broadcaster; } + ObjectStore* object_store() const { return m_object_store; } + NodeFactory* node_factory() const { return m_node_factory; } + Queue* event_queue() const { return m_event_queue; } + //EventSource* pre_processor() const { return m_pre_processor; } + PostProcessor* post_processor() const { return m_post_processor; } + + /** Return the active driver for the given (template parameter) type. + * This is a hook for BridgeNode. See OmApp.cpp for specializations. */ + template Driver* driver(); + +private: + // Prevent copies + OmApp(const OmApp&); + OmApp& operator=(const OmApp&); + + Maid* m_maid; + AudioDriver* m_audio_driver; + MidiDriver* m_midi_driver; + OSCReceiver* m_osc_receiver; + ClientBroadcaster* m_client_broadcaster; + ObjectStore* m_object_store; + NodeFactory* m_node_factory; + Queue* m_event_queue; + //EventSource* m_pre_processor; + PostProcessor* m_post_processor; + + bool m_quit_flag; + bool m_activated; +}; + + +} // namespace Om + +#endif // OMAPP_H diff --git a/src/libs/engine/OmInProcess.cpp b/src/libs/engine/OmInProcess.cpp new file mode 100644 index 00000000..971a1316 --- /dev/null +++ b/src/libs/engine/OmInProcess.cpp @@ -0,0 +1,74 @@ +/* This file is part of Om. Copyright (C) 2006 Mario Lang. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "Om.h" +#include "OmApp.h" +#include "OSCReceiver.h" +#include "JackAudioDriver.h" +#ifdef HAVE_LASH +#include "LashDriver.h" +#endif + +extern "C" +{ + int jack_initialize(jack_client_t* client, const char* load_init); + void jack_finish(void* arg); +} + + +void* +run_main(void* arg) +{ + Om::om->main(); +#ifdef HAVE_LASH + + delete Om::lash_driver; +#endif + + delete Om::om; + return 0; +} + + +pthread_t main_thread; + + +int +jack_initialize(jack_client_t* client, const char* load_init) +{ + if ((Om::om = new Om::OmApp(load_init, new Om::JackAudioDriver(client))) != NULL) { + pthread_create(&main_thread, NULL, run_main, NULL); + return 0; // Success + } else { + return 1; + } +} + + +void +jack_finish(void* arg) +{ + void* ret; + Om::om->quit(); + pthread_join(main_thread, &ret); +} + diff --git a/src/libs/engine/OmObject.h b/src/libs/engine/OmObject.h new file mode 100644 index 00000000..606a3dba --- /dev/null +++ b/src/libs/engine/OmObject.h @@ -0,0 +1,115 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OMOBJECT_H +#define OMOBJECT_H + +#include +#include +#include +#include +#include "MaidObject.h" +#include "util/Path.h" + +using std::string; using std::map; + +namespace Om { + +class Patch; +class Node; +class Port; + + +/** An object in the "synth space" of Om - Patch, Node, Port, etc. + * + * Each of these is a MaidObject and so can be deleted in a realtime safe + * way from anywhere, and they all have a map of metadata for clients to store + * arbitrary values in (which the engine puts no significance to whatsoever). + * + * \ingroup engine + */ +class OmObject : public MaidObject +{ +public: + OmObject(OmObject* parent, const string& name) + : m_parent(parent), m_name(name) + { + assert(parent == NULL || m_name.length() > 0); + assert(parent == NULL || m_name.find("/") == string::npos); + //assert(((string)path()).find("//") == string::npos); + } + + virtual ~OmObject() {} + + // Ghetto home-brew RTTI + virtual Patch* as_patch() { return NULL; } + virtual Node* as_node() { return NULL; } + virtual Port* as_port() { return NULL; } + + OmObject* parent() const { return m_parent; } + + inline const string& name() const { return m_name; } + + virtual void set_path(const Path& new_path) { + m_name = new_path.name(); + assert(m_name.find("/") == string::npos); + } + + void set_metadata(const string& key, const string& value) { m_metadata[key] = value; } + const string& get_metadata(const string& key) { + static const string empty_string = ""; + map::iterator i = m_metadata.find(key); + if (i != m_metadata.end()) + return (*i).second; + else + return empty_string; + } + + const map& metadata() const { return m_metadata; } + + inline const Path path() const { + if (m_parent == NULL) + return Path(string("/").append(m_name)); + else if (m_parent->path() == "/") + return Path(string("/").append(m_name)); + else + return Path(m_parent->path() +"/"+ m_name); + } + + /** Patch and Node override this to recursively add their children. */ + virtual void add_to_store() = 0; + + /** Patch and Node override this to recursively remove their children. */ + virtual void remove_from_store() = 0; + +protected: + OmObject() {} + + OmObject* m_parent; + string m_name; + +private: + // Prevent copies (undefined) + OmObject(const OmObject&); + OmObject& operator=(const OmObject& copy); + + map m_metadata; +}; + + +} // namespace Om + +#endif // OMOBJECT_H diff --git a/src/libs/engine/OutputPort.cpp b/src/libs/engine/OutputPort.cpp new file mode 100644 index 00000000..bf971919 --- /dev/null +++ b/src/libs/engine/OutputPort.cpp @@ -0,0 +1,51 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OutputPort.h" +#include "InputPort.h" +#include "PortInfo.h" +#include + +namespace Om { + +template +OutputPort::OutputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size) +: PortBase(node, name, index, poly, port_info, buffer_size) +{ + assert(port_info->is_output() && !port_info->is_input()); +} +template OutputPort::OutputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); +template OutputPort::OutputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); + + +template +void +OutputPort::set_tied_port(InputPort* port) +{ + assert(!m_is_tied); + assert(m_tied_port == NULL); + assert(static_cast*>(port) != static_cast*>(this)); + assert(port != NULL); + + m_is_tied = true; + m_tied_port = (PortBase*)port; +} +template void OutputPort::set_tied_port(InputPort* port); +template void OutputPort::set_tied_port(InputPort* port); + + +} // namespace Om + diff --git a/src/libs/engine/OutputPort.h b/src/libs/engine/OutputPort.h new file mode 100644 index 00000000..90488a7f --- /dev/null +++ b/src/libs/engine/OutputPort.h @@ -0,0 +1,64 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OUTPUTPORT_H +#define OUTPUTPORT_H + +#include +#include +#include "PortBase.h" +#include "util/types.h" + +namespace Om { + +template class InputPort; + + +/** An output port. + * + * Output ports always have a locally allocated buffer, and buffer() will + * always return that buffer. (This is very different from InputPort) + * + * This class actually adds no functionality to Port whatsoever right now, + * it will in the future when more advanced port types exist, and it makes + * things clearer throughout the engine. + * + * \ingroup engine + */ +template +class OutputPort : public PortBase +{ +public: + OutputPort(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); + virtual ~OutputPort() {} + + void set_tied_port(InputPort* port); + +private: + // Prevent copies (undefined) + OutputPort(const OutputPort& copy); + OutputPort& operator=(const OutputPort&); + + using PortBase::m_is_tied; + using PortBase::m_tied_port; +}; + + +template class OutputPort; + +} // namespace Om + +#endif // OUTPUTPORT_H diff --git a/src/libs/engine/Patch.cpp b/src/libs/engine/Patch.cpp new file mode 100644 index 00000000..be938cae --- /dev/null +++ b/src/libs/engine/Patch.cpp @@ -0,0 +1,356 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "Node.h" +#include "Patch.h" +#include "Plugin.h" +#include "Port.h" +#include "PortInfo.h" +#include "ClientBroadcaster.h" +#include "InternalNode.h" +#include "Connection.h" +#include "Om.h" +#include "OmApp.h" +#include "PortBase.h" +#include "ObjectStore.h" +#include "interface/ClientInterface.h" + +using std::cerr; using std::cout; using std::endl; + +namespace Om { + + +Patch::Patch(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size, size_t internal_poly) +: NodeBase(path, poly, parent, srate, buffer_size), + m_internal_poly(internal_poly), + m_process_order(NULL), + m_process(false) +{ + assert(internal_poly >= 1); + + m_plugin.type(Plugin::Patch); + m_plugin.lib_path(""); + m_plugin.plug_label("om_patch"); + m_plugin.name("Om patch"); + + //std::cerr << "Creating patch " << m_name << ", poly = " << poly + // << ", internal poly = " << internal_poly << std::endl; +} + + +Patch::~Patch() +{ + assert(!m_activated); + + for (List::iterator i = m_connections.begin(); i != m_connections.end(); ++i) { + delete (*i); + delete m_connections.remove(i); + } + + for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) { + assert(!(*i)->activated()); + delete (*i); + delete m_nodes.remove(i); + } + + delete m_process_order; +} + + +void +Patch::activate() +{ + NodeBase::activate(); + + for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) + (*i)->activate(); + + assert(m_activated); +} + + +void +Patch::deactivate() +{ + if (m_activated) { + + NodeBase::deactivate(); + + for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) { + if ((*i)->activated()) + (*i)->deactivate(); + assert(!(*i)->activated()); + } + } + assert(!m_activated); +} + + +void +Patch::process(bool b) +{ + if (!b) { + // Write output buffers to 0 + for (List::iterator i = m_bridge_nodes.begin(); i != m_bridge_nodes.end(); ++i) { + assert((*i)->as_port() != NULL); + if ((*i)->as_port()->port_info()->is_output()) + (*i)->as_port()->clear_buffers(); + } + } + m_process = b; +} + + +/** Run the patch for the specified number of frames. + * + * Calls all Nodes in the order m_process_order specifies. + */ +inline void +Patch::run(size_t nframes) +{ + if (m_process_order == NULL || !m_process) + return; + + // Prepare all ports + for (List::iterator i = m_bridge_nodes.begin(); i != m_bridge_nodes.end(); ++i) + (*i)->as_port()->prepare_buffers(nframes); + + // Run all nodes + for (size_t i=0; i < m_process_order->size(); ++i) { + // Could be a gap due to a node removal event (see RemoveNodeEvent.cpp) + // If you're thinking this isn't very nice, you're right. + if (m_process_order->at(i) != NULL) + m_process_order->at(i)->run(nframes); + } +} + + +/** Returns the number of ports. + * + * Needs to override the NodeBase implementation since a Patch's ports are really + * just it's input and output nodes' ports. + */ +size_t +Patch::num_ports() const +{ + return m_bridge_nodes.size(); +} + + +#if 0 +void +Patch::send_creation_messages(ClientInterface* client) const +{ + cerr << "FIXME: creation\n"; + + om->client_broadcaster()->send_patch_to(client, this); + + for (List::const_iterator j = m_nodes.begin(); j != m_nodes.end(); ++j) { + Node* node = (*j); + Port* port = node->as_port(); // NULL unless a bridge node + node->send_creation_messages(client); + + usleep(100); + + // If this is a bridge (input/output) node, send the patch control value as well + if (port != NULL && port->port_info()->is_control()) + om->client_broadcaster()->send_control_change_to(client, port->path(), + ((PortBase*)port)->buffer(0)->value_at(0)); + } + + for (List::const_iterator j = m_connections.begin(); j != m_connections.end(); ++j) { + om->client_broadcaster()->send_connection_to(client, *j); + } + + // Send port information + /*for (size_t i=0; i < m_ports.size(); ++i) { + Port* const port = m_ports.at(i); + + // Send metadata + const map& data = port->metadata(); + for (map::const_iterator i = data.begin(); i != data.end(); ++i) + om->client_broadcaster()->send_metadata_update_to(client, port->path(), (*i).first, (*i).second); + + if (port->port_info()->is_control()) + om->client_broadcaster()->send_control_change_to(client, port->path(), + ((PortBase*)port)->buffer(0)->value_at(0)); + }*/ +} +#endif + + +void +Patch::add_to_store() +{ + // Add self and ports + NodeBase::add_to_store(); + + // Add nodes + for (List::iterator j = m_nodes.begin(); j != m_nodes.end(); ++j) + (*j)->add_to_store(); +} + + +void +Patch::remove_from_store() +{ + // Remove self and ports + NodeBase::remove_from_store(); + + // Remove nodes + for (List::iterator j = m_nodes.begin(); j != m_nodes.end(); ++j) { + (*j)->remove_from_store(); + assert(om->object_store()->find((*j)->path()) == NULL); + } +} + + +// Patch specific stuff + + +void +Patch::add_node(ListNode* ln) +{ + assert(ln != NULL); + assert(ln->elem() != NULL); + assert(ln->elem()->parent_patch() == this); + assert(ln->elem()->poly() == m_internal_poly || ln->elem()->poly() == 1); + + m_nodes.push_back(ln); +} + + +ListNode* +Patch::remove_node(const string& name) +{ + for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) + if ((*i)->name() == name) + return m_nodes.remove(i); + + return NULL; +} + + +/** Remove a connection. Realtime safe. + */ +ListNode* +Patch::remove_connection(const Port* src_port, const Port* dst_port) +{ + bool found = false; + ListNode* connection = NULL; + for (List::iterator i = m_connections.begin(); i != m_connections.end(); ++i) { + if ((*i)->src_port() == src_port && (*i)->dst_port() == dst_port) { + connection = m_connections.remove(i); + found = true; + } + } + + if ( ! found) + cerr << "WARNING: [Patch::remove_connection] Connection not found !" << endl; + + return connection; +} + + +/** Remove a bridge_node. Realtime safe. + */ +ListNode* +Patch::remove_bridge_node(const InternalNode* node) +{ + bool found = false; + ListNode* bridge_node = NULL; + for (List::iterator i = m_bridge_nodes.begin(); i != m_bridge_nodes.end(); ++i) { + if ((*i) == node) { + bridge_node = m_bridge_nodes.remove(i); + found = true; + } + } + + if ( ! found) + cerr << "WARNING: [Patch::remove_bridge_node] InternalNode not found !" << endl; + + return bridge_node; +} + + +/** Find the process order for this Patch. + * + * The process order is a flat list that the patch will execute in order + * when it's run() method is called. Return value is a newly allocated list + * which the caller is reponsible to delete. Note that this function does + * NOT actually set the process order, it is returned so it can be inserted + * at the beginning of an audio cycle (by various Events). + * + * This function is not realtime safe, due to the use of the List iterator + */ +Array* +Patch::build_process_order() const +{ + Node* node = NULL; + Array* const process_order = new Array(m_nodes.size()); + + for (List::const_iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) + (*i)->traversed(false); + + // Traverse backwards starting at outputs + for (List::const_iterator i = m_bridge_nodes.begin(); i != m_bridge_nodes.end(); ++i) { + node = (*i); + assert(node->as_port() != NULL); + + // If the output node has been disconnected and has no connections left, don't traverse + // into it so it's not in the process order (and can be removed w/o flaming segfault death) + if (node->as_port()->port_info()->is_output() && node->providers()->size() > 0) + build_process_order_recursive(node, process_order); + } + + // Add any nodes that weren't hit by the traversal (disjoint nodes) + for (List::const_iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) { + node = (*i); + if ( ! node->traversed()) { + process_order->push_back(*i); + node->traversed(true); + } + } + + assert(process_order->size() == m_nodes.size()); + + return process_order; +} + + +/** Rename this Patch. + * + * This is responsible for updating the ObjectStore so the Patch can be + * found at it's new path, as well as all it's children. + */ +void +Patch::set_path(const Path& new_path) +{ + const Path old_path = path(); + + // Update nodes + for (List::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) + (*i)->set_path(new_path.base_path() + (*i)->name()); + + // Update self + NodeBase::set_path(new_path); +} + + +} // namespace Om diff --git a/src/libs/engine/Patch.h b/src/libs/engine/Patch.h new file mode 100644 index 00000000..e2a1ed48 --- /dev/null +++ b/src/libs/engine/Patch.h @@ -0,0 +1,136 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PATCH_H +#define PATCH_H + +#include +#include +#include "NodeBase.h" +#include "Plugin.h" +#include "List.h" + +using std::string; + +template class Array; + +namespace Om { + +class Connection; +class InternalNode; +namespace Shared { + class ClientInterface; +} using Shared::ClientInterface; + + +/** A group of nodes in a graph, possibly polyphonic. + * + * Note that this is also a Node, just one which contains Nodes. + * Therefore infinite subpatching is possible, of polyphonic + * patches of polyphonic nodes etc. etc. + * + * \ingroup engine + */ +class Patch : public NodeBase +{ +public: + Patch(const string& name, size_t poly, Patch* parent, samplerate srate, size_t buffer_size, size_t local_poly); + virtual ~Patch(); + + Patch* as_patch() { return static_cast(this); } + + void activate(); + void deactivate(); + + void run(size_t nframes); + + size_t num_ports() const; + + //void send_creation_messages(ClientInterface* client) const; + + void add_to_store(); + void remove_from_store(); + + void set_path(const Path& new_path); + + // Patch specific stuff not inherited from Node + + void add_node(ListNode* tn); + ListNode* remove_node(const string& name); + + List& nodes() { return m_nodes; } + List& connections() { return m_connections; } + + const List& nodes() const { return m_nodes; } + const List& connections() const { return m_connections; } + + void add_bridge_node(ListNode* n) { m_bridge_nodes.push_back(n); } + ListNode* remove_bridge_node(const InternalNode* n); + + void add_connection(ListNode* c) { m_connections.push_back(c); } + ListNode* remove_connection(const Port* src_port, const Port* dst_port); + + Array* process_order() { return m_process_order; } + void process_order(Array* po) { m_process_order = po; } + + Array* build_process_order() const; + inline void build_process_order_recursive(Node* n, Array* order) const; + + /** Whether to run this patch's DSP in the audio thread */ + bool process() const { return m_process; } + void process(bool b); + + size_t internal_poly() const { return m_internal_poly; } + + const Plugin* plugin() const { return &m_plugin; } + void plugin(const Plugin* const) { exit(EXIT_FAILURE); } + +private: + // Prevent copies (undefined) + Patch(const Patch&); + Patch& operator=(const Patch&); + + size_t m_internal_poly; + Array* m_process_order; + List m_connections; + List m_bridge_nodes; ///< Inputs and outputs + List m_nodes; + bool m_process; + + Plugin m_plugin; +}; + + + +/** Private helper for build_process_order */ +inline void +Patch::build_process_order_recursive(Node* n, Array* order) const +{ + if (n == NULL || n->traversed()) return; + n->traversed(true); + assert(order != NULL); + + for (List::iterator i = n->providers()->begin(); i != n->providers()->end(); ++i) + if ( ! (*i)->traversed() ) + build_process_order_recursive((*i), order); + + order->push_back(n); +} + + +} // namespace Om + +#endif // PATCH_H diff --git a/src/libs/engine/Plugin.h b/src/libs/engine/Plugin.h new file mode 100644 index 00000000..d350b1e8 --- /dev/null +++ b/src/libs/engine/Plugin.h @@ -0,0 +1,149 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_SLV2 +#include +#endif +using std::string; +using std::cerr; using std::endl; + + +namespace Om { + +class PluginLibrary; + + +/** Representation of a plugin (of various types). + * + * A Node is an instance of this, conceptually. + * FIXME: This whole thing is a filthy mess and needs a rewrite. Probably + * with derived classes for each plugin type. + */ +class Plugin +{ +public: + enum Type { LV2, LADSPA, DSSI, Internal, Patch }; + + Plugin() : m_type(Internal), m_lib_path("/Om"), + m_id(0), m_library(NULL) + { +#ifdef HAVE_SLV2 + m_slv2_plugin = NULL; +#endif + } + + Plugin(const Plugin* const copy) { + // Copying only allowed for Internal plugins. Bit of a hack, but + // allows the PluginInfo to be defined in the Node class which keeps + // things localized and convenient (FIXME?) + if (copy->m_type != Internal) + exit(EXIT_FAILURE); + m_type = copy->m_type; + m_lib_path = copy->m_lib_path; + m_plug_label = copy->m_plug_label; + m_name = copy->m_name; + m_library = copy->m_library; + } + + Type type() const { return m_type; } + void type(Type t) { m_type = t; } + const string& lib_path() const { return m_lib_path; } + void lib_path(const string& s) { m_lib_path = s; } + string lib_name() const { return m_lib_path.substr(m_lib_path.find_last_of("/")); } + const string& plug_label() const { return m_plug_label; } + void plug_label(const string& s) { m_plug_label = s; } + const string& name() const { return m_name; } + void name(const string& s) { m_name = s; } + unsigned long id() const { return m_id; } + void id(unsigned long i) { m_id = i; } + void uri(const string& s) { m_uri = s; } + const string uri() const + { + char id_str[11]; + snprintf(id_str, 11, "%lu", m_id); + + if (m_uri.length() > 0) { + return m_uri; + } else if (m_type == Internal) { + return string("om:") + m_plug_label; + } else if (m_type == LADSPA) { + return string("ladspa:").append(id_str); + } else if (m_type == DSSI) { + return string("dssi:") + lib_name() +":"+ m_plug_label; + } else { + return ""; + } + } + + PluginLibrary* library() const { return m_library; } + void library(PluginLibrary* const library) { m_library = library; } + + const char* type_string() const { + if (m_type == LADSPA) return "LADSPA"; + else if (m_type == LV2) return "LV2"; + else if (m_type == DSSI) return "DSSI"; + else if (m_type == Internal) return "Internal"; + else if (m_type == Patch) return "Patch"; + else return ""; + } + + void set_type(const string& type_string) { + if (type_string == "LADSPA") m_type = LADSPA; + else if (type_string == "LV2") m_type = LV2; + else if (type_string == "DSSI") m_type = DSSI; + else if (type_string == "Internal") m_type = Internal; + else if (type_string == "Patch") m_type = Patch; + } + + // FIXME: ew +#ifdef HAVE_SLV2 + SLV2Plugin* slv2_plugin() { return m_slv2_plugin; } + void slv2_plugin(const SLV2Plugin* p) { m_slv2_plugin = p; } + +#endif +private: + // Disallow copies (undefined) + Plugin(const Plugin&); + Plugin& operator=(const Plugin&); + + Type m_type; + string m_uri; ///< LV2 only + string m_lib_path; ///< LADSPA/DSSI only + string m_plug_label; ///< LADSPA/DSSI only + string m_name; ///< LADSPA/DSSI only + unsigned long m_id; ///< LADSPA/DSSI only + + PluginLibrary* m_library; + +#ifdef HAVE_SLV2 + SLV2Plugin* m_slv2_plugin; +#endif +}; + + +} // namespace Om + +#endif // PLUGIN_H + diff --git a/src/libs/engine/PluginLibrary.h b/src/libs/engine/PluginLibrary.h new file mode 100644 index 00000000..53279d8a --- /dev/null +++ b/src/libs/engine/PluginLibrary.h @@ -0,0 +1,100 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef PLUGINLIBRARY_H +#define PLUGINLIBRARY_H + +#include +#include +#include +using std::string; +using std::cerr; using std::endl; + + +namespace Om { + + +/** Representation of a shared library containing at least one Plugin. + * + * In the NodeFactory, this represents one loaded shared library instance, + * which is what handle() returns. + */ +class PluginLibrary +{ +public: + /** Construct a new PluginLibrary. + * + * Path is assumed to be the path of a valid shared library that can be + * successfully dlopen'ed. + */ + PluginLibrary(const string& path) + : m_path(path), m_handle(NULL) + {} + + ~PluginLibrary() + { + close(); + } + + /** Load and resolve all symbols in this shared library + * (dlopen with RTLD_NOW). + * + * It is okay to call this many times, the library will only be opened + * once. + */ + void open() + { + if (m_handle == NULL) { + dlerror(); + m_handle = dlopen(m_path.c_str(), RTLD_NOW); + if (m_handle == NULL) + cerr << "[PluginLibrary] Warning: Error opening shared library " + << m_path << "(" << dlerror() << ")" << endl; + } + } + + /** Close the dynamic library. + * + * This can be called on an already closed PluginLibrary without problems. + */ + void close() + { + if (m_handle != NULL) { + dlerror(); + if (dlclose(m_handle)) + cerr << "[PluginLibrary] Error closing shared library " << m_path + << "(" << dlerror() << ")" << endl; + } + m_handle = NULL; + } + + void* handle() const { return m_handle; } + +private: + // Disallow copies (undefined) + PluginLibrary(const PluginLibrary&); + PluginLibrary& operator=(const PluginLibrary&); + + string m_path; + void* m_handle; +}; + + +} // namespace Om + +#endif // PLUGINLIBRARY_H + diff --git a/src/libs/engine/Port.cpp b/src/libs/engine/Port.cpp new file mode 100644 index 00000000..987d232d --- /dev/null +++ b/src/libs/engine/Port.cpp @@ -0,0 +1,56 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Port.h" +#include "Node.h" +#include "PortInfo.h" +#include "Om.h" +#include "OmApp.h" +#include "ObjectStore.h" + +namespace Om { + +Port::Port(Node* const node, const string& name, size_t index, size_t poly, PortInfo* port_info) +: OmObject(node, name), + m_index(index), + m_poly(poly), + m_port_info(port_info) +{ + assert(node != NULL); + assert(port_info != NULL); + assert(m_poly > 0); +} + + +void +Port::add_to_store() +{ + om->object_store()->add(this); +} + + +void +Port::remove_from_store() +{ + // Remove self + TreeNode* node = om->object_store()->remove(path()); + assert(node != NULL); + assert(om->object_store()->find(path()) == NULL); + delete node; +} + + +} // namespace Om diff --git a/src/libs/engine/Port.h b/src/libs/engine/Port.h new file mode 100644 index 00000000..f51d7382 --- /dev/null +++ b/src/libs/engine/Port.h @@ -0,0 +1,80 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PORT_H +#define PORT_H + +#include +#include +#include "util/types.h" +#include "OmObject.h" + +using std::string; + +namespace Om { + +class Node; +class PortInfo; + + +/** A port on a Node. + * + * This is a non-template abstract base class, which basically exists so + * things can pass around Port pointers and not have to worry about type, + * templates, etc. + * + * \ingroup engine + */ +class Port : public OmObject +{ +public: + virtual ~Port() {} + + Port* as_port() { return this; } + + PortInfo* port_info() const { return m_port_info; } + void port_info(PortInfo* pi) { m_port_info = pi; } + + void add_to_store(); + void remove_from_store(); + + /** Called once per process cycle */ + virtual void prepare_buffers(size_t nframes) = 0; + + /** Empty buffer contents completely (ie silence) */ + virtual void clear_buffers() = 0; + + Node* parent_node() const { return m_parent->as_node(); } + bool is_sample() const { return false; } + size_t num() const { return m_index; } + size_t poly() const { return m_poly; } + +protected: + Port(Node* const node, const string& name, size_t index, size_t poly, PortInfo* port_info); + + // Prevent copies (undefined) + Port(const Port&); + Port& operator=(const Port&); + + size_t m_index; + size_t m_poly; + PortInfo* m_port_info; +}; + + +} // namespace Om + +#endif // PORT_H diff --git a/src/libs/engine/PortBase.cpp b/src/libs/engine/PortBase.cpp new file mode 100644 index 00000000..3d8dbc67 --- /dev/null +++ b/src/libs/engine/PortBase.cpp @@ -0,0 +1,133 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PortBase.h" +#include +#include +#include +#include +#include +#include "util.h" +#include "Node.h" +#include "PortInfo.h" +#include "MidiMessage.h" + +namespace Om { + + +/** Constructor for a Port. + */ +template +PortBase::PortBase(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size) +: Port(node, name, index, poly, port_info), + m_buffer_size(buffer_size), + m_fixed_buffers(false), + m_is_tied(false), + m_tied_port(NULL) +{ + allocate_buffers(); + clear_buffers(); + + assert(m_buffers.size() > 0); +} +template +PortBase::PortBase(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); +template +PortBase::PortBase(Node* node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); + + +template +PortBase::~PortBase() +{ + for (size_t i=0; i < m_poly; ++i) + delete m_buffers.at(i); + + delete m_port_info; +} +template PortBase::~PortBase(); +template PortBase::~PortBase(); + + +/** Set the port's value for all voices. + */ +template<> +void +PortBase::set_value(sample val, size_t offset) +{ + if (m_port_info->is_control()) + offset = 0; + assert(offset < m_buffer_size); + + for (size_t v=0; v < m_poly; ++v) + m_buffers.at(v)->set(val, offset); +} + +/** Set the port's value for a specific voice. + */ +template<> +void +PortBase::set_value(size_t voice, sample val, size_t offset) +{ + if (m_port_info->is_control()) + offset = 0; + assert(offset < m_buffer_size); + + m_buffers.at(voice)->set(val, offset); +} + + +template +void +PortBase::allocate_buffers() +{ + m_buffers.alloc(m_poly); + + for (size_t i=0; i < m_poly; ++i) + m_buffers.at(i) = new Buffer(m_buffer_size); +} +template void PortBase::allocate_buffers(); +template void PortBase::allocate_buffers(); + + +template<> +void +PortBase::prepare_buffers(size_t nframes) +{ + for (size_t i=0; i < m_poly; ++i) + m_buffers.at(i)->prepare(nframes); +} + + +template<> +void +PortBase::prepare_buffers(size_t nframes) +{ +} + + +template +void +PortBase::clear_buffers() +{ + for (size_t i=0; i < m_poly; ++i) + m_buffers.at(i)->clear(); +} +template void PortBase::clear_buffers(); +template void PortBase::clear_buffers(); + + +} // namespace Om + diff --git a/src/libs/engine/PortBase.h b/src/libs/engine/PortBase.h new file mode 100644 index 00000000..9962538e --- /dev/null +++ b/src/libs/engine/PortBase.h @@ -0,0 +1,87 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PORTBASE_H +#define PORTBASE_H + +#include +#include "util/types.h" +#include "Array.h" +#include "Port.h" +#include "Buffer.h" + +using std::string; + +namespace Om { + +class MidiMessage; +class Node; + + +/** A port (with a type). + * + * This is basically just a buffer and a bunch of flags and helper methods. + * All the interesting functionality of ports is in InputPort. + * + * \ingroup engine + */ +template +class PortBase : public Port +{ +public: + virtual ~PortBase(); + + void set_value(size_t voice, T val, size_t offset); + void set_value(T val, size_t offset); + + Buffer* buffer(size_t voice) const { return m_buffers.at(voice); } + + virtual void prepare_buffers(size_t nframes); + virtual void clear_buffers(); + + PortBase* tied_port() const { return m_tied_port; } + void untie() { m_is_tied = false; m_tied_port = NULL; } + + size_t buffer_size() const { return m_buffer_size; } + + /** Used by drivers to prevent port from changing buffers */ + void fixed_buffers(bool b) { m_fixed_buffers = b; } + bool fixed_buffers() { return m_fixed_buffers; } + +protected: + PortBase(Node* const node, const string& name, size_t index, size_t poly, PortInfo* port_info, size_t buffer_size); + + // Prevent copies (undefined) + PortBase(const PortBase& copy); + PortBase& operator=(const Port&); + + void allocate_buffers(); + + size_t m_buffer_size; + bool m_fixed_buffers; + bool m_is_tied; + PortBase* m_tied_port; + + Array*> m_buffers; +}; + + +template class PortBase; +template class PortBase; + +} // namespace Om + +#endif // PORTBASE_H diff --git a/src/libs/engine/PortInfo.h b/src/libs/engine/PortInfo.h new file mode 100644 index 00000000..3fa4215a --- /dev/null +++ b/src/libs/engine/PortInfo.h @@ -0,0 +1,153 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef PORTINFO_H +#define PORTINFO_H + +#include +#include +#include + +using std::string; + +namespace Om { + + +enum PortType { CONTROL, AUDIO, MIDI }; +enum PortDirection { INPUT = 0, OUTPUT = 1 }; // FIXME: dupe of ClientInterface::PortDirection +enum PortHint { NONE, INTEGER, TOGGLE, LOGARITHMIC }; + + +/** Information about a Port. + * + * I'm not sure this actually has a reason for existing anymore. This is the + * model for a Port, but no other OmObjects need a model, soo.... + * + * \ingroup engine + */ +class PortInfo +{ +public: + PortInfo(const string& port_name, PortType type, PortDirection dir, PortHint hint, float default_val, float min, float max) + : m_name(port_name), + m_type(type), + m_direction(dir), + m_hint(hint), + m_default_val(default_val), + m_min_val(min), + m_max_val(max) + {} + + PortInfo(const string& port_name, PortType type, PortDirection dir, float default_val, float min, float max) + : m_name(port_name), + m_type(type), + m_direction(dir), + m_hint(NONE), + m_default_val(default_val), + m_min_val(min), + m_max_val(max) + {} + + PortInfo(const string& port_name, PortType type, PortDirection dir, PortHint hint = NONE) + : m_name(port_name), + m_type(type), + m_direction(dir), + m_hint(hint), + m_default_val(0.0f), + m_min_val(0.0f), + m_max_val(1.0f) + {} + + PortInfo(const string& port_name, LADSPA_PortDescriptor d, LADSPA_PortRangeHintDescriptor hint) + : m_name(port_name), + m_default_val(1.0f), + m_min_val(0.0f), + m_max_val(1.0f) + { + if (LADSPA_IS_PORT_AUDIO(d)) m_type = AUDIO; + else if (LADSPA_IS_PORT_CONTROL(d)) m_type = CONTROL; + else exit(EXIT_FAILURE); + + if (LADSPA_IS_PORT_INPUT(d)) m_direction = INPUT; + else if (LADSPA_IS_PORT_OUTPUT(d)) m_direction = OUTPUT; + else exit(EXIT_FAILURE); + + if (LADSPA_IS_HINT_TOGGLED(hint)) { + m_hint = TOGGLE; m_min_val = 0; m_max_val = 1; m_default_val = 0; + } else if (LADSPA_IS_HINT_LOGARITHMIC(hint)) + m_hint = LOGARITHMIC; + else if (LADSPA_IS_HINT_INTEGER(hint)) + m_hint = INTEGER; + else + m_hint = NONE; + } + + PortType type() const { return m_type; } + void type(PortType t) { m_type = t; } + float min_val() const { return m_min_val; } + void min_val(float f) { m_min_val = f; } + float default_val() const { return m_default_val; } + void default_val(float f) { m_default_val = f; } + float max_val() const { return m_max_val; } + void max_val(float f) { m_max_val = f; } + PortDirection direction() const { return m_direction; } + + string type_string() { + switch (m_type) { + case CONTROL: return "CONTROL"; break; + case AUDIO: return "AUDIO"; break; + case MIDI: return "MIDI"; break; + default: return "UNKNOWN"; + } + } + string direction_string() { if (m_direction == INPUT) return "INPUT"; else return "OUTPUT"; } + string hint_string() { if (m_hint == INTEGER) return "INTEGER"; + else if (m_hint == LOGARITHMIC) return "LOGARITHMIC"; + else if (m_hint == TOGGLE) return "TOGGLE"; + else return "NONE"; } + + bool is_control() const { return (m_type == CONTROL); } + bool is_audio() const { return (m_type == AUDIO); } + bool is_midi() const { return (m_type == MIDI); } + bool is_input() const { return (m_direction == INPUT); } + bool is_output() const { return (m_direction == OUTPUT); } + + bool is_logarithmic() const { return (m_hint == LOGARITHMIC); } + bool is_integer() const { return (m_hint == INTEGER); } + bool is_toggle() const { return (m_hint == TOGGLE); } + + const string& name() const { return m_name; } + void name(const string& n) { m_name = n; } + +private: + // Prevent copies (undefined) + PortInfo(const PortInfo&); + PortInfo& operator=(const PortInfo&); + + string m_name; + PortType m_type; + PortDirection m_direction; + PortHint m_hint; + float m_default_val; + float m_min_val; + float m_max_val; +}; + + +} // namespace Om + +#endif // PORTINFO_H diff --git a/src/libs/engine/PostProcessor.cpp b/src/libs/engine/PostProcessor.cpp new file mode 100644 index 00000000..65b92015 --- /dev/null +++ b/src/libs/engine/PostProcessor.cpp @@ -0,0 +1,122 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PostProcessor.h" +#include +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "Event.h" +#include "util/Queue.h" +#include "Maid.h" + + +using std::cerr; using std::cout; using std::endl; + +namespace Om { + +bool PostProcessor::m_process_thread_exit_flag = false; + + +PostProcessor::PostProcessor(size_t queue_size) +: m_events(queue_size), + m_thread_exists(false), + m_semaphore(0) +{ +} + + +PostProcessor::~PostProcessor() +{ + stop(); +} + + +/** Start the process thread. + */ +void +PostProcessor::start() +{ + cout << "[PostProcessor] Starting." << endl; + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 1500000); + + pthread_create(&m_process_thread, &attr, process_events, this); + m_thread_exists = true; +} + + +/** Stop the process thread. + */ +void +PostProcessor::stop() +{ + if (m_thread_exists) { + m_process_thread_exit_flag = true; + pthread_cancel(m_process_thread); + pthread_join(m_process_thread, NULL); + m_thread_exists = false; + } +} + + +/** Signal the PostProcessor to process all pending events. + */ +void +PostProcessor::signal() +{ + m_semaphore.post(); +} + + +void* +PostProcessor::process_events(void* osc_processer) +{ + PostProcessor* me = (PostProcessor*)osc_processer; + return me->m_process_events(); +} + + +/** OSC message processing thread. + */ +void* +PostProcessor::m_process_events() +{ + Event* ev = NULL; + + while (true) { + m_semaphore.wait(); + + if (m_process_thread_exit_flag) + break; + + while (!m_events.is_empty()) { + ev = m_events.pop(); + assert(ev != NULL); + ev->post_process(); + om->maid()->push(ev); + } + } + + cout << "[PostProcessor] Exiting post processor thread." << endl; + + return NULL; +} + +} // namespace Om diff --git a/src/libs/engine/PostProcessor.h b/src/libs/engine/PostProcessor.h new file mode 100644 index 00000000..843569d8 --- /dev/null +++ b/src/libs/engine/PostProcessor.h @@ -0,0 +1,78 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef POSTPROCESSOR_H +#define POSTPROCESSOR_H + +#include +#include "util/types.h" +#include "util/Queue.h" +#include "util/Semaphore.h" + +namespace Om { + +class Event; + + +/** Processor for Events after leaving the audio thread. + * + * The audio thread pushes events to this when it is done with them (which + * is realtime-safe), which signals the processing thread through a semaphore + * to handle the event and pass it on to the Maid. + * + * \ingroup engine + */ +class PostProcessor +{ +public: + PostProcessor(size_t queue_size); + ~PostProcessor(); + + void start(); + void stop(); + + inline void push(Event* const ev); + void signal(); + +private: + // Prevent copies + PostProcessor(const PostProcessor&); + PostProcessor& operator=(const PostProcessor&); + + Queue m_events; + + static void* process_events(void* me); + void* m_process_events(); + + pthread_t m_process_thread; + bool m_thread_exists; + static bool m_process_thread_exit_flag; + Semaphore m_semaphore; +}; + + +/** Push an event on to the process queue, realtime-safe, not thread-safe. + */ +inline void +PostProcessor::push(Event* const ev) +{ + m_events.push(ev); +} + + +} // namespace Om + +#endif // POSTPROCESSOR_H diff --git a/src/libs/engine/QueuedEngineInterface.cpp b/src/libs/engine/QueuedEngineInterface.cpp new file mode 100644 index 00000000..0734eb7a --- /dev/null +++ b/src/libs/engine/QueuedEngineInterface.cpp @@ -0,0 +1,299 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "QueuedEngineInterface.h" +#include "QueuedEventSource.h" +#include "events.h" +#include "Om.h" +#include "util/Queue.h" +#include "OmApp.h" + +namespace Om { + +QueuedEngineInterface::QueuedEngineInterface(size_t queue_size) +: QueuedEventSource(queue_size) +, _responder(CountedPtr(new Responder())) // NULL responder +{ +} + + +/** Set the Responder to send responses to commands with, once the commands + * are preprocessed and ready to be executed (or not). + * + * Ownership of @a responder is taken. + */ +void +QueuedEngineInterface::set_responder(CountedPtr responder) +{ + //cerr << "SET\n"; + _responder = responder; +} + + +void +QueuedEngineInterface::disable_responses() +{ + static CountedPtr null_responder(new Responder()); + //cerr << "DISABLE\n"; + set_responder(null_responder); +} + + +/* *** EngineInterface implementation below here *** */ + + +void +QueuedEngineInterface::register_client(ClientKey key, CountedPtr client) +{ + RegisterClientEvent* ev = new RegisterClientEvent(_responder, key, client); + push(ev); +} + + +void +QueuedEngineInterface::unregister_client(ClientKey key) +{ + UnregisterClientEvent* ev = new UnregisterClientEvent(_responder, key); + push(ev); +} + + + +// Engine commands +void +QueuedEngineInterface::load_plugins() +{ + LoadPluginsEvent* ev = new LoadPluginsEvent(_responder); + push(ev); + +} + + +void +QueuedEngineInterface::activate() +{ + ActivateEvent* ev = new ActivateEvent(_responder); + push(ev); +} + + +void +QueuedEngineInterface::deactivate() +{ + DeactivateEvent* ev = new DeactivateEvent(_responder); + push(ev); +} + + +void +QueuedEngineInterface::quit() +{ + _responder->respond_ok(); + om->quit(); +} + + + +// Object commands + +void +QueuedEngineInterface::create_patch(const string& path, + uint32_t poly) +{ + CreatePatchEvent* ev = new CreatePatchEvent(_responder, path, poly); + push(ev); + +} + + +void +QueuedEngineInterface::create_node(const string& path, + const string& plugin_type, + const string& plugin_uri, + bool polyphonic) +{ + // FIXME: ew + + Plugin* plugin = new Plugin(); + plugin->set_type(plugin_type); + plugin->uri(plugin_uri); + + AddNodeEvent* ev = new AddNodeEvent(_responder, + path, plugin, polyphonic); + push(ev); +} + + +void +QueuedEngineInterface::rename(const string& old_path, + const string& new_name) +{ + RenameEvent* ev = new RenameEvent(_responder, old_path, new_name); + push(ev); +} + + +void +QueuedEngineInterface::destroy(const string& path) +{ + DestroyEvent* ev = new DestroyEvent(_responder, path); + push(ev); +} + + +void +QueuedEngineInterface::clear_patch(const string& patch_path) +{ +} + + +void +QueuedEngineInterface::enable_patch(const string& patch_path) +{ + EnablePatchEvent* ev = new EnablePatchEvent(_responder, patch_path); + push(ev); +} + + +void +QueuedEngineInterface::disable_patch(const string& patch_path) +{ + DisablePatchEvent* ev = new DisablePatchEvent(_responder, patch_path); + push(ev); +} + + +void +QueuedEngineInterface::connect(const string& src_port_path, + const string& dst_port_path) +{ + ConnectionEvent* ev = new ConnectionEvent(_responder, src_port_path, dst_port_path); + push(ev); + +} + + +void +QueuedEngineInterface::disconnect(const string& src_port_path, + const string& dst_port_path) +{ + DisconnectionEvent* ev = new DisconnectionEvent(_responder, src_port_path, dst_port_path); + push(ev); +} + + +void +QueuedEngineInterface::disconnect_all(const string& node_path) +{ + DisconnectNodeEvent* ev = new DisconnectNodeEvent(_responder, node_path); + push(ev); +} + + +void +QueuedEngineInterface::set_port_value(const string& port_path, + float value) +{ + SetPortValueEvent* ev = new SetPortValueEvent(_responder, port_path, value); + om->event_queue()->push(ev); +} + + +void +QueuedEngineInterface::set_port_value(const string& port_path, + uint32_t voice, + float value) +{ + SetPortValueEvent* ev = new SetPortValueEvent(_responder, voice, port_path, value); + om->event_queue()->push(ev); +} + + +void +QueuedEngineInterface::set_port_value_queued(const string& port_path, + float value) +{ + SetPortValueQueuedEvent* ev = new SetPortValueQueuedEvent(_responder, port_path, value); + push(ev); +} + + +void +QueuedEngineInterface::set_program(const string& node_path, + uint32_t bank, + uint32_t program) +{ + push(new DSSIProgramEvent(_responder, node_path, bank, program)); +} + + +void +QueuedEngineInterface::midi_learn(const string& node_path) +{ + MidiLearnEvent* ev = new MidiLearnEvent(_responder, node_path); + push(ev); +} + + +void +QueuedEngineInterface::set_metadata(const string& path, + const string& predicate, + const string& value) +{ + SetMetadataEvent* ev = new SetMetadataEvent(_responder, + path, predicate, value); + + push(ev); +} + + +// Requests // + +void +QueuedEngineInterface::ping() +{ + PingQueuedEvent* ev = new PingQueuedEvent(_responder); + push(ev); +} + + +void +QueuedEngineInterface::request_port_value(const string& port_path) +{ + RequestPortValueEvent* ev = new RequestPortValueEvent(_responder, port_path); + push(ev); +} + + +void +QueuedEngineInterface::request_plugins() +{ + RequestPluginsEvent* ev = new RequestPluginsEvent(_responder); + push(ev); +} + + +void +QueuedEngineInterface::request_all_objects() +{ + RequestAllObjectsEvent* ev = new RequestAllObjectsEvent(_responder); + push(ev); +} + + +} // namespace Om + + diff --git a/src/libs/engine/QueuedEngineInterface.h b/src/libs/engine/QueuedEngineInterface.h new file mode 100644 index 00000000..cc9c575f --- /dev/null +++ b/src/libs/engine/QueuedEngineInterface.h @@ -0,0 +1,145 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef QUEUEDENGINEINTERFACE_H +#define QUEUEDENGINEINTERFACE_H + +#include +#include +#include +#include "util/CountedPtr.h" +#include "interface/ClientInterface.h" +#include "interface/ClientKey.h" +#include "QueuedEventSource.h" +#include "Responder.h" +using std::string; + +namespace Om { + +using Shared::ClientKey; +using Shared::ClientInterface; + + +/** A queued (preprocessed) event source / interface. + * + * This is the bridge between the EngineInterface presented to the client, and + * the EventSource that needs to be presented to the AudioDriver. + * + * This is sort of a state machine, \ref set_responder sets the Responder that + * will be used to send the response from all future function calls. Stateless + * protocols like UDP/OSC can use this to set a different response address for + * each event (eg incoming UDP port), but engine/client interfaces that don't + * need to change an 'address' constantly can just set it once on initialisation. + * Blocking control interfaces can be made by setting a Responder which signals + * the caller when the 'response' is 'sent'. + * + * If you do not register a responder, you have no way of knowing if your calls + * are successful. + * + * FIXME: this isn't really "queued" entirely, since some events aren't queued + * events and get pushed directly into the realtime event queue. Should that + * be separated into a different interface/client? + */ +class QueuedEngineInterface : public Om::QueuedEventSource +{ +public: + QueuedEngineInterface(size_t queue_size); + virtual ~QueuedEngineInterface() {} + + virtual void set_responder(CountedPtr responder); + virtual void disable_responses(); + + // Client registration + virtual void register_client(ClientKey key, CountedPtr client); + virtual void unregister_client(ClientKey key); + + + // Engine commands + virtual void load_plugins(); + virtual void activate(); + virtual void deactivate(); + virtual void quit(); + + // Object commands + + virtual void create_patch(const string& path, + uint32_t poly); + + virtual void create_node(const string& path, + const string& plugin_type, + const string& plugin_uri, + bool polyphonic); + + virtual void rename(const string& old_path, + const string& new_name); + + virtual void destroy(const string& path); + + virtual void clear_patch(const string& patch_path); + + virtual void enable_patch(const string& patch_path); + + virtual void disable_patch(const string& patch_path); + + virtual void connect(const string& src_port_path, + const string& dst_port_path); + + virtual void disconnect(const string& src_port_path, + const string& dst_port_path); + + virtual void disconnect_all(const string& node_path); + + virtual void set_port_value(const string& port_path, + float val); + + virtual void set_port_value(const string& port_path, + uint32_t voice, + float val); + + virtual void set_port_value_queued(const string& port_path, + float val); + + virtual void set_program(const string& node_path, + uint32_t bank, + uint32_t program); + + virtual void midi_learn(const string& node_path); + + virtual void set_metadata(const string& path, + const string& predicate, + const string& value); + + // Requests // + + virtual void ping(); + + virtual void request_port_value(const string& port_path); + + virtual void request_plugins(); + + virtual void request_all_objects(); + +protected: + + /** Where responses to current messages will go. */ + CountedPtr _responder; +}; + + +} // namespace Om + +#endif // QUEUEDENGINEINTERFACE_H + diff --git a/src/libs/engine/QueuedEvent.h b/src/libs/engine/QueuedEvent.h new file mode 100644 index 00000000..16560aaa --- /dev/null +++ b/src/libs/engine/QueuedEvent.h @@ -0,0 +1,86 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef QUEUEDEVENT_H +#define QUEUEDEVENT_H + +#include "Event.h" + +namespace Om { + +class Responder; +class QueuedEventSource; + + +/** An Event with a not-time-critical preprocessing stage. + * + * These events are events that aren't able to be executed immediately by the + * Jack thread (because they allocate memory or whatever). They are pushed + * on to the QueuedEventQueue where they are preprocessed then pushed on + * to the realtime Event Queue when they are ready. + * + * Lookups for these events should go in the pre_process() method, since they are + * not time critical and shouldn't waste time in the audio thread doing + * lookups they can do beforehand. (This applies for any expensive operation that + * could be done before the execute() method). + * + * \ingroup engine + */ +class QueuedEvent : public Event +{ +public: + /** Process this event into a realtime-suitable event. + */ + virtual void pre_process() { + assert(m_pre_processed == false); + m_pre_processed = true; + } + + virtual void execute(samplecount offset) { + assert(m_pre_processed); + Event::execute(offset); + } + + virtual void post_process() {} + + /** If this event blocks the prepare phase of other slow events */ + bool is_blocking() { return m_blocking; } + + bool is_prepared() { return m_pre_processed; } + +protected: + // Prevent copies + QueuedEvent(const QueuedEvent& copy); + QueuedEvent& operator=(const QueuedEvent&); + + QueuedEvent(CountedPtr responder, bool blocking = false, QueuedEventSource* source=NULL) + : Event(responder), m_pre_processed(false), m_blocking(blocking), m_source(source) + {} + + // NULL event base (for internal events) + QueuedEvent() + : Event(), m_pre_processed(false), m_blocking(false), m_source(NULL) + {} + + bool m_pre_processed; + bool m_blocking; + QueuedEventSource* m_source; +}; + + +} // namespace Om + +#endif // QUEUEDEVENT_H diff --git a/src/libs/engine/QueuedEventSource.cpp b/src/libs/engine/QueuedEventSource.cpp new file mode 100644 index 00000000..953eb5b1 --- /dev/null +++ b/src/libs/engine/QueuedEventSource.cpp @@ -0,0 +1,201 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "QueuedEventSource.h" +#include "QueuedEvent.h" +#include +#include +using std::cout; using std::cerr; using std::endl; + + +namespace Om { + + +QueuedEventSource::QueuedEventSource(size_t size) +: m_front(0), + m_back(0), + m_prepared_back(0), + m_size(size+1), + m_thread_exists(false), + m_prepare_thread_exit_flag(false), + m_semaphore(0) +{ + m_events = (QueuedEvent**)calloc(m_size, sizeof(QueuedEvent*)); + + pthread_mutex_init(&m_blocking_mutex, NULL); + pthread_cond_init(&m_blocking_cond, NULL); + + mlock(m_events, m_size * sizeof(QueuedEvent*)); +} + + +QueuedEventSource::~QueuedEventSource() +{ + stop(); + + free(m_events); + pthread_mutex_destroy(&m_blocking_mutex); + pthread_cond_destroy(&m_blocking_cond); +} + + +/** Start the prepare thread. + */ +void +QueuedEventSource::start() +{ + if (m_thread_exists) { + cerr << "[QueuedEventSource] Thread already launched?" << endl; + return; + } else { + cout << "[QueuedEventSource] Launching thread." << endl; + } + + m_prepare_thread_exit_flag = false; + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 1500000); + + pthread_create(&m_prepare_thread, &attr, &QueuedEventSource::prepare_loop, this); + pthread_attr_destroy(&attr); + + m_thread_exists = true; +} + + +/** Destroy the prepare thread. + */ +void +QueuedEventSource::stop() +{ + if (m_thread_exists) { + m_prepare_thread_exit_flag = true; + pthread_cancel(m_prepare_thread); + pthread_join(m_prepare_thread, NULL); + m_thread_exists = false; + cout << "[QueuedEventSource] Stopped thread." << endl; + } +} + + +/** Push an unprepared event onto the queue. + */ +void +QueuedEventSource::push(QueuedEvent* const ev) +{ + assert(!ev->is_prepared()); + + if (m_events[m_back] != NULL) { + cerr << "[QueuedEventSource] Error: Queue is full! Event is lost, please report!" << endl; + delete ev; + } else { + m_events[m_back] = ev; + m_back = (m_back + 1) % m_size; + m_semaphore.post(); + } +} + + +/** Pops the prepared event at the front of the queue, if it exists. + * + * This method will only pop events that have been prepared, and are + * stamped before the time passed. In other words, it may return NULL + * even if there are events pending in the queue. The events returned are + * actually QueuedEvent*s, but after this they are "normal" events and the + * engine deals with them just like a realtime in-band event. + */ +Event* +QueuedEventSource::pop_earliest_event_before(const samplecount time) +{ + QueuedEvent* front_event = m_events[m_front]; + + // Pop + if (front_event != NULL && front_event->time_stamp() < time && front_event->is_prepared()) { + m_events[m_front] = NULL; + m_front = (m_front + 1) % m_size; + return front_event; + } else { + return NULL; + } +} + + +// Private // + + + +/** Signal that the blocking event is finished. + * + * When this is called preparing will resume. This will be called by + * blocking events in their post_process() method. + */ +void +QueuedEventSource::unblock() +{ + /* FIXME: Make this a semaphore, and have events signal at the end of their + * execute() methods so the preprocessor can start preparing events immediately + * instead of waiting for the postprocessor to get around to finalizing the event? */ + pthread_mutex_lock(&m_blocking_mutex); + pthread_cond_signal(&m_blocking_cond); + pthread_mutex_unlock(&m_blocking_mutex); +} + + +void* +QueuedEventSource::m_prepare_loop() +{ + QueuedEvent* ev = NULL; + + while (true) { + m_semaphore.wait(); + + if (m_prepare_thread_exit_flag) + break; // exit signalled + + ev = m_events[m_prepared_back]; + assert(ev != NULL); + + if (ev == NULL) { + cerr << "[QueuedEventSource] ERROR: Signalled, but event is NULL." << endl; + continue; + } + + assert(ev != NULL); + assert(!ev->is_prepared()); + + if (ev->is_blocking()) + pthread_mutex_lock(&m_blocking_mutex); + + ev->pre_process(); + + m_prepared_back = (m_prepared_back+1) % m_size; + + // If a blocking event, wait for event to finish passing through + // the audio cycle before preparing the next event + if (ev->is_blocking()) { + pthread_cond_wait(&m_blocking_cond, &m_blocking_mutex); + pthread_mutex_unlock(&m_blocking_mutex); + } + } + + cout << "[QueuedEventSource] Exiting slow event queue thread." << endl; + return NULL; +} + + +} // namespace Om + diff --git a/src/libs/engine/QueuedEventSource.h b/src/libs/engine/QueuedEventSource.h new file mode 100644 index 00000000..002fc642 --- /dev/null +++ b/src/libs/engine/QueuedEventSource.h @@ -0,0 +1,83 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef QUEUEDEVENTSOURCE_H +#define QUEUEDEVENTSOURCE_H + +#include +#include +#include "util/types.h" +#include "util/Semaphore.h" +#include "EventSource.h" + +namespace Om { + +class Event; +class QueuedEvent; + + +/** Queue of events that need processing before reaching the audio thread. + * + * Implemented as a deque (ringbuffer) in a circular array. Pushing and + * popping are threadsafe, as long as a single thread pushes and a single + * thread pops (ie this data structure is threadsafe, but the push and pop + * methods themselves are not). + */ +class QueuedEventSource : public EventSource +{ +public: + QueuedEventSource(size_t size); + ~QueuedEventSource(); + + Event* pop_earliest_event_before(const samplecount time); + + void unblock(); + + void start(); + void stop(); + +protected: + void push(QueuedEvent* const ev); + +private: + // Prevent copies (undefined) + QueuedEventSource(const QueuedEventSource&); + QueuedEventSource& operator=(const QueuedEventSource&); + + // Note that it's crucially important which functions access which of these + // variables, to maintain threadsafeness. + + size_t m_front; ///< Front of queue + size_t m_back; ///< Back of entire queue (1 past index of back element) + size_t m_prepared_back; ///< Back of prepared section (1 past index of back prepared element) + const size_t m_size; + QueuedEvent** m_events; + + bool m_thread_exists; + bool m_prepare_thread_exit_flag; + pthread_t m_prepare_thread; + Semaphore m_semaphore; ///< Counting semaphor for driving prepare thread + pthread_mutex_t m_blocking_mutex; + pthread_cond_t m_blocking_cond; + + static void* prepare_loop(void* q) { return ((QueuedEventSource*)q)->m_prepare_loop(); } + void* m_prepare_loop(); +}; + + +} // namespace Om + +#endif // QUEUEDEVENTSOURCE_H diff --git a/src/libs/engine/Responder.h b/src/libs/engine/Responder.h new file mode 100644 index 00000000..cf16a20a --- /dev/null +++ b/src/libs/engine/Responder.h @@ -0,0 +1,63 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef RESPONDER_H +#define RESPONDER_H + +#include +#include +#include "util/CountedPtr.h" +#include "interface/ClientInterface.h" +using std::string; + +namespace Om { + +using Shared::ClientInterface; + + +/** Class to handle responding to clients. + * + * This is an abstract base class to fully abstract the details of client + * communication from the internals of the engine. + * + * Note that this class only handles sending responses to commands from + * clients, (ie OK or an error), not notifications (ie new node, + * disconnection) - that's what ClientInterface is for. If a command is + * a request, \ref find_client can find the corresponding ClientInterface + * for this client to send the reply to. + * + * ClientInterface and Responder are seperate because responding might not + * actually get exposed to the client interface (eg in simulated blocking + * interfaces that wait for responses before returning). + */ +class Responder +{ +public: + Responder() {} + virtual ~Responder() {} + + virtual CountedPtr find_client() + { return CountedPtr(NULL); } + + virtual void respond_ok() {} + virtual void respond_error(const string& msg) {} +}; + + +} // namespace Om + +#endif // RESPONDER_H + diff --git a/src/libs/engine/TransportNode.cpp b/src/libs/engine/TransportNode.cpp new file mode 100644 index 00000000..f5183d56 --- /dev/null +++ b/src/libs/engine/TransportNode.cpp @@ -0,0 +1,155 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "TransportNode.h" +#include +#include "OutputPort.h" +#include "Plugin.h" +#include "JackAudioDriver.h" +#include "Port.h" +#include "util.h" +#include "Om.h" +#include "OmApp.h" +#include "PortInfo.h" + +namespace Om { + + +TransportNode::TransportNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size) +: InternalNode(path, 1, parent, srate, buffer_size) +{ + m_num_ports = 10; + m_ports.alloc(m_num_ports); + + OutputPort* spb_port = new OutputPort(this, "Seconds per Beat", 0, 1, + new PortInfo("Seconds per Beat", CONTROL, OUTPUT, 0, 0, 1), 1); + m_ports.at(0) = spb_port; + + OutputPort* bpb_port = new OutputPort(this, "Beats per Bar", 1, 1, + new PortInfo("Beats per Bar", CONTROL, OUTPUT, 0, 0, 1), 1); + m_ports.at(1) = bpb_port; + + OutputPort* bar_port = new OutputPort(this, "Bar", 3, 1, + new PortInfo("Bar", CONTROL, OUTPUT, 0, 0, 1), buffer_size); + m_ports.at(2) = bar_port; + + OutputPort* beat_port = new OutputPort(this, "Beat", 3, 1, + new PortInfo("Beat", CONTROL, OUTPUT, 0, 0, 1), buffer_size); + m_ports.at(3) = beat_port; + + OutputPort* frame_port = new OutputPort(this, "Frame", 3, 1, + new PortInfo("Frame", CONTROL, OUTPUT, 0, 0, 1), buffer_size); + m_ports.at(4) = frame_port; + + OutputPort* hour_port = new OutputPort(this, "Hour", 3, 1, + new PortInfo("Hour", CONTROL, OUTPUT, 0, 0, 1), buffer_size); + m_ports.at(5) = hour_port; + + OutputPort* minute_port = new OutputPort(this, "Minute", 3, 1, + new PortInfo("Minute", CONTROL, OUTPUT, 0, 0, 1), buffer_size); + m_ports.at(6) = minute_port; + + OutputPort* second_port = new OutputPort(this, "Second", 3, 1, + new PortInfo("Second", CONTROL, OUTPUT, 0, 0, 1), buffer_size); + m_ports.at(7) = second_port; + + OutputPort* trg_port = new OutputPort(this, "Beat Tick", 2, 1, + new PortInfo("Beat Tick", AUDIO, OUTPUT, 0, 0, 1), buffer_size); + m_ports.at(8) = trg_port; + + OutputPort* bar_trig_port = new OutputPort(this, "Bar Tick", 3, 1, + new PortInfo("Bar Tick", AUDIO, OUTPUT, 0, 0, 1), buffer_size); + m_ports.at(9) = bar_trig_port; + + m_plugin.type(Plugin::Internal); + m_plugin.plug_label("transport"); + m_plugin.name("Om Transport Node (BROKEN)"); +} + + +void +TransportNode::run(size_t nframes) +{ + NodeBase::run(nframes); +#if 0 + + // FIXME: this will die horribly with any driver other than jack (in theory) + const jack_position_t* const position = ((JackAudioDriver*)om->audio_driver())->position(); + jack_transport_state_t state = ((JackAudioDriver*)om->audio_driver())->transport_state(); + double bpm = position->beats_per_minute; + float bpb = position->beats_per_bar; + float spb = 60.0 / bpm; + + //cerr << "bpm = " << bpm << endl; + //cerr << "spb = " << spb << endl; + + if (position->valid & JackPositionBBT) { + cerr << "bar: " << position->bar << endl; + cerr << "beat: " << position->beat << endl; + cerr << "tick: " << position->tick << endl; + } else { + cerr << "No BBT" << endl; + } + + if (position->valid & JackBBTFrameOffset) { + cerr << "bbt_offset: " << position->bbt_offset << endl; + } else { + cerr << "No BBT offset" << endl; + } + + if (position->valid & JackPositionTimecode) { + double time = position->frame_time; + cerr << "Seconds: " << time << " : " << endl; + /*time /= 60.0; + cerr << "Minutes: " << time << " : "; + time /= 60.0; + cerr << "Hours: " << time << " : ";*/ + } else { + cerr << "No timecode." << endl; + } + + + ((OutputPort*)m_ports.at(0))->buffer(0)->set(spb, 0, 0); + ((OutputPort*)m_ports.at(1))->buffer(0)->set(bpb, 0, 0); + + // fill the trigger buffers with zeros + ((OutputPort*)m_ports.at(2))->buffer(0)->set(0.0f, 0, nframes - 1); + ((OutputPort*)m_ports.at(3))->buffer(0)->set(0.0f, 0, nframes - 1); + + // if the transport is rolling, add triggers at the right frame positions + if ((position->valid & JackTransportBBT) && (state == JackTransportRolling)) { + double frames_per_beat = position->frame_rate * spb; + double first_beat = (1.0f - position->tick / position->ticks_per_beat) * frames_per_beat; + int first_beat_no = position->beat; + if (first_beat >= frames_per_beat) { + first_beat -= frames_per_beat; + --first_beat_no; + } + for ( ; first_beat < nframes; first_beat += frames_per_beat) { + ((OutputPort*)m_ports.at(2))->buffer(0)->set(1.0f, size_t(first_beat)); + if (first_beat_no % int(bpb) == 0) { + ((OutputPort*)m_ports.at(3))->buffer(0)->set(1.0f, size_t(first_beat)); + ++first_beat_no; + } + } + } + #endif +} + + +} // namespace Om + diff --git a/src/libs/engine/TransportNode.h b/src/libs/engine/TransportNode.h new file mode 100644 index 00000000..15b1059c --- /dev/null +++ b/src/libs/engine/TransportNode.h @@ -0,0 +1,48 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef TRANSPORTNODE_H +#define TRANSPORTNODE_H + + +#include +#include +#include "InternalNode.h" + +namespace Om { + +using std::string; + + +/** Transport Node, brings timing information into patches. + * + * This node uses the Jack transport API to get information about BPM, time + * signature, etc.. all sample accurate. Using this you can do + * tempo-synced effects or even synthesis, etc. + */ +class TransportNode : public InternalNode +{ +public: + TransportNode(const string& path, size_t poly, Patch* parent, samplerate srate, size_t buffer_size); + + void run(size_t nframes); +}; + + +} // namespace Om + +#endif // TRANSPORTNODE_H diff --git a/src/libs/engine/Tree.h b/src/libs/engine/Tree.h new file mode 100644 index 00000000..033d48b7 --- /dev/null +++ b/src/libs/engine/Tree.h @@ -0,0 +1,155 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NODETREE_H +#define NODETREE_H + +#include +#include +#include "MaidObject.h" +using std::string; + +template class Tree; + + +/** A node in a Tree. + */ +template +class TreeNode : public MaidObject +{ +public: + TreeNode(const string& key) + : m_parent(NULL), m_left_child(NULL), m_right_child(NULL), + m_key(key), m_node(NULL) {} + + TreeNode(const string& key, T n) + : m_parent(NULL), m_left_child(NULL), m_right_child(NULL), + m_key(key), m_node(n) {} + + ~TreeNode() { + assert(m_parent == NULL || m_parent->left_child() != this); + assert(m_parent == NULL || m_parent->right_child() != this); + assert(m_left_child == NULL || m_left_child->parent() != this); + assert(m_right_child == NULL || m_right_child->parent() != this); + m_parent = m_left_child = m_right_child = NULL; + } + + string key() const { return m_key; } + void key(const string& key) { m_key = key; } + TreeNode* parent() const { return m_parent; } + void parent(TreeNode* n) { m_parent = n; } + TreeNode* left_child() const { return m_left_child; } + void left_child(TreeNode* n) { m_left_child = n; } + TreeNode* right_child() const { return m_right_child; } + void right_child(TreeNode* n) { m_right_child = n; } + + bool is_leaf() { return (m_left_child == NULL && m_right_child == NULL); } + bool is_left_child() { return (m_parent != NULL && m_parent->left_child() == this); } + bool is_right_child() { return (m_parent != NULL && m_parent->right_child() == this); } + + T node() { return m_node; } + + friend class Tree; + +protected: + // Prevent copies (undefined) + TreeNode(const TreeNode&); + TreeNode& operator=(const TreeNode&); + + TreeNode* m_parent; + TreeNode* m_left_child; + TreeNode* m_right_child; + string m_key; + T m_node; +}; + + +/** The tree all objects are stored in. + * + * Textbook naive (unbalanced) Binary Search Tree. Slightly different + * from a usual BST implementation in that the "Node" classes (TreeNode) are + * exposed to the user. This is so QueuedEvent's can create the TreeNode in + * another thread, and the realtime jack thread can insert them (without having + * to allocating a TreeNode which is a no-no). + * + * It's also a more annoying implementation because there's no leaf type (since + * a leaf object would have to be deleted on insert). + * + * Tree::iterator is not realtime safe, but the insert/remove/find methods + * of Tree do not use them. + */ +template +class Tree +{ +public: + Tree() : m_root(0), m_size(0) {} + ~Tree(); + + void insert(TreeNode* const n); + TreeNode* remove(const string& key); + T find(const string& key) const; + TreeNode* find_treenode(const string& key) const; + + size_t size() const { return m_size; } + + /** NON realtime safe iterator for a Tree. */ + class iterator + { + public: + iterator(const Tree* tree, size_t size); + ~iterator(); + + T operator*() const; + iterator& operator++(); + bool operator!=(const iterator& iter) const; + + friend class Tree; + + iterator(const iterator& copy); + iterator& operator=(const iterator& copy); + + private: + int m_depth; + size_t m_size; + TreeNode** m_stack; + const Tree* m_tree; + }; + + iterator begin() const; + iterator end() const; + +private: + // Prevent copies (undefined) + Tree(const Tree&); + Tree& operator=(const Tree&); + + void m_set_all_traversed_recursive(TreeNode* root, bool b); + + TreeNode* m_find_smallest(TreeNode* root); + TreeNode* m_find_largest(TreeNode* root); + + TreeNode* m_root; + size_t m_size; +}; + + +/* This needs to be done so the templates are defined and can get instantiated + * automatically by the compilter. + */ +//#include "TreeImplementation.h" + + +#endif // NODETREE_H diff --git a/src/libs/engine/TreeImplementation.h b/src/libs/engine/TreeImplementation.h new file mode 100644 index 00000000..a61ec407 --- /dev/null +++ b/src/libs/engine/TreeImplementation.h @@ -0,0 +1,410 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Tree.h" +#include +#include +#include +using std::cerr; using std::endl; + + +/* FIXME: this is all in horrible need of a rewrite. */ + + +/** Destroy the tree. + * + * Note that this does not delete any TreeNodes still inside the tree, + * that is the user's responsibility. + */ +template +Tree::~Tree() +{ +} + + +/** Insert a node into the tree. Realtime safe. + * + * @a n will be inserted using the key() field for searches. + * n->key() must not be the empty string. + */ +template +void +Tree::insert(TreeNode* const n) +{ + assert(n != NULL); + assert(n->left_child() == NULL); + assert(n->right_child() == NULL); + assert(n->parent() == NULL); + assert(n->key().length() > 0); + assert(find_treenode(n->key()) == NULL); + + if (m_root == NULL) { + m_root = n; + } else { + bool left = false; // which child to insert at + bool right = false; + TreeNode* i = m_root; + while (true) { + assert(i != NULL); + if (n->key() <= i->key()) { + if (i->left_child() == NULL) { + left = true; + break; + } else { + i = i->left_child(); + } + } else { + if (i->right_child() == NULL) { + right = true; + break; + } else { + i = i->right_child(); + } + } + } + + assert(i != NULL); + assert(left || right); + assert( ! (left && right) ); + + if (left) { + assert(i->left_child() == NULL); + i->left_child(n); + } else if (right) { + assert(i->right_child() == NULL); + i->right_child(n); + } + n->parent(i); + } + ++m_size; +} + + +/** Remove a node from the tree. + * + * Realtime safe, caller is responsible to delete returned value. + * + * @return NULL if object with @a key is not in tree. + */ +template +TreeNode* +Tree::remove(const string& key) +{ + TreeNode* node = find_treenode(key); + TreeNode* n = node; + TreeNode* swap = NULL; + T temp_node; + string temp_key; + + if (node == NULL) + return NULL; + + // Node is not even in tree + if (node->parent() == NULL && m_root != node) + return NULL; + // FIXME: What if the node is in a different tree? Check for this? + +#ifndef NDEBUG + const T& remove_node = node->node(); // for error checking +#endif // NDEBUG + + // n has two children + if (n->left_child() != NULL && n->right_child() != NULL) { + if (rand()%2) + swap = m_find_largest(n->left_child()); + else + swap = m_find_smallest(n->right_child()); + + // Swap node's elements + temp_node = swap->m_node; + swap->m_node = n->m_node; + n->m_node = temp_node; + + // Swap node's keys + temp_key = swap->m_key; + swap->m_key = n->m_key; + n->m_key = temp_key; + + n = swap; + assert(n != NULL); + } + + // be sure we swapped correctly (ie right node is getting removed) + assert(n->node() == remove_node); + + // n now has at most one child + assert(n->left_child() == NULL || n->right_child() == NULL); + + if (n->is_leaf()) { + if (n->is_left_child()) + n->parent()->left_child(NULL); + else if (n->is_right_child()) + n->parent()->right_child(NULL); + + if (m_root == n) m_root = NULL; + } else { // has a single child + TreeNode* child = NULL; + if (n->left_child() != NULL) + child = n->left_child(); + else if (n->right_child() != NULL) + child = n->right_child(); + else + exit(EXIT_FAILURE); + + assert(child != n); + assert(child != NULL); + assert(n->parent() != n); + + if (n->is_left_child()) { + assert(n->parent() != child); + n->parent()->left_child(child); + child->parent(n->parent()); + } else if (n->is_right_child()) { + assert(n->parent() != child); + n->parent()->right_child(child); + child->parent(n->parent()); + } else { + child->parent(NULL); + } + if (m_root == n) m_root = child; + } + + // Be sure node is cut off completely + assert(n != NULL); + assert(n->parent() == NULL || n->parent()->left_child() != n); + assert(n->parent() == NULL || n->parent()->right_child() != n); + assert(n->left_child() == NULL || n->left_child()->parent() != n); + assert(n->right_child() == NULL || n->right_child()->parent() != n); + assert(m_root != n); + + n->parent(NULL); + n->left_child(NULL); + n->right_child(NULL); + + --m_size; + + if (m_size == 0) m_root = NULL; + + // Be sure right node is being removed + assert(n->node() == remove_node); + + return n; +} + + +template +T +Tree::find(const string& name) const +{ + TreeNode* tn = find_treenode(name); + + return (tn == NULL) ? NULL : tn->node(); +} + + +template +TreeNode* +Tree::find_treenode(const string& name) const +{ + TreeNode* i = m_root; + int cmp = 0; + + while (i != NULL) { + cmp = name.compare(i->key()); + if (cmp < 0) + i = i->left_child(); + else if (cmp > 0) + i = i->right_child(); + else + break; + } + + return i; +} + + +/// Private /// +template +void +Tree::m_set_all_traversed_recursive(TreeNode* root, bool b) +{ + assert(root != NULL); + + // Preorder traversal + root->node()->traversed(b); + if (root->left_child() != NULL) + m_set_all_traversed_recursive(root->left_child(), b); + if (root->right_child() != NULL) + m_set_all_traversed_recursive(root->right_child(), b); +} + + +/** Finds the smallest (key) node in the subtree rooted at "root" + */ +template +TreeNode* +Tree::m_find_smallest(TreeNode* root) +{ + TreeNode* r = root; + + while (r->left_child() != NULL) + r = r->left_child(); + + return r; +} + + +/** Finds the largest (key) node in the subtree rooted at "root". + */ +template +TreeNode* +Tree::m_find_largest(TreeNode* root) +{ + TreeNode* r = root; + + while (r->right_child() != NULL) + r = r->right_child(); + + return r; + +} + + + +//// Iterator Stuff //// + + + +template +Tree::iterator::iterator(const Tree *tree, size_t size) +: m_depth(-1), + m_size(size), + m_stack(NULL), + m_tree(tree) +{ + if (size > 0) + m_stack = new TreeNode*[size]; +} + + +template +Tree::iterator::~iterator() +{ + delete[] m_stack; +} + + +/* FIXME: Make these next two not memcpy (possibly have to force a single + * iterator existing at any given time) for speed. + */ + +// Copy constructor (for the typical for loop usage) +template +Tree::iterator::iterator(const Tree::iterator& copy) +: m_depth(copy.m_depth), + m_size(copy.m_size), + m_tree(copy.m_tree) +{ + if (m_size > 0) { + m_stack = new TreeNode*[m_size]; + memcpy(m_stack, copy.m_stack, m_size * sizeof(TreeNode*)); + } +} + + +// Assignment operator +template +typename Tree::iterator& +Tree::iterator::operator=(const Tree::iterator& copy) { + m_depth = copy.m_depth; + m_size = copy.m_size; + m_tree = copy.m_tree; + + if (m_size > 0) { + m_stack = new TreeNode*[m_size]; + memcpy(m_stack, copy.m_stack, m_size * sizeof(TreeNode*)); + } + return *this; +} + + +template +T +Tree::iterator::operator*() const +{ + assert(m_depth >= 0); + return m_stack[m_depth]->node(); +} + + +template +typename Tree::iterator& +Tree::iterator::operator++() +{ + assert(m_depth >= 0); + + TreeNode* tn = m_stack[m_depth]; + --m_depth; + + tn = tn->right_child(); + while (tn != NULL) { + ++m_depth; + m_stack[m_depth] = tn; + tn = tn->left_child(); + } + + return *this; +} + + +template +bool +Tree::iterator::operator!=(const Tree::iterator& iter) const +{ + // (DeMorgan's Law) + return (m_tree != iter.m_tree || m_depth != iter.m_depth); +} + + +template +typename Tree::iterator +Tree::begin() const +{ + typename Tree::iterator iter(this, m_size); + iter.m_depth = -1; + + TreeNode *ptr = m_root; + while (ptr != NULL) { + iter.m_depth++; + iter.m_stack[iter.m_depth] = ptr; + ptr = ptr->left_child(); + } + + return iter; +} + + +template +typename Tree::iterator +Tree::end() const +{ + typename Tree::iterator iter(this, 0); + iter.m_depth = -1; + + return iter; +} + + diff --git a/src/libs/engine/cmdline.c b/src/libs/engine/cmdline.c new file mode 100644 index 00000000..6b7ddf6a --- /dev/null +++ b/src/libs/engine/cmdline.c @@ -0,0 +1,150 @@ +/* + File autogenerated by gengetopt version 2.10 + generated with the following command: + gengetopt + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + + +#include +#include +#include + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#include "cmdline.h" + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); +} + +void +cmdline_parser_print_help (void) +{ + cmdline_parser_print_version (); + printf("\n" + "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); + printf(" -h --help Print help and exit\n"); + printf(" -V --version Print version and exit\n"); + printf(" -pSTRING --port=STRING OSC port to listen on (default='16180')\n"); + printf(" -i --in-jackd Run engine as in-process JACK client (default=off)\n"); +} + + +static char *gengetopt_strdup (const char *s); + +/* gengetopt_strdup() */ +/* strdup.c replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) +{ + int c; /* Character of the parsed option. */ + int missing_required_options = 0; + + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->port_given = 0 ; + args_info->in_jackd_given = 0 ; +#define clear_args() { \ + args_info->port_arg = gengetopt_strdup("16180") ;\ + args_info->in_jackd_flag = 0;\ +} + + clear_args(); + + optarg = 0; + optind = 1; + opterr = 1; + optopt = '?'; + + while (1) + { + int option_index = 0; + char *stop_char; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "port", 1, NULL, 'p' }, + { "in-jackd", 0, NULL, 'i' }, + { NULL, 0, NULL, 0 } + }; + + stop_char = 0; + c = getopt_long (argc, argv, "hVp:i", long_options, &option_index); + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + clear_args (); + cmdline_parser_print_help (); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + clear_args (); + cmdline_parser_print_version (); + exit (EXIT_SUCCESS); + + case 'p': /* OSC port to listen on. */ + if (args_info->port_given) + { + fprintf (stderr, "%s: `--port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->port_given = 1; + args_info->port_arg = gengetopt_strdup (optarg); + break; + + case 'i': /* Run engine as in-process JACK client. */ + if (args_info->in_jackd_given) + { + fprintf (stderr, "%s: `--in-jackd' (`-i') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->in_jackd_given = 1; + args_info->in_jackd_flag = !(args_info->in_jackd_flag); + break; + + + case 0: /* Long option with no short option */ + + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + exit (EXIT_FAILURE); + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); + abort (); + } /* switch */ + } /* while */ + + + if ( missing_required_options ) + exit (EXIT_FAILURE); + + return 0; +} diff --git a/src/libs/engine/cmdline.ggo b/src/libs/engine/cmdline.ggo new file mode 100644 index 00000000..8c006ca7 --- /dev/null +++ b/src/libs/engine/cmdline.ggo @@ -0,0 +1,7 @@ +# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) + +package "Om - An OSC controlled realtime modular synthesizer" + +option "port" p "OSC port to listen on" string default="16180" no +option "in-jackd" i "Run engine as in-process JACK client" flag off + diff --git a/src/libs/engine/cmdline.h b/src/libs/engine/cmdline.h new file mode 100644 index 00000000..fe36a969 --- /dev/null +++ b/src/libs/engine/cmdline.h @@ -0,0 +1,45 @@ +/* cmdline.h */ + +/* File autogenerated by gengetopt version 2.10 */ + +#ifndef CMDLINE_H +#define CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +#define CMDLINE_PARSER_PACKAGE "Om - An OSC controlled realtime modular synthesizer" +#endif + +#ifndef CMDLINE_PARSER_VERSION +#define CMDLINE_PARSER_VERSION VERSION +#endif + +struct gengetopt_args_info +{ + char * port_arg; /* OSC port to listen on (default='16180'). */ + int in_jackd_flag; /* Run engine as in-process JACK client (default=off). */ + + int help_given ; /* Whether help was given. */ + int version_given ; /* Whether version was given. */ + int port_given ; /* Whether port was given. */ + int in_jackd_given ; /* Whether in-jackd was given. */ + +} ; + +int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); + +void cmdline_parser_print_help(void); +void cmdline_parser_print_version(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/src/libs/engine/events.h b/src/libs/engine/events.h new file mode 100644 index 00000000..f1bc5f58 --- /dev/null +++ b/src/libs/engine/events.h @@ -0,0 +1,62 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EVENTS_H +#define EVENTS_H + +#include "config.h" + +#include "ActivateEvent.h" +#include "DeactivateEvent.h" +#include "EnablePatchEvent.h" +#include "DisablePatchEvent.h" +#include "ClearPatchEvent.h" +#include "SetPortValueEvent.h" +#include "SetPortValueQueuedEvent.h" +#include "ConnectionEvent.h" +#include "DisconnectionEvent.h" +#include "AddNodeEvent.h" +#include "CreatePatchEvent.h" +#include "DestroyEvent.h" +#include "SetMetadataEvent.h" +#include "RequestMetadataEvent.h" +#include "RequestPortValueEvent.h" +#include "RequestAllObjectsEvent.h" +#include "RequestPluginsEvent.h" +#include "LoadPluginsEvent.h" +#include "NoteOnEvent.h" +#include "NoteOffEvent.h" +#include "AllNotesOffEvent.h" +#include "DisconnectNodeEvent.h" +#include "RegisterClientEvent.h" +#include "UnregisterClientEvent.h" +#include "RenameEvent.h" +#include "PingQueuedEvent.h" +#include "MidiLearnEvent.h" + +#ifdef HAVE_LASH +#include "LashRestoreDoneEvent.h" +#endif + +#ifdef HAVE_DSSI +#include "DSSIUpdateEvent.h" +#include "DSSIControlEvent.h" +#include "DSSIConfigureEvent.h" +#include "DSSIProgramEvent.h" +#endif + +#endif // EVENTS_H + diff --git a/src/libs/engine/events/ActivateEvent.cpp b/src/libs/engine/events/ActivateEvent.cpp new file mode 100644 index 00000000..671b26d5 --- /dev/null +++ b/src/libs/engine/events/ActivateEvent.cpp @@ -0,0 +1,52 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ActivateEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" + +namespace Om { + + +ActivateEvent::ActivateEvent(CountedPtr responder) +: QueuedEvent(responder) +{ +} + + +void +ActivateEvent::pre_process() +{ + QueuedEvent::pre_process(); + + if (om != NULL) + om->activate(); +} + + +void +ActivateEvent::post_process() +{ + if (om != NULL) + m_responder->respond_ok(); + else + m_responder->respond_error("Not ready to activate yet."); +} + + +} // namespace Om + diff --git a/src/libs/engine/events/ActivateEvent.h b/src/libs/engine/events/ActivateEvent.h new file mode 100644 index 00000000..280b5523 --- /dev/null +++ b/src/libs/engine/events/ActivateEvent.h @@ -0,0 +1,41 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ACTIVATEEVENT_H +#define ACTIVATEEVENT_H + +#include "QueuedEvent.h" + +namespace Om { + + +/** Activates the engine. + * + * \ingroup engine + */ +class ActivateEvent : public QueuedEvent +{ +public: + ActivateEvent(CountedPtr responder); + + void pre_process(); + void post_process(); +}; + + +} // namespace Om + +#endif // ACTIVATEEVENT_H diff --git a/src/libs/engine/events/AddNodeEvent.cpp b/src/libs/engine/events/AddNodeEvent.cpp new file mode 100644 index 00000000..2b31ef4a --- /dev/null +++ b/src/libs/engine/events/AddNodeEvent.cpp @@ -0,0 +1,128 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AddNodeEvent.h" +#include "Responder.h" +#include "Patch.h" +#include "Node.h" +#include "Tree.h" +#include "Plugin.h" +#include "Om.h" +#include "OmApp.h" +#include "Patch.h" +#include "NodeFactory.h" +#include "ClientBroadcaster.h" +#include "Maid.h" +#include "util/Path.h" +#include "ObjectStore.h" +#include "util/Path.h" +#include "Port.h" + +namespace Om { + + +AddNodeEvent::AddNodeEvent(CountedPtr responder, const string& path, Plugin* plugin, bool poly) +: QueuedEvent(responder), + m_path(path), + m_plugin(plugin), + m_poly(poly), + m_patch(NULL), + m_node(NULL), + m_process_order(NULL), + m_node_already_exists(false) +{ +} + + +AddNodeEvent::~AddNodeEvent() +{ + delete m_plugin; +} + + +void +AddNodeEvent::pre_process() +{ + if (om->object_store()->find(m_path) != NULL) { + m_node_already_exists = true; + QueuedEvent::pre_process(); + return; + } + + m_patch = om->object_store()->find_patch(m_path.parent()); + + if (m_patch != NULL) { + if (m_poly) + m_node = om->node_factory()->load_plugin(m_plugin, m_path.name(), m_patch->internal_poly(), m_patch); + else + m_node = om->node_factory()->load_plugin(m_plugin, m_path.name(), 1, m_patch); + + if (m_node != NULL) { + m_node->activate(); + + // This can be done here because the audio thread doesn't touch the + // node tree - just the process order array + m_patch->add_node(new ListNode(m_node)); + m_node->add_to_store(); + + if (m_patch->process()) + m_process_order = m_patch->build_process_order(); + } + } + QueuedEvent::pre_process(); +} + + +void +AddNodeEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); + + if (m_node != NULL) { + m_node->add_to_patch(); + + if (m_patch->process_order() != NULL) + om->maid()->push(m_patch->process_order()); + m_patch->process_order(m_process_order); + } +} + + +void +AddNodeEvent::post_process() +{ + string msg; + if (m_node_already_exists) { + msg = string("Could not create node - ").append(m_path);// + " already exists."; + m_responder->respond_error(msg); + } else if (m_patch == NULL) { + msg = "Could not find patch '" + m_path.parent() +"' for add_node."; + m_responder->respond_error(msg); + } else if (m_node == NULL) { + msg = "Unable to load node "; + msg.append(m_path).append(" (you're missing the plugin \"").append( + m_plugin->lib_name()).append(":").append(m_plugin->plug_label()).append("\")");; + m_responder->respond_error(msg); + } else { + m_responder->respond_ok(); + //om->client_broadcaster()->send_node_creation_messages(m_node); + om->client_broadcaster()->send_node(m_node); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/AddNodeEvent.h b/src/libs/engine/events/AddNodeEvent.h new file mode 100644 index 00000000..fe0236ba --- /dev/null +++ b/src/libs/engine/events/AddNodeEvent.h @@ -0,0 +1,63 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ADDNODEEVENT_H +#define ADDNODEEVENT_H + +#include "QueuedEvent.h" +#include "util/Path.h" +#include +using std::string; + +template class Array; +template class TreeNode; + +namespace Om { + +class Patch; +class Node; +class Plugin; + + +/** An event to load a Node and insert it into a Patch. + * + * \ingroup engine + */ +class AddNodeEvent : public QueuedEvent +{ +public: + AddNodeEvent(CountedPtr responder, const string& path, Plugin* plugin, bool poly); + ~AddNodeEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_patch_name; + Path m_path; + Plugin* m_plugin; + bool m_poly; + Patch* m_patch; + Node* m_node; + Array* m_process_order; // Patch's new process order + bool m_node_already_exists; +}; + + +} // namespace Om + +#endif // ADDNODEEVENT_H diff --git a/src/libs/engine/events/AllNotesOffEvent.cpp b/src/libs/engine/events/AllNotesOffEvent.cpp new file mode 100644 index 00000000..aa3a00f1 --- /dev/null +++ b/src/libs/engine/events/AllNotesOffEvent.cpp @@ -0,0 +1,67 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AllNotesOffEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ObjectStore.h" + +namespace Om { + + +/** Note off with patch explicitly passed - triggered by MIDI. + */ +AllNotesOffEvent::AllNotesOffEvent(CountedPtr responder, Patch* patch) +: Event(responder), + m_patch(patch) +{ +} + + +/** Note off event with lookup - triggered by OSC. + */ +AllNotesOffEvent::AllNotesOffEvent(CountedPtr responder, const string& patch_path) +: Event(responder), + m_patch(NULL), + m_patch_path(patch_path) +{ +} + + +void +AllNotesOffEvent::execute(samplecount offset) +{ + if (m_patch == NULL && m_patch_path != "") + m_patch = om->object_store()->find_patch(m_patch_path); + + //if (m_patch != NULL) + // for (List::iterator j = m_patch->midi_in_nodes().begin(); j != m_patch->midi_in_nodes().end(); ++j) + // (*j)->all_notes_off(offset); +} + + +void +AllNotesOffEvent::post_process() +{ + if (m_patch != NULL) + m_responder->respond_ok(); +} + + +} // namespace Om + + diff --git a/src/libs/engine/events/AllNotesOffEvent.h b/src/libs/engine/events/AllNotesOffEvent.h new file mode 100644 index 00000000..ea23301b --- /dev/null +++ b/src/libs/engine/events/AllNotesOffEvent.h @@ -0,0 +1,50 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ALLNOTESOFFEVENT_H +#define ALLNOTESOFFEVENT_H + +#include "Event.h" +#include +using std::string; + +namespace Om { + +class Patch; + + +/** A note off event for all active voices. + * + * \ingroup engine + */ +class AllNotesOffEvent : public Event +{ +public: + AllNotesOffEvent(CountedPtr responder, Patch* patch); + AllNotesOffEvent(CountedPtr responder, const string& patch_path); + + void execute(samplecount offset); + void post_process(); + +private: + Patch* m_patch; + string m_patch_path; +}; + + +} // namespace Om + +#endif // ALLNOTESOFFEVENT_H diff --git a/src/libs/engine/events/ClearPatchEvent.cpp b/src/libs/engine/events/ClearPatchEvent.cpp new file mode 100644 index 00000000..8b8fc223 --- /dev/null +++ b/src/libs/engine/events/ClearPatchEvent.cpp @@ -0,0 +1,114 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ClearPatchEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "Patch.h" +#include "ClientBroadcaster.h" +#include "util.h" +#include "ObjectStore.h" +#include "Port.h" +#include "Maid.h" +#include "Node.h" +#include "Connection.h" +#include "QueuedEventSource.h" + +namespace Om { + + +ClearPatchEvent::ClearPatchEvent(CountedPtr responder, const string& patch_path) +: QueuedEvent(responder, true), + m_patch_path(patch_path), + m_patch(NULL), + m_process(false) +{ +} + + +void +ClearPatchEvent::pre_process() +{ + m_patch = om->object_store()->find_patch(m_patch_path); + + if (m_patch != NULL) { + + m_process = m_patch->process(); + + for (List::const_iterator i = m_patch->nodes().begin(); i != m_patch->nodes().end(); ++i) + (*i)->remove_from_store(); + } + + QueuedEvent::pre_process(); +} + + +void +ClearPatchEvent::execute(samplecount offset) +{ + if (m_patch != NULL) { + m_patch->process(false); + + for (List::const_iterator i = m_patch->nodes().begin(); i != m_patch->nodes().end(); ++i) + (*i)->remove_from_patch(); + + if (m_patch->process_order() != NULL) { + om->maid()->push(m_patch->process_order()); + m_patch->process_order(NULL); + } + } + + QueuedEvent::execute(offset); +} + + +void +ClearPatchEvent::post_process() +{ + if (m_patch != NULL) { + // Delete all nodes + for (List::iterator i = m_patch->nodes().begin(); i != m_patch->nodes().end(); ++i) { + (*i)->deactivate(); + delete *i; + } + m_patch->nodes().clear(); + + // Delete all connections + for (List::iterator i = m_patch->connections().begin(); i != m_patch->connections().end(); ++i) + delete *i; + m_patch->connections().clear(); + + // Restore patch's run state + m_patch->process(m_process); + + // Make sure everything's sane + assert(m_patch->nodes().size() == 0); + assert(m_patch->connections().size() == 0); + + // Reply + m_responder->respond_ok(); + om->client_broadcaster()->send_patch_cleared(m_patch_path); + } else { + m_responder->respond_error(string("Patch ") + m_patch_path + " not found"); + } + + m_source->unblock(); +} + + +} // namespace Om + diff --git a/src/libs/engine/events/ClearPatchEvent.h b/src/libs/engine/events/ClearPatchEvent.h new file mode 100644 index 00000000..c6e531a8 --- /dev/null +++ b/src/libs/engine/events/ClearPatchEvent.h @@ -0,0 +1,54 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CLEARPATCHEVENT_H +#define CLEARPATCHEVENT_H + +#include +#include "QueuedEvent.h" +#include "Array.h" + +using std::string; + +namespace Om { + +class Patch; + + +/** Delete all nodes from a patch. + * + * \ingroup engine + */ +class ClearPatchEvent : public QueuedEvent +{ +public: + ClearPatchEvent(CountedPtr responder, const string& patch_path); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_patch_path; + Patch* m_patch; + bool m_process; +}; + + +} // namespace Om + + +#endif // CLEARPATCHEVENT_H diff --git a/src/libs/engine/events/ConnectionEvent.cpp b/src/libs/engine/events/ConnectionEvent.cpp new file mode 100644 index 00000000..fe3b991e --- /dev/null +++ b/src/libs/engine/events/ConnectionEvent.cpp @@ -0,0 +1,240 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ConnectionEvent.h" +#include +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ConnectionBase.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Patch.h" +#include "ClientBroadcaster.h" +#include "Port.h" +#include "PortInfo.h" +#include "Maid.h" +#include "ObjectStore.h" +#include "util/Path.h" + +using std::string; +namespace Om { + + +//// ConnectionEvent //// + + +ConnectionEvent::ConnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path) +: QueuedEvent(responder), + m_src_port_path(src_port_path), + m_dst_port_path(dst_port_path), + m_patch(NULL), + m_src_port(NULL), + m_dst_port(NULL), + m_typed_event(NULL), + m_error(NO_ERROR) +{ +} + + +ConnectionEvent::~ConnectionEvent() +{ + delete m_typed_event; +} + + +void +ConnectionEvent::pre_process() +{ + if (m_src_port_path.parent().parent() != m_dst_port_path.parent().parent()) { + m_error = PARENT_PATCH_DIFFERENT; + QueuedEvent::pre_process(); + return; + } + + /*m_patch = om->object_store()->find_patch(m_src_port_path.parent().parent()); + + if (m_patch == NULL) { + m_error = PORT_NOT_FOUND; + QueuedEvent::pre_process(); + return; + }*/ + + Port* port1 = om->object_store()->find_port(m_src_port_path); + Port* port2 = om->object_store()->find_port(m_dst_port_path); + + if (port1 == NULL || port2 == NULL) { + m_error = PORT_NOT_FOUND; + QueuedEvent::pre_process(); + return; + } + + if (port1->port_info()->type() != port2->port_info()->type()) { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + + if (port1->port_info()->is_output() && port2->port_info()->is_input()) { + m_src_port = port1; + m_dst_port = port2; + } else if (port2->port_info()->is_output() && port1->port_info()->is_input()) { + m_src_port = port2; + m_dst_port = port1; + } else { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + + // Create the typed event to actually do the work + const PortType type = port1->port_info()->type(); + if (type == AUDIO || type == CONTROL) { + m_typed_event = new TypedConnectionEvent(m_responder, + (OutputPort*)m_src_port, (InputPort*)m_dst_port); + } else if (type == MIDI) { + m_typed_event = new TypedConnectionEvent(m_responder, + (OutputPort*)m_src_port, (InputPort*)m_dst_port); + } else { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + + m_typed_event->pre_process(); + + QueuedEvent::pre_process(); +} + + +void +ConnectionEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); + + if (m_error == NO_ERROR) + m_typed_event->execute(offset); +} + + +void +ConnectionEvent::post_process() +{ + if (m_error == NO_ERROR) { + m_typed_event->post_process(); + } else { + // FIXME: better error messages + string msg = "Unable to make connection "; + msg.append(m_src_port_path + " -> " + m_dst_port_path); + m_responder->respond_error(msg); + } +} + + + +//// TypedConnectionEvent //// + + +template +TypedConnectionEvent::TypedConnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port) +: QueuedEvent(responder), + m_src_port(src_port), + m_dst_port(dst_port), + m_patch(NULL), + m_process_order(NULL), + m_connection(NULL), + m_port_listnode(NULL), + m_succeeded(true) +{ + assert(src_port != NULL); + assert(dst_port != NULL); +} + +template +TypedConnectionEvent::~TypedConnectionEvent() +{ + // FIXME: haaaack, prevent a double delete + // this class is unusable by anything other than ConnectionEvent because of this + //m_responder = NULL; +} + + +template +void +TypedConnectionEvent::pre_process() +{ + Node* const src_node = m_src_port->parent_node(); + Node* const dst_node = m_dst_port->parent_node(); + + m_patch = src_node->parent_patch(); + + if (src_node == NULL || dst_node == NULL) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + if (src_node->parent() != m_patch || dst_node->parent() != m_patch) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + m_connection = new ConnectionBase(m_src_port, m_dst_port); + m_port_listnode = new ListNode*>(m_connection); + m_patch_listnode = new ListNode(m_connection); + + dst_node->providers()->push_back(new ListNode(src_node)); + src_node->dependants()->push_back(new ListNode(dst_node)); + + if (m_patch->process()) + m_process_order = m_patch->build_process_order(); +} + + +template +void +TypedConnectionEvent::execute(samplecount offset) +{ + if (m_succeeded) { + // These must be inserted here, since they're actually used by the audio thread + m_dst_port->add_connection(m_port_listnode); + m_patch->add_connection(m_patch_listnode); + if (m_patch->process_order() != NULL) + om->maid()->push(m_patch->process_order()); + m_patch->process_order(m_process_order); + } +} + + +template +void +TypedConnectionEvent::post_process() +{ + if (m_succeeded) { + assert(m_connection != NULL); + + m_responder->respond_ok(); + + om->client_broadcaster()->send_connection(m_connection); + } else { + m_responder->respond_error("Unable to make connection."); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/ConnectionEvent.h b/src/libs/engine/events/ConnectionEvent.h new file mode 100644 index 00000000..8aaf2292 --- /dev/null +++ b/src/libs/engine/events/ConnectionEvent.h @@ -0,0 +1,107 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONNECTIONEVENT_H +#define CONNECTIONEVENT_H + +#include +#include "QueuedEvent.h" +#include "util/Path.h" +#include "util/types.h" +using std::string; + +template class ListNode; +template class Array; + +namespace Om { + +class Patch; +class Node; +class Connection; +class MidiMessage; +class Port; +template class ConnectionBase; +template class InputPort; +template class OutputPort; +template class TypedConnectionEvent; // helper, defined below + + +/** Make a Connection between two Ports. + * + * \ingroup engine + */ +class ConnectionEvent : public QueuedEvent +{ +public: + ConnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path); + ~ConnectionEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + + enum ErrorType { NO_ERROR, PARENT_PATCH_DIFFERENT, PORT_NOT_FOUND, TYPE_MISMATCH }; + + Path m_src_port_path; + Path m_dst_port_path; + + Patch* m_patch; + Port* m_src_port; + Port* m_dst_port; + + QueuedEvent* m_typed_event; + + ErrorType m_error; +}; + + +/** Templated ConnectionEvent. + * + * Intended to be called from ConnectionEvent so callers (ie OSCReceiver) + * can use ConnectionEvent without knowing anything about types (which + * they can't, since all they have is Port paths). + */ +template +class TypedConnectionEvent : public QueuedEvent +{ +public: + TypedConnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port); + ~TypedConnectionEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + OutputPort* m_src_port; + InputPort* m_dst_port; + + Patch* m_patch; + Array* m_process_order; ///< New process order for Patch + ConnectionBase* m_connection; + ListNode* m_patch_listnode; + ListNode*>* m_port_listnode; + + bool m_succeeded; +}; + + + +} // namespace Om + +#endif // CONNECTIONEVENT_H diff --git a/src/libs/engine/events/CreatePatchEvent.cpp b/src/libs/engine/events/CreatePatchEvent.cpp new file mode 100644 index 00000000..9f0ae7f2 --- /dev/null +++ b/src/libs/engine/events/CreatePatchEvent.cpp @@ -0,0 +1,150 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "CreatePatchEvent.h" +#include "Responder.h" +#include "Patch.h" +#include "Node.h" +#include "Tree.h" +#include "Plugin.h" +#include "Om.h" +#include "OmApp.h" +#include "Maid.h" +#include "ClientBroadcaster.h" +#include "AudioDriver.h" +#include "util/Path.h" +#include "ObjectStore.h" + +namespace Om { + + +CreatePatchEvent::CreatePatchEvent(CountedPtr responder, const string& path, int poly) +: QueuedEvent(responder), + m_path(path), + m_patch(NULL), + m_parent(NULL), + m_process_order(NULL), + m_poly(poly), + m_error(NO_ERROR) +{ +} + + +void +CreatePatchEvent::pre_process() +{ + if (om->object_store()->find(m_path) != NULL) { + m_error = OBJECT_EXISTS; + QueuedEvent::pre_process(); + return; + } + + if (m_poly < 1) { + m_error = INVALID_POLY; + QueuedEvent::pre_process(); + return; + } + + if (m_path != "/") { + m_parent = om->object_store()->find_patch(m_path.parent()); + if (m_parent == NULL) { + m_error = PARENT_NOT_FOUND; + QueuedEvent::pre_process(); + return; + } + } + + size_t poly = 1; + if (m_parent != NULL && m_poly > 1 && m_poly == static_cast(m_parent->internal_poly())) + poly = m_poly; + + m_patch = new Patch(m_path.name(), poly, m_parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size(), m_poly); + + if (m_parent != NULL) { + m_parent->add_node(new ListNode(m_patch->as_node())); + + if (m_parent->process()) + m_process_order = m_parent->build_process_order(); + } + + m_patch->activate(); + + // Insert into ObjectStore + m_patch->add_to_store(); + + QueuedEvent::pre_process(); +} + + +void +CreatePatchEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); + + if (m_patch != NULL) { + if (m_parent == NULL) { + assert(m_path == "/"); + assert(m_patch->parent_patch() == NULL); + om->audio_driver()->set_root_patch(m_patch); + } else { + assert(m_parent != NULL); + assert(m_path != "/"); + + m_patch->add_to_patch(); + + if (m_parent->process_order() != NULL) + om->maid()->push(m_parent->process_order()); + m_parent->process_order(m_process_order); + } + } +} + + +void +CreatePatchEvent::post_process() +{ + if (m_responder.get()) { + if (m_error == NO_ERROR) { + + m_responder->respond_ok(); + + // Don't want to send nodes that have been added since prepare() + //om->client_broadcaster()->send_node_creation_messages(m_patch); + + // Patches are always empty on creation, so this is fine + om->client_broadcaster()->send_patch(m_patch); + + } else if (m_error == OBJECT_EXISTS) { + string msg = "Unable to create patch: "; + msg += m_path += " already exists."; + m_responder->respond_error(msg); + } else if (m_error == PARENT_NOT_FOUND) { + string msg = "Unable to create patch: Parent "; + msg += m_path.parent() += " not found."; + m_responder->respond_error(msg); + } else if (m_error == INVALID_POLY) { + string msg = "Unable to create patch "; + msg.append(m_path).append(": ").append("Invalid polyphony respondered."); + m_responder->respond_error(msg); + } else { + m_responder->respond_error("Unable to load patch."); + } + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/CreatePatchEvent.h b/src/libs/engine/events/CreatePatchEvent.h new file mode 100644 index 00000000..507d03c7 --- /dev/null +++ b/src/libs/engine/events/CreatePatchEvent.h @@ -0,0 +1,64 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CREATEPATCHEVENT_H +#define CREATEPATCHEVENT_H + +#include "util/Path.h" +#include "QueuedEvent.h" +#include +using std::string; + +template class Array; +template class TreeNode; + +namespace Om { + +class Patch; +class Node; +class Plugin; + + +/** Creates a new Patch. + * + * \ingroup engine + */ +class CreatePatchEvent : public QueuedEvent +{ +public: + CreatePatchEvent(CountedPtr responder, const string& path, int poly); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + enum ErrorType { NO_ERROR, OBJECT_EXISTS, PARENT_NOT_FOUND, INVALID_POLY }; + + Path m_path; + Patch* m_patch; + Patch* m_parent; + Array* m_process_order; + TreeNode* m_patch_treenode; + int m_poly; + ErrorType m_error; +}; + + +} // namespace Om + + +#endif // CREATEPATCHEVENT_H diff --git a/src/libs/engine/events/DSSIConfigureEvent.cpp b/src/libs/engine/events/DSSIConfigureEvent.cpp new file mode 100644 index 00000000..2ade4671 --- /dev/null +++ b/src/libs/engine/events/DSSIConfigureEvent.cpp @@ -0,0 +1,73 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DSSIConfigureEvent.h" +#include "Om.h" +#include "OmApp.h" +#include "Node.h" +#include "ClientBroadcaster.h" +#include "Plugin.h" +#include "ObjectStore.h" + +namespace Om { + + +DSSIConfigureEvent::DSSIConfigureEvent(CountedPtr responder, const string& node_path, const string& key, const string& val) +: QueuedEvent(responder), + m_node_path(node_path), + m_key(key), + m_val(val), + m_node(NULL) +{ +} + + +void +DSSIConfigureEvent::pre_process() +{ + Node* node = om->object_store()->find_node(m_node_path); + + if (node != NULL && node->plugin()->type() == Plugin::DSSI) { + m_node = (DSSIPlugin*)node; + m_node->configure(m_key, m_val); + } + + QueuedEvent::pre_process(); +} + + +void +DSSIConfigureEvent::execute(samplecount offset) +{ + // Nothing. +} + + +void +DSSIConfigureEvent::post_process() +{ + if (m_node == NULL) { + cerr << "Unable to find DSSI node " << m_node_path << endl; + } else { + string key = "dssi-configure--"; + key += m_key; + om->client_broadcaster()->send_metadata_update(m_node_path, key, m_val); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DSSIConfigureEvent.h b/src/libs/engine/events/DSSIConfigureEvent.h new file mode 100644 index 00000000..00b4a134 --- /dev/null +++ b/src/libs/engine/events/DSSIConfigureEvent.h @@ -0,0 +1,49 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DSSICONFIGUREEVENT_H +#define DSSICONFIGUREEVENT_H + +#include "QueuedEvent.h" +#include "DSSIPlugin.h" + +namespace Om { + + +/** Change of a 'configure' key/value pair for a DSSI plugin. + * + * \ingroup engine + */ +class DSSIConfigureEvent : public QueuedEvent +{ +public: + DSSIConfigureEvent(CountedPtr responder, const string& node_path, const string& key, const string& val); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_node_path; + string m_key; + string m_val; + DSSIPlugin* m_node; +}; + + +} // namespace Om + +#endif // DSSICONFIGUREEVENT_H diff --git a/src/libs/engine/events/DSSIControlEvent.cpp b/src/libs/engine/events/DSSIControlEvent.cpp new file mode 100644 index 00000000..ea3e70ac --- /dev/null +++ b/src/libs/engine/events/DSSIControlEvent.cpp @@ -0,0 +1,68 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DSSIControlEvent.h" +#include "Om.h" +#include "OmApp.h" +#include "Node.h" +#include "Plugin.h" +#include "ObjectStore.h" + +namespace Om { + + +DSSIControlEvent::DSSIControlEvent(CountedPtr responder, const string& node_path, int port_num, sample val) +: QueuedEvent(responder), + m_node_path(node_path), + m_port_num(port_num), + m_val(val), + m_node(NULL) +{ +} + + +void +DSSIControlEvent::pre_process() +{ + Node* node = om->object_store()->find_node(m_node_path); + + if (node->plugin()->type() != Plugin::DSSI) + m_node = NULL; + else + m_node = (DSSIPlugin*)node; + + QueuedEvent::pre_process(); +} + + +void +DSSIControlEvent::execute(samplecount offset) +{ + if (m_node != NULL) + m_node->set_control(m_port_num, m_val); +} + + +void +DSSIControlEvent::post_process() +{ + if (m_node == NULL) + std::cerr << "Unable to find DSSI node " << m_node_path << std::endl; +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DSSIControlEvent.h b/src/libs/engine/events/DSSIControlEvent.h new file mode 100644 index 00000000..30a5279e --- /dev/null +++ b/src/libs/engine/events/DSSIControlEvent.h @@ -0,0 +1,51 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DSSICONTROLEVENT_H +#define DSSICONTROLEVENT_H + +#include "QueuedEvent.h" +#include "DSSIPlugin.h" + +namespace Om { + + +/** A control change event for a DSSI plugin. + * + * This does essentially the same thing as a SetPortValueEvent. + * + * \ingroup engine + */ +class DSSIControlEvent : public QueuedEvent +{ +public: + DSSIControlEvent(CountedPtr responder, const string& node_path, int port_num, sample val); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_node_path; + int m_port_num; + float m_val; + DSSIPlugin* m_node; +}; + + +} // namespace Om + +#endif // DSSICONTROLEVENT_H diff --git a/src/libs/engine/events/DSSIProgramEvent.cpp b/src/libs/engine/events/DSSIProgramEvent.cpp new file mode 100644 index 00000000..eb68ef77 --- /dev/null +++ b/src/libs/engine/events/DSSIProgramEvent.cpp @@ -0,0 +1,77 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DSSIProgramEvent.h" +#include +#include +#include "Om.h" +#include "OmApp.h" +#include "Node.h" +#include "ClientBroadcaster.h" +#include "Plugin.h" +#include "ObjectStore.h" +using std::cout; using std::cerr; using std::endl; + + +namespace Om { + + +DSSIProgramEvent::DSSIProgramEvent(CountedPtr responder, const string& node_path, int bank, int program) +: QueuedEvent(responder), + m_node_path(node_path), + m_bank(bank), + m_program(program), + m_node(NULL) +{ +} + + +void +DSSIProgramEvent::pre_process() +{ + Node* node = om->object_store()->find_node(m_node_path); + + if (node != NULL && node->plugin()->type() == Plugin::DSSI) + m_node = (DSSIPlugin*)node; + + QueuedEvent::pre_process(); +} + + +void +DSSIProgramEvent::execute(samplecount offset) +{ + if (m_node != NULL) + m_node->program(m_bank, m_program); +} + + +void +DSSIProgramEvent::post_process() +{ + if (m_node == NULL) { + cerr << "Unable to find DSSI node " << m_node_path << endl; + } else { + // sends program as metadata in the form bank/program + char* temp_buf = new char[16]; + snprintf(temp_buf, 16, "%d/%d", m_bank, m_program); + om->client_broadcaster()->send_metadata_update(m_node_path, "dssi-program", temp_buf); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DSSIProgramEvent.h b/src/libs/engine/events/DSSIProgramEvent.h new file mode 100644 index 00000000..152f3cb1 --- /dev/null +++ b/src/libs/engine/events/DSSIProgramEvent.h @@ -0,0 +1,49 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DSSIPROGRAMEVENT_H +#define DSSIPROGRAMEVENT_H + +#include "QueuedEvent.h" +#include "DSSIPlugin.h" + +namespace Om { + + +/** A program change for a DSSI plugin. + * + * \ingroup engine + */ +class DSSIProgramEvent : public QueuedEvent +{ +public: + DSSIProgramEvent(CountedPtr responder, const string& node_path, int bank, int program); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_node_path; + int m_bank; + int m_program; + DSSIPlugin* m_node; +}; + + +} // namespace Om + +#endif // DSSIPROGRAMEVENT_H diff --git a/src/libs/engine/events/DSSIUpdateEvent.cpp b/src/libs/engine/events/DSSIUpdateEvent.cpp new file mode 100644 index 00000000..5650dd63 --- /dev/null +++ b/src/libs/engine/events/DSSIUpdateEvent.cpp @@ -0,0 +1,80 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DSSIUpdateEvent.h" +#include +#include "Node.h" +#include "ObjectStore.h" +#include "Om.h" +#include "OmApp.h" +#include "DSSIPlugin.h" +#include "Plugin.h" + +using std::cerr; using std::endl; + +namespace Om { + + +DSSIUpdateEvent::DSSIUpdateEvent(CountedPtr responder, const string& path, const string& url) +: QueuedEvent(responder), + m_path(path), + m_url(url), + m_node(NULL) +{ +} + + +void +DSSIUpdateEvent::pre_process() +{ + Node* node = om->object_store()->find_node(m_path); + + if (node == NULL || node->plugin()->type() != Plugin::DSSI) { + m_node = NULL; + QueuedEvent::pre_process(); + return; + } else { + m_node = (DSSIPlugin*)node; + } + + QueuedEvent::pre_process(); +} + + +void +DSSIUpdateEvent::execute(samplecount offset) +{ + if (m_node != NULL) { + m_node->set_ui_url(m_url); + } + + QueuedEvent::execute(offset); +} + + +void +DSSIUpdateEvent::post_process() +{ + cerr << "DSSI update event: " << m_url << endl; + + if (m_node != NULL) { + m_node->send_update(); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DSSIUpdateEvent.h b/src/libs/engine/events/DSSIUpdateEvent.h new file mode 100644 index 00000000..cdd8851e --- /dev/null +++ b/src/libs/engine/events/DSSIUpdateEvent.h @@ -0,0 +1,54 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DSSIUPDATEEVENT_H +#define DSSIUPDATEEVENT_H + +#include "QueuedEvent.h" +#include + +using std::string; + +namespace Om { + +class DSSIPlugin; + + +/** A DSSI "update" responder for a DSSI plugin/node. + * + * This sends all information about the plugin to the UI (over OSC). + * + * \ingroup engine + */ +class DSSIUpdateEvent : public QueuedEvent +{ +public: + DSSIUpdateEvent(CountedPtr responder, const string& path, const string& url); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_path; + string m_url; + DSSIPlugin* m_node; +}; + + +} // namespace Om + +#endif // DSSIUPDATEEVENT_H diff --git a/src/libs/engine/events/DeactivateEvent.cpp b/src/libs/engine/events/DeactivateEvent.cpp new file mode 100644 index 00000000..48bff55a --- /dev/null +++ b/src/libs/engine/events/DeactivateEvent.cpp @@ -0,0 +1,54 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DeactivateEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" + +namespace Om { + + +DeactivateEvent::DeactivateEvent(CountedPtr responder) +: QueuedEvent(responder) +{ +} + + +void +DeactivateEvent::pre_process() +{ + QueuedEvent::pre_process(); +} + + +void +DeactivateEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); +} + + +void +DeactivateEvent::post_process() +{ + m_responder->respond_ok(); + om->deactivate(); +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DeactivateEvent.h b/src/libs/engine/events/DeactivateEvent.h new file mode 100644 index 00000000..8401f332 --- /dev/null +++ b/src/libs/engine/events/DeactivateEvent.h @@ -0,0 +1,42 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DEACTIVATEEVENT_H +#define DEACTIVATEEVENT_H + +#include "QueuedEvent.h" + +namespace Om { + + +/** Deactivates the engine. + * + * \ingroup engine + */ +class DeactivateEvent : public QueuedEvent +{ +public: + DeactivateEvent(CountedPtr responder); + + void pre_process(); + void execute(samplecount offset); + void post_process(); +}; + + +} // namespace Om + +#endif // DEACTIVATEEVENT_H diff --git a/src/libs/engine/events/DestroyEvent.cpp b/src/libs/engine/events/DestroyEvent.cpp new file mode 100644 index 00000000..3988195a --- /dev/null +++ b/src/libs/engine/events/DestroyEvent.cpp @@ -0,0 +1,168 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DestroyEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "Patch.h" +#include "Tree.h" +#include "Node.h" +#include "Plugin.h" +#include "InternalNode.h" +#include "DisconnectNodeEvent.h" +#include "DisconnectPortEvent.h" +#include "ClientBroadcaster.h" +#include "Maid.h" +#include "ObjectStore.h" +#include "util/Path.h" +#include "QueuedEventSource.h" +#include "Port.h" + +namespace Om { + + +DestroyEvent::DestroyEvent(CountedPtr responder, const string& path, bool lock_mutex) +: QueuedEvent(responder, true), + m_path(path), + m_node(NULL), + m_patch_listnode(NULL), + m_store_treenode(NULL), + m_process_order(NULL), + m_disconnect_event(NULL), + m_parent_disconnect_event(NULL) +{ +} + + +DestroyEvent::DestroyEvent(CountedPtr responder, Node* node, bool lock_mutex) +: QueuedEvent(responder, true), + m_path(node->path()), + m_node(node), + m_patch_listnode(NULL), + m_store_treenode(NULL), + m_process_order(NULL), + m_disconnect_event(NULL), + m_parent_disconnect_event(NULL) +{ +} + + +DestroyEvent::~DestroyEvent() +{ + delete m_disconnect_event; + delete m_parent_disconnect_event; +} + + +void +DestroyEvent::pre_process() +{ + if (m_node == NULL) { + OmObject* const obj = om->object_store()->find_node(m_path); + + if (obj != NULL && obj->as_node() != NULL) + m_node = obj->as_node(); + } + + if (m_node != NULL && m_path != "/") { + assert(m_node->parent_patch() != NULL); + m_patch_listnode = m_node->parent_patch()->remove_node(m_path.name()); + if (m_patch_listnode != NULL) { + assert(m_patch_listnode->elem() == m_node); + + m_node->remove_from_store(); + + if (m_node->providers()->size() != 0 || m_node->dependants()->size() != 0) { + m_disconnect_event = new DisconnectNodeEvent(m_node); + m_disconnect_event->pre_process(); + } + + // Create a recursive disconnect event for the parent port, if a bridge node + Port* parent_port = m_patch_listnode->elem()->as_port(); + if (parent_port != NULL) { // Bridge node + m_parent_disconnect_event = new DisconnectPortEvent(parent_port); + m_parent_disconnect_event->pre_process(); + } + + if (m_node->parent_patch()->process()) { + m_process_order = m_node->parent_patch()->build_process_order(); + // Remove node to be removed from the process order so it isn't executed by + // Patch::run and can safely be destroyed + //for (size_t i=0; i < m_process_order->size(); ++i) + // if (m_process_order->at(i) == m_node) + // m_process_order->at(i) = NULL; // ew, gap + +#ifdef DEBUG + // Be sure node is removed from process order, so it can be destroyed + for (size_t i=0; i < m_process_order->size(); ++i) + assert(m_process_order->at(i) != m_node); +#endif + } + } + } + + QueuedEvent::pre_process(); +} + + +void +DestroyEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); + + if (m_patch_listnode != NULL) { + m_node->remove_from_patch(); + + if (m_disconnect_event != NULL) + m_disconnect_event->execute(offset); + if (m_parent_disconnect_event != NULL) + m_parent_disconnect_event->execute(offset); + + if (m_node->parent_patch()->process_order() != NULL) + om->maid()->push(m_node->parent_patch()->process_order()); + m_node->parent_patch()->process_order(m_process_order); + } +} + + +void +DestroyEvent::post_process() +{ + m_source->unblock(); + + if (m_node == NULL) { + if (m_path == "/") + m_responder->respond_error("You can not destroy the root patch (/)"); + else + m_responder->respond_error("Could not find node to destroy"); + } else if (m_patch_listnode != NULL) { + m_node->deactivate(); + m_responder->respond_ok(); + if (m_disconnect_event != NULL) + m_disconnect_event->post_process(); + if (m_parent_disconnect_event != NULL) + m_parent_disconnect_event->post_process(); + om->client_broadcaster()->send_destroyed(m_path); + om->maid()->push(m_patch_listnode); + om->maid()->push(m_node); + } else { + m_responder->respond_error("Unable to destroy object"); + } +} + + +} // namespace Om diff --git a/src/libs/engine/events/DestroyEvent.h b/src/libs/engine/events/DestroyEvent.h new file mode 100644 index 00000000..fc579bf4 --- /dev/null +++ b/src/libs/engine/events/DestroyEvent.h @@ -0,0 +1,68 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DESTROYEVENT_H +#define DESTROYEVENT_H + +#include "util/Path.h" +#include "QueuedEvent.h" +#include + +using std::string; + +template class Array; +template class ListNode; +template class TreeNode; + +namespace Om { + +class OmObject; +class Patch; +class Node; +class Plugin; +class DisconnectNodeEvent; +class DisconnectPortEvent; + + +/** An event to remove and delete a Node. + * + * \ingroup engine + */ +class DestroyEvent : public QueuedEvent +{ +public: + DestroyEvent(CountedPtr responder, const string& path, bool lock_mutex = true); + DestroyEvent(CountedPtr responder, Node* node, bool lock_mutex = true); + ~DestroyEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + Path m_path; + Node* m_node; + ListNode* m_patch_listnode; + TreeNode* m_store_treenode; + Array* m_process_order; // Patch's new process order + DisconnectNodeEvent* m_disconnect_event; + DisconnectPortEvent* m_parent_disconnect_event; // used for input/output nodes +}; + + +} // namespace Om + +#endif // DESTROYEVENT_H diff --git a/src/libs/engine/events/DisablePatchEvent.cpp b/src/libs/engine/events/DisablePatchEvent.cpp new file mode 100644 index 00000000..a772e6e9 --- /dev/null +++ b/src/libs/engine/events/DisablePatchEvent.cpp @@ -0,0 +1,70 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DisablePatchEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "Patch.h" +#include "ClientBroadcaster.h" +#include "util.h" +#include "ObjectStore.h" +#include "Port.h" + +namespace Om { + + +DisablePatchEvent::DisablePatchEvent(CountedPtr responder, const string& patch_path) +: QueuedEvent(responder), + m_patch_path(patch_path), + m_patch(NULL) +{ +} + + +void +DisablePatchEvent::pre_process() +{ + m_patch = om->object_store()->find_patch(m_patch_path); + + QueuedEvent::pre_process(); +} + + +void +DisablePatchEvent::execute(samplecount offset) +{ + if (m_patch != NULL) + m_patch->process(false); + + QueuedEvent::execute(offset); +} + + +void +DisablePatchEvent::post_process() +{ + if (m_patch != NULL) { + m_responder->respond_ok(); + om->client_broadcaster()->send_patch_disable(m_patch_path); + } else { + m_responder->respond_error(string("Patch ") + m_patch_path + " not found"); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DisablePatchEvent.h b/src/libs/engine/events/DisablePatchEvent.h new file mode 100644 index 00000000..f38f14af --- /dev/null +++ b/src/libs/engine/events/DisablePatchEvent.h @@ -0,0 +1,52 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DISABLEPATCHEVENT_H +#define DISABLEPATCHEVENT_H + +#include +#include "QueuedEvent.h" + +using std::string; + +namespace Om { + +class Patch; + + +/** Disables a Patch's DSP processing. + * + * \ingroup engine + */ +class DisablePatchEvent : public QueuedEvent +{ +public: + DisablePatchEvent(CountedPtr responder, const string& patch_path); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_patch_path; + Patch* m_patch; +}; + + +} // namespace Om + + +#endif // DISABLEPATCHEVENT_H diff --git a/src/libs/engine/events/DisconnectNodeEvent.cpp b/src/libs/engine/events/DisconnectNodeEvent.cpp new file mode 100644 index 00000000..17367dd4 --- /dev/null +++ b/src/libs/engine/events/DisconnectNodeEvent.cpp @@ -0,0 +1,140 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DisconnectNodeEvent.h" +#include +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "Maid.h" +#include "List.h" +#include "Node.h" +#include "ConnectionBase.h" +#include "DisconnectionEvent.h" +#include "Port.h" +#include "Array.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Patch.h" +#include "ClientBroadcaster.h" +#include "util.h" +#include "ObjectStore.h" +#include "util/Path.h" + +using std::cerr; using std::endl; + +namespace Om { + + +DisconnectNodeEvent::DisconnectNodeEvent(CountedPtr responder, const string& node_path) +: QueuedEvent(responder), + m_node_path(node_path), + m_patch(NULL), + m_node(NULL), + m_succeeded(true), + m_lookup(true) +{ +} + + +/** Internal version, disconnects parent port as well (in the case of InputNode, etc). + */ +DisconnectNodeEvent::DisconnectNodeEvent(Node* node) +: QueuedEvent(), + m_node_path(""), + m_patch(node->parent_patch()), + m_node(node), + m_succeeded(true), + m_lookup(false) +{ +} + + +DisconnectNodeEvent::~DisconnectNodeEvent() +{ + for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) + delete (*i); +} + + +void +DisconnectNodeEvent::pre_process() +{ + typedef List::const_iterator ConnectionListIterator; + + // cerr << "Preparing disconnection event...\n"; + + if (m_lookup) { + m_patch = om->object_store()->find_patch(m_node_path.parent()); + + if (m_patch == NULL) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + m_node = om->object_store()->find_node(m_node_path); + + if (m_node == NULL) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + } + + Connection* c = NULL; + for (ConnectionListIterator i = m_patch->connections().begin(); i != m_patch->connections().end(); ++i) { + c = (*i); + if ((c->src_port()->parent_node() == m_node || c->dst_port()->parent_node() == m_node) && !c->pending_disconnection()) { + DisconnectionEvent* ev = new DisconnectionEvent(CountedPtr(new Responder()), c->src_port(), c->dst_port()); + ev->pre_process(); + m_disconnection_events.push_back(new ListNode(ev)); + c->pending_disconnection(true); + } + } + + m_succeeded = true; + QueuedEvent::pre_process(); +} + + +void +DisconnectNodeEvent::execute(samplecount offset) +{ + if (m_succeeded) { + for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) + (*i)->execute(offset); + } + + QueuedEvent::execute(offset); +} + + +void +DisconnectNodeEvent::post_process() +{ + if (m_succeeded) { + m_responder->respond_ok(); + for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) + (*i)->post_process(); + } else { + m_responder->respond_error("Unable to disconnect all ports."); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DisconnectNodeEvent.h b/src/libs/engine/events/DisconnectNodeEvent.h new file mode 100644 index 00000000..a82fbaec --- /dev/null +++ b/src/libs/engine/events/DisconnectNodeEvent.h @@ -0,0 +1,68 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DISCONNECTNODEEVENT_H +#define DISCONNECTNODEEVENT_H + +#include +#include "util/Path.h" +#include "QueuedEvent.h" +#include "List.h" +using std::string; + +namespace Om { + +class DisconnectionEvent; +class Patch; +class Node; +class Connection; +template class ConnectionBase; +class Port; +template class InputPort; +template class OutputPort; + + +/** An event to disconnect all connections to a Node. + * + * \ingroup engine + */ +class DisconnectNodeEvent : public QueuedEvent +{ +public: + DisconnectNodeEvent(CountedPtr responder, const string& node_path); + DisconnectNodeEvent(Node* node); + ~DisconnectNodeEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + Path m_node_path; + Patch* m_patch; + Node* m_node; + List m_disconnection_events; + + bool m_succeeded; + bool m_lookup; + bool m_disconnect_parent; +}; + + +} // namespace Om + + +#endif // DISCONNECTNODEEVENT_H diff --git a/src/libs/engine/events/DisconnectPortEvent.cpp b/src/libs/engine/events/DisconnectPortEvent.cpp new file mode 100644 index 00000000..a4c213d5 --- /dev/null +++ b/src/libs/engine/events/DisconnectPortEvent.cpp @@ -0,0 +1,145 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DisconnectPortEvent.h" +#include +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "Maid.h" +#include "List.h" +#include "Node.h" +#include "Connection.h" +#include "DisconnectionEvent.h" +#include "Port.h" +#include "Array.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Patch.h" +#include "ClientBroadcaster.h" +#include "util.h" +#include "ObjectStore.h" +#include "util/Path.h" + +using std::cerr; using std::endl; + +namespace Om { + + +DisconnectPortEvent::DisconnectPortEvent(CountedPtr responder, const string& port_path) +: QueuedEvent(responder), + m_port_path(port_path), + m_patch(NULL), + m_port(NULL), + m_process_order(NULL), + m_succeeded(true), + m_lookup(true) +{ +} + + +DisconnectPortEvent::DisconnectPortEvent(Port* port) +: QueuedEvent(), + m_port_path(""), + m_patch((port->parent_node() == NULL) ? NULL : port->parent_node()->parent_patch()), + m_port(port), + m_process_order(NULL), + m_succeeded(true), + m_lookup(false) +{ + //cerr << "DisconnectPortEvent()\n"; +} + + +DisconnectPortEvent::~DisconnectPortEvent() +{ + for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) + delete (*i); +} + + +void +DisconnectPortEvent::pre_process() +{ + // cerr << "Preparing disconnection event...\n"; + + if (m_lookup) { + m_patch = om->object_store()->find_patch(m_port_path.parent().parent()); + + if (m_patch == NULL) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + m_port = om->object_store()->find_port(m_port_path); + + if (m_port == NULL) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + } + + if (m_patch == NULL) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + Connection* c = NULL; + for (List::const_iterator i = m_patch->connections().begin(); i != m_patch->connections().end(); ++i) { + c = (*i); + if ((c->src_port() == m_port || c->dst_port() == m_port) && !c->pending_disconnection()) { + DisconnectionEvent* ev = new DisconnectionEvent(CountedPtr(new Responder()), c->src_port(), c->dst_port()); + ev->pre_process(); + m_disconnection_events.push_back(new ListNode(ev)); + c->pending_disconnection(true); + } + } + + m_succeeded = true; + QueuedEvent::pre_process(); +} + + +void +DisconnectPortEvent::execute(samplecount offset) +{ + if (m_succeeded) { + for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) + (*i)->execute(offset); + } + + QueuedEvent::execute(offset); +} + + +void +DisconnectPortEvent::post_process() +{ + if (m_succeeded) { + m_responder->respond_ok(); + for (List::iterator i = m_disconnection_events.begin(); i != m_disconnection_events.end(); ++i) + (*i)->post_process(); + } else { + m_responder->respond_error("Unable to disconnect port."); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DisconnectPortEvent.h b/src/libs/engine/events/DisconnectPortEvent.h new file mode 100644 index 00000000..e8de4120 --- /dev/null +++ b/src/libs/engine/events/DisconnectPortEvent.h @@ -0,0 +1,70 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DISCONNECTPORTEVENT_H +#define DISCONNECTPORTEVENT_H + +#include +#include "util/Path.h" +#include "QueuedEvent.h" +#include "List.h" + +template class Array; + +namespace Om { + + +class Patch; +class Node; +class Connection; +class Port; +class DisconnectionEvent; + +using std::string; + + +/** An event to disconnect all connections to a Port. + * + * \ingroup engine + */ +class DisconnectPortEvent : public QueuedEvent +{ +public: + DisconnectPortEvent(CountedPtr responder, const string& port_path); + DisconnectPortEvent(Port* port); + ~DisconnectPortEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + Path m_port_path; + Patch* m_patch; + Port* m_port; + List m_disconnection_events; + + Array* m_process_order; // Patch's new process order + + bool m_succeeded; + bool m_lookup; +}; + + +} // namespace Om + + +#endif // DISCONNECTPORTEVENT_H diff --git a/src/libs/engine/events/DisconnectionEvent.cpp b/src/libs/engine/events/DisconnectionEvent.cpp new file mode 100644 index 00000000..e7d06eab --- /dev/null +++ b/src/libs/engine/events/DisconnectionEvent.cpp @@ -0,0 +1,295 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DisconnectionEvent.h" +#include +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ConnectionBase.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Patch.h" +#include "ClientBroadcaster.h" +#include "Port.h" +#include "PortInfo.h" +#include "Maid.h" +#include "ObjectStore.h" +#include "util/Path.h" + +using std::string; +namespace Om { + + +//// DisconnectionEvent //// + + +DisconnectionEvent::DisconnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path) +: QueuedEvent(responder), + m_src_port_path(src_port_path), + m_dst_port_path(dst_port_path), + m_patch(NULL), + m_src_port(NULL), + m_dst_port(NULL), + m_lookup(true), + m_typed_event(NULL), + m_error(NO_ERROR) +{ +} + + +DisconnectionEvent::DisconnectionEvent(CountedPtr responder, Port* const src_port, Port* const dst_port) +: QueuedEvent(responder), + m_src_port_path(src_port->path()), + m_dst_port_path(dst_port->path()), + m_patch(src_port->parent_node()->parent_patch()), + m_src_port(src_port), + m_dst_port(dst_port), + m_lookup(false), + m_typed_event(NULL), + m_error(NO_ERROR) +{ + assert(src_port->port_info()->is_output()); + assert(dst_port->port_info()->is_input()); + assert(src_port->port_info()->type() == dst_port->port_info()->type()); + assert(src_port->parent_node()->parent_patch() + == dst_port->parent_node()->parent_patch()); +} + +DisconnectionEvent::~DisconnectionEvent() +{ + delete m_typed_event; +} + + +void +DisconnectionEvent::pre_process() +{ + if (m_lookup) { + if (m_src_port_path.parent().parent() != m_dst_port_path.parent().parent()) { + m_error = PARENT_PATCH_DIFFERENT; + QueuedEvent::pre_process(); + return; + } + + /*m_patch = om->object_store()->find_patch(m_src_port_path.parent().parent()); + + if (m_patch == NULL) { + m_error = PORT_NOT_FOUND; + QueuedEvent::pre_process(); + return; + }*/ + + Port* port1 = om->object_store()->find_port(m_src_port_path); + Port* port2 = om->object_store()->find_port(m_dst_port_path); + + if (port1 == NULL || port2 == NULL) { + m_error = PORT_NOT_FOUND; + QueuedEvent::pre_process(); + return; + } + + if (port1->port_info()->type() != port2->port_info()->type()) { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + + if (port1->port_info()->is_output() && port2->port_info()->is_input()) { + m_src_port = port1; + m_dst_port = port2; + } else if (port2->port_info()->is_output() && port1->port_info()->is_input()) { + m_src_port = port2; + m_dst_port = port1; + } else { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + } + + // Create the typed event to actually do the work + const PortType type = m_src_port->port_info()->type(); + if (type == AUDIO || type == CONTROL) { + m_typed_event = new TypedDisconnectionEvent(m_responder, + (OutputPort*)m_src_port, (InputPort*)m_dst_port); + } else if (type == MIDI) { + m_typed_event = new TypedDisconnectionEvent(m_responder, + (OutputPort*)m_src_port, (InputPort*)m_dst_port); + } else { + m_error = TYPE_MISMATCH; + QueuedEvent::pre_process(); + return; + } + + m_typed_event->pre_process(); + + QueuedEvent::pre_process(); +} + + +void +DisconnectionEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); + + if (m_error == NO_ERROR) + m_typed_event->execute(offset); +} + + +void +DisconnectionEvent::post_process() +{ + if (m_error == NO_ERROR) { + m_typed_event->post_process(); + } else { + // FIXME: better error messages + string msg = "Unable to make connection "; + msg.append(m_src_port_path + " -> " + m_dst_port_path); + m_responder->respond_error(msg); + } +} + + + +//// TypedDisconnectionEvent //// + + +template +TypedDisconnectionEvent::TypedDisconnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port) +: QueuedEvent(responder), + m_src_port(src_port), + m_dst_port(dst_port), + m_patch(NULL), + m_process_order(NULL), + m_succeeded(true) +{ + assert(src_port != NULL); + assert(dst_port != NULL); +} + +template +TypedDisconnectionEvent::~TypedDisconnectionEvent() +{ + // FIXME: haaaack, prevent a double delete + // this class is unusable by anything other than DisconnectionEvent because of this + //m_responder = NULL; +} + + +template +void +TypedDisconnectionEvent::pre_process() +{ + if (!m_dst_port->is_connected_to(m_src_port)) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + Node* const src_node = m_src_port->parent_node(); + Node* const dst_node = m_dst_port->parent_node(); + + m_patch = src_node->parent_patch(); + + if (src_node == NULL || dst_node == NULL) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + if (src_node->parent() != m_patch || dst_node->parent() != m_patch) { + m_succeeded = false; + QueuedEvent::pre_process(); + return; + } + + bool removed = false; + + for (List::iterator i = dst_node->providers()->begin(); i != dst_node->providers()->end(); ++i) + if ((*i) == src_node) { + delete dst_node->providers()->remove(i); + removed = true; + break; + } + assert(removed); + removed = false; + + for (List::iterator i = src_node->dependants()->begin(); i != src_node->dependants()->end(); ++i) + if ((*i) == dst_node) { + delete src_node->dependants()->remove(i); + removed = true; + break; + } + assert(removed); + + if (m_patch->process()) + m_process_order = m_patch->build_process_order(); + + m_succeeded = true; + QueuedEvent::pre_process(); +} + + +template +void +TypedDisconnectionEvent::execute(samplecount offset) +{ + if (m_succeeded) { + + ListNode*>* const port_connection + = m_dst_port->remove_connection(m_src_port); + + if (port_connection != NULL) { + ListNode* const patch_connection + = m_patch->remove_connection(m_src_port, m_dst_port); + + assert((Connection*)port_connection->elem() == patch_connection->elem()); + + // Clean up both the list node and the connection itself... + om->maid()->push(port_connection); + om->maid()->push(patch_connection); + om->maid()->push(port_connection->elem()); + + if (m_patch->process_order() != NULL) + om->maid()->push(m_patch->process_order()); + m_patch->process_order(m_process_order); + } else { + m_succeeded = false; // Ports weren't connected + } + } + QueuedEvent::execute(offset); +} + + +template +void +TypedDisconnectionEvent::post_process() +{ + if (m_succeeded) { + + m_responder->respond_ok(); + + om->client_broadcaster()->send_disconnection(m_src_port->path(), m_dst_port->path()); + } else { + m_responder->respond_error("Unable to disconnect ports."); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/DisconnectionEvent.h b/src/libs/engine/events/DisconnectionEvent.h new file mode 100644 index 00000000..bbb70f3c --- /dev/null +++ b/src/libs/engine/events/DisconnectionEvent.h @@ -0,0 +1,106 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DISCONNECTIONEVENT_H +#define DISCONNECTIONEVENT_H + +#include +#include "util/Path.h" +#include "QueuedEvent.h" +#include "util/types.h" +using std::string; + +template class ListNode; +template class Array; + +namespace Om { + +class Patch; +class Node; +class Connection; +class MidiMessage; +class Port; +template class ConnectionBase; +template class InputPort; +template class OutputPort; +template class TypedDisconnectionEvent; // helper, defined below + + +/** Make a Connection between two Ports. + * + * \ingroup engine + */ +class DisconnectionEvent : public QueuedEvent +{ +public: + DisconnectionEvent(CountedPtr responder, const string& src_port_path, const string& dst_port_path); + DisconnectionEvent(CountedPtr responder, Port* const src_port, Port* const dst_port); + ~DisconnectionEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + + enum ErrorType { NO_ERROR, PARENT_PATCH_DIFFERENT, PORT_NOT_FOUND, TYPE_MISMATCH }; + + Path m_src_port_path; + Path m_dst_port_path; + + Patch* m_patch; + Port* m_src_port; + Port* m_dst_port; + + bool m_lookup; + QueuedEvent* m_typed_event; + + ErrorType m_error; +}; + + +/** Templated DisconnectionEvent. + * + * Intended to be called from DisconnectionEvent so callers (ie OSCReceiver) + * can use DisconnectionEvent without knowing anything about types (which + * they can't, since all they have is Port paths). + */ +template +class TypedDisconnectionEvent : public QueuedEvent +{ +public: + TypedDisconnectionEvent(CountedPtr responder, OutputPort* src_port, InputPort* dst_port); + ~TypedDisconnectionEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + OutputPort* m_src_port; + InputPort* m_dst_port; + + Patch* m_patch; + Array* m_process_order; ///< New process order for Patch + + bool m_succeeded; +}; + + + +} // namespace Om + +#endif // DISCONNECTIONEVENT_H diff --git a/src/libs/engine/events/EnablePatchEvent.cpp b/src/libs/engine/events/EnablePatchEvent.cpp new file mode 100644 index 00000000..6af3b844 --- /dev/null +++ b/src/libs/engine/events/EnablePatchEvent.cpp @@ -0,0 +1,82 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "EnablePatchEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "Patch.h" +#include "util.h" +#include "ClientBroadcaster.h" +#include "ObjectStore.h" + +namespace Om { + + +EnablePatchEvent::EnablePatchEvent(CountedPtr responder, const string& patch_path) +: QueuedEvent(responder), + m_patch_path(patch_path), + m_patch(NULL), + m_process_order(NULL) +{ +} + + +void +EnablePatchEvent::pre_process() +{ + m_patch = om->object_store()->find_patch(m_patch_path); + + if (m_patch != NULL) { + /* Any event that requires a new process order will set the patch's + * process order to NULL if it is executed when the patch is not + * active. So, if the PO is NULL, calculate it here */ + if (m_patch->process_order() == NULL) + m_process_order = m_patch->build_process_order(); + } + + QueuedEvent::pre_process(); +} + + +void +EnablePatchEvent::execute(samplecount offset) +{ + if (m_patch != NULL) { + m_patch->process(true); + + if (m_patch->process_order() == NULL) + m_patch->process_order(m_process_order); + } + + QueuedEvent::execute(offset); +} + + +void +EnablePatchEvent::post_process() +{ + if (m_patch != NULL) { + m_responder->respond_ok(); + om->client_broadcaster()->send_patch_enable(m_patch_path); + } else { + m_responder->respond_error(string("Patch ") + m_patch_path + " not found"); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/EnablePatchEvent.h b/src/libs/engine/events/EnablePatchEvent.h new file mode 100644 index 00000000..f3d22e69 --- /dev/null +++ b/src/libs/engine/events/EnablePatchEvent.h @@ -0,0 +1,56 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ENABLEPATCHEVENT_H +#define ENABLEPATCHEVENT_H + +#include +#include "QueuedEvent.h" + +using std::string; + +template class Array; + +namespace Om { + +class Patch; +class Node; + + +/** Enables a patch's DSP processing. + * + * \ingroup engine + */ +class EnablePatchEvent : public QueuedEvent +{ +public: + EnablePatchEvent(CountedPtr responder, const string& patch_path); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_patch_path; + Patch* m_patch; + Array* m_process_order; // Patch's new process order +}; + + +} // namespace Om + + +#endif // ENABLEPATCHEVENT_H diff --git a/src/libs/engine/events/LashRestoreDoneEvent.h b/src/libs/engine/events/LashRestoreDoneEvent.h new file mode 100644 index 00000000..dfc5b120 --- /dev/null +++ b/src/libs/engine/events/LashRestoreDoneEvent.h @@ -0,0 +1,54 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LASHRESTOREDONEEVENT_H +#define LASHRESTOREDONEEVENT_H + +#include "QueuedEvent.h" +#include "LashDriver.h" +#include "util/types.h" + +#include +using std::cerr; + +namespace Om { + +class Port; + + +/** Notification from a client that the LASH session is finished restoring. + * + * This is a bit of a hack, but needed to defer notifying LASH of our + * existance until all ports are created. + * + * \ingroup engine + */ +class LashRestoreDoneEvent : public QueuedEvent +{ +public: + LashRestoreDoneEvent(CountedPtr responder) : QueuedEvent(responder) {} + + void post_process() + { + m_responder->respond_ok(); + lash_driver->restore_finished(); + } +}; + + +} // namespace Om + +#endif // LASHRESTOREDONEEVENT_H diff --git a/src/libs/engine/events/LoadPluginsEvent.cpp b/src/libs/engine/events/LoadPluginsEvent.cpp new file mode 100644 index 00000000..656e9010 --- /dev/null +++ b/src/libs/engine/events/LoadPluginsEvent.cpp @@ -0,0 +1,44 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "LoadPluginsEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "NodeFactory.h" + +namespace Om { + + +LoadPluginsEvent::LoadPluginsEvent(CountedPtr responder) +: QueuedEvent(responder) +{ +} + + +void +LoadPluginsEvent::post_process() +{ + // Why is this done here and not in pre_process()??? + om->node_factory()->load_plugins(); + m_responder->respond_ok(); + + //cerr << "Load plugins post finished\n"; +} + + +} // namespace Om + diff --git a/src/libs/engine/events/LoadPluginsEvent.h b/src/libs/engine/events/LoadPluginsEvent.h new file mode 100644 index 00000000..b69dbb38 --- /dev/null +++ b/src/libs/engine/events/LoadPluginsEvent.h @@ -0,0 +1,40 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LOADPLUGINSEVENT_H +#define LOADPLUGINSEVENT_H + +#include "QueuedEvent.h" + +namespace Om { + + +/** Loads all plugins into the internal plugin database (in NodeFactory). + * + * \ingroup engine + */ +class LoadPluginsEvent : public QueuedEvent +{ +public: + LoadPluginsEvent(CountedPtr responder); + + void post_process(); +}; + + +} // namespace Om + +#endif // LOADPLUGINSEVENT_H diff --git a/src/libs/engine/events/Makefile.am b/src/libs/engine/events/Makefile.am new file mode 100644 index 00000000..5b29e12b --- /dev/null +++ b/src/libs/engine/events/Makefile.am @@ -0,0 +1,67 @@ +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = \ + events/RegisterClientEvent.h \ + events/RegisterClientEvent.cpp \ + events/UnregisterClientEvent.h \ + events/UnregisterClientEvent.cpp \ + events/PingQueuedEvent.h \ + events/ActivateEvent.h \ + events/ActivateEvent.cpp \ + events/DeactivateEvent.h \ + events/DeactivateEvent.cpp \ + events/SetPortValueEvent.h \ + events/SetPortValueEvent.cpp \ + events/SetPortValueQueuedEvent.h \ + events/SetPortValueQueuedEvent.cpp \ + events/NoteOnEvent.h \ + events/NoteOnEvent.cpp \ + events/NoteOffEvent.h \ + events/NoteOffEvent.cpp \ + events/AllNotesOffEvent.h \ + events/AllNotesOffEvent.cpp \ + events/ConnectionEvent.h \ + events/ConnectionEvent.cpp \ + events/DisconnectionEvent.h \ + events/DisconnectionEvent.cpp \ + events/DisconnectNodeEvent.h \ + events/DisconnectNodeEvent.cpp \ + events/DisconnectPortEvent.h \ + events/DisconnectPortEvent.cpp \ + events/DestroyEvent.h \ + events/DestroyEvent.cpp \ + events/AddNodeEvent.h \ + events/AddNodeEvent.cpp \ + events/SetMetadataEvent.h \ + events/SetMetadataEvent.cpp \ + events/RequestMetadataEvent.h \ + events/RequestMetadataEvent.cpp \ + events/RequestPortValueEvent.h \ + events/RequestPortValueEvent.cpp \ + events/RequestAllObjectsEvent.h \ + events/RequestAllObjectsEvent.cpp \ + events/RequestPluginsEvent.h \ + events/RequestPluginsEvent.cpp \ + events/CreatePatchEvent.h \ + events/CreatePatchEvent.cpp \ + events/LoadPluginsEvent.h \ + events/LoadPluginsEvent.cpp \ + events/EnablePatchEvent.h \ + events/EnablePatchEvent.cpp \ + events/DisablePatchEvent.h \ + events/DisablePatchEvent.cpp \ + events/ClearPatchEvent.h \ + events/ClearPatchEvent.cpp \ + events/RenameEvent.h \ + events/RenameEvent.cpp \ + events/MidiLearnEvent.h \ + events/MidiLearnEvent.cpp \ + DSSIConfigureEvent.cpp \ + DSSIConfigureEvent.h \ + DSSIControlEvent.cpp \ + DSSIControlEvent.h \ + DSSIProgramEvent.cpp \ + DSSIProgramEvent.h \ + DSSIUpdateEvent.cpp \ + DSSIUpdateEvent.h + diff --git a/src/libs/engine/events/MidiLearnEvent.cpp b/src/libs/engine/events/MidiLearnEvent.cpp new file mode 100644 index 00000000..63ad82fc --- /dev/null +++ b/src/libs/engine/events/MidiLearnEvent.cpp @@ -0,0 +1,88 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MidiLearnEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ObjectStore.h" +#include "Node.h" +#include "MidiControlNode.h" +#include "ClientBroadcaster.h" + +namespace Om { + + +// MidiLearnResponseEvent + +void +MidiLearnResponseEvent::post_process() +{ + om->client_broadcaster()->send_control_change(m_port_path, m_value); +} + + + +// MidiLearnEvent + +MidiLearnEvent::MidiLearnEvent(CountedPtr responder, const string& node_path) +: QueuedEvent(responder), + m_node_path(node_path), + m_node(NULL), + m_response_event(NULL) +{ +} + + +void +MidiLearnEvent::pre_process() +{ + m_node = om->object_store()->find_node(m_node_path); + m_response_event = new MidiLearnResponseEvent(m_node_path + "/Controller Number"); + + QueuedEvent::pre_process(); +} + + +void +MidiLearnEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); + + // FIXME: this isn't very good at all. + if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal + && m_node->plugin()->plug_label() == "midi_control_in") { + ((MidiControlNode*)m_node)->learn(m_response_event); + } +} + + +void +MidiLearnEvent::post_process() +{ + if (m_node != NULL) { + m_responder->respond_ok(); + } else { + string msg = "Did not find node '"; + msg.append(m_node_path).append("' for MIDI learn."); + m_responder->respond_error(msg); + } +} + + +} // namespace Om + + diff --git a/src/libs/engine/events/MidiLearnEvent.h b/src/libs/engine/events/MidiLearnEvent.h new file mode 100644 index 00000000..793e675a --- /dev/null +++ b/src/libs/engine/events/MidiLearnEvent.h @@ -0,0 +1,84 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MIDILEARNEVENT_H +#define MIDILEARNEVENT_H + +#include "QueuedEvent.h" +#include "MidiControlNode.h" +#include "util/types.h" +#include +using std::string; + +namespace Om { + +class Node; +class ControlChangeEvent; + + +/** Response event for a MIDI learn. + * + * This is a trivial event that sends a control change in it's post_process + * method (used by MidiLearnEvent to notify clients when the learn happens) + */ +class MidiLearnResponseEvent : public Event +{ +public: + MidiLearnResponseEvent(const string& port_path) + : Event(CountedPtr(NULL)), + m_port_path(port_path), + m_value(0.0f) + {} + + void set_value(sample val) { m_value = val; } + void post_process(); + +private: + string m_port_path; + sample m_value; +}; + + + +/** A MIDI learn event. + * + * This creates a MidiLearnResponseEvent and passes it to the learning node, which + * will push it to the post-processor once the learn happens in order to reply + * to the client with the new port (learned controller) value. + * + * \ingroup engine + */ +class MidiLearnEvent : public QueuedEvent +{ +public: + MidiLearnEvent(CountedPtr responder, const string& node_path); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_node_path; + Node* m_node; + + /// Event to respond with when learned + MidiLearnResponseEvent* m_response_event; +}; + + +} // namespace Om + +#endif // MIDILEARNEVENT_H diff --git a/src/libs/engine/events/NoteOffEvent.cpp b/src/libs/engine/events/NoteOffEvent.cpp new file mode 100644 index 00000000..fde2e520 --- /dev/null +++ b/src/libs/engine/events/NoteOffEvent.cpp @@ -0,0 +1,78 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NoteOffEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ObjectStore.h" +#include "Node.h" +#include "MidiNoteNode.h" +#include "MidiTriggerNode.h" + +namespace Om { + + +/** Note off with patch explicitly passed - triggered by MIDI. + */ +NoteOffEvent::NoteOffEvent(CountedPtr responder, Node* node, uchar note_num) +: Event(responder), + m_node(node), + m_note_num(note_num) +{ +} + + +/** Note off event with lookup - triggered by OSC. + */ +NoteOffEvent::NoteOffEvent(CountedPtr responder, const string& node_path, uchar note_num) +: Event(responder), + m_node(NULL), + m_node_path(node_path), + m_note_num(note_num) +{ +} + + +void +NoteOffEvent::execute(samplecount offset) +{ + if (m_node == NULL && m_node_path != "") + m_node = om->object_store()->find_node(m_node_path); + + // FIXME: this isn't very good at all. + if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal) { + if (m_node->plugin()->plug_label() == "note_in") + ((MidiNoteNode*)m_node)->note_off(m_note_num, offset); + else if (m_node->plugin()->plug_label() == "trigger_in") + ((MidiTriggerNode*)m_node)->note_off(m_note_num, offset); + } +} + + +void +NoteOffEvent::post_process() +{ + if (m_node != NULL) + m_responder->respond_ok(); + else + m_responder->respond_error("Did not find node for note_off"); +} + + +} // namespace Om + + diff --git a/src/libs/engine/events/NoteOffEvent.h b/src/libs/engine/events/NoteOffEvent.h new file mode 100644 index 00000000..edd0b373 --- /dev/null +++ b/src/libs/engine/events/NoteOffEvent.h @@ -0,0 +1,52 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NOTEOFFEVENT_H +#define NOTEOFFEVENT_H + +#include "Event.h" +#include "util/types.h" +#include +using std::string; + +namespace Om { + +class Node; + + +/** A note off event. + * + * \ingroup engine + */ +class NoteOffEvent : public Event +{ +public: + NoteOffEvent(CountedPtr responder, Node* node, uchar note_num); + NoteOffEvent(CountedPtr responder, const string& node_path, uchar note_num); + + void execute(samplecount offset); + void post_process(); + +private: + Node* m_node; + string m_node_path; + uchar m_note_num; +}; + + +} // namespace Om + +#endif // NOTEOFFEVENT_H diff --git a/src/libs/engine/events/NoteOnEvent.cpp b/src/libs/engine/events/NoteOnEvent.cpp new file mode 100644 index 00000000..9688af79 --- /dev/null +++ b/src/libs/engine/events/NoteOnEvent.cpp @@ -0,0 +1,89 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NoteOnEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ObjectStore.h" +#include "Node.h" +#include "MidiNoteNode.h" +#include "MidiTriggerNode.h" +#include "Plugin.h" + +namespace Om { + + +/** Note on with Patch explicitly passed. + * + * Used to be triggered by MIDI. Not used anymore. + */ +NoteOnEvent::NoteOnEvent(CountedPtr responder, Node* patch, uchar note_num, uchar velocity) +: Event(responder), + m_node(patch), + m_note_num(note_num), + m_velocity(velocity), + m_is_osc_triggered(false) +{ +} + + +/** Note on with Node lookup. + * + * Triggered by OSC. + */ +NoteOnEvent::NoteOnEvent(CountedPtr responder, const string& node_path, uchar note_num, uchar velocity) +: Event(responder), + m_node(NULL), + m_node_path(node_path), + m_note_num(note_num), + m_velocity(velocity), + m_is_osc_triggered(true) +{ +} + + +void +NoteOnEvent::execute(samplecount offset) +{ + // Lookup if neccessary + if (m_is_osc_triggered) + m_node = om->object_store()->find_node(m_node_path); + + // FIXME: this isn't very good at all. + if (m_node != NULL && m_node->plugin()->type() == Plugin::Internal) { + if (m_node->plugin()->plug_label() == "note_in") + ((MidiNoteNode*)m_node)->note_on(m_note_num, m_velocity, offset); + else if (m_node->plugin()->plug_label() == "trigger_in") + ((MidiTriggerNode*)m_node)->note_on(m_note_num, m_velocity, offset); + } +} + + +void +NoteOnEvent::post_process() +{ + if (m_is_osc_triggered) { + if (m_node != NULL) + m_responder->respond_ok(); + else + m_responder->respond_error("Did not find node for note_on"); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/NoteOnEvent.h b/src/libs/engine/events/NoteOnEvent.h new file mode 100644 index 00000000..1e09e450 --- /dev/null +++ b/src/libs/engine/events/NoteOnEvent.h @@ -0,0 +1,54 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NOTEONEVENT_H +#define NOTEONEVENT_H + +#include "Event.h" +#include "util/types.h" +#include +using std::string; + +namespace Om { + +class Node; + + +/** A note on event. + * + * \ingroup engine + */ +class NoteOnEvent : public Event +{ +public: + NoteOnEvent(CountedPtr responder, Node* patch, uchar note_num, uchar velocity); + NoteOnEvent(CountedPtr responder, const string& node_path, uchar note_num, uchar velocity); + + void execute(samplecount offset); + void post_process(); + +private: + Node* m_node; + string m_node_path; + uchar m_note_num; + uchar m_velocity; + bool m_is_osc_triggered; +}; + + +} // namespace Om + +#endif // NOTEONEVENT_H diff --git a/src/libs/engine/events/PingQueuedEvent.h b/src/libs/engine/events/PingQueuedEvent.h new file mode 100644 index 00000000..cfba7058 --- /dev/null +++ b/src/libs/engine/events/PingQueuedEvent.h @@ -0,0 +1,44 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PINGQUEUEDEVENT_H +#define PINGQUEUEDEVENT_H + +#include "QueuedEvent.h" +#include "util/types.h" +#include "Responder.h" + +namespace Om { + +class Port; + + +/** A "blocking" ping that travels through the event queue before responding. + * + * \ingroup engine + */ +class PingQueuedEvent : public QueuedEvent +{ +public: + PingQueuedEvent(CountedPtr responder) : QueuedEvent(responder) {} + + void post_process() { m_responder->respond_ok(); } +}; + + +} // namespace Om + +#endif // PINGQUEUEDEVENT_H diff --git a/src/libs/engine/events/RegisterClientEvent.cpp b/src/libs/engine/events/RegisterClientEvent.cpp new file mode 100644 index 00000000..ca7dd1f6 --- /dev/null +++ b/src/libs/engine/events/RegisterClientEvent.cpp @@ -0,0 +1,53 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "RegisterClientEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ClientBroadcaster.h" + +namespace Om { + + +RegisterClientEvent::RegisterClientEvent(CountedPtr responder, + ClientKey key, + CountedPtr client) +: QueuedEvent(responder) +, _key(key) +, _client(client) +{ +} + + +void +RegisterClientEvent::pre_process() +{ + om->client_broadcaster()->register_client(_key, _client); + + QueuedEvent::pre_process(); +} + + +void +RegisterClientEvent::post_process() +{ + m_responder->respond_ok(); +} + + +} // namespace Om + diff --git a/src/libs/engine/events/RegisterClientEvent.h b/src/libs/engine/events/RegisterClientEvent.h new file mode 100644 index 00000000..f4b6b60f --- /dev/null +++ b/src/libs/engine/events/RegisterClientEvent.h @@ -0,0 +1,53 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef REGISTERCLIENTEVENT_H +#define REGISTERCLIENTEVENT_H + +#include "QueuedEvent.h" +#include "interface/ClientKey.h" +#include "interface/ClientInterface.h" +#include +using std::string; +using Om::Shared::ClientInterface; +using Om::Shared::ClientKey; + +namespace Om { + + +/** Registers a new client with the OSC system, so it can receive updates. + * + * \ingroup engine + */ +class RegisterClientEvent : public QueuedEvent +{ +public: + RegisterClientEvent(CountedPtr responder, + ClientKey key, + CountedPtr client); + + void pre_process(); + void post_process(); + +private: + ClientKey _key; + CountedPtr _client; +}; + + +} // namespace Om + +#endif // REGISTERCLIENTEVENT_H diff --git a/src/libs/engine/events/RenameEvent.cpp b/src/libs/engine/events/RenameEvent.cpp new file mode 100644 index 00000000..e2e98dd0 --- /dev/null +++ b/src/libs/engine/events/RenameEvent.cpp @@ -0,0 +1,123 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "RenameEvent.h" +#include "Responder.h" +#include "Patch.h" +#include "Node.h" +#include "Tree.h" +#include "Om.h" +#include "OmApp.h" +#include "ClientBroadcaster.h" +#include "util/Path.h" +#include "ObjectStore.h" + +namespace Om { + + +RenameEvent::RenameEvent(CountedPtr responder, const string& path, const string& name) +: QueuedEvent(responder), + m_old_path(path), + m_name(name), + m_new_path(m_old_path.parent().base_path() + name), + m_parent_patch(NULL), + m_store_treenode(NULL), + m_error(NO_ERROR) +{ + /* + if (m_old_path.parent() == "/") + m_new_path = string("/") + m_name; + else + m_new_path = m_old_path.parent() +"/"+ m_name;*/ +} + + +RenameEvent::~RenameEvent() +{ +} + + +void +RenameEvent::pre_process() +{ + if (m_name.find("/") != string::npos) { + m_error = INVALID_NAME; + QueuedEvent::pre_process(); + return; + } + + if (om->object_store()->find(m_new_path)) { + m_error = OBJECT_EXISTS; + QueuedEvent::pre_process(); + return; + } + + OmObject* obj = om->object_store()->find(m_old_path); + + if (obj == NULL) { + m_error = OBJECT_NOT_FOUND; + QueuedEvent::pre_process(); + return; + } + + // Renaming only works for Nodes and Patches (which are Nodes) + if (obj->as_node() == NULL) { + m_error = OBJECT_NOT_RENAMABLE; + QueuedEvent::pre_process(); + return; + } + + if (obj != NULL) { + obj->set_path(m_new_path); + assert(obj->path() == m_new_path); + } + + QueuedEvent::pre_process(); +} + + +void +RenameEvent::execute(samplecount offset) +{ + //cout << "Executing rename event..."; + QueuedEvent::execute(offset); +} + + +void +RenameEvent::post_process() +{ + string msg = "Unable to rename object - "; + + if (m_error == NO_ERROR) { + m_responder->respond_ok(); + om->client_broadcaster()->send_rename(m_old_path, m_new_path); + } else { + if (m_error == OBJECT_EXISTS) + msg.append("Object already exists at ").append(m_new_path); + else if (m_error == OBJECT_NOT_FOUND) + msg.append("Could not find object ").append(m_old_path); + else if (m_error == OBJECT_NOT_RENAMABLE) + msg.append(m_old_path).append(" is not renamable"); + else if (m_error == INVALID_NAME) + msg.append(m_name).append(" is not a valid name"); + + m_responder->respond_error(msg); + } +} + + +} // namespace Om diff --git a/src/libs/engine/events/RenameEvent.h b/src/libs/engine/events/RenameEvent.h new file mode 100644 index 00000000..c1c9fe91 --- /dev/null +++ b/src/libs/engine/events/RenameEvent.h @@ -0,0 +1,66 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef RENAMEEVENT_H +#define RENAMEEVENT_H + +#include "QueuedEvent.h" +#include "util/Path.h" +#include +using std::string; + +template class TreeNode; +template class ListNode; + +namespace Om { + +class OmObject; +class Patch; +class Node; +class Plugin; +class DisconnectNodeEvent; +class DisconnectPortEvent; + + +/** An event to change the name of an OmObject. + * + * \ingroup engine + */ +class RenameEvent : public QueuedEvent +{ +public: + RenameEvent(CountedPtr responder, const string& path, const string& name); + ~RenameEvent(); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + enum ErrorType { NO_ERROR, OBJECT_NOT_FOUND, OBJECT_EXISTS, OBJECT_NOT_RENAMABLE, INVALID_NAME }; + + Path m_old_path; + string m_name; + Path m_new_path; + Patch* m_parent_patch; + TreeNode* m_store_treenode; + ErrorType m_error; +}; + + +} // namespace Om + +#endif // RENAMEEVENT_H diff --git a/src/libs/engine/events/RequestAllObjectsEvent.cpp b/src/libs/engine/events/RequestAllObjectsEvent.cpp new file mode 100644 index 00000000..ef40a0de --- /dev/null +++ b/src/libs/engine/events/RequestAllObjectsEvent.cpp @@ -0,0 +1,55 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "RequestAllObjectsEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ObjectSender.h" + +namespace Om { + + +RequestAllObjectsEvent::RequestAllObjectsEvent(CountedPtr responder) +: QueuedEvent(responder), + m_client(CountedPtr(NULL)) +{ +} + + +void +RequestAllObjectsEvent::pre_process() +{ + m_client = m_responder->find_client(); + + QueuedEvent::pre_process(); +} + + +void +RequestAllObjectsEvent::post_process() +{ + if (m_client) { + m_responder->respond_ok(); + ObjectSender::send_all(m_client.get()); + } else { + m_responder->respond_error("Invalid URL"); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/RequestAllObjectsEvent.h b/src/libs/engine/events/RequestAllObjectsEvent.h new file mode 100644 index 00000000..df63a577 --- /dev/null +++ b/src/libs/engine/events/RequestAllObjectsEvent.h @@ -0,0 +1,50 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef REQUESTALLOBJECTSEVENT_H +#define REQUESTALLOBJECTSEVENT_H + +#include +#include "QueuedEvent.h" +using std::string; + +namespace Om { + +namespace Shared { + class ClientInterface; +} using Shared::ClientInterface; + + +/** A request from a client to send notification of all objects (ie refresh). + * + * \ingroup engine + */ +class RequestAllObjectsEvent : public QueuedEvent +{ +public: + RequestAllObjectsEvent(CountedPtr responder); + + void pre_process(); + void post_process(); + +private: + CountedPtr m_client; +}; + + +} // namespace Om + +#endif // REQUESTALLOBJECTSEVENT_H diff --git a/src/libs/engine/events/RequestMetadataEvent.cpp b/src/libs/engine/events/RequestMetadataEvent.cpp new file mode 100644 index 00000000..10e1007c --- /dev/null +++ b/src/libs/engine/events/RequestMetadataEvent.cpp @@ -0,0 +1,80 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "RequestMetadataEvent.h" +#include +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "OmObject.h" +#include "ObjectStore.h" +#include "interface/ClientInterface.h" +#include "ClientBroadcaster.h" +using std::string; + +namespace Om { + + +RequestMetadataEvent::RequestMetadataEvent(CountedPtr responder, const string& node_path, const string& key) +: QueuedEvent(responder), + m_path(node_path), + m_key(key), + m_value(""), + m_object(NULL), + m_client(CountedPtr(NULL)) +{ +} + + +void +RequestMetadataEvent::pre_process() +{ + m_client = m_responder->find_client(); + + if (m_client) { + m_object = om->object_store()->find(m_path); + if (m_object == NULL) { + QueuedEvent::pre_process(); + return; + } + } + + m_value = m_object->get_metadata(m_key); + + QueuedEvent::pre_process(); +} + + +void +RequestMetadataEvent::post_process() +{ + if (m_client) { + if (m_value == "") { + string msg = "Unable to find object "; + msg += m_path; + m_responder->respond_error(msg); + } else { + m_responder->respond_ok(); + m_client->metadata_update(m_path, m_key, m_value); + } + } else { + m_responder->respond_error("Unknown client"); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/RequestMetadataEvent.h b/src/libs/engine/events/RequestMetadataEvent.h new file mode 100644 index 00000000..e4243eb3 --- /dev/null +++ b/src/libs/engine/events/RequestMetadataEvent.h @@ -0,0 +1,56 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef REQUESTMETADATAEVENT_H +#define REQUESTMETADATAEVENT_H + +#include +#include "QueuedEvent.h" + +using std::string; + +namespace Om { + +class OmObject; +namespace Shared { + class ClientInterface; +} using Shared::ClientInterface; + + +/** A request from a client for a piece of metadata. + * + * \ingroup engine + */ +class RequestMetadataEvent : public QueuedEvent +{ +public: + RequestMetadataEvent(CountedPtr responder, const string& path, const string& key); + + void pre_process(); + void post_process(); + +private: + string m_path; + string m_key; + string m_value; + OmObject* m_object; + CountedPtr m_client; +}; + + +} // namespace Om + +#endif // REQUESTMETADATAEVENT_H diff --git a/src/libs/engine/events/RequestPluginsEvent.cpp b/src/libs/engine/events/RequestPluginsEvent.cpp new file mode 100644 index 00000000..89dbefd5 --- /dev/null +++ b/src/libs/engine/events/RequestPluginsEvent.cpp @@ -0,0 +1,55 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "RequestPluginsEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ClientBroadcaster.h" + +namespace Om { + + +RequestPluginsEvent::RequestPluginsEvent(CountedPtr responder) +: QueuedEvent(responder), + m_client(CountedPtr(NULL)) +{ +} + + +void +RequestPluginsEvent::pre_process() +{ + m_client = m_responder->find_client(); + + QueuedEvent::pre_process(); +} + + +void +RequestPluginsEvent::post_process() +{ + if (m_client) { + om->client_broadcaster()->send_plugins_to(m_client.get()); + m_responder->respond_ok(); + } else { + m_responder->respond_error("Invalid URL"); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/RequestPluginsEvent.h b/src/libs/engine/events/RequestPluginsEvent.h new file mode 100644 index 00000000..83447fb3 --- /dev/null +++ b/src/libs/engine/events/RequestPluginsEvent.h @@ -0,0 +1,51 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef REQUESTPLUGINSEVENT_H +#define REQUESTPLUGINSEVENT_H + +#include +#include "QueuedEvent.h" +using std::string; + +namespace Om { + +class Responder; +namespace Shared { + class ClientInterface; +} using Shared::ClientInterface; + + +/** A request from a client to send notification of all objects (ie refresh). + * + * \ingroup engine + */ +class RequestPluginsEvent : public QueuedEvent +{ +public: + RequestPluginsEvent(CountedPtr responder); + + void pre_process(); + void post_process(); + +private: + CountedPtr m_client; +}; + + +} // namespace Om + +#endif // REQUESTPLUGINSEVENT_H diff --git a/src/libs/engine/events/RequestPortValueEvent.cpp b/src/libs/engine/events/RequestPortValueEvent.cpp new file mode 100644 index 00000000..e4d3985e --- /dev/null +++ b/src/libs/engine/events/RequestPortValueEvent.cpp @@ -0,0 +1,81 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "RequestPortValueEvent.h" +#include +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "interface/ClientInterface.h" +#include "PortBase.h" +#include "PortInfo.h" +#include "ObjectStore.h" +#include "ClientBroadcaster.h" + +using std::string; + +namespace Om { + + +RequestPortValueEvent::RequestPortValueEvent(CountedPtr responder, const string& port_path) +: QueuedEvent(responder), + m_port_path(port_path), + m_port(NULL), + m_value(0.0), + m_client(CountedPtr(NULL)) +{ +} + + +void +RequestPortValueEvent::pre_process() +{ + m_client = m_responder->find_client(); + m_port = om->object_store()->find_port(m_port_path); + + QueuedEvent::pre_process(); +} + + +void +RequestPortValueEvent::execute(samplecount offset) +{ + if (m_port != NULL && m_port->port_info()->is_audio() || m_port->port_info()->is_control()) + m_value = ((PortBase*)m_port)->buffer(0)->value_at(offset); + else + m_port = NULL; // triggers error response + + QueuedEvent::execute(offset); +} + + +void +RequestPortValueEvent::post_process() +{ + string msg; + if (m_port) { + m_responder->respond_error("Unable to find port for get_value responder."); + } else if (m_client) { + m_responder->respond_ok(); + m_client->control_change(m_port_path, m_value); + } else { + m_responder->respond_error("Invalid URL"); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/RequestPortValueEvent.h b/src/libs/engine/events/RequestPortValueEvent.h new file mode 100644 index 00000000..d970ee9c --- /dev/null +++ b/src/libs/engine/events/RequestPortValueEvent.h @@ -0,0 +1,56 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef REQUESTPORTVALUEEVENT_H +#define REQUESTPORTVALUEEVENT_H + +#include +#include "QueuedEvent.h" +#include "util/types.h" + +using std::string; + +namespace Om { + +class Port; +namespace Shared { class ClientInterface; } +using Shared::ClientInterface; + + +/** A request from a client to send the value of a port. + * + * \ingroup engine + */ +class RequestPortValueEvent : public QueuedEvent +{ +public: + RequestPortValueEvent(CountedPtr responder, const string& port_path); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_port_path; + Port* m_port; + sample m_value; + CountedPtr m_client; +}; + + +} // namespace Om + +#endif // REQUESTPORTVALUEEVENT_H diff --git a/src/libs/engine/events/SetMetadataEvent.cpp b/src/libs/engine/events/SetMetadataEvent.cpp new file mode 100644 index 00000000..614f7ca9 --- /dev/null +++ b/src/libs/engine/events/SetMetadataEvent.cpp @@ -0,0 +1,79 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SetMetadataEvent.h" +#include +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ClientBroadcaster.h" +#include "OmObject.h" +#include "ObjectStore.h" + +using std::string; + +namespace Om { + + +SetMetadataEvent::SetMetadataEvent(CountedPtr responder, const string& path, const string& key, const string& value) +: QueuedEvent(responder), + m_path(path), + m_key(key), + m_value(value), + m_object(NULL) +{ +} + + +void +SetMetadataEvent::pre_process() +{ + m_object = om->object_store()->find(m_path); + if (m_object == NULL) { + QueuedEvent::pre_process(); + return; + } + + m_object->set_metadata(m_key, m_value); + + QueuedEvent::pre_process(); +} + + +void +SetMetadataEvent::execute(samplecount offset) +{ + // Do nothing + + QueuedEvent::execute(offset); +} + + +void +SetMetadataEvent::post_process() +{ + if (m_object == NULL) { + string msg = "Unable to find object "; + msg += m_path; + m_responder->respond_error(msg); + } else { + m_responder->respond_ok(); + om->client_broadcaster()->send_metadata_update(m_path, m_key, m_value); + } +} + + +} // namespace Om diff --git a/src/libs/engine/events/SetMetadataEvent.h b/src/libs/engine/events/SetMetadataEvent.h new file mode 100644 index 00000000..ef471033 --- /dev/null +++ b/src/libs/engine/events/SetMetadataEvent.h @@ -0,0 +1,53 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SETMETADATAEVENT_H +#define SETMETADATAEVENT_H + +#include +#include "QueuedEvent.h" + +using std::string; + +namespace Om { + +class OmObject; + + +/** An event to set a piece of metadata for an OmObject. + * + * \ingroup engine + */ +class SetMetadataEvent : public QueuedEvent +{ +public: + SetMetadataEvent(CountedPtr responder, const string& path, const string& key, const string& value); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + string m_path; + string m_key; + string m_value; + OmObject* m_object; +}; + + +} // namespace Om + +#endif // SETMETADATAEVENT_H diff --git a/src/libs/engine/events/SetPortValueEvent.cpp b/src/libs/engine/events/SetPortValueEvent.cpp new file mode 100644 index 00000000..964cd9ca --- /dev/null +++ b/src/libs/engine/events/SetPortValueEvent.cpp @@ -0,0 +1,104 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SetPortValueEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "PortBase.h" +#include "PortInfo.h" +#include "ClientBroadcaster.h" +#include "Node.h" +#include "ObjectStore.h" + +namespace Om { + + +/** Voice-specific control setting + */ +SetPortValueEvent::SetPortValueEvent(CountedPtr responder, size_t voice_num, const string& port_path, sample val) +: Event(responder), + m_voice_num(voice_num), + m_port_path(port_path), + m_val(val), + m_port(NULL), + m_error(NO_ERROR) +{ +} + + +SetPortValueEvent::SetPortValueEvent(CountedPtr responder, const string& port_path, sample val) +: Event(responder), + m_voice_num(-1), + m_port_path(port_path), + m_val(val), + m_port(NULL), + m_error(NO_ERROR) +{ +} + + +void +SetPortValueEvent::execute(samplecount offset) +{ + if (m_port == NULL) + m_port = om->object_store()->find_port(m_port_path); + + if (m_port == NULL) { + m_error = PORT_NOT_FOUND; + } else if (!m_port->port_info()->is_audio() && !m_port->port_info()->is_control()) { + m_error = TYPE_MISMATCH; + } else { + if (m_voice_num == -1) + ((PortBase*)m_port)->set_value(m_val, offset); + else + ((PortBase*)m_port)->set_value(m_voice_num, m_val, offset); + //((PortBase*)m_port)->buffer(m_voice_num)->set(m_val, offset); // FIXME: check range + } +} + + +void +SetPortValueEvent::post_process() +{ + if (m_error == NO_ERROR) { + assert(m_port != NULL); + + m_responder->respond_ok(); + om->client_broadcaster()->send_control_change(m_port_path, m_val); + + // Send patch port control change, if this is a bridge port + Port* parent_port = m_port->parent_node()->as_port(); + if (parent_port != NULL) { + assert(parent_port->port_info()->is_control() || parent_port->port_info()->is_audio()); + om->client_broadcaster()->send_control_change(parent_port->path(), m_val); + } + + } else if (m_error == PORT_NOT_FOUND) { + string msg = "Unable to find port "; + msg.append(m_port_path).append(" for set_port_value"); + m_responder->respond_error(msg); + + } else if (m_error == TYPE_MISMATCH) { + string msg = "Attempt to set "; + msg.append(m_port_path).append(" to incompatible type"); + m_responder->respond_error(msg); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/SetPortValueEvent.h b/src/libs/engine/events/SetPortValueEvent.h new file mode 100644 index 00000000..0a9614b9 --- /dev/null +++ b/src/libs/engine/events/SetPortValueEvent.h @@ -0,0 +1,56 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SETPORTVALUEEVENT_H +#define SETPORTVALUEEVENT_H + +#include +#include "Event.h" +#include "util/types.h" +using std::string; + +namespace Om { + +class Port; + + +/** An event to change the value of a port. + * + * \ingroup engine + */ +class SetPortValueEvent : public Event +{ +public: + SetPortValueEvent(CountedPtr responder, const string& port_path, sample val); + SetPortValueEvent(CountedPtr responder, size_t voice_num, const string& port_path, sample val); + + void execute(samplecount offset); + void post_process(); + +private: + enum ErrorType { NO_ERROR, PORT_NOT_FOUND, TYPE_MISMATCH }; + + int m_voice_num; + string m_port_path; + float m_val; + Port* m_port; + ErrorType m_error; +}; + + +} // namespace Om + +#endif // SETPORTVALUEEVENT_H diff --git a/src/libs/engine/events/SetPortValueQueuedEvent.cpp b/src/libs/engine/events/SetPortValueQueuedEvent.cpp new file mode 100644 index 00000000..e73c0486 --- /dev/null +++ b/src/libs/engine/events/SetPortValueQueuedEvent.cpp @@ -0,0 +1,116 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SetPortValueQueuedEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "PortBase.h" +#include "PortInfo.h" +#include "ClientBroadcaster.h" +#include "Plugin.h" +#include "Node.h" +#include "ObjectStore.h" + +namespace Om { + + +/** Voice-specific control setting + */ +SetPortValueQueuedEvent::SetPortValueQueuedEvent(CountedPtr responder, size_t voice_num, const string& port_path, sample val) +: QueuedEvent(responder), + m_voice_num(voice_num), + m_port_path(port_path), + m_val(val), + m_port(NULL), + m_error(NO_ERROR) +{ +} + + +SetPortValueQueuedEvent::SetPortValueQueuedEvent(CountedPtr responder, const string& port_path, sample val) +: QueuedEvent(responder), + m_voice_num(-1), + m_port_path(port_path), + m_val(val), + m_port(NULL), + m_error(NO_ERROR) +{ +} + + +void +SetPortValueQueuedEvent::pre_process() +{ + if (m_port == NULL) + m_port = om->object_store()->find_port(m_port_path); + + if (m_port == NULL) { + m_error = PORT_NOT_FOUND; + } else if (!m_port->port_info()->is_audio() && !m_port->port_info()->is_control()) { + m_error = TYPE_MISMATCH; + } + + QueuedEvent::pre_process(); +} + + +void +SetPortValueQueuedEvent::execute(samplecount offset) +{ + QueuedEvent::execute(offset); + + if (m_error == NO_ERROR) { + assert(m_port != NULL); + if (m_voice_num == -1) + ((PortBase*)m_port)->set_value(m_val, offset); + else + ((PortBase*)m_port)->buffer(m_voice_num)->set(m_val, offset); // FIXME: check range + } +} + + +void +SetPortValueQueuedEvent::post_process() +{ + if (m_error == NO_ERROR) { + assert(m_port != NULL); + + m_responder->respond_ok(); + om->client_broadcaster()->send_control_change(m_port_path, m_val); + + // Send patch port control change, if this is a bridge port + Port* parent_port = m_port->parent_node()->as_port(); + if (parent_port != NULL) { + assert(parent_port->port_info()->is_control() || parent_port->port_info()->is_audio()); + om->client_broadcaster()->send_control_change(parent_port->path(), m_val); + } + + } else if (m_error == PORT_NOT_FOUND) { + string msg = "Unable to find port "; + msg.append(m_port_path).append(" for set_port_value_slow"); + m_responder->respond_error(msg); + + } else if (m_error == TYPE_MISMATCH) { + string msg = "Attempt to set "; + msg.append(m_port_path).append(" to incompatible type"); + m_responder->respond_error(msg); + } +} + + +} // namespace Om + diff --git a/src/libs/engine/events/SetPortValueQueuedEvent.h b/src/libs/engine/events/SetPortValueQueuedEvent.h new file mode 100644 index 00000000..b92beacf --- /dev/null +++ b/src/libs/engine/events/SetPortValueQueuedEvent.h @@ -0,0 +1,57 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SETPORTVALUEQUEUEDEVENT_H +#define SETPORTVALUEQUEUEDEVENT_H + +#include "QueuedEvent.h" +#include "util/types.h" +#include +using std::string; + +namespace Om { + +class Port; + + +/** An event to change the value of a port. + * + * \ingroup engine + */ +class SetPortValueQueuedEvent : public QueuedEvent +{ +public: + SetPortValueQueuedEvent(CountedPtr responder, const string& port_path, sample val); + SetPortValueQueuedEvent(CountedPtr responder, size_t voice_num, const string& port_path, sample val); + + void pre_process(); + void execute(samplecount offset); + void post_process(); + +private: + enum ErrorType { NO_ERROR, PORT_NOT_FOUND, TYPE_MISMATCH }; + + int m_voice_num; + string m_port_path; + float m_val; + Port* m_port; + ErrorType m_error; +}; + + +} // namespace Om + +#endif // SETPORTVALUEQUEUEDEVENT_H diff --git a/src/libs/engine/events/UnregisterClientEvent.cpp b/src/libs/engine/events/UnregisterClientEvent.cpp new file mode 100644 index 00000000..ef5a9979 --- /dev/null +++ b/src/libs/engine/events/UnregisterClientEvent.cpp @@ -0,0 +1,45 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "UnregisterClientEvent.h" +#include "Responder.h" +#include "Om.h" +#include "OmApp.h" +#include "ClientBroadcaster.h" +#include "interface/ClientInterface.h" + +namespace Om { + + +UnregisterClientEvent::UnregisterClientEvent(CountedPtr responder, ClientKey key) +: QueuedEvent(responder) +, _key(key) +{ +} + + +void +UnregisterClientEvent::post_process() +{ + if (om->client_broadcaster()->unregister_client(_key)) + m_responder->respond_ok(); + else + m_responder->respond_error("Unable to unregister client"); +} + + +} // namespace Om + diff --git a/src/libs/engine/events/UnregisterClientEvent.h b/src/libs/engine/events/UnregisterClientEvent.h new file mode 100644 index 00000000..fdbdb314 --- /dev/null +++ b/src/libs/engine/events/UnregisterClientEvent.h @@ -0,0 +1,53 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UNREGISTERCLIENTEVENT_H +#define UNREGISTERCLIENTEVENT_H + +#include "QueuedEvent.h" +#include "interface/ClientKey.h" +#include +using std::string; + +namespace Om { + +namespace Shared { + class ClientInterface; + class ClientKey; +} +using Shared::ClientInterface; +using Shared::ClientKey; + + +/** Unregisters an OSC client so it no longer receives notifications. + * + * \ingroup engine + */ +class UnregisterClientEvent : public QueuedEvent +{ +public: + UnregisterClientEvent(CountedPtr responder, ClientKey key); + + void post_process(); + +private: + ClientKey _key; +}; + + +} // namespace Om + +#endif // UNREGISTERCLIENTEVENT_H diff --git a/src/libs/engine/instantiations.cpp b/src/libs/engine/instantiations.cpp new file mode 100644 index 00000000..e2b0088d --- /dev/null +++ b/src/libs/engine/instantiations.cpp @@ -0,0 +1,49 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * Explicit template instantiations. + * + * Need to do this to avoid undefined references, because GCC doesn't seem to + * know how to recursively instantiate templates. Cleaner to do it all here + * than pollute everything with it. :/ + */ + +#include "Tree.h" +#include "TreeImplementation.h" +#include "OmObject.h" +#include "Node.h" + + +/* Tree */ +template class Tree; +template class TreeNode; + +template Tree::Tree(); +template Tree::~Tree(); +template void Tree::insert(TreeNode* const n); +template TreeNode* Tree::remove(const string& key); +template Om::OmObject* Tree::find(const string& key) const; +template TreeNode* Tree::find_treenode(const string& key) const; + +template Tree::iterator Tree::begin() const; +template Tree::iterator Tree::end() const; + +template Tree::iterator::~iterator(); +template Om::OmObject* Tree::iterator::operator*() const; +template Tree::iterator& Tree::iterator::operator++(); +template bool Tree::iterator::operator!=(const iterator& iter) const; + diff --git a/src/libs/engine/main.cpp b/src/libs/engine/main.cpp new file mode 100644 index 00000000..a69c7e76 --- /dev/null +++ b/src/libs/engine/main.cpp @@ -0,0 +1,153 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "config.h" +#include "util.h" +#include "cmdline.h" +#include "Om.h" +#include "OmApp.h" +#ifdef HAVE_LASH +#include "LashDriver.h" +#endif +#ifdef BUILD_IN_PROCESS_ENGINE +#include +#include +#endif + +using std::cout; using std::endl; using std::cerr; + + +void +catch_int(int) +{ + signal(SIGINT, catch_int); + signal(SIGTERM, catch_int); + + std::cout << "[Main] Om interrupted." << std::endl; + Om::om->quit(); +} + + +#ifdef BUILD_IN_PROCESS_ENGINE + +jack_client_t* jack_client; +jack_intclient_t jack_intclient; + + +void +unload_in_process_engine(int) +{ + jack_status_t status; + int ret = EXIT_SUCCESS; + + cout << "Unloading..."; + status = jack_internal_client_unload(jack_client, jack_intclient); + if (status & JackFailure) { + cout << "failed" << endl; + ret = EXIT_FAILURE; + } else { + cout << "done" << endl; + } + jack_client_close(jack_client); + exit(ret); +} + + +int +load_in_process_engine(const char* port) +{ + int ret = EXIT_SUCCESS; + + jack_status_t status; + + if ((jack_client = jack_client_open("om_load", JackNoStartServer, + &status)) != NULL) { + jack_intclient = + jack_internal_client_load(jack_client, "Om", + (jack_options_t)(JackLoadName|JackLoadInit), + &status, "om", port); + if (status == 0) { + cout << "Engine loaded" << endl; + signal(SIGINT, unload_in_process_engine); + signal(SIGTERM, unload_in_process_engine); + + while (1) { + sleep(1); + } + } else if (status & JackFailure) { + cerr << "Could not load om.so" << endl; + ret = EXIT_FAILURE; + } + + jack_client_close(jack_client); + } else { + cerr << "jack_client_open failed" << endl; + ret = EXIT_FAILURE; + } +} + +#endif // BUILD_IN_PROCESS_ENGINE + + +int +main(int argc, char** argv) +{ +#ifdef HAVE_LASH + lash_args_t* lash_args = lash_extract_args(&argc, &argv); +#endif + + int ret = EXIT_SUCCESS; + + /* Parse command line options */ + gengetopt_args_info args_info; + if (cmdline_parser (argc, argv, &args_info) != 0) + return EXIT_FAILURE; + + + if (args_info.in_jackd_flag) { +#ifdef BUILD_IN_PROCESS_ENGINE + ret = load_in_process_engine(args_info.port_arg); +#else + cerr << "In-process Jack client support not enabled in this build." << endl; + ret = EXIT_FAILURE; +#endif // JACK_IN_PROCESS_ENGINE + } else { + signal(SIGINT, catch_int); + signal(SIGTERM, catch_int); + + Om::set_denormal_flags(); + + Om::om = new Om::OmApp(args_info.port_arg); + +#ifdef HAVE_LASH + Om::lash_driver = new Om::LashDriver(Om::om, lash_args); +#endif + + Om::om->main(); + +#ifdef HAVE_LASH + delete Om::lash_driver; +#endif + + delete Om::om; + } + + return ret; +} + diff --git a/src/libs/engine/midi.h b/src/libs/engine/midi.h new file mode 100644 index 00000000..6575ede7 --- /dev/null +++ b/src/libs/engine/midi.h @@ -0,0 +1,135 @@ +/* Definitions to ease working with raw MIDI. + * + * Stolen from Alsa's asounddef.h + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef MIDI_H +#define MIDI_H + + +/** + * \defgroup midi MIDI Definitions + * MIDI command and controller number definitions. + * \{ + */ + +// Commands: + +#define MIDI_CMD_NOTE_OFF 0x80 /**< note off */ +#define MIDI_CMD_NOTE_ON 0x90 /**< note on */ +#define MIDI_CMD_NOTE_PRESSURE 0xA0 /**< key pressure */ +#define MIDI_CMD_CONTROL 0xB0 /**< control change */ +#define MIDI_CMD_PGM_CHANGE 0xC0 /**< program change */ +#define MIDI_CMD_CHANNEL_PRESSURE 0xD0 /**< channel pressure */ +#define MIDI_CMD_BENDER 0xE0 /**< pitch bender */ + +#define MIDI_CMD_COMMON_SYSEX 0xF0 /**< sysex (system exclusive) begin */ +#define MIDI_CMD_COMMON_MTC_QUARTER 0xF1 /**< MTC quarter frame */ +#define MIDI_CMD_COMMON_SONG_POS 0xF2 /**< song position */ +#define MIDI_CMD_COMMON_SONG_SELECT 0xF3 /**< song select */ +#define MIDI_CMD_COMMON_TUNE_REQUEST 0xF6 /**< tune request */ +#define MIDI_CMD_COMMON_SYSEX_END 0xF7 /**< end of sysex */ +#define MIDI_CMD_COMMON_CLOCK 0xF8 /**< clock */ +#define MIDI_CMD_COMMON_START 0xFA /**< start */ +#define MIDI_CMD_COMMON_CONTINUE 0xFB /**< continue */ +#define MIDI_CMD_COMMON_STOP 0xFC /**< stop */ +#define MIDI_CMD_COMMON_SENSING 0xFE /**< active sensing */ +#define MIDI_CMD_COMMON_RESET 0xFF /**< reset */ + + +// Controllers: + +#define MIDI_CTL_MSB_BANK 0x00 /**< Bank selection */ +#define MIDI_CTL_MSB_MODWHEEL 0x01 /**< Modulation */ +#define MIDI_CTL_MSB_BREATH 0x02 /**< Breath */ +#define MIDI_CTL_MSB_FOOT 0x04 /**< Foot */ +#define MIDI_CTL_MSB_PORTAMENTO_TIME 0x05 /**< Portamento time */ +#define MIDI_CTL_MSB_DATA_ENTRY 0x06 /**< Data entry */ +#define MIDI_CTL_MSB_MAIN_VOLUME 0x07 /**< Main volume */ +#define MIDI_CTL_MSB_BALANCE 0x08 /**< Balance */ +#define MIDI_CTL_MSB_PAN 0x0A /**< Panpot */ +#define MIDI_CTL_MSB_EXPRESSION 0x0B /**< Expression */ +#define MIDI_CTL_MSB_EFFECT1 0x0C /**< Effect1 */ +#define MIDI_CTL_MSB_EFFECT2 0x0D /**< Effect2 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE1 0x10 /**< General purpose 1 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE2 0x11 /**< General purpose 2 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE3 0x12 /**< General purpose 3 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE4 0x13 /**< General purpose 4 */ +#define MIDI_CTL_LSB_BANK 0x20 /**< Bank selection */ +#define MIDI_CTL_LSB_MODWHEEL 0x21 /**< Modulation */ +#define MIDI_CTL_LSB_BREATH 0x22 /**< Breath */ +#define MIDI_CTL_LSB_FOOT 0x24 /**< Foot */ +#define MIDI_CTL_LSB_PORTAMENTO_TIME 0x25 /**< Portamento time */ +#define MIDI_CTL_LSB_DATA_ENTRY 0x26 /**< Data entry */ +#define MIDI_CTL_LSB_MAIN_VOLUME 0x27 /**< Main volume */ +#define MIDI_CTL_LSB_BALANCE 0x28 /**< Balance */ +#define MIDI_CTL_LSB_PAN 0x2A /**< Panpot */ +#define MIDI_CTL_LSB_EXPRESSION 0x2B /**< Expression */ +#define MIDI_CTL_LSB_EFFECT1 0x2C /**< Effect1 */ +#define MIDI_CTL_LSB_EFFECT2 0x2D /**< Effect2 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE1 0x30 /**< General purpose 1 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE2 0x31 /**< General purpose 2 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE3 0x32 /**< General purpose 3 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE4 0x33 /**< General purpose 4 */ +#define MIDI_CTL_SUSTAIN 0x40 /**< Sustain pedal */ +#define MIDI_CTL_PORTAMENTO 0x41 /**< Portamento */ +#define MIDI_CTL_SOSTENUTO 0x42 /**< Sostenuto */ +#define MIDI_CTL_SUSTENUTO 0x42 /**< Sostenuto (a typo in the older version) */ +#define MIDI_CTL_SOFT_PEDAL 0x43 /**< Soft pedal */ +#define MIDI_CTL_LEGATO_FOOTSWITCH 0x44 /**< Legato foot switch */ +#define MIDI_CTL_HOLD2 0x45 /**< Hold2 */ +#define MIDI_CTL_SC1_SOUND_VARIATION 0x46 /**< SC1 Sound Variation */ +#define MIDI_CTL_SC2_TIMBRE 0x47 /**< SC2 Timbre */ +#define MIDI_CTL_SC3_RELEASE_TIME 0x48 /**< SC3 Release Time */ +#define MIDI_CTL_SC4_ATTACK_TIME 0x49 /**< SC4 Attack Time */ +#define MIDI_CTL_SC5_BRIGHTNESS 0x4A /**< SC5 Brightness */ +#define MIDI_CTL_SC6 0x4B /**< SC6 */ +#define MIDI_CTL_SC7 0x4C /**< SC7 */ +#define MIDI_CTL_SC8 0x4D /**< SC8 */ +#define MIDI_CTL_SC9 0x4E /**< SC9 */ +#define MIDI_CTL_SC10 0x4F /**< SC10 */ +#define MIDI_CTL_GENERAL_PURPOSE5 0x50 /**< General purpose 5 */ +#define MIDI_CTL_GENERAL_PURPOSE6 0x51 /**< General purpose 6 */ +#define MIDI_CTL_GENERAL_PURPOSE7 0x52 /**< General purpose 7 */ +#define MIDI_CTL_GENERAL_PURPOSE8 0x53 /**< General purpose 8 */ +#define MIDI_CTL_PORTAMENTO_CONTROL 0x54 /**< Portamento control */ +#define MIDI_CTL_E1_REVERB_DEPTH 0x5B /**< E1 Reverb Depth */ +#define MIDI_CTL_E2_TREMOLO_DEPTH 0x5C /**< E2 Tremolo Depth */ +#define MIDI_CTL_E3_CHORUS_DEPTH 0x5D /**< E3 Chorus Depth */ +#define MIDI_CTL_E4_DETUNE_DEPTH 0x5E /**< E4 Detune Depth */ +#define MIDI_CTL_E5_PHASER_DEPTH 0x5F /**< E5 Phaser Depth */ +#define MIDI_CTL_DATA_INCREMENT 0x60 /**< Data Increment */ +#define MIDI_CTL_DATA_DECREMENT 0x61 /**< Data Decrement */ +#define MIDI_CTL_NONREG_PARM_NUM_LSB 0x62 /**< Non-registered parameter number */ +#define MIDI_CTL_NONREG_PARM_NUM_MSB 0x63 /**< Non-registered parameter number */ +#define MIDI_CTL_REGIST_PARM_NUM_LSB 0x64 /**< Registered parameter number */ +#define MIDI_CTL_REGIST_PARM_NUM_MSB 0x65 /**< Registered parameter number */ +#define MIDI_CTL_ALL_SOUNDS_OFF 0x78 /**< All sounds off */ +#define MIDI_CTL_RESET_CONTROLLERS 0x79 /**< Reset Controllers */ +#define MIDI_CTL_LOCAL_CONTROL_SWITCH 0x7A /**< Local control switch */ +#define MIDI_CTL_ALL_NOTES_OFF 0x7B /**< All notes off */ +#define MIDI_CTL_OMNI_OFF 0x7C /**< Omni off */ +#define MIDI_CTL_OMNI_ON 0x7D /**< Omni on */ +#define MIDI_CTL_MONO1 0x7E /**< Mono1 */ +#define MIDI_CTL_MONO2 0x7F /**< Mono2 */ +//@} + + +/** \} */ + +#endif /* MIDI_H */ diff --git a/src/libs/engine/tests/Makefile.am b/src/libs/engine/tests/Makefile.am new file mode 100644 index 00000000..54f6ad1f --- /dev/null +++ b/src/libs/engine/tests/Makefile.am @@ -0,0 +1,27 @@ +if BUILD_UNIT_TESTS + +AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ -I../../common +common_ldadd = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ -lrt +node_tree_test_LDADD = $(common_ldadd) +queue_test_LDADD = $(common_ldadd) + +bin_PROGRAMS = node_tree_test queue_test list_test path_test + +list_test_SOURCES = \ + ../List.h \ + list_test.cpp + +path_test_SOURCES = \ + ../../common/Path.h \ + path_test.cpp + +node_tree_test_SOURCES = \ + node_tree_test.cpp \ + ../Tree.h \ + ../TreeImplementation.h + +queue_test_SOURCES = \ + queue_test.cpp \ + ../../common/Queue.h + +endif # BUILD_UNIT_TESTS diff --git a/src/libs/engine/tests/list_test.cpp b/src/libs/engine/tests/list_test.cpp new file mode 100644 index 00000000..d2f91c9d --- /dev/null +++ b/src/libs/engine/tests/list_test.cpp @@ -0,0 +1,93 @@ +#include "../List.h" +#include +#include + +using std::cout; using std::endl; + + +int main() +{ + List l; + + l.push_back(new ListNode(1)); + l.push_back(new ListNode(2)); + l.push_back(new ListNode(3)); + l.push_back(new ListNode(4)); + l.push_back(new ListNode(5)); + l.push_back(new ListNode(6)); + l.push_back(new ListNode(7)); + l.push_back(new ListNode(8)); + + cout << "List:" << endl; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + cout << endl; + + + for (List::iterator i = l.begin(); i != l.end(); ++i) { + if ((*i) == 4) + l.remove(i); + } + + std::cerr << "Removed 4 (by iterator)...\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + cout << endl; + + l.remove(1); + + std::cerr << "Removed 1 (head) (by value)...\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + cout << endl; + + for (List::iterator i = l.begin(); i != l.end(); ++i) { + if ((*i) == 2) + l.remove(i); + } + + std::cerr << "Removed 2 (head) (by iterator)...\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + cout << endl; + + l.remove(5); + + std::cerr << "Removed 5 (by value)...\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + cout << endl; + + l.remove(8); + + std::cerr << "Removed 8 (tail) (by value)...\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + cout << endl; + + for (List::iterator i = l.begin(); i != l.end(); ++i) { + if ((*i) == 7) + l.remove(i); + } + + std::cerr << "Removed 7 (tail) (by iterator)...\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + cout << endl; + + List r; + r.push_back(new ListNode(9)); + r.remove(9); + std::cerr << "Should not see ANY numbers:\n"; + for (List::iterator i = r.begin(); i != r.end(); ++i) { + cout << *i << endl; + } + return 0; +} diff --git a/src/libs/engine/tests/node_tree_test.cpp b/src/libs/engine/tests/node_tree_test.cpp new file mode 100644 index 00000000..2bce9b97 --- /dev/null +++ b/src/libs/engine/tests/node_tree_test.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include "../Tree.h" +#include "../TreeImplementation.h" + +using std::vector; +using std::cout; using std::cerr; using std::endl; + +static const uint NUM_NODES = 20; + +int +main() +{ + cout << "\n\n\n\n"; + + Tree tree; + vector names; + vector in_tree; // arrays + uint num_in_tree = 0; + + + string name; + + for (uint i=0; i < NUM_NODES; ++i) { + name = (char)(i+'A'); + TreeNode* n = new TreeNode(name, name); + tree.insert(n); + names.push_back(name); + in_tree.push_back(true); + ++num_in_tree; + } + + cout << "Added " << NUM_NODES << " nodes." << endl; + cout << "Tree size: " << tree.size() << endl << endl; + + cout << "Tree contents: " << endl; + for (Tree::iterator i = tree.begin(); i != tree.end(); ++i) { + cout << (*i) << ", "; + } + cout << endl; + + + while (true) { + bool insert; + int num = rand() % NUM_NODES; + + if (num_in_tree == 0) + insert = true; + else if (num_in_tree == NUM_NODES) + insert = false; + else { + while (true) { + insert = rand() % 2; + num = rand() % NUM_NODES; + if ((insert && !in_tree[num]) || (!insert && in_tree[num])) + break; + } + } + + string name = names[num]; + + if (insert) { + assert(in_tree[num] == false); + cout << "\nInserting '" << name << "'" << endl; + tree.insert(new TreeNode(name, name)); + in_tree[num] = true; + ++num_in_tree; + cout << "Tree size: " << tree.size() << endl; + assert(num_in_tree == tree.size()); + } else { + assert(in_tree[num] == true); + cout << "\nRemoving '" << name << "'" << endl; + TreeNode* removed = tree.remove(name); + assert(removed != NULL); + assert(removed->node() == name); + assert(removed->key() == name); + delete removed; + in_tree[num] = false; + assert(names[num] == name); + --num_in_tree; + cout << "Tree size: " << tree.size() << endl; + assert(num_in_tree == tree.size()); + } + assert(num_in_tree == tree.size()); + cout << "Tree contents: " << endl; + for (Tree::iterator i = tree.begin(); i != tree.end(); ++i) { + cout << (*i) << ", "; + } + cout << endl; + } + + return 0; +} diff --git a/src/libs/engine/tests/old_node_tree_test.cpp b/src/libs/engine/tests/old_node_tree_test.cpp new file mode 100644 index 00000000..3b5ed485 --- /dev/null +++ b/src/libs/engine/tests/old_node_tree_test.cpp @@ -0,0 +1,72 @@ +#include +#include "../NodeTree.h" +#include "../NodeBase.h" + +using std::cout; using std::cerr; using std::endl; + +int main() +{ + cout << "\n\n\n\n"; + + NodeBase* n = NULL; + TreeNode* tn = NULL; + TreeNode* baz = NULL; + TreeNode* quuux = NULL; + TreeNode* bar = NULL; + + NodeTree tree; + n = new NodeBase("foo", 0, 0, 0); + tn = new TreeNode(n); + tree.insert(tn); + n = new NodeBase("bar", 0, 0, 0); + bar = new TreeNode(n); + tree.insert(bar); + n = new NodeBase("baz", 0, 0, 0); + baz = new TreeNode(n); + tree.insert(baz); + n = new NodeBase("quux", 0, 0, 0); + tn = new TreeNode(n); + tree.insert(tn); + n = new NodeBase("quuux", 0, 0, 0); + quuux = new TreeNode(n); + tree.insert(quuux); + n = new NodeBase("quuuux", 0, 0, 0); + tn = new TreeNode(n); + tree.insert(tn); + + + cout << "Added 6 nodes." << endl; + cout << "Tree size: " << tree.size() << endl << endl; + + cout << "Iterating: " << endl; + for (NodeTree::iterator i = tree.begin(); i != tree.end(); ++i) { + cout << (*i)->name() << endl; + } + + cout << endl << "Search 'foo' - " << tree.find("foo")->name() << endl; + cout << endl << "Search 'bar' - " << tree.find("bar")->name() << endl; + cout << endl << "Search 'baz' - " << tree.find("baz")->name() << endl; + cout << endl << "Search 'quux' - " << tree.find("quux")->name() << endl; + cout << endl << "Search 'quuux' - " << tree.find("quuux")->name() << endl; + cout << endl << "Search 'quuuux' - " << tree.find("quuuux")->name() << endl; + cout << endl << "Search 'dave' - " << tree.find("dave") << endl; + cout << endl << "Search 'fo' - " << tree.find("fo") << endl << endl; + + cout << "Removing 'baz'." << endl; + tree.remove(baz); + + cout << "Iterating: " << endl; + for (NodeTree::iterator i = tree.begin(); i != tree.end(); ++i) { + cout << (*i)->name() << endl; + } + + cout << "Removing 'bar' (the root): " << endl; + tree.remove(bar); + + cout << "Iterating: " << endl; + for (NodeTree::iterator i = tree.begin(); i != tree.end(); ++i) { + cout << (*i)->name() << endl; + } + + return 0; +} diff --git a/src/libs/engine/tests/queue_test.cpp b/src/libs/engine/tests/queue_test.cpp new file mode 100644 index 00000000..3381a329 --- /dev/null +++ b/src/libs/engine/tests/queue_test.cpp @@ -0,0 +1,47 @@ +#include +#include +#include "../../common/Queue.h" + +using std::string; using std::cerr; using std::cout; using std::endl; + + +int main() +{ + Queue q(10); + + cout << "New queue. Should be empty: " << q.is_empty() << endl; + cout << "Capacity: " << q.capacity() << endl; + cout << "Fill: " << q.fill() << endl; + + for (uint i=0; i < 5; ++i) { + q.push(i); + assert(!q.is_full()); + q.pop(); + } + cout << "Pushed and popped 5 elements. Queue should be empty: " << q.is_empty() << endl; + cout << "Fill: " << q.fill() << endl; + + for (uint i=10; i < 20; ++i) { + q.push(i); + } + cout << "Pushed 10 elements. Queue should be full: " << q.is_full() << endl; + cout << "Fill: " << q.fill() << endl; + + cout << "The digits 10->19 should print: " << endl; + while (!q.is_empty()) { + int foo = q.pop(); + cout << "Popped: " << foo << endl; + } + cout << "Queue should be empty: " << q.is_empty() << endl; + cout << "Fill: " << q.fill() << endl; + + cout << "Attempting to add eleven elements to queue of size 10. Only first 10 should succeed:" << endl; + for (uint i=20; i <= 39; ++i) { + cout << i; + cout << " - Fill: " << q.fill(); + cout << ", is full: " << q.is_full(); + cout << ", succeeded: " << q.push(i) << endl; + } + + return 0; +} diff --git a/src/libs/engine/tuning.h b/src/libs/engine/tuning.h new file mode 100644 index 00000000..aeec81da --- /dev/null +++ b/src/libs/engine/tuning.h @@ -0,0 +1,39 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TUNING_H +#define TUNING_H + +#include +#include + +namespace Om { + +// FIXME: put this in a Config class + +static const size_t event_queue_size = 1024; +static const size_t pre_processor_queue_size = 1024; +static const size_t post_processor_queue_size = 1024; +static const size_t maid_queue_size = 1024; + +// This controls both the LASH event processing rate and the Maid cleanup rate +// (both of which are driven from the main thread) +static const timespec main_rate = { 0, 500000000 }; // 1/2 second + + +} // namespace Om + +#endif // TUNING_H diff --git a/src/libs/engine/util.h b/src/libs/engine/util.h new file mode 100644 index 00000000..9cf4bf7f --- /dev/null +++ b/src/libs/engine/util.h @@ -0,0 +1,73 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UTIL_H +#define UTIL_H + +#include +#include + +#include +#ifdef __SSE__ +#include +#endif + +using std::cerr; using std::endl; + +namespace Om { + +/** Set flags to disable denormal processing. + */ +inline void +set_denormal_flags() +{ +#ifdef __SSE__ + unsigned long a, b, c, d; + + asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); + if (d & 1<<25) { /* It has SSE support */ + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + + asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (0)); + if (b == 0x756e6547) { /* It's an Intel */ + int stepping, model, family, extfamily; + + family = (a >> 8) & 0xf; + extfamily = (a >> 20) & 0xff; + model = (a >> 4) & 0xf; + stepping = a & 0xf; + if (family == 15 && extfamily == 0 && model == 0 && stepping < 7) { + return; + } + } + asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); + if (d & 1<<26) { /* bit 26, SSE2 support */ + _mm_setcsr(_mm_getcsr() | 0x40); + //cerr << "Set SSE denormal fix flag." << endl; + } + } else { + cerr << "This code has been built with SSE support, but your processor does" + << " not support the SSE instruction set." << endl << "Exiting." << endl; + exit(EXIT_FAILURE); + } +#endif + // Set 387 control register via standard C99 interface + fesetround(FE_TOWARDZERO); +} + +} // namespace Om + +#endif // UTIL_H diff --git a/src/progs/om/Makefile.am b/src/progs/om/Makefile.am new file mode 100644 index 00000000..ae0b3e53 --- /dev/null +++ b/src/progs/om/Makefile.am @@ -0,0 +1,259 @@ +SUBDIRS = tests +DIST_SUBDIRS = events + +AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @SLV2_CFLAGS@ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/engine/events -fno-exceptions -fno-rtti + +MAINTAINERCLEANFILES = Makefile.in + +common_SOURCES = \ + util.h \ + tuning.h \ + Node.h \ + NodeBase.h \ + NodeBase.cpp \ + InternalNode.h \ + Patch.h \ + Patch.cpp \ + NodeFactory.h \ + NodeFactory.cpp \ + Om.h \ + Om.cpp \ + OmApp.h \ + OmApp.cpp \ + JackAudioDriver.h \ + JackAudioDriver.cpp \ + OSCReceiver.h \ + OSCReceiver.cpp \ + Responder.h \ + OSCResponder.h \ + OSCResponder.cpp \ + ClientKey.h \ + ClientBroadcaster.h \ + ClientBroadcaster.cpp \ + ObjectSender.h \ + ObjectSender.cpp \ + OSCClient.h \ + OSCClient.cpp \ + Buffer.h \ + Buffer.cpp \ + Port.h \ + Port.cpp \ + PortBase.h \ + PortBase.cpp \ + InputPort.h \ + InputPort.cpp \ + OutputPort.h \ + OutputPort.cpp \ + MidiMessage.h \ + MidiNoteNode.h \ + MidiNoteNode.cpp \ + MidiTriggerNode.h \ + MidiTriggerNode.cpp \ + MidiControlNode.h \ + MidiControlNode.cpp \ + BridgeNode.h \ + BridgeNode.cpp \ + ControlInputNode.h \ + ControlInputNode.cpp \ + ControlOutputNode.h \ + ControlOutputNode.cpp \ + AudioInputNode.h \ + AudioInputNode.cpp \ + AudioOutputNode.h \ + AudioOutputNode.cpp \ + MidiInputNode.h \ + MidiInputNode.cpp \ + MidiOutputNode.h \ + MidiOutputNode.cpp \ + Event.h \ + Event.cpp \ + QueuedEvent.h \ + EventSource.h \ + QueuedEventSource.h \ + QueuedEventSource.cpp \ + QueuedEngineInterface.h \ + QueuedEngineInterface.cpp \ + OmObject.h \ + Maid.h \ + Maid.cpp \ + MaidObject.h \ + Tree.h \ + ClientRecord.h \ + PortInfo.h \ + PluginLibrary.h \ + Plugin.h \ + Array.h \ + List.h \ + PostProcessor.h \ + PostProcessor.cpp \ + Connection.h \ + Connection.cpp \ + ConnectionBase.h \ + ConnectionBase.cpp \ + ObjectStore.h \ + ObjectStore.cpp \ + TransportNode.h \ + TransportNode.cpp \ + Driver.h \ + AudioDriver.h \ + MidiDriver.h \ + midi.h \ + ../common/util/Semaphore.h \ + ../common/util/types.h \ + ../common/util/Path.h \ + ../common/util/Queue.h \ + ../common/interface/ClientInterface.h \ + ../common/interface/EngineInterface.h \ + instantiations.cpp + +# Events +common_SOURCES += \ + events/RegisterClientEvent.h \ + events/RegisterClientEvent.cpp \ + events/UnregisterClientEvent.h \ + events/UnregisterClientEvent.cpp \ + events/PingQueuedEvent.h \ + events/ActivateEvent.h \ + events/ActivateEvent.cpp \ + events/DeactivateEvent.h \ + events/DeactivateEvent.cpp \ + events/SetPortValueEvent.h \ + events/SetPortValueEvent.cpp \ + events/SetPortValueQueuedEvent.h \ + events/SetPortValueQueuedEvent.cpp \ + events/NoteOnEvent.h \ + events/NoteOnEvent.cpp \ + events/NoteOffEvent.h \ + events/NoteOffEvent.cpp \ + events/AllNotesOffEvent.h \ + events/AllNotesOffEvent.cpp \ + events/ConnectionEvent.h \ + events/ConnectionEvent.cpp \ + events/DisconnectionEvent.h \ + events/DisconnectionEvent.cpp \ + events/DisconnectNodeEvent.h \ + events/DisconnectNodeEvent.cpp \ + events/DisconnectPortEvent.h \ + events/DisconnectPortEvent.cpp \ + events/DestroyEvent.h \ + events/DestroyEvent.cpp \ + events/AddNodeEvent.h \ + events/AddNodeEvent.cpp \ + events/SetMetadataEvent.h \ + events/SetMetadataEvent.cpp \ + events/RequestMetadataEvent.h \ + events/RequestMetadataEvent.cpp \ + events/RequestPortValueEvent.h \ + events/RequestPortValueEvent.cpp \ + events/RequestAllObjectsEvent.h \ + events/RequestAllObjectsEvent.cpp \ + events/RequestPluginsEvent.h \ + events/RequestPluginsEvent.cpp \ + events/CreatePatchEvent.h \ + events/CreatePatchEvent.cpp \ + events/LoadPluginsEvent.h \ + events/LoadPluginsEvent.cpp \ + events/EnablePatchEvent.h \ + events/EnablePatchEvent.cpp \ + events/DisablePatchEvent.h \ + events/DisablePatchEvent.cpp \ + events/ClearPatchEvent.h \ + events/ClearPatchEvent.cpp \ + events/RenameEvent.h \ + events/RenameEvent.cpp \ + events/MidiLearnEvent.h \ + events/MidiLearnEvent.cpp + +if WITH_JACK_MIDI +common_SOURCES += \ + JackMidiDriver.h \ + JackMidiDriver.cpp +endif + +if WITH_ALSA_MIDI +common_SOURCES += \ + AlsaMidiDriver.h \ + AlsaMidiDriver.cpp +endif + +if WITH_LADSPA +common_SOURCES += \ + LADSPAPlugin.h \ + LADSPAPlugin.cpp +endif + +if WITH_DSSI +common_SOURCES += \ + DSSIPlugin.h \ + DSSIPlugin.cpp \ + events/DSSIConfigureEvent.cpp \ + events/DSSIConfigureEvent.h \ + events/DSSIControlEvent.cpp \ + events/DSSIControlEvent.h \ + events/DSSIProgramEvent.cpp \ + events/DSSIProgramEvent.h \ + events/DSSIUpdateEvent.cpp \ + events/DSSIUpdateEvent.h +endif + +if WITH_LV2 +common_SOURCES += \ + LV2Plugin.h \ + LV2Plugin.cpp +endif + +if WITH_LASH +common_SOURCES += \ + LashDriver.h \ + LashDriver.cpp \ + LashRestoreDoneEvent.h +endif + + +# +# Non-installed library to link stand-alone and in-process build against +# + +noinst_LTLIBRARIES = libom.la +libom_la_SOURCES = $(common_SOURCES) + + + +# +# Stand-alone engine +# +if BUILD_ENGINE + +bin_PROGRAMS = om +om_DEPENDENCIES = libom.la +om_LDADD = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -lrt libom.la + +om_SOURCES = \ + main.cpp \ + cmdline.h \ + cmdline.c + +endif # BUILD_ENGINE + + + +# +# Jack internal client +# +if BUILD_IN_PROCESS_ENGINE + + +# FIXME: broken + + +# FIXME: Figure out how to get this properly +omdir = $(prefix)/lib/jack + +om_la_CFLAGS = -fPIC +om_LTLIBRARIES = om.la +om_la_LDFLAGS = -module -avoid-version @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ +om_la_SOURCES = OmInProcess.cpp + +endif # BUILD_IN_PROCESS_ENGINE + + -- cgit v1.2.1