The client for Voice over IRC. Can't let those newfangled social networks win, eh?
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

audio.nim 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import sequtils
  2. import soundio
  3. var audioReaderFunc: proc(buffer: var seq[int16])
  4. var audioWriterFunc: proc(frameCountMin: int, frameCountMax: int): seq[int16]
  5. var audioBuffer = newSeq[int16](0)
  6. var sio: ptr SoundIo
  7. proc readCallback(inStream: ptr SoundIoInStream, frameCountMin: cint, frameCountMax: cint) {.cdecl.} =
  8. var areas: ptr SoundIoChannelArea
  9. var framesLeft = frameCountMax
  10. while true:
  11. var frameCount = framesLeft
  12. var err = inStream.begin_read(areas.addr, frameCount.addr)
  13. if frameCount <= 0:
  14. break
  15. for frame in 0..<frameCount:
  16. var ptrSample = cast[ptr int16](cast[int](areas.pointer) + frame*areas.step)
  17. audioBuffer.add(ptrSample[])
  18. err = inStream.end_read()
  19. framesLeft -= frameCount
  20. if framesLeft <= 0:
  21. break
  22. audioReaderFunc(audioBuffer)
  23. proc writeCallback(outStream: ptr SoundIoOutStream, frameCountMin: cint, frameCountMax: cint) {.cdecl.} =
  24. let data = audioWriterFunc(frameCountMin, frameCountMax)
  25. var areas: ptr SoundIoChannelArea
  26. var framesLeft = frameCountMax
  27. var framePos = 0
  28. while true:
  29. var frameCount = framesLeft
  30. var err = outStream.beginWrite(areas.addr, frameCount.addr)
  31. if frameCount <= 0:
  32. break
  33. let layout = outStream.layout
  34. for frame in 0..<frameCount:
  35. let sample = data[framePos + frame]
  36. for channel in 0..<layout.channelCount:
  37. let ptrArea = cast[ptr SoundIoChannelArea](cast[int](areas) + channel * (sizeof SoundIoChannelArea))
  38. var ptrSample = cast[ptr int16](cast[int](ptrArea.pointer) + frame*ptrArea.step)
  39. ptrSample[] = int16(sample)
  40. err = outStream.endWrite()
  41. framesLeft -= frameCount
  42. framePos += frameCount
  43. if framesLeft <= 0:
  44. break
  45. proc init*() =
  46. sio = soundioCreate()
  47. if sio.isNil:
  48. quit "out of memory"
  49. if sio.connect() > 0:
  50. quit "unable to connect to backend"
  51. echo "Backend: ", sio.currentBackend.name
  52. sio.flushEvents()
  53. proc init_record*(sampleRate: int, afunc: proc(buffer: var seq[int16])) =
  54. audioReaderFunc = afunc
  55. let devID = sio.defaultInputDeviceIndex
  56. let microphone = sio.getInputDevice(devID)
  57. if microphone.isNil:
  58. quit "out of memory"
  59. if microphone.probeError > 0:
  60. quit "unable to connect to device"
  61. echo "Microphone: ", microphone.name
  62. let micStream = microphone.inStreamCreate()
  63. micStream.format = SoundIoFormatS16NE
  64. micStream.sample_rate = cast[cint](sampleRate)
  65. micStream.read_callback = readCallback
  66. let err = micStream.open()
  67. if err > 0:
  68. quit "unable to start listening (1)" & $err
  69. if micStream.layoutError > 0:
  70. quit "unable to start listening (2)" & $micStream.layoutError
  71. if micStream.start() > 0:
  72. quit "unable to start listening (3)"
  73. proc init_playback*(sampleRate: int, afunc: proc(frameCountMin: int, frameCountMax: int): seq[int16]) =
  74. audioWriterFunc = afunc
  75. let devID = sio.defaultOutputDeviceIndex
  76. let speaker = sio.getOutputDevice(devID)
  77. if speaker.isNil:
  78. quit "out of memory"
  79. if speaker.probeError > 0:
  80. quit "unable to connect to device"
  81. echo "Speaker: ", speaker.name
  82. let outStream = speaker.outStreamCreate()
  83. outStream.format = SoundIoFormatS16NE
  84. outStream.sample_rate = cast[cint](sampleRate)
  85. outStream.write_callback = writeCallback
  86. let err = outStream.open()
  87. if err > 0:
  88. quit "unable to start playing (1)" & $err
  89. if outStream.layoutError > 0:
  90. quit "unable to start playing (2)" & $outStream.layoutError.strerror
  91. if outStream.start() > 0:
  92. quit "unable to start playing (3)"
  93. proc update*() =
  94. sio.flushEvents()
  95. proc deinit*() =
  96. sio.destroy()