diff --git a/examples/ggwave-wasm/CMakeLists.txt b/examples/ggwave-wasm/CMakeLists.txt index f9db37e..18937da 100644 --- a/examples/ggwave-wasm/CMakeLists.txt +++ b/examples/ggwave-wasm/CMakeLists.txt @@ -16,3 +16,8 @@ target_link_libraries(${TARGET} PRIVATE ggwave-common ggwave-common-sdl2 ) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/index-tmpl.html ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/index.html @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/style.css ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/style.css COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/main.js ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/main.js COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/plucky.mp3 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/plucky.mp3 COPYONLY) diff --git a/examples/ggwave-wasm/index-tmpl.html b/examples/ggwave-wasm/index-tmpl.html new file mode 100644 index 0000000..10fbff8 --- /dev/null +++ b/examples/ggwave-wasm/index-tmpl.html @@ -0,0 +1,400 @@ + + + + + ggwave : emscripten example + + + + + + + +
+

ggwave

+ + Open this page on multiple devices (computers, phones, tables, etc.).
+ Press the init button and broadcast some text. Make sure your speakers and microphones are enabled. + +

+ +
+
+ + + + + + + + + + + +
+ +
+
+

Output:

+
+
+

Capture:

+
+
+

Browser:

+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + +
+ +

+ +

Standard output:

+ + +
+
Downloading...
+ +
+ +
+
+ +
+ + | + Build time: @GIT_DATE@ | + Commit hash: @GIT_SHA1@ | + Commit subject: @GIT_COMMIT_SUBJECT@ | + +
+
+ View on GitHub + + +
+ + + + + + + diff --git a/examples/ggwave-wasm/main.js b/examples/ggwave-wasm/main.js new file mode 100644 index 0000000..fd64655 --- /dev/null +++ b/examples/ggwave-wasm/main.js @@ -0,0 +1,60 @@ +/*! \file main.js + * \brief Text transfer over sound + * \author Georgi Gerganov + */ + +function transmitText(sText) { + var r = new Uint8Array(256); + for (var i = 0; i < sText.length; ++i) { + r[i] = sText.charCodeAt(i); + } + + var buffer = Module._malloc(256); + Module.writeArrayToMemory(r, buffer, 256); + Module._setText(sText.length, buffer); + Module._free(buffer); +} + +var firstTimeFail = false; +var peerInfo = document.querySelector('a#peer-info'); + +function updatePeerInfo() { + if (typeof Module === 'undefined') return; + var framesLeftToRecord = Module._getFramesLeftToRecord(); + var framesToRecord = Module._getFramesToRecord(); + var framesLeftToAnalyze = Module._getFramesLeftToAnalyze(); + var framesToAnalyze = Module._getFramesToAnalyze(); + + if (framesToAnalyze > 0) { + peerInfo.innerHTML= + "Analyzing Rx data: "; + peerReceive.innerHTML= ""; + } else if (framesLeftToRecord > Math.max(0, 0.05*framesToRecord)) { + firstTimeFail = true; + peerInfo.innerHTML= + "Transmission in progress: "; + } else if (framesToRecord > 0) { + peerInfo.innerHTML= "Analyzing Rx data ..."; + } else if (framesToRecord == 0) { + peerInfo.innerHTML= "

Listening for waves ...

"; + } else if (framesToRecord == -1) { + if (firstTimeFail) { + playSound("/media/case-closed"); + firstTimeFail = false; + } + peerInfo.innerHTML= "

Failed to decode Rx data

"; + } +} + +function updateRx() { + if (typeof Module === 'undefined') return; + Module._getText(bufferRx); + var result = ""; + for (var i = 0; i < 140; ++i){ + result += (String.fromCharCode((Module.HEAPU8)[bufferRx + i])); + brx[i] = (Module.HEAPU8)[bufferRx + i]; + } + document.getElementById('rxData').innerHTML = result; +} diff --git a/examples/ggwave-wasm/plucky.mp3 b/examples/ggwave-wasm/plucky.mp3 new file mode 100644 index 0000000..367a0e9 Binary files /dev/null and b/examples/ggwave-wasm/plucky.mp3 differ diff --git a/examples/ggwave-wasm/style.css b/examples/ggwave-wasm/style.css new file mode 100644 index 0000000..7d02fde --- /dev/null +++ b/examples/ggwave-wasm/style.css @@ -0,0 +1,279 @@ +body { + margin: 0; background-color: white; + -webkit-font-smoothing: subpixel-antialiased; + font-smoothing: subpixel-antialiased; +} +#screen { + margin: 0; + padding: 0; + font-size: 13px; + height: 100%; + font: sans-serif; +} +.no-sel { + -moz-user-select: none; + -webkit-user-select: none; + -webkit-touch-callout: none; + -ms-user-select:none; + user-select:none; + -o-user-select:none; +} +.cell { + pointer-events: none; +} +.cell-version { + padding-left: 4px; + padding-top: 0.5em; + text-align: left; + display: inline-block; + float: left; + color: rgba(0, 0, 0, 0.75); +} +.cell-about { + padding-right: 24px; + padding-top: 0.5em; + text-align: right; + display: inline-block; + float: right; +} +.nav-link { + text-decoration: none; + color: rgba(0, 0, 0, 1.0); +} + +#main-container { + font-size:12px; + font-family: monospace; +} + +textarea { + font-size:12px; + font-family: monospace; +} + +.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; } +div.emscripten { text-align: center; } +div.emscripten_border { border: 1px solid black; } + +canvas.emscripten { border: 0px none; background-color: black; } + +.spinner { + height: 30px; + width: 30px; + margin: 0; + margin-top: 20px; + margin-left: 20px; + display: inline-block; + vertical-align: top; + + -webkit-animation: rotation .8s linear infinite; + -moz-animation: rotation .8s linear infinite; + -o-animation: rotation .8s linear infinite; + animation: rotation 0.8s linear infinite; + + border-left: 5px solid rgb(235, 235, 235); + border-right: 5px solid rgb(235, 235, 235); + border-bottom: 5px solid rgb(235, 235, 235); + border-top: 5px solid rgb(120, 120, 120); + + border-radius: 100%; + background-color: rgb(189, 215, 46); +} + +@-webkit-keyframes rotation { + from {-webkit-transform: rotate(0deg);} + to {-webkit-transform: rotate(360deg);} +} +@-moz-keyframes rotation { + from {-moz-transform: rotate(0deg);} + to {-moz-transform: rotate(360deg);} +} +@-o-keyframes rotation { + from {-o-transform: rotate(0deg);} + to {-o-transform: rotate(360deg);} +} +@keyframes rotation { + from {transform: rotate(0deg);} + to {transform: rotate(360deg);} +} + +#status { + display: inline-block; + vertical-align: top; + margin-top: 30px; + margin-left: 20px; + font-weight: bold; + color: rgb(120, 120, 120); +} + +#progress { + height: 20px; + width: 30px; +} + +#output { + width: 800px; + height: 200px; + margin: 0 auto; + margin-top: 10px; + border-left: 0px; + border-right: 0px; + padding-left: 0px; + padding-right: 0px; + background-color: black; + color: white; + font-size:10px; + font-family: 'Lucida Console', Monaco, monospace; + outline: none; +} + +.led-box { + height: 30px; + width: 25%; + margin: 10px 0; + float: left; +} + +.led-box p { + font-size: 12px; + text-align: center; + margin: 1em; +} + +.led-red { + margin: 0 auto; + width: 12px; + height: 12px; + background-color: #F00; + border-radius: 50%; + box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #441313 0 -1px 9px, rgba(255, 0, 0, 0.5) 0 2px 12px; + -webkit-animation: blinkRed 0.5s infinite; + -moz-animation: blinkRed 0.5s infinite; + -ms-animation: blinkRed 0.5s infinite; + -o-animation: blinkRed 0.5s infinite; + animation: blinkRed 0.5s infinite; +} + +@-webkit-keyframes blinkRed { + from { background-color: #F00; } + 50% { background-color: #A00; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #441313 0 -1px 9px, rgba(255, 0, 0, 0.5) 0 2px 0;} + to { background-color: #F00; } +} +@-moz-keyframes blinkRed { + from { background-color: #F00; } + 50% { background-color: #A00; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #441313 0 -1px 9px, rgba(255, 0, 0, 0.5) 0 2px 0;} + to { background-color: #F00; } +} +@-ms-keyframes blinkRed { + from { background-color: #F00; } + 50% { background-color: #A00; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #441313 0 -1px 9px, rgba(255, 0, 0, 0.5) 0 2px 0;} + to { background-color: #F00; } +} +@-o-keyframes blinkRed { + from { background-color: #F00; } + 50% { background-color: #A00; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #441313 0 -1px 9px, rgba(255, 0, 0, 0.5) 0 2px 0;} + to { background-color: #F00; } +} +@keyframes blinkRed { + from { background-color: #F00; } + 50% { background-color: #A00; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #441313 0 -1px 9px, rgba(255, 0, 0, 0.5) 0 2px 0;} + to { background-color: #F00; } +} + +.led-yellow { + margin: 0 auto; + width: 12px; + height: 12px; + background-color: #FF0; + border-radius: 50%; + box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #808002 0 -1px 9px, #FF0 0 2px 12px; + -webkit-animation: blinkYellow 1s infinite; + -moz-animation: blinkYellow 1s infinite; + -ms-animation: blinkYellow 1s infinite; + -o-animation: blinkYellow 1s infinite; + animation: blinkYellow 1s infinite; +} + +@-webkit-keyframes blinkYellow { + from { background-color: #FF0; } + 50% { background-color: #AA0; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #808002 0 -1px 9px, #FF0 0 2px 0; } + to { background-color: #FF0; } +} +@-moz-keyframes blinkYellow { + from { background-color: #FF0; } + 50% { background-color: #AA0; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #808002 0 -1px 9px, #FF0 0 2px 0; } + to { background-color: #FF0; } +} +@-ms-keyframes blinkYellow { + from { background-color: #FF0; } + 50% { background-color: #AA0; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #808002 0 -1px 9px, #FF0 0 2px 0; } + to { background-color: #FF0; } +} +@-o-keyframes blinkYellow { + from { background-color: #FF0; } + 50% { background-color: #AA0; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #808002 0 -1px 9px, #FF0 0 2px 0; } + to { background-color: #FF0; } +} +@keyframes blinkYellow { + from { background-color: #FF0; } + 50% { background-color: #AA0; box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #808002 0 -1px 9px, #FF0 0 2px 0; } + to { background-color: #FF0; } +} + +.led-green { + margin: 0 auto; + width: 12px; + height: 12px; + background-color: #ABFF00; + border-radius: 50%; + box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #304701 0 -1px 9px, #89FF00 0 2px 12px; +} + +.led-blue { + margin: 0 auto; + width: 18px; + height: 18px; + background-color: #24E0FF; + border-radius: 50%; + box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 7px 1px, inset #006 0 -1px 9px, #3F8CFF 0 2px 14px; +} + +table td { + border: 1px solid #e8e8e8; +} +table th, table td { + padding: 10px 10px; +} +table td { + border: 1px solid #e8e8e8; +} +table th, table td { + padding: 10px 10px; +} +td[Attributes Style] { + text-align: -webkit-center; +} +td { + display: table-cell; + vertical-align: inherit; +} +table { + margin-bottom: 30px; + width: 800px; + text-align: left; + color: #3f3f3f; + border-collapse: collapse; + border: 1px solid #e8e8e8; +} +table { + margin-bottom: 30px; + width: 800px; + text-align: left; + color: #3f3f3f; + border-collapse: collapse; + border: 1px solid #e8e8e8; +} +table { + border-collapse: separate; + border-spacing: 2px; +}