/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
* mainwindow.cc
*
* Tue Nov 10 10:21:04 CET 2009
* Copyright 2009 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
/*
* This file is part of DrumGizmo.
*
* DrumGizmo is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DrumGizmo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "mainwindow.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QStatusBar>
#include <QApplication>
#include <QDockWidget>
#include <QSettings>
#include <QToolBar>
#include <QAction>
#include <QMenuBar>
#include <QFileDialog>
#include <QIntValidator>
#include <QTabWidget>
#include <QProgressBar>
#include <QTime>
#include <QSpinBox>
#include "sleep.h"
#include "canvastool.h"
#include "canvastoolthreshold.h"
#include "volumefader.h"
#include "selectioneditor.h"
#define MAXVAL 10000000L
#define SINGLESTEP MAXVAL/100000
#define PAGESTEP MAXVAL/10000
static void addTool(QToolBar *toolbar, Canvas *canvas, CanvasTool *tool)
{
QAction *action = new QAction(tool->name(), toolbar);
action->setCheckable(true);
toolbar->addAction(action);
tool->connect(action, SIGNAL(toggled(bool)), tool, SLOT(setActive(bool)));
tool->setActive(false);
canvas->tools.push_back(tool);
}
MainWindow::MainWindow()
{
{
int start = 44100 * 60;
Selection p(start, start + 44100 * 60, 0, 0); // one minute selection
selections_preview.add(p);
}
QWidget *central = new QWidget();
QHBoxLayout *lh = new QHBoxLayout();
QVBoxLayout *lv = new QVBoxLayout();
central->setLayout(lv);
setCentralWidget(central);
extractor = new AudioExtractor(selections, this);
canvas = new Canvas(this);
QToolBar *toolbar = addToolBar("Tools");
listen = new CanvasToolListen(canvas, player);
addTool(toolbar, canvas, listen);
threshold = new CanvasToolThreshold(canvas);
canvas->tools.push_back(threshold);//addTool(toolbar, canvas, threshold);
tool_selections = new CanvasToolSelections(canvas, selections,
selections_preview);
connect(threshold, SIGNAL(thresholdChanged(double)),
tool_selections, SLOT(thresholdChanged(double)));
connect(threshold, SIGNAL(thresholdChanging(double)),
tool_selections, SLOT(thresholdChanged(double)));
connect(&selections, SIGNAL(activeChanged(sel_id_t)),
canvas, SLOT(update()));
connect(&selections, SIGNAL(updated(sel_id_t)),
canvas, SLOT(update()));
addTool(toolbar, canvas, tool_selections);
QMenu *fileMenu = menuBar()->addMenu("&File");
QAction *act_quit = new QAction("&Quit", this);
fileMenu->addAction(act_quit);
connect(act_quit, SIGNAL(triggered()), this, SLOT(close()));
// QWidget *dock = new QWidget();
yoffset = new QScrollBar(Qt::Vertical);
yoffset->setRange(0, MAXVAL);
yoffset->setPageStep(PAGESTEP);
yoffset->setSingleStep(SINGLESTEP);
connect(yoffset, SIGNAL(valueChanged(int)), this, SLOT(setYOffset(int)));
yscale = new QScrollBar(Qt::Vertical);
yscale->setRange(0, MAXVAL);
yscale->setPageStep(PAGESTEP);
yscale->setSingleStep(SINGLESTEP);
connect(yscale, SIGNAL(valueChanged(int)), this, SLOT(setYScale(int)));
xscale = new QScrollBar(Qt::Horizontal);
xscale->setRange(0, MAXVAL);
xscale->setPageStep(PAGESTEP);
xscale->setSingleStep(SINGLESTEP);
connect(xscale, SIGNAL(valueChanged(int)), this, SLOT(setXScale(int)));
xoffset = new QScrollBar(Qt::Horizontal);
xoffset->setRange(0, MAXVAL);
xoffset->setPageStep(PAGESTEP);
xoffset->setSingleStep(SINGLESTEP);
connect(xoffset, SIGNAL(valueChanged(int)), this, SLOT(setXOffset(int)));
sorter = new SampleSorter(selections, selections_preview);
connect(&selections, SIGNAL(added(sel_id_t)),
sorter, SLOT(addSelection(sel_id_t)));
connect(&selections_preview, SIGNAL(added(sel_id_t)),
sorter, SLOT(addSelectionPreview(sel_id_t)));
connect(&selections, SIGNAL(updated(sel_id_t)), sorter, SLOT(relayout()));
connect(&selections_preview, SIGNAL(updated(sel_id_t)),
sorter, SLOT(relayout()));
connect(&selections, SIGNAL(removed(sel_id_t)), sorter, SLOT(relayout()));
connect(&selections_preview, SIGNAL(removed(sel_id_t)),
sorter, SLOT(relayout()));
connect(&selections, SIGNAL(activeChanged(sel_id_t)),
sorter, SLOT(relayout()));
QPushButton *btn_playsamples = new QPushButton("Play samples");
connect(btn_playsamples, SIGNAL(clicked()), this, SLOT(playSamples()));
sb_playsamples = new QScrollBar(Qt::Horizontal);
sb_playsamples->setRange(100, 4000); // ms
lh->addWidget(canvas);
lh->addWidget(yscale);
lh->addWidget(yoffset);
lv->addLayout(lh, 100);
lv->addWidget(xscale, 100);
lv->addWidget(xoffset, 100);
lv->addWidget(sorter, 15);
lv->addWidget(btn_playsamples);
lv->addWidget(sb_playsamples);
QDockWidget *dockWidget = new QDockWidget(tr("Dock Widget"), this);
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
dockWidget->setWidget(new QWidget());
dockWidget->widget()->setLayout(new QVBoxLayout());
// dockWidget->widget()->layout()->addWidget(new QLabel("Presets:"));
// presets = new QComboBox();
// connect(presets, SIGNAL(currentIndexChanged(int)),
// this, SLOT(setPreset(int)));
// dockWidget->widget()->layout()->addWidget(presets);
tabs = new QTabWidget(this);
tabs->addTab(createFilesTab(), "Files");
generateTabId = tabs->addTab(createGenerateTab(), "Generate");
tabs->addTab(createEditTab(), "Edit");
tabs->addTab(createExportTab(), "Export");
connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
tabChanged(tabs->currentIndex());
dockWidget->widget()->layout()->addWidget(tabs);
VolumeFader *vol = new VolumeFader();
connect(vol, SIGNAL(volumeChangedDb(double)),
&player, SLOT(setGainDB(double)));
connect(&player, SIGNAL(peakUpdate(double)),
vol, SLOT(updatePeakPower(double)));
// connect(&player, SIGNAL(peakUpdateDB(double)),
// vol, SLOT(updatePeakDb(double)));
vol->setVolumeDb(0);
dockWidget->widget()->layout()->addWidget(vol);
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
yscale->setValue(MAXVAL);
yoffset->setValue(MAXVAL/2);
xscale->setValue(0);
xoffset->setValue(0);
loadSettings();
/*
QSettings settings("presets.ini", QSettings::IniFormat);
QStringList list = settings.childGroups();
for(int i = 0; i != list.size(); i++) {
QString presetname = list.at(i);
Preset p;
settings.beginGroup(presetname);
p.prefix = settings.value("prefix", "unknown").toString();
p.attacklength = settings.value("attacklength", 0).toInt();
p.falloff = settings.value("falloff", 0).toInt();
p.fadelength = settings.value("fadelength", 0).toInt();
settings.endGroup();
QVariant v;
v.setValue(p);
presets->addItem(presetname, v);
}
*/
statusBar()->showMessage("Ready");
}
MainWindow::~MainWindow()
{
}
void MainWindow::tabChanged(int tabid)
{
tool_selections->setShowPreview(tabid == generateTabId);
sorter->setShowPreview(tabid == generateTabId);
tool_selections->autoCreateSelectionsPreview();
threshold->setActive(tabid == generateTabId);
}
QWidget *MainWindow::createFilesTab()
{
QWidget *w = new QWidget();
QVBoxLayout *l = new QVBoxLayout();
w->setLayout(l);
l->addWidget(new QLabel("Files: (double-click to set as master)"));
QPushButton *loadbtn = new QPushButton();
loadbtn->setText("Add files...");
l->addWidget(loadbtn);
filelist = new FileList();
connect(filelist, SIGNAL(masterFileChanged(QString)),
this, SLOT(loadFile(QString)));
connect(loadbtn, SIGNAL(clicked()), filelist, SLOT(addFiles()));
connect(filelist, SIGNAL(fileAdded(QString, QString)),
extractor, SLOT(addFile(QString, QString)));
connect(filelist, SIGNAL(fileRemoved(QString, QString)),
extractor, SLOT(removeFile(QString, QString)));
connect(filelist, SIGNAL(nameChanged(QString, QString)),
extractor, SLOT(changeName(QString, QString)));
l->addWidget(filelist);
return w;
}
QWidget *MainWindow::createEditTab()
{
SelectionEditor *se = new SelectionEditor(selections);
connect(&selections, SIGNAL(added(sel_id_t)), se, SLOT(added(sel_id_t)));
connect(&selections, SIGNAL(updated(sel_id_t)), se, SLOT(updated(sel_id_t)));
connect(&selections, SIGNAL(removed(sel_id_t)), se, SLOT(removed(sel_id_t)));
connect(&selections, SIGNAL(activeChanged(sel_id_t)),
se, SLOT(activeChanged(sel_id_t)));
return se;
}
QSlider *createAttribute(QWidget *parent, QString name,
int range_from, int range_to)
{
QSlider *slider;
QGridLayout *l = new QGridLayout();
l->addWidget(new QLabel(name), 0, 0, 1, 2);
QSpinBox *spin = new QSpinBox();
spin->setRange(range_from, range_to);
l->addWidget(spin, 1, 0, 1, 1);
slider = new QSlider(Qt::Horizontal);
slider->setRange(range_from, range_to);
l->addWidget(slider, 1, 1, 1,1);
QObject::connect(spin, SIGNAL(valueChanged(int)),
slider, SLOT(setValue(int)));
QObject::connect(slider, SIGNAL(valueChanged(int)),
spin, SLOT(setValue(int)));
((QBoxLayout *)parent->layout())->addLayout(l);
return slider;
}
QWidget *MainWindow::createGenerateTab()
{
QWidget *w = new QWidget();
QVBoxLayout *l = new QVBoxLayout();
w->setLayout(l);
QHBoxLayout *btns = new QHBoxLayout();
QPushButton *autosel = new QPushButton();
autosel->setText("Generate");
connect(autosel, SIGNAL(clicked()),
tool_selections, SLOT(clearSelections()));
connect(autosel, SIGNAL(clicked()),
tool_selections, SLOT(autoCreateSelections()));
connect(threshold, SIGNAL(thresholdChanged(double)),
tool_selections, SLOT(autoCreateSelectionsPreview()));
connect(threshold, SIGNAL(thresholdChanging(double)),
tool_selections, SLOT(autoCreateSelectionsPreview()));
QPushButton *clearsel = new QPushButton();
clearsel->setText("Clear");
connect(clearsel, SIGNAL(clicked()),
tool_selections, SLOT(clearSelections()));
btns->addWidget(autosel);
btns->addWidget(clearsel);
l->addLayout(btns);
slider_attacklength = createAttribute(w, "Attack length:", 10, 1000);
connect(slider_attacklength, SIGNAL(valueChanged(int)),
sorter, SLOT(setAttackLength(int)));
connect(slider_attacklength, SIGNAL(valueChanged(int)),
tool_selections, SLOT(autoCreateSelectionsPreview()));
slider_attacklength->setValue(300);
slider_hold = createAttribute(w, "Minimum size (samples):", 0, 200000);
connect(slider_hold, SIGNAL(valueChanged(int)),
tool_selections, SLOT(holdChanged(int)));
connect(slider_hold, SIGNAL(valueChanged(int)),
tool_selections, SLOT(autoCreateSelectionsPreview()));
slider_hold->setValue(100);
slider_falloff = createAttribute(w, "Falloff:", 10, 5000);
connect(slider_falloff, SIGNAL(valueChanged(int)),
tool_selections, SLOT(noiseFloorChanged(int)));
connect(slider_falloff, SIGNAL(valueChanged(int)),
tool_selections, SLOT(autoCreateSelectionsPreview()));
slider_falloff->setValue(300);
slider_fadelength = createAttribute(w, "Fadelength:", 0, 2000);
connect(slider_fadelength, SIGNAL(valueChanged(int)),
tool_selections, SLOT(fadeoutChanged(int)));
connect(slider_fadelength, SIGNAL(valueChanged(int)),
tool_selections, SLOT(autoCreateSelectionsPreview()));
slider_fadelength->setValue(666);
l->addStretch();
return w;
}
QWidget *MainWindow::createExportTab()
{
QWidget *w = new QWidget();
QVBoxLayout *l = new QVBoxLayout();
w->setLayout(l);
l->addWidget(new QLabel("Prefix:"));
prefix = new QLineEdit();
connect(prefix, SIGNAL(textChanged(const QString &)),
extractor, SLOT(setOutputPrefix(const QString &)));
l->addWidget(prefix);
l->addWidget(new QLabel("Export path:"));
QHBoxLayout *lo_exportp = new QHBoxLayout();
lineed_exportp = new QLineEdit();
connect(lineed_exportp, SIGNAL(textChanged(const QString &)),
extractor, SLOT(setExportPath(const QString &)));
lo_exportp->addWidget(lineed_exportp);
QPushButton *btn_browse = new QPushButton("...");
connect(btn_browse, SIGNAL(clicked()), this, SLOT(browse()));
lo_exportp->addWidget(btn_browse);
l->addLayout(lo_exportp);
QPushButton *exportsel = new QPushButton();
exportsel->setText("Export");
connect(exportsel, SIGNAL(clicked()), this, SLOT(doExport()));
l->addWidget(exportsel);
QProgressBar *bar = new QProgressBar();
connect(extractor, SIGNAL(progressUpdate(int)), bar, SLOT(setValue(int)));
connect(extractor, SIGNAL(setMaximumProgress(int)),
bar, SLOT(setMaximum(int)));
l->addWidget(bar);
l->addStretch();
return w;
}
void MainWindow::playSamples()
{
Selections *sels = &selections;
if(tabs->currentIndex() == generateTabId) sels = &selections_preview;
QVector<sel_id_t> ids = sels->ids();
for(int v1 = 0; v1 < ids.size(); v1++) {
for(int v2 = 0; v2 < ids.size(); v2++) {
Selection sel1 = sels->get(ids[v1]);
Selection sel2 = sels->get(ids[v2]);
if(sel1.energy < sel2.energy) {
sel_id_t vtmp = ids[v1];
ids[v1] = ids[v2];
ids[v2] = vtmp;
}
}
}
QVector<sel_id_t>::iterator i = ids.begin();
while(i != ids.end()) {
Selection sel = sels->get(*i);
unsigned int length = sb_playsamples->value() * 44100 / 1000;
unsigned int sample_length = sel.to - sel.from;
unsigned int to = sel.to;
if(sample_length > length) to = sel.from + length;
sels->setActive(*i);
connect(&player, SIGNAL(positionUpdate(size_t)),
listen, SLOT(update(size_t)));
player.playSelection(sel, to - sel.from);
QTime t;
t.start();
while(t.elapsed() < sb_playsamples->value()) {
qApp->processEvents();
q_usleep(25 * 1000);
}
player.stop();
disconnect(&player, SIGNAL(positionUpdate(size_t)),
listen, SLOT(update(size_t)));
i++;
}
}
void MainWindow::closeEvent(QCloseEvent *)
{
saveSettings();
QApplication::quit();
}
void MainWindow::loadSettings()
{
QSettings settings;
settings.beginGroup("MainWindow");
lineed_exportp->setText(settings.value("exportpath", "").toString());
filelist->path = settings.value("loadpath", "").toString();
resize(settings.value("size", QSize(700, 800)).toSize());
move(settings.value("pos", QPoint(0, 0)).toPoint());
settings.endGroup();
}
void MainWindow::saveSettings()
{
QSettings settings;
settings.beginGroup("MainWindow");
settings.setValue("loadpath", filelist->path);
settings.setValue("exportpath", lineed_exportp->text());
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void MainWindow::setXScale(int sz)
{
// range 0.0 - 1.0
float val = (float)(sz * -1 + MAXVAL)/(float)MAXVAL;
canvas->setXScale(val);
if(val < 0.001) val = 0.001;
xoffset->setPageStep(PAGESTEP * 10 * val);
xoffset->setSingleStep(SINGLESTEP * 10 * val);
}
void MainWindow::setYScale(int sz)
{
// range 0.0 - 1.0
float val = (float)(sz * -1 + MAXVAL)/(float)MAXVAL;
canvas->setYScale(val);
}
void MainWindow::setXOffset(int of)
{
// range 0.0 - 1.0
float val = (float)of/(float)MAXVAL;
canvas->setXOffset(val);
}
void MainWindow::setYOffset(int of)
{
// range 0.0 - 1.0
float val = (float)(of * -1 + MAXVAL)/(float)MAXVAL;
canvas->setYOffset(val);
}
void MainWindow::doExport()
{
extractor->exportSelections();
}
void MainWindow::loadFile(QString filename)
{
setCursor(Qt::WaitCursor);
statusBar()->showMessage("Loading...");
qApp->processEvents();
sorter->setWavData(NULL, 0);
player.setPcmData(NULL, 0);
canvas->load(filename);
sorter->setWavData(canvas->data, canvas->size);
player.setPcmData(canvas->data, canvas->size);
statusBar()->showMessage("Ready");
setCursor(Qt::ArrowCursor);
}
void MainWindow::setPreset(int index)
{
/*
QVariant v = presets->itemData(index);
Preset p = v.value<Preset>();
slider_attacklength->setValue(p.attacklength);
slider_falloff->setValue(p.falloff);
slider_fadelength->setValue(p.fadelength);
prefix->setText(p.prefix);
*/
}
void MainWindow::browse() {
QString path = QFileDialog::getExistingDirectory(this, "Select export path",
lineed_exportp->text());
lineed_exportp->setText(path);
}