(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/adlib.c

    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: 
   25: #include <assert.h>
   26: #include "hw.h"
   27: #include "audiodev.h"
   28: #include "audio/audio.h"
   29: #include "isa.h"
   30: 
   31: //#define DEBUG
   32: 
   33: #define ADLIB_KILL_TIMERS 1
   34: 
   35: #ifdef DEBUG
   36: #include "qemu-timer.h"
   37: #endif
   38: 
   39: #define dolog(...) AUD_log ("adlib", __VA_ARGS__)
   40: #ifdef DEBUG
   41: #define ldebug(...) dolog (__VA_ARGS__)
   42: #else
   43: #define ldebug(...)
   44: #endif
   45: 
   46: #ifdef HAS_YMF262
   47: #include "ymf262.h"
   48: void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
   49: #define SHIFT 2
   50: #else
   51: #include "fmopl.h"
   52: #define SHIFT 1
   53: #endif
   54: 
   55: #define IO_READ_PROTO(name) \
   56:     uint32_t name (void *opaque, uint32_t nport)
   57: #define IO_WRITE_PROTO(name) \
   58:     void name (void *opaque, uint32_t nport, uint32_t val)
   59: 
   60: static struct {
   61:     int port;
   62:     int freq;
   63: } conf = {0x220, 44100};
   64: 
   65: typedef struct {
   66:     QEMUSoundCard card;
   67:     int ticking[2];
   68:     int enabled;
   69:     int active;
   70:     int bufpos;
   71: #ifdef DEBUG
   72:     int64_t exp[2];
   73: #endif
   74:     int16_t *mixbuf;
   75:     uint64_t dexp[2];
   76:     SWVoiceOut *voice;
   77:     int left, pos, samples;
   78:     QEMUAudioTimeStamp ats;
   79: #ifndef HAS_YMF262
   80:     FM_OPL *opl;
   81: #endif
   82: } AdlibState;
   83: 
   84: static AdlibState glob_adlib;
   85: 
   86: static void adlib_stop_opl_timer (AdlibState *s, size_t n)
   87: {
   88: #ifdef HAS_YMF262
   89:     YMF262TimerOver (0, n);
   90: #else
   91:     OPLTimerOver (s->opl, n);
   92: #endif
   93:     s->ticking[n] = 0;
   94: }
   95: 
   96: static void adlib_kill_timers (AdlibState *s)
   97: {
   98:     size_t i;
   99: 
  100:     for (i = 0; i < 2; ++i) {
  101:         if (s->ticking[i]) {
  102:             uint64_t delta;
  103: 
  104:             delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
  105:             ldebug (
  106:                 "delta = %f dexp = %f expired => %d\n",
  107:                 delta / 1000000.0,
  108:                 s->dexp[i] / 1000000.0,
  109:                 delta >= s->dexp[i]
  110:                 );
  111:             if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
  112:                 adlib_stop_opl_timer (s, i);
  113:                 AUD_init_time_stamp_out (s->voice, &s->ats);
  114:             }
  115:         }
  116:     }
  117: }
  118: 
  119: static IO_WRITE_PROTO(adlib_write)
  120: {
  121:     AdlibState *s = opaque;
  122:     int a = nport & 3;
  123:     int status;
  124: 
  125:     s->active = 1;
  126:     AUD_set_active_out (s->voice, 1);
  127: 
  128:     adlib_kill_timers (s);
  129: 
  130: #ifdef HAS_YMF262
  131:     status = YMF262Write (0, a, val);
  132: #else
  133:     status = OPLWrite (s->opl, a, val);
  134: #endif
  135: }
  136: 
  137: static IO_READ_PROTO(adlib_read)
  138: {
  139:     AdlibState *s = opaque;
  140:     uint8_t data;
  141:     int a = nport & 3;
  142: 
  143:     adlib_kill_timers (s);
  144: 
  145: #ifdef HAS_YMF262
  146:     data = YMF262Read (0, a);
  147: #else
  148:     data = OPLRead (s->opl, a);
  149: #endif
  150:     return data;
  151: }
  152: 
  153: static void timer_handler (int c, double interval_Sec)
  154: {
  155:     AdlibState *s = &glob_adlib;
  156:     unsigned n = c & 1;
  157: #ifdef DEBUG
  158:     double interval;
  159:     int64_t exp;
  160: #endif
  161: 
  162:     if (interval_Sec == 0.0) {
  163:         s->ticking[n] = 0;
  164:         return;
  165:     }
  166: 
  167:     s->ticking[n] = 1;
  168: #ifdef DEBUG
  169:     interval = ticks_per_sec * interval_Sec;
  170:     exp = qemu_get_clock (vm_clock) + interval;
  171:     s->exp[n] = exp;
  172: #endif
  173: 
  174:     s->dexp[n] = interval_Sec * 1000000.0;
  175:     AUD_init_time_stamp_out (s->voice, &s->ats);
  176: }
  177: 
  178: static int write_audio (AdlibState *s, int samples)
  179: {
  180:     int net = 0;
  181:     int pos = s->pos;
  182: 
  183:     while (samples) {
  184:         int nbytes, wbytes, wsampl;
  185: 
  186:         nbytes = samples << SHIFT;
  187:         wbytes = AUD_write (
  188:             s->voice,
  189:             s->mixbuf + (pos << (SHIFT - 1)),
  190:             nbytes
  191:             );
  192: 
  193:         if (wbytes) {
  194:             wsampl = wbytes >> SHIFT;
  195: 
  196:             samples -= wsampl;
  197:             pos = (pos + wsampl) % s->samples;
  198: 
  199:             net += wsampl;
  200:         }
  201:         else {
  202:             break;
  203:         }
  204:     }
  205: 
  206:     return net;
  207: }
  208: 
  209: static void adlib_callback (void *opaque, int free)
  210: {
  211:     AdlibState *s = opaque;
  212:     int samples, net = 0, to_play, written;
  213: 
  214:     samples = free >> SHIFT;
  215:     if (!(s->active && s->enabled) || !samples) {
  216:         return;
  217:     }
  218: 
  219:     to_play = audio_MIN (s->left, samples);
  220:     while (to_play) {
  221:         written = write_audio (s, to_play);
  222: 
  223:         if (written) {
  224:             s->left -= written;
  225:             samples -= written;
  226:             to_play -= written;
  227:             s->pos = (s->pos + written) % s->samples;
  228:         }
  229:         else {
  230:             return;
  231:         }
  232:     }
  233: 
  234:     samples = audio_MIN (samples, s->samples - s->pos);
  235:     if (!samples) {
  236:         return;
  237:     }
  238: 
  239: #ifdef HAS_YMF262
  240:     YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
  241: #else
  242:     YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
  243: #endif
  244: 
  245:     while (samples) {
  246:         written = write_audio (s, samples);
  247: 
  248:         if (written) {
  249:             net += written;
  250:             samples -= written;
  251:             s->pos = (s->pos + written) % s->samples;
  252:         }
  253:         else {
  254:             s->left = samples;
  255:             return;
  256:         }
  257:     }
  258: }
  259: 
  260: static void Adlib_fini (AdlibState *s)
  261: {
  262: #ifdef HAS_YMF262
  263:     YMF262Shutdown ();
  264: #else
  265:     if (s->opl) {
  266:         OPLDestroy (s->opl);
  267:         s->opl = NULL;
  268:     }
  269: #endif
  270: 
  271:     if (s->mixbuf) {
  272:         qemu_free (s->mixbuf);
  273:     }
  274: 
  275:     s->active = 0;
  276:     s->enabled = 0;
  277:     AUD_remove_card (&s->card);
  278: }
  279: 
  280: int Adlib_init (AudioState *audio, qemu_irq *pic)
  281: {
  282:     AdlibState *s = &glob_adlib;
  283:     audsettings_t as;
  284: 
  285:     if (!audio) {
  286:         dolog ("No audio state\n");
  287:         return -1;
  288:     }
  289: 
  290: #ifdef HAS_YMF262
  291:     if (YMF262Init (1, 14318180, conf.freq)) {
  292:         dolog ("YMF262Init %d failed\n", conf.freq);
  293:         return -1;
  294:     }
  295:     else {
  296:         YMF262SetTimerHandler (0, timer_handler, 0);
  297:         s->enabled = 1;
  298:     }
  299: #else
  300:     s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
  301:     if (!s->opl) {
  302:         dolog ("OPLCreate %d failed\n", conf.freq);
  303:         return -1;
  304:     }
  305:     else {
  306:         OPLSetTimerHandler (s->opl, timer_handler, 0);
  307:         s->enabled = 1;
  308:     }
  309: #endif
  310: 
  311:     as.freq = conf.freq;
  312:     as.nchannels = SHIFT;
  313:     as.fmt = AUD_FMT_S16;
  314:     as.endianness = AUDIO_HOST_ENDIANNESS;
  315: 
  316:     AUD_register_card (audio, "adlib", &s->card);
  317: 
  318:     s->voice = AUD_open_out (
  319:         &s->card,
  320:         s->voice,
  321:         "adlib",
  322:         s,
  323:         adlib_callback,
  324:         &as
  325:         );
  326:     if (!s->voice) {
  327:         Adlib_fini (s);
  328:         return -1;
  329:     }
  330: 
  331:     s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
  332:     s->mixbuf = qemu_mallocz (s->samples << SHIFT);
  333: 
  334:     if (!s->mixbuf) {
  335:         dolog ("Could not allocate mixing buffer, %d samples (each %d bytes)\n",
  336:                s->samples, 1 << SHIFT);
  337:         Adlib_fini (s);
  338:         return -1;
  339:     }
  340: 
  341:     register_ioport_read (0x388, 4, 1, adlib_read, s);
  342:     register_ioport_write (0x388, 4, 1, adlib_write, s);
  343: 
  344:     register_ioport_read (conf.port, 4, 1, adlib_read, s);
  345:     register_ioport_write (conf.port, 4, 1, adlib_write, s);
  346: 
  347:     register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
  348:     register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
  349: 
  350:     return 0;
  351: }
Syntax (Markdown)