Skip to content

Commit

Permalink
refactor(node-medley): extract function for getting audio properties …
Browse files Browse the repository at this point in the history
…out of the Metadata class
  • Loading branch information
vittee committed Mar 9, 2024
1 parent ec6b642 commit 34986e2
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 65 deletions.
146 changes: 103 additions & 43 deletions packages/engine/src/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,30 +191,6 @@ namespace {
}
}

void medley::Metadata::readMpegInfo(const File& f)
{
FileInputStream stream(f);

mp3dec_io_t io{};
mp3dec_ex_t dec{};

io.read = &minimp3_read_cb;
io.seek = &minimp3_seek_cb;
io.read_data = io.seek_data = &stream;

mp3dec_ex_open_cb(&dec, &io, MP3D_SEEK_TO_SAMPLE);

auto lengthInSamples = dec.detected_samples / dec.info.channels;

if (lengthInSamples <= 0) {
lengthInSamples = dec.samples / dec.info.channels;
}

bitrate = dec.info.bitrate_kbps;
sampleRate = dec.info.hz;
duration = lengthInSamples / (float)sampleRate;
}

bool medley::Metadata::readID3V2(const juce::File& f)
{
#ifdef _WIN32
Expand All @@ -230,9 +206,6 @@ bool medley::Metadata::readID3V2(const juce::File& f)
}

try {

readMpegInfo(f);

if (!file.hasID3v2Tag()) {
return false;
}
Expand Down Expand Up @@ -341,22 +314,7 @@ bool medley::Metadata::readFLAC(const File& f)
TagLib::FLAC::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), true, TagLib::AudioProperties::Fast);

if (!file.isValid()) {
throw std::runtime_error("Invalid FLAC file");
}

if (isFLACSupported(&stream)) {
try {
auto const props = file.audioProperties();

bitrate = props->bitrate();
sampleRate = props->sampleRate();
duration = props->lengthInMilliseconds() / 1000.0;
}
catch (...) {
bitrate = 0;
sampleRate = 0;
duration = 0;
}
throw std::runtime_error("Could not open FLAC file for reading");
}

try {
Expand Down Expand Up @@ -533,3 +491,105 @@ void medley::Metadata::CoverAndLyrics::read(const File& file, bool readCover, bo
}
}
}

medley::Metadata::AudioProperties::AudioProperties(const File& file)
{
read(file);
}

void medley::Metadata::AudioProperties::read(const File& file)
{
auto filetype = utils::getFileTypeFromFileName(file);

switch (filetype) {
case utils::FileType::MP3: {
readMpegInfo(file);
return;
}

case utils::FileType::FLAC: {
readXiph(file);
return;
}
}
}

void medley::Metadata::AudioProperties::readMpegInfo(const File& f)
{
#ifdef _WIN32
TagLib::FileName fileName((const wchar_t*)f.getFullPathName().toWideCharPointer());
#else
TagLib::FileName fileName(f.getFullPathName().toRawUTF8());
#endif

TagLib::FileStream stream(fileName);
TagLib::MPEG::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), true, TagLib::AudioProperties::Average);

if (file.isSupported(&stream)) {
auto props = file.audioProperties();

bitrate = props->bitrate();
sampleRate = props->sampleRate();
duration = props->lengthInSeconds();

//if ((bitrate != 0) && (sampleRate != 0) && (duration != 0)) {
// return;
//}
}

/*{
FileInputStream stream(f);
mp3dec_io_t io{};
mp3dec_ex_t dec{};
io.read = &minimp3_read_cb;
io.seek = &minimp3_seek_cb;
io.read_data = io.seek_data = &stream;
if (mp3dec_ex_open_cb(&dec, &io, MP3D_SEEK_TO_SAMPLE) != 0) {
return;
}
auto lengthInSamples = dec.detected_samples / dec.info.channels;
if (lengthInSamples <= 0) {
lengthInSamples = dec.samples / dec.info.channels;
}
bitrate = dec.info.bitrate_kbps;
sampleRate = dec.info.hz;
duration = lengthInSamples / (float)sampleRate;
}*/
}

void medley::Metadata::AudioProperties::readXiph(const File& f)
{
#ifdef _WIN32
TagLib::FileName fileName((const wchar_t*)f.getFullPathName().toWideCharPointer());
#else
TagLib::FileName fileName(f.getFullPathName().toRawUTF8());
#endif

TagLib::FileStream stream(fileName);
TagLib::FLAC::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), true, TagLib::AudioProperties::Fast);

if (!file.isValid()) {
throw std::runtime_error("Invalid FLAC file");
}

if (isFLACSupported(&stream)) {
try {
auto const props = file.audioProperties();

bitrate = props->bitrate();
sampleRate = props->sampleRate();
duration = props->lengthInMilliseconds() / 1000.0;
}
catch (...) {
bitrate = 0;
sampleRate = 0;
duration = 0;
}
}
}
29 changes: 20 additions & 9 deletions packages/engine/src/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,25 @@ class Metadata {
juce::String lyrics;
};

class AudioProperties
{
public:
AudioProperties(const File& file);

int getBitrate() const { return bitrate; }
int getSampleRate() const { return sampleRate; }
double getDuration() const { return duration; }

private:
void read(const File& file);
void readMpegInfo(const File& f);
void readXiph(const File& f);

int bitrate = 0;
int sampleRate = 0;
double duration = 0;
};

Metadata();

bool readFromTrack(const ITrack::Ptr track);
Expand All @@ -82,14 +101,10 @@ class Metadata {
double getCueIn() const { return cueIn; }
double getCueOut() const { return cueOut; }
double getLastAudible() const { return lastAudible; }
int getBitrate() const { return bitrate; }
int getSampleRate() const { return sampleRate; }
double getDuration() const { return duration; }

std::vector<std::pair<juce::String, juce::String>>& getComments() { return comments; }

private:
void readMpegInfo(const File& f);
private:
bool readID3V2(const File& f);
bool readFLAC(const File& f);
void readTag(const TagLib::Tag& tag);
Expand All @@ -108,10 +123,6 @@ class Metadata {
double lastAudible = -1.0;

std::vector<std::pair<juce::String, juce::String>> comments;

int bitrate = 0;
int sampleRate = 0;
double duration = 0;
};

}
2 changes: 1 addition & 1 deletion packages/node-medley/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@seamless-medley/medley",
"description": "Audio engine for Node.js, with built-in \"radio like\" gapless/seamless playback",
"version": "0.4.1-fix-doubled-track-loading.0",
"version": "0.4.1-audio-property.0",
"author": {
"name": "Wittawas Nakkasem",
"email": "[email protected]",
Expand Down
40 changes: 32 additions & 8 deletions packages/node-medley/src/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ namespace {
result.Set("albumArtist", safeString(env, metadata.getAlbumArtist()));
result.Set("originalArtist", safeString(env, metadata.getOriginalArtist()));

auto bitrate = metadata.getBitrate();
auto sampleRate = metadata.getSampleRate();
auto duration = metadata.getDuration();

result.Set("bitrate", bitrate != 0.0f ? Napi::Number::New(env, bitrate) : env.Undefined());
result.Set("sampleRate", sampleRate != 0.0f ? Napi::Number::New(env, sampleRate) : env.Undefined());
result.Set("duration", duration != 0.0f ? Napi::Number::New(env, duration) : env.Undefined());

auto trackGain = metadata.getTrackGain();
auto bpm = metadata.getBeatsPerMinute();

Expand All @@ -49,6 +41,21 @@ namespace {

return result;
}

void readAudioProperties(juce::String trackFile, Object& result) {
medley::Metadata::AudioProperties audProps(trackFile);

auto bitrate = audProps.getBitrate();
auto sampleRate = audProps.getSampleRate();
auto duration = audProps.getDuration();

auto env = result.Env();

result.Set("bitrate", bitrate != 0.0f ? Napi::Number::New(env, bitrate) : env.Undefined());
result.Set("sampleRate", sampleRate != 0.0f ? Napi::Number::New(env, sampleRate) : env.Undefined());
result.Set("duration", duration != 0.0f ? Napi::Number::New(env, duration) : env.Undefined());
}

}

void Medley::Initialize(Object& exports) {
Expand Down Expand Up @@ -86,6 +93,7 @@ void Medley::Initialize(Object& exports) {
InstanceAccessor<&Medley::getReplayGainBoost, &Medley::setReplayGainBoost>("replayGainBoost"),
//
StaticMethod<&Medley::static_getMetadata>("getMetadata"),
StaticMethod<&Medley::static_getAudioProperties>("getAudioProperties"),
StaticMethod<&Medley::static_getCoverAndLyrics>("getCoverAndLyrics"),
StaticMethod<&Medley::static_isTrackLoadable>("isTrackLoadable"),
StaticMethod<&Medley::static_getInfo>("$getInfo"),
Expand Down Expand Up @@ -967,6 +975,22 @@ Napi::Value Medley::static_getMetadata(const CallbackInfo& info) {
return createJSMetadata(env, metadata);
}

Napi::Value Medley::static_getAudioProperties(const Napi::CallbackInfo& info) {
auto env = info.Env();

if (info.Length() < 1) {
TypeError::New(env, "Insufficient parameter").ThrowAsJavaScriptException();
return env.Undefined();
}

juce::String trackFile = info[0].ToString().Utf8Value();
auto result = Object::New(env);

readAudioProperties(trackFile, result);

return result;
}

Napi::Value Medley::static_getCoverAndLyrics(const Napi::CallbackInfo& info) {
auto env = info.Env();

Expand Down
2 changes: 2 additions & 0 deletions packages/node-medley/src/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ class Medley : public ObjectWrap<Medley>, public Engine::Callback, public Engine

static Napi::Value static_getMetadata(const Napi::CallbackInfo& info);

static Napi::Value static_getAudioProperties(const Napi::CallbackInfo& info);

static Napi::Value static_getCoverAndLyrics(const Napi::CallbackInfo& info);

static Napi::Value static_isTrackLoadable(const Napi::CallbackInfo& info);
Expand Down
11 changes: 8 additions & 3 deletions packages/node-medley/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ export declare class Medley<T extends TrackInfo = TrackInfo> {

static getMetadata(path: string): Metadata | undefined;

static getAudioProperties(path: string): AudioProperties;

static getCoverAndLyrics(path: string): CoverAndLyrics;

static isTrackLoadable(track: TrackDescriptor<any>): boolean;
Expand Down Expand Up @@ -360,14 +362,17 @@ export type Metadata = {
isrc?: string;
albumArtist?: string;
originalArtist?: string;
bitrate?: number;
sampleRate?: number;
duration?: number;
trackGain?: number;
bpm?: number;
comments: [string, string][];
}

export type AudioProperties = {
bitrate?: number;
sampleRate?: number;
duration?: number;
}

export type MetadataFields = keyof Metadata;

export type CoverAndLyrics = {
Expand Down
2 changes: 1 addition & 1 deletion packages/node-medley/src/version.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#define MEDLEY_VERSION_MAJOR 0
#define MEDLEY_VERSION_MINOR 4
#define MEDLEY_VERSION_PATCH 1
#define MEDLEY_VERSION_PRE_RELEASE "fix-doubled-track-loading.0"
#define MEDLEY_VERSION_PRE_RELEASE "audio-property.0"

0 comments on commit 34986e2

Please sign in to comment.