2012-05-26 14:49:10 +02:00
//=============================================================================
// MuseScore
// Linux Music Score Editor
// $Id: seq.cpp 5660 2012-05-22 14:17:39Z wschweer $
//
// Copyright (C) 2002-2011 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
# include "config.h"
# include "seq.h"
# include "musescore.h"
2013-04-02 20:46:07 +02:00
# include "synthesizer/msynthesizer.h"
2012-05-26 14:49:10 +02:00
# include "libmscore/slur.h"
2013-08-22 12:18:14 +02:00
# include "libmscore/tie.h"
2012-05-26 14:49:10 +02:00
# include "libmscore/score.h"
# include "libmscore/segment.h"
# include "libmscore/note.h"
# include "libmscore/chord.h"
# include "libmscore/tempo.h"
# include "scoreview.h"
# include "playpanel.h"
# include "libmscore/staff.h"
# include "libmscore/measure.h"
# include "preferences.h"
# include "libmscore/part.h"
# include "libmscore/ottava.h"
# include "libmscore/utils.h"
# include "libmscore/repeatlist.h"
# include "libmscore/audio.h"
# include "synthcontrol.h"
# include "pianoroll.h"
2015-04-01 17:18:09 +02:00
# include "pianotools.h"
2012-05-26 14:49:10 +02:00
# include "click.h"
# include <vorbis/vorbisfile.h>
2018-04-02 01:35:20 +02:00
# ifdef USE_PORTMIDI
2017-05-14 17:43:28 +02:00
# if defined(Q_OS_MAC) || defined(Q_OS_WIN)
# include "portmidi/porttime/porttime.h"
# else
# include <porttime.h>
# endif
2018-04-02 01:35:20 +02:00
# endif
2017-05-14 17:43:28 +02:00
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:49:10 +02:00
Seq * seq ;
static const int guiRefresh = 10 ; // Hz
static const int peakHoldTime = 1400 ; // msec
static const int peakHold = ( peakHoldTime * guiRefresh ) / 1000 ;
static OggVorbis_File vf ;
2014-06-17 14:35:16 +02:00
#if 0 // yet(?) unused
2012-05-26 14:49:10 +02:00
static const int AUDIO_BUFFER_SIZE = 1024 * 512 ; // 2 MB
2014-06-17 14:35:16 +02:00
# endif
2013-10-26 12:40:58 +02:00
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// VorbisData
//---------------------------------------------------------
struct VorbisData {
int pos ; // current position in audio->data()
QByteArray data ;
} ;
static VorbisData vorbisData ;
static size_t ovRead ( void * ptr , size_t size , size_t nmemb , void * datasource ) ;
static int ovSeek ( void * datasource , ogg_int64_t offset , int whence ) ;
static long ovTell ( void * datasource ) ;
static ov_callbacks ovCallbacks = {
ovRead , ovSeek , 0 , ovTell
} ;
//---------------------------------------------------------
// ovRead
//---------------------------------------------------------
static size_t ovRead ( void * ptr , size_t size , size_t nmemb , void * datasource )
{
VorbisData * vd = ( VorbisData * ) datasource ;
size_t n = size * nmemb ;
if ( vd - > data . size ( ) < int ( vd - > pos + n ) )
n = vd - > data . size ( ) - vd - > pos ;
if ( n ) {
const char * src = vd - > data . data ( ) + vd - > pos ;
memcpy ( ptr , src , n ) ;
vd - > pos + = n ;
}
return n ;
}
//---------------------------------------------------------
// ovSeek
//---------------------------------------------------------
static int ovSeek ( void * datasource , ogg_int64_t offset , int whence )
{
VorbisData * vd = ( VorbisData * ) datasource ;
switch ( whence ) {
case SEEK_SET :
vd - > pos = offset ;
break ;
case SEEK_CUR :
vd - > pos + = offset ;
break ;
case SEEK_END :
vd - > pos = vd - > data . size ( ) - offset ;
break ;
}
return 0 ;
}
//---------------------------------------------------------
// ovTell
//---------------------------------------------------------
static long ovTell ( void * datasource )
{
VorbisData * vd = ( VorbisData * ) datasource ;
return vd - > pos ;
}
//---------------------------------------------------------
// Seq
//---------------------------------------------------------
Seq : : Seq ( )
{
running = false ;
playlistChanged = false ;
cs = 0 ;
cv = 0 ;
2016-08-08 17:46:56 +02:00
tackRemain = 0 ;
tickRemain = 0 ;
2014-07-25 19:29:22 +02:00
maxMidiOutPort = 0 ;
2012-05-26 14:49:10 +02:00
2017-05-14 17:43:28 +02:00
endUTick = 0 ;
2014-06-03 17:14:35 +02:00
state = Transport : : STOP ;
2012-05-26 14:49:10 +02:00
oggInit = false ;
2013-04-02 20:46:07 +02:00
_driver = 0 ;
2013-04-08 10:31:17 +02:00
playPos = events . cbegin ( ) ;
2017-05-14 17:43:28 +02:00
playFrame = 0 ;
2012-05-26 14:49:10 +02:00
metronomeVolume = 0.3 ;
2014-07-07 17:31:41 +02:00
useJackTransportSavedFlag = false ;
2012-05-26 14:49:10 +02:00
2013-10-15 09:36:17 +02:00
inCountIn = false ;
countInPlayPos = countInEvents . cbegin ( ) ;
2017-05-14 17:43:28 +02:00
countInPlayFrame = 0 ;
2013-10-15 09:36:17 +02:00
2012-05-26 14:49:10 +02:00
meterValue [ 0 ] = 0.0 ;
meterValue [ 1 ] = 0.0 ;
meterPeakValue [ 0 ] = 0.0 ;
meterPeakValue [ 1 ] = 0.0 ;
peakTimer [ 0 ] = 0 ;
peakTimer [ 1 ] = 0 ;
heartBeatTimer = new QTimer ( this ) ;
2013-05-03 11:37:28 +02:00
connect ( heartBeatTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( heartBeatTimeout ( ) ) ) ;
2012-05-26 14:49:10 +02:00
noteTimer = new QTimer ( this ) ;
noteTimer - > setSingleShot ( true ) ;
connect ( noteTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( stopNotes ( ) ) ) ;
noteTimer - > stop ( ) ;
2014-07-07 17:31:41 +02:00
connect ( this , SIGNAL ( toGui ( int , int ) ) , this , SLOT ( seqMessage ( int , int ) ) , Qt : : QueuedConnection ) ;
2014-05-30 23:18:52 +02:00
prevTimeSig . setNumerator ( 0 ) ;
prevTempo = 0 ;
connect ( this , SIGNAL ( timeSigChanged ( ) ) , this , SLOT ( handleTimeSigTempoChanged ( ) ) ) ;
connect ( this , SIGNAL ( tempoChanged ( ) ) , this , SLOT ( handleTimeSigTempoChanged ( ) ) ) ;
2017-05-14 17:43:28 +02:00
initialMillisecondTimestampWithLatency = 0 ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// Seq
//---------------------------------------------------------
Seq : : ~ Seq ( )
{
2013-04-02 20:46:07 +02:00
delete _driver ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// setScoreView
//---------------------------------------------------------
void Seq : : setScoreView ( ScoreView * v )
{
if ( oggInit ) {
ov_clear ( & vf ) ;
oggInit = false ;
}
if ( cv ! = v & & cs ) {
2013-02-20 17:53:15 +01:00
unmarkNotes ( ) ;
2012-05-26 14:49:10 +02:00
stopWait ( ) ;
}
cv = v ;
2014-04-02 10:49:54 +02:00
if ( cs )
disconnect ( cs , SIGNAL ( playlistChanged ( ) ) , this , SLOT ( setPlaylistChanged ( ) ) ) ;
2016-03-11 12:18:46 +01:00
cs = cv ? cv - > score ( ) - > masterScore ( ) : 0 ;
2012-05-26 14:49:10 +02:00
if ( ! heartBeatTimer - > isActive ( ) )
2013-08-09 07:17:57 +02:00
heartBeatTimer - > start ( 20 ) ; // msec
2012-05-26 14:49:10 +02:00
playlistChanged = true ;
2013-04-02 20:46:07 +02:00
_synti - > reset ( ) ;
2014-04-02 10:49:54 +02:00
if ( cs ) {
2012-05-26 14:49:10 +02:00
initInstruments ( ) ;
2014-04-02 10:49:54 +02:00
connect ( cs , SIGNAL ( playlistChanged ( ) ) , this , SLOT ( setPlaylistChanged ( ) ) ) ;
}
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// init
// return false on error
//---------------------------------------------------------
2014-07-30 15:38:54 +02:00
bool Seq : : init ( bool hotPlug )
2012-05-26 14:49:10 +02:00
{
2014-07-30 15:38:54 +02:00
if ( ! _driver | | ! _driver - > start ( hotPlug ) ) {
2012-05-26 14:49:10 +02:00
qDebug ( " Cannot start I/O " ) ;
2014-10-11 15:32:34 +02:00
running = false ;
2012-05-26 14:49:10 +02:00
return false ;
}
running = true ;
return true ;
}
//---------------------------------------------------------
// exit
//---------------------------------------------------------
void Seq : : exit ( )
{
2013-04-02 20:46:07 +02:00
if ( _driver ) {
2012-05-26 14:49:10 +02:00
if ( MScore : : debugMode )
2014-03-25 13:33:47 +01:00
qDebug ( " Stop I/O " ) ;
2012-05-26 14:49:10 +02:00
stopWait ( ) ;
2013-04-02 20:46:07 +02:00
delete _driver ;
_driver = 0 ;
2012-05-26 14:49:10 +02:00
}
}
//---------------------------------------------------------
// rewindStart
//---------------------------------------------------------
void Seq : : rewindStart ( )
{
seek ( 0 ) ;
}
2013-08-08 11:38:32 +02:00
2013-08-13 05:01:38 +02:00
//---------------------------------------------------------
// loopStart
//---------------------------------------------------------
void Seq : : loopStart ( )
{
start ( ) ;
2014-03-25 13:33:47 +01:00
// qDebug("LoopStart. playPos = %d", playPos);
2013-08-13 05:01:38 +02:00
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// canStart
// return true if sequencer can be started
//---------------------------------------------------------
bool Seq : : canStart ( )
{
2013-04-02 20:46:07 +02:00
if ( ! _driver )
2012-05-26 14:49:10 +02:00
return false ;
2014-04-02 10:49:54 +02:00
if ( playlistChanged )
2012-05-26 14:49:10 +02:00
collectEvents ( ) ;
2017-05-14 17:43:28 +02:00
return ( ! events . empty ( ) & & endUTick ! = 0 ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// start
// called from gui thread
//---------------------------------------------------------
void Seq : : start ( )
{
2017-05-14 17:43:28 +02:00
if ( ! _driver ) {
qDebug ( " No driver! " ) ;
return ;
}
2014-04-02 10:49:54 +02:00
if ( playlistChanged )
2012-05-26 14:49:10 +02:00
collectEvents ( ) ;
2014-05-30 10:16:38 +02:00
if ( cs - > playMode ( ) = = PlayMode : : AUDIO ) {
2012-05-26 14:49:10 +02:00
if ( ! oggInit ) {
vorbisData . pos = 0 ;
vorbisData . data = cs - > audio ( ) - > data ( ) ;
int n = ov_open_callbacks ( & vorbisData , & vf , 0 , 0 , ovCallbacks ) ;
if ( n < 0 ) {
2014-03-04 16:48:06 +01:00
qDebug ( " ogg open failed: %d " , n ) ;
2012-05-26 14:49:10 +02:00
}
oggInit = true ;
}
}
2013-08-22 18:29:25 +02:00
if ( ( mscore - > loop ( ) ) ) {
2014-07-07 17:31:41 +02:00
if ( cs - > selection ( ) . isRange ( ) )
2013-08-23 03:32:16 +02:00
setLoopSelection ( ) ;
2017-11-29 08:21:36 +01:00
if ( ! preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) | | ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) & & state = = Transport : : STOP ) )
2014-06-18 21:36:53 +02:00
seek ( cs - > repeatList ( ) - > tick2utick ( cs - > loopInTick ( ) ) ) ;
}
else {
2017-11-29 08:21:36 +01:00
if ( ! preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) | | ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) & & state = = Transport : : STOP ) )
2014-06-18 21:36:53 +02:00
seek ( cs - > repeatList ( ) - > tick2utick ( cs - > playPos ( ) ) ) ;
2014-07-07 17:31:41 +02:00
}
2017-11-29 08:21:36 +01:00
if ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) & & mscore - > countIn ( ) & & state = = Transport : : STOP ) {
2014-07-07 17:31:41 +02:00
// Ready to start playing count in, switching to fake transport
// to prevent playing in other applications with our ticks simultaneously
useJackTransportSavedFlag = true ;
2017-11-29 08:21:36 +01:00
preferences . setPreference ( PREF_IO_JACK_USEJACKTRANSPORT , false ) ;
2013-08-09 07:17:57 +02:00
}
2013-04-02 20:46:07 +02:00
_driver - > startTransport ( ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// stop
// called from gui thread
//---------------------------------------------------------
void Seq : : stop ( )
{
2014-06-03 17:14:35 +02:00
if ( state = = Transport : : STOP )
2012-05-26 14:49:10 +02:00
return ;
2014-05-30 23:18:52 +02:00
2012-05-26 14:49:10 +02:00
if ( oggInit ) {
ov_clear ( & vf ) ;
oggInit = false ;
}
2013-04-02 20:46:07 +02:00
if ( ! _driver )
2012-05-26 14:49:10 +02:00
return ;
2017-11-29 08:21:36 +01:00
if ( ! preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) | | ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) & & _driver - > getState ( ) = = Transport : : PLAY ) )
2014-06-18 21:36:53 +02:00
_driver - > stopTransport ( ) ;
2012-05-26 14:49:10 +02:00
if ( cv )
cv - > setCursorOn ( false ) ;
if ( cs ) {
2017-01-20 11:05:52 +01:00
//?? cs->setLayoutAll();
2012-05-26 14:49:10 +02:00
cs - > setUpdateAll ( ) ;
2016-04-18 18:11:51 +02:00
cs - > update ( ) ;
2012-05-26 14:49:10 +02:00
}
}
2013-04-29 19:42:38 +02:00
//---------------------------------------------------------
// stopWait
//---------------------------------------------------------
void Seq : : stopWait ( )
{
stop ( ) ;
QWaitCondition sleep ;
int idx = 0 ;
2014-06-03 17:14:35 +02:00
while ( state ! = Transport : : STOP ) {
2015-03-06 22:54:52 +01:00
qDebug ( " State %d " , ( int ) state ) ;
2013-04-29 19:42:38 +02:00
mutex . lock ( ) ;
sleep . wait ( & mutex , 100 ) ;
mutex . unlock ( ) ;
+ + idx ;
2014-03-04 13:06:23 +01:00
Q_ASSERT ( idx < = 10 ) ;
2013-04-29 19:42:38 +02:00
}
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// seqStarted
//---------------------------------------------------------
void MuseScore : : seqStarted ( )
{
2013-02-20 17:53:15 +01:00
if ( cv )
2012-05-26 14:49:10 +02:00
cv - > setCursorOn ( true ) ;
2013-02-20 17:53:15 +01:00
if ( cs )
2016-04-18 18:11:51 +02:00
cs - > update ( ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// seqStopped
// JACK has stopped
// executed in gui environment
//---------------------------------------------------------
void MuseScore : : seqStopped ( )
{
cv - > setCursorOn ( false ) ;
}
2013-02-20 17:53:15 +01:00
//---------------------------------------------------------
// unmarkNotes
//---------------------------------------------------------
void Seq : : unmarkNotes ( )
{
foreach ( const Note * n , markedNotes ) {
n - > setMark ( false ) ;
cs - > addRefresh ( n - > canvasBoundingRect ( ) ) ;
}
markedNotes . clear ( ) ;
2015-04-01 17:18:09 +02:00
PianoTools * piano = mscore - > pianoTools ( ) ;
if ( piano & & piano - > isVisible ( ) )
piano - > heartBeat ( markedNotes ) ;
2013-02-20 17:53:15 +01:00
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// guiStop
//---------------------------------------------------------
void Seq : : guiStop ( )
{
QAction * a = getAction ( " play " ) ;
a - > setChecked ( false ) ;
2013-02-20 17:53:15 +01:00
unmarkNotes ( ) ;
if ( ! cs )
2012-05-26 14:49:10 +02:00
return ;
2017-05-14 17:43:28 +02:00
cs - > setPlayPos ( cs - > repeatList ( ) - > utick2tick ( cs - > utime2utick ( qreal ( playFrame ) / qreal ( MScore : : sampleRate ) ) ) ) ;
2016-04-18 18:11:51 +02:00
cs - > update ( ) ;
2012-05-26 14:49:10 +02:00
emit stopped ( ) ;
}
//---------------------------------------------------------
// seqSignal
// sequencer message to GUI
// execution environment: gui thread
//---------------------------------------------------------
2014-07-07 17:31:41 +02:00
void Seq : : seqMessage ( int msg , int arg )
2012-05-26 14:49:10 +02:00
{
switch ( msg ) {
2014-07-07 17:31:41 +02:00
case ' 5 ' : {
// Update the screen after seeking from the realtime thread
Segment * seg = cs - > tick2segment ( arg ) ;
if ( seg )
mscore - > currentScoreView ( ) - > moveCursor ( seg - > tick ( ) ) ;
cs - > setPlayPos ( arg ) ;
2016-04-18 18:11:51 +02:00
cs - > update ( ) ;
2014-07-07 17:31:41 +02:00
break ;
}
2013-09-12 15:57:14 +02:00
case ' 4 ' : // Restart the playback at the end of the score
loopStart ( ) ;
break ;
2013-09-03 21:01:03 +02:00
case ' 3 ' : // Loop restart while playing
2013-09-13 00:21:01 +02:00
seek ( cs - > repeatList ( ) - > tick2utick ( cs - > loopInTick ( ) ) ) ;
2013-09-03 21:01:03 +02:00
break ;
2013-04-29 20:16:06 +02:00
case ' 2 ' :
2012-05-26 14:49:10 +02:00
guiStop ( ) ;
// heartBeatTimer->stop();
2013-04-02 20:46:07 +02:00
if ( _driver & & mscore - > getSynthControl ( ) ) {
2012-05-26 14:49:10 +02:00
meterValue [ 0 ] = .0f ;
meterValue [ 1 ] = .0f ;
meterPeakValue [ 0 ] = .0f ;
meterPeakValue [ 1 ] = .0f ;
peakTimer [ 0 ] = 0 ;
peakTimer [ 1 ] = 0 ;
mscore - > getSynthControl ( ) - > setMeter ( 0.0 , 0.0 , 0.0 , 0.0 ) ;
}
2013-04-29 19:42:38 +02:00
seek ( 0 ) ;
2012-05-26 14:49:10 +02:00
break ;
case ' 0 ' : // STOP
guiStop ( ) ;
// heartBeatTimer->stop();
2013-04-02 20:46:07 +02:00
if ( _driver & & mscore - > getSynthControl ( ) ) {
2012-05-26 14:49:10 +02:00
meterValue [ 0 ] = .0f ;
meterValue [ 1 ] = .0f ;
meterPeakValue [ 0 ] = .0f ;
meterPeakValue [ 1 ] = .0f ;
peakTimer [ 0 ] = 0 ;
peakTimer [ 1 ] = 0 ;
mscore - > getSynthControl ( ) - > setMeter ( 0.0 , 0.0 , 0.0 , 0.0 ) ;
}
break ;
case ' 1 ' : // PLAY
emit started ( ) ;
// heartBeatTimer->start(1000/guiRefresh);
break ;
default :
2014-03-25 13:33:47 +01:00
qDebug ( " MScore::Seq:: unknown seq msg %d " , msg ) ;
2012-05-26 14:49:10 +02:00
break ;
}
}
//---------------------------------------------------------
// playEvent
// send one event to the synthesizer
//---------------------------------------------------------
2014-07-29 16:31:44 +02:00
void Seq : : playEvent ( const NPlayEvent & event , unsigned framePos )
2012-05-26 14:49:10 +02:00
{
int type = event . type ( ) ;
if ( type = = ME_NOTEON ) {
2016-09-16 12:07:37 +02:00
bool mute = false ;
2012-05-26 14:49:10 +02:00
const Note * note = event . note ( ) ;
if ( note ) {
2016-09-16 12:07:37 +02:00
Staff * staff = note - > staff ( ) ;
Instrument * instr = staff - > part ( ) - > instrument ( note - > chord ( ) - > tick ( ) ) ;
2015-03-05 16:46:37 +01:00
const Channel * a = instr - > channel ( note - > subchannel ( ) ) ;
2016-09-16 12:07:37 +02:00
mute = a - > mute | | a - > soloMute | | ! staff - > playbackVoice ( note - > voice ( ) ) ;
2012-05-26 14:49:10 +02:00
}
if ( ! mute )
2014-07-29 16:31:44 +02:00
putEvent ( event , framePos ) ;
2012-05-26 14:49:10 +02:00
}
2015-06-01 19:49:48 +02:00
else if ( type = = ME_CONTROLLER | | type = = ME_PITCHBEND )
2014-07-29 16:31:44 +02:00
putEvent ( event , framePos ) ;
2012-05-26 14:49:10 +02:00
}
2014-07-25 19:29:22 +02:00
//---------------------------------------------------------
// recomputeMaxMidiOutPort
// Computes the maximum number of midi out ports
// in all opened scores
//---------------------------------------------------------
2016-03-11 12:18:46 +01:00
void Seq : : recomputeMaxMidiOutPort ( )
{
2017-11-29 08:21:36 +01:00
if ( ! ( preferences . getBool ( PREF_IO_JACK_USEJACKMIDI ) | | preferences . getBool ( PREF_IO_ALSA_USEALSAAUDIO ) ) )
2014-07-25 19:29:22 +02:00
return ;
int max = 0 ;
2016-03-11 12:18:46 +01:00
for ( Score * s : MuseScoreCore : : mscoreCore - > scores ( ) ) {
if ( s - > masterScore ( ) - > midiPortCount ( ) > max )
max = s - > masterScore ( ) - > midiPortCount ( ) ;
2014-07-25 19:29:22 +02:00
}
maxMidiOutPort = max ;
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// processMessages
2014-07-07 17:31:41 +02:00
// from gui to process thread
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
void Seq : : processMessages ( )
{
for ( ; ; ) {
2016-02-06 22:03:43 +01:00
if ( toSeq . empty ( ) )
2012-05-26 14:49:10 +02:00
break ;
SeqMsg msg = toSeq . dequeue ( ) ;
switch ( msg . id ) {
2014-06-03 10:46:57 +02:00
case SeqMsgId : : TEMPO_CHANGE :
2012-05-26 14:49:10 +02:00
{
2013-12-10 17:46:57 +01:00
if ( ! cs )
continue ;
2017-05-14 17:43:28 +02:00
if ( playFrame ! = 0 ) {
int utick = cs - > utime2utick ( qreal ( playFrame ) / qreal ( MScore : : sampleRate ) ) ;
2013-02-20 17:53:15 +01:00
cs - > tempomap ( ) - > setRelTempo ( msg . realVal ) ;
2017-05-14 17:43:28 +02:00
playFrame = cs - > utick2utime ( utick ) * MScore : : sampleRate ;
2017-11-29 08:21:36 +01:00
if ( preferences . getBool ( PREF_IO_JACK_TIMEBASEMASTER ) & & preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) )
2014-07-07 17:31:41 +02:00
_driver - > seekTransport ( utick + 2 * cs - > utime2utick ( qreal ( ( _driver - > bufferSize ( ) ) + 1 ) / qreal ( MScore : : sampleRate ) ) ) ;
2012-05-26 14:49:10 +02:00
}
else
2013-02-20 17:53:15 +01:00
cs - > tempomap ( ) - > setRelTempo ( msg . realVal ) ;
2014-11-28 12:41:59 +01:00
cs - > repeatList ( ) - > update ( ) ;
2014-05-30 23:18:52 +02:00
prevTempo = curTempo ( ) ;
emit tempoChanged ( ) ;
2012-05-26 14:49:10 +02:00
}
break ;
2014-06-03 10:46:57 +02:00
case SeqMsgId : : PLAY :
2012-05-26 14:49:10 +02:00
putEvent ( msg . event ) ;
break ;
2014-06-03 10:46:57 +02:00
case SeqMsgId : : SEEK :
2013-02-20 17:53:15 +01:00
setPos ( msg . intVal ) ;
2012-05-26 14:49:10 +02:00
break ;
2014-06-03 10:46:57 +02:00
default :
break ;
2012-05-26 14:49:10 +02:00
}
}
}
//---------------------------------------------------------
// metronome
//---------------------------------------------------------
2013-10-15 09:36:17 +02:00
void Seq : : metronome ( unsigned n , float * p , bool force )
2012-05-26 14:49:10 +02:00
{
2013-10-15 09:36:17 +02:00
if ( ! mscore - > metronome ( ) & & ! force ) {
2016-08-08 17:46:56 +02:00
tickRemain = 0 ;
tackRemain = 0 ;
2012-05-26 14:49:10 +02:00
return ;
}
2016-08-08 17:46:56 +02:00
if ( tickRemain ) {
tackRemain = 0 ;
int idx = tickLength - tickRemain ;
int nn = n < tickRemain ? n : tickRemain ;
2012-05-26 14:49:10 +02:00
for ( int i = 0 ; i < nn ; + + i ) {
2016-08-08 17:46:56 +02:00
qreal v = tick [ idx ] * tickVolume * metronomeVolume ;
2012-05-26 14:49:10 +02:00
* p + + + = v ;
* p + + + = v ;
+ + idx ;
}
2016-08-08 17:46:56 +02:00
tickRemain - = nn ;
2012-05-26 14:49:10 +02:00
}
2016-08-08 17:46:56 +02:00
if ( tackRemain ) {
int idx = tackLength - tackRemain ;
int nn = n < tackRemain ? n : tackRemain ;
2012-05-26 14:49:10 +02:00
for ( int i = 0 ; i < nn ; + + i ) {
2016-08-08 17:46:56 +02:00
qreal v = tack [ idx ] * tackVolume * metronomeVolume ;
2012-05-26 14:49:10 +02:00
* p + + + = v ;
* p + + + = v ;
+ + idx ;
}
2016-08-08 17:46:56 +02:00
tackRemain - = nn ;
2012-05-26 14:49:10 +02:00
}
}
2013-10-15 09:36:17 +02:00
//---------------------------------------------------------
// addCountInClicks
//---------------------------------------------------------
void Seq : : addCountInClicks ( )
{
2016-08-08 17:46:56 +02:00
const int plPos = cs - > playPos ( ) ;
2013-10-15 09:36:17 +02:00
Measure * m = cs - > tick2measure ( plPos ) ;
2016-08-08 17:46:56 +02:00
const int msrTick = m - > tick ( ) ;
const qreal tempo = cs - > tempomap ( ) - > tempo ( msrTick ) ;
TimeSigFrac timeSig = cs - > sigmap ( ) - > timesig ( msrTick ) . nominal ( ) ;
const int clickTicks = timeSig . isBeatedCompound ( tempo ) ? timeSig . beatTicks ( ) : timeSig . dUnitTicks ( ) ;
// add at least one full measure of just clicks.
int endTick = timeSig . ticksPerMeasure ( ) ;
// add extra clicks if...
endTick + = plPos - msrTick ; // ...not starting playback at beginning of measure
if ( m - > isAnacrusis ( ) ) // ...measure is incomplete (anacrusis)
endTick + = timeSig . ticksPerMeasure ( ) - m - > ticks ( ) ;
for ( int tick = 0 ; tick < endTick ; tick + = clickTicks ) {
const int rtick = tick % timeSig . ticksPerMeasure ( ) ;
countInEvents . insert ( std : : pair < int , NPlayEvent > ( tick , NPlayEvent ( timeSig . rtick2beatType ( rtick ) ) ) ) ;
}
2015-06-10 17:45:04 +02:00
NPlayEvent event ;
2013-10-15 09:36:17 +02:00
event . setType ( ME_INVALID ) ;
event . setPitch ( 0 ) ;
2016-08-08 17:46:56 +02:00
countInEvents . insert ( std : : pair < int , NPlayEvent > ( endTick , event ) ) ;
2013-10-15 09:36:17 +02:00
// initialize play parameters to count-in events
countInPlayPos = countInEvents . cbegin ( ) ;
2017-05-14 17:43:28 +02:00
countInPlayFrame = 0 ;
2013-10-15 09:36:17 +02:00
}
2014-06-05 08:35:39 +02:00
//-------------------------------------------------------------------
2012-05-26 14:49:10 +02:00
// process
2014-06-05 08:35:39 +02:00
// This function is called in a realtime context. This
// means that no blocking operations are allowed which
// includes memory allocation. The usual thread synchronisation
// methods like semaphores can also not be used.
//-------------------------------------------------------------------
2012-05-26 14:49:10 +02:00
2017-05-14 17:43:28 +02:00
void Seq : : process ( unsigned framesPerPeriod , float * buffer )
2012-05-26 14:49:10 +02:00
{
2017-05-14 17:43:28 +02:00
unsigned framesRemain = framesPerPeriod ; // the number of frames remaining to be processed by this call to Seq::process
2014-06-03 17:14:35 +02:00
Transport driverState = _driver - > getState ( ) ;
2014-07-03 18:02:33 +02:00
// Checking for the reposition from JACK Transport
2017-05-14 17:43:28 +02:00
_driver - > checkTransportSeek ( playFrame , framesRemain , inCountIn ) ;
2014-07-25 19:29:22 +02:00
2013-08-09 06:57:26 +02:00
if ( driverState ! = state ) {
2014-05-24 21:30:33 +02:00
// Got a message from JACK Transport panel: Play
2014-06-03 17:14:35 +02:00
if ( state = = Transport : : STOP & & driverState = = Transport : : PLAY ) {
2017-11-29 08:21:36 +01:00
if ( ( preferences . getBool ( PREF_IO_JACK_USEJACKMIDI ) | | preferences . getBool ( PREF_IO_JACK_USEJACKAUDIO ) ) & & ! getAction ( " play " ) - > isChecked ( ) ) {
2014-05-24 21:30:33 +02:00
// Do not play while editing elements
2014-07-07 17:31:41 +02:00
if ( mscore - > state ( ) ! = STATE_NORMAL | | ! isRunning ( ) | | ! canStart ( ) )
2014-05-24 21:30:33 +02:00
return ;
2014-07-07 17:31:41 +02:00
getAction ( " play " ) - > setChecked ( true ) ;
getAction ( " play " ) - > triggered ( true ) ;
// If we just launch MuseScore and press "Play" on JACK Transport with time 0:00
// MuseScore doesn't seek to 0 and guiPos is uninitialized, so let's make it manually
2017-11-29 08:21:36 +01:00
if ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) & & getCurTick ( ) = = 0 )
2014-07-07 17:31:41 +02:00
seekRT ( 0 ) ;
// Switching to fake transport while playing count in
// to prevent playing in other applications with our ticks simultaneously
2017-11-29 08:21:36 +01:00
if ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) & & mscore - > countIn ( ) ) {
2014-07-07 17:31:41 +02:00
// Stopping real JACK Transport
_driver - > stopTransport ( ) ;
// Starting fake transport
2017-11-29 08:21:36 +01:00
useJackTransportSavedFlag = preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) ;
preferences . setPreference ( PREF_IO_JACK_USEJACKTRANSPORT , false ) ;
2014-07-07 17:31:41 +02:00
_driver - > startTransport ( ) ;
2014-05-24 21:30:33 +02:00
}
}
2016-08-11 16:06:04 +02:00
// Initializing instruments every time we start playback.
// External synth can have wrong values, for example
// if we switch between scores
initInstruments ( true ) ;
2014-05-24 21:30:33 +02:00
// Need to change state after calling collectEvents()
2014-06-03 17:14:35 +02:00
state = Transport : : PLAY ;
2014-05-31 07:23:36 +02:00
if ( mscore - > countIn ( ) & & cs - > playMode ( ) = = PlayMode : : SYNTHESIZER ) {
2013-10-15 09:36:17 +02:00
countInEvents . clear ( ) ;
inCountIn = true ;
}
2013-04-29 19:42:38 +02:00
emit toGui ( ' 1 ' ) ;
}
2014-05-24 21:30:33 +02:00
// Got a message from JACK Transport panel: Stop
2014-06-03 17:14:35 +02:00
else if ( state = = Transport : : PLAY & & driverState = = Transport : : STOP ) {
state = Transport : : STOP ;
2014-05-24 21:30:33 +02:00
// Muting all notes
2014-08-25 17:07:37 +02:00
stopNotes ( - 1 , true ) ;
2016-08-11 16:06:04 +02:00
initInstruments ( true ) ;
2013-08-09 01:20:07 +02:00
if ( playPos = = events . cend ( ) ) {
if ( mscore - > loop ( ) ) {
2017-05-14 17:43:28 +02:00
qDebug ( " Seq.cpp - Process - Loop whole score. playPos = %d, cs->pos() = %d " , playPos - > first , cs - > pos ( ) ) ;
2013-09-12 15:57:14 +02:00
emit toGui ( ' 4 ' ) ;
2014-02-11 11:36:03 +01:00
return ;
2013-08-19 11:21:21 +02:00
}
2013-08-09 01:20:07 +02:00
else {
emit toGui ( ' 2 ' ) ;
}
}
else {
emit toGui ( ' 0 ' ) ;
}
2013-04-29 19:42:38 +02:00
}
2012-05-26 14:49:10 +02:00
else if ( state ! = driverState )
2014-03-25 13:33:47 +01:00
qDebug ( " Seq: state transition %d -> %d ? " ,
2015-03-06 22:54:52 +01:00
( int ) state , ( int ) driverState ) ;
2012-05-26 14:49:10 +02:00
}
2017-05-14 17:43:28 +02:00
memset ( buffer , 0 , sizeof ( float ) * framesPerPeriod * 2 ) ; // assume two channels
2012-05-26 14:49:10 +02:00
float * p = buffer ;
2014-05-30 23:18:52 +02:00
2012-05-26 14:49:10 +02:00
processMessages ( ) ;
2014-06-03 17:14:35 +02:00
if ( state = = Transport : : PLAY ) {
2014-07-07 17:31:41 +02:00
if ( ! cs )
2013-06-28 16:59:19 +02:00
return ;
2017-05-14 17:43:28 +02:00
// if currently in count-in, these pointers will reference data in the count-in
EventMap : : const_iterator * pPlayPos = & playPos ;
EventMap * pEvents = & events ;
int * pPlayFrame = & playFrame ;
2013-10-15 09:36:17 +02:00
if ( inCountIn ) {
if ( countInEvents . size ( ) = = 0 )
addCountInClicks ( ) ;
2017-05-14 17:43:28 +02:00
pEvents = & countInEvents ;
pPlayPos = & countInPlayPos ;
pPlayFrame = & countInPlayFrame ;
2013-10-15 09:36:17 +02:00
}
2017-05-14 17:43:28 +02:00
2012-05-26 14:49:10 +02:00
//
// play events for one segment
//
2017-05-14 17:43:28 +02:00
unsigned framePos = 0 ; // frame currently being processed relative to the first frame of this call to Seq::process
int periodEndFrame = * pPlayFrame + framesPerPeriod ; // the ending frame (relative to start of playback) of the period being processed by this call to Seq::process
int scoreEndUTick = cs - > repeatList ( ) - > tick2utick ( cs - > lastMeasure ( ) - > endTick ( ) ) ;
while ( * pPlayPos ! = pEvents - > cend ( ) ) {
int playPosUTick = ( * pPlayPos ) - > first ;
int n ; // current frame (relative to start of playback) that is being synthesized
2014-03-28 16:29:55 +01:00
2017-05-14 17:43:28 +02:00
if ( inCountIn ) {
qreal beatsPerSecond = curTempo ( ) * cs - > tempomap ( ) - > relTempo ( ) ; // relTempo needed here to ensure that bps changes as we slide the tempo bar
qreal ticksPerSecond = beatsPerSecond * MScore : : division ;
qreal playPosSeconds = playPosUTick / ticksPerSecond ;
int playPosFrame = playPosSeconds * MScore : : sampleRate ;
if ( playPosFrame > = periodEndFrame )
2013-10-15 09:36:17 +02:00
break ;
2017-05-14 17:43:28 +02:00
n = playPosFrame - * pPlayFrame ;
2013-10-15 09:36:17 +02:00
if ( n < 0 ) {
2017-05-14 17:43:28 +02:00
qDebug ( " Count-in: playPosUTick %d: n = %d - %d " , playPosUTick , playPosFrame , * pPlayFrame ) ;
2013-10-15 09:36:17 +02:00
n = 0 ;
}
2012-05-26 14:49:10 +02:00
}
2013-10-15 09:36:17 +02:00
else {
2017-05-14 17:43:28 +02:00
qreal playPosSeconds = cs - > utick2utime ( playPosUTick ) ;
int playPosFrame = playPosSeconds * MScore : : sampleRate ;
if ( playPosFrame > = periodEndFrame )
2013-10-15 09:36:17 +02:00
break ;
2017-05-14 17:43:28 +02:00
n = playPosFrame - * pPlayFrame ;
2013-10-15 09:36:17 +02:00
if ( n < 0 ) {
2017-05-14 17:43:28 +02:00
qDebug ( " %d: %d - %d " , playPosUTick , playPosFrame , * pPlayFrame ) ;
2013-10-15 09:36:17 +02:00
n = 0 ;
}
if ( mscore - > loop ( ) ) {
2017-05-14 17:43:28 +02:00
int loopOutUTick = cs - > repeatList ( ) - > tick2utick ( cs - > loopOutTick ( ) ) ;
if ( loopOutUTick < scoreEndUTick ) {
2016-06-18 17:04:21 +02:00
// Also make sure we are not "before" the loop
2017-05-14 17:43:28 +02:00
if ( playPosUTick > = loopOutUTick | | cs - > repeatList ( ) - > utick2tick ( playPosUTick ) < cs - > loopInTick ( ) ) {
qDebug ( " Process: playPosUTick = %d, cs->loopInTick() = %d, cs->loopOutTick() = %d, getCurTick() = %d, loopOutUTick = %d, playFrame = %d " ,
playPosUTick , cs - > loopInTick ( ) , cs - > loopOutTick ( ) , getCurTick ( ) , loopOutUTick , * pPlayFrame ) ;
2017-11-29 08:21:36 +01:00
if ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) ) {
2017-05-14 17:43:28 +02:00
int loopInUTick = cs - > repeatList ( ) - > tick2utick ( cs - > loopInTick ( ) ) ;
_driver - > seekTransport ( loopInUTick ) ;
if ( loopInUTick ! = 0 ) {
int seekto = loopInUTick - 2 * cs - > utime2utick ( ( qreal ) _driver - > bufferSize ( ) / MScore : : sampleRate ) ;
2014-07-07 17:31:41 +02:00
seekRT ( ( seekto > 0 ) ? seekto : 0 ) ;
2014-06-18 21:36:53 +02:00
}
}
2014-07-03 18:02:33 +02:00
else {
emit toGui ( ' 3 ' ) ;
}
2014-06-18 21:36:53 +02:00
// Exit this function to avoid segmentation fault in Scoreview
2013-10-15 09:36:17 +02:00
return ;
}
2016-06-18 17:04:21 +02:00
}
2013-10-15 09:36:17 +02:00
}
2013-09-03 21:01:03 +02:00
}
2012-05-26 14:49:10 +02:00
if ( n ) {
2014-05-30 10:16:38 +02:00
if ( cs - > playMode ( ) = = PlayMode : : SYNTHESIZER ) {
2013-10-15 09:36:17 +02:00
metronome ( n , p , inCountIn ) ;
2013-04-02 20:46:07 +02:00
_synti - > process ( n , p ) ;
2012-05-26 14:49:10 +02:00
p + = n * 2 ;
2017-05-14 17:43:28 +02:00
* pPlayFrame + = n ;
framesRemain - = n ;
framePos + = n ;
2012-05-26 14:49:10 +02:00
}
else {
while ( n > 0 ) {
int section ;
float * * pcm ;
long rn = ov_read_float ( & vf , & pcm , n , & section ) ;
if ( rn = = 0 )
break ;
for ( int i = 0 ; i < rn ; + + i ) {
* p + + = pcm [ 0 ] [ i ] ;
* p + + = pcm [ 1 ] [ i ] ;
}
2017-05-14 17:43:28 +02:00
* pPlayFrame + = rn ;
framesRemain - = rn ;
framePos + = rn ;
n - = rn ;
2012-05-26 14:49:10 +02:00
}
}
}
2013-10-15 09:36:17 +02:00
const NPlayEvent & event = ( * pPlayPos ) - > second ;
2014-07-29 16:31:44 +02:00
playEvent ( event , framePos ) ;
2016-08-08 17:46:56 +02:00
if ( event . type ( ) = = ME_TICK1 ) {
tickRemain = tickLength ;
tickVolume = event . velo ( ) ? qreal ( event . value ( ) ) / 127.0 : 1.0 ;
}
else if ( event . type ( ) = = ME_TICK2 ) {
tackRemain = tackLength ;
tackVolume = event . velo ( ) ? qreal ( event . value ( ) ) / 127.0 : 1.0 ;
}
2013-02-20 17:53:15 +01:00
mutex . lock ( ) ;
2013-10-15 09:36:17 +02:00
+ + ( * pPlayPos ) ;
2013-02-20 17:53:15 +01:00
mutex . unlock ( ) ;
2012-05-26 14:49:10 +02:00
}
2017-05-14 17:43:28 +02:00
if ( framesRemain ) {
2014-05-30 10:16:38 +02:00
if ( cs - > playMode ( ) = = PlayMode : : SYNTHESIZER ) {
2017-05-14 17:43:28 +02:00
metronome ( framesRemain , p , inCountIn ) ;
_synti - > process ( framesRemain , p ) ;
* pPlayFrame + = framesRemain ;
2012-05-26 14:49:10 +02:00
}
else {
2017-05-14 17:43:28 +02:00
int n = framesRemain ;
2012-05-26 14:49:10 +02:00
while ( n > 0 ) {
int section ;
float * * pcm ;
long rn = ov_read_float ( & vf , & pcm , n , & section ) ;
if ( rn = = 0 )
break ;
for ( int i = 0 ; i < rn ; + + i ) {
* p + + = pcm [ 0 ] [ i ] ;
* p + + = pcm [ 1 ] [ i ] ;
}
2017-05-14 17:43:28 +02:00
* pPlayFrame + = rn ;
framesRemain - = rn ;
framePos + = rn ;
n - = rn ;
2012-05-26 14:49:10 +02:00
}
}
}
2013-10-15 09:36:17 +02:00
if ( * pPlayPos = = pEvents - > cend ( ) ) {
2014-07-07 17:31:41 +02:00
if ( inCountIn ) {
2013-10-15 09:36:17 +02:00
inCountIn = false ;
2014-07-07 17:31:41 +02:00
// Connecting to JACK Transport if MuseScore was temporarily disconnected from it
if ( useJackTransportSavedFlag ) {
// Stopping fake driver
_driver - > stopTransport ( ) ;
2017-11-29 08:21:36 +01:00
preferences . setPreference ( PREF_IO_JACK_USEJACKTRANSPORT , true ) ;
2014-07-07 17:31:41 +02:00
// Starting the real JACK Transport. All applications play in sync now
_driver - > startTransport ( ) ;
}
}
2013-10-15 09:36:17 +02:00
else
_driver - > stopTransport ( ) ;
}
2012-05-26 14:49:10 +02:00
}
else {
2016-08-08 17:46:56 +02:00
// Outside of playback mode
while ( ! liveEventQueue ( ) - > empty ( ) ) {
const NPlayEvent & event = liveEventQueue ( ) - > dequeue ( ) ;
if ( event . type ( ) = = ME_TICK1 ) {
tickRemain = tickLength ;
tickVolume = event . velo ( ) ? qreal ( event . value ( ) ) / 127.0 : 1.0 ;
}
else if ( event . type ( ) = = ME_TICK2 ) {
tackRemain = tackLength ;
tackVolume = event . velo ( ) ? qreal ( event . value ( ) ) / 127.0 : 1.0 ;
}
}
2017-05-14 17:43:28 +02:00
if ( framesRemain ) {
metronome ( framesRemain , p , true ) ;
_synti - > process ( framesRemain , p ) ;
2016-08-08 17:46:56 +02:00
}
2012-05-26 14:49:10 +02:00
}
//
2013-03-27 20:10:14 +01:00
// metering / master gain
2012-05-26 14:49:10 +02:00
//
2016-02-15 09:33:54 +01:00
qreal lv = 0.0f ;
qreal rv = 0.0f ;
2013-03-27 20:10:14 +01:00
p = buffer ;
2017-05-14 17:43:28 +02:00
for ( unsigned i = 0 ; i < framesRemain ; + + i ) {
2013-04-03 12:49:55 +02:00
qreal val = * p ;
2016-02-15 09:33:54 +01:00
lv = qMax ( lv , qAbs ( val ) ) ;
2017-08-18 17:40:19 +02:00
p + + ;
2013-03-27 20:10:14 +01:00
2013-04-03 12:49:55 +02:00
val = * p ;
2017-08-18 17:21:22 +02:00
rv = qMax ( rv , qAbs ( val ) ) ;
2017-08-18 17:40:19 +02:00
p + + ;
2012-05-26 14:49:10 +02:00
}
meterValue [ 0 ] = lv ;
meterValue [ 1 ] = rv ;
if ( meterPeakValue [ 0 ] < lv ) {
meterPeakValue [ 0 ] = lv ;
peakTimer [ 0 ] = 0 ;
}
if ( meterPeakValue [ 1 ] < rv ) {
meterPeakValue [ 1 ] = rv ;
peakTimer [ 1 ] = 0 ;
}
}
2013-08-08 11:38:32 +02:00
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// initInstruments
//---------------------------------------------------------
2014-08-25 17:07:37 +02:00
void Seq : : initInstruments ( bool realTime )
2012-05-26 14:49:10 +02:00
{
2014-07-25 19:29:22 +02:00
// Add midi out ports if necessary
2017-11-29 08:21:36 +01:00
if ( cs & & ( preferences . getBool ( PREF_IO_JACK_USEJACKMIDI ) | | preferences . getBool ( PREF_IO_ALSA_USEALSAAUDIO ) ) ) {
2014-07-25 19:29:22 +02:00
// Increase the maximum number of midi ports if user adds staves/instruments
2016-03-11 12:18:46 +01:00
int scoreMaxMidiPort = cs - > masterScore ( ) - > midiPortCount ( ) ;
2014-07-25 19:29:22 +02:00
if ( maxMidiOutPort < scoreMaxMidiPort )
maxMidiOutPort = scoreMaxMidiPort ;
// if maxMidiOutPort is equal to existing ports number, it will do nothing
2014-11-29 11:09:56 +01:00
if ( _driver )
_driver - > updateOutPortCount ( maxMidiOutPort + 1 ) ;
2014-07-25 19:29:22 +02:00
}
2012-05-26 14:49:10 +02:00
foreach ( const MidiMapping & mm , * cs - > midiMapping ( ) ) {
Channel * channel = mm . articulation ;
2013-04-25 09:50:55 +02:00
foreach ( const MidiCoreEvent & e , channel - > init ) {
2012-05-26 14:49:10 +02:00
if ( e . type ( ) = = ME_INVALID )
continue ;
2013-04-25 09:50:55 +02:00
NPlayEvent event ( e . type ( ) , channel - > channel , e . dataA ( ) , e . dataB ( ) ) ;
2014-08-25 17:07:37 +02:00
if ( realTime )
putEvent ( event ) ;
else
sendEvent ( event ) ;
2012-05-26 14:49:10 +02:00
}
2015-06-03 18:36:59 +02:00
// Setting pitch bend sensitivity to 12 semitones for external synthesizers
2017-11-29 08:21:36 +01:00
if ( ( preferences . getBool ( PREF_IO_JACK_USEJACKMIDI ) | | preferences . getBool ( PREF_IO_ALSA_USEALSAAUDIO ) ) & & mm . channel ! = 9 ) {
2015-06-03 18:36:59 +02:00
if ( realTime ) {
putEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_LRPN , 0 ) ) ;
putEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_HRPN , 0 ) ) ;
putEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_HDATA , 12 ) ) ;
putEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_LRPN , 127 ) ) ;
putEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_HRPN , 127 ) ) ;
}
else {
sendEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_LRPN , 0 ) ) ;
sendEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_HRPN , 0 ) ) ;
sendEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_HDATA , 12 ) ) ;
sendEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_LRPN , 127 ) ) ;
sendEvent ( NPlayEvent ( ME_CONTROLLER , channel - > channel , CTRL_HRPN , 127 ) ) ;
}
}
2012-05-26 14:49:10 +02:00
}
}
//---------------------------------------------------------
// collectEvents
//---------------------------------------------------------
void Seq : : collectEvents ( )
{
2012-06-23 15:54:01 +02:00
//do not collect even while playing
2014-06-03 17:14:35 +02:00
if ( state = = Transport : : PLAY )
2012-06-23 15:54:01 +02:00
return ;
2017-02-28 00:15:46 +01:00
mutex . lock ( ) ;
2012-05-26 14:49:10 +02:00
events . clear ( ) ;
2012-11-19 09:29:46 +01:00
cs - > renderMidi ( & events ) ;
2017-05-14 17:43:28 +02:00
endUTick = 0 ;
2013-05-03 11:37:28 +02:00
2012-05-26 14:49:10 +02:00
if ( ! events . empty ( ) ) {
2013-04-08 10:31:17 +02:00
auto e = events . cend ( ) ;
2012-05-26 14:49:10 +02:00
- - e ;
2017-05-14 17:43:28 +02:00
endUTick = e - > first ;
2012-05-26 14:49:10 +02:00
}
2013-05-03 14:45:25 +02:00
playPos = events . cbegin ( ) ;
mutex . unlock ( ) ;
2012-05-26 14:49:10 +02:00
playlistChanged = false ;
}
//---------------------------------------------------------
// getCurTick
//---------------------------------------------------------
int Seq : : getCurTick ( )
{
2017-05-14 17:43:28 +02:00
return cs - > utime2utick ( qreal ( playFrame ) / qreal ( MScore : : sampleRate ) ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// setRelTempo
// relTempo = 1.0 = normal tempo
//---------------------------------------------------------
void Seq : : setRelTempo ( double relTempo )
{
2014-06-03 10:46:57 +02:00
guiToSeq ( SeqMsg ( SeqMsgId : : TEMPO_CHANGE , relTempo ) ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// setPos
// seek
// realtime environment
//---------------------------------------------------------
void Seq : : setPos ( int utick )
{
2013-03-20 17:08:12 +01:00
if ( cs = = 0 )
return ;
2014-08-25 17:07:37 +02:00
stopNotes ( - 1 , true ) ;
2012-05-26 14:49:10 +02:00
2013-05-03 14:24:14 +02:00
int ucur ;
2017-02-28 00:15:46 +01:00
mutex . lock ( ) ;
2013-05-03 14:24:14 +02:00
if ( playPos ! = events . end ( ) )
ucur = cs - > repeatList ( ) - > utick2tick ( playPos - > first ) ;
else
ucur = utick - 1 ;
2013-04-29 19:42:38 +02:00
if ( utick ! = ucur )
updateSynthesizerState ( ucur , utick ) ;
2017-05-14 17:43:28 +02:00
playFrame = cs - > utick2utime ( utick ) * MScore : : sampleRate ;
2013-04-08 10:31:17 +02:00
playPos = events . lower_bound ( utick ) ;
2013-02-20 17:53:15 +01:00
mutex . unlock ( ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
2014-07-07 17:31:41 +02:00
// seekCommon
// a common part of seek() and seekRT(), contains code
// that could be safely called from any thread.
// Do not use explicitly, use seek() or seekRT()
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
2014-07-07 17:31:41 +02:00
void Seq : : seekCommon ( int utick )
2012-05-26 14:49:10 +02:00
{
if ( cs = = 0 )
return ;
2013-02-20 17:53:15 +01:00
2014-04-02 10:49:54 +02:00
if ( playlistChanged )
2013-04-25 14:35:32 +02:00
collectEvents ( ) ;
2014-07-02 20:47:42 +02:00
2014-07-07 17:31:41 +02:00
if ( cs - > playMode ( ) = = PlayMode : : AUDIO ) {
ogg_int64_t sp = cs - > utick2utime ( utick ) * MScore : : sampleRate ;
ov_pcm_seek ( & vf , sp ) ;
2014-06-18 21:36:53 +02:00
}
2014-07-07 17:31:41 +02:00
guiPos = events . lower_bound ( utick ) ;
mscore - > setPos ( cs - > repeatList ( ) - > utick2tick ( utick ) ) ;
unmarkNotes ( ) ;
2013-02-20 17:53:15 +01:00
}
//---------------------------------------------------------
// seek
2014-07-07 17:31:41 +02:00
// send seek message to sequencer
// gui thread
2013-02-20 17:53:15 +01:00
//---------------------------------------------------------
2014-07-07 17:31:41 +02:00
void Seq : : seek ( int utick )
2013-02-20 17:53:15 +01:00
{
2017-11-29 08:21:36 +01:00
if ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) ) {
2017-05-14 17:43:28 +02:00
if ( utick > endUTick )
2014-07-07 17:31:41 +02:00
utick = 0 ;
_driver - > seekTransport ( utick ) ;
if ( utick ! = 0 )
return ;
}
seekCommon ( utick ) ;
2013-05-03 14:45:25 +02:00
2014-06-18 21:36:53 +02:00
int tick = cs - > repeatList ( ) - > utick2tick ( utick ) ;
2014-07-07 17:31:41 +02:00
Segment * seg = cs - > tick2segment ( tick ) ;
2013-05-03 14:45:25 +02:00
if ( seg )
2013-07-03 11:17:14 +02:00
mscore - > currentScoreView ( ) - > moveCursor ( seg - > tick ( ) ) ;
2014-06-18 21:36:53 +02:00
cs - > setPlayPos ( tick ) ;
2016-04-18 18:11:51 +02:00
cs - > update ( ) ;
2014-07-07 17:31:41 +02:00
guiToSeq ( SeqMsg ( SeqMsgId : : SEEK , utick ) ) ;
}
2012-11-19 09:29:46 +01:00
2014-07-07 17:31:41 +02:00
//---------------------------------------------------------
// seekRT
// realtime thread
//---------------------------------------------------------
2012-05-26 14:49:10 +02:00
2014-07-07 17:31:41 +02:00
void Seq : : seekRT ( int utick )
{
2017-11-29 08:21:36 +01:00
if ( preferences . getBool ( PREF_IO_JACK_USEJACKTRANSPORT ) & & utick > endUTick )
2014-07-07 17:31:41 +02:00
utick = 0 ;
seekCommon ( utick ) ;
setPos ( utick ) ;
// Update the screen in GUI thread
emit toGui ( ' 5 ' , cs - > repeatList ( ) - > utick2tick ( utick ) ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// startNote
//---------------------------------------------------------
2012-06-28 14:50:47 +02:00
void Seq : : startNote ( int channel , int pitch , int velo , double nt )
2012-05-26 14:49:10 +02:00
{
2014-06-03 17:14:35 +02:00
if ( state ! = Transport : : STOP )
2012-05-26 14:49:10 +02:00
return ;
2013-04-25 09:50:55 +02:00
NPlayEvent ev ( ME_NOTEON , channel , pitch , velo ) ;
2012-05-26 14:49:10 +02:00
ev . setTuning ( nt ) ;
sendEvent ( ev ) ;
}
2012-06-28 14:50:47 +02:00
void Seq : : startNote ( int channel , int pitch , int velo , int duration , double nt )
2012-05-26 14:49:10 +02:00
{
stopNotes ( ) ;
2012-06-28 14:50:47 +02:00
startNote ( channel , pitch , velo , nt ) ;
2012-05-26 14:49:10 +02:00
startNoteTimer ( duration ) ;
}
2016-08-08 17:46:56 +02:00
//---------------------------------------------------------
// playMetronomeBeat
//---------------------------------------------------------
void Seq : : playMetronomeBeat ( BeatType type )
{
if ( state ! = Transport : : STOP )
return ;
liveEventQueue ( ) - > enqueue ( NPlayEvent ( type ) ) ;
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// startNoteTimer
//---------------------------------------------------------
void Seq : : startNoteTimer ( int duration )
{
if ( duration ) {
noteTimer - > setInterval ( duration ) ;
noteTimer - > start ( ) ;
}
}
//---------------------------------------------------------
// stopNoteTimer
//---------------------------------------------------------
void Seq : : stopNoteTimer ( )
{
if ( noteTimer - > isActive ( ) ) {
noteTimer - > stop ( ) ;
stopNotes ( ) ;
}
}
//---------------------------------------------------------
// stopNotes
//---------------------------------------------------------
2014-08-25 17:07:37 +02:00
void Seq : : stopNotes ( int channel , bool realTime )
2012-05-26 14:49:10 +02:00
{
2014-12-20 20:39:34 +01:00
auto send = [ this , realTime ] ( const NPlayEvent & event ) {
if ( realTime )
putEvent ( event ) ;
else
sendEvent ( event ) ;
} ;
2014-08-25 17:07:37 +02:00
// Stop notes in all channels
2014-05-30 23:18:52 +02:00
if ( channel = = - 1 ) {
2014-12-20 21:56:46 +01:00
for ( int ch = 0 ; ch < cs - > midiMapping ( ) - > size ( ) ; ch + + ) {
send ( NPlayEvent ( ME_CONTROLLER , ch , CTRL_SUSTAIN , 0 ) ) ;
2014-12-20 20:39:34 +01:00
send ( NPlayEvent ( ME_CONTROLLER , ch , CTRL_ALL_NOTES_OFF , 0 ) ) ;
2015-06-03 18:36:59 +02:00
if ( cs - > midiChannel ( ch ) ! = 9 )
send ( NPlayEvent ( ME_PITCHBEND , ch , 0 , 64 ) ) ;
2014-12-20 21:56:46 +01:00
}
2014-05-30 23:18:52 +02:00
}
else {
2014-12-20 21:56:46 +01:00
send ( NPlayEvent ( ME_CONTROLLER , channel , CTRL_SUSTAIN , 0 ) ) ;
2014-12-20 20:39:34 +01:00
send ( NPlayEvent ( ME_CONTROLLER , channel , CTRL_ALL_NOTES_OFF , 0 ) ) ;
2015-06-03 18:36:59 +02:00
if ( cs - > midiChannel ( channel ) ! = 9 )
send ( NPlayEvent ( ME_PITCHBEND , channel , 0 , 64 ) ) ;
2014-05-30 23:18:52 +02:00
}
2017-11-29 08:21:36 +01:00
if ( preferences . getBool ( PREF_IO_ALSA_USEALSAAUDIO ) | | preferences . getBool ( PREF_IO_JACK_USEJACKAUDIO ) | | preferences . getBool ( PREF_IO_PULSEAUDIO_USEPULSEAUDIO ) | | preferences . getBool ( PREF_IO_PORTAUDIO_USEPORTAUDIO ) )
2014-05-30 23:18:52 +02:00
_synti - > allNotesOff ( channel ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// setController
//---------------------------------------------------------
void Seq : : setController ( int channel , int ctrl , int data )
{
2013-04-25 09:50:55 +02:00
NPlayEvent event ( ME_CONTROLLER , channel , ctrl , data ) ;
2012-05-26 14:49:10 +02:00
sendEvent ( event ) ;
}
//---------------------------------------------------------
// sendEvent
// called from GUI context to send a midi event to
// midi out or synthesizer
//---------------------------------------------------------
2013-04-25 09:50:55 +02:00
void Seq : : sendEvent ( const NPlayEvent & ev )
2012-05-26 14:49:10 +02:00
{
2014-06-03 10:46:57 +02:00
guiToSeq ( SeqMsg ( SeqMsgId : : PLAY , ev ) ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// nextMeasure
//---------------------------------------------------------
void Seq : : nextMeasure ( )
{
2013-04-08 10:31:17 +02:00
Measure * m = cs - > tick2measure ( guiPos - > first ) ;
2012-05-26 14:49:10 +02:00
if ( m ) {
2013-02-21 11:04:41 +01:00
if ( m - > nextMeasure ( ) )
m = m - > nextMeasure ( ) ;
seek ( m - > tick ( ) ) ;
2012-05-26 14:49:10 +02:00
}
}
//---------------------------------------------------------
// nextChord
//---------------------------------------------------------
void Seq : : nextChord ( )
{
2013-04-08 10:31:17 +02:00
int tick = guiPos - > first ;
for ( auto i = guiPos ; i ! = events . cend ( ) ; + + i ) {
if ( i - > second . type ( ) = = ME_NOTEON & & i - > first > tick & & i - > second . velo ( ) ) {
seek ( i - > first ) ;
2012-05-26 14:49:10 +02:00
break ;
}
}
}
//---------------------------------------------------------
// prevMeasure
//---------------------------------------------------------
void Seq : : prevMeasure ( )
{
2013-02-21 11:04:41 +01:00
auto i = guiPos ;
if ( i = = events . begin ( ) )
2012-05-26 14:49:10 +02:00
return ;
2013-02-21 11:04:41 +01:00
- - i ;
2013-04-08 10:31:17 +02:00
Measure * m = cs - > tick2measure ( i - > first ) ;
2012-05-26 14:49:10 +02:00
if ( m ) {
2013-04-08 10:31:17 +02:00
if ( ( i - > first = = m - > tick ( ) ) & & m - > prevMeasure ( ) )
2013-02-20 17:53:15 +01:00
m = m - > prevMeasure ( ) ;
seek ( m - > tick ( ) ) ;
2012-05-26 14:49:10 +02:00
}
}
//---------------------------------------------------------
// prevChord
//---------------------------------------------------------
void Seq : : prevChord ( )
{
2013-04-08 10:31:17 +02:00
int tick = playPos - > first ;
2012-05-26 14:49:10 +02:00
//find the chord just before playpos
2014-03-27 19:37:33 +01:00
EventMap : : const_iterator i = events . upper_bound ( cs - > repeatList ( ) - > tick2utick ( tick ) ) ;
2012-05-26 14:49:10 +02:00
for ( ; ; ) {
2013-04-08 10:31:17 +02:00
if ( i - > second . type ( ) = = ME_NOTEON ) {
2013-04-25 09:50:55 +02:00
const NPlayEvent & n = i - > second ;
2013-04-08 10:31:17 +02:00
if ( i - > first < tick & & n . velo ( ) ) {
tick = i - > first ;
2012-05-26 14:49:10 +02:00
break ;
}
}
2013-04-08 10:31:17 +02:00
if ( i = = events . cbegin ( ) )
2012-05-26 14:49:10 +02:00
break ;
- - i ;
}
//go the previous chord
2013-04-08 10:31:17 +02:00
if ( i ! = events . cbegin ( ) ) {
2012-05-26 14:49:10 +02:00
i = playPos ;
for ( ; ; ) {
2013-04-08 10:31:17 +02:00
if ( i - > second . type ( ) = = ME_NOTEON ) {
2013-04-25 09:50:55 +02:00
const NPlayEvent & n = i - > second ;
2013-04-08 10:31:17 +02:00
if ( i - > first < tick & & n . velo ( ) ) {
seek ( i - > first ) ;
2012-05-26 14:49:10 +02:00
break ;
}
}
2013-04-08 10:31:17 +02:00
if ( i = = events . cbegin ( ) )
2012-05-26 14:49:10 +02:00
break ;
- - i ;
}
}
}
//---------------------------------------------------------
// seekEnd
//---------------------------------------------------------
void Seq : : seekEnd ( )
{
2014-03-25 13:33:47 +01:00
qDebug ( " seek to end " ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// guiToSeq
//---------------------------------------------------------
void Seq : : guiToSeq ( const SeqMsg & msg )
{
2013-04-02 20:46:07 +02:00
if ( ! _driver | | ! running )
2012-05-26 14:49:10 +02:00
return ;
toSeq . enqueue ( msg ) ;
}
//---------------------------------------------------------
// eventToGui
//---------------------------------------------------------
2013-04-25 09:50:55 +02:00
void Seq : : eventToGui ( NPlayEvent e )
2012-05-26 14:49:10 +02:00
{
2014-06-03 10:46:57 +02:00
fromSeq . enqueue ( SeqMsg ( SeqMsgId : : MIDI_INPUT_EVENT , e ) ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// midiInputReady
//---------------------------------------------------------
void Seq : : midiInputReady ( )
{
2013-04-02 20:46:07 +02:00
if ( _driver )
_driver - > midiRead ( ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// SeqMsgFifo
//---------------------------------------------------------
SeqMsgFifo : : SeqMsgFifo ( )
{
maxCount = SEQ_MSG_FIFO_SIZE ;
clear ( ) ;
}
//---------------------------------------------------------
// enqueue
//---------------------------------------------------------
void SeqMsgFifo : : enqueue ( const SeqMsg & msg )
{
int i = 0 ;
int n = 50 ;
QMutex mutex ;
QWaitCondition qwc ;
mutex . lock ( ) ;
for ( ; i < n ; + + i ) {
if ( ! isFull ( ) )
break ;
qwc . wait ( & mutex , 100 ) ;
}
2013-02-15 14:50:03 +01:00
mutex . unlock ( ) ;
2012-05-26 14:49:10 +02:00
if ( i = = n ) {
2014-03-25 13:33:47 +01:00
qDebug ( " ===SeqMsgFifo: overflow " ) ;
2012-05-26 14:49:10 +02:00
return ;
}
messages [ widx ] = msg ;
push ( ) ;
}
//---------------------------------------------------------
// dequeue
//---------------------------------------------------------
SeqMsg SeqMsgFifo : : dequeue ( )
{
SeqMsg msg = messages [ ridx ] ;
pop ( ) ;
return msg ;
}
//---------------------------------------------------------
// putEvent
//---------------------------------------------------------
2014-07-29 16:31:44 +02:00
void Seq : : putEvent ( const NPlayEvent & event , unsigned framePos )
2012-05-26 14:49:10 +02:00
{
if ( ! cs )
return ;
int channel = event . channel ( ) ;
2013-03-27 15:16:23 +01:00
if ( channel > = cs - > midiMapping ( ) - > size ( ) ) {
2015-03-05 16:46:37 +01:00
qDebug ( " bad channel value %d >= %d " , channel , cs - > midiMapping ( ) - > size ( ) ) ;
2013-03-27 15:16:23 +01:00
return ;
}
2017-05-14 17:43:28 +02:00
// audio
2013-04-04 13:01:58 +02:00
int syntiIdx = _synti - > index ( cs - > midiMapping ( channel ) - > articulation - > synti ) ;
2013-04-02 20:46:07 +02:00
_synti - > play ( event , syntiIdx ) ;
2017-05-14 17:43:28 +02:00
// midi
2017-11-29 08:21:36 +01:00
if ( _driver ! = 0 & & ( preferences . getBool ( PREF_IO_JACK_USEJACKMIDI ) | | preferences . getBool ( PREF_IO_ALSA_USEALSAAUDIO ) | | preferences . getBool ( PREF_IO_PORTAUDIO_USEPORTAUDIO ) ) )
2014-07-29 16:31:44 +02:00
_driver - > putEvent ( event , framePos ) ;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// heartBeat
// update GUI
//---------------------------------------------------------
2013-05-03 11:37:28 +02:00
void Seq : : heartBeatTimeout ( )
2012-05-26 14:49:10 +02:00
{
SynthControl * sc = mscore - > getSynthControl ( ) ;
2013-04-02 20:46:07 +02:00
if ( sc & & _driver ) {
2012-05-26 14:49:10 +02:00
if ( + + peakTimer [ 0 ] > = peakHold )
meterPeakValue [ 0 ] * = .7f ;
if ( + + peakTimer [ 1 ] > = peakHold )
meterPeakValue [ 1 ] * = .7f ;
sc - > setMeter ( meterValue [ 0 ] , meterValue [ 1 ] , meterPeakValue [ 0 ] , meterPeakValue [ 1 ] ) ;
}
2013-02-20 17:53:15 +01:00
2016-02-06 22:03:43 +01:00
while ( ! fromSeq . empty ( ) ) {
2013-02-20 17:53:15 +01:00
SeqMsg msg = fromSeq . dequeue ( ) ;
2014-06-03 10:46:57 +02:00
if ( msg . id = = SeqMsgId : : MIDI_INPUT_EVENT ) {
2013-02-20 17:53:15 +01:00
int type = msg . event . type ( ) ;
if ( type = = ME_NOTEON )
mscore - > midiNoteReceived ( msg . event . channel ( ) , msg . event . pitch ( ) , msg . event . velo ( ) ) ;
else if ( type = = ME_NOTEOFF )
mscore - > midiNoteReceived ( msg . event . channel ( ) , msg . event . pitch ( ) , 0 ) ;
else if ( type = = ME_CONTROLLER )
mscore - > midiCtrlReceived ( msg . event . controller ( ) , msg . event . value ( ) ) ;
}
}
2014-06-03 17:14:35 +02:00
if ( state ! = Transport : : PLAY | | inCountIn )
2012-05-26 14:49:10 +02:00
return ;
2014-06-18 21:36:53 +02:00
2017-05-14 17:43:28 +02:00
int endFrame = playFrame ;
2012-05-26 14:49:10 +02:00
2013-02-20 17:53:15 +01:00
mutex . lock ( ) ;
auto ppos = playPos ;
2013-04-08 10:31:17 +02:00
if ( ppos ! = events . cbegin ( ) )
2013-02-20 17:53:15 +01:00
- - ppos ;
mutex . unlock ( ) ;
2014-07-07 17:31:41 +02:00
if ( cs & & cs - > sigmap ( ) - > timesig ( getCurTick ( ) ) . nominal ( ) ! = prevTimeSig ) {
2014-06-05 17:50:29 +02:00
prevTimeSig = cs - > sigmap ( ) - > timesig ( getCurTick ( ) ) . nominal ( ) ;
emit timeSigChanged ( ) ;
}
2014-07-07 17:31:41 +02:00
if ( cs & & curTempo ( ) ! = prevTempo ) {
2014-06-05 17:50:29 +02:00
prevTempo = curTempo ( ) ;
emit tempoChanged ( ) ;
}
2013-06-25 10:41:15 +02:00
QRectF r ;
2013-04-08 10:31:17 +02:00
for ( ; guiPos ! = events . cend ( ) ; + + guiPos ) {
2013-09-03 22:30:17 +02:00
if ( guiPos - > first > ppos - > first )
break ;
2013-09-03 21:01:03 +02:00
if ( mscore - > loop ( ) )
2014-02-10 17:30:30 +01:00
if ( guiPos - > first > = cs - > repeatList ( ) - > tick2utick ( cs - > loopOutTick ( ) ) )
2013-09-03 21:01:03 +02:00
break ;
2013-04-25 09:50:55 +02:00
const NPlayEvent & n = guiPos - > second ;
2013-02-20 17:53:15 +01:00
if ( n . type ( ) = = ME_NOTEON ) {
2012-05-26 14:49:10 +02:00
const Note * note1 = n . note ( ) ;
if ( n . velo ( ) ) {
while ( note1 ) {
2013-02-20 17:53:15 +01:00
note1 - > setMark ( true ) ;
2012-05-26 14:49:10 +02:00
markedNotes . append ( note1 ) ;
2013-06-25 10:41:15 +02:00
r | = note1 - > canvasBoundingRect ( ) ;
2012-05-26 14:49:10 +02:00
note1 = note1 - > tieFor ( ) ? note1 - > tieFor ( ) - > endNote ( ) : 0 ;
}
}
else {
while ( note1 ) {
2013-02-20 17:53:15 +01:00
note1 - > setMark ( false ) ;
2013-06-25 10:41:15 +02:00
r | = note1 - > canvasBoundingRect ( ) ;
2012-05-26 14:49:10 +02:00
markedNotes . removeOne ( note1 ) ;
note1 = note1 - > tieFor ( ) ? note1 - > tieFor ( ) - > endNote ( ) : 0 ;
}
}
}
}
2013-04-08 10:31:17 +02:00
int utick = ppos - > first ;
2012-07-02 18:43:11 +02:00
int tick = cs - > repeatList ( ) - > utick2tick ( utick ) ;
2012-05-26 14:49:10 +02:00
mscore - > currentScoreView ( ) - > moveCursor ( tick ) ;
mscore - > setPos ( tick ) ;
2013-05-03 11:37:28 +02:00
2017-05-14 17:43:28 +02:00
emit ( heartBeat ( tick , utick , endFrame ) ) ;
2012-05-26 14:49:10 +02:00
PianorollEditor * pre = mscore - > getPianorollEditor ( ) ;
if ( pre & & pre - > isVisible ( ) )
pre - > heartBeat ( this ) ;
2015-04-01 17:18:09 +02:00
PianoTools * piano = mscore - > pianoTools ( ) ;
if ( piano & & piano - > isVisible ( ) )
piano - > heartBeat ( markedNotes ) ;
2013-06-25 10:41:15 +02:00
cv - > update ( cv - > toPhysical ( r ) ) ;
2012-05-26 14:49:10 +02:00
}
2013-04-25 14:35:32 +02:00
//---------------------------------------------------------
// updateSynthesizerState
// collect all controller events between tick1 and tick2
// and send them to the synthesizer
2014-10-01 20:17:30 +02:00
// Called from RT thread
2013-04-25 14:35:32 +02:00
//---------------------------------------------------------
void Seq : : updateSynthesizerState ( int tick1 , int tick2 )
{
if ( tick1 > tick2 )
tick1 = 0 ;
2014-10-01 20:17:30 +02:00
// Making a local copy of events to avoid touching it
// from different threads at the same time
EventMap ev = events ;
EventMap : : const_iterator i1 = ev . lower_bound ( tick1 ) ;
EventMap : : const_iterator i2 = ev . upper_bound ( tick2 ) ;
2013-04-25 14:35:32 +02:00
for ( ; i1 ! = i2 ; + + i1 ) {
if ( i1 - > second . type ( ) = = ME_CONTROLLER )
2014-07-29 16:31:44 +02:00
playEvent ( i1 - > second , 0 ) ;
2013-04-25 14:35:32 +02:00
}
}
2013-05-03 11:37:28 +02:00
//---------------------------------------------------------
// curTempo
//---------------------------------------------------------
double Seq : : curTempo ( ) const
{
2018-08-06 14:41:11 +02:00
if ( playPos ! = events . end ( ) )
2018-07-10 14:57:05 +02:00
return cs ? cs - > tempomap ( ) - > tempo ( playPos - > first ) : 0.0 ;
2018-08-06 14:41:11 +02:00
return 0.0 ;
2013-05-03 11:37:28 +02:00
}
2013-08-09 01:20:07 +02:00
//---------------------------------------------------------
// set Loop in position
//---------------------------------------------------------
2013-08-09 06:57:26 +02:00
2013-08-09 01:20:07 +02:00
void Seq : : setLoopIn ( )
{
2013-08-19 08:53:30 +02:00
int tick ;
2014-06-03 17:14:35 +02:00
if ( state = = Transport : : PLAY ) { // If in playback mode, set the In position where note is being played
2013-09-03 21:01:03 +02:00
auto ppos = playPos ;
if ( ppos ! = events . cbegin ( ) )
- - ppos ; // We have to go back one pos to get the correct note that has just been played
2013-09-12 15:57:14 +02:00
tick = cs - > repeatList ( ) - > utick2tick ( ppos - > first ) ;
2013-09-03 21:01:03 +02:00
}
2013-10-18 12:21:01 +02:00
else
2013-09-03 21:01:03 +02:00
tick = cs - > pos ( ) ; // Otherwise, use the selected note.
if ( tick > = cs - > loopOutTick ( ) ) // If In pos >= Out pos, reset Out pos to end of score
2015-09-13 20:27:57 +02:00
cs - > setPos ( POS : : RIGHT , cs - > lastMeasure ( ) - > endTick ( ) ) ;
2013-10-18 12:21:01 +02:00
cs - > setPos ( POS : : LEFT , tick ) ;
2013-08-09 01:20:07 +02:00
}
2013-08-19 08:53:30 +02:00
2013-08-09 01:20:07 +02:00
//---------------------------------------------------------
2013-09-03 21:01:03 +02:00
// set Loop Out position
2013-08-09 01:20:07 +02:00
//---------------------------------------------------------
2013-08-09 06:57:26 +02:00
2013-08-09 01:20:07 +02:00
void Seq : : setLoopOut ( )
{
2013-08-19 08:53:30 +02:00
int tick ;
2014-06-03 17:14:35 +02:00
if ( state = = Transport : : PLAY ) { // If in playback mode, set the Out position where note is being played
2013-09-12 15:57:14 +02:00
tick = cs - > repeatList ( ) - > utick2tick ( playPos - > first ) ;
2013-09-03 21:01:03 +02:00
}
2013-10-18 12:21:01 +02:00
else
2014-07-07 17:31:41 +02:00
tick = cs - > pos ( ) + cs - > inputState ( ) . ticks ( ) ; // Otherwise, use the selected note.
2013-09-03 21:01:03 +02:00
if ( tick < = cs - > loopInTick ( ) ) // If Out pos <= In pos, reset In pos to beginning of score
2013-10-18 12:21:01 +02:00
cs - > setPos ( POS : : LEFT , 0 ) ;
2014-09-22 04:55:58 +02:00
else
2015-09-13 20:27:57 +02:00
if ( tick > cs - > lastMeasure ( ) - > endTick ( ) )
tick = cs - > lastMeasure ( ) - > endTick ( ) ;
2013-10-18 12:21:01 +02:00
cs - > setPos ( POS : : RIGHT , tick ) ;
2014-06-03 17:14:35 +02:00
if ( state = = Transport : : PLAY )
2014-06-03 10:46:57 +02:00
guiToSeq ( SeqMsg ( SeqMsgId : : SEEK , tick ) ) ;
2013-08-22 18:29:25 +02:00
}
2013-11-28 16:13:41 +01:00
void Seq : : setPos ( POS , unsigned tick )
{
2014-03-04 16:48:06 +01:00
qDebug ( " seq: setPos %d " , tick ) ;
2013-11-28 16:13:41 +01:00
}
2013-08-22 18:29:25 +02:00
//---------------------------------------------------------
// set Loop In/Out position based on the selection
//---------------------------------------------------------
void Seq : : setLoopSelection ( )
{
cs - > setLoopInTick ( cs - > selection ( ) . tickStart ( ) ) ;
cs - > setLoopOutTick ( cs - > selection ( ) . tickEnd ( ) ) ;
2013-08-13 05:01:38 +02:00
}
2014-05-30 23:18:52 +02:00
2014-06-18 21:36:53 +02:00
//---------------------------------------------------------
// Called after tempo or time signature
// changed while playback
//---------------------------------------------------------
2014-05-30 23:18:52 +02:00
void Seq : : handleTimeSigTempoChanged ( )
{
2014-06-18 21:36:53 +02:00
_driver - > handleTimeSigTempoChanged ( ) ;
2014-05-30 23:18:52 +02:00
}
2017-05-14 17:43:28 +02:00
//---------------------------------------------------------
// setInitialMillisecondTimestampWithLatency
// Called whenever seq->process() starts.
// Sets a starting reference time for which subsequent PortMidi events will be offset from.
// Time is relative to the start of PortMidi's initialization.
//---------------------------------------------------------
void Seq : : setInitialMillisecondTimestampWithLatency ( )
{
# ifdef USE_PORTMIDI
2017-11-29 08:21:36 +01:00
initialMillisecondTimestampWithLatency = Pt_Time ( ) + preferences . getInt ( PREF_IO_PORTMIDI_OUTPUTLATENCYMILLISECONDS ) ;
//qDebug("PortMidi initialMillisecondTimestampWithLatency: %d = %d + %d", initialMillisecondTimestampWithLatency, unsigned(Pt_Time()), preferences.getInt(PREF_IO_PORTMIDI_OUTPUTLATENCYMILLISECONDS));
2017-05-14 17:43:28 +02:00
# endif
}
//---------------------------------------------------------
// getCurrentMillisecondTimestampWithLatency
// Called when midi messages are sent to PortMidi device.
// Returns the time in milliseconds of the current play cursor.
// Time is relative to the start of PortMidi's initialization.
//---------------------------------------------------------
unsigned Seq : : getCurrentMillisecondTimestampWithLatency ( unsigned framePos ) const
{
# ifdef USE_PORTMIDI
unsigned playTimeMilliseconds = unsigned ( framePos * 1000 ) / unsigned ( MScore : : sampleRate ) ;
//qDebug("PortMidi timestamp = %d + %d", initialMillisecondTimestampWithLatency, playTimeMilliseconds);
return initialMillisecondTimestampWithLatency + playTimeMilliseconds ;
# else
qDebug ( " Shouldn't be using this function if not using PortMidi " ) ;
return 0 ;
# endif
}
2013-08-19 08:53:30 +02:00
}