diff --git a/CdgLib/CDGFile.cs b/CdgLib/CDGFile.cs new file mode 100644 index 0000000..71ba040 --- /dev/null +++ b/CdgLib/CDGFile.cs @@ -0,0 +1,677 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; + +namespace CdgLib +{ + public class CDGFile : IDisposable + { + private const int COLOUR_TABLE_SIZE = 16; + + // To detect redundant calls + private bool disposedValue; + + #region " IDisposable Support " + + // This code added by Visual Basic to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + + // IDisposable + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + m_pStream.Close(); + } + m_pStream = null; + m_pSurface = null; + } + disposedValue = true; + } + + #region "Constants" + + //CDG Command Code + + private const byte CDG_COMMAND = 0x9; + //CDG Instruction Codes + private const int CDG_INST_MEMORY_PRESET = 1; + private const int CDG_INST_BORDER_PRESET = 2; + private const int CDG_INST_TILE_BLOCK = 6; + private const int CDG_INST_SCROLL_PRESET = 20; + private const int CDG_INST_SCROLL_COPY = 24; + private const int CDG_INST_DEF_TRANSP_COL = 28; + private const int CDG_INST_LOAD_COL_TBL_LO = 30; + private const int CDG_INST_LOAD_COL_TBL_HIGH = 31; + + private const int CDG_INST_TILE_BLOCK_XOR = 38; + //Bitmask for all CDG fields + private const byte CDG_MASK = 0x3f; + private const int CDG_PACKET_SIZE = 24; + private const int TILE_HEIGHT = 12; + + private const int TILE_WIDTH = 6; + //This is the size of the display as defined by the CDG specification. + //The pixels in this region can be painted, and scrolling operations + //rotate through this number of pixels. + public const int CDG_FULL_WIDTH = 300; + + public const int CDG_FULL_HEIGHT = 216; + //This is the size of the screen that is actually intended to be + //visible. It is the center area of CDG_FULL. + private const int CDG_DISPLAY_WIDTH = 294; + + private const int CDG_DISPLAY_HEIGHT = 204; + + #endregion + + #region "Private Declarations" + + private readonly byte[,] m_pixelColours = new byte[CDG_FULL_HEIGHT, CDG_FULL_WIDTH]; + private readonly int[] m_colourTable = new int[COLOUR_TABLE_SIZE]; + private int m_presetColourIndex; + private int m_borderColourIndex; + + private int m_transparentColour; + private int m_hOffset; + + private int m_vOffset; + private CdgFileIoStream m_pStream; + private ISurface m_pSurface; + private long m_positionMs; + + private long m_duration; + + private Bitmap mImage; + + #endregion + + #region "Properties" + + public bool Transparent { get; set; } + + public Image RgbImage + { + get + { + Stream temp = new MemoryStream(); + try + { + var i = 0; + for (var ri = 0; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + for (var ci = 0; ci <= CDG_FULL_WIDTH - 1; ci++) + { + var ARGBInt = m_pSurface.rgbData[ri, ci]; + var myByte = new byte[4]; + myByte = BitConverter.GetBytes(ARGBInt); + temp.Write(myByte, 0, 4); + } + } + } + catch (Exception ex) + { + //Do nothing (empty bitmap will be returned) + } + var myBitmap = GraphicUtil.StreamToBitmap(ref temp, CDG_FULL_WIDTH, CDG_FULL_HEIGHT); + if (Transparent) + { + myBitmap.MakeTransparent(myBitmap.GetPixel(1, 1)); + } + return myBitmap; + } + } + + #endregion + + #region "Public Methods" + + //Png Export + public void SavePng(string filename) + { + RgbImage.Save(filename, ImageFormat.Png); + } + + //New + public CDGFile(string cdgFileName) + { + m_pStream = new CdgFileIoStream(); + m_pStream.Open(cdgFileName); + m_pSurface = new ISurface(); + if (m_pStream != null && m_pSurface != null) + { + reset(); + m_duration = m_pStream.Getsize() / CDG_PACKET_SIZE * 1000 / 300; + } + } + + public long getTotalDuration() + { + return m_duration; + } + + public bool renderAtPosition(long ms) + { + var pack = new CdgPacket(); + long numPacks = 0; + var res = true; + + if (m_pStream == null) + { + return false; + } + + if (ms < m_positionMs) + { + if (m_pStream.Seek(0, SeekOrigin.Begin) < 0) + return false; + m_positionMs = 0; + } + + //duration of one packet is 1/300 seconds (4 packets per sector, 75 sectors per second) + + numPacks = ms - m_positionMs; + numPacks /= 10; + + m_positionMs += numPacks * 10; + numPacks *= 3; + + //TODO: double check logic due to inline while loop fucntionality + //AndAlso m_pSurface.rgbData Is Nothing + while (numPacks > 0) + { + res = readPacket(ref pack); + processPacket(ref pack); + numPacks -= 1; + } + + render(); + return res; + } + + #endregion + + #region "Private Methods" + + private void reset() + { + Array.Clear(m_pixelColours, 0, m_pixelColours.Length); + Array.Clear(m_colourTable, 0, m_colourTable.Length); + + m_presetColourIndex = 0; + m_borderColourIndex = 0; + m_transparentColour = 0; + m_hOffset = 0; + m_vOffset = 0; + + m_duration = 0; + m_positionMs = 0; + + //clear surface + if (m_pSurface.rgbData != null) + { + Array.Clear(m_pSurface.rgbData, 0, m_pSurface.rgbData.Length); + } + } + + private bool readPacket(ref CdgPacket pack) + { + if (m_pStream == null || m_pStream.Eof()) + { + return false; + } + + var read = 0; + + read += m_pStream.Read(ref pack.command, 1); + read += m_pStream.Read(ref pack.instruction, 1); + read += m_pStream.Read(ref pack.parityQ, 2); + read += m_pStream.Read(ref pack.data, 16); + read += m_pStream.Read(ref pack.parityP, 4); + + return read == 24; + } + + + private void processPacket(ref CdgPacket pack) + { + var inst_code = 0; + + if ((pack.command[0] & CDG_MASK) == CDG_COMMAND) + { + inst_code = pack.instruction[0] & CDG_MASK; + switch (inst_code) + { + case CDG_INST_MEMORY_PRESET: + memoryPreset(ref pack); + + + break; + case CDG_INST_BORDER_PRESET: + borderPreset(ref pack); + + + break; + case CDG_INST_TILE_BLOCK: + tileBlock(ref pack, false); + + + break; + case CDG_INST_SCROLL_PRESET: + scroll(ref pack, false); + + + break; + case CDG_INST_SCROLL_COPY: + scroll(ref pack, true); + + + break; + case CDG_INST_DEF_TRANSP_COL: + defineTransparentColour(ref pack); + + + break; + case CDG_INST_LOAD_COL_TBL_LO: + loadColorTable(ref pack, 0); + + + break; + case CDG_INST_LOAD_COL_TBL_HIGH: + loadColorTable(ref pack, 1); + + + break; + case CDG_INST_TILE_BLOCK_XOR: + tileBlock(ref pack, true); + + + break; + default: + //Ignore the unsupported commands + + break; + } + } + } + + + private void memoryPreset(ref CdgPacket pack) + { + var colour = 0; + var ri = 0; + var ci = 0; + var repeat = 0; + + colour = pack.data[0] & 0xf; + repeat = pack.data[1] & 0xf; + + //Our new interpretation of CD+G Revealed is that memory preset + //commands should also change the border + m_presetColourIndex = colour; + m_borderColourIndex = colour; + + //we have a reliable data stream, so the repeat command + //is executed only the first time + + + if (repeat == 0) + { + //Note that this may be done before any load colour table + //commands by some CDGs. So the load colour table itself + //actual recalculates the RGB values for all pixels when + //the colour table changes. + + //Set the preset colour for every pixel. Must be stored in + //the pixel colour table indeces array + + for (ri = 0; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + for (ci = 0; ci <= CDG_FULL_WIDTH - 1; ci++) + { + m_pixelColours[ri, ci] = (byte)colour; + } + } + } + } + + + private void borderPreset(ref CdgPacket pack) + { + var colour = 0; + var ri = 0; + var ci = 0; + + colour = pack.data[0] & 0xf; + m_borderColourIndex = colour; + + //The border area is the area contained with a rectangle + //defined by (0,0,300,216) minus the interior pixels which are contained + //within a rectangle defined by (6,12,294,204). + + for (ri = 0; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + for (ci = 0; ci <= 5; ci++) + { + m_pixelColours[ri, ci] = (byte)colour; + } + + for (ci = CDG_FULL_WIDTH - 6; ci <= CDG_FULL_WIDTH - 1; ci++) + { + m_pixelColours[ri, ci] = (byte)colour; + } + } + + for (ci = 6; ci <= CDG_FULL_WIDTH - 7; ci++) + { + for (ri = 0; ri <= 11; ri++) + { + m_pixelColours[ri, ci] = (byte)colour; + } + + for (ri = CDG_FULL_HEIGHT - 12; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + m_pixelColours[ri, ci] = (byte)colour; + } + } + } + + + private void loadColorTable(ref CdgPacket pack, int table) + { + for (var i = 0; i <= 7; i++) + { + //[---high byte---] [---low byte----] + //7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 + //X X r r r r g g X X g g b b b b + + var byte0 = pack.data[2 * i]; + var byte1 = pack.data[2 * i + 1]; + var red = (byte0 & 0x3f) >> 2; + var green = ((byte0 & 0x3) << 2) | ((byte1 & 0x3f) >> 4); + var blue = byte1 & 0xf; + + red *= 17; + green *= 17; + blue *= 17; + + if (m_pSurface != null) + { + m_colourTable[i + table * 8] = m_pSurface.MapRGBColour(red, green, blue); + } + } + } + + + private void tileBlock(ref CdgPacket pack, bool bXor) + { + var colour0 = 0; + var colour1 = 0; + var column_index = 0; + var row_index = 0; + var myByte = 0; + var pixel = 0; + var xor_col = 0; + var currentColourIndex = 0; + var new_col = 0; + + colour0 = pack.data[0] & 0xf; + colour1 = pack.data[1] & 0xf; + row_index = (pack.data[2] & 0x1f) * 12; + column_index = (pack.data[3] & 0x3f) * 6; + + if (row_index > CDG_FULL_HEIGHT - TILE_HEIGHT) + return; + if (column_index > CDG_FULL_WIDTH - TILE_WIDTH) + return; + + //Set the pixel array for each of the pixels in the 12x6 tile. + //Normal = Set the colour to either colour0 or colour1 depending + //on whether the pixel value is 0 or 1. + //XOR = XOR the colour with the colour index currently there. + + + for (var i = 0; i <= 11; i++) + { + myByte = pack.data[4 + i] & 0x3f; + for (var j = 0; j <= 5; j++) + { + pixel = (myByte >> (5 - j)) & 0x1; + if (bXor) + { + //Tile Block XOR + if (pixel == 0) + { + xor_col = colour0; + } + else + { + xor_col = colour1; + } + + //Get the colour index currently at this location, and xor with it + currentColourIndex = m_pixelColours[row_index + i, column_index + j]; + new_col = currentColourIndex ^ xor_col; + } + else + { + if (pixel == 0) + { + new_col = colour0; + } + else + { + new_col = colour1; + } + } + + //Set the pixel with the new colour. We set both the surfarray + //containing actual RGB values, as well as our array containing + //the colour indexes into our colour table. + m_pixelColours[row_index + i, column_index + j] = (byte)new_col; + } + } + } + + private void defineTransparentColour(ref CdgPacket pack) + { + m_transparentColour = pack.data[0] & 0xf; + } + + + private void scroll(ref CdgPacket pack, bool copy) + { + var colour = 0; + var hScroll = 0; + var vScroll = 0; + var hSCmd = 0; + var hOffset = 0; + var vSCmd = 0; + var vOffset = 0; + var vScrollPixels = 0; + var hScrollPixels = 0; + + //Decode the scroll command parameters + colour = pack.data[0] & 0xf; + hScroll = pack.data[1] & 0x3f; + vScroll = pack.data[2] & 0x3f; + + hSCmd = (hScroll & 0x30) >> 4; + hOffset = hScroll & 0x7; + vSCmd = (vScroll & 0x30) >> 4; + vOffset = vScroll & 0xf; + + + m_hOffset = hOffset < 5 ? hOffset : 5; + m_vOffset = vOffset < 11 ? vOffset : 11; + + //Scroll Vertical - Calculate number of pixels + + vScrollPixels = 0; + if (vSCmd == 2) + { + vScrollPixels = -12; + } + else if (vSCmd == 1) + { + vScrollPixels = 12; + } + + //Scroll Horizontal- Calculate number of pixels + + hScrollPixels = 0; + if (hSCmd == 2) + { + hScrollPixels = -6; + } + else if (hSCmd == 1) + { + hScrollPixels = 6; + } + + if (hScrollPixels == 0 && vScrollPixels == 0) + { + return; + } + + //Perform the actual scroll. + + var temp = new byte[CDG_FULL_HEIGHT + 1, CDG_FULL_WIDTH + 1]; + var vInc = vScrollPixels + CDG_FULL_HEIGHT; + var hInc = hScrollPixels + CDG_FULL_WIDTH; + var ri = 0; + //row index + var ci = 0; + //column index + + for (ri = 0; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + for (ci = 0; ci <= CDG_FULL_WIDTH - 1; ci++) + { + temp[(ri + vInc) % CDG_FULL_HEIGHT, (ci + hInc) % CDG_FULL_WIDTH] = m_pixelColours[ri, ci]; + } + } + + + //if copy is false, we were supposed to fill in the new pixels + //with a new colour. Go back and do that now. + + + if (copy == false) + { + if (vScrollPixels > 0) + { + for (ci = 0; ci <= CDG_FULL_WIDTH - 1; ci++) + { + for (ri = 0; ri <= vScrollPixels - 1; ri++) + { + temp[ri, ci] = (byte)colour; + } + } + } + else if (vScrollPixels < 0) + { + for (ci = 0; ci <= CDG_FULL_WIDTH - 1; ci++) + { + for (ri = CDG_FULL_HEIGHT + vScrollPixels; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + temp[ri, ci] = (byte)colour; + } + } + } + + + if (hScrollPixels > 0) + { + for (ci = 0; ci <= hScrollPixels - 1; ci++) + { + for (ri = 0; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + temp[ri, ci] = (byte)colour; + } + } + } + else if (hScrollPixels < 0) + { + for (ci = CDG_FULL_WIDTH + hScrollPixels; ci <= CDG_FULL_WIDTH - 1; ci++) + { + for (ri = 0; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + temp[ri, ci] = (byte)colour; + } + } + } + } + + //Now copy the temporary buffer back to our array + + for (ri = 0; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + for (ci = 0; ci <= CDG_FULL_WIDTH - 1; ci++) + { + m_pixelColours[ri, ci] = temp[ri, ci]; + } + } + } + + + private void render() + { + if (m_pSurface == null) + return; + for (var ri = 0; ri <= CDG_FULL_HEIGHT - 1; ri++) + { + for (var ci = 0; ci <= CDG_FULL_WIDTH - 1; ci++) + { + if (ri < TILE_HEIGHT || ri >= CDG_FULL_HEIGHT - TILE_HEIGHT || ci < TILE_WIDTH || + ci >= CDG_FULL_WIDTH - TILE_WIDTH) + { + m_pSurface.rgbData[ri, ci] = m_colourTable[m_borderColourIndex]; + } + else + { + m_pSurface.rgbData[ri, ci] = m_colourTable[m_pixelColours[ri + m_vOffset, ci + m_hOffset]]; + } + } + } + } + + #endregion + } +} + + +namespace CdgLib +{ + public class CdgPacket + { + public byte[] command = new byte[1]; + public byte[] data = new byte[16]; + public byte[] instruction = new byte[1]; + public byte[] parityP = new byte[4]; + public byte[] parityQ = new byte[2]; + } +} + +namespace CdgLib +{ + public class ISurface + { + public int[,] rgbData = new int[CDGFile.CDG_FULL_HEIGHT, CDGFile.CDG_FULL_WIDTH]; + + public int MapRGBColour(int red, int green, int blue) + { + return Color.FromArgb(red, green, blue).ToArgb(); + } + } +} diff --git a/CdgLib/CdgFileIoStream.cs b/CdgLib/CdgFileIoStream.cs new file mode 100644 index 0000000..8d25f5d --- /dev/null +++ b/CdgLib/CdgFileIoStream.cs @@ -0,0 +1,96 @@ +using System.IO; + +namespace CdgLib +{ + + /// + /// + public class CdgFileIoStream + { + private Stream _cdgFile; + + /// + /// + public CdgFileIoStream() + { + _cdgFile = null; + } + + /// + /// Reads the specified buf. + /// + /// The buf. + /// The buf_size. + /// + public int Read(ref byte[] buf, int bufSize) + { + return _cdgFile.Read(buf, 0, bufSize); + } + + /// + /// Writes the specified buf. + /// + /// The buf. + /// The buf_size. + /// + public int Write(ref byte[] buf, int bufSize) + { + _cdgFile.Write(buf, 0, bufSize); + return 1; + } + + /// + /// Seeks the specified offset. + /// + /// The offset. + /// The whence. + /// + public int Seek(int offset, SeekOrigin whence) + { + return (int)_cdgFile.Seek(offset, whence); + } + + /// + /// EOFs this instance. + /// + /// + public bool Eof() + { + return _cdgFile.Position >= _cdgFile.Length; + } + + /// + /// Getsizes this instance. + /// + /// + public int Getsize() + { + return (int)_cdgFile.Length; + } + + /// + /// Opens the specified filename. + /// + /// The filename. + /// + public bool Open(string filename) + { + Close(); + _cdgFile = new FileStream(filename, FileMode.Open); + return _cdgFile != null; + } + + /// + /// Closes this instance. + /// + public void Close() + { + if (_cdgFile != null) + { + _cdgFile.Close(); + _cdgFile = null; + } + } + } +} + diff --git a/CdgLib/CdgLib.csproj b/CdgLib/CdgLib.csproj new file mode 100644 index 0000000..3103364 --- /dev/null +++ b/CdgLib/CdgLib.csproj @@ -0,0 +1,57 @@ + + + + + Debug + AnyCPU + {3203DFD2-DA5B-47B3-B009-18DD9C401FC3} + Library + Properties + CdgLib + CdgLib + v4.6 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CdgLib/GraphicUtil.cs b/CdgLib/GraphicUtil.cs new file mode 100644 index 0000000..d64191f --- /dev/null +++ b/CdgLib/GraphicUtil.cs @@ -0,0 +1,109 @@ +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.InteropServices; + +namespace CdgLib +{ + /// + /// + public class GraphicUtil + { + /// + /// Bitmaps to stream. + /// + /// The filename. + /// + public static Stream BitmapToStream(string filename) + { + var oldBmp = (Bitmap)Image.FromFile(filename); + var oldData = oldBmp.LockBits(new Rectangle(0, 0, oldBmp.Width, oldBmp.Height), ImageLockMode.WriteOnly, + PixelFormat.Format24bppRgb); + var length = oldData.Stride * oldBmp.Height; + var stream = new byte[length]; + Marshal.Copy(oldData.Scan0, stream, 0, length); + oldBmp.UnlockBits(oldData); + oldBmp.Dispose(); + return new MemoryStream(stream); + } + + + /// + /// Streams to bitmap. + /// + /// The stream. + /// The width. + /// The height. + /// + public static Bitmap StreamToBitmap(ref Stream stream, int width, int height) + { + //create a new bitmap + var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); + var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat); + stream.Seek(0, SeekOrigin.Begin); + //copy the stream of pixel + for (var n = 0; n <= stream.Length - 1; n++) + { + var myByte = new byte[1]; + stream.Read(myByte, 0, 1); + Marshal.WriteByte(bmpData.Scan0, n, myByte[0]); + } + bmp.UnlockBits(bmpData); + return bmp; + } + + /// + /// Gets the CDG size bitmap. + /// + /// The filename. + /// + public static Bitmap GetCdgSizeBitmap(string filename) + { + var bm = new Bitmap(filename); + return ResizeBitmap(ref bm, CDGFile.CDG_FULL_WIDTH, CDGFile.CDG_FULL_HEIGHT); + } + + /// + /// Resizes the bitmap. + /// + /// The bm. + /// The width. + /// The height. + /// + public static Bitmap ResizeBitmap(ref Bitmap bm, int width, int height) + { + var thumb = new Bitmap(width, height); + using (bm) + { + using (var g = Graphics.FromImage(thumb)) + { + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.DrawImage(bm, new Rectangle(0, 0, width, height), new Rectangle(0, 0, bm.Width, bm.Height), + GraphicsUnit.Pixel); + } + } + return thumb; + } + + /// + /// Merges the images with transparency. + /// + /// The pic1. + /// The pic2. + /// + public static Bitmap MergeImagesWithTransparency(Bitmap picture1, Bitmap picture2) + { + Bitmap mergedImage; + var bm = new Bitmap(picture1.Width, picture1.Height); + using (var gr = Graphics.FromImage(bm)) + { + gr.DrawImage(picture1, 0, 0); + picture2.MakeTransparent(picture2.GetPixel(1, 1)); + gr.DrawImage(picture2, 0, 0); + mergedImage = bm; + } + return mergedImage; + } + } +} diff --git a/CdgLib/Properties/AssemblyInfo.cs b/CdgLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0b89514 --- /dev/null +++ b/CdgLib/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CdgLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CdgLib")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3203dfd2-da5b-47b3-b009-18dd9c401fc3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/KaraokeConverter/App.config b/KaraokeConverter/App.config new file mode 100644 index 0000000..8324aa6 --- /dev/null +++ b/KaraokeConverter/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/KaraokeConverter/ExportAVI.cs b/KaraokeConverter/ExportAVI.cs new file mode 100644 index 0000000..769f04e --- /dev/null +++ b/KaraokeConverter/ExportAVI.cs @@ -0,0 +1,130 @@ +using AviFile; +using CdgLib; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace KaraokeConverter +{ + public class ExportAVI + { + + + public void CDGtoAVI(string aviFileName, string cdgFileName, string mp3FileName, double frameRate, string backgroundFileName = "") + { + Bitmap backgroundBmp = null; + Bitmap mergedBMP = null; + VideoStream aviStream = null; + CDGFile myCDGFile = new CDGFile(cdgFileName); + myCDGFile.renderAtPosition(0); + Bitmap bitmap__1 = (Bitmap)myCDGFile.RgbImage; + if (!string.IsNullOrEmpty(backgroundFileName)) + { + try + { + if (IsMovie(backgroundFileName)) + backgroundBmp = MovieFrameExtractor.GetBitmap(0, backgroundFileName, CDGFile.CDG_FULL_WIDTH, CDGFile.CDG_FULL_HEIGHT); + if (IsGraphic(backgroundFileName)) + backgroundBmp = GraphicUtil.GetCdgSizeBitmap(backgroundFileName); + } + catch (Exception ex) + { + } + } + AviManager aviManager = new AviManager(aviFileName, false); + if (backgroundBmp != null) + { + mergedBMP = GraphicUtil.MergeImagesWithTransparency(backgroundBmp, bitmap__1); + aviStream = aviManager.AddVideoStream(true, frameRate, mergedBMP); + mergedBMP.Dispose(); + if (IsMovie(backgroundFileName)) + backgroundBmp.Dispose(); + } + else { + aviStream = aviManager.AddVideoStream(true, frameRate, bitmap__1); + } + + int count = 0; + double frameInterval = 1000 / frameRate; + long totalDuration = myCDGFile.getTotalDuration(); + double position = 0; + while (position <= totalDuration) + { + count += 1; + position = count * frameInterval; + myCDGFile.renderAtPosition(Convert.ToInt64(position)); + bitmap__1 = (Bitmap)myCDGFile.RgbImage; + if (!string.IsNullOrEmpty(backgroundFileName)) + { + if (IsMovie(backgroundFileName)) + backgroundBmp = MovieFrameExtractor.GetBitmap(position / 1000, backgroundFileName, CDGFile.CDG_FULL_WIDTH, CDGFile.CDG_FULL_HEIGHT); + } + if (backgroundBmp != null) + { + mergedBMP = GraphicUtil.MergeImagesWithTransparency(backgroundBmp, bitmap__1); + aviStream.AddFrame(mergedBMP); + mergedBMP.Dispose(); + if (IsMovie(backgroundFileName)) + backgroundBmp.Dispose(); + } + else { + aviStream.AddFrame(bitmap__1); + } + bitmap__1.Dispose(); + int percentageDone = (int)((position / totalDuration) * 100); + if (Status != null) + { + Status(percentageDone.ToString()); + } + Application.DoEvents(); + } + myCDGFile.Dispose(); + aviManager.Close(); + if (backgroundBmp != null) + backgroundBmp.Dispose(); + AddMP3toAVI(aviFileName, mp3FileName); + } + + public static void AddMP3toAVI(string aviFileName, string mp3FileName) + { + /* + string newAVIFileName = Regex.Replace(aviFileName, "\\.avi$", "MUX.avi", RegexOptions.IgnoreCase); + string cmdLineArgs = "-ovc copy -oac copy -audiofile \"" + mp3FileName + "\" -o \"" + newAVIFileName + "\" \"" + aviFileName + "\""; + using (Process myProcess = new Process()) { + string myCMD = "\"" + System.AppDomain.CurrentDomain.BaseDirectory() + "mencoder.exe \"" + cmdLineArgs; + myProcess.StartInfo.FileName = "\"" + System.AppDomain.CurrentDomain.BaseDirectory() + "mencoder.exe\""; + myProcess.StartInfo.Arguments = cmdLineArgs; + myProcess.StartInfo.UseShellExecute = false; + myProcess.StartInfo.CreateNoWindow = true; + myProcess.Start(); + myProcess.PriorityClass = ProcessPriorityClass.Normal; + myProcess.WaitForExit(); + } + if (File.Exists(newAVIFileName)) { + File.Delete(aviFileName); + File.Move(newAVIFileName, aviFileName); + } + */ + } + + public static bool IsMovie(string filename) + { + return Regex.IsMatch(filename, "^.+(\\.avi|\\.mpg|\\.wmv)$", RegexOptions.IgnoreCase); + } + + public static bool IsGraphic(string filename) + { + return Regex.IsMatch(filename, "^.+(\\.jpg|\\.bmp|\\.png|\\.tif|\\.tiff|\\.gif|\\.wmf)$", RegexOptions.IgnoreCase); + } + + public event StatusEventHandler Status; + public delegate void StatusEventHandler(string message); + + + } +} diff --git a/KaraokeConverter/Form1.Designer.cs b/KaraokeConverter/Form1.Designer.cs new file mode 100644 index 0000000..a60be36 --- /dev/null +++ b/KaraokeConverter/Form1.Designer.cs @@ -0,0 +1,314 @@ +namespace KaraokeConverter +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tbFileName = new System.Windows.Forms.TextBox(); + this.btBrowseCDG = new System.Windows.Forms.Button(); + this.OpenFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.Panel1 = new System.Windows.Forms.Panel(); + this.GroupBox3 = new System.Windows.Forms.GroupBox(); + this.chkBackGraph = new System.Windows.Forms.CheckBox(); + this.tbBackGroundImg = new System.Windows.Forms.TextBox(); + this.btBrowseImg = new System.Windows.Forms.Button(); + this.chkBackGround = new System.Windows.Forms.CheckBox(); + this.tbBackGroundAVI = new System.Windows.Forms.TextBox(); + this.btBackGroundBrowse = new System.Windows.Forms.Button(); + this.lbSaveAs = new System.Windows.Forms.Label(); + this.tbAVIFile = new System.Windows.Forms.TextBox(); + this.btOutputAVI = new System.Windows.Forms.Button(); + this.tbFPS = new System.Windows.Forms.TextBox(); + this.lbFPS = new System.Windows.Forms.Label(); + this.btConvert = new System.Windows.Forms.Button(); + this.GroupBox2 = new System.Windows.Forms.GroupBox(); + this.GroupBox1 = new System.Windows.Forms.GroupBox(); + this.pbAVI = new System.Windows.Forms.ProgressBar(); + this.Panel2 = new System.Windows.Forms.Panel(); + this.SaveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.Panel1.SuspendLayout(); + this.GroupBox3.SuspendLayout(); + this.GroupBox2.SuspendLayout(); + this.GroupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // tbFileName + // + this.tbFileName.Location = new System.Drawing.Point(9, 13); + this.tbFileName.Name = "tbFileName"; + this.tbFileName.ReadOnly = true; + this.tbFileName.Size = new System.Drawing.Size(475, 20); + this.tbFileName.TabIndex = 0; + // + // btBrowseCDG + // + this.btBrowseCDG.Location = new System.Drawing.Point(490, 11); + this.btBrowseCDG.Name = "btBrowseCDG"; + this.btBrowseCDG.Size = new System.Drawing.Size(68, 23); + this.btBrowseCDG.TabIndex = 1; + this.btBrowseCDG.Text = "Browse..."; + this.btBrowseCDG.UseVisualStyleBackColor = true; + this.btBrowseCDG.Click += new System.EventHandler(this.btBrowseCDG_Click); + // + // OpenFileDialog1 + // + this.OpenFileDialog1.FileName = "OpenFileDialog1"; + // + // Panel1 + // + this.Panel1.Controls.Add(this.GroupBox3); + this.Panel1.Controls.Add(this.GroupBox2); + this.Panel1.Controls.Add(this.GroupBox1); + this.Panel1.Dock = System.Windows.Forms.DockStyle.Top; + this.Panel1.Location = new System.Drawing.Point(0, 0); + this.Panel1.Name = "Panel1"; + this.Panel1.Size = new System.Drawing.Size(577, 255); + this.Panel1.TabIndex = 3; + // + // GroupBox3 + // + this.GroupBox3.Controls.Add(this.chkBackGraph); + this.GroupBox3.Controls.Add(this.tbBackGroundImg); + this.GroupBox3.Controls.Add(this.btBrowseImg); + this.GroupBox3.Controls.Add(this.chkBackGround); + this.GroupBox3.Controls.Add(this.tbBackGroundAVI); + this.GroupBox3.Controls.Add(this.btBackGroundBrowse); + this.GroupBox3.Controls.Add(this.lbSaveAs); + this.GroupBox3.Controls.Add(this.tbAVIFile); + this.GroupBox3.Controls.Add(this.btOutputAVI); + this.GroupBox3.Controls.Add(this.tbFPS); + this.GroupBox3.Controls.Add(this.lbFPS); + this.GroupBox3.Controls.Add(this.btConvert); + this.GroupBox3.Location = new System.Drawing.Point(3, 53); + this.GroupBox3.Name = "GroupBox3"; + this.GroupBox3.Size = new System.Drawing.Size(571, 145); + this.GroupBox3.TabIndex = 18; + this.GroupBox3.TabStop = false; + this.GroupBox3.Text = "AVI Settings"; + // + // chkBackGraph + // + this.chkBackGraph.AutoSize = true; + this.chkBackGraph.Location = new System.Drawing.Point(7, 79); + this.chkBackGraph.Name = "chkBackGraph"; + this.chkBackGraph.Size = new System.Drawing.Size(122, 17); + this.chkBackGraph.TabIndex = 23; + this.chkBackGraph.Text = "Background graphic"; + this.chkBackGraph.UseVisualStyleBackColor = true; + this.chkBackGraph.CheckedChanged += new System.EventHandler(this.chkBackGraph_CheckedChanged); + // + // tbBackGroundImg + // + this.tbBackGroundImg.Enabled = false; + this.tbBackGroundImg.Location = new System.Drawing.Point(128, 77); + this.tbBackGroundImg.Name = "tbBackGroundImg"; + this.tbBackGroundImg.Size = new System.Drawing.Size(356, 20); + this.tbBackGroundImg.TabIndex = 21; + // + // btBrowseImg + // + this.btBrowseImg.Enabled = false; + this.btBrowseImg.Location = new System.Drawing.Point(490, 75); + this.btBrowseImg.Name = "btBrowseImg"; + this.btBrowseImg.Size = new System.Drawing.Size(75, 23); + this.btBrowseImg.TabIndex = 22; + this.btBrowseImg.Text = "Browse..."; + this.btBrowseImg.UseVisualStyleBackColor = true; + this.btBrowseImg.Click += new System.EventHandler(this.btBrowseImg_Click); + // + // chkBackGround + // + this.chkBackGround.AutoSize = true; + this.chkBackGround.Location = new System.Drawing.Point(7, 51); + this.chkBackGround.Name = "chkBackGround"; + this.chkBackGround.Size = new System.Drawing.Size(115, 17); + this.chkBackGround.TabIndex = 20; + this.chkBackGround.Text = "Background movie"; + this.chkBackGround.UseVisualStyleBackColor = true; + this.chkBackGround.CheckedChanged += new System.EventHandler(this.chkBackGround_CheckedChanged); + // + // tbBackGroundAVI + // + this.tbBackGroundAVI.Enabled = false; + this.tbBackGroundAVI.Location = new System.Drawing.Point(128, 49); + this.tbBackGroundAVI.Name = "tbBackGroundAVI"; + this.tbBackGroundAVI.Size = new System.Drawing.Size(356, 20); + this.tbBackGroundAVI.TabIndex = 17; + // + // btBackGroundBrowse + // + this.btBackGroundBrowse.Enabled = false; + this.btBackGroundBrowse.Location = new System.Drawing.Point(490, 47); + this.btBackGroundBrowse.Name = "btBackGroundBrowse"; + this.btBackGroundBrowse.Size = new System.Drawing.Size(75, 23); + this.btBackGroundBrowse.TabIndex = 18; + this.btBackGroundBrowse.Text = "Browse..."; + this.btBackGroundBrowse.UseVisualStyleBackColor = true; + this.btBackGroundBrowse.Click += new System.EventHandler(this.btBackGroundBrowse_Click); + // + // lbSaveAs + // + this.lbSaveAs.AutoSize = true; + this.lbSaveAs.Location = new System.Drawing.Point(76, 22); + this.lbSaveAs.Name = "lbSaveAs"; + this.lbSaveAs.Size = new System.Drawing.Size(46, 13); + this.lbSaveAs.TabIndex = 16; + this.lbSaveAs.Text = "Save as"; + // + // tbAVIFile + // + this.tbAVIFile.Location = new System.Drawing.Point(128, 19); + this.tbAVIFile.Name = "tbAVIFile"; + this.tbAVIFile.Size = new System.Drawing.Size(356, 20); + this.tbAVIFile.TabIndex = 9; + // + // btOutputAVI + // + this.btOutputAVI.Location = new System.Drawing.Point(490, 17); + this.btOutputAVI.Name = "btOutputAVI"; + this.btOutputAVI.Size = new System.Drawing.Size(75, 23); + this.btOutputAVI.TabIndex = 10; + this.btOutputAVI.Text = "Browse..."; + this.btOutputAVI.UseVisualStyleBackColor = true; + this.btOutputAVI.Click += new System.EventHandler(this.btOutputAVI_Click_1); + // + // tbFPS + // + this.tbFPS.Location = new System.Drawing.Point(128, 108); + this.tbFPS.Name = "tbFPS"; + this.tbFPS.Size = new System.Drawing.Size(67, 20); + this.tbFPS.TabIndex = 15; + this.tbFPS.Text = "15"; + // + // lbFPS + // + this.lbFPS.AutoSize = true; + this.lbFPS.Location = new System.Drawing.Point(201, 111); + this.lbFPS.Name = "lbFPS"; + this.lbFPS.Size = new System.Drawing.Size(94, 13); + this.lbFPS.TabIndex = 12; + this.lbFPS.Text = "frames per second"; + // + // btConvert + // + this.btConvert.Location = new System.Drawing.Point(490, 106); + this.btConvert.Name = "btConvert"; + this.btConvert.Size = new System.Drawing.Size(75, 23); + this.btConvert.TabIndex = 13; + this.btConvert.Text = "Create AVI"; + this.btConvert.UseVisualStyleBackColor = true; + this.btConvert.Click += new System.EventHandler(this.btConvert_Click); + // + // GroupBox2 + // + this.GroupBox2.Controls.Add(this.tbFileName); + this.GroupBox2.Controls.Add(this.btBrowseCDG); + this.GroupBox2.Location = new System.Drawing.Point(3, 3); + this.GroupBox2.Name = "GroupBox2"; + this.GroupBox2.Size = new System.Drawing.Size(571, 40); + this.GroupBox2.TabIndex = 17; + this.GroupBox2.TabStop = false; + this.GroupBox2.Text = "MP3 + CDG File"; + // + // GroupBox1 + // + this.GroupBox1.Controls.Add(this.pbAVI); + this.GroupBox1.Location = new System.Drawing.Point(3, 204); + this.GroupBox1.Name = "GroupBox1"; + this.GroupBox1.Size = new System.Drawing.Size(571, 48); + this.GroupBox1.TabIndex = 16; + this.GroupBox1.TabStop = false; + this.GroupBox1.Text = "Progress"; + // + // pbAVI + // + this.pbAVI.Location = new System.Drawing.Point(7, 19); + this.pbAVI.Name = "pbAVI"; + this.pbAVI.Size = new System.Drawing.Size(555, 23); + this.pbAVI.TabIndex = 14; + // + // Panel2 + // + this.Panel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.Panel2.Location = new System.Drawing.Point(0, 255); + this.Panel2.Name = "Panel2"; + this.Panel2.Size = new System.Drawing.Size(577, 0); + this.Panel2.TabIndex = 4; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(577, 253); + this.Controls.Add(this.Panel2); + this.Controls.Add(this.Panel1); + this.Name = "Form1"; + this.Text = "MP3+CDG To Video Converter"; + this.Panel1.ResumeLayout(false); + this.GroupBox3.ResumeLayout(false); + this.GroupBox3.PerformLayout(); + this.GroupBox2.ResumeLayout(false); + this.GroupBox2.PerformLayout(); + this.GroupBox1.ResumeLayout(false); + this.ResumeLayout(false); + + } + private System.Windows.Forms.TextBox tbFileName; + private System.Windows.Forms.Button btBrowseCDG; + + private System.Windows.Forms.OpenFileDialog OpenFileDialog1; + private System.Windows.Forms.Panel Panel1; + private System.Windows.Forms.Panel Panel2; + private System.Windows.Forms.GroupBox GroupBox2; + private System.Windows.Forms.GroupBox GroupBox1; + private System.Windows.Forms.ProgressBar pbAVI; + private System.Windows.Forms.TextBox tbFPS; + + private System.Windows.Forms.Button btConvert; + + private System.Windows.Forms.Label lbFPS; + private System.Windows.Forms.Button btOutputAVI; + + private System.Windows.Forms.TextBox tbAVIFile; + private System.Windows.Forms.GroupBox GroupBox3; + private System.Windows.Forms.SaveFileDialog SaveFileDialog1; + private System.Windows.Forms.TextBox tbBackGroundAVI; + private System.Windows.Forms.Button btBackGroundBrowse; + + private System.Windows.Forms.Label lbSaveAs; + private System.Windows.Forms.CheckBox chkBackGround; + + private System.Windows.Forms.CheckBox chkBackGraph; + + private System.Windows.Forms.TextBox tbBackGroundImg; + private System.Windows.Forms.Button btBrowseImg; + + + #endregion + } +} + diff --git a/KaraokeConverter/Form1.cs b/KaraokeConverter/Form1.cs new file mode 100644 index 0000000..1a82fb5 --- /dev/null +++ b/KaraokeConverter/Form1.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using CdgLib; + +namespace KaraokeConverter +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + #region "Private Declarations" + + private CDGFile mCDGFile; + private CdgFileIoStream mCDGStream; + private string mCDGFileName; + private string mMP3FileName; + private string mTempDir; + private ExportAVI withEventsField_mExportAVI; + private ExportAVI mExportAVI + { + get { return withEventsField_mExportAVI; } + set + { + if (withEventsField_mExportAVI != null) + { + withEventsField_mExportAVI.Status -= mExportAVI_Status; + } + withEventsField_mExportAVI = value; + if (withEventsField_mExportAVI != null) + { + withEventsField_mExportAVI.Status += mExportAVI_Status; + } + } + + } + #endregion + + #region "Control Events" + + private void btOutputAVI_Click_1(System.Object sender, System.EventArgs e) + { + SelectOutputAVI(); + } + + private void btBackGroundBrowse_Click(System.Object sender, System.EventArgs e) + { + SelectBackGroundAVI(); + } + + private void btConvert_Click(System.Object sender, System.EventArgs e) + { + ConvertAVI(); + } + + private void tbFPS_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) + { + /* + if ((Strings.Asc(e.KeyChar) >= Keys.D0 & Strings.Asc(e.KeyChar) <= Keys.D9) | Strings.Asc(e.KeyChar) == Keys.Back | e.KeyChar == ".") { + e.Handled = false; + } else { + e.Handled = true; + } + */ + } + + private void btBrowseCDG_Click(System.Object sender, System.EventArgs e) + { + OpenFileDialog1.Filter = "CDG or Zip Files (*.zip, *.cdg)|*.zip;*.cdg"; + OpenFileDialog1.ShowDialog(); + tbFileName.Text = OpenFileDialog1.FileName; + } + + private void chkBackGraph_CheckedChanged(System.Object sender, System.EventArgs e) + { + if (chkBackGround.Checked && chkBackGraph.Checked) + { + chkBackGround.Checked = false; + } + ToggleCheckBox(); + } + + private void chkBackGround_CheckedChanged(System.Object sender, System.EventArgs e) + { + if (chkBackGraph.Checked && chkBackGround.Checked) + { + chkBackGraph.Checked = false; + } + ToggleCheckBox(); + } + + private void btBrowseImg_Click(System.Object sender, System.EventArgs e) + { + SelectBackGroundGraphic(); + } + + #endregion + + #region "Events" + + private void mExportAVI_Status(string message) + { + pbAVI.Value = (Convert.ToInt32(message)); + } + + #endregion + + #region "Private Methods" + + private void SelectOutputAVI() + { + SaveFileDialog1.Filter = "AVI Files (*.avi)|*.avi"; + SaveFileDialog1.ShowDialog(); + tbAVIFile.Text = SaveFileDialog1.FileName; + } + + private void SelectBackGroundAVI() + { + OpenFileDialog1.Filter = "Movie Files (*.avi, *.mpg, *.wmv)|*.avi;*.mpg;*.wmv"; + OpenFileDialog1.ShowDialog(); + tbBackGroundAVI.Text = OpenFileDialog1.FileName; + } + + private void SelectBackGroundGraphic() + { + OpenFileDialog1.Filter = "Graphic Files|*.jpg;*.bmp;*.png;*.tif;*.tiff;*.gif;*.wmf"; + OpenFileDialog1.ShowDialog(); + tbBackGroundImg.Text = OpenFileDialog1.FileName; + } + + private void ConvertAVI() + { + try + { + PreProcessFiles(); + if (string.IsNullOrEmpty(mCDGFileName) | string.IsNullOrEmpty(mMP3FileName)) + { + MessageBox.Show("Cannot find a CDG and MP3 file to convert together."); + return; + } + } + catch (Exception ex) + { + //Do nothing for now + } + mExportAVI = new ExportAVI(); + pbAVI.Value = 0; + string backGroundFilename = ""; + if (chkBackGraph.Checked) + backGroundFilename = tbBackGroundImg.Text; + if (chkBackGround.Checked) + backGroundFilename = tbBackGroundAVI.Text; + mExportAVI.CDGtoAVI(tbAVIFile.Text, mCDGFileName, mMP3FileName, Convert.ToDouble(tbFPS.Text), backGroundFilename); + pbAVI.Value = 0; + try + { + CleanUp(); + } + catch (Exception ex) + { + //Do nothing for now + } + } + + private void CleanUp() + { + if (!string.IsNullOrEmpty(mTempDir)) + { + try + { + Directory.Delete(mTempDir, true); + } + catch (Exception ex) + { + } + } + mTempDir = ""; + } + + private void PreProcessFiles() + { + /* + string myCDGFileName = ""; + if (Regex.IsMatch(tbFileName.Text, "\\.zip$")) { + string myTempDir = Path.GetTempPath() + Path.GetRandomFileName(); + Directory.CreateDirectory(myTempDir); + mTempDir = myTempDir; + myCDGFileName = Unzip.UnzipMP3GFiles(tbFileName.Text, myTempDir); + goto PairUpFiles; + } else if (Regex.IsMatch(tbFileName.Text, "\\.cdg$")) { + myCDGFileName = tbFileName.Text; + PairUpFiles: + string myMP3FileName = System.Text.RegularExpressions.Regex.Replace(myCDGFileName, "\\.cdg$", ".mp3"); + if (File.Exists(myMP3FileName)) { + mMP3FileName = myMP3FileName; + mCDGFileName = myCDGFileName; + mTempDir = ""; + } + } + */ + } + + + private void ToggleCheckBox() + { + tbBackGroundAVI.Enabled = chkBackGround.Checked; + btBackGroundBrowse.Enabled = chkBackGround.Checked; + tbBackGroundImg.Enabled = chkBackGraph.Checked; + btBrowseImg.Enabled = chkBackGraph.Checked; + } + + #endregion + + } +} diff --git a/KaraokeConverter/Form1.resx b/KaraokeConverter/Form1.resx new file mode 100644 index 0000000..fdfe6a4 --- /dev/null +++ b/KaraokeConverter/Form1.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 159, 17 + + \ No newline at end of file diff --git a/KaraokeConverter/KaraokeConverter.csproj b/KaraokeConverter/KaraokeConverter.csproj new file mode 100644 index 0000000..cd0a149 --- /dev/null +++ b/KaraokeConverter/KaraokeConverter.csproj @@ -0,0 +1,123 @@ + + + + + Debug + AnyCPU + {2821C26D-52D8-43D9-BEF4-7CE4DFA60776} + WinExe + Properties + KaraokeConverter + KaraokeConverter + v4.6 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + lib\AviFile.dll + + + False + lib\DirectShowLib-2005.dll + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + True + + + False + False + lib\Interop.DexterLib.dll + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + + + + {3203dfd2-da5b-47b3-b009-18dd9c401fc3} + CdgLib + + + + + \ No newline at end of file diff --git a/KaraokeConverter/MovieFrameExtractor.cs b/KaraokeConverter/MovieFrameExtractor.cs new file mode 100644 index 0000000..528926d --- /dev/null +++ b/KaraokeConverter/MovieFrameExtractor.cs @@ -0,0 +1,33 @@ +using System.Drawing; +using System.IO; +namespace KaraokeConverter +{ + public class MovieFrameExtractor + { + + public static Bitmap GetBitmap(double position, string movieFileName, int width, int height) + { + + DexterLib.MediaDetClass det = new DexterLib.MediaDetClass(); + det.Filename = movieFileName; + det.CurrentStream = 0; + double len = det.StreamLength; + if (position > len) + { + return null; + } + + string myTempFile = System.IO.Path.GetTempFileName(); + det.WriteBitmapBits(position, width, height, myTempFile); + Bitmap myBMP = null; + using (FileStream lStream = new FileStream(myTempFile, FileMode.Open, FileAccess.Read)) + { + myBMP = (Bitmap)Image.FromStream(lStream); + } + System.IO.File.Delete(myTempFile); + return myBMP; + + } + + } +} diff --git a/KaraokeConverter/Program.cs b/KaraokeConverter/Program.cs new file mode 100644 index 0000000..a227dba --- /dev/null +++ b/KaraokeConverter/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace KaraokeConverter +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/KaraokeConverter/Properties/AssemblyInfo.cs b/KaraokeConverter/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..af6ad95 --- /dev/null +++ b/KaraokeConverter/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("KaraokeConverter")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("KaraokeConverter")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2821c26d-52d8-43d9-bef4-7ce4dfa60776")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/KaraokeConverter/Properties/Resources.Designer.cs b/KaraokeConverter/Properties/Resources.Designer.cs new file mode 100644 index 0000000..d065a06 --- /dev/null +++ b/KaraokeConverter/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace KaraokeConverter.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("KaraokeConverter.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/KaraokeConverter/Properties/Resources.resx b/KaraokeConverter/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/KaraokeConverter/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/KaraokeConverter/Properties/Settings.Designer.cs b/KaraokeConverter/Properties/Settings.Designer.cs new file mode 100644 index 0000000..86bce9f --- /dev/null +++ b/KaraokeConverter/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace KaraokeConverter.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/KaraokeConverter/Properties/Settings.settings b/KaraokeConverter/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/KaraokeConverter/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/KaraokeConverter/Unzip.cs b/KaraokeConverter/Unzip.cs new file mode 100644 index 0000000..2507dc2 --- /dev/null +++ b/KaraokeConverter/Unzip.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KaraokeConverter +{ + + public class Unzip + { + + public static string UnzipMP3GFiles(string zipFilename, string outputPath) + { + string functionReturnValue = null; + functionReturnValue = ""; + try + { + ICSharpCode.SharpZipLib.Zip.FastZip myZip = new ICSharpCode.SharpZipLib.Zip.FastZip(); + myZip.ExtractZip(zipFilename, outputPath, ""); + DirectoryInfo myDirInfo = new DirectoryInfo(outputPath); + FileInfo[] myFileInfo = myDirInfo.GetFiles("*.cdg", SearchOption.AllDirectories); + if (myFileInfo.Length > 0) + { + functionReturnValue = myFileInfo[0].FullName; + } + } + catch (Exception ex) + { + } + return functionReturnValue; + } + + } +} diff --git a/KaraokeConverter/lib/AviFile.dll b/KaraokeConverter/lib/AviFile.dll new file mode 100644 index 0000000..0019757 Binary files /dev/null and b/KaraokeConverter/lib/AviFile.dll differ diff --git a/KaraokeConverter/lib/DirectShowLib-2005.dll b/KaraokeConverter/lib/DirectShowLib-2005.dll new file mode 100644 index 0000000..ba11a16 Binary files /dev/null and b/KaraokeConverter/lib/DirectShowLib-2005.dll differ diff --git a/KaraokeConverter/lib/Interop.DexterLib.dll b/KaraokeConverter/lib/Interop.DexterLib.dll new file mode 100644 index 0000000..b5b2c9b Binary files /dev/null and b/KaraokeConverter/lib/Interop.DexterLib.dll differ diff --git a/KaraokeConverter/lib/mencoder.exe b/KaraokeConverter/lib/mencoder.exe new file mode 100644 index 0000000..df8e2d8 Binary files /dev/null and b/KaraokeConverter/lib/mencoder.exe differ diff --git a/KaraokeConverter/packages.config b/KaraokeConverter/packages.config new file mode 100644 index 0000000..273ff53 --- /dev/null +++ b/KaraokeConverter/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/KaraokePlayer.sln b/KaraokePlayer.sln index c5cf7de..52544fa 100644 --- a/KaraokePlayer.sln +++ b/KaraokePlayer.sln @@ -5,6 +5,10 @@ VisualStudioVersion = 14.0.25008.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KaraokePlayer", "KaraokePlayer\KaraokePlayer.csproj", "{2CF318E2-04B5-40FC-9577-6DAC62B86FB2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KaraokeConverter", "KaraokeConverter\KaraokeConverter.csproj", "{2821C26D-52D8-43D9-BEF4-7CE4DFA60776}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CdgLib", "CdgLib\CdgLib.csproj", "{3203DFD2-DA5B-47B3-B009-18DD9C401FC3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +19,14 @@ Global {2CF318E2-04B5-40FC-9577-6DAC62B86FB2}.Debug|Any CPU.Build.0 = Debug|Any CPU {2CF318E2-04B5-40FC-9577-6DAC62B86FB2}.Release|Any CPU.ActiveCfg = Release|Any CPU {2CF318E2-04B5-40FC-9577-6DAC62B86FB2}.Release|Any CPU.Build.0 = Release|Any CPU + {2821C26D-52D8-43D9-BEF4-7CE4DFA60776}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2821C26D-52D8-43D9-BEF4-7CE4DFA60776}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2821C26D-52D8-43D9-BEF4-7CE4DFA60776}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2821C26D-52D8-43D9-BEF4-7CE4DFA60776}.Release|Any CPU.Build.0 = Release|Any CPU + {3203DFD2-DA5B-47B3-B009-18DD9C401FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3203DFD2-DA5B-47B3-B009-18DD9C401FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3203DFD2-DA5B-47B3-B009-18DD9C401FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3203DFD2-DA5B-47B3-B009-18DD9C401FC3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/KaraokePlayer/CDGWindow.Designer.cs b/KaraokePlayer/CDGWindow.Designer.cs new file mode 100644 index 0000000..2f3dff5 --- /dev/null +++ b/KaraokePlayer/CDGWindow.Designer.cs @@ -0,0 +1,69 @@ +namespace KaraokePlayer +{ + partial class CDGWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CDGWindow)); + this.PictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)this.PictureBox1).BeginInit(); + this.SuspendLayout(); + // + //PictureBox1 + // + this.PictureBox1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.PictureBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.PictureBox1.Location = new System.Drawing.Point(0, 0); + this.PictureBox1.Name = "PictureBox1"; + this.PictureBox1.Size = new System.Drawing.Size(300, 216); + this.PictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.PictureBox1.TabIndex = 0; + this.PictureBox1.TabStop = false; + // + //CDGWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6f, 13f); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Black; + this.ClientSize = new System.Drawing.Size(300, 216); + this.Controls.Add(this.PictureBox1); + this.KeyPreview = true; + this.Name = "CDGWindow"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Karaoke"; + this.TopMost = true; + ((System.ComponentModel.ISupportInitialize)this.PictureBox1).EndInit(); + this.ResumeLayout(false); + + } + public System.Windows.Forms.PictureBox PictureBox1; + + + #endregion + } +} \ No newline at end of file diff --git a/KaraokePlayer/CDGWindow.cs b/KaraokePlayer/CDGWindow.cs new file mode 100644 index 0000000..4e19210 --- /dev/null +++ b/KaraokePlayer/CDGWindow.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace KaraokePlayer +{ + public partial class CDGWindow : Form + { + + private void CDGWindow_DoubleClick(object sender, System.EventArgs e) + { + AutoSizeWindow(); + } + + private void PictureBox1_DoubleClick(object sender, System.EventArgs e) + { + AutoSizeWindow(); + } + + private void AutoSizeWindow() + { + if (this.WindowState == FormWindowState.Normal) + { + this.WindowState = FormWindowState.Maximized; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.TopMost = true; + this.Refresh(); + } + else { + this.WindowState = FormWindowState.Normal; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable; + this.TopMost = false; + this.Refresh(); + } + } + + private void CDGWindow_SizeChanged(object sender, System.EventArgs e) + { + if (this.WindowState == FormWindowState.Maximized) + { + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.TopMost = true; + } + else { + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable; + this.TopMost = false; + } + } + public CDGWindow() + { + SizeChanged += CDGWindow_SizeChanged; + DoubleClick += CDGWindow_DoubleClick; + InitializeComponent(); + } + + } +} diff --git a/KaraokePlayer/Form1.Designer.cs b/KaraokePlayer/Form1.Designer.cs index dd0e1d3..5605616 100644 --- a/KaraokePlayer/Form1.Designer.cs +++ b/KaraokePlayer/Form1.Designer.cs @@ -29,9 +29,203 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); + this.tbFileName = new System.Windows.Forms.TextBox(); + this.btBrowse = new System.Windows.Forms.Button(); + this.OpenFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.Timer1 = new System.Windows.Forms.Timer(this.components); + this.Panel1 = new System.Windows.Forms.Panel(); + this.Label2 = new System.Windows.Forms.Label(); + this.nudKey = new System.Windows.Forms.NumericUpDown(); + this.Label1 = new System.Windows.Forms.Label(); + this.ToolStrip1 = new System.Windows.Forms.ToolStrip(); + this.tsbPlay = new System.Windows.Forms.ToolStripButton(); + this.tsbStop = new System.Windows.Forms.ToolStripButton(); + this.tsbPause = new System.Windows.Forms.ToolStripButton(); + this.trbVolume = new System.Windows.Forms.TrackBar(); + this.Panel2 = new System.Windows.Forms.Panel(); + this.Panel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudKey)).BeginInit(); + this.ToolStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.trbVolume)).BeginInit(); + this.SuspendLayout(); + // + // tbFileName + // + this.tbFileName.Location = new System.Drawing.Point(3, 5); + this.tbFileName.Name = "tbFileName"; + this.tbFileName.ReadOnly = true; + this.tbFileName.Size = new System.Drawing.Size(309, 20); + this.tbFileName.TabIndex = 0; + // + // btBrowse + // + this.btBrowse.Location = new System.Drawing.Point(318, 6); + this.btBrowse.Name = "btBrowse"; + this.btBrowse.Size = new System.Drawing.Size(75, 23); + this.btBrowse.TabIndex = 1; + this.btBrowse.Text = "Browse..."; + this.btBrowse.UseVisualStyleBackColor = true; + this.btBrowse.Click += new System.EventHandler(this.Button1_Click); + // + // OpenFileDialog1 + // + this.OpenFileDialog1.FileName = "OpenFileDialog1"; + // + // Timer1 + // + this.Timer1.Interval = 50; + // + // Panel1 + // + this.Panel1.Controls.Add(this.Label2); + this.Panel1.Controls.Add(this.nudKey); + this.Panel1.Controls.Add(this.Label1); + this.Panel1.Controls.Add(this.ToolStrip1); + this.Panel1.Controls.Add(this.tbFileName); + this.Panel1.Controls.Add(this.btBrowse); + this.Panel1.Controls.Add(this.trbVolume); + this.Panel1.Dock = System.Windows.Forms.DockStyle.Top; + this.Panel1.Location = new System.Drawing.Point(0, 0); + this.Panel1.Name = "Panel1"; + this.Panel1.Size = new System.Drawing.Size(397, 61); + this.Panel1.TabIndex = 3; + // + // Label2 + // + this.Label2.AutoSize = true; + this.Label2.Location = new System.Drawing.Point(230, 37); + this.Label2.Name = "Label2"; + this.Label2.Size = new System.Drawing.Size(25, 13); + this.Label2.TabIndex = 9; + this.Label2.Text = "Key"; + // + // nudKey + // + this.nudKey.Location = new System.Drawing.Point(261, 35); + this.nudKey.Maximum = new decimal(new int[] { + 12, + 0, + 0, + 0}); + this.nudKey.Minimum = new decimal(new int[] { + 12, + 0, + 0, + -2147483648}); + this.nudKey.Name = "nudKey"; + this.nudKey.Size = new System.Drawing.Size(50, 20); + this.nudKey.TabIndex = 8; + this.nudKey.ValueChanged += new System.EventHandler(this.nudKey_ValueChanged); + // + // Label1 + // + this.Label1.AutoSize = true; + this.Label1.Location = new System.Drawing.Point(90, 35); + this.Label1.Name = "Label1"; + this.Label1.Size = new System.Drawing.Size(42, 13); + this.Label1.TabIndex = 7; + this.Label1.Text = "Volume"; + // + // ToolStrip1 + // + this.ToolStrip1.Dock = System.Windows.Forms.DockStyle.None; + this.ToolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.tsbPlay, + this.tsbStop, + this.tsbPause}); + this.ToolStrip1.Location = new System.Drawing.Point(3, 29); + this.ToolStrip1.Name = "ToolStrip1"; + this.ToolStrip1.Size = new System.Drawing.Size(81, 25); + this.ToolStrip1.TabIndex = 2; + this.ToolStrip1.Text = "ToolStrip1"; + // + // tsbPlay + // + this.tsbPlay.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tsbPlay.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsbPlay.Name = "tsbPlay"; + this.tsbPlay.Size = new System.Drawing.Size(23, 22); + this.tsbPlay.Text = "Play"; + this.tsbPlay.Click += new System.EventHandler(this.tsbPlay_Click); + // + // tsbStop + // + this.tsbStop.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tsbStop.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsbStop.Name = "tsbStop"; + this.tsbStop.Size = new System.Drawing.Size(23, 22); + this.tsbStop.Text = "Stop"; + this.tsbStop.Click += new System.EventHandler(this.tsbStop_Click); + // + // tsbPause + // + this.tsbPause.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tsbPause.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsbPause.Name = "tsbPause"; + this.tsbPause.Size = new System.Drawing.Size(23, 22); + this.tsbPause.Text = "Pause"; + this.tsbPause.Click += new System.EventHandler(this.tsbPause_Click); + // + // trbVolume + // + this.trbVolume.Location = new System.Drawing.Point(131, 34); + this.trbVolume.Maximum = 100; + this.trbVolume.Name = "trbVolume"; + this.trbVolume.Size = new System.Drawing.Size(101, 45); + this.trbVolume.TabIndex = 6; + this.trbVolume.TickFrequency = 5; + this.trbVolume.TickStyle = System.Windows.Forms.TickStyle.None; + this.trbVolume.Value = 100; + this.trbVolume.Scroll += new System.EventHandler(this.TrackBar1_Scroll); + // + // Panel2 + // + this.Panel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.Panel2.Location = new System.Drawing.Point(0, 61); + this.Panel2.Name = "Panel2"; + this.Panel2.Size = new System.Drawing.Size(397, 0); + this.Panel2.TabIndex = 4; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Text = "Form1"; + this.ClientSize = new System.Drawing.Size(397, 61); + this.Controls.Add(this.Panel2); + this.Controls.Add(this.Panel1); + this.Name = "Form1"; + this.Text = "MP3+CDG Player"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Form1_FormClosed); + this.Load += new System.EventHandler(this.Form1_Load); + this.Panel1.ResumeLayout(false); + this.Panel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudKey)).EndInit(); + this.ToolStrip1.ResumeLayout(false); + this.ToolStrip1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.trbVolume)).EndInit(); + this.ResumeLayout(false); + } + private System.Windows.Forms.TextBox tbFileName; + private System.Windows.Forms.Button btBrowse; + private System.Windows.Forms.OpenFileDialog OpenFileDialog1; + private System.Windows.Forms.Timer Timer1; + private System.Windows.Forms.Panel Panel1; + private System.Windows.Forms.Panel Panel2; + private System.Windows.Forms.ToolStrip ToolStrip1; + private System.Windows.Forms.ToolStripButton tsbPlay; + + private System.Windows.Forms.ToolStripButton tsbStop; + + private System.Windows.Forms.ToolStripButton tsbPause; + private System.Windows.Forms.Label Label1; + + private System.Windows.Forms.TrackBar trbVolume; + + private System.Windows.Forms.Label Label2; + + private System.Windows.Forms.NumericUpDown nudKey; + #endregion } diff --git a/KaraokePlayer/Form1.cs b/KaraokePlayer/Form1.cs index 3264230..1e9a57f 100644 --- a/KaraokePlayer/Form1.cs +++ b/KaraokePlayer/Form1.cs @@ -7,14 +7,312 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using CdgLib; +using Un4seen.Bass; +using System.Text.RegularExpressions; +using System.IO; namespace KaraokePlayer { public partial class Form1 : Form - { +{ public Form1() { InitializeComponent(); } - } + + #region "Private Declarations" + + private CDGFile mCDGFile; + private CdgFileIoStream mCDGStream; + private int mSemitones = 0; + private bool mPaused; + private long mFrameCount = 0; + private bool mStop; + private string mCDGFileName; + private string mMP3FileName; + private string mTempDir; + private int mMP3Stream; + private CDGWindow withEventsField_mCDGWindow = new CDGWindow(); + private CDGWindow mCDGWindow { + get { return withEventsField_mCDGWindow; } + set { + if (withEventsField_mCDGWindow != null) { + withEventsField_mCDGWindow.FormClosing -= mCDGWindow_FormClosing; + } + withEventsField_mCDGWindow = value; + if (withEventsField_mCDGWindow != null) { + withEventsField_mCDGWindow.FormClosing += mCDGWindow_FormClosing; + } + } + } + + private bool mBassInitalized = false; + #endregion + + #region "Control Events" + + private void Form1_Load(object sender, System.EventArgs e) + { + //Add registration key here if you have a license + //BassNet.Registration("email@domain.com", "0000000000000000") + try { + Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, this.Handle); + mBassInitalized = true; + } catch (Exception ex) { + MessageBox.Show("Unable to initialize the audio playback system."); + } + } + + private void Button1_Click(System.Object sender, System.EventArgs e) + { + BrowseCDGZip(); + } + + private void Form1_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e) + { + StopPlayback(); + } + + private void tsbPlay_Click(System.Object sender, System.EventArgs e) + { + Play(); + } + + private void tsbStop_Click(System.Object sender, System.EventArgs e) + { + try { + StopPlayback(); + } catch (Exception ex) { + //Do nothing for now + } + } + + private void tsbPause_Click(System.Object sender, System.EventArgs e) + { + Pause(); + } + + private void TrackBar1_Scroll(System.Object sender, System.EventArgs e) + { + AdjustVolume(); + } + + private void nudKey_ValueChanged(System.Object sender, System.EventArgs e) + { + AdjustPitch(); + } + + private void mCDGWindow_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e) + { + StopPlayback(); + mCDGWindow.Hide(); + e.Cancel = true; + } + + #endregion + + #region "CDG + MP3 Playback Operations" + + private void Pause() + { + mPaused = !mPaused; + if (mMP3Stream != 0) { + if (Bass.BASS_ChannelIsActive(mMP3Stream) != BASSActive.BASS_ACTIVE_PLAYING) { + Bass.BASS_ChannelPlay(mMP3Stream, false); + tsbPause.Text = "Pause"; + } else { + Bass.BASS_ChannelPause(mMP3Stream); + tsbPause.Text = "Resume"; + } + } + } + + private void PlayMP3Bass(string mp3FileName) + { + if (mBassInitalized || Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, this.Handle)) { + mMP3Stream = 0; + mMP3Stream = Bass.BASS_StreamCreateFile(mp3FileName, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN); + mMP3Stream = Un4seen.Bass.AddOn.Fx.BassFx.BASS_FX_TempoCreate(mMP3Stream, BASSFlag.BASS_FX_FREESOURCE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_SAMPLE_LOOP); + if (mMP3Stream != 0) { + AdjustPitch(); + AdjustVolume(); + ShowCDGWindow(); + Bass.BASS_ChannelPlay(mMP3Stream, false); + } else { + throw new Exception(string.Format("Stream error: {0}", Bass.BASS_ErrorGetCode())); + } + } + } + + private void StopPlaybackBass() + { + Bass.BASS_Stop(); + Bass.BASS_StreamFree(mMP3Stream); + Bass.BASS_Free(); + mMP3Stream = 0; + mBassInitalized = false; + } + + private void StopPlayback() + { + mStop = true; + HideCDGWindow(); + StopPlaybackBass(); + mCDGFile.Dispose(); + CleanUp(); + } + + private void PausePlayback() + { + Bass.BASS_Pause(); + } + + private void ResumePlayback() + { + Bass.BASS_Pause(); + } + + private void Play() + { + try { + if (mMP3Stream != 0 && Bass.BASS_ChannelIsActive(mMP3Stream) == BASSActive.BASS_ACTIVE_PLAYING) { + StopPlayback(); + } + PreProcessFiles(); + if (string.IsNullOrEmpty(mCDGFileName) | string.IsNullOrEmpty(mMP3FileName)) { + MessageBox.Show("Cannot find a CDG and MP3 file to play together."); + StopPlayback(); + return; + } + mPaused = false; + mStop = false; + mFrameCount = 0; + mCDGFile = new CDGFile(mCDGFileName); + long cdgLength = mCDGFile.getTotalDuration(); + PlayMP3Bass(mMP3FileName); + DateTime startTime = DateTime.Now; + var endTime = startTime.AddMilliseconds(mCDGFile.getTotalDuration()); + long millisecondsRemaining = cdgLength; + while (millisecondsRemaining > 0) { + if (mStop) { + break; // TODO: might not be correct. Was : Exit While + } + millisecondsRemaining = (long)endTime.Subtract(DateTime.Now).TotalMilliseconds; + long pos = cdgLength - millisecondsRemaining; + while (mPaused) { + endTime = DateTime.Now.AddMilliseconds(millisecondsRemaining); + Application.DoEvents(); + } + mCDGFile.renderAtPosition(pos); + mFrameCount += 1; + mCDGWindow.PictureBox1.Image = mCDGFile.RgbImage; + mCDGWindow.PictureBox1.BackColor = ((Bitmap)mCDGFile.RgbImage).GetPixel(1, 1); + mCDGWindow.PictureBox1.Refresh(); + + Application.DoEvents(); + } + StopPlayback(); + } catch (Exception ex) { + } + } + + private void AdjustPitch() + { + if (mMP3Stream != 0) { + Bass.BASS_ChannelSetAttribute(mMP3Stream, BASSAttribute.BASS_ATTRIB_TEMPO_PITCH, (float)nudKey.Value); + } + } + + private void AdjustVolume() + { + if (mMP3Stream != 0) { + Bass.BASS_ChannelSetAttribute(mMP3Stream, BASSAttribute.BASS_ATTRIB_VOL, trbVolume.Value == 0 ? 0 : (trbVolume.Value / 100)); + } + } + + #endregion + + #region "File Access" + + private void BrowseCDGZip() + { + OpenFileDialog1.Filter = "CDG or Zip Files (*.zip, *.cdg)|*.zip;*.cdg"; + OpenFileDialog1.ShowDialog(); + tbFileName.Text = OpenFileDialog1.FileName; + } + + private void PreProcessFiles() + { + + string myCDGFileName = ""; + if (Regex.IsMatch(tbFileName.Text, "\\.zip$")) { + string myTempDir = Path.GetTempPath() + Path.GetRandomFileName(); + Directory.CreateDirectory(myTempDir); + mTempDir = myTempDir; + myCDGFileName = Unzip.UnzipMP3GFiles(tbFileName.Text, myTempDir); + + } else if (Regex.IsMatch(tbFileName.Text, "\\.cdg$")) { + myCDGFileName = tbFileName.Text; + PairUpFiles: + string myMP3FileName = System.Text.RegularExpressions.Regex.Replace(myCDGFileName, "\\.cdg$", ".mp3"); + if (File.Exists(myMP3FileName)) { + mMP3FileName = myMP3FileName; + mCDGFileName = myCDGFileName; + mTempDir = ""; + } + } + + } + + private void CleanUp() + { + if (!string.IsNullOrEmpty(mTempDir)) { + try { + Directory.Delete(mTempDir, true); + } catch (Exception ex) { + } + } + mTempDir = ""; + } + + #endregion + + #region "CDG Graphics Window" + + private void ShowCDGWindow() + { + mCDGWindow.Show(); + } + + private void HideCDGWindow() + { + mCDGWindow.PictureBox1.Image = null; + mCDGWindow.Hide(); + } + + #endregion + + + + + + + + + + + + + + + + + + + + + + + } } diff --git a/KaraokePlayer/Form1.resx b/KaraokePlayer/Form1.resx new file mode 100644 index 0000000..c8cba2e --- /dev/null +++ b/KaraokePlayer/Form1.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 159, 17 + + + 248, 17 + + \ No newline at end of file diff --git a/KaraokePlayer/KaraokePlayer.csproj b/KaraokePlayer/KaraokePlayer.csproj index 7f0af26..35af766 100644 --- a/KaraokePlayer/KaraokePlayer.csproj +++ b/KaraokePlayer/KaraokePlayer.csproj @@ -33,6 +33,13 @@ 4 + + lib\Bass.Net.dll + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + True + @@ -46,6 +53,12 @@ + + Form + + + CDGWindow.cs + Form @@ -54,6 +67,10 @@ + + + Form1.cs + ResXFileCodeGenerator Resources.Designer.cs @@ -63,6 +80,7 @@ True Resources.resx + SettingsSingleFileGenerator Settings.Designer.cs @@ -76,7 +94,22 @@ + + + + + + + + {3203dfd2-da5b-47b3-b009-18dd9c401fc3} + CdgLib + + + + copy "$(ProjectDir)lib\bass.dll" "$(TargetDir)" +copy "$(ProjectDir)lib\bass_fx.dll" "$(TargetDir)" +