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') spdlog = spdlog_subproject.get_variable('spdlog_dep')
endif 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 # Create SampleHiveConfig.hpp based on configuration
config = configure_file(output: 'SampleHiveConfig.hpp', config = configure_file(output: 'SampleHiveConfig.hpp',
configuration: config_data,) configuration: config_data,)
@ -291,7 +298,7 @@ executable('SampleHive',
cpp_args: [wx_cxx_flags], cpp_args: [wx_cxx_flags],
link_args: [wx_libs, link_args], link_args: [wx_libs, link_args],
include_directories : include_dirs, include_directories : include_dirs,
dependencies: [wx, taglib, sqlite3, yaml, snd, spdlog], dependencies: [wx, taglib, sqlite3, yaml, snd, spdlog, aubio],
install: true, install: true,
install_rpath: prefix / 'lib') install_rpath: prefix / 'lib')

View File

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

View File

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

View File

@ -914,6 +914,13 @@ void cMainFrame::PlaySample(const std::string& filepath, const std::string& samp
if (!m_pMediaCtrl->Play()) if (!m_pMediaCtrl->Play())
SH_LOG_ERROR("Error! Cannot play sample."); 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); PushStatusText(wxString::Format(_("Now playing: %s"), sample), 1);
if (!m_pTimer->IsRunning()) if (!m_pTimer->IsRunning())

View File

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

View File

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

View File

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

View File

@ -40,13 +40,14 @@ class Sample
public: public:
Sample(); Sample();
Sample(int favorite, const std::string& filename, const std::string& fileExtension, Sample(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length, const std::string& samplePack, const std::string& type, int channels, int bpm,
int sampleRate, int bitrate, const std::string& path, int trashed); int length, int sampleRate, int bitrate, const std::string& path, int trashed);
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
int m_Favorite = 0; int m_Favorite = 0;
int m_Channels = 0; int m_Channels = 0;
int m_BPM = 0;
int m_Length = 0; int m_Length = 0;
int m_SampleRate = 0; int m_SampleRate = 0;
int m_Bitrate = 0; int m_Bitrate = 0;
@ -62,6 +63,7 @@ class Sample
// Getters // Getters
int GetFavorite() const { return m_Favorite; } int GetFavorite() const { return m_Favorite; }
int GetChannels() const { return m_Channels; } int GetChannels() const { return m_Channels; }
int GetBPM() const { return m_BPM; }
int GetLength() const { return m_Length; } int GetLength() const { return m_Length; }
int GetSampleRate() const { return m_SampleRate; } int GetSampleRate() const { return m_SampleRate; }
int GetBitrate() const { return m_Bitrate; } int GetBitrate() const { return m_Bitrate; }
@ -75,11 +77,12 @@ class Sample
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Setters // Setters
void Set(int favorite, const std::string& filename, const std::string& fileExtension, void Set(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length, const std::string& samplePack, const std::string& type, int channels, int bpm,
int sampleRate, int bitrate, const std::string& path, int trashed); int length, int sampleRate, int bitrate, const std::string& path, int trashed);
void SetFavorite(int favorite) { m_Favorite = favorite; } void SetFavorite(int favorite) { m_Favorite = favorite; }
void SetChannels(int channels) { m_Channels = channels; } void SetChannels(int channels) { m_Channels = channels; }
void SetBPM(int bpm) { m_BPM = bpm; }
void SetLength(int length) { m_Length = length; } void SetLength(int length) { m_Length = length; }
void SetSampleRate(int sampleRate) { m_SampleRate = sampleRate; } void SetSampleRate(int sampleRate) { m_SampleRate = sampleRate; }
void SetBitrate(int bitrate) { m_Bitrate = bitrate; } 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/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <cmath>
#include "Database/Database.hpp" #include "Database/Database.hpp"
#include "Utility/HiveData.hpp" #include "Utility/HiveData.hpp"
#include "Utility/Log.hpp" #include "Utility/Log.hpp"
@ -32,6 +34,8 @@
#include <wx/progdlg.h> #include <wx/progdlg.h>
#include <wx/string.h> #include <wx/string.h>
#include <aubio/aubio.h>
namespace SampleHive { namespace SampleHive {
SampleHive::cUtils::FileInfo SampleHive::cUtils::GetFilenamePathAndExtension(const wxString& selected, SampleHive::cUtils::FileInfo SampleHive::cUtils::GetFilenamePathAndExtension(const wxString& selected,
@ -75,6 +79,9 @@ namespace SampleHive {
std::string extension; std::string extension;
std::string filename; std::string filename;
float bpm = 0.0f;
float key = 0.0f;
//Check All Files At Once //Check All Files At Once
wxArrayString sorted_files; wxArrayString sorted_files;
@ -110,6 +117,8 @@ namespace SampleHive {
filename = serializer.DeserializeShowFileExtension() ? filename = serializer.DeserializeShowFileExtension() ?
filename_with_extension : filename_without_extension; filename_with_extension : filename_without_extension;
bpm = GetBPM(path);
Sample sample; Sample sample;
sample.SetPath(path); sample.SetPath(path);
@ -122,11 +131,13 @@ namespace SampleHive {
sample.SetSamplePack(artist); sample.SetSamplePack(artist);
sample.SetChannels(tags.GetAudioInfo().channels); sample.SetChannels(tags.GetAudioInfo().channels);
sample.SetBPM(static_cast<int>(bpm));
sample.SetLength(tags.GetAudioInfo().length); sample.SetLength(tags.GetAudioInfo().length);
sample.SetSampleRate(tags.GetAudioInfo().sample_rate); sample.SetSampleRate(tags.GetAudioInfo().sample_rate);
sample.SetBitrate(tags.GetAudioInfo().bitrate); sample.SetBitrate(tags.GetAudioInfo().bitrate);
wxString length = CalculateAndGetISOStandardTime(sample.GetLength()); wxString length = CalculateAndGetISOStandardTime(sample.GetLength());
wxString bpm_str = GetBPMString(sample.GetBPM());
wxVector<wxVariant> data; wxVector<wxVariant> data;
@ -140,6 +151,7 @@ namespace SampleHive {
data.push_back(sample.GetSamplePack()); data.push_back(sample.GetSamplePack());
data.push_back(""); data.push_back("");
data.push_back(wxString::Format("%d", sample.GetChannels())); data.push_back(wxString::Format("%d", sample.GetChannels()));
data.push_back(bpm_str);
data.push_back(length); data.push_back(length);
data.push_back(wxString::Format("%d", sample.GetSampleRate())); data.push_back(wxString::Format("%d", sample.GetSampleRate()));
data.push_back(wxString::Format("%d", sample.GetBitrate())); data.push_back(wxString::Format("%d", sample.GetBitrate()));
@ -249,4 +261,72 @@ namespace SampleHive {
return iso_length; 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 AddSamples(wxArrayString& files, wxWindow* parent);
void OnAutoImportDir(const wxString& pathToDirectory, wxWindow* parent); void OnAutoImportDir(const wxString& pathToDirectory, wxWindow* parent);
wxString CalculateAndGetISOStandardTime(wxLongLong length); wxString CalculateAndGetISOStandardTime(wxLongLong length);
wxString GetBPMString(float bpm);
float GetBPM(const std::string& path);
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------