#include /* * 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; i127) { 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 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 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> 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> 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> 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= 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 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 '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 '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; i127) { printf("\n\rName has invalid "); printf("character in it - "); printf("re-try"); name_valid = FALSE; break; } if (name_valid) for(i=0; i= 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= 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