Discman
Loading...
Searching...
No Matches
application.cc
Go to the documentation of this file.
1
6
7#include "application.h"
8
9Application::Application(int argc, char **argv)
10 : _argc(argc)
11 , _argv(argv)
12 , _ripper(nullptr)
13 , _audio_output(AudioOutput<int16_t>::instance())
14 , _track(0)
15{
16 _audio_output->producer(&_drive_manager.disc_drive());
17 _audio_output->init();
18
20
21 _app = Gtk::Application::create("com.nirjacobson.discman");
22 _app->signal_activate().connect(sigc::mem_fun(*this, &Application::on_activate));
23
24 _builder = Gtk::Builder::create();
25 _builder->add_from_resource("/ui/discman.glade");
26
27 _stack = _builder->get_widget<Gtk::Stack>("stack");
28 _bluetooth_box = _builder->get_widget<Gtk::Box>("bluetoothBox");
29 _player_box = _builder->get_widget<Gtk::Box>("playerBox");
30 _album_art_box = _builder->get_widget<Gtk::Box>("albumArtBox");
31 _shutdown_button = _builder->get_widget<Gtk::Button>("shutdownButton");
32
34 _disc_component->set_disc(nullptr);
35 _disc_component->signal_eject_requested().connect(sigc::mem_fun(*this, &Application::eject));
36 _disc_component->signal_rip_requested().connect(sigc::mem_fun(*this, &Application::rip));
37 _disc_component->signal_track_selected().connect(sigc::mem_fun(*this, &Application::on_track_selected));
38
40 _now_playing_component->signal_button().connect(sigc::mem_fun(*this, &Application::on_button));
41 _now_playing_component->signal_album_art().connect(sigc::mem_fun(*this, &Application::on_album_art_button));
42
44 _album_art_component->signal_done().connect(sigc::mem_fun(*this, &Application::on_album_art_done));
45 _album_art_component->signal_art().connect(sigc::mem_fun(*this, &Application::on_album_art_art));
46
48 _bluetooth_component->signal_connected().connect(sigc::mem_fun(*this, &Application::on_bluetooth_connected));
49 _bluetooth_component->signal_done().connect(sigc::mem_fun(*this, &Application::on_bluetooth_done));
50 _bluetooth_component->signal_button().connect(sigc::mem_fun(*this, &Application::on_bluetooth_button));
51
52 _shutdown_button->signal_clicked().connect(sigc::mem_fun(*this, &Application::on_shutdown_button));
53
54 _window = _builder->get_widget<Gtk::Window>("window");
55
56 _drive_manager.signal_inserted().connect(sigc::mem_fun(*this, &Application::on_insert));
57 _drive_manager.signal_ejected().connect(sigc::mem_fun(*this, &Application::on_eject));
58
59 _systemd_proxy = Gio::DBus::Proxy::create_for_bus_sync(
60 Gio::DBus::BusType::SYSTEM,
61 "org.freedesktop.login1",
62 "/org/freedesktop/login1",
63 "org.freedesktop.login1.Manager");
64}
65
67 delete _player_box;
68 delete _bluetooth_box;
69 delete _album_art_box;
70 delete _shutdown_button;
71 delete _stack;
72 delete _window;
76 delete _disc_component;
77
78 _audio_output->destroy();
79
81}
82
84 _app->run(_argc, _argv);
85}
86
88 if (drive == DriveManager::Drive::Disc) {
90 _disc_component->set_disc(&_disc);
91
92 std::vector<AlbumArtProvider::AlbumArt> arts = AlbumArtProvider::instance()->album_art(_disc.artist(), _disc.title(), AlbumArtComponent::ART_SIZE, AlbumArtComponent::ART_SIZE);
93
94 _album_art_component->set_album_arts(arts, _window->get_width());
95 _now_playing_component->set_album(_album_art_url = arts[0].url);
97
98 _disc_component->show_double_eject_button(_drive_manager.is_removable_present());
99
100 if (_drive_manager.is_removable_present()) {
101 }
102 } else if (drive == DriveManager::Drive::Removable) {
103 _disc_component->show_ipod_button(true);
104
105 _disc_component->show_double_eject_button(_drive_manager.is_disc_present());
106 _disc_component->enable_ipod_button(_drive_manager.is_disc_present());
107 }
108};
109
110
112 _disc_component->show_double_eject_button(false);
113 _disc_component->enable_eject_button(_drive_manager.is_disc_present() || _drive_manager.is_removable_present());
114
115 if (drive == DriveManager::Drive::Disc) {
116 _disc_component->set_disc(nullptr);
118
119 if (_drive_manager.is_removable_present()) {
120 _disc_component->enable_ipod_button(false);
121 }
122 } else if (drive == DriveManager::Drive::Removable) {
123 _disc_component->show_ipod_button(false);
124 }
125};
126
128 DiscDB::Disc::Builder builder;
129
130 for (unsigned int i = 0; i < _drive_manager.disc_drive().tracks(); i++) {
131 builder.track(DiscDB::Track::Builder()
132 .frame_offset(_drive_manager.disc_drive().lba(1 + i))
133 .build());
134 }
135
136 const DiscDB::Disc disc = builder
137 .length(_drive_manager.disc_drive().seconds())
138 .calculate_disc_id()
139 .build();
140
141 _disc = DiscDB::find(disc);
142}
143
145 _app->add_window(*_window);
146 _window->show();
147}
148
150 _stack->set_visible_child(*_bluetooth_box);
151 _bluetooth_component->on_show();
152}
153
155 _stack->set_visible_child(*_album_art_box);
156}
157
159 Glib::signal_timeout().connect([this]() {
160 _audio_output->restart();
161 _bluetooth_component->on_device_initialization_complete(true);
162 return false;
163 }, 1000);
164}
165
167 _bluetooth_component->on_hide();
168 _stack->set_visible_child(*_player_box);
169}
170
172 _stack->set_visible_child(*_player_box);
173}
174
175void Application::on_album_art_art(const std::string url) {
176 _now_playing_component->set_album(_album_art_url = url);
178}
179
180void Application::on_track_selected(unsigned int track) {
181 play(track);
182}
183
185 switch (button) {
187 play(_track - 1);
188 break;
191 pause();
192 } else {
193 play();
194 }
195 break;
197 stop();
198 break;
200 play(_track + 1);
201 break;
202 }
203}
204
206 if (_drive_manager.disc_drive().done()) {
208 } else {
209 if (_track > 0 && _track != _drive_manager.disc_drive().track()) {
210 _track = _drive_manager.disc_drive().track();
211 _disc_component->set_selection(_track);
212 _now_playing_component->set_track(_disc, _track, _track == 1, _track == _disc.tracks().size());
213 }
214 _now_playing_component->set_seconds(_drive_manager.disc_drive().elapsed());
215 }
216
217 return true;
218}
219
221 _systemd_proxy->call_sync("PowerOff", Glib::VariantContainerBase::create_tuple(Glib::Variant<bool>::create(false)));
222}
223
224void Application::play(unsigned int track) {
226 stop();
227
228 _track = track;
229
230 _drive_manager.disc_drive().track(track);
231 _disc_component->set_selection(track);
232 _now_playing_component->set_track(_disc, _track, track == 1, track == _disc.tracks().size());
233 play();
234}
235
237 if (_track == 0) {
238 play(1);
239 } else {
240 _timer_connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Application::on_timeout), 250);
241 _audio_output->start();
243 }
244}
245
251
253 _track = 0;
254
255 _timer_connection.disconnect();
256 _audio_output->stop();
257 _disc_component->clear_selection();
259}
260
262 if (drive == DriveManager::Drive::Disc) {
264 stop();
265 }
266 }
267
268 _drive_manager.eject(drive);
269}
270
271void Application::rip(unsigned int track) {
272 _track = 0;
273
274 _timer_connection.disconnect();
275 _audio_output->stop();
276 _disc_component->clear_selection();
278
279 _disc_component->enable_ipod_button(false);
280 _disc_component->show_progress(true);
281
282 _ripper = new CDRipper(_drive_manager.disc_drive(), _disc, _album_art_url, _drive_manager.removable().mount_point());
283
284 _ripper->signal_track_progress().connect(sigc::mem_fun(*this, &Application::on_track_progress));
285 _ripper->signal_done().connect(sigc::mem_fun(*this, &Application::on_rip_done));
286
287 _drive_manager.disc_drive().resize_buffer(CDDrive::BUFFER_SIZE_RIPPING);
288
289 if (track == 0) {
290 _ripper->rip();
291 } else {
292 _ripper->rip(track);
293 }
294}
295
296void Application::on_track_progress(const unsigned track, const unsigned progress) {
297 _disc_component->update_track_progress(track, progress);
298}
299
301 _disc_component->enable_ipod_button(true);
302
303 delete _ripper;
304
305 _drive_manager.disc_drive().resize_buffer(CDDrive::BUFFER_SIZE_PLAYING);
306
307 _track = 0;
308 _timer_connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Application::on_timeout), 250);
310}
Handles the interactions with the album art selection screen.
static constexpr int ART_SIZE
The width and height of art displayed on the album art selection screen.
virtual std::vector< AlbumArt > album_art(const std::string &artist, const std::string &title, const int width, const int height)=0
Return all album art matching the criteria, at a specific width and height.
static void destroy()
Destroys the AlbumArtProvider.
static AlbumArtProvider * instance()
Factory method to return the album art provider. It may be called one or more times....
AudioOutput< int16_t > * _audio_output
The audio output.
Definition application.h:64
void on_album_art_button()
AlbumArtComponent done button handler.
void on_shutdown_button()
Shutdown button handler.
void on_album_art_done()
Called when the AlbumArtComponent done button is clicked.
void on_bluetooth_button()
Bluetooth button handler.
Glib::RefPtr< Gio::DBus::Proxy > _systemd_proxy
The systemd D-Bus proxy, used for host shutdown.
Definition application.h:68
void stop()
Stop handler.
Gtk::Stack * _stack
Stack that switches between application screens.
Definition application.h:76
sigc::connection _timer_connection
A connection of a timer to the callback that periodically checks the current track state.
Definition application.h:70
void on_track_progress(unsigned int track, unsigned int progress)
Called when the CDRipper reports progress on a certain track.
NowPlayingComponent * _now_playing_component
Handles the left-hand side of the main application screen showing album art and current track.
Definition application.h:89
Gtk::Box * _player_box
Box holding the main application screen.
Definition application.h:77
void on_rip_done()
Called when the CDRipper reports it is done.
void eject(const DriveManager::Drive drive)
Instructs the DriveManager to eject a drive.
void on_button(const NowPlayingComponent::Button button)
Called when a playback control button (prev/next, play/pause, stop) is clicked.
void on_eject(DriveManager::Drive drive)
Called when a drive (disc or iPod/thumb drive) is removed.
DiscComponent * _disc_component
Handles the album labels, track listing and eject/rip buttons on the main application screen.
Definition application.h:88
void rip(unsigned int track)
Instructs the CDRipper to begin ripping one specific track.
void query_discdb()
Queries DiscDB for the full information of the disc inserted.
Gtk::Button * _shutdown_button
Shutdown button.
Definition application.h:94
Gtk::Window * _window
Reference to the application window.
Definition application.h:60
void run()
Runs Discman.
std::string _album_art_url
The URL of the currently displayed album art.
Definition application.h:66
bool on_timeout()
Called when the track monitoring timer reaches zero.
DriveManager _drive_manager
Drive manager.
Definition application.h:61
~Application()
Application destructor.
Application(int argc, char **argv)
Application constructor.
Definition application.cc:9
DiscDB::Disc _disc
The Disc returned by DiscDB for the inserted CD.
Definition application.h:63
void on_track_selected(unsigned int track)
Called when a track is selected in the DiscComponent.
BluetoothComponent * _bluetooth_component
Handles the Bluetooth device selection screen.
Definition application.h:90
void on_insert(DriveManager::Drive drive)
Called when a drive (disc or iPod/thumb drive) is inserted.
Gtk::Box * _bluetooth_box
Box holding the Bluetooth device selection screen.
Definition application.h:78
void on_activate()
Called when _app is activated.
unsigned int _track
The current 1-based track being played.
Definition application.h:65
Glib::RefPtr< Gtk::Application > _app
The underlying Gtk::Application.
Definition application.h:59
Glib::RefPtr< Gtk::Builder > _builder
The builder initialized with the Discman UI.
Definition application.h:58
void pause()
Pause handler.
char ** _argv
The application arguments.
Definition application.h:56
int _argc
The application argument count.
Definition application.h:55
void on_album_art_art(const std::string url)
Called when album art is selected in the AlbumArtComponent.
void play()
Play handler.
AlbumArtComponent * _album_art_component
Handles the album art selection screen.
Definition application.h:91
void on_bluetooth_connected()
Called when the user connects to a Bluetooth device.
Gtk::Box * _album_art_box
Box holding the album art selection screen.
Definition application.h:79
CDRipper * _ripper
CD ripper.
Definition application.h:62
void on_bluetooth_done()
Called when the BluetoothComponent done button is clicked.
Abstracts PortAudio using a given audio sample data type.
Handles the interactions with the Bluetooth device selection screen.
static constexpr int BUFFER_SIZE_PLAYING
The audio buffer size when playing, in CD audio frames.
Definition cd_drive.h:42
static constexpr int BUFFER_SIZE_RIPPING
The audio buffer size when ripping, in CD audio frames.
Definition cd_drive.h:43
Rips CDs and individual tracks to M4A files.
Definition cd_ripper.h:41
Handles the interactions with the album labels, track listing and ipod/eject buttons.
Drive
The two drives supported.
Handles the interactions with the "now playing" side of the main screen.
Button
Playback control button identifiers.