home *** CD-ROM | disk | FTP | other *** search
- /* TX.C
-
- (c) 1987 Todor Fay
-
- */
-
- #include "exec/types.h"
- #include "exec/exec.h"
- #include "hardware/custom.h"
- #include "hardware/cia.h"
- #include "exec/interrupts.h"
- #include "exec/memory.h"
- #include "hardware/intbits.h"
- #include "libraries/dos.h"
- #include "intuition/intuition.h"
- #include "soundscape.h"
-
- extern struct CIA ciaa;
- extern struct Custom custom;
-
- /* The state structure for this module has just the
- file name for saving a TX81Z (or DX21/27/100) voice.
- Whenever an environment save command (SAVESTATE)
- occurs, the file that the voice was saved in is
- returned here. When an environment load command
- (LOADSTATE) happens, the file that is given here
- will be loaded by this module.
- */
-
- struct SynthState {
- long length;
- char filename[70];
- };
-
- /* Initialise the file name as empty. */
-
- static struct SynthState synthstate = { 70,0, };
-
- /* The port id for this port. */
-
- static short thisport;
-
- /* The icon in the Patch Panel. */
-
- UWORD tx81zdata[] = { /* 32 x 12 */
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 8078, 32752,
- 12486, 448,
- 8070, 1792,
- 12486, 7168,
- 8079, 32752,
- 16383, 57344,
- 224, 0,
- 231, 28672,
- 227, 57344,
- 225, 49152,
- 227, 57344,
- 231, 28672,
- 0, 32752,
- 0, 448,
- 0, 1792,
- 0, 7168,
- 0, 32752,
- };
-
- struct Image tx81zimage = { 0,0,32,12,2,tx81zdata,3,0,0 };
-
- /* We need to be able to display messages to the user.
- For example, "Sending the voice...". Two
- routines handle this. Onmessage opens a window
- and displays the given strings. Offmessage
- closes that window. Here is the window declaration.
- */
-
- struct NewWindow NewWindowStructure = {
- 134,35,
- 336,66,
- 0,1,
- NULL,
- ACTIVATE,
- NULL,
- NULL,
- "TX81Z/DX21/DX27/DX100 Librarian",
- NULL,
- NULL,
- 5,5,
- 640,200,
- WBENCHSCREEN
- };
-
- struct Window *messagewindow = 0;
-
- void onmessage(string1,string2)
-
- /* Opens a window and prints the message.
- Window is closed by offmessage().
- */
-
- char string1[], string2[];
-
- {
- static struct IntuiText text = { 2,0,JAM2,0,0,0,0, };
- messagewindow = (struct Window *)
- OpenWindow(&NewWindowStructure);
- if (messagewindow) {
- text.IText = string1;
- PrintIText(messagewindow->RPort,&text,20,20);
- if (string2) {
- text.IText = string2;
- PrintIText(messagewindow->RPort,&text,20,30);
- }
- }
- }
-
- void offmessage()
-
- /* This just closes messagewindow if it is open. */
-
- {
- if (messagewindow) {
- CloseWindow(messagewindow);
- }
- messagewindow = 0;
- }
-
-
- opencode(direction)
-
- /* Routine to open this modules's port in the
- direction specified. Always return TRUE
- for success.
- */
-
- char direction;
-
- {
- return(1);
- }
-
-
- closecode(direction)
-
- /* Always close successfully. */
-
- char direction;
-
- {
- return(1);
- }
-
-
- unsigned long processbyte(buffer,maxlength,midiindata)
-
- /* When a data byte comes in, this routine is
- called to process it. Buffer is a pointer
- to an array to store the data in. Maxlength
- is the size of that array. Midiindata is
- the data byte that just came in.
-
- The static variable sysexon keeps track of
- whether we are currently reading a system
- exclusive packet. It is initialised to
- FALSE (0). When a System Exclusive status
- byte comes in, sysexon is set. When the
- end of the packet is reached, sysexon is
- turned off again.
-
- The static variable length keeps track of
- where we are in the array. It is not
- allowed to become greater than maxlength.
-
- Return 0 if still reading or about to
- read the packet. Return the length when
- the packet end has been reached.
- */
-
- register unsigned char *buffer;
- register unsigned long maxlength;
- register unsigned char midiindata;
-
- {
- static unsigned long length;
- static char sysexon = 0;
- /* Is this a status byte? */
- if (midiindata & 0x80) {
- /* MIDI real time event? */
- if (midiindata >= CLOCK) {
- return(0);
- }
- /* End of packet? */
- else if (sysexon) {
- sysexon = 0;
- buffer[length++] = midiindata;
- return(length);
- }
- /* Start of packet? */
- else if (midiindata == SYSTEMX) {
- sysexon = 1;
- length = 1;
- *buffer = SYSTEMX;
- }
- }
- /* Read data. */
- else if (sysexon) {
- if (length < maxlength) {
- buffer[length++] = midiindata;
- }
- }
- return(0);
- }
-
-
- unsigned long ReceiveSysEx(buffer,maxlength)
-
- /* To receive a system exclusive buffer,
- disable interrupts and poll the serial
- port and mouse button. Whenever a data
- byte comes in, pass it to the processbyte
- routine, which deals with is appropriately.
- Once the packet is in, return the length.
- */
-
- register char *buffer;
- register unsigned long maxlength;
-
- {
- register unsigned char c;
- unsigned long length = 0;
- Disable();
- for (;;) {
- while (!(custom.serdatr & 0x4000)) {
- if ((~ciaa.ciapra) & 0xC0) {
- Enable();
- return(0);
- }
- }
- c = (unsigned char) custom.serdatr;
- custom.intreq = INTF_RBF;
- if (length = processbyte(buffer,maxlength,c))
- break;
- }
- Enable();
- return(length);
- }
-
-
- void SendSysEx(buffer,length)
-
- /* First, set the priority of this task to
- higher than the SoundScape packet router
- so there is no danger of SoundScape sending
- a MIDI packet at the same time.
-
- Then, send all the bytes in the buffer,
- polling the buffer empty bit before
- sending each byte.
-
- When done, bring the priority back down.
- */
-
- register char *buffer;
- register unsigned long length;
-
- {
- register long oldpri = SetTaskPri(FindTask(0),21);
- register unsigned long i;
- for (i=0; i<length; i++) {
- while (!(custom.serdatr & 0x2000));
- custom.serdat = buffer[i] | 0x300;
- }
- SetTaskPri(FindTask(0),oldpri);
- }
-
-
- void dosomething(direction,filename)
-
- /* This routine is called to either read
- a voice from disk and send it
- to the synth, or read a voice from
- the synth and store it to disk.
-
- Direction is set if we are to
- store a sound to disk, otherwise cleared.
-
- A filename may be given (the case for
- environment loads and saves.) If
- so, the variable filename will have
- that file name in it. If there is
- no filename (filename[0] == 0),
- put up a requester with a call to
- ReadFileName or WriteFileName.
-
- If saving a voice to disk, first
- send a dump request to the synth.
- Then read the system exclusive packet
- that comes back. There is a danger
- that no synth is hooked up, or the
- wrong data is returned. If this happens,
- the length of the data returned will not
- be 101, so don't save it to file.
-
- If sending a new voice, just read
- it from file and send the data.
- */
-
- char direction;
- register char filename[];
-
- {
- register long buffer;
- register long file;
- static unsigned char dumprequest[] = { 0xF0,0x43,0x20,0x03,0xF7};
- long length;
- buffer = AllocMem(200,MEMF_PUBLIC);
- if (buffer) {
- if (direction) {
- if (!filename[0])
- WriteFileName(filename,"TX81Z/DX Voice","tx81zvoice");
- if (filename[0]) {
- onmessage("Getting a Voice... ",
- "Click mouse to abort");
- SendSysEx(dumprequest,5);
- length = ReceiveSysEx(buffer,200);
- offmessage();
- if (length == 101) {
- file = Open(filename,MODE_NEWFILE);
- if (file) {
- Write(file,&length,4);
- Write(file,buffer,length);
- Close(file);
- }
- }
- }
- }
- else {
- if (!filename[0])
- ReadFileName(filename,"TX81Z/DX Voice","tx81zvoice");
- if (filename[0]) {
- file = Open(filename,MODE_OLDFILE);
- if (file) {
- Read(file,&length,4);
- if (length == 101) {
- Read(file,buffer,length);
- Close(file);
- onmessage("Sending the Voice... ",0);
- SendSysEx(buffer,length);
- offmessage();
- }
- }
- }
- }
- FreeMem(buffer,200);
- }
- }
-
-
- void editcode(direction,command,buffer)
-
- /* This, the edit routine, is called under
- five circumstances:
-
- USEREDIT:
- The user clicked on either the left or right
- icon in the patch panel. Which icon is
- determined by the variable direction. Clear
- the SynthState filename field so there is no
- current filename and make a FunctionCall to
- dosomething(direction,synthstate.filename)
- which will either load a sound or save
- one.
-
- SETSTATE:
- This occurs when another module wishes to
- change the data in this module's state
- structure. Simply copy the passed buffer
- into synthstate.
-
- GETSTATE:
- Another module wishes to read the contents
- of this module's state structure. Simply
- copy synthstate into the passed buffer.
-
- LOADSTATE:
- Another module asks this module to load
- files. This ususally occurs in the
- context of an environment load. Once again,
- a buffer is passed and the data from it
- is copied into synthstate. This should have the
- name of the file to read and send to the
- TX81Z.
-
- SAVESTATE:
- Another module asks this module to save
- files. This usually occurs in the
- context of an environment save. This
- time, we get the sound from the TX81Z and
- save it to disk, then return the file name,
- so that can be stored in the environment
- file.
- */
-
- char direction, command;
- struct SynthState *buffer;
-
- {
- switch (command) {
- case USEREDIT :
- synthstate.filename[0] = 0;
- FunctionCall(dosomething,direction,synthstate.filename);
- break;
- case SETSTATE :
- movmem(buffer,&synthstate,sizeof(synthstate));
- break;
- case GETSTATE :
- movmem(&synthstate,buffer,sizeof(synthstate));
- break;
- case LOADSTATE :
- movmem(buffer,&synthstate,sizeof(synthstate));
- FunctionCall(dosomething,0,synthstate.filename);
- movmem(&synthstate,buffer,sizeof(synthstate));
- break;
- case SAVESTATE :
- FunctionCall(dosomething,1,synthstate.filename);
- movmem(&synthstate,buffer,sizeof(synthstate));
- break;
- }
- buffer->length = 70;
- }
-
- long SoundScapeBase, IntuitionBase, GfxBase;
-
- /* Here's the main program. As always with a
- SoundScape module, open the SoundScape library
- to get a handle on the routines, then close
- it so it can be eventually closed by the
- program that opened it initially.
- Create a midi port in the patch panel and
- wait for it to be closed, then leave.
- */
-
- void main() {
- IntuitionBase = OpenLibrary("intuition.library",0);
- GfxBase = OpenLibrary("graphics.library",0);
- SoundScapeBase = OpenLibrary("soundscape.library",0);
- if (SoundScapeBase) {
- CloseLibrary(SoundScapeBase);
- thisport = AddMidiPort(opencode,closecode,editcode,0,
- &tx81zimage,&tx81zimage,-1,"tx81z");
- SetTaskPri(FindTask(0),-20);
- while (MidiPort(thisport)) Delay(100);
- }
- CloseLibrary(IntuitionBase);
- CloseLibrary(GfxBase);
- }
-