Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/flickernoise
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: f7b8fa1
Choose a base ref
...
head repository: m-labs/flickernoise
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a7e1867
Choose a head ref
  • 7 commits
  • 6 files changed
  • 1 contributor

Commits on Jan 14, 2012

  1. gui/performance.c (patches): convert array to doubly linked list

    This eliminates the MAX_PATCHES limit, which we were about to hit.
    Also makes the code look a bit tidier.
    wpwrak committed Jan 14, 2012
    Copy the full SHA
    44722c4 View commit details
  2. Copy the full SHA
    a605f4e View commit details
  3. gui/performance.c: cache patches for later reuse (WIP)

    This cache is not persistent. Patches are lost when rebooting.
    
    To do:
    - need to check error handling
    - need to check whether images have changed
    wpwrak committed Jan 14, 2012
    Copy the full SHA
    23ce54d View commit details
  4. compiler: record file name and stat for images; report problems (WIP)

    This is a preparation for correct image caching. (Current image
    caching is overzealous.)
    
    This patch also adds basic error reporting if the image file is not
    found or if there is a problem loading it.
    
    To do:
    - do the actual cache check
    - find out why free() complains if assign_image_name returns an
      error
    wpwrak committed Jan 14, 2012
    Copy the full SHA
    ea44cff View commit details
  5. Copy the full SHA
    5f6566e View commit details
  6. Copy the full SHA
    3fd3e84 View commit details
  7. Merge branch 'cache'

    wpwrak committed Jan 14, 2012
    Copy the full SHA
    a7e1867 View commit details
Showing with 241 additions and 111 deletions.
  1. +61 −13 src/compiler/compiler.c
  2. +17 −1 src/compiler/compiler.h
  3. +1 −3 src/compiler/parser.y
  4. +18 −0 src/compiler/test/image
  5. +143 −93 src/gui/performance.c
  6. +1 −1 src/renderer/eval.c
74 changes: 61 additions & 13 deletions src/compiler/compiler.c
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/stat.h>

#include <fpvm/fpvm.h>
#include <fpvm/symbol.h>
@@ -399,9 +400,12 @@ static const char *assign_image_name(struct parser_comm *comm,
#ifndef STANDALONE
struct compiler_sc *sc = comm->u.sc;
char *totalname;
struct image *img;
#endif

if(number > IMAGE_COUNT)
return strdup("image number out of bounds");
#ifndef STANDALONE
number--;

if(*name == '/')
@@ -413,10 +417,25 @@ static const char *assign_image_name(struct parser_comm *comm,
strcpy(totalname, sc->basedir);
strcat(totalname, name);
}
pixbuf_dec_ref(sc->p->images[number]);
sc->p->images[number] = pixbuf_get(totalname);
free(totalname);
#endif /* STANDALONE */

img = sc->p->images+number;
pixbuf_dec_ref(img->pixbuf);
free((void *) img->filename);
img->pixbuf = NULL;
img->filename = NULL;

if(lstat(totalname, &img->st) < 0) {
free(totalname);
return strdup("image file not found");
}
img->pixbuf = pixbuf_get(totalname);
if(img->pixbuf) {
img->filename = totalname;
} else {
free(totalname);
return strdup("cannot load image file");
}
#endif /* !STANDALONE */
return NULL;
}

@@ -456,8 +475,11 @@ struct patch *patch_compile(const char *basedir, const char *patch_code,
free(sc);
return NULL;
}
for(i=0;i<IMAGE_COUNT;i++)
sc->p->images[i] = NULL;
for(i=0;i<IMAGE_COUNT;i++) {
sc->p->images[i].pixbuf = NULL;
sc->p->images[i].filename = NULL;
}
sc->p->ref = 1;
sc->p->require = 0;
sc->p->original = NULL;
sc->p->next = NULL;
@@ -517,25 +539,51 @@ struct patch *patch_compile_filename(const char *filename,
struct patch *patch_copy(struct patch *p)
{
struct patch *new_patch;
int i;
struct image *img;

new_patch = malloc(sizeof(struct patch));
assert(new_patch != NULL);
memcpy(new_patch, p, sizeof(struct patch));
new_patch->ref = 1;
new_patch->original = p;
new_patch->next = NULL;
for(i=0;i<IMAGE_COUNT;i++)
pixbuf_inc_ref(new_patch->images[i]);
for(img = new_patch->images;
img != new_patch->images+IMAGE_COUNT; img++) {
if(img->filename)
img->filename = strdup(img->filename);
pixbuf_inc_ref(img->pixbuf);
}
return new_patch;
}

void patch_free(struct patch *p)
{
int i;

for(i=0;i<IMAGE_COUNT;i++)
pixbuf_dec_ref(p->images[i]);
struct image *img;

assert(p->ref);
if(--p->ref);
return;
for(img = p->images; img != p->images+IMAGE_COUNT; img++) {
pixbuf_dec_ref(img->pixbuf);
free((void *) img->filename);
}
free(p);
}

int patch_images_uptodate(const struct patch *p)
{
const struct image *img;
struct stat st;

for(img = p->images; img != p->images+IMAGE_COUNT; img++) {
if(!img->pixbuf)
continue;
if(lstat(img->filename, &st) < 0)
return 0;
if(st.st_mtime != img->st.st_mtime)
return 0;
}
return 1;
}

#endif
18 changes: 17 additions & 1 deletion src/compiler/compiler.h
Original file line number Diff line number Diff line change
@@ -25,6 +25,8 @@
#include STANDALONE
#endif /* STANDALONE */

#include <sys/stat.h>

#include <fpvm/fpvm.h>

#include "../renderer/framedescriptor.h"
@@ -217,9 +219,15 @@ enum {
#define REQUIRE_MIDI (1 << 2)
#define REQUIRE_VIDEO (1 << 3)

struct image {
struct pixbuf *pixbuf; /* NULL if unused */
const char *filename; /* undefined if unused */
struct stat st;
};

struct patch {
/* per-frame */
struct pixbuf *images[IMAGE_COUNT]; /* < images used in this patch */
struct image images[IMAGE_COUNT]; /* < images used in this patch */
float pfv_initial[COMP_PFV_COUNT]; /* < patch initial conditions */
int pfv_allocation[COMP_PFV_COUNT]; /* < where per-frame variables are mapped in PFPU regf, -1 if unmapped */
int perframe_prog_length; /* < how many instructions in perframe_prog */
@@ -233,14 +241,22 @@ struct patch {
/* meta */
unsigned int require; /* < bitmask: dmx, osc, midi, video */
void *original; /* < original patch (with initial register values) */
int ref; /* reference count */
struct patch *next; /* < used when chaining patches in mashups */
};

typedef void (*report_message)(const char *);

static inline struct patch *patch_clone(struct patch *p)
{
p->ref++;
return p;
}

struct patch *patch_compile(const char *basedir, const char *patch_code, report_message rmc);
struct patch *patch_compile_filename(const char *filename, const char *patch_code, report_message rmc);
struct patch *patch_copy(struct patch *p);
void patch_free(struct patch *p);
int patch_images_uptodate(const struct patch *p);

#endif /* __COMPILER_H */
4 changes: 1 addition & 3 deletions src/compiler/parser.y
Original file line number Diff line number Diff line change
@@ -293,14 +293,12 @@ assignment ::= TOK_IMAGEFILE(I) TOK_ASSIGN TOK_FNAME(N). {

msg = state->comm->assign_image_name(state->comm,
atoi(I->label+9), N->fname);
free(I);
if(msg) {
FAIL(msg);
free((void *) msg);
free((void *) N->fname);
free(N);
return;
}
free(I);
free((void *) N->fname);
free(N);
}
18 changes: 18 additions & 0 deletions src/compiler/test/image
Original file line number Diff line number Diff line change
@@ -66,4 +66,22 @@ expect <<EOF
image 1 = "*** test - robust & ness ***"
EOF

#------------------------------------------------------------------------------

ptest_fail "image: imagefile0=foo" -c <<EOF
imagefile0=foo
EOF
expect <<EOF
line 2: can initialize non-system variables only to zero near 'EOF'
EOF

#------------------------------------------------------------------------------

ptest_fail "image: imagefile3=foo" -c <<EOF
imagefile3=foo
EOF
expect <<EOF
line 2: image number out of bounds near 'EOF'
EOF

###############################################################################
236 changes: 143 additions & 93 deletions src/gui/performance.c
Original file line number Diff line number Diff line change
@@ -41,41 +41,54 @@

#define FILENAME_LEN 384

#define MAX_PATCHES 64

struct patch_info {
char filename[FILENAME_LEN];
struct patch *p;
struct stat st;
struct patch_info *prev, *next;
};

static int npatches;
static struct patch_info patches[MAX_PATCHES];
static struct patch_info *patches = NULL;
static struct patch_info *cache = NULL;
static struct patch_info *last_patch = NULL;
static int simple_mode;
static int simple_mode_current;
static struct patch_info *simple_mode_current;
static int dt_mode;
static int as_mode;
static int input_video;
static int showing_title;

static int add_patch(const char *filename)
static struct patch_info *add_patch(const char *filename)
{
int i;
struct patch_info *pi;

for(i=0;i<npatches;i++) {
if(strcmp(patches[i].filename, filename) == 0)
return i;
}
if(npatches == MAX_PATCHES) return -1;
strcpy(patches[npatches].filename, filename);
patches[npatches].p = NULL;
return npatches++;
}
for(pi = patches; pi; pi = pi->next)
if(strcmp(pi->filename, filename) == 0)
return pi;

static int keyboard_patches[26];
static int ir_patches[64];
pi = malloc(sizeof(struct patch_info));
if(!pi)
return NULL;
strcpy(pi->filename, filename);
pi->p = NULL;
if(last_patch)
last_patch->next = pi;
else
patches = pi;
pi->next = NULL;
pi->prev = last_patch;
last_patch = pi;
npatches++;

return pi;
}

static struct patch_info *keyboard_patches[26];
static struct patch_info *ir_patches[64];
static int midi_channel;
static int midi_patches[128];
static int osc_patches[64];
static struct patch_info *midi_patches[128];
static struct patch_info *osc_patches[64];

static void add_firstpatch(void)
{
@@ -100,7 +113,7 @@ static void add_keyboard_patches(void)
if(filename != NULL)
keyboard_patches[i] = add_patch(filename);
else
keyboard_patches[i] = -1;
keyboard_patches[i] = NULL;
}
}

@@ -116,7 +129,7 @@ static void add_ir_patches(void)
if(filename != NULL)
ir_patches[i] = add_patch(filename);
else
ir_patches[i] = -1;
ir_patches[i] = NULL;
}
}

@@ -133,7 +146,7 @@ static void add_midi_patches(void)
if(filename != NULL)
midi_patches[i] = add_patch(filename);
else
midi_patches[i] = -1;
midi_patches[i] = NULL;
}
}

@@ -149,7 +162,7 @@ static void add_osc_patches(void)
if(filename != NULL)
osc_patches[i] = add_patch(filename);
else
osc_patches[i] = -1;
osc_patches[i] = NULL;
}
}

@@ -189,10 +202,14 @@ static void close_callback(mtk_event *e, void *arg)

static void update_buttons(void)
{
mtk_cmdf(appid, "b_mode_simple.set(-state %s)", simple_mode ? "on" : "off");
mtk_cmdf(appid, "b_mode_file.set(-state %s)", !simple_mode ? "on" : "off");
mtk_cmdf(appid, "b_mode_simple_dt.set(-state %s)", dt_mode ? "on" : "off");
mtk_cmdf(appid, "b_mode_simple_as.set(-state %s)", as_mode ? "on" : "off");
mtk_cmdf(appid, "b_mode_simple.set(-state %s)",
simple_mode ? "on" : "off");
mtk_cmdf(appid, "b_mode_file.set(-state %s)",
!simple_mode ? "on" : "off");
mtk_cmdf(appid, "b_mode_simple_dt.set(-state %s)",
dt_mode ? "on" : "off");
mtk_cmdf(appid, "b_mode_simple_as.set(-state %s)",
as_mode ? "on" : "off");
}

static void simple_callback(mtk_event *e, void *arg)
@@ -277,62 +294,83 @@ void init_performance(void)
}

static int compiled_patches;
struct patch_info *error_patch;
#define UPDATE_PERIOD 20
static rtems_interval next_update;

static void dummy_rmc(const char *msg)
{
}

static struct patch *compile_patch(const char *filename)
static struct patch *compile_patch(const char *filename, const struct stat *st)
{
FILE *file;
struct stat st;
int r;
char *buf = NULL;
struct patch *p;

file = fopen(filename, "r");
if(file == NULL)
return NULL;
if(fstat(fileno(file), &st) < 0)
goto fail;
buf = malloc(st.st_size+1);
r = fread(buf, 1, st.st_size, file);
if(r <= 0)
goto fail;
buf = malloc(st->st_size+1);
r = fread(buf, 1, st->st_size, file);
if(r <= 0) {
free(buf);
fclose(file);
return NULL;
}

buf[r] = 0;
fclose(file);

p = patch_compile_filename(filename, buf, dummy_rmc);
free(buf);
return p;
}

fail:
free(buf);
fclose(file);
static struct patch *cache_lookup(const struct patch_info *pi)
{
const struct patch_info *c;

for(c = cache; c; c = c->next)
if(c->st.st_mtime == pi->st.st_mtime &&
!strcmp(c->filename, pi->filename) &&
patch_images_uptodate(c->p))
return patch_clone(c->p);
return NULL;
}

static rtems_task comp_task(rtems_task_argument argument)
{
for(;compiled_patches<npatches;compiled_patches++) {
patches[compiled_patches].p = compile_patch(patches[compiled_patches].filename);
if(patches[compiled_patches].p == NULL) {
compiled_patches = -compiled_patches-1;
struct patch_info *pi;

for(pi = patches; pi; pi = pi->next) {
if(lstat(pi->filename, &pi->st) < 0) {
pi->p = NULL;
} else {
pi->p = cache_lookup(pi);
if(!pi->p)
pi->p = compile_patch(pi->filename, &pi->st);
}
if(!pi->p) {
error_patch = pi;
break;
}
compiled_patches++;
}
rtems_task_delete(RTEMS_SELF);
}

static void free_patches(void)
static void free_patches(struct patch_info *list)
{
int i;
struct patch_info *next;

for(i=0;i<npatches;i++) {
if(patches[i].p != NULL)
patch_free(patches[i].p);
while(list) {
next = list->next;
if(list->p)
patch_free(list->p);
free(list);
list = next;
}
}

@@ -378,7 +416,8 @@ static void update_next_as_time(void)
rtems_interval t;

t = rtems_clock_get_ticks_since_boot();
next_as_time = t + AUTOSWITCH_PERIOD_MIN + (rand() % (AUTOSWITCH_PERIOD_MAX - AUTOSWITCH_PERIOD_MIN));
next_as_time = t + AUTOSWITCH_PERIOD_MIN +
(rand() % (AUTOSWITCH_PERIOD_MAX - AUTOSWITCH_PERIOD_MIN));
}

static int suitable_for_simple(struct patch *p)
@@ -395,16 +434,21 @@ static int suitable_for_simple(struct patch *p)

static void skip_unsuitable(int next)
{
int looped;
const struct patch_info *looped;

looped = simple_mode_current;
while(1) {
simple_mode_current += next;
if(simple_mode_current == npatches)
simple_mode_current = 0;
if(simple_mode_current < 0)
simple_mode_current = npatches - 1;
if(suitable_for_simple(patches[simple_mode_current].p))
if(next == 1) {
simple_mode_current = simple_mode_current->next;
if(!simple_mode_current)
simple_mode_current = patches;
}
if(next == -1) {
simple_mode_current = simple_mode_current->prev;
if(!simple_mode_current)
simple_mode_current = last_patch;
}
if(suitable_for_simple(simple_mode_current->p))
break;
if(!next) {
next = 1;
@@ -425,7 +469,7 @@ static void simple_mode_event(mtk_event *e, int *next)
if(e->type != EVENT_TYPE_PRESS)
return;
if(e->press.code == MTK_KEY_F1) {
osd_event_cb(patches[simple_mode_current].filename, osd_off);
osd_event_cb(simple_mode_current->filename, osd_off);
showing_title = 1;
}
if(e->press.code == MTK_KEY_F11)
@@ -437,55 +481,56 @@ static void simple_mode_event(mtk_event *e, int *next)
static void simple_mode_next(int next)
{
skip_unsuitable(next);
renderer_pulse_patch(patches[simple_mode_current].p);
renderer_pulse_patch(simple_mode_current->p);
if(as_mode)
update_next_as_time();
if(dt_mode || showing_title)
osd_event_cb(patches[simple_mode_current].filename, osd_off);
osd_event_cb(simple_mode_current->filename, osd_off);
}

static void configured_mode_event(mtk_event *e)
{
struct patch_info *pi;
int index;

if(e->type == EVENT_TYPE_PRESS) {
index = keycode_to_index(e->press.code);
if(index != -1) {
index = keyboard_patches[index];
if(index != -1)
renderer_add_patch(patches[index].p);
}
pi = keyboard_patches[index];
if(pi)
renderer_add_patch(pi->p);
}
} else if(e->type == EVENT_TYPE_RELEASE) {
index = keycode_to_index(e->release.code);
if(index != -1) {
index = keyboard_patches[index];
if(index != -1)
renderer_del_patch(patches[index].p);
pi = keyboard_patches[index];
if(pi)
renderer_del_patch(pi->p);
}
} else if(e->type == EVENT_TYPE_IR) {
index = e->press.code;
index = ir_patches[index];
if(index != -1)
renderer_pulse_patch(patches[index].p);
pi = ir_patches[index];
if(pi)
renderer_pulse_patch(pi->p);
} else if(e->type == EVENT_TYPE_MIDI_NOTEON) {
if(((e->press.code & 0x0f0000) >> 16) == midi_channel) {
index = e->press.code & 0x7f;
index = midi_patches[index];
if(index != -1)
renderer_add_patch(patches[index].p);
pi = midi_patches[index];
if(pi)
renderer_add_patch(pi->p);
}
} else if(e->type == EVENT_TYPE_MIDI_NOTEOFF) {
if(((e->press.code & 0x0f0000) >> 16) == midi_channel) {
index = e->press.code & 0x7f;
index = midi_patches[index];
if(index != -1)
renderer_del_patch(patches[index].p);
pi = midi_patches[index];
if(pi)
renderer_del_patch(pi->p);
}
} else if(e->type == EVENT_TYPE_OSC) {
index = e->press.code & 0x3f;
index = osc_patches[index];
if(index != -1)
renderer_pulse_patch(patches[index].p);
pi = osc_patches[index];
if(pi)
renderer_pulse_patch(pi->p);
}
}

@@ -500,8 +545,8 @@ static void event_callback(mtk_event *e, int count)
* We can can't show the first title in start_rendering
* because the renderer isn't up yet. So we do it here.
*/
if (first_event && dt_mode)
osd_event(patches[simple_mode_current].filename);
if(first_event && dt_mode)
osd_event(simple_mode_current->filename);
next = 0;
for(i=0;i<count;i++)
simple_mode_event(e+i, &next);
@@ -521,26 +566,30 @@ static void event_callback(mtk_event *e, int count)

static void stop_callback(void)
{
free_patches();
free_patches(cache);
cache = patches;
patches = NULL;
last_patch = NULL;

started = 0;
input_delete_callback(event_callback);
}

static void start_rendering(void)
{
int index = 0;
struct patch_info *first = patches;

update_next_as_time();
input_add_callback(event_callback);
mtk_cmd(appid, "l_status.set(-text \"Ready.\")");

if(simple_mode) {
skip_unsuitable(0);
index = simple_mode_current;
first = simple_mode_current;
}

first_event = 1;
if(!guirender(appid, patches[index].p, stop_callback))
if(!guirender(appid, first->p, stop_callback))
stop_callback();
}

@@ -551,7 +600,7 @@ static void refresh_callback(mtk_event *e, int count)
t = rtems_clock_get_ticks_since_boot();
if(t < next_update)
return;
if(compiled_patches >= 0) {
if(!error_patch) {
mtk_cmdf(appid, "progress.barconfig(load, -value %d)",
(100*compiled_patches)/npatches);
if(compiled_patches == npatches) {
@@ -561,15 +610,14 @@ static void refresh_callback(mtk_event *e, int count)
return;
}
} else {
int error_patch;

error_patch = -compiled_patches-1;
mtk_cmdf(appid,
"l_status.set(-text \"Failed to compile patch %s\")",
patches[error_patch].filename);
error_patch->filename);
input_delete_callback(refresh_callback);
started = 0;
free_patches();
free_patches(patches);
patches = NULL;
last_patch = NULL;
fb_unblank();
return;
}
@@ -615,7 +663,6 @@ void start_performance(int simple, int dt, int as)

/* build patch list */
npatches = 0;
simple_mode_current = 0;
if(simple) {
input_video = check_input_video();
add_simple_patches();
@@ -638,16 +685,19 @@ void start_performance(int simple, int dt, int as)
add_midi_patches();
add_osc_patches();
}
simple_mode_current = patches;

/* start patch compilation task */
compiled_patches = 0;
error_patch = NULL;
mtk_cmd(appid, "l_status.set(-text \"Compiling patches...\")");
mtk_cmd(appid, "progress.barconfig(load, -value 0)");
next_update = rtems_clock_get_ticks_since_boot() + UPDATE_PERIOD;
input_add_callback(refresh_callback);
sc = rtems_task_create(rtems_build_name('C', 'O', 'M', 'P'), 20, 300*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
0, &comp_task_id);
sc = rtems_task_create(rtems_build_name('C', 'O', 'M', 'P'),
20, 300*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
0, &comp_task_id);
assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_start(comp_task_id, comp_task, 0);
assert(sc == RTEMS_SUCCESSFUL);
2 changes: 1 addition & 1 deletion src/renderer/eval.c
Original file line number Diff line number Diff line change
@@ -312,7 +312,7 @@ static rtems_task eval_task(rtems_task_argument argument)
* will be valid until the renderer has fully stopped.
*/
for(i=0;i<IMAGE_COUNT;i++)
frd->images[i] = p->images[i];
frd->images[i] = p->images[i].pixbuf;

reinit_all_pfv(p);
set_pfv_from_frd(p, frd);