Programm friert unerklärlich und zufällig ein

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    Programm friert unerklärlich und zufällig ein

    Guten Morgen :)

    Ich nehme mit der bass.dll den Sound einer externen Quelle auf und zwischenspeichere die Audiodaten erstmal in einem Byte-Array. Die Audiodaten werden dazu auch in einer WaveForm angezeigt.

    Ich habe mal alle Codestellen hier geschrieben, von denen ich denke, dass sie relavant sind.

    Aber wenn ich die Aufnahme stoppe, friert mein Programmm regelmässig, aber nicht immer ein. Die Klasse (ViewModel) wird so initialisiert:

    Edit: Weiss nicht warum, aber mittlerweile friert es jedes Mal ein...

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private IsRecording As Boolean
    2. Private HasRecorded As Boolean
    3. Private Peak(2) As Single
    4. Private PeakTimer As New System.Timers.Timer
    5. Private _RecordingOrStoppedIcon As String
    6. Public Property RecordingOrStoppedIcon As String
    7. Get
    8. Return _RecordingOrStoppedIcon
    9. End Get
    10. Set(value As String)
    11. _RecordingOrStoppedIcon = value
    12. RaisePropertyChanged()
    13. End Set
    14. End Property
    15. Private _PeakL As Single
    16. Public Property PeakL As Single
    17. Get
    18. Return _PeakL
    19. End Get
    20. Set(value As Single)
    21. _PeakL = value
    22. RaisePropertyChanged()
    23. End Set
    24. End Property
    25. Private _PeakR As Single
    26. Public Property PeakR As Single
    27. Get
    28. Return _PeakR
    29. End Get
    30. Set(value As Single)
    31. _PeakR = value
    32. RaisePropertyChanged()
    33. End Set
    34. End Property
    35. Public Sub New()
    36. RecordingOrStoppedIcon = RecordingIcon
    37. PeakTimer.Interval = 50
    38. AddHandler PeakTimer.Elapsed, AddressOf UpdatePeak
    39. PeakTimer.Start()
    40. End Sub


    Dann gibt es noch diesen Timerhandler:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub UpdatePeak(sender As Object, e As ElapsedEventArgs)
    2. If RecordingChannel <> Nothing Then
    3. If StereoOn Then
    4. Bass.BASS_ChannelGetLevel(RecordingChannel, Peak, 0.05, BASSLevel.BASS_LEVEL_ALL)
    5. PeakL = Peak(2)
    6. PeakR = Peak(1)
    7. Else
    8. Bass.BASS_ChannelGetLevel(RecordingChannel, Peak, 0.05, BASSLevel.BASS_LEVEL_MONO)
    9. PeakL = Peak(0)
    10. PeakR = Peak(0)
    11. End If
    12. End If
    13. End Sub


    Die Methode, die beim Klicken des Start/Stopp-Buttons ausgeführt wird, sieht so aus:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub StarteRecording_Execute(obj As Object)
    2. If HasRecorded Then
    3. Dim OKVM = New OKDialogViewModel
    4. OKVM.Meldung = "Du hast bereits eine Aufnahme gemacht, ohne diese zu speichern. Um eine neue Aufname zu machen, verwerfe oder speichere die aktuelle Aufnahme."
    5. dialogService.ShowModalDialog("", OKVM, Me, True, False, Services.WindowStyle.None, Services.ResizeMode.NoResize, 500, Services.SizeToContent.Height, Services.WindowStartupLocation.CenterOwner, "")
    6. Return
    7. End If
    8. If Not IsRecording Then
    9. Bass.BASS_RecordInit(MainModule.LayerVM.SettingsViewModel.LineInIndex)
    10. MeineRecordingCallback = New RECORDPROC(AddressOf MyRecording)
    11. ' start recording paused
    12. RecordingChannel = Bass.BASS_RecordStart(44100, NumberOfChannels, BASSFlag.BASS_RECORD_PAUSE, MeineRecordingCallback, IntPtr.Zero)
    13. ' really start recording
    14. Bass.BASS_ChannelPlay(RecordingChannel, False)
    15. InitialisiereWaveForm()
    16. Dim Laenge As Single = CSng(Bass.BASS_ChannelBytes2Seconds(RecordingChannel, CLng(MaxTrackLaengeInBytes)))
    17. WF.RenderStartRecording(RecordingChannel, Laenge, 0)
    18. 'End Playback during recording
    19. RecordingOrStoppedIcon = StoppedIcon
    20. IsRecording = True
    21. Else
    22. Bass.BASS_ChannelStop(RecordingChannel) 'Hier friert das Programm ein, ich kann also auch in der nächsten Zeile den ErrorCode nicht abfragen
    23. Debug.WriteLine("STOP: " & Bass.BASS_ErrorGetCode.ToString) 'diese Zeile wird nicht mehr ausgeführt
    24. PeakL = 0
    25. PeakR = 0
    26. RecordingOrStoppedIcon = RecordingIcon
    27. HasRecorded = True
    28. IsRecording = False
    29. End If
    30. End Sub


    Während der Aufnahme ruft die bass.dll alle paar Millisekunden, wie ich denke, diese Callbackfunktion auf:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Function MyRecording(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Boolean
    2. Dim cont As Boolean = True
    3. If length > 0 AndAlso buffer <> IntPtr.Zero Then
    4. If RecordedData Is Nothing OrElse RecordedData.Length < length Then
    5. RecordedData = New Byte(length) {}
    6. End If
    7. ReDim Preserve RecordedData(BytesWritten + length - 1)
    8. ' copy from managed to unmanaged memory
    9. Marshal.Copy(buffer, RecordedData, BytesWritten, length)
    10. BytesWritten += length
    11. Dim Prozent As Double = BytesWritten / MaxTrackLaengeInBytes * 100
    12. RecordingXPosWF = WFBreite / 100 * Prozent
    13. RecordingPosition = TimeSpan.FromSeconds(GetPositionInSeconds(RecordingXPosWF))
    14. ' get and draw our live recording waveform
    15. WF.RenderRecording(buffer, length)
    16. Try
    17. Services.ServiceContainer.GetService(Of IMainWindowService)?.HoleDispatcher().Invoke(Sub() WellenFormZeichnen())
    18. Catch
    19. End Try
    20. If BytesWritten >= MaxTrackLaengeInBytes Then
    21. cont = False ' stop recording
    22. End If
    23. End If
    24. Return cont
    25. End Function

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

    kafffee schrieb:

    Während der Aufnahme ruft die bass.dll alle paar Millisekunden, wie ich denke, diese Callbackfunktion auf
    Diese Prozedur ist nicht optimal implementiert.
    Ich hatte ein äquivalentes Problem mit dem Abspielen einer Wave-Datei aus dem Speicher:
    Diese Prozedur muss so schnell wie irgend möglich abgearbeitet werden.
    ReDim Preserve RecordedData(BytesWritten + length - 1) sollte nur dann aufgerufen werden, wenn der angeforderte Speicher größer ist als der vorhandene.
    RenderRecording() und WellenFormZeichnen() solltest Du in dieser Prozedur gar nicht aufrufen, sondern über einen Timer.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Neu

    jepp. Am besten wäre, die erforderliche Grösse vorab zu dimensionieren. (Wenn das nicht geht, frag nach Alternativen)

    RodFromGermany schrieb:

    RenderRecording() und WellenFormZeichnen() solltest Du in dieser Prozedur gar nicht aufrufen, sondern über einen Timer.
    Evtl kann man diese auch in einem anderen Thread aufrufen, als in dem der Callback läuft.
    WellenForm.Invoke deutet ja schon an, dass der Callback nicht im MainThread stattfindet. RenderRecording sollte dann in nochmal einem anderen Thread.
    Aber vilt geht das auch nicht - ich weiss ja nicht, was diese Methoden so machen (etwa: woher nimmt WellenFormzeichnen seine Daten?)

    Übrigens zeile#9: der Kommentar lügt.

    Neu

    Ich denke mal, in der Bass.Net.xml steht ein Minimal-Beispiel, wie die MyRecording()-Prozedur zu implementieren ist.
    Und:
    Wo bleibt er denn hängen, wenn Du in solch Situation Break drückst?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Neu

    kafffee schrieb:

    WF.RenderRecording(buffer, length)


    Ist dir klar wie oft du renderst? Du solltest schleunigst mal schauen wie oft das passiert. Schaur dir mal diese überladung con BASS_RecordStart an:
    bass.radio42.com/help/html/f6c…974-9e0b-c7a2ce6bb9ed.htm

    Du verwendest die überladung ohne "period". Bei der mit steht folgendes, wenn du nun liest:
    Set the period (in milliseconds) between calls to the callback function (RECORDPROC). The minimum period is 5ms, the maximum the maximum is half the BASS_CONFIG_REC_BUFFER setting. If the period specified is outside this range, it is automatically capped. The default is 100ms.

    Was denkst du dann? Kannst ja mal mit Debug.WriteLine die aktuelle Zeit ausgeben in MyRecording.

    PS.

    kafffee schrieb:

    alle paar Millisekunden, wie ich denke, diese Callbackfunktion auf:


    Aha, ist es denn nötig mit 10-20+ FPS so ein Waveform zu malen? Reicht nicht 1-2 mal pro Sekunde?
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „DTF“ ()

    Neu

    Keine Angst das mit dem Array mach ich auch noch, aber soweit bin ich noch nicht gekommen:

    RodFromGermany schrieb:

    RenderRecording() und WellenFormZeichnen() solltest Du in dieser Prozedur gar nicht aufrufen, sondern über einen Timer.


    Da gibts nur ein Problem:

    RenderRecording will zwei Argumente, buffer und length. Ich habe versucht, einfach zwei Variablen ausserhalb der Prozedur zu deklarieren, aber da läuft was schief. Siehe Screenshot. Die rote vertikale Linie sollte gleichauf mit den aufgenommenen Daten sein in der Wellenform. Wie hast du das bei dir gemacht?
    Edit: Kommando zurück, ich kann ja das Updaten der roten Linie (RecordingPosition) in die UpdateWaveForm mit reinpacken...

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private RenderBuffer As IntPtr
    2. Private RenderLength As Integer
    3. Private NewDataTimer As New System.Timers.Timer
    4. Public Sub New()
    5. NewDataTimer.Interval = 250
    6. End Sub


    Starten der Aufnahme:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub StarteRecording_Execute(obj As Object)
    2. If HasRecorded Then
    3. Dim OKVM = New OKDialogViewModel
    4. OKVM.Meldung = "Du hast bereits eine Aufnahme gemacht, ohne diese zu speichern. Um eine neue Aufname zu machen, verwerfe oder speichere die aktuelle Aufnahme."
    5. dialogService.ShowModalDialog("", OKVM, Me, True, False, Services.WindowStyle.None, Services.ResizeMode.NoResize, 500, Services.SizeToContent.Height, Services.WindowStartupLocation.CenterOwner, "")
    6. Return
    7. End If
    8. If Not IsRecording Then
    9. Bass.BASS_RecordInit(MainModule.LayerVM.SettingsViewModel.LineInIndex)
    10. MeineRecordingCallback = New RECORDPROC(AddressOf MyRecording)
    11. ' start recording paused
    12. RecordingChannel = Bass.BASS_RecordStart(44100, NumberOfChannels, BASSFlag.BASS_RECORD_PAUSE, 500, MeineRecordingCallback, IntPtr.Zero)
    13. ' really start recording
    14. Bass.BASS_ChannelPlay(RecordingChannel, False)
    15. InitialisiereWaveForm()
    16. Dim Laenge As Single = CSng(Bass.BASS_ChannelBytes2Seconds(RecordingChannel, CLng(MaxTrackLaengeInBytes)))
    17. WF.RenderStartRecording(RecordingChannel, Laenge, 0)
    18. AddHandler NewDataTimer.Elapsed, AddressOf UpdateWaveForm
    19. NewDataTimer.Start()
    20. 'End Playback during recording
    21. RecordingOrStoppedIcon = StoppedIcon
    22. IsRecording = True
    23. Else
    24. NewDataTimer.Stop()
    25. RemoveHandler NewDataTimer.Elapsed, AddressOf UpdateWaveForm
    26. Bass.BASS_ChannelStop(RecordingChannel)
    27. WellenFormZeichnen()
    28. PeakL = 0
    29. PeakR = 0
    30. RecordingOrStoppedIcon = RecordingIcon
    31. Bass.BASS_ChannelStop(RecordingChannel)
    32. Debug.WriteLine("STOP: " & Bass.BASS_ErrorGetCode.ToString)
    33. PeakL = 0
    34. PeakR = 0
    35. RecordingOrStoppedIcon = RecordingIcon
    36. HasRecorded = True
    37. IsRecording = False
    38. End If
    39. End Sub


    Die Callback:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Function MyRecording(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Boolean
    2. Dim cont As Boolean = True
    3. If length > 0 AndAlso buffer <> IntPtr.Zero Then
    4. If RecordedData Is Nothing OrElse RecordedData.Length < length Then
    5. RecordedData = New Byte(length) {}
    6. End If
    7. ReDim Preserve RecordedData(BytesWritten + length - 1)
    8. Marshal.Copy(buffer, RecordedData, BytesWritten, length)
    9. BytesWritten += length
    10. Dim Prozent As Double = BytesWritten / MaxTrackLaengeInBytes * 100
    11. RecordingXPosWF = WFBreite / 100 * Prozent
    12. RecordingPosition = TimeSpan.FromSeconds(GetPositionInSeconds(RecordingXPosWF))
    13. RenderBuffer = buffer
    14. RenderLength = length
    15. If BytesWritten >= MaxTrackLaengeInBytes Then
    16. cont = False ' stop recording
    17. End If
    18. End If
    19. Return cont
    20. End Function


    PS: Was haltet ihr davon, cont aus der Callback einfach ausserhalb der Prozedur zu deklarieren und wenn ich stoppen will, einfach auf False zu setzen?

    Edit2: @RodFromGermany

    kafffee schrieb:

    Edit: Kommando zurück, ich kann ja das Updaten der roten Linie (RecordingPosition) in die UpdateWaveForm mit reinpacken...


    Ne das bringt keine Änderung der hinkt immer noch hinterher :( Also nochmal die Frage: Wie würdet ihr das machen?
    Bilder
    • transport.PNG

      2,11 kB, 227×125, 79 mal angesehen

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „kafffee“ ()

    Neu

    kafffee schrieb:

    buffer und length
    sollten doch in Form der Daten, die Du eh in Deiner Klasse hältst, vorhanden sein.
    ====
    Ich spiele vorhandene Daten ab, die werden als Wave binär eingelesen und sequenziell ausgegeben.
    Die Daten liegen in der Klasse, ich habe einen Wiedergabe-Index und bekomme von Bass die Länge des von mir zu befüllenden Speichers mitgeteilt.
    Der Wiedergabe-Index wird dann entsprechend hochgezählt.
    ==
    Die bei Dir rote Markierung wird bei mir über einen Timer bei Bass ausgelesen und an die GUI gesendet.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Neu

    RodFromGermany schrieb:

    sollten doch in Form der Daten, die Du eh in Deiner Klasse hältst, vorhanden sein.

    Also ich hab ja RecordedData As Byte() in der Klasse. Sonst eher nix. Und die .RenderRecording will ja einen IntPtr. Ich gehe auch davon aus, dass .RenderRecording nur die "neuen" Daten haben will (also buffer), nicht die ganze Aufnahme (wie es bei mir bei RecordedData der Fall ist.)

    RodFromGermany schrieb:

    Ich spiele vorhandene Daten ab, die werden als Wave binär eingelesen und sequenziell ausgegeben.

    Jo das hab ich auch vor. Solange das hier mal läuft :)

    RodFromGermany schrieb:

    Die Daten liegen in der Klasse, ich habe einen Wiedergabe-Index und bekomme von Bass die Länge des von mir zu befüllenden Speichers mitgeteilt.

    Benutzt du auch einen PushStream? Was meinst genau mit "zu befüllendem Speicher"?

    RodFromGermany schrieb:

    Die bei Dir rote Markierung wird bei mir über einen Timer bei Bass ausgelesen und an die GUI gesendet.

    Bei mir auch.

    Neu

    kafffee schrieb:

    Ich gehe auch davon aus
    Das solltest Du schon mal aufklären.
    Meine Interpretation: Bass stellt einen IntPtr und eine Anzahl bereit, wo Du die entsprechenden Daten hin kopieren musst.
    Bei der Wiedergabe sieht das bei mir so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. /// <summary>
    2. /// Callback der BASS.dll, um die abzuspielenden Samples zu holen
    3. /// </summary>
    4. /// <returns>Anzahl der geschriebenen Bytes</returns>
    5. private int PlayIntern(int handle, IntPtr buffer, int length, IntPtr user)
    6. {
    7. if (!this._IsPlaying)
    8. {
    9. // Pause, Abbruch
    10. return 0;
    11. }
    12. // byte => float
    13. int length4 = length / 4;
    14. // einen puffer anlegen um Daten aus und in den Speicher zu kopieren
    15. if (this.PlayBuffer == null || this.PlayBuffer.Length < length4)
    16. {
    17. // stationärer Buffer, dessen Größe von der Bass.dll vorgegeben wird
    18. // und in den die nächsten zu spielenden Samples kopiert werden
    19. this.PlayBuffer = new float[length4];
    20. }
    21. // _PlayArrayIndex ist der aktuelle float-Auslese-Index
    22. // läuft bei Stereo doppelt so schnell
    23. // _PlaySampleIndexEnd ist der letzte Auslese-Index bei Play
    24. int count = Math.Min(length4, (this._PlaySampleIndexEnd * this.Channels) - this._PlayArrayIndex);
    25. if (count <= 0)
    26. {
    27. return (int)BASSStreamProc.BASS_STREAMPROC_END;
    28. }
    29. for (int i = 0; i < count; i++)
    30. {
    31. // Samples kopieren, dabei den
    32. // aktuellen Lautstärke-Faktor berücksichtigen
    33. this.PlayBuffer[i] = this.WaveformData[this._PlayArrayIndex++] * this.Volume;
    34. }
    35. // die float-Daten zum Abgespielen in den Bass-Speicher kopieren.
    36. Marshal.Copy(this.PlayBuffer, 0, buffer, count);
    37. // float => byte
    38. count *= 4;
    39. if (count < length)
    40. {
    41. count |= (int)BASSStreamProc.BASS_STREAMPROC_END;
    42. }
    43. return count;
    44. }

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Neu

    RodFromGermany schrieb:

    Das solltest Du schon mal aufklären.


    Hab grad mal eine Anfrage im Un4Seen Forum gemacht deswegen.

    RodFromGermany schrieb:

    C#-Quellcode

    1. Marshal.Copy(this.PlayBuffer, 0, buffer, count);

    Ah okay buffer wird als IntPtr übergben, d.h. das funktioniert dann so ähnlich wie wenn buffer als ByRef übergeben wurde, liege ich da richtig?

    RodFromGermany schrieb:

    C#-Quellcode

    1. // _PlaySampleIndexEnd ist der letzte Auslese-Index bei Play


    Also auf gut deutsch die rote Linie beim Recording? Spielst du auch während der Aufnahme schon ab?

    _________________________

    Edit: Für mich sieht das fast so aus, dass eben wenn ich das Waveform zeichnen mit nem Timer mach, das Ganze halt nicht 100% "in sync" mit dem Aufrufen der Callback ist (warum sollte sie auch), und deswegen meine rote Linie hinterher hinkt.

    Zur Info: Ich benutz dafür mittlerweile die Graphics-Klasse und . DrawLine

    Wie und wo zeichnest du deine rote Linie?

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

    Neu

    kafffee schrieb:

    Also auf gut deutsch die rote Linie beim Recording?
    Nein, das ist der rechte Rand.
    Den aktuellen Play-Index frage ich in einem Timer ab.
    Die Darstellung erfolgt bei mir genau so.
    Ich habe keine Aufnahme, sondern nur eine Wiedergabe.
    Das ganze ist also "nur" äquivalent, nicht aber gleich.

    kafffee schrieb:

    liege ich da richtig?
    Das steht doch in der richtigen Überladung der Marshal.Copy()-Prozedur.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Neu

    @RodFromGermany
    Warum wandelst du in Zeile 14 deines Codes die Länge in Bytes in Float bzw. Single um?

    ErfinderDesRades schrieb:

    Am besten wäre, die erforderliche Grösse vorab zu dimensionieren

    Doch das sollte gehen. Hab eine Option wo man die maximale Aufnahmelänge angeben muss.

    ErfinderDesRades schrieb:

    Evtl kann man diese auch in einem anderen Thread aufrufen, als in dem der Callback läuft

    Mit welcher Funktion würdest das machen? Ich glaub Threads aufrufen kann man ja auf eine Handvoll Art und Weise...


    ErfinderDesRades schrieb:

    WellenForm.Invoke deutet ja schon an, dass der Callback nicht im MainThread stattfindet.

    Genau. Die Calllback tut das nicht, daher invoke ich WellenForm() vom Thread des MainWindow aus, sonst crasht mein Programm...

    ErfinderDesRades schrieb:

    Übrigens zeile#9: der Kommentar lügt.

    Stimmt. Der gehört eine Zeile tiefer. Ich verbessere das gleich...

    Neu

    kafffee schrieb:

    Warum wandelst du in Zeile 14 deines Codes die Länge in Bytes in Float bzw. Single um?
    Weil die Bass.dll entsprechende Überladungen des Datenformats (Byte, Single) anbietet und die Daten in Single vorliegen.
    ====
    Jeder beliebige Timer arbeitet in einem Nicht-Bass-Thread. 8o
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Neu

    Das glaub ich dir gern ich würde jetzt aber trotzdem mal versuchen den Timer mal versuchsweise Timer sein zu lassen und stattdessen trotzdem mal explizit in nem anderen Thread laufen lassen.
    Du holst dir deine aktuelle Position mit ChannelGetPosition? Ich mach das über die Variable BytesWritten, aber da sollte ja eigentlich keinen Einfluss haben...
    Ist auch ein WPF-Projekt, vielleicht macht das ja auch nochmal einen Unterschied.
    Hab jedenfalls das hier gefunden, aber bin mir nicht sicher, wie gesagt, welche Methode ich verwenden sollte:

    learn.microsoft.com/de-de/dotn…w=netframeworkdesktop-4.8

    Was hältst du davon, die Variable cont in meiner Callback einfach außerhalb der Callback zu platzieren und wenn ich stoppen will, einfach den entsprechenden Wert setzen?

    Vielleicht probier ich's auch einfach mal mit nem Dispatcher.Timer...

    stackoverflow.com/questions/22…-app-for-a-task-scheduler

    btw: Habt ihr auch seit dem letzten Win10 Update das Problem dass er erstmal 10min braucht zum Runterfahren, zum wiederholten Mal?

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „kafffee“ ()

    Neu

    kafffee schrieb:

    Ich mach das über die Variable BytesWritten, aber da sollte ja eigentlich keinen Einfluss haben...
    Möglicherweise doch, denn Bass holt sich bei mir die Bytes immer häppchen-weise und spielt die dann synchron ab. BytesWritten folgt den holperigen Häppchen, nicht aber dem kontinuierlichen Play-Stream.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Neu

    @RodFromGermany

    Was ich bei deinem Beispielcode noch nicht verstanden hab: Wie bekommst du dein WaveFormData zustande.... Ich hab ja PCM Daten, ist ja das gleiche ohne Header... Und die hab ich in einem Byte Array dassis einfach: SampleRate * Bittiefe * Kanäle / 8.
    Wie bekommst du das Byte() in ein Single() konvertiert? Bzw in welchem Muster liegen die Daten dann im Single ()? Werden dann immer einfach 4 Bytes zu einem "Block" zusammengefasst?

    Übrigens der Ian hat zurück geschrieben: der in der RECORDPROC als Argument übergebene buffer, das sind nur die "neuen" Daten; also das nächste Byte Chunk. Und length die Länge davon. Folglich erwartet die .RenderRecording auch nur das nächste Byte Chunk, nicht die komplette Aufnahme von Anfang an...

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

    Neu

    Also, statt BytesWritten hab ich's mal mit Bass.BASS_ChannelGetPosition versucht, hinkt immer noch hinterher. Ausserdem möchte ich ja, BytesWritten für die Position des Recording-Fortschrittes genommen wird, da mir das die tatsächliche Länge der Daten ausgibt. Ist bisschen eine andere Heruasforderung wie bei @RodFromGermany...

    Statt dem System.Timers.Timer hab ich mal den DispatcherTimer versucht, das hat auch nix gebracht... Also hab ich mal den Timer wieder komplett rausgeschmissen, und habs hiermit versucht (in der MyRecording)

    VB.NET-Quellcode

    1. Services.ServiceContainer.GetService(Of IMainWindowService)?.HoleDispatcher().InvokeAsync(Sub() WF.RenderRecording(buffer, length), DispatcherPriority.SystemIdle) 'HoleDispatcher ist der Main-UI-Thread vom MainWindow
    2. Services.ServiceContainer.GetService(Of IMainWindowService)?.HoleDispatcher().InvokeAsync(Sub() UpdateWaveForm(Nothing, Nothing), DispatcherPriority.SystemIdle)


    Habs jetzt fünf mal versucht und es hat sich nix aufgehängt... Aber das mag ja noch nix heissen, weil ich hatte das Probem ja immer nicht jedes Mal...