Add MIDI viewer / visualization
parent
d10c4de9c3
commit
425dc14482
|
@ -27,3 +27,7 @@ target_link_libraries(simple openlase)
|
|||
|
||||
add_executable(pong pong.c)
|
||||
target_link_libraries(pong openlase)
|
||||
|
||||
find_package(ALSA REQUIRED)
|
||||
add_executable(midiview midiview.c)
|
||||
target_link_libraries(midiview openlase ${ALSA_LIBRARIES})
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
OpenLase - a realtime laser graphics toolkit
|
||||
|
||||
Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
|
||||
|
||||
This program 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 or version 3.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libol.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <jack/jack.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <math.h>
|
||||
|
||||
int portid;
|
||||
|
||||
struct blip {
|
||||
int active;
|
||||
float ts;
|
||||
float age;
|
||||
float x, y;
|
||||
float r;
|
||||
float phase;
|
||||
float bright;
|
||||
int note;
|
||||
};
|
||||
|
||||
float notespeed = 1.0;
|
||||
float avgnotes = 0.0;
|
||||
|
||||
#define NUM_BLIPS 32
|
||||
|
||||
int cur_blip = 0;
|
||||
struct blip blips[NUM_BLIPS];
|
||||
|
||||
snd_seq_t *open_seq(void) {
|
||||
snd_seq_t *seq_handle;
|
||||
|
||||
if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, 0) < 0) {
|
||||
fprintf(stderr, "Error opening ALSA sequencer.\n");
|
||||
return NULL;
|
||||
}
|
||||
snd_seq_set_client_name(seq_handle, "midiview");
|
||||
if ((portid = snd_seq_create_simple_port(seq_handle, "midiview",
|
||||
SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
|
||||
SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
|
||||
fprintf(stderr, "Error creating sequencer port.\n");
|
||||
return NULL;
|
||||
}
|
||||
return seq_handle;
|
||||
}
|
||||
|
||||
void note_on(int note, int velocity)
|
||||
{
|
||||
float ts = avgnotes;
|
||||
if (ts > 20)
|
||||
ts = 20;
|
||||
|
||||
blips[cur_blip].active = 1;
|
||||
blips[cur_blip].ts = ts;
|
||||
int xp = (note) % 12;
|
||||
blips[cur_blip].x = (xp / 6.0 - 1.0)* 0.6;
|
||||
blips[cur_blip].y = (2*note/127.0)-1.0;
|
||||
blips[cur_blip].r = 0.05;
|
||||
blips[cur_blip].bright = 0.3+(velocity / 70.0);
|
||||
blips[cur_blip].phase = 1;
|
||||
blips[cur_blip].note = 1;
|
||||
|
||||
cur_blip = (cur_blip + 1) % NUM_BLIPS;
|
||||
}
|
||||
|
||||
int midi_action(snd_seq_t *seq_handle) {
|
||||
|
||||
snd_seq_event_t *ev;
|
||||
int cnt = 0;
|
||||
|
||||
do {
|
||||
snd_seq_event_input(seq_handle, &ev);
|
||||
switch (ev->type) {
|
||||
case SND_SEQ_EVENT_NOTEON:
|
||||
if (ev->data.note.velocity != 0) {
|
||||
note_on(ev->data.note.note, ev->data.note.velocity);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
snd_seq_free_event(ev);
|
||||
} while (snd_seq_event_input_pending(seq_handle, 0) > 0);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
#define CP 0.55228475f
|
||||
|
||||
void circle(float x, float y, float r, uint32_t color)
|
||||
{
|
||||
olPushMatrix();
|
||||
olPushColor();
|
||||
olMultColor(color);
|
||||
olTranslate(x, y);
|
||||
olRotate((x+y)*123);
|
||||
/*olBegin(OL_BEZIERSTRIP);
|
||||
olVertex(0, r, color);
|
||||
int i;
|
||||
for (i=0; i<2; i++) {
|
||||
olVertex(CP*r, r, C_WHITE);
|
||||
olVertex(r, CP*r, C_WHITE);
|
||||
olVertex(r, 0, C_WHITE);
|
||||
olVertex(r, -CP*r, C_WHITE);
|
||||
olVertex(CP*r, -r, C_WHITE);
|
||||
olVertex(0, -r, C_WHITE);
|
||||
olVertex(-CP*r, -r, C_WHITE);
|
||||
olVertex(-r, -CP*r, C_WHITE);
|
||||
olVertex(-r, 0, C_WHITE);
|
||||
olVertex(-r, CP*r, C_WHITE);
|
||||
olVertex(-CP*r, r, C_WHITE);
|
||||
olVertex(0, r, C_WHITE);
|
||||
}*/
|
||||
/* olVertex(0, r, color);
|
||||
olVertex(0, r, color);
|
||||
olVertex(r*0.1, r, color);
|
||||
olVertex(r*0.1, r, color);*/
|
||||
|
||||
float circum = 2 * M_PI * r;
|
||||
int segments = circum / (1/30.0);
|
||||
if (segments < 50)
|
||||
segments = 50;
|
||||
int i;
|
||||
olBegin(OL_POINTS);
|
||||
olVertex(r, 0, 0);
|
||||
for (i=0; i<=(2*segments+10); i++) {
|
||||
float w = i * M_PI * 2.0 / segments;
|
||||
uint32_t c = C_WHITE;
|
||||
if (i > 2*segments)
|
||||
c = C_GREY((10-(i-segments)) * 28);
|
||||
else if (i < 3)
|
||||
c = C_GREY(i * 85);
|
||||
olVertex(r*cosf(w), r*sinf(w), c);
|
||||
}
|
||||
olEnd();
|
||||
olPopColor();
|
||||
olPopMatrix();
|
||||
}
|
||||
|
||||
int draw(void)
|
||||
{
|
||||
int i;
|
||||
int cnt = 0;
|
||||
for (i=0; i<NUM_BLIPS; i++) {
|
||||
struct blip *b = &blips[i];
|
||||
if (b->active) {
|
||||
float br = b->bright * b->phase * 255.0;
|
||||
br = br > 255 ? 255 : br;
|
||||
uint32_t col = C_GREY((int)br);
|
||||
circle(b->x, b->y, b->r, col);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void animate(float time)
|
||||
{
|
||||
int i;
|
||||
float ts = avgnotes;
|
||||
if (ts > 20)
|
||||
ts = 20;
|
||||
for (i=0; i<NUM_BLIPS; i++) {
|
||||
struct blip *b = &blips[i];
|
||||
|
||||
if (b->active) {
|
||||
//if (b->age < 0.3 && b->ts < ts)
|
||||
// b->ts = ts;
|
||||
float bt = time * ts/14;
|
||||
b->r *= powf(300.0f, bt);
|
||||
//b->r += bt*1.4;
|
||||
b->phase -= bt * 2;
|
||||
if (b->r > 0.7 || b->phase < 0 || b->bright * b->phase < 0.3)
|
||||
b->active = 0;
|
||||
b->age += time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
snd_seq_t *seq_handle;
|
||||
int npfd;
|
||||
struct pollfd *pfd;
|
||||
|
||||
seq_handle = open_seq();
|
||||
npfd = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
|
||||
pfd = malloc(npfd * sizeof(*pfd));
|
||||
snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN);
|
||||
|
||||
if (argc == 2) {
|
||||
snd_seq_addr_t addr;
|
||||
if (snd_seq_parse_address(seq_handle, &addr, argv[1]) == 0) {
|
||||
if (snd_seq_connect_from(seq_handle, portid, addr.client, addr.port) == 0) {
|
||||
printf("Connected to %s\n", argv[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OLRenderParams params;
|
||||
|
||||
memset(¶ms, 0, sizeof params);
|
||||
params.rate = 48000;
|
||||
params.on_speed = 2.0/50.0;
|
||||
params.off_speed = 2.0/35.0;
|
||||
params.start_wait = 6;
|
||||
params.start_dwell = 1;
|
||||
params.curve_dwell = 0;
|
||||
params.corner_dwell = 0;
|
||||
params.curve_angle = cosf(30.0*(M_PI/180.0)); // 30 deg
|
||||
params.end_dwell = 0;
|
||||
params.end_wait = 7;
|
||||
params.flatness = 0.00001;
|
||||
params.snap = 1/100000.0;
|
||||
params.render_flags = RENDER_GRAYSCALE;
|
||||
|
||||
if(olInit(3, 30000) < 0)
|
||||
return 1;
|
||||
|
||||
olSetRenderParams(¶ms);
|
||||
|
||||
float time = 0;
|
||||
float ftime;
|
||||
int i,j;
|
||||
|
||||
int frames = 0;
|
||||
|
||||
float nps = 0;
|
||||
avgnotes = 5;
|
||||
|
||||
while(1) {
|
||||
olLoadIdentity();
|
||||
|
||||
int drawn = draw();
|
||||
if (drawn < 2)
|
||||
draw();
|
||||
|
||||
ftime = olRenderFrame(100);
|
||||
|
||||
float t = powf(0.3, ftime);
|
||||
avgnotes = avgnotes * t + (nps+2) * (1.0f-t);
|
||||
|
||||
animate(ftime);
|
||||
|
||||
int notes = 0;
|
||||
if (poll(pfd, npfd, 0) > 0)
|
||||
notes = midi_action(seq_handle);
|
||||
|
||||
int pnotes = notes;
|
||||
if (pnotes > 1)
|
||||
pnotes = 1;
|
||||
|
||||
nps = pnotes / ftime * 1.2;
|
||||
|
||||
frames++;
|
||||
time += ftime;
|
||||
printf("Frame time: %f, Avg FPS:%f, Cur FPS:%f, %d, nps:%3d, avgnotes:%f\n", ftime, frames/time, 1/ftime, notes, (int)nps, avgnotes);
|
||||
}
|
||||
|
||||
olShutdown();
|
||||
exit (0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue