Hi,

This is a patch based on trunk SVN 85. It fixes one problem, and changes 
the behaviour of one feature. I can split it up into bugfix as one diff 
and new feature as another diff if you like.

Bugfix:
=====

As discussed on the Hydrogen forum, track outputs were re-initialised 
every time a new note was played, meaning that successive hits of the 
same sample cut each other off, leading to a staccato-like sound which 
was very different to what came out of the main output. I have changed 
the behaviour to implement a new buffer for each track output which is 
only re-initialised once every time, in the same way the main output is. 
The way I've created the buffer is the same way it was done before, 
which was admitted in the comment as a hack but I don't know of a better 
way.

New Feature:
==========

Track outputs were pre-fader meaning the only way to adjust relative 
volumes of instruments was to adjust the gains of the individual layers. 
The change is to add an option in the preferences dialog to allow track 
outputs to be post-fader in which case fader, LPF, all gains, and ADSR 
are applied to each track output. This option is also saved in Preferences.

I've been running this for a few weeks quite intensively and it has been 
stable so far, but I'm a little nervous about it as I'm no C++ expert. 
I'm happy to discuss it and try alternative approaches.

Index: hydrogen-trunk/gui/src/PreferencesDialog.cpp
===================================================================
--- hydrogen-trunk/gui/src/PreferencesDialog.cpp        (revision 85)
+++ hydrogen-trunk/gui/src/PreferencesDialog.cpp        (working copy)
@@ -121,6 +121,7 @@
        // JACK
        //trackOutsCheckBox->setChecked( pPref->m_bJackTrackOuts );
        connectDefaultsCheckBox->setChecked( pPref->m_bJackConnectDefaults );
+       postFaderTrackOutsCheckBox->setChecked( pPref->m_bPostFaderTrackOuts );
        //~ JACK
 
 
@@ -276,6 +277,7 @@
        // JACK
        //pPref->m_bJackTrackOuts = trackOutsCheckBox->isChecked();
        pPref->m_bJackConnectDefaults = connectDefaultsCheckBox->isChecked();
+       pPref->m_bPostFaderTrackOuts = postFaderTrackOutsCheckBox->isChecked();
        //~ JACK
 
        pPref->m_nBufferSize = bufferSizeSpinBox->value();
@@ -403,6 +405,7 @@
                bufferSizeSpinBox->setEnabled( false );
                sampleRateComboBox->setEnabled( false );
                connectDefaultsCheckBox->setEnabled( false );
+               postFaderTrackOutsCheckBox->setEnabled( false );
        }
        else if ( driverComboBox->currentText() == "OSS" ) {    // OSS
                info += trUtf8("<b>Open Sound System</b><br>Simple audio driver 
[/dev/dsp]");
@@ -414,6 +417,7 @@
                bufferSizeSpinBox->setEnabled(true);
                sampleRateComboBox->setEnabled(true);
                connectDefaultsCheckBox->setEnabled(false);
+               postFaderTrackOutsCheckBox->setEnabled( false );
        }
        else if ( driverComboBox->currentText() == "JACK" ) {   // JACK
                info += trUtf8("<b>Jack Audio Connection Kit Driver</b><br>Low 
latency audio driver");
@@ -425,6 +429,7 @@
                bufferSizeSpinBox->setEnabled(false);
                sampleRateComboBox->setEnabled(false);
                connectDefaultsCheckBox->setEnabled(true);
+               postFaderTrackOutsCheckBox->setEnabled( true );
        }
        else if ( driverComboBox->currentText() == "ALSA" ) {   // ALSA
                info += trUtf8("<b>ALSA Driver</b><br>");
@@ -436,6 +441,7 @@
                bufferSizeSpinBox->setEnabled(true);
                sampleRateComboBox->setEnabled(true);
                connectDefaultsCheckBox->setEnabled(false);
+               postFaderTrackOutsCheckBox->setEnabled( false );
        }
        else if ( driverComboBox->currentText() == "PortAudio" ) {
                info += trUtf8( "<b>PortAudio Driver</b><br>" );
@@ -447,6 +453,7 @@
                bufferSizeSpinBox->setEnabled(true);
                sampleRateComboBox->setEnabled(true);
                connectDefaultsCheckBox->setEnabled(false);
+               postFaderTrackOutsCheckBox->setEnabled( false );
        }
        else if ( driverComboBox->currentText() == "CoreAudio" ) {
                info += trUtf8( "<b>CoreAudio Driver</b><br>" );
@@ -458,6 +465,7 @@
                bufferSizeSpinBox->setEnabled(true);
                sampleRateComboBox->setEnabled(true);
                connectDefaultsCheckBox->setEnabled(false);
+               postFaderTrackOutsCheckBox->setEnabled( false );
        }
        else {
                std::string selectedDriver = 
(driverComboBox->currentText()).toStdString();
Index: hydrogen-trunk/gui/src/UI/PreferencesDialog_UI.ui
===================================================================
--- hydrogen-trunk/gui/src/UI/PreferencesDialog_UI.ui   (revision 85)
+++ hydrogen-trunk/gui/src/UI/PreferencesDialog_UI.ui   (working copy)
@@ -435,6 +435,22 @@
       </item>
      </layout>
     </widget>
+    <widget class="QCheckBox" name="postFaderTrackOutsCheckBox" >
+     <property name="geometry" >
+      <rect>
+       <x>10</x>
+       <y>170</y>
+       <width>191</width>
+       <height>22</height>
+      </rect>
+     </property>
+     <property name="text" >
+      <string>Post-Fader Track Outputs</string>
+     </property>
+     <property name="shortcut" >
+      <string>Alt+F</string>
+     </property>
+    </widget>
    </widget>
    <widget class="QWidget" name="tab" >
     <attribute name="title" >
@@ -446,7 +462,7 @@
        <x>10</x>
        <y>10</y>
        <width>451</width>
-       <height>107</height>
+       <height>114</height>
       </rect>
      </property>
      <layout class="QGridLayout" >
@@ -811,7 +827,6 @@
   </widget>
  </widget>
  <layoutdefault spacing="6" margin="11" />
- <includes/>
  <resources/>
  <connections/>
 </ui>
Index: hydrogen-trunk/hydrogen.kdevelop
===================================================================
--- hydrogen-trunk/hydrogen.kdevelop    (revision 85)
+++ hydrogen-trunk/hydrogen.kdevelop    (working copy)
@@ -134,8 +134,7 @@
   </kdevtrollproject>
   <kdevcppsupport>
     <references>
-      <pcs>Qt4</pcs>
-      <pcs>automatic_%2Fhome%2Fcomix%2Fprogetti%2Fhydrogen_svn%2Ftrunk</pcs>
+      <pcs>automatic_%2Fhome%2Fbob%2Fsrc%2Fhydrogen-trunk</pcs>
     </references>
     <codecompletion>
       <includeGlobalFunctions>true</includeGlobalFunctions>
@@ -181,7 +180,7 @@
       <includestyle>4</includestyle>
       <designerintegration>ExternalDesigner</designerintegration>
       <qmake>/usr/bin/qmake</qmake>
-      <designer></designer>
+      <designer>/usr/bin/designer-qt4</designer>
       <designerpluginpaths/>
     </qt>
     <splitheadersource>
Index: hydrogen-trunk/libs/hydrogen/include/hydrogen/Preferences.h
===================================================================
--- hydrogen-trunk/libs/hydrogen/include/hydrogen/Preferences.h (revision 85)
+++ hydrogen-trunk/libs/hydrogen/include/hydrogen/Preferences.h (working copy)
@@ -161,6 +161,7 @@
        std::string m_sJackPortName2;
        bool m_bJackTransportMode;
        bool m_bJackConnectDefaults;
+        bool m_bPostFaderTrackOuts;
 
 
        /// Returns an instance of PreferencesMng class
Index: hydrogen-trunk/libs/hydrogen/include/hydrogen/sampler/Sampler.h
===================================================================
--- hydrogen-trunk/libs/hydrogen/include/hydrogen/sampler/Sampler.h     
(revision 85)
+++ hydrogen-trunk/libs/hydrogen/include/hydrogen/sampler/Sampler.h     
(working copy)
@@ -51,6 +51,9 @@
        float *__main_out_L;    ///< sampler main out (left channel)
        float *__main_out_R;    ///< sampler main out (right channel)
 
+       float *__track_out_L[MAX_INSTRUMENTS];
+       float *__track_out_R[MAX_INSTRUMENTS];
+
        Sampler();
        ~Sampler();
 
@@ -73,7 +76,9 @@
 
        void set_audio_output( AudioOutput* audio_output );
 
+        void makeTrackOutputQueues( );
 
+
 private:
        std::vector<Note*> __playing_notes_queue;
        static Sampler* __instance;
@@ -82,7 +87,6 @@
        /// Instrument used for the preview feature.
        Instrument *__preview_instrument;
 
-
        unsigned __render_note( Note* pNote, unsigned nBufferSize, Song* pSong 
);
 
        int __render_note_no_resample(
@@ -92,7 +96,8 @@
            int nInitialSilence,
            float cost_L,
            float cost_R,
-           float cost_track,
+           float cost_track_L,
+           float cost_track_R,
            float fSendFXLevel_L,
            float fSendFXLevel_R,
            Song* pSong
@@ -105,7 +110,8 @@
            int nInitialSilence,
            float cost_L,
            float cost_R,
-           float cost_track,
+           float cost_track_L,
+           float cost_track_R,
            float fLayerPitch,
            float fSendFXLevel_L,
            float fSendFXLevel_R,
Index: hydrogen-trunk/libs/hydrogen/include/hydrogen/IO/JackOutput.h
===================================================================
--- hydrogen-trunk/libs/hydrogen/include/hydrogen/IO/JackOutput.h       
(revision 85)
+++ hydrogen-trunk/libs/hydrogen/include/hydrogen/IO/JackOutput.h       
(working copy)
@@ -58,6 +58,7 @@
        void deactivate();
        unsigned getBufferSize();
        unsigned getSampleRate();
+        int getNumTracks();
 
        jack_transport_state_t getTransportState() {
                return m_JackTransportState;
Index: hydrogen-trunk/libs/hydrogen/src/preferences.cpp
===================================================================
--- hydrogen-trunk/libs/hydrogen/src/preferences.cpp    (revision 85)
+++ hydrogen-trunk/libs/hydrogen/src/preferences.cpp    (working copy)
@@ -243,6 +243,7 @@
                                        }
                                        //m_bJackTrackOuts = 
LocalFileMng::readXmlBool( jackDriverNode, "jack_track_outs", m_bJackTrackOuts 
);
                                        m_bJackConnectDefaults = 
LocalFileMng::readXmlBool( jackDriverNode, "jack_connect_defaults", 
m_bJackConnectDefaults );
+                                       m_bPostFaderTrackOuts = 
LocalFileMng::readXmlBool( jackDriverNode, "track_out_post_fader", 
m_bPostFaderTrackOuts );
                                }
 
 
@@ -454,6 +455,12 @@
                        }
                        LocalFileMng::writeXmlString( &jackDriverNode, 
"jack_connect_defaults", jackConnectDefaultsString );
 
+                       std::string postFaderTrackOutsString = "false";
+                       if ( m_bPostFaderTrackOuts ) {
+                               postFaderTrackOutsString = "true";
+                       }
+                       LocalFileMng::writeXmlString( &jackDriverNode, 
"track_out_post_fader", postFaderTrackOutsString );
+
                        // jack track outs
                        //string jackTrackOutsString = "false";
                        //if (m_bJackTrackOuts) {
Index: hydrogen-trunk/libs/hydrogen/src/hydrogen.cpp
===================================================================
--- hydrogen-trunk/libs/hydrogen/src/hydrogen.cpp       (revision 85)
+++ hydrogen-trunk/libs/hydrogen/src/hydrogen.cpp       (working copy)
@@ -872,6 +872,9 @@
        if ( m_pAudioDriver->get_class_name() == "JackOutput" ) {
                static_cast< JackOutput* >( m_pAudioDriver )->makeTrackOutputs( 
m_pSong );
        }
+
+       AudioEngine::get_instance()->get_sampler()->makeTrackOutputQueues();
+
 #endif
 }
 
Index: hydrogen-trunk/libs/hydrogen/src/sampler/sampler.cpp
===================================================================
--- hydrogen-trunk/libs/hydrogen/src/sampler/sampler.cpp        (revision 85)
+++ hydrogen-trunk/libs/hydrogen/src/sampler/sampler.cpp        (working copy)
@@ -94,6 +94,14 @@
        memset( __main_out_R, 0, nFrames * sizeof( float ) );
 
 
+#ifdef JACK_SUPPORT
+       if ( __audio_output->has_track_outs() ) {
+               for(int nTrack = 0; nTrack < ( ( JackOutput* )__audio_output 
)->getNumTracks( ); nTrack++) {
+                       memset( __track_out_L[nTrack], 0, ( ( JackOutput* 
)__audio_output )->getBufferSize( ) * sizeof( float ) );
+                       memset( __track_out_R[nTrack], 0, ( ( JackOutput* 
)__audio_output )->getBufferSize( ) * sizeof( float ) );
+               }
+       }
+#endif // JACK_SUPPORT
 
        // Max notes limit
        int m_nMaxNotes = Preferences::getInstance()->m_nMaxNotes;
@@ -226,14 +234,18 @@
 
        float cost_L = 1.0f;
        float cost_R = 1.0f;
-       float cost_track = 1.0f;
+       float cost_track_L = 1.0f;
+       float cost_track_R = 1.0f;
        float fSendFXLevel_L = 1.0f;
        float fSendFXLevel_R = 1.0f;
 
        if ( pInstr->is_muted() || pSong->__is_muted ) {        // is 
instrument muted?
                cost_L = 0.0;
                cost_R = 0.0;
-
+               if ( Preferences::getInstance()->m_bPostFaderTrackOuts ) {
+                       cost_track_L = 0.0;
+                       cost_track_R = 0.0;
+               }
                fSendFXLevel_L = 0.0f;
                fSendFXLevel_R = 0.0f;
        } else {        // Precompute some values...
@@ -245,6 +257,9 @@
                fSendFXLevel_L = cost_L;
 
                cost_L = cost_L * pInstr->get_volume();         // instrument 
volume
+               if ( Preferences::getInstance()->m_bPostFaderTrackOuts ) {
+                       cost_track_L = cost_L * 2;
+               }
                cost_L = cost_L * pSong->get_volume();  // song volume
                cost_L = cost_L * 2; // max pan is 0.5
 
@@ -257,13 +272,19 @@
                fSendFXLevel_R = cost_R;
 
                cost_R = cost_R * pInstr->get_volume();         // instrument 
volume
+               if ( Preferences::getInstance()->m_bPostFaderTrackOuts ) {
+                       cost_track_R = cost_R * 2;
+               }
                cost_R = cost_R * pSong->get_volume();  // song pan
                cost_R = cost_R * 2; // max pan is 0.5
        }
 
+       if ( !Preferences::getInstance()->m_bPostFaderTrackOuts ) {
        // direct track outputs only use velocity
-       cost_track = cost_track * pNote->get_velocity();
-       cost_track = cost_track * fLayerGain;
+               cost_track_L = cost_track_L * pNote->get_velocity();
+               cost_track_L = cost_track_L * fLayerGain;
+               cost_track_R = cost_track_L;
+       }
 
        // Se non devo fare resample (drumkit) posso evitare di utilizzare i 
float e gestire il tutto in
        // maniera ottimizzata
@@ -277,9 +298,9 @@
        //_INFOLOG( "total pitch: " + to_string( fTotalPitch ) );
 
        if ( fTotalPitch == 0.0 && pSample->get_sample_rate() == 
__audio_output->getSampleRate() ) {    // NO RESAMPLE
-               return __render_note_no_resample( pSample, pNote, nBufferSize, 
nInitialSilence, cost_L, cost_R, cost_track, fSendFXLevel_L, fSendFXLevel_R, 
pSong );
+               return __render_note_no_resample( pSample, pNote, nBufferSize, 
nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, fSendFXLevel_L, 
fSendFXLevel_R, pSong );
        } else {        // RESAMPLE
-               return __render_note_resample( pSample, pNote, nBufferSize, 
nInitialSilence, cost_L, cost_R, cost_track, fLayerPitch, fSendFXLevel_L, 
fSendFXLevel_R, pSong );
+               return __render_note_resample( pSample, pNote, nBufferSize, 
nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, fLayerPitch, 
fSendFXLevel_L, fSendFXLevel_R, pSong );
        }
 }
 
@@ -293,7 +314,8 @@
     int nInitialSilence,
     float cost_L,
     float cost_R,
-    float cost_track,
+    float cost_track_L,
+    float cost_track_R,
     float fSendFXLevel_L,
     float fSendFXLevel_R,
     Song* pSong
@@ -344,21 +366,9 @@
                }
 
                fADSRValue = pNote->m_adsr.get_value( 1 );
-               fVal_L = pSample_data_L[ nSamplePos ] * cost_L * fADSRValue;
-               fVal_R = pSample_data_R[ nSamplePos ] * cost_R * fADSRValue;
+               fVal_L = pSample_data_L[ nSamplePos ] * fADSRValue;
+               fVal_R = pSample_data_R[ nSamplePos ] * fADSRValue;
 
-               if ( __audio_output->has_track_outs() ) {
-                       // hack hack hack: cast to JackOutput
-#ifdef JACK_SUPPORT
-                       float* track_out_L = ( ( JackOutput* )__audio_output 
)->getTrackOut_L( nInstrument );
-                       float* track_out_R = ( ( JackOutput* )__audio_output 
)->getTrackOut_L( nInstrument );
-                       assert( track_out_L );
-                       assert( track_out_R );
-                       track_out_L[nBufferPos] = pSample_data_L[nSamplePos] * 
cost_track * fADSRValue;
-                       track_out_R[nBufferPos] = pSample_data_R[nSamplePos] * 
cost_track * fADSRValue;
-#endif
-               }
-
                // Low pass resonant filter
                if ( bUseLPF ) {
                        pNote->m_fBandPassFilterBuffer_L = fResonance * 
pNote->m_fBandPassFilterBuffer_L + fCutoff * ( fVal_L - 
pNote->m_fLowPassFilterBuffer_L );
@@ -370,6 +380,21 @@
                        fVal_R = pNote->m_fLowPassFilterBuffer_R;
                }
 
+               if ( __audio_output->has_track_outs() ) {
+#ifdef JACK_SUPPORT
+                        assert( __track_out_L[ nInstrument ] );
+                        assert( __track_out_R[ nInstrument ] );
+                        // NOTE: LPF is not applied at this point!
+//                     __track_out_L[ nInstrument ][nBufferPos] += 
(pSample_data_L[ nSamplePos ] * cost_track_L * fADSRValue);
+//                     __track_out_R[ nInstrument ][nBufferPos] += 
(pSample_data_R[ nSamplePos ] * cost_track_R * fADSRValue);
+                       __track_out_L[ nInstrument ][nBufferPos] += fVal_L * 
cost_track_L;
+                       __track_out_R[ nInstrument ][nBufferPos] += fVal_R * 
cost_track_R;
+#endif
+               }
+
+                fVal_L = fVal_L * cost_L;
+               fVal_R = fVal_R * cost_R;
+
                // update instr peak
                if ( fVal_L > fInstrPeak_L ) {
                        fInstrPeak_L = fVal_L;
@@ -431,7 +456,8 @@
     int nInitialSilence,
     float cost_L,
     float cost_R,
-    float cost_track,
+    float cost_track_L,
+    float cost_track_R,
     float fLayerPitch,
     float fSendFXLevel_L,
     float fSendFXLevel_R,
@@ -500,22 +526,10 @@
                        fVal_R = linear_interpolation( 
pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], fDiff );
                }
 
-               if ( __audio_output->has_track_outs() ) {
-#ifdef JACK_SUPPORT
-                       // hack hack hack: cast to JackOutput
-                       float* track_out_L = ( ( JackOutput* )__audio_output 
)->getTrackOut_L( nInstrument );
-                       float* track_out_R = ( ( JackOutput* )__audio_output 
)->getTrackOut_L( nInstrument );
-                       assert( track_out_L );
-                       assert( track_out_R );
-                       track_out_L[nBufferPos] = fVal_L * cost_track * 
fADSRValue;
-                       track_out_R[nBufferPos] = fVal_R * cost_track * 
fADSRValue;
-#endif
-               }
-
                // ADSR envelope
                fADSRValue = pNote->m_adsr.get_value( fStep );
-               fVal_L = fVal_L * cost_L * fADSRValue;
-               fVal_R = fVal_R * cost_R * fADSRValue;
+               fVal_L = fVal_L * fADSRValue;
+               fVal_R = fVal_R * fADSRValue;
 
                // Low pass resonant filter
                if ( bUseLPF ) {
@@ -528,6 +542,20 @@
                        fVal_R = pNote->m_fLowPassFilterBuffer_R;
                }
 
+               if ( __audio_output->has_track_outs() ) {
+#ifdef JACK_SUPPORT
+                       assert( __track_out_L[ nInstrument ] );
+                        assert( __track_out_R[ nInstrument ] );
+//                     __track_out_L[ nInstrument ][nBufferPos] += (tVal_L * 
cost_track_L * fADSRValue);
+//                     __track_out_R[ nInstrument ][nBufferPos] += (tVal_R * 
cost_track_R * fADSRValue);
+                       __track_out_L[ nInstrument ][nBufferPos] += (fVal_L * 
cost_track_L);
+                       __track_out_R[ nInstrument ][nBufferPos] += (fVal_R * 
cost_track_R);
+#endif
+               }
+
+               fVal_L = fVal_L * cost_L;
+               fVal_R = fVal_R * cost_R;
+
                // update instr peak
                if ( fVal_L > fInstrPeak_L ) {
                        fInstrPeak_L = fVal_L;
@@ -664,10 +692,20 @@
 void Sampler::set_audio_output( AudioOutput* audio_output )
 {
        __audio_output = audio_output;
+
 }
 
+void Sampler::makeTrackOutputQueues( )
+{
+#ifdef JACK_SUPPORT
+       if ( __audio_output->has_track_outs() ) {
+               for (int nTrack = 0; nTrack < ( ( JackOutput* )__audio_output 
)->getNumTracks( ); nTrack++) {
+                       __track_out_L[nTrack] = ( ( JackOutput* )__audio_output 
)->getTrackOut_L( nTrack );
+                       __track_out_R[nTrack] = ( ( JackOutput* )__audio_output 
)->getTrackOut_R( nTrack );
+               }
+       }
+#endif // JACK_SUPPORT
 
+}
 
-
-};
-
+}
Index: hydrogen-trunk/libs/hydrogen/src/IO/jack_output.cpp
===================================================================
--- hydrogen-trunk/libs/hydrogen/src/IO/jack_output.cpp (revision 85)
+++ hydrogen-trunk/libs/hydrogen/src/IO/jack_output.cpp (working copy)
@@ -561,7 +561,12 @@
        }
 }
 
+int JackOutput::getNumTracks()
+{
+       return track_port_count;
 
+}
+
 };
 
 #endif // JACK_SUPPORT



-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Hydrogen-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/hydrogen-devel

Reply via email to