
On Thu, 16 Dec 2004 12:38:26 +0000, Jules Bean
On 16 Dec 2004, at 06:57, Sebastian Sylvan wrote:
Here's the problem though. If the SamplePlaybackRaw is currently playing sound when it gets garbage collected, I want to keep the sound resource (SoundSample) alive until the playback has finished.
I probably haven't understood the details correctly but why not just spawn a thread in your 'start playback' function. This thread (a) keeps a reference to the soundsample (which guarantees it will never be GC'ed) and (b) checks every second or so to see if the playing has finished. If the playing has finished, it arranges to no longer hold the reference, and in due course GC will take it out.
This is my "if-all-else-fails" backup. I really don't want to poll the sound sample all the time since it uses up resources needlessly. If it comes to that, though, it's pretty much guaranteed that it will get the job done. The plan was to try to initiate the polling loop only when the GC wants to delete the sound channel. Here's what I imagine a typical execution could look like 1. Sound resource, s, is loaded 2. Calling "play" on s, returns a "channel" in which the sound is being played. 3. Repeat 2 any number of times. 4. The GC is being invoked. s may no longer be in scope, but the "channels" are still referencing the sound resource so it won't get collected. If the channel(s) are out of scope and the GC tries to collect them, they will each spawn a "keep-alive-loop" in their finalizer which has no other purpose but to keep the sound resource alive for however long it takes to finish playing. This is what I tried to do. I've now tried to do it with weak pointers as well. I get the finalizer to run, but for some reason the finalizer for the sound resource gets invoked before the finalizer for the channel. This is extremply strange since the channel contains a reference to the "ForeignPtr CSoundSample" so I wouldn't expect the sound resource finalizer to EVER get invoked while there are still channels around that are referencing it. Here's the latest attempt: -- the sound resource. -- The finalizer will simply call the C-library's "free"-function sampleLoad :: String -> IO SoundSample sampleLoad s = do cs <- newCString s samplePtr <- fsound_SampleLoad (-1) cs 0 0 0 finalizer <- mkSampleFinalizer sampleFinalizer newForeignPtr finalizer samplePtr -- The playback -- contains the channel AND a reference to the SoundSample -- so the soundsample should NEVER get finalized before the -- SamplePlaybackRaw data SamplePlaybackRaw = SP !CInt !SoundSample type SamplePlayback = Weak SamplePlaybackRaw -- play a sample samplePlay :: SoundSample -> IO SamplePlayback samplePlay sample = do ch <- withForeignPtr sample (fsound_PlaySound (-1)) let spb = SP ch sample -- SamplePlaybackRaw mkWeakPtr spb (Just (samplePlaybackFinalizer spb)) samplePlaybackFinalizer :: SamplePlaybackRaw -> IO () samplePlaybackFinalizer (SP ch sample) = do putStrLn "Starting keep-alive loop for sample playback" hFlush stdout touchForeignPtr sample forkIO (keepAlive ch sample) return () keepAlive :: CInt -> SoundSample -> IO () keepAlive ch sample = do putStrLn "Keeping channel alive!" hFlush stdout touchForeignPtr sample threadDelay 500000 -- wait a while b <- fsound_IsPlaying ch case cscharToBool b of True -> keepAlive ch sample False -> putStrLn "Finished keeping sample alive" /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862