Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

1

17.08.2003, 17:13

tbMusic und Abfrage von GetState

Hallo :huhu: ,
zur Zeit befasse ich mich ein klein wenig mit tbMusic, hab aber ein Problem mit dem Abspielen, bzw. eher mit dem Abfragen des zur Zeit laufenden Stücks.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
tbResult CIntro::Init()
{
    m_pMusic = new tbMusic;
    if(m_pMusic->Init("Data\\Aahh.mp3"))
    {
        // Fehler!
        TB_ERROR("Fehler beim Laden der Musik!", TB_ERROR);
    }
    m_pMusic->Play(FALSE);
    return TB_OK;
}

In der Init wird also das erste Musikstück geladen und abgespielt.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tbResult CIntro::Move(float fTime)
{
    m_pMusic->Process();
    if(m_pMusic->GetState() != State_Running)
    {
TB_INFO("Finished");
        if(m_pMusic->Init("Data\\Behh.mp3"))
        {
            // Fehler!
            TB_ERROR("Fehler beim Laden der Musik!", TB_ERROR);
        }
        m_pMusic->Play(FALSE);
    }
    return TB_OK;
}

Sobald das erste Musikstück am Ende ist, soll er das zweite laden und abspielen. Das tut er aber nie. Es tritt nie die Bedingung !State_Running ein, weil der Status nur bei den Funktionen Stop() oder Pause() anspringt, bzw. wenns nicht gestartet wurde. Gibt es überhaupt eine Möglichkeit von tbMusic her in Erfahrung zu bringen, ob das Stück noch spielt oder nicht? Oder schreit es hier nach einer kleinen Engine-Erweiterung? :ohoh:

Noch eine kleine Frage zur Init, sehe ich das richtig, dass man kein zweites mal Init aufrufen darf (so wie ich das oben gemacht habe), da es sonst zu Speicherverlust kommt? Man muss also immer erst
TB_SAFE_DELETE(m_pMusic);
und dann
m_pMusic = new tbMusic;
aufrufen, bevor man ein neues File einladen möchte (geht auch so, spielt das alte halt weiter, lustiger echo-Effekt ;D )? Warum ist da keine Prüfung drinn, die z.B. eine Unload-Funktion aufruft?

Thnx4Infos :opa:

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

17.08.2003, 22:08

Re: tbMusic und Abfrage von GetState

Zitat von »"Snorky"«

Gibt es überhaupt eine Möglichkeit von tbMusic her in Erfahrung zu bringen, ob das Stück noch spielt oder nicht?

Schau mal, wie tbMusic::Process das regelt. Es erkennt ja auch, wenn das Stück vorbei ist, damit es bei aktiviertem Looping wieder von vorne anfängt.

Zitat von »"Snorky"«

Noch eine kleine Frage zur Init, sehe ich das richtig, dass man kein zweites mal Init aufrufen darf (so wie ich das oben gemacht habe), da es sonst zu Speicherverlust kommt?

Ja.

Zitat von »"Snorky"«

Warum ist da keine Prüfung drinn, die z.B. eine Unload-Funktion aufruft?

Könnte man einbauen, aber wenn man sich dran hält, geht's auch ohne :)

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

3

17.08.2003, 23:47

Kleine Änderungen an tbMusic

Das mit tbMusic::Process() hab ich schon gesehen, hab nur gedacht es gäbe eine Funktion zum abprüfen, also das was eigentlich GetState() machen sollte. Wenn dem aber nicht so ist, dann füge ich sie hiermit selber ein ;D

Dazu wird einfach folgende inline-Funktion in die tbMusic.h eingefüt.

Quellcode

1
    inline BOOL             IsPlaying()                 {return m_bPlaying;}

Und wenn wir schon mal dabei sind auch eine Unload(), denn Programmierer sind die faulsten Menschen auf der Welt und jedesmal den Pointer freizugeben um ihn dann nächste Zeile wieder zu belegen sind mindestens 2 Zeilen zuviel ;) . Also kommt in die Header noch die Deklaration von Unload:

Quellcode

1
    tbResult        Unload();                               // Alles freigeben und zurücksetzen


Die Definition kommt dann in die tbMusic.cpp

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Alles freigeben und zurücksetzen
tbResult tbMusic::Unload()
{
    // Wiedergabe stoppen
    if(IsPlaying()) Stop();

    // Alle Schnittstellen freigeben
    TB_SAFE_RELEASE(m_pMediaControl);
    TB_SAFE_RELEASE(m_pMediaSeeking);
    TB_SAFE_RELEASE(m_pBasicAudio);
    TB_SAFE_RELEASE(m_pGraph);

    // Alles zurücksetzen
    ZeroMemory(this, sizeof(tbMusic));

    return TB_OK;
}

und kann dann auch aus dem Destruktor aufgerufen werden

Quellcode

1
2
3
4
5
// Destruktor der tbMusic-Klasse
tbMusic::~tbMusic()
{
    Unload();
}


Um sich die besagten 2 überflüssigen Zeilen dann zu sparen muss die Unload natürlich auch in der Init() aufgerufen werden

Quellcode

1
2
3
4
5
6
7
8
9
10
11
tbResult tbMusic::Init(char* pcFilename)
{
    // Alles zurücksetzen
    Unload();

    HRESULT     hResult;
    LONGLONG    llDuration;
    WCHAR       awcFilename[256];

    // Graph erstellen
...


Damit m_bPlaying auch wirklich den aktuellen Status besitzt muss die Variable in Process auch berücksichtigt werden und auf FALSE gesetzt werden, wenn das Stück zuende ist.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Verarbeitet die Musik
tbResult tbMusic::Process()
{
    if(m_bPlaying)
    {
        if(GetCurrentPosition() >= (int)(m_dwDuration))
        {
            if(m_bLooping)
            {
                // Wenn Looping eingeschaltet ist und die Musik zu 
                // Ende ist, dann spielen wir sie erneut ab.
                return Play(TRUE);
            }
            else
            {
                // Ansonsten wird nicht mehr gespielt
                m_bPlaying = FALSE;
                return TB_OK;
            }
        }
    }

    return TB_OK;
}



So das wärs, damit kann man in der Render-Methode z.B. mit

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
tbResult CIntro::Move(float fTime)
{
    m_pMusic->Process();
    if(!m_pMusic->IsPlaying())
    {
        if(m_pMusic->Init(GetRandomMusicFile()))
        {
            // Fehler!
            TB_ERROR("Fehler beim Laden der Musik!", TB_ERROR);
        }
        m_pMusic->Play(FALSE);
    }
    return TB_OK;
}

immer überprüfen, ob der Sound noch spielt. Wenn nicht, kann man hier per Zufallsgenerator einen anderen aus einer Liste aussuchen und abspielen. So kommt auch ein bischen Abwechsung in den Hintergrund.
:jumpy: :dance: :jumpy:

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

18.08.2003, 00:48

Gut, dass es Dich gibt :)
Ich ändere es und werde wohl auch bei allen Klassen die "Unload"-Methode einführen. Wahrscheinlich werde ich sie aber "UnInit" oder so nennen.

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

5

18.08.2003, 11:04

Speicherfreigabe

Zitat

Gut, dass es Dich gibt
Hach danke, jetzt hat mein Ego endlich wieder einen Auftrieb erhalten ;D

Ich habe Unload wegen der Anlehnung an Deinen Spielen genommen, UnInit ist hier aber sicher Vernünftiger.
Was den Texturmanager angeht, da hab ich mitlerweile das Makro TB_SAFE_MEMFREE bewußt wahrgenommen :wirbel:
Anstatt in DeleteAllTextures

Quellcode

1
2
    tbMemFree(m_pTextureList);
    m_pTextureList = NULL;
aufzurufen, sollte man auch das verwenden, was geplant war

Quellcode

1
 TB_SAFE_MEMFREE(m_pTextureList); 
und nicht versuchen die tbMemFree umzubiegen :-D

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

6

18.08.2003, 12:39

So, ich habe mich jetzt für den Namen "Exit" entschieden - ebenfalls in Anlehnung an andere Dinge (tbInit <-> tbExit...). Es ist auch schon in allen Klassen eingebaut und im Buch schon verändert. Das ging schnell, und alles ist jetzt viel sicherer :)

Vorher gab es nämlich ein paar Destruktoren, die einen Fehler verursacht hätten, wenn das Objekt noch nicht mit Init initialisiert gewesen wäre. Jetzt musste ich diese Lücken schließen, da Exit ja sowieso bei jedem Init-Aufruf mit im Spiel ist.

Snorky

Frischling

  • »Snorky« ist der Autor dieses Themas

Beiträge: 34

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

7

18.08.2003, 13:00

Zitat

Auuusgezeichnet
:)
Gibt es den neuen Engine-Code auch zum downloaden? Da sind sicher im Lauf der Zeit noch andere Fehler behoben worden oder Teile erweitert, die ich vielleicht nicht mitbekommen habe. Wäre echt cool, wenn der neueste Stand irgendwo irgendwann irgendwie erhältlich wäre. Vielleicht als Zip-Update bei den Nachträgen oder so. :-)

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

8

18.08.2003, 13:07

Ja, wird es ganz sicher geben.

Werbeanzeige