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

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

unix.superglobalmegacorp.com

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