CSCore - Highperformance Audiobibliothek

    • Release
    • Open Source

    Es gibt 589 Antworten in diesem Thema. Der letzte Beitrag () ist von simpelSoft.

      Hej @thefiloe.

      Bei Dim source As IWaveSource = CodecFactory.Instance.GetCodec(FileName) scheint CSCore Probleme mit meinen MP3-Dateien zu haben. Ersetze ich das ganze durch Dim source As IWaveSource = New Codecs.MP3.DmoMp3Decoder(FileName) funktioniert es bei ca. 50% der Dateien, bei den anderen 50 spielt er nur komische Töne ab (wie z.B das schnelle düt-düt-düt-Stottern).

      Zudem habe ich ein Problem, wenn ich ein anderes Lied starte und schon eines läuft, stürzt er ohne Fehler in der StopPlayback() ab, nachdem er gute 3 Minuten hängte.

      Grüße
      Väinämö
      Ok, ist mir absolut neu. CSCore wurde mit tausenden von MP3s getestet. Die laufen stabil.
      1) Welche Version von CSCore hast du?
      2) Gesamter Source bitte
      3) Schick mir mal eine düt-düt-düt mp3


      Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
      1. Auf GitHub vorgestern das Repository als .zip geladen, in VS neu erstellt und dann die DLL in mein Projekt eingebunden.
      2. github.com/vainamov/hvla
      3. fdev.markab.uberspace.de/sync/Jetta_-_Operators.mp3

      Grüße
      Väinämö
      Danke, das ist ja ein ganz komisches Teil. Also der Mp3MediafoundationDecoder packts.
      Ändere mal temporär die CodecFactory-Klasse wie folgt ab.
      Ich schau mir das an.

      C#-Quellcode

      1. Register("mp3", new CodecFactoryEntry(s =>
      2. {
      3. //try
      4. //{
      5. // return new DmoMp3Decoder(s);
      6. //}
      7. //catch (Exception)
      8. //{
      9. //if (Mp3MediafoundationDecoder.IsSupported)
      10. return new Mp3MediafoundationDecoder(s);
      11. // throw;
      12. //}
      13. },
      14. "mp3", "mpeg3"));


      Edit Fehler behoben. Wie das passieren konnte ist mir ehrlich gesagt ein Rätzel. Habe vor Monaten eine alte Implementierung migriert, die auch entsprechend getestet. Irgendwann dann den Default Decoder in der CodecFactory umgestellt und hat immer funktioniert. Jetzt sehe ich das Problem, der Teil wo ID3-Tags übersprungen werden, ist raus geflogen.


      Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „thefiloe“ ()

      thefiloe schrieb:

      Ändere mal temporär die CodecFactory-Klasse wie folgt ab.

      Hab ich, soll ich jetzt auch wieder die CodecFactory nehmen? CSCore - Highperformance Audiobibliothek

      Edit: Abspielen der Datei geht wieder. Wenn ich aber eine andere Datei abspielen will und schon eine läuft, spielen beide gleichzeitig einen Ton im Loop und das Programm friert ein.
      Edit: Das Problem mit dem Einfrieren tritt auch beim Schließen auf, wodurch der Fehler in der StopPlayback() sein muss.

      Grüße
      Väinämö

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Vainamo V“ ()

      Das Problem ist schlichtweg ein Deadlock. Hab das deshalb in sämtlichen Beispielen entsprechend kommentiert.
      Die OnBlockRead Sub wird direkt im WasapiPlaybackThread gefeuert. Da synchron auf die GUI Invoken ist sehr gefährlich. Mach ein BeginInvoke draus, dass es asynchron ist und das Problem ist gegessen.
      Ansonsten hast du das Problem, dass du versuchst den PlaybackThread aus einem Thread aus zu beenden, auf welchen aus dem PlaybackThread gewartet wird.


      Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
      Hej @thefiloe.

      Mal was anderes, wie schaffe ich es festzustellen, ob ein Lied fertig abgespielt ist? Ich habe versucht im OnBlockRead-Event source.Position mit source.Length zu vergleichen, die waren aber nie exakt gleich.

      Und vielleicht auch @VincentTB, wie kann ich die Tags eines abgespielten Liedes bearbeiten? Bei mir meckert er dann immer rum, dass die Datei bereits von einem anderen Prozess verwendet wird.

      Grüße
      Väinämö

      Vainamo V schrieb:

      ​OnBlockRead-Event source.Position mit source.Length zu vergleichen, die waren aber nie exakt gleich.

      Exakt das wollte ich auch zuerst ausprobieren :D Du kannst einfach einen LoopStream erstellen, welcher das Event ​StreamFinished aufweist. Wenn du willst, kannst du auch hier mal einen Blick reinwerfen:
      github.com/Anapher/Hurricane/b…e/Engines/CSCoreEngine.cs

      Vainamo V schrieb:

      ​wie kann ich die Tags eines abgespielten Liedes bearbeiten?

      Es ist natürlich nicht möglich, die Tags von einem Lied zu bearbeiten, welches gerade abgespielt wird, weil dieses ja dann gerade verwendet wird. Ich würde einfach eine MessageBox anzeigen.
      Mfg
      Vincent

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VincentTB“ ()

      VincentTB schrieb:

      welches gerade abgespielt wird

      Ich weiß, aber bei fertig abgespielten (also lief schonmal, aber jetzt gerade nicht) klappt es auch nicht.

      Grüße
      Väinämö
      Magst du dir das mal ansehen?
      Ich habe auch noch ein Problem mit dem StreamFinished-Event. Er hört zwar auf zu spielen, mehr passiert aber nicht.

      Einmal hier klicken.

      Grüße
      Väinämö
      Huiuiui, du solltest in Erwähnung ziehen, den Code in mehrere Klassen aufzuspalten und mehr Absätze zu machen ;)
      Ich habe mir erstmal nur die StartPlayback Sub angeguckt, als erstes kann ich dir empfehlen, statt CType DirectCast zu verwenden.
      Außerdem sehe ich dort eine Menge von Objekten, die IDisposanble implementieren, aber von dir nicht groß beachtet werden. Dein Problem basiert wahrscheinlich darauf, dass du source nicht disponst (ist das ein Wort?), aber es fehlt auch sampleSource, Ls und source1. Ich weiß nicht, ob es immer 100 % notwendig ist, jedoch würde ich es dir nahelegen, diese Objekte in lokalen Variablen abzulegen und diese dann beim Stopp zu verwerfen. Siehe übrigens auch meine AudioEngine, ich würde dir empfehlen, auch dafür eine extra Klasse zu schreiben, sonst wird es sehr unübersichtlich.
      Mfg
      Vincent

      VincentTB schrieb:

      den Code in mehrere Klassen aufzuspalten und mehr Absätze zu machen

      Ist geplant, dieses Projekt hier ist auch nur gedacht, um mit CSCore son bisschen vertraut zu werden.

      VincentTB schrieb:

      statt CType DirectCast

      VincentTB schrieb:

      Menge von Objekten, die IDisposanble implementieren, aber von dir nicht groß beachtet werden

      Beschwer dich bei @thefiloe, ist sein Beispiel-Code aus dem Startpost :P .

      VincentTB schrieb:

      diese Objekte in lokalen Variablen abzulegen und diese dann beim Stopp zu verwerfen

      Mach ich ^^ .

      Edit: Das hat schonmal geholfen. Also Tags bearbeiten funktioniert jetzt wieder. Bleibt noch das Problem mit dem Ende des Liedes.

      Deine AudioEngine sehe ich mir bei der Gelegenheit auch gleich mal an.

      Grüße
      Väinämö

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Vainamo V“ ()

      Bzgl. "Ende des Liedes" wurde die Lösung bereits gesagt. Das Problem, weshalb du nicht Length und Position vergleichen kannst ist, dass es bei den MediaFoundationDecodern zu Abweichungen kommen kann. Das ist nichts was ich beeinflussen könnte, das liegt an den Windows Bibliotheken. Intern werden da wohl Länge etc. hochgerechnet, müssen jedoch nicht zu 100% hin kommen. Besser ist es da, sich auf das StreamFinished Event des LoopStreams (falls du diesen verbaut hast) oder das Stopped Event der jeweiligen SoundOut Komponente zu verlassen.


      Übrigens wurde vor einigen Tagen ein Beispiel zu der seit längerem gewünschten Waveform hinzugefügt (auf dem Bild ein 5.1 Surround Sound Track):


      Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
      Hi @thefiloe,

      hab da mal ne kurz Frage:
      Wenn ich aus einer IWaveSource mit Read(byte[], int, int) lese, dann gibt die Read-Methode einen int zurück. Wie auch in der MSDN-Doku, geh ich mal davon aus, dass hier das selbe System verwendet wird, wie bei allen .NET-Streams. Sprich alles größer gleich 1 bedeutet dass noch nict EOF bzw in dem Fall EOS(=End of Stream) ist. 0 hingegen meint EOF, respektive EOS.
      Hier mal den Code, den ich verwende:
      Spoiler anzeigen

      C#-Quellcode

      1. using CSCore;
      2. using CSCore.Streams;
      3. using CSCore.SoundIn;
      4. using CSCore.CoreAudioAPI;
      5. public class Test1
      6. {
      7. public Test1(MMDevice device)
      8. {
      9. ISoundIn soundIn = new WasapiCapture() { Device = device };
      10. soundIn.Initialize();
      11. SoundInSource soundInSource = new SoundInSource(soundIn);
      12. SingleBlockNotificationStream sbns = new SingleBlockNotificationStream(soundInSource.ToSampleSource());
      13. IWaveSource finalSource = sbns.ToWaveSource();
      14. byte[] data = new byte[finalSource.WaveFormat.BytesPerSecond / 2];
      15. soundInSource.DataAvailable += (s, e) =>
      16. {
      17. int read;
      18. while ((read = finalSource.Read(data, 0, data.Length)) > 0)
      19. {
      20. client.Send(data, data.Length, ep); //client ist ein UDP-Client
      21. }
      22. };
      23. soundIn.Start();
      24. }
      25. }


      Was mich jetz aber wundert ist folgendes:
      Wenn ich jetz aber mit der WriteableBufferingSource arbeite, dann hat die ja die Methode Write(byte[], int, int). Jedoch den Rückgabewert int.
      Hab mich halt zuerst gewundert, wieso int? Nachdem ich die MSDN-Doku durchgeblättert habe, hab ich feststellen müssten, dass die als Rückgabewert void haben(NetworkStream, StreamWriter).
      Hier mal mein Code:
      Spoiler anzeigen

      C#-Quellcode

      1. using CSCore;
      2. using CSCore.Streams;
      3. using CSCore.SoundOut;
      4. using CSCore.CoreAudioAPI;
      5. public class Test2
      6. {
      7. public Test2(MMDevice device)
      8. {
      9. ISoundOut soundOut = new WasapiOut(){ Device = device, Latency = 100 };
      10. WriteableBufferingSource wbs = new WriteableBufferingSource(new WaveFormat()) { FillWithZeros = true };
      11. soundOut.Initialize(wbs.ToSampleSource().ToWaveSource());
      12. soundOut.Play();
      13. byte[] data;
      14. do
      15. {
      16. data = client.Receive(ref ep); //client ist ein UDP-Client, ep ein IPEndPoint
      17. wbs.Write(data, 0, data.Length);
      18. } while (true);
      19. }
      20. }

      Für was hast du dann den Rückgabewert implementiert? Oder funktioniert der, entgegen MSDN als Anzeige ob EOF/EOS ist. Oder hat das was ganz anderes zu bedeuten.
      (Bin jetz seit gut ner dreiviertel Stunde dabei, den Code auf Github durchzusuchen...hab aber bisher nix brauchbares gefunden :( )

      Lg Radinator
      In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
      Moin,

      ich habe auch noch ein Problem. Ich versuche den Audio-Pegel eines bestimmten Programms auszulesen. Das Problem ist, dass bei nur 2 von den 5 Prozessen der DisplayName gesetzt ist und ich dadurch nicht weiß welches die richtige Session ist. Mache ich da was Falsch, oder gibt es noch einen anderen Weg?

      C#-Quellcode

      1. using (MMDeviceEnumerator mmde = new MMDeviceEnumerator())
      2. using (AudioSessionManager2 asm2 = AudioSessionManager2.FromMMDevice(mmde.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia)))
      3. asm2.GetSessionEnumerator().ToList().ForEach(x => System.Diagnostics.Debug.WriteLine(x.DisplayName));

      Hey!
      Ich habe heute nach einem Weg gesucht, einen Sound, der über die Soundkarte abgespielt wird, wieder zu erkennen. Da dachte ich mir, dass das ja eigentlich mit der FFT dieser Lib funktionieren sollte, oder? :)

      Mein Problem ist leider nur, dass ich noch nicht ganz verstehe, wie ich vorgehen muss, um einen Sound "wiedererkennen" zu können.
      Ich habe folgenden Beispielcode hier aus dem Thread gefunden:

      VB.NET-Quellcode

      1. Dim source As IWaveSource = CodecFactory.Instance.GetCodec("C:\Temp\test.mp3")
      2. Dim fftSource As FFTAggregator = New FFTAggregator(source, 1024) '1024 bands
      3. AddHandler fftSource.FFTCalculated, Sub(sender1 As Object, e1 As FFTCalculatedEventArgs)
      4. For i = 0 To e1.Data.Length / 2
      5. Dim value = e1.Data(CInt(i))
      6. Dim percentage = value.CalculateFFTPercentage()
      7. Next
      8. End Sub
      9. Dim read As Integer
      10. Dim buffer(fftSource.WaveFormat.BytesPerSecond) As Byte
      11. Do
      12. read = fftSource.Read(buffer, 0, buffer.Length)
      13. Loop While read > 0


      Ich verstehe dabei, dass eine .mp3 eingelesen wird (soll später direkt die Soundkarte sein, aber das ist ja erstmal irrelevant) und diese dann Fourier-Analysiert werden soll. Allerdings fehlt mir das Verständnis für den Rückgabewert.
      Zurückgegeben wird ja einfach eine Komplexe Zahl, die auch in einen "Prozentwert" umgerechnet wird. Dazu hätt ich ein paar Fragen:

      - Was genau sagt dieser Prozentwert denn aus? Prozent des Maximums oder soetwas?
      - Wie finde ich raus, zu welcher Frequenz (bzw. Frequenzband) der jeweilige Wert gehört? Kann man das irgendwie über das i berechnen?
      - Wie genau funktioniert das mit der mp3-Datei? Also im Prinzip gibt es ja zu jedem Zeitpunkt eine andere Frequenzverteilung. Wird das Calculated-Event dann einfach in bestimmten Abständen gefeuert oder wie? Wenn ja kann ich irgendwie den Zeitpunkt ermitteln, an dem eine bestimmte Frequenzverteilung vorliegt?

      Über alle Antworten würde ich mich wirklich sehr freuen! :)
      Danke schonmal..
      Versuch folgendes @Bluespide:

      C#-Quellcode

      1. ​using (MMDeviceEnumerator mmde = new MMDeviceEnumerator())
      2. using (AudioSessionManager2 asm2 = AudioSessionManager2.FromMMDevice(mmde.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia)))
      3. asm2.GetSessionEnumerator().Select(x => x.QueryInterface<AudioSessionControl2>()).ToList().ForEach(x => System.Diagnostics.Debug.WriteLine(x.Process == null ? String.Empty : session2.Process.MainWindowTitle));


      Du hast nicht nur einen Prozentwert, du hast mehrere Prozentwerte. Das Prinzip ist eigentlich ganz einfach. Du hast ein Signal das sich durch eine Folge von Samples abbilden lässt. Du nimmst, also n Samples von dem Signal. n ist dabei frei wählbar. Diese jagst du durch die FFT und bekommst Werte für jedes Frequenzband. Die Frage nach der Frequenz ist absolut berechtigt. Hier ist ein Beispiel das, das Frequenzband aufgrund einer Frequenz ermittelt: github.com/filoe/cscore/blob/m…icSpectrumProvider.cs#L23. Du kannst die Formel entsprechend umstellen um die Frequenzen, welche in einem Frequenzband beinhaltet sind zu ermitteln. Das Calculated Event wird in fixen Abständen gefeuert. Der Abstand richtet sich nach n, also der Anzahl der Frequenzbänder. Ich würde dabei jedoch eher auf den FftProvider setzen. Damit bist du flexibler. Schau dir einfach mal das WinformsVisualization Beispiel an.


      Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
      Jo danke, jetzt klappt es. Für TeamSpeak muss man noch die FileDescription abgreifen, da es kein aktives Fenster hat, wenn es minimiert ist. :)

      C#-Quellcode

      1. using (MMDeviceEnumerator mmde = new MMDeviceEnumerator()) {
      2. using (AudioSessionManager2 asm2 = AudioSessionManager2.FromMMDevice(mmde.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia))) {
      3. foreach (AudioSessionControl asc in asm2.GetSessionEnumerator()) {
      4. string name = asc.DisplayName;
      5. if (String.IsNullOrWhiteSpace(name)) {
      6. using (AudioSessionControl2 asc2 = asc.QueryInterface<AudioSessionControl2>()) {
      7. name = asc2.Process.MainWindowTitle;
      8. if (String.IsNullOrWhiteSpace(name)) {
      9. name = asc2.Process.MainModule.FileVersionInfo.FileDescription;
      10. }
      11. }
      12. }
      13. System.Diagnostics.Debug.WriteLine(name);
      14. }
      15. }
      16. }

      Hey,
      ich habe gerade mal als kleines Testprojekt angefangen, eine VoIP Anwendung zu schreiben. Das hat auch sehr gut funktioniert, ich sende die Daten über TCP. Jedoch werden dann die Raw-Daten gesendet, was natürlich zu Problemen führt, wenn die Übertragung länger dauert. NAudio bietet Codecs an: naudio.codeplex.com/SourceCont…kChatDemo/AcmChatCodec.cs
      Alle diese Codecs basieren auf einem ​AcmStream (Acm Codec). Ich habe bereits versucht, alles von NAudio auf CSCore zu übertragen, jedoch kam es da zu größeren Problemen, weil NAudio zwar ähnlich aufgebaut ist, einzelne Dinge jedoch etwas anders macht. Für mich wäre wichtig, dass für den Codec nicht noch etwas installiert werden muss. Was würdest du da empfehlen? Für mich ist eine geringe Latenz unproblematisch, jedoch würde ich gerne die Datenmengen etwas verkleinern. Würde man dafür zur Not auch einen schnellen Kompressionsalgorithmus wie zB QuickLZ nutzen? Mp3 ist ja ein Codec, der die Datenmenge erheblich verkleinert, kann man das irgendwie streamen?
      Mfg
      Vincent