0

Background info: I was working on my C project these days. And due to the reason that this project is a piecs of homework of a course, we are told that using other libraries is not allowed. Our teacher provied us with a simple graphic lib and I planned to write a simple 2DGameEngine.

However when I tried to use mciSendString() to realize the audio system, I found that this function work out with GREAT DELAY (about 0.5s or a little bit more than that), It's not bareable for Game sound effect.

At first I thought it was because my function play need first open a audio and then play it (I thought open a file from disk would spend a lot of time),However when I move open operation out of play, the delay still exist. I found many blogs or answers told me to use PlaySound() or use XAudio2. But the former cannot play audio parally and the latter seems doesn't work well C. So I am expecting some solutions that DO NOT depends on any other libraries except Windows API and are able to immediately play the sound without any delay.

Here are some pieces of my code:

//Using OOP style in C and Audio is a Component.
Audio* newAudio(char* filePath, bool loop) {
    Audio* audio = (Audio*)malloc(sizeof(Audio));
    initAudio(audio, filePath, loop);
    return audio;
}

static void initAudio(struct Audio *audio, char* filePath, bool loop){
    
    Component* super = newComponent(renderAudio, updateAudio);
    memcpy(&(audio->super), super, sizeof(Component));
    audio->super.vptr = NULL;
    audio->super.vptr = (componentvTable*)calloc(1, sizeof(componentvTable));
    if (audio->super.vptr == NULL) {
        printf("Cannot allocate memory for vptr of audio component\n");
        return;
    }
    memcpy(audio->super.vptr, super->vptr, sizeof(componentvTable));
    audio->super.vptr->getComponentType = returnAudioType;
    destoryComponent(super);
    audio->super.vptr->getComponentType = returnAudioType;
    audio->super.meta = NULL;
    audio->super.next = NULL;
    audio->super.prev = NULL;

    audio->filePath = filePath;
    audio->playing = FALSE;
    audio->loop = loop;
    audio->volume = 100;
    audio->play = Audio_play;
    audio->pause = Audio_pause;
    audio->stop = Audio_stop;
    audio->setVolume = Audio_setVolume;
    audio->getFilePath = Audio_getFilePath;
    audio->getMeta = audio->super.getMeta;
    audio->setMeta = audio->super.setMeta;

    char command[256];
    sprintf(command, "open \"%s\" type mpegvideo alias audio%d", audio->filePath, (int)audio);
    mciSendString(command, NULL, 0, NULL);
}

static void renderAudio(Component* c){
    return;
}

static void updateAudio(Component* c, ...){
    return;
}

static const int returnAudioType(ComponentNode c){
    return AUDIO;
}

static void Audio_play(struct Audio* audio) {
    char command[256];
    if (!audio->loop) {
        sprintf(command, "play audio%d", (int)audio);
        mciSendString(command, NULL, 0, NULL);
    } else {
        sprintf(command, "play audio%d repeat", (int)audio);
        mciSendString(command, NULL, 0, NULL);
    }
    
    audio->playing = TRUE;
}

static void Audio_pause(struct Audio* audio) {
    char command[256];
    sprintf(command, "pause audio%d", (int)audio);
    mciSendString(command, NULL, 0, NULL);
    
    audio->playing = FALSE;
}

static void Audio_stop(struct Audio* audio) {
    char command[256];
    sprintf(command, "stop audio%d", (int)audio);
    mciSendString(command, NULL, 0, NULL);
    sprintf(command, "seek audio%d to %ld", (int)audio, 0L);
    mciSendString(command, NULL, 0, NULL);
    
    audio->playing = FALSE;
}

static void Audio_setVolume(struct Audio* audio, int volume) {
    char command[256];
    sprintf(command, "setaudio audio%d volume to %d", (int)audio, volume);
    mciSendString(command, NULL, 0, NULL);
    
    audio->volume = volume;
}

static char* Audio_getFilePath(struct Audio* audio) {
    return audio->filePath;
}

static void destoryAudio(struct Audio* audio) {
    char command[256];
    sprintf(command, "close audio%d", (int)audio);
    mciSendString(command, NULL, 0, NULL);
    free(audio->super.vptr);
    free(audio);
}

And below is how I use it.

static void playerUpdate(ActorNode player, double delta)
{
    //other code
    
    //R键技能
    Vector *dashDirection = newVector(inmng.mouseX - player->pos.x, inmng.mouseY - player->pos.y);
    if (dashDirection->length(dashDirection) > 5)
    {
        dashDirection->normalize(dashDirection);
        dashDirection->mult(dashDirection, 5);
    }
    if (inmng.keyStates['R'])
    {
        //Start to play skill sound effect here.
        if (!bulletTimeSound->playing)
            bulletTimeSound->play(bulletTimeSound);

        GAME_TIME_TICK = 1.0 / 500.0;
        rPressed = TRUE;
        playerDashTargetCircle->pos.x = player->pos.x + dashDirection->x;
        playerDashTargetCircle->pos.y = player->pos.y + dashDirection->y;
        playerDashTargetCircle->visible = TRUE;
        playerDashTargetCircle->super.vptr->update((ComponentNode)playerDashTargetCircle, &(playerDashTargetCircle->pos));
    }
    else
    {
        GAME_TIME_TICK = 1.0 / 60.0;
        if (rPressed && inmng.keyBoardEventType == KEY_UP)
        {
            rPressed = FALSE;
            playerDashTargetCircle->visible = FALSE;
            if (dashPower >= 10){
                dashPower = dashPower - 40 > 0 ? dashPower - 40 : 0;
                player->vel.x = dashDirection->x; player->vel.y = dashDirection->y;
                Vector vel;
                memcpy(&(vel), &(player->vel), sizeof(Vector));
                vel.mult(&(vel), delta * VEL_CONST * 25);
                player->pos.add(&(player->pos), &(vel));
                
                //Stop skill sound effect play here
                bulletTimeSound->stop(bulletTimeSound);
            }
            
        }
    }
    // other code
}
  • Are you asking how to write a multi-threaded Windows program? – Lundin May 12 '23 at 12:32
  • Not exactly.... Actually I just need a sound playing solution support parallel playing like `mciSendString` but without ant delay. – LilDinosaur May 12 '23 at 12:34
  • I've viewed this question: https://stackoverflow.com/questions/67270203/how-to-fix-mcisendstring-delay. And it seems still helpless for me. : ( – LilDinosaur May 12 '23 at 12:41
  • Windows' audio subsystem is essentially exposed as two APIs: [XAudio2](https://learn.microsoft.com/en-us/windows/win32/xaudio2/xaudio2-apis-portal), a low-level API providing the base to implement an audio engine, and [Microsoft Media Foundation](https://learn.microsoft.com/en-us/windows/win32/medfound/microsoft-media-foundation-sdk), a higher-level interface, primarily intended for rendering and authoring digital media. Either one is capable of rendering low-latency audio, and either API is based on COM. Using COM from C is somewhat verbose, but not entirely difficult to comprehend either. – IInspectable May 12 '23 at 18:50
  • Though I'm not aware of any online resources that cover COM ([the Component Object Model](https://learn.microsoft.com/en-us/windows/win32/com/the-component-object-model)) from a C developer's perspective, I'm sure there have to be. @Lundin Asynchronous I/O doesn't imply *"multi-threading"* on Windows. – IInspectable May 12 '23 at 18:55
  • @IInspectable No it's a poor man's multi-threading... Though you can of course start it from a thread anyway, not to burned other unrelated threads with the callbacks. – Lundin May 12 '23 at 21:32
  • @Lundin You've got that backwards. Multi-threading is a poor man's implementation of asynchronous procedure calls. It's the go-to solution when programming for platforms whose kernel doesn't support asynchronous procedure calls, so you may not have much practical experience with APCs. – IInspectable May 13 '23 at 06:37
  • What do you mean with "cannot play audio parally" couldn't you use the `SND_ASYNC` flag? – noah1400 May 13 '23 at 22:47
  • I suggest you could try to use thread. Refer to the thread:https://stackoverflow.com/questions/16853586/c-win32-what-in-my-mci-utilization-is-causing-a-delay. [PlaySound](https://learn.microsoft.com/en-us/windows/win32/multimedia/using-playsound-to-play-waveform-audio-files) is used to play .wav files. What do you mean "cannot play audio parally"? – Jeaninez - MSFT May 17 '23 at 09:46
  • Thanks for so many answers! It seems that other features in this project have already earned me enough scores for this course :-). – LilDinosaur Jun 15 '23 at 07:28
  • Maybe Multi-threading with playSound() could help,But I’d like to change the base of my 2DGameEngine. Maybe SDL2 can be a good choice (Anyway it’s much better then the library our professor told us to depends on to finish our project, its a old style graphic lib based on Win32API). And of course I’ll try to reconstruct this project in C++ rather than C in the future – LilDinosaur Jun 15 '23 at 07:30

0 Answers0