Skip to content

Commit

Permalink
MythMusic: Add a 88-Key Piano Visualization
Browse files Browse the repository at this point in the history
Basically, it's a spectrum analyzer that detects frequencies specifically at
the pitches of a piano keyboard, and then displays the notes being pressed on
a piano keyboard displayed across the screen. Thanks to Martin Andrews for the
patch. Closes #10214.

Note: Edited slightly to match our coding standards.
Signed-off-by: Paul Harrison <pharrison@mythtv.org>
  • Loading branch information
Martin Andrews authored and Paul Harrison committed Dec 29, 2011
1 parent 1e9d43a commit 845b087
Show file tree
Hide file tree
Showing 4 changed files with 579 additions and 22 deletions.
50 changes: 28 additions & 22 deletions mythplugins/mythmusic/mythmusic/mainvisual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void VisualBase::drawWarning(QPainter *p, const QColor &back, const QSize &size,
}

MainVisual::MainVisual(QWidget *parent, const char *name)
: QWidget(parent), vis(0), playing(false), fps(20),
: QWidget(parent), vis(0), playing(false), fps(20), samples(SAMPLES_DEFAULT_SIZE),
timer (0), bannerTimer(0), info_widget(0)
{
setObjectName(name);
Expand Down Expand Up @@ -144,6 +144,7 @@ void MainVisual::setVisual(const QString &name)
vis = pVisFactory->create(this, (long int) winId(), pluginName);
vis->resize(size());
fps = vis->getDesiredFPS();
samples = vis->getDesiredSamples();
break;
}
}
Expand All @@ -163,44 +164,46 @@ void MainVisual::prepare()
}
}

// This is called via : mythtv/libs/libmyth/output.cpp :: OutputListeners::dispatchVisual
// from : mythtv/libs/libmyth/audio/audiooutputbase.cpp :: AudioOutputBase::AddData
// Caller holds mutex() lock
void MainVisual::add(uchar *b, unsigned long b_len, unsigned long w, int c, int p)
void MainVisual::add(uchar *buffer, unsigned long b_len, unsigned long timecode, int source_channels, int bits_per_sample)
{
long len = b_len, cnt;
unsigned long len = b_len, cnt;
short *l = 0, *r = 0;

len /= c;
len /= (p / 8);
// len is length of buffer in fully converted samples
len /= source_channels;
len /= (bits_per_sample / 8);

#define SAMPLES 512
if (len > SAMPLES)
len = SAMPLES;
if (len > samples)
len = samples;

cnt = len;

if (c == 2)
if (source_channels == 2)
{
l = new short[len];
r = new short[len];

if (p == 8)
stereo16_from_stereopcm8(l, r, b, cnt);
else if (p == 16)
stereo16_from_stereopcm16(l, r, (short *) b, cnt);
if (bits_per_sample == 8)
stereo16_from_stereopcm8(l, r, buffer, cnt);
else if (bits_per_sample == 16)
stereo16_from_stereopcm16(l, r, (short *) buffer, cnt);
}
else if (c == 1)
else if (source_channels == 1)
{
l = new short[len];

if (p == 8)
mono16_from_monopcm8(l, b, cnt);
else if (p == 16)
mono16_from_monopcm16(l, (short *) b, cnt);
if (bits_per_sample == 8)
mono16_from_monopcm8(l, buffer, cnt);
else if (bits_per_sample == 16)
mono16_from_monopcm16(l, (short *) buffer, cnt);
}
else
len = 0;

nodes.append(new VisualNode(l, r, len, w));
nodes.append(new VisualNode(l, r, len, timecode));
}

void MainVisual::timeout()
Expand All @@ -220,6 +223,9 @@ void MainVisual::timeout()
break;
nodes.pop_front();

if (vis)
vis->processUndisplayed(node);

delete node;
node = n;
}
Expand All @@ -233,7 +239,7 @@ void MainVisual::timeout()
stop = vis->process(node);
QPainter p(&pixmap);
if (vis->draw(&p, Qt::black))
update();
update(); // This implictly picks up the data in pixmap, filled in by draw
}

if (!playing && stop)
Expand Down Expand Up @@ -519,7 +525,7 @@ bool StereoScope::process( VisualNode *node )

if (node) {
double index = 0;
double const step = (double)SAMPLES / size.width();
double const step = (double)SAMPLES_DEFAULT_SIZE / size.width();
for ( int i = 0; i < size.width(); i++) {
unsigned long indexTo = (unsigned long)(index + step);
if (indexTo == (unsigned long)(index))
Expand Down Expand Up @@ -722,7 +728,7 @@ bool MonoScope::process( VisualNode *node )
if (node)
{
double index = 0;
double const step = (double)SAMPLES / size.width();
double const step = (double)SAMPLES_DEFAULT_SIZE / size.width();
for (int i = 0; i < size.width(); i++)
{
unsigned long indexTo = (unsigned long)(index + step);
Expand Down
13 changes: 13 additions & 0 deletions mythplugins/mythmusic/mythmusic/mainvisual.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class InfoWidget;
class Metadata;
class MainVisual;

#define SAMPLES_DEFAULT_SIZE 512

class VisualNode
{
public:
Expand Down Expand Up @@ -60,10 +62,20 @@ class VisualBase

// return true if the output should stop
virtual bool process( VisualNode *node ) = 0;

// this is called on nodes that will not be displayed :: Not needed for most visualizations
// (i.e. between the displayed frames, if you need the whole audio stream)
virtual bool processUndisplayed( VisualNode * )
{
return true; // By default this does nothing : Ignore the in-between chunks of audio data
};

virtual bool draw( QPainter *, const QColor & ) = 0;
virtual void resize( const QSize &size ) = 0;
virtual void handleKeyPress(const QString &action) = 0;
virtual int getDesiredFPS(void) { return fps; }
// Override this if you need the potential of capturing more data than the default
virtual unsigned long getDesiredSamples(void) { return SAMPLES_DEFAULT_SIZE; }
void drawWarning(QPainter *, const QColor &, const QSize &, QString);

protected:
Expand Down Expand Up @@ -133,6 +145,7 @@ public slots:
QList<VisualNode*> nodes;
bool playing;
int fps;
unsigned long samples;
QTimer *timer;
QTimer *bannerTimer;
InfoWidget* info_widget;
Expand Down
Loading

0 comments on commit 845b087

Please sign in to comment.