1
0
Fork 0

bad apple: Initial version of the demo.

This adds famous movie with music.
master
Pavel Machek 2023-12-08 21:19:41 +01:00
parent b5abec090e
commit 2347a01fa0
11 changed files with 156 additions and 0 deletions

1
apps/bad/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: attempt to import

8
apps/bad/README.md Normal file
View File

@ -0,0 +1,8 @@
# Bad Apple demo ![](app.png)
"Bad Apple" is like "Hello World" for graphics system. So this is it
for Bangle.js2. Watch have no speaker, so vibration motor is used,
instead, to produce (pretty quiet) sound.
Tools for preparing bad.araw and bad.vraw are in prep/ directory. Full
3 minute demo should actually fit to the watch.

1
apps/bad/app-icon.js Normal file
View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwgIifiAFWj//Aod///gAgMH///+AFBn4FB/AQDAoYEB//8gEBAokDAoX+ApguCAAIFqGoYFNLIZHBApZxFAoyDCAoqJCSoqsBUIcPAoKtF4AFBJAS/DHIQAeA="))

BIN
apps/bad/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

65
apps/bad/bad.app.js Normal file
View File

@ -0,0 +1,65 @@
/* sox Rear_Right.wav -r 4k -b 8 -c 1 -e unsigned-integer 0.raw vol 2
aplay -r 4000 /tmp/0.raw
*/
/* https://forum.espruino.com/conversations/348912/ */
let pin = D19;
function play(name, callback) {
function playChar(offs) {
var l = 10240;
var s = require("Storage").read(name, offs, l);
//print("Waveform " + name + " " + s.length);
if (!s.length) {
digitalWrite(pin,0);
if (callback) callback();
return;
}
var w = new Waveform(s.length);
var b = w.buffer;
b.set(s);
//print("Buffer", s.length);
//for (var i=s.length-1;i>=0;i--)b[i]/=4;
w.startOutput(pin, 4000);
w.on("finish", function(buf) {
playChar(offs+l);
});
}
analogWrite(pin, 0.1, {freq:40000});
playChar(0);
}
function video(name, callback) {
function frame() {
var s = require("Storage").read(name, offs, l);
if (!s)
return;
g.drawImage(s, 0, 0, { scale: 2 });
g.flip();
offs += l;
}
g.clear();
var offs = 0;
//var l = 3875; for 176x176
//var l = 515; for 64x64
var l = 971;
setInterval(frame, 200);
}
function run() {
clearInterval(i);
print("Running");
play('bad.araw');
t1 = getTime();
video('bad.vraw');
print("100 frames in ", getTime()-t1);
// 1.7s, unscaled
// 2.68s, scale 1.01
// 5.73s, scale 2.00
// 9.93s, scale 2, full screen
// 14.4s scaled. 176/64
}
print("Loaded");
i = setInterval(run, 100);

BIN
apps/bad/bad.araw Normal file

Binary file not shown.

BIN
apps/bad/bad.vraw Normal file

Binary file not shown.

16
apps/bad/metadata.json Normal file
View File

@ -0,0 +1,16 @@
{ "id": "bad",
"name": "Bad Apple",
"version":"0.01",
"description": "Bad Apple demo",
"icon": "app.png",
"readme": "README.md",
"supports" : ["BANGLEJS2"],
"allow_emulator": false,
"tags": "game",
"storage": [
{"name":"bad.app.js","url":"bad.app.js"},
{"name":"bad.vraw","url":"bad.vraw"},
{"name":"bad.araw","url":"bad.araw"},
{"name":"bad.img","url":"app-icon.js","evaluate":true}
]
}

32
apps/bad/prep/img_convert.py Executable file
View File

@ -0,0 +1,32 @@
#!/usr/bin/python3
from PIL import Image
import os
def convert_image(input_path, output_width, output_height):
img = Image.open(input_path)
img_resized = img.resize((output_width, output_height), Image.ANTIALIAS)
img_gray = img_resized.convert('L')
img_1bpp = img_gray.point(lambda x: 0 if x < 128 else 255, '1')
return img_1bpp
def convert_and_append_header(input_directory, size):
input_files = [f for f in os.listdir(input_directory) if f.startswith("image_") and f.endswith(".png")]
input_files.sort()
header_bytes = size.to_bytes(1, byteorder='big') + size.to_bytes(1, byteorder='big') + b'\x01'
for i, input_file in enumerate(input_files):
input_path = os.path.join(input_directory, input_file)
img_1bpp = convert_image(input_path, size, size)
output_file = input_path + ".raw"
with open(output_file, 'wb') as raw_file:
raw_file.write(header_bytes)
raw_file.write(img_1bpp.tobytes())
if __name__ == "__main__":
input_directory = "." # Replace with the path to your image directory
output_width = 88
output_file_path = "output_with_header.raw" # Replace with the desired output file path
convert_and_append_header(input_directory, output_width)

20
apps/bad/prep/run Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
# aplay -r 4000 /tmp/0.raw
#bug: Terminal exists on b.js, it is dumb terminal, not vt100.
rm image_*.png image_*.png.raw output.wav ../bad.araw ../bad.vraw
I=bad.mp4
S=1:18
E=1:50
ffmpeg -i $I -ss $S -to $E -vn -acodec pcm_u8 -ar 4000 -ac 1 -y output.wav
./wav_divider.py
mv output.raw ../bad.araw
ffmpeg -i $I -ss $S -to $E -r 5 -vf fps=5 image_%04d.png
./img_convert.py
cat *.png.raw > ../bad.vraw
ls -al ../bad.*

13
apps/bad/prep/wav_divider.py Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/python3
def divide_bytes(input_file, output_file):
with open(input_file, 'rb') as infile:
with open(output_file, 'wb') as outfile:
byte = infile.read(1)
while byte:
# Convert byte to integer, divide by 4, and write back as byte
new_byte = bytes([int.from_bytes(byte, byteorder='big') // 3])
outfile.write(new_byte)
byte = infile.read(1)
divide_bytes("output.wav", "output.raw")