[DONE]Sound output for externel Device

Just starting out? Need help? Post your questions and find answers here.
gregreen
User
User
Posts: 28
Joined: Fri Apr 21, 2023 7:26 pm

Re: [DONE]Sound output for externel Device

Post by gregreen »

My guess was correct. It is expecting 48,000 not 44100

Code runs now but there is a big "snap" when the audio ends. I'm looking into that.
gregreen
User
User
Posts: 28
Joined: Fri Apr 21, 2023 7:26 pm

Re: [WORKING] Sound output for externel Device

Post by gregreen »

This code is working for me but I'd like to figure out how to set left/right volume. It's mentioned above, I just have to see if I can figure it out.
This is really pretty awesome if I can get everything I want to do working! Very grateful for this forum! I fixed the "snap" by adding an Eof check in the PLAY_Write() procedure.

Code: Select all

EnableExplicit
;/ Edited by gregreen Sept. 7, 2024  Working with PB 6.10
    ;/ Object     Audio player 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
    ;  04/02/2010 : DrGolf for PB 4.50
    ;  01/20/2011 : Vitor_Boss® -- Fixed clamping
    ;  6/8/2012 -- revised again by chris319 on PB 4.61
    ;  28/8/2022 : modified by morosh
    ;   modified
    
#MONO = 1
#STEREO = 2
#Button =0

Global QuitRec
Global lBuf, nBuf, nDev, fname.s, format.WAVEFORMATEX,  hWindow, FileId
Global size, buffer, output, wave, played ,playing.b
Global Dim outHdr.WAVEHDR(16)
Global testfail=0

Declare PLAY_Stop()
Declare PLAY_Start()
Declare PLAY_GetDevices()
Declare PLAY_Write(hwaveOut,*hWave.WAVEHDR)
Declare FILE_Close()
Declare FILE_Open()
Declare FILE_wav2raw(fname.s)

Declare GUI_CallBack(hWnd,Msg,wParam,lParam)

Procedure getfiledatanum(nof, offset, len)
Protected tmpl=0, ch, i
FileSeek(nof,offset)
For i=1 To len
  ReadData(nof, @ch, 1)
  tmpl+ch*Pow(256,i-1)
Next
ProcedureReturn tmpl
EndProcedure

Procedure PLAY_Start()
Define i
format\wFormatTag = getfiledatanum(0,20,2)
format\nChannels = getfiledatanum(0,22,2)
format\nSamplesPerSec = getfiledatanum(0,24,4)
format\wBitsPerSample = getfiledatanum(0,34,2) 
;FileSeek(0,58)  <- changed this because starting later swapped the left/right channel?
FileSeek(0,SizeOf(WAVEHDR))  ;Why not set to the size of the WAVEHDR?
PLAY_Stop()
format\nBlockAlign = (format\nChannels * format\wBitsPerSample) / 8
format\nAvgBytesPerSec = format\nSamplesPerSec * format\nBlockAlign
format\cbSize = 0
 
If waveOutOpen_(@wave,nDev,@format,hWindow,#Null,#CALLBACK_WINDOW|#WAVE_FORMAT_DIRECT) = #MMSYSERR_NOERROR  
  Debug "wave: "+Str(wave)+" nDev: "+Str(nDev)+" Header size: "+SizeOf(WAVEHDR)
  
  For i = 0 To nBuf - 1
    outHdr(i)\lpData = AllocateMemory(lBuf)
    outHdr(i)\dwBufferLength = lBuf
    waveOutPrepareHeader_(wave,outHdr(i),SizeOf(WAVEHDR))
    waveOutWrite_(wave,outHdr(i),SizeOf(WAVEHDR))
  Next
  If waveOutReset_(wave) <> #MMSYSERR_NOERROR
    MessageRequester("Error","waveOutStart_(wave)",#MB_ICONERROR)
    QuitRec=1
  EndIf
Else
  MessageRequester("Error","waveOutOpen_ failed",#MB_ICONERROR)
  QuitRec=1  
EndIf

EndProcedure

Procedure PLAY_Stop()
  Define i.a
  Debug "PLAY_Stop()"
  If wave
  waveOutReset_(wave)
 ; waveOutStop_(wave)
  For i = 0 To nBuf - 1
    If outHdr(i)
      Debug "outHdr: "+Str(outHdr(i))
      waveOutUnprepareHeader_(wave,outHdr(i),SizeOf(WAVEHDR))
    EndIf
  Next
  waveOutClose_(wave)
EndIf
EndProcedure
    ;
Procedure PLAY_Write(hwaveOut,*hWave.WAVEHDR)
  ;  Define *hWave.WAVEHDR
  ;*hWave=lpWaveHdr
  
buffer=*hWave\lpData
size=*hWave\dwBufferLength
;size is 2048?
If playing = #True
  ReadData(0, buffer,size)
  If Eof(0)
    Debug "The End was reached: "+Str(played)
    Debug "file length: "+Str(Lof(0))
    PLAY_Stop()
  EndIf 
  played + size
  Debug "Played: "+Str(played+size)+ " of "
EndIf

waveOutWrite_(hwaveOut,*hWave,SizeOf(WAVEHDR)) ;-------------------------------------------------------------------- added -1
;Beep_(100,100)
EndProcedure
    ;
Procedure PLAY_GetDevices()
  Define MMNumDevice, MMDeviceId, MMResult, Caps.waveOutCAPS
  
  MMNumDevice = waveOutGetNumDevs_()
  If MMNumDevice
    For MMDeviceId=#WAVE_MAPPER To MMNumDevice-1
      MMResult = waveOutGetDevCaps_(MMDeviceId,@Caps,SizeOf(waveOutCAPS))
      If MMResult = #MMSYSERR_NOERROR
         Debug Str(MMDeviceId) + "  " + PeekS(@Caps\szPname,#MAXPNAMELEN)
        ; AddGadgetItem(gadId,-1,PeekS(@Caps\szPname,#MAXPNAMELEN))
      EndIf
    Next
  EndIf
EndProcedure
 
Procedure FILE_Open()
If playing = #False
  FILE_wav2raw(fname)
EndIf
played  = #Null ; -- MOVED HERE BY chris319
Debug "Reading file: "+fname
FileId=ReadFile(0,fname)
Debug "FileID: "+Str(FileID)
If FileId
  playing=#True
Else
  MessageRequester("Error","Can't Read file",#MB_ICONERROR)
EndIf 
EndProcedure

Procedure FILE_Close()
If playing
  playing = #False
  CloseFile(0)
  Delay(1000)
EndIf
EndProcedure

Procedure FILE_wav2raw(fname.s)  ;create a raw file?
Define inId, outId, pBuf, subchunk2size, chunksize, f$, x$, b.w, c.w, h
;Commented this out because no need to create a PCM raw file / It does work and create a .RAW file if you uncomment!
; inId = ReadFile(#PB_Any,fname)
; 
; If inId = #Null
;   MessageRequester("Error", "Unable to open file",#MB_ICONERROR) ; chris319
;   ProcedureReturn #False
; EndIf
; 
; lBuf = Lof(inId)
; If lBuf = #Null
;   MessageRequester("Error", "lbuf=0",#MB_ICONERROR) ; chris319
;   ProcedureReturn #False
; EndIf
; 
; pBuf = AllocateMemory(lBuf)
; If pBuf = #Null
;   MessageRequester("Error", "Unable to allocate buffer",#MB_ICONERROR) ; chris319
;   ProcedureReturn #False
; EndIf
; 
; ReadData(inId, pBuf,lBuf)
; CloseFile(inId)
; 
; f$ = GetFilePart(fname)
; x$ = GetPathPart(fname)+Left(f$,Len(f$)-Len(GetExtensionPart(fname))-1)+".raw"
; 
; outId = CreateFile(#PB_Any,x$)
; If outId = #Null
;   MessageRequester("Error", "Unable to create file",#MB_ICONERROR) ; chris319
;   ProcedureReturn #False
; EndIf
; WriteData(outId, pBuf+58,lBuf-58)
; 
; CloseFile(outId)
; FreeMemory(pBuf) ;chris319
; ProcedureReturn #True
EndProcedure
        ;
Procedure GUI_CallBack(hWnd,Msg,wParam,lParam)
  Define Result
  
Result = #PB_ProcessPureBasicEvents
Select Msg
  Case #WM_KEYDOWN
    If GetAsyncKeyState_(#VK_ESCAPE)
      QuitRec = 1
    EndIf
  Case #MM_WOM_DONE
    PLAY_Write(wParam,lParam)
  Case #WM_COMMAND
    Select wParam & $FFFF
      Case #Button      
        FILE_Open() : PLAY_Start()
      Case #Button+1    
        FILE_Close() : QuitRec=1
  EndSelect
EndSelect
ProcedureReturn Result     
EndProcedure
    ;- REC MAIN
;;;;;;;;;;;;;;;;;;;;;;;;;;;GUI_init ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QuitRec = 0
fname = "c:\audio\singer0_48.wav"  ;needs to be 48,000 Sample Rate
nDev = 6  ;was 0 changed to 6 as this is the audio output channel 3&4 for testing
nBuf = 8
lBuf = 2048

hWindow=OpenWindow(0,0,0,500,400,"Player",#PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_SizeGadget)
LoadFont(0, "Arial", 12)
ButtonGadget(#Button, 50,50,100,20,"Replay")
ButtonGadget(#Button+1, 200,50,100,20,"Stop")
SetGadgetFont(#Button, FontID(0)) 
SetGadgetFont(#Button+1, FontID(0)) 

PLAY_GetDevices()
SetWindowCallback(@GUI_CallBack())
playing = #False

FILE_Open()
PLAY_Start()
Repeat
  
Until WaitWindowEvent() = #WM_CLOSE Or QuitRec
PLAY_Stop()
CloseDebugOutput()
;  Devices
;-1  Microsoft Sound Mapper
;0  Speakers (Realtek High Definiti
;1  Realtek Digital Output (Realtek
;2  Speakers (Bluetooth AV Audio)
;3  Speakers (Bluetooth SCO Audio)

PHP
User
User
Posts: 65
Joined: Sat Sep 10, 2005 5:38 pm

Re: [DONE]Sound output for externel Device

Post by PHP »

Test the last code here and got this:

Image

Of course the .wav file is 48 kHz...

Any ideas what's wrong? Do i have to select the output device first somewhere?
Post Reply