mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-10-27 22:42:38 +01:00
Merge pull request #1274 from jdpurcell/audiovis1
Some more wave visualizer enhancements
This commit is contained in:
commit
2af71513f3
@ -249,9 +249,8 @@ namespace Nikse.SubtitleEdit.Core
|
||||
/// <summary>
|
||||
/// Generate peaks (samples with some interval) for an uncompressed wave file
|
||||
/// </summary>
|
||||
/// <param name="peaksPerSecond">Sampeles per second / sample rate</param>
|
||||
/// <param name="delayInMilliseconds">Delay in milliseconds (normally zero)</param>
|
||||
public void GeneratePeakSamples(int peaksPerSecond, int delayInMilliseconds)
|
||||
public void GeneratePeakSamples(int delayInMilliseconds)
|
||||
{
|
||||
if (Header.BytesPerSample == 4)
|
||||
{
|
||||
@ -259,7 +258,11 @@ namespace Nikse.SubtitleEdit.Core
|
||||
throw new Exception("32-bit samples are unsupported.");
|
||||
}
|
||||
|
||||
PeaksPerSecond = peaksPerSecond;
|
||||
PeaksPerSecond = Math.Min(Configuration.Settings.VideoControls.WaveformMinimumSampleRate, Header.SampleRate);
|
||||
|
||||
// Ensure that peaks per second is a multiple of the sample rate
|
||||
while (Header.SampleRate % PeaksPerSecond != 0)
|
||||
PeaksPerSecond++;
|
||||
|
||||
ReadSampleDataValueDelegate readSampleDataValue = GetSampleDataReader();
|
||||
DataMinValue = int.MaxValue;
|
||||
@ -268,7 +271,7 @@ namespace Nikse.SubtitleEdit.Core
|
||||
|
||||
if (delayInMilliseconds > 0)
|
||||
{
|
||||
for (int i = 0; i < peaksPerSecond * delayInMilliseconds / 1000; i++)
|
||||
for (int i = 0; i < PeaksPerSecond * delayInMilliseconds / 1000; i++)
|
||||
PeakSamples.Add(0);
|
||||
}
|
||||
|
||||
@ -276,9 +279,9 @@ namespace Nikse.SubtitleEdit.Core
|
||||
_data = new byte[Header.BytesPerSecond];
|
||||
_stream.Position = Header.DataStartPosition;
|
||||
int bytesRead = _stream.Read(_data, 0, _data.Length);
|
||||
while (bytesRead == Header.BytesPerSecond)
|
||||
while (bytesRead > 0)
|
||||
{
|
||||
for (int i = 0; i < Header.BytesPerSecond; i += bytesInterval)
|
||||
for (int i = 0; i < bytesRead; i += bytesInterval)
|
||||
{
|
||||
int index = i;
|
||||
int value = 0;
|
||||
@ -286,7 +289,7 @@ namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
value += readSampleDataValue.Invoke(ref index);
|
||||
}
|
||||
value = value / Header.NumberOfChannels;
|
||||
value /= Header.NumberOfChannels;
|
||||
if (value < DataMinValue)
|
||||
DataMinValue = value;
|
||||
if (value > DataMaxValue)
|
||||
@ -318,14 +321,14 @@ namespace Nikse.SubtitleEdit.Core
|
||||
DataMaxValue = int.MinValue;
|
||||
AllSamples = new List<int>();
|
||||
int index = 0;
|
||||
while (index + Header.NumberOfChannels < Header.DataChunkSize)
|
||||
while (index < Header.DataChunkSize)
|
||||
{
|
||||
int value = 0;
|
||||
for (int channelNumber = 0; channelNumber < Header.NumberOfChannels; channelNumber++)
|
||||
{
|
||||
value += readSampleDataValue.Invoke(ref index);
|
||||
}
|
||||
value = value / Header.NumberOfChannels;
|
||||
value /= Header.NumberOfChannels;
|
||||
if (value < DataMinValue)
|
||||
DataMinValue = value;
|
||||
if (value > DataMaxValue)
|
||||
@ -508,6 +511,8 @@ namespace Nikse.SubtitleEdit.Core
|
||||
int chunkCount = (int)Math.Ceiling((double)(fileSampleCount + delaySampleCount) / chunkSampleCount);
|
||||
double[] chunkSamples = new double[chunkSampleCount];
|
||||
|
||||
Directory.CreateDirectory(spectrogramDirectory);
|
||||
|
||||
_data = new byte[chunkSampleCount * Header.BlockAlign];
|
||||
_stream.Seek(Header.DataStartPosition, SeekOrigin.Begin);
|
||||
|
||||
@ -604,8 +609,8 @@ namespace Nikse.SubtitleEdit.Core
|
||||
|
||||
private class SpectrogramDrawer
|
||||
{
|
||||
private const double raisedCosineWindowScale = 0.5;
|
||||
private const int magnitudeIndexRange = 256;
|
||||
private const double RaisedCosineWindowScale = 0.5;
|
||||
private const int MagnitudeIndexRange = 256;
|
||||
|
||||
private readonly int _nfft;
|
||||
private readonly MagnitudeToIndexMapper _mapper;
|
||||
@ -619,7 +624,7 @@ namespace Nikse.SubtitleEdit.Core
|
||||
public SpectrogramDrawer(int nfft)
|
||||
{
|
||||
_nfft = nfft;
|
||||
_mapper = new MagnitudeToIndexMapper(100.0, magnitudeIndexRange - 1);
|
||||
_mapper = new MagnitudeToIndexMapper(100.0, MagnitudeIndexRange - 1);
|
||||
_fft = new RealFFT(nfft);
|
||||
_palette = GeneratePalette();
|
||||
_segment = new double[nfft];
|
||||
@ -627,7 +632,7 @@ namespace Nikse.SubtitleEdit.Core
|
||||
_magnitude1 = new double[nfft / 2];
|
||||
_magnitude2 = new double[nfft / 2];
|
||||
|
||||
double scaleCorrection = 1.0 / (raisedCosineWindowScale * _fft.ForwardScaleFactor);
|
||||
double scaleCorrection = 1.0 / (RaisedCosineWindowScale * _fft.ForwardScaleFactor);
|
||||
for (int i = 0; i < _window.Length; i++)
|
||||
{
|
||||
_window[i] *= scaleCorrection;
|
||||
@ -694,18 +699,18 @@ namespace Nikse.SubtitleEdit.Core
|
||||
|
||||
private static FastBitmap.PixelData[] GeneratePalette()
|
||||
{
|
||||
var palette = new FastBitmap.PixelData[magnitudeIndexRange];
|
||||
var palette = new FastBitmap.PixelData[MagnitudeIndexRange];
|
||||
if (Configuration.Settings.VideoControls.SpectrogramAppearance == "Classic")
|
||||
{
|
||||
for (int colorIndex = 0; colorIndex < magnitudeIndexRange; colorIndex++)
|
||||
palette[colorIndex] = new FastBitmap.PixelData(PaletteValue(colorIndex, magnitudeIndexRange));
|
||||
for (int colorIndex = 0; colorIndex < MagnitudeIndexRange; colorIndex++)
|
||||
palette[colorIndex] = new FastBitmap.PixelData(PaletteValue(colorIndex, MagnitudeIndexRange));
|
||||
}
|
||||
else
|
||||
{
|
||||
var list = SmoothColors(0, 0, 0, Configuration.Settings.VideoControls.WaveformColor.R,
|
||||
Configuration.Settings.VideoControls.WaveformColor.G,
|
||||
Configuration.Settings.VideoControls.WaveformColor.B, magnitudeIndexRange);
|
||||
for (int i = 0; i < magnitudeIndexRange; i++)
|
||||
Configuration.Settings.VideoControls.WaveformColor.B, MagnitudeIndexRange);
|
||||
for (int i = 0; i < MagnitudeIndexRange; i++)
|
||||
palette[i] = new FastBitmap.PixelData(list[i]);
|
||||
}
|
||||
return palette;
|
||||
|
@ -133,8 +133,8 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
}
|
||||
|
||||
public const double VerticalZoomMinimum = 1.0;
|
||||
public const double VerticalZoomMaximum = 20.0;
|
||||
private double _verticalZoomFactor = 1.0; // 1.0=no zoom
|
||||
public const double VerticalZoomMaximum = 40.0;
|
||||
private double _verticalZoomFactor = 2.0; // 1.0=no zoom
|
||||
public double VerticalZoomFactor
|
||||
{
|
||||
get
|
||||
@ -404,7 +404,7 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
private static int CalculateHeight(double value, int imageHeight, int maxHeight)
|
||||
{
|
||||
double percentage = value / maxHeight;
|
||||
var result = (int)Math.Round((percentage * imageHeight) + (imageHeight / 2.0));
|
||||
var result = (int)Math.Round((percentage / 2.0 + 0.5) * imageHeight);
|
||||
return imageHeight - result;
|
||||
}
|
||||
|
||||
@ -1690,18 +1690,28 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
|
||||
public void ZoomIn()
|
||||
{
|
||||
ZoomFactor = ZoomFactor + 0.1;
|
||||
ZoomFactor += 0.1;
|
||||
if (OnZoomedChanged != null)
|
||||
OnZoomedChanged.Invoke(this, null);
|
||||
}
|
||||
|
||||
public void ZoomOut()
|
||||
{
|
||||
ZoomFactor = ZoomFactor - 0.1;
|
||||
ZoomFactor -= 0.1;
|
||||
if (OnZoomedChanged != null)
|
||||
OnZoomedChanged.Invoke(this, null);
|
||||
}
|
||||
|
||||
private void VerticalZoomIn()
|
||||
{
|
||||
VerticalZoomFactor *= 1.1;
|
||||
}
|
||||
|
||||
private void VerticalZoomOut()
|
||||
{
|
||||
VerticalZoomFactor /= 1.1;
|
||||
}
|
||||
|
||||
private void WaveformMouseWheel(object sender, MouseEventArgs e)
|
||||
{
|
||||
// The scroll wheel could work in theory without the waveform loaded (it would be
|
||||
@ -1720,6 +1730,16 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
return;
|
||||
}
|
||||
|
||||
if (ModifierKeys == (Keys.Control | Keys.Shift))
|
||||
{
|
||||
if (e.Delta > 0)
|
||||
VerticalZoomIn();
|
||||
else
|
||||
VerticalZoomOut();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int delta = e.Delta;
|
||||
if (!MouseWheelScrollUpIsForward)
|
||||
delta = delta * -1;
|
||||
|
4
src/Forms/AddWaveForm.Designer.cs
generated
4
src/Forms/AddWaveForm.Designer.cs
generated
@ -138,8 +138,8 @@
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Generate waveform data";
|
||||
this.Shown += new System.EventHandler(this.AddWareForm_Shown);
|
||||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.AddWareForm_KeyDown);
|
||||
this.Shown += new System.EventHandler(this.AddWaveform_Shown);
|
||||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.AddWaveform_KeyDown);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
|
@ -234,28 +234,24 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
labelProgress.Text = Configuration.Settings.Language.AddWaveform.GeneratingPeakFile;
|
||||
Refresh();
|
||||
|
||||
var waveFile = new WavePeakGenerator(targetFile);
|
||||
|
||||
int sampleRate = Configuration.Settings.VideoControls.WaveformMinimumSampleRate; // Normally 128
|
||||
while (waveFile.Header.SampleRate % sampleRate != 0 && sampleRate < 5000)
|
||||
sampleRate++; // old sample-rate / new sample-rate must have rest = 0
|
||||
|
||||
waveFile.GeneratePeakSamples(sampleRate, delayInMilliseconds); // samples per second - SampleRate
|
||||
|
||||
if (Configuration.Settings.VideoControls.GenerateSpectrogram)
|
||||
using (var waveFile = new WavePeakGenerator(targetFile))
|
||||
{
|
||||
labelProgress.Text = Configuration.Settings.Language.AddWaveform.GeneratingSpectrogram;
|
||||
Refresh();
|
||||
Directory.CreateDirectory(_spectrogramDirectory);
|
||||
SpectrogramBitmaps = waveFile.GenerateFourierData(256, _spectrogramDirectory, delayInMilliseconds); // image height = nfft / 2
|
||||
waveFile.GeneratePeakSamples(delayInMilliseconds);
|
||||
|
||||
if (Configuration.Settings.VideoControls.GenerateSpectrogram)
|
||||
{
|
||||
labelProgress.Text = Configuration.Settings.Language.AddWaveform.GeneratingSpectrogram;
|
||||
Refresh();
|
||||
SpectrogramBitmaps = waveFile.GenerateFourierData(256, _spectrogramDirectory, delayInMilliseconds); // image height = nfft / 2
|
||||
}
|
||||
|
||||
WavePeak = waveFile;
|
||||
}
|
||||
WavePeak = waveFile;
|
||||
waveFile.Close();
|
||||
|
||||
labelPleaseWait.Visible = false;
|
||||
}
|
||||
|
||||
private void AddWareForm_Shown(object sender, EventArgs e)
|
||||
private void AddWaveform_Shown(object sender, EventArgs e)
|
||||
{
|
||||
Refresh();
|
||||
var audioTrackNames = new List<string>();
|
||||
@ -367,7 +363,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private void AddWareForm_KeyDown(object sender, KeyEventArgs e)
|
||||
private void AddWaveform_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape)
|
||||
DialogResult = DialogResult.Cancel;
|
||||
|
@ -211,7 +211,12 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
while (index < listViewInputFiles.Items.Count && _abort == false)
|
||||
{
|
||||
var item = listViewInputFiles.Items[index];
|
||||
item.SubItems[3].Text = Configuration.Settings.Language.AddWaveformBatch.ExtractingAudio;
|
||||
Action<string> updateStatus = status =>
|
||||
{
|
||||
item.SubItems[3].Text = status;
|
||||
Refresh();
|
||||
};
|
||||
updateStatus(Configuration.Settings.Language.AddWaveformBatch.ExtractingAudio);
|
||||
string fileName = item.Text;
|
||||
try
|
||||
{
|
||||
@ -285,7 +290,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
}
|
||||
}
|
||||
|
||||
item.SubItems[3].Text = Configuration.Settings.Language.AddWaveformBatch.Calculating;
|
||||
updateStatus(Configuration.Settings.Language.AddWaveformBatch.Calculating);
|
||||
MakeWaveformAndSpectrogram(fileName, targetFile, _delayInMilliseconds);
|
||||
|
||||
// cleanup
|
||||
@ -300,13 +305,13 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
IncrementAndShowProgress();
|
||||
|
||||
item.SubItems[3].Text = Configuration.Settings.Language.AddWaveformBatch.Done;
|
||||
updateStatus(Configuration.Settings.Language.AddWaveformBatch.Done);
|
||||
}
|
||||
catch
|
||||
{
|
||||
IncrementAndShowProgress();
|
||||
|
||||
item.SubItems[3].Text = Configuration.Settings.Language.AddWaveformBatch.Error;
|
||||
updateStatus(Configuration.Settings.Language.AddWaveformBatch.Error);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
@ -322,21 +327,16 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
private void MakeWaveformAndSpectrogram(string videoFileName, string targetFile, int delayInMilliseconds)
|
||||
{
|
||||
var waveFile = new WavePeakGenerator(targetFile);
|
||||
using (var waveFile = new WavePeakGenerator(targetFile))
|
||||
{
|
||||
waveFile.GeneratePeakSamples(delayInMilliseconds);
|
||||
waveFile.WritePeakSamples(Main.GetPeakWaveFileName(videoFileName));
|
||||
|
||||
int sampleRate = Configuration.Settings.VideoControls.WaveformMinimumSampleRate; // Normally 128
|
||||
while (waveFile.Header.SampleRate % sampleRate != 0 && sampleRate < 5000)
|
||||
sampleRate++; // old sample-rate / new sample-rate must have rest = 0
|
||||
|
||||
waveFile.GeneratePeakSamples(sampleRate, delayInMilliseconds); // samples per second - SampleRate
|
||||
|
||||
//if (Configuration.Settings.VideoControls.GenerateSpectrogram)
|
||||
//{
|
||||
// //Directory.CreateDirectory(_spectrogramDirectory);
|
||||
// //SpectrogramBitmaps = waveFile.GenerateFourierData(256, _spectrogramDirectory, delayInMilliseconds); // image height = nfft / 2
|
||||
//}
|
||||
waveFile.WritePeakSamples(Main.GetPeakWaveFileName(videoFileName));
|
||||
waveFile.Close();
|
||||
if (Configuration.Settings.VideoControls.GenerateSpectrogram)
|
||||
{
|
||||
waveFile.GenerateFourierData(256, Main.GetSpectrogramFolder(videoFileName), delayInMilliseconds); // image height = nfft / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void IncrementAndShowProgress()
|
||||
|
2
src/Forms/Main.Designer.cs
generated
2
src/Forms/Main.Designer.cs
generated
@ -4450,7 +4450,7 @@
|
||||
this.audioVisualizer.TextBold = true;
|
||||
this.audioVisualizer.TextColor = System.Drawing.Color.Gray;
|
||||
this.audioVisualizer.TextSize = 9F;
|
||||
this.audioVisualizer.VerticalZoomFactor = 1D;
|
||||
this.audioVisualizer.VerticalZoomFactor = 2D;
|
||||
this.audioVisualizer.WaveformNotLoadedText = "Click to add waveform";
|
||||
this.audioVisualizer.WavePeaks = null;
|
||||
this.audioVisualizer.ZoomFactor = 1D;
|
||||
|
@ -14803,7 +14803,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
return wavePeakName;
|
||||
}
|
||||
|
||||
private static string GetSpectrogramFolder(string videoFileName)
|
||||
public static string GetSpectrogramFolder(string videoFileName)
|
||||
{
|
||||
var dir = Configuration.SpectrogramsFolder.TrimEnd(Path.DirectorySeparatorChar);
|
||||
if (!Directory.Exists(dir))
|
||||
|
Loading…
Reference in New Issue
Block a user