It is currently Sat May 25, 2013 1:06 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 68 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next
Author Message
 Post subject:
PostPosted: Tue Aug 14, 2007 10:56 pm 
Offline
Addict
Addict
User avatar

Joined: Tue Jul 22, 2003 5:02 pm
Posts: 1496
Location: Nantes, France
chris319 wrote:
Capturing audio works fine under Windows XP but does not work under Vista using either PB 4.03 or PB 4.10 Beta 3. It is based on code found here (see Flype's post dated Oct. 18, 2006):

http://www.purebasic.fr/english/viewtopic.php?t=7009&postdays=0&postorder=asc&start=15

(NOTE: In PB 4.10 it is no longer necessary to include the WAVEFORMATEX structure.)

Microsoft has done some weird and wacky things to the audio in Vista.


freak wrote:
Why should this be our problem ?

Please talk to MS about problems in their operatingsystems.
This section is for bugreports about PB, not the Windows API.


chris319 wrote:
If PB doesn't keep up with changes to the OS, be it Windows, Linux or OS X, it will eventually become useless. If PB is to keep up with other changes to Windows I don't see why audio capture should be an exception.


ts-soft wrote:
This is no PB only source, the source uses API from the OS. This is not the
problem of the PB TEAM.


I also agree,
to make it works on Vista, the code might be modified.
that's not in anyway a purebasic incompatibility.
it's the programmer task to 'convert' his code to Vista if he decided to use API programming.
So i decided to move here this discussion.


I don't own Vista, so can't test - any Vista pros here :?:

But it might be a Vista 'path' access problem.

this snippet write the raw sound in 'c:\unnamed.raw'

the application is maybe not allowed to write in c:\

_________________
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 14, 2007 11:16 pm 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
I have extensively modified the code posted here so that PB allocates a large RAM buffer and copies the audio data there. The audio is not saved to disk until the user explicitly chooses to do so, at which time the program creates a wav header and writes it all to disk. So I don't think the problem is related to C: drive write permission.

This might be a clue:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=704965&SiteID=1

I'd be surprised if Microsoft let this problem linger for so long, but then this is Microsoft we're dealing with.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Sep 02, 2007 9:42 am 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
OK, I finally got the audio recorder to work under Vista, but in order to do so I had to use flype's code posted on Oct 18, 2006. For some reason that code works under Vista but the original code, modified by me and which works under XP, does not. Even flype's code had a bug preventing it from recording which is now fixed. Now I am modifying flype's code (extensively) with the emphasis on metering (level display) and on glitch-free recording (no dropped samples). Also, the metering code has been rewritten to be much less CPU intensive. I can make the code available when I'm a little further along. I really like flype's drop-down selection of audio devices.

Would anyone be terribly offended if 8-bit sampling were eliminated? I can't imagine anyone actually considering it "audio".

BTW, this program is currently being developed on a MacBook running Vista under Boot Camp and PB 4.10 Beta 3.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Sep 02, 2007 7:56 pm 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
Below is a bug-fixed version of flype's audio recorder. You can find my fixes by searching for "chris319". The fixes consist of:

4/5/2009:
- Fixed procedure DRAW_Wave16S() to draw stereo properly.
- Removed deprecated CreateGadgetList() for 4.30.
- Set default buffer size to 2048.
- Other fixes in wave-drawing procedures to not overrun audio buffer.

- Structure member Config\size was not being saved before calling waveInAddBuffer and thus always had a value of zero.

- Structure member Config\recorded was being set to zero prematurely; moved to procedure FILE_Create().

- Incorrect calculation of blockalign (saving to wav file) fixed. Third-party programs no longer complain when opening files created by this program.

- Procedure raw2wav() now obtains audio buffer size from variable Config\recorded.

The oscilloscope display is VERY CPU intensive. Pops and clicks could be heard in recordings, presumably due to dropped samples caused by CPU activity.

Code:
;/
;/ Object     Audio Recorder 1.0 (a)
;/
;/ Date       August 2004
;/ Author     Philippe Carpentier
;/ Contact    flype@altern.org
;/ Info       MS Windows only - winmm.lib - mmsystem.h
;/
;  Bug fixes by chris319 on September 2, 2007
;
;- REC GLOBAL
;
Global QuitRec.l
;
;- REC CONSTANTES
;
#MinWidth      = 320
#MinHeight     = 240
;
;- REC INITIALISATION
;
Enumeration 0 ; #CHANNEL
  #CHANNEL_LEFT
  #CHANNEL_RIGHT
EndEnumeration
Enumeration 0 ; #GADGET
  #gadFrame1
  #gadFrame2
  #gadStart
  #gadStop
  #gadSndVol
  #gadFile
  #gadChannel
  #gadResolution
  #gadFrequence
  #gadDevice
EndEnumeration
Enumeration 0 ; #WINDOW
  #Window
EndEnumeration
Enumeration 0 ; #TOOLBAR
  #ToolBar
EndEnumeration
Enumeration 0 ; #STATUSBAR
  #StatusBar
EndEnumeration

;Structure WAVEFORMATEX -- NOT NEEDED IN PB 4.10 -- chris319
;  wFormatTag.w
;  nChannels.w
;  nSamplesPerSec.l
;  nAvgBytesPerSec.l
;  nBlockAlign.w
;  wBitsPerSample.w
;  cbSize.w
;EndStructure
Structure SCOPE
  channel.b
  left.l
  top.l
  width.l
  height.l
  middleY.l
  quarterY.l
EndStructure
Structure CONFIG
 
  hWindow.l           ; Window handle
  hToolBar.l          ; ToolBar handle
  hfont.l             ; Font handle
 
  Date.l              ; Start date
  size.l              ; Wave buffer size
  buffer.l            ; Wave buffer pointer
  output.l            ; WindowOutput()
  wave.l              ; Address of waveform-audio input device
  recorded.l          ; Number of bytes recorded
  recording.b         ; Record is running...
 
  File.s              ; Recording FileName (c:\unnamed.raw)
  FileId.l            ; Recording FileId (#PB_Any)
  SndVol.s            ; Microsoft Volume Control (sndvol32.exe)

  format.WAVEFORMATEX ; Capturing WaveFormatEx
  lBuf.l              ; Capturing Buffer size
  nBuf.l              ; Capturing Buffer number
  nDev.l              ; Capturing Device identifier
  nBit.l              ; Capturing Resolution (8/16)
  nHertz.l            ; Capturing Frequency  (Hertz)
  nChannel.l          ; Capturing Channels number (Mono/Stereo)
 
  LScope.SCOPE        ; Wave form display
  RScope.SCOPE        ; Wave form display
  ScopeTimer.l        ; Scope Timer (redraw every n times)
  cback.l             ; Back color
  cline.l             ; Line color
  cwave.l             ; Wave color
  ColRecWave.l        ; Scope Record Wave Color
  ColRecBack.l        ; Scope Record Back Color
  ColRecLine.l        ; Scope Record Line Color
  ColCapWave.l        ; Scope Capture Wave Color
  ColCapBack.l        ; Scope Capture Back Color
  ColCapLine.l        ; Scope Capture Line Color
 
EndStructure

Global Config.CONFIG
Global Dim inHdr.WAVEHDR(16)

Config\hfont             = LoadFont(0,"Arial",7)
Config\format\cbSize     = 0
Config\format\wFormatTag = #WAVE_FORMAT_PCM
Config\LScope\channel    = #CHANNEL_LEFT
Config\RScope\channel    = #CHANNEL_RIGHT
;
;- REC DECLARATIONS
;
Declare Clamp(value.l,min.l,max.l)

Declare CONFIG_Load()
Declare CONFIG_Save()

Declare CAPTURE_Stop()
Declare CAPTURE_Start()
Declare CAPTURE_Error(err.l)
Declare CAPTURE_GetDevices(gadId.l)
Declare CAPTURE_Read(hWaveIn.l,lpWaveHdr.l)

Declare DRAW_Scope()
Declare DRAW_Wave(*scope.SCOPE)
Declare DRAW_Wave8M(*scope.SCOPE)
Declare DRAW_Wave8S(*scope.SCOPE)
Declare DRAW_Wave16M(*scope.SCOPE)
Declare DRAW_Wave16S(*scope.SCOPE)
Declare DRAW_LCD(*scope.SCOPE,lcd$)
Declare DRAW_Background(*scope.SCOPE)

Declare FILE_Close()
Declare FILE_Append()
Declare FILE_Create()
Declare FILE_Select()
Declare FILE_Recording(state.b)
Declare FILE_raw2wav(File.s)

Declare GUI_Init()
Declare GUI_Resize()
Declare GUI_TBCombo(Id,x,y,w,h)
Declare GUI_CallBack(hWnd.l,Msg.l,wParam.l,lParam.l)

;
;- REC PROCEDURES
;
;
Procedure Clamp(value.l,min.l,max.l)
  If value<min : ProcedureReturn min : EndIf
  If value>max : ProcedureReturn max : EndIf 
  ProcedureReturn value
EndProcedure
;
Procedure CONFIG_Load()
 
  OpenPreferences("Recorder.ini")
 
  PreferenceGroup("Files")
  Config\File   = ReadPreferenceString("FileName","c:\unnamed.raw")
  Config\SndVol = ReadPreferenceString("SndVol","sndvol32")
 
  PreferenceGroup("Capture")
  Config\nDev     = ReadPreferenceLong("Device",0)
  Config\nChannel = ReadPreferenceLong("Channel",1)
  Config\nHertz   = ReadPreferenceLong("Frequency",7)
  Config\nBit     = ReadPreferenceLong("Resolution",1)
  Config\nBuf     = ReadPreferenceLong("BufferNum",8)
  Config\lBuf     = ReadPreferenceLong("BufferLen", 2048) ;chris319
 
  PreferenceGroup("Scope")
  Config\ScopeTimer   = ReadPreferenceLong("ScopeTimer",25)
  Config\ColRecLine   = ReadPreferenceLong("ColRecLine",  $000035)
  Config\ColRecWave   = ReadPreferenceLong("ColRecWave",  $1010E0)
  Config\ColRecBack   = ReadPreferenceLong("ColRecBack",  $000050)
  Config\ColCapLine   = ReadPreferenceLong("ColCapLine",  $004000)
  Config\ColCapWave   = ReadPreferenceLong("ColCapWave",  $20E020)
  Config\ColCapBack   = ReadPreferenceLong("ColCapBack",  $004900)
 
  PreferenceGroup("Window")
  pos.WINDOWPLACEMENT
  pos\length=SizeOf(WINDOWPLACEMENT)
  pos\ptMinPosition\x         = ReadPreferenceLong("MinPosX",0)
  pos\ptMinPosition\y         = ReadPreferenceLong("MinPoxY",0)
  pos\ptMaxPosition\x         = ReadPreferenceLong("MaxPosX",-1)
  pos\ptMaxPosition\y         = ReadPreferenceLong("MaxPosY",-1)
  pos\rcNormalPosition\left   = ReadPreferenceLong("PosX1",100)
  pos\rcNormalPosition\top    = ReadPreferenceLong("PosY1",100)
  pos\rcNormalPosition\right  = ReadPreferenceLong("PosX2",#MinWidth)
  pos\rcNormalPosition\bottom = ReadPreferenceLong("PosY2",#MinHeight)
 
  ClosePreferences()
 
  Config\cback   = Config\ColCapBack
  Config\cline   = Config\ColCapLine
  Config\cwave   = Config\ColCapWave
 
  StatusBarText(0,2,Config\File)
  SetGadgetState(#gadDevice,Config\nDev)
  SetGadgetState(#gadChannel,Config\nChannel)
  SetGadgetState(#gadFrequence,Config\nHertz)
  SetGadgetState(#gadResolution,Config\nBit)
  SetWindowPlacement_(Config\hWindow,@pos)
  ShowWindow_(Config\hWindow,#True)
 
EndProcedure
;
Procedure CONFIG_Save()
 
  pos.WINDOWPLACEMENT
  pos\length = SizeOf(WINDOWPLACEMENT)
  GetWindowPlacement_(Config\hWindow,@pos)
 
  If CreatePreferences("Recorder.ini")
   
    PreferenceGroup("Files")
    WritePreferenceString("FileName",Config\File)
    WritePreferenceString("SndVol",Config\SndVol)
   
    PreferenceGroup("Capture")
    WritePreferenceLong("Device",Config\nDev)
    WritePreferenceLong("Channel",Config\nChannel)
    WritePreferenceLong("Frequency",Config\nHertz)
    WritePreferenceLong("Resolution",Config\nBit)
    WritePreferenceLong("BufferNum",Config\nBuf)
    WritePreferenceLong("BufferLen",Config\lBuf)
   
    PreferenceGroup("Scope")
    WritePreferenceLong("ScopeTimer",Config\ScopeTimer)
    WritePreferenceLong("ColRecLine",Config\ColRecLine)
    WritePreferenceLong("ColRecWave",Config\ColRecWave)
    WritePreferenceLong("ColRecBack",Config\ColRecBack)
    WritePreferenceLong("ColCapLine",Config\ColCapLine)
    WritePreferenceLong("ColCapWave",Config\ColCapWave)
    WritePreferenceLong("ColCapBack",Config\ColCapBack)
   
    PreferenceGroup("Window")
    WritePreferenceLong("MinPosX",pos\ptMinPosition\x)
    WritePreferenceLong("MinPoxY",pos\ptMinPosition\y)
    WritePreferenceLong("MaxPosX",pos\ptMaxPosition\x)
    WritePreferenceLong("MaxPosY",pos\ptMaxPosition\y)
    WritePreferenceLong("PosX1",pos\rcNormalPosition\left)
    WritePreferenceLong("PosY1",pos\rcNormalPosition\top)
    WritePreferenceLong("PosX2",pos\rcNormalPosition\right)
    WritePreferenceLong("PosY2",pos\rcNormalPosition\bottom)
   
    ClosePreferences()
    ProcedureReturn #True
   
  EndIf
 
EndProcedure
;
Procedure CAPTURE_Error(err.l)

  If err
    text.s=Space(#MAXERRORLENGTH)
    waveInGetErrorText_(err,text,#MAXERRORLENGTH)
    MessageRequester("Error",text,#MB_ICONERROR)
    CAPTURE_Stop()
    End
  EndIf

EndProcedure
;
Procedure CAPTURE_Start()
 
  CAPTURE_Stop()
 
  Config\nDev = GetGadgetState(#gadDevice)
 
  Config\nChannel = GetGadgetState(#gadChannel)
  Select Config\nChannel
    Case 0 : Config\format\nChannels = 1
    Case 1 : Config\format\nChannels = 2
  EndSelect
 
  Config\nBit = GetGadgetState(#gadResolution)
  Select Config\nBit
    Case 0 : Config\format\wBitsPerSample = 8
    Case 1 : Config\format\wBitsPerSample = 16
  EndSelect
 
  Config\nHertz = GetGadgetState(#gadFrequence)
  Select Config\nHertz
    Case 0 : Config\format\nSamplesPerSec =  8000
    Case 1 : Config\format\nSamplesPerSec = 11025
    Case 2 : Config\format\nSamplesPerSec = 12000
    Case 3 : Config\format\nSamplesPerSec = 16000
    Case 4 : Config\format\nSamplesPerSec = 22050
    Case 5 : Config\format\nSamplesPerSec = 24000
    Case 6 : Config\format\nSamplesPerSec = 32000
    Case 7 : Config\format\nSamplesPerSec = 44100
    Case 8 : Config\format\nSamplesPerSec = 48000
  EndSelect
 
  Config\format\nBlockAlign     = (Config\format\nChannels*Config\format\wBitsPerSample)/8
  Config\format\nAvgBytesPerSec = Config\format\nSamplesPerSec*Config\format\nBlockAlign
 
  If #MMSYSERR_NOERROR = waveInOpen_(@Config\wave,#WAVE_MAPPER+Config\nDev,@Config\format,Config\hWindow,#Null,#CALLBACK_WINDOW|#WAVE_FORMAT_DIRECT)
   
    For i=0 To Config\nBuf-1
      inHdr(i)\lpData=AllocateMemory(Config\lBuf)
      inHdr(i)\dwBufferLength=Config\lBuf
      waveInPrepareHeader_(Config\wave,inHdr(i),SizeOf(WAVEHDR))
      waveInAddBuffer_(Config\wave,inHdr(i),SizeOf(WAVEHDR))
    Next
   
    If #MMSYSERR_NOERROR = waveInStart_(Config\wave)
      SetTimer_(Config\hWindow,0,Config\ScopeTimer,0)
    EndIf
   
  EndIf
 
EndProcedure
;
Procedure CAPTURE_Stop()

  If Config\wave
    waveInReset_(Config\wave)
    waveInStop_(Config\wave)
    For i=0 To Config\nBuf-1
      If inHdr(i)
        waveInUnprepareHeader_(Config\wave,inHdr(i),SizeOf(WAVEHDR))
      EndIf
    Next
    waveInClose_(Config\wave)
  EndIf
 
  KillTimer_(Config\hWindow,0)
 
EndProcedure
;
Procedure CAPTURE_Read(hWaveIn.l,lpWaveHdr.l)
;  waveInAddBuffer_(hWaveIn,lpWaveHdr,SizeOf(WAVEHDR))

  *hWave.WAVEHDR=lpWaveHdr
  Config\buffer=*hWave\lpData
  Config\size=*hWave\dwBytesRecorded
;  dwBytesRecorded MUST BE SAVED BEFORE CALLING waveInAddBuffer -- chris319 
  waveInAddBuffer_(hWaveIn,lpWaveHdr,SizeOf(WAVEHDR))

  FILE_Append()
 
EndProcedure
;
Procedure CAPTURE_GetDevices(gadId.l)
  MMNumDevice.l = waveInGetNumDevs_()
  If MMNumDevice
    For MMDeviceId=#WAVE_MAPPER To MMNumDevice-1
      MMResult.l = waveInGetDevCaps_(MMDeviceId,@Caps.WAVEINCAPS,SizeOf(WAVEINCAPS))
      If MMResult = #MMSYSERR_NOERROR
        AddGadgetItem(gadId,-1,PeekS(@Caps\szPname,#MAXPNAMELEN))
      EndIf
    Next
  EndIf
EndProcedure
;
Procedure DRAW_Scope()
  If Config\buffer
    StartDrawing(Config\output)
      DRAW_Background(Config\LScope)
      DRAW_Background(Config\RScope)
      DRAW_Wave(Config\LScope)
      If Config\nChannel
        DRAW_Wave(Config\RScope)
      EndIf
    StopDrawing()
  EndIf
EndProcedure
;
Procedure DRAW_Background(*scope.SCOPE)
 
  Box (*scope\left,*scope\top,*scope\width,*scope\height,Config\cback)
  Line(*scope\left,*scope\middleY-*scope\quarterY,*scope\width,0,Config\cline)
  Line(*scope\left,*scope\middleY+*scope\quarterY,*scope\width,0,Config\cline)
 
EndProcedure
;
Procedure DRAW_LCD(*scope.SCOPE,lcd$)
 
  DrawingMode(1)
  FrontColor($00FFFF)
  DrawingFont(Config\hfont)
  Select *scope\channel
    Case #CHANNEL_LEFT  : DrawText(*scope\left+1, *scope\top, "[L] "+lcd$)
    Case #CHANNEL_RIGHT : DrawText(*scope\left+1, *scope\top, "[R] "+lcd$)
  EndSelect
  DrawingMode(0)
 
EndProcedure
;
Procedure DRAW_Wave(*scope.SCOPE)
  Select Config\nBit
    Case 0
      DRAW_LCD(*scope.SCOPE,"8 bits")
      Select Config\nChannel
        Case 0 : DRAW_Wave8M(*scope.SCOPE)
        Case 1 : DRAW_Wave8S(*scope.SCOPE)
      EndSelect
    Case 1
      DRAW_LCD(*scope.SCOPE,"16 bits")
      Select Config\nChannel
        Case 0 : DRAW_Wave16M(*scope.SCOPE)
        Case 1 : DRAW_Wave16S(*scope.SCOPE)
      EndSelect
  EndSelect
EndProcedure
;
Procedure DRAW_Wave8M(*scope.SCOPE)
 
  oldx.l=*scope\left
  For i = 0 To Config\size - 1 ;chris319
    value.b=PeekB(Config\buffer+i)+$7F
    xx=Clamp(*scope\left+(i**scope\width)/(Config\size+1),*scope\left,*scope\width)
    yy=(value**scope\height)/$FF
    LineXY(oldx,*scope\middleY+oldy,xx,*scope\middleY+yy,Config\cwave)
    oldx=xx:oldy=yy
  Next
 
EndProcedure
;
Procedure DRAW_Wave8S(*scope.SCOPE)
 
  oldx.l=*scope\left
  For i = 0 To (Config\size - 1) Step 2 ;chris319
    value.b=PeekB(Config\buffer+i+*scope\channel*2)+$7F
    xx=Clamp(*scope\left+(i**scope\width)/(Config\size+1),*scope\left,*scope\width)
    yy=(value**scope\height)/$FF
    LineXY(oldx,*scope\middleY+oldy,xx,*scope\middleY+yy,Config\cwave)
    oldx=xx:oldy=yy
  Next
 
EndProcedure
;
Procedure DRAW_Wave16M(*scope.SCOPE)
 
  oldx.l=*scope\left
  For i=0 To (Config\size -2) Step 2 ;chris319
    value.w=PeekW(Config\buffer+i)
    xx=Clamp(*scope\left+(i**scope\width)/(Config\size+1),*scope\left,*scope\width)
    yy=(value**scope\height)/$FFFF
    LineXY(oldx,*scope\middleY+oldy,xx,*scope\middleY+yy,Config\cwave)
    oldx=xx:oldy=yy
  Next
 
EndProcedure
;
Procedure DRAW_Wave16S(*scope.SCOPE) ;chris319

Select *scope\channel

Case 0 ;LEFT CHANNEL
  oldx.l = *scope\left
  For i = 0 To (Config\size - 2) Step 4
    value.w = PeekW(Config\buffer + i)
    xx = Clamp(*scope\left+(i**scope\width)/(Config\size+1),*scope\left,*scope\width)
;    yy = (value * *scope\height)/$FFFF
    yy = (value * *scope\height) / $FFF
    ayy = Abs(yy)
    If ayy > vmax: vmax = ayy: EndIf
    LineXY(oldx,*scope\middleY+oldy,xx,*scope\middleY+yy,Config\cwave)
    oldx = xx: oldy = yy
  Next

Case 1 ;RIGHT CHANNEL
  oldx.l = *scope\left
  For i = 2 To (Config\size - 2) Step 4
    value.w = PeekW(Config\buffer + i)
    xx=Clamp(*scope\left+(i * *scope\width)/(Config\size+1),*scope\left,*scope\width)
;    yy = (value * *scope\height)/$FFFF
    yy = (value * *scope\height) / $FFF
    ayy = Abs(yy)
    If ayy > vmax: vmax = ayy: EndIf
    LineXY(oldx,*scope\middleY + oldy, xx, *scope\middleY + yy, Config\cwave)
    oldx = xx: oldy = yy
  Next

EndSelect

EndProcedure
;
Procedure FILE_Create()
 
  Config\recorded  = #Null ; -- MOVED HERE BY chris319
   
  If Config\File
    Config\FileId = CreateFile(#PB_Any,Config\File)
    If Config\FileId
      DisableToolBarButton(#ToolBar, #gadStart,#True)
      DisableToolBarButton(#ToolBar, #gadFile,#True)
      DisableGadget(#gadChannel,#True)
      DisableGadget(#gadFrequence,#True)
      DisableGadget(#gadResolution,#True)
      DisableGadget(#gadDevice,#True)
      Config\Date = GetTickCount_()
      FILE_Recording(#True)
    Else
      MessageRequester("Error","Can't create file",#MB_ICONERROR)
    EndIf
  EndIf
 
EndProcedure
;
Procedure FILE_Append()
 
  If Config\recording = #True
    Config\recorded + Config\size
    WriteData(Config\FileId, Config\buffer,Config\size)
    StatusBarText(#StatusBar, 0,Str(Config\recorded)+" bytes",#PB_StatusBar_Center)
    StatusBarText(#StatusBar, 1,StrF((GetTickCount_()-Config\Date)/1000,3)+" secs",#PB_StatusBar_Center)
  EndIf
 
EndProcedure
;
Procedure FILE_Recording(state.b)
 
  If state
    Config\cback   = Config\ColRecBack
    Config\cline   = Config\ColRecLine
    Config\cwave   = Config\ColRecWave
  Else
    Config\cback   = Config\ColCapBack
    Config\cline   = Config\ColCapLine
    Config\cwave   = Config\ColCapWave
  EndIf
 
  Config\recording = state
;  Config\recorded  = #Null -- THIS LINE OF CODE MOVED TO FILE_create-- chris319

EndProcedure
;
Procedure FILE_Close()

  If Config\recording
    Config\Date = #Null
    FILE_Recording(#False)
    CloseFile(Config\FileId)
    Delay(1000)
    FILE_raw2wav(Config\File)   
    DisableToolBarButton(#ToolBar, #gadStart,#False)
    DisableToolBarButton(#ToolBar, #gadFile,#False)
    DisableGadget(#gadChannel,#False)
    DisableGadget(#gadFrequence,#False)
    DisableGadget(#gadResolution,#False)
    DisableGadget(#gadDevice,#False)
  EndIf

EndProcedure
;
Procedure FILE_Select()
 
  File.s = SaveFileRequester("Select a file",Config\File,"Raw Sound|(*.raw)",0)
 
  If File
    Config\File = File
  EndIf
 
  StatusBarText(0,2,Config\File)
 
EndProcedure
;
Procedure FILE_raw2wav(File.s)

  inId.l = ReadFile(#PB_Any,File)
 
  If inId = #Null
    MessageRequester("Error", "Unable to open file",#MB_ICONERROR) ; chris319
    ProcedureReturn #False
  EndIf
 
  lBuf.l = Lof(inId)
  pBuf.l = AllocateMemory(lBuf)
  If pBuf = #Null
    MessageRequester("Error", "Unable to allocate buffer",#MB_ICONERROR) ; chris319
    ProcedureReturn #False
  EndIf
 
  ReadData(inId, pBuf,lBuf)
  CloseFile(inId)
 
  subchunk2size.l = Config\recorded
  chunksize.l = 36 + subchunk2size
 
  f$ = GetFilePart(File)
  x$ = GetPathPart(File)+Left(f$,Len(f$)-Len(GetExtensionPart(File))-1)+".wav"
 
  outId.l = CreateFile(#PB_Any,x$) 
  If outId = #Null
    MessageRequester("Error", "Unable to create file",#MB_ICONERROR) ; chris319
    ProcedureReturn #False
  EndIf
 
  b.w = Config\format\wBitsPerSample
  c.w = Config\format\nChannels
  h.l = Config\format\nSamplesPerSec
 
  WriteString(outId, "RIFF") ; 4 bytes

;  WriteLong(outId, lBuf+44) ; 4 bytes
  WriteLong(outId, chunksize) ; 4 bytes -- chris319

  WriteString(outId, "WAVEfmt ") ; 8 bytes -- chris319
    ;WriteString(outId, "fmt ")
 
  ;WriteLong(outId, 16)
  WriteLong(outId, b) ; 4 bytes -- chris319
 
   
  WriteWord(outId, 1) ; 2 bytes -- PCM
  WriteWord(outId, c) ; 2 bytes
  WriteLong(outId, h) ; 4 bytes
  WriteLong(outId, c*h*(b/8)) ; 4 bytes
 
  ;WriteWord(outId, c*(h/8))
  WriteWord(outId, (c * b) / 8) ; -- blockalign 2 bytes -- chris319
   
  WriteWord(outId, b) ; 2 bytes
  WriteString(outId, "data") ; 4 bytes

  WriteLong(outId, lBuf) ; -- 4 bytes
  WriteData(outId, pBuf,lBuf)
 
  CloseFile(outId)
 
  ProcedureReturn #True
 
EndProcedure
;
Procedure GUI_Init()
  QuitRec = 0
  WndId.l = OpenWindow(0,0,0,500,400,"Recorder",#PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_Invisible)
  If WndId=#Null : ProcedureReturn #False : EndIf
 
  Config\hWindow=WindowID(0)
  Config\output=WindowOutput(0)
 
  Config\hToolBar=CreateToolBar(#ToolBar,Config\hWindow)
  If Config\hToolBar=#Null : ProcedureReturn #False : EndIf
 
  If CreateStatusBar(#StatusBar,Config\hWindow)=#Null
    ProcedureReturn #False
  EndIf
 
  ToolBarStandardButton(#gadStart,#PB_ToolBarIcon_Open)
  ToolBarStandardButton(#gadStop,#PB_ToolBarIcon_Delete)
 
  ToolBarStandardButton(#gadFile,#PB_ToolBarIcon_Save)
  ToolBarSeparator()
  ToolBarStandardButton(#gadSndVol,#PB_ToolBarIcon_Properties)
  ToolBarSeparator()
 
  ToolBarToolTip(#ToolBar, #gadStart,"Record")
  ToolBarToolTip(#ToolBar, #gadStop,"Stop")
  ToolBarToolTip(#ToolBar, #gadFile,"Create a file")
  ToolBarToolTip(#ToolBar, #gadSndVol,"Volume")
 
  GUI_TBCombo(#gadChannel,0,1,58,200)
  AddGadgetItem(#gadChannel,-1,"Mono")
  AddGadgetItem(#gadChannel,-1,"Stereo")
  SetGadgetState(#gadChannel,0)
 
  GUI_TBCombo(#gadResolution,2,1,55,200)
  AddGadgetItem(#gadResolution,-1,"8 bits")
  AddGadgetItem(#gadResolution,-1,"16 bits")
 
  GUI_TBCombo(#gadFrequence,2,1,80,200)
  AddGadgetItem(#gadFrequence,-1,"8.0 kHz")
  AddGadgetItem(#gadFrequence,-1,"11.025 kHz")
  AddGadgetItem(#gadFrequence,-1,"12.0 kHz")
  AddGadgetItem(#gadFrequence,-1,"16.0 kHz")
  AddGadgetItem(#gadFrequence,-1,"22.05 kHz")
  AddGadgetItem(#gadFrequence,-1,"24.0 kHz")
  AddGadgetItem(#gadFrequence,-1,"32.0 kHz")
  AddGadgetItem(#gadFrequence,-1,"44.1 kHz")
  AddGadgetItem(#gadFrequence,-1,"48.0 kHz")
 
  GUI_TBCombo(#gadDevice,2,1,160,200)
  CAPTURE_GetDevices(#gadDevice)
  SetGadgetState(#gadDevice,0)
 
  Frame3DGadget(#gadFrame1,0,0,0,0,"",#PB_Frame3D_Double)
  Frame3DGadget(#gadFrame2,0,0,0,0,"",#PB_Frame3D_Double)
 
  AddStatusBarField( 100)
  AddStatusBarField(  80)
  AddStatusBarField(1000)
  StatusBarText(0,0,"0 "+"bytes",#PB_StatusBar_Center)
  StatusBarText(0,1,"0.000 "+"secs",#PB_StatusBar_Center)
 
  SetWindowCallback(@GUI_CallBack())
  FILE_Recording(#False)
  GUI_Resize()
 
  ProcedureReturn #True
 
EndProcedure
;
Procedure GUI_Resize()
 
  WndW.l = ( WindowWidth(0)  -  4 )
  WndH.l = ( WindowHeight(0) - 60 ) >> 1

  Config\LScope\left     = 2
  Config\LScope\top      = 30
  Config\LScope\width    = WndW
  Config\LScope\height   = WndH
  Config\LScope\quarterY = Config\LScope\height >> 2
  Config\LScope\middleY  = Config\LScope\top + Config\LScope\height >> 1
  ResizeGadget(#gadFrame1,Config\LScope\left-2,Config\LScope\top-2,Config\LScope\width+4,Config\LScope\height+4)
 
  Config\RScope\left     = 2
  Config\RScope\top      = Config\LScope\top + Config\LScope\height + 6
  Config\RScope\width    = WndW
  Config\RScope\height   = WndH
  Config\RScope\quarterY = Config\RScope\height >> 2
  Config\RScope\middleY  = Config\RScope\top + Config\RScope\height >> 1
  ResizeGadget(#gadFrame2,Config\RScope\left-2,Config\RScope\top-2,Config\RScope\width+4,Config\RScope\height+4)
 
EndProcedure
;
Procedure GUI_TBCombo(Id,x,y,w,h)
 
  pos=SendMessage_(Config\hToolBar,#TB_BUTTONCOUNT,0,0)
  ToolBarSeparator()       
  SendMessage_(Config\hToolBar,#TB_GETBUTTON,pos,@separator.TBBUTTON)
  separator\iBitmap=x+w
  SendMessage_(Config\hToolBar,#TB_DELETEBUTTON,pos,0)
  SendMessage_(Config\hToolBar,#TB_INSERTBUTTON,pos,separator)
  SendMessage_(Config\hToolBar,#TB_GETITEMRECT,pos,@rc.RECT)   
  UseGadgetList(Config\hToolBar)
  ComboBoxGadget(Id,x+rc\left,y,w,h)
  UseGadgetList(Config\hWindow)
 
EndProcedure
;
Procedure GUI_CallBack(hWnd.l,Msg.l,wParam.l,lParam.l)
 
  Result.l=#PB_ProcessPureBasicEvents
 
  Select Msg
    Case #WM_KEYDOWN
      If GetAsyncKeyState_(#VK_ESCAPE)
        QuitRec = 1
      EndIf
    Case #WM_SIZE     : GUI_Resize()
    Case #WM_TIMER    : DRAW_Scope()
    Case #MM_WIM_DATA : CAPTURE_Read(wParam,lParam)
    Case #WM_COMMAND
      Select wParam & $FFFF
        Case #gadStart      : FILE_Create()
        Case #gadStop       : FILE_Close()
        Case #gadFile       : FILE_Select()
        Case #gadSndVol     : RunProgram(Config\SndVol,"","")
        Case #gadFrequence  : If EventType()=9 : CAPTURE_Start() : EndIf
        Case #gadResolution : If EventType()=9 : CAPTURE_Start() : EndIf
        Case #gadChannel    : If EventType()=9 : CAPTURE_Start() : EndIf
        Case #gadDevice     : If EventType()=9 : CAPTURE_Start() : EndIf
      EndSelect
    Case #WM_GETMINMAXINFO
      *mmi.MINMAXINFO=lParam
      *mmi\ptMinTrackSize\x=#MinWidth
      *mmi\ptMinTrackSize\y=#MinHeight
  EndSelect
 
  ProcedureReturn Result
 
EndProcedure
;
;- REC MAIN
;
Procedure StartRecorder()
 
  If GUI_Init()
    CONFIG_Load()
    CAPTURE_Start()
    Repeat
    Until WaitWindowEvent()=#WM_CLOSE Or QuitRec
    CAPTURE_Stop()
    CONFIG_Save()
  EndIf
 
EndProcedure

StartRecorder()


Last edited by chris319 on Sun Apr 05, 2009 7:29 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 07, 2007 10:43 pm 
Offline
Addict
Addict
User avatar

Joined: Tue Jul 22, 2003 5:02 pm
Posts: 1496
Location: Nantes, France
so cool,

i will have a look at your changes :)

thank you chris319

_________________
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 08, 2007 4:53 am 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
Flype -

You made a lot of changes since the first version.

Do you want to work on a DirectSound recorder/meter? Something that would go up to 24 bits/96000 Hz? This low-level interfacing to Windows confuses me.

I want to look into getting PB to support the new MMCSS in Vista. MMCSS has a category called "Pro Audio" which gives higher priority to real-time functions such as audio recording.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 08, 2007 10:27 pm 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
You want to change a line in GUI_CallBack. "Case #WM_SIZE" should be "Case #WM_PAINT".


Top
 Profile  
 
 Post subject:
PostPosted: Sun Sep 09, 2007 12:44 am 
Offline
User
User
User avatar

Joined: Wed Aug 30, 2006 12:07 am
Posts: 75
I get the error line 187:windowID():Incorrect Number of parameters

** Edit **

Now I get the error Line 84: Structure Not Found: WaveFormatEx

** Edit **

Now I'm getting Line 111:Structure Field Not Found:Format


Top
 Profile  
 
 Post subject:
PostPosted: Sun Sep 09, 2007 2:00 am 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
Ah, should've mentioned that this was tested on PB 4.10 beta 3. Sorry for the inconvenience. The WAVEFORMATEX structure is still in there, only commented out.

That's the correct number of parameters for WindowID().


Top
 Profile  
 
 Post subject:
PostPosted: Sun Sep 09, 2007 10:47 pm 
Offline
User
User
User avatar

Joined: Wed Aug 30, 2006 12:07 am
Posts: 75
I see. I'll have to download that then.

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 10, 2007 8:07 pm 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
I'm not sure this program will work very well under Vista. After some testing over the weekend, the record level control seems to behave quite erratically and this directly affects metering. There is this from Larry Osterman's blog:

Quote:
For capture, clipping happens whenever the volume control at the ADC (analog-digital converter) is set too high. That means that the only volume control that actually matters for capture is the master volume. The entire concept of per-application volume doesn't work for capture.

Needless to say, this was a bit embarrassing. Inside the audio engine, capture and render are essentially identical - the only difference between the two is the order in which the audio graph is built, so my internal mind-set treated them the same. I'd been so focused on rendering scenarios that I simply didn't think about how capture was basically different from render.

This tells me that Osterman/Microsoft were designing the new Vista audio stack around games and watching movies. Audio recording/capture were clearly an afterthought.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 11, 2007 9:22 pm 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
The outlook for this program under Vista may not be as dire as first thought. There is a workaround for the erratic behavior of Vista audio.

Go to Control Panel -> Sound -> Recording and select one of the devices you plan to use. Click on the "Enhancements" tab and check the "Disable All Enhacements" box. Unless this box is explicitly checked, the volume control will behave erratically.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 27, 2007 2:54 am 
Offline
Enthusiast
Enthusiast

Joined: Mon May 14, 2007 2:13 am
Posts: 734
Location: Darling River
I like your changes to this code chris319.
Works a treat, Thanks...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 05, 2007 4:57 am 
Offline
Addict
Addict
User avatar

Joined: Sat Feb 19, 2005 5:05 pm
Posts: 1693
Location: Norway
Or use OpenAL 1.1 which supports recording, and if a native OpenAL driver is available for your card then have fun, not entirely sure what happens if no native driver is available though, it should fall back to DirectSound or WaveIn in that case and no idea if the enhancements affect the recording in that case (when through OpenAL).

_________________
Image website, journal, projects, reviews and more.
Normality exist in the minds of others, not mine! - Rescator


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 15, 2007 7:50 am 
Offline
Enthusiast
Enthusiast

Joined: Mon Oct 24, 2005 1:05 pm
Posts: 386
Flype is the real brains behind this program. I just make it look pretty :-)

OpenAL does not support 24-bit recording. If I were to change the audio platform it would have to be something which supports 24-bit recording. Also, come to learn that WMM does not recognize S/PDIF input. For that you need ASIO. You can see why I'm so confused :?:


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 68 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye