Skip to content

Commit

Permalink
Fix finishCallback not compiling and pass the player to the callback
Browse files Browse the repository at this point in the history
Add a finishCallback usage to the example project
  • Loading branch information
samdze committed Apr 13, 2024
1 parent 44898f0 commit d0c5c74
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 25 deletions.
3 changes: 3 additions & 0 deletions playdate_example/src/playdate_example.nim
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ proc handler(event: PDSystemEvent, keycode: uint) {.raises: [].} =
# Errors are handled through exceptions
try:
samplePlayer = playdate.sound.newSamplePlayer("/audio/jingle")

samplePlayer.finishCallback = proc(player: SamplePlayer) =
playdate.system.logToConsole("Sound finished playing.")
except:
playdate.system.logToConsole(getCurrentExceptionMsg())
# Inline try/except
Expand Down
9 changes: 5 additions & 4 deletions src/playdate/bindings/sound.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import utils
type FilePlayerPtr = pointer
type AudioSamplePtr = pointer
type SamplePlayerPtr = pointer
type SoundSourcePtr = pointer
type SoundSourceRaw {.importc: "SoundSource", header: "pd_api.h".} = object
type SoundSourcePtr = ptr SoundSourceRaw

type PDSndCallbackProcRaw {.importc: "sndCallbackProc", header: "pd_api.h".} = proc(soundSource: SoundSourcePtr, userData: pointer): void {.cdecl.}
type PDSndCallbackProcRaw {.importc: "sndCallbackProc", header: "pd_api.h".} = proc(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl.}


type PlaydateSoundFileplayer {.importc: "const struct playdate_sound_fileplayer",
Expand All @@ -33,8 +34,8 @@ type PlaydateSoundFileplayer {.importc: "const struct playdate_sound_fileplayer"
# setLoopRange* {.importc: "setLoopRange".}: proc (player: ptr FilePlayer;
# start: cfloat; `end`: cfloat) {.cdecl.}
# didUnderrun* {.importc: "didUnderrun".}: proc (player: ptr FilePlayer): cint {.cdecl.}
# setFinishCallback* {.importc: "setFinishCallback".}: proc (
# player: ptr FilePlayer; callback: SndCallbackProc) {.cdecl.}
setFinishCallback* {.importc: "setFinishCallback".}: proc (
player: FilePlayerPtr; callback: PDSndCallbackProcRaw, userData: pointer = nil) {.cdecl, raises: [].}
# setLoopCallback* {.importc: "setLoopCallback".}: proc (player: ptr FilePlayer;
# callback: SndCallbackProc) {.cdecl.}
getOffset {.importc: "getOffset".}: proc (player: FilePlayerPtr): cfloat {.cdecl, raises: [].}
Expand Down
67 changes: 46 additions & 21 deletions src/playdate/sound.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ proc getLength*(this: AudioSample): float32 =
# AudioSource
type SoundSourceObj {.requiresinit.} = object of RootObj
resource: pointer
callback: PDSoundCallbackFunction
type SoundSource* = ref SoundSourceObj

# FilePlayer
type
FilePlayerObj = object of SoundSourceObj
finishCallback: PDFilePlayerCallbackFunction
FilePlayer* = ref FilePlayerObj

PDFilePlayerCallbackFunction* = proc(player: FilePlayer) {.raises: [].}

proc `=destroy`(this: var FilePlayerObj) =
privateAccess(PlaydateSound)
privateAccess(PlaydateSoundFileplayer)
Expand All @@ -65,12 +67,12 @@ proc `=destroy`(this: var FilePlayerObj) =
proc newFilePlayer*(this: ptr PlaydateSound): FilePlayer =
privateAccess(PlaydateSound)
privateAccess(PlaydateSoundFileplayer)
result = FilePlayer(resource: this.fileplayer.newPlayer(), callback: nil)
result = FilePlayer(resource: this.fileplayer.newPlayer(), finishCallback: nil)

proc newFilePlayer*(this: ptr PlaydateSound, path: string): FilePlayer {.raises: [IOError].} =
privateAccess(PlaydateSound)
privateAccess(PlaydateSoundFileplayer)
result = FilePlayer(resource: this.fileplayer.newPlayer(), callback: nil)
result = FilePlayer(resource: this.fileplayer.newPlayer(), finishCallback: nil)
if this.fileplayer.loadIntoPlayer(result.resource, path.cstring) == 0:
raise newException(IOError, fmt"file {path} not found: No such file")

Expand Down Expand Up @@ -132,12 +134,35 @@ proc `offset=`*(this: FilePlayer, offset: float32) =
privateAccess(PlaydateSoundFileplayer)
playdate.sound.fileplayer.setOffset(this.resource, offset.cfloat)

proc privateFilePlayerFinishCallback(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl, raises: [].} =
let filePlayer = cast[FilePlayer](userdata)
if filePlayer.finishCallback != nil:
filePlayer.finishCallback(filePlayer)

proc setFinishCallback*(this: FilePlayer, callback: PDFilePlayerCallbackFunction) =
privateAccess(PlaydateSound)
privateAccess(PlaydateSoundFileplayer)
this.finishCallback = callback
if callback == nil:
playdate.sound.fileplayer.setFinishCallback(this.resource, nil, nil)
else:
playdate.sound.fileplayer.setFinishCallback(this.resource, privateFilePlayerFinishCallback, cast[pointer](this))

proc finishCallback*(this: FilePlayer): PDFilePlayerCallbackFunction =
return this.finishCallback

proc `finishCallback=`*(this: FilePlayer, callback: PDFilePlayerCallbackFunction) =
this.setFinishCallback(callback)

# SamplePlayer
type
SamplePlayerObj = object of SoundSourceObj
sample: AudioSample
finishCallback: PDSamplePlayerCallbackFunction
SamplePlayer* = ref SamplePlayerObj

PDSamplePlayerCallbackFunction* = proc(player: SamplePlayer) {.raises: [].}

proc `=destroy`(this: var SamplePlayerObj) =
privateAccess(PlaydateSound)
privateAccess(PlaydateSoundSampleplayer)
Expand All @@ -147,7 +172,7 @@ proc `=destroy`(this: var SamplePlayerObj) =
proc newSamplePlayer*(this: ptr PlaydateSound): SamplePlayer =
privateAccess(PlaydateSound)
privateAccess(PlaydateSoundSampleplayer)
result = SamplePlayer(resource: this.sampleplayer.newPlayer(), callback: nil)
result = SamplePlayer(resource: this.sampleplayer.newPlayer(), finishCallback: nil)

proc sample*(this: SamplePlayer): AudioSample =
return this.sample
Expand All @@ -161,7 +186,7 @@ proc `sample=`*(this: SamplePlayer, sample: AudioSample) =
proc newSamplePlayer*(this: ptr PlaydateSound, path: string): SamplePlayer {.raises: [IOError].} =
privateAccess(PlaydateSound)
privateAccess(PlaydateSoundSampleplayer)
result = SamplePlayer(resource: this.sampleplayer.newPlayer(), callback: nil)
result = SamplePlayer(resource: this.sampleplayer.newPlayer(), finishCallback: nil)
result.`sample=`(this.newAudioSample(path))

proc volume*(this: SamplePlayer): tuple[left: float32, right: float32] =
Expand Down Expand Up @@ -221,25 +246,25 @@ proc rate*(this: SamplePlayer): float32 =
privateAccess(PlaydateSoundSampleplayer)
return playdate.sound.sampleplayer.getRate(this.resource).float32

proc privateSampleFinishCallback(soundSourcePtr: SoundSourcePtr, userData: pointer) {.cdecl, raises: [].} =
try:
let samplePlayer = cast[SamplePlayer](userdata)[]
if samplePlayer.callback != nil:
samplePlayer.callback(userData)
except:
echo "Error while calling SamplePlayer finish callback"
proc privateSamplePlayerFinishCallback(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl, raises: [].} =
let samplePlayer = cast[SamplePlayer](userdata)
if samplePlayer.finishCallback != nil:
samplePlayer.finishCallback(samplePlayer)

proc setFinishCallback*(this: SamplePlayer, callback: PDSoundCallbackFunction) =
proc setFinishCallback*(this: SamplePlayer, callback: PDSamplePlayerCallbackFunction) =
privateAccess(PlaydateSound)
privateAccess(PlaydateSoundSampleplayer)
try:
this.callback = callback
if callback == nil:
playdate.sound.sampleplayer.setFinishCallback(this.resource, nil, nil)
else:
playdate.sound.sampleplayer.setFinishCallback(this.resource, privateSampleFinishCallback, cast[pointer](this))
except:
echo "Error setting finish callback"
this.finishCallback = callback
if callback == nil:
playdate.sound.sampleplayer.setFinishCallback(this.resource, nil, nil)
else:
playdate.sound.sampleplayer.setFinishCallback(this.resource, privateSamplePlayerFinishCallback, cast[pointer](this))

proc finishCallback*(this: SamplePlayer): PDSamplePlayerCallbackFunction =
return this.finishCallback

proc `finishCallback=`*(this: SamplePlayer, callback: PDSamplePlayerCallbackFunction) =
this.setFinishCallback(callback)

proc setPlayRange*(this: SamplePlayer, start: int32, `end`: int32) =
privateAccess(PlaydateSound)
Expand Down

0 comments on commit d0c5c74

Please sign in to comment.