forked from MrBesen/soundboard
new dialog to add samples (basic)
This commit is contained in:
parent
2f0c25c421
commit
7246ab94b7
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef EDITSAMPLE_H
|
||||||
|
#define EDITSAMPLE_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class EditSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditSample : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit EditSample(QWidget *parent = nullptr);
|
||||||
|
~EditSample();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::EditSample *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EDITSAMPLE_H
|
|
@ -34,6 +34,7 @@ public slots:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void alwaysOnTopSettingChange(int status);
|
void alwaysOnTopSettingChange(int status);
|
||||||
|
void addSample();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newStatusMessage(const QString&);
|
void newStatusMessage(const QString&);
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "miniaudio.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
|
@ -9,6 +9,9 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "sounddevice.h"
|
#include "sounddevice.h"
|
||||||
|
#include "samplereader.h"
|
||||||
|
|
||||||
|
#include "sound.h"
|
||||||
|
|
||||||
class Sound {
|
class Sound {
|
||||||
public:
|
public:
|
||||||
|
@ -21,6 +24,8 @@ public:
|
||||||
void stopAll();
|
void stopAll();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
SampleReader* openFile(const std::string& name);
|
||||||
|
|
||||||
static std::string FOLDER;
|
static std::string FOLDER;
|
||||||
private:
|
private:
|
||||||
Sound();
|
Sound();
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtWidgets/QGraphicsView>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
|
@ -24,6 +24,9 @@ SOURCES += \
|
||||||
src/sounddevice.cpp \
|
src/sounddevice.cpp \
|
||||||
src/soundbutton.cpp \
|
src/soundbutton.cpp \
|
||||||
src/config.cpp \
|
src/config.cpp \
|
||||||
|
src/editsample.cpp \
|
||||||
|
src/soundview.cpp \
|
||||||
|
src/samplereader.cpp \
|
||||||
Log/Log.cpp
|
Log/Log.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
@ -33,6 +36,9 @@ HEADERS += \
|
||||||
include/soundbutton.h \
|
include/soundbutton.h \
|
||||||
miniaudio/miniaudio.h \
|
miniaudio/miniaudio.h \
|
||||||
include/config.h \
|
include/config.h \
|
||||||
|
include/editsample.h \
|
||||||
|
include/soundview.h \
|
||||||
|
include/samplereader.h \
|
||||||
Log/Log.h
|
Log/Log.h
|
||||||
|
|
||||||
MOC_DIR = generated/
|
MOC_DIR = generated/
|
||||||
|
@ -40,6 +46,7 @@ UI_DIR = ui/
|
||||||
OBJECTS_DIR = obj/
|
OBJECTS_DIR = obj/
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
|
ui/editsample.ui \
|
||||||
ui/mainwindow.ui
|
ui/mainwindow.ui
|
||||||
|
|
||||||
TRANSLATIONS += \
|
TRANSLATIONS += \
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -1,6 +1,10 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
|
#include "editsample.h"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -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->reloadButton, SIGNAL(clicked()), this, SLOT(reloadConfig()));
|
||||||
QObject::connect(ui->stopButton, SIGNAL( clicked() ), this, SLOT( stop() ));
|
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(ui->allwaysOnTop, SIGNAL( stateChanged(int) ), this, SLOT( alwaysOnTopSettingChange(int) ));
|
||||||
QObject::connect(stopGlobal, SIGNAL( activated() ), this, SLOT( stop() ));
|
QObject::connect(stopGlobal, SIGNAL( activated() ), this, SLOT( stop() ));
|
||||||
QObject::connect(this, SIGNAL(newStatusMessage(const QString&)), ui->statusbar, SLOT(showMessage(const QString&)));
|
QObject::connect(this, SIGNAL(newStatusMessage(const QString&)), ui->statusbar, SLOT(showMessage(const QString&)));
|
||||||
|
@ -129,6 +134,30 @@ void MainWindow::alwaysOnTopSettingChange(int status) {
|
||||||
show();
|
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() {
|
void MainWindow::loadSoundFromConfig() {
|
||||||
Sound& sound = Sound::instance(); // init sound
|
Sound& sound = Sound::instance(); // init sound
|
||||||
sound.reset();
|
sound.reset();
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include "samplereader.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <Log.h>
|
||||||
|
|
||||||
|
#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<int16_t>::max())) / (double) read);
|
||||||
|
if(avg > 1) avg = 1;
|
||||||
|
else if(avg < 0) avg = 0;
|
||||||
|
return avg;
|
||||||
|
}
|
|
@ -109,6 +109,10 @@ void Sound::reset() {
|
||||||
Log::info << "ResetAudio done";
|
Log::info << "ResetAudio done";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SampleReader* Sound::openFile(const std::string& name) {
|
||||||
|
return SampleReader::createSampleReader(FOLDER + name);
|
||||||
|
}
|
||||||
|
|
||||||
Sound::Sound() {
|
Sound::Sound() {
|
||||||
init();
|
init();
|
||||||
startBackgroundThread();
|
startBackgroundThread();
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include "soundview.h"
|
||||||
|
|
||||||
|
#include "sound.h"
|
||||||
|
#include <Log.h>
|
||||||
|
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>EditSample</class>
|
||||||
|
<widget class="QDialog" name="EditSample">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="SoundView" name="graphicsView" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="soundOutputselect">
|
||||||
|
<property name="editable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="timeRow">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="startlabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Start:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTimeEdit" name="startTime">
|
||||||
|
<property name="displayFormat">
|
||||||
|
<string>mm:ss.z</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lengthlabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Length:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTimeEdit" name="lengthTime">
|
||||||
|
<property name="displayFormat">
|
||||||
|
<string>mm:ss.z</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
|
||||||
|
</property>
|
||||||
|
<property name="centerButtons">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>SoundView</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>soundview.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>EditSample</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>EditSample</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
|
@ -40,6 +40,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>+</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
Loading…
Reference in New Issue