home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
music
/
patchlib
/
patchsrc
/
patch.c
< prev
Wrap
Text File
|
1985-11-19
|
44KB
|
1,676 lines
#include <curses.h>
/*
* The following source code is being placed in the public domain
* with the sole restriction that if any of it is used in any manner,
* proper acknowledgement will be given to the original author -
* Eric Pettersen
*/
#define Effect (!((Random() >> 3) % weirdness))
#define sfunc(i,b) ((types[i][b] == 1) ? "high": ((types[i][b] == 2) ? \
" mid": " low"))
#define Get_roll(a) roll = get_roll(a)
#define AND_CHAR 241
#define OPTIONS 9
#define EDIT_OPTIONS 8
#define MAIN 0
#define EDIT 1
#define OK 0
#undef NULL
#define NULL -1
#define ABORT -2
#define BAD -3
#define VOICES 1000
/* either #define DX100 or CZ101 here */
#ifdef DX100
#define RANDOM_FILE "DX100.DTA"
#define VOICE_FILE "DXVOICES.DTA"
#define VOICE_SIZE 77
#define TOTAL_SIZE 93
#else
#define RANDOM_FILE "CZ101.DTA"
#define VOICE_FILE "CZVOICES.DTA"
#define VOICE_SIZE 81
#define TOTAL_SIZE 128
#define VDT 0
#define VRm 1
#define VRl 2
#define VD 3
#define SLOTS 4
char table[SLOTS][100]; /* the CZMIDI.DTA data file fits in this table */
int dca_kf[10] = { 0, 8, 17, 26, 36, 47, 58, 69, 82, 95 };
int dcw_kf[10] = { 0, 31, 44, 57, 70, 83, 96, 110, 146, 255 };
#endif
int weirdness;
int ranges[VOICE_SIZE]; /* data from DX/CZDATA.DTA */
int types[VOICE_SIZE][2]; /* is read into these */
int tries[VOICE_SIZE][2]; /* arrays */
char out[80], key_tbl[384]; /* data from KEYTAB.DTA goes in */
/* key_tbl array */
int cur_voice, load_ptr; /* cur_voice: points to where */
/* next saved voice will go in */
/* the voices array (and also, */
/* therefore, how many voices */
/* we have in the library) */
/* load_ptr: which voice from */
/* voices array was last loaded */
/* into the synth */
long cur_space; /* how much free space on disk */
unsigned char voices[VOICES][TOTAL_SIZE]; /* actual voices */
char v_names[VOICES+1][80]; /* associated voice names */
/* main: Handle all main menu I/O and call any subroutines requested */
main()
{
char key, ans;
char voice[TOTAL_SIZE], v_name[80], search_str[80];
int i, j, name_valid, load_voice, leng, found, init_rez;
if ((init_rez = Getrez()) == 0) Setscreen(-1L, -1L, 1);
init_curses();
scr_func(CLEAR_SCR);
printf("Getting old voices from file\n\r");
get_voices(v_names, voices);
load_ptr = -1;
printf("Getting random voice weights from file\n\r");
initialize();
show_screen(MAIN);
do {
pos_cursor(8, 3+OPTIONS);
scr_func(ERASE_TO_EOP);
switch((int)(key = Crawcin())) {
case 'n':
case 'N':
printf("n");
printf("\n\rmaking voice");
make_voice(voice);
load_ptr = cur_voice;
/* FALL THROUGH */
case 'r':
case 'R':
if (key == 'r' || key == 'R'){
printf("r");
}
if (load_ptr < 0)
printf("\n\rno current voice\n\r");
else {
printf("\n\rsending voice\n\r");
if (load_ptr == cur_voice)
send_voice(voice);
else
send_voice(voices[load_ptr]);
show_voice(load_ptr);
}
break;
case 's':
case 'S':
printf("s");
printf("\n\rreceiving voice\n\r");
#ifndef DEBUG
receive_voice(voice);
#endif
do {
do {
pos_cursor(0,5+OPTIONS);
scr_func(CLEAR_TO_EOL);
printf("enter voice name: \007");
printf("\n\r[ESC to abort]");
pos_cursor(18, 5+OPTIONS);
leng = get_str(v_name);
} while (leng == 0);
if (leng < 0) break;
name_valid = TRUE;
for(i=0; i<leng; i++)
if (v_name[i]<32 || v_name[i]>127) {
printf("\n\rName has invalid ");
printf("character in it - ");
printf("re-try");
name_valid = FALSE;
break;
}
v_name[i] = '\0';
if (name_valid)
for(i=0; i<cur_voice; i++) {
if(!strcmp(v_names[i],v_name))
{
printf("\n\rThere is al");
printf("ready a voice");
printf(" named '%s'",
v_name);
printf(" - re-try");
name_valid = FALSE;
break;
}
}
} while(name_valid == FALSE);
if (leng < 0) break;
#ifdef DX100
strncpy(voice+77, v_name, 10);
for(i=strlen(v_name); i<10; i++) voice[77+i] = ' ';
#endif
pos_cursor(0,6+OPTIONS);
scr_func(CLEAR_TO_EOL);
for(i=0; i<TOTAL_SIZE; i++) voices[cur_voice][i] = voice[i];
strcpy(v_names[cur_voice], v_name);
printf("writing voice '%s' to file\n\r", v_name);
write_voice(v_name, voice);
cur_voice++;
show_voice(load_ptr);
break;
case 'a':
case 'A':
printf("a");
goto test;
case 'l':
case 'L':
printf("l");
test:
if (cur_voice == 0) {
warn("No voices to load");
break;
}
if (key == 'a' || key == 'A') {
load_ptr = (load_ptr + 1) % cur_voice;
goto load_it;
}
load_voice = get_v_num(5+OPTIONS);
if (load_voice == ABORT) break;
load_ptr = load_voice;
load_it:
pos_cursor(0,6+OPTIONS);
scr_func(CLEAR_TO_EOL);
printf("Loading voice '%s'\n\r", v_names[load_ptr]);
send_voice(voices[load_ptr]);
show_voice(load_ptr);
break;
case 'w':
case 'W':
printf("w");
do {
pos_cursor(0, 5+OPTIONS);
scr_func(CLEAR_TO_EOL);
printf("New weirdness factor: ");
leng = get_num();
if (leng == BAD || leng == 0) {
printf("\n\rInput 1 or higher ");
printf("[ESC to abort]");
}
} while(leng == 0 || leng == BAD);
if (leng > 0) {
weirdness = leng;
show_weirdness();
}
break;
case 'e':
case 'E':
show_screen(EDIT);
edit();
show_screen(MAIN);
break;
case 'f':
case 'F':
printf("f");
Keytbl(key_tbl, key_tbl+128, key_tbl+256);
pos_cursor(0, 5+OPTIONS);
printf("Enter string(s) to search for: \n\r");
printf("[ESC to abort]");
pos_cursor(32, 5+OPTIONS);
leng = get_str(search_str);
Bioskeys();
if (leng <= 0) break;
found = -1;
pos_cursor(0, 8+OPTIONS);
printf(" # name\n\r");
printf("--- ----");
do {
found = search(search_str, found+1);
if (found < cur_voice) {
pos_cursor(0, 10+OPTIONS);
scr_func(CLEAR_TO_EOL);
printf("%03d '%s'", found,
v_names[found]);
pos_cursor(0, 6+OPTIONS);
scr_func(CLEAR_TO_EOL);
printf("Continue search (y/n)? \007");
printf("%c", (ans = Crawcin()));
}
else {
pos_cursor(0, 10+OPTIONS);
scr_func(CLEAR_TO_EOL);
printf("*** NONE");
pos_cursor(0, 6+OPTIONS);
scr_func(CLEAR_TO_EOL);
printf("-- Hit any key to continue --");
wait();
}
} while (found<cur_voice && (ans == 'y' || ans == 'Y'));
break;
case 'q':
case 'Q':
printf("q");
break;
default:
printf("\007");
printf("\n\rBad option '%c' - re-try", key);
break;
}
} while (key != 'q' && key != 'Q');
if (init_rez == 0) Setscreen(-1L, -1L, 0);
curses_cleanup();
}
/* get_voices: read the standard voice library file and initialize the
voices in memory */
get_voices(names, voice_data)
char names[][80], voice_data[][TOTAL_SIZE];
{
long result;
int handle;
check_disk();
if (cur_space < 80 + TOTAL_SIZE) {
warn(
"WARNING: There is not enough space on the disk to store more voices");
}
result = Fsfirst(VOICE_FILE, 0);
if (result == EFILNF) {
printf("file '%s' not found -- attempting to create\n\r",
VOICE_FILE);
handle = Fcreate(VOICE_FILE, 0);
if (handle < 0) {
sprintf(out, "cannot create '%s'", VOICE_FILE);
error(out);
}
else {
printf("'%s' created\n\r", VOICE_FILE);
Fclose(handle);
result = E_OK;
}
}
if (result == E_OK) {
handle = Fopen(VOICE_FILE, READ);
if (handle < 0) {
sprintf(out, "cannot open '%s'", VOICE_FILE);
error(out);
}
else {
printf("file opened\n\r");
}
}
else {
sprintf(out, "cannot find '%s'", VOICE_FILE);
error(out);
}
cur_voice = 0;
printf("reading in voice data\n\r");
while(TRUE) {
if (scan_name(handle, names[cur_voice]) != OK) break;
if (strlen(names[cur_voice]) > 0) {
if (scan_voice(handle, voice_data[cur_voice]) != OK)
break;
cur_voice++;
}
else break;
}
Fclose(handle);
}
/* make_voice: create a random voice and put it in 'voice' */
make_voice(voice)
char voice[];
{
int i, roll, wave1, wave2, nmod, rmod, line, step, sustain;
int rate, level;
#ifdef DX100
for (i=0; i<VOICE_SIZE; i++) {
if (Effect) voice[i] = func(i,0);
else voice[i] = func(i,1);
}
if (!((Random() >> 3) % 4)) voice[10] = 0; /* each operator */
if (!((Random() >> 3) % 4)) voice[23] = 0; /* (except # 1) */
if (!((Random() >> 3) % 4)) voice[36] = 0; /* given arbitrary */
/* 25% chance of not */
/* being used */
if (!Effect) voice[11] = round(voice[11]); /* normal frequency */
if (!Effect) voice[24] = round(voice[24]); /* ratios are */
if (!Effect) voice[37] = round(voice[37]); /* rational multiples*/
if (!Effect) voice[50] = round(voice[50]); /* of 1.0 */
voice[49] = 99; /* max operator 1 output */
voice[62] /= 12;
voice[62] *= 12; /* make key change shift whole octaves */
sprintf(voice+77, "RANDOM ");
for(i=87; i<93; i++) voice[i] = 0;
#else
/* Do I want to explain how the code works for the CZ101? NOOO!!! *
* I suggest you get a copy of CZ101 MIDI system exclusive specs *
* and then examine the code closely. What makes this stuff so *
* hard to understand is that the random values have to be put *
* into specific *bit positions* in specific bytes, instead of *
* being given bytes of their very own, i.e. several different *
* values are stuffed into a specific byte. If there is something*
* crucial that you cannot understand you can E-mail me. If you *
* scrap the code and write your own, I suggest you retain CZMIDI.*
* DTA because that is a pain to generate by hand. */
Get_roll(0);
roll = (roll - 1) % 3;
voice[0] = 0 | (roll << 2) | (line = 3);
/* Line select and Octave */
voice[1] = (Random() >> 3) % 2;
/* Detune + or - */
Get_roll(1);
voice[2] = (((10*roll)/151) << 4) + ((roll + roll/15 - 1) % 16);
/* Fine Detune */
Get_roll(2);
voice[3] = roll;
/* Octave and Note Detune */
Get_roll(3);
voice[4] = 8/(roll+1) + (roll == 3) * 28;
/* Vibrato Waveform */
Get_roll(4);
voice[5] = roll;
voice[6] = table[VDT][roll];
voice[7] = (roll > 79) + (roll > 95);
/* Vibrato Delay Time (3 bytes) */
Get_roll(5);
voice[8] = roll;
voice[9] = table[VRl][roll];
voice[10] = table[VRm][roll];
/* Vibrato Rate (3 bytes) */
Get_roll(6);
voice[11] = roll;
voice[12] = table[VD][roll];
voice[13] = (roll > 78) + (roll > 94) + (roll > 98);
/* Vibrato Depth (3 bytes) */
for(i=0; i<2; i++) {
Get_roll(7+i*37);
wave1 = roll;
Get_roll(8+i*37);
if (roll) {
Get_roll(9+i*37);
wave2 = roll+1;
if (wave1 > 4 && wave2 > 5) wave2 = 0;
}
else wave2 = 0;
Get_roll(10+i*37);
if (!(rmod = roll)) {
Get_roll(11+i*37);
nmod = roll;
} else nmod = 0;
if (i || line < 2) nmod = rmod = 0;
voice[14+i*57] =
((wave1 < 3 ? wave1 : (wave1 > 4 ? 6 : wave1+1)) << 5)
+(wave2>0)*((wave2<4 ? wave2-1:(wave2>5 ? 6:wave2))<<2)
+((wave2 > 0) << 1);
/* DCO waves */
wave2--;
voice[15+i*57] =
((max(wave1,wave2) > 4 ? max(wave1,wave2)-4 : 0) << 6)
+ (rmod << 5) + ((3*nmod) << 3);
/* Modulation and DCO wave resonance */
Get_roll(12+i*37);
voice[16+i*57] = roll;
voice[17+i*57] = dca_kf[roll];
/* DCA Key Follow */
Get_roll(13+i*37);
voice[18+i*57] = roll;
voice[19+i*57] = dcw_kf[roll];
/* DCW Key Follow */
Get_roll(14+i*37);
if (!i && roll < 1) roll = 1;
voice[20+i*57] = roll;
/* DCA End Step */
if (Effect) sustain = 8;
else sustain = mid(voice[20+i*57], 3);
if (sustain == voice[20+i*57]) sustain = 8;
Get_roll(15+i*37);
rate = roll;
voice[21+i*57] = (119 * rate) / 99;
/* DCA Attack Rate */
Get_roll(16+i*37);
level = roll;
voice[22+i*57] = (sustain == 0 ? 128 : 0) +
(level == 0 ? 0 : level+28);
/* DCA Attack Level */
for (step=1; step<voice[20+i*57]; step++) {
if (sustain < 8) {
if (step < sustain) {
Get_roll(17+i*37);
rate = roll;
Get_roll(18+i*37);
level = roll;
}
else if (step == sustain) {
Get_roll(19+i*37);
rate = roll;
Get_roll(20+i*37);
level = roll;
}
else {
Get_roll(21+i*37);
rate = roll;
Get_roll(22+i*37);
level = roll;
}
}
else if (step < (voice[20+i*37]+1)/2) {
Get_roll(17+i*37);
rate = roll;
Get_roll(18+i*37);
level = roll;
}
else {
Get_roll(21+i*37);
rate = roll;
Get_roll(22+i*37);
level = roll;
}
voice[21+2*step+i*57] = (level < (voice[20+2*step+i*57]
& 0x007F) ? 128 : 0) + ((119 * rate)/99);
/* DCA intermediate rate */
voice[22+2*step+i*57] = (sustain == step ? 128 : 0) +
(level == 0 ? 0 : level+28);
/* DCA intermediate level */
}
Get_roll(23+i*37);
rate = roll;
voice[21+2*step+i*57] = 128 + ((119 * rate)/99);
/* DCA End Rate */
voice[22+2*step+i*57] = 0;
/* DCA End Level */
for(step=step+1;step<8;step++) {
voice[21+2*step+i*57] = (119*50)/99;
voice[22+2*step+i*57] = 0;
/* Envelope cleanup */
}
Get_roll(24+i*37);
voice[37+i*57] = roll;
/* DCW End Step */
if (Effect) sustain = 8;
else sustain = mid(voice[37+i*57], 3);
if (sustain == voice[37+i*57]) sustain = 8;
Get_roll(25+i*37);
rate = roll;
Get_roll(26+i*37);
level = roll;
voice[38+i*57] = (119 * rate) / 99;
/* DCW Attack Rate */
voice[39+i*57] = (127 * level) / 99;
/* DCW Attack Level */
for (step=1; step<voice[37+i*57]; step++) {
if (sustain < 8) {
if (step < sustain) {
Get_roll(27+i*37);
rate = roll;
Get_roll(28+i*37);
level = roll;
}
else if (step == sustain) {
Get_roll(29+i*37);
rate = roll;
Get_roll(30+i*37);
level = roll;
}
else {
Get_roll(31+i*37);
rate = roll;
Get_roll(32+i*37);
level = roll;
}
}
else if (step < (voice[20+i*37]+1)/2) {
Get_roll(27+i*37);
rate = roll;
Get_roll(28+i*37);
level = roll;
}
else {
Get_roll(31+i*37);
rate = roll;
Get_roll(32+i*37);
level = roll;
}
voice[38+2*step+i*57] = (level < (voice[37+2*step+i*57]
& 0x007F) ? 128 : 0) + ((119 * rate)/99);
/* DCW intermediate rate */
voice[39+2*step+i*57] = (sustain == step ? 128 : 0) +
((127 * level) / 99);
/* DCW intermediate level */
}
Get_roll(33+i*37);
rate = roll;
voice[38+2*step+i*57] = 128 + ((119 * rate)/99);
/* DCW End Rate */
voice[39+2*step+i*57] = 0;
/* DCW End Level */
for(step=step+1;step<8;step++) {
voice[38+2*step+i*57] = (119*50)/99;
voice[39+2*step+i*57] = 0;
/* Envelope cleanup */
}
Get_roll(34+i*37);
voice[54+i*57] = roll;
/* DCO End Step */
if (Effect) sustain = 8;
else sustain = mid(voice[54+i*57], 3);
if (sustain == voice[54+i*57]) sustain = 8;
Get_roll(35+i*37);
rate = roll;
Get_roll(36+i*37);
level = roll;
voice[55+i*57] = (127 * rate) / 99;
/* DCO Attack Rate */
voice[56+i*57] = (level < 64 ? level : level+4);
/* DCO Attack Level */
for (step=1; step<voice[54+i*57]; step++) {
if (sustain < 8) {
if (step < sustain) {
Get_roll(37+i*37);
rate = roll;
Get_roll(38+i*37);
level = roll;
}
else if (step == sustain) {
Get_roll(39+i*37);
rate = roll;
Get_roll(40+i*37);
level = roll;
}
else {
Get_roll(41+i*37);
rate = roll;
Get_roll(42+i*37);
level = roll;
}
}
else if (step < (voice[20+i*37]+1)/2) {
Get_roll(37+i*37);
rate = roll;
Get_roll(38+i*37);
level = roll;
}
else {
Get_roll(41+i*37);
rate = roll;
Get_roll(42+i*37);
level = roll;
}
voice[55+2*step+i*57] = (level < (voice[54+2*step+i*57]
& 0x007F) ? 128 : 0) + ((127 * rate)/99);
/* DCO intermediate rate */
voice[56+2*step+i*57] = (sustain == step ? 128 : 0) +
(level < 64 ? level : level+4);
/* DCO intermediate level */
}
Get_roll(43+i*37);
rate = roll;
voice[55+2*step+i*57] = 128 + ((127 * rate)/99);
/* DCO End Rate */
voice[56+2*step+i*57] = 0;
/* DCO End Level */
for(step=step+1;step<8;step++) {
voice[55+2*step+i*57] = (127*50)/99;
voice[56+2*step+i*57] = 0;
/* Envelope cleanup */
}
}
for (i=0; i<TOTAL_SIZE; i++)
voice[i] = (voice[i] << 4) + (0x000F & (voice[i] >> 4));
/* Casio sends nibbles in *reverse* order */
#endif
}
/* send_voice: send a voice ('voice') to the synth */
send_voice(voice)
char voice[];
{
int i,j;
char checksum;
#ifdef CZ101
retry:
midi_flush();
#endif
send('\360');
#ifdef DX100
send('\103');
send('\000');
send('\003');
send('\000');
send('\135');
checksum = 0;
for(i=0;i<TOTAL_SIZE;i++) {
send(voice[i]);
checksum += ~voice[i] + 1;
}
checksum &= '\177';
send(checksum);
#else
send('\104');
send('\000');
send('\000');
send('\160');
send('\040');
send('\140');
if(!handshake('\360')) goto retry;
if(!handshake('\104')) goto retry;
if(!handshake('\000')) goto retry;
if(!handshake('\000')) goto retry;
if(!handshake('\160')) goto retry;
if(!handshake('\060')) goto retry;
for(i=0; i<TOTAL_SIZE; i++) {
send((char)(0x000F & (voice[i] >> 4)));
send((char)(0x000F & voice[i]));
}
for (i=0; i<256 - 2*TOTAL_SIZE; i++) send('\000');
#endif
send('\367');
#ifdef CZ101
if(!handshake('\367')) goto retry;
#endif
}
/* receive_voice: receive a voice from the synth and place it in 'voice' */
receive_voice(voice)
char voice[];
{
int i,j;
#ifdef DX100
char checksum, test;
#else
char high, low;
#endif
retry:
midi_flush();
send('\360');
#ifdef DX100
send('\103');
send('\040');
send('\003');
send('\367');
for(i=0;i<5;i++) {
while((test=Bconin(3)) & '\200');
}
test = 0;
for(i=0;i<TOTAL_SIZE;i++) {
while((voice[i] = Bconin(3)) & '\200');
test += ~voice[i] + 1;
}
test &= '\177';
while((checksum = Bconin(3)) & '\200');
if (test == checksum) {
printf("good checksum\n\r");
}
else {
printf("bad checksum -- re-trying\n\r");
goto retry;
}
#else
send('\104');
send('\000');
send('\000');
send('\160');
send('\020');
send('\140');
if (!handshake('\360')) goto retry;
if (!handshake('\104')) goto retry;
if (!handshake('\000')) goto retry;
if (!handshake('\000')) goto retry;
if (!handshake('\160')) goto retry;
if (!handshake('\060')) goto retry;
send('\160');
send('\061');
for(i=0;i<TOTAL_SIZE;i++) {
while((high = Bconin(3)) & '\200');
while((low = Bconin(3)) & '\200');
voice[i] = (high << 4) + low;
}
send('\367');
#endif
}
/* write_voice: write voice 'voice' with name 'name' to the standard
library file */
write_voice(name, voice)
char name[], voice[];
{
int handle;
if (cur_voice >= VOICES) {
printf("At voice number limit [%d], to save current voice:\n\r",
VOICES);
printf(" (1) use 'quit' option to exit program.\n\r");
printf(" (2) rename file %s to any other name.\n\r",
VOICE_FILE);
printf(" (3) restart program and save voice.\n\r");
printf("Note: To access the voices stored in the old ");
printf("%s it must be renamed back\n\rto %s ", VOICE_FILE,
VOICE_FILE);
printf("and the current %s named something else ", VOICE_FILE);
printf("temporarily.\n\r");
printf("-- hit any key to continue --");
wait();
return;
}
if (cur_space < 94 + strlen(name))
error("Not enough free space on disk to store voice data");
handle = Fopen(VOICE_FILE, READ_WRITE);
if (handle < 0) {
sprintf(out, "Cannot open '%s'", VOICE_FILE);
error(out);
}
Fseek(0L, handle, 2);
if (Fwrite(handle, (long)(strlen(name) + 1), name) < 0)
error("Error while writing voice name to file");
cur_space -= strlen(name)+1;
if (Fwrite(handle, (long)TOTAL_SIZE, voice) < 0)
error("Error while writing voice data to file");
cur_space -= TOTAL_SIZE;
Fclose(handle);
if (cur_space < 80 + TOTAL_SIZE) {
warn(
"WARNING: there may not be enough space on the current disk for another voice");
}
if (cur_voice == VOICES-1) {
printf("WARNING: voice number limit of %d reached\n\r", VOICES);
printf("To save more voices:\n\r");
printf(" (1) use 'quit' option to exit program.\n\r");
printf(" (2) rename file %s to any other name.\n\r",
VOICE_FILE);
printf(" (3) restart program.\n\r");
printf("Note: To access the voices stored in the old ");
printf("%s it must be renamed back\n\rto %s ", VOICE_FILE,
VOICE_FILE);
printf("and the current %s named something else ", VOICE_FILE);
printf("temporarily.\n\r");
printf("-- hit any key to continue --");
wait();
}
}
/* scan_name: read a voice name from a file with handle 'handle' into 'name',
returning the success of the operation */
int
scan_name(handle, name)
int handle;
char name[];
{
if (Fread(handle, 1L, name) == 0) {
name[0] = '\0';
}
else do {
name++;
if (Fread(handle, 1L, name) == 0) {
warn("unexpected end-of-file in voice file -- check voices");
return(BAD);
}
} while(*name != '\0');
return(OK);
}
/* scan_voice: read a voice from a file with handle 'handle' into 'voice',
returning the success of the operation */
int
scan_voice(handle, voice)
int handle;
char voice[];
{
if (Fread(handle, (long)TOTAL_SIZE, voice) != TOTAL_SIZE) {
warn("Unexpected end-of-file in voice file -- check voices");
return(BAD);
}
return(OK);
}
/* error: print message 'message', wait, and terminate */
error(message)
char *message;
{
scr_func(CLEAR_SCR);
printf("%s\n\r", message);
printf("\n\r-- hit any key to exit --\n\r");
wait();
curses_cleanup();
exit();
}
/* warn: print message 'message', wait, and continue */
warn(message)
char *message;
{
printf("\n\r%s\n\r", message);
printf("-- hit any key to continue --\n\r");
wait();
}
/* midi_flush: flush the MIDI input buffer */
midi_flush()
{
while(Bconstat(3)) Bconin(3);
}
/* send: send the byte 'data' to MIDI out */
send(data)
char data;
{
while(!Bcostat(3));
Bconout(3, data);
}
/* mid: find the median of 'rolls' numbers between zero and 'range' */
mid(range, rolls)
int range, rolls;
{
int i, lowest, place, j;
int results[100];
for(i=0; i<rolls; i++)
results[i] = Random() % (range+1);
for(i=0; i<rolls/2; i++) {
lowest = range;
for(j=0;j<rolls;j++)
if(results[j] < lowest) {
lowest = results[j];
place = j;
}
results[place] = range;
}
lowest = range;
for(j=0;j<rolls;j++)
if(results[j] < lowest) {
lowest = results[j];
place = j;
}
return(lowest);
}
/* low: find the lowest of 'rolls' numbers in the range zero to 'range' */
low(range, rolls)
int range, rolls;
{
int i, lowest, roll;
lowest = range;
for(i=0; i<rolls; i++)
if ((roll = Random() % (range+1)) < lowest) lowest = roll;
return(lowest);
}
/* high: find the highest of 'rolls' numbers in the range zero to 'range' */
high(range, rolls)
int range, rolls;
{
int i, highest, roll;
highest = 0;
for(i=0; i<rolls; i++)
if ((roll = Random() % (range+1)) > highest) highest = roll;
return(highest);
}
/* initialize: initialize various tables and variables */
initialize()
{
int i, handle, slot;
if ((handle = Fopen("KEYTAB.DTA", READ)) < 0)
error("Cannot open 'KEYTAB.DTA'");
if (Fread(handle, 384L, key_tbl) < 384)
error("Read error on 'KEYTAB.DTA'");
Fclose(handle);
handle = Fopen(RANDOM_FILE, READ);
if (handle < 0)
error("Cannot open random weight file");
weirdness = 50;
for (i=0; i<VOICE_SIZE; i++) ranges[i] = get_int(handle);
for (i=0; i<VOICE_SIZE; i++) {
types[i][0] = get_int(handle);
types[i][1] = get_int(handle);
}
for (i=0; i<VOICE_SIZE; i++) {
tries[i][0] = get_int(handle);
tries[i][1] = get_int(handle);
}
Fclose(handle);
#ifdef CZ101
handle = Fopen("CZMIDI.DTA", READ);
if (handle < 0) error("Cannot open MIDI table file");
for (slot=0; slot<SLOTS; slot++) for(i=0; i<100; i++) {
if (Fread(handle, 1L, &table[slot][i]) < 1)
error("Unexpected EOF in 'CZMIDI.DTA'");
}
Fclose(handle);
#endif
}
/* get_int: read an integer from the file pointed to by 'handle',
ignoring non-numeric characters */
int
get_int(handle)
int handle;
{
char data;
int num, in_comment;
in_comment = FALSE;
do {
if (Fread(handle, 1L, &data) < 1) {
sprintf(out, "Unexpected EOF in '%s'", RANDOM_FILE);
error(out);
}
if (data == '*') in_comment = !in_comment;
} while(data < '0' || data > '9' || in_comment);
num = data - '0';
if (Fread(handle, 1L, &data) < 1) {
sprintf(out, "Unexpected EOF in '%s'", RANDOM_FILE);
error(out);
}
else if (data >= '0' && data <= '9')
num = 10*num + data - '0';
return(num);
}
/* get_num: read an integer from the keyboard and return it or an error code */
int
get_num()
{
int i, num, leng;
if ((leng = get_str(out)) < 0) return(ABORT);
else if (leng == 0) return(NULL);
num = 0;
for(i=0; i<leng; i++) {
if (out[i] < '0' || out[i] > '9')
return(BAD);
else
num = 10*num + out[i] - '0';
}
return(num);
}
/* handshake: wait for character 'verify' from the CZ101 */
handshake(verify)
char verify;
{
int received;
while(!Bconstat(3));
if ((received = (0x00FF & Bconin(3))) != (0x00FF & verify)) {
warn("Bad handshaking from synth - Make sure MIDI channel = 1");
sprintf(out, "Expecting %x but received %x", (int) verify,
received);
warn(out);
sprintf(out, "Next byte = %x", (0x00FF & Bconin(3)));
error(out);
return(FALSE);
}
return(TRUE);
}
/* show_weirdness: display the weirdness factor on the screen */
show_weirdness()
{
pos_cursor(40, 2);
scr_func(CLEAR_TO_EOL);
sprintf(out, "weirdness factor = 1 in %d", weirdness);
pos_cursor(80 - strlen(out), 2);
printf("%s", out);
}
/* show_voice: show the name and voice number of voice number 'voice'
on the screen */
show_voice(voice)
{
pos_cursor(77, 3);
if (voice < 0) printf("---");
else printf("%03d", voice);
pos_cursor(40, 4);
scr_func(CLEAR_TO_EOL);
if (voice < 0) {
pos_cursor(76, 4);
printf("NONE");
}
else if (voice == cur_voice) {
pos_cursor(74, 4);
printf("RANDOM");
}
else {
pos_cursor(max(78-strlen(v_names[voice]),40), 4);
printf("'%s'", v_names[voice]);
}
}
/* show_screen: if 'screen' equals MAIN, display the main menu,
otherwise display the edit menu */
show_screen(screen)
int screen;
{
scr_func(CLEAR_SCR);
if (screen == MAIN) {
printf("OPTIONS\n\r");
printf("-------\n\r");
printf("n = generate and load new voice\n\r");
printf("s = save currently loaded [and edited] voice\n\r");
printf("r = reload current voice\n\r");
printf("l = load previously saved voice\n\r");
printf("a = audition next voice in library\n\r");
printf("w = change weirdness factor\n\r");
printf("e = edit voice library\n\r");
printf("f = find voice by name\n\r");
printf("q = quit\n\r");
printf("\n\rOption? ");
show_weirdness();
sprintf(out, "current voice # ");
pos_cursor(80 - strlen(out), 3);
printf("%s", out);
show_voice(load_ptr);
}
else {
printf("EDIT OPTIONS\n\r");
printf("---- -------\n\r");
printf("c = change voice name\n\r");
printf("d = delete voice\n\r");
printf("D = delete range of voices\n\r");
printf("m = move voice\n\r");
printf("M = move range of voices\n\r");
printf("r = read in and append voices from alternate file\n\r");
printf("x = execute changes and return to main menu\n\r");
printf("q = quit edit menu, abandoning changes\n\r");
printf("\n\rOption? ");
}
}
/* list_voices: list the voice names and numbers available in the library */
list_voices()
{
int i,j;
pos_cursor(0,14);
scr_func(ERASE_TO_EOP);
for(i=0; i<cur_voice; i+=10){
for(j=0; j<10; j++) {
pos_cursor(0, 14+j);
scr_func(CLEAR_TO_EOL);
if (i+j < cur_voice)
printf("[%3d] %s", i+j, v_names[i+j]);
}
printf("\n\r -- hit any key to ");
printf("continue or ESC to ");
printf("quit listing --");
if ((char)Crawcin() == 27)
break;
}
pos_cursor(0,14);
scr_func(ERASE_TO_EOP);
}
/* edit: handle edit screen I/O and call appropiate subroutines */
edit()
{
int i, j, e_voice, e_max, leng, name_valid, changed, target;
int last_slash, main_drive, start, f_handle;
long drv_map;
char key, voice[TOTAL_SIZE], v_name[80];
char pfname[80], path[80], file[20], main_path[80];
changed = FALSE;
do {
pos_cursor(8, 3+EDIT_OPTIONS);
scr_func(ERASE_TO_EOP);
switch((int)(key = Crawcin())) {
case 'c':
case 'C':
printf("c\n\r");
e_voice = get_v_num(5+EDIT_OPTIONS);
if (e_voice == ABORT) break;
do {
do {
pos_cursor(0,6+EDIT_OPTIONS);
scr_func(CLEAR_TO_EOL);
printf("enter voice name: \007");
printf("\n\r[ESC to abort]");
pos_cursor(18, 6+EDIT_OPTIONS);
leng = get_str(v_name);
} while (leng == 0);
if (leng < 0) break;
name_valid = TRUE;
for(i=0; i<leng; i++)
if (v_name[i]<32 || v_name[i]>127) {
printf("\n\rName has invalid ");
printf("character in it - ");
printf("re-try");
name_valid = FALSE;
break;
}
if (name_valid)
for(i=0; i<cur_voice; i++) {
if(!strcmp(v_names[i],v_name))
{
printf("\n\rThere is al");
printf("ready a voice");
printf(" named '%s'",
v_name);
printf(" - re-try");
name_valid = FALSE;
break;
}
}
} while(name_valid == FALSE);
if (leng < 0) break;
#ifdef DX100
strncpy(voices[e_voice]+77, v_name, 10);
for(i=strlen(v_name); i<10; i++)
voices[e_voice][77+i] = ' ';
#endif
strcpy(v_names[e_voice], v_name);
changed = TRUE;
break;
case 'd':
case 'D':
printf("%c\n\r", key);
if (key == 'd')
printf("Delete voice...\n\r");
else
printf("Delete from voice...\n\r");
e_voice = get_v_num(6+EDIT_OPTIONS);
if (e_voice < 0) break;
if (key == 'D') {
printf("\n\r");
scr_func(CLEAR_TO_EOL);
printf("up through voice...\n\r");
do {
e_max = get_v_num(8+EDIT_OPTIONS);
if (e_max >= 0 && e_max < e_voice) {
sprintf( out,
"\n\rLast voice number must be greater than first voice number [%d]",
e_voice);
warn(out);
}
} while (e_max >= 0 && e_max < e_voice);
if (e_max < 0) break;
} else e_max = e_voice;
for (i = e_max+1; i < cur_voice; i++) {
strcpy(v_names[e_voice + i - (e_max+1)],
v_names[i]);
voice_copy(voices[e_voice + i - (e_max+1)],
voices[i]);
}
cur_voice -= e_max+1 - e_voice;
changed = TRUE;
break;
case 'm':
case 'M':
printf("%c\n\r", key);
if (key == 'm')
printf("Move voice...\n\r");
else
printf("First voice to move...\n\r");
e_voice = get_v_num(6+EDIT_OPTIONS);
if (e_voice < 0) break;
if (key == 'M') {
printf("\n\r");
scr_func(CLEAR_TO_EOL);
printf("up through voice...\n\r");
do {
e_max = get_v_num(8+EDIT_OPTIONS);
if (e_max >= 0 && e_max < e_voice) {
sprintf( out,
"\n\rLast voice number must be greater than first voice number [%d]",
e_voice);
warn(out);
}
} while (e_max >= 0 && e_max < e_voice);
if (e_max < 0) break;
} else e_max = e_voice;
do {
pos_cursor(0, 5+EDIT_OPTIONS);
scr_func(ERASE_TO_EOP);
if (e_max == e_voice)
printf("move voice %d in front of voice...",
e_voice);
else
printf("move voices %d to %d in front of voice...",
e_voice, e_max);
printf("\n\r(End of file is position %d)",
cur_voice);
strcpy(v_names[cur_voice++], "END OF FILE");
target = get_v_num(7+EDIT_OPTIONS);
cur_voice--;
if (target > cur_voice) {
sprintf(out,
"\n\r\n\rhighest legal position is %d",
cur_voice);
warn(out);
} else if (target > e_voice && target <= e_max){
printf(
"\n\r\n\rblock cannot be moved inside itself!");
sprintf(out,
"\n\rLegal ranges are from 0 to %d and from %d to %d",
e_voice, e_max+1, cur_voice);
warn(out);
}
} while (target > cur_voice ||
target > e_voice && target <= e_max);
if (target < 0) break;
printf("\n\rMoving voice(s)...");
for (i = e_voice; i < e_max+1; i++) {
if (target > e_max) {
strcpy(v_name, v_names[e_voice]);
voice_copy(voice, voices[e_voice]);
for (j = e_voice+1; j < target; j++) {
strcpy(v_names[j-1],v_names[j]);
voice_copy(voices[j-1],
voices[j]);
}
strcpy(v_names[target-1], v_name);
voice_copy(voices[target-1], voice);
} else {
strcpy(v_name, v_names[i]);
voice_copy(voice, voices[i]);
for (j = i-1; j >= target+i - e_voice;
j--) {
strcpy(v_names[j+1],v_names[j]);
voice_copy(voices[j+1],
voices[j]);
}
strcpy(v_names[target + i - e_voice],
v_name);
voice_copy(voices[target + i - e_voice],
voice);
}
}
changed = TRUE;
break;
case 'r':
printf("r\n\r");
Dgetpath(main_path, 0);
drv_map = Dsetdrv(main_drive = Dgetdrv());
do {
name_valid = !E_OK;
warn("Enter disk if necessary");
pos_cursor(0, 5+EDIT_OPTIONS);
scr_func(ERASE_TO_EOP);
printf("[Drive:] Path/File name: ");
printf("\n\r[ESC to abort]");
pos_cursor(25, 5+EDIT_OPTIONS);
if ((leng = get_str(pfname)) < 0) break;
printf("\n\r");
if (pfname[1] == ':') {
if (pfname[0] >= 'a'
&& pfname[0] <= 'z')
pfname[0] += 'A' - 'a';
if (pfname[0] < 'A' || pfname[0] > 'Z'){
warn("Bad drive; Drive letter must be in the range A-Z... re-try");
continue;
}
if (!((1L<<(pfname[0]-'A')) & drv_map)){
sprintf(out,
"Bad drive; Drive '%c' not installed... re-try",
pfname[0]);
warn(out);
continue;
}
Dsetdrv(pfname[0] - 'A');
strcpy(pfname, &pfname[2]);
}
if (pfname[0] == '\\') {
last_slash = 0;
for (i=1; i < leng; i++)
if (pfname[i] == '\\')
last_slash = i;
for (i=0; i<last_slash; i++)
path[i] = pfname[i];
path[last_slash] = '\0';
Dsetpath(path);
strcpy(file, &pfname[last_slash+1]);
}
else strcpy(file, pfname);
if ((name_valid = Fsfirst(file, 0)) != E_OK)
printf("'%s' not found, re-try...\n\r",
pfname);
else printf("'%s' found...", pfname);
} while (name_valid != E_OK);
if (leng < 0) break;
if ((f_handle = Fopen(file, READ)) < 0) {
sprintf(out,
"Cannot open '%s' for reading -- aborting...",
pfname);
warn(out);
break;
}
printf("reading in voice data\n\r");
while(TRUE) {
if (cur_voice+1 >= VOICES) {
sprintf(out,
"voices number limit reached (%d) -- file read aborted",
VOICES);
warn(out);
break;
}
if (scan_name(f_handle, v_names[cur_voice])
!= OK) break;
if (strlen(v_names[cur_voice]) > 0) {
if (scan_voice(f_handle,
voices[cur_voice]) != OK) break;
cur_voice++;
}
else break;
}
Fclose(f_handle);
changed = TRUE;
warn("Re-insert original disk if necessary");
Dsetdrv(main_drive);
Dsetpath(main_path);
break;
case 'x':
case 'X':
printf("x\n\r");
if (changed && save_edit() < 0) break;
else key = 'q';
break;
case 'q':
case 'Q':
printf("q\n\r");
if (!changed) break;
printf("Restoring library to pre-edit state from disk\n\r");
get_voices(v_names, voices);
break;
default:
printf("\007");
printf("Bad option '%c' - re-try", key);
break;
}
} while (key != 'q' && key != 'Q');
}
/* save_edit: save the edited voice library, returning a success/failure code */
int
save_edit()
{
long needed_space, lib_size(), *fsize;
unsigned char response;
needed_space = lib_size();
while (Fsfirst(VOICE_FILE, 0) != E_OK) {
printf("'%s' not found.\n\r", VOICE_FILE);
warn("Please insert voice disk.");
}
fsize = Fgetdta() + 26;
if (*fsize + cur_space >= needed_space) {
return(dump_voices());
}
else {
do {
printf("\n\rNot enough room on disk to save ");
printf("file\n\rDo you have a formatted disk ");
printf("with at least %ld free bytes \n\r",
needed_space);
printf("\tavailable to insert (y/n)? ");
if ((response = Crawcin()) == 'y') {
printf("y\n\r");
warn("Insert disk");
check_disk();
if (Fsfirst(VOICE_FILE, 0) == E_OK) {
fsize = Fgetdta() + 26;
} else {
fsize = Fgetdta() + 26;
*fsize = 0;
}
if (cur_space + *fsize > needed_space) {
return(dump_voices());
break;
}
} else {
printf("n\n\r");
printf("Aborting save...\n\r");
printf("It is recommended that you ");
printf("quit out of this program and ");
printf("\n\rcreate enough space on a ");
printf("disk to save the file as ");
printf("desired\n\r");
printf("Hit any key to continue...");
wait();
break;
}
} while ((response = Crawcin()) == 'y');
}
}
/* lib_size: return the size of the voice library (in bytes) */
long
lib_size()
{
int i;
long size;
for (i=0, size=0; i < cur_voice; i++) {
size += strlen(v_names[i]) + 1;
size += TOTAL_SIZE;
}
return(size);
}
/* search: search the voice library names for a match with 's_str', handling
special cases in 's_str', starting from voice 'from' */
int
search(s_str, from)
char *s_str;
int from;
{
int found, target_len;
char ps_str[80], rs_str[80], ss_str[80], srs_str[80];
if (extract(s_str, ps_str, rs_str) == NULL) return(from);
for (found=from; found < cur_voice; found++) {
if (substr(v_names[found], ps_str)) {
strcpy(srs_str, rs_str);
do {
if (extract(srs_str, ss_str, srs_str) == NULL)
return(found);
} while (substr(v_names[found], ss_str));
}
}
return(found);
}
/* extract: break string 'raw_str' into an initial search string ('fs_str')
and a remnant string ('rs_str') returning NULL if 'raw_str' is empty,
!NULL otherwise */
int
extract(raw_str, fs_str, rs_str)
char *raw_str, *fs_str, *rs_str;
{
if (*raw_str == '\0') return(NULL);
if (*raw_str == AND_CHAR) *raw_str++;
while (*raw_str != '\0' && *raw_str != AND_CHAR)
*fs_str++ = *raw_str++;
*fs_str = '\0';
while ((*rs_str++ = *raw_str++) != '\0');
return(!NULL);
}
/* substr: determine if pattern 'pattern' exists in string 'field',
returning TRUE if so, FALSE otherwise */
int
substr(field, pattern)
char *field, *pattern;
{
int i, reps, leng;
if ((leng = strlen(pattern)) == 0) return(TRUE);
reps = strlen(field) - leng;
for (i=0; i <= reps; i++)
if (!strncmp(field+i, pattern, leng)) return(TRUE);
return(FALSE);
}
/* check_disk: determine free space on disk */
check_disk()
{
struct { long free_c, tot_c, sec_siz, sec_in_c; } disk_info;
printf("checking disk usage\n\r");
Dfree(&disk_info, 0);
cur_space = disk_info.free_c * disk_info.sec_in_c * disk_info.sec_siz;
}
/* dump_voices: actually write the voice library to disk, an error *should*
not be possible at this point. Nonetheless, a success/failure code
is returned */
int
dump_voices()
{
int f_handle, i;
long f_start_leng, offset, incr;
char response;
if (Fsfirst(VOICE_FILE, 0) != E_OK) f_start_leng = 0;
else {
f_start_leng = *(long *)(Fgetdta() + 26);
Fdelete(VOICE_FILE);
printf("'%s' deleted\n\r", VOICE_FILE);
}
do {
if ((f_handle = Fcreate(VOICE_FILE, 0)) < 0) {
printf("Cannot create voice file.\n\r");
printf("Ensure disk is inserted and ");
printf("not write protected.\n\r");
printf("Re-try (y/n)? ");
if ((response = Crawcin()) == 'y') {
printf("y\n\r");
continue;
} else {
printf("n\n\r");
sprintf(out,
"'%s' deleted/not found and current voices NOT saved!",
VOICE_FILE);
warn(out);
return(BAD);
}
} else {
printf("'%s' created.\n\r", VOICE_FILE);
Fclose(f_handle);
}
} while (f_handle < 0);
f_handle = Fopen(VOICE_FILE, READ_WRITE);
if (f_handle < 0) {
sprintf(out, "Cannot open '%s' -- Aborting save", VOICE_FILE);
warn(out);
return(BAD);
}
printf("'%s' opened for reading/writing...\n\r", VOICE_FILE);
pos_cursor(0, 24);
printf("Saving voice number ");
for (i = 0, offset = 0; i < cur_voice; i++) {
pos_cursor(20, 24);
scr_func(CLEAR_TO_EOL);
printf("%d", i);
incr = strlen(v_names[i]) + 1;
if (Fwrite(f_handle, incr, v_names[i]) < incr)
error("Unknown write error on voice file - bye!");
offset += incr;
if (Fwrite(f_handle, (long) TOTAL_SIZE, voices[i]) < 0)
error("Unknown write error on voice file - bye!");
offset += TOTAL_SIZE;
}
cur_space += f_start_leng;
cur_space -= offset;
Fclose(f_handle);
return(OK);
}
/* get_v_num: interact with the user to get a voice number and return it
(putting prompts at screen line 'curs_y') */
int
get_v_num(curs_y)
int curs_y;
{
int v_num;
do {
pos_cursor(0,curs_y);
scr_func(CLEAR_TO_EOL);
printf("enter voice number: \n\r");
printf("[ESC to abort, RETURN to list, voices 0-%d available]",
cur_voice-1);
pos_cursor(20, curs_y);
if ((v_num = get_num()) == NULL)
list_voices();
if (v_num == BAD)
printf("\n\r\n\rBad input - re-try");
} while (v_num != ABORT &&
(v_num < 0 || v_num >= cur_voice));
return(v_num);
}
/* func: call the appropiate voice parameter determining function and
return its value */
int
func(i,b)
int i,b;
{
switch(types[i][b]) {
case 1:
return(high(ranges[i], tries[i][b]));
break;
case 2:
return(mid(ranges[i], tries[i][b]));
break;
case 3:
default:
return(low(ranges[i], tries[i][b]));
break;
}
}
/* get_roll: determine whether func should be called with a normal or
weird value and return what func returns */
int
get_roll(a)
int a;
{
if (Effect) return(func(a,0));
else return(func(a,1));
}
/* voice_copy: copy voice 'v2' into voice 'v1' */
voice_copy(v1, v2)
char *v1, *v2;
{
int i;
for (i=0; i<TOTAL_SIZE; i++) *v1++ = *v2++;
}
#ifdef DX100
/* round: return the nearest integral frequency ratio to ratio 'freq' */
int
round(freq)
int freq;
{
if (freq < 2) return(0);
if (freq < 6) return(4);
if (freq < 9) return(8);
if (freq < 12) return(10);
if (freq < 15) return(13);
if (freq < 18) return(16);
if (freq < 21) return(19);
if (freq < 24) return(22);
if (freq < 27) return(25);
if (freq < 30) return(28);
if (freq < 33) return(31);
if (freq < 36) return(34);
if (freq < 38) return(36);
if (freq < 41) return(40);
if (freq < 45) return(42);
if (freq < 64) return(45);
return(4);
}
#endif
ə