-- | module Music.Theory.Braille where import Data.Char {- base -} import Data.List {- base -} import Data.Maybe {- base -} import Text.Printf {- base -} -- | Braille coding data. Elements are: (ASCII HEX,ASCII CHAR,DOT -- LIST,UNICODE CHAR,MEANING). The dot numbers are in column order. type BRAILLE = (Int,Char,[Int],Char,String) -- | ASCII 'Char' of 'BRAILLE'. braille_ascii :: BRAILLE -> Char braille_ascii (_,c,_,_,_) = c -- | Unicode 'Char' of 'BRAILLE'. braille_unicode :: BRAILLE -> Char braille_unicode (_,_,_,c,_) = c -- | Dot list of 'BRAILLE'. braille_dots :: BRAILLE -> [Int] braille_dots (_,_,d,_,_) = d -- | ASCII Braille table. -- -- > all id (map (\(x,c,_,_,_) -> x == fromEnum c) braille_table) == True braille_table :: [BRAILLE] braille_table = [(0x20,' ',[],'⠀'," ") ,(0x21,'!',[2,3,4,6],'⠮',"the") ,(0x22,'"',[5],'⠐',"contraction") ,(0x23,'#',[3,4,5,6],'⠼',"number prefix") ,(0x24,'$',[1,2,4,6],'⠫',"ed") ,(0x25,'%',[1,4,6],'⠩',"sh") ,(0x26,'&',[1,2,3,4,6],'⠯',"and") ,(0x27,'\'',[3],'⠄',"'") ,(0x28,'(',[1,2,3,5,6],'⠷',"of") ,(0x29,')',[2,3,4,5,6],'⠾',"with") ,(0x2A,'*',[1,6],'⠡',"ch") ,(0x2B,'+',[3,4,6],'⠬',"ing") ,(0x2C,',',[6],'⠠',"uppercase prefix") ,(0x2D,'-',[3,6],'⠤',"-") ,(0x2E,'.',[4,6],'⠨',"italic prefix") ,(0x2F,'/',[3,4],'⠌',"st") ,(0x30,'0',[3,5,6],'⠴',"”") ,(0x31,'1',[2],'⠂',",") ,(0x32,'2',[2,3],'⠆',";") ,(0x33,'3',[2,5],'⠒',":") ,(0x34,'4',[2,5,6],'⠲',".") ,(0x35,'5',[2,6],'⠢',"en") ,(0x36,'6',[2,3,5],'⠖',"!") ,(0x37,'7',[2,3,5,6],'⠶',"( or )") ,(0x38,'8',[2,3,6],'⠦',"“ or ?") ,(0x39,'9',[3,5],'⠔',"in") ,(0x3A,':',[1,5,6],'⠱',"wh") ,(0x3B,';',[5,6],'⠰',"letter prefix") ,(0x3C,'<',[1,2,6],'⠣',"gh") ,(0x3D,'=',[1,2,3,4,5,6],'⠿',"for") ,(0x3E,'>',[3,4,5],'⠜',"ar") ,(0x3F,'?',[1,4,5,6],'⠹',"th") ,(0x40,'@',[4],'⠈',"accent prefix") ,(0x41,'A',[1],'⠁',"a") ,(0x42,'B',[1,2],'⠃',"b") ,(0x43,'C',[1,4],'⠉',"c") ,(0x44,'D',[1,4,5],'⠙',"d") ,(0x45,'E',[1,5],'⠑',"e") ,(0x46,'F',[1,2,4],'⠋',"f") ,(0x47,'G',[1,2,4,5],'⠛',"g") ,(0x48,'H',[1,2,5],'⠓',"h") ,(0x49,'I',[2,4],'⠊',"i") ,(0x4A,'J',[2,4,5],'⠚',"j") ,(0x4B,'K',[1,3],'⠅',"k") ,(0x4C,'L',[1,2,3],'⠇',"l") ,(0x4D,'M',[1,3,4],'⠍',"m") ,(0x4E,'N',[1,3,4,5],'⠝',"n") ,(0x4F,'O',[1,3,5],'⠕',"o") ,(0x50,'P',[1,2,3,4],'⠏',"p") ,(0x51,'Q',[1,2,3,4,5],'⠟',"q") ,(0x52,'R',[1,2,3,5],'⠗',"r") ,(0x53,'S',[2,3,4],'⠎',"s") ,(0x54,'T',[2,3,4,5],'⠞',"t") ,(0x55,'U',[1,3,6],'⠥',"u") ,(0x56,'V',[1,2,3,6],'⠧',"v") ,(0x57,'W',[2,4,5,6],'⠺',"w") ,(0x58,'X',[1,3,4,6],'⠭',"x") ,(0x59,'Y',[1,3,4,5,6],'⠽',"y") ,(0x5A,'Z',[1,3,5,6],'⠵',"z") ,(0x5B,'[',[2,4,6],'⠪',"ow") ,(0x5C,'\\',[1,2,5,6],'⠳',"ou") ,(0x5D,']',[1,2,4,5,6],'⠻',"er") ,(0x5E,'^',[4,5],'⠘',"currency prefix") ,(0x5F,'_',[4,5,6],'⠸',"contraction") ] -- | Lookup 'BRAILLE' value for unicode character. -- -- > braille_lookup_unicode '⠝' == Just (0x4E,'N',[1,3,4,5],'⠝',"n") braille_lookup_unicode :: Char -> Maybe BRAILLE braille_lookup_unicode c = find ((== c) . braille_unicode) braille_table -- | Lookup 'BRAILLE' value for ascii character (case invariant). -- -- > braille_lookup_ascii 'N' == Just (0x4E,'N',[1,3,4,5],'⠝',"n") braille_lookup_ascii :: Char -> Maybe BRAILLE braille_lookup_ascii c = find ((== (toUpper c)) . braille_ascii) braille_table -- | The arrangement of the 6-dot patterns into /decades/, sequences -- of (1,10,3) cells. The cell to the left of the decade is the empty -- cell, the two cells to the right are the first two cells of the -- decade shifted right. -- -- For each decade there are two extra cells that shift -- the first two cells of the decade right one place. Subsequent -- decades are derived by simple transformation of the first. The -- second is the first with the addition of dot @3@, the third adds -- dots @3@ and @6@, the fourth adds dot @6@ and the fifth shifts the -- first down one row. -- -- The first decade has the 13 of the 16 4-dot patterns, the remaining -- 3 are in the fifth decade, that is they are the three 4-dot -- patterns that are down shifts of a 4-dot pattern. -- -- > let trimap f (p,q,r) = (f p,f q,f r) -- > let f = map (fromJust . decode) in map (trimap f) braille_64 braille_64 :: [(String,String,String)] braille_64 = [("⠀","⠁⠃⠉⠙⠑⠋⠛⠓⠊⠚","⠈⠘") ,("⠄","⠅⠇⠍⠝⠕⠏⠟⠗⠎⠞","⠌⠜") ,("⠤","⠥⠧⠭⠽⠵⠯⠿⠷⠮⠾","⠬⠼") ,("⠠","⠡⠣⠩⠹⠱⠫⠻⠳⠪⠺","⠨⠸") ,("","⠂⠆⠒⠲⠢⠖⠶⠦⠔⠴","⠐⠰")] -- | Transcribe ASCII to unicode braille. -- -- > transcribe_unicode "BRAILLE ASCII CHAR GRID" == "⠃⠗⠁⠊⠇⠇⠑⠀⠁⠎⠉⠊⠊⠀⠉⠓⠁⠗⠀⠛⠗⠊⠙" -- > transcribe_unicode "BRAILLE HTML TABLE GRID" == "⠃⠗⠁⠊⠇⠇⠑⠀⠓⠞⠍⠇⠀⠞⠁⠃⠇⠑⠀⠛⠗⠊⠙" transcribe_unicode :: String -> String transcribe_unicode = map (braille_unicode . fromJust . braille_lookup_ascii) -- | Generate a character grid using inidicated values for filled and empty cells. -- -- > let ch = (' ','.') -- > putStrLn$ transcribe_char_grid ch "BRAILLE ASCII CHAR GRID" -- -- > let ch = (white_circle,black_circle) -- > putStrLn$ string_html_table $ transcribe_char_grid ch "BRAILLE HTML TABLE GRID" transcribe_char_grid :: (Char,Char) -> String -> String transcribe_char_grid (w,b) = unlines . map concat . transpose . map (dots_grid (w,b) . braille_dots . fromJust . braille_lookup_ascii) -- | Generate 6-dot grid given (white,black) values. -- -- > dots_grid (0,1) [1,2,3,5] == [[1,0],[1,1],[1,0]] dots_grid :: (c,c) -> [Int] -> [[c]] dots_grid (w,b) d = let f n = if n `elem` d then b else w in map (map f) [[1,4],[2,5],[3,6]] string_html_table :: String -> String string_html_table s = let f x = "" ++ [x] ++ "" g x = "" ++ concatMap f x ++ "" h x = "" ++ concatMap g x ++ "
" in h (lines s) {- | Decoding. > let t0 = ["⠠⠁⠇⠇⠀⠓⠥⠍⠁⠝⠀⠆⠬⠎⠀⠜⠑⠀⠃⠕⠗⠝⠀⠋⠗⠑⠑⠀⠯⠀⠑⠟⠥⠁⠇⠀⠔⠀⠙⠊⠛⠝⠰⠽⠀⠯⠀⠐⠗⠎⠲" > ,"⠠⠮⠽⠀⠜⠑⠀⠢⠙⠪⠫⠀⠾⠀⠗⠂⠎⠕⠝⠀⠯⠀⠒⠎⠉⠊⠰⠑⠀⠯⠀⠩⠙⠀⠁⠉⠞⠀⠞⠪⠜⠙⠎⠀⠐⠕⠀⠁⠝⠕⠤" > ,"⠮⠗⠀⠔⠀⠁⠀⠸⠎⠀⠷⠀⠃⠗⠕⠮⠗⠓⠕⠕⠙⠲"] > concatMap (fromMaybe "#" . decode) (concat t0) -} decode :: Char -> Maybe String decode c = case braille_lookup_unicode c of Just (_,_,_,_,s) -> Just s Nothing -> Nothing -- | Start and end unicode indices. braille_rng :: Integral i => (i,i) braille_rng = (0x2800,0x28FF) -- | All characters, in sequence. -- -- > length braille_seq == 256 -- > putStrLn braille_seq braille_seq :: [Char] braille_seq = let (l,r) = braille_rng in [toEnum l .. toEnum r] -- | The /n/th character, zero indexed. braille_char :: Int -> Char braille_char = toEnum . (+) 0x2800 -- | Two element index, 255 * 255 = 65025 places. -- -- > map braille_ix [100,300] braille_ix :: Int -> (Char,Char) braille_ix n = let (i,j) = n `divMod` 255 f k = braille_char (k + 1) in (f i,f j) -- | HTML character encoding (as hex integer). -- -- > unwords $ map unicode_html braille_seq unicode_html :: Char -> String unicode_html = printf "&#x%x;" . fromEnum -- * Unicode -- | White (empty) circle. white_circle :: Char white_circle = '○' -- | Black (filled) circle. black_circle :: Char black_circle = '●' -- | Shaded (hatched) circle. shaded_circle :: Char shaded_circle = '◍' -- * Contractions -- | Table of one letter contractions. one_letter_contractions :: [(Char,String)] one_letter_contractions = [('⠃',"but") ,('⠉',"can") ,('⠙',"do") ,('⠑',"every") ,('⠋',"from,-self") ,('⠛',"go") ,('⠓',"have") ,('⠚',"just") ,('⠅',"knowledge") ,('⠇',"like") ,('⠍',"more") ,('⠝',"not") ,('⠏',"people") ,('⠟',"quite") ,('⠗',"rather") ,('⠎',"so") ,('⠞',"that") ,('⠌',"still") ,('⠥',"us") ,('⠧',"very") ,('⠭',"it") ,('⠽',"you") ,('⠵',"as") ,('⠡',"child") ,('⠩',"shall") ,('⠹',"this") ,('⠱',"which") ,('⠳',"out") ,('⠺',"will") ,('⠆',"be,be-") ,('⠒',"con-") ,('⠲',"dis-") ,('⠢',"enough") ,('⠖',"to") ,('⠶',"were") ,('⠦',"his") ,('⠔',"in") ,('⠴',"by,was") ,('⠤',"com-") ]