Sound und GE_SEND_NOTIFICATION

  • Ich versuche mir ein Framework für das Abspielen von Musikdaten zu basteln. Das Definieren und Abspielen von Musikdaten ist mir soweit klar. Nur das Unlocken muss noch gekärt werden.

    In einer Methode / Funktion übergebe ich einen optr mit dem Namen music von meinem Chunk mit den Musikdaten:

    Code
    word *p_music;
    MemLock(OptrToHandle(music));
    p_music = LMemDeref(music);
    SoundAllocMusic(p_music, 4, &g_songHandle);
    SoundPlayMusic(g_songHandle, SP_STANDARD + SP_IMMEDIATE, EIGHTH, UNLOCK_ON_EOS);

    Die Funktion SoundPlayMusic erwartet, dass der Chunk music die ganze Zeit gelockt ist. Das UNLOCK_ON_EOS macht dies laut meinen Tests nicht.

    Es stellt sich jetzt die Frage, wie ich denn mitbekomme, wenn das Abspielen der Muskdaten fertig ist. Hierzu könnte man meiner Meinung nach die Möglichkeit der Notifikation innerhalb der Musikdaten benutzen:

    Code
    /*
     ; GE_SEND_NOTIFICATION causes the stream to send
     ; a given message to a given object.  The message
     ; will be placed at the end of the queue.
     ;
     ; USAGE ::  GE_SEND_NOTIFICATION <word message>
     ;               <object handle> <object chunk> 
    */

    Das sieht dann so aus:

    Code
    @chunk word DemoSong[] = {
      SSE_CHANGE, 0, IP_LEAD_0, IT_STANDARD_TABLE,
    ...
      SSE_GENERAL, GE_SEND_NOTIFICATION, MSG_SND_STOP_SELF, 0, 0,
      SSE_GENERAL, GE_END_OF_SONG
    //  SSE_GENERAL, GE_SEND_NOTIFICATION, MSG_SND_STOP_SONG, OptrToHandle(process), OptrToChunk(process),
    //  SSE_GENERAL, GE_SEND_NOTIFICATION, MSG_SND_STOP_SELF, OptrToHandle(oself), OptrToChunk(oself),
    //  SSE_GENERAL, GE_SEND_NOTIFICATION, MSG_SND_STOP_SELF, OptrToHandle(@SoundControl), OptrToChunk(@SoundControl),
    };

    Leider kann ich in einem "statischen" Chunk die Werte für das Objekt nicht hinterlegen. Diese sind ja erst zur Laufzeit bekannt. Darum sind beide mit 0 angegeben und die Idee ist nun, dies zur Laufzeit zu patchen.

    Code
    e = LMemGetChunkSize(music);
    *(p_music + e - 4) = (word) OptrToHandle(@SoundControl);
    *(p_music + e - 3) = (word) OptrToChunk(@SoundControl);

    SoundControl ist ein generisches Objekt (MetaClass) und nur dafür gedacht, diese Meldung zu erhalten. Habe das kurz anprobiert, aber leider noch ohne Erfolg.

    Was denkt Ihr? Macht das Sinn? Seht Ihr andere Möglichkeiten?

  • Dass mein Test nicht funktionierte lag wohl daran, dass wieder einmal ein Wiederholungstäter am Werk ist. Chunks sind dword aligned...

    Wenn ich am Schluss der Musikdaten die "leere" Notifikation einfüge:

    Code
    SSE_GENERAL, GE_SEND_NOTIFICATION, 0, 0, 0,
    SSE_GENERAL, GE_END_OF_SONG

    Kann ich vor dem Abspielen die Message und das Objekt abfüllen:

    Das funktioniert sogar. In der Methode MSG_SND_STOP_SELF gebe ich dann den MemLock der Musikdaten frei. Auch auf das Stoppen der Musik bevor sie am Ende angekommen ist macht kein Problem. Klar, das nächste Level wäre wohl es mit einem Stream zu versuchen. So wie ich Streams verstehe, muss man da ja irgendeine Call-Backup-Methode zum Daten nachschieben haben? Und da weiss man, wann der Schluss da ist und kann den Lock lösen. Aber das ist was für die ferne Zukunft.

    Zu guter letzt:
    Was wäre der einfachste Weg, wenn ich die Message anstatt dem SoundControl-Objekt dem Prozess selbst senden möchte? Über GeodeGetProcessHandle? Nur mit process will er nicht...

    PS:
    Manchmal habe ich das Gefühl immer wieder das Gleiche zu Fragen :pinch:

    Edited once, last by bolle732 (October 1, 2024 at 4:50 PM).

  • Lieber Andreas,

    sorry, aber da ich mich nie so tief mit der Materie beschäftigt habe, muss ich jetzt aussteigen. Ich müsste mal schauen ob und wie ich das Problem end-of-song-erkennung in R-BASIC gelöst habe. SoundStreams habe ich noch nie gemacht.

    Unqualifizierte Kommentare:

    Vom Gefühl her würde ich keine MetaClaass für eigene Objekte ableiten, sondern bestenfalls GenClass. Eventuell sogar ein einfaches konkretes Objekt wie GenGlyph.

    UNLOCK_ON_EOS sollte eigentlich gehen. Die aufwändige Variante wäre, sich in den Code zu vertiefen ...

    Den Soundbuffer zu patchen, wegen dem Zielobjekt, fühlt sich nicht gut an, wäre aber wohl auch meine Lösung, da ich keine bessere Idee habe.

    Für den Process würde ich ConstructOptr(GeodeGetProcessHandle(), 0) versuchen. Das hatten wir schon mal irgendwo, glaube ich.

    if (*(p_music + e) == SSE_GENERAL && *(p_music + e + 1) == GE_SEND_NOTIFICATION)

    Die Abfrage ist evtl. etwas Quick&dirty. Solange es geht, ist es ok, aber es könnte theoretisch sein dass irgend ein Datenfeld (Tondauer, Tonhöhe ...) zufälliger Weise genau diese bytes enthält.

    Bin dahin erst mal
    Rainer

    Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

  • Hallo Rainer

    Den Soundbuffer zu patchen, wegen dem Zielobjekt, fühlt sich nicht gut an, wäre aber wohl auch meine Lösung, da ich keine bessere Idee habe.

    Ich habe die Doku mehrfach tiefergehend angeschaut und bin einfach auf keine andere Idee gekommen. Das UNLOCK_ON_EOS wäre auch mein Favorit. Aber meine Tests haben ergeben, dass der Lock bestehen bleibt. Und Weder in der Doku noch in den anderen Applikationen habe ich Hinweise gefunden. Und den Block einfach als fixed zu definieren will ich nicht. der kann am Schluss doch schnell 10KB oder so werden...

    Für den Process würde ich ConstructOptr(GeodeGetProcessHandle(), 0) versuchen. Das hatten wir schon mal irgendwo, glaube ich.

    Genau, den hatten wir schon ;) War mir nur unsicher, da in dem Fall nur der Handle gebraucht wird. Das heisst dann, der Prozess hat immer den Chunk 0, oder?

    Auf jeden Fall geht das nun auch über den Prozess.

    Die Abfrage ist evtl. etwas Quick&dirty. Solange es geht, ist es ok, aber es könnte theoretisch sein dass irgend ein Datenfeld (Tondauer, Tonhöhe ...) zufälliger Weise genau diese bytes enthält.

    Ja, das ist mir auch durch den Kopf. Dachte, ich nehme mal while zur Abwechslung. Mit for weiss ich eigentlich, dass es nicht weiter als 10 Bytes vom Ende sein kann.

    Am liebsten wäre es mir, wenn ich das definitive Ende des Chunks vom System bekommen könnte. Sowas wie length(optr MyChunk). Dann müsste man nicht suchen, sondern man kann gleich die richtige Position adressieren.

  • Könnte man eigentlich anstatt eines normalen Chunk ein ChunkArray nehmen? Von diesem kann man dann die Anzahl Elemente fragen und sollte somit das Ende direkt adressieren können.

    Also, anstatt @chunk word DemoSong[] = { einfach @chunkArray word DemoSong[] = {.

    Jetzt frage ich mich, ob das bezüglich Performance einen negativen Einfluss hat oder ob ich da sogar Gefahr laufe, dass die Reihenfolge im Speicher nicht garantiert ist...

  • Hm, ich glaube, bei einem ChunkArray sind die Elemente auch irgendwie aligned - das konnte man aber per hexdump (swat commando bytes) prüfen. Wenn es dword aligned ist, hast du ein Problem, wenn nicht, ist es eine interessante Idee. Der Performace-Verlust sollte minimal sein.

    Rainer

    Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.