2
0

adlib.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * QEMU Proxy for OPL2/3 emulation by MAME team
  3. *
  4. * Copyright (c) 2004-2005 Vassili Karpov (malc)
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include <assert.h>
  25. #include "hw.h"
  26. #include "audiodev.h"
  27. #include "audio/audio.h"
  28. #include "isa.h"
  29. //#define DEBUG
  30. #define ADLIB_KILL_TIMERS 1
  31. #ifdef DEBUG
  32. #include "qemu-timer.h"
  33. #endif
  34. #define dolog(...) AUD_log ("adlib", __VA_ARGS__)
  35. #ifdef DEBUG
  36. #define ldebug(...) dolog (__VA_ARGS__)
  37. #else
  38. #define ldebug(...)
  39. #endif
  40. #ifdef HAS_YMF262
  41. #include "ymf262.h"
  42. void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
  43. #define SHIFT 2
  44. #else
  45. #include "fmopl.h"
  46. #define SHIFT 1
  47. #endif
  48. #define IO_READ_PROTO(name) \
  49. uint32_t name (void *opaque, uint32_t nport)
  50. #define IO_WRITE_PROTO(name) \
  51. void name (void *opaque, uint32_t nport, uint32_t val)
  52. static struct {
  53. int port;
  54. int freq;
  55. } conf = {0x220, 44100};
  56. typedef struct {
  57. QEMUSoundCard card;
  58. int ticking[2];
  59. int enabled;
  60. int active;
  61. int bufpos;
  62. #ifdef DEBUG
  63. int64_t exp[2];
  64. #endif
  65. int16_t *mixbuf;
  66. uint64_t dexp[2];
  67. SWVoiceOut *voice;
  68. int left, pos, samples;
  69. QEMUAudioTimeStamp ats;
  70. #ifndef HAS_YMF262
  71. FM_OPL *opl;
  72. #endif
  73. } AdlibState;
  74. static AdlibState glob_adlib;
  75. static void adlib_stop_opl_timer (AdlibState *s, size_t n)
  76. {
  77. #ifdef HAS_YMF262
  78. YMF262TimerOver (0, n);
  79. #else
  80. OPLTimerOver (s->opl, n);
  81. #endif
  82. s->ticking[n] = 0;
  83. }
  84. static void adlib_kill_timers (AdlibState *s)
  85. {
  86. size_t i;
  87. for (i = 0; i < 2; ++i) {
  88. if (s->ticking[i]) {
  89. uint64_t delta;
  90. delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
  91. ldebug (
  92. "delta = %f dexp = %f expired => %d\n",
  93. delta / 1000000.0,
  94. s->dexp[i] / 1000000.0,
  95. delta >= s->dexp[i]
  96. );
  97. if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
  98. adlib_stop_opl_timer (s, i);
  99. AUD_init_time_stamp_out (s->voice, &s->ats);
  100. }
  101. }
  102. }
  103. }
  104. static IO_WRITE_PROTO(adlib_write)
  105. {
  106. AdlibState *s = opaque;
  107. int a = nport & 3;
  108. int status;
  109. s->active = 1;
  110. AUD_set_active_out (s->voice, 1);
  111. adlib_kill_timers (s);
  112. #ifdef HAS_YMF262
  113. status = YMF262Write (0, a, val);
  114. #else
  115. status = OPLWrite (s->opl, a, val);
  116. #endif
  117. }
  118. static IO_READ_PROTO(adlib_read)
  119. {
  120. AdlibState *s = opaque;
  121. uint8_t data;
  122. int a = nport & 3;
  123. adlib_kill_timers (s);
  124. #ifdef HAS_YMF262
  125. data = YMF262Read (0, a);
  126. #else
  127. data = OPLRead (s->opl, a);
  128. #endif
  129. return data;
  130. }
  131. static void timer_handler (int c, double interval_Sec)
  132. {
  133. AdlibState *s = &glob_adlib;
  134. unsigned n = c & 1;
  135. #ifdef DEBUG
  136. double interval;
  137. int64_t exp;
  138. #endif
  139. if (interval_Sec == 0.0) {
  140. s->ticking[n] = 0;
  141. return;
  142. }
  143. s->ticking[n] = 1;
  144. #ifdef DEBUG
  145. interval = ticks_per_sec * interval_Sec;
  146. exp = qemu_get_clock (vm_clock) + interval;
  147. s->exp[n] = exp;
  148. #endif
  149. s->dexp[n] = interval_Sec * 1000000.0;
  150. AUD_init_time_stamp_out (s->voice, &s->ats);
  151. }
  152. static int write_audio (AdlibState *s, int samples)
  153. {
  154. int net = 0;
  155. int pos = s->pos;
  156. while (samples) {
  157. int nbytes, wbytes, wsampl;
  158. nbytes = samples << SHIFT;
  159. wbytes = AUD_write (
  160. s->voice,
  161. s->mixbuf + (pos << (SHIFT - 1)),
  162. nbytes
  163. );
  164. if (wbytes) {
  165. wsampl = wbytes >> SHIFT;
  166. samples -= wsampl;
  167. pos = (pos + wsampl) % s->samples;
  168. net += wsampl;
  169. }
  170. else {
  171. break;
  172. }
  173. }
  174. return net;
  175. }
  176. static void adlib_callback (void *opaque, int free)
  177. {
  178. AdlibState *s = opaque;
  179. int samples, net = 0, to_play, written;
  180. samples = free >> SHIFT;
  181. if (!(s->active && s->enabled) || !samples) {
  182. return;
  183. }
  184. to_play = audio_MIN (s->left, samples);
  185. while (to_play) {
  186. written = write_audio (s, to_play);
  187. if (written) {
  188. s->left -= written;
  189. samples -= written;
  190. to_play -= written;
  191. s->pos = (s->pos + written) % s->samples;
  192. }
  193. else {
  194. return;
  195. }
  196. }
  197. samples = audio_MIN (samples, s->samples - s->pos);
  198. if (!samples) {
  199. return;
  200. }
  201. #ifdef HAS_YMF262
  202. YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
  203. #else
  204. YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
  205. #endif
  206. while (samples) {
  207. written = write_audio (s, samples);
  208. if (written) {
  209. net += written;
  210. samples -= written;
  211. s->pos = (s->pos + written) % s->samples;
  212. }
  213. else {
  214. s->left = samples;
  215. return;
  216. }
  217. }
  218. }
  219. static void Adlib_fini (AdlibState *s)
  220. {
  221. #ifdef HAS_YMF262
  222. YMF262Shutdown ();
  223. #else
  224. if (s->opl) {
  225. OPLDestroy (s->opl);
  226. s->opl = NULL;
  227. }
  228. #endif
  229. if (s->mixbuf) {
  230. qemu_free (s->mixbuf);
  231. }
  232. s->active = 0;
  233. s->enabled = 0;
  234. AUD_remove_card (&s->card);
  235. }
  236. int Adlib_init (AudioState *audio, qemu_irq *pic)
  237. {
  238. AdlibState *s = &glob_adlib;
  239. struct audsettings as;
  240. if (!audio) {
  241. dolog ("No audio state\n");
  242. return -1;
  243. }
  244. #ifdef HAS_YMF262
  245. if (YMF262Init (1, 14318180, conf.freq)) {
  246. dolog ("YMF262Init %d failed\n", conf.freq);
  247. return -1;
  248. }
  249. else {
  250. YMF262SetTimerHandler (0, timer_handler, 0);
  251. s->enabled = 1;
  252. }
  253. #else
  254. s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
  255. if (!s->opl) {
  256. dolog ("OPLCreate %d failed\n", conf.freq);
  257. return -1;
  258. }
  259. else {
  260. OPLSetTimerHandler (s->opl, timer_handler, 0);
  261. s->enabled = 1;
  262. }
  263. #endif
  264. as.freq = conf.freq;
  265. as.nchannels = SHIFT;
  266. as.fmt = AUD_FMT_S16;
  267. as.endianness = AUDIO_HOST_ENDIANNESS;
  268. AUD_register_card (audio, "adlib", &s->card);
  269. s->voice = AUD_open_out (
  270. &s->card,
  271. s->voice,
  272. "adlib",
  273. s,
  274. adlib_callback,
  275. &as
  276. );
  277. if (!s->voice) {
  278. Adlib_fini (s);
  279. return -1;
  280. }
  281. s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
  282. s->mixbuf = qemu_mallocz (s->samples << SHIFT);
  283. register_ioport_read (0x388, 4, 1, adlib_read, s);
  284. register_ioport_write (0x388, 4, 1, adlib_write, s);
  285. register_ioport_read (conf.port, 4, 1, adlib_read, s);
  286. register_ioport_write (conf.port, 4, 1, adlib_write, s);
  287. register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
  288. register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
  289. return 0;
  290. }