# Title Different channel behavior when switching from Core API to Studio API: after sound finishes Channel::\* calls fail

**URL:** <https://qa.fmod.com/t/title-different-channel-behavior-when-switching-from-core-api-to-studio-api-after-sound-finishes-channel-calls-fail/23358>\
**Category:** FMOD Engine\
**Tags:** cpp\
**Created:** [September 15, 2025, 11:02pm UTC](https://qa.fmod.com/t/title-different-channel-behavior-when-switching-from-core-api-to-studio-api-after-sound-finishes-channel-calls-fail/23358 "2025-09-15T23:02:50Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![kozl22](https://avatars.discourse-cdn.com/v4/letter/k/dfb087/32.png) [@kozl22](https://qa.fmod.com/u/kozl22)\
**Post date:** [September 15, 2025, 11:02pm UTC](https://qa.fmod.com/t/title-different-channel-behavior-when-switching-from-core-api-to-studio-api-after-sound-finishes-channel-calls-fail/23358/1 "2025-09-15T23:02:50Z")

</div>

Windows (x64), C++  
FMOD: 2.03.09

I have a working setup with the Core API:

```cpp
CHECKFMODERR(FMOD::System_Create(&system));

CHECKFMODERR(system->setSoftwareChannels(MAX_SOUNDS_SLOTS));

CHECKFMODERR(system->init(MAX_SOUNDS_SLOTS, FMOD_INIT_NORMAL, nullptr));

CHECKFMODERR(system->set3DSettings(1.0f, DISTANCEFACTOR, 1.0f));

// per frame:

CHECKFMODERR(system->update());

```

When I switch to the Studio API (but still play sounds via low-level System::playSound):

```cpp
CHECKFMODERR(FMOD::Studio::System::create(&studiosystem));

CHECKFMODERR(studiosystem->getCoreSystem(&system));

CHECKFMODERR(system->setSoftwareChannels(MAX_SOUNDS_SLOTS));

CHECKFMODERR(studiosystem->initialize(MAX_SOUNDS_SLOTS, FMOD_STUDIO_INIT_NORMAL, FMOD_INIT_NORMAL, nullptr));

CHECKFMODERR(system->set3DSettings(1.0f, DISTANCEFACTOR, 1.0f));

// per frame:

CHECKFMODERR(studiosystem->update());

```

Observed:

- After a short sound naturally finishes, any calls on the channel (e.g., channel-\>getPaused, channel-\>isPlaying) sometimes do not return FMOD\_OK. With pure Core init I get FMOD\_OK and isPlaying=false in the same situation.
- Virtualization behaves differently: channels become virtual more often / seem to “disappear” earlier, even though I did not change virtualization settings.

Questions:

1. Is it expected that the lifetime/validity of low-level channels (FMOD::Channel) differs when initialized via Studio API vs pure Core init? In my case, this is critical (see the code below).
2. Can Studio API be configured to behave as close as possible to Core (same/near virtualization behavior and the same return codes after a sound ends)?

Additional notes:

- Channels are created with system-\>playSound (not Studio events).
- With Core API the current logic is stable; issues appear immediately after switching Init/Update to Studio.

Small code excerpt where the issue manifests (cleanup after completion):

```cpp
bool paused = true;
FMOD_RESULT status = PlayingSounds[i].channel->getPaused(&paused);
if (status != FMOD_OK) {
    core.Trace("PlayingSounds[%d].channel 0x%08X %s paused %d status %d",
               i, PlayingSounds[i].channel, PlayingSounds[i].Name.c_str(), paused, status);
    i = FreeSound(i);
    continue;
}

if (paused) continue;

bool is_playing;
status = CHECKFMODERR(PlayingSounds[i].channel->isPlaying(&is_playing));

if (!is_playing || status != FMOD_OK) {
    if (PlayingSounds[i].aliasLoopIdx != -1)
        AliasRandomLoopSound(i);
    else {
        PlayingSounds[i].channel = nullptr;
        if (i <= 1 && OGG_sound[i] != nullptr) {
            CHECKFMODERR(OGG_sound[i]->release());
            OGG_sound[i] = nullptr;
        }
        i = FreeSound(i);
        int32_t soundId = (i + 1) | (PlayingSounds[i].stamp << 16);
        core.Event("SoundEnded", "l", soundId);
    }
}

```

In Core, checking the paused state worked fine, but in Studio, sounds that have finished playing immediately return FMOD\_ERR\_INVALID\_HANDLE. Even if I rewrite this logic, the channel becomes completely inaccessible, including losing info like its last 3D coordinates, which is important for restarting a random sound from a specific list at the same location.

---

<div class="post-metadata">

**Author:** ![kozl22](https://avatars.discourse-cdn.com/v4/letter/k/dfb087/32.png) [@kozl22](https://qa.fmod.com/u/kozl22)\
**Post date:** [September 19, 2025, 10:55am UTC](https://qa.fmod.com/t/title-different-channel-behavior-when-switching-from-core-api-to-studio-api-after-sound-finishes-channel-calls-fail/23358/2 "2025-09-19T10:55:42Z")

</div>

1. I rewrote the error handling so that in a couple of places FMOD\_ERR\_INVALID\_HANDLE / FMOD\_ERR\_CHANNEL\_STOLEN are treated not as errors but as the normal scenario after a channel finished playback.
2. The issue where channel coordinates couldn’t be retrieved via the getter (because with the Studio API the channel becomes invalid immediately after the sound ends) was fixed by adding an FMOD\_VECTOR field to the sound structure. Rewriting the crossfade from a delta-time–based implementation to a proper API-based approach also freed up three floats.
3. Regarding virtualization: FMOD Core by default does not virtualize channels (vol0virtualvol = -1.0f), while FMOD Studio does. Damn, this is nowhere documented. I’m also a bit unhappy that at the start of playback, until the updater runs, a channel that should be virtual will be real for one frame.

In general, I would like more information about what gets overridden when FMOD Studio is enabled if previously only the Core was used.

---

<div class="post-metadata">

**Author:** ![Leah\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/leah_fmod/32/3685_2.png) [@Leah\_FMOD](https://qa.fmod.com/u/Leah_FMOD)\
**Post date:** [September 29, 2025, 6:16am UTC](https://qa.fmod.com/t/title-different-channel-behavior-when-switching-from-core-api-to-studio-api-after-sound-finishes-channel-calls-fail/23358/3 "2025-09-29T06:16:49Z")

</div>

Apologies for the delayed response!

> [@kozl22](#):
>
> Is it expected that the lifetime/validity of low-level channels (FMOD::Channel) differs when initialized via Studio API vs pure Core init? In my case, this is critical (see the code below).

Unfortunately, I haven’t been able to reproduce the behavior you described, where channels played by a Studio system’s Core system become invalid when finished, but do not when only played by a Core system. Behavior for both cases is the same on my end - channels become invalid once they finish playing.

Can you share a code snippet demonstrating how sounds are being created and played?

> [@kozl22](#):
>
> I’m also a bit unhappy that at the start of playback, until the updater runs, a channel that should be virtual will be real for one frame.

I’m also unable to reproduce this. I’m observing that channels that would exceed the software channel count are immediately virtual, even before the system is updated. How is your channel going virtual? Is it exceeding the software channels limit, or falling below `vol0virtualvol`?

> [@kozl22](#):
>
> Regarding virtualization: FMOD Core by default does not virtualize channels (vol0virtualvol = -1.0f), while FMOD Studio does. Damn, this is nowhere documented.

Studio initializes with `FMOD_INIT_VOL0_BECOMES_VIRTUAL`, while the Core API does not, which I have noticed isn’t documented - I’ve flagged this internally.

However, unless it has been specified in `FMOD_ADVANCEDSETTINGS`, `vol0virtualvol` isn’t set at all for both Studio and Core systems, and should be 0. How are you observing the value of `vol0virtualvol`?
