{- wavedrum-lib, a library to parse, edit and write Korg Wavedrum programs. Copyright (C) 2013 Ricardo Wurmus This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -} {-# LANGUAGE OverloadedStrings #-} module Wavedrum where import Control.Monad (replicateM,mapM_) import Data.Binary.Get import Data.Binary.Put import qualified Data.ByteString.Lazy as B import Wavedrum.Types import Wavedrum.Algorithm byTarget :: Program -> Target -> [Param] byTarget prg t = filter (\param -> target param == t) prg parseProgram :: Get Program parseProgram = do values1 <- replicateM 7 (fmap fromIntegral getWord16be) headVals <- replicateM 8 (fmap fromIntegral getWord16be) values2 <- replicateM 5 (fmap fromIntegral getWord16be) rimVals <- replicateM 8 (fmap fromIntegral getWord16be) values3 <- replicateM 26 (fmap fromIntegral getWord16be) let headSettings = getSettingsForAlg (last values1) let rimSettings = getSettingsForAlg (last values2) return $ concat [ zipWith ($) params1 values1 , zipWith ($) (zipWith3 ($) headParams (map fst headSettings) (map snd headSettings)) headVals , zipWith ($) params2 values2 , zipWith ($) (zipWith3 ($) rimParams (map fst rimSettings) (map snd rimSettings)) rimVals , zipWith ($) params3 values3 ] where getSettingsForAlg n = if n > 0 && n < length algorithms then algoParams $ algorithms !! (n - 1) else replicate 8 ("", (0,0)) params1 = [ Param HeadAlg "Pressure curve" ( 0, 5) , Param General "Pre EQ" ( 0, 4) -- H-H, H-S, S S, H-n, S-n , Param HeadAlg "Tune" ( 0,100) , Param HeadAlg "Level" ( 0,100) , Param HeadAlg "Decay" ( 0,100) , Param HeadAlg "Pan" (-50, 50) -- L50..R50 , Param HeadAlg "Algorithm select" ( 1, 36) -- 01..36 ] params2 = [ Param RimAlg "Tune" ( 0,100) , Param RimAlg "Decay" ( 0,100) , Param RimAlg "Level" ( 0,100) , Param RimAlg "Pan" (-50, 50) -- L50..R50 , Param RimAlg "Algorithm select" ( 1, 25) ] params3 = [ Param HeadPCM "Tune" (-24, 24) -- semitones , Param HeadPCM "Decay" (-99, 99) , Param HeadPCM "Level" ( 0,100) , Param HeadPCM "Pan" (-50, 50) -- L50..R50 , Param HeadPCM "PCM instrument select" ( 0,100) , Param HeadPCM "Velocity curve" ( 0, 9) , Param HeadPCM "Pressure curve" ( 0, 5) , Param HeadPCM "Pressure tune" (-12, 12) , Param HeadPCM "Pressure decay" (-50, 50) , Param RimPCM "Tune" (-24, 24) -- semitones , Param RimPCM "Decay" (-99, 99) , Param RimPCM "Level" ( 0,100) , Param RimPCM "Pan" (-50, 50) -- L50..R50 , Param RimPCM "PCM instrument select" ( 0,100) , Param RimPCM "Velocity curve" ( 0, 9) , Param RimPCM "Pressure curve" ( 0, 5) , Param RimPCM "Pressure tune" (-12, 12) , Param RimPCM "Pressure decay" (-50, 50) , Param General "Reverb type" ( 0, 10) , Param General "Reverb effect level" ( 0,100) , Param General "Reverb decay time" ( 0, 90) , Param General "Reverb frequency damping" ( 0,100) , Param General "Delay feedback" ( 0, 99) , Param General "Delay effect level" ( 0,100) , Param General "Delay time" ( 0,200) , Param General "Delay frequency damping" ( 0,100) ] headParams = replicate 8 $ Param HeadAlg rimParams = replicate 8 $ Param RimAlg readProgram :: B.ByteString -> Program readProgram = runGet parseProgram -- each Program is 108 bytes long (54 16-bit words) readAllPrograms :: B.ByteString -> [Program] readAllPrograms bs = if B.null bs then [] else let (rawPrg, rest) = B.splitAt 108 bs in readProgram rawPrg : readAllPrograms rest putRawParams :: Program -> Put putRawParams = mapM_ putRawParam where putRawParam = putWord16be . fromIntegral . value serialize :: Program -> B.ByteString serialize p = runPut $ putRawParams p serializeAll :: [Program] -> B.ByteString serializeAll = B.concat . map serialize loadProgramFromFile :: String -> IO Program loadProgramFromFile f = fmap readProgram (B.readFile f) loadProgramsFromFile :: String -> IO [Program] loadProgramsFromFile f = fmap readAllPrograms (B.readFile f) writeProgramToFile :: String -> Program -> IO () writeProgramToFile f p = B.writeFile f (serialize p) ppProgram :: Program -> IO () ppProgram = mapM_ (putStrLn . show)