
/*********************	   DUNGEON.MM		   **************************/
/* slave ("internal service") function code */


/****** "Show" group - displays data or status *******/ 
  /** Called by many other functions - should have no effects */

show_board()	       /* display the current patchboard setup */
{int scan, slot;
 slot = 0; 
 fputs("\n   Current patchboard configuration:\n",stdout);
 fputs("Unit#  Slot#  Label                 Input               Output\n", 
       stdout); 
 for(scan = 0; scan < MAXFUNCS; scan++)
    {fprintf(stdout," %3d    %3d   %-20s  %-20s  %-20s\n",scan,slot,
	     board[slot].whatsit,tracks[board[slot].in].tlabel,
	     tracks[board[slot].out].tlabel);
     slot = board[slot].next;
     if(!slot) return(0);
     }
 }  /* End show_board */

/************** 		    ****************/
disp_patch(slot)    /* show board[] unit status */
int slot;
{struct knob_space *kptr;  /* pointer to knobs of unit */
 fprintf(stdout,"\nSlot %d: %s      ",slot,board[slot].whatsit);
 if(board[slot].active)
   fputs("Now active\n",stdout);
  else fputs("Deactivated\n",stdout);
 fprintf(stdout,"Input is track %d (%s);  Output is track %d (%s)\n",
	 board[slot].in, tracks[board[slot].in].tlabel,
	 board[slot].out, tracks[board[slot].out].tlabel);
 /* set pointer to start of knobs data space for unit */
 kptr = board[slot].knobs;
 if(kptr == NULL)
   {fputs("No knobs on this unit\n",stdout);
    return(0);
    }
 /* show knob parameter names and data values */
 for(slot = 0;slot < MAXPARAMS;slot++)
    if(bag[kptr->type].set[slot][0])	/* param has a name */
      fprintf(stdout,"%s:  %d\n",bag[kptr->type].set[slot],kptr->value[slot]);
 return(0);
 }  /* End disp_patch */

/************** 		    ****************/
show_patch()	  /* called by "show" menu, calls disp_patch */
{int slot;
 show_board();
 fputs("Show knob values for slot# ",stdout);
 getnum(&slot);
 disp_patch(slot);
 return(0);
 }  /* End show_patch */

/************** 		    ****************/
show_tdata()
{int tnum, snum, cnt;
 uchar *creeper;
 long ftell(), oldpos;

 show_tracks();
 fputs("Show data bytes for track: ",stdout);
 getnum(&tnum);
 fputs("\nHow many bytes (from start): ",stdout);
 getnum(&snum);
 if(!snum)  return(0);
 if(tracks[tnum].media == 1)  /* it's on a disk file */
 {oldpos = ftell(tracks[tnum].tloc);  /* save current file position */ 
  fseek(tracks[tnum].tloc,0L,0);      /* rewind to start byte */ 
  for(cnt = 0; snum--; cnt++)
    {if(!(cnt % 20))  fputc('\n',stdout);
     fprintf(stdout,"%2x ",fgetc(tracks[tnum].tloc));
     }
  fseek(tracks[tnum].tloc,oldpos,0);  /* reset file to prev position */ 
  } 
 else  /* assume it's a RAM track */ 
 {creeper = tracks[tnum].tloc;	  /* set start address */
  for(cnt = 0; snum--; creeper++, cnt++)
     {if(!(cnt % 20))  fputc('\n',stdout);
      fprintf(stdout,"%2x ",*creeper);
      }
  } 
 fputc('\n',stdout);
 return(0);
 }  /* End show_tdata */

/************** 		    ****************/

show_bag()	    /* display list of available functions */
{int scan;
 for(scan = 1; scan < MAXBAG; scan++)
    {if(!bag[scan].geek[0]) continue;  /* skip empty entries */
     fprintf(stdout,"Unit %3d  %-20s   Needs %u bytes knob space.\n",scan,
	     bag[scan].geek, bag[scan].ksize);
     }
 fputc('\n',stdout);
 return(0);
 }  /* End show_bag */

/************** 		    ****************/

show_tracks()	/* display allocated track storage areas */
{int scan;
 for(scan = 0; scan < MAXHEADROOM; scan++)
    {if(!tracks[scan].tlabel[0]) continue;  /* skip empty entries */
     fprintf(stdout,"\nTrack %3d:  %-20s -> %u bytes, %u filled.",scan,
     tracks[scan].tlabel,tracks[scan].tsize,tracks[scan].tcount);
     }
 fputc('\n',stdout);
 return(0);
 }  /* End show_tracks */


/****** Data track management group, RAM or disk  ******/

add_track()    /* allocate a new track storage area - add to tracks[] array */
{unsigned int coreleft(), cl, space;
 uchar *alloc();
 int slot = 0;

 /* find a free slot in the tracks array */
 while(slot < MAXHEADROOM)
      {if(!tracks[slot].tlabel[0])  break;
       slot++;
       }
 if(slot == MAXHEADROOM)
   {fputs("\nYour track array is full.\n",stdout);
    return(0);	/* give up immediately */
    }

 /* determine and allocate space */
 cl = coreleft();    /* find free RAM, allow 1000 bytes safety */
 if(cl < 1000) {fputs("\nNot enough memory left.\n",stdout); return(0); }
 fprintf(stdout,"\n%u bytes are available.",cl);
 fputs("\nHow many bytes are needed for this track: ",stdout);
 getnum(&space);
 if(cl < space) 
   {fputs("\nWe ain't got that much.\n",stdout);
    return(0);	  /* give up - have to remove something */
    }
 tracks[slot].tloc = alloc(space);
 tracks[slot].tsize = space;
 tracks[slot].tcount = 0;
 tracks[slot].media = 0;   /* set RAM track flag value */
 fputs("\nLabel for this track: ",stdout);
 gets(tracks[slot].tlabel,20,stdin);

 fputs("\nTrack allocated and ready.  Resuming run...\n",stdout);
 return(0);
 }  /* End add_track */

/************** 		    ****************/

add_disk_track()    /* open a disk file and make it a track */
{long ftell();
 uchar *fopen();
 int slot = 0;

 /* find a free slot in the tracks array */
 while(slot < MAXHEADROOM)
      {if(!tracks[slot].tlabel[0])  break;
       slot++;
       }
 if(slot == MAXHEADROOM)
   {fputs("\nYour track array is full.\n",stdout);
    return(0);	/* give up immediately */
    }

 fputs("\nFile name for this track: ",stdout);
 gets(tracks[slot].tlabel,20,stdin);
 /* create disk file if not existing, position at end for update */
 tracks[slot].tloc = fopen(tracks[slot].tlabel,"arb");
 if(tracks[slot].tloc == NULL)
   {fputs("\nCan't open the file for some reason\n",stdout);
    tracks[slot].tlabel[0] = 0;  /* kill name entry */
    return(0);
    }
 tracks[slot].media = 1;  /* set flag for disk file track */
 /* set size and count to EOF byte position */ 
 tracks[slot].tcount = tracks[slot].tsize = ftell(tracks[slot].tloc);
 tracks[slot].tsize = tracks[slot].tcount ? tracks[slot].tcount : 0xFFFF;
 fseek(tracks[slot].tloc,0L,0); /* rewind to start of file per convention */ 

 fputs("\nDisk track allocated and ready.  Resuming run...\n",stdout);
 return(0);
 }  /* End add_disk_track */

/************** 	     ****************/
close_disk_track()    /* close a disk file, remove from tracks[] */
{int tr;
 show_tracks();
 fputs("Remove track #",stdout);
 getnum(&tr);
 if(tr > MPU_IN) {fputs("\nCan't touch them, boss\n",stdout); return(0);}
 if(tracks[tr].media != 1) {fputs("\nDat ain't no disky file!\n"); return(0);}
 fclose(tracks[tr].tloc);     /* close disk file */
 tracks[tr].tsize = tracks[tr].tcount = 0;  /* reset counters */
 fprintf(stdout,"\n%s closed\n",tracks[tr].tlabel);
 tracks[tr].tlabel[0] = 0;  /* null out name string */
 return(0);
 }  /* End close_disk_track */

/************** 	     ****************/
remove_track()	 /* remove an allocated track, free its space */
{int tr;
 show_tracks();
 fputs("Remove track #",stdout);
 getnum(&tr);
 if(tr <= MPU_COND_OUT)   /* protected MPU tracks */
   {fputs("\nCan't touch them, boss\n",stdout); return(0);}
 if(tracks[tr].media != 0) {fputs("\nDat ain't no RAM track!\n"); return(0);}
 free(tracks[tr].tloc);     /* free allocated space */
 tracks[tr].tsize = tracks[tr].tcount = 0;  /* reset counters */
 fprintf(stdout,"\n%s removed\n",tracks[tr].tlabel);
 tracks[tr].tlabel[0] = 0;  /* null out name string */
 return(0);
 }  /* End remove_track */


/***** Functions to add and remove MIDI functions to board[] ******/

add_unit()	/* add a function from bag[] to board[] for run */
{unsigned int coreleft(), cl;
 struct knob_space *knob;
 uchar *alloc();
 int slot, unit, io;
 /* find a free slot in the board[] */
 for(slot = 0;slot < MAXFUNCS;slot++)
      {if(!board[slot].whatsit[0])  break;
       }
 if(slot == MAXFUNCS) fputs("\nSorry - no more slots\n",stdout);
 /* pick a function from the bag[] */
 show_bag();
 fputs("\nPick one, or 0 to cancel: ",stdout);
 getnum(&unit);
 if(!unit)  return(0);	  /* user quit here */
 if((cl = coreleft()) < (bag[unit].ksize + 1000))
   {fprintf("\nCan't allocate knob space... only %u bytes left\n",cl);
    return(0);
    }
 /* allocate the RAM for the knobs space, set knob to point at start */
 knob = board[slot].knobs = alloc(bag[unit].ksize);
 board[slot].funky = bag[unit].finger;	 /* set function pointer */
 fprintf(stdout,"\nUnit type is %s\nWhat label for the board slot? ",
	 bag[unit].geek);
 gets(board[slot].whatsit,20,stdin);
 if(!board[slot].whatsit[0])  /* no input - default to basic name */
   strncpy(board[slot].whatsit,bag[unit].geek,19);
 /* start filling knob data space with values */
 knob->slot = slot;		  /* index back to board[] */
 knob->type = unit;		  /* index back to bag[] */
 /* pick input and output data spaces - tracks[] */
 show_tracks();
 fputs("\nTake input from track ",stdout);
 getnum(&io);
 knob->inctr = &tracks[io].tcount;   /* ptr to track counter */
 knob->input = tracks[io].tloc;      /* start of data track */ 
 knob->endin = knob->input + tracks[io].tsize - 1;   /* last byte in track */
 board[slot].in = io;  /* index to tracks[] for i/o name displays */
 fputs("\nSend output to track ",stdout);
 getnum(&io);
 knob->outctr = &tracks[io].tcount;
 knob->output = tracks[io].tloc;
 knob->endout = knob->output + tracks[io].tsize - 1;
 board[slot].out = io;	/* index to tracks[] for i/o name displays */
 /* show names of other parameters, fill knobs with values */
 for(io = 0;io < MAXPARAMS;io++)
    {if(!bag[unit].set[io][0])
       {knob->value[io] = 0;   /* no parameter, set to 0 */
	}
     else
       {fputc('\n',stdout);
	fputs(bag[unit].set[io],stdout);  /* show param name */
	getnum(&knob->value[io]);	  /* allow +- values */
	} 
      }

 /* link new unit into board[] to run after given unit */
 show_board();
 fputs("\nRun this one after slot #",stdout);
 getnum(&io);
 board[slot].next = board[io].next;
 board[io].next = slot;

 fputs("\nNew unit added.  Resuming run.\n",stdout);
 board[slot].active = 1;  /* make active, run on next loop through board[] */
 return(0);
 }  /* End add_unit */

/************** 		    ****************/
remove_unit()	/* remove a unit from the board[] run array */
{int unit;   /* index to board[] function */
 int scan;
 
 show_board();
 fputs("Remove slot #",stdout);
 getnum(&unit);

 for(scan = 0;scan < MAXFUNCS;scan++)
    {if(board[scan].next == unit)  break;
     }
 if(scan == MAXFUNCS)
   {fprintf(stdout,"\nCan't find link to slot %d\n",unit);
    return(-1);
    }
 board[scan].next = board[unit].next;	/* relink board to skip this unit */
 board[unit].next = 0;
 free(board[unit].knobs);	/* release knob data space */
 fprintf(stdout,"\n%s removed\n",board[unit].whatsit);
 board[unit].whatsit[0] = 0;   /* null out name */
 free(board[unit].knobs);      /* free knob data space */
 return(0);
 }  /* End remove(unit) */


/****** Program termination (called by F10 now) ****************/
die()	 /* end it all */
{int trk;
 /* close all remaining disk file tracks first */
 for(trk = 0;trk < MAXHEADROOM;trk++)
    if(tracks[trk].tlabel[0] && (tracks[trk].media == 1))
      fclose(tracks[trk].tloc);

/****** IF YOUR VERSION OF C HAS THE INTERREST() FUNCTION TO RESTORE AN 
	INTERRUPT, REMOVE THIS COMMENT AND RECOMPILE.
	  AS IT IS NOW, THE .EXE VERSION DOES NOT RESTORE THE HARDWARE
	INTERRUPT, SO RE-BOOT YOUR CPU WHEN YOU EXIT.  THE FOLLOWING
	FUNCTION FROM HENDERSHOTT'S MPUISR.C WILL RESTORE THE INT, BUT I
	CAN'T COMPILE IT WITH C86 V2.1.  

 deinit_handler();  /* restore the hardware interrupt used by the MPU-401 */

************* END OF SNAFU  **/

 fputs("WARNING: This version does not reset the system interrupts.\n",stdout);
 fputs("Re-boot your system before running anything else.\n\n",stdout);

 exit(0);
 }  /* End of the world */
