opl3_drums.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) by Uros Bizjak <uros@kss-loka.si>
  4. *
  5. * OPL2/OPL3/OPL4 FM routines for internal percussion channels
  6. */
  7. #include "opl3_voice.h"
  8. static const char snd_opl3_drum_table[47] =
  9. {
  10. OPL3_BASSDRUM_ON, OPL3_BASSDRUM_ON, OPL3_HIHAT_ON, /* 35 - 37 */
  11. OPL3_SNAREDRUM_ON, OPL3_HIHAT_ON, OPL3_SNAREDRUM_ON, /* 38 - 40 */
  12. OPL3_BASSDRUM_ON, OPL3_HIHAT_ON, OPL3_BASSDRUM_ON, /* 41 - 43 */
  13. OPL3_HIHAT_ON, OPL3_TOMTOM_ON, OPL3_HIHAT_ON, /* 44 - 46 */
  14. OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, OPL3_CYMBAL_ON, /* 47 - 49 */
  15. OPL3_TOMTOM_ON, OPL3_CYMBAL_ON, OPL3_CYMBAL_ON, /* 50 - 52 */
  16. OPL3_CYMBAL_ON, OPL3_CYMBAL_ON, OPL3_CYMBAL_ON, /* 53 - 55 */
  17. OPL3_HIHAT_ON, OPL3_CYMBAL_ON, OPL3_TOMTOM_ON, /* 56 - 58 */
  18. OPL3_CYMBAL_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 59 - 61 */
  19. OPL3_HIHAT_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 62 - 64 */
  20. OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 65 - 67 */
  21. OPL3_TOMTOM_ON, OPL3_HIHAT_ON, OPL3_HIHAT_ON, /* 68 - 70 */
  22. OPL3_HIHAT_ON, OPL3_HIHAT_ON, OPL3_TOMTOM_ON, /* 71 - 73 */
  23. OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 74 - 76 */
  24. OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 77 - 79 */
  25. OPL3_CYMBAL_ON, OPL3_CYMBAL_ON /* 80 - 81 */
  26. };
  27. struct snd_opl3_drum_voice {
  28. int voice;
  29. int op;
  30. unsigned char am_vib;
  31. unsigned char ksl_level;
  32. unsigned char attack_decay;
  33. unsigned char sustain_release;
  34. unsigned char feedback_connection;
  35. unsigned char wave_select;
  36. };
  37. struct snd_opl3_drum_note {
  38. int voice;
  39. unsigned char fnum;
  40. unsigned char octave_f;
  41. unsigned char feedback_connection;
  42. };
  43. static const struct snd_opl3_drum_voice bass_op0 = {6, 0, 0x00, 0x32, 0xf8, 0x66, 0x30, 0x00};
  44. static const struct snd_opl3_drum_voice bass_op1 = {6, 1, 0x00, 0x03, 0xf6, 0x57, 0x30, 0x00};
  45. static const struct snd_opl3_drum_note bass_note = {6, 0x90, 0x09};
  46. static const struct snd_opl3_drum_voice hihat = {7, 0, 0x00, 0x03, 0xf0, 0x06, 0x20, 0x00};
  47. static const struct snd_opl3_drum_voice snare = {7, 1, 0x00, 0x03, 0xf0, 0x07, 0x20, 0x02};
  48. static const struct snd_opl3_drum_note snare_note = {7, 0xf4, 0x0d};
  49. static const struct snd_opl3_drum_voice tomtom = {8, 0, 0x02, 0x03, 0xf0, 0x06, 0x10, 0x00};
  50. static const struct snd_opl3_drum_note tomtom_note = {8, 0xf4, 0x09};
  51. static const struct snd_opl3_drum_voice cymbal = {8, 1, 0x04, 0x03, 0xf0, 0x06, 0x10, 0x00};
  52. /*
  53. * set drum voice characteristics
  54. */
  55. static void snd_opl3_drum_voice_set(struct snd_opl3 *opl3,
  56. const struct snd_opl3_drum_voice *data)
  57. {
  58. unsigned char op_offset = snd_opl3_regmap[data->voice][data->op];
  59. unsigned char voice_offset = data->voice;
  60. unsigned short opl3_reg;
  61. /* Set OPL3 AM_VIB register */
  62. opl3_reg = OPL3_LEFT | (OPL3_REG_AM_VIB + op_offset);
  63. opl3->command(opl3, opl3_reg, data->am_vib);
  64. /* Set OPL3 KSL_LEVEL register */
  65. opl3_reg = OPL3_LEFT | (OPL3_REG_KSL_LEVEL + op_offset);
  66. opl3->command(opl3, opl3_reg, data->ksl_level);
  67. /* Set OPL3 ATTACK_DECAY register */
  68. opl3_reg = OPL3_LEFT | (OPL3_REG_ATTACK_DECAY + op_offset);
  69. opl3->command(opl3, opl3_reg, data->attack_decay);
  70. /* Set OPL3 SUSTAIN_RELEASE register */
  71. opl3_reg = OPL3_LEFT | (OPL3_REG_SUSTAIN_RELEASE + op_offset);
  72. opl3->command(opl3, opl3_reg, data->sustain_release);
  73. /* Set OPL3 FEEDBACK_CONNECTION register */
  74. opl3_reg = OPL3_LEFT | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset);
  75. opl3->command(opl3, opl3_reg, data->feedback_connection);
  76. /* Select waveform */
  77. opl3_reg = OPL3_LEFT | (OPL3_REG_WAVE_SELECT + op_offset);
  78. opl3->command(opl3, opl3_reg, data->wave_select);
  79. }
  80. /*
  81. * Set drum voice pitch
  82. */
  83. static void snd_opl3_drum_note_set(struct snd_opl3 *opl3,
  84. const struct snd_opl3_drum_note *data)
  85. {
  86. unsigned char voice_offset = data->voice;
  87. unsigned short opl3_reg;
  88. /* Set OPL3 FNUM_LOW register */
  89. opl3_reg = OPL3_LEFT | (OPL3_REG_FNUM_LOW + voice_offset);
  90. opl3->command(opl3, opl3_reg, data->fnum);
  91. /* Set OPL3 KEYON_BLOCK register */
  92. opl3_reg = OPL3_LEFT | (OPL3_REG_KEYON_BLOCK + voice_offset);
  93. opl3->command(opl3, opl3_reg, data->octave_f);
  94. }
  95. /*
  96. * Set drum voice volume and position
  97. */
  98. static void snd_opl3_drum_vol_set(struct snd_opl3 *opl3,
  99. const struct snd_opl3_drum_voice *data,
  100. int vel, struct snd_midi_channel *chan)
  101. {
  102. unsigned char op_offset = snd_opl3_regmap[data->voice][data->op];
  103. unsigned char voice_offset = data->voice;
  104. unsigned char reg_val;
  105. unsigned short opl3_reg;
  106. /* Set OPL3 KSL_LEVEL register */
  107. reg_val = data->ksl_level;
  108. snd_opl3_calc_volume(&reg_val, vel, chan);
  109. opl3_reg = OPL3_LEFT | (OPL3_REG_KSL_LEVEL + op_offset);
  110. opl3->command(opl3, opl3_reg, reg_val);
  111. /* Set OPL3 FEEDBACK_CONNECTION register */
  112. /* Set output voice connection */
  113. reg_val = data->feedback_connection | OPL3_STEREO_BITS;
  114. if (chan->gm_pan < 43)
  115. reg_val &= ~OPL3_VOICE_TO_RIGHT;
  116. if (chan->gm_pan > 85)
  117. reg_val &= ~OPL3_VOICE_TO_LEFT;
  118. opl3_reg = OPL3_LEFT | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset);
  119. opl3->command(opl3, opl3_reg, reg_val);
  120. }
  121. /*
  122. * Loads drum voices at init time
  123. */
  124. void snd_opl3_load_drums(struct snd_opl3 *opl3)
  125. {
  126. snd_opl3_drum_voice_set(opl3, &bass_op0);
  127. snd_opl3_drum_voice_set(opl3, &bass_op1);
  128. snd_opl3_drum_note_set(opl3, &bass_note);
  129. snd_opl3_drum_voice_set(opl3, &hihat);
  130. snd_opl3_drum_voice_set(opl3, &snare);
  131. snd_opl3_drum_note_set(opl3, &snare_note);
  132. snd_opl3_drum_voice_set(opl3, &tomtom);
  133. snd_opl3_drum_note_set(opl3, &tomtom_note);
  134. snd_opl3_drum_voice_set(opl3, &cymbal);
  135. }
  136. /*
  137. * Switch drum voice on or off
  138. */
  139. void snd_opl3_drum_switch(struct snd_opl3 *opl3, int note, int vel, int on_off,
  140. struct snd_midi_channel *chan)
  141. {
  142. unsigned char drum_mask;
  143. const struct snd_opl3_drum_voice *drum_voice;
  144. if (!(opl3->drum_reg & OPL3_PERCUSSION_ENABLE))
  145. return;
  146. if ((note < 35) || (note > 81))
  147. return;
  148. drum_mask = snd_opl3_drum_table[note - 35];
  149. if (on_off) {
  150. switch (drum_mask) {
  151. case OPL3_BASSDRUM_ON:
  152. drum_voice = &bass_op1;
  153. break;
  154. case OPL3_HIHAT_ON:
  155. drum_voice = &hihat;
  156. break;
  157. case OPL3_SNAREDRUM_ON:
  158. drum_voice = &snare;
  159. break;
  160. case OPL3_TOMTOM_ON:
  161. drum_voice = &tomtom;
  162. break;
  163. case OPL3_CYMBAL_ON:
  164. drum_voice = &cymbal;
  165. break;
  166. default:
  167. drum_voice = &tomtom;
  168. }
  169. snd_opl3_drum_vol_set(opl3, drum_voice, vel, chan);
  170. opl3->drum_reg |= drum_mask;
  171. } else {
  172. opl3->drum_reg &= ~drum_mask;
  173. }
  174. opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION,
  175. opl3->drum_reg);
  176. }