AudioIN/OUT Module (WinAPI)

Share your advanced PureBasic knowledge/code with the community.
User avatar
Bananenfreak
Enthusiast
Enthusiast
Posts: 519
Joined: Mon Apr 15, 2013 12:22 pm

AudioIN/OUT Module (WinAPI)

Post by Bananenfreak »

Heyho,
here´s an module for AudioIN (Microphone,...). It uses Winapi to get the Input.
I want to use it with the integrated Soundlib (Sound is played instantly), but there´s a Problem with the raw Soundformat; The soundlib can´t handle with it. If anyone knows how to do that, it would be perfect :)
If you have nice Features for it, please post it!

Excuse me please, all comments are in german. Just Google the functionnames if you want to know how it works.

Code: Select all

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>>                             >>
;>>  Name: AudioIN              >>
;>>                             >>
;>>  Author: (c) Chimorin       >>
;>>             (Bananenfreak)  >>
;>>                             >>
;>>  Date: 05.10.2014           >>
;>>                             >>
;>>  OS: Windows                >>
;>>                             >>
;>>                             >>
;>>                             >>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
EnableExplicit


Define.f KeyX, KeyY, MouseX, MouseY
Define nx.f, nz.f, Boost.f = 1, Yaw.f, Pitch.f
Define.i Quit, sound, file
#kam_0 = 0
#window = 0


DeclareModule AudioIn
  EnableExplicit
  
  Structure rec
    buffer.i
    size.i
  EndStructure
  
  #BUFFER_NUM = 8         ; Number of buffer for capture 
  
  Global NewList devices.WAVEINCAPS()
  Global NewList audio.rec()
  Global Dim inHdr.WAVEHDR(#BUFFER_NUM-1)
  Global.i mutex = CreateMutex()
  
  Declare GetDevices()
  Declare Start()
  ;Declare ARead()
EndDeclareModule


Module AudioIn
  Global.i inputZgr       ;Ist das Handle des geöffneten Inputdevice
  
  #SOUND_NCHANNELS = 1    ;Anzahl der Kanäle: 1 = Mono
  #SOUND_NBITS = 16       ;Bittiefe des Audiodings, hier 16bit
  #SOUND_NHERTZ = 44100   ;Hertzanzahl. 
  #BUFFER_SIZE = 512      ; Size of each buffer, should be x2 in Stereo 
  
  
  Declare Error(err.i)
  
  
  Procedure Stop()        ;Stoppt die Aufnahme und freet alles.
  Protected.i i
  
  
  If inputZgr
    Error(waveInReset_(inputZgr))       ;Die Funktion waveInReset stoppt Input auf der vorhandenen Wave-Audio-Eingabegerät und setzt die aktuelle Position auf Null (zurück). Alle ausstehenden Puffer sind  als erledigt markiert und werden zur Anwendung "zurückgeschickt".
    Error(waveInStop_(inputZgr))        ;Die Funktion waveInStop stoppt Wave-Audio input.
    For i = 0 To #BUFFER_NUM - 1 
      Error(waveInUnprepareHeader_(inputZgr, inHdr(i), SizeOf(WAVEHDR)))        ;Diese Funktion bereinigt die Vorbereitung durch waveInPrepareHeader durchgeführt. Die Funktion muss aufgerufen werden, nachdem die Gerätetreiber füllt einen Datenpuffer und gibt sie an die Anwendung. Sie müssen diese Funktion vor der Befreiung der Datenpuffer nennen.
    Next 
    Error(waveInClose_(inputZgr))       ;Diese Funktion schließt die angegebene wave-Audio-Eingabegerät.
  EndIf
  EndProcedure
  
  
  Procedure Error(err.i)        ;Wirft den Fehler aus, der zu diesem Ding gehört.
    Protected.s text
    
    
    If err 
      text = Space(#MAXERRORLENGTH) 
      waveInGetErrorText_(err, text, #MAXERRORLENGTH)       ;Diese Funktion ruft eine Textbeschreibung des von der angegebenen Fehlernummer identifiziert Fehler.
      MessageRequester("Error", text, #MB_ICONERROR)
      Stop() 
      End 
    EndIf 
  EndProcedure
  
  
  Procedure GetDevices()       ;Listet die vorhandenen Audioeingänge auf und gibt den Namen Eines zurück.
    Protected.i size, zaehler
    
    size = waveInGetNumDevs_()
    FirstElement(devices())
    For zaehler = 0 To size -1        ;Die waveInGetNumDevs Funktion gibt die Anzahl der Wellenform-Audio-Eingang im System vorhandenen Geräte.
      AddElement(devices())
      Error(waveInGetDevCaps_(zaehler, devices(), SizeOf(WAVEINCAPS)))       ;Die waveInGetDevCaps Funktion ruft die Fähigkeiten eines gegebenen Wellenform-Audioeingabegerät.
      If Not Bool(devices()\dwFormats & #WAVE_FORMAT_4M16)                   ;dwFormats ist eine Addition aller unterstützter Audioformate (Siehe Anhang 1)
        DeleteElement(devices())
      EndIf
    Next 
  EndProcedure 
  
  
  Procedure ARead(wParam.i)
    Protected.i buffer, size
    
    
    Error(waveInAddBuffer_(inputZgr, wParam, SizeOf(WAVEHDR)))
    ;Debug PeekS(wParam)
    buffer = PeekL(wParam)
    ;Debug buffer
    ;Debug PeekL(buffer)
    ;Debug "000000000000000000"
    
    ;If Not buffer = 0
    ;Debug ".........."
    LockMutex(mutex)
    PushListPosition(audio())
    LastElement(audio())
    AddElement(audio())
    Debug "reingehauen"
    audio()\buffer = buffer;PeekL(buffer)
    audio()\size = PeekL(wParam + 8)
    PopListPosition(audio())
    UnlockMutex(mutex)
      
    ;Else
      ;Debug "Buffer ist 0, warum?"
    ;EndIf
  EndProcedure
  
  
  Procedure CallBack(hWnd.i, uMsg.i, instance.i, wParam.i, lParam.i)        ;Callbackfunktion für alle Inputevents. hWnd: inputZgr | instance ist nur vorhanden, wenn bei waveInOpen_() dwInstance angegeben wurde.
;     Debug hWnd
;     Debug uMsg
;     Debug "i:" + instance
;     Debug "w" + wParam
;     Debug "l:" + lParam
;     Debug "--------------------"
    Select uMsg 
      Case #WIM_DATA
        If hWnd = inputZgr
          ARead(wParam)
          
        Else
          Debug "Da ist was anderes im Busch!"
          
        EndIf
        
      Case #WIM_OPEN
        Debug "Open"
        
      Case #WIM_CLOSE
        Debug "Close"
    EndSelect
  EndProcedure
  
  
  Procedure Start()       ;Initialisierungszeug.
    Protected.WAVEFORMATEX format   ;format.WAVEFORMATEX übergibt in waveInOpen_() Infos über das angeforderte Audiomaterial.
    Protected.i zaehler
    
    
    format\wFormatTag      = 1        ;#WAVE_FORMAT_PCM? Ist es das?
    format\nChannels       = #SOUND_NCHANNELS
    format\wBitsPerSample  = #SOUND_NBITS
    format\nSamplesPerSec  = #SOUND_NHERTZ
    format\nBlockAlign     = #SOUND_NCHANNELS * (#SOUND_NBITS/8)
    format\nAvgBytesPerSec = #SOUND_NHERTZ * format\nBlockAlign
    format\cbSize          = 0
    Error(waveInOpen_(@inputZgr, #WAVE_MAPPER, @format, @CallBack(), 13, #CALLBACK_FUNCTION|#WAVE_FORMAT_DIRECT))        ;Öffnet das spezifische Waveinputdevice.
    
    For zaehler = 0 To #BUFFER_NUM -1
      inHdr(zaehler)\lpData         = AllocateMemory(#BUFFER_SIZE) 
      inHdr(zaehler)\dwBufferLength = #BUFFER_SIZE
      Error(waveInPrepareHeader_(inputZgr, inHdr(zaehler), SizeOf(WAVEHDR)))        ;Diese Funktion erstellt einen Puffer für wave-input. Diese Funktion ermöglicht dem Audiotreiber und dem Betriebssystem (OS) zu Zeit raubende Verarbeitung des Kopf-und / oder Puffer einmal bei der Initialisierung. Die Anwendung kann die Puffer wiederholt ohne zusätzliche Verarbeitungs Nutzung durch den Fahrer oder das Betriebssystem.
      Error(waveInAddBuffer_(inputZgr, inHdr(zaehler), SizeOf(WAVEHDR)))            ;Die waveInAddBuffer Funktion sendet einen inputpuffer, an das gegebene Wave-Audioeingabegerät. Wenn der Puffer voll ist, wird die Anwendung informiert.
    Next zaehler
    
    Error(waveInStart_(inputZgr))        ;Diese Funktion startet input auf dem angegebenen wave-Eingabegerät.
  EndProcedure
EndModule


InitSprite()
InitKeyboard()
InitSound()

OpenWindow(#window, 0, 0, 1800, 1000, "AudioIn-Out Test", #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(#window), 10, 10, 2000, 2000, 0, 10, 10, #PB_Screen_SmartSynchronization)

;SetWindowCallback(@CallBack())

AudioIn::GetDevices()
; ForEach AudioIn::devices()
;   Debug PeekS(AudioIn::@devices()\szPname)
; Next
AudioIn::Start()

file = CreateFile(#PB_Any, "D:\test.raw")

Repeat
  Repeat
  Until WindowEvent() = 0
  
  If ExamineKeyboard()
    
  EndIf
  
  If ListSize(AudioIn::audio())
    LockMutex(AudioIn::mutex)
    PushListPosition(AudioIn::audio())
    FirstElement(AudioIn::audio())
    ForEach AudioIn::audio()
      Debug "1 rausgehauen"
      WriteData(file, AudioIn::audio()\buffer, AudioIn::audio()\size)
      DeleteElement(AudioIn::audio())
    Next AudioIn::audio()
    PopListPosition(AudioIn::audio())
    UnlockMutex(AudioIn::mutex)
;     If IsSound(sound)
;       Select SoundStatus(sound)
;         Case #PB_Sound_Stopped
;           Debug "1"
;           FirstElement(AudioIn::audio())
;           ;sound = CatchSound(#PB_Any, AudioIn::audio()\buffer, AudioIn::audio()\size)
;           ;PlaySound(sound)
;           DeleteElement(AudioIn::audio())
;           
;       EndSelect
;       
;     Else
;       Debug "2"
;       FirstElement(AudioIn::audio())
;       Debug "Buffer:" + AudioIn::audio()\buffer
;       sound = CatchSound(#PB_Any, AudioIn::audio()\buffer)
;       Debug sound
;       ;PlaySound(sound)
;       DeleteElement(AudioIn::audio())
;     EndIf
  EndIf
  
  
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1

CloseFile(file)
End
EDIT:
Dadido3 (Or Xaardas) has done a great work out of my code with more functions, get it here:
>>> Dadido3 GitHub Releases <<<
Image