Annotation of hatari/src/midi.c, revision 1.1.1.9

1.1       root        1: /*
1.1.1.2   root        2:   Hatari - midi.c
1.1       root        3: 
1.1.1.9 ! root        4:   This file is distributed under the GNU General Public License, version 2
        !             5:   or at your option any later version. Read the file gpl.txt for details.
1.1.1.2   root        6: 
                      7:   MIDI communication.
                      8:   Note that this code is far from being perfect. However, it is already
                      9:   enough to let some ST programs (e.g. the game Pirates!) use the host's midi
                     10:   system.
                     11: 
                     12:   TODO:
                     13:    - Most bits in the ACIA's status + control registers are currently ignored.
                     14:    - Check when we have to clear the ACIA_SR_INTERRUPT_REQUEST bit in the
                     15:      ACIA status register (it is currently done when reading or writing to
                     16:      the data register, but probably it should rather be done when reading the
                     17:      status register?).
1.1       root       18: */
1.1.1.6   root       19: const char Midi_fileid[] = "Hatari midi.c : " __DATE__ " " __TIME__;
1.1.1.2   root       20: 
                     21: #include <SDL_types.h>
1.1       root       22: 
                     23: #include "main.h"
1.1.1.2   root       24: #include "configuration.h"
1.1.1.3   root       25: #include "ioMem.h"
1.1.1.4   root       26: #include "m68000.h"
1.1.1.2   root       27: #include "mfp.h"
                     28: #include "midi.h"
1.1.1.5   root       29: #include "file.h"
1.1.1.9 ! root       30: #include "acia.h"
1.1.1.2   root       31: 
                     32: 
                     33: #define ACIA_SR_INTERRUPT_REQUEST  0x80
1.1.1.6   root       34: #define ACIA_SR_TX_EMPTY           0x02
                     35: #define ACIA_SR_RX_FULL            0x01
1.1.1.2   root       36: 
                     37: #define MIDI_DEBUG 0
                     38: #if MIDI_DEBUG
                     39: #define Dprintf(a) printf a
                     40: #else
                     41: #define Dprintf(a)
                     42: #endif
                     43: 
                     44: 
1.1.1.6   root       45: static FILE *pMidiFhIn  = NULL;        /* File handle used for Midi input */
                     46: static FILE *pMidiFhOut = NULL;        /* File handle used for Midi output */
1.1.1.2   root       47: static Uint8 MidiControlRegister;
                     48: static Uint8 MidiStatusRegister;
1.1.1.6   root       49: static Uint8 nRxDataByte;
1.1.1.2   root       50: 
                     51: 
1.1.1.5   root       52: /**
                     53:  * Initialization: Open MIDI device.
                     54:  */
1.1.1.2   root       55: void Midi_Init(void)
                     56: {
1.1.1.5   root       57:        if (!ConfigureParams.Midi.bEnableMidi)
                     58:                return;
1.1.1.2   root       59: 
1.1.1.6   root       60:        if (ConfigureParams.Midi.sMidiOutFileName[0])
1.1.1.5   root       61:        {
1.1.1.6   root       62:                /* Open MIDI output file */
                     63:                pMidiFhOut = File_Open(ConfigureParams.Midi.sMidiOutFileName, "wb");
                     64:                if (!pMidiFhOut)
                     65:                {
                     66:                        Log_AlertDlg(LOG_ERROR, "MIDI output file open failed. MIDI support disabled.");
1.1.1.7   root       67:                        ConfigureParams.Midi.bEnableMidi = false;
1.1.1.6   root       68:                        return;
                     69:                }
                     70:                setvbuf(pMidiFhOut, NULL, _IONBF, 0);    /* No output buffering! */
                     71:                Dprintf(("Opened file '%s' for MIDI output.\n",
                     72:                         ConfigureParams.Midi.sMidiOutFileName));
                     73:        }
                     74:        if (ConfigureParams.Midi.sMidiInFileName[0])
                     75:        {
                     76:                /* Try to open MIDI input file */
                     77:                pMidiFhIn = File_Open(ConfigureParams.Midi.sMidiInFileName, "rb");
                     78:                if (!pMidiFhIn)
                     79:                {
                     80:                        Log_AlertDlg(LOG_ERROR, "MIDI input file open failed. MIDI support disabled.");
1.1.1.7   root       81:                        ConfigureParams.Midi.bEnableMidi = false;
1.1.1.6   root       82:                        return;
                     83:                }
                     84:                setvbuf(pMidiFhIn, NULL, _IONBF, 0);    /* No input buffering! */
                     85:                Dprintf(("Opened file '%s' for MIDI input.\n",
                     86:                         ConfigureParams.Midi.sMidiInFileName));
1.1.1.2   root       87:        }
                     88: }
                     89: 
                     90: 
1.1.1.5   root       91: /**
                     92:  * Close MIDI device.
                     93:  */
1.1.1.2   root       94: void Midi_UnInit(void)
                     95: {
1.1.1.6   root       96:        pMidiFhIn = File_Close(pMidiFhIn);
                     97:        pMidiFhOut = File_Close(pMidiFhOut);
                     98: 
1.1.1.8   root       99:        CycInt_RemovePendingInterrupt(INTERRUPT_MIDI);
1.1.1.2   root      100: }
                    101: 
                    102: 
1.1.1.5   root      103: /**
1.1.1.6   root      104:  * Reset MIDI emulation.
1.1.1.5   root      105:  */
1.1.1.6   root      106: void Midi_Reset(void)
1.1.1.2   root      107: {
1.1.1.6   root      108:        MidiControlRegister = 0;
                    109:        MidiStatusRegister = ACIA_SR_TX_EMPTY;
                    110:        nRxDataByte = 1;
1.1.1.2   root      111: 
1.1.1.6   root      112:        if (ConfigureParams.Midi.bEnableMidi)
1.1.1.8   root      113:                CycInt_AddRelativeInterrupt(2050, INT_CPU_CYCLE, INTERRUPT_MIDI);
1.1.1.9 ! root      114:        else
        !           115:                CycInt_RemovePendingInterrupt (INTERRUPT_MIDI);
1.1.1.2   root      116: }
                    117: 
                    118: 
1.1.1.5   root      119: /**
1.1.1.6   root      120:  * Read MIDI status register ($FFFC04).
1.1.1.5   root      121:  */
1.1.1.6   root      122: void Midi_Control_ReadByte(void)
1.1.1.2   root      123: {
1.1.1.6   root      124:        Dprintf(("Midi_ReadControl : $%x.\n", MidiStatusRegister));
1.1.1.2   root      125: 
1.1.1.9 ! root      126:        ACIA_AddWaitCycles ();                                          /* Additional cycles when accessing the ACIA */
1.1.1.4   root      127: 
1.1.1.6   root      128:        IoMem[0xfffc04] = MidiStatusRegister;
1.1.1.2   root      129: }
                    130: 
1.1       root      131: 
1.1.1.5   root      132: /**
                    133:  * Write to MIDI control register ($FFFC04).
                    134:  */
1.1.1.3   root      135: void Midi_Control_WriteByte(void)
1.1.1.2   root      136: {
1.1.1.9 ! root      137:        ACIA_AddWaitCycles ();                                          /* Additional cycles when accessing the ACIA */
1.1.1.4   root      138: 
1.1.1.3   root      139:        MidiControlRegister = IoMem[0xfffc04];
1.1.1.2   root      140: 
1.1.1.3   root      141:        Dprintf(("Midi_WriteControl($%x)\n", MidiControlRegister));
1.1.1.2   root      142: 
                    143:        /* Do we need to generate a transfer interrupt? */
                    144:        if ((MidiControlRegister & 0xA0) == 0xA0)
                    145:        {
                    146:                Dprintf(("WriteControl: Transfer interrupt!\n"));
                    147: 
                    148:                /* Acknowledge in MFP circuit, pass bit,enable,pending */
1.1.1.9 ! root      149:                MFP_InputOnChannel ( MFP_INT_ACIA , 0 );
1.1.1.2   root      150: 
                    151:                MidiStatusRegister |= ACIA_SR_INTERRUPT_REQUEST;
                    152:        }
                    153: }
                    154: 
                    155: 
1.1.1.6   root      156: /**
                    157:  * Read MIDI data register ($FFFC06).
                    158:  */
                    159: void Midi_Data_ReadByte(void)
                    160: {
                    161:        Dprintf(("Midi_ReadData : $%x.\n", 1));
                    162: 
1.1.1.9 ! root      163:        ACIA_AddWaitCycles ();                                          /* Additional cycles when accessing the ACIA */
1.1.1.6   root      164: 
                    165:        MidiStatusRegister &= ~(ACIA_SR_INTERRUPT_REQUEST|ACIA_SR_RX_FULL);
                    166: 
                    167:        /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt,
                    168:         * becomes high(1) again after data has been read. */
                    169:        MFP_GPIP |= 0x10;
                    170: 
                    171:        IoMem[0xfffc06] = nRxDataByte;
                    172: }
                    173: 
                    174: 
1.1.1.5   root      175: /**
                    176:  * Write to MIDI data register ($FFFC06).
                    177:  */
1.1.1.3   root      178: void Midi_Data_WriteByte(void)
1.1.1.2   root      179: {
1.1.1.6   root      180:        Uint8 nTxDataByte;
1.1.1.4   root      181: 
1.1.1.9 ! root      182:        ACIA_AddWaitCycles ();                                          /* Additional cycles when accessing the ACIA */
1.1.1.4   root      183: 
1.1.1.6   root      184:        nTxDataByte = IoMem[0xfffc06];
1.1.1.3   root      185: 
1.1.1.6   root      186:        Dprintf(("Midi_WriteData($%x)\n", nTxDataByte));
1.1.1.2   root      187: 
                    188:        MidiStatusRegister &= ~ACIA_SR_INTERRUPT_REQUEST;
                    189: 
                    190:        if (!ConfigureParams.Midi.bEnableMidi)
                    191:                return;
                    192: 
1.1.1.6   root      193:        if (pMidiFhOut)
1.1.1.2   root      194:        {
                    195:                int ret;
1.1.1.6   root      196: 
1.1.1.2   root      197:                /* Write the character to the output file: */
1.1.1.6   root      198:                ret = fputc(nTxDataByte, pMidiFhOut);
                    199: 
1.1.1.2   root      200:                /* If there was an error then stop the midi emulation */
                    201:                if (ret == EOF)
                    202:                {
                    203:                        Midi_UnInit();
                    204:                        return;
                    205:                }
                    206:        }
                    207: 
1.1.1.6   root      208:        MidiStatusRegister &= ~ACIA_SR_TX_EMPTY;
                    209: }
                    210: 
                    211: 
                    212: /**
                    213:  * Read and write MIDI interface data regularly
                    214:  */
                    215: void Midi_InterruptHandler_Update(void)
                    216: {
                    217:        int nInChar;
                    218: 
                    219:        /* Remove this interrupt from list and re-order */
1.1.1.8   root      220:        CycInt_AcknowledgeInterrupt();
1.1.1.6   root      221: 
                    222:        /* Flush outgoing data */
                    223:        if (!(MidiStatusRegister & ACIA_SR_TX_EMPTY))
1.1.1.2   root      224:        {
1.1.1.6   root      225:                /* Do we need to generate a transfer interrupt? */
                    226:                if ((MidiControlRegister & 0xA0) == 0xA0)
                    227:                {
                    228:                        Dprintf(("WriteData: Transfer interrupt!\n"));
                    229:                        /* Acknowledge in MFP circuit, pass bit,enable,pending */
1.1.1.9 ! root      230:                        MFP_InputOnChannel ( MFP_INT_ACIA , 0 );
1.1.1.6   root      231:                        MidiStatusRegister |= ACIA_SR_INTERRUPT_REQUEST;
                    232:                }
1.1.1.2   root      233: 
1.1.1.6   root      234:                // if (pMidiFhOut)
                    235:                //      fflush(pMidiFhOut);
1.1.1.2   root      236: 
1.1.1.6   root      237:                MidiStatusRegister |= ACIA_SR_TX_EMPTY;
1.1.1.2   root      238:        }
1.1.1.6   root      239: 
                    240:        /* Read the bytes in, if we have any */
                    241:        if (pMidiFhIn && File_InputAvailable(pMidiFhIn))
                    242:        {
                    243:                nInChar = fgetc(pMidiFhIn);
                    244:                if (nInChar != EOF)
                    245:                {
                    246:                        Dprintf(("Midi: Read character $%x\n", nInChar));
                    247:                        /* Copy into our internal queue */
                    248:                        nRxDataByte = nInChar;
                    249:                        /* Do we need to generate a receive interrupt? */
                    250:                        if ((MidiControlRegister & 0x80) == 0x80)
                    251:                        {
                    252:                                Dprintf(("WriteData: Receive interrupt!\n"));
                    253:                                /* Acknowledge in MFP circuit */
1.1.1.9 ! root      254:                                MFP_InputOnChannel ( MFP_INT_ACIA , 0 );
1.1.1.6   root      255:                                MidiStatusRegister |= ACIA_SR_INTERRUPT_REQUEST;
                    256:                        }
                    257:                        MidiStatusRegister |= ACIA_SR_RX_FULL;
                    258:                        /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt:
                    259:                         * It will remain low(0) until data is read from $fffc06. */
                    260:                        MFP_GPIP &= ~0x10;
                    261:                }
                    262:                else
                    263:                {
                    264:                        Dprintf(("Midi: error during read!\n"));
                    265:                        clearerr(pMidiFhIn);
                    266:                }
                    267:        }
                    268: 
1.1.1.8   root      269:        CycInt_AddRelativeInterrupt(2050, INT_CPU_CYCLE, INTERRUPT_MIDI);
1.1.1.2   root      270: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.