home *** CD-ROM | disk | FTP | other *** search
- /* casio - download sample data from a casio fz-1 */
-
- /* Copyright (C) 1988 Hackercorp. All Rights Reserved */
-
- #include <libraries/dos.h>
- #include <clib/macros.h>
- #include <midi/midi.h>
- #include <functions.h>
- #include <stdio.h>
- #include <devices/timer.h>
-
- #include "casio.h"
- #include "prototypes.h"
-
- char *program_name = "casio fz1 download program";
-
- #define CheckMsg(m) (m->mp_MsgList.lh_Head->ln_Succ != 0)
-
- extern struct timerequest *timer_request;
-
- /* message ids for fz-1 system exclusive messages */
- #define OPEN_MIDI_MSG 0x70
- #define CLOSE_MIDI_MSG 0x71
- #define OK_MIDI_MSG 0x72
- #define ERR_MIDI_MSG 0x73
- #define DATA_MIDI_MSG 0x74
- #define EFFECT_MIDI_MSG 0x76
- #define REMOTE_MIDI_MSG 0x7f
-
- /* additional messages I define as responses from its_an_fz1_message */
- #define NOT_A_FZ_MESSAGE 0
- #define NOT_THE_REQUESTED_FZ_CHANNEL 1
- #define DATA_ERROR 2
-
- /* states for the i/o loop */
- #define WAITING_FOR_OPEN 0
- #define READING_FZ_DATA 1
-
- #define MAX_RETRIES 10
-
- #define CAPTURE_BUFFER_SIZE 16384
- UBYTE capture_buffer[CAPTURE_BUFFER_SIZE];
-
- void *MidiBase = NULL;
- void *IntuitionBase = NULL;
-
- struct MDest *dest = NULL;
- struct MSource *source = NULL;
-
- struct MRoute *route_a = NULL;
- struct MRoute *route_b = NULL;
-
- UBYTE *msg; /* buffer this in case we get shut down before freeing the current message */
-
- int capture_position = 0;
-
- void midi_cleanup(void)
- {
- /* if (msg)
- FreeMidiMsg(msg); */
-
- if (IntuitionBase)
- CloseLibrary(IntuitionBase);
-
- if (dest)
- DeleteMDest(dest);
- if (source)
- DeleteMSource(source);
-
- if (route_a)
- DeleteMRoute(route_a);
- if (route_b)
- DeleteMRoute(route_b);
-
- if (MidiBase)
- CloseLibrary(MidiBase);
- }
-
- /* if channel is -1, any channel is ok (within FZ-1 System Exclusive message) */
-
- /* validate the incoming message, including all sorts of stuff about the header
- * and anything we know specifically within the message type as well */
-
- UBYTE its_an_fz1_message(UBYTE *msg, int requested_channel)
- {
- int channel, length, expected_length;
- struct FZ1_Message *p;
-
- p = (struct FZ1_Message *)msg;
-
- /* compare first bytes of message,
- extract channel number and verify,
- return function code
- */
- length = MidiMsgLength(msg);
-
- if ((p->casio_id != 0x44) || (p->fz1_id != 0x200)
- || ((p->encoded_channel & 0xf0) != 0x70))
- return(NOT_A_FZ_MESSAGE);
-
- channel = (p->encoded_channel & 0x0f);
- if ((requested_channel != -1) && (channel != requested_channel))
- return(NOT_THE_REQUESTED_FZ_CHANNEL);
-
- switch(p->command)
- {
- case OPEN_MIDI_MSG:
- expected_length = 16;
- break;
-
- case CLOSE_MIDI_MSG:
- expected_length = 7;
- break;
-
- case DATA_MIDI_MSG:
- expected_length = 136;
- if (length == expected_length && (p->body.datamsg.checksum != calc_checksum(p)))
- {
- fprintf(stderr,"checksum error, expected %x, saw %x\n",
- p->body.datamsg.checksum,calc_checksum(p));
- return(DATA_ERROR);
- }
- break;
-
- /* haven't seen any of these yet */
- case OK_MIDI_MSG:
- case ERR_MIDI_MSG:
- case EFFECT_MIDI_MSG:
- case REMOTE_MIDI_MSG:
- panic("got a message I don't know how to handle");
-
- /* it wasn't a message we understood yet it had all the makings of
- * being one, it must be garbled */
- default:
- return(DATA_ERROR);
- }
- if (length != expected_length)
- return(DATA_ERROR);
-
- return(p->command);
- }
-
- void commune_with_fz1(struct MSource *source, struct MDest *dest, int channel, int outfd)
- {
- long len;
- UBYTE *ip;
- int command, retry_count = 0;
- int state = WAITING_FOR_OPEN;
- ULONG waitflags;
- int packets_received = 0, error_count = 0, done = 0;
- struct FZ1_Message *p;
-
- /* wait for a message or control-C or "done" control var to be set */
- while ((!((waitflags = Wait(-1)) & SIGBREAKF_CTRL_C)) && !done)
- {
- /* if ((waitflags & SIGBREAKF_CTRL_D) && (state = READING_FZ_DATA))
- {
- printf("saw a ^d\n");
- goto data_error;
- } */
-
- /* while there are messages to process, process messages */
- while (!done && (msg = GetMidiMsg(dest)))
- {
- /* discard all but system exclusive data - should be done
- * by the route, check someday to see if we can find our
- * route and change it if it isn't */
- if (*msg != MS_SYSEX)
- goto message_done;
-
- p = (struct FZ1_Message *)msg;
- command = its_an_fz1_message((UBYTE *)p,channel);
-
- if (state == WAITING_FOR_OPEN)
- {
- if (command != OPEN_MIDI_MSG)
- panic("out of sync - looking for 'Open' from FZ1");
-
- /* we need to specify a channel ID in our messages
- * if we're not looking for a specific one, reply
- * with the one we got in the first message */
- if (channel == -1)
- channel = p->encoded_channel & 0x0f;
- state = READING_FZ_DATA;
- dump_open(p);
- send_fz(source,channel,OK_MIDI_MSG);
- goto message_done;
- }
-
- if (state == READING_FZ_DATA)
- {
- abort_timeout_timer();
- switch(command)
- {
- case DATA_MIDI_MSG:
- send_fz(source,channel,OK_MIDI_MSG);
- start_timeout_timer();
- packets_received++;
- if ((packets_received % 10) == 0)
- {
- printf("%4d ok \r",packets_received);
- fflush(stdout);
- }
- capture(p,outfd);
- retry_count = 0;
- break;
-
- case DATA_ERROR:
- data_error:
- send_fz(source,channel,ERR_MIDI_MSG);
- start_timeout_timer();
- printf("%4d err\r",packets_received);
- fflush(stdout);
- error_count++;
- if (++retry_count > MAX_RETRIES)
- panic("exceeded max retries for a packet - transfer failed");
- break;
-
- /* we get this when the fz is done */
- case CLOSE_MIDI_MSG:
- fprintf(stderr,"casio is done\n");
- done = 1;
- break;
-
- default:
- fprintf(stderr,"unknown command = 0x%x\n",command);
- if (state = READING_FZ_DATA)
- {
- fprintf(stderr,"will try treating it as a data error\n");
- goto data_error;
- }
- else
- panic("unknown command and not in 'read' mode");
- }
- goto message_done;
- }
-
- panic("state variable fried");
-
- message_done: FreeMidiMsg(msg); /* free it */
- }
-
- if (CheckMsg(timer_request->tr_node.io_Message.mn_ReplyPort) &&
- (GetMsg(timer_request->tr_node.io_Message.mn_ReplyPort)) )
- {
- if (state == READING_FZ_DATA)
- {
- send_fz(source,channel,ERR_MIDI_MSG);
- printf("%4d tmo\r",packets_received);
- fflush(stdout);
- error_count++;
- if (++retry_count > MAX_RETRIES)
- panic("exceeded max retries for a packet - transfer failed");
- }
- }
- }
- if (capture_position != 0)
- {
- if (write(outfd,capture_buffer,capture_position) != capture_position)
- perror("output file");
- }
- printf("total packets received %d (%d retries)\n",packets_received,error_count);
- }
-
- void send_fz(struct MSource *source, int channel_id, int message_id)
- {
- static UBYTE buf[] = {0xf0, 0x44, 0x02, 0x00, 0x70,0x00,0xf7};
- buf[4] |= channel_id;
- buf[5] = message_id;
- PutMidiMsg(source,buf);
- }
-
- int calc_checksum(struct FZ1_Message *p)
- {
- UBYTE *ip, lownibble, hinibble;
- int len, running_sum;
-
- /* I assume the message has already been validated as a Casio FZ-1
- * data message
- */
-
- ip = &p->body.datamsg.data[0];
-
- for (len = 0, running_sum = 0; len < 128; len++)
- {
- running_sum += *ip++;
- }
- return((0 - running_sum) & 0x7f);
- }
-
- void capture(struct FZ1_Message *p, int outfd)
- {
- UBYTE *ip, lownibble, hinibble;
- int len;
-
- ip = &p->body.datamsg.data[0];
-
- for (len = 0; len < 64; len++)
- {
- lownibble = *ip++;
- hinibble = *ip++;
- capture_buffer[capture_position++] = (hinibble << 4) | lownibble;
- if (capture_position >= CAPTURE_BUFFER_SIZE)
- {
- if (write(outfd,capture_buffer,CAPTURE_BUFFER_SIZE) != CAPTURE_BUFFER_SIZE)
- {
- perror("output file");
- }
- capture_position = 0;
- }
- }
- }
-
- struct MRouteInfo myrouteinfo =
- {
- MMF_SYSEX,0xffff,0,0,{0},{0}
- };
-
- main(int argc,char *argv[])
- {
-
- char *sname, *dname, *filename;
- int outfd;
- int wanted_channel = -1;
-
- fprintf(stderr,"ready to talk to casio, the routes are done automatically from\n");
- fprintf(stderr,"midi_in if it's available, else MidiIn and to MidiOut.\n");
- fprintf(stderr,"I download and exit when done. I automatically do retries.\n");
- fprintf(stderr,"Nonetheless, I may 'hang' when uploading. This is soft.\n");
- fprintf(stderr,"Hit ^D to retry. Or hit ^C, I'll exit.\n");
- fprintf(stderr,"I write to the file on the fly (every 256 packets), so watch it.\n");
- if (argc != 2)
- {
- fprintf(stderr,"usage: casio filename, routes are automatic, then\n");
- fprintf(stderr," select FZ output device as 'midi' and do a voice save\n");
- exit(1);
- }
-
- sname = "FZ1out";
- dname = "FZ1in";
- filename = argv[1];
-
- if ((outfd = creat(filename,0666)) == -1)
- {
- fprintf(stderr,"couldn't create output file\n");
- perror(filename);
- exit(2);
- }
-
- if (!(IntuitionBase = OpenLibrary("intuition.library",0)))
- {
- fprintf(stderr,"can't open intuition.library\n");
- goto clean;
- }
-
- add_cleanup(midi_cleanup);
-
- if (!(MidiBase = OpenLibrary(MIDINAME,MIDIVERSION)))
- {
- fprintf(stderr,"can't open midi.library\n");
- goto clean;
- }
-
- /* create our public source node */
- if (!(source = CreateMSource(sname,NULL)))
- {
- fprintf(stderr,"can't create Source port %s\n",sname);
- goto clean;
- }
-
- /* create our dest node (public) */
- if (!(dest = CreateMDest(dname,NULL)))
- {
- fprintf(stderr,"can't create Dest port %s\n",dname);
- goto clean;
- }
-
- route_a = MRoutePublic("midi_in",dname,&myrouteinfo);
- if (!route_a)
- route_a = MRoutePublic("MidiIn",dname,&myrouteinfo);
-
- route_b = MRoutePublic(sname,"MidiOut",&myrouteinfo);
-
- init_timer();
-
- commune_with_fz1(source,dest,wanted_channel,outfd); /* process until shutdown */
-
- clean:
- close(outfd);
- cleanup();
- exit(0);
- }
-
- void _abort(void) /* abort routine called when CTRL-C is hit (Aztec) */
- {
- /* fflush(stdout); cleanup(); exit(1); */
- } /* we're polling it in the loop */
-
- void dump_open(struct FZ1_Message *p)
- {
- unsigned int nblocks;
-
- printf("dump of Open MIDI message received from Casio FZ-1\n");
- printf("channel %d, status %d, ",p->encoded_channel & 0x0f,p->body.openmsg.status);
- printf("banks %d, voices %d, ",p->body.openmsg.banks,p->body.openmsg.voices);
-
- if(p->body.openmsg.status != 1 || p->body.openmsg.banks != 0
- || p->body.openmsg.voices != 1)
- panic("I don't know how to do anything other than save a single voice");
-
- nblocks = (p->body.openmsg.nblocks_hinibble << 12)
- | (p->body.openmsg.nblocks_next_to_hinibble << 8)
- | (p->body.openmsg.nblocks_next_to_lonibble << 4)
- | p->body.openmsg.nblocks_lonibble;
- printf("nblocks %d, ",nblocks);
- printf("edit bank %d, edit voice %d\n",p->body.openmsg.edit_bank,p->body.openmsg.edit_voice);
- }
-
- /* end of casio.c */
-
-