heinetz: Javascript Fade Audio

Hallo Forum,

ich habe in einer REACT-Komponente einen Mute-Button für ein Video einbaut. Die Methode ist schlicht:

mute = muted => this.setState({ muted });

Nun soll der Sound nicht abrupt aus- und angehen, sondern ein- und ausgefaded werden.

Mein Versuch:

  mute = muted => {
    console.log('mute()');
    console.log(this.intro.current.volume);
    this.intro.current.volume = 0.5;
    const fadeAudio = setTimeout(() => {
      if (this.intro.current.volume >= 0) {
        console.log(this.intro.current.volume);
        this.intro.current.volume = this.intro.current.volume - 0.1;
        console.log(this.intro.current.volume);
      } else {
        clearTimeout(fadeAudio);
        this.setState({ muted });
      }
    }, 100);
  };

... scheint grundsätzlich zu funktionieren. Die Ausgabe sieht aber so aus:

0.5
0.4
0.30000000000000004
0.10000000000000003
2.7755575615628914e-17

Das Incrementieren scheint irgendwie fehlerhaft zu sein, was ich nicht verstehe. Wo ich mir auch nicht sicher bin, ist der Timeout. Wird der auf diese Weise sauber wieder entfernt?

danke für Tipps und

gruss, heinetz

  1. Hallo heinetz,

    ... scheint grundsätzlich zu funktionieren. Die Ausgabe sieht aber so aus:

    0.5
    0.4
    0.30000000000000004
    0.10000000000000003
    2.7755575615628914e-17

    Das Incrementieren scheint irgendwie fehlerhaft zu sein, was ich nicht verstehe.

    https://wiki.selfhtml.org/wiki/Programmiertechnik/Rechnerarithmetik

    Bis demnächst
    Matthias

    --
    Pantoffeltierchen haben keine Hobbys.
    ¯\_(ツ)_/¯
    1. @@Matthias Apsel

      0.5
      0.4
      0.30000000000000004
      0.10000000000000003
      2.7755575615628914e-17

      https://wiki.selfhtml.org/wiki/Programmiertechnik/Rechnerarithmetik

      Und darin wird der Sprung von 0.3 auf 0.1 erklärt?

      LLAP 🖖

      --
      „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
      „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

      —Marc-Uwe Kling
      1. Hallo Gunnar Bittersmann,

        Und darin wird der Sprung von 0.3 auf 0.1 erklärt?

        Die fehlende 0.2 ist ein cnp-Fehler 😀

        Bis demnächst
        Matthias

        --
        Pantoffeltierchen haben keine Hobbys.
        ¯\_(ツ)_/¯
  2. Lieber heinetz,

    0.5 0.4 0.30000000000000004 0.10000000000000003 2.7755575615628914e-17

    dazu hat Dir Matthias schon etwas verlinkt.

    Wo ich mir auch nicht sicher bin, ist der Timeout. Wird der auf diese Weise sauber wieder entfernt?

    Vielleicht, vielleicht auch nicht. Warum nicht so?

      mute = muted => {
    
        let volume = 50; // percentage
    
        const fadeAudio = () => {
    
          if (volume > 0) {
    
            volume -= 10; // -10%
    
            if (volume < 0) {
              volume = 0
            }
    
            this.intro.current.volume = volume / 100;
            setTimeout(fadeAudio, 100);
    
          } else {
    
            this.setState({ muted: muted });
          }
        };
    
        fadeAudio();
      };
    

    Liebe Grüße

    Felix Riesterer

    1. Hallo Felix,

      die "mach erstmal und zieh's dann gerade" Technik finde ich suboptimal, darum würde ich die Logik ein bisschen variieren:

          const fadeAudio = () => {
      
            if (volume > 10) {
      
               volume -= 10;
               this.intro.current.volume = volume / 100;
               // volume ist nun noch größer 0, neuen Aufruf buchen
               setTimeout(fadeAudio, 100);
      
            } else { 
      
               volume = 0;
               this.setState({ muted: muted });
      
            }
          };
      

      (edit: setState für muted nachgetragen)

      Dass man so einen Test weniger hat, ist ein netter (aber für Laufzeit irrelevanter) Nebeneffekt.

      Rolf

      --
      sumpsi - posui - clusi
      1. Lieber Rolf,

        die "mach erstmal und zieh's dann gerade" Technik finde ich suboptimal

        OK, das geht tatsächlich besser.

            const fadeAudio = () => {
        
              if (volume > 10) {
        
                 volume -= 10;
                 // volume ist nun noch größer 0, neuen Aufruf buchen
                 setTimeout(fadeAudio, 100);
        
              } else { 
        
                 volume = 0;
        
              }
              this.intro.current.volume = volume / 100;
            };
        

        Hier wird die Sache mit this.setState({ muted: muted }); nicht mehr berücksichtigt. Der Player ist also nicht mehr auf lautlos gestellt, was bei volume=0 aber sinnvoll ist.

        Dass man so einen Test weniger hat, ist ein netter (aber für Laufzeit irrelevanter) Nebeneffekt.

        Stimmt. Danke für die Optimierung.

        Liebe Grüße

        Felix Riesterer

        1. Hallo Felix,

          danke für den Hinweis auf mein Versäumnis. Das Muting hatte ich vergessen und habe es nachgetragen.

          Rolf

          --
          sumpsi - posui - clusi
          1. Lieber Rolf,

            Das Muting hatte ich vergessen und habe es nachgetragen.

            aha, jetzt sehe ich's auch. Aber der Player bekommt keine Lautstärke mit dem Wert 0 mehr. Mein Verbesserungsvorschlag:

                const fadeAudio = () => {
            
                  if (volume > 10) {
            
                     volume -= 10;
                     // volume ist nun noch größer 0, neuen Aufruf buchen
                     setTimeout(fadeAudio, 100);
            
                  } else { 
            
                     volume = 0;
                     this.setState({ muted: muted });
            
                  }
            
                  // Lautstärke tatsächlich verändern
                  this.intro.current.volume = volume / 100;
                };
            

            Liebe Grüße

            Felix Riesterer

  3. Hallo heinetz,

    sehe ich es richtig, dass Du die Zeile mit 0.200...004 zu kopieren vergessen hast?

    Die Prozenttechnik von Felix funktioniert deshalb besser, weil das IEEE 754 Format Zahlen ohne Nachkommastellen immer fehlerfrei darstellen kann (solange sie nicht zu groß sind).

    Wenn Du bei Fließkommazahlen bleibst, müsstest Du current.volume > 0.15 testen (dann ist es 0.2 oder mehr). Wenn dieser Test zutrifft, ziehst Du 0.1 ab. Andernfalls setzt Du es hart auf 0. Felix tut sich

    Deine Abfrage von current.volume >= 0 ist auf jeden Fall falsch, weil dadurch eine negative Lautstärke entsteht. Das ist sicherlich kein definierter Wert. Wenn die Audio-Library gutmütig ist, macht sie 0 draus. Aber es könnte auch eine Exception geworfen werden.

    Was deiner Funktion auch fehlt, ist der rekursive setTimeout Aufruf. Der gehört in den Teil, wo Du 0.1 abziehst, und es ist sinnvoll, wenn man die Funktion, die in setTimeout hinterlegt wird, namentlich ansprechbar ist. Wie das geht, zeigt Dir ebenfalls Felix.

    clearTimeout braucht man nur dann, wenn man einen gebuchten setTimeout stornieren will. Das ist aber nur ausnahmsweise der Fall. Mit setTimeout bucht man einen einmaligen Aufruf der angegebenen Funktion; für eine periodische Wiederholung nimmt man setInterval (was man mit clearInterval beenden muss) oder man bucht in der Funktion, die von setTimeout aufgerufen wird, den nächsten Aufruf.

    Rolf

    --
    sumpsi - posui - clusi