Waveform mit bass.dll darstellen

  • VB.NET

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von TByte.

    Waveform mit bass.dll darstellen

    Hallo,
    ich weiß jetzt nicht, ob das Thema schon öfters gepostet wurde, doch nach meiner mehrtägigen Online-Recherche-Odysee versuche ich jetzt mal hier mein Glück:
    Im Grunde ist es ganz simple: Wie gibt man mittels der bass.dll die komplette Waveform eines Songs aus? Z.B. in einer PictureBox!
    Die durch meine Online-Recherchen gefundenen Codefragmente waren nicht allzu hilfreich, da diese alle immer unvollständig oder sehr fehlerhaft waren...!
    Also, wer eine Tutorial, einen kompletten Beispielcode oder ähnliches kennt, bitte posten...
    DAnke fschonmal für jede Hilfe.
    mfg
    TByte
    Willkommen im Club. :thumbsup:
    Hast Du schon die beiden Bass-DLL-Tutorials hier im Forum gefunden:
    Bass-Tut 1 und Bass-Tut 2
    Kompletten Beispielcode findest Du nur im vb@rchiv oder so.
    Wenn Du schon Code hast, der aber nicht läuft, poste ihn hoch, wie reden drüber und bügeln die Fehler raus. Die Initiative aber liegt bei Dir.
    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!
    Hallo,
    wegen des Codes: Das ist u.a. Beispielcode, wie der folgende, den man selbst in ein Projekt einbetten muß:

    VB.NET-Quellcode

    1. Private WF As Un4seen.Bass.Misc.WaveForm = Nothing
    2. Private Sub GetWaveForm()
    3. ' render a wave form
    4. WF = New Un4seen.Bass.Misc.WaveForm("test.mp3", New Un4seen.Bass.Misc.WAVEFORMPROC(MyWaveFormCallback), Me)
    5. WF.CallbackFrequency = 500
    6. ' every 10 seconds rendered
    7. WF.ColorBackground = Color.Black
    8. WF.ColorBase = Color.Lime
    9. WF.ColorPeak = Color.Red
    10. ' it is important to use the same resolution flags as for the playing stream
    11. ' e.g. if an already playing stream is 32-bit float, so this should also be
    12. ' or use 'SyncPlayback' as shown below
    13. WF.RenderStart(True, BASSFlag.BASS_SAMPLE_FLOAT)
    14. End Sub
    15. Private Sub MyWaveFormCallback(framesDone As Integer,framesTotal As Integer,elapsedTime As TimeSpan,finished As Boolean)
    16. ' will be called during rendering...
    17. DrawWave()
    18. If finished Then
    19. Console.WriteLine("Finished rendering in {0}sec.",elapsedTime)
    20. Console.WriteLine("FramesRendered={0} of {1}",WF.FramesRendered,WF.FramesToRender)
    21. ' if your playback stream uses a different resolution than the WF
    22. ' use this to sync them
    23. WF.SyncPlayback(_stream)
    24. End If
    25. End Sub
    26. Private Sub DrawWave()
    27. If Not (WF Is Nothing) Then
    28. Me.pictureBox1.BackgroundImage = WF.CreateBitmap(Me.pictureBox1.Width,Me.pictureBox1.Height,-1,-1,False)
    29. Else
    30. Me.pictureBox1.BackgroundImage = Nothing
    31. End If
    32. End Sub


    Ich habe mal den Originalcode eingefügt, so wie ich ihn im Netz gefunden habe.
    Alles, was auf eine Konsolenanwendung hinweißt habe ich umgeschrieben, so daß ich da Ausgaben in Labels bekomme...

    mfg
    TByte

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „TByte“ ()

    Ich hoffe, Du bist meiner Meinung wenn ich sage, dass Dein Code-Zitat hier absolut be... ankommt. :thumbdown:
    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!
    Jetzt ist es in Ordnung. Danke.
    Wo kommt denn die Deklaration dieser Prozedur her:

    VB.NET-Quellcode

    1. Private Sub MyWaveFormCallback(ByVal framesDone As Integer, ByVal framesTotal As Integer, ByVal elapsedTime As TimeSpan, ByVal finished As Boolean)

    Der Delegat "Un4seen.Bass.Misc.WAVEFORMPROC" erfordert als einziges Argument für seinen Konstruktor einen AddressOf-Ausdruck oder einen Lambda-Ausdruck.
    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!
    Da muß ich ehrlich sein, das weiß ich nicht so genau!
    In Zeile 4 wird ja am Ende diese Funktion (MyWaveFormCallback) aufgerufen und keine Werte mitübergeben. Das hat mich schon etwas stutzig gemacht... Ich habe dann etwas rumprobiert, also, die Werte weggelassen, benötigte Werte ausgelesen und mitübergeben, aber irgendwie wollte das alles nicht so funktionieren.
    Ich denke mal, daß der Code mehr oder weniger als Grundlage genutzt werden kann, um da was eigenes zu erstellen...
    Sieh Dir mal die beiden Tuts an, die ich Dir oben gepostet habe.
    Da sollte in jedem Falle ein lauffähiger Code drin sein.
    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!
    Hallo TByte.

    Da das wirklich nicht einfach ist, hab ich mich entschieden, Dir diesen Code zu posten.

    Die Picturebox heisst in diesem Fall "PictureBoxBigWave"

    Spoiler anzeigen

    VB.NET-Quellcode

    1. #Region " Wave Form Drawing & Spektrum"
    2. ' Deklaration - Wave Form zeichnen
    3. Private IsDrawing As Boolean = False
    4. Private WF As Un4seen.Bass.Misc.WaveForm
    5. Private _deviceLatencyBytes As Integer = 0
    6. #End Region
    7. #Region " updateTimer"
    8. Private _updateTimer As BASSTimer = Nothing
    9. Private _updateInterval As Integer = 50
    10. Private Channel_Pos As Long ' Position in bytes
    11. Private Channel_Len As Long ' Länge in bytes
    12. #End Region
    13. Private Sub Form_load
    14. If False = Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT Or BASSFlag.BASS_STREAM_PRESCAN, Me.Handle) Then
    15. ‘Fehlerbehandlung
    16. End If
    17. _updateTimer = New Un4seen.Bass.BASSTimer(_updateInterval)
    18. AddHandler _updateTimer.Tick, AddressOf timerUpdate_Tick
    19. End Sub
    20. Private Sub abspielen()
    21. ' evtl. laufenden stream schließen
    22. If strm <> 0 Then
    23. If WF.IsRenderingInProgress Then
    24. WF.RenderStop()
    25. WF.Reset()
    26. End If
    27. Bass.BASS_ChannelStop(strm)
    28. Bass.BASS_StreamFree(strm)
    29. End If
    30. strm = Bass.BASS_StreamCreateFile(_filename, 0, 0, BASSFlag.BASS_DEFAULT Or BASSFlag.BASS_STREAM_AUTOFREE Or BASSFlag.BASS_SAMPLE_FLOAT)
    31. SetupWaveForm()
    32. If strm <> 0 AndAlso Bass.BASS_ChannelPlay(strm, False) Then
    33. _updateTimer.[Start]()
    34. Else
    35. MsgBox(BASS_GetErrorDescription(Bass.BASS_ErrorGetCode()))
    36. End If
    37. End Sub
    38. #Region " timerUpdate"
    39. Private Sub timerUpdate_Tick(ByVal sender As Object, ByVal e As System.EventArgs)
    40. Channel_Pos = Bass.BASS_ChannelGetPosition(strm, BASSMode.BASS_POS_BYTES) ' Position in bytes
    41. Channel_Len = Bass.BASS_ChannelGetLength(strm, BASSMode.BASS_POS_BYTES) ' Länge in bytes
    42. If CType(Bass.BASS_ChannelIsActive(strm), BASSActive) = BASSActive.BASS_ACTIVE_PLAYING Then
    43. DrawWavePosition(Channel_Pos, Channel_Len) 'Wave Position updaten
    44. ElseIf CType(Bass.BASS_ChannelIsActive(strm), BASSActive) = BASSActive.BASS_ACTIVE_PAUSED Then
    45. DrawWavePosition(Channel_Pos, Channel_Len) 'Wave Position updaten
    46. Else
    47. _updateTimer.[Stop]()
    48. _updateTimer.[Dispose]()
    49. Exit Sub
    50. End If
    51. End Sub
    52. #End Region
    53. #Region " Wave Form Drawing "
    54. Private Sub SetupWaveForm()
    55. WF = New WaveForm(_filename, New WAVEFORMPROC(AddressOf MyWaveFormCallback), Me)
    56. WF.FrameResolution = 0.01F ' 10ms
    57. WF.CallbackFrequency = 500 ' alle 5 sekunden wird gerendert (500*10ms=5sec)
    58. 'Farben
    59. WF.ColorBackground = Color.Transparent
    60. WF.ColorLeft = Color.FromArgb(64, 64, 50)
    61. WF.ColorRight = Color.FromArgb(64, 64, 50)
    62. WF.ColorLeftEnvelope = Color.Orange
    63. WF.ColorRightEnvelope = Color.Orange
    64. WF.ColorMiddleLeft = Color.Wheat
    65. WF.ColorMiddleRight = Color.Wheat
    66. WF.DrawCenterLine = True
    67. WF.DrawEnvelope = True
    68. WF.DrawMarker = WaveForm.MARKERDRAWTYPE.Line Or WaveForm.MARKERDRAWTYPE.Name Or WaveForm.MARKERDRAWTYPE.NamePositionMiddle
    69. WF.RenderStart(True, BASSFlag.BASS_SAMPLE_FLOAT Or BASSFlag.BASS_STREAM_PRESCAN)
    70. WF.SyncPlayback(strm)
    71. End Sub
    72. Private Sub MyWaveFormCallback(ByVal framesDone As Integer, ByVal framesTotal As Integer, ByVal elapsedTime As TimeSpan, ByVal finished As Boolean)
    73. DrawWave(False)
    74. If finished Then
    75. DrawWave(True)
    76. End If
    77. End Sub
    78. Private Sub DrawWave(Optional ByVal highQuality As Boolean = False)
    79. If highQuality = False Then
    80. IsDrawing = Not IsDrawing
    81. If IsDrawing Then Exit Sub
    82. End If
    83. If Not WF Is Nothing Then
    84. Me.PictureBoxBigWave.BackgroundImage = WF.CreateBitmap(Me.PictureBoxBigWave.Width, Me.PictureBoxBigWave.Height, -1, -1, highQuality)
    85. If WF.IsRenderingInProgress Then Exit Sub
    86. Else
    87. Me.PictureBoxBigWave.BackgroundImage = Nothing
    88. End If
    89. End Sub
    90. Private Sub DrawWavePosition(ByVal pos As Long, ByVal len As Long)
    91. Dim PenColor As Color = Color.Red
    92. If len = 0 OrElse pos < 0 Then
    93. Me.PictureBoxBigWave.Image = Nothing
    94. Return
    95. End If
    96. Dim bitmap As Bitmap = Nothing
    97. Dim g As Graphics = Nothing
    98. Dim p As Pen = Nothing
    99. Dim bpp As Double = 0
    100. Try
    101. bpp = len / CType(Me.PictureBoxBigWave.Width, Double)
    102. pos -= _deviceLatencyBytes
    103. p = New Pen(PenColor)
    104. bitmap = New Bitmap(Me.PictureBoxBigWave.Width, Me.PictureBoxBigWave.Height)
    105. g = Graphics.FromImage(bitmap)
    106. g.Clear(Color.White)
    107. Dim x As Integer = CType(Math.Round(pos / bpp), Integer)
    108. ' position (x) = wo die Linie gezeichnet wird
    109. g.DrawLine(p, x, 0, x, Me.PictureBoxBigWave.Height - 1)
    110. bitmap.MakeTransparent(Color.White)
    111. Catch
    112. bitmap = Nothing
    113. Finally
    114. ' Graphic Resourcen freigeben
    115. If Not p Is Nothing Then p.Dispose()
    116. If Not g Is Nothing Then g.Dispose()
    117. End Try
    118. Me.PictureBoxBigWave.Image = bitmap
    119. End Sub
    120. #End Region



    Das funktioniert am besten, wenn Du die Abspielvorgänge in einem Timer laufen läßt. (in diesem Fall ein BASSTimer).
    Die Wave bekommt man auch ohne abspielen, aber da musst Du die Datei prescannen bei Bass.BASS_StreamCreateFile(...

    Und bitte daran denken, nicht 1 zu 1 übernehmen, der Code ist aus meinem Projekt und ich kann nicht garantieren, auf die Schnelle
    alle nötigen Variablen deklariert zu haben. Aber zum studieren und begreifen reichts allemal

    Das sollte aber erstmal genügen.

    mfg OnkelR
    Hallo,
    danke, werde es gleich mal ausprobieren bzw. mich versuchen da reinzudenken...
    Natürlich werde ich den Code nicht 1zu1 übernehmen, da man ja in seinen eigenen Projekten immer auf die persönliche Originalität achten sollte...
    Aber als Denkanstoß ist es trotzdem super... Also nochmal danke... Ich werde es dann posten, wenn ich es hinbekommen habe... Kann aber etwas dauern...
    grüsse
    TByte
    für nen besseres Verständnis wäre es sehr empfehlenswert die sehr gute Dokumentation von der Bibliothek anzuschauen. Das ist dann eigentlich schon fast selbsterklärend.
    bass.radio42.com/help/html/6a2…86b-74e7-3a0a65f7e545.htm


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    So, es funktioniert einwandfrei...
    Wenn man mal weiß, wie es geht, dann ist es nicht mehr schwer...
    Ich danke allen, die mir hierbei geholfen haben...
    Grüsse
    TByte

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

    TByte schrieb:

    da man ja in seinen eigenen Projekten immer auf die persönliche Originalität achten sollte...

    Wieviel eigene Projekte hast Du denn bis jetzt erstellt?
    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!
    Eigene Projekte??
    Keine Ahnung, ich programmiere eigentlich nur so für mich, wenn es der Job zuläßt, um zu schauen, wie was funktioniert, um quasi up-to-date zu bleiben...
    Meine Projekte waren bis jetzt meistens nur für den Eigengebrauch und der Rest für die Ablage...
    Zur Zeit schreibe ich an ner kleinen Light & Sound-Applikation für meinen Partykeller...