void SongEditorPatternList::movePatternLine( int nSourcePattern , int nTargetPattern ) { Engine *engine = g_engine; T<Song>::shared_ptr pSong = engine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); // move instruments... T<Tritium::Pattern>::shared_ptr pSourcePattern = pPatternList->get( nSourcePattern );//Instrument *pSourceInstr = pPatternList->get(nSourcePattern); if ( nSourcePattern < nTargetPattern) { for (int nPatr = nSourcePattern; nPatr < nTargetPattern; nPatr++) { T<Tritium::Pattern>::shared_ptr pPattern = pPatternList->get(nPatr + 1); pPatternList->replace( pPattern, nPatr ); } pPatternList->replace( pSourcePattern, nTargetPattern ); } else { for (int nPatr = nSourcePattern; nPatr >= nTargetPattern; nPatr--) { T<Tritium::Pattern>::shared_ptr pPattern = pPatternList->get(nPatr - 1); pPatternList->replace( pPattern, nPatr ); } pPatternList->replace( pSourcePattern, nTargetPattern ); } engine->setSelectedPatternNumber( nTargetPattern ); CompositeApp::get_instance()->getSongEditorPanel()->updateAll(); }
void SongEditorPatternList::patternPopup_load() { Engine *engine = g_engine; int tmpselectedpatternpos = engine->getSelectedPatternNumber(); T<Song>::shared_ptr song = engine->getSong(); PatternList *pPatternList = song->get_pattern_list(); T<Instrument>::shared_ptr instr = engine->get_sampler()->get_instrument_list()->get( 0 ); assert( instr ); QDir dirPattern( g_engine->get_preferences()->getDataDirectory() + "/patterns" ); std::auto_ptr<QFileDialog> fd( new QFileDialog ); fd->setFileMode(QFileDialog::ExistingFile); fd->setFilter( trUtf8("Hydrogen Pattern (*.h2pattern)") ); fd->setDirectory(dirPattern ); fd->setWindowTitle( trUtf8( "Open Pattern" ) ); QString filename; if (fd->exec() == QDialog::Accepted) { filename = fd->selectedFiles().first(); } else { return; } LocalFileMng mng(g_engine); LocalFileMng fileMng(g_engine); T<Pattern>::shared_ptr err = fileMng.loadPattern( filename ); if ( err == 0 ) { ERRORLOG( "Error loading the pattern" ); }else{ T<Pattern>::shared_ptr pNewPattern = err; pPatternList->add( pNewPattern ); song->set_modified( true ); createBackground(); update(); } int listsize = pPatternList->get_size(); engine->setSelectedPatternNumber( listsize -1 ); T<Pattern>::shared_ptr pTemp = pPatternList->get( engine->getSelectedPatternNumber() ); pPatternList->replace( pPatternList->get( tmpselectedpatternpos ), listsize -1); pPatternList->replace( pTemp, tmpselectedpatternpos ); listsize = pPatternList->get_size(); engine->setSelectedPatternNumber( listsize -1 ); patternPopup_delete(); engine->setSelectedPatternNumber( tmpselectedpatternpos ); CompositeApp::get_instance()->getSongEditorPanel()->updateAll(); }
void SongEditor::keyPressEvent ( QKeyEvent * ev ) { Engine *pEngine = g_engine; PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); T<Song::pattern_group_t>::shared_ptr pColumns = pEngine->getSong()->get_pattern_group_vector(); if ( ev->key() == Qt::Key_Delete ) { if ( m_selectedCells.size() != 0 ) { g_engine->lock( RIGHT_HERE ); // delete all selected cells for ( uint i = 0; i < m_selectedCells.size(); i++ ) { QPoint cell = m_selectedCells[ i ]; T<PatternList>::shared_ptr pColumn = (*pColumns)[ cell.x() ]; pColumn->del(pPatternList->get( cell.y() ) ); } g_engine->unlock(); m_selectedCells.clear(); m_bSequenceChanged = true; update(); } return; } ev->ignore(); }
void PatternEditorPanel::selectedPatternChangedEvent() { PatternList *pPatternList = Hydrogen::get_instance()->getSong()->get_pattern_list(); int nSelectedPatternNumber = Hydrogen::get_instance()->getSelectedPatternNumber(); if ( (nSelectedPatternNumber != -1) && ( (uint)nSelectedPatternNumber < pPatternList->size() ) ) { // update pattern name text m_pPattern = pPatternList->get( nSelectedPatternNumber ); QString sCurrentPatternName = m_pPattern->get_name(); this->setWindowTitle( ( trUtf8( "Pattern editor - %1").arg( sCurrentPatternName ) ) ); m_pPatternNameLbl->setText( sCurrentPatternName ); // update pattern size combobox int nPatternSize = m_pPattern->get_length(); int nEighth = MAX_NOTES / 8; for ( int i = 1; i <= 32; i++ ) { if ( nPatternSize == nEighth * i ) { __pattern_size_combo->set_text( QString( "%1" ).arg( i ) ); break; } } } else { m_pPattern = NULL; this->setWindowTitle( ( trUtf8( "Pattern editor - %1").arg(QString("No pattern selected.")) ) ); m_pPatternNameLbl->setText( trUtf8( "No pattern selected" ) ); } resizeEvent( NULL ); // force an update of the scrollbars }
void SongEditorPatternList::patternPopup_copy() { Engine *pEngine = g_engine; T<Song>::shared_ptr pSong = pEngine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); int nSelectedPattern = pEngine->getSelectedPatternNumber(); T<Tritium::Pattern>::shared_ptr pPattern = pPatternList->get( nSelectedPattern ); T<Tritium::Pattern>::shared_ptr pNewPattern = pPattern->copy(); pPatternList->add( pNewPattern ); // rename the copied pattern PatternPropertiesDialog *dialog = new PatternPropertiesDialog( this, pNewPattern, true ); if ( dialog->exec() == QDialog::Accepted ) { pSong->set_modified( true ); pEngine->setSelectedPatternNumber(pPatternList->get_size() - 1); // select the last pattern (the copied one) if (pSong->get_mode() == Song::PATTERN_MODE) { pEngine->sequencer_setNextPattern( pPatternList->get_size() - 1, false, false ); // select the last pattern (the new copied pattern) } } else { pPatternList->del( pNewPattern ); pNewPattern.reset(); } delete dialog; CompositeApp::get_instance()->getSongEditorPanel()->updateAll(); }
void SongEditorPatternList::dropEvent(QDropEvent *event) { QString sText = event->mimeData()->text(); if( sText.startsWith("Songs:") || sText.startsWith("move instrument:") ){ event->acceptProposedAction(); return; } if (sText.startsWith("move pattern:")) { Engine *engine = g_engine; int nSourcePattern = engine->getSelectedPatternNumber(); int nTargetPattern = event->pos().y() / m_nGridHeight; if ( nSourcePattern == nTargetPattern ) { event->acceptProposedAction(); return; } movePatternLine( nSourcePattern , nTargetPattern ); event->acceptProposedAction(); }else { PatternList *pPatternList = g_engine->getSong()->get_pattern_list(); QStringList tokens = sText.split( "::" ); QString sPatternName = tokens.at( 1 ); int nTargetPattern = event->pos().y() / m_nGridHeight; LocalFileMng mng(g_engine); T<Pattern>::shared_ptr err = mng.loadPattern( sPatternName ); if ( err == 0 ) { ERRORLOG( "Error loading the pattern" ); }else{ T<Pattern>::shared_ptr pNewPattern = err; pPatternList->add( pNewPattern ); for (int nPatr = pPatternList->get_size() +1 ; nPatr >= nTargetPattern; nPatr--) { T<Tritium::Pattern>::shared_ptr pPattern = pPatternList->get(nPatr - 1); pPatternList->replace( pPattern, nPatr ); } pPatternList->replace( pNewPattern, nTargetPattern ); g_engine->getSong()->set_modified( true ); createBackground(); update(); } CompositeApp::get_instance()->getSongEditorPanel()->updateAll(); event->acceptProposedAction(); } }
void SongEditor::drawSequence() { QPainter p; p.begin( m_pSequencePixmap ); p.drawPixmap( rect(), *m_pBackgroundPixmap, rect() ); p.end(); T<Song>::shared_ptr song = g_engine->getSong(); PatternList *patList = song->get_pattern_list(); T<Song::pattern_group_t>::shared_ptr pColumns = song->get_pattern_group_vector(); uint listLength = patList->get_size(); for (uint i = 0; i < pColumns->size(); i++) { T<PatternList>::shared_ptr pColumn = (*pColumns)[ i ]; for (uint nPat = 0; nPat < pColumn->get_size(); ++nPat) { T<Tritium::Pattern>::shared_ptr pat = pColumn->get( nPat ); int position = -1; // find the position in pattern list for (uint j = 0; j < listLength; j++) { T<Tritium::Pattern>::shared_ptr pat2 = patList->get( j ); if (pat == pat2) { position = j; break; } } if (position == -1) { DEBUGLOG( QString("[drawSequence] position == -1, group = %1").arg( i ) ); } drawPattern( i, position ); } } // Moving cells p.begin( m_pSequencePixmap ); // p.setRasterOp( Qt::XorROP ); // comix: this composition mode seems to be not available on Mac p.setCompositionMode( QPainter::CompositionMode_Xor ); QPen pen( Qt::gray ); pen.setStyle( Qt::DotLine ); p.setPen( pen ); for ( uint i = 0; i < m_movingCells.size(); i++ ) { int x = 10 + m_nGridWidth * ( m_movingCells[ i ] ).x(); int y = m_nGridHeight * ( m_movingCells[ i ] ).y(); QColor patternColor; patternColor.setRgb( 255, 255, 255 ); p.fillRect( x + 2, y + 4, m_nGridWidth - 3, m_nGridHeight - 7, patternColor ); } }
H2Core::Pattern* InstrumentLine::getCurrentPattern() { Hydrogen *pEngine = Hydrogen::get_instance(); PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); assert( pPatternList != NULL ); int nSelectedPatternNumber = pEngine->getSelectedPatternNumber(); if ( nSelectedPatternNumber != -1 ) { Pattern* pCurrentPattern = pPatternList->get( nSelectedPatternNumber ); return pCurrentPattern; } return NULL; }
void SongEditorPanel::revertaddEmptyPattern( int idx ) { Hydrogen *pEngine = Hydrogen::get_instance(); Song *pSong = pEngine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); H2Core::Pattern *pPattern = pPatternList->get( idx ); if( idx == pEngine->getSelectedPatternNumber() ) pEngine->setSelectedPatternNumber( idx -1 ); pPatternList->del( pPattern ); delete pPattern; pSong->set_is_modified( true ); updateAll(); }
void SongEditorPatternList::inlineEditPatternName( int row ) { Engine *engine = g_engine; T<Song>::shared_ptr song = engine->getSong(); PatternList *patternList = song->get_pattern_list(); if ( row >= (int)patternList->get_size() ) { return; } 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(); }
void SongEditorPatternList::patternPopup_properties() { Engine *engine = g_engine; T<Song>::shared_ptr song = engine->getSong(); PatternList *patternList = song->get_pattern_list(); int nSelectedPattern = engine->getSelectedPatternNumber(); T<Tritium::Pattern>::shared_ptr pattern = patternList->get( nSelectedPattern ); PatternPropertiesDialog *dialog = new PatternPropertiesDialog(this, pattern, false); if (dialog->exec() == QDialog::Accepted) { // Engine *engine = g_engine; // Song *song = engine->getSong(); song->set_modified( true ); g_engine->get_event_queue()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 ); createBackground(); update(); } delete dialog; dialog = NULL; }
void SMFWriter::save( const QString& sFilename, Song *pSong ) { INFOLOG( "save" ); const int DRUM_CHANNEL = 9; vector<SMFEvent*> eventList; SMF smf; // Standard MIDI format 1 files should have the first track being the tempo map // which is a track that contains global meta events only. SMFTrack *pTrack0 = new SMFTrack(); pTrack0->addEvent( new SMFCopyRightNoticeMetaEvent( pSong->__author , 0 ) ); pTrack0->addEvent( new SMFTrackNameMetaEvent( pSong->__name , 0 ) ); pTrack0->addEvent( new SMFSetTempoMetaEvent( pSong->__bpm , 0 ) ); pTrack0->addEvent( new SMFTimeSignatureMetaEvent( 4 , 4 , 24 , 8 , 0 ) ); smf.addTrack( pTrack0 ); // Standard MIDI Format 1 files should have note events in tracks =>2 SMFTrack *pTrack1 = new SMFTrack(); smf.addTrack( pTrack1 ); AutomationPath *vp = pSong->get_velocity_automation_path(); InstrumentList *iList = pSong->get_instrument_list(); // ogni pattern sara' una diversa traccia int nTick = 1; for ( unsigned nPatternList = 0 ; nPatternList < pSong->get_pattern_group_vector()->size() ; nPatternList++ ) { // infoLog( "[save] pattern list pos: " + toString( nPatternList ) ); PatternList *pPatternList = ( *(pSong->get_pattern_group_vector()) )[ nPatternList ]; int nStartTicks = nTick; int nMaxPatternLength = 0; for ( unsigned nPattern = 0 ; nPattern < pPatternList->size() ; nPattern++ ) { Pattern *pPattern = pPatternList->get( nPattern ); // infoLog( " |-> pattern: " + pPattern->getName() ); if ( ( int )pPattern->get_length() > nMaxPatternLength ) { nMaxPatternLength = pPattern->get_length(); } for ( unsigned nNote = 0; nNote < pPattern->get_length(); nNote++ ) { const Pattern::notes_t* notes = pPattern->get_notes(); FOREACH_NOTE_CST_IT_BOUND(notes,it,nNote) { Note *pNote = it->second; if ( pNote ) { float rnd = (float)rand()/(float)RAND_MAX; if ( pNote->get_probability() < rnd ) { continue; } float fPos = nPatternList + (float)nNote/(float)nMaxPatternLength; float velocity_adjustment = vp->get_value(fPos); int nVelocity = (int)( 127.0 * pNote->get_velocity() * velocity_adjustment ); int nInstr = iList->index(pNote->get_instrument()); Instrument *pInstr = pNote->get_instrument(); int nPitch = pNote->get_midi_key(); eventList.push_back( new SMFNoteOnEvent( nStartTicks + nNote, DRUM_CHANNEL, nPitch, nVelocity ) ); int nLength = 12; if ( pNote->get_length() != -1 ) { nLength = pNote->get_length(); } eventList.push_back( new SMFNoteOffEvent( nStartTicks + nNote + nLength, DRUM_CHANNEL, nPitch, nVelocity ) ); } } } } nTick += nMaxPatternLength; }
void BackProp::trainNetWork(PatternList patterns, int max_match, double threshold) { /*** Back propagation algorithm to train the network * @param counter, count how many iterations * @param success, count how many successful nodes * @param limit, the size of patterns * @return value, the success nodes number */ int limit = patterns.getsize(); int counter = 0; // int success = 0; bool flag = true; std::cout << "Total pattern number: " << limit << std::endl; while (flag) { std::cout << " . " << std::flush; // show the progress // success = 0; for (int i=0; i<limit; ++i) { Pattern pattern = patterns.get(i); // run the network int size = pattern.getinputsize(); double *ret = (double *)malloc(size * sizeof(double)); this->_network->runNetWork(pattern.getinput(), ret); // train the network size = pattern.getoutputsize(); double * rawret = (double *)malloc(size * sizeof(double)); double * rets = (double *)malloc(size * sizeof(double)); double * truth = (double *)malloc(size * sizeof(double)); this->_network->trainNetWork(pattern.getoutput(), size, rawret); // TODO: the first element is the threshold value, NEED to adjust in future. // thresholdTransfer(threshold, pattern.getoutput(), size, truth); // thresholdTransfer(threshold, rawret, size, rets); // pattern.setTrained(true); // for(int j=0; j<size; ++j) { // if (rets[j] != truth[j]) { // pattern.setTrained(false); // break; // } // } // // if pattern shown as expected, increase the successful node // if (pattern.isTrained()) // ++success; free (ret); free (rawret); free (rets); free (truth); } // // make sure all nodes are successful // if (success < limit) // flag = true; // else // flag = false; // // donot want the infinite loop, set the maximum iteration number if (counter > this->iteration) flag = false; ++counter; } std::cout << std::endl; // following is for test purpose // for (int i=0; i<limit; ++i) { // Pattern pattern = patterns.get(i); // int size = pattern.getinputsize(); // double *ret = (double *)malloc(sizeof(double)); // this->_network->runNetWork(pattern.getinput(), ret); // for (int j=0; j<size; ++j) std::cout << pattern.getinput()[j] << ", "; // std::cout << ret[0] << "\n"; // free (ret); // } // this->_network->printvalues(); // std::cout << "======\n"; // testing ends return; }
void Sampler::setPlayingNotelength( Instrument* instrument, unsigned long ticks, unsigned long noteOnTick ) { if ( instrument ) { // stop all notes using this instrument Hydrogen *pEngine = Hydrogen::get_instance(); Song* mSong = pEngine->getSong(); int selectedpattern = pEngine->__get_selected_PatterNumber(); Pattern* currentPattern = NULL; if ( mSong->get_mode() == Song::PATTERN_MODE || ( pEngine->getState() != STATE_PLAYING )){ PatternList *pPatternList = mSong->get_pattern_list(); if ( ( selectedpattern != -1 ) && ( selectedpattern < ( int )pPatternList->size() ) ) { currentPattern = pPatternList->get( selectedpattern ); } }else { std::vector<PatternList*> *pColumns = mSong->get_pattern_group_vector(); // Pattern *pPattern = NULL; int pos = pEngine->getPatternPos() +1; for ( int i = 0; i < pos; ++i ) { PatternList *pColumn = ( *pColumns )[i]; currentPattern = pColumn->get( 0 ); } } if ( currentPattern ) { int patternsize = currentPattern->get_length(); for ( unsigned nNote = 0; nNote < currentPattern->get_length(); nNote++ ) { const Pattern::notes_t* notes = currentPattern->get_notes(); FOREACH_NOTE_CST_IT_BOUND(notes,it,nNote) { Note *pNote = it->second; if ( pNote!=NULL ) { if( !Preferences::get_instance()->__playselectedinstrument ){ if ( pNote->get_instrument() == instrument && pNote->get_position() == noteOnTick ) { AudioEngine::get_instance()->lock( RIGHT_HERE ); if ( ticks > patternsize ) ticks = patternsize - noteOnTick; pNote->set_length( ticks ); Hydrogen::get_instance()->getSong()->__is_modified = true; AudioEngine::get_instance()->unlock(); // unlock the audio engine } }else { if ( pNote->get_instrument() == pEngine->getSong()->get_instrument_list()->get( pEngine->getSelectedInstrumentNumber()) && pNote->get_position() == noteOnTick ) { AudioEngine::get_instance()->lock( RIGHT_HERE ); if ( ticks > patternsize ) ticks = patternsize - noteOnTick; pNote->set_length( ticks ); Hydrogen::get_instance()->getSong()->__is_modified = true; AudioEngine::get_instance()->unlock(); // unlock the audio engine } } } } } } }
void* diskWriterDriver_thread( void* param ) { Object* __object = ( Object* )param; DiskWriterDriver *pDriver = ( DiskWriterDriver* )param; EventQueue::get_instance()->push_event( EVENT_PROGRESS, 0 ); pDriver->setBpm( Hydrogen::get_instance()->getSong()->__bpm ); pDriver->audioEngine_process_checkBPMChanged(); __INFOLOG( "DiskWriterDriver thread start" ); // always rolling, no user interaction pDriver->m_transport.m_status = TransportInfo::ROLLING; SF_INFO soundInfo; soundInfo.samplerate = pDriver->m_nSampleRate; // soundInfo.frames = -1;//getNFrames(); ///\todo: da terminare soundInfo.channels = 2; //default format int sfformat = 0x010000; //wav format (default) int bits = 0x0002; //16 bit PCM (default) //sf_format switch if( pDriver->m_sFilename.endsWith(".aiff") || pDriver->m_sFilename.endsWith(".AIFF") ){ sfformat = 0x020000; //Apple/SGI AIFF format (big endian) } if( pDriver->m_sFilename.endsWith(".flac") || pDriver->m_sFilename.endsWith(".FLAC") ){ sfformat = 0x170000; //FLAC lossless file format } if( ( pDriver->m_nSampleDepth == 8 ) && ( pDriver->m_sFilename.endsWith(".aiff") || pDriver->m_sFilename.endsWith(".AIFF") ) ){ bits = 0x0001; //Signed 8 bit data works with aiff } if( ( pDriver->m_nSampleDepth == 8 ) && ( pDriver->m_sFilename.endsWith(".wav") || pDriver->m_sFilename.endsWith(".WAV") ) ){ bits = 0x0005; //Unsigned 8 bit data needed for Microsoft WAV format } if( pDriver->m_nSampleDepth == 16 ){ bits = 0x0002; //Signed 16 bit data } if( pDriver->m_nSampleDepth == 24 ){ bits = 0x0003; //Signed 24 bit data } if( pDriver->m_nSampleDepth == 32 ){ bits = 0x0004; ////Signed 32 bit data } soundInfo.format = sfformat|bits; // #ifdef HAVE_OGGVORBIS //ogg vorbis option if( pDriver->m_sFilename.endsWith( ".ogg" ) | pDriver->m_sFilename.endsWith( ".OGG" ) ) soundInfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS; // #endif ///formats // SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian). */ // SF_FORMAT_AIFF = 0x020000, /* Apple/SGI AIFF format (big endian). */ // SF_FORMAT_AU = 0x030000, /* Sun/NeXT AU format (big endian). */ // SF_FORMAT_RAW = 0x040000, /* RAW PCM data. */ // SF_FORMAT_PAF = 0x050000, /* Ensoniq PARIS file format. */ // SF_FORMAT_SVX = 0x060000, /* Amiga IFF / SVX8 / SV16 format. */ // SF_FORMAT_NIST = 0x070000, /* Sphere NIST format. */ // SF_FORMAT_VOC = 0x080000, /* VOC files. */ // SF_FORMAT_IRCAM = 0x0A0000, /* Berkeley/IRCAM/CARL */ // SF_FORMAT_W64 = 0x0B0000, /* Sonic Foundry's 64 bit RIFF/WAV */ // SF_FORMAT_MAT4 = 0x0C0000, /* Matlab (tm) V4.2 / GNU Octave 2.0 */ // SF_FORMAT_MAT5 = 0x0D0000, /* Matlab (tm) V5.0 / GNU Octave 2.1 */ // SF_FORMAT_PVF = 0x0E0000, /* Portable Voice Format */ // SF_FORMAT_XI = 0x0F0000, /* Fasttracker 2 Extended Instrument */ // SF_FORMAT_HTK = 0x100000, /* HMM Tool Kit format */ // SF_FORMAT_SDS = 0x110000, /* Midi Sample Dump Standard */ // SF_FORMAT_AVR = 0x120000, /* Audio Visual Research */ // SF_FORMAT_WAVEX = 0x130000, /* MS WAVE with WAVEFORMATEX */ // SF_FORMAT_SD2 = 0x160000, /* Sound Designer 2 */ // SF_FORMAT_FLAC = 0x170000, /* FLAC lossless file format */ // SF_FORMAT_CAF = 0x180000, /* Core Audio File format */ // SF_FORMAT_OGG ///bits // SF_FORMAT_PCM_S8 = 0x0001, /* Signed 8 bit data */ // SF_FORMAT_PCM_16 = 0x0002, /* Signed 16 bit data */ // SF_FORMAT_PCM_24 = 0x0003, /* Signed 24 bit data */ // SF_FORMAT_PCM_32 = 0x0004, /* Signed 32 bit data */ ///used for ogg // SF_FORMAT_VORBIS if ( !sf_format_check( &soundInfo ) ) { __ERRORLOG( "Error in soundInfo" ); return 0; } SNDFILE* m_file = sf_open( pDriver->m_sFilename.toLocal8Bit(), SFM_WRITE, &soundInfo ); float *pData = new float[ pDriver->m_nBufferSize * 2 ]; // always stereo float *pData_L = pDriver->m_pOut_L; float *pData_R = pDriver->m_pOut_R; Hydrogen* engine = Hydrogen::get_instance(); std::vector<PatternList*> *pPatternColumns = Hydrogen::get_instance()->getSong()->get_pattern_group_vector(); int nColumns = pPatternColumns->size(); int nPatternSize; int validBpm = engine->getSong()->__bpm; float oldBPM = 0; float ticksize = 0; for ( int patternposition = 0; patternposition < nColumns; ++patternposition ) { PatternList *pColumn = ( *pPatternColumns )[ patternposition ]; if ( pColumn->size() != 0 ) { nPatternSize = pColumn->get( 0 )->get_length(); } else { nPatternSize = MAX_NOTES; } ticksize = pDriver->m_nSampleRate * 60.0 / engine->getSong()->__bpm / engine->getSong()->__resolution; // check pattern bpm if timeline bpm is in use Timeline* pTimeline = engine->getTimeline(); if(Preferences::get_instance()->getUseTimelineBpm() ){ if( pTimeline->m_timelinevector.size() >= 1 ){ for ( int t = 0; t < pTimeline->m_timelinevector.size(); t++){ if(pTimeline->m_timelinevector[t].m_htimelinebeat == patternposition && pTimeline->m_timelinevector[t].m_htimelinebpm != validBpm){ validBpm = pTimeline->m_timelinevector[t].m_htimelinebpm; } } } pDriver->setBpm(validBpm); ticksize = pDriver->m_nSampleRate * 60.0 / validBpm / Hydrogen::get_instance()->getSong()->__resolution; pDriver->audioEngine_process_checkBPMChanged(); engine->setPatternPos(patternposition); // delay needed time to calculate all rubberband samples if( Preferences::get_instance()->getRubberBandBatchMode() && validBpm != oldBPM ){ EventQueue::get_instance()->push_event( EVENT_RECALCULATERUBBERBAND, -1); int sleepTime = Preferences::get_instance()->getRubberBandCalcTime()+1; while ((sleepTime = sleep(sleepTime)) > 0); } oldBPM = validBpm; } else { ticksize = pDriver->m_nSampleRate * 60.0 / Hydrogen::get_instance()->getSong()->__bpm / Hydrogen::get_instance()->getSong()->__resolution; //pDriver->m_transport.m_nTickSize = ticksize; } //here we have the pattern length in frames dependent from bpm and samplerate unsigned patternLengthInFrames = ticksize * nPatternSize; unsigned frameNumber = 0; int lastRun = 0; while ( frameNumber < patternLengthInFrames ) { int usedBuffer = pDriver->m_nBufferSize; //this will calculate the the size from -last- (end of pattern) used frame buffer, //which is mostly smaller than pDriver->m_nBufferSize if( patternLengthInFrames - frameNumber < pDriver->m_nBufferSize ){ lastRun = patternLengthInFrames - frameNumber; usedBuffer = lastRun; }; frameNumber += usedBuffer; int ret = pDriver->m_processCallback( usedBuffer, NULL ); for ( unsigned i = 0; i < usedBuffer; i++ ) { if(pData_L[i] > 1){ pData[i * 2] = 1; } else if(pData_L[i] < -1){ pData[i * 2] = -1; }else { pData[i * 2] = pData_L[i]; } if(pData_R[i] > 1){ pData[i * 2 + 1] = 1; } else if(pData_R[i] < -1){ pData[i * 2 + 1] = -1; }else { pData[i * 2 + 1] = pData_R[i]; } } int res = sf_writef_float( m_file, pData, usedBuffer ); if ( res != ( int )usedBuffer ) { __ERRORLOG( "Error during sf_write_float" ); } } // this progress bar methode is not exact but ok enough to give users a usable visible progress feedback float fPercent = ( float )(patternposition +1) / ( float )nColumns * 100.0; EventQueue::get_instance()->push_event( EVENT_PROGRESS, ( int )fPercent ); } delete[] pData; pData = NULL; sf_close( m_file ); __INFOLOG( "DiskWriterDriver thread end" ); pthread_exit( NULL ); return NULL; }
void SongEditor::mouseReleaseEvent( QMouseEvent * /*ev*/ ) { Engine *pEngine = g_engine; PatternList *pPatternList = pEngine->getSong()->get_pattern_list(); T<Song::pattern_group_t>::shared_ptr pColumns = pEngine->getSong()->get_pattern_group_vector(); if ( m_bIsMoving ) { // fine dello spostamento dei pattern g_engine->lock( RIGHT_HERE ); // create the new patterns for ( uint i = 0; i < m_movingCells.size(); i++ ) { QPoint cell = m_movingCells[ i ]; if ( cell.x() < 0 || cell.y() < 0 || cell.y() >= (int)pPatternList->get_size() ) { // skip continue; } // aggiungo un pattern per volta T<PatternList>::shared_ptr pColumn; if ( cell.x() < (int)pColumns->size() ) { pColumn = (*pColumns)[ cell.x() ]; } else { // creo dei patternlist vuoti int nSpaces = cell.x() - pColumns->size(); for ( int i = 0; i <= nSpaces; i++ ) { pColumn.reset( new PatternList() ); pColumns->push_back( pColumn ); } } pColumn->add( pPatternList->get( cell.y() ) ); } if ( m_bIsCtrlPressed ) { // COPY } else { // MOVE // remove the old patterns for ( uint i = 0; i < m_selectedCells.size(); i++ ) { QPoint cell = m_selectedCells[ i ]; T<PatternList>::shared_ptr pColumn; if ( cell.x() < (int)pColumns->size() ) { pColumn = (*pColumns)[ cell.x() ]; } else { pColumn.reset( new PatternList() ); pColumns->push_back( pColumn ); } pColumn->del(pPatternList->get( cell.y() ) ); } } // remove the empty patternlist at the end of the song for ( int i = pColumns->size() - 1; i != 0 ; i-- ) { T<PatternList>::shared_ptr pList = (*pColumns)[ i ]; int nSize = pList->get_size(); if ( nSize == 0 ) { pColumns->erase( pColumns->begin() + i ); pList.reset(); } else { break; } } pEngine->getSong()->set_modified( true ); g_engine->unlock(); m_bIsMoving = false; m_movingCells.clear(); m_selectedCells.clear(); } setCursor( QCursor( Qt::ArrowCursor ) ); m_bShowLasso = false; m_bSequenceChanged = true; m_bIsCtrlPressed = false; update(); }
void SongEditor::mouseMoveEvent(QMouseEvent *ev) { int nRow = ev->y() / m_nGridHeight; int nColumn = ( (int)ev->x() - 10 ) / (int)m_nGridWidth; PatternList *pPatternList = g_engine->getSong()->get_pattern_list(); T<Song::pattern_group_t>::shared_ptr pColumns = g_engine->getSong()->get_pattern_group_vector(); if ( m_bIsMoving ) { // WARNINGLOG( "[mouseMoveEvent] Move patterns not implemented yet" ); int nRowDiff = nRow - m_clickPoint.y(); int nColumnDiff = nColumn - m_clickPoint.x(); // DEBUGLOG( "[mouseMoveEvent] row diff: "+ to_string( nRowDiff ) ); // DEBUGLOG( "[mouseMoveEvent] col diff: "+ to_string( nColumnDiff ) ); for ( int i = 0; i < (int)m_movingCells.size(); i++ ) { QPoint cell = m_movingCells[ i ]; m_movingCells[ i ].setX( m_selectedCells[ i ].x() + nColumnDiff ); m_movingCells[ i ].setY( m_selectedCells[ i ].y() + nRowDiff ); } m_bSequenceChanged = true; update(); return; } if ( m_bShowLasso ) { // SELECTION setCursor( QCursor( Qt::CrossCursor ) ); int x = ev->x(); int y = ev->y(); if ( x < 0 ) { x = 0; } if ( y < 0 ) { y = 0; } m_lasso.setBottomRight( QPoint( x, y ) ); // aggiorno la lista di celle selezionate m_selectedCells.clear(); int nStartColumn = (int)( ( m_lasso.left() - 10.0 ) / m_nGridWidth ); int nEndColumn = nColumn; if ( nStartColumn > nEndColumn ) { int nTemp = nEndColumn; nEndColumn = nStartColumn; nStartColumn = nTemp; } int nStartRow = m_lasso.top() / m_nGridHeight; int nEndRow = nRow; if ( nStartRow > nEndRow ) { int nTemp = nEndRow; nEndRow = nStartRow; nStartRow = nTemp; } for ( int nRow = nStartRow; nRow <= nEndRow; nRow++ ) { for ( int nCol = nStartColumn; nCol <= nEndColumn; nCol++ ) { if ( nRow >= (int)pPatternList->get_size() || nRow < 0 || nCol < 0 ) { return; } T<Tritium::Pattern>::shared_ptr pPattern = pPatternList->get( nRow ); if ( nCol < (int)pColumns->size() ) { T<PatternList>::shared_ptr pColumn = ( *pColumns )[ nCol ]; for ( uint i = 0; i < pColumn->get_size(); i++) { if ( pColumn->get(i) == pPattern ) { // esiste un pattern in questa posizione m_selectedCells.push_back( QPoint( nCol, nRow ) ); } } } } } m_bSequenceChanged = true; update(); } }
void SongEditor::mousePressEvent( QMouseEvent *ev ) { if ( ev->x() < 10 ) { return; } int nRow = ev->y() / m_nGridHeight; int nColumn = ( (int)ev->x() - 10 ) / (int)m_nGridWidth; if ( ev->modifiers() == Qt::ControlModifier ) { DEBUGLOG( "[mousePressEvent] CTRL pressed!" ); m_bIsCtrlPressed = true; } else { m_bIsCtrlPressed = false; } Engine *pEngine = g_engine; T<Song>::shared_ptr pSong = pEngine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); // don't lock the audio driver before checking that... if ( nRow >= (int)pPatternList->get_size() || nRow < 0 || nColumn < 0 ) { return; } g_engine->lock( RIGHT_HERE ); SongEditorActionMode actionMode = CompositeApp::get_instance()->getSongEditorPanel()->getActionMode(); if ( actionMode == SELECT_ACTION ) { bool bOverExistingPattern = false; for ( uint i = 0; i < m_selectedCells.size(); i++ ) { QPoint cell = m_selectedCells[ i ]; if ( cell.x() == nColumn && cell.y() == nRow ) { bOverExistingPattern = true; break; } } if ( bOverExistingPattern ) { // MOVE PATTERNS // DEBUGLOG( "[mousePressEvent] Move patterns" ); m_bIsMoving = true; m_bShowLasso = false; m_movingCells = m_selectedCells; m_clickPoint.setX( nColumn ); m_clickPoint.setY( nRow ); } else { // DEBUGLOG( "[mousePressEvent] Select patterns" ); // select patterns m_bShowLasso = true; m_lasso.setCoords( ev->x(), ev->y(), ev->x(), ev->y() ); setCursor( QCursor( Qt::CrossCursor ) ); m_selectedCells.clear(); m_selectedCells.push_back( QPoint( nColumn, nRow ) ); } } else if ( actionMode == DRAW_ACTION ) { T<Tritium::Pattern>::shared_ptr pPattern = pPatternList->get( nRow ); T<Song::pattern_group_t>::shared_ptr pColumns = pSong->get_pattern_group_vector(); // E' la lista di "colonne" di pattern if ( nColumn < (int)pColumns->size() ) { T<PatternList>::shared_ptr pColumn = ( *pColumns )[ nColumn ]; bool bFound = false; unsigned nColumnIndex = 0; for ( nColumnIndex = 0; nColumnIndex < pColumn->get_size(); nColumnIndex++) { if ( pColumn->get( nColumnIndex ) == pPattern ) { // il pattern e' gia presente bFound = true; break; } } if ( bFound ) { // DELETE PATTERN // DEBUGLOG( "[mousePressEvent] delete pattern" ); pColumn->del( nColumnIndex ); // elimino le colonne vuote for ( int i = pColumns->size() - 1; i >= 0; i-- ) { T<PatternList>::shared_ptr pColumn = ( *pColumns )[ i ]; if ( pColumn->get_size() == 0 ) { pColumns->erase( pColumns->begin() + i ); pColumn.reset(); } else { break; } } } else { if ( nColumn < (int)pColumns->size() ) { // ADD PATTERN // DEBUGLOG( "[mousePressEvent] add pattern" ); m_selectedCells.clear(); pColumn->add( pPattern ); } } } else { // ADD PATTERN (with spaces..) m_selectedCells.clear(); int nSpaces = nColumn - pColumns->size(); // DEBUGLOG( "[mousePressEvent] add pattern (with " + to_string( nSpaces ) + " spaces)" ); T<PatternList>::shared_ptr pColumn( new PatternList() ); pColumns->push_back( pColumn ); for ( int i = 0; i < nSpaces; i++ ) { pColumn.reset( new PatternList() ); pColumns->push_back( pColumn ); } pColumn->add( pPattern ); } pSong->set_modified( true ); } g_engine->unlock(); // update m_bSequenceChanged = true; update(); }
void SongEditorPatternList::fillRangeWithPattern(FillRange* pRange, int nPattern) { Engine *pEngine = g_engine; g_engine->lock( RIGHT_HERE ); T<Song>::shared_ptr pSong = pEngine->getSong(); PatternList *pPatternList = pSong->get_pattern_list(); T<Tritium::Pattern>::shared_ptr pPattern = pPatternList->get( nPattern ); T<Song::pattern_group_t>::shared_ptr pColumns = pSong->get_pattern_group_vector(); // E' la lista di "colonne" di pattern T<PatternList>::shared_ptr pColumn; int nColumn, nColumnIndex; bool bHasPattern = false; int fromVal = pRange->fromVal - 1; int toVal = pRange->toVal; // Add patternlists to PatternGroupVector as necessary int nDelta = toVal - pColumns->size() + 1; for ( int i = 0; i < nDelta; i++ ) { pColumn.reset( new PatternList() ); pColumns->push_back( pColumn ); } // Fill or Clear each cell in range for ( nColumn = fromVal; nColumn < toVal; nColumn++ ) { // expand Pattern pColumn = ( *pColumns )[ nColumn ]; bHasPattern = false; // check whether the pattern (and column) already exists for ( nColumnIndex = 0; pColumn && nColumnIndex < (int)pColumn->get_size(); nColumnIndex++) { if ( pColumn->get( nColumnIndex ) == pPattern ) { bHasPattern = true; break; } } if ( pRange->bInsert && !bHasPattern ) { //fill pColumn->add( pPattern); } else if ( !pRange->bInsert && bHasPattern ) { // clear pColumn->del( pPattern); } } // remove all the empty patternlists at the end of the song for ( int i = pColumns->size() - 1; i != 0 ; i-- ) { T<PatternList>::shared_ptr pList = (*pColumns)[ i ]; int nSize = pList->get_size(); if ( nSize == 0 ) { pColumns->erase( pColumns->begin() + i ); pList.reset(); } else { break; } } g_engine->unlock(); // Update pSong->set_modified( true ); }
void SongEditorPatternList::patternPopup_delete() { Engine *pEngine = g_engine; // int state = engine->get_transport()->get_state(); // // per ora non lascio possibile la cancellazione del pattern durante l'esecuzione // // da togliere quando correggo il bug // if (state == PLAYING) { // QMessageBox::information( this, "Composite", trUtf8("Can't delete the pattern while the audio engine is playing")); // return; // } if ( pEngine->getSong()->get_mode() == Song::PATTERN_MODE ) { pEngine->sequencer_setNextPattern( -1, false, false ); // reimposto il prossimo pattern a NULL, altrimenti viene scelto quello che sto distruggendo ora... } // pEngine->sequencer_stop(); // "lock engine" I am not sure, but think this is unnecessarily. -wolke- // g_engine->lock( RIGHT_HERE ); T<Song>::shared_ptr song = pEngine->getSong(); PatternList *pSongPatternList = song->get_pattern_list(); T<Pattern>::shared_ptr pattern = pSongPatternList->get( pEngine->getSelectedPatternNumber() ); DEBUGLOG( QString("[patternPopup_delete] Delete pattern: %1 @%2").arg(pattern->get_name()).arg( (long)pattern.get() ) ); pSongPatternList->del(pattern); T<Song::pattern_group_t>::shared_ptr patternGroupVect = song->get_pattern_group_vector(); uint i = 0; while (i < patternGroupVect->size() ) { T<PatternList>::shared_ptr list = (*patternGroupVect)[i]; uint j = 0; while ( j < list->get_size() ) { T<Tritium::Pattern>::shared_ptr pOldPattern = list->get( j ); if (pOldPattern == pattern ) { list->del( j ); continue; } j++; } // for (uint j = 0; j < list->get_size(); j++) { // Pattern *pOldPattern = list->get( j ); // if (pOldPattern == pattern ) { // list->del( j ); // } // } /* if (list->get_size() == 0 ) { patternGroupVect->erase( patternGroupVect->begin() + i ); delete list; list = NULL; } else { */ i++; // } } T<PatternList>::shared_ptr list = pEngine->getCurrentPatternList(); list->del( pattern ); // se esiste, seleziono il primo pattern if ( pSongPatternList->get_size() > 0 ) { T<Tritium::Pattern>::shared_ptr pFirstPattern = pSongPatternList->get( 0 ); list->add( pFirstPattern ); // Cambio due volte...cosi' il pattern editor viene costretto ad aggiornarsi pEngine->setSelectedPatternNumber( -1 ); pEngine->setSelectedPatternNumber( 0 ); } else { // there's no patterns.. T<Pattern>::shared_ptr emptyPattern = Pattern::get_empty_pattern(); emptyPattern->set_name( trUtf8("Pattern 1") ); emptyPattern->set_category( trUtf8("not_categorized") ); pSongPatternList->add( emptyPattern ); pEngine->setSelectedPatternNumber( -1 ); pEngine->setSelectedPatternNumber( 0 ); } pattern.reset(); song->set_modified( true ); // "unlock" I am not sure, but think this is unnecessarily. -wolke- // g_engine->unlock(); ( CompositeApp::get_instance() )->getSongEditorPanel()->updateAll(); }