Subversion Repositories svn.mios32

Compare Revisions

Ignore whitespace Rev 2595 → Rev 2596

/trunk/apps/sequencers/LoopA/setup.c
New file
0,0 → 1,250
#include "commonIncludes.h"
 
#include "setup.h"
 
// --- Globals ---
u8 configChangesToBeWritten_ = 0;
 
 
/**
* (After a configuration change), write the global setup file to disk
*
*/
void writeSetup()
{
configChangesToBeWritten_ = 0;
MUTEX_SDCARD_TAKE;
 
if ((FILE_WriteOpen(configFilePath, 1)) < 0)
{
FILE_WriteClose(); // important to free memory given by malloc
MUTEX_SDCARD_GIVE;
return;
}
 
char line_buffer[128];
 
// WRITE MIDI ROUTER CONFIG
{
u8 node;
midi_router_node_entry_t *n = &midi_router_node[0];
for (node = 0; node < MIDI_ROUTER_NUM_NODES; ++node, ++n)
{
sprintf(line_buffer, "MIDI_RouterNode %d %s %d %s %d\n",
node,
MIDI_PORT_InNameGet(MIDI_PORT_InIxGet((mios32_midi_port_t) n->src_port)),
n->src_chn,
MIDI_PORT_OutNameGet(MIDI_PORT_InIxGet((mios32_midi_port_t) n->dst_port)),
n->dst_chn);
 
FILE_WriteBuffer((u8 *)line_buffer, strlen(line_buffer));
}
}
 
// close file
FILE_WriteClose();
 
MUTEX_SDCARD_GIVE;
 
}
// ----------------------------------------------------------------------------------------
 
 
/**
* Help function which parses a decimal or hex value
*
*/
static s32 get_dec(const char *word)
{
if (word == NULL)
return -1;
 
char *next;
long l = strtol(word, &next, 0);
 
if (word == next)
return -256; // modification for SEQ_FILE_C: return -256 if value invalid, since we read signed bytes
 
return l; // value is valid
}
// ----------------------------------------------------------------------------------------
 
 
/**
* Another help function which also returns an error message if range is violated
*
*/
static s32 get_dec_range(char *word, char *parameter, int min, int max)
{
s32 value = get_dec(word);
if (value < -255 || value < min || value > max)
{
#if DEBUG_VERBOSE_LEVEL >= 1
DEBUG_MSG("[SEQ_FILE_C] ERROR invalid value '%s' for parameter '%s'\n", word, parameter);
#endif
return -255; // invalid value or range
}
return value;
}
// ----------------------------------------------------------------------------------------
 
 
/**
* Returns the mios32_port_t if the name matches with a MIDI Port (either name or value such as 0x10 for USB1)
* Returns -1 if no matching port has been found
*
*/
s32 MIDI_PORT_InPortFromNameGet(const char* name)
{
int port_ix;
 
for(port_ix=0; port_ix<MIDI_PORT_InNumGet(); ++port_ix)
{
// terminate port name at first space
const char *port_name = MIDI_PORT_InNameGet(port_ix);
const char *search_name = name;
 
while (*port_name != 0 && *port_name == *search_name )
{
++port_name;
++search_name;
 
if (*search_name == 0 && (*port_name == ' ' || *port_name == 0))
return MIDI_PORT_InPortGet(port_ix);
}
}
 
s32 value = get_dec(name);
if (value >= 0 && value <= 0xff)
return value;
 
return -1; // port not found
}
// ----------------------------------------------------------------------------------------
 
 
/**
* Returns the mios32_port_t if the name matches with a MIDI Port (either name or value such as 0x10 for USB1)
* Returns -1 if no matching port has been found
*
*/
s32 MIDI_PORT_OutPortFromNameGet(const char* name)
{
int port_ix;
 
for(port_ix=0; port_ix<MIDI_PORT_OutNumGet(); ++port_ix)
{
// terminate port name at first space
const char *port_name = MIDI_PORT_OutNameGet(port_ix);
const char *search_name = name;
 
while (*port_name != 0 && *port_name == *search_name )
{
++port_name;
++search_name;
 
if (*search_name == 0 && (*port_name == ' ' || *port_name == 0))
return MIDI_PORT_OutPortGet(port_ix);
}
}
 
s32 value = get_dec(name);
if (value >= 0 && value <= 0xff)
return value;
 
return -1; // port not found
}
// ----------------------------------------------------------------------------------------
 
 
/**
* Read global setup from disk (usually only at startup time, called from MUTEX locked environment)
*
*/
void readSetup()
{
file_t file;
s32 status;
 
if (FILE_ReadOpen(&file, configFilePath) < 0)
{
return;
}
 
// read config values
char line_buffer[128];
do
{
status = FILE_ReadLine((u8 *) line_buffer, 128);
/// DEBUG_MSG("readSetup() read: %s", line_buffer);
 
if (status > 1)
{
// sscanf consumes too much memory, therefore we parse directly
char *separators = " \t";
char *brkt;
char *parameter;
 
if ((parameter = strtok_r(line_buffer, separators, &brkt)))
{
if (*parameter == '#')
{
// ignore comments
}
else
{
char *word = strtok_r(NULL, separators, &brkt);
 
if (strcmp(parameter, "MIDI_RouterNode") == 0)
{
int values[5];
 
s32 value = get_dec_range(word, parameter, 0, 255);
if (value < 0)
continue;
 
values[0] = value;
int i;
for (i = 1; i < 5; ++i)
{
word = strtok_r(NULL, separators, &brkt);
 
if (i == 1)
{
values[i] = MIDI_PORT_InPortFromNameGet(word);
}
else if (i == 3)
{
values[i] = MIDI_PORT_OutPortFromNameGet(word);
}
else
{
values[i] = get_dec(word);
}
if (values[i] < 0)
{
break;
}
}
 
if (i == 5)
{
if (values[0] < MIDI_ROUTER_NUM_NODES)
{
midi_router_node_entry_t *n = &midi_router_node[values[0]];
n->src_port = (u8) values[1];
n->src_chn = (u8) values[2];
n->dst_port = (u8) values[3];
n->dst_chn = (u8) values[4];
}
}
}
}
}
}
} while (status >= 1);
 
// close file
FILE_ReadClose(&file);
}
// ----------------------------------------------------------------------------------------
/trunk/apps/sequencers/LoopA/setup.h
New file
0,0 → 1,14
#include "commonIncludes.h"
 
// --- constants ---
#define configFilePath "/setup.txt"
 
// --- globals ---
extern u8 configChangesToBeWritten_;
 
// --- functions ---
// (After a configuration change), write the global setup file to disk
extern void writeSetup();
 
// Read global setup from disk (usually only at startup time)
extern void readSetup();
/trunk/apps/sequencers/LoopA/loopa.c
7,28 → 7,10
// Also, all clips will loop by default (it is called LoopA, anyways)
// This emulates the behaviour of the MBSEQ.
//
// INTERFACE (LoopA v2 - with limited encoders/buttons)
// ----------------------------------------------------
//
// Right encoder: flips through pages aka modes (unless a command is selected, then it changes its data value)
//
// Left encoder: changes global data of mode:
// - in play mode, changes currently active track
// - in note mode, changes currently selected note
// - in disk mode, changes selected session number
//
// To modify command data (e.g. transpose), the GP button under the command must be pushed, then the
// right encoder can change the command data. Pushing the GP button again exits command data modification mode, then
// the right encoder can be used again to change pages aka modes.
//
// Pushing the right or left encoder always returns back to play mode (shortcut)
// (v3 needs no pushable encoders, as we will have more buttons and encoders directly under the commands)
// =================================================================================================
 
#include "commonIncludes.h"
 
#include "tasks.h"
#include "file.h"
#include "loopa.h"
#include "hardware.h"
#include "ui.h"
35,10 → 17,10
#include "screen.h"
#include "app_lcd.h"
#include "voxelspace.h"
#include "setup.h"
 
// -- Local types ---
 
 
// --- Global vars ---
 
static s32 (*clipPlayEventCallback)(u8 clipNumber, mios32_midi_package_t midi_package, u32 tick) = 0; // fetchClipEvents() callback
393,37 → 375,6
void loopaStartup()
{
screenShowLoopaLogo(1);
// Set up fixed MIDI router
DEBUG_MSG("Setting up MIDI router");
// Router: IN1 all -> OUT2 all
midi_router_node_entry_t *n = &midi_router_node[0];
n->src_port = USB0 + ((4&0xc) << 2) + (4&3);
n->src_chn = 17;
n->dst_port = USB0 + ((5&0xc) << 2) + (5&3);
n->dst_chn = 17;
// Router: IN2 all -> OUT1 all
n = &midi_router_node[1];
n->src_port = USB0 + ((5&0xc) << 2) + (5&3);
n->src_chn = 17;
n->dst_port = USB0 + ((4&0xc) << 2) + (4&3);
n->dst_chn = 17;
// Router: IN1 all -> OUT3 all
n = &midi_router_node[2];
n->src_port = USB0 + ((4&0xc) << 2) + (4&3);
n->src_chn = 17;
n->dst_port = USB0 + ((6&0xc) << 2) + (6&3);
n->dst_chn = 17;
// Router: IN3 all -> OUT1 all
n = &midi_router_node[3];
n->src_port = USB0 + ((6&0xc) << 2) + (6&3);
n->src_chn = 17;
n->dst_port = USB0 + ((4&0xc) << 2) + (4&3);
n->dst_chn = 17;
}
// -------------------------------------------------------------------------------------------------
 
911,7 → 862,9
*/
void loopaSDCardAvailable()
{
loadSession(1); // -> XXX: load latest session with a free clip slot instead
readSetup();
 
loadSession(1); // Todo: load last session (stored in setup)
seqInit();
trackMute_[0] = 0;
seqArmButton();
/trunk/apps/sequencers/LoopA/ui.c
6,6 → 6,7
#include "ui.h"
#include "hardware.h"
#include "loopa.h"
#include "setup.h"
#include "screen.h"
#include "voxelspace.h"
 
82,6 → 83,23
MIOS32_DOUT_PinSet(led_page_5, page == PAGE_DISK);
MIOS32_DOUT_PinSet(led_page_6, page == PAGE_TEMPO);
MUTEX_DIGITALOUT_GIVE;
 
// Map to a proper command, that is on this page (or no command at all)
switch(page)
{
case PAGE_MUTE: command_ = COMMAND_NONE; break;
case PAGE_ROUTER: command_ = COMMAND_ROUTE_SELECT; break;
case PAGE_DISK: command_ = COMMAND_NONE; break;
case PAGE_TEMPO: command_= COMMAND_BPM; break;
case PAGE_CLIP: command_ = COMMAND_CLIPLEN; break;
case PAGE_NOTES: command_ = COMMAND_POSITION; break;
case PAGE_TRACK: command_ = COMMAND_PORT; break;
default:
command_ = COMMAND_NONE; break;
}
 
if (configChangesToBeWritten_)
writeSetup();
}
// -------------------------------------------------------------------------------------------------
 
308,10 → 326,10
 
case PAGE_NOTES:
led_gp1 |= command_ == COMMAND_POSITION ? LED_RED : LED_OFF;
led_gp2 |= command_ == COMMAND_NOTE ? LED_RED : LED_OFF;
led_gp3 |= command_ == COMMAND_VELOCITY ? LED_RED : LED_OFF;
led_gp4 |= command_ == COMMAND_LENGTH ? LED_RED : LED_OFF;
led_gp6 |= command_ == COMMAND_DELETENOTE ? LED_RED : LED_OFF;
led_gp2 |= command_ == COMMAND_NOTE_KEY ? LED_RED : LED_OFF;
led_gp3 |= command_ == COMMAND_NOTE_VELOCITY ? LED_RED : LED_OFF;
led_gp4 |= command_ == COMMAND_NOTE_LENGTH ? LED_RED : LED_OFF;
led_gp6 |= command_ == COMMAND_NOTE_DELETE ? LED_RED : LED_OFF;
break;
 
case PAGE_TRACK:
329,6 → 347,14
led_gp1 |= command_ == COMMAND_BPM ? LED_RED : LED_OFF;
led_gp2 |= command_ == COMMAND_BPMFLASH ? LED_RED : LED_OFF;
break;
 
case PAGE_ROUTER:
led_gp1 |= command_ == COMMAND_ROUTE_SELECT ? LED_RED : LED_OFF;
led_gp2 |= command_ == COMMAND_ROUTE_IN_PORT ? LED_RED : LED_OFF;
led_gp3 |= command_ == COMMAND_ROUTE_IN_CHANNEL ? LED_RED : LED_OFF;
led_gp4 |= command_ == COMMAND_ROUTE_OUT_PORT ? LED_RED : LED_OFF;
led_gp5 |= command_ == COMMAND_ROUTE_OUT_CHANNEL ? LED_RED : LED_OFF;
break;
}
}
 
449,7 → 475,7
*/
void notesNote()
{
command_ = command_ == COMMAND_NOTE ? COMMAND_NONE : COMMAND_NOTE;
command_ = command_ == COMMAND_NOTE_KEY ? COMMAND_NONE : COMMAND_NOTE_KEY;
}
// -------------------------------------------------------------------------------------------------
 
460,7 → 486,7
*/
void notesVelocity()
{
command_ = command_ == COMMAND_VELOCITY ? COMMAND_NONE : COMMAND_VELOCITY;
command_ = command_ == COMMAND_NOTE_VELOCITY ? COMMAND_NONE : COMMAND_NOTE_VELOCITY;
}
// -------------------------------------------------------------------------------------------------
 
471,7 → 497,7
*/
void notesLength()
{
command_ = command_ == COMMAND_LENGTH ? COMMAND_NONE : COMMAND_LENGTH;
command_ = command_ == COMMAND_NOTE_LENGTH ? COMMAND_NONE : COMMAND_NOTE_LENGTH;
}
// -------------------------------------------------------------------------------------------------
 
482,7 → 508,7
*/
void notesDeleteNote()
{
command_ = command_ == COMMAND_DELETENOTE ? COMMAND_NONE : COMMAND_DELETENOTE;
command_ = command_ == COMMAND_NOTE_DELETE ? COMMAND_NONE : COMMAND_NOTE_DELETE;
 
u16 activeNote = clipActiveNote_[activeTrack_][activeScene_];
 
542,7 → 568,7
saveSession(sessionNumber_);
diskScanSessionFileAvailable();
 
page_ = PAGE_MUTE;
setActivePage(PAGE_MUTE);
screenNotifyPageChanged();
}
// -------------------------------------------------------------------------------------------------
558,7 → 584,7
 
loadSession(sessionNumber_);
 
page_ = PAGE_MUTE;
setActivePage(PAGE_MUTE);
screenNotifyPageChanged();
}
// -------------------------------------------------------------------------------------------------
573,7 → 599,7
command_ = COMMAND_NONE;
 
seqInit();
page_ = PAGE_MUTE;
setActivePage(PAGE_MUTE);
screenNotifyPageChanged();
 
screenFormattedFlashMessage("A fresh start... :-)");
673,7 → 699,7
{
if (screenIsInMenu())
{
page_ = PAGE_SETUP;
setActivePage(PAGE_SETUP);
}
else
{
684,7 → 710,7
{
if (screenIsInMenu())
{
page_ = PAGE_ROUTER;
setActivePage(PAGE_ROUTER);
}
else
{
695,7 → 721,7
{
if (screenIsInMenu())
{
page_ = PAGE_DISK;
setActivePage(PAGE_DISK);
}
else
{
721,7 → 747,7
{
if (screenIsInMenu())
{
page_ = PAGE_CLIP;
setActivePage(PAGE_CLIP);
}
else
{
740,7 → 766,7
{
if (screenIsInMenu())
{
page_ = PAGE_FX;
setActivePage(PAGE_FX);
}
else
{
764,7 → 790,7
{
if (screenIsInMenu())
{
page_ = PAGE_TRACK;
setActivePage(PAGE_TRACK);
}
else
{
776,7 → 802,7
{
if (screenIsInMenu())
{
// page_ = PAGE_SYSEX; TODO
// setActivePage(PAGE_SYSEX); TODO
}
else
{
809,7 → 835,7
{
if (screenIsInMenu())
{
page_ = PAGE_MIDIMONITOR;
setActivePage(PAGE_MIDIMONITOR);
}
else
{
842,7 → 868,7
{
if (screenIsInMenu())
{
page_ = PAGE_TEMPO;
setActivePage(PAGE_TEMPO);
}
else
{
871,7 → 897,7
{
if (screenIsInMenu())
{
page_ = PAGE_MUTE;
setActivePage(PAGE_MUTE);
}
else
{
895,7 → 921,7
{
if (screenIsInMenu())
{
page_ = PAGE_NOTES;
setActivePage(PAGE_NOTES);
}
else
{
916,7 → 942,7
{
if (screenIsInMenu())
{
// page_ = PAGE_SONG; TODO
// setActivePage(PAGE_SONG); TODO
}
else
{
936,7 → 962,7
}
else if (pin == sw_encoder2)
{
page_ = PAGE_MUTE; // shortcut back to track display
setActivePage(PAGE_MUTE); // shortcut back to track display
command_ = COMMAND_NONE;
screenNotifyPageChanged();
}
1153,7 → 1179,7
clipNotes_[activeTrack_][activeScene_][activeNote].tick = newTick;
}
}
else if (command_ == COMMAND_NOTE)
else if (command_ == COMMAND_NOTE_KEY)
{
u16 activeNote = clipActiveNote_[activeTrack_][activeScene_];
 
1173,7 → 1199,7
clipNotes_[activeTrack_][activeScene_][activeNote].note = newNote;
}
}
else if (command_ == COMMAND_LENGTH)
else if (command_ == COMMAND_NOTE_LENGTH)
{
u16 activeNote = clipActiveNote_[activeTrack_][activeScene_];
 
1193,7 → 1219,7
clipNotes_[activeTrack_][activeScene_][activeNote].length = newLength;
}
}
else if (command_ == COMMAND_VELOCITY)
else if (command_ == COMMAND_NOTE_VELOCITY)
{
u16 activeNote = clipActiveNote_[activeTrack_][activeScene_];
 
1213,7 → 1239,7
clipNotes_[activeTrack_][activeScene_][activeNote].velocity = newVel;
}
}
else if (command_ == COMMAND_DELETENOTE)
else if (command_ == COMMAND_NOTE_DELETE)
{
u16 activeNote = clipActiveNote_[activeTrack_][activeScene_];
 
1240,14 → 1266,60
 
trackMidiChannel_[activeTrack_] = newChannel;
}
else if (command_ == COMMAND_ROUTE_SELECT)
{
s8 newActiveRoute = routerActiveRoute_ += incrementer;
newActiveRoute = (s8)(newActiveRoute < 0 ? 0 : newActiveRoute);
routerActiveRoute_ = (u8)(newActiveRoute < MIDI_ROUTER_NUM_NODES ? newActiveRoute : (MIDI_ROUTER_NUM_NODES - 1));
}
else if (command_ == COMMAND_ROUTE_IN_PORT)
{
// from seq
//u8 port_ix = SEQ_MIDI_PORT_InIxGet(seq_midi_in_port[selected_bus]);
//if( SEQ_UI_Var8_Inc(&port_ix, 0, SEQ_MIDI_PORT_InNumGet()-1-4, incrementer) >= 0 ) { // don't allow selection of Bus1..Bus4
// seq_midi_in_port[selected_bus] = SEQ_MIDI_PORT_InPortGet(port_ix);
midi_router_node_entry_t *n = &midi_router_node[routerActiveRoute_];
s8 newPortIndex = (s8)(MIDI_PORT_InIxGet((mios32_midi_port_t)n->src_port) + incrementer);
 
newPortIndex = (s8)(newPortIndex < 0 ? 0 : newPortIndex);
 
if (newPortIndex >= MIDI_PORT_InNumGet()-1-4)
newPortIndex = (s8)(MIDI_PORT_InNumGet()-1-4);
 
n->src_port = MIDI_PORT_InPortGet((u8)newPortIndex);
configChangesToBeWritten_ = 1;
}
else if (command_ == COMMAND_ROUTE_IN_CHANNEL)
{
midi_router_node_entry_t *n = &midi_router_node[routerActiveRoute_];
s8 newChannel = (s8)((mios32_midi_port_t)n->src_chn + incrementer);
 
newChannel = (s8)(newChannel < 0 ? 0 : newChannel);
newChannel = (s8)(newChannel > 17 ? 17 : newChannel);
 
n->src_chn = (u8)newChannel;
configChangesToBeWritten_ = 1;
}
else if (command_ == COMMAND_ROUTE_OUT_PORT)
{
midi_router_node_entry_t *n = &midi_router_node[routerActiveRoute_];
s8 newPortIndex = (s8)(MIDI_PORT_OutIxGet((mios32_midi_port_t)n->dst_port) + incrementer);
 
newPortIndex = (s8)(newPortIndex < 0 ? 0 : newPortIndex);
 
if (newPortIndex >= MIDI_PORT_OutNumGet()-1-4)
newPortIndex = (s8)(MIDI_PORT_OutNumGet()-1-4);
 
n->dst_port = MIDI_PORT_OutPortGet((u8)newPortIndex);
configChangesToBeWritten_ = 1;
}
else if (command_ == COMMAND_ROUTE_OUT_CHANNEL)
{
midi_router_node_entry_t *n = &midi_router_node[routerActiveRoute_];
s8 newChannel = (s8)((mios32_midi_port_t)n->dst_chn + incrementer);
 
newChannel = (s8)(newChannel < 0 ? 0 : newChannel);
newChannel = (s8)(newChannel > 17 ? 17 : newChannel);
 
n->dst_chn = (u8)newChannel;
configChangesToBeWritten_ = 1;
}
}
}
// -------------------------------------------------------------------------------------------------
/trunk/apps/sequencers/LoopA/screen.c
771,16 → 771,16
else
printFormattedString(0, 54, "Po %d", pos);
 
command_ == COMMAND_NOTE ? setFontInverted() : setFontNonInverted();
command_ == COMMAND_NOTE_KEY ? setFontInverted() : setFontNonInverted();
 
char noteStr[8];
stringNote(noteStr, note);
printFormattedString(42, 54, "%s", noteStr);
 
command_ == COMMAND_VELOCITY ? setFontInverted() : setFontNonInverted();
command_ == COMMAND_NOTE_VELOCITY ? setFontInverted() : setFontNonInverted();
printFormattedString(84, 54, "Vel %d", velocity);
 
command_ == COMMAND_LENGTH ? setFontInverted() : setFontNonInverted();
command_ == COMMAND_NOTE_LENGTH ? setFontInverted() : setFontNonInverted();
printFormattedString(126, 54, "Len %d", length);
 
command_ == COMMAND_FREEZE ? setFontInverted() : setFontNonInverted();
/trunk/apps/sequencers/LoopA/loopa.h
1,8 → 1,6
// LoopA Core Logic
// (c) Hawkeye 2015-2018
 
#define DEBUG_MSG MIOS32_MIDI_SendDebugMessage
 
#define TRACKS 6
#define SCENES 6
 
/trunk/apps/sequencers/LoopA/app.c
358,9 → 358,6
// stop sequencer
SEQ_BPM_Stop();
 
// load all file infos
/// MIDIO_FILE_LoadAllFiles(1); // including HW info
 
// immediately go to next step
sdcard_check_ctr = sdcard_check_delay;
}
/trunk/apps/sequencers/LoopA/ui.h
19,7 → 19,7
{
COMMAND_NONE,
COMMAND_CLIPLEN, COMMAND_QUANTIZE, COMMAND_TRANSPOSE, COMMAND_SCROLL, COMMAND_STRETCH, COMMAND_FREEZE, // PAGE_CLIP
COMMAND_POSITION, COMMAND_NOTE, COMMAND_VELOCITY, COMMAND_LENGTH, COMMAND_DELETENOTE, // PAGE_NOTES
COMMAND_POSITION, COMMAND_NOTE_KEY, COMMAND_NOTE_VELOCITY, COMMAND_NOTE_LENGTH, COMMAND_NOTE_DELETE, // PAGE_NOTES
COMMAND_PORT, COMMAND_CHANNEL, // PAGE_TRACK
COMMAND_SAVE, COMMAND_LOAD, COMMAND_NEW, // PAGE_DISK
COMMAND_BPM, COMMAND_BPMFLASH, // PAGE_TEMPO
/trunk/apps/sequencers/LoopA/commonIncludes.h
5,7 → 5,10
#ifndef LOOPA_COMMONINCLUDES_H
#define LOOPA_COMMONINCLUDES_H
 
#define DEBUG_MSG MIOS32_MIDI_SendDebugMessage
 
#include "loopa_datatypes.h"
#include "tasks.h"
 
#include <string.h>
#include <stdarg.h>
18,5 → 21,6
#include <midi_port.h>
#include <midi_router.h>
 
#include "file.h"
 
#endif //LOOPA_COMMONINCLUDES_H
/trunk/apps/sequencers/LoopA/Makefile
22,6 → 22,7
hardware.c \
terminal.c \
loopa.c \
setup.c \
screen.c \
ui.c \
voxelspace.c