Mehrere Sounds gleichzeitig abspielen



  • Aloha 😉

    Ich bin gerade dabei einen Gehörbildungstrainer zu schreiben und bin auf ein dickes Problem gestoßen...

    Es ist elementar, dass ich mehrere Töne gleichzeitig abspielen können muss (z.B. bei der Intervallerkennung) - das klappt aber noch nich sooooooo toll...

    Ich benutze die irrKlang Bibliothek

    Ich hab für jeden Ton eine eigene Funktion bisher, die sehn sich alle ziemlich ähnlich, hiermal für den Ton C

    void spieleC() {
    
    	ISoundEngine* soundEngine = createIrrKlangDevice();
    
    	string soundFile = "C.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    

    damit kann ich halt jeden Ton einzeln abspielen wenn ich möchte. Jetzt möchte ich sie aber gleichzeitig erklingen lassen:

    int main() {
    
        spieleC();
        spieleE();
        spieleG();
    
        return 0;
    }
    

    die Variante hier klappt nicht (wäre auch zu schön gewesen....)
    Hier spielt er die Töne kurz nacheinander und nicht sortiert, wenn mich mein Gehör nicht ganz verarscht müsste er:

    G - C - E

    spielen... Soll halt aber C - E - G spielen...

    Kann mir da jemand weiterhelfen...? 😉



  • Erzeug' deine soundEngine mal am Anfang von main (und übergib den Pointer dann an die SpieleX-Funktion oder mach ihn global) und sag dann erst am Schluss soundEngine->Drop().

    PS: GNU Solfege kennst du schon?



  • Wenn ich die soundEngine in der main erstelle ändert das bisher gar nix^^ Töne kommen immer noch unsortiert und nacheinander raus...

    Bis eben kannte ich GNU Solfege nicht - jetzt schon^^



  • Schau mal hier rein: http://www.ambiera.com/irrklang/tutorial-helloworld.html
    Da machen die eigentlich genau das, was du willst.



  • Leider nein, da ich nicht das Problem habe, dass ich ne Backgroundmusik habe und dann dazu einen Sound spielen will, das kann mein Programm derzeit schon^^ 3 Sounds müssen zeitgleich gestartet werden, das ist das Problem^^



  • Also bei mir tut sowas hier genau das, was es soll, nämlich alle drei sounds gleichzeitig abspielen:

    #include <stdio.h>
    #include <irrKlang.h>
    #if defined(WIN32)
    #include <conio.h>
    #else
    #include "../common/conio.h"
    #endif
    using namespace irrklang;
    #pragma comment(lib, "irrKlang.lib")
    int main(int argc, const char** argv)
    {
    	ISoundEngine* engine = createIrrKlangDevice();
    	if (!engine)
    	{
    		printf("Could not startup engine\n");
    		return 0; // error starting up the engine
    	}
    
    	engine->play2D("1.wav");
    	engine->play2D("2.wav");
    	engine->play2D("3.wav");
    	do
    	{
    		printf("Press 'q' to quit.\n");
    	}
    	while(getch() != 'q');
    	engine->drop();
    	return 0;
    }
    

    Die benutzten Sound-Dateien hab ich dir auch mal hochgeladen: http://daiw.de/share/IrrKlangTest001.zip



  • Viele Dank für deine Mühe^^

    Ich habs jetzt auch noch mal mit einer einzigen Sounddatei getestet....

    Ich schätze es liegt stumpf daran, dass die Noten nicht zur selben Zeit starten, also die Sounddatei selbst hat bei der Aufnahme wohl irgendwie noch 0,00x Sekunden leere Aufnahme davor...

    Immerhin weiß ich jetzt auf jeden Fall, wie ich Sounds gleichzeitig abspielen können MÜSSTE 😃 😉

    Vielen Dank 😉

    Edit:

    wenn ich

    spieleA();
        spieleA();
        spieleA();
        spieleA();
    

    ausführe, wobei spieleA() so aussieht:

    void spieleA() {
        ISoundEngine* soundEngine = createIrrKlangDevice();
    
        string soundFile = "A.mp3";
    
        soundEngine->play2D(soundFile.c_str());
    }
    

    dann sollte er die Töne doch gleichzeitig abspielen und es müsste nur 1 Ton zu hören sein... Liegt wohl doch nicht an der Sounddatei...Wenn ich das wie oben ausführe höre ich, dass er den Ton mind. 2x ganz schnell HINTEREINANDER abspielt... Det is doof... Weiß jemand, woran das liegt...? 😞



  • Ja. Hör auf, für jeden Ton einzelnen mit createIrrKlangDevice eine neue Instanz von ISoundEngine anzufordern, sondern benutz einfach immer die selbe, nämlich eine die du beim Programmstart einmal erzeugst. Beispielsweise so:

    #include <stdio.h>
    #include <irrKlang.h>
    #if defined(WIN32)
    #include <conio.h>
    #else
    #include "../common/conio.h"
    #endif
    using namespace irrklang;
    #pragma comment(lib, "irrKlang.lib")
    ISoundEngine* engine(0); // Globale SoundEngine.
    void SpieleA()
    {
        engine->play2D("1.wav");
    }
    void SpieleB()
    {
        engine->play2D("2.wav");
    }
    void SpieleC()
    {
        engine->play2D("3.wav");
    }
    int main(int argc, const char** argv)
    {
        engine = createIrrKlangDevice(); // Engine beim Programmstart erzeugen.
        if (!engine)
        {
            printf("Could not startup engine\n");
            return 0; // error starting up the engine
        }
        SpieleA();
        SpieleB();
        SpieleC();
        do
        {
            printf("Press 'q' to quit.\n");
        }
        while(getch() != 'q');
        engine->drop(); // Engine beim Programmende droppen.
        return 0;
    }
    


  • class MySoundEffect
    {
    public:
        MySoundEffect(ISoundEngine* engine)
          : m_engine(engine)
        {}
    
        virtual ~MySoundEffect()
        {
          m_engine->Drop();
        }
    
       void play()
       {
          m_engine->Play("1.wav");
          m_engine->Play("2.wav");
          m_engine->Play("3.wav");
       }
    
    private:
       ISoundEngine* m_engine;
    };
    
    int main(int argc, const char** argv)
    {
        ISoundEngine* engine = createIrrKlangDevice(); // Engine beim Programmstart erzeugen.
        if (!engine)
        {
            printf("Could not startup engine\n");
            return 0; // error starting up the engine
        }
        MySoundEffect effect(engine);
        effect->Play();
        do
        {
            printf("Press 'q' to quit.\n");
        }
        while(getch() != 'q');
        engine->drop(); // Engine beim Programmende droppen.
        return 0;
    }
    

    Du brauchst keine globale.
    ISoundEngine hat einen Referenzzähler.

    edit
    Oder auch:

    class MySoundEffect
    {
    public:
        MySoundEffect()
          : m_engine(createIrrKlangDevice())
        {}
    
        virtual ~MySoundEffect()
        {
          m_engine->Drop();
        }
    
       void play()
       {
          m_engine->Play("1.wav");
          m_engine->Play("2.wav");
          m_engine->Play("3.wav");
       }
    
    private:
       ISoundEngine* m_engine;
    };
    
    int main(int argc, const char** argv)
    {
        MySoundEffect effect();
        effect->Play();
        do
        {
            printf("Press 'q' to quit.\n");
        }
        while(getch() != 'q');
        return 0;
    }
    


  • Mal abgesehen davon, dass es in den Zeilen 15 bis 17 "engine->play2D(...);" heissen muss und in Zeile 33 "effect.play();": Wo nutzt du da irgendwas referenzzählermäßiges?

    Edit: Mir ist schon klar, dass der Enginepointer nicht global sein muss. 😉
    Ich wollte halt nah am dem bleiben, was Zel2491 da macht, weil er offensichtlich nocht nicht so erfahren im Lesen von C++-Code ist. Deshalb wollte ich dann auch nicht mit sowas verwirren:

    void SpieleA(ISoundEngine& engine)
    {
        engine.play2D("1.wav");
    }
    ...
    ISoundEngine* engine = createIrrKlangDevice();
    SpieleA(*engine);
    

    In nem richtigen Programm würde ich das aber vermutlich auch irgendwie klassenmäßig kapseln, keine Sorge. 🙂



  • Ja sorry für den kleinen Fehler, ich hasse es im Browser code zu tippen hehe.
    Das macht irrKlang automatisch. Amberria nutzt für irrLicht und irrKlang überall Referenzzählungen für die Pointer. Wenn ich mich jetzt nicht komplett täusche...

    Auch wenn du 10x createSoundDevice() aufrufst, du kriegst iirc immer den selben unterliegenden Zeiger.



  • Ah ok. Aber du hast das in deinem Beispiel ja auch nicht benutzt. Habs mal getestet, geht:

    #include <stdio.h>
    #include <irrKlang.h>
    #if defined(WIN32)
    #include <conio.h>
    #else
    #include "../common/conio.h"
    #endif
    using namespace irrklang;
    #pragma comment(lib, "irrKlang.lib")
    int main(int argc, const char** argv)
    {
        ISoundEngine* engine(0);
        engine = createIrrKlangDevice();
        engine->play2D("1.wav");
        engine = createIrrKlangDevice();
        engine->play2D("2.wav");
        engine = createIrrKlangDevice();
        engine->play2D("3.wav");
        do
        {
            printf("Press 'q' to quit.\n");
        }
        while(getch() != 'q');
        engine->drop(); // Engine beim Programmende droppen.
        return 0;
    }
    

    @Zel2491: Poste doch mal deinen kompletten Code als Minimalbeispiel. Vielleicht kann man dann erkennen, warum es bei dir nicht funktioniert. Beendest du dein Programm vielleicht sofort nachdem du angefangen hast, die sounds abzuspielen?



  • Meine Klassen:

    Noten.cpp

    #include "Noten.h"
    
    ISoundEngine* soundEngine;
    
    void spieleC(ISoundEngine* soundEngine) {
    
    	string soundFile = "C.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    
    void spieleCisDes(ISoundEngine* soundEngine) {
    
    	string soundFile = "CisDes.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleD(ISoundEngine* soundEngine) {
    
    	string soundFile = "D.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleDisEis(ISoundEngine* soundEngine) {
    
    	string soundFile = "DisEis.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleE(ISoundEngine* soundEngine) {
    
    	string soundFile = "E.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleF(ISoundEngine* soundEngine) {
    
    	string soundFile = "F.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleFisGes(ISoundEngine* soundEngine) {
    
    	string soundFile = "FisGes.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleG(ISoundEngine* soundEngine) {
    
    	string soundFile = "G.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleGisAs(ISoundEngine* soundEngine) {
    
    	string soundFile = "GisAs.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleA(ISoundEngine* soundEngine) {
    
    	string soundFile = "A.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    }
    void spieleAisB(ISoundEngine* soundEngine) {
    
    	string soundFile = "AisB.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    
    }
    void spieleB(ISoundEngine* soundEngine) {
    
    	string soundFile = "B.mp3";
    
    	soundEngine->play2D(soundFile.c_str());
    }
    

    Noten.h

    #include "stdafx.h"
    #include <iostream>
    #include <string>
    #include <windows.h>
    #include "include/irrKlang.h"
    
    #pragma comment(lib, "irrklang.lib")
    
    using namespace std;
    using namespace irrklang;
    
    #pragma once
    
    void spieleC(ISoundEngine*);
    void spieleCisDes(ISoundEngine*);
    void spieleD(ISoundEngine*);
    void spieleDisEis(ISoundEngine*);
    void spieleE(ISoundEngine*);
    void spieleF(ISoundEngine*);
    void spieleFisGes(ISoundEngine*);
    void spieleG(ISoundEngine*);
    void spieleGisAs(ISoundEngine*);
    void spieleA(ISoundEngine*);
    void spieleAisB(ISoundEngine*);
    void spieleB(ISoundEngine*);
    

    Der Aufruf erfolgt dann in meinem GUI, ich benutze Windows-Form fürs GUI und ich rufe die Funktionen (zu Testzwecken) beim Button-Klick auf:

    private: System::Void C_Click(System::Object^  sender, System::EventArgs^  e) {
    
    				 ISoundEngine* soundEngine = createIrrKlangDevice();
    
    				 spieleA(soundEngine);
    				 spieleCisDes(soundEngine);
    				 spieleE(soundEngine);
    
    			 }
    

    Nach der Variante klappts jedenfalls nicht^^

    Ich probier das jetzt nochmal, dass ich die Notenklasse nochmal umschreibe...

    Edit:

    Kann bitte jemand das mal mit diesen Sounddateien testen? Ich bin mir irgendwie nicht zu 100% sicher, dass es NICHT an den Sounddateien liegt...

    http://www.file-upload.net/download-4595195/C.mp3.html
    http://www.file-upload.net/download-4595207/E.mp3.html
    http://www.file-upload.net/download-4595210/G.mp3.html



  • Ein compilierbares und ausführbares Minimalbeispiel ist das noch nicht. Sowas wie eine stdafx.h habe ich nicht, also hab ich die Zeile einfach mal rausgenommen. Eine int main() oder sowas hast du auch nicht mitgeliefert, also hab ich den code aus deinem event-Handler mal in eine reinkopiert. Allerdings musste ich ihn noch ändern, weil du die mp3s für einen C-Dur-Akkord hochgeladen hast, dein Code allerdings versucht, A-Dur zu spielen. So konnte ich es dann ans Laufen bringen:

    // main.cpp
    #include <stdio.h>
    #include <conio.h>
    #include "Noten.h"
    using namespace irrklang;
    int main(int argc, const char** argv)
    {
    	ISoundEngine* soundEngine = createIrrKlangDevice();           
    	spieleC(soundEngine);
    	spieleE(soundEngine);
    	spieleG(soundEngine);
    	do
    	{
    		printf("Press 'q' to quit.\n");
    	}
    	while(getch() != 'q');
    	soundEngine->drop();
    	return 0;
    }
    
    // Noten.h
    #ifndef NOTEN_H_
    #define NOTEN_H_
    #include <irrKlang.h>
    void spieleC(irrklang::ISoundEngine*);
    void spieleE(irrklang::ISoundEngine*);
    void spieleG(irrklang::ISoundEngine*);
    #endif /* NOTEN_H_ */
    
    // Noten.cpp
    #include "Noten.h"
    #include <string>
    #pragma comment(lib, "irrklang.lib")
    using namespace irrklang;
    using namespace std;
    void spieleC(ISoundEngine* soundEngine) {
        string soundFile = "C.mp3";
        soundEngine->play2D(soundFile.c_str());
    }
    void spieleE(ISoundEngine* soundEngine) {
        string soundFile = "E.mp3";
        soundEngine->play2D(soundFile.c_str());
    }
    void spieleG(ISoundEngine* soundEngine) {
        string soundFile = "G.mp3";
        soundEngine->play2D(soundFile.c_str());
    }
    

    Ich wollte nicht zu viel ändern, aber ein paar Sachen mussten einfach sein.
    - Benutze keine using-Direktiven in Header-Dateien. Damit verschmutzt du nur den globalen Namensraum der includierenden Cpps. Wenn die using sagen wollen, sollen sie das selbst tun.
    - Die Deklaration des Soundengine-Pointers in der Noten.cpp war überflüssig. Du übergibst ja eh einen als Parameter.
    - Die Funktionen, die für das Minimalbeispiel nicht gebraucht werden, hab ich mal rausgenommen, damit es übersichtlicher wird.
    So, das Ganze funktioniert bei mir einwandfrei. Alle drei Samples werden gleichzeitig abgespielt. Komisch hört sich das ganze trotzdem an. Hör mal einzeln in deine Dateien rein. Eine hat einen komischen Zusatzton (Übersteuerung?). Eine andere hat am Anfang etwas Stille.
    Versuch mal, ob du das Minimalbeispiel bei dir ans Laufen bekommst. Wenn bei dir trotzdem irgendwas nicht geht, versuch das Problem auf das nötigste zu reduzieren und dann so zu posten, dass wir das hier einfach bei uns nachstellen können. Siehe: http://www.c-plusplus.net/forum/304133


Anmelden zum Antworten