Repository: arduano/Zenith-MIDI Branch: master Commit: 36f8ba3c06a6 Files: 175 Total size: 1.1 MB Directory structure: gitextract_07bla4mi/ ├── .angulardoc.json ├── .gitattributes ├── .gitignore ├── BMEngine/ │ ├── BufferByteReader.cs │ ├── FastList.cs │ ├── GLTextEngine.cs │ ├── GLUtils.cs │ ├── IPluginRender.cs │ ├── MidiFile.cs │ ├── MidiInfo.cs │ ├── MidiTrack.cs │ ├── NoteColorPalettePick.xaml │ ├── NoteColorPalettePick.xaml.cs │ ├── OpenTK.dll.config │ ├── PluginUtils.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── RenderSettings.cs │ ├── ScriptedCompile/ │ │ ├── ExtraUI.cs │ │ └── IO.cs │ ├── UI/ │ │ ├── BBinding.cs │ │ ├── BetterCheckbox.xaml │ │ ├── BetterCheckbox.xaml.cs │ │ ├── BetterRadio.xaml │ │ ├── BetterRadio.xaml.cs │ │ ├── BetterSlider.xaml │ │ ├── BetterSlider.xaml.cs │ │ ├── Colors.xaml │ │ ├── Converters.cs │ │ ├── HexColorPicker.xaml │ │ ├── HexColorPicker.xaml.cs │ │ ├── InplaceConverter.cs │ │ ├── ListBox.xaml │ │ ├── Material.xaml │ │ ├── NumberSelect.xaml │ │ ├── NumberSelect.xaml.cs │ │ ├── RippleEffectDecorator.cs │ │ ├── Scrollbar.xaml │ │ ├── ValueSlider.xaml │ │ └── ValueSlider.xaml.cs │ ├── ZenithEngine.csproj │ └── packages.config ├── Black-Midi-Render/ │ ├── App.config │ ├── GLPostbuffer.cs │ ├── GLUtils.cs │ ├── KDMAPI.cs │ ├── Languages/ │ │ └── en/ │ │ └── window.xaml │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── OpenTK.dll.config │ ├── Program.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── RenderWindow.cs │ ├── Settings.cs │ ├── Zenith.csproj │ └── packages.config ├── ClassicRender/ │ ├── ClassicRender.csproj │ ├── Languages/ │ │ └── en/ │ │ └── classic.xaml │ ├── OpenTK.dll.config │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── README.md │ ├── Render.cs │ ├── Settings.cs │ ├── SettingsCtrl.xaml │ ├── SettingsCtrl.xaml.cs │ └── packages.config ├── FlatRender/ │ ├── FlatRender.csproj │ ├── Languages/ │ │ └── en/ │ │ └── flat.xaml │ ├── OpenTK.dll.config │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── README.md │ ├── Render.cs │ ├── Settings.cs │ ├── SettingsCtrl.xaml │ ├── SettingsCtrl.xaml.cs │ └── packages.config ├── LICENSE ├── MidiTrailRender/ │ ├── AuraSelect.xaml │ ├── AuraSelect.xaml.cs │ ├── Languages/ │ │ └── en/ │ │ └── miditrail.xaml │ ├── MidiTrailRender.csproj │ ├── OpenTK.dll.config │ ├── ProfileManager.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── README.md │ ├── Render.cs │ ├── Settings.cs │ ├── SettingsCtrl.xaml │ ├── SettingsCtrl.xaml.cs │ ├── Util.cs │ └── packages.config ├── NoteCountRender/ │ ├── Languages/ │ │ └── en/ │ │ └── notecounter.xaml │ ├── NoteCountRender.csproj │ ├── OpenTK.dll.config │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── README.md │ ├── Render.cs │ ├── Settings.cs │ ├── SettingsCtrl.xaml │ ├── SettingsCtrl.xaml.cs │ └── packages.config ├── PFARender/ │ ├── .gitignore │ ├── Languages/ │ │ └── en/ │ │ └── pfa.xaml │ ├── OpenTK.dll.config │ ├── PFARender.csproj │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── README.md │ ├── Render.cs │ ├── Settings.cs │ ├── SettingsCtrl.xaml │ ├── SettingsCtrl.xaml.cs │ └── packages.config ├── README-plugin.md ├── README.md ├── ScriptedRenderer/ │ ├── Languages/ │ │ └── en/ │ │ └── scripted.xaml │ ├── OpenTK.dll.config │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── Render.cs │ ├── Script.cs │ ├── ScriptedRender.csproj │ ├── Settings.cs │ ├── SettingsCtrl.xaml │ ├── SettingsCtrl.xaml.cs │ └── packages.config ├── TexturedRender/ │ ├── Languages/ │ │ └── en/ │ │ └── textured.xaml │ ├── OpenTK.dll.config │ ├── Pack.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── README.md │ ├── Render.cs │ ├── Resources/ │ │ └── pack.json │ ├── Settings.cs │ ├── SettingsCtrl.xaml │ ├── SettingsCtrl.xaml.cs │ ├── TexturedRender.csproj │ └── packages.config ├── Zenith.sln ├── ZenithInstaller/ │ ├── App.config │ ├── App.xaml │ ├── App.xaml.cs │ ├── FodyWeavers.xml │ ├── FodyWeavers.xsd │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Program.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── ZenithInstaller.csproj │ ├── ZenithInstaller_nf5vy1mn_wpftmp.csproj │ └── packages.config ├── ZenithShared/ │ ├── InstallFailedException.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── ZenithLanguages.cs │ ├── ZenithShared.csproj │ ├── ZenithUpdates.cs │ └── packages.config └── build.bat ================================================ FILE CONTENTS ================================================ ================================================ FILE: .angulardoc.json ================================================ { "repoId": "132e1921-3d2f-40c3-9aad-ca5bf9141f7d", "lastSync": 0 } ================================================ FILE: .gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # DNX project.lock.json project.fragment.lock.json artifacts/ *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted #*.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # NuGet v3's project.json files produces more ignoreable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings node_modules/ orleans.codegen.cs # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # CodeRush .cr/ # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc cleanup.bat bin */obj/* build/ ================================================ FILE: BMEngine/BufferByteReader.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ZenithEngine { public class BufferByteReader { long pos; int buffersize; int bufferpos; int maxbufferpos; long streamstart; long streamlen; Stream stream; byte[] buffer; byte[] bufferNext; Task nextReader = null; public BufferByteReader(Stream stream, int buffersize, long streamstart, long streamlen) { if (buffersize > streamlen) buffersize = (int)streamlen; this.buffersize = buffersize; this.streamstart = streamstart; this.streamlen = streamlen; this.stream = stream; buffer = new byte[buffersize]; bufferNext = new byte[buffersize]; UpdateBuffer(pos, true); } void UpdateBuffer(long pos, bool first = false) { if (first) { nextReader = Task.Run(() => { lock (stream) { stream.Position = pos + streamstart; stream.Read(bufferNext, 0, buffersize); } }); } nextReader.GetAwaiter().GetResult(); Buffer.BlockCopy(bufferNext, 0, buffer, 0, buffersize); nextReader = Task.Run(() => { lock (stream) { stream.Position = pos + streamstart + buffersize; stream.Read(bufferNext, 0, buffersize); } }); nextReader.GetAwaiter().GetResult(); //lock (stream) //{ // stream.Position = pos + streamstart; // stream.Read(buffer, 0, buffersize); //} maxbufferpos = (int)Math.Min(streamlen - pos + 1, buffersize); } public long Location => pos; public int Pushback = -1; public byte Read() { if (Pushback != -1) { byte _b = (byte)Pushback; Pushback = -1; return _b; } byte b = buffer[bufferpos++]; if (bufferpos < maxbufferpos) return b; else if (bufferpos >= buffersize) { pos += bufferpos; bufferpos = 0; UpdateBuffer(pos); return b; } else throw new IndexOutOfRangeException(); } public byte ReadFast() { byte b = buffer[bufferpos++]; if (bufferpos < maxbufferpos) return b; else if (bufferpos >= buffersize) { pos += bufferpos; bufferpos = 0; UpdateBuffer(pos); return b; } else throw new IndexOutOfRangeException(); } public void Reset() { pos = 0; bufferpos = 0; UpdateBuffer(pos, true); } public void Skip(int count) { for (int i = 0; i < count; i++) { if(Pushback != -1) { Pushback = -1; continue; } bufferpos++; if (bufferpos < maxbufferpos) continue; if (bufferpos >= buffersize) { pos += bufferpos; bufferpos = 0; UpdateBuffer(pos); } else throw new IndexOutOfRangeException(); } } public void Dispose() { buffer = null; } } } ================================================ FILE: BMEngine/FastList.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ZenithEngine { public class FastList : IEnumerable { private class ListItem { public ListItem Next; public T item; } private ListItem root = new ListItem(); private ListItem last = null; public T First { get { if (root.Next != null) return root.Next.item; else return default(T); } } public class Iterator { FastList _ilist; private ListItem prev; private ListItem curr; internal Iterator(FastList ll) { _ilist = ll; Reset(); } public bool MoveNext(out T v) { ListItem ll = curr.Next; if (ll == null) { v = default(T); _ilist.last = curr; return false; } v = ll.item; prev = curr; curr = ll; return true; } public void Remove() { if (_ilist.last.Equals(curr)) _ilist.last = prev; prev.Next = curr.Next; } public void Insert(T item) { var i = new ListItem() { item = item, Next = curr }; if (prev == null) _ilist.root.Next = i; else prev.Next = i; //if (curr.Equals(_ilist.last)) //{ // _ilist.last = curr; //} } public void Reset() { this.prev = null; this.curr = _ilist.root; } } public class FastIterator : IEnumerator { FastList _ilist; private ListItem curr; internal FastIterator(FastList ll) { _ilist = ll; Reset(); } public object Current => curr.item; T IEnumerator.Current => curr.item; public void Dispose() { } public bool MoveNext() { try { curr = curr.Next; return curr != null; } catch { return false; } } public void Reset() { this.curr = _ilist.root; } } public void Add(T item) { ListItem li = new ListItem(); li.item = item; if (root.Next != null && last != null) { while (last.Next != null) last = last.Next; last.Next = li; } else root.Next = li; last = li; } public T Pop() { ListItem el = root.Next; root.Next = el.Next; return el.item; } public Iterator Iterate() { return new Iterator(this); } public bool ZeroLen => root.Next == null; public IEnumerator FastIterate() { return new FastIterator(this); } public void Unlink() { root.Next = null; last = null; } public int Count() { int cnt = 0; ListItem li = root.Next; while (li != null) { cnt++; li = li.Next; } return cnt; } public bool Any() { return root.Next != null; } IEnumerator IEnumerable.GetEnumerator() { return FastIterate(); } public IEnumerator GetEnumerator() { return FastIterate(); } } } ================================================ FILE: BMEngine/GLTextEngine.cs ================================================ using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using OpenTK.Graphics.OpenGL; using OpenTK.Graphics; using OpenTK; using System.Drawing.Imaging; using Size = System.Drawing.Size; namespace ZenithEngine { public class GLTextEngine { #region Shaders string textShaderVert = @"#version 330 compatibility layout(location = 0) in vec2 position; layout(location = 1) in vec2 uv; uniform mat4 viewmat; uniform vec4 Col; out vec2 UV; out vec4 Color; void main() { gl_Position = viewmat * vec4(position.x, position.y, 0, 1.0f); UV = uv; Color = Col; } "; string textShaderFrag = @"#version 330 compatibility in vec2 UV; in vec4 Color; out vec4 color; uniform sampler2D textureSampler; void main() { float mask = texture2D( textureSampler, UV ).y; color = vec4(1, 1, 1, mask) * Color; } "; #endregion int charMapTex; Size mapCharSize; SizeF[] charSizes; int textShader; int uniformMatrix; int uniformColor; int vertexBufferID; int uvBufferID; int quadBufferLength = 2048 * 2; double[] quadVertexbuff; double[] quaduvbuff; int quadBufferPos = 0; int indexBufferId; uint[] indexes = new uint[2048 * 4 * 6]; public void Dispose() { GL.DeleteBuffers(3, new int[] { vertexBufferID }); GL.DeleteProgram(textShader); GL.DeleteTexture(charMapTex); } public string Font { get; private set; } = ""; public int FontSize { get; private set; } = -1; public GLTextEngine() { int _vertexObj = GL.CreateShader(ShaderType.VertexShader); int _fragObj = GL.CreateShader(ShaderType.FragmentShader); int statusCode; string info; GL.ShaderSource(_vertexObj, textShaderVert); GL.CompileShader(_vertexObj); info = GL.GetShaderInfoLog(_vertexObj); GL.GetShader(_vertexObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); GL.ShaderSource(_fragObj, textShaderFrag); GL.CompileShader(_fragObj); info = GL.GetShaderInfoLog(_fragObj); GL.GetShader(_fragObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); textShader = GL.CreateProgram(); GL.AttachShader(textShader, _fragObj); GL.AttachShader(textShader, _vertexObj); GL.LinkProgram(textShader); quadVertexbuff = new double[quadBufferLength * 8]; quaduvbuff = new double[quadBufferLength * 8]; GL.GenBuffers(1, out vertexBufferID); GL.GenBuffers(1, out uvBufferID); for (uint i = 0; i < indexes.Length / 6; i++) { indexes[i * 6 + 0] = i * 4 + 0; indexes[i * 6 + 1] = i * 4 + 1; indexes[i * 6 + 2] = i * 4 + 3; indexes[i * 6 + 3] = i * 4 + 1; indexes[i * 6 + 4] = i * 4 + 3; indexes[i * 6 + 5] = i * 4 + 2; } GL.GenBuffers(1, out indexBufferId); GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBufferId); GL.BufferData( BufferTarget.ElementArrayBuffer, (IntPtr)(indexes.Length * 4), indexes, BufferUsageHint.StaticDraw); uniformMatrix = GL.GetUniformLocation(textShader, "viewmat"); uniformColor = GL.GetUniformLocation(textShader, "Col"); charMapTex = GL.GenTexture(); } public void SetFont(string font, int size) { var bitmap = GenerateCharacters(size, font, out mapCharSize, out charSizes); loadImage(bitmap, charMapTex); bitmap.Dispose(); Font = font; FontSize = size; } public void SetFont(string font, int size, string charmap) { Characters = charmap; SetFont(font, size); } public void SetFont(string font, System.Drawing.FontStyle fontStyle, int size) { var bitmap = GenerateCharacters(size, font, fontStyle, out mapCharSize, out charSizes); loadImage(bitmap, charMapTex); bitmap.Dispose(); Font = font; FontSize = size; } public void SetFont(string font, System.Drawing.FontStyle fontStyle, int size, string charmap) { Characters = charmap; SetFont(font, fontStyle, size); } void loadImage(Bitmap image, int texID) { GL.BindTexture(TextureTarget.Texture2D, texID); BitmapData data = image.LockBits(new System.Drawing.Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); image.UnlockBits(data); } public void Render(string text, Matrix4 transform, Color4 color) { //GL.Enable(EnableCap.Blend); //GL.EnableClientState(ArrayCap.VertexArray); //GL.EnableClientState(ArrayCap.ColorArray); //GL.EnableClientState(ArrayCap.TextureCoordArray); //GL.Enable(EnableCap.Texture2D); //GL.EnableVertexAttribArray(0); //GL.EnableVertexAttribArray(1); //GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.UseProgram(textShader); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, charMapTex); GL.Uniform4(uniformColor, color); GL.UniformMatrix4(uniformMatrix, false, ref transform); quadBufferPos = 0; Vector2 curpos = new Vector2(0, 0); int charImHeight = (Characters.Length - (Characters.Length % charImWidth)) / charImWidth + 1; double charwidth = 1.0 / charImWidth; double charheight = 1.0 / charImHeight; foreach (char c in text) { if (c == '\n') { curpos.Y += mapCharSize.Height; curpos.X = 0; } if (c == ' ') { curpos.X += mapCharSize.Width / 4.0f; } if (!Characters.Contains(c)) continue; var chari = Characters.IndexOf(c); var sz = charSizes[chari]; int charix = chari % charImWidth; int chariy = (chari - charix) / charImWidth; double sx = charwidth * charix; double ex = sx + charSizes[chari].Width / mapCharSize.Width * charwidth; double sy = charheight * chariy; double ey = sy + charSizes[chari].Height / mapCharSize.Height * charheight; float padding = mapCharSize.Width / 8f; sz.Width -= padding * 2; Vector2 endpos = curpos + new Vector2(sz.Width, sz.Height); int pos = quadBufferPos * 8; quadVertexbuff[pos++] = (curpos.X - padding); quadVertexbuff[pos++] = curpos.Y; quadVertexbuff[pos++] = (curpos.X - padding); quadVertexbuff[pos++] = endpos.Y; quadVertexbuff[pos++] = (endpos.X + padding); quadVertexbuff[pos++] = endpos.Y; quadVertexbuff[pos++] = (endpos.X + padding); quadVertexbuff[pos++] = curpos.Y; curpos.X += sz.Width; pos = quadBufferPos * 8; quaduvbuff[pos++] = sx; quaduvbuff[pos++] = sy; quaduvbuff[pos++] = sx; quaduvbuff[pos++] = ey; quaduvbuff[pos++] = ex; quaduvbuff[pos++] = ey; quaduvbuff[pos++] = ex; quaduvbuff[pos++] = sy; //quaduvbuff[pos++] = 0; //quaduvbuff[pos++] = 0; //quaduvbuff[pos++] = 1; //quaduvbuff[pos++] = 0; //quaduvbuff[pos++] = 1; //quaduvbuff[pos++] = 1; //quaduvbuff[pos++] = 0; //quaduvbuff[pos++] = 1; quadBufferPos++; FlushQuadBuffer(); } FlushQuadBuffer(false); //GL.Disable(EnableCap.Blend); //GL.Disable(EnableCap.Texture2D); //GL.DisableClientState(ArrayCap.VertexArray); //GL.DisableClientState(ArrayCap.ColorArray); //GL.DisableClientState(ArrayCap.TextureCoordArray); //GL.DisableVertexAttribArray(0); //GL.DisableVertexAttribArray(1); } public SizeF GetBoundBox(string text) { Vector2 curpos = new Vector2(0, 0); int rows = 1; float maxWidth = 0; float padding = mapCharSize.Width / 8f; foreach (char c in text) { if (c == '\n') { curpos.X = 0; rows++; } if (!Characters.Contains(c)) continue; var chari = Characters.IndexOf(c); var sz = charSizes[chari]; sz.Width -= padding * 2; Vector2 endpos = curpos + new Vector2(sz.Width, sz.Height); curpos.X += sz.Width; if (curpos.X > maxWidth) maxWidth = curpos.X; } return new SizeF(maxWidth + padding * 2, mapCharSize.Height * rows); } void FlushQuadBuffer(bool check = true) { if (quadBufferPos < quadBufferLength && check) return; if (quadBufferPos == 0) return; GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferID); GL.BufferData( BufferTarget.ArrayBuffer, (IntPtr)(quadVertexbuff.Length * 8), quadVertexbuff, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Double, false, 16, 0); GL.BindBuffer(BufferTarget.ArrayBuffer, uvBufferID); GL.BufferData( BufferTarget.ArrayBuffer, (IntPtr)(quaduvbuff.Length * 8), quaduvbuff, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Double, false, 16, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBufferId); GL.IndexPointer(IndexPointerType.Int, 1, 0); GL.DrawElements(PrimitiveType.Triangles, quadBufferPos * 6, DrawElementsType.UnsignedInt, IntPtr.Zero); quadBufferPos = 0; } private string Characters = @" qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789µ§½!""#¤%&/()=?^*@£€${[]}\~¨'-_.:,;<>|°©®±¥"; private const int charImWidth = 20; public Bitmap GenerateCharacters(int fontSize, string fontName, out Size charSize, out SizeF[] charSizes) { return GenerateCharacters(fontSize, fontName, System.Drawing.FontStyle.Regular, out charSize, out charSizes); } public Bitmap GenerateCharacters(int fontSize, string fontName, System.Drawing.FontStyle fontStyle, out Size charSize, out SizeF[] charSizes) { charSizes = new SizeF[Characters.Length]; var characters = new List(); using (var font = new Font(fontName, fontSize, fontStyle)) { for (int i = 0; i < Characters.Length; i++) { var charBmp = GenerateCharacter(font, Characters[i]); charSizes[i] = GetSize(font, Characters[i]); characters.Add(charBmp); } charSize = new Size(characters.Max(x => x.Width), characters.Max(x => x.Height)); var charMap = new Bitmap(charSize.Width * charImWidth, charSize.Height * ((characters.Count - (characters.Count % charImWidth)) / charImWidth + 1)); using (var gfx = Graphics.FromImage(charMap)) { gfx.FillRectangle(Brushes.Black, 0, 0, charMap.Width, charMap.Height); for (int i = 0; i < characters.Count; i++) { var c = characters[i]; int x = i % charImWidth; int y = (i - x) / charImWidth; gfx.DrawImageUnscaled(c, x * charSize.Width, y * charSize.Height); c.Dispose(); } } return charMap; } } private Bitmap GenerateCharacter(Font font, char c) { var size = GetSize(font, c); var bmp = new Bitmap((int)size.Width, (int)size.Height); using (var gfx = Graphics.FromImage(bmp)) { gfx.FillRectangle(Brushes.Black, 0, 0, bmp.Width, bmp.Height); gfx.DrawString(c.ToString(), font, Brushes.White, 0, 0); } return bmp; } private SizeF GetSize(Font font, char c) { using (var bmp = new Bitmap(512, 512)) { using (var gfx = Graphics.FromImage(bmp)) { return gfx.MeasureString(c.ToString(), font); } } } } } ================================================ FILE: BMEngine/GLUtils.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using OpenTK.Graphics.OpenGL; namespace ZenithEngine { public static class GLUtils { public static int MakeShaderProgram(string name) { int _vertexObj = GL.CreateShader(ShaderType.VertexShader); int _fragObj = GL.CreateShader(ShaderType.FragmentShader); int statusCode; string info; GL.ShaderSource(_vertexObj, File.ReadAllText("Shaders\\" + name + ".vert")); GL.CompileShader(_vertexObj); info = GL.GetShaderInfoLog(_vertexObj); GL.GetShader(_vertexObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); GL.ShaderSource(_fragObj, File.ReadAllText("Shaders\\" + name + ".frag")); GL.CompileShader(_fragObj); info = GL.GetShaderInfoLog(_fragObj); GL.GetShader(_fragObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); int shader = GL.CreateProgram(); GL.AttachShader(shader, _fragObj); GL.AttachShader(shader, _vertexObj); GL.LinkProgram(shader); return shader; } public static int MakePostShaderProgram(string name) { int _vertexObj = GL.CreateShader(ShaderType.VertexShader); int _fragObj = GL.CreateShader(ShaderType.FragmentShader); int statusCode; string info; GL.ShaderSource(_vertexObj, File.ReadAllText("Shaders\\Post\\post.vert")); GL.CompileShader(_vertexObj); info = GL.GetShaderInfoLog(_vertexObj); GL.GetShader(_vertexObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); GL.ShaderSource(_fragObj, File.ReadAllText("Shaders\\Post\\" + name + ".frag")); GL.CompileShader(_fragObj); info = GL.GetShaderInfoLog(_fragObj); GL.GetShader(_fragObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); int shader = GL.CreateProgram(); GL.AttachShader(shader, _fragObj); GL.AttachShader(shader, _vertexObj); GL.LinkProgram(shader); return shader; } public static void GenFrameBufferTexture(int width, int height, out int fbuffer, out int rtexture) { fbuffer = GL.GenFramebuffer(); GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbuffer); rtexture = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, rtexture); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.Byte, (IntPtr)0); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, rtexture, 0); if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete) throw new Exception(); } public static void GenFrameBufferTexture3d(int width, int height, out int fbuffer, out int rtexture, out int depthrenderbuffer) { fbuffer = GL.GenFramebuffer(); GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbuffer); rtexture = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, rtexture); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.Byte, (IntPtr)0); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); depthrenderbuffer = GL.GenRenderbuffer(); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthrenderbuffer); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent, width, height); GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, depthrenderbuffer); GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, rtexture, 0); if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete) throw new Exception(); } } } ================================================ FILE: BMEngine/IPluginRender.cs ================================================ using OpenTK.Graphics; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Media; namespace ZenithEngine { public interface IPluginRender : IDisposable { string Name { get; } string Description { get; } bool Initialized { get; } ImageSource PreviewImage { get; } bool ManualNoteDelete { get; } double NoteCollectorOffset { get; } NoteColor[][] NoteColors { set; } double Tempo { set; } MidiInfo CurrentMidi { set; } string LanguageDictName { get; } double NoteScreenTime { get; } long LastNoteCount { get; } Control SettingsControl { get; } void Init(); void RenderFrame(FastList notes, double midiTime, int finalCompositeBuff); void ReloadTrackColors(); } } ================================================ FILE: BMEngine/MidiFile.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ZenithEngine { public class MidiFile : IDisposable { Stream MidiFileReader; public ushort division; public int trackcount; public ushort format; public int zerothTempo = 500000; List trackBeginnings = new List(); List trackLengths = new List(); public MidiTrack[] tracks; public MidiInfo info; public long maxTrackTime; public long noteCount = 0; public long currentSyncTime = 0; public double currentFlexSyncTime = 0; public FastList globalDisplayNotes = new FastList(); public FastList globalTempoEvents = new FastList(); public FastList globalColorEvents = new FastList(); public FastList globalPlaybackEvents = new FastList(); public double tempoTickMultiplier = 0; public int unendedTracks = 0; RenderSettings settings; public MidiFile(string filename, RenderSettings settings) { this.settings = settings; MidiFileReader = new StreamReader(filename).BaseStream; ParseHeaderChunk(); while (MidiFileReader.Position < MidiFileReader.Length) { ParseTrackChunk(); } tracks = new MidiTrack[trackcount]; Console.WriteLine("Loading tracks into memory"); info = new MidiInfo(); LoadAndParseAll(true); Console.WriteLine("Loaded!"); Console.WriteLine("Note count: " + noteCount); unendedTracks = trackcount; info.division = division; info.firstTempo = zerothTempo; info.noteCount = noteCount; info.tickLength = maxTrackTime; info.trackCount = trackcount; tempoTickMultiplier = (double)division / 500000 * 1000; } void AssertText(string text) { foreach (char c in text) { if (MidiFileReader.ReadByte() != c) { throw new Exception("Corrupt chunk headers"); } } } uint ReadInt32() { uint length = 0; for (int i = 0; i != 4; i++) length = (uint)((length << 8) | (byte)MidiFileReader.ReadByte()); return length; } ushort ReadInt16() { ushort length = 0; for (int i = 0; i != 2; i++) length = (ushort)((length << 8) | (byte)MidiFileReader.ReadByte()); return length; } void ParseHeaderChunk() { AssertText("MThd"); uint length = ReadInt32(); if (length != 6) throw new Exception("Header chunk size isn't 6"); format = ReadInt16(); ReadInt16(); division = ReadInt16(); if (format == 2) throw new Exception("Midi type 2 not supported"); if (division < 0) throw new Exception("Division < 0 not supported"); } void ParseTrackChunk() { AssertText("MTrk"); uint length = ReadInt32(); trackBeginnings.Add(MidiFileReader.Position); trackLengths.Add(length); MidiFileReader.Position += length; trackcount++; Console.WriteLine("Track " + trackcount + ", Size " + length); } public bool ParseUpTo(double targetTime) { lock (globalDisplayNotes) { if (settings.timeBasedNotes) for (; currentFlexSyncTime <= targetTime && settings.running; currentSyncTime++) { currentFlexSyncTime += 1 / tempoTickMultiplier; int ut = 0; for (int trk = 0; trk < trackcount; trk++) { var t = tracks[trk]; if (!t.trackEnded) { ut++; t.Step(currentSyncTime); } } unendedTracks = ut; } else for (; currentSyncTime <= targetTime && settings.running; currentSyncTime++) { int ut = 0; for (int trk = 0; trk < trackcount; trk++) { var t = tracks[trk]; if (!t.trackEnded) { ut++; t.Step(currentSyncTime); } } unendedTracks = ut; } foreach (var t in tracks) { if (!t.trackEnded) return true; } return false; } } public void LoadAndParseAll(bool useBufferStream = false) { long[] tracklens = new long[tracks.Length]; int p = 0; List> tempos = new List>(); Parallel.For(0, tracks.Length, (i) => { var reader = new BufferByteReader(MidiFileReader, settings.maxTrackBufferSize, trackBeginnings[i], trackLengths[i]); tracks[i] = new MidiTrack(i, reader, this, settings); var t = tracks[i]; while (!t.trackEnded) { try { t.ParseNextEventFast(); } catch { break; } } noteCount += t.noteCount; tracklens[i] = t.trackTime; if (t.foundTimeSig != null) info.timeSig = t.foundTimeSig; if (t.zerothTempo != -1) { zerothTempo = t.zerothTempo; } lock (tempos) tempos.Add(t.TempoEvents); t.Reset(); Console.WriteLine("Loaded track " + p++ + "/" + tracks.Length); GC.Collect(); }); maxTrackTime = tracklens.Max(); Console.WriteLine("Processing Tempos"); LinkedList Tempos = new LinkedList(); var iters = tempos.Select(t => t.GetEnumerator()).ToArray(); bool[] unended = new bool[iters.Length]; for (int i = 0; i < iters.Length; i++) unended[i] = iters[i].MoveNext(); while (true) { long smallest = 0; bool first = true; int id = 0; for (int i = 0; i < iters.Length; i++) { if (!unended[i]) continue; if (first) { smallest = iters[i].Current.pos; id = i; first = false; continue; } if (iters[i].Current.pos < smallest) { smallest = iters[i].Current.pos; id = i; } } if (first) { break; } Tempos.AddLast(iters[id].Current); unended[id] = iters[id].MoveNext(); } double time = 0; long ticks = maxTrackTime; double multiplier = ((double)500000 / division) / 1000000; long lastt = 0; foreach (var t in Tempos) { var offset = t.pos - lastt; time += offset * multiplier; ticks -= offset; lastt = t.pos; multiplier = ((double)t.tempo / division) / 1000000; } time += ticks * multiplier; info.secondsLength = time; maxTrackTime = tracklens.Max(); unendedTracks = trackcount; } public void SetZeroColors() { foreach (var t in tracks) t.SetZeroColors(); } public void Reset() { globalDisplayNotes.Unlink(); globalTempoEvents.Unlink(); globalColorEvents.Unlink(); globalPlaybackEvents.Unlink(); currentSyncTime = 0; currentFlexSyncTime = 0; unendedTracks = trackcount; tempoTickMultiplier = (double)division / 500000 * 1000; foreach (var t in tracks) t.Reset(); } public void Dispose() { foreach (var t in tracks) t.Dispose(); MidiFileReader.Dispose(); } } } ================================================ FILE: BMEngine/MidiInfo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ZenithEngine { public class MidiInfo { public int division; public int trackCount; public long noteCount; public int firstTempo; public long tickLength; public double secondsLength; public TimeSignature timeSig = new TimeSignature() { numerator = 4, denominator = 4 }; } } ================================================ FILE: BMEngine/MidiTrack.cs ================================================ using OpenTK.Graphics; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ZenithEngine { public class Note { public double start; public double end; public bool hasEnded; public byte channel; public byte key; public byte vel; public bool delete = false; public object meta = null; public int track; public NoteColor color; } public class NoteColor { public Color4 left; public Color4 right; public bool isDefault = true; } public struct PlaybackEvent { public double pos; public int val; } public class Tempo { public long pos; public int tempo; } public class ColorChange { public double pos; public Color4 col1; public Color4 col2; public byte channel; public MidiTrack track; } public class TimeSignature { public int numerator { get; internal set; } public int denominator { get; internal set; } } public class MidiTrack : IDisposable { public int trackID; public bool trackEnded = false; public long trackTime = 0; public long lastStepTime = 0; public double trackFlexTime = 0; public long noteCount = 0; public int zerothTempo = -1; byte channelPrefix = 0; MidiFile midi; public FastList[] UnendedNotes = null; public LinkedList Tempos = new LinkedList(); FastList globalDisplayNotes; FastList globalTempoEvents; FastList globalColorEvents; FastList globalPlaybackEvents; public NoteColor[] trkColors; public NoteColor[] zeroTickTrkColors; public TimeSignature foundTimeSig = null; bool readDelta = false; BufferByteReader reader; public void Reset() { if (UnendedNotes != null) foreach (var un in UnendedNotes) un.Unlink(); reader.Reset(); ResetColors(); trackTime = 0; lastStepTime = 0; trackFlexTime = 0; trackEnded = false; readDelta = false; channelPrefix = 0; noteCount = 0; UnendedNotes = null; } public void ResetColors() { trkColors = new NoteColor[16]; for (int i = 0; i < 16; i++) { trkColors[i] = new NoteColor() { left = Color4.Gray, right = Color4.Gray, isDefault = true }; } } public void SetZeroColors() { for (int i = 0; i < 16; i++) { if (zeroTickTrkColors[i] != null) { trkColors[i].left = zeroTickTrkColors[i].left; trkColors[i].right = zeroTickTrkColors[i].right; } } } RenderSettings settings; public MidiTrack(int id, BufferByteReader reader, MidiFile file, RenderSettings settings) { this.settings = settings; globalDisplayNotes = file.globalDisplayNotes; globalTempoEvents = file.globalTempoEvents; globalColorEvents = file.globalColorEvents; globalPlaybackEvents = file.globalPlaybackEvents; midi = file; this.reader = reader; trackID = id; ResetColors(); zeroTickTrkColors = new NoteColor[16]; for (int i = 0; i < 16; i++) zeroTickTrkColors[i] = null; } long ReadVariableLen() { byte c; int val = 0; for (int i = 0; i < 4; i++) { c = reader.ReadFast(); if (c > 0x7F) { val = (val << 7) | (c & 0x7F); } else { val = val << 7 | c; return val; } } return val; } public void Step(long time) { timebase = settings.timeBasedNotes; trackFlexTime += (time - lastStepTime) / midi.tempoTickMultiplier; lastStepTime = time; try { if (time >= trackTime) { if (readDelta) { long d = trackTime; do { ParseNextEvent(); if (trackEnded) return; trackTime += ReadVariableLen(); readDelta = true; } while (trackTime == d); } else { if (trackEnded) return; trackTime += ReadVariableLen(); readDelta = true; } } } catch (IndexOutOfRangeException) { EndTrack(); } } void EndTrack() { trackEnded = true; if (UnendedNotes != null) foreach (var un in UnendedNotes) { var iter = un.Iterate(); Note n; while (iter.MoveNext(out n)) { n.end = trackTime; n.hasEnded = true; } un.Unlink(); } UnendedNotes = null; } byte prevCommand = 0; bool timebase = false; public void ParseNextEvent() { try { if (!readDelta) { trackTime += ReadVariableLen(); } readDelta = false; double time = trackTime; if (timebase) time = trackFlexTime; byte command = reader.ReadFast(); if (command < 0x80) { reader.Pushback = command; command = prevCommand; } prevCommand = command; byte comm = (byte)(command & 0b11110000); if (comm == 0b10010000) { byte channel = (byte)(command & 0b00001111); byte note = reader.Read(); byte vel = reader.ReadFast(); if (settings.playbackEnabled && vel > 10) { globalPlaybackEvents.Add(new PlaybackEvent() { pos = time, val = command | (note << 8) | (vel << 16) }); } if (vel == 0) { var l = UnendedNotes[note << 4 | channel]; if (!l.ZeroLen) { Note n = l.Pop(); n.end = time; n.hasEnded = true; } } else { Note n = new Note(); n.start = time; n.key = note; n.color = trkColors[channel]; n.channel = channel; n.vel = vel; n.track = trackID; if (UnendedNotes == null) { UnendedNotes = new FastList[256 * 16]; for (int i = 0; i < 256 * 16; i++) { UnendedNotes[i] = new FastList(); } } UnendedNotes[note << 4 | channel].Add(n); globalDisplayNotes.Add(n); } } else if (comm == 0b10000000) { int channel = command & 0b00001111; byte note = reader.Read(); byte vel = reader.ReadFast(); var l = UnendedNotes[note << 4 | channel]; if (!l.ZeroLen) { try { Note n = l.Pop(); if (settings.playbackEnabled && n.vel > 10) { globalPlaybackEvents.Add(new PlaybackEvent() { pos = time, val = command | (note << 8) | (vel << 16) }); } n.end = time; n.hasEnded = true; } catch { } } } else if (comm == 0b10100000) { int channel = command & 0b00001111; byte note = reader.Read(); byte vel = reader.Read(); if (settings.playbackEnabled) { globalPlaybackEvents.Add(new PlaybackEvent() { pos = time, val = command | (note << 8) | (vel << 16) }); } } else if (comm == 0b11000000) { int channel = command & 0b00001111; byte program = reader.Read(); if (settings.playbackEnabled) { globalPlaybackEvents.Add(new PlaybackEvent() { pos = time, val = command | (program << 8) }); } } else if (comm == 0b11010000) { int channel = command & 0b00001111; byte pressure = reader.Read(); if (settings.playbackEnabled) { globalPlaybackEvents.Add(new PlaybackEvent() { pos = time, val = command | (pressure << 8) }); } } else if (comm == 0b11100000) { int channel = command & 0b00001111; byte l = reader.Read(); byte m = reader.Read(); if (settings.playbackEnabled) { globalPlaybackEvents.Add(new PlaybackEvent() { pos = time, val = command | (l << 8) | (m << 16) }); } } else if (comm == 0b10110000) { int channel = command & 0b00001111; byte cc = reader.Read(); byte vv = reader.Read(); if (settings.playbackEnabled) { globalPlaybackEvents.Add(new PlaybackEvent() { pos = time, val = command | (cc << 8) | (vv << 16) }); } } else if (command == 0b11110000) { while (reader.Read() != 0b11110111) ; } else if (command == 0b11110100 || command == 0b11110001 || command == 0b11110101 || command == 0b11111001 || command == 0b11111101) { //printf("Undefined\n"); } else if (command == 0b11110010) { int channel = command & 0b00001111; byte ll = reader.Read(); byte mm = reader.Read(); } else if (command == 0b11110011) { byte ss = reader.Read(); } else if (command == 0b11110110) { } else if (command == 0b11110111) { } else if (command == 0b11111000) { } else if (command == 0b11111010) { } else if (command == 0b11111100) { } else if (command == 0b11111110) { } else if (command == 0xFF) { command = reader.Read(); if (command == 0x00) { if (reader.Read() != 2) { throw new Exception("Corrupt Track"); } reader.Read(); reader.Read(); } else if (command == 0x01) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x02) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x03) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x04) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x05) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x06) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x07) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x08) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x09) { int size = (int)ReadVariableLen(); char[] text = new char[size]; for (int i = 0; i < size; i++) { text[i] = (char)reader.Read(); } string str = new string(text); } else if (command == 0x0A) { int size = (int)ReadVariableLen(); byte[] data = new byte[size]; for (int i = 0; i < size; i++) { data[i] = reader.Read(); } if (data.Length == 8 || data.Length == 12) { if (data[0] == 0x00 && data[1] == 0x0F) { Color4 col1 = new Color4(data[4], data[5], data[6], data[7]); Color4 col2; if (data.Length == 12) col2 = new Color4(data[8], data[9], data[10], data[11]); else col2 = col1; if (data[2] < 0x10 || data[2] == 0x7F) { var c = new ColorChange() { pos = time, col1 = col1, col2 = col2, channel = data[2], track = this }; globalColorEvents.Add(c); } } } } else if (command == 0x20) { command = reader.Read(); if (command != 1) { throw new Exception("Corrupt Track"); } channelPrefix = reader.Read(); } else if (command == 0x21) { command = reader.Read(); if (command != 1) { throw new Exception("Corrupt Track"); } reader.Skip(1); //TODO: MIDI port } else if (command == 0x2F) { command = reader.Read(); if (command != 0) { throw new Exception("Corrupt Track"); } EndTrack(); } else if (command == 0x51) { command = reader.Read(); if (command != 3) { throw new Exception("Corrupt Track"); } int btempo = 0; for (int i = 0; i != 3; i++) btempo = (int)((btempo << 8) | reader.Read()); if (!timebase) { Tempo t = new Tempo(); t.pos = trackTime; t.tempo = btempo; lock (globalTempoEvents) { globalTempoEvents.Add(t); } } midi.tempoTickMultiplier = ((double)midi.division / btempo) * 1000; } else if (command == 0x54) { command = reader.Read(); if (command != 5) { throw new Exception("Corrupt Track"); } reader.Skip(4); } else if (command == 0x58) { command = reader.Read(); if (command != 4) { throw new Exception("Corrupt Track"); } reader.Skip(4); } else if (command == 0x59) { command = reader.Read(); if (command != 2) { throw new Exception("Corrupt Track"); } reader.Skip(2); //TODO: Key Signature } else if (command == 0x7F) { int size = (int)ReadVariableLen(); byte[] data = new byte[size]; for (int i = 0; i < size; i++) { data[i] = reader.Read(); } } else { throw new Exception("Corrupt Track"); } } else { throw new Exception("Corrupt Track"); } } catch (IndexOutOfRangeException) { EndTrack(); } catch { } } public FastList TempoEvents = new FastList(); public void ParseNextEventFast() { try { trackTime += ReadVariableLen(); byte command = reader.Read(); if (command < 0x80) { reader.Pushback = command; command = prevCommand; } prevCommand = command; byte comm = (byte)(command & 0b11110000); if (comm == 0b10010000) { byte channel = (byte)(command & 0b00001111); reader.Skip(1); byte vel = reader.Read(); if (vel != 0) noteCount++; } else if (comm == 0b10000000) { int channel = command & 0b00001111; reader.Skip(2); } else if (comm == 0b10100000) { int channel = command & 0b00001111; reader.Skip(2); } else if (comm == 0b11000000) { int channel = command & 0b00001111; reader.Skip(1); } else if (comm == 0b11010000) { int channel = command & 0b00001111; reader.Skip(1); } else if (comm == 0b11100000) { int channel = command & 0b00001111; reader.Skip(2); } else if (comm == 0b10110000) { int channel = command & 0b00001111; reader.Skip(2); } else if (command == 0b11110000) { while (reader.Read() != 0b11110111) ; } else if (command == 0b11110100 || command == 0b11110001 || command == 0b11110101 || command == 0b11111001 || command == 0b11111101) { //printf("Undefined\n"); } else if (command == 0b11110010) { int channel = command & 0b00001111; reader.Skip(2); } else if (command == 0b11110011) { byte ss = reader.Read(); } else if (command == 0b11110110) { } else if (command == 0b11110111) { } else if (command == 0b11111000) { } else if (command == 0b11111010) { } else if (command == 0b11111100) { } else if (command == 0b11111110) { } else if (command == 0xFF) { command = reader.Read(); if (command == 0x00) { if (reader.Read() != 2) { throw new Exception("Corrupt Track"); } } else if (command >= 0x01 && command <= 0x0A) { int size = (int)ReadVariableLen(); if (command != 0x0A || trackTime != 0) { reader.Skip(size); } else { byte[] data = new byte[size]; for (int i = 0; i < size; i++) { data[i] = reader.Read(); } if (data.Length == 8 || data.Length == 12) { if (data[0] == 0x00 && data[1] == 0x0F) { Color4 col1 = new Color4(data[4], data[5], data[6], data[7]); Color4 col2; if (data.Length == 12) col2 = new Color4(data[8], data[9], data[10], data[11]); else col2 = col1; if (data[2] < 0x10) { zeroTickTrkColors[data[2]] = new NoteColor() { left = col1, right = col2 }; } else if (data[2] == 0x7F) { for (int i = 0; i < 16; i++) zeroTickTrkColors[i] = new NoteColor() { left = col1, right = col2 }; } } } } } else if (command == 0x20) { command = reader.Read(); if (command != 1) { throw new Exception("Corrupt Track"); } channelPrefix = reader.Read(); } else if (command == 0x21) { command = reader.Read(); if (command != 1) { throw new Exception("Corrupt Track"); } reader.Skip(1); //TODO: MIDI port } else if (command == 0x2F) { command = reader.Read(); if (command != 0) { throw new Exception("Corrupt Track"); } EndTrack(); } else if (command == 0x51) { command = reader.Read(); if (command != 3) { throw new Exception("Corrupt Track"); } int btempo = 0; for (int i = 0; i != 3; i++) btempo = (int)((btempo << 8) | reader.Read()); if (trackTime == 0) { zerothTempo = btempo; } Tempo t = new Tempo(); t.pos = trackTime; t.tempo = btempo; TempoEvents.Add(t); } else if (command == 0x54) { command = reader.Read(); if (command != 5) { throw new Exception("Corrupt Track"); } reader.Skip(4); } else if (command == 0x58) { command = reader.Read(); if (command != 4) { throw new Exception("Corrupt Track"); } int nn = reader.ReadFast(); int dd = reader.ReadFast(); dd = (int)Math.Pow(2, dd); foundTimeSig = new TimeSignature() { numerator = nn, denominator = dd }; reader.Skip(2); } else if (command == 0x59) { command = reader.Read(); if (command != 2) { throw new Exception("Corrupt Track"); } reader.Skip(2); //TODO: Key Signature } else if (command == 0x7F) { int size = (int)ReadVariableLen(); reader.Skip(size); } else { throw new Exception("Corrupt Track"); } } else { throw new Exception("Corrupt Track"); } } catch (IndexOutOfRangeException) { EndTrack(); } catch { } } public void Dispose() { reader.Dispose(); } } } ================================================ FILE: BMEngine/NoteColorPalettePick.xaml ================================================  ================================================ FILE: BMEngine/UI/NumberSelect.xaml.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ZenithEngine.UI { /// /// Interaction logic for NumberSelect.xaml /// public partial class NumberSelect : UserControl { public decimal Value { get => (decimal)GetValue(ValueProperty); set => SetValue(ValueProperty, value); } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(decimal), typeof(NumberSelect), new PropertyMetadata((decimal)0, new PropertyChangedCallback(OnPropertyChange))); public int DecimalPoints { get => (int)GetValue(DecimalPointsProperty); set => SetValue(DecimalPointsProperty, value); } public static readonly DependencyProperty DecimalPointsProperty = DependencyProperty.Register("DecimalPoints", typeof(int), typeof(NumberSelect), new PropertyMetadata((int)0, new PropertyChangedCallback(OnPropertyChange))); public decimal Minimum { get => (decimal)GetValue(MinimumProperty); set => SetValue(MinimumProperty, value); } public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(decimal), typeof(NumberSelect), new PropertyMetadata((decimal)0, new PropertyChangedCallback(OnPropertyChange))); public decimal Maximum { get => (decimal)GetValue(MaximumProperty); set => SetValue(MaximumProperty, value); } public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(decimal), typeof(NumberSelect), new PropertyMetadata((decimal)1000, new PropertyChangedCallback(OnPropertyChange))); public decimal Step { get => (decimal)GetValue(StepProperty); set => SetValue(StepProperty, value); } public static readonly DependencyProperty StepProperty = DependencyProperty.Register("Step", typeof(decimal), typeof(NumberSelect), new PropertyMetadata((decimal)1)); public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent( "ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(NumberSelect)); public event RoutedPropertyChangedEventHandler ValueChanged { add { AddHandler(ValueChangedEvent, value); } remove { RemoveHandler(ValueChangedEvent, value); } } private static void OnPropertyChange(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((NumberSelect)sender).UpdateValue(); } public bool TextFocused => textBox.IsFocused; string prevText = ""; public NumberSelect() { InitializeComponent(); prevText = Value.ToString(); textBox.Text = prevText; upArrow.SetBinding(IsEnabledProperty, new BBinding(IsEnabledProperty, this)); downArrow.SetBinding(IsEnabledProperty, new BBinding(IsEnabledProperty, this)); textBox.SetBinding(IsEnabledProperty, new BBinding(IsEnabledProperty, this)); } bool ignoreChange = false; void UpdateValue() { if (!ignoreChange) { try { decimal old = Value; decimal d = Decimal.Round(old, DecimalPoints); if (d < Minimum) d = Minimum; if (d > Maximum) d = Maximum; if (d != old) { Value = d; } try { RaiseEvent(new RoutedPropertyChangedEventArgs(old, d, ValueChangedEvent)); } catch { } } catch { } textBox.Text = Value.ToString(); } ignoreChange = false; } private void TextBox_TextChanged(object sender, TextChangedEventArgs e) { try { decimal _d = Convert.ToDecimal(textBox.Text); decimal d = Decimal.Round(_d, DecimalPoints); if (d < Minimum) d = Minimum; if (d > Maximum) d = Maximum; else { var old = Value; if (d != old) { ignoreChange = true; Value = d; try { RaiseEvent(new RoutedPropertyChangedEventArgs(old, d, ValueChangedEvent)); } catch { } } } } catch { if(textBox.Text != "") textBox.Text = prevText; } prevText = textBox.Text; } private void TextBox_LostFocus(object sender, RoutedEventArgs e) { CheckAndSave(); } void CheckAndSave() { try { decimal _d = Convert.ToDecimal(textBox.Text); decimal d = Decimal.Round(_d, DecimalPoints); if (d < Minimum) d = Minimum; if (d > Maximum) d = Maximum; var old = Value; if (d != old) { Value = d; try { RaiseEvent(new RoutedPropertyChangedEventArgs(old, d, ValueChangedEvent)); } catch { } } } catch { } textBox.Text = Value.ToString(); } private void TextBox_TextInput(object sender, TextCompositionEventArgs e) { } private void Button_Click(object sender, RoutedEventArgs e) { var d = Value + Step; if (d < Minimum) d = Minimum; if (d > Maximum) d = Maximum; var old = Value; Value = d; textBox.Text = Value.ToString(); if (old != d) RaiseEvent(new RoutedPropertyChangedEventArgs(old, d, ValueChangedEvent)); } private void Button_Click_1(object sender, RoutedEventArgs e) { var d = Value - Step; if (d < Minimum) d = Minimum; if (d > Maximum) d = Maximum; var old = Value; Value = d; textBox.Text = Value.ToString(); if (old != d) RaiseEvent(new RoutedPropertyChangedEventArgs(old, d, ValueChangedEvent)); } private void UserControl_KeyDown(object sender, KeyEventArgs e) { if(e.Key == Key.Enter) { CheckAndSave(); e.Handled = true; Keyboard.ClearFocus(); FrameworkElement parent = (FrameworkElement)textBox.Parent; while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable) { parent = (FrameworkElement)parent.Parent; } DependencyObject scope = FocusManager.GetFocusScope(textBox); FocusManager.SetFocusedElement(scope, parent as IInputElement); } } private void TextBox_KeyDown(object sender, KeyEventArgs e) { } } } ================================================ FILE: BMEngine/UI/RippleEffectDecorator.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace ZenithEngine.UI { public class RippleEffectDecorator : ContentControl { new public double Opacity { get { return (double)GetValue(OpacityProperty); } set { SetValue(OpacityProperty, value); } } // Using a DependencyProperty as the backing store for Opacity. This enables animation, styling, binding, etc... new public static readonly DependencyProperty OpacityProperty = DependencyProperty.Register("Opacity", typeof(double), typeof(RippleEffectDecorator), new PropertyMetadata(0.4)); public double ExpandTime { get { return (double)GetValue(ExpandTimeProperty); } set { SetValue(ExpandTimeProperty, value); } } // Using a DependencyProperty as the backing store for ExpandTime. This enables animation, styling, binding, etc... public static readonly DependencyProperty ExpandTimeProperty = DependencyProperty.Register("ExpandTime", typeof(double), typeof(RippleEffectDecorator), new PropertyMetadata(0.4)); public double FadeTime { get { return (double)GetValue(FadeTimeProperty); } set { SetValue(FadeTimeProperty, value); } } // Using a DependencyProperty as the backing store for FadeTime. This enables animation, styling, binding, etc... public static readonly DependencyProperty FadeTimeProperty = DependencyProperty.Register("FadeTime", typeof(double), typeof(RippleEffectDecorator), new PropertyMetadata(0.3)); public RippleEffectDecorator() { } public override void OnApplyTemplate() { base.OnApplyTemplate(); var parentGrid = new Grid(); var grid = new Grid(); var content = new ContentControl(); grid.Background = Brushes.Transparent; grid.ClipToBounds = true; parentGrid.Children.Add(grid); parentGrid.Children.Add(content); var c = Content; this.Content = parentGrid; content.Content = c; grid.SetBinding(WidthProperty, new Binding("ActualWidth") { Source = parentGrid }); grid.SetBinding(HeightProperty, new Binding("ActualHeight") { Source = parentGrid }); parentGrid.PreviewMouseDown += (sender, e) => { var targetWidth = (Math.Max(ActualWidth, ActualHeight) * 2) / ExpandTime * (ExpandTime + FadeTime); var mousePosition = (e as MouseButtonEventArgs).GetPosition(this); var startMargin = new Thickness(mousePosition.X, mousePosition.Y, 0, 0); var endMargin = new Thickness(mousePosition.X - targetWidth / 2, mousePosition.Y - targetWidth / 2, 0, 0); var ellipse = new Ellipse() { Fill = Brushes.White, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Opacity = Opacity }; ellipse.Margin = startMargin; ellipse.SetBinding(HeightProperty, new Binding("Width") { Source = ellipse }); Storyboard storyboard = new Storyboard(); var expand = new DoubleAnimation(0, targetWidth, new Duration(TimeSpan.FromSeconds(ExpandTime + FadeTime))); storyboard.Children.Add(expand); Storyboard.SetTarget(expand, ellipse); Storyboard.SetTargetProperty(expand, new PropertyPath(WidthProperty)); var marginShrink = new ThicknessAnimation(startMargin, endMargin, new Duration(TimeSpan.FromSeconds(ExpandTime + FadeTime))); storyboard.Children.Add(marginShrink); Storyboard.SetTarget(marginShrink, ellipse); Storyboard.SetTargetProperty(marginShrink, new PropertyPath(MarginProperty)); var opacity = new DoubleAnimation(Opacity, 0, new Duration(TimeSpan.FromSeconds(FadeTime))); opacity.BeginTime = TimeSpan.FromSeconds(ExpandTime); storyboard.Children.Add(opacity); Storyboard.SetTarget(opacity, ellipse); Storyboard.SetTargetProperty(opacity, new PropertyPath(Ellipse.OpacityProperty)); grid.Children.Add(ellipse); storyboard.Begin(); var waitTime = ExpandTime + FadeTime; Task.Run(() => { Thread.Sleep(TimeSpan.FromSeconds(waitTime)); Dispatcher.Invoke(() => { grid.Children.Remove(ellipse); }); }); e.Handled = false; }; } } } ================================================ FILE: BMEngine/UI/Scrollbar.xaml ================================================  ================================================ FILE: BMEngine/UI/ValueSlider.xaml ================================================  ================================================ FILE: BMEngine/UI/ValueSlider.xaml.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ZenithEngine.UI { /// /// Interaction logic for ValueSlider.xaml /// public partial class ValueSlider : UserControl { public double Minimum { get { return (double)GetValue(MinimumProperty); } set { SetValue(MinimumProperty, value); } } public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(ValueSlider), new PropertyMetadata(0.0)); public double Maximum { get { return (double)GetValue(MaximumProperty); } set { SetValue(MaximumProperty, value); } } public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(ValueSlider), new PropertyMetadata(1.0)); public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(ValueSlider), new PropertyMetadata(0.0, (s, e) => (s as ValueSlider).OnValueChange(e))); public int DecimalPoints { get { return (int)GetValue(DecimalPointsProperty); } set { SetValue(DecimalPointsProperty, value); } } public static readonly DependencyProperty DecimalPointsProperty = DependencyProperty.Register("DecimalPoints", typeof(int), typeof(ValueSlider), new PropertyMetadata(0)); public decimal TrueMin { get { return (decimal)GetValue(TrueMinProperty); } set { SetValue(TrueMinProperty, value); } } public static readonly DependencyProperty TrueMinProperty = DependencyProperty.Register("TrueMin", typeof(decimal), typeof(ValueSlider), new PropertyMetadata((decimal)0.0)); public decimal TrueMax { get { return (decimal)GetValue(TrueMaxProperty); } set { SetValue(TrueMaxProperty, value); } } public static readonly DependencyProperty TrueMaxProperty = DependencyProperty.Register("TrueMax", typeof(decimal), typeof(ValueSlider), new PropertyMetadata((decimal)1.0d)); public decimal Step { get => (decimal)GetValue(StepProperty); set => SetValue(StepProperty, value); } public static readonly DependencyProperty StepProperty = DependencyProperty.Register("Step", typeof(decimal), typeof(ValueSlider), new PropertyMetadata((decimal)1)); public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent( "ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(ValueSlider)); public event RoutedPropertyChangedEventHandler ValueChanged { add { AddHandler(ValueChangedEvent, value); } remove { RemoveHandler(ValueChangedEvent, value); } } void OnValueChange(DependencyPropertyChangedEventArgs e) { if (!ignoreslider) slider.Value = nudToSlider(Value); if (!ignorevalue) updown.Value = (decimal)Value; ignoreslider = false; ignorevalue = false; RaiseEvent(new RoutedPropertyChangedEventArgs((double)e.OldValue, (double)e.NewValue, ValueChangedEvent)); } public Func sliderToNud = v => v; public Func nudToSlider = v => v; public ValueSlider() { InitializeComponent(); FocusVisualStyle = null; slider.SetBinding(BetterSlider.MaximumProperty, new Binding("Maximum") { Source = this }); slider.SetBinding(BetterSlider.MinimumProperty, new Binding("Minimum") { Source = this }); updown.SetBinding(NumberSelect.MinimumProperty, new Binding("TrueMin") { Source = this }); updown.SetBinding(NumberSelect.MaximumProperty, new Binding("TrueMax") { Source = this }); updown.SetBinding(NumberSelect.DecimalPointsProperty, new Binding("DecimalPoints") { Source = this }); updown.SetBinding(NumberSelect.StepProperty, new Binding("Step") { Source = this }); } bool ignoreslider = false; bool ignorevalue = false; private void Slider_ValueChanged(object sender, double e) { if (IsInitialized) { ignoreslider = true; Value = sliderToNud(slider.Value); } } private void Updown_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (IsInitialized) { if (!ignorevalue) { ignorevalue = true; Value = (double)updown.Value; } ignorevalue = false; } } } } ================================================ FILE: BMEngine/ZenithEngine.csproj ================================================  Debug AnyCPU {60F2212A-D56C-4776-836F-6A49453CDBC4} Library Properties BMEngine ZenithEngine v4.6.1 512 true true bin\x86\Debug\ DEBUG;TRACE full x86 prompt MinimumRecommendedRules.ruleset bin\x86\Release\ TRACE true pdbonly x86 prompt MinimumRecommendedRules.ruleset true bin\Debug\ DEBUG;TRACE full AnyCPU prompt MinimumRecommendedRules.ruleset bin\Release\ TRACE true pdbonly AnyCPU prompt MinimumRecommendedRules.ruleset true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset ..\packages\OpenTK.3.1.0\lib\net20\OpenTK.dll ..\packages\SharpCompress.0.24.0\lib\net45\SharpCompress.dll NoteColorPalettePick.xaml BetterCheckbox.xaml BetterRadio.xaml BetterSlider.xaml HexColorPicker.xaml NumberSelect.xaml ValueSlider.xaml MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer Designer MSBuild:Compile MSBuild:Compile Designer Designer MSBuild:Compile Designer MSBuild:Compile MSBuild:Compile Designer Designer MSBuild:Compile MSBuild:Compile Designer Designer MSBuild:Compile ================================================ FILE: BMEngine/packages.config ================================================  ================================================ FILE: Black-Midi-Render/App.config ================================================  ================================================ FILE: Black-Midi-Render/GLPostbuffer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ZenithEngine; using OpenTK.Graphics.OpenGL; namespace Zenith_MIDI { class GLPostbuffer: IDisposable { public int BufferID { get; private set; } public int TextureID { get; private set; } public GLPostbuffer(int width, int height) { int b, t; GLUtils.GenFrameBufferTexture(width, height, out b, out t); BufferID = b; TextureID = t; } public void BindBuffer() { GL.BindFramebuffer(FramebufferTarget.Framebuffer, BufferID); } public void BindTexture() { GL.BindTexture(TextureTarget.Texture2D, TextureID); } public static void UnbindBuffers() { GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); } public static void UnbindTextures() { GL.BindTexture(TextureTarget.Texture2D, 0); } public void Dispose() { GL.DeleteFramebuffer(BufferID); GL.DeleteTexture(TextureID); } } } ================================================ FILE: Black-Midi-Render/GLUtils.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using OpenTK.Graphics.OpenGL; namespace Zenith_MIDI { static class GLUtils { public static int MakeShaderProgram(string name) { int _vertexObj = GL.CreateShader(ShaderType.VertexShader); int _fragObj = GL.CreateShader(ShaderType.FragmentShader); int statusCode; string info; GL.ShaderSource(_vertexObj, File.ReadAllText("Shaders\\" + name + ".vert")); GL.CompileShader(_vertexObj); info = GL.GetShaderInfoLog(_vertexObj); GL.GetShader(_vertexObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); GL.ShaderSource(_fragObj, File.ReadAllText("Shaders\\" + name + ".frag")); GL.CompileShader(_fragObj); info = GL.GetShaderInfoLog(_fragObj); GL.GetShader(_fragObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); int shader = GL.CreateProgram(); GL.AttachShader(shader, _fragObj); GL.AttachShader(shader, _vertexObj); GL.LinkProgram(shader); return shader; } public static int MakePostShaderProgram(string name) { int _vertexObj = GL.CreateShader(ShaderType.VertexShader); int _fragObj = GL.CreateShader(ShaderType.FragmentShader); int statusCode; string info; GL.ShaderSource(_vertexObj, File.ReadAllText("Shaders\\Post\\post.vert")); GL.CompileShader(_vertexObj); info = GL.GetShaderInfoLog(_vertexObj); GL.GetShader(_vertexObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); GL.ShaderSource(_fragObj, File.ReadAllText("Shaders\\Post\\" + name + ".frag")); GL.CompileShader(_fragObj); info = GL.GetShaderInfoLog(_fragObj); GL.GetShader(_fragObj, ShaderParameter.CompileStatus, out statusCode); if (statusCode != 1) throw new ApplicationException(info); int shader = GL.CreateProgram(); GL.AttachShader(shader, _fragObj); GL.AttachShader(shader, _vertexObj); GL.LinkProgram(shader); return shader; } public static void GenFrameBufferTexture(int width, int height, out int fbuffer, out int rtexture) { fbuffer = GL.GenFramebuffer(); GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbuffer); rtexture = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, rtexture); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.Byte, (IntPtr)0); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, rtexture, 0); if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete) throw new Exception(); } } } ================================================ FILE: Black-Midi-Render/KDMAPI.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; static class KDMAPI { public struct MIDIHDR { string lpdata; uint dwBufferLength; uint dwBytesRecorded; IntPtr dwUser; uint dwFlags; IntPtr lpNext; IntPtr reserved; uint dwOffset; IntPtr dwReserved; } public enum OMSettingMode { OM_SET = 0x0, OM_GET = 0x1 } public enum OMSetting { OM_CAPFRAMERATE = 0x10000, OM_DEBUGMMODE = 0x10001, OM_DISABLEFADEOUT = 0x10002, OM_DONTMISSNOTES = 0x10003, OM_ENABLESFX = 0x10004, OM_FULLVELOCITY = 0x10005, OM_IGNOREVELOCITYRANGE = 0x10006, OM_IGNOREALLEVENTS = 0x10007, OM_IGNORESYSEX = 0x10008, OM_IGNORESYSRESET = 0x10009, OM_LIMITRANGETO88 = 0x10010, OM_MT32MODE = 0x10011, OM_MONORENDERING = 0x10012, OM_NOTEOFF1 = 0x10013, OM_EVENTPROCWITHAUDIO = 0x10014, OM_SINCINTER = 0x10015, OM_SLEEPSTATES = 0x10016, OM_AUDIOBITDEPTH = 0x10017, OM_AUDIOFREQ = 0x10018, OM_CURRENTENGINE = 0x10019, OM_BUFFERLENGTH = 0x10020, OM_MAXRENDERINGTIME = 0x10021, OM_MINIGNOREVELRANGE = 0x10022, OM_MAXIGNOREVELRANGE = 0x10023, OM_OUTPUTVOLUME = 0x10024, OM_TRANSPOSE = 0x10025, OM_MAXVOICES = 0x10026, OM_SINCINTERCONV = 0x10027, OM_OVERRIDENOTELENGTH = 0x10028, OM_NOTELENGTH = 0x10029, OM_ENABLEDELAYNOTEOFF = 0x10030, OM_DELAYNOTEOFFVAL = 0x10031 } public struct DebugInfo { float RenderingTime; int[] ActiveVoices; double ASIOInputLatency; double ASIOOutputLatency; } [DllImport("OmniMIDI\\OmniMIDI")] public static extern bool ReturnKDMAPIVer(out Int32 Major, out Int32 Minor, out Int32 Build, out Int32 Revision); [DllImport("OmniMIDI\\OmniMIDI")] public static extern bool IsKDMAPIAvailable(); [DllImport("OmniMIDI\\OmniMIDI")] public static extern int InitializeKDMAPIStream(); [DllImport("OmniMIDI\\OmniMIDI")] public static extern int TerminateKDMAPIStream(); [DllImport("OmniMIDI\\OmniMIDI")] public static extern void ResetKDMAPIStream(); [DllImport("OmniMIDI\\OmniMIDI")] public static extern uint SendCustomEvent(uint eventtype, uint chan, uint param); [DllImport("OmniMIDI\\OmniMIDI")] public static extern uint SendDirectData(uint dwMsg); [DllImport("OmniMIDI\\OmniMIDI")] public static extern uint SendDirectDataNoBuf(uint dwMsg); [DllImport("OmniMIDI\\OmniMIDI")] public static extern uint SendDirectLongData(ref MIDIHDR IIMidiHdr); [DllImport("OmniMIDI\\OmniMIDI")] public static extern uint SendDirectLongDataNoBuf(ref MIDIHDR IIMidiHdr); [DllImport("OmniMIDI\\OmniMIDI")] public static extern uint PrepareLongData(ref MIDIHDR IIMidiHdr); [DllImport("OmniMIDI\\OmniMIDI")] public static extern uint UnprepareLongData(ref MIDIHDR IIMidiHdr); [DllImport("OmniMIDI\\OmniMIDI")] public static extern bool DriverSettings(OMSetting Setting, OMSettingMode Mode, IntPtr Value, Int32 cbValue); [DllImport("OmniMIDI\\OmniMIDI")] public static extern void LoadCustomSoundFontsList(ref String Directory); [DllImport("OmniMIDI\\OmniMIDI")] public static extern DebugInfo GetDriverDebugInfo(); } ================================================ FILE: Black-Midi-Render/Languages/en/window.xaml ================================================  English General Modules Module Settings Render Downloading update... Update installed! Click here to restart Zenith Load Unload Width Height Browse FPS Presets Warning: Zenith Preview renders in the resolution above, then downscales to the window size SSAA Increasing SSAA can greatly increase the smoothness of the pixels but takes much more performance Language Render Resolution Preview Options Render Options Reload Start Preview Stop V-Sync Enabled Tempo Multiplier Right click slider or press space to toggle pause Preview Paused Save Path Include Audio Render Transparency Mask Bitrate FFMPEG crf: 0 = lossless, 51 = worst quality possible Delay start (seconds) ffmpeg debug Start Render If uploading the video online, please credit the program Customize FFmpeg Options (for experts, at your own risk) Realtime Playback Disable KDMAPI Enable KDMAPI Note Size Tick Based Time Based Ignore Color Events Use Background Press space to toggle pause, press enter on the preview window to fullscreen Reload Randomise color order Open Palettes Folder ================================================ FILE: Black-Midi-Render/MainWindow.xaml ================================================  True False False False True True False