// MIDI clip export method.
bool qtractorMidiClip::clipExport (
	ClipExport pfnClipExport, void *pvArg,
	unsigned long iOffset, unsigned long iLength ) const
{
	qtractorTrack *pTrack = track();
	if (pTrack == NULL)
		return false;

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

	qtractorMidiSequence *pSeq = sequence();
	if (pSeq == NULL)
		return false;

	if (iLength < 1)
		iLength = clipLength();

	const unsigned short iTicksPerBeat = pSession->ticksPerBeat();
	const unsigned long iTimeOffset = pSeq->timeOffset();

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

	unsigned long f1 = clipStart() + clipOffset() + iOffset;
	pNode = cursor.seekFrame(f1);
	const unsigned long t1 = pNode->tickFromFrame(f1);
	unsigned long iTimeStart = t1 - t0;
	iTimeStart = (iTimeStart > iTimeOffset ? iTimeStart - iTimeOffset : 0);
	pNode = cursor.seekFrame(f1 += iLength);
	const unsigned long iTimeEnd = iTimeStart + pNode->tickFromFrame(f1) - t1;

	qtractorMidiSequence seq(pSeq->name(), pSeq->channel(), iTicksPerBeat);

	seq.setBank(pTrack->midiBank());
	seq.setProg(pTrack->midiProg());

	for (qtractorMidiEvent *pEvent = pSeq->events().first();
			pEvent; pEvent = pEvent->next()) {
		const unsigned long iTime = pEvent->time();
		if (iTime >= iTimeStart && iTime < iTimeEnd) {
			qtractorMidiEvent *pNewEvent = new qtractorMidiEvent(*pEvent);
			pNewEvent->setTime(iTime - iTimeStart);
			if (pNewEvent->type() == qtractorMidiEvent::NOTEON) {
				pNewEvent->setVelocity((unsigned char)
					(clipGain() * float(pNewEvent->velocity())) & 0x7f);
				if (iTime + pEvent->duration() > iTimeEnd)
					pNewEvent->setDuration(iTimeEnd - iTime);
			}
			seq.insertEvent(pNewEvent);
		}
	}

	(*pfnClipExport)(&seq, pvArg);

	return true;
}
// Clip close-commit (record specific)
void qtractorMidiClip::close (void)
{
#ifdef CONFIG_DEBUG_0
	qDebug("qtractorMidiClip[%p]::close(%d)\n", this);
#endif

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

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

	// Take pretended clip-length...
	unsigned long iClipLength = clipLength();
	qtractorMidiSequence *pSeq = sequence();
	if (pSeq) {
		if (iClipLength > 0)
			pSeq->setTimeLength(pSession->tickFromFrame(iClipLength));
		// Final read statistics...
		m_noteMin = pSeq->noteMin();
		m_noteMax = pSeq->noteMax();
		// Actual sequence closure...
		pSeq->close();
		// Commit the final clip length...
		if (iClipLength < 1) {
			iClipLength = pSession->frameFromTick(pSeq->duration());
			setClipLength(iClipLength);
		}
	}

	// Now's time to write the whole thing...
	const bool bNewFile
		= (m_pFile && m_pFile->mode() == qtractorMidiFile::Write);
	if (bNewFile && iClipLength > 0 && pSeq) {
		// Write channel tracks...
		if (m_iFormat == 1)
			m_pFile->writeTrack(NULL);	// Setup track (SMF format 1).
		m_pFile->writeTrack(pSeq);		// Channel track.
		m_pFile->close();
	}

	// Sure close MIDI clip editor if any...
	if (m_pMidiEditorForm) {
		m_pMidiEditorForm->close();
		delete m_pMidiEditorForm;
		m_pMidiEditorForm = NULL;
	}

	// Just to be sure things get deallocated..
	closeMidiFile();

	// If proven empty, remove the file.
	if (bNewFile && iClipLength < 1)
		QFile::remove(filename());
}
// returns the duration of the source clip
TTimeIntervalMicroSeconds CMMFRawFormatRead::Duration(TMediaId aMediaId) const
	{
	if ((aMediaId.iMediaType == KUidMediaTypeAudio) && 
		(iClipLength) && (iSampleRate) && (iBitsPerSample) && (iChannels))
		{//we have enough values to calculate the duration
		TInt64 clipLength(iClipLength);
		clipLength*=KOneSecondInMicroSeconds;
		TTimeIntervalMicroSeconds duration = TTimeIntervalMicroSeconds(clipLength/iSampleRate);
		duration = TTimeIntervalMicroSeconds(duration.Int64()/(iBitsPerSample*iChannels));
		duration = TTimeIntervalMicroSeconds(duration.Int64()*8);
		return duration;
		}
	else return TTimeIntervalMicroSeconds(0);
	}
// Clip editor update.
void qtractorMidiClip::updateEditor ( bool bSelectClear )
{
	if (m_pMidiEditorForm == NULL)
		return;

	qtractorMidiEditor *pMidiEditor = m_pMidiEditorForm->editor();
	if (pMidiEditor) {
		pMidiEditor->reset(bSelectClear);
		pMidiEditor->setOffset(clipStart());
		pMidiEditor->setLength(clipLength());
		qtractorTrack *pTrack = track();
		if (pTrack) {
			pMidiEditor->setForeground(pTrack->foreground());
			pMidiEditor->setBackground(pTrack->background());
		}
		pMidiEditor->updateContents();
	}

	m_pMidiEditorForm->resetDirtyCount();
	m_pMidiEditorForm->updateInstrumentNames();
	m_pMidiEditorForm->stabilizeForm();
}
Exemple #5
0
/*
** SQL Trace callback
*/
static void sqlTraceCallback(void *NotUsed1, const char *zSql){
  UNUSED_PARAMETER(NotUsed1);
  logMessage("[%.*s]", clipLength(zSql), zSql);
}
// 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;
}