[BACK]Return to dev.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sndiod

Annotation of src/usr.bin/sndiod/dev.c, Revision 1.1

1.1     ! ratchov     1: /*     $OpenBSD$       */
        !             2: /*
        !             3:  * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17: #include <stdio.h>
        !            18: #include <string.h>
        !            19:
        !            20: #include "abuf.h"
        !            21: #include "defs.h"
        !            22: #include "dev.h"
        !            23: #include "dsp.h"
        !            24: #include "siofile.h"
        !            25: #include "midi.h"
        !            26: #include "opt.h"
        !            27: #include "sysex.h"
        !            28: #include "utils.h"
        !            29:
        !            30: int  dev_open(struct dev *);
        !            31: void dev_close(struct dev *);
        !            32: void dev_clear(struct dev *);
        !            33: void dev_master(struct dev *, unsigned int);
        !            34:
        !            35: void slot_attach(struct slot *);
        !            36: void slot_ready(struct slot *);
        !            37: void slot_mix_drop(struct slot *);
        !            38: void slot_sub_sil(struct slot *);
        !            39:
        !            40: void zomb_onmove(void *, int);
        !            41: void zomb_onvol(void *, unsigned int);
        !            42: void zomb_fill(void *);
        !            43: void zomb_flush(void *);
        !            44: void zomb_eof(void *);
        !            45: void zomb_mmcstart(void *);
        !            46: void zomb_mmcstop(void *);
        !            47: void zomb_mmcloc(void *, unsigned int);
        !            48: void zomb_exit(void *);
        !            49:
        !            50: void dev_midi_imsg(void *, unsigned char *, int);
        !            51: void dev_midi_omsg(void *, unsigned char *, int);
        !            52: void dev_midi_fill(void *, int);
        !            53: void dev_midi_exit(void *);
        !            54:
        !            55: struct midiops dev_midiops = {
        !            56:        dev_midi_imsg,
        !            57:        dev_midi_omsg,
        !            58:        dev_midi_fill,
        !            59:        dev_midi_exit
        !            60: };
        !            61:
        !            62: struct slotops zomb_slotops = {
        !            63:        zomb_onmove,
        !            64:        zomb_onvol,
        !            65:        zomb_fill,
        !            66:        zomb_flush,
        !            67:        zomb_eof,
        !            68:        zomb_mmcstart,
        !            69:        zomb_mmcstop,
        !            70:        zomb_mmcloc,
        !            71:        zomb_exit
        !            72: };
        !            73:
        !            74: struct dev *dev_list = NULL;
        !            75: unsigned int dev_sndnum = 0;
        !            76:
        !            77: void
        !            78: dev_log(struct dev *d)
        !            79: {
        !            80:        log_puts("snd");
        !            81:        log_putu(d->num);
        !            82: }
        !            83:
        !            84: void
        !            85: slot_log(struct slot *s)
        !            86: {
        !            87: #ifdef DEBUG
        !            88:        static char *pstates[] = {
        !            89:                "ini", "sta", "rdy", "run", "stp", "mid"
        !            90:        };
        !            91:        static char *tstates[] = {
        !            92:                "off", "sta", "run", "stp"
        !            93:        };
        !            94: #endif
        !            95:        log_puts(s->name);
        !            96:        log_putu(s->unit);
        !            97: #ifdef DEBUG
        !            98:        if (log_level >= 3) {
        !            99:                log_puts(" vol=");
        !           100:                log_putu(s->vol);
        !           101:                if (s->ops) {
        !           102:                        log_puts(",pst=");
        !           103:                        log_puts(pstates[s->pstate]);
        !           104:                        log_puts(",mmc=");
        !           105:                        log_puts(tstates[s->tstate]);
        !           106:                }
        !           107:        }
        !           108: #endif
        !           109: }
        !           110:
        !           111: void
        !           112: zomb_onmove(void *arg, int delta)
        !           113: {
        !           114: }
        !           115:
        !           116: void
        !           117: zomb_onvol(void *arg, unsigned int vol)
        !           118: {
        !           119: }
        !           120:
        !           121: void
        !           122: zomb_fill(void *arg)
        !           123: {
        !           124: }
        !           125:
        !           126: void
        !           127: zomb_flush(void *arg)
        !           128: {
        !           129: }
        !           130:
        !           131: void
        !           132: zomb_eof(void *arg)
        !           133: {
        !           134:        struct slot *s = arg;
        !           135:
        !           136: #ifdef DEBUG
        !           137:        if (log_level >= 3) {
        !           138:                slot_log(s);
        !           139:                log_puts(": zomb_eof\n");
        !           140:        }
        !           141: #endif
        !           142:        s->ops = NULL;
        !           143: }
        !           144:
        !           145: void
        !           146: zomb_mmcstart(void *arg)
        !           147: {
        !           148: }
        !           149:
        !           150: void
        !           151: zomb_mmcstop(void *arg)
        !           152: {
        !           153: }
        !           154:
        !           155: void
        !           156: zomb_mmcloc(void *arg, unsigned int pos)
        !           157: {
        !           158: }
        !           159:
        !           160: void
        !           161: zomb_exit(void *arg)
        !           162: {
        !           163: #ifdef DEBUG
        !           164:        struct slot *s = arg;
        !           165:
        !           166:        if (log_level >= 3) {
        !           167:                slot_log(s);
        !           168:                log_puts(": zomb_exit\n");
        !           169:        }
        !           170: #endif
        !           171: }
        !           172:
        !           173: /*
        !           174:  * send a quarter frame MTC message
        !           175:  */
        !           176: void
        !           177: dev_midi_qfr(struct dev *d, int delta)
        !           178: {
        !           179:        unsigned char buf[2];
        !           180:        unsigned int data;
        !           181:        int qfrlen;
        !           182:
        !           183:        d->mtc.delta += delta * MTC_SEC;
        !           184:        qfrlen = d->rate * (MTC_SEC / (4 * d->mtc.fps));
        !           185:        while (d->mtc.delta >= qfrlen) {
        !           186:                switch (d->mtc.qfr) {
        !           187:                case 0:
        !           188:                        data = d->mtc.fr & 0xf;
        !           189:                        break;
        !           190:                case 1:
        !           191:                        data = d->mtc.fr >> 4;
        !           192:                        break;
        !           193:                case 2:
        !           194:                        data = d->mtc.sec & 0xf;
        !           195:                        break;
        !           196:                case 3:
        !           197:                        data = d->mtc.sec >> 4;
        !           198:                        break;
        !           199:                case 4:
        !           200:                        data = d->mtc.min & 0xf;
        !           201:                        break;
        !           202:                case 5:
        !           203:                        data = d->mtc.min >> 4;
        !           204:                        break;
        !           205:                case 6:
        !           206:                        data = d->mtc.hr & 0xf;
        !           207:                        break;
        !           208:                case 7:
        !           209:                        data = (d->mtc.hr >> 4) | (d->mtc.fps_id << 1);
        !           210:                        /*
        !           211:                         * tick messages are sent 2 frames ahead
        !           212:                         */
        !           213:                        d->mtc.fr += 2;
        !           214:                        if (d->mtc.fr < d->mtc.fps)
        !           215:                                break;
        !           216:                        d->mtc.fr -= d->mtc.fps;
        !           217:                        d->mtc.sec++;
        !           218:                        if (d->mtc.sec < 60)
        !           219:                                break;
        !           220:                        d->mtc.sec = 0;
        !           221:                        d->mtc.min++;
        !           222:                        if (d->mtc.min < 60)
        !           223:                                break;
        !           224:                        d->mtc.min = 0;
        !           225:                        d->mtc.hr++;
        !           226:                        if (d->mtc.hr < 24)
        !           227:                                break;
        !           228:                        d->mtc.hr = 0;
        !           229:                        break;
        !           230:                default:
        !           231:                        /* NOTREACHED */
        !           232:                        data = 0;
        !           233:                }
        !           234:                buf[0] = 0xf1;
        !           235:                buf[1] = (d->mtc.qfr << 4) | data;
        !           236:                d->mtc.qfr++;
        !           237:                d->mtc.qfr &= 7;
        !           238:                midi_send(d->midi, buf, 2);
        !           239:                d->mtc.delta -= qfrlen;
        !           240:        }
        !           241: }
        !           242:
        !           243: /*
        !           244:  * send a full frame MTC message
        !           245:  */
        !           246: void
        !           247: dev_midi_full(struct dev *d)
        !           248: {
        !           249:        struct sysex x;
        !           250:        unsigned int fps;
        !           251:
        !           252:        d->mtc.delta = MTC_SEC * dev_getpos(d);
        !           253:        if (d->rate % (30 * 4 * d->round) == 0) {
        !           254:                d->mtc.fps_id = MTC_FPS_30;
        !           255:                d->mtc.fps = 30;
        !           256:        } else if (d->rate % (25 * 4 * d->round) == 0) {
        !           257:                d->mtc.fps_id = MTC_FPS_25;
        !           258:                d->mtc.fps = 25;
        !           259:        } else {
        !           260:                d->mtc.fps_id = MTC_FPS_24;
        !           261:                d->mtc.fps = 24;
        !           262:        }
        !           263: #ifdef DEBUG
        !           264:        if (log_level >= 3) {
        !           265:                dev_log(d);
        !           266:                log_puts(": mtc full frame at ");
        !           267:                log_puti(d->mtc.delta);
        !           268:                log_puts(", ");
        !           269:                log_puti(d->mtc.fps);
        !           270:                log_puts(" fps\n");
        !           271:        }
        !           272: #endif
        !           273:        fps = d->mtc.fps;
        !           274:        d->mtc.hr =  (d->mtc.origin / (MTC_SEC * 3600)) % 24;
        !           275:        d->mtc.min = (d->mtc.origin / (MTC_SEC * 60))   % 60;
        !           276:        d->mtc.sec = (d->mtc.origin / (MTC_SEC))        % 60;
        !           277:        d->mtc.fr =  (d->mtc.origin / (MTC_SEC / fps))  % fps;
        !           278:
        !           279:        x.start = SYSEX_START;
        !           280:        x.type = SYSEX_TYPE_RT;
        !           281:        x.dev = 0x7f;
        !           282:        x.id0 = SYSEX_MTC;
        !           283:        x.id1 = SYSEX_MTC_FULL;
        !           284:        x.u.full.hr = d->mtc.hr | (d->mtc.fps_id << 5);
        !           285:        x.u.full.min = d->mtc.min;
        !           286:        x.u.full.sec = d->mtc.sec;
        !           287:        x.u.full.fr = d->mtc.fr;
        !           288:        x.u.full.end = SYSEX_END;
        !           289:        d->mtc.qfr = 0;
        !           290:        midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(full));
        !           291: }
        !           292:
        !           293: /*
        !           294:  * send a volume change MIDI message
        !           295:  */
        !           296: void
        !           297: dev_midi_vol(struct dev *d, struct slot *s)
        !           298: {
        !           299:        unsigned char msg[3];
        !           300:
        !           301:        msg[0] = MIDI_CTL | (s - d->slot);
        !           302:        msg[1] = MIDI_CTL_VOL;
        !           303:        msg[2] = s->vol;
        !           304:        midi_send(d->midi, msg, 3);
        !           305: }
        !           306:
        !           307: /*
        !           308:  * send a master volume MIDI message
        !           309:  */
        !           310: void
        !           311: dev_midi_master(struct dev *d)
        !           312: {
        !           313:        struct sysex x;
        !           314:
        !           315:        memset(&x, 0, sizeof(struct sysex));
        !           316:        x.start = SYSEX_START;
        !           317:        x.type = SYSEX_TYPE_RT;
        !           318:        x.id0 = SYSEX_CONTROL;
        !           319:        x.id1 = SYSEX_MASTER;
        !           320:        x.u.master.fine = 0;
        !           321:        x.u.master.coarse = d->master;
        !           322:        x.u.master.end = SYSEX_END;
        !           323:        midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(master));
        !           324: }
        !           325:
        !           326: /*
        !           327:  * send a sndiod-specific slot description MIDI message
        !           328:  */
        !           329: void
        !           330: dev_midi_slotdesc(struct dev *d, struct slot *s)
        !           331: {
        !           332:        struct sysex x;
        !           333:
        !           334:        memset(&x, 0, sizeof(struct sysex));
        !           335:        x.start = SYSEX_START;
        !           336:        x.type = SYSEX_TYPE_EDU;
        !           337:        x.id0 = SYSEX_AUCAT;
        !           338:        x.id1 = SYSEX_AUCAT_SLOTDESC;
        !           339:        if (*s->name != '\0') {
        !           340:                snprintf((char *)x.u.slotdesc.name, SYSEX_NAMELEN,
        !           341:                    "%s%u", s->name, s->unit);
        !           342:        }
        !           343:        x.u.slotdesc.chan = s - d->slot;
        !           344:        x.u.slotdesc.end = SYSEX_END;
        !           345:        midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(slotdesc));
        !           346: }
        !           347:
        !           348: void
        !           349: dev_midi_dump(struct dev *d)
        !           350: {
        !           351:        struct sysex x;
        !           352:        struct slot *s;
        !           353:        int i;
        !           354:
        !           355:        dev_midi_master(d);
        !           356:        for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
        !           357:                dev_midi_slotdesc(d, s);
        !           358:                dev_midi_vol(d, s);
        !           359:        }
        !           360:        x.start = SYSEX_START;
        !           361:        x.type = SYSEX_TYPE_EDU;
        !           362:        x.dev = 0;
        !           363:        x.id0 = SYSEX_AUCAT;
        !           364:        x.id1 = SYSEX_AUCAT_DUMPEND;
        !           365:        x.u.dumpend.end = SYSEX_END;
        !           366:        midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(dumpend));
        !           367: }
        !           368:
        !           369: void
        !           370: dev_midi_imsg(void *arg, unsigned char *msg, int len)
        !           371: {
        !           372: #ifdef DEBUG
        !           373:        struct dev *d = arg;
        !           374:
        !           375:        dev_log(d);
        !           376:        log_puts(": can't receive midi messages\n");
        !           377:        panic();
        !           378: #endif
        !           379: }
        !           380:
        !           381: void
        !           382: dev_midi_omsg(void *arg, unsigned char *msg, int len)
        !           383: {
        !           384:        struct dev *d = arg;
        !           385:        struct sysex *x;
        !           386:        unsigned int fps, chan;
        !           387:
        !           388:        if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) {
        !           389:                chan = msg[0] & MIDI_CHANMASK;
        !           390:                if (chan >= DEV_NSLOT)
        !           391:                        return;
        !           392:                slot_setvol(d->slot + chan, msg[2]);
        !           393:                return;
        !           394:        }
        !           395:        x = (struct sysex *)msg;
        !           396:        if (x->start != SYSEX_START)
        !           397:                return;
        !           398:        if (len < SYSEX_SIZE(empty))
        !           399:                return;
        !           400:        switch (x->type) {
        !           401:        case SYSEX_TYPE_RT:
        !           402:                if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
        !           403:                        if (len == SYSEX_SIZE(master))
        !           404:                                dev_master(d, x->u.master.coarse);
        !           405:                        return;
        !           406:                }
        !           407:                if (x->id0 != SYSEX_MMC)
        !           408:                        return;
        !           409:                switch (x->id1) {
        !           410:                case SYSEX_MMC_STOP:
        !           411:                        if (len != SYSEX_SIZE(stop))
        !           412:                                return;
        !           413:                        if (log_level >= 2) {
        !           414:                                dev_log(d);
        !           415:                                log_puts(": mmc stop\n");
        !           416:                        }
        !           417:                        dev_mmcstop(d);
        !           418:                        break;
        !           419:                case SYSEX_MMC_START:
        !           420:                        if (len != SYSEX_SIZE(start))
        !           421:                                return;
        !           422:                        if (log_level >= 2) {
        !           423:                                dev_log(d);
        !           424:                                log_puts(": mmc start\n");
        !           425:                        }
        !           426:                        dev_mmcstart(d);
        !           427:                        break;
        !           428:                case SYSEX_MMC_LOC:
        !           429:                        if (len != SYSEX_SIZE(loc) ||
        !           430:                            x->u.loc.len != SYSEX_MMC_LOC_LEN ||
        !           431:                            x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
        !           432:                                return;
        !           433:                        switch (x->u.loc.hr >> 5) {
        !           434:                        case MTC_FPS_24:
        !           435:                                fps = 24;
        !           436:                                break;
        !           437:                        case MTC_FPS_25:
        !           438:                                fps = 25;
        !           439:                                break;
        !           440:                        case MTC_FPS_30:
        !           441:                                fps = 30;
        !           442:                                break;
        !           443:                        default:
        !           444:                                dev_mmcstop(d);
        !           445:                                return;
        !           446:                        }
        !           447:                        dev_mmcloc(d,
        !           448:                            (x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
        !           449:                             x->u.loc.min * 60 * MTC_SEC +
        !           450:                             x->u.loc.sec * MTC_SEC +
        !           451:                             x->u.loc.fr * (MTC_SEC / fps) +
        !           452:                             x->u.loc.cent * (MTC_SEC / 100 / fps));
        !           453:                        break;
        !           454:                }
        !           455:                break;
        !           456:        case SYSEX_TYPE_EDU:
        !           457:                if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ)
        !           458:                        return;
        !           459:                if (len != SYSEX_SIZE(dumpreq))
        !           460:                        return;
        !           461:                dev_midi_dump(d);
        !           462:                break;
        !           463:        }
        !           464: }
        !           465:
        !           466: void
        !           467: dev_midi_fill(void *arg, int count)
        !           468: {
        !           469: #ifdef DEBUG
        !           470:        struct dev *d = arg;
        !           471:
        !           472:        dev_log(d);
        !           473:        log_puts(": can't receive fill input\n");
        !           474:        panic();
        !           475: #endif
        !           476: }
        !           477:
        !           478: void
        !           479: dev_midi_exit(void *arg)
        !           480: {
        !           481:        struct dev *d = arg;
        !           482:
        !           483:        if (log_level >= 1) {
        !           484:                dev_log(d);
        !           485:                log_puts(": midi end point died\n");
        !           486:        }
        !           487:        if (d->pstate != DEV_CFG)
        !           488:                dev_close(d);
        !           489: }
        !           490:
        !           491: void
        !           492: slot_mix_drop(struct slot *s)
        !           493: {
        !           494:        while (s->mix.drop > 0 && s->mix.buf.used >= s->round * s->mix.bpf) {
        !           495: #ifdef DEBUG
        !           496:                if (log_level >= 4) {
        !           497:                        slot_log(s);
        !           498:                        log_puts(": dropped a play block\n");
        !           499:                }
        !           500: #endif
        !           501:                abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf);
        !           502:                s->mix.drop--;
        !           503:        }
        !           504: }
        !           505:
        !           506: void
        !           507: slot_sub_sil(struct slot *s)
        !           508: {
        !           509:        unsigned char *data;
        !           510:        int count;
        !           511:
        !           512:        while (s->sub.silence > 0) {
        !           513:                data = abuf_wgetblk(&s->sub.buf, &count);
        !           514:                if (count < s->round * s->sub.bpf)
        !           515:                        break;
        !           516: #ifdef DEBUG
        !           517:                if (log_level >= 4) {
        !           518:                        slot_log(s);
        !           519:                        log_puts(": inserted a rec block of silence\n");
        !           520:                }
        !           521: #endif
        !           522:                if (s->sub.encbuf)
        !           523:                        enc_sil_do(&s->sub.enc, data, s->round);
        !           524:                else
        !           525:                        memset(data, 0, s->round * s->sub.bpf);
        !           526:                abuf_wcommit(&s->sub.buf, s->round * s->sub.bpf);
        !           527:                s->sub.silence--;
        !           528:        }
        !           529: }
        !           530:
        !           531: /*
        !           532:  * merge play buffer contents into record buffer as if the
        !           533:  * play stream was recorded
        !           534:  */
        !           535: void
        !           536: dev_mon_snoop(struct dev *d)
        !           537: {
        !           538: }
        !           539:
        !           540: int
        !           541: play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
        !           542: {
        !           543:        int i, offs, vol, nch;
        !           544:        void *in;
        !           545:
        !           546:        if (s->mix.resampbuf) {
        !           547:                todo = resamp_do(&s->mix.resamp,
        !           548:                    res_in, s->mix.resampbuf, todo);
        !           549:                in = s->mix.resampbuf;
        !           550:        } else
        !           551:                in = res_in;
        !           552:
        !           553:        nch = s->mix.slot_cmax - s->mix.slot_cmin + 1;
        !           554:        vol = ADATA_MUL(s->mix.weight, s->mix.vol) / s->mix.join;
        !           555:        cmap_add(&s->mix.cmap, in, out, vol, todo);
        !           556:
        !           557:        offs = 0;
        !           558:        for (i = s->mix.join - 1; i > 0; i--) {
        !           559:                offs += nch;
        !           560:                if (offs > s->mix.cmap.inext)
        !           561:                        break;
        !           562:                cmap_add(&s->mix.cmap, (adata_t *)in + offs, out, vol, todo);
        !           563:        }
        !           564:        offs = 0;
        !           565:        for (i = s->mix.expand - 1; i > 0; i--) {
        !           566:                offs += nch;
        !           567:                if (offs > s->mix.cmap.onext)
        !           568:                        break;
        !           569:                cmap_add(&s->mix.cmap, in, (adata_t *)out + offs, vol, todo);
        !           570:        }
        !           571:        return todo;
        !           572: }
        !           573:
        !           574: int
        !           575: play_filt_dec(struct slot *s, void *in, void *out, int todo)
        !           576: {
        !           577:        void *tmp;
        !           578:
        !           579:        tmp = s->mix.decbuf;
        !           580:        if (tmp)
        !           581:                dec_do(&s->mix.dec, in, tmp, todo);
        !           582:        return play_filt_resamp(s, tmp ? tmp : in, out, todo);
        !           583: }
        !           584:
        !           585: /*
        !           586:  * mix "todo" frames from the input block over the output block; if
        !           587:  * there are frames to drop, less frames are consumed from the input
        !           588:  */
        !           589: void
        !           590: dev_mix_badd(struct dev *d, struct slot *s)
        !           591: {
        !           592:        adata_t *idata, *odata;
        !           593:        int icount;
        !           594:
        !           595:        odata = DEV_PBUF(d);
        !           596:        idata = (adata_t *)abuf_rgetblk(&s->mix.buf, &icount);
        !           597: #ifdef DEBUG
        !           598:        if (icount < s->round * s->mix.bpf) {
        !           599:                slot_log(s);
        !           600:                log_puts(": not enough data to mix (");
        !           601:                log_putu(icount);
        !           602:                log_puts("bytes)\n");
        !           603:                panic();
        !           604:        }
        !           605: #endif
        !           606:        play_filt_dec(s, idata, odata, s->round);
        !           607:        abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf);
        !           608: }
        !           609:
        !           610: void
        !           611: dev_empty_cycle(struct dev *d)
        !           612: {
        !           613:        unsigned char *base;
        !           614:        int nsamp;
        !           615:
        !           616:        base = (unsigned char *)DEV_PBUF(d);
        !           617:        nsamp = d->round * d->pchan;
        !           618:        memset(base, 0, nsamp * sizeof(adata_t));
        !           619:        if (d->encbuf) {
        !           620:                enc_do(&d->enc, (unsigned char *)DEV_PBUF(d),
        !           621:                    d->encbuf, d->round);
        !           622:        }
        !           623: }
        !           624:
        !           625: /*
        !           626:  * Normalize input levels.
        !           627:  */
        !           628: void
        !           629: dev_mix_adjvol(struct dev *d)
        !           630: {
        !           631:        unsigned int n;
        !           632:        struct slot *i, *j;
        !           633:        int weight;
        !           634:
        !           635:        for (i = d->slot_list; i != NULL; i = i->next) {
        !           636:                if (!(i->mode & MODE_PLAY))
        !           637:                        continue;
        !           638:                weight = ADATA_UNIT;
        !           639:                if (d->autovol) {
        !           640:                        /*
        !           641:                         * count the number of inputs that have
        !           642:                         * overlapping channel sets
        !           643:                         */
        !           644:                        n = 0;
        !           645:                        for (j = d->slot_list; j != NULL; j = j->next) {
        !           646:                                if (!(j->mode & MODE_PLAY))
        !           647:                                        continue;
        !           648:                                if (i->mix.slot_cmin <= j->mix.slot_cmax &&
        !           649:                                    i->mix.slot_cmax >= j->mix.slot_cmin)
        !           650:                                        n++;
        !           651:                        }
        !           652:                        weight /= n;
        !           653:                }
        !           654:                if (weight > i->mix.maxweight)
        !           655:                        weight = i->mix.maxweight;
        !           656:                i->mix.weight = ADATA_MUL(weight, MIDI_TO_ADATA(d->master));
        !           657: #ifdef DEBUG
        !           658:                if (log_level >= 3) {
        !           659:                        slot_log(i);
        !           660:                        log_puts(": set weight: ");
        !           661:                        log_puti(i->mix.weight);
        !           662:                        log_puts("/");
        !           663:                        log_puti(i->mix.maxweight);
        !           664:                        log_puts("\n");
        !           665:                }
        !           666: #endif
        !           667:        }
        !           668: }
        !           669:
        !           670: void
        !           671: dev_mix_cycle(struct dev *d)
        !           672: {
        !           673:        struct slot *s, **ps;
        !           674:        unsigned char *base;
        !           675:        int nsamp;
        !           676:
        !           677: #ifdef DEBUG
        !           678:        if (log_level >= 4) {
        !           679:                dev_log(d);
        !           680:                log_puts(": dev_mix_cycle, poffs = ");
        !           681:                log_puti(d->poffs);
        !           682:                log_puts("\n");
        !           683:        }
        !           684: #endif
        !           685:        base = (unsigned char *)DEV_PBUF(d);
        !           686:        nsamp = d->round * d->pchan;
        !           687:        memset(base, 0, nsamp * sizeof(adata_t));
        !           688:        ps = &d->slot_list;
        !           689:        while ((s = *ps) != NULL) {
        !           690:                if (!(s->mode & MODE_PLAY)) {
        !           691:                        ps = &s->next;
        !           692:                        continue;
        !           693:                }
        !           694: #ifdef DEBUG
        !           695:                if (log_level >= 4) {
        !           696:                        slot_log(s);
        !           697:                        log_puts(": mixing, drop = ");
        !           698:                        log_puti(s->mix.drop);
        !           699:                        log_puts(" cycles\n");
        !           700:                }
        !           701: #endif
        !           702:                slot_mix_drop(s);
        !           703:                if (s->mix.drop < 0) {
        !           704:                        s->mix.drop++;
        !           705:                        ps = &s->next;
        !           706:                        continue;
        !           707:                }
        !           708:                if (s->mix.buf.used < s->round * s->mix.bpf &&
        !           709:                    s->pstate == SLOT_STOP) {
        !           710:                        /*
        !           711:                         * partial blocks are zero-filled by socket
        !           712:                         * layer
        !           713:                         */
        !           714:                        s->pstate = SLOT_INIT;
        !           715:                        abuf_done(&s->mix.buf);
        !           716:                        if (s->mix.decbuf)
        !           717:                                xfree(s->mix.decbuf);
        !           718:                        if (s->mix.resampbuf)
        !           719:                                xfree(s->mix.resampbuf);
        !           720:                        s->ops->eof(s->arg);
        !           721:                        *ps = s->next;
        !           722:                        dev_mix_adjvol(d);
        !           723:                        continue;
        !           724:                }
        !           725:                if (s->mix.buf.used < s->round * s->mix.bpf &&
        !           726:                    !(s->pstate == SLOT_STOP)) {
        !           727:                        if (s->xrun == XRUN_IGNORE) {
        !           728:                                if (s->mode & MODE_RECMASK)
        !           729:                                        s->sub.silence--;
        !           730:                                s->delta -= s->round;
        !           731: #ifdef DEBUG
        !           732:                                if (log_level >= 3) {
        !           733:                                        slot_log(s);
        !           734:                                        log_puts(": underrun, pause cycle\n");
        !           735:                                }
        !           736: #endif
        !           737:                                ps = &s->next;
        !           738:                                continue;
        !           739:                        }
        !           740:                        if (s->xrun == XRUN_SYNC) {
        !           741:                                s->mix.drop++;
        !           742:                                ps = &s->next;
        !           743:                                continue;
        !           744:                        }
        !           745:                        if (s->xrun == XRUN_ERROR) {
        !           746:                                s->ops->exit(s->arg);
        !           747:                                *ps = s->next;
        !           748:                                continue;
        !           749:                        }
        !           750:                } else {
        !           751:                        dev_mix_badd(d, s);
        !           752:                        if (s->pstate != SLOT_STOP)
        !           753:                                s->ops->fill(s->arg);
        !           754:                }
        !           755:                ps = &s->next;
        !           756:        }
        !           757:        if (d->encbuf) {
        !           758:                enc_do(&d->enc, (unsigned char *)DEV_PBUF(d),
        !           759:                    d->encbuf, d->round);
        !           760:        }
        !           761: }
        !           762:
        !           763: int
        !           764: rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
        !           765: {
        !           766:        int i, vol, offs, nch;
        !           767:        void *out = res_out;
        !           768:
        !           769:        out = (s->sub.resampbuf) ? s->sub.resampbuf : res_out;
        !           770:
        !           771:        nch = s->sub.slot_cmax - s->sub.slot_cmin + 1;
        !           772:        vol = ADATA_UNIT / s->sub.join;
        !           773:        cmap_copy(&s->sub.cmap, in, out, vol, todo);
        !           774:
        !           775:        offs = 0;
        !           776:        for (i = s->sub.join - 1; i > 0; i--) {
        !           777:                offs += nch;
        !           778:                cmap_add(&s->sub.cmap, (adata_t *)in + offs, out, vol, todo);
        !           779:        }
        !           780:        offs = 0;
        !           781:        for (i = s->sub.expand - 1; i > 0; i--) {
        !           782:                offs += nch;
        !           783:                cmap_copy(&s->sub.cmap, in, (adata_t *)out + offs, vol, todo);
        !           784:        }
        !           785:        if (s->sub.resampbuf) {
        !           786:                todo = resamp_do(&s->sub.resamp,
        !           787:                    s->sub.resampbuf, res_out, todo);
        !           788:        }
        !           789:        return todo;
        !           790: }
        !           791:
        !           792: int
        !           793: rec_filt_enc(struct slot *s, void *in, void *out, int todo)
        !           794: {
        !           795:        void *tmp;
        !           796:
        !           797:        tmp = s->sub.encbuf;
        !           798:        todo = rec_filt_resamp(s, in, tmp ? tmp : out, todo);
        !           799:        if (tmp)
        !           800:                enc_do(&s->sub.enc, tmp, out, todo);
        !           801:        return todo;
        !           802: }
        !           803:
        !           804: /*
        !           805:  * Copy data from slot to device
        !           806:  */
        !           807: void
        !           808: dev_sub_bcopy(struct dev *d, struct slot *s)
        !           809: {
        !           810:        adata_t *idata, *odata;
        !           811:        int ocount;
        !           812:
        !           813:        idata = (s->mode & MODE_MON) ? DEV_PBUF(d) : d->rbuf;
        !           814:        odata = (adata_t *)abuf_wgetblk(&s->sub.buf, &ocount);
        !           815: #ifdef DEBUG
        !           816:        if (ocount < s->round * s->sub.bpf) {
        !           817:                log_puts("dev_sub_bcopy: not enough space\n");
        !           818:                panic();
        !           819:        }
        !           820: #endif
        !           821:        ocount = rec_filt_enc(s, idata, odata, d->round);
        !           822:        abuf_wcommit(&s->sub.buf, ocount * s->sub.bpf);
        !           823: }
        !           824:
        !           825: void
        !           826: dev_sub_cycle(struct dev *d)
        !           827: {
        !           828:        struct slot *s, **ps;
        !           829:
        !           830: #ifdef DEBUG
        !           831:        if (log_level >= 4) {
        !           832:                dev_log(d);
        !           833:                log_puts(": dev_sub_cycle\n");
        !           834:        }
        !           835: #endif
        !           836:        if ((d->mode & MODE_REC) && d->decbuf)
        !           837:                dec_do(&d->dec, d->decbuf, (unsigned char *)d->rbuf, d->round);
        !           838:        ps = &d->slot_list;
        !           839:        while ((s = *ps) != NULL) {
        !           840:                if (!(s->mode & MODE_RECMASK) || s->pstate == SLOT_STOP) {
        !           841:                        ps = &s->next;
        !           842:                        continue;
        !           843:                }
        !           844:                slot_sub_sil(s);
        !           845:                if (s->sub.silence < 0) {
        !           846:                        s->sub.silence++;
        !           847:                        ps = &s->next;
        !           848:                        continue;
        !           849:                }
        !           850:                if (s->sub.buf.len - s->sub.buf.used < s->round * s->sub.bpf) {
        !           851:                        if (s->xrun == XRUN_IGNORE) {
        !           852:                                if (s->mode & MODE_PLAY)
        !           853:                                        s->mix.drop--;
        !           854:                                s->delta -= s->round;
        !           855: #ifdef DEBUG
        !           856:                                if (log_level >= 3) {
        !           857:                                        slot_log(s);
        !           858:                                        log_puts(": overrun, pause cycle\n");
        !           859:                                }
        !           860: #endif
        !           861:                                ps = &s->next;
        !           862:                                continue;
        !           863:                        }
        !           864:                        if (s->xrun == XRUN_SYNC) {
        !           865:                                s->sub.silence++;
        !           866:                                ps = &s->next;
        !           867:                                continue;
        !           868:                        }
        !           869:                        if (s->xrun == XRUN_ERROR) {
        !           870:                                s->ops->exit(s->arg);
        !           871:                                *ps = s->next;
        !           872:                                continue;
        !           873:                        }
        !           874:                } else {
        !           875:                        dev_sub_bcopy(d, s);
        !           876:                        s->ops->flush(s->arg);
        !           877:                }
        !           878:                ps = &s->next;
        !           879:        }
        !           880: }
        !           881:
        !           882: /*
        !           883:  * called at every clock tick by the device
        !           884:  */
        !           885: void
        !           886: dev_onmove(struct dev *d, int delta)
        !           887: {
        !           888:        long long pos;
        !           889:        struct slot *s, *snext;
        !           890:
        !           891:        /*
        !           892:         * s->ops->onmove() may remove the slot
        !           893:         */
        !           894:        for (s = d->slot_list; s != NULL; s = snext) {
        !           895:                snext = s->next;
        !           896:                pos = (long long)delta * s->round + s->delta_rem;
        !           897:                s->delta_rem = pos % d->round;
        !           898:                s->delta += pos / (int)d->round;
        !           899:                if (s->delta >= 0)
        !           900:                        s->ops->onmove(s->arg, delta);
        !           901:        }
        !           902:        if (d->tstate == MMC_RUN)
        !           903:                dev_midi_qfr(d, delta);
        !           904: }
        !           905:
        !           906: void
        !           907: dev_master(struct dev *d, unsigned int master)
        !           908: {
        !           909:        if (log_level >= 2) {
        !           910:                dev_log(d);
        !           911:                log_puts(": master volume set to ");
        !           912:                log_putu(master);
        !           913:                log_puts("\n");
        !           914:        }
        !           915:        d->master = master;
        !           916:        if (d->mode & MODE_PLAY)
        !           917:                dev_mix_adjvol(d);
        !           918: }
        !           919:
        !           920: void
        !           921: dev_cycle(struct dev *d)
        !           922: {
        !           923:        if (d->slot_list == NULL && d->tstate != MMC_RUN) {
        !           924:                if (log_level >= 2) {
        !           925:                        dev_log(d);
        !           926:                        log_puts(": device stopped\n");
        !           927:                }
        !           928:                dev_sio_stop(d);
        !           929:                d->pstate = DEV_INIT;
        !           930:                if (d->refcnt == 0)
        !           931:                        dev_close(d);
        !           932:                else
        !           933:                        dev_clear(d);
        !           934:                return;
        !           935:        }
        !           936: #ifdef DEBUG
        !           937:        if (log_level >= 4) {
        !           938:                dev_log(d);
        !           939:                log_puts(": device cycle, prime = ");
        !           940:                log_putu(d->prime);
        !           941:                log_puts("\n");
        !           942:        }
        !           943: #endif
        !           944:        if (d->prime > 0) {
        !           945:                d->prime -= d->round;
        !           946:                dev_empty_cycle(d);
        !           947:        } else {
        !           948:                if (d->mode & MODE_RECMASK)
        !           949:                        dev_sub_cycle(d);
        !           950:                if (d->mode & MODE_PLAY)
        !           951:                        dev_mix_cycle(d);
        !           952:        }
        !           953: }
        !           954:
        !           955: /*
        !           956:  * return the latency that a stream would have if it's attached
        !           957:  */
        !           958: int
        !           959: dev_getpos(struct dev *d)
        !           960: {
        !           961:        return (d->mode & MODE_PLAY) ? -d->bufsz : 0;
        !           962: }
        !           963:
        !           964: /*
        !           965:  * Create a sndio device
        !           966:  */
        !           967: struct dev *
        !           968: dev_new(char *path, struct aparams *par,
        !           969:     unsigned int mode, unsigned int bufsz, unsigned int round,
        !           970:     unsigned int rate, unsigned int hold, unsigned int autovol)
        !           971: {
        !           972:        struct dev *d;
        !           973:        unsigned int i;
        !           974:
        !           975:        if (dev_sndnum == DEV_NMAX) {
        !           976:                if (log_level >= 1)
        !           977:                        log_puts("too many devices\n");
        !           978:                return NULL;
        !           979:        }
        !           980:        d = xmalloc(sizeof(struct dev));
        !           981:        d->num = dev_sndnum++;
        !           982:
        !           983:        /*
        !           984:         * XXX: below, we allocate a midi input buffer, since we don't
        !           985:         *      receive raw midi data, so no need to allocate a input
        !           986:         *      ibuf.  Possibly set imsg & fill callbacks to NULL and
        !           987:         *      use this to in midi_new() to check if buffers need to be
        !           988:         *      allocated
        !           989:         */
        !           990:        d->midi = midi_new(&dev_midiops, d, MODE_MIDIIN | MODE_MIDIOUT);
        !           991:        midi_tag(d->midi, d->num);
        !           992:        d->path = path;
        !           993:        d->reqpar = *par;
        !           994:        d->reqmode = mode;
        !           995:        d->reqpchan = d->reqrchan = 0;
        !           996:        d->reqbufsz = bufsz;
        !           997:        d->reqround = round;
        !           998:        d->reqrate = rate;
        !           999:        d->hold = hold;
        !          1000:        d->autovol = autovol;
        !          1001:        d->autostart = 0;
        !          1002:        d->refcnt = 0;
        !          1003:        d->pstate = DEV_CFG;
        !          1004:        d->serial = 0;
        !          1005:        for (i = 0; i < DEV_NSLOT; i++) {
        !          1006:                d->slot[i].unit = i;
        !          1007:                d->slot[i].ops = NULL;
        !          1008:                d->slot[i].vol = MIDI_MAXCTL;
        !          1009:                d->slot[i].tstate = MMC_OFF;
        !          1010:                d->slot[i].serial = d->serial++;
        !          1011:                d->slot[i].name[0] = '\0';
        !          1012:        }
        !          1013:        d->slot_list = NULL;
        !          1014:        d->master = MIDI_MAXCTL;
        !          1015:        d->mtc.origin = 0;
        !          1016:        d->tstate = MMC_STOP;
        !          1017:        d->next = dev_list;
        !          1018:        dev_list = d;
        !          1019:        return d;
        !          1020: }
        !          1021:
        !          1022: /*
        !          1023:  * adjust device parameters and mode
        !          1024:  */
        !          1025: void
        !          1026: dev_adjpar(struct dev *d, int mode,
        !          1027:     int pmin, int pmax, int rmin, int rmax)
        !          1028: {
        !          1029:        d->reqmode |= mode & MODE_AUDIOMASK;
        !          1030:        if (mode & MODE_PLAY) {
        !          1031:                if (d->reqpchan < pmax + 1)
        !          1032:                        d->reqpchan = pmax + 1;
        !          1033:        }
        !          1034:        if (mode & MODE_REC) {
        !          1035:                if (d->reqrchan < rmax + 1)
        !          1036:                        d->reqrchan = rmax + 1;
        !          1037:        }
        !          1038: }
        !          1039:
        !          1040: /*
        !          1041:  * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
        !          1042:  * monitor, midi control, and any necessary conversions.
        !          1043:  */
        !          1044: int
        !          1045: dev_open(struct dev *d)
        !          1046: {
        !          1047:        d->mode = d->reqmode;
        !          1048:        d->round = d->reqround;
        !          1049:        d->bufsz = d->reqbufsz;
        !          1050:        d->rate = d->reqrate;
        !          1051:        d->pchan = d->reqpchan;
        !          1052:        d->rchan = d->reqrchan;
        !          1053:        d->par = d->reqpar;
        !          1054:        if (d->pchan == 0)
        !          1055:                d->pchan = 2;
        !          1056:        if (d->rchan == 0)
        !          1057:                d->rchan = 2;
        !          1058:        if (!dev_sio_open(d)) {
        !          1059:                if (log_level >= 1) {
        !          1060:                        dev_log(d);
        !          1061:                        log_puts(": ");
        !          1062:                        log_puts(d->path);
        !          1063:                        log_puts(": failed to open audio device\n");
        !          1064:                }
        !          1065:                return 0;
        !          1066:        }
        !          1067:        if (d->mode & MODE_REC) {
        !          1068:                /*
        !          1069:                 * Create device <-> demuxer buffer
        !          1070:                 */
        !          1071:                d->rbuf = xmalloc(d->round * d->rchan * sizeof(adata_t));
        !          1072:
        !          1073:                /*
        !          1074:                 * Insert a converter, if needed.
        !          1075:                 */
        !          1076:                if (!aparams_native(&d->par)) {
        !          1077:                        dec_init(&d->dec, &d->par, d->rchan);
        !          1078:                        d->decbuf = xmalloc(d->round * d->rchan * d->par.bps);
        !          1079:                } else
        !          1080:                        d->decbuf = NULL;
        !          1081:        }
        !          1082:        if (d->mode & MODE_PLAY) {
        !          1083:                /*
        !          1084:                 * Create device <-> mixer buffer
        !          1085:                 */
        !          1086:                d->pbuf = xmalloc(d->bufsz * d->pchan * sizeof(adata_t));
        !          1087:                d->poffs = 0;
        !          1088:                d->mode |= MODE_MON;
        !          1089:
        !          1090:                /*
        !          1091:                 * Append a converter, if needed.
        !          1092:                 */
        !          1093:                if (!aparams_native(&d->par)) {
        !          1094:                        enc_init(&d->enc, &d->par, d->pchan);
        !          1095:                        d->encbuf = xmalloc(d->round * d->pchan * d->par.bps);
        !          1096:                } else
        !          1097:                        d->encbuf = NULL;
        !          1098:        }
        !          1099:        d->pstate = DEV_INIT;
        !          1100:        if (log_level >= 2) {
        !          1101:                dev_log(d);
        !          1102:                log_puts(": ");
        !          1103:                log_putu(d->rate);
        !          1104:                log_puts("Hz, ");
        !          1105:                aparams_log(&d->par);
        !          1106:                if (d->mode & MODE_PLAY) {
        !          1107:                        log_puts(", play 0:");
        !          1108:                        log_puti(d->pchan - 1);
        !          1109:                }
        !          1110:                if (d->mode & MODE_REC) {
        !          1111:                        log_puts(", rec 0:");
        !          1112:                        log_puti(d->rchan - 1);
        !          1113:                }
        !          1114:                log_puts(", ");
        !          1115:                log_putu(d->bufsz / d->round);
        !          1116:                log_puts(" blocks of ");
        !          1117:                log_putu(d->round);
        !          1118:                log_puts(" frames\n");
        !          1119:        }
        !          1120:        return 1;
        !          1121: }
        !          1122:
        !          1123: /*
        !          1124:  * force the device to go in DEV_CFG state, the caller is supposed to
        !          1125:  * ensure buffers are drained
        !          1126:  */
        !          1127: void
        !          1128: dev_close(struct dev *d)
        !          1129: {
        !          1130:        struct slot *s, *snext;
        !          1131:
        !          1132: #ifdef DEBUG
        !          1133:        if (log_level >= 3) {
        !          1134:                dev_log(d);
        !          1135:                log_puts(": closing\n");
        !          1136:        }
        !          1137: #endif
        !          1138:        while ((s = d->slot_list) != NULL) {
        !          1139:                snext = s->next;
        !          1140:                if (s->ops)
        !          1141:                        s->ops->exit(s->arg);
        !          1142:                s->ops = NULL;
        !          1143:                d->slot_list = snext;
        !          1144:        }
        !          1145:        dev_sio_close(d);
        !          1146:        if (d->mode & MODE_PLAY) {
        !          1147:                if (d->encbuf != NULL)
        !          1148:                        xfree(d->encbuf);
        !          1149:                xfree(d->pbuf);
        !          1150:        }
        !          1151:        if (d->mode & MODE_REC) {
        !          1152:                if (d->decbuf != NULL)
        !          1153:                        xfree(d->decbuf);
        !          1154:                xfree(d->rbuf);
        !          1155:        }
        !          1156:        dev_clear(d);
        !          1157:        d->pstate = DEV_CFG;
        !          1158: }
        !          1159:
        !          1160: int
        !          1161: dev_ref(struct dev *d)
        !          1162: {
        !          1163: #ifdef DEBUG
        !          1164:        if (log_level >= 3) {
        !          1165:                dev_log(d);
        !          1166:                log_puts(": device requested\n");
        !          1167:        }
        !          1168: #endif
        !          1169:        if (d->pstate == DEV_CFG && !dev_open(d))
        !          1170:                return 0;
        !          1171:        d->refcnt++;
        !          1172:        return 1;
        !          1173: }
        !          1174:
        !          1175: void
        !          1176: dev_unref(struct dev *d)
        !          1177: {
        !          1178: #ifdef DEBUG
        !          1179:        if (log_level >= 3) {
        !          1180:                dev_log(d);
        !          1181:                log_puts(": device released\n");
        !          1182:        }
        !          1183: #endif
        !          1184:        d->refcnt--;
        !          1185:        if (d->refcnt == 0 && d->pstate == DEV_INIT)
        !          1186:                dev_close(d);
        !          1187: }
        !          1188:
        !          1189: /*
        !          1190:  * initialize the device with the current parameters
        !          1191:  */
        !          1192: int
        !          1193: dev_init(struct dev *d)
        !          1194: {
        !          1195:        if ((d->reqmode & MODE_AUDIOMASK) == 0) {
        !          1196: #ifdef DEBUG
        !          1197:                    dev_log(d);
        !          1198:                    log_puts(": has no streams\n");
        !          1199: #endif
        !          1200:                    return 0;
        !          1201:        }
        !          1202:        if (d->hold && !dev_ref(d))
        !          1203:                return 0;
        !          1204:        return 1;
        !          1205: }
        !          1206:
        !          1207: /*
        !          1208:  * Unless the device is already in process of closing, request it to close
        !          1209:  */
        !          1210: void
        !          1211: dev_done(struct dev *d)
        !          1212: {
        !          1213: #ifdef DEBUG
        !          1214:        if (log_level >= 3) {
        !          1215:                dev_log(d);
        !          1216:                log_puts(": draining\n");
        !          1217:        }
        !          1218: #endif
        !          1219:        if (d->hold)
        !          1220:                dev_unref(d);
        !          1221: }
        !          1222:
        !          1223: struct dev *
        !          1224: dev_bynum(int num)
        !          1225: {
        !          1226:        struct dev *d;
        !          1227:
        !          1228:        for (d = dev_list; d != NULL; d = d->next) {
        !          1229:                if (num-- == 0)
        !          1230:                        return d;
        !          1231:        }
        !          1232:        return NULL;
        !          1233: }
        !          1234:
        !          1235: /*
        !          1236:  * Free the device
        !          1237:  */
        !          1238: void
        !          1239: dev_del(struct dev *d)
        !          1240: {
        !          1241:        struct dev **p;
        !          1242:
        !          1243: #ifdef DEBUG
        !          1244:        if (log_level >= 3) {
        !          1245:                dev_log(d);
        !          1246:                log_puts(": deleting\n");
        !          1247:        }
        !          1248: #endif
        !          1249:        if (d->pstate != DEV_CFG)
        !          1250:                dev_close(d);
        !          1251:        for (p = &dev_list; *p != d; p = &(*p)->next) {
        !          1252: #ifdef DEBUG
        !          1253:                if (*p == NULL) {
        !          1254:                        dev_log(d);
        !          1255:                        log_puts(": device to delete not on the list\n");
        !          1256:                        panic();
        !          1257:                }
        !          1258: #endif
        !          1259:        }
        !          1260:        midi_del(d->midi);
        !          1261:        *p = d->next;
        !          1262:        xfree(d);
        !          1263: }
        !          1264:
        !          1265: unsigned int
        !          1266: dev_roundof(struct dev *d, unsigned int newrate)
        !          1267: {
        !          1268:        return (d->round * newrate + d->rate / 2) / d->rate;
        !          1269: }
        !          1270:
        !          1271: /*
        !          1272:  * If the device is paused, then resume it.
        !          1273:  */
        !          1274: void
        !          1275: dev_wakeup(struct dev *d)
        !          1276: {
        !          1277:        if (d->pstate == DEV_INIT) {
        !          1278:                if (log_level >= 2) {
        !          1279:                        dev_log(d);
        !          1280:                        log_puts(": device started\n");
        !          1281:                }
        !          1282:                if (d->mode & MODE_PLAY) {
        !          1283:                        d->prime = d->bufsz;
        !          1284:                } else {
        !          1285:                        d->prime = 0;
        !          1286:                }
        !          1287:                d->pstate = DEV_RUN;
        !          1288:                dev_sio_start(d);
        !          1289:        }
        !          1290: }
        !          1291:
        !          1292: /*
        !          1293:  * Clear buffers of the play and record chains so that when the device
        !          1294:  * is started, playback and record start in sync.
        !          1295:  */
        !          1296: void
        !          1297: dev_clear(struct dev *d)
        !          1298: {
        !          1299:        d->poffs = 0;
        !          1300: }
        !          1301:
        !          1302: /*
        !          1303:  * check that all clients controlled by MMC are ready to start, if so,
        !          1304:  * attach them all at the same position
        !          1305:  */
        !          1306: void
        !          1307: dev_sync_attach(struct dev *d)
        !          1308: {
        !          1309:        int i;
        !          1310:        struct slot *s;
        !          1311:
        !          1312:        if (d->tstate != MMC_START) {
        !          1313:                if (log_level >= 2) {
        !          1314:                        dev_log(d);
        !          1315:                        log_puts(": not started by mmc yet, waiting...\n");
        !          1316:                }
        !          1317:                return;
        !          1318:        }
        !          1319:        for (i = 0; i < DEV_NSLOT; i++) {
        !          1320:                s = d->slot + i;
        !          1321:                if (!s->ops || s->tstate == MMC_OFF)
        !          1322:                        continue;
        !          1323:                if (s->tstate != MMC_START || s->pstate != SLOT_READY) {
        !          1324: #ifdef DEBUG
        !          1325:                        if (log_level >= 3) {
        !          1326:                                slot_log(s);
        !          1327:                                log_puts(": not ready, start delayed\n");
        !          1328:                        }
        !          1329: #endif
        !          1330:                        return;
        !          1331:                }
        !          1332:        }
        !          1333:        if (!dev_ref(d))
        !          1334:                return;
        !          1335:        for (i = 0; i < DEV_NSLOT; i++) {
        !          1336:                s = d->slot + i;
        !          1337:                if (!s->ops)
        !          1338:                        continue;
        !          1339:                if (s->tstate == MMC_START) {
        !          1340: #ifdef DEBUG
        !          1341:                        if (log_level >= 3) {
        !          1342:                                slot_log(s);
        !          1343:                                log_puts(": started\n");
        !          1344:                        }
        !          1345: #endif
        !          1346:                        s->tstate = MMC_RUN;
        !          1347:                        slot_attach(s);
        !          1348:                }
        !          1349:        }
        !          1350:        d->tstate = MMC_RUN;
        !          1351:        dev_midi_full(d);
        !          1352:        dev_wakeup(d);
        !          1353: }
        !          1354:
        !          1355: /*
        !          1356:  * start all slots simultaneously
        !          1357:  */
        !          1358: void
        !          1359: dev_mmcstart(struct dev *d)
        !          1360: {
        !          1361:        if (d->tstate == MMC_STOP) {
        !          1362:                d->tstate = MMC_START;
        !          1363:                dev_sync_attach(d);
        !          1364: #ifdef DEBUG
        !          1365:        } else {
        !          1366:                if (log_level >= 3) {
        !          1367:                        dev_log(d);
        !          1368:                        log_puts(": ignoring mmc start\n");
        !          1369:                }
        !          1370: #endif
        !          1371:        }
        !          1372: }
        !          1373:
        !          1374: /*
        !          1375:  * stop all slots simultaneously
        !          1376:  */
        !          1377: void
        !          1378: dev_mmcstop(struct dev *d)
        !          1379: {
        !          1380:        int i;
        !          1381:        struct slot *s;
        !          1382:
        !          1383:        switch (d->tstate) {
        !          1384:        case MMC_START:
        !          1385:                d->tstate = MMC_STOP;
        !          1386:                return;
        !          1387:        case MMC_RUN:
        !          1388:                d->tstate = MMC_STOP;
        !          1389:                dev_unref(d);
        !          1390:                break;
        !          1391:        default:
        !          1392: #ifdef DEBUG
        !          1393:                if (log_level >= 3) {
        !          1394:                        dev_log(d);
        !          1395:                        log_puts(": ignored mmc stop\n");
        !          1396:                }
        !          1397: #endif
        !          1398:                return;
        !          1399:        }
        !          1400:        for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
        !          1401:                if (!s->ops)
        !          1402:                        continue;
        !          1403:                if (s->tstate == MMC_RUN) {
        !          1404: #ifdef DEBUG
        !          1405:                        if (log_level >= 3) {
        !          1406:                                slot_log(s);
        !          1407:                                log_puts(": requested to stop\n");
        !          1408:                        }
        !          1409: #endif
        !          1410:                        s->ops->mmcstop(s->arg);
        !          1411:                }
        !          1412:        }
        !          1413: }
        !          1414:
        !          1415: /*
        !          1416:  * relocate all slots simultaneously
        !          1417:  */
        !          1418: void
        !          1419: dev_mmcloc(struct dev *d, unsigned int origin)
        !          1420: {
        !          1421:        int i;
        !          1422:        struct slot *s;
        !          1423:
        !          1424:        if (log_level >= 2) {
        !          1425:                dev_log(d);
        !          1426:                log_puts(": relocated to ");
        !          1427:                log_putu(origin);
        !          1428:                log_puts("\n");
        !          1429:        }
        !          1430:        if (d->tstate == MMC_RUN)
        !          1431:                dev_mmcstop(d);
        !          1432:        d->mtc.origin = origin;
        !          1433:        for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
        !          1434:                if (!s->ops)
        !          1435:                        continue;
        !          1436:                s->ops->mmcloc(s->arg, d->mtc.origin);
        !          1437:        }
        !          1438:        if (d->tstate == MMC_RUN)
        !          1439:                dev_mmcstart(d);
        !          1440: }
        !          1441:
        !          1442: /*
        !          1443:  * allocate a new slot and register the given call-backs
        !          1444:  */
        !          1445: struct slot *
        !          1446: slot_new(struct dev *d, char *who, struct slotops *ops, void *arg, int mode)
        !          1447: {
        !          1448:        char *p;
        !          1449:        char name[SLOT_NAMEMAX];
        !          1450:        unsigned int i, unit, umap = 0;
        !          1451:        unsigned int ser, bestser, bestidx;
        !          1452:        struct slot *s;
        !          1453:
        !          1454:        /*
        !          1455:         * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
        !          1456:         */
        !          1457:        for (i = 0, p = who; ; p++) {
        !          1458:                if (i == SLOT_NAMEMAX - 1 || *p == '\0') {
        !          1459:                        name[i] = '\0';
        !          1460:                        break;
        !          1461:                } else if (*p >= 'A' && *p <= 'Z') {
        !          1462:                        name[i++] = *p + 'a' - 'A';
        !          1463:                } else if (*p >= 'a' && *p <= 'z')
        !          1464:                        name[i++] = *p;
        !          1465:        }
        !          1466:        if (i == 0)
        !          1467:                strlcpy(name, "noname", SLOT_NAMEMAX);
        !          1468:
        !          1469:        /*
        !          1470:         * find the first unused "unit" number for this name
        !          1471:         */
        !          1472:        for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
        !          1473:                if (s->ops == NULL)
        !          1474:                        continue;
        !          1475:                if (strcmp(s->name, name) == 0)
        !          1476:                        umap |= (1 << s->unit);
        !          1477:        }
        !          1478:        for (unit = 0; ; unit++) {
        !          1479:                if ((umap & (1 << unit)) == 0)
        !          1480:                        break;
        !          1481:        }
        !          1482:
        !          1483:        /*
        !          1484:         * find a xfree controller slot with the same name/unit
        !          1485:         */
        !          1486:        for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
        !          1487:                if (s->ops == NULL &&
        !          1488:                    strcmp(s->name, name) == 0 &&
        !          1489:                    s->unit == unit) {
        !          1490: #ifdef DEBUG
        !          1491:                        if (log_level >= 3) {
        !          1492:                                log_puts(name);
        !          1493:                                log_putu(unit);
        !          1494:                                log_puts(": reused\n");
        !          1495:                        }
        !          1496: #endif
        !          1497:                        goto found;
        !          1498:                }
        !          1499:        }
        !          1500:
        !          1501:        /*
        !          1502:         * couldn't find a matching slot, pick oldest xfree slot
        !          1503:         * and set its name/unit
        !          1504:         */
        !          1505:        bestser = 0;
        !          1506:        bestidx = DEV_NSLOT;
        !          1507:        for (i = 0, s = d->slot; i < DEV_NSLOT; i++, s++) {
        !          1508:                if (s->ops != NULL)
        !          1509:                        continue;
        !          1510:                ser = d->serial - s->serial;
        !          1511:                if (ser > bestser) {
        !          1512:                        bestser = ser;
        !          1513:                        bestidx = i;
        !          1514:                }
        !          1515:        }
        !          1516:        if (bestidx == DEV_NSLOT) {
        !          1517:                if (log_level >= 1) {
        !          1518:                        log_puts(name);
        !          1519:                        log_putu(unit);
        !          1520:                        log_puts(": out of sub-device slots\n");
        !          1521:                }
        !          1522:                return NULL;
        !          1523:        }
        !          1524:        s = d->slot + bestidx;
        !          1525:        if (s->name[0] != '\0')
        !          1526:                s->vol = MIDI_MAXCTL;
        !          1527:        strlcpy(s->name, name, SLOT_NAMEMAX);
        !          1528:        s->serial = d->serial++;
        !          1529:        s->unit = unit;
        !          1530: #ifdef DEBUG
        !          1531:        if (log_level >= 3) {
        !          1532:                log_puts(name);
        !          1533:                log_putu(unit);
        !          1534:                log_puts(": overwritten slot ");
        !          1535:                log_putu(bestidx);
        !          1536:                log_puts("\n");
        !          1537:        }
        !          1538: #endif
        !          1539:
        !          1540: found:
        !          1541:        if (!dev_ref(d))
        !          1542:                return NULL;
        !          1543:        s->dev = d;
        !          1544:        s->ops = ops;
        !          1545:        s->arg = arg;
        !          1546:        s->pstate = SLOT_INIT;
        !          1547:        s->tstate = MMC_OFF;
        !          1548:
        !          1549:        if ((mode & s->dev->mode) != mode) {
        !          1550:                if (log_level >= 1) {
        !          1551:                        slot_log(s);
        !          1552:                        log_puts(": requested mode not supported\n");
        !          1553:                }
        !          1554:                return 0;
        !          1555:        }
        !          1556:        s->mode = mode;
        !          1557:        s->par = d->par;
        !          1558:        if (s->mode & MODE_PLAY) {
        !          1559:                s->mix.slot_cmin = 0;
        !          1560:                s->mix.slot_cmax = d->pchan - 1;
        !          1561:        }
        !          1562:        if (s->mode & MODE_RECMASK) {
        !          1563:                s->sub.slot_cmin = 0;
        !          1564:                s->sub.slot_cmax = ((s->mode & MODE_MON) ?
        !          1565:                    d->pchan : d->rchan) - 1;
        !          1566:        }
        !          1567:        s->xrun = XRUN_IGNORE;
        !          1568:        s->dup = 0;
        !          1569:        s->appbufsz = d->bufsz;
        !          1570:        s->round = d->round;
        !          1571:        dev_midi_slotdesc(d, s);
        !          1572:        dev_midi_vol(d, s);
        !          1573:        return s;
        !          1574: }
        !          1575:
        !          1576: /*
        !          1577:  * release the given slot
        !          1578:  */
        !          1579: void
        !          1580: slot_del(struct slot *s)
        !          1581: {
        !          1582:        s->arg = s;
        !          1583:        s->ops = &zomb_slotops;
        !          1584:        switch (s->pstate) {
        !          1585:        case SLOT_INIT:
        !          1586:                s->ops = NULL;
        !          1587:                break;
        !          1588:        case SLOT_START:
        !          1589:        case SLOT_READY:
        !          1590:        case SLOT_RUN:
        !          1591:                slot_stop(s);
        !          1592:                /* PASSTHROUGH */
        !          1593:        case SLOT_STOP:
        !          1594:                break;
        !          1595:        }
        !          1596:        dev_unref(s->dev);
        !          1597:        s->dev = NULL;
        !          1598: }
        !          1599:
        !          1600: /*
        !          1601:  * change the slot play volume; called either by the slot or by MIDI
        !          1602:  */
        !          1603: void
        !          1604: slot_setvol(struct slot *s, unsigned int vol)
        !          1605: {
        !          1606: #ifdef DEBUG
        !          1607:        if (log_level >= 3) {
        !          1608:                slot_log(s);
        !          1609:                log_puts(": setting volume ");
        !          1610:                log_putu(vol);
        !          1611:                log_puts("\n");
        !          1612:        }
        !          1613: #endif
        !          1614:        s->vol = vol;
        !          1615:        if (s->ops == NULL)
        !          1616:                return;
        !          1617:        s->mix.vol = MIDI_TO_ADATA(s->vol);
        !          1618: }
        !          1619:
        !          1620: /*
        !          1621:  * attach the slot to the device (ie start playing & recording
        !          1622:  */
        !          1623: void
        !          1624: slot_attach(struct slot *s)
        !          1625: {
        !          1626:        struct dev *d = s->dev;
        !          1627:        unsigned int slot_nch, dev_nch;
        !          1628:        int startpos;
        !          1629:
        !          1630:        /*
        !          1631:         * start the device if not started
        !          1632:         */
        !          1633:        dev_wakeup(d);
        !          1634:
        !          1635:        /*
        !          1636:         * get the current position, the origin is when the first sample
        !          1637:         * played and/or recorded
        !          1638:         */
        !          1639:        startpos = dev_getpos(d) * (int)s->round / (int)d->round;
        !          1640:        s->delta = startpos;
        !          1641:        s->delta_rem = 0;
        !          1642:        s->pstate = SLOT_RUN;
        !          1643: #ifdef DEBUG
        !          1644:        if (log_level >= 3) {
        !          1645:                slot_log(s);
        !          1646:                log_puts(": attached at ");
        !          1647:                log_puti(startpos);
        !          1648:                log_puts("\n");
        !          1649:        }
        !          1650: #endif
        !          1651:
        !          1652:        /*
        !          1653:         * We dont check whether the device is dying,
        !          1654:         * because dev_xxx() functions are supposed to
        !          1655:         * work (i.e., not to crash)
        !          1656:         */
        !          1657: #ifdef DEBUG
        !          1658:        if ((s->mode & d->mode) != s->mode) {
        !          1659:                slot_log(s);
        !          1660:                log_puts(": mode beyond device mode, not attaching\n");
        !          1661:                panic();
        !          1662:        }
        !          1663: #endif
        !          1664:        s->next = d->slot_list;
        !          1665:        d->slot_list = s;
        !          1666:        if (s->mode & MODE_PLAY) {
        !          1667:                slot_nch = s->mix.slot_cmax - s->mix.slot_cmin + 1;
        !          1668:                dev_nch = s->mix.dev_cmax - s->mix.dev_cmin + 1;
        !          1669:                s->mix.decbuf = NULL;
        !          1670:                s->mix.resampbuf = NULL;
        !          1671:                s->mix.join = 1;
        !          1672:                s->mix.expand = 1;
        !          1673:                if (s->dup) {
        !          1674:                        if (dev_nch > slot_nch)
        !          1675:                                s->mix.expand = dev_nch / slot_nch;
        !          1676:                        else if (dev_nch < slot_nch)
        !          1677:                                s->mix.join = slot_nch / dev_nch;
        !          1678:                }
        !          1679:                cmap_init(&s->mix.cmap,
        !          1680:                    s->mix.slot_cmin, s->mix.slot_cmax,
        !          1681:                    s->mix.slot_cmin, s->mix.slot_cmax,
        !          1682:                    0, d->pchan - 1,
        !          1683:                    s->mix.dev_cmin, s->mix.dev_cmax);
        !          1684:                if (!aparams_native(&s->par)) {
        !          1685:                        dec_init(&s->mix.dec, &s->par, slot_nch);
        !          1686:                        s->mix.decbuf =
        !          1687:                            xmalloc(d->round * slot_nch * sizeof(adata_t));
        !          1688:                }
        !          1689:                if (s->rate != d->rate) {
        !          1690:                        resamp_init(&s->mix.resamp, s->round, d->round,
        !          1691:                            slot_nch);
        !          1692:                        s->mix.resampbuf =
        !          1693:                            xmalloc(d->round * slot_nch * sizeof(adata_t));
        !          1694:                }
        !          1695:                s->mix.drop = 0;
        !          1696:                s->mix.vol = MIDI_TO_ADATA(s->vol);
        !          1697:                dev_mix_adjvol(d);
        !          1698:        }
        !          1699:        if (s->mode & MODE_RECMASK) {
        !          1700:                slot_nch = s->sub.slot_cmax - s->sub.slot_cmin + 1;
        !          1701:                dev_nch = s->sub.dev_cmax - s->sub.dev_cmin + 1;
        !          1702:                s->sub.encbuf = NULL;
        !          1703:                s->sub.resampbuf = NULL;
        !          1704:                s->sub.join = 1;
        !          1705:                s->sub.expand = 1;
        !          1706:                if (s->dup) {
        !          1707:                        if (dev_nch > slot_nch)
        !          1708:                                s->sub.join = dev_nch / slot_nch;
        !          1709:                        else if (dev_nch < slot_nch)
        !          1710:                                s->sub.expand = slot_nch / dev_nch;
        !          1711:                }
        !          1712:                cmap_init(&s->sub.cmap,
        !          1713:                    0, ((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1,
        !          1714:                    s->sub.dev_cmin, s->sub.dev_cmax,
        !          1715:                    s->sub.slot_cmin, s->sub.slot_cmax,
        !          1716:                    s->sub.slot_cmin, s->sub.slot_cmax);
        !          1717:                if (s->rate != d->rate) {
        !          1718:                        resamp_init(&s->sub.resamp, d->round, s->round,
        !          1719:                            slot_nch);
        !          1720:                        s->sub.resampbuf =
        !          1721:                            xmalloc(d->round * slot_nch * sizeof(adata_t));
        !          1722:                }
        !          1723:                if (!aparams_native(&s->par)) {
        !          1724:                        enc_init(&s->sub.enc, &s->par, slot_nch);
        !          1725:                        s->sub.encbuf =
        !          1726:                            xmalloc(d->round * slot_nch * sizeof(adata_t));
        !          1727:                }
        !          1728:
        !          1729:                /*
        !          1730:                 * N-th recorded block is the N-th played block
        !          1731:                 */
        !          1732:                s->sub.silence = startpos / (int)s->round;
        !          1733:        }
        !          1734: }
        !          1735:
        !          1736: /*
        !          1737:  * if MMC is enabled, and try to attach all slots synchronously, else
        !          1738:  * simply attach the slot
        !          1739:  */
        !          1740: void
        !          1741: slot_ready(struct slot *s)
        !          1742: {
        !          1743:        if (s->tstate == MMC_OFF)
        !          1744:                slot_attach(s);
        !          1745:        else {
        !          1746:                s->tstate = MMC_START;
        !          1747:                dev_sync_attach(s->dev);
        !          1748:        }
        !          1749: }
        !          1750:
        !          1751: /*
        !          1752:  * setup buffers & conversion layers, prepare the slot to receive data
        !          1753:  * (for playback) or start (recording).
        !          1754:  */
        !          1755: void
        !          1756: slot_start(struct slot *s)
        !          1757: {
        !          1758:        unsigned int bufsz;
        !          1759: #ifdef DEBUG
        !          1760:        struct dev *d = s->dev;
        !          1761:
        !          1762:
        !          1763:        if (s->pstate != SLOT_INIT) {
        !          1764:                slot_log(s);
        !          1765:                log_puts(": slot_start: wrong state\n");
        !          1766:                panic();
        !          1767:        }
        !          1768: #endif
        !          1769:        bufsz = s->appbufsz;
        !          1770:        if (s->mode & MODE_PLAY) {
        !          1771: #ifdef DEBUG
        !          1772:                if (log_level >= 3) {
        !          1773:                        slot_log(s);
        !          1774:                        log_puts(": playing ");
        !          1775:                        aparams_log(&s->par);
        !          1776:                        log_puts(" -> ");
        !          1777:                        aparams_log(&d->par);
        !          1778:                        log_puts("\n");
        !          1779:                }
        !          1780: #endif
        !          1781:                s->mix.bpf = s->par.bps *
        !          1782:                    (s->mix.slot_cmax - s->mix.slot_cmin + 1);
        !          1783:                abuf_init(&s->mix.buf, bufsz * s->mix.bpf);
        !          1784:        }
        !          1785:        if (s->mode & MODE_RECMASK) {
        !          1786: #ifdef DEBUG
        !          1787:                if (log_level >= 3) {
        !          1788:                        slot_log(s);
        !          1789:                        log_puts(": recording ");
        !          1790:                        aparams_log(&s->par);
        !          1791:                        log_puts(" <- ");
        !          1792:                        aparams_log(&d->par);
        !          1793:                        log_puts("\n");
        !          1794:        }
        !          1795: #endif
        !          1796:                s->sub.bpf = s->par.bps *
        !          1797:                    (s->sub.slot_cmax - s->sub.slot_cmin + 1);
        !          1798:                abuf_init(&s->sub.buf, bufsz * s->sub.bpf);
        !          1799:        }
        !          1800:        s->mix.weight = MIDI_TO_ADATA(MIDI_MAXCTL);
        !          1801: #ifdef DEBUG
        !          1802:        if (log_level >= 3) {
        !          1803:                slot_log(s);
        !          1804:                log_puts(": allocated ");
        !          1805:                log_putu(s->appbufsz);
        !          1806:                log_puts("/");
        !          1807:                log_putu(SLOT_BUFSZ(s));
        !          1808:                log_puts(" fr buffers\n");
        !          1809:        }
        !          1810: #endif
        !          1811:        if (s->mode & MODE_PLAY) {
        !          1812:                s->pstate = SLOT_START;
        !          1813:        } else {
        !          1814:                s->pstate = SLOT_READY;
        !          1815:                slot_ready(s);
        !          1816:        }
        !          1817: }
        !          1818:
        !          1819: /*
        !          1820:  * stop playback and recording, and free conversion layers
        !          1821:  */
        !          1822: void
        !          1823: slot_detach(struct slot *s)
        !          1824: {
        !          1825:        struct slot **ps;
        !          1826:
        !          1827: #ifdef DEBUG
        !          1828:        if (log_level >= 3) {
        !          1829:                slot_log(s);
        !          1830:                log_puts(": detaching\n");
        !          1831:        }
        !          1832: #endif
        !          1833:        for (ps = &s->dev->slot_list; *ps != s; ps = &(*ps)->next) {
        !          1834: #ifdef DEBUG
        !          1835:                if (s == NULL) {
        !          1836:                        slot_log(s);
        !          1837:                        log_puts(": can't detach, not on list\n");
        !          1838:                        panic();
        !          1839:                }
        !          1840: #endif
        !          1841:        }
        !          1842:        *ps = s->next;
        !          1843:        if (s->mode & MODE_RECMASK) {
        !          1844:                if (s->sub.encbuf)
        !          1845:                        xfree(s->sub.encbuf);
        !          1846:                if (s->sub.resampbuf)
        !          1847:                        xfree(s->sub.resampbuf);
        !          1848:        }
        !          1849:        if (s->mode & MODE_PLAY) {
        !          1850:                if (s->mix.decbuf)
        !          1851:                        xfree(s->mix.decbuf);
        !          1852:                if (s->mix.resampbuf)
        !          1853:                        xfree(s->mix.resampbuf);
        !          1854:                dev_mix_adjvol(s->dev);
        !          1855:        }
        !          1856: }
        !          1857:
        !          1858: /*
        !          1859:  * put the slot in stopping state (draining play buffers) or
        !          1860:  * stop & detach if no data to drain.
        !          1861:  */
        !          1862: void
        !          1863: slot_stop(struct slot *s)
        !          1864: {
        !          1865: #ifdef DEBUG
        !          1866:        if (log_level >= 3) {
        !          1867:                slot_log(s);
        !          1868:                log_puts(": stopping\n");
        !          1869:        }
        !          1870: #endif
        !          1871:        if (s->pstate == SLOT_START) {
        !          1872:                if (s->mode & MODE_PLAY) {
        !          1873:                        s->pstate = SLOT_READY;
        !          1874:                        slot_ready(s);
        !          1875:                } else
        !          1876:                        s->pstate = SLOT_INIT;
        !          1877:        }
        !          1878:        if (s->mode & MODE_RECMASK)
        !          1879:                abuf_done(&s->sub.buf);
        !          1880:        if (s->pstate == SLOT_READY) {
        !          1881: #ifdef DEBUG
        !          1882:                if (log_level >= 3) {
        !          1883:                        slot_log(s);
        !          1884:                        log_puts(": not drained (blocked by mmc)\n");
        !          1885:                }
        !          1886: #endif
        !          1887:                if (s->mode & MODE_PLAY)
        !          1888:                        abuf_done(&s->mix.buf);
        !          1889:                s->ops->eof(s->arg);
        !          1890:                s->pstate = SLOT_INIT;
        !          1891:        } else {
        !          1892:                /* s->pstate == SLOT_RUN */
        !          1893:                if (s->mode & MODE_PLAY)
        !          1894:                        s->pstate = SLOT_STOP;
        !          1895:                else {
        !          1896:                        slot_detach(s);
        !          1897:                        s->pstate = SLOT_INIT;
        !          1898:                        s->ops->eof(s->arg);
        !          1899:                }
        !          1900:        }
        !          1901:        if (s->tstate != MMC_OFF)
        !          1902:                s->tstate = MMC_STOP;
        !          1903: }
        !          1904:
        !          1905: /*
        !          1906:  * notify the slot that we just wrote in the play buffer, must be called
        !          1907:  * after each write
        !          1908:  */
        !          1909: void
        !          1910: slot_write(struct slot *s)
        !          1911: {
        !          1912:        if (s->pstate == SLOT_START && s->mix.buf.used == s->mix.buf.len) {
        !          1913: #ifdef DEBUG
        !          1914:                if (log_level >= 4) {
        !          1915:                        slot_log(s);
        !          1916:                        log_puts(": switching to READY state\n");
        !          1917:                }
        !          1918: #endif
        !          1919:                s->pstate = SLOT_READY;
        !          1920:                slot_ready(s);
        !          1921:        }
        !          1922: }
        !          1923:
        !          1924: /*
        !          1925:  * notify the slot that we freed some space in the rec buffer
        !          1926:  */
        !          1927: void
        !          1928: slot_read(struct slot *s)
        !          1929: {
        !          1930:        /* nothing yet */
        !          1931: }