/ source / audiolib / src / driver_adlib.cpp
driver_adlib.cpp
  1  /*
  2  Copyright (C) 1994-1995 Apogee Software, Ltd.
  3  Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
  4  Copyright (C) EDuke32 developers and contributors
  5  
  6  This program is free software; you can redistribute it and/or
  7  modify it under the terms of the GNU General Public License
  8  as published by the Free Software Foundation; either version 2
  9  of the License, or (at your option) any later version.
 10  
 11  This program is distributed in the hope that it will be useful,
 12  but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 14  
 15  See the GNU General Public License for more details.
 16  
 17  You should have received a copy of the GNU General Public License
 18  along with this program; if not, write to the Free Software
 19  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 20  
 21  */
 22  /**********************************************************************
 23     module: AL_MIDI.C
 24  
 25     author: James R. Dose
 26     date:   April 1, 1994
 27  
 28     Low level routines to support General MIDI music on AdLib compatible
 29     cards.
 30  
 31     (c) Copyright 1994 James R. Dose.  All Rights Reserved.
 32  **********************************************************************/
 33  
 34  #include "driver_adlib.h"
 35  
 36  #include "_al_midi.h"
 37  #include "_multivc.h"
 38  #include "compat.h"
 39  #include "midi.h"
 40  #include "midifuncs.h"
 41  #include "opl3.h"
 42  #include "opl3_reg.h"
 43  
 44  enum
 45  {
 46     AdLibErr_Error   = -1,
 47     AdLibErr_Ok      = 0,
 48  };
 49  
 50  static int AL_Volume = MIDI_MaxVolume;
 51  static opl3_chip AL_Chip;
 52  
 53  static void AL_Shutdown(void);
 54  static int ErrorCode;
 55  
 56  int AdLibDrv_GetError(void) { return ErrorCode; }
 57  
 58  const char *AdLibDrv_ErrorString(int const ErrorNumber)
 59  {
 60      switch (ErrorNumber)
 61      {
 62          case AdLibErr_Error: return AdLibDrv_ErrorString(ErrorCode);
 63          case AdLibErr_Ok:    return "AdLib ok.";
 64          default:             return "Unknown AdLib error.";
 65      }
 66  }
 67  
 68  int AdLibDrv_MIDI_Init(midifuncs * const funcs)
 69  {
 70      AdLibDrv_MIDI_Shutdown();
 71      Bmemset(funcs, 0, sizeof(midifuncs));
 72  
 73      funcs->NoteOff           = AL_NoteOff;
 74      funcs->NoteOn            = AL_NoteOn;
 75      funcs->PolyAftertouch    = nullptr;
 76      funcs->ControlChange     = AL_ControlChange;
 77      funcs->ProgramChange     = AL_ProgramChange;
 78      funcs->ChannelAftertouch = nullptr;
 79      funcs->PitchBend         = AL_SetPitchBend;
 80      funcs->SetVolume         = AL_SetVolume;
 81  
 82      AL_Volume = MIDI_MaxVolume;
 83  
 84      return AdLibErr_Ok;
 85  }
 86  
 87  void AdLibDrv_MIDI_HaltPlayback(void) { MV_UnhookMusicRoutine(); }
 88  
 89  void AdLibDrv_MIDI_Shutdown(void)
 90  {
 91      AdLibDrv_MIDI_HaltPlayback();
 92      AL_Shutdown();
 93  }
 94  
 95  int AdLibDrv_MIDI_StartPlayback(void)
 96  {
 97      AdLibDrv_MIDI_HaltPlayback();
 98  
 99      AL_Init();
100      MV_HookMusicRoutine(AdLibDrv_MIDI_Service);
101  
102      return MIDI_Ok;
103  }
104  
105  void AdLibDrv_MIDI_SetTempo(int const tempo, int const division)
106  {
107      MV_MIDIRenderTempo = tempo * division / 60;
108      MV_MIDIRenderTimer = 0;
109  }
110  
111  void AdLibDrv_MIDI_Service(void)
112  {
113      int16_t * buffer16 = (int16_t *)MV_MusicBuffer;
114  
115      for (int i = 0; i < MV_MIXBUFFERSIZE; i++)
116      {
117          int16_t buf[2];
118          while (MV_MIDIRenderTimer >= MV_MixRate)
119          {
120              if (MV_MIDIRenderTempo >= 0)
121                  MIDI_ServiceRoutine();
122              MV_MIDIRenderTimer -= MV_MixRate;
123          }
124          if (MV_MIDIRenderTempo >= 0) MV_MIDIRenderTimer += MV_MIDIRenderTempo;
125          OPL3_GenerateResampled(&AL_Chip, buf);
126          if (MV_Channels == 2)
127          {
128              *buffer16++ = clamp((buf[0] * AL_PostAmp * AL_Volume * (1.f / MIDI_MaxVolume)), INT16_MIN, INT16_MAX);
129              *buffer16++ = clamp((buf[1] * AL_PostAmp * AL_Volume * (1.f / MIDI_MaxVolume)), INT16_MIN, INT16_MAX);
130          }
131          else
132              *buffer16++ = clamp(((buf[0] + buf[1]) * AL_PostAmp * AL_Volume * (.5f / MIDI_MaxVolume)), INT16_MIN, INT16_MAX);
133      }
134  }
135  
136  
137  /* Definition of octave information to be ORed onto F-Number */
138  
139  static uint32_t constexpr OctavePitch[MAX_OCTAVE+1] = {
140      0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00,
141  };
142  
143  static uint32_t NoteMod12[MAX_NOTE+1];
144  static uint32_t NoteDiv12[MAX_NOTE+1];
145  
146  // Pitch table
147  
148  //static unsigned NotePitch[FINETUNE_MAX+1][12] =
149  //   {
150  //      { C, C_SHARP, D, D_SHARP, E, F, F_SHARP, G, G_SHARP, A, A_SHARP, B },
151  //   };
152  
153  static uint32_t constexpr NotePitch[FINETUNE_MAX+1][12] = {
154      { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287 },
155      { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x242, 0x264, 0x288 },
156      { 0x158, 0x16c, 0x182, 0x199, 0x1b1, 0x1cb, 0x1e6, 0x203, 0x221, 0x243, 0x265, 0x289 },
157      { 0x158, 0x16c, 0x183, 0x19a, 0x1b2, 0x1cc, 0x1e7, 0x204, 0x222, 0x244, 0x266, 0x28a },
158      { 0x159, 0x16d, 0x183, 0x19a, 0x1b3, 0x1cd, 0x1e8, 0x205, 0x223, 0x245, 0x267, 0x28b },
159      { 0x15a, 0x16e, 0x184, 0x19b, 0x1b3, 0x1ce, 0x1e9, 0x206, 0x224, 0x246, 0x268, 0x28c },
160      { 0x15a, 0x16e, 0x185, 0x19c, 0x1b4, 0x1ce, 0x1ea, 0x207, 0x225, 0x247, 0x269, 0x28e },
161      { 0x15b, 0x16f, 0x185, 0x19d, 0x1b5, 0x1cf, 0x1eb, 0x208, 0x226, 0x248, 0x26a, 0x28f },
162      { 0x15b, 0x170, 0x186, 0x19d, 0x1b6, 0x1d0, 0x1ec, 0x209, 0x227, 0x249, 0x26b, 0x290 },
163      { 0x15c, 0x170, 0x187, 0x19e, 0x1b7, 0x1d1, 0x1ec, 0x20a, 0x228, 0x24a, 0x26d, 0x291 },
164      { 0x15d, 0x171, 0x188, 0x19f, 0x1b7, 0x1d2, 0x1ed, 0x20b, 0x229, 0x24b, 0x26e, 0x292 },
165      { 0x15d, 0x172, 0x188, 0x1a0, 0x1b8, 0x1d3, 0x1ee, 0x20c, 0x22a, 0x24c, 0x26f, 0x293 },
166      { 0x15e, 0x172, 0x189, 0x1a0, 0x1b9, 0x1d4, 0x1ef, 0x20d, 0x22b, 0x24d, 0x270, 0x295 },
167      { 0x15f, 0x173, 0x18a, 0x1a1, 0x1ba, 0x1d4, 0x1f0, 0x20e, 0x22c, 0x24e, 0x271, 0x296 },
168      { 0x15f, 0x174, 0x18a, 0x1a2, 0x1bb, 0x1d5, 0x1f1, 0x20f, 0x22d, 0x24f, 0x272, 0x297 },
169      { 0x160, 0x174, 0x18b, 0x1a3, 0x1bb, 0x1d6, 0x1f2, 0x210, 0x22e, 0x250, 0x273, 0x298 },
170      { 0x161, 0x175, 0x18c, 0x1a3, 0x1bc, 0x1d7, 0x1f3, 0x211, 0x22f, 0x251, 0x274, 0x299 },
171      { 0x161, 0x176, 0x18c, 0x1a4, 0x1bd, 0x1d8, 0x1f4, 0x212, 0x230, 0x252, 0x276, 0x29b },
172      { 0x162, 0x176, 0x18d, 0x1a5, 0x1be, 0x1d9, 0x1f5, 0x212, 0x231, 0x254, 0x277, 0x29c },
173      { 0x162, 0x177, 0x18e, 0x1a6, 0x1bf, 0x1d9, 0x1f5, 0x213, 0x232, 0x255, 0x278, 0x29d },
174      { 0x163, 0x178, 0x18f, 0x1a6, 0x1bf, 0x1da, 0x1f6, 0x214, 0x233, 0x256, 0x279, 0x29e },
175      { 0x164, 0x179, 0x18f, 0x1a7, 0x1c0, 0x1db, 0x1f7, 0x215, 0x235, 0x257, 0x27a, 0x29f },
176      { 0x164, 0x179, 0x190, 0x1a8, 0x1c1, 0x1dc, 0x1f8, 0x216, 0x236, 0x258, 0x27b, 0x2a1 },
177      { 0x165, 0x17a, 0x191, 0x1a9, 0x1c2, 0x1dd, 0x1f9, 0x217, 0x237, 0x259, 0x27c, 0x2a2 },
178      { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1de, 0x1fa, 0x218, 0x238, 0x25a, 0x27e, 0x2a3 },
179      { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1df, 0x1fb, 0x219, 0x239, 0x25b, 0x27f, 0x2a4 },
180      { 0x167, 0x17c, 0x193, 0x1ab, 0x1c4, 0x1e0, 0x1fc, 0x21a, 0x23a, 0x25c, 0x280, 0x2a6 },
181      { 0x168, 0x17d, 0x194, 0x1ac, 0x1c5, 0x1e0, 0x1fd, 0x21b, 0x23b, 0x25d, 0x281, 0x2a7 },
182      { 0x168, 0x17d, 0x194, 0x1ad, 0x1c6, 0x1e1, 0x1fe, 0x21c, 0x23c, 0x25e, 0x282, 0x2a8 },
183      { 0x169, 0x17e, 0x195, 0x1ad, 0x1c7, 0x1e2, 0x1ff, 0x21d, 0x23d, 0x260, 0x283, 0x2a9 },
184      { 0x16a, 0x17f, 0x196, 0x1ae, 0x1c8, 0x1e3, 0x1ff, 0x21e, 0x23e, 0x261, 0x284, 0x2ab },
185      { 0x16a, 0x17f, 0x197, 0x1af, 0x1c8, 0x1e4, 0x200, 0x21f, 0x23f, 0x262, 0x286, 0x2ac }
186  };
187  
188  // Slot numbers as a function of the voice and the operator.
189  // ( melodic only)
190  
191  static int constexpr slotVoice[NUMADLIBVOICES][2] = {
192      { 0, 3 },    // voice 0
193      { 1, 4 },    // 1
194      { 2, 5 },    // 2
195      { 6, 9 },    // 3
196      { 7, 10 },   // 4
197      { 8, 11 },   // 5
198      { 12, 15 },  // 6
199      { 13, 16 },  // 7
200      { 14, 17 },  // 8
201  };
202  
203  static int VoiceLevel[AL_NumChipSlots][2];
204  static int VoiceKsl[AL_NumChipSlots][2];
205  
206  // This table gives the offset of each slot within the chip.
207  // offset = fn( slot)
208  
209  static int8_t constexpr offsetSlot[AL_NumChipSlots] = { 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21 };
210  
211  static int VoiceReserved[NUMADLIBVOICES * 2];
212  
213  static AdLibVoice     Voice[NUMADLIBVOICES * 2];
214  static AdLibVoiceList Voice_Pool;
215  
216  static AdLibChannel Channel[NUMADLIBCHANNELS];
217  
218  static int constexpr AL_LeftPort  = ADLIB_PORT;
219  static int constexpr AL_RightPort = ADLIB_PORT + 2;
220  
221  static int constexpr AL_MaxMidiChannel = ARRAY_SIZE(Channel);
222  
223  int AL_Stereo = TRUE;
224  int AL_AdditiveMode;
225  
226  float AL_PostAmp = 3.f;
227  
228  // TODO: clean up this shit...
229  #define OFFSET(structure, offset) (*((char **)&(structure)[offset]))
230  
231  #define LL_AddToTail(type, listhead, node)                                                                                 \
232      LL_AddNode((char *)(node), (char **)&((listhead)->end), (char **)&((listhead)->start), (intptr_t)offsetof(type, prev), \
233                 (intptr_t)offsetof(type, next))
234  
235  #define LL_Remove(type, listhead, node)                                                                                       \
236      LL_RemoveNode((char *)(node), (char **)&((listhead)->start), (char **)&((listhead)->end), (intptr_t)offsetof(type, next), \
237                    (intptr_t)offsetof(type, prev))
238  
239  static void LL_RemoveNode(char * __restrict item, char ** __restrict head, char ** __restrict tail, intptr_t next, intptr_t prev)
240  {
241      if (OFFSET(item, prev) == nullptr)
242          *head = OFFSET(item, next);
243      else
244          OFFSET(OFFSET(item, prev), next) = OFFSET(item, next);
245  
246      if (OFFSET(item, next) == nullptr)
247          *tail = OFFSET(item, prev);
248      else
249          OFFSET(OFFSET(item, next), prev) = OFFSET(item, prev);
250  
251      OFFSET(item, next) = nullptr;
252      OFFSET(item, prev) = nullptr;
253  }
254  
255  static void LL_AddNode(char * __restrict item, char ** __restrict head, char ** __restrict tail, intptr_t next, intptr_t prev)
256  {
257      OFFSET(item, prev) = nullptr;
258      OFFSET(item, next) = *head;
259  
260      if (*head)
261          OFFSET(*head, prev) = item;
262      else
263          *tail = item;
264  
265      *head = item;
266  }
267  
268  
269  static FORCE_INLINE void AL_SendOutputToPort(int const port, int const reg, int const data)
270  {
271      OPL3_WriteRegBuffered(&AL_Chip, (uint16_t)(reg + ((port & 2) << 7)), (uint8_t)data);
272  }
273  
274  
275  static FORCE_INLINE void AL_SendOutput(int const voice, int const reg, int const data)
276  {
277      AL_SendOutputToPort(voice ? AL_LeftPort : AL_RightPort, reg, data);
278  }
279  
280  
281  static void AL_SetVoiceTimbre(int const voice)
282  {
283      int const channel = Voice[voice].channel;
284      int const patch = (channel == 9) ? Voice[voice].key + 128 : Channel[channel].Timbre;
285  
286      if (Voice[voice].timbre == patch)
287          return;
288  
289      Voice[voice].timbre = patch;
290  
291      auto const timbre = &ADLIB_TimbreBank[patch];
292  
293      int const port = Voice[voice].port;
294      int const voc  = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
295      int       slot = slotVoice[voc][0];
296      int       off  = offsetSlot[slot];
297  
298      VoiceLevel[slot][port] = OPL3_TOTAL_LEVEL_MASK - (timbre->Level[0] & OPL3_TOTAL_LEVEL_MASK);
299      VoiceKsl[slot][port]   = timbre->Level[0] & OPL3_KSL_MASK;
300  
301      AL_SendOutput(port, OPL3_FNUM_LOW + voc, 0);
302      AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, 0);
303  
304      // Let voice clear the release
305      AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, 0xff);
306  
307      AL_SendOutput(port, OPL3_ATTACK_DECAY + off, timbre->Env1[0]);
308      AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, timbre->Env2[0]);
309      AL_SendOutput(port, OPL3_ENABLE_WAVE_SELECT + off, timbre->SAVEK[0]);
310      AL_SendOutput(port, OPL3_WAVE_SELECT + off, timbre->Wave[0]);
311  
312      AL_SendOutput(port, OPL3_KSL_LEVEL + off, timbre->Level[0]);
313      slot = slotVoice[voc][1];
314  
315      AL_SendOutput(port, OPL3_FEEDBACK_CONNECTION + voc,
316          (timbre->Feedback & (OPL3_FEEDBACK_MASK | OPL3_CONNECTION_BIT)) | OPL3_STEREO_BITS);
317  
318      off = offsetSlot[slot];
319  
320      VoiceLevel[slot][port] = OPL3_TOTAL_LEVEL_MASK - (timbre->Level[1] & OPL3_TOTAL_LEVEL_MASK);
321      VoiceKsl[slot][port]   = timbre->Level[1] & OPL3_KSL_MASK;
322  
323      AL_SendOutput(port, OPL3_KSL_LEVEL + off, OPL3_TOTAL_LEVEL_MASK);
324  
325      // Let voice clear the release
326      AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, 0xff);
327  
328      AL_SendOutput(port, OPL3_ATTACK_DECAY + off, timbre->Env1[1]);
329      AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, timbre->Env2[1]);
330      AL_SendOutput(port, OPL3_ENABLE_WAVE_SELECT + off, timbre->SAVEK[1]);
331      AL_SendOutput(port, OPL3_WAVE_SELECT + off, timbre->Wave[1]);
332  }
333  
334  
335  static void AL_SetVoiceVolume(int const voice)
336  {
337      int  const channel  = Voice[voice].channel;
338      auto const timbre   = &ADLIB_TimbreBank[Voice[voice].timbre];
339      int  const velocity = min<int>(Voice[voice].velocity + timbre->Velocity, MAX_VELOCITY);
340  
341      int const voc  = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
342      int const slot = slotVoice[voc][1];
343      int const port = Voice[voice].port;
344  
345      // amplitude
346      auto t1 = (uint32_t)VoiceLevel[slot][port] * (velocity + 0x80);
347      t1 = (Channel[channel].Volume * t1) >> 15;
348  
349      uint32_t volume = t1 ^ OPL3_TOTAL_LEVEL_MASK;
350      volume |= (uint32_t)VoiceKsl[slot][port];
351  
352      AL_SendOutput(port, OPL3_KSL_LEVEL + offsetSlot[slot], volume);
353  
354      // Check if this timbre is Additive
355      if (timbre->Feedback & 0x01)
356      {
357          int const slot = slotVoice[voc][0];
358          uint32_t t2;
359  
360          // amplitude
361          if (AL_AdditiveMode)
362              t1 = (uint32_t)VoiceLevel[slot][port] * (velocity + 0x80);
363  
364          t2 = (Channel[channel].Volume * t1) >> 15;
365  
366          volume = t2 ^ OPL3_TOTAL_LEVEL_MASK;
367          volume |= (uint32_t)VoiceKsl[slot][port];
368  
369          AL_SendOutput(port, OPL3_KSL_LEVEL + offsetSlot[slot], volume);
370      }
371  }
372  
373  
374  static int AL_AllocVoice(void)
375  {
376      if (!Voice_Pool.start)
377          return AL_VoiceNotFound;
378  
379      int const voice = Voice_Pool.start->num;
380      LL_Remove(AdLibVoice, &Voice_Pool, &Voice[voice]);
381      return voice;
382  }
383  
384  
385  static int AL_GetVoice(int const channel, int const key)
386  {
387      auto const *voice = Channel[channel].Voices.start;
388  
389      while (voice != nullptr)
390      {
391          if (voice->key == (uint32_t)key)
392              return  voice->num;
393          voice = voice->next;
394      }
395  
396      return  AL_VoiceNotFound;
397  }
398  
399  
400  static void AL_SetVoicePitch(int const voice)
401  {
402      int const port    = Voice[voice].port;
403      int const voc     = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
404      int const channel = Voice[voice].channel;
405  
406      int patch, note;
407  
408      if (channel == 9)
409      {
410          patch = Voice[voice].key + 128;
411          note  = ADLIB_TimbreBank[patch].Transpose;
412      }
413      else
414      {
415          patch = Channel[channel].Timbre;
416          note  = Voice[voice].key + ADLIB_TimbreBank[patch].Transpose;
417      }
418  
419      note += Channel[channel].KeyOffset - 12;
420      note = clamp(note, 0, MAX_NOTE);
421  
422      int detune = Channel[channel].KeyDetune;
423  
424      int ScaleNote = NoteMod12[note];
425      int Octave    = NoteDiv12[note];
426  
427      int pitch = OctavePitch[Octave] | NotePitch[detune][ScaleNote];
428  
429      Voice[voice].pitchleft = pitch;
430  
431      pitch |= Voice[voice].status;
432  
433      AL_SendOutput(port, OPL3_FNUM_LOW + voc, pitch);
434      AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, pitch >> 8);
435  }
436  
437  static void AL_SetVoicePan(int const voice)
438  {
439      int const port    = Voice[voice].port;
440      int const voc     = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
441      int const channel = Voice[voice].channel;
442  
443      if (AL_Stereo)
444          AL_SendOutput(port, 0xD0 + voc, Channel[channel].Pan << 1);
445  }
446  
447  
448  static void AL_SetChannelVolume(int const channel, int const volume)
449  {
450      Channel[channel].Volume = clamp(volume, 0, AL_MaxVolume);
451  
452      auto voice = Channel[channel].Voices.start;
453  
454      while (voice != nullptr)
455      {
456          AL_SetVoiceVolume(voice->num);
457          voice = voice->next;
458      }
459  }
460  
461  
462  static void AL_SetChannelPan(int const channel, int const pan)
463  {
464      // Don't pan drum sounds
465      if (channel != 9)
466          Channel[channel].Pan = pan;
467  
468      auto voice = Channel[channel].Voices.start;
469      while (voice != nullptr)
470      {
471          AL_SetVoicePan(voice->num);
472          voice = voice->next;
473      }
474  }
475  
476  
477  static void AL_SetChannelDetune(int const channel, int const detune) { Channel[channel].Detune = detune; }
478  
479  
480  static void AL_ResetVoices(void)
481  {
482      Voice_Pool.start = nullptr;
483      Voice_Pool.end   = nullptr;
484  
485      int const numvoices = NUMADLIBVOICES * 2;
486  
487      for (int index = 0; index < numvoices; index++)
488      {
489          if (VoiceReserved[index] == FALSE)
490          {
491              Voice[index].num      = index;
492              Voice[index].key      = 0;
493              Voice[index].velocity = 0;
494              Voice[index].channel  = -1;
495              Voice[index].timbre   = -1;
496              Voice[index].port     = (index < NUMADLIBVOICES) ? 0 : 1;
497              Voice[index].status   = NOTE_OFF;
498              LL_AddToTail(AdLibVoice, &Voice_Pool, &Voice[index]);
499          }
500      }
501  
502      for (int index = 0; index < NUMADLIBCHANNELS; index++)
503      {
504          Channel[index] = {};
505          Channel[index].Volume             = AL_DefaultChannelVolume;
506          Channel[index].Pan                = 64;
507          Channel[index].PitchBendRange     = AL_DefaultPitchBendRange;
508          Channel[index].PitchBendSemiTones = AL_DefaultPitchBendRange / 100;
509          Channel[index].PitchBendHundreds  = AL_DefaultPitchBendRange % 100;
510      }
511  }
512  
513  
514  static void AL_CalcPitchInfo(void)
515  {
516      for (int note = 0; note <= MAX_NOTE; note++)
517      {
518          NoteMod12[note] = note % 12;
519          NoteDiv12[note] = note / 12;
520      }
521  
522  #if 0
523      for (int finetune = 1; finetune <= FINETUNE_MAX; finetune++)
524      {
525          double detune = pow(2, (double)finetune / (12.0 * FINETUNE_RANGE));
526  
527          for (int note = 0; note < 12; note++)
528              NotePitch[finetune][note] = ((double)NotePitch[0][note] * detune);
529      }
530  #endif
531  }
532  
533  
534  static void AL_FlushCard(int const port)
535  {
536      for (int i = 0; i < NUMADLIBVOICES; i++)
537      {
538          if (VoiceReserved[i])
539              continue;
540  
541          auto slot1 = offsetSlot[slotVoice[i][0]];
542          auto slot2 = offsetSlot[slotVoice[i][1]];
543  
544          AL_SendOutputToPort(port, OPL3_FNUM_LOW + i, 0);
545          AL_SendOutputToPort(port, OPL3_KEYON_BLOCK + i, 0);
546  
547          AL_SendOutputToPort(port, OPL3_WAVE_SELECT + slot1, 0);
548          AL_SendOutputToPort(port, OPL3_WAVE_SELECT + slot2, 0);
549  
550          // Set the envelope to be fast and quiet
551          AL_SendOutputToPort(port, OPL3_ATTACK_DECAY + slot1, 0xff);
552          AL_SendOutputToPort(port, OPL3_ATTACK_DECAY + slot2, 0xff);
553          AL_SendOutputToPort(port, OPL3_SUSTAIN_RELEASE + slot1, 0xff);
554          AL_SendOutputToPort(port, OPL3_SUSTAIN_RELEASE + slot2, 0xff);
555  
556          // Maximum attenuation
557          AL_SendOutputToPort(port, OPL3_KSL_LEVEL + slot1, 0xff);
558          AL_SendOutputToPort(port, OPL3_KSL_LEVEL + slot2, 0xff);
559      }
560  }
561  
562  
563  static void AL_Reset(void)
564  {
565      AL_SendOutputToPort(ADLIB_PORT, 1, OPL3_ENABLE_WAVE_SELECT);
566      AL_SendOutputToPort(ADLIB_PORT, OPL3_KBD_SPLIT_REGISTER, 0);
567  
568      // Set the values: AM Depth, VIB depth & Rhythm
569      AL_SendOutputToPort(ADLIB_PORT, OPL3_PERCUSSION_REGISTER, 0);
570  
571      AL_SetStereo(AL_Stereo);
572  
573      AL_FlushCard(AL_LeftPort);
574      AL_FlushCard(AL_RightPort);
575  }
576  
577  
578  void AL_SetStereo(int const stereo) { AL_SendOutputToPort(AL_RightPort, OPL3_MODE_REGISTER, (stereo << 1) + 1); }
579  
580  
581  static void AL_NoteOff(int const channel, int const key, int velocity)
582  {
583      UNREFERENCED_PARAMETER(velocity);
584  
585      // We only play channels 1 through 10
586      if (channel >= AL_MaxMidiChannel)
587          return;
588  
589      int const voice = AL_GetVoice(channel, key);
590  
591      if (voice == AL_VoiceNotFound)
592          return;
593  
594      Voice[voice].status = NOTE_OFF;
595  
596      int const port = Voice[voice].port;
597      int const voc  = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
598  
599      AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, hibyte(Voice[voice].pitchleft));
600  
601      LL_Remove(AdLibVoice, &Channel[channel].Voices, &Voice[voice]);
602      LL_AddToTail(AdLibVoice, &Voice_Pool, &Voice[voice]);
603  }
604  
605  
606  static void AL_NoteOn(int const channel, int const key, int const velocity)
607  {
608      // We only play channels 1 through 10
609      if (channel >= AL_MaxMidiChannel)
610          return;
611  
612      if (velocity == 0)
613      {
614          AL_NoteOff(channel, key, velocity);
615          return;
616      }
617  
618      int voice = AL_AllocVoice();
619  
620      if (voice == AL_VoiceNotFound)
621      {
622          if (Channel[9].Voices.start)
623          {
624              AL_NoteOff(9, Channel[9].Voices.start->key, 0);
625              voice = AL_AllocVoice();
626          }
627  
628          if (voice == AL_VoiceNotFound)
629              return;
630      }
631  
632      Voice[voice].key      = key;
633      Voice[voice].channel  = channel;
634      Voice[voice].velocity = velocity;
635      Voice[voice].status   = NOTE_ON;
636  
637      LL_AddToTail(AdLibVoice, &Channel[channel].Voices, &Voice[voice]);
638  
639      AL_SetVoiceTimbre(voice);
640      AL_SetVoiceVolume(voice);
641      AL_SetVoicePitch(voice);
642      AL_SetVoicePan(voice);
643  }
644  
645  
646  static FORCE_INLINE void AL_AllNotesOff(int const channel)
647  {
648      while (Channel[channel].Voices.start != nullptr)
649          AL_NoteOff(channel, Channel[channel].Voices.start->key, 0);
650  }
651  
652  
653  static void AL_ControlChange(int const channel, int const type, int const data)
654  {
655      // We only play channels 1 through 10
656      if (channel >= AL_MaxMidiChannel)
657          return;
658  
659      switch (type)
660      {
661          case MIDI_VOLUME:
662              AL_SetChannelVolume(channel, data);
663              break;
664  
665          case MIDI_PAN:
666              AL_SetChannelPan(channel, data);
667              break;
668  
669          case MIDI_DETUNE:
670              AL_SetChannelDetune(channel, data);
671              break;
672  
673          case MIDI_ALL_NOTES_OFF:
674              AL_AllNotesOff(channel);
675              break;
676  
677          case MIDI_RESET_ALL_CONTROLLERS:
678              AL_ResetVoices();
679              AL_SetChannelVolume(channel, AL_DefaultChannelVolume);
680              AL_SetChannelPan(channel, 64);
681              AL_SetChannelDetune(channel, 0);
682              break;
683  
684          case MIDI_RPN_MSB:
685              Channel[channel].RPN &= 0x00FF;
686              Channel[channel].RPN |= (data & 0xFF) << 8;
687              break;
688  
689          case MIDI_RPN_LSB:
690              Channel[channel].RPN &= 0xFF00;
691              Channel[channel].RPN |= data & 0xFF;
692              break;
693  
694          case MIDI_DATAENTRY_MSB:
695              if (Channel[channel].RPN == MIDI_PITCHBEND_MSB)
696              {
697                  Channel[channel].PitchBendSemiTones = data;
698                  Channel[channel].PitchBendRange     = Channel[channel].PitchBendSemiTones * 100 + Channel[channel].PitchBendHundreds;
699              }
700              break;
701  
702          case MIDI_DATAENTRY_LSB:
703              if (Channel[channel].RPN == MIDI_PITCHBEND_LSB)
704              {
705                  Channel[channel].PitchBendHundreds = data;
706                  Channel[channel].PitchBendRange    = Channel[channel].PitchBendSemiTones * 100 + Channel[channel].PitchBendHundreds;
707              }
708              break;
709      }
710  }
711  
712  
713  static void AL_ProgramChange(int const channel, int const patch)
714  {
715      // We only play channels 1 through 10
716      if (channel >= AL_MaxMidiChannel)
717          return;
718  
719      Channel[channel].Timbre = patch;
720  }
721  
722  
723  static void AL_SetPitchBend(int const channel, int const lsb, int const msb)
724  {
725      // We only play channels 1 through 10
726      if (channel >= AL_MaxMidiChannel)
727          return;
728  
729      int const pitchbend = lsb + (msb << 8);
730      int const TotalBend = pitchbend * Channel[channel].PitchBendRange / (PITCHBEND_CENTER / FINETUNE_RANGE);
731  
732      Channel[channel].Pitchbend = pitchbend;
733      Channel[channel].KeyOffset = (int)(TotalBend / FINETUNE_RANGE);
734      Channel[channel].KeyOffset -= Channel[channel].PitchBendSemiTones;
735  
736      Channel[channel].KeyDetune = (uint32_t)(TotalBend % FINETUNE_RANGE);
737  
738      auto voice = Channel[channel].Voices.start;
739      while (voice != nullptr)
740      {
741          AL_SetVoicePitch(voice->num);
742          voice = voice->next;
743      }
744  }
745  
746  
747  static void AL_SetVolume(int volume) { AL_Volume = clamp(volume, 0, MIDI_MaxVolume); }
748  
749  
750  static void AL_Shutdown(void)
751  {
752      OPL3_Reset(&AL_Chip, MV_MixRate);
753      AL_Reset();
754      AL_ResetVoices();
755  }
756  
757  
758  static int AL_Init(void)
759  {
760      AL_Shutdown();
761      AL_CalcPitchInfo();
762  
763      return AdLibErr_Ok;
764  }
765  
766  
767  void AL_RegisterTimbreBank(uint8_t *timbres)
768  {
769      for (int i = 0; i < 256; i++)
770      {
771          ADLIB_TimbreBank[i].SAVEK[0]  = *(timbres++);
772          ADLIB_TimbreBank[i].SAVEK[1]  = *(timbres++);
773          ADLIB_TimbreBank[i].Level[0]  = *(timbres++);
774          ADLIB_TimbreBank[i].Level[1]  = *(timbres++);
775          ADLIB_TimbreBank[i].Env1[0]   = *(timbres++);
776          ADLIB_TimbreBank[i].Env1[1]   = *(timbres++);
777          ADLIB_TimbreBank[i].Env2[0]   = *(timbres++);
778          ADLIB_TimbreBank[i].Env2[1]   = *(timbres++);
779          ADLIB_TimbreBank[i].Wave[0]   = *(timbres++);
780          ADLIB_TimbreBank[i].Wave[1]   = *(timbres++);
781          ADLIB_TimbreBank[i].Feedback  = *(timbres++);
782          ADLIB_TimbreBank[i].Transpose = *(int8_t *)(timbres++);
783          ADLIB_TimbreBank[i].Velocity  = *(int8_t *)(timbres++);
784      }
785  }