Soundaufnahme, Systemsound, Mikrofon etc...

    • VB.NET
    • .NET (FX) 4.0

    Es gibt 1 Antwort in diesem Thema. Der letzte Beitrag () ist von NoIde.

      Soundaufnahme, Systemsound, Mikrofon etc...

      Hi,

      nachdem mal wieder die Frage kam, wie man denn den Sound des Systems aufnehmen kann, wie (oder auch)auch das Device welches aufgenommen werden soll festlegen kann und ich auf ein altes Beispiel(VB6) verwiesen habe, dachte ich mir, ich mach mal ein zeitgemässes Beispiel. Mit diesem Codeschnipsel ist es möglich, den Sound von Mikrofonen, Line-Ins oder jedem Loopback-Device(Wiedergabegeräte) aufzunehen. Sollte mit jedem Windows-OS ab Vista/Win7 funktionieren.

      Mit konvertierung ins mp3-format siehe 2. post

      Benötigt werden folgende DLLs welche bei un4seen.com erhält sind:
      bassnet.dll 'verweis auf die bassnet.dll hinzufügen!
      bass.dll
      bassenc.dll
      basswasapi.dll

      VB.NET-Quellcode

      1. Imports Un4seen.Bass
      2. Imports Un4seen.Bass.AddOn.Enc
      3. Imports Un4seen.BassWasapi
      4. Public Class FormMain
      5. 'links zur dokumentation
      6. 'BASS_Init http://bass.radio42.com/help/html/ad9238db-aafe-e4fc-88c9-ceae2fd3eeea.htm
      7. 'WASAPIPROC http://www.bass.radio42.com/help/html/0d1b4edc-3396-4fce-f7c1-3483ce83b641.htm
      8. 'BASS_WASAPI_DEVICEINFO http://www.bass.radio42.com/help/html/559b8efe-a0a6-6e52-a025-864c30e460de.htm
      9. 'BASS_WASAPI_Init http://www.bass.radio42.com/help/html/6ad6926e-179a-6b10-3748-50dab4b07f8d.htm
      10. 'BASS_StreamCreate http://bass.radio42.com/help/html/a9731743-19e1-27d5-c7a8-6f597f533537.htm
      11. 'Bass klasse http://www.bass.radio42.com/help/html/8f455613-bc52-0829-5d87-aedf2f8d99f5.htm
      12. Private Proc As WASAPIPROC 'WasapiProc Delegate
      13. Private Dummy As Integer = 0 'stream handle
      14. Private Devices As New List(Of Device) 'liste verfügbarer devices
      15. Private CurrentDevice As Integer = -1 'aktuelles device = deafult
      16. Private Inlevel As Single 'luautstärke pegel
      17. Private RecordStartTime As DateTime
      18. Private RecordingActive As Boolean = False
      19. Private Sub FormMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
      20. 'aufräumen
      21. BassWasapi.BASS_WASAPI_Stop(True)
      22. BassWasapi.BASS_WASAPI_Free()
      23. Bass.BASS_StreamFree(Dummy)
      24. Bass.BASS_Free()
      25. End Sub
      26. Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      27. 'bass mit "no sound" initialisieren, da wir nichts wiedergeben
      28. Bass.BASS_Init(0, 0, 0, Nothing)
      29. Proc = New WASAPIPROC(AddressOf InWasapiProc)
      30. 'für device-informationen
      31. Dim devInfo As New BASS_WASAPI_DEVICEINFO
      32. Dim note As Integer = -1
      33. 'alle verfügbaren devices durchlaufen
      34. For i As Integer = 0 To BassWasapi.BASS_WASAPI_GetDeviceCount() - 1
      35. 'device informationen hohlen
      36. BassWasapi.BASS_WASAPI_GetDeviceInfo(i, devInfo)
      37. 'ist es ein input device, wie auch aktiv?
      38. If (devInfo.flags And BASSWASAPIDeviceInfo.BASS_DEVICE_INPUT) = BASSWASAPIDeviceInfo.BASS_DEVICE_INPUT _
      39. AndAlso (devInfo.flags And BASSWASAPIDeviceInfo.BASS_DEVICE_ENABLED) = BASSWASAPIDeviceInfo.BASS_DEVICE_ENABLED Then
      40. 'device in die auflistung
      41. Devices.Add(New Device(i, devInfo.name))
      42. 'device initialisieren
      43. BassWasapi.BASS_WASAPI_Init(i, 0, 0, 0, 0.5, 0, Proc, Nothing)
      44. 'wenn ein loopback device aufgenommen werden soll, dann muss das korrespondierende
      45. 'output-device initilisiert werden, da sonst nicht dauerhaft gelauscht wird, sondern
      46. 'nur wenn ein buffer vorhanden ist, somit würde stille nicht aufgezeichnet werden,
      47. 'das korrespondierende output-device ist immer loopbackdevice.index - 1
      48. If devInfo.IsLoopback Then
      49. BassWasapi.BASS_WASAPI_Init(i - 1, 0, 0, 0, 0, 0, Nothing, Nothing)
      50. End If
      51. BassWasapi.BASS_WASAPI_SetDevice(i)
      52. 'is es das default device?
      53. If ((devInfo.flags And BASSWASAPIDeviceInfo.BASS_DEVICE_DEFAULT) = BASSWASAPIDeviceInfo.BASS_DEVICE_DEFAULT) Then
      54. CurrentDevice = i
      55. note = Devices.Count - 1
      56. End If
      57. End If
      58. Next
      59. ComboBoxDevices.DataSource = Devices
      60. ComboBoxDevices.DisplayMember = "Name"
      61. If note > -1 Then
      62. ComboBoxDevices.SelectedIndex = note
      63. End If
      64. End Sub
      65. Private Function InWasapiProc(ByVal buffer As IntPtr, ByVal length As Integer, ByVal user As IntPtr) As Integer
      66. 'daten in den dummy stream schreiben
      67. Bass.BASS_ChannelGetData(Dummy, buffer, length)
      68. 'lautststärke pegel hohlen
      69. Dim level As Single = BassWasapi.BASS_WASAPI_GetDeviceLevel(CurrentDevice, -1) '-1 alle kanäle des devices
      70. 'wurde im Beispiel "basswasapi.zip/vb/rectest" so gemacht
      71. 'keine Ahnung warum, aber ich habs einfach übernommen
      72. If Inlevel > 0.1 Then
      73. Inlevel -= 0.1F
      74. Else
      75. Inlevel = 0.0F
      76. End If
      77. If level > Inlevel Then
      78. Inlevel = level
      79. End If
      80. If Inlevel > 1.0F Then 'um sicher zu sein, da progressbar.Maximum = 100 ist
      81. Inlevel = 1.0F
      82. End If
      83. BeginInvoke(Sub()
      84. ProgressBarLevel.Value = CInt(Inlevel * 100)
      85. If RecordingActive Then
      86. LabelRecordDuration.Text = (Now - RecordStartTime).ToString("hh\:mm\:ss\.ff")
      87. Else
      88. LabelRecordDuration.Text = "00:00:00.00"
      89. End If
      90. End Sub)
      91. Return 1
      92. End Function
      93. Private Sub ComboBoxDevices_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBoxDevices.SelectedIndexChanged
      94. 'abhorchen beenden
      95. If BassWasapi.BASS_WASAPI_IsStarted Then
      96. BassWasapi.BASS_WASAPI_Stop(True)
      97. End If
      98. Dummy = 0
      99. CurrentDevice = DirectCast(ComboBoxDevices.SelectedItem, Device).Index
      100. 'aktuelles device festlegen
      101. BassWasapi.BASS_WASAPI_SetDevice(CurrentDevice)
      102. 'device informationen beschaffen
      103. Dim devInfo As New BASS_WASAPI_DEVICEINFO
      104. BassWasapi.BASS_WASAPI_GetDeviceInfo(CurrentDevice, devInfo)
      105. 'dummy stream erstellen
      106. Dummy = Bass.BASS_StreamCreate(devInfo.mixfreq, devInfo.mixchans, BASSFlag.BASS_SAMPLE_FLOAT Or BASSFlag.BASS_STREAM_DECODE, BASSStreamProc.STREAMPROC_DUMMY)
      107. 'abhorchen
      108. BassWasapi.BASS_WASAPI_Start()
      109. Dim devType As String
      110. Select Case devInfo.type
      111. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_NETWORKDEVICE
      112. devType = "Remote Network Device"
      113. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_SPEAKERS
      114. devType = "Speakers"
      115. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_LINELEVEL
      116. devType = "Line In"
      117. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_HEADPHONES
      118. devType = "Headphones"
      119. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_MICROPHONE
      120. devType = "Microphone"
      121. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_HEADSET
      122. devType = "Headset"
      123. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_HANDSET
      124. devType = "Handset"
      125. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_DIGITAL
      126. devType = "Digital"
      127. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_SPDIF
      128. devType = "SPDIF"
      129. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_HDMI
      130. devType = "HDMI"
      131. Case Else
      132. devType = "undefined"
      133. End Select
      134. If (devInfo.flags And BASSWASAPIDeviceInfo.BASS_DEVICE_LOOPBACK) = BASSWASAPIDeviceInfo.BASS_DEVICE_LOOPBACK Then
      135. devType &= " (Playback-Device)"
      136. Else
      137. devType &= " (Input-Device)"
      138. End If
      139. LabelRecordDuration.Text = devType
      140. End Sub
      141. Private Class Device
      142. Public Property Index As Integer
      143. Public Property Name As String
      144. Public Sub New()
      145. End Sub
      146. Public Sub New(ByVal index As Integer, ByVal name As String)
      147. Me.Index = index
      148. Me.Name = name
      149. End Sub
      150. End Class
      151. Private Sub ButtonRecordStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonRecordStart.Click
      152. RecordingActive = True
      153. ComboBoxDevices.Enabled = Not RecordingActive
      154. ButtonRecordStop.Enabled = RecordingActive
      155. ButtonRecordStart.Enabled = Not RecordingActive
      156. RecordStartTime = Now
      157. 'aufnahme starten(aufzeichnung in datei)
      158. BassEnc.BASS_Encode_Start(Dummy, "output.wav", BASSEncode.BASS_ENCODE_PCM Or BASSEncode.BASS_ENCODE_FP_16BIT Or BASSEncode.BASS_ENCODE_AUTOFREE, Nothing, Nothing)
      159. End Sub
      160. Private Sub ButtonRecordStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonRecordStop.Click
      161. RecordingActive = False
      162. ComboBoxDevices.Enabled = Not RecordingActive
      163. ButtonRecordStop.Enabled = RecordingActive
      164. ButtonRecordStart.Enabled = Not RecordingActive
      165. 'aufnahme stoppen(aufzeichnung in datei)
      166. BassEnc.BASS_Encode_Stop(Dummy)
      167. End Sub
      168. End Class
      Dateien
      Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
      „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
      Benjamin Franklin

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

      Soundaufnahme, Systemsound, Mikrofon etc... mit konvertierung

      Es besteht auch die möglichkeit im mp3-format aufzunehmen, dazu müsst ihr euch die lame.exe herunterladen, die lame.exe und die lame_enc.dll zusätzlich jeweils in den debug und release ordner hinzufügen.

      'hierfür könnt ihr die Projektmappe auf dem 1. Post nehmen.

      VB.NET-Quellcode

      1. Imports Un4seen.Bass
      2. Imports Un4seen.Bass.AddOn.Enc
      3. Imports Un4seen.Bass.Misc
      4. Imports Un4seen.BassWasapi
      5. Imports Un4seen.Bass.AddOn.Tags
      6. Public Class FormMain
      7. 'links zur dokumentation
      8. 'BASS_Init http://bass.radio42.com/help/html/ad9238db-aafe-e4fc-88c9-ceae2fd3eeea.htm
      9. 'WASAPIPROC http://www.bass.radio42.com/help/html/0d1b4edc-3396-4fce-f7c1-3483ce83b641.htm
      10. 'BASS_WASAPI_DEVICEINFO http://www.bass.radio42.com/help/html/559b8efe-a0a6-6e52-a025-864c30e460de.htm
      11. 'BASS_WASAPI_Init http://www.bass.radio42.com/help/html/6ad6926e-179a-6b10-3748-50dab4b07f8d.htm
      12. 'BASS_StreamCreate http://bass.radio42.com/help/html/a9731743-19e1-27d5-c7a8-6f597f533537.htm
      13. 'Bass klasse http://www.bass.radio42.com/help/html/8f455613-bc52-0829-5d87-aedf2f8d99f5.htm
      14. Private Proc As WASAPIPROC 'WasapiProc Delegate
      15. Private Dummy As Integer = 0 'stream handle
      16. Private Devices As New List(Of Device) 'liste verfügbarer devices
      17. Private CurrentDevice As Integer = -1 'aktuelles device = deafult
      18. Private Inlevel As Single 'lautstärke pegel
      19. Private RecordStartTime As DateTime
      20. Private RecordingActive As Boolean = False
      21. Private LameEncoder As EncoderLAME
      22. Private Sub FormMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
      23. 'aufräumen
      24. BassWasapi.BASS_WASAPI_Stop(True)
      25. BassWasapi.BASS_WASAPI_Free()
      26. Bass.BASS_StreamFree(Dummy)
      27. Bass.BASS_Free()
      28. End Sub
      29. Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      30. 'bass mit "no sound" initialisieren, da wir nichts wiedergeben
      31. Bass.BASS_Init(0, 0, 0, Nothing)
      32. Proc = New WASAPIPROC(AddressOf InWasapiProc)
      33. 'für device-informationen
      34. Dim devInfo As New BASS_WASAPI_DEVICEINFO
      35. Dim note As Integer = -1
      36. 'alle verfügbaren devices durchlaufen
      37. For i As Integer = 0 To BassWasapi.BASS_WASAPI_GetDeviceCount() - 1
      38. 'device informationen hohlen
      39. BassWasapi.BASS_WASAPI_GetDeviceInfo(i, devInfo)
      40. 'ist es ein input device, wie auch aktiv?
      41. If (devInfo.flags And BASSWASAPIDeviceInfo.BASS_DEVICE_INPUT) = BASSWASAPIDeviceInfo.BASS_DEVICE_INPUT _
      42. AndAlso (devInfo.flags And BASSWASAPIDeviceInfo.BASS_DEVICE_ENABLED) = BASSWASAPIDeviceInfo.BASS_DEVICE_ENABLED Then
      43. 'device in die auflistung
      44. Devices.Add(New Device(i, devInfo.name))
      45. 'device initialisieren
      46. BassWasapi.BASS_WASAPI_Init(i, 0, 0, 0, 0.5, 0, Proc, Nothing)
      47. 'wenn ein loopback device aufgenommen werden soll, dann muss das korrespondierende
      48. 'output-device initilisiert werden, da sonst nicht dauerhaft gelauscht wird, sondern
      49. 'nur wenn ein buffer vorhanden ist, somit würde stille nicht aufgezeichnet werden,
      50. 'das korrespondierende output-device ist immer loopbackdevice.index - 1
      51. If devInfo.IsLoopback Then
      52. BassWasapi.BASS_WASAPI_Init(i - 1, 0, 0, 0, 0, 0, Nothing, Nothing)
      53. End If
      54. BassWasapi.BASS_WASAPI_SetDevice(i)
      55. 'is es das default device?
      56. If ((devInfo.flags And BASSWASAPIDeviceInfo.BASS_DEVICE_DEFAULT) = BASSWASAPIDeviceInfo.BASS_DEVICE_DEFAULT) Then
      57. CurrentDevice = i
      58. note = Devices.Count - 1
      59. End If
      60. End If
      61. Next
      62. ComboBoxDevices.DataSource = Devices
      63. ComboBoxDevices.DisplayMember = "Name"
      64. If note > -1 Then
      65. ComboBoxDevices.SelectedIndex = note
      66. End If
      67. End Sub
      68. Private Function InWasapiProc(ByVal buffer As IntPtr, ByVal length As Integer, ByVal user As IntPtr) As Integer
      69. 'daten in den dummy stream schreiben
      70. Bass.BASS_ChannelGetData(Dummy, buffer, length)
      71. 'lautststärke pegel hohlen
      72. Dim level As Single = BassWasapi.BASS_WASAPI_GetDeviceLevel(CurrentDevice, -1) '-1 alle kanäle des devices
      73. 'wurde im Beispiel "basswasapi.zip/vb/rectest" so gemacht
      74. 'keine Ahnung warum, aber ich habs einfach übernommen
      75. If Inlevel > 0.1 Then
      76. Inlevel -= 0.1F
      77. Else
      78. Inlevel = 0.0F
      79. End If
      80. If level > Inlevel Then
      81. Inlevel = level
      82. End If
      83. If Inlevel > 1.0F Then 'um sicher zu sein, da progressbar.Maximum = 100 ist
      84. Inlevel = 1.0F
      85. End If
      86. BeginInvoke(Sub()
      87. ProgressBarLevel.Value = CInt(Inlevel * 100)
      88. If RecordingActive Then
      89. LabelRecordDuration.Text = (Now - RecordStartTime).ToString("hh\:mm\:ss\.ff")
      90. Else
      91. LabelRecordDuration.Text = "00:00:00.00"
      92. End If
      93. End Sub)
      94. Return 1
      95. End Function
      96. Private Sub ComboBoxDevices_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBoxDevices.SelectedIndexChanged
      97. 'abhorchen beenden
      98. If BassWasapi.BASS_WASAPI_IsStarted Then
      99. BassWasapi.BASS_WASAPI_Stop(True)
      100. End If
      101. Dummy = 0
      102. CurrentDevice = DirectCast(ComboBoxDevices.SelectedItem, Device).Index
      103. 'aktuelles device festlegen
      104. BassWasapi.BASS_WASAPI_SetDevice(CurrentDevice)
      105. 'device informationen beschaffen
      106. Dim devInfo As New BASS_WASAPI_DEVICEINFO
      107. BassWasapi.BASS_WASAPI_GetDeviceInfo(CurrentDevice, devInfo)
      108. 'dummy stream erstellen
      109. Dummy = Bass.BASS_StreamCreate(devInfo.mixfreq, devInfo.mixchans, BASSFlag.BASS_SAMPLE_FLOAT Or BASSFlag.BASS_STREAM_DECODE, BASSStreamProc.STREAMPROC_DUMMY)
      110. 'abhorchen
      111. BassWasapi.BASS_WASAPI_Start()
      112. Dim devType As String
      113. Select Case devInfo.type
      114. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_NETWORKDEVICE
      115. devType = "Remote Network Device"
      116. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_SPEAKERS
      117. devType = "Speakers"
      118. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_LINELEVEL
      119. devType = "Line In"
      120. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_HEADPHONES
      121. devType = "Headphones"
      122. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_MICROPHONE
      123. devType = "Microphone"
      124. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_HEADSET
      125. devType = "Headset"
      126. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_HANDSET
      127. devType = "Handset"
      128. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_DIGITAL
      129. devType = "Digital"
      130. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_SPDIF
      131. devType = "SPDIF"
      132. Case BASSWASAPIDeviceType.BASS_WASAPI_TYPE_HDMI
      133. devType = "HDMI"
      134. Case Else
      135. devType = "undefined"
      136. End Select
      137. If (devInfo.flags And BASSWASAPIDeviceInfo.BASS_DEVICE_LOOPBACK) = BASSWASAPIDeviceInfo.BASS_DEVICE_LOOPBACK Then
      138. devType &= " (Playback-Device)"
      139. Else
      140. devType &= " (Input-Device)"
      141. End If
      142. LabelRecordDuration.Text = devType
      143. End Sub
      144. Private Class Device
      145. Public Property Index As Integer
      146. Public Property Name As String
      147. Public Sub New()
      148. End Sub
      149. Public Sub New(ByVal index As Integer, ByVal name As String)
      150. Me.Index = index
      151. Me.Name = name
      152. End Sub
      153. End Class
      154. Private Sub ButtonRecordStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonRecordStart.Click
      155. RecordingActive = True
      156. ComboBoxDevices.Enabled = Not RecordingActive
      157. ButtonRecordStop.Enabled = RecordingActive
      158. ButtonRecordStart.Enabled = Not RecordingActive
      159. RecordStartTime = Now
      160. 'aufnahme starten(aufzeichnung in datei)
      161. LameEncoder = New EncoderLAME(Dummy)
      162. LameEncoder.LAME_UseVBR = False
      163. LameEncoder.LAME_Bitrate = EncoderLAME.BITRATE.kbps_320
      164. LameEncoder.LAME_TargetSampleRate = EncoderLAME.SAMPLERATE.Hz_48000
      165. LameEncoder.LAME_Mode = EncoderLAME.LAMEMode.Stereo
      166. 'id3v2 tag für zieldatei
      167. Dim tag As New TAG_INFO()
      168. tag.tagType = BASSTag.BASS_TAG_ID3V2
      169. tag.title = "soundrecord " & Now.ToString("dd.MM.yyyy HH:mm:ss")
      170. tag.artist = Environment.MachineName
      171. tag.genre = "soundrecord"
      172. tag.album = "soundrecord"
      173. tag.albumartist = Environment.MachineName
      174. tag.track = "0"
      175. tag.disc = "0"
      176. tag.year = Now.Year.ToString()
      177. LameEncoder.TAGs = tag
      178. LameEncoder.OutputFile = "soundrecord_" & Now.ToString("dd_MM_yyyy___HH_mm_ss") & ".mp3"
      179. 'aufnahme starten(aufzeichnung in datei)
      180. LameEncoder.Start(Nothing, IntPtr.Zero, False)
      181. End Sub
      182. Private Sub ButtonRecordStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonRecordStop.Click
      183. RecordingActive = False
      184. ComboBoxDevices.Enabled = Not RecordingActive
      185. ButtonRecordStop.Enabled = RecordingActive
      186. ButtonRecordStart.Enabled = Not RecordingActive
      187. 'aufnahme stoppen(aufzeichnung in datei)
      188. If Not LameEncoder Is Nothing Then
      189. If LameEncoder.IsActive Then
      190. LameEncoder.Stop()
      191. End If
      192. End If
      193. End Sub
      194. End Class
      Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
      „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
      Benjamin Franklin