2
0

adlib.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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 "qemu/osdep.h"
  25. #include "qapi/error.h"
  26. #include "qemu/module.h"
  27. #include "hw/audio/soundhw.h"
  28. #include "audio/audio.h"
  29. #include "hw/isa/isa.h"
  30. #include "hw/qdev-properties.h"
  31. //#define DEBUG
  32. #define ADLIB_KILL_TIMERS 1
  33. #define ADLIB_DESC "Yamaha YM3812 (OPL2)"
  34. #ifdef DEBUG
  35. #include "qemu/timer.h"
  36. #endif
  37. #define dolog(...) AUD_log ("adlib", __VA_ARGS__)
  38. #ifdef DEBUG
  39. #define ldebug(...) dolog (__VA_ARGS__)
  40. #else
  41. #define ldebug(...)
  42. #endif
  43. #include "fmopl.h"
  44. #define SHIFT 1
  45. #define TYPE_ADLIB "adlib"
  46. #define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB)
  47. typedef struct {
  48. ISADevice parent_obj;
  49. QEMUSoundCard card;
  50. uint32_t freq;
  51. uint32_t port;
  52. int ticking[2];
  53. int enabled;
  54. int active;
  55. int bufpos;
  56. #ifdef DEBUG
  57. int64_t exp[2];
  58. #endif
  59. int16_t *mixbuf;
  60. uint64_t dexp[2];
  61. SWVoiceOut *voice;
  62. int left, pos, samples;
  63. QEMUAudioTimeStamp ats;
  64. FM_OPL *opl;
  65. PortioList port_list;
  66. } AdlibState;
  67. static void adlib_stop_opl_timer (AdlibState *s, size_t n)
  68. {
  69. OPLTimerOver (s->opl, n);
  70. s->ticking[n] = 0;
  71. }
  72. static void adlib_kill_timers (AdlibState *s)
  73. {
  74. size_t i;
  75. for (i = 0; i < 2; ++i) {
  76. if (s->ticking[i]) {
  77. uint64_t delta;
  78. delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
  79. ldebug (
  80. "delta = %f dexp = %f expired => %d\n",
  81. delta / 1000000.0,
  82. s->dexp[i] / 1000000.0,
  83. delta >= s->dexp[i]
  84. );
  85. if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
  86. adlib_stop_opl_timer (s, i);
  87. AUD_init_time_stamp_out (s->voice, &s->ats);
  88. }
  89. }
  90. }
  91. }
  92. static void adlib_write(void *opaque, uint32_t nport, uint32_t val)
  93. {
  94. AdlibState *s = opaque;
  95. int a = nport & 3;
  96. s->active = 1;
  97. AUD_set_active_out (s->voice, 1);
  98. adlib_kill_timers (s);
  99. OPLWrite (s->opl, a, val);
  100. }
  101. static uint32_t adlib_read(void *opaque, uint32_t nport)
  102. {
  103. AdlibState *s = opaque;
  104. uint8_t data;
  105. int a = nport & 3;
  106. adlib_kill_timers (s);
  107. data = OPLRead (s->opl, a);
  108. return data;
  109. }
  110. static void timer_handler (void *opaque, int c, double interval_Sec)
  111. {
  112. AdlibState *s = opaque;
  113. unsigned n = c & 1;
  114. #ifdef DEBUG
  115. double interval;
  116. int64_t exp;
  117. #endif
  118. if (interval_Sec == 0.0) {
  119. s->ticking[n] = 0;
  120. return;
  121. }
  122. s->ticking[n] = 1;
  123. #ifdef DEBUG
  124. interval = NANOSECONDS_PER_SECOND * interval_Sec;
  125. exp = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + interval;
  126. s->exp[n] = exp;
  127. #endif
  128. s->dexp[n] = interval_Sec * 1000000.0;
  129. AUD_init_time_stamp_out (s->voice, &s->ats);
  130. }
  131. static int write_audio (AdlibState *s, int samples)
  132. {
  133. int net = 0;
  134. int pos = s->pos;
  135. while (samples) {
  136. int nbytes, wbytes, wsampl;
  137. nbytes = samples << SHIFT;
  138. wbytes = AUD_write (
  139. s->voice,
  140. s->mixbuf + (pos << (SHIFT - 1)),
  141. nbytes
  142. );
  143. if (wbytes) {
  144. wsampl = wbytes >> SHIFT;
  145. samples -= wsampl;
  146. pos = (pos + wsampl) % s->samples;
  147. net += wsampl;
  148. }
  149. else {
  150. break;
  151. }
  152. }
  153. return net;
  154. }
  155. static void adlib_callback (void *opaque, int free)
  156. {
  157. AdlibState *s = opaque;
  158. int samples, net = 0, to_play, written;
  159. samples = free >> SHIFT;
  160. if (!(s->active && s->enabled) || !samples) {
  161. return;
  162. }
  163. to_play = MIN (s->left, samples);
  164. while (to_play) {
  165. written = write_audio (s, to_play);
  166. if (written) {
  167. s->left -= written;
  168. samples -= written;
  169. to_play -= written;
  170. s->pos = (s->pos + written) % s->samples;
  171. }
  172. else {
  173. return;
  174. }
  175. }
  176. samples = MIN (samples, s->samples - s->pos);
  177. if (!samples) {
  178. return;
  179. }
  180. YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
  181. while (samples) {
  182. written = write_audio (s, samples);
  183. if (written) {
  184. net += written;
  185. samples -= written;
  186. s->pos = (s->pos + written) % s->samples;
  187. }
  188. else {
  189. s->left = samples;
  190. return;
  191. }
  192. }
  193. }
  194. static void Adlib_fini (AdlibState *s)
  195. {
  196. if (s->opl) {
  197. OPLDestroy (s->opl);
  198. s->opl = NULL;
  199. }
  200. g_free(s->mixbuf);
  201. s->active = 0;
  202. s->enabled = 0;
  203. AUD_remove_card (&s->card);
  204. }
  205. static MemoryRegionPortio adlib_portio_list[] = {
  206. { 0, 4, 1, .read = adlib_read, .write = adlib_write, },
  207. { 0, 2, 1, .read = adlib_read, .write = adlib_write, },
  208. { 0x388, 4, 1, .read = adlib_read, .write = adlib_write, },
  209. PORTIO_END_OF_LIST(),
  210. };
  211. static void adlib_realizefn (DeviceState *dev, Error **errp)
  212. {
  213. AdlibState *s = ADLIB(dev);
  214. struct audsettings as;
  215. s->opl = OPLCreate (3579545, s->freq);
  216. if (!s->opl) {
  217. error_setg (errp, "OPLCreate %d failed", s->freq);
  218. return;
  219. }
  220. else {
  221. OPLSetTimerHandler(s->opl, timer_handler, s);
  222. s->enabled = 1;
  223. }
  224. as.freq = s->freq;
  225. as.nchannels = SHIFT;
  226. as.fmt = AUDIO_FORMAT_S16;
  227. as.endianness = AUDIO_HOST_ENDIANNESS;
  228. AUD_register_card ("adlib", &s->card);
  229. s->voice = AUD_open_out (
  230. &s->card,
  231. s->voice,
  232. "adlib",
  233. s,
  234. adlib_callback,
  235. &as
  236. );
  237. if (!s->voice) {
  238. Adlib_fini (s);
  239. error_setg (errp, "Initializing audio voice failed");
  240. return;
  241. }
  242. s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
  243. s->mixbuf = g_malloc0 (s->samples << SHIFT);
  244. adlib_portio_list[0].offset = s->port;
  245. adlib_portio_list[1].offset = s->port + 8;
  246. portio_list_init (&s->port_list, OBJECT(s), adlib_portio_list, s, "adlib");
  247. portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0);
  248. }
  249. static Property adlib_properties[] = {
  250. DEFINE_AUDIO_PROPERTIES(AdlibState, card),
  251. DEFINE_PROP_UINT32 ("iobase", AdlibState, port, 0x220),
  252. DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100),
  253. DEFINE_PROP_END_OF_LIST (),
  254. };
  255. static void adlib_class_initfn (ObjectClass *klass, void *data)
  256. {
  257. DeviceClass *dc = DEVICE_CLASS (klass);
  258. dc->realize = adlib_realizefn;
  259. set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
  260. dc->desc = ADLIB_DESC;
  261. dc->props = adlib_properties;
  262. }
  263. static const TypeInfo adlib_info = {
  264. .name = TYPE_ADLIB,
  265. .parent = TYPE_ISA_DEVICE,
  266. .instance_size = sizeof (AdlibState),
  267. .class_init = adlib_class_initfn,
  268. };
  269. static int Adlib_init (ISABus *bus)
  270. {
  271. isa_create_simple (bus, TYPE_ADLIB);
  272. return 0;
  273. }
  274. static void adlib_register_types (void)
  275. {
  276. type_register_static (&adlib_info);
  277. isa_register_soundhw("adlib", ADLIB_DESC, Adlib_init);
  278. }
  279. type_init (adlib_register_types)