Differences

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 16:07]
dev:recording_from_multiple_midi_ports [2022/05/06 16: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
 +device.
 +
 +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/)
 +MidiDevice.C
 +
 +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: 2022/05/06 16:07 (external edit)
Recent changes RSS feed Creative Commons License Valid XHTML 1.0 Valid CSS Driven by DokuWiki