├── .clang-format
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── codecov.yml
├── include
├── audio
│ ├── base
│ │ ├── analyzer.h
│ │ ├── decoder.h
│ │ ├── notifier.h
│ │ └── playback.h
│ ├── command.h
│ ├── driver
│ │ ├── alsa.h
│ │ ├── ffmpeg.h
│ │ └── fftw.h
│ ├── lyric
│ │ ├── base
│ │ │ ├── html_parser.h
│ │ │ └── url_fetcher.h
│ │ ├── driver
│ │ │ ├── curl_wrapper.h
│ │ │ └── libxml_wrapper.h
│ │ ├── lyric_finder.h
│ │ └── search_config.h
│ └── player.h
├── debug
│ ├── dummy_analyzer.h
│ ├── dummy_decoder.h
│ ├── dummy_fetcher.h
│ ├── dummy_parser.h
│ └── dummy_playback.h
├── middleware
│ └── media_controller.h
├── model
│ ├── application_error.h
│ ├── audio_filter.h
│ ├── bar_animation.h
│ ├── block_identifier.h
│ ├── playlist.h
│ ├── playlist_operation.h
│ ├── question_data.h
│ ├── song.h
│ └── volume.h
├── util
│ ├── arg_parser.h
│ ├── file_handler.h
│ ├── formatter.h
│ ├── logger.h
│ └── sink.h
└── view
│ ├── base
│ ├── block.h
│ ├── custom_event.h
│ ├── dialog.h
│ ├── element.h
│ ├── event_dispatcher.h
│ ├── keybinding.h
│ ├── notifier.h
│ └── terminal.h
│ ├── block
│ ├── file_info.h
│ ├── main_content.h
│ ├── main_content
│ │ ├── audio_equalizer.h
│ │ ├── song_lyric.h
│ │ └── spectrum_visualizer.h
│ ├── media_player.h
│ ├── sidebar.h
│ └── sidebar_content
│ │ ├── list_directory.h
│ │ └── playlist_viewer.h
│ └── element
│ ├── button.h
│ ├── error_dialog.h
│ ├── focus_controller.h
│ ├── help_dialog.h
│ ├── internal
│ ├── base_menu.h
│ ├── file_menu.h
│ ├── playlist_menu.h
│ └── song_menu.h
│ ├── menu.h
│ ├── playlist_dialog.h
│ ├── question_dialog.h
│ ├── style.h
│ ├── tab.h
│ ├── text_animation.h
│ └── util.h
├── sonar-project.properties
├── src
├── CMakeLists.txt
├── audio
│ ├── command.cc
│ ├── driver
│ │ ├── alsa.cc
│ │ ├── ffmpeg.cc
│ │ └── fftw.cc
│ ├── lyric
│ │ ├── driver
│ │ │ ├── curl_wrapper.cc
│ │ │ └── libxml_wrapper.cc
│ │ ├── lyric_finder.cc
│ │ └── search_config.cc
│ └── player.cc
├── main.cc
├── middleware
│ └── media_controller.cc
├── model
│ ├── audio_filter.cc
│ ├── bar_animation.cc
│ ├── block_identifier.cc
│ ├── playlist.cc
│ ├── playlist_operation.cc
│ ├── question_data.cc
│ └── song.cc
├── util
│ ├── arg_parser.cc
│ ├── file_handler.cc
│ ├── logger.cc
│ └── sink.cc
└── view
│ ├── base
│ ├── block.cc
│ ├── custom_event.cc
│ ├── dialog.cc
│ ├── element.cc
│ ├── keybinding.cc
│ └── terminal.cc
│ ├── block
│ ├── file_info.cc
│ ├── main_content.cc
│ ├── main_content
│ │ ├── audio_equalizer.cc
│ │ ├── song_lyric.cc
│ │ └── spectrum_visualizer.cc
│ ├── media_player.cc
│ ├── sidebar.cc
│ └── sidebar_content
│ │ ├── list_directory.cc
│ │ └── playlist_viewer.cc
│ └── element
│ ├── button.cc
│ ├── error_dialog.cc
│ ├── focus_controller.cc
│ ├── help_dialog.cc
│ ├── internal
│ ├── file_menu.cc
│ ├── playlist_menu.cc
│ └── song_menu.cc
│ ├── menu.cc
│ ├── playlist_dialog.cc
│ ├── question_dialog.cc
│ ├── tab.cc
│ └── text_animation.cc
└── test
├── CMakeLists.txt
├── audio_lyric_finder.cc
├── audio_player.cc
├── block_file_info.cc
├── block_main_content.cc
├── block_media_player.cc
├── block_sidebar.cc
├── dialog_playlist.cc
├── driver_fftw.cc
├── general
├── block.h
├── dialog.h
├── sync_testing.h
└── utils.h
├── middleware_media_controller.cc
├── mock
├── analyzer_mock.h
├── audio_control_mock.h
├── decoder_mock.h
├── event_dispatcher_mock.h
├── file_handler_mock.h
├── html_parser_mock.h
├── interface_notifier_mock.h
├── lyric_finder_mock.h
├── playback_mock.h
└── url_fetcher_mock.h
└── util_argparser.cc
/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: Google
2 | Standard: c++17
3 | ColumnLimit: 100
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .cache
2 | .vscode
3 | build
4 | compile_commands.json
5 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18)
2 | project(spectrum)
3 |
4 | set(CMAKE_CXX_STANDARD 17)
5 |
6 | # Export compilation database for external tools
7 | set(CMAKE_EXPORT_COMPILE_COMMANDS
8 | ON
9 | CACHE INTERNAL "")
10 |
11 | # Use pkg-config and FetchContent modules for CMake build
12 | find_package(PkgConfig REQUIRED)
13 | include(FetchContent)
14 |
15 | # Add compiler options for code coverage
16 | function(check_coverage library)
17 | if(ENABLE_COVERAGE)
18 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES
19 | ".*Clang")
20 | target_compile_options(${library} INTERFACE --coverage -O0 -g)
21 | target_link_libraries(${library} INTERFACE --coverage)
22 | endif()
23 | endif()
24 | endfunction()
25 |
26 | # Build options
27 | option(SPECTRUM_DEBUG
28 | "Set to ON to build without external dependencies (ALSA, FFmpeg, FFTW3)"
29 | OFF)
30 | option(ENABLE_TESTS "Set to ON to build executable for unit testing" OFF)
31 | option(ENABLE_COVERAGE "Set to ON to build tests with coverage" OFF)
32 | option(ENABLE_INSTALL "Generate the install target" ON)
33 |
34 | if(SPECTRUM_DEBUG)
35 | message(STATUS "Enabling debug mode...")
36 | add_definitions(-DSPECTRUM_DEBUG)
37 | endif()
38 |
39 | # Build application
40 | add_subdirectory(src)
41 |
42 | if(ENABLE_TESTS AND NOT SPECTRUM_DEBUG)
43 | message(STATUS "Enabling tests...")
44 | add_definitions(-DENABLE_TESTS)
45 | add_subdirectory(test)
46 | endif()
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Vinicius Moura Longaray.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | :headphones: spectrum
4 |
5 |
6 |
7 | A simple and intuitive console-based music player written in C++
8 |
9 | https://github.com/v1nns/spectrum/assets/22479290/5ab537cf-34d6-4627-8d66-4f7128cd6915
10 |
11 | Introducing yet another music player for tech enthusiasts that will simplify the way you experience your favorite tunes! Immerse yourself in the sound with the powerful equalizer, allowing you to fine-tune every aspect of the music to your exact specifications, perfectly matching your mood.
12 |
13 | With an intuitive user interface and lightning-fast performance, this music player is the perfect addition to any audiophile's collection. Whether you're a casual listener or a serious music lover, this console-based music player will exceed your expectations.
14 |
15 | ## Features :speech_balloon:
16 |
17 | - Simple and intuitive terminal user interface;
18 | - Plays music in any format;
19 | - Basic playback controls such as play, pause, stop, and skip;
20 | - Displays information about the currently playing track;
21 | - Audio spectrum visualizer;
22 | - Audio equalizer;
23 | - Fetch song lyrics;
24 | - Support for playlists.
25 |
26 | ## Installation :floppy_disk:
27 |
28 | ### AUR (using yay)
29 |
30 | If you're using Arch Linux or any derivative, you can install spectrum using yay, a popular AUR helper:
31 |
32 | ```bash
33 | # Install the latest version
34 | yay -S spectrum-git
35 | ```
36 |
37 | ### Flatpak
38 |
39 | To install Spectrum using Flatpak:
40 |
41 | 1. Add the Flathub repository (if not already added):
42 | ```bash
43 | flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
44 | ```
45 |
46 | 2. Install spectrum:
47 | ```bash
48 | flatpak install flathub io.github.v1nns.spectrum
49 | ```
50 |
51 | ## Development :memo:
52 |
53 | To build spectrum, you need to have a C++ compiler installed on your system.
54 |
55 | ```bash
56 | # Package dependencies (on Ubuntu)
57 | sudo apt install build-essential libasound2-dev libavcodec-dev \
58 | libavfilter-dev libavformat-dev libfftw3-dev libswresample-dev \
59 | libcurl4-openssl-dev libxml++2.6-dev
60 |
61 | # Clone repository
62 | git clone https://github.com/v1nns/spectrum.git
63 | cd spectrum
64 |
65 | # Generate build system in the build directory
66 | cmake -S . -B build
67 |
68 | # Build executable
69 | cmake --build build
70 |
71 | # Install to /usr/local/bin/ (optional)
72 | sudo cmake --install build
73 |
74 | # OR just execute it
75 | ./build/src/spectrum
76 | ```
77 |
78 | To ensure that any new implementation won't impact the existing one, you may execute unit tests to check that. To enable unit testing, you should compile with the following settings:
79 |
80 | ```bash
81 | # Generate build system for testing/debugging
82 | cmake -S . -B build -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -G Ninja
83 |
84 | # Execute unit tests
85 | cmake --build build && ./build/test/test
86 |
87 | # For manual testing, you may take a look in the log file
88 | cmake --build build && ./build/src/spectrum -l /tmp/log.txt
89 | ```
90 |
91 | ## Credits :placard:
92 |
93 | This software uses the following open source packages:
94 |
95 | - [FFmpeg](https://ffmpeg.org/)
96 | - [FFTW](https://www.fftw.org/)
97 | - [curl](https://curl.se/)
98 | - [libxml++](https://libxmlplusplus.github.io/libxmlplusplus/)
99 | - [FTXUI](https://github.com/ArthurSonzogni/FTXUI)
100 | - [cava](https://github.com/karlstav/cava) (visualizer is based on cava implementation)
101 | - [json](https://github.com/nlohmann/json)
102 |
103 | ## Contributing
104 |
105 | Contributions are always welcome! If you find any bugs or have suggestions for new features, please open an issue or submit a pull request.
106 |
107 | ## License
108 |
109 | This project is licensed under the MIT License. See the LICENSE file for details.
110 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | # ignored files for code coverage
2 | ignore:
3 | - "src/main.cc"
4 |
--------------------------------------------------------------------------------
/include/audio/base/analyzer.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Interface class for audio analyzer support
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_BASE_ANALYZER_H_
7 | #define INCLUDE_AUDIO_BASE_ANALYZER_H_
8 |
9 | #include "model/application_error.h"
10 |
11 | namespace driver {
12 |
13 | /**
14 | * @brief Common interface to execute frequency analysis on audio data
15 | */
16 | class Analyzer {
17 | public:
18 | /**
19 | * @brief Construct a new Analyzer object
20 | */
21 | Analyzer() = default;
22 |
23 | /**
24 | * @brief Destroy the Analyzer object
25 | */
26 | virtual ~Analyzer() = default;
27 |
28 | /* ******************************************************************************************** */
29 | //! Public API
30 |
31 | /**
32 | * @brief Initialize internal structures for audio analysis
33 | * @param output_size Size for output vector from Execute
34 | */
35 | virtual error::Code Init(int output_size) = 0;
36 |
37 | /**
38 | * @brief Run FFT on input vector to get information about audio in the frequency domain
39 | * @param in Input vector with audio raw data (signal amplitude)
40 | * @param size Input vector size
41 | * @param out Output vector where each entry represents a frequency bar
42 | */
43 | virtual error::Code Execute(double *in, int size, double *out) = 0;
44 |
45 | /**
46 | * @brief Get internal buffer size
47 | * @return Maximum size for input vector
48 | */
49 | virtual int GetBufferSize() = 0;
50 |
51 | /**
52 | * @brief Get output buffer size
53 | * @return Size for output vector (considering number of bars multiplied per number of channels)
54 | */
55 | virtual int GetOutputSize() = 0;
56 | };
57 |
58 | } // namespace driver
59 | #endif // INCLUDE_AUDIO_BASE_ANALYZER_H_
60 |
--------------------------------------------------------------------------------
/include/audio/base/decoder.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Interface class for decoder support
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_BASE_DECODER_H_
7 | #define INCLUDE_AUDIO_BASE_DECODER_H_
8 |
9 | #include
10 |
11 | #include "model/application_error.h"
12 | #include "model/audio_filter.h"
13 | #include "model/song.h"
14 | #include "model/volume.h"
15 |
16 | namespace driver {
17 |
18 | /**
19 | * @brief Common interface to read audio file as an input stream, decode it, apply biquad IIR
20 | * filters on extracted audio data and finally, send the result to audio callback
21 | */
22 | class Decoder {
23 | public:
24 | /**
25 | * @brief Construct a new Decoder object
26 | */
27 | Decoder() = default;
28 |
29 | /**
30 | * @brief Destroy the Decoder object
31 | */
32 | virtual ~Decoder() = default;
33 |
34 | /* ******************************************************************************************** */
35 | //! Public API for Decoder
36 |
37 | /**
38 | * @brief Function invoked after resample is available.
39 | * (for better understanding: take a look at Audio Loop from Player, and also Playback class)
40 | */
41 | using AudioCallback = std::function;
42 |
43 | /**
44 | * @brief Open file as input stream and check for codec compatibility for decoding
45 | * @param audio_info (In/Out) In case of success, this is filled with detailed audio information
46 | * @return error::Code Application error code
47 | */
48 | virtual error::Code OpenFile(model::Song& audio_info) = 0;
49 |
50 | /**
51 | * @brief Decode and resample input stream to desired sample format/rate
52 | * @param samples Maximum value of samples
53 | * @param callback Pass resamples to this callback
54 | * @return error::Code Application error code
55 | */
56 | virtual error::Code Decode(int samples, AudioCallback callback) = 0;
57 |
58 | /**
59 | * @brief After file is opened and decoded, or when some error occurs, always clear internal cache
60 | */
61 | virtual void ClearCache() = 0;
62 |
63 | /* ******************************************************************************************** */
64 | //! Public API for Equalizer TODO: split into a new header along with FFmpeg class
65 |
66 | /**
67 | * @brief Set volume on playback stream
68 | *
69 | * @param value Desired volume (in a range between 0.f and 1.f)
70 | * @return error::Code Decoder error converted to application error code
71 | */
72 | virtual error::Code SetVolume(model::Volume value) = 0;
73 |
74 | /**
75 | * @brief Get volume from playback stream
76 | * @return model::Volume Volume percentage (in a range between 0.f and 1.f)
77 | */
78 | virtual model::Volume GetVolume() const = 0;
79 |
80 | /**
81 | * @brief Update audio filters in the filter chain (used for equalization)
82 | *
83 | * @param filters Audio filters
84 | * @return error::Code Decoder error converted to application error code
85 | */
86 | virtual error::Code UpdateFilters(const model::EqualizerPreset& filters) = 0;
87 | };
88 |
89 | } // namespace driver
90 | #endif // INCLUDE_AUDIO_BASE_DECODER_H_
91 |
--------------------------------------------------------------------------------
/include/audio/base/notifier.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Interface class for sending actions from GUI to Audio Player
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_BASE_NOTIFIER_H_
7 | #define INCLUDE_AUDIO_BASE_NOTIFIER_H_
8 |
9 | #include
10 |
11 | #include "model/audio_filter.h"
12 | #include "model/playlist.h"
13 | #include "model/volume.h"
14 |
15 | namespace audio {
16 |
17 | /**
18 | * @brief Interface class to notify an action to Audio Player
19 | */
20 | class Notifier {
21 | public:
22 | /**
23 | * @brief Construct a new Notifier object
24 | */
25 | Notifier() = default;
26 |
27 | /**
28 | * @brief Destroy the Notifier object
29 | */
30 | virtual ~Notifier() = default;
31 |
32 | /* ******************************************************************************************** */
33 | //! Public API
34 |
35 | /**
36 | * @brief Notify Audio Player about file selected by user on Terminal User Interface (TUI)
37 | * @param file Full path to file (may be a song or not)
38 | */
39 | virtual void NotifyFileSelection(const std::filesystem::path& file) = 0;
40 |
41 | /**
42 | * @brief Notify Audio Player to pause/resume the current song
43 | */
44 | virtual void PauseOrResume() = 0;
45 |
46 | /**
47 | * @brief Notify Audio Player to stop the current song
48 | */
49 | virtual void Stop() = 0;
50 |
51 | /**
52 | * @brief Notify Audio Player to set volume
53 | * @param value Sound volume information
54 | */
55 | virtual void SetVolume(model::Volume value) = 0;
56 |
57 | /**
58 | * @brief Notify Audio Player to resize quantity of frequency bars as result from audio analysis
59 | * @param value Maximum quantity of frequency bars
60 | */
61 | virtual void ResizeAnalysisOutput(int value) = 0;
62 |
63 | /**
64 | * @brief Notify Audio Player to seek forward position in current playing song
65 | * @param value Offset value
66 | */
67 | virtual void SeekForwardPosition(int value) = 0;
68 |
69 | /**
70 | * @brief Notify Audio Player to seek backward position in current playing song
71 | * @param value Offset value
72 | */
73 | virtual void SeekBackwardPosition(int value) = 0;
74 |
75 | /**
76 | * @brief Notify Audio Player to apply audio filters in the audio chain
77 | * @param frequencies Vector of audio filters
78 | */
79 | virtual void ApplyAudioFilters(const model::EqualizerPreset& filters) = 0;
80 |
81 | /**
82 | * @brief Notify Audio Player about playlist selected by user
83 | * @param playlist Song queue
84 | */
85 | virtual void NotifyPlaylistSelection(const model::Playlist& playlist) = 0;
86 | };
87 |
88 | } // namespace audio
89 | #endif // INCLUDE_AUDIO_BASE_NOTIFIER_H_
90 |
--------------------------------------------------------------------------------
/include/audio/base/playback.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Interface class for playback support
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_BASE_PLAYBACK_H_
7 | #define INCLUDE_AUDIO_BASE_PLAYBACK_H_
8 |
9 | #include
10 |
11 | #include "model/application_error.h"
12 | #include "model/volume.h"
13 |
14 | namespace driver {
15 |
16 | /**
17 | * @brief Common interface to create and handle playback audio stream
18 | */
19 | class Playback {
20 | public:
21 | /**
22 | * @brief Construct a new Playback object
23 | */
24 | Playback() = default;
25 |
26 | /**
27 | * @brief Destroy the Playback object
28 | */
29 | virtual ~Playback() = default;
30 |
31 | /* ******************************************************************************************** */
32 | //! Public API
33 |
34 | /**
35 | * @brief Create a Playback Stream
36 | * @return error::Code Playback error converted to application error code
37 | */
38 | virtual error::Code CreatePlaybackStream() = 0;
39 |
40 | /**
41 | * @brief Configure Playback Stream parameters (sample format, etc...)
42 | * @return error::Code Playback error converted to application error code
43 | */
44 | virtual error::Code ConfigureParameters() = 0;
45 |
46 | /**
47 | * @brief Make playback stream ready to play
48 | * @return error::Code Playback error converted to application error code
49 | */
50 | virtual error::Code Prepare() = 0;
51 |
52 | /**
53 | * @brief Pause current song on playback stream
54 | * @return error::Code Playback error converted to application error code
55 | */
56 | virtual error::Code Pause() = 0;
57 |
58 | /**
59 | * @brief Stop playing song on playback stream
60 | * @return error::Code Playback error converted to application error code
61 | */
62 | virtual error::Code Stop() = 0;
63 |
64 | /**
65 | * @brief Directly write audio buffer to playback stream (this should be called by decoder)
66 | *
67 | * @param buffer Audio data buffer
68 | * @param size Buffer size
69 | * @return error::Code Playback error converted to application error code
70 | */
71 | virtual error::Code AudioCallback(void* buffer, int size) = 0;
72 |
73 | /**
74 | * @brief Set volume on playback stream
75 | *
76 | * @param value Desired volume (in a range between 0.f and 1.f)
77 | * @return error::Code Playback error converted to application error code
78 | */
79 | virtual error::Code SetVolume(model::Volume value) = 0;
80 |
81 | /**
82 | * @brief Get volume from playback stream
83 | * @return model::Volume Volume percentage (in a range between 0.f and 1.f)
84 | */
85 | virtual model::Volume GetVolume() = 0;
86 |
87 | /**
88 | * @brief Get period size
89 | * @return uint32_t Period size
90 | */
91 | virtual uint32_t GetPeriodSize() const = 0;
92 | };
93 |
94 | } // namespace driver
95 | #endif // INCLUDE_AUDIO_BASE_PLAYBACK_H_
96 |
--------------------------------------------------------------------------------
/include/audio/command.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Structure for an audio player command
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_COMMAND_H_
7 | #define INCLUDE_AUDIO_COMMAND_H_
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "model/audio_filter.h"
15 | #include "model/volume.h"
16 |
17 | namespace audio {
18 |
19 | /**
20 | * @brief Interface for commands to be handled by audio player
21 | */
22 | struct Command {
23 | //! Identifier for all existing events
24 | enum class Identifier {
25 | None = 8000,
26 | Play = 8001,
27 | PauseOrResume = 8002,
28 | Stop = 8003,
29 | SeekForward = 8004,
30 | SeekBackward = 8005,
31 | SetVolume = 8006,
32 | UpdateAudioFilters = 8007,
33 | Exit = 8008,
34 | };
35 |
36 | //! Overloaded operators
37 | friend bool operator==(const Command& lhs, const Command& rhs) { return lhs.id == rhs.id; }
38 | friend bool operator!=(const Command& lhs, const Command& rhs) { return lhs.id != rhs.id; }
39 | friend bool operator==(const Command& lhs, const Command::Identifier& rhs) {
40 | return lhs.id == rhs;
41 | }
42 | friend bool operator!=(const Command& lhs, const Command::Identifier& rhs) {
43 | return lhs.id != rhs;
44 | }
45 |
46 | //! Output command to ostream
47 | friend std::ostream& operator<<(std::ostream& out, const Command& cmd);
48 | friend std::ostream& operator<<(std::ostream& out, const std::vector& cmds);
49 |
50 | //! Possible commands to be handled by audio player
51 | static Command None();
52 | static Command Play(const std::string& filepath = "");
53 | static Command PauseOrResume();
54 | static Command Stop();
55 | static Command SeekForward(int offset);
56 | static Command SeekBackward(int offset);
57 | static Command SetVolume(const model::Volume& value);
58 | static Command UpdateAudioFilters(const model::EqualizerPreset& filters);
59 | static Command Exit();
60 |
61 | //! Possible types for content
62 | using Content =
63 | std::variant;
64 |
65 | //! Getter for command identifier
66 | Identifier GetId() const { return id; }
67 |
68 | //! Generic getter for command content
69 | template
70 | T GetContent() const {
71 | if (std::holds_alternative(content)) {
72 | return std::get(content);
73 | }
74 | return T();
75 | }
76 |
77 | //! Variables
78 | // P.S. removed private keyword, otherwise wouldn't be possible to use C++ brace initialization
79 | Identifier id; //!< Unique type identifier for Command
80 | Content content; //!< Wrapper for content
81 | };
82 |
83 | } // namespace audio
84 |
85 | #endif // INCLUDE_AUDIO_COMMAND_H_
86 |
--------------------------------------------------------------------------------
/include/audio/driver/alsa.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Class to support using ALSA driver
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_DRIVER_ALSA_H_
7 | #define INCLUDE_AUDIO_DRIVER_ALSA_H_
8 |
9 | #include
10 |
11 | #include
12 |
13 | #include "audio/base/playback.h"
14 | #include "model/application_error.h"
15 |
16 | namespace driver {
17 |
18 | /**
19 | * @brief Provides an interface to use ALSA library for handling audio with hardware
20 | */
21 | class Alsa final : public Playback {
22 | public:
23 | /**
24 | * @brief Construct a new Alsa object
25 | */
26 | Alsa() = default;
27 |
28 | /**
29 | * @brief Destroy the Alsa object
30 | */
31 | ~Alsa() override = default;
32 |
33 | /* ******************************************************************************************** */
34 | //! Public API
35 | /**
36 | * @brief Create a Playback Stream using ALSA API
37 | * @return error::Code Playback error converted to application error code
38 | */
39 | error::Code CreatePlaybackStream() override;
40 |
41 | /**
42 | * @brief Configure Playback Stream parameters (sample format, etc...) using ALSA API
43 | * @return error::Code Playback error converted to application error code
44 | */
45 | error::Code ConfigureParameters() override;
46 |
47 | /**
48 | * @brief Ask ALSA API to make playback stream ready to play
49 | * @return error::Code Playback error converted to application error code
50 | */
51 | error::Code Prepare() override;
52 |
53 | /**
54 | * @brief Pause current song on playback stream
55 | * @return error::Code Playback error converted to application error code
56 | */
57 | error::Code Pause() override;
58 |
59 | /**
60 | * @brief Stop playing song on playback stream
61 | * @return error::Code Playback error converted to application error code
62 | */
63 | error::Code Stop() override;
64 |
65 | /**
66 | * @brief Directly write audio buffer to playback stream (this should be called by decoder)
67 | *
68 | * @param buffer Audio data buffer
69 | * @param size Buffer size
70 | * @return error::Code Playback error converted to application error code
71 | */
72 | error::Code AudioCallback(void* buffer, int size) override;
73 |
74 | /**
75 | * @brief Set volume on playback stream
76 | *
77 | * @param value Desired volume (in a range between 0.f and 1.f)
78 | * @return error::Code Playback error converted to application error code
79 | */
80 | error::Code SetVolume(model::Volume value) override;
81 |
82 | /**
83 | * @brief Get volume from playback stream
84 | * @return model::Volume Volume percentage (in a range between 0.f and 1.f)
85 | */
86 | model::Volume GetVolume() override;
87 |
88 | /**
89 | * @brief Get period size (previously filled by ALSA API)
90 | * @return uint32_t Period size
91 | */
92 | uint32_t GetPeriodSize() const override { return (uint32_t)period_size_; }
93 |
94 | /* ******************************************************************************************** */
95 | //! Utility
96 | private:
97 | /**
98 | * @brief Find and return master playback from High level control interface from ALSA (p.s.: not
99 | * necessary the use of smart pointers here because this resource is managed by ALSA)
100 | */
101 | snd_mixer_elem_t* GetMasterPlayback();
102 |
103 | /* ******************************************************************************************** */
104 | //! Default Constants for Audio Parameters
105 | static constexpr const char kSelemName[] = "Master";
106 | static constexpr int kChannels = 2;
107 | static constexpr int kSampleRate = 44100;
108 | static constexpr snd_pcm_format_t kSampleFormat = SND_PCM_FORMAT_S16_LE;
109 |
110 | /* ******************************************************************************************** */
111 | //! Custom declarations with deleters
112 | struct PcmDeleter {
113 | void operator()(snd_pcm_t* p) const {
114 | snd_pcm_drain(p);
115 | snd_pcm_close(p);
116 | }
117 | };
118 |
119 | struct MixerDeleter {
120 | void operator()(snd_mixer_t* p) const { snd_mixer_close(p); }
121 | };
122 |
123 | using PcmPlayback = std::unique_ptr;
124 |
125 | using MixerControl = std::unique_ptr;
126 |
127 | /* ******************************************************************************************** */
128 | //! Variables
129 |
130 | PcmPlayback playback_handle_; //! Playback stream handled by ALSA API
131 | MixerControl mixer_; //! High level control interface from ALSA API (to manage volume)
132 | snd_pcm_uframes_t period_size_ = 0; //! Period size (necessary in order to discover buffer size)
133 | };
134 |
135 | } // namespace driver
136 | #endif // INCLUDE_AUDIO_DRIVER_ALSA_H_
137 |
--------------------------------------------------------------------------------
/include/audio/lyric/base/html_parser.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Interface class for HTML parsing support
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_LYRIC_BASE_HTML_PARSER_H_
7 | #define INCLUDE_AUDIO_LYRIC_BASE_HTML_PARSER_H_
8 |
9 | #include
10 | #include
11 |
12 | namespace lyric {
13 |
14 | //! SongLyric declaration
15 | using SongLyric = std::vector;
16 |
17 | } // namespace lyric
18 |
19 | namespace driver {
20 |
21 | /**
22 | * @brief Common interface to parse HTML content into a DOM tree
23 | */
24 | class HtmlParser {
25 | public:
26 | /**
27 | * @brief Construct a new HtmlParser object
28 | */
29 | HtmlParser() = default;
30 |
31 | /**
32 | * @brief Destroy the HtmlParser object
33 | */
34 | virtual ~HtmlParser() = default;
35 |
36 | /* ******************************************************************************************** */
37 | //! Public API
38 |
39 | /**
40 | * @brief Parse buffer data based on the given XPath
41 | * @param data Buffer data
42 | * @param xpath XPath to find
43 | * @return Song lyrics parsed from buffer data
44 | */
45 | virtual lyric::SongLyric Parse(const std::string &data, const std::string &xpath) = 0;
46 | };
47 |
48 | } // namespace driver
49 | #endif // INCLUDE_AUDIO_LYRIC_BASE_HTML_PARSER_H_
50 |
--------------------------------------------------------------------------------
/include/audio/lyric/base/url_fetcher.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Interface class for URL fetching support
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_LYRIC_BASE_URL_FETCHER_H_
7 | #define INCLUDE_AUDIO_LYRIC_BASE_URL_FETCHER_H_
8 |
9 | #include
10 |
11 | #include "model/application_error.h"
12 |
13 | namespace driver {
14 |
15 | /**
16 | * @brief Common interface to fetch content from URL
17 | */
18 | class UrlFetcher {
19 | public:
20 | /**
21 | * @brief Construct a new UrlFetcher object
22 | */
23 | UrlFetcher() = default;
24 |
25 | /**
26 | * @brief Destroy the UrlFetcher object
27 | */
28 | virtual ~UrlFetcher() = default;
29 |
30 | /* ******************************************************************************************** */
31 | //! Public API
32 |
33 | /**
34 | * @brief Fetch content from the given URL
35 | * @param URL Endpoint address
36 | * @param output Output from fetch (out)
37 | * @return Error code from operation
38 | */
39 | virtual error::Code Fetch(const std::string &URL, std::string &output) = 0;
40 | };
41 |
42 | } // namespace driver
43 | #endif // INCLUDE_AUDIO_LYRIC_BASE_URL_FETCHER_H_
44 |
--------------------------------------------------------------------------------
/include/audio/lyric/driver/curl_wrapper.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Class to wrap CURL funcionalities
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_LYRIC_CURL_WRAPPER_H_
7 | #define INCLUDE_AUDIO_LYRIC_CURL_WRAPPER_H_
8 |
9 | #include
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include "audio/lyric/base/url_fetcher.h"
16 | #include "model/application_error.h"
17 |
18 | namespace driver {
19 |
20 | /**
21 | * @brief Class to manage CURL resources and perform content fetching from the given URL
22 | */
23 | class CURLWrapper : public driver::UrlFetcher {
24 | // The Accept request HTTP header indicates which content types, expressed as MIME types, the
25 | // client is able to understand
26 | static constexpr std::string_view kAcceptType =
27 | "Accept:text/html,application/xhtml+xml,application/xml";
28 |
29 | // The User-Agent request header is a characteristic string that lets servers and network peers
30 | // identify the application, operating system, vendor and version of the requesting user agent.
31 | static constexpr std::string_view kUserAgent =
32 | "User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.17 (KHTML, like Gecko) "
33 | "Chrome/24.0.1312.70 Safari/537.17";
34 |
35 | public:
36 | /**
37 | * @brief Fetch content from the given URL
38 | * @param URL Endpoint address
39 | * @param output Output from fetch (out)
40 | * @return Error code from operation
41 | */
42 | error::Code Fetch(const std::string &URL, std::string &output) override;
43 |
44 | private:
45 | /**
46 | * @brief This callback function gets called by libcurl as soon as there is data received that
47 | * needs to be saved. For most transfers, this callback gets called many times and each invoke
48 | * delivers another chunk of data.
49 | * @param buffer Pointer to delivered data
50 | * @param size Value always equal to 1
51 | * @param nmemb Size of data
52 | * @param data Output buffer
53 | * @return Real size from received data
54 | */
55 | static size_t WriteCallback(const char *buffer, size_t size, size_t nmemb, void *data);
56 |
57 | //! Smart pointer to manage CURL resource
58 | using SmartCURL = std::unique_ptr;
59 | };
60 |
61 | } // namespace driver
62 | #endif // INCLUDE_AUDIO_LYRIC_CURL_WRAPPER_H_
63 |
--------------------------------------------------------------------------------
/include/audio/lyric/driver/libxml_wrapper.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Class to wrap libxml++ funcionalities
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_LYRIC_LIBXML_WRAPPER_H_
7 | #define INCLUDE_AUDIO_LYRIC_LIBXML_WRAPPER_H_
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include
14 | #include
15 |
16 | #include "audio/lyric/base/html_parser.h"
17 |
18 | namespace driver {
19 |
20 | /**
21 | * @brief Class to manage libxml++ resources and perform content parsing
22 | */
23 | class LIBXMLWrapper : public driver::HtmlParser {
24 | public:
25 | /**
26 | * @brief Parse buffer data based on the given XPath
27 | * @param data Buffer data
28 | * @param xpath XPath to find
29 | * @return Song lyrics parsed from buffer data
30 | */
31 | lyric::SongLyric Parse(const std::string &data, const std::string &xpath) override;
32 |
33 | private:
34 | /**
35 | * @brief Filter only text nodes to emplace back on lyrics
36 | * @param node XML node
37 | * @param lyric Song lyrics (out)
38 | */
39 | void ScrapContent(const xmlpp::Node *node, lyric::SongLyric &lyric);
40 |
41 | //! Smart pointer to manage libxml resources
42 | using XmlDocGuard = std::unique_ptr;
43 | };
44 |
45 | } // namespace driver
46 | #endif // INCLUDE_AUDIO_LYRIC_LIBXML_WRAPPER_H_
47 |
--------------------------------------------------------------------------------
/include/audio/lyric/lyric_finder.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Class for Lyric Finder
4 | */
5 |
6 | #ifndef INCLUDE_AUDIO_LYRIC_LYRIC_FINDER_H_
7 | #define INCLUDE_AUDIO_LYRIC_LYRIC_FINDER_H_
8 |
9 | #include
10 | #include
11 |
12 | #include "audio/lyric/base/html_parser.h"
13 | #include "audio/lyric/base/url_fetcher.h"
14 | #include "audio/lyric/search_config.h"
15 |
16 | #ifdef ENABLE_TESTS
17 | namespace {
18 | class LyricFinderTest;
19 | }
20 | #endif
21 |
22 | namespace lyric {
23 |
24 | /**
25 | * @brief Responsible to fetch content from search engines and web scrap song lyrics from it
26 | */
27 | class LyricFinder {
28 | /**
29 | * @brief Construct a new LyricFinder object
30 | * @param fetcher Pointer to URL fetcher interface
31 | * @param parser Pointer to HTML parser interface
32 | */
33 | explicit LyricFinder(std::unique_ptr&& fetcher,
34 | std::unique_ptr&& parser);
35 |
36 | protected:
37 | /**
38 | * @brief Construct a new LyricFinder object
39 | */
40 | LyricFinder() = default;
41 |
42 | public:
43 | /**
44 | * @brief Factory method: Create, initialize internal components and return LyricFinder object
45 | * @param fetcher Pass fetcher to be used within LyricFinder (optional)
46 | * @param parser Pass parser to be used within LyricFinder (optional)
47 | * @return std::unique_ptr LyricFinder instance
48 | */
49 | static std::unique_ptr Create(driver::UrlFetcher* fetcher = nullptr,
50 | driver::HtmlParser* parser = nullptr);
51 |
52 | /**
53 | * @brief Destroy the LyricFinder object
54 | */
55 | virtual ~LyricFinder() = default;
56 |
57 | //! Remove these
58 | LyricFinder(const LyricFinder& other) = delete; // copy constructor
59 | LyricFinder(LyricFinder&& other) = delete; // move constructor
60 | LyricFinder& operator=(const LyricFinder& other) = delete; // copy assignment
61 | LyricFinder& operator=(LyricFinder&& other) = delete; // move assignment
62 |
63 | /* ******************************************************************************************** */
64 | //! Public API
65 |
66 | /**
67 | * @brief Search for lyrics by fetching the search engine and web scraping it
68 | * @param artist Artist name
69 | * @param title Song name
70 | * @return Song lyrics
71 | */
72 | virtual SongLyric Search(const std::string& artist, const std::string& title);
73 |
74 | /* ******************************************************************************************** */
75 | //! Variables
76 | private:
77 | Config engines_ = SearchConfig::Create(); //!< Search engine settings
78 | std::unique_ptr fetcher_; //!< URL fetcher
79 | std::unique_ptr parser_; //!< HTML parser
80 |
81 | /* ******************************************************************************************** */
82 | //! Friend class for testing purpose
83 |
84 | #ifdef ENABLE_TESTS
85 | friend class ::LyricFinderTest;
86 | #endif
87 | };
88 |
89 | } // namespace lyric
90 | #endif // INCLUDE_AUDIO_LYRIC_LYRIC_FINDER_H_
91 |
--------------------------------------------------------------------------------
/include/debug/dummy_analyzer.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Dummy class for audio analyzer support
4 | */
5 |
6 | #ifndef INCLUDE_DEBUG_DUMMY_ANALYZER_H_
7 | #define INCLUDE_DEBUG_DUMMY_ANALYZER_H_
8 |
9 | #include "audio/base/analyzer.h"
10 | #include "model/application_error.h"
11 |
12 | namespace driver {
13 |
14 | /**
15 | * @brief Dummy implementation
16 | */
17 | class DummyAnalyzer : public Analyzer {
18 | public:
19 | /**
20 | * @brief Construct a new Analyzer object
21 | */
22 | DummyAnalyzer() = default;
23 |
24 | /**
25 | * @brief Destroy the Analyzer object
26 | */
27 | virtual ~DummyAnalyzer() = default;
28 |
29 | /* ******************************************************************************************** */
30 | //! Public API
31 |
32 | /**
33 | * @brief Initialize internal structures for audio analysis
34 | *
35 | * @param output_size Size for output vector from Execute
36 | */
37 | error::Code Init(int output_size) override {
38 | output_size_ = output_size;
39 | return error::kSuccess;
40 | }
41 |
42 | /**
43 | * @brief Run FFT on input vector to get information about audio in the frequency domain
44 | *
45 | * @param in Input vector with audio raw data (signal amplitude)
46 | * @param size Input vector size
47 | * @param out Output vector where each entry represents a frequency bar
48 | */
49 | error::Code Execute(double *in, int size, double *out) override { return error::kSuccess; }
50 |
51 | /**
52 | * @brief Get internal buffer size
53 | *
54 | * @return Maximum size for input vector
55 | */
56 | int GetBufferSize() override { return kBufferSize; }
57 |
58 | /**
59 | * @brief Get output buffer size
60 | *
61 | * @return Size for output vector (considering number of bars multiplied per number of channels)
62 | */
63 | int GetOutputSize() override { return output_size_; }
64 |
65 | /* *********************************************************************************************/
66 | //! Default Constants
67 | private:
68 | static constexpr int kBufferSize = 1024; //!< Base size for buffers
69 |
70 | /* ******************************************************************************************** */
71 | //! Variables
72 | private:
73 | int output_size_; //!< Maximum output size from audio analysis
74 | };
75 |
76 | } // namespace driver
77 | #endif // INCLUDE_DEBUG_DUMMY_ANALYZER_H_
78 |
--------------------------------------------------------------------------------
/include/debug/dummy_decoder.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Dummy class for decoder support
4 | */
5 |
6 | #ifndef INCLUDE_DEBUG_DUMMY_DECODER_H_
7 | #define INCLUDE_DEBUG_DUMMY_DECODER_H_
8 |
9 | #include
10 |
11 | #include "audio/base/decoder.h"
12 | #include "model/application_error.h"
13 | #include "model/audio_filter.h"
14 | #include "model/song.h"
15 | #include "model/volume.h"
16 | #include "util/file_handler.h"
17 |
18 | namespace driver {
19 |
20 | /**
21 | * @brief Dummy implementation
22 | */
23 | class DummyDecoder : public Decoder {
24 | public:
25 | /**
26 | * @brief Construct a new Decoder object
27 | */
28 | DummyDecoder() = default;
29 |
30 | /**
31 | * @brief Destroy the Decoder object
32 | */
33 | virtual ~DummyDecoder() = default;
34 |
35 | /* ******************************************************************************************** */
36 | //! Public API that do not follow the instance lifecycle
37 |
38 | /**
39 | * @brief Check if file contains an available audio stream
40 | * @param file Full path to file
41 | * @return true if file contains an audio stream, false otherwise
42 | */
43 | static inline bool ContainsAudioStream(const util::File& file) { return true; }
44 |
45 | /* ******************************************************************************************** */
46 | //! Public API for Decoder
47 |
48 | /**
49 | * @brief Function invoked after resample is available.
50 | * (for better understanding: take a look at Audio Loop from Player, and also Playback class)
51 | */
52 | using AudioCallback = std::function;
53 |
54 | /**
55 | * @brief Open file as input stream and check for codec compatibility for decoding
56 | * @param audio_info (In/Out) In case of success, this is filled with detailed audio information
57 | * @return error::Code Application error code
58 | */
59 | error::Code OpenFile(model::Song& audio_info) override {
60 | audio_info = model::Song{.artist = "Dummy artist",
61 | .title = "Dummy title",
62 | .num_channels = 2,
63 | .sample_rate = 44100,
64 | .bit_rate = 320000,
65 | .bit_depth = 32,
66 | .duration = 120};
67 |
68 | return error::kSuccess;
69 | }
70 |
71 | /**
72 | * @brief Decode and resample input stream to desired sample format/rate
73 | * @param samples Maximum value of samples
74 | * @param callback Pass resamples to this callback
75 | * @return error::Code Application error code
76 | */
77 | error::Code Decode(int samples, AudioCallback callback) override {
78 | callback((void*)nullptr, 0, position_);
79 | return error::kSuccess;
80 | }
81 |
82 | /**
83 | * @brief After file is opened and decoded, or when some error occurs, always clear internal cache
84 | */
85 | void ClearCache() override {}
86 |
87 | /* ******************************************************************************************** */
88 | //! Public API for Equalizer
89 |
90 | /**
91 | * @brief Set volume on playback stream
92 | *
93 | * @param value Desired volume (in a range between 0.f and 1.f)
94 | * @return error::Code Decoder error converted to application error code
95 | */
96 | error::Code SetVolume(model::Volume value) override {
97 | volume_ = value;
98 | return error::kSuccess;
99 | }
100 |
101 | /**
102 | * @brief Get volume from playback stream
103 | * @return model::Volume Volume percentage (in a range between 0.f and 1.f)
104 | */
105 | model::Volume GetVolume() const override { return volume_; }
106 |
107 | /**
108 | * @brief Update audio filters in the filter chain (used for equalization)
109 | *
110 | * @param filters Audio filters
111 | * @return error::Code Decoder error converted to application error code
112 | */
113 | error::Code UpdateFilters(const model::EqualizerPreset& filters) override {
114 | return error::kSuccess;
115 | }
116 |
117 | /* ******************************************************************************************** */
118 | //! Variables
119 | private:
120 | model::Volume volume_; //!< Playback stream volume
121 | int64_t position_; //!< Audio position
122 | };
123 |
124 | } // namespace driver
125 | #endif // INCLUDE_DEBUG_DUMMY_DECODER_H_
126 |
--------------------------------------------------------------------------------
/include/debug/dummy_fetcher.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Dummy class for URL fetching support
4 | */
5 |
6 | #ifndef INCLUDE_DEBUG_DUMMY_FETCHER_H_
7 | #define INCLUDE_DEBUG_DUMMY_FETCHER_H_
8 |
9 | #include
10 |
11 | namespace driver {
12 |
13 | /**
14 | * @brief Dummy implementation
15 | */
16 | class DummyFetcher : public UrlFetcher {
17 | public:
18 | /**
19 | * @brief Construct a new DummyFetcher object
20 | */
21 | DummyFetcher() = default;
22 |
23 | /**
24 | * @brief Destroy the DummyFetcher object
25 | */
26 | virtual ~DummyFetcher() = default;
27 |
28 | /* ******************************************************************************************** */
29 | //! Public API
30 |
31 | /**
32 | * @brief Fetch content from the given URL
33 | * @param URL Endpoint address
34 | * @param output Output from fetch (out)
35 | * @return Error code from operation
36 | */
37 | error::Code Fetch(const std::string &URL, std::string &output) override {
38 | return error::kSuccess;
39 | }
40 | };
41 |
42 | } // namespace driver
43 | #endif // INCLUDE_DEBUG_DUMMY_FETCHER_H_
44 |
--------------------------------------------------------------------------------
/include/debug/dummy_parser.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Dummy class for HTML parsing support
4 | */
5 |
6 | #ifndef INCLUDE_DEBUG_DUMMY_PARSER_H_
7 | #define INCLUDE_DEBUG_DUMMY_PARSER_H_
8 |
9 | #include
10 | #include
11 |
12 | #include "model/application_error.h"
13 |
14 | namespace lyric {
15 |
16 | //! SongLyric declaration
17 | using SongLyric = std::vector;
18 |
19 | } // namespace lyric
20 |
21 | namespace driver {
22 |
23 | /**
24 | * @brief Dummy implementation
25 | */
26 | class DummyParser : public HtmlParser {
27 | public:
28 | /**
29 | * @brief Construct a new DummyParser object
30 | */
31 | DummyParser() = default;
32 |
33 | /**
34 | * @brief Destroy the DummyParser object
35 | */
36 | virtual ~DummyParser() = default;
37 |
38 | /* ******************************************************************************************** */
39 | //! Public API
40 |
41 | /**
42 | * @brief Parse buffer data based on the given XPath
43 | * @param data Buffer data
44 | * @param xpath XPath to find
45 | * @return Song lyrics parsed from buffer data
46 | */
47 | lyric::SongLyric Parse(const std::string &data, const std::string &xpath) override {
48 | return lyric::SongLyric{};
49 | }
50 | };
51 |
52 | } // namespace driver
53 | #endif // INCLUDE_DEBUG_DUMMY_PARSER_H_
54 |
--------------------------------------------------------------------------------
/include/debug/dummy_playback.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Interface class for playback support
4 | */
5 |
6 | #ifndef INCLUDE_DEBUG_DUMMY_PLAYBACK_H_
7 | #define INCLUDE_DEBUG_DUMMY_PLAYBACK_H_
8 |
9 | #include "audio/base/playback.h"
10 | #include "model/application_error.h"
11 | #include "model/volume.h"
12 |
13 | namespace driver {
14 |
15 | /**
16 | * @brief Dummy
17 | */
18 | class DummyPlayback : public Playback {
19 | public:
20 | /**
21 | * @brief Construct a new Playback object
22 | */
23 | DummyPlayback() = default;
24 |
25 | /**
26 | * @brief Destroy the Playback object
27 | */
28 | ~DummyPlayback() = default;
29 |
30 | /* ******************************************************************************************** */
31 | //! Public API
32 |
33 | /**
34 | * @brief Create a Playback Stream
35 | * @return error::Code Playback error converted to application error code
36 | */
37 | error::Code CreatePlaybackStream() override { return error::kSuccess; }
38 |
39 | /**
40 | * @brief Configure Playback Stream parameters (sample format, etc...)
41 | * @return error::Code Playback error converted to application error code
42 | */
43 | error::Code ConfigureParameters() override { return error::kSuccess; }
44 |
45 | /**
46 | * @brief Make playback stream ready to play
47 | * @return error::Code Playback error converted to application error code
48 | */
49 | error::Code Prepare() override { return error::kSuccess; }
50 |
51 | /**
52 | * @brief Pause current song on playback stream
53 | * @return error::Code Playback error converted to application error code
54 | */
55 | error::Code Pause() override { return error::kSuccess; }
56 |
57 | /**
58 | * @brief Stop playing song on playback stream
59 | * @return error::Code Playback error converted to application error code
60 | */
61 | error::Code Stop() override { return error::kSuccess; }
62 |
63 | /**
64 | * @brief Directly write audio buffer to playback stream (this should be called by decoder)
65 | *
66 | * @param buffer Audio data buffer
67 | * @param size Buffer size
68 | * @return error::Code Playback error converted to application error code
69 | */
70 | error::Code AudioCallback(void* buffer, int size) override { return error::kSuccess; }
71 |
72 | /**
73 | * @brief Set volume on playback stream
74 | *
75 | * @param value Desired volume (in a range between 0.f and 1.f)
76 | * @return error::Code Playback error converted to application error code
77 | */
78 | error::Code SetVolume(model::Volume value) override { return error::kSuccess; }
79 |
80 | /**
81 | * @brief Get volume from playback stream
82 | * @return model::Volume Volume percentage (in a range between 0.f and 1.f)
83 | */
84 | model::Volume GetVolume() override { return model::Volume(); }
85 |
86 | /**
87 | * @brief Get period size
88 | * @return uint32_t Period size
89 | */
90 | uint32_t GetPeriodSize() const override { return kPeriodSize; }
91 |
92 | /* ******************************************************************************************** */
93 | //! Constants
94 | private:
95 | static constexpr uint32_t kPeriodSize = 1024;
96 | };
97 |
98 | } // namespace driver
99 | #endif // INCLUDE_DEBUG_DUMMY_PLAYBACK_H_
100 |
--------------------------------------------------------------------------------
/include/model/application_error.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief All error codes from application in a single map
4 | */
5 |
6 | #ifndef INCLUDE_MODEL_APPLICATION_ERROR_H_
7 | #define INCLUDE_MODEL_APPLICATION_ERROR_H_
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | namespace error {
15 |
16 | //! To make life easier in the first versions, error is simple an int
17 | // TODO: next step is to add a level (like critical or non-critical, warning, ...)
18 | using Code = int;
19 |
20 | //! Everything fine!
21 | static constexpr Code kSuccess = 0;
22 | static constexpr Code kUnknownError = 99;
23 |
24 | //! Terminal errors
25 | static constexpr Code kTerminalInitialization = 1;
26 | static constexpr Code kTerminalColorsUnavailable = 2;
27 |
28 | //! File and directory navigation
29 | static constexpr Code kAccessDirFailed = 20;
30 |
31 | //! Song errors
32 | static constexpr Code kInvalidFile = 30;
33 | static constexpr Code kFileNotSupported = 31;
34 | static constexpr Code kFileCompressionNotSupported = 32;
35 | static constexpr Code kUnknownNumOfChannels = 33;
36 | static constexpr Code kInconsistentHeaderInfo = 34;
37 | static constexpr Code kCorruptedData = 35;
38 |
39 | //! ALSA driver errors
40 | static constexpr Code kSetupAudioParamsFailed = 50;
41 |
42 | //! FFMPEG driver errors
43 | static constexpr Code kDecodeFileFailed = 70;
44 | static constexpr Code kSeekFrameFailed = 71;
45 |
46 | /* ********************************************************************************************** */
47 |
48 | /**
49 | * @brief Class holding the map with all possible errors that may occur during application lifetime
50 | */
51 | class ApplicationError {
52 | private:
53 | //! Single entry for error message
54 | using Message = std::pair;
55 |
56 | //! Array similar to a map and contains all "mapped" errors (pun intended)
57 | static constexpr std::array kErrorMap{{
58 | {kTerminalInitialization, "Cannot initialize screen"},
59 | {kTerminalColorsUnavailable, "No support to change colors"},
60 | {kAccessDirFailed, "Cannot access directory"},
61 | {kInvalidFile, "Invalid file"},
62 | {kFileNotSupported, "File not supported"},
63 | {kFileCompressionNotSupported, "Decoding compressed file is not supported"},
64 | {kUnknownNumOfChannels,
65 | "File does not seem to be neither mono nor stereo (perhaps multi-track or corrupted)"},
66 | {kInconsistentHeaderInfo, "Header data is inconsistent"},
67 | {kCorruptedData, "File is corrupted"},
68 | {kSetupAudioParamsFailed, "Cannot set audio parameters"},
69 | {kDecodeFileFailed, "Cannot decode song"},
70 | {kSeekFrameFailed, "Cannot seek frame in song"},
71 | {kUnknownError, "Unknown error used for almost everything during development =)"},
72 | }};
73 |
74 | /* ******************************************************************************************** */
75 | public:
76 | /**
77 | * @brief Get the error associated to the specific code
78 | *
79 | * @param code Error code
80 | * @return Message Error detail
81 | */
82 | static std::string_view GetMessage(Code id) {
83 | auto find_error = [&id](Message element) { return element.first == id; };
84 |
85 | auto error = std::find_if(kErrorMap.begin(), kErrorMap.end(), find_error);
86 | assert(error != kErrorMap.end());
87 |
88 | return error->second;
89 | }
90 | };
91 |
92 | } // namespace error
93 | #endif // INCLUDE_MODEL_APPLICATION_ERROR_H_
--------------------------------------------------------------------------------
/include/model/audio_filter.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * \brief Base class for an audio filter
4 | */
5 |
6 | #ifndef INCLUDE_MODEL_AUDIO_FILTER_H_
7 | #define INCLUDE_MODEL_AUDIO_FILTER_H_
8 |
9 | #include
10 | #include
11 | #include