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

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: {
1.1.1.8 ! root      346:     int 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:     hw->samples = conf.nb_samples;
1.1       root      378:     return 0;
                    379: }
                    380: 
1.1.1.2   root      381: static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1       root      382: {
                    383:     int status;
1.1.1.2   root      384:     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
1.1       root      385: 
                    386:     switch (cmd) {
                    387:     case VOICE_ENABLE:
                    388:         fmod_clear_sample (fmd);
                    389:         status = FSOUND_SetPaused (fmd->channel, 0);
                    390:         if (!status) {
1.1.1.2   root      391:             fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
1.1       root      392:         }
                    393:         break;
                    394: 
                    395:     case VOICE_DISABLE:
                    396:         status = FSOUND_SetPaused (fmd->channel, 1);
                    397:         if (!status) {
1.1.1.2   root      398:             fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
1.1       root      399:         }
                    400:         break;
                    401:     }
                    402:     return 0;
                    403: }
                    404: 
1.1.1.5   root      405: static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
1.1.1.2   root      406: {
1.1.1.8 ! root      407:     int mode;
1.1.1.2   root      408:     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
1.1.1.5   root      409:     struct audsettings obt_as = *as;
1.1.1.2   root      410: 
                    411:     if (conf.broken_adc) {
                    412:         return -1;
                    413:     }
                    414: 
                    415:     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
                    416:     fmd->fmod_sample = FSOUND_Sample_Alloc (
                    417:         FSOUND_FREE,            /* index */
                    418:         conf.nb_samples,        /* length */
                    419:         mode,                   /* mode */
                    420:         as->freq,               /* freq */
                    421:         255,                    /* volume */
                    422:         128,                    /* pan */
                    423:         255                     /* priority */
                    424:         );
                    425: 
                    426:     if (!fmd->fmod_sample) {
                    427:         fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
                    428:         return -1;
                    429:     }
                    430: 
                    431:     /* FMOD always operates on little endian frames? */
1.1.1.3   root      432:     obt_as.endianness = 0;
                    433:     audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2   root      434:     hw->samples = conf.nb_samples;
                    435:     return 0;
                    436: }
                    437: 
                    438: static void fmod_fini_in (HWVoiceIn *hw)
                    439: {
                    440:     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
                    441: 
                    442:     if (fmd->fmod_sample) {
                    443:         FSOUND_Record_Stop ();
                    444:         FSOUND_Sample_Free (fmd->fmod_sample);
                    445:         fmd->fmod_sample = 0;
                    446:     }
                    447: }
                    448: 
                    449: static int fmod_run_in (HWVoiceIn *hw)
                    450: {
                    451:     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
                    452:     int hwshift = hw->info.shift;
                    453:     int live, dead, new_pos, len;
                    454:     unsigned int blen1 = 0, blen2 = 0;
                    455:     unsigned int len1, len2;
                    456:     unsigned int decr;
                    457:     void *p1, *p2;
                    458: 
                    459:     live = audio_pcm_hw_get_live_in (hw);
                    460:     dead = hw->samples - live;
                    461:     if (!dead) {
                    462:         return 0;
                    463:     }
                    464: 
                    465:     new_pos = FSOUND_Record_GetPosition ();
                    466:     if (new_pos < 0) {
                    467:         fmod_logerr ("Could not get recording position\n");
                    468:         return 0;
                    469:     }
                    470: 
                    471:     len = audio_ring_dist (new_pos,  hw->wpos, hw->samples);
                    472:     if (!len) {
                    473:         return 0;
                    474:     }
                    475:     len = audio_MIN (len, dead);
                    476: 
                    477:     if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
                    478:                           hw->wpos, len,
                    479:                           &p1, &p2,
                    480:                           &blen1, &blen2)) {
                    481:         return 0;
                    482:     }
                    483: 
                    484:     len1 = blen1 >> hwshift;
                    485:     len2 = blen2 >> hwshift;
                    486:     decr = len1 + len2;
                    487: 
                    488:     if (p1 && blen1) {
1.1.1.7   root      489:         hw->conv (hw->conv_buf + hw->wpos, p1, len1);
1.1.1.2   root      490:     }
                    491:     if (p2 && len2) {
1.1.1.7   root      492:         hw->conv (hw->conv_buf, p2, len2);
1.1.1.2   root      493:     }
                    494: 
                    495:     fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
                    496:     hw->wpos = (hw->wpos + decr) % hw->samples;
                    497:     return decr;
                    498: }
                    499: 
1.1       root      500: static struct {
                    501:     const char *name;
                    502:     int type;
                    503: } drvtab[] = {
1.1.1.6   root      504:     { .name = "none",   .type = FSOUND_OUTPUT_NOSOUND },
1.1       root      505: #ifdef _WIN32
1.1.1.6   root      506:     { .name = "winmm",  .type = FSOUND_OUTPUT_WINMM   },
                    507:     { .name = "dsound", .type = FSOUND_OUTPUT_DSOUND  },
                    508:     { .name = "a3d",    .type = FSOUND_OUTPUT_A3D     },
                    509:     { .name = "asio",   .type = FSOUND_OUTPUT_ASIO    },
1.1       root      510: #endif
                    511: #ifdef __linux__
1.1.1.6   root      512:     { .name = "oss",    .type = FSOUND_OUTPUT_OSS     },
                    513:     { .name = "alsa",   .type = FSOUND_OUTPUT_ALSA    },
                    514:     { .name = "esd",    .type = FSOUND_OUTPUT_ESD     },
1.1       root      515: #endif
                    516: #ifdef __APPLE__
1.1.1.6   root      517:     { .name = "mac",    .type = FSOUND_OUTPUT_MAC     },
1.1       root      518: #endif
                    519: #if 0
1.1.1.6   root      520:     { .name = "xbox",   .type = FSOUND_OUTPUT_XBOX    },
                    521:     { .name = "ps2",    .type = FSOUND_OUTPUT_PS2     },
                    522:     { .name = "gcube",  .type = FSOUND_OUTPUT_GC      },
1.1       root      523: #endif
1.1.1.6   root      524:     { .name = "none-realtime", .type = FSOUND_OUTPUT_NOSOUND_NONREALTIME }
1.1       root      525: };
                    526: 
                    527: static void *fmod_audio_init (void)
                    528: {
1.1.1.2   root      529:     size_t i;
1.1       root      530:     double ver;
                    531:     int status;
                    532:     int output_type = -1;
1.1.1.2   root      533:     const char *drv = conf.drvname;
1.1       root      534: 
                    535:     ver = FSOUND_GetVersion ();
                    536:     if (ver < FMOD_VERSION) {
                    537:         dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
                    538:         return NULL;
                    539:     }
                    540: 
1.1.1.2   root      541: #ifdef __linux__
                    542:     if (ver < 3.75) {
                    543:         dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
                    544:                "ADC will be disabled.\n");
                    545:         conf.broken_adc = 1;
                    546:     }
                    547: #endif
                    548: 
1.1       root      549:     if (drv) {
                    550:         int found = 0;
1.1.1.5   root      551:         for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
1.1       root      552:             if (!strcmp (drv, drvtab[i].name)) {
                    553:                 output_type = drvtab[i].type;
                    554:                 found = 1;
                    555:                 break;
                    556:             }
                    557:         }
                    558:         if (!found) {
1.1.1.2   root      559:             dolog ("Unknown FMOD driver `%s'\n", drv);
                    560:             dolog ("Valid drivers:\n");
1.1.1.5   root      561:             for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
1.1.1.2   root      562:                 dolog ("  %s\n", drvtab[i].name);
                    563:             }
1.1       root      564:         }
                    565:     }
                    566: 
                    567:     if (output_type != -1) {
                    568:         status = FSOUND_SetOutput (output_type);
                    569:         if (!status) {
1.1.1.2   root      570:             fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
1.1       root      571:             return NULL;
                    572:         }
                    573:     }
                    574: 
                    575:     if (conf.bufsize) {
                    576:         status = FSOUND_SetBufferSize (conf.bufsize);
                    577:         if (!status) {
1.1.1.2   root      578:             fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
1.1       root      579:         }
                    580:     }
                    581: 
                    582:     status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
                    583:     if (!status) {
1.1.1.2   root      584:         fmod_logerr ("FSOUND_Init failed\n");
1.1       root      585:         return NULL;
                    586:     }
                    587: 
                    588:     return &conf;
                    589: }
                    590: 
1.1.1.2   root      591: static int fmod_read (SWVoiceIn *sw, void *buf, int size)
                    592: {
                    593:     return audio_pcm_sw_read (sw, buf, size);
                    594: }
                    595: 
                    596: static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    597: {
                    598:     int status;
                    599:     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
                    600: 
                    601:     switch (cmd) {
                    602:     case VOICE_ENABLE:
                    603:         status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
                    604:         if (!status) {
                    605:             fmod_logerr ("Failed to start recording\n");
                    606:         }
                    607:         break;
                    608: 
                    609:     case VOICE_DISABLE:
                    610:         status = FSOUND_Record_Stop ();
                    611:         if (!status) {
                    612:             fmod_logerr ("Failed to stop recording\n");
                    613:         }
                    614:         break;
                    615:     }
                    616:     return 0;
                    617: }
                    618: 
1.1       root      619: static void fmod_audio_fini (void *opaque)
                    620: {
1.1.1.2   root      621:     (void) opaque;
1.1       root      622:     FSOUND_Close ();
                    623: }
                    624: 
1.1.1.2   root      625: static struct audio_option fmod_options[] = {
1.1.1.6   root      626:     {
                    627:         .name  = "DRV",
                    628:         .tag   = AUD_OPT_STR,
                    629:         .valp  = &conf.drvname,
                    630:         .descr = "FMOD driver"
                    631:     },
                    632:     {
                    633:         .name  = "FREQ",
                    634:         .tag   = AUD_OPT_INT,
                    635:         .valp  = &conf.freq,
                    636:         .descr = "Default frequency"
                    637:     },
                    638:     {
                    639:         .name  = "SAMPLES",
                    640:         .tag   = AUD_OPT_INT,
                    641:         .valp  = &conf.nb_samples,
                    642:         .descr = "Buffer size in samples"
                    643:     },
                    644:     {
                    645:         .name  = "CHANNELS",
                    646:         .tag   = AUD_OPT_INT,
                    647:         .valp  = &conf.nb_channels,
                    648:         .descr = "Number of default channels (1 - mono, 2 - stereo)"
                    649:     },
                    650:     {
                    651:         .name  = "BUFSIZE",
                    652:         .tag   = AUD_OPT_INT,
                    653:         .valp  = &conf.bufsize,
                    654:         .descr = "(undocumented)"
                    655:     },
                    656:     { /* End of list */ }
1.1.1.2   root      657: };
                    658: 
                    659: static struct audio_pcm_ops fmod_pcm_ops = {
1.1.1.6   root      660:     .init_out = fmod_init_out,
                    661:     .fini_out = fmod_fini_out,
                    662:     .run_out  = fmod_run_out,
                    663:     .write    = fmod_write,
                    664:     .ctl_out  = fmod_ctl_out,
                    665: 
                    666:     .init_in  = fmod_init_in,
                    667:     .fini_in  = fmod_fini_in,
                    668:     .run_in   = fmod_run_in,
                    669:     .read     = fmod_read,
                    670:     .ctl_in   = fmod_ctl_in
1.1       root      671: };
                    672: 
1.1.1.2   root      673: struct audio_driver fmod_audio_driver = {
1.1.1.6   root      674:     .name           = "fmod",
                    675:     .descr          = "FMOD 3.xx http://www.fmod.org",
                    676:     .options        = fmod_options,
                    677:     .init           = fmod_audio_init,
                    678:     .fini           = fmod_audio_fini,
                    679:     .pcm_ops        = &fmod_pcm_ops,
                    680:     .can_be_default = 1,
                    681:     .max_voices_out = INT_MAX,
                    682:     .max_voices_in  = INT_MAX,
                    683:     .voice_size_out = sizeof (FMODVoiceOut),
                    684:     .voice_size_in  = sizeof (FMODVoiceIn)
1.1       root      685: };

unix.superglobalmegacorp.com

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