mmsyn7ukr-array (empty) → 0.1.0.0
raw patch · 11 files changed
+2010/−0 lines, 11 filesdep +basedep +directorydep +mmsyn2-arraysetup-changedbinary-added
Dependencies added: base, directory, mmsyn2-array, mmsyn3, process
Files
- ChangeLog.md +8/−0
- Control/Exception/FinalException/Arr.hs +65/−0
- LICENSE +20/−0
- Processing_mmsyn7ukr_array.hs +446/−0
- README.md +259/−0
- ReplaceP/Arr.hs +37/−0
- Setup.hs +2/−0
- SoXBasics/Arr.hs +715/−0
- SoXBasics1/Arr.hs +431/−0
- mmsyn7ukr-array.cabal +27/−0
- y.wav binary
+ ChangeLog.md view
@@ -0,0 +1,8 @@+# Revision history for mmsyn7ukr++## 0.1.0.0 -- 2022-08-15++* First version. Released on an unsuspecting world. Is rewritten from the mmsyn7ukr-0.17.0.0 package+to reduce the dependencies.++
+ Control/Exception/FinalException/Arr.hs view
@@ -0,0 +1,65 @@+-- |+-- Module : Control.Exception.FinalException.Arr+-- Copyright : (c) OleksandrZhabenko 2020-2022+-- License : MIT+-- Stability : Experimental+-- Maintainer : olexandr543@yahoo.com+--+-- A program and a library that can be used as a simple +-- basic interface to some SoX functionality or for producing +-- the approximately Ukrainian speech with your own recorded +-- voice (actually it produces the needed sound representations).+--++{-# LANGUAGE DeriveDataTypeable #-}++module Control.Exception.FinalException.Arr (+ FinalException(..)+ -- * Exception+ , catchEnd+) where++import Data.Typeable+import Control.Exception (Exception, catch, throw)+import System.Environment (getProgName)+import System.IO+import GHC.IO.Handle.Types (Newline( CRLF ), nativeNewline)++-- | Data type 'FinalException' is used to terminate the not needed further execution.+data FinalException = ExecutableNotProperlyInstalled | MaybePartiallyTrimmed | NotCreatedWithEffect String+ | InitialFileNotChanged String | NotCreated String | NotRecorded String | NoiseProfileNotCreatedB String | NoiseProfileNotCreatedE String+ | NotEnoughData String | NotCreatedWithEffects String | StrangeAnswer String String | NotFileNameGiven | DataFileNotClosed String+ | DataSoundFileNotRead String | UndefinedFunction String+ deriving ( Typeable )++instance Exception FinalException++instance Show FinalException where+ show ExecutableNotProperlyInstalled = "ExecutableNotProperlyInstalled: SoX is not properly installed in your system. Please, install it properly and then call the function again." ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show MaybePartiallyTrimmed = "MaybePartiallyTrimmed: The function did not create the needed file, but may be it trimmed the initial one (not enough)!"+ ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (NotCreatedWithEffect xs) = "NotCreatedWithEffect: File was not created with " ++ show xs ++ " effect!" ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (InitialFileNotChanged xs) = "InitialFileNotChanged: The initial file " ++ show xs ++ " was not changed!" ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (NotCreated xs) = "NotCreated: The function did not create the needed file " ++ show xs ++ "!" ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (NotRecorded xs) = "NotRecorded: The file " ++ show xs ++ " was not recorded!" ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (NoiseProfileNotCreatedB xs) = "NoiseProfileNotCreatedB: The noise profile " ++ xs ++ ".b.prof was not created!"+ ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (NoiseProfileNotCreatedE xs) = "NoiseProfileNotCreatedE: The noise profile " ++ xs ++ ".e.prof was not created!"+ ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (NotEnoughData xs) = "NotEnoughData: SoX cannot determine the number of the samples in the file " ++ show xs +++ "! May be it is a RAW file and it needs additional parameters to be processed." ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (NotCreatedWithEffects xs) = "NotCreatedWithEffects: File was not created with " ++ (init . unwords . map ((++ ",") . show) . words $ xs) ++ " effects!"+ ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (StrangeAnswer xs ys) = xs ++ ": the " ++ show ys ++ " function gave a strange result!" ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show NotFileNameGiven = "Please, specify as a command line argument at least a name of the resulting file (without its extension)! "+ ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (DataFileNotClosed xs) = "File " ++ show xs ++ " is not closed!" ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (DataSoundFileNotRead xs) = "Data sound file " ++ show xs ++ " is not read!" ++ (if nativeNewline == CRLF then "\r\n" else "\n")+ show (UndefinedFunction xs) = xs ++ ": the function is undefined for the arguments. " ++ (if nativeNewline == CRLF then "\r\n" else "\n")++-- | Function to work with exception 'FinalException' similarly to the example in the documentation for the 'catch' function. It throws an exception+-- to the thread where it is called. +catchEnd :: FinalException -> IO ()+catchEnd e = do+ progName <- getProgName+ catch (throw e) (\e0 -> hPutStr stderr (progName ++ ": " ++ show (e0 :: FinalException)))
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2019-2022 Oleksandr Zhabenko++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Processing_mmsyn7ukr_array.hs view
@@ -0,0 +1,446 @@+-- |+-- Module : Processing_mmsyn7ukr+-- Copyright : (c) OleksandrZhabenko 2019-2022+-- License : MIT+-- Stability : Experimental+-- Maintainer : olexandr543@yahoo.com+--+-- A program and a library that can be used as a simple +-- basic interface to some SoX functionality or for producing +-- the approximately Ukrainian speech with your own recorded +-- voice (actually it produces the needed sound representations).+--+++module Processing_mmsyn7ukr_array (+ -- * Producing sound+ produceSound2+ , produceSound3+ , produceSound4+ , beginProcessing+ , controlNoiseReduction+ -- * Additional functions+ , tempS+ , showCoef+ , tempeRa+ -- ** Informational messages printing functions+ , printGenInfo0+ , printGenInfo1+ , printGenInfo2+ , recommendSharp+ -- * Cleaning+ , cleanTemp+ , cleanTempN+) where++import Control.Concurrent (threadDelay)+import Data.Typeable+import Numeric+import System.Directory+import Control.Exception (onException)+import EndOfExe (showE)+import Data.Maybe (fromJust)+import Data.Char+import qualified Data.List as L+import qualified Control.Monad as CM+import System.Process+import System.IO+import System.Info (os)+import System.Environment (getProgName)+import System.Exit+import SoXBasics.Arr+import CaseBi.Arr (getBFst')+import GHC.Arr+import ReplaceP.Arr (replaceP, replaceP4)+import Control.Exception.FinalException.Arr++-- | Function 'produceSound3' is used internally in the 'produceSound2' function.+produceSound3 :: (String, String) -> (FilePath, FilePath) -> String -> (Int, Float) -> Float -> IO ()+produceSound3 (actsctrl, noiseLim) (file, file1) soundUkr (noiseMax, duration0) lim0+ | actsctrl == "-1" = prodSnd3H (actsctrl, noiseLim) (file, file1) soundUkr+ | take 1 actsctrl == "0" = prodSnd3H (actsctrl, noiseLim) (file, file1) soundUkr+ | take 1 actsctrl == "1" = do+ prodSnd3H2 (actsctrl, noiseLim) (file, file1) soundUkr (noiseMax, duration0) lim0 >>= \lim1 -> + if lim1 <= 0.0 then return () else resampleA "8_x.wav" (22050::Int) >> produceSound4 (file, file1) "38_x.wav"+ | take 1 actsctrl == "2" = do+ prodSnd3H2 (actsctrl, noiseLim) (file, file1) soundUkr (noiseMax, duration0) lim0 >>= \lim1 -> + if lim1 <= 0.0 then return () else sincA "8_x.wav" >> resampleA "4.8_x.wav" (22050::Int) >> produceSound4 (file, file1) "34.8_x.wav"+ | otherwise = do+ prodSnd3H2 (actsctrl, noiseLim) (file, file1) soundUkr (noiseMax, duration0) lim0 >>= \lim1 -> + if lim1 <= 0.0 then return () else sincA "8_x.wav" >> resampleA "4.8_x.wav" (22050::Int) >> quarterSinFade "34.8_x.wav" >> + produceSound4 (file, file1) "434.8_x.wav"++prodSnd3H :: (String, String) -> (FilePath, FilePath) -> String -> IO ()+prodSnd3H (actsctrl, noiseLim) (file, file1) soundUkr = do + lim1 <- durationA "8_x.wav"+ if lim1 <= 0.0+ then beginProcessing (file, file1) soundUkr (actsctrl, noiseLim)+ else do + resampleA "8_x.wav" (22050::Int)+ produceSound4 (file, file1) "38_x.wav"++prodSnd3H2 :: (String, String) -> (FilePath, FilePath) -> String -> (Int, Float) -> Float -> IO Float+prodSnd3H2 (actsctrl, noiseLim) (file, file1) soundUkr (noiseMax, duration0) lim0 = do+ alterVadB "8_x.wav" lim0 noiseMax (duration0*0.03)+ lim1 <- durationA "8_x.wav"+ if lim1 <= 0.0+ then beginProcessing (file, file1) soundUkr (actsctrl, noiseLim)+ else alterVadE "8_x.wav" lim1 noiseMax (duration0*0.03)+ return lim1++-- | Function 'produceSound4' is used internally in the 'produceSound3' function for amplification +-- up/down to the maximum level of the first @FilePath@ parameter in the tuple. The second one gives +-- a name of the resulting file and the third @FilePath@ parameter of the function is the @FilePath@ for +-- the input file.+produceSound4 :: (FilePath, FilePath) -> FilePath -> IO ()+produceSound4 (file, file1) fileB = do + norm fileB+ volS2 ("8" ++ fileB) file+ renameFile ("8." ++ fileB) file1++-- | Function 'showCoef' is used to represent the duration of the sound file.+showCoef :: String -> String+showCoef xs | '.' `elem` xs = + let (ts, us) = break (== '.') xs in let ws = showFFloat (Just 6) ((fromIntegral (read (take 6 . drop 1 $ us)::Int) + 1.0) / 1000000.0) "" in + ts ++ drop 1 ws+ | otherwise = xs+ +-- | Function 'beginProcessing' is used to catch the variant where the sound is fully cut by the SoX because the sound was created in inappropriate time.+-- It returns the process to the beginning of the sound recording. For the meaning of the tuple of @Sring@ parameters, refer to +-- 'produceSound' documentation. The first @FilePath@ in the tuple of @FilePath@ parameters is a name of the sound file in @mmsyn6ukr-array@ package. The second one is the +-- name of the resulting file to be produced in the current directory.+beginProcessing :: (FilePath, FilePath) -> String -> (String, String) -> IO ()+beginProcessing (file, file1) soundUkr (actsctrl, noiseLim) = do {+ cleanTemp+; putStr "The needed files were NOT created, because the sound was not at the moment of recording! The process will be restarted "+; putStrLn "for the sound. Please, produce a sound during the first 3 seconds (after 0.5 second delay) or specify greater ratio!"+; putStrLn $ "Listen to the \"" ++ soundUkr ++ "\" sound and note first of all its duration. "+; playA file+; putStrLn " *****"+; putStrLn ""+; putStrLn "The sound duration is: "+; produceSound2 (file, file1) (actsctrl, noiseLim) soundUkr}++-- | Function 'produceSound2' is used internally in the 'produceSound' function.+produceSound2 :: (FilePath, FilePath) -> (String, String) -> String -> IO ()+produceSound2 (file, file1) (actsctrl, noiseLim) soundUkr = do {+; duration0 <- durationA file+; putStrLn $ showCoef (showFFloat (Just 6) duration0 "")+; putStrLn ""+; putStrLn "It means that to produce more than 3 seconds of recording, you must specify at least "+; putStrLn $ " " ++ show (3.0/duration0) ++ " as a next step ratio being prompt "+; putStrLn " OR "+; putStrLn $ " " ++ show (1.0/duration0) ++ " per one second but not less than the previous number."+; putStrLn $ "For example for 10 seconds record, please, specify " ++ show (10.0/duration0) ++ " as a next step ratio."+; putStrLn " *****"+; putStrLn ""+; (_, Just hout, _, _) <- createProcess (proc (fromJust . showE $ "soxi") ["-D", file]) { std_out = CreatePipe }+; x3 <- hGetContents hout+; recommendSharp soundUkr+; (longerK0,pause0,sharp) <- tempS soundUkr noiseLim+; let longerK = (read x3::Float)*longerK0+; putStrLn $ "Please, wait for " ++ show pause0 ++ " seconds and pronounce the sound representation for the "+; putStrLn ""+; putStrLn $ " \"" ++ (if soundUkr /= "ь" then map toUpper soundUkr else soundUkr) ++ "\""+; putStrLn ""+; putStrLn " sound or whatever you would like to be substituted instead (be sensible, please)! "+; if sharp || (compare longerK 3.0 == GT)+ then recB "x.wav" (longerK, pause0)+ else recB "x.wav" (3.0, pause0)+; putStrLn "The file is recorded and now will be automatically processed. You will be notificated with the text message in the terminal about the creation of the needed file. Please, wait a little. "+; controlNoiseReduction actsctrl+; norm "_x.wav"+; lim0 <- durationA "8_x.wav" +; if null noiseLim+ then printGenInfo1+ else if last noiseLim == 's'+ then putStr ""+ else printGenInfo1+; let noiseMax = case (take 1 noiseLim) of+ "0" -> 0::Int+ "1" -> 1::Int+ "2" -> 2::Int+ "3" -> 3::Int+ _ -> 2::Int+; produceSound3 (actsctrl, noiseLim) (file, file1) soundUkr (noiseMax, duration0) lim0+; cleanTemp }++-- | Function 'printGenInfo1' prints the general information about behaviour of the program in case of the different specified first two command line+-- arguments. If in the second command line argument there is letter \'s\' at the end, then the printing is omitted.+printGenInfo1 :: IO ()+printGenInfo1 = do {+putStrLn ""+; putStrLn "If you specified as a first command line argument one of the numbers below the program behaves as follows: "+; putStrLn "-1 -> the program does not reduce noise, it only resamples the audio to the needed 22050 Hz and adjusts the amplitude;"+; putStrLn ""+; putStr "If you specified something else then the program will reduce the noise using the created noise profile. If the first character is one of the "+; putStr "following, then the program will do the following actions besides. After the first character (without any spaces) you can specify "+; putStr "the level of noise reduction by 2 next digits. They are treated by the program as a fractional part of the number \"0.\" ++ \"...\" "+; putStr "so that the last number is passed to the SoX as an amount parameter in the \"noisered\" effect (the greater number gives more aggressive "+; putStrLn "noise reduction with the default one equal to 0.5. For more information, please, refer to the SoX documentation. "+; putStrLn ""+; putStrLn "Therefore, if you specify as a first symbol in the first command line argument one of the following numbers, then the program will behave: "+; putStrLn "0 -> after the noise reduction the program only resamples the audio to the needed 22050 Hz and adjusts the amplitude; "+; putStrLn "1 -> after the noise reduction the program additionally to the 0-processing truncates the silence from the beginning and end of the audio to the level given by the second command line parameter; "+; putStrLn "2 -> after the noise reduction the program additionally to the 1-processing applies a double band-reject filter to the audio (SoX \'sinc\' effect); "+; putStrLn "3 -> after the noise reduction the program additionally to the 2-processing applies fade-in and fade-out effects to the audio; "+; putStrLn "_ -> is the same as 3. "+; putStrLn " ---------------------- "+; putStrLn ""+; putStrLn "If you specify at the beginning of a second command line argument one of the numbers below the program behaves as follows: "+; putStrLn ""+; putStr "0 -> if the first character in the first command line argument is greater or equal to 1, "+; putStr "then the program trims the sound at the beginning and at the end of it. "+; putStr "It firstly normalizes the sound (so its maximum amplitude is equal to 1) "+; putStr "and then applies trimming. The parts of the audio at the beginning "+; putStr "and at the end of the sound, which amplitudes in such a case are "+; putStr "less than 0.01 are trimmed and the resulting sound data are processed "+; putStrLn "further. "+; putStrLn ""+; putStr "1 -> if the first character in the first command line argument is greater or equal to 1, "+; putStr "then the program trims the sound at the beginning and at the end of it. "+; putStr "It firstly normalizes the sound (so its maximum amplitude is equal to 1) "+; putStr "and then applies trimming. The parts of the audio at the beginning "+; putStr "and at the end of the sound, which amplitudes in such a case are "+; putStr "less than 0.02 are trimmed and the resulting sound data are processed "+; putStrLn "further. "+; putStrLn ""+; putStr "2 -> if the first character in the first command line argument is greater or equal to 1, "+; putStr "then the program trims the sound at the beginning and at the end of it. "+; putStr "It firstly normalizes the sound (so its maximum amplitude is equal to 1) "+; putStr "and then applies trimming. The parts of the audio at the beginning "+; putStr "and at the end of the sound, which amplitudes in such a case are "+; putStr "less than 0.04 are trimmed and the resulting sound data are processed "+; putStrLn "further. "+; putStrLn ""+; putStr "3 -> if the first character in the first command line argument is greater or equal to 1, "+; putStr "then the program trims the sound at the beginning and at the end of it. "+; putStr "It firstly normalizes the sound (so its maximum amplitude is equal to 1) "+; putStr "and then applies trimming. The parts of the audio at the beginning "+; putStr "and at the end of the sound, which amplitudes in such a case are "+; putStr "less than 0.08 are trimmed and the resulting sound data are processed "+; putStrLn "further. "+; putStrLn ""+; putStr "_ -> if the first character in the first command line argument is greater or equal to 1, "+; putStr "then the program trims the sound at the beginning and at the end of it. "+; putStr "It firstly normalizes the sound (so its maximum amplitude is equal to 1) "+; putStr "and then applies trimming. The parts of the audio at the beginning "+; putStr "and at the end of the sound, which amplitudes in such a case are "+; putStr "less than 0.04 are trimmed and the resulting sound data are processed "+; putStrLn "further. So effectively it is the same as 2 (the default value). "+; putStrLn ""+; putStrLn " ---------------------- "+; putStr "You can shorten the information printed during the program execution by specifying as the "+; putStr "last symbol in the second command line argument an \'s\'. In such a case, the program omits "+; putStr "printing the much of its informational messages that are used mostly for the learning "+; putStr "to deal with the program. If you specified the second command line argument without the \'s\' "+; putStrLn "at the end, then the program prints all the additional information that is considered important."+; putStrLn "" }++-- | Function 'controlNoiseReduction' is used in the 'produceSound2' and 'beginProcessing' functions to reduce the noise with the created by the+-- 'tempeRa' noise profile. If you specified something else than \"-1\" as a first command line argument, then the program will reduce the noise+-- using the created noise profile. +-- If the first character is one of the following, then the program will do the following actions besides. After the first character+-- (without any spaces) you can specify the level of noise reduction by 2 next digits. They are treated by the program as a fractional part+-- of the number \"0.\" ++ \"...\" so that the last number is passed to the SoX as an amount parameter in the \"noisered\" effect+-- (the greater number gives more aggressive noise reduction with the default one equal to 0.5. For more information, please, refer to the SoX documentation. +controlNoiseReduction :: String -> IO ()+controlNoiseReduction actsctrl = if actsctrl /= "-1"+ then do+ s2 <- onException (do+ let s1 = take 1 actsctrl+ sr0 = filter isDigit . drop 1 $ actsctrl+ if null sr0+ then return 0.5+ else let sr = "0." ++ sr0+ s = read sr::Float in if s > 0.0 then return s else return 0.01) (return 0.5)+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) ["x.wav", "_x.wav", "noisered", "nx0.wav.b.prof", showFFloat (Just 4) s2 $ show 0] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist "_x.wav"+ if e1+ then do+ removeFile "_x.wav"+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist "_x.wav"+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged "x.wav")+ else renameFile "x.wav" "_x.wav"++-- | Function to get the @(Float, Float, Bool)@ value. The first @Float@ value shows in how many times you expect that your sound representation+-- will be longer than the one provided by the @mmsyn6ukr-array@ package. The second one specifies a duration of the pause before SoX actually starts to+-- record the needed sound data (in seconds). The @Bool@ value specifies whether the program uses a \'sharp\' mode meaning that+-- it does not check whether the resulting duration of the recording is at least 3 seconds long, so you can specify shorter durations.+-- The @String@ arguments are the Ukrainian sound representation name and the second command line argument for the program respectively.+tempS :: String -> String -> IO (Float, Float, Bool)+tempS soundUkr noiseLim = onException (do+ if null noiseLim+ then printGenInfo2+ else if last noiseLim == 's'+ then putStr ""+ else printGenInfo2+ putStrLn "In how many times do you think your sound representing " + putStrLn ""+ putStrLn $ " \"" ++ (if soundUkr /= "ь" then map toUpper soundUkr else soundUkr) ++ "\"" + putStrLn ""+ putStrLn "will sound longer than the recently played one? Specify your input as a Float value without \'e\' notation (with the preceding asterisk sign for the \'sharp\' mode). "+ putStrLn ""+ longivityZ <- getLine+ let sharp0 = take 1 longivityZ+ sharp1 = drop 1 . dropWhile (/= '#') $ longivityZ+ sharp2 = if null sharp1 then 0.5 else let zzz0 = read (filter (\z -> isDigit z || z == '.') sharp1)::Float in if zzz0 /= 0.0 then zzz0 else 0.5+ case sharp0 of+ "*" -> let long = read (takeWhile (/= '#') . drop 1 $ longivityZ)::Float in return (long,sharp2,True)+ _ -> let long = read (takeWhile (/= '#') longivityZ)::Float in return (long,sharp2,False)) (do + putStrLn "Please, specify again the valid values!"+ tempS soundUkr noiseLim)++-- | Function 'printGenInfo2' prints the additional information about the \'sharp\' mode and the possibility to specify the duration of the+-- pause before the SoX executable actuall starts recording of the sound representation.+-- If in the second command line argument there is letter \'s\' at the end, then the printing is omitted.+printGenInfo2 :: IO ()+printGenInfo2 = do+ putStrLn ""+ putStr "IMPORTANT. Would you like to use a \'sharp\' mode for this sound representaiion? (Enter \'*\' as the first symbol in your next input to use the "+ putStr "\'sharp\' mode, in which the program does not use 3 seconds minimal limit to record the sound representation, "+ putStr "but a recording duration is no more than the one specified by your entered ratio). For not using the \'sharp\' mode, "+ putStrLn "enter your next input without the asterisk."+ putStrLn ""+ putStrLn "IMPORTANT 2. After specifying the ratio you can input \'#\' sign and specify after it the duration (in seconds) of the needed pause before SoX will actually start recording of the sound data. The default one is 0.5 seconds if nothing is specified. This also provides backward compatibility of the program."+ putStrLn ""++-- | Function 'cleanTemp' removes all the intermediate temporary files in the directory where it is called from.+cleanTemp :: IO ()+cleanTemp = do+ filenames <- getDirectoryContents =<< getCurrentDirectory+ mapM_ removeFile . filter (\x -> head x `elem` (['2'..'9'] ++ "_" ++ "x")) $ filenames++-- | Function 'cleanTempN' removes all the intermediate temporary files produced during a noise profile creation in the directory where it is called from.+cleanTempN :: IO ()+cleanTempN = do+ filenames <- getDirectoryContents =<< getCurrentDirectory+ mapM_ removeFile . filter (\x -> head x == 'n') $ filenames++-- | Function 'tempeRa' is used to create a noise profile for all the recorded sounds. The function is used internally in the @mmsyn7ukr@+-- program. While running if you provide a 5 seconds silence as needed, the program @mmsyn7ukr@ will+-- reduce the noise in your recordings. This will create a cleaner sound. If you would like not to reduce the noise at all, then, please,+-- specify \"-1\" as the first command line argument for the program @mmsyn7ukr@.+tempeRa :: Int -> IO ()+tempeRa n = do {+ putStrLn "Now, please, be in a silence for 5 seconds so that the program can create a noise profile to remove the noise from the recording. "+ ; putStr "Otherwise, the program can remove from the recorded sound data some important parts as a noise. "+ ; if n == 1 then putStrLn "If you would like not to reduce the noise at all, then, please, specify as the first command line argument \"-1\". "+ else putStr ""+ ; CM.zipWithM_ (\i x -> recA ("nx" ++ show i ++ ".wav") 0.07 >> threadDelay (50000 * x)) [1..5] $ [2,3,2,2,3]+ ; [upperB1,upperB2,upperB3,upperB4,upperB5] <- mapM (\c -> upperBnd ("nx" ++ (c:".wav"))) "12345"+ ; v0 <- CM.zipWithM (\i upp -> fmap (\kt -> abs (read (fst kt)::Float)) . selMaxAbs ("nx" ++ show i ++ ".wav") $ (0,upp)) [1..5] $ [upperB1,upperB2,upperB3,upperB4,upperB5]+ ; let minn = minimum v0 in renameFile ("nx" ++ (show ((fromJust . L.findIndex (<= minn) $ v0) + 1) ++ ".wav")) "nx0.wav"+ ; noiseProfB "nx0.wav" >> putStrLn "" >> threadDelay 400000 >> putStrLn "The noise sound profile is now created. The program can proceed further." }++-- | Function 'recommendSharp' is used to print an advice about the speech transformation for the Ukrainian sounds that you can pronounce+-- properly continually and so it can be better to use for their producing a \'sharp\' mode.+recommendSharp :: String -> IO ()+recommendSharp soundUkr = do+ let k0 = getBFst' (False, listArray (0,16) . zip ["\1072","\1077","\1078","\1079","\1080","\1083","\1084","\1085","\1086","\1088","\1089","\1089\1100","\1091","\1092","\1093","\1096","\1110"] $ replicate 17 True) soundUkr+ if k0+ then do+ putStr $ "In case of speech transformation: for the sound representation for the Ukrainian \"" ++ soundUkr+ putStrLn "\" it is recommended to use a \'sharp\' mode. So, try to specify \'*\' as a first symbol and maybe pronounce the corresponding Ukrainian sound continually. "+ else do+ putStr $ "In case of speech transformation: for the sound representation for the Ukrainian \"" ++ soundUkr+ putStrLn "\" it is recommended to use a common mode (the usual one). So, try not to specify \'*\' as a first symbol. "++-- | Function 'printGenInfo0' prints once the general information if in the second command line argument there is no letter \'s\' at the end.+printGenInfo0 :: IO ()+printGenInfo0 = do+ putStr "The program mmsyn7ukr produces the \"voice\" represented as an ordered "+ putStr "set of sounds each of which corresponds (represents) one of the "+ putStr "Ukrainian sounds so that using them together by mmsyn7h program "+ putStr "(https://hackage.haskell.org/package/mmsyn7h) can be a background "+ putStr "for sound synthesis. If you pronounce sounds as the appropriate "+ putStr "Ukrainian ones, close to proper Ukrainian speech with your own "+ putStr "voice. This program approximates your voice with a sequence "+ putStr "of recorded separate sounds with your control over the "+ putStr "duration of the sounds. They are then precessed by the SoX "+ putStr "binaries already installed in the system to produce the "+ putStr "needed sounds and then you can pronounce some Ukrainian text "+ putStr "with your recorded \"voice\" using mmsyn7h program. In-between "+ putStr "you can do some additional processing as you need. Moreover, "+ putStr "you can substitute whatever sounds you like (consider being "+ putStrLn "sensible) instead of your own voice."+ putStrLn ""+ putStr "Be aware that if somebody can get access to the sounds of "+ putStr "your voice or to the recorded speech (except you) then this "+ putStr "possibility itself creates security issues and concerns. So, "+ putStr "please, do NOT give access to such records to anybody else "+ putStrLn "except you."+ putStrLn ""+ putStr "In such a case, the program is for personal usage of every "+ putStrLn "user ONLY!"+ putStrLn ""+ putStr "Being given as an advice in such a case, run the program "+ putStr "in the empty directory with the current user permissions to write, "+ putStr "read and search and provide some proofs and evidence that nobody else "+ putStr "can even read the files in the directory. May be, it is better "+ putStr "to execute the program being in the directory located in the RAM, "+ putStr "then consequently wait until the program ends and then reboot "+ putStrLn "the computer. "+ putStrLn ""+ putStr "If the program ends earlier, you must then remove "+ putStr "(better wipe) the directory contents. No other users should "+ putStr "have access to the computer after you have begun to run the "+ putStr "program and have not deleted (or better wiped) the contents "+ putStr "of the directory. Please, be aware, that there are possibilities "+ putStr "to read sensitive information from the drives after you have "+ putStr "deleted the files in a usual way. You can use wiping for better "+ putStr "security. Besides, if somebody can get access to the memory of "+ putStr "the computer or to the directory contents where you run the "+ putStr "program or (may be) to the temporary files created by SoX or "+ putStr "to the drive where you run the program (not in the RAM, or may "+ putStr "be in it) then your voice can be stolen and / or used "+ putStr "inappropriately. Use all possible precautions and measures to "+ putStrLn "avoid the situation. "+ putStrLn ""+ putStr "Be aware also that the given by the program technology (or "+ putStr "documentation for it in any form) of the voice processing can "+ putStr "be improved so there is NO guarantees that the given technology "+ putStr "or its successors cannot be used in violating your voice identity "+ putStr "to produce from some available voice records the voice for the "+ putStr "inappropriate usage. Therefore, better is to proove your identity not "+ putStr "only with the solely voice itself but with some additional "+ putStrLn "independent sources and measures. "+ putStrLn ""+ putStr "The author of the program accordingly to the LICENSE (MIT) does not "+ putStr "response for any possible issues, but by this notification tries to "+ putStrLn "intent you to be aware of some possible issues."+ putStrLn ""+ putStrLn " ***** More Information *****"+ putStrLn ""+ putStr "You can create a sound in either a \'sharp\' mode or in a usual mode."+ putStr "The first one means that the program does not check whether the"+ putStr "specified duration for recording the initial sound data"+ putStr "is greater than 3 seconds. In such a case the duration can be"+ putStr "much smaller. This mode needs more mastership in interacting with a"+ putStr "program. For speech synthesis (as an advice) use this mode for"+ putStr "the very short sounds (like the sound representation for \"ь\")"+ putStr "or for the sounds, you can articulate for a long time continually"+ putStr "(for example, vowels and some consonants). The \'sharp\' mode delegates"+ putStr "the responsibility for the sound to much broader extent to the user,"+ putStrLn "so for a beginning it is not recommended (though you can give it a try)."+ putStrLn ""+ putStr "At the beginning the program also creates a noise profile (once per execution)."+ putStr "It is now used to reduce the noise level for the recorded sound representations."+ putStr "It uses the default SoX noise reducing settings with a hope that for you they can"+ putStrLn "be sufficient."+ putStrLn ""+ putStrLn " ***** Ukrainian Localization *****"+ putStrLn ""+ putStr "Please, before using the program check that uk_UA.UTF8 localization is"+ putStr "present in your system as one of the system locales. Otherwise,"+ putStr "the program will possibly (in some cases surely) cycle. In such a case,"+ putStrLn "you can terminate it in a usual way by sending interruption signals."+ putStrLn ""+
+ README.md view
@@ -0,0 +1,259 @@+A program and a library that can be used as a simple +basic interface to some [SoX](https://sourceforge.net/projects/sox/)+functionality or for producing +the approximately Ukrainian speech with your own recorded +voice (actually it produces the needed sound representations).++The program starts with CAUTION to be responsible for usage +and to use it personally. Then the program guides you +through the creating and using your Ukrainian "voice". +Please, use it carefully. After the execution you can+execute mmsyn7h program to produce some records with your +newly created "voice". During the execution of the last one+you can choose whether to remove (clean) +all the created sound files in the current directory for +security reasons. If the programs terminate by interruption (or +generally) it is a good practice to remove the current +directory sound files manually.++ ***** CAUTION! *****+ ====================++"The possession of great power necessarily implies+great responsibility."++ (William Lamb)++The program mmsyn7ukr produces the "voice" represented as an ordered +set of sounds each of which corresponds (represents) one of the +Ukrainian sounds so that using them together by+[mmsyn7h program](https://hackage.haskell.org/package/mmsyn7h)+can be a background for sound synthesis.+If you pronounce sounds as the appropriate +Ukrainian ones, close to proper Ukrainian speech with your own +voice. This program approximates your voice with a sequence +of recorded separate sounds with your control over the +duration of the sounds. They are then precessed by the SoX +binaries already installed in the system to produce the +needed sounds and then you can pronounce some Ukrainian text +with your recorded "voice" using mmsyn7h program. In-between +you can do some additional processing as you need. Moreover, +you can substitute whatever sounds you like (consider being +sensible) instead of your own voice.++Be aware that if somebody can get access to the sounds of +your voice or to the recorded speech (except you) then this +possibility itself creates security issues and concerns. So, +please, do NOT give access to such records to anybody else +except you.++In such a case, the program is for personal usage of every +user ONLY!++Being given as an advice in such a case, run the program +in the empty directory with the current user permissions to write, +read and search and provide some proofs and evidence that nobody else +can even read the files in the directory. May be, it is better +to execute the program being in the directory located in the RAM, +then consequently wait until the program ends and then reboot +the computer. ++If the program ends earlier, you must then remove +(better wipe) the directory contents. No other users should +have access to the computer after you have begun to run the +program and have not deleted (or better wiped) the contents +of the directory. Please, be aware, that there are possibilities +to read sensitive information from the drives after you have +deleted the files in a usual way. You can use wiping for better +security. Besides, if somebody can get access to the memory of +the computer or to the directory contents where you run the +program or (may be) to the temporary files created by SoX or +to the drive where you run the program (not in the RAM, or may +be in it) then your voice can be stolen and / or used +inappropriately. Use all possible precautions and measures to +avoid the situation. ++Be aware also that the given by the program technology (or +documentation for it in any form) of the voice processing can +be improved so there is NO guarantees that the given technology +or its successors cannot be used in violating your voice identity +to produce from some available voice records the voice for the +inappropriate usage. Therefore, better is to prove your identity not +only with the solely voice itself but with some additional +independent sources and measures. ++The author of the program accordingly to the LICENSE (MIT) does not +response for any possible issues, but by this notification tries to +intent you to be aware of some possible issues.++ ***** Command Line Arguments *****+ ==================================++If you specify as a first command line argument one of the numbers below+the program behaves as follows:++ -1 -> the program does not reduce noise, it only resamples+ the audio to the needed 22050 Hz and adjusts the amplitude.++If you specified something else then the program will reduce the noise+using the created noise profile. If the first character is one of the +following, then the program will do the following actions besides.+After the first character (without any spaces) you can specify +the level of noise reduction by 2 next digits. They are treated+by the program as a fractional part of the number "0." ++ "..." +so that the last number is passed to the sox as an amount parameter+in the "noisered" effect (the greater number gives more aggressive +noise reduction with the default one equal to 0.5).+For more information, please, refer to the SoX documentation. ++Therefore, if you specify as a first symbol in the first+command line argument one of the next numbers, then+the program will behave as follows:++ 0 -> after the noise reduction the program only resamples + the audio to the needed 22050 Hz and adjusts the amplitude;+ + 1 -> after the noise reduction the program additionally + to the 0-processing truncates the silence from the beginning + and the end of the audio to the level given by the second + command line parameter;+ + 2 -> after the noise reduction the program additionally to + the 1-processing applies a double band-reject filter to + the audio (SoX "sinc" effect);+ + 3 -> after the noise reduction the program additionally to + the 2-processing applies fade-in and fade-out effects to + the audio;+ + _ -> is the same as 3. ++If you specify at the beginning of a second command line argument one of the numbers below+the program behaves as follows:++ 0 -> if the first character in the first command line argument is greater or equal to 1,+ then the program trims the sound at the beginning and at the end of it.+ It firstly normalizes the sound (so its maximum amplitude is equal to 1)+ and then applies trimming. The parts of the audio at the beginning+ and at the end of the sound, which amplitudes in such a case are+ less than 0.01 are trimmed and the resulting sound data are processed+ further. + + 1 -> if the first character in the first command line argument is greater or equal to 1,+ then the program trims the sound at the beginning and at the end of it.+ It firstly normalizes the sound (so its maximum amplitude is equal to 1)+ and then applies trimming. The parts of the audio at the beginning+ and at the end of the sound, which amplitudes in such a case are+ less than 0.02 are trimmed and the resulting sound data are processed+ further. + + 2 -> if the first character in the first command line argument is greater or equal to 1,+ then the program trims the sound at the beginning and at the end of it.+ It firstly normalizes the sound (so its maximum amplitude is equal to 1)+ and then applies trimming. The parts of the audio at the beginning+ and at the end of the sound, which amplitudes in such a case are+ less than 0.04 are trimmed and the resulting sound data are processed+ further. + + 3 -> if the first character in the first command line argument is greater or equal to 1,+ then the program trims the sound at the beginning and at the end of it.+ It firstly normalizes the sound (so its maximum amplitude is equal to 1)+ and then applies trimming. The parts of the audio at the beginning+ and at the end of the sound, which amplitudes in such a case are+ less than 0.08 are trimmed and the resulting sound data are processed+ further. + + _ -> if the first character in the first command line argument is greater or equal to 1,+ then the program trims the sound at the beginning and at the end of it.+ It firstly normalizes the sound (so its maximum amplitude is equal to 1)+ and then applies trimming. The parts of the audio at the beginning+ and at the end of the sound, which amplitudes in such a case are+ less than 0.04 are trimmed and the resulting sound data are processed+ further. So effectively it is the same as 2 (the default value).++After the number as its ending you can specify the letter 's' to shorten the printed+informational messages by the program. More information is further below.+ +If you specify the third command line argument, it must be a list +of Strings that can be obtained by executing the+[mmsyn7s program](https://hackage.haskell.org/package/mmsyn7s).+The program will create just that non-silent representations for+the Ukrainian sounds, which are given. The list must be sorted.++ ***** More Information *****+ ============================++You can create a sound in either a 'sharp' mode or in a usual mode.+The first one means that the program does not check whether the+specified duration for recording the initial sound data+is greater than 3 seconds. In such a case the duration can be+much smaller. This mode needs more mastership in interacting with a+program. For speech synthesis (as an advice) use this mode for+the very short sounds (like the sound representation for "ь")+or for the sounds, you can articulate for a long time continually+(for example, vowels and some consonants). The 'sharp' mode delegates+the responsibility for the sound to much broader extent to the user,+so for a beginning it is not recommended (though you can give it a try).++ ***** Noise Reduction *****+ ===========================++At the beginning the program also creates a noise profile (once per execution).+It is now used to reduce the noise level for the recorded sound representations.+By default, the program uses the default SoX noise reducing settings with+a hope that for you they can be sufficient. You can change the level of reduction+by the first command line argument as it is written above. If you see that+the program removes some sensitive and important sound data from the recorded+by it sound representations, then you can specify as a first command line+argument "-1". The program in such a case will create a noise profile as usual,+but will not reduce the noise at all.++ ***** Ukrainian Localization *****+ ==================================++Please, before using the program check that uk_UA.UTF8 localization is+present in your system as one of the system locales. Otherwise,+the program will possibly (in some cases surely) cycle. In such a case,+you can terminate it in a usual way by sending interruption signals.++ ***** SoXBasics and SoXBasics1 *****+ ====================================++The library have two similar modules with partially overlapping function names+(so it is recommended to import them qualified). SoXBasics1 functions after+creation of the resulting file try to replace by it the initial one and to clean+the space from the temporary files. This can be helpful in writing sequentially+applied functions but needs somewhat more resources.++ ***** Test Sound Duration *****+ ===============================+ +You can now test the sound duration needed as a 0.5 second pause before+the program can record every non-silent sound. This pause is caused not by the program+itself, but by some sound recording equipment specific time needed to normalize+the behaviour of the recording (it depends on your equipment, but for a wide range of+possible its configuration the pause for 0.5 second is valid).+To test a needed 0.5 second duration of the pause, you can use as a first+command line argument "-t" and the program will only play the test sound with+just that duration. Remember its duration -- it is the duration of the needed+pause before you can start your recording of the every sound representation.++ ***** Specifying the Pause before SoX Actually Starts Recording *****+ =====================================================================+ +You can specify the pause before SoX actually starts recording of the sound data+for every sound representation. For this, please, specify after the needed+ratio a '#' sign and after it the needed duration of the pause in seconds as a+Double value. The program will try to use it. If not specified or not properly+specified, the program uses a default one (compatible with the previous versions)+equal to 0.5 second pause.++ ***** The Possibility to Shorten the Printed Information *****+ ==============================================================++You can shorten the information printed during the program execution by specifying+as the last symbol in the second command line argument an 's'. In such a case,+the program omits printing the much of its informational messages that are used+mostly for the learning to deal with the program. If you specified the second command+line argument without the 's' at the end, then the program prints all the+additional information that is considered important.
+ ReplaceP/Arr.hs view
@@ -0,0 +1,37 @@+-- |+-- Module : ReplaceP.Arr+-- Copyright : (c) OleksandrZhabenko 2020-2022+-- License : MIT+-- Stability : Experimental+-- Maintainer : olexandr543@yahoo.com+--+-- A program and a library that can be used as a simple +-- basic interface to some SoX functionality or for producing +-- the approximately Ukrainian speech with your own recorded +-- voice (actually it produces the needed sound representations).+--++module ReplaceP.Arr where++-- | Function is used internally to parse a given third command line argument as a @[String]@ representing the Ukrainian sounds, which will be produced.+replaceP :: String -> String+replaceP (x:y:z:u:v:xs) | x == '[' && y == '\"' && z == '[' && u == '\\' && v == '\\' = "[\"\\" ++ replaceP xs+ | x == ',' && y == '\\' && z == '\\' = "\",\"\\" ++ replaceP (u:v:xs)+ | x == ']' && y == '\"' && z == ']' = "\"]" ++ replaceP (u:v:xs)+ | otherwise = x:replaceP (y:z:u:v:xs)+replaceP (x:y:z:u:xs) | x == ',' && y == '\\' && z == '\\' = "\",\"\\" ++ replaceP (u:xs)+ | x == ']' && y == '\"' && z == ']' = "\"]" ++ replaceP (u:xs)+ | otherwise = x:replaceP (y:z:u:xs)+replaceP (x:y:z:xs) | x == ',' && y == '\\' && z == '\\' = "\",\"\\" ++ replaceP xs+ | x == ']' && y == '\"' && z == ']' = "\"]" ++ replaceP xs+ | otherwise = x:replaceP (y:z:xs)+replaceP xs = xs++-- | Function is used internally to parse further the result dealt with 'replaceP' function.+replaceP4 :: String -> String+replaceP4 (t:x:y:z:u:v:xs) | [t,x,y,z,u,v] == "\\\\1078" = '\1078':replaceP4 xs+ | [t,x,y,z,u,v] == "\\\\1079" = '\1079':replaceP4 xs+ | [t,x,y,z,u,v] == "\\\\1100" = '\1100':replaceP4 xs+ | otherwise = t:replaceP4 (x:y:z:u:v:xs)+replaceP4 (x:xs) = x:replaceP4 xs+replaceP4 [] = []
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ SoXBasics/Arr.hs view
@@ -0,0 +1,715 @@+-- |+-- Module : SoXBasics.Arr+-- Copyright : (c) OleksandrZhabenko 2019-2022+-- License : MIT+-- Stability : Experimental+-- Maintainer : olexandr543@yahoo.com+--+-- A program and a library that can be used as a simple +-- basic interface to some SoX functionality or for producing +-- the approximately Ukrainian speech with your own recorded +-- voice (actually it produces the needed sound representations).+--+++module SoXBasics.Arr (+ -- * Get Information+ maxAbs+ , getMaxA+ , getMinA+ , selMaxAbs+ , selMA+ , extremeS+ , extremeS1+ , soxStat+ , upperBnd+ , durationA+ , sampleAn+ -- * Produce sound+ -- ** Trimming the silence+ , alterVadB+ , alterVadE+ , alterVadHelp+ , opFile+ -- ** Amplitude modification+ , norm+ , normL+ , gainL+ , quarterSinFade+ -- ** Adding silence+ , silenceBoth+ -- ** Recording+ , recA+ , recB+ -- ** Changing sample rate+ , resampleA+ -- ** Working with noise+ , noiseProfB+ , noiseProfE+ , noiseReduceB+ , noiseReduceE+ , noiseReduceBU+ , noiseReduceEU+ -- ** Filtering+ , sincA+ -- ** Volume amplification+ , volS+ , volS2+ -- * Playing sound+ , playA+) where++import System.Directory+import Data.Maybe (isJust, fromJust)+import Numeric+import Data.Char+import System.Process+import System.IO+import EndOfExe+import System.Exit+import Control.Concurrent (threadDelay)+import Control.Exception (onException)+import System.Info (os)+import Control.Exception.FinalException.Arr++-- | Function 'maxAbs' allows to choose a maximum by absolute value if the values are written as @String@. Bool @True@ corresponds to maximum value, @False@ - to minimum value+maxAbs :: (String, String) -> (String, Bool)+maxAbs (xs, ys) | null xs || null ys = ([], False)+ | head xs == '-' && head ys == '-' = if compare xs ys /= LT then (xs, False) else (ys, False)+ | head xs /= '-' && head ys /= '-' = if compare xs ys == GT then (xs, True) else (ys, True)+ | head xs == '-' && head ys /= '-' = if compare (tail xs) ys /= LT then (xs, False) else (ys, True)+ | otherwise = if compare xs (tail ys) == GT then (xs, True) else (ys, False)++-- | Function 'getMaxA' returns a maximum amplitude of the sound in the file in the given lower and upper bounds represented as a tuple of @Int@ values.+getMaxA :: FilePath -> (Int, Int) -> IO String+getMaxA file (lowerbound, upperbound) = if isJust (showE "sox") + then do+ (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", show lowerbound ++ "s", "=" ++ show upperbound ++ "s", "stat"] ""+ let zs = lines herr in return (let u = (words $ zs !! 3) !! 2 in if head u == '-' then take 9 u else take 8 u)+ else do+ catchEnd ExecutableNotProperlyInstalled+ return []++-- | Function 'getMinA' returns a minimum amplitude of the sound in the file in the given lower and upper bounds represented as a tuple of @Int@ values. +getMinA :: FilePath -> (Int, Int) -> IO String+getMinA file (lowerbound, upperbound) = if isJust (showE "sox") + then do+ (_, _, herr1) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", show lowerbound ++ "s", "=" ++ show upperbound ++ "s", "stat"] ""+ let zs = lines herr1 in return (let u = (words $ zs !! 4) !! 2 in if head u == '-' then take 9 u else take 8 u)+ else do+ catchEnd ExecutableNotProperlyInstalled+ return []++-- | Function 'selMaxAbs' returns a maximum by absolute value amplitude of the sound and allows by its second value in the tuple determine whether it is a maximum or minimum. +-- Bool @True@ corresponds to maximum value, @False@ - to minimum value.+selMaxAbs :: FilePath -> (Int, Int) -> IO (String, Bool)+selMaxAbs file (lowerbnd, upperbnd) = do + tX <- getMaxA file (lowerbnd, upperbnd)+ tN <- getMinA file (lowerbnd, upperbnd)+ return (maxAbs (tX, tN))++-- | Function 'selMA' returns a maximum or a minimum of the sound amplitude of the file depending on the @Bool@ value given. +-- Bool @True@ corresponds to maximum value, @False@ - to minimum value.+selMA :: FilePath -> (Int, Int) -> Bool -> IO String+selMA file (lowerbnd, upperbnd) x = if x then getMaxA file (lowerbnd, upperbnd) else getMinA file (lowerbnd, upperbnd)++-- | Function 'extremeS' returns an approximate sample number of the extremum, which will be used further for fade effect.+extremeS :: FilePath -> (Int, Int) -> Int -> IO (String, Bool) -> IO Int+extremeS file (lowerbnd, upperbnd) eps x = if compare (upperbnd - lowerbnd) (eps + 33) == LT + then return $ (upperbnd + lowerbnd) `quot` 2+ else do + (ys, z) <- x+ let t = (lowerbnd + upperbnd) `quot` 2 + rs <- selMA file (lowerbnd, t) z+ if (ys == rs) + then extremeS file (lowerbnd, t) eps x+ else extremeS file (t, upperbnd) eps x++-- | Function 'alterVadB' removes an approximate silence measured by the absolute value of the sound amplitude from the beginning of the file. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). The file must have maximum amplitude absolute value close to 1 before call to the 'alterVadB'. +-- The second @Float@ parameter is used to exit the iteration cycle. The @Int@ parameter from the range [0..3] specifies a maximum amplitude, starting from +-- which the sound will not be trimmed.+alterVadB :: FilePath -> Float -> Int -> Float -> IO ()+alterVadB file lim noiseMax exit | compare lim exit /= GT = putStrLn $ "File " ++ file ++ " is ready for further processing."+ | otherwise = + if isJust (showE "sox")+ then do+ lim1 <- durationA file+ alterVadHelp file lim1 lim noiseMax exit + else catchEnd ExecutableNotProperlyInstalled+ +-- | Function 'alterVadHelp' is used internally in the 'alterVadB' and 'alterVadE' functions. +alterVadHelp :: FilePath -> Float -> Float -> Int -> Float -> IO ()+alterVadHelp file lim1 lim noiseMax exit | compare lim1 lim == LT = alterVadB file lim1 noiseMax exit+ | compare lim1 lim == EQ = + let noiseM = (case noiseMax of + 0 -> "0.01"+ 1 -> "0.02"+ 2 -> "0.04"+ 3 -> "0.08"+ _ -> "0.04") in do + (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", "0", showFFloat Nothing (lim1 / 2.0) $ show 0, "stat"] ""+ let zs = lines herr in let z = concatMap (dropWhile (not . isDigit)) . take 1 . drop 3 $ zs in if z < noiseM+ then do + (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "7" ++ file, "trim", showFFloat Nothing (lim1 / 2.0) $ show 0, "-0.000000"] ""+ if code == ExitSuccess+ then do+ threadDelay 100000+ opFile file exit noiseMax+ else do+ e0 <- doesFileExist $ "7" ++ file+ if e0+ then do+ removeFile $ "7" ++ file+ catchEnd MaybePartiallyTrimmed+ else catchEnd MaybePartiallyTrimmed+ else alterVadB file (lim1 / 4.0) noiseMax exit + | otherwise = + let noiseM = (case noiseMax of + 0 -> "0.01"+ 1 -> "0.02"+ 2 -> "0.04"+ 3 -> "0.08"+ _ -> "0.04") in do + (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", "0", showFFloat Nothing (lim / 2.0) $ show 0, "stat"] ""+ let zs = lines herr in let z = concatMap (dropWhile (not . isDigit)) . take 1 . drop 3 $ zs in if z < noiseM+ then do + (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "7" ++ file, "trim", showFFloat Nothing (lim / 2.0) $ show 0, "-0.000000"] ""+ if code == ExitSuccess+ then do+ threadDelay 100000+ opFile file exit noiseMax+ else do+ e0 <- doesFileExist $ "7" ++ file+ if e0+ then do+ removeFile $ "7" ++ file+ catchEnd MaybePartiallyTrimmed+ else catchEnd MaybePartiallyTrimmed+ else alterVadB file (lim / 4.0) noiseMax exit++-- | Function 'opFile' is used internally in 'alterVadB' to check whether @FilePath@ exist and if so to do some processing to allow the 'alterVadB' function iterate further.+opFile :: FilePath -> Float -> Int -> IO ()+opFile file exit noiseMax = do+ removeFile file+ exist0 <- doesFileExist file+ if not exist0 + then do + renameFile ("7" ++ file) file+ lim2 <- durationA file+ alterVadB file lim2 noiseMax exit+ else opFile file exit noiseMax++-- | Function 'norm' applies a SoX normalization effect on the audio file. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+norm :: FilePath -> IO ()+norm file = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "8" ++ file, "norm"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "8" ++ file+ if e1+ then do+ removeFile $ "8" ++ file+ catchEnd (NotCreatedWithEffect "norm")+ else catchEnd (NotCreatedWithEffect "norm")+ else do + e2 <- doesFileExist $ "8" ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'normL' applies a SoX gain effect on the audio file with the maximum absolute dB value given by the @Int@ argument. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+normL :: FilePath -> Int -> IO ()+normL file level = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "9" ++ file, "gain", "-n", show level] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "9" ++ file+ if e1+ then do+ removeFile $ "9" ++ file+ catchEnd (NotCreatedWithEffect "gain -n")+ else catchEnd (NotCreatedWithEffect "gain -n")+ else do + e2 <- doesFileExist $ "9" ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'normL' applies a SoX \"gain -b [db-Value]\" effect on the audio file with dB value given by the @Float@ argument. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+gainL :: FilePath -> Float -> IO ()+gainL file level = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "9" ++ file, "gain", "-b", showFFloat (Just 6) level $ show 0] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "9" ++ file+ if e1+ then do+ removeFile $ "9" ++ file+ catchEnd (NotCreatedWithEffect "gain -b")+ else catchEnd (NotCreatedWithEffect "gain -b")+ else do + e2 <- doesFileExist $ "9" ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'soxStat' prints a SoX statistics for the audio file.+soxStat :: FilePath -> IO ()+soxStat file = if isJust (showE "sox") + then do + (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "stat"] ""+ putStrLn herr+ else catchEnd ExecutableNotProperlyInstalled+ +-- | Function 'alterVadE' removes an approximate silence measured by the absolute value of the sound amplitude from the end of the file. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). The second @Float@ parameter is used to exit the iteration cycle. The @Int@ parameter +-- from the range [0..3] specifies a maximum amplitude, starting from which the sound will not be trimmed.+alterVadE :: FilePath -> Float -> Int -> Float -> IO ()+alterVadE file lim noiseMax exit | compare lim exit /= GT = putStrLn $ "File " ++ file ++ " is ready for further processing"+ | otherwise = + if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "6" ++ file, "reverse"] ""+ if code /= ExitSuccess+ then do+ e0 <- doesFileExist $ "6" ++ file+ if e0+ then do+ removeFile $ "6" ++ file+ catchEnd (NotCreated file)+ else do+ catchEnd (NotCreated file)+ else do+ alterVadB ("6" ++ file) lim noiseMax exit+ (code1, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) ["6" ++ file, "76" ++ file, "reverse"] ""+ if code1 /= ExitSuccess+ then do+ e1 <- doesFileExist $ "76" ++ file+ if e1+ then do+ removeFile $ "76" ++ file+ removeFile $ "6" ++ file+ catchEnd (NotCreated file)+ else do+ removeFile $ "6" ++ file+ catchEnd (NotCreated file)+ else do+ e2 <- doesFileExist $ "76" ++ file+ if e2+ then do+ removeFile $ "6" ++ file+ removeFile file+ renameFile ("76" ++ file) file+ else do+ removeFile $ "6" ++ file+ catchEnd (NotCreated file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'upperBnd' returns a maximum number of samples for use in other functions.+upperBnd :: FilePath -> IO Int+upperBnd file = if isJust (showE "soxi") + then do + (_, Just hout, _, _) <- createProcess (proc (fromJust (showE "soxi")) ["-s",file]){ std_out = CreatePipe }+ x0 <- hGetContents hout+ let z = read x0::Int in return z+ else catchEnd ExecutableNotProperlyInstalled >> return (0::Int)++-- | Variant of the function 'extremeS' with all the additional information included.+extremeS1 :: FilePath -> IO Int+extremeS1 file = do+ upp <- upperBnd file+ extremeS file (0::Int, upp) (if upp `quot` 32 > 2 then upp `quot` 32 else 2::Int) (selMaxAbs file (0::Int, upp))++-- | Function 'quarterSinFade' applies a fade effect by SoX to the audio file with \"q\" type. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+quarterSinFade :: FilePath -> IO ()+quarterSinFade file = if isJust (showE "sox") + then do+ pos <- extremeS1 file+ upp <- upperBnd file+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "4" ++ file, "fade", "q", show pos ++ "s", "=" ++ show upp ++ "s", show (upp - pos) ++ "s"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "4" ++ file+ if e1+ then do+ removeFile $ "4" ++ file+ catchEnd (NotCreatedWithEffect "fade q")+ else catchEnd (NotCreatedWithEffect "fade q")+ else do + e2 <- doesFileExist $ "4" ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'silenceBoth' adds some silence to both ends of the audio. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+silenceBoth :: FilePath -> Int -> Int -> IO ()+silenceBoth file beginning end = if isJust (showE "sox") + then do+ _ <- readProcessWithExitCode (fromJust (showE "sox")) [file, "3" ++ file, "delay", show beginning ++ "s", "reverse"] ""+ _ <- readProcessWithExitCode (fromJust (showE "sox")) ["3" ++ file, "2" ++ file, "delay", show end ++ "s", "reverse"] ""+ removeFile $ "3" ++ file+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'recA' records audio file with the given name and duration in seconds. For Windows it uses a default audio device and \"-t waveaudio -d\" option to the SoX.+recA :: FilePath -> Float -> IO ()+recA file x | isJust (showE "sox") && take 5 os == "mingw" = do + (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) ["-t","waveaudio","-d","-b16", "-c1", "-esigned-integer", "-L", file, "trim", "0.5", showFFloat Nothing x $ show 0] ""+ if code /= ExitSuccess+ then do+ e0 <- doesFileExist file+ if e0+ then do+ removeFile file+ catchEnd (NotRecorded file)+ else catchEnd (NotRecorded file)+ else do+ e1 <- doesFileExist file+ if e1+ then return ()+ else catchEnd (NotRecorded file)+ | isJust (showE "rec") = do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "rec")) ["-b16", "-c1", "-esigned-integer", "-L", file, "trim", "0.5", showFFloat Nothing x $ show 0] ""+ if code /= ExitSuccess+ then do+ e0 <- doesFileExist file+ if e0+ then do+ removeFile file+ catchEnd (NotRecorded file)+ else catchEnd (NotRecorded file)+ else do+ e1 <- doesFileExist file+ if e1+ then return ()+ else catchEnd (NotRecorded file)+ | otherwise = catchEnd ExecutableNotProperlyInstalled++-- | Function 'recB' records audio file with the given name and duration in seconds. For Windows it uses a default audio device and \"-t waveaudio -d\" option +-- to the SoX. Unlike 'recA', the duration of the pause in seconds (before the SoX executable actually starts to record sound data after+-- an initialization of the sound recording device) is controlled by the second @Float@ function argument. +recB :: FilePath -> (Float, Float) -> IO ()+recB file (x, y) | isJust (showE "sox") && take 5 os == "mingw" = do + (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) ["-t","waveaudio","-d","-b16", "-c1", "-esigned-integer", "-L", file, "trim", showFFloat Nothing y $ show 0, showFFloat Nothing x $ show 0] ""+ if code /= ExitSuccess+ then do+ e0 <- doesFileExist file+ if e0+ then do+ removeFile file+ catchEnd (NotRecorded file)+ else catchEnd (NotRecorded file)+ else do+ e1 <- doesFileExist file+ if e1+ then return ()+ else catchEnd (NotRecorded file)+ | isJust (showE "rec") = do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "rec")) ["-b16", "-c1", "-esigned-integer", "-L", file, "trim", showFFloat Nothing y $ show 0, showFFloat Nothing x $ show 0] ""+ if code /= ExitSuccess+ then do+ e0 <- doesFileExist file+ if e0+ then do+ removeFile file+ catchEnd (NotRecorded file)+ else catchEnd (NotRecorded file)+ else do+ e1 <- doesFileExist file+ if e1+ then return ()+ else catchEnd (NotRecorded file)+ | otherwise = catchEnd ExecutableNotProperlyInstalled++-- | Function 'resampleA' changes the sample rate for the recorded audio for further processing. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+resampleA :: FilePath -> Int -> IO ()+resampleA file frequency = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "3" ++ file, "rate", "-s", "-I", show frequency] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "3" ++ file+ if e1+ then do+ removeFile $ "3" ++ file+ catchEnd (NotCreatedWithEffect "rate")+ else catchEnd (NotCreatedWithEffect "rate")+ else do + e2 <- doesFileExist $ "3" ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'durationA' returns a duration of the audio file in seconds.+durationA :: FilePath -> IO Float+durationA file = if isJust (showE "soxi") + then do+ (_, Just hout, _, _) <- createProcess (proc (fromJust (showE "soxi")) ["-D",file]){ std_out = CreatePipe }+ x0 <- hGetContents hout+ let z = read x0::Float in return z+ else catchEnd ExecutableNotProperlyInstalled >> return 0.0++-- | Function 'playA' plays the given file with SoX. For Windows it uses \"-t waveaudio -d\" options for SoX.+playA :: FilePath -> IO ()+playA file | take 5 os == "mingw" = + if isJust (showE "sox") + then readProcessWithExitCode (fromJust (showE "sox")) [file, "-t", "waveaudio", "-d"] "" >> return ()+ else catchEnd ExecutableNotProperlyInstalled+ | otherwise = if isJust (showE "play") + then readProcessWithExitCode (fromJust (showE "play")) [file] "" >> return ()+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseProfB' creates with SoX a file containing a noise profile for the first 0.05 s of the audio file given.+noiseProfB :: FilePath -> IO ()+noiseProfB file = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", "0", "0.05", "noiseprof",file ++ ".b.prof"] ""+ if code /= ExitSuccess+ then do+ e0 <- doesFileExist $ file ++ ".b.prof"+ if e0+ then do+ removeFile $ file ++ ".b.prof"+ catchEnd (NoiseProfileNotCreatedB file)+ else catchEnd (NoiseProfileNotCreatedB file)+ else do + e1 <- doesFileExist $ file ++ ".b.prof"+ if e1+ then return ()+ else catchEnd (NoiseProfileNotCreatedB file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseProfE' creates with SoX a file containing a noise profile for the last 0.05 s of the audio file given. +noiseProfE :: FilePath -> IO ()+noiseProfE file = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", "-0.05", "0.05", "noiseprof",file ++ ".e.prof"] ""+ if code /= ExitSuccess+ then do+ e0 <- doesFileExist $ file ++ ".e.prof"+ if e0+ then do+ removeFile $ file ++ ".e.prof"+ catchEnd (NoiseProfileNotCreatedE file)+ else catchEnd (NoiseProfileNotCreatedE file)+ else do + e1 <- doesFileExist $ file ++ ".e.prof"+ if e1+ then return ()+ else catchEnd (NoiseProfileNotCreatedE file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseReduceB' reduces with SoX a noise in the file given with the corresponding noise profile created with 'noiseProfB' function. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+noiseReduceB :: FilePath -> IO ()+noiseReduceB file = if isJust (showE "sox")+ then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "_" ++ file, "noisered", file ++ ".b.prof"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "_" ++ file+ if e1+ then do+ removeFile $ "_" ++ file+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist $ "_" ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseReduceE' reduces with SoX a noise in the file given with the corresponding noise profile created with 'noiseProfE' function. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+noiseReduceE :: FilePath -> IO ()+noiseReduceE file = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "_." ++ file, "noisered", file ++ ".e.prof"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "_." ++ file+ if e1+ then do+ removeFile $ "_." ++ file+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist $ "_." ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseReduceBU' reduces with SoX a noise in the file given with the corresponding noise profile created with 'noiseProfBU' function. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). The @Float@ parameter is a number between 0 and 1 showing the level of+-- reducing the noise (the greater number means that the function will reduce more intensively may be even aggressively so that for greater+-- numbers it can remove some sensitive and important sound data as a noise). Internally this parameter is passed unchanged to the \"sox\"+-- so that it uses it as an amount parameter for the \"noisered\" effect. Therefore, please, (as being stated in the SoX manual) experiment+-- with the amount to get suitable results. +noiseReduceBU :: FilePath -> Float -> IO ()+noiseReduceBU file amount = if isJust (showE "sox")+ then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "_" ++ file, "noisered", file ++ ".b.prof", showFFloat (Just 4) amount $ show 0] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "_" ++ file+ if e1+ then do+ removeFile $ "_" ++ file+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist $ "_" ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseReduceEU' reduces with SoX a noise in the file given with the corresponding noise profile created with 'noiseProfEU' function. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). The @Float@ parameter is a number between 0 and 1 showing the level of+-- reducing the noise (the greater number means that the function will reduce more intensively may be even aggressively so that for greater+-- numbers it can remove some sensitive and important sound data as a noise). Internally this parameter is passed unchanged to the \"sox\"+-- so that it uses it as an amount parameter for the \"noisered\" effect. Therefore, please, (as being stated in the SoX manual) experiment+-- with the amount to get suitable results. +noiseReduceEU :: FilePath -> Float -> IO ()+noiseReduceEU file amount = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "_." ++ file, "noisered", file ++ ".e.prof", showFFloat (Just 4) amount $ show 0] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "_." ++ file+ if e1+ then do+ removeFile $ "_." ++ file+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist $ "_." ++ file+ if e2 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'volS' changes the given audio with the linear ratio for the amplitude so that the resulting amlitude is equal to the given @Float@ parameter.+-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from).+volS :: FilePath -> Float -> IO ()+volS file amplitude = if isJust (showE "sox") + then do+ norm file+ e0 <- doesFileExist $ "8" ++ file+ if e0+ then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) ["8" ++ file, "8." ++ file, "vol", showFFloat Nothing amplitude $ show 0, "amplitude"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "8." ++ file+ if e1+ then do+ removeFile $ "8." ++ file+ removeFile $ "8" ++ file+ catchEnd (NotCreatedWithEffect "vol")+ else do+ removeFile $ "8" ++ file+ catchEnd (NotCreatedWithEffect "vol")+ else do + e2 <- doesFileExist $ "8." ++ file+ if e2 + then return ()+ else do + removeFile $ "8" ++ file+ catchEnd (InitialFileNotChanged file)+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'volS2' changes the given audio (the first @FilePath@ parameter, which must be normalized e. g. by the 'norm' function before) with +-- the linear ratio for the amplitude so that the resulting amlitude is equal to the maximum by absolute value amplitude for the file given +-- by the second @FilePath@ parameter. The function must be used with the first @FilePath@ parameter containing no directories in its name +-- (that means the file of the first @FilePath@ parameter must be in the same directory where the function is called from).+volS2 :: FilePath -> FilePath -> IO ()+volS2 fileA fileB = if isJust (showE "sox") + then do+ upp <- upperBnd fileB+ amplMax <- selMA fileB (0, upp) True+ amplMin <- selMA fileB (0, upp) False+ let ampl = read (fst . maxAbs $ (amplMax, amplMin))::Float+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [fileA, "8." ++ tail fileA, "vol", showFFloat Nothing ampl $ show 0, "amplitude"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "8." ++ tail fileA+ if e1+ then do+ removeFile $ "8." ++ tail fileA+ catchEnd (NotCreatedWithEffect "vol")+ else catchEnd (NotCreatedWithEffect "vol")+ else do + file8e <- doesFileExist $ "8." ++ tail fileA+ if file8e + then return ()+ else catchEnd (InitialFileNotChanged fileA)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'sincA' uses a \"sinc\" effect with @-a 50 -I 0.07k-11k@ band-pass filter for the audio file given.+sincA :: FilePath -> IO ()+sincA file = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "4." ++ file, "sinc", "-a", "50", "-I", "0.07k-11k"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "4." ++ file+ if e1+ then do+ removeFile $ "4." ++ file+ catchEnd (NotCreatedWithEffect "sinc")+ else catchEnd (NotCreatedWithEffect "sinc")+ else do + e0 <- doesFileExist $ "4." ++ file+ if e0 + then return ()+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'sampleAn' analyzes the one samle of the 1-channel sound file (or k samples for the k-channel file) and returns a tuple pair of +-- the maximum and minimum amplitudes of the sound given as @String@s. For the 1-channel sound file they are the same. +-- The @Integer@ parameter is the number of the sample, starting from which SoX analyzes the sound. If it is less than number of the samples available, +-- then the function returns the value for the last one sample for the 1-channel file (or the last k samples for the k-channel sound file). +-- The file must not be in a RAW format for the function to work properly.+sampleAn :: FilePath -> Integer -> IO (String, String)+sampleAn file pos = if isJust (showE "sox") && isJust (showE "soxi")+ then onException (do+ (_, hout, _) <- readProcessWithExitCode (fromJust (showE "soxi")) ["-s", file] ""+ let length0 = read hout::Integer+ f param = do + (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", show param ++ "s", "1s", "stat"] ""+ let lns = map (last . words) . drop 3 . take 5 . lines $ herr in return (head lns, last lns)+ if compare length0 (fromIntegral pos) == GT + then f pos+ else f (length0 - 1)) (catchEnd (NotEnoughData file))+ else catchEnd ExecutableNotProperlyInstalled >> return ("","")
+ SoXBasics1/Arr.hs view
@@ -0,0 +1,431 @@+-- |+-- Module : SoXBasics1.Arr+-- Copyright : (c) OleksandrZhabenko 2020-2022+-- License : MIT+-- Stability : Experimental+-- Maintainer : olexandr543@yahoo.com+--+-- A program and a library that can be used as a simple +-- basic interface to some SoX functionality or for producing +-- the approximately Ukrainian speech with your own recorded +-- voice (actually it produces the needed sound representations). +-- This module differs from a SoXBasics that the resulting files+-- in it have possibly just the same name as the input ones. The functions+-- try to replace the initial file with the processed one.+-- +++module SoXBasics1.Arr (+ -- * Produce sound+ -- ** Amplitude modification+ norm+ , normL+ , gainL+ , quarterSinFade+ -- ** Adding silence+ , silenceBoth+ -- ** Changing sample rate+ , resampleA+ -- ** Working with noise+ , noiseReduceB+ , noiseReduceE+ , noiseReduceBU+ , noiseReduceEU+ -- ** Filtering+ , sincA+ -- ** Volume amplification+ , volS+ , volS2+) where++import System.Directory+import Data.Maybe (isJust, fromJust)+import Numeric+import System.Process+import EndOfExe+import System.Exit+import qualified SoXBasics.Arr as SB (extremeS1,upperBnd,selMA,maxAbs,norm)+import Control.Exception.FinalException.Arr++-- | Function 'norm' applies a SoX normalization effect on the audio file. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+norm :: FilePath -> IO ()+norm file = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "8" ++ file, "norm"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "8" ++ file+ if e1+ then do+ removeFile $ "8" ++ file+ catchEnd (NotCreatedWithEffect "norm")+ else catchEnd (NotCreatedWithEffect "norm")+ else do + e2 <- doesFileExist $ "8" ++ file+ if e2 + then do+ removeFile file+ renameFile ("8" ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'normL' applies a SoX gain effect on the audio file with the maximum absolute dB value given by the @Int@ argument. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+normL :: FilePath -> Int -> IO ()+normL file level = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "9" ++ file, "gain", "-n", show level] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "9" ++ file+ if e1+ then do+ removeFile $ "9" ++ file+ catchEnd (NotCreatedWithEffect "gain -n")+ else catchEnd (NotCreatedWithEffect "gain -n")+ else do + e2 <- doesFileExist $ "9" ++ file+ if e2 + then do+ removeFile file+ renameFile ("9" ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'normL' applies a SoX \"gain -b [db-Value]\" effect on the audio file with dB value given by the @Float@ argument. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+gainL :: FilePath -> Float -> IO ()+gainL file level = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "9" ++ file, "gain", "-b", showFFloat (Just 6) level $ show 0] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "9" ++ file+ if e1+ then do+ removeFile $ "9" ++ file+ catchEnd (NotCreatedWithEffect "gain -b")+ else catchEnd (NotCreatedWithEffect "gain -b")+ else do + e2 <- doesFileExist $ "9" ++ file+ if e2 + then do+ removeFile file+ renameFile ("9" ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'quarterSinFade' applies a fade effect by SoX to the audio file with \"q\" type. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+quarterSinFade :: FilePath -> IO ()+quarterSinFade file = if isJust (showE "sox") + then do+ pos <- SB.extremeS1 file+ upp <- SB.upperBnd file+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "4" ++ file, "fade", "q", show pos ++ "s", "=" ++ show upp ++ "s", show (upp - pos) ++ "s"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "4" ++ file+ if e1+ then do+ removeFile $ "4" ++ file+ catchEnd (NotCreatedWithEffect "fade q")+ else catchEnd (NotCreatedWithEffect "fade q")+ else do + e2 <- doesFileExist $ "4" ++ file+ if e2 + then do+ removeFile file+ renameFile ("4" ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'silenceBoth' adds some silence to both ends of the audio. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+silenceBoth :: FilePath -> Int -> Int -> IO ()+silenceBoth file beginning end = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "3" ++ file, "delay", show beginning ++ "s", "reverse"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "3" ++ file+ if e1+ then do+ removeFile $ "3" ++ file+ catchEnd (NotCreatedWithEffects "delay reverse")+ else catchEnd (NotCreatedWithEffects "delay reverse")+ else do + e2 <- doesFileExist $ "3" ++ file+ if e2 + then do+ (code1, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) ["3" ++ file, "2" ++ file, "delay", show end ++ "s", "reverse"] ""+ if code1 /= ExitSuccess+ then do+ e2 <- doesFileExist $ "2" ++ file+ if e2+ then do+ removeFile $ "3" ++ file+ removeFile $ "2" ++ file+ catchEnd (NotCreated file)+ else do+ removeFile $ "3" ++ file+ catchEnd (NotCreated file)+ else do+ e3 <- doesFileExist $ "2" ++ file+ if e3+ then do+ removeFile $ "3" ++ file+ removeFile file+ renameFile ("2" ++ file) file+ else do+ removeFile $ "3" ++ file+ catchEnd (NotCreated file)+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'resampleA' changes the sample rate for the recorded audio for further processing. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+resampleA :: FilePath -> Int -> IO ()+resampleA file frequency = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "3" ++ file, "rate", "-s", "-I", show frequency] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "3" ++ file+ if e1+ then do+ removeFile $ "3" ++ file+ catchEnd (NotCreatedWithEffect "rate")+ else catchEnd (NotCreatedWithEffect "rate")+ else do + e2 <- doesFileExist $ "3" ++ file+ if e2 + then do+ removeFile file+ renameFile ("3" ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseReduceB' reduces with SoX a noise in the file given with the corresponding noise profile created with 'noiseProfB' function. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+noiseReduceB :: FilePath -> IO ()+noiseReduceB file = if isJust (showE "sox")+ then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "_" ++ file, "noisered", file ++ ".b.prof"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "_" ++ file+ if e1+ then do+ removeFile $ "_" ++ file+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist $ "_" ++ file+ if e2 + then do+ removeFile file+ renameFile ("_" ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseReduceE' reduces with SoX a noise in the file given with the corresponding noise profile created with 'noiseProfE' function. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+noiseReduceE :: FilePath -> IO ()+noiseReduceE file = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "_." ++ file, "noisered", file ++ ".e.prof"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "_." ++ file+ if e1+ then do+ removeFile $ "_." ++ file+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist $ "_." ++ file+ if e2 + then do+ removeFile file+ renameFile ("_." ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseReduceBU' reduces with SoX a noise in the file given with the corresponding noise profile created with 'noiseProfBU' function. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). The @Float@ parameter is a number between 0 and 1 showing the level of+-- reducing the noise (the greater number means that the function will reduce more intensively may be even aggressively so that for greater+-- numbers it can remove some sensitive and important sound data as a noise). Internally this parameter is passed unchanged to the \"sox\"+-- so that it uses it as an amount parameter for the \"noisered\" effect. Therefore, please, (as being stated in the SoX manual) experiment+-- with the amount to get suitable results. While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+noiseReduceBU :: FilePath -> Float -> IO ()+noiseReduceBU file amount = if isJust (showE "sox")+ then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "_" ++ file, "noisered", file ++ ".b.prof", showFFloat (Just 4) amount $ show 0] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "_" ++ file+ if e1+ then do+ removeFile $ "_" ++ file+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist $ "_" ++ file+ if e2 + then do+ removeFile file+ renameFile ("_" ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'noiseReduceEU' reduces with SoX a noise in the file given with the corresponding noise profile created with 'noiseProfE' function. +-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). The @Float@ parameter is a number between 0 and 1 showing the level of+-- reducing the noise (the greater number means that the function will reduce more intensively may be even aggressively so that for greater+-- numbers it can remove some sensitive and important sound data as a noise). Internally this parameter is passed unchanged to the \"sox\"+-- so that it uses it as an amount parameter for the \"noisered\" effect. Therefore, please, (as being stated in the SoX manual) experiment+-- with the amount to get suitable results. While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+noiseReduceEU :: FilePath -> Float -> IO ()+noiseReduceEU file amount = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "_." ++ file, "noisered", file ++ ".e.prof", showFFloat (Just 4) amount $ show 0] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "_." ++ file+ if e1+ then do+ removeFile $ "_." ++ file+ catchEnd (NotCreatedWithEffect "noisered")+ else catchEnd (NotCreatedWithEffect "noisered")+ else do + e2 <- doesFileExist $ "_." ++ file+ if e2 + then do+ removeFile file+ renameFile ("_." ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'volS' changes the given audio with the linear ratio for the amplitude so that the resulting amlitude is equal to the given @Float@ parameter.+-- The function must be used with the @FilePath@ parameter containing no directories in its name (that means the file of the @FilePath@ parameter must be +-- in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+volS :: FilePath -> Float -> IO ()+volS file amplitude = if isJust (showE "sox") + then do+ SB.norm file+ e0 <- doesFileExist $ "8" ++ file+ if e0+ then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) ["8" ++ file, "8." ++ file, "vol", showFFloat Nothing amplitude $ show 0, "amplitude"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "8." ++ file+ if e1+ then do+ removeFile $ "8." ++ file+ removeFile $ "8" ++ file+ catchEnd (NotCreatedWithEffect "vol")+ else do+ removeFile $ "8" ++ file+ catchEnd (NotCreatedWithEffect "vol")+ else do + e2 <- doesFileExist $ "8." ++ file+ if e2 + then do+ removeFile file+ removeFile $ "8" ++ file+ renameFile ("8." ++ file) file+ else do + removeFile $ "8" ++ file+ catchEnd (InitialFileNotChanged file)+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'volS2' changes the given audio (the first @FilePath@ parameter, which must be normalized e. g. by the 'norm' function before) with +-- the linear ratio for the amplitude so that the resulting amlitude is equal to the maximum by absolute value amplitude for the file given +-- by the second @FilePath@ parameter. The function must be used with the first @FilePath@ parameter containing no directories in its name +-- (that means the file of the first @FilePath@ parameter must be in the same directory where the function is called from). While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+volS2 :: FilePath -> FilePath -> IO ()+volS2 fileA fileB = if isJust (showE "sox") + then do+ upp <- SB.upperBnd fileB+ amplMax <- SB.selMA fileB (0, upp) True+ amplMin <- SB.selMA fileB (0, upp) False+ let ampl = read (fst . SB.maxAbs $ (amplMax, amplMin))::Float+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [fileA, "8." ++ tail fileA, "vol", showFFloat Nothing ampl $ show 0, "amplitude"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "8." ++ tail fileA+ if e1+ then do+ removeFile $ "8." ++ tail fileA+ catchEnd (NotCreatedWithEffect "vol")+ else catchEnd (NotCreatedWithEffect "vol")+ else do + file8e <- doesFileExist $ "8." ++ tail fileA+ if file8e + then do+ removeFile fileA+ renameFile ("8." ++ tail fileA) fileA+ else catchEnd (InitialFileNotChanged fileA)+ else catchEnd ExecutableNotProperlyInstalled++-- | Function 'sincA' uses a \"sinc\" effect with @-a 50 -I 0.07k-11k@ band-pass filter for the audio file given. While being+-- executed the function tries to replace the initial file with the resulting processed one and to clean the temporary files. If it is not+-- successful the function exits with exception of the type 'FinalException' and leaves the initial file without modification.+sincA :: FilePath -> IO ()+sincA file = if isJust (showE "sox") + then do+ (code, _, _) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "4." ++ file, "sinc", "-a", "50", "-I", "0.07k-11k"] ""+ if code /= ExitSuccess + then do+ e1 <- doesFileExist $ "4." ++ file+ if e1+ then do+ removeFile $ "4." ++ file+ catchEnd (NotCreatedWithEffect "sinc")+ else catchEnd (NotCreatedWithEffect "sinc")+ else do + e0 <- doesFileExist $ "4." ++ file+ if e0 + then do+ removeFile file+ renameFile ("4." ++ file) file+ else catchEnd (InitialFileNotChanged file)+ else catchEnd ExecutableNotProperlyInstalled+
+ mmsyn7ukr-array.cabal view
@@ -0,0 +1,27 @@+-- Initial mmsyn7ukr-array.cabal. For further+-- documentation, see http://haskell.org/cabal/users-guide/++name: mmsyn7ukr-array+version: 0.1.0.0+synopsis: A simple reduced basic interface to some SoX functionality or to produce a voice that can be used by mmsyn7h-array, dobutokO2-array and other similar packages+description: A reduced set of modules and functionality needed to dobutokO2-array package and probably some other ones. Is rewritten from the mmsyn7ukr-0.17.0.0 package to reduce the needed dependencies.+homepage: https://hackage.haskell.org/package/mmsyn7ukr-array+license: MIT+license-file: LICENSE+author: OleksandrZhabenko+maintainer: olexandr543@yahoo.com+copyright: (c) Oleksandr Zhabenko 2019-2022+category: Language, Sound+build-type: Simple+extra-source-files: ChangeLog.md, README.md+data-files: y.wav+cabal-version: >=1.10++library+ exposed-modules: SoXBasics.Arr, SoXBasics1.Arr, Processing_mmsyn7ukr_array, ReplaceP.Arr, Control.Exception.FinalException.Arr+ -- other-modules:+ -- other-extensions:+ build-depends: base >=4.7 && <5, process >=1.4 && <2, mmsyn2-array ==0.3.0.0, directory >=1.2.5 && <2, mmsyn3 ==0.1.6.0+ -- hs-source-dirs:+ default-language: Haskell2010+
+ y.wav view
binary file changed (absent → 8044 bytes)