Sound, from memory?

For now it seems the only legal way to play a sound is to suply a file to it via TCastlePlayingSound.sound.URL

But in the end all the files are streams (or memory-maped files) plus attributes (like file names - but file names can be misleading, so actual format analyzer is better than file extension dictionary).

Once could think there could’ve been an easy way to short-circuit it and provide immediate TBytes or TBytesStream to the sound engine.

Or, maybe, some special URL scheme like .URL := 'castle-memory://0/name' where name would be a registered name (like in TDictionary<string, TBytes>) and zero would be a “folder” index (as in TObjectList<TDictionary<string, TBytes>>) - merely for optional grouping resources

Good point, I added TCastleSound.LoadFromStream to load sound data from arbitrary stream (like TMemoryStream). This is our answer to such needs throughout CGE (e.g. LoadNode also has overload to load from stream).

The TCastleSound.LoadFromStream implementation is quite unoptimal now (does unnecessary base64 encode/decode), but at least API is there.

To make URLs like castle-memory://0/name you could implement your own URL scheme, following examples/network/custom_url_handler/ approach. Each application can roll its own idea how it can look like. (I do not want to implement castle-memory://0/name built-in CGE, to keep things simple.)

Each application can roll its own idea how it can look like

yeah, reinvernting a wheel.

Well, maybe you can make it part of the examples / code templates, and then document it, so it would not be “part of the cintract” API that you would be bound to keep, but still kind of endorsed and promoted, so applications could just take and use it if it fits their bill? Like Jedi CodeLib did with their exception stack trace dialog. Formally, it is just a demo, but de facto lot of applicati nincluding Delphi itself just use it with minor tweaks.

I simply do not see castle-memory://0/name URL scheme as a critical feature in the engine. And, as I said before, I believe that applications that need it – may have unique requirements around it (e.g. whether to identify such memory streams by integers or by strings).

To manage multiple memory streams, in normal cases, you don’t need any special URL scheme – I haven’t seen it being necessary in any games and examples I made, in CGE or other engines. Instead you just have multiple TMemoryStream instances and manage them however you like.

Again, each application can implement such URL scheme on their own, following examples/network/custom_url_handler/ example.

Hello again.

I was under impression that SoundEngine.Enabled is like a Mute butotn on TV set - you can always check it off and back on at will, and the sound would just kick in as it was.

procedure TMyBuzzing.SoundsOn;
var B: TCastlePlayingSound;
    i: integer;
begin
  FSoundsEnabled := True;

  for i := Low(Buzz) to High(Buzz) do
  begin
    if not Infos[i].Enabled then Continue;
    B := Buzz[i];
    if nil = B then Continue;
    SoundEngine.Play(B);
  end;

  FSkipChange := 0;
  SoundEngine.Enabled := True;
end;

procedure TMyBuzzing.SoundsOff;
var B: TCastlePlayingSound;
begin
  SoundEngine.Enabled := False;
  for B in Buzz do
     if nil <> B then
        B.Stop;
  FSoundsEnabled := False;
end;

This, however, does not work. It seems i first have to SoundEngine.Enabled := True; then to re-init every single sound source.

Is it as intended? I am a under impression (but not certain) that it used toi be a different way.

That any moment i could do something like

SoundEngine.Enabled := False;
Sleep(2000);
SoundEngine.Enabled := True;

…and it would just continue from the place it paused ?

Probably the intended approach is to insert some “intermediate group objects” between the TCastlePlayingSound and SoundEngine

Setting SoundEngine.Enabled to false means that the sound backend (like OpenAL) will not be initialized. If it was already initialized, it will be deinitialized. When the sound backend is not initialized, we do not track sound progress, we do not track what is being played (doing that would mean we need to implement a “skeleton sound engine” just for this purpose – big work for little practical gain).

Basically, SoundEngine.Enabled := false is not a way to temporarily mute the application.

So mute the application, simply set SoundEngine.Volume := 0 . All sound backends (OpenAL, FMOD etc.) will be optimized for this specific case.

( There was no change to this in CGE. SoundEngine.Enabled worked like this from the beginning when it was present. )

P.S. Please create a new thread for a new question :slight_smile: