/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rosegarden
A MIDI and audio sequencer and musical notation editor .
This program is Copyright 2000 - 2008
Guillaume Laurent < glaurent @ telegraph - road . org > ,
Chris Cannam < cannam @ all - day - breakfast . com > ,
Richard Bown < richard . bown @ ferventsoftware . com >
The moral rights of Guillaume Laurent , Chris Cannam , and Richard
Bown to claim authorship of this work have been asserted .
Other copyrights also apply to some parts of this work . Please
see the AUTHORS file and individual file headers for details .
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation ; either version 2 of the
License , or ( at your option ) any later version . See the file
COPYING included with this distribution for more information .
*/
# include "RosegardenSequencerApp.h"
# include <kapplication.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <sys/mman.h>
# include <unistd.h>
# include <errno.h>
# include <iostream>
# include <klocale.h>
# include <kstandarddirs.h>
# include <dcopclient.h>
# include <tqdatetime.h>
# include <tqstring.h>
# include <tqdir.h>
# include <tqbuffer.h>
# include <tqvaluevector.h>
# include "misc/Debug.h"
# include "ControlBlockMmapper.h"
# include "MmappedSegment.h"
# include "gui/application/RosegardenDCOP.h"
# include "sound/ControlBlock.h"
# include "sound/SoundDriver.h"
# include "sound/SoundDriverFactory.h"
# include "sound/MappedInstrument.h"
# include "base/Profiler.h"
# include "sound/PluginFactory.h"
namespace Rosegarden
{
// The default latency and read-ahead values are actually sent
// down from the GUI every time playback or recording starts
// so the local values are kind of meaningless.
//
//
RosegardenSequencerApp : : RosegardenSequencerApp ( ) :
DCOPObject ( " RosegardenSequencerIface " ) ,
m_driver ( 0 ) ,
m_transportStatus ( STOPPED ) ,
m_songPosition ( 0 , 0 ) ,
m_lastFetchSongPosition ( 0 , 0 ) ,
m_readAhead ( 0 , 80000000 ) , // default value
m_audioMix ( 0 , 60000000 ) , // default value
m_audioRead ( 0 , 100000000 ) , // default value
m_audioWrite ( 0 , 200000000 ) , // default value
m_smallFileSize ( 128 ) ,
m_loopStart ( 0 , 0 ) ,
m_loopEnd ( 0 , 0 ) ,
m_studio ( new MappedStudio ( ) ) ,
m_segmentFilesPath ( KGlobal : : dirs ( ) - > resourceDirs ( " tmp " ) . last ( ) ) ,
m_metaIterator ( 0 ) ,
m_controlBlockMmapper ( 0 ) ,
m_transportToken ( 1 ) ,
m_isEndOfCompReached ( false )
{
SEQUENCER_DEBUG < < " Registering with DCOP server " < < endl ;
// Without DCOP we are nothing
TQCString realAppId = kapp - > dcopClient ( ) - > registerAs ( kapp - > name ( ) , false ) ;
if ( realAppId . isNull ( ) ) {
SEQUENCER_DEBUG < < " RosegardenSequencer cannot register "
< < " with DCOP server " < < endl ;
close ( ) ;
}
// Initialise the MappedStudio
//
initialiseStudio ( ) ;
// Creating this object also initialises the Rosegarden ALSA/JACK
// interface for both playback and recording. MappedStudio
// audio faders are also created.
//
m_driver = SoundDriverFactory : : createDriver ( m_studio ) ;
m_studio - > setSoundDriver ( m_driver ) ;
if ( ! m_driver ) {
SEQUENCER_DEBUG < < " RosegardenSequencer object could not be allocated "
< < endl ;
close ( ) ;
}
m_driver - > setAudioBufferSizes ( m_audioMix , m_audioRead , m_audioWrite ,
m_smallFileSize ) ;
m_driver - > setSequencerDataBlock ( m_sequencerMapper . getSequencerDataBlock ( ) ) ;
m_driver - > setExternalTransportControl ( this ) ;
// Check for new clients every so often
//
m_newClientTimer = new TQTimer ( this ) ;
connect ( m_newClientTimer , TQT_SIGNAL ( timeout ( ) ) ,
this , TQT_SLOT ( slotCheckForNewClients ( ) ) ) ;
m_newClientTimer - > start ( 3000 ) ; // every 3 seconds
}
RosegardenSequencerApp : : ~ RosegardenSequencerApp ( )
{
SEQUENCER_DEBUG < < " RosegardenSequencer - shutting down " < < endl ;
m_driver - > shutdown ( ) ;
delete m_studio ;
delete m_driver ;
delete m_controlBlockMmapper ;
}
void
RosegardenSequencerApp : : quit ( )
{
std : : cerr < < " RosegardenSequencerApp::quit() " < < std : : endl ;
close ( ) ;
// and break out of the loop next time around
m_transportStatus = TQUIT ;
}
void
RosegardenSequencerApp : : stop ( )
{
// set our state at this level to STOPPING (pending any
// unfinished NOTES)
m_transportStatus = STOPPING ;
// report
//
SEQUENCER_DEBUG < < " RosegardenSequencerApp::stop() - stopping " < < endl ;
// process pending NOTE OFFs and stop the Sequencer
m_driver - > stopPlayback ( ) ;
// the Sequencer doesn't need to know these once
// we've stopped.
//
m_songPosition . sec = 0 ;
m_songPosition . nsec = 0 ;
m_lastFetchSongPosition . sec = 0 ;
m_lastFetchSongPosition . nsec = 0 ;
cleanupMmapData ( ) ;
Profiles : : getInstance ( ) - > dump ( ) ;
incrementTransportToken ( ) ;
}
// Get a slice of events from the GUI
//
void
RosegardenSequencerApp : : fetchEvents ( MappedComposition & composition ,
const RealTime & start ,
const RealTime & end ,
bool firstFetch )
{
// Always return nothing if we're stopped
//
if ( m_transportStatus = = STOPPED | | m_transportStatus = = STOPPING )
return ;
// If we're looping then we should get as much of the rest of
// the right hand of the loop as possible and also events from
// the beginning of the loop. We can do this in two fetches.
// Make sure that we delete all returned pointers when we've
// finished with them.
//
//
/*
if ( isLooping ( ) = = true & & end > = m_loopEnd )
{
RealTime loopOverlap = end - m_loopEnd ;
MappedComposition * endLoop = 0 ;
if ( m_loopEnd > start ) {
endLoop = getSlice ( start , m_loopEnd , firstFetch ) ;
}
if ( loopOverlap > RealTime : : zeroTime ) {
MappedComposition * beginLoop =
getSlice ( m_loopStart , m_loopStart + loopOverlap , true ) ;
// move the start time of the begin section one loop width
// into the future and ensure that we keep the clocks level
// until this time has passed
//
beginLoop - > moveStartTime ( m_loopEnd - m_loopStart ) ;
if ( endLoop ) {
( * endLoop ) = ( * endLoop ) + ( * beginLoop ) ;
delete beginLoop ;
} else {
endLoop = beginLoop ;
}
}
if ( endLoop ) return endLoop ;
else return new MappedComposition ( ) ;
}
else
*/
getSlice ( composition , start , end , firstFetch ) ;
applyLatencyCompensation ( composition ) ;
}
void
RosegardenSequencerApp : : getSlice ( MappedComposition & composition ,
const RealTime & start ,
const RealTime & end ,
bool firstFetch )
{
// SEQUENCER_DEBUG << "RosegardenSequencerApp::getSlice (" << start << " -> " << end << ", " << firstFetch << ")" << endl;
if ( firstFetch | | ( start < m_lastStartTime ) ) {
SEQUENCER_DEBUG < < " [calling jumpToTime on start] " < < endl ;
m_metaIterator - > jumpToTime ( start ) ;
}
( void ) m_metaIterator - > fillCompositionWithEventsUntil
( firstFetch , & composition , start , end ) ;
// setEndOfCompReached(eventsRemaining); // don't do that, it breaks recording because
// playing stops right after it starts.
m_lastStartTime = start ;
}
void
RosegardenSequencerApp : : applyLatencyCompensation ( MappedComposition & composition )
{
RealTime maxLatency = m_driver - > getMaximumPlayLatency ( ) ;
if ( maxLatency = = RealTime : : zeroTime )
return ;
for ( MappedComposition : : iterator i = composition . begin ( ) ;
i ! = composition . end ( ) ; + + i ) {
RealTime instrumentLatency =
m_driver - > getInstrumentPlayLatency ( ( * i ) - > getInstrument ( ) ) ;
// std::cerr << "RosegardenSequencerApp::applyLatencyCompensation: maxLatency " << maxLatency << ", instrumentLatency " << instrumentLatency << ", moving " << (*i)->getEventTime() << " to " << (*i)->getEventTime() + maxLatency - instrumentLatency << std::endl;
( * i ) - > setEventTime ( ( * i ) - > getEventTime ( ) +
maxLatency - instrumentLatency ) ;
}
}
// The first fetch of events from the core/ and initialisation for
// this session of playback. We fetch up to m_readAhead ahead at
// first at then top up at each slice.
//
bool
RosegardenSequencerApp : : startPlaying ( )
{
// Fetch up to m_readHead microseconds worth of events
//
m_lastFetchSongPosition = m_songPosition + m_readAhead ;
// This will reset the Sequencer's internal clock
// ready for new playback
m_driver - > initialisePlayback ( m_songPosition ) ;
m_mC . clear ( ) ;
fetchEvents ( m_mC , m_songPosition , m_songPosition + m_readAhead , true ) ;
// process whether we need to or not as this also processes
// the audio queue for us
//
m_driver - > processEventsOut ( m_mC , m_songPosition , m_songPosition + m_readAhead ) ;
std : : vector < MappedEvent > audioEvents ;
m_metaIterator - > getAudioEvents ( audioEvents ) ;
m_driver - > initialiseAudioQueue ( audioEvents ) ;
// SEQUENCER_DEBUG << "RosegardenSequencerApp::startPlaying: pausing to simulate high-load environment" << endl;
// ::sleep(2);
// and only now do we signal to start the clock
//
m_driver - > startClocks ( ) ;
incrementTransportToken ( ) ;
return true ; // !isEndOfCompReached();
}
bool
RosegardenSequencerApp : : keepPlaying ( )
{
Profiler profiler ( " RosegardenSequencerApp::keepPlaying " ) ;
m_mC . clear ( ) ;
RealTime fetchEnd = m_songPosition + m_readAhead ;
if ( isLooping ( ) & & fetchEnd > = m_loopEnd ) {
fetchEnd = m_loopEnd - RealTime ( 0 , 1 ) ;
}
if ( fetchEnd > m_lastFetchSongPosition ) {
fetchEvents ( m_mC , m_lastFetchSongPosition , fetchEnd , false ) ;
}
// Again, process whether we need to or not to keep
// the Sequencer up-to-date with audio events
//
m_driver - > processEventsOut ( m_mC , m_lastFetchSongPosition , fetchEnd ) ;
if ( fetchEnd > m_lastFetchSongPosition ) {
m_lastFetchSongPosition = fetchEnd ;
}
return true ; // !isEndOfCompReached(); - until we sort this out, we don't stop at end of comp.
}
// Return current Sequencer time in GUI compatible terms
//
void
RosegardenSequencerApp : : updateClocks ( )
{
Profiler profiler ( " RosegardenSequencerApp::updateClocks " ) ;
m_driver - > runTasks ( ) ;
checkExternalTransport ( ) ;
//SEQUENCER_DEBUG << "RosegardenSequencerApp::updateClocks" << endl;
// If we're not playing etc. then that's all we need to do
//
if ( m_transportStatus ! = PLAYING & &
m_transportStatus ! = RECORDING )
return ;
RealTime newPosition = m_driver - > getSequencerTime ( ) ;
// Go around the loop if we've reached the end
//
if ( isLooping ( ) & & newPosition > = m_loopEnd ) {
RealTime oldPosition = m_songPosition ;
// Remove the loop width from the song position and send
// this position to the GUI
//
newPosition = m_songPosition = m_lastFetchSongPosition = m_loopStart ;
m_driver - > stopClocks ( ) ;
// Reset playback using this jump
//
m_driver - > resetPlayback ( oldPosition , m_songPosition ) ;
m_mC . clear ( ) ;
fetchEvents ( m_mC , m_songPosition , m_songPosition + m_readAhead , true ) ;
m_driver - > processEventsOut ( m_mC , m_songPosition , m_songPosition + m_readAhead ) ;
m_driver - > startClocks ( ) ;
} else {
m_songPosition = newPosition ;
if ( m_songPosition < = m_driver - > getStartPosition ( ) )
newPosition = m_driver - > getStartPosition ( ) ;
}
RealTime maxLatency = m_driver - > getMaximumPlayLatency ( ) ;
if ( maxLatency ! = RealTime : : zeroTime ) {
// std::cerr << "RosegardenSequencerApp::updateClocks: latency compensation moving " << newPosition << " to " << newPosition - maxLatency << std::endl;
newPosition = newPosition - maxLatency ;
}
// Remap the position pointer
//
m_sequencerMapper . updatePositionPointer ( newPosition ) ;
}
void
RosegardenSequencerApp : : notifySequencerStatus ( )
{
TQByteArray data , replyData ;
TQCString replyType ;
TQDataStream arg ( data , IO_WriteOnly ) ;
arg < < ( int ) m_transportStatus ;
if ( ! kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" notifySequencerStatus(int) " ,
data ) ) {
SEQUENCER_DEBUG < < " RosegardenSequencer::notifySequencerStatus() "
< < " - can't send to RosegardenGUI client "
< < endl ;
// Stop the sequencer
//
stop ( ) ;
}
}
void
RosegardenSequencerApp : : sleep ( const RealTime & rt )
{
m_driver - > sleep ( rt ) ;
}
// Sets the Sequencer object and this object to the new time
// from where playback can continue.
//
void
RosegardenSequencerApp : : jumpTo ( long posSec , long posNsec )
{
SEQUENCER_DEBUG < < " RosegardenSequencerApp::jumpTo( " < < posSec < < " , " < < posNsec < < " ) \n " ;
if ( posSec < 0 & & posNsec < 0 )
return ;
m_driver - > stopClocks ( ) ;
RealTime oldPosition = m_songPosition ;
m_songPosition = m_lastFetchSongPosition = RealTime ( posSec , posNsec ) ;
if ( m_sequencerMapper . getSequencerDataBlock ( ) ) {
m_sequencerMapper . getSequencerDataBlock ( ) - > setPositionPointer
( m_songPosition ) ;
}
m_driver - > resetPlayback ( oldPosition , m_songPosition ) ;
if ( m_driver - > isPlaying ( ) ) {
// Now prebuffer as in startPlaying:
m_mC . clear ( ) ;
fetchEvents ( m_mC , m_songPosition , m_songPosition + m_readAhead , true ) ;
// process whether we need to or not as this also processes
// the audio queue for us
//
m_driver - > processEventsOut ( m_mC , m_songPosition , m_songPosition + m_readAhead ) ;
}
incrementTransportToken ( ) ;
// SEQUENCER_DEBUG << "RosegardenSequencerApp::jumpTo: pausing to simulate high-load environment" << endl;
// ::sleep(1);
m_driver - > startClocks ( ) ;
return ;
}
// Send the last recorded MIDI block
//
void
RosegardenSequencerApp : : processRecordedMidi ( )
{
MappedComposition * mC = m_driver - > getMappedComposition ( ) ;
if ( mC - > empty ( ) | | ! m_controlBlockMmapper )
return ;
applyFiltering ( mC , m_controlBlockMmapper - > getRecordFilter ( ) , false ) ;
m_sequencerMapper . updateRecordingBuffer ( mC ) ;
if ( m_controlBlockMmapper - > isMidiRoutingEnabled ( ) ) {
applyFiltering ( mC , m_controlBlockMmapper - > getThruFilter ( ) , true ) ;
routeEvents ( mC , false ) ;
}
}
void
RosegardenSequencerApp : : routeEvents ( MappedComposition * mC , bool useSelectedTrack )
{
InstrumentId instrumentId ;
if ( useSelectedTrack ) {
instrumentId = m_controlBlockMmapper - > getInstrumentForTrack
( m_controlBlockMmapper - > getSelectedTrack ( ) ) ;
for ( MappedComposition : : iterator i = mC - > begin ( ) ;
i ! = mC - > end ( ) ; + + i ) {
( * i ) - > setInstrument ( instrumentId ) ;
}
} else {
for ( MappedComposition : : iterator i = mC - > begin ( ) ;
i ! = mC - > end ( ) ; + + i ) {
instrumentId = m_controlBlockMmapper - > getInstrumentForEvent
( ( * i ) - > getRecordedDevice ( ) , ( * i ) - > getRecordedChannel ( ) ) ;
( * i ) - > setInstrument ( instrumentId ) ;
}
}
m_driver - > processEventsOut ( * mC ) ;
}
// Send an update
//
void
RosegardenSequencerApp : : processRecordedAudio ( )
{
// Nothing to do here: the recording time is sent back to the GUI
// in the sequencer mapper as a normal case.
}
// This method is called during STOPPED or PLAYING operations
// to mop up any async (unexpected) incoming MIDI or Audio events
// and forward them to the GUI for display
//
void
RosegardenSequencerApp : : processAsynchronousEvents ( )
{
if ( ! m_controlBlockMmapper ) {
// If the control block mmapper doesn't exist, we'll just
// return here. But we want to ensure we don't check again
// immediately, because we're probably waiting for the GUI to
// start up.
static bool lastChecked = false ;
static struct timeval lastCheckedAt ;
struct timeval tv ;
( void ) gettimeofday ( & tv , 0 ) ;
if ( lastChecked & &
tv . tv_sec = = lastCheckedAt . tv_sec ) {
lastCheckedAt = tv ;
return ;
}
lastChecked = true ;
lastCheckedAt = tv ;
try {
m_controlBlockMmapper = new ControlBlockMmapper ( KGlobal : : dirs ( ) - > resourceDirs ( " tmp " ) . last ( )
+ " /rosegarden_control_block " ) ;
} catch ( Exception e ) {
// Assume that the control block simply hasn't been
// created yet because the GUI's still starting up.
// If there's a real problem with the mmapper, it
// will show up in play() instead.
return ;
}
m_sequencerMapper . setControlBlock ( m_controlBlockMmapper - > getControlBlock ( ) ) ;
}
MappedComposition * mC = m_driver - > getMappedComposition ( ) ;
if ( mC - > empty ( ) ) {
m_driver - > processPending ( ) ;
return ;
}
// std::cerr << "processAsynchronousEvents: have " << mC->size() << " events" << std::endl;
TQByteArray data ;
TQDataStream arg ( data , IO_WriteOnly ) ;
arg < < mC ;
if ( m_controlBlockMmapper - > isMidiRoutingEnabled ( ) ) {
applyFiltering ( mC , m_controlBlockMmapper - > getThruFilter ( ) , true ) ;
routeEvents ( mC , true ) ;
}
// std::cerr << "processAsynchronousEvents: sent " << mC->size() << " events" << std::endl;
if ( ! kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" processAsynchronousMidi(MappedComposition) " , data ) ) {
SEQUENCER_DEBUG < < " RosegardenSequencer::processAsynchronousEvents() - "
< < " can't call RosegardenGUI client " < < endl ;
// Stop the sequencer so we can see if we can try again later
//
stop ( ) ;
}
// Process any pending events (Note Offs or Audio) as part of
// same procedure.
//
m_driver - > processPending ( ) ;
}
void
RosegardenSequencerApp : : applyFiltering ( MappedComposition * mC ,
MidiFilter filter ,
bool filterControlDevice )
{
for ( MappedComposition : : iterator i = mC - > begin ( ) ;
i ! = mC - > end ( ) ; ) { // increment in loop
MappedComposition : : iterator j = i ;
+ + j ;
if ( ( ( * i ) - > getType ( ) & filter ) | |
( filterControlDevice & & ( ( * i ) - > getRecordedDevice ( ) = =
Device : : CONTROL_DEVICE ) ) ) {
mC - > erase ( i ) ;
}
i = j ;
}
}
int
RosegardenSequencerApp : : record ( const RealTime & time ,
const RealTime & readAhead ,
const RealTime & audioMix ,
const RealTime & audioRead ,
const RealTime & audioWrite ,
long smallFileSize ,
long recordMode )
{
TransportStatus localRecordMode = ( TransportStatus ) recordMode ;
SEQUENCER_DEBUG < < " RosegardenSequencerApp::record - recordMode is " < < recordMode < < " , transport status is " < < m_transportStatus < < endl ;
// punch in recording
if ( m_transportStatus = = PLAYING ) {
if ( localRecordMode = = STARTING_TO_RECORD ) {
SEQUENCER_DEBUG < < " RosegardenSequencerApp::record: punching in " < < endl ;
localRecordMode = RECORDING ; // no need to start playback
}
}
// For audio recording we need to retrieve audio
// file names from the GUI
//
if ( localRecordMode = = STARTING_TO_RECORD | |
localRecordMode = = RECORDING ) {
SEQUENCER_DEBUG < < " RosegardenSequencerApp::record() "
< < " - starting to record " < < endl ;
TQValueVector < InstrumentId > armedInstruments ;
TQValueVector < TQString > audioFileNames ;
{
TQByteArray data , replyData ;
TQCString replyType ;
TQDataStream arg ( data , IO_WriteOnly ) ;
if ( ! kapp - > dcopClient ( ) - > call ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" getArmedInstruments() " ,
data , replyType , replyData , true ) ) {
SEQUENCER_DEBUG < < " RosegardenSequencer::record() "
< < " - can't call RosegardenGUI client for getArmedInstruments "
< < endl ;
}
TQDataStream reply ( replyData , IO_ReadOnly ) ;
if ( replyType = = " TQValueVector<InstrumentId> " ) {
reply > > armedInstruments ;
} else {
SEQUENCER_DEBUG < < " RosegardenSequencer::record() - "
< < " unrecognised type returned for getArmedInstruments " < < endl ;
}
}
TQValueVector < InstrumentId > audioInstruments ;
for ( unsigned int i = 0 ; i < armedInstruments . size ( ) ; + + i ) {
if ( armedInstruments [ i ] > = AudioInstrumentBase & &
armedInstruments [ i ] < MidiInstrumentBase ) {
audioInstruments . push_back ( armedInstruments [ i ] ) ;
}
}
if ( audioInstruments . size ( ) > 0 ) {
TQByteArray data , replyData ;
TQCString replyType ;
TQDataStream arg ( data , IO_WriteOnly ) ;
arg < < audioInstruments ;
if ( ! kapp - > dcopClient ( ) - > call ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" createRecordAudioFiles(TQValueVector<InstrumentId>) " ,
data , replyType , replyData , true ) ) {
SEQUENCER_DEBUG < < " RosegardenSequencer::record() "
< < " - can't call RosegardenGUI client for createNewAudioFiles "
< < endl ;
}
TQDataStream reply ( replyData , IO_ReadOnly ) ;
if ( replyType = = " TQValueVector<TQString> " ) {
reply > > audioFileNames ;
} else {
SEQUENCER_DEBUG < < " RosegardenSequencer::record() - "
< < " unrecognised type returned for createNewAudioFiles " < < endl ;
}
if ( audioFileNames . size ( ) ! = audioInstruments . size ( ) ) {
std : : cerr < < " ERROR: RosegardenSequencer::record(): Failed to create correct number of audio files (wanted " < < audioInstruments . size ( ) < < " , got " < < audioFileNames . size ( ) < < " ) " < < std : : endl ;
stop ( ) ;
return 0 ;
}
}
std : : vector < InstrumentId > armedInstrumentsVec ;
std : : vector < TQString > audioFileNamesVec ;
for ( int i = 0 ; i < armedInstruments . size ( ) ; + + i ) {
armedInstrumentsVec . push_back ( armedInstruments [ i ] ) ;
}
for ( int i = 0 ; i < audioFileNames . size ( ) ; + + i ) {
audioFileNamesVec . push_back ( audioFileNames [ i ] ) ;
}
// Get the Sequencer to prepare itself for recording - if
// this fails we stop.
//
if ( m_driver - > record ( RECORD_ON ,
& armedInstrumentsVec ,
& audioFileNamesVec ) = = false ) {
stop ( ) ;
return 0 ;
}
} else {
// unrecognised type - return a problem
return 0 ;
}
// Now set the local transport status to the record mode
//
//
m_transportStatus = localRecordMode ;
if ( localRecordMode = = RECORDING ) { // punch in
return 1 ;
} else {
// Ensure that playback is initialised
//
m_driver - > initialisePlayback ( m_songPosition ) ;
return play ( time , readAhead , audioMix , audioRead , audioWrite , smallFileSize ) ;
}
}
// We receive a starting time from the GUI which we use as the
// basis of our first fetch of events from the GUI core. Assuming
// this works we set our internal state to PLAYING and go ahead
// and play the piece until we get a signal to stop.
//
// DCOP wants us to use an int as a return type instead of a bool.
//
int
RosegardenSequencerApp : : play ( const RealTime & time ,
const RealTime & readAhead ,
const RealTime & audioMix ,
const RealTime & audioRead ,
const RealTime & audioWrite ,
long smallFileSize )
{
if ( m_transportStatus = = PLAYING | |
m_transportStatus = = STARTING_TO_PLAY )
return true ;
// Check for record toggle (punch out)
//
if ( m_transportStatus = = RECORDING ) {
m_transportStatus = PLAYING ;
return punchOut ( ) ;
}
// To play from the given song position sets up the internal
// play state to "STARTING_TO_PLAY" which is then caught in
// the main event loop
//
m_songPosition = time ;
if ( m_sequencerMapper . getSequencerDataBlock ( ) ) {
m_sequencerMapper . getSequencerDataBlock ( ) - > setPositionPointer
( m_songPosition ) ;
}
if ( m_transportStatus ! = RECORDING & &
m_transportStatus ! = STARTING_TO_RECORD ) {
m_transportStatus = STARTING_TO_PLAY ;
}
m_driver - > stopClocks ( ) ;
// Set up buffer size
//
m_readAhead = readAhead ;
if ( m_readAhead = = RealTime : : zeroTime )
m_readAhead . sec = 1 ;
m_audioMix = audioMix ;
m_audioRead = audioRead ;
m_audioWrite = audioWrite ;
m_smallFileSize = smallFileSize ;
m_driver - > setAudioBufferSizes ( m_audioMix , m_audioRead , m_audioWrite ,
m_smallFileSize ) ;
cleanupMmapData ( ) ;
// Map all segments
//
TQDir segmentsDir ( m_segmentFilesPath , " segment_* " ) ;
for ( unsigned int i = 0 ; i < segmentsDir . count ( ) ; + + i ) {
mmapSegment ( m_segmentFilesPath + " / " + segmentsDir [ i ] ) ;
}
TQString tmpDir = KGlobal : : dirs ( ) - > resourceDirs ( " tmp " ) . last ( ) ;
// Map metronome
//
TQString metronomeFileName = tmpDir + " /rosegarden_metronome " ;
TQFileInfo metronomeFileInfo ( metronomeFileName ) ;
if ( metronomeFileInfo . exists ( ) )
mmapSegment ( metronomeFileName ) ;
else
SEQUENCER_DEBUG < < " RosegardenSequencerApp::play() - no metronome found \n " ;
// Map tempo segment
//
TQString tempoSegmentFileName = tmpDir + " /rosegarden_tempo " ;
TQFileInfo tempoSegmentFileInfo ( tempoSegmentFileName ) ;
if ( tempoSegmentFileInfo . exists ( ) )
mmapSegment ( tempoSegmentFileName ) ;
else
SEQUENCER_DEBUG < < " RosegardenSequencerApp::play() - no tempo segment found \n " ;
// Map time sig segment
//
TQString timeSigSegmentFileName = tmpDir + " /rosegarden_timesig " ;
TQFileInfo timeSigSegmentFileInfo ( timeSigSegmentFileName ) ;
if ( timeSigSegmentFileInfo . exists ( ) )
mmapSegment ( timeSigSegmentFileName ) ;
else
SEQUENCER_DEBUG < < " RosegardenSequencerApp::play() - no time sig segment found \n " ;
// Map control block if necessary
//
if ( ! m_controlBlockMmapper ) {
m_controlBlockMmapper = new ControlBlockMmapper ( tmpDir + " /rosegarden_control_block " ) ;
m_sequencerMapper . setControlBlock ( m_controlBlockMmapper - > getControlBlock ( ) ) ;
}
initMetaIterator ( ) ;
// report
//
SEQUENCER_DEBUG < < " RosegardenSequencerApp::play() - starting to play \n " ;
// Test bits
// m_metaIterator = new MmappedSegmentsMetaIterator(m_mmappedSegments);
// MappedComposition testCompo;
// m_metaIterator->fillCompositionWithEventsUntil(&testCompo,
// RealTime(2,0));
// dumpFirstSegment();
// keep it simple
return true ;
}
int
RosegardenSequencerApp : : punchOut ( )
{
// Check for record toggle (punch out)
//
if ( m_transportStatus = = RECORDING ) {
m_driver - > punchOut ( ) ;
m_transportStatus = PLAYING ;
return true ;
}
return false ;
}
MmappedSegment * RosegardenSequencerApp : : mmapSegment ( const TQString & file )
{
MmappedSegment * m = 0 ;
try {
m = new MmappedSegment ( file ) ;
} catch ( Exception e ) {
SEQUENCER_DEBUG < < " RosegardenSequencerApp::mmapSegment() - couldn't map file " < < file
< < " : " < < e . getMessage ( ) . c_str ( ) < < endl ;
return 0 ;
}
m_mmappedSegments [ file ] = m ;
return m ;
}
void RosegardenSequencerApp : : initMetaIterator ( )
{
delete m_metaIterator ;
m_metaIterator = new MmappedSegmentsMetaIterator ( m_mmappedSegments , m_controlBlockMmapper ) ;
}
void RosegardenSequencerApp : : cleanupMmapData ( )
{
for ( MmappedSegmentsMetaIterator : : mmappedsegments : : iterator i =
m_mmappedSegments . begin ( ) ; i ! = m_mmappedSegments . end ( ) ; + + i )
delete i - > second ;
m_mmappedSegments . clear ( ) ;
delete m_metaIterator ;
m_metaIterator = 0 ;
}
void RosegardenSequencerApp : : remapSegment ( const TQString & filename , size_t newSize )
{
if ( m_transportStatus ! = PLAYING )
return ;
SEQUENCER_DEBUG < < " RosegardenSequencerApp::remapSegment( " < < filename < < " ) \n " ;
MmappedSegment * m = m_mmappedSegments [ filename ] ;
if ( m - > remap ( newSize ) & & m_metaIterator )
m_metaIterator - > resetIteratorForSegment ( filename ) ;
}
void RosegardenSequencerApp : : addSegment ( const TQString & filename )
{
if ( m_transportStatus ! = PLAYING )
return ;
SEQUENCER_DEBUG < < " MmappedSegment::addSegment( " < < filename < < " ) \n " ;
MmappedSegment * m = mmapSegment ( filename ) ;
if ( m_metaIterator )
m_metaIterator - > addSegment ( m ) ;
}
void RosegardenSequencerApp : : deleteSegment ( const TQString & filename )
{
if ( m_transportStatus ! = PLAYING )
return ;
SEQUENCER_DEBUG < < " MmappedSegment::deleteSegment( " < < filename < < " ) \n " ;
MmappedSegment * m = m_mmappedSegments [ filename ] ;
if ( m_metaIterator )
m_metaIterator - > deleteSegment ( m ) ;
delete m ;
// #932415
m_mmappedSegments . erase ( filename ) ;
}
void RosegardenSequencerApp : : closeAllSegments ( )
{
SEQUENCER_DEBUG < < " MmappedSegment::closeAllSegments() \n " ;
for ( MmappedSegmentsMetaIterator : : mmappedsegments : : iterator
i = m_mmappedSegments . begin ( ) ;
i ! = m_mmappedSegments . end ( ) ; + + i ) {
if ( m_metaIterator )
m_metaIterator - > deleteSegment ( i - > second ) ;
delete i - > second ;
}
m_mmappedSegments . clear ( ) ;
m_sequencerMapper . setControlBlock ( 0 ) ;
delete m_controlBlockMmapper ;
m_controlBlockMmapper = 0 ;
}
void RosegardenSequencerApp : : remapTracks ( )
{
// SEQUENCER_DEBUG << "RosegardenSequencerApp::remapTracks" << endl;
std : : cout < < " RosegardenSequencerApp::remapTracks " < < std : : endl ;
rationalisePlayingAudio ( ) ;
}
// DCOP Wrapper for play(RealTime,
// RealTime,
// RealTime)
//
//
int
RosegardenSequencerApp : : play ( long timeSec ,
long timeNSec ,
long readAheadSec ,
long readAheadNSec ,
long audioMixSec ,
long audioMixNsec ,
long audioReadSec ,
long audioReadNsec ,
long audioWriteSec ,
long audioWriteNsec ,
long smallFileSize )
{
return play ( RealTime ( timeSec , timeNSec ) ,
RealTime ( readAheadSec , readAheadNSec ) ,
RealTime ( audioMixSec , audioMixNsec ) ,
RealTime ( audioReadSec , audioReadNsec ) ,
RealTime ( audioWriteSec , audioWriteNsec ) ,
smallFileSize ) ;
}
// Wrapper for record(RealTime,
// RealTime,
// RealTime,
// recordMode);
//
//
int
RosegardenSequencerApp : : record ( long timeSec ,
long timeNSec ,
long readAheadSec ,
long readAheadNSec ,
long audioMixSec ,
long audioMixNsec ,
long audioReadSec ,
long audioReadNsec ,
long audioWriteSec ,
long audioWriteNsec ,
long smallFileSize ,
long recordMode )
{
return record ( RealTime ( timeSec , timeNSec ) ,
RealTime ( readAheadSec , readAheadNSec ) ,
RealTime ( audioMixSec , audioMixNsec ) ,
RealTime ( audioReadSec , audioReadNsec ) ,
RealTime ( audioWriteSec , audioWriteNsec ) ,
smallFileSize ,
recordMode ) ;
}
void
RosegardenSequencerApp : : setLoop ( const RealTime & loopStart ,
const RealTime & loopEnd )
{
m_loopStart = loopStart ;
m_loopEnd = loopEnd ;
m_driver - > setLoop ( loopStart , loopEnd ) ;
}
void
RosegardenSequencerApp : : setLoop ( long loopStartSec ,
long loopStartNSec ,
long loopEndSec ,
long loopEndNSec )
{
setLoop ( RealTime ( loopStartSec , loopStartNSec ) ,
RealTime ( loopEndSec , loopEndNSec ) ) ;
}
// Return the status of the sound systems (audio and MIDI)
//
unsigned int
RosegardenSequencerApp : : getSoundDriverStatus ( const TQString & guiVersion )
{
unsigned int driverStatus = m_driver - > getStatus ( ) ;
if ( guiVersion = = VERSION )
driverStatus | = VERSION_OK ;
else {
std : : cerr < < " WARNING: RosegardenSequencerApp::getSoundDriverStatus: "
< < " GUI version \" " < < guiVersion . ascii ( )
< < " \" does not match sequencer version \" " < < VERSION
< < " \" " < < std : : endl ;
}
return driverStatus ;
}
// Add an audio file to the sequencer
int
RosegardenSequencerApp : : addAudioFile ( const TQString & fileName , int id )
{
return ( ( int ) m_driver - > addAudioFile ( fileName . utf8 ( ) . data ( ) , id ) ) ;
}
int
RosegardenSequencerApp : : removeAudioFile ( int id )
{
return ( ( int ) m_driver - > removeAudioFile ( id ) ) ;
}
void
RosegardenSequencerApp : : clearAllAudioFiles ( )
{
m_driver - > clearAudioFiles ( ) ;
}
void
RosegardenSequencerApp : : setMappedInstrument ( int type , unsigned char channel ,
unsigned int id )
{
InstrumentId mID = ( InstrumentId ) id ;
Instrument : : InstrumentType mType =
( Instrument : : InstrumentType ) type ;
MidiByte mChannel = ( MidiByte ) channel ;
m_driver - > setMappedInstrument (
new MappedInstrument ( mType , mChannel , mID ) ) ;
}
// Process a MappedComposition sent from Sequencer with
// immediate effect
//
void
RosegardenSequencerApp : : processSequencerSlice ( MappedComposition mC )
{
// Use the "now" API
//
m_driver - > processEventsOut ( mC ) ;
}
void
RosegardenSequencerApp : : processMappedEvent ( unsigned int id ,
int type ,
unsigned char pitch ,
unsigned char velocity ,
long absTimeSec ,
long absTimeNsec ,
long durationSec ,
long durationNsec ,
long audioStartMarkerSec ,
long audioStartMarkerNSec )
{
MappedEvent * mE =
new MappedEvent (
( InstrumentId ) id ,
( MappedEvent : : MappedEventType ) type ,
( MidiByte ) pitch ,
( MidiByte ) velocity ,
RealTime ( absTimeSec , absTimeNsec ) ,
RealTime ( durationSec , durationNsec ) ,
RealTime ( audioStartMarkerSec , audioStartMarkerNSec ) ) ;
MappedComposition mC ;
// SEQUENCER_DEBUG << "processMappedEvent(data) - sending out single event at time " << mE->getEventTime() << endl;
/*
std : : cout < < " ID = " < < mE - > getInstrument ( ) < < std : : endl ;
std : : cout < < " TYPE = " < < mE - > getType ( ) < < std : : endl ;
std : : cout < < " D1 = " < < ( int ) mE - > getData1 ( ) < < std : : endl ;
std : : cout < < " D2 = " < < ( int ) mE - > getData2 ( ) < < std : : endl ;
*/
mC . insert ( mE ) ;
m_driver - > processEventsOut ( mC ) ;
}
void
RosegardenSequencerApp : : processMappedEvent ( MappedEvent mE )
{
MappedComposition mC ;
mC . insert ( new MappedEvent ( mE ) ) ;
SEQUENCER_DEBUG < < " processMappedEvent(ev) - sending out single event at time " < < mE . getEventTime ( ) < < endl ;
m_driver - > processEventsOut ( mC ) ;
}
// Get the MappedDevice (DCOP wrapped vector of MappedInstruments)
//
MappedDevice
RosegardenSequencerApp : : getMappedDevice ( unsigned int id )
{
return m_driver - > getMappedDevice ( id ) ;
}
unsigned int
RosegardenSequencerApp : : getDevices ( )
{
return m_driver - > getDevices ( ) ;
}
int
RosegardenSequencerApp : : canReconnect ( int type )
{
return m_driver - > canReconnect ( ( Device : : DeviceType ) type ) ;
}
unsigned int
RosegardenSequencerApp : : addDevice ( int type , unsigned int direction )
{
return m_driver - > addDevice ( ( Device : : DeviceType ) type ,
( MidiDevice : : DeviceDirection ) direction ) ;
}
void
RosegardenSequencerApp : : removeDevice ( unsigned int deviceId )
{
m_driver - > removeDevice ( deviceId ) ;
}
void
RosegardenSequencerApp : : renameDevice ( unsigned int deviceId , TQString name )
{
m_driver - > renameDevice ( deviceId , name ) ;
}
unsigned int
RosegardenSequencerApp : : getConnections ( int type , unsigned int direction )
{
return m_driver - > getConnections ( ( Device : : DeviceType ) type ,
( MidiDevice : : DeviceDirection ) direction ) ;
}
TQString
RosegardenSequencerApp : : getConnection ( int type , unsigned int direction ,
unsigned int connectionNo )
{
return m_driver - > getConnection ( ( Device : : DeviceType ) type ,
( MidiDevice : : DeviceDirection ) direction ,
connectionNo ) ;
}
void
RosegardenSequencerApp : : setConnection ( unsigned int deviceId ,
TQString connection )
{
m_driver - > setConnection ( deviceId , connection ) ;
}
void
RosegardenSequencerApp : : setPlausibleConnection ( unsigned int deviceId ,
TQString connection )
{
m_driver - > setPlausibleConnection ( deviceId , connection ) ;
}
unsigned int
RosegardenSequencerApp : : getTimers ( )
{
return m_driver - > getTimers ( ) ;
}
TQString
RosegardenSequencerApp : : getTimer ( unsigned int n )
{
return m_driver - > getTimer ( n ) ;
}
TQString
RosegardenSequencerApp : : getCurrentTimer ( )
{
return m_driver - > getCurrentTimer ( ) ;
}
void
RosegardenSequencerApp : : setCurrentTimer ( TQString timer )
{
m_driver - > setCurrentTimer ( timer ) ;
}
void
RosegardenSequencerApp : : setLowLatencyMode ( bool ll )
{
m_driver - > setLowLatencyMode ( ll ) ;
}
void
RosegardenSequencerApp : : sequencerAlive ( )
{
if ( ! kapp - > dcopClient ( ) - >
isApplicationRegistered ( TQCString ( ROSEGARDEN_GUI_APP_NAME ) ) ) {
SEQUENCER_DEBUG < < " RosegardenSequencerApp::sequencerAlive() - "
< < " waiting for GUI to register " < < endl ;
return ;
}
TQByteArray data ;
if ( ! kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" alive() " ,
data ) ) {
SEQUENCER_DEBUG < < " RosegardenSequencer::alive() "
< < " - can't call RosegardenGUI client "
< < endl ;
}
SEQUENCER_DEBUG < < " RosegardenSequencerApp::sequencerAlive() - "
< < " trying to tell GUI that we're alive " < < endl ;
}
MappedRealTime
RosegardenSequencerApp : : getAudioPlayLatency ( )
{
return MappedRealTime ( m_driver - > getAudioPlayLatency ( ) ) ;
}
MappedRealTime
RosegardenSequencerApp : : getAudioRecordLatency ( )
{
return MappedRealTime ( m_driver - > getAudioRecordLatency ( ) ) ;
}
// Initialise the virtual studio with a few audio faders and
// create a plugin manager. For the moment this is pretty
// arbitrary but eventually we'll drive this from the gui
// and rg file "Studio" entries.
//
void
RosegardenSequencerApp : : initialiseStudio ( )
{
// clear down the studio before we start adding anything
//
m_studio - > clear ( ) ;
}
void
RosegardenSequencerApp : : setMappedProperty ( int id ,
const TQString & property ,
float value )
{
// SEQUENCER_DEBUG << "setProperty: id = " << id
// << " : property = \"" << property << "\""
// << ", value = " << value << endl;
MappedObject * object = m_studio - > getObjectById ( id ) ;
if ( object )
object - > setProperty ( property , value ) ;
}
void
RosegardenSequencerApp : : setMappedProperties ( const MappedObjectIdList & ids ,
const MappedObjectPropertyList & properties ,
const MappedObjectValueList & values )
{
MappedObject * object = 0 ;
MappedObjectId prevId = 0 ;
for ( size_t i = 0 ;
i < ids . size ( ) & & i < properties . size ( ) & & i < values . size ( ) ;
+ + i ) {
if ( i = = 0 | | ids [ i ] ! = prevId ) {
object = m_studio - > getObjectById ( ids [ i ] ) ;
prevId = ids [ i ] ;
}
if ( object ) {
object - > setProperty ( properties [ i ] , values [ i ] ) ;
}
}
}
void
RosegardenSequencerApp : : setMappedProperty ( int id ,
const TQString & property ,
const TQString & value )
{
SEQUENCER_DEBUG < < " setProperty: id = " < < id
< < " : property = \" " < < property < < " \" "
< < " , value = " < < value < < endl ;
MappedObject * object = m_studio - > getObjectById ( id ) ;
if ( object )
object - > setProperty ( property , value ) ;
}
void
RosegardenSequencerApp : : setMappedPropertyList ( int id , const TQString & property ,
const MappedObjectPropertyList & values )
{
SEQUENCER_DEBUG < < " setPropertyList: id = " < < id
< < " : property list size = \" " < < values . size ( )
< < " \" " < < endl ;
MappedObject * object = m_studio - > getObjectById ( id ) ;
if ( object ) {
try {
object - > setPropertyList ( property , values ) ;
} catch ( TQString err ) {
TQByteArray data ;
TQDataStream arg ( data , IO_WriteOnly ) ;
arg < < err ;
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" showError(TQString) " ,
data ) ;
}
}
}
int
RosegardenSequencerApp : : getMappedObjectId ( int type )
{
int value = - 1 ;
MappedObject * object =
m_studio - > getObjectOfType (
MappedObject : : MappedObjectType ( type ) ) ;
if ( object ) {
value = int ( object - > getId ( ) ) ;
}
return value ;
}
std : : vector < TQString >
RosegardenSequencerApp : : getPropertyList ( int id ,
const TQString & property )
{
std : : vector < TQString > list ;
MappedObject * object =
m_studio - > getObjectById ( id ) ;
if ( object ) {
list = object - > getPropertyList ( property ) ;
}
SEQUENCER_DEBUG < < " getPropertyList - return " < < list . size ( )
< < " items " < < endl ;
return list ;
}
std : : vector < TQString >
RosegardenSequencerApp : : getPluginInformation ( )
{
std : : vector < TQString > list ;
PluginFactory : : enumerateAllPlugins ( list ) ;
return list ;
}
TQString
RosegardenSequencerApp : : getPluginProgram ( int id , int bank , int program )
{
MappedObject * object = m_studio - > getObjectById ( id ) ;
if ( object ) {
MappedPluginSlot * slot =
dynamic_cast < MappedPluginSlot * > ( object ) ;
if ( slot ) {
return slot - > getProgram ( bank , program ) ;
}
}
return TQString ( ) ;
}
unsigned long
RosegardenSequencerApp : : getPluginProgram ( int id , const TQString & name )
{
MappedObject * object = m_studio - > getObjectById ( id ) ;
if ( object ) {
MappedPluginSlot * slot =
dynamic_cast < MappedPluginSlot * > ( object ) ;
if ( slot ) {
return slot - > getProgram ( name ) ;
}
}
return 0 ;
}
unsigned int
RosegardenSequencerApp : : getSampleRate ( ) const
{
if ( m_driver )
return m_driver - > getSampleRate ( ) ;
return 0 ;
}
// Creates an object of a type
//
int
RosegardenSequencerApp : : createMappedObject ( int type )
{
MappedObject * object =
m_studio - > createObject (
MappedObject : : MappedObjectType ( type ) ) ;
if ( object ) {
SEQUENCER_DEBUG < < " createMappedObject - type = "
< < type < < " , object id = "
< < object - > getId ( ) < < endl ;
return object - > getId ( ) ;
}
return 0 ;
}
// Destroy an object
//
int
RosegardenSequencerApp : : destroyMappedObject ( int id )
{
return ( int ( m_studio - > destroyObject ( MappedObjectId ( id ) ) ) ) ;
}
// Connect two objects
//
void
RosegardenSequencerApp : : connectMappedObjects ( int id1 , int id2 )
{
m_studio - > connectObjects ( MappedObjectId ( id1 ) ,
MappedObjectId ( id2 ) ) ;
// When this happens we need to resynchronise our audio processing,
// and this is the easiest (and most brutal) way to do it.
if ( m_transportStatus = = PLAYING | |
m_transportStatus = = RECORDING ) {
RealTime seqTime = m_driver - > getSequencerTime ( ) ;
jumpTo ( seqTime . sec , seqTime . nsec ) ;
}
}
// Disconnect two objects
//
void
RosegardenSequencerApp : : disconnectMappedObjects ( int id1 , int id2 )
{
m_studio - > disconnectObjects ( MappedObjectId ( id1 ) ,
MappedObjectId ( id2 ) ) ;
}
// Disconnect an object from everything
//
void
RosegardenSequencerApp : : disconnectMappedObject ( int id )
{
m_studio - > disconnectObject ( MappedObjectId ( id ) ) ;
}
void
RosegardenSequencerApp : : clearStudio ( )
{
SEQUENCER_DEBUG < < " clearStudio() " < < endl ;
m_studio - > clear ( ) ;
m_sequencerMapper . getSequencerDataBlock ( ) - > clearTemporaries ( ) ;
}
void
RosegardenSequencerApp : : setMappedPort ( int pluginId ,
unsigned long portId ,
float value )
{
MappedObject * object =
m_studio - > getObjectById ( pluginId ) ;
MappedPluginSlot * slot =
dynamic_cast < MappedPluginSlot * > ( object ) ;
if ( slot ) {
slot - > setPort ( portId , value ) ;
} else {
SEQUENCER_DEBUG < < " no such slot " < < endl ;
}
}
float
RosegardenSequencerApp : : getMappedPort ( int pluginId ,
unsigned long portId )
{
MappedObject * object =
m_studio - > getObjectById ( pluginId ) ;
MappedPluginSlot * slot =
dynamic_cast < MappedPluginSlot * > ( object ) ;
if ( slot ) {
return slot - > getPort ( portId ) ;
} else {
SEQUENCER_DEBUG < < " no such slot " < < endl ;
}
return 0 ;
}
void
RosegardenSequencerApp : : slotCheckForNewClients ( )
{
// Don't do this check if any of these conditions hold
//
if ( m_transportStatus = = PLAYING | |
m_transportStatus = = RECORDING )
return ;
if ( m_driver - > checkForNewClients ( ) ) {
SEQUENCER_DEBUG < < " client list changed " < < endl ;
}
}
// Set the MIDI Clock period in microseconds
//
void
RosegardenSequencerApp : : setQuarterNoteLength ( long timeSec , long timeNSec )
{
SEQUENCER_DEBUG < < " RosegardenSequencerApp::setQuarterNoteLength "
< < RealTime ( timeSec , timeNSec ) < < endl ;
m_driver - > setMIDIClockInterval (
RealTime ( timeSec , timeNSec ) / 24 ) ;
}
TQString
RosegardenSequencerApp : : getStatusLog ( )
{
return m_driver - > getStatusLog ( ) ;
}
void RosegardenSequencerApp : : dumpFirstSegment ( )
{
SEQUENCER_DEBUG < < " Dumping 1st segment data : \n " ;
unsigned int i = 0 ;
MmappedSegment * firstMappedSegment = ( * ( m_mmappedSegments . begin ( ) ) ) . second ;
MmappedSegment : : iterator it ( firstMappedSegment ) ;
for ( ; ! it . atEnd ( ) ; + + it ) {
MappedEvent evt = ( * it ) ;
SEQUENCER_DEBUG < < i < < " : inst = " < < evt . getInstrument ( )
< < " - type = " < < evt . getType ( )
< < " - data1 = " < < ( unsigned int ) evt . getData1 ( )
< < " - data2 = " < < ( unsigned int ) evt . getData2 ( )
< < " - time = " < < evt . getEventTime ( )
< < " - duration = " < < evt . getDuration ( )
< < " - audio mark = " < < evt . getAudioStartMarker ( )
< < endl ;
+ + i ;
}
SEQUENCER_DEBUG < < " Dumping 1st segment data - done \n " ;
}
void
RosegardenSequencerApp : : rationalisePlayingAudio ( )
{
std : : vector < MappedEvent > audioEvents ;
m_metaIterator - > getAudioEvents ( audioEvents ) ;
m_driver - > initialiseAudioQueue ( audioEvents ) ;
}
ExternalTransport : : TransportToken
RosegardenSequencerApp : : transportChange ( TransportRequest request )
{
TransportPair pair ( request , RealTime : : zeroTime ) ;
m_transportRequests . push_back ( pair ) ;
std : : cout < < " RosegardenSequencerApp::transportChange: " < < request < < std : : endl ;
if ( request = = TransportNoChange )
return m_transportToken ;
else
return m_transportToken + 1 ;
}
ExternalTransport : : TransportToken
RosegardenSequencerApp : : transportJump ( TransportRequest request ,
RealTime rt )
{
TransportPair pair ( request , rt ) ;
m_transportRequests . push_back ( pair ) ;
std : : cout < < " RosegardenSequencerApp::transportJump: " < < request < < " , " < < rt < < std : : endl ;
if ( request = = TransportNoChange )
return m_transportToken + 1 ;
else
return m_transportToken + 2 ;
}
bool
RosegardenSequencerApp : : isTransportSyncComplete ( TransportToken token )
{
std : : cout < < " RosegardenSequencerApp::isTransportSyncComplete: token " < < token < < " , current token " < < m_transportToken < < std : : endl ;
return m_transportToken > = token ;
}
bool
RosegardenSequencerApp : : checkExternalTransport ( )
{
bool rv = ( ! m_transportRequests . empty ( ) ) ;
while ( ! m_transportRequests . empty ( ) ) {
TransportPair pair = * m_transportRequests . begin ( ) ;
m_transportRequests . pop_front ( ) ;
TQByteArray data ;
switch ( pair . first ) {
case TransportNoChange :
break ;
case TransportStop :
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" stop() " ,
data ) ;
break ;
case TransportStart :
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" play() " ,
data ) ;
break ;
case TransportPlay :
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" play() " ,
data ) ;
break ;
case TransportRecord :
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" record() " ,
data ) ;
break ;
case TransportJumpToTime : {
TQDataStream arg ( data , IO_WriteOnly ) ;
arg < < ( int ) pair . second . sec ;
arg < < ( int ) pair . second . usec ( ) ;
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" jumpToTime(int, int) " ,
data ) ;
if ( m_transportStatus = = PLAYING | |
m_transportStatus ! = RECORDING ) {
jumpTo ( pair . second . sec , pair . second . usec ( ) * 1000 ) ;
}
incrementTransportToken ( ) ;
break ;
}
case TransportStartAtTime : {
TQDataStream arg ( data , IO_WriteOnly ) ;
arg < < ( int ) pair . second . sec ;
arg < < ( int ) pair . second . usec ( ) ;
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" startAtTime(int, int) " ,
data ) ;
break ;
}
case TransportStopAtTime : {
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" stop() " ,
data ) ;
TQDataStream arg ( data , IO_WriteOnly ) ;
arg < < ( int ) pair . second . sec ;
arg < < ( int ) pair . second . usec ( ) ;
kapp - > dcopClient ( ) - > send ( ROSEGARDEN_GUI_APP_NAME ,
ROSEGARDEN_GUI_IFACE_NAME ,
" jumpToTime(int, int) " ,
data ) ;
break ;
}
}
}
return rv ;
}
void
RosegardenSequencerApp : : incrementTransportToken ( )
{
+ + m_transportToken ;
SEQUENCER_DEBUG < < " RosegardenSequencerApp::incrementTransportToken: incrementing to " < < m_transportToken < < endl ;
}
}
# include "RosegardenSequencerApp.moc"