Hello

These patches introduce some new features in time for the freeze (I hope.)

The most important is a fix-up of the pattern mode: Fixed some timing problems 
with jack, and added a "live editing mode", which makes the selected pattern 
always play in pattern mode, similar to what Scott proposed. The feature can 
be turned off / on during playback by pressing "L". It's quite neat I 
think :^)

The other patch is a minor convenience: To rename a pattern, double-clicking 
its name in the song editor, a line-edit will appear _inside the pattern 
list_, instead of in a small dialog window. The dialog is still accessible 
from the right-click menu, should it be necessary to add some other property 
(than the name) to it later on.

Sebastian, I don't know if you've tried to merged the patch I sent in earlier; 
in any case I think there are some lines in the old patch (perhaps changes in 
jack_output.cpp and hydrogen.cpp), that are also in the new one.  I'm not 
very big on svn and merging stuff, but I hope you can make it without too 
much hassle...

Cheers

Jakob Lund.
Index: gui/src/PatternPropertiesDialog.cpp
===================================================================
--- gui/src/PatternPropertiesDialog.cpp	(revision 220)
+++ gui/src/PatternPropertiesDialog.cpp	(working copy)
@@ -71,32 +71,30 @@
 /**
  * Do some name check
  */
-void PatternPropertiesDialog::on_patternNameTxt_textChanged() {
-
-	bool valid = true;
-
-	QString pattName = patternNameTxt->text();
+bool PatternPropertiesDialog::nameCheck( QString pattName )
+{
 	if (pattName == "") {
-		valid = false;
+		return false;
 	}
-
-	Hydrogen *engine = Hydrogen::get_instance();
-	Song *song = engine->getSong();
-	PatternList *patternList = song->get_pattern_list();
-
+	PatternList *patternList = Hydrogen::get_instance()->getSong()->get_pattern_list();
+	
 	for (uint i = 0; i < patternList->get_size(); i++) {
-		Pattern *pat = patternList->get(i);
-
-		if ( pat->get_name() == pattName) {
-			valid = false;
-			break;
+		if ( patternList->get(i)->get_name() == pattName) {
+			return false;
 		}
 	}
+	return true;
+}
 
-	if (valid) {
+
+void PatternPropertiesDialog::on_patternNameTxt_textChanged() {
+
+	if ( nameCheck( patternNameTxt->text() )) {
 		okBtn->setEnabled(true);
 	}
 	else {
 		okBtn->setEnabled(false);
 	}
 }
+
+
Index: gui/src/PatternPropertiesDialog.h
===================================================================
--- gui/src/PatternPropertiesDialog.h	(revision 220)
+++ gui/src/PatternPropertiesDialog.h	(working copy)
@@ -41,6 +41,7 @@
 
 		/** Destructor */
 		~PatternPropertiesDialog();
+		static bool nameCheck( QString );
 
 
 	private slots:
Index: gui/src/SongEditor/SongEditor.cpp
===================================================================
--- gui/src/SongEditor/SongEditor.cpp	(revision 220)
+++ gui/src/SongEditor/SongEditor.cpp	(working copy)
@@ -637,6 +637,14 @@
 	m_nWidth = 200;
 	m_nGridHeight = 18;
 	setAttribute(Qt::WA_NoBackground);
+	
+	patternBeingEdited = NULL;
+	
+	line = new QLineEdit( "Inline Pattern Name", this );
+	line->setFrame( false );
+	line->hide();
+	connect( line, SIGNAL(editingFinished()), this, SLOT(inlineEditingFinished()) );
+	connect( line, SIGNAL(returnPressed()), this, SLOT(inlineEditingEntered()) );
 
 	this->resize( m_nWidth, m_nInitialHeight );
 
@@ -686,26 +694,27 @@
 	if ( row >= (int)patternList->get_size() ) {
 		return;
 	}
-	engine->setSelectedPatternNumber( row );
 
 	if ( ev->button() == Qt::MidButton || ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::RightButton || ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::LeftButton ){
 		togglePattern( row );
-	}
-	else if (ev->button() == Qt::RightButton)  {
-/*
-		if ( song->getMode() == Song::PATTERN_MODE ) {
-
-			PatternList *pCurrentPatternList = engine->getCurrentPatternList();
-			if ( pCurrentPatternList->get_size() == 0 ) {
-				// nessun pattern e' attivo. seleziono subito questo.
-				pCurrentPatternList->add( patternList->get( row ) );
+	} else {
+		engine->setSelectedPatternNumber( row );
+		if (ev->button() == Qt::RightButton)  {
+	/*
+			if ( song->getMode() == Song::PATTERN_MODE ) {
+	
+				PatternList *pCurrentPatternList = engine->getCurrentPatternList();
+				if ( pCurrentPatternList->get_size() == 0 ) {
+					// nessun pattern e' attivo. seleziono subito questo.
+					pCurrentPatternList->add( patternList->get( row ) );
+				}
+				else {
+					engine->setNextPattern( row );
+				}
 			}
-			else {
-				engine->setNextPattern( row );
-			}
+	*/
+			m_pPatternPopup->popup( QPoint( ev->globalX(), ev->globalY() ) );
 		}
-*/
-		m_pPatternPopup->popup( QPoint( ev->globalX(), ev->globalY() ) );
 	}
 
 	createBackground();
@@ -753,9 +762,11 @@
 void SongEditorPatternList::mouseDoubleClickEvent( QMouseEvent *ev )
 {
 	int row = (ev->y() / m_nGridHeight);
+	inlineEditPatternName( row );
+}
 
-// 	WARNINGLOG( "double clicked " + to_string( row ) );
-
+void SongEditorPatternList::inlineEditPatternName( int row )
+{
 	Hydrogen *engine = Hydrogen::get_instance();
 	Song *song = engine->getSong();
 	PatternList *patternList = song->get_pattern_list();
@@ -763,13 +774,36 @@
 	if ( row >= (int)patternList->get_size() ) {
 		return;
 	}
-	engine->setSelectedPatternNumber(row);
+	patternBeingEdited = patternList->get( row );
+	line->setGeometry( 23, row * m_nGridHeight , m_nWidth - 23, m_nGridHeight  );
+	line->setText( patternBeingEdited->get_name() );
+	line->selectAll();
+	line->show();
+	line->setFocus();
+}
 
-	patternPopup_properties();
+void SongEditorPatternList::inlineEditingEntered()
+{
+	assert( patternBeingEdited != NULL );
+	if ( PatternPropertiesDialog::nameCheck( line->text() ) )
+	{
+		patternBeingEdited->set_name( line->text() );
+		Hydrogen::get_instance()->getSong()->__is_modified = true;
+		EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );
+		createBackground();
+		update();
+	}
+// 	patternBeingEdited = NULL;
 }
 
 
+void SongEditorPatternList::inlineEditingFinished()
+{
+	patternBeingEdited = NULL;
+	line->hide();
+}
 
+
 void SongEditorPatternList::paintEvent( QPaintEvent *ev )
 {
 	QPainter painter(this);
@@ -974,8 +1008,8 @@
 
 	PatternPropertiesDialog *dialog = new PatternPropertiesDialog(this, pattern);
 	if (dialog->exec() == QDialog::Accepted) {
-		Hydrogen *engine = Hydrogen::get_instance();
-		Song *song = engine->getSong();
+// 		Hydrogen *engine = Hydrogen::get_instance();
+// 		Song *song = engine->getSong();
 		song->__is_modified = true;
 		EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );
 		createBackground();
@@ -1303,6 +1337,11 @@
 	if ( column >= (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) {
 		return;
 	}
+	
+	// disabling son relocates while in pattern mode as it causes weird behaviour. (jakob lund)
+	if ( Hydrogen::get_instance()->getSong()->get_mode() == Song::PATTERN_MODE ) {
+		return;
+	}
 
 	int nPatternPos = Hydrogen::get_instance()->getPatternPos();
 	if ( nPatternPos != column ) {
Index: gui/src/SongEditor/SongEditor.h
===================================================================
--- gui/src/SongEditor/SongEditor.h	(revision 220)
+++ gui/src/SongEditor/SongEditor.h	(working copy)
@@ -118,6 +118,8 @@
 		void patternPopup_delete();
 		void patternPopup_copy();
 		void patternPopup_fill();
+		void inlineEditingFinished();
+		void inlineEditingEntered();
 
 
 	private:
@@ -134,6 +136,9 @@
 		QPixmap m_playingPattern_off_Pixmap;
 
 		QMenu *m_pPatternPopup;
+		QLineEdit *line;
+		H2Core::Pattern *patternBeingEdited;
+		void inlineEditPatternName( int row );
 
 		virtual void mousePressEvent( QMouseEvent *ev );
 		virtual void mouseDoubleClickEvent( QMouseEvent *ev );
Index: gui/src/MainForm.cpp
===================================================================
--- gui/src/MainForm.cpp	(revision 220)
+++ gui/src/MainForm.cpp	(working copy)
@@ -400,7 +400,6 @@
 				ERRORLOG( "Unknown return code: " + to_string( res ) );
 		}
 	}
-
 	closeAll();
 	return true;
 }
@@ -510,6 +509,7 @@
 	LocalFileMng mng;
 	bool saved = false;
 	saved = song->save( filename );
+	
 
 	if(! saved) {
 		QMessageBox::warning( this, "Hydrogen", trUtf8("Could not save song.") );
@@ -977,7 +977,6 @@
 
 
 void MainForm::closeAll() {
-
 	// save window properties in the preferences files
 	Preferences *pref = Preferences::getInstance();
 
@@ -1318,6 +1317,13 @@
 				return TRUE;
 				break;
 			
+			case Qt::Key_L :
+				Hydrogen::get_instance()->togglePlaysSelected();
+				QString msg = Preferences::getInstance()->patternModePlaysSelected() ? "Live Edit Mode ON" : "Live Edit Mode OFF";
+				HydrogenApp::getInstance()->setStatusBarMessage( msg, 5000 );
+				
+				return TRUE;
+			
 		// 	QAccel *a = new QAccel( this );
 // 	a->connectItem( a->insertItem(Key_S + CTRL), this, SLOT( onSaveAccelEvent() ) );
 // 	a->connectItem( a->insertItem(Key_O + CTRL), this, SLOT( onOpenAccelEvent() ) );
Index: gui/src/PreferencesDialog.cpp
===================================================================
--- gui/src/PreferencesDialog.cpp	(revision 220)
+++ gui/src/PreferencesDialog.cpp	(working copy)
@@ -224,6 +224,7 @@
 
 	// General tab
 	restoreLastUsedSongCheckbox->setChecked( pPref->isRestoreLastSongEnabled() );
+	patternModeFollowsSelection->setChecked( pPref->patternModePlaysSelected() );
 
 	m_bNeedDriverRestart = false;
 }
@@ -357,6 +358,7 @@
 
 	// General tab
 	pPref->setRestoreLastSongEnabled( restoreLastUsedSongCheckbox->isChecked() );
+	pPref->setPatternModePlaysSelected( patternModeFollowsSelection->isChecked() );
 
 	pPref->savePreferences();
 
Index: gui/src/PatternPropertiesDialog.h
===================================================================
--- gui/src/PatternPropertiesDialog.h	(revision 220)
+++ gui/src/PatternPropertiesDialog.h	(working copy)
@@ -41,6 +41,7 @@
 
 		/** Destructor */
 		~PatternPropertiesDialog();
+		static bool nameCheck( QString );
 
 
 	private slots:
Index: gui/src/UI/PreferencesDialog_UI.ui
===================================================================
--- gui/src/UI/PreferencesDialog_UI.ui	(revision 220)
+++ gui/src/UI/PreferencesDialog_UI.ui	(working copy)
@@ -25,18 +25,9 @@
     <property name="spacing" >
      <number>6</number>
     </property>
-    <property name="leftMargin" >
+    <property name="margin" >
      <number>0</number>
     </property>
-    <property name="topMargin" >
-     <number>0</number>
-    </property>
-    <property name="rightMargin" >
-     <number>0</number>
-    </property>
-    <property name="bottomMargin" >
-     <number>0</number>
-    </property>
     <item>
      <spacer>
       <property name="orientation" >
@@ -45,7 +36,7 @@
       <property name="sizeType" >
        <enum>QSizePolicy::Expanding</enum>
       </property>
-      <property name="sizeHint" >
+      <property name="sizeHint" stdset="0" >
        <size>
         <width>184</width>
         <height>16</height>
@@ -111,7 +102,7 @@
       <property name="sizeType" >
        <enum>QSizePolicy::Expanding</enum>
       </property>
-      <property name="sizeHint" >
+      <property name="sizeHint" stdset="0" >
        <size>
         <width>183</width>
         <height>16</height>
@@ -140,9 +131,17 @@
     <enum>QTabWidget::Rounded</enum>
    </property>
    <property name="currentIndex" >
-    <number>2</number>
+    <number>0</number>
    </property>
    <widget class="QWidget" name="tab" >
+    <property name="geometry" >
+     <rect>
+      <x>0</x>
+      <y>0</y>
+      <width>529</width>
+      <height>341</height>
+     </rect>
+    </property>
     <attribute name="title" >
      <string>&amp;General</string>
     </attribute>
@@ -168,8 +167,29 @@
       <string>Alt+R</string>
      </property>
     </widget>
+    <widget class="QCheckBox" name="patternModeFollowsSelection" >
+     <property name="geometry" >
+      <rect>
+       <x>10</x>
+       <y>60</y>
+       <width>511</width>
+       <height>31</height>
+      </rect>
+     </property>
+     <property name="text" >
+      <string>Always play selected pattern in Pattern Mode</string>
+     </property>
+    </widget>
    </widget>
    <widget class="QWidget" name="tab" >
+    <property name="geometry" >
+     <rect>
+      <x>0</x>
+      <y>0</y>
+      <width>529</width>
+      <height>341</height>
+     </rect>
+    </property>
     <attribute name="title" >
      <string>Audio &amp;System</string>
     </attribute>
@@ -218,28 +238,16 @@
        <x>10</x>
        <y>50</y>
        <width>291</width>
-       <height>114</height>
+       <height>131</height>
       </rect>
      </property>
      <layout class="QGridLayout" >
-      <property name="leftMargin" >
+      <property name="margin" >
        <number>0</number>
       </property>
-      <property name="topMargin" >
-       <number>0</number>
-      </property>
-      <property name="rightMargin" >
-       <number>0</number>
-      </property>
-      <property name="bottomMargin" >
-       <number>0</number>
-      </property>
-      <property name="horizontalSpacing" >
+      <property name="spacing" >
        <number>6</number>
       </property>
-      <property name="verticalSpacing" >
-       <number>6</number>
-      </property>
       <item row="1" column="1" >
        <widget class="QSpinBox" name="bufferSizeSpinBox" >
         <property name="minimumSize" >
@@ -374,24 +382,12 @@
       </rect>
      </property>
      <layout class="QGridLayout" >
-      <property name="leftMargin" >
+      <property name="margin" >
        <number>0</number>
       </property>
-      <property name="topMargin" >
-       <number>0</number>
-      </property>
-      <property name="rightMargin" >
-       <number>0</number>
-      </property>
-      <property name="bottomMargin" >
-       <number>0</number>
-      </property>
-      <property name="horizontalSpacing" >
+      <property name="spacing" >
        <number>6</number>
       </property>
-      <property name="verticalSpacing" >
-       <number>6</number>
-      </property>
       <item row="0" column="1" >
        <widget class="QSpinBox" name="maxVoicesTxt" >
         <property name="minimumSize" >
@@ -492,6 +488,14 @@
     </widget>
    </widget>
    <widget class="QWidget" name="tab" >
+    <property name="geometry" >
+     <rect>
+      <x>0</x>
+      <y>0</y>
+      <width>529</width>
+      <height>341</height>
+     </rect>
+    </property>
     <attribute name="title" >
      <string>&amp;Midi System</string>
     </attribute>
@@ -501,28 +505,16 @@
        <x>10</x>
        <y>10</y>
        <width>521</width>
-       <height>117</height>
+       <height>123</height>
       </rect>
      </property>
      <layout class="QGridLayout" >
-      <property name="leftMargin" >
+      <property name="margin" >
        <number>0</number>
       </property>
-      <property name="topMargin" >
-       <number>0</number>
-      </property>
-      <property name="rightMargin" >
-       <number>0</number>
-      </property>
-      <property name="bottomMargin" >
-       <number>0</number>
-      </property>
-      <property name="horizontalSpacing" >
+      <property name="spacing" >
        <number>6</number>
       </property>
-      <property name="verticalSpacing" >
-       <number>6</number>
-      </property>
       <item row="1" column="0" >
        <widget class="QLabel" name="textLabel1_3_2" >
         <property name="minimumSize" >
@@ -678,6 +670,14 @@
     </widget>
    </widget>
    <widget class="QWidget" name="tab" >
+    <property name="geometry" >
+     <rect>
+      <x>0</x>
+      <y>0</y>
+      <width>529</width>
+      <height>341</height>
+     </rect>
+    </property>
     <attribute name="title" >
      <string>&amp;Appearance</string>
     </attribute>
@@ -704,24 +704,12 @@
       </rect>
      </property>
      <layout class="QGridLayout" >
-      <property name="leftMargin" >
+      <property name="margin" >
        <number>0</number>
       </property>
-      <property name="topMargin" >
-       <number>0</number>
-      </property>
-      <property name="rightMargin" >
-       <number>0</number>
-      </property>
-      <property name="bottomMargin" >
-       <number>0</number>
-      </property>
-      <property name="horizontalSpacing" >
+      <property name="spacing" >
        <number>6</number>
       </property>
-      <property name="verticalSpacing" >
-       <number>6</number>
-      </property>
       <item row="0" column="0" >
        <widget class="QLabel" name="applicationFontLbl" >
         <property name="minimumSize" >
@@ -776,24 +764,12 @@
       </rect>
      </property>
      <layout class="QGridLayout" >
-      <property name="leftMargin" >
+      <property name="margin" >
        <number>0</number>
       </property>
-      <property name="topMargin" >
-       <number>0</number>
-      </property>
-      <property name="rightMargin" >
-       <number>0</number>
-      </property>
-      <property name="bottomMargin" >
-       <number>0</number>
-      </property>
-      <property name="horizontalSpacing" >
+      <property name="spacing" >
        <number>6</number>
       </property>
-      <property name="verticalSpacing" >
-       <number>6</number>
-      </property>
       <item row="0" column="1" >
        <widget class="QPushButton" name="selectMixerFontBtn" >
         <property name="minimumSize" >
Index: libs/hydrogen/include/hydrogen/Preferences.h
===================================================================
--- libs/hydrogen/include/hydrogen/Preferences.h	(revision 220)
+++ libs/hydrogen/include/hydrogen/Preferences.h	(working copy)
@@ -417,6 +417,13 @@
 	UIStyle* getDefaultUIStyle() {
 		return m_pDefaultUIStyle;
 	}
+	
+	bool patternModePlaysSelected() {
+		return m_bPatternModePlaysSelected;
+	}
+	void setPatternModePlaysSelected( bool b ) {
+		m_bPatternModePlaysSelected = b;
+	}
 
 private:
 	static Preferences *instance;
@@ -428,6 +435,7 @@
 	QString demoPath;
 
 	//___ General properties ___
+	bool m_bPatternModePlaysSelected; /// Behaviour of Pattern Mode
 	bool restoreLastSong;		///< Restore last song?
 	bool m_bShowDevelWarning;	///< Show development version warning?
 	QString lastSongFilename;	///< Last song used
Index: libs/hydrogen/include/hydrogen/hydrogen.h
===================================================================
--- libs/hydrogen/include/hydrogen/hydrogen.h	(revision 220)
+++ libs/hydrogen/include/hydrogen/hydrogen.h	(working copy)
@@ -64,6 +64,7 @@
 	void midi_noteOff( Note *note );
 
 	void sequencer_setNextPattern( int pos, bool appendPattern, bool deletePattern );
+	void togglePlaysSelected( void );
 // ***** ~SEQUENCER ********
 
 	/// Set current song
@@ -99,6 +100,8 @@
 
 	int getPatternPos();
 	void setPatternPos( int pos );
+	
+	void triggerRelocateDuringPlay();
 
 	long getTickForPosition( int );
 
Index: libs/hydrogen/src/preferences.cpp
===================================================================
--- libs/hydrogen/src/preferences.cpp	(revision 220)
+++ libs/hydrogen/src/preferences.cpp	(working copy)
@@ -222,6 +222,8 @@
 			//m_sLadspaPath = LocalFileMng::readXmlString( this, rootNode, "ladspaPath", m_sLadspaPath );
 			m_bShowDevelWarning = LocalFileMng::readXmlBool( rootNode, "showDevelWarning", m_bShowDevelWarning );
 			restoreLastSong = LocalFileMng::readXmlBool( rootNode, "restoreLastSong", restoreLastSong );
+			m_bPatternModePlaysSelected = LocalFileMng::readXmlBool( rootNode, "patternModePlaysSelected", TRUE );
+
 			hearNewNotes = LocalFileMng::readXmlBool( rootNode, "hearNewNotes", hearNewNotes );
 			recordEvents = LocalFileMng::readXmlBool( rootNode, "recordEvents", recordEvents );
 			quantizeEvents = LocalFileMng::readXmlBool( rootNode, "quantizeEvents", quantizeEvents );
@@ -523,6 +525,8 @@
 
 	////// GENERAL ///////
 	LocalFileMng::writeXmlString( &rootNode, "restoreLastSong", restoreLastSong ? "true": "false" );
+	
+	LocalFileMng::writeXmlString( &rootNode, "patternModePlaysSelected", m_bPatternModePlaysSelected ? "true": "false" );
 
 	//show development version warning
 	LocalFileMng::writeXmlString( &rootNode, "showDevelWarning", m_bShowDevelWarning ? "true": "false" );
Index: libs/hydrogen/src/hydrogen.cpp
===================================================================
--- libs/hydrogen/src/hydrogen.cpp	(revision 220)
+++ libs/hydrogen/src/hydrogen.cpp	(working copy)
@@ -362,7 +362,6 @@
 		return 0;	// FIXME!!
 	}
 
-
 	//Preferences *preferencesMng = Preferences::getInstance();
 	m_fMasterPeak_L = 0.0f;
 	m_fMasterPeak_R = 0.0f;
@@ -582,7 +581,7 @@
 	if ( bLoopMode ) {
 		loop = true;
 	}
-
+	
 	m_nSongPos = findPatternInTick( tickNumber_start, loop, &m_nPatternStartTick );
 //	sprintf(tmp, "[audioEngine_seek()] m_nSongPos = %d", m_nSongPos);
 //	hydrogenInstance->infoLog(tmp);
@@ -1023,7 +1022,7 @@
 	// plus lookahead. lookahead should be equal or greater than the nLeadLagFactor + nMaxTimeHumanize.
 	int lookahead = nLeadLagFactor + nMaxTimeHumanize + 1;
 	if ( framepos == 0 ) {
-		tickNumber_start = (int)( framepos / m_pAudioDriver->m_transport.m_nTickSize );
+		tickNumber_start = 0; // a.k.a.: (int)( framepos / m_pAudioDriver->m_transport.m_nTickSize );
 	}
 	else {
 		tickNumber_start = (int)( (framepos + lookahead) / m_pAudioDriver->m_transport.m_nTickSize );
@@ -1032,8 +1031,22 @@
 
 	int tick = tickNumber_start;
 
+// 	_WARNINGLOG( "Lookahead: " + to_string( lookahead /  m_pAudioDriver->m_transport.m_nTickSize ) );
 	// get initial timestamp for first tick
 	gettimeofday( &m_currentTickTime, NULL );
+	
+	Pattern * selectedPatternWasAdded = NULL;
+	
+	// The Preferences object isn't thread safe, so we shouldnt access it here unless we're in the playing state.
+	if ( m_audioEngineState == STATE_PLAYING ) {
+		if ( m_pSong->get_mode() == Song::PATTERN_MODE && Preferences::getInstance()->patternModePlaysSelected() ) {
+			Pattern * pSelectedPattern = m_pSong->get_pattern_list()->get(m_nSelectedPatternNumber);
+			if ( ( m_pPlayingPatterns->del( pSelectedPattern ) ) == NULL ) {
+				selectedPatternWasAdded = pSelectedPattern;
+			}
+			m_pPlayingPatterns->add( pSelectedPattern );
+		}
+	}
 
 	while ( tick <= tickNumber_end ) {
 		if ( tick == nLastTick ) {
@@ -1062,7 +1075,11 @@
 			continue;
 		}
 
+// 		if ( m_nPatternStartTick == -1 ) { // for debugging pattern mode :s
+// 			_WARNINGLOG( "m_nPatternStartTick == -1; tick = " + to_string( tick ) );
+// 		}
 
+
 		// SONG MODE
 		if ( m_pSong->get_mode() == Song::SONG_MODE ) {
 			if ( m_pSong->get_pattern_group_vector()->size() == 0 ) {
@@ -1102,7 +1119,7 @@
 				}
 			}
 		}
-
+		
 		// PATTERN MODE
 		else if ( m_pSong->get_mode() == Song::PATTERN_MODE )	{
 			//hydrogenInstance->warningLog( "pattern mode not implemented yet" );
@@ -1110,6 +1127,7 @@
 			// per ora considero solo il primo pattern, se ce ne saranno piu' di uno
 			// bisognera' prendere quello piu' piccolo
 
+			//m_nPatternTickPosition = tick % m_pCurrentPattern->getSize();
 			int nPatternSize = MAX_NOTES;
 
 			if ( m_pPlayingPatterns->get_size() != 0 ) {
@@ -1133,22 +1151,33 @@
 											}
 											m_pPlayingPatterns->add( m_pNextPattern );
 										}*/
-					_WARNINGLOG( "uh-oh, next patterns..." );
+// 					_WARNINGLOG( "uh-oh, next patterns..." );
 					Pattern * p;
 					for ( uint i = 0; i < m_pNextPatterns->get_size(); i++ ) {
 						p = m_pNextPatterns->get( i );
-						_WARNINGLOG( QString( "Got pattern # %1" ).arg( i + 1 ) );
+// 						_WARNINGLOG( QString( "Got pattern # %1" ).arg( i + 1 ) );
 						// if the pattern isn't playing already, start it now.
-						if ( ( m_pPlayingPatterns->del( p ) ) == NULL )
+						if ( selectedPatternWasAdded == p )
+							selectedPatternWasAdded = NULL;
+						else if ( m_pSong->get_pattern_list()->get( m_nSelectedPatternNumber ) == p && Preferences::getInstance()->patternModePlaysSelected() )
+							selectedPatternWasAdded = p;
+						else if ( ( m_pPlayingPatterns->del( p ) ) == NULL ) {
 							m_pPlayingPatterns->add( p );
+						}
 					}
 					m_pNextPatterns->clear();
 					bSendPatternChange = true;
 				}
-				m_nPatternStartTick = tick;
+				if ( m_nPatternStartTick == -1 ) {
+					m_nPatternStartTick = tick - (tick % nPatternSize);
+// 					_WARNINGLOG( "set Pattern Start Tick to " + to_string( m_nPatternStartTick ) );
+				} else {
+					m_nPatternStartTick = tick;
+				}
 			}
-			//m_nPatternTickPosition = tick % m_pCurrentPattern->getSize();
-			m_nPatternTickPosition = tick % nPatternSize;
+// 			m_nPatternTickPosition = tick % nPatternSize;
+			m_nPatternTickPosition = tick - m_nPatternStartTick;
+			assert( m_nPatternTickPosition < nPatternSize );
 		}
 		/*
 					else {
@@ -1162,9 +1191,11 @@
 
 
 		// metronome
-		if (  ( m_nPatternStartTick == tick ) || ( ( tick - m_nPatternStartTick ) % 48 == 0 ) ) {
+// 		if (  ( m_nPatternStartTick == tick ) || ( ( tick - m_nPatternStartTick ) % 48 == 0 ) ) {
+		if ( m_nPatternTickPosition % 48 == 0 ) {
 			float fPitch;
 			float fVelocity;
+// 			_INFOLOG( "Beat: " + to_string(m_nPatternTickPosition / 48 + 1) + "@ " + to_string( tick ) );
 			if ( m_nPatternTickPosition == 0 ) {
 				fPitch = 3;
 				fVelocity = 1.0;
@@ -1228,6 +1259,8 @@
 		}
 		++tick;
 	}
+	
+	if ( selectedPatternWasAdded != NULL ) m_pPlayingPatterns->del( selectedPatternWasAdded );
 
 	// audioEngine_process must send the pattern change event after mutex unlock
 	if ( bSendPatternChange ) {
@@ -2258,10 +2291,8 @@
 		int dummy;
 		m_nSongPos = findPatternInTick( totalTick, m_pSong->is_loop_enabled(), &dummy );
 	}
-
 	m_pAudioDriver->locate( ( int ) ( totalTick * m_pAudioDriver->m_transport.m_nTickSize ) );
 
-
 	AudioEngine::get_instance()->unlock();
 }
 
@@ -2407,9 +2438,17 @@
 {
 	// FIXME: controllare se e' valido..
 	if ( nPat == m_nSelectedPatternNumber )	return;
+	
+	
+	if ( Preferences::getInstance()->patternModePlaysSelected() ) {
+		AudioEngine::get_instance()->lock( "Hydrogen::setSelectedPatternNumber" );
+	
+		m_nSelectedPatternNumber = nPat;
+		AudioEngine::get_instance()->unlock();
+	} else {
+		m_nSelectedPatternNumber = nPat;
+	}
 
-	m_nSelectedPatternNumber = nPat;
-
 	EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );
 }
 
@@ -2595,7 +2634,9 @@
 
 long Hydrogen::getTickForHumanPosition( int humanpos )
 {
-	int nPatternGroups = m_pSong->get_pattern_group_vector()->size();
+	std::vector< PatternList* > * columns = m_pSong->get_pattern_group_vector();
+	
+	int nPatternGroups = columns->size();
 	if ( humanpos >= nPatternGroups ) {
 		if ( m_pSong->is_loop_enabled() ) {
 			humanpos = humanpos % nPatternGroups;
@@ -2604,10 +2645,21 @@
 		}
 	}
 
-	std::vector<PatternList*> *pColumns = m_pSong->get_pattern_group_vector();
-	long humanTick = 0;
-	int nPatternSize;
-	Pattern *pPattern = NULL;
+// 	std::vector<PatternList*> *pColumns = m_pSong->get_pattern_group_vector()[ humanpos - 1 ].get( 0 )->get_lenght();
+	
+	ERRORLOG( "Kick me!" );
+	if ( humanpos == 0 ) return 0;
+	Pattern *pPattern = columns->at( humanpos - 1 )->get( 0 );
+	if ( pPattern ) {
+		return pPattern->get_lenght();
+	} else {
+		return MAX_NOTES;
+	}
+// 	int nPatternSize;
+	
+// 	pColumns
+	
+/*	Pattern *pPattern = NULL;
 	for ( int i = 0; i < humanpos; ++i ) {
 		PatternList *pColumn = ( *pColumns )[ i ];
 		pPattern = pColumn->get( 0 );
@@ -2618,8 +2670,8 @@
 		}
 
 		humanTick = nPatternSize;
-	}
-	return humanTick;
+	}*/
+// 	return humanTick;
 }
 
 
@@ -2636,6 +2688,25 @@
 	m_nHumantimeFrames = nFrames + m_nHumantimeFrames;
 }
 //~ jack transport master
+void Hydrogen::triggerRelocateDuringPlay() {
+	m_nPatternStartTick = -1; // This forces the barline position to be recalculated in Pattern Mode.
+}
 
+void Hydrogen::togglePlaysSelected() {
+	if ( getSong()->get_mode() != Song::PATTERN_MODE )
+		return;
+	Preferences * P = Preferences::getInstance();
+	
+	AudioEngine::get_instance()->lock( "Live mode" );
+	
+	bool isPlaysSelected = P->patternModePlaysSelected();
+	
+	
+	P->setPatternModePlaysSelected( !isPlaysSelected );
+	
+	AudioEngine::get_instance()->unlock();
+	
+}
 
 };
+
Index: libs/hydrogen/src/IO/jack_output.cpp
===================================================================
--- libs/hydrogen/src/IO/jack_output.cpp	(revision 220)
+++ libs/hydrogen/src/IO/jack_output.cpp	(working copy)
@@ -212,19 +212,23 @@
 void JackOutput::relocateBBT()
 {
 	//wolke if hydrogen is jack time master this is not relevant
-	if( Preferences::getInstance()->m_bJackMasterMode == Preferences::USE_JACK_TIME_MASTER ){
+	if( Preferences::getInstance()->m_bJackMasterMode == Preferences::USE_JACK_TIME_MASTER ) {
 		//Hydrogen::get_instance()->setHumantimeFrames(m_JackTransportPos.frame );
-		if ( m_transport.m_status != TransportInfo::ROLLING)
+		if ( m_transport.m_status != TransportInfo::ROLLING )
 		m_transport.m_nFrames = Hydrogen::get_instance()->getHumantimeFrames() - getBufferSize();
+		WARNINGLOG( "Relocate: Call it off" );
+		calculateFrameOffset();
 	 	return;
-	}else
-	{
-		if ( m_transport.m_status != TransportInfo::ROLLING || !( m_JackTransportPos.valid & JackPositionBBT ) /**the last check is *probably* redundant*/ ) return;
+	} else {
+		if ( m_transport.m_status != TransportInfo::ROLLING || !( m_JackTransportPos.valid & JackPositionBBT ) /**the last check is *probably* redundant*/ ) 
+			return;
+		
+		WARNINGLOG( "..." );
 	
 		Hydrogen * H = Hydrogen::get_instance();
 		Song * S = H->getSong();
 	
-		float hydrogen_TPB = ( float )S->__resolution;
+		float hydrogen_TPB = ( float )( S->__resolution / m_JackTransportPos.beat_type * 4 );
 	
 		long bar_ticks = 0;
 		//long beat_ticks = 0;
@@ -234,9 +238,9 @@
 		}
 		float hydrogen_ticks_to_locate =  bar_ticks + ( m_JackTransportPos.beat-1 )*hydrogen_TPB + m_JackTransportPos.tick *( hydrogen_TPB/m_JackTransportPos.ticks_per_beat ) ;
 	
-		char bbt[15];
-		sprintf( bbt, "[%d,%d,%d]", m_JackTransportPos.bar, m_JackTransportPos.beat, m_JackTransportPos.tick );
-//		WARNINGLOG( "Locating BBT: " + bbt + /*" -- Tx/Beat = "+to_string(m_JackTransportPos.ticks_per_beat)+", Meter "+to_string(m_JackTransportPos.beats_per_bar)+"/"+to_string(m_JackTransportPos.beat_type)+*/" =>tick " + to_string( hydrogen_ticks_to_locate ) );
+// 		char bbt[30];
+// 		sprintf( bbt, "Locating BBT: [%d,%d,%d]", m_JackTransportPos.bar, m_JackTransportPos.beat, m_JackTransportPos.tick );
+// 		WARNINGLOG( QString(bbt) + " -- Tx/Beat = "+to_string(m_JackTransportPos.ticks_per_beat)+", Meter "+to_string(m_JackTransportPos.beats_per_bar)+"/"+to_string(m_JackTransportPos.beat_type)+" =>tick " + to_string( hydrogen_ticks_to_locate ) );
 	
 		float fNewTickSize = getSampleRate() * 60.0 /  m_transport.m_nBPM / S->__resolution;
 		// not S->m_fBPM !??
@@ -297,23 +301,27 @@
 
 		// FIXME
 		// TickSize and BPM
+		Hydrogen * H = Hydrogen::get_instance();
 
 		if ( m_JackTransportPos.valid & JackPositionBBT ) {
 			float bpm = ( float )m_JackTransportPos.beats_per_minute;
 			if ( m_transport.m_nBPM != bpm ) {
 
 				
-				if( Preferences::getInstance()->m_bJackMasterMode == Preferences::NO_JACK_TIME_MASTER){
-					//WARNINGLOG( QString( "Tempo change from jack-transport: %1" ).arg( bpm ) );
+				if ( Preferences::getInstance()->m_bJackMasterMode == Preferences::NO_JACK_TIME_MASTER ){
+// 					WARNINGLOG( QString( "Tempo change from jack-transport: %1" ).arg( bpm ) );
 					m_transport.m_nBPM = bpm;
 					must_relocate = 1; // The tempo change has happened somewhere during the previous cycle; relocate right away.
-				}else
-				{
-					if(m_transport.m_status == TransportInfo::STOPPED){
-						oldpo = Hydrogen::get_instance()->getPatternPos();
+
+// This commenting out is rude perhaps, but I cant't figure out what this bit is doing.
+// In any case, setting must_relocate = 1 here causes too many relocates. Jakob Lund
+/*				} else { 
+					if ( m_transport.m_status == TransportInfo::STOPPED ) {
+						oldpo = H->getPatternPos();
 						must_relocate = 1;
 						//changer =1;
-					}
+					}*/
+
 				}
 				
 				// Hydrogen::get_instance()->setBPM( m_JackTransportPos.beats_per_minute ); // unnecessary, as Song->m_BPM gets updated in audioEngine_process_transport (after calling this function)
@@ -322,35 +330,41 @@
 
 		if ( m_transport.m_nFrames + bbt_frame_offset != m_JackTransportPos.frame ) {
 			if ( ( m_JackTransportPos.valid & JackPositionBBT ) && must_relocate == 0 ) {
-				//WARNINGLOG( "Frame offset mismatch; triggering resync in 2 cycles" );
+				WARNINGLOG( "Frame offset mismatch; triggering resync in 2 cycles" );
 				must_relocate = 2;
-			} else { // NOTE There's no timebase_master. If audioEngine_process_checkBPMChanged handled a tempo change during last cycle, the offset doesn't match.m_transport.m_nFrames = m_JackTransportPos.frame/* - bbt_frame_offset*/;
-
-				//m_transport.m_nFrames = m_JackTransportPos.frame - bbt_frame_offset;
-				///this is experimantal... but it works for the moment... fix me fix :-) wolke		
-				m_transport.m_nFrames = Hydrogen::get_instance()->getHumantimeFrames() - getBufferSize();
-				bbt_frame_offset = 0;
+			} else {
+				if ( Preferences::getInstance()->m_bJackMasterMode == Preferences::NO_JACK_TIME_MASTER ) {
+					// NOTE There's no timebase_master. If audioEngine_process_checkBPMChanged handled a tempo change during last cycle, the offset doesn't match.
+					// In jack 'slave' mode, if there's no master, the following line is needed to be able to relocate by clicking the song ruler (wierd corner case, but still...)
+					m_transport.m_nFrames = m_JackTransportPos.frame - bbt_frame_offset;
+					if ( m_transport.m_status == TransportInfo::ROLLING )
+							H->triggerRelocateDuringPlay();
+				} else {
+					///this is experimantal... but it works for the moment... fix me fix :-) wolke
+					// ... will this actually happen? keeping it for now ( jakob lund )
+					m_transport.m_nFrames = H->getHumantimeFrames() - getBufferSize();
+				}
+// 				bbt_frame_offset = 0;
 			}
 		}
 		
 		// humantime fix
-		if ( Hydrogen::get_instance()->getHumantimeFrames() != m_JackTransportPos.frame ) {
+		if ( H->getHumantimeFrames() != m_JackTransportPos.frame ) {
 
-			Hydrogen::get_instance()->setHumantimeFrames(m_JackTransportPos.frame);
+			H->setHumantimeFrames(m_JackTransportPos.frame);
 			//WARNINGLOG("fix Humantime " + to_string (m_JackTransportPos.frame));
 		}
 
-
-
-
 		if ( must_relocate == 1 ) {
 			//WARNINGLOG( "Resyncing!" );
 			relocateBBT();
+			if ( m_transport.m_status == TransportInfo::ROLLING ) {
+				H->triggerRelocateDuringPlay();
+			}
 		}
-
+		
 		if ( must_relocate > 0 ) must_relocate--;
 	}
-	
 }
-------------------------------------------------------------------------
Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW!
Studies have shown that voting for your favorite open source project,
along with a healthy diet, reduces your potential for chronic lameness
and boredom. Vote Now at http://www.sourceforge.net/community/cca08
_______________________________________________
Hydrogen-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/hydrogen-devel

Reply via email to