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

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