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

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.");
        !            66:                        ConfigureParams.Midi.bEnableMidi = FALSE;
        !            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.");
        !            80:                        ConfigureParams.Midi.bEnableMidi = FALSE;
        !            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: 
        !            98:        Int_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:        {
        !           113:                Int_AddRelativeInterrupt(2050, INT_CPU_CYCLE, INTERRUPT_MIDI);
        !           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 */
        !           223:        Int_AcknowledgeInterrupt();
        !           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: 
        !           272:        Int_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.