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>&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 &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>&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>&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