Mehrere Töne gleichzeitig abspielen

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 57 Antworten in diesem Thema. Der letzte Beitrag () ist von tron25.

    Hi. Keine Ahnung ob die Bass.dll mehrere Frequenzen gleichzeitig abspielen kann ohne das erst das ganze neu berechnet werden muss. Üblicherweise erstellt man mehrere SoundBuffer mit unterschiedlichen Frequenzen die gleichzeitig abgespielt werden können. Um das zusammen mixen hat sich die entsprechende Schnittstelle (WASAPI, DirectSound, MediaFoundation) zu kümmern. Noch einfacher ist es eine oder mehrere Grundfrequenzen zu erstellen und diese per Pitch an die gewünschte Frequenz anzupassen ohne ständig alles selbst neu berechnen zu müssen. Natürlich spielt auch die Phasenlage eine gewisse Rolle wie die gemixte Frequenz wahrgenommen wird.
    Mfg -Franky-

    Haudruferzappeltnoch schrieb:

    Also was verstehst du unter "akustisch eine Rolle spielen"?
    Generiere Dir je eine Wave-Sequenz über sagen wir 10 Sekunden mit 2 Frequenzen und verschiedenen Phasenlagen der Frequenzen zueinander.
    Spiele sie nacheinander ab und versuche akustisch, also hörend, einen Unterschied zu erkennen.
    Es gibt keinen.
    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!
    Ok, bei nur zwei Frequenzen kann das gut funktionieren, wenn sie nicht zu nah beieinander liegen, macht Sinn.
    Ich sagte ja bereits, wenn ich nur eine Frequenz in der Phase verschiebe, dann ist das logisch. Bei zwei lässt sich das noch gut nachvollziehen, wenn sie nicht annähernd gleich sind.
    Aber bei drei Frequenzen wird es schon kompliziert die richtigen Randbedingungen anzugeben um die Aussage wahr zu machen.

    Ich frag mich wie Noise-Cancelling-Kopfhörer programmiert werden. Das müsste ganz ähnlich laufen: erzeuge die richtigen Frequenzen = höre weniger...aber mehr hören kann man mit den Dingern auch machen, da wird sicherlich auch dynamisch die Phase berücksichtigt der eingehenden Töne.

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

    Bei ANC(Active Noise Cancelling) werden zwar gegen Schallwellen verwendet, aber man müsste nicht mal die störenden Geräusche komplett eliminieren, nur soweit abschwächen das sie nicht mehr oder kaum noch warnehmbar sind, wenn es dann kaum warnehmbar ist, wird man es beim Musikhören "überhören". Dazu wird man nicht unbedingt die Phase berücksichtigen müssen. Die Wellen treffen aufeinandern und stören/neutralisieren sich, kommt eher auf die richtige Stärke an, damit man nicht ein störendes Geräusch erzeugt.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

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

    Doch natürlich, sagen wir der eingehende Schall ist eine normale Sinuswelle. Die Gegenwelle ist identisch, also die sollte auch ungefähr aussehen wie ein Sinus.
    Und wenn man da nun die Phase nicht berücksichtigt, dann ist das Resultat der Amplitude irgendwo zwischen doppelt so laut und weg, alles mögliche. Wie in Post 18 zu sehen.
    @tron25 Im Prinzip benötigst Du eine Kombination aus onlinetonegenerator.com/multiple-tone-generator.html und szynalski.com/tone-generator/ Beim ersten kannst Du mehrere feste Frequenzen erzeugen, ein oder ausschalten, Panning und Volume ändern. Beim zweiten kann man die Frequenz über den Schieberegler entsprechend anpassen.

    Edit: Nur der Vollständigkeit halber wie es per DirectSound funktioniert: handmade.network/forums/articles/t/3040-directsound Im Prinzip erstellt man mehrere SoundBuffer und mit den entsprechenden DSBCAPS_-Flags hast Du alles was Du brauchst und kannst Volume, Pitch, Panning entsprechend, und wenn ich mich nicht irre, on the fly anpassen.
    Mfg -Franky-

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

    Sorry, dass ich mich so spät melde, aber ich war in den letzten Tagen sehr beschäftigt.

    Vielen Dank erst einmal für die Zahlreichen Beiträge.

    So, jetzt habe ich auch einen ersten Entwurf für die Oberfläche. Zum Testen wollte ich versuchen, zwei Töne gleichzeitig abzuspielen. Dabei habe ich das Problem, wie ich die Werte für Lautstärke oder die Frequenzen in Variablen packen kann. Beispielsweise für die Lautstärke "0.5D". Die Lautstärke ist ja ein "Double". Aber wie bekomme ich das "D" dahinter? Mit "&" funktioniert es nicht. Hier der bisherige Code:

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Imports Un4seen.Bass
    3. Public Class MultiBeepFormular
    4. 'handle für den audio stream
    5. Private streamHandle1 As Integer = 0
    6. Private streamHandle2 As Integer = 0
    7. 'STREAMPROC delegate, "zeigt" dann auf die angegebene Funktion die dann
    8. 'regelmäßig gecallt wird
    9. Private streamProc1 As STREAMPROC
    10. Private streamProc2 As STREAMPROC
    11. Dim Links1Frequenz As Integer
    12. Dim Links2Frequenz As Integer
    13. Dim Links1Lautstaerke As Double
    14. Dim Links2Lautstaerke As Double
    15. Dim Rechts1Frequenz As Integer
    16. Dim Rechts1Lautstaerke As Double
    17. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    18. If Not Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_CPSPEAKERS, IntPtr.Zero) Then
    19. MessageBox.Show($"BASS Initialisierungsfehler: { Bass.BASS_ErrorGetCode() }")
    20. Application.Exit()
    21. End If
    22. End Sub
    23. Private Function StreamProcCallback(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Integer
    24. 'einen puffer anlegen um Daten aus und in den Speicher zu kopieren
    25. Dim buff As Byte() = New Byte(length) {}
    26. 'die Daten aus dem Speicher in unseren Puffer kopieren, die Daten sind "stumm" weil nichts im Stream zum abspielen da ist
    27. Marshal.Copy(buffer, buff, 0, length)
    28. Dim samplerate As Double = 44100D
    29. 'Wie bekomme ich den Wert "500D" in eine Variable?
    30. Dim waveFrequencyLeft As Double = 500D 'frequenz in Hz linker Kanal
    31. Dim waveFrequencyRight As Double = 1000D 'frequenz in Hz rechter Kanal
    32. 'Das Gleiche mit der Lautstärke
    33. Dim gainLeft As Double = 0.1D 'lautstärke linker Kanal
    34. Dim gainRight As Double = 1D 'lautstärke rechter Kanal
    35. 'die einzelnen Samples erstellen, jedes Sample besteht aus 8 Bytes, je 2 Singles(2x 4 Bytes), je einmal für links und einmal für rechts
    36. For i As Integer = 0 To buff.Length - 9 Step 8
    37. Dim left As Single = CSng(Math.Sin(i / 8D * 2D * Math.PI * waveFrequencyLeft / samplerate) * gainLeft)
    38. Dim right As Single = CSng(Math.Sin(i / 8D * 2D * Math.PI * waveFrequencyRight / samplerate) * gainRight)
    39. 'die bytes für den Puffer
    40. Dim bytesLeft As Byte() = BitConverter.GetBytes(left)
    41. Dim bytesRight As Byte() = BitConverter.GetBytes(right)
    42. 'die bytes in unseren Puffer kopieren
    43. Array.Copy(bytesLeft, 0, buff, i, 4)
    44. Array.Copy(bytesRight, 0, buff, i + 4, 4)
    45. Next
    46. 'die Daten aus unseren Puffer in den Speicher kopieren, damit sie nun abgespielt werden können.
    47. Marshal.Copy(buff, 0, buffer, length)
    48. Return length
    49. End Function
    50. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    51. Bass.BASS_ChannelStop(streamHandle1)
    52. Bass.BASS_ChannelStop(streamHandle2)
    53. streamProc1 = Nothing
    54. streamProc2 = Nothing
    55. Bass.BASS_StreamFree(streamHandle1)
    56. Bass.BASS_StreamFree(streamHandle2)
    57. End Sub
    58. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    59. 'neues STREAMPROC, "zeigt" auf die Sub StreamProcCallback
    60. streamProc1 = New STREAMPROC(AddressOf StreamProcCallback)
    61. streamProc2 = New STREAMPROC(AddressOf StreamProcCallback)
    62. 'das handle für den Stream erstellen
    63. streamHandle1 = Bass.BASS_StreamCreate(44100, 2, BASSFlag.BASS_SAMPLE_FLOAT, streamProc1, IntPtr.Zero)
    64. streamHandle2 = Bass.BASS_StreamCreate(44100, 2, BASSFlag.BASS_SAMPLE_FLOAT, streamProc2, IntPtr.Zero)
    65. 'den stream starten
    66. Bass.BASS_ChannelPlay(streamHandle1, False)
    67. Bass.BASS_ChannelPlay(streamHandle2, False)
    68. End Sub
    69. End Class


    Wenn ich das Programm laufen lasse, höre ich auch den Ton. Allerdings kann ich wegen der oben genannten Probleme keine zweite Frequenz bestimmen. Natürlich könnte ich versuchen, die Funktion zu dublizieren, aber das erscheint mir nicht effizient. Zudem hätte ich dann immernoch das Problem mit den Variablen.

    Habt ihr da eine Idee? Oder könntet ihr die Funktionen auf zwei Frequenzen erweitern, sodas ich dann damit weiterarbeiten kann?

    Vielen Dank nochmal.
    @-Franky-: Menno, ich hab 2 Tage dran gearbeitet, Töne zu bauen, zu überlagern, abzuspeichern!
    Und jetzt haust du da diese Online-Apps raus, wo das alles gelöst ist, inklusive das Problem, bei grossem Frequenzbereich gleichzeitig extrem fein tunen können zu müssen.

    @tron25: Komisch, dass du da garnet drauf eingehst.
    Ich habe mir die zwei Programme angeschaut. Leider sind das aber beides Webanwendungen, die für Blinde, die einen Screenreader verwenden nicht sonderlich barrierefrei sind.

    Den C-Code habe ich mir auch angeschaut. Allerdings brauche ich da Zeit, um den Code in VB zu übersetzen.

    Trotzdem danke für die Tips.

    ErfinderDesRades schrieb:

    Und jetzt haust du da diese Online-Apps raus, wo das alles gelöst ist, ...

    Diese Beispiele sollten nur zeigen, wie ich mir so eine App vorstellen könnte. Adhoc einfach noch eine weitere Frequenz dazu packen oder wieder wegnehmen, Pitch, Volume, Panning usw. ohne das alles neu berechnet werden muss wenn sich ein Parameter ändert. Jetzt braucht man halt die geeignete Soundschnittstelle die das abbilden kann.

    @tron25 Siehe Quote -> @ErfinderDesRades
    Es ist mir schon klar das diese Webanwendungen für Dich ungeeignet sind. Falls Du den Code von meinem Link übersetzen möchtest, es ist nur eine API, zwei COM-Interfaces plus ein paar Structure, Const und Enums. Für Dich mag es eventuell auch einfacher sein, wenn Du z.B. SharpDX nutzt. Da hatte ich ja auch schon einen Link zu einem SinusGenrator mit SharpDX gepostet.
    Mfg -Franky-
    @tron25 Ich hatte etwas Zeit und hab mal den Code vom DirectSound-Link nach VB.NET übersetzt.
    Code in der Form

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Public Class Form1
    3. Private SinGen As SinusGenerator
    4. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    5. SinGen = New SinusGenerator(Me.Handle)
    6. End Sub
    7. Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
    8. SinGen = Nothing
    9. End Sub
    10. End Class

    Code in eine Klasse SinusGenerator (einige Interface Funktionen sind nicht komplett)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class SinusGenerator
    3. #Region "APIs"
    4. <DllImport("DSound.dll", EntryPoint:="DirectSoundCreate8")>
    5. <PreserveSig> Private Shared Function DirectSoundCreate8(<[In]> ByRef lpcGuidDevice As Guid,
    6. <Out, MarshalAs(UnmanagedType.Interface)> ByRef ppDS8 As IDirectSound8,
    7. <[In]> pUnkOuter As IntPtr) As Integer
    8. End Function
    9. #End Region
    10. #Region "Class"
    11. Public Sub New(OwnerHwnd As IntPtr)
    12. If OwnerHwnd <> IntPtr.Zero Then
    13. If DirectSoundCreate8(New Guid(DSDEVID_DefaultPlayback),
    14. m_IDirectSound8,
    15. IntPtr.Zero) = DS_OK Then
    16. If m_IDirectSound8.SetCooperativeLevel(OwnerHwnd, DSSCL_FLAG.DSSCL_PRIORITY) = DS_OK Then
    17. Dim BufferDescription As New DSBUFFERDESC With {
    18. .dwSize = Marshal.SizeOf(Of DSBUFFERDESC),
    19. .dwFlags = DSBCAPS_FLAGS.DSBCAPS_PRIMARYBUFFER
    20. }
    21. If m_IDirectSound8.CreateSoundBuffer(BufferDescription, m_IDirectSoundBuffer_Primary, IntPtr.Zero) = DS_OK Then
    22. Dim WaveFormat As New WAVEFORMATEX With {
    23. .wFormatTag = WAVE_FORMAT_PCM,
    24. .nSamplesPerSec = 44100,
    25. .wBitsPerSample = 16,
    26. .nChannels = 2
    27. }
    28. WaveFormat.nBlockAlign = CShort((WaveFormat.wBitsPerSample / 8) * WaveFormat.nChannels)
    29. WaveFormat.nAvgBytesPerSec = WaveFormat.nSamplesPerSec * WaveFormat.nBlockAlign
    30. If m_IDirectSoundBuffer_Primary.SetFormat(WaveFormat) = DS_OK Then
    31. BufferDescription.dwFlags = DSBCAPS_FLAGS.DSBCAPS_CTRLVOLUME Or
    32. DSBCAPS_FLAGS.DSBCAPS_CTRLFREQUENCY Or
    33. DSBCAPS_FLAGS.DSBCAPS_CTRLPAN
    34. BufferDescription.dwBufferBytes = 44100 * 4
    35. Dim pWaveFormat As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Of WAVEFORMATEX))
    36. Marshal.StructureToPtr(WaveFormat, pWaveFormat, True)
    37. BufferDescription.lpwfxFormat = pWaveFormat
    38. Marshal.FreeHGlobal(pWaveFormat)
    39. If m_IDirectSound8.CreateSoundBuffer(BufferDescription, m_IDirectSoundBuffer_Secundary, IntPtr.Zero) = DS_OK Then
    40. Dim pBuffer As IntPtr
    41. Dim BufferSize As Integer
    42. If m_IDirectSoundBuffer_Secundary.Lock(0, BufferDescription.dwBufferBytes,
    43. pBuffer, BufferSize, IntPtr.Zero,
    44. 0, DSBLOCK_FLAG.DSBLOCK_NONE) = DS_OK Then
    45. Const Frequency As Double = 440
    46. Dim LeftRight As Integer
    47. Dim TimeStep As Double
    48. Dim Values As Integer() = New Integer(WaveFormat.nSamplesPerSec) {}
    49. For i = 0 To WaveFormat.nSamplesPerSec - 1
    50. LeftRight = CInt(32000 * Math.Sin(2 * Math.PI * Frequency * TimeStep))
    51. Values(i) = 65536 * LeftRight + LeftRight
    52. TimeStep += 1D / WaveFormat.nSamplesPerSec
    53. Next i
    54. Marshal.Copy(Values, 0, pBuffer, Values.Length)
    55. If m_IDirectSoundBuffer_Secundary.Unlock(pBuffer, BufferSize, IntPtr.Zero, 0) = DS_OK Then
    56. m_IDirectSoundBuffer_Secundary.SetCurrentPosition(0)
    57. m_IDirectSoundBuffer_Secundary.SetVolume(DSBVOLUME_MAX)
    58. m_IDirectSoundBuffer_Secundary.SetPan(DSBPAN_CENTER)
    59. m_IDirectSoundBuffer_Secundary.SetFrequency(DSBFREQUENCY_ORIGINAL)
    60. If m_IDirectSoundBuffer_Secundary.Play(0, 0, DSBPLAY_FLAGS.DSBPLAY_LOOPING) = DS_OK Then
    61. End If
    62. End If
    63. End If
    64. End If
    65. End If
    66. End If
    67. End If
    68. End If
    69. End If
    70. End Sub
    71. Protected Overrides Sub Finalize()
    72. If m_IDirectSound8 IsNot Nothing Then
    73. If m_IDirectSoundBuffer_Secundary IsNot Nothing Then
    74. Marshal.ReleaseComObject(m_IDirectSoundBuffer_Secundary)
    75. m_IDirectSoundBuffer_Secundary = Nothing
    76. End If
    77. If m_IDirectSoundBuffer_Primary IsNot Nothing Then
    78. Marshal.ReleaseComObject(m_IDirectSoundBuffer_Primary)
    79. m_IDirectSoundBuffer_Primary = Nothing
    80. End If
    81. Marshal.ReleaseComObject(m_IDirectSound8)
    82. m_IDirectSound8 = Nothing
    83. End If
    84. MyBase.Finalize()
    85. End Sub
    86. #End Region
    87. #Region "Enums"
    88. Private Enum DSBLOCK_FLAG As Integer
    89. DSBLOCK_NONE = &H0
    90. DSBLOCK_FROMWRITECURSOR = &H1
    91. DSBLOCK_ENTIREBUFFER = &H2
    92. End Enum
    93. Private Enum DSSCL_FLAG As Integer
    94. DSSCL_NONE = &H0
    95. DSSCL_NORMAL = &H1
    96. DSSCL_PRIORITY = &H2
    97. DSSCL_EXCLUSIVE = &H3
    98. DSSCL_WRITEPRIMARY = &H4
    99. End Enum
    100. Private Enum DSBPLAY_FLAGS As Integer
    101. DSBPLAY_NONE = &H0
    102. DSBPLAY_LOOPING = &H1
    103. 'DSBPLAY_LOCHARDWARE = &H2
    104. 'DSBPLAY_LOCSOFTWARE = &H4
    105. 'DSBPLAY_TERMINATEBY_TIME = &H8
    106. 'DSBPLAY_TERMINATEBY_DISTANCE = &H10
    107. 'DSBPLAY_TERMINATEBY_PRIORITY = &H20
    108. End Enum
    109. Private Enum DSBSTATUS
    110. DSBSTATUS_NONE = &H0
    111. DSBSTATUS_PLAYING = &H1
    112. DSBSTATUS_BUFFERLOST = &H2
    113. DSBSTATUS_LOOPING = &H4
    114. DSBSTATUS_LOCHARDWARE = &H8
    115. DSBSTATUS_LOCSOFTWARE = &H10
    116. DSBSTATUS_TERMINATED = &H20
    117. End Enum
    118. Private Enum DSBCAPS_FLAGS As Integer
    119. DSBCAPS_NONE = &H0
    120. DSBCAPS_PRIMARYBUFFER = &H1
    121. DSBCAPS_STATIC = &H2
    122. DSBCAPS_LOCHARDWARE = &H4
    123. DSBCAPS_LOCSOFTWARE = &H8
    124. DSBCAPS_CTRL3D = &H10
    125. DSBCAPS_CTRLFREQUENCY = &H20
    126. DSBCAPS_CTRLPAN = &H40
    127. DSBCAPS_CTRLVOLUME = &H80
    128. DSBCAPS_CTRLPOSITIONNOTIFY = &H100
    129. DSBCAPS_CTRLFX = &H200
    130. DSBCAPS_STICKYFOCUS = &H4000
    131. DSBCAPS_GLOBALFOCUS = &H8000
    132. DSBCAPS_GETCURRENTPOSITION2 = &H10000
    133. DSBCAPS_MUTE3DATMAXDISTANCE = &H20000
    134. DSBCAPS_LOCDEFER = &H40000
    135. DSBCAPS_TRUEPLAYPOSITION = &H80000
    136. End Enum
    137. #End Region
    138. #Region "Consts"
    139. Private Const DS_OK As Integer = 0
    140. Private Const WAVE_FORMAT_PCM As Integer = 1
    141. ' IDirectSoundBuffer.SetVolume Min/Max
    142. Private Const DSBVOLUME_MAX As Long = 0
    143. Private Const DSBVOLUME_MIN As Long = -10000
    144. ' IDirectSoundBuffer.SetFrequency Min/Max
    145. Private Const DSBFREQUENCY_ORIGINAL As Integer = 0
    146. Private Const DSBFREQUENCY_MIN As Integer = 100
    147. Private Const DSBFREQUENCY_MAX As Integer = 100000
    148. ' IDirectSoundBuffer.SetPan Min/Max
    149. Private Const DSBPAN_LEFT As Long = -10000
    150. Private Const DSBPAN_CENTER As Long = 0
    151. Private Const DSBPAN_RIGHT As Long = 10000
    152. Private Const DSDEVID_DefaultPlayback As String = "def00000-9c6d-47ed-aaf1-4Dda8f2b5c03"
    153. Private Const IID_IDirectSound8 As String = "c50a7e93-f395-4834-9ef6-7fa99de50966"
    154. Private Const IID_IDirectSoundBuffer As String = "279afa85-4981-11ce-a521-0020af0be560"
    155. #End Region
    156. #Region "Variables"
    157. Private m_IDirectSound8 As IDirectSound8
    158. Private m_IDirectSoundBuffer_Primary As IDirectSoundBuffer
    159. Private m_IDirectSoundBuffer_Secundary As IDirectSoundBuffer
    160. #End Region
    161. #Region "Structures"
    162. Private Structure WAVEFORMATEX
    163. Dim wFormatTag As Short
    164. Dim nChannels As Short
    165. Dim nSamplesPerSec As Integer
    166. Dim nAvgBytesPerSec As Integer
    167. Dim nBlockAlign As Short
    168. Dim wBitsPerSample As Short
    169. Dim cbSize As Short
    170. End Structure
    171. Private Structure DSBUFFERDESC
    172. Dim dwSize As Integer
    173. Dim dwFlags As DSBCAPS_FLAGS
    174. Dim dwBufferBytes As Integer
    175. Dim dwReserved As Integer
    176. Dim lpwfxFormat As IntPtr '<- WAVEFORMATEX
    177. Dim guid3DAlgorithm As Guid
    178. End Structure
    179. #End Region
    180. #Region "Interface IDirectSound8"
    181. <ComImport>
    182. <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    183. <Guid(IID_IDirectSound8)>
    184. Private Interface IDirectSound8
    185. <PreserveSig> Function CreateSoundBuffer(<[In]> ByRef pcDSBufferDesc As DSBUFFERDESC,
    186. <Out, MarshalAs(UnmanagedType.Interface)> ByRef ppDSBuffer As IDirectSoundBuffer,
    187. <[In]> pUnkOuter As IntPtr) As Integer
    188. <PreserveSig> Function GetCaps() As Integer
    189. <PreserveSig> Function DuplicateSoundBuffer() As Integer
    190. <PreserveSig> Function SetCooperativeLevel(<[In]> hwnd As IntPtr,
    191. <[In]> dwLevel As DSSCL_FLAG) As Integer
    192. <PreserveSig> Function Compact() As Integer
    193. <PreserveSig> Function GetSpeakerConfig() As Integer
    194. <PreserveSig> Function SetSpeakerConfig() As Integer
    195. <PreserveSig> Function Initialize() As Integer
    196. <PreserveSig> Function VerifyCertification() As Integer
    197. End Interface
    198. #End Region
    199. #Region "Interface IDirectSoundBuffer"
    200. <ComImport>
    201. <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    202. <Guid(IID_IDirectSoundBuffer)>
    203. Private Interface IDirectSoundBuffer
    204. <PreserveSig> Function GetCaps() As Integer
    205. <PreserveSig> Function GetCurrentPosition() As Integer
    206. <PreserveSig> Function GetFormat() As Integer
    207. <PreserveSig> Function GetVolume() As Integer
    208. <PreserveSig> Function GetPan() As Integer
    209. <PreserveSig> Function GetFrequency() As Integer
    210. <PreserveSig> Function GetStatus(<Out> ByRef lpdwStatus As DSBSTATUS) As Integer
    211. <PreserveSig> Function Initialize() As Integer
    212. <PreserveSig> Function Lock(<[In]> dwOffset As Integer,
    213. <[In]> dwBytes As Integer,
    214. <Out> ByRef ppvAudioPtr1 As IntPtr,
    215. <Out> ByRef pdwAudioBytes1 As Integer,
    216. <Out> ByRef ppvAudioPtr2 As IntPtr,
    217. <Out> ByRef pdwAudioBytes2 As Integer,
    218. <[In]> dwFlags As DSBLOCK_FLAG) As Integer
    219. <PreserveSig> Function Play(<[In]> dwReserved1 As Integer,
    220. <[In]> dwReserved2 As Integer,
    221. <[In]> dwFlags As DSBPLAY_FLAGS) As Integer
    222. <PreserveSig> Function SetCurrentPosition(<[In]> dwNewPosition As Integer) As Integer
    223. <PreserveSig> Function SetFormat(<[In]> ByRef pcfxFormat As WAVEFORMATEX) As Integer
    224. <PreserveSig> Function SetVolume(<[In]> lVolume As Long) As Integer
    225. <PreserveSig> Function SetPan(<[In]> lPan As Long) As Integer
    226. <PreserveSig> Function SetFrequency(<[In]> dwFrequency As Integer) As Integer
    227. <PreserveSig> Function [Stop]() As Integer
    228. <PreserveSig> Function Unlock(<[In]> pvAudioPtr1 As IntPtr,
    229. <[In]> dwAudioBytes1 As Integer,
    230. <[In]> pvAudioPtr2 As IntPtr,
    231. <[In]> dwAudioBytes2 As Integer) As Integer
    232. <PreserveSig> Function Restore() As Integer
    233. End Interface
    234. #End Region
    235. End Class


    Denke das das ganze einfach zu verstehen ist. Für jede weitere Frequenz erzeugst Du einfach weitere Secundary DirectSoundBuffer per DirectSound8.CreateSoundBuffer, füllst diese mit Daten und DirectSoundBuffer.Play/Stop usw. Volume, Panning und Pitsch (SetFrequency) kannst Du vorher einstellen und auch wenn der DirectSoundBuffer abgespielt wird.
    Mfg -Franky-
    Vielen Dank für die Übersetzung.

    Wenn ich etwas funktionierendes gebastelt habe, kann ich es ja hier reinsetzen.

    Das wird aber etwas dauern. Ich muß zuerst den Text aufbereiten, beispielsweise die Zeilennummer und in jeder Zeile das Thema entfernen, dann in meine Oberfläche einbinden, den Code begreifen und etwas funktionierendes bauen.

    -----

    Inzwischen habe ich etwas mit Erfolg ausprobiert.

    Ich habe die Funktion

    VB.NET-Quellcode

    1. Private Function StreamProcCallback(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Integer

    dupliziert. Jede dieser Funktionen erzeugt eine unterschiedliche Frequenz. Wenn ich nun beide aufrufe, höre ich auch zwei unterschiedliche Töne, so wie ich es eigentlich auch haben möchte. Allerdings weiß ich leider immer noch nicht, wie ich den Wert der Frequenz in eine Variable packen kann. An der Zahl klebt noch ein "D" und ich weiß nicht, wie ich solch eine Zahl generieren kann.

    VB.NET-Quellcode

    1. Dim waveFrequencyLeft As Double = 100D 'frequenz in Hz linker Kanal


    Hat jemand eine Idee, wie solche Zahlen konvertiert bzw erzeugt werden?

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

    @tron25 So:

    VB.NET-Quellcode

    1. Dim waveFrequencyLeft As Double = 100
    Das As Double und das D-Appendix sind redundant.
    Wo liegt das Problem?
    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!
    So, jetzt werden sich einige von euch die Hände beim Anblick des folgenden Codes über dem Kopf zusammenschlagen, aber es funktioniert.

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Imports Un4seen.Bass
    3. Public Class MultiBeepFormular
    4. 'handle für den audio stream
    5. Private Links1StreamHandle As Integer = 0
    6. Private Links2StreamHandle As Integer = 0
    7. 'STREAMPROC delegate, "zeigt" dann auf die angegebene Funktion die dann
    8. 'regelmäßig gecallt wird
    9. Private Links1StreamProc As STREAMPROC
    10. Private Links2StreamProc As STREAMPROC
    11. Dim Links1Frequenz As Double = 100
    12. Dim Links2Frequenz As Double = 1200
    13. Dim Links1Lautstaerke As Double = 0.2
    14. Dim Links2Lautstaerke As Double = 0.2
    15. Dim Samplingrate As Double = 44100
    16. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    17. End
    18. End Sub
    19. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    20. If Not Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_CPSPEAKERS, IntPtr.Zero) Then
    21. MessageBox.Show($"BASS Initialisierungsfehler: { Bass.BASS_ErrorGetCode() }")
    22. Application.Exit()
    23. End If
    24. End Sub
    25. Private Function Links1TonErzeugen(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Integer
    26. 'einen puffer anlegen um Daten aus und in den Speicher zu kopieren
    27. Dim buff As Byte() = New Byte(length) {}
    28. 'die Daten aus dem Speicher in unseren Puffer kopieren, die Daten sind "stumm" weil nichts im Stream zum abspielen da ist
    29. Marshal.Copy(buffer, buff, 0, length)
    30. 'die einzelnen Samples erstellen, jedes Sample besteht aus 8 Bytes, je 2 Singles(2x 4 Bytes), je einmal für links und einmal für rechts
    31. For i As Integer = 0 To buff.Length - 9 Step 8
    32. Dim Links As Single = CSng(Math.Sin(i / 8D * 2D * Math.PI * Links1Frequenz / Samplingrate) * Links1Lautstaerke)
    33. Dim Rechts As Single = CSng(Math.Sin(i / 8D * 2D * Math.PI * 0 / Samplingrate) * 0)
    34. 'die bytes für den Puffer
    35. Dim LinksBytes As Byte() = BitConverter.GetBytes(Links)
    36. Dim RechtsBytes As Byte() = BitConverter.GetBytes(Rechts)
    37. 'die bytes in unseren Puffer kopieren
    38. Array.Copy(LinksBytes, 0, buff, i, 4)
    39. Array.Copy(RechtsBytes, 0, buff, i + 4, 4)
    40. Next
    41. 'die Daten aus unseren Puffer in den Speicher kopieren, damit sie nun abgespielt werden können.
    42. Marshal.Copy(buff, 0, buffer, length)
    43. Return length
    44. End Function
    45. Private Function Links2TonErzeugen(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Integer
    46. 'einen puffer anlegen um Daten aus und in den Speicher zu kopieren
    47. Dim buff As Byte() = New Byte(length) {}
    48. 'die Daten aus dem Speicher in unseren Puffer kopieren, die Daten sind "stumm" weil nichts im Stream zum abspielen da ist
    49. Marshal.Copy(buffer, buff, 0, length)
    50. 'die einzelnen Samples erstellen, jedes Sample besteht aus 8 Bytes, je 2 Singles(2x 4 Bytes), je einmal für links und einmal für rechts
    51. For i As Integer = 0 To buff.Length - 9 Step 8
    52. Dim Links As Single = CSng(Math.Sin(i / 8D * 2D * Math.PI * Links2Frequenz / Samplingrate) * Links2Lautstaerke)
    53. Dim Rechts As Single = CSng(Math.Sin(i / 8D * 2D * Math.PI * 0 / Samplingrate) * 0)
    54. 'die bytes für den Puffer
    55. Dim LinksBytes As Byte() = BitConverter.GetBytes(Links)
    56. Dim RechtsBytes As Byte() = BitConverter.GetBytes(Rechts)
    57. 'die bytes in unseren Puffer kopieren
    58. Array.Copy(LinksBytes, 0, buff, i, 4)
    59. Array.Copy(RechtsBytes, 0, buff, i + 4, 4)
    60. Next
    61. 'die Daten aus unseren Puffer in den Speicher kopieren, damit sie nun abgespielt werden können.
    62. Marshal.Copy(buff, 0, buffer, length)
    63. Return length
    64. End Function
    65. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    66. Bass.BASS_ChannelStop(Links1StreamHandle)
    67. Links1StreamProc = Nothing
    68. Bass.BASS_StreamFree(Links1StreamHandle)
    69. Bass.BASS_ChannelStop(Links2StreamHandle)
    70. Links2StreamProc = Nothing
    71. Bass.BASS_StreamFree(Links2StreamHandle)
    72. End Sub
    73. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    74. 'neues STREAMPROC, "zeigt" auf die Sub StreamProcCallback
    75. Links1StreamProc = New STREAMPROC(AddressOf Links1TonErzeugen)
    76. Links2StreamProc = New STREAMPROC(AddressOf Links2TonErzeugen)
    77. 'das handle für den Stream erstellen
    78. Links1StreamHandle = Bass.BASS_StreamCreate(CInt(Samplingrate), 2, BASSFlag.BASS_SAMPLE_FLOAT, Links1StreamProc, IntPtr.Zero)
    79. Links2StreamHandle = Bass.BASS_StreamCreate(CInt(Samplingrate), 2, BASSFlag.BASS_SAMPLE_FLOAT, Links2StreamProc, IntPtr.Zero)
    80. 'den stream starten
    81. Bass.BASS_ChannelPlay(Links1StreamHandle, False)
    82. Bass.BASS_ChannelPlay(Links2StreamHandle, False)
    83. End Sub
    84. End Class

    Wenn ich die Funktion für jeden Ton mit neuen Werten aufrufe, werden die Frequenzen nicht gleichzeitig abgespielt. Daher habe ich eine Funktion für jeden einzelnen Ton.
    Ich werde das Ganze nun für 5 Töne auf jedem Ohr ausweiten.

    -Franky- schrieb:

    Es ist mir schon klar das diese Webanwendungen für Dich ungeeignet sind.
    Na, wenn das so ist, kann mein Werk ja doch noch was nütze sein.

    rechts wählt man einen Output an.
    Jeder Output hat zwei Akkorde (links, rechts)
    Jeder Akkord hat keinen bis viele Töne, sowie eine Lautstärke.
    Jeder Ton hat Frequenz und Lautstärken-Anteil.
    Beachte die Warnung aus der Browser-App: Mit Kopfhörer kann man schon bei moderater Lautstärke bei höheren Frequenzen Hz sich das Ohr beschädigen.
    Das ist tückisch: tiefe Töne muss man laut drehen, aber wenn man dann die Frequenz erhöht sollte man vorher die Lautstärke drastisch runterdrehen.

    Und ich zumindest brauch die Anwendung garnet. Hier mein Browser-App-Tinnitus: MyTinnitus
    Und solche Links kann man sich ja mehrere zurücklegen
    Dateien
    • Tinnitus08.zip

      (237,61 kB, 42 mal heruntergeladen, zuletzt: )

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

    Vielen Dank für dein Programm. Ich habe allerdings noch einige Schwierigkeiten, es zu öffnen.
    Erst einmal kann ich keine Formularansicht aktivieren. Außerdem bekomme ich folgende Fehlermeldungen:

    "JsonConvert" wurde nicht deklariert. Aufgrund der Schutzstufe ist unter Umständen kein Zugriff möglich. GeneralHelpers D:\Programmierung\Tinnitus08\_AllHelpers\GeneralHelpers\System\ObjectX.vb 11

    "Formatting" wurde nicht deklariert. Aufgrund der Schutzstufe ist unter Umständen kein Zugriff möglich. GeneralHelpers D:\Programmierung\Tinnitus08\_AllHelpers\GeneralHelpers\System\ObjectX.vb 11

    Die Datei "MyControls\CheckMenu.resx" konnte nicht verarbeitet werden, weil sie sich im Internet oder in der Zone eingeschränkter Websites befindet oder die Webmarkierung aufweist. Entfernen Sie die Webmarkierung, wenn Sie diese Dateien verarbeiten möchten. WinFormHelpers

    (aktiv) BC2017 Bibliothek "D:\Programmierung\Tinnitus08\_AllHelpers\GeneralHelpers\bin\Debug\GeneralHelpersVb.dll" wurde nicht gefunden Tinnitus D:\Programmierung\Tinnitus08\Tinnitus\Tinnitus\vbc 1

    (aktiv) BC2017 Bibliothek "D:\Programmierung\Tinnitus08\_AllHelpers\WinFormHelpers\bin\Debug\WinFormHelpers.dll" wurde nicht gefunden Tinnitus D:\Programmierung\Tinnitus08\Tinnitus\Tinnitus\vbc 1

    Die Komponente "Newtonsoft.Json", auf die verwiesen wird, wurde nicht gefunden. GeneralHelpers

    (aktiv) BC40056 Der in Imports "Newtonsoft.Json" angegebene Namespace oder Typ enthält keine öffentlichen Member oder kann nicht gefunden werden. Stellen Sie sicher, dass der Namespace oder der Typ definiert ist und mindestens einen öffentlichen Member enthält, und dass der importierte Elementname keine Aliase verwendet. GeneralHelpers D:\Programmierung\Tinnitus08\_AllHelpers\GeneralHelpers\System\ObjectX.vb 4

    Hast du einen Tipp, woran es liegen könnte?
    • .resx-Dateien werden bei entsprechender Sicherheits-Stufe vom System gesperrt. Da kannste im Explorer nach "*.resx" suchen, und bei allen gefundenen Dateien in den Datei-Eigenschaften iwas mit Internet und "zulassen" klicksen.
    • Der Json-Kram erfordert, dass du die Nuget-Packete refreshst.
      (Allerdings zickt Nuget bei mir gerne herum. Alternativ kannste den Verweis auf NewtonSoft auch rauswerfen, und alle Codestellen löschen, wo iwas mit NewtonSoft und Json vorkommt - weil wird hier garnet gebraucht.)

    Ich hoffe, dann gehts, und das andere seien nur FolgeFehler.
    Den Internetzugriff habe ich bei allen .resx-Dateien angehakt. Dann habe ich auch den nuget-Verweis entfernt. Nun habe ich noch folgende Meldung:

    System.BadImageFormatException
    HResult=0x8007000B
    Nachricht = Es wurde versucht, eine Datei mit einem falschen Format zu laden. (Ausnahme von HRESULT: 0x8007000B)
    Quelle = ManagedBass
    Stapelüberwachung:
    bei ManagedBass.Bass.Init(Int32 Device, Int32 Frequency, DeviceInitFlags Flags, IntPtr Win, IntPtr ClsID)
    bei Tinnitus.Program.Main(String[] args) in D:\Programmierung\Tinnitus08\Tinnitus\Tinnitus\Program.vb: Zeile28

    Wie kann ich dieses Problem noch lösen?
    da hast du wohl die falsche bass.dll in deim bin\debug - Ordner.
    Ich hab die bass.dll ja per Nuget "installiert", und dabei ist auch ein "Native"-Ordner mitgekommen,und aus dem muss die bass.dll kommen.
    Bei mir ist das: "...\Tinnitus\packages\BASS.Native.2.4.13.10\build\native\x64\bass.dll"
    Die ist 250Kb gross.