Add BPM detection using aubio.

This commit is contained in:
apoorv569 2022-09-16 16:44:24 +05:30
parent c2256d8d2e
commit 66ce190098
10 changed files with 186 additions and 55 deletions

View File

@ -277,6 +277,13 @@ if not spdlog.found()
spdlog = spdlog_subproject.get_variable('spdlog_dep')
endif
aubio = dependency('aubio', version: '>=0.4.9', required: false)
if not aubio.found()
aubio_subproject = subproject('aubio')
aubio = aubio_subproject.get_variable('aubio_dep')
endif
# Create SampleHiveConfig.hpp based on configuration
config = configure_file(output: 'SampleHiveConfig.hpp',
configuration: config_data,)
@ -291,7 +298,7 @@ executable('SampleHive',
cpp_args: [wx_cxx_flags],
link_args: [wx_libs, link_args],
include_directories : include_dirs,
dependencies: [wx, taglib, sqlite3, yaml, snd, spdlog],
dependencies: [wx, taglib, sqlite3, yaml, snd, spdlog, aubio],
install: true,
install_rpath: prefix / 'lib')

View File

@ -106,6 +106,7 @@ void cDatabase::CreateTableSamples()
"SAMPLEPACK TEXT NOT NULL,"
"TYPE TEXT NOT NULL,"
"CHANNELS INT NOT NULL,"
"BPM INT NOT NULL,"
"LENGTH INT NOT NULL,"
"SAMPLERATE INT NOT NULL,"
"BITRATE INT NOT NULL,"
@ -158,9 +159,9 @@ void cDatabase::InsertIntoSamples(const std::vector<Sample> &samples)
try
{
const auto sql = "INSERT INTO SAMPLES (FAVORITE, FILENAME, \
EXTENSION, SAMPLEPACK, TYPE, CHANNELS, LENGTH, \
EXTENSION, SAMPLEPACK, TYPE, CHANNELS, BPM, LENGTH, \
SAMPLERATE, BITRATE, PATH, TRASHED, HIVE) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
Sqlite3Statement statement(m_pDatabase, sql);
@ -192,12 +193,13 @@ void cDatabase::InsertIntoSamples(const std::vector<Sample> &samples)
throw_on_sqlite3_error(sqlite3_bind_text(statement.stmt, 4, sample_pack.c_str(), sample_pack.size(), SQLITE_STATIC));
throw_on_sqlite3_error(sqlite3_bind_text(statement.stmt, 5, type.c_str(), type.size(), SQLITE_STATIC));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 6, sample.GetChannels()));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 7, sample.GetLength()));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 8, sample.GetSampleRate()));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 9, sample.GetBitrate()));
throw_on_sqlite3_error(sqlite3_bind_text(statement.stmt, 10, path.c_str(), path.size(), SQLITE_STATIC));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 11, sample.GetTrashed()));
throw_on_sqlite3_error(sqlite3_bind_text(statement.stmt, 12, hive.c_str(), hive.size(), SQLITE_STATIC));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 7, sample.GetBPM()));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 8, sample.GetLength()));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 9, sample.GetSampleRate()));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 10, sample.GetBitrate()));
throw_on_sqlite3_error(sqlite3_bind_text(statement.stmt, 11, path.c_str(), path.size(), SQLITE_STATIC));
throw_on_sqlite3_error(sqlite3_bind_int(statement.stmt, 12, sample.GetTrashed()));
throw_on_sqlite3_error(sqlite3_bind_text(statement.stmt, 13, hive.c_str(), hive.size(), SQLITE_STATIC));
sqlite3_step(statement.stmt);
@ -591,7 +593,7 @@ wxVector<wxVector<wxVariant>> cDatabase::LoadSamplesDatabase(wxDataViewTreeCtrl
}
Sqlite3Statement statement(m_pDatabase, "SELECT FAVORITE, FILENAME, EXTENSION, SAMPLEPACK, \
TYPE, CHANNELS, LENGTH, SAMPLERATE, BITRATE, PATH, \
TYPE, CHANNELS, BPM, LENGTH, SAMPLERATE, BITRATE, PATH, \
TRASHED, HIVE FROM SAMPLES;");
int row = 0;
@ -604,14 +606,16 @@ wxVector<wxVector<wxVariant>> cDatabase::LoadSamplesDatabase(wxDataViewTreeCtrl
wxString sample_pack = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 3)));
wxString sample_type = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 4)));
int channels = sqlite3_column_int(statement.stmt, 5);
int length = sqlite3_column_int(statement.stmt, 6);
int sample_rate = sqlite3_column_int(statement.stmt, 7);
int bitrate = sqlite3_column_int(statement.stmt, 8);
wxString path = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 9)));
int trashed = sqlite3_column_int(statement.stmt, 10);
wxString hive_name = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 11)));
int bpm = sqlite3_column_int(statement.stmt, 6);
int length = sqlite3_column_int(statement.stmt, 7);
int sample_rate = sqlite3_column_int(statement.stmt, 8);
int bitrate = sqlite3_column_int(statement.stmt, 9);
wxString path = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 10)));
int trashed = sqlite3_column_int(statement.stmt, 11);
wxString hive_name = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 12)));
wxString len = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(length);
wxString _length = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(length);
wxString _bpm = SampleHive::cUtils::Get().GetBPMString(bpm);
wxVector<wxVariant> vec;
vec.reserve(12);
@ -684,7 +688,8 @@ wxVector<wxVector<wxVariant>> cDatabase::LoadSamplesDatabase(wxDataViewTreeCtrl
vec.push_back(sample_pack);
vec.push_back(sample_type);
vec.push_back(wxString::Format("%d", channels));
vec.push_back(len);
vec.push_back(_bpm);
vec.push_back(_length);
vec.push_back(wxString::Format("%d", sample_rate));
vec.push_back(wxString::Format("%d", bitrate));
vec.push_back(path);
@ -716,7 +721,7 @@ wxVector<wxVector<wxVariant>>cDatabase::FilterDatabaseBySampleName(const std::st
try
{
Sqlite3Statement statement(m_pDatabase, "SELECT FAVORITE, FILENAME, SAMPLEPACK, TYPE, \
CHANNELS, LENGTH, SAMPLERATE, BITRATE, PATH \
CHANNELS, BPM, LENGTH, SAMPLERATE, BITRATE, PATH \
FROM SAMPLES WHERE FILENAME LIKE '%' || ? || '%' ;");
throw_on_sqlite3_error(sqlite3_bind_text(statement.stmt, 1, sampleName.c_str(), sampleName.size(), SQLITE_STATIC));
@ -732,12 +737,14 @@ wxVector<wxVector<wxVariant>>cDatabase::FilterDatabaseBySampleName(const std::st
wxString sample_pack = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 2))));
wxString sample_type = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 3)));
int channels = sqlite3_column_int(statement.stmt, 4);
int length = sqlite3_column_int(statement.stmt, 5);
int sample_rate = sqlite3_column_int(statement.stmt, 6);
int bitrate = sqlite3_column_int(statement.stmt, 7);
wxString path = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 8))));
int bpm = sqlite3_column_int(statement.stmt, 5);
int length = sqlite3_column_int(statement.stmt, 6);
int sample_rate = sqlite3_column_int(statement.stmt, 7);
int bitrate = sqlite3_column_int(statement.stmt, 8);
wxString path = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 9))));
wxString len = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(length);
wxString _length = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(length);
wxString _bpm = SampleHive::cUtils::Get().GetBPMString(bpm);
wxVector<wxVariant> vec;
@ -758,7 +765,8 @@ wxVector<wxVector<wxVariant>>cDatabase::FilterDatabaseBySampleName(const std::st
vec.push_back(sample_pack);
vec.push_back(sample_type);
vec.push_back(wxString::Format("%d", channels));
vec.push_back(len);
vec.push_back(_bpm);
vec.push_back(_length);
vec.push_back(wxString::Format("%d", sample_rate));
vec.push_back(wxString::Format("%d", bitrate));
vec.push_back(path);
@ -789,7 +797,7 @@ wxVector<wxVector<wxVariant>>cDatabase::FilterDatabaseByHiveName(const std::stri
try
{
Sqlite3Statement statement(m_pDatabase, "SELECT FAVORITE, FILENAME, SAMPLEPACK, TYPE, \
CHANNELS, LENGTH, SAMPLERATE, BITRATE, PATH \
CHANNELS, BPM, LENGTH, SAMPLERATE, BITRATE, PATH \
FROM SAMPLES WHERE HIVE = ? AND FAVORITE = 1;");
throw_on_sqlite3_error(sqlite3_bind_text(statement.stmt, 1, hiveName.c_str(), hiveName.size(), SQLITE_STATIC));
@ -805,12 +813,14 @@ wxVector<wxVector<wxVariant>>cDatabase::FilterDatabaseByHiveName(const std::stri
wxString sample_pack = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 2))));
wxString sample_type = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 3)));
int channels = sqlite3_column_int(statement.stmt, 4);
int length = sqlite3_column_int(statement.stmt, 5);
int sample_rate = sqlite3_column_int(statement.stmt, 6);
int bitrate = sqlite3_column_int(statement.stmt, 7);
wxString path = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 8))));
int bpm = sqlite3_column_int(statement.stmt, 5);
int length = sqlite3_column_int(statement.stmt, 6);
int sample_rate = sqlite3_column_int(statement.stmt, 7);
int bitrate = sqlite3_column_int(statement.stmt, 8);
wxString path = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 9))));
wxString len = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(length);
wxString _length = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(length);
wxString _bpm = SampleHive::cUtils::Get().GetBPMString(bpm);
wxVector<wxVariant> vec;
@ -827,7 +837,8 @@ wxVector<wxVector<wxVariant>>cDatabase::FilterDatabaseByHiveName(const std::stri
vec.push_back(sample_pack);
vec.push_back(sample_type);
vec.push_back(wxString::Format("%d", channels));
vec.push_back(len);
vec.push_back(_bpm);
vec.push_back(_length);
vec.push_back(wxString::Format("%d", sample_rate));
vec.push_back(wxString::Format("%d", bitrate));
vec.push_back(path);
@ -969,7 +980,7 @@ wxVector<wxVector<wxVariant>>cDatabase::RestoreFromTrashByFilename(const std::st
try
{
const auto sql = "SELECT FAVORITE, FILENAME, EXTENSION, SAMPLEPACK, \
TYPE, CHANNELS, LENGTH, SAMPLERATE, BITRATE, PATH, \
TYPE, CHANNELS, BPM, LENGTH, SAMPLERATE, BITRATE, PATH, \
TRASHED, HIVE FROM SAMPLES WHERE FILENAME = ?;";
Sqlite3Statement statement(m_pDatabase, sql);
@ -984,14 +995,16 @@ wxVector<wxVector<wxVariant>>cDatabase::RestoreFromTrashByFilename(const std::st
wxString sample_pack = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 3)));
wxString sample_type = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 4)));
int channels = sqlite3_column_int(statement.stmt, 5);
int length = sqlite3_column_int(statement.stmt, 6);
int sample_rate = sqlite3_column_int(statement.stmt, 7);
int bitrate = sqlite3_column_int(statement.stmt, 8);
wxString path = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 9)));
int trashed = sqlite3_column_int(statement.stmt, 10);
wxString hive_name = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 11)));
int bpm = sqlite3_column_int(statement.stmt, 6);
int length = sqlite3_column_int(statement.stmt, 7);
int sample_rate = sqlite3_column_int(statement.stmt, 8);
int bitrate = sqlite3_column_int(statement.stmt, 9);
wxString path = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 10)));
int trashed = sqlite3_column_int(statement.stmt, 11);
wxString hive_name = std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement.stmt, 12)));
wxString len = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(length);
wxString _length = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(length);
wxString _bpm = SampleHive::cUtils::Get().GetBPMString(bpm);
wxVector<wxVariant> vec;
@ -1010,7 +1023,8 @@ wxVector<wxVector<wxVariant>>cDatabase::RestoreFromTrashByFilename(const std::st
vec.push_back(sample_pack);
vec.push_back(sample_type);
vec.push_back(wxString::Format("%d", channels));
vec.push_back(len);
vec.push_back(_bpm);
vec.push_back(_length);
vec.push_back(wxString::Format("%d", sample_rate));
vec.push_back(wxString::Format("%d", bitrate));
vec.push_back(path);

View File

@ -76,6 +76,13 @@ cListCtrl::cListCtrl(wxWindow* window)
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("BPM"),
wxDATAVIEW_CELL_INERT,
80,
wxALIGN_RIGHT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("Length"),
wxDATAVIEW_CELL_INERT,
80,
@ -679,10 +686,11 @@ void cListCtrl::OnShowLibraryColumnHeaderContextMenu(wxDataViewEvent& event)
wxDataViewColumn* SamplePackColumn = this->GetColumn(2);
wxDataViewColumn* TypeColumn = this->GetColumn(3);
wxDataViewColumn* ChannelsColumn = this->GetColumn(4);
wxDataViewColumn* LengthColumn = this->GetColumn(5);
wxDataViewColumn* SampleRateColumn = this->GetColumn(6);
wxDataViewColumn* BitrateColumn = this->GetColumn(7);
wxDataViewColumn* PathColumn = this->GetColumn(8);
wxDataViewColumn* BpmColumn = this->GetColumn(5);
wxDataViewColumn* LengthColumn = this->GetColumn(6);
wxDataViewColumn* SampleRateColumn = this->GetColumn(7);
wxDataViewColumn* BitrateColumn = this->GetColumn(8);
wxDataViewColumn* PathColumn = this->GetColumn(9);
menu.AppendCheckItem(SampleHive::ID::MN_ColumnFavorite, _("Favorites"),
_("Toggle favorites column"))->Check(FavoriteColumn->IsShown());
@ -694,6 +702,8 @@ void cListCtrl::OnShowLibraryColumnHeaderContextMenu(wxDataViewEvent& event)
_("Toggle type column"))->Check(TypeColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnChannels, _("Channels"),
_("Toggle channels column"))->Check(ChannelsColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnBPM, _("BPM"),
_("Toggle length column"))->Check(BpmColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnLength, _("Length"),
_("Toggle length column"))->Check(LengthColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnSampleRate, _("Sample Rate"),
@ -720,6 +730,9 @@ void cListCtrl::OnShowLibraryColumnHeaderContextMenu(wxDataViewEvent& event)
case SampleHive::ID::MN_ColumnChannels:
ChannelsColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnChannels));
break;
case SampleHive::ID::MN_ColumnBPM:
BpmColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnBPM));
break;
case SampleHive::ID::MN_ColumnLength:
LengthColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnLength));
break;

View File

@ -914,6 +914,13 @@ void cMainFrame::PlaySample(const std::string& filepath, const std::string& samp
if (!m_pMediaCtrl->Play())
SH_LOG_ERROR("Error! Cannot play sample.");
// ====================================================
// TODO: Remove these lines (for debugging only)
float bpm = SampleHive::cUtils::Get().GetBPM(filepath);
wxString bpm_str = SampleHive::cUtils::Get().GetBPMString(bpm);
SH_LOG_DEBUG("BPM: {}, BPM_STR: {}", bpm, bpm_str);
// ====================================================
PushStatusText(wxString::Format(_("Now playing: %s"), sample), 1);
if (!m_pTimer->IsRunning())

View File

@ -81,6 +81,8 @@ class cWaveformViewer : public wxPanel
// -------------------------------------------------------------------
std::pair<double, double> CalculateLoopPoints();
float GetBPM(const std::string& path);
public:
// -------------------------------------------------------------------
void ResetBitmapDC();

View File

@ -90,6 +90,7 @@ namespace SampleHive { namespace ID {
MN_ColumnSamplePack,
MN_ColumnType,
MN_ColumnChannels,
MN_ColumnBPM,
MN_ColumnLength,
MN_ColumnSampleRate,
MN_ColumnBitrate,

View File

@ -36,11 +36,10 @@ Sample::Sample()
///Overloaded Constructor, Creates a sample profile with supplied data. @see Set()
Sample::Sample(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length,
int sampleRate, int bitrate, const std::string& path, int trashed)
const std::string& samplePack, const std::string& type, int channels, int bpm,
int length, int sampleRate, int bitrate, const std::string& path, int trashed)
{
Set(favorite, filename, fileExtension, samplePack, type,
channels, length, sampleRate, bitrate, path, trashed);
Set(favorite, filename, fileExtension, samplePack, type, channels, bpm, length, sampleRate, bitrate, path, trashed);
}
///Clears all sample data
@ -48,6 +47,7 @@ void Sample::Clear()
{
m_Favorite = 0;
m_Channels = 0;
m_BPM = 0;
m_Length = 0;
m_SampleRate = 0;
m_Bitrate = 0;
@ -60,8 +60,8 @@ void Sample::Clear()
}
void Sample::Set(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length,
int sampleRate, int bitrate, const std::string& path, int trashed)
const std::string& samplePack, const std::string& type, int channels, int bpm,
int length, int sampleRate, int bitrate, const std::string& path, int trashed)
{
m_Favorite = favorite;
m_Filename = filename;
@ -69,6 +69,7 @@ void Sample::Set(int favorite, const std::string& filename, const std::string& f
m_SamplePack = samplePack;
m_Type = type;
m_Channels = channels;
m_BPM = bpm;
m_Length = length;
m_SampleRate = sampleRate;
m_Bitrate = bitrate;

View File

@ -40,13 +40,14 @@ class Sample
public:
Sample();
Sample(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length,
int sampleRate, int bitrate, const std::string& path, int trashed);
const std::string& samplePack, const std::string& type, int channels, int bpm,
int length, int sampleRate, int bitrate, const std::string& path, int trashed);
private:
// -------------------------------------------------------------------
int m_Favorite = 0;
int m_Channels = 0;
int m_BPM = 0;
int m_Length = 0;
int m_SampleRate = 0;
int m_Bitrate = 0;
@ -62,6 +63,7 @@ class Sample
// Getters
int GetFavorite() const { return m_Favorite; }
int GetChannels() const { return m_Channels; }
int GetBPM() const { return m_BPM; }
int GetLength() const { return m_Length; }
int GetSampleRate() const { return m_SampleRate; }
int GetBitrate() const { return m_Bitrate; }
@ -75,11 +77,12 @@ class Sample
// -------------------------------------------------------------------
// Setters
void Set(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length,
int sampleRate, int bitrate, const std::string& path, int trashed);
const std::string& samplePack, const std::string& type, int channels, int bpm,
int length, int sampleRate, int bitrate, const std::string& path, int trashed);
void SetFavorite(int favorite) { m_Favorite = favorite; }
void SetChannels(int channels) { m_Channels = channels; }
void SetBPM(int bpm) { m_BPM = bpm; }
void SetLength(int length) { m_Length = length; }
void SetSampleRate(int sampleRate) { m_SampleRate = sampleRate; }
void SetBitrate(int bitrate) { m_Bitrate = bitrate; }

View File

@ -18,6 +18,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cmath>
#include "Database/Database.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Log.hpp"
@ -32,6 +34,8 @@
#include <wx/progdlg.h>
#include <wx/string.h>
#include <aubio/aubio.h>
namespace SampleHive {
SampleHive::cUtils::FileInfo SampleHive::cUtils::GetFilenamePathAndExtension(const wxString& selected,
@ -75,6 +79,9 @@ namespace SampleHive {
std::string extension;
std::string filename;
float bpm = 0.0f;
float key = 0.0f;
//Check All Files At Once
wxArrayString sorted_files;
@ -110,6 +117,8 @@ namespace SampleHive {
filename = serializer.DeserializeShowFileExtension() ?
filename_with_extension : filename_without_extension;
bpm = GetBPM(path);
Sample sample;
sample.SetPath(path);
@ -122,11 +131,13 @@ namespace SampleHive {
sample.SetSamplePack(artist);
sample.SetChannels(tags.GetAudioInfo().channels);
sample.SetBPM(static_cast<int>(bpm));
sample.SetLength(tags.GetAudioInfo().length);
sample.SetSampleRate(tags.GetAudioInfo().sample_rate);
sample.SetBitrate(tags.GetAudioInfo().bitrate);
wxString length = CalculateAndGetISOStandardTime(sample.GetLength());
wxString bpm_str = GetBPMString(sample.GetBPM());
wxVector<wxVariant> data;
@ -140,6 +151,7 @@ namespace SampleHive {
data.push_back(sample.GetSamplePack());
data.push_back("");
data.push_back(wxString::Format("%d", sample.GetChannels()));
data.push_back(bpm_str);
data.push_back(length);
data.push_back(wxString::Format("%d", sample.GetSampleRate()));
data.push_back(wxString::Format("%d", sample.GetBitrate()));
@ -249,4 +261,72 @@ namespace SampleHive {
return iso_length;
}
wxString cUtils::GetBPMString(float bpm)
{
return wxString::Format("%d", static_cast<int>(bpm));
}
float cUtils::GetBPM(const std::string& path)
{
uint_t buff_size = 1024, hop_size = buff_size / 2, frames = 0, samplerate = 0, read = 0;
aubio_tempo_t* tempo;
fvec_t* in, *out;
aubio_source_t* source = new_aubio_source(path.c_str(), samplerate, hop_size);
float bpm = 0.0f;
if (!source)
return 0.0f;
else
{
try
{
if (samplerate == 0)
samplerate = aubio_source_get_samplerate(source);
tempo = new_aubio_tempo("default", buff_size, hop_size, samplerate);
if (!tempo)
return 0.0f;
in = new_fvec(hop_size);
out = new_fvec(1);
do
{
// put some fresh data in input vector
aubio_source_do(source, in, &read);
// execute tempo
aubio_tempo_do(tempo, in, out);
// do something with the beats
// if (out->data[0] != 0)
// {
// SH_LOG_DEBUG("Track: {} Beat at {}s, {}s, frame {}, {} bpm with confidence {}",
// path, aubio_tempo_get_last_ms(tempo), aubio_tempo_get_last_s(tempo),
// aubio_tempo_get_last(tempo), aubio_tempo_get_bpm(tempo),
// aubio_tempo_get_confidence(tempo));
// }
frames += read;
bpm = aubio_tempo_get_bpm(tempo);
}
while (read == hop_size);
// clean up memory
del_aubio_tempo(tempo);
del_fvec(in);
del_fvec(out);
del_aubio_source(source);
aubio_cleanup();
}
catch (std::exception& e)
{
SH_LOG_ERROR("Aubio Error! {}", e.what());
}
}
return bpm;
}
}

View File

@ -60,6 +60,9 @@ namespace SampleHive {
void AddSamples(wxArrayString& files, wxWindow* parent);
void OnAutoImportDir(const wxString& pathToDirectory, wxWindow* parent);
wxString CalculateAndGetISOStandardTime(wxLongLong length);
wxString GetBPMString(float bpm);
float GetBPM(const std::string& path);
private:
// -------------------------------------------------------------------