11namespace tracktion {
inline namespace engine
16 return engine.getAudioFileFormatManager().readFormatManager.createReaderFor (file);
21 auto& manager = engine.getAudioFileFormatManager().readFormatManager;
23 for (
auto af : manager)
25 if (af->canHandleFile (file))
27 if (
auto in = file.createInputStream())
29 if (
auto r = af->createReaderFor (in.release(),
true))
43 auto& manager = engine.getAudioFileFormatManager().readFormatManager;
45 for (
auto af : manager)
47 if (af->canHandleFile (file))
49 if (
auto r = af->createMemoryMappedReader (file))
64 auto& fileFormatManager = engine.getAudioFileFormatManager();
69 if (
auto audioFormat = fileFormatManager.getFormatFromFileName (file))
80 result->mappedFile = std::move (mf);
81 result->reader = std::move (reader);
92 double sampleRate,
unsigned int numChannels,
int bitsPerSample,
99 if (
auto writer =
format->createWriterFor (out.get(), sampleRate,
100 numChannels, bitsPerSample,
113 unsigned int numChannels,
int bitsPerSample,
116 if (
auto format = engine.getAudioFileFormatManager().getFormatFromFileName (file))
117 return createWriterFor (format, file, sampleRate, numChannels, bitsPerSample, metadata, quality);
122SampleRange AudioFileUtils::scanForNonZeroSamples (
Engine& engine,
const juce::File& file,
float maxZeroLevelDb)
126 if (reader ==
nullptr)
129 auto numChans = (
int) reader->numChannels;
131 if (numChans == 0 || reader->lengthInSamples == 0)
134 const float floatMaxZeroLevel = 2.0f * dbToGain (maxZeroLevelDb);
136 const int sampsPerBlock = 32768;
139 chans.
calloc ((
size_t) numChans + 2);
143 for (
int i = 0; i < numChans; ++i)
144 chans[i] = buffer + i * sampsPerBlock;
146 SampleCount firstNonZero = 0, lastNonZero = 0, n = 0;
147 bool needFirst =
true;
149 while (n < reader->lengthInSamples)
151 for (
int j = numChans; --j >= 0;)
152 std::memset (chans[j], 0,
sizeof (
int) * sampsPerBlock);
154 reader->read (chans, numChans, n, sampsPerBlock,
false);
156 for (
int j = numChans; --j >= 0;)
158 if (reader->usesFloatingPointData)
160 const float*
const chan = (
const float*) chans[j];
162 for (
int i = 0; i < sampsPerBlock; ++i)
164 if (std::abs (chan[i]) > floatMaxZeroLevel)
168 firstNonZero = n + i;
172 lastNonZero =
std::max (lastNonZero, n + i);
178 const int*
const chan = chans[j];
180 for (
int i = 0; i < sampsPerBlock; ++i)
182 if (std::abs (chan[i]) > intMaxZeroLevel)
186 firstNonZero = n + i;
190 lastNonZero =
std::max (lastNonZero, n + i);
199 return { firstNonZero, lastNonZero };
206 if (range.contains ({ 0, reader->lengthInSamples })
212 return range.getLength();
219 (
int) reader->bitsPerSample,
220 reader->metadataValues,
223 if (writer !=
nullptr
224 && writer->writeFromAudioReader (*reader, range.getStart(), range.getLength()))
225 return range.getLength();
230SampleCount AudioFileUtils::copySectionToNewFile (
Engine& e,
const juce::File& sourceFile,
231 const juce::File& destFile, SampleRange range)
238 if (reader !=
nullptr)
239 return copySection (e, reader, sourceFile, destFile, range);
244SampleCount AudioFileUtils::copySectionToNewFile (
Engine& e,
254 if (reader !=
nullptr)
255 return copySection (e, reader, sourceFile, destFile,
256 { (SampleCount) tracktion::toSamples (range.getStart(), reader->sampleRate),
257 (SampleCount) tracktion::toSamples (range.getEnd(), reader->sampleRate) });
262SampleRange AudioFileUtils::copyNonSilentSectionToNewFile (
Engine& e,
265 float maxZeroLevelDb)
267 auto range = scanForNonZeroSamples (e, sourceFile, maxZeroLevelDb);
269 if (copySectionToNewFile (e, sourceFile, destFile, range) >= 0)
275SampleRange AudioFileUtils::trimSilence (
Engine& e,
const juce::File& file,
float maxZeroLevelDb)
277 if (file.hasWriteAccess())
280 auto range = copyNonSilentSectionToNewFile (e, file, tempFile.getFile(), maxZeroLevelDb);
282 if (! range.isEmpty())
283 if (tempFile.overwriteTargetFileWithTemporary())
298 if (reader ==
nullptr || format ==
nullptr)
302 if (format->isCompressed() && canCreateWavIntermediate)
310 if (out ==
nullptr || (! convertToFormat<juce::WavAudioFormat> (engine, source, *out, 0, {})))
314 return reverse (engine, tempFile.getFile(), destination, progress, job,
false);
318 if (reader->metadataValues.getValue (
"MetaDataSource",
"None") ==
"AIFF")
319 reader->metadataValues.clear();
322 (
int) reader->numChannels, reader->sampleRate,
323 std::max (16, (
int) reader->bitsPerSample),
324 reader->metadataValues, 0);
326 if (
auto af = writer.file.getFormat())
336 SampleCount sourceSample = 0;
337 SampleCount samplesToDo = reader->lengthInSamples;
338 const int bufferSize = 65536;
339 auto sampleNum = samplesToDo;
341 const int numChans = (
int) reader->numChannels;
344 bool shouldExit =
false;
348 auto numThisTime = (
int)
std::min (samplesToDo, (SampleCount) bufferSize);
350 if (numThisTime <= 0)
353 for (
int i = numChans; --i >= 0;)
356 sampleNum -= numThisTime;
357 reader->read (buffers, numChans, sampleNum, numThisTime,
true);
359 for (
int i = numThisTime / 2; --i >= 0;)
361 const int other = (numThisTime - i) - 1;
363 for (
int j = numChans; --j >= 0;)
365 if (buffers[j] !=
nullptr)
367 const int temp = buffers[j][i];
368 buffers[j][i] = buffers[j][other];
369 buffers[j][other] = temp;
377 samplesToDo -= numThisTime;
378 sourceSample += numThisTime;
380 progress =
juce::jlimit (0.0f, 1.0f, (
float) (sourceSample / (
double) reader->lengthInSamples));
396SampleCount AudioFileUtils::getFileLengthSamples (
Engine& e,
const juce::File& file)
400 if (reader !=
nullptr)
401 return reader->lengthInSamples;
403 TRACKTION_LOG_ERROR (
"Couldn't read file: " + file.getFileName());
413 return reader !=
nullptr;
416void AudioFileUtils::applyBWAVStartTime (
const juce::File& file, SampleCount time)
418 if (isWavFile (file))
427 for (
int i = 0; i < 2048; ++i)
433 for (
int j = 0; j < 4; ++j)
444 pos += 256 + 32 + 32 + 10 + 8;
450 fo.setPosition (pos);
452 fo.writeInt ((
int) (uint32_t) (time & 0xffffffff));
453 fo.writeInt ((
int) (uint32_t) (time >> 32));
Type * getWritePointer(int channelNumber) noexcept
String getFileExtension() const
bool copyFileTo(const File &targetLocation) const
static File createTempFile(StringRef fileNameEnding)
ElementType * getData() const noexcept
void calloc(SizeType newNumElements, const size_t elementSize=sizeof(ElementType))
bool shouldExit() const noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Smart wrapper for writing to an audio file.
bool appendBuffer(juce::AudioBuffer< float > &buffer, int numSamples)
Appends an AudioBuffer to the file.
bool isOpen() const noexcept
Returns true if the file is open and ready to write to.
The Engine is the central class for all tracktion sessions.
AudioFileFormatManager & getAudioFileFormatManager() const
Returns the AudioFileFormatManager that maintains a list of available audio file formats.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
static bool reverse(Engine &, const juce::File &source, const juce::File &destination, std::atomic< float > &progress, juce::ThreadPoolJob *job=nullptr, bool canCreateWavIntermediate=true)
Reverses a file updating a progress value and checking the exit status of a given job.
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.