public static IEnumerable <FFmpegCommand> BuildFFmpegCommandSeries( FFmpegInput inputVideo, FFmpegOutput outputFile, DirectoryInfo tempFilesFolder, IEnumerable <TaggedBeat> taggedBeats, BeatPositioner beatPositioner, int approxGlowsPerStage ) { ErrorUtils.ThrowIfArgNull(inputVideo, nameof(inputVideo)); ErrorUtils.ThrowIfArgNull(outputFile, nameof(outputFile)); ErrorUtils.ThrowIfArgNull(taggedBeats, nameof(taggedBeats)); ErrorUtils.ThrowIfArgNull(beatPositioner, nameof(beatPositioner)); ErrorUtils.ThrowIfArgLessThan(approxGlowsPerStage, 1, nameof(approxGlowsPerStage)); var beatGroupInfos = GetBeatGroupInfos(inputVideo, outputFile, tempFilesFolder, taggedBeats, approxGlowsPerStage); return(beatGroupInfos.Select( (x, i) => GlowOverlayCommandBuilder.BuildFFmpegCommand( x.InputFile, x.OutputFile, x.BeatGroup, beatPositioner ) )); }
/// <summary> /// /// </summary> /// <param name="inputVideo"></param> /// <param name="outputFile"></param> /// <param name="taggedBeats"></param> /// <param name="beatPositioner"></param> /// <param name="approxGlowsPerStage"> /// Multiple glows in a single beat cannot be divided, so in these cases this value may be exceeded. /// For the last stage, this value will not be reached if there are too few glows remaining. /// </param> /// <returns></returns> public static string BuildBatchCommand( FFmpegInput inputVideo, FFmpegOutput outputFile, IEnumerable <TaggedBeat> taggedBeats, BeatPositioner beatPositioner, int approxGlowsPerStage ) { var tempFilesFolder = new DirectoryInfo( Path.Combine( Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()) ) ); tempFilesFolder.Create(); var ffmpegCommands = BuildFFmpegCommandSeries( inputVideo, outputFile, tempFilesFolder, taggedBeats, beatPositioner, approxGlowsPerStage ); return( string.Join( " && ", ffmpegCommands ) + $" & DEL /P \"{tempFilesFolder.FullName}\"" //Gives the user a prompt before deleing, and empties the folder + $" && RMDIR \"{tempFilesFolder.FullName}\"" //Doesn't prompt, and only deletes the folder if it's empty ); }
public IndependantGlowSeries(ImmutableList <TaggedBeat> beats, BeatPositioner beatPositioner) : this( beats : ErrorUtils.ThrowIfArgNull(beats, nameof(beats)), glowStartTime : beats.Min( b => b.Tags.OfType <Glow>().Min( g => beatPositioner.BeatToTime(b.Beat) - g.FadeInTime ) ), glowEndTime : beats.Max( b => b.Tags.OfType <Glow>().Max( g => beatPositioner.BeatToTime(b.Beat) + g.FadeOutTime ) ) ) { }
private static IEnumerable <FFmpegCommand> BuildCutGlowOverlayCommands( FFmpegInput cutVideo, double cutStartTime, double cutEndTime, IEnumerable <TaggedBeat> cutBeats, BeatPositioner beatPositioner, DirectoryInfo tempFilesFolder, int approxGlowsPerSubstage, out FFmpegOutput glowOverlayedCutVideo ) { glowOverlayedCutVideo = new FFmpegOutput( file: new FileInfo( Path.Combine( tempFilesFolder.FullName, Path.ChangeExtension( Path.GetRandomFileName(), FFmpegOutput.LosslessOutputExtension ) ) ), modifiers: FFmpegOutput.LosslessOutputOptions ); //?// double cutFirstBeatTime = cutBeats.Min(b => beatPositioner.BeatToTime(b.Beat)); Debug.WriteLine("cutStartTime: " + cutStartTime + ", beatPositioner.FirstBeat: " + beatPositioner.FirstBeat + ", first beat beat-time: " + cutBeats.First().Beat); var newBP = new BeatPositioner( firstBeat: beatPositioner.FirstBeat - cutStartTime, interval: beatPositioner.Interval, barLength: beatPositioner.BarLength ); Debug.WriteLine("beatPositioner.FirstBeat - cutStartTime: " + (beatPositioner.FirstBeat - cutStartTime) + ", newBP.FirstBeat: " + newBP.FirstBeat); return(StaggeredGlowOverlayCommandBuilder.BuildFFmpegCommandSeries( inputVideo: cutVideo, outputFile: glowOverlayedCutVideo, tempFilesFolder: tempFilesFolder, taggedBeats: cutBeats, beatPositioner: newBP, approxGlowsPerStage: approxGlowsPerSubstage )); }
public static string BuildBatchCommand( FFmpegInput inputVideo, FFmpegOutput outputFile, IEnumerable <TaggedBeat> taggedBeats, BeatPositioner beatPositioner, int approxGlowsPerCut, int approxGlowsPerSubstage ) { var tempFilesFolder = new DirectoryInfo( Path.Combine( Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()) ) ); tempFilesFolder.Create(); var ffmpegCommands = BuildFFmpegCommandSeries( inputVideo, outputFile, tempFilesFolder, taggedBeats, beatPositioner, approxGlowsPerCut, approxGlowsPerSubstage ); return( // && == proceed if previous command succeeded, & == proceed regardless of success "ECHO Started at %DATE% %TIME%" + Environment.NewLine + string.Join( Environment.NewLine, ffmpegCommands ) + Environment.NewLine + $"ECHO Finished processing at %DATE% %TIME%" //TODO: Fix the fact that this is evaluated at the start of the command, not when it's relevant + Environment.NewLine + $"DEL /P \"{tempFilesFolder.FullName}\"" //Gives the user a prompt before deleing, and empties the folder + Environment.NewLine + $"RMDIR \"{tempFilesFolder.FullName}\"" //Doesn't prompt, and only deletes the folder if it's empty + Environment.NewLine + $"ECHO Exited at %DATE% %TIME%" ); }
//Note: Use FFmpegInput and FFmpegOutput instead of FileInfos so that //codec information and other options can be easily passed in by the caller. public static FFmpegCommand BuildFFmpegCommand( FFmpegInput inputVideo, FFmpegOutput outputFile, IEnumerable <TaggedBeat> taggedBeats, BeatPositioner beatPositioner ) { ErrorUtils.ThrowIfArgNull(inputVideo, nameof(inputVideo)); ErrorUtils.ThrowIfArgNull(outputFile, nameof(outputFile)); ErrorUtils.ThrowIfArgNull(taggedBeats, nameof(taggedBeats)); ErrorUtils.ThrowIfArgNull(beatPositioner, nameof(beatPositioner)); var glowTypeInfos = GetGlowTypeInfos(taggedBeats); int totalGlows = glowTypeInfos.Sum(x => x.Value.count); var inputs = GetInputs(inputVideo, glowTypeInfos).ToImmutableList(); return(new FFmpegCommand( inputs: GetInputs(inputVideo, glowTypeInfos).ToImmutableList(), filterGraph: new FFmpegComplexFilterGraph( ImmutableList.CreateRange( Enumerable.Concat( GetGlowDuplicatorFilterChains(glowTypeInfos), GetGlowModifyAndOverlayFilterChains(glowTypeInfos, taggedBeats, beatPositioner) ) ) ), otherMidOptions: ImmutableList.Create( new FFmpegOption("pix_fmt", "yuv420p"), new FFmpegOption("c:a", "copy") // new FFmpegOption("preset", "ultrafast") ), outputs: ImmutableList.Create( outputFile ), otherFinalOptions: ImmutableList.Create <FFmpegOption>() )); }
/// <summary> /// /// </summary> /// <param name="beats">Does not need to be sorted</param> /// <param name="beatPositioner"></param> /// <param name="targetSize"></param> /// <returns> /// Note: Will be sorted by <see cref="GlowStartTime"/> (and therefore /// also <see cref="GlowEndTime"/>, as they can't overlap) /// </returns> public static List <IndependantGlowSeries> Split(IEnumerable <TaggedBeat> beats, BeatPositioner beatPositioner, int targetSize) { if (beats == null) { throw new ArgumentNullException(nameof(beats)); } if (beatPositioner == null) { throw new ArgumentNullException(nameof(beatPositioner)); } if (beats == null) { throw new ArgumentNullException(nameof(beats)); } var glowSeriesList = new List <IndependantGlowSeries>(); foreach (var beat in beats) { double beatTime = beatPositioner.BeatToTime(beat.Beat); // var glowEndTime = beats[i].Tags.OfType<Glow>().Max(g => beatTime + g.FadeOutTime); var glows = beat.Tags.OfType <Glow>(); var glowStartTime = beatTime - glows.Max(g => g.FadeInTime); var glowEndTime = beatTime + glows.Max(g => g.FadeOutTime); // - Loop through all existing glow series. // - For the first one that overlaps with the current beat, // add the current beat to it (and expand the glow start/end times as appropriate) // - For each subsequent one that overlaps, add it to the first // one that overlapped (and expand the glow start/end times as appropriate) // - Then set the index the subsquent overlapping series was at to Empty (equiv. of null) // - After the looping, remove all Empty entries from the glow series list // - Finally, if the beat did not overlap with any existing glow series, // add a new glow series with just that beat. // - This design allows any IEnumerable to be used. In contrast, a design that looked ahead // through the subsequent elements to check if they overlapped would only work with an // IList (as it is not advisable to enumerate through an IEnumerable multiple times, as // it could be performing some complex query or taking data from a database for all we know) // - This should (hopefully) be less than O(n^2) when there's a decent amount of overlapping // (the null-entry-removal step might complicate it, idk) int firstOverlapIndex = -1; for (int gsIndex = 0; gsIndex < glowSeriesList.Count; gsIndex++) { bool overlaps = ( glowSeriesList[gsIndex].GlowEndTime >= glowStartTime && glowSeriesList[gsIndex].GlowStartTime <= glowEndTime ); if (overlaps) { if (firstOverlapIndex < 0) { firstOverlapIndex = gsIndex; glowSeriesList[gsIndex] = glowSeriesList[gsIndex].AddAndExpand( beats: new[] { beat }, glowStartTime: glowStartTime, glowEndTime: glowEndTime ); } else { glowSeriesList[firstOverlapIndex] = glowSeriesList[firstOverlapIndex].AddAndExpand( beats: glowSeriesList[gsIndex].Beats, glowStartTime: glowSeriesList[gsIndex].GlowStartTime, glowEndTime: glowSeriesList[gsIndex].GlowStartTime ); glowSeriesList[gsIndex] = Empty; } } } RemoveAllUnordered(glowSeriesList, x => x.IsEmpty); // ^ Do this each outer loop to avoid the list getting overly long if (firstOverlapIndex < 0) { glowSeriesList.Add( new IndependantGlowSeries( beats: ImmutableList.Create(beat), glowStartTime: glowStartTime, glowEndTime: glowEndTime ) ); } // if ( // beats // .Select((taggedBeat, index) => (taggedBeat, index)) // .Skip(beatIndex + 1) // .TryGetLast( // x => x.taggedBeat.Tags.OfType<Glow>().Any( // g => beatPositioner.BeatToTime(x.taggedBeat.Beat) - g.FadeInTime <= lastBeatGlowEndTime // ), // out var lastOverlap // ) // ) { // // } // // beatIndex++; } glowSeriesList.Sort((x, y) => x.GlowStartTime.CompareTo(y.GlowStartTime)); GroupToMeetTargetSize(glowSeriesList, targetSize); return(glowSeriesList); }
static void SyncAudioVideo() { const double firstBeatVideoPos = 16.03; //13.70; const double firstBeatAudioPos = 37.365; //TODO: ^ think this should actually be 37.675 const double beatInterval = ( //1st manual counting attempt: // 0.26077241379310344827586206896552 //(75.177 - 37.365)/145 (my own measurements & counting - I think I miscounted or something) //Online lookup: // 128 BPM. // Results in interval of 0.46875s (exactly) // Based on: // - https://www.audiokeychain.com/track/tgi/laidback-luke-peking-duk-mufasa // - https://tunebat.com/Info/Mufasa-Original-Mix-Laidback-Luke-Peking-Duck/49mTyByYvtaQwedg3VM6ky // - https://www.beatport.com/track/mufasa-original-mix/6319471 //Due to possible innacuraccy in the results, I then did some more manual measurements: //2nd manual counting attempt: // 76 beats in 44.918 seconds = 101.5183222761476 bpm = interval of 0.59102631578947s //Completely wrong, it was meant to be 96 beats //3rd manual counting attempt: // 96 beats in 44.914 seconds (37.673...82.588) = 128.24509061762479405085274079352 bpm = interval of 0.46785416666666666666666666666665s //1st attempt checking the bpm of the build up of the song: // 80 beats in 37.495 seconds (00.178...37.673) = 128.0170689425256700893452460328 bpm // .'. should be safe to assume bpm is constant throughout song (unless results differ significantly) //4th manual counting attempt: // 212 beats in 99.444 seconds (82.588...182.032) = 127.91118619524556534330879691082 bpm = interval of 0.46907547169811320754716981132077s //5th manual counting attempt: // 212 + 96 + 80 = 388 beats in 181.854 seconds (00.178...182.032) = 128.01478108812563924906793361708 bpm = interval of 0.46869587628865979381443298969071 0.46869587628865979381443298969071 //5th manual count ); const int barLength = 4; var beats = new BeatPositioner( firstBeat: firstBeatAudioPos, interval: beatInterval, barLength: barLength ); //Intro music: // https://open.spotify.com/track/1oDAFTOXZGSQedBa6hXGhT?si=jIQijymKSayXfa-l_erSkw (sugar plum v1) // 00:27 to 00:43 // 01:37 to 01:55 // https://open.spotify.com/track/7a9g6fPCrxdZ8p4tLCWNdR?si=GrxBoHLVT5mNm7jjYcNEDQ (sugar plum v2) // 00:30 to 00:48 // 01:44 to 02:01 // https://www.youtube.com/watch?v=45lNvNsdPLc (sugar plum v3) // 00:26 to 00:41 (use this one) (15 seconds) // 01:30 to 01:45 WmmProject project = VideoMusicSync.Sync( video: new FileInfo(@"C:\Users\Alex\Pictures\From Phone\Pictures\Phone\Personal\Mum Sleeping TV\Z1_VID_20180425_205156-face-1-blurred-by-youtube-via-clipconverter.mp4"), audio: new FileInfo(@"C:\Users\Alex\Pictures\Meme Templates\Meme Making\Mum Headbanging\Peking Duk & Laidback Luke - Mufasa (Radio Edit) - edit 4.wav"), videoLength: 344.91, audioLength: 183.948, syncPoints: ( new SyncPointCollection( new BeatSyncSequence( firstSyncPoint: new SyncPoint(firstBeatVideoPos, firstBeatAudioPos), beatInterval: beatInterval, barLength: barLength ) .SkipByBeats(2.0 / 3.0).SyncWithVideo(16.49) //creep forward .SkipToBeat(Beat.NextBeat).SyncWithVideo(17.83) //slam forward .SkipByBeats(2.0 / 3.0).SyncWithVideo(19.30) //sideways nod .SkipToBeat(Beat.NextBeat).SyncWithVideo(21.20) //slam back .SkipByBeats(2.0 / 3.0).SyncWithVideo(22.23) //slow small nod forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(23.17) //small slam back .SkipByBeats(2.0 / 3.0).SyncWithVideo(24.03) //creep forward .SkipToBeat(Beat.NextBeat).SyncWithVideo(24.97) //slam forward .SkipByBeats(1.0 / 3.0).SyncWithVideo(27.30) //creep back & sideways .SkipByBeats(1.0 / 3.0).SyncWithVideo(28.83) //slam back on inserted beat .SkipToBeat(Beat.NextBeat) .SkipByBeats(1.0 / 3.0).SyncWithVideo(29.00) //creep forwards until inserted beat .SkipToBeat(Beat.NextBeat).SyncWithVideo(30.63) //slam forwards from inserted beat to actual beat .SkipByBeats(2.0 / 3.0).SyncWithVideo(33.20) //slow sideways nod .SkipToBeat(Beat.NextBeat).SyncWithVideo(35.27) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(35.70) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(36.73) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(37.80) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(40.43) //slam backwards //40.83 .SkipByBeats(2.0 / 3.0).SyncWithVideo(41.20) //stay still then creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(42.30) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(43.47) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(44.33) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(45.13) //hover .SkipToBeat(Beat.NextBeat).SyncWithVideo(45.97) //slam further backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(46.27) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(46.90) //slam forwards //Normal beat, replaced by synced to notes version //.SkipByBeats(2.0/3.0 ).SyncWithVideo( 49.37) //hover & creep backwards //.SkipToBeat (Beat.NextBeat).SyncWithVideo( 50.90) //slam backwards //.SkipByBeats(2.0/3.0 ).SyncWithVideo( 51.27) //creep forwards //.SkipToBeat (Beat.NextBeat).SyncWithVideo( 52.17) //slam forwards //.SkipByBeats(2.0/3.0 ).SyncWithVideo( 53.67) //sideways nod //.SkipToBeat (Beat.NextBeat).SyncWithVideo( 54.97) //slam backwards //No idea but this didn't sync up properly with the beats. The next bit worked instead //.SkipToBeat (Beat.NextBeat) //.SkipByBeats(1.0/3.0 ).SyncWithVideo( 47.23) //almost freeze - extended //49.47 //.SkipByBeats(1.0/3.0 ).SyncWithVideo( 50.90) //slam backwards on note //.SkipToBeat (Beat.NextBeat).SyncWithVideo( 52.17) //slam forwards on beat //.SkipByBeats(1.0/3.0 ).SyncWithVideo( 53.67) //sideways nod //.SkipByBeats(1.0/3.0 ).SyncWithVideo( 54.97) //slam backwards on note //.SkipToBeat (Beat.NextBeat).SyncWithVideo( 56.07) //slam forwards on beat //I have no idea why this bit works but it does .SkipToBeat(Beat.NextBeat).SyncWithVideo(47.23) //almost freeze - extended .SkipByBeats(1.0 / 3.0).SyncWithVideo(50.90) //slam backwards on note .SkipByBeats(1.0 / 3.0).SyncWithVideo(52.17) //slam forwards on beat .SkipToBeat(Beat.NextBeat).SyncWithVideo(53.67) //sideways nod .SkipByBeats(1.0 / 3.0).SyncWithVideo(54.97) //slam backwards on note .SkipByBeats(1.0 / 3.0).SyncWithVideo(56.07) //slam forwards on beat .SkipToBeat(Beat.NextBeat).SyncWithVideo(56.83) //creep backwards .SkipByBeats(1.0 / 3.0).SyncWithVideo(58.80) //slam backwards on note .SkipByBeats(1.0 / 3.0).SyncWithVideo(61.17) //slam forwards on beat //Back to normal from here, makes sense again .SkipByBeats(2.5 / 3.0).SyncWithVideo(62.00) //creep backwards //This one looked awkward as two slams back in a row, so I made it one stuttered //slam (as there's also a wobble, which adds a third pause) //.SkipByBeats(2.5/3.0 ).SyncWithVideo( 64.40) //wobble & creep backwards //.SkipToBeat (Beat.NextBeat).SyncWithVideo( 65.63) //mini slam backwards pre-beat //.SkipByBeats(2.5/3.0 ).SyncWithVideo( 66.73) //hover .SkipToBeat(Beat.NextBeat).SyncWithVideo(67.27) //stuttered slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(67.50) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(68.33) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(69.00) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(69.70) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(70.97) //hover .SkipToBeat(Beat.NextBeat).SyncWithVideo(72.27) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(72.63) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(73.73) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(78.87) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(80.10) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(80.87) //hover .SkipToBeat(Beat.NextBeat).SyncWithVideo(81.67) //slam further backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(82.13) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(83.27) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(83.90) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(86.37) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(87.37) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(88.47) //slam forwards .SkipToBeat(Beat.NextBeat) .SkipToBeat(Beat.NextBeat) .SkipToBeat(Beat.NextBeat) .SkipToBeat(Beat.NextBeat) .SkipToBeat(Beat.NextBeat) //5 total .SkipByBeats(2.0 / 3.0).SyncWithVideo(94.57) //intermission (half wake up) //.SkipByBeats(2.0/3.0 ).SyncWithVideo( 98.93) //intermission .SkipToBeat(Beat.NextBeat).SyncWithVideo(100.33) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(100.67) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(101.70) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(102.03) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(103.23) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(103.53) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(104.67) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(105.27) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(106.00) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(108.13) //hover & creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(109.23) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(111.43) //side glance & creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(112.97) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(113.33) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(114.33) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(115.13) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(116.10) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(120.73) //hover & creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(121.83) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(127.93) //hover & creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(129.83) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(130.37) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(131.07) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(131.80) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(135.03) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(135.23) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(136.20) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(137.50) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(138.80) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(139.30) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(140.07) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(141.43) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(142.10) //slam backwards (small) .SkipByBeats(2.0 / 3.0).SyncWithVideo(142.63) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(143.33) //slam forwards (small) //.SkipByBeats(5) //.SkipToBeat (Beat.NextBeat).SyncWithVideo(152.83) //intermission .SkipByBeats(2.0 / 3.0).SyncWithVideo(152.83) //long hover & creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(154.60) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(154.97) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(155.70) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(156.20) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(158.13) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(158.50) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(159.43) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(160.77) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(162.40) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(165.00) //hover & creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(166.20) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(167.73) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(170.03) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(170.50) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(171.50) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(172.70) //creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(173.33) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(173.90) //hover .SkipToBeat(Beat.NextBeat).SyncWithVideo(175.20) //slam further backwards //174.97 .SkipByBeats(2.0 / 3.0).SyncWithVideo(175.63) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(176.87) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(179.40) //creep backwards (half wake up) .SkipToBeat(Beat.NextBeat).SyncWithVideo(181.50) //slam backwards (with one stutter) .SkipByBeats(2.0 / 3.0).SyncWithVideo(182.87) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(183.87) //slam forwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(187.00) //hover & creep backwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(190.03) //slam backwards .SkipByBeats(2.0 / 3.0).SyncWithVideo(190.60) //creep forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(191.77) //slam forwards .SkipToBeat(Beat.NextBeat).SyncWithVideo(193.20) //end video between last beat and here // .SkipByBeats(2.0/3.0 ).SyncWithVideo(193.20) //sideways nod // .SkipToBeat (Beat.NextBeat).SyncWithVideo(195.77) //slam backwards (with one stutter) // .SkipByBeats(2.0/3.0 ).SyncWithVideo(196.00) //creep forwards // .SkipToBeat (Beat.NextBeat).SyncWithVideo(196.80) //slam forwards // .SkipByBeats(10.0).SyncWithVideo(196.80 + 5) //wake up // .SkipByBeats(2.0/3.0 ).SyncWithVideo() // .SkipToBeat (Beat.NextBeat).SyncWithVideo() .SyncPoints.ToImmutableList() ) ) ); project.ToXml().Save( @"C:\Users\Alex\Pictures\Meme Templates\Meme Making\Mum Headbanging\" + "Sync " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".wlmp" ); }
static void PrintFFmpegOverlayEffectsCommand() { const double firstBeatAudioPos = 16.483; //Different as this is using the synced & edited video const double beatInterval = 0.46875; const int barLength = 4; var beats = new BeatPositioner( firstBeat: firstBeatAudioPos, interval: beatInterval, barLength: barLength ); const string mainFolder = @"C:\Users\Alex\Pictures\Meme Templates\Meme Making\Mum Headbanging"; var GlowWhiteCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-white.png"))); var GlowLargeWhiteCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-white-2x.png"))); var GlowTransparentRedCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-red-opacity130.png"))); var GlowTransparentBlueCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-blue-opacity130.png"))); var GlowTransparentGreenCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-green-opacity130.png"))); var GlowTransparentYellowCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-yellow-opacity170.png"))); var GlowTransparentPurpleCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-purple-opacity150.png"))); var GlowTransparentOrangeCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-orange-opacity170.png"))); var GlowTransparentLightblueCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-lightblue-opacity180.png"))); var GlowTransparentDarkgreenCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-darkgreen-opacity170.png"))); var GlowRedCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-red.png"))); var GlowBlueCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-blue.png"))); var GlowGreenCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-green.png"))); var GlowYellowCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-yellow.png"))); var GlowPurpleCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-purple.png"))); var GlowOrangeCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-orange.png"))); var GlowLightblueCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-lightblue.png"))); var GlowDarkgreenCircle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-darkgreen.png"))); var GlowSemitransparentWhiteRectangle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-white-rectangle-opacity230.png"))); var GlowTransparentWhiteRectangle = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-circlular-white-rectangle-opacity200.png"))); //var GlowDiamond = new GlowType(new FileInfo(Path.Combine(mainFolder, "glow-diamond-white.png"))); // colorMixer: new FFmpegColorChannelMixer( // redPart: (1, 1, 1, 0), // greenPart: (0, 0, 0, 0), // bluePart: (0, 0, 0, 0), // alphaPart: (0, 0, 0, 0.5) // ), //Note: // 1 third of a beat = 0.15625 // To prevent a continuous overlap in the section with repeated beats 1 third of a beat apart, // set the synth beat glow durations to, at most, 0.156 seconds (in total, ie. fade in + fade out) //Note: // If a fade in or out time is zero - even just one, not both - the fade doesn't show at all. // I've modified Glow() to handle this. Glow fullBeatEven = new Glow(GlowSemitransparentWhiteRectangle, 0.001, 0.2, x: 0.5, y: 0.5); Glow fullBeatOdd = new Glow(GlowSemitransparentWhiteRectangle, 0.001, 0.2, x: 0.5, y: 0.5); Glow leftSynthBeatRed = new Glow(GlowRedCircle, 0.001, 0.15, x: 0, y: 0); Glow leftSynthBeatBlue = new Glow(GlowBlueCircle, 0.001, 0.15, x: 0, y: 0); Glow leftSynthBeatGreen = new Glow(GlowGreenCircle, 0.001, 0.15, x: 0, y: 0); Glow leftSynthBeatYellow = new Glow(GlowYellowCircle, 0.001, 0.15, x: 0, y: 0); Glow leftSynthBeatPurple = new Glow(GlowPurpleCircle, 0.001, 0.15, x: 0, y: 0); Glow leftSynthBeatOrange = new Glow(GlowOrangeCircle, 0.001, 0.15, x: 0, y: 0); Glow leftSynthBeatLightblue = new Glow(GlowLightblueCircle, 0.001, 0.15, x: 0, y: 0); Glow leftSynthBeatDarkgreen = new Glow(GlowDarkgreenCircle, 0.001, 0.15, x: 0, y: 0); Glow rightSynthBeatRed = new Glow(GlowRedCircle, 0.001, 0.15, x: 1, y: 0); Glow rightSynthBeatBlue = new Glow(GlowBlueCircle, 0.001, 0.15, x: 1, y: 0); Glow rightSynthBeatGreen = new Glow(GlowGreenCircle, 0.001, 0.15, x: 1, y: 0); Glow rightSynthBeatYellow = new Glow(GlowYellowCircle, 0.001, 0.15, x: 1, y: 0); Glow rightSynthBeatPurple = new Glow(GlowPurpleCircle, 0.001, 0.15, x: 1, y: 0); Glow rightSynthBeatOrange = new Glow(GlowOrangeCircle, 0.001, 0.15, x: 1, y: 0); Glow rightSynthBeatLightblue = new Glow(GlowLightblueCircle, 0.001, 0.15, x: 1, y: 0); Glow rightSynthBeatDarkgreen = new Glow(GlowDarkgreenCircle, 0.001, 0.15, x: 1, y: 0); var taggedBeats = new BeatTagSequence( beatPositioner: beats, firstBeatTags: ImmutableList.Create <object>(fullBeatEven, leftSynthBeatRed, rightSynthBeatRed) ) .SkipByBeats(2.5 / 3.0).TagAndAdd(leftSynthBeatBlue) .SkipByBeats(0.25 / 3.0).TagAndAdd(rightSynthBeatBlue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatGreen) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatBlue) //Prev: duhh, drrruhh du du duhh //Next: duhh, duh boof, duh boof, duh boof, duh boof .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatYellow, rightSynthBeatYellow) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatPurple) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven) .SkipByBeats(2.0 / 3.0).TagAndAdd(rightSynthBeatGreen) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatBlue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven) .SkipByBeats(2.0 / 3.0).TagAndAdd(rightSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd) //Prev: duhh, duh boof, duh boof, duh boof, duh boof //Next: duh duhh, drrruh du du duhh du du duhh .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatLightblue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, rightSynthBeatLightblue) .SkipByBeats(2.5 / 3.0).TagAndAdd(leftSynthBeatGreen) .SkipByBeats(0.25 / 3.0).TagAndAdd(rightSynthBeatGreen) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatPurple) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatPurple) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatPurple) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatPurple) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatGreen) //Prev: duh duhh, drrruh du du duhh du du duhh //Next: duhh, boof, duh duhh, duh duhh-- .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatRed, rightSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatYellow, rightSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatGreen, rightSynthBeatGreen) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatYellow, rightSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatGreen, rightSynthBeatGreen) //Prev: duhh, boof, duh duhh, duh duhh-- //Next: --duh duhh, drrruh du du duhh .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatYellow, rightSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatGreen, rightSynthBeatGreen) .SkipByBeats(2.5 / 3.0).TagAndAdd(leftSynthBeatRed) .SkipByBeats(0.25 / 3.0).TagAndAdd(rightSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatBlue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatRed) //Prev: --duh duhh, drrruh du du duhh //Next: duhh, duh boof, duh boof, duh boof, duh boof .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatLightblue, rightSynthBeatLightblue) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatPurple) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatBlue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatGreen) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd) //Prev: duhh, duh boof, duh boof, duh boof, duh boof //Next: duh duhh, drrruh du du duhh du du duhh .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatRed, rightSynthBeatRed) .SkipByBeats(2.5 / 3.0).TagAndAdd(leftSynthBeatLightblue) .SkipByBeats(0.25 / 3.0).TagAndAdd(rightSynthBeatLightblue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatLightblue) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatPurple) //Prev: duh duhh, drrruh du du duhh du du duhh //Next: duhh, boof, duh duhh, duh duhh, duh-- (iighiahhh iighiahhh iighiahhh iighiahhh iighiahhh) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatRed.With(fadeOutTime: 0.6), rightSynthBeatRed.With(fadeOutTime: 0.6)) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatRed.With(fadeOutTime: 0.6), rightSynthBeatRed.With(fadeOutTime: 0.6)) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatRed) //looks better with //leave these out for extra emphasis of the other beats .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatRed.With(fadeOutTime: 0.6), rightSynthBeatRed.With(fadeOutTime: 0.6)) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatRed) //looks better with //leave these out for extra emphasis of the other beats .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatRed.With(fadeOutTime: 0.6), rightSynthBeatRed.With(fadeOutTime: 0.6)) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatRed) //looks better with //leave these out for extra emphasis of the other beats //Prev: duhh, boof, duh duhh, duh duhh, duh (iighiahhh iighiahhh iighiahhh iighiahhh iighiahhh) //Next: duhh du du duhh du du duhh du du duhh du du (#1) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatOrange) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatOrange) //Prev: duhh du du duhh du du duhh du du duhh du du (#1) //Next: duhh du du duhh du du duhh du du duhh du du (#2) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatOrange) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatOrange) //Prev: duhh du du duhh du du duhh du du duhh du du (#2) //Next: duhh du du duhh du du duhh du du duhh du du (#3) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, rightSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatGreen) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, rightSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatGreen) //Prev: duhh du du duhh du du duhh du du duhh du du (#3) //Next: duhh du du duhh du du duhh du du duhh du du (#4) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatBlue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, rightSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatBlue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, rightSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(rightSynthBeatRed) //Prev: duhh du du duhh du du duhh du du duhh du du (#4) //Next: duhh du du duhh du du duhh du du duhh du du (#5) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatLightblue, rightSynthBeatLightblue) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatBlue, rightSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatBlue, rightSynthBeatBlue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatYellow, rightSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange, rightSynthBeatOrange) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatOrange, rightSynthBeatOrange) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatGreen, rightSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatDarkgreen, rightSynthBeatDarkgreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatDarkgreen, rightSynthBeatDarkgreen) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatRed, rightSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatRed) //Prev: duhh du du duhh du du duhh du du duhh du du (#5) //Next: duhh du du duhh du du duhh du du duhh du du (#6) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatBlue, rightSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatYellow, rightSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatBlue, rightSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatYellow, rightSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatYellow, rightSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatRed, rightSynthBeatPurple) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatPurple, rightSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatPurple) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatLightblue, rightSynthBeatGreen) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatGreen, rightSynthBeatLightblue) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatLightblue, rightSynthBeatGreen) //Prev: duhh du du duhh du du duhh du du duhh du du (#6) //Next: duhh du du duhh du du duhh, duhh du du duhh, duhh boof, mu fa, sa boof, duh BOOF. .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatRed, leftSynthBeatRed, rightSynthBeatPurple, rightSynthBeatPurple) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatPurple, rightSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatPurple, rightSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatYellow, rightSynthBeatRed) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatYellow) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatRed, rightSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatYellow, rightSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd, leftSynthBeatBlue, rightSynthBeatPurple) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatPurple, rightSynthBeatBlue) .SkipByBeats(1.0 / 3.0).TagAndAdd(leftSynthBeatPurple, rightSynthBeatBlue) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatBlue, rightSynthBeatPurple) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatRed, leftSynthBeatRed, rightSynthBeatRed, rightSynthBeatRed) .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd) .SkipByBeats(2.0 / 3.0).TagAndAdd(fullBeatEven, leftSynthBeatLightblue, rightSynthBeatGreen) //mu .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatEven, leftSynthBeatGreen, rightSynthBeatLightblue) //fa .SkipByBeats(2.0 / 3.0).TagAndAdd(fullBeatEven, leftSynthBeatLightblue, rightSynthBeatGreen) //sa .SkipToBeat(Beat.NextBeat).TagAndAdd(fullBeatOdd) .SkipByBeats(2.0 / 3.0).TagAndAdd(leftSynthBeatYellow, rightSynthBeatYellow) .SkipToBeat(Beat.NextBeat).TagAndAdd( fullBeatEven, leftSynthBeatRed.With(fadeOutTime: 0.6), rightSynthBeatRed.With(fadeOutTime: 0.6), leftSynthBeatRed.With(fadeOutTime: 0.6), rightSynthBeatRed.With(fadeOutTime: 0.6), leftSynthBeatYellow.With(fadeOutTime: 0.6), rightSynthBeatPurple.With(fadeOutTime: 0.6) ); //Prev: duhh du du duhh du du duhh, duhh du du duhh, duhh boof, mu fa, sa boof, duh BOOF. Console.WriteLine("Tagged beat timings:"); Console.WriteLine(); foreach (var b in taggedBeats.TaggedBeats) { Console.WriteLine(beats.BeatToTime(b.Beat).ToString(".0000") + " [" + string.Join(", ", b.Tags) + "]"); } Console.WriteLine(); Console.WriteLine("FFmpeg input:"); Console.WriteLine(); Console.WriteLine( // GlowOverlayCommandBuilder.BuildFFmpegCommand( // inputVideo: new FFmpegInput( // new FileInfo( // Path.Combine(mainFolder, "Meme Video 1.2.1.mp4") // ) // ), // outputFile: new FFOutput( // new FileInfo( // Path.Combine(mainFolder, "Meme Video 5.3 - " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".mp4") // ) // ), // taggedBeats: taggedBeats.TaggedBeats, // beatPositioner: beats // ).ToString() // StaggeredGlowOverlayCommandBuilder.BuildBatchCommand( // inputVideo: new FFmpegInput( // new FileInfo( // Path.Combine(mainFolder, "Meme Video 1.2.1.mp4") // ) // ), // outputFile: new FFOutput( // new FileInfo( // Path.Combine(mainFolder, "Meme Video 5.3 - " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".mp4") // ) // ), // taggedBeats: taggedBeats.TaggedBeats, // beatPositioner: beats, // approxGlowsPerStage: 2 // ) CuttingGlowOverlayCommandBuilder.BuildBatchCommand( inputVideo: new FFmpegInput( new FileInfo( Path.Combine(mainFolder, "Meme Video 1.2.1.mp4") ) ), outputFile: new FFmpegOutput( new FileInfo( Path.Combine(mainFolder, "Meme Video 5.3 - " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".mp4") ) ), taggedBeats: taggedBeats.TaggedBeats, beatPositioner: beats, approxGlowsPerCut: 7, approxGlowsPerSubstage: 5 ) ); Console.ReadLine(); }
public static IEnumerable <FFmpegCommand> BuildFFmpegCommandSeries( FFmpegInput inputVideo, FFmpegOutput outputFile, DirectoryInfo tempFilesFolder, IEnumerable <TaggedBeat> taggedBeats, BeatPositioner beatPositioner, int approxGlowsPerCut, int approxGlowsPerSubstage ) { List <IndependantGlowSeries> cuts = IndependantGlowSeries.Split(taggedBeats, beatPositioner, approxGlowsPerCut); var prevResult = inputVideo; var glowOverlayedCutVideos = new List <(FFmpegOutput file, double cutStartTime, double cutEndTime)>(); for (int i = 0; i < cuts.Count; i++) { bool isLastCut = i < cuts.Count - 1; double cutStartTime = cuts[i].GlowStartTime; double cutEndTime = cuts[i].GlowEndTime; //Build a command that cuts the relevant region out of the source video yield return(BuildCutCommand( originalInputVideo: inputVideo, cutStartTime: cutStartTime, cutEndTime: cutEndTime, tempFilesFolder: tempFilesFolder, cutVideo: out FFmpegOutput cutVideo )); //Build commands that overlay glows onto the cut region IEnumerable <FFmpegCommand> glowOverlayCommands = BuildCutGlowOverlayCommands( cutVideo: new FFmpegInput(cutVideo.File), cutStartTime: cutStartTime, cutEndTime: cutEndTime, cutBeats: cuts[i].Beats, beatPositioner: beatPositioner, tempFilesFolder: tempFilesFolder, approxGlowsPerSubstage: approxGlowsPerSubstage, glowOverlayedCutVideo: out FFmpegOutput glowOverlayedCutVideo ); glowOverlayedCutVideos.Add(( file: glowOverlayedCutVideo, cutStartTime: cutStartTime, cutEndTime: cutEndTime )); foreach (var goc in glowOverlayCommands) { yield return(goc); } } //Build a command that overlays each cut region ontop of the source video, at their original times yield return(BuildReoverlayCommand( originalInputVideo: inputVideo, glowOverlayedCutVideos: glowOverlayedCutVideos, outputFile: outputFile )); }