/CrabEmu/sound/sn76489.c

https://github.com/nicoya/OpenEmu · C · 307 lines · 232 code · 47 blank · 28 comment · 38 complexity · 5fe8c20440dbaad6028faec3e6875d04 MD5 · raw file

  1. /*
  2. This file is part of CrabEmu.
  3. Copyright (C) 2005, 2006, 2007, 2008 Lawrence Sebald
  4. CrabEmu is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License version 2
  6. as published by the Free Software Foundation.
  7. CrabEmu is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with CrabEmu; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  14. */
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include "sn76489.h"
  18. /* These constants came from Maxim's core (then doubled). */
  19. static const int volume_values[16] = {
  20. 1784, 1548, 1338, 1150, 984, 834, 702, 584,
  21. 478, 384, 300, 226, 160, 100, 48, 0
  22. };
  23. int sn76489_init(sn76489_t *psg, float clock, float sample_rate,
  24. uint16 noise_bits, uint16 tapped) {
  25. psg->volume[0] = 0xF;
  26. psg->volume[1] = 0xF;
  27. psg->volume[2] = 0xF;
  28. psg->volume[3] = 0xF;
  29. psg->tone[0] = 0x00;
  30. psg->tone[1] = 0x00;
  31. psg->tone[2] = 0x00;
  32. psg->noise = 0x00;
  33. psg->latched_reg = LATCH_TONE0;
  34. psg->counter[0] = 0x00;
  35. psg->counter[1] = 0x00;
  36. psg->counter[2] = 0x00;
  37. psg->counter[3] = 0x00;
  38. psg->tone_state[0] = 1;
  39. psg->tone_state[1] = 1;
  40. psg->tone_state[2] = 1;
  41. psg->tone_state[3] = 1;
  42. psg->enabled_channels = 0x0F;
  43. psg->output_channels = 0xFF; /* All Channels, both sides */
  44. memset(psg->channel_masks[0], 0xFFFFFFFF, 4 * sizeof(uint32));
  45. memset(psg->channel_masks[1], 0xFFFFFFFF, 4 * sizeof(uint32));
  46. psg->clocks_per_sample = clock / 16.0f / sample_rate;
  47. psg->noise_shift = (1 << (noise_bits - 1));
  48. psg->noise_tapped = tapped;
  49. psg->noise_bits = noise_bits;
  50. return 0;
  51. }
  52. void sn76489_write(sn76489_t *psg, uint8 byte) {
  53. if(byte & 0x80) {
  54. /* This is a LATCH/DATA byte */
  55. psg->latched_reg = (byte & 0x70);
  56. switch(psg->latched_reg) {
  57. case LATCH_TONE0:
  58. psg->tone[0] = (psg->tone[0] & 0x3F0) | (byte & 0x0F);
  59. break;
  60. case LATCH_TONE1:
  61. psg->tone[1] = (psg->tone[1] & 0x3F0) | (byte & 0x0F);
  62. break;
  63. case LATCH_TONE2:
  64. psg->tone[2] = (psg->tone[2] & 0x3F0) | (byte & 0x0F);
  65. break;
  66. case LATCH_NOISE:
  67. psg->noise = (byte & 0x07);
  68. psg->noise_shift = 1 << (psg->noise_bits - 1);
  69. break;
  70. case LATCH_VOL0:
  71. psg->volume[0] = (byte & 0x0F);
  72. break;
  73. case LATCH_VOL1:
  74. psg->volume[1] = (byte & 0x0F);
  75. break;
  76. case LATCH_VOL2:
  77. psg->volume[2] = (byte & 0x0F);
  78. break;
  79. case LATCH_VOL3:
  80. psg->volume[3] = (byte & 0x0F);
  81. break;
  82. }
  83. }
  84. else {
  85. /* This is a DATA byte */
  86. switch(psg->latched_reg) {
  87. case LATCH_TONE0:
  88. psg->tone[0] = (psg->tone[0] & 0x000F) | ((byte & 0x3F) << 4);
  89. break;
  90. case LATCH_TONE1:
  91. psg->tone[1] = (psg->tone[1] & 0x000F) | ((byte & 0x3F) << 4);
  92. break;
  93. case LATCH_TONE2:
  94. psg->tone[2] = (psg->tone[2] & 0x000F) | ((byte & 0x3F) << 4);
  95. break;
  96. case LATCH_NOISE:
  97. psg->noise = (byte & 0x07);
  98. psg->noise_shift = 1 << (psg->noise_bits - 1);
  99. break;
  100. case LATCH_VOL0:
  101. psg->volume[0] = (byte & 0x0F);
  102. break;
  103. case LATCH_VOL1:
  104. psg->volume[1] = (byte & 0x0F);
  105. break;
  106. case LATCH_VOL2:
  107. psg->volume[2] = (byte & 0x0F);
  108. break;
  109. case LATCH_VOL3:
  110. psg->volume[3] = (byte & 0x0F);
  111. break;
  112. }
  113. }
  114. }
  115. /* This is pretty much taken directly from Maxim's SN76489 document. */
  116. static inline int parity(uint16 input) {
  117. input ^= input >> 8;
  118. input ^= input >> 4;
  119. input ^= input >> 2;
  120. input ^= input >> 1;
  121. return input & 1;
  122. }
  123. #ifndef _arch_dreamcast
  124. void sn76489_execute_samples(sn76489_t *psg, int16 *buf,
  125. uint32 samples) {
  126. int32 channels[4];
  127. uint32 i, j;
  128. for(i = 0; i < samples; ++i) {
  129. for(j = 0; j < 3; ++j) {
  130. psg->counter[j] -= psg->clocks_per_sample;
  131. channels[j] = ((psg->enabled_channels >> j) & 0x01) *
  132. psg->tone_state[j] * volume_values[psg->volume[j]];
  133. if(psg->counter[j] <= 0.0f) {
  134. if(psg->tone[j] < 7) {
  135. /* The PSG doesn't change states if the tone isn't at least
  136. 7, this fixes the "Sega" at the beginning of Sonic The
  137. Hedgehog 2 for the Game Gear. */
  138. psg->tone_state[j] = 1;
  139. }
  140. else {
  141. psg->tone_state[j] = -psg->tone_state[j];
  142. }
  143. psg->counter[j] += psg->tone[j];
  144. }
  145. }
  146. channels[3] = ((psg->enabled_channels >> 3) & 0x01) *
  147. (psg->noise_shift & 0x01) * volume_values[psg->volume[3]];
  148. psg->counter[3] -= psg->clocks_per_sample;
  149. if(psg->counter[3] < 0.0f) {
  150. psg->tone_state[3] = -psg->tone_state[3];
  151. if((psg->noise & 0x03) == 0x03) {
  152. psg->counter[3] = psg->counter[2];
  153. }
  154. else {
  155. psg->counter[3] += 0x10 << (psg->noise & 0x03);
  156. }
  157. if(psg->tone_state[3] == 1) {
  158. if(psg->noise & 0x04) {
  159. psg->noise_shift = (psg->noise_shift >> 1) |
  160. (parity(psg->noise_shift & psg->noise_tapped) <<
  161. (psg->noise_bits - 1));
  162. }
  163. else {
  164. psg->noise_shift = (psg->noise_shift >> 1) |
  165. ((psg->noise_shift & 0x01) << (psg->noise_bits - 1));
  166. }
  167. }
  168. }
  169. buf[i << 1] = (channels[0] & psg->channel_masks[0][0]) +
  170. (channels[1] & psg->channel_masks[0][1]) +
  171. (channels[2] & psg->channel_masks[0][2]) +
  172. (channels[3] & psg->channel_masks[0][3]);
  173. buf[(i << 1) + 1] = (channels[0] & psg->channel_masks[1][0]) +
  174. (channels[1] & psg->channel_masks[1][1]) +
  175. (channels[2] & psg->channel_masks[1][2]) +
  176. (channels[3] & psg->channel_masks[1][3]);
  177. }
  178. }
  179. #else
  180. void sn76489_execute_samples_dc(sn76489_t *psg, int16 *bufl,
  181. int16 *bufr, uint32 samples) {
  182. int32 channels[4];
  183. uint32 i, j;
  184. for(i = 0; i < samples; ++i) {
  185. for(j = 0; j < 3; ++j) {
  186. psg->counter[j] -= psg->clocks_per_sample;
  187. channels[j] = ((psg->enabled_channels >> j) & 0x01) *
  188. psg->tone_state[j] * volume_values[psg->volume[j]];
  189. if(psg->counter[j] <= 0.0f) {
  190. if(psg->tone[j] < 7) {
  191. /* The PSG doesn't change states if the tone isn't at least
  192. 7, this fixes the "Sega" at the beginning of Sonic The
  193. Hedgehog 2 for the Game Gear. */
  194. psg->tone_state[j] = 1;
  195. }
  196. else {
  197. psg->tone_state[j] = -psg->tone_state[j];
  198. }
  199. psg->counter[j] += psg->tone[j];
  200. }
  201. }
  202. channels[3] = ((psg->enabled_channels >> 3) & 0x01) *
  203. (psg->noise_shift & 0x01) * volume_values[psg->volume[3]];
  204. psg->counter[3] -= psg->clocks_per_sample;
  205. if(psg->counter[3] < 0.0f) {
  206. psg->tone_state[3] = -psg->tone_state[3];
  207. if((psg->noise & 0x03) == 0x03) {
  208. psg->counter[3] = psg->counter[2];
  209. }
  210. else {
  211. psg->counter[3] += 0x10 << (psg->noise & 0x03);
  212. }
  213. if(psg->tone_state[3] == 1) {
  214. if(psg->noise & 0x04) {
  215. psg->noise_shift = (psg->noise_shift >> 1) |
  216. (parity(psg->noise_shift & psg->noise_tapped) <<
  217. (psg->noise_bits - 1));
  218. }
  219. else {
  220. psg->noise_shift = (psg->noise_shift >> 1) |
  221. ((psg->noise_shift & 0x01) << (psg->noise_bits - 1));
  222. }
  223. }
  224. }
  225. *bufl++ = (channels[0] & psg->channel_masks[0][0]) +
  226. (channels[1] & psg->channel_masks[0][1]) +
  227. (channels[2] & psg->channel_masks[0][2]) +
  228. (channels[3] & psg->channel_masks[0][3]);
  229. *bufr++ = (channels[0] & psg->channel_masks[1][0]) +
  230. (channels[1] & psg->channel_masks[1][1]) +
  231. (channels[2] & psg->channel_masks[1][2]) +
  232. (channels[3] & psg->channel_masks[1][3]);
  233. }
  234. }
  235. #endif
  236. void sn76489_set_output_channels(sn76489_t *psg, uint8 data) {
  237. psg->output_channels = data;
  238. memset(psg->channel_masks[0], 0, 4 * sizeof(uint32));
  239. memset(psg->channel_masks[1], 0, 4 * sizeof(uint32));
  240. if(psg->output_channels & TONE0_LEFT)
  241. psg->channel_masks[0][0] = 0xFFFFFFFF;
  242. if(psg->output_channels & TONE1_LEFT)
  243. psg->channel_masks[0][1] = 0xFFFFFFFF;
  244. if(psg->output_channels & TONE2_LEFT)
  245. psg->channel_masks[0][2] = 0xFFFFFFFF;
  246. if(psg->output_channels & NOISE_LEFT)
  247. psg->channel_masks[0][3] = 0xFFFFFFFF;
  248. if(psg->output_channels & TONE0_RIGHT)
  249. psg->channel_masks[1][0] = 0xFFFFFFFF;
  250. if(psg->output_channels & TONE1_RIGHT)
  251. psg->channel_masks[1][1] = 0xFFFFFFFF;
  252. if(psg->output_channels & TONE2_RIGHT)
  253. psg->channel_masks[1][2] = 0xFFFFFFFF;
  254. if(psg->output_channels & NOISE_RIGHT)
  255. psg->channel_masks[1][3] = 0xFFFFFFFF;
  256. }