mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-02-07 00:27:10 +00:00
347 lines
8.6 KiB
C
347 lines
8.6 KiB
C
#define delay(x) Sleep(x)
|
|
|
|
const //List of FNumbers
|
|
uint16_t FNr[12] = {
|
|
/*C*/ 343,
|
|
/*C#/Db*/ 363,
|
|
/*D*/ 385,
|
|
/*D#/Eb*/ 408,
|
|
/*E*/ 432,
|
|
/*F*/ 458,
|
|
/*F#/Gb*/ 485,
|
|
/*G*/ 514,
|
|
/*G#/Ab*/ 544,
|
|
/*A*/ 577,
|
|
/*A#/Bb*/ 611,
|
|
/*B*/ 647 };
|
|
|
|
//Flat Whole Sharp}
|
|
#define C 0
|
|
#define CSharp 1
|
|
#define DFlat 1
|
|
#define D 2
|
|
#define DSharp 3
|
|
#define EFlat 3
|
|
#define E 4
|
|
#define F 5
|
|
#define FSharp 6
|
|
#define GFlat 6
|
|
#define G 7
|
|
#define GSharp 8
|
|
#define AFlat 8
|
|
#define A 9
|
|
#define ASharp 10
|
|
#define BFlat 10
|
|
#define B 11
|
|
|
|
|
|
struct Operator {
|
|
uint8_t
|
|
//Tremolo
|
|
Tremolo,
|
|
//Vibrato
|
|
Vibrato,
|
|
//Envelop generator type
|
|
EGType,
|
|
//KSR
|
|
KSR,
|
|
//Frequency multiplier
|
|
Multi,
|
|
//Key scaling level
|
|
KSL,
|
|
//Volume
|
|
TotalLevel,
|
|
//Shape of the wave envelop
|
|
Attack, Decay, Sustain, Release,
|
|
//Type of wave
|
|
WaveShape;
|
|
};
|
|
|
|
struct Instrument {
|
|
struct Operator Modulator, Carrier;
|
|
|
|
uint8_t
|
|
//Feedback strength
|
|
Feedback,
|
|
//Synthesis type
|
|
SynType;
|
|
};
|
|
|
|
|
|
struct Instrument Flute, Piano, Harp;
|
|
uint8_t CurNote, CurBlock;
|
|
|
|
/**************************************************************************
|
|
** Writes a value to a specified index register on the FM card **
|
|
**************************************************************************/
|
|
void WriteFM(uint8_t Register, uint8_t Value)
|
|
{
|
|
OPL3Write(0, Register);
|
|
OPL3Write(1, Value);
|
|
|
|
// unsigned char Counter;
|
|
|
|
//Select register
|
|
// outportb(0x388, Register);
|
|
//Wait for card to accept value
|
|
// for (Counter = 1; Counter < 25; Counter++) { inportb(0x388); }
|
|
//Send value
|
|
// outportb(0x389, Value);
|
|
//Wait for card to accept value
|
|
// for (Counter = 1; Counter < 100; Counter++) { inportb(0x388); }
|
|
}
|
|
|
|
/**************************************************************************
|
|
** Checks for the presence of an FM card **
|
|
**************************************************************************/
|
|
uint8_t FMInstalled()
|
|
{
|
|
|
|
// unsigned char A, B;
|
|
|
|
// WriteFM(1, 0);
|
|
// WriteFM(4, 0x60);
|
|
// WriteFM(4, 0x80);
|
|
// A = inportb(0x388);
|
|
// A = OPL3Read(0);
|
|
// WriteFM(2, 0xFF);
|
|
// WriteFM(4, 0x21);
|
|
// B = inportb(0x388);
|
|
// OPL3TimerOver(0);
|
|
// B = OPL3Read(0);
|
|
// WriteFM(4, 0x60);
|
|
// WriteFM(4, 0x80);
|
|
// if ((A & 0xE0) == 0 && (B & 0xE0) == 0xC0) {
|
|
return (1);
|
|
// }
|
|
// else {
|
|
// return (0);
|
|
// }
|
|
}
|
|
|
|
/**************************************************************************
|
|
** Activates a voice on the FM card **
|
|
***************************************************************************
|
|
** Voice selects one of the 9 FM voices **
|
|
** FNumber selects the note to be played **
|
|
** Block selects the octave for the specified note **
|
|
**************************************************************************/
|
|
void NoteOn(uint8_t Voice, uint8_t Note, uint8_t Block)
|
|
{
|
|
WriteFM(0xA0 + Voice, FNr[Note] & 0xFF);
|
|
WriteFM(0xB0 + Voice, (FNr[Note] >> 8) + (Block << 2) + 32);
|
|
}
|
|
|
|
/**************************************************************************
|
|
** Deactivates a voice on the FM card **
|
|
***************************************************************************
|
|
** Make sure to give the same values for Note and Block or this will **
|
|
** sound very odd. **
|
|
**************************************************************************/
|
|
void NoteOff(uint8_t Voice, uint8_t Note, uint8_t Block)
|
|
{
|
|
WriteFM(0xA0 + Voice, FNr[Note] & 0xFF);
|
|
WriteFM(0xB0 + Voice, (FNr[Note] >> 8) + (Block << 2));
|
|
}
|
|
|
|
/**************************************************************************
|
|
** Sets instrument settings for a voice on the FM card **
|
|
**************************************************************************/
|
|
const static unsigned char OpAdr[9] = { 0, 1, 2, 8, 9, 10, 16, 17, 18 }; //Addresses of the operators used to form voice data
|
|
void SetInstrument(uint8_t Voice, struct Instrument *Instr)
|
|
{
|
|
uint8_t Value;
|
|
|
|
//Set up voice modulator
|
|
Value = Instr->Modulator.Tremolo << 8
|
|
| Instr->Modulator.Vibrato << 7
|
|
| Instr->Modulator.EGType << 6
|
|
| Instr->Modulator.KSR << 5
|
|
| Instr->Modulator.Multi;
|
|
WriteFM(0x20 + OpAdr[Voice], Value);
|
|
|
|
Value = Instr->Modulator.KSL << 7
|
|
| Instr->Modulator.TotalLevel;
|
|
WriteFM(0x40 + OpAdr[Voice], Value);
|
|
|
|
Value = Instr->Modulator.Attack << 4
|
|
| Instr->Modulator.Decay;
|
|
WriteFM(0x60 + OpAdr[Voice], Value);
|
|
|
|
Value = Instr->Modulator.Sustain << 4
|
|
| Instr->Modulator.Release;
|
|
WriteFM(0x80 + OpAdr[Voice], Value);
|
|
|
|
WriteFM(0xE0 + OpAdr[Voice], Instr->Modulator.WaveShape);
|
|
|
|
Value = Instr->Feedback << 1
|
|
| Instr->SynType;
|
|
WriteFM(0xC0 + OpAdr[Voice], Value);
|
|
|
|
//Set up voice carrier
|
|
Value = Instr->Carrier.Tremolo << 8
|
|
| Instr->Carrier.Vibrato << 7
|
|
| Instr->Carrier.EGType << 6
|
|
| Instr->Carrier.KSR << 5
|
|
| Instr->Carrier.Multi;
|
|
WriteFM(0x23 + OpAdr[Voice], Value);
|
|
|
|
Value = Instr->Carrier.KSL << 7
|
|
| Instr->Carrier.TotalLevel;
|
|
WriteFM(0x43 + OpAdr[Voice], Value);
|
|
|
|
Value = Instr->Carrier.Attack << 4
|
|
| Instr->Carrier.Decay;
|
|
WriteFM(0x63 + OpAdr[Voice], Value);
|
|
|
|
Value = Instr->Carrier.Sustain << 4
|
|
| Instr->Carrier.Release;
|
|
WriteFM(0x83 + OpAdr[Voice], Value);
|
|
|
|
WriteFM(0xE3 + OpAdr[Voice], Instr->Carrier.WaveShape);
|
|
}
|
|
|
|
void test()
|
|
{
|
|
// clrscr();
|
|
again:
|
|
printf("Demonstration of programming a FM sound card [AdLib, SB and compatibles]\n");
|
|
printf("--------------------------------------------------------------------------\n");
|
|
|
|
//Check to see if an FM sound card is present
|
|
/* if (FMInstalled()) {
|
|
printf("AdLib/SB or compatible FM sound card found.\n");
|
|
}
|
|
else {
|
|
//If not, end the programme
|
|
printf("AdLib/SB or compatible FM sound card not found.\n");
|
|
return;
|
|
}
|
|
*/
|
|
//Set up voices 0 - 3 to a "harp" - note, only the values other than 0 are set
|
|
Harp.Modulator.Attack = 15;
|
|
Harp.Modulator.Decay = 5;
|
|
Harp.Modulator.Sustain = 8;
|
|
Harp.Modulator.Release = 5;
|
|
Harp.Modulator.Multi = 2;
|
|
Harp.Modulator.TotalLevel = 41;
|
|
|
|
Harp.Carrier.Attack = 15;
|
|
Harp.Carrier.Decay = 2;
|
|
Harp.Carrier.Release = 3;
|
|
Harp.Carrier.Multi = 1;
|
|
Harp.Carrier.KSL = 2;
|
|
Harp.Carrier.TotalLevel = 3;
|
|
|
|
SetInstrument(0, &Harp);
|
|
SetInstrument(1, &Harp);
|
|
SetInstrument(2, &Harp);
|
|
|
|
//Play C chord using Harp
|
|
printf("Playing C chord.\n");
|
|
|
|
NoteOn(0, C, 4);
|
|
NoteOn(1, E, 4);
|
|
NoteOn(2, G, 4);
|
|
delay(1000); //Wait 1 second
|
|
NoteOff(0, C, 4);
|
|
NoteOff(1, E, 4);
|
|
NoteOff(2, G, 4);
|
|
//Wait a while
|
|
delay(500);
|
|
|
|
//Set up voice 3 to a "piano" - this doesn't really sound like a piano,
|
|
//but that's what they call it!
|
|
Piano.Modulator.Attack = 15;
|
|
Piano.Modulator.Decay = 1;
|
|
Piano.Modulator.Sustain = 10;
|
|
Piano.Modulator.Release = 3;
|
|
Piano.Modulator.Multi = 1;
|
|
Piano.Modulator.KSL = 1;
|
|
Piano.Modulator.TotalLevel = 16;
|
|
|
|
Piano.Carrier.Attack = 13;
|
|
Piano.Carrier.Decay = 2;
|
|
Piano.Carrier.Sustain = 8;
|
|
Piano.Carrier.Release = 4;
|
|
Piano.Carrier.Multi = 1;
|
|
Piano.Carrier.TotalLevel = 0;
|
|
Piano.Carrier.KSR = 1;
|
|
|
|
Piano.Feedback = 3;
|
|
|
|
SetInstrument(3, &Piano);
|
|
|
|
//Play all notes in octave 4 for .1 seconds using piano [voice 3]
|
|
printf("Playing all notes in octave four.\n");
|
|
CurBlock = 4;
|
|
for (CurNote = 0; CurNote < 12; CurNote++) {
|
|
NoteOn(3, CurNote, CurBlock);
|
|
delay(100); //Wait .1 seconds
|
|
NoteOff(3, CurNote, CurBlock);
|
|
}
|
|
|
|
//Wait a while
|
|
delay(500);
|
|
//Set up voice 4 to a "flute"
|
|
Flute.Modulator.Attack = 6;
|
|
Flute.Modulator.Decay = 14;
|
|
Flute.Modulator.Sustain = 7;
|
|
Flute.Modulator.Release = 15;
|
|
Flute.Modulator.Vibrato = 1;
|
|
Flute.Modulator.Tremolo = 1;
|
|
Flute.Modulator.EGType = 1;
|
|
Flute.Modulator.KSL = 3;
|
|
Flute.Modulator.TotalLevel = 44;
|
|
|
|
Flute.Carrier.Attack = 6;
|
|
Flute.Carrier.Decay = 5;
|
|
Flute.Carrier.Sustain = 13;
|
|
Flute.Carrier.Release = 10;
|
|
Flute.Carrier.Vibrato = 1;
|
|
Flute.Carrier.EGType = 1;
|
|
Flute.Carrier.Multi = 1;
|
|
Flute.Carrier.TotalLevel = 0;
|
|
|
|
Flute.Feedback = 7;
|
|
Flute.SynType = 3;
|
|
|
|
SetInstrument(4, &Flute);
|
|
|
|
//Play short tune using Flute [voice 4] as primary, Harp [voice 0] as secondary voice
|
|
printf("Playing short tune.\n");
|
|
|
|
NoteOn(4, C, 5); NoteOn(0, C, 3);
|
|
delay(250);
|
|
NoteOff(4, C, 5);
|
|
NoteOn(4, E, 5);
|
|
delay(250);
|
|
NoteOff(4, E, 5); NoteOff(0, C, 3);
|
|
|
|
NoteOn(4, C, 5); NoteOn(0, G, 3);
|
|
delay(250);
|
|
NoteOff(4, C, 5);
|
|
NoteOn(4, G, 4);
|
|
delay(250);
|
|
NoteOff(4, G, 4); NoteOff(0, G, 3);
|
|
|
|
NoteOn(4, E, 4); NoteOn(0, C, 4);
|
|
delay(250);
|
|
NoteOff(4, E, 4);
|
|
NoteOn(4, G, 4);
|
|
delay(250);
|
|
NoteOff(4, G, 4); NoteOff(0, C, 4);
|
|
|
|
NoteOn(4, E, 4); NoteOn(0, G, 3);
|
|
delay(250);
|
|
NoteOff(4, E, 4);
|
|
NoteOn(4, D, 4);
|
|
delay(250);
|
|
NoteOff(4, D, 4); NoteOff(0, G, 3);
|
|
|
|
NoteOn(4, C, 4); NoteOn(0, C, 3);
|
|
delay(2000);
|
|
NoteOff(4, C, 4); NoteOff(0, C, 3);
|
|
goto again;
|
|
}
|