diff --git a/kernels/bad-apple/Makefile b/kernels/bad-apple/Makefile new file mode 100644 index 0000000..671827e --- /dev/null +++ b/kernels/bad-apple/Makefile @@ -0,0 +1,23 @@ +VIDEO_ROW = 25 +VIDEO_COL = 80 +AUDIO_FREQ = 44100 +AUDIO_CHANNEL = 1 + +VIDEO_SRC = bad-apple.mp4 +VIDEO = build/video.frame +AUDIO = build/audio.pcm + +NAME = bad-apple +SRCS = bad-apple.c resources.S +include $(AM_HOME)/Makefile + +CFLAGS += -DVIDEO_ROW=$(VIDEO_ROW) -DVIDEO_COL=$(VIDEO_COL) \ + -DAUDIO_FREQ=$(AUDIO_FREQ) -DAUDIO_CHANNEL=$(AUDIO_CHANNEL) +ASFLAGS += -DVIDEO_FILE=\"$(abspath $(VIDEO))\" -DAUDIO_FILE=\"$(abspath $(AUDIO))\" +$(VIDEO): + ffmpeg -i $(VIDEO_SRC) -f image2pipe -s $(VIDEO_COL)x$(VIDEO_ROW) -vcodec rawvideo -pix_fmt monow $@ + +$(AUDIO): + ffmpeg -i $(VIDEO_SRC) -vn -acodec pcm_s16le -f s16le -ac $(AUDIO_CHANNEL) -ar $(AUDIO_FREQ) $@ + +resources.S: $(VIDEO) $(AUDIO) diff --git a/kernels/bad-apple/bad-apple.c b/kernels/bad-apple/bad-apple.c new file mode 100644 index 0000000..06a8c60 --- /dev/null +++ b/kernels/bad-apple/bad-apple.c @@ -0,0 +1,74 @@ +#include +#include +#include + +#define FPS 30 +#define CHAR_WHITE '.' +#define CHAR_BLACK 'X' + +typedef struct { + uint8_t pixel[VIDEO_ROW * VIDEO_COL / 8]; +} frame_t; + +static void sleep_until(uint64_t next) { + while (io_read(AM_TIMER_UPTIME).us < next) ; +} + +static uint8_t getbit(uint8_t *p, int idx) { + int byte_idx = idx / 8; + int bit_idx = idx % 8; + bit_idx = 7 - bit_idx; + uint8_t byte = p[byte_idx]; + uint8_t bit = (byte >> bit_idx) & 1; + return bit; +} + +int main() { + extern uint8_t video_payload, video_payload_end; + extern uint8_t audio_payload, audio_payload_end; + int audio_len = 0, audio_left = 0; + Area sbuf; + + ioe_init(); + + frame_t *f = (void *)&video_payload; + frame_t *fend = (void *)&video_payload_end; + printf("\033[H\033[J"); // screan_clear + + bool has_audio = io_read(AM_AUDIO_CONFIG).present; + if (has_audio) { + io_write(AM_AUDIO_CTRL, AUDIO_FREQ, AUDIO_CHANNEL, 1024); + audio_left = audio_len = &audio_payload_end - &audio_payload; + sbuf.start = &audio_payload; + } + + uint64_t now = io_read(AM_TIMER_UPTIME).us; + for (; f < fend; f ++) { + printf("\033[0;0H"); // reset cursor + for (int y = 0; y < VIDEO_ROW; y++) { + for (int x = 0; x < VIDEO_COL; x++) { + uint8_t p = getbit(f->pixel, y * VIDEO_COL + x); + putch(p ? CHAR_BLACK : CHAR_WHITE); + } + putch('\n'); + } + + if (has_audio) { + int should_play = (AUDIO_FREQ / FPS) * sizeof(int16_t); + if (should_play > audio_left) should_play = audio_left; + while (should_play > 0) { + int len = (should_play > 4096 ? 4096 : should_play); + sbuf.end = sbuf.start + len; + io_write(AM_AUDIO_PLAY, sbuf); + sbuf.start += len; + should_play -= len; + } + audio_left -= should_play; + } + + uint64_t next = now + (1000 * 1000 / FPS); + sleep_until(next); + now = next; + } + return 0; +} diff --git a/kernels/bad-apple/bad-apple.mp4 b/kernels/bad-apple/bad-apple.mp4 new file mode 100644 index 0000000..c96449a Binary files /dev/null and b/kernels/bad-apple/bad-apple.mp4 differ diff --git a/kernels/bad-apple/resources.S b/kernels/bad-apple/resources.S new file mode 100644 index 0000000..7332567 --- /dev/null +++ b/kernels/bad-apple/resources.S @@ -0,0 +1,12 @@ +.section .data +.global video_payload, video_payload_end +.p2align 3 +video_payload: +.incbin VIDEO_FILE +video_payload_end: + +.global audio_payload, audio_payload_end +.p2align 3 +audio_payload: +.incbin AUDIO_FILE +audio_payload_end: