I am working on a binding from Haskell to FMOD and I have run into a problem. I am trying to figure out if it is my binding code or if I am improperly using FMOD.
I combined 4 mono .wav files into a single .fsbank file. I want to play this file, but be able to set levels on the 4 channels within the sound. I used setMixLevelsInput and passed in an array of 4 zeroes, but all 4 channels play at their normal volumes. Is setMixLevelsInput the correct function to use in this situation?
Here is my main module
module MixBank2 where
import Control.Monad.Trans.Except (ExceptT (..), catchE, runExceptT, throwE)
import Data.Foldable (toList)
import Data.Sequence (Seq)
import qualified Data.Sequence as Sequence
import Fmod.LowLevel.Refined.Channel (Channel)
import qualified Fmod.LowLevel.Refined.Channel as Channel
import Fmod.LowLevel.Refined.Sound (Sound)
import qualified Fmod.LowLevel.Refined.Sound as Sound
import Fmod.LowLevel.Refined.System (System)
import qualified Fmod.LowLevel.Refined.System as System
import Fmod.LowLevel.Refined.Tokens
import Text.Read (readMaybe)
main :: IO (Either Result ())
main = runExceptT $ do
s <- System.create
System.init s 32 [FMOD_INIT_NORMAL] ()
snd <- System.createStream s "/home/bwroga/test.fsb" [FMOD_LOOP_NORMAL]
snd' <- Sound.getSubSound snd 0
c <- System.playSound s snd' Nothing False
let sq = Sequence.fromList $ [0,0,0,0]
Channel.setMixLevelsInput c (fromIntegral <$> toList sq)
System.update s
ask s c sq
Sound.release snd
System.release s
lift $ print "Done :]"
ask :: System -> Channel -> Seq Int -> ExceptT Result IO ()
ask s c sq = do
lift $ putStrLn ""
lift $ putStrLn "Toggle Channel (0-3), quit with q"
choice <- lift getLine
case choice of
x | Just y <- ((readMaybe x) :: Maybe Int)
, 0 <= y && y <= 3 ->
do let sq' = Sequence.adjust ((^2) . subtract 1) y sq
Channel.setMixLevelsInput c (fromIntegral <$> toList sq')
System.update s
ask s c sq'
"q" -> ExceptT $ return $ Right ()
_ -> do lift $ putStrLn "Invalid choice"
ask s c sq
lift :: (Monad m) => m a -> ExceptT e m a
lift = ExceptT . fmap Right
This is the definition of setMixLevelsInput in the module Fmod.LowLevel.Refined.Channel
setMixLevelsInput :: Channel -> [Double] -> ExceptT Result IO ()
setMixLevelsInput (Channel c) ls = ExceptT $
do withArray (realToFrac <$> ls) $ \ls' ->
do r <- Result <$> fmodChannelSetMixLevelsInput c ls' (fromIntegral $ length ls)
if r /= FMOD_OK
then return $ Left r
else return $ Right ()
This is the definition of fmodChannelSetMixLevelsInput in Fmod.LowLevel.Raw.Channel
foreign import ccall unsafe "fmod.h FMOD_Channel_SetMixLevelsInput"
fmodChannelSetMixLevelsInput :: Ptr FmodChannel -> Ptr CFloat -> CInt -> IO FmodResult
If I use setMixMatrix instead, I can get it to work.
main :: IO (Either Result ())
main = runExceptT $ do
s <- System.create
System.init s 32 [FMOD_INIT_NORMAL] ()
snd <- System.createStream s "/home/bwroga/test.fsb" [FMOD_LOOP_NORMAL]
snd' <- Sound.getSubSound snd 0
c <- System.playSound s snd' Nothing False
let sq = Sequence.fromList $ [0,0,0,0]
Channel.setMixMatrix c (fromIntegral <$> toList sq) 1 4
System.update s
ask s c sq
Sound.release snd
System.release s
lift $ print "Done :]"
ask :: System -> Channel -> Seq Int -> ExceptT Result IO ()
ask s c sq = do
lift $ putStrLn ""
lift $ putStrLn "Toggle Channel (0-3), quit with q"
choice <- lift getLine
case choice of
x | Just y <- ((readMaybe x) :: Maybe Int)
, 0 <= y && y <= 3 ->
do let sq' = Sequence.adjust ((^2) . subtract 1) y sq
Channel.setMixMatrix c (fromIntegral <$> toList sq') 1 4
System.update s
ask s c sq'
"q" -> ExceptT $ return $ Right ()
_ -> do lift $ putStrLn "Invalid choice"
ask s c sq
lift :: (Monad m) => m a -> ExceptT e m a
lift = ExceptT . fmap Right
It's seems weird that a 1x4 matrix works here, I expected that I would have to use a 2x4 matrix.
To rule out it being a haskell/binding problem, I edited the play_stream example that came in the library download. I changed it so it loads my test sound file and then added this after the call to play_sound:
float levels[] = {0.0f, 0.0f, 0.0f, 0.0f};
result = channel->setMixLevelsInput (levels, 4);
ERRCHECK(result);
This had no effect. All 4 channels of the sound played at normal volume.
In case it helps, I am developing on Ubuntu 16.04.