duke3d/audiolib/mpu401.c

452 lines
9.4 KiB
C
Executable File

/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**********************************************************************
module: MPU401.C
author: James R. Dose
date: January 1, 1994
Low level routines to support sending of MIDI data to MPU401
compatible MIDI interfaces.
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include "dpmi.h"
#include "user.h"
#include "mpu401.h"
#define MIDI_NOTE_OFF 0x80
#define MIDI_NOTE_ON 0x90
#define MIDI_POLY_AFTER_TCH 0xA0
#define MIDI_CONTROL_CHANGE 0xB0
#define MIDI_PROGRAM_CHANGE 0xC0
#define MIDI_AFTER_TOUCH 0xD0
#define MIDI_PITCH_BEND 0xE0
#define MIDI_META_EVENT 0xFF
#define MIDI_END_OF_TRACK 0x2F
#define MIDI_TEMPO_CHANGE 0x51
#define MIDI_MONO_MODE_ON 0x7E
#define MIDI_ALL_NOTES_OFF 0x7B
int MPU_BaseAddr = MPU_DefaultAddress;
//unsigned MPU_Delay = 500;
//unsigned MPU_Delay = 5000;
unsigned MPU_Delay = 0x5000;
/**********************************************************************
Memory locked functions:
**********************************************************************/
#define MPU_LockStart MPU_SendMidi
/*---------------------------------------------------------------------
Function: MPU_SendMidi
Sends a byte of MIDI data to the music device.
---------------------------------------------------------------------*/
void MPU_SendMidi
(
int data
)
{
int port = MPU_BaseAddr + 1;
unsigned count;
count = MPU_Delay;
while( count > 0 )
{
// check if status port says we're ready for write
if ( !( inp( port ) & MPU_ReadyToWrite ) )
{
break;
}
count--;
}
port--;
// Send the midi data
outp( port, data );
}
/*---------------------------------------------------------------------
Function: MPU_NoteOff
Sends a full MIDI note off event out to the music device.
---------------------------------------------------------------------*/
void MPU_NoteOff
(
int channel,
int key,
int velocity
)
{
MPU_SendMidi( MIDI_NOTE_OFF | channel );
MPU_SendMidi( key );
MPU_SendMidi( velocity );
}
/*---------------------------------------------------------------------
Function: MPU_NoteOn
Sends a full MIDI note on event out to the music device.
---------------------------------------------------------------------*/
void MPU_NoteOn
(
int channel,
int key,
int velocity
)
{
MPU_SendMidi( MIDI_NOTE_ON | channel );
MPU_SendMidi( key );
MPU_SendMidi( velocity );
}
/*---------------------------------------------------------------------
Function: MPU_PolyAftertouch
Sends a full MIDI polyphonic aftertouch event out to the music device.
---------------------------------------------------------------------*/
void MPU_PolyAftertouch
(
int channel,
int key,
int pressure
)
{
MPU_SendMidi( MIDI_POLY_AFTER_TCH | channel );
MPU_SendMidi( key );
MPU_SendMidi( pressure );
}
/*---------------------------------------------------------------------
Function: MPU_ControlChange
Sends a full MIDI control change event out to the music device.
---------------------------------------------------------------------*/
void MPU_ControlChange
(
int channel,
int number,
int value
)
{
MPU_SendMidi( MIDI_CONTROL_CHANGE | channel );
MPU_SendMidi( number );
MPU_SendMidi( value );
}
/*---------------------------------------------------------------------
Function: MPU_ProgramChange
Sends a full MIDI program change event out to the music device.
---------------------------------------------------------------------*/
void MPU_ProgramChange
(
int channel,
int program
)
{
MPU_SendMidi( MIDI_PROGRAM_CHANGE | channel );
MPU_SendMidi( program );
}
/*---------------------------------------------------------------------
Function: MPU_ChannelAftertouch
Sends a full MIDI channel aftertouch event out to the music device.
---------------------------------------------------------------------*/
void MPU_ChannelAftertouch
(
int channel,
int pressure
)
{
MPU_SendMidi( MIDI_AFTER_TOUCH | channel );
MPU_SendMidi( pressure );
}
/*---------------------------------------------------------------------
Function: MPU_PitchBend
Sends a full MIDI pitch bend event out to the music device.
---------------------------------------------------------------------*/
void MPU_PitchBend
(
int channel,
int lsb,
int msb
)
{
MPU_SendMidi( MIDI_PITCH_BEND | channel );
MPU_SendMidi( lsb );
MPU_SendMidi( msb );
}
/*---------------------------------------------------------------------
Function: MPU_SendCommand
Sends a command to the MPU401 card.
---------------------------------------------------------------------*/
void MPU_SendCommand
(
int data
)
{
int port = MPU_BaseAddr + 1;
unsigned count;
count = 0xffff;
while( count > 0 )
{
// check if status port says we're ready for write
if ( !( inp( port ) & MPU_ReadyToWrite ) )
{
break;
}
count--;
}
outp( port, data );
}
/*---------------------------------------------------------------------
Function: MPU_Reset
Resets the MPU401 card.
---------------------------------------------------------------------*/
int MPU_Reset
(
void
)
{
int port = MPU_BaseAddr + 1;
unsigned count;
// Output "Reset" command via Command port
MPU_SendCommand( MPU_CmdReset );
// Wait for status port to be ready for read
count = 0xffff;
while( count > 0 )
{
if ( !( inp( port ) & MPU_ReadyToRead ) )
{
port--;
// Check for a successful reset
if ( inp( port ) == MPU_CmdAcknowledge )
{
return( MPU_Ok );
}
port++;
}
count--;
}
// Failed to reset : MPU-401 not detected
return( MPU_NotFound );
}
/*---------------------------------------------------------------------
Function: MPU_EnterUART
Sets the MPU401 card to operate in UART mode.
---------------------------------------------------------------------*/
int MPU_EnterUART
(
void
)
{
int port = MPU_BaseAddr + 1;
unsigned count;
// Output "Enter UART" command via Command port
MPU_SendCommand( MPU_CmdEnterUART );
// Wait for status port to be ready for read
count = 0xffff;
while( count > 0 )
{
if ( !( inp( port ) & MPU_ReadyToRead ) )
{
port--;
// Check for a successful reset
if ( inp( port ) == MPU_CmdAcknowledge )
{
return( MPU_Ok );
}
port++;
}
count--;
}
// Failed to reset : MPU-401 not detected
return( MPU_UARTFailed );
}
/*---------------------------------------------------------------------
Function: MPU_Init
Detects and initializes the MPU401 card.
---------------------------------------------------------------------*/
int MPU_Init
(
int addr
)
{
int status;
int count;
char *ptr;
ptr = USER_GetText( "MPUDELAY" );
if ( ptr != NULL )
{
MPU_Delay = ( unsigned )atol( ptr );
}
MPU_BaseAddr = addr;
count = 4;
while( count > 0 )
{
status = MPU_Reset();
if ( status == MPU_Ok )
{
return( MPU_EnterUART() );
}
count--;
}
return( status );
}
/*---------------------------------------------------------------------
Function: MPU_LockEnd
Used for determining the length of the functions to lock in memory.
---------------------------------------------------------------------*/
static void MPU_LockEnd
(
void
)
{
}
/*---------------------------------------------------------------------
Function: MPU_UnlockMemory
Locks all neccessary data.
---------------------------------------------------------------------*/
void MPU_UnlockMemory
(
void
)
{
DPMI_UnlockMemoryRegion( MPU_LockStart, MPU_LockEnd );
DPMI_Unlock( MPU_BaseAddr );
DPMI_Unlock( MPU_Delay );
}
/*---------------------------------------------------------------------
Function: MPU_LockMemory
Locks all neccessary data.
---------------------------------------------------------------------*/
int MPU_LockMemory
(
void
)
{
int status;
status = DPMI_LockMemoryRegion( MPU_LockStart, MPU_LockEnd );
status |= DPMI_Lock( MPU_BaseAddr );
status |= DPMI_Lock( MPU_Delay );
if ( status != DPMI_Ok )
{
MPU_UnlockMemory();
return( MPU_Error );
}
return( MPU_Ok );
}