tbool CExportDSPTask::DoWork()
{
	tbool bError = false;

	switch (miActionOrder) {
		case geExportDSP_Start:
			{
				if (miChannels < 1) {
					// The Channels drop-down was left at "unchanged"
					// This always means stereo for DSP exports,
					// since all channels are processed stereo
					miChannels = 2;
				}

				// Save position
				muiPosSaved = gpApplication->GetSongPos();

				// Find end position + tail
				tint32 iTailFrames = Float2Int((miTailMS * gpApplication->GetSampleRate()) / 1000.0f);
				tint64 iLastSample = miFinalSample;
				if (iLastSample < 0) {
					if (IsOutMix()) {
						iLastSample = gpDSPEngine->Get_Session_End_Sample();
					}
					else {
						tint64 iFirstSample_Ignored;
						if (!gpDSPEngine->CalcTrackDuration(miTrack, &iFirstSample_Ignored, &iLastSample)) {
							// Fal back to full length
							iLastSample = gpDSPEngine->Get_Session_End_Sample();
						}
					}
				}
				muiEndPosPlusTail = iLastSample + iTailFrames;

				muiProgressTarget = 0;

				if (mfNormalizationFactor != 0.0f) {
					// We have a predefined normalization factor - don't do peak search
					miActionOrder = geExportDSP_Peak_After;
					miActionOrder++;
				}
				else {
					// Go to next task (peak search)
					miActionOrder++;
				}
			}
			break;

		case geExportDSP_Peak_Before:
			{
				gpApplication->Playback_InProgressTask(miFirstSample);
				if (IsOutMix())
					gpApplication->Playback_ExportOutMix(miFirstSample);
				else
					gpApplication->Playback_ExportTrack(miTrack, miFirstSample, miFinalSample);

				msProgress = "Peak search '";
				msProgress += msTrackName;

				msProgress += "'";
				muiProgressIx = 0;
				muiProgressTarget = muiEndPosPlusTail - miFirstSample;

				AllocBuffers(kiPeakPortionSize);

				mfPeak = 0.001f;
				muiPortionSize = kiPeakPortionSize;
				uiWholePortions = (muiEndPosPlusTail - miFirstSample) / kiPeakPortionSize;
				uiLastPortionSize = muiEndPosPlusTail % kiPeakPortionSize;

				if (!mbSkipFileOutput) {
					// Prepare for intermediate buffer file
					msIntermediateFiles[0] = sDestFolder + sDestNameAndExt + ".raw0";
					msIntermediateFiles[1] = sDestFolder + sDestNameAndExt + ".raw1";
					mpfIntermediateFiles[0] = IFile::Create();
					mpfIntermediateFiles[1] = IFile::Create();
					if ((mpfIntermediateFiles[0] == NULL) || (mpfIntermediateFiles[1] == NULL)) {
						msIntermediateFiles[0] = "";
						msIntermediateFiles[1] = "";
					}
					else {
						if (
							(!mpfIntermediateFiles[0]->Open(msIntermediateFiles[0].c_str(), IFile::FileCreate))
							||
							(!mpfIntermediateFiles[1]->Open(msIntermediateFiles[1].c_str(), IFile::FileCreate))
							)
						{
							msIntermediateFiles[0] = "";
							msIntermediateFiles[1] = "";
							mpfIntermediateFiles[0]->Destroy();
							mpfIntermediateFiles[0] = NULL;
							mpfIntermediateFiles[1]->Destroy();
							mpfIntermediateFiles[1] = NULL;
						}
						else if ((miFirstSample > 0) && (!mbRemoveInitialSilence)) {
							// Dump silence into file
							const tint32 kiChunkSamples = 1024;
							tint64 iSilentChunks = (miFirstSample / kiChunkSamples);
							tint64 iAfterChunks_Samples = miFirstSample - (iSilentChunks * kiChunkSamples);

							// Initialize a memory portion with silence
							tfloat32 afSilentChunk[kiChunkSamples];
							tchar* pacSilentChunk = (tchar*)afSilentChunk;
							memset(pacSilentChunk, '\0', kiChunkSamples * sizeof(tfloat32));

							// Write whole chunks
							for ( ;iSilentChunks > 0; iSilentChunks--) {
								// Since these are temporary files we ignore MSB / LSB questions
								mpfIntermediateFiles[0]->Write(pacSilentChunk, kiChunkSamples * sizeof(tfloat32));
								mpfIntermediateFiles[1]->Write(pacSilentChunk, kiChunkSamples * sizeof(tfloat32));
							}
							// Write extra samples after whole chunks
							if (iAfterChunks_Samples > 0) {
								// Since these are temporary files we ignore MSB / LSB questions
								mpfIntermediateFiles[0]->Write(pacSilentChunk, iAfterChunks_Samples * sizeof(tfloat32));
								mpfIntermediateFiles[1]->Write(pacSilentChunk, iAfterChunks_Samples * sizeof(tfloat32));
							}
						}
					}
				}

				miActionOrder++;
			}
			break;

		case geExportDSP_Peak_Action:
			{
				bError = !DoEncode_InALoop(false);
			}
			break;

		case geExportDSP_Peak_After:
			{
				msProgress = "Peak search done";
				muiProgressIx = muiProgressTarget = 1;

				mfNormalizationFactor = 1.0f;
				mfNormalizationFactor /= mfPeak;

				if (mpfIntermediateFiles[0]) {
					mpfIntermediateFiles[0]->Close();
				}
				if (mpfIntermediateFiles[1]) {
					mpfIntermediateFiles[1]->Close();
				}

				if (mbSkipFileOutput) {
					miActionOrder = geExportDSP_After;
				}
				miActionOrder++;
			}
			break;

		case geExportDSP_Before:
			{
				if (mbSkipFileOutput) {
					// Skip encoding
					gpApplication->Playback_InProgressTask(muiPosSaved);
					msProgress = "";
					muiProgressIx = muiProgressTarget = 0;

					miActionOrder = geExportDSP_After;
					miActionOrder++;
				}
				else {
					// Prepare for encoding
					tint64 iPosToStart = (mbRemoveInitialSilence) ? miFirstSample : 0;
					if (msIntermediateFiles[0].length()) {
						// Load from intermediate files
						mpfIntermediateFiles[0]->Open(msIntermediateFiles[0].c_str(), IFile::FileRead);
						mpfIntermediateFiles[1]->Open(msIntermediateFiles[1].c_str(), IFile::FileRead);
					}
					else {
						if (IsOutMix())
							gpApplication->Playback_ExportOutMix(iPosToStart);
						else
							gpApplication->Playback_ExportTrack(miTrack, iPosToStart, miFinalSample);
					}

					msProgress = "Exporting '";
					msProgress += sDestNameAndExt;

					msProgress += "'";
					muiProgressIx = 0;
					muiProgressTarget = (muiEndPosPlusTail - iPosToStart);

					AllocBuffers(miPortionSize);

					muiPortionSize = miPortionSize;
					uiWholePortions = (muiEndPosPlusTail - iPosToStart) / miPortionSize;
					uiLastPortionSize = muiEndPosPlusTail % miPortionSize;

					miActionOrder++;
				}
			}
			break;

		case geExportDSP_Action:
			{
				if (mpfOutput == NULL) {
					bError = !DoEncode_FirstTimeHere();
				}

				if (!bError) {
					bError = !DoEncode_InALoop(true);
				}
			}
			break;

		case geExportDSP_After:
			{
				gpApplication->Playback_InProgressTask(muiPosSaved);
				msProgress = "Export done";
				muiProgressIx = muiProgressTarget = 1;

				miActionOrder++;
			}
			break;

		default:
			// Why are we here?
			bError = true;
			break;

	}

	if (bError) {
		miActionOrder = geExportDSP_Done;
	}
	return !bError;
} // DoWork
Ejemplo n.º 2
0
tbool CExportClipTask::DoEncode()
{
	tbool bError = false;

	if (mpfDst == NULL) {
		// First time here
		bError = !DoEncode_FirstTimeHere();
	}

	if (!bError) {
		tint64 iActuallyProcessed = 0;

		// Maybe prepare a chunk of silence
		if (IsSilence() && (mpcSilence == NULL)) {
			tint32 iSilence24bitSize = iMaxToProcess * (24 / 8);
			mpcSilence = new tchar[iSilence24bitSize];
			memset(mpcSilence, '\0', iSilence24bitSize);
		}

		if (muiSamplesNeeded > 0) {
			// How many samples now?
			tint32 iWantsToProcess = iMaxToProcess;
			if (muiSamplesNeeded < iWantsToProcess)
				iWantsToProcess = (tint32)muiSamplesNeeded;

			tbool bPartSuccess = false;
			switch (iFiles) {
				case 0: // silence
					{
						tint64 iOF_Dummy = 0;
						bPartSuccess = mpEncoder->SetRawMode(true, 1, false, 24, iSampleRate);
						if (bPartSuccess) {
							tint32 iBytes = iWantsToProcess * (24 / 8);
							bPartSuccess = mpEncoder->ProcessRaw(mpcSilence, NULL, iBytes, &iOF_Dummy);
							mpEncoder->SetRawMode(false, 0, false, 0, 0);
							iActuallyProcessed = iWantsToProcess;
						}
					}
					break;
				case 1: // mono
					bPartSuccess = mpEncoder->Process(
						pfWaveL,
						(tint32)muiCurrEncodeIx, iWantsToProcess, &iActuallyProcessed);
					break;
				default: // stereo
					bPartSuccess = mpEncoder->Process(
						pfWaveL, pfWaveR,
						(tint32)muiCurrEncodeIx, iWantsToProcess, &iActuallyProcessed);
					break;
			}
			if (bPartSuccess) {
				if (muiSamplesNeeded == (tuint64)-1) {
					// Figure out how big the file really is (to show progress correctly)
					muiSamplesNeeded = mpEncoder->miInputSamples_IncludingSkipped;
					muiProgressTarget = muiSamplesNeeded;
				}

				muiProgressIx += iActuallyProcessed;
				muiCurrEncodeIx += iActuallyProcessed;
				muiSamplesNeeded -= iActuallyProcessed;
			}
			else {
				tchar pszErr[1024];
				mpEncoder->GetErrMsg(pszErr, 1024, true);
				msExtendedError += pszErr;
				iActuallyProcessed = 0;
				bError = true;
			}
		}
	}

	if ((!bError) && (muiSamplesNeeded == 0)) {
		// We're done with this clip / silent bit
		
		// Prepare to advance to next task
		miActionOrder++;

		// Test if we should concatenate another file
		if (pConcatenateNextTask) {
			// Transfer encoder and other stuff to next clip (we don't close them)
			pConcatenateNextTask->mpEncoder = mpEncoder;
			mpEncoder = NULL;
			pConcatenateNextTask->mpfDst = mpfDst;
			mpfDst = NULL;
			pConcatenateNextTask->sOut = sOut;
		}
		else {
			// We're done - close encoder and other stuff
			if (!mpEncoder->Finalize()) {
				// Encoder finalize failed!
				tchar pszErr[1024];
				mpEncoder->GetErrMsg(pszErr, 1024, true);
				msExtendedError = pszErr;
				bError = true;
			}
			else {
				mpEncoder->Destroy();
				mpEncoder = NULL;

				mpfDst->Destroy();
				mpfDst = NULL;
			}
		}
	}

	return !bError;
} // DoEncode