Compare commits

..

73 Commits

Author SHA1 Message Date
apoorv569 97963fd52c Fix spdlog errors during build caused by wxString 2025-09-24 16:11:56 +05:30
apoorv569 3f2bb4551c Update meson.build file
- Bump meson version requirement
- Bump cpp_std to gnu++20
- Bump copyright years to 2020-2025
- Add spdlog cmake options
- Bump wx version requirement to 3.2.8
- Bump sqlite3 version requirement to 3.45.1
- Bump yaml-cpp version requirement to 0.8.0
2025-09-24 16:06:39 +05:30
apoorv569 fd2789d401 Update all meson wrap files. 2025-09-24 16:04:49 +05:30
apoorv569 023d4bca27 Only clone libsndfile and spdlog if not available on system 2023-12-08 02:21:03 +05:30
Apoorv 0f1700fcdc Merge branch 'nimius-testing-patch-44800' into 'testing'
Fixed compilation error for spdlog.

See merge request samplehive/sample-hive!10
2022-11-26 07:38:26 +00:00
apoorv569 eb603be129 Update README add audio dependency. 2022-11-26 02:33:40 +05:30
Lucas Wieling 01dad0c725 Fixed compilation error on Arch Linux as suggested by @apoorv569 2022-11-25 07:36:46 +00:00
apoorv569 7f13c45c40 Fix segmentation fault when using -r flag on the command line and add double click to play a sample. 2022-10-31 15:50:46 +05:30
apoorv569 66ce190098 Add BPM detection using aubio. 2022-09-16 16:44:24 +05:30
apoorv569 c2256d8d2e Revert spdlog version v1.9.2 as v1.10.0 seems to have issues with fmt. 2022-09-16 16:33:47 +05:30
apoorv569 9a3ac45800 Bump wxWidgets version to v3.2.1 and spdlog version to v1.10.0. 2022-09-16 01:15:51 +05:30
apoorv569 491852a756 Add build type define and minor meson build file update. 2022-09-16 01:13:54 +05:30
apoorv569 6d0f66d144 Show milliseconds in addition to minutes and seconds for the length of a sample in the ISO 8601 standard. 2022-03-27 15:29:09 +05:30
apoorv569 293c12a7e0 Remove unnecessary logging statements and database queries. 2022-03-18 17:39:52 +05:30
apoorv569 22f45fbd66 Temporary fix the short sample not looping from beginning. 2022-03-18 17:37:33 +05:30
apoorv569 165e11ce6f Add option to BuyMeACoffee. 2022-03-15 23:02:23 +05:30
apoorv569 023874a9be Add DemoMode for auditioning samples without storing them in database. 2022-03-05 14:35:19 +05:30
apoorv569 3db1e5858e fixup! Add experimental Windows build. 2022-02-15 23:13:37 +05:30
apoorv569 b367a9d895 Add experimental Windows build. 2022-02-15 22:54:44 +05:30
apoorv569 db7a476a1d Add wxBITMAP_TYPE flags to support other platforms. 2022-02-13 20:38:46 +05:30
apoorv569 1ccb616b93 Add option to disable splash on startup and some cleanup. 2022-02-10 20:43:31 +05:30
apoorv569 dde610a78f Add check for darwin and restricted wx to v3.1.5. 2022-02-10 20:42:08 +05:30
apoorv569 c9d3ab8295 Merge branch 'experimental-encapsulation' into testing 2022-02-04 17:42:36 +05:30
apoorv569 a14705f31f Add check for which toolkit to use based on platform and general cleanup. 2022-02-02 00:55:42 +05:30
apoorv569 490012b5eb Fix wxBitmapToggleButton function parameters for the new wx update. 2022-02-02 00:54:48 +05:30
apoorv569 010a798fe5 More encapsulation, lots of reformatting and cleanup. 2022-01-24 02:39:57 +05:30
apoorv569 016fd28d34 fixup! Caught an unhandled exception from libsndfile 2021-12-14 00:36:56 +05:30
apoorv569 9e0be8f55a More encapsulation and add new class Signal for handling custom events. 2021-12-13 23:42:12 +05:30
apoorv569 1e6a0e635b Caught an unhandled exception from libsndfile 2021-12-13 22:20:33 +05:30
apoorv569 7dd7f2b3c1 Separate transport control panel to its own class. 2021-11-16 14:07:48 +05:30
apoorv569 ccda509068 Add serialize option for the splitter window sash position. 2021-11-16 10:35:10 +05:30
apoorv569 1210b5e6ce fixup! Fix database initializing before loading configuration file. 2021-11-14 09:32:04 +05:30
apoorv569 e1d89d0b24 Fix database initializing before loading configuration file. 2021-11-11 04:13:11 +05:30
apoorv569 c9b79a6935 Add serialization for window size, recursive search for files and media volume. 2021-11-10 03:19:37 +05:30
apoorv569 f40f514912 Add new custom events. 2021-11-08 13:22:03 +05:30
apoorv569 77fb65377b Add command line option to reset app data, new Paths header, more code refactoring. 2021-11-07 08:41:04 +05:30
apoorv569 8bfb8c718a Replaced wxLog with spdlog for logging, add spdlog dependency to README. 2021-11-06 18:28:16 +05:30
apoorv569 202cb1e7d8 Fix wxBitmapButton function parameters for the new wx update. 2021-11-06 05:21:07 +05:30
apoorv569 c52d7708d8 Refactoring, organizing files in directories. Add directory watcher, removed unnecessary calls to settings dialog. 2021-11-04 19:16:58 +05:30
apoorv569 5714beab03 fixup! Initial commit on SourceHut 2021-10-25 17:52:44 +05:30
apoorv569 fbf26100e5 Initial commit on SourceHut 2021-10-25 17:50:45 +05:30
apoorv569 0ecf694997 Remove InfoBar from Database. 2021-10-08 15:50:00 +05:30
Apoorv 4630695589 Merge branch 'refactor_database' into 'testing'
Refactor database

See merge request samplehive/sample-hive!7
2021-10-08 07:29:27 +00:00
Mathias Buhr c7005dd559 Checkout submodules as well 2021-10-07 22:48:57 +02:00
Mathias Buhr 3558cac62d Reduce redundant database code 2021-10-07 22:48:18 +02:00
Mathias Buhr 7eccf406dc Use const& for loop 2021-10-07 21:38:37 +02:00
Mathias Buhr e00d753302 Cleanup Database interface 2021-10-07 21:38:34 +02:00
Mathias Buhr 63173df9ad Refactor database 2021-10-07 21:36:19 +02:00
Mathias Buhr f808a8281f Use C++14 2021-10-07 21:23:53 +02:00
apoorv569 fe463fe199 Add yaml-cpp, sqlite3 and libsndfile subprojects. 2021-10-07 12:54:44 +05:30
apoorv569 1a92c58954 fixup! Merge branch 'experimental-draw-waveform' into 'testing' 2021-10-04 14:39:10 +05:30
Apoorv 2e656b057e Merge branch 'experimental-draw-waveform' into 'testing'
Show waveform for the selected sample.

See merge request samplehive/sample-hive!9
2021-10-04 09:01:55 +00:00
apoorv569 101dfa2474 Version bump to v0.9.0_alpha.1, general cleanup and replace screenshots with new, showing off waveform. 2021-10-04 14:15:53 +05:30
apoorv569 3fcea8af12 fixup! fixup! Fix taglib include path for meson subproject and update README for dependencies. 2021-10-03 19:20:02 +05:30
apoorv569 601ff10690 fixup! Fix taglib include path for meson subproject and update README for dependencies. 2021-10-03 18:57:18 +05:30
apoorv569 dd5b5196ee Fix taglib include path for meson subproject and update README for dependencies. 2021-10-03 18:54:21 +05:30
apoorv569 79cb16324a Add wxWidgets and Taglib as meson subprojects, up the version requirement for wxWidgets to v3.1.5 and Taglib to v1.12 add new icons for buttons. 2021-09-30 14:04:54 +05:30
apoorv569 56d6d86f66 Remove unnecessary wxTimer calls. 2021-09-13 04:52:30 +05:30
Apoorv 28cff9a8fe Merge branch 'experimental-draw-waveform' into 'experimental-draw-waveform'
Waveform optimization: split into RMS of chunks instead of drawing every point

See merge request samplehive/sample-hive!8
2021-09-07 22:31:00 +00:00
Tremeschin 86a5c218ac Waveform optimization: split into RMS of chunks instead of drawing every point 2021-09-07 19:05:04 -03:00
apoorv569 0eaf78923c Can loop a region now. 2021-09-05 03:27:18 +05:30
apoorv569 f061fe8a8c Add custom event to send loop points to MainFrame. 2021-08-29 19:45:03 +05:30
apoorv569 627cb76950 Add ability make a selection for loop region. 2021-08-11 02:32:39 +05:30
apoorv569 cf9c3f5551 Fix assert when mouse is click but playhead is not captured and pop status text, when there is no text to pop. 2021-08-03 23:11:46 +05:30
apoorv569 af929cecc2 Waveform panel moved to its own class, add ability to change waveform color and can seek the playhead now. 2021-08-02 09:11:00 +05:30
apoorv569 8aac911f07 Add loop point controls, draw waveform and playhead. 2021-07-30 23:40:45 +05:30
apoorv569 efc67f483c Add details for contributing to SampleHive in README.org 2021-07-25 12:13:01 +05:30
apoorv569 fd9ec9131a Add CONTRIBUTING.org 2021-07-25 12:02:44 +05:30
Apoorv 3e8a6fccaa Update Bug.md 2021-07-25 06:21:31 +00:00
Apoorv 030c6be7c3 Update FeatureRequest.md 2021-07-25 06:21:17 +00:00
apoorv569 85f534aa6e fixup! Add issue templates. 2021-07-25 01:00:14 +05:30
apoorv569 d46bfdf229 Add issue templates. 2021-07-25 00:34:22 +05:30
apoorv569 c49aca13a4 Add command line option to SampleHive version. 2021-07-25 00:32:46 +05:30
84 changed files with 10365 additions and 6543 deletions

42
.dir-locals.el Executable file → Normal file
View File

@ -1,11 +1,35 @@
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
;; (concat (cdr (project-current))
((nil . ((cmake-ide-project-dir . "~/repos/sample-hive")
(cmake-ide-build-dir . "~/repos/sample-hive/build")
(cmake-ide-cmake-opts . "-DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DPORTABLE=1 -DCMAKE_CXX_COMPILER='/usr/bin/g++'")
;; (projectile-project-root . "~/repos/sample-hive")
(projectile-project-name . "SampleHive")
(projectile-project-run-cmd . "~/repos/sample-hive/build/SampleHive")
;; (projectile-project-run-cmd . "/tmp/SampleHive/bin/SampleHive")
(compile-command . "ninja -C ~/repos/sample-hive/build")
(fill-column . 110)
;; Setup dap debugging template for the project
(setq dap-debug-template-configurations
'(("SampleHive::Core::Debug"
:type "gdb"
:request "launch"
:name "SampleHive::Core::Debug"
:target "${workspaceFolder}/build/SampleHive"
;; :target "/tmp/SampleHive/bin/SampleHive"
:cwd "${workspaceFolder}"
:symbolLoadInfo "loadAll"
:additionalSOLibSearchPath "/tmp/SampleHive/bin/"))))))
(cmake-ide-build-dir . "~/repos/sample-hive/build")
(cmake-ide-cmake-opts . "-DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DPORTABLE=1 -DCMAKE_CXX_COMPILER='/usr/bin/g++'")
(projectile-project-name . "SampleHive")
(projectile-project-run-cmd . "~/repos/sample-hive/build/SampleHive")
(projectile-project-test-cmd . "./test.sh"))))
;; ((c++-mode . ((dap-debug-template-configurations . '(("SampleHive::Core::Debug"
;; :type "gdb"
;; :request "launch"
;; :name "SampleHive::Core::Debug"
;; :target "${workspaceFolder}/build/SampleHive"
;; ;; :target "/tmp/SampleHive/bin/SampleHive"
;; :cwd "${workspaceFolder}"
;; :symbolLoadInfo "loadAll"
;; :additionalSOLibSearchPath "/tmp/SampleHive/bin/"))))))

View File

@ -0,0 +1,24 @@
## Quick Information
<!-- This is to help replicate the issue as closely as possible !-->
- **Operating System**
- **Application version**
## What Happened?
<!-- A brief description of what happened when you tried to perform an action !-->
## Expected result
<!-- What should have happened when you performed the actions !-->
## Steps to reproduce
<!-- List the steps required to produce the error. These should be as few as possible !-->
## Screenshots
<!-- Any relevant screenshots which show the issue !-->
## Priority/Severity
<!-- Delete as appropriate. The priority and severity assigned may be different to this !-->
- [ ] High (anything that impacts the normal user flow or blocks app usage)
- [ ] Medium (anything that negatively affects the user experience)
- [ ] Low (anything else e.g., typos, missing icons, layout issues, etc.)
/label ~Bug

View File

@ -0,0 +1,26 @@
## Problem Statement
<!-- What is the issue being faced and needs addressing? !-->
## Who will benefit?
<!-- Will this fix a problem that only one user has, or will it benefit a lot of people !-->
## Benefits and risks
<!--
What benefits does this bring?
What risks might this introduce?
!-->
## Proposed solution
<!-- How would you like to see this issue resolved? !-->
## Examples
<!-- Are there any examples of this which exist in other similar software? !-->
## Priority/Severity
<!-- Delete as appropriate. The priority and severity assigned may be different to this !-->
- [ ] High (This will bring a huge increase in performance/productivity/usability)
- [ ] Medium (This will bring a good increase in performance/productivity/usability)
- [ ] Low (anything else e.g., trivial, minor improvements)
/label ~"Feature request"

229
CONTRIBUTING.org Normal file
View File

@ -0,0 +1,229 @@
#+TITLE: Contributing to SampleHive
#+AUTHOR: Apoorv Singh
#+DESCRIPTION: A simple, modern audio sample browser/manager for GNU/Linux.
* Table Of Contents :toc:
:PROPERTIES:
:CUSTOM_ID: table-of-contents
:END:
- [[#contributing-to-samplehive][Contributing to SampleHive]]
- [[#what-should-i-know-before-i-get-started][What should I know before I get started?]]
- [[#how-can-i-contribute][How Can I Contribute?]]
- [[#styleguides][Styleguides]]
- [[#additional-notes][Additional Notes]]
* Contributing to SampleHive
:PROPERTIES:
:CUSTOM_ID: contributing-to-samplehive
:END:
First off, thanks for taking the time to contribute!
The following is a set of guidelines for contributing to [[https://gitlab.com/samplehive/sample-hive][SampleHive]], which is hosted on [[https://about.gitlab.com/][GitLab]]. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
** What should I know before I get started?
:PROPERTIES:
:CUSTOM_ID: what-should-i-know-before-i-get-started
:END:
** How Can I Contribute?
:PROPERTIES:
:CUSTOM_ID: how-can-i-contribute
:END:
*** Reporting Bugs
:PROPERTIES:
:CUSTOM_ID: reporting-bugs
:END:
This section guides you through submitting a bug report for [[https://gitlab.com/samplehive/sample-hive][SampleHive]]. Following these guidelines helps me and the community understand your report, reproduce the behavior, and find related reports.
Before creating bug reports, please check [[#before-submitting-a-bug-report][this list]] as you might find out that you don't need to create one. When you are creating a bug report, please [[#how-do-i-submit-a-good-bug-report][include as many details as possible]]. Fill out [[https://gitlab.com/samplehive/sample-hive/-/blob/testing/.gitlab/issue_templates/Bug.md][the required template]], the information it asks for helps us resolve issues faster.
#+begin_quote
*Note:* If you find a *Closed* issue that seems like it is the same thing that you're experiencing, do not open a new issue, instead re-open the the old one, and add a comment there, stating any additional details you want to add.
#+end_quote
**** Before Submitting A Bug Report
:PROPERTIES:
:CUSTOM_ID: before-submitting-a-bug-report
:END:
- *Perform a cursory search* to see if the bug has already been reported. If it has, add a comment to the existing issue instead of opening a new one.
**** How Do I Submit A (Good) Bug Report?
:PROPERTIES:
:CUSTOM_ID: how-do-i-submit-a-good-bug-report
:END:
Explain the problem and include additional details to help me reproduce the problem:
- *Use a clear and descriptive title* for the issue to identify the problem.
- *Describe the exact steps which reproduce the problem* in as many details as possible.
- *Describe the behavior you observed after following the steps* and point out what exactly is the problem with that behavior.
- *Explain which behavior you expected to see instead and why.*
- *Include screenshots and animated GIFs* which show you following the described steps and clearly demonstrate the problem. *You can record the GIF using* [[https://github.com/phw/peek][Peek]]
- *If you're reporting that SampleHive crashed*, include a crash report with a stack trace from the operating system.
Include details about your configuration and environment:
- *Which version of SampleHive are you using?* You can get the exact version by opening up the about dialog inside the application or you can run =SampleHive --version= in your terminal.
- *What's the name and version of the Operating System you're using*?
*** Suggesting Enhancements
:PROPERTIES:
:CUSTOM_ID: suggesting-enhancements
:END:
This section guides you through submitting an enhancement suggestion for SampleHive, including completely new features and minor improvements to existing functionality. Following these guidelines helps me and the community understand your suggestion and find related suggestions.
Before creating enhancement suggestions, please check [[#before-submitting-an-enhancement-suggestion][this list]] as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [[#how-do-i-submit-a-good-enhancement-suggestion][include as many details as possible]]. Fill out [[https://gitlab.com/samplehive/sample-hive/-/blob/testing/.gitlab/issue_templates/FeatureRequest.md][the required template]], including the steps that you imagine you would take if the feature you're requesting existed.
**** Before Submitting An Enhancement Suggestion
:PROPERTIES:
:CUSTOM_ID: before-submitting-an-enhancement-suggestion
:END:
- *Perform a cursory search* to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
**** How Do I Submit A (Good) Enhancement Suggestion?
:PROPERTIES:
:CUSTOM_ID: how-do-i-submit-a-good-enhancement-suggestion
:END:
Enhancement suggestions are tracked as [[https://docs.gitlab.com/ee/user/project/issues/][GitLab issues]]. Create an issue and provide the following information:
- *Use a clear and descriptive title* for the issue to identify the suggestion.
- *Provide a step-by-step description of the suggested enhancement* in as many details as possible.
- *Provide specific examples to demonstrate the steps*. Include copy/pasteable snippets which you use in those examples, as [[https://about.gitlab.com/handbook/markdown-guide/][Markdown code blocks]].
- *Describe the current behavior* and *explain which behavior you expected to see instead* and why.
- *Include screenshots and animated GIFs* which help you demonstrate the steps or point out the part of SampleHive which the suggestion is related to. You can use [[https://github.com/phw/peek][Peek]] to record GIFs.
- *Explain why this enhancement would be useful* to most SampleHive users.
- *List some other sample manager/browsers or similar applications where this enhancement exists.*
- *Specify which version of SampleHive you're using.* You can get the exact version by opening up the about dialog inside the application or you can run =SampleHive --version= in your terminal.
- *Specify the name and version of the Operating System you're using.*
*** Pull Requests
:PROPERTIES:
:CUSTOM_ID: pull-requests
:END:
Please follow these steps to have your contribution considered by the maintainers:
1. Follow the [[#styleguides][styleguides]]
** Styleguides
:PROPERTIES:
:CUSTOM_ID: styleguides
:END:
*** Git Commit Messages
:PROPERTIES:
:CUSTOM_ID: git-commit-messages
:END:
- Use the present tense ("Add feature" not "Added feature")
*** C++ Styleguide
:PROPERTIES:
:CUSTOM_ID: c-styleguide
:END:
- Formatting the body, spacing and where to put the reference or pointer symbol
#+begin_src c++
// Use this
int Function(int* param, std::string& anotherParam)
{
// 4 spaces
}
// Instead of
int function ( int *param, std::string &another_param ) {
// Tabs
}
#+end_src
- Using =if= =else= =for= =while= or any of the similar statements
- You can leave the ={}= if there is only a single line of code after
the statements
#+begin_src c++
// Use this:
if (condition)
{
// some code here
}
else
{
// some code here
}
// Instead of
if( condition ) {
// some code here
}
else {
// some code here
}
#+end_src
- Variable names
#+begin_src c++
// Member variables
int m_SomeVar; // for stack allocated
int* m_pSomeVar; // for heap allocated
bool m_bSomeVar; // for booleans
// Local variables
int some_var; // for stack allocated
int* someVar; // for heap allocated
bool some_var; // for booleans
#+end_src
- Classes and structs
#+begin_src c++
// Use this
class cMyClass : public cSomeOtherClass
{
public:
MyClass();
~MyClass();
private:
// private stuff
};
// Instead of
class myClass : public someOtherClass {
public:
MyClass();
~MyClass();
private:
// private stuff
};
#+end_src
** Additional Notes
:PROPERTIES:
:CUSTOM_ID: additional-notes
:END:
*** Issue and Pull Request Labels
:PROPERTIES:
:CUSTOM_ID: issue-and-pull-request-labels
:END:
This section lists the labels I use to help me track and manage issues and pull requests.
**** Issue Labels
:PROPERTIES:
:CUSTOM_ID: issue-labels
:END:
| Label name | Description |
|---------------------------+------------------------------------------------------------------------------------------------------------|
| =Enhancement= | Issues related to improving the project in some way. |
| =Bug= | Confirmed bugs or reports that are very likely to be bugs. |
| =Question= | Questions more than bug reports or feature requests (e.g. how do I do X). |
| =Feedback= | General feedback more than bug reports or feature requests. |
| =Help wanted= | Issues about user(s) needing help. |
| =More information needed= | More information needs to be collected about these problems or feature requests (e.g. steps to reproduce). |
| =Needs reproduction= | Likely bugs, but haven't been reliably reproduced. |
| =Duplicate= | Issues which are duplicates of other issues, i.e. they have been reported before. |
**** Pull Request Labels
:PROPERTIES:
:CUSTOM_ID: pull-request-labels
:END:
| Label name | Description |
|--------------------+------------------------------------------------------------------------------------------|
| =Work in progress= | Pull requests which are still being worked on, more changes will follow. |
| =Needs review= | Pull requests which need code review, and approval from maintainers. |
| =Under review= | Pull requests being reviewed by maintainers. |
| =Requires changes= | Pull requests which need to be updated based on review comments and then reviewed again. |
| =Needs testing= | Pull requests which need manual testing. |

View File

@ -25,6 +25,8 @@
- [[#how-to-run-samplehive][How to run SampleHive?]]
- [[#are-there-any-keybindings-for-samplehive][Are there any keybindings for SampleHive?]]
- [[#can-i-configure-samplehive][Can I configure SampleHive?]]
- [[#how-do-i-contribute-to-the-samplehive][How do I contribute to the SampleHive?]]
- [[#want-to-buy-me-a-coffee][Want to BuyMeACoffee?]]
** What is SampleHive?
:PROPERTIES:
@ -46,19 +48,27 @@ SampleHive let's you manage your audio samples in a nice and simple way, just ad
:END:
On Arch based distributions,
#+begin_example
sudo pacman -S wxgtk3 wxsvg sqlite taglib yaml-cpp
#+end_example
#+begin_src
sudo pacman -S wxgtk3 sqlite taglib yaml-cpp libsndfile spdlog aubio
#+end_src
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
#+end_example
#+begin_src
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 libspdlog-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev libaubio-dev
#+end_src
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=
*Experimental Windows Build*:
If you want to try out =SampleHive= on =Windows=, you can use the [[https://www.msys2.org/][MSYS2]] environment and [[https://osdn.net/projects/mingw/][MinGW]] compiler for =Windows=. After setting up =MSYS2= and =MinGW= install the following dependencies using the package manager =pacman=.
#+begin_src
pacman -S mingw-w64-x86_64-wxmsw3.1 mingw-w64-x86_64-sqlite mingw-w64-x86_64-taglib mingw-w64-x86_64-yaml-cpp mingw-w64-x86_64-libsndfile mingw-w64-x86_64-spdlog mingw-w64-x86_64-aubio mingw-w64-x86_64-meson mingw-w64-x86_64-cmake git
#+end_src
** How to build SampleHive?
:PROPERTIES:
@ -105,3 +115,16 @@ If you didn't provide a prefix, you can find SampleHive in your menu system or r
:CUSTOM_ID: can-i-configure-samplehive
:END:
SampleHive comes with a =config.yaml= file, that is placed under =~/.config/SampleHive/config.yaml=, that you can edit to change some settings for it.
** How do I contribute to the SampleHive?
:PROPERTIES:
:CUSTOM_ID: how-do-i-contribute-to-samplehive
:END:
Want to help by contributing to =SampleHive=, please check out [[https://gitlab.com/samplehive/sample-hive/-/blob/testing/CONTRIBUTING.org][CONTRIBUTING.org]] for more details.
** Want to BuyMeACoffee?
:PROPERTIES:
:CUSTOM_ID: want-to-buy-me-a-coffee
:END:
#+begin_html
<a href="https://www.buymeacoffee.com/apoorv569"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=apoorv569&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff" /></a>
#+end_html

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 176 KiB

View File

@ -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

331
meson.build Executable file → Normal file
View File

@ -17,13 +17,52 @@
# 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',
version : 'v0.8.4_alpha.1',
project('SampleHive',
'cpp',
version : 'v0.9.0_alpha.1',
license : 'GPL v3',
default_options : ['warning_level=1',
'cpp_std=c++11'])
meson_version: '>= 1.5.2',
default_options : ['warning_level=2',
'buildtype=debugoptimized',
'b_lto=true',
'b_lto_threads=2',
'cpp_std=gnu++20'])
# Create configuration data
config_data = configuration_data()
# Save project information
meson_src_root = meson.current_source_dir()
meson_build_root = meson.current_build_dir()
project_name = meson.project_name()
project_license = meson.project_license()
project_version = meson.project_version()
project_author = 'Apoorv'
project_copyright_years = '2020-2025'
project_description = 'A simple, modern audio sample browser/manager for GNU/Linux.'
project_website = 'http://samplehive.gitlab.io/website'
build_type = get_option('buildtype')
host_sys = host_machine.system()
cpp_compiler_id = meson.get_compiler('cpp').get_id()
cpp_compiler_version = meson.get_compiler('cpp').version()
config_data.set_quoted('PROJECT_NAME', project_name)
config_data.set_quoted('PROJECT_LICENSE', project_license)
config_data.set_quoted('PROJECT_VERSION', project_version)
config_data.set_quoted('PROJECT_AUTHOR', project_author)
config_data.set_quoted('PROJECT_COPYRIGHT_YEARS', project_copyright_years)
config_data.set_quoted('PROJECT_DESCRIPTION', project_description)
config_data.set_quoted('PROJECT_WEBSITE', project_website)
config_data.set_quoted('BUILD_TYPE', build_type)
config_data.set_quoted('HOST_MACHINE', host_sys)
config_data.set_quoted('MESON_SRC_ROOT', meson_src_root)
config_data.set_quoted('MESON_BUILD_ROOT', meson_build_root)
config_data.set_quoted('CPP_COMPILER', cpp_compiler_id)
config_data.set_quoted('CPP_COMPILER_VERSION', cpp_compiler_version)
# Save important directories
prefix = get_option('prefix')
@ -32,59 +71,277 @@ libdir = prefix / get_option('libdir')
datadir = prefix / get_option('datadir')
samplehive_datadir = datadir / 'SampleHive'
# Create configuration data
config_data = configuration_data()
config_data.set_quoted('PREFIX', prefix)
config_data.set_quoted('BINDIR', bindir)
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,
)
if build_type == 'debug' or build_type == 'debugoptimized'
config_data.set('SH_BUILD_DEBUG', 1)
elif build_type == 'release'
config_data.set('SH_BUILD_RELEASE', 1)
endif
# Import CMake
cmake = import('cmake')
# Check which platform the build is for and set the appropriate GUI toolkit
wx_toolkit = ''
if host_sys == 'linux'
wx_toolkit = 'gtk3'
elif host_sys == 'windows'
wx_toolkit = 'msw'
elif host_sys == 'darwin'
wx_toolkit = 'osx_cocoa'
endif
wx_opts = cmake.subproject_options()
wx_opts.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON',
'CMAKE_INSTALL_PREFIX': prefix,
'CMAKE_BUILD_TYPE': 'Release',
'wxBUILD_SHARED': 'OFF',
'wxBUILD_MONOLITHIC': 'OFF',
'wxBUILD_BENCHMARKS': 'OFF',
'wxBUILD_PRECOMP': 'OFF',
'wxBUILD_TESTS': 'OFF',
'wxBUILD_SAMPLES': 'OFF',
'wxBUILD_DEMOS': 'OFF',
'wxBUILD_COMPATIBILITY': '3.2',
'wxBUILD_TOOLKIT': wx_toolkit,
'wxUSE_UNICODE': 'ON',
'wxUSE_GUI': '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_POSTSCRIPT': 'ON',
'wxUSE_RICHTEXT': 'OFF',
'wxUSE_WEBVIEW': 'OFF',
'wxUSE_LIBSDL': 'OFF',
'wxUSE_MEDIACTRL': 'ON'})
spdlog_opts = cmake.subproject_options()
spdlog_opts.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON',
'CMAKE_INSTALL_PREFIX': prefix,
'CMAKE_BUILD_TYPE': 'Release',
'SPDLOG_USE_STD_FORMAT': 'ON',
'SPDLOG_BUILD_EXAMPLE': 'OFF',
'SPDLOG_BUILD_EXAMPLE_HO': 'OFF',
'SPDLOG_BUILD_TESTS': 'OFF',
'SPDLOG_BUILD_TESTS_HO': 'OFF',
'SPDLOG_BUILD_BENCH': 'OFF'})
taglib_opts = cmake.subproject_options()
taglib_opts.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON',
'CMAKE_INSTALL_PREFIX': prefix,
'CMAKE_BUILD_TYPE': 'Release'})
yaml_opts = cmake.subproject_options()
yaml_opts.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON',
'CMAKE_INSTALL_PREFIX': prefix,
'CMAKE_BUILD_TYPE': 'Release',
'YAML_BUILD_SHARED_LIBS': 'ON',
'YAML_CPP_BUILD_TESTS': 'OFF',
'YAML_CPP_BUILD_CONTRIB': 'ON',
'YAML_CPP_BUILD_TOOLS': 'ON'})
snd_opts = cmake.subproject_options()
snd_shared = ''
if host_sys == 'windows'
snd_shared = 'OFF'
else
snd_shared = 'ON'
endif
snd_opts.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON',
'CMAKE_INSTALL_PREFIX': prefix,
'CMAKE_BUILD_TYPE': 'Release',
'BUILD_SHARED_LIBS': snd_shared,
'BUILD_PROGRAMS': 'OFF',
'BUILD_EXAMPLES': 'OFF',
'BUILD_TESTING': 'OFF',
'ENABLE_EXTERNAL_LIBS': 'ON',
'ENABLE_MPEG': 'ON'})
# Disable link time optimization if host is Windows
if host_sys == 'windows'
wx_opts.set_override_option('b_lto', 'false')
taglib_opts.set_override_option('b_lto', 'false')
yaml_opts.set_override_option('b_lto', 'false')
snd_opts.set_override_option('b_lto', 'false')
endif
# Source files to be compiled
src = [
'src/App.cpp',
'src/MainFrame.cpp',
'src/SettingsDialog.cpp',
'src/TagEditorDialog.cpp',
'src/Database.cpp',
'src/Sample.cpp',
'src/Serialize.cpp',
'src/Tags.cpp',
'src/GUI/MainFrame.cpp',
'src/GUI/TransportControls.cpp',
'src/GUI/WaveformViewer.cpp',
'src/GUI/Notebook.cpp',
'src/GUI/DirectoryBrowser.cpp',
'src/GUI/Hives.cpp',
'src/GUI/Trash.cpp',
'src/GUI/ListCtrl.cpp',
'src/GUI/SearchBar.cpp',
'src/GUI/InfoBar.cpp',
'src/GUI/Library.cpp',
'src/GUI/Dialogs/Settings.cpp',
'src/GUI/Dialogs/TagEditor.cpp',
'src/Database/Database.cpp',
'src/Utility/Sample.cpp',
'src/Utility/Serialize.cpp',
'src/Utility/Tags.cpp',
'src/Utility/Event.cpp',
'src/Utility/Signal.cpp',
'src/Utility/Log.cpp',
'src/Utility/Utils.cpp',
]
wxconfig = find_program(['wx-config-gtk3', 'wx-config'])
wx_modules = ['media', 'std']
include_dirs = include_directories('src')
# Static link C and CXX libs if platform is windows
link_args = []
if host_sys == 'windows'
link_args += ['-static-libgcc', '-static-libstdc++']
endif
# Dependencies
wx = dependency('wxwidgets', version: '>=3.2.8', required: true)
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
if not wx.found()
wx_subproject = cmake.subproject('wxwidgets', options: wx_opts)
wx_media = wx_subproject.dependency('wxmedia')
wx_core = wx_subproject.dependency('wxcore')
wx_base = wx_subproject.dependency('wxbase')
wx = [wx_media, wx_core, wx_base]
# Dependencies
wx = dependency('wxwidgets', version: '>=3.0.4')
taglib = dependency('taglib', version: '>=1.11')
sqlite3 = dependency('sqlite3')
yaml = dependency('yaml-cpp')
if host_sys == 'windows'
win = import('windows')
wx_inc = wx_subproject.include_directories('wxbase')
rc_file = win.compile_resources('src/GUI/Resources.rc', include_directories: wx_inc)
install_subdir(
'assets',
install_dir: samplehive_datadir,
exclude_directories: 'screenshots'
)
src += rc_file
endif
else
wxconfig = find_program(['wx-config', 'wx-config-gtk3', 'wx-config-3.2'])
wx_modules = ['media', 'std']
foreach module : wx_modules
wx_cxx_flags += run_command(wxconfig, '--cxxflags', module, capture: true, check: false).stdout().strip().split()
wx_libs += run_command(wxconfig, '--libs', module, capture: true, check: false).stdout().strip().split()
endforeach
endif
taglib = dependency('taglib', version: '>=1.12', required: true)
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', version: '>=3.45.1', required: true)
if not sqlite3.found()
sqlite3_subproject = subproject('sqlite3')
libsqlite3 = sqlite3_subproject.get_variable('libsqlite3')
sqlite3 = declare_dependency(link_with: libsqlite3)
endif
yaml = dependency('yaml-cpp', version: '>=0.8.0', required: true)
if not yaml.found()
yaml_subproject = cmake.subproject('yaml-cpp', options: yaml_opts)
yaml = yaml_subproject.dependency('yaml-cpp')
endif
snd = dependency('sndfile', version: '>=1.2.0', required: true)
if not snd.found()
snd_subproject = cmake.subproject('libsndfile', options: snd_opts)
snd = snd_subproject.dependency('sndfile')
endif
spdlog = dependency('spdlog', version: '>=1.12.0', required: true)
if not spdlog.found()
spdlog_subproject = cmake.subproject('spdlog', options: spdlog_opts)
spdlog = spdlog_subproject.dependency('spdlog')
endif
aubio = dependency('aubio', version: '>=0.4.9', required: true)
if not aubio.found()
aubio_subproject = subproject('aubio')
aubio = aubio_subproject.get_variable('aubio_dep')
endif
# Create SampleHiveConfig.hpp based on configuration
config = configure_file(output: 'SampleHiveConfig.hpp',
configuration: config_data,)
install_subdir('assets',
install_dir: samplehive_datadir,
exclude_directories: 'screenshots',
strip_directory: true)
executable('SampleHive',
sources: src,
cpp_args: [wx_cxx_flags],
link_args: [wx_libs],
dependencies: [wx, taglib, sqlite3, yaml],
install: true)
link_args: [wx_libs, link_args],
include_directories : include_dirs,
dependencies: [wx, taglib, sqlite3, yaml, snd, spdlog, aubio],
install: true,
install_rpath: prefix / 'lib')
summary(
{
'Build type': build_type,
'Optimization': get_option('optimization'),
'Link time optimization': get_option('b_lto'),
'Warning level': get_option('warning_level'),
'Host system': host_sys,
},
section: 'General')
summary(
{
'prefix': prefix,
'bindir': bindir,
'libdir': libdir,
'datadir': datadir,
'samplehive_datadir': samplehive_datadir,
},
section: 'Directories')
summary(
{
'Project name': project_name,
'Project license': project_license,
'Project version': project_version,
'Project author': project_author,
'Project copyright years': project_copyright_years,
'Project description': project_description,
'Project website': project_website,
},
section: 'Project')

View File

@ -19,47 +19,159 @@
*/
#include "App.hpp"
#include "SampleHiveConfig.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Log.hpp"
#include <wx/bitmap.h>
#include <wx/defs.h>
#include <wx/filefn.h>
#include <wx/fswatcher.h>
#include <wx/gdicmn.h>
#include <wx/splash.h>
#include <wx/image.h>
#include <wx/imagpng.h>
#define SPLASH_LOGO SAMPLEHIVE_DATADIR "/assets/logo/logo-samplehive_768x432.png"
wxIMPLEMENT_APP(cApp);
wxIMPLEMENT_APP(App);
App::App()
cApp::cApp()
{
// Initialize the logger
SampleHive::cLog::InitLogger("SampleHive");
}
App::~App()
cApp::~cApp()
{
}
bool App::OnInit()
bool cApp::OnInit()
{
if (!wxApp::OnInit())
return false;
m_Frame = new MainFrame();
SampleHive::cSerializer serializer;
wxLog::AddTraceMask("EventSource");
wxLog::AddTraceMask(wxTRACE_FSWATCHER);
// Add image handler for PNG
wxImage::AddHandler(new wxPNGHandler);
m_pFrame = new cMainFrame();
wxBitmap bitmap;
wxSplashScreen* splash;
if (bitmap.LoadFile(SPLASH_LOGO, wxBITMAP_TYPE_PNG))
{
splash = new wxSplashScreen(bitmap,
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT,
2000, NULL, -1, wxDefaultPosition, wxDefaultSize,
wxBORDER_SIMPLE | wxSTAY_ON_TOP);
m_pSplash = new wxSplashScreen(bitmap,
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT,
2000, NULL, -1, wxDefaultPosition, wxDefaultSize,
wxBORDER_SIMPLE | wxSTAY_ON_TOP);
}
if (!serializer.DeserializeShowSplash())
m_pSplash->Hide();
else
m_pSplash->Show();
wxYield();
m_Frame->Show(true);
m_pFrame->Show(true);
return true;
}
void cApp::OnInitCmdLine(wxCmdLineParser& parser)
{
wxApp::OnInitCmdLine(parser);
parser.AddSwitch("v", "version", "Shows the application version", 0);
parser.AddSwitch("r", "reset", "Reset app data", 0);
parser.Parse(true);
}
bool cApp::OnCmdLineParsed(wxCmdLineParser& parser)
{
if (!wxApp::OnCmdLineParsed(parser))
return false;
if (parser.Found("version"))
{
std::cout << PROJECT_NAME << ' ' << PROJECT_VERSION << std::endl;
std::cout <<
"\nCopyright (C) 2021 Apoorv Singh"
"\nA simple, modern audio sample browser/manager for GNU/Linux."
"\n"
"\nThis file is a part of SampleHive"
"\n"
"\nSampleHive is free software: you can redistribute it and/or modify"
"\nit under the terms of the GNU General Public License as published by"
"\nthe Free Software Foundation, either version 3 of the License, or"
"\n(at your option) any later version."
"\n"
"\nSampleHive is distributed in the hope that it will be useful,"
"\nbut WITHOUT ANY WARRANTY; without even the implied warranty of"
"\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"
"\nGNU General Public License for more details."
"\n"
"\nYou should have received a copy of the GNU General Public License"
"\nalong with this program. If not, see <https://www.gnu.org/licenses/>."
<< std::endl;
return false;
}
else if (parser.Found("reset"))
{
char ans;
std::cout << "Are you sure you want clear all app data? [y/N] ";
std::cin >> ans;
if (ans == 'y' || ans == 'Y')
{
if (!wxFileExists(static_cast<std::string>(CONFIG_FILEPATH)))
{
SH_LOG_ERROR("Error! File {} doesn't exist.", static_cast<std::string>(CONFIG_FILEPATH));
return false;
}
bool config_is_deleted = wxRemoveFile(static_cast<std::string>(CONFIG_FILEPATH));
if (config_is_deleted)
SH_LOG_INFO("Deleted {}", static_cast<std::string>(CONFIG_FILEPATH));
else
SH_LOG_ERROR("Could not delete {}", static_cast<std::string>(CONFIG_FILEPATH));
if (!wxFileExists(static_cast<std::string>(DATABASE_FILEPATH)))
{
SH_LOG_ERROR("Error! File {} doesn't exist.", static_cast<std::string>(DATABASE_FILEPATH));
return false;
}
bool db_is_deleted = wxRemoveFile(static_cast<std::string>(DATABASE_FILEPATH));
if (db_is_deleted)
SH_LOG_INFO("Deleted {}", static_cast<std::string>(DATABASE_FILEPATH));
else
SH_LOG_ERROR("Could not delete {}", static_cast<std::string>(DATABASE_FILEPATH));
if (config_is_deleted && db_is_deleted)
SH_LOG_INFO("Successfully cleared app data");
else
SH_LOG_ERROR("Error! Could not clear app data");
return false;
}
else if (ans == 'n' || ans == 'N')
return false;
else
{
SH_LOG_ERROR("Unknown option '{}' please select a correct option", ans);
return false;
}
}
return true;
}
void cApp::OnEventLoopEnter(wxEventLoopBase* event)
{
if (m_pFrame->CreateWatcherIfNecessary())
SH_LOG_INFO("Filesystem watcher created sucessfully");
}

View File

@ -20,19 +20,25 @@
#pragma once
#include "GUI/MainFrame.hpp"
#include <wx/app.h>
#include <wx/cmdline.h>
#include <wx/splash.h>
#include "MainFrame.hpp"
class App : public wxApp
class cApp : public wxApp
{
public:
App();
~App();
private:
MainFrame* m_Frame = nullptr;
cApp();
~cApp();
private:
virtual bool OnInit();
virtual void OnEventLoopEnter(wxEventLoopBase* event);
virtual void OnInitCmdLine(wxCmdLineParser& parser);
virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
private:
wxSplashScreen* m_pSplash = nullptr;
cMainFrame* m_pFrame = nullptr;
};

View File

@ -1,113 +0,0 @@
/* 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 <wx/defs.h>
enum ControlIDs
{
/*
** BC = Browser control
** SD = Settings dialog
** MN = Popup menu
** ET = Edit tag dialog
*/
// -------------------------------------------------------------------
// Browser controls
BC_Play = wxID_HIGHEST + 1,
BC_Settings,
BC_Loop,
BC_Stop,
BC_Mute,
BC_Autoplay,
BC_Volume,
BC_SamplePosition,
BC_Hives,
BC_DirCtrl,
BC_Library,
BC_Search,
BC_MediaCtrl,
BC_Trash,
BC_RestoreTrashedItem,
BC_HiveAdd,
BC_HiveRemove,
// -------------------------------------------------------------------
// Setting dialog controls
SD_BrowseConfigDir,
SD_BrowseDatabaseDir,
SD_AutoImport,
SD_ShowFileExtension,
SD_BrowseAutoImportDir,
SD_FontType,
SD_FontSize,
SD_FontBrowseButton,
// -------------------------------------------------------------------
// App Menu items
MN_AddFile,
MN_AddDirectory,
MN_ToggleExtension,
MN_ToggleMenuBar,
MN_ToggleStatusBar,
// -------------------------------------------------------------------
// Library Menu items
MN_FavoriteSample,
MN_DeleteSample,
MN_TrashSample,
MN_EditTagSample,
MN_OpenFile,
// -------------------------------------------------------------------
// Library Column Header Menu items
MN_ColumnFavorite,
MN_ColumnFilename,
MN_ColumnSamplePack,
MN_ColumnType,
MN_ColumnChannels,
MN_ColumnLength,
MN_ColumnSampleRate,
MN_ColumnBitrate,
MN_ColumnPath,
// -------------------------------------------------------------------
// Hives Menu items
MN_RenameHive,
MN_DeleteHive,
MN_RemoveSample,
MN_FilterLibrary,
MN_ShowInLibrary,
// -------------------------------------------------------------------
// Trash Menu items
MN_DeleteTrash,
MN_RestoreTrashedItem,
// -------------------------------------------------------------------
// Edit tags dialog controls
ET_TitleCheck,
ET_ArtistCheck,
ET_AlbumCheck,
ET_GenreCheck,
ET_CommentsCheck,
ET_TypeCheck,
ET_CustomTag,
};

File diff suppressed because it is too large Load Diff

View File

@ -1,112 +0,0 @@
/* 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 <string>
#include <vector>
#include <iostream>
#include <wx/dataview.h>
#include <wx/infobar.h>
#include <wx/treebase.h>
#include <wx/treectrl.h>
#include <wx/vector.h>
#include <wx/variant.h>
#include <sqlite3.h>
#include "Sample.hpp"
class Database
{
public:
Database(wxInfoBar& infoBar);
~Database();
private:
// -------------------------------------------------------------------
sqlite3* m_Database;
int rc;
char* m_ErrMsg;
sqlite3_stmt* m_Stmt;
private:
// -------------------------------------------------------------------
wxInfoBar& m_InfoBar;
public:
// -------------------------------------------------------------------
// Create the table
void CreateTableSamples(const std::string& dbPath);
void CreateTableHives(const std::string& dbPath);
// -------------------------------------------------------------------
// Insert into database
void InsertIntoSamples(const std::string& dbPath, std::vector<Sample>);
void InsertIntoHives(const std::string& dbPath, const std::string& hiveName);
// -------------------------------------------------------------------
// Update database
void UpdateFavoriteColumn(const std::string& dbPath, const std::string& filename, int value);
void UpdateHive(const std::string& dbPath, const std::string& hiveOldName, const std::string& hiveNewName);
void UpdateHiveName(const std::string& dbPath, const std::string& filename, const std::string& hiveName);
void UpdateTrashColumn(const std::string& dbPath, const std::string& filename, int value);
void UpdateSamplePack(const std::string& dbPath, const std::string& filename, const std::string& samplePack);
void UpdateSampleType(const std::string& dbPath, const std::string& filename, const std::string& type);
// -------------------------------------------------------------------
// Get from database
int GetFavoriteColumnValueByFilename(const std::string& dbPath, const std::string& filename);
std::string GetHiveByFilename(const std::string& dbPath, const std::string& filename);
std::string GetSamplePathByFilename(const std::string& dbPath, const std::string& filename);
std::string GetSampleFileExtension(const std::string& dbPath, const std::string& filename);
std::string GetSampleType(const std::string& dbPath, const std::string& filename);
// -------------------------------------------------------------------
// Check database
bool IsTrashed(const std::string& dbPath, const std::string& filename);
wxArrayString CheckDuplicates(const std::string& dbPath, const wxArrayString& files);
// -------------------------------------------------------------------
// Remove from database
void RemoveSampleFromDatabase(const std::string& dbPath, const std::string& filename);
void RemoveHiveFromDatabase(const std::string& dbPath, const std::string& hiveName);
// -------------------------------------------------------------------
wxVector<wxVector<wxVariant>>
// LoadDatabase(wxVector<wxVector<wxVariant>> &vecSet,
// wxTreeCtrl& favorite_tree, wxTreeItemId& favorite_item,
// wxTreeCtrl& trash_tree, wxTreeItemId& trash_item, bool show_extension);
LoadSamplesDatabase(const std::string& dbPath, wxVector<wxVector<wxVariant>>& vecSet,
wxDataViewTreeCtrl& favorite_tree, wxDataViewItem& favorite_item,
wxTreeCtrl& trash_tree, wxTreeItemId& trash_item, bool show_extension,
const std::string& icon_star_filled, const std::string& icon_star_emtpy);
void LoadHivesDatabase(const std::string& dbPath, wxDataViewTreeCtrl& favorite_tree);
wxVector<wxVector<wxVariant>>
RestoreFromTrashByFilename(const std::string& dbPath, const std::string& filename,
wxVector<wxVector<wxVariant>>& vecSet, bool show_extension,
const std::string& icon_star_filled, const std::string& icon_star_empty);
wxVector<wxVector<wxVariant>>
FilterDatabaseBySampleName(const std::string& dbPath, wxVector<wxVector<wxVariant>>& sampleVec,
const std::string& sampleName, bool show_extension,
const std::string& icon_star_filled, const std::string& icon_star_empty);
wxVector<wxVector<wxVariant>>
FilterDatabaseByHiveName(const std::string& dbPath, wxVector<wxVector<wxVariant>>& sampleVec,
const std::string& hiveName, bool show_extension,
const std::string& icon_star_filled, const std::string& icon_star_empty);
};

1057
src/Database/Database.cpp Normal file

File diff suppressed because it is too large Load Diff

112
src/Database/Database.hpp Normal file
View File

@ -0,0 +1,112 @@
/* 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 "Utility/Sample.hpp"
#include <string>
#include <vector>
#include <iostream>
#include <wx/dataview.h>
#include <wx/infobar.h>
#include <wx/treebase.h>
#include <wx/treectrl.h>
#include <wx/vector.h>
#include <wx/variant.h>
#include <sqlite3.h>
class cDatabase
{
public:
cDatabase();
~cDatabase();
private:
// -------------------------------------------------------------------
sqlite3* m_pDatabase = nullptr;
int rc;
char* m_pErrMsg = nullptr;
private:
// -------------------------------------------------------------------
void OpenDatabase();
void CloseDatabase();
void OpenTemporaryDatabase();
public:
// -------------------------------------------------------------------
// Create the table
void CreateTableSamples();
void CreateTableHives();
// -------------------------------------------------------------------
// Insert into database
void InsertIntoSamples(const std::vector<Sample>&);
void InsertIntoHives(const std::string& hiveName);
// -------------------------------------------------------------------
// Update database
void UpdateFavoriteColumn(const std::string& filename, int value);
void UpdateHive(const std::string& hiveOldName, const std::string& hiveNewName);
void UpdateHiveName(const std::string& filename, const std::string& hiveName);
void UpdateTrashColumn(const std::string& filename, int value);
void UpdateSamplePack(const std::string& filename, const std::string& samplePack);
void UpdateSampleType(const std::string& filename, const std::string& type);
// -------------------------------------------------------------------
// Get from database
int GetFavoriteColumnValueByFilename(const std::string& filename);
std::string GetHiveByFilename(const std::string& filename);
std::string GetSamplePathByFilename(const std::string& filename);
std::string GetSampleFileExtension(const std::string& filename);
std::string GetSampleType(const std::string& filename);
// -------------------------------------------------------------------
// Check database
bool IsTrashed(const std::string& filename);
wxArrayString CheckDuplicates(const wxArrayString& files);
// -------------------------------------------------------------------
// Remove from database
void RemoveSampleFromDatabase(const std::string& filename);
void RemoveHiveFromDatabase(const std::string& hiveName);
void DeleteAllSamples();
// -------------------------------------------------------------------
wxVector<wxVector<wxVariant>>
LoadSamplesDatabase(wxDataViewTreeCtrl& favorite_tree, wxDataViewItem& favorite_item,
wxTreeCtrl& trash_tree, wxTreeItemId& trash_item, bool show_extension,
const std::string& icon_star_filled, const std::string& icon_star_emtpy);
void LoadHivesDatabase(wxDataViewTreeCtrl& favorite_tree);
wxVector<wxVector<wxVariant>>
RestoreFromTrashByFilename(const std::string& filename,
wxVector<wxVector<wxVariant>>& vecSet, bool show_extension,
const std::string& icon_star_filled, const std::string& icon_star_empty);
wxVector<wxVector<wxVariant>>
FilterDatabaseBySampleName(const std::string& sampleName, bool show_extension,
const std::string& icon_star_filled, const std::string& icon_star_empty);
wxVector<wxVector<wxVariant>>
FilterDatabaseByHiveName(const std::string& hiveName, bool show_extension,
const std::string& icon_star_filled, const std::string& icon_star_empty);
};

View File

@ -0,0 +1,534 @@
/* 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 "GUI/Dialogs/Settings.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Serialize.hpp"
#include <wx/defs.h>
#include <wx/gdicmn.h>
#include <wx/stringimpl.h>
#include <wx/settings.h>
cSettings::cSettings(wxWindow *window)
: wxDialog(window, wxID_ANY, "cSettings", wxDefaultPosition,
wxSize(720, 300), wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP),
m_pWindow(window)
{
m_pPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_pMainSizer = new wxBoxSizer(wxVERTICAL);
m_pNotebookSizer = new wxBoxSizer(wxVERTICAL);
m_pButtonSizer = new wxBoxSizer(wxHORIZONTAL);
m_pNotebook = new wxNotebook(m_pPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, _T("NOTEBOOK"));
m_pDisplaySettingPanel = new wxPanel(m_pNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_pDisplayTopSizer = new wxBoxSizer(wxVERTICAL);
m_pDisplayFontSizer = new wxBoxSizer(wxHORIZONTAL);
m_pWaveformColourSizer = new wxBoxSizer(wxHORIZONTAL);
SampleHive::cSerializer serializer;
wxString fontChoices[] = { "System default" };
m_pFontTypeText = new wxStaticText(m_pDisplaySettingPanel, wxID_ANY, "Font", wxDefaultPosition, wxDefaultSize, 0);
m_pFontType = new wxChoice(m_pDisplaySettingPanel, SampleHive::ID::SD_FontType,
wxDefaultPosition, wxDefaultSize, 1, fontChoices, 0);
m_pFontType->SetSelection(0);
m_pFontSize = new wxSpinCtrl(m_pDisplaySettingPanel, SampleHive::ID::SD_FontSize, "Default", wxDefaultPosition, wxDefaultSize);
m_pFontSize->SetValue(window->GetFont().GetPointSize());
m_pFontBrowseButton = new wxButton(m_pDisplaySettingPanel, SampleHive::ID::SD_FontBrowseButton, "Select font",
wxDefaultPosition, wxDefaultSize, 0);
m_pWaveformColourLabel = new wxStaticText(m_pDisplaySettingPanel, wxID_ANY, "Waveform colour",
wxDefaultPosition, wxDefaultSize, 0);
m_pWaveformColourPickerCtrl = new wxColourPickerCtrl(m_pDisplaySettingPanel, SampleHive::ID::SD_WaveformColourPickerCtrl,
serializer.DeserializeWaveformColour(),
wxDefaultPosition, wxDefaultSize,
wxCLRP_DEFAULT_STYLE);
m_pShowSplashCheck = new wxCheckBox(m_pDisplaySettingPanel, SampleHive::ID::SD_ShowSplash, "Show splash on startup",
wxDefaultPosition, wxDefaultSize, 0);
m_pShowSplashCheck->SetValue(serializer.DeserializeShowSplash());
m_pCollectionSettingPanel = new wxPanel(m_pNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_pCollectionMainSizer = new wxBoxSizer(wxVERTICAL);
m_pCollectionImportDirSizer = new wxBoxSizer(wxHORIZONTAL);
m_pCollectionImportOptionsSizer = new wxBoxSizer(wxHORIZONTAL);
m_pCollectionShowExtensionSizer = new wxBoxSizer(wxVERTICAL);
m_pDoubleClickToPlaySizer = new wxBoxSizer(wxVERTICAL);
wxString defaultDir = wxGetHomeDir();
m_pAutoImportCheck = new wxCheckBox(m_pCollectionSettingPanel, SampleHive::ID::SD_AutoImport, "Auto import",
wxDefaultPosition, wxDefaultSize, 0);
m_pImportDirLocation = new wxTextCtrl(m_pCollectionSettingPanel, wxID_ANY, defaultDir,
wxDefaultPosition, wxDefaultSize, 0);
m_pImportDirLocation->Disable();
m_pBrowseAutoImportDirButton = new wxButton(m_pCollectionSettingPanel, SampleHive::ID::SD_BrowseAutoImportDir, "Browse",
wxDefaultPosition, wxDefaultSize, 0);
m_pBrowseAutoImportDirButton->Disable();
m_pFollowSymLinksCheck = new wxCheckBox(m_pCollectionSettingPanel, SampleHive::ID::SD_FollowSymLinks,
"Follow symbolic links", wxDefaultPosition, wxDefaultSize, 0);
m_pFollowSymLinksCheck->SetToolTip("Wheather to follow symbolic links");
m_pFollowSymLinksCheck->Disable();
m_pRecursiveImportCheck = new wxCheckBox(m_pCollectionSettingPanel, SampleHive::ID::SD_RecursiveImport,
"Recursive search", wxDefaultPosition, wxDefaultSize, 0);
m_pRecursiveImportCheck->SetToolTip("Recursively search for samples in the directory");
m_pRecursiveImportCheck->Disable();
m_pShowFileExtensionCheck = new wxCheckBox(m_pCollectionSettingPanel, SampleHive::ID::SD_ShowFileExtension,
"Show file extension", wxDefaultPosition, wxDefaultSize, 0);
m_pShowFileExtensionCheck->SetToolTip("Weather to show file extension");
m_pDoubleClickToPlayCheck = new wxCheckBox(m_pCollectionSettingPanel, SampleHive::ID::SD_DoubleClickToPlay,
"Enable double click to play sample", wxDefaultPosition, wxDefaultSize, 0);
m_pConfigurationSettingPanel = new wxPanel(m_pNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_pGeneralMainSizer = new wxFlexGridSizer(2, 3, 0, 0);
m_pGeneralMainSizer->AddGrowableCol(1);
m_pGeneralMainSizer->SetFlexibleDirection(wxBOTH);
m_pGeneralMainSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
m_pConfigLabel = new wxStaticText(m_pConfigurationSettingPanel, wxID_ANY,
"Default configuration file location", wxDefaultPosition, wxDefaultSize);
m_pConfigText = new wxTextCtrl(m_pConfigurationSettingPanel, wxID_ANY, static_cast<std::string>(CONFIG_FILEPATH),
wxDefaultPosition, wxDefaultSize);
m_pConfigBrowse = new wxButton(m_pConfigurationSettingPanel, SampleHive::ID::SD_BrowseConfigDir, "Browse",
wxDefaultPosition, wxDefaultSize, 0);
m_pDatabaseLabel = new wxStaticText(m_pConfigurationSettingPanel, wxID_ANY, "Default database location",
wxDefaultPosition, wxDefaultSize);
m_pDatabaseText = new wxTextCtrl(m_pConfigurationSettingPanel, wxID_ANY, static_cast<std::string>(DATABASE_FILEPATH),
wxDefaultPosition, wxDefaultSize);
m_pDatabaseBrowse = new wxButton(m_pConfigurationSettingPanel, SampleHive::ID::SD_BrowseDatabaseDir, "Browse",
wxDefaultPosition, wxDefaultSize, 0);
m_pNotebook->AddPage(m_pDisplaySettingPanel, "Display");
m_pNotebook->AddPage(m_pCollectionSettingPanel, "Collection");
m_pNotebook->AddPage(m_pConfigurationSettingPanel, "General");
m_pOkButton = new wxButton(m_pPanel, wxID_OK, "OK", wxDefaultPosition, wxDefaultSize);
m_pCancelButton = new wxButton(m_pPanel, wxID_CANCEL, "Cancel", wxDefaultPosition, wxDefaultSize);
LoadDefaultConfig();
// Bind events
Bind(wxEVT_CHECKBOX, &cSettings::OnCheckAutoImport, this, SampleHive::ID::SD_AutoImport);
Bind(wxEVT_CHECKBOX, &cSettings::OnCheckFollowSymLinks, this, SampleHive::ID::SD_FollowSymLinks);
Bind(wxEVT_CHECKBOX, &cSettings::OnCheckRecursiveImport, this, SampleHive::ID::SD_RecursiveImport);
Bind(wxEVT_CHECKBOX, &cSettings::OnCheckShowFileExtension, this, SampleHive::ID::SD_ShowFileExtension);
Bind(wxEVT_CHECKBOX, &cSettings::OnCheckEnableDoubleClickToPlay, this, SampleHive::ID::SD_DoubleClickToPlay);
Bind(wxEVT_SPINCTRL, &cSettings::OnChangeFontSize, this, SampleHive::ID::SD_FontSize);
Bind(wxEVT_BUTTON, &cSettings::OnSelectFont, this, SampleHive::ID::SD_FontBrowseButton);
Bind(wxEVT_BUTTON, &cSettings::OnClickBrowseAutoImportDir, this, SampleHive::ID::SD_BrowseAutoImportDir);
Bind(wxEVT_BUTTON, &cSettings::OnClickConfigBrowse, this, SampleHive::ID::SD_BrowseConfigDir);
Bind(wxEVT_BUTTON, &cSettings::OnClickDatabaseBrowse, this, SampleHive::ID::SD_BrowseDatabaseDir);
Bind(wxEVT_COLOURPICKER_CHANGED, &cSettings::OnChangeWaveformColour, this, SampleHive::ID::SD_WaveformColourPickerCtrl);
Bind(wxEVT_CHECKBOX, &cSettings::OnCheckShowSplash, this, SampleHive::ID::SD_ShowSplash);
// Adding controls to sizers
m_pNotebookSizer->Add(m_pNotebook, 1, wxALL | wxEXPAND, 2);
m_pGeneralMainSizer->Add(m_pConfigLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pGeneralMainSizer->Add(m_pConfigText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_pGeneralMainSizer->Add(m_pConfigBrowse, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pGeneralMainSizer->Add(m_pDatabaseLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pGeneralMainSizer->Add(m_pDatabaseText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_pGeneralMainSizer->Add(m_pDatabaseBrowse, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pDisplayFontSizer->Add(m_pFontTypeText, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pDisplayFontSizer->Add(m_pFontType, 1, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pDisplayFontSizer->Add(m_pFontSize, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pDisplayFontSizer->Add(m_pFontBrowseButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pWaveformColourSizer->Add(m_pWaveformColourLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pWaveformColourSizer->Add(m_pWaveformColourPickerCtrl, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pDisplayTopSizer->Add(m_pDisplayFontSizer, 0, wxALL | wxEXPAND, 2);
m_pDisplayTopSizer->Add(m_pWaveformColourSizer, 0, wxALL | wxEXPAND, 2);
m_pDisplayTopSizer->Add(m_pShowSplashCheck, 0, wxALL | wxEXPAND, 2);
m_pCollectionImportDirSizer->Add(m_pAutoImportCheck, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pCollectionImportDirSizer->Add(m_pImportDirLocation, 1, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pCollectionImportDirSizer->Add(m_pBrowseAutoImportDirButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pCollectionImportOptionsSizer->Add(m_pFollowSymLinksCheck, 0, wxALL, 2);
m_pCollectionImportOptionsSizer->Add(m_pRecursiveImportCheck, 0, wxALL, 2);
m_pCollectionShowExtensionSizer->Add(m_pShowFileExtensionCheck, 0, wxALL, 2);
m_pDoubleClickToPlaySizer->Add(m_pDoubleClickToPlayCheck, 0, wxALL, 2);
m_pCollectionMainSizer->Add(m_pCollectionImportDirSizer, 0, wxALL | wxEXPAND, 2);
m_pCollectionMainSizer->Add(m_pCollectionImportOptionsSizer, 0, wxALL | wxEXPAND, 2);
m_pCollectionMainSizer->Add(m_pCollectionShowExtensionSizer, 0, wxALL | wxEXPAND, 2);
m_pCollectionMainSizer->Add(m_pDoubleClickToPlaySizer, 0, wxALL | wxEXPAND, 2);
m_pButtonSizer->Add(m_pOkButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_pButtonSizer->Add(m_pCancelButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_pMainSizer->Add(m_pNotebookSizer, 1, wxALL | wxEXPAND, 2);
m_pMainSizer->Add(m_pButtonSizer, 0, wxALL | wxALIGN_RIGHT, 2);
// Top panel layout
m_pPanel->SetSizer(m_pMainSizer);
m_pMainSizer->Fit(m_pPanel);
m_pMainSizer->SetSizeHints(m_pPanel);
m_pMainSizer->Layout();
// Display panel layout
m_pDisplaySettingPanel->SetSizer(m_pDisplayTopSizer);
m_pDisplayTopSizer->Fit(m_pDisplaySettingPanel);
m_pDisplayTopSizer->SetSizeHints(m_pDisplaySettingPanel);
m_pDisplayTopSizer->Layout();
// Collection panel layout
m_pCollectionSettingPanel->SetSizer(m_pCollectionMainSizer);
m_pCollectionMainSizer->Fit(m_pCollectionSettingPanel);
m_pCollectionMainSizer->SetSizeHints(m_pCollectionSettingPanel);
m_pCollectionMainSizer->Layout();
// Configuration panel layout
m_pConfigurationSettingPanel->SetSizer(m_pGeneralMainSizer);
m_pGeneralMainSizer->Fit(m_pConfigurationSettingPanel);
m_pGeneralMainSizer->SetSizeHints(m_pConfigurationSettingPanel);
m_pGeneralMainSizer->Layout();
}
void cSettings::OnClickConfigBrowse(wxCommandEvent& event)
{
wxString initial_dir = wxGetHomeDir();
wxDirDialog dir_dialog(this, "Select a directory..", initial_dir,
wxDD_DEFAULT_STYLE |
wxDD_DIR_MUST_EXIST |
wxDD_NEW_DIR_BUTTON,
wxDefaultPosition, wxDefaultSize);
switch (dir_dialog.ShowModal())
{
case wxID_OK:
{
wxString path = dir_dialog.GetPath();
m_pConfigText->SetValue(path + "/config.yaml");
break;
}
default:
return;
}
}
void cSettings::OnClickDatabaseBrowse(wxCommandEvent& event)
{
wxString initial_dir = wxGetHomeDir();
wxDirDialog dir_dialog(this, "Select a directory..", initial_dir,
wxDD_DEFAULT_STYLE |
wxDD_DIR_MUST_EXIST |
wxDD_NEW_DIR_BUTTON,
wxDefaultPosition, wxDefaultSize);
switch (dir_dialog.ShowModal())
{
case wxID_OK:
{
wxString path = dir_dialog.GetPath();
m_pDatabaseText->SetValue(path + "/config.yaml");
break;
}
default:
return;
}
}
void cSettings::OnCheckAutoImport(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
if (!m_pAutoImportCheck->GetValue())
{
m_bAutoImport = false;
m_pImportDirLocation->Disable();
m_pBrowseAutoImportDirButton->Disable();
m_pFollowSymLinksCheck->Disable();
m_pRecursiveImportCheck->Disable();
serializer.SerializeAutoImport(m_bAutoImport, m_pImportDirLocation->GetValue().ToStdString());
}
else
{
m_bAutoImport = true;
m_pImportDirLocation->Enable();
m_pBrowseAutoImportDirButton->Enable();
m_pFollowSymLinksCheck->Enable();
m_pRecursiveImportCheck->Enable();
serializer.SerializeAutoImport(m_bAutoImport, m_pImportDirLocation->GetValue().ToStdString());
}
}
void cSettings::OnCheckFollowSymLinks(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
serializer.SerializeFollowSymLink(m_pFollowSymLinksCheck->GetValue());
}
void cSettings::OnCheckRecursiveImport(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
serializer.SerializeRecursiveImport(m_pRecursiveImportCheck->GetValue());
}
void cSettings::OnCheckShowFileExtension(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
serializer.SerializeShowFileExtension(m_pShowFileExtensionCheck->GetValue());
}
void cSettings::OnCheckEnableDoubleClickToPlay(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
serializer.SerializeDoubleClickToPlay(m_pDoubleClickToPlayCheck->GetValue());
}
void cSettings::OnClickBrowseAutoImportDir(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
wxString initial_dir = wxGetHomeDir();
wxDirDialog dir_dialog(this, "Select a directory..", initial_dir,
wxDD_DEFAULT_STYLE |
wxDD_DIR_MUST_EXIST |
wxDD_NEW_DIR_BUTTON,
wxDefaultPosition, wxDefaultSize);
switch (dir_dialog.ShowModal())
{
case wxID_OK:
{
wxString path = dir_dialog.GetPath();
m_pImportDirLocation->SetValue(path);
serializer.SerializeAutoImport(m_bAutoImport, m_pImportDirLocation->GetValue().ToStdString());
break;
}
default:
return;
}
}
void cSettings::OnSelectFont(wxCommandEvent& event)
{
wxFontDialog font_dialog(this);
switch (font_dialog.ShowModal())
{
case wxID_OK:
{
wxFontData fontData = font_dialog.GetFontData();
m_Font = fontData.GetChosenFont();
if (m_pFontType->GetCount() > 1)
{
m_pFontType->Delete(1);
m_pFontType->AppendString(m_Font.GetFaceName());
m_pFontType->SetSelection(1);
}
else
{
m_pFontType->AppendString(m_Font.GetFaceName());
m_pFontType->SetSelection(1);
}
SetCustomFont();
}
default:
return;
}
PrintFont();
}
void cSettings::OnChangeFontSize(wxSpinEvent& event)
{
SampleHive::cSerializer serializer;
int font_size = m_pFontSize->GetValue();
if (m_pFontType->GetStringSelection() == "System default")
m_Font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
m_Font.SetPointSize(font_size);
serializer.SerializeFontSettings(m_Font);
m_pWindow->SetFont(m_Font);
this->SetFont(m_Font);
SH_LOG_DEBUG("Font size: {}", font_size);
SH_LOG_DEBUG("Font size: {}", m_Font.GetPointSize());
}
void cSettings::LoadDefaultConfig()
{
SampleHive::cSerializer serializer;
wxFont sys_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
wxString system_font = sys_font.GetFaceName();
int system_font_size = sys_font.GetPointSize();
wxString font_face = serializer.DeserializeFontSettings().GetFaceName();
int font_size = serializer.DeserializeFontSettings().GetPointSize();
if (system_font != font_face)
{
if (m_pFontType->GetCount() > 1)
{
m_pFontType->Delete(1);
m_pFontType->AppendString(font_face);
m_pFontType->SetSelection(1);
m_Font.SetFaceName(font_face);
m_Font.SetPointSize(font_size);
}
else
{
m_pFontType->AppendString(font_face);
m_pFontType->SetSelection(1);
m_Font.SetFaceName(font_face);
m_Font.SetPointSize(font_size);
}
}
m_pFontSize->SetValue(font_size);
SetCustomFont();
m_bAutoImport = serializer.DeserializeAutoImport().first;
m_pAutoImportCheck->SetValue(m_bAutoImport);
m_pImportDirLocation->SetValue(serializer.DeserializeAutoImport().second);
m_pShowFileExtensionCheck->SetValue(serializer.DeserializeShowFileExtension());
m_pDoubleClickToPlayCheck->SetValue(serializer.DeserializeDoubleClickToPlay());
m_pFollowSymLinksCheck->SetValue(serializer.DeserializeFollowSymLink());
m_pRecursiveImportCheck->SetValue(serializer.DeserializeRecursiveImport());
if (m_bAutoImport)
{
m_pImportDirLocation->Enable();
m_pBrowseAutoImportDirButton->Enable();
m_pFollowSymLinksCheck->Enable();
m_pRecursiveImportCheck->Enable();
}
}
void cSettings::SetShowExtension(bool value)
{
SampleHive::cSerializer serializer;
m_pShowFileExtensionCheck->SetValue(value);
serializer.SerializeShowFileExtension(value);
}
void cSettings::PrintFont()
{
SH_LOG_DEBUG("Font face: {}", m_Font.GetFaceName().ToStdString());
SH_LOG_DEBUG("Font size: {}", m_Font.GetPointSize());
SH_LOG_DEBUG("Font family: {}", m_Font.GetFamilyString().ToStdString());
SH_LOG_DEBUG("Font style: {}", m_Font.GetStyleString().ToStdString());
SH_LOG_DEBUG("Font weight: {}", m_Font.GetWeightString().ToStdString());
}
void cSettings::SetCustomFont()
{
SampleHive::cSerializer serializer;
wxFont sys_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
std::string system_font = sys_font.GetFaceName().ToStdString();
int system_font_size = sys_font.GetPointSize();
wxString font_face = serializer.DeserializeFontSettings().GetFaceName();
int font_size = serializer.DeserializeFontSettings().GetPointSize();
if (m_pFontType->GetStringSelection() == "System default")
{
m_pWindow->SetFont(sys_font);
this->SetFont(sys_font);
serializer.SerializeFontSettings(sys_font);
}
else
{
m_pWindow->SetFont(m_Font);
this->SetFont(m_Font);
serializer.SerializeFontSettings(m_Font);
}
}
wxString cSettings::GetImportDirPath()
{
wxString dir = wxEmptyString;
if (m_pAutoImportCheck->GetValue())
dir = m_pImportDirLocation->GetValue();
return dir;
}
void cSettings::OnChangeWaveformColour(wxColourPickerEvent& event)
{
SampleHive::cSerializer serializer;
wxColour colour = m_pWaveformColourPickerCtrl->GetColour();
wxColour wave_colour = serializer.DeserializeWaveformColour();
if (colour != wave_colour)
{
SH_LOG_INFO("Waveform colour changed.");
m_bWaveformColourChanged = true;
serializer.SerializeWaveformColour(colour);
}
else
{
SH_LOG_INFO("Waveform colour not changed.");
m_bWaveformColourChanged = false;
serializer.SerializeWaveformColour(colour);
}
}
void cSettings::OnCheckShowSplash(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
serializer.SerializeShowSplash(m_pShowSplashCheck->GetValue());
}
cSettings::~cSettings()
{
}

View File

@ -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>
@ -39,98 +40,26 @@
#include <wx/toplevel.h>
#include <wx/window.h>
class Settings : public wxDialog
class cSettings : public wxDialog
{
public:
Settings(const std::string& configFilepath, const std::string& databaseFilepath);
Settings(wxWindow* window, const std::string& configFilepath, const std::string& databaseFilepath);
~Settings();
private:
// -------------------------------------------------------------------
wxWindow* m_Window;
const std::string& m_ConfigFilepath;
const std::string& m_DatabaseFilepath;
private:
// -------------------------------------------------------------------
// Top panel for wxDialog
wxPanel* m_Panel;
// -------------------------------------------------------------------
// Notebook page panels
wxPanel* m_DisplaySettingPanel;
wxPanel* m_CollectionSettingPanel;
wxPanel* m_ConfigurationSettingPanel;
// -------------------------------------------------------------------
// Top panel sizers
wxBoxSizer* m_MainSizer;
wxBoxSizer* m_NotebookSizer;
wxBoxSizer* m_ButtonSizer;
// -------------------------------------------------------------------
// Notebook
wxNotebook* m_Notebook;
// -------------------------------------------------------------------
// Display page
wxBoxSizer* m_DisplayTopSizer;
wxBoxSizer* m_DisplayFontSizer;
wxStaticText* m_RowHeightText;
wxStaticText* m_FontTypeText;
wxChoice* m_RowHeight;
wxChoice* m_FontType;
wxFontDialog* m_FontDialog;
wxButton* m_FontBrowseButton;
wxSpinCtrl* m_FontSize;
// -------------------------------------------------------------------
// Collection page
wxBoxSizer* m_CollectionTopSizer;
wxBoxSizer* m_CollectionImportDirSizer;
wxBoxSizer* m_ShowFileExtensionSizer;
wxCheckBox* m_AutoImportCheck;
wxCheckBox* m_ShowFileExtensionCheck;
wxTextCtrl* m_ImportDirLocation;
wxButton* m_BrowseAutoImportDirButton;
wxDirDialog* m_DirDialog;
// -------------------------------------------------------------------
// General configuration page
wxFlexGridSizer* m_GeneralMainSizer;
wxStaticText* m_ConfigLabel;
wxStaticText* m_DatabaseLabel;
wxTextCtrl* m_ConfigText;
wxTextCtrl* m_DatabaseText;
wxButton* m_ConfigBrowse;
wxButton* m_DatabaseBrowse;
// -------------------------------------------------------------------
// Common buttons for wxDialog
wxButton* m_OkButton;
wxButton* m_CancelButton;
private:
// -------------------------------------------------------------------
wxFont m_Font;
private:
// -------------------------------------------------------------------
bool bAutoImport = false;
bool bShowExtension = true;
cSettings(wxWindow* window);
~cSettings();
private:
// -------------------------------------------------------------------
void OnClickConfigBrowse(wxCommandEvent& event);
void OnClickDatabaseBrowse(wxCommandEvent& event);
void OnCheckAutoImport(wxCommandEvent& event);
void OnCheckFollowSymLinks(wxCommandEvent& event);
void OnCheckRecursiveImport(wxCommandEvent& event);
void OnCheckShowFileExtension(wxCommandEvent& event);
void OnCheckEnableDoubleClickToPlay(wxCommandEvent& event);
void OnClickBrowseAutoImportDir(wxCommandEvent& event);
void OnChangeFontSize(wxSpinEvent& event);
void OnSelectFont(wxCommandEvent& event);
void OnChangeWaveformColour(wxColourPickerEvent& event);
void OnCheckShowSplash(wxCommandEvent& event);
// -------------------------------------------------------------------
void SetCustomFont();
@ -144,7 +73,92 @@ class Settings : public wxDialog
// Getters
wxString GetImportDirPath();
inline wxFont GetFontType() { return m_Font; };
inline bool CanAutoImport() { return bAutoImport; };
inline bool ShouldShowFileExtension() { return bShowExtension; };
// inline wxFont GetFontType() { return m_Font; };
inline bool CanAutoImport() { return m_bAutoImport; };
inline bool IsWaveformColourChanged() { return m_bWaveformColourChanged; }
// -------------------------------------------------------------------
// Setters
void SetShowExtension(bool value);
private:
// -------------------------------------------------------------------
wxWindow* m_pWindow = nullptr;
private:
// -------------------------------------------------------------------
// Top panel for wxDialog
wxPanel* m_pPanel = nullptr;
// -------------------------------------------------------------------
// Notebook page panels
wxPanel* m_pDisplaySettingPanel = nullptr;
wxPanel* m_pCollectionSettingPanel = nullptr;
wxPanel* m_pConfigurationSettingPanel = nullptr;
// -------------------------------------------------------------------
// Top panel sizers
wxBoxSizer* m_pMainSizer = nullptr;
wxBoxSizer* m_pNotebookSizer = nullptr;
wxBoxSizer* m_pButtonSizer = nullptr;
// -------------------------------------------------------------------
// Notebook
wxNotebook* m_pNotebook = nullptr;
// -------------------------------------------------------------------
// Display page
wxBoxSizer* m_pDisplayTopSizer = nullptr;
wxBoxSizer* m_pDisplayFontSizer = nullptr;
wxStaticText* m_pRowHeightText = nullptr;
wxStaticText* m_pFontTypeText = nullptr;
wxChoice* m_pRowHeight = nullptr;
wxChoice* m_pFontType = nullptr;
wxButton* m_pFontBrowseButton = nullptr;
wxSpinCtrl* m_pFontSize = nullptr;
wxBoxSizer* m_pWaveformColourSizer = nullptr;
wxStaticText* m_pWaveformColourLabel = nullptr;
wxColourPickerCtrl* m_pWaveformColourPickerCtrl = nullptr;
wxCheckBox* m_pShowSplashCheck = nullptr;
// -------------------------------------------------------------------
// Collection page
wxBoxSizer* m_pCollectionMainSizer = nullptr;
wxBoxSizer* m_pCollectionImportDirSizer = nullptr;
wxBoxSizer* m_pCollectionImportOptionsSizer = nullptr;
wxBoxSizer* m_pCollectionShowExtensionSizer = nullptr;
wxBoxSizer* m_pDoubleClickToPlaySizer = nullptr;
wxCheckBox* m_pAutoImportCheck = nullptr;
wxCheckBox* m_pFollowSymLinksCheck = nullptr;
wxCheckBox* m_pRecursiveImportCheck = nullptr;
wxCheckBox* m_pShowFileExtensionCheck = nullptr;
wxCheckBox* m_pDoubleClickToPlayCheck = nullptr;
wxTextCtrl* m_pImportDirLocation = nullptr;
wxButton* m_pBrowseAutoImportDirButton = nullptr;
// -------------------------------------------------------------------
// General configuration page
wxFlexGridSizer* m_pGeneralMainSizer = nullptr;
wxStaticText* m_pConfigLabel = nullptr;
wxStaticText* m_pDatabaseLabel = nullptr;
wxTextCtrl* m_pConfigText = nullptr;
wxTextCtrl* m_pDatabaseText = nullptr;
wxButton* m_pConfigBrowse = nullptr;
wxButton* m_pDatabaseBrowse = nullptr;
// -------------------------------------------------------------------
// Common buttons for wxDialog
wxButton* m_pOkButton = nullptr;
wxButton* m_pCancelButton = nullptr;
private:
// -------------------------------------------------------------------
wxFont m_Font;
private:
// -------------------------------------------------------------------
bool m_bAutoImport = false;
// bool bFollowSymLinks = false;
// bool bShowExtension = true;
bool m_bWaveformColourChanged = false;
};

View File

@ -0,0 +1,334 @@
/* 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 "GUI/Dialogs/TagEditor.hpp"
#include "Database/Database.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Event.hpp"
#include "Utility/Signal.hpp"
#include <wx/defs.h>
#include <wx/gdicmn.h>
#include <wx/msgdlg.h>
#include <wx/stringimpl.h>
#include <wx/textdlg.h>
cTagEditor::cTagEditor(wxWindow* window, const std::string& filename)
: wxDialog(window, wxID_ANY, "Edit tags", wxDefaultPosition,
wxSize(640, 360), wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP),
m_pWindow(window), m_Filename(filename), tags(filename)
{
m_pPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_pMainSizer = new wxBoxSizer(wxVERTICAL);
m_pButtonSizer = new wxBoxSizer(wxHORIZONTAL);
m_pEditTagSizer = new wxFlexGridSizer(6, 2, 0, 0);
m_pEditTagSizer->AddGrowableCol(1);
m_pEditTagSizer->SetFlexibleDirection(wxBOTH);
m_pEditTagSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
m_pSampleTypeSizer = new wxFlexGridSizer(1, 3, 0, 0);
m_pSampleTypeSizer->AddGrowableCol(1);
m_pSampleTypeSizer->SetFlexibleDirection(wxBOTH);
m_pSampleTypeSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
m_pStaticEditTagSizer = new wxStaticBoxSizer(wxVERTICAL, m_pPanel, "Edit tags");
m_pStaticSampleTypeSizer = new wxStaticBoxSizer(wxVERTICAL, m_pPanel, "Sample type");
wxString choices[] = {"Kick", "Snare", "Clap", "HiHat", "Cymbal", "Cowbell", "Ride", "Tom", "Shaker", "Percussion"};
m_pTitleCheck = new wxCheckBox(m_pPanel, SampleHive::ID::ET_TitleCheck, "Title", wxDefaultPosition, wxDefaultSize);
m_pArtistCheck = new wxCheckBox(m_pPanel, SampleHive::ID::ET_ArtistCheck, "Artist", wxDefaultPosition, wxDefaultSize);
m_pAlbumCheck = new wxCheckBox(m_pPanel, SampleHive::ID::ET_AlbumCheck, "Album", wxDefaultPosition, wxDefaultSize);
m_pGenreCheck = new wxCheckBox(m_pPanel, SampleHive::ID::ET_GenreCheck, "Genre", wxDefaultPosition, wxDefaultSize);
m_pCommentCheck = new wxCheckBox(m_pPanel, SampleHive::ID::ET_CommentsCheck, "Comments", wxDefaultPosition, wxDefaultSize);
m_pSampleTypeCheck = new wxCheckBox(m_pPanel, SampleHive::ID::ET_TypeCheck, "Type", wxDefaultPosition, wxDefaultSize);
m_pTitleText = new wxTextCtrl(m_pPanel, wxID_ANY, tags.GetAudioInfo().title, wxDefaultPosition, wxDefaultSize);
m_pTitleText->Disable();
m_pArtistText = new wxTextCtrl(m_pPanel, wxID_ANY, tags.GetAudioInfo().artist, wxDefaultPosition, wxDefaultSize);
m_pArtistText->Disable();
m_pAlbumText = new wxTextCtrl(m_pPanel, wxID_ANY, tags.GetAudioInfo().album, wxDefaultPosition, wxDefaultSize);
m_pAlbumText->Disable();
m_pGenreText = new wxTextCtrl(m_pPanel, wxID_ANY, tags.GetAudioInfo().genre, wxDefaultPosition, wxDefaultSize);
m_pGenreText->Disable();
m_pCommentText = new wxTextCtrl(m_pPanel, wxID_ANY, tags.GetAudioInfo().comment, wxDefaultPosition, wxDefaultSize);
m_pCommentText->Disable();
m_pSampleTypeChoice = new wxChoice(m_pPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 10, choices, wxCB_SORT);
m_pSampleTypeChoice->Disable();
m_pSampleTypeButton = new wxButton(m_pPanel, SampleHive::ID::ET_CustomTag, "Custom", wxDefaultPosition, wxDefaultSize);
m_pSampleTypeButton->Disable();
m_pOkButton = new wxButton(m_pPanel, wxID_OK, "OK", wxDefaultPosition, wxDefaultSize);
m_pApplyButton = new wxButton(m_pPanel, wxID_APPLY, "Apply", wxDefaultPosition, wxDefaultSize);
m_pCancelButton = new wxButton(m_pPanel, wxID_CANCEL, "Cancel", wxDefaultPosition, wxDefaultSize);
// Binding events
Bind(wxEVT_CHECKBOX, &cTagEditor::OnCheckTitle, this, SampleHive::ID::ET_TitleCheck);
Bind(wxEVT_CHECKBOX, &cTagEditor::OnCheckArtist, this, SampleHive::ID::ET_ArtistCheck);
Bind(wxEVT_CHECKBOX, &cTagEditor::OnCheckAlbum, this, SampleHive::ID::ET_AlbumCheck);
Bind(wxEVT_CHECKBOX, &cTagEditor::OnCheckGenre, this, SampleHive::ID::ET_GenreCheck);
Bind(wxEVT_CHECKBOX, &cTagEditor::OnCheckComments, this, SampleHive::ID::ET_CommentsCheck);
Bind(wxEVT_CHECKBOX, &cTagEditor::OnCheckType, this, SampleHive::ID::ET_TypeCheck);
Bind(wxEVT_BUTTON, &cTagEditor::OnClickCustomTagButton, this, SampleHive::ID::ET_CustomTag);
Bind(wxEVT_BUTTON, &cTagEditor::OnClickApply, this, wxID_APPLY);
m_pEditTagSizer->Add(m_pTitleCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_pEditTagSizer->Add(m_pTitleText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_pEditTagSizer->Add(m_pArtistCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_pEditTagSizer->Add(m_pArtistText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_pEditTagSizer->Add(m_pAlbumCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_pEditTagSizer->Add(m_pAlbumText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_pEditTagSizer->Add(m_pGenreCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_pEditTagSizer->Add(m_pGenreText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_pEditTagSizer->Add(m_pCommentCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_pEditTagSizer->Add(m_pCommentText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_pSampleTypeSizer->Add(m_pSampleTypeCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_pSampleTypeSizer->Add(m_pSampleTypeChoice, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_pSampleTypeSizer->Add(m_pSampleTypeButton, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
m_pStaticEditTagSizer->Add(m_pEditTagSizer, 1, wxALL | wxEXPAND, 2);
m_pStaticSampleTypeSizer->Add(m_pSampleTypeSizer, 1, wxALL | wxEXPAND, 2);
m_pButtonSizer->Add(m_pOkButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_pButtonSizer->Add(m_pApplyButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_pButtonSizer->Add(m_pCancelButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_pMainSizer->Add(m_pStaticEditTagSizer, 1, wxALL | wxEXPAND, 2);
m_pMainSizer->Add(m_pStaticSampleTypeSizer, 1, wxALL | wxEXPAND, 2);
m_pMainSizer->Add(m_pButtonSizer, 0, wxALL | wxALIGN_RIGHT, 2);
// Top panel layout
m_pPanel->SetSizer(m_pMainSizer);
m_pMainSizer->Fit(m_pPanel);
m_pMainSizer->SetSizeHints(m_pPanel);
m_pMainSizer->Layout();
}
void cTagEditor::OnCheckTitle(wxCommandEvent &event)
{
if (m_pTitleCheck->GetValue())
{
m_pTitleText->Enable();
}
else
{
m_pTitleText->Disable();
}
}
void cTagEditor::OnCheckArtist(wxCommandEvent &event)
{
if (m_pArtistCheck->GetValue())
{
m_pArtistText->Enable();
}
else
{
m_pArtistText->Disable();
}
}
void cTagEditor::OnCheckAlbum(wxCommandEvent &event)
{
if (m_pAlbumCheck->GetValue())
{
m_pAlbumText->Enable();
}
else
{
m_pAlbumText->Disable();
}
}
void cTagEditor::OnCheckGenre(wxCommandEvent &event)
{
if (m_pGenreCheck->GetValue())
{
m_pGenreText->Enable();
}
else
{
m_pGenreText->Disable();
}
}
void cTagEditor::OnCheckComments(wxCommandEvent &event)
{
if (m_pCommentCheck->GetValue())
{
m_pCommentText->Enable();
}
else
{
m_pCommentText->Disable();
}
}
void cTagEditor::OnCheckType(wxCommandEvent &event)
{
if (m_pSampleTypeCheck->GetValue())
{
m_pSampleTypeChoice->Enable();
m_pSampleTypeButton->Enable();
}
else
{
m_pSampleTypeChoice->Disable();
m_pSampleTypeButton->Disable();
}
}
void cTagEditor::OnClickCustomTagButton(wxCommandEvent& event)
{
wxTextEntryDialog* customTag;
customTag = new wxTextEntryDialog(this, "Enter a custom tag",
"Add custom tag", wxEmptyString,
wxTextEntryDialogStyle, wxDefaultPosition);
switch (customTag->ShowModal())
{
case wxID_OK:
{
wxString tag = customTag->GetValue();
m_pSampleTypeChoice->AppendString(tag);
m_pSampleTypeChoice->SetStringSelection(tag);
break;
}
case wxID_CANCEL:
break;
default:
return;
}
}
void cTagEditor::OnClickApply(wxCommandEvent& event)
{
cDatabase db;
wxString title = m_pTitleText->GetValue();
wxString artist = m_pArtistText->GetValue();
wxString album = m_pAlbumText->GetValue();
wxString genre = m_pGenreText->GetValue();
wxString comment = m_pCommentText->GetValue();
wxString type = m_pSampleTypeChoice->GetStringSelection();
std::string sampleType = db.GetSampleType(m_Filename);
std::string filename = wxString(m_Filename).AfterLast('/').BeforeLast('.').ToStdString();
wxString warning_msg = "Are you sure you want save these changes?";
wxMessageDialog* msgDialog = new wxMessageDialog(this, warning_msg,
"Edit tags", wxCENTRE |
wxYES_NO | wxNO_DEFAULT |
wxICON_QUESTION |
wxSTAY_ON_TOP,
wxDefaultPosition);
wxString info_msg;
switch (msgDialog->ShowModal())
{
case wxID_YES:
if (m_pTitleCheck->GetValue() && m_pTitleText->GetValue() != tags.GetAudioInfo().title)
{
SH_LOG_INFO("Changing title tag..");
tags.SetTitle(title.ToStdString());
info_msg = wxString::Format("Successfully changed title tag to %s", title);
}
if (m_pArtistCheck->GetValue() && m_pArtistText->GetValue() != tags.GetAudioInfo().artist)
{
SH_LOG_INFO("Changing artist tag..");
tags.SetArtist(artist.ToStdString());
db.UpdateSamplePack(m_Filename, artist.ToStdString());
SH_LOG_DEBUG("SAMPLE FILENAME HERE: %s", m_Filename);
info_msg = wxString::Format("Successfully changed artist tag to %s", artist);
}
if (m_pAlbumCheck->GetValue() && m_pAlbumText->GetValue() != tags.GetAudioInfo().album)
{
SH_LOG_INFO("Changing album tag..");
tags.SetAlbum(album.ToStdString());
info_msg = wxString::Format("Successfully changed album tag to %s", album);
}
if (m_pGenreCheck->GetValue() && m_pGenreText->GetValue() != tags.GetAudioInfo().genre)
{
SH_LOG_INFO("Changing genre tag..");
tags.SetGenre(genre.ToStdString());
info_msg = wxString::Format("Successfully changed genre tag to %s", genre);
}
if (m_pCommentCheck->GetValue() && m_pCommentText->GetValue() != tags.GetAudioInfo().comment)
{
SH_LOG_INFO("Changing comment tag..");
tags.SetComment(comment.ToStdString());
info_msg = wxString::Format("Successfully changed comment tag to %s", comment);
}
if (m_pSampleTypeCheck->GetValue() && m_pSampleTypeChoice->GetStringSelection() != sampleType)
{
SH_LOG_INFO("Changing type tag..");
db.UpdateSampleType(filename, type.ToStdString());
info_msg = wxString::Format("Successfully changed type tag to %s", type);
}
break;
case wxID_NO:
break;
default:
info_msg = "Error, cannot change tag!";
}
SampleHive::cSignal::SendInfoBarMessage(info_msg, wxICON_INFORMATION, *this, true);
}
// void cTagEditor::SendInfoBarMessage(const wxString& msg, int mode)
// {
// SH_LOG_INFO("{} called..", __FUNCTION__);
// SampleHive::SH_InfoBarMessageEvent event(SampleHive::SH_EVT_INFOBAR_MESSAGE_SHOW, this->GetId());
// event.SetEventObject(this);
// event.SetInfoBarMessage({ msg, mode });
// GetParent()->GetEventHandler()->ProcessEvent(event);
// }
cTagEditor::~cTagEditor()
{
}

View File

@ -20,6 +20,8 @@
#pragma once
#include "Utility/Tags.hpp"
#include <string>
#include <wx/button.h>
@ -34,61 +36,11 @@
#include <wx/toplevel.h>
#include <wx/window.h>
#include "Tags.hpp"
class TagEditor : public wxDialog
class cTagEditor : public wxDialog
{
public:
TagEditor(wxWindow* window, const std::string& dbPath, const std::string& filename, wxInfoBar& info_bar);
~TagEditor();
private:
// -------------------------------------------------------------------
wxWindow* m_Window;
const std::string m_DatabaseFilepath;
const std::string m_Filename;
wxInfoBar& m_InfoBar;
private:
// -------------------------------------------------------------------
// Top panel for wxDialog
wxPanel* m_Panel;
// -------------------------------------------------------------------
// Top panel sizers
wxBoxSizer* m_MainSizer;
wxFlexGridSizer* m_EditTagSizer;
wxFlexGridSizer* m_SampleTypeSizer;
wxBoxSizer* m_ButtonSizer;
wxStaticBoxSizer* m_StaticEditTagSizer;
wxStaticBoxSizer* m_StaticSampleTypeSizer;
// -------------------------------------------------------------------
// Dialog controls
wxCheckBox* m_TitleCheck;
wxCheckBox* m_ArtistCheck;
wxCheckBox* m_AlbumCheck;
wxCheckBox* m_GenreCheck;
wxCheckBox* m_CommentCheck;
wxCheckBox* m_SampleTypeCheck;
wxTextCtrl* m_TitleText;
wxTextCtrl* m_ArtistText;
wxTextCtrl* m_AlbumText;
wxTextCtrl* m_GenreText;
wxTextCtrl* m_CommentText;
wxChoice* m_SampleTypeChoice;
wxButton* m_SampleTypeButton;
// -------------------------------------------------------------------
// Common buttons for wxDialog
wxButton* m_OkButton;
wxButton* m_ApplyButton;
wxButton* m_CancelButton;
private:
// -------------------------------------------------------------------
Tags tags;
cTagEditor(wxWindow* window, const std::string& filename);
~cTagEditor();
private:
// -------------------------------------------------------------------
@ -105,4 +57,51 @@ class TagEditor : public wxDialog
// -------------------------------------------------------------------
void OnClickApply(wxCommandEvent& event);
private:
// -------------------------------------------------------------------
wxWindow* m_pWindow = nullptr;
// -------------------------------------------------------------------
const std::string& m_Filename;
private:
// -------------------------------------------------------------------
// Top panel for wxDialog
wxPanel* m_pPanel = nullptr;
// -------------------------------------------------------------------
// Top panel sizers
wxBoxSizer* m_pMainSizer = nullptr;
wxFlexGridSizer* m_pEditTagSizer = nullptr;
wxFlexGridSizer* m_pSampleTypeSizer = nullptr;
wxBoxSizer* m_pButtonSizer = nullptr;
wxStaticBoxSizer* m_pStaticEditTagSizer = nullptr;
wxStaticBoxSizer* m_pStaticSampleTypeSizer = nullptr;
// -------------------------------------------------------------------
// Dialog controls
wxCheckBox* m_pTitleCheck = nullptr;
wxCheckBox* m_pArtistCheck = nullptr;
wxCheckBox* m_pAlbumCheck = nullptr;
wxCheckBox* m_pGenreCheck = nullptr;
wxCheckBox* m_pCommentCheck = nullptr;
wxCheckBox* m_pSampleTypeCheck = nullptr;
wxTextCtrl* m_pTitleText = nullptr;
wxTextCtrl* m_pArtistText = nullptr;
wxTextCtrl* m_pAlbumText = nullptr;
wxTextCtrl* m_pGenreText = nullptr;
wxTextCtrl* m_pCommentText = nullptr;
wxChoice* m_pSampleTypeChoice = nullptr;
wxButton* m_pSampleTypeButton = nullptr;
// -------------------------------------------------------------------
// Common buttons for wxDialog
wxButton* m_pOkButton = nullptr;
wxButton* m_pApplyButton = nullptr;
wxButton* m_pCancelButton = nullptr;
private:
// -------------------------------------------------------------------
SampleHive::cTags tags;
};

View File

@ -0,0 +1,134 @@
/* 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 "Database/Database.hpp"
#include "GUI/DirectoryBrowser.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Sample.hpp"
#include "Utility/Serialize.hpp"
#include "Utility/Utils.hpp"
#include <wx/dataobj.h>
#include <wx/dir.h>
#include <wx/dnd.h>
#include <wx/treebase.h>
cDirectoryBrowser::cDirectoryBrowser(wxWindow* window)
: wxGenericDirCtrl(window, SampleHive::ID::BC_DirCtrl, wxDirDialogDefaultFolderStr, wxDefaultPosition,
wxDefaultSize, wxDIRCTRL_SHOW_FILTERS,
_("All files|*|Ogg files (*.ogg)|*.ogg|Wav files (*.wav)|*.wav|"
"Flac files (*.flac)|*.flac"), 0),
m_pWindow(window)
{
SetPath(USER_HOME_DIR);
Bind(wxEVT_DIRCTRL_FILEACTIVATED, &cDirectoryBrowser::OnClickDirCtrl, this, SampleHive::ID::BC_DirCtrl);
Bind(wxEVT_TREE_BEGIN_DRAG, &cDirectoryBrowser::OnDragFromDirCtrl, this, this->GetTreeCtrl()->GetId());
Bind(wxEVT_TREE_ITEM_ACTIVATED, &cDirectoryBrowser::OnDirCtrlExpanded, this, this->GetTreeCtrl()->GetId());
}
void cDirectoryBrowser::OnClickDirCtrl(wxCommandEvent& event)
{
wxArrayString path;
path.push_back(this->GetFilePath());
SampleHive::cUtils::Get().AddSamples(path, m_pWindow);
}
// Temporary function to check drag and drop result
void LogDragResult(wxDragResult result)
{
wxString msg;
switch (result)
{
case wxDragError: msg = "Error!"; break;
case wxDragNone: msg = "Nothing"; break;
case wxDragCopy: msg = "Copied"; break;
case wxDragMove: msg = "Moved"; break;
case wxDragCancel: msg = "Cancelled"; break;
default: msg = "Huh?"; break;
}
SH_LOG_DEBUG("Drag result: {}", msg.ToStdString());
}
void cDirectoryBrowser::OnDragFromDirCtrl(wxTreeEvent& event)
{
wxFileDataObject file_data;
file_data.AddFile(this->GetPath(event.GetItem()));
wxDropSource drop_source(this);
drop_source.SetData(file_data);
LogDragResult(drop_source.DoDragDrop());
}
void cDirectoryBrowser::OnDirCtrlExpanded(wxTreeEvent& event)
{
cDatabase db;
SampleHive::cSerializer serializer;
if (serializer.DeserializeDemoMode())
{
wxBusyCursor busy_cursor;
wxWindowDisabler window_disabler;
wxString filepath;
wxArrayString filepath_array;
const wxString pathToDirectory = this->GetPath(event.GetItem());
size_t number_of_files = wxDir::GetAllFiles(pathToDirectory, &filepath_array, wxEmptyString, wxDIR_FILES);
for (size_t i = 0; i < number_of_files; i++)
{
filepath = filepath_array[i];
if (wxFileExists(filepath))
{
filepath_array.push_back(filepath);
}
else if (wxDirExists(filepath))
{
wxDir::GetAllFiles(filepath, &filepath_array);
}
}
// Delete all Files
if (SampleHive::cHiveData::Get().GetListCtrlItemCount() >= 1)
{
db.DeleteAllSamples();
SampleHive::cHiveData::Get().ListCtrlDeleteAllItems();
}
SampleHive::cUtils::Get().AddSamples(filepath_array, this);
}
else
event.Veto();
}
cDirectoryBrowser::~cDirectoryBrowser()
{
}

View File

@ -0,0 +1,42 @@
/* 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/control.h>
#include <wx/dirctrl.h>
#include <wx/window.h>
class cDirectoryBrowser : public wxGenericDirCtrl
{
public:
cDirectoryBrowser(wxWindow* window);
~cDirectoryBrowser();
private:
// -------------------------------------------------------------------
// DirCtrl event handlers
void OnClickDirCtrl(wxCommandEvent& event);
void OnDragFromDirCtrl(wxTreeEvent& event);
void OnDirCtrlExpanded(wxTreeEvent& event);
private:
wxWindow* m_pWindow = nullptr;
};

736
src/GUI/Hives.cpp Normal file
View File

@ -0,0 +1,736 @@
/* 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 "GUI/Hives.hpp"
#include "Database/Database.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Signal.hpp"
#include "Utility/Serialize.hpp"
#include <deque>
#include <wx/gdicmn.h>
#include <wx/textdlg.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
cHivesPanel::cHivesPanel(wxWindow* window)
: wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL),
m_pWindow(window)
{
m_pMainSizer = new wxBoxSizer(wxVERTICAL);
m_pHivesSizer = new wxBoxSizer(wxVERTICAL);
m_pButtonSizer = new wxBoxSizer(wxHORIZONTAL);
m_pAddHiveButton = new wxButton(this, SampleHive::ID::BC_HiveAdd, "+", wxDefaultPosition, wxDefaultSize, 0);
m_pAddHiveButton->SetToolTip(_("Create new hive"));
m_pButtonSizer->Add(m_pAddHiveButton, wxSizerFlags(1).Expand());
m_pRemoveHiveButton = new wxButton(this, SampleHive::ID::BC_HiveRemove, "-", wxDefaultPosition, wxDefaultSize, 0);
m_pRemoveHiveButton->SetToolTip(_("Delete selected hive"));
m_pButtonSizer->Add(m_pRemoveHiveButton, wxSizerFlags(1).Expand());
// Initializing wxDataViewTreeCtrl as another page of wxNotebook
m_pHives = new wxDataViewTreeCtrl(this, SampleHive::ID::BC_Hives, wxDefaultPosition, wxDefaultSize, wxDV_NO_HEADER | wxDV_SINGLE);
m_pHivesSizer->Add(m_pHives, wxSizerFlags(1).Expand());
// Adding default hive
m_FavoritesHive = m_pHives->AppendContainer(wxDataViewItem(wxNullPtr), _("Favorites"));
// Setting m_Hives to accept files to be dragged and dropped on it
m_pHives->DragAcceptFiles(true);
m_pHives->Connect(wxEVT_DROP_FILES, wxDropFilesEventHandler(cHivesPanel::OnDragAndDropToHives), NULL, this);
Bind(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, &cHivesPanel::OnShowHivesContextMenu, this, SampleHive::ID::BC_Hives);
Bind(wxEVT_DATAVIEW_ITEM_START_EDITING, &cHivesPanel::OnHiveStartEditing, this, SampleHive::ID::BC_Hives);
Bind(wxEVT_BUTTON, &cHivesPanel::OnClickAddHive, this, SampleHive::ID::BC_HiveAdd);
Bind(wxEVT_BUTTON, &cHivesPanel::OnClickRemoveHive, this, SampleHive::ID::BC_HiveRemove);
m_pMainSizer->Add(m_pHivesSizer, wxSizerFlags(1).Expand());
m_pMainSizer->Add(m_pButtonSizer, wxSizerFlags(0).Expand());
// Sizer for Hives page for wxNotebook
this->SetSizer(m_pMainSizer);
m_pMainSizer->Fit(this);
m_pMainSizer->SetSizeHints(this);
m_pMainSizer->Layout();
}
void cHivesPanel::OnDragAndDropToHives(wxDropFilesEvent& event)
{
SampleHive::cSerializer serializer;
cDatabase db;
if (event.GetNumberOfFiles() > 0)
{
wxFileDataObject file_data;
wxArrayString files;
wxDataViewItemArray items;
int rows = SampleHive::cHiveData::Get().GetListCtrlSelections(items);
wxDataViewItem drop_target;;
wxDataViewColumn* column;
wxPoint position = event.GetPosition();
m_pHives->HitTest(position, drop_target, column);
wxString hive_name = m_pHives->GetItemText(drop_target);
wxString msg;
for (int i = 0; i < rows; i++)
{
int row = SampleHive::cHiveData::Get().GetListCtrlRowFromItem(items, i);
wxString name = SampleHive::cHiveData::Get().GetListCtrlTextValue(row, 1);
file_data.AddFile(name);
files = file_data.GetFilenames();
wxString file_name = serializer.DeserializeShowFileExtension() ?
files[i].BeforeLast('.') : files[i];
SH_LOG_DEBUG("Dropping {} file(s) {} on {}", rows - i, files[i].ToStdString(), m_pHives->GetItemText(drop_target).ToStdString());
if (drop_target.IsOk() && m_pHives->IsContainer(drop_target) &&
db.GetFavoriteColumnValueByFilename(file_name.ToStdString()) == 0)
{
m_pHives->AppendItem(drop_target, files[i]);
SampleHive::cHiveData::Get().ListCtrlSetVariant(wxVariant(wxBitmap(ICON_STAR_FILLED_16px, wxBITMAP_TYPE_PNG)), row, 0);
db.UpdateFavoriteColumn(file_name.ToStdString(), 1);
db.UpdateHiveName(file_name.ToStdString(), hive_name.ToStdString());
msg = wxString::Format(_("%s added to %s."), files[i], hive_name);
}
else
{
if (db.GetFavoriteColumnValueByFilename(file_name.ToStdString()) == 1)
{
wxMessageBox(wxString::Format(_("%s is already added to %s hive"), files[i],
db.GetHiveByFilename(file_name.ToStdString())),
_("Error!"), wxOK | wxICON_ERROR | wxCENTRE, this);
}
else
{
if (m_pHives->GetItemText(drop_target) == "")
wxMessageBox(_("Cannot drop item outside of a hive, try dropping on a hive."),
_("Error!"), wxOK | wxICON_ERROR | wxCENTRE, this);
else
wxMessageBox(wxString::Format(_("%s is not a hive, try dropping on a hive."),
m_pHives->GetItemText(drop_target)), _("Error!"),
wxOK | wxICON_ERROR | wxCENTRE, this);
}
}
if (!msg.IsEmpty())
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_ERROR, *this);
}
}
}
void cHivesPanel::OnShowHivesContextMenu(wxDataViewEvent& event)
{
SampleHive::cSerializer serializer;
cDatabase db;
wxDataViewItem selected_hive = event.GetItem();
wxString hive_name = m_pHives->GetItemText(selected_hive);
wxMenu menu;
if (m_pHives->IsContainer(selected_hive))
{
// Container menu items
menu.Append(SampleHive::ID::MN_RenameHive, _("Rename hive"), _("Rename selected hive"));
menu.Append(SampleHive::ID::MN_DeleteHive, _("Delete hive"), _("Delete selected hive"));
if (!m_bFiltered)
menu.Append(SampleHive::ID::MN_FilterLibrary, _("Filter library"), _("Show only samples from current hive in library"));
else
menu.Append(SampleHive::ID::MN_FilterLibrary, _("Clear filter"), _("Clear the filter"));
}
else
{
// Child menu items
menu.Append(SampleHive::ID::MN_RemoveSample, _("Remove sample"), _("Remove the selected sample(s)"));
menu.Append(SampleHive::ID::MN_ShowInLibrary, _("Show sample in library"), _("Show the selected in library"));
}
if (selected_hive.IsOk() && m_pHives->IsContainer(selected_hive))
{
switch (m_pHives->GetPopupMenuSelectionFromUser(menu, event.GetPosition()))
{
case SampleHive::ID::MN_RenameHive:
{
std::deque<wxDataViewItem> nodes;
nodes.push_back(m_pHives->GetNthChild(wxDataViewItem(wxNullPtr), 0));
wxDataViewItem current_item, found_item;
int row = 0;
int hive_count = m_pHives->GetChildCount(wxDataViewItem(wxNullPtr));
wxString msg;
wxTextEntryDialog renameEntry(this, _("Enter new name"), wxGetTextFromUserPromptStr,
wxEmptyString, wxTextEntryDialogStyle, wxDefaultPosition);
renameEntry.SetTextValidator(wxFILTER_EMPTY);
switch (renameEntry.ShowModal())
{
case wxID_OK:
{
wxString hive_name = renameEntry.GetValue();
while(!nodes.empty())
{
current_item = nodes.front();
nodes.pop_front();
if (m_pHives->GetItemText(current_item) == hive_name)
{
found_item = current_item;
SH_LOG_DEBUG("Found item: {}", m_pHives->GetItemText(current_item).ToStdString());
break;
}
wxDataViewItem child = m_pHives->GetNthChild(wxDataViewItem(wxNullPtr), 0);
while (row < (hive_count - 1))
{
row ++;
child = m_pHives->GetNthChild(wxDataViewItem(wxNullPtr), row);
nodes.push_back(child);
}
}
nodes.clear();
if (found_item.IsOk())
{
wxMessageBox(wxString::Format(_("Another hive by the name %s already exist. "
"Please try with a different name."), hive_name),
_("Error!"), wxOK | wxCENTRE, this);
}
else
{
wxString selected_hive_name = m_pHives->GetItemText(selected_hive);
int sample_count = m_pHives->GetChildCount(selected_hive);
if (sample_count <= 0)
{
m_pHives->SetItemText(selected_hive, hive_name);
db.UpdateHive(selected_hive_name.ToStdString(), hive_name.ToStdString());
}
else
{
for (int i = 0; i < sample_count; i++)
{
wxDataViewItem sample_item = m_pHives->GetNthChild(selected_hive, i);
wxString sample_name = serializer.DeserializeShowFileExtension() ?
m_pHives->GetItemText(sample_item).BeforeLast('.') :
m_pHives->GetItemText(sample_item);
db.UpdateHiveName(sample_name.ToStdString(), hive_name.ToStdString());
db.UpdateHive(selected_hive_name.ToStdString(), hive_name.ToStdString());
m_pHives->SetItemText(selected_hive, hive_name);
}
}
msg = wxString::Format(_("Successfully changed hive name to %s."), hive_name);
}
}
break;
case wxID_CANCEL:
break;
default:
return;
}
if (!msg.IsEmpty())
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_INFORMATION, *this);
}
break;
case SampleHive::ID::MN_DeleteHive:
{
wxString msg;
wxMessageDialog deleteEmptyHiveDialog(this, wxString::Format(_("Are you sure you want to delete %s from hives?"),
hive_name),
wxMessageBoxCaptionStr,
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION | wxSTAY_ON_TOP);
wxMessageDialog deleteFilledHiveDialog(this, wxString::Format(_("Are you sure you want to delete %s and all samples "
"inside %s from hives?"), hive_name, hive_name),
wxMessageBoxCaptionStr,
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION | wxSTAY_ON_TOP);
if (hive_name == m_pHives->GetItemText(m_FavoritesHive))
{
wxMessageBox(wxString::Format(_("Error! Default hive %s cannot be deleted."), hive_name),
_("Error!"), wxOK | wxCENTRE, this);
return;
}
else if (!selected_hive.IsOk())
{
wxMessageBox(_("No hive selected, try selecting a hive first"), _("Error!"),
wxOK | wxCENTRE, this);
return;
}
else if (selected_hive.IsOk() && !m_pHives->IsContainer(selected_hive))
{
wxMessageBox(wxString::Format(_("Error! %s is not a hive, cannot delete from hives."), hive_name),
_("Error!"), wxOK | wxCENTRE, this);
return;
}
if (m_pHives->GetChildCount(selected_hive) <= 0)
{
switch (deleteEmptyHiveDialog.ShowModal())
{
case wxID_YES:
if (selected_hive.IsOk() && m_pHives->IsContainer(selected_hive) &&
hive_name != m_pHives->GetItemText(m_FavoritesHive))
{
m_pHives->DeleteItem(selected_hive);
db.RemoveHiveFromDatabase(hive_name.ToStdString());
msg = wxString::Format(_("%s deleted from hives successfully."), hive_name);
}
break;
case wxID_NO:
break;
default:
return;
}
}
else
{
switch (deleteFilledHiveDialog.ShowModal())
{
case wxID_YES:
if (selected_hive.IsOk() && m_pHives->IsContainer(selected_hive) &&
hive_name != m_pHives->GetItemText(m_FavoritesHive))
{
wxDataViewItem child_item;
for (int i = 0; i < SampleHive::cHiveData::Get().GetListCtrlItemCount(); i++)
{
wxString matched_sample = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetListCtrlTextValue(i, 1).BeforeLast('.') :
SampleHive::cHiveData::Get().GetListCtrlTextValue(i, 1);
for (int j = 0; j < m_pHives->GetChildCount(selected_hive); j++)
{
child_item = m_pHives->GetNthChild(selected_hive, j);
wxString child_name =
serializer.DeserializeShowFileExtension() ?
m_pHives->GetItemText(child_item).BeforeLast('.') :
m_pHives->GetItemText(child_item);
if (child_name == matched_sample)
{
SH_LOG_DEBUG("Found match");
SampleHive::cHiveData::Get().ListCtrlSetVariant(wxVariant(wxBitmap(ICON_STAR_EMPTY_16px, wxBITMAP_TYPE_PNG)),
i, 0);
db.UpdateFavoriteColumn(matched_sample.ToStdString(), 0);
db.UpdateHiveName(matched_sample.ToStdString(),
m_pHives->GetItemText(m_FavoritesHive).ToStdString());
break;
}
else
SH_LOG_DEBUG("No match found");
}
}
m_pHives->DeleteChildren(selected_hive);
m_pHives->DeleteItem(selected_hive);
db.RemoveHiveFromDatabase(hive_name.ToStdString());
msg = wxString::Format(_("%s and all samples inside %s have been deleted from hives successfully."),
hive_name, hive_name);
}
break;
case wxID_NO:
break;
default:
return;
}
}
if (!msg.IsEmpty())
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_INFORMATION, *this);
}
break;
case SampleHive::ID::MN_FilterLibrary:
{
if (!m_bFiltered)
{
try
{
const auto dataset = db.FilterDatabaseByHiveName(hive_name.ToStdString(),
serializer.DeserializeShowFileExtension(),
ICON_STAR_FILLED_16px, ICON_STAR_EMPTY_16px);
if (dataset.empty())
{
wxMessageBox(_("Error! Database is empty."), _("Error!"),
wxOK | wxICON_ERROR | wxCENTRE, this);
return;
}
else
{
SampleHive::cHiveData::Get().ListCtrlDeleteAllItems();
for (auto data : dataset)
{
SampleHive::cHiveData::Get().ListCtrlAppendItem(data);
}
}
}
catch (std::exception& e)
{
wxMessageBox(wxString::Format(_("Error loading data, cannot filter sample view. Error: %s"), e.what()),
_("Error!"), wxOK | wxICON_ERROR | wxCENTRE, this);
}
m_bFiltered = true;
}
else
{
try
{
const auto dataset = db.FilterDatabaseBySampleName("", serializer.DeserializeShowFileExtension(),
ICON_STAR_FILLED_16px, ICON_STAR_EMPTY_16px);
if (dataset.empty())
{
wxMessageBox(_("Error! Database is empty."), _("Error!"), wxOK | wxICON_ERROR | wxCENTRE, this);
}
else
{
SampleHive::cHiveData::Get().ListCtrlDeleteAllItems();
for (auto data : dataset)
{
SampleHive::cHiveData::Get().ListCtrlAppendItem(data);
}
}
}
catch (std::exception& e)
{
wxMessageBox(wxString::Format(_("Error loading data, cannot filter sample view. Error: %s"), e.what()),
_("Error!"), wxOK | wxICON_ERROR | wxCENTRE, this);
}
m_bFiltered = false;
}
}
break;
default:
return;
}
}
else if (selected_hive.IsOk() && !m_pHives->IsContainer(selected_hive))
{
switch (m_pHives->GetPopupMenuSelectionFromUser(menu, event.GetPosition()))
{
case SampleHive::ID::MN_RemoveSample:
for (int i = 0; i < SampleHive::cHiveData::Get().GetListCtrlItemCount(); i++)
{
wxString matched_sample = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetListCtrlTextValue(i, 1).BeforeLast('.') :
SampleHive::cHiveData::Get().GetListCtrlTextValue(i, 1);
wxString selected_sample_name = serializer.DeserializeShowFileExtension() ?
m_pHives->GetItemText(event.GetItem()).BeforeLast('.') :
m_pHives->GetItemText(event.GetItem());
if (selected_sample_name == matched_sample)
{
SH_LOG_DEBUG("Found match");
SampleHive::cHiveData::Get().ListCtrlSetVariant(wxVariant(wxBitmap(ICON_STAR_EMPTY_16px, wxBITMAP_TYPE_PNG)), i, 0);
db.UpdateFavoriteColumn(matched_sample.ToStdString(), 0);
db.UpdateHiveName(matched_sample.ToStdString(), m_pHives->GetItemText(m_FavoritesHive).ToStdString());
m_pHives->DeleteItem(selected_hive);
break;
}
wxString msg = wxString::Format(_("Removed %s from %s"), m_pHives->GetItemText(event.GetItem()),
db.GetHiveByFilename(matched_sample.ToStdString()));
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_INFORMATION, *this);
}
break;
case SampleHive::ID::MN_ShowInLibrary:
for (int i = 0; i < SampleHive::cHiveData::Get().GetListCtrlItemCount(); i++)
{
wxString matched_sample = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetListCtrlTextValue(i, 1).BeforeLast('.') :
SampleHive::cHiveData::Get().GetListCtrlTextValue(i, 1);
wxString selected_sample_name = serializer.DeserializeShowFileExtension() ?
m_pHives->GetItemText(event.GetItem()).BeforeLast('.') :
m_pHives->GetItemText(event.GetItem());
if (selected_sample_name == matched_sample)
{
SH_LOG_DEBUG("Found match");
wxDataViewItem matched_item = SampleHive::cHiveData::Get().GetListCtrlItemFromRow(i);
SampleHive::cHiveData::Get().ListCtrlUnselectAllItems();
SampleHive::cHiveData::Get().ListCtrlSelectRow(i);
SampleHive::cHiveData::Get().ListCtrlEnsureVisible(matched_item);
break;
}
}
break;
default:
return;
}
}
}
void cHivesPanel::OnHiveStartEditing(wxDataViewEvent &event)
{
SH_LOG_INFO("Right click on a hive and select rename to rename it..");
event.Veto();
}
void cHivesPanel::OnClickAddHive(wxCommandEvent& event)
{
cDatabase db;
std::deque<wxDataViewItem> nodes;
nodes.push_back(m_pHives->GetNthChild(wxDataViewItem(wxNullPtr), 0));
wxDataViewItem current_item, found_item;
int row = 0;
int hive_count = m_pHives->GetChildCount(wxDataViewItem(wxNullPtr));
wxString msg;
wxTextEntryDialog hiveEntry(this, _("Enter hive name"), _("Create new hive"), wxEmptyString,
wxTextEntryDialogStyle, wxDefaultPosition);
hiveEntry.SetTextValidator(wxFILTER_EMPTY);
switch (hiveEntry.ShowModal())
{
case wxID_OK:
{
wxString hive_name = hiveEntry.GetValue();
while (!nodes.empty())
{
current_item = nodes.front();
nodes.pop_front();
if (m_pHives->GetItemText(current_item) == hive_name)
{
found_item = current_item;
SH_LOG_DEBUG("Found item: {}", m_pHives->GetItemText(current_item).ToStdString());
break;
}
wxDataViewItem child = m_pHives->GetNthChild(wxDataViewItem(wxNullPtr), 0);
while (row < (hive_count - 1))
{
row ++;
child = m_pHives->GetNthChild(wxDataViewItem(wxNullPtr), row);
nodes.push_back(child);
}
}
nodes.clear();
if (found_item.IsOk())
{
wxMessageBox(wxString::Format(_("Another hive by the name %s already exist. Please try with a different name."),
hive_name), _("Error!"), wxOK | wxCENTRE, this);
}
else
{
m_pHives->AppendContainer(wxDataViewItem(wxNullPtr), hive_name);
db.InsertIntoHives(hive_name.ToStdString());
msg = wxString::Format(_("%s added to Hives."), hive_name);
}
break;
}
case wxID_CANCEL:
break;
default:
return;
}
if (!msg.IsEmpty())
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_INFORMATION, *this);
}
void cHivesPanel::OnClickRemoveHive(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
cDatabase db;
wxDataViewItem selected_item = m_pHives->GetSelection();
wxString hive_name = m_pHives->GetItemText(selected_item);
wxString msg;
wxMessageDialog deleteEmptyHiveDialog(this, wxString::Format(_("Are you sure you want to delete %s from hives?"), hive_name),
wxMessageBoxCaptionStr, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION | wxSTAY_ON_TOP);
wxMessageDialog deleteFilledHiveDialog(this, wxString::Format(_("Are you sure you want to delete "
"%s and all sample inside %s from hives?"), hive_name, hive_name),
wxMessageBoxCaptionStr, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION | wxSTAY_ON_TOP);
if (hive_name == m_pHives->GetItemText(m_FavoritesHive))
{
wxMessageBox(wxString::Format(_("Error! Default hive %s cannot be deleted."), hive_name), _("Error!"), wxOK | wxCENTRE, this);
return;
}
else if (!selected_item.IsOk())
{
wxMessageBox(_("No hive selected, try selecting a hive first"), _("Error!"), wxOK | wxCENTRE, this);
return;
}
else if (selected_item.IsOk() && !m_pHives->IsContainer(selected_item))
{
wxMessageBox(wxString::Format(_("Error! %s is not a hive, cannot delete from hives."), hive_name),
_("Error!"), wxOK | wxCENTRE, this);
return;
}
if (m_pHives->GetChildCount(selected_item) <= 0)
{
switch (deleteEmptyHiveDialog.ShowModal())
{
case wxID_YES:
if (selected_item.IsOk() && m_pHives->IsContainer(selected_item) &&
hive_name != m_pHives->GetItemText(m_FavoritesHive))
{
m_pHives->DeleteItem(selected_item);
db.RemoveHiveFromDatabase(hive_name.ToStdString());
msg = wxString::Format(_("%s deleted from hives successfully."), hive_name);
}
break;
case wxID_NO:
break;
default:
return;
}
}
else
{
switch (deleteFilledHiveDialog.ShowModal())
{
case wxID_YES:
if (selected_item.IsOk() && m_pHives->IsContainer(selected_item) &&
hive_name != m_pHives->GetItemText(m_FavoritesHive))
{
wxDataViewItem child_item;
for (int i = 0; i < SampleHive::cHiveData::Get().GetListCtrlItemCount(); i++)
{
wxString matched_sample = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetListCtrlTextValue(i, 1).BeforeLast('.') :
SampleHive::cHiveData::Get().GetListCtrlTextValue(i, 1);
for (int j = 0; j < m_pHives->GetChildCount(selected_item); j++)
{
child_item = m_pHives->GetNthChild(selected_item, j);
wxString child_name = serializer.DeserializeShowFileExtension() ?
m_pHives->GetItemText(child_item).BeforeLast('.') :
m_pHives->GetItemText(child_item);
if (child_name == matched_sample)
{
SH_LOG_DEBUG("Found match");
SampleHive::cHiveData::Get().ListCtrlSetVariant(wxVariant(wxBitmap(ICON_STAR_EMPTY_16px, wxBITMAP_TYPE_PNG)), i, 0);
db.UpdateFavoriteColumn(matched_sample.ToStdString(), 0);
db.UpdateHiveName(matched_sample.ToStdString(), m_pHives->GetItemText(m_FavoritesHive).ToStdString());
break;
}
else
SH_LOG_DEBUG("No match found");
}
}
m_pHives->DeleteChildren(selected_item);
m_pHives->DeleteItem(selected_item);
db.RemoveHiveFromDatabase(hive_name.ToStdString());
msg = wxString::Format(_("%s and all samples inside %s have been deleted from hives successfully."),
hive_name, hive_name);
}
break;
case wxID_NO:
break;
default:
return;
}
}
if (!msg.IsEmpty())
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_INFORMATION, *this);
}
cHivesPanel::~cHivesPanel()
{
}

69
src/GUI/Hives.hpp Normal file
View File

@ -0,0 +1,69 @@
/* 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/button.h>
#include <wx/dataview.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/window.h>
class cHivesPanel : public wxPanel
{
public:
// -------------------------------------------------------------------
cHivesPanel(wxWindow* window);
~cHivesPanel();
public:
// -------------------------------------------------------------------
wxDataViewTreeCtrl* GetHivesObject() { return m_pHives; }
wxDataViewItem& GetFavoritesHive() { return m_FavoritesHive; }
bool IsLibraryFiltered() { return m_bFiltered; }
private:
// -------------------------------------------------------------------
// Hives panel button event handlers
void OnDragAndDropToHives(wxDropFilesEvent& event);
void OnClickAddHive(wxCommandEvent& event);
void OnClickRemoveHive(wxCommandEvent& event);
void OnShowHivesContextMenu(wxDataViewEvent& event);
void OnHiveStartEditing(wxDataViewEvent& event);
private:
// -------------------------------------------------------------------
wxDataViewItem m_FavoritesHive;
wxDataViewTreeCtrl* m_pHives = nullptr;
wxButton* m_pAddHiveButton = nullptr;
wxButton* m_pRemoveHiveButton = nullptr;
wxBoxSizer* m_pMainSizer = nullptr;
wxBoxSizer* m_pHivesSizer = nullptr;
wxBoxSizer* m_pButtonSizer = nullptr;
private:
// -------------------------------------------------------------------
bool m_bFiltered = false;
// -------------------------------------------------------------------
wxWindow* m_pWindow = nullptr;
};

32
src/GUI/InfoBar.cpp Normal file
View File

@ -0,0 +1,32 @@
/* 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 "InfoBar.hpp"
cInfoBar::cInfoBar(wxWindow* window)
: wxInfoBar(window)
{
}
cInfoBar::~cInfoBar()
{
}

37
src/GUI/InfoBar.hpp Normal file
View File

@ -0,0 +1,37 @@
/* 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/infobar.h>
#include <wx/window.h>
class cInfoBar : public wxInfoBar
{
public:
cInfoBar(wxWindow* window);
~cInfoBar();
public:
wxInfoBar* GetInfoBarObject() { return this; }
private:
wxWindow* m_pWindow;
};

47
src/GUI/Library.cpp Normal file
View File

@ -0,0 +1,47 @@
/* 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 "GUI/Library.hpp"
#include "Utility/Log.hpp"
cLibrary::cLibrary(wxWindow* window)
: wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
{
m_pSizer = new wxBoxSizer(wxVERTICAL);
m_pSearchBar = new cSearchBar(this);
m_pInfoBar = new cInfoBar(this);
m_pListCtrl = new cListCtrl(this);
m_pSizer->Add(m_pSearchBar, wxSizerFlags(1).Expand());
m_pSizer->Add(m_pInfoBar, wxSizerFlags(0).Expand());
m_pSizer->Add(m_pListCtrl, wxSizerFlags(1).Expand());
// Sizer for bottom right panel
this->SetSizer(m_pSizer);
m_pSizer->Fit(this);
m_pSizer->SetSizeHints(this);
m_pSizer->Layout();
}
cLibrary::~cLibrary()
{
}

49
src/GUI/Library.hpp Normal file
View File

@ -0,0 +1,49 @@
/* 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 "GUI/InfoBar.hpp"
#include "GUI/ListCtrl.hpp"
#include "GUI/SearchBar.hpp"
#include <wx/dataview.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/treectrl.h>
#include <wx/window.h>
class cLibrary : public wxPanel
{
public:
cLibrary(wxWindow* window);
~cLibrary();
public:
wxSearchCtrl* GetSearchCtrlObject() const { return m_pSearchBar; }
wxInfoBar* GetInfoBarObject() const { return m_pInfoBar; }
wxDataViewListCtrl* GetListCtrlObject() const { return m_pListCtrl; }
private:
cSearchBar* m_pSearchBar = nullptr;
cInfoBar* m_pInfoBar = nullptr;
cListCtrl* m_pListCtrl = nullptr;
wxBoxSizer* m_pSizer = nullptr;
};

805
src/GUI/ListCtrl.cpp Normal file
View File

@ -0,0 +1,805 @@
/* 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 "GUI/ListCtrl.hpp"
#include "GUI/Dialogs/TagEditor.hpp"
#include "Database/Database.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Serialize.hpp"
#include "Utility/Event.hpp"
#include "Utility/Signal.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Utils.hpp"
#include <wx/dir.h>
#include <wx/gdicmn.h>
#include <wx/menu.h>
#include <wx/progdlg.h>
#include <wx/msgdlg.h>
cListCtrl::cListCtrl(wxWindow* window)
: wxDataViewListCtrl(window, SampleHive::ID::BC_Library, wxDefaultPosition, wxDefaultSize,
wxDV_MULTIPLE | wxDV_HORIZ_RULES | wxDV_VERT_RULES | wxDV_ROW_LINES),
m_pWindow(window)
{
// Adding columns to wxDataViewListCtrl.
AppendBitmapColumn(wxBitmap(ICON_STAR_FILLED_16px, wxBITMAP_TYPE_PNG),
0,
wxDATAVIEW_CELL_ACTIVATABLE,
30,
wxALIGN_CENTER,
!wxDATAVIEW_COL_RESIZABLE);
AppendTextColumn(_("Filename"),
wxDATAVIEW_CELL_INERT,
250,
wxALIGN_LEFT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("Sample Pack"),
wxDATAVIEW_CELL_INERT,
180,
wxALIGN_LEFT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("Type"),
wxDATAVIEW_CELL_INERT,
120,
wxALIGN_LEFT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("Channels"),
wxDATAVIEW_CELL_INERT,
90,
wxALIGN_RIGHT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("BPM"),
wxDATAVIEW_CELL_INERT,
80,
wxALIGN_RIGHT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("Length"),
wxDATAVIEW_CELL_INERT,
80,
wxALIGN_RIGHT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("Sample Rate"),
wxDATAVIEW_CELL_INERT,
120,
wxALIGN_RIGHT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("Bitrate"),
wxDATAVIEW_CELL_INERT,
80,
wxALIGN_RIGHT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
AppendTextColumn(_("Path"),
wxDATAVIEW_CELL_INERT,
250,
wxALIGN_LEFT,
wxDATAVIEW_COL_RESIZABLE |
wxDATAVIEW_COL_SORTABLE |
wxDATAVIEW_COL_REORDERABLE);
// Enable cListCtrl to accept files to be dropped on it
this->DragAcceptFiles(true);
// Enable dragging a file from cListCtrl
this->EnableDragSource(wxDF_FILENAME);
Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, &cListCtrl::OnClickLibrary, this, SampleHive::ID::BC_Library);
Bind(wxEVT_DATAVIEW_ITEM_ACTIVATED, &cListCtrl::OnDoubleClickLibrary, this, SampleHive::ID::BC_Library);
Bind(wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, &cListCtrl::OnDragFromLibrary, this);
this->Connect(wxEVT_DROP_FILES, wxDropFilesEventHandler(cListCtrl::OnDragAndDropToLibrary), NULL, this);
Bind(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, &cListCtrl::OnShowLibraryContextMenu, this, SampleHive::ID::BC_Library);
Bind(wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, &cListCtrl::OnShowLibraryColumnHeaderContextMenu, this, SampleHive::ID::BC_Library);
}
void cListCtrl::OnClickLibrary(wxDataViewEvent& event)
{
cDatabase db;
int selected_row = this->ItemToRow(event.GetItem());
int current_row = this->ItemToRow(this->GetCurrentItem());
if (selected_row < 0 || !event.GetItem().IsOk())
return;
if (selected_row != current_row)
{
this->SetCurrentItem(event.GetItem());
return;
}
// Update the waveform bitmap
SampleHive::cSignal::SendWaveformUpdateStatus(*this);
// Update LoopAB button value
SampleHive::cSignal::SendLoopABButtonValueChange(*this);
// Stop the timer
SampleHive::cSignal::SendTimerStopStatus(*this);
wxString selection = this->GetTextValue(selected_row, 1);
// Get curremt column
wxDataViewColumn* CurrentColumn = this->GetCurrentColumn();
// Get favorite column
wxDataViewColumn* FavoriteColumn = this->GetColumn(0);
if (!CurrentColumn)
return;
wxString sample_path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Path;
std::string filename = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Filename;
std::string extension = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Extension;
if (CurrentColumn != FavoriteColumn)
{
// ClearLoopPoints();
SampleHive::cSignal::SendClearLoopPointsStatus(*this);
// Play the sample
SampleHive::cSignal::SendCallFunctionPlay(selection, true, *this);
}
else
{
wxString msg;
// Get hive name and location
std::string hive_name = SampleHive::cHiveData::Get().GetHiveItemText(true).ToStdString();
wxDataViewItem hive_selection = SampleHive::cHiveData::Get().GetHiveItemSelection();
SH_LOG_DEBUG("HIVE NAME: {}", hive_name);
if (hive_selection.IsOk() && SampleHive::cHiveData::Get().IsHiveItemContainer(hive_selection))
hive_name = SampleHive::cHiveData::Get().GetHiveItemText(false, hive_selection);
wxString name = this->GetTextValue(selected_row, 1);
// Get root
wxDataViewItem root = wxDataViewItem(wxNullPtr);
wxDataViewItem container;
wxDataViewItem child;
if (db.GetFavoriteColumnValueByFilename(filename) == 0)
{
this->SetValue(wxVariant(wxBitmap(ICON_STAR_FILLED_16px, wxBITMAP_TYPE_PNG)), selected_row, 0);
db.UpdateFavoriteColumn(filename, 1);
db.UpdateHiveName(filename, hive_name);
for (int i = 0; i < SampleHive::cHiveData::Get().GetHiveChildCount(root); i++)
{
container = SampleHive::cHiveData::Get().GetHiveNthChild(root, i);
if (SampleHive::cHiveData::Get().GetHiveItemText(false, container) == hive_name)
{
SampleHive::cHiveData::Get().HiveAppendItem(container, name);
break;
}
}
msg = wxString::Format(_("Added %s to %s"), name, hive_name);
}
else
{
this->SetValue(wxVariant(wxBitmap(ICON_STAR_EMPTY_16px, wxBITMAP_TYPE_PNG)), selected_row, 0);
db.UpdateFavoriteColumn(filename, 0);
db.UpdateHiveName(filename, SampleHive::cHiveData::Get().GetHiveItemText(true).ToStdString());
for (int i = 0; i < SampleHive::cHiveData::Get().GetHiveChildCount(root); i++)
{
container = SampleHive::cHiveData::Get().GetHiveNthChild(root, i);
for (int j = 0; j < SampleHive::cHiveData::Get().GetHiveChildCount(container); j++)
{
child = SampleHive::cHiveData::Get().GetHiveNthChild(container, j);
if (SampleHive::cHiveData::Get().GetHiveItemText(false, child) == name)
{
SampleHive::cHiveData::Get().HiveDeleteItem(child);
break;
}
}
}
msg = wxString::Format(_("Removed %s from %s"), name, hive_name);
}
if (!msg.IsEmpty())
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_INFORMATION, *this);
}
}
void cListCtrl::OnDoubleClickLibrary(wxDataViewEvent& event)
{
cDatabase db;
SampleHive::cSerializer serializer;
int selected_row = this->ItemToRow(event.GetItem());
int current_row = this->ItemToRow(this->GetCurrentItem());
if (selected_row < 0 || !event.GetItem().IsOk())
return;
if (selected_row != current_row)
{
this->SetCurrentItem(event.GetItem());
return;
}
// Update the waveform bitmap
SampleHive::cSignal::SendWaveformUpdateStatus(*this);
// Update LoopAB button value
SampleHive::cSignal::SendLoopABButtonValueChange(*this);
// Stop the timer
SampleHive::cSignal::SendTimerStopStatus(*this);
wxString selection = this->GetTextValue(selected_row, 1);
// Get curremt column
wxDataViewColumn* CurrentColumn = this->GetCurrentColumn();
// Get favorite column
wxDataViewColumn* FavoriteColumn = this->GetColumn(0);
if (!CurrentColumn)
return;
if (CurrentColumn != FavoriteColumn)
{
// ClearLoopPoints();
SampleHive::cSignal::SendClearLoopPointsStatus(*this);
// Play the sample
if (serializer.DeserializeDoubleClickToPlay())
SampleHive::cSignal::SendCallFunctionPlay(selection, false, *this);
}
}
void cListCtrl::OnDragAndDropToLibrary(wxDropFilesEvent& event)
{
SH_LOG_DEBUG("Start Inserting Samples");
if (event.GetNumberOfFiles() > 0)
{
wxString* dropped = event.GetFiles();
wxASSERT(dropped);
wxBusyCursor busy_cursor;
wxWindowDisabler window_disabler;
wxString name;
wxString filepath;
wxArrayString filepath_array;
wxProgressDialog* progressDialog = new wxProgressDialog(_("Reading files.."),
_("Reading files, please wait..."),
event.GetNumberOfFiles(), this,
wxPD_APP_MODAL | wxPD_SMOOTH |
wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
progressDialog->CenterOnParent(wxBOTH);
wxYield();
for (int i = 0; i < event.GetNumberOfFiles(); i++)
{
filepath = dropped[i];
if (wxFileExists(filepath))
{
filepath_array.push_back(filepath);
}
else if (wxDirExists(filepath))
{
wxDir::GetAllFiles(filepath, &filepath_array);
}
progressDialog->Pulse(_("Reading Samples"), NULL);
}
progressDialog->Destroy();
SampleHive::cUtils::Get().AddSamples(filepath_array, m_pWindow);
SH_LOG_DEBUG("Done Inserting Samples");
}
}
void cListCtrl::OnDragFromLibrary(wxDataViewEvent& event)
{
int selected_row = this->ItemToRow(event.GetItem());
if (selected_row < 0)
return;
wxString selection = this->GetTextValue(selected_row, 1);
wxString sample_path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Path;
wxFileDataObject* fileData = new wxFileDataObject();
fileData->AddFile(sample_path);
event.SetDataObject(fileData);
SH_LOG_DEBUG("Started dragging '{}'.", sample_path.ToStdString());
}
void cListCtrl::OnShowLibraryContextMenu(wxDataViewEvent& event)
{
cTagEditor* tagEditor;
cDatabase db;
SampleHive::cSerializer serializer;
wxString msg;
wxDataViewItem item = event.GetItem();
int selected_row;
if (item.IsOk())
selected_row = this->ItemToRow(item);
else
return;
wxString selection = this->GetTextValue(selected_row, 1);
wxString sample_path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Path;
std::string filename = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Filename;
std::string extension = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Extension;
wxMenu menu;
//true = add false = remove
bool favorite_add = false;
if (db.GetFavoriteColumnValueByFilename(filename) == 1)
menu.Append(SampleHive::ID::MN_FavoriteSample, _("Remove from hive"), _("Remove the selected sample(s) from hive"));
else
{
menu.Append(SampleHive::ID::MN_FavoriteSample, _("Add to hive"), _("Add selected sample(s) to hive"));
favorite_add = true;
}
menu.Append(SampleHive::ID::MN_DeleteSample, _("Delete"), _("Delete the selected sample(s) from database"));
menu.Append(SampleHive::ID::MN_TrashSample, _("Trash"), _("Send the selected sample(s) to trash"));
if (this->GetSelectedItemsCount() <= 1)
{
menu.Append(SampleHive::ID::MN_EditTagSample, _("Edit tags"),
_("Edit the tags for the selected sample"))->Enable(true);
menu.Append(SampleHive::ID::MN_OpenFile, _("Open in file manager"),
_("Open the selected sample in system's file manager"))->Enable(true);
}
else
{
menu.Append(SampleHive::ID::MN_EditTagSample, _("Edit tags"),
_("Edit the tags for the selected sample"))->Enable(false);
menu.Append(SampleHive::ID::MN_OpenFile, _("Open in file manager"),
_("Open the selected sample in system's file manager"))->Enable(false);
}
switch (this->GetPopupMenuSelectionFromUser(menu, event.GetPosition()))
{
case SampleHive::ID::MN_FavoriteSample:
{
std::string hive_name = SampleHive::cHiveData::Get().GetHiveItemText(true).ToStdString();
wxDataViewItem hive_selection = SampleHive::cHiveData::Get().GetHiveItemSelection();
if (hive_selection.IsOk() && SampleHive::cHiveData::Get().IsHiveItemContainer(hive_selection))
hive_name = SampleHive::cHiveData::Get().GetHiveItemText(false, hive_selection);
wxDataViewItem root = wxDataViewItem(wxNullPtr);
wxDataViewItem container;
wxDataViewItem child;
wxDataViewItemArray samples;
int sample_count = this->GetSelections(samples);
int selected_row = 0;
int db_status = 0;
for (int k = 0; k < sample_count; k++)
{
selected_row = this->ItemToRow(samples[k]);
if (selected_row < 0)
continue;
wxString name = this->GetTextValue(selected_row, 1);
filename = serializer.DeserializeShowFileExtension() ?
name.BeforeLast('.').ToStdString() : name.ToStdString();
db_status = db.GetFavoriteColumnValueByFilename(filename);
// Aleady Added, Do Nothing
if (favorite_add && db_status == 1)
continue;
// Already Removed, Do Nothing
if (!favorite_add && db_status == 0)
continue;
// Add To Favorites
if (favorite_add && db_status == 0)
{
this->SetValue(wxVariant(wxBitmap(ICON_STAR_FILLED_16px, wxBITMAP_TYPE_PNG)), selected_row, 0);
db.UpdateFavoriteColumn(filename, 1);
db.UpdateHiveName(filename, hive_name);
for (int i = 0; i < SampleHive::cHiveData::Get().GetHiveChildCount(root); i++)
{
container = SampleHive::cHiveData::Get().GetHiveNthChild(root, i);
if (SampleHive::cHiveData::Get().GetHiveItemText(false, container) == hive_name)
{
SampleHive::cHiveData::Get().HiveAppendItem(container, name);
msg = wxString::Format(_("Added %s to %s"), name, hive_name);
break;
}
}
}
else
{
//Remove From Favorites
this->SetValue(wxVariant(wxBitmap(ICON_STAR_EMPTY_16px, wxBITMAP_TYPE_PNG)), selected_row, 0);
db.UpdateFavoriteColumn(filename, 0);
db.UpdateHiveName(filename, SampleHive::cHiveData::Get().GetHiveItemText(true).ToStdString());
for (int i = 0; i < SampleHive::cHiveData::Get().GetHiveChildCount(root); i++)
{
container = SampleHive::cHiveData::Get().GetHiveNthChild(root, i);
for (int j = 0; j < SampleHive::cHiveData::Get().GetHiveChildCount(container); j++)
{
child = SampleHive::cHiveData::Get().GetHiveNthChild(container, j);
if (SampleHive::cHiveData::Get().GetHiveItemText(false, child) == name)
{
SampleHive::cHiveData::Get().HiveDeleteItem(child);
msg = wxString::Format(_("Removed %s from %s"), name, hive_name);
break;
}
}
}
}
}
break;
}
case SampleHive::ID::MN_DeleteSample:
{
wxDataViewItemArray items;
int rows = this->GetSelections(items);
wxMessageDialog singleMsgDialog(this, wxString::Format(_("Are you sure you want to delete %s from database? "
"Warning this change is permanent, and cannot be undone."),
sample_path.AfterLast('/')),
wxMessageBoxCaptionStr,
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION | wxSTAY_ON_TOP | wxCENTER);
wxMessageDialog multipleMsgDialog(this, wxString::Format(_("Are you sure you want to delete "
"%d selected samples from database? Warning this change is "
"permanent, and cannot be undone."), rows),
wxMessageBoxCaptionStr,
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION | wxSTAY_ON_TOP | wxCENTER);
wxDataViewItem root = wxDataViewItem(wxNullPtr);
wxDataViewItem container;
wxDataViewItem child;
if (this->GetSelectedItemsCount() <= 1)
{
switch (singleMsgDialog.ShowModal())
{
case wxID_YES:
{
db.RemoveSampleFromDatabase(filename);
this->DeleteItem(selected_row);
for (int j = 0; j < SampleHive::cHiveData::Get().GetHiveChildCount(root); j++)
{
container = SampleHive::cHiveData::Get().GetHiveNthChild(root, j);
for (int k = 0; k < SampleHive::cHiveData::Get().GetHiveChildCount(container); k++)
{
child = SampleHive::cHiveData::Get().GetHiveNthChild(container, k);
wxString child_text = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetHiveItemText(false, child).BeforeLast('.') :
SampleHive::cHiveData::Get().GetHiveItemText(false, child);
if (child_text == filename)
{
SampleHive::cHiveData::Get().HiveDeleteItem(child);
break;
}
}
}
msg = wxString::Format(_("Deleted %s from database successfully"), selection);
}
break;
case wxID_NO:
msg = _("Cancel delete");
break;
default:
wxMessageBox(_("Unexpected wxMessageDialog return code!"), _("Error!"),
wxOK | wxICON_ERROR | wxCENTRE, this);
}
}
else
{
switch (multipleMsgDialog.ShowModal())
{
case wxID_YES:
{
for (int i = 0; i < rows; i++)
{
int row = this->ItemToRow(items[i]);
wxString text_value = this->GetTextValue(row, 1);
std::string multi_selection = serializer.DeserializeShowFileExtension() ?
text_value.BeforeLast('.').ToStdString() : text_value.ToStdString() ;
db.RemoveSampleFromDatabase(multi_selection);
this->DeleteItem(row);
for (int j = 0; j < SampleHive::cHiveData::Get().GetHiveChildCount(root); j++)
{
container = SampleHive::cHiveData::Get().GetHiveNthChild(root, j);
for (int k = 0; k < SampleHive::cHiveData::Get().GetHiveChildCount(container); k++)
{
child = SampleHive::cHiveData::Get().GetHiveNthChild(container, k);
wxString child_text = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetHiveItemText(false, child).BeforeLast('.') :
SampleHive::cHiveData::Get().GetHiveItemText(false, child);
if (child_text == multi_selection)
{
SampleHive::cHiveData::Get().HiveDeleteItem(child);
break;
}
}
}
msg = wxString::Format(_("Deleted %s from database successfully"), text_value);
}
}
break;
case wxID_NO:
msg = _("Cancel delete");
break;
default:
wxMessageBox(_("Unexpected wxMessageDialog return code!"), _("Error!"),
wxOK | wxICON_ERROR | wxCENTRE, this);
}
}
}
break;
case SampleHive::ID::MN_TrashSample:
{
wxDataViewItem root = wxDataViewItem(wxNullPtr);
wxDataViewItem container, child;
if (db.IsTrashed(filename))
SH_LOG_INFO("{} already trashed", filename);
else
{
wxDataViewItemArray items;
int rows = this->GetSelections(items);
wxString name;
wxFileDataObject file_data;
wxArrayString files;
for (int i = 0; i < rows; i++)
{
int item_row = this->ItemToRow(items[i]);
wxString text_value = this->GetTextValue(item_row, 1);
std::string multi_selection = serializer.DeserializeShowFileExtension() ?
this->GetTextValue(item_row, 1).BeforeLast('.').ToStdString() :
this->GetTextValue(item_row, 1).ToStdString() ;
file_data.AddFile(multi_selection);
files = file_data.GetFilenames();
if (db.GetFavoriteColumnValueByFilename(files[i].ToStdString()))
{
this->SetValue(wxVariant(wxBitmap(ICON_STAR_EMPTY_16px, wxBITMAP_TYPE_PNG)), item_row, 0);
db.UpdateFavoriteColumn(files[i].ToStdString(), 0);
for (int j = 0; j < SampleHive::cHiveData::Get().GetHiveChildCount(root); j++)
{
container = SampleHive::cHiveData::Get().GetHiveNthChild(root, j);
for (int k = 0; k < SampleHive::cHiveData::Get().GetHiveChildCount(container); k++)
{
child = SampleHive::cHiveData::Get().GetHiveNthChild(container, k);
wxString child_text = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetHiveItemText(false, child).BeforeLast('.') :
SampleHive::cHiveData::Get().GetHiveItemText(false, child);
if (child_text == files[i])
{
SampleHive::cHiveData::Get().HiveDeleteItem(child);
break;
}
}
}
}
SampleHive::cHiveData::Get().TrashAppendItem(SampleHive::cHiveData::Get().GetTrashRoot(), text_value);
this->DeleteItem(item_row);
db.UpdateTrashColumn(files[i].ToStdString(), 1);
db.UpdateHiveName(files[i].ToStdString(), SampleHive::cHiveData::Get().GetHiveItemText(true).ToStdString());
msg = wxString::Format(_("%s sent to trash"), text_value);
}
}
}
break;
case SampleHive::ID::MN_EditTagSample:
{
tagEditor = new cTagEditor(this, static_cast<std::string>(sample_path));
switch (tagEditor->ShowModal())
{
case wxID_OK:
SH_LOG_DEBUG("tags dialog ok, Return code: {}", tagEditor->GetReturnCode());
break;
case wxID_APPLY:
SH_LOG_DEBUG("tags dialog apply, Return code: {}", tagEditor->GetReturnCode());
break;
case wxID_CANCEL:
SH_LOG_DEBUG("tags dialog cancel, Return code: {}", tagEditor->GetReturnCode());
break;
default:
msg = _("Unexpected TagEditor return code!");
}
}
break;
case SampleHive::ID::MN_OpenFile:
wxExecute(wxString::Format("xdg-open '%s'", sample_path.BeforeLast('/')));
break;
case wxID_NONE:
return;
default:
wxMessageBox(_("Unexpected wxMenu return code!"), _("Error!"),
wxOK | wxICON_ERROR | wxCENTRE, this);
break;
}
if (!msg.IsEmpty())
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_INFORMATION, *this);
}
void cListCtrl::OnShowLibraryColumnHeaderContextMenu(wxDataViewEvent& event)
{
wxMenu menu;
wxDataViewColumn* FavoriteColumn = this->GetColumn(0);
wxDataViewColumn* FilenameColumn = this->GetColumn(1);
wxDataViewColumn* SamplePackColumn = this->GetColumn(2);
wxDataViewColumn* TypeColumn = this->GetColumn(3);
wxDataViewColumn* ChannelsColumn = this->GetColumn(4);
wxDataViewColumn* BpmColumn = this->GetColumn(5);
wxDataViewColumn* LengthColumn = this->GetColumn(6);
wxDataViewColumn* SampleRateColumn = this->GetColumn(7);
wxDataViewColumn* BitrateColumn = this->GetColumn(8);
wxDataViewColumn* PathColumn = this->GetColumn(9);
menu.AppendCheckItem(SampleHive::ID::MN_ColumnFavorite, _("Favorites"),
_("Toggle favorites column"))->Check(FavoriteColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnFilename, _("Filename"),
_("Toggle filename column"))->Check(FilenameColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnSamplePack, _("Sample Pack"),
_("Toggle sample pack column"))->Check(SamplePackColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnType, _("Type"),
_("Toggle type column"))->Check(TypeColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnChannels, _("Channels"),
_("Toggle channels column"))->Check(ChannelsColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnBPM, _("BPM"),
_("Toggle length column"))->Check(BpmColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnLength, _("Length"),
_("Toggle length column"))->Check(LengthColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnSampleRate, _("Sample Rate"),
_("Toggle sample rate column"))->Check(SampleRateColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnBitrate, _("Bitrate"),
_("Toggle bitrate column"))->Check(BitrateColumn->IsShown());
menu.AppendCheckItem(SampleHive::ID::MN_ColumnPath, _("Path"),
_("Toggle path column"))->Check(PathColumn->IsShown());
switch (this->GetPopupMenuSelectionFromUser(menu, event.GetPosition()))
{
case SampleHive::ID::MN_ColumnFavorite:
FavoriteColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnFavorite));
break;
case SampleHive::ID::MN_ColumnFilename:
FilenameColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnFilename));
break;
case SampleHive::ID::MN_ColumnSamplePack:
SamplePackColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnSamplePack));
break;
case SampleHive::ID::MN_ColumnType:
TypeColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnType));
break;
case SampleHive::ID::MN_ColumnChannels:
ChannelsColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnChannels));
break;
case SampleHive::ID::MN_ColumnBPM:
BpmColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnBPM));
break;
case SampleHive::ID::MN_ColumnLength:
LengthColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnLength));
break;
case SampleHive::ID::MN_ColumnSampleRate:
SampleRateColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnSampleRate));
break;
case SampleHive::ID::MN_ColumnBitrate:
BitrateColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnBitrate));
break;
case SampleHive::ID::MN_ColumnPath:
PathColumn->SetHidden(!menu.IsChecked(SampleHive::ID::MN_ColumnPath));
break;
default:
break;
}
}
cListCtrl::~cListCtrl()
{
}

View File

@ -20,46 +20,32 @@
#pragma once
#include <string>
#include <wx/dataview.h>
#include <wx/treectrl.h>
#include <wx/window.h>
#include <wx/string.h>
struct AudioInfo
{
wxString title;
wxString artist;
wxString album;
wxString genre;
wxString comment;
int channels;
int length;
int sample_rate;
int bitrate;
};
class Tags
class cListCtrl : public wxDataViewListCtrl
{
public:
Tags(const std::string& filepath);
~Tags();
// -------------------------------------------------------------------
cListCtrl(wxWindow* window);
~cListCtrl();
public:
// -------------------------------------------------------------------
wxDataViewListCtrl* GetListCtrlObject() { return this; }
private:
// -------------------------------------------------------------------
const std::string& m_Filepath;
// Library event handlers
void OnClickLibrary(wxDataViewEvent& event);
void OnDoubleClickLibrary(wxDataViewEvent& event);
void OnDragAndDropToLibrary(wxDropFilesEvent& event);
void OnDragFromLibrary(wxDataViewEvent& event);
void OnShowLibraryContextMenu(wxDataViewEvent& event);
void OnShowLibraryColumnHeaderContextMenu(wxDataViewEvent& event);
bool bValid = false;
public:
private:
// -------------------------------------------------------------------
AudioInfo GetAudioInfo();
void SetTitle(std::string artist);
void SetArtist(std::string artist);
void SetAlbum(std::string album);
void SetGenre(std::string genre);
void SetComment(std::string comment);
public:
// -------------------------------------------------------------------
inline bool IsFileValid() { return bValid; }
wxWindow* m_pWindow = nullptr;
};

978
src/GUI/MainFrame.cpp Normal file
View File

@ -0,0 +1,978 @@
/* 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 "GUI/MainFrame.hpp"
#include "GUI/Dialogs/Settings.hpp"
#include "Database/Database.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Utils.hpp"
#include "SampleHiveConfig.hpp"
#include <exception>
#include <wx/aboutdlg.h>
#include <wx/artprov.h>
#include <wx/defs.h>
#include <wx/filedlg.h>
#include <wx/fswatcher.h>
#include <wx/gdicmn.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
#include <wx/stringimpl.h>
cMainFrame::cMainFrame()
: wxFrame(NULL, wxID_ANY, "SampleHive", wxDefaultPosition)
{
// Initialize statusbar with 4 sections
m_pStatusBar = CreateStatusBar(4);
// Set width for each section of the statusbar
int status_width[4] = { 300, -6, -1, -2 };
m_pStatusBar->SetStatusWidths(4, status_width);
m_pHiveBitmap = new wxStaticBitmap(m_pStatusBar, wxID_ANY, wxBitmap(ICON_HIVE_24px, wxBITMAP_TYPE_PNG));
// Initialize menubar and menus
m_pMenuBar = new wxMenuBar();
m_pFileMenu = new wxMenu();
m_pEditMenu = new wxMenu();
m_pViewMenu = new wxMenu();
m_pHelpMenu = new wxMenu();
// File menu items
m_pAddFile = new wxMenuItem(m_pFileMenu, SampleHive::ID::MN_AddFile, _("Add a file\tCtrl+F"), _("Add a file"));
m_pAddFile->SetBitmap(wxArtProvider::GetBitmap(wxART_NORMAL_FILE));
m_pFileMenu->Append(m_pAddFile);
m_pAddDirectory = new wxMenuItem(m_pFileMenu, SampleHive::ID::MN_AddDirectory, _("Add a directory\tCtrl+D"), _("Add a directory"));
m_pAddDirectory->SetBitmap(wxArtProvider::GetBitmap(wxART_FOLDER));
m_pFileMenu->Append(m_pAddDirectory);
m_pFileMenu->AppendSeparator();
m_pFileMenu->Append(wxID_EXIT, wxEmptyString, _("Exits the application"));
// Edit menu items
m_pEditMenu->Append(wxID_PREFERENCES, _("Preferences\tCtrl+P"), _("Open preferences dialog"));
// View menu items
m_pDemoMode = new wxMenuItem(m_pViewMenu, wxID_ANY, _("Demo mode"), _("Toggle demo mode On/Off"), wxITEM_CHECK);
m_pToggleExtension = new wxMenuItem(m_pViewMenu, SampleHive::ID::MN_ToggleExtension,
_("Toggle Extension\tCtrl+E"), _("Show/Hide Extension"), wxITEM_CHECK);
m_pToggleMenuBar = new wxMenuItem(m_pViewMenu, SampleHive::ID::MN_ToggleMenuBar,
_("Toggle Menu Bar\tCtrl+M"), _("Show/Hide Menu Bar"), wxITEM_CHECK);
m_pToggleStatusBar = new wxMenuItem(m_pViewMenu, SampleHive::ID::MN_ToggleStatusBar,
_("Toggle Status Bar\tCtrl+B"), _("Show/Hide Status Bar"), wxITEM_CHECK);
m_pViewMenu->Append(m_pDemoMode)->Check(false);
m_pViewMenu->Append(m_pToggleExtension)->Check(true);
m_pViewMenu->Append(m_pToggleMenuBar)->Check(m_pMenuBar->IsShown());
m_pViewMenu->Append(m_pToggleStatusBar)->Check(m_pStatusBar->IsShown());
// Help menu items
m_pHelpMenu->Append(wxID_REFRESH, _("Reset app data"), _("Clear the application data revert to default configuration"));
m_pHelpMenu->Append(wxID_ABOUT, wxEmptyString, _("Show about the application"));
// Append all menus to menubar
m_pMenuBar->Append(m_pFileMenu, _("&File"));
m_pMenuBar->Append(m_pEditMenu, _("&Edit"));
m_pMenuBar->Append(m_pViewMenu, _("&View"));
m_pMenuBar->Append(m_pHelpMenu, _("&Help"));
// Set the menu bar to use
SetMenuBar(m_pMenuBar);
// Load default yaml config file.
LoadConfigFile();
// Initialize the database
InitDatabase();
// Initializing Sizers
m_pMainSizer = new wxBoxSizer(wxVERTICAL);
m_pTopPanelMainSizer = new wxBoxSizer(wxVERTICAL);
// Creating top splitter window
m_pTopSplitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxSP_NOBORDER | wxSP_LIVE_UPDATE | wxSP_THIN_SASH);
m_pTopSplitter->SetMinimumPaneSize(200);
m_pTopSplitter->SetSashGravity(0);
// Top half of TopSplitter window
m_pTopPanel = new wxPanel(m_pTopSplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
// Bottom half of the TopSplitter window
m_pBottomSplitter = new wxSplitterWindow(m_pTopSplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxSP_NOBORDER | wxSP_LIVE_UPDATE | wxSP_THIN_SASH);
m_pBottomSplitter->SetMinimumPaneSize(300);
m_pBottomSplitter->SetSashGravity(0);
m_pNotebook = new cNotebook(m_pBottomSplitter);
m_pLibrary = new cLibrary(m_pBottomSplitter);
if (m_bDemoMode)
{
m_pLibrary->GetInfoBarObject()->ShowMessage("WARNING: Demo mode is turned on, all samples will be deleted on application exit.", wxICON_WARNING);
}
SampleHive::cHiveData::Get().InitHiveData(*m_pLibrary->GetListCtrlObject(),
*m_pNotebook->GetHivesPanel()->GetHivesObject(),
m_pNotebook->GetHivesPanel()->GetFavoritesHive(),
*m_pNotebook->GetTrashPanel()->GetTrashObject(),
m_pNotebook->GetTrashPanel()->GetTrashRoot());
// Set split direction
m_pTopSplitter->SplitHorizontally(m_pTopPanel, m_pBottomSplitter);
m_pBottomSplitter->SplitVertically(m_pNotebook, m_pLibrary);
// Initializing wxMediaCtrl.
m_pMediaCtrl = new wxMediaCtrl(this, SampleHive::ID::BC_MediaCtrl, wxEmptyString, wxDefaultPosition,
wxDefaultSize, 0, wxEmptyString);
// Intializing wxTimer
m_pTimer = new wxTimer(this);
m_pTransportControls = new cTransportControls(m_pTopPanel, *m_pMediaCtrl);
m_pWaveformViewer = new cWaveformViewer(m_pTopPanel, *m_pMediaCtrl);
// Binding events.
Bind(wxEVT_MENU, &cMainFrame::OnSelectAddFile, this, SampleHive::ID::MN_AddFile);
Bind(wxEVT_MENU, &cMainFrame::OnSelectAddDirectory, this, SampleHive::ID::MN_AddDirectory);
Bind(wxEVT_MENU, &cMainFrame::OnSelectToggleDemoMode, this, m_pDemoMode->GetId());
Bind(wxEVT_MENU, &cMainFrame::OnSelectToggleExtension, this, SampleHive::ID::MN_ToggleExtension);
Bind(wxEVT_MENU, &cMainFrame::OnSelectToggleMenuBar, this, SampleHive::ID::MN_ToggleMenuBar);
Bind(wxEVT_MENU, &cMainFrame::OnSelectToggleStatusBar, this, SampleHive::ID::MN_ToggleStatusBar);
Bind(wxEVT_MENU, &cMainFrame::OnSelectExit, this, wxID_EXIT);
Bind(wxEVT_MENU, &cMainFrame::OnSelectPreferences, this, wxID_PREFERENCES);
Bind(wxEVT_MENU, &cMainFrame::OnSelectResetAppData, this, wxID_REFRESH);
Bind(wxEVT_MENU, &cMainFrame::OnSelectAbout, this, wxID_ABOUT);
Bind(wxEVT_SPLITTER_SASH_POS_CHANGING, &cMainFrame::OnTopSplitterSashPosChanged, this, m_pTopSplitter->GetId());
Bind(wxEVT_SPLITTER_SASH_POS_CHANGING, &cMainFrame::OnBottomSplitterSashPosChanged, this, m_pBottomSplitter->GetId());
this->Connect(wxEVT_SIZE, wxSizeEventHandler(cMainFrame::OnResizeFrame), NULL, this);
m_pStatusBar->Connect(wxEVT_SIZE, wxSizeEventHandler(cMainFrame::OnResizeStatusBar), NULL, this);
Bind(wxEVT_MEDIA_FINISHED, &cMainFrame::OnMediaFinished, this, SampleHive::ID::BC_MediaCtrl);
Bind(wxEVT_TIMER, &cMainFrame::UpdateElapsedTime, this);
Bind(SampleHive::SH_EVT_LOOP_POINTS_UPDATED, &cMainFrame::OnRecieveLoopPoints, this);
Bind(SampleHive::SH_EVT_LOOP_POINTS_CLEAR, &cMainFrame::OnRecieveClearLoopPointsStatus, this);
Bind(SampleHive::SH_EVT_STATUSBAR_STATUS_PUSH, &cMainFrame::OnRecievePushStatusBarStatus, this);
Bind(SampleHive::SH_EVT_STATUSBAR_STATUS_POP, &cMainFrame::OnRecievePopStatusBarStatus, this);
Bind(SampleHive::SH_EVT_STATUSBAR_STATUS_SET, &cMainFrame::OnRecieveSetStatusBarStatus, this);
Bind(SampleHive::SH_EVT_INFOBAR_MESSAGE_SHOW, &cMainFrame::OnRecieveInfoBarStatus, this);
Bind(SampleHive::SH_EVT_TIMER_STOP, &cMainFrame::OnRecieveTimerStopStatus, this);
Bind(SampleHive::SH_EVT_UPDATE_WAVEFORM, &cMainFrame::OnRecieveWaveformUpdateStatus, this);
Bind(SampleHive::SH_EVT_CALL_FUNC_PLAY, &cMainFrame::OnRecieveCallFunctionPlay, this);
Bind(SampleHive::SH_EVT_LOOP_AB_BUTTON_VALUE_CHANGE, &cMainFrame::OnRecieveLoopABButtonValueChange, this);
// Adding widgets to their sizers
m_pMainSizer->Add(m_pTopSplitter, 1, wxALL | wxEXPAND, 0);
m_pTopPanelMainSizer->Add(m_pWaveformViewer, 1, wxALL | wxEXPAND, 2);
m_pTopPanelMainSizer->Add(m_pTransportControls, 0, wxALL | wxEXPAND, 2);
// Sizer for the frame
this->SetSizer(m_pMainSizer);
this->Layout();
this->Center(wxBOTH);
// Sizer for TopPanel
m_pTopPanel->SetSizer(m_pTopPanelMainSizer);
m_pTopPanelMainSizer->Fit(m_pTopPanel);
m_pTopPanelMainSizer->SetSizeHints(m_pTopPanel);
m_pTopPanelMainSizer->Layout();
// Restore the data previously added to Library only if demo mode is disabled
if (!m_bDemoMode)
LoadDatabase();
// Set some properites after the frame has been created
CallAfter(&cMainFrame::SetAfterFrameCreate);
}
void cMainFrame::OnMediaFinished(wxMediaEvent& event)
{
if (m_pTransportControls->CanLoop())
{
// FIXME: Temporary fix for the sample not playing from beginning when looping. Might need to change this.
if (m_pMediaCtrl->Stop()) // TODO: <--
if (!m_pMediaCtrl->Play())
{
wxMessageDialog msgDialog(NULL, _("Error! Cannot loop media."), _("Error"), wxOK | wxICON_ERROR);
msgDialog.ShowModal();
}
}
else
{
if (m_pTimer->IsRunning())
{
m_pTimer->Stop();
SH_LOG_DEBUG("Stopping timer.");
}
m_pTransportControls->SetSamplePositionText("--:--.---/--:--.---");
PopStatusText(1);
this->SetStatusText(_("Stopped"), 1);
}
}
void cMainFrame::UpdateElapsedTime(wxTimerEvent& event)
{
wxString duration, position;
duration = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(m_pMediaCtrl->Length());
position = SampleHive::cUtils::Get().CalculateAndGetISOStandardTime(m_pMediaCtrl->Tell());
m_pTransportControls->SetSamplePositionText(wxString::Format(wxT("%s/%s"), position.c_str(), duration.c_str()));
m_pWaveformViewer->Refresh();
if (m_bLoopPointsSet && m_pTransportControls->IsLoopABOn())
if (static_cast<double>(m_pMediaCtrl->Tell()) >= m_LoopB.ToDouble())
m_pMediaCtrl->Seek(m_LoopA.ToDouble(), wxFromStart);
}
void cMainFrame::LoadDatabase()
{
SampleHive::cSerializer serializer;
try
{
const auto dataset = m_pDatabase->LoadSamplesDatabase(*m_pNotebook->GetHivesPanel()->GetHivesObject(),
m_pNotebook->GetHivesPanel()->GetFavoritesHive(),
*m_pNotebook->GetTrashPanel()->GetTrashObject(),
m_pNotebook->GetTrashPanel()->GetTrashRoot(),
serializer.DeserializeShowFileExtension(),
ICON_STAR_FILLED_16px, ICON_STAR_EMPTY_16px);
if (dataset.empty())
SH_LOG_INFO("Error! Database is empty.");
else
{
for (auto data : dataset)
SampleHive::cHiveData::Get().ListCtrlAppendItem(data);
}
m_pDatabase->LoadHivesDatabase(*m_pNotebook->GetHivesPanel()->GetHivesObject());
}
catch (std::exception& e)
{
SH_LOG_ERROR("Error loading data. {}", e.what());
}
}
void cMainFrame::LoadConfigFile()
{
// Check if SampleHive configuration directory exist and create it if not
if (!wxDirExists(APP_CONFIG_DIR))
{
SH_LOG_WARN("Configuration directory not found. Creating directory at {}", static_cast<std::string>(APP_CONFIG_DIR));
if (wxFileName::Mkdir(APP_CONFIG_DIR, wxPOSIX_USER_READ | wxPOSIX_USER_WRITE | wxPOSIX_USER_EXECUTE |
wxPOSIX_GROUP_READ | wxPOSIX_GROUP_EXECUTE |
wxPOSIX_OTHERS_READ | wxPOSIX_OTHERS_EXECUTE, wxPATH_MKDIR_FULL))
{
SH_LOG_INFO("Successfully created configuration directory at {}", static_cast<std::string>(APP_CONFIG_DIR));
}
else
{
wxMessageBox(wxString::Format(_("Error! Could not create configuration directory %s"), APP_CONFIG_DIR),
_("Error!"), wxOK | wxCENTRE, this);
}
}
else
SH_LOG_INFO("Found {} directory.", static_cast<std::string>(APP_CONFIG_DIR));
// Check if SampleHive data directory exist and create it if not
if (!wxDirExists(APP_DATA_DIR))
{
SH_LOG_WARN("Data directory not found. Creating directory at {}", static_cast<std::string>(APP_DATA_DIR));
if (wxFileName::Mkdir(APP_DATA_DIR, wxPOSIX_USER_READ | wxPOSIX_USER_WRITE | wxPOSIX_USER_EXECUTE |
wxPOSIX_GROUP_READ | wxPOSIX_GROUP_EXECUTE |
wxPOSIX_OTHERS_READ | wxPOSIX_OTHERS_EXECUTE, wxPATH_MKDIR_FULL))
{
SH_LOG_INFO("Successfully created data directory at {}", static_cast<std::string>(APP_DATA_DIR));
}
else
{
wxMessageBox(wxString::Format(_("Error! Could not create data directory %s"), APP_DATA_DIR),
_("Error!"), wxOK | wxCENTRE, this);
}
}
else
SH_LOG_INFO("Found {} directory.", static_cast<std::string>(APP_DATA_DIR));
SampleHive::cSerializer serializer;
SH_LOG_INFO("Reading configuration file..");
int height = 600, width = 800;
width = serializer.DeserializeWinSize().first;
height = serializer.DeserializeWinSize().second;
int min_width = 960, min_height = 540;
m_bShowMenuBar = serializer.DeserializeShowMenuAndStatusBar("menubar");
m_bShowStatusBar = serializer.DeserializeShowMenuAndStatusBar("statusbar");
m_bDemoMode = serializer.DeserializeDemoMode();
m_pToggleMenuBar->Check(m_bShowMenuBar);
m_pMenuBar->Show(m_bShowMenuBar);
m_pToggleStatusBar->Check(m_bShowStatusBar);
m_pStatusBar->Show(m_bShowStatusBar);
m_pDemoMode->Check(m_bDemoMode);
m_pToggleExtension->Check(serializer.DeserializeShowFileExtension());
this->SetFont(serializer.DeserializeFontSettings());
this->SetSize(width, height);
this->SetMinSize(wxSize(min_width, min_height));
this->CenterOnScreen(wxBOTH);
this->SetIcon(wxIcon(ICON_HIVE_256px, wxBITMAP_TYPE_PNG));
this->SetTitle(PROJECT_NAME);
this->SetStatusText(wxString::Format("%s %s", PROJECT_NAME, PROJECT_VERSION), 3);
this->SetStatusText(_("Stopped"), 1);
}
// void cMainFrame::RefreshDatabase()
// {
// m_pLibrary->GetListCtrlObject()->DeleteAllItems();
// if (m_pNotebook->GetHivesPanel()->GetHivesObject()->GetChildCount(wxDataViewItem(wxNullPtr)) <= 1 &&
// m_pNotebook->GetHivesPanel()->GetHivesObject()->GetItemText(wxDataViewItem(wxNullPtr)) ==
// m_pNotebook->GetHivesPanel()->GetHivesObject()->GetItemText(m_pNotebook->GetHivesPanel()->GetFavoritesHive()))
// return;
// else
// m_pNotebook->GetHivesPanel()->GetHivesObject()->DeleteAllItems();
// m_pNotebook->GetTrashPanel()->GetTrashObject()->DeleteAllItems();
// LoadDatabase();
// }
bool cMainFrame::CreateWatcherIfNecessary()
{
if (m_pFsWatcher)
return false;
CreateWatcher();
Bind(wxEVT_FSWATCHER, &cMainFrame::OnFileSystemEvent, this);
return true;
}
void cMainFrame::CreateWatcher()
{
SampleHive::cSerializer serializer;
wxCHECK_RET(!m_pFsWatcher, _("Watcher already initialized"));
m_pFsWatcher = new wxFileSystemWatcher();
m_pFsWatcher->SetOwner(this);
wxString path = serializer.DeserializeAutoImport().second;
if (serializer.DeserializeAutoImport().first)
{
SH_LOG_INFO("Adding watch entry: {}", path.ToStdString());
if (serializer.DeserializeRecursiveImport())
AddWatchEntry(wxFSWPath_Tree, path.ToStdString());
else
AddWatchEntry(wxFSWPath_Dir, path.ToStdString());
}
}
void cMainFrame::AddWatchEntry(wxFSWPathType type, std::string path)
{
SampleHive::cSerializer serializer;
if (path.empty())
{
path = wxDirSelector(_("Choose a directory to watch"), "", wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
if (path.empty())
return;
}
wxCHECK_RET(m_pFsWatcher, _("Watcher not initialized"));
SH_LOG_INFO("Adding {}: '{}'", path, type == wxFSWPath_Dir ? "directory" : "directory tree");
wxFileName filename = wxFileName::DirName(path);
if (!filename.IsOk() || !filename.IsDir() || !filename.IsDirReadable())
{
SH_LOG_ERROR("Error! Something wrong with {} path", filename.GetFullPath().ToStdString());
return;
}
if (!serializer.DeserializeFollowSymLink())
{
filename.DontFollowLink();
}
bool ok = false;
switch (type)
{
case wxFSWPath_Dir:
ok = m_pFsWatcher->Add(filename);
break;
case wxFSWPath_Tree:
ok = m_pFsWatcher->AddTree(filename);
break;
case wxFSWPath_File:
break;
case wxFSWPath_None:
wxFAIL_MSG(_("Error! Unexpected path type."));
}
if (!ok)
{
SH_LOG_ERROR("Error! Cannot add '{}' to watched paths", filename.GetPath().ToStdString());
return;
}
}
void cMainFrame::OnFileSystemEvent(wxFileSystemWatcherEvent& event)
{
wxLogTrace(wxTRACE_FSWATCHER, "*** %s ***", event.ToString());
int type = event.GetChangeType();
wxString path = event.GetPath().GetFullPath();
wxArrayString files;
files.push_back(path);
SH_LOG_DEBUG("{} {}", path.ToStdString(), event.ToString().ToStdString());
switch (type)
{
case wxFSW_EVENT_CREATE:
SH_LOG_INFO("NEW FILES DETECTED, ADDING: {}", path.ToStdString());
SampleHive::cUtils::Get().AddSamples(files, this);
break;
case wxFSW_EVENT_ACCESS:
SH_LOG_INFO("ACCESSING DIRECTORY: {}", path.ToStdString());
break;
case wxFSW_EVENT_DELETE:
SH_LOG_INFO("FILES DELETED IN DIRECTORY: {}", path.ToStdString());
break;
case wxFSW_EVENT_MODIFY:
SH_LOG_INFO("DIRECTORY MODIFIED: {}", path.ToStdString());
break;
case wxFSW_EVENT_RENAME:
SH_LOG_INFO("FILES RENAMED IN DIRECTORY: {}", event.GetNewPath().GetFullPath().ToStdString());
break;
case wxFSW_EVENT_WARNING:
SH_LOG_INFO("Filesystem watcher warning: {}", static_cast<int>(event.GetWarningType()));
break;
case wxFSW_EVENT_ERROR:
SH_LOG_INFO("Error! Filesystem watcher: {}", event.GetErrorDescription().ToStdString());
break;
default:
break;
}
}
void cMainFrame::OnSelectAddFile(wxCommandEvent& event)
{
wxFileDialog file_dialog(this, wxFileSelectorPromptStr, USER_HOME_DIR,
wxEmptyString, wxFileSelectorDefaultWildcardStr,
wxFD_DEFAULT_STYLE | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE | wxFD_PREVIEW,
wxDefaultPosition, wxDefaultSize);
switch (file_dialog.ShowModal())
{
case wxID_OK:
{
wxArrayString paths;
file_dialog.GetPaths(paths);
for (size_t i = 0; i < (size_t)paths.size(); i++)
SampleHive::cUtils::Get().AddSamples(paths, this);
}
break;
default:
break;
}
}
void cMainFrame::OnSelectAddDirectory(wxCommandEvent& event)
{
wxDirDialog dir_dialog(this, wxDirSelectorPromptStr, USER_HOME_DIR,
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST, wxDefaultPosition, wxDefaultSize);
switch (dir_dialog.ShowModal())
{
case wxID_OK:
{
wxString path = dir_dialog.GetPath();
SampleHive::cUtils::Get().OnAutoImportDir(path, this);
}
break;
default:
break;
}
}
void cMainFrame::OnSelectToggleDemoMode(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
if (m_pDemoMode->IsChecked())
{
serializer.SerializeDemoMode(true);
m_pLibrary->GetInfoBarObject()->ShowMessage(_("Demo mode toggled on, "
"please restart the app for changes take effect"), wxICON_INFORMATION);
m_bDemoMode = true;
}
else
{
serializer.SerializeDemoMode(false);
m_pLibrary->GetInfoBarObject()->ShowMessage(_("Demo mode toggled off, "
"please restart the app for changes take effect"), wxICON_INFORMATION);
m_bDemoMode = false;
}
}
void cMainFrame::OnSelectToggleExtension(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
if (m_pToggleExtension->IsChecked())
{
serializer.SerializeShowFileExtension(true);
m_pLibrary->GetInfoBarObject()->ShowMessage(_("Extension showing, restart the application to view changes "
"or press CTRL+E to toggle show/hide."), wxICON_INFORMATION);
}
else
{
serializer.SerializeShowFileExtension(false);
m_pLibrary->GetInfoBarObject()->ShowMessage(_("Extension hidden, restart the application to view changes "
"or press CTRL+E to toggle show/hide."), wxICON_INFORMATION);
}
}
void cMainFrame::OnSelectToggleMenuBar(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
if (m_pToggleMenuBar->IsChecked())
{
m_pMenuBar->Show();
m_pLibrary->GetInfoBarObject()->ShowMessage(_("MenuBar showing, press CTRL+M to toggle show/hide."), wxICON_INFORMATION);
m_bShowMenuBar = true;
serializer.SerializeShowMenuAndStatusBar("menubar", m_bShowMenuBar);
}
else
{
m_pMenuBar->Hide();
m_pLibrary->GetInfoBarObject()->ShowMessage(_("MenuBar hidden, press CTRL+M to toggle show/hide."), wxICON_INFORMATION);
m_bShowMenuBar = false;
serializer.SerializeShowMenuAndStatusBar("menubar", m_bShowMenuBar);
}
}
void cMainFrame::OnSelectToggleStatusBar(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
if (m_pToggleStatusBar->IsChecked())
{
m_pStatusBar->Show();
m_pLibrary->GetInfoBarObject()->ShowMessage(_("StatusBar showing, press CTRL+B to toggle show/hide."), wxICON_INFORMATION);
m_bShowStatusBar = true;
serializer.SerializeShowMenuAndStatusBar("statusbar", m_bShowStatusBar);
}
else
{
m_pStatusBar->Hide();
m_pLibrary->GetInfoBarObject()->ShowMessage(_("StatusBar hidden, press CTRL+B to toggle show/hide."), wxICON_INFORMATION);
m_bShowStatusBar = false;
serializer.SerializeShowMenuAndStatusBar("statusbar", m_bShowStatusBar);
}
}
void cMainFrame::OnSelectExit(wxCommandEvent& event)
{
Close();
}
void cMainFrame::OnSelectPreferences(wxCommandEvent& event)
{
cSettings* settings = new cSettings(this);
switch (settings->ShowModal())
{
case wxID_OK:
if (settings->CanAutoImport())
{
SampleHive::cUtils::Get().OnAutoImportDir(settings->GetImportDirPath(), this);
// RefreshDatabase();
}
if (settings->IsWaveformColourChanged())
{
m_pWaveformViewer->ResetBitmapDC();
}
break;
case wxID_CANCEL:
break;
default:
return;
}
}
void cMainFrame::OnSelectResetAppData(wxCommandEvent& event)
{
wxMessageDialog clearDataDialog(this, wxString::Format(_("Warning! This will delete configuration file "
"\"%s\" and database file \"%s\" permanently, "
"are you sure you want to delete these files?"),
static_cast<std::string>(CONFIG_FILEPATH),
static_cast<std::string>(DATABASE_FILEPATH)),
_("Clear app data?"), wxYES_NO | wxNO_DEFAULT | wxCENTRE, wxDefaultPosition);
bool remove = false;
switch (clearDataDialog.ShowModal())
{
case wxID_YES:
remove = true;
if (remove)
{
if (!wxFileExists(static_cast<std::string>(CONFIG_FILEPATH)))
{
SH_LOG_ERROR("Error! File {} doesn't exist.", static_cast<std::string>(CONFIG_FILEPATH));
return;
}
bool config_is_deleted = wxRemoveFile(static_cast<std::string>(CONFIG_FILEPATH));
if (config_is_deleted)
SH_LOG_INFO("Deleted {}", static_cast<std::string>(CONFIG_FILEPATH));
else
SH_LOG_ERROR("Could not delete {}", static_cast<std::string>(CONFIG_FILEPATH));
if (!wxFileExists(static_cast<std::string>(DATABASE_FILEPATH)))
{
SH_LOG_ERROR("Error! File {} doesn't exist.", static_cast<std::string>(DATABASE_FILEPATH));
return;
}
bool db_is_deleted = wxRemoveFile(static_cast<std::string>(DATABASE_FILEPATH));
if (db_is_deleted)
SH_LOG_INFO("Deleted {}", static_cast<std::string>(DATABASE_FILEPATH));
else
SH_LOG_ERROR("Could not delete {}", static_cast<std::string>(DATABASE_FILEPATH));
if (config_is_deleted && db_is_deleted)
{
m_pLibrary->GetInfoBarObject()->ShowMessage(_("Successfully cleared app data"), wxICON_INFORMATION);
SH_LOG_INFO("Cleared app data successfully");
}
else
wxMessageBox(_("Error! Could not clear app data"), _("Error!"), wxOK | wxCENTRE | wxICON_ERROR, this);
}
break;
case wxID_NO:
break;
default:
break;
}
}
void cMainFrame::OnSelectAbout(wxCommandEvent& event)
{
wxAboutDialogInfo aboutInfo;
aboutInfo.SetName(PROJECT_NAME);
aboutInfo.SetIcon(wxIcon(ICON_HIVE_64px, wxBITMAP_TYPE_PNG));
aboutInfo.AddArtist(PROJECT_AUTHOR);
aboutInfo.SetVersion(PROJECT_VERSION, _("Version 0.9.0_alpha.1"));
aboutInfo.SetDescription(_(PROJECT_DESCRIPTION));
aboutInfo.SetCopyright("(C)" PROJECT_COPYRIGHT_YEARS);
aboutInfo.SetWebSite(PROJECT_WEBSITE);
aboutInfo.AddDeveloper(PROJECT_AUTHOR);
aboutInfo.SetLicence(wxString::Format(wxString::FromAscii(
"%s %s\n"
"Copyright (C) %s Apoorv Singh\n"
"\n"
"%s 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"
"%s 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"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program. If not, see <https://www.gnu.org/licenses/>.\n"
), PROJECT_NAME, PROJECT_VERSION, PROJECT_COPYRIGHT_YEARS, PROJECT_NAME, PROJECT_NAME));
wxAboutBox(aboutInfo);
}
void cMainFrame::OnResizeStatusBar(wxSizeEvent& event)
{
wxRect rect;
m_pStatusBar->GetFieldRect(2, rect);
wxSize bitmap_size = m_pHiveBitmap->GetSize();
m_pHiveBitmap->Move(rect.x + (rect.width - bitmap_size.x),
rect.y + (rect.height - bitmap_size.y));
event.Skip();
}
void cMainFrame::OnResizeFrame(wxSizeEvent& event)
{
SampleHive::cSerializer serializer;
SH_LOG_DEBUG("Frame resized to {}, {}", GetSize().GetWidth(), GetSize().GetHeight());
serializer.SerializeWinSize(GetSize().GetWidth(), GetSize().GetHeight());
event.Skip();
}
void cMainFrame::OnTopSplitterSashPosChanged(wxSplitterEvent& event)
{
SampleHive::cSerializer serializer;
SH_LOG_DEBUG("TopSplitter at {}", m_pTopSplitter->GetSashPosition());
serializer.SerializeSplitterSashPos("top", m_pTopSplitter->GetSashPosition());
}
void cMainFrame::OnBottomSplitterSashPosChanged(wxSplitterEvent& event)
{
SampleHive::cSerializer serializer;
SH_LOG_DEBUG("BottomSplitter at {}", m_pBottomSplitter->GetSashPosition());
serializer.SerializeSplitterSashPos("bottom", m_pBottomSplitter->GetSashPosition());
}
void cMainFrame::SetAfterFrameCreate()
{
SampleHive::cSerializer serializer;
m_pTopSplitter->SetSashPosition(serializer.DeserializeSplitterSashPos("top"));
m_pBottomSplitter->SetSashPosition(serializer.DeserializeSplitterSashPos("bottom"));
}
void cMainFrame::OnRecieveLoopPoints(SampleHive::cLoopPointsEvent& event)
{
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());
SH_LOG_INFO("Loop points set: A: {:2}:{:02}, B: {:2}:{:02}", loopA_min, loopA_sec, loopB_min, loopB_sec);
m_pTransportControls->SetLoopABValue(true);
m_bLoopPointsSet = true;
}
void cMainFrame::OnRecievePushStatusBarStatus(SampleHive::cStatusBarStatusEvent& event)
{
std::pair<wxString, int> status = event.GetPushMessageAndSection();
m_pStatusBar->PushStatusText(status.first, status.second);
}
void cMainFrame::OnRecievePopStatusBarStatus(SampleHive::cStatusBarStatusEvent& event)
{
m_pStatusBar->PopStatusText(event.GetPopMessageSection());
}
void cMainFrame::OnRecieveSetStatusBarStatus(SampleHive::cStatusBarStatusEvent& event)
{
std::pair<wxString, int> status = event.GetStatusTextAndSection();
m_pStatusBar->SetStatusText(status.first, status.second);
}
void cMainFrame::OnRecieveInfoBarStatus(SampleHive::cInfoBarMessageEvent& event)
{
std::pair<wxString, int> info = event.GetInfoBarMessage();
m_pLibrary->GetInfoBarObject()->ShowMessage(info.first, info.second);
}
void cMainFrame::OnRecieveTimerStopStatus(SampleHive::cTimerEvent& event)
{
if (m_pTimer->IsRunning())
m_pTimer->Stop();
}
void cMainFrame::OnRecieveCallFunctionPlay(SampleHive::cCallFunctionEvent& event)
{
SampleHive::cSerializer serializer;
wxString selection = event.GetSlection();
bool checkAutoplay = event.GetAutoplayValue();
wxString sample_path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Path;
if (checkAutoplay)
{
if (m_pTransportControls->CanAutoplay())
{
if (m_bLoopPointsSet && m_pTransportControls->IsLoopABOn())
PlaySample(sample_path.ToStdString(), selection.ToStdString(), true, m_LoopA.ToDouble(), wxFromStart);
else
PlaySample(sample_path.ToStdString(), selection.ToStdString());
}
else
m_pMediaCtrl->Stop();
}
else
{
if (m_bLoopPointsSet && m_pTransportControls->IsLoopABOn())
PlaySample(sample_path.ToStdString(), selection.ToStdString(), true, m_LoopA.ToDouble(), wxFromStart);
else
PlaySample(sample_path.ToStdString(), selection.ToStdString());
}
}
void cMainFrame::OnRecieveWaveformUpdateStatus(SampleHive::cWaveformUpdateEvent& event)
{
m_pWaveformViewer->ResetBitmapDC();
}
void cMainFrame::OnRecieveClearLoopPointsStatus(SampleHive::cLoopPointsEvent& event)
{
ClearLoopPoints();
}
void cMainFrame::OnRecieveLoopABButtonValueChange(SampleHive::cLoopPointsEvent& event)
{
m_pTransportControls->SetLoopABValue(false);
}
void cMainFrame::ClearLoopPoints()
{
m_LoopA = 0;
m_LoopB = 0;
m_bLoopPointsSet = false;
}
void cMainFrame::PlaySample(const std::string& filepath, const std::string& sample, bool seek, wxFileOffset where, wxSeekMode mode)
{
if (m_pMediaCtrl->Load(filepath))
{
if (seek)
m_pMediaCtrl->Seek(where, mode);
if (!m_pMediaCtrl->Play())
SH_LOG_ERROR("Error! Cannot play sample.");
// ====================================================
// TODO: Remove these lines (for debugging only)
float bpm = SampleHive::cUtils::Get().GetBPM(filepath);
wxString bpm_str = SampleHive::cUtils::Get().GetBPMString(bpm);
SH_LOG_DEBUG("BPM: {}, BPM_STR: {}", bpm, bpm_str.ToStdString());
// ====================================================
PushStatusText(wxString::Format(_("Now playing: %s"), sample), 1);
if (!m_pTimer->IsRunning())
{
SH_LOG_DEBUG("Starting timer.");
m_pTimer->Start(20, wxTIMER_CONTINUOUS);
}
}
else
SH_LOG_ERROR("Error! Cannot load sample.");
}
void cMainFrame::InitDatabase()
{
// Initialize the database
try
{
m_pDatabase = std::make_unique<cDatabase>();
m_pDatabase->CreateTableSamples();
if (!m_bDemoMode)
m_pDatabase->CreateTableHives();
}
catch (std::exception& e)
{
SH_LOG_ERROR("Error! Cannot initialize database {}", e.what());
}
}
cMainFrame::~cMainFrame()
{
// Delete wxTimer
delete m_pTimer;
// Delete wxFilesystemWatcher
delete m_pFsWatcher;
SampleHive::cSerializer serializer;
if (serializer.DeserializeDemoMode())
{
if (wxFileExists("tempdb.db"))
if (wxRemoveFile("tempdb.db"))
SH_LOG_WARN("Deleted temporary database file..");
else
SH_LOG_ERROR("Could not delete file..");
else
SH_LOG_DEBUG("File doesn't exists");
}
}

204
src/GUI/MainFrame.hpp Normal file
View File

@ -0,0 +1,204 @@
/* 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 "GUI/Library.hpp"
#include "GUI/Notebook.hpp"
#include "GUI/TransportControls.hpp"
#include "GUI/WaveformViewer.hpp"
#include "Database/Database.hpp"
#include "Utility/Serialize.hpp"
#include "Utility/Event.hpp"
#include "SampleHiveConfig.hpp"
#include <memory>
#include <string>
#include <wx/event.h>
#include <wx/frame.h>
#include <wx/fswatcher.h>
#include <wx/mediactrl.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/splitter.h>
#include <wx/statbmp.h>
#include <wx/statusbr.h>
#include <wx/string.h>
#include <wx/timer.h>
class cMainFrame : public wxFrame
{
public:
cMainFrame();
~cMainFrame();
private:
// -------------------------------------------------------------------
// Top panel control handlers
void OnMediaFinished(wxMediaEvent& event);
// -------------------------------------------------------------------
// App menu items event handlers
void OnSelectAddFile(wxCommandEvent& event);
void OnSelectAddDirectory(wxCommandEvent& event);
void OnSelectToggleDemoMode(wxCommandEvent& event);
void OnSelectToggleExtension(wxCommandEvent& event);
void OnSelectToggleMenuBar(wxCommandEvent& event);
void OnSelectToggleStatusBar(wxCommandEvent& event);
void OnSelectExit(wxCommandEvent& event);
void OnSelectPreferences(wxCommandEvent& event);
void OnSelectResetAppData(wxCommandEvent& event);
void OnSelectAbout(wxCommandEvent& event);
// -------------------------------------------------------------------
// Statusbar event handler
void OnResizeStatusBar(wxSizeEvent& event);
// -------------------------------------------------------------------
// Frame resize event handler
void OnResizeFrame(wxSizeEvent& event);
// Splitter window sash pos event handler
void OnTopSplitterSashPosChanged(wxSplitterEvent& event);
void OnBottomSplitterSashPosChanged(wxSplitterEvent& event);
// -------------------------------------------------------------------
// Timer update event handler
void UpdateElapsedTime(wxTimerEvent& event);
// -------------------------------------------------------------------
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::cLoopPointsEvent& event);
void OnRecieveClearLoopPointsStatus(SampleHive::cLoopPointsEvent& event);
void OnRecieveLoopABButtonValueChange(SampleHive::cLoopPointsEvent& event);
void OnRecievePushStatusBarStatus(SampleHive::cStatusBarStatusEvent& event);
void OnRecievePopStatusBarStatus(SampleHive::cStatusBarStatusEvent& event);
void OnRecieveSetStatusBarStatus(SampleHive::cStatusBarStatusEvent& event);
void OnRecieveInfoBarStatus(SampleHive::cInfoBarMessageEvent& event);
void OnRecieveTimerStopStatus(SampleHive::cTimerEvent& event);
void OnRecieveCallFunctionPlay(SampleHive::cCallFunctionEvent& event);
void OnRecieveWaveformUpdateStatus(SampleHive::cWaveformUpdateEvent& event);
// -------------------------------------------------------------------
void LoadDatabase();
void LoadConfigFile();
// void RefreshDatabase();
// -------------------------------------------------------------------
// Directory watchers
bool CreateWatcherIfNecessary();
void CreateWatcher();
void AddWatchEntry(wxFSWPathType type, std::string path);
void OnFileSystemEvent(wxFileSystemWatcherEvent& event);
// -------------------------------------------------------------------
// Call after frame creation
void SetAfterFrameCreate();
// -------------------------------------------------------------------
void ClearLoopPoints();
// -------------------------------------------------------------------
void InitDatabase();
// -------------------------------------------------------------------
friend class cApp;
private:
// -------------------------------------------------------------------
// Main Panel
wxBoxSizer* m_pMainSizer = nullptr;
// -------------------------------------------------------------------
// Hive bitmap icon for the statusbar
wxStaticBitmap* m_pHiveBitmap = nullptr;
// -------------------------------------------------------------------
// App statusbar
wxStatusBar* m_pStatusBar = nullptr;
// -------------------------------------------------------------------
// App menubar
wxMenuBar* m_pMenuBar = nullptr;
// -------------------------------------------------------------------
// Menu and menu items for the menubar
wxMenu* m_pFileMenu = nullptr;
wxMenu* m_pEditMenu = nullptr;
wxMenu* m_pViewMenu = nullptr;
wxMenu* m_pHelpMenu = nullptr;
wxMenuItem* m_pAddFile = nullptr;
wxMenuItem* m_pAddDirectory = nullptr;
wxMenuItem* m_pToggleExtension = nullptr;
wxMenuItem* m_pToggleMenuBar = nullptr;
wxMenuItem* m_pToggleStatusBar = nullptr;
wxMenuItem* m_pDemoMode = nullptr;
// -------------------------------------------------------------------
// Splitter windows
wxSplitterWindow* m_pTopSplitter = nullptr;
wxSplitterWindow* m_pBottomSplitter = nullptr;
// -------------------------------------------------------------------
// Top panel controls
wxPanel* m_pTopPanel = nullptr;
cWaveformViewer* m_pWaveformViewer = nullptr;
cTransportControls* m_pTransportControls = nullptr;
wxBoxSizer* m_pTopPanelMainSizer = nullptr;
// -------------------------------------------------------------------
// Left panel controls
cNotebook* m_pNotebook = nullptr;
// -------------------------------------------------------------------
// Right panel controls
cLibrary* m_pLibrary = nullptr;
// -------------------------------------------------------------------
// MediaCtrl
wxMediaCtrl* m_pMediaCtrl = nullptr;
// -------------------------------------------------------------------
// Timer
wxTimer* m_pTimer = nullptr;
// -------------------------------------------------------------------
std::unique_ptr<cDatabase> m_pDatabase = nullptr;
// -------------------------------------------------------------------
// FileSystemWatcher
wxFileSystemWatcher* m_pFsWatcher = nullptr;
// -------------------------------------------------------------------
wxLongLong m_LoopA, m_LoopB;
private:
// -------------------------------------------------------------------
bool m_bFiltered = false;
bool m_bShowMenuBar = false;
bool m_bShowStatusBar = false;
bool m_bLoopPointsSet = false;
bool m_bDemoMode = false;
};

53
src/GUI/Notebook.cpp Normal file
View File

@ -0,0 +1,53 @@
/* 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 "GUI/Notebook.hpp"
#include "GUI/DirectoryBrowser.hpp"
#include "GUI/Hives.hpp"
#include "GUI/Trash.hpp"
cNotebook::cNotebook(wxWindow* window)
: wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
{
m_pNotebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
m_DirectoryBrowser = new cDirectoryBrowser(m_pNotebook);
m_HivesPanel = new cHivesPanel(m_pNotebook);
m_TrashPanel = new cTrashPanel(m_pNotebook);
// Adding the pages to wxNotebook
m_pNotebook->AddPage(m_DirectoryBrowser, _("Browse"), false);
m_pNotebook->AddPage(m_HivesPanel, _("Hives"), false);
m_pNotebook->AddPage(m_TrashPanel, _("Trash"), false);
m_pSizer = new wxBoxSizer(wxVERTICAL);
m_pSizer->Add(m_pNotebook, wxSizerFlags(1).Expand());
this->SetSizer(m_pSizer);
m_pSizer->Fit(this);
m_pSizer->SetSizeHints(this);
m_pSizer->Layout();
}
cNotebook::~cNotebook()
{
}

53
src/GUI/Notebook.hpp Normal file
View File

@ -0,0 +1,53 @@
/* 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 "GUI/DirectoryBrowser.hpp"
#include "GUI/Hives.hpp"
#include "GUI/Trash.hpp"
#include <wx/dataview.h>
#include <wx/panel.h>
#include <wx/notebook.h>
#include <wx/sizer.h>
class cNotebook : public wxPanel
{
public:
// -------------------------------------------------------------------
cNotebook(wxWindow* window);
~cNotebook();
// -------------------------------------------------------------------
cDirectoryBrowser* GetDirectoryBrowser() const { return m_DirectoryBrowser; }
cHivesPanel* GetHivesPanel() const { return m_HivesPanel; }
cTrashPanel* GetTrashPanel() const { return m_TrashPanel; }
private:
// -------------------------------------------------------------------
wxNotebook* m_pNotebook = nullptr;
wxBoxSizer* m_pSizer = nullptr;
// -------------------------------------------------------------------
cDirectoryBrowser* m_DirectoryBrowser = nullptr;
cHivesPanel* m_HivesPanel = nullptr;
cTrashPanel* m_TrashPanel = nullptr;
};

6
src/GUI/Resources.rc Normal file
View File

@ -0,0 +1,6 @@
#define wxUSE_RC_MANIFEST 1
#define wxUSE_DPI_AWARE_MANIFEST 2
#include <wx/msw/wx.rc>
ApplicationIcon ICON "../../assets/icons/icon-hive_32x32.ico"

92
src/GUI/SearchBar.cpp Normal file
View File

@ -0,0 +1,92 @@
/* 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 "GUI/SearchBar.hpp"
#include "GUI/ListCtrl.hpp"
#include "Database/Database.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Serialize.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Log.hpp"
#include <exception>
cSearchBar::cSearchBar(wxWindow* window)
: wxSearchCtrl(window, SampleHive::ID::BC_Search, _("Search for samples.."),
wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER),
m_pWindow(window)
{
// Set minimum and maximum size of m_SearchBox
// so it doesn't expand too wide when resizing the main frame.
SetMinSize(wxSize(-1, 38));
SetMaxSize(wxSize(-1, 38));
ShowSearchButton(true);
ShowCancelButton(true);
Bind(wxEVT_TEXT, &cSearchBar::OnDoSearch, this, SampleHive::ID::BC_Search);
Bind(wxEVT_SEARCHCTRL_SEARCH_BTN, &cSearchBar::OnDoSearch, this, SampleHive::ID::BC_Search);
Bind(wxEVT_SEARCHCTRL_CANCEL_BTN, &cSearchBar::OnCancelSearch, this, SampleHive::ID::BC_Search);
}
void cSearchBar::OnDoSearch(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
cDatabase db;
const auto search = this->GetValue().ToStdString();
try
{
const auto dataset = db.FilterDatabaseBySampleName(search, serializer.DeserializeShowFileExtension(),
ICON_STAR_FILLED_16px, ICON_STAR_EMPTY_16px);
if (dataset.empty())
{
SH_LOG_INFO("Error! Database is empty.");
}
else
{
SampleHive::cHiveData::Get().ListCtrlDeleteAllItems();
std::cout << search << std::endl;
for (const auto& data : dataset)
{
SampleHive::cHiveData::Get().ListCtrlAppendItem(data);
}
}
}
catch (std::exception& e)
{
SH_LOG_ERROR("Error loading data. {}", e.what());
}
}
void cSearchBar::OnCancelSearch(wxCommandEvent& event)
{
this->Clear();
}
cSearchBar::~cSearchBar()
{
}

44
src/GUI/SearchBar.hpp Normal file
View File

@ -0,0 +1,44 @@
/* 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/srchctrl.h>
class cSearchBar : public wxSearchCtrl
{
public:
cSearchBar(wxWindow* window);
~cSearchBar();
public:
wxSearchCtrl* GetSearchCtrlObject() { return this; }
private:
// -------------------------------------------------------------------
// SearchCtrl event handlers
void OnDoSearch(wxCommandEvent& event);
void OnCancelSearch(wxCommandEvent& event);
private:
// -------------------------------------------------------------------
wxWindow* m_pWindow = nullptr;
};

View File

@ -0,0 +1,298 @@
/* 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 "GUI/TransportControls.hpp"
#include "GUI/Dialogs/Settings.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/Event.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Sample.hpp"
#include "Utility/Signal.hpp"
#include "Utility/Serialize.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Utils.hpp"
#include <wx/gdicmn.h>
cTransportControls::cTransportControls(wxWindow* window, wxMediaCtrl& mediaCtrl)
: wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER),
m_MediaCtrl(mediaCtrl)
{
m_pMainSizer = new wxBoxSizer(wxHORIZONTAL);
// Looping region controls
if (m_Theme.IsDark())
m_pLoopABButton = new wxBitmapToggleButton(this, SampleHive::ID::BC_LoopABButton,
wxBitmap(ICON_AB_LIGHT_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
else
m_pLoopABButton = new wxBitmapToggleButton(this, SampleHive::ID::BC_LoopABButton,
wxBitmap(ICON_AB_DARK_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
m_pLoopABButton->SetToolTip(_("Loop selected region"));
// Autoplay checkbox
m_pAutoPlayCheck = new wxCheckBox(this, SampleHive::ID::BC_Autoplay, _("Autoplay"),
wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
m_pAutoPlayCheck->SetToolTip(_("Autoplay"));
// Volume slider
m_pVolumeSlider = new wxSlider(this, SampleHive::ID::BC_Volume, 100, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL);
m_pVolumeSlider->SetToolTip(_("Volume"));
m_pVolumeSlider->SetMinSize(wxSize(120, -1));
m_pVolumeSlider->SetMaxSize(wxSize(120, -1));
// Sample position static text
m_pSamplePosition = new wxStaticText(this, SampleHive::ID::BC_SamplePosition, "--:--.---/--:--.---",
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
// Transport control buttons
if (m_Theme.IsDark())
{
m_pPlayButton = new wxBitmapButton(this, SampleHive::ID::BC_Play,
wxBitmap(ICON_PLAY_LIGHT_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
m_pLoopButton = new wxBitmapToggleButton(this, SampleHive::ID::BC_Loop,
wxBitmap(ICON_LOOP_LIGHT_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
m_pStopButton = new wxBitmapButton(this, SampleHive::ID::BC_Stop,
wxBitmap(ICON_STOP_LIGHT_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
m_pMuteButton = new wxBitmapToggleButton(this, SampleHive::ID::BC_Mute,
wxBitmap(ICON_MUTE_LIGHT_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
}
else
{
m_pPlayButton = new wxBitmapButton(this, SampleHive::ID::BC_Play,
wxBitmap(ICON_PLAY_DARK_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
m_pLoopButton = new wxBitmapToggleButton(this, SampleHive::ID::BC_Loop,
wxBitmap(ICON_LOOP_DARK_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
m_pStopButton = new wxBitmapButton(this, SampleHive::ID::BC_Stop,
wxBitmap(ICON_STOP_DARK_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
m_pMuteButton = new wxBitmapToggleButton(this, SampleHive::ID::BC_Mute,
wxBitmap(ICON_MUTE_DARK_16px, wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, 0);
}
m_pPlayButton->SetToolTip(_("Play"));
m_pLoopButton->SetToolTip(_("Loop"));
m_pStopButton->SetToolTip(_("Stop"));
m_pMuteButton->SetToolTip(_("Mute"));
m_pSettingsButton = new wxButton(this, SampleHive::ID::BC_Settings, _("Settings"), wxDefaultPosition, wxDefaultSize, 0);
m_pSettingsButton->SetToolTip(_("Settings"));
m_pMainSizer->Add(m_pPlayButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pMainSizer->Add(m_pStopButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pMainSizer->Add(m_pLoopButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pMainSizer->Add(m_pLoopABButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pMainSizer->Add(m_pSettingsButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pMainSizer->Add(0,0,1, wxALL | wxEXPAND, 0);
m_pMainSizer->Add(m_pSamplePosition, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pMainSizer->Add(60,0,0, wxALL | wxEXPAND, 0);
m_pMainSizer->Add(m_pMuteButton, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pMainSizer->Add(m_pVolumeSlider, 1, wxALL | wxALIGN_CENTER_VERTICAL, 2);
m_pMainSizer->Add(m_pAutoPlayCheck, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
this->SetSizer(m_pMainSizer);
m_pMainSizer->Fit(this);
m_pMainSizer->SetSizeHints(this);
m_pMainSizer->Layout();
Bind(wxEVT_BUTTON, &cTransportControls::OnClickPlay, this, SampleHive::ID::BC_Play);
Bind(wxEVT_TOGGLEBUTTON, &cTransportControls::OnClickLoop, this, SampleHive::ID::BC_Loop);
Bind(wxEVT_BUTTON, &cTransportControls::OnClickStop, this, SampleHive::ID::BC_Stop);
Bind(wxEVT_TOGGLEBUTTON, &cTransportControls::OnClickMute, this, SampleHive::ID::BC_Mute);
Bind(wxEVT_BUTTON, &cTransportControls::OnClickSettings, this, SampleHive::ID::BC_Settings);
Bind(wxEVT_CHECKBOX, &cTransportControls::OnCheckAutoplay, this, SampleHive::ID::BC_Autoplay);
Bind(wxEVT_SCROLL_THUMBTRACK, &cTransportControls::OnSlideVolume, this, SampleHive::ID::BC_Volume);
Bind(wxEVT_SCROLL_THUMBRELEASE, &cTransportControls::OnReleaseVolumeSlider, this, SampleHive::ID::BC_Volume);
// Load control values from config file
LoadConfigFile();
}
void cTransportControls::OnClickSettings(wxCommandEvent& event)
{
cSettings* settings = new cSettings(this);
switch (settings->ShowModal())
{
case wxID_OK:
if (settings->CanAutoImport())
{
SampleHive::cUtils::Get().OnAutoImportDir(settings->GetImportDirPath(), this);
// RefreshDatabase();
}
if (settings->IsWaveformColourChanged())
{
SampleHive::cSignal::SendWaveformUpdateStatus(*this);
}
break;
case wxID_CANCEL:
break;
default:
return;
}
}
void cTransportControls::OnClickPlay(wxCommandEvent& event)
{
m_bStopped = false;
int selected_row = SampleHive::cHiveData::Get().GetListCtrlSelectedRow();
if (selected_row < 0)
return;
wxString selection = SampleHive::cHiveData::Get().GetListCtrlTextValue(selected_row, 1);
// Send custom event to MainFrame to play the sample
SampleHive::cSignal::SendCallFunctionPlay(selection, false, *this);
}
void cTransportControls::OnClickLoop(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
m_bLoop = m_pLoopButton->GetValue();
serializer.SerializeMediaOptions("loop", m_bLoop);
}
void cTransportControls::OnClickStop(wxCommandEvent& event)
{
if (!m_MediaCtrl.Stop())
SH_LOG_ERROR("Error! Unable to stop media.");
m_bStopped = true;
// Send custom event to MainFrame to stop the timer
SampleHive::cSignal::SendTimerStopStatus(*this);
m_pSamplePosition->SetLabel("--:--.---/--:--.---");
// Send custom event to MainFrame to set the statusbar status
SampleHive::cSignal::SendSetStatusBarStatus(_("Stopped"), 1, *this);
}
void cTransportControls::OnClickMute(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
if (m_pMuteButton->GetValue())
{
m_MediaCtrl.SetVolume(0.0);
m_bMuted = true;
serializer.SerializeMediaOptions("muted", m_bMuted);
}
else
{
m_MediaCtrl.SetVolume(double(m_pVolumeSlider->GetValue()) / 100);
m_bMuted = false;
serializer.SerializeMediaOptions("muted", m_bMuted);
}
}
void cTransportControls::OnCheckAutoplay(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
if (m_pAutoPlayCheck->GetValue())
{
m_bAutoplay = true;
serializer.SerializeMediaOptions("autoplay", m_bAutoplay);
}
else
{
m_bAutoplay = false;
serializer.SerializeMediaOptions("autoplay", m_bAutoplay);
}
}
void cTransportControls::OnSlideVolume(wxScrollEvent& event)
{
m_MediaCtrl.SetVolume(double(m_pVolumeSlider->GetValue()) / 100);
// Send custom event to MainFrame to push status to statusbar
SampleHive::cSignal::SendPushStatusBarStatus(wxString::Format(_("Volume: %d"), m_pVolumeSlider->GetValue()), 1, *this);
}
void cTransportControls::OnReleaseVolumeSlider(wxScrollEvent& event)
{
SampleHive::cSerializer serializer;
serializer.SerializeMediaVolume(m_pVolumeSlider->GetValue());
int selected_row = SampleHive::cHiveData::Get().GetListCtrlSelectedRow();
if (selected_row < 0)
return;
wxString selection = SampleHive::cHiveData::Get().GetListCtrlTextValue(selected_row, 1);
// Wait a second then remove the status from statusbar
wxSleep(1);
// Send custom event to MainFrame to pop status from statusbar
SampleHive::cSignal::SendPopStatusBarStatus(1, *this);
if (m_MediaCtrl.GetState() == wxMEDIASTATE_STOPPED)
SampleHive::cSignal::SendSetStatusBarStatus(_("Stopped"), 1, *this);
else
SampleHive::cSignal::SendPushStatusBarStatus(wxString::Format(_("Now playing: %s"), selection), 1, *this);
}
void cTransportControls::LoadConfigFile()
{
SampleHive::cSerializer serializer;
SH_LOG_INFO("Reading transport control values..");
m_bAutoplay = serializer.DeserializeMediaOptions("autoplay");
m_bLoop = serializer.DeserializeMediaOptions("loop");
m_bMuted = serializer.DeserializeMediaOptions("muted");
m_pAutoPlayCheck->SetValue(m_bAutoplay);
m_pLoopButton->SetValue(m_bLoop);
m_pMuteButton->SetValue(m_bMuted);
m_pVolumeSlider->SetValue(serializer.DeserializeMediaVolume());
if (!m_bMuted)
m_MediaCtrl.SetVolume(double(m_pVolumeSlider->GetValue()) / 100);
else
m_MediaCtrl.SetVolume(0.0);
}
cTransportControls::~cTransportControls()
{
}

View File

@ -0,0 +1,117 @@
/* 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/bmpbuttn.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/event.h>
#include <wx/mediactrl.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include <wx/tglbtn.h>
#include <wx/panel.h>
#include <wx/version.h>
#include <wx/window.h>
class cTransportControls : public wxPanel
{
public:
// -------------------------------------------------------------------
cTransportControls(wxWindow* window, wxMediaCtrl& mediaCtrl);
~cTransportControls();
public:
// -------------------------------------------------------------------
bool IsLoopABOn() const { return m_pLoopABButton->GetValue(); }
// -------------------------------------------------------------------
inline bool CanAutoplay() const { return m_bAutoplay; };
inline bool CanLoop() const { return m_bLoop; };
inline bool IsMuted() const { return m_bMuted; };
inline bool IsStopped() const { return m_bStopped; };
// -------------------------------------------------------------------
void SetLoopABValue(bool value) { m_pLoopABButton->SetValue(value); }
// -------------------------------------------------------------------
void SetCanAutoplay(bool autoplay) { m_bAutoplay = autoplay; }
void SetCanLoop(bool loop) { m_bLoop = loop; }
void SetIsMuted(bool muted) { m_bMuted = muted; }
void SetIsStopped(bool stopped) { m_bStopped = stopped; }
// -------------------------------------------------------------------
inline wxString GetSamplePositionText() const { return m_pSamplePosition->GetLabelText(); }
// -------------------------------------------------------------------
void SetSamplePositionText(const wxString& text) { m_pSamplePosition->SetLabel(text); }
private:
// -------------------------------------------------------------------
// Event handlers
void OnClickPlay(wxCommandEvent& event);
void OnClickLoop(wxCommandEvent& event);
void OnClickStop(wxCommandEvent& event);
void OnClickMute(wxCommandEvent& event);
void OnClickSettings(wxCommandEvent& event);
void OnCheckAutoplay(wxCommandEvent& event);
void OnSlideVolume(wxScrollEvent& event);
void OnReleaseVolumeSlider(wxScrollEvent& event);
private:
// -------------------------------------------------------------------
// Load control values from config file
void LoadConfigFile();
void OnAutoImportDir(const wxString& pathToDirectory);
private:
// -------------------------------------------------------------------
wxMediaCtrl& m_MediaCtrl;
private:
// -------------------------------------------------------------------
bool m_bAutoplay = false;
bool m_bLoop = false;
bool m_bMuted = false;
bool m_bStopped = false;
private:
// -------------------------------------------------------------------
wxBitmapButton* m_pPlayButton = nullptr;
wxBitmapToggleButton* m_pLoopButton = nullptr;
wxBitmapButton* m_pStopButton = nullptr;
wxButton* m_pSettingsButton = nullptr;
wxBitmapToggleButton* m_pMuteButton = nullptr;
wxBitmapToggleButton* m_pLoopABButton = nullptr;
wxStaticText* m_pSamplePosition = nullptr;
wxSlider* m_pVolumeSlider = nullptr;
wxCheckBox* m_pAutoPlayCheck = nullptr;
// -------------------------------------------------------------------
wxBoxSizer* m_pMainSizer = nullptr;
private:
// -------------------------------------------------------------------
wxSystemAppearance m_Theme = wxSystemSettings::GetAppearance();
};

307
src/GUI/Trash.cpp Normal file
View File

@ -0,0 +1,307 @@
/* 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 "GUI/Trash.hpp"
#include "Database/Database.hpp"
#include "Utility/ControlIDs.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Signal.hpp"
#include "Utility/Serialize.hpp"
#include "Utility/Utils.hpp"
#include <exception>
#include <wx/gdicmn.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
cTrashPanel::cTrashPanel(wxWindow* window)
: wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL),
m_pWindow(window)
{
m_pMainSizer = new wxBoxSizer(wxVERTICAL);
m_pTrashSizer = new wxBoxSizer(wxVERTICAL);
m_pButtonSizer = new wxBoxSizer(wxHORIZONTAL);
m_pTrash = new wxTreeCtrl(this, SampleHive::ID::BC_Trash, wxDefaultPosition, wxDefaultSize,
wxTR_NO_BUTTONS | wxTR_HIDE_ROOT | wxTR_MULTIPLE);
// Setting m_Trash to accept files to be dragged and dropped on it
m_pTrash->DragAcceptFiles(true);
m_pTrashSizer->Add(m_pTrash, wxSizerFlags(1).Expand());
m_pRestoreTrashedItemButton = new wxButton(this, SampleHive::ID::BC_RestoreTrashedItem, _("Restore sample"),
wxDefaultPosition, wxDefaultSize, 0);
m_pRestoreTrashedItemButton->SetToolTip(_("Restore selected sample"));
m_pButtonSizer->Add(m_pRestoreTrashedItemButton, wxSizerFlags(1).Expand());
// Addubg root to TrashedItems
m_TrashRoot = m_pTrash->AddRoot("Trash");
m_pTrash->Connect(wxEVT_DROP_FILES, wxDropFilesEventHandler(cTrashPanel::OnDragAndDropToTrash), NULL, this);
Bind(wxEVT_TREE_ITEM_RIGHT_CLICK, &cTrashPanel::OnShowTrashContextMenu, this, SampleHive::ID::BC_Trash);
Bind(wxEVT_BUTTON, &cTrashPanel::OnClickRestoreTrashItem, this, SampleHive::ID::BC_RestoreTrashedItem);
m_pMainSizer->Add(m_pTrashSizer, wxSizerFlags(1).Expand());
m_pMainSizer->Add(m_pButtonSizer, wxSizerFlags(0).Expand());
// Sizer for trash pane
this->SetSizer(m_pMainSizer);
m_pMainSizer->Fit(this);
m_pMainSizer->SetSizeHints(this);
m_pMainSizer->Layout();
}
void cTrashPanel::OnDragAndDropToTrash(wxDropFilesEvent& event)
{
SampleHive::cSerializer serializer;
cDatabase db;
if (event.GetNumberOfFiles() > 0)
{
wxFileDataObject file_data;
wxArrayString files;
wxDataViewItemArray items;
int rows = SampleHive::cHiveData::Get().GetListCtrlSelections(items);
wxString msg;
wxDataViewItem root = wxDataViewItem(wxNullPtr);
wxDataViewItem container, child;
for (int i = 0; i < rows; i++)
{
int item_row = SampleHive::cHiveData::Get().GetListCtrlRowFromItem(items, i);
wxString text_value = SampleHive::cHiveData::Get().GetListCtrlTextValue(item_row, 1);
std::string multi_selection = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetListCtrlTextValue(item_row, 1).BeforeLast('.').ToStdString() :
SampleHive::cHiveData::Get().GetListCtrlTextValue(item_row, 1).ToStdString() ;
file_data.AddFile(multi_selection);
files = file_data.GetFilenames();
if (db.GetFavoriteColumnValueByFilename(files[i].ToStdString()))
{
SampleHive::cHiveData::Get().ListCtrlSetVariant(wxVariant(wxBitmap(ICON_STAR_EMPTY_16px, wxBITMAP_TYPE_PNG)), item_row, 0);
db.UpdateFavoriteColumn(files[i].ToStdString(), 0);
for (int j = 0; j < SampleHive::cHiveData::Get().GetHiveChildCount(root); j++)
{
container = SampleHive::cHiveData::Get().GetHiveNthChild(root, j);
for (int k = 0; k < SampleHive::cHiveData::Get().GetHiveChildCount(container); k++)
{
child = SampleHive::cHiveData::Get().GetHiveNthChild(container, k);
wxString child_text = serializer.DeserializeShowFileExtension() ?
SampleHive::cHiveData::Get().GetHiveItemText(child).BeforeLast('.') :
SampleHive::cHiveData::Get().GetHiveItemText(child);
if (child_text == files[i])
{
SampleHive::cHiveData::Get().HiveDeleteItem(child);
break;
}
}
}
}
db.UpdateTrashColumn(files[i].ToStdString(), 1);
db.UpdateHiveName(files[i].ToStdString(),
SampleHive::cHiveData::Get().GetHiveItemText(SampleHive::cHiveData::Get().GetFavoritesHive()).ToStdString());
m_pTrash->AppendItem(m_TrashRoot, text_value);
SampleHive::cHiveData::Get().ListCtrlDeleteItem(item_row);
msg = wxString::Format(_("%s sent to trash"), text_value);
}
if (!msg.IsEmpty())
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_ERROR, *this);
}
}
void cTrashPanel::OnShowTrashContextMenu(wxTreeEvent& event)
{
SampleHive::cSerializer serializer;
cDatabase db;
wxTreeItemId selected_trashed_item = event.GetItem();
wxMenu menu;
menu.Append(SampleHive::ID::MN_DeleteTrash, _("Delete from database"), _("Delete the selected sample(s) from database"));
menu.Append(SampleHive::ID::MN_RestoreTrashedItem, _("Restore sample"), _("Restore the selected sample(s) back to library"));
if (selected_trashed_item.IsOk())
{
switch (m_pTrash->GetPopupMenuSelectionFromUser(menu, event.GetPoint()))
{
case SampleHive::ID::MN_DeleteTrash:
{
wxString trashed_item_name = serializer.DeserializeShowFileExtension() ?
m_pTrash->GetItemText(selected_trashed_item).BeforeLast('.') :
m_pTrash->GetItemText(selected_trashed_item);
db.RemoveSampleFromDatabase(trashed_item_name.ToStdString());
m_pTrash->Delete(selected_trashed_item);
SH_LOG_INFO("{} deleted from trash and databse", trashed_item_name.ToStdString());
}
break;
case SampleHive::ID::MN_RestoreTrashedItem:
{
wxArrayTreeItemIds selected_item_ids;
m_pTrash->GetSelections(selected_item_ids);
wxFileDataObject file_data;
wxArrayString files;
wxString selected_item_text;
std::string filename;
for (size_t i = 0; i < selected_item_ids.GetCount(); i++)
{
selected_item_text = m_pTrash->GetItemText(selected_item_ids[i]);
filename = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selected_item_text).Filename;
file_data.AddFile(filename);
files = file_data.GetFilenames();
db.UpdateTrashColumn(files[i].ToStdString(), 0);
try
{
wxVector<wxVector<wxVariant>> dataset;
if (db.RestoreFromTrashByFilename(files[i].ToStdString(),
dataset,
serializer.DeserializeShowFileExtension(),
ICON_STAR_FILLED_16px, ICON_STAR_EMPTY_16px).empty())
{
SH_LOG_INFO("Error! Database is empty.");
}
else
{
for (auto data : dataset)
{
SampleHive::cHiveData::Get().ListCtrlAppendItem(data);
}
}
}
catch (std::exception& e)
{
SH_LOG_ERROR("Error loading data. {}", e.what());
}
m_pTrash->Delete(selected_item_ids[i]);
SH_LOG_INFO("{} restored from trash", files[i].ToStdString());
}
}
break;
default:
break;
}
}
}
void cTrashPanel::OnClickRestoreTrashItem(wxCommandEvent& event)
{
SampleHive::cSerializer serializer;
cDatabase db;
wxArrayTreeItemIds selected_item_ids;
m_pTrash->GetSelections(selected_item_ids);
wxFileDataObject file_data;
wxArrayString files;
wxString selected_item_text;
std::string filename;
if (m_pTrash->GetChildrenCount(m_TrashRoot) == 0)
{
wxMessageBox(_("Trash is empty, nothing to restore!"), wxMessageBoxCaptionStr, wxOK | wxCENTRE, this);
return;
}
if (selected_item_ids.IsEmpty())
{
wxMessageBox(_("No item selected, try selected a item first."), wxMessageBoxCaptionStr, wxOK | wxCENTRE, this);
return;
}
for (size_t i = 0; i < selected_item_ids.GetCount(); i++)
{
selected_item_text = m_pTrash->GetItemText(selected_item_ids[i]);
filename = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selected_item_text).Filename;
file_data.AddFile(filename);
files = file_data.GetFilenames();
db.UpdateTrashColumn(files[i].ToStdString(), 0);
try
{
wxVector<wxVector<wxVariant>> dataset;
if (db.RestoreFromTrashByFilename(files[i].ToStdString(), dataset,
serializer.DeserializeShowFileExtension(),
ICON_STAR_FILLED_16px, ICON_STAR_EMPTY_16px).empty())
{
SH_LOG_INFO("Error! Database is empty.");
}
else
{
for (auto data : dataset)
{
SampleHive::cHiveData::Get().ListCtrlAppendItem(data);
}
}
}
catch (std::exception& e)
{
SH_LOG_ERROR("Error loading data. {}", e.what());
}
m_pTrash->Delete(selected_item_ids[i]);
}
}
cTrashPanel::~cTrashPanel()
{
}

58
src/GUI/Trash.hpp Normal file
View File

@ -0,0 +1,58 @@
/* 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/button.h>
#include <wx/dataview.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/treebase.h>
#include <wx/treectrl.h>
#include <wx/window.h>
class cTrashPanel : public wxPanel
{
public:
cTrashPanel(wxWindow* window);
~cTrashPanel();
public:
wxTreeCtrl* GetTrashObject() { return m_pTrash; }
wxTreeItemId& GetTrashRoot() { return m_TrashRoot; }
private:
// -------------------------------------------------------------------
// TrashPane event handlers
void OnShowTrashContextMenu(wxTreeEvent& event);
void OnClickRestoreTrashItem(wxCommandEvent& event);
void OnDragAndDropToTrash(wxDropFilesEvent& event);
private:
wxTreeItemId m_TrashRoot;
wxTreeCtrl* m_pTrash = nullptr;
wxButton* m_pRestoreTrashedItemButton = nullptr;
wxBoxSizer* m_pMainSizer = nullptr;
wxBoxSizer* m_pTrashSizer = nullptr;
wxBoxSizer* m_pButtonSizer = nullptr;
private:
wxWindow* m_pWindow = nullptr;
};

475
src/GUI/WaveformViewer.cpp Normal file
View File

@ -0,0 +1,475 @@
/* 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 "GUI/WaveformViewer.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Utils.hpp"
#include "Utility/Serialize.hpp"
#include "Utility/Event.hpp"
#include "Utility/Signal.hpp"
#include "Utility/Tags.hpp"
#include <cstddef>
#include <exception>
#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/pen.h>
#include <sndfile.h>
#include <sndfile.hh>
cWaveformViewer::cWaveformViewer(wxWindow* window, wxMediaCtrl& mediaCtrl)
: wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE),
m_Window(window), m_MediaCtrl(mediaCtrl)
{
this->SetDoubleBuffered(true);
Bind(wxEVT_PAINT, &cWaveformViewer::OnPaint, this);
Bind(wxEVT_MOTION, &cWaveformViewer::OnMouseMotion, this);
Bind(wxEVT_LEFT_DOWN, &cWaveformViewer::OnMouseLeftButtonDown, this);
Bind(wxEVT_LEFT_UP, &cWaveformViewer::OnMouseLeftButtonUp, this);
// Bind(wxEVT_KEY_DOWN, &cWaveformViewer::OnControlKeyDown, this);
Bind(wxEVT_KEY_UP, &cWaveformViewer::OnControlKeyUp, this);
m_Sizer = new wxBoxSizer(wxVERTICAL);
this->SetSizer(m_Sizer);
m_Sizer->Fit(this);
m_Sizer->SetSizeHints(this);
m_Sizer->Layout();
}
cWaveformViewer::~cWaveformViewer()
{
}
void cWaveformViewer::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)
{
SH_LOG_INFO("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();
SampleHive::cSignal::SendLoopPoints(CalculateLoopPoints(), *this);
}
else
bAreaSelected = false;
}
void cWaveformViewer::RenderPlayhead(wxDC& dc)
{
int selected_row = SampleHive::cHiveData::Get().GetListCtrlSelectedRow();
if (selected_row < 0)
return;
wxString selected = SampleHive::cHiveData::Get().GetListCtrlTextValue(selected_row, 1);
std::string path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selected).Path.ToStdString();
SampleHive::cTags 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);
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 cWaveformViewer::UpdateWaveformBitmap()
{
SampleHive::cSerializer serializer;
int selected_row = SampleHive::cHiveData::Get().GetListCtrlSelectedRow();
if (selected_row < 0)
return;
wxString selection = SampleHive::cHiveData::Get().GetListCtrlTextValue(selected_row, 1);
wxString path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selection).Path;
SndfileHandle snd_file(path.ToStdString().c_str());
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;
try
{
// 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();
SH_LOG_INFO("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 (size_t 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));
SH_LOG_DEBUG("Drawing bitmap..");
for (size_t 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);
}
SH_LOG_DEBUG("Done drawing bitmap..");
}
catch (std::exception& e)
{
SH_LOG_ERROR("Error! SNDFILE {}", e.what());
SH_LOG_ERROR("Error! SNDFILE {}", sf_strerror(snd_file.rawHandle()));
}
}
void cWaveformViewer::OnControlKeyDown(wxKeyEvent &event)
{
switch (event.GetKeyCode())
{
case WXK_CONTROL:
SetCursor(wxCURSOR_IBEAM);
break;
default:
SetCursor(wxCURSOR_ARROW);
break;
}
event.Skip();
}
void cWaveformViewer::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 cWaveformViewer::OnMouseMotion(wxMouseEvent& event)
{
int selected_row = SampleHive::cHiveData::Get().GetListCtrlSelectedRow();
if (selected_row < 0)
return;
wxString selected = SampleHive::cHiveData::Get().GetListCtrlTextValue(selected_row, 1);
std::string path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selected).Path.ToStdString();
SampleHive::cTags 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));
SH_LOG_DEBUG("Cursor on playhead..");
}
else if (bSelectRange)
{
m_CurrentPoint = wxPoint(pos.x , pos.y);
Refresh();
SH_LOG_INFO("CTRL pressed, pressing LMB will draw selection range at {}, {}", pos.x, pos.y);
}
else
return;
}
void cWaveformViewer::OnMouseLeftButtonDown(wxMouseEvent& event)
{
int selected_row = SampleHive::cHiveData::Get().GetListCtrlSelectedRow();
if (selected_row < 0)
return;
wxString selected = SampleHive::cHiveData::Get().GetListCtrlTextValue(selected_row, 1);
std::string path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selected).Path.ToStdString();
SampleHive::cTags 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();
SH_LOG_DEBUG("Mouse Captured playhead..");
}
else if (event.ControlDown())
{
SH_LOG_DEBUG("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 cWaveformViewer::OnMouseLeftButtonUp(wxMouseEvent& event)
{
int selected_row = SampleHive::cHiveData::Get().GetListCtrlSelectedRow();
if (selected_row < 0)
return;
wxString selected = SampleHive::cHiveData::Get().GetListCtrlTextValue(selected_row, 1);
std::string path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selected).Path.ToStdString();
SampleHive::cTags 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())
{
SH_LOG_INFO("Window doesn't have capture skipping..");
return;
}
if (bSelectRange)
{
SH_LOG_DEBUG("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);
SampleHive::cSignal::SendPushStatusBarStatus(wxString::Format(_("Now playing: %s"), selected), 1, *this);
SampleHive::cSignal::SendCallFunctionPlay(selected, false, *this);
}
}
void cWaveformViewer::ResetBitmapDC()
{
bBitmapDirty = true;
bSelectRange = false;
bDrawSelectedArea = false;
Refresh();
}
std::pair<double, double> cWaveformViewer::CalculateLoopPoints()
{
int selected_row = SampleHive::cHiveData::Get().GetListCtrlSelectedRow();
if (selected_row < 0)
return { 0.0, 0.0 };
wxString selected = SampleHive::cHiveData::Get().GetListCtrlTextValue(selected_row, 1);
std::string path = SampleHive::cUtils::Get().GetFilenamePathAndExtension(selected).Path.ToStdString();
SampleHive::cTags 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;
return { loopA, loopB };
}

View File

@ -0,0 +1,89 @@
/* 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/bitmap.h>
#include <wx/colour.h>
#include <wx/dc.h>
#include <wx/event.h>
#include <wx/mediactrl.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/statusbr.h>
#include <wx/window.h>
class cWaveformViewer : public wxPanel
{
public:
cWaveformViewer(wxWindow* window, wxMediaCtrl& mediaCtrl);
~cWaveformViewer();
private:
// -------------------------------------------------------------------
wxWindow* m_Window;
wxBoxSizer* m_Sizer;
// -------------------------------------------------------------------
wxMediaCtrl& m_MediaCtrl;
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);
// -------------------------------------------------------------------
std::pair<double, double> CalculateLoopPoints();
float GetBPM(const std::string& path);
public:
// -------------------------------------------------------------------
void ResetBitmapDC();
};

File diff suppressed because it is too large Load Diff

View File

@ -1,269 +0,0 @@
/* 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 <string>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/collpane.h>
#include <wx/dataview.h>
#include <wx/dirctrl.h>
#include <wx/event.h>
#include <wx/frame.h>
#include <wx/fswatcher.h>
#include <wx/infobar.h>
#include <wx/listctrl.h>
#include <wx/mediactrl.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/setup.h>
#include <wx/srchctrl.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/splitter.h>
#include <wx/statbmp.h>
#include <wx/statusbr.h>
#include <wx/string.h>
#include <wx/stringimpl.h>
#include <wx/tglbtn.h>
#include <wx/timer.h>
#include <wx/toplevel.h>
#include <wx/treebase.h>
#include <wx/treectrl.h>
#include <wx/window.h>
#include <taglib/taglib.h>
#include <taglib/fileref.h>
#include <taglib/tstring.h>
struct FileInfo
{
wxString Path;
std::string Extension;
std::string Filename;
};
class MainFrame : public wxFrame
{
public:
MainFrame();
~MainFrame();
private:
// -------------------------------------------------------------------
// Main Panel
wxPanel* m_MainPanel;
wxBoxSizer* m_MainSizer;
// -------------------------------------------------------------------
// Hive bitmap icon for the statusbar
wxStaticBitmap* m_HiveBitmap;
// -------------------------------------------------------------------
// App statusbar
wxStatusBar* m_StatusBar;
// -------------------------------------------------------------------
// App menubar
wxMenuBar* m_MenuBar;
// -------------------------------------------------------------------
// Menu and menu items for the menubar
wxMenu* m_FileMenu;
wxMenu* m_EditMenu;
wxMenu* m_ViewMenu;
wxMenu* m_HelpMenu;
wxMenuItem* m_AddFile;
wxMenuItem* m_AddDirectory;
wxMenuItem* m_ToggleExtension;
wxMenuItem* m_ToggleMenuBar;
wxMenuItem* m_ToggleStatusBar;
// -------------------------------------------------------------------
// Splitter windows
wxSplitterWindow* m_TopSplitter;
wxSplitterWindow* m_BottomSplitter;
// -------------------------------------------------------------------
// Top panel controls
wxPanel* m_TopPanel;
wxBoxSizer* m_TopSizer;
wxBoxSizer* m_TopPanelMainSizer;
wxBoxSizer* m_WaveformDisplaySizer;
wxStaticBitmap* m_WaveformViewer;
wxBoxSizer* m_BrowserControlSizer;
wxButton* m_PlayButton;
wxToggleButton* m_LoopButton;
wxButton* m_StopButton;
wxButton* m_SettingsButton;
wxToggleButton* m_MuteButton;
wxStaticText* m_SamplePosition;
wxSlider* m_VolumeSlider;
wxCheckBox* m_AutoPlayCheck;
// -------------------------------------------------------------------
// Left panel controls
wxPanel* m_BottomLeftPanel;
wxPanel* m_HivesPanel;
wxPanel* m_TrashPanel;
wxNotebook* m_Notebook;
wxBoxSizer* m_BottomLeftPanelMainSizer;
wxBoxSizer* m_HivesMainSizer;
wxBoxSizer* m_HivesFavoritesSizer;
wxBoxSizer* m_HivesButtonSizer;
wxBoxSizer* m_TrashMainSizer;
wxBoxSizer* m_TrashItemSizer;
wxBoxSizer* m_TrashButtonSizer;
wxDirCtrl* m_DirCtrl;
wxDataViewTreeCtrl* m_Hives;
wxDataViewItem favorites_hive;
wxTreeItemId trash_root;
wxTreeCtrl* m_Trash;
wxButton* m_AddHiveButton;
wxButton* m_RemoveHiveButton;
wxButton* m_RestoreTrashedItemButton;
// -------------------------------------------------------------------
// Right panel controls
wxPanel* m_BottomRightPanel;
wxBoxSizer* m_BottomRightPanelMainSizer;
wxSearchCtrl* m_SearchBox;
wxInfoBar* m_InfoBar;
wxDataViewListCtrl* m_Library;
// -------------------------------------------------------------------
// MediaCtrl
wxMediaCtrl* m_MediaCtrl;
// -------------------------------------------------------------------
// Timer
wxTimer* m_Timer;
// -------------------------------------------------------------------
// FileSystemWatcher
wxFileSystemWatcher* m_FsWatcher;
private:
// -------------------------------------------------------------------
bool bAutoplay = false;
bool bLoop = false;
bool bMuted = false;
bool bStopped = false;
bool bFiltered = false;
// -------------------------------------------------------------------
const std::string m_ConfigFilepath;
const std::string m_DatabaseFilepath;
private:
// -------------------------------------------------------------------
// Top panel control handlers
void OnClickPlay(wxCommandEvent& event);
void OnClickLoop(wxCommandEvent& event);
void OnClickStop(wxCommandEvent& event);
void OnClickMute(wxCommandEvent& event);
void OnMediaFinished(wxMediaEvent& event);
void OnCheckAutoplay(wxCommandEvent& event);
void OnSlideVolume(wxScrollEvent& event);
void OnReleaseVolumeSlider(wxScrollEvent& event);
void OnClickSettings(wxCommandEvent& event);
// -------------------------------------------------------------------
// DirCtrl event handlers
void OnClickDirCtrl(wxCommandEvent& event);
void OnDragFromDirCtrl(wxTreeEvent& event);
// -------------------------------------------------------------------
// TrashPane event handlers
void OnShowTrashContextMenu(wxTreeEvent& event);
void OnClickRestoreTrashItem(wxCommandEvent& event);
void OnDragAndDropToTrash(wxDropFilesEvent& event);
// -------------------------------------------------------------------
// Hives panel button event handlers
void OnDragAndDropToHives(wxDropFilesEvent& event);
void OnClickAddHive(wxCommandEvent& event);
void OnClickRemoveHive(wxCommandEvent& event);
void OnShowHivesContextMenu(wxDataViewEvent& event);
void OnHiveStartEditing(wxDataViewEvent& event);
// -------------------------------------------------------------------
// SearchCtrl event handlers
void OnDoSearch(wxCommandEvent& event);
void OnCancelSearch(wxCommandEvent& event);
// -------------------------------------------------------------------
// Library event handlers
void OnClickLibrary(wxDataViewEvent& event);
void OnDragAndDropToLibrary(wxDropFilesEvent& event);
void OnDragFromLibrary(wxDataViewEvent& event);
void OnShowLibraryContextMenu(wxDataViewEvent& event);
void OnShowLibraryColumnHeaderContextMenu(wxDataViewEvent& event);
// -------------------------------------------------------------------
// App menu items event handlers
void OnSelectAddFile(wxCommandEvent& event);
void OnSelectAddDirectory(wxCommandEvent& event);
void OnSelectToggleExtension(wxCommandEvent& event);
void OnSelectToggleMenuBar(wxCommandEvent& event);
void OnSelectToggleStatusBar(wxCommandEvent& event);
void OnSelectExit(wxCommandEvent& event);
void OnSelectPreferences(wxCommandEvent& event);
void OnSelectResetAppData(wxCommandEvent& event);
void OnSelectAbout(wxCommandEvent& event);
// -------------------------------------------------------------------
// Statusbar event handler
void OnResizeStatusBar(wxSizeEvent& event);
// -------------------------------------------------------------------
// Timer update event handler
void UpdateElapsedTime(wxTimerEvent& event);
// -------------------------------------------------------------------
void AddSamples(wxArrayString& files);
void OnAutoImportDir(const wxString& pathToDirectory);
// -------------------------------------------------------------------
void LoadDatabase();
void RefreshDatabase();
void LoadConfigFile();
// -------------------------------------------------------------------
// Getters
FileInfo GetFilenamePathAndExtension(const wxString& selected,
bool checkExtension = true, bool doGetFilename = true) const;
// -------------------------------------------------------------------
// Directory watchers
bool CreateWatcherIfNecessary();
void CreateWatcher();
// wxString TagLibTowx(const TagLib::String& in);
// -------------------------------------------------------------------
// Call after frame creation
void SetAfterFrameCreate();
// -------------------------------------------------------------------
friend class App;
};

View File

@ -1,405 +0,0 @@
/* 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 <fstream>
#include <sstream>
#include <wx/log.h>
#include <wx/stdpaths.h>
#include <wx/filename.h>
#include <yaml-cpp/emittermanip.h>
#include <yaml-cpp/node/parse.h>
#include "Serialize.hpp"
Serializer::Serializer(const std::string& filepath)
: m_Filepath(filepath)
{
std::ifstream ifstrm(m_Filepath);
wxFont font = wxSystemSettings::GetFont(wxSYS_SYSTEM_FONT);
std::string system_font_face = font.GetFaceName().ToStdString();
int system_font_size = font.GetPointSize();
std::string dir = wxStandardPaths::Get().GetDocumentsDir().ToStdString();
if (!ifstrm)
{
wxLogDebug("Genrating configuration file..");
m_Emitter << YAML::Comment("This is the configuration file for SampleHive,"
"feel free to edit the file as needed");
m_Emitter << YAML::Newline;
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Newline << YAML::Key << "Window";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Width" << YAML::Value << 1280;
m_Emitter << YAML::Key << "Height" << YAML::Value << 720;
m_Emitter << YAML::EndMap << YAML::Newline;
m_Emitter << YAML::Newline << YAML::Key << "Media";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Autoplay" << YAML::Value << false;
m_Emitter << YAML::Key << "Loop" << YAML::Value << false;
m_Emitter << YAML::Key << "Muted" << YAML::Value << false;
m_Emitter << YAML::EndMap << YAML::Newline;
m_Emitter << YAML::Newline << YAML::Key << "Display";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Font";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Family" << YAML::Value << system_font_face;
m_Emitter << YAML::Key << "Size" << YAML::Value << system_font_size;
m_Emitter << YAML::EndMap;
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;
m_Emitter << YAML::Key << "Directory" << YAML::Value << dir;
m_Emitter << YAML::Key << "ShowFileExtension" << YAML::Value << true;
m_Emitter << YAML::EndMap << YAML::Newline;
m_Emitter << YAML::EndMap;
std::ofstream ofstrm(m_Filepath);
ofstrm << m_Emitter.c_str();
wxLogDebug("Generated %s successfully!", m_Filepath);
}
else
{
wxLogDebug("Config file already exists! Skipping..");
}
}
Serializer::~Serializer()
{
}
int Serializer::DeserializeWinSize(std::string key, int size) const
{
int width = 800, height = 600;
try
{
YAML::Node data = YAML::LoadFile(m_Filepath);
if (!data["Window"])
{
return false;
}
if (auto win = data["Window"])
{
if (key == "Height")
{
size = height;
size = win["Height"].as<int>();
}
if (key == "Width")
{
size = width;
size = win["Width"].as<int>();
}
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
wxLogDebug("Window size: %d", size);
return size;
}
bool Serializer::DeserializeBrowserControls(std::string key, bool control) const
{
bool autoplay = false; bool loop = false; bool muted = false;
try
{
YAML::Node config = YAML::LoadFile(m_Filepath);
if (auto media = config["Media"])
{
if (key == "autoplay")
{
control = autoplay;
autoplay = media["Autoplay"].as<bool>();
}
if (key == "loop")
{
control = loop;
loop = media["Loop"].as<bool>();
}
if (key == "muted")
{
control = muted;
muted = media["Muted"].as<bool>();
}
}
else
{
wxLogDebug("Error! Cannot fetch values.");
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
wxLogDebug("Autoplay: %s, Loop: %s, Muted: %s",
autoplay ? "enabled" : "disabled",
loop ? "enabled" : "disabled",
muted ? "muted" : "unmuted");
return control;
}
void Serializer::SerializeDisplaySettings(wxFont& font)
{
YAML::Emitter out;
std::string font_face = font.GetFaceName().ToStdString();
int font_size = font.GetPointSize();
try
{
YAML::Node config = YAML::LoadFile(m_Filepath);
auto display = config["Display"];
if (auto fontSetting = display["Font"])
{
wxLogDebug("Changing font settings");
wxLogDebug("Font face: %s", font_face);
wxLogDebug("Font size: %d", font_size);
fontSetting["Family"] = font_face;
fontSetting["Size"] = font_size;
out << config;
std::ofstream ofstrm(m_Filepath);
ofstrm << out.c_str();
}
else
{
wxLogDebug("Error! Cannot store font values.");
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
}
FontType Serializer::DeserializeDisplaySettings() const
{
wxString face;
int size = 0 ;
try
{
YAML::Node config = YAML::LoadFile(m_Filepath);
auto display = config["Display"];
if (auto font_setting = display["Font"])
{
face = font_setting["Family"].as<std::string>();
size = font_setting["Size"].as<int>();
}
else
{
wxLogDebug("Error! Cannot fetch font values.");
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
return { face, size };
}
void Serializer::SerializeAutoImportSettings(wxTextCtrl& textCtrl, wxCheckBox& checkBox)
{
YAML::Emitter out;
std::string import_dir = textCtrl.GetValue().ToStdString();
bool auto_import = checkBox.GetValue();
try
{
YAML::Node config = YAML::LoadFile(m_Filepath);
if (auto autoImportInfo = config["Collection"])
{
autoImportInfo["AutoImport"] = auto_import;
autoImportInfo["Directory"] = import_dir;
out << config;
std::ofstream ofstrm(m_Filepath);
ofstrm << out.c_str();
}
else
{
wxLogDebug("Error! Cannot store import dir values.");
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
}
ImportDirInfo Serializer::DeserializeAutoImportSettings() const
{
wxString dir;
bool auto_import = false;
try
{
YAML::Node config = YAML::LoadFile(m_Filepath);
if (auto autoImportInfo = config["Collection"])
{
auto_import = autoImportInfo["AutoImport"].as<bool>();
dir = autoImportInfo["Directory"].as<std::string>();
}
else
{
wxLogDebug("Error! Cannot fetch import dir values.");
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
return { auto_import, dir};
}
void Serializer::SerializeShowFileExtensionSetting(wxCheckBox& checkBox)
{
YAML::Emitter out;
bool show_extension = checkBox.GetValue();
try
{
YAML::Node config = YAML::LoadFile(m_Filepath);
if (auto fileExtensionInfo = config["Collection"])
{
fileExtensionInfo["ShowFileExtension"] = show_extension;
out << config;
wxLogDebug("Changing show file extension value.");
std::ofstream ofstrm(m_Filepath);
ofstrm << out.c_str();
}
else
{
wxLogDebug("Error! Cannot store import dir values.");
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
}
bool Serializer::DeserializeShowFileExtensionSetting() const
{
bool show_extension = false;
try
{
YAML::Node config = YAML::LoadFile(m_Filepath);
if (auto fileExtensionInfo = config["Collection"])
{
show_extension = fileExtensionInfo["ShowFileExtension"].as<bool>();
}
else
{
wxLogDebug("Error! Cannot fetch import dir values.");
}
}
catch(const YAML::ParserException& ex)
{
std::cout << ex.what() << std::endl;
}
return show_extension;
}
void Serializer::SerializeDataViewTreeCtrlItems(wxTreeCtrl& tree, wxTreeItemId& item)
{
std::string path = "tree.yaml";
std::ifstream ifstrm(path);
YAML::Emitter out;
out << YAML::BeginMap; // Container
out << YAML::Key << "Container" << YAML::Value << "";
if (tree.HasChildren(item))
{
out << YAML::Key << "Child";
out << YAML::BeginMap; // Child
for ( size_t i = 0; i < tree.GetChildrenCount(item); i++ )
{
// wxTreeItemIdValue cookie;
wxString child = tree.GetItemText(tree.GetSelection());
out << YAML::Key << "Item" << YAML::Value << child.ToStdString();
}
out << YAML::EndMap; // Child
}
out << YAML::EndMap; // Container
std::ofstream ofstrm(path);
ofstrm << out.c_str();
}
bool Serializer::DeserializeDataViewTreeCtrlItems(YAML::Emitter &out, wxDataViewItem item) const
{
return false;
}

View File

@ -1,94 +0,0 @@
/* 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 <string>
#include <wx/checkbox.h>
#include <wx/dataview.h>
#include <wx/font.h>
#include <wx/string.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/treebase.h>
#include <wx/treectrl.h>
#include <yaml-cpp/yaml.h>
#include <yaml-cpp/emitter.h>
#include <yaml-cpp/emittermanip.h>
#include <yaml-cpp/exceptions.h>
#include <yaml-cpp/node/node.h>
#include <yaml-cpp/node/parse.h>
#include <yaml-cpp/null.h>
#include <yaml-cpp/emittermanip.h>
struct FontType
{
wxString font_face;
int font_size;
};
struct ImportDirInfo
{
bool auto_import;
wxString import_dir;
};
class Serializer
{
public:
Serializer(const std::string& filepath);
~Serializer();
private:
// -------------------------------------------------------------------
const std::string& m_Filepath;
YAML::Emitter m_Emitter;
public:
// -------------------------------------------------------------------
// Window size
int DeserializeWinSize(std::string key, int size) const;
// -------------------------------------------------------------------
// Browser controls
void SerializeBrowserControls();
bool DeserializeBrowserControls(std::string key, bool control) const;
// -------------------------------------------------------------------
// Display settings
void SerializeDisplaySettings(wxFont& font);
FontType DeserializeDisplaySettings() const;
// -------------------------------------------------------------------
// Auto import settings
void SerializeAutoImportSettings(wxTextCtrl& textCtrl, wxCheckBox& checkBox);
ImportDirInfo DeserializeAutoImportSettings() const;
// -------------------------------------------------------------------
// Show file extension
void SerializeShowFileExtensionSetting(wxCheckBox& checkBox);
bool DeserializeShowFileExtensionSetting() const;
// -------------------------------------------------------------------
// Favorite samples
void SerializeDataViewTreeCtrlItems(wxTreeCtrl& tree, wxTreeItemId& item);
bool DeserializeDataViewTreeCtrlItems(YAML::Emitter& out, wxDataViewItem item) const;
};

View File

@ -1,429 +0,0 @@
/* 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 <wx/defs.h>
#include <wx/gdicmn.h>
#include <wx/log.h>
#include <wx/stdpaths.h>
#include <wx/stringimpl.h>
#include "ControlID_Enums.hpp"
#include "SettingsDialog.hpp"
#include "Serialize.hpp"
Settings::Settings(const std::string& configFilepath, const std::string& databaseFilepath)
: m_ConfigFilepath(configFilepath), m_DatabaseFilepath(databaseFilepath)
{
}
Settings::Settings(wxWindow* window, const std::string& configFilepath, const std::string& databaseFilepath)
: wxDialog(window, wxID_ANY, "Settings", wxDefaultPosition,
wxSize(720, 270), wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP),
m_Window(window), m_ConfigFilepath(configFilepath), m_DatabaseFilepath(databaseFilepath)
{
m_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_MainSizer = new wxBoxSizer(wxVERTICAL);
m_NotebookSizer = new wxBoxSizer(wxVERTICAL);
m_ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
m_Notebook = new wxNotebook(m_Panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, _T("NOTEBOOK"));
m_DisplaySettingPanel = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_DisplayTopSizer = new wxBoxSizer(wxVERTICAL);
m_DisplayFontSizer = new wxBoxSizer(wxHORIZONTAL);
wxString fontChoices[] = {"System default"};
// m_RowHeightText = new wxStaticText();
m_FontTypeText = new wxStaticText(m_DisplaySettingPanel, wxID_ANY, "Font", wxDefaultPosition, wxDefaultSize, 0);
// m_RowHeight = new wxChoice();
m_FontType = new wxChoice(m_DisplaySettingPanel, SD_FontType, wxDefaultPosition, wxDefaultSize, 1, fontChoices, 0);
m_FontType->SetSelection(0);
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_CollectionSettingPanel = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_CollectionTopSizer = new wxBoxSizer(wxVERTICAL);
m_CollectionImportDirSizer = new wxBoxSizer(wxHORIZONTAL);
m_ShowFileExtensionSizer = new wxBoxSizer(wxHORIZONTAL);
wxString defaultDir = wxStandardPaths::Get().GetDocumentsDir();
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);
m_ImportDirLocation->Disable();
m_BrowseAutoImportDirButton = new wxButton(m_CollectionSettingPanel, SD_BrowseAutoImportDir, "Browse", wxDefaultPosition, wxDefaultSize, 0);
m_BrowseAutoImportDirButton->Disable();
m_ShowFileExtensionCheck = new wxCheckBox(m_CollectionSettingPanel, SD_ShowFileExtension, "Show file extension", wxDefaultPosition, wxDefaultSize, 0);
m_ConfigurationSettingPanel = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_GeneralMainSizer = new wxFlexGridSizer(2, 3, 0, 0);
m_GeneralMainSizer->AddGrowableCol(1);
m_GeneralMainSizer->SetFlexibleDirection(wxBOTH);
m_GeneralMainSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
m_ConfigLabel = new wxStaticText(m_ConfigurationSettingPanel, wxID_ANY, "Default configuration file location", wxDefaultPosition, wxDefaultSize);
m_ConfigText = new wxTextCtrl(m_ConfigurationSettingPanel, wxID_ANY, configFilepath, wxDefaultPosition, wxDefaultSize);
m_ConfigBrowse = new wxButton(m_ConfigurationSettingPanel, SD_BrowseConfigDir, "Browse", wxDefaultPosition, wxDefaultSize, 0);
m_DatabaseLabel = new wxStaticText(m_ConfigurationSettingPanel, wxID_ANY, "Default database location", wxDefaultPosition, wxDefaultSize);
m_DatabaseText = new wxTextCtrl(m_ConfigurationSettingPanel, wxID_ANY, databaseFilepath, wxDefaultPosition, wxDefaultSize);
m_DatabaseBrowse = new wxButton(m_ConfigurationSettingPanel, SD_BrowseDatabaseDir, "Browse", wxDefaultPosition, wxDefaultSize, 0);
m_Notebook->AddPage(m_DisplaySettingPanel, "Display");
m_Notebook->AddPage(m_CollectionSettingPanel, "Collection");
m_Notebook->AddPage(m_ConfigurationSettingPanel, "General");
m_OkButton = new wxButton(m_Panel, wxID_OK, "OK", wxDefaultPosition, wxDefaultSize);
m_CancelButton = new wxButton(m_Panel, wxID_CANCEL, "Cancel", wxDefaultPosition, wxDefaultSize);
LoadDefaultConfig();
// Bind events
Bind(wxEVT_CHECKBOX, &Settings::OnCheckAutoImport, this, SD_AutoImport);
Bind(wxEVT_CHECKBOX, &Settings::OnCheckShowFileExtension, this, SD_ShowFileExtension);
Bind(wxEVT_SPINCTRL, &Settings::OnChangeFontSize, this, SD_FontSize);
Bind(wxEVT_BUTTON, &Settings::OnSelectFont, this, SD_FontBrowseButton);
Bind(wxEVT_BUTTON, &Settings::OnClickBrowseAutoImportDir, this, SD_BrowseAutoImportDir);
Bind(wxEVT_BUTTON, &Settings::OnClickConfigBrowse, this, SD_BrowseConfigDir);
Bind(wxEVT_BUTTON, &Settings::OnClickDatabaseBrowse, this, SD_BrowseDatabaseDir);
// 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_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_DatabaseLabel, 0, wxALL | wxALIGN_LEFT | 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_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_DisplayTopSizer->Add(m_DisplayFontSizer, 1, wxALL | wxEXPAND, 2);
m_CollectionImportDirSizer->Add(m_AutoImportCheck, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT, 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_ShowFileExtensionSizer->Add(m_ShowFileExtensionCheck, 0, wxALL | wxALIGN_LEFT, 2);
m_CollectionTopSizer->Add(m_CollectionImportDirSizer, 0, wxALL | wxEXPAND, 2);
m_CollectionTopSizer->Add(m_ShowFileExtensionSizer, 0, wxALL | wxEXPAND, 2);
m_ButtonSizer->Add(m_OkButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_ButtonSizer->Add(m_CancelButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_MainSizer->Add(m_NotebookSizer, 1, wxALL | wxEXPAND, 2);
m_MainSizer->Add(m_ButtonSizer, 0, wxALL | wxALIGN_RIGHT, 2);
// Top panel layout
m_Panel->SetSizer(m_MainSizer);
m_MainSizer->Fit(m_Panel);
m_MainSizer->SetSizeHints(m_Panel);
m_MainSizer->Layout();
// Display panel layout
m_DisplaySettingPanel->SetSizer(m_DisplayTopSizer);
m_DisplayTopSizer->Fit(m_DisplaySettingPanel);
m_DisplayTopSizer->SetSizeHints(m_DisplaySettingPanel);
m_DisplayTopSizer->Layout();
// Collection panel layout
m_CollectionSettingPanel->SetSizer(m_CollectionTopSizer);
m_CollectionTopSizer->Fit(m_CollectionSettingPanel);
m_CollectionTopSizer->SetSizeHints(m_CollectionSettingPanel);
m_CollectionTopSizer->Layout();
// Configuration panel layout
m_ConfigurationSettingPanel->SetSizer(m_GeneralMainSizer);
m_GeneralMainSizer->Fit(m_ConfigurationSettingPanel);
m_GeneralMainSizer->SetSizeHints(m_ConfigurationSettingPanel);
m_GeneralMainSizer->Layout();
}
void Settings::OnClickConfigBrowse(wxCommandEvent& event)
{
wxString initial_dir = wxStandardPaths::Get().GetDocumentsDir();
m_DirDialog = new wxDirDialog(this, "Select a directory..", initial_dir,
wxDD_DEFAULT_STYLE |
wxDD_DIR_MUST_EXIST |
wxDD_NEW_DIR_BUTTON,
wxDefaultPosition, wxDefaultSize);
switch (m_DirDialog->ShowModal())
{
case wxID_OK:
{
wxString path = m_DirDialog->GetPath();
m_ConfigText->SetValue(path + "/config.yaml");
break;
}
default:
return;
}
}
void Settings::OnClickDatabaseBrowse(wxCommandEvent& event)
{
wxString initial_dir = wxStandardPaths::Get().GetDocumentsDir();
m_DirDialog = new wxDirDialog(this, "Select a directory..", initial_dir,
wxDD_DEFAULT_STYLE |
wxDD_DIR_MUST_EXIST |
wxDD_NEW_DIR_BUTTON,
wxDefaultPosition, wxDefaultSize);
switch (m_DirDialog->ShowModal())
{
case wxID_OK:
{
wxString path = m_DirDialog->GetPath();
m_DatabaseText->SetValue(path + "/config.yaml");
break;
}
default:
return;
}
}
void Settings::OnCheckAutoImport(wxCommandEvent& event)
{
Serializer serializer(m_ConfigFilepath);
if (!m_AutoImportCheck->GetValue())
{
bAutoImport = false;
m_ImportDirLocation->Disable();
m_BrowseAutoImportDirButton->Disable();
serializer.SerializeAutoImportSettings(*m_ImportDirLocation, *m_AutoImportCheck);
}
else
{
bAutoImport = true;
m_ImportDirLocation->Enable();
m_BrowseAutoImportDirButton->Enable();
serializer.SerializeAutoImportSettings(*m_ImportDirLocation, *m_AutoImportCheck);
}
}
void Settings::OnCheckShowFileExtension(wxCommandEvent& event)
{
Serializer serialize(m_ConfigFilepath);
if (!m_ShowFileExtensionCheck->GetValue())
{
bShowExtension = false;
serialize.SerializeShowFileExtensionSetting(*m_ShowFileExtensionCheck);
}
else
{
bShowExtension = true;
serialize.SerializeShowFileExtensionSetting(*m_ShowFileExtensionCheck);
}
}
void Settings::OnClickBrowseAutoImportDir(wxCommandEvent& event)
{
Serializer serializer(m_ConfigFilepath);
wxString initial_dir = wxStandardPaths::Get().GetDocumentsDir();
m_DirDialog = new wxDirDialog(this, "Select a directory..", initial_dir,
wxDD_DEFAULT_STYLE |
wxDD_DIR_MUST_EXIST |
wxDD_NEW_DIR_BUTTON,
wxDefaultPosition, wxDefaultSize);
switch (m_DirDialog->ShowModal())
{
case wxID_OK:
{
wxString path = m_DirDialog->GetPath();
m_ImportDirLocation->SetValue(path);
serializer.SerializeAutoImportSettings(*m_ImportDirLocation, *m_AutoImportCheck);
break;
}
default:
return;
}
}
void Settings::OnSelectFont(wxCommandEvent& event)
{
m_FontDialog = new wxFontDialog(this);
switch (m_FontDialog->ShowModal())
{
case wxID_OK:
{
wxFontData fontData = m_FontDialog->GetFontData();
m_Font = fontData.GetChosenFont();
if (m_FontType->GetCount() > 1)
{
m_FontType->Delete(1);
m_FontType->AppendString(m_Font.GetFaceName());
m_FontType->SetSelection(1);
}
else
{
m_FontType->AppendString(m_Font.GetFaceName());
m_FontType->SetSelection(1);
}
SetCustomFont();
}
default:
return;
}
PrintFont();
}
void Settings::OnChangeFontSize(wxSpinEvent& event)
{
Serializer serializer(m_ConfigFilepath);
int font_size = m_FontSize->GetValue();
if ( m_FontType->GetStringSelection() == "System default" )
m_Font = wxSystemSettings::GetFont(wxSYS_SYSTEM_FONT);
m_Font.SetPointSize(font_size);
serializer.SerializeDisplaySettings(m_Font);
m_Window->SetFont(m_Font);
this->SetFont(m_Font);
wxLogDebug("Font size: %d", font_size);
wxLogDebug("Font size: %d", m_Font.GetPointSize());
}
void Settings::LoadDefaultConfig()
{
Serializer serializer(m_ConfigFilepath);
wxFont sys_font = wxSystemSettings::GetFont(wxSYS_SYSTEM_FONT);
std::string system_font = sys_font.GetFaceName().ToStdString();
int system_font_size = sys_font.GetPointSize();
wxString font_face = serializer.DeserializeDisplaySettings().font_face;
int font_size = serializer.DeserializeDisplaySettings().font_size;
if ( system_font != font_face )
{
if (m_FontType->GetCount() > 1)
{
m_FontType->Delete(1);
m_FontType->AppendString(font_face);
m_FontType->SetSelection(1);
m_Font.SetFaceName(font_face);
m_Font.SetPointSize(font_size);
}
else
{
m_FontType->AppendString(font_face);
m_FontType->SetSelection(1);
m_Font.SetFaceName(font_face);
m_Font.SetPointSize(font_size);
}
}
m_FontSize->SetValue(font_size);
SetCustomFont();
bAutoImport = serializer.DeserializeAutoImportSettings().auto_import;
wxString location = serializer.DeserializeAutoImportSettings().import_dir;
bShowExtension = serializer.DeserializeShowFileExtensionSetting();
m_AutoImportCheck->SetValue(bAutoImport);
m_ImportDirLocation->SetValue(location);
m_ShowFileExtensionCheck->SetValue(bShowExtension);
if (bAutoImport)
{
m_ImportDirLocation->Enable();
m_BrowseAutoImportDirButton->Enable();
}
}
void Settings::PrintFont()
{
wxLogDebug("Font face: %s", m_Font.GetFaceName());
wxLogDebug("Font size: %d", m_Font.GetPointSize());
wxLogDebug("Font family: %s", m_Font.GetFamilyString());
wxLogDebug("Font style: %s", m_Font.GetStyleString());
wxLogDebug("Font weight: %s", m_Font.GetWeightString());
}
void Settings::SetCustomFont()
{
Serializer serializer(m_ConfigFilepath);
wxFont sys_font = wxSystemSettings::GetFont(wxSYS_SYSTEM_FONT);
std::string system_font = sys_font.GetFaceName().ToStdString();
int system_font_size = sys_font.GetPointSize();
wxString font_face = serializer.DeserializeDisplaySettings().font_face;
int font_size = serializer.DeserializeDisplaySettings().font_size;
if ( m_FontType->GetStringSelection() == "System default" )
{
m_Window->SetFont(sys_font);
this->SetFont(sys_font);
serializer.SerializeDisplaySettings(sys_font);
}
else
{
m_Window->SetFont(m_Font);
this->SetFont(m_Font);
serializer.SerializeDisplaySettings(m_Font);
}
}
wxString Settings::GetImportDirPath()
{
wxString dir = wxEmptyString;
if (m_AutoImportCheck->GetValue())
dir = m_ImportDirLocation->GetValue();
return dir;
}
Settings::~Settings(){}

View File

@ -1,319 +0,0 @@
/* 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 <wx/defs.h>
#include <wx/gdicmn.h>
#include <wx/log.h>
#include <wx/msgdlg.h>
#include <wx/stringimpl.h>
#include <wx/textdlg.h>
#include "ControlID_Enums.hpp"
#include "Database.hpp"
#include "TagEditorDialog.hpp"
TagEditor::TagEditor(wxWindow* window, const std::string& dbPath, const std::string& filename, wxInfoBar& info_bar)
: wxDialog(window, wxID_ANY, "Edit tags", wxDefaultPosition,
wxSize(640, 360), wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP),
m_Window(window), m_DatabaseFilepath(dbPath), m_Filename(filename), m_InfoBar(info_bar), tags(filename)
{
m_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_MainSizer = new wxBoxSizer(wxVERTICAL);
m_ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
m_EditTagSizer = new wxFlexGridSizer(6, 2, 0, 0);
m_EditTagSizer->AddGrowableCol(1);
m_EditTagSizer->SetFlexibleDirection(wxBOTH);
m_EditTagSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
m_SampleTypeSizer = new wxFlexGridSizer(1, 3, 0, 0);
m_SampleTypeSizer->AddGrowableCol(1);
m_SampleTypeSizer->SetFlexibleDirection(wxBOTH);
m_SampleTypeSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
m_StaticEditTagSizer = new wxStaticBoxSizer(wxVERTICAL, m_Panel, "Edit tags");
m_StaticSampleTypeSizer = new wxStaticBoxSizer(wxVERTICAL, m_Panel, "Sample type");
wxString choices[] = {"Kick", "Snare", "Clap", "HiHat", "Cymbal", "Cowbell", "Ride", "Tom", "Shaker", "Percussion"};
m_TitleCheck = new wxCheckBox(m_Panel, ET_TitleCheck, "Title", wxDefaultPosition, wxDefaultSize);
m_ArtistCheck = new wxCheckBox(m_Panel, ET_ArtistCheck, "Artist", wxDefaultPosition, wxDefaultSize);
m_AlbumCheck = new wxCheckBox(m_Panel, ET_AlbumCheck, "Album", wxDefaultPosition, wxDefaultSize);
m_GenreCheck = new wxCheckBox(m_Panel, ET_GenreCheck, "Genre", wxDefaultPosition, wxDefaultSize);
m_CommentCheck = new wxCheckBox(m_Panel, ET_CommentsCheck, "Comments", wxDefaultPosition, wxDefaultSize);
m_SampleTypeCheck = new wxCheckBox(m_Panel, ET_TypeCheck, "Type", wxDefaultPosition, wxDefaultSize);
m_TitleText = new wxTextCtrl(m_Panel, wxID_ANY, tags.GetAudioInfo().title, wxDefaultPosition, wxDefaultSize);
m_TitleText->Disable();
m_ArtistText = new wxTextCtrl(m_Panel, wxID_ANY, tags.GetAudioInfo().artist, wxDefaultPosition, wxDefaultSize);
m_ArtistText->Disable();
m_AlbumText = new wxTextCtrl(m_Panel, wxID_ANY, tags.GetAudioInfo().album, wxDefaultPosition, wxDefaultSize);
m_AlbumText->Disable();
m_GenreText = new wxTextCtrl(m_Panel, wxID_ANY, tags.GetAudioInfo().genre, wxDefaultPosition, wxDefaultSize);
m_GenreText->Disable();
m_CommentText = new wxTextCtrl(m_Panel, wxID_ANY, tags.GetAudioInfo().comment, wxDefaultPosition, wxDefaultSize);
m_CommentText->Disable();
m_SampleTypeChoice = new wxChoice(m_Panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 10, choices, wxCB_SORT);
m_SampleTypeChoice->Disable();
m_SampleTypeButton = new wxButton(m_Panel, ET_CustomTag, "Custom", wxDefaultPosition, wxDefaultSize);
m_SampleTypeButton->Disable();
m_OkButton = new wxButton(m_Panel, wxID_OK, "OK", wxDefaultPosition, wxDefaultSize);
m_ApplyButton = new wxButton(m_Panel, wxID_APPLY, "Apply", wxDefaultPosition, wxDefaultSize);
m_CancelButton = new wxButton(m_Panel, wxID_CANCEL, "Cancel", wxDefaultPosition, wxDefaultSize);
// Binding events
Bind(wxEVT_CHECKBOX, &TagEditor::OnCheckTitle, this, ET_TitleCheck);
Bind(wxEVT_CHECKBOX, &TagEditor::OnCheckArtist, this, ET_ArtistCheck);
Bind(wxEVT_CHECKBOX, &TagEditor::OnCheckAlbum, this, ET_AlbumCheck);
Bind(wxEVT_CHECKBOX, &TagEditor::OnCheckGenre, this, ET_GenreCheck);
Bind(wxEVT_CHECKBOX, &TagEditor::OnCheckComments, this, ET_CommentsCheck);
Bind(wxEVT_CHECKBOX, &TagEditor::OnCheckType, this, ET_TypeCheck);
Bind(wxEVT_BUTTON, &TagEditor::OnClickCustomTagButton, this, ET_CustomTag);
Bind(wxEVT_BUTTON, &TagEditor::OnClickApply, this, wxID_APPLY);
m_EditTagSizer->Add(m_TitleCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_EditTagSizer->Add(m_TitleText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_EditTagSizer->Add(m_ArtistCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_EditTagSizer->Add(m_ArtistText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_EditTagSizer->Add(m_AlbumCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_EditTagSizer->Add(m_AlbumText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_EditTagSizer->Add(m_GenreCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_EditTagSizer->Add(m_GenreText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_EditTagSizer->Add(m_CommentCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_EditTagSizer->Add(m_CommentText, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_SampleTypeSizer->Add(m_SampleTypeCheck, 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
m_SampleTypeSizer->Add(m_SampleTypeChoice, 1, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
m_SampleTypeSizer->Add(m_SampleTypeButton, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
m_StaticEditTagSizer->Add(m_EditTagSizer, 1, wxALL | wxEXPAND, 2);
m_StaticSampleTypeSizer->Add(m_SampleTypeSizer, 1, wxALL | wxEXPAND, 2);
m_ButtonSizer->Add(m_OkButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_ButtonSizer->Add(m_ApplyButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_ButtonSizer->Add(m_CancelButton, 0, wxALL | wxALIGN_BOTTOM, 2);
m_MainSizer->Add(m_StaticEditTagSizer, 1, wxALL | wxEXPAND, 2);
m_MainSizer->Add(m_StaticSampleTypeSizer, 1, wxALL | wxEXPAND, 2);
m_MainSizer->Add(m_ButtonSizer, 0, wxALL | wxALIGN_RIGHT, 2);
// Top panel layout
m_Panel->SetSizer(m_MainSizer);
m_MainSizer->Fit(m_Panel);
m_MainSizer->SetSizeHints(m_Panel);
m_MainSizer->Layout();
}
void TagEditor::OnCheckTitle(wxCommandEvent &event)
{
if (m_TitleCheck->GetValue())
{
m_TitleText->Enable();
}
else
{
m_TitleText->Disable();
}
}
void TagEditor::OnCheckArtist(wxCommandEvent &event)
{
if (m_ArtistCheck->GetValue())
{
m_ArtistText->Enable();
}
else
{
m_ArtistText->Disable();
}
}
void TagEditor::OnCheckAlbum(wxCommandEvent &event)
{
if (m_AlbumCheck->GetValue())
{
m_AlbumText->Enable();
}
else
{
m_AlbumText->Disable();
}
}
void TagEditor::OnCheckGenre(wxCommandEvent &event)
{
if (m_GenreCheck->GetValue())
{
m_GenreText->Enable();
}
else
{
m_GenreText->Disable();
}
}
void TagEditor::OnCheckComments(wxCommandEvent &event)
{
if (m_CommentCheck->GetValue())
{
m_CommentText->Enable();
}
else
{
m_CommentText->Disable();
}
}
void TagEditor::OnCheckType(wxCommandEvent &event)
{
if (m_SampleTypeCheck->GetValue())
{
m_SampleTypeChoice->Enable();
m_SampleTypeButton->Enable();
}
else
{
m_SampleTypeChoice->Disable();
m_SampleTypeButton->Disable();
}
}
void TagEditor::OnClickCustomTagButton(wxCommandEvent& event)
{
wxTextEntryDialog* customTag;
customTag = new wxTextEntryDialog(this, "Enter a custom tag",
"Add custom tag", wxEmptyString,
wxTextEntryDialogStyle, wxDefaultPosition);
switch (customTag->ShowModal())
{
case wxID_OK:
{
wxString tag = customTag->GetValue();
m_SampleTypeChoice->AppendString(tag);
m_SampleTypeChoice->SetStringSelection(tag);
break;
}
case wxID_CANCEL:
break;
default:
return;
}
}
void TagEditor::OnClickApply(wxCommandEvent& event)
{
Database db(m_InfoBar);
wxString title = m_TitleText->GetValue();
wxString artist = m_ArtistText->GetValue();
wxString album = m_AlbumText->GetValue();
wxString genre = m_GenreText->GetValue();
wxString comment = m_CommentText->GetValue();
wxString type = m_SampleTypeChoice->GetStringSelection();
std::string sampleType = db.GetSampleType(m_DatabaseFilepath, m_Filename);
std::string filename = wxString(m_Filename).AfterLast('/').BeforeLast('.').ToStdString();
wxString warning_msg = "Are you sure you want save these changes?";
wxMessageDialog* msgDialog = new wxMessageDialog(this, warning_msg,
"Edit tags", wxCENTRE |
wxYES_NO | wxNO_DEFAULT |
wxICON_QUESTION |
wxSTAY_ON_TOP,
wxDefaultPosition);
wxString info_msg;
switch (msgDialog->ShowModal())
{
case wxID_YES:
if (m_TitleCheck->GetValue() && m_TitleText->GetValue() != tags.GetAudioInfo().title)
{
wxLogDebug("Changing title tag..");
tags.SetTitle(title.ToStdString());
info_msg = wxString::Format("Successfully changed title tag to %s", title);
}
if (m_ArtistCheck->GetValue() && m_ArtistText->GetValue() != tags.GetAudioInfo().artist)
{
wxLogDebug("Changing artist tag..");
tags.SetArtist(artist.ToStdString());
db.UpdateSamplePack(m_DatabaseFilepath, m_Filename, artist.ToStdString());
wxLogDebug("SAMPLE FILENAME HERE: %s", m_Filename);
info_msg = wxString::Format("Successfully changed artist tag to %s", artist);
}
if (m_AlbumCheck->GetValue() && m_AlbumText->GetValue() != tags.GetAudioInfo().album)
{
wxLogDebug("Changing album tag..");
tags.SetAlbum(album.ToStdString());
info_msg = wxString::Format("Successfully changed album tag to %s", album);
}
if (m_GenreCheck->GetValue() && m_GenreText->GetValue() != tags.GetAudioInfo().genre)
{
wxLogDebug("Changing genre tag..");
tags.SetGenre(genre.ToStdString());
info_msg = wxString::Format("Successfully changed genre tag to %s", genre);
}
if (m_CommentCheck->GetValue() && m_CommentText->GetValue() != tags.GetAudioInfo().comment)
{
wxLogDebug("Changing comment tag..");
tags.SetComment(comment.ToStdString());
info_msg = wxString::Format("Successfully changed comment tag to %s", comment);
}
if (m_SampleTypeCheck->GetValue() && m_SampleTypeChoice->GetStringSelection() != sampleType)
{
wxLogDebug("Changing type tag..");
db.UpdateSampleType(m_DatabaseFilepath, filename, type.ToStdString());
info_msg = wxString::Format("Successfully changed type tag to %s", type);
}
break;
case wxID_NO:
break;
default:
info_msg = "Error, cannot change tag!";
}
m_InfoBar.ShowMessage(info_msg, wxICON_INFORMATION);
}
TagEditor::~TagEditor()
{
}

View File

@ -1,144 +0,0 @@
/* 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 <taglib/taglib.h>
#include <taglib/fileref.h>
#include <taglib/tstring.h>
#include "Tags.hpp"
Tags::Tags(const std::string& filename)
: m_Filepath(filename)
{
}
Tags::~Tags()
{
}
AudioInfo Tags::GetAudioInfo()
{
wxString artist, album, genre, title, comment;
int channels = 0, length = 0, sample_rate = 0, bitrate = 0;
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
TagLib::AudioProperties* properties = f.audioProperties();
TagLib::String Title = tag->title();
TagLib::String Artist = tag->artist();
TagLib::String Album = tag->album();
TagLib::String Genre = tag->genre();
TagLib::String Comment = tag->comment();
int seconds = properties->length() % 60;
int minutes = (properties->length() - seconds) / 60;
bitrate = properties->bitrate();
channels = properties->channels();
length = properties->lengthInMilliseconds();
int length_sec = properties->lengthInSeconds();
sample_rate = properties->sampleRate();
title = wxString::FromUTF8(Title.toCString(true));
artist = wxString::FromUTF8(Artist.toCString(true));
album = wxString::FromUTF8(Album.toCString(true));
genre = wxString::FromUTF8(Genre.toCString(true));
comment = wxString::FromUTF8(Comment.toCString(true));
bValid = true;
}
else
{
bValid = false;
}
return { title, artist, album, genre, comment, channels, length, sample_rate, bitrate };
}
void Tags::SetTitle(std::string title)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setTitle(title);
f.save();
}
}
void Tags::SetArtist(std::string artist)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setArtist(artist);
f.save();
}
}
void Tags::SetAlbum(std::string album)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setAlbum(album);
f.save();
}
}
void Tags::SetGenre(std::string genre)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setGenre(genre);
f.save();
}
}
void Tags::SetComment(std::string comment)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setComment(comment);
f.save();
}
}

124
src/Utility/ControlIDs.hpp Normal file
View File

@ -0,0 +1,124 @@
/* 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 <wx/defs.h>
namespace SampleHive { namespace ID {
enum ControlIDs
{
/*
** BC = Browser control
** SD = Settings dialog
** MN = Popup menu
** ET = Edit tag dialog
*/
// -------------------------------------------------------------------
// Browser controls
BC_Play = wxID_HIGHEST + 1,
BC_Settings,
BC_Loop,
BC_Stop,
BC_LoopABButton,
BC_Mute,
BC_Autoplay,
BC_Volume,
BC_SamplePosition,
BC_Hives,
BC_DirCtrl,
BC_Library,
BC_Search,
BC_MediaCtrl,
BC_Trash,
BC_RestoreTrashedItem,
BC_HiveAdd,
BC_HiveRemove,
// -------------------------------------------------------------------
// Setting dialog controls
SD_BrowseConfigDir,
SD_BrowseDatabaseDir,
SD_AutoImport,
SD_FollowSymLinks,
SD_RecursiveImport,
SD_ShowFileExtension,
SD_DoubleClickToPlay,
SD_BrowseAutoImportDir,
SD_FontType,
SD_FontSize,
SD_FontBrowseButton,
SD_WaveformColourPickerCtrl,
SD_ShowSplash,
// -------------------------------------------------------------------
// App Menu items
MN_AddFile,
MN_AddDirectory,
MN_ToggleExtension,
MN_ToggleMenuBar,
MN_ToggleStatusBar,
// -------------------------------------------------------------------
// Library Menu items
MN_FavoriteSample,
MN_DeleteSample,
MN_TrashSample,
MN_EditTagSample,
MN_OpenFile,
// -------------------------------------------------------------------
// Library Column Header Menu items
MN_ColumnFavorite,
MN_ColumnFilename,
MN_ColumnSamplePack,
MN_ColumnType,
MN_ColumnChannels,
MN_ColumnBPM,
MN_ColumnLength,
MN_ColumnSampleRate,
MN_ColumnBitrate,
MN_ColumnPath,
// -------------------------------------------------------------------
// Hives Menu items
MN_RenameHive,
MN_DeleteHive,
MN_RemoveSample,
MN_FilterLibrary,
MN_ShowInLibrary,
// -------------------------------------------------------------------
// Trash Menu items
MN_DeleteTrash,
MN_RestoreTrashedItem,
// -------------------------------------------------------------------
// Edit tags dialog controls
ET_TitleCheck,
ET_ArtistCheck,
ET_AlbumCheck,
ET_GenreCheck,
ET_CommentsCheck,
ET_TypeCheck,
ET_CustomTag,
};
}}

119
src/Utility/Event.cpp Normal file
View File

@ -0,0 +1,119 @@
/* 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 "Utility/Event.hpp"
namespace SampleHive
{
cLoopPointsEvent::cLoopPointsEvent(wxEventType eventType, int winId)
: wxCommandEvent(eventType, winId)
{
}
cLoopPointsEvent::~cLoopPointsEvent()
{
}
wxDEFINE_EVENT(SH_EVT_LOOP_POINTS_UPDATED, cLoopPointsEvent);
wxDEFINE_EVENT(SH_EVT_LOOP_POINTS_CLEAR, cLoopPointsEvent);
wxDEFINE_EVENT(SH_EVT_LOOP_AB_BUTTON_VALUE_CHANGE, cLoopPointsEvent);
// MediaEvent::MediaEvent(wxEventType eventType, int winId)
// : wxCommandEvent(eventType, winId)
// {
// }
// MediaEvent::~MediaEvent()
// {
// }
// wxDEFINE_EVENT(SH_EVT_MEDIA_STATUS_UPDATED, MediaEvent);
cStatusBarStatusEvent::cStatusBarStatusEvent(wxEventType eventType, int winId)
: wxCommandEvent(eventType, winId)
{
}
cStatusBarStatusEvent::~cStatusBarStatusEvent()
{
}
wxDEFINE_EVENT(SH_EVT_STATUSBAR_STATUS_PUSH, cStatusBarStatusEvent);
wxDEFINE_EVENT(SH_EVT_STATUSBAR_STATUS_POP, cStatusBarStatusEvent);
wxDEFINE_EVENT(SH_EVT_STATUSBAR_STATUS_SET, cStatusBarStatusEvent);
cInfoBarMessageEvent::cInfoBarMessageEvent(wxEventType eventType, int winId)
: wxCommandEvent(eventType, winId)
{
}
cInfoBarMessageEvent::~cInfoBarMessageEvent()
{
}
wxDEFINE_EVENT(SH_EVT_INFOBAR_MESSAGE_SHOW, cInfoBarMessageEvent);
cTimerEvent::cTimerEvent(wxEventType eventType, int winId)
: wxCommandEvent(eventType, winId)
{
}
cTimerEvent::~cTimerEvent()
{
}
wxDEFINE_EVENT(SH_EVT_TIMER_STOP, cTimerEvent);
cCallFunctionEvent::cCallFunctionEvent(wxEventType eventType, int winId)
: wxCommandEvent(eventType, winId)
{
}
cCallFunctionEvent::~cCallFunctionEvent()
{
}
wxDEFINE_EVENT(SH_EVT_CALL_FUNC_PLAY, cCallFunctionEvent);
cWaveformUpdateEvent::cWaveformUpdateEvent(wxEventType eventType, int winId)
: wxCommandEvent(eventType, winId)
{
}
cWaveformUpdateEvent::~cWaveformUpdateEvent()
{
}
wxDEFINE_EVENT(SH_EVT_UPDATE_WAVEFORM, cWaveformUpdateEvent);
}

167
src/Utility/Event.hpp Normal file
View File

@ -0,0 +1,167 @@
/* 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 <utility>
#include <wx/event.h>
namespace SampleHive
{
class cLoopPointsEvent : public wxCommandEvent
{
public:
cLoopPointsEvent(wxEventType eventType, int winId);
~cLoopPointsEvent();
public:
virtual wxEvent* Clone() const { return new cLoopPointsEvent(*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, cLoopPointsEvent);
wxDECLARE_EVENT(SH_EVT_LOOP_POINTS_CLEAR, cLoopPointsEvent);
wxDECLARE_EVENT(SH_EVT_LOOP_AB_BUTTON_VALUE_CHANGE, cLoopPointsEvent);
// class cMediaEvent : public wxCommandEvent
// {
// public:
// cMediaEvent(wxEventType eventType, int winId);
// ~cMediaEvent();
// public:
// virtual wxEvent* Clone() const { return new cMediaEvent(*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, cMediaEvent);
class cStatusBarStatusEvent : public wxCommandEvent
{
public:
cStatusBarStatusEvent(wxEventType eventType, int winId);
~cStatusBarStatusEvent();
public:
virtual wxEvent* Clone() const { return new cStatusBarStatusEvent(*this); }
public:
std::pair<wxString, int> GetPushMessageAndSection() const { return { m_Msg, m_PushSection }; }
void SetPushMessageAndSection(std::pair<const wxString&, int> status)
{ m_Msg = status.first; m_PushSection = status.second; }
std::pair<wxString, int> GetStatusTextAndSection() const { return { m_Text, m_SetSection }; }
void SetStatusTextAndSection(std::pair<const wxString&, int> status)
{ m_Text = status.first, m_SetSection = status.second; }
int GetPopMessageSection() const { return m_PopSection; }
void SetPopMessageSection(int section) { m_PopSection = section; }
private:
wxString m_Msg, m_Text;
int m_PushSection, m_PopSection, m_SetSection;
};
wxDECLARE_EVENT(SH_EVT_STATUSBAR_STATUS_PUSH, cStatusBarStatusEvent);
wxDECLARE_EVENT(SH_EVT_STATUSBAR_STATUS_POP, cStatusBarStatusEvent);
wxDECLARE_EVENT(SH_EVT_STATUSBAR_STATUS_SET, cStatusBarStatusEvent);
class cInfoBarMessageEvent : public wxCommandEvent
{
public:
cInfoBarMessageEvent(wxEventType eventType, int winId);
~cInfoBarMessageEvent();
public:
virtual wxEvent* Clone() const { return new cInfoBarMessageEvent(*this); }
public:
std::pair<wxString, int> GetInfoBarMessage() const { return { m_Msg, m_Mode }; }
void SetInfoBarMessage(std::pair<const wxString&, int> info)
{ m_Msg = info.first; m_Mode = info.second; }
private:
wxString m_Msg;
int m_Mode;
};
wxDECLARE_EVENT(SH_EVT_INFOBAR_MESSAGE_SHOW, cInfoBarMessageEvent);
class cTimerEvent : public wxCommandEvent
{
public:
cTimerEvent(wxEventType eventType, int winId);
~cTimerEvent();
public:
virtual wxEvent* Clone() const { return new cTimerEvent(*this); }
};
wxDECLARE_EVENT(SH_EVT_TIMER_STOP, cTimerEvent);
class cCallFunctionEvent : public wxCommandEvent
{
public:
cCallFunctionEvent(wxEventType eventType, int winId);
~cCallFunctionEvent();
public:
virtual wxEvent* Clone() const { return new cCallFunctionEvent(*this); }
public:
wxString GetSlection() const { return m_Selection; }
bool GetAutoplayValue() const { return m_bCheckAutoplay; }
void SetSelection(const wxString& selection) { m_Selection = selection; }
void SetAutoplayValue(bool autoplay) { m_bCheckAutoplay = autoplay; }
private:
wxString m_Selection;
bool m_bCheckAutoplay;
};
wxDECLARE_EVENT(SH_EVT_CALL_FUNC_PLAY, cCallFunctionEvent);
class cWaveformUpdateEvent : public wxCommandEvent
{
public:
cWaveformUpdateEvent(wxEventType eventType, int winId);
~cWaveformUpdateEvent();
public:
virtual wxEvent* Clone() const { return new cWaveformUpdateEvent(*this); }
};
wxDECLARE_EVENT(SH_EVT_UPDATE_WAVEFORM, cWaveformUpdateEvent);
}

115
src/Utility/HiveData.hpp Normal file
View File

@ -0,0 +1,115 @@
/* 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 "wx/dataview.h"
#include "wx/string.h"
#include "wx/treectrl.h"
#include "wx/treebase.h"
#include "wx/variant.h"
#include "wx/vector.h"
#include <string>
namespace SampleHive {
class cHiveData
{
private:
cHiveData() = default;
public:
cHiveData(const cHiveData&) = delete;
cHiveData& operator=(const cHiveData) = delete;
public:
static cHiveData& Get()
{
static cHiveData s_HiveData;
return s_HiveData;
}
public:
// ===============================================================
// HivesPanel functions
void InitHiveData(wxDataViewListCtrl& listCtrl, wxDataViewTreeCtrl& hives, wxDataViewItem favoriteHive,
wxTreeCtrl& trash, wxTreeItemId trashRoot)
{
m_pListCtrl = &listCtrl;
m_FavoriteHive = favoriteHive;
m_pHives = &hives;
m_TrashRoot = trashRoot;
m_pTrash = &trash;
}
inline wxDataViewTreeCtrl& GetHivesObj() { return *m_pHives; }
inline wxDataViewItem& GetFavoritesHive() { return m_FavoriteHive; }
wxString GetHiveItemText(bool ofFavHive = false, wxDataViewItem hive = wxDataViewItem(0))
{
wxString item_text;
if (ofFavHive)
item_text = m_pHives->GetItemText(m_FavoriteHive);
else
item_text = m_pHives->GetItemText(hive);
return item_text;
}
inline wxDataViewItem GetHiveItemSelection() { return m_pHives->GetSelection(); }
inline bool IsHiveItemContainer(wxDataViewItem& hiveItem) { return m_pHives->IsContainer(hiveItem); }
inline int GetHiveChildCount(wxDataViewItem& root) { return m_pHives->GetChildCount(root); }
inline wxDataViewItem GetHiveNthChild(wxDataViewItem& root, int pos) { return m_pHives->GetNthChild(root, pos); }
inline void HiveAppendItem(wxDataViewItem& hiveItem, wxString name) { m_pHives->AppendItem(hiveItem, name); }
inline void HiveDeleteItem(wxDataViewItem& hiveItem) { m_pHives->DeleteItem(hiveItem); }
// ===============================================================
// TrashPanel functions
inline wxTreeCtrl& GetTrashObj() { return *m_pTrash; }
inline wxTreeItemId& GetTrashRoot() { return m_TrashRoot; }
inline void TrashAppendItem(const wxTreeItemId& parent, const wxString& text) { m_pTrash->AppendItem(parent, text); }
// ===============================================================
// ListCtrl functions
inline wxDataViewListCtrl& GetListCtrlObj() { return *m_pListCtrl; }
inline int GetListCtrlSelections(wxDataViewItemArray& items) { return m_pListCtrl->GetSelections(items); }
inline int GetListCtrlRowFromItem(wxDataViewItemArray& items, int index) { return m_pListCtrl->ItemToRow(items[index]); }
inline int GetListCtrlSelectedRow() { return m_pListCtrl->GetSelectedRow(); }
inline wxDataViewItem GetListCtrlItemFromRow(int row) { return m_pListCtrl->RowToItem(row); }
inline wxString GetListCtrlTextValue(unsigned int row, unsigned int col) { return m_pListCtrl->GetTextValue(row, col); }
inline int GetListCtrlItemCount() { return m_pListCtrl->GetItemCount(); }
inline void ListCtrlAppendItem(const wxVector<wxVariant>& values) { m_pListCtrl->AppendItem(values); }
inline void ListCtrlSetVariant(const wxVariant& variant, unsigned int row, unsigned int col)
{ m_pListCtrl->SetValue(variant, row, col); }
inline void ListCtrlUnselectAllItems() { m_pListCtrl->UnselectAll(); }
inline void ListCtrlSelectRow(int row) { m_pListCtrl->SelectRow(row); }
inline void ListCtrlEnsureVisible(const wxDataViewItem& item) { m_pListCtrl->EnsureVisible(item); }
inline void ListCtrlDeleteItem(unsigned int row) { m_pListCtrl->DeleteItem(row); }
inline void ListCtrlDeleteAllItems() { m_pListCtrl->DeleteAllItems(); }
private:
wxDataViewListCtrl* m_pListCtrl = nullptr;
wxDataViewItem m_FavoriteHive;
wxDataViewTreeCtrl* m_pHives = nullptr;
wxTreeCtrl* m_pTrash = nullptr;
wxTreeItemId m_TrashRoot;
};
}

46
src/Utility/Log.cpp Normal file
View File

@ -0,0 +1,46 @@
/* 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 "Log.hpp"
#include <iostream>
#include "spdlog/sinks/stdout_color_sinks.h"
namespace SampleHive {
std::shared_ptr<spdlog::logger> cLog::s_pLogger;
void cLog::InitLogger(const std::string& logger)
{
spdlog::set_pattern("%^[%-T] [%-n] [%l]: %v %@%$");
try
{
s_pLogger = spdlog::stdout_color_mt(logger);
s_pLogger->set_level(spdlog::level::trace);
}
catch (const spdlog::spdlog_ex& ex)
{
std::cout << "Logger initialization failed: " << ex.what() << std::endl;
}
}
}

57
src/Utility/Log.hpp Normal file
View File

@ -0,0 +1,57 @@
/* 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 <memory>
#include <SampleHiveConfig.hpp>
#ifdef SH_BUILD_DEBUG
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#else
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_OFF
#endif
#include <spdlog/spdlog.h>
namespace SampleHive {
class cLog
{
public:
static void InitLogger(const std::string& logger);
public:
inline static std::shared_ptr<spdlog::logger>& GetLogger() { return s_pLogger; }
private:
static std::shared_ptr<spdlog::logger> s_pLogger;
};
// Log macros
#define SH_LOG_TRACE(...) SPDLOG_LOGGER_TRACE(::SampleHive::cLog::GetLogger(), __VA_ARGS__)
#define SH_LOG_INFO(...) SPDLOG_LOGGER_INFO(::SampleHive::cLog::GetLogger(), __VA_ARGS__)
#define SH_LOG_WARN(...) SPDLOG_LOGGER_WARN(::SampleHive::cLog::GetLogger(), __VA_ARGS__)
#define SH_LOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(::SampleHive::cLog::GetLogger(), __VA_ARGS__)
#define SH_LOG_ERROR(...) SPDLOG_LOGGER_ERROR(::SampleHive::cLog::GetLogger(), __VA_ARGS__)
#define SH_LOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(::SampleHive::cLog::GetLogger(), __VA_ARGS__)
}

55
src/Utility/Paths.hpp Normal file
View File

@ -0,0 +1,55 @@
/* 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 "SampleHiveConfig.hpp"
namespace SampleHive {
// Path to all the assets
#define ICON_HIVE_16px SAMPLEHIVE_DATADIR "/icons/icon-hive_16x16.png"
#define ICON_HIVE_24px SAMPLEHIVE_DATADIR "/icons/icon-hive_24x24.png"
#define ICON_HIVE_32px SAMPLEHIVE_DATADIR "/icons/icon-hive_32x32.png"
#define ICON_HIVE_64px SAMPLEHIVE_DATADIR "/icons/icon-hive_64x64.png"
#define ICON_HIVE_128px SAMPLEHIVE_DATADIR "/icons/icon-hive_128x128.png"
#define ICON_HIVE_256px SAMPLEHIVE_DATADIR "/icons/icon-hive_256x256.png"
#define ICON_STAR_FILLED_16px SAMPLEHIVE_DATADIR "/icons/icon-star_filled_16x16.png"
#define ICON_STAR_EMPTY_16px SAMPLEHIVE_DATADIR "/icons/icon-star_empty_16x16.png"
#define ICON_PLAY_DARK_16px SAMPLEHIVE_DATADIR "/icons/icon-play-dark_16x16.png"
#define ICON_STOP_DARK_16px SAMPLEHIVE_DATADIR "/icons/icon-stop-dark_16x16.png"
#define ICON_AB_DARK_16px SAMPLEHIVE_DATADIR "/icons/icon-ab-dark_16x16.png"
#define ICON_LOOP_DARK_16px SAMPLEHIVE_DATADIR "/icons/icon-loop-dark_16x16.png"
#define ICON_MUTE_DARK_16px SAMPLEHIVE_DATADIR "/icons/icon-mute-dark_16x16.png"
#define ICON_PLAY_LIGHT_16px SAMPLEHIVE_DATADIR "/icons/icon-play-light_16x16.png"
#define ICON_STOP_LIGHT_16px SAMPLEHIVE_DATADIR "/icons/icon-stop-light_16x16.png"
#define ICON_AB_LIGHT_16px SAMPLEHIVE_DATADIR "/icons/icon-ab-light_16x16.png"
#define ICON_LOOP_LIGHT_16px SAMPLEHIVE_DATADIR "/icons/icon-loop-light_16x16.png"
#define ICON_MUTE_LIGHT_16px SAMPLEHIVE_DATADIR "/icons/icon-mute-light_16x16.png"
#define SPLASH_LOGO SAMPLEHIVE_DATADIR "/logo/logo-samplehive_768x432.png"
// Path to useful directories and files
#define USER_HOME_DIR wxGetUserHome()
#define APP_CONFIG_DIR USER_HOME_DIR + "/.config/SampleHive"
#define APP_DATA_DIR USER_HOME_DIR + "/.local/share/SampleHive"
#define CONFIG_FILEPATH APP_CONFIG_DIR + "/config.yaml"
#define DATABASE_FILEPATH APP_DATA_DIR "/sample.hive"
}

View File

@ -26,18 +26,20 @@
* @copyright GNU GPL v3
*/
#include "Sample.hpp"
#include "Utility/Sample.hpp"
///Default Constructor, Creates an empty sample profile
Sample::Sample(){}
Sample::Sample()
{
}
///Overloaded Constructor, Creates a sample profile with supplied data. @see Set()
Sample::Sample(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length,
int sampleRate, int bitrate, const std::string& path, int trashed)
const std::string& samplePack, const std::string& type, int channels, int bpm,
int length, int sampleRate, int bitrate, const std::string& path, int trashed)
{
Set(favorite, filename, fileExtension, samplePack, type,
channels, length, sampleRate, bitrate, path, trashed);
Set(favorite, filename, fileExtension, samplePack, type, channels, bpm, length, sampleRate, bitrate, path, trashed);
}
///Clears all sample data
@ -45,6 +47,7 @@ void Sample::Clear()
{
m_Favorite = 0;
m_Channels = 0;
m_BPM = 0;
m_Length = 0;
m_SampleRate = 0;
m_Bitrate = 0;
@ -56,21 +59,9 @@ void Sample::Clear()
m_Path = "";
}
// int Sample::GetFavorite() { return m_Favorite; }
// int Sample::GetChannels() { return m_Channels; }
// int Sample::GetLength() { return m_Length; }
// int Sample::GetSampleRate() { return m_SampleRate; }
// int Sample::GetBitrate() { return m_Bitrate; }
// int Sample::GetTrashed () { return m_Trashed; }
// std::string Sample::GetFilename() { return m_Filename; }
// std::string Sample::GetFileExtension() { return m_FileExtension; }
// std::string Sample::GetSamplePack() { return m_SamplePack; }
// std::string Sample::GetType() { return m_Type; }
// std::string Sample::GetPath() { return m_Path; }
void Sample::Set(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length,
int sampleRate, int bitrate, const std::string& path, int trashed)
const std::string& samplePack, const std::string& type, int channels, int bpm,
int length, int sampleRate, int bitrate, const std::string& path, int trashed)
{
m_Favorite = favorite;
m_Filename = filename;
@ -78,21 +69,10 @@ void Sample::Set(int favorite, const std::string& filename, const std::string& f
m_SamplePack = samplePack;
m_Type = type;
m_Channels = channels;
m_BPM = bpm;
m_Length = length;
m_SampleRate = sampleRate;
m_Bitrate = bitrate;
m_Path = path;
m_Trashed = trashed;
}
// void Sample::SetFavorite(int favorite) { m_Favorite = favorite; }
// void Sample::SetChannels(int channels) { m_Channels = channels; }
// void Sample::SetLength(int length) { m_Length = length; }
// void Sample::SetSampleRate(int sampleRate) { m_SampleRate = sampleRate; }
// void Sample::SetBitrate(int bitrate) { m_Bitrate = bitrate; }
// void Sample::SetTrashed (int trashed) { m_Trashed = trashed; }
// void Sample::SetFilename(std::string filename) { m_Filename = filename; }
// void Sample::SetFileExtension(std::string fileExtension) { m_FileExtension = fileExtension; }
// void Sample::SetSamplePack(std::string samplePack) { m_SamplePack = samplePack; }
// void Sample::SetType(std::string type) { m_Type = type; }
// void Sample::SetPath(std::string path) { m_Path = path; }
}

View File

@ -26,8 +26,7 @@
* @copyright GNU GPL v3
*/
#ifndef _SAMPLE_HPP__
#define _SAMPLE_HPP__
#pragma once
#include <string>
@ -40,15 +39,15 @@ class Sample
{
public:
Sample();
Sample(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length,
int sampleRate, int bitrate, const std::string& path, int trashed);
const std::string& samplePack, const std::string& type, int channels, int bpm,
int length, int sampleRate, int bitrate, const std::string& path, int trashed);
private:
// -------------------------------------------------------------------
int m_Favorite = 0;
int m_Channels = 0;
int m_BPM = 0;
int m_Length = 0;
int m_SampleRate = 0;
int m_Bitrate = 0;
@ -62,20 +61,9 @@ class Sample
public:
// -------------------------------------------------------------------
// Getters
// int GetFavorite();
// int GetChannels();
// int GetLength();
// int GetSampleRate();
// int GetBitrate();
// int GetTrashed ();
// std::string GetFilename();
// std::string GetFileExtension();
// std::string GetSamplePack();
// std::string GetType();
// std::string GetPath();
int GetFavorite() const { return m_Favorite; }
int GetChannels() const { return m_Channels; }
int GetBPM() const { return m_BPM; }
int GetLength() const { return m_Length; }
int GetSampleRate() const { return m_SampleRate; }
int GetBitrate() const { return m_Bitrate; }
@ -86,30 +74,15 @@ class Sample
std::string GetType() const { return m_Type; }
std::string GetPath() const { return m_Path; }
// -------------------------------------------------------------------
// Clear sample data
void Clear();
// -------------------------------------------------------------------
// Setters
void Set(int favorite, const std::string& filename, const std::string& fileExtension,
const std::string& samplePack, const std::string& type, int channels, int length,
int sampleRate, int bitrate, const std::string& path, int trashed);
// void SetFavorite(int favorite);
// void SetChannels(int channels);
// void SetLength(int length);
// void SetSampleRate(int sampleRate);
// void SetBitrate(int bitrate);
// void SetTrashed(int trashed);
// void SetFilename(std::string filename);
// void SetFileExtension(std::string fileExtension);
// void SetSamplePack(std::string samplePack);
// void SetType(std::string type);
// void SetPath(std::string path);
const std::string& samplePack, const std::string& type, int channels, int bpm,
int length, int sampleRate, int bitrate, const std::string& path, int trashed);
void SetFavorite(int favorite) { m_Favorite = favorite; }
void SetChannels(int channels) { m_Channels = channels; }
void SetBPM(int bpm) { m_BPM = bpm; }
void SetLength(int length) { m_Length = length; }
void SetSampleRate(int sampleRate) { m_SampleRate = sampleRate; }
void SetBitrate(int bitrate) { m_Bitrate = bitrate; }
@ -119,6 +92,8 @@ class Sample
void SetSamplePack(const std::string& samplePack) { m_SamplePack = samplePack; }
void SetType(const std::string& type) { m_Type = type; }
void SetPath(const std::string& path) { m_Path = path; }
};
#endif
// -------------------------------------------------------------------
// Clear sample data
void Clear();
};

921
src/Utility/Serialize.cpp Normal file
View File

@ -0,0 +1,921 @@
/* 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 "Utility/Serialize.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include <fstream>
#include <sstream>
#include <wx/colour.h>
#include <wx/filename.h>
#include <wx/settings.h>
#include <yaml-cpp/emittermanip.h>
#include <yaml-cpp/node/parse.h>
namespace SampleHive {
cSerializer::cSerializer()
{
std::ifstream ifstrm(static_cast<std::string>(CONFIG_FILEPATH));
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
std::string system_font_face = font.GetFaceName().ToStdString();
int system_font_size = font.GetPointSize();
wxColour colour = "#FE9647";
std::string dir = wxGetHomeDir().ToStdString();
// Initialize the logger
// SampleHive::Log::InitLogger("Serializer");
if (!ifstrm)
{
SH_LOG_INFO("Genrating configuration file..");
m_Emitter << YAML::Comment("This is the configuration file for SampleHive,"
"feel free to edit the file as needed");
m_Emitter << YAML::Newline;
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Newline << YAML::Key << "Window";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Width" << YAML::Value << 1280;
m_Emitter << YAML::Key << "Height" << YAML::Value << 720;
m_Emitter << YAML::Key << "TopSplitterSashPos" << YAML::Value << 200;
m_Emitter << YAML::Key << "BottomSplitterSashPos" << YAML::Value << 300;
m_Emitter << YAML::Key << "ShowMenuBar" << YAML::Value << true;
m_Emitter << YAML::Key << "ShowStatusBar" << YAML::Value << true;
m_Emitter << YAML::EndMap << YAML::Newline;
m_Emitter << YAML::Newline << YAML::Key << "General";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "DemoMode" << YAML::Value << false;
m_Emitter << YAML::EndMap << YAML::Newline;
m_Emitter << YAML::Newline << YAML::Key << "Media";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Autoplay" << YAML::Value << false;
m_Emitter << YAML::Key << "Loop" << YAML::Value << false;
m_Emitter << YAML::Key << "Muted" << YAML::Value << false;
m_Emitter << YAML::Key << "Volume" << YAML::Value << 100;
m_Emitter << YAML::EndMap << YAML::Newline;
m_Emitter << YAML::Newline << YAML::Key << "Display";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Font";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Family" << YAML::Value << system_font_face;
m_Emitter << YAML::Key << "Size" << YAML::Value << system_font_size;
m_Emitter << YAML::EndMap;
m_Emitter << YAML::Key << "Waveform";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "Colour" << YAML::Value << colour.GetAsString().ToStdString();
m_Emitter << YAML::EndMap;
m_Emitter << YAML::Key << "Splash";
m_Emitter << YAML::BeginMap;
m_Emitter << YAML::Key << "ShowSplashOnStartup" << YAML::Value << true;
m_Emitter << YAML::EndMap;
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;
m_Emitter << YAML::Key << "Directory" << YAML::Value << dir;
m_Emitter << YAML::Key << "FollowSymLink" << YAML::Value << false;
m_Emitter << YAML::Key << "RecursiveImport" << YAML::Value << false;
m_Emitter << YAML::Key << "ShowFileExtension" << YAML::Value << true;
m_Emitter << YAML::Key << "DoubleClickToPlay" << YAML::Value << false;
m_Emitter << YAML::EndMap << YAML::Newline;
m_Emitter << YAML::EndMap;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << m_Emitter.c_str();
SH_LOG_INFO("Generated {} successfully!", static_cast<std::string>(CONFIG_FILEPATH));
}
}
cSerializer::~cSerializer()
{
}
void cSerializer::SerializeWinSize(int w, int h)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto win = config["Window"])
{
win["Width"] = w;
win["Height"] = h;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store window size values.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
WindowSize cSerializer::DeserializeWinSize() const
{
int width = 800, height = 600;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (!config["Window"])
{
return { width, height };
}
if (auto win = config["Window"])
{
height = win["Height"].as<int>();
width = win["Width"].as<int>();
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
SH_LOG_INFO("Window size: {}, {}", width, height);
return { width, height };
}
void cSerializer::SerializeShowMenuAndStatusBar(std::string key, bool value)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto bar = config["Window"])
{
if (key == "menubar")
bar["ShowMenuBar"] = value;
if (key == "statusbar")
bar["ShowStatusBar"] = value;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
SH_LOG_ERROR("Error! Cannot store show bar values.");
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
bool cSerializer::DeserializeShowMenuAndStatusBar(std::string key) const
{
bool show = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto bar = config["Window"])
{
if (key == "menubar")
show = bar["ShowMenuBar"].as<bool>();
if (key == "statusbar")
show = bar["ShowStatusBar"].as<bool>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch show bar values.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return show;
}
void cSerializer::SerializeSplitterSashPos(std::string key, int pos)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto sash = config["Window"])
{
if (key == "top")
sash["TopSplitterSashPos"] = pos;
if (key == "bottom")
sash["BottomSplitterSashPos"] = pos;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
SH_LOG_ERROR("Error! Cannot store sash pos values.");
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
int cSerializer::DeserializeSplitterSashPos(std::string key) const
{
int pos = 0;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto bar = config["Window"])
{
if (key == "top")
pos = bar["TopSplitterSashPos"].as<int>();
if (key == "bottom")
pos = bar["BottomSplitterSashPos"].as<int>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch sash pos values.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return pos;
}
void cSerializer::SerializeMediaOptions(std::string key, bool value)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto media = config["Media"])
{
if (key == "autoplay")
media["Autoplay"] = value;
if (key == "loop")
media["Loop"] = value;
if (key == "muted")
media["Muted"] = value;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
SH_LOG_ERROR("Error! Cannot store media values.");
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
bool cSerializer::DeserializeMediaOptions(std::string key) const
{
bool control = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto media = config["Media"])
{
if (key == "autoplay")
control = media["Autoplay"].as<bool>();
if (key == "loop")
control = media["Loop"].as<bool>();
if (key == "muted")
control = media["Muted"].as<bool>();
}
else
SH_LOG_ERROR("Error! Cannot fetch media values.");
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
SH_LOG_INFO("{}: {}", key, control ? "enabled" : "disabled");
return control;
}
void cSerializer::SerializeMediaVolume(int volume)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto media = config["Media"])
{
media["Volume"] = volume;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
SH_LOG_ERROR("Error! Cannot store volume values.");
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
int cSerializer::DeserializeMediaVolume() const
{
int volume = 0;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto media = config["Media"])
volume = media["Volume"].as<int>();
else
SH_LOG_ERROR("Error! Cannot fetch volume values.");
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
SH_LOG_INFO("Volume: {}", volume);
return volume;
}
void cSerializer::SerializeFontSettings(wxFont& font)
{
YAML::Emitter out;
std::string font_face = font.GetFaceName().ToStdString();
int font_size = font.GetPointSize();
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
auto display = config["Display"];
if (auto fontSetting = display["Font"])
{
fontSetting["Family"] = font_face;
fontSetting["Size"] = font_size;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store font values.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
wxFont cSerializer::DeserializeFontSettings() const
{
wxFont font;
wxString face;
int size = 0 ;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
auto display = config["Display"];
if (auto font_setting = display["Font"])
{
face = font_setting["Family"].as<std::string>();
size = font_setting["Size"].as<int>();
font.SetFaceName(face);
font.SetPointSize(size);
}
else
{
SH_LOG_ERROR("Error! Cannot fetch font values.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return font;
}
void cSerializer::SerializeWaveformColour(wxColour& colour)
{
YAML::Emitter out;
std::string colour_string = colour.GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
auto display = config["Display"];
if (auto waveform = display["Waveform"])
{
waveform["Colour"] = colour_string;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store waveform colour.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
wxColour cSerializer::DeserializeWaveformColour() const
{
std::string colour;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
auto display = config["Display"];
if (auto waveform = display["Waveform"])
{
colour = waveform["Colour"].as<std::string>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch waveform colour.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return static_cast<wxString>(colour);
}
void cSerializer::SerializeShowSplash(bool value)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
auto display = config["Display"];
if (auto splash = display["Splash"])
{
splash["ShowSplashOnStartup"] = value;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store show splash value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
bool cSerializer::DeserializeShowSplash() const
{
bool show = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
auto display = config["Display"];
if (auto splash = display["Splash"])
{
show = splash["ShowSplashOnStartup"].as<bool>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch show splash value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return show;
}
void cSerializer::SerializeAutoImport(bool autoImport, const std::string& importDir)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto autoImportInfo = config["Collection"])
{
autoImportInfo["AutoImport"] = autoImport;
autoImportInfo["Directory"] = importDir;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store import dir values.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
ImportDirInfo cSerializer::DeserializeAutoImport() const
{
wxString dir;
bool auto_import = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto autoImportInfo = config["Collection"])
{
auto_import = autoImportInfo["AutoImport"].as<bool>();
dir = autoImportInfo["Directory"].as<std::string>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch import dir values.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return { auto_import, dir };
}
void cSerializer::SerializeFollowSymLink(bool followSymLinks)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto followSymLinks = config["Collection"])
{
followSymLinks["FollowSymLink"] = followSymLinks;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store follow symbolic links value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
bool cSerializer::DeserializeFollowSymLink() const
{
bool follow_sym_links = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto followSymLinks = config["Collection"])
{
follow_sym_links = followSymLinks["FollowSymLink"].as<bool>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch follow symbolic links value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return follow_sym_links;
}
void cSerializer::SerializeRecursiveImport(bool recursiveImport)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto recursive = config["Collection"])
{
recursive["RecursiveImport"] = recursiveImport;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store recursive import value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
bool cSerializer::DeserializeRecursiveImport() const
{
bool recursive_import = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto recursive = config["Collection"])
{
recursive_import = recursive["RecursiveImport"].as<bool>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch recursive import value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return recursive_import;
}
void cSerializer::SerializeShowFileExtension(bool showExtension)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto fileExtensionInfo = config["Collection"])
{
fileExtensionInfo["ShowFileExtension"] = showExtension;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store show file extension value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
bool cSerializer::DeserializeShowFileExtension() const
{
bool show_extension = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto fileExtensionInfo = config["Collection"])
{
show_extension = fileExtensionInfo["ShowFileExtension"].as<bool>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch show file extension value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return show_extension;
}
void cSerializer::SerializeDoubleClickToPlay(bool enableDoubleClick)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto doubleClickValue = config["Collection"])
{
doubleClickValue["DoubleClickToPlay"] = enableDoubleClick;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store show enable double click to play value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
bool cSerializer::DeserializeDoubleClickToPlay() const
{
bool double_click_to_play = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto doubleClickValue = config["Collection"])
{
double_click_to_play = doubleClickValue["DoubleClickToPlay"].as<bool>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch double click to play value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return double_click_to_play;
}
void cSerializer::SerializeDemoMode(bool showDemoMode)
{
YAML::Emitter out;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto general = config["General"])
{
general["DemoMode"] = showDemoMode;
out << config;
std::ofstream ofstrm(static_cast<std::string>(CONFIG_FILEPATH));
ofstrm << out.c_str();
}
else
{
SH_LOG_ERROR("Error! Cannot store show demo mode value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
}
bool cSerializer::DeserializeDemoMode() const
{
bool show_demo_mode = false;
try
{
YAML::Node config = YAML::LoadFile(static_cast<std::string>(CONFIG_FILEPATH));
if (auto general = config["General"])
{
show_demo_mode = general["DemoMode"].as<bool>();
}
else
{
SH_LOG_ERROR("Error! Cannot fetch show demo mode value.");
}
}
catch (const YAML::ParserException& ex)
{
SH_LOG_ERROR(ex.what());
}
return show_demo_mode;
}
}

125
src/Utility/Serialize.hpp Normal file
View File

@ -0,0 +1,125 @@
/* 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 <string>
#include <wx/checkbox.h>
#include <wx/dataview.h>
#include <wx/font.h>
#include <wx/string.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/treebase.h>
#include <wx/treectrl.h>
#include <yaml-cpp/yaml.h>
#include <yaml-cpp/emitter.h>
#include <yaml-cpp/emittermanip.h>
#include <yaml-cpp/exceptions.h>
#include <yaml-cpp/node/node.h>
#include <yaml-cpp/node/parse.h>
#include <yaml-cpp/null.h>
#include <yaml-cpp/emittermanip.h>
typedef std::pair<int, int> WindowSize;
// typedef std::pair<wxString, int> FontType;
typedef std::pair<bool, wxString> ImportDirInfo;
namespace SampleHive {
class cSerializer
{
public:
cSerializer();
~cSerializer();
public:
// -------------------------------------------------------------------
// Window size
void SerializeWinSize(int w, int h);
WindowSize DeserializeWinSize() const;
// -------------------------------------------------------------------
// Menu and status bar
void SerializeShowMenuAndStatusBar(std::string key, bool value);
bool DeserializeShowMenuAndStatusBar(std::string key) const;
// -------------------------------------------------------------------
// Splitter window sash pos
void SerializeSplitterSashPos(std::string key, int pos);
int DeserializeSplitterSashPos(std::string key) const;
// -------------------------------------------------------------------
// Browser controls
void SerializeMediaOptions(std::string key, bool value);
bool DeserializeMediaOptions(std::string key) const;
void SerializeMediaVolume(int volume);
int DeserializeMediaVolume() const;
// -------------------------------------------------------------------
// Display settings
void SerializeFontSettings(wxFont& font);
wxFont DeserializeFontSettings() const;
// -------------------------------------------------------------------
// Waveform colour
void SerializeWaveformColour(wxColour& colour);
wxColour DeserializeWaveformColour() const;
// -------------------------------------------------------------------
// Splash screen
void SerializeShowSplash(bool value);
bool DeserializeShowSplash() const;
// -------------------------------------------------------------------
// Auto import settings
void SerializeAutoImport(bool autoImport, const std::string& importDir);
ImportDirInfo DeserializeAutoImport() const;
// -------------------------------------------------------------------
// Follow symbolic links
void SerializeFollowSymLink(bool followSymLink);
bool DeserializeFollowSymLink() const;
// -------------------------------------------------------------------
// Recursive import
void SerializeRecursiveImport(bool recursiveImport);
bool DeserializeRecursiveImport() const;
// -------------------------------------------------------------------
// Show file extension
void SerializeShowFileExtension(bool showExtension);
bool DeserializeShowFileExtension() const;
// Enable double click to play
void SerializeDoubleClickToPlay(bool showExtension);
bool DeserializeDoubleClickToPlay() const;
// Demo mode
void SerializeDemoMode(bool showDemoMode);
bool DeserializeDemoMode() const;
private:
// -------------------------------------------------------------------
YAML::Emitter m_Emitter;
};
}

150
src/Utility/Signal.cpp Normal file
View File

@ -0,0 +1,150 @@
/* 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 "Utility/Signal.hpp"
#include "Utility/Log.hpp"
#include "Utility/Event.hpp"
namespace SampleHive {
void cSignal::SendInfoBarMessage(const wxString& msg, int mode, wxWindow& window, bool isDialog)
{
SampleHive::cInfoBarMessageEvent event(SampleHive::SH_EVT_INFOBAR_MESSAGE_SHOW, window.GetId());
event.SetEventObject(&window);
event.SetInfoBarMessage({ msg, mode });
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendPushStatusBarStatus(const wxString& msg, int section, wxWindow& window, bool isDialog)
{
SampleHive::cStatusBarStatusEvent event(SampleHive::SH_EVT_STATUSBAR_STATUS_PUSH, window.GetId());
event.SetEventObject(&window);
event.SetPushMessageAndSection({ msg, section });
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendPopStatusBarStatus(int section, wxWindow& window, bool isDialog)
{
SampleHive::cStatusBarStatusEvent event(SampleHive::SH_EVT_STATUSBAR_STATUS_POP, window.GetId());
event.SetEventObject(&window);
event.SetPopMessageSection(section);
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendSetStatusBarStatus(const wxString& text, int section, wxWindow& window, bool isDialog)
{
SampleHive::cStatusBarStatusEvent event(SampleHive::SH_EVT_STATUSBAR_STATUS_SET, window.GetId());
event.SetEventObject(&window);
event.SetStatusTextAndSection({ text, section });
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendCallFunctionPlay(const wxString& selection, bool checkAutoplay, wxWindow& window, bool isDialog)
{
SampleHive::cCallFunctionEvent event(SampleHive::SH_EVT_CALL_FUNC_PLAY, window.GetId());
event.SetEventObject(&window);
event.SetSelection(selection);
event.SetAutoplayValue(checkAutoplay);
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendTimerStopStatus(wxWindow& window, bool isDialog)
{
SampleHive::cTimerEvent event(SampleHive::SH_EVT_TIMER_STOP, window.GetId());
event.SetEventObject(&window);
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendLoopPoints(std::pair<double, double> loopPoint, wxWindow& window, bool isDialog)
{
SampleHive::cLoopPointsEvent event(SampleHive::SH_EVT_LOOP_POINTS_UPDATED, window.GetId());
event.SetEventObject(&window);
event.SetLoopPoints({loopPoint.first, loopPoint.second});
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendClearLoopPointsStatus(wxWindow& window, bool isDialog)
{
SampleHive::cLoopPointsEvent event(SampleHive::SH_EVT_LOOP_POINTS_CLEAR, window.GetId());
event.SetEventObject(&window);
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendLoopABButtonValueChange(wxWindow& window, bool isDialog)
{
SampleHive::cLoopPointsEvent event(SampleHive::SH_EVT_LOOP_AB_BUTTON_VALUE_CHANGE, window.GetId());
event.SetEventObject(&window);
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
void cSignal::SendWaveformUpdateStatus(wxWindow& window, bool isDialog)
{
SampleHive::cWaveformUpdateEvent event(SampleHive::SH_EVT_UPDATE_WAVEFORM, window.GetId());
event.SetEventObject(&window);
if (isDialog)
window.GetParent()->GetEventHandler()->ProcessEvent(event);
else
window.HandleWindowEvent(event);
}
}

47
src/Utility/Signal.hpp Normal file
View File

@ -0,0 +1,47 @@
/* 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/string.h>
#include <wx/window.h>
namespace SampleHive {
class cSignal
{
public:
cSignal();
~cSignal();
public:
static void SendInfoBarMessage(const wxString& msg, int mode, wxWindow& window, bool isDialog = false);
static void SendPushStatusBarStatus(const wxString& msg, int section, wxWindow& window, bool isDialog = false);
static void SendSetStatusBarStatus(const wxString& msg, int section, wxWindow& window, bool isDialog = false);
static void SendPopStatusBarStatus(int section, wxWindow& window, bool isDialog = false);
static void SendCallFunctionPlay(const wxString& selection, bool checkAutoplay, wxWindow& window, bool isDialog = false);
static void SendTimerStopStatus(wxWindow& window, bool isDialog = false);
static void SendLoopPoints(std::pair<double, double> loopPoint, wxWindow& window, bool isDialog = false);
static void SendClearLoopPointsStatus(wxWindow& window, bool isDialog = false);
static void SendLoopABButtonValueChange(wxWindow& window, bool isDialog = false);
static void SendWaveformUpdateStatus(wxWindow& window, bool isDialog = false);
};
}

157
src/Utility/Tags.cpp Normal file
View File

@ -0,0 +1,157 @@
/* 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 "Utility/Tags.hpp"
#include "SampleHiveConfig.hpp"
// #include <iomanip>
#include <taglib/tag.h>
#include <taglib/fileref.h>
// #include <taglib/tpropertymap.h>
#ifndef USE_SYSTEM_INCLUDE_PATH
#include <taglib/toolkit/tstring.h>
#else
#include <taglib/tstring.h>
#endif
namespace SampleHive {
cTags::cTags(const std::string& filename)
: m_Filepath(filename)
{
}
cTags::~cTags()
{
}
cTags::AudioInfo cTags::GetAudioInfo()
{
wxString artist, album, genre, title, comment;
int channels = 0, length = 0, sample_rate = 0, bitrate = 0;
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
TagLib::AudioProperties* properties = f.audioProperties();
TagLib::String Title = tag->title();
TagLib::String Artist = tag->artist();
TagLib::String Album = tag->album();
TagLib::String Genre = tag->genre();
TagLib::String Comment = tag->comment();
int seconds = properties->length() % 60;
int minutes = (properties->length() - seconds) / 60;
bitrate = properties->bitrate();
channels = properties->channels();
length = properties->lengthInMilliseconds();
int length_sec = properties->lengthInSeconds();
sample_rate = properties->sampleRate();
title = wxString::FromUTF8(Title.toCString(true));
artist = wxString::FromUTF8(Artist.toCString(true));
album = wxString::FromUTF8(Album.toCString(true));
genre = wxString::FromUTF8(Genre.toCString(true));
comment = wxString::FromUTF8(Comment.toCString(true));
m_bValid = true;
}
else
{
m_bValid = false;
}
return { title, artist, album, genre, comment, channels, length, sample_rate, bitrate };
}
void cTags::SetTitle(std::string title)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setTitle(title);
f.save();
}
}
void cTags::SetArtist(std::string artist)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setArtist(artist);
f.save();
}
}
void cTags::SetAlbum(std::string album)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setAlbum(album);
f.save();
}
}
void cTags::SetGenre(std::string genre)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setGenre(genre);
f.save();
}
}
void cTags::SetComment(std::string comment)
{
TagLib::FileRef f (static_cast<const char*>(m_Filepath.c_str()), true, TagLib::AudioProperties::ReadStyle::Average);
if (!f.isNull() && f.tag() && f.audioProperties())
{
TagLib::Tag* tag = f.tag();
tag->setComment(comment);
f.save();
}
}
}

69
src/Utility/Tags.hpp Normal file
View File

@ -0,0 +1,69 @@
/* 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 <string>
#include <wx/string.h>
namespace SampleHive {
class cTags
{
struct AudioInfo
{
wxString title;
wxString artist;
wxString album;
wxString genre;
wxString comment;
int channels;
int length;
int sample_rate;
int bitrate;
};
public:
cTags(const std::string& filepath);
~cTags();
public:
// -------------------------------------------------------------------
cTags::AudioInfo GetAudioInfo();
void SetTitle(std::string artist);
void SetArtist(std::string artist);
void SetAlbum(std::string album);
void SetGenre(std::string genre);
void SetComment(std::string comment);
public:
// -------------------------------------------------------------------
inline bool IsFileValid() { return m_bValid; }
private:
// -------------------------------------------------------------------
const std::string& m_Filepath;
bool m_bValid = false;
};
}

332
src/Utility/Utils.cpp Normal file
View File

@ -0,0 +1,332 @@
/* 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 <cmath>
#include "Database/Database.hpp"
#include "Utility/HiveData.hpp"
#include "Utility/Log.hpp"
#include "Utility/Paths.hpp"
#include "Utility/Serialize.hpp"
#include "Utility/Signal.hpp"
#include "Utility/Tags.hpp"
#include "Utility/Utils.hpp"
#include <wx/dir.h>
#include <wx/gdicmn.h>
#include <wx/progdlg.h>
#include <wx/string.h>
#include <aubio/aubio.h>
namespace SampleHive {
SampleHive::cUtils::FileInfo SampleHive::cUtils::GetFilenamePathAndExtension(const wxString& selected,
bool checkExtension, bool doGetFilename)
{
wxString path;
std::string extension, filename;
path = GetSamplePath(selected);
if (checkExtension)
extension = path.AfterLast('/').AfterLast('.').ToStdString();
if (doGetFilename)
filename = path.AfterLast('/').BeforeLast('.').ToStdString();
return { path, extension, filename };
}
void SampleHive::cUtils::AddSamples(wxArrayString& files, wxWindow* parent)
{
SampleHive::cSerializer serializer;
cDatabase db;
wxBusyCursor busy_cursor;
wxWindowDisabler window_disabler;
wxProgressDialog* progressDialog = new wxProgressDialog(_("Adding files.."),
_("Adding files, please wait..."),
static_cast<int>(files.size()), parent,
wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_CAN_ABORT |
wxPD_AUTO_HIDE);
progressDialog->CenterOnParent(wxBOTH);
std::vector<Sample> sample_array;
std::string path;
std::string artist;
std::string filename_with_extension;
std::string filename_without_extension;
std::string extension;
std::string filename;
float bpm = 0.0f;
float key = 0.0f;
//Check All Files At Once
wxArrayString sorted_files;
if (!serializer.DeserializeDemoMode())
{
sorted_files = db.CheckDuplicates(files);
files = sorted_files;
}
if (files.size() < 1)
{
progressDialog->Destroy();
return;
}
progressDialog->SetRange(files.size());
for (unsigned int i = 0; i < files.size(); i++)
{
progressDialog->Update(i, wxString::Format(_("Getting Data For %s"), files[i].AfterLast('/')));
if (progressDialog->WasCancelled())
{
progressDialog->Destroy();
return;
}
path = files[i].ToStdString();
filename_with_extension = files[i].AfterLast('/').ToStdString();
filename_without_extension = files[i].AfterLast('/').BeforeLast('.').ToStdString();
extension = files[i].AfterLast('.').ToStdString();
filename = serializer.DeserializeShowFileExtension() ?
filename_with_extension : filename_without_extension;
bpm = GetBPM(path);
Sample sample;
sample.SetPath(path);
sample.SetFilename(filename_without_extension);
sample.SetFileExtension(extension);
cTags tags(path);
artist = tags.GetAudioInfo().artist.ToStdString();
sample.SetSamplePack(artist);
sample.SetChannels(tags.GetAudioInfo().channels);
sample.SetBPM(static_cast<int>(bpm));
sample.SetLength(tags.GetAudioInfo().length);
sample.SetSampleRate(tags.GetAudioInfo().sample_rate);
sample.SetBitrate(tags.GetAudioInfo().bitrate);
wxString length = CalculateAndGetISOStandardTime(sample.GetLength());
wxString bpm_str = GetBPMString(sample.GetBPM());
wxVector<wxVariant> data;
wxVariant icon = wxVariant(wxBitmap(ICON_STAR_EMPTY_16px, wxBITMAP_TYPE_PNG));
if (tags.IsFileValid())
{
data.clear();
data.push_back(icon);
data.push_back(filename);
data.push_back(sample.GetSamplePack());
data.push_back("");
data.push_back(wxString::Format("%d", sample.GetChannels()));
data.push_back(bpm_str);
data.push_back(length);
data.push_back(wxString::Format("%d", sample.GetSampleRate()));
data.push_back(wxString::Format("%d", sample.GetBitrate()));
data.push_back(path);
SH_LOG_INFO("Adding file: {}, Extension: {}", sample.GetFilename(), sample.GetFileExtension());
SampleHive::cHiveData::Get().ListCtrlAppendItem(data);
sample_array.push_back(sample);
}
else
{
wxString msg = wxString::Format(_("Error! Cannot open %s, Invalid file type."),
filename_with_extension);
SampleHive::cSignal::SendInfoBarMessage(msg, wxICON_ERROR, *parent);
}
}
progressDialog->Pulse(_("Updating Database.."), NULL);
db.InsertIntoSamples(sample_array);
progressDialog->Destroy();
}
void cUtils::OnAutoImportDir(const wxString& pathToDirectory, wxWindow* parent)
{
SH_LOG_DEBUG("Start Importing Samples");
wxBusyCursor busy_cursor;
wxWindowDisabler window_disabler;
wxString filepath;
wxArrayString filepath_array;
size_t number_of_files = wxDir::GetAllFiles(pathToDirectory, &filepath_array, wxEmptyString, wxDIR_DEFAULT);
wxProgressDialog* progressDialog = new wxProgressDialog(_("Adding files.."),
_("Adding files, please wait..."),
static_cast<int>(number_of_files), parent,
wxPD_APP_MODAL | wxPD_SMOOTH |
wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
progressDialog->CenterOnParent(wxBOTH);
for (size_t i = 0; i < number_of_files; i++)
{
filepath = filepath_array[i];
if (wxFileExists(filepath))
{
filepath_array.push_back(filepath);
}
else if (wxDirExists(filepath))
{
wxDir::GetAllFiles(filepath, &filepath_array);
}
progressDialog->Pulse(_("Reading Samples"), NULL);
}
progressDialog->Destroy();
AddSamples(filepath_array, parent);
SH_LOG_DEBUG("Done Importing Samples");
}
std::string cUtils::GetSamplePath(const wxString& name)
{
SampleHive::cSerializer serializer;
cDatabase db;
wxString sample_path;
if (m_PathCache.find(name.ToStdString()) != m_PathCache.end())
return m_PathCache[name.ToStdString()];
else
{
sample_path = serializer.DeserializeShowFileExtension() ?
db.GetSamplePathByFilename(name.BeforeLast('.').ToStdString()) :
db.GetSamplePathByFilename(name.ToStdString());
m_PathCache[name.ToStdString()] = sample_path;
}
return sample_path.ToStdString();
}
wxString cUtils::CalculateAndGetISOStandardTime(wxLongLong length)
{
const int min_digits = 2;
const size_t max_digits = 2;
wxString iso_length;
int min = static_cast<int>((length / 60000).GetValue());
int sec = static_cast<int>(((length % 60000) / 1000).GetValue());
int ms = static_cast<int>((length % 1000).GetValue());
iso_length = wxString::Format("%s:%s.%s",
wxString::Format("%0*i", min_digits, min).Left(max_digits),
wxString::Format("%0*i", min_digits, sec).Left(max_digits),
wxString::Format("%0*i", min_digits + 1, ms).Left(max_digits + 1));
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;
}
}

76
src/Utility/Utils.hpp Normal file
View File

@ -0,0 +1,76 @@
/* 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 "wx/arrstr.h"
#include "wx/string.h"
#include "wx/window.h"
#include <unordered_map>
namespace SampleHive {
class cUtils
{
private:
cUtils() = default;
public:
// -------------------------------------------------------------------
cUtils(const cUtils&) = delete;
cUtils& operator=(const cUtils) = delete;
public:
// -------------------------------------------------------------------
static cUtils& Get()
{
static cUtils s_cUtils;
return s_cUtils;
}
public:
// -------------------------------------------------------------------
struct FileInfo
{
wxString Path;
std::string Extension;
std::string Filename;
};
// -------------------------------------------------------------------
cUtils::FileInfo GetFilenamePathAndExtension(const wxString& selected,
bool checkExtension = true,
bool doGetFilename = true);
void AddSamples(wxArrayString& files, wxWindow* parent);
void OnAutoImportDir(const wxString& pathToDirectory, wxWindow* parent);
wxString CalculateAndGetISOStandardTime(wxLongLong length);
wxString GetBPMString(float bpm);
float GetBPM(const std::string& path);
private:
// -------------------------------------------------------------------
std::string GetSamplePath(const wxString& name);
private:
// -------------------------------------------------------------------
std::unordered_map<std::string, std::string> m_PathCache;
};
}

View File

@ -0,0 +1,13 @@
[wrap-file]
directory = libsndfile-1.2.2
source_url = https://github.com/libsndfile/libsndfile/releases/download/1.2.2/libsndfile-1.2.2.tar.xz
source_filename = libsndfile-1.2.2.tar.xz
source_hash = 3799ca9924d3125038880367bf1468e53a1b7e3686a934f098b7e1d286cdb80e
patch_filename = libsndfile_1.2.2-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/libsndfile_1.2.2-2/get_patch
patch_hash = 47c69c9bdd3d3b2a3ca3834f7288f2527cbc399c15a13705a182b221942aa3a5
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libsndfile_1.2.2-2/libsndfile-1.2.2.tar.xz
wrapdb_version = 1.2.2-2
[provide]
sndfile = libsndfile_dep

13
subprojects/spdlog.wrap Normal file
View File

@ -0,0 +1,13 @@
[wrap-file]
directory = spdlog-1.15.3
source_url = https://github.com/gabime/spdlog/archive/refs/tags/v1.15.3.tar.gz
source_filename = spdlog-1.15.3.tar.gz
source_hash = 15a04e69c222eb6c01094b5c7ff8a249b36bb22788d72519646fb85feb267e67
patch_filename = spdlog_1.15.3-4_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.15.3-4/get_patch
patch_hash = ccdc72f3d965980d5edd1a56129a9b7fa5f7c86f31e4ecf2dba6a6068829d4e2
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/spdlog_1.15.3-4/spdlog-1.15.3.tar.gz
wrapdb_version = 1.15.3-4
[provide]
spdlog = spdlog_dep

13
subprojects/sqlite3.wrap Normal file
View File

@ -0,0 +1,13 @@
[wrap-file]
directory = sqlite-amalgamation-3500400
source_url = https://www.sqlite.org/2025/sqlite-amalgamation-3500400.zip
source_filename = sqlite-amalgamation-3500400.zip
source_hash = 1d3049dd0f830a025a53105fc79fd2ab9431aea99e137809d064d8ee8356b032
patch_filename = sqlite3_3.50.4-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.50.4-1/get_patch
patch_hash = 61f23729c411d96d575b8d16c47a454f41b815de585289dec8daf855620ebc3e
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sqlite3_3.50.4-1/sqlite-amalgamation-3500400.zip
wrapdb_version = 3.50.4-1
[provide]
sqlite3 = sqlite3_dep

13
subprojects/taglib.wrap Normal file
View File

@ -0,0 +1,13 @@
[wrap-file]
directory = taglib-2.1.1
source_url = https://github.com/taglib/taglib/archive/refs/tags/v2.1.1.tar.gz
source_filename = taglib-2.1.1.tar.gz
source_hash = bd57924496a272322d6f9252502da4e620b6ab9777992e8934779ebd64babd6e
patch_filename = taglib_2.1.1-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/taglib_2.1.1-1/get_patch
patch_hash = 2f872cf5c75b4a0e38177170d1f61314451488e9eea3ef04b6534caacaab27e5
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/taglib_2.1.1-1/taglib-2.1.1.tar.gz
wrapdb_version = 2.1.1-1
[provide]
taglib = taglib_dep

View File

@ -0,0 +1,4 @@
[wrap-git]
url = https://github.com/wxWidgets/wxWidgets
revision = v3.2.8
clone-recursive = true

13
subprojects/yaml-cpp.wrap Normal file
View File

@ -0,0 +1,13 @@
[wrap-file]
directory = yaml-cpp-0.8.0
source_url = https://github.com/jbeder/yaml-cpp/archive/refs/tags/0.8.0.zip
source_filename = yaml-cpp-0.8.0.zip
source_hash = 334e80ab7b52e14c23f94e041c74bab0742f2281aad55f66be2f19f4b7747071
patch_filename = yaml-cpp_0.8.0-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/yaml-cpp_0.8.0-1/get_patch
patch_hash = bb7ae2e0941ab0e885a4ff2562aaa84979230087fc80c0b4eb283a44094d661b
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/yaml-cpp_0.8.0-1/yaml-cpp-0.8.0.zip
wrapdb_version = 0.8.0-1
[provide]
dependency_names = yaml-cpp