示例#1
0
文件: Parser.cpp 项目: looncraz/haiku
DisjList*
Parser::ParsePatternList(Range range) {
	PatternList *list = new(std::nothrow) PatternList(range);
	if (!list)
		ThrowOutOfMemError(stream.Pos());
	try {		
		// LeftParen
		stream.Read(LeftParen);
		// [Flag] Pattern, (Divider, [Flag] Pattern)*
		while (true) {
			// [Flag]
			if (stream.CondRead(CaseInsensitiveFlag))
				list->SetCaseInsensitive(true);		
			// Pattern
			list->Add(ParsePattern());
			// [Divider]
			if (!stream.CondRead(Divider))
				break;
		} 
		// RightParen
		const Token *t = stream.Get();
		if (t->Type() != RightParen)
			throw new Err("Sniffer pattern error: expecting '|', ')', or possibly '&'", t->Pos());
	} catch (...) {
		delete list;
		throw;
	}
	return list;
}
示例#2
0
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
}
示例#3
0
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();
}
示例#4
0
void SongEditorPanel::addEmptyPattern( QString newPatternName ,QString newPatternInfo, QString newPatternCategory, int idx )
{
	Hydrogen	*pEngine = Hydrogen::get_instance();
	Song		*pSong = pEngine->getSong();
	PatternList *pPatternList = pSong->get_pattern_list();
	
	pPatternList->insert( idx, new Pattern( newPatternName, newPatternInfo, newPatternCategory ) );
	pSong->set_is_modified( true );
	updateAll();
}
示例#5
0
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 );
	}

}
示例#6
0
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();
}
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;
}
示例#8
0
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();
		
}
示例#9
0
void SongEditorPanel::restoreGroupVector( QString filename )
{
	//clear the old sequese
	vector<PatternList*> *pPatternGroupsVect = Hydrogen::get_instance()->getSong()->get_pattern_group_vector();
	for (uint i = 0; i < pPatternGroupsVect->size(); i++) {
		PatternList *pPatternList = (*pPatternGroupsVect)[i];
		pPatternList->clear();
		delete pPatternList;
	}
	pPatternGroupsVect->clear();

	Hydrogen::get_instance()->getSong()->readTempPatternList( filename );
	m_pSongEditor->updateEditorandSetTrue();
	updateAll();
}
示例#10
0
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();
}
示例#11
0
///
/// Create a new pattern
///
void SongEditorPanel::newPatBtnClicked( Button* btn )
{
	UNUSED( btn );
	Hydrogen	*pEngine = Hydrogen::get_instance();
	Song		*pSong = pEngine->getSong();
	PatternList *pPatternList = pSong->get_pattern_list();
	Pattern		*pNewPattern = new Pattern( trUtf8("Pattern %1").arg(pPatternList->size()+1));
	PatternPropertiesDialog *pDialog = new PatternPropertiesDialog( this, pNewPattern, 0, true );

	if ( pDialog->exec() == QDialog::Accepted ) {
		SE_addEmptyPatternAction*action =
				new SE_addEmptyPatternAction( pNewPattern->get_name() , pNewPattern->get_info(), pNewPattern->get_category(), pEngine->getSelectedPatternNumber()+1);
		HydrogenApp::get_instance()->m_undoStack->push( action );
	}

	delete pNewPattern;
	delete pDialog;
}
示例#12
0
void MainForm::action_file_openPattern()
{

	Hydrogen *engine = Hydrogen::get_instance();
	Song *song = engine->getSong();
	PatternList *pPatternList = song->get_pattern_list();

	Instrument *instr = song->get_instrument_list()->get ( 0 );
	assert ( instr );

	QDir dirPattern( Preferences::get_instance()->getDataDirectory() + "/patterns" );
	QFileDialog fd(this);
	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();
	}
	QString patternname = filename;


	LocalFileMng mng;
	LocalFileMng fileMng;
	Pattern* err = fileMng.loadPattern ( patternname );
	if ( err == 0 )
	{
		_ERRORLOG( "Error loading the pattern" );
		_ERRORLOG( patternname );
	}
	else
	{
		H2Core::Pattern *pNewPattern = err;
		pPatternList->add ( pNewPattern );
		song->__is_modified = true;
	}

	HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
}
示例#13
0
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();

}
示例#14
0
void SoundLibraryPanel::on_patternLoadAction()
{
	LocalFileMng mng;

	QString patternName = __sound_library_tree->currentItem()->text( 0 ) + ".h2pattern";
	QString drumkitname = __sound_library_tree->currentItem()->toolTip ( 0 );
	Hydrogen *engine = Hydrogen::get_instance();
	Song *song = engine->getSong();
	PatternList *pPatternList = song->get_pattern_list();
	
	QString sDirectory;

	std::vector<QString> patternDirList = mng.getPatternDirList();

	for (uint i = 0; i < patternDirList.size(); ++i) {
		QString absPath =  patternDirList[i];
		mng.getPatternList( absPath );
	}

	std::vector<QString> allPatternDirList = mng.getallPatternList();

	for (uint i = 0; i < allPatternDirList.size(); ++i) {
		QString testName = allPatternDirList[i];
		if( testName.contains( patternName ) && testName.contains( drumkitname )){
			sDirectory = allPatternDirList[i];		
		} 
	}

	Pattern* err = mng.loadPattern (sDirectory );

	if ( err == 0 ) {
		ERRORLOG( "Error loading the pattern" );
	}
	else {
		H2Core::Pattern *pNewPattern = err;
		pPatternList->add ( pNewPattern );
		song->__is_modified = true;
	}

	HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
}
示例#15
0
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;
}
示例#16
0
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();
}
示例#17
0
/// Single click, select the next pattern
void SongEditorPatternList::mousePressEvent( QMouseEvent *ev )
{
	int row = (ev->y() / m_nGridHeight);

	Engine *engine = g_engine;
	T<Song>::shared_ptr song = engine->getSong();
	PatternList *patternList = song->get_pattern_list();

	if ( row >= (int)patternList->get_size() ) {
		return;
	}

	if ( (ev->button() == Qt::MidButton) || (ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::RightButton) || (ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::LeftButton) ){
		togglePattern( row );
	} else {
		engine->setSelectedPatternNumber( row );
		if (ev->button() == Qt::RightButton)  {
	/*
			if ( song->getMode() == Song::PATTERN_MODE ) {
	
				PatternList *pCurrentPatternList = engine->getCurrentPatternList();
				if ( pCurrentPatternList->get_size() == 0 ) {
					// nessun pattern e' attivo. seleziono subito questo.
					pCurrentPatternList->add( patternList->get( row ) );
				}
				else {
					engine->setNextPattern( row );
				}
			}
	*/
			m_pPatternPopup->popup( QPoint( ev->globalX(), ev->globalY() ) );
		}
	}

	createBackground();
	update();
}
示例#18
0
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();
		
	}
}
示例#19
0
void MainForm::functionDeleteInstrument(int instrument)
{
	Hydrogen * H = Hydrogen::get_instance();
	Instrument *pSelectedInstrument = H->getSong()->get_instrument_list()->get( instrument );

	std::list< Note* > noteList;
	Song* song = H->getSong();
	PatternList *patList = song->get_pattern_list();

	QString instrumentName =  pSelectedInstrument->get_name();
	QString drumkitName = H->getCurrentDrumkitname();

	for ( int i = 0; i < patList->size(); i++ ) {
		H2Core::Pattern *pPattern = song->get_pattern_list()->get(i);
		const Pattern::notes_t* notes = pPattern->get_notes();
		FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) {
			Note *pNote = it->second;
			assert( pNote );
			if ( pNote->get_instrument() == pSelectedInstrument ) {
				pNote->set_pattern_idx( i );
				noteList.push_back( pNote );
			}
		}
	}
示例#20
0
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 );
}
示例#21
0
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;
	}
示例#22
0
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
								}
							}
						}
					}
				}
			}
		}
示例#23
0
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;
}
示例#24
0
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();
}
示例#25
0
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();
	}

}
示例#26
0
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();
}
示例#27
0
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();
}
示例#28
0
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;
}