Tastendruck bei Audiosignal simulieren



  • Durchgängig anhören und auswerten. Dann ist die Latenz fast gleich deiner von dir festgelegten Mindestdauer zur Erkennung des Signals



  • Genau da liegt ja mein Problem. Wie kann ich gleichzeitig abhören und auswerten? Bin leider nicht mehr ganz so fit. Ich würde das ganze gerne in C++ realisieren.



  • Was ist mit Midi?
    Wenn du Midi benutzen kannst/möchtest, dann würde ich das an deiner Stelle mit Pure Data machen (oder Max/MSP, falls du das hast).
    (Leider kann man mit Pure Data afaik keine Tastendrücke simulieren)



  • Die geringste Latenz bekommt man unter Windows (und wohl auch anderen Systemen) angeblich mit ASIO hin. Damit hab' ich allerdings noch nie 'was gemacht, daher kann ich da auch keine Tips geben.

    Mit DirectSound ist es allerdings "relativ" einfach: du erzeugst einen IDirectSoundCaptureBuffer, und startest ihn.
    Dann fragst du periodisch (in möglicht kurzen Abständen) die "read position" ab.
    Bis zu dieser liegen aufgenommene Audio-Daten vor.
    Dabei merkst du dir immer die letzte "read position" die du bekommen hast. Die Daten die zwischen der letzten "read position" und der aktuellen liegen, sind neue Audio-Daten. Die nimmst du, und stopfst sie in deine "Signal-Detection" Funktion.

    Ein DirectSound Capture Buffer ist ein Ringpuffer, d.h. irgendwann springt die "read position" wieder zum Anfang zurück. Dann hast du eine letzte "read position" die nahe dem Ende des Puffers ist, und eine aktuelle die nahe dem Anfang ist. In dem Fall liegen die Daten von der letzten "read position" bis zum Ende des Puffers, und vom Anfang des Puffers bis zur aktuellen "read position".

    Was die "Signal-Detection" Funktion angeht: da könnte man z.B. ganz einfach einen Hochpassfilter verwenden, von dem was da rauskommt pro Sample den Absolutwert nehmen, und das ganze dann durch einen Tiefpass jagen. Den Ausgangswert des Tiefpass' schickst du dann noch durch einen Komparator mit Hysterese (Schmitt Trigger). Der Ausgang dieses Schalters ist dein Ergebnis.

    Pseudocode:

    main()
    {
        AudioCaptureThing capture;
        SignalProcessorThing leftProcessor;
        SignalProcessorThing rightProcessor;
    
        while (!IsExitCondition())
        {
            Sleep(aFewMilliseconds);
    
            StereoAudioData newAudioData = capture.GetNewData();
    
            bool left = leftProcessor.Process(GetLeftChannel(newAudioData));
            bool right = rightProcessor.Process(GetRightChannel(newAudioData));
    
            if (left && right)
                ; // no nothing
            else if (left)
                SwitchToPreviousPreset();
            else if (right)
                SwitchToNextPreset();
        }
    }
    
    bool SignalProcessorThing::Process(MonoAudioData data)
    {
        bool raisingEdgeDetected = false;
    
        for each (sample in data)
        {
            Sample s = m_highpass.Push(sample);
            s = abs(s);
            s = m_lowpass.Push(s);
    
            bool oldTriggerState = m_triggerState;
            if (s > m_activationThreshold)
                m_triggerState = true;
            else if (s < m_deactivationThreshold)
                m_triggerState = false;
    
            if (oldTriggerState == false && m_triggerState == true)
                raisingEdgeDetected = true;
        }
    
        return raisingEdgeDetected;
    }
    


  • @Hyde++
    Vor MIDI scheu ich mich im Moment, da ein einfaches 2 Taster Pedal schon an die 100€ kostet. Ein 2 Taster Pedal mit Klinke kostet dagegen 12€ und außerdem hab ich davon noch eins rumliegen.

    @hustbaer
    Danke schonmal für den Pseudocode. Man, da hab ich mir ja was vorgenommen. Da muss ich mich erstmal in DirectSound und generell in die Verarbeitung von Audiodaten einarbeiten. Gibt's da nicht einen einfacheren Weg bzw. eine einfachere API?



  • S1ckness schrieb:

    @Hyde++
    Vor MIDI scheu ich mich im Moment, da ein einfaches 2 Taster Pedal schon an die 100€ kostet. Ein 2 Taster Pedal mit Klinke kostet dagegen 12€ und außerdem hab ich davon noch eins rumliegen.

    Das hast du falsch verstanden (womöglich habe ich mich nicht klar ausgedrückt).
    Ich meinte, ob du intern Midi nutzen kannst, dann könntest du weiterhin dein Pedal benutzen, du würdest auch wie gehabt Audio auslesen, nur eben keine Tastendrücke simulieren, sondern Midi-Noten, oder Controller-Daten, wie du möchtest.

    Mit Pure Data ist das wirklich sehr schnell gemacht, falls du dich damit nicht auskennst, kann ich dir auch was schicken, du müsstest nat. Pure Data installieren (das ist frei).



  • Ja, da hab ich dich wohl falsch verstanden. Intern kann ich alles nutzen, was ich möchte. Ich brauch das Porgramm in erster Linie ja nur zum Heimgebrauch für ein paar Auftritte. Wenn du mir da was schicken könntest wäre nett.



  • So, ich möchte meinen alten Thread nochmal hervorholen, da ich immernoch beim gleichen Problem hänge.
    Ich konnte dank hyde++ mein Vorhaben zunächst mit PureData realisieren. Nach einigen Anpassungen musste ich dann aber feststellen, dass ich eine Latenz von 250ms "einstellen" muss, da es sonst zum mehrfachen Auslösen kommt.

    Ich möchte das ganze nun mit C++ realisieren um zum einen meine Kentnisse zu Schulen und zum anderen das ganze dann zu verbessern. Zur Signalerkennung möchte ich einen Schmitt-Trigger mit RC-Glied verwenden. Dabei liegt auch nicht mein Problem. Vielmehr würde ich gerne wissen wie das ganze mit den Buffern geht, sodass ich nahezu in "Echtzeit" agieren kann. Hab ich das richtig verstanden, dass ich z.B. 5ms aufnehme, die dann bearbeite, dann wieder 5ms aufnehme, wieder bearbeite, usw.? Muss ich hier mit Threads arbeiten, um "gleichzeitig" Aufzunehmen und Auszuwerten?

    Danke,
    S1ckness.



  • Du brauchst keine Threads.
    Du kannst einen Input-Puffer machen, den kannst du im Prinzip ruhig recht gross anlegen, sagen wir 1 Sekunde.
    Dann machst du 5ms "Sleep", und dann guckst du was im Puffer dazugekommen ist.
    Den neu hinzugekommenen Teil verarbeitest du dann.
    Und dann wieder Sleep.

    Siehe mein Beispiel-Code.

    Die Latenz bestimmt sich dann durch die Soundkarte (bzw. deren Treiber) und die Zeit die du "Sleep" machst.
    Die Sleep-Zeit kannst du problemlos in die Grössenordnung von 5ms bringen. Was die Soundkarte macht wird man sehen. Trau' ich mich nicht abschätzen.



  • Gut, danke. Dann werde ich mich jetzt mal in DirectSound einarbeiten. Kannst du mir da irgendwas empfehlen?



  • DirectSound ist nicht speziell schwer. Gibt einige Tutorials über Google zu finden wo du dir abgucken kannst wir man grundsätzlich mal zu einem DirectSound Objekt kommt, dann nen Puffer erzeugt etc.

    Wie der Puffer funktioniert solltest du dann versuchen selbst zu verstehen. Ist aber auch nicht schwer, und alles in der MSDN dokumentiert. Geht ja bloss darum dass das Ding eben ein zirkulärer Puffer ist, und was die beiden Cursor bedeuten die man abfragen kann. Wobei du zum Aufnehmen eigentlich nur einen brauchst, wenn du keine Timestamps mit Sample-Positionen assoziieren musst. Was du ja nicht musst.


Anmelden zum Antworten