update cdg code

This commit is contained in:
Brett Sanderson 2016-03-02 01:24:39 -05:00
parent dd5a85b220
commit 4ee3899264
6 changed files with 99 additions and 222 deletions

View File

@ -2,46 +2,16 @@
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Schema; using System.Xml.Schema;
namespace CdgLib namespace CdgLib
{ {
public class CdgFile : IDisposable public class CdgFile : FileStream
{ {
private const int ColourTableSize = 16; private const int ColourTableSize = 16;
// To detect redundant calls
private bool _disposedValue;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// IDisposable
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_mPStream.Close();
}
_mPStream = null;
_mPSurface = null;
}
_disposedValue = true;
}
#region "Constants"
//CDG Command Code
private const byte CdgCommand = 0x9; private const byte CdgCommand = 0x9;
//CDG Instruction Codes
private const int CdgInstMemoryPreset = 1; private const int CdgInstMemoryPreset = 1;
private const int CdgInstBorderPreset = 2; private const int CdgInstBorderPreset = 2;
private const int CdgInstTileBlock = 6; private const int CdgInstTileBlock = 6;
@ -50,51 +20,27 @@ namespace CdgLib
private const int CdgInstDefTranspCol = 28; private const int CdgInstDefTranspCol = 28;
private const int CdgInstLoadColTblLo = 30; private const int CdgInstLoadColTblLo = 30;
private const int CdgInstLoadColTblHigh = 31; private const int CdgInstLoadColTblHigh = 31;
private const int CdgInstTileBlockXor = 38; private const int CdgInstTileBlockXor = 38;
//Bitmask for all CDG fields
private const byte CdgMask = 0x3f; private const byte CdgMask = 0x3f;
private const int CdgPacketSize = 24; private const int CdgPacketSize = 24;
private const int TileHeight = 12; private const int TileHeight = 12;
private const int TileWidth = 6; private const int TileWidth = 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 CdgFullWidth = 300; public const int CdgFullWidth = 300;
public const int CdgFullHeight = 216; public const int CdgFullHeight = 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 CdgDisplayWidth = 294; private const int CdgDisplayWidth = 294;
private const int CdgDisplayHeight = 204; private const int CdgDisplayHeight = 204;
#endregion
#region "Private Declarations"
private readonly byte[,] _mPixelColours = new byte[CdgFullHeight, CdgFullWidth]; private readonly byte[,] _mPixelColours = new byte[CdgFullHeight, CdgFullWidth];
private readonly int[] _mColourTable = new int[ColourTableSize]; private readonly int[] _mColourTable = new int[ColourTableSize];
private int _mPresetColourIndex; private int _mPresetColourIndex;
private int _mBorderColourIndex; private int _mBorderColourIndex;
private int _mTransparentColour; private int _mTransparentColour;
private int _mHOffset; private int _mHOffset;
private int _mVOffset; private int _mVOffset;
private CdgFileIoStream _mPStream; private CdgFileIoStream _mPStream;
private Surface _mPSurface; private Surface _mPSurface;
private long _mPositionMs; private long _previousPosition;
private long _mDuration; private long _mDuration;
private Bitmap _mImage; private Bitmap _mImage;
#endregion
#region "Properties"
public bool Transparent => true; public bool Transparent => true;
public Image RgbImage public Image RgbImage
@ -129,10 +75,6 @@ namespace CdgLib
} }
} }
#endregion
#region "Public Methods"
//Png Export //Png Export
public void SavePng(string filename) public void SavePng(string filename)
{ {
@ -140,170 +82,107 @@ namespace CdgLib
} }
//New //New
public CdgFile(string cdgFileName) public CdgFile(string path, FileMode mode, FileAccess fileAccess) : base(path, mode, fileAccess)
{ {
_mPStream = new CdgFileIoStream();
_mPStream.Open(cdgFileName);
_mPSurface = new Surface(); _mPSurface = new Surface();
if (_mPStream != null && _mPSurface != null)
{
Reset();
_mDuration = _mPStream.Getsize()/CdgPacketSize*1000/300;
}
} }
private long Duration => Length / CdgPacketSize * 1000 / 300;
public long GetTotalDuration() public long GetTotalDuration()
{ {
return _mDuration; return _mDuration;
} }
public bool RenderAtPosition(long ms) public async Task<bool> RenderAtPosition(long position)
{ {
var pack = new CdgPacket(); long numberOfSubCodePackets = 0;
long numPacks = 0;
var res = true; if (position < _previousPosition)
if (_mPStream == null)
{ {
return false; Position = 0;
} _previousPosition = 0;
if (ms < _mPositionMs)
{
if (_mPStream.Seek(0, SeekOrigin.Begin) < 0)
return false;
_mPositionMs = 0;
} }
//duration of one packet is 1/300 seconds (4 packets per sector, 75 sectors per second) //duration of one packet is 1/300 seconds (4 packets per sector, 75 sectors per second)
//300p/s == 300p/1000ms == 3p/10
numPacks = ms - _mPositionMs; var timeToRender = position - _previousPosition;
numPacks /= 10; _previousPosition += timeToRender;
numberOfSubCodePackets=(timeToRender*3)/10;
_mPositionMs += numPacks*10;
numPacks *= 3;
//TODO: double check logic due to inline while loop fucntionality //TODO: double check logic due to inline while loop fucntionality
//AndAlso m_pSurface.rgbData Is Nothing //AndAlso m_pSurface.rgbData Is Nothing
while (numPacks > 0) while (numberOfSubCodePackets > 0)
{ {
res = ReadPacket(ref pack); var pack = await ReadSubCode();
ProcessPacket(ref pack); ProcessPacket(pack);
numPacks -= 1; numberOfSubCodePackets -= 1;
} }
Render(); Render();
return res; return true;
} }
#endregion private async Task<SubCodePacket> ReadSubCode()
#region "Private Methods"
private void Reset()
{ {
Array.Clear(_mPixelColours, 0, _mPixelColours.Length); var subCode = new SubCodePacket();
Array.Clear(_mColourTable, 0, _mColourTable.Length); byte[] buffer = new byte[24];
var bytesRead = await ReadAsync(buffer, 0, 24);
_mPresetColourIndex = 0; if (bytesRead < 24)
_mBorderColourIndex = 0;
_mTransparentColour = 0;
_mHOffset = 0;
_mVOffset = 0;
_mDuration = 0;
_mPositionMs = 0;
//clear surface
if (_mPSurface.RgbData != null)
{ {
Array.Clear(_mPSurface.RgbData, 0, _mPSurface.RgbData.Length); return new SubCodePacket();
}
}
private bool ReadPacket(ref CdgPacket pack)
{
if (_mPStream == null || _mPStream.Eof())
{
return false;
} }
var read = 0; Array.Copy(buffer, 0, subCode.Command, 0, 1);
Array.Copy(buffer, 1, subCode.Instruction, 0, 1);
Array.Copy(buffer, 2, subCode.ParityQ, 0, 2);
Array.Copy(buffer, 4, subCode.Data, 0, 16);
Array.Copy(buffer, 20, subCode.ParityP, 0, 4);
read += _mPStream.Read(ref pack.Command, 1); return subCode;
read += _mPStream.Read(ref pack.Instruction, 1);
read += _mPStream.Read(ref pack.ParityQ, 2);
read += _mPStream.Read(ref pack.Data, 16);
read += _mPStream.Read(ref pack.ParityP, 4);
return read == 24;
} }
private void ProcessPacket(ref CdgPacket pack) private void ProcessPacket(SubCodePacket subCodePacketPacket)
{ {
var instCode = 0; if ((subCodePacketPacket.Command[0] & CdgMask) != CdgCommand) return;
var instructionCode = subCodePacketPacket.Instruction[0] & CdgMask;
if ((pack.Command[0] & CdgMask) == CdgCommand) switch (instructionCode)
{ {
instCode = pack.Instruction[0] & CdgMask; case CdgInstMemoryPreset:
switch (instCode) MemoryPreset(ref subCodePacketPacket);
{ break;
case CdgInstMemoryPreset: case CdgInstBorderPreset:
MemoryPreset(ref pack); BorderPreset(ref subCodePacketPacket);
break;
case CdgInstTileBlock:
break; TileBlock(ref subCodePacketPacket, false);
case CdgInstBorderPreset: break;
BorderPreset(ref pack); case CdgInstScrollPreset:
Scroll(ref subCodePacketPacket, false);
break;
break; case CdgInstScrollCopy:
case CdgInstTileBlock: Scroll(ref subCodePacketPacket, true);
TileBlock(ref pack, false); break;
case CdgInstDefTranspCol:
DefineTransparentColour(ref subCodePacketPacket);
break; break;
case CdgInstScrollPreset: case CdgInstLoadColTblLo:
Scroll(ref pack, false); LoadColorTable(ref subCodePacketPacket, 0);
break;
case CdgInstLoadColTblHigh:
break; LoadColorTable(ref subCodePacketPacket, 1);
case CdgInstScrollCopy: break;
Scroll(ref pack, true); case CdgInstTileBlockXor:
TileBlock(ref subCodePacketPacket, true);
break;
break;
case CdgInstDefTranspCol:
DefineTransparentColour(ref pack);
break;
case CdgInstLoadColTblLo:
LoadColorTable(ref pack, 0);
break;
case CdgInstLoadColTblHigh:
LoadColorTable(ref pack, 1);
break;
case CdgInstTileBlockXor:
TileBlock(ref pack, true);
break;
default:
//Ignore the unsupported commands
break;
}
} }
} }
private void MemoryPreset(ref CdgPacket pack) private void MemoryPreset(ref SubCodePacket pack)
{ {
var colour = 0; var colour = 0;
var ri = 0; var ri = 0;
@ -336,14 +215,14 @@ namespace CdgLib
{ {
for (ci = 0; ci <= CdgFullWidth - 1; ci++) for (ci = 0; ci <= CdgFullWidth - 1; ci++)
{ {
_mPixelColours[ri, ci] = (byte) colour; _mPixelColours[ri, ci] = (byte)colour;
} }
} }
} }
} }
private void BorderPreset(ref CdgPacket pack) private void BorderPreset(ref SubCodePacket pack)
{ {
var colour = 0; var colour = 0;
var ri = 0; var ri = 0;
@ -360,12 +239,12 @@ namespace CdgLib
{ {
for (ci = 0; ci <= 5; ci++) for (ci = 0; ci <= 5; ci++)
{ {
_mPixelColours[ri, ci] = (byte) colour; _mPixelColours[ri, ci] = (byte)colour;
} }
for (ci = CdgFullWidth - 6; ci <= CdgFullWidth - 1; ci++) for (ci = CdgFullWidth - 6; ci <= CdgFullWidth - 1; ci++)
{ {
_mPixelColours[ri, ci] = (byte) colour; _mPixelColours[ri, ci] = (byte)colour;
} }
} }
@ -373,18 +252,18 @@ namespace CdgLib
{ {
for (ri = 0; ri <= 11; ri++) for (ri = 0; ri <= 11; ri++)
{ {
_mPixelColours[ri, ci] = (byte) colour; _mPixelColours[ri, ci] = (byte)colour;
} }
for (ri = CdgFullHeight - 12; ri <= CdgFullHeight - 1; ri++) for (ri = CdgFullHeight - 12; ri <= CdgFullHeight - 1; ri++)
{ {
_mPixelColours[ri, ci] = (byte) colour; _mPixelColours[ri, ci] = (byte)colour;
} }
} }
} }
private void LoadColorTable(ref CdgPacket pack, int table) private void LoadColorTable(ref SubCodePacket pack, int table)
{ {
for (var i = 0; i <= 7; i++) for (var i = 0; i <= 7; i++)
{ {
@ -392,8 +271,8 @@ namespace CdgLib
//7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 //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 //X X r r r r g g X X g g b b b b
var byte0 = pack.Data[2*i]; var byte0 = pack.Data[2 * i];
var byte1 = pack.Data[2*i + 1]; var byte1 = pack.Data[2 * i + 1];
var red = (byte0 & 0x3f) >> 2; var red = (byte0 & 0x3f) >> 2;
var green = ((byte0 & 0x3) << 2) | ((byte1 & 0x3f) >> 4); var green = ((byte0 & 0x3) << 2) | ((byte1 & 0x3f) >> 4);
var blue = byte1 & 0xf; var blue = byte1 & 0xf;
@ -404,13 +283,13 @@ namespace CdgLib
if (_mPSurface != null) if (_mPSurface != null)
{ {
_mColourTable[i + table*8] = _mPSurface.MapRgbColour(red, green, blue); _mColourTable[i + table * 8] = _mPSurface.MapRgbColour(red, green, blue);
} }
} }
} }
private void TileBlock(ref CdgPacket pack, bool bXor) private void TileBlock(ref SubCodePacket pack, bool bXor)
{ {
var colour0 = 0; var colour0 = 0;
var colour1 = 0; var colour1 = 0;
@ -424,8 +303,8 @@ namespace CdgLib
colour0 = pack.Data[0] & 0xf; colour0 = pack.Data[0] & 0xf;
colour1 = pack.Data[1] & 0xf; colour1 = pack.Data[1] & 0xf;
rowIndex = (pack.Data[2] & 0x1f)*12; rowIndex = (pack.Data[2] & 0x1f) * 12;
columnIndex = (pack.Data[3] & 0x3f)*6; columnIndex = (pack.Data[3] & 0x3f) * 6;
if (rowIndex > CdgFullHeight - TileHeight) if (rowIndex > CdgFullHeight - TileHeight)
return; return;
@ -475,18 +354,18 @@ namespace CdgLib
//Set the pixel with the new colour. We set both the surfarray //Set the pixel with the new colour. We set both the surfarray
//containing actual RGB values, as well as our array containing //containing actual RGB values, as well as our array containing
//the colour indexes into our colour table. //the colour indexes into our colour table.
_mPixelColours[rowIndex + i, columnIndex + j] = (byte) newCol; _mPixelColours[rowIndex + i, columnIndex + j] = (byte)newCol;
} }
} }
} }
private void DefineTransparentColour(ref CdgPacket pack) private void DefineTransparentColour(ref SubCodePacket pack)
{ {
_mTransparentColour = pack.Data[0] & 0xf; _mTransparentColour = pack.Data[0] & 0xf;
} }
private void Scroll(ref CdgPacket pack, bool copy) private void Scroll(ref SubCodePacket pack, bool copy)
{ {
var colour = 0; var colour = 0;
var hScroll = 0; var hScroll = 0;
@ -555,7 +434,7 @@ namespace CdgLib
{ {
for (ci = 0; ci <= CdgFullWidth - 1; ci++) for (ci = 0; ci <= CdgFullWidth - 1; ci++)
{ {
temp[(ri + vInc)%CdgFullHeight, (ci + hInc)%CdgFullWidth] = _mPixelColours[ri, ci]; temp[(ri + vInc) % CdgFullHeight, (ci + hInc) % CdgFullWidth] = _mPixelColours[ri, ci];
} }
} }
@ -572,7 +451,7 @@ namespace CdgLib
{ {
for (ri = 0; ri <= vScrollPixels - 1; ri++) for (ri = 0; ri <= vScrollPixels - 1; ri++)
{ {
temp[ri, ci] = (byte) colour; temp[ri, ci] = (byte)colour;
} }
} }
} }
@ -582,7 +461,7 @@ namespace CdgLib
{ {
for (ri = CdgFullHeight + vScrollPixels; ri <= CdgFullHeight - 1; ri++) for (ri = CdgFullHeight + vScrollPixels; ri <= CdgFullHeight - 1; ri++)
{ {
temp[ri, ci] = (byte) colour; temp[ri, ci] = (byte)colour;
} }
} }
} }
@ -594,7 +473,7 @@ namespace CdgLib
{ {
for (ri = 0; ri <= CdgFullHeight - 1; ri++) for (ri = 0; ri <= CdgFullHeight - 1; ri++)
{ {
temp[ri, ci] = (byte) colour; temp[ri, ci] = (byte)colour;
} }
} }
} }
@ -604,7 +483,7 @@ namespace CdgLib
{ {
for (ri = 0; ri <= CdgFullHeight - 1; ri++) for (ri = 0; ri <= CdgFullHeight - 1; ri++)
{ {
temp[ri, ci] = (byte) colour; temp[ri, ci] = (byte)colour;
} }
} }
} }
@ -621,7 +500,6 @@ namespace CdgLib
} }
} }
private void Render() private void Render()
{ {
if (_mPSurface == null) if (_mPSurface == null)
@ -643,6 +521,5 @@ namespace CdgLib
} }
} }
#endregion
} }
} }

View File

@ -75,7 +75,7 @@ namespace CdgLib
public bool Open(string filename) public bool Open(string filename)
{ {
Close(); Close();
_cdgFile = new FileStream(filename, FileMode.Open); _cdgFile = new FileStream(filename, FileMode.Open, FileAccess.Read);
return _cdgFile != null; return _cdgFile != null;
} }

View File

@ -44,7 +44,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="CdgFile.cs" /> <Compile Include="CdgFile.cs" />
<Compile Include="CdgFileIoStream.cs" /> <Compile Include="CdgFileIoStream.cs" />
<Compile Include="CdgPacket.cs" /> <Compile Include="SubCodePacket.cs" />
<Compile Include="GraphicUtil.cs" /> <Compile Include="GraphicUtil.cs" />
<Compile Include="Surface.cs" /> <Compile Include="Surface.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -1,6 +1,6 @@
namespace CdgLib namespace CdgLib
{ {
public class CdgPacket public class SubCodePacket
{ {
public byte[] Command = new byte[1]; public byte[] Command = new byte[1];
public byte[] Data = new byte[16]; public byte[] Data = new byte[16];

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
using AviFile; using AviFile;
@ -18,7 +19,7 @@ namespace KaraokeConverter
Bitmap backgroundBmp = null; Bitmap backgroundBmp = null;
Bitmap mergedBMP = null; Bitmap mergedBMP = null;
VideoStream aviStream = null; VideoStream aviStream = null;
var myCDGFile = new CdgFile(cdgFileName); var myCDGFile = new CdgFile(cdgFileName, FileMode.Open, FileAccess.Read);
myCDGFile.RenderAtPosition(0); myCDGFile.RenderAtPosition(0);
var bitmap__1 = (Bitmap) myCDGFile.RgbImage; var bitmap__1 = (Bitmap) myCDGFile.RgbImage;
if (!string.IsNullOrEmpty(backgroundFileName)) if (!string.IsNullOrEmpty(backgroundFileName))

View File

@ -22,20 +22,19 @@ namespace KaraokePlayer
public KaraokeVideoPlayer() public KaraokeVideoPlayer()
{ {
InitializeComponent(); InitializeComponent();
_lyricTimer.Interval = 30; _lyricTimer.Interval = 50;
_lyricTimer.Elapsed += LyricTimerOnElapsed; _lyricTimer.Elapsed += LyricTimerOnElapsed;
} }
private async void LyricTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs) private async void LyricTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{ {
System.Diagnostics.Debug.Print(DateTime.Now.Millisecond.ToString()); System.Diagnostics.Debug.Print((DateTime.Now - _startTime).TotalMilliseconds.ToString());
if (vlcPlayer.IsPlaying) if (vlcPlayer.IsPlaying)
{ {
await Task.Run(() =>
{ await _cdgFile.RenderAtPosition(
_cdgFile.RenderAtPosition(
(long)(DateTime.Now - _startTime).TotalMilliseconds); (long)(DateTime.Now - _startTime).TotalMilliseconds);
});
Invoke((MethodInvoker)(() => Invoke((MethodInvoker)(() =>
@ -53,7 +52,7 @@ namespace KaraokePlayer
public void Play(Uri file) public void Play(Uri file)
{ {
vlcPlayer.SetMedia(file); vlcPlayer.SetMedia(file);
_cdgFile = new CdgFile(Path.ChangeExtension(file.LocalPath, "cdg")); _cdgFile = new CdgFile(Path.ChangeExtension(file.LocalPath, "cdg"), FileMode.Open, FileAccess.Read);
vlcPlayer.Play(); vlcPlayer.Play();
} }