Annotation of qemu/audio/fmodaudio.c, revision 1.1.1.7

1.1       root        1: /*
1.1.1.2   root        2:  * QEMU FMOD audio driver
                      3:  *
                      4:  * Copyright (c) 2004-2005 Vassili Karpov (malc)
                      5:  *
1.1       root        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 <fmod.h>
                     25: #include <fmod_errors.h>
1.1.1.4   root       26: #include "qemu-common.h"
                     27: #include "audio.h"
1.1       root       28: 
1.1.1.2   root       29: #define AUDIO_CAP "fmod"
                     30: #include "audio_int.h"
1.1       root       31: 
1.1.1.2   root       32: typedef struct FMODVoiceOut {
                     33:     HWVoiceOut hw;
1.1       root       34:     unsigned int old_pos;
                     35:     FSOUND_SAMPLE *fmod_sample;
                     36:     int channel;
1.1.1.2   root       37: } FMODVoiceOut;
1.1       root       38: 
1.1.1.2   root       39: typedef struct FMODVoiceIn {
                     40:     HWVoiceIn hw;
                     41:     FSOUND_SAMPLE *fmod_sample;
                     42: } FMODVoiceIn;
1.1       root       43: 
                     44: static struct {
1.1.1.2   root       45:     const char *drvname;
1.1       root       46:     int nb_samples;
                     47:     int freq;
                     48:     int nb_channels;
                     49:     int bufsize;
1.1.1.2   root       50:     int broken_adc;
1.1       root       51: } conf = {
1.1.1.6   root       52:     .nb_samples  = 2048 * 2,
                     53:     .freq        = 44100,
                     54:     .nb_channels = 2,
1.1       root       55: };
                     56: 
1.1.1.2   root       57: static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
                     58: {
                     59:     va_list ap;
                     60: 
                     61:     va_start (ap, fmt);
                     62:     AUD_vlog (AUDIO_CAP, fmt, ap);
                     63:     va_end (ap);
1.1       root       64: 
1.1.1.2   root       65:     AUD_log (AUDIO_CAP, "Reason: %s\n",
                     66:              FMOD_ErrorString (FSOUND_GetError ()));
                     67: }
                     68: 
                     69: static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
                     70:     const char *typ,
                     71:     const char *fmt,
                     72:     ...
                     73:     )
1.1       root       74: {
1.1.1.2   root       75:     va_list ap;
                     76: 
                     77:     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
                     78: 
                     79:     va_start (ap, fmt);
                     80:     AUD_vlog (AUDIO_CAP, fmt, ap);
                     81:     va_end (ap);
                     82: 
                     83:     AUD_log (AUDIO_CAP, "Reason: %s\n",
                     84:              FMOD_ErrorString (FSOUND_GetError ()));
1.1       root       85: }
                     86: 
1.1.1.2   root       87: static int fmod_write (SWVoiceOut *sw, void *buf, int len)
1.1       root       88: {
1.1.1.2   root       89:     return audio_pcm_sw_write (sw, buf, len);
                     90: }
                     91: 
                     92: static void fmod_clear_sample (FMODVoiceOut *fmd)
                     93: {
                     94:     HWVoiceOut *hw = &fmd->hw;
1.1       root       95:     int status;
                     96:     void *p1 = 0, *p2 = 0;
                     97:     unsigned int len1 = 0, len2 = 0;
                     98: 
                     99:     status = FSOUND_Sample_Lock (
                    100:         fmd->fmod_sample,
                    101:         0,
1.1.1.2   root      102:         hw->samples << hw->info.shift,
1.1       root      103:         &p1,
                    104:         &p2,
                    105:         &len1,
                    106:         &len2
                    107:         );
                    108: 
                    109:     if (!status) {
1.1.1.2   root      110:         fmod_logerr ("Failed to lock sample\n");
1.1       root      111:         return;
                    112:     }
                    113: 
1.1.1.2   root      114:     if ((len1 & hw->info.align) || (len2 & hw->info.align)) {
                    115:         dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
                    116:                len1, len2, hw->info.align + 1);
1.1       root      117:         goto fail;
                    118:     }
                    119: 
1.1.1.2   root      120:     if ((len1 + len2) - (hw->samples << hw->info.shift)) {
                    121:         dolog ("Lock returned incomplete length %d, %d\n",
                    122:                len1 + len2, hw->samples << hw->info.shift);
1.1       root      123:         goto fail;
                    124:     }
1.1.1.2   root      125: 
                    126:     audio_pcm_info_clear_buf (&hw->info, p1, hw->samples);
1.1       root      127: 
                    128:  fail:
                    129:     status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
                    130:     if (!status) {
1.1.1.2   root      131:         fmod_logerr ("Failed to unlock sample\n");
1.1       root      132:     }
                    133: }
                    134: 
1.1.1.2   root      135: static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
1.1       root      136: {
1.1.1.2   root      137:     int src_len1 = dst_len;
                    138:     int src_len2 = 0;
                    139:     int pos = hw->rpos + dst_len;
1.1.1.5   root      140:     struct st_sample *src1 = hw->mix_buf + hw->rpos;
                    141:     struct st_sample *src2 = NULL;
1.1       root      142: 
1.1.1.2   root      143:     if (pos > hw->samples) {
                    144:         src_len1 = hw->samples - hw->rpos;
                    145:         src2 = hw->mix_buf;
1.1       root      146:         src_len2 = dst_len - src_len1;
                    147:         pos = src_len2;
                    148:     }
                    149: 
                    150:     if (src_len1) {
                    151:         hw->clip (dst, src1, src_len1);
                    152:     }
                    153: 
                    154:     if (src_len2) {
1.1.1.2   root      155:         dst = advance (dst, src_len1 << hw->info.shift);
1.1       root      156:         hw->clip (dst, src2, src_len2);
                    157:     }
1.1.1.2   root      158: 
                    159:     hw->rpos = pos % hw->samples;
1.1       root      160: }
                    161: 
1.1.1.2   root      162: static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2,
1.1       root      163:                                unsigned int blen1, unsigned int blen2)
                    164: {
1.1.1.2   root      165:     int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2);
1.1       root      166:     if (!status) {
1.1.1.2   root      167:         fmod_logerr ("Failed to unlock sample\n");
1.1       root      168:         return -1;
                    169:     }
                    170:     return 0;
                    171: }
                    172: 
1.1.1.2   root      173: static int fmod_lock_sample (
                    174:     FSOUND_SAMPLE *sample,
                    175:     struct audio_pcm_info *info,
                    176:     int pos,
                    177:     int len,
                    178:     void **p1,
                    179:     void **p2,
                    180:     unsigned int *blen1,
                    181:     unsigned int *blen2
                    182:     )
1.1       root      183: {
                    184:     int status;
                    185: 
                    186:     status = FSOUND_Sample_Lock (
1.1.1.2   root      187:         sample,
                    188:         pos << info->shift,
                    189:         len << info->shift,
1.1       root      190:         p1,
                    191:         p2,
                    192:         blen1,
                    193:         blen2
                    194:         );
                    195: 
                    196:     if (!status) {
1.1.1.2   root      197:         fmod_logerr ("Failed to lock sample\n");
1.1       root      198:         return -1;
                    199:     }
                    200: 
1.1.1.2   root      201:     if ((*blen1 & info->align) || (*blen2 & info->align)) {
                    202:         dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
                    203:                *blen1, *blen2, info->align + 1);
                    204: 
                    205:         fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2);
                    206: 
                    207:         *p1 = NULL - 1;
                    208:         *p2 = NULL - 1;
                    209:         *blen1 = ~0U;
                    210:         *blen2 = ~0U;
1.1       root      211:         return -1;
                    212:     }
1.1.1.2   root      213: 
                    214:     if (!*p1 && *blen1) {
                    215:         dolog ("warning: !p1 && blen1=%d\n", *blen1);
                    216:         *blen1 = 0;
                    217:     }
                    218: 
                    219:     if (!p2 && *blen2) {
                    220:         dolog ("warning: !p2 && blen2=%d\n", *blen2);
                    221:         *blen2 = 0;
                    222:     }
                    223: 
1.1       root      224:     return 0;
                    225: }
                    226: 
1.1.1.6   root      227: static int fmod_run_out (HWVoiceOut *hw, int live)
1.1       root      228: {
1.1.1.2   root      229:     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
1.1.1.6   root      230:     int decr;
1.1       root      231:     void *p1 = 0, *p2 = 0;
                    232:     unsigned int blen1 = 0, blen2 = 0;
                    233:     unsigned int len1 = 0, len2 = 0;
                    234: 
1.1.1.6   root      235:     if (!hw->pending_disable) {
1.1.1.2   root      236:         return 0;
1.1       root      237:     }
                    238: 
                    239:     decr = live;
                    240: 
                    241:     if (fmd->channel >= 0) {
1.1.1.2   root      242:         int len = decr;
                    243:         int old_pos = fmd->old_pos;
                    244:         int ppos = FSOUND_GetCurrentPosition (fmd->channel);
1.1       root      245: 
1.1.1.2   root      246:         if (ppos == old_pos || !ppos) {
                    247:             return 0;
1.1       root      248:         }
1.1.1.2   root      249: 
                    250:         if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
                    251:             len = ppos - old_pos;
                    252:         }
                    253:         else {
                    254:             if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
                    255:                 len = hw->samples - old_pos + ppos;
                    256:             }
                    257:         }
                    258:         decr = len;
                    259: 
                    260:         if (audio_bug (AUDIO_FUNC, decr < 0)) {
                    261:             dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
                    262:                    decr, live, ppos, old_pos, len);
                    263:             return 0;
1.1       root      264:         }
                    265:     }
                    266: 
1.1.1.2   root      267: 
                    268:     if (!decr) {
                    269:         return 0;
1.1       root      270:     }
                    271: 
1.1.1.2   root      272:     if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
                    273:                           fmd->old_pos, decr,
                    274:                           &p1, &p2,
                    275:                           &blen1, &blen2)) {
                    276:         return 0;
1.1       root      277:     }
                    278: 
1.1.1.2   root      279:     len1 = blen1 >> hw->info.shift;
                    280:     len2 = blen2 >> hw->info.shift;
1.1       root      281:     ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
                    282:     decr = len1 + len2;
                    283: 
1.1.1.2   root      284:     if (p1 && len1) {
                    285:         fmod_write_sample (hw, p1, len1);
1.1       root      286:     }
                    287: 
1.1.1.2   root      288:     if (p2 && len2) {
                    289:         fmod_write_sample (hw, p2, len2);
1.1       root      290:     }
                    291: 
1.1.1.2   root      292:     fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
1.1       root      293: 
                    294:     fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
1.1.1.2   root      295:     return decr;
1.1       root      296: }
                    297: 
1.1.1.2   root      298: static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
1.1       root      299: {
                    300:     int mode = FSOUND_LOOP_NORMAL;
                    301: 
                    302:     switch (fmt) {
                    303:     case AUD_FMT_S8:
                    304:         mode |= FSOUND_SIGNED | FSOUND_8BITS;
                    305:         break;
                    306: 
                    307:     case AUD_FMT_U8:
                    308:         mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
                    309:         break;
                    310: 
                    311:     case AUD_FMT_S16:
                    312:         mode |= FSOUND_SIGNED | FSOUND_16BITS;
                    313:         break;
                    314: 
                    315:     case AUD_FMT_U16:
                    316:         mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
                    317:         break;
                    318: 
                    319:     default:
1.1.1.2   root      320:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
                    321: #ifdef DEBUG_FMOD
                    322:         abort ();
                    323: #endif
                    324:         mode |= FSOUND_8BITS;
1.1       root      325:     }
                    326:     mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
                    327:     return mode;
                    328: }
                    329: 
1.1.1.2   root      330: static void fmod_fini_out (HWVoiceOut *hw)
1.1       root      331: {
1.1.1.2   root      332:     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
1.1       root      333: 
                    334:     if (fmd->fmod_sample) {
                    335:         FSOUND_Sample_Free (fmd->fmod_sample);
                    336:         fmd->fmod_sample = 0;
                    337: 
                    338:         if (fmd->channel >= 0) {
                    339:             FSOUND_StopSound (fmd->channel);
                    340:         }
                    341:     }
                    342: }
                    343: 
1.1.1.5   root      344: static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
1.1       root      345: {
                    346:     int bits16, mode, channel;
1.1.1.2   root      347:     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
1.1.1.5   root      348:     struct audsettings obt_as = *as;
1.1       root      349: 
1.1.1.2   root      350:     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
1.1       root      351:     fmd->fmod_sample = FSOUND_Sample_Alloc (
                    352:         FSOUND_FREE,            /* index */
                    353:         conf.nb_samples,        /* length */
                    354:         mode,                   /* mode */
1.1.1.2   root      355:         as->freq,               /* freq */
1.1       root      356:         255,                    /* volume */
                    357:         128,                    /* pan */
                    358:         255                     /* priority */
                    359:         );
                    360: 
                    361:     if (!fmd->fmod_sample) {
1.1.1.2   root      362:         fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
1.1       root      363:         return -1;
                    364:     }
                    365: 
                    366:     channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
                    367:     if (channel < 0) {
1.1.1.2   root      368:         fmod_logerr2 ("DAC", "Failed to start playing sound\n");
1.1       root      369:         FSOUND_Sample_Free (fmd->fmod_sample);
                    370:         return -1;
                    371:     }
                    372:     fmd->channel = channel;
                    373: 
1.1.1.2   root      374:     /* FMOD always operates on little endian frames? */
1.1.1.3   root      375:     obt_as.endianness = 0;
                    376:     audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2   root      377:     bits16 = (mode & FSOUND_16BITS) != 0;
                    378:     hw->samples = conf.nb_samples;
1.1       root      379:     return 0;
                    380: }
                    381: 
1.1.1.2   root      382: static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1       root      383: {
                    384:     int status;
1.1.1.2   root      385:     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
1.1       root      386: 
                    387:     switch (cmd) {
                    388:     case VOICE_ENABLE:
                    389:         fmod_clear_sample (fmd);
                    390:         status = FSOUND_SetPaused (fmd->channel, 0);
                    391:         if (!status) {
1.1.1.2   root      392:             fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
1.1       root      393:         }
                    394:         break;
                    395: 
                    396:     case VOICE_DISABLE:
                    397:         status = FSOUND_SetPaused (fmd->channel, 1);
                    398:         if (!status) {
1.1.1.2   root      399:             fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
1.1       root      400:         }
                    401:         break;
                    402:     }
                    403:     return 0;
                    404: }
                    405: 
1.1.1.5   root      406: static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
1.1.1.2   root      407: {
                    408:     int bits16, mode;
                    409:     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
1.1.1.5   root      410:     struct audsettings obt_as = *as;
1.1.1.2   root      411: 
                    412:     if (conf.broken_adc) {
                    413:         return -1;
                    414:     }
                    415: 
                    416:     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
                    417:     fmd->fmod_sample = FSOUND_Sample_Alloc (
                    418:         FSOUND_FREE,            /* index */
                    419:         conf.nb_samples,        /* length */
                    420:         mode,                   /* mode */
                    421:         as->freq,               /* freq */
                    422:         255,                    /* volume */
                    423:         128,                    /* pan */
                    424:         255                     /* priority */
                    425:         );
                    426: 
                    427:     if (!fmd->fmod_sample) {
                    428:         fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
                    429:         return -1;
                    430:     }
                    431: 
                    432:     /* FMOD always operates on little endian frames? */
1.1.1.3   root      433:     obt_as.endianness = 0;
                    434:     audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2   root      435:     bits16 = (mode & FSOUND_16BITS) != 0;
                    436:     hw->samples = conf.nb_samples;
                    437:     return 0;
                    438: }
                    439: 
                    440: static void fmod_fini_in (HWVoiceIn *hw)
                    441: {
                    442:     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
                    443: 
                    444:     if (fmd->fmod_sample) {
                    445:         FSOUND_Record_Stop ();
                    446:         FSOUND_Sample_Free (fmd->fmod_sample);
                    447:         fmd->fmod_sample = 0;
                    448:     }
                    449: }
                    450: 
                    451: static int fmod_run_in (HWVoiceIn *hw)
                    452: {
                    453:     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
                    454:     int hwshift = hw->info.shift;
                    455:     int live, dead, new_pos, len;
                    456:     unsigned int blen1 = 0, blen2 = 0;
                    457:     unsigned int len1, len2;
                    458:     unsigned int decr;
                    459:     void *p1, *p2;
                    460: 
                    461:     live = audio_pcm_hw_get_live_in (hw);
                    462:     dead = hw->samples - live;
                    463:     if (!dead) {
                    464:         return 0;
                    465:     }
                    466: 
                    467:     new_pos = FSOUND_Record_GetPosition ();
                    468:     if (new_pos < 0) {
                    469:         fmod_logerr ("Could not get recording position\n");
                    470:         return 0;
                    471:     }
                    472: 
                    473:     len = audio_ring_dist (new_pos,  hw->wpos, hw->samples);
                    474:     if (!len) {
                    475:         return 0;
                    476:     }
                    477:     len = audio_MIN (len, dead);
                    478: 
                    479:     if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
                    480:                           hw->wpos, len,
                    481:                           &p1, &p2,
                    482:                           &blen1, &blen2)) {
                    483:         return 0;
                    484:     }
                    485: 
                    486:     len1 = blen1 >> hwshift;
                    487:     len2 = blen2 >> hwshift;
                    488:     decr = len1 + len2;
                    489: 
                    490:     if (p1 && blen1) {
1.1.1.7 ! root      491:         hw->conv (hw->conv_buf + hw->wpos, p1, len1);
1.1.1.2   root      492:     }
                    493:     if (p2 && len2) {
1.1.1.7 ! root      494:         hw->conv (hw->conv_buf, p2, len2);
1.1.1.2   root      495:     }
                    496: 
                    497:     fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
                    498:     hw->wpos = (hw->wpos + decr) % hw->samples;
                    499:     return decr;
                    500: }
                    501: 
1.1       root      502: static struct {
                    503:     const char *name;
                    504:     int type;
                    505: } drvtab[] = {
1.1.1.6   root      506:     { .name = "none",   .type = FSOUND_OUTPUT_NOSOUND },
1.1       root      507: #ifdef _WIN32
1.1.1.6   root      508:     { .name = "winmm",  .type = FSOUND_OUTPUT_WINMM   },
                    509:     { .name = "dsound", .type = FSOUND_OUTPUT_DSOUND  },
                    510:     { .name = "a3d",    .type = FSOUND_OUTPUT_A3D     },
                    511:     { .name = "asio",   .type = FSOUND_OUTPUT_ASIO    },
1.1       root      512: #endif
                    513: #ifdef __linux__
1.1.1.6   root      514:     { .name = "oss",    .type = FSOUND_OUTPUT_OSS     },
                    515:     { .name = "alsa",   .type = FSOUND_OUTPUT_ALSA    },
                    516:     { .name = "esd",    .type = FSOUND_OUTPUT_ESD     },
1.1       root      517: #endif
                    518: #ifdef __APPLE__
1.1.1.6   root      519:     { .name = "mac",    .type = FSOUND_OUTPUT_MAC     },
1.1       root      520: #endif
                    521: #if 0
1.1.1.6   root      522:     { .name = "xbox",   .type = FSOUND_OUTPUT_XBOX    },
                    523:     { .name = "ps2",    .type = FSOUND_OUTPUT_PS2     },
                    524:     { .name = "gcube",  .type = FSOUND_OUTPUT_GC      },
1.1       root      525: #endif
1.1.1.6   root      526:     { .name = "none-realtime", .type = FSOUND_OUTPUT_NOSOUND_NONREALTIME }
1.1       root      527: };
                    528: 
                    529: static void *fmod_audio_init (void)
                    530: {
1.1.1.2   root      531:     size_t i;
1.1       root      532:     double ver;
                    533:     int status;
                    534:     int output_type = -1;
1.1.1.2   root      535:     const char *drv = conf.drvname;
1.1       root      536: 
                    537:     ver = FSOUND_GetVersion ();
                    538:     if (ver < FMOD_VERSION) {
                    539:         dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
                    540:         return NULL;
                    541:     }
                    542: 
1.1.1.2   root      543: #ifdef __linux__
                    544:     if (ver < 3.75) {
                    545:         dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
                    546:                "ADC will be disabled.\n");
                    547:         conf.broken_adc = 1;
                    548:     }
                    549: #endif
                    550: 
1.1       root      551:     if (drv) {
                    552:         int found = 0;
1.1.1.5   root      553:         for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
1.1       root      554:             if (!strcmp (drv, drvtab[i].name)) {
                    555:                 output_type = drvtab[i].type;
                    556:                 found = 1;
                    557:                 break;
                    558:             }
                    559:         }
                    560:         if (!found) {
1.1.1.2   root      561:             dolog ("Unknown FMOD driver `%s'\n", drv);
                    562:             dolog ("Valid drivers:\n");
1.1.1.5   root      563:             for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
1.1.1.2   root      564:                 dolog ("  %s\n", drvtab[i].name);
                    565:             }
1.1       root      566:         }
                    567:     }
                    568: 
                    569:     if (output_type != -1) {
                    570:         status = FSOUND_SetOutput (output_type);
                    571:         if (!status) {
1.1.1.2   root      572:             fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
1.1       root      573:             return NULL;
                    574:         }
                    575:     }
                    576: 
                    577:     if (conf.bufsize) {
                    578:         status = FSOUND_SetBufferSize (conf.bufsize);
                    579:         if (!status) {
1.1.1.2   root      580:             fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
1.1       root      581:         }
                    582:     }
                    583: 
                    584:     status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
                    585:     if (!status) {
1.1.1.2   root      586:         fmod_logerr ("FSOUND_Init failed\n");
1.1       root      587:         return NULL;
                    588:     }
                    589: 
                    590:     return &conf;
                    591: }
                    592: 
1.1.1.2   root      593: static int fmod_read (SWVoiceIn *sw, void *buf, int size)
                    594: {
                    595:     return audio_pcm_sw_read (sw, buf, size);
                    596: }
                    597: 
                    598: static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    599: {
                    600:     int status;
                    601:     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
                    602: 
                    603:     switch (cmd) {
                    604:     case VOICE_ENABLE:
                    605:         status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
                    606:         if (!status) {
                    607:             fmod_logerr ("Failed to start recording\n");
                    608:         }
                    609:         break;
                    610: 
                    611:     case VOICE_DISABLE:
                    612:         status = FSOUND_Record_Stop ();
                    613:         if (!status) {
                    614:             fmod_logerr ("Failed to stop recording\n");
                    615:         }
                    616:         break;
                    617:     }
                    618:     return 0;
                    619: }
                    620: 
1.1       root      621: static void fmod_audio_fini (void *opaque)
                    622: {
1.1.1.2   root      623:     (void) opaque;
1.1       root      624:     FSOUND_Close ();
                    625: }
                    626: 
1.1.1.2   root      627: static struct audio_option fmod_options[] = {
1.1.1.6   root      628:     {
                    629:         .name  = "DRV",
                    630:         .tag   = AUD_OPT_STR,
                    631:         .valp  = &conf.drvname,
                    632:         .descr = "FMOD driver"
                    633:     },
                    634:     {
                    635:         .name  = "FREQ",
                    636:         .tag   = AUD_OPT_INT,
                    637:         .valp  = &conf.freq,
                    638:         .descr = "Default frequency"
                    639:     },
                    640:     {
                    641:         .name  = "SAMPLES",
                    642:         .tag   = AUD_OPT_INT,
                    643:         .valp  = &conf.nb_samples,
                    644:         .descr = "Buffer size in samples"
                    645:     },
                    646:     {
                    647:         .name  = "CHANNELS",
                    648:         .tag   = AUD_OPT_INT,
                    649:         .valp  = &conf.nb_channels,
                    650:         .descr = "Number of default channels (1 - mono, 2 - stereo)"
                    651:     },
                    652:     {
                    653:         .name  = "BUFSIZE",
                    654:         .tag   = AUD_OPT_INT,
                    655:         .valp  = &conf.bufsize,
                    656:         .descr = "(undocumented)"
                    657:     },
                    658:     { /* End of list */ }
1.1.1.2   root      659: };
                    660: 
                    661: static struct audio_pcm_ops fmod_pcm_ops = {
1.1.1.6   root      662:     .init_out = fmod_init_out,
                    663:     .fini_out = fmod_fini_out,
                    664:     .run_out  = fmod_run_out,
                    665:     .write    = fmod_write,
                    666:     .ctl_out  = fmod_ctl_out,
                    667: 
                    668:     .init_in  = fmod_init_in,
                    669:     .fini_in  = fmod_fini_in,
                    670:     .run_in   = fmod_run_in,
                    671:     .read     = fmod_read,
                    672:     .ctl_in   = fmod_ctl_in
1.1       root      673: };
                    674: 
1.1.1.2   root      675: struct audio_driver fmod_audio_driver = {
1.1.1.6   root      676:     .name           = "fmod",
                    677:     .descr          = "FMOD 3.xx http://www.fmod.org",
                    678:     .options        = fmod_options,
                    679:     .init           = fmod_audio_init,
                    680:     .fini           = fmod_audio_fini,
                    681:     .pcm_ops        = &fmod_pcm_ops,
                    682:     .can_be_default = 1,
                    683:     .max_voices_out = INT_MAX,
                    684:     .max_voices_in  = INT_MAX,
                    685:     .voice_size_out = sizeof (FMODVoiceOut),
                    686:     .voice_size_in  = sizeof (FMODVoiceIn)
1.1       root      687: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.