diff --git a/README.md b/README.md index 5095da4..0fea756 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # vaporwave generator 旺育栄 + A vaporwave music (+art, +video soon, I promise) generator bodged together using code from various sources. Runs on Python3 ``` -usage: main.py [-h] [-M] [-V] [-i INPUT] +usage: main.py [-h] [-M] [-P] [-V] [-i INPUT] This program takes YouTube URL or title of a song and converts it into vaporwave @@ -10,13 +11,26 @@ vaporwave optional arguments: -h, --help show this help message and exit -M, --music generate v a p o r w a v e music + -P, --picture generate VHS Style image -V, --version show program version -i INPUT, --input INPUT - input url + ``` If the program gives an error for sox, try running `ulimit -n 999'` +## Demo + +### M U S I C + +Linking to Bandcamp soon + +### V H S I M A G E + +![]("assets/in-vhs.jpg") + +![]("assets/out-vhs.jpg") + ## Installation This was tested on macOS Catalina ( so should work on almost all macOS versions). @@ -43,28 +57,38 @@ pip install -r requirements.txt ## Usage -### YouTube URL +### M U S I C + +#### YouTube URL ``` python3 main.py -M -i ``` -### Song Title +#### Song Title ``` python3 main.py -M -i Song Title ``` +### V H S I M A G E S + +`python3 main.py -P -i "image.jpg"` + ## Bugs This project is a result of bodging and therefore has tons of bugs which need to be ironed out ## To-Do -[ ] Move away from using os.system calls, and use Python modules instead ( Looking at you, Sox and aubio) -[ ] Clean the Code -[ ] Add Artwork Generator -[ ] Add Video Generator +[] Move away from using os.system calls, and use Python modules instead ( Looking at you, Sox and aubio) +[] Clean the Code +[] Add Artwork Generator +[x] VHS Picture Styler ( Added in v1.5 ) +[] Add Video Generator +[] Add Custom Date to VHS Styler ## Credits @WJLiddy His repo `Macintech` forms the base code for the music generator -@felipecustodio Using his repo `virtualdreamsbot` YouTube DL code ( Hopefully I will be able to integrate this project as a Telegram Bot) \ No newline at end of file +@felipecustodio Using his repo `virtualdreamsbot` YouTube DL code ( Hopefully I will be able to integrate this project as a Telegram Bot) + +@Ragex04 His repo `VHS_BingImages` forms the base code for the VHS Image Styler \ No newline at end of file diff --git a/VaporSong.py b/VaporSong.py deleted file mode 100644 index bb75646..0000000 --- a/VaporSong.py +++ /dev/null @@ -1,182 +0,0 @@ -import os -import subprocess -import re -from random import randint - -import logzero -from logzero import logger -from logzero import setup_logger - -CONFIDENCE_THRESH = 0.02 - -class VaporSong: - - # Slows down Track - - def slow_down(src, rate, dest): - cmd = "sox -G -D " + src + " " + dest + " speed " + str(rate) - os.system(cmd) - return dest - - # Adds Reverb - - def reverbize(src, dest): - cmd = "sox -G -D " + src + " " + dest + " reverb 100 fade 5 -0 7" # idk what this does tbh, https://stackoverflow.com/a/57767238/8386344 - os.system(cmd) - return dest - - - # Crops "src" from "start" plus "start + dur" and return it in "dest" - def crop(src,dest,start,dur): - cmd = "sox " + src + " " + dest + " trim " + " " + str(start) + " " + str(dur) - os.system(cmd) - - - # Randomly crops a part of the song of at most max_sec_len. - def random_crop(src, max_sec_len, dest): - out = subprocess.check_output(["soxi","-D",src]).rstrip() - f_len = int(float(out)) - if (f_len <= max_sec_len): - os.system("cp " + src + " " + dest) - return - else: - start_region = f_len - max_sec_len - start = randint(0,start_region) - VaporSong.crop(src,dest,start,max_sec_len) - - - # Given a file, returns a list of [beats, confidence], executable based on audibo's test-beattracking.c - # TODO: Move away from executable and use aubio's Python module - def fetchbeats(src): - beat_matrix = [] - if os.name == 'posix': - beats = subprocess.check_output(["noah", "get-beats",src]).rstrip() - else: - beats = subprocess.check_output(["get-beats",src]).rstrip() - beats_ary = beats.splitlines() - for i in beats_ary: - record = i.split() - record[0] = float(record[0])/1000.0 - record[1] = float(record[1]) - beat_matrix.append(record) - return beat_matrix - - # Splits an audio file into beats according to beat_matrix list - - def split_beat(src,beat_matrix): - split_files = [] - for i in range(0,len(beat_matrix)-1): - - if(beat_matrix[i][1] > CONFIDENCE_THRESH): - dur = (beat_matrix[i+1][0] - beat_matrix[i][0]) - out = src.split(".")[0]+str(i)+".wav" - VaporSong.crop(src,out,beat_matrix[i][0],dur) - split_files.append(out) - return split_files - - # Combines a list of sections - - def combine(sections,dest): - tocomb = [] - tocomb.append("sox") - tocomb.append("-G") - for section in sections: - for sample in section: - tocomb.append(sample) - tocomb.append(dest) - tmpFileLimit = len(tocomb) + 256 # in case the program messes up, it does not actually frick up your system - n = str(tmpFileLimit) - #logger.info("Setting file limit to ", n) - os.system("ulimit -n " + n) - subprocess.check_output(tocomb) - return dest - - # Arbitrarily groups beats into lists of 4, 6, 8, or 9, perfect for looping. - - def generate_sections(ary): - sections = [] - beats = [4,6,8,9] - index = 0 - while(index != len(ary)): - current_beat = beats[randint(0,len(beats)-1)] - new_section = [] - while((current_beat != 0) and (index != len(ary))): - new_section.append(ary[index]) - current_beat -= 1 - index += 1 - sections.append(new_section) - return sections - - - # given a list of sections, selects some of them and duplicates them, perfect for that vaporwave looping effect - def dup_sections(sections): - new_section = [] - for section in sections: - new_section.append(section) - if(randint(0,1) == 0): - new_section.append(section) - return new_section - - # a passage is a list of sections. This takes some sections and groups them into passages. - - def make_passages(sections): - passages = [] - index = 0 - while(index != len(sections)): - passage_len = randint(1,4) - passage = [] - while(index != len(sections) and passage_len > 0): - passage.append(sections[index]) - index += 1 - passage_len -= 1 - passages.append(passage) - return passages - - # Given all of our passages, picks some of them and inserts them into a list some number of times. - - def reorder_passages(passages): - new_passages = [] - passage_count = randint(5,12) - while(passage_count != 0): - passage = passages[randint(0,len(passages)-1)] - passage_count -= 1 - dup = randint(1,4) - while(dup != 0): - dup -= 1 - new_passages.append(passage) - return new_passages - - # converts a list of passages to a list of sections. - - def flatten(passages): - sections = [] - for passage in passages: - for section in passage: - sections.append(section) - return sections - - # It's all coming together - - def vaporize_song(fname, title): - logger.info("Slowing down the music") - VaporSong.slow_down(fname, 0.7, "beats/out.wav") - #logger.info("Cropping") - #VaporSong.random_crop("beats/out.wav",150,"beats/outcrop.wav") - logger.info("Doing Beat Analysis") - bm = VaporSong.fetchbeats("beats/out.wav") - logger.info("Split into beats") - splitd = VaporSong.split_beat("beats/out.wav",bm) - #group beats to sections - logger.info("Divide into sections") - sections = VaporSong.generate_sections(splitd) - logger.info("Duping Sections") - sdup = VaporSong.dup_sections(sections) - # group sections into passages - paslist = VaporSong.make_passages(sdup) - # reorder packages - pasloop = VaporSong.reorder_passages(paslist) - sectionflat = VaporSong.flatten(pasloop) - logger.info("Mastering & Reverbing") - VaporSong.combine(sectionflat,"beats/out_norev.wav") - VaporSong.reverbize("beats/out_norev.wav","./" + (re.sub(r"\W+|_", " ", title)).replace(" ","_") + ".wav") - logger.info("Generated V A P O R W A V E") diff --git a/assets/in-vhs.jpg b/assets/in-vhs.jpg new file mode 100644 index 0000000..7bcafb0 Binary files /dev/null and b/assets/in-vhs.jpg differ diff --git a/assets/out-vhs.jpg b/assets/out-vhs.jpg new file mode 100644 index 0000000..9637d5c Binary files /dev/null and b/assets/out-vhs.jpg differ diff --git a/main.py b/main.py index de93106..50a0d90 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,5 @@ -from VaporSong import VaporSong +from src.VaporSong import VaporSong +from src.VHSImage import generateVHSStyle import os import sys import youtube_dl @@ -18,20 +19,28 @@ text = 'This program takes YouTube URL or title of a song and converts it into v parser = argparse.ArgumentParser(description = text) parser.add_argument("-M", "--music", help="generate v a p o r w a v e music", action="store_true") +parser.add_argument("-P", "--picture", help="generate VHS Style image", action="store_true") parser.add_argument("-V", "--version", help="show program version", action="store_true") -parser.add_argument("-i", "--input", help="input url") +parser.add_argument("-i", "--input") + args = parser.parse_args() +music = False +picture = False + if args.version: print("vaporwave generator 旺育栄", version) exit if args.music: music = True +elif args.picture: + picture = True if args.input: query = args.input else: - query = input("Enter target song's name or YouTube URL: ") + parser.print_help() + exit MAX_DURATION = 600 # In-case the program finds a compilation youtube_urls = ('youtube.com', 'https://www.youtube.com/', 'http://www.youtube.com/', 'http://youtu.be/', 'https://youtu.be/', 'youtu.be') @@ -149,3 +158,6 @@ for s in sys.argv: if music: name, title = download_file(query) gen_vapor(name, title) +elif picture: + generateVHSStyle(query,"out.jpg") + \ No newline at end of file