From 7246ab94b784822e724e836f84bdc26bf8130fdc Mon Sep 17 00:00:00 2001 From: mrbesen Date: Mon, 20 Dec 2021 00:19:35 +0100 Subject: [PATCH] new dialog to add samples (basic) --- include/editsample.h | 22 +++++++ include/mainwindow.h | 1 + include/samplereader.h | 25 ++++++++ include/sound.h | 5 ++ include/soundview.h | 28 +++++++++ soundboard.pro | 7 +++ src/editsample.cpp | 10 ++++ src/mainwindow.cpp | 29 ++++++++++ src/samplereader.cpp | 54 ++++++++++++++++++ src/sound.cpp | 4 ++ src/soundview.cpp | 56 ++++++++++++++++++ ui/editsample.ui | 127 +++++++++++++++++++++++++++++++++++++++++ ui/mainwindow.ui | 10 ++++ 13 files changed, 378 insertions(+) create mode 100644 include/editsample.h create mode 100644 include/samplereader.h create mode 100644 include/soundview.h create mode 100644 src/editsample.cpp create mode 100644 src/samplereader.cpp create mode 100644 src/soundview.cpp create mode 100644 ui/editsample.ui diff --git a/include/editsample.h b/include/editsample.h new file mode 100644 index 0000000..7f2e5df --- /dev/null +++ b/include/editsample.h @@ -0,0 +1,22 @@ +#ifndef EDITSAMPLE_H +#define EDITSAMPLE_H + +#include + +namespace Ui { + class EditSample; +} + +class EditSample : public QDialog +{ + Q_OBJECT + +public: + explicit EditSample(QWidget *parent = nullptr); + ~EditSample(); + +private: + Ui::EditSample *ui; +}; + +#endif // EDITSAMPLE_H diff --git a/include/mainwindow.h b/include/mainwindow.h index 5f5dafc..77a8452 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -34,6 +34,7 @@ public slots: private slots: void alwaysOnTopSettingChange(int status); + void addSample(); signals: void newStatusMessage(const QString&); diff --git a/include/samplereader.h b/include/samplereader.h new file mode 100644 index 0000000..0600d71 --- /dev/null +++ b/include/samplereader.h @@ -0,0 +1,25 @@ +#pragma once + +#include "miniaudio.h" + +#include +#include + +class SampleReader { +private: + SampleReader(); +public: + //returns nullptr on error + static SampleReader* createSampleReader(const std::string& filepath); + ~SampleReader(); + + void setWidth(uint32_t w); + + float readSample(uint32_t pos); +private: + ma_decoder decoder; + + uint32_t width = 1; + uint64_t decoderSize = 0; + uint32_t stepSize = 0; +}; \ No newline at end of file diff --git a/include/sound.h b/include/sound.h index d8f3c4c..10afd43 100644 --- a/include/sound.h +++ b/include/sound.h @@ -9,6 +9,9 @@ #include #include "sounddevice.h" +#include "samplereader.h" + +#include "sound.h" class Sound { public: @@ -21,6 +24,8 @@ public: void stopAll(); void reset(); + SampleReader* openFile(const std::string& name); + static std::string FOLDER; private: Sound(); diff --git a/include/soundview.h b/include/soundview.h new file mode 100644 index 0000000..cfa032f --- /dev/null +++ b/include/soundview.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "samplereader.h" + +class SoundView : public QGraphicsView { + Q_OBJECT + +public: + explicit SoundView(QWidget* parent = nullptr); + ~SoundView(); + + void loadFile(const std::string& file); + + void redraw(); + + void paintEvent(QPaintEvent*) override; + void resizeEvent(QResizeEvent*) override; +private: + QGraphicsScene scene; + + SampleReader* samples = nullptr; + + std::string file; + uint64_t offset = 0; + uint64_t length = 0; +}; \ No newline at end of file diff --git a/soundboard.pro b/soundboard.pro index 841a151..919427d 100644 --- a/soundboard.pro +++ b/soundboard.pro @@ -24,6 +24,9 @@ SOURCES += \ src/sounddevice.cpp \ src/soundbutton.cpp \ src/config.cpp \ + src/editsample.cpp \ + src/soundview.cpp \ + src/samplereader.cpp \ Log/Log.cpp HEADERS += \ @@ -33,6 +36,9 @@ HEADERS += \ include/soundbutton.h \ miniaudio/miniaudio.h \ include/config.h \ + include/editsample.h \ + include/soundview.h \ + include/samplereader.h \ Log/Log.h MOC_DIR = generated/ @@ -40,6 +46,7 @@ UI_DIR = ui/ OBJECTS_DIR = obj/ FORMS += \ + ui/editsample.ui \ ui/mainwindow.ui TRANSLATIONS += \ diff --git a/src/editsample.cpp b/src/editsample.cpp new file mode 100644 index 0000000..96cd9d8 --- /dev/null +++ b/src/editsample.cpp @@ -0,0 +1,10 @@ +#include "editsample.h" +#include "ui_editsample.h" + +EditSample::EditSample(QWidget *parent) : QDialog(parent), ui(new Ui::EditSample) { + ui->setupUi(this); +} + +EditSample::~EditSample() { + delete ui; +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5ede1f0..0b4fbdb 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,6 +1,10 @@ #include "mainwindow.h" #include "ui_mainwindow.h" +#include "editsample.h" + +#include + #include #include @@ -22,6 +26,7 @@ MainWindow::MainWindow(const std::string& binary, QWidget* parent) : QMainWindow QObject::connect(ui->reloadButton, SIGNAL(clicked()), this, SLOT(reloadConfig())); QObject::connect(ui->stopButton, SIGNAL( clicked() ), this, SLOT( stop() )); + QObject::connect(ui->addButton, SIGNAL( clicked() ), this, SLOT( addSample() )); QObject::connect(ui->allwaysOnTop, SIGNAL( stateChanged(int) ), this, SLOT( alwaysOnTopSettingChange(int) )); QObject::connect(stopGlobal, SIGNAL( activated() ), this, SLOT( stop() )); QObject::connect(this, SIGNAL(newStatusMessage(const QString&)), ui->statusbar, SLOT(showMessage(const QString&))); @@ -129,6 +134,30 @@ void MainWindow::alwaysOnTopSettingChange(int status) { show(); } +void MainWindow::addSample() { + Log::debug << "open sampleEditor"; + + QFileDialog fileselector(this); + fileselector.setFileMode(QFileDialog::ExistingFile); + fileselector.setDirectory(QString::fromStdString(Sound::FOLDER)); + fileselector.exec(); + + QStringList filelist = fileselector.selectedFiles(); + if(filelist.size() != 1) { + Log::error << "no file selected"; + return; + } else { + QString qfile = filelist.at(0); + std::string file = qfile.toStdString(); + file = file.substr(file.rfind('/')+1); + Log::info << "selected file: " << file; + } + + EditSample esample(this); + esample.exec(); +} + + void MainWindow::loadSoundFromConfig() { Sound& sound = Sound::instance(); // init sound sound.reset(); diff --git a/src/samplereader.cpp b/src/samplereader.cpp new file mode 100644 index 0000000..afc594d --- /dev/null +++ b/src/samplereader.cpp @@ -0,0 +1,54 @@ +#include "samplereader.h" + +#include +#include + +#define CHANNELCOUNT 2 + +SampleReader::SampleReader() {} + +//returns nullptr on error +SampleReader* SampleReader::createSampleReader(const std::string& filepath) { + SampleReader* sr = new SampleReader(); + + if (ma_decoder_init_file((filepath).c_str(), NULL, &(sr->decoder)) != MA_SUCCESS) { + Log::error << "Sound file: " << filepath << " could not be loaded"; + delete sr; + return nullptr; + } + + sr->decoderSize = ma_decoder_get_length_in_pcm_frames(&(sr->decoder)); + + return sr; +} + +SampleReader::~SampleReader() { + ma_decoder_uninit(&decoder); +} + +void SampleReader::setWidth(uint32_t w){ + width = w; + stepSize = decoderSize / (double) w; + Log::info << "SampleReaderWidth: " << w << " " << stepSize; +} + +float SampleReader::readSample(uint32_t pos) { + double acc = 0; + + ma_decoder_seek_to_pcm_frame(&decoder, stepSize * pos); + int16_t* buffer = new int16_t[stepSize * decoder.outputChannels]; + const uint64_t read = ma_decoder_read_pcm_frames(&decoder, buffer, stepSize); + if(read == 0) { + Log::error << "no sample could be read"; + return 0; + } + for(uint64_t i = 0; i < read * decoder.outputChannels; i += decoder.outputChannels) { + acc += buffer[i]; + } + delete[] buffer; + + float avg = (float) ((acc / (double) (std::numeric_limits::max())) / (double) read); + if(avg > 1) avg = 1; + else if(avg < 0) avg = 0; + return avg; +} \ No newline at end of file diff --git a/src/sound.cpp b/src/sound.cpp index 84e0992..2db208f 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -109,6 +109,10 @@ void Sound::reset() { Log::info << "ResetAudio done"; } +SampleReader* Sound::openFile(const std::string& name) { + return SampleReader::createSampleReader(FOLDER + name); +} + Sound::Sound() { init(); startBackgroundThread(); diff --git a/src/soundview.cpp b/src/soundview.cpp new file mode 100644 index 0000000..e95724a --- /dev/null +++ b/src/soundview.cpp @@ -0,0 +1,56 @@ +#include "soundview.h" + +#include "sound.h" +#include + +#include + +SoundView::SoundView(QWidget* parent) : QGraphicsView(parent) { + setScene(&scene); + + redraw(); +} + +SoundView::~SoundView() { + delete samples; +} + +void SoundView::loadFile(const std::string& file) { + samples = Sound::instance().openFile(file); +} + +void SoundView::redraw() { + //Log::debug << "redraw SoundView"; + scene.clear(); + + scene.setBackgroundBrush(QBrush(Qt::GlobalColor::black)); + scene.addRect(0, 0, width()-4, height()-4, QPen(Qt::green)); + + uint32_t h = scene.height()-4; + + //Log::info << "scene Size: " << scene.width() << " " << scene.height() << " " << width() << " " << height(); + + scene.addLine(0, h/2, scene.width()-4, h/2, QPen(Qt::red)); + +/* + for(uint32_t x = 0; x < width(); ++x) { + float s = samples->readSample(x); + scene.addLine(x, h/2, x, s*h, QPen(Qt::white)); + //Log::info << "Line: " << x << " " << h/2; + } + */ +} + +void SoundView::paintEvent(QPaintEvent* event) { + QGraphicsView::paintEvent(event); + + redraw(); +} + +void SoundView::resizeEvent(QResizeEvent* event) { + QGraphicsView::resizeEvent(event); + + if(samples) { + samples->setWidth(event->size().width()); + } +} diff --git a/ui/editsample.ui b/ui/editsample.ui new file mode 100644 index 0000000..88d9046 --- /dev/null +++ b/ui/editsample.ui @@ -0,0 +1,127 @@ + + + EditSample + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + + + + 0 + 0 + + + + + + + + false + + + + + + + + + Start: + + + + + + + mm:ss.z + + + + + + + Length: + + + + + + + mm:ss.z + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Save + + + false + + + + + + + + SoundView + QWidget +
soundview.h
+
+
+ + + + buttonBox + accepted() + EditSample + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + EditSample + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index f95ca9e..b845542 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -40,6 +40,16 @@ + + + + true + + + + + + +