Klasse in Konstruktor einer anderen Klasse definieren



  • Hallo zusammen,
    ich stelle mich mal kurz vor:
    Mein Name ist Stefan, ich habe E-Technik studiert und einiges an Programmierskills schon wieder vergessen 😉 Ich würde mich daher als Anfänger einstufen. Ich kann gut Zusammenhänge zur HW herstellen aber die Syntax und besonders die Programmierpraxis und Erfahrung fehlen mir.
    Ach ja, mein Arbeitsplatz ist xcode...
    Mein aktuelles Projekt ist ein VST Plugin, in dem ich Laufzeitunterschiede zwischen zwei Audiosignalen ausgleichen will.
    Kurzer Abriss zum VST: Es handelt sich um eine von Steinberg(c) entwickelte Umgebung, die es ermöglicht, Instrumente und Effekte für Audio einzubinden. Dazu gibt es eine Host-SW und halt das jeweilige PlugIn. Die Anbindung der Audio Hardware geschieht Host-seitig, daher ist die Entwicklung eines PlugIns vergleichsweise einfach. Die Audiodaten werden beim Aufruf der "Effekt-Funktion" als Pointer auf ein Feld übergeben und direkt bearbeitet = ersetzt.

    Okay, das sollte genügen.
    Aktuell hänge ich an einer Stelle, die ich mal wie folgt beschreiben möchte.

    Beim Laden des PlugIns wird ein Konstruktor aufgerufen, der die Effektklasse "konstruiert".

    ADelay::ADelay (audioMasterCallback audioMaster)
    	: AudioEffectX (audioMaster, kNumPrograms, kNumParams)
    

    Der Callback-Kram muss mich dabei erstmal nicht interessieren.
    Dort werden auch die Variablen initialisiert, die im späteren, eigentlichen Effektprozess relevant sind.
    Der Prozess lautet

    void ADelay::processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames)
    

    und gehört ebenfalls zur ADelay Klasse. (Findige Leute werden hier feststellen, dass ich das von Steinberg mitgelieferte Beispiel editiere. Hat den Vorteil, dass eine lauffähige Basis vorliegt)
    Nun zu meinem Problem:
    Ich möchte eine Operation aus der Signalverarbeitung durchführen (Kreuzkorrelation) und den Ergebnisvektor speichern.
    Die processReplacing Funktion wird vom Host aufgerufen und editiert ca. 10ms Signal und wird danach wieder verlassen. Das bedeutet, dass ja meine Ergebnisse aus dieser Klasse erstmal weg sind.
    Also war meine Idee, zunächst im Konstruktor der ADelay den (noch parameterlosen) Konstruktor meiner Xcorr Klasse aufzurufen:

    Xcorr Correlation;
    

    Nun möchte ich den Ergebnisvektor mittels einer Memberfunktion

    int Xcorr::createResultVector(int size)
    {
        resultVector = new float[2*size];       // type resultVector = float*
        *resultVector = {0};                    // initialisation
        sizeResultVector=sizeof(resultVector);
        return (sizeResultVector);
    }
    

    erstellen. Das kann ich aber erst in der processReplacing tun, da mir erst dort der Wert von size vorliegt.
    Hier mein Problem: Ich kann nicht innerhalb der processReplacing meinen Aufruf tätigen

    Correlation.createResultVector(sampleFrames);
    

    Es heißt use of undeclared identifier "Correlation"
    Ich gehe mal davon aus, dass es eine einfache Erklärung gibt 🙄 👍
    Besten Dank schonmal



  • β

    Stefatronik schrieb:

    Ich gehe mal davon aus, dass es eine einfache Erklärung gibt 🙄 👍
    Besten Dank schonmal

    Ich habe mir das gerade mal angeschaut: warum sprichst Du denn eigentlich noch von ADelay? Die Klasse müsstest Du doch komplett implementieren für Dein Vorhaben?!

    Wie Du allerdings dann Daten aus dem Plugin bekommst, und ob das überhaupt geht: keine Ahnung.

    Aber prinzipiell koennte das irgendwie so aussehen:

    #include <algorithm>
    #include <iterator>
    #include <utility>
    #include <vector>
    
    struct xcorr : public AudioEffectX{
    	// blablabla
    	void processReplacing (float**, float**, VstInt32);	
    private:
    	float compute(float, float) const; // Funktion z. Kreuzkorrelation...
    	std::vector<float> result;   // ...und deren Ergebnisse
    };
    
    void xcorr::processReplacing (float** inputs, float** outputs, VstInt32 n)
    {
    	using namespace std;
    	const float* first0 = inputs[0], *last0=inputs[0]+n;
    	const float* first1 = inputs[1], *last1=inputs[1]+n;
    
    	// f() ist this->compute()
    	const auto& f = bind(&xcorr::compute, this);
    	// Kreuzkorrelation berechnen und in result speichern
    	transform(first0, last0, first1, back_inserter(result), f);
    
    	//durchschleifen:
    	copy(first0, last0, outputs[0]);
    	copy(first1, last1, outputs[1]);
    }
    


  • Hi
    danke für deinen Beitrag, den ich leider erst heute gesehen habe.

    warum sprichst Du denn eigentlich noch von ADelay?

    Weil ich diese funktionierende Klasse erstmal nur anpassen möchte. Die Delay Funktion, die ich später nutzen möchte, ist ja bereits vorhanden und funktioniert.
    wenn ich dein Beispiel richtig verstehe, dann befinden sich alle Funktionen für die Kreuzkorrelation als Memberfunktionen innerhalb der Effektklasse (bei mir ADelay, bei dir xcorr). Ich wollte versuchen, die Kreuzkorrelation als eigene Klasse zu definieren, damit ich diese später leichter exportieren und in ein anderes Projekt einfügen kann.
    Ist diese Art der Aufteilung überhaupt möglich und macht die Vorgehensweise Sinn?



  • Stefatronik schrieb:

    wenn ich dein Beispiel richtig verstehe, dann befinden sich alle Funktionen für die Kreuzkorrelation als Memberfunktionen innerhalb der Effektklasse (bei mir ADelay, bei dir xcorr).

    Ich weiss ja nichteinmal, was eine Kreuzkorrelation ist - das Beispiel soll nur zeigen, wie Du in processReplacing() mit C++ sehr einfach eine unbekannte Menge von Daten speichern kannst. Und insbesondere, dass die manuelle Speicherverwaltung, die Du ansatzweise gepostet hast (Dein Xcorr::createResultVector() ) völlig in die Irre führt.
    Sieh meine Version von processReplacing() als subtilen Hinweis, dass Du Dich mit der C++-Standardbibliothek vertraut machen sollst! 🙂

    Stefatronik schrieb:

    Ich wollte versuchen, die Kreuzkorrelation als eigene Klasse zu definieren, damit ich diese später leichter exportieren und in ein anderes Projekt einfügen kann.
    Ist diese Art der Aufteilung überhaupt möglich und macht die Vorgehensweise Sinn?

    Klar, wenn zur Kreuzkorrelation mehr gehört als eine simple Funktion, die zwei floats nimmt und einen wieder ausspuckt, ist das lohnend.
    Ohne viel Schnickschnack hat das Plugin dann beispielsweise ein Xcorr member:

    // Deine Klasse zur Kreuzkorr.
    struct Xcorr{
        // bla bla bla
    };
    
    struct stefatronik_plugin : public AudioEffectX{
      // bla bla
      void xcorr::processReplacing (float** inputs, float** outputs, VstInt32 n)
      {
        //... mach was mit inputs, outputs und xc_;
      }
    private:
      Xcorr xc_; // hier ist sie wieder, die Kreuzkorr.
    };
    


  • Vielleicht sollte das Problem anders formulieren.
    Bitte zieht auch in Betracht, dass ich möglicherweise einen sehr grundlegenden Anfängerfehler mache, wie gesagt, Programmiererfahrung = wenig ^^

    Ich möchte im Konstruktor der Klasse "A" eine Instanz einer Klasse "kl" vom Typ "B" öffnen.
    Nun möchte ich im weiteren Verlauf aus einer Memberfunktion von "A" eine Memberfunktion aus "kl" aufrufen.
    Wie muss also dieser Aufruf aussehen?
    Ich hoffe, das war anschaulicher.



  • Stefatronik schrieb:

    Ich möchte im Konstruktor der Klasse "A" eine Instanz einer Klasse "kl" vom Typ "B" öffnen.

    Was bedeutet "öffnen" in diesem Zusammenhang?
    So?

    #include <iostream>
    #include <string>
    
    struct B{
      B(const std::string& s)
        : s_(s)
      {
      }
      void hello() const
      {
        std::cout << s_ << '\n';
      }
    private:
      std::string s_;
    };
    
    struct A{
      A()
        : kl("Hello World")
      {
      }
      void func() const
      {
        kl.hello();
      }
    private:
      B kl;
    };
    
    int main(){
      A a;
      a.func();
    }
    

    Ich empfehle Dir ein C++ Buch - das sind Grundlagen. Und ein Forum ist IMHO nicht der richtige Ort um Grundlagen zu lernen.


Anmelden zum Antworten