Gavan Fantom
18 years ago
commit
163fea6b89
33 changed files with 5627 additions and 0 deletions
@ -0,0 +1,10 @@ |
|||||||
|
#!/bin/sh |
||||||
|
|
||||||
|
SUBDIRS="common lsc lsi" |
||||||
|
|
||||||
|
for dir in ${SUBDIRS} |
||||||
|
do |
||||||
|
cd ${dir} |
||||||
|
make $* |
||||||
|
cd .. |
||||||
|
done |
@ -0,0 +1,19 @@ |
|||||||
|
# Makefile
|
||||||
|
|
||||||
|
OBJS= hash.o mem.o
|
||||||
|
SRCS= hash.c mem.c
|
||||||
|
|
||||||
|
INCDIR=../include
|
||||||
|
|
||||||
|
CFLAGS+= -Wall -Werror
|
||||||
|
CPPFLAGS+= -I${INCDIR}
|
||||||
|
|
||||||
|
all: ${OBJS} |
||||||
|
|
||||||
|
install: |
||||||
|
|
||||||
|
depend: |
||||||
|
mkdep -- ${CFLAGS} ${CPPFLAGS} ${SRCS}
|
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f ${OBJS}
|
@ -0,0 +1,105 @@ |
|||||||
|
/* hash.c */ |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include "hash.h" |
||||||
|
#include "mem.h" |
||||||
|
|
||||||
|
/*
|
||||||
|
* Declare hash as: |
||||||
|
* struct hashentry hash[HASHSIZE]; |
||||||
|
* |
||||||
|
* Initialise with hash_init(hash); |
||||||
|
* free all hash items with hash_clear(hash); |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* Based on Jenkins one-at-a-time hash, from |
||||||
|
* http://en.wikipedia.org/wiki/Hash_table
|
||||||
|
*/ |
||||||
|
|
||||||
|
int hashfn(char *key) |
||||||
|
{ |
||||||
|
uint32_t hash = 0; |
||||||
|
size_t i; |
||||||
|
size_t len = strlen(key); |
||||||
|
|
||||||
|
for (i = 0; i < len; i++) |
||||||
|
{ |
||||||
|
hash += key[i]; |
||||||
|
hash += (hash << 10); |
||||||
|
hash ^= (hash >> 6); |
||||||
|
} |
||||||
|
|
||||||
|
hash += (hash << 3); |
||||||
|
hash ^= (hash >> 11); |
||||||
|
hash += (hash << 15); |
||||||
|
|
||||||
|
return hash & HASHMASK; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void hash_iterate(struct hashentry **hash, void (*fn)(struct hashentry *)) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
struct hashentry *hashptr; |
||||||
|
|
||||||
|
for (i = 0; i < HASHSIZE; i++) |
||||||
|
if (hash[i]) { |
||||||
|
hashptr = hash[i]; |
||||||
|
while (hashptr) { |
||||||
|
fn(hashptr); |
||||||
|
hashptr = hashptr->next; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void hash_clear(struct hashentry **hash) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
struct hashentry *hashptr; |
||||||
|
struct hashentry *last; |
||||||
|
|
||||||
|
for (i = 0; i < HASHSIZE; i++) |
||||||
|
if (hash[i]) { |
||||||
|
hashptr = hash[i]; |
||||||
|
while (hashptr) { |
||||||
|
last = hashptr; |
||||||
|
hashptr = hashptr->next; |
||||||
|
free(last); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void hash_init(struct hashentry **hash) |
||||||
|
{ |
||||||
|
bzero(hash, sizeof(struct hashentry *) * HASHSIZE); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
struct hashentry *hash_lookup(struct hashentry **base, char *key, int create) |
||||||
|
{ |
||||||
|
struct hashentry *hashptr; |
||||||
|
int hash; |
||||||
|
int found; |
||||||
|
|
||||||
|
hash = hashfn(key); |
||||||
|
hashptr = base[hash]; |
||||||
|
found = 0; |
||||||
|
|
||||||
|
while (hashptr) { |
||||||
|
if (strcmp(key, hashptr->name) == 0) |
||||||
|
return hashptr; |
||||||
|
hashptr = hashptr->next; |
||||||
|
} |
||||||
|
|
||||||
|
if (!create) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
hashptr = safe_malloc(sizeof(struct hashentry)); |
||||||
|
hashptr->next = base[hash]; |
||||||
|
hashptr->name = NULL; /* Signal that this is new */ |
||||||
|
base[hash] = hashptr; |
||||||
|
|
||||||
|
return hashptr; |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* mem.c */ |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <err.h> |
||||||
|
|
||||||
|
void *safe_malloc(size_t size) |
||||||
|
{ |
||||||
|
void *mem; |
||||||
|
|
||||||
|
mem = malloc(size); |
||||||
|
if (mem == NULL) |
||||||
|
err(EXIT_FAILURE, "Failed to malloc %d bytes", size); |
||||||
|
// printf("Allocated %d bytes at %p\n", size, mem);
|
||||||
|
return mem; |
||||||
|
} |
||||||
|
|
||||||
|
void *safe_realloc(void *ptr, size_t size) |
||||||
|
{ |
||||||
|
void *mem; |
||||||
|
|
||||||
|
mem = realloc(ptr, size); |
||||||
|
if (mem == NULL) |
||||||
|
err(EXIT_FAILURE, "Failed to relloc %d bytes", size); |
||||||
|
return mem; |
||||||
|
} |
@ -0,0 +1,154 @@ |
|||||||
|
/* code.h */ |
||||||
|
|
||||||
|
/*
|
||||||
|
* Opcode is one byte |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Stack opcodes */ |
||||||
|
#define OP_NOP 0 /* Do nothing */ |
||||||
|
#define OP_PUSH 1 /* Push immediate */ |
||||||
|
#define OP_PUSHSTR 2 /* Push immediate string */ |
||||||
|
#define OP_POP 3 /* sp += n */ |
||||||
|
#define OP_ALLOC 4 /* sp -= n */ |
||||||
|
#define OP_LOAD 5 /* push(*(sp+n)) */ |
||||||
|
#define OP_STORE 6 /* *(sp+n) = pop() ; use sp after pop */ |
||||||
|
|
||||||
|
/* Branch opcodes are odd if link, even otherwise */ |
||||||
|
#define OP_B 8 /* relative branch */ |
||||||
|
#define OP_BL 9 |
||||||
|
#define OP_BI 10 /* indirect branch */ |
||||||
|
#define OP_BIL 11 |
||||||
|
#define OP_BZ 12 /* pop and relative branch if zero */ |
||||||
|
#define OP_BZL 13 |
||||||
|
#define OP_BNZ 14 /* pop and relative branch if not zero */ |
||||||
|
#define OP_BNZL 15 |
||||||
|
#define OP_RET 16 /* pop and branch to return address */ |
||||||
|
|
||||||
|
/* Calls */ |
||||||
|
#define OP_CALLNUM 17 /* call numbered function */ |
||||||
|
#define OP_CALLSTR 18 /* call string function */ |
||||||
|
|
||||||
|
/* Arithmetic */ |
||||||
|
#define OP_ADD 19 |
||||||
|
#define OP_SUB 20 |
||||||
|
#define OP_MUL 21 |
||||||
|
#define OP_DIV 22 |
||||||
|
#define OP_EQ 23 |
||||||
|
#define OP_NE 24 |
||||||
|
#define OP_LT 25 |
||||||
|
#define OP_GT 26 |
||||||
|
#define OP_LE 27 |
||||||
|
#define OP_GE 28 |
||||||
|
|
||||||
|
#define FLOP_ADD 29 |
||||||
|
#define FLOP_SUB 30 |
||||||
|
#define FLOP_MUL 31 |
||||||
|
#define FLOP_DIV 32 |
||||||
|
#define FLOP_EQ 33 |
||||||
|
#define FLOP_NE 34 |
||||||
|
#define FLOP_LT 35 |
||||||
|
#define FLOP_GT 36 |
||||||
|
#define FLOP_LE 37 |
||||||
|
#define FLOP_GE 38 |
||||||
|
|
||||||
|
char *instr_names[] = { |
||||||
|
"NOP", |
||||||
|
"PUSH", |
||||||
|
"PUSHSTR", |
||||||
|
"POP", |
||||||
|
"ALLOC", |
||||||
|
"LOAD", |
||||||
|
"STORE", |
||||||
|
"ERR", |
||||||
|
"B", |
||||||
|
"BL", |
||||||
|
"BI", |
||||||
|
"BIL", |
||||||
|
"BZ", |
||||||
|
"BZL", |
||||||
|
"BNZ", |
||||||
|
"BNZL", |
||||||
|
"RET", |
||||||
|
"CALLNUM", |
||||||
|
"CALLSTR", |
||||||
|
"ADD", |
||||||
|
"SUB", |
||||||
|
"MUL", |
||||||
|
"DIV", |
||||||
|
"EQ", |
||||||
|
"NE", |
||||||
|
"LT", |
||||||
|
"GT", |
||||||
|
"LE", |
||||||
|
"GE", |
||||||
|
"FLADD", |
||||||
|
"FLSUB", |
||||||
|
"FLMUL", |
||||||
|
"FLDIV", |
||||||
|
"FLEQ", |
||||||
|
"FLNE", |
||||||
|
"FLLT", |
||||||
|
"FLGT", |
||||||
|
"FLLE", |
||||||
|
"FLGE", |
||||||
|
}; |
||||||
|
|
||||||
|
#define NINSTR (sizeof(instr_names)/sizeof(char *)) |
||||||
|
#define INSTR_NAME(x) (instr_names[x]) |
||||||
|
|
||||||
|
/*
|
||||||
|
* For opcodes which take an operand, the byte count is stored |
||||||
|
* in the top 2 bits |
||||||
|
*/ |
||||||
|
#define BYTECOUNT(x) ((((x) >> 6) & 3) + 1) |
||||||
|
#define SET_BYTECOUNT(x) (((x)-1)<<6) |
||||||
|
#define OPCODE_MASK(x) ((x) & 0x3f) |
||||||
|
|
||||||
|
/*
|
||||||
|
* For OP_PUSHSTR and OP_CALLSTR, the byte count is the number of bytes |
||||||
|
* which follow the opcode to describe the length of the string. In |
||||||
|
* most cases, the string will be <256 bytes long, so the byte count will |
||||||
|
* be 1. |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
/* Internal functions */ |
||||||
|
|
||||||
|
#define INTFN_NOP 0 |
||||||
|
#define INTFN_GLOBAL_STORE 1 |
||||||
|
#define INTFN_GLOBAL_LOAD 2 |
||||||
|
#define INTFN_GLOBAL_ARRAY_STORE 3 |
||||||
|
#define INTFN_GLOBAL_ARRAY_LOAD 4 |
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is important because sizeof(stkentry) must be the same both |
||||||
|
* in the compiler and the vm, in order to get string handling right. |
||||||
|
*/ |
||||||
|
typedef int stkentry; |
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure of the file header: |
||||||
|
* |
||||||
|
* 2 "LC" (magic) |
||||||
|
* 2 0 (version) |
||||||
|
* 4 ptr (pointer to function table) |
||||||
|
* |
||||||
|
* ptr-4 code |
||||||
|
* |
||||||
|
* 1 or more of: |
||||||
|
* 4 length of block, or 0 to terminate |
||||||
|
* 4 type of block (0 for function) |
||||||
|
* 4 pointer to function (offset within file) |
||||||
|
* 4 number of arguments (unused for now) |
||||||
|
* n NULL-terminated function name. |
||||||
|
* - align to 4-byte boundary |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#define MAGIC1 'L' |
||||||
|
#define MAGIC2 'C' |
||||||
|
#define VERSION1 0 |
||||||
|
#define VERSION2 0 |
||||||
|
|
@ -0,0 +1,39 @@ |
|||||||
|
/* hash.h */ |
||||||
|
|
||||||
|
/*
|
||||||
|
* Declare hash as: |
||||||
|
* struct hashentry *hash[HASHSIZE]; |
||||||
|
* |
||||||
|
* Initialise with hash_init(hash); |
||||||
|
* free all hash items with hash_clear(hash); |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
struct hashentry { |
||||||
|
char *name; |
||||||
|
int value; |
||||||
|
int flags; |
||||||
|
struct hashentry *next; |
||||||
|
}; |
||||||
|
|
||||||
|
#define HASHSIZE 512 |
||||||
|
#define HASHMASK (HASHSIZE - 1) |
||||||
|
|
||||||
|
typedef void (*hash_action)(struct hashentry *); |
||||||
|
|
||||||
|
int hashfn(char *); |
||||||
|
void hash_iterate(struct hashentry **, hash_action); |
||||||
|
void hash_clear(struct hashentry **); |
||||||
|
void hash_init(struct hashentry **); |
||||||
|
|
||||||
|
/*
|
||||||
|
* hash_lookup - lookup item in the hash |
||||||
|
* |
||||||
|
* The action on failure is determined by arg 3. If non-zero, |
||||||
|
* then a hash entry will be created and returned. Otherwise, |
||||||
|
* NULL is returned. If a new item is created, the name field |
||||||
|
* will be NULL, and it is the responsibility of the caller |
||||||
|
* to fill this in correctly. |
||||||
|
*/ |
||||||
|
struct hashentry *hash_lookup(struct hashentry **, char *, int); |
||||||
|
|
@ -0,0 +1,4 @@ |
|||||||
|
/* mem.h */ |
||||||
|
|
||||||
|
void *safe_malloc(size_t); |
||||||
|
void *safe_realloc(void *, size_t); |
@ -0,0 +1,40 @@ |
|||||||
|
# Makefile
|
||||||
|
|
||||||
|
PREFIX?= /usr/local
|
||||||
|
|
||||||
|
OBJS= lexer.o parser.o ast.o codegen.o
|
||||||
|
SRCS= ast.c codegen.c
|
||||||
|
|
||||||
|
COMMONOBJS= mem.o hash.o
|
||||||
|
COMMONDIR= ../common
|
||||||
|
|
||||||
|
INCDIR=../include
|
||||||
|
|
||||||
|
PROGOBJS= ${OBJS} ${COMMONOBJS:S/^/${COMMONDIR}\//}
|
||||||
|
|
||||||
|
YACC= yacc -d
|
||||||
|
|
||||||
|
CFLAGS+= -Wall -Werror
|
||||||
|
CPPFLAGS+= -I${INCDIR}
|
||||||
|
|
||||||
|
|
||||||
|
lsc: ${OBJS} |
||||||
|
${LINK.c} -o ${.TARGET} ${PROGOBJS}
|
||||||
|
|
||||||
|
y.tab.h: parser.o |
||||||
|
|
||||||
|
lexer.o: lexer.l y.tab.h types.h |
||||||
|
|
||||||
|
parser.o: parser.y ast.h types.h codegen.h |
||||||
|
|
||||||
|
|
||||||
|
install: lsc |
||||||
|
${INSTALL} -d ${PREFIX}/bin
|
||||||
|
${INSTALL} -c lsc ${PREFIX}/bin/lsc
|
||||||
|
|
||||||
|
depend: |
||||||
|
mkdep -- ${CFLAGS} ${CPPFLAGS} ${SRCS}
|
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f ${OBJS} lsc y.tab.h
|
||||||
|
|
@ -0,0 +1,413 @@ |
|||||||
|
/* ast.c */ |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <err.h> |
||||||
|
#include "types.h" |
||||||
|
#include "ast.h" |
||||||
|
#include "mem.h" |
||||||
|
|
||||||
|
ast_list *make_list(ast *elem, ast_list *tail) |
||||||
|
{ |
||||||
|
ast_list *list = safe_malloc(sizeof(ast_list)); |
||||||
|
|
||||||
|
list->elem = elem; |
||||||
|
list->next = tail; |
||||||
|
|
||||||
|
return list; |
||||||
|
} |
||||||
|
|
||||||
|
ast_list *reverse_list(ast_list *list) |
||||||
|
{ |
||||||
|
ast_list *last = NULL; |
||||||
|
ast_list *next; |
||||||
|
|
||||||
|
while (list) { |
||||||
|
next = list->next; |
||||||
|
list->next = last; |
||||||
|
last = list; |
||||||
|
list = next; |
||||||
|
} |
||||||
|
|
||||||
|
return last; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_list_node(ast_list *list) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_list; |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_string(char *string) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = str_ast; |
||||||
|
elem->info.string = string; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_integer(long integer) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = int_ast; |
||||||
|
elem->info.integer = integer; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_real(float real) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = real_ast; |
||||||
|
elem->info.real = real; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_function(char *identifier, ast_list *args, ast_list *stmts) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list = NULL; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_fndef; |
||||||
|
list = make_list(make_list_node(stmts), list); |
||||||
|
list = make_list(make_list_node(args), list); |
||||||
|
list = make_list(make_string(identifier), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_fndefint(char *identifier, long num) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list = NULL; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_fndefint; |
||||||
|
list = make_list(make_integer(num), list); |
||||||
|
list = make_list(make_string(identifier), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_constant(char *identifier, long num) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list = NULL; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_constant; |
||||||
|
list = make_list(make_integer(num), list); |
||||||
|
list = make_list(make_string(identifier), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_realconstant(char *identifier, float num) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list = NULL; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_constant; |
||||||
|
list = make_list(make_real(num), list); |
||||||
|
list = make_list(make_string(identifier), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_fndefext(char *identifier) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list = NULL; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_fndefext; |
||||||
|
list = make_list(make_string(identifier), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_variable(char *identifier) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = var_ast; |
||||||
|
elem->info.variable = identifier; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_array(char *identifier, ast *expression) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list; |
||||||
|
|
||||||
|
elem->tag = array_ast; |
||||||
|
elem->info.node.tag = kind_array; |
||||||
|
list = make_list(expression, NULL); |
||||||
|
list = make_list(make_variable(identifier), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
ast *make_assignment(char *identifier, ast *expression) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_assign; |
||||||
|
list = make_list(expression, NULL); |
||||||
|
list = make_list(make_variable(identifier), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
ast *make_assignment(ast_list *identifier_list, ast *expression) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_assign; |
||||||
|
list = make_list(expression, NULL); |
||||||
|
list = make_list(make_list_node(identifier_list), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_binary_op(ast_kind op, ast *exp1, ast *exp2) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = op; |
||||||
|
list = make_list(exp2, NULL); |
||||||
|
list = make_list(exp1, list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_unary_op(ast_kind op, ast *exp1) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = op; |
||||||
|
list = make_list(exp1, NULL); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_call(char *identifier, ast_list *args) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = kind_call; |
||||||
|
list = make_list(make_list_node(args), NULL); |
||||||
|
list = make_list(make_string(identifier), list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_statement(ast_kind type, ast *expression, ast_list *statements, |
||||||
|
ast_list *more_statements) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
ast_list *list; |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = type; |
||||||
|
list = NULL; |
||||||
|
if (more_statements) |
||||||
|
list = make_list(make_list_node(more_statements), list); |
||||||
|
list = make_list(make_list_node(statements), list); |
||||||
|
list = make_list(expression, list); |
||||||
|
elem->info.node.head = list; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_case_statement_variable(char *identifier) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = casevar_ast; |
||||||
|
elem->info.variable = identifier; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_case_statement_number(long num) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = casenum_ast; |
||||||
|
elem->info.integer = num; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_return_statement(void) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = stmt_return; |
||||||
|
elem->info.node.head = NULL; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_break_statement(void) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = stmt_break; |
||||||
|
elem->info.node.head = NULL; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
ast *make_default_statement(void) |
||||||
|
{ |
||||||
|
ast *elem = safe_malloc(sizeof(ast)); |
||||||
|
|
||||||
|
elem->tag = node_ast; |
||||||
|
elem->info.node.tag = stmt_default; |
||||||
|
elem->info.node.head = NULL; |
||||||
|
|
||||||
|
return elem; |
||||||
|
} |
||||||
|
|
||||||
|
void indent(int spaces) |
||||||
|
{ |
||||||
|
spaces = spaces * 2; |
||||||
|
while (spaces--) { |
||||||
|
printf(" "); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ast_dump_main(ast *, int); |
||||||
|
|
||||||
|
void ast_dump_list(ast_list *list, int spaces) |
||||||
|
{ |
||||||
|
while (list) { |
||||||
|
ast_dump_main(list->elem, spaces); |
||||||
|
list = list->next; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ast_dump_main(ast *node, int spaces) |
||||||
|
{ |
||||||
|
indent(spaces); |
||||||
|
switch (node->tag) { |
||||||
|
case int_ast: |
||||||
|
printf("integer: %ld\n", node->info.integer); |
||||||
|
break; |
||||||
|
case real_ast: |
||||||
|
printf("real: %g\n", node->info.real); |
||||||
|
break; |
||||||
|
case var_ast: |
||||||
|
printf("variable: %s\n", node->info.variable); |
||||||
|
break; |
||||||
|
case str_ast: |
||||||
|
printf("string: %s\n", node->info.string); |
||||||
|
break; |
||||||
|
case node_ast: |
||||||
|
switch (node->info.node.tag) { |
||||||
|
case kind_fndef: |
||||||
|
printf("function definition:\n"); |
||||||
|
break; |
||||||
|
case kind_assign: |
||||||
|
printf("assignment:\n");
|
||||||
|
break; |
||||||
|
case kind_list: |
||||||
|
printf("generic list:\n"); |
||||||
|
break; |
||||||
|
case kind_call: |
||||||
|
printf("function call:\n"); |
||||||
|
break; |
||||||
|
case op_plus: |
||||||
|
printf("plus operation:\n"); |
||||||
|
break; |
||||||
|
case op_minus: |
||||||
|
printf("minus operation:\n"); |
||||||
|
break; |
||||||
|
case op_times: |
||||||
|
printf("times operation:\n"); |
||||||
|
break; |
||||||
|
case op_divide: |
||||||
|
printf("divide operation:\n"); |
||||||
|
break; |
||||||
|
case op_gt: |
||||||
|
printf("greater than operation:\n"); |
||||||
|
break; |
||||||
|
case op_lt: |
||||||
|
printf("less than operation:\n"); |
||||||
|
break; |
||||||
|
case op_ge: |
||||||
|
printf("greater than or equal operation:\n"); |
||||||
|
break; |
||||||
|
case op_le: |
||||||
|
printf("less than or equal operation:\n"); |
||||||
|
break; |
||||||
|
case op_eq: |
||||||
|
printf("equality operation:\n"); |
||||||
|
break; |
||||||
|
case op_ne: |
||||||
|
printf("not equal operation:\n"); |
||||||
|
break; |
||||||
|
case stmt_if: |
||||||
|
printf("if statement:\n"); |
||||||
|
break; |
||||||
|
case stmt_while: |
||||||
|
printf("while statement:\n"); |
||||||
|
break; |
||||||
|
default: |
||||||
|
printf("unknown list type:\n"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
ast_dump_list(node->info.node.head, spaces+1); |
||||||
|
break; |
||||||
|
default: |
||||||
|
printf("unknown node type\n"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ast_dump(ast *node) |
||||||
|
{ |
||||||
|
ast_dump_main(node, 0); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,27 @@ |
|||||||
|
/* ast.h */ |
||||||
|
|
||||||
|
ast_list *make_list(ast *, ast_list *); |
||||||
|
ast_list *reverse_list(ast_list *); |
||||||
|
ast *make_list_node(ast_list *); |
||||||
|
ast *make_function(char *, ast_list *, ast_list *); |
||||||
|
ast *make_fndefint(char *, long); |
||||||
|
ast *make_constant(char *, long); |
||||||
|
ast *make_realconstant(char *, float); |
||||||
|
ast *make_fndefext(char *); |
||||||
|
ast *make_variable(char *); |
||||||
|
ast *make_array(char *, ast *); |
||||||
|
ast *make_string(char *); |
||||||
|
ast *make_assignment(ast_list *, ast *); |
||||||
|
ast *make_binary_op(ast_kind, ast *, ast *); |
||||||
|
ast *make_unary_op(ast_kind, ast *); |
||||||
|
ast *make_call(char *, ast_list *); |
||||||
|
ast *make_integer(long); |
||||||
|
ast *make_real(float); |
||||||
|
ast *make_statement(ast_kind, ast *, ast_list *, ast_list *); |
||||||
|
ast *make_case_statement_number(long); |
||||||
|
ast *make_case_statement_variable(char *); |
||||||
|
ast *make_break_statement(); |
||||||
|
ast *make_default_statement(); |
||||||
|
ast *make_return_statement(); |
||||||
|
|
||||||
|
void ast_dump(ast *); |
@ -0,0 +1,4 @@ |
|||||||
|
/* codegen.h */ |
||||||
|
|
||||||
|
void codegen(ast *); |
||||||
|
void output_code(void); |
@ -0,0 +1,37 @@ |
|||||||
|
/* header.lh */ |
||||||
|
|
||||||
|
/* Standard header */ |
||||||
|
|
||||||
|
fndefint __nop 0; |
||||||
|
fndefint __global_store 1; |
||||||
|
fndefint __global_load 2; |
||||||
|
fndefint __global_array_store 3; |
||||||
|
fndefint __global_array_load 4; |
||||||
|
fndefint __printint 5; |
||||||
|
fndefint __printreal 6; |
||||||
|
fndefint __printstr 7; |
||||||
|
fndefint dmx_setchannel 8; |
||||||
|
fndefint dmx_output 9; |
||||||
|
fndefint gettime 10; |
||||||
|
fndefint waittime 11; |
||||||
|
fndefint wait 12; |
||||||
|
fndefint wakeup 13; |
||||||
|
fndefint spawn 14; |
||||||
|
fndefint midi_read 15; |
||||||
|
fndefint beatdetect_read 16; |
||||||
|
fndefint beatdetect_phase 17; |
||||||
|
fndefint beatdetect_confidence 18; |
||||||
|
fndefint realtoint 19; |
||||||
|
fndefint inttoreal 20; |
||||||
|
fndefint map3d_setcal 21; |
||||||
|
fndefint map3d_calibrate 22; |
||||||
|
fndefint map3d_transform 23; |
||||||
|
fndefint map3d_setparams 24; |
||||||
|
fndefint map3d_load 25; |
||||||
|
fndefint map3d_save 26; |
||||||
|
fndefint sin 27; |
||||||
|
fndefint cos 28; |
||||||
|
fndefint random 29; |
||||||
|
|
||||||
|
constant _dmxoutput 10; |
||||||
|
constant _beat 11; |
@ -0,0 +1,146 @@ |
|||||||
|
/* lexer.l */ |
||||||
|
|
||||||
|
/* |
||||||
|
* The incl state is used for picking up the name of an include file |
||||||
|
*/ |
||||||
|
%x incl |
||||||
|
|
||||||
|
%x comment |
||||||
|
%x str |
||||||
|
|
||||||
|
%{ |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
#include <err.h> |
||||||
|
#include "types.h" |
||||||
|
#include "y.tab.h" |
||||||
|
|
||||||
|
#define MAX_INCLUDE_DEPTH 10 |
||||||
|
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; |
||||||
|
int lineno_stack[MAX_INCLUDE_DEPTH]; |
||||||
|
int include_stack_ptr = 0; |
||||||
|
|
||||||
|
#define MAX_STR_CONST 1024 |
||||||
|
char string_buf[MAX_STR_CONST]; |
||||||
|
char *string_buf_ptr; |
||||||
|
|
||||||
|
%} |
||||||
|
|
||||||
|
%option yylineno |
||||||
|
|
||||||
|
%% |
||||||
|
|
||||||
|
%include BEGIN(incl); |
||||||
|
"/*" BEGIN(comment); |
||||||
|
|
||||||
|
<comment>{ |
||||||
|
[^*]* /* eat anything that's not a '*' */ |
||||||
|
"*"+[^*/]* /* eat up '*'s not followed by '/'s */ |
||||||
|
"*"+"/" BEGIN(INITIAL); |
||||||
|
} |
||||||
|
|
||||||
|
\" string_buf_ptr = string_buf; BEGIN(str); |
||||||
|
|
||||||
|
<str>{ |
||||||
|
\" { |
||||||
|
BEGIN(INITIAL); |
||||||
|
*string_buf_ptr = '\0'; |
||||||
|
yylval.Tstring = strdup(string_buf); |
||||||
|
return STRING; |
||||||
|
} |
||||||
|
\n { |
||||||
|
fprintf(stderr, "Unterminated string at line %d\n", yylineno); |
||||||
|
exit(1); |
||||||
|
} |
||||||
|
\\[0-7]{1,3} { |
||||||
|
/* octal escape sequence */ |
||||||
|
int result; |
||||||
|
(void) sscanf(yytext + 1, "%o", &result); |
||||||
|
if (result > 0xff) { |
||||||
|
fprintf(stderr, |
||||||
|
"octal escape out of bounds at line %d\n", |
||||||
|
yylineno); |
||||||
|
exit(1); |
||||||
|
} |
||||||
|
} |
||||||
|
\\[0-9]+ { |
||||||
|
/* bad escape sequence */ |
||||||
|
fprintf(stderr, "bad escape sequence at line %d\n", yylineno); |
||||||
|
exit(1); |
||||||
|
} |
||||||
|
\\n *string_buf_ptr++ = '\n'; |
||||||
|
\\t *string_buf_ptr++ = '\t'; |
||||||
|
\\r *string_buf_ptr++ = '\r'; |
||||||
|
\\b *string_buf_ptr++ = '\b'; |
||||||
|
\\f *string_buf_ptr++ = '\f'; |
||||||
|
|
||||||
|
\\(.|\n) *string_buf_ptr++ = yytext[1]; |
||||||
|
|
||||||
|
[^\\\n\"]+ { |
||||||
|
char *yptr = yytext; |
||||||
|
|
||||||
|
while (*yptr) |
||||||
|
*string_buf_ptr++ = *yptr++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function return TOKFUNCTION; |
||||||
|
fndefint return TOKFNDEFINT; |
||||||
|
fndefext return TOKFNDEFEXT; |
||||||
|
constant return TOKCONSTANT; |
||||||
|
while return TOKWHILE; |
||||||
|
if return TOKIF; |
||||||
|
else return TOKELSE; |
||||||
|
switch return TOKSWITCH; |
||||||
|
case return TOKCASE; |
||||||
|
default return TOKDEFAULT; |
||||||
|
break return TOKBREAK; |
||||||
|
return return TOKRETURN; |
||||||
|
== return TOKEQ; |
||||||
|
!= return TOKNE; |
||||||
|
\<= return TOKLE; |
||||||
|
\>= return TOKGE; |
||||||
|
&& return TOKAND; |
||||||
|
\|\| return TOKOR; |
||||||
|
|
||||||
|
[0-9]+ yylval.Tinteger = atoi(yytext); return NUMBER; |
||||||
|
-[0-9]+ yylval.Tinteger = atoi(yytext); return NUMBER; |
||||||
|
[0-9]+\.[0-9]+ yylval.Treal = atof(yytext); return REAL; |
||||||
|
-[0-9]+\.[0-9]+ yylval.Treal = atof(yytext); return REAL; |
||||||
|
[_a-zA-Z0-9]+ yylval.Tstring = strdup(yytext); return IDENTIFIER; |
||||||
|
%[_a-zA-Z0-9]+ yylval.Tstring = strdup(yytext); return IDENTIFIER; |
||||||
|
$[_a-zA-Z0-9]+ yylval.Tstring = strdup(yytext); return IDENTIFIER; |
||||||
|
|
||||||
|
[ \t\n]+ /* eat whitespace */ |
||||||
|
|
||||||
|
. return (int) yytext[0]; |
||||||
|
|
||||||
|
<incl>[ \t]* /* eat the whitespace */ |
||||||
|
<incl>[^ \t\n]+ { /* got the include filename */ |
||||||
|
if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { |
||||||
|
fprintf(stderr, "Includes nested too deeply"); |
||||||
|
exit(1); |
||||||
|
} |
||||||
|
include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; |
||||||
|
lineno_stack[include_stack_ptr++] = yylineno; |
||||||
|
yyin = fopen(yytext, "r"); |
||||||
|
yylineno = 1; |
||||||
|
if (!yyin) |
||||||
|
err(1, "%s", yytext); |
||||||
|
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); |
||||||
|
BEGIN(INITIAL); |
||||||
|
} |
||||||
|
|
||||||
|
<<EOF>> { |
||||||
|
if (--include_stack_ptr < 0) { |
||||||
|
yyterminate(); |
||||||
|
} else { |
||||||
|
yy_delete_buffer(YY_CURRENT_BUFFER); |
||||||
|
yy_switch_to_buffer( |
||||||
|
include_stack[include_stack_ptr]); |
||||||
|
yylineno = lineno_stack[include_stack_ptr]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
%% |
||||||
|
|
@ -0,0 +1,335 @@ |
|||||||
|
%{ |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
#include <err.h> |
||||||
|
#include "types.h" |
||||||
|
#include "ast.h" |
||||||
|
#include "codegen.h" |
||||||
|
|
||||||
|
int yyparse(void); |
||||||
|
int yylex(void); |
||||||
|
|
||||||
|
extern int yylineno; |
||||||
|
char *yytext; |
||||||
|
|
||||||
|
/* XXX */ |
||||||
|
extern FILE *binout; |
||||||
|
extern FILE *yyin; |
||||||
|
|
||||||
|
void yyerror(const char * str) |
||||||
|
{ |
||||||
|
fprintf(stderr, "\n%s on line %d before '%s'\n", str, yylineno, yytext); |
||||||
|
} |
||||||
|
|
||||||
|
int yywrap() |
||||||
|
{ |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
argv++; /* skip over program name */ |
||||||
|
argc--; |
||||||
|
if (argc > 0) { |
||||||
|
char *outfile; |
||||||
|
int len; |
||||||
|
|
||||||
|
outfile = strdup(argv[0]); |
||||||
|
if (outfile == NULL) |
||||||
|
err(1, "Failed to allocate memory"); |
||||||
|
len = strlen(outfile); |
||||||
|
if ((len < 3) || |
||||||
|
(outfile[len-1] != 's') || |
||||||
|
(outfile[len-2] != 'l') || |
||||||
|
(outfile[len-3] != '.')) |
||||||
|
errx(1, "Can only compile .ls files"); |
||||||
|
outfile[len-1] = 'c'; |
||||||
|
|
||||||
|
yyin = fopen(argv[0], "r"); |
||||||
|
if (yyin == NULL) |
||||||
|
err(1, "%s: Failed to open input file", argv[0]); |
||||||
|
binout = fopen(outfile, "w"); |
||||||
|
if (binout == NULL) |
||||||
|
err(1, "%s: Failed to open output file", outfile); |
||||||
|
|
||||||
|
free(outfile); |
||||||
|
} else { |
||||||
|
yyin = stdin; |
||||||
|
binout = fopen("out.lc", "w"); |
||||||
|
if (binout == NULL) |
||||||
|
err(1, "%s: Failed to open output file", "out.lc"); |
||||||
|
} |
||||||
|
|
||||||
|
yyparse(); |
||||||
|
fclose(binout); |
||||||
|
fclose(yyin); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
%} |
||||||
|
|
||||||
|
%token TOKFUNCTION TOKFNDEFINT TOKFNDEFEXT TOKCONSTANT |
||||||
|
%token TOKWHILE TOKIF TOKELSE TOKSWITCH TOKCASE TOKDEFAULT |
||||||
|
%token TOKBREAK TOKRETURN TOKEQ TOKNE TOKAND TOKOR STRING |
||||||
|
|
||||||
|
%union { |
||||||
|
ast* Tast; |
||||||
|
ast_list* Tast_list; |
||||||
|
char * Tstring; |
||||||
|
long Tinteger; |
||||||
|
float Treal; |
||||||
|
} |
||||||
|
|
||||||
|
%type <Tast> argument |
||||||
|
%type <Tast> constant |
||||||
|
%type <Tast> function |
||||||
|
%type <Tast> fndefint |
||||||
|
%type <Tast> fndefext |
||||||
|
%type <Tast> statement |
||||||
|
%type <Tast> assignment |
||||||
|
%type <Tast> expression |
||||||
|
%type <Tast> realconstant |
||||||
|
%type <Tast> statement_if |
||||||
|
%type <Tast> statement_case |
||||||
|
%type <Tast> statement_while |
||||||
|
%type <Tast> statement_break |
||||||
|
%type <Tast> statement_switch |
||||||
|
%type <Tast> statement_return |
||||||
|
%type <Tast> statement_default |
||||||
|
%type <Tast_list> stmt_list_inner |
||||||
|
%type <Tast_list> exp_list_inner |
||||||
|
%type <Tast_list> arg_list_inner |
||||||
|
%type <Tast_list> fn_list_inner |
||||||
|
%type <Tast_list> assign_list |
||||||
|
%type <Tast_list> stmt_list |
||||||
|
%type <Tast_list> exp_list |
||||||
|
%type <Tast_list> arg_list |
||||||
|
%type <Tast_list> fn_list |
||||||
|
%token <Tstring> IDENTIFIER |
||||||
|
%token <Tstring> STRING |
||||||
|
%token <Tinteger> NUMBER |
||||||
|
%token <Treal> REAL |
||||||
|
|
||||||
|
%left '+' |
||||||
|
%left '-' |
||||||
|
%left '*' |
||||||
|
%left '/' |
||||||
|
%left TOKAND |
||||||
|
%left TOKOR |
||||||
|
%nonassoc '<' |
||||||
|
%nonassoc '>' |
||||||
|
%nonassoc TOKLE |
||||||
|
%nonassoc TOKGE |
||||||
|
%nonassoc TOKEQ |
||||||
|
%nonassoc TOKNE |
||||||
|
|
||||||
|
%start start |
||||||
|
|
||||||
|
%% |
||||||
|
|
||||||
|
start: |
||||||
|
fn_list |
||||||
|
{ |
||||||
|
codegen(make_list_node($1)); |
||||||
|
output_code(); |
||||||
|
} |
||||||
|
; |
||||||
|
|
||||||
|
fn_list: |
||||||
|
fn_list_inner { $$ = reverse_list($1); } |
||||||
|
; |
||||||
|
|
||||||
|
fn_list_inner: |
||||||
|
fn_list_inner function { $$ = make_list($2, $1); } |
||||||
|
| fn_list_inner fndefint { $$ = make_list($2, $1); } |
||||||
|
| fn_list_inner fndefext { $$ = make_list($2, $1); } |
||||||
|
| fn_list_inner constant { $$ = make_list($2, $1); } |
||||||
|
| fn_list_inner realconstant { $$ = make_list($2, $1); } |
||||||
|
| { $$ = NULL; } |
||||||
|
; |
||||||
|
|
||||||
|
function: |
||||||
|
TOKFUNCTION IDENTIFIER '(' arg_list ')' '{' stmt_list '}' |
||||||
|
{ $$ = make_function($2, $4, $7); } |
||||||
|
; |
||||||
|
|
||||||
|
fndefint: |
||||||
|
TOKFNDEFINT IDENTIFIER NUMBER ';' |
||||||
|
{ $$ = make_fndefint($2, $3); } |
||||||
|
; |
||||||
|
|
||||||
|
constant: |
||||||
|
TOKCONSTANT IDENTIFIER NUMBER ';' |
||||||
|
{ $$ = make_constant($2, $3); } |
||||||
|
; |
||||||
|
|
||||||
|
realconstant: |
||||||
|
TOKCONSTANT IDENTIFIER REAL ';' |
||||||
|
{ $$ = make_realconstant($2, $3); } |
||||||
|
; |
||||||
|
|
||||||
|
fndefext: |
||||||
|
TOKFNDEFEXT IDENTIFIER ';' |
||||||
|
{ $$ = make_fndefext($2); } |
||||||
|
; |
||||||
|
|
||||||
|
argument: |
||||||
|
IDENTIFIER |
||||||
|
{ $$ = make_variable($1); } |
||||||
|
; |
||||||
|
|
||||||
|
arg_list: |
||||||
|
arg_list_inner { $$ = reverse_list($1); } |
||||||
|
; |
||||||
|
|
||||||
|
arg_list_inner: |
||||||
|
arg_list_inner ',' argument { $$ = make_list($3, $1); } |
||||||
|
| argument { $$ = make_list($1, NULL); } |
||||||
|
| { $$ = NULL; } |
||||||
|
; |
||||||
|
|
||||||
|
stmt_list: |
||||||
|
stmt_list_inner { $$ = reverse_list($1); } |
||||||
|
; |
||||||
|
|
||||||
|
stmt_list_inner: |
||||||
|
stmt_list_inner statement { $$ = make_list($2, $1); } |
||||||
|
| { $$ = NULL; } |
||||||
|
; |
||||||
|
|
||||||
|
statement: |
||||||
|
statement_if |
||||||
|
| |
||||||
|
statement_while |
||||||
|
| |
||||||
|
statement_switch |
||||||
|
| |
||||||
|
statement_case |
||||||
|
| |
||||||
|
statement_default |
||||||
|
| |
||||||
|
statement_break ';' |
||||||
|
| |
||||||
|
assignment ';' |
||||||
|
| |
||||||
|
expression ';' |
||||||
|
{ $$ = make_assignment(NULL, $1); } |
||||||
|
| |
||||||
|
statement_return ';' |
||||||
|
; |
||||||
|
|
||||||
|
assignment: |
||||||
|
assign_list '=' expression |
||||||
|
{ $$ = make_assignment($1, $3); } |
||||||
|
; |
||||||
|
|
||||||
|
assign_list: |
||||||
|
assign_list ',' IDENTIFIER |
||||||
|
{ $$ = make_list(make_variable($3), $1); } |
||||||
|
| IDENTIFIER |
||||||
|
{ $$ = make_list(make_variable($1), NULL); } |
||||||
|
| assign_list ',' IDENTIFIER '[' expression ']' |
||||||
|
{ $$ = make_list(make_array($3, $5), $1); } |
||||||
|
| IDENTIFIER '[' expression ']' |
||||||
|
{ $$ = make_list(make_array($1, $3), NULL); } |
||||||
|
; |
||||||
|
|
||||||
|
expression: |
||||||
|
expression '+' expression { $$ = make_binary_op(op_plus, $1, $3); } |
||||||
|
| |
||||||
|
expression '-' expression { $$ = make_binary_op(op_minus, $1, $3); } |
||||||
|
| |
||||||
|
expression '*' expression { $$ = make_binary_op(op_times, $1, $3); } |
||||||
|
| |
||||||
|
expression '/' expression { $$ = make_binary_op(op_divide, $1, $3); } |
||||||
|
| |
||||||
|
expression '<' expression { $$ = make_binary_op(op_lt, $1, $3); } |
||||||
|
| |
||||||
|
expression '>' expression { $$ = make_binary_op(op_gt, $1, $3); } |
||||||
|
| |
||||||
|
expression TOKLE expression { $$ = make_binary_op(op_le, $1, $3); } |
||||||
|
| |
||||||
|
expression TOKGE expression { $$ = make_binary_op(op_ge, $1, $3); } |
||||||
|
| |
||||||
|
expression TOKEQ expression { $$ = make_binary_op(op_eq, $1, $3); } |
||||||
|
| |
||||||
|
expression TOKNE expression { $$ = make_binary_op(op_ne, $1, $3); } |
||||||
|
| |
||||||
|
expression TOKAND expression { $$ = make_binary_op(op_and, $1, $3); } |
||||||
|
| |
||||||
|
expression TOKOR expression { $$ = make_binary_op(op_or, $1, $3); } |
||||||
|
| |
||||||
|
'-' expression { $$ = make_unary_op(op_minus, $2); } |
||||||
|
| |
||||||
|
'(' expression ')' { $$ = $2; } |
||||||
|
| |
||||||
|
IDENTIFIER '(' exp_list ')' |
||||||
|
{ $$ = make_call($1, $3); } |
||||||
|
| |
||||||
|
IDENTIFIER '[' expression ']' |
||||||
|
{ $$ = make_array($1, $3); } |
||||||
|
| |
||||||
|
IDENTIFIER |
||||||
|
{ $$ = make_variable($1); } |
||||||
|
| |
||||||
|
NUMBER |
||||||
|
{ $$ = make_integer($1); } |
||||||
|
| |
||||||
|
REAL |
||||||
|
{ $$ = make_real($1); } |
||||||
|
| |
||||||
|
STRING |
||||||
|
{ $$ = make_string($1); } |
||||||
|
; |
||||||
|
|
||||||
|
exp_list: |
||||||
|
exp_list_inner { $$ = reverse_list($1); } |
||||||
|
; |
||||||
|
|
||||||
|
exp_list_inner: |
||||||
|
exp_list_inner ',' expression { $$ = make_list($3, $1); } |
||||||
|
| expression { $$ = make_list($1, NULL); } |
||||||
|
| { $$ = NULL; } |
||||||
|
; |
||||||
|
|
||||||
|
statement_if: |
||||||
|
TOKIF '(' expression ')' '{' stmt_list '}' |
||||||
|
{ $$ = make_statement(stmt_if, $3, $6, NULL); } |
||||||
|
| |
||||||
|
TOKIF '(' expression ')' '{' stmt_list '}' TOKELSE '{' stmt_list '}' |
||||||
|
{ $$ = make_statement(stmt_if, $3, $6, $10); } |
||||||
|
; |
||||||
|
|
||||||
|
statement_while: |
||||||
|
TOKWHILE '(' expression ')' '{' stmt_list '}' |
||||||
|
{ $$ = make_statement(stmt_while, $3, $6, NULL); } |
||||||
|
; |
||||||
|
|
||||||
|
statement_switch: |
||||||
|
TOKSWITCH '(' expression ')' '{' stmt_list '}' |
||||||
|
{ $$ = make_statement(stmt_switch, $3, $6, NULL); } |
||||||
|
; |
||||||
|
|
||||||
|
statement_case: |
||||||
|
TOKCASE NUMBER ':' |
||||||
|
{ $$ = make_case_statement_number($2); } |
||||||
|
| |
||||||
|
TOKCASE IDENTIFIER ':' |
||||||
|
{ $$ = make_case_statement_variable($2); } |
||||||
|
; |
||||||
|
|
||||||
|
statement_return: |
||||||
|
TOKRETURN |
||||||
|
{ $$ = make_return_statement(); } |
||||||
|
; |
||||||
|
|
||||||
|
statement_break: |
||||||
|
TOKBREAK |
||||||
|
{ $$ = make_break_statement(); } |
||||||
|
; |
||||||
|
|
||||||
|
statement_default: |
||||||
|
TOKDEFAULT ':' |
||||||
|
{ $$ = make_default_statement(); } |
||||||
|
; |
||||||
|
|
@ -0,0 +1,37 @@ |
|||||||
|
/* types.h */ |
||||||
|
|
||||||
|
typedef enum { |
||||||
|
|
||||||
|
kind_fndef, kind_fndefint, kind_fndefext, kind_constant, |
||||||
|
kind_assign, kind_list, kind_call, kind_array, |
||||||
|
|
||||||
|
op_plus, op_minus, op_times, op_divide, |
||||||
|
op_gt, op_lt, op_ge, op_le, op_eq, op_ne, |
||||||
|
op_and, op_or, |
||||||
|
|
||||||
|
stmt_if, stmt_while, stmt_switch, stmt_casenum, stmt_casevar, |
||||||
|
stmt_break, stmt_default, stmt_return |
||||||
|
|
||||||
|
} ast_kind; |
||||||
|
|
||||||
|
typedef struct ast { |
||||||
|
enum { |
||||||
|
int_ast, real_ast, var_ast, casenum_ast, casevar_ast, |
||||||
|
str_ast, node_ast, array_ast |
||||||
|
} tag; |
||||||
|
union { |
||||||
|
long integer; |
||||||
|
float real; |
||||||
|
char* variable; |
||||||
|
char* string; |
||||||
|
struct { |
||||||
|
ast_kind tag; |
||||||
|
struct ast_list* head; |
||||||
|
} node; |
||||||
|
} info; |
||||||
|
} ast; |
||||||
|
|
||||||
|
typedef struct ast_list {
|
||||||
|
ast* elem; |
||||||
|
struct ast_list* next; |
||||||
|
} ast_list; |
@ -0,0 +1,31 @@ |
|||||||
|
# Makefile
|
||||||
|
|
||||||
|
PREFIX?= /usr/local
|
||||||
|
|
||||||
|
OBJS= main.o vm.o dmx.o midi.o beatdetect.o fft.o map3d.o mouse.o
|
||||||
|
SRCS= main.c vm.c dmx.c midi.c beatdetect.c fft.c map3d.c mouse.c
|
||||||
|
|
||||||
|
COMMONOBJS= mem.o hash.o
|
||||||
|
COMMONDIR= ../common
|
||||||
|
|
||||||
|
INCDIR= ../include
|
||||||
|
|
||||||
|
CFLAGS+= -Wall -Werror
|
||||||
|
CPPFLAGS+= -I${INCDIR}
|
||||||
|
LDLIBS+= -lm
|
||||||
|
|
||||||
|
PROGOBJS= ${OBJS} ${COMMONOBJS:S/^/${COMMONDIR}\//}
|
||||||
|
|
||||||
|
|
||||||
|
lsi: ${OBJS} |
||||||
|
${LINK.c} -o ${.TARGET} ${PROGOBJS} ${LDLIBS}
|
||||||
|
|
||||||
|
install: lsi |
||||||
|
${INSTALL} -d ${PREFIX}/bin
|
||||||
|
${INSTALL} -c lsi ${PREFIX}/bin/lsi
|
||||||
|
|
||||||
|
depend: |
||||||
|
mkdep -- ${CFLAGS} ${CPPFLAGS} ${SRCS}
|
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f ${OBJS} lsi
|
@ -0,0 +1,377 @@ |
|||||||
|
/* beatdetect.c */ |
||||||
|
|
||||||
|
#include <sys/types.h> |
||||||
|
#include <sys/ioctl.h> |
||||||
|
#include <sys/audioio.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <signal.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <math.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <err.h> |
||||||
|
#include <string.h> |
||||||
|
#include <errno.h> |
||||||
|
|
||||||
|
#include "fft.h" |
||||||
|
#include "vm.h" |
||||||
|
|
||||||
|
#define AUDIO_DEVICE "/dev/sound" |
||||||
|
|
||||||
|
#define BUFSIZE 2048 |
||||||
|
|
||||||
|
#define CLIP 1 |
||||||
|
|
||||||
|
#define HISTSIZE 43 |
||||||
|
#define NOUTPUTS 10 |
||||||
|
#define BAR 1.5 |
||||||
|
|
||||||
|
#define MAXP 44 |
||||||
|
#define MINP 22 |
||||||
|
|
||||||
|
#define CHISTSIZE 512 |
||||||
|
|
||||||
|
double outputslist[NOUTPUTS] = { |
||||||
|
1, 3, 7, 15, 31, 63, 127, 255, 511, 1023 |
||||||
|
}; |
||||||
|
|
||||||
|
#if 0 |
||||||
|
/*
|
||||||
|
double profile[NOUTPUTS] = { |
||||||
|
1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 |
||||||
|
}; |
||||||
|
*/ |
||||||
|
double profile[NOUTPUTS] = { |
||||||
|
1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0
|
||||||
|
}; |
||||||
|
|
||||||
|
#else |
||||||
|
|
||||||
|
double profile[NOUTPUTS] = { |
||||||
|
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
||||||
|
|
||||||
|
int audiofd; |
||||||
|
#if 0 |
||||||
|
double lavg[NOUTPUTS]; |
||||||
|
double var[NOUTPUTS]; |
||||||
|
#endif |
||||||
|
int lastmi = 0; |
||||||
|
int lastmj = 0; |
||||||
|
int lastmp = 0; |
||||||
|
double lastmax = 0; |
||||||
|
int minp, maxp; |
||||||
|
double lastsum[NOUTPUTS]; |
||||||
|
double history[NOUTPUTS][HISTSIZE]; |
||||||
|
double chistory[NOUTPUTS][CHISTSIZE]; |
||||||
|
int histptr; |
||||||
|
int chistptr; |
||||||
|
char buffer[BUFSIZE]; |
||||||
|
char *bufptr; |
||||||
|
int bufleft; |
||||||
|
double phase; |
||||||
|
double confidence; |
||||||
|
int audio_initialised = 0; |
||||||
|
|
||||||
|
#define HISTORY(i, x) (history[i][((histptr+(x) >= HISTSIZE) ? histptr+(x)-HISTSIZE : histptr+(x))]) |
||||||
|
|
||||||
|
#define HISTWRITE(i, x) history[i][histptr] = (x) |
||||||
|
|
||||||
|
#define HISTNEXT do { \ |
||||||
|
histptr++; \
|
||||||
|
if (histptr >= HISTSIZE) \
|
||||||
|
histptr = 0; \
|
||||||
|
} while (0) |
||||||
|
|
||||||
|
#define CHISTORY(i, x) (chistory[i][((chistptr+(x) >= CHISTSIZE) ? chistptr+(x)-CHISTSIZE : chistptr+(x))]) |
||||||
|
|
||||||
|
#define CHISTWRITE(i, x) chistory[i][chistptr] = (x) |
||||||
|
|
||||||
|
#define CHISTNEXT do { \ |
||||||
|
chistptr++; \
|
||||||
|
if (chistptr >= CHISTSIZE) \
|
||||||
|
chistptr = 0; \
|
||||||
|
} while (0) |
||||||
|
|
||||||
|
#define SUMSQ(a, b) ((a) * (a) + (b) * (b)) |
||||||
|
#define MAGSQ(i) SUMSQ(freqs[2*(i)], freqs[2*(i)+1]) |
||||||
|
|
||||||
|
void beatdetect_close(void) |
||||||
|
{ |
||||||
|
close(audiofd); |
||||||
|
} |
||||||
|
|
||||||
|
double beatdetect_getphase(void) |
||||||
|
{ |
||||||
|
return phase; |
||||||
|
} |
||||||
|
|
||||||
|
double beatdetect_getconfidence(void) |
||||||
|
{ |
||||||
|
return confidence; |
||||||
|
} |
||||||
|
|
||||||
|
void beatdetect_init(void) |
||||||
|
{ |
||||||
|
audio_info_t info, oinfo; |
||||||
|
|
||||||
|
audiofd = open(AUDIO_DEVICE, O_RDONLY | O_NONBLOCK, 0); |
||||||
|
if (audiofd < 0) |
||||||
|
err(1, "failed to open audio device"); |
||||||
|
|
||||||
|
if (ioctl(audiofd, AUDIO_GETINFO, &oinfo) < 0) |
||||||
|
err(1, "failed to get audio info"); |
||||||
|
|
||||||
|
AUDIO_INITINFO(&info); |
||||||
|
|
||||||
|
info.record.sample_rate = 44100; |
||||||
|
info.record.channels = 1; |
||||||
|
info.record.precision = 16; |
||||||
|
info.record.encoding = AUDIO_ENCODING_SLINEAR; |
||||||
|
info.record.gain = oinfo.record.gain; |
||||||
|
info.record.port = oinfo.record.port; |
||||||
|
info.record.balance = oinfo.record.balance; |
||||||
|
|
||||||
|
info.monitor_gain = oinfo.monitor_gain; |
||||||
|
|
||||||
|
info.mode = AUMODE_RECORD; |
||||||
|
|
||||||
|
if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0) |
||||||
|
err(1, "failed to set audio info"); |
||||||
|
|
||||||
|
fft_init(BUFSIZE/2); |
||||||
|
|
||||||
|
bzero(history, sizeof(history)); |
||||||
|
bzero(chistory, sizeof(chistory)); |
||||||
|
histptr = 0; |
||||||
|
chistptr = 0; |
||||||
|
|
||||||
|
bufptr = buffer; |
||||||
|
bufleft = BUFSIZE; |
||||||
|
|
||||||
|
audio_initialised = 1; |
||||||
|
|
||||||
|
/* vm_register_blah */ |
||||||
|
vm_register_signal_fd(audiofd, VM_BEATQ); |
||||||
|
} |
||||||
|
|
||||||
|
int beatdetect_read(void) |
||||||
|
{ |
||||||
|
#if 0 |
||||||
|
double elem; |
||||||
|
#endif |
||||||
|
int i, j, n, p; |
||||||
|
int rv; |
||||||
|
int clip; |
||||||
|
double localsum[NOUTPUTS]; |
||||||
|
fft_type *freqs; |
||||||
|
int count; |
||||||
|
int nitems; |
||||||
|
double mean, variance, sd; |
||||||
|
int beat; |
||||||
|
double r[NOUTPUTS][MAXP][MAXP-MINP]; |
||||||
|
double max; |
||||||
|
double cmax; |
||||||
|
int mi, mj, mp; |
||||||
|
int cmi, cmj, cmp; |
||||||
|
|
||||||
|
if (!audio_initialised) |
||||||
|
return 0; |
||||||
|
|
||||||
|
while (1) { |
||||||
|
rv = read(audiofd, bufptr, bufleft); |
||||||
|
if (rv == -1) { |
||||||
|
if (errno == EAGAIN) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
printf("audio read failed\n"); |
||||||
|
audio_initialised = 0; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
if (rv == 0) |
||||||
|
return 0; |
||||||
|
|
||||||
|
bufptr += rv; |
||||||
|
bufleft -= rv; |
||||||
|
|
||||||
|
if (bufleft != 0) { |
||||||
|
// printf("audio: short read (read %d)\n", rv);
|
||||||
|
if (bufleft < 0) { |
||||||
|
printf("audio: oversize read\n"); |
||||||
|
bufptr = buffer; |
||||||
|
bufleft = BUFSIZE; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
bufptr = buffer; |
||||||
|
bufleft = BUFSIZE; |
||||||
|
|
||||||
|
fft_data_signed16((int16_t *)buffer); |
||||||
|
|
||||||
|
clip = 0; |
||||||
|
|
||||||
|
/* Check for clip and compute rms */ |
||||||
|
for (i = 0; i < BUFSIZE/2; i++) { |
||||||
|
int sample = ((int16_t *)buffer)[i]; |
||||||
|
if ((sample == INT16_MAX) || (sample == (-1 - INT16_MAX))) |
||||||
|
clip = 1; |
||||||
|
} |
||||||
|
|
||||||
|
fft_window(); |
||||||
|
fft_compute(); |
||||||
|
freqs = fft_getresult(); |
||||||
|
|
||||||
|
n = 0; |
||||||
|
for (i = 0; i < NOUTPUTS; i++) { |
||||||
|
double output = 0; |
||||||
|
for (j = 0; i+j < outputslist[n]; j++) |
||||||
|
output += MAGSQ(i+j); |
||||||
|
output = output / j; |
||||||
|
localsum[i] = output; |
||||||
|
HISTWRITE(i, output); |
||||||
|
n++; |
||||||
|
} |
||||||
|
|
||||||
|
HISTNEXT; |
||||||
|
|
||||||
|
#if 0 |
||||||
|
for (i = 0; i < NOUTPUTS; i++) { |
||||||
|
lavg[i] = 0; |
||||||
|
for (j = 0; j < HISTSIZE; j++) { |
||||||
|
lavg[i] += HISTORY(i, j); |
||||||
|
} |
||||||
|
lavg[i] = lavg[i] / (double)HISTSIZE; |
||||||
|
} |
||||||
|
|
||||||
|
for (i = 0; i < NOUTPUTS; i++) { |
||||||
|
var[i] = 0; |
||||||
|
for (j = 0; j < HISTSIZE; j++) { |
||||||
|
elem = HISTORY(i, j) - lavg[i]; |
||||||
|
var[i] += elem * elem; |
||||||
|
} |
||||||
|
var[i] = var[i] / (double)HISTSIZE; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#if CLIP |
||||||
|
if (clip) |
||||||
|
printf("C"); |
||||||
|
else |
||||||
|
printf(" "); |
||||||
|
#endif |
||||||
|
|
||||||
|
for (i = 0; i < NOUTPUTS; i++) { |
||||||
|
CHISTWRITE(i, localsum[i] - lastsum[i]); |
||||||
|
lastsum[i] = localsum[i]; |
||||||
|
} |
||||||
|
CHISTNEXT; |
||||||
|
|
||||||
|
max = 0; |
||||||
|
mi = 0; |
||||||
|
mp = 0; |
||||||
|
mj = 0; |
||||||
|
mean = 0; |
||||||
|
nitems = 0; |
||||||
|
|
||||||
|
for (i = 0; i < NOUTPUTS; i++) { |
||||||
|
for (p = MINP; p < MAXP; p++) { |
||||||
|
for (j = 0; j < p; j++) { |
||||||
|
r[i][j][p-MINP] = |
||||||
|
(CHISTORY(i, CHISTSIZE-j-1) + |
||||||
|
CHISTORY(i, CHISTSIZE-(p+j)-1) + |
||||||
|
CHISTORY(i, CHISTSIZE-(2*p+j)-1) + |
||||||
|
CHISTORY(i, CHISTSIZE-(3*p+j)-1) + |
||||||
|
CHISTORY(i, CHISTSIZE-(4*p+j)-1) + |
||||||
|
CHISTORY(i, CHISTSIZE-(5*p+j)-1) + |
||||||
|
CHISTORY(i, CHISTSIZE-(6*p+j)-1) + |
||||||
|
CHISTORY(i, CHISTSIZE-(7*p+j)-1)) |
||||||
|
* profile[i]; |
||||||
|
// printf("i j p = %d %d %d\n", i, j, p);
|
||||||
|
if (r[i][j][p-MINP] < 0) |
||||||
|
r[i][j][p-MINP] = 0; |
||||||
|
if (r[i][j][p-MINP] > max) { |
||||||
|
max = r[i][j][p-MINP]; |
||||||
|
mi = i; |
||||||
|
mp = p; |
||||||
|
mj = j; |
||||||
|
} |
||||||
|
mean += r[i][j][p-MINP]; |
||||||
|
nitems++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
mean /= nitems; |
||||||
|
|
||||||
|
cmax = 0; |
||||||
|
cmi = 0; |
||||||
|
cmp = 0; |
||||||
|
cmj = 0; |
||||||
|
|
||||||
|
minp = lastmp - 1; |
||||||
|
if (minp < MINP) |
||||||
|
minp = MINP; |
||||||
|
maxp = lastmp + 1; |
||||||
|
if (maxp >= MAXP) |
||||||
|
maxp = MAXP-1; |
||||||
|
|
||||||
|
for (i = 0; i < NOUTPUTS; i++) { |
||||||
|
for (p = minp; p <= maxp; p++) { |
||||||
|
for (j = lastmj; j <= lastmj+2; j++) { |
||||||
|
int nj = j; |
||||||
|
if (nj >= p) |
||||||
|
nj -= p; |
||||||
|
if (r[i][nj][p-MINP] > cmax) { |
||||||
|
cmax = r[i][nj][p-MINP]; |
||||||
|
cmi = i; |
||||||
|
cmj = nj; |
||||||
|
cmp = p; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
count = 0; |
||||||
|
variance = 0; |
||||||
|
for (i = 0; i < NOUTPUTS; i++) |
||||||
|
for (p = MINP; p < MAXP; p++) |
||||||
|
for (j = 0; j < p; j++) { |
||||||
|
double val; |
||||||
|
if (r[i][j][p-MINP] > max / 1.2) |
||||||
|
count++; |
||||||
|
val = r[i][j][p-MINP] - mean; |
||||||
|
variance += val * val; |
||||||
|
} |
||||||
|
|
||||||
|
variance /= nitems; |
||||||
|
sd = sqrt(variance); |
||||||
|
|
||||||
|
if (cmax > (max / 1.2)) { |
||||||
|
max = cmax; |
||||||
|
mi = cmi; |
||||||
|
mj = cmj; |
||||||
|
mp = cmp; |
||||||
|
} |
||||||
|
|
||||||
|
phase = (((double)mj) / ((double)mp)); |
||||||
|
confidence = sd; |
||||||
|
beat = 0; |
||||||
|
if (sd > /*200*/ 10) |
||||||
|
if (mj < lastmj) { |
||||||
|
beat = 1; |
||||||
|
} |
||||||
|
|
||||||
|
lastmax = max; |
||||||
|
lastmj = mj; |
||||||
|
lastmi = mi; |
||||||
|
lastmp = mp; |
||||||
|
|
||||||
|
if (beat) |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,7 @@ |
|||||||
|
/* beatdetect.h */ |
||||||
|
|
||||||
|
void beatdetect_init(void); |
||||||
|
void beatdetect_close(void); |
||||||
|
double beatdetect_getphase(void); |
||||||
|
double beatdetect_getconfidence(void); |
||||||
|
int beatdetect_read(void); |
@ -0,0 +1,129 @@ |
|||||||
|
/* dmx.c */ |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <err.h> |
||||||
|
#include <termios.h> |
||||||
|
#include <strings.h> |
||||||
|
#include <assert.h> |
||||||
|
#include "dmx.h" |
||||||
|
|
||||||
|
#define PORT "/dev/ttyU0" |
||||||
|
#define DMX_PACKETSIZE (DMX_UNIVERSESIZE + 6) |
||||||
|
|
||||||
|
int dmxfd; |
||||||
|
|
||||||
|
char dmxpacket[DMX_UNIVERSESIZE + DMX_PACKETSIZE]; |
||||||
|
char *dmxuniverse; |
||||||
|
|
||||||
|
void dmx_open(void) |
||||||
|
{ |
||||||
|
struct termios t; |
||||||
|
int flags; |
||||||
|
|
||||||
|
dmxfd = open(PORT, O_NONBLOCK | O_RDWR, 0); |
||||||
|
if (dmxfd == -1) { |
||||||
|
err(1, "failed to open DMX port"); |
||||||
|
} |
||||||
|
|
||||||
|
flags = fcntl(dmxfd, F_GETFL); |
||||||
|
fcntl(dmxfd, F_SETFL, flags & ~O_NONBLOCK); |
||||||
|
|
||||||
|
tcgetattr(dmxfd, &t); |
||||||
|
cfmakeraw(&t); |
||||||
|
t.c_cflag = CLOCAL | CREAD | CS8; |
||||||
|
tcsetattr(dmxfd, TCSANOW, &t); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void dmx_close(void) |
||||||
|
{ |
||||||
|
close(dmxfd); |
||||||
|
} |
||||||
|
|
||||||
|
void dmx_dumpparams(void) |
||||||
|
{ |
||||||
|
char buf[1024]; |
||||||
|
int more; |
||||||
|
char *ptr; |
||||||
|
int bytes; |
||||||
|
int len; |
||||||
|
|
||||||
|
buf[0] = 0x7e; |
||||||
|
buf[1] = 3; |
||||||
|
buf[2] = 2; |
||||||
|
buf[3] = 0; |
||||||
|
buf[4] = 0; |
||||||
|
buf[5] = 0; |
||||||
|
buf[6] = 0xe7; |
||||||
|
if (write(dmxfd, buf, 7) != 7) |
||||||
|
printf("didn't write 7 bytes\n"); |
||||||
|
|
||||||
|
more = 1; |
||||||
|
ptr = buf; |
||||||
|
bytes = 0; |
||||||
|
len = 0; |
||||||
|
while (more) { |
||||||
|
if (read(dmxfd, ptr, 1) != 1) |
||||||
|
goto out; |
||||||
|
bytes++; |
||||||
|
ptr++; |
||||||
|
if (buf[0] != 0x7e) { |
||||||
|
printf("Invalid packet received\n"); |
||||||
|
goto out; |
||||||
|
} |
||||||
|
if (bytes == 4) |
||||||
|
len = buf[2] | (buf[3] << 8); |
||||||
|
if (bytes == len + 5) { |
||||||
|
if (buf[bytes-1] != (char)0xe7) { |
||||||
|
printf("Invalid packet end\n"); |
||||||
|
goto out; |
||||||
|
} |
||||||
|
more = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
printf("Received packet:\n"); |
||||||
|
printf("%x %x %x %x %x %x %x %x %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); |
||||||
|
|
||||||
|
out: |
||||||
|
printf("buffer contents:\n"); |
||||||
|
printf("%x %x %x %x %x %x %x %x %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); |
||||||
|
} |
||||||
|
|
||||||
|
void dmx_init(void) |
||||||
|
{ |
||||||
|
dmx_open(); |
||||||
|
dmxpacket[0] = 0x7e; |
||||||
|
dmxpacket[1] = 6; |
||||||
|
dmxpacket[2] = (DMX_UNIVERSESIZE+1) & 0xff; |
||||||
|
dmxpacket[3] = ((DMX_UNIVERSESIZE+1) >> 8) & 0xff; |
||||||
|
dmxpacket[4] = 0; /* start code */ |
||||||
|
bzero(dmxpacket+5, DMX_UNIVERSESIZE); |
||||||
|
dmxpacket[DMX_UNIVERSESIZE+5] = 0xe7; |
||||||
|
dmxuniverse = dmxpacket+5; |
||||||
|
// dmx_dumpparams();
|
||||||
|
} |
||||||
|
|
||||||
|
void dmx_setchannel(int channel, int value) |
||||||
|
{ |
||||||
|
assert(channel < DMX_UNIVERSESIZE); |
||||||
|
dmxuniverse[channel] = (char)value; |
||||||
|
} |
||||||
|
|
||||||
|
void dmx_output(void) |
||||||
|
{ |
||||||
|
int off = 0; |
||||||
|
// char *buf = dmxpacket;
|
||||||
|
// printf("%x %x %x %x %x %x %x %x %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
|
||||||
|
while (off < DMX_PACKETSIZE) { |
||||||
|
int r; |
||||||
|
r = write(dmxfd, dmxpacket + off, DMX_PACKETSIZE - off); |
||||||
|
// printf("write returned %d\n", r);
|
||||||
|
if (r == -1) |
||||||
|
err(1, "error writing packet"); |
||||||
|
off += r; |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,9 @@ |
|||||||
|
/* dmx.h */ |
||||||
|
|
||||||
|
#define DMX_UNIVERSESIZE 512 |
||||||
|
|
||||||
|
void dmx_close(void); |
||||||
|
void dmx_init(void); |
||||||
|
void dmx_setchannel(int channel, int value); |
||||||
|
void dmx_output(void); |
||||||
|
|
@ -0,0 +1,138 @@ |
|||||||
|
/* fft.c */ |
||||||
|
|
||||||
|
#include <math.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <assert.h> |
||||||
|
#include "mem.h" |
||||||
|
#include "fft.h" |
||||||
|
|
||||||
|
#define FFT_SIGN (-1) |
||||||
|
|
||||||
|
int fft_size = 0; |
||||||
|
fft_type *fft_buffer = NULL; |
||||||
|
long fft_logN; |
||||||
|
|
||||||
|
void fft_init(int size) |
||||||
|
{ |
||||||
|
assert(fft_size == 0); |
||||||
|
assert(fft_buffer == NULL); |
||||||
|
|
||||||
|
/* We use complex pairs, so we need twice the number of elements */ |
||||||
|
fft_buffer = safe_malloc(sizeof(fft_type) * size * 2); |
||||||
|
fft_size = size; |
||||||
|
fft_logN = (long)(log(fft_size)/log(2.0)+0.5); |
||||||
|
} |
||||||
|
|
||||||
|
void fft_data_float(float *buf) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
|
||||||
|
for (i = 0; i < fft_size; i++) { |
||||||
|
fft_buffer[i*2] = buf[i]; |
||||||
|
fft_buffer[i*2+1] = 0.0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void fft_data_signed16(int16_t *buf) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
|
||||||
|
for (i = 0; i < fft_size; i++) { |
||||||
|
fft_buffer[i*2] = (fft_type)buf[i] / (INT16_MAX+1); |
||||||
|
fft_buffer[i*2+1] = 0.0; |
||||||
|
// printf("input: %f, %f\n", fft_buffer[i*2], fft_buffer[i*2+1]);
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void fft_data_unsigned16(uint16_t *buf) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
|
||||||
|
for (i = 0; i < fft_size; i++) { |
||||||
|
fft_buffer[i*2] = (fft_type)buf[i] / (INT16_MAX+1) - |
||||||
|
(INT16_MAX+1); |
||||||
|
fft_buffer[i*2+1] = 0.0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fft_type *fft_getresult(void) |
||||||
|
{ |
||||||
|
return fft_buffer; |
||||||
|
} |
||||||
|
|
||||||
|
void fft_window(void) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
|
||||||
|
for (i = 0; i < fft_size; i++) { |
||||||
|
fft_buffer[2*i] = fft_buffer[2*i] * (0.5 + 0.5 * |
||||||
|
cos(M_PI * (i - fft_size/2)/(fft_size/2 + 1))); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* FFT routine |
||||||
|
* Based on routine (C) 1996 S.M.Bernsee. |
||||||
|
*/ |
||||||
|
void fft_compute(void) |
||||||
|
{ |
||||||
|
fft_type wr, wi, arg, *p1, *p2, temp; |
||||||
|
fft_type tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i; |
||||||
|
long i, bitm, j, le, le2, k; |
||||||
|
|
||||||
|
for (i = 2; i < 2*fft_size-2; i += 2) { |
||||||
|
|
||||||
|
for (bitm = 2, j = 0; bitm < 2*fft_size; bitm <<= 1) { |
||||||
|
|
||||||
|
if (i & bitm) j++; |
||||||
|
j <<= 1; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (i < j) { |
||||||
|
|
||||||
|
p1 = fft_buffer+i; p2 = fft_buffer+j; |
||||||
|
temp = *p1; *(p1++) = *p2; |
||||||
|
*(p2++) = temp; temp = *p1; |
||||||
|
*p1 = *p2; *p2 = temp; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
for (k = 0, le = 2; k < fft_logN; k++) { |
||||||
|
|
||||||
|
le <<= 1; |
||||||
|
le2 = le>>1; |
||||||
|
ur = 1.0; |
||||||
|
ui = 0.0; |
||||||
|
arg = M_PI / (le2>>1); |
||||||
|
wr = cos(arg); |
||||||
|
wi = FFT_SIGN*sin(arg); |
||||||
|
|
||||||
|
for (j = 0; j < le2; j += 2) { |
||||||
|
|
||||||
|
p1r = fft_buffer+j; p1i = p1r+1; |
||||||
|
p2r = p1r+le2; p2i = p2r+1; |
||||||
|
|
||||||
|
for (i = j; i < 2*fft_size; i += le) { |
||||||
|
|
||||||
|
tr = *p2r * ur - *p2i * ui; |
||||||
|
ti = *p2r * ui + *p2i * ur; |
||||||
|
*p2r = *p1r - tr; *p2i = *p1i - ti; |
||||||
|
*p1r += tr; *p1i += ti; |
||||||
|
p1r += le; p1i += le; |
||||||
|
p2r += le; p2i += le; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
tr = ur*wr - ui*wi; |
||||||
|
ui = ur*wi + ui*wr; |
||||||
|
ur = tr; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
/* fft.h */ |
||||||
|
|
||||||
|
typedef float fft_type; |
||||||
|
|
||||||
|
/* Initialise fft with the size of the data */ |
||||||
|
void fft_init(int); |
||||||
|
void fft_data_float(float *); |
||||||
|
void fft_data_signed16(int16_t *); |
||||||
|
void fft_data_unsigned16(uint16_t *); |
||||||
|
fft_type *fft_getresult(void); |
||||||
|
void fft_window(void); |
||||||
|
void fft_compute(void); |
@ -0,0 +1,42 @@ |
|||||||
|
/* main.c */ |
||||||
|
|
||||||
|
#include <signal.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <err.h> |
||||||
|
#include "vm.h" |
||||||
|
#include "dmx.h" |
||||||
|
#include "midi.h" |
||||||
|
#include "beatdetect.h" |
||||||
|
#include "mouse.h" |
||||||
|
|
||||||
|
void finish(void) |
||||||
|
{ |
||||||
|
dmx_close(); |
||||||
|
midi_close(); |
||||||
|
beatdetect_close(); |
||||||
|
exit(0); |
||||||
|
} |
||||||
|
|
||||||
|
void sigint_handler(int signal) |
||||||
|
{ |
||||||
|
finish(); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
argv++; |
||||||
|
argc--; |
||||||
|
if (argc != 1) |
||||||
|
errx(1, "Usage: lsi <filename>"); |
||||||
|
vm_init(); |
||||||
|
vm_load(argv[0]); |
||||||
|
signal(SIGINT, sigint_handler); |
||||||
|
midi_init(); |
||||||
|
dmx_init(); |
||||||
|
beatdetect_init(); |
||||||
|
mouse_init(); |
||||||
|
vm_spawn("main"); |
||||||
|
vm_run(); |
||||||
|
finish(); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,645 @@ |
|||||||
|
/* map3d.c */ |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <math.h> |
||||||
|
#include <strings.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include "vm.h" |
||||||
|
|
||||||
|
#define NLIGHTS 16 |
||||||
|
|
||||||
|
#define PANMAX 127 |
||||||
|
#define PANRANGE M_PI_2 |
||||||
|
#define PANOFFSET 128 |
||||||
|
#define TILTMAX 127 |
||||||
|
#define TILTRANGE M_PI_4 |
||||||
|
#define TILTOFFSET 128 |
||||||
|
|
||||||
|
#define MAP3D_FILENAME ".map3d.caldata" |
||||||
|
|
||||||
|
struct light { |
||||||
|
double M[4][3]; |
||||||
|
double cp[3][3]; |
||||||
|
double pan[3]; |
||||||
|
double tilt[3]; |
||||||
|
}; |
||||||
|
|
||||||
|
struct light map3d_cal[NLIGHTS]; |
||||||
|
|
||||||
|
#define MAG(x) (sqrt(SQUARE(x[0]) + SQUARE(x[1]) + SQUARE(x[2]))) |
||||||
|
#define SQUARE(x) ((x) * (x)) |
||||||
|
#define PYTHAG3(a, b) sqrt(SQUARE(a[0]-b[0]) + SQUARE(a[1]-b[1]) + SQUARE(a[2]-b[2])) |
||||||
|
|
||||||
|
#define DEG(x) (180 * (x) / M_PI) |
||||||
|
|
||||||
|
void normalise(double *v) |
||||||
|
{ |
||||||
|
double mag; |
||||||
|
int i; |
||||||
|
|
||||||
|
mag = MAG(v); |
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) |
||||||
|
v[i] /= mag; |
||||||
|
} |
||||||
|
|
||||||
|
#define MM map3d_cal[light].M |
||||||
|
|
||||||
|
void multiply(int light, double *i, double *o) { |
||||||
|
o[0] = i[0] * MM[0][0] + i[1] * MM[1][0] + i[2] * MM[2][0] + MM[3][0]; |
||||||
|
o[1] = i[0] * MM[0][1] + i[1] * MM[1][1] + i[2] * MM[2][1] + MM[3][1]; |
||||||
|
o[2] = i[0] * MM[0][2] + i[1] * MM[1][2] + i[2] * MM[2][2] + MM[3][2]; |
||||||
|
} |
||||||
|
|
||||||
|
#undef MM |
||||||
|
|
||||||
|
void map3d_init(void) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
void map3d_close(void) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
void map3d_save(void) |
||||||
|
{ |
||||||
|
int fd, rv; |
||||||
|
|
||||||
|
fd = open(MAP3D_FILENAME, O_WRONLY | O_CREAT, 0666); |
||||||
|
rv = write(fd, map3d_cal, sizeof(map3d_cal)); |
||||||
|
if (rv != sizeof(map3d_cal)) |
||||||
|
printf("Warning: Calibration data not saved correctly\n"); |
||||||
|
close(fd); |
||||||
|
} |
||||||
|
|
||||||
|
int map3d_load(void) |
||||||
|
{ |
||||||
|
int fd, rv; |
||||||
|
|
||||||
|
fd = open(MAP3D_FILENAME, O_RDONLY, 0666); |
||||||
|
if (!fd) |
||||||
|
return 0; |
||||||
|
rv = read(fd, map3d_cal, sizeof(map3d_cal)); |
||||||
|
if (rv != sizeof(map3d_cal)) |
||||||
|
printf("Warning: Calibration data not read correctly\n"); |
||||||
|
close(fd); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
void map3d_transform(int light, double x, double y, double z, |
||||||
|
int *pan, int *tilt) |
||||||
|
{ |
||||||
|
double pv[3]; |
||||||
|
double rv[3]; |
||||||
|
double p, t; |
||||||
|
|
||||||
|
// printf("Transforming for light %d: (%f, %f, %f)\n", light, x, y, z);
|
||||||
|
fflush(stdout); |
||||||
|
pv[0] = x; |
||||||
|
pv[1] = y; |
||||||
|
pv[2] = z; |
||||||
|
multiply(light, pv, rv); |
||||||
|
normalise(rv); |
||||||
|
t = asin(rv[1]); |
||||||
|
p = asin(rv[0]/cos(t)); |
||||||
|
|
||||||
|
*pan = (int)round((p * PANMAX)/PANRANGE) + PANOFFSET; |
||||||
|
*tilt = (int)round((t * TILTMAX)/TILTRANGE) + TILTOFFSET; |
||||||
|
if (*pan < 0) |
||||||
|
*pan = 0; |
||||||
|
if (*pan > 255) |
||||||
|
*pan = 255; |
||||||
|
if (*tilt < 0) |
||||||
|
*tilt = 0; |
||||||
|
if (*tilt > 255) |
||||||
|
*tilt = 255; |
||||||
|
// printf("pan = %d, tilt = %d\n", *pan, *tilt);
|
||||||
|
} |
||||||
|
|
||||||
|
void map3d_setcal(int light, int n, double x, double y, double z, |
||||||
|
int pan, int tilt) |
||||||
|
{ |
||||||
|
printf("setcal(%d, %d, %f, %f, %f, %d, %d)\n", light, n, x, y, z, pan, tilt); |
||||||
|
map3d_cal[light].cp[n][0] = x; |
||||||
|
map3d_cal[light].cp[n][1] = y; |
||||||
|
map3d_cal[light].cp[n][2] = z; |
||||||
|
map3d_cal[light].pan[n] = PANRANGE * ((double)pan - PANOFFSET) / PANMAX; |
||||||
|
map3d_cal[light].tilt[n] = TILTRANGE * ((double)tilt - TILTOFFSET) |
||||||
|
/ TILTMAX; |
||||||
|
printf("Setcal: pan = %f, tilt = %f\n", map3d_cal[light].pan[n], map3d_cal[light].tilt[n]); |
||||||
|
} |
||||||
|
|
||||||
|
void unitvector(double *vec, double pan, double tilt) |
||||||
|
{ |
||||||
|
double tmp[3]; |
||||||
|
double cosp, sinp, cost, sint; |
||||||
|
|
||||||
|
/* Precalculate some values */ |
||||||
|
cosp = cos(pan); |
||||||
|
sinp = sin(pan); |
||||||
|
cost = cos(tilt); |
||||||
|
sint = sin(tilt); |
||||||
|
|
||||||
|
/* Start with a unit vector */ |
||||||
|
vec[0] = 0; |
||||||
|
vec[1] = 0; |
||||||
|
vec[2] = 1; |
||||||
|
|
||||||
|
/* Rotate around X axis (tilt) */ |
||||||
|
tmp[0] = vec[0]; |
||||||
|
tmp[1] = vec[1]*cost + vec[2]*sint; |
||||||
|
tmp[2] = vec[2]*cost - vec[1]*sint; |
||||||
|
|
||||||
|
/* Rotate around Y axis (pan) */ |
||||||
|
vec[0] = tmp[0]*cosp + tmp[2]*sinp; |
||||||
|
vec[1] = tmp[1]; |
||||||
|
vec[2] = tmp[2]*cosp - tmp[0]*sinp; |
||||||
|
} |
||||||
|
|
||||||
|
double dotproduct(double *a, double *b) |
||||||
|
{ |
||||||
|
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; |
||||||
|
} |
||||||
|
|
||||||
|
void crossproduct(double *a, double *b, double *r) |
||||||
|
{ |
||||||
|
r[0] = a[1]*b[2] - a[2]*b[1]; |
||||||
|
r[1] = a[2]*b[0] - a[0]*b[2]; |
||||||
|
r[2] = a[0]*b[1] - a[1]*b[0]; |
||||||
|
} |
||||||
|
|
||||||
|
void dumpmatrix(double sim[12][13]) { |
||||||
|
int i, j; |
||||||
|
|
||||||
|
for (i = 0; i < 12; i++) { |
||||||
|
for (j = 0; j < 13; j++) |
||||||
|
printf("\t%f", sim[i][j]); |
||||||
|
printf("\n"); |
||||||
|
} |
||||||
|
printf("\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void eliminate(double sim[12][13], double *var) |
||||||
|
{ |
||||||
|
int i, j, k, maxpos; |
||||||
|
double max, val, tmp, x; |
||||||
|
|
||||||
|
dumpmatrix(sim); |
||||||
|
|
||||||
|
for (i = 0; i < 12; i++) { |
||||||
|
/* Find the maximum element in the ith column */ |
||||||
|
max = 0.0; |
||||||
|
maxpos = i; |
||||||
|
for (j = i; j < 12; j++) { |
||||||
|
val = fabs(sim[j][i]); |
||||||
|
if (val > max) { |
||||||
|
max = val; |
||||||
|
maxpos = j; |
||||||
|
} |
||||||
|
} |
||||||
|
if (maxpos != i) |
||||||
|
for (j = 0; j < 13; j++) { |
||||||
|
tmp = sim[maxpos][j]; |
||||||
|
sim[maxpos][j] = sim[i][j]; |
||||||
|
sim[i][j] = tmp; |
||||||
|
} |
||||||
|
if (fabs(sim[i][i]) < 0.0001) |
||||||
|
printf("Warning: Lost accuracy at row %d\n", i); |
||||||
|
for (j = i+1; j < 12; j++) { |
||||||
|
if (fabs(sim[j][i]) > 0.0) { |
||||||
|
/*
|
||||||
|
* Subtract x times row i from row j, |
||||||
|
* where x is chosen such that |
||||||
|
* sim[i][i] * x = sim[j][i] |
||||||
|
*/ |
||||||
|
x = sim[j][i] / sim[i][i]; |
||||||
|
for (k = 0; k < 13; k++) |
||||||
|
sim[j][k] -= x*sim[i][k]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dumpmatrix(sim); |
||||||
|
|
||||||
|
/* Next, substitute in the unknowns. */ |
||||||
|
for (i = 12-1; i >= 0; i--) { |
||||||
|
var[i] = sim[i][12]; |
||||||
|
for (j = i+1; j < 12; j++) |
||||||
|
var[i] -= var[j] * sim[i][j]; |
||||||
|
var[i] /= sim[i][i]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* In: Guess, length, angle, space for solutions */ |
||||||
|
void solvetriangle(double c, double a, double A, double *solp, double *soln) |
||||||
|
{ |
||||||
|
double root; |
||||||
|
double cosA; |
||||||
|
double med; |
||||||
|
|
||||||
|
cosA = cos(A); |
||||||
|
med = 4*c*c*cosA*cosA - 4*(c*c-a*a); |
||||||
|
root = sqrt(med); |
||||||
|
|
||||||
|
if (isnan(root)) |
||||||
|
/* sqrt() of a negative number */ |
||||||
|
if (med > -0.000000001) |
||||||
|
root = 0; |
||||||
|
|
||||||
|
*solp = (2*c*cosA + root)/2; |
||||||
|
*soln = (2*c*cosA - root)/2; |
||||||
|
} |
||||||
|
|
||||||
|
double try(int n, double dguess, double a, double b, double c, double A, double B, double C) |
||||||
|
{ |
||||||
|
double s1, s2; |
||||||
|
double e, f, d; |
||||||
|
|
||||||
|
solvetriangle(dguess, a, A, &s1, &s2); |
||||||
|
e = (n>=4?s2:s1); |
||||||
|
n = n % 4; |
||||||
|
solvetriangle(e, c, C, &s1, &s2); |
||||||
|
f = (n>=2?s2:s1); |
||||||
|
n = n % 2; |
||||||
|
solvetriangle(f, b, B, &s1, &s2); |
||||||
|
d = (n>=1?s2:s1); |
||||||
|
|
||||||
|
return d; |
||||||
|
} |
||||||
|
|
||||||
|
void getsolution(int n, double dguess, double a, double b, double c, double A, double B, double C, double *e, double *f) |
||||||
|
{ |
||||||
|
double s1, s2; |
||||||
|
|
||||||
|
solvetriangle(dguess, a, A, &s1, &s2); |
||||||
|
*e = (n>=4?s2:s1); |
||||||
|
n = n % 4; |
||||||
|
solvetriangle(*e, c, C, &s1, &s2); |
||||||
|
*f = (n>=2?s2:s1); |
||||||
|
} |
||||||
|
|
||||||
|
#define DINCR 0.005 |
||||||
|
|
||||||
|
/*
|
||||||
|
* A is angle opposite a, between d and e |
||||||
|
* B is angle opposite b, between d and f |
||||||
|
* C is angle opposite c, between e and f |
||||||
|
*/ |
||||||
|
int trysolvetetra(int n, double a, double b, double c, |
||||||
|
double A, double B, double C, |
||||||
|
double *dr, double *er, double *fr) |
||||||
|
{ |
||||||
|
double dguess; |
||||||
|
double thresh = 0.000000000001; |
||||||
|
double d, lastd; |
||||||
|
double mind, maxd; |
||||||
|
double d1, d2, d3; |
||||||
|
double e, f; |
||||||
|
int found; |
||||||
|
|
||||||
|
lastd = 0.0/0.0; /* NaN */ |
||||||
|
mind = maxd = 0; /* Shut up compiler */ |
||||||
|
|
||||||
|
/* Find a bracket */ |
||||||
|
found = 0; |
||||||
|
for (dguess = 0.0; dguess < 100.0; dguess+=DINCR) { |
||||||
|
d = try(n, dguess, a, b, c, A, B, C) - dguess; |
||||||
|
if (((d >= 0) && (lastd < 0)) || ((d <= 0) && (lastd > 0))) { |
||||||
|
mind = dguess - DINCR; |
||||||
|
maxd = dguess; |
||||||
|
printf("Found bracket: (%f, %f)\n", mind, maxd); |
||||||
|
found = 1; |
||||||
|
break; |
||||||
|
} |
||||||
|
lastd = d; |
||||||
|
} |
||||||
|
if (!found) |
||||||
|
return 0; |
||||||
|
|
||||||
|
while ((maxd-mind) > thresh) { |
||||||
|
d1 = try(n, mind, a, b, c, A, B, C) - mind; |
||||||
|
d2 = try(n, (mind+maxd)/2, a, b, c, A, B, C) - (mind+maxd)/2; |
||||||
|
d3 = try(n, maxd, a, b, c, A, B, C) - maxd; |
||||||
|
if (((d2 >= 0) && (d1 < 0)) || ((d2 < 0) && (d1 >= 0))) |
||||||
|
maxd = (mind+maxd)/2; |
||||||
|
else |
||||||
|
mind = (mind+maxd)/2; |
||||||
|
} |
||||||
|
|
||||||
|
d = (mind+maxd)/2; |
||||||
|
|
||||||
|
getsolution(n, d, a, b, c, A, B, C, &e, &f); |
||||||
|
|
||||||
|
printf("Found solution: (%f, %f, %f)\n", d, e, f); |
||||||
|
|
||||||
|
*dr = d; |
||||||
|
*er = e; |
||||||
|
*fr = f; |
||||||
|
|
||||||
|
if (!isfinite(d)) |
||||||
|
return 0; |
||||||
|
if (!isfinite(e)) |
||||||
|
return 0; |
||||||
|
if (!isfinite(f)) |
||||||
|
return 0; |
||||||
|
if (d < 0) |
||||||
|
return 0; |
||||||
|
if (e < 0) |
||||||
|
return 0; |
||||||
|
if (f < 0) |
||||||
|
return 0; |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
int solvetetra(double a, double b, double c, |
||||||
|
double A, double B, double C, |
||||||
|
double *dr, double *er, double *fr) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) |
||||||
|
if (trysolvetetra(i, a, b, c, A, B, C, dr, er, fr)) |
||||||
|
return 1; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int map3d_calibrate(int light) |
||||||
|
{ |
||||||
|
double v1[3], v2[3], v3[3], p4[3]; |
||||||
|
double angle1, angle2, angle3; |
||||||
|
double a, b, c, d, e, f; |
||||||
|
double pAB[3], pBC[3]; |
||||||
|
double axis1[3], axis2[3], axis3[3]; |
||||||
|
double axm1, axm2, axm3; |
||||||
|
double hypot, alpha, beta, gamma, delta; |
||||||
|
double sim[12][13]; |
||||||
|
double var[12]; |
||||||
|
double pv[3], tv[3]; |
||||||
|
int success, i; |
||||||
|
|
||||||
|
/*
|
||||||
|
* First, create unit vectors in the directions of the |
||||||
|
* pan & tilt values given |
||||||
|
*/ |
||||||
|
unitvector(v1, map3d_cal[light].pan[0], map3d_cal[light].tilt[0]); |
||||||
|
unitvector(v2, map3d_cal[light].pan[1], map3d_cal[light].tilt[1]); |
||||||
|
unitvector(v3, map3d_cal[light].pan[2], map3d_cal[light].tilt[2]); |
||||||
|
|
||||||
|
/*
|
||||||
|
* Now, we need the angles between them |
||||||
|
*/ |
||||||
|
angle1 = acos(dotproduct(v1, v2)); |
||||||
|
angle2 = acos(dotproduct(v2, v3)); |
||||||
|
angle3 = acos(dotproduct(v3, v1)); |
||||||
|
|
||||||
|
printf("angles (%f, %f, %f)\n", DEG(angle1), DEG(angle2), DEG(angle3)); |
||||||
|
|
||||||
|
/*
|
||||||
|
* And the lengths of the edges which we know |
||||||
|
*/ |
||||||
|
a = PYTHAG3(map3d_cal[light].cp[0], map3d_cal[light].cp[1]); |
||||||
|
b = PYTHAG3(map3d_cal[light].cp[1], map3d_cal[light].cp[2]); |
||||||
|
c = PYTHAG3(map3d_cal[light].cp[2], map3d_cal[light].cp[0]); |
||||||
|
|
||||||
|
/* Solve the tetrahedron */ |
||||||
|
success = solvetetra(a, b, c, angle1, angle2, angle3, &d, &e, &f); |
||||||
|
if (!success) { |
||||||
|
printf("failed to solve tetrahedron\n"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* Multiply the vectors by their magnitudes */ |
||||||
|
for (i = 0; i < 3; i++) { |
||||||
|
v1[i] *= e; |
||||||
|
v2[i] *= d; |
||||||
|
v3[i] *= f; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Find two vectors to define the triangle between |
||||||
|
* the calibration points |
||||||
|
*/ |
||||||
|
for (i = 0; i < 3; i++) { |
||||||
|
pAB[i] = map3d_cal[light].cp[1][i]-map3d_cal[light].cp[0][i]; |
||||||
|
pBC[i] = map3d_cal[light].cp[2][i]-map3d_cal[light].cp[1][i]; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Create some perpendicular vectors in terms of which we can |
||||||
|
* calculate a vector to the fourth point |
||||||
|
*/ |
||||||
|
axis1[0] = pAB[0]; |
||||||
|
axis1[1] = pAB[1]; |
||||||
|
axis1[2] = pAB[2]; |
||||||
|
normalise(axis1); |
||||||
|
crossproduct(axis1, pBC, axis2); |
||||||
|
normalise(axis2); |
||||||
|
crossproduct(axis1, axis2, axis3); |
||||||
|
normalise(axis3); |
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we do some trigonometry to find out the distance to |
||||||
|
* the fourth point in terms of the three axes |
||||||
|
*/ |
||||||
|
beta = asin(d*sin(angle1)/a); |
||||||
|
gamma = asin(f*sin(angle3)/c); |
||||||
|
delta = acos(((a*a)+(c*c)-(b*b))/(2*a*c)); |
||||||
|
|
||||||
|
alpha = acos((cos(gamma)-cos(beta)*cos(delta))/(sin(beta)*sin(delta))); |
||||||
|
|
||||||
|
hypot = e*sin(beta); |
||||||
|
axm1 = e*cos(beta); |
||||||
|
axm2 = hypot*sin(alpha); |
||||||
|
axm3 = hypot*cos(alpha); |
||||||
|
|
||||||
|
/* Now we have the magnitudes, let's get the vectors */ |
||||||
|
for (i = 0; i < 3; i++) { |
||||||
|
axis1[i] *= axm1; |
||||||
|
axis2[i] *= axm2; |
||||||
|
axis3[i] *= axm3; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we can simply add these vectors to point A |
||||||
|
* to get the fourth point |
||||||
|
*/ |
||||||
|
for (i = 0; i < 3; i++) |
||||||
|
p4[i] = map3d_cal[light].cp[0][i] + axis1[i] + |
||||||
|
axis2[i] + axis3[i]; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we can construct a matrix to represent 12 simultaneous |
||||||
|
* equations, which we then solve to get our transformation matrix. |
||||||
|
*/ |
||||||
|
bzero(sim, sizeof(sim)); |
||||||
|
|
||||||
|
/* First point */ |
||||||
|
sim[0][0] = map3d_cal[light].cp[0][0]; |
||||||
|
sim[0][1] = map3d_cal[light].cp[0][1]; |
||||||
|
sim[0][2] = map3d_cal[light].cp[0][2]; |
||||||
|
sim[0][9] = 1; |
||||||
|
sim[0][12] = v1[0]; |
||||||
|
|
||||||
|
sim[1][3] = map3d_cal[light].cp[0][0]; |
||||||
|
sim[1][4] = map3d_cal[light].cp[0][1]; |
||||||
|
sim[1][5] = map3d_cal[light].cp[0][2]; |
||||||
|
sim[1][10] = 1; |
||||||
|
sim[1][12] = v1[1]; |
||||||
|
|
||||||
|
sim[2][6] = map3d_cal[light].cp[0][0]; |
||||||
|
sim[2][7] = map3d_cal[light].cp[0][1]; |
||||||
|
sim[2][8] = map3d_cal[light].cp[0][2]; |
||||||
|
sim[2][11] = 1; |
||||||
|
sim[2][12] = v1[2]; |
||||||
|
|
||||||
|
/* Second point */ |
||||||
|
sim[3][0] = map3d_cal[light].cp[1][0]; |
||||||
|
sim[3][1] = map3d_cal[light].cp[1][1]; |
||||||
|
sim[3][2] = map3d_cal[light].cp[1][2]; |
||||||
|
sim[3][9] = 1; |
||||||
|
sim[3][12] = v2[0]; |
||||||
|
|
||||||
|
sim[4][3] = map3d_cal[light].cp[1][0]; |
||||||
|
sim[4][4] = map3d_cal[light].cp[1][1]; |
||||||
|
sim[4][5] = map3d_cal[light].cp[1][2]; |
||||||
|
sim[4][10] = 1; |
||||||
|
sim[4][12] = v2[1]; |
||||||
|
|
||||||
|
sim[5][6] = map3d_cal[light].cp[1][0]; |
||||||
|
sim[5][7] = map3d_cal[light].cp[1][1]; |
||||||
|
sim[5][8] = map3d_cal[light].cp[1][2]; |
||||||
|
sim[5][11] = 1; |
||||||
|
sim[5][12] = v2[2]; |
||||||
|
|
||||||
|
/* Third point */ |
||||||
|
sim[6][0] = map3d_cal[light].cp[2][0]; |
||||||
|
sim[6][1] = map3d_cal[light].cp[2][1]; |
||||||
|
sim[6][2] = map3d_cal[light].cp[2][2]; |
||||||
|
sim[6][9] = 1; |
||||||
|
sim[6][12] = v3[0]; |
||||||
|
|
||||||
|
sim[7][3] = map3d_cal[light].cp[2][0]; |
||||||
|
sim[7][4] = map3d_cal[light].cp[2][1]; |
||||||
|
sim[7][5] = map3d_cal[light].cp[2][2]; |
||||||
|
sim[7][10] = 1; |
||||||
|
sim[7][12] = v3[1]; |
||||||
|
|
||||||
|
sim[8][6] = map3d_cal[light].cp[2][0]; |
||||||
|
sim[8][7] = map3d_cal[light].cp[2][1]; |
||||||
|
sim[8][8] = map3d_cal[light].cp[2][2]; |
||||||
|
sim[8][11] = 1; |
||||||
|
sim[8][12] = v3[2]; |
||||||
|
|
||||||
|
/* Fourth point */ |
||||||
|
sim[9][0] = p4[0]; |
||||||
|
sim[9][1] = p4[1]; |
||||||
|
sim[9][2] = p4[2]; |
||||||
|
sim[9][9] = 1; |
||||||
|
sim[9][12] = 0; |
||||||
|
|
||||||
|
sim[10][3] = p4[0]; |
||||||
|
sim[10][4] = p4[1]; |
||||||
|
sim[10][5] = p4[2]; |
||||||
|
sim[10][10] = 1; |
||||||
|
sim[10][12] = 0; |
||||||
|
|
||||||
|
sim[11][6] = p4[0]; |
||||||
|
sim[11][7] = p4[1]; |
||||||
|
sim[11][8] = p4[2]; |
||||||
|
sim[11][11] = 1; |
||||||
|
sim[11][12] = 0; |
||||||
|
|
||||||
|
eliminate(sim, var); |
||||||
|
|
||||||
|
map3d_cal[light].M[0][0] = var[0]; |
||||||
|
map3d_cal[light].M[1][0] = var[1]; |
||||||
|
map3d_cal[light].M[2][0] = var[2]; |
||||||
|
map3d_cal[light].M[0][1] = var[3]; |
||||||
|
map3d_cal[light].M[1][1] = var[4]; |
||||||
|
map3d_cal[light].M[2][1] = var[5]; |
||||||
|
map3d_cal[light].M[0][2] = var[6]; |
||||||
|
map3d_cal[light].M[1][2] = var[7]; |
||||||
|
map3d_cal[light].M[2][2] = var[8]; |
||||||
|
map3d_cal[light].M[3][0] = var[9]; |
||||||
|
map3d_cal[light].M[3][1] = var[10]; |
||||||
|
map3d_cal[light].M[3][2] = var[11]; |
||||||
|
|
||||||
|
printf("%f\t%f\t%f\t\t%f\n", var[0], var[3], var[6], var[9]); |
||||||
|
printf("%f\t%f\t%f\t\t%f\n", var[1], var[4], var[7], var[10]); |
||||||
|
printf("%f\t%f\t%f\t\t%f\n", var[2], var[5], var[8], var[11]); |
||||||
|
|
||||||
|
printf("Calibration points are:\n"); |
||||||
|
multiply(light, map3d_cal[light].cp[0], tv); |
||||||
|
printf("(%f, %f, %f) => (%f, %f, %f)\n", map3d_cal[light].cp[0][0], map3d_cal[light].cp[0][1], map3d_cal[light].cp[0][2], tv[0], tv[1], tv[2]); |
||||||
|
multiply(light, map3d_cal[light].cp[1], tv); |
||||||
|
printf("(%f, %f, %f) => (%f, %f, %f)\n", map3d_cal[light].cp[1][0], map3d_cal[light].cp[1][1], map3d_cal[light].cp[1][2], tv[0], tv[1], tv[2]); |
||||||
|
multiply(light, map3d_cal[light].cp[2], tv); |
||||||
|
printf("(%f, %f, %f) => (%f, %f, %f)\n", map3d_cal[light].cp[2][0], map3d_cal[light].cp[2][1], map3d_cal[light].cp[2][2], tv[0], tv[1], tv[2]); |
||||||
|
multiply(light, p4, tv); |
||||||
|
printf("(%f, %f, %f) => (%f, %f, %f)\n", p4[0], p4[1], p4[2], tv[0], tv[1], tv[2]); |
||||||
|
for (i = 0; i < 10; i++) { |
||||||
|
pv[0] = 0; |
||||||
|
pv[1] = (double)i/10.0; |
||||||
|
pv[2] = 0; |
||||||
|
multiply(light, pv, tv); |
||||||
|
printf("(%f, %f, %f) => (%f, %f, %f)\n", pv[0], pv[1], pv[2], tv[0], tv[1], tv[2]); |
||||||
|
} |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
/* Set parameters based on position (x, y, z) and direction (tx, ty, tz) */ |
||||||
|
/* Temp: x, y = pan, tilt measured to (0, 0, 0)
|
||||||
|
tx, ty = pan, tilt of light fixture |
||||||
|
tz = distance from light fixture to (0, 0, 0) |
||||||
|
*/ |
||||||
|
void map3d_setparams(int light, int opan, int otilt, double lpan, double ltilt, double dist) |
||||||
|
{ |
||||||
|
double n[3]; |
||||||
|
double up[3]; |
||||||
|
double right[3]; |
||||||
|
double v[3]; |
||||||
|
double op, ot; |
||||||
|
|
||||||
|
op = PANRANGE * ((double)opan - PANOFFSET) / PANMAX; |
||||||
|
ot = TILTRANGE * ((double)otilt - TILTOFFSET) / TILTMAX; |
||||||
|
|
||||||
|
unitvector(v, op, ot); |
||||||
|
unitvector(n, lpan, ltilt); |
||||||
|
|
||||||
|
up[0] = 0; |
||||||
|
up[1] = (n[1] + sqrt(n[1]*n[1]+4*n[2]*n[2])) / |
||||||
|
(4*n[2]); |
||||||
|
up[2] = -up[1]*n[1]/n[2]; |
||||||
|
normalise(up); |
||||||
|
|
||||||
|
crossproduct(n, up, right); |
||||||
|
normalise(right); |
||||||
|
|
||||||
|
printf("n:\t%f\t%f\t%f\n", n[0], n[1], n[2]); |
||||||
|
printf("up: \t%f\t%f\t%f\n", up[0], up[1], up[2]); |
||||||
|
printf("right: \t%f\t%f\t%f\n", right[0], right[1], right[2]); |
||||||
|
printf("\n"); |
||||||
|
|
||||||
|
/* Construct matrix */ |
||||||
|
|
||||||
|
map3d_cal[light].M[0][0] = right[0]; |
||||||
|
map3d_cal[light].M[0][1] = right[1]; |
||||||
|
map3d_cal[light].M[0][2] = right[2]; |
||||||
|
map3d_cal[light].M[1][0] = up[0]; |
||||||
|
map3d_cal[light].M[1][1] = up[1]; |
||||||
|
map3d_cal[light].M[1][2] = up[2]; |
||||||
|
map3d_cal[light].M[2][0] = n[0]; |
||||||
|
map3d_cal[light].M[2][1] = n[1]; |
||||||
|
map3d_cal[light].M[2][2] = n[2]; |
||||||
|
map3d_cal[light].M[3][0] = dist*v[0]; |
||||||
|
map3d_cal[light].M[3][1] = dist*v[1]; |
||||||
|
map3d_cal[light].M[3][2] = dist*v[2]; |
||||||
|
|
||||||
|
printf("\t%f\t%f\t%f\t\t%f\n", map3d_cal[light].M[0][0], map3d_cal[light].M[0][1], map3d_cal[light].M[0][2], map3d_cal[light].M[3][0]); |
||||||
|
printf("\t%f\t%f\t%f\t\t%f\n", map3d_cal[light].M[1][0], map3d_cal[light].M[1][1], map3d_cal[light].M[1][2], map3d_cal[light].M[3][1]); |
||||||
|
printf("\t%f\t%f\t%f\t\t%f\n", map3d_cal[light].M[2][0], map3d_cal[light].M[2][1], map3d_cal[light].M[2][2], map3d_cal[light].M[3][2]); |
||||||
|
printf("\n"); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
/* map3d.h */ |
||||||
|
|
||||||
|
void map3d_init(void); |
||||||
|
|
||||||
|
void map3d_close(void); |
||||||
|
int map3d_load(void); |
||||||
|
void map3d_save(void); |
||||||
|
void map3d_transform(int, double, double, double, int *, int *); |
||||||
|
void map3d_setcal(int, int, double, double, double, int, int); |
||||||
|
int map3d_calibrate(int); |
||||||
|
void map3d_setparams(int, int, int, double, double, double); |
@ -0,0 +1,101 @@ |
|||||||
|
/* midi.c */ |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <err.h> |
||||||
|
#include <sys/midiio.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <sys/ioctl.h> |
||||||
|
#include "vm.h" |
||||||
|
|
||||||
|
#define PORT "/dev/music" |
||||||
|
|
||||||
|
int midi_fd; |
||||||
|
int midi_bytes; |
||||||
|
seq_event_rec midi_buf; |
||||||
|
int midi_initialised = 0; |
||||||
|
|
||||||
|
void midi_init(void) |
||||||
|
{ |
||||||
|
midi_fd = open(PORT, O_NONBLOCK | O_RDONLY, 0); |
||||||
|
if (midi_fd == -1) { |
||||||
|
err(1, "failed to open MIDI port"); |
||||||
|
} |
||||||
|
midi_bytes = 0; |
||||||
|
midi_initialised = 1; |
||||||
|
vm_register_signal_fd(midi_fd, VM_MIDIQ); |
||||||
|
} |
||||||
|
|
||||||
|
void midi_close(void) |
||||||
|
{ |
||||||
|
printf("Closing MIDI\n"); |
||||||
|
ioctl(midi_fd, SEQUENCER_SYNC, NULL); |
||||||
|
ioctl(midi_fd, SEQUENCER_RESET, NULL); |
||||||
|
printf("...\n"); |
||||||
|
close(midi_fd); |
||||||
|
printf("X.\n"); |
||||||
|
midi_fd = 0; |
||||||
|
midi_initialised = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns non-zero if we're interested in the packet |
||||||
|
* received. Zero otherwise.
|
||||||
|
*/ |
||||||
|
int midi_filter(void) |
||||||
|
{ |
||||||
|
switch (midi_buf.arr[0]) { |
||||||
|
case SEQ_CHN_COMMON: |
||||||
|
/* We don't care about the unit number - yet */ |
||||||
|
/* We don't care about the channel - yet */ |
||||||
|
if (midi_buf.arr[2] == 0xb0) /* cmd */ |
||||||
|
return 1; |
||||||
|
return 0; |
||||||
|
case SEQ_TIMING: |
||||||
|
return 0; |
||||||
|
default: |
||||||
|
printf("Unknown MIDI message received\n"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int midi_read(void) |
||||||
|
{ |
||||||
|
if (!midi_initialised) |
||||||
|
return 0; |
||||||
|
|
||||||
|
while (1) { |
||||||
|
int rv; |
||||||
|
int left = sizeof(midi_buf) - midi_bytes; |
||||||
|
rv = read(midi_fd, midi_buf.arr + midi_bytes, left); |
||||||
|
if (rv == -1) { |
||||||
|
if (errno == EAGAIN) |
||||||
|
return 0; |
||||||
|
printf("Error reading from MIDI\n"); |
||||||
|
close(midi_fd); |
||||||
|
midi_initialised = 0; |
||||||
|
} |
||||||
|
if (rv == 0) |
||||||
|
return 0; |
||||||
|
midi_bytes += rv; |
||||||
|
if (midi_bytes == sizeof(midi_buf)) { |
||||||
|
midi_bytes = 0; |
||||||
|
if (midi_filter()) |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the interesting bits of the MIDI command. |
||||||
|
* The contents of this function is likely to change |
||||||
|
* as we become interested in more types of MIDI device. |
||||||
|
* Pre-condition: midi_filter() has returned 1 |
||||||
|
*/ |
||||||
|
void midi_getcmd(int *button, int *value) |
||||||
|
{ |
||||||
|
*button = midi_buf.arr[4]; |
||||||
|
*value = midi_buf.arr[6]; |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
/* midi.h */ |
||||||
|
|
||||||
|
void midi_init(void); |
||||||
|
void midi_close(void); |
||||||
|
int midi_filter(void); |
||||||
|
int midi_read(void); |
||||||
|
int midi_getcmd(int *, int *); |
@ -0,0 +1,132 @@ |
|||||||
|
/* mouse.c */ |
||||||
|
|
||||||
|
#include <sys/time.h> |
||||||
|
#include <dev/wscons/wsconsio.h> |
||||||
|
|
||||||
|
#include <fcntl.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <err.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include "vm.h" |
||||||
|
|
||||||
|
#define MOUSEDEVICE "/dev/wsmouse" |
||||||
|
|
||||||
|
char *events[] = { |
||||||
|
"undefined", |
||||||
|
"WSCONS_EVENT_KEY_UP", |
||||||
|
"WSCONS_EVENT_KEY_DOWN", |
||||||
|
"WSCONS_EVENT_ALL_KEYS_UP", |
||||||
|
"WSCONS_EVENT_MOUSE_UP", |
||||||
|
"WSCONS_EVENT_MOUSE_DOWN", |
||||||
|
"WSCONS_EVENT_MOUSE_DELTA_X", |
||||||
|
"WSCONS_EVENT_MOUSE_DELTA_Y", |
||||||
|
"WSCONS_EVENT_MOUSE_ABSOLUTE_X", |
||||||
|
"WSCONS_EVENT_MOUSE_ABSOLUTE_Y", |
||||||
|
"WSCONS_EVENT_MOUSE_DELTA_Z", |
||||||
|
"WSCONS_EVENT_MOUSE_ABSOLUTE_Z", |
||||||
|
"WSCONS_EVENT_SCREEN_SWITCH", |
||||||
|
"WSCONS_EVENT_ASCII", |
||||||
|
"WSCONS_EVENT_MOUSE_DELTA_W", |
||||||
|
"WSCONS_EVENT_MOUSE_ABSOLUTE_W" |
||||||
|
}; |
||||||
|
|
||||||
|
#define WSCONS_EVENT_DELTA_X 6 |
||||||
|
#define WSCONS_EVENT_DELTA_Y 7 |
||||||
|
#define WSCONS_EVENT_DELTA_Z 10 |
||||||
|
|
||||||
|
#define MOUSE_SCALE 4 |
||||||
|
|
||||||
|
#define MOUSE_X_MIN (-127 * MOUSE_SCALE) |
||||||
|
#define MOUSE_X_MAX (127 * MOUSE_SCALE) |
||||||
|
#define MOUSE_Y_MIN (-127 * MOUSE_SCALE) |
||||||
|
#define MOUSE_Y_MAX (127 * MOUSE_SCALE) |
||||||
|
#define MOUSE_Z_MIN -127 |
||||||
|
#define MOUSE_Z_MAX 127 |
||||||
|
|
||||||
|
int mouse_fd; |
||||||
|
int mouse_bytes; |
||||||
|
struct wscons_event mouse_buf; |
||||||
|
int mouse_initialised = 0; |
||||||
|
int mouse_x, mouse_y, mouse_z; |
||||||
|
|
||||||
|
void mouse_init(void) |
||||||
|
{ |
||||||
|
mouse_fd = open(MOUSEDEVICE, O_RDONLY); |
||||||
|
if (mouse_fd < 0) |
||||||
|
err(1, "can't open mouse device"); |
||||||
|
|
||||||
|
vm_register_signal_fd(mouse_fd, VM_MOUSEQ); |
||||||
|
mouse_initialised = 1; |
||||||
|
mouse_x = 0; |
||||||
|
mouse_y = 0; |
||||||
|
mouse_z = 0; |
||||||
|
} |
||||||
|
|
||||||
|
void mouse_close(void) |
||||||
|
{ |
||||||
|
close(mouse_fd); |
||||||
|
mouse_initialised = 0; |
||||||
|
} |
||||||
|
|
||||||
|
int mouse_filter(void) |
||||||
|
{ |
||||||
|
switch (mouse_buf.type) { |
||||||
|
case WSCONS_EVENT_MOUSE_DELTA_X: |
||||||
|
mouse_x += mouse_buf.value; |
||||||
|
if (mouse_x > MOUSE_X_MAX) |
||||||
|
mouse_x = MOUSE_X_MAX; |
||||||
|
if (mouse_x < MOUSE_X_MIN) |
||||||
|
mouse_x = MOUSE_X_MIN; |
||||||
|
return 1; |
||||||
|
case WSCONS_EVENT_MOUSE_DELTA_Y: |
||||||
|
mouse_y += mouse_buf.value; |
||||||
|
if (mouse_y > MOUSE_Y_MAX) |
||||||
|
mouse_y = MOUSE_Y_MAX; |
||||||
|
if (mouse_y < MOUSE_Y_MIN) |
||||||
|
mouse_y = MOUSE_Y_MIN; |
||||||
|
return 1; |
||||||
|
case WSCONS_EVENT_MOUSE_DELTA_Z: |
||||||
|
mouse_z += mouse_buf.value; |
||||||
|
if (mouse_z > MOUSE_Z_MAX) |
||||||
|
mouse_z = MOUSE_Z_MAX; |
||||||
|
if (mouse_z < MOUSE_Z_MIN) |
||||||
|
mouse_z = MOUSE_Z_MIN; |
||||||
|
return 1; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
void mouse_getpos(int *x, int *y, int *z) |
||||||
|
{ |
||||||
|
*x = mouse_x / MOUSE_SCALE; |
||||||
|
*y = mouse_y / MOUSE_SCALE; |
||||||
|
*z = mouse_z; |
||||||
|
} |
||||||
|
|
||||||
|
int mouse_read(void) |
||||||
|
{ |
||||||
|
if (!mouse_initialised) |
||||||
|
return 0; |
||||||
|
|
||||||
|
while (1) { |
||||||
|
int rv; |
||||||
|
int left = sizeof(mouse_buf) - mouse_bytes; |
||||||
|
rv = read(mouse_fd, ((char *)&mouse_buf) + mouse_bytes, left); |
||||||
|
if (rv == -1) { |
||||||
|
if (errno == EAGAIN) |
||||||
|
return 0; |
||||||
|
printf("Error reading from mouse\n"); |
||||||
|
close(mouse_fd); |
||||||
|
mouse_initialised = 0; |
||||||
|
} |
||||||
|
if (rv == 0) |
||||||
|
return 0; |
||||||
|
mouse_bytes += rv; |
||||||
|
if (mouse_bytes == sizeof(mouse_buf)) { |
||||||
|
mouse_bytes = 0; |
||||||
|
if (mouse_filter()) |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
/* mouse.h */ |
||||||
|
|
||||||
|
void mouse_init(void); |
||||||
|
void mouse_close(void); |
||||||
|
int mouse_filter(void); |
||||||
|
void mouse_getpos(int *, int *, int *); |
||||||
|
int mouse_read(void); |
@ -0,0 +1,20 @@ |
|||||||
|
/* vm.h */ |
||||||
|
|
||||||
|
void vm_init(void); |
||||||
|
void vm_load(char *); |
||||||
|
int vm_spawn(char *); |
||||||
|
void vm_run(void); |
||||||
|
void vm_register_signal_fd(int /* fd */, int /* queue */); |
||||||
|
|
||||||
|
#define VM_MAXQUEUES 512 |
||||||
|
#define VM_RUNQ 0 |
||||||
|
#define VM_TIMEQ 1 |
||||||
|
|
||||||
|
#define VM_MOUSEQ 6 |
||||||
|
#define VM_BEATQ 7 |
||||||
|
#define VM_MIDIQ 8 |
||||||
|
#define VM_SOCKQ 9 |
||||||
|
|
||||||
|
#define VM_USERQMIN 10 |
||||||
|
#define VM_NOQUEUE (-1) |
||||||
|
|
Loading…
Reference in new issue