diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e7ef40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# seq2audio output +tools/*.wav +tools/*.filelist + +# except the input files +!tools/1.wav +!tools/2.wav +!tools/3.wav +!tools/4.wav +!tools/5.wav +!tools/6.wav +!tools/7.wav +!tools/8.wav +!tools/9.wav +!tools/0.wav +!tools/Star.wav +!tools/Octothorpe.wav +!tools/skip.wav + +# TeX output +*.aux +*.fdb_latexmk +*.fls +*.log +*.toc +*.xdv +*.pdf +*.synctex.gz + +# Haskell outputs +dist-newstyle diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..827404d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "grammar/nguhslides"] + path = grammar/nguhslides + url = git@github.com:Agma-Schwa/nguhslides.git diff --git a/README.md b/README.md index e69de29..c717bce 100644 --- a/README.md +++ b/README.md @@ -0,0 +1 @@ +Submission for the 3rd annual Cursed Conlang Circus diff --git a/grammar/main.tex b/grammar/main.tex new file mode 100644 index 0000000..9808f44 --- /dev/null +++ b/grammar/main.tex @@ -0,0 +1,239 @@ +%! TeX Root: main.tex +% vim: set et tw=80 ts=4 sw=4: +\documentclass{article} +\usepackage{fontspec} +\setmainfont{Andika}[StylisticSet=13] +\setsansfont{Minion 3}[Scale=MatchUppercase] +\setmonofont{Iosevka}[ + Scale=MatchUppercase, + CharacterVariant={99:8} +] +\usepackage[margin=25mm]{geometry} +\usepackage{nguhgloss} +\let\nf\normalfont +\def\z#1{\texttt{#1}} +\def\Clong{\z{811\#0*034C534*4\#C004-*\#3*75} } +\title{\Clong\\{\large A CCC3 Submission}} +\author{Annwan} +\date{2024} + +\setlength\parskip{1ex} +\setlength\parindent{0ex} + +\begin{document} +\maketitle +% \tableofcontents +\section{Presentation} + +\Clong is the language of telephone exchanges + +\section{Phone-ology} + +Telephone exchanges cannot speak like humans do. Instead, \Clong uses DTMF +Keypad Tones to convey information. + +Here is a table of DTMF tones for reference. + +\begin{center} + \begin{tabular}{c|cccc} + & \bf 1209 Hz & \bf 1336 Hz & \bf 1477 Hz & \bf 1633 Hz \\\hline + \bf 697 Hz & \z 1 & \z 2 & \z 3 & \z A \\ + \bf 770 Hz & \z 4 & \z 5 & \z 6 & \z B \\ + \bf 852 Hz & \z 7 & \z 8 & \z 9 & \z C \\ + \bf 941 Hz & \z * & \z 0 & \z \# & \z D + \end{tabular} +\end{center} + + + +\section{Units of meaning -- Packets} + +Semantic information is encoded into packets. A packet can be of 5 types: {\bf +Semantic}, {\bf Proper Noun}, {\bf Syntactic}, {\bf Continuation} and {\bf +Variable}. A packet is a sequences of coniguous tones surrounded by blanks. +additionally individual packets have a maximal length of 20 tones. If a +packet's information would exceed that length limit, the extra data shall be +included in one or more continuation packets. + +\subsection{Semantic Packet} + +A semantic packet is a packet encoding a concept. It uses the Universal Decimal +Clasification to encode the topics. Numeric values are encoded with their +appropriate digit, dots are encoded with \z*, slashes are encoded with \z A. +dashes are encoded with \z{BA}, equals with \z{BB}, column with \z C and quotes +with \z D and parens with \z\#. This has the side effect that semantic packets +cannot start with \z*. + +A reference to a variable (see \ref{variables}) starts with \z{B*} and ends with +\z{B\#}. The variable prefix is omitted in that use. + +\newpage +\subsection{Proper Nouns} + +A proper noun packet is encoded as follows: +\begin{enumerate} +\item Two Stars (\z{**}) +\item The length of the encoding of the proper noun in tones, expressed as an +hexadecimal digit where \z* stands for 14, \z\# stands for 15 and \z0 +stands for 16. +\item the proper noun encoded according to EBCDIC page 00803 in hexadecimal +where \z* stands for 0xE and \z\# stands for 0xF. +\end{enumerate} +If the noun exceeds 16 tones (8 bytes) when encoded, one shall use continuation +packets. + +If the noun cannot be fully encoded into EBCDIC 00803 it shall be expressed +as a sequences of hexadecimal unicode codepoints of the form U+xxxxxxxx in +normalised decomposed form then subsequently encoded to EBCDIC page 00803 + +A proper noun must be followed by a semantic packet qualifying the nature of +the entity described by the proper noun. + +\subsection{Syntactic Packet} + +Syntactic Packets start with a \z* followed by one or more digit or letters. If +they take parameters those are expressed after the Syntactic packet in the order +specified. They are of two kinds: + +\subsubsection {Morphological packets} There exists 5 such packets. They encode +the gramatical role of parameters in the sentence. + +\begin{description} +\item[Assertive \z{*1}] takes one argument and produces the clause that +asserts that the postulate is true, or that the object exists +\item[Intransitive \z{*2A}] takes two arguments and produces the clause with +the first argument as Agent and the second argument as Verb +\item[Intransitive Passive \z{*2B}] takes two arguments and produces the +clause with the first argument as Patient and the second argument as Verb +\item[Transitive \z{*3}] takes three arguments and produces the clause with the +first argument as Subject, the sencond argument as Object, and the third +argument as Verb. For an equivalent of a passive construction, simply reverse +the arguments +\item[Ditransitive \z{*4}] takes four arguments and produces the clause with +the first argument as Subject, the second as Object, the third as Beneficiary +and the fourth as Verb. +\item[Collectionaliser \z{*C}] takes two constructs and forms the collection of + those constructs. For larger collections, one instance of the + collectionaliser is required per element. While the order is not + gramatically mandated, it is common to emit all the collectionalisers of a + group at the start, then list the elements. +\end{description} + +\subsubsection{Referential Packets} +\begin{description} + \item[Proper Noun Qualifier \z{*D}] Proper nouns cannot be used on their + own, instead they must be qualified by:LL: the type of {\it thing} refered + to by the proper noun. For that one uses this qualifer. Takes a proper + noun and a common noun and produces the a reference to the {\it thing} + described by the common noun refered to by the proper noun. + \item[Variable Definition Packet \z{*0}] takes a variable name and a + syntactic construct and assigns the syntactic construct as value of the + variable. the Variable may, after this point be used in stead of the + construct, this is effectively a pronoun, but not limited to just nouns + and noun phrases. + \item[Participant Reference \z{*A1} and \z{*A2}] refer to the + participants of the conversation. The respectly refer to the speaker, + the listner and both the speaker and the listner + \item +\end{description} + + + +\subsection{Continuation Packet} + +A continuation packet is used whenever a packet goes over it's maximum size +(3+16 tones for proper noun packets, 20 tones for semantic packets) to contain +the rest of the information to be contained. + +A continuation packet is formed as follws +\begin{itemize} + \item A Star and an Octothorpe (\z{*\#}) + \item The number of tones in the body of the semantic packet as a single + hexadecimal digit with \z* standing for 14, \z\# standing for 15 and \z0 + standing for 16. + \item The tones of the body +\end{itemize} + +If the entire contents cannot be fit in the body of the packey, more +continuation packets shall be used. + +\subsection{Variable packet}\label{variables} + +A variable packet represents a variable to be refered too as later, they act a +bit like pronouns but can refer to any construct of the language. They are +formed by two Octothorpes followed by the identifier of the variables composed +of up to 18 digits. + +\section{Actually communicating -- Flow control and error correction} + +The packets previously documented are only the encapsulated semantic meaning of +language. An actual conversation would use the following flow control language: + +A discussion is initiated by a + +\section{Sample Texts} + +These text samples do not contain the control flow communications. The +corresponding audio samples are as if said by a speaker at adress 42069 +(decimal) broadcasting to the network. + +\begin{quote} +Hark! It was ruled by Agamashuya and His son Gu Sabah: Tian practices against +the lesser side of the invisible origin of light, beset by cosmetic prohibitions +of silence and restraint; for Ngu, a slave to creativity, shall make inspection +and certification prior to confirmation of Najva Guns’ official status. Deny +thine humanity: There are no politics in real life. +\end{quote} +\ExplSyntaxOn +\cs_set:Npn \__nguh_multigloss_word:nn #1#2 { + \allowbreak + + \hbox { + \begin{tabular}{@{}l} + \ttfamily \__nguh_gloss_rescan:n {\ignorespaces#1} \\ + \noalign{\vskip-6pt} + \scshape \__nguh_gloss_rescan:n {\ignorespaces#2} \\ + \end{tabular} + } + + \space +} +\ExplSyntaxOff +{ +\catcode`#=12 +\multigloss { + *B | *B | *B + cnew | cnew | cnew + + *1 | *A1 | *0 | ##0 | *D | **0*44*#0#0#0#0#0#0 + assert | 1sg | let | var[0] | ppn | ``Agamashuya'' + + *#0#4#1*44*#0#0#0#0 | *#0#0#0#6#7*44*#0#0 | *#0#0#0#0#0#6#1*44* + cont | cont | cont + + *#0#0#0#0#0#0#0#6C4 | *#0*44*#0#0#0#0#0#0 | *#0#6#1*44*#0#0#0#0 + cont | cont | cont + + *#0#0#0#7#3*44*#0#0 | *#0#0#0#0#0#6#8*44* | *#0#0#0#0#0#0#0#7#5 + cont | cont | cont + + *#0*44*#0#0#0#0#0#0 | *#0#7#9*44*#0#0#0#0 | *#8#0#0#6#1 | BA05 | *3 | *C + cont | cont | cont | person | trans | col + + ##0 | *D | **0*44*#0#0#0#0#0#0 + var[0] | ppn | ``Gu Sabah'' + + *#0#4#7*44*#0#0#0#0 | *#0#0#0#7#5*44*#0#0 | *#0#0#0#0#0#2#0*44* + cont | cont | cont + + *#0#0#0#0#0#0#0#5#3 | *#0*44*#0#0#0#0#0#0 | *#0#6#1*44*#0#0#0#0 + cont | cont | cont + + *#0#0#0#6#2*44*#0#0 | *#0#0#0#0#0#6#1*44* | *#0#0#0#0#0#0#0#6#8 + cont | cont | cont + + BA055*1B0BA055*6CB*0 | *#4B#B1 | * | 328 + {\nf male child of} var[0] | cont | gnr | govern +} +} +\end{document} diff --git a/grammar/nguhslides b/grammar/nguhslides new file mode 160000 index 0000000..acda305 --- /dev/null +++ b/grammar/nguhslides @@ -0,0 +1 @@ +Subproject commit acda305ca6ee2f577a8589a8bc0e62117c4922b8 diff --git a/tools/0.wav b/tools/0.wav new file mode 100644 index 0000000..0aed754 Binary files /dev/null and b/tools/0.wav differ diff --git a/tools/1.wav b/tools/1.wav new file mode 100644 index 0000000..c4f5f44 Binary files /dev/null and b/tools/1.wav differ diff --git a/tools/2.wav b/tools/2.wav new file mode 100644 index 0000000..25c8be0 Binary files /dev/null and b/tools/2.wav differ diff --git a/tools/3.wav b/tools/3.wav new file mode 100644 index 0000000..03afe48 Binary files /dev/null and b/tools/3.wav differ diff --git a/tools/4.wav b/tools/4.wav new file mode 100644 index 0000000..529fb53 Binary files /dev/null and b/tools/4.wav differ diff --git a/tools/5.wav b/tools/5.wav new file mode 100644 index 0000000..668640f Binary files /dev/null and b/tools/5.wav differ diff --git a/tools/6.wav b/tools/6.wav new file mode 100644 index 0000000..3b91a86 Binary files /dev/null and b/tools/6.wav differ diff --git a/tools/7.wav b/tools/7.wav new file mode 100644 index 0000000..d61634e Binary files /dev/null and b/tools/7.wav differ diff --git a/tools/8.wav b/tools/8.wav new file mode 100644 index 0000000..2a7ce03 Binary files /dev/null and b/tools/8.wav differ diff --git a/tools/9.wav b/tools/9.wav new file mode 100644 index 0000000..6bd3dbd Binary files /dev/null and b/tools/9.wav differ diff --git a/tools/A.wav b/tools/A.wav new file mode 100644 index 0000000..73c5d5e Binary files /dev/null and b/tools/A.wav differ diff --git a/tools/B.wav b/tools/B.wav new file mode 100644 index 0000000..c81a676 Binary files /dev/null and b/tools/B.wav differ diff --git a/tools/C.wav b/tools/C.wav new file mode 100644 index 0000000..301984c Binary files /dev/null and b/tools/C.wav differ diff --git a/tools/D.wav b/tools/D.wav new file mode 100644 index 0000000..5a1dc4f Binary files /dev/null and b/tools/D.wav differ diff --git a/tools/Octothorpe.wav b/tools/Octothorpe.wav new file mode 100644 index 0000000..41dde80 Binary files /dev/null and b/tools/Octothorpe.wav differ diff --git a/tools/Star.wav b/tools/Star.wav new file mode 100644 index 0000000..071784e Binary files /dev/null and b/tools/Star.wav differ diff --git a/tools/ppn2seq/CHANGELOG.md b/tools/ppn2seq/CHANGELOG.md new file mode 100644 index 0000000..79afd88 --- /dev/null +++ b/tools/ppn2seq/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for ppn2seq + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/tools/ppn2seq/LICENSE b/tools/ppn2seq/LICENSE new file mode 100644 index 0000000..d3d3328 --- /dev/null +++ b/tools/ppn2seq/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2024 Annwan + +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. diff --git a/tools/ppn2seq/ppn2seq.cabal b/tools/ppn2seq/ppn2seq.cabal new file mode 100644 index 0000000..a1587d2 --- /dev/null +++ b/tools/ppn2seq/ppn2seq.cabal @@ -0,0 +1,27 @@ +cabal-version: 3.0 +name: ppn2seq +version: 0.1.0.0 +-- synopsis: +-- description: +license: MIT +license-file: LICENSE +author: Annwan +maintainer: annwan@annwan.me +-- copyright: +build-type: Simple +extra-doc-files: CHANGELOG.md +-- extra-source-files: + +common warnings + ghc-options: -Wall + +executable ppn2seq + import: warnings + main-is: Ppn2Seq.hs + -- other-modules: + -- other-extensions: + build-depends: base ^>=4.18.0.0 + , text + , unicode-transforms + hs-source-dirs: src + default-language: GHC2021 diff --git a/tools/ppn2seq/src/Ppn2Seq.hs b/tools/ppn2seq/src/Ppn2Seq.hs new file mode 100644 index 0000000..7cfab67 --- /dev/null +++ b/tools/ppn2seq/src/Ppn2Seq.hs @@ -0,0 +1,136 @@ +module Main where + +import Text.Printf +import Data.Text.Normalize +import qualified Data.Text as T + +chunksof :: Int -> [a] -> [[a]] +chunksof n s = case drop n s of + [] -> [s] + rest -> (take n s) : chunksof n rest + +phoneify :: [String] -> String +phoneify [] = "" +phoneify (x:xs) = "**" ++ length_fmt x ++ x ++ phoneify_rest xs + where + length_fmt :: String -> String + length_fmt s = case length s of + { 1 -> "1" ; 2 -> "2" ; 3 -> "3"; 4 -> "4" + ; 5 -> "5" ; 6 -> "6" ; 7 -> "7"; 8 -> "8" + ; 9 -> "9" ; 10 -> "A" ; 11 -> "B" ; 12 -> "C" + ; 13 -> "D"; 14 -> "*" ; 15 -> "#" ; 16 -> "0" + ; _ -> "!" + } + phoneify_rest [] = "" + phoneify_rest (y:ys) = "-*#" ++ length_fmt y ++ y ++ phoneify_rest ys + +toEbcdic :: String -> String +toEbcdic = concatMap $ \x -> case x of + ' ' -> "40" + '$' -> "4A" + '.' -> "4B" + '<' -> "4C" + '(' -> "4D" + '+' -> "4*" + '|' -> "4#" + 'א' -> "50" + '!' -> "5A" + '*' -> "5C" + ')' -> "5D" + ';' -> "5*" + '¬' -> "5#" + '-' -> "60" + '/' -> "61" + ',' -> "6B" + '%' -> "6C" + '_' -> "6D" + '>' -> "6*" + '?' -> "6#" + ':' -> "7A" + '#' -> "7B" + '@' -> "7C" + '\'' -> "7D" + '=' -> "7*" + '"' -> "7#" + 'ב' -> "81" + 'ג' -> "82" + 'ד' -> "83" + 'ה' -> "84" + 'ו' -> "85" + 'ז' -> "86" + 'ח' -> "84" + 'ט' -> "88" + 'י' -> "89" + 'ך' -> "91" + 'כ' -> "92" + 'ל' -> "93" + 'ם' -> "94" + 'מ' -> "95" + 'ן' -> "96" + 'נ' -> "97" + 'ס' -> "98" + 'ע' -> "99" + '€' -> "9C" + '₪' -> "9E" + -- 'ע' -> "A2" -- FOR SOME UN-FUCKING-GODLY REASON IBM DECIDED TO ENCODE THIS TWICE, ENCODED AS 99 + 'ף' -> "A3" + 'פ' -> "A4" + 'ץ' -> "A5" + 'צ' -> "A6" + 'ק' -> "A7" + 'ר' -> "A8" + 'ש' -> "A9" + 'ת' -> "AA" + 'A' -> "C1" + 'B' -> "C2" + 'C' -> "C3" + 'D' -> "C4" + 'E' -> "C5" + 'F' -> "C6" + 'G' -> "C7" + 'H' -> "C8" + 'I' -> "C9" + 'J' -> "D1" + 'K' -> "D2" + 'L' -> "D3" + 'M' -> "D4" + 'N' -> "D5" + 'O' -> "D6" + 'P' -> "D7" + 'Q' -> "D8" + 'R' -> "D9" + 'S' -> "*2" + 'T' -> "*3" + 'U' -> "*4" + 'V' -> "*5" + 'W' -> "*6" + 'X' -> "*7" + 'Y' -> "*8" + 'Z' -> "*9" + '0' -> "#0" + '1' -> "#1" + '2' -> "#2" + '3' -> "#3" + '4' -> "#4" + '5' -> "#5" + '6' -> "#6" + '7' -> "#7" + '8' -> "#8" + '9' -> "#9" + _ -> "!" + + +toUnicodeC :: Char -> String +toUnicodeC = printf "U+%08X" + +toUnicode :: String -> String +toUnicode = concatMap toUnicodeC + +convert :: String -> String +convert s = + if '!' `elem` toEbcdic s + then toEbcdic $ toUnicode s + else toEbcdic s + +main :: IO () +main = interact $ unlines . map (phoneify . chunksof 16 . convert . T.unpack . normalize NFD . T.pack) . lines diff --git a/tools/seqtoaudio b/tools/seqtoaudio new file mode 100755 index 0000000..7b19b1c --- /dev/null +++ b/tools/seqtoaudio @@ -0,0 +1,55 @@ +#!/usr/bin/env lua + +--- Transforms a code into a list of file to stitch +---@param code string the code to parse +---@return table +local function parse(code) + if type(code) ~= "string" then error("parse expects a string") end + local filemap = { + ["1"] = "1.wav", + ["2"] = "2.wav", + ["3"] = "3.wav", + ["4"] = "4.wav", + ["5"] = "5.wav", + ["6"] = "6.wav", + ["7"] = "7.wav", + ["8"] = "8.wav", + ["9"] = "9.wav", + ["0"] = "0.wav", + ["*"] = "Star.wav", + ["#"] = "Octothorpe.wav", + ["A"] = "A.wav", + ["B"] = "B.wav", + ["C"] = "C.wav", + ["D"] = "D.wav", + ["-"] = "skip.wav", + } + local seq = {} + for i = 1, #code do + table.insert(seq, filemap[code:sub(i, i)] or filemap["-"]) + end + return seq +end + + + +local args = {...} + +local i = 1 +while i <= #args do + local code = args[i] + local out = args[i+1] or "out.wav" + local sequence = parse(code) + local list = io.open(out .. ".filelist", "w") + if not list then + io.stderr:write("Cannot open `" .. out .. ".filelist\n") + io.stderr:write("Abborting\n") + os.exit(1) + end + for _, v in ipairs(sequence) do + list:write("file '" .. v .. "'\n") + end + list:close() + os.execute("ffmpeg -f concat -safe 0 -i " .. out .. ".filelist -c copy " .. out) + i = i + 2 +end diff --git a/tools/skip.wav b/tools/skip.wav new file mode 100644 index 0000000..2318db5 Binary files /dev/null and b/tools/skip.wav differ