diff --git a/app/Main.hs b/app/Main.hs index 44f8fe9..9a50c8e 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -107,6 +107,7 @@ audioCallback samples cursorRef fmt buffer = case fmt of let bufferLen = V.length buffer nToCopy = min bufferLen cursor when (cursor < bufferLen) $ do + -- TODO That's not correct V.set buffer 0 V.copy (V.slice 0 nToCopy buffer) (V.slice 0 nToCopy samples) -- If more samples are ready diff --git a/src/Nes/APU/State/Filter/Chain.hs b/src/Nes/APU/State/Filter/Chain.hs index 5e9fa46..27c30bd 100644 --- a/src/Nes/APU/State/Filter/Chain.hs +++ b/src/Nes/APU/State/Filter/Chain.hs @@ -48,11 +48,14 @@ filterChainConsumeSample sample fc = do V.modifyM (filters fc) (consume sample) 0 firstFilter <- V.read (filters fc) 0 _ <- - V.ifoldM - ( \prev currIdx curr -> do - newCurr <- filterChainConsumeIteration prev (dt fc) curr - V.write (filters fc) currIdx newCurr - return newCurr + V.ifoldM' + ( \prev currIdx curr -> + if currIdx == 0 + then return curr + else do + !newCurr <- filterChainConsumeIteration prev (dt fc) curr + V.write (filters fc) currIdx newCurr + return newCurr ) firstFilter (filters fc) diff --git a/src/Nes/APU/State/Filter/Iir.hs b/src/Nes/APU/State/Filter/Iir.hs index fda3cb4..062c567 100644 --- a/src/Nes/APU/State/Filter/Iir.hs +++ b/src/Nes/APU/State/Filter/Iir.hs @@ -21,9 +21,11 @@ data IirFilter = MkIirF , previousOutput :: {-# UNPACK #-} !Sample , previousInput :: {-# UNPACK #-} !Sample , delta :: {-# UNPACK #-} !Float - , outputF :: !(IirFilter -> Sample) + , pass :: {-# UNPACK #-} !IirFilterPass } +data IirFilterPass = Identity | LowPass | HighPass deriving (Eq) + identityIirFilter :: IirFilter identityIirFilter = MkIirF @@ -31,7 +33,7 @@ identityIirFilter = , previousInput = 0 , previousOutput = 0 , delta = 0 - , outputF = previousInput + , pass = Identity } highPassIirFilter :: SampleRate -> Cutoff -> IirFilter @@ -41,7 +43,7 @@ highPassIirFilter sampleRate cutoff = , previousOutput = 0 , previousInput = 0 , delta = 0 - , outputF = \f -> alpha f * previousOutput f + alpha f * delta f + , pass = HighPass } where period = 1 / sampleRate @@ -54,7 +56,7 @@ lowPassIirFilter sampleRate cutoff = , previousOutput = 0 , previousInput = 0 , delta = 0 - , outputF = \f -> previousOutput f + alpha f * delta f + , pass = LowPass } where period = 1 / sampleRate @@ -62,7 +64,11 @@ lowPassIirFilter sampleRate cutoff = instance (Monad m) => Filter m IirFilter where {-# INLINE output #-} - output f = return $ outputF f f + output f = return $ case pass f of + Identity -> previousInput f + LowPass -> previousOutput f + alpha f * delta f + HighPass -> alpha f * previousOutput f + alpha f * delta f + {-# INLINE consume #-} consume sample f = do prevOut <- output @m f diff --git a/test/nestest/Spec.hs b/test/nestest/Spec.hs index da4dce9..a355a1e 100644 --- a/test/nestest/Spec.hs +++ b/test/nestest/Spec.hs @@ -45,7 +45,7 @@ spec = it "Trace should match logfile" $ do let st = newCPUState{programCounter = 0xc000} -- TODO why is the tick count set to 7 ? Reset? _ <- try @IOException $ runProgram' st (bus{cycles = 7}) (trace traceRef) - actualTrace <- fmap fixStackValue . beforeUnhandledOpcode . toRawTrace <$> readIORef traceRef + actualTrace <- fmap fixStackValue . beforeAPUAccess . toRawTrace <$> readIORef traceRef -- BS.writeFile "actual.log" $ BSC.unlines actualTrace length actualTrace `shouldBe` length expectedTrace forM_ [0 .. length expectedTrace - 1] $ \i -> do @@ -170,8 +170,8 @@ getCPUStateTrace = withCPUState $ \st -> (unByte $ unSR $ status st) (unByte $ registerS st) -beforeUnhandledOpcode :: [ByteString] -> [ByteString] -beforeUnhandledOpcode = +beforeAPUAccess :: [ByteString] -> [ByteString] +beforeAPUAccess = takeWhile (\line -> not $ "C68B" `BS.isPrefixOf` line) @@ -179,8 +179,7 @@ loadExpectedRawTrace :: IO RawTrace loadExpectedRawTrace = do fileContent <- BS.readFile "test/assets/rom_trace.log" let rawTrace = fixStackValue <$> BSC.lines fileContent - -- TODO When project is finished, we shouldn't have to do the following filters - return $ withoutPPUCycles <$> beforeUnhandledOpcode rawTrace + return $ withoutPPUCycles <$> beforeAPUAccess rawTrace where withoutPPUCycles bs = let beforePPU = fst . BS.breakSubstring " PPU:" $ bs