summaryrefslogtreecommitdiffstats
path: root/noatun-plugins/nexscope/nex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'noatun-plugins/nexscope/nex.cpp')
-rw-r--r--noatun-plugins/nexscope/nex.cpp597
1 files changed, 597 insertions, 0 deletions
diff --git a/noatun-plugins/nexscope/nex.cpp b/noatun-plugins/nexscope/nex.cpp
new file mode 100644
index 0000000..af19409
--- /dev/null
+++ b/noatun-plugins/nexscope/nex.cpp
@@ -0,0 +1,597 @@
+#include "nex.h"
+#include "gui.h"
+
+#include <unistd.h>
+
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qmultilineedit.h>
+
+#include "renderers.h"
+
+Mutex runLock;
+Nex *Nex::sNex=0;
+QTime timer;
+
+Renderer::Renderer() {}
+Renderer::~Renderer() {}
+
+Thread::Thread() : mThread(0)
+{
+
+}
+
+Thread::~Thread()
+{
+ if (mThread)
+ kill();
+}
+
+void Thread::start()
+{
+ mThread=SDL_CreateThread(&threadRun, (void*)this);
+}
+
+void Thread::kill()
+{
+ SDL_KillThread(mThread);
+}
+
+int Thread::wait()
+{
+ int val;
+ SDL_WaitThread(mThread, &val);
+ return val;
+}
+
+int Thread::threadRun(void *v)
+{
+ Thread *t=(Thread*)v;
+ return t->run();
+}
+
+NexCheckBox::NexCheckBox(QWidget *parent,
+ const QString &name, bool *v)
+ : QCheckBox(name, parent)
+{
+ value=v;
+ setChecked(*v);
+ connect(this, SIGNAL(toggled(bool)), SLOT(change(bool)));
+}
+void NexCheckBox::change(bool b)
+{
+ *value=b;
+}
+
+
+
+NexColorButton::NexColorButton(QWidget *parent, Pixel *color)
+ : KColorButton(parent)
+{
+ c=color;
+ QColor temp( (*c >> 16) & 0xFF, (*c >> 8) & 0xFF, *c & 0xFF);
+ setColor(temp);
+ connect(this, SIGNAL(changed(const QColor&)), SLOT(change(const QColor&)));
+}
+
+void NexColorButton::change(const QColor &co)
+{
+ *c= COLOR(qRed(co.rgb()), qGreen(co.rgb()), qBlue(co.rgb()));
+}
+
+void Bitmap::resize(int w, int h)
+{
+ delete [] mData;
+ mData=new Pixel[w*h];
+}
+
+void Bitmap::clear()
+{
+ memset(mData, 0, bytes());
+}
+
+void Bitmap::drawCircle(int x, int y, int r, Pixel color)
+{
+ int16_t cx = 0;
+ int16_t cy = r;
+ int16_t ocx = -1;
+ int16_t ocy = -1;
+ int16_t df = 1 - r;
+ int16_t d_e = 3;
+ int16_t d_se = -2 * r + 5;
+ int16_t xpcx, xmcx, xpcy, xmcy;
+ int16_t ypcy, ymcy, ypcx, ymcx;
+
+ do
+ { // Draw
+ if ((ocy!=cy) || (ocx!=cx))
+ {
+ xpcx=x+cx;
+ xmcx=x-cx;
+ if (cy>0)
+ {
+ ypcy=y+cy;
+ ymcy=y-cy;
+ setPixel(xmcx,ypcy,color);
+ setPixel(xpcx,ypcy,color);
+ setPixel(xmcx,ymcy,color);
+ setPixel(xpcx,ymcy,color);
+ }
+ else
+ {
+ setPixel(xmcx,y,color);
+ setPixel(xpcx,y,color);
+ }
+
+ ocy=cy;
+ xpcy=x+cy;
+ xmcy=x-cy;
+ if (cx>0)
+ {
+ ypcx=y+cx;
+ ymcx=y-cx;
+ setPixel(xmcy,ypcx,color);
+ setPixel(xpcy,ypcx,color);
+ setPixel(xmcy,ymcx,color);
+ setPixel(xpcy,ymcx,color);
+ }
+ else
+ {
+ setPixel(xmcy,y,color);
+ setPixel(xpcy,y,color);
+ }
+ ocx=cx;
+ }
+ // Update
+ if (df < 0)
+ {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+ cx++;
+ } while(cx <= cy);
+}
+
+
+void Bitmap::fillCircle(int x, int y, int r, Pixel color)
+{
+ int16_t cx = 0;
+ int16_t cy = r;
+ int16_t ocx = -1;
+ int16_t ocy = -1;
+ int16_t df = 1 - r;
+ int16_t d_e = 3;
+ int16_t d_se = -2 * r + 5;
+ int16_t xpcx, xmcx, xpcy, xmcy;
+ int16_t ypcy, ymcy, ypcx, ymcx;
+
+ do
+ { // Draw
+ if ((ocy!=cy) || (ocx!=cx))
+ {
+ xpcx=x+cx;
+ xmcx=x-cx;
+ if (cy>0)
+ {
+ ypcy=y+cy;
+ ymcy=y-cy;
+ setPixel(xmcx,ypcy,color);
+ setPixel(xpcx,ypcy,color);
+ setPixel(xmcx,ymcy,color);
+ setPixel(xpcx,ymcy,color);
+ for (int h=xmcx; h<xpcx; h++)
+ setPixel(h, ypcy, color);
+
+ for (int h=xmcx; h<xpcx; h++)
+ setPixel(h, ymcy, color);
+ }
+ else
+ {
+ setPixel(xmcx,y,color);
+ setPixel(xpcx,y,color);
+ for (int h=xmcx; h<xpcx; h++)
+ setPixel(h, y, color);
+ }
+
+
+ ocy=cy;
+ xpcy=x+cy;
+ xmcy=x-cy;
+ if (cx>0)
+ {
+ ypcx=y+cx;
+ ymcx=y-cx;
+ setPixel(xmcy,ypcx,color);
+ setPixel(xpcy,ypcx,color);
+ setPixel(xmcy,ymcx,color);
+ setPixel(xpcy,ymcx,color);
+ for (int h=xmcy; h<xpcy; h++)
+ setPixel(h, ypcx, color);
+
+ for (int h=xmcy; h<xpcy; h++)
+ setPixel(h, ymcx, color);
+ }
+ else
+ {
+ setPixel(xmcy,y,color);
+ setPixel(xpcy,y,color);
+ for (int h=xmcy; h<xpcy; h++)
+ setPixel(h, y, color);
+ }
+ ocx=cx;
+ }
+ // Update
+ if (df < 0)
+ {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+ cx++;
+ } while(cx <= cy);
+}
+
+
+void Bitmap::drawLine(int x1, int y1, int x2, int y2, Pixel color)
+{
+ // Variable setup
+ int dx = x2 - x1;
+ int sx = (dx >= 0) ? 1 : -1;
+ dx = sx * dx + 1;
+
+ int dy = y2 - y1;
+ int sy = (dy >= 0) ? 1 : -1;
+ dy = sy * dy + 1;
+
+
+ int pixx = sizeof(Pixel);
+ int pixy = width*sizeof(Pixel);
+ uint8_t *pixel = (uint8_t*)pixels() + pixx * x1 + pixy * y1;
+ pixx *= sx;
+ pixy *= sy;
+
+ if (dx < dy)
+ {
+ int swaptmp = dx;
+ dx = dy;
+ dy = swaptmp;
+ swaptmp = pixx;
+ pixx = pixy;
+ pixy = swaptmp;
+ }
+
+
+ // Draw
+ int y=0;
+
+ for(int x=0; x < dx; x++, pixel += pixx)
+ {
+ *(Pixel*)pixel=color;
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ pixel += pixy;
+ }
+ }
+
+}
+
+RendererList::RendererList() : mClearAfter(false)
+{
+ mFrame=nex->bitmapPool()->get(true);
+}
+
+RendererList::~RendererList()
+{
+ nex->bitmapPool()->release(mFrame);
+}
+
+Bitmap *RendererList::render(float *pcm[4], Bitmap *source)
+{
+ if (mClearAfter) mFrame->clear();
+
+ lock();
+ for (QPtrListIterator<Renderer> i(mRendererList); i.current(); ++i)
+ {
+ Bitmap *newframe=(*i)->render(pcm, mFrame);
+
+ if (newframe!=mFrame)
+ {
+ nex->bitmapPool()->release(mFrame);
+ mFrame=newframe;
+ }
+ }
+
+ unlock();
+
+ // add source+=source; return source;
+
+ uint8_t *d=(uint8_t*)source->pixels();
+ uint8_t *end=(uint8_t*)((uint8_t*)d+source->bytes());
+ uint8_t *s=(uint8_t*)mFrame->pixels();
+
+ while (d<end)
+ {
+ register int dest=*d;
+ if (dest && ((dest | *s) & 128))
+ {
+ // there's danger of going past 0xFF
+ dest+=*s;
+ if (dest & 256)
+ *d=0xFF; // oops, we did!
+ else
+ *d=dest;
+ }
+ else
+ {
+ // if neither touch the 128th bit, then the sum
+ // can't possibly be more than 0xFF
+ *d=dest+*s;
+ }
+
+
+ ++s;
+ ++d;
+ }
+
+ return source;
+}
+
+void RendererList::save(QDomElement &e)
+{
+ lock();
+ e.setTagName("List");
+
+ for (QPtrListIterator<Renderer> i(mRendererList); *i; ++i)
+ {
+ QDomElement item;
+ (*i)->save(item);
+ e.appendChild(item);
+ }
+
+ unlock();
+}
+
+void RendererList::load(const QDomElement &e)
+{
+ lock();
+
+ for (QDomNode n=e.firstChild(); !n.isNull(); n=n.nextSibling())
+ {
+ if (!n.isElement()) continue;
+ QDomElement child=n.toElement();
+
+ Renderer *r=0;
+
+ if (e.tagName()=="List")
+ r=new RendererList;
+ else
+ r=nex->renderer(e.tagName());
+
+ if (!r) continue;
+
+ r->load(child);
+ mRendererList.append(r);
+ }
+
+ unlock();
+}
+
+
+
+QWidget *RendererList::configure(QWidget *parent)
+{
+ return new RendererListConfigurator(this, parent);
+}
+
+RendererListConfigurator::RendererListConfigurator(RendererList *l, QWidget *parent)
+ : QWidget(parent), mList(l)
+{
+ (new QVBoxLayout(this))->setAutoAdd(true);
+ mErase=new QCheckBox(i18n("&Erase between frames"), this);
+ connect(mErase, SIGNAL(toggled(bool)), SLOT(eraseOn(bool)));
+ mErase->setChecked(mList->mClearAfter);
+
+ if (nex->rendererList()==l)
+ {
+ QCheckBox *mConvolve=new QCheckBox(i18n("&Convolve audio"), this);
+ connect(mConvolve, SIGNAL(toggled(bool)), SLOT(convolve(bool)));
+ mConvolve->setChecked(nex->input()->convolve());
+ }
+
+ new QLabel(i18n("Comments"), this);
+
+ mComments=new QMultiLineEdit(this);
+ mComments->setText(l->mComments);
+ mComments->setWordWrap(QMultiLineEdit::WidgetWidth);
+}
+
+RendererListConfigurator::~RendererListConfigurator()
+{
+ mList->mComments=mComments->text();
+}
+
+void RendererListConfigurator::eraseOn(bool state)
+{
+ mList->mClearAfter=state;
+}
+
+void RendererListConfigurator::convolve(bool state)
+{
+ nex->input()->setConvolve(state);
+}
+
+
+
+#define INSERT(name, func) mCreators.insert(name, new CreatorSig*(&func))
+
+Nex::Nex()
+{
+ sNex=this;
+ mBitmapPool=0;
+ mRendererList=0;
+
+ setupSize(width, height);
+
+ INSERT("Fade", Creators::fade);
+ INSERT("Doubler", Creators::doubler);
+ INSERT("Waveform", Creators::waveform);
+ INSERT("Hartley", Creators::hartley);
+}
+#undef INSERT
+
+void Nex::setupSize(int , int )
+{
+ mInput=new Input;
+ delete mBitmapPool;
+ delete mRendererList;
+ mBitmapPool=new BitmapPool();
+ mRendererList=new RendererList;
+}
+
+Nex::~Nex()
+{
+ delete mRendererList;
+ delete mBitmapPool;
+}
+
+#define NOTHREAD
+
+void Nex::go()
+{
+ runLock.unlock();
+ float *audio[6];
+
+ Bitmap *frame;
+ frame=mBitmapPool->get(true);
+
+ int frames=0;
+ QTime start(QTime::currentTime());
+
+ while (1)
+ {
+ mInput->getAudio(audio);
+ mRendererList->render(audio, frame);
+ int result=mOutput.display(frame);
+
+ frames++;
+
+ switch (result)
+ {
+ case OutputSDL::Exit:
+ std::cerr << "Trying" << std::endl;
+ delete mInput;
+ std::cerr << "Deleted" << std::endl;
+
+ std::cout << "Frames per Second: "
+ << frames/start.secsTo(QTime::currentTime()) << std::endl;
+ return;
+ case OutputSDL::Resize:
+// setupSize(width, height);
+ break;
+ }
+#ifdef NOTHREAD
+ kapp->processEvents();
+#endif
+ frame->clear();
+ }
+}
+
+
+Renderer *Nex::renderer(const QString &name)
+{
+ CreatorSig **sig=mCreators[name];
+ if (sig)
+ return (**sig)();
+ else
+ return 0;
+}
+
+QStringList Nex::renderers() const
+{
+ QDictIterator<CreatorSig*> i(mCreators);
+ QStringList list;
+
+ for (;i.current(); ++i)
+ list += i.currentKey();
+
+ return list;
+}
+
+
+#ifndef NOTHREAD
+class VisThread : public Thread
+{
+public:
+ virtual int run()
+ {
+ Nex::sNex->go();
+ exit(0);
+ return 0;
+ }
+};
+#endif
+
+int main(int argc, char **argv)
+{
+ Nex theNex;
+ Nex::sNex=&theNex;
+
+#ifndef NOTHREAD
+ runLock.lock();
+
+ VisThread vis;
+ vis.start();
+
+ runLock.lock();
+#endif
+
+ KAboutData aboutData("nex", I18N_NOOP("Nex"), "0.0.1",
+ I18N_NOOP("The awesome customizable scope"),
+ KAboutData::License_LGPL, "(C) 2001 Charles Samuels", 0,
+ "http://noatun.kde.org");
+
+ aboutData.addAuthor("Charles Samuels", I18N_NOOP("Nex Author"),
+ "charles@kde.org");
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KApplication app;
+
+
+ (new Control)->show();
+#ifdef NOTHREAD
+ theNex.go();
+
+#else
+ app.exec();
+
+ vis.wait();
+#endif
+ exit(0); //prevent segfault on exit, for some reason
+ return 0;
+}
+
+#include "nex.moc"
+