11namespace tracktion {
inline namespace engine
15 : engine (e), state (IDs::LOOPINFO)
17 initialiseMissingProps();
21 : engine (e), state (IDs::LOOPINFO)
25 if (
auto af = formatManager.getFormatFromFileName (f))
30 init (afr.
get(), af, f);
36 : engine (e), state (IDs::LOOPINFO)
42 : engine (e), state (v), um (u), maintainParent (v.getParent().isValid())
44 initialiseMissingProps();
48 : engine (other.engine)
55 return copyFrom (o.state);
66 if (newBpm != currentBpm)
69 const double ratio = newBpm / currentBpm;
81 if (wi.sampleRate == 0.0)
84 if (newBpm < 30.0 || newBpm > 1000.0)
87 const double currentBpm =
getBpm (wi);
92 const auto lengthMins = wi.getLengthInSeconds() / 60.0;
93 const auto numBeats = newBpm * lengthMins;
98 setBpm (newBpm, currentBpm);
106 if (wi.sampleRate == 0.0)
112 if (out == -1 || out > wi.lengthInSamples)
113 out = wi.lengthInSamples;
118 auto length = (out - in) / wi.sampleRate;
159 auto lp = getLoopPoints().
getChild (idx);
162 return {
static_cast<juce::int64> (lp.getProperty (IDs::value)),
163 (
LoopPointType)
static_cast<int> (lp.getProperty (IDs::type)) };
173 auto t = createValueTree (IDs::LOOPPOINT,
175 IDs::type, (
int) type);
177 getOrCreateLoopPoints().
addChild (t, -1,
nullptr);
185 auto lp = getLoopPoints().
getChild (idx);
195 removeChildIfEmpty (IDs::LOOPPOINTS);
208 auto lps = getLoopPoints();
210 for (
int i = lps.getNumChildren(); --i >= 0;)
211 if (((
LoopPointType)
int (lps.getChild (i).getProperty (IDs::type))) == type)
212 lps.removeChild (i,
nullptr);
225 t.setProperty (IDs::name, tag, um);
226 getOrCreateTags().
addChild (t, -1, um);
231 for (
const auto& t : tags)
235void LoopInfo::initialiseMissingProps()
238 setPropertyIfMissing (state, IDs::numBeats, 0.0, um);
239 setPropertyIfMissing (state, IDs::denominator, 0, um);
240 setPropertyIfMissing (state, IDs::numerator, 0, um);
241 setPropertyIfMissing (state, IDs::oneShot, 0, um);
242 setPropertyIfMissing (state, IDs::bpm, 0, um);
243 setPropertyIfMissing (state, IDs::rootNote, -1, um);
244 setPropertyIfMissing (state, IDs::inMarker, 0, um);
245 setPropertyIfMissing (state, IDs::outMarker, -1, um);
251 copyValueTree (state, o, um);
259 if (v.getNumChildren() == 0)
269void LoopInfo::duplicateIfShared()
283 if (parent.isValid())
285 index = parent.indexOf (state);
286 parent.removeChild (index, um);
291 if (parent.isValid())
302 return af1 == af2 || (af1 !=
nullptr && af2 !=
nullptr
308 if (afr ==
nullptr || af ==
nullptr)
314 #if TRACKTION_ENABLE_REX
315 if (isSameFormat (af, formatManager.getRexFormat()))
319 const double bpm = afr->
metadataValues[RexAudioFormat::rexTempo].getDoubleValue();
320 setProp (IDs::bpm, bpm);
327 for (
int i = 0; i < beatPoints.
size(); ++i)
332 if (isSameFormat (af, formatManager.getAiffFormat()))
342 setProp (IDs::numBeats, numBeats);
348 t.removeEmptyStrings();
350 for (
int i = 0; i < t.size(); ++i)
353 else if (isSameFormat (af, formatManager.getWavFormat()))
360 copyFrom (juce::ValueTree::fromXml (*n));
369 if (
auto smplNote = afr->
metadataValues[
"MidiUnityNote"].getIntValue())
381 else if (isSameFormat (af, formatManager.getNativeAudioFormat()))
388 copyFrom (juce::ValueTree::fromXml (*n));
395 setProp (IDs::bpm, bpm);
410 setProp (IDs::bpm, beats / fileDuration / 60.0);
416 if (timeSig.isNotEmpty())
418 setDenominator (timeSig.upToFirstOccurrenceOf (
"/",
false,
false).getIntValue());
419 setNumerator (timeSig.fromFirstOccurrenceOf (
"/",
false,
false).getIntValue());
424 if (keySig.isNotEmpty())
426 bool sharpOrFlat = keySig[1] ==
'#' || keySig[1] ==
'b';
427 setRootNote (Pitch::getPitchFromString (
engine, keySig.substring (0, sharpOrFlat ? 2 : 1)));
428 addTag (keySig.getLastCharacter() ==
'm' ?
"minor" :
"major");
455 deduceTempo (file, *afr);
457 initialiseMissingProps();
462 if (
auto tempoStr = metadata[
"CueLabel0Text"]; tempoStr.isNotEmpty())
463 if (tempoStr.contains (
"Tempo:"))
464 if (
auto val = tempoStr.fromFirstOccurrenceOf (
"Tempo: ",
false,
false).getFloatValue(); val >= 50 && val <= 250)
473 std::reverse (tokens.strings.begin(), tokens.strings.end());
481 for (
auto token : reverseTokens (name,
"_",
""))
483 if (token.containsIgnoreCase (
"bpm"))
487 while (token.startsWith (
"0"))
490 auto val = token.getIntValue();
492 if (val > 50 && val < 250 &&
juce::String (val) == token)
497 for (
auto token : reverseTokens (name,
"_",
""))
499 auto val = token.getIntValue();
501 while (token.startsWith (
"0"))
502 token = token.substring (1);
504 if (val > 50 && val < 250 &&
juce::String (val) == token)
515 for (
auto token : reverseTokens (name,
"_",
""))
521 if (token ==
"a")
return 57;
522 if (token ==
"a#")
return 58;
523 if (token ==
"bb")
return 58;
524 if (token ==
"b")
return 59;
525 if (token ==
"c")
return 60;
526 if (token ==
"c#")
return 61;
527 if (token ==
"db")
return 61;
528 if (token ==
"d")
return 62;
529 if (token ==
"d#")
return 63;
530 if (token ==
"eb")
return 63;
531 if (token ==
"e")
return 64;
532 if (token ==
"f")
return 65;
533 if (token ==
"f#")
return 66;
534 if (token ==
"gb")
return 66;
535 if (token ==
"g")
return 67;
536 if (token ==
"g#")
return 68;
537 if (token ==
"ab")
return 68;
546 if (len <= 1.0 && len > 60.0)
549 auto fn = file.getFileNameWithoutExtension();
552 if (! tempo.has_value())
553 tempo = getFileNameTempo (fn);
555 if (! tempo.has_value())
558 auto beats = *tempo / 60 * len;
560 if (rem < 0.0f || (rem > 0.1f && rem < 3.9f) || rem > 4.0f)
564 setProp (IDs::oneShot,
false);
569 if (
auto root = getFileNameRootNote (fn))
572 #if LOG_DEDUCED_TEMPO
578 #if LOG_DEDUCED_TEMPO
std::unique_ptr< FileInputStream > createInputStream() const
static String getMidiNoteName(int noteNumber, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
void removeEmptyStrings(bool removeWhitespaceStrings=true)
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
int size() const noexcept
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
bool containsKey(StringRef key) const noexcept
String dropLastCharacters(int numberToDrop) const
static String formatted(const String &formatStr, Args... args)
String toLowerCase() const
double getDoubleValue() const noexcept
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
String substring(int startIndex, int endIndex) const
int getIntValue() const noexcept
bool isNotEmpty() const noexcept
void removeChild(const ValueTree &child, UndoManager *undoManager)
ValueTree getChild(int index) const
int getNumChildren() const noexcept
int getReferenceCount() const noexcept
ValueTree & setProperty(const Identifier &name, const var &newValue, UndoManager *undoManager)
void addChild(const ValueTree &child, int index, UndoManager *undoManager)
ValueTree getParent() const noexcept
const var & getProperty(const Identifier &name) const noexcept
ValueTree createCopy() const
ValueTree getChildWithName(const Identifier &type) const
ValueTree getOrCreateChildWithName(const Identifier &type, UndoManager *undoManager)
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.
Holds tempo/beat information about an audio file.
bool isOneShot() const
Returns true if this can be is a one-shot e.g.
SampleCount getOutMarker() const
Returns the sample number used as the end point in the file.
void clearLoopPoints()
Removes all the loop points.
void setInMarker(SampleCount)
Sets the sample number to be used as the start point in the file.
void setNumerator(int newNumerator)
Sets the numerator of the object.
void setDenominator(int newDenominator)
Sets the denominator of the object.
void setBpm(double newBpm, const AudioFileInfo &)
Sets the tempo of the object.
void addLoopPoint(SampleCount, LoopPointType)
Adds a loop point at the given position.
LoopInfo(Engine &)
Creates an empty LoopInfo.
int getDenominator() const
Returns the denominator of the object.
int getNumTags() const
Returns the number of tags.
LoopInfo & operator=(const LoopInfo &)
Creates a copy of another LoopInfo.
void addTag(const juce::String &tag)
Adds a tag.
bool isLoopable() const
Returns true if this can be looped.
LoopPoint getLoopPoint(int index) const
Returns the loop points at the given index.
int getRootNote() const
Returns the root note of the object.
void changeLoopPoint(int index, SampleCount, LoopPointType)
Sets the loop point at the given index to a new position and type.
int getNumLoopPoints() const
Returns the number of loop points in the object.
LoopPointType
Enum to represet the type of loop point.
@ manual
A manual loop point.
SampleCount getInMarker() const
Returns the sample number used as the start point in the file.
void addTags(const juce::StringArray &tags)
Adds multiple tags.
double getNumBeats() const
Returns the number of beats.
double getBpm(const AudioFileInfo &) const
Returns the tempo of the object.
void clearTags()
Removes all the tags.
void setOutMarker(SampleCount)
Sets the sample number to be used as the end point in the file.
void deleteLoopPoint(int index)
Removes the loop point at the given index.
int getNumerator() const
Returns the numerator of the object.
Engine & engine
The engine this belongs to.
juce::String getTag(int index) const
Returns the tag at a given index.
void setRootNote(int note)
Sets the root note of the object.
void setNumBeats(double newNumBeats)
Sets the number of beats.
double getBeatsPerSecond(const AudioFileInfo &) const
Returns the tempo of the object.
constexpr Type jmax(Type a, Type b)
std::unique_ptr< XmlElement > parseXML(const String &textToParse)
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.