Spaces:
Runtime error
Runtime error
| from . import main | |
| import numpy as np | |
| # L L L L L L L L L | |
| def generate(song, difficulties = [0.2, 0.1, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025], lib='madmom.MultiModelSelectionProcessor', caching=True, log = True, output = '', add_peaks = True): | |
| # for i in difficulties: | |
| # if i<0.005: print(f'Difficulties < 0.005 may result in broken beatmaps, found difficulty = {i}') | |
| if lib.lower == 'stunlocked': add_peaks = False | |
| if not isinstance(song, main.song): song = main.song(song) | |
| if log is True: print(f'Using {lib}; ', end='') | |
| filename = song.path.replace('\\', '/').split('/')[-1] | |
| if ' - ' in filename and len(filename.split(' - '))>1: | |
| artist = filename.split(' - ')[0] | |
| title = ' - '.join(filename.split(' - ')[1:]) | |
| else: | |
| artist = '' | |
| title = filename | |
| if caching is True: | |
| audio_id=hex(len(song.audio[0])) | |
| import os | |
| if not os.path.exists('beat_manipulator/beatmaps'): | |
| os.mkdir('beat_manipulator/beatmaps') | |
| cacheDir="beat_manipulator/beatmaps/" + filename + "_"+lib+"_"+audio_id+'.txt' | |
| try: | |
| beatmap=np.loadtxt(cacheDir) | |
| if log is True: print('loaded cached beatmap.') | |
| except OSError: | |
| if log is True:print("beatmap hasn't been generated yet. Generating...") | |
| beatmap = None | |
| if beatmap is None: | |
| if 'madmom' in lib.lower(): | |
| from collections.abc import MutableMapping, MutableSequence | |
| import madmom | |
| assert len(song.audio[0])>song.sr*2, f'Audio file is too short, len={len(song.audio[0])} samples, or {len(song.audio[0])/song.sr} seconds. Minimum length is 2 seconds, audio below that breaks madmom processors.' | |
| if lib=='madmom.RNNBeatProcessor': | |
| proc = madmom.features.beats.RNNBeatProcessor() | |
| beatmap = proc(madmom.audio.signal.Signal(song.audio.T, song.sr)) | |
| elif lib=='madmom.MultiModelSelectionProcessor': | |
| proc = madmom.features.beats.RNNBeatProcessor(post_processor=None) | |
| predictions = proc(madmom.audio.signal.Signal(song.audio.T, song.sr)) | |
| mm_proc = madmom.features.beats.MultiModelSelectionProcessor(num_ref_predictions=None) | |
| beatmap= mm_proc(predictions)*song.sr | |
| beatmap/= np.max(beatmap) | |
| elif lib=='stunlocked': | |
| spikes = np.abs(np.gradient(np.clip(song.audio[0], -1, 1)))[:int(len(song.audio[0]) - (len(song.audio[0])%int(song.sr/100)))] | |
| spikes = spikes.reshape(-1, (int(song.sr/100))) | |
| spikes = np.asarray(list(np.max(i) for i in spikes)) | |
| if len(beatmap) > len(spikes): beatmap = beatmap[:len(spikes)] | |
| elif len(spikes) > len(beatmap): spikes = spikes[:len(beatmap)] | |
| zeroing = 0 | |
| for i in range(len(spikes)): | |
| if zeroing > 0: | |
| if spikes[i] <= 0.1: zeroing -=1 | |
| spikes[i] = 0 | |
| elif spikes[i] >= 0.1: | |
| spikes[i] = 1 | |
| zeroing = 7 | |
| if spikes[i] <= 0.1: spikes[i] = 0 | |
| beatmap = spikes | |
| if caching is True: np.savetxt(cacheDir, beatmap) | |
| if add_peaks is True: | |
| spikes = np.abs(np.gradient(np.clip(song.audio[0], -1, 1)))[:int(len(song.audio[0]) - (len(song.audio[0])%int(song.sr/100)))] | |
| spikes = spikes.reshape(-1, (int(song.sr/100))) | |
| spikes = np.asarray(list(np.max(i) for i in spikes)) | |
| if len(beatmap) > len(spikes): beatmap = beatmap[:len(spikes)] | |
| elif len(spikes) > len(beatmap): spikes = spikes[:len(beatmap)] | |
| zeroing = 0 | |
| for i in range(len(spikes)): | |
| if zeroing > 0: | |
| if spikes[i] <= 0.1: zeroing -=1 | |
| spikes[i] = 0 | |
| elif spikes[i] >= 0.1: | |
| spikes[i] = 1 | |
| zeroing = 7 | |
| if spikes[i] <= 0.1: spikes[i] = 0 | |
| else: spikes = None | |
| def _process(song: main.song, beatmap, spikes, threshold): | |
| '''ඞ''' | |
| if add_peaks is True: beatmap += spikes | |
| hitmap=[] | |
| actual_samplerate=int(song.sr/100) | |
| beat_middle=int(actual_samplerate/2) | |
| for i in range(len(beatmap)): | |
| if beatmap[i]>threshold: hitmap.append(i*actual_samplerate + beat_middle) | |
| hitmap=np.asarray(hitmap) | |
| clump=[] | |
| for i in range(len(hitmap)-1): | |
| #print(i, abs(song.beatmap[i]-song.beatmap[i+1]), clump) | |
| if abs(hitmap[i] - hitmap[i+1]) < song.sr/16 and i != len(hitmap)-2: clump.append(i) | |
| elif clump!=[]: | |
| clump.append(i) | |
| actual_time=hitmap[clump[0]] | |
| hitmap[np.array(clump)]=0 | |
| #print(song.beatmap) | |
| hitmap[clump[0]]=actual_time | |
| clump=[] | |
| hitmap=hitmap[hitmap!=0] | |
| return hitmap | |
| osufile=lambda title,artist,version: ("osu file format v14\n" | |
| "\n" | |
| "[General]\n" | |
| f"AudioFilename: {song.path.split('/')[-1]}\n" | |
| "AudioLeadIn: 0\n" | |
| "PreviewTime: -1\n" | |
| "Countdown: 0\n" | |
| "SampleSet: Normal\n" | |
| "StackLeniency: 0.5\n" | |
| "Mode: 0\n" | |
| "LetterboxInBreaks: 0\n" | |
| "WidescreenStoryboard: 0\n" | |
| "\n" | |
| "[Editor]\n" | |
| "DistanceSpacing: 1.1\n" | |
| "BeatDivisor: 4\n" | |
| "GridSize: 8\n" | |
| "TimelineZoom: 1.6\n" | |
| "\n" | |
| "[Metadata]\n" | |
| f"Title:{title}\n" | |
| f"TitleUnicode:{title}\n" | |
| f"Artist:{artist}\n" | |
| f"ArtistUnicode:{artist}\n" | |
| f'Creator:{lib} + BeatManipulator\n' | |
| f'Version:{version} {lib}\n' | |
| 'Source:\n' | |
| 'Tags:BeatManipulator\n' | |
| 'BeatmapID:0\n' | |
| 'BeatmapSetID:-1\n' | |
| '\n' | |
| '[Difficulty]\n' | |
| 'HPDrainRate:4\n' | |
| 'CircleSize:4\n' | |
| 'OverallDifficulty:5\n' | |
| 'ApproachRate:10\n' | |
| 'SliderMultiplier:3.3\n' | |
| 'SliderTickRate:1\n' | |
| '\n' | |
| '[Events]\n' | |
| '//Background and Video events\n' | |
| '//Break Periods\n' | |
| '//Storyboard Layer 0 (Background)\n' | |
| '//Storyboard Layer 1 (Fail)\n' | |
| '//Storyboard Layer 2 (Pass)\n' | |
| '//Storyboard Layer 3 (Foreground)\n' | |
| '//Storyboard Layer 4 (Overlay)\n' | |
| '//Storyboard Sound Samples\n' | |
| '\n' | |
| '[TimingPoints]\n' | |
| '0,140.0,4,1,0,100,1,0\n' | |
| '\n' | |
| '\n' | |
| '[HitObjects]\n') | |
| # remove the clumps | |
| #print(self.beatmap) | |
| #print(self.beatmap) | |
| #print(len(osumap)) | |
| #input('banana') | |
| import shutil, os | |
| if os.path.exists('beat_manipulator/temp'): shutil.rmtree('beat_manipulator/temp') | |
| os.mkdir('beat_manipulator/temp') | |
| hitmap=[] | |
| import random | |
| for difficulty in difficulties: | |
| for i in range(4): | |
| #print(i) | |
| this_difficulty=_process(song, beatmap, spikes, difficulty) | |
| hitmap.append(this_difficulty) | |
| for k in range(len(hitmap)): | |
| osumap=np.vstack((hitmap[k],np.zeros(len(hitmap[k])),np.zeros(len(hitmap[k])))).T | |
| difficulty= difficulties[k] | |
| for i in range(len(osumap)-1): | |
| if i==0:continue | |
| dist=(osumap[i,0]-osumap[i-1,0])*(1-(difficulty**0.3)) | |
| if dist<1000: dist=0.005 | |
| elif dist<2000: dist=0.01 | |
| elif dist<3000: dist=0.015 | |
| elif dist<4000: dist=0.02 | |
| elif dist<5000: dist=0.25 | |
| elif dist<6000: dist=0.35 | |
| elif dist<7000: dist=0.45 | |
| elif dist<8000: dist=0.55 | |
| elif dist<9000: dist=0.65 | |
| elif dist<10000: dist=0.75 | |
| elif dist<12500: dist=0.85 | |
| elif dist<15000: dist=0.95 | |
| elif dist<20000: dist=1 | |
| #elif dist<30000: dist=0.8 | |
| prev_x=osumap[i-1,1] | |
| prev_y=osumap[i-1,2] | |
| if prev_x>0: prev_x=prev_x-dist*0.1 | |
| elif prev_x<0: prev_x=prev_x+dist*0.1 | |
| if prev_y>0: prev_y=prev_y-dist*0.1 | |
| elif prev_y<0: prev_y=prev_y+dist*0.1 | |
| dirx=random.uniform(-dist,dist) | |
| diry=dist-abs(dirx)*random.choice([-1, 1]) | |
| if abs(prev_x+dirx)>1: dirx=-dirx | |
| if abs(prev_y+diry)>1: diry=-diry | |
| x=prev_x+dirx | |
| y=prev_y+diry | |
| #print(dirx,diry,x,y) | |
| #print(x>1, x<1, y>1, y<1) | |
| if x>1: x=0.8 | |
| if x<-1: x=-0.8 | |
| if y>1: y=0.8 | |
| if y<-1: y=-0.8 | |
| #print(dirx,diry,x,y) | |
| osumap[i,1]=x | |
| osumap[i,2]=y | |
| osumap[:,1]*=300 | |
| osumap[:,1]+=300 | |
| osumap[:,2]*=180 | |
| osumap[:,2]+=220 | |
| file=osufile(artist, title, difficulty) | |
| for j in osumap: | |
| #print('285,70,'+str(int(int(i)*1000/self.samplerate))+',1,0') | |
| file+=f'{int(j[1])},{int(j[2])},{str(int(int(j[0])*1000/song.sr))},1,0\n' | |
| with open(f'beat_manipulator/temp/{artist} - {title} (BeatManipulator {difficulty} {lib}].osu', 'x', encoding="utf-8") as f: | |
| f.write(file) | |
| from . import io | |
| import shutil, os | |
| shutil.copyfile(song.path, 'beat_manipulator/temp/'+filename) | |
| shutil.make_archive('beat_manipulator_osz', 'zip', 'beat_manipulator/temp') | |
| outputname = io._outputfilename(path = output, filename = song.path, suffix = ' ('+lib + ')', ext = 'osz') | |
| if not os.path.exists(outputname): | |
| os.rename('beat_manipulator_osz.zip', outputname) | |
| if log is True: print(f'Created `{outputname}`') | |
| else: print(f'{outputname} already exists!') | |
| shutil.rmtree('beat_manipulator/temp') | |
| return outputname |