void Drumkit::dump() { DEBUGLOG( "Drumkit dump" ); DEBUGLOG( " |- Path = " + __path ); DEBUGLOG( " |- Name = " + __name ); DEBUGLOG( " |- Author = " + __author ); DEBUGLOG( " |- Info = " + __info ); DEBUGLOG( " |- Instrument list" ); for ( int i=0; i<__instruments->size(); i++ ) { Instrument* instrument = ( *__instruments )[i]; DEBUGLOG( QString( " |- (%1 of %2) Name = %3" ) .arg( i ) .arg( __instruments->size()-1 ) .arg( instrument->get_name() ) ); for (std::vector<InstrumentComponent*>::iterator it = instrument->get_components()->begin() ; it != instrument->get_components()->end(); ++it) { InstrumentComponent* component = *it; for ( int j=0; j<MAX_LAYERS; j++ ) { InstrumentLayer* layer = component->get_layer( j ); if ( layer ) { Sample* sample = layer->get_sample(); if ( sample ) { DEBUGLOG( QString( " |- %1 [%2]" ).arg( sample->get_filepath() ).arg( sample->is_empty() ) ); } else { DEBUGLOG( " |- NULL sample" ); } } } } } }
void Instrument::unload_samples() { for (std::vector<InstrumentComponent*>::iterator it = get_components()->begin() ; it != get_components()->end(); ++it) { InstrumentComponent* component = *it; for ( int i=0; i<MAX_LAYERS; i++ ) { InstrumentLayer* layer = component->get_layer( i ); if( layer ) layer->unload_sample(); } } }
bool Drumkit::save_samples( const QString& dk_dir, bool overwrite ) { INFOLOG( QString( "Saving drumkit %1 samples into %2" ).arg( __name ).arg( dk_dir ) ); if( !Filesystem::mkdir( dk_dir ) ) { return false; } InstrumentList* instruments = get_instruments(); for( int i = 0; i < instruments->size(); i++ ) { Instrument* instrument = ( *instruments )[i]; for (std::vector<InstrumentComponent*>::iterator it = instrument->get_components()->begin() ; it != instrument->get_components()->end(); ++it) { InstrumentComponent* component = *it; for( int n = 0; n < MAX_LAYERS; n++ ) { InstrumentLayer* layer = component->get_layer( n ); if( layer ) { QString src = layer->get_sample()->get_filepath(); QString dst = dk_dir + "/" + layer->get_sample()->get_filename(); if( src != dst ) { QString original_dst = dst; // If the destination path does not have an extension and there is a dot in the path, hell will break loose. QFileInfo maybe? int insertPosition = original_dst.length(); if( original_dst.lastIndexOf(".") > 0 ) insertPosition = original_dst.lastIndexOf("."); if(overwrite == false) { // If the destination path already exists, try to use basename_1, basename_2, etc. instead of basename. int tries = 0; while( Filesystem::file_exists( dst, true )) { tries++; dst = original_dst; dst.insert( insertPosition, QString("_%1").arg(tries) ); } } layer->get_sample()->set_filename( dst ); if( !Filesystem::file_copy( src, dst ) ) { return false; } } } } } } return true; }
/// Preview, uses only the first layer void Sampler::preview_sample( Sample* sample, int length ) { AudioEngine::get_instance()->lock( RIGHT_HERE ); for (std::vector<InstrumentComponent*>::iterator it = __preview_instrument->get_components()->begin() ; it != __preview_instrument->get_components()->end(); ++it) { InstrumentComponent* pComponent = *it; InstrumentLayer *pLayer = pComponent->get_layer( 0 ); pLayer->set_sample( sample ); Note *pPreviewNote = new Note( __preview_instrument, 0, 1.0, 0.5, 0.5, length, 0 ); stop_playing_notes( __preview_instrument ); note_on( pPreviewNote ); } AudioEngine::get_instance()->unlock(); }
/// /// Update and redraw all... /// void SongEditorPanel::updateAll() { InstrumentComponent *pCompo = AudioEngine::get_instance()->get_sampler()->__playback_instrument->get_components()->front(); m_pWaveDisplay->updateDisplay( pCompo->get_layer(0) ); m_pPatternList->createBackground(); m_pPatternList->update(); m_pSongEditor->cleanUp(); m_pSongEditor->createBackground(); m_pSongEditor->update(); Hydrogen *engine = Hydrogen::get_instance(); Song *song = engine->getSong(); m_pAutomationPathView->setAutomationPath (song->get_velocity_automation_path()); resyncExternalScrollBar(); }
bool Sampler::processPlaybackTrack(int nBufferSize) { Hydrogen* pEngine = Hydrogen::get_instance(); AudioOutput* pAudioOutput = Hydrogen::get_instance()->getAudioOutput(); Song* pSong = pEngine->getSong(); if( !pSong->get_playback_track_enabled() || pEngine->getState() != STATE_PLAYING || pSong->get_mode() != Song::SONG_MODE) { return false; } InstrumentComponent *pCompo = __playback_instrument->get_components()->front(); Sample *pSample = pCompo->get_layer(0)->get_sample(); float fVal_L; float fVal_R; float *pSample_data_L = pSample->get_data_l(); float *pSample_data_R = pSample->get_data_r(); float fInstrPeak_L = __playback_instrument->get_peak_l(); // this value will be reset to 0 by the mixer.. float fInstrPeak_R = __playback_instrument->get_peak_r(); // this value will be reset to 0 by the mixer.. assert(pSample); int nAvail_bytes = 0; int nInitialBufferPos = 0; if(pSample->get_sample_rate() == pAudioOutput->getSampleRate()){ //No resampling __playBackSamplePosition = pAudioOutput->m_transport.m_nFrames; nAvail_bytes = pSample->get_frames() - ( int )__playBackSamplePosition; if ( nAvail_bytes > nBufferSize ) { nAvail_bytes = nBufferSize; } int nInitialSamplePos = ( int ) __playBackSamplePosition; int nSamplePos = nInitialSamplePos; int nTimes = nInitialBufferPos + nAvail_bytes; if(__playBackSamplePosition > pSample->get_frames()){ //playback track has ended.. return true; } for ( int nBufferPos = nInitialBufferPos; nBufferPos < nTimes; ++nBufferPos ) { fVal_L = pSample_data_L[ nSamplePos ]; fVal_R = pSample_data_R[ nSamplePos ]; fVal_L = fVal_L * 1.0f * pSong->get_playback_track_volume(); //costr fVal_R = fVal_R * 1.0f * pSong->get_playback_track_volume(); //cost l //pDrumCompo->set_outs( nBufferPos, fVal_L, fVal_R ); // to main mix if ( fVal_L > fInstrPeak_L ) { fInstrPeak_L = fVal_L; } if ( fVal_R > fInstrPeak_R ) { fInstrPeak_R = fVal_R; } __main_out_L[nBufferPos] += fVal_L; __main_out_R[nBufferPos] += fVal_R; ++nSamplePos; } } else { //Perform resampling double fSamplePos = 0; int nSampleFrames = pSample->get_frames(); float fStep = 1.0594630943593; fStep *= ( float )pSample->get_sample_rate() / pAudioOutput->getSampleRate(); // Adjust for audio driver sample rate if(pAudioOutput->m_transport.m_nFrames == 0){ fSamplePos = 0; } else { fSamplePos = ( (pAudioOutput->m_transport.m_nFrames/nBufferSize) * (nBufferSize * fStep)); } nAvail_bytes = ( int )( ( float )( pSample->get_frames() - fSamplePos ) / fStep ); if ( nAvail_bytes > nBufferSize ) { nAvail_bytes = nBufferSize; } int nTimes = nInitialBufferPos + nAvail_bytes; for ( int nBufferPos = nInitialBufferPos; nBufferPos < nTimes; ++nBufferPos ) { int nSamplePos = ( int ) fSamplePos; double fDiff = fSamplePos - nSamplePos; if ( ( nSamplePos + 1 ) >= nSampleFrames ) { //we reach the last audioframe. //set this last frame to zero do nothin wrong. fVal_L = 0.0; fVal_R = 0.0; } else { // some interpolation methods need 4 frames data. float last_l; float last_r; if ( ( nSamplePos + 2 ) >= nSampleFrames ) { last_l = 0.0; last_r = 0.0; } else { last_l = pSample_data_L[nSamplePos + 2]; last_r = pSample_data_R[nSamplePos + 2]; } switch( __interpolateMode ){ case LINEAR: fVal_L = pSample_data_L[nSamplePos] * (1 - fDiff ) + pSample_data_L[nSamplePos + 1] * fDiff; fVal_R = pSample_data_R[nSamplePos] * (1 - fDiff ) + pSample_data_R[nSamplePos + 1] * fDiff; break; case COSINE: fVal_L = cosine_Interpolate( pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], fDiff); fVal_R = cosine_Interpolate( pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], fDiff); break; case THIRD: fVal_L = third_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); fVal_R = third_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; case CUBIC: fVal_L = cubic_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); fVal_R = cubic_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; case HERMITE: fVal_L = hermite_Interpolate( pSample_data_L[ nSamplePos -1], pSample_data_L[nSamplePos], pSample_data_L[nSamplePos + 1], last_l, fDiff); fVal_R = hermite_Interpolate( pSample_data_R[ nSamplePos -1], pSample_data_R[nSamplePos], pSample_data_R[nSamplePos + 1], last_r, fDiff); break; } } if ( fVal_L > fInstrPeak_L ) { fInstrPeak_L = fVal_L; } if ( fVal_R > fInstrPeak_R ) { fInstrPeak_R = fVal_R; } __main_out_L[nBufferPos] += fVal_L; __main_out_R[nBufferPos] += fVal_R; fSamplePos += fStep; } //for } __playback_instrument->set_peak_l( fInstrPeak_L ); __playback_instrument->set_peak_r( fInstrPeak_R ); return true; }
/// Render a note /// Return false: the note is not ended /// Return true: the note is ended bool Sampler::__render_note( Note* pNote, unsigned nBufferSize, Song* pSong ) { //infoLog( "[renderNote] instr: " + pNote->getInstrument()->m_sName ); assert( pSong ); unsigned int nFramepos; Hydrogen* pEngine = Hydrogen::get_instance(); AudioOutput* audio_output = pEngine->getAudioOutput(); if ( pEngine->getState() == STATE_PLAYING ) { nFramepos = audio_output->m_transport.m_nFrames; } else { // use this to support realtime events when not playing nFramepos = pEngine->getRealtimeFrames(); } Instrument *pInstr = pNote->get_instrument(); if ( !pInstr ) { ERRORLOG( "NULL instrument" ); return 1; } bool nReturnValues [pInstr->get_components()->size()]; for(int i = 0; i < pInstr->get_components()->size(); i++){ nReturnValues[i] = false; } int nReturnValueIndex = 0; int nAlreadySelectedLayer = -1; for (std::vector<InstrumentComponent*>::iterator it = pInstr->get_components()->begin() ; it !=pInstr->get_components()->end(); ++it) { nReturnValues[nReturnValueIndex] = false; InstrumentComponent *pCompo = *it; DrumkitComponent* pMainCompo = pEngine->getSong()->get_component( pCompo->get_drumkit_componentID() ); if( pNote->get_specific_compo_id() != -1 && pNote->get_specific_compo_id() != pCompo->get_drumkit_componentID() ) continue; if( pInstr->is_preview_instrument() || pInstr->is_metronome_instrument()){ pMainCompo = pEngine->getSong()->get_components()->front(); } else { pMainCompo = pEngine->getSong()->get_component( pCompo->get_drumkit_componentID() ); } assert(pMainCompo); float fLayerGain = 1.0; float fLayerPitch = 0.0; // scelgo il sample da usare in base alla velocity Sample *pSample = nullptr; SelectedLayerInfo *pSelectedLayer = pNote->get_layer_selected( pCompo->get_drumkit_componentID() ); if ( !pSelectedLayer ) { QString dummy = QString( "NULL Layer Information for instrument %1. Component: %2" ).arg( pInstr->get_name() ).arg( pCompo->get_drumkit_componentID() ); WARNINGLOG( dummy ); nReturnValues[nReturnValueIndex] = true; continue; } if( pSelectedLayer->SelectedLayer != -1 ) { InstrumentLayer *pLayer = pCompo->get_layer( pSelectedLayer->SelectedLayer ); if( pLayer ) { pSample = pLayer->get_sample(); fLayerGain = pLayer->get_gain(); fLayerPitch = pLayer->get_pitch(); } } else { switch ( pInstr->sample_selection_alg() ) { case Instrument::VELOCITY: for ( unsigned nLayer = 0; nLayer < __maxLayers; ++nLayer ) { InstrumentLayer *pLayer = pCompo->get_layer( nLayer ); if ( pLayer == NULL ) continue; if ( ( pNote->get_velocity() >= pLayer->get_start_velocity() ) && ( pNote->get_velocity() <= pLayer->get_end_velocity() ) ) { pSelectedLayer->SelectedLayer = nLayer; pSample = pLayer->get_sample(); fLayerGain = pLayer->get_gain(); fLayerPitch = pLayer->get_pitch(); break; } } break; case Instrument::RANDOM: if( nAlreadySelectedLayer != -1 ) { InstrumentLayer *pLayer = pCompo->get_layer( nAlreadySelectedLayer ); if ( pLayer != NULL ) { pSelectedLayer->SelectedLayer = nAlreadySelectedLayer; pSample = pLayer->get_sample(); fLayerGain = pLayer->get_gain(); fLayerPitch = pLayer->get_pitch(); } } if( pSample == NULL ) { int __possibleIndex[ __maxLayers ]; int __poundSamples = 0; for ( unsigned nLayer = 0; nLayer < __maxLayers; ++nLayer ) { InstrumentLayer *pLayer = pCompo->get_layer( nLayer ); if ( pLayer == NULL ) continue; if ( ( pNote->get_velocity() >= pLayer->get_start_velocity() ) && ( pNote->get_velocity() <= pLayer->get_end_velocity() ) ) { __possibleIndex[__poundSamples] = nLayer; __poundSamples++; } } if( __poundSamples > 0 ) { nAlreadySelectedLayer = __possibleIndex[rand() % __poundSamples]; pSelectedLayer->SelectedLayer = nAlreadySelectedLayer; InstrumentLayer *pLayer = pCompo->get_layer( nAlreadySelectedLayer ); pSample = pLayer->get_sample(); fLayerGain = pLayer->get_gain(); fLayerPitch = pLayer->get_pitch(); } } break; case Instrument::ROUND_ROBIN: if( nAlreadySelectedLayer != -1 ) { InstrumentLayer *pLayer = pCompo->get_layer( nAlreadySelectedLayer ); if ( pLayer != NULL ) { pSelectedLayer->SelectedLayer = nAlreadySelectedLayer; pSample = pLayer->get_sample(); fLayerGain = pLayer->get_gain(); fLayerPitch = pLayer->get_pitch(); } } if( !pSample ) { int __possibleIndex[ __maxLayers ]; int __foundSamples = 0; float __roundRobinID; for ( unsigned nLayer = 0; nLayer < __maxLayers; ++nLayer ) { InstrumentLayer *pLayer = pCompo->get_layer( nLayer ); if ( pLayer == NULL ) continue; if ( ( pNote->get_velocity() >= pLayer->get_start_velocity() ) && ( pNote->get_velocity() <= pLayer->get_end_velocity() ) ) { __possibleIndex[__foundSamples] = nLayer; __roundRobinID = pLayer->get_start_velocity(); __foundSamples++; } } if( __foundSamples > 0 ) { __roundRobinID = pInstr->get_id() * 10 + __roundRobinID; int p_indexToUse = pSong->get_latest_round_robin(__roundRobinID)+1; if( p_indexToUse > __foundSamples - 1) p_indexToUse = 0; pSong->set_latest_round_robin(__roundRobinID, p_indexToUse); nAlreadySelectedLayer = __possibleIndex[p_indexToUse]; pSelectedLayer->SelectedLayer = nAlreadySelectedLayer; InstrumentLayer *pLayer = pCompo->get_layer( nAlreadySelectedLayer ); pSample = pLayer->get_sample(); fLayerGain = pLayer->get_gain(); fLayerPitch = pLayer->get_pitch(); } } break; } } if ( !pSample ) { QString dummy = QString( "NULL sample for instrument %1. Note velocity: %2" ).arg( pInstr->get_name() ).arg( pNote->get_velocity() ); WARNINGLOG( dummy ); nReturnValues[nReturnValueIndex] = true; continue; } if ( pSelectedLayer->SamplePosition >= pSample->get_frames() ) { WARNINGLOG( "sample position out of bounds. The layer has been resized during note play?" ); nReturnValues[nReturnValueIndex] = true; continue; } int noteStartInFrames = ( int ) ( pNote->get_position() * audio_output->m_transport.m_nTickSize ) + pNote->get_humanize_delay(); int nInitialSilence = 0; if ( noteStartInFrames > ( int ) nFramepos ) { // scrivo silenzio prima dell'inizio della nota nInitialSilence = noteStartInFrames - nFramepos; int nFrames = nBufferSize - nInitialSilence; if ( nFrames < 0 ) { int noteStartInFramesNoHumanize = ( int )pNote->get_position() * audio_output->m_transport.m_nTickSize; if ( noteStartInFramesNoHumanize > ( int )( nFramepos + nBufferSize ) ) { // this note is not valid. it's in the future...let's skip it.... ERRORLOG( QString( "Note pos in the future?? Current frames: %1, note frame pos: %2" ).arg( nFramepos ).arg(noteStartInFramesNoHumanize ) ); //pNote->dumpInfo(); nReturnValues[nReturnValueIndex] = true; continue; } // delay note execution //INFOLOG( "Delaying note execution. noteStartInFrames: " + to_string( noteStartInFrames ) + ", nFramePos: " + to_string( nFramepos ) ); //return 0; continue; } } float cost_L = 1.0f; float cost_R = 1.0f; float cost_track_L = 1.0f; float cost_track_R = 1.0f; assert(pMainCompo); bool isMutedForExport = (pEngine->getIsExportSessionActive() && !pInstr->is_currently_exported()); /* * Is instrument muted? * * This can be the case either if the song, instrument or component is muted or if we're in an * export session and we're doing per-instruments exports, but this instrument is not currently * beeing exported. */ if ( isMutedForExport || pInstr->is_muted() || pSong->__is_muted || pMainCompo->is_muted() ) { cost_L = 0.0; cost_R = 0.0; if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) { // Post-Fader cost_track_L = 0.0; cost_track_R = 0.0; } } else { // Precompute some values... if ( pInstr->get_apply_velocity() ) { cost_L = cost_L * pNote->get_velocity(); // note velocity cost_R = cost_R * pNote->get_velocity(); // note velocity } cost_L = cost_L * pNote->get_pan_l(); // note pan cost_L = cost_L * fLayerGain; // layer gain cost_L = cost_L * pInstr->get_pan_l(); // instrument pan cost_L = cost_L * pInstr->get_gain(); // instrument gain cost_L = cost_L * pCompo->get_gain(); // Component gain cost_L = cost_L * pMainCompo->get_volume(); // Component volument cost_L = cost_L * pInstr->get_volume(); // instrument volume if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) { // Post-Fader 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 cost_R = cost_R * pNote->get_pan_r(); // note pan cost_R = cost_R * fLayerGain; // layer gain cost_R = cost_R * pInstr->get_pan_r(); // instrument pan cost_R = cost_R * pInstr->get_gain(); // instrument gain cost_R = cost_R * pCompo->get_gain(); // Component gain cost_R = cost_R * pMainCompo->get_volume(); // Component volument cost_R = cost_R * pInstr->get_volume(); // instrument volume if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) { // Post-Fader 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 } // direct track outputs only use velocity if ( Preferences::get_instance()->m_nJackTrackOutputMode == 1 ) { 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 // constant^12 = 2, so constant = 2^(1/12) = 1.059463. // float nStep = 1.0;1.0594630943593 float fTotalPitch = pNote->get_total_pitch() + fLayerPitch; //_INFOLOG( "total pitch: " + to_string( fTotalPitch ) ); if( ( int )pSelectedLayer->SamplePosition == 0 ) { if( Hydrogen::get_instance()->getMidiOutput() != NULL ){ Hydrogen::get_instance()->getMidiOutput()->handleQueueNote( pNote ); } } if ( fTotalPitch == 0.0 && pSample->get_sample_rate() == audio_output->getSampleRate() ) // NO RESAMPLE nReturnValues[nReturnValueIndex] = __render_note_no_resample( pSample, pNote, pSelectedLayer, pCompo, pMainCompo, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, pSong ); else // RESAMPLE nReturnValues[nReturnValueIndex] = __render_note_resample( pSample, pNote, pSelectedLayer, pCompo, pMainCompo, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, fLayerPitch, pSong ); nReturnValueIndex++; } for ( unsigned i = 0 ; i < pInstr->get_components()->size() ; i++ ) if ( !nReturnValues[i] ) return false; return true; }
// Returns 0 on success, passes the TinyXml error code otherwise. int SongWriter::writeSong( Song *song, const QString& filename ) { INFOLOG( "Saving song " + filename ); int rv = 0; // return value // FIXME: has the file write-permssion? // FIXME: verificare che il file non sia gia' esistente // FIXME: effettuare copia di backup per il file gia' esistente QDomDocument doc; QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\""); doc.appendChild( header ); QDomNode songNode = doc.createElement( "song" ); LocalFileMng::writeXmlString( songNode, "version", QString( get_version().c_str() ) ); LocalFileMng::writeXmlString( songNode, "bpm", QString("%1").arg( song->__bpm ) ); LocalFileMng::writeXmlString( songNode, "volume", QString("%1").arg( song->get_volume() ) ); LocalFileMng::writeXmlString( songNode, "metronomeVolume", QString("%1").arg( song->get_metronome_volume() ) ); LocalFileMng::writeXmlString( songNode, "name", song->__name ); LocalFileMng::writeXmlString( songNode, "author", song->__author ); LocalFileMng::writeXmlString( songNode, "notes", song->get_notes() ); LocalFileMng::writeXmlString( songNode, "license", song->get_license() ); LocalFileMng::writeXmlBool( songNode, "loopEnabled", song->is_loop_enabled() ); LocalFileMng::writeXmlBool( songNode, "patternModeMode", Preferences::get_instance()->patternModePlaysSelected()); LocalFileMng::writeXmlString( songNode, "playbackTrackFilename", QString("%1").arg( song->get_playback_track_filename() ) ); LocalFileMng::writeXmlBool( songNode, "playbackTrackEnabled", song->get_playback_track_enabled() ); LocalFileMng::writeXmlString( songNode, "playbackTrackVolume", QString("%1").arg( song->get_playback_track_volume() ) ); if ( song->get_mode() == Song::SONG_MODE ) { LocalFileMng::writeXmlString( songNode, "mode", QString( "song" ) ); } else { LocalFileMng::writeXmlString( songNode, "mode", QString( "pattern" ) ); } LocalFileMng::writeXmlString( songNode, "humanize_time", QString("%1").arg( song->get_humanize_time_value() ) ); LocalFileMng::writeXmlString( songNode, "humanize_velocity", QString("%1").arg( song->get_humanize_velocity_value() ) ); LocalFileMng::writeXmlString( songNode, "swing_factor", QString("%1").arg( song->get_swing_factor() ) ); // component List QDomNode componentListNode = doc.createElement( "componentList" ); for (std::vector<DrumkitComponent*>::iterator it = song->get_components()->begin() ; it != song->get_components()->end(); ++it) { DrumkitComponent* pCompo = *it; QDomNode componentNode = doc.createElement( "drumkitComponent" ); LocalFileMng::writeXmlString( componentNode, "id", QString("%1").arg( pCompo->get_id() ) ); LocalFileMng::writeXmlString( componentNode, "name", pCompo->get_name() ); LocalFileMng::writeXmlString( componentNode, "volume", QString("%1").arg( pCompo->get_volume() ) ); componentListNode.appendChild( componentNode ); } songNode.appendChild( componentListNode ); // instrument list QDomNode instrumentListNode = doc.createElement( "instrumentList" ); unsigned nInstrument = song->get_instrument_list()->size(); // INSTRUMENT NODE for ( unsigned i = 0; i < nInstrument; i++ ) { Instrument *instr = song->get_instrument_list()->get( i ); assert( instr ); QDomNode instrumentNode = doc.createElement( "instrument" ); LocalFileMng::writeXmlString( instrumentNode, "id", QString("%1").arg( instr->get_id() ) ); LocalFileMng::writeXmlString( instrumentNode, "name", instr->get_name() ); LocalFileMng::writeXmlString( instrumentNode, "drumkit", instr->get_drumkit_name() ); LocalFileMng::writeXmlString( instrumentNode, "volume", QString("%1").arg( instr->get_volume() ) ); LocalFileMng::writeXmlBool( instrumentNode, "isMuted", instr->is_muted() ); LocalFileMng::writeXmlString( instrumentNode, "pan_L", QString("%1").arg( instr->get_pan_l() ) ); LocalFileMng::writeXmlString( instrumentNode, "pan_R", QString("%1").arg( instr->get_pan_r() ) ); LocalFileMng::writeXmlString( instrumentNode, "gain", QString("%1").arg( instr->get_gain() ) ); LocalFileMng::writeXmlBool( instrumentNode, "applyVelocity", instr->get_apply_velocity() ); LocalFileMng::writeXmlBool( instrumentNode, "filterActive", instr->is_filter_active() ); LocalFileMng::writeXmlString( instrumentNode, "filterCutoff", QString("%1").arg( instr->get_filter_cutoff() ) ); LocalFileMng::writeXmlString( instrumentNode, "filterResonance", QString("%1").arg( instr->get_filter_resonance() ) ); LocalFileMng::writeXmlString( instrumentNode, "FX1Level", QString("%1").arg( instr->get_fx_level( 0 ) ) ); LocalFileMng::writeXmlString( instrumentNode, "FX2Level", QString("%1").arg( instr->get_fx_level( 1 ) ) ); LocalFileMng::writeXmlString( instrumentNode, "FX3Level", QString("%1").arg( instr->get_fx_level( 2 ) ) ); LocalFileMng::writeXmlString( instrumentNode, "FX4Level", QString("%1").arg( instr->get_fx_level( 3 ) ) ); assert( instr->get_adsr() ); LocalFileMng::writeXmlString( instrumentNode, "Attack", QString("%1").arg( instr->get_adsr()->get_attack() ) ); LocalFileMng::writeXmlString( instrumentNode, "Decay", QString("%1").arg( instr->get_adsr()->get_decay() ) ); LocalFileMng::writeXmlString( instrumentNode, "Sustain", QString("%1").arg( instr->get_adsr()->get_sustain() ) ); LocalFileMng::writeXmlString( instrumentNode, "Release", QString("%1").arg( instr->get_adsr()->get_release() ) ); LocalFileMng::writeXmlString( instrumentNode, "randomPitchFactor", QString("%1").arg( instr->get_random_pitch_factor() ) ); LocalFileMng::writeXmlString( instrumentNode, "muteGroup", QString("%1").arg( instr->get_mute_group() ) ); LocalFileMng::writeXmlBool( instrumentNode, "isStopNote", instr->is_stop_notes() ); switch ( instr->sample_selection_alg() ) { case Instrument::VELOCITY: LocalFileMng::writeXmlString( instrumentNode, "sampleSelectionAlgo", "VELOCITY" ); break; case Instrument::RANDOM: LocalFileMng::writeXmlString( instrumentNode, "sampleSelectionAlgo", "RANDOM" ); break; case Instrument::ROUND_ROBIN: LocalFileMng::writeXmlString( instrumentNode, "sampleSelectionAlgo", "ROUND_ROBIN" ); break; } LocalFileMng::writeXmlString( instrumentNode, "midiOutChannel", QString("%1").arg( instr->get_midi_out_channel() ) ); LocalFileMng::writeXmlString( instrumentNode, "midiOutNote", QString("%1").arg( instr->get_midi_out_note() ) ); LocalFileMng::writeXmlString( instrumentNode, "isHihat", QString("%1").arg( instr->get_hihat_grp() ) ); LocalFileMng::writeXmlString( instrumentNode, "lower_cc", QString("%1").arg( instr->get_lower_cc() ) ); LocalFileMng::writeXmlString( instrumentNode, "higher_cc", QString("%1").arg( instr->get_higher_cc() ) ); for (std::vector<InstrumentComponent*>::iterator it = instr->get_components()->begin() ; it != instr->get_components()->end(); ++it) { InstrumentComponent* pComponent = *it; QDomNode componentNode = doc.createElement( "instrumentComponent" ); LocalFileMng::writeXmlString( componentNode, "component_id", QString("%1").arg( pComponent->get_drumkit_componentID() ) ); LocalFileMng::writeXmlString( componentNode, "gain", QString("%1").arg( pComponent->get_gain() ) ); for ( unsigned nLayer = 0; nLayer < InstrumentComponent::getMaxLayers(); nLayer++ ) { InstrumentLayer *pLayer = pComponent->get_layer( nLayer ); if ( pLayer == NULL ) continue; Sample *pSample = pLayer->get_sample(); if ( pSample == NULL ) continue; bool sIsModified = pSample->get_is_modified(); Sample::Loops lo = pSample->get_loops(); Sample::Rubberband ro = pSample->get_rubberband(); QString sMode = pSample->get_loop_mode_string(); QDomNode layerNode = doc.createElement( "layer" ); LocalFileMng::writeXmlString( layerNode, "filename", Filesystem::prepare_sample_path( pSample->get_filepath() ) ); LocalFileMng::writeXmlBool( layerNode, "ismodified", sIsModified); LocalFileMng::writeXmlString( layerNode, "smode", pSample->get_loop_mode_string() ); LocalFileMng::writeXmlString( layerNode, "startframe", QString("%1").arg( lo.start_frame ) ); LocalFileMng::writeXmlString( layerNode, "loopframe", QString("%1").arg( lo.loop_frame ) ); LocalFileMng::writeXmlString( layerNode, "loops", QString("%1").arg( lo.count ) ); LocalFileMng::writeXmlString( layerNode, "endframe", QString("%1").arg( lo.end_frame ) ); LocalFileMng::writeXmlString( layerNode, "userubber", QString("%1").arg( ro.use ) ); LocalFileMng::writeXmlString( layerNode, "rubberdivider", QString("%1").arg( ro.divider ) ); LocalFileMng::writeXmlString( layerNode, "rubberCsettings", QString("%1").arg( ro.c_settings ) ); LocalFileMng::writeXmlString( layerNode, "rubberPitch", QString("%1").arg( ro.pitch ) ); LocalFileMng::writeXmlString( layerNode, "min", QString("%1").arg( pLayer->get_start_velocity() ) ); LocalFileMng::writeXmlString( layerNode, "max", QString("%1").arg( pLayer->get_end_velocity() ) ); LocalFileMng::writeXmlString( layerNode, "gain", QString("%1").arg( pLayer->get_gain() ) ); LocalFileMng::writeXmlString( layerNode, "pitch", QString("%1").arg( pLayer->get_pitch() ) ); Sample::VelocityEnvelope* velocity = pSample->get_velocity_envelope(); for (int y = 0; y < velocity->size(); y++){ QDomNode volumeNode = doc.createElement( "volume" ); LocalFileMng::writeXmlString( volumeNode, "volume-position", QString("%1").arg( velocity->at(y).frame ) ); LocalFileMng::writeXmlString( volumeNode, "volume-value", QString("%1").arg( velocity->at(y).value ) ); layerNode.appendChild( volumeNode ); } Sample::PanEnvelope* pan = pSample->get_pan_envelope(); for (int y = 0; y < pan->size(); y++){ QDomNode panNode = doc.createElement( "pan" ); LocalFileMng::writeXmlString( panNode, "pan-position", QString("%1").arg( pan->at(y).frame ) ); LocalFileMng::writeXmlString( panNode, "pan-value", QString("%1").arg( pan->at(y).value ) ); layerNode.appendChild( panNode ); } componentNode.appendChild( layerNode ); } instrumentNode.appendChild( componentNode ); } instrumentListNode.appendChild( instrumentNode ); } songNode.appendChild( instrumentListNode ); // pattern list QDomNode patternListNode = doc.createElement( "patternList" ); unsigned nPatterns = song->get_pattern_list()->size(); for ( unsigned i = 0; i < nPatterns; i++ ) { Pattern *pat = song->get_pattern_list()->get( i ); // pattern QDomNode patternNode = doc.createElement( "pattern" ); LocalFileMng::writeXmlString( patternNode, "name", pat->get_name() ); LocalFileMng::writeXmlString( patternNode, "category", pat->get_category() ); LocalFileMng::writeXmlString( patternNode, "size", QString("%1").arg( pat->get_length() ) ); LocalFileMng::writeXmlString( patternNode, "info", pat->get_info() ); QDomNode noteListNode = doc.createElement( "noteList" ); const Pattern::notes_t* notes = pat->get_notes(); FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) { Note *pNote = it->second; assert( pNote ); QDomNode noteNode = doc.createElement( "note" ); LocalFileMng::writeXmlString( noteNode, "position", QString("%1").arg( pNote->get_position() ) ); LocalFileMng::writeXmlString( noteNode, "leadlag", QString("%1").arg( pNote->get_lead_lag() ) ); LocalFileMng::writeXmlString( noteNode, "velocity", QString("%1").arg( pNote->get_velocity() ) ); LocalFileMng::writeXmlString( noteNode, "pan_L", QString("%1").arg( pNote->get_pan_l() ) ); LocalFileMng::writeXmlString( noteNode, "pan_R", QString("%1").arg( pNote->get_pan_r() ) ); LocalFileMng::writeXmlString( noteNode, "pitch", QString("%1").arg( pNote->get_pitch() ) ); LocalFileMng::writeXmlString( noteNode, "probability", QString("%1").arg( pNote->get_probability() ) ); LocalFileMng::writeXmlString( noteNode, "key", pNote->key_to_string() ); LocalFileMng::writeXmlString( noteNode, "length", QString("%1").arg( pNote->get_length() ) ); LocalFileMng::writeXmlString( noteNode, "instrument", QString("%1").arg( pNote->get_instrument()->get_id() ) ); QString noteoff = "false"; if ( pNote->get_note_off() ) noteoff = "true"; LocalFileMng::writeXmlString( noteNode, "note_off", noteoff ); noteListNode.appendChild( noteNode ); } patternNode.appendChild( noteListNode ); patternListNode.appendChild( patternNode ); }
void InstrumentEditor::buttonClicked( Button* pButton ) { if ( pButton == m_pShowInstrumentBtn ) { m_pShowInstrumentBtn->setPressed( true ); m_pShowLayersBtn->setPressed( false ); m_pInstrumentProp->show(); m_pLayerProp->hide(); m_pShowLayersBtn->show(); m_pShowInstrumentBtn->show(); } else if ( pButton == m_pShowLayersBtn ) { m_pShowLayersBtn->setPressed( true ); m_pShowInstrumentBtn->setPressed( false ); m_pLayerProp->show(); m_pInstrumentProp->hide(); m_pShowLayersBtn->show(); m_pShowInstrumentBtn->show(); } else if ( pButton == m_pLoadLayerBtn ) { loadLayer(); } else if ( pButton == m_pRemoveLayerBtn ) { //Hydrogen *pEngine = Hydrogen::get_instance(); AudioEngine::get_instance()->lock( RIGHT_HERE ); if ( m_pInstrument ) { InstrumentComponent* pCompo = m_pInstrument->get_component(m_nSelectedComponent); if( pCompo ) { H2Core::InstrumentLayer *pLayer = m_pInstrument->get_component(m_nSelectedComponent)->get_layer( m_nSelectedLayer ); if ( pLayer ) { m_pInstrument->get_component(m_nSelectedComponent)->set_layer( NULL, m_nSelectedLayer ); delete pLayer; } int p_count = 0; for( int n = 0; n < MAX_LAYERS; n++ ) { InstrumentLayer* layer = m_pInstrument->get_component(m_nSelectedComponent)->get_layer( n ); if( layer ) p_count++; } if( p_count == 0 ) m_pInstrument->get_components()->erase( m_pInstrument->get_components()->begin() + m_nSelectedComponent ); } } AudioEngine::get_instance()->unlock(); selectedInstrumentChangedEvent(); // update all m_pLayerPreview->updateAll(); } else if ( pButton == m_pSampleEditorBtn ){ if ( m_pInstrument ) { InstrumentComponent* pCompo = m_pInstrument->get_component(m_nSelectedComponent); if( pCompo ) { H2Core::InstrumentLayer *pLayer = pCompo->get_layer( m_nSelectedLayer ); if ( pLayer ) { Sample* pSample = pLayer->get_sample(); if( pSample == NULL) return; QString name = pSample->get_filepath(); HydrogenApp::get_instance()->showSampleEditor( name, m_nSelectedLayer ); } } } } else { ERRORLOG( "[buttonClicked] unhandled button" ); } }
void InstrumentEditor::rotaryChanged(Rotary *ref) { float fVal = ref->getValue(); if ( m_pInstrument ) { if ( ref == m_pRandomPitchRotary ){ m_pInstrument->set_random_pitch_factor( fVal ); } else if ( ref == m_pCutoffRotary ) { m_pInstrument->set_filter_cutoff( fVal ); } else if ( ref == m_pResonanceRotary ) { if ( fVal > 0.95f ) { fVal = 0.95f; } m_pInstrument->set_filter_resonance( fVal ); } else if ( ref == m_pAttackRotary ) { m_pInstrument->get_adsr()->set_attack( fVal * fVal * 100000 ); } else if ( ref == m_pDecayRotary ) { m_pInstrument->get_adsr()->set_decay( fVal * fVal * 100000 ); } else if ( ref == m_pSustainRotary ) { m_pInstrument->get_adsr()->set_sustain( fVal ); } else if ( ref == m_pReleaseRotary ) { m_pInstrument->get_adsr()->set_release( 256.0 + fVal * fVal * 100000 ); } else if ( ref == m_pLayerGainRotary ) { fVal = fVal * 5.0; char tmp[20]; sprintf( tmp, "%#.2f", fVal ); m_pLayerGainLCD->setText( tmp ); InstrumentComponent* pCompo = m_pInstrument->get_component(m_nSelectedComponent); if( pCompo ) { H2Core::InstrumentLayer *pLayer = pCompo->get_layer( m_nSelectedLayer ); if ( pLayer ) { pLayer->set_gain( fVal ); m_pWaveDisplay->updateDisplay( pLayer ); } } } else if ( ref == m_pCompoGainRotary ) { fVal = fVal * 5.0; char tmp[20]; sprintf( tmp, "%#.2f", fVal ); m_pCompoGainLCD->setText( tmp ); InstrumentComponent* pCompo = m_pInstrument->get_component(m_nSelectedComponent); pCompo->set_gain( fVal ); } else if ( ref == m_pLayerPitchCoarseRotary ) { //fVal = fVal * 24.0 - 12.0; m_pLayerPitchCoarseLCD->setText( QString( "%1" ).arg( (int)fVal ) ); InstrumentComponent* pCompo = m_pInstrument->get_component(m_nSelectedComponent); if( pCompo ) { H2Core::InstrumentLayer *pLayer = pCompo->get_layer( m_nSelectedLayer ); if ( pLayer ) { int nCoarse = (int)m_pLayerPitchCoarseRotary->getValue(); float fFine = m_pLayerPitchFineRotary->getValue() / 100.0; pLayer->set_pitch( nCoarse + fFine ); INFOLOG( QString("pitch: %1").arg( pLayer->get_pitch() ) ); } } } else if ( ref == m_pLayerPitchFineRotary ) { m_pLayerPitchFineLCD->setText( QString( "%1" ).arg( fVal ) ); InstrumentComponent* pCompo = m_pInstrument->get_component(m_nSelectedComponent); if( pCompo ) { H2Core::InstrumentLayer *pLayer = pCompo->get_layer( m_nSelectedLayer ); if ( pLayer ) { int nCoarse = (int)m_pLayerPitchCoarseRotary->getValue(); float fFine = m_pLayerPitchFineRotary->getValue() / 100.0; pLayer->set_pitch( nCoarse + fFine ); INFOLOG( QString("pitch: %1").arg( pLayer->get_pitch()) ); } } } else if ( ref == m_pInstrumentGain ) { fVal = fVal * 5.0; char tmp[20]; sprintf( tmp, "%#.2f", fVal ); m_pInstrumentGainLCD->setText( tmp ); m_pInstrument->set_gain( fVal ); } else { ERRORLOG( "[rotaryChanged] unhandled rotary" ); } } }
void InstrumentEditor::selectedInstrumentChangedEvent() { AudioEngine::get_instance()->lock( RIGHT_HERE ); Song *pSong = Hydrogen::get_instance()->getSong(); if (pSong != NULL) { InstrumentList *pInstrList = pSong->get_instrument_list(); int nInstr = Hydrogen::get_instance()->getSelectedInstrumentNumber(); if ( nInstr >= (int)pInstrList->size() ) { nInstr = -1; } if (nInstr == -1) { m_pInstrument = NULL; } else { m_pInstrument = pInstrList->get( nInstr ); //INFOLOG( "new instr: " + m_pInstrument->m_sName ); } } else { m_pInstrument = NULL; } AudioEngine::get_instance()->unlock(); // update layer list if (m_pInstrument) { m_pNameLbl->setText( m_pInstrument->get_name() ); // ADSR m_pAttackRotary->setValue( sqrtf(m_pInstrument->get_adsr()->get_attack() / 100000.0) ); m_pDecayRotary->setValue( sqrtf(m_pInstrument->get_adsr()->get_decay() / 100000.0) ); m_pSustainRotary->setValue( m_pInstrument->get_adsr()->get_sustain() ); float fTmp = m_pInstrument->get_adsr()->get_release() - 256.0; if( fTmp < 0.0 ) { fTmp = 0.0; } m_pReleaseRotary->setValue( sqrtf(fTmp / 100000.0) ); //~ ADSR // filter m_pFilterBypassBtn->setPressed( !m_pInstrument->is_filter_active()); m_pCutoffRotary->setValue( m_pInstrument->get_filter_cutoff()); m_pResonanceRotary->setValue( m_pInstrument->get_filter_resonance()); //~ filter // random pitch m_pRandomPitchRotary->setValue( m_pInstrument->get_random_pitch_factor()); //Stop Note m_pIsStopNoteCheckBox->setChecked( m_pInstrument->is_stop_notes() ); // instr gain char tmp[20]; sprintf( tmp, "%#.2f", m_pInstrument->get_gain()); m_pInstrumentGainLCD->setText( tmp ); m_pInstrumentGain->setValue( m_pInstrument->get_gain()/ 5.0 ); // instr mute group QString sMuteGroup = QString("%1").arg( m_pInstrument->get_mute_group() ); if (m_pInstrument->get_mute_group() == -1 ) { sMuteGroup = "Off"; } m_pMuteGroupLCD->setText( sMuteGroup ); // midi out QString sMidiOutChannel = QString("%1").arg( m_pInstrument->get_midi_out_channel()+1); if (m_pInstrument->get_midi_out_channel() == -1 ) { sMidiOutChannel = "Off"; } m_pMidiOutChannelLCD->setText( sMidiOutChannel ); // hihat m_pIsHihat->setChecked( m_pInstrument->is_hihat() ); QString sHiHatMinRange = QString("%1").arg( m_pInstrument->get_lower_cc() ); m_pHihatMinRangeLCD->setText( sHiHatMinRange ); QString sHiHatMaxRange = QString("%1").arg( m_pInstrument->get_higher_cc() ); m_pHihatMaxRangeLCD->setText( sHiHatMaxRange ); //Convert note id into notation { int note = m_pInstrument->get_midi_out_note(); int octave = (note / 12) - 2; const char *noteStrs[12] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; QString sMidiOutNote = QString(noteStrs[note % 12]) + QString::number(octave); m_pMidiOutNoteLCD->setText( sMidiOutNote ); } itemsCompo.clear(); std::vector<DrumkitComponent*>* compoList = Hydrogen::get_instance()->getSong()->get_components(); for (std::vector<DrumkitComponent*>::iterator it = compoList->begin() ; it != compoList->end(); ++it) { DrumkitComponent* p_compo = *it; if( !itemsCompo.contains( p_compo->get_name() ) ) itemsCompo.append( p_compo->get_name() ); } itemsCompo.append("--sep--"); itemsCompo.append("add"); itemsCompo.append("delete"); itemsCompo.append("rename"); update(); DrumkitComponent* p_tmpCompo = Hydrogen::get_instance()->getSong()->get_component( m_nSelectedComponent ); assert(p_tmpCompo); m_pCompoNameLbl->setText( p_tmpCompo->get_name() ); if(m_nSelectedLayer >= 0){ InstrumentComponent* component = m_pInstrument->get_component( m_nSelectedComponent ); if(component) { char tmp[20]; sprintf( tmp, "%#.2f", component->get_gain()); m_pCompoGainLCD->setText( tmp ); m_pCompoGainRotary->setValue( component->get_gain() / 5.0 ); InstrumentLayer* p_layer = component->get_layer( m_nSelectedLayer ); if(p_layer) { m_pWaveDisplay->updateDisplay( p_layer ); } else { m_pWaveDisplay->updateDisplay( NULL ); } } else { m_pWaveDisplay->updateDisplay( NULL ); } } else{ m_pWaveDisplay->updateDisplay( NULL ); } } else { m_pNameLbl->setText( QString( "NULL Instrument..." ) ); m_pWaveDisplay->updateDisplay( NULL ); m_nSelectedLayer = 0; } selectLayer( m_nSelectedLayer ); }
void InstrumentEditor::compoChangeAddDelete(QAction* pAction) { QString sSelectedAction = pAction->text(); Hydrogen * pEngine = Hydrogen::get_instance(); if( sSelectedAction.compare("add") == 0 ) { if ( m_pInstrument ) { bool bIsOkPressed; QString sNewName = QInputDialog::getText( this, "Hydrogen", trUtf8( "Component name" ), QLineEdit::Normal, "New Component", &bIsOkPressed ); if ( bIsOkPressed ) { DrumkitComponent* pDrumkitComponent = new DrumkitComponent( findFreeDrumkitComponentId(), sNewName ); pEngine->getSong()->get_components()->push_back( pDrumkitComponent ); //InstrumentComponent* instrument_component = new InstrumentComponent( dm_component->get_id() ); //instrument_component->set_gain( 1.0f ); //m_pInstrument->get_components()->push_back( instrument_component ); m_nSelectedComponent = pDrumkitComponent->get_id(); m_pLayerPreview->set_selected_component( pDrumkitComponent->get_id() ); selectedInstrumentChangedEvent(); // this will force an update... EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); #ifdef H2CORE_HAVE_JACK pEngine->renameJackPorts(pEngine->getSong()); #endif } else { // user entered nothing or pressed Cancel } } } else if( sSelectedAction.compare("delete") == 0 ) { std::vector<DrumkitComponent*>* pDrumkitComponents = pEngine->getSong()->get_components(); if(pDrumkitComponents->size() == 1){ return; } DrumkitComponent* pDrumkitComponent = pEngine->getSong()->get_component( m_nSelectedComponent ); InstrumentList* pInstruments = pEngine->getSong()->get_instrument_list(); for ( int n = ( int )pInstruments->size() - 1; n >= 0; n-- ) { Instrument* pInstrument = pInstruments->get( n ); for( int o = 0 ; o < pInstrument->get_components()->size() ; o++ ) { InstrumentComponent* pInstrumentComponent = pInstrument->get_components()->at( o ); if( pInstrumentComponent->get_drumkit_componentID() == pDrumkitComponent->get_id() ) { for( int nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) { InstrumentLayer* pLayer = pInstrumentComponent->get_layer( nLayer ); if( pLayer ) delete pLayer; } pInstrument->get_components()->erase( pInstrument->get_components()->begin() + o );; break; } } } for ( int n = 0 ; n < pDrumkitComponents->size() ; n++ ) { DrumkitComponent* pTmpDrumkitComponent = pDrumkitComponents->at( n ); if( pTmpDrumkitComponent->get_id() == pDrumkitComponent->get_id() ) { pDrumkitComponents->erase( pDrumkitComponents->begin() + n ); break; } } m_nSelectedComponent = pDrumkitComponents->front()->get_id(); selectedInstrumentChangedEvent(); // this will force an update... EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); } else if( sSelectedAction.compare("rename") == 0 ) { labelCompoClicked( NULL ); } else { m_nSelectedComponent = -1; std::vector<DrumkitComponent*>* pDrumkitComponents = pEngine->getSong()->get_components(); for (std::vector<DrumkitComponent*>::iterator it = pDrumkitComponents->begin() ; it != pDrumkitComponents->end(); ++it) { DrumkitComponent* pDrumkitComponent = *it; if( pDrumkitComponent->get_name().compare( sSelectedAction ) == 0) { m_nSelectedComponent = pDrumkitComponent->get_id(); m_pCompoNameLbl->setText( pDrumkitComponent->get_name() ); break; } } if( m_pInstrument && !m_pInstrument->get_component(m_nSelectedComponent)) { INFOLOG("Component needs to be added"); InstrumentComponent* pInstrComponent = new InstrumentComponent( m_nSelectedComponent ); pInstrComponent->set_gain( 1.0f ); m_pInstrument->get_components()->push_back( pInstrComponent ); #ifdef H2CORE_HAVE_JACK pEngine->renameJackPorts(pEngine->getSong()); #endif } m_pLayerPreview->set_selected_component(m_nSelectedComponent); selectedInstrumentChangedEvent(); // this will force an update... EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 ); } }
/// Render a note /// Return 0: the note is not ended /// Return 1: the note is ended unsigned Sampler::__render_note( Note* pNote, unsigned nBufferSize, Song* pSong ) { //infoLog( "[renderNote] instr: " + pNote->getInstrument()->m_sName ); assert( pSong ); unsigned int nFramepos; Hydrogen* pEngine = Hydrogen::get_instance(); AudioOutput* audio_output = pEngine->getAudioOutput(); if ( pEngine->getState() == STATE_PLAYING ) { nFramepos = audio_output->m_transport.m_nFrames; } else { // use this to support realtime events when not playing nFramepos = pEngine->getRealtimeFrames(); } Instrument *pInstr = pNote->get_instrument(); if ( !pInstr ) { ERRORLOG( "NULL instrument" ); return 1; } int nReturnValue = 0; for (std::vector<InstrumentComponent*>::iterator it = pInstr->get_components()->begin() ; it !=pInstr->get_components()->end(); ++it) { InstrumentComponent *pCompo = *it; DrumkitComponent* pMainCompo = 0; if( pInstr->is_preview_instrument() || pInstr->is_metronome_instrument()){ pMainCompo = pEngine->getSong()->get_components()->front(); } else { pMainCompo = pEngine->getSong()->get_component( pCompo->get_drumkit_componentID() ); } assert(pMainCompo); float fLayerGain = 1.0; float fLayerPitch = 0.0; // scelgo il sample da usare in base alla velocity Sample *pSample = NULL; for ( unsigned nLayer = 0; nLayer < MAX_LAYERS; ++nLayer ) { InstrumentLayer *pLayer = pCompo->get_layer( nLayer ); if ( pLayer == NULL ) continue; if ( ( pNote->get_velocity() >= pLayer->get_start_velocity() ) && ( pNote->get_velocity() <= pLayer->get_end_velocity() ) ) { pSample = pLayer->get_sample(); fLayerGain = pLayer->get_gain(); fLayerPitch = pLayer->get_pitch(); break; } } if ( !pSample ) { QString dummy = QString( "NULL sample for instrument %1. Note velocity: %2" ).arg( pInstr->get_name() ).arg( pNote->get_velocity() ); WARNINGLOG( dummy ); nReturnValue = 1; continue; } if ( pNote->get_sample_position( pCompo->get_drumkit_componentID() ) >= pSample->get_frames() ) { WARNINGLOG( "sample position out of bounds. The layer has been resized during note play?" ); nReturnValue = 1; continue; } int noteStartInFrames = ( int ) ( pNote->get_position() * audio_output->m_transport.m_nTickSize ) + pNote->get_humanize_delay(); int nInitialSilence = 0; if ( noteStartInFrames > ( int ) nFramepos ) { // scrivo silenzio prima dell'inizio della nota nInitialSilence = noteStartInFrames - nFramepos; int nFrames = nBufferSize - nInitialSilence; if ( nFrames < 0 ) { int noteStartInFramesNoHumanize = ( int )pNote->get_position() * audio_output->m_transport.m_nTickSize; if ( noteStartInFramesNoHumanize > ( int )( nFramepos + nBufferSize ) ) { // this note is not valid. it's in the future...let's skip it.... ERRORLOG( QString( "Note pos in the future?? Current frames: %1, note frame pos: %2" ).arg( nFramepos ).arg(noteStartInFramesNoHumanize ) ); //pNote->dumpInfo(); nReturnValue = 1; continue; } // delay note execution //INFOLOG( "Delaying note execution. noteStartInFrames: " + to_string( noteStartInFrames ) + ", nFramePos: " + to_string( nFramepos ) ); //return 0; continue; } } float cost_L = 1.0f; float cost_R = 1.0f; float cost_track_L = 1.0f; float cost_track_R = 1.0f; assert(pMainCompo); if ( pInstr->is_muted() || pSong->__is_muted || pMainCompo->is_muted() ) { // is instrument muted? cost_L = 0.0; cost_R = 0.0; if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) { // Post-Fader cost_track_L = 0.0; cost_track_R = 0.0; } } else { // Precompute some values... cost_L = cost_L * pNote->get_velocity(); // note velocity cost_L = cost_L * pNote->get_pan_l(); // note pan cost_L = cost_L * fLayerGain; // layer gain cost_L = cost_L * pInstr->get_pan_l(); // instrument pan cost_L = cost_L * pInstr->get_gain(); // instrument gain cost_L = cost_L * pCompo->get_gain(); // Component gain cost_L = cost_L * pMainCompo->get_volume(); // Component volument cost_L = cost_L * pInstr->get_volume(); // instrument volume if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) { // Post-Fader 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 cost_R = cost_R * pNote->get_velocity(); // note velocity cost_R = cost_R * pNote->get_pan_r(); // note pan cost_R = cost_R * fLayerGain; // layer gain cost_R = cost_R * pInstr->get_pan_r(); // instrument pan cost_R = cost_R * pInstr->get_gain(); // instrument gain cost_R = cost_R * pCompo->get_gain(); // Component gain cost_R = cost_R * pMainCompo->get_volume(); // Component volument cost_R = cost_R * pInstr->get_volume(); // instrument volume if ( Preferences::get_instance()->m_nJackTrackOutputMode == 0 ) { // Post-Fader 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 } // direct track outputs only use velocity if ( Preferences::get_instance()->m_nJackTrackOutputMode == 1 ) { 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 // constant^12 = 2, so constant = 2^(1/12) = 1.059463. // float nStep = 1.0;1.0594630943593 float fTotalPitch = pNote->get_total_pitch() + fLayerPitch; //_INFOLOG( "total pitch: " + to_string( fTotalPitch ) ); if( ( int )pNote->get_sample_position(pCompo->get_drumkit_componentID()) == 0 ) { if( Hydrogen::get_instance()->getMidiOutput() != NULL ){ Hydrogen::get_instance()->getMidiOutput()->handleQueueNote( pNote ); } } if ( fTotalPitch == 0.0 && pSample->get_sample_rate() == audio_output->getSampleRate() ) { // NO RESAMPLE if ( __render_note_no_resample( pSample, pNote, pCompo, pMainCompo, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, pSong ) == 1 ) nReturnValue = 1; } else { // RESAMPLE if ( __render_note_resample( pSample, pNote, pCompo, pMainCompo, nBufferSize, nInitialSilence, cost_L, cost_R, cost_track_L, cost_track_R, fLayerPitch, pSong ) == 1 ) nReturnValue = 1; } } return nReturnValue; }
void Instrument::load_from( Drumkit* pDrumkit, Instrument* pInstrument, bool is_live ) { this->get_components()->clear(); for (std::vector<InstrumentComponent*>::iterator it = pInstrument->get_components()->begin() ; it != pInstrument->get_components()->end(); ++it) { InstrumentComponent* pSrcComponent = *it; InstrumentComponent* pMyComponent = new InstrumentComponent( pSrcComponent->get_drumkit_componentID() ); pMyComponent->set_gain( pSrcComponent->get_gain() ); this->get_components()->push_back( pMyComponent ); for ( int i=0; i<MAX_LAYERS; i++ ) { InstrumentLayer* src_layer = pSrcComponent->get_layer( i ); InstrumentLayer* my_layer = pMyComponent->get_layer( i ); if( src_layer==0 ) { if ( is_live ) AudioEngine::get_instance()->lock( RIGHT_HERE ); pMyComponent->set_layer( NULL, i ); if ( is_live ) AudioEngine::get_instance()->unlock(); } else { QString sample_path = pDrumkit->get_path() + "/" + src_layer->get_sample()->get_filename(); Sample* sample = Sample::load( sample_path ); if ( sample==0 ) { _ERRORLOG( QString( "Error loading sample %1. Creating a new empty layer." ).arg( sample_path ) ); if ( is_live ) AudioEngine::get_instance()->lock( RIGHT_HERE ); pMyComponent->set_layer( NULL, i ); if ( is_live ) AudioEngine::get_instance()->unlock(); } else { if ( is_live ) AudioEngine::get_instance()->lock( RIGHT_HERE ); pMyComponent->set_layer( new InstrumentLayer( src_layer, sample ), i ); if ( is_live ) AudioEngine::get_instance()->unlock(); } } delete my_layer; } } if ( is_live ) AudioEngine::get_instance()->lock( RIGHT_HERE ); this->set_id( pInstrument->get_id() ); this->set_name( pInstrument->get_name() ); this->set_drumkit_name( pDrumkit->get_name() ); this->set_gain( pInstrument->get_gain() ); this->set_volume( pInstrument->get_volume() ); this->set_pan_l( pInstrument->get_pan_l() ); this->set_pan_r( pInstrument->get_pan_r() ); this->set_adsr( new ADSR( *( pInstrument->get_adsr() ) ) ); this->set_filter_active( pInstrument->is_filter_active() ); this->set_filter_cutoff( pInstrument->get_filter_cutoff() ); this->set_filter_resonance( pInstrument->get_filter_resonance() ); this->set_random_pitch_factor( pInstrument->get_random_pitch_factor() ); this->set_muted( pInstrument->is_muted() ); this->set_mute_group( pInstrument->get_mute_group() ); this->set_midi_out_channel( pInstrument->get_midi_out_channel() ); this->set_midi_out_note( pInstrument->get_midi_out_note() ); this->set_stop_notes( pInstrument->is_stop_notes() ); this->set_hihat_grp( pInstrument->get_hihat_grp() ); this->set_lower_cc( pInstrument->get_lower_cc() ); this->set_higher_cc( pInstrument->get_higher_cc() ); if ( is_live ) AudioEngine::get_instance()->unlock(); }
SongEditorPanel::SongEditorPanel(QWidget *pParent) : QWidget( pParent ) , Object( __class_name ) , m_actionMode( DRAW_ACTION ) { m_nInitialWidth = 600; m_nInitialHeight = 250; Preferences *pPref = Preferences::get_instance(); Hydrogen* pEngine = Hydrogen::get_instance(); Song* pSong = pEngine->getSong(); setWindowTitle( trUtf8( "Song Editor" ) ); // background PixmapWidget *pBackPanel = new PixmapWidget( NULL ); pBackPanel->setFixedSize( 196, 49 ); pBackPanel->setPixmap( "/songEditor/bg_topPanel.png" ); // time line toggle button m_pTimeLineToggleBtn = new ToggleButton( pBackPanel, "/songEditor/btn_bpm_on.png", "/songEditor/btn_bpm_off.png", "/songEditor/btn_bpm_over.png", QSize( 54, 13 ) ); m_pTimeLineToggleBtn->move( 133, 6 ); m_pTimeLineToggleBtn->setToolTip( trUtf8( "Enable time line edit") ); connect( m_pTimeLineToggleBtn, SIGNAL( clicked( Button* ) ), this, SLOT( timeLineBtnPressed(Button* ) ) ); m_pTimeLineToggleBtn->setPressed( pPref->getUseTimelineBpm() ); // clear sequence button m_pClearPatternSeqBtn = new Button( pBackPanel, "/songEditor/btn_clear_on.png", "/songEditor/btn_clear_off.png", "/songEditor/btn_clear_over.png", QSize(53,13) ); m_pClearPatternSeqBtn->move( 6, 5 + 25 ); m_pClearPatternSeqBtn->setToolTip( trUtf8("Clear pattern sequence") ); connect( m_pClearPatternSeqBtn, SIGNAL( clicked( Button* ) ), this, SLOT( clearSequence(Button*) ) ); // new pattern button Button *newPatBtn = new Button( pBackPanel, "/songEditor/btn_new_on.png", "/songEditor/btn_new_off.png", "/songEditor/btn_new_over.png", QSize(19, 13) ); newPatBtn->move( 64, 5 + 25); newPatBtn->setToolTip( trUtf8("Create new pattern") ); connect( newPatBtn, SIGNAL( clicked( Button* ) ), this, SLOT( newPatBtnClicked( Button* ) ) ); // down button m_pDownBtn = new Button( pBackPanel, "/songEditor/btn_down_on.png", "/songEditor/btn_down_off.png", "/songEditor/btn_down_over.png", QSize(18,13) ); m_pDownBtn->move( 89, 5 + 25); m_pDownBtn->setToolTip( trUtf8("Move the selected pattern down") ); connect( m_pDownBtn, SIGNAL( clicked( Button* ) ), this, SLOT( downBtnClicked( Button* ) ) ); // up button m_pUpBtn = new Button( pBackPanel, "/songEditor/btn_up_on.png", "/songEditor/btn_up_off.png", "/songEditor/btn_up_over.png", QSize(18,13) ); m_pUpBtn->move( 106, 5 + 25 ); m_pUpBtn->setToolTip( trUtf8("Move the selected pattern up") ); connect( m_pUpBtn, SIGNAL( clicked( Button* ) ), this, SLOT( upBtnClicked( Button* ) ) ); // select toggle button m_pPointerActionBtn = new ToggleButton( pBackPanel, "/songEditor/btn_select_on.png", "/songEditor/btn_select_off.png", "/songEditor/btn_select_over.png", QSize( 18, 13 ) ); m_pPointerActionBtn->move( 128, 5 + 25 ); m_pPointerActionBtn->setToolTip( trUtf8( "Select mode" ) ); connect( m_pPointerActionBtn, SIGNAL( clicked( Button* ) ), this, SLOT( pointerActionBtnPressed(Button*) ) ); // draw toggle button m_pDrawActionBtn = new ToggleButton( pBackPanel, "/songEditor/btn_draw_on.png", "/songEditor/btn_draw_off.png", "/songEditor/btn_draw_over.png", QSize( 18, 13 ) ); m_pDrawActionBtn->move( 147, 5 + 25 ); m_pDrawActionBtn->setToolTip( trUtf8( "Draw mode") ); connect( m_pDrawActionBtn, SIGNAL( clicked( Button* ) ), this, SLOT( drawActionBtnPressed(Button* ) ) ); m_pDrawActionBtn->setPressed( true ); m_pModeActionBtn = new ToggleButton( pBackPanel, "/songEditor/btn_mode_on.png", "/songEditor/btn_mode_off.png", "/songEditor/btn_mode_over.png", QSize( 18, 13 ) ); m_pModeActionBtn->move( 169, 5 + 25 ); m_pModeActionBtn->setToolTip( trUtf8( "stacked mode") ); m_pModeActionBtn->setPressed( pPref->patternModePlaysSelected() ); connect( m_pModeActionBtn, SIGNAL( clicked( Button* ) ), this, SLOT( modeActionBtnPressed() ) ); // ZOOM m_pHScrollBar = new QScrollBar( Qt::Horizontal,NULL ); connect( m_pHScrollBar, SIGNAL(valueChanged(int)), this, SLOT( syncToExternalScrollBar() ) ); // zoom-in btn Button* pZoomInBtn = new Button( NULL, "/songEditor/btn_new_on.png", "/songEditor/btn_new_off.png", "/songEditor/btn_new_over.png", QSize( 19, 13 ) ); connect( pZoomInBtn, SIGNAL( clicked( Button* ) ), this, SLOT( zoomOutBtnPressed(Button* ) ) ); // zoom-out btn Button* pZoomOutBtn = new Button( NULL, "/songEditor/btn_minus_on.png", "/songEditor/btn_minus_off.png", "/songEditor/btn_minus_over.png", QSize( 19, 13 ) ); connect( pZoomOutBtn, SIGNAL( clicked( Button* ) ), this, SLOT( zoomInBtnPressed(Button* ) ) ); // view playback track toggle button m_pViewPlaybackToggleBtn = new ToggleButton( NULL, "/songEditor/btn_viewPL_on.png", "/songEditor/btn_viewPL_off.png", "/songEditor/btn_viewPL_over.png", QSize( 19, 13 ) ); m_pViewPlaybackToggleBtn->setToolTip( trUtf8( "View playback track") ); connect( m_pViewPlaybackToggleBtn, SIGNAL( clicked( Button* ) ), this, SLOT( viewPlaybackTrackBtnPressed(Button* ) ) ); m_pViewPlaybackToggleBtn->setPressed( false ); // Playback Fader m_pPlaybackTrackFader = new VerticalFader( pBackPanel, false, false ); m_pPlaybackTrackFader->move( 6, 2 ); m_pPlaybackTrackFader->setMinValue( 0.0 ); m_pPlaybackTrackFader->setMaxValue( 1.5 ); m_pPlaybackTrackFader->setValue( pSong->get_playback_track_volume() ); m_pPlaybackTrackFader->hide(); connect( m_pPlaybackTrackFader, SIGNAL( valueChanged(Fader*) ), this, SLOT( faderChanged(Fader*) ) ); // mute playback track toggle button m_pMutePlaybackToggleBtn = new ToggleButton( pBackPanel, "/mixerPanel/master_mute_on.png", "/mixerPanel/master_mute_off.png", "/mixerPanel/master_mute_over.png", QSize( 42, 13 ) ); m_pMutePlaybackToggleBtn->setToolTip( trUtf8( "Mute playback track") ); m_pMutePlaybackToggleBtn->move( 151, 6 ); m_pMutePlaybackToggleBtn->hide(); connect( m_pMutePlaybackToggleBtn, SIGNAL( clicked( Button* ) ), this, SLOT( mutePlaybackTrackBtnPressed(Button* ) ) ); m_pMutePlaybackToggleBtn->setPressed( !pSong->get_playback_track_enabled() ); // edit playback track toggle button m_pEditPlaybackBtn = new Button( pBackPanel, "/mixerPanel/edit_on.png", "/mixerPanel/edit_off.png", "/mixerPanel/edit_over.png", QSize( 42, 13 ) ); m_pEditPlaybackBtn->setToolTip( trUtf8( "Choose playback track") ); m_pEditPlaybackBtn->move( 124, 6 ); m_pEditPlaybackBtn->hide(); connect( m_pEditPlaybackBtn, SIGNAL( clicked( Button* ) ), this, SLOT( editPlaybackTrackBtnPressed(Button* ) ) ); m_pEditPlaybackBtn->setPressed( false ); // timeline view toggle button m_pViewTimeLineToggleBtn = new ToggleButton( NULL, "/songEditor/btn_viewTL_on.png", "/songEditor/btn_viewTL_off.png", "/songEditor/btn_viewTL_over.png", QSize( 19, 13 ) ); m_pViewTimeLineToggleBtn->setToolTip( trUtf8( "View timeline") ); connect( m_pViewTimeLineToggleBtn, SIGNAL( clicked( Button* ) ), this, SLOT( viewTimeLineBtnPressed(Button* ) ) ); m_pViewTimeLineToggleBtn->setPressed( true ); QHBoxLayout *pHZoomLayout = new QHBoxLayout(); pHZoomLayout->setSpacing( 0 ); pHZoomLayout->setMargin( 0 ); pHZoomLayout->addWidget( m_pViewPlaybackToggleBtn ); pHZoomLayout->addWidget( m_pViewTimeLineToggleBtn ); pHZoomLayout->addWidget( m_pHScrollBar ); pHZoomLayout->addWidget( pZoomInBtn ); pHZoomLayout->addWidget( pZoomOutBtn ); QWidget *pHScrollbarPanel = new QWidget(); pHScrollbarPanel->setLayout( pHZoomLayout ); //~ ZOOM // PATTERN LIST m_pPatternListScrollView = new QScrollArea( NULL ); m_pPatternListScrollView->setFrameShape( QFrame::NoFrame ); m_pPatternListScrollView->setFixedWidth( m_nPatternListWidth ); m_pPatternListScrollView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_pPatternListScrollView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); connect( m_pPatternListScrollView->verticalScrollBar(), SIGNAL( valueChanged(int) ), this, SLOT( on_patternListScroll() ) ); m_pPatternList = new SongEditorPatternList( m_pPatternListScrollView->viewport() ); m_pPatternListScrollView->setWidget( m_pPatternList ); // EDITOR m_pEditorScrollView = new QScrollArea( NULL ); m_pEditorScrollView->setFrameShape( QFrame::NoFrame ); m_pEditorScrollView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_pEditorScrollView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_pSongEditor = new SongEditor( m_pEditorScrollView->viewport() ); m_pEditorScrollView->setWidget( m_pSongEditor ); connect( m_pEditorScrollView->horizontalScrollBar(), SIGNAL( valueChanged(int) ), this, SLOT( on_EditorScroll() ) ); connect( m_pEditorScrollView->verticalScrollBar(), SIGNAL( valueChanged(int) ), this, SLOT( on_EditorScroll() ) ); // POSITION RULER m_pPositionRulerScrollView = new QScrollArea( NULL ); m_pPositionRulerScrollView->setFrameShape( QFrame::NoFrame ); m_pPositionRulerScrollView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_pPositionRulerScrollView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_pPositionRulerScrollView->setFixedHeight( 50 ); m_pWidgetStack = new QStackedWidget( m_pPositionRulerScrollView ); m_pPositionRuler = new SongEditorPositionRuler( NULL ); m_pWaveDisplay = new WaveDisplay( m_pPositionRulerScrollView->viewport() ); InstrumentComponent *pCompo = AudioEngine::get_instance()->get_sampler()->__preview_instrument->get_components()->front(); assert(pCompo); m_pWaveDisplay->updateDisplay( pCompo->get_layer(0) ); m_pWidgetStack->addWidget( m_pPositionRuler ); m_pWidgetStack->addWidget( m_pWaveDisplay ); m_pPositionRulerScrollView->setWidgetResizable(true); m_pPositionRulerScrollView->setWidget( m_pWidgetStack ); m_pAutomationPathScrollView = new QScrollArea( NULL ); m_pAutomationPathScrollView->setFrameShape( QFrame::NoFrame ); m_pAutomationPathScrollView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_pAutomationPathScrollView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_pAutomationPathView = new AutomationPathView( m_pAutomationPathScrollView->viewport() ); m_pAutomationPathScrollView->setWidget( m_pAutomationPathView ); m_pAutomationPathScrollView->setFixedHeight( 64 ); connect( m_pAutomationPathView, SIGNAL( valueChanged() ), this, SLOT( automationPathChanged() ) ); connect( m_pAutomationPathView, SIGNAL( pointAdded(float, float) ), this, SLOT( automationPathPointAdded(float,float) ) ); connect( m_pAutomationPathView, SIGNAL( pointRemoved(float, float) ), this, SLOT( automationPathPointRemoved(float,float) ) ); connect( m_pAutomationPathView, SIGNAL( pointMoved(float, float, float, float) ), this, SLOT( automationPathPointMoved(float,float, float, float) ) ); m_pAutomationCombo = new LCDCombo( NULL, 22 ); m_pAutomationCombo->setToolTip( trUtf8("Adjust parameter values in time") ); m_pAutomationCombo->addItem( trUtf8("Velocity") ); m_pAutomationCombo->set_text( trUtf8("Velocity") ); m_pAutomationCombo->update(); m_pVScrollBar = new QScrollBar( Qt::Vertical, NULL ); connect( m_pVScrollBar, SIGNAL(valueChanged(int)), this, SLOT( syncToExternalScrollBar() ) ); // ok...let's build the layout QGridLayout *pGridLayout = new QGridLayout(); pGridLayout->setSpacing( 0 ); pGridLayout->setMargin( 0 ); pGridLayout->addWidget( pBackPanel, 0, 0 ); pGridLayout->addWidget( m_pPositionRulerScrollView, 0, 1 ); pGridLayout->addWidget( m_pPatternListScrollView, 1, 0 ); pGridLayout->addWidget( m_pEditorScrollView, 1, 1 ); pGridLayout->addWidget( m_pVScrollBar, 1, 2, 2, 1 ); pGridLayout->addWidget( m_pAutomationPathScrollView, 2, 1); pGridLayout->addWidget( m_pAutomationCombo, 2, 0, Qt::AlignTop | Qt::AlignRight ); pGridLayout->addWidget( pHScrollbarPanel, 3, 1 ); if( !pPref->getShowAutomationArea() ){ m_pAutomationPathScrollView->hide(); m_pAutomationCombo->hide(); } this->setLayout( pGridLayout ); QPalette defaultPalette; defaultPalette.setColor( QPalette::Background, QColor( 58, 62, 72 ) ); this->setPalette( defaultPalette ); show(); updateAll(); HydrogenApp::get_instance()->addEventListener( this ); m_pTimer = new QTimer(this); connect(m_pTimer, SIGNAL(timeout()), this, SLOT( updatePlayHeadPosition() ) ); connect(m_pTimer, SIGNAL(timeout()), this, SLOT( updatePlaybackFaderPeaks() ) ); m_pTimer->start(100); }