Add MIDI viewer / visualization

for-marcan
Hector Martin 2010-11-30 06:01:21 +01:00
parent d10c4de9c3
commit 425dc14482
2 changed files with 287 additions and 0 deletions

View File

@ -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})

283
examples/midiview.c Normal file
View File

@ -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(&params, 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(&params);
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);
}