samstyle / Xpeccy

Multiplatform emulator of retro computers
MIT License
73 stars 13 forks source link

SAA envelope mixing fix, SAASound-like tone&noise mixing #5

Closed LasDesu closed 9 years ago

LasDesu commented 9 years ago

SAA mixer fixed. Don't know if tone and noise mixer is really so complicated.

samstyle commented 9 years ago

А вот тут надо пояснить. Где-то задокументированы такие извращения? Почему при одновременном шуме и тоне громкость вдруг падает в 2 раза, а при отсутствии хотя бы одного - второй не выводится вообще?

LasDesu commented 9 years ago

Собственно так делается в SAASound (http://simonowen.com/sam/saasound/) и в SimCoupe, но метод кажется довольно замороченным. Вот фиг знает как на самом деле, да и не так сильно влияет на звучание.

samstyle commented 9 years ago

Как-то странно это, с мануалом расходится... Пока не буду коммитить.

LasDesu commented 9 years ago

Логика скорей такая: если только один из сигналов (тон или нойз) единица - будет полная амплитуда, если оба нули - ноль, а если оба в единице - половина амплитуды. Я из тона и нойза формирую инвертированный сигнал (всё равно долбятся туда-сюда), так код огибающей чуть проще. Хотя может совсем не правильно, зависит от того как мелкосхема реагирует на изменение громкости при выключенных тоне, шуме и огибающей. Без инверсии будет как-то так :

sndPair saaMixTN(saaChan* ch, saaNoise* noiz) {
    sndPair res;
    int signal = 0;
    if ( (ch->freqEn && ch->lev) || (ch->noizEn && noiz->lev) ) {
        if ( (ch->freqEn && ch->lev) && (ch->noizEn && noiz->lev) )
            signal = 2;
        else
            signal = 1;
    }
    if ( signal ) {
        res.left = ch->ampLeft / signal;
        res.right = ch->ampRight / signal;
    } else {
        res.left = 0;
        res.right = 0;
    }
    return res;
}

sndPair saaMixTNE(saaChan* ch, saaNoise* noiz, saaEnv* env) {
    if (!env->enable) return saaMixTN(ch, noiz);
    sndPair res;
    int signal = 1;
    if ( ch->freqEn || ch->noizEn )
    {
        signal = 0;
        if ( (ch->freqEn && ch->lev) || (ch->noizEn && noiz->lev) ) {
            if ( (ch->freqEn && ch->lev) && (ch->noizEn && noiz->lev) )
                signal = 2;
            else
                signal = 1;
        }
    }
    if ( signal ) {
        res.left = ch->ampLeft * 7 * env->vol / 15 / 8 / signal;
        res.right = ch->ampRight * 7 * ((env->invRight) ? (env->vol ^ 0x0f) : env->vol) / 15 / 8 / signal;
    } else {
        res.left = 0;
        res.right = 0;
    }
    return res;
}

Или без выпендрежа:

sndPair saaMixTN(saaChan* ch, saaNoise* noiz) {
    sndPair res;
    int signal = 0;
    if ( (ch->freqEn && ch->lev) || (ch->noizEn && noiz->lev) ) {
        signal = 1;
    }
    if ( signal ) {
        res.left = ch->ampLeft;
        res.right = ch->ampRight;
    } else {
        res.left = 0;
        res.right = 0;
    }
    return res;
}

sndPair saaMixTNE(saaChan* ch, saaNoise* noiz, saaEnv* env) {
    if (!env->enable) return saaMixTN(ch, noiz);
    sndPair res;
    int signal = 1;
    if ( ch->freqEn || ch->noizEn )
    {
        signal = 0;
        if ( (ch->freqEn && ch->lev) || (ch->noizEn && noiz->lev) ) {
            signal = 1;
        }
    }
    if ( signal ) {
        res.left = ch->ampLeft * 7 * env->vol / 15 / 8;
        res.right = ch->ampRight * 7 * ((env->invRight) ? (env->vol ^ 0x0f) : env->vol) / 15 / 8;
    } else {
        res.left = 0;
        res.right = 0;
    }
    return res;
}