commit 1e185584721712e943acb5744b4ecf3b65472dd0 Author: Vilyaem Date: Mon May 13 08:28:48 2024 -0400 First diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6399ee7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.svcs/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..ae10a8c --- /dev/null +++ b/README.md @@ -0,0 +1,144 @@ +# VNM +Venom (vnm, virtual nano media) is an experimental +image, audio, and video file format. + +It's suppposed to be extremely simple and [suckless](https://suckless.org). +Images are 16 color and run length encoded, It's like 'farbfeld' driven +to its end conclusion. The default color palette is that of TempleOS'. + +__Venom is the best set of multimedia formats in the world.__ + +--- + +## IMAGES + +Magic number letter "V" (86) + +uint8 width and height as a single value +(must be power of two), this is multiplied by 8, max resulting resolution is +1024x1024 +So to get 1024x1024 this value is 128, to get 512x512 you do 64. + +row by row uint8 (color) and uint8 (run length) + +--- + +## AUDIO + +Audio is always 8000hz +Magic number letter "A" (65) +uint8 list of samples. + +--- + +## VIDEO + +Video is at the top, audio at the bottom, Video is 30FPS. +Width and height is unchanging. + +Sequence of "V" images +The audio "A" sequence + +--- + +## TOS COLOR PALETTE + +This will be default for all the programs. + +00. #000000 (Black) 0,0,0 +01. #0000AA (Blue) 0,0,170 +02. #00AA00 (Green) 0,170,0 +03. #00AAAA (Cyan) 0,170,170 +04. #AA0000 (Red) 170,0,0 +05. #AA00AA (Magenta) 170,0,170 +06. #AA5500 (Brown) 170,79,0 +07. #AAAAAA (Light Gray) 170,170,170 +08. #555555 (Dark Gray) 79,79,79 +09. #5555FF (Light Blue) 79,79,255 +10. #55FF55 (Light Green) 79,255,79 +11. #55FFFF (Light Cyan) 79,255,255 +12. #FF5555 (Light Red) 255,79,79 +13. #FF55FF (Light Magenta) 255,79,255 +14. #FFFF55 (Yellow) 255,255,79 +15. #FFFFFF (White) 255,255,255 + +--- + +## Why? + +Multimedia sucks. You may notice that all the files are completely +composed of eight bit integers, this allows for multimedia files to +be easily modified by UNIX utilities in interesting interactions, or +be generated very easily. I can see the feasibility of getting a VNM +file to glitch out, but I don't really care, and it has never +happened in practice. Ive discovered that 16 color isnt a such +a hardship, it's quite liberating, especially with proper dithering +images can look indistinguishable and 'cooler'. The palettes of the programs +can also just be modified to best suite a set of images. +VNM is also perfect for embedded assets in ROMs. + +--- + +## PROGRAMS + +ff2vnm - Convert farbfeld images to vnm images +vnmstat - Program that identifies, validates, and makes stats for a vnm file +vnmnoise - Example program that generates an unoptimized noisy image +vnmbeat - Example program that generates a sound file +vnmcarr - Convert VNM files into C arrays + +VNM is so simple, you can just use your core utils to work +with it. + +Combining images into a video: cat baby.vnm recursion.vnm > slideshow.vnm +Splitting video into images and audio: csplit -z slideshow.vnm /V/ '{*}' + +--- + +## SCRIPTS + +png2vnm.sh - Convert PNG to VNM given png2ff +vid2vnm.sh - Convert video to VNM + + +## PHILANTHROPY + +_official VNM donation fund_ + +Monero (XMR): 48Sxa8J6518gqp4WeGtQ4rLe6SctPrEnnCqm6v6ydjLwRPi9Uh9gvVuUsU2AEDw75meTHCNY8KfU6Txysom4Bn5qPKMJ75w + +Wownero (WOW): WW2L2yC6DMg7GArAH3nqXPA6UBoRogf64GodceqA32SeZQpx27xd6rqN82e36KE48a8SAMSoXDB5WawAgVEFKfkw1Q5KSGfX9 + +If you have philanthropic interest in VNM, contact Vilyaem. + +--- + +## LICENSE + + +CHRISTIAN FREE SOFTWARE LICENSE + CFSL + +This software is free and open source charity ware, users are asked +to donate to the Eastern Orthodox Church by any means. + +Redistribution of this project in source and/or binary forms with/without +modification, are permitted provided that the following conditions are met: + +1. Redistributions must retain this notice, the conditions, and the disclaimer. +2. Redistributions must retain credit to the author, and signage to where the original +work can be found. +3. Redistributions cannot become a part of, in anyway shape or form, part of proprietary +software, or software that is clearly out of line with Christian values. +4. Redistributions must remain free, both in price, and what users may do with the software, +the software must remain public and easily accessible. + +DISCLAIMER + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/bin/ff2vnm b/bin/ff2vnm new file mode 100755 index 0000000..f58e61f Binary files /dev/null and b/bin/ff2vnm differ diff --git a/bin/vnmbeat b/bin/vnmbeat new file mode 100755 index 0000000..4d0fe24 Binary files /dev/null and b/bin/vnmbeat differ diff --git a/bin/vnmcarr b/bin/vnmcarr new file mode 100755 index 0000000..88d0758 Binary files /dev/null and b/bin/vnmcarr differ diff --git a/bin/vnmnoise b/bin/vnmnoise new file mode 100755 index 0000000..81c3c2b Binary files /dev/null and b/bin/vnmnoise differ diff --git a/bin/vnmstat b/bin/vnmstat new file mode 100755 index 0000000..38594be Binary files /dev/null and b/bin/vnmstat differ diff --git a/c.sh b/c.sh new file mode 100755 index 0000000..8215b9c --- /dev/null +++ b/c.sh @@ -0,0 +1,10 @@ +#!/bin/sh +cl +rm bin/* +CC="cc -O3 -std=c89 -Wall -Wpedantic -Wextra -Werror " +$CC programs/ff2vnm.c -o bin/ff2vnm +$CC programs/vnmbeat.c -o bin/vnmbeat +$CC programs/vnmcarr.c -o bin/vnmcarr +$CC programs/vnmnoise.c -o bin/vnmnoise +$CC programs/vnmstat.c -o bin/vnmstat +doas cp bin/* /usr/bin/ diff --git a/examples/baby.ff b/examples/baby.ff new file mode 100644 index 0000000..c3623dd Binary files /dev/null and b/examples/baby.ff differ diff --git a/examples/baby.vnm b/examples/baby.vnm new file mode 100644 index 0000000..9ac56ca Binary files /dev/null and b/examples/baby.vnm differ diff --git a/examples/black.ff b/examples/black.ff new file mode 100644 index 0000000..173a03d Binary files /dev/null and b/examples/black.ff differ diff --git a/examples/black.vnm b/examples/black.vnm new file mode 100644 index 0000000..9558200 Binary files /dev/null and b/examples/black.vnm differ diff --git a/examples/church.ff b/examples/church.ff new file mode 100644 index 0000000..2203d0b Binary files /dev/null and b/examples/church.ff differ diff --git a/examples/church.vnm b/examples/church.vnm new file mode 100644 index 0000000..a038d06 Binary files /dev/null and b/examples/church.vnm differ diff --git a/examples/empire.wav b/examples/empire.wav new file mode 100644 index 0000000..b85a702 Binary files /dev/null and b/examples/empire.wav differ diff --git a/examples/lord.ff b/examples/lord.ff new file mode 100644 index 0000000..6711466 Binary files /dev/null and b/examples/lord.ff differ diff --git a/examples/noise.vnm b/examples/noise.vnm new file mode 100644 index 0000000..010b8d7 Binary files /dev/null and b/examples/noise.vnm differ diff --git a/examples/recursive.ff b/examples/recursive.ff new file mode 100644 index 0000000..2ddde7d Binary files /dev/null and b/examples/recursive.ff differ diff --git a/examples/recursive.vnm b/examples/recursive.vnm new file mode 100644 index 0000000..6283732 Binary files /dev/null and b/examples/recursive.vnm differ diff --git a/programs/ff2vnm.c b/programs/ff2vnm.c new file mode 100644 index 0000000..9e03a10 --- /dev/null +++ b/programs/ff2vnm.c @@ -0,0 +1,156 @@ +/********************************************* +* Description - Convert Farbfeld images to VNM +* Author - Vilyaem +* Date - May 03 2024 +* *******************************************/ + +/*----------PREPROCESSOR----------*/ + +#include +#include + +#define MAXRES 512 + +/*----------DATA STRUCTURES----------*/ + +/*color*/ +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} Color; + +/*----------GLOBALS----------*/ + +Color palette[16] = { + {0, 0, 0}, /*#000000 (Black)*/ + {0, 0, 170}, /*#0000AA (Blue)*/ + {0, 170, 0}, /*#00AA00 (Green)*/ + {0, 170, 170}, /*#00AAAA (Cyan)*/ + {170, 0, 0}, /*#AA0000 (Red)*/ + {170, 0, 170}, /*#AA00AA (Magenta)*/ + {170, 79, 0}, /*#AA5500 (Brown)*/ + {170, 170, 170}, /*#AAAAAA (Light Gray)*/ + {79, 79, 79}, /*#555555 (Dark Gray)*/ + {79, 79, 255}, /*#5555FF (Light Blue)*/ + {79, 255, 79}, /*#55FF55 (Light Green)*/ + {79, 255, 255}, /*#55FFFF (Light Cyan)*/ + {255, 79, 79}, /*#FF5555 (Light Red)*/ + {255, 79, 255}, /*#FF55FF (Light Magenta)*/ + {255, 255, 79}, /*#FFFF55 (Yellow)*/ + {255, 255, 255} /*#FFFFFF (White)*/ +}; + +int i; + +/*----------FUNCTIONS----------*/ + +/********************************************* +* Description - Find closest colour in the palette +* Author - Vilyaem +* Date - May 03 2024 +* *******************************************/ +uint8_t findClosestColor(Color pixel) { + uint8_t closestColor; + int minDistance; + closestColor = 0; + minDistance = 255 * 255 * 3; /* Initialize with max distance value*/ + + for (i = 0; i < 16; i++) { + int dr; + int dg; + int db; + int distance; + + dr = pixel.r - palette[i].r; + dg = pixel.g - palette[i].g; + db = pixel.b - palette[i].b; + distance = dr * dr + dg * dg + db * db; + + if (distance < minDistance) { + minDistance = distance; + closestColor = i; + } + } + + return closestColor; +} + +/********************************************* +* Description - Main +* Author - Vilyaem +* Date - May 03 2024 +* *******************************************/ +int main(int argc, char* argv[]) { + uint32_t width; + uint32_t height; + FILE* output; + FILE* input; + char magic[8]; + Color prevPixel = {0,0,0}; + uint8_t colorCount; + + + if (argc != 3) { + printf("Usage: %s input_image.farbfeld output_image.rle\n", argv[0]); + return 1; + } + + input = fopen(argv[1], "rb"); + if (!input) { + puts("Error: Unable to open input file.\n"); + return 1; + } + + /*Reading header*/ + fread(magic, 1, 8, input); + + /*Forced width and height*/ + width = MAXRES; + height = MAXRES; + + /*Output the RLE header*/ + output = fopen(argv[2], "wb"); + fputc('V', output); /* Magic number*/ + fputc(width / 8, output); /* Actual width*/ + fputc(height / 8, output); /* Actual height*/ + + /*Read and convert each pixel*/ + colorCount = 1; + + for (i = 0; i < (int)width * (int)height; i++) { + uint16_t rgba[4]; + uint8_t currentColor; + Color pixel; + + fread(rgba, sizeof(uint16_t), 4, input); + + /*pixel = (Color){rgba[0] >> 8, rgba[1] >> 8, rgba[2] >> 8};*/ + pixel.r = rgba[0] >> 8; + pixel.g = rgba[1] >> 8; + pixel.b = rgba[2] >> 8; + + currentColor = findClosestColor(pixel); + + if (currentColor == findClosestColor(prevPixel) && colorCount < 64) { /*dont make V and A characters and break files!*/ + colorCount++; + } else { + fputc(findClosestColor(prevPixel), output); + fputc(colorCount, output); + prevPixel = pixel; + colorCount = 1; + } + } + + /*Output the last color run*/ + if (colorCount > 0) { + fputc(findClosestColor(prevPixel), output); + fputc(colorCount, output); + } + + fclose(input); + fclose(output); + + puts("Conversion complete.\n"); + return 0; +} diff --git a/programs/vnmbeat.c b/programs/vnmbeat.c new file mode 100644 index 0000000..9d18c09 --- /dev/null +++ b/programs/vnmbeat.c @@ -0,0 +1,21 @@ +/********************************************* + * Description - VNMBeat, example program + * that generates a sound in VNM + * + * ./vnmbeat > vnmbeat.vnm + * + * Author - Vilyaem + * Date - Apr 28 2024 + * *******************************************/ + +#include + +int main(void){ + int i; + putchar('A'); + for ( i = 0; i < 1000000; i++) + putchar( + ( (i * i ^ i) | ((i % 73) * i*8 & i >> 24)) /*play with this to make music*/ + ); + return 0; +} diff --git a/programs/vnmcarr.c b/programs/vnmcarr.c new file mode 100644 index 0000000..6843808 --- /dev/null +++ b/programs/vnmcarr.c @@ -0,0 +1,30 @@ +/********************************************* + * Description - Convert VNM files to C arrays + * Author - Vilyaem + * Date - May 03 2024 + * *******************************************/ + +/*----------PREPROCESSOR----------*/ +#include + +/*----------FUNCTIONS----------*/ + +/********************************************* + * Description - Main + * Author - Vilyaem + * Date - May 03 2024 + * *******************************************/ +int main(void){ + int c; + puts("/* Generated by VNMCARR */\nuint8_t vnm[] = {"); + while((c = fgetc(stdin)) != EOF){ + if(c % 2 == 0){ /*Avoid the last indice having a comma*/ + printf(",%d",c); + } + else{ + printf("%d",c); + } + } + puts("\n};"); + return 0; +} diff --git a/programs/vnmnoise.c b/programs/vnmnoise.c new file mode 100644 index 0000000..094cbaa --- /dev/null +++ b/programs/vnmnoise.c @@ -0,0 +1,27 @@ +/********************************************* + * Description - Example VNM noise generator + * THis does no attempt to make the output tiny, + * this is a demonstration on how easy it is to produce + * vnm files. + * + * ./vnmnoise > noise.vnm + * + * Author - Vilyaem + * Date - Apr 26 2024 + * *******************************************/ + +#include +#include + +#define RES 1024 /*Our resolution*/ + +int main(void){ + int i; + putchar('V'); + putchar(RES/8); + for(i = 0; i != RES*RES;i++){ + putchar(1); + putchar(i%rand()); + } + return 0; +} diff --git a/programs/vnmopt.c b/programs/vnmopt.c new file mode 100644 index 0000000..c70eef3 --- /dev/null +++ b/programs/vnmopt.c @@ -0,0 +1,27 @@ +/********************************************* + * Description - VNM Image optimizer + * Author - Vilyaem + * Date - May 03 2024 + * *******************************************/ + +/*----------PREPROCESSOR----------*/ +#include + +/*----------FUNCTIONS----------*/ + +/********************************************* + * Description - Main + * Author - Vilyaem + * Date - May 03 2024 + * *******************************************/ +int main(void){ + int c; + int curcolour = 0; + while((c = fgetc(stdin)) != EOF){ + if(c - 1 % 2 == 0){ /*it's run length*/ + } + else { /*it's a colour*/ + curcolour = c; + } + } +} diff --git a/programs/vnmstat.c b/programs/vnmstat.c new file mode 100644 index 0000000..f7e6e38 --- /dev/null +++ b/programs/vnmstat.c @@ -0,0 +1,75 @@ +/********************************************* + * Description - VNM Stat, report and identify on VNM + * files + * + * < file.vnm | ./vnmstat + * + * Author - Vilyaem + * Date - Apr 26 2024 + * *******************************************/ + + +/*----------PREPROCESSOR----------*/ + +#include +#include + +#define IMG 0 +#define AUD 1 +#define VID 2 + +/*----------GLOBALS----------*/ +int c; +int charcnt = 0; +int framecnt = 0; +int mode = -1; +int res = 0; + +/*----------FUNCTIONS----------*/ + +/********************************************* + * Description - Main + * Author - Vilyaem + * Date - Apr 26 2024 + * *******************************************/ +int main(void){ + + /*Recieve file via STDIN*/ + while(c != EOF){ + c = fgetc(stdin); + + /*Determine the type of file*/ + if(charcnt == 0 && c == 'V'){ + mode = IMG; + } + else if(charcnt == 0 && c == 'A'){ + mode = AUD; + } + /*Determine if the image is actually a video*/ + if((mode == IMG && charcnt != 0) && (c == 'V' || c == 'A')){ + mode = VID; + framecnt = 1; /*(counting the first one)*/ + } + /*Determine resolution*/ + if(mode == IMG && charcnt == 1){ + res = c * 8; + } + /*Count up frames*/ + if(mode == VID && c == 'V'){ + framecnt++; + } + + + charcnt++; + } + + /*Print the results*/ + puts("---VNM STATS---"); + switch(mode){ + case IMG: printf("This is an image, it has %d bytes of data, the resolution is %d.\n",charcnt,res); break; + case AUD: printf("This is an audio file, it has %d bytes of data.\n",charcnt); break; + case VID: printf("This is a video, it has %d bytes of data, it has %d frames, the resolution is %d.\n",charcnt,framecnt,res); break; + default:puts("error: bad file");break; + } + return 0; +} diff --git a/scripts/png2vnm.sh b/scripts/png2vnm.sh new file mode 100755 index 0000000..bc8638c --- /dev/null +++ b/scripts/png2vnm.sh @@ -0,0 +1,4 @@ +#!/bin/sh +png2ff < "$1" > "$1.png" +cat "$1.png" | ff2.vnm > "$1.vnm" +rm "$1.png" diff --git a/scripts/vid2vnm.sh b/scripts/vid2vnm.sh new file mode 100755 index 0000000..165d189 --- /dev/null +++ b/scripts/vid2vnm.sh @@ -0,0 +1,20 @@ +#!/bin/sh +clear +input_video="$1" +rm result.vnm +## Convert video to PNG frames at 30 FPS +ffmpeg -r 30 -i "$input_video" frame-%04d.png +ls +## Process the frames into farbfeld format with ff2png +find -type f . -name "*.png" -exec cat {} | ff2png >> {}.ff \; +ls +## Process the farbfeld images to VNM images +find -type f . -name "*.png.ff" -exec ff2vnm {} {}.vnm \; +ls +## Extract audio from video to an 8000hz WAV file +ffmpeg -ar 8000 -ac 1 -i "$input_video" AUDIO.raw +cat *.vnm > result.vnm +echo "A" >> result.vnm +cat AUDIO.wav >> result.vnm +rm frame* +rm AUDIO.wav