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
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