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

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

unix.superglobalmegacorp.com

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