Merge branch 'experimental-draw-waveform' into 'testing'
Show waveform for the selected sample. See merge request samplehive/sample-hive!9
|
|
@ -48,18 +48,18 @@ SampleHive let's you manage your audio samples in a nice and simple way, just ad
|
|||
On Arch based distributions,
|
||||
|
||||
#+begin_example
|
||||
sudo pacman -S wxgtk3 wxsvg sqlite taglib yaml-cpp
|
||||
sudo pacman -S wxgtk3 wxsvg sqlite taglib yaml-cpp libsndfile
|
||||
#+end_example
|
||||
|
||||
On Debian, Ubuntu and distributions based the on two,
|
||||
|
||||
#+begin_example
|
||||
sudo apt install libwxbase3.0-dev libwxgtk-media3.0-gtk3-dev libwxgtk3.0-gtk3-dev wx3.0-headers libsqlite3-dev libyaml-cpp-dev libtagc0-dev libtag1-dev libtagc0 libexif-dev libpango1.0-dev
|
||||
sudo apt install libwxbase3.0-dev libwxgtk-media3.0-gtk3-dev libwxgtk3.0-gtk3-dev wx3.0-headers libsqlite3-dev libyaml-cpp-dev libtagc0-dev libtag1-dev libtagc0 libexif-dev libpango1.0-dev libsndfile1-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev
|
||||
#+end_example
|
||||
|
||||
You might also need to install =git=, =meson= and =g++= as well, if you don't already have them installed in order to build SampleHive.
|
||||
You might also need to install =git=, =cmake=, =meson= and =g++= as well, if you don't already have them installed in order to build SampleHive.
|
||||
|
||||
/NOTE:/ On Debian and Debian based distributions you also have to install =libwxgtk-media3.0-dev=
|
||||
*NOTE:* On Debian and Debian based distributions you also have to install =libwxgtk-media3.0-dev=
|
||||
|
||||
** How to build SampleHive?
|
||||
:PROPERTIES:
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 244 B |
|
After Width: | Height: | Size: 280 B |
|
After Width: | Height: | Size: 415 B |
|
After Width: | Height: | Size: 428 B |
|
After Width: | Height: | Size: 455 B |
|
After Width: | Height: | Size: 445 B |
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 263 B |
|
After Width: | Height: | Size: 267 B |
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 176 KiB |
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 95.13" style="enable-background:new 0 0 122.88 95.13" xml:space="preserve"><g><path d="M100.95,23.32c0-2.09,1.69-3.78,3.78-3.78c2.09,0,3.78,1.69,3.78,3.78v48.5c0,2.09-1.69,3.78-3.78,3.78 c-2.09,0-3.78-1.69-3.78-3.78V23.32L100.95,23.32z M0,31.82c0-2.09,1.69-3.78,3.78-3.78c2.09,0,3.78,1.69,3.78,3.78v31.49 c0,2.09-1.69,3.78-3.78,3.78C1.69,67.09,0,65.4,0,63.31V31.82L0,31.82z M14.42,23.32c0-2.09,1.69-3.78,3.78-3.78 c2.09,0,3.78,1.69,3.78,3.78v48.5c0,2.09-1.69,3.78-3.78,3.78c-2.09,0-3.78-1.69-3.78-3.78V23.32L14.42,23.32z M28.9,13.9 c0-2.08,1.67-3.76,3.72-3.76c2.06,0,3.72,1.68,3.72,3.76v67.34c0,2.08-1.67,3.76-3.72,3.76c-2.06,0-3.72-1.68-3.72-3.76V13.9 L28.9,13.9z M43.26,3.78c0-2.09,1.69-3.78,3.78-3.78c2.09,0,3.78,1.69,3.78,3.78v87.57c0,2.09-1.69,3.78-3.78,3.78 c-2.09,0-3.78-1.69-3.78-3.78V3.78L43.26,3.78z M86.53,31.82c0-2.09,1.69-3.78,3.78-3.78c2.09,0,3.78,1.69,3.78,3.78v31.49 c0,2.09-1.69,3.78-3.78,3.78c-2.09,0-3.78-1.69-3.78-3.78V31.82L86.53,31.82z M72.11,23.32c0-2.09,1.69-3.78,3.78-3.78 c2.09,0,3.78,1.69,3.78,3.78v48.5c0,2.09-1.69,3.78-3.78,3.78c-2.09,0-3.78-1.69-3.78-3.78V23.32L72.11,23.32z M57.74,13.9 c0-2.08,1.67-3.76,3.72-3.76c2.06,0,3.72,1.68,3.72,3.76v67.34c0,2.08-1.67,3.76-3.72,3.76c-2.06,0-3.72-1.68-3.72-3.76V13.9 L57.74,13.9z M115.43,13.9c0-2.08,1.67-3.76,3.72-3.76c2.06,0,3.72,1.68,3.72,3.76v67.34c0,2.08-1.67,3.76-3.72,3.76 c-2.06,0-3.72-1.68-3.72-3.76V13.9L115.43,13.9z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
146
meson.build
|
|
@ -17,13 +17,15 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
project('SampleHive', 'cpp',
|
||||
project('SampleHive',
|
||||
'cpp',
|
||||
version : 'v0.8.4_alpha.1',
|
||||
license : 'GPL v3',
|
||||
default_options : ['warning_level=1',
|
||||
'cpp_std=c++11'])
|
||||
|
||||
meson_src_root = meson.current_source_dir()
|
||||
meson_build_root = meson.current_build_dir()
|
||||
|
||||
# Save important directories
|
||||
prefix = get_option('prefix')
|
||||
|
|
@ -40,11 +42,39 @@ config_data.set_quoted('LIBDIR', libdir)
|
|||
config_data.set_quoted('DATADIR', datadir)
|
||||
config_data.set_quoted('SAMPLEHIVE_DATADIR', samplehive_datadir)
|
||||
|
||||
# Create samplehive-config.h based on configuration
|
||||
config_h = configure_file(
|
||||
output: 'SampleHiveConfig.hpp',
|
||||
configuration: config_data,
|
||||
)
|
||||
# Import CMake
|
||||
cmake = import('cmake')
|
||||
|
||||
wx_opts = cmake.subproject_options()
|
||||
wx_opts.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON',
|
||||
'CMAKE_INSTALL_PREFIX': prefix,
|
||||
'CMAKE_BUILD_TYPE': 'Release',
|
||||
'CMAKE_CXX_COMPILER': 'g++',
|
||||
'wxBUILD_SHARED': 'ON',
|
||||
'wxBUILD_TESTS': 'OFF',
|
||||
'wxBUILD_SAMPLES': 'OFF',
|
||||
'wxBUILD_DEMOS': 'OFF',
|
||||
'wxBUILD_COMPATIBILITY': '3.0',
|
||||
'wxUSE_UNICODE': 'ON',
|
||||
'wxUSE_AUI': 'OFF',
|
||||
'wxUSE_XML': 'OFF',
|
||||
'wxUSE_XRC': 'ON',
|
||||
'wxUSE_HTML': 'ON',
|
||||
'wxUSE_QA': 'ON',
|
||||
'wxUSE_PROPGRID': 'OFF',
|
||||
'wxUSE_RIBBON': 'OFF',
|
||||
'wxUSE_MDI': 'OFF',
|
||||
'wxUSE_MDI_ARCHITECTURE': 'OFF',
|
||||
'wxUSE_RICHTEXT': 'OFF',
|
||||
'wxUSE_WEBVIEW': 'OFF',
|
||||
'wxUSE_LIBSDL': 'OFF',
|
||||
'wxUSE_MEDIACTRL': 'ON'})
|
||||
|
||||
taglib_opts = cmake.subproject_options()
|
||||
taglib_opts.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON',
|
||||
'CMAKE_INSTALL_PREFIX': prefix,
|
||||
'CMAKE_BUILD_TYPE': 'Release',
|
||||
'CMAKE_CXX_COMPILER': 'g++'})
|
||||
|
||||
# Source files to be compiled
|
||||
src = [
|
||||
|
|
@ -57,34 +87,88 @@ src = [
|
|||
'src/Sample.cpp',
|
||||
'src/Serialize.cpp',
|
||||
'src/Tags.cpp',
|
||||
'src/WaveformViewer.cpp',
|
||||
'src/SH_Event.cpp',
|
||||
|
||||
]
|
||||
|
||||
wxconfig = find_program(['wx-config-gtk3', 'wx-config'])
|
||||
wx_modules = ['media', 'std']
|
||||
wx_cxx_flags = []
|
||||
wx_libs = []
|
||||
|
||||
foreach module : wx_modules
|
||||
wx_cxx_flags += run_command(wxconfig, '--cxxflags', module).stdout().strip().split()
|
||||
wx_libs += run_command(wxconfig, '--libs', module).stdout().strip().split()
|
||||
endforeach
|
||||
|
||||
# Dependencies
|
||||
wx = dependency('wxwidgets', version: '>=3.0.4')
|
||||
taglib = dependency('taglib', version: '>=1.11')
|
||||
sqlite3 = dependency('sqlite3')
|
||||
yaml = dependency('yaml-cpp')
|
||||
wx = dependency('wxwidgets', version: '>=3.1.5', required: false)
|
||||
|
||||
install_subdir(
|
||||
'assets',
|
||||
install_dir: samplehive_datadir,
|
||||
exclude_directories: 'screenshots'
|
||||
)
|
||||
wx_found = false
|
||||
|
||||
executable('SampleHive',
|
||||
sources: src,
|
||||
cpp_args: [wx_cxx_flags],
|
||||
link_args: [wx_libs],
|
||||
dependencies: [wx, taglib, sqlite3, yaml],
|
||||
install: true)
|
||||
if not wx.found()
|
||||
wx_found = false
|
||||
|
||||
wx_subproject = cmake.subproject('wxwidgets', options: wx_opts)
|
||||
wx_base = wx_subproject.dependency('wxbase')
|
||||
wx_core = wx_subproject.dependency('wxcore')
|
||||
wx_media = wx_subproject.dependency('wxmedia')
|
||||
wx = [wx_core, wx_base, wx_media]
|
||||
else
|
||||
wx_found = true
|
||||
|
||||
wxconfig = find_program(['wx-config-gtk3', 'wx-config'])
|
||||
wx_modules = ['media', 'std']
|
||||
wx_cxx_flags = []
|
||||
wx_libs = []
|
||||
|
||||
foreach module : wx_modules
|
||||
wx_cxx_flags += run_command(wxconfig, '--cxxflags', module).stdout().strip().split()
|
||||
wx_libs += run_command(wxconfig, '--libs', module).stdout().strip().split()
|
||||
endforeach
|
||||
endif
|
||||
|
||||
taglib = dependency('taglib', version: '>=1.12', required: false)
|
||||
|
||||
if not taglib.found()
|
||||
taglib_subproject = cmake.subproject('taglib', options: taglib_opts)
|
||||
taglib = taglib_subproject.dependency('tag')
|
||||
else
|
||||
config_data.set('USE_SYSTEM_INCLUDE_PATH', 1)
|
||||
endif
|
||||
|
||||
sqlite3 = dependency('sqlite3', required: true)
|
||||
yaml = dependency('yaml-cpp', required: true)
|
||||
snd = dependency('sndfile', required: true)
|
||||
|
||||
# Create samplehive-config.h based on configuration
|
||||
config_h = configure_file(output: 'SampleHiveConfig.hpp',
|
||||
configuration: config_data,)
|
||||
|
||||
install_subdir('assets',
|
||||
install_dir: samplehive_datadir,
|
||||
exclude_directories: 'screenshots')
|
||||
|
||||
if wx_found
|
||||
executable('SampleHive',
|
||||
sources: src,
|
||||
cpp_args: [wx_cxx_flags],
|
||||
link_args: [wx_libs],
|
||||
dependencies: [wx, taglib, sqlite3, yaml, snd],
|
||||
install: true,
|
||||
install_rpath: prefix / 'lib')
|
||||
else
|
||||
executable('SampleHive',
|
||||
sources: src,
|
||||
dependencies: [wx, taglib, sqlite3, yaml, snd],
|
||||
install: true,
|
||||
install_rpath: prefix / 'lib')
|
||||
endif
|
||||
|
||||
summary(
|
||||
{
|
||||
'Debug': get_option('debug'),
|
||||
'Optimization': get_option('optimization'),
|
||||
},
|
||||
section: 'General')
|
||||
|
||||
summary(
|
||||
{
|
||||
'prefix': prefix,
|
||||
'bindir': bindir,
|
||||
'libdir': libdir,
|
||||
'datadir': datadir,
|
||||
'samplehive_datadir': samplehive_datadir,
|
||||
},
|
||||
section: 'Directories')
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ bool App::OnCmdLineParsed(wxCmdLineParser& parser)
|
|||
|
||||
if (parser.Found("version"))
|
||||
{
|
||||
std::cout << "SampleHive v0.8.4_alpha.1" << std::endl;
|
||||
std::cout << "SampleHive v0.9.0_alpha.1" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ enum ControlIDs
|
|||
BC_Settings,
|
||||
BC_Loop,
|
||||
BC_Stop,
|
||||
BC_LoopABButton,
|
||||
BC_Mute,
|
||||
BC_Autoplay,
|
||||
BC_Volume,
|
||||
|
|
@ -59,6 +60,7 @@ enum ControlIDs
|
|||
SD_FontType,
|
||||
SD_FontSize,
|
||||
SD_FontBrowseButton,
|
||||
SD_WaveformColourPickerCtrl,
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// App Menu items
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include <wx/variant.h>
|
||||
|
||||
#include "Database.hpp"
|
||||
#include "SettingsDialog.hpp"
|
||||
|
||||
Database::Database(wxInfoBar& infoBar)
|
||||
: m_InfoBar(infoBar)
|
||||
|
|
@ -383,7 +382,7 @@ void Database::UpdateHive(const std::string& dbPath, const std::string& hiveOldN
|
|||
}
|
||||
else
|
||||
{
|
||||
wxLogInfo("Hive updated successfully. %s", m_ErrMsg);
|
||||
wxLogDebug("Hive updated successfully. %s", m_ErrMsg);
|
||||
}
|
||||
|
||||
sqlite3_close(m_Database);
|
||||
|
|
@ -566,7 +565,7 @@ std::string Database::GetSampleType(const std::string& dbPath, const std::string
|
|||
|
||||
if (sqlite3_step(m_Stmt) == SQLITE_ROW)
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
|
||||
type = std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 0)));
|
||||
}
|
||||
|
|
@ -582,7 +581,7 @@ std::string Database::GetSampleType(const std::string& dbPath, const std::string
|
|||
}
|
||||
else
|
||||
{
|
||||
wxLogInfo("Selected data from table successfully.");
|
||||
wxLogDebug("Selected data from table successfully.");
|
||||
}
|
||||
|
||||
sqlite3_close(m_Database);
|
||||
|
|
@ -611,7 +610,7 @@ int Database::GetFavoriteColumnValueByFilename(const std::string& dbPath, const
|
|||
|
||||
if (sqlite3_step(m_Stmt) == SQLITE_ROW)
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
value = sqlite3_column_int(m_Stmt, 0);
|
||||
}
|
||||
|
||||
|
|
@ -626,7 +625,7 @@ int Database::GetFavoriteColumnValueByFilename(const std::string& dbPath, const
|
|||
}
|
||||
else
|
||||
{
|
||||
wxLogInfo("Selected data from table successfully.");
|
||||
wxLogDebug("Selected data from table successfully.");
|
||||
}
|
||||
|
||||
sqlite3_close(m_Database);
|
||||
|
|
@ -655,7 +654,7 @@ std::string Database::GetHiveByFilename(const std::string& dbPath, const std::st
|
|||
|
||||
if (sqlite3_step(m_Stmt) == SQLITE_ROW)
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
|
||||
hive = std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 0)));
|
||||
}
|
||||
|
|
@ -671,7 +670,7 @@ std::string Database::GetHiveByFilename(const std::string& dbPath, const std::st
|
|||
}
|
||||
else
|
||||
{
|
||||
wxLogInfo("Selected data from table successfully.");
|
||||
wxLogDebug("Selected data from table successfully.");
|
||||
}
|
||||
|
||||
sqlite3_close(m_Database);
|
||||
|
|
@ -778,7 +777,7 @@ std::string Database::GetSamplePathByFilename(const std::string& dbPath, const s
|
|||
|
||||
if (sqlite3_step(m_Stmt) == SQLITE_ROW)
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
path = std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 0)));
|
||||
}
|
||||
|
||||
|
|
@ -793,7 +792,7 @@ std::string Database::GetSamplePathByFilename(const std::string& dbPath, const s
|
|||
}
|
||||
else
|
||||
{
|
||||
wxLogInfo("Selected data from table successfully.");
|
||||
wxLogDebug("Selected data from table successfully.");
|
||||
}
|
||||
|
||||
sqlite3_close(m_Database);
|
||||
|
|
@ -822,7 +821,7 @@ std::string Database::GetSampleFileExtension(const std::string& dbPath, const st
|
|||
|
||||
if (sqlite3_step(m_Stmt) == SQLITE_ROW)
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
extension = std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 0)));
|
||||
}
|
||||
|
||||
|
|
@ -837,7 +836,7 @@ std::string Database::GetSampleFileExtension(const std::string& dbPath, const st
|
|||
}
|
||||
else
|
||||
{
|
||||
wxLogInfo("Selected data from table successfully.");
|
||||
wxLogDebug("Selected data from table successfully.");
|
||||
}
|
||||
|
||||
sqlite3_close(m_Database);
|
||||
|
|
@ -1039,7 +1038,7 @@ Database::FilterDatabaseBySampleName(const std::string& dbPath, wxVector<wxVecto
|
|||
|
||||
while (SQLITE_ROW == sqlite3_step(m_Stmt))
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
int favorite = sqlite3_column_int(m_Stmt, 0);
|
||||
wxString filename = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 1))));
|
||||
wxString sample_pack = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 2))));
|
||||
|
|
@ -1141,7 +1140,7 @@ Database::FilterDatabaseByHiveName(const std::string& dbPath, wxVector<wxVector<
|
|||
|
||||
while (SQLITE_ROW == sqlite3_step(m_Stmt))
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
int favorite = sqlite3_column_int(m_Stmt, 0);
|
||||
wxString filename = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 1))));
|
||||
wxString sample_pack = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 2))));
|
||||
|
|
@ -1234,7 +1233,7 @@ void Database::LoadHivesDatabase(const std::string& dbPath, wxDataViewTreeCtrl&
|
|||
{
|
||||
while (SQLITE_ROW == sqlite3_step(m_Stmt))
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
wxString hive = wxString(std::string(reinterpret_cast<const char*>(sqlite3_column_text(m_Stmt, 0))));
|
||||
|
||||
treeCtrl.AppendContainer(wxDataViewItem(wxNullPtr), hive);
|
||||
|
|
@ -1314,7 +1313,7 @@ bool Database::IsTrashed(const std::string& dbPath, const std::string& filename)
|
|||
|
||||
if (sqlite3_step(m_Stmt) == SQLITE_ROW)
|
||||
{
|
||||
wxLogInfo("Record found, fetching..");
|
||||
wxLogDebug("Record found, fetching..");
|
||||
|
||||
if (sqlite3_column_int(m_Stmt, 0) == 1)
|
||||
return true;
|
||||
|
|
@ -1331,7 +1330,7 @@ bool Database::IsTrashed(const std::string& dbPath, const std::string& filename)
|
|||
}
|
||||
else
|
||||
{
|
||||
wxLogInfo("Selected data from table successfully.");
|
||||
wxLogDebug("Selected data from table successfully.");
|
||||
}
|
||||
|
||||
sqlite3_close(m_Database);
|
||||
|
|
|
|||
|
|
@ -20,8 +20,10 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <ios>
|
||||
|
||||
#include <wx/aboutdlg.h>
|
||||
#include <wx/accel.h>
|
||||
|
|
@ -48,14 +50,12 @@
|
|||
#include <wx/msgdlg.h>
|
||||
#include <wx/object.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/stringimpl.h>
|
||||
#include <wx/textdlg.h>
|
||||
#include <wx/valtext.h>
|
||||
#include <wx/variant.h>
|
||||
#include <wx/vector.h>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/unix/stdpaths.h>
|
||||
|
||||
#include "MainFrame.hpp"
|
||||
#include "ControlID_Enums.hpp"
|
||||
|
|
@ -76,9 +76,18 @@
|
|||
#define ICON_HIVE_256px SAMPLEHIVE_DATADIR "/assets/icons/icon-hive_256x256.png"
|
||||
#define ICON_STAR_FILLED_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-star_filled_16x16.png"
|
||||
#define ICON_STAR_EMPTY_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-star_empty_16x16.png"
|
||||
#define WAVEFORM_SVG SAMPLEHIVE_DATADIR "/assets/waveform.svg"
|
||||
#define APP_CONFIG_DIR wxStandardPaths::Get().GetUserConfigDir() + "/.config/SampleHive"
|
||||
#define APP_DATA_DIR wxStandardPaths::Get().GetDocumentsDir() + "/.local/share/SampleHive"
|
||||
#define ICON_PLAY_DARK_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-play-dark_16x16.png"
|
||||
#define ICON_STOP_DARK_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-stop-dark_16x16.png"
|
||||
#define ICON_AB_DARK_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-ab-dark_16x16.png"
|
||||
#define ICON_LOOP_DARK_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-loop-dark_16x16.png"
|
||||
#define ICON_MUTE_DARK_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-mute-dark_16x16.png"
|
||||
#define ICON_PLAY_LIGHT_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-play-light_16x16.png"
|
||||
#define ICON_STOP_LIGHT_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-stop-light_16x16.png"
|
||||
#define ICON_AB_LIGHT_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-ab-light_16x16.png"
|
||||
#define ICON_LOOP_LIGHT_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-loop-light_16x16.png"
|
||||
#define ICON_MUTE_LIGHT_16px SAMPLEHIVE_DATADIR "/assets/icons/icon-mute-light_16x16.png"
|
||||
#define APP_CONFIG_DIR wxGetHomeDir() + "/.config/SampleHive"
|
||||
#define APP_DATA_DIR wxGetHomeDir() + "/.local/share/SampleHive"
|
||||
#define CONFIG_FILEPATH APP_CONFIG_DIR + "/config.yaml"
|
||||
#define DATABASE_FILEPATH APP_DATA_DIR "/sample.hive"
|
||||
|
||||
|
|
@ -196,7 +205,7 @@ MainFrame::MainFrame()
|
|||
_("All files|*|Ogg files (*.ogg)|*.ogg|Wav files (*.wav)|*.wav|"
|
||||
"Flac files (*.flac)|*.flac"), 0);
|
||||
|
||||
wxString path = wxStandardPaths::Get().GetDocumentsDir();
|
||||
wxString path = wxGetHomeDir();
|
||||
m_DirCtrl->SetPath(path);
|
||||
|
||||
// This panel will hold 2nd page of wxNotebook
|
||||
|
|
@ -244,32 +253,58 @@ MainFrame::MainFrame()
|
|||
m_TopSplitter->SplitHorizontally(m_TopPanel, m_BottomSplitter);
|
||||
m_BottomSplitter->SplitVertically(m_BottomLeftPanel, m_BottomRightPanel);
|
||||
|
||||
m_TopControlsPanel = new wxPanel(m_TopPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER);
|
||||
|
||||
// Looping region controls
|
||||
if (m_Theme.IsDark())
|
||||
m_LoopABButton = new wxBitmapToggleButton(m_TopControlsPanel, BC_LoopABButton, static_cast<wxString>(ICON_AB_LIGHT_16px), wxDefaultPosition, wxDefaultSize, 0);
|
||||
else
|
||||
m_LoopABButton = new wxBitmapToggleButton(m_TopControlsPanel, BC_LoopABButton, static_cast<wxString>(ICON_AB_DARK_16px), wxDefaultPosition, wxDefaultSize, 0);
|
||||
|
||||
m_LoopABButton->SetToolTip(_("Loop selected region"));
|
||||
|
||||
// Initializing browser controls on top panel.
|
||||
m_AutoPlayCheck = new wxCheckBox(m_TopPanel, BC_Autoplay, _("Autoplay"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
|
||||
m_AutoPlayCheck = new wxCheckBox(m_TopControlsPanel, BC_Autoplay, _("Autoplay"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
|
||||
m_AutoPlayCheck->SetToolTip(_("Autoplay"));
|
||||
m_VolumeSlider = new wxSlider(m_TopPanel, BC_Volume, 100, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL);
|
||||
m_VolumeSlider = new wxSlider(m_TopControlsPanel, BC_Volume, 100, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL);
|
||||
m_VolumeSlider->SetToolTip(_("Volume"));
|
||||
m_VolumeSlider->SetMinSize(wxSize(120, -1));
|
||||
m_VolumeSlider->SetMaxSize(wxSize(120, -1));
|
||||
m_SamplePosition = new wxStaticText(m_TopPanel, BC_SamplePosition, "--:--/--:--",
|
||||
m_SamplePosition = new wxStaticText(m_TopControlsPanel, BC_SamplePosition, "--:--/--:--",
|
||||
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
|
||||
|
||||
// Temporary widget to show a waveform sample image
|
||||
// TODO: Replace with actual waveform display
|
||||
m_WaveformViewer = new wxStaticBitmap(m_TopPanel, wxID_ANY, wxBitmap(WAVEFORM_SVG));
|
||||
|
||||
// Initialize browser control buttons
|
||||
m_PlayButton = new wxButton(m_TopPanel, BC_Play, _("Play"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
if (m_Theme.IsDark())
|
||||
{
|
||||
m_PlayButton = new wxBitmapButton(m_TopControlsPanel, BC_Play, static_cast<wxString>(ICON_PLAY_LIGHT_16px),
|
||||
wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_LoopButton = new wxBitmapToggleButton(m_TopControlsPanel, BC_Loop, static_cast<wxString>(ICON_LOOP_LIGHT_16px),
|
||||
wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_StopButton = new wxBitmapButton(m_TopControlsPanel, BC_Stop, static_cast<wxString>(ICON_STOP_LIGHT_16px),
|
||||
wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_MuteButton = new wxBitmapToggleButton(m_TopControlsPanel, BC_Mute, static_cast<wxString>(ICON_MUTE_LIGHT_16px),
|
||||
wxDefaultPosition, wxDefaultSize, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PlayButton = new wxBitmapButton(m_TopControlsPanel, BC_Play, static_cast<wxString>(ICON_PLAY_DARK_16px),
|
||||
wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_LoopButton = new wxBitmapToggleButton(m_TopControlsPanel, BC_Loop, static_cast<wxString>(ICON_LOOP_DARK_16px),
|
||||
wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_StopButton = new wxBitmapButton(m_TopControlsPanel, BC_Stop, static_cast<wxString>(ICON_STOP_DARK_16px),
|
||||
wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_MuteButton = new wxBitmapToggleButton(m_TopControlsPanel, BC_Mute, static_cast<wxString>(ICON_MUTE_DARK_16px),
|
||||
wxDefaultPosition, wxDefaultSize, 0);
|
||||
}
|
||||
|
||||
m_PlayButton->SetToolTip(_("Play"));
|
||||
m_LoopButton = new wxToggleButton(m_TopPanel, BC_Loop, _("Loop"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_LoopButton->SetToolTip(_("Loop"));
|
||||
m_StopButton = new wxButton(m_TopPanel, BC_Stop, _("Stop"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_StopButton->SetToolTip(_("Stop"));
|
||||
m_SettingsButton = new wxButton(m_TopPanel, BC_Settings, _("Settings"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_SettingsButton->SetToolTip(_("Settings"));
|
||||
m_MuteButton = new wxToggleButton(m_TopPanel, BC_Mute, _("Mute"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_MuteButton->SetToolTip(_("Mute"));
|
||||
|
||||
m_SettingsButton = new wxButton(m_TopControlsPanel, BC_Settings, _("Settings"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_SettingsButton->SetToolTip(_("Settings"));
|
||||
|
||||
// Initializing wxSearchCtrl on bottom panel.
|
||||
m_SearchBox = new wxSearchCtrl(m_BottomRightPanel, BC_Search, _("Search for samples.."), wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||
|
|
@ -364,6 +399,9 @@ MainFrame::MainFrame()
|
|||
// Intializing wxTimer
|
||||
m_Timer = new wxTimer(this);
|
||||
|
||||
m_TopWaveformPanel = new WaveformViewer(this, m_TopPanel, *m_Library, *m_MediaCtrl, *m_InfoBar,
|
||||
m_ConfigFilepath, m_DatabaseFilepath);
|
||||
|
||||
// Binding events.
|
||||
Bind(wxEVT_MENU, &MainFrame::OnSelectAddFile, this, MN_AddFile);
|
||||
Bind(wxEVT_MENU, &MainFrame::OnSelectAddDirectory, this, MN_AddDirectory);
|
||||
|
|
@ -412,26 +450,28 @@ MainFrame::MainFrame()
|
|||
Bind(wxEVT_BUTTON, &MainFrame::OnClickAddHive, this, BC_HiveAdd);
|
||||
Bind(wxEVT_BUTTON, &MainFrame::OnClickRemoveHive, this, BC_HiveRemove);
|
||||
|
||||
Bind(SampleHive::SH_EVT_LOOP_POINTS_UPDATED, &MainFrame::OnRecieveLoopPoints, this);
|
||||
Bind(SampleHive::SH_EVT_STATUSBAR_MESSAGE_UPDATED, &MainFrame::OnRecieveStatusBarStatus, this);
|
||||
|
||||
// Adding widgets to their sizers
|
||||
m_MainSizer->Add(m_MainPanel, 1, wxALL | wxEXPAND, 0);
|
||||
|
||||
m_TopSizer->Add(m_TopSplitter, 1, wxALL | wxEXPAND, 0);
|
||||
|
||||
m_BrowserControlSizer->Add(m_PlayButton, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_LoopButton, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_StopButton, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_SettingsButton, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_PlayButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_StopButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_LoopButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_LoopABButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_SettingsButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(0,0,1, wxALL | wxEXPAND, 0);
|
||||
m_BrowserControlSizer->Add(m_SamplePosition, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_SamplePosition, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(30,0,0, wxALL | wxEXPAND, 0);
|
||||
m_BrowserControlSizer->Add(m_MuteButton, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_VolumeSlider, 1, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_AutoPlayCheck, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_MuteButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_VolumeSlider, 1, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_BrowserControlSizer->Add(m_AutoPlayCheck, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_WaveformDisplaySizer->Add(m_WaveformViewer, 1, wxALL | wxEXPAND, 2);
|
||||
|
||||
m_TopPanelMainSizer->Add(m_WaveformDisplaySizer, 1, wxALL | wxEXPAND, 2);
|
||||
m_TopPanelMainSizer->Add(m_BrowserControlSizer, 0, wxALL | wxEXPAND, 2);
|
||||
m_TopPanelMainSizer->Add(m_TopWaveformPanel, 1, wxALL | wxEXPAND, 2);
|
||||
m_TopPanelMainSizer->Add(m_TopControlsPanel, 0, wxALL | wxEXPAND, 2);
|
||||
|
||||
m_BottomLeftPanelMainSizer->Add(m_Notebook, 1, wxALL | wxEXPAND, 0);
|
||||
|
||||
|
|
@ -464,6 +504,16 @@ MainFrame::MainFrame()
|
|||
m_TopSizer->SetSizeHints(m_MainPanel);
|
||||
m_TopSizer->Layout();
|
||||
|
||||
m_TopControlsPanel->SetSizer(m_BrowserControlSizer);
|
||||
m_BrowserControlSizer->Fit(m_TopControlsPanel);
|
||||
m_BrowserControlSizer->SetSizeHints(m_TopControlsPanel);
|
||||
m_BrowserControlSizer->Layout();
|
||||
|
||||
m_TopWaveformPanel->SetSizer(m_WaveformDisplaySizer);
|
||||
m_WaveformDisplaySizer->Fit(m_TopWaveformPanel);
|
||||
m_WaveformDisplaySizer->SetSizeHints(m_TopWaveformPanel);
|
||||
m_WaveformDisplaySizer->Layout();
|
||||
|
||||
// Sizer for TopPanel
|
||||
m_TopPanel->SetSizer(m_TopPanelMainSizer);
|
||||
m_TopPanelMainSizer->Fit(m_TopPanel);
|
||||
|
|
@ -518,6 +568,10 @@ void MainFrame::OnClickSettings(wxCommandEvent& event)
|
|||
OnAutoImportDir(settings->GetImportDirPath());
|
||||
RefreshDatabase();
|
||||
}
|
||||
if (settings->IsWaveformColourChanged())
|
||||
{
|
||||
m_TopWaveformPanel->ResetDC();
|
||||
}
|
||||
break;
|
||||
case wxID_CANCEL:
|
||||
break;
|
||||
|
|
@ -885,7 +939,8 @@ void MainFrame::OnClickPlay(wxCommandEvent& event)
|
|||
|
||||
int selected_row = m_Library->GetSelectedRow();
|
||||
|
||||
if (selected_row < 0) return;
|
||||
if (selected_row < 0)
|
||||
return;
|
||||
|
||||
wxString selection = m_Library->GetTextValue(selected_row, 1);
|
||||
|
||||
|
|
@ -901,25 +956,18 @@ void MainFrame::OnClickPlay(wxCommandEvent& event)
|
|||
|
||||
wxString sample_path = GetFilenamePathAndExtension(selection).Path;
|
||||
|
||||
m_MediaCtrl->Load(sample_path);
|
||||
|
||||
PushStatusText(wxString::Format(_("Now playing: %s"), selection), 1);
|
||||
|
||||
m_MediaCtrl->Play();
|
||||
|
||||
m_Timer->Start(100, wxTIMER_CONTINUOUS);
|
||||
if (bLoopPointsSet && m_LoopABButton->GetValue())
|
||||
PlaySample(sample_path.ToStdString(), selection.ToStdString(), true, m_LoopA.ToDouble(), wxFromStart);
|
||||
else
|
||||
PlaySample(sample_path.ToStdString(), selection.ToStdString());
|
||||
}
|
||||
|
||||
void MainFrame::OnClickLoop(wxCommandEvent& event)
|
||||
{
|
||||
if (m_LoopButton->GetValue())
|
||||
{
|
||||
bLoop = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bLoop = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MainFrame::OnClickStop(wxCommandEvent& event)
|
||||
|
|
@ -927,7 +975,9 @@ void MainFrame::OnClickStop(wxCommandEvent& event)
|
|||
m_MediaCtrl->Stop();
|
||||
bStopped = true;
|
||||
|
||||
m_Timer->Stop();
|
||||
if (m_Timer->IsRunning())
|
||||
m_Timer->Stop();
|
||||
|
||||
m_SamplePosition->SetLabel("--:--/--:--");
|
||||
|
||||
this->SetStatusText(_("Stopped"), 1);
|
||||
|
|
@ -957,14 +1007,16 @@ void MainFrame::OnMediaFinished(wxMediaEvent& event)
|
|||
msgDialog.ShowModal();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_MediaCtrl->Play();
|
||||
m_Timer->Start(100, wxTIMER_CONTINUOUS);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Timer->Stop();
|
||||
if (m_Timer->IsRunning())
|
||||
{
|
||||
m_Timer->Stop();
|
||||
wxLogDebug("TIMER STOPPED");
|
||||
}
|
||||
|
||||
m_SamplePosition->SetLabel("--:--/--:--");
|
||||
PopStatusText(1);
|
||||
this->SetStatusText(_("Stopped"), 1);
|
||||
|
|
@ -973,6 +1025,8 @@ void MainFrame::OnMediaFinished(wxMediaEvent& event)
|
|||
|
||||
void MainFrame::UpdateElapsedTime(wxTimerEvent& event)
|
||||
{
|
||||
wxLogDebug("TIMER IS RUNNING..");
|
||||
|
||||
wxString duration, position;
|
||||
wxLongLong llLength, llTell;
|
||||
|
||||
|
|
@ -988,6 +1042,13 @@ void MainFrame::UpdateElapsedTime(wxTimerEvent& event)
|
|||
position.Printf(wxT("%2i:%02i"), current_min, current_sec);
|
||||
|
||||
m_SamplePosition->SetLabel(wxString::Format(wxT("%s/%s"), position.c_str(), duration.c_str()));
|
||||
|
||||
m_TopControlsPanel->Refresh();
|
||||
m_TopWaveformPanel->Refresh();
|
||||
|
||||
if (bLoopPointsSet && m_LoopABButton->GetValue())
|
||||
if (static_cast<double>(m_MediaCtrl->Tell()) >= m_LoopB.ToDouble())
|
||||
m_MediaCtrl->Seek(m_LoopA.ToDouble(), wxFromStart);
|
||||
}
|
||||
|
||||
void MainFrame::OnCheckAutoplay(wxCommandEvent& event)
|
||||
|
|
@ -1047,6 +1108,17 @@ void MainFrame::OnClickLibrary(wxDataViewEvent& event)
|
|||
return;
|
||||
}
|
||||
|
||||
// Update the waveform bitmap
|
||||
m_TopWaveformPanel->ResetDC();
|
||||
|
||||
m_LoopABButton->SetValue(false);
|
||||
|
||||
if (m_Timer->IsRunning())
|
||||
{
|
||||
m_Timer->Stop();
|
||||
wxLogDebug("TIMER STOPPED");
|
||||
}
|
||||
|
||||
wxString selection = m_Library->GetTextValue(selected_row, 1);
|
||||
|
||||
// Get curremt column
|
||||
|
|
@ -1084,15 +1156,17 @@ void MainFrame::OnClickLibrary(wxDataViewEvent& event)
|
|||
|
||||
if (CurrentColumn != FavoriteColumn)
|
||||
{
|
||||
m_MediaCtrl->Load(sample_path);
|
||||
ClearLoopPoints();
|
||||
|
||||
if (bAutoplay)
|
||||
{
|
||||
PushStatusText(wxString::Format(_("Now playing: %s"), selection), 1);
|
||||
|
||||
m_MediaCtrl->Play();
|
||||
m_Timer->Start(100, wxTIMER_CONTINUOUS);
|
||||
if (bLoopPointsSet && m_LoopABButton->GetValue())
|
||||
PlaySample(sample_path.ToStdString(), selection.ToStdString(), true, m_LoopA.ToDouble(), wxFromStart);
|
||||
else
|
||||
PlaySample(sample_path.ToStdString(), selection.ToStdString());
|
||||
}
|
||||
else
|
||||
m_MediaCtrl->Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2568,7 +2642,7 @@ void MainFrame::LoadConfigFile()
|
|||
this->CenterOnScreen(wxBOTH);
|
||||
this->SetIcon(wxIcon(ICON_HIVE_256px, wxICON_DEFAULT_TYPE, -1, -1));
|
||||
this->SetTitle("SampleHive");
|
||||
this->SetStatusText("SampleHive v0.8.4_alpha.1", 3);
|
||||
this->SetStatusText("SampleHive v0.9.0_alpha.1", 3);
|
||||
this->SetStatusText(_("Stopped"), 1);
|
||||
}
|
||||
|
||||
|
|
@ -2646,7 +2720,7 @@ void MainFrame::OnHiveStartEditing(wxDataViewEvent &event)
|
|||
|
||||
void MainFrame::OnSelectAddFile(wxCommandEvent& event)
|
||||
{
|
||||
wxFileDialog file_dialog(this, wxFileSelectorPromptStr, wxStandardPaths::Get().GetDocumentsDir(),
|
||||
wxFileDialog file_dialog(this, wxFileSelectorPromptStr, wxGetHomeDir(),
|
||||
wxEmptyString, wxFileSelectorDefaultWildcardStr,
|
||||
wxFD_DEFAULT_STYLE | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE | wxFD_PREVIEW,
|
||||
wxDefaultPosition, wxDefaultSize);
|
||||
|
|
@ -2669,7 +2743,7 @@ void MainFrame::OnSelectAddFile(wxCommandEvent& event)
|
|||
|
||||
void MainFrame::OnSelectAddDirectory(wxCommandEvent& event)
|
||||
{
|
||||
wxDirDialog dir_dialog(this, wxDirSelectorPromptStr, wxStandardPaths::Get().GetDocumentsDir(),
|
||||
wxDirDialog dir_dialog(this, wxDirSelectorPromptStr, wxGetHomeDir(),
|
||||
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST, wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
switch (dir_dialog.ShowModal())
|
||||
|
|
@ -2813,21 +2887,21 @@ void MainFrame::OnSelectAbout(wxCommandEvent& event)
|
|||
aboutInfo.SetName("SampleHive");
|
||||
aboutInfo.SetIcon(wxIcon(ICON_HIVE_64px));
|
||||
aboutInfo.AddArtist("Apoorv");
|
||||
aboutInfo.SetVersion("v0.8.4_alpha.1", _("Version 0.8.4_alpha.1"));
|
||||
aboutInfo.SetVersion("v0.9.0_alpha.1", _("Version 0.9.0_alpha.1"));
|
||||
aboutInfo.SetDescription(_("A simple, modern audio sample browser/manager for GNU/Linux."));
|
||||
aboutInfo.SetCopyright("(C) 2020-2021");
|
||||
aboutInfo.SetWebSite("http://samplehive.gitlab.io");
|
||||
aboutInfo.AddDeveloper("Apoorv");
|
||||
aboutInfo.SetLicence(wxString::FromAscii(
|
||||
"SampleHive v0.8.4_alpha.1\n"
|
||||
"SampleHive v0.9.0_alpha.1\n"
|
||||
"Copyright (C) 2021 Apoorv Singh\n"
|
||||
"\n"
|
||||
"This program is free software: you can redistribute it and/or modify\n"
|
||||
"SampleHive is free software: you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation, either version 3 of the License, or\n"
|
||||
"(at your option) any later version.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"SampleHive is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
|
|
@ -2858,4 +2932,64 @@ void MainFrame::SetAfterFrameCreate()
|
|||
m_BottomSplitter->SetSashPosition(300);
|
||||
}
|
||||
|
||||
void MainFrame::OnRecieveLoopPoints(SampleHive::SH_LoopPointsEvent& event)
|
||||
{
|
||||
wxLogDebug("%s called and recieved loop points", __FUNCTION__);
|
||||
|
||||
std::pair<double, double> loop_points = event.GetLoopPoints();
|
||||
|
||||
m_LoopA = wxLongLong(loop_points.first);
|
||||
m_LoopB = wxLongLong(loop_points.second);
|
||||
|
||||
int loopA_min = static_cast<int>((m_LoopA / 60000).GetValue());
|
||||
int loopA_sec = static_cast<int>(((m_LoopA % 60000) / 1000).GetValue());
|
||||
int loopB_min = static_cast<int>((m_LoopB / 60000).GetValue());
|
||||
int loopB_sec = static_cast<int>(((m_LoopB % 60000) / 1000).GetValue());
|
||||
|
||||
wxLogDebug(wxString::Format("LoopA: %2i:%02i, LoopB: %2i:%02i",
|
||||
loopA_min, loopA_sec, loopB_min, loopB_sec));
|
||||
|
||||
m_LoopABButton->SetValue(true);
|
||||
|
||||
bLoopPointsSet = true;
|
||||
|
||||
wxLogDebug("%s Event processed successfully..", __FUNCTION__);
|
||||
}
|
||||
|
||||
void MainFrame::OnRecieveStatusBarStatus(SampleHive::SH_SetStatusBarMessageEvent& event)
|
||||
{
|
||||
std::pair<wxString, int> status = event.GetMessageAndSection();
|
||||
|
||||
m_StatusBar->PushStatusText(status.first, status.second);
|
||||
}
|
||||
|
||||
void MainFrame::ClearLoopPoints()
|
||||
{
|
||||
m_LoopA = 0;
|
||||
m_LoopB = 0;
|
||||
|
||||
bLoopPointsSet = false;
|
||||
}
|
||||
|
||||
void MainFrame::PlaySample(const std::string& filepath, const std::string& sample, bool seek, wxFileOffset where, wxSeekMode mode)
|
||||
{
|
||||
wxLogDebug("TIMER STARTING FROM %s", __FUNCTION__);
|
||||
|
||||
if (m_MediaCtrl->Load(filepath))
|
||||
{
|
||||
if (seek)
|
||||
m_MediaCtrl->Seek(where, mode);
|
||||
|
||||
if (!m_MediaCtrl->Play())
|
||||
wxLogDebug(_("Error! Cannot play sample."));
|
||||
|
||||
PushStatusText(wxString::Format(_("Now playing: %s"), sample), 1);
|
||||
|
||||
if (!m_Timer->IsRunning())
|
||||
m_Timer->Start(20, wxTIMER_CONTINUOUS);
|
||||
}
|
||||
else
|
||||
wxLogDebug(_("Error! Cannot load sample."));
|
||||
}
|
||||
|
||||
MainFrame::~MainFrame(){}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "WaveformViewer.hpp"
|
||||
#include "SampleHiveConfig.hpp"
|
||||
#include "SH_Event.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/bmpbuttn.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/collpane.h>
|
||||
#include <wx/dataview.h>
|
||||
|
|
@ -40,6 +45,7 @@
|
|||
#include <wx/sizer.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/splitter.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/statbmp.h>
|
||||
#include <wx/statusbr.h>
|
||||
#include <wx/string.h>
|
||||
|
|
@ -51,9 +57,14 @@
|
|||
#include <wx/treectrl.h>
|
||||
#include <wx/window.h>
|
||||
|
||||
#include <taglib/taglib.h>
|
||||
#include <taglib/tag.h>
|
||||
#include <taglib/fileref.h>
|
||||
#include <taglib/tstring.h>
|
||||
|
||||
#ifndef USE_SYSTEM_INCLUDE_PATH
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#else
|
||||
#include <taglib/tstring.h>
|
||||
#endif
|
||||
|
||||
struct FileInfo
|
||||
{
|
||||
|
|
@ -106,16 +117,18 @@ class MainFrame : public wxFrame
|
|||
// -------------------------------------------------------------------
|
||||
// Top panel controls
|
||||
wxPanel* m_TopPanel;
|
||||
WaveformViewer* m_TopWaveformPanel;
|
||||
wxPanel* m_TopControlsPanel;
|
||||
wxBoxSizer* m_TopSizer;
|
||||
wxBoxSizer* m_TopPanelMainSizer;
|
||||
wxBoxSizer* m_WaveformDisplaySizer;
|
||||
wxStaticBitmap* m_WaveformViewer;
|
||||
wxBoxSizer* m_BrowserControlSizer;
|
||||
wxButton* m_PlayButton;
|
||||
wxToggleButton* m_LoopButton;
|
||||
wxButton* m_StopButton;
|
||||
wxBitmapButton* m_PlayButton;
|
||||
wxBitmapToggleButton* m_LoopButton;
|
||||
wxBitmapButton* m_StopButton;
|
||||
wxButton* m_SettingsButton;
|
||||
wxToggleButton* m_MuteButton;
|
||||
wxBitmapToggleButton* m_MuteButton;
|
||||
wxBitmapToggleButton* m_LoopABButton;
|
||||
wxStaticText* m_SamplePosition;
|
||||
wxSlider* m_VolumeSlider;
|
||||
wxCheckBox* m_AutoPlayCheck;
|
||||
|
|
@ -162,6 +175,12 @@ class MainFrame : public wxFrame
|
|||
// FileSystemWatcher
|
||||
wxFileSystemWatcher* m_FsWatcher;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
wxLongLong m_LoopA, m_LoopB;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
wxSystemAppearance m_Theme = wxSystemSettings::GetAppearance();
|
||||
|
||||
private:
|
||||
// -------------------------------------------------------------------
|
||||
bool bAutoplay = false;
|
||||
|
|
@ -169,6 +188,7 @@ class MainFrame : public wxFrame
|
|||
bool bMuted = false;
|
||||
bool bStopped = false;
|
||||
bool bFiltered = false;
|
||||
bool bLoopPointsSet = false;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
const std::string m_ConfigFilepath;
|
||||
|
|
@ -243,6 +263,15 @@ class MainFrame : public wxFrame
|
|||
void AddSamples(wxArrayString& files);
|
||||
void OnAutoImportDir(const wxString& pathToDirectory);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void PlaySample(const std::string& filepath, const std::string& sample, bool seek = false,
|
||||
wxFileOffset where = NULL, wxSeekMode mode = wxFromStart);
|
||||
|
||||
// Recieve custom events
|
||||
// -------------------------------------------------------------------
|
||||
void OnRecieveLoopPoints(SampleHive::SH_LoopPointsEvent& event);
|
||||
void OnRecieveStatusBarStatus(SampleHive::SH_SetStatusBarMessageEvent& event);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void LoadDatabase();
|
||||
void RefreshDatabase();
|
||||
|
|
@ -264,6 +293,9 @@ class MainFrame : public wxFrame
|
|||
// Call after frame creation
|
||||
void SetAfterFrameCreate();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void ClearLoopPoints();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
friend class App;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
#include "SH_Event.hpp"
|
||||
|
||||
namespace SampleHive
|
||||
{
|
||||
SH_LoopPointsEvent::SH_LoopPointsEvent(wxEventType eventType, int winId)
|
||||
: wxCommandEvent(eventType, winId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SH_LoopPointsEvent::~SH_LoopPointsEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
wxDEFINE_EVENT(SH_EVT_LOOP_POINTS_UPDATED, SH_LoopPointsEvent);
|
||||
|
||||
// SH_AddSampleEvent::SH_AddSampleEvent(wxEventType eventType, int winId)
|
||||
// : wxCommandEvent(eventType, winId)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// SH_AddSampleEvent::~SH_AddSampleEvent()
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// wxDEFINE_EVENT(SH_EVT_STATUS_ADD_SAMPLE, SH_AddSampleEvent);
|
||||
|
||||
// SH_MediaEvent::SH_MediaEvent(wxEventType eventType, int winId)
|
||||
// : wxCommandEvent(eventType, winId)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// SH_MediaEvent::~SH_MediaEvent()
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// wxDEFINE_EVENT(SH_EVT_MEDIA_STATUS_UPDATED, SH_MediaEvent);
|
||||
|
||||
SH_SetStatusBarMessageEvent::SH_SetStatusBarMessageEvent(wxEventType eventType, int winId)
|
||||
: wxCommandEvent(eventType, winId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SH_SetStatusBarMessageEvent::~SH_SetStatusBarMessageEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
wxDEFINE_EVENT(SH_EVT_STATUSBAR_MESSAGE_UPDATED, SH_SetStatusBarMessageEvent);
|
||||
|
||||
// SH_TimerEvent::SH_TimerEvent(wxEventType eventType, int winId)
|
||||
// : wxCommandEvent(eventType, winId)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// SH_TimerEvent::~SH_TimerEvent()
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// wxDEFINE_EVENT(SH_EVT_TIMER_STATUS_UPDATED, SH_TimerEvent);
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <wx/event.h>
|
||||
|
||||
namespace SampleHive
|
||||
{
|
||||
class SH_LoopPointsEvent : public wxCommandEvent
|
||||
{
|
||||
public:
|
||||
SH_LoopPointsEvent(wxEventType eventType, int winId);
|
||||
~SH_LoopPointsEvent();
|
||||
|
||||
public:
|
||||
virtual wxEvent* Clone() const { return new SH_LoopPointsEvent(*this); }
|
||||
|
||||
public:
|
||||
std::pair<double, double> GetLoopPoints() const { return { m_LoopA, m_LoopB }; };
|
||||
void SetLoopPoints(std::pair<double&, double&> loopPoints)
|
||||
{ m_LoopA = loopPoints.first; m_LoopB = loopPoints.second; };
|
||||
|
||||
private:
|
||||
double m_LoopA, m_LoopB;
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(SH_EVT_LOOP_POINTS_UPDATED, SH_LoopPointsEvent);
|
||||
|
||||
// class SH_AddSampleEvent : public wxCommandEvent
|
||||
// {
|
||||
// public:
|
||||
// SH_AddSampleEvent(wxEventType eventType, int winId);
|
||||
// ~SH_AddSampleEvent();
|
||||
|
||||
// public:
|
||||
// virtual wxEvent* Clone() const { return new SH_AddSampleEvent(*this); }
|
||||
|
||||
// public:
|
||||
// wxArrayString GetArrayString() const { return m_Files; };
|
||||
// void SetArrayString(const wxArrayString& files) { m_Files = files; };
|
||||
|
||||
// private:
|
||||
// wxArrayString m_Files;
|
||||
// };
|
||||
|
||||
// wxDECLARE_EVENT(SH_EVT_STATUS_ADD_SAMPLE, SH_AddSampleEvent);
|
||||
|
||||
// class SH_MediaEvent : public wxCommandEvent
|
||||
// {
|
||||
// public:
|
||||
// SH_MediaEvent(wxEventType eventType, int winId);
|
||||
// ~SH_MediaEvent();
|
||||
|
||||
// public:
|
||||
// virtual wxEvent* Clone() const { return new SH_MediaEvent(*this); }
|
||||
|
||||
// public:
|
||||
// void SetPath(const wxString& path) { m_Path = path; }
|
||||
// wxString GetPath() const { return m_Path; }
|
||||
|
||||
// private:
|
||||
// wxString m_Path;
|
||||
// };
|
||||
|
||||
// wxDECLARE_EVENT(SH_EVT_MEDIA_STATUS_UPDATED, SH_MediaEvent);
|
||||
|
||||
class SH_SetStatusBarMessageEvent : public wxCommandEvent
|
||||
{
|
||||
public:
|
||||
SH_SetStatusBarMessageEvent(wxEventType eventType, int winId);
|
||||
~SH_SetStatusBarMessageEvent();
|
||||
|
||||
public:
|
||||
virtual wxEvent* Clone() const { return new SH_SetStatusBarMessageEvent(*this); }
|
||||
|
||||
public:
|
||||
std::pair<wxString, int> GetMessageAndSection() const { return { m_Msg, m_Section }; }
|
||||
void SetMessageAndSection(std::pair<const wxString&, int> status) { m_Msg = status.first; m_Section = status.second; }
|
||||
|
||||
private:
|
||||
wxString m_Msg;
|
||||
int m_Section;
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(SH_EVT_STATUSBAR_MESSAGE_UPDATED, SH_SetStatusBarMessageEvent);
|
||||
|
||||
// class SH_TimerEvent : public wxCommandEvent
|
||||
// {
|
||||
// public:
|
||||
// SH_TimerEvent(wxEventType eventType, int winId);
|
||||
// ~SH_TimerEvent();
|
||||
|
||||
// public:
|
||||
// virtual wxEvent* Clone() const { return new SH_TimerEvent(*this); }
|
||||
|
||||
// public:
|
||||
// std::pair<int, bool> GetSecondsAndMode() const { return { m_Seconds, m_Mode }; }
|
||||
// void SetSecondsAndMode(std::pair<int, bool> timerStatus) { m_Seconds = timerStatus.first; m_Mode = timerStatus.second; }
|
||||
|
||||
// private:
|
||||
// int m_Seconds;
|
||||
// bool m_Mode;
|
||||
// };
|
||||
|
||||
// wxDECLARE_EVENT(SH_EVT_TIMER_STATUS_UPDATED, SH_TimerEvent);
|
||||
}
|
||||
|
|
@ -21,8 +21,9 @@
|
|||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <wx/colour.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/stdpaths.h>
|
||||
// #include <wx/stdpaths.h>
|
||||
#include <wx/filename.h>
|
||||
|
||||
#include <yaml-cpp/emittermanip.h>
|
||||
|
|
@ -39,7 +40,9 @@ Serializer::Serializer(const std::string& filepath)
|
|||
std::string system_font_face = font.GetFaceName().ToStdString();
|
||||
int system_font_size = font.GetPointSize();
|
||||
|
||||
std::string dir = wxStandardPaths::Get().GetDocumentsDir().ToStdString();
|
||||
wxColour colour = "#FE9647";
|
||||
|
||||
std::string dir = wxGetHomeDir().ToStdString();
|
||||
|
||||
if (!ifstrm)
|
||||
{
|
||||
|
|
@ -73,6 +76,11 @@ Serializer::Serializer(const std::string& filepath)
|
|||
m_Emitter << YAML::EndMap;
|
||||
m_Emitter << YAML::EndMap << YAML::Newline;
|
||||
|
||||
m_Emitter << YAML::Newline << YAML::Key << "Waveform";
|
||||
m_Emitter << YAML::BeginMap;
|
||||
m_Emitter << YAML::Key << "Colour" << YAML::Value << colour.GetAsString().ToStdString();
|
||||
m_Emitter << YAML::EndMap << YAML::Newline;
|
||||
|
||||
m_Emitter << YAML::Newline << YAML::Key << "Collection";
|
||||
m_Emitter << YAML::BeginMap;
|
||||
m_Emitter << YAML::Key << "AutoImport" << YAML::Value << false;
|
||||
|
|
@ -249,6 +257,64 @@ FontType Serializer::DeserializeDisplaySettings() const
|
|||
return { face, size };
|
||||
}
|
||||
|
||||
void Serializer::SerializeWaveformColour(wxColour& colour)
|
||||
{
|
||||
YAML::Emitter out;
|
||||
|
||||
std::string colour_string = colour.GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
|
||||
|
||||
try
|
||||
{
|
||||
YAML::Node config = YAML::LoadFile(m_Filepath);
|
||||
|
||||
if (auto waveform = config["Waveform"])
|
||||
{
|
||||
wxLogDebug("Changing waveform colour");
|
||||
wxLogDebug("Waveform colour: %s", colour_string);
|
||||
|
||||
waveform["Colour"] = colour_string;
|
||||
|
||||
out << config;
|
||||
|
||||
std::ofstream ofstrm(m_Filepath);
|
||||
ofstrm << out.c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogDebug("Error! Cannot store waveform colour.");
|
||||
}
|
||||
}
|
||||
catch(const YAML::ParserException& ex)
|
||||
{
|
||||
std::cout << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
wxColour Serializer::DeserializeWaveformColour() const
|
||||
{
|
||||
std::string colour;
|
||||
|
||||
try
|
||||
{
|
||||
YAML::Node config = YAML::LoadFile(m_Filepath);
|
||||
|
||||
if (auto waveform = config["Waveform"])
|
||||
{
|
||||
colour = waveform["Colour"].as<std::string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogDebug("Error! Cannot fetch waveform colour.");
|
||||
}
|
||||
}
|
||||
catch(const YAML::ParserException& ex)
|
||||
{
|
||||
std::cout << ex.what() << std::endl;
|
||||
}
|
||||
|
||||
return static_cast<wxString>(colour);
|
||||
}
|
||||
|
||||
void Serializer::SerializeAutoImportSettings(wxTextCtrl& textCtrl, wxCheckBox& checkBox)
|
||||
{
|
||||
YAML::Emitter out;
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ class Serializer
|
|||
// Display settings
|
||||
void SerializeDisplaySettings(wxFont& font);
|
||||
FontType DeserializeDisplaySettings() const;
|
||||
void SerializeWaveformColour(wxColour& colour);
|
||||
wxColour DeserializeWaveformColour() const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Auto import settings
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
#include <wx/defs.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/stdpaths.h>
|
||||
// #include <wx/stdpaths.h>
|
||||
#include <wx/stringimpl.h>
|
||||
|
||||
#include "ControlID_Enums.hpp"
|
||||
|
|
@ -51,8 +51,10 @@ Settings::Settings(wxWindow* window, const std::string& configFilepath, const st
|
|||
|
||||
m_DisplayTopSizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_DisplayFontSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_WaveformColourSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxString fontChoices[] = {"System default"};
|
||||
Serializer serializer(m_ConfigFilepath);
|
||||
// m_RowHeightText = new wxStaticText();
|
||||
m_FontTypeText = new wxStaticText(m_DisplaySettingPanel, wxID_ANY, "Font", wxDefaultPosition, wxDefaultSize, 0);
|
||||
// m_RowHeight = new wxChoice();
|
||||
|
|
@ -61,6 +63,9 @@ Settings::Settings(wxWindow* window, const std::string& configFilepath, const st
|
|||
m_FontSize = new wxSpinCtrl(m_DisplaySettingPanel, SD_FontSize, "Default", wxDefaultPosition, wxDefaultSize);
|
||||
m_FontSize->SetValue(window->GetFont().GetPointSize());
|
||||
m_FontBrowseButton = new wxButton(m_DisplaySettingPanel, SD_FontBrowseButton, "Select font", wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_WaveformColourLabel = new wxStaticText(m_DisplaySettingPanel, wxID_ANY, "Waveform colour", wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_WaveformColourPickerCtrl = new wxColourPickerCtrl(m_DisplaySettingPanel, SD_WaveformColourPickerCtrl, serializer.DeserializeWaveformColour(),
|
||||
wxDefaultPosition, wxDefaultSize, wxCLRP_DEFAULT_STYLE);
|
||||
|
||||
m_CollectionSettingPanel = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
|
|
@ -68,7 +73,7 @@ Settings::Settings(wxWindow* window, const std::string& configFilepath, const st
|
|||
m_CollectionImportDirSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_ShowFileExtensionSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxString defaultDir = wxStandardPaths::Get().GetDocumentsDir();
|
||||
wxString defaultDir = wxGetHomeDir();
|
||||
|
||||
m_AutoImportCheck = new wxCheckBox(m_CollectionSettingPanel, SD_AutoImport, "Auto import", wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_ImportDirLocation = new wxTextCtrl(m_CollectionSettingPanel, wxID_ANY, defaultDir, wxDefaultPosition, wxDefaultSize, 0);
|
||||
|
|
@ -108,30 +113,34 @@ Settings::Settings(wxWindow* window, const std::string& configFilepath, const st
|
|||
Bind(wxEVT_BUTTON, &Settings::OnClickBrowseAutoImportDir, this, SD_BrowseAutoImportDir);
|
||||
Bind(wxEVT_BUTTON, &Settings::OnClickConfigBrowse, this, SD_BrowseConfigDir);
|
||||
Bind(wxEVT_BUTTON, &Settings::OnClickDatabaseBrowse, this, SD_BrowseDatabaseDir);
|
||||
Bind(wxEVT_COLOURPICKER_CHANGED, &Settings::OnChangeWaveformColour, this, SD_WaveformColourPickerCtrl);
|
||||
|
||||
// Adding controls to sizers
|
||||
m_NotebookSizer->Add(m_Notebook, 1, wxALL | wxEXPAND, 2);
|
||||
|
||||
m_GeneralMainSizer->Add(m_ConfigLabel, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_GeneralMainSizer->Add(m_ConfigLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_GeneralMainSizer->Add(m_ConfigText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
|
||||
m_GeneralMainSizer->Add(m_ConfigBrowse, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_GeneralMainSizer->Add(m_ConfigBrowse, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_GeneralMainSizer->Add(m_DatabaseLabel, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_GeneralMainSizer->Add(m_DatabaseLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_GeneralMainSizer->Add(m_DatabaseText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
|
||||
m_GeneralMainSizer->Add(m_DatabaseBrowse, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_GeneralMainSizer->Add(m_DatabaseBrowse, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_DisplayFontSizer->Add(m_FontTypeText, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_DisplayFontSizer->Add(m_FontType, 1, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_DisplayFontSizer->Add(m_FontSize, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_DisplayFontSizer->Add(m_FontBrowseButton, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 2);
|
||||
m_DisplayFontSizer->Add(m_FontBrowseButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_WaveformColourSizer->Add(m_WaveformColourLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_WaveformColourSizer->Add(m_WaveformColourPickerCtrl, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_DisplayTopSizer->Add(m_DisplayFontSizer, 1, wxALL | wxEXPAND, 2);
|
||||
m_DisplayTopSizer->Add(m_DisplayFontSizer, 0, wxALL | wxEXPAND, 2);
|
||||
m_DisplayTopSizer->Add(m_WaveformColourSizer, 0, wxALL | wxEXPAND, 2);
|
||||
|
||||
m_CollectionImportDirSizer->Add(m_AutoImportCheck, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT, 2);
|
||||
m_CollectionImportDirSizer->Add(m_AutoImportCheck, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_CollectionImportDirSizer->Add(m_ImportDirLocation, 1, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
m_CollectionImportDirSizer->Add(m_BrowseAutoImportDirButton, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 2);
|
||||
m_CollectionImportDirSizer->Add(m_BrowseAutoImportDirButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
m_ShowFileExtensionSizer->Add(m_ShowFileExtensionCheck, 0, wxALL | wxALIGN_LEFT, 2);
|
||||
m_ShowFileExtensionSizer->Add(m_ShowFileExtensionCheck, 0, wxALL, 2);
|
||||
|
||||
m_CollectionTopSizer->Add(m_CollectionImportDirSizer, 0, wxALL | wxEXPAND, 2);
|
||||
m_CollectionTopSizer->Add(m_ShowFileExtensionSizer, 0, wxALL | wxEXPAND, 2);
|
||||
|
|
@ -169,7 +178,7 @@ Settings::Settings(wxWindow* window, const std::string& configFilepath, const st
|
|||
|
||||
void Settings::OnClickConfigBrowse(wxCommandEvent& event)
|
||||
{
|
||||
wxString initial_dir = wxStandardPaths::Get().GetDocumentsDir();
|
||||
wxString initial_dir = wxGetHomeDir();
|
||||
|
||||
m_DirDialog = new wxDirDialog(this, "Select a directory..", initial_dir,
|
||||
wxDD_DEFAULT_STYLE |
|
||||
|
|
@ -192,7 +201,7 @@ void Settings::OnClickConfigBrowse(wxCommandEvent& event)
|
|||
|
||||
void Settings::OnClickDatabaseBrowse(wxCommandEvent& event)
|
||||
{
|
||||
wxString initial_dir = wxStandardPaths::Get().GetDocumentsDir();
|
||||
wxString initial_dir = wxGetHomeDir();
|
||||
|
||||
m_DirDialog = new wxDirDialog(this, "Select a directory..", initial_dir,
|
||||
wxDD_DEFAULT_STYLE |
|
||||
|
|
@ -255,7 +264,7 @@ void Settings::OnClickBrowseAutoImportDir(wxCommandEvent& event)
|
|||
{
|
||||
Serializer serializer(m_ConfigFilepath);
|
||||
|
||||
wxString initial_dir = wxStandardPaths::Get().GetDocumentsDir();
|
||||
wxString initial_dir = wxGetHomeDir();
|
||||
|
||||
m_DirDialog = new wxDirDialog(this, "Select a directory..", initial_dir,
|
||||
wxDD_DEFAULT_STYLE |
|
||||
|
|
@ -426,4 +435,25 @@ wxString Settings::GetImportDirPath()
|
|||
return dir;
|
||||
}
|
||||
|
||||
void Settings::OnChangeWaveformColour(wxColourPickerEvent& event)
|
||||
{
|
||||
Serializer serializer(m_ConfigFilepath);
|
||||
wxColour colour = m_WaveformColourPickerCtrl->GetColour();
|
||||
|
||||
wxColour wave_colour = serializer.DeserializeWaveformColour();
|
||||
|
||||
if (colour != wave_colour)
|
||||
{
|
||||
wxLogDebug("Waveform colour changed.");
|
||||
bWaveformColourChanged = true;
|
||||
|
||||
serializer.SerializeWaveformColour(colour);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogDebug("Waveform colour not changed.");
|
||||
bWaveformColourChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
Settings::~Settings(){}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <string>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/clrpicker.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/dialog.h>
|
||||
|
|
@ -86,6 +87,9 @@ class Settings : public wxDialog
|
|||
wxFontDialog* m_FontDialog;
|
||||
wxButton* m_FontBrowseButton;
|
||||
wxSpinCtrl* m_FontSize;
|
||||
wxBoxSizer* m_WaveformColourSizer;
|
||||
wxStaticText* m_WaveformColourLabel;
|
||||
wxColourPickerCtrl* m_WaveformColourPickerCtrl;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Collection page
|
||||
|
|
@ -121,6 +125,7 @@ class Settings : public wxDialog
|
|||
// -------------------------------------------------------------------
|
||||
bool bAutoImport = false;
|
||||
bool bShowExtension = true;
|
||||
bool bWaveformColourChanged = false;
|
||||
|
||||
private:
|
||||
// -------------------------------------------------------------------
|
||||
|
|
@ -131,6 +136,7 @@ class Settings : public wxDialog
|
|||
void OnClickBrowseAutoImportDir(wxCommandEvent& event);
|
||||
void OnChangeFontSize(wxSpinEvent& event);
|
||||
void OnSelectFont(wxCommandEvent& event);
|
||||
void OnChangeWaveformColour(wxColourPickerEvent& event);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void SetCustomFont();
|
||||
|
|
@ -147,4 +153,6 @@ class Settings : public wxDialog
|
|||
inline wxFont GetFontType() { return m_Font; };
|
||||
inline bool CanAutoImport() { return bAutoImport; };
|
||||
inline bool ShouldShowFileExtension() { return bShowExtension; };
|
||||
inline bool IsWaveformColourChanged() { return bWaveformColourChanged; }
|
||||
inline wxColour GetWaveformColour() { return m_WaveformColourPickerCtrl->GetColour(); }
|
||||
};
|
||||
|
|
|
|||
14
src/Tags.cpp
|
|
@ -18,11 +18,17 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <taglib/taglib.h>
|
||||
#include <taglib/fileref.h>
|
||||
#include <taglib/tstring.h>
|
||||
|
||||
#include "Tags.hpp"
|
||||
#include "SampleHiveConfig.hpp"
|
||||
|
||||
#include <taglib/tag.h>
|
||||
#include <taglib/fileref.h>
|
||||
|
||||
#ifndef USE_SYSTEM_INCLUDE_PATH
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#else
|
||||
#include <taglib/tstring.h>
|
||||
#endif
|
||||
|
||||
Tags::Tags(const std::string& filename)
|
||||
: m_Filepath(filename)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,496 @@
|
|||
/* SampleHive
|
||||
* Copyright (C) 2021 Apoorv Singh
|
||||
* A simple, modern audio sample browser/manager for GNU/Linux.
|
||||
*
|
||||
* This file is a part of SampleHive
|
||||
*
|
||||
* SampleHive is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SampleHive is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <wx/brush.h>
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/dcmemory.h>
|
||||
#include <wx/filefn.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/pen.h>
|
||||
|
||||
#include <sndfile.hh>
|
||||
|
||||
#include "WaveformViewer.hpp"
|
||||
#include "Database.hpp"
|
||||
#include "SettingsDialog.hpp"
|
||||
#include "Serialize.hpp"
|
||||
#include "Tags.hpp"
|
||||
#include "SH_Event.hpp"
|
||||
|
||||
WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataViewListCtrl& library,
|
||||
wxMediaCtrl& mediaCtrl, wxInfoBar& infoBar,
|
||||
const std::string& configFilepath, const std::string& databaseFilepath)
|
||||
: wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE),
|
||||
m_ParentFrame(parentFrame), m_Window(window), m_Library(library), m_InfoBar(infoBar), m_MediaCtrl(mediaCtrl),
|
||||
m_ConfigFilepath(configFilepath), m_DatabaseFilepath(databaseFilepath)
|
||||
{
|
||||
this->SetDoubleBuffered(true);
|
||||
|
||||
Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, this);
|
||||
Bind(wxEVT_MOTION, &WaveformViewer::OnMouseMotion, this);
|
||||
Bind(wxEVT_LEFT_DOWN, &WaveformViewer::OnMouseLeftButtonDown, this);
|
||||
Bind(wxEVT_LEFT_UP, &WaveformViewer::OnMouseLeftButtonUp, this);
|
||||
// Bind(wxEVT_KEY_DOWN, &WaveformViewer::OnControlKeyDown, this);
|
||||
Bind(wxEVT_KEY_UP, &WaveformViewer::OnControlKeyUp, this);
|
||||
}
|
||||
|
||||
WaveformViewer::~WaveformViewer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WaveformViewer::OnPaint(wxPaintEvent& event)
|
||||
{
|
||||
wxPaintDC dc(this);
|
||||
|
||||
const wxSize& size = m_Window->GetClientSize();
|
||||
|
||||
if (!m_WaveformBitmap.IsOk()
|
||||
|| m_WaveformBitmap.GetWidth() != size.x
|
||||
|| m_WaveformBitmap.GetHeight() != size.y
|
||||
|| bBitmapDirty)
|
||||
{
|
||||
wxLogDebug("Updating waveform bitmap..");
|
||||
|
||||
m_WaveformBitmap = wxBitmap(wxImage(size.x, size.y), 32);
|
||||
|
||||
UpdateWaveformBitmap();
|
||||
|
||||
bBitmapDirty = false;
|
||||
}
|
||||
|
||||
dc.DrawBitmap(m_WaveformBitmap, 0, 0, false);
|
||||
|
||||
RenderPlayhead(dc);
|
||||
|
||||
// Draw selection range
|
||||
if (bSelectRange)
|
||||
{
|
||||
wxRect rect(m_CurrentPoint, m_AnchorPoint);
|
||||
|
||||
dc.SetPen(wxPen(wxColour(200, 200, 200), 2, wxPENSTYLE_SOLID));
|
||||
dc.SetBrush(wxBrush(wxColour(200, 200, 200, 80), wxBRUSHSTYLE_SOLID));
|
||||
dc.DrawRectangle(rect);
|
||||
}
|
||||
|
||||
// Draw selected area
|
||||
if (!bSelectRange && bDrawSelectedArea && !bBitmapDirty)
|
||||
{
|
||||
dc.SetPen(wxPen(wxColour(200, 200, 200, 255), 4, wxPENSTYLE_SOLID));
|
||||
dc.SetBrush(wxBrush(wxColour(200, 200, 200, 80), wxBRUSHSTYLE_SOLID));
|
||||
dc.DrawRectangle(wxRect(m_AnchorPoint.x, -2, m_CurrentPoint.x - m_AnchorPoint.x, this->GetSize().GetHeight() + 5));
|
||||
|
||||
bAreaSelected = true;
|
||||
SendLoopPoints();
|
||||
}
|
||||
else
|
||||
bAreaSelected = false;
|
||||
}
|
||||
|
||||
void WaveformViewer::RenderPlayhead(wxDC& dc)
|
||||
{
|
||||
Database db(m_InfoBar);
|
||||
|
||||
int selected_row = m_Library.GetSelectedRow();
|
||||
|
||||
if (selected_row < 0)
|
||||
return;
|
||||
|
||||
wxString selected = m_Library.GetTextValue(selected_row, 1);
|
||||
std::string path = db.GetSamplePathByFilename(m_DatabaseFilepath, selected.BeforeLast('.').ToStdString());
|
||||
|
||||
Tags tags(path);
|
||||
|
||||
int length = tags.GetAudioInfo().length;
|
||||
wxLogDebug("Sample length: %d", length);
|
||||
|
||||
double position = m_MediaCtrl.Tell();
|
||||
wxLogDebug("Current Sample Position: %f", position);
|
||||
|
||||
int panel_width = this->GetSize().GetWidth();
|
||||
double line_pos = panel_width * (position / length);
|
||||
|
||||
wxLogDebug("Drawing playhead at: %f", line_pos);
|
||||
|
||||
m_PlayheadColour = wxColor(255, 0, 0, 255);
|
||||
|
||||
// Draw the triangle
|
||||
dc.SetPen(wxPen(m_PlayheadColour, 8, wxPENSTYLE_SOLID));
|
||||
dc.DrawLine(line_pos - 5, this->GetSize().GetHeight() - (this->GetSize().GetHeight() - 1),
|
||||
line_pos, this->GetSize().GetHeight() - (this->GetSize().GetHeight() - 1) + 5);
|
||||
dc.DrawLine(line_pos + 5, this->GetSize().GetHeight() - (this->GetSize().GetHeight() - 1),
|
||||
line_pos, this->GetSize().GetHeight() - (this->GetSize().GetHeight()- 1) + 5);
|
||||
|
||||
// Draw the line
|
||||
dc.SetPen(wxPen(m_PlayheadColour, 2, wxPENSTYLE_SOLID));
|
||||
dc.DrawLine(line_pos, this->GetSize().GetHeight() - (this->GetSize().GetHeight() - 1),
|
||||
line_pos, this->GetSize().GetHeight() - 1);
|
||||
}
|
||||
|
||||
void WaveformViewer::UpdateWaveformBitmap()
|
||||
{
|
||||
Database db(m_InfoBar);
|
||||
Settings settings(m_ParentFrame, m_ConfigFilepath, m_DatabaseFilepath);
|
||||
Serializer serializer(m_ConfigFilepath);
|
||||
|
||||
int selected_row = m_Library.GetSelectedRow();
|
||||
|
||||
if (selected_row < 0)
|
||||
return;
|
||||
|
||||
wxString selection = m_Library.GetTextValue(selected_row, 1);
|
||||
|
||||
wxString filepath_with_extension = db.GetSamplePathByFilename(m_DatabaseFilepath, selection.BeforeLast('.').ToStdString());
|
||||
wxString filepath_without_extension = db.GetSamplePathByFilename(m_DatabaseFilepath, selection.ToStdString());
|
||||
|
||||
std::string extension = settings.ShouldShowFileExtension() ?
|
||||
db.GetSampleFileExtension(m_DatabaseFilepath, selection.ToStdString()) :
|
||||
db.GetSampleFileExtension(m_DatabaseFilepath, selection.BeforeLast('.').ToStdString());
|
||||
|
||||
wxString path = selection.Contains(wxString::Format(".%s", extension)) ?
|
||||
filepath_with_extension : filepath_without_extension;
|
||||
|
||||
SndfileHandle snd_file(path);
|
||||
|
||||
int channels = snd_file.channels();
|
||||
double sample_rate = snd_file.samplerate();
|
||||
sf_count_t frames = snd_file.frames();
|
||||
|
||||
std::vector<float> sample;
|
||||
sample.resize(frames * channels);
|
||||
|
||||
std::vector<float> waveform;
|
||||
|
||||
// TODO, FIXME: Don't reload file on every window resize
|
||||
snd_file.read(&sample.at(0), frames * channels);
|
||||
|
||||
float display_width = this->GetSize().GetWidth();
|
||||
float display_height = this->GetSize().GetHeight();
|
||||
|
||||
wxLogDebug("Calculating Waveform bars RMS..");
|
||||
|
||||
float chunk_size = (float)(frames) / (float)display_width;
|
||||
int number_of_chunks = static_cast<int>(static_cast<float>(frames) / chunk_size);
|
||||
|
||||
// Start with low non-zero value
|
||||
float normalize = 0.00001;
|
||||
|
||||
for (int i = 0; i < number_of_chunks; i++)
|
||||
{
|
||||
double sum = 0, mono = 0;
|
||||
|
||||
int start_point = static_cast<int>(i * chunk_size * channels);
|
||||
|
||||
// Iterate on the chunk, get the square of sum of monos
|
||||
for (int j = 0; j < chunk_size; j++)
|
||||
{
|
||||
if (channels == 2)
|
||||
mono = 0.5f * (sample[start_point + (2 * j)] + sample[start_point + (2 * j) + 1]);
|
||||
else
|
||||
mono = sample[start_point + j];
|
||||
|
||||
sum += mono * mono; // Square
|
||||
}
|
||||
|
||||
sum /= chunk_size; // Mean
|
||||
sum = pow(sum, 0.5); // Root
|
||||
|
||||
// We might bleed a bit on the end and get some near infs, dunno
|
||||
// what is causing astronomically big numbers from sample[]
|
||||
if ((sum < 200.0) && (sum > normalize))
|
||||
normalize = sum;
|
||||
|
||||
waveform.push_back(sum);
|
||||
}
|
||||
|
||||
// Actually normalize
|
||||
for (int i = 0; i < waveform.size(); i++)
|
||||
waveform[i] /= normalize;
|
||||
|
||||
// Draw code
|
||||
wxMemoryDC mdc(m_WaveformBitmap);
|
||||
|
||||
mdc.SetBackground(wxBrush(wxColour(0, 0, 0, 150), wxBRUSHSTYLE_SOLID));
|
||||
mdc.Clear();
|
||||
|
||||
m_WaveformColour = serializer.DeserializeWaveformColour();
|
||||
|
||||
mdc.SetPen(wxPen(wxColour(m_WaveformColour), 2, wxPENSTYLE_SOLID));
|
||||
|
||||
wxLogDebug("Drawing bitmap..");
|
||||
|
||||
for (int i = 0; i < waveform.size() - 1; i++)
|
||||
{
|
||||
float half_display_height = static_cast<float>(display_height) / 2.0f;
|
||||
|
||||
// X is percentage of i relative to waveform.size() multiplied by
|
||||
// the width, Y is the half height times the value up or down
|
||||
float X = display_width * ((float)i / waveform.size());
|
||||
float Y = waveform[i] * half_display_height;
|
||||
|
||||
mdc.DrawLine(X, half_display_height + Y, X, half_display_height - Y);
|
||||
}
|
||||
|
||||
wxLogDebug("Done drawing bitmap..");
|
||||
}
|
||||
|
||||
void WaveformViewer::OnControlKeyDown(wxKeyEvent &event)
|
||||
{
|
||||
switch (event.GetKeyCode())
|
||||
{
|
||||
case WXK_CONTROL:
|
||||
SetCursor(wxCURSOR_IBEAM);
|
||||
break;
|
||||
default:
|
||||
SetCursor(wxCURSOR_ARROW);
|
||||
break;
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void WaveformViewer::OnControlKeyUp(wxKeyEvent &event)
|
||||
{
|
||||
switch (event.GetKeyCode())
|
||||
{
|
||||
case WXK_CONTROL:
|
||||
if (bSelectRange)
|
||||
{
|
||||
SetCursor(wxCURSOR_ARROW);
|
||||
bSelectRange = false;
|
||||
bDrawSelectedArea = false;
|
||||
ReleaseMouse();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void WaveformViewer::OnMouseMotion(wxMouseEvent& event)
|
||||
{
|
||||
Database db(m_InfoBar);
|
||||
|
||||
int selected_row = m_Library.GetSelectedRow();
|
||||
|
||||
if (selected_row < 0)
|
||||
return;
|
||||
|
||||
wxString selected = m_Library.GetTextValue(selected_row, 1);
|
||||
std::string path = db.GetSamplePathByFilename(m_DatabaseFilepath, selected.BeforeLast('.').ToStdString());
|
||||
|
||||
Tags tags(path);
|
||||
|
||||
int length = tags.GetAudioInfo().length;
|
||||
|
||||
double position = m_MediaCtrl.Tell();
|
||||
|
||||
int panel_width = this->GetSize().GetWidth();
|
||||
double line_pos = panel_width * (position / length);
|
||||
|
||||
wxPoint pos = event.GetPosition();
|
||||
|
||||
double seek_to = ((double)pos.x / panel_width) * length;
|
||||
|
||||
if (abs(pos.x - line_pos) <= 5 && pos.y <= 5)
|
||||
{
|
||||
SetCursor(wxCursor(wxCURSOR_HAND));
|
||||
wxLogDebug("Cursor on playhead..");
|
||||
}
|
||||
else if (bSelectRange)
|
||||
{
|
||||
m_CurrentPoint = wxPoint(pos.x , pos.y);
|
||||
|
||||
Refresh();
|
||||
|
||||
wxLogDebug("CTRL pressed, pressing LMB will draw selection range at %d, %d", pos.x, pos.y);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
void WaveformViewer::OnMouseLeftButtonDown(wxMouseEvent& event)
|
||||
{
|
||||
Database db(m_InfoBar);
|
||||
int selected_row = m_Library.GetSelectedRow();
|
||||
|
||||
if (selected_row < 0)
|
||||
return;
|
||||
|
||||
wxString selected = m_Library.GetTextValue(selected_row, 1);
|
||||
std::string path = db.GetSamplePathByFilename(m_DatabaseFilepath, selected.BeforeLast('.').ToStdString());
|
||||
|
||||
Tags tags(path);
|
||||
|
||||
int length = tags.GetAudioInfo().length;
|
||||
|
||||
double position = m_MediaCtrl.Tell();
|
||||
|
||||
int panel_width = this->GetSize().GetWidth();
|
||||
double line_pos = panel_width * (position / length);
|
||||
|
||||
wxPoint pos = event.GetPosition();
|
||||
|
||||
if (abs(pos.x - line_pos) <= 5 && pos.y <= 5)
|
||||
{
|
||||
SetCursor(wxCURSOR_CLOSED_HAND);
|
||||
CaptureMouse();
|
||||
|
||||
wxLogDebug("Mouse Captured playhead..");
|
||||
}
|
||||
else if (event.ControlDown())
|
||||
{
|
||||
wxLogDebug("LMB pressed");
|
||||
|
||||
SetCursor(wxCURSOR_CLOSED_HAND);
|
||||
CaptureMouse();
|
||||
|
||||
bSelectRange = true;
|
||||
|
||||
m_AnchorPoint = wxPoint(pos.x, pos.y);
|
||||
m_CurrentPoint = m_AnchorPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCursor(wxCURSOR_ARROW);
|
||||
return;
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void WaveformViewer::OnMouseLeftButtonUp(wxMouseEvent& event)
|
||||
{
|
||||
Database db(m_InfoBar);
|
||||
|
||||
int selected_row = m_Library.GetSelectedRow();
|
||||
|
||||
if (selected_row < 0)
|
||||
return;
|
||||
|
||||
wxString selected = m_Library.GetTextValue(selected_row, 1);
|
||||
std::string path = db.GetSamplePathByFilename(m_DatabaseFilepath, selected.BeforeLast('.').ToStdString());
|
||||
|
||||
Tags tags(path);
|
||||
|
||||
int length = tags.GetAudioInfo().length;
|
||||
|
||||
double position = m_MediaCtrl.Tell();
|
||||
|
||||
int panel_width = this->GetSize().GetWidth();
|
||||
double line_pos = panel_width * (position / length);
|
||||
|
||||
wxPoint pos = event.GetPosition();
|
||||
|
||||
double seek_to = ((double)pos.x / panel_width) * length;
|
||||
|
||||
if (!wxWindow::HasCapture())
|
||||
{
|
||||
wxLogDebug("Window doesn't have capture skipping..");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bSelectRange)
|
||||
{
|
||||
wxLogDebug("LMB released");
|
||||
|
||||
m_CurrentPoint = wxPoint(pos.x, pos.y);
|
||||
|
||||
ReleaseMouse();
|
||||
SetCursor(wxCURSOR_ARROW);
|
||||
|
||||
Refresh();
|
||||
|
||||
bSelectRange = false;
|
||||
|
||||
if (!bSelectRange)
|
||||
bDrawSelectedArea = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReleaseMouse();
|
||||
SetCursor(wxCURSOR_ARROW);
|
||||
|
||||
m_MediaCtrl.Seek(seek_to, wxFromStart);
|
||||
SendStatusBarStatus(wxString::Format(_("Now playing: %s"), selected), 1);
|
||||
m_MediaCtrl.Play();
|
||||
}
|
||||
}
|
||||
|
||||
void WaveformViewer::ResetDC()
|
||||
{
|
||||
bBitmapDirty = true;
|
||||
bSelectRange = false;
|
||||
bDrawSelectedArea = false;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void WaveformViewer::SendLoopPoints()
|
||||
{
|
||||
wxLogDebug("%s Called", __FUNCTION__);
|
||||
|
||||
SampleHive::SH_LoopPointsEvent event(SampleHive::SH_EVT_LOOP_POINTS_UPDATED, this->GetId());
|
||||
event.SetEventObject(this);
|
||||
|
||||
Database db(m_InfoBar);
|
||||
|
||||
int selected_row = m_Library.GetSelectedRow();
|
||||
|
||||
if (selected_row < 0)
|
||||
return;
|
||||
|
||||
wxString selected = m_Library.GetTextValue(selected_row, 1);
|
||||
std::string path = db.GetSamplePathByFilename(m_DatabaseFilepath, selected.BeforeLast('.').ToStdString());
|
||||
|
||||
Tags tags(path);
|
||||
|
||||
int length = tags.GetAudioInfo().length;
|
||||
|
||||
int panel_width = this->GetSize().GetWidth();
|
||||
|
||||
int a = m_AnchorPoint.x, b = m_CurrentPoint.x;
|
||||
|
||||
double loopA = ((double)a / panel_width) * length;
|
||||
double loopB = ((double)b / panel_width) * length;
|
||||
|
||||
event.SetLoopPoints({ loopA, loopB });
|
||||
|
||||
HandleWindowEvent(event);
|
||||
|
||||
wxLogDebug("%s processed event, sending loop points..", __FUNCTION__);
|
||||
}
|
||||
|
||||
void WaveformViewer::SendStatusBarStatus(const wxString& msg, int section)
|
||||
{
|
||||
SampleHive::SH_SetStatusBarMessageEvent event(SampleHive::SH_EVT_STATUSBAR_MESSAGE_UPDATED, this->GetId());
|
||||
event.SetEventObject(this);
|
||||
|
||||
event.SetMessageAndSection({ msg, section });
|
||||
|
||||
HandleWindowEvent(event);
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/* SampleHive
|
||||
* Copyright (C) 2021 Apoorv Singh
|
||||
* A simple, modern audio sample browser/manager for GNU/Linux.
|
||||
*
|
||||
* This file is a part of SampleHive
|
||||
*
|
||||
* SampleHive is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SampleHive is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/dataview.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/dc.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/infobar.h>
|
||||
#include <wx/mediactrl.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statusbr.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/window.h>
|
||||
|
||||
class WaveformViewer : public wxPanel
|
||||
{
|
||||
public:
|
||||
WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataViewListCtrl& library,
|
||||
wxMediaCtrl& mediaCtrl, wxInfoBar& infoBar,
|
||||
const std::string& configFilepath, const std::string& databaseFilepath);
|
||||
~WaveformViewer();
|
||||
|
||||
private:
|
||||
// -------------------------------------------------------------------
|
||||
wxWindow* m_ParentFrame;
|
||||
wxWindow* m_Window;
|
||||
|
||||
wxDataViewListCtrl& m_Library;
|
||||
wxInfoBar& m_InfoBar;
|
||||
wxMediaCtrl& m_MediaCtrl;
|
||||
|
||||
const std::string& m_ConfigFilepath;
|
||||
const std::string& m_DatabaseFilepath;
|
||||
|
||||
private:
|
||||
// -------------------------------------------------------------------
|
||||
wxBitmap m_WaveformBitmap;
|
||||
wxColour m_PlayheadColour;
|
||||
wxColour m_WaveformColour;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Selection area coordinates
|
||||
wxPoint m_AnchorPoint;
|
||||
wxPoint m_CurrentPoint;
|
||||
|
||||
private:
|
||||
// -------------------------------------------------------------------
|
||||
bool bBitmapDirty = false;
|
||||
bool bSelectRange = false;
|
||||
bool bDrawSelectedArea = false;
|
||||
bool bAreaSelected = false;
|
||||
|
||||
private:
|
||||
// -------------------------------------------------------------------
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void RenderPlayhead(wxDC& dc);
|
||||
void UpdateWaveformBitmap();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void OnMouseMotion(wxMouseEvent& event);
|
||||
void OnMouseLeftButtonDown(wxMouseEvent& event);
|
||||
void OnMouseLeftButtonUp(wxMouseEvent& event);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void OnControlKeyUp(wxKeyEvent& event);
|
||||
void OnControlKeyDown(wxKeyEvent& event);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Send custom events
|
||||
void SendLoopPoints();
|
||||
void SendStatusBarStatus(const wxString& msg, int section);
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
void ResetDC();
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[wrap-git]
|
||||
url = https://github.com/taglib/taglib.git
|
||||
revision = master
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[wrap-git]
|
||||
url = https://github.com/wxWidgets/wxWidgets
|
||||
revision = master
|
||||