diff --git a/.gitignore b/.gitignore index 7764a17..3402407 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,9 @@ sample*.s chickens.wav chickens.s dubstep.wav -dubstep.wav.* \ No newline at end of file +dubstep.wav.* +video-rickroll/frames +video-doom/frames +video-cat/frames +video-bulk/frames +video/frames diff --git a/Makefile b/Makefile index 86d0922..5e57313 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,44 @@ -all : sample0.xex \ - sample1.xex sample2.xex sample3.xex sample4.xex sample5.xex sample6.xex \ - fruit.xex mapclock.xex sailboat.xex sunset.xex train404.xex \ - potato.xex selfie.xex kitty.xex meme.xex +all : rickroll.xex # sample5.s from sample5.jpg # reminder: $< is input # $@ is output -%.s : %.jpg dither-image.js +%.s : %.jpg dither-image.js gif.sh mp4.sh node dither-image.js $< $@ +chickens.s : chickens.wav pack-wav.js + node pack-wav.js $< $@ + +dubstep.wav.s : dubstep.wav pack-wav.js + node pack-wav.js $< $@ + +dubstep.wav : Dubstep_Loop_by_WinnieTheMoog.ogg + ffmpeg -i "Dubstep_Loop_by_WinnieTheMoog.ogg" \ + -t 2.0 \ + -acodec pcm_u8 \ + -ac 1 \ + -ar 15704 \ + -y $@ + +never-gonna-give-you-up.wav.s : never-gonna-give-you-up.wav pack-wav.js + node pack-wav.js $< $@ + +never-gonna-give-you-up.wav : never-gonna-give-you-up.mp4 + ffmpeg -i "never-gonna-give-you-up.mp4" \ + -vn \ + -t 2.0 \ + -acodec pcm_u8 \ + -ac 1 \ + -ar 15704 \ + -y $@ + %.o : %.s ca65 -v -t atari -o $@ $< -%.xex : %.o dither4.o atari-asm-xex.cfg - ld65 -v -C ./atari-asm-xex.cfg -o $@ dither4.o $< +%.xex : %.o dither4.o never-gonna-give-you-up.wav.o atari-asm-xex.cfg + ld65 -v -C ./atari-asm-xex.cfg -o $@ dither4.o never-gonna-give-you-up.wav.o $< clean : rm -f *.o @@ -24,3 +47,14 @@ clean : rm -f fruit.s mapclock.s sailboat.s sunset.s train404.s rm -f potato.s selfie.s kitty.s meme.s rm -f *.xex + rm -f chickens.s + rm -f chickens.o + rm -f dubstep.wav + rm -f dubstep.wav.[so] + rm -f never-gonna-give-you-up.wav + rm -f never-gonna-give-you-up.wav.[so] + +test : all + atari800 rickroll.xex + +.dummy: clean test sample0.s sample1.s sample2.s sample3.s sample4.s sample5.s sample6.s chickens.s rickroll.s diff --git a/dither-image.js b/dither-image.js index 93fddd9..f14f1d8 100644 --- a/dither-image.js +++ b/dither-image.js @@ -1067,7 +1067,7 @@ async function saveImage(width, height, lines, dest) { resolve(image); }); }); - await image.resize(Math.round(width2 * 2 / 1.2), height * 2); + await image.resize(Math.round(width2 * 2), height * 2); await image.writeAsync(dest); } diff --git a/dither4.s b/dither4.s index fd4c0ec..cdb2371 100644 --- a/dither4.s +++ b/dither4.s @@ -26,6 +26,7 @@ sample_ptrl = $84 sample_ptrh = $85 sample_ptr = sample_ptrl scanline = $86 +audiotemp = $87 frame_counter = $89 ;height = 160 @@ -39,6 +40,9 @@ scanline_max = (lines_per_frame - scanline_offset) / 2 .data +.import audio_samples +.import audio_samples_end + .import frame1_top .import frame1_bottom .import frame1_palette1_even @@ -49,11 +53,41 @@ scanline_max = (lines_per_frame - scanline_offset) / 2 .import frame1_palette3_odd .import displaylist +audio_high_byte: + .scope + .macro byteseq val + .repeat 16 + .byte val | $10 + .endrep + .endmacro + byteseq $0 + byteseq $1 + byteseq $2 + byteseq $3 + byteseq $4 + byteseq $5 + byteseq $7 + byteseq $8 + byteseq $9 + byteseq $a + byteseq $b + byteseq $c + byteseq $d + byteseq $e + byteseq $f + .endscope + .code .export start .proc start + ; Set up the audio sample buffer + lda #.lobyte(audio_samples) + sta sample_ptrl + lda #.hibyte(audio_samples) + sta sample_ptrh + ; Disable display DMA lda #$00 sta DMACTL @@ -98,8 +132,6 @@ wait_loop: .macro inner_scanline frame_offset, line_offset ; Y should be VCOUNT at entry ; it'll fire on unused lines, but harmlessly - ;ldy scanline ; 3 cyc - ;inc scanline ; 5 cyc ; 23-26 cycles before break ; Leisurely memory fetches @@ -109,6 +141,7 @@ wait_loop: lda frame1_palette3_even + frame_offset + line_offset - scanline_offset / 2,y ; 4/5 tay ; 2 pla ; 3 + ; Wait for horizontal blank sta WSYNC ; 4 @@ -119,6 +152,59 @@ wait_loop: sty COLPF2 ; 4 .endmacro + .macro audio_play_raw + ;ldy VCOUNT ; set on entry + lda (sample_ptr),y ; 5/6 cyc + sta AUDC1 ; 4 cyc + .endmacro + + .macro audio_prep + ; Y is VCOUNT at entry + lda (sample_ptr),y ; 5/6 cyc + sta audiotemp ; 3 cyc + .endmacro + + ; call with A pre-loaded to audiotemp + .macro audio_play_lo + ;lda audiotemp ; 3 cyc + and #$0f ; 2 cyc + ora #$10 ; 2 cyc + sta AUDC1 ; 4 cyc + .endmacro + + ; clobbers Y + .macro audio_play_hi ; 12 cycles + ldy audiotemp ; 3 cyc + lda audio_high_byte,y ; 5 cyc + sta AUDC1 ; 4 cyc + .endmacro + + .macro audio_inc + ; 22 cycles + lda sample_ptrl ; 3 cyc + clc ; 2 cyc + adc #131 ; 2 cyc + sta sample_ptrl ; 3 cyc + lda sample_ptrh ; 3 cyc + adc #0 ; 2 cyc + sta sample_ptrh ; 3 cyc + cmp #.hibyte(audio_samples_end) ; 2 cyc + bmi audio_cont ; 2 cyc + + sta WSYNC + + ; 10 cycles, optional + lda #.lobyte(audio_samples) ; 2 + sta sample_ptrl ; 3 + lda #.hibyte(audio_samples) ; 2 + sta sample_ptrh ; 3 + + sta WSYNC + ldy VCOUNT ; 4 cycles + + audio_cont: + .endmacro + .macro run_frame frame_offset .scope ; each scanline is 228 color clocks @@ -129,13 +215,21 @@ wait_loop: sty scanline ; 3 cycles inner_scanline frame_offset, 0 ; 23-26 cycles before break, 12 cycles after + ldy scanline ; 3 cycles + audio_prep + audio_play_lo + ldy scanline ; 3 cycles inner_scanline frame_offset, 128 ; 23-26 cycles before break, 12 cycles after + audio_play_hi + ; pair cleanup: 6 cycles ldy VCOUNT ; 4 cycles bne each_scanline_pair ; 2 cycles + audio_inc ; 22-32 cycles + ; frame cleanup: 11 cycles lda frame_counter ; 3 cycles eor #1 ; 2 cycles diff --git a/never-gonna-give-you-up.mp4 b/never-gonna-give-you-up.mp4 new file mode 100644 index 0000000..46e24c7 Binary files /dev/null and b/never-gonna-give-you-up.mp4 differ diff --git a/pack-wav.js b/pack-wav.js index f8ee37f..50379a0 100644 --- a/pack-wav.js +++ b/pack-wav.js @@ -14,31 +14,44 @@ function byte2byte(arr) { return lines.join('\n'); } -function to4bit(val8) { - let val = (val8 + 7) >> 4; - if (val > 15) { - return 15; +class Dither { + constructor() { + this.err = 0; + } + + to4bit(val8) { + let val = (val8 / 255) - this.err; + if (val < 0) { + val = 0; + } + if (val > 1) { + val = 1; + } + let val4 = Math.round(val * 15); + let dithered = (val4 / 15); + this.err = (dithered - val); + return val4; } - return val; } function pack(audio) { let packed = []; - /* + let dither = new Dither(); for (let i = 0; i < audio.length; i += 2) { // little-endian 4-bit samples - let low = to4bit(audio[i]); - let high = to4bit(audio[i + 1]); + let low = dither.to4bit(audio[i]); + let high = dither.to4bit(audio[i + 1]); let byte = low | (high << 4); packed.push(byte); } - */ + /* // raw push bytes for (let i = 0; i < audio.length; i += 2) { let val = to4bit(audio[i]); let byte = val | 0x10; packed.push(byte); } + */ return packed; } diff --git a/package-lock.json b/package-lock.json index 8956c12..19cd297 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "dependencies": { "jimp": "^0.16.2", + "wav": "^1.0.2", "wavefile": "^11.0.0" }, "devDependencies": { @@ -708,6 +709,22 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "license": "MIT" + }, "node_modules/buffer-equal": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", @@ -716,6 +733,18 @@ "node": ">=0.4.0" } }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "license": "MIT" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -765,6 +794,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1216,8 +1251,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/is-extglob": { "version": "2.1.1", @@ -1254,6 +1288,12 @@ "node": ">=8" } }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1621,6 +1661,18 @@ } ] }, + "node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -1709,6 +1761,36 @@ "node": ">=8" } }, + "node_modules/stream-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", + "license": "MIT", + "dependencies": { + "debug": "2" + } + }, + "node_modules/stream-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/stream-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -1805,6 +1887,34 @@ "pako": "^1.0.5" } }, + "node_modules/wav": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wav/-/wav-1.0.2.tgz", + "integrity": "sha512-viHtz3cDd/Tcr/HbNqzQCofKdF6kWUymH9LGDdskfWFoIy/HJ+RTihgjEcHfnsy1PO4e9B+y4HwgTwMrByquhg==", + "license": "MIT", + "dependencies": { + "buffer-alloc": "^1.1.0", + "buffer-from": "^1.0.0", + "debug": "^2.2.0", + "readable-stream": "^1.1.14", + "stream-parser": "^0.3.1" + } + }, + "node_modules/wav/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/wav/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/wavefile": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/wavefile/-/wavefile-11.0.0.tgz", @@ -2411,11 +2521,35 @@ "ieee754": "^1.1.13" } }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, "buffer-equal": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==" }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2453,6 +2587,11 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2792,8 +2931,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "is-extglob": { "version": "2.1.1", @@ -2821,6 +2959,11 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3101,6 +3244,17 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -3156,6 +3310,34 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "stream-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", + "requires": { + "debug": "2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3228,6 +3410,33 @@ "pako": "^1.0.5" } }, + "wav": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wav/-/wav-1.0.2.tgz", + "integrity": "sha512-viHtz3cDd/Tcr/HbNqzQCofKdF6kWUymH9LGDdskfWFoIy/HJ+RTihgjEcHfnsy1PO4e9B+y4HwgTwMrByquhg==", + "requires": { + "buffer-alloc": "^1.1.0", + "buffer-from": "^1.0.0", + "debug": "^2.2.0", + "readable-stream": "^1.1.14", + "stream-parser": "^0.3.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, "wavefile": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/wavefile/-/wavefile-11.0.0.tgz", diff --git a/package.json b/package.json index 38ecf37..9d78029 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "type": "module", "dependencies": { "jimp": "^0.16.2", + "wav": "^1.0.2", "wavefile": "^11.0.0" }, "devDependencies": { diff --git a/rickroll.jpg b/rickroll.jpg new file mode 100644 index 0000000..931e14e Binary files /dev/null and b/rickroll.jpg differ diff --git a/video-rickroll/combine.sh b/video-rickroll/combine.sh new file mode 100644 index 0000000..29d177c --- /dev/null +++ b/video-rickroll/combine.sh @@ -0,0 +1,10 @@ +ffmpeg \ + -r 60000/1001 \ + -i 'frames/dither-%05d.png' \ + -i 'rickroll-audio.wav' \ + -ac 2 \ + -ar 48000 \ + -vf 'scale=534x384,setsar=1' \ + -pix_fmt yuv420p \ + -movflags +faststart \ + -y rickroll-dither.mp4 diff --git a/video-rickroll/extract.sh b/video-rickroll/extract.sh new file mode 100644 index 0000000..59ce590 --- /dev/null +++ b/video-rickroll/extract.sh @@ -0,0 +1,17 @@ +set -a + +mkdir -p frames + +ffmpeg \ + -i rickroll.mp4 \ + -vf 'scale=320:230,framerate=60000/1001' \ + -an \ + -y 'frames/rickroll-%05d.png' + +ffmpeg \ + -i rickroll.mp4 \ + -vn \ + -ac 1 \ + -ar 15734 \ + -acodec pcm_u8 \ + -y 'rickroll-audio.wav' diff --git a/video-rickroll/video.sh b/video-rickroll/video.sh new file mode 100644 index 0000000..b3158bf --- /dev/null +++ b/video-rickroll/video.sh @@ -0,0 +1,15 @@ +set -e + +for frame in frames/rickroll-[0-9][0-9][0-9][0-9][0-9].png +do + n="${frame#frames/rickroll-}" + n="${n%.png}" + out="frames/dither-${n}" + last="${n:0-1}" + node ../dither-image.js "$frame" "$out" & + if (( last == 9 )) + then + wait + fi +done +wait