|
9 | 9 | <label for="story">Decode</label><br />
|
10 | 10 | <textarea id="textarea-encoded" rows="5" cols="33">Digitale Initiativen</textarea><br />
|
11 | 11 | <br />
|
12 |
| - <button onclick="playAudio()">Play</button> |
13 |
| - <button onclick="stopAudio()">Stop</button> |
14 |
| - <script> |
| 12 | + <button id="button-play">Play</button> |
| 13 | + <button id="button-stop">Stop</button> |
| 14 | + <button id="button-download">Download</button> |
| 15 | + <script type="module"> |
| 16 | + import Crunker from "https://unpkg.com/crunker@latest/dist/crunker.esm.js"; |
| 17 | + |
15 | 18 | let decode, encode;
|
16 | 19 |
|
17 | 20 | const getJsonFromUrl = async (url) => {
|
|
40 | 43 | });
|
41 | 44 |
|
42 | 45 | addChangeListenerToTextarea(encodedTextarea, () => {
|
43 |
| - plainTextarea.value = decode(encodedTextarea.value); |
| 46 | + plainTextarea.value = decode(encodedTextarea.value.toLowerCase()); |
44 | 47 | });
|
45 | 48 |
|
46 | 49 | init();
|
47 | 50 |
|
48 | 51 | const timeouts = [];
|
49 |
| - const soundMapping = { |
50 |
| - " ": undefined, |
51 |
| - b: () => new Audio("./sounds/b-1.m4a"), |
52 |
| - z: () => new Audio("./sounds/z-1.m4a"), |
| 52 | + const soundPathMapping = { |
| 53 | + " ": "./sounds/space-1.m4a", |
| 54 | + b: "./sounds/b-1.m4a", |
| 55 | + z: "./sounds/z-1.m4a", |
53 | 56 | };
|
54 | 57 | const timeMapping = {
|
55 | 58 | " ": 500,
|
56 | 59 | b: 200,
|
57 | 60 | z: 250,
|
58 | 61 | };
|
59 | 62 |
|
| 63 | + const getEncodedSymbolArray = () => { |
| 64 | + return encodedTextarea.value |
| 65 | + .toLowerCase() |
| 66 | + .split("") |
| 67 | + .filter((letter) => [" ", "b", "z"].includes(letter)); |
| 68 | + }; |
| 69 | + |
60 | 70 | const playAudio = () => {
|
61 |
| - const encoded = encodedTextarea.value; |
62 | 71 | let timeOffset = 0;
|
63 |
| - for (const letter of encoded.split("")) { |
64 |
| - if ([" ", "b", "z"].includes(letter)) { |
65 |
| - const timeoutId = setTimeout(() => { |
66 |
| - if (soundMapping[letter]) { |
67 |
| - soundMapping[letter]().play(); |
68 |
| - } |
69 |
| - }, timeOffset); |
70 |
| - timeouts.push(timeoutId); |
71 |
| - timeOffset += timeMapping[letter]; |
72 |
| - } |
| 72 | + for (const letter of getEncodedSymbolArray()) { |
| 73 | + const timeoutId = setTimeout(() => { |
| 74 | + new Audio(soundPathMapping[letter]).play(); |
| 75 | + }, timeOffset); |
| 76 | + timeouts.push(timeoutId); |
| 77 | + timeOffset += timeMapping[letter]; |
73 | 78 | }
|
74 | 79 | };
|
75 | 80 |
|
|
78 | 83 | clearTimeout(timeoutId);
|
79 | 84 | }
|
80 | 85 | };
|
| 86 | + const downloadAudio = async () => { |
| 87 | + let crunker = new Crunker(); |
| 88 | + |
| 89 | + const symbols = getEncodedSymbolArray(); |
| 90 | + crunker |
| 91 | + .fetchAudio(...symbols.map((symbol) => soundPathMapping[symbol])) |
| 92 | + .then((buffers) => crunker.concatAudio(buffers)) |
| 93 | + .then((merged) => crunker.export(merged, "audio/mp3")) |
| 94 | + .then((output) => crunker.download(output.blob, "bz")) |
| 95 | + .catch((error) => { |
| 96 | + throw new Error(error); |
| 97 | + }); |
| 98 | + }; |
| 99 | + |
| 100 | + document.getElementById("button-play").addEventListener("click", playAudio); |
| 101 | + document.getElementById("button-stop").addEventListener("click", stopAudio); |
| 102 | + document.getElementById("button-download").addEventListener("click", downloadAudio); |
81 | 103 | </script>
|
82 | 104 | <script src="./huffman-coding.js"></script>
|
83 | 105 | </body>
|
|
0 commit comments