mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
CD parity information database
This commit is contained in:
@@ -41,6 +41,8 @@ using System.Runtime.InteropServices;
|
||||
using CUETools.Codecs;
|
||||
using CUETools.CDImage;
|
||||
using CUETools.AccurateRip;
|
||||
//using CUETools.CDRepair;
|
||||
using CUETools.CTDB;
|
||||
using CUETools.Ripper;
|
||||
using CUETools.Compression;
|
||||
using MusicBrainz;
|
||||
@@ -928,6 +930,8 @@ namespace CUETools.Processor
|
||||
public int maxAlbumArtSize;
|
||||
public string arLogFilenameFormat, alArtFilenameFormat;
|
||||
public CUEStyle gapsHandling;
|
||||
public bool separateDecodingThread;
|
||||
public bool useSystemProxySettings;
|
||||
|
||||
public bool CopyAlbumArt { get { return copyAlbumArt; } set { copyAlbumArt = value; } }
|
||||
public bool FlaCudaThreads { get { return flaCudaThreads; } set { flaCudaThreads = value; } }
|
||||
@@ -1004,6 +1008,9 @@ namespace CUETools.Processor
|
||||
arLogFilenameFormat = "%filename%.accurip";
|
||||
alArtFilenameFormat = "folder.jpg";
|
||||
|
||||
separateDecodingThread = true;
|
||||
useSystemProxySettings = true;
|
||||
|
||||
gapsHandling = CUEStyle.GapsAppended;
|
||||
|
||||
language = Thread.CurrentThread.CurrentUICulture.Name;
|
||||
@@ -1090,6 +1097,29 @@ if (tracksMatch * 100 < processor.Config.encodeWhenPercent * processor.TrackCoun
|
||||
processor.Action = CUEAction.Encode;
|
||||
return processor.Go();
|
||||
"));
|
||||
scripts.Add("repair", new CUEToolsScript("repair", true,
|
||||
new CUEAction[] { CUEAction.Encode },
|
||||
@"
|
||||
processor.UseCUEToolsDB();
|
||||
processor.Action = CUEAction.Verify;
|
||||
if (processor.CTDB.DBStatus != null)
|
||||
return CTDB.DBStatus;
|
||||
processor.Go();
|
||||
processor.CTDB.DoVerify();
|
||||
if (!processor.CTDB.Verify.HasErrors)
|
||||
return ""nothing to fix"";
|
||||
if (!processor.CTDB.Verify.CanRecover)
|
||||
return ""cannot fix"";
|
||||
processor._useCUEToolsDBFix = true;
|
||||
processor.Action = CUEAction.Encode;
|
||||
return processor.Go();
|
||||
"));
|
||||
scripts.Add("submit", new CUEToolsScript("submit", true,
|
||||
new CUEAction[] { CUEAction.Verify },
|
||||
@"
|
||||
string status = processor.Go();
|
||||
"));
|
||||
|
||||
defaultVerifyScript = "default";
|
||||
defaultEncodeScript = "default";
|
||||
}
|
||||
@@ -1145,6 +1175,9 @@ return processor.Go();
|
||||
sw.Save("CheckForUpdates", checkForUpdates);
|
||||
sw.Save("Language", language);
|
||||
|
||||
sw.Save("SeparateDecodingThread", separateDecodingThread);
|
||||
sw.Save("UseSystemProxySettings", useSystemProxySettings);
|
||||
|
||||
sw.Save("WriteBasicTagsFromCUEData", writeBasicTagsFromCUEData);
|
||||
sw.Save("CopyBasicTags", copyBasicTags);
|
||||
sw.Save("CopyUnknownTags", copyUnknownTags);
|
||||
@@ -1289,6 +1322,9 @@ return processor.Go();
|
||||
arLogFilenameFormat = sr.Load("ArLogFilenameFormat") ?? arLogFilenameFormat;
|
||||
alArtFilenameFormat = sr.Load("AlArtFilenameFormat") ?? alArtFilenameFormat;
|
||||
|
||||
separateDecodingThread = sr.LoadBoolean("SeparateDecodingThread") ?? separateDecodingThread;
|
||||
useSystemProxySettings = sr.LoadBoolean("UseSystemProxySettings") ?? useSystemProxySettings;
|
||||
|
||||
int totalEncoders = sr.LoadInt32("ExternalEncoders", 0, null) ?? 0;
|
||||
for (int nEncoders = 0; nEncoders < totalEncoders; nEncoders++)
|
||||
{
|
||||
@@ -1477,6 +1513,7 @@ return processor.Go();
|
||||
_useFreeDb = sr.LoadBoolean("FreedbLookup") ?? _useFreeDb;
|
||||
_useMusicBrainz = sr.LoadBoolean("MusicBrainzLookup") ?? _useMusicBrainz;
|
||||
_useAccurateRip = sr.LoadBoolean("AccurateRipLookup") ?? _useAccurateRip;
|
||||
_useCUEToolsDB = sr.LoadBoolean("CUEToolsDBLookup") ?? _useCUEToolsDB;
|
||||
_outputAudioType = (AudioEncoderType?)sr.LoadInt32("OutputAudioType", null, null) ?? _outputAudioType;
|
||||
_outputAudioFormat = sr.Load("OutputAudioFmt") ?? _outputAudioFormat;
|
||||
_action = (CUEAction?)sr.LoadInt32("AccurateRipMode", (int)CUEAction.Encode, (int)CUEAction.CorrectFilenames) ?? _action;
|
||||
@@ -1493,6 +1530,7 @@ return processor.Go();
|
||||
sw.Save("FreedbLookup", _useFreeDb);
|
||||
sw.Save("MusicBrainzLookup", _useMusicBrainz);
|
||||
sw.Save("AccurateRipLookup", _useAccurateRip);
|
||||
sw.Save("CUEToolsDBLookup", _useCUEToolsDB);
|
||||
sw.Save("OutputAudioType", (int)_outputAudioType);
|
||||
sw.Save("OutputAudioFmt", _outputAudioFormat);
|
||||
sw.Save("AccurateRipMode", (int)_action);
|
||||
@@ -1508,7 +1546,7 @@ return processor.Go();
|
||||
public CUEAction _action = CUEAction.Encode;
|
||||
public CUEStyle _CUEStyle = CUEStyle.SingleFileWithCUE;
|
||||
public int _writeOffset = 0;
|
||||
public bool _useFreeDb = true, _useMusicBrainz = true, _useAccurateRip = true;
|
||||
public bool _useFreeDb = true, _useMusicBrainz = true, _useAccurateRip = true, _useCUEToolsDB = true;
|
||||
|
||||
public string _name;
|
||||
}
|
||||
@@ -1533,9 +1571,9 @@ return processor.Go();
|
||||
{
|
||||
public string path;
|
||||
public string contents;
|
||||
public bool isEAC;
|
||||
public object data;
|
||||
|
||||
public CUEToolsSourceFile(string _path, StreamReader reader)
|
||||
public CUEToolsSourceFile(string _path, TextReader reader)
|
||||
{
|
||||
path = _path;
|
||||
contents = reader.ReadToEnd();
|
||||
@@ -1556,6 +1594,10 @@ return processor.Go();
|
||||
private int _writeOffset;
|
||||
private CUEAction _action;
|
||||
private bool _useAccurateRip = false;
|
||||
private bool _useCUEToolsDB = false;
|
||||
private bool _useCUEToolsDBFix = false;
|
||||
private bool _useCUEToolsDBSibmit = false;
|
||||
private bool _processed = false;
|
||||
private uint? _minDataTrackLength;
|
||||
private string _accurateRipId;
|
||||
private string _eacLog;
|
||||
@@ -1581,10 +1623,12 @@ return processor.Go();
|
||||
private string _archivePassword;
|
||||
private CUEToolsProgressEventArgs _progress;
|
||||
private AccurateRipVerify _arVerify;
|
||||
private CUEToolsDB _CUEToolsDB;
|
||||
private CDImageLayout _toc;
|
||||
private string _arLogFileName, _alArtFileName;
|
||||
private TagLib.IPicture[] _albumArt;
|
||||
private int _padding = 8192;
|
||||
private IWebProxy proxy;
|
||||
|
||||
public event EventHandler<CompressionPasswordRequiredEventArgs> PasswordRequired;
|
||||
public event EventHandler<CUEToolsProgressEventArgs> CUEToolsProgress;
|
||||
@@ -1614,6 +1658,7 @@ return processor.Go();
|
||||
_isArchive = false;
|
||||
_isCD = false;
|
||||
_albumArt = null;
|
||||
proxy = _config.useSystemProxySettings ? WebRequest.GetSystemWebProxy() : null;
|
||||
}
|
||||
|
||||
public void OpenCD(ICDRipper ripper)
|
||||
@@ -1625,7 +1670,9 @@ return processor.Go();
|
||||
_trackFilenames.Add(string.Format("{0:00}.wav", iTrack + 1));
|
||||
_tracks.Add(new TrackInfo());
|
||||
}
|
||||
_arVerify = new AccurateRipVerify(_toc);
|
||||
_arVerify = new AccurateRipVerify(_toc, proxy);
|
||||
_CUEToolsDB = new CUEToolsDB(_toc, proxy);
|
||||
_CUEToolsDB.UploadHelper.onProgress += new EventHandler<Krystalware.UploadHelper.UploadProgressEventArgs>(UploadProgress);
|
||||
_isCD = true;
|
||||
SourceInfo cdInfo;
|
||||
cdInfo.Path = _ripper.ARName;
|
||||
@@ -1653,6 +1700,14 @@ return processor.Go();
|
||||
}
|
||||
}
|
||||
|
||||
public CUEToolsDB CTDB
|
||||
{
|
||||
get
|
||||
{
|
||||
return _CUEToolsDB;
|
||||
}
|
||||
}
|
||||
|
||||
public ICDRipper CDRipper
|
||||
{
|
||||
get
|
||||
@@ -2533,7 +2588,9 @@ return processor.Go();
|
||||
}
|
||||
}
|
||||
|
||||
_arVerify = new AccurateRipVerify(_toc);
|
||||
_arVerify = new AccurateRipVerify(_toc, proxy);
|
||||
_CUEToolsDB = new CUEToolsDB(_toc, proxy);
|
||||
_CUEToolsDB.UploadHelper.onProgress += new EventHandler<Krystalware.UploadHelper.UploadProgressEventArgs>(UploadProgress);
|
||||
|
||||
if (_eacLog != null)
|
||||
{
|
||||
@@ -2578,6 +2635,16 @@ return processor.Go();
|
||||
_padding += _eacLog.Length;
|
||||
}
|
||||
|
||||
public void UseCUEToolsDB()
|
||||
{
|
||||
ShowProgress((string)"Contacting CUETools database...", 0, 0, null, null);
|
||||
|
||||
_CUEToolsDB.ContactDB(_accurateRipId ?? AccurateRipVerify.CalculateAccurateRipId(_toc));
|
||||
|
||||
ShowProgress("", 0.0, 0.0, null, null);
|
||||
_useCUEToolsDB = true;
|
||||
}
|
||||
|
||||
public void UseAccurateRip()
|
||||
{
|
||||
ShowProgress((string)"Contacting AccurateRip database...", 0, 0, null, null);
|
||||
@@ -2685,6 +2752,18 @@ return processor.Go();
|
||||
this.CUEToolsProgress(this, _progress);
|
||||
}
|
||||
|
||||
private void UploadProgress(object sender, Krystalware.UploadHelper.UploadProgressEventArgs e)
|
||||
{
|
||||
CheckStop();
|
||||
if (this.CUEToolsProgress == null)
|
||||
return;
|
||||
_progress.percentDisk = 1.0;
|
||||
_progress.percentTrck = e.percent;
|
||||
_progress.offset = 0;
|
||||
_progress.status = e.uri;
|
||||
this.CUEToolsProgress(this, _progress);
|
||||
}
|
||||
|
||||
private void CDReadProgress(object sender, ReadProgressArgs e)
|
||||
{
|
||||
CheckStop();
|
||||
@@ -3016,7 +3095,8 @@ return processor.Go();
|
||||
if (Path.GetExtension(path) == ".dummy" || Path.GetExtension(path) == ".bin")
|
||||
{
|
||||
fileInfo = null;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
TagLib.UserDefined.AdditionalFileTypes.Config = _config;
|
||||
TagLib.File.IFileAbstraction file = _isArchive
|
||||
@@ -3026,15 +3106,18 @@ return processor.Go();
|
||||
}
|
||||
|
||||
IAudioSource audioSource = AudioReadWrite.GetAudioSource(path, _isArchive ? OpenArchive(path, true) : null, _config);
|
||||
if (!audioSource.PCM.IsRedBook ||
|
||||
audioSource.Length <= 0 ||
|
||||
audioSource.Length >= Int32.MaxValue)
|
||||
try
|
||||
{
|
||||
if (!audioSource.PCM.IsRedBook ||
|
||||
audioSource.Length <= 0 ||
|
||||
audioSource.Length >= Int32.MaxValue)
|
||||
throw new Exception("Audio format is invalid.");
|
||||
return (int)audioSource.Length;
|
||||
}
|
||||
finally
|
||||
{
|
||||
audioSource.Close();
|
||||
throw new Exception("Audio format is invalid.");
|
||||
}
|
||||
audioSource.Close();
|
||||
return (int)audioSource.Length;
|
||||
}
|
||||
|
||||
public static void WriteText(string path, string text, Encoding encoding)
|
||||
@@ -3122,6 +3205,48 @@ return processor.Go();
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine(" Pre-gap length 0:{0}.{1:00}", CDImageLayout.TimeToString("{0:00}:{1:00}", _toc[track + _toc.FirstAudio].Pregap + (track + _toc.FirstAudio == 1 ? 150U : 0U)), (_toc[track + _toc.FirstAudio].Pregap % 75) * 100 / 75);
|
||||
}
|
||||
|
||||
int errCount = 0;
|
||||
uint tr_start = _toc[track + _toc.FirstAudio].Start;
|
||||
uint tr_end = (_toc[track + _toc.FirstAudio].Length + 74) / 75;
|
||||
for (uint iSecond = 0; iSecond < tr_end; iSecond ++)
|
||||
{
|
||||
uint sec_start = tr_start + iSecond * 75;
|
||||
uint sec_end = Math.Min(sec_start + 74, _toc[track + _toc.FirstAudio].End);
|
||||
bool fError = false;
|
||||
for (uint iSector = sec_start; iSector <= sec_end; iSector++)
|
||||
if (_ripper.Errors[(int)iSector])
|
||||
fError = true;
|
||||
if (fError)
|
||||
{
|
||||
uint end = iSecond;
|
||||
for (uint jSecond = iSecond + 1; jSecond < tr_end; jSecond++)
|
||||
{
|
||||
uint jsec_start = tr_start + jSecond * 75;
|
||||
uint jsec_end = Math.Min(jsec_start + 74, _toc[track + _toc.FirstAudio].End);
|
||||
bool jfError = false;
|
||||
for (uint jSector = jsec_start; jSector <= jsec_end; jSector++)
|
||||
if (_ripper.Errors[(int)jSector])
|
||||
jfError = true;
|
||||
if (jfError)
|
||||
end = jSecond;
|
||||
}
|
||||
if (errCount == 0)
|
||||
logWriter.WriteLine();
|
||||
if (errCount++ > 20)
|
||||
break;
|
||||
//"Suspicious position 0:02:20"
|
||||
//" Suspicious position 0:02:23 - 0:02:24"
|
||||
string s1 = CDImageLayout.TimeToString("0:{0:00}:{1:00}", iSecond * 75);
|
||||
string s2 = CDImageLayout.TimeToString("0:{0:00}:{1:00}", end * 75);
|
||||
if (iSecond == end)
|
||||
logWriter.WriteLine(" Suspicious position {0}", s1);
|
||||
else
|
||||
logWriter.WriteLine(" Suspicious position {0} - {1}", s1, s2);
|
||||
iSecond = end;
|
||||
}
|
||||
}
|
||||
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine(" Peak level {0:F1} %", (Tracks[track].PeakLevel * 1000 / 32768) * 0.1);
|
||||
logWriter.WriteLine(" Track quality 100.0 %");
|
||||
@@ -3391,6 +3516,8 @@ return processor.Go();
|
||||
|
||||
public void GenerateAccurateRipLog(TextWriter sw)
|
||||
{
|
||||
if (!_processed)
|
||||
throw new Exception("not processed");
|
||||
sw.WriteLine("[Verification date: {0}]", DateTime.Now);
|
||||
sw.WriteLine("[Disc ID: {0}]", _accurateRipId ?? AccurateRipVerify.CalculateAccurateRipId(_toc));
|
||||
if (PreGapLength != 0)
|
||||
@@ -3414,6 +3541,10 @@ return processor.Go();
|
||||
sw.WriteLine("HDCD: {0:f}", hdcdDecoder);
|
||||
if (0 != _writeOffset)
|
||||
sw.WriteLine("Offset applied: {0}", _writeOffset);
|
||||
if (_useCUEToolsDBFix)// && _CUEToolsDB.SelectedEntry != null)
|
||||
sw.WriteLine("CUETools DB: corrected {0} errors.", _CUEToolsDB.SelectedEntry.repair.CorrectableErrors);
|
||||
else if (_useCUEToolsDB)
|
||||
sw.WriteLine("CUETools DB: {0}.", _CUEToolsDB.Status);
|
||||
_arVerify.GenerateFullLog(sw, _config.arLogVerbose);
|
||||
}
|
||||
|
||||
@@ -3550,6 +3681,14 @@ return processor.Go();
|
||||
if (_audioEncoderType != AudioEncoderType.NoAudio || _action == CUEAction.Verify)
|
||||
WriteAudioFilesPass(OutputDir, OutputStyle, destLengths, htoaToFile, _action == CUEAction.Verify);
|
||||
|
||||
if (_useCUEToolsDB && CTDB.AccResult == HttpStatusCode.OK)
|
||||
{
|
||||
if (!_useCUEToolsDBFix)
|
||||
CTDB.DoVerify();
|
||||
}
|
||||
|
||||
_processed = true;
|
||||
|
||||
CreateRipperLOG();
|
||||
|
||||
if (_action == CUEAction.Encode)
|
||||
@@ -4097,6 +4236,8 @@ return processor.Go();
|
||||
|
||||
if (_useAccurateRip)
|
||||
_arVerify.Init();
|
||||
if (_useCUEToolsDB && !_useCUEToolsDBFix)
|
||||
_CUEToolsDB.Init(_useCUEToolsDBSibmit);
|
||||
|
||||
ShowProgress(String.Format("{2} track {0:00} ({1:00}%)...", 0, 0, noOutput ? "Verifying" : "Writing"), 0, 0.0, null, null);
|
||||
|
||||
@@ -4179,6 +4320,13 @@ return processor.Go();
|
||||
}
|
||||
|
||||
copyCount = audioSource.Read(sampleBuffer, copyCount);
|
||||
if (_useCUEToolsDB)
|
||||
{
|
||||
if (_useCUEToolsDBFix)
|
||||
_CUEToolsDB.SelectedEntry.repair.Write(sampleBuffer);
|
||||
else
|
||||
_CUEToolsDB.Verify.Write(sampleBuffer);
|
||||
}
|
||||
if (!discardOutput)
|
||||
{
|
||||
if (!_config.detectHDCD || !_config.decodeHDCD)
|
||||
@@ -4208,7 +4356,7 @@ return processor.Go();
|
||||
{
|
||||
_arVerify.Write(sampleBuffer);
|
||||
if (iTrack > 0 || iIndex > 0)
|
||||
Tracks[iTrack + (iIndex == 0 ? -1 : 0)].MeasurePeakLevel(sampleBuffer.Samples, copyCount);
|
||||
Tracks[iTrack + (iIndex == 0 ? -1 : 0)].MeasurePeakLevel(sampleBuffer, copyCount);
|
||||
}
|
||||
|
||||
currentOffset += copyCount;
|
||||
@@ -4550,7 +4698,9 @@ return processor.Go();
|
||||
if (sourceInfo.Offset != 0)
|
||||
audioSource.Position = sourceInfo.Offset;
|
||||
|
||||
//audioSource = new AudioPipe(audioSource, 0x10000);
|
||||
//if (!(audioSource is AudioPipe) && !(audioSource is UserDefinedReader) && _config.separateDecodingThread)
|
||||
if (!(audioSource is AudioPipe) && _config.separateDecodingThread)
|
||||
audioSource = new AudioPipe(audioSource, 0x10000);
|
||||
|
||||
return audioSource;
|
||||
}
|
||||
@@ -4902,6 +5052,14 @@ return processor.Go();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Processed
|
||||
{
|
||||
get
|
||||
{
|
||||
return _processed;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCD
|
||||
{
|
||||
get
|
||||
@@ -5039,6 +5197,56 @@ return processor.Go();
|
||||
return Go();
|
||||
case "only if found":
|
||||
return ArVerify.AccResult != HttpStatusCode.OK ? WriteReport() : Go();
|
||||
case "submit":
|
||||
{
|
||||
if (!_useCUEToolsDB)
|
||||
return "CUETools DB not enabled";
|
||||
if (ArVerify.ARStatus != null)
|
||||
return "AccurateRip: " + ArVerify.ARStatus;
|
||||
if (ArVerify.WorstTotal() < 3)
|
||||
return "AccurateRip: confidence too low";
|
||||
//if (CTDB.AccResult == HttpStatusCode.OK)
|
||||
//return "CUEToolsDB: disc already present in database";
|
||||
if (CTDB.AccResult != HttpStatusCode.NotFound && CTDB.AccResult != HttpStatusCode.OK)
|
||||
return "CUEToolsDB: " + CTDB.DBStatus;
|
||||
_useCUEToolsDBSibmit = true;
|
||||
string status = Go();
|
||||
if (CTDB.AccResult == HttpStatusCode.OK)
|
||||
foreach (DBEntry entry in CTDB.Entries)
|
||||
if (!entry.hasErrors)
|
||||
return "CUEToolsDB: " + CTDB.Status;
|
||||
if (ArVerify.WorstConfidence() < 3)
|
||||
return status + ": confidence too low";
|
||||
return CTDB.Submit((int)ArVerify.WorstConfidence(), (int)ArVerify.WorstTotal());
|
||||
}
|
||||
case "repair":
|
||||
{
|
||||
UseCUEToolsDB();
|
||||
Action = CUEAction.Verify;
|
||||
if (CTDB.DBStatus != null)
|
||||
return CTDB.DBStatus;
|
||||
bool useAR = _useAccurateRip;
|
||||
_useAccurateRip = false;
|
||||
Go();
|
||||
_useAccurateRip = useAR;
|
||||
List<CUEToolsSourceFile> choices = new List<CUEToolsSourceFile>();
|
||||
foreach (DBEntry entry in CTDB.Entries)
|
||||
if (!entry.hasErrors || entry.canRecover)
|
||||
{
|
||||
CUEToolsSourceFile choice = new CUEToolsSourceFile(entry.Status, new StringReader(""));
|
||||
choice.data = entry;
|
||||
choices.Add(choice);
|
||||
}
|
||||
CUEToolsSourceFile selectedEntry = ChooseFile(choices, null, true);
|
||||
if (selectedEntry == null)
|
||||
return CTDB.Status;
|
||||
CTDB.SelectedEntry = (DBEntry)selectedEntry.data;
|
||||
if (!CTDB.SelectedEntry.hasErrors)
|
||||
return CTDB.Status;
|
||||
_useCUEToolsDBFix = true;
|
||||
Action = CUEAction.Encode;
|
||||
return Go();
|
||||
}
|
||||
case "fix offset":
|
||||
{
|
||||
if (ArVerify.AccResult != HttpStatusCode.OK)
|
||||
@@ -5276,12 +5484,15 @@ return processor.Go();
|
||||
_peakLevel = 0;
|
||||
}
|
||||
|
||||
public unsafe void MeasurePeakLevel(int[,] samplesBuffer, int sampleCount)
|
||||
public unsafe void MeasurePeakLevel(AudioBuffer buff, int sampleCount)
|
||||
{
|
||||
fixed (int* s = samplesBuffer)
|
||||
if (!buff.PCM.IsRedBook)
|
||||
throw new Exception();
|
||||
fixed (byte* bb = buff.Bytes)
|
||||
{
|
||||
short* ss = (short*)bb;
|
||||
for (int i = 0; i < sampleCount * 2; i++)
|
||||
_peakLevel = Math.Max(_peakLevel, Math.Abs(s[i]));
|
||||
_peakLevel = Math.Max(_peakLevel, Math.Abs((int)ss[i]));
|
||||
}
|
||||
//for (uint i = 0; i < sampleCount; i++)
|
||||
// for (uint j = 0; j < 2; j++)
|
||||
|
||||
Reference in New Issue
Block a user