Serenity Operating System
at hosted 123 lines 4.8 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "AudioEngine.h" 29#include "MainWidget.h" 30#include <LibAudio/ClientConnection.h> 31#include <LibAudio/WavWriter.h> 32#include <LibCore/EventLoop.h> 33#include <LibCore/File.h> 34#include <LibGUI/AboutDialog.h> 35#include <LibGUI/Action.h> 36#include <LibGUI/Application.h> 37#include <LibGUI/FilePicker.h> 38#include <LibGUI/Menu.h> 39#include <LibGUI/MenuBar.h> 40#include <LibGUI/MessageBox.h> 41#include <LibGUI/Window.h> 42#include <LibGfx/Bitmap.h> 43#include <LibThread/Thread.h> 44 45int main(int argc, char** argv) 46{ 47 GUI::Application app(argc, argv); 48 49 auto audio_client = Audio::ClientConnection::construct(); 50 audio_client->handshake(); 51 52 AudioEngine audio_engine; 53 54 auto window = GUI::Window::construct(); 55 auto& main_widget = window->set_main_widget<MainWidget>(audio_engine); 56 window->set_title("Piano"); 57 window->set_rect(90, 90, 840, 600); 58 window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-piano.png")); 59 window->show(); 60 61 Audio::WavWriter wav_writer; 62 Optional<String> save_path; 63 bool need_to_write_wav = false; 64 65 LibThread::Thread audio_thread([&] { 66 auto audio = Core::File::construct("/dev/audio"); 67 if (!audio->open(Core::IODevice::WriteOnly)) { 68 dbgprintf("Can't open audio device: %s", audio->error_string()); 69 return 1; 70 } 71 72 FixedArray<Sample> buffer(sample_count); 73 for (;;) { 74 audio_engine.fill_buffer(buffer); 75 audio->write(reinterpret_cast<u8*>(buffer.data()), buffer_size); 76 Core::EventLoop::current().post_event(main_widget, make<Core::CustomEvent>(0)); 77 Core::EventLoop::wake(); 78 79 if (need_to_write_wav) { 80 need_to_write_wav = false; 81 audio_engine.reset(); 82 audio_engine.set_should_loop(false); 83 do { 84 audio_engine.fill_buffer(buffer); 85 wav_writer.write_samples(reinterpret_cast<u8*>(buffer.data()), buffer_size); 86 } while (audio_engine.time()); 87 audio_engine.reset(); 88 audio_engine.set_should_loop(true); 89 wav_writer.finalize(); 90 } 91 } 92 }); 93 audio_thread.start(); 94 95 auto menubar = make<GUI::MenuBar>(); 96 97 auto& app_menu = menubar->add_menu("Piano"); 98 app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) { 99 GUI::Application::the().quit(0); 100 return; 101 })); 102 app_menu.add_action(GUI::Action::create("Export", { Mod_Ctrl, Key_E }, [&](const GUI::Action&) { 103 save_path = GUI::FilePicker::get_save_filepath("Untitled", "wav"); 104 if (!save_path.has_value()) 105 return; 106 wav_writer.set_file(save_path.value()); 107 if (wav_writer.has_error()) { 108 GUI::MessageBox::show(String::format("Failed to export WAV file: %s", wav_writer.error_string()), "Error", GUI::MessageBox::Type::Error); 109 wav_writer.clear_error(); 110 return; 111 } 112 need_to_write_wav = true; 113 })); 114 115 auto& help_menu = menubar->add_menu("Help"); 116 help_menu.add_action(GUI::Action::create("About", [&](const GUI::Action&) { 117 GUI::AboutDialog::show("Piano", Gfx::Bitmap::load_from_file("/res/icons/32x32/app-piano.png"), window); 118 })); 119 120 app.set_menubar(move(menubar)); 121 122 return app.exec(); 123}