Playing sound files with Cocoa

Mac OSX specific forum
WilliamL
Addict
Addict
Posts: 1224
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Playing sound files with Cocoa

Post by WilliamL »

Well, I feel that I came late to the party. It seems that wilbert posted the code https://www.purebasic.fr/english/viewto ... 31#p392931 for playing sounds with Cocoa ten years ago. I guess I didn't need it till I upgraded to Catalina and InitMovie() quit working.

So I explored playing the system sounds with Cocoa using wilbert's code. https://www.purebasic.fr/english/viewtopic.php?t=78710

Now I have re-written my code to use wilber's code to play files. I'm only interested in playing short sounds like system sounds when loading/saving/clicking/error/etc. so his code works fine. I haven't tried playing longer files and I imagine you'd need to know when the playing is over etc.

Here is his code to load and play a sound.

Code: Select all

EnableExplicit
Define MySound,Sound_SetVolume,Sound_Play
Define event,filename$

Procedure Sound_Load(FileName.s)
  ProcedureReturn CocoaMessage(0,CocoaMessage(0,0,"NSSound alloc"), "initWithContentsOfFile:$", @FileName, "byReference:", #YES)
EndProcedure

Procedure Sound_Catch(*MemoryAddress, Size)
  Protected Result.i = CocoaMessage(0, 0, "NSData dataWithBytes:", *MemoryAddress, "length:", Size)
  If Result : Result = CocoaMessage(0, CocoaMessage(0, 0, "NSSound alloc"), "initWithData:", Result) : EndIf
  ProcedureReturn Result
EndProcedure

Procedure Sound_SetVolume(SoundObject, Volume.f)
  CocoaMessage(0, SoundObject, "setVolume:@", @Volume)
EndProcedure

Procedure Sound_Play(SoundObject, Loop = 0)
  Protected currentTime.d
  CocoaMessage(0, SoundObject, "setLoops:", Loop)
  CocoaMessage(0, SoundObject, "setCurrentTime:@", @currentTime)
  ProcedureReturn CocoaMessage(0, SoundObject, "play")
EndProcedure

Procedure Sound_Stop(SoundObject)
  ProcedureReturn CocoaMessage(0, SoundObject, "stop")
EndProcedure

Procedure Sound_IsPlaying(SoundObject)
  ProcedureReturn CocoaMessage(0, SoundObject, "isPlaying")
EndProcedure

Procedure Sound_Release(SoundObject)
  CocoaMessage(0, SoundObject, "stop")
  CocoaMessage(0, SoundObject, "release")
EndProcedure

;filename$="/Users/vering2/Desktop/WhirrSoft.aif"
Filename$ = OpenFileRequester("Open mp3","WhirrSoft.aif","",1)
Debug filename$

MySound = Sound_Load(filename$)
Sound_SetVolume(MySound, 0.8)
Sound_Play(MySound)

If OpenWindow(0,100,100,100,100,"This window must be open",#PB_Window_SystemMenu | #PB_Window_WindowCentered)

EndIf

Repeat
    event = WaitWindowEvent()
Until event=#PB_Event_CloseWindow
Here is the code I am using in my program. It will not run but will only show how I did it. I load all the sounds at once and just use the address when playing the sound. The first part is the code provided by wilbert in his post.

Code: Select all

;sound section
Procedure Sound_Load(FileName.s)
  ProcedureReturn CocoaMessage(0,CocoaMessage(0,0,"NSSound alloc"), "initWithContentsOfFile:$", @FileName, "byReference:", #YES)
EndProcedure

Procedure Sound_Catch(*MemoryAddress, Size)
  Protected Result.i = CocoaMessage(0, 0, "NSData dataWithBytes:", *MemoryAddress, "length:", Size)
  If Result : Result = CocoaMessage(0, CocoaMessage(0, 0, "NSSound alloc"), "initWithData:", Result) : EndIf
  ProcedureReturn Result
EndProcedure

Procedure Sound_SetVolume(SoundObject, Volume.f)
  CocoaMessage(0, SoundObject, "setVolume:@", @Volume)
EndProcedure

Procedure Sound_Play(SoundObject, Loop = 0)
  Protected currentTime.d
  CocoaMessage(0, SoundObject, "setLoops:", Loop)
  CocoaMessage(0, SoundObject, "setCurrentTime:@", @currentTime)
  ProcedureReturn CocoaMessage(0, SoundObject, "play")
EndProcedure

Procedure Sound_Stop(SoundObject)
  ProcedureReturn CocoaMessage(0, SoundObject, "stop")
EndProcedure

Procedure Sound_IsPlaying(SoundObject)
  ProcedureReturn CocoaMessage(0, SoundObject, "isPlaying")
EndProcedure

Procedure Sound_Release(SoundObject)
  CocoaMessage(0, SoundObject, "stop")
  CocoaMessage(0, SoundObject, "release")
EndProcedure
;--end of coca sound routines

Global Dim SoundAddress(7) ; one extra for 'end'

DataSection
    SoundData:
    Data.s "WhirrSoft.aif","Tink.aiff","click.aif","Uh oh.aif","Frog.aiff","Bye.mp3","Whit.aif","End"
EndDataSection

Enumeration 1
    #sndsave
    #sndtink ; up/down arrows
    #sndclick
    #snderror ; Uh oh.aiff
    #sndmove  ; left/right arrows
    #sndbye   ; end prog
    #sndwhit ; rename file
EndEnumeration

Restore SoundData : cnt=1 : Read.s filename$
While filename$<>"End"
    event=Sound_Load(RsrcPath+"Sounds/"+filename$)
    If event=0
       MessageRequester("Loading sounds...",filename$+" was not loaded")
    Else
        SoundAddress(cnt)=event
    EndIf
    cnt+1
    Read.s filename$
Wend
;End snd section

Procedure Speak(snd)
    Sound_SetVolume(SoundAddress(snd), 0.8)
    Sound_Play(SoundAddress(snd))
EndProcedure
MacBook Pro-M1 (2021), Sonoma 14.4.1, PB 6.10LTS M1