Beispiel #1
0
// Unlink (clone) local hash data.
void qtractorMidiClip::unlinkHashData (void)
{
	if (m_pData == NULL)
		return;
	if (m_pData->count() < 2)
		return;

	m_pData->detach(this);

	Data *pNewData = new Data();

	qtractorMidiSequence *pOldSeq = m_pData->sequence();
	qtractorMidiSequence *pNewSeq = pNewData->sequence();

	pNewSeq->setName(pOldSeq->name());
	pNewSeq->setChannel(pOldSeq->channel());
	pNewSeq->setBank(pOldSeq->bank());
	pNewSeq->setProg(pOldSeq->prog());
	pNewSeq->setTicksPerBeat(pOldSeq->ticksPerBeat());
	pNewSeq->setTimeOffset(pOldSeq->timeOffset());
	pNewSeq->setTimeLength(pOldSeq->timeLength());
	pNewSeq->setDuration(pOldSeq->duration());
	pNewSeq->setNoteMin(pOldSeq->noteMin());
	pNewSeq->setNoteMax(pOldSeq->noteMax());
	pNewSeq->copyEvents(pOldSeq);

	m_pData = pNewData;
	m_pData->attach(this);

	updateHashKey();
	insertHashKey();
}
Beispiel #2
0
void Position::move(const Move m) {
	// std::cerr << "Position::move(" << m.toString() << ");" << std::endl;

	// move_history.emplace_back(m);

	updateHashKey		(m, m.from());				// needs to know square where moving tower is, i.e., pre or post move
	value -= moveValue	(m, m.from());				// "

	bitb.move(m.from(), m.to(), turn);
	std::swap(tower[m.to()], tower[m.from()]);			// swap towers

	assert (bitb.isOfficer(m.to(), turn) == tower[m.to()].isOfficer());
	if (m.isOnPromotionSquare() && !tower[m.to()].isOfficer()) {	// move promotes
		tower[m.to()].promote();
		bitb.bits[turn+2] |= (1<<m.to());
	}

	if (m.isJump()) {
		unsigned int other = !turn;
		for (unsigned int j = 0; j<m.size(); j++) {		// captures
			unsigned int over = m.over(j);
			const bool iso = tower[over].isOfficer();
			tower[m.to()].push_back(tower[over].pop());	// add captured stone to turns tower
			if      ( iso && !tower[over].isOfficer()) bitb.degrade (over, other);
			else if (!iso &&  tower[over].isOfficer()) bitb.promote (over, other);
			// bitb.setGrade(over, other, tower[over].isOfficer());
			if (tower[over].empty()) {			// last stone of tower captured
				bitb.erase(over, other);
			} else if (tower[over].color() == turn) {	// color switch
				bitb.switchColor(over, turn);
			}						// if color remains same after hit, nothing to do.
		}
	}

	checkTowerKeys		(m);					// beside constructor only place where hash keys for a tower may not exist
	updateHashKey		(m, m.to());				// needs to know square where moving tower is, i.e., pre or post move
	value += moveValue	(m, m.to());				// "

	pos_stack.emplace(pos_key);
	assert(pos_key == generateKey());
	assert(value == evaluateTowers());

	switchTurn();
}
Beispiel #3
0
void Position::undo(const Move m) {
	// std::cerr << "Position::undo(" << m.toString() << ");" << std::endl;

	// move_history.pop_back();
	switchTurn();

	value -= moveValue	(m, m.to());
	updateHashKey		(m, m.to());

	bitb.move(m.to(), m.from(), turn);
	std::swap(tower[m.to()], tower[m.from()]);

	if (m.isPromotion()) {
		tower[m.from()].degrade();
		bitb.bits[turn+2] &= ~(1<<m.from());
	}	

	if (m.isJump()) {
		unsigned int other = !turn;
		for (unsigned int j = m.size(); j; j--) {	// cause unsigned
			unsigned int over = m.over(j-1);	// substract here
			if (tower[over].empty()) {			// last stone of tower was captured
				bitb.set(over, tower[m.from()].back());
			} else if (tower[over].color() == turn) {	// color change
				bitb.switchColor(over, other);
			}
			const bool iso = tower[over].isOfficer();
			tower[over].push(tower[m.from()].pop_back());	// restore stone on top of tower
			if      ( iso && !tower[over].isOfficer()) bitb.degrade (over, other);
			else if (!iso &&  tower[over].isOfficer()) bitb.promote (over, other);
		}
	}

	updateHashKey		(m, m.from());
	value += moveValue	(m, m.from());

	pos_stack.pop();
	assert(pos_key == generateKey());
	assert(value == evaluateTowers());
}
Beispiel #4
0
// Relink local hash data.
void qtractorMidiClip::relinkHashData (void)
{
	if (m_pData == NULL)
		return;
	if (m_pData->count() > 1)
		return;

	removeHashKey();
	updateHashKey();

	Data *pNewData = g_hashTable.value(*m_pKey, NULL);
	if (pNewData == NULL) {
		delete m_pKey;
		m_pKey = NULL;
	} else {
		m_pData->detach(this);
		delete m_pData;
		m_pData = pNewData;
		m_pData->attach(this);
	}

	insertHashKey();
}
Beispiel #5
0
// The main use method.
bool qtractorMidiClip::openMidiFile (
	const QString& sFilename, int iTrackChannel, int iMode )
{
	closeMidiFile();

	qtractorTrack *pTrack = track();
	if (pTrack == NULL)
		return false;

	qtractorSession *pSession = pTrack->session();
	if (pSession == NULL)
		return false;

#ifdef CONFIG_DEBUG_0
	qDebug("qtractorMidiClip[%p]::openMidiFile(\"%s\", %d, %d)", this,
		sFilename.toUtf8().constData(), iTrackChannel, iMode);
#endif

	// Check file primordial state...
	const bool bWrite = (iMode & qtractorMidiFile::Write);

	// Set local properties...
	setFilename(sFilename);
	setDirty(false);

	// Register file path...
	pSession->files()->addClipItem(qtractorFileList::Midi, this, bWrite);

	// New key-data sequence...
	if (!bWrite) {
		m_pKey  = new Key(this);
		m_pData = g_hashTable.value(*m_pKey, NULL);
		if (m_pData) {
			m_pData->attach(this);
			qtractorMidiSequence *pSeq = m_pData->sequence();
			// Clip name should be clear about it all.
			if (clipName().isEmpty())
				setClipName(pSeq->name());
			if (clipName().isEmpty())
				setClipName(shortClipName(QFileInfo(filename()).baseName()));
			// Uh oh...
			m_playCursor.reset(pSeq);
			m_drawCursor.reset(pSeq);
			return true;
		}
	}

	// Create and open up the real MIDI file...
	m_pFile = new qtractorMidiFile();
	if (!m_pFile->open(sFilename, iMode)) {
		delete m_pFile;
		m_pFile = NULL;
		return false;
	}

	// Initialize MIDI event container...
	m_pData = new Data();
	m_pData->attach(this);

	qtractorMidiSequence *pSeq = m_pData->sequence();

	pSeq->clear();
	pSeq->setTicksPerBeat(pSession->ticksPerBeat());

	const unsigned long iClipStart  = clipStart();
	const unsigned long iClipOffset = clipOffset();
	qtractorTimeScale::Cursor cursor(pSession->timeScale());
	qtractorTimeScale::Node *pNode = cursor.seekFrame(iClipStart);
	const unsigned long t0 = pNode->tickFromFrame(iClipStart);

	const unsigned long iClipOffset2 = iClipStart + iClipOffset;
//	pNode = cursor.seekFrame(iClipOffset2);
	pSeq->setTimeOffset(pNode->tickFromFrame(iClipOffset2) - t0);

	const unsigned long iClipLength = clipLength();
	const unsigned long iClipEnd = iClipStart + iClipLength;
	pNode = cursor.seekFrame(iClipEnd);
	pSeq->setTimeLength(pNode->tickFromFrame(iClipEnd) - t0);

	// Initial statistics...
	pSeq->setNoteMin(m_noteMin);
	pSeq->setNoteMax(m_noteMax);

	// Are we on a pre-writing status?
	if (bWrite) {
		// On write mode, iTrackChannel holds the SMF format,
		// so we'll convert it here as properly.
		const unsigned short iFormat
			= qtractorMidiClip::defaultFormat();
		unsigned short iTracks = 1;
		if (iFormat == 1) {
			// SMF format 1 (2 tracks, 1 channel)
			iTrackChannel = 1;
			++iTracks;
		}
		// That's it.
		setFormat(iFormat);
		// Write SMF header...
		if (m_pFile->writeHeader(iFormat, iTracks, pSeq->ticksPerBeat())) {
			// Set initial local properties...
			if (m_pFile->tempoMap()) {
				m_pFile->tempoMap()->fromTimeScale(
					pSession->timeScale(), pSeq->timeOffset());
			}
		}
		// And initial clip name...
		pSeq->setName(shortClipName(QFileInfo(m_pFile->filename()).baseName()));
		pSeq->setChannel(pTrack->midiChannel());
		// Nothing more as for writing...
	} else {
		// On read mode, SMF format is properly given by open file.
		setFormat(m_pFile->format());
		// Read the event sequence in...
		m_pFile->readTrack(pSeq, iTrackChannel);
		// For immediate feedback, once...
		m_noteMin = pSeq->noteMin();
		m_noteMax = pSeq->noteMax();
		// FIXME: On demand, set session time properties from MIDI file...
		if (m_bSessionFlag) {
		#if 0
			// Import eventual SysEx setup...
			// - take care that given track might not be currently open,
			//   so that we'll resolve MIDI output bus somehow...
			qtractorMidiBus *pMidiBus = NULL;
			qtractorMidiEngine *pMidiEngine = pSession->midiEngine();
			if (pMidiEngine) {
				pMidiBus = static_cast<qtractorMidiBus *> (
					pMidiEngine->findOutputBus(pTrack->outputBusName()));
				if (pMidiBus == NULL) {
					for (qtractorBus *pBus = pMidiEngine->buses().first();
							pBus; pBus = pBus->next()) {
						if (pBus->busMode() & qtractorBus::Output) {
							pMidiBus = static_cast<qtractorMidiBus *> (pBus);
							break;
						}
					}
				}
			}
			// Import eventual SysEx setup...
			if (pMidiBus)
				pMidiBus->importSysexList(pSeq);
		#endif
			// Import tempo map as well...
			qtractorMidiFileTempo *pTempoMap = m_pFile->tempoMap();
			if (pTempoMap) {
				pTempoMap->intoTimeScale(pSession->timeScale(), t0);
				pSession->updateTimeScale();
			}
			// Reset session flag now.
			m_bSessionFlag = false;
		}
		// We should have events, otherwise this clip is of no use...
		//if (m_pSeq->events().count() < 1)
		//	return false;
	}

	// Actual track-channel is set by now...
	setTrackChannel(iTrackChannel);

	// Make it a brand new revision...
	// setRevision(1);

	// Default clip length will be whole sequence duration.
	if (iClipLength == 0) {
		const unsigned long t1 = t0 + pSeq->timeLength();
		setClipLength(pSession->frameFromTick(t1) - iClipStart);
	}

	// Clip name should be clear about it all.
	if (clipName().isEmpty())
		setClipName(pSeq->name());
	if (clipName().isEmpty())
		setClipName(shortClipName(QFileInfo(filename()).baseName()));

	// Uh oh...
	m_playCursor.reset(pSeq);
	m_drawCursor.reset(pSeq);

	// Something might have changed...
	updateHashKey();
	insertHashKey();

	// Update/reset MIDI clip editor if any...
	if (m_pMidiEditorForm)
		m_pMidiEditorForm->setup(this);

	return true;
}