summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2014-09-05 19:57:14 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2014-09-05 19:57:14 +0200
commit4ae6300717a10c7fa850b800f18a730aee1d3e07 (patch)
tree455ae17634f5bbd8b18ce3a256db2647853bd600 /src
parentf4b015398462fff1a64d70b632390b4f06fe3bbe (diff)
Internal code editor. Sound system.
Diffstat (limited to 'src')
-rw-r--r--src/codeeditor.cc163
-rw-r--r--src/codeeditor.h103
-rw-r--r--src/kaiman.cc13
-rw-r--r--src/luascript.cc99
-rw-r--r--src/luascript.h14
-rw-r--r--src/mainwindow.cc32
-rw-r--r--src/mainwindow.h7
-rw-r--r--src/outputwindow.cc27
-rw-r--r--src/outputwindow.h7
-rw-r--r--src/soundplayer.cc134
-rw-r--r--src/soundplayer.h60
11 files changed, 636 insertions, 23 deletions
diff --git a/src/codeeditor.cc b/src/codeeditor.cc
new file mode 100644
index 0000000..44b0e9b
--- /dev/null
+++ b/src/codeeditor.cc
@@ -0,0 +1,163 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ ** * Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** * Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in
+ ** the documentation and/or other materials provided with the
+ ** distribution.
+ ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+ ** of its contributors may be used to endorse or promote products derived
+ ** from this software without specific prior written permission.
+ **
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#include <QtGui>
+
+#include "codeeditor.h"
+
+
+CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
+{
+ lineNumberArea = new LineNumberArea(this);
+
+ connect(this, SIGNAL(blockCountChanged(int)),
+ this, SLOT(updateLineNumberAreaWidth(int)));
+ connect(this, SIGNAL(updateRequest(QRect,int)),
+ this, SLOT(updateLineNumberArea(QRect,int)));
+ connect(this, SIGNAL(cursorPositionChanged()),
+ this, SLOT(highlightCurrentLine()));
+
+ setStyleSheet("font: 12pt \"Courier\";");
+
+ updateLineNumberAreaWidth(0);
+ highlightCurrentLine();
+}
+
+
+
+int CodeEditor::lineNumberAreaWidth()
+{
+ int digits = 1;
+ int max = qMax(1, blockCount());
+ while (max >= 10) {
+ max /= 10;
+ ++digits;
+ }
+
+ int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;
+
+ return space;
+}
+
+
+
+void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
+{
+ setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
+}
+
+
+
+void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
+{
+ if (dy)
+ lineNumberArea->scroll(0, dy);
+ else
+ lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
+
+ if (rect.contains(viewport()->rect()))
+ updateLineNumberAreaWidth(0);
+}
+
+
+
+void CodeEditor::resizeEvent(QResizeEvent *e)
+{
+ QPlainTextEdit::resizeEvent(e);
+
+ QRect cr = contentsRect();
+ lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(),
+ cr.height()));
+}
+
+
+
+void CodeEditor::highlightCurrentLine()
+{
+ QList<QTextEdit::ExtraSelection> extraSelections;
+
+ if (!isReadOnly()) {
+ QTextEdit::ExtraSelection selection;
+
+ QColor lineColor = QColor(Qt::yellow).lighter(160);
+
+ selection.format.setBackground(lineColor);
+ selection.format.setProperty(QTextFormat::FullWidthSelection, true);
+ selection.cursor = textCursor();
+ selection.cursor.clearSelection();
+ extraSelections.append(selection);
+ }
+
+ setExtraSelections(extraSelections);
+}
+
+void CodeEditor::runningLine(int lineno)
+{
+ lineNumber = lineno;
+ repaint();
+}
+
+void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
+{
+ QPainter painter(lineNumberArea);
+ painter.fillRect(event->rect(), Qt::lightGray);
+
+
+ QTextBlock block = firstVisibleBlock();
+ int blockNumber = block.blockNumber();
+ int top =
+ (int) blockBoundingGeometry(block).translated(contentOffset()).top();
+ int bottom = top + (int) blockBoundingRect(block).height();
+
+ while (block.isValid() && top <= event->rect().bottom()) {
+ if (block.isVisible() && bottom >= event->rect().top()) {
+ QString number = QString::number(blockNumber + 1);
+ if(blockNumber + 1 == lineNumber) painter.setPen(Qt::green);
+ else painter.setPen(Qt::black);
+ painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(),
+ Qt::AlignRight, number);
+ }
+
+ block = block.next();
+ top = bottom;
+ bottom = top + (int) blockBoundingRect(block).height();
+ ++blockNumber;
+ }
+}
diff --git a/src/codeeditor.h b/src/codeeditor.h
new file mode 100644
index 0000000..1f0274a
--- /dev/null
+++ b/src/codeeditor.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ ** * Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** * Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in
+ ** the documentation and/or other materials provided with the
+ ** distribution.
+ ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+ ** of its contributors may be used to endorse or promote products derived
+ ** from this software without specific prior written permission.
+ **
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#ifndef __CODEEDITOR_H__
+#define __CODEEDITOR_H__
+
+#include <QPlainTextEdit>
+#include <QObject>
+
+class QPaintEvent;
+class QResizeEvent;
+class QSize;
+class QWidget;
+
+class LineNumberArea;
+
+class CodeEditor : public QPlainTextEdit
+{
+ Q_OBJECT
+
+ public:
+ CodeEditor(QWidget *parent = 0);
+
+ void lineNumberAreaPaintEvent(QPaintEvent *event);
+ int lineNumberAreaWidth();
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+
+public slots:
+ void runningLine(int lineno);
+
+private slots:
+ void updateLineNumberAreaWidth(int newBlockCount);
+ void highlightCurrentLine();
+ void updateLineNumberArea(const QRect &, int);
+
+private:
+ QWidget *lineNumberArea;
+ int lineNumber;
+};
+
+
+class LineNumberArea : public QWidget
+{
+public:
+ LineNumberArea(CodeEditor *editor) : QWidget(editor) {
+ codeEditor = editor;
+ }
+
+ QSize sizeHint() const {
+ return QSize(codeEditor->lineNumberAreaWidth(), 0);
+ }
+
+protected:
+ void paintEvent(QPaintEvent *event) {
+ codeEditor->lineNumberAreaPaintEvent(event);
+ }
+
+private:
+ CodeEditor *codeEditor;
+};
+
+#endif/*__CODEEDITOR_H__*/
diff --git a/src/kaiman.cc b/src/kaiman.cc
index 82dcfdd..75d3035 100644
--- a/src/kaiman.cc
+++ b/src/kaiman.cc
@@ -27,7 +27,16 @@
*/
#include <QApplication>
+#include <QLocale>
+
#include "mainwindow.h"
+#include <locale.h>
+
+void __attribute__ ((constructor)) premain()
+{
+ printf("premain()\n");
+ printf("locale: %s\n", setlocale(LC_ALL, "da_DK"));
+}
int main(int argc, char *argv[])
{
@@ -36,10 +45,12 @@ int main(int argc, char *argv[])
return 1;
}
+ // QLocale::setDefault(QLocale(QLocale::Danish, QLocale::Denmark));
+
QApplication app(argc, argv);
MainWindow wnd(argv[1]);
- // wnd.show();
+ wnd.showMaximized();
return app.exec();
}
diff --git a/src/luascript.cc b/src/luascript.cc
index df607de..ecbed53 100644
--- a/src/luascript.cc
+++ b/src/luascript.cc
@@ -58,9 +58,9 @@ static int _forward(lua_State *L)
Pracro::T_STRING,
Pracro::T_END);
*/
- int x = lua_tonumber(L, lua_gettop(L));
+ double x = lua_tonumber(L, lua_gettop(L));
- printf("forward %d\n", x);
+ printf("forward %f\n", x);
lua_getglobal(L, GLOBAL_POINTER);
LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
@@ -82,6 +82,33 @@ static int _forward(lua_State *L)
return 0;
}
+static int _coord(lua_State *L)
+{/*
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_END);
+ */
+ lua_getglobal(L, GLOBAL_POINTER);
+ LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
+
+ if(!lua) {
+ lua_pushstring(L, "No LUA pointer!");
+ lua_error(L);
+ return 1;
+ }
+
+ if(lua->lua_stop) {
+ printf("stopping...\n");
+ lua_pushstring(L, "stop");
+ lua_error(L);
+ }
+
+ lua_pushnumber(L, lua->out->coordX());
+ lua_pushnumber(L, lua->out->coordY());
+
+ return 2;
+}
+
static int _loadpen(lua_State *L)
{/*
Pracro::checkParameters(L,
@@ -211,9 +238,9 @@ static int _turn(lua_State *L)
Pracro::T_STRING,
Pracro::T_END);
*/
- int x = lua_tonumber(L, lua_gettop(L));
+ double x = lua_tonumber(L, lua_gettop(L));
- printf("turn %d\n", x);
+ printf("turn %f\n", x);
lua_getglobal(L, GLOBAL_POINTER);
LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
@@ -235,6 +262,22 @@ static int _turn(lua_State *L)
return 0;
}
+static int _playsound(lua_State *L)
+{/*
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_END);
+ */
+ QString file = lua_tostring(L, lua_gettop(L));
+
+ lua_getglobal(L, GLOBAL_POINTER);
+ LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
+
+ lua->playSound(file);
+
+ return 0;
+}
+
static int _reset(lua_State *L)
{/*
Pracro::checkParameters(L,
@@ -263,6 +306,36 @@ static int _reset(lua_State *L)
return 0;
}
+void hook(lua_State *L, lua_Debug *ar)
+{
+ lua_getinfo(L, "Snl", ar);
+
+ lua_getglobal(L, GLOBAL_POINTER);
+ LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
+
+ if(!lua) {
+ lua_pushstring(L, "No LUA pointer!");
+ lua_error(L);
+ return;
+ }
+
+ // printf("kaiman file: %s\n", lua->file.toStdString().c_str());
+
+ if(lua->file == QString(ar->short_src)) {
+ // printf(" ---- currentline: %d\n", ar->currentline);
+ lua->lineChange(ar->currentline);
+ qApp->processEvents();
+ }
+ /*
+ printf("HOOK:\n");
+ printf(" what: %s\n", ar->what);
+ printf(" name: %s\n", ar->name);
+ printf(" source: %s\n", ar->source);
+ printf(" short_src: %s\n", ar->short_src);
+ printf(" currentline: %d\n", ar->currentline);
+ */
+}
+
LUAScript::LUAScript(OutputWindow *o, QString f)
{
DEBUG(luascript, "LUAScript()\n");
@@ -281,6 +354,11 @@ LUAScript::~LUAScript()
DEBUG(luascript, "~LUAScript()\n");
}
+void LUAScript::lineChange(int lineno)
+{
+ emit lineChanged(lineno);
+}
+
void LUAScript::init()
throw(Exception)
{
@@ -298,13 +376,17 @@ void LUAScript::init()
lua_setglobal(L, GLOBAL_POINTER); // Assign it to a global lua var.
lua_register(L, "debug", _debug);
- lua_register(L, "fremad", _forward);
- lua_register(L, "drej", _turn);
+ lua_register(L, "forward", _forward);
+ lua_register(L, "turn", _turn);
lua_register(L, "speed", _speed);
lua_register(L, "scale", _scale);
lua_register(L, "reset", _reset);
lua_register(L, "colour", _colour);
lua_register(L, "loadpen", _loadpen);
+ lua_register(L, "coord", _coord);
+ lua_register(L, "playsound", _playsound);
+
+ lua_sethook(L, hook, LUA_MASKLINE, 0);
}
void LUAScript::cleanup()
@@ -329,6 +411,11 @@ void LUAScript::run()
printf("LUA Thread Stopped!\n");
}
+void LUAScript::playSound(QString file)
+{
+ player.playFile(file);
+}
+
void LUAScript::stopScript()
{
lua_stop = true;
diff --git a/src/luascript.h b/src/luascript.h
index 6516611..93478df 100644
--- a/src/luascript.h
+++ b/src/luascript.h
@@ -36,6 +36,7 @@
#include <vector>
#include "outputwindow.h"
+#include "soundplayer.h"
#include <QThread>
@@ -59,13 +60,20 @@ public:
OutputWindow *out;
- void stopScript();
+ void lineChange(int lineno);
+
+ void playSound(QString file);
volatile bool lua_stop;
volatile bool lua_stopped;
+ QString file;
+
+public slots:
+ void stopScript();
signals:
void reset();
+ void lineChanged(int lineno);
protected:
lua_State *L;
@@ -76,9 +84,9 @@ private:
int top;
- QString file;
-
bool running;
+
+ SoundPlayer player;
};
diff --git a/src/mainwindow.cc b/src/mainwindow.cc
index c8036ca..ba6c779 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -30,20 +30,45 @@
#include "outputwindow.h"
#include <QApplication>
+#include <QSplitter>
+#include <QToolBar>
+#include <QAction>
+#include <QFile>
MainWindow::MainWindow(QString p)
{
program = p;
+ /* // Watch file on disk?
connect(&watcher, SIGNAL(fileChanged(const QString &)),
this, SLOT(reset()));
watcher.addPath(program);
+ */
+ QSplitter *splitter = new QSplitter();
+ setCentralWidget(splitter);
+
+ editor = new CodeEditor();
+ splitter->addWidget(editor);
+ QFile file(program);
+ file.open(QIODevice::ReadOnly);
+ editor->setPlainText(file.readAll());
+ file.close();
+
out = new OutputWindow();
- out->show();
+ splitter->addWidget(out);
l = new LUAScript(out, program);
+ connect(l, SIGNAL(lineChanged(int)), editor, SLOT(runningLine(int)));
+
+ QToolBar *toolbar = new QToolBar();
+ addToolBar(Qt::TopToolBarArea, toolbar);
+ QAction *act_run = toolbar->addAction("Run");
+ connect(act_run, SIGNAL(triggered()), this, SLOT(reset()));
+
+ QAction *act_stop = toolbar->addAction("Stop");
+ connect(act_stop, SIGNAL(triggered()), l, SLOT(stopScript()));
reset();
}
@@ -51,6 +76,11 @@ MainWindow::MainWindow(QString p)
void MainWindow::reset()
{
printf("Resetting...\n");
+ QFile file(program);
+ file.open(QIODevice::WriteOnly);
+ QString code = editor->toPlainText();
+ file.write(code.toStdString().c_str(), code.length());
+ file.close();
out->stopScript();
l->stopScript();
out->reset();
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 1376a84..c9a1844 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -28,14 +28,15 @@
#ifndef __KAIMAN_MAINWINDOW_H__
#define __KAIMAN_MAINWINDOW_H__
-#include <QWidget>
+#include <QMainWindow>
#include <QFileSystemWatcher>
+#include "codeeditor.h"
#include "outputwindow.h"
#include "luascript.h"
-class MainWindow : public QWidget {
+class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QString program);
@@ -44,6 +45,8 @@ private slots:
void reset();
private:
+ CodeEditor *editor;
+
QFileSystemWatcher watcher;
QString program;
OutputWindow *out;
diff --git a/src/outputwindow.cc b/src/outputwindow.cc
index 43e691f..498af23 100644
--- a/src/outputwindow.cc
+++ b/src/outputwindow.cc
@@ -48,6 +48,16 @@ OutputWindow::OutputWindow()
reset();
}
+double OutputWindow::coordX()
+{
+ return x;
+}
+
+double OutputWindow::coordY()
+{
+ return y;
+}
+
void OutputWindow::stopScript()
{
stop = true;
@@ -117,7 +127,7 @@ void OutputWindow::paintEvent(QPaintEvent *)
p.setTransform(gt);
QPen pen;
- pen.setWidth(6);
+ pen.setWidth(4);
/*
p.setPen(pen);
p.drawLines(points);
@@ -148,7 +158,7 @@ void OutputWindow::paintEvent(QPaintEvent *)
QColor c = colour;
c.setAlpha(c.alpha() / 4);
pen.setStyle(Qt::SolidLine);
- pen.setWidth(6);
+ pen.setWidth(4);
pen.setColor(c);
p.setPen(pen);
for(int i = 0; i < current_points.size(); i+=2) {
@@ -183,9 +193,10 @@ static inline int sign(int x)
return -1;
}
-void OutputWindow::forward(int dist)
+void OutputWindow::forward(double dist)
{
sem.acquire();
+
float target_x = sin(r * (M_PI / 180.0)) * dist;
float target_y = cos(r * (M_PI / 180.0)) * dist;
@@ -222,15 +233,15 @@ void OutputWindow::forward(int dist)
}
// Turn x degrees
-void OutputWindow::turn(int x)
+void OutputWindow::turn(double x)
{
- int spd = (speed * abs(x) / 80);
- float offset = this->r;
+ double spd = (speed * abs(x) / 80.0);
+ double offset = this->r;
sem.acquire();
for(int i = 0; i < spd; i++) {
if(stop) return;
- float p = (float)i / (float)spd;
- this->r = offset + (float)x * p;
+ double p = (double)i / spd;
+ this->r = offset + x * p;
sem.acquire();
}
this->r = offset + x;
diff --git a/src/outputwindow.h b/src/outputwindow.h
index d875b36..bd8bf27 100644
--- a/src/outputwindow.h
+++ b/src/outputwindow.h
@@ -40,8 +40,8 @@ Q_OBJECT
public:
OutputWindow();
- void forward(int x);
- void turn(int x);
+ void forward(double x);
+ void turn(double x);
void stopScript();
@@ -51,6 +51,9 @@ public:
void loadPen(QString file);
+ double coordX();
+ double coordY();
+
public slots:
void timeout();
void reset();
diff --git a/src/soundplayer.cc b/src/soundplayer.cc
new file mode 100644
index 0000000..c59e84e
--- /dev/null
+++ b/src/soundplayer.cc
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * soundplayer.cc
+ *
+ * Fri Sep 5 17:31:28 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Kaiman.
+ *
+ * Kaiman 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.
+ *
+ * Kaiman 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 Kaiman; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "soundplayer.h"
+
+#include <ao/ao.h>
+#include <sndfile.h>
+
+#define BUFSZ 512
+
+SoundPlayer::SoundPlayer()
+{
+ start();
+}
+
+SoundPlayer::~SoundPlayer()
+{
+ running = false;
+ wait();
+}
+
+void SoundPlayer::run()
+{
+
+ printf("SoundPlayer running\n");
+
+ ao_initialize();
+
+ ao_sample_format sf;
+ memset(&sf, 0, sizeof(sf));
+ sf.bits = 16;
+ sf.rate = 44100;
+ sf.channels = 2;
+ sf.byte_format = AO_FMT_NATIVE;
+
+ ao_device *dev = ao_open_live(ao_default_driver_id(), &sf, 0);
+
+ running = true;
+
+ short s[BUFSZ];
+ while(running) {
+
+ { // Check for new Selection.
+ QMutexLocker lock(&mutex);
+ while(queue.size()) {
+ printf(" - New sound\n");
+ active.append(queue.front());
+ queue.pop_front();
+ }
+ }
+
+ memset(s, 0, BUFSZ * sizeof(short));
+
+ QList<QueueItem>::iterator it = active.begin();
+ while(it != active.end()) {
+ QueueItem &item = *it;
+
+ for(size_t i = 0; i < BUFSZ; i++) {
+ if(item.pos >= item.size) {
+ it = active.erase(it);
+ goto nextitem;
+ }
+ s[i] += item.samples[item.pos] * 32536;
+ item.pos++;
+ }
+
+ it++;
+
+ nextitem:
+ int a = 1;(void)a;
+ }
+
+ ao_play(dev, (char*)s, BUFSZ * sizeof(short));
+ }
+
+ ao_close(dev);
+ ao_shutdown();
+}
+
+void SoundPlayer::playFile(QString file)
+{
+
+ printf(" - playFile(%s)\n", file.toStdString().c_str());
+
+ SNDFILE *fh;
+ SF_INFO sf_info;
+
+ fh = sf_open(file.toStdString().c_str(), SFM_READ, &sf_info);
+ if(!fh) {
+ printf("Load error '%s'\n", file.toStdString().c_str());
+ return;
+ }
+
+ size_t size = sf_info.frames * sf_info.channels;
+ float *data = new float[size];
+ sf_read_float(fh, data, size);
+
+ sf_close(fh);
+
+ QueueItem qi;
+ qi.samples = data;
+ qi.pos = 0;
+ qi.size = size;
+
+ {
+ QMutexLocker lock(&mutex);
+ queue.append(qi);
+ }
+
+}
diff --git a/src/soundplayer.h b/src/soundplayer.h
new file mode 100644
index 0000000..c5b36d4
--- /dev/null
+++ b/src/soundplayer.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * soundplayer.h
+ *
+ * Fri Sep 5 17:31:27 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Kaiman.
+ *
+ * Kaiman 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.
+ *
+ * Kaiman 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 Kaiman; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __KAIMAN_SOUNDPLAYER_H__
+#define __KAIMAN_SOUNDPLAYER_H__
+
+#include <QThread>
+#include <QString>
+#include <QList>
+#include <QMutex>
+
+class QueueItem {
+public:
+ float *samples;
+ size_t pos;
+ size_t size;
+};
+
+class SoundPlayer : public QThread {
+public:
+ SoundPlayer();
+ ~SoundPlayer();
+
+ void playFile(QString file);
+
+ void run();
+
+private:
+ volatile bool running;
+ QMutex mutex;
+
+ QList<QueueItem> queue;
+ QList<QueueItem> active;
+};
+
+#endif/*__KAIMAN_SOUNDPLAYER_H__*/