-- Copyright 2013 Evan Laforge
-- This program is distributed under the terms of the GNU General Public
-- License 3.0, see COPYING or http://www.gnu.org/licenses/gpl-3.0.txt

{-# OPTIONS_GHC -fno-warn-unused-binds #-}
-- In ghc 8 change to:
-- {-# OPTIONS_GHC -Wno-warn-unused-top-binds #-}

-- | Utilities to encode and generate z1 sysex dumps.
--
-- TODO
-- Basic parsing and modification works, but some fields, like effects, are not
-- parsed.
module User.Elaforge.Instrument.Z1Spec (
    decode, encode, spec_bytes
    , program_dump_header, current_program_dump_header
    , patch_spec, multiset_spec
) where
import qualified Data.ByteString as B
import Data.ByteString (ByteString)

import qualified Midi.Midi as Midi
import qualified Instrument.Sysex as Sysex
import Instrument.Sysex
       (Specs, Spec(..), bits, ranged_bits, unsigned, bool_bit, enum, enum_bits,
        ranged, signed)
import Global

-- TODO
-- * finish the effects
-- - put them in patch_spec and multiset_spec
-- - finish osc types

config :: Sysex.Config
config :: Config
config = Config
Sysex.config_8bit

encode :: Specs -> Sysex.RMap -> Either String ByteString
encode :: Specs -> RMap -> Either [Char] ByteString
encode = Config -> Specs -> RMap -> Either [Char] ByteString
Sysex.encode Config
config

decode :: Specs -> ByteString -> Either String (Sysex.RMap, ByteString)
decode :: Specs -> ByteString -> Either [Char] (RMap, ByteString)
decode = Config -> Specs -> ByteString -> Either [Char] (RMap, ByteString)
Sysex.decode Config
config

spec_bytes :: Specs -> Int
spec_bytes :: Specs -> Int
spec_bytes = Config -> Specs -> Int
Sysex.spec_bytes Config
config

assert_valid :: String -> Int -> Specs -> Specs
assert_valid :: [Char] -> Int -> Specs -> Specs
assert_valid = Config -> [Char] -> Int -> Specs -> Specs
Sysex.assert_valid Config
config

-- | I think 0x30 should be 0x3g where g is the global channel, but I use 0
-- so this works.
z1_header :: ByteString
z1_header :: ByteString
z1_header = [Word8] -> ByteString
B.pack [Word8
0xf0, Word8
Midi.korg_code, Word8
0x30, Word8
0x46]

program_dump_header :: Specs
program_dump_header :: Specs
program_dump_header =
    [ ([Char]
"", ByteString -> Spec
Constant ByteString
z1_header)
    , ([Char]
"", ByteString -> Spec
Constant (Word8 -> ByteString
B.singleton Word8
0x4c))
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"bank", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName
"a", EnumName
"b"])
        , ([Char]
"unit", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName
"program", EnumName
"bank", EnumName
"", EnumName
"all"])
        ])
    , ([Char]
"program number", Int -> Spec
unsigned Int
127)
    , ([Char]
"", ByteString -> Spec
Constant (Word8 -> ByteString
B.singleton Word8
0))
    ]

current_program_dump_header :: Specs
current_program_dump_header :: Specs
current_program_dump_header =
    [ ([Char]
"", ByteString -> Spec
Constant ByteString
z1_header)
    , ([Char]
"", ByteString -> Spec
Constant (ByteString -> Spec) -> ByteString -> Spec
forall a b. (a -> b) -> a -> b
$ [Word8] -> ByteString
B.pack [Word8
0x40, Word8
0x01])
    ]

-- * program / patch

patch_spec :: Specs
patch_spec :: Specs
patch_spec = Config -> [Char] -> Int -> Specs -> Specs
Sysex.assert_valid Config
config [Char]
"patch_spec" Int
576
    [ ([Char]
"name", Int -> Spec
Str Int
16)
    , ([Char]
"category", [EnumName] -> Spec
enum [EnumName]
categories)
    , ([Char]
"user group", Int -> Spec
unsigned Int
15)
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"hold", Int -> BitField
bits Int
1)
        , ([Char]
"key priority", Int -> [EnumName] -> BitField
enum_bits Int
2 [EnumName
"last", EnumName
"low", EnumName
"high"])
        , ([Char]
"voice assign mode", Int -> [EnumName] -> BitField
enum_bits Int
5
            [EnumName
"mono multi", EnumName
"mono single", EnumName
"poly"])
        ])
    , ([Char]
"retrigger controllor", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)
    , ([Char]
"retrigger control threshold", Int -> Int -> Spec
ranged Int
1 Int
127)
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"unison type", Int -> [EnumName] -> BitField
enum_bits Int
2 [EnumName
"off", EnumName
"2", EnumName
"3", EnumName
"6"])
        , ([Char]
"unison sw", BitField
bool_bit)
        , ([Char]
"unison mode", Int -> [EnumName] -> BitField
enum_bits Int
5 [EnumName
"fixed", EnumName
"dynamic"])
        ])
    , ([Char]
"unison detune", Int -> Spec
unsigned Int
99)
    -- scale
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"scale key", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName]
scale_keys)
        , ([Char]
"scale type", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName]
scale_types)
        ])
    , ([Char]
"random pitch intensity", Int -> Spec
unsigned Int
99)
    , ([Char]
"eg", Int -> Specs -> Spec
List Int
4 Specs
eg_spec)
    , ([Char]
"lfo", Int -> Specs -> Spec
List Int
4 Specs
lfo_spec)
    -- osc common
    , ([Char], Spec)
pitch_bend
    , ([Char]
"common pitch mod source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"common pitch"
    , ([Char]
"portamento", Specs -> Spec
SubSpec
        [ ([Char]
"", [([Char], BitField)] -> Spec
Bits
            [ ([Char]
"sw", BitField
bool_bit)
            , ([Char]
"mode", Int -> [EnumName] -> BitField
enum_bits Int
7 [EnumName
"normal", EnumName
"fingered"])
            ])
        , ([Char]
"time", Int -> Spec
unsigned Int
99)
        , ([Char]
"mod source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
""
        ])
    , ([Char]
"osc", Int -> Specs -> Spec
List Int
2 Specs
osc_spec)
    , ([Char]
"sub osc", Specs -> Spec
SubSpec Specs
sub_osc_spec)
    , ([Char]
"noise generator filter", Specs -> Spec
SubSpec Specs
noise_generator_spec)
    , ([Char]
"mixer", Specs -> Spec
SubSpec Specs
mixer_spec)
    , ([Char]
"filter common", Specs -> Spec
SubSpec Specs
filter_common_spec)
    , ([Char]
"filter", Int -> Specs -> Spec
List Int
2 Specs
filter_spec)
    , ([Char]
"amp", Specs -> Spec
SubSpec Specs
amp_spec)
    , ([Char]
"output", Specs -> Spec
SubSpec Specs
output_spec)
    , ([Char]
"effect", Specs -> Spec
SubSpec Specs
effect_spec)
    , ([Char]
"controller", Specs -> Spec
SubSpec Specs
controller_spec)
    , ([Char]
"link arpeggio", Specs -> Spec
SubSpec (Int -> Specs
link_arpeggio_spec Int
7))
    , ([Char]
"pe knob", Int -> Specs -> Spec
List Int
5 Specs
pe_knob_spec)
    ]

pitch_bend :: (Sysex.Name, Spec)
pitch_bend :: ([Char], Spec)
pitch_bend = ([Char]
"pitch bend", Specs -> Spec
SubSpec
    [ ([Char]
"intensity +", Int -> Int -> Spec
ranged (-Int
60) Int
24)
    , ([Char]
"intensity -", Int -> Int -> Spec
ranged (-Int
60) Int
24)
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits ([([Char], BitField)] -> Spec) -> [([Char], BitField)] -> Spec
forall a b. (a -> b) -> a -> b
$
        let vals :: [EnumName]
vals = [EnumName
"0", EnumName
"1/8", EnumName
"1/4", EnumName
"1/2"] [EnumName] -> [EnumName] -> [EnumName]
forall a. [a] -> [a] -> [a]
++ (Integer -> EnumName) -> [Integer] -> [EnumName]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> EnumName
forall a. Show a => a -> EnumName
showt [Integer
1..Integer
12] in
        [ ([Char]
"step +", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName]
vals)
        , ([Char]
"step -", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName]
vals)
        ])
    ])

eg_spec :: Specs
eg_spec :: Specs
eg_spec =
    [ [Char] -> ([Char], Spec)
level [Char]
"start"
    , [Char] -> ([Char], Spec)
time [Char]
"attack"
    , [Char] -> ([Char], Spec)
level [Char]
"attack"
    , [Char] -> ([Char], Spec)
time [Char]
"decay"
    , [Char] -> ([Char], Spec)
level [Char]
"break"
    , [Char] -> ([Char], Spec)
time [Char]
"slope"
    , [Char] -> ([Char], Spec)
level [Char]
"sustain"
    , [Char] -> ([Char], Spec)
time [Char]
"release"
    , [Char] -> ([Char], Spec)
level [Char]
"release"
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"eg level"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"eg level"
    , ([Char]
"eg level velocity control", Int -> Spec
signed Int
99)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"eg time"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"eg time"
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"eg node time"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"attack time", [Char] -> ([Char], Spec)
mod_intensity [Char]
"decay time"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"slope time", [Char] -> ([Char], Spec)
mod_intensity [Char]
"release time"
    ]
    where
    level :: [Char] -> ([Char], Spec)
level [Char]
name = ([Char]
name [Char] -> [Char] -> [Char]
<+> [Char]
"level", Int -> Spec
signed Int
99)
    time :: [Char] -> ([Char], Spec)
time [Char]
name = ([Char]
name [Char] -> [Char] -> [Char]
<+> [Char]
"time", Int -> Spec
unsigned Int
99)

lfo_spec :: Specs
lfo_spec :: Specs
lfo_spec =
    [ ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"wave form", Int -> [EnumName] -> BitField
enum_bits Int
6 [EnumName]
lfo_waveforms)
        , ([Char]
"key sync sw", Int -> [EnumName] -> BitField
enum_bits Int
2 [EnumName
"off", EnumName
"timbre", EnumName
"voice"])
        ])
    , ([Char]
"frequency", Int -> Spec
unsigned Int
199)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"frequency 1"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"frequency 1"
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"frequency 2"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"frequency 2"
    , ([Char]
"fade in", Int -> Spec
unsigned Int
99)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"amplitude"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"amplitude"
    , ([Char]
"offset", Int -> Spec
signed Int
50)
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"midi sync time", Int -> (Int, Int) -> BitField
ranged_bits Int
4 (Int
0, Int
15))
        , ([Char]
"midi sync base", Int -> (Int, Int) -> BitField
ranged_bits Int
3 (Int
0, Int
7))
        , ([Char]
"midi sync", BitField
bool_bit)
        ])
    ]

lfo_waveforms :: [Sysex.EnumName]
lfo_waveforms :: [EnumName]
lfo_waveforms =
    [ EnumName
"triangle 0", EnumName
"triangle 90", EnumName
"tri random", EnumName
"sine"
    , EnumName
"saw up 0", EnumName
"saw up 180", EnumName
"saw down 0", EnumName
"saw down 180"
    , EnumName
"square", EnumName
"random s/h", EnumName
"random vector"
    , EnumName
"step tri 4", EnumName
"step tri 6", EnumName
"step saw 4", EnumName
"step saw 6"
    , EnumName
"exp tri", EnumName
"exp saw up", EnumName
"exp saw down"
    ]

-- | The Z1 has a built-in set of categories. Map the category index to the
-- name.
categories :: [Sysex.EnumName]
categories :: [EnumName]
categories =
    [ EnumName
"Synth-Hard", EnumName
"Synth-Soft", EnumName
"Synth-Lead", EnumName
"Synth-Motion", EnumName
"Synth-Bass"
    , EnumName
"E.Piano", EnumName
"Organ", EnumName
"Keyboard", EnumName
"Bell", EnumName
"Strings", EnumName
"Band/Choir"
    , EnumName
"Brass", EnumName
"Reed/Wind", EnumName
"Guitar/Plucked", EnumName
"Bass", EnumName
"Percussive"
    , EnumName
"Argpeggio", EnumName
"SFX/Other"
    ]

scale_keys :: [Sysex.EnumName]
scale_keys :: [EnumName]
scale_keys =
    [ EnumName
"c", EnumName
"cs", EnumName
"d", EnumName
"ds", EnumName
"e", EnumName
"f", EnumName
"g", EnumName
"gs", EnumName
"a", EnumName
"as", EnumName
"b"]

scale_types :: [Sysex.EnumName]
scale_types :: [EnumName]
scale_types =
    [ EnumName
"equal temperament", EnumName
"pure major temperament", EnumName
"pure minor temperament"
    , EnumName
"arabic temperament", EnumName
"pythagorean", EnumName
"werckmeister", EnumName
"kirnberger"
    , EnumName
"slendro", EnumName
"pelog", EnumName
"user scale 1", EnumName
"user scale 2", EnumName
"user scale 3"
    ]

-- * osc

osc_spec :: Specs
osc_spec :: Specs
osc_spec =
    [ ([Char]
"type", [EnumName] -> Spec
enum [EnumName]
osc_types)
    , ([Char]
"octave", Spec
octave)
    , ([Char]
"semi tone", Int -> Spec
signed Int
12)
    , ([Char]
"fine tune", Int -> Spec
signed Int
50)
    , ([Char]
"frequency offset", Int -> Spec
signed Int
100)
    -- pitch slope
    , ([Char]
"center key", Int -> Spec
unsigned Int
127)
    , ([Char]
"lower slope", Int -> Int -> Spec
ranged (-Int
50) Int
100)
    , ([Char]
"higher slope", Int -> Int -> Spec
ranged (-Int
50) Int
100)
    -- pitch modulation
    , ([Char]
"mod1 source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)
    , [Char] -> ([Char], Spec)
intensity [Char]
"mod1"
    , ([Char]
"mod1 intensity controller", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)
    , ([Char]
"mod1 intensity controller intensity", Int -> Spec
signed Int
99)
    , ([Char]
"mod2 source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)
    , ([Char]
"mod2 intensity", Int -> Spec
signed Int
99)
    , ([Char]
"setting", Int -> Spec
Unparsed Int
38) -- union of osc params
    ]

osc_types :: [Sysex.EnumName]
osc_types :: [EnumName]
osc_types =
    [ EnumName
"standard", EnumName
"comb", EnumName
"vpm", EnumName
"resonance", EnumName
"ring-mod", EnumName
"cross-mod", EnumName
"sync"
    , EnumName
"organ", EnumName
"electric-piano", EnumName
"brass", EnumName
"reed", EnumName
"plucked", EnumName
"bowed"
    ]

sub_osc_spec :: Specs
sub_osc_spec :: Specs
sub_osc_spec =
    [ ([Char]
"octave", Spec
octave)
    , ([Char]
"semi tone", Int -> Spec
signed Int
12)
    , ([Char]
"fine tune", Int -> Spec
signed Int
50)
    , ([Char]
"frequency offset", Int -> Spec
signed Int
100)
    -- pitch slope
    , ([Char]
"center key", Int -> Spec
unsigned Int
127)
    , ([Char]
"lower slope", Int -> Int -> Spec
ranged (-Int
50) Int
100)
    , ([Char]
"higher slope", Int -> Int -> Spec
ranged (-Int
50) Int
100)
    -- pitch modulation
    , ([Char]
"mod1 source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)
    , ([Char]
"mod1 intensity", Int -> Spec
signed Int
99)
    , ([Char]
"mod1 intensity controller", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)
    , ([Char]
"mod1 intensity controller intensity", Int -> Spec
signed Int
99)
    , ([Char]
"mod2 source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)
    , ([Char]
"mod2 intensity", Int -> Spec
signed Int
99)
    , ([Char]
"wave form", [EnumName] -> Spec
enum [EnumName
"saw", EnumName
"square", EnumName
"triangle", EnumName
"sine"])
    ]

octave :: Spec
octave :: Spec
octave = [EnumName] -> Spec
enum [EnumName
"-2", EnumName
"-1", EnumName
"0", EnumName
"1"] -- 32', 16', 8', 4'

noise_generator_spec :: Specs
noise_generator_spec :: Specs
noise_generator_spec =
    [ ([Char]
"type", [EnumName] -> Spec
enum [EnumName
"thru", EnumName
"lpf", EnumName
"hpf", EnumName
"bpf"])
    , ([Char]
"input trim", Int -> Spec
unsigned Int
99)
    , ([Char]
"cutoff", Int -> Spec
unsigned Int
99)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"cutoff mod1"
    , ([Char]
"cutoff mod1 intensity", Int -> Spec
signed Int
99)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"cutoff mod2"
    , ([Char]
"cutoff mod2 intensity", Int -> Spec
signed Int
99)
    , ([Char]
"resonance", Int -> Spec
unsigned Int
99)
    ]

-- ** osc types

standard_osc :: Specs
standard_osc :: Specs
standard_osc =
    [ ([Char]
"wave", [EnumName] -> Spec
enum [EnumName
"saw", EnumName
"pulse"])
    , ([Char]
"wave edge", Int -> Spec
unsigned Int
99)
    , ([Char]
"wave level", Int -> Spec
unsigned Int
99)
    , ([Char]
"triangle level", Int -> Spec
unsigned Int
99)
    , ([Char]
"sine level", Int -> Spec
unsigned Int
99)
    , ([Char]
"triangle phase shift", Int -> Spec
signed Int
99)
    , ([Char]
"wave form", Specs -> Spec
SubSpec
        [ ([Char]
"wave form", Int -> Spec
signed Int
99)
        , ([Char]
"mod lfo",
            -- TODO For some reason, the range is 6--9, take a look at z1
            [EnumName] -> Spec
enum [EnumName
"", EnumName
"", EnumName
"", EnumName
"", EnumName
"", EnumName
"", EnumName
"lfo1", EnumName
"lfo2", EnumName
"lfo3", EnumName
"lfo4"])
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"lfo"
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
""
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
""
        ])
    , ([Char]
"wave shape", Specs -> Spec
SubSpec
        [ ([Char]
"input level", Int -> Spec
unsigned Int
99)
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"input level"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"input level"
        , ([Char]
"offset", Int -> Spec
signed Int
99)
        , ([Char]
"table", [EnumName] -> Spec
enum [EnumName
"clip", EnumName
"reso"])
        , ([Char]
"wave shape", Int -> Spec
unsigned Int
99)
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
""
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
""
        , ([Char]
"balance", Int -> Spec
unsigned Int
99)
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"balance"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"balance"
        ])
    ]

comb_filter_osc :: Specs
comb_filter_osc :: Specs
comb_filter_osc =
    [ ([Char]
"input select", [EnumName] -> Spec
enum [EnumName
"sc1+noise", EnumName
"subosc+noise", EnumName
"filter1+noise",
        EnumName
"filter2+noise", EnumName
"pulse noise", EnumName
"impulse"])
    , ([Char]
"input wave level", Int -> Spec
unsigned Int
99)
    , ([Char]
"noise level", Int -> Spec
unsigned Int
99)
    , ([Char]
"width", Int -> Spec
unsigned Int
99)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"input level"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"input level"
    , ([Char]
"comb filter feedback", Int -> Spec
unsigned Int
99)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"feedback 1"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"feedback 1"
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"feedback 2"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"feedback 2"
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"high damp"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"high damp"
    ]

-- * mixer

mixer_spec :: Specs
mixer_spec :: Specs
mixer_spec =
    [ [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"osc1 out1", [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"osc1 out2"
    , [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"osc2 out1", [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"osc2 out2"
    , [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"sub osc out1", [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"sub osc out2"
    , [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"noise out1", [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"noise out2"
    , [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"feedback out1", [Char] -> ([Char], Spec)
forall {a}. a -> (a, Spec)
channel [Char]
"feedback out2"
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"osc1 mixer output sw", BitField
bool_bit)
        , ([Char]
"osc2 mixer output sw", BitField
bool_bit)
        , ([Char]
"sub mixer output sw", BitField
bool_bit)
        , ([Char]
"noise mixer output sw", BitField
bool_bit)
        , Int -> ([Char], BitField)
Sysex.unparsed_bits Int
4
        ])
    ]
    where
    channel :: a -> (a, Spec)
channel a
name =
        (a
name, Specs -> Spec
SubSpec
            [ ([Char]
"level", Int -> Spec
unsigned Int
99)
            , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"level"
            , [Char] -> ([Char], Spec)
mod_intensity [Char]
"level"
            ])

-- * filter

filter_common_spec :: Specs
filter_common_spec :: Specs
filter_common_spec =
    [ ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"filter routing", Int -> [EnumName] -> BitField
enum_bits Int
2 [EnumName
"serial1", EnumName
"serial2", EnumName
"parallel"])
        , ([Char]
"filter2 link switch", Int -> [EnumName] -> BitField
enum_bits Int
2 [EnumName
"off", EnumName
"on"])
        , ([Char]
"filter eg knob target", Int -> [EnumName] -> BitField
enum_bits Int
5
            [EnumName
"", EnumName
"filter1", EnumName
"filter2", EnumName
"both"])
        ])
    ]

filter_spec :: Specs
filter_spec :: Specs
filter_spec =
    [ ([Char]
"filter type", [EnumName] -> Spec
enum [EnumName
"", EnumName
"lpf", EnumName
"hpf", EnumName
"bpf", EnumName
"brf", EnumName
"2bpf"])
    , ([Char]
"a", Specs -> Spec
SubSpec (Specs -> Spec) -> Specs -> Spec
forall a b. (a -> b) -> a -> b
$ Specs
filter_common Specs -> Specs -> Specs
forall a. [a] -> [a] -> [a]
++
        [ ([Char]
"cutoff frequency", Specs -> Spec
SubSpec
            [ ([Char]
"mod eg", Spec
egs)
            , [Char] -> ([Char], Spec)
mod_intensity [Char]
"eg"
            , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"1", [Char] -> ([Char], Spec)
mod_intensity [Char]
"1"
            , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"2", [Char] -> ([Char], Spec)
mod_intensity [Char]
"2"
            ])
        -- resonance
        , ([Char]
"resonance", Int -> Spec
unsigned Int
99)
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"resonance"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"resonance"
        ])
    , ([Char]
"b", Specs -> Spec
SubSpec (Specs -> Spec) -> Specs -> Spec
forall a b. (a -> b) -> a -> b
$ Specs
filter_common Specs -> Specs -> Specs
forall a. [a] -> [a] -> [a]
++
        [ ([Char]
"cutoff frequency", Specs -> Spec
SubSpec
            [ [Char] -> ([Char], Spec)
intensity [Char]
"mod eg"
            , [Char] -> ([Char], Spec)
intensity [Char]
"mod1"
            , [Char] -> ([Char], Spec)
intensity [Char]
"mod2"
            ])
        , ([Char]
"resonance", Int -> Spec
unsigned Int
99)
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"resonance mod"
        ])
    ]
    where
    filter_common :: Specs
filter_common =
        [ ([Char]
"input trim", Int -> Spec
unsigned Int
99)
        , ([Char]
"cutoff frequency", Int -> Spec
unsigned Int
99)
        -- cutoff keyboard track
        , ([Char]
"low key", Spec
midi_key), ([Char]
"high key", Spec
midi_key)
        , [Char] -> ([Char], Spec)
intensity [Char]
"lower", [Char] -> ([Char], Spec)
intensity [Char]
"higher"
        ]

egs :: Spec
egs :: Spec
egs = [EnumName] -> Spec
enum [EnumName
"", EnumName
"eg1", EnumName
"eg2", EnumName
"eg3", EnumName
"eg4", EnumName
"amp eg"]
    -- TODO 0 is undocumented but I assume off?  Or invalid?

-- * other

amp_spec :: Specs
amp_spec :: Specs
amp_spec = [Char] -> Int -> Specs -> Specs
assert_valid [Char]
"amp" Int
37
    [ ([Char]
"amp", Int -> Specs -> Spec
List Int
2
        [ ([Char]
"amplitude", Int -> Spec
unsigned Int
99)
        , ([Char]
"low key", Spec
midi_key)
        , ([Char]
"high key", Spec
midi_key)
        , [Char] -> ([Char], Spec)
intensity [Char]
"lower"
        , [Char] -> ([Char], Spec)
intensity [Char]
"higher"
        , ([Char]
"mod eg", Spec
egs)
        , ([Char]
"", Int -> Spec
Unparsed Int
1)
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
""
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
""
        ])
    , ([Char]
"eg", Specs -> Spec
SubSpec
        [ ([Char]
"", Int -> Spec
Unparsed Int
1)
        , [Char] -> ([Char], Spec)
time [Char]
"attack"
        , [Char] -> ([Char], Spec)
level [Char]
"attack"
        , [Char] -> ([Char], Spec)
time [Char]
"decay"
        , [Char] -> ([Char], Spec)
level [Char]
"break"
        , [Char] -> ([Char], Spec)
time [Char]
"slope"
        , [Char] -> ([Char], Spec)
level [Char]
"sustain"
        , [Char] -> ([Char], Spec)
time [Char]
"release"
        , ([Char]
"", Int -> Spec
Unparsed Int
1)
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"eg level"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"eg level"
        , ([Char]
"eg velocity control", Int -> Spec
signed Int
99)
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"eg time"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"eg time"
        , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"eg node time"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"attack time"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"decay time"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"slope time"
        , [Char] -> ([Char], Spec)
mod_intensity [Char]
"release time"
        ])
    ]
    where
    level :: [Char] -> ([Char], Spec)
level [Char]
name = ([Char]
name [Char] -> [Char] -> [Char]
<+> [Char]
"level", Int -> Spec
signed Int
99)
    time :: [Char] -> ([Char], Spec)
time [Char]
name = ([Char]
name [Char] -> [Char] -> [Char]
<+> [Char]
"time", Int -> Spec
unsigned Int
99)

output_spec :: Specs
output_spec :: Specs
output_spec = [Char] -> Int -> Specs -> Specs
assert_valid [Char]
"output" Int
4
    [ ([Char]
"panpot", Int -> Spec
unsigned Int
127)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"panpot"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"panpot"
    , ([Char]
"output", Int -> Spec
unsigned Int
127)
    ]

effect_spec :: Specs
effect_spec :: Specs
effect_spec = [Char] -> Int -> Specs -> Specs
assert_valid [Char]
"effect" Int
72
    [ ([Char]
"effect send", Int -> Spec
unsigned Int
100)
    , [Char] -> ([Char], Spec)
mod_source_1 [Char]
"effect send"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"effect send"
    , ([Char]
"effect1 select", [EnumName] -> Spec
enum [EnumName]
effect_type1)
    , ([Char]
"effect1 setting", Int -> Spec
Unparsed Int
22)
    , ([Char]
"effect2 select", [EnumName] -> Spec
enum [EnumName]
effect_type1)
    , ([Char]
"effect2 setting", Int -> Spec
Unparsed Int
22)
    , ([Char]
"master effect select", [EnumName] -> Spec
enum [EnumName]
master_effect_type)
    , ([Char]
"master effect setting", Int -> Spec
Unparsed Int
18)
    , ([Char]
"eq", Specs -> Spec
SubSpec
        [ ([Char]
"low freq", Spec
freq)
        , ([Char]
"low gain", Spec
gain)
        , ([Char]
"high freq", Spec
freq)
        , ([Char]
"high gain", Spec
gain)
        ])
    ]

controller_spec :: Specs
controller_spec :: Specs
controller_spec = [Char] -> Int -> Specs -> Specs
assert_valid [Char]
"controller" Int
4
    [ ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"sw1 function", Int -> [EnumName] -> BitField
enum_bits Int
7 [EnumName]
sw1_function)
        , ([Char]
"sw1 mode", BitField
latch)
        ])
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"sw2 function", Int -> [EnumName] -> BitField
enum_bits Int
7 [EnumName]
sw2_function)
        , ([Char]
"sw2 mode", BitField
latch)
        ])
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"foot sw function", Int -> [EnumName] -> BitField
enum_bits Int
7 [EnumName]
foot_sw_function)
        , ([Char]
"foot sw mode", BitField
latch)
        ])
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"pedal function", Int -> [EnumName] -> BitField
enum_bits Int
3 [EnumName]
pedal_function)
        , ([Char]
"pad hold", Int -> [EnumName] -> BitField
enum_bits Int
5 [EnumName
"off", EnumName
"on"])
        ])
    ]
    where
    latch :: BitField
latch = Int -> [EnumName] -> BitField
enum_bits Int
1 [EnumName
"latch", EnumName
"unlatch"]
    sw1_function :: [EnumName]
sw1_function =
        [ EnumName
"mod sw 1", EnumName
"master fx", EnumName
"fx1", EnumName
"fx2", EnumName
"octave up", EnumName
"octave down"
        , EnumName
"mono sw", EnumName
"unison"
        ]
    sw2_function :: [EnumName]
sw2_function =
        [ EnumName
"mod sw 2", EnumName
"master fx", EnumName
"fx1", EnumName
"fx2", EnumName
"octave up", EnumName
"octave down"
        , EnumName
"mono sw", EnumName
"unison"
        ]
    foot_sw_function :: [EnumName]
foot_sw_function =
        [ EnumName
"foot sw", EnumName
"midi damper", EnumName
"midi portamento", EnumName
"midi sostenuto"
        , EnumName
"master fx", EnumName
"fx1", EnumName
"fx2", EnumName
"octave up", EnumName
"octave down", EnumName
"mono sw"
        , EnumName
"unison", EnumName
"arpeggio", EnumName
"pad hold"
        ]
    pedal_function :: [EnumName]
pedal_function =
        [ EnumName
"pedal", EnumName
"breath control", EnumName
"portamento time", EnumName
"volume", EnumName
"panpot"
        , EnumName
"expression"
        ]

link_arpeggio_spec :: Int -> Specs
link_arpeggio_spec :: Int -> Specs
link_arpeggio_spec Int
reserved = [Char] -> Int -> Specs -> Specs
assert_valid [Char]
"link arpeggio" (Int
6 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
reserved)
    [ ([Char]
"unparsed", Int -> Spec
Unparsed Int
6) -- TODO
    , ([Char]
"", Int -> Spec
Unparsed Int
reserved)
    ]

pe_knob_spec :: Specs
pe_knob_spec :: Specs
pe_knob_spec = [Char] -> Int -> Specs -> Specs
assert_valid [Char]
"pe knob" Int
16
    [ ([Char]
"p0", Specs -> Spec
SubSpec Specs
knob)
    , ([Char]
"p1", Specs -> Spec
SubSpec Specs
knob)
    , ([Char]
"p2", Specs -> Spec
SubSpec Specs
knob)
    , ([Char]
"p3", Specs -> Spec
SubSpec Specs
knob)
    ]
    where
    knob :: Specs
knob =
        -- TODO
        [ ([Char]
"parameter", [EnumName] -> Spec
enum ([EnumName] -> Spec) -> [EnumName] -> Spec
forall a b. (a -> b) -> a -> b
$ EnumName
"off" EnumName -> [EnumName] -> [EnumName]
forall a. a -> [a] -> [a]
: [EnumName
"unknown " EnumName -> EnumName -> EnumName
forall a. Semigroup a => a -> a -> a
<> Integer -> EnumName
forall a. Show a => a -> EnumName
showt Integer
n | Integer
n <- [Integer
1..Integer
230]])
        , ([Char]
"left value", Spec
percent)
        , ([Char]
"right value", Spec
percent)
        , ([Char]
"curve", [EnumName] -> Spec
enum [EnumName
"linear", EnumName
"exponential", EnumName
"log", EnumName
"sw"])
        ]


-- * multiset

-- | Spec to both parse and generate a multiset dump.
multiset_spec :: Specs
multiset_spec :: Specs
multiset_spec = Config -> [Char] -> Int -> Specs -> Specs
Sysex.assert_valid Config
config [Char]
"multiset_spec" Int
208
    [ ([Char]
"name", Int -> Spec
Str Int
16)
    , ([Char]
"timbre", Int -> Specs -> Spec
List Int
6 Specs
timbre_spec)
    -- effect
    , ([Char]
"effect 1", Specs -> Spec
SubSpec
        [ ([Char]
"select", [EnumName] -> Spec
enum [EnumName]
effect_type1)
        , ([Char]
"setting", Int -> Spec
Unparsed Int
22)
        ])
    , ([Char]
"effect 2", Specs -> Spec
SubSpec
        [ ([Char]
"effect 2 select", [EnumName] -> Spec
enum [EnumName]
effect_type2)
        , ([Char]
"effect 2 setting", Int -> Spec
Unparsed Int
22)
        ])
    , ([Char]
"master effect", Specs -> Spec
SubSpec
        [ ([Char]
"select", [EnumName] -> Spec
enum [EnumName]
master_effect_type)
        , ([Char]
"setting", Int -> Spec
Unparsed Int
18)
        , ([Char]
"low eq freq", Int -> Spec
unsigned Int
49)
        , ([Char]
"low eq gain", Spec
gain)
        , ([Char]
"high eq freq", Int -> Spec
unsigned Int
49)
        , ([Char]
"high eq gain", Spec
gain)
        ])
    -- common
    , ([Char], Spec)
pitch_bend
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"scale key", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName]
scale_keys)
        , ([Char]
"scale type", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName]
scale_types)
        ])
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"portamento sw", BitField
bool_bit)
        , ([Char]
"unison sw", Int -> [EnumName] -> BitField
enum_bits Int
7 [EnumName
"off", EnumName
"on"])
        ])
    , ([Char]
"", Int -> Spec
Unparsed Int
10)
    , ([Char]
"controller", Specs -> Spec
SubSpec Specs
controller_spec)
    , ([Char]
"link arpeggio", Specs -> Spec
SubSpec (Int -> Specs
link_arpeggio_spec Int
2))
    ]

timbre_spec :: Specs
timbre_spec :: Specs
timbre_spec =
    -- timbre
    [ ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"program number", Int -> BitField
bits Int
7)
        , ([Char]
"program bank", Int -> BitField
bits Int
1)
        ])
    , ([Char]
"reserve voice", Int -> Spec
unsigned Int
12)
    -- pitch
    , ([Char]
"transpose", Int -> Int -> Spec
ranged (-Int
24) Int
24)
    , ([Char]
"detune", Int -> Int -> Spec
ranged (-Int
50) Int
50)
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"arpeggiator", (Int
4, [EnumName] -> Range
Sysex.Enum [EnumName
"on", EnumName
"off"]))
        , ([Char]
"scale select", Int -> [EnumName] -> BitField
enum_bits Int
4 [EnumName
"common", EnumName
"program"])
        ])
    -- mixer
    , ([Char]
"output level", Int -> Spec
unsigned Int
128) -- 128 is PROG
    , ([Char]
"panpot", Int -> Spec
unsigned Int
128) -- 128 is PROG
    , ([Char]
"effect send", Int -> Spec
unsigned Int
101) -- 101 is PROG
    -- zone
    , ([Char]
"key zone top", Int -> Spec
unsigned Int
127)
    , ([Char]
"key zone bottom", Int -> Spec
unsigned Int
127)
    , ([Char]
"velocity zone top", Int -> Int -> Spec
ranged Int
1 Int
127)
    , ([Char]
"velocity zone bottom", Int -> Int -> Spec
ranged Int
1 Int
127)
    -- MIDI
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"midi channel", Int -> (Int, Int) -> BitField
ranged_bits Int
7 (Int
0, Int
16)) -- 16 is GLOBAL
        , ([Char]
"program change", BitField
bool_bit)
        ])
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"realtime edit", BitField
bool_bit)
        , ([Char]
"portamento sw", BitField
bool_bit)
        , ([Char]
"damper", BitField
bool_bit)
        , ([Char]
"x-y pad controller", BitField
bool_bit)
        , ([Char]
"modulation wheel", BitField
bool_bit)
        , ([Char]
"after touch", BitField
bool_bit)
        , ([Char]
"pitch bend", Int -> [EnumName] -> BitField
enum_bits Int
2 [EnumName
"off", EnumName
"common", EnumName
"program"])
        ])
    , ([Char]
"", [([Char], BitField)] -> Spec
Bits
        [ ([Char]
"unused", Int -> BitField
bits Int
6)
        , ([Char]
"performance edit", BitField
bool_bit)
        , ([Char]
"others", BitField
bool_bit)
        ])
    , ([Char]
"", Int -> Spec
Unparsed Int
1)
    ]

-- * effects

effect_type2 :: [Sysex.EnumName]
effect_type2 :: [EnumName]
effect_type2 =
    [ EnumName
"overdrive", EnumName
"compressor", EnumName
"parametric eq", EnumName
"wah", EnumName
"exciter"
    , EnumName
"decimator", EnumName
"chorus", EnumName
"flanger", EnumName
"phaser", EnumName
"rotary speaker-small"
    , EnumName
"delay-mono"
    ]

effect_type1 :: [Sysex.EnumName]
effect_type1 :: [EnumName]
effect_type1 = [EnumName]
effect_type2 [EnumName] -> [EnumName] -> [EnumName]
forall a. [a] -> [a] -> [a]
++
    [ EnumName
"talking modulator", EnumName
"multitap delay", EnumName
"ensemble", EnumName
"rotary speaker-large"
    ]

effect_overdrive :: Specs
effect_overdrive :: Specs
effect_overdrive =
    [ ([Char]
"mode", [EnumName] -> Spec
enum [EnumName
"overdrive", EnumName
"distortion"])
    , ([Char]
"drive", Int -> Spec
unsigned Int
99)
    , ([Char]
"output level", Int -> Spec
unsigned Int
99)
    , ([Char]
"pre low cutoff", Int -> Spec
unsigned Int
99)
    , [Char] -> ([Char], Spec)
eq [Char]
"low", [Char] -> ([Char], Spec)
eq [Char]
"mid low", [Char] -> ([Char], Spec)
eq [Char]
"mid high", [Char] -> ([Char], Spec)
eq [Char]
"high"
    , ([Char], Spec)
effect_balance
    ]
    where eq :: [Char] -> ([Char], Spec)
eq [Char]
prefix = ([Char]
prefix [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" eq", Specs -> Spec
SubSpec Specs
eq_settings)

effect_compressor :: Specs
effect_compressor :: Specs
effect_compressor =
    [ ([Char]
"sensitivity", Int -> Int -> Spec
ranged Int
1 Int
99)
    , ([Char]
"attack", Int -> Int -> Spec
ranged Int
1 Int
99)
    , ([Char]
"eq trim", Int -> Spec
unsigned Int
99)
    , ([Char]
"pre low eq gain", Spec
gain)
    , ([Char]
"pre high eq gain", Spec
gain)
    , ([Char]
"output level", Int -> Spec
unsigned Int
99)
    , ([Char], Spec)
effect_balance
    ]

effect_parametric_eq :: Specs
effect_parametric_eq :: Specs
effect_parametric_eq =
    [ ([Char]
"trim", Int -> Spec
unsigned Int
99)
    , ([Char]
"low eq", Specs -> Spec
SubSpec (Specs -> Spec) -> Specs -> Spec
forall a b. (a -> b) -> a -> b
$
        ([Char]
"type", [EnumName] -> Spec
enum [EnumName
"peaking", EnumName
"shelving"]) ([Char], Spec) -> Specs -> Specs
forall a. a -> [a] -> [a]
: Specs
eq_settings)
    , ([Char]
"mid low eq", Specs -> Spec
SubSpec (Specs -> Spec) -> Specs -> Spec
forall a b. (a -> b) -> a -> b
$ Specs
eq_settings Specs -> Specs -> Specs
forall a. [a] -> [a] -> [a]
++
        [ ([Char]
"gain mod source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)
        , ([Char]
"gain mod intensity", Spec
gain)
        ])
    , ([Char]
"mid high eq", Specs -> Spec
SubSpec Specs
eq_settings)
    , ([Char]
"high eq", Specs -> Spec
SubSpec (Specs -> Spec) -> Specs -> Spec
forall a b. (a -> b) -> a -> b
$
        ([Char]
"type", [EnumName] -> Spec
enum [EnumName
"peaking", EnumName
"shelving"]) ([Char], Spec) -> Specs -> Specs
forall a. a -> [a] -> [a]
: Specs
eq_settings)
    , ([Char], Spec)
effect_balance
    ]

effect_wah :: Specs
effect_wah :: Specs
effect_wah =
    [ ([Char]
"frequency bottom", Int -> Spec
unsigned Int
99)
    , ([Char]
"frequency top", Int -> Spec
unsigned Int
99)
    , ([Char]
"sweep mode", [EnumName] -> Spec
enum [EnumName
"auto", EnumName
"mod source"])
    , ([Char]
"sweep source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)
    , ([Char]
"sweep response", Int -> Spec
unsigned Int
99)
    , ([Char]
"envelope sensitivity", Int -> Spec
unsigned Int
99)
    , ([Char]
"envelope shape", Int -> Spec
signed Int
99)
    , ([Char]
"resonance", Int -> Spec
unsigned Int
99)
    , ([Char]
"filter mode", [EnumName] -> Spec
enum [EnumName
"bpf", EnumName
"lpf"])
    , ([Char], Spec)
effect_balance
    ]

effect_exciter :: Specs
effect_exciter :: Specs
effect_exciter =
    [ [Char] -> Spec -> ([Char], Spec)
mod_source_intensity [Char]
"blend" (Int -> Spec
signed Int
99)
    , [Char] -> Spec -> ([Char], Spec)
mod_source_intensity [Char]
"emphatic point" (Int -> Spec
signed Int
99)
    , ([Char]
"pre eq input trim", Int -> Spec
unsigned Int
99)
    , ([Char]
"pre low eq gain", Spec
gain)
    , ([Char]
"pre high eq gain", Spec
gain)
    , ([Char], Spec)
effect_balance
    ]

effect_decimator :: Specs
effect_decimator :: Specs
effect_decimator =
    [ ([Char]
"pre lpf", Spec
bool)
    , ([Char]
"sampling frequency", Int -> Int -> Spec
ranged Int
5 Int
120) -- 1.0k~24.0kHz
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"sampling frequency"
    -- Different from other intensities!
    , ([Char]
"sampling frequency mod intensity", Int -> Spec
signed Int
120) -- -24.0k~+24.0kHz
    , ([Char]
"resolution", Int -> Int -> Spec
ranged Int
4 Int
24)
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"output level", Int -> Spec
unsigned Int
99)
    , ([Char], Spec)
effect_balance
    ]

effect_chorus :: Specs
effect_chorus :: Specs
effect_chorus =
    [ ([Char]
"delay time", Int -> Spec
unsigned Int
140) -- 0-50 msec
    , ([Char]
"lfo wave form", [EnumName] -> Spec
enum [EnumName
"triangle", EnumName
"sine"])
    , ([Char]
"lfo frequency", Int -> Int -> Spec
ranged Int
1 Int
115) -- 00.04~20.00Hz
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"lfo frequency"
    , ([Char]
"lfo frequency mod intensity", Int -> Spec
signed Int
115) -- -20.00~+20.00Hz
    , ([Char], Spec)
midi_sync
    , [Char] -> Spec -> ([Char], Spec)
mod_source_intensity [Char]
"depth" (Int -> Spec
unsigned Int
99)
    , ([Char]
"pre eq input trim", Int -> Spec
unsigned Int
99)
    , ([Char]
"pre low eq gain", Spec
gain)
    , ([Char]
"pre high eq gain", Spec
gain)
    , ([Char], Spec)
effect_balance
    ]

effect_flanger :: Specs
effect_flanger :: Specs
effect_flanger =
    [ ([Char]
"delay time", Int -> Spec
unsigned Int
140) -- 0.0~50.0msec
    , ([Char]
"lfo", Specs -> Spec
SubSpec
        [ ([Char]
"wave form", [EnumName] -> Spec
enum [EnumName
"triangle", EnumName
"sine"])
        , ([Char]
"shape", Int -> Spec
signed Int
99)
        , ([Char]
"frequency", Int -> Int -> Spec
ranged Int
1 Int
115) -- 00.04~20.00Hz
        , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"frequency"
        , ([Char]
"frequency mod intensity", Int -> Spec
signed Int
115)
        ])
    , ([Char], Spec)
midi_sync
    , ([Char]
"depth", Int -> Spec
unsigned Int
99)
    , ([Char]
"feedback", Int -> Spec
signed Int
99)
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"output phase", [EnumName] -> Spec
enum [EnumName
"+", EnumName
"-", EnumName
"+-"])
    , ([Char], Spec)
effect_balance
    ]

effect_phaser :: Specs
effect_phaser :: Specs
effect_phaser =
    [ ([Char]
"lfo", Specs -> Spec
SubSpec
        [ ([Char]
"wave form", [EnumName] -> Spec
enum [EnumName
"triangle", EnumName
"sine"])
        , ([Char]
"shape", Int -> Spec
signed Int
99)
        , ([Char]
"frequency", Int -> Int -> Spec
ranged Int
1 Int
115) -- 00.04~20.00Hz
        , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"frequency"
        , ([Char]
"frequency mod intensity", Int -> Spec
signed Int
115)
        ])
    , ([Char], Spec)
midi_sync
    , ([Char]
"manual", Int -> Spec
unsigned Int
99)
    , ([Char]
"depth", Int -> Spec
unsigned Int
99)
    , ([Char]
"resonance", Int -> Spec
signed Int
99)
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"output phase", [EnumName] -> Spec
enum [EnumName
"+", EnumName
"-", EnumName
"+-"])
    , ([Char], Spec)
effect_balance
    ]

effect_small_rotary_speaker :: Specs
effect_small_rotary_speaker :: Specs
effect_small_rotary_speaker =
    [ ([Char]
"speed", [EnumName] -> Spec
enum [EnumName
"slow", EnumName
"fast"])
    , ([Char]
"speed sw", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)
    , ([Char]
"horn acceleration", Int -> Spec
unsigned Int
99)
    , ([Char]
"horn rate", Int -> Spec
unsigned Int
99)
    , ([Char]
"mic distance", Int -> Spec
unsigned Int
99)
    , ([Char]
"horn / rotor balance", Int -> Spec
unsigned Int
99)
    , ([Char], Spec)
effect_balance
    ]

effect_delay :: Specs
effect_delay :: Specs
effect_delay =
    [ [Char] -> ([Char], Spec)
mod_source_2 [Char]
"input level"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"input level"
    , ([Char]
"delay time", Spec
delay_time)
    , ([Char]
"feedback", Int -> Spec
signed Int
99)
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"feedback"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"feedback"
    , ([Char]
"low damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , ([Char], Spec)
effect_balance
    ]

effect_talking_modulator :: Specs
effect_talking_modulator :: Specs
effect_talking_modulator =
    [ ([Char]
"control mode", [EnumName] -> Spec
enum [EnumName
"manual", EnumName
"mod source"])
    , ([Char]
"manual control", Int -> Spec
unsigned Int
99)
    , ([Char]
"control source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)
    , ([Char]
"voice top", [EnumName] -> Spec
enum [EnumName
"a", EnumName
"i", EnumName
"u", EnumName
"e", EnumName
"o"])
    , ([Char]
"voice center", [EnumName] -> Spec
enum [EnumName
"a", EnumName
"i", EnumName
"u", EnumName
"e", EnumName
"o"])
    , ([Char]
"voice bottom", [EnumName] -> Spec
enum [EnumName
"a", EnumName
"i", EnumName
"u", EnumName
"e", EnumName
"o"])
    , ([Char]
"formant shift", Int -> Spec
signed Int
99)
    , ([Char]
"resonance", Int -> Spec
unsigned Int
99)
    , ([Char], Spec)
effect_balance
    ]

effect_multitap_delay :: Specs
effect_multitap_delay :: Specs
effect_multitap_delay =
    [ ([Char]
"type", [EnumName] -> Spec
enum [EnumName
"normal", EnumName
"cross1", EnumName
"cross2", EnumName
"pan1", EnumName
"pan2"])
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"input level"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"input level"
    , ([Char]
"tap1 time", Spec
delay_time)
    , ([Char]
"tap1 level", Int -> Spec
unsigned Int
99)
    , ([Char]
"tap2 time", Spec
delay_time)
    , ([Char]
"tap2 level", Int -> Spec
unsigned Int
99)
    , ([Char]
"feedback", Int -> Spec
signed Int
99)
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"feedback"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"feedback"
    , ([Char]
"low damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"spread", Int -> Spec
signed Int
99)
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"spread"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"spread"
    , ([Char], Spec)
effect_balance
    ]

effect_ensemble :: Specs
effect_ensemble :: Specs
effect_ensemble =
    [ ([Char]
"speed", Int -> Spec
unsigned Int
99)
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"speed"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"speed"
    , ([Char]
"shimmer", Int -> Spec
unsigned Int
99)
    , ([Char]
"depth", Int -> Spec
unsigned Int
99)
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"depth"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"depth"
    , ([Char], Spec)
effect_balance
    ]

effect_rotary_speaker :: Specs
effect_rotary_speaker :: Specs
effect_rotary_speaker =
    [ ([Char]
"speed", [EnumName] -> Spec
enum [EnumName
"slow", EnumName
"fast"])
    , ([Char]
"speed sw", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)
    , ([Char]
"mode", [EnumName] -> Spec
enum [EnumName
"rotate", EnumName
"stop"])
    , ([Char]
"mode sw", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)
    , ([Char]
"rotor acceleration", Int -> Spec
unsigned Int
99)
    , ([Char]
"rotor rate", Int -> Spec
unsigned Int
99)
    , ([Char]
"horn acceleration", Int -> Spec
unsigned Int
99)
    , ([Char]
"horn rate", Int -> Spec
unsigned Int
99)
    , ([Char]
"mic distance", Int -> Spec
unsigned Int
99)
    , ([Char]
"mic spread", Int -> Spec
unsigned Int
99)
    , ([Char]
"horn / rotor balance", Int -> Spec
unsigned Int
99)
    , ([Char], Spec)
effect_balance
    ]

-- * master effects

effect_stereo_delay :: Specs
effect_stereo_delay :: Specs
effect_stereo_delay =
    [ ([Char]
"type", [EnumName] -> Spec
enum [EnumName
"stereo", EnumName
"cross"])
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"input level"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"input level"
    , ([Char]
"left delay time", Spec
delay_time)
    , ([Char]
"right delay time", Spec
delay_time)
    , ([Char]
"feedback l", Int -> Spec
signed Int
99)
    , ([Char]
"feedback r", Int -> Spec
signed Int
99)
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
"feedback"
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
"feedback"
    , ([Char]
"low damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , ([Char], Spec)
effect_balance
    ]

effect_reverb_hall :: Specs
effect_reverb_hall :: Specs
effect_reverb_hall =
    [ ([Char]
"reverb time", Int -> Int -> Spec
ranged Int
1 Int
100) -- 0.1~10.0sec
    , ([Char]
"pre delay", Int -> Spec
unsigned Int
200) -- msec
    , ([Char]
"pre delay thru level", Int -> Spec
unsigned Int
99)
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"pre eq trim", Int -> Spec
unsigned Int
99)
    , ([Char]
"pre low eq gain", Spec
gain)
    , ([Char]
"pre high eq gain", Spec
gain)
    , ([Char], Spec)
effect_balance
    ]

effect_reverb_room :: Specs
effect_reverb_room :: Specs
effect_reverb_room =
    [ ([Char]
"reverb time", Int -> Int -> Spec
ranged Int
1 Int
30) -- 0.1~3.0sec
    , ([Char]
"pre delay", Int -> Spec
unsigned Int
200) -- msec
    , ([Char]
"pre delay thru level", Int -> Spec
unsigned Int
99)
    , ([Char]
"high damp", Int -> Spec
unsigned Int
99)
    , ([Char]
"er level", Int -> Spec
unsigned Int
99)
    , ([Char]
"reverb level", Int -> Spec
unsigned Int
99)
    , ([Char]
"pre eq trim", Int -> Spec
unsigned Int
99)
    , ([Char]
"pre low eq gain", Spec
gain)
    , ([Char]
"pre high eq gain", Spec
gain)
    ]

delay_time :: Spec
delay_time :: Spec
delay_time = Int -> Spec
unsigned Int
251 -- 0~680msec

-- * util

eq_settings :: Specs
eq_settings :: Specs
eq_settings = [([Char]
"freq", Spec
freq), ([Char]
"q", Int -> Spec
unsigned Int
95), ([Char]
"gain", Spec
gain)]

mod_source_intensity :: String -> Spec -> (String, Spec)
mod_source_intensity :: [Char] -> Spec -> ([Char], Spec)
mod_source_intensity [Char]
name Spec
range = ([Char]
name, Specs -> Spec
SubSpec
    [ ([Char]
"val", Spec
range)
    , [Char] -> ([Char], Spec)
mod_source_2 [Char]
name
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
name
    ])

midi_sync :: (Sysex.Name, Spec)
midi_sync :: ([Char], Spec)
midi_sync = ([Char]
"midi sync", [([Char], BitField)] -> Spec
Bits
    [ ([Char]
"time", Int -> (Int, Int) -> BitField
ranged_bits Int
4 (Int
0, Int
15))
    , ([Char]
"base", Int -> (Int, Int) -> BitField
ranged_bits Int
3 (Int
0, Int
7)) -- 16th to whole
    , ([Char]
"val", BitField
bool_bit)
    ])

midi_key :: Spec
midi_key :: Spec
midi_key = Int -> Spec
unsigned Int
127

mod_source_1 :: String -> (String, Spec)
mod_source_1 :: [Char] -> ([Char], Spec)
mod_source_1 [Char]
name = ([Char]
name [Char] -> [Char] -> [Char]
<+> [Char]
"mod source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_1)

mod_source_2 :: String -> (String, Spec)
mod_source_2 :: [Char] -> ([Char], Spec)
mod_source_2 [Char]
name = ([Char]
name [Char] -> [Char] -> [Char]
<+> [Char]
"mod source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)

intensity :: String -> (String, Spec)
intensity :: [Char] -> ([Char], Spec)
intensity [Char]
name = ([Char]
name [Char] -> [Char] -> [Char]
<+> [Char]
"intensity", Int -> Spec
signed Int
99)

mod_intensity :: String -> (String, Spec)
mod_intensity :: [Char] -> ([Char], Spec)
mod_intensity [Char]
name = ([Char]
name [Char] -> [Char] -> [Char]
<+> [Char]
"mod intensity", Int -> Spec
signed Int
99)

(<+>) :: String -> String -> String
[Char]
x <+> :: [Char] -> [Char] -> [Char]
<+> [Char]
y
    | [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
x = [Char]
y
    | [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
y = [Char]
x
    | Bool
otherwise = [Char]
x [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
y

-- | Gain in dB.
gain :: Spec
gain :: Spec
gain = Int -> Int -> Spec
ranged (-Int
36) Int
36

bool :: Spec
bool :: Spec
bool = [EnumName] -> Spec
enum [EnumName
"off", EnumName
"on"]

-- | Frequency in Hz.
freq :: Spec
freq :: Spec
freq = Int -> Spec
unsigned Int
49

effect_balance :: (Sysex.Name, Spec)
effect_balance :: ([Char], Spec)
effect_balance = ([Char]
"effect balance", Specs -> Spec
SubSpec
    [ ([Char]
"balance", Spec
percent)
    , ([Char]
"mod source", [EnumName] -> Spec
enum [EnumName]
mod_source_list_2)
    , [Char] -> ([Char], Spec)
mod_intensity [Char]
""
    ])

percent :: Spec
percent :: Spec
percent = Int -> Spec
unsigned Int
100

-- | TODO like mod_source_list_1 except entries 1--10 are invalid.
mod_source_list_2 :: [Sysex.EnumName]
mod_source_list_2 :: [EnumName]
mod_source_list_2 = [EnumName]
mod_source_list_1

mod_source_list_1 :: [Sysex.EnumName]
mod_source_list_1 :: [EnumName]
mod_source_list_1 =
    [ EnumName
"off"
    , EnumName
"eg1", EnumName
"eg2", EnumName
"eg3", EnumName
"eg4"
    , EnumName
"amp eg"
    , EnumName
"lfo1", EnumName
"lfo2", EnumName
"lfo3", EnumName
"lfo4"
    , EnumName
"portamento"
    , EnumName
"note [linear]", EnumName
"note [exp]"
    , EnumName
"note split [high]", EnumName
"note split [low]"
    , EnumName
"velocity [soft]", EnumName
"velocity [medium]", EnumName
"velocity [hard]"
    , EnumName
"pitch bend"
    , EnumName
"after touch"
    , EnumName
"modulation wheel (cc#1)"
    , EnumName
"atouch + mod.wheel"
    , EnumName
"athalf + mod.wheel"
    , EnumName
"x [+/-] (cc#16)", EnumName
"x [+] (cc#16)", EnumName
"x [-] (cc#16)"
    , EnumName
"y [+/-] (cc#17)", EnumName
"y [+] (cc#17)", EnumName
"y [-] (cc#17)"
    , EnumName
"knob1 (cc#19)", EnumName
"knob2 (cc#20)", EnumName
"knob3 (cc#21)", EnumName
"knob4 (cc#22)"
    , EnumName
"knob5 (cc#23)"
    , EnumName
"mod.sw1 (cc#80)", EnumName
"mod.sw2 (cc#81)"
    , EnumName
"foot sw (cc#82)"
    , EnumName
"foot pedal (cc#4)"
    , EnumName
"damper (cc#64)"
    , EnumName
"sostenuto (cc#66)"
    , EnumName
"midi breath control (cc#2)"
    , EnumName
"midi volume (cc#7)"
    , EnumName
"midi panpot (cc#10)"
    , EnumName
"midi expression (cc#11)"
    , EnumName
"midi portamento time (cc#5)"
    , EnumName
"midi portamento sw (cc#65)"
    , EnumName
"master fx off/on (cc#92)"
    , EnumName
"fx1 off/on (cc#94)", EnumName
"fx2 off/on (cc#95)"
    ]

master_effect_type :: [Sysex.EnumName]
master_effect_type :: [EnumName]
master_effect_type = [EnumName
"stereo delay", EnumName
"reverb-hall", EnumName
"reverb-room"]