home *** CD-ROM | disk | FTP | other *** search
- /* MusicSerial.c
- Copyright (c) 1990,1991,1992,1993 by Thomas E. Janzen
- All Rights Reserved
-
- THIS SOFTWARE IS FURNISHED FREE OF CHARGE FOR STUDY AND USE AND MAY
- BE COPIED ONLY FOR PERSONAL USE OR COMPLETELY AS OFFERED WITH NO
- CHANGES FOR FREE DISTRIBUTION. NO TITLE TO AND OWNERSHIP OF THE
- SOFTWARE IS HEREBY TRANSFERRED. THOMAS E. JANZEN ASSUMES NO
- RESPONSIBILITY FOR THE USE OR RELIABILITY OF THIS SOFTWARE.
-
- Thomas E. Janzen
- 208A Olde Derby Road
- Norwood, MA 02062-1761
- (617)769-7733
- ** FACILITY:
- **
- ** AlgoRhythms music improviser on Commodore (TM) Amiga (TM)
- ** compiled with SAS/C Amiga Compiler 6.50
- **
- ** ABSTRACT:
- **
- ** MusicSerial.c manages the serial device at the MIDI bit rate.
- ** All sends to MIDI occur here.
- **
- ** AUTHORS: Thomas E. Janzen
- **
- ** CREATION DATE: 26-MAR-1990
- **
- ** MODIFICATION HISTORY:
- ** DATE NAME DESCRIPTION
- ** 7 Dec 90 T. Janzen Used SendIO rather than DoIO - didn't up performance
- ** 4 Nov 91 T. Janzen incorporate MIDI running status; delete SendNoteOff
- ** 8 DEC 91 T. Janzen conform to SAS/C 5.10b remove extern from functs
- ** 4 Jan 92 TEJ last changes for 2.0
- ** 14 SEP 92 TEJ Make play_note_on use NOTEOFF when dynamic is zero
- ** (works, fixes stuck note bug)
- ** 15 SEP 92 TEJ Fix stuck notes by using MAXVOICE in stop_all_notes
- * 2 AUG 93 TEJ stop guru's by checking before set audio call
- ** 6 DEC 94 TEJ remove SERIALNAME from CreatePort. Change flags in
- ** OpenDevice serial ExtIO (esp. remove 7 wire).
- ** 10 DEC 94 TEJ Improved error reporting with error number.
- ** Made it work with audio even though serial device fails.
- **--
- */
-
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/lists.h>
- #include <exec/ports.h>
- #include <exec/libraries.h>
- #include <exec/devices.h>
- #include <devices/serial.h>
- #include <exec/io.h>
- #include <intuition/intuition.h>
- #include <proto/dos.h>
- #include <proto/graphics.h>
- #include <proto/exec.h>
- #include <proto/mathffp.h>
- #include <proto/intuition.h>
- #ifdef CLI
- #include <stdio.h>
- #endif
- #include "Window.h"
- #include "AlgoRhythms.h"
- #include "MusicSerial.h"
- #include "Record.h"
- #include "audio.h"
-
- #define NOTEONCMD (0x90) /* MIDI Note on byte */
- #define NOTEOFFCMD (0x80) /* MIDI Note off byte */
- #define START (0xFA) /* MIDI Start play byte */
- #define STOP (0xFC) /* MIDI Stop play byte */
- #define CONTINUE (0xFB) /* MIDI Continue play byte */
- #define TIMINGCLOCK (0xF8) /* MIDI Timing clock byte */
-
- static int response;
-
- static struct IOExtSer *ior_ser = NULL;
- static struct MsgPort *port = NULL;
-
- static int serial_fubar = FALSE;
-
- extern struct IORequest *CreateExtIO();
- extern void DeletePort(struct MsgPort *);
-
- /* strings for error alerts */
- static char quit_str[5] = "Quit",
- ser_err_str[20] = "Serial Device Error",
- prt_err_str[11] = "Port Error",
- io_err_str[19] = "Create ExtIO Error",
- dev_err_str[20] = "Serial Device Error",
- prm_err_str[15] = "Set Parm Error",
- wrt_err_str[26] = "Serial.device write error";
- #ifndef CLI
- struct IntuiText quit_txt
- = {2, 1, JAM1, 5, 4, &font_choice, quit_str, NULL};
- #endif
- static char playbuffer[4]; /* MIDI note message buffer */
-
- #ifdef MEASURE
- unsigned int gi_notes_measure = 0;
- #endif
-
- static char DBGstr[80];
- #ifndef CLI
- static struct IntuiText
- DBGTxt = {2, 1, JAM1, 5, 15, &font_choice, DBGstr, NULL};
- #endif
-
- static void AutoError(const int ErrorNum, const char *ErrorStr);
-
- static int set_serial(struct IOExtSer *io, unsigned long rbuf_len,
- unsigned char rlen, unsigned char wlen, unsigned long brk,
- unsigned long baud, unsigned char sf,
- unsigned long ta0, unsigned long ta1);
-
- static int set_serial(struct IOExtSer *io, unsigned long rbuf_len,
- unsigned char rlen, unsigned char wlen, unsigned long brk,
- unsigned long baud, unsigned char sf,
- unsigned long ta0, unsigned long ta1)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Sets up serial port
- **
- ** RETURN VALUE:
- ** description:
- ** data_type:
- **
- ** ARGUMENTS:
- **
- ** io-
- ** description: IO device structure
- ** data_type: pointer to struct IOExtSer
- ** access: read/write
- **
- ** rbuf_len-
- ** description: read buffer length returned
- ** data_type: unsigned long
- ** access: read only
- **
- ** rlen-
- ** description: length of read buffer
- ** data_type: unsigned char
- ** access: read only
- **
- ** wlen-
- ** description: length of write buffer
- ** data_type: unsigned char
- ** access: read only
- **
- ** brk-
- ** description: length of break time
- ** data_type: unsigned long
- ** access: read only
- **
- ** baud-
- ** description: baud rate
- ** data_type: unsigned long
- ** access: read only
- **
- ** sf-
- ** description: serial flags
- ** data_type: unsigned char
- ** access: read only
- **
- ** ta0-
- ** description: misc flags
- ** data_type: unsigned long
- ** access: read only
- **
- ** ta1-
- ** description: misc flags
- ** data_type: unsigned long
- ** access: read only
- **
- ** DESIGN:
- ** ROUTINE
- ** : Fill out io structure for setting up serial device
- ** : send the command to the serial device
- ** : IF set up failed
- ** : : set quit and fubar
- ** : : post error
- ** : ENDIF
- ** : return error
- ** ENDROUTINE
- */
- {
- auto int error;
-
- io->io_ReadLen = rlen;
- io->io_BrkTime = brk; /*length of break time (irrelevant)*/
- io->io_Baud = baud;
- io->io_WriteLen = wlen;
- io->io_StopBits = 0x01;
- io->io_RBufLen = rbuf_len;
- io->io_SerFlags
- |= SERF_XDISABLED | SERF_SHARED | SERF_RAD_BOOGIE;
- io->IOSer.io_Command = SDCMD_SETPARAMS;
- io->io_TermArray.TermArray0 = ta0;
- io->io_TermArray.TermArray1 = ta1;
- if (!serial_fubar)
- {
- if ((error = DoIO(io)) != 0)
- {
- serial_fubar = TRUE;
- AutoError(io->IOSer.io_Error, ser_err_str);
- }
- }
- return error;
- }
-
- void open_midi_port(void)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Opens the serial devices for MIDI usage
- **
- ** DESIGN:
- ** ROUTINE
- ** : CreatePort to serial device
- ** : IF failed
- ** : : set quit and fubar
- ** : : post error
- ** : ENDIF
- ** : ior_ser = CreateExtIO()
- ** : IF failed
- ** : : set quit and fubar
- ** : : post error
- ** : ENDIF
- ** : OpenDevice()
- ** : IF failed
- ** : : set quit and fubar
- ** : : post error
- ** : ENDIF
- ** : IF not failed yet
- ** : : set_serial()
- ** : : IF failed
- ** : : : set fubar and quit
- ** : : : post error
- ** : : ENDIF
- ** : ENDIF
- ** : return
- ** ENDROUTINE
- */
- {
- auto int error;
- auto unsigned long rbl = 512, /*read buffer length*/
- brk = 750000, /* length of break in usec */
- baud = 31250, /* MIDI baud rate 31.25k bits/sec*/
- t0 = 0x51040303, /*termination characters*/
- t1 = 0x03030303;
- auto unsigned char rwl = 0x08, /*bits per read char */
- wwl = 0x08, /*bits per write char */
- sf = 0x00; /*serial flags */
-
- port = CreatePort(0, 0);
- if (NULL == port)
- {
-
- serial_fubar = TRUE;
- AutoError(0, prt_err_str);
- stop_midi();
- }
- ior_ser
- = (struct IOExtSer *)CreateExtIO(port, sizeof(struct IOExtSer));
- if (NULL == ior_ser)
- {
- serial_fubar = TRUE;
- AutoError(ior_ser->IOSer.io_Error, io_err_str);
- stop_midi();
- }
- ior_ser->io_SerFlags
- = SERF_XDISABLED | SERF_SHARED | SERF_RAD_BOOGIE;
- if ((error = OpenDevice(SERIALNAME, 0,
- (struct IORequest *)ior_ser, 0)) != 0)
- {
- serial_fubar = TRUE;
-
- AutoError(ior_ser->IOSer.io_Error, dev_err_str);
- stop_midi();
- }
-
- if (!gi_quit && !gi_fubar && !serial_fubar)
- {
- if ((error
- = set_serial(ior_ser, rbl, rwl, wwl, brk, baud, sf, t0, t1)) != 0)
- {
- serial_fubar = TRUE;
-
- AutoError(ior_ser->IOSer.io_Error, prm_err_str);
-
- stop_midi();
- }
- }
- return;
- /* The serial device is open, so go ahead and play music.*/
- }
-
- int write_ser(struct IOExtSer *ser_io, char *data, int length)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Write data to serial port.
- **
- ** RETURN VALUE:
- ** description: TRUE if failed, FALSE if succeeded
- ** data_type: int
- **
- ** ARGUMENTS:
- **
- ** ser_io-
- ** description: serial device structure
- ** data_type: pointer to IOExtSer
- ** access: read only
- **
- ** data-
- ** description: data to send to serial device
- ** data_type: pointer to char
- ** access: read only
- **
- ** length-
- ** description: length in bytes of serial data
- ** data_type: int
- ** access: read only
- **
- ** DESIGN:
- ** ROUTINE
- ** : WaitIO() in case some send is not done yet
- ** : copy send data and length into ser_io
- ** : DoIO(ser_io) (send data)
- ** : IF failed
- ** : : set quit and fubar
- ** : : post error
- ** : ENDIF
- ** : return error
- ** ENDROUTINE
- */
- {
- auto int error;
- WaitIO(ser_io);
- ser_io->IOSer.io_Data = (APTR)data;
- ser_io->IOSer.io_Length = length;
- ser_io->IOSer.io_Command = CMD_WRITE;
- error = DoIO(ser_io);
- if (error)
- {
- serial_fubar = TRUE;
- AutoError(ser_io->IOSer.io_Error, wrt_err_str);
- stop_midi();
- }
- return error;
- }
-
- void play_note_on(NOTE_EVENT_TYPE *play_event)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Sends note on and note off MIDI commands; tracks running status
- **
- ** ARGUMENTS:
- **
- ** play_event-
- ** description: Information about a voice and its status
- ** data_type: pointer to NOTE_EVENT_TYPE
- ** access: read only
- **
- ** DESIGN:
- ** ROUTINE
- ** : IF channel is negative
- ** : : clear running status
- ** : : return
- ** : ENDIF
- ** : copy channel and NOTEONCMD to playbuffer[0]
- ** : copy dynamic to playbuffer[2]
- ** : IF this is a note-on
- ** : : playbuffer[1] = new pitch from scale
- ** : ELSE
- ** : : playbuffer[1] = old pitch
- ** : ENDIF
- ** : IF playbuffer[0] == Running_Status
- ** : : write_ser &playbuffer[1], length of 2
- ** : ELSE running status has changed
- ** : : write_ser &playbuffer[0], length of 3
- ** : : set new running status
- ** : ENDIF
- ** ENDROUTINE
- */
- {
- static unsigned char Running_Status = 0X00;
-
- if ((play_event->nv_i_channel) < 0)
- {
- Running_Status = 0;
- return;
- }
- playbuffer[0] = (unsigned char)
- (((play_event->nv_i_channel) & 0XF) | NOTEONCMD);
- playbuffer[2] = (unsigned char)(play_event->nv_i_dynamic);
-
- playbuffer[1] = (unsigned char)(play_event->nv_i_cur_pitch);
- #ifdef MEASURE
- if (play_event->nv_i_dynamic != 0)
- {
- gi_notes_measure++;
- }
- #endif
- if (!serial_fubar) {
- if (playbuffer[0] == Running_Status)
- {
- write_ser(ior_ser, &playbuffer[1], 2); /* send it out MIDI */
- }
- else
- {
- write_ser(ior_ser, playbuffer, 3); /* send it out MIDI */
- Running_Status = playbuffer[0];
- }
- }
- play_event->nv_i_was_audio = 0;
- return;
- }
-
- void send_function(const int Function)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Sends special MIDI functions down serial line
- **
- ** ARGUMENTS:
- **
- ** Function-
- ** description: the MIDI function to send out MIDI
- ** data_type: int
- ** access: read only
- **
- ** DESIGN:
- ** ROUTINE
- ** : clear playbuffer[1]
- ** : CASE Function
- ** : : STARTFUNCT
- ** : : : set playbuffer[0] to START
- ** : : STOPFUNCT
- ** : : : set playbuffer[0] to STOP
- ** : : CLOCKFUNCT
- ** : : : set playbuffer[0] to TIMINGCLOCK
- ** : : CONTFUNCT
- ** : : : set playbuffer[0] to CONTINUE
- ** : ENDCASE
- ** : write_ser playbuffer[0] length of 1
- ** ENDROUTINE
- */
- {
- playbuffer[1] = 0;
- switch (Function)
- {
- case STARTFUNCT:
- playbuffer[0] = (unsigned char)START;
- break;
- case STOPFUNCT:
- playbuffer[0] = (unsigned char)STOP;
- break;
- case CLOCKFUNCT:
- playbuffer[0] = (unsigned char)TIMINGCLOCK;
- break;
- case CONTFUNCT:
- playbuffer[0] = (unsigned char)CONTINUE;
- break;
- default:
- break;
- }
- if (!serial_fubar) {
- write_ser(ior_ser, playbuffer, 1); /* send it out MIDI */
- }
- return;
- }
-
- void stop_all_notes(NOTE_EVENT_TYPE *notes_to_stop)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Sends note-offs for all MIDI notes in all voices
- **
- ** ARGUMENTS:
- **
- ** notes_to_stop-
- ** description:
- ** data_type: pointer to NOTE_EVENT_TYPE
- ** access: read/write only
- **
- ** DESIGN:
- ** ROUTINE
- ** : FOR vox_index = 0 to MAXVOICE
- ** : : IF notes_to_stop[vox_index] is playing
- ** : : : send a note off for this voice
- ** : : : IF recording
- ** : : : : record a note off for this voice
- ** : : : ENDIF
- ** : : : Clear playing bit for this voice
- ** : : : IF fubar
- ** : : : : break out of FOR
- ** : : : ENDIF
- ** : : ENDIF
- ** : ENDFOR
- ** : send_function(STOPFUNCT)
- ** ENDROUTINE
- */
- {
- auto int vox_index;
-
- for (vox_index = 0; vox_index < MAXVOICE; vox_index++)
- {
- if (notes_to_stop[vox_index].nv_i_playing)
- {
- Delay(1);
- notes_to_stop[vox_index].nv_i_dynamic = 0;
- if (notes_to_stop[vox_index].nv_i_was_audio)
- {
- play_audio_note(&(notes_to_stop[vox_index]));
- }
- else
- {
- play_note_on(&(notes_to_stop[vox_index]));
- }
- #ifndef CLI
- if (recording)
- {
- record_note_event(&(notes_to_stop[vox_index]));
- }
- #endif
- notes_to_stop[vox_index].nv_i_playing = FALSE;
- if (gi_fubar)
- {
- break;
- }
- }
- }
- send_function(STOPFUNCT);
- return;
- }
-
- void stop_midi(void)
- /*
- ** FUNCTIONAL DESCRIPTION:
- ** Disconnects from serial device
- **
- ** DESIGN:
- ** ROUTINE
- ** : IF port
- ** : : DeletePort
- ** : ENDIF
- ** : IF ior_ser
- ** : : CloseDevice
- ** : ENDIF
- ** ENDROUTINE
- */
- {
- if (ior_ser != NULL)
- {
- CloseDevice(ior_ser);
- DeleteExtIO(ior_ser);
- ior_ser = NULL;
- }
- if (port != NULL)
- {
- DeletePort(port);
- port = NULL;
- }
- serial_fubar = TRUE;
- return;
- }
-
- static void AutoError(const int ErrorNum, const char *ErrorStr) {
- auto char NumStr[20];
- switch (ErrorNum) {
- case SerErr_DevBusy:
- sprintf(NumStr, "DevBusy");
- break;
- case SerErr_BaudMismatch:
- sprintf(NumStr, "BaudMismatch");
- break;
- case SerErr_BufErr:
- sprintf(NumStr, "BufErr");
- break;
- case SerErr_InvParam:
- sprintf(NumStr, "InvParam");
- break;
- case SerErr_LineErr:
- sprintf(NumStr, "LineErr");
- break;
- case SerErr_ParityErr:
- sprintf(NumStr, "Parity");
- break;
- case SerErr_TimerErr:
- sprintf(NumStr, "Timer");
- break;
- case SerErr_BufOverflow:
- sprintf(NumStr, "Overflow");
- break;
- case SerErr_NoDSR:
- sprintf(NumStr, "NoDataSetRdy");
- break;
- case SerErr_DetectedBreak:
- sprintf(NumStr, "break came");
- break;
- default:
- sprintf(NumStr, "%ld", ErrorNum);
- break;
- }
- sprintf(DBGstr, "%s %s", ErrorStr, NumStr);
- #ifndef CLI
- AutoRequest(w, &DBGTxt, &quit_txt, &quit_txt, 0L, 0L, 300L, 60L);
- #else
- puts(DBGstr);
- #endif
-
- return;
- }
-