Не удается заставить OpenAL воспроизводить звук

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

Сначала несколько примечаний ... Я искал что-то, что позволило бы мне использовать оригинальную методологию. Исходная система использовала парные байты для музыки (звуковые эффекты - только 2 - обрабатывались в коде.) Байт времени, который отсчитывался каждый раз при вызове подпрограммы, и байт ноты, который воспроизводился до тех пор, пока время не достигло нуля. это было сделано путем вставки в вектор прерывания, окна не позволяют этого, поэтому я установил таймер маршрутизации, который выполняет то же самое. Таймер срабатывает, обновляет дисплей, а затем запускает музыкальную последовательность. Я установил это на определенное время, чтобы у меня было только одно место для настройки времени (чтобы сделать его как можно ближе к исходной последовательности. Музыка представляет собой сгенерированную форму волны (и я дважды проверил математику, и даже проверил сгенерированные данные в режиме отладки), и это выглядит хорошо. Последовательность выглядит хорошо, но на самом деле не воспроизводит звук. Сначала я попробовал SDL2, и этот метод воспроизведения только 1 звука не работает для меня, также , если я не сделаю длительность семпла очень короткой (и звук, производимый таким образом, ужасен), я не смогу согласовать время (он проигрывает весь семпл через собственное прерывание, не позволяя мне вносить коррективы). Кроме того, смешивание трех голосов вместе (когда все они работают с разным таймингом) - это беспорядок. Большинство других движков, которые я исследовал, работают примерно так же, они хотят использовать собственное прерывание обратного вызова и не позволяют мне настраивать его соответствующим образом. почему я начал работать с OpenAL. Он позволяет использовать несколько голосов (источников) и позволяет мне тайминги устанавливаю сам. По совету нескольких форумов я настроил его так, чтобы длина выборки была кратна полному циклу. Во всяком случае, вот код.

int main(int argc, char* argv[])
{
    FreeConsole();  //Get rid of the DOS console, don't need it
    if (InitLog() < 0) return -1;   //Start logging

    UINT_PTR tim = NULL;
    SDL_Event event;


    InitVideo(false);   //Set to window for now, will put options in later
    curmusic = 5;
    InitAudio();

    SetTimer(NULL,tim,_FREQ_,TimerProc);

    SDL_PollEvent(&event);
    while (event.type != SDL_KEYDOWN) SDL_PollEvent(&event);

    SDL_Quit();
    return 0;
}

void CALLBACK TimerProc(HWND hWind, UINT Msg, UINT_PTR idEvent, DWORD dwTime)
{
    RenderOutput();
    PlayMusic();
    //UpdateTimer();
    //RotateGate();
    return;
}

void InitAudio(void)
{
    ALCdevice *dev;
    ALCcontext *cxt;

    Log("Initializing OpenAL Audio\r\n");
    dev = alcOpenDevice(NULL);
    if (!dev) {
        Log("Failed to open an audio device\r\n");
        exit(-1);
    }
    cxt = alcCreateContext(dev, NULL);
    alcMakeContextCurrent(cxt);
    if(!cxt) {
        Log("Failed to create audio context\r\n");
        exit(-1);
    }
    alGenBuffers(4,Buffer);
    if (alGetError() != AL_NO_ERROR) {
        Log("Error during buffer creation\r\n");
        exit(-1);
    }
    alGenSources(4, Source);
    if (alGetError() != AL_NO_ERROR) {
        Log("Error during source creation\r\n");
        exit(-1);
    }

    return;
}

void PlayMusic()
{
    static int oldsong, ofset, mtime[4];
    double freq;
    ALuint srate = 44100;
    ALuint voice, i, note, len, hold;
    short buf[4][_BUFFSIZE_];
    bool test[4] = {false, false, false, false};

    if (curmusic != oldsong) {
        oldsong = (int)curmusic;
        if (curmusic > 0)
            ofset = moffset[(curmusic - 1)];
        for (voice = 1; voice < 4; voice++)
            alSourceStop(Source[voice]);
            mtime[voice] = 0;
        return;
    }

    if (curmusic == 0) return;
                                            //Only 3 voices for music, but have
    for (voice = 0; voice < 3; voice ++) {  // 4 set asside for eventual sound effects
        if (mtime[voice] == 0) {                //is note finished
            alSourceStop(Source[voice]);  //It is, so stop the channel (source)
            mtime[voice] = music[ofset++];      //Get the next duration
            if (mtime[voice] == 0) {oldsong = 0; return;}  //zero marks end, so restart
            note = music[ofset++];              //Get the next note
            if (note > 127) {           //Old HW data was designed for could only
                if (note == 255) note = 127;    //use values 128 - 255 (255 = 127)
                freq = (15980 / (voice + (int)(voice / 3))) / (256 - note);  //freq of note
                len = (ALuint)(srate / freq);   //A single cycle of that freq.
                hold = len;
                while (len < (srate / (1000 / _FREQ_))) len += hold;  //Multiply till 1 interrup cycle
                while (len > _BUFFSIZE_) len -= hold; //Don't overload buffer
                if (len == 0) len = _BUFFSIZE_; //Just to be safe
                for (i = 0; i < len; i++)   //calculate sine wave and put in buffer
                    buf[voice][i] = (short)((32760 * sin((2 * M_PI * i * freq) / srate)));
                alBufferData(Buffer[voice], AL_FORMAT_MONO16, buf[voice], len, srate);
                alSourcei(openAL.Source[i], AL_LOOPING, AL_TRUE);
                alSourcei(Source[i], AL_BUFFER, Buffer[i]);
                alSourcePlay(Source[voice]);
           }
        } else --mtime[voice];
    }
}

person user3399848    schedule 15.08.2014    source источник
comment
Прежде чем кто-либо прокомментирует (исправление проблемы деления на ноль не помогает - изначально это был голос 1–3 с нулем, зарезервированным для звуковых эффектов). Скопировал код после изменения на 0–3 для целей тестирования, но до того, как я исправил делим на ноль выпуск. Извини за это.   -  person user3399848    schedule 15.08.2014
comment
TimerProc заменен на _beginthread, поскольку TimerProc, казалось, хотел запускаться только в моем цикле ожидания тестирования (просто зацикливался, пока я не нажал клавишу). Там он отлично работал. Если я сохраню синусоидальные волны в файл и открою его с помощью медиаплеера, он будет звучать нормально (хотя и приглушенно), поэтому я генерирую правильные частоты, а время прерывания довольно близко. Однако все еще не могу заставить его издавать звук.   -  person user3399848    schedule 17.08.2014


Ответы (1)


Оказывается, с моим кодом было 3 проблемы. Во-первых, вы должны связать построенный волновой буфер с буфером, сгенерированным AL, "до" того, как вы свяжете буфер с источником:

alBufferData(buffer,AL_FORMAT_MONO16,&wave_sample,sample_lenght * sizeof(short),frequency);
alSourcei(source,AL_BUFFER,buffer);

Также в приведенном выше примере я умножил sample_length на количество байтов в каждой выборке (в данном случае «sizeof (short)».

Последняя проблема заключалась в том, что вам нужно отсоединить буфер от источника перед изменением данных буфера.

alSourcei(source,AL_BUFFER,NULL);

Музыка будет играть, но не правильно, пока я не добавлю эту строку в код изменения ноты.

person user3399848    schedule 19.08.2014
comment
К сожалению, код отмены связи изменен на NULL вместо буфера. - person user3399848; 20.08.2014