Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
sigrdrifa committed Jan 5, 2024
1 parent 495a9b6 commit 63d95a8
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 26 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ cabal.project.local~
.ghc.environment.*
*_enc.wav
*.tix
docs/
docs

test/output/*.wav
test/output/*.png
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,9 @@ analyse-spectrograms:
sh test/analyse/createSpectrograms.sh
sh test/analyse/analyseSpectrograms.sh

generate-docs:
cabal haddock --html docs
cp -r ./dist-newstyle/build/x86_64-linux/ghc-9.4.7/audiocate-0.2.0.0/doc/html/audiocate/ ./docs

help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.* ?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
3 changes: 3 additions & 0 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ data Opts =
, optCommand :: !Command
}

-- | Main entry point to the CLI executable. Uses optparse-applicative to
-- parse various CLI parameters and create and execute the appropriate
-- Audiocate Command.
main :: IO ()
main = do
(opts :: Opts) <- execParser optsParser
Expand Down
2 changes: 2 additions & 0 deletions gui/AppState.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
-- | Represents GUI application state that is passed around
-- between functions.
module AppState (
AppState (..),
AppStateLoadedAudio (..),
Expand Down
6 changes: 5 additions & 1 deletion gui/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,25 @@ import System.Environment (getArgs, getProgName)
import MainWindow (initMainWindow, MainWindow (window))
import AppState (newAppState)


-- | Activates the Adwaita GTK application by initialising
-- the MainWindow and presenting it.
activate :: Adw.Application -> IO ()
activate app = do
appState <- newAppState
mw <- initMainWindow app appState
let w = window mw
w.present

-- | Helper function for toggling the light and dark theme of the
-- application.
toggleTheme :: Adw.Application -> [String] -> IO ()
toggleTheme _ [] = pure ()
toggleTheme app ["--light"] = do
sm <- Adw.getApplicationStyleManager app
Adw.setStyleManagerColorScheme sm Adw.ColorSchemeForceLight
toggleTheme _ _ = pure ()

-- | Main entry point for the GUI application.
main :: IO ()
main = do
args <- getArgs
Expand Down
24 changes: 19 additions & 5 deletions gui/MainWindow.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
-- | MainWindow module definition, acting as the top level container
-- of the GUI application.
module MainWindow where

import AppState (AppState)
Expand All @@ -22,6 +24,7 @@ import View.LoadView (LoadView(..), initLoadView)
import GI.Gio (MenuItem(..), menuItemSetLabel)
import qualified GI.Gio as Gtk

-- | MainWindow ADT that holds boxed pointers to relevant components
data MainWindow =
MainWindow
{ application :: !Adw.Application
Expand All @@ -33,17 +36,23 @@ data MainWindow =
, loadView :: !LoadView
}

-- | Sets the EncodeViewFileLoaded MVar mutex to signal that a
-- file was successfully loaded.
updateEncodeViewFileLoad :: MVar Bool -> AppState -> EncodeView -> IO ()
updateEncodeViewFileLoad fileLoadedMVar state encodeView = do
_ <- takeMVar fileLoadedMVar
updateEncodeViewAudioFileLoaded state encodeView
putMVar fileLoadedMVar True

-- | Sets the DecodeViewFileLoaded MVar mutex to signal that a
-- file was successfully loaded.
updateDecodeViewFileLoad :: MVar Bool -> AppState -> DecodeView -> IO ()
updateDecodeViewFileLoad fileLoadedMVar state decodeView = do
_ <- takeMVar fileLoadedMVar
updateDecodeViewAudioFileLoaded state decodeView

-- | Initialises the MainWindow by instantiating the sub-views and
-- the Adwaita ApplicationWindow instance.
initMainWindow :: Adw.Application -> AppState -> IO MainWindow
initMainWindow app state = do
content <- new Gtk.Box [#orientation := Gtk.OrientationVertical]
Expand All @@ -57,17 +66,22 @@ initMainWindow app state = do
, #defaultWidth := 1220
, #defaultHeight := 800
]
let welcomeTitle = "Audiocate " <> version
encodeView <- initEncodeView state overlay
let encViewBox = encodeViewBox encodeView
decodeView <- initDecodeView state overlay
let decViewBox = decodeViewBox decodeView

-- run signal handlers for fileload Mutex operations
fileLoadedMVar <- newEmptyMVar
_ <-
forkIO (forever $ updateEncodeViewFileLoad fileLoadedMVar state encodeView)
_ <-
forkIO (forever $ updateDecodeViewFileLoad fileLoadedMVar state decodeView)

-- instantiate sub-views
let welcomeTitle = "Audiocate " <> version
encodeView <- initEncodeView state overlay
let encViewBox = encodeViewBox encodeView
decodeView <- initDecodeView state overlay
let decViewBox = decodeViewBox decodeView
loadView <- initLoadView window state overlay fileLoadedMVar

let lViewBox = loadViewBox loadView
welcomePage <-
new
Expand Down
1 change: 1 addition & 0 deletions gui/View/DecodeView.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
-- | Module that defines the DecodeView
module View.DecodeView
( DecodeView(..)
, initDecodeView
Expand Down
1 change: 1 addition & 0 deletions gui/View/EncodeView.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
-- | Module that defines the EncodeView
module View.EncodeView
( EncodeView(..)
, initEncodeView
Expand Down
1 change: 1 addition & 0 deletions gui/View/LoadView.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
-- | Module that defines the LoadView
module View.LoadView
( LoadView (..),
initLoadView,
Expand Down
3 changes: 3 additions & 0 deletions lib/Command/Cmd.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ instance Show CommandReturnCode where
show (DecodeCmdSuccess _) = "Decode command completed successfully."
show _ = "Command unknown or fault"

-- | Top level interpret function that takes a Command and a realTime and
-- verbose flag and executes the Command. Returns a CommandReturnCode indicating
-- the result of the execution.
interpretCmd :: Command -> Bool -> Bool -> IO CommandReturnCode
interpretCmd cmd isRealTime isVerbose =
case cmd of
Expand Down
20 changes: 13 additions & 7 deletions lib/Command/DecodeCmd.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ import Stego.Decode.Decoder
, stopDecoder
)

-- | Creates a decoder instance using doDecodeWaveAudio to decode the audio read from
-- the input audiofile. Returns an error or the DecoderResultList of the decoding.
runDecodeCmd :: StegoParams -> FilePath -> IO (Either String DecoderResultList)
runDecodeCmd stegoParams inputFile = do
startTime <- getCurrentTime
audio <- runExceptT (waveAudioFromFile inputFile)
case audio of
Left err -> do
Left err -> do
pure (Left err)
Right wa -> do
result <- doDecodeWaveAudio stegoParams wa
Expand All @@ -44,16 +46,18 @@ runDecodeCmd stegoParams inputFile = do
putStrLn $ "Completed decode in " <> show (diffUTCTime endTime startTime)
pure (Right result)

-- | Creates a decoder instance to decode the audio in the provided WaveAudio
-- instance. Returns the resulting DecoderResultList.
doDecodeWaveAudio :: StegoParams -> WaveAudio -> IO DecoderResultList
doDecodeWaveAudio stegoParams waveAudio = do
decoder <- newDecoder stegoParams
resD <- getResultChannel decoder
m <- newEmptyTMVarIO
void $ forkIO $ decodeLoop resD [] m
decodeDoneMutex <- newEmptyTMVarIO
void $ forkIO $ decodeLoop resD [] decodeDoneMutex
let frames = audioFrames waveAudio
mapM_ (enqueueFrame decoder) frames
_ <- stopDecoder decoder
atomically $ takeTMVar m
atomically $ takeTMVar decodeDoneMutex
where
decodeLoop channel fs resultVar = do
res <- atomically $ readTChan channel
Expand All @@ -64,14 +68,16 @@ doDecodeWaveAudio stegoParams waveAudio = do
f -> do
decodeLoop channel (f : fs) resultVar

-- | Similar to doDecodeWaveAudio. Decodes the provided Frames using an
-- injected Decoder instance, and returns the DecoderResultList.
doDecodeFramesWithDecoder :: Decoder -> Frames -> IO DecoderResultList
doDecodeFramesWithDecoder decoder frames = do
resD <- getResultChannel decoder
m <- newEmptyTMVarIO
void $ forkIO $ decodeLoop resD [] m
decodeDoneMutex <- newEmptyTMVarIO
void $ forkIO $ decodeLoop resD [] decodeDoneMutex
mapM_ (enqueueFrame decoder) frames
_ <- stopDecoder decoder
atomically $ takeTMVar m
atomically $ takeTMVar decodeDoneMutex
where
decodeLoop channel fs resultVar = do
res <- atomically $ readTChan channel
Expand Down
9 changes: 8 additions & 1 deletion lib/Command/EncodeCmd.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import Stego.Encode.Encoder
, stopEncoder
)

-- | Creates two concurrent encoder and decoder instances to encode
-- the input audiofile and writes the decoded result audio to the output
-- file location. Returns an error or the DecoderResultList of the decoding.
runEncodeCmd ::
StegoParams
-> FilePath
Expand Down Expand Up @@ -67,6 +70,9 @@ runEncodeCmd stegoParams inputFile outputFile = do
"Completed encode in " <> show (diffUTCTime endTime startTime)
pure (Right combined)

-- | Helper function used to create an encoder and decoder pair to
-- encode the provided Frames, returning the DecoderResultList of the
-- encoding.
doEncodeFrames :: StegoParams -> Frames -> IO DC.DecoderResultList
doEncodeFrames stegoParams frames = do
encoder <- newEncoder stegoParams
Expand Down Expand Up @@ -98,7 +104,8 @@ doEncodeFrames stegoParams frames = do
_ -> do
printLoop c (fs + 1) totalFs

-- | Performs an Encoding on the provided Frames using the provided Encoder instance
-- | Similar to doEncodeFrames.
-- Performs an Encoding on the provided Frames using the provided Encoder instance
doEncodeFramesWithEncoder :: Encoder -> Frames -> IO DC.DecoderResultList
doEncodeFramesWithEncoder encoder frames = do
let stegoPs = stegoParams encoder
Expand Down
2 changes: 2 additions & 0 deletions lib/Command/EncodeStreamCmd.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ runEncodeStreamCmd verbose stegoP inputFile outputFile = do
runConduitRes $
CA.sinkSnd outputFile fmt (CA.AudioSource source rate channels frames)

-- | Helper function for encoding a single Frame or skipping it
-- based on the Stego.Common.shouldSkipFrame function result.
doEncodeFrame :: StegoParams -> UTCTime -> Frame -> Frame
doEncodeFrame stegoP time f =
if shouldSkipFrame f
Expand Down
20 changes: 8 additions & 12 deletions lib/Data/Audio/Wave.hs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{-# LANGUAGE TypeApplications #-}

{- | Contains logic for interacting with 16-bit Wave files including
parsing, reading and writing to files and converting to types.
-}
-- | Contains logic for interacting with 16-bit Wave files including
-- parsing, reading and writing to files and converting to types.
module Data.Audio.Wave
( WaveAudio(..)
, Sample
Expand Down Expand Up @@ -67,9 +66,8 @@ toWaveAudio path (Audio hz chans raw) =
where
chunks = chunksOf hz (elems raw)

{- | Attempts to read the provided Wave file into 16-bit samples
or returns an error string.
-}
-- | Attempts to read the provided Wave file into 16-bit samples
-- or returns an error string.
readWaveFile :: FilePath -> IO (Either String (Audio Int16))
readWaveFile path = do
wav <- Codec.Wav.importFile path
Expand All @@ -79,15 +77,13 @@ readWaveFile path = do
readWaveFile' :: FilePath -> ExceptT String IO (Audio Int16)
readWaveFile' path = ExceptT (readWaveFile path)

{- | Attempts to read the wave file at the provided filepath into
a full WaveAudio instance.
-}
-- | Attempts to read the wave file at the provided filepath into
-- a full WaveAudio instance.
waveAudioFromFile :: FilePath -> ExceptT String IO WaveAudio
waveAudioFromFile path = toWaveAudio path <$> readWaveFile' path

{- | Writes the provided WaveAudio to a valid .wav file at path or raises
an IOException in the ExcepT monad
-}
-- | Writes the provided WaveAudio to a valid .wav file at path or raises
-- an IOException in the ExcepT monad
waveAudioToFile :: FilePath -> WaveAudio -> ExceptT String IO ()
waveAudioToFile path w = do
withExceptT (show @IOException) $
Expand Down

0 comments on commit 63d95a8

Please sign in to comment.