This shows you the differences between two versions of the page.

Link to this comparison view

dev:recording_from_multiple_midi_ports [2018/02/07 17:07]
dev:recording_from_multiple_midi_ports [2018/02/07 17:07] (current)
Line 1: Line 1:
 +====== Recording from Multiple MIDI Ports ======
 +Multiport recording implementation
 +June 27, 2004
 +The implementation of the multiport recording functionality can be phased out,
 +each step with separate development,​ test and debugging. At the end of each
 +step, the changes will be committed using a branch created for the  project,
 +named '​multiport_recording'​. Each step is an incremental and accumulative
 +approach to the final goal: to have several input sources working at once in
 +Rosegarden, and to have a smart and comfortable management ​ of input
 +subscriptions. This feature is limited to the ALSA driver.
 +===== Phase 1 =====
 +Split the single Rosegarden port into an input port and an output one. This is
 +not strictly necessary, but is better for readability and debugging purposes.
 +The input port will be created with automatic timestamping in real time units.
 +This allow the connections made with external programs behave like the
 +internally made ones. The output port will be hidden, at least for polite
 +programs (kaconnect). The client name will be renamed to only "​Rosegarden"​.
 +Each port will have the following properties:
 +  #0, name: Rosegarden input, ​
 +            capabilities:​ SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE
 +  #1, name: Rosegarden output, ​
 +            capabilities:​ SND_SEQ_PORT_CAP_READ
 +The AlsaDriver'​s variable member m_port will be replaced by two: m_inputport
 +and m_outputport (both private). All the changes involve only the files
 +sound/​AlsaDriver.cpp and sound/​AlsaDriver.h
 +At this point, we will be able to make subscriptions to the Rosegarden input
 +port with a command like this:
 +  $ aconnect 72:0 Rosegarden:​0
 +Yes, it is not a mistake. You can use the client name instead the port name. We
 +know that the input port number will be 0, and no options are required,
 +because that has been done at input port creation time. Output port 
 +connection management isn't allowed outside of Rosegarden.
 +===== Phase 2 =====
 +The selected input port is stored in the file "​rosegardenrc",​ section
 +"​[SequencerOptions]",​ key "​midirecorddevice"​. This was a single value (a
 +device number), but it will be a list, now. So, the configuration files will
 +be compatible, but the values are stored into a QStringList in the program,
 +and must be read with KConfig::​readListEntry()
 +The message id MappedEvent::​SystemRecordDevice was used by the GUI to tell the
 +sequencer that a new device is selected for recording. The only change
 +required is to use another constructor with one more parameter to disconnect a
 +recording port, too. The MappedEvent object will be constructed with the
 +device as Data1 and true/false in Data2. See sequencemanager.cpp:​1380 and
 +devicemanager.cpp:​460. When this message was received in AlsaDriver, the old
 +connection was removed, and a new one was established. The new behavior is to
 +only perform the requested operation (connect/​disconnect) upon the indicated
 +The MappedEvent::​SystemUpdateInstruments message is generated by a timer each 3
 +seconds when the ALSA port list has changed. It is necessary to generate it
 +also when the connections to the Rosegarden input port has changed
 +(checkForNewClients). Here may be useful to complement the 3 seconds timer with
 +a subscription to the ALSA System:​Announce port. Another needed change
 +involves sound/​MappedDevice,​ and base/​MidiDevice. Both classes have now a
 +boolean m_recording data member and public accesors.
 +Files Changed: (gui/) rosegardenguidoc.cpp,​ devicemanager.cpp,​
 +sequencemanager.cpp,​ (sound/) AlsaDriver.cpp,​ MappedDevice.cpp (base/)
 +At this point we can connect a external port to Rosegarden (with aconnect), and
 +it will be reflected in the Studio window. We can also connect several
 +recording inputs in the Studio window, and disconnect any connection. The port
 +connection state will be saved in the resource settings file (rosegardenrc),​
 +and restored again in the next program run.
 +There is a funny behavior, though. If you connect another input device using a
 +external program, like aconnect, the connection is shown in the Studio window,
 +but it is not saved to the configuration file, so it won't be restored ​
 +the next time rosegarden is run. Also, externally made connections take less
 +precedence over persistent connections,​ so if you unsubscribe a saved (in
 +rosegardenrc) connection with an external program, it will be restored by
 +rosegarden as soon as the change is detected, obstinately.
 +===== Phase 3 =====
 +We can store for each event recorded a set of properties. Two new properties
 +will be created, with names "​recorded-port"​ and "​recorded-channel"​. The former
 +will hold the ALSA client:port pair of the originating event, and the latter
 +the original MIDI channel. These properties will be used for future
 +functionalities as "Split by channel"​ or "Split by input port" dialogs,
 +similar to the "Split by pitch" one.
 +The implementation should modify MappedEvent class, including two new
 +properties: ​ recordedPort and recordedChannel,​ with the corresponding
 +setters/​getters. Store these properties in AlsaDriver::​getMappedComposition(),​
 +when applicable. Note and other Channel Events have channel information,​ and
 +can be retrieved with event->​data.note.channel or event->​data.control.channel.
 +The property value for recordedPort can be retrieved from event->​source.client
 +and event->​source.port (two integers); event->​source is a snd_seq_addr_t.
 +Files  sound/​MappedEvent.h and sound/​MappedEvent.cpp
 +It is necessary also to modify rosegardenguidoc.cpp,​ method
 +RosegardenGUIDoc::​insertRecordedMidi(),​ inserting the new properties in
 +rEvent. The new properties are non-persistent. See base/​Event.[C|h]
 +Phase 3 can be delayed until it is required by a real functionality.
 +===== Known issues =====
 +You can record from several input sources, but (of course) all the inputs are
 +merged on a single output port. They are also merged in a single segment. The
 +note duration detection is based on a single map (m_noteOnMap,​ member of
 +SoundDriver). The map handles a event for each noteon received, and it's
 +updated with the note length when a noteoff is received. When you record from
 +several input sources, two musicians can collide in the same note, and one is
 +lost (and the other note may have a wrong length). ​
 +To solve this issue, several changes are needed. m_noteOnMap is a SoundDriver
 +data member but it's not referred to in any SoundDriver code and there are no
 +public SoundDriver methods using it.  Ergo, there'​s no compelling reason it
 +should be a member of SoundDriver rather than the subclasses (AlsaDriver and
 +ArtsDriver). ​ And it's a bit of a hack anyway; conceptually it's really a
 +map<​ChannelNo,​ map<​Pitch,​ MappedEvent *> > but the channel number and pitch
 +have been rolled into a single int for brevity. ​ I would see no problem with
 +unrolling them, giving a more complex definition but probably simpler usage,
 +and making it obvious how to include another level of indirection (say to map
 +from origin port to channel number to pitch to mapped event). ​
 +Last update: July 3, 2004
dev/recording_from_multiple_midi_ports.txt ยท Last modified: 2018/02/07 17:07 (external edit)
Recent changes RSS feed Creative Commons License Valid XHTML 1.0 Valid CSS Driven by DokuWiki