2006-01-16 22:02:54 +01:00
// Copyright (c) 2005, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
# include <wx/tglbtn.h>
2006-08-27 21:54:51 +02:00
# include <math.h>
# include <vector>
2006-01-16 22:02:54 +01:00
# include "audio_display.h"
2006-07-04 08:13:54 +02:00
# include "audio_provider_stream.h"
2006-01-16 22:02:54 +01:00
# include "main.h"
# include "ass_dialogue.h"
# include "subs_grid.h"
# include "ass_file.h"
# include "subs_edit_box.h"
# include "options.h"
# include "audio_karaoke.h"
# include "audio_box.h"
# include "fft.h"
# include "video_display.h"
# include "vfr.h"
# include "colorspace.h"
# include "hotkeys.h"
# include "utils.h"
///////////////
// Constructor
AudioDisplay : : AudioDisplay ( wxWindow * parent , VideoDisplay * display )
: wxWindow ( parent , - 1 , wxDefaultPosition , wxSize ( 200 , Options . AsInt ( _T ( " Audio Display Height " ) ) ) , wxSUNKEN_BORDER | wxWANTS_CHARS , _T ( " Audio Display " ) )
{
// Set variables
2006-07-02 01:31:15 +02:00
video = NULL ;
2006-01-16 22:02:54 +01:00
origImage = NULL ;
spectrumDisplay = NULL ;
ScrollBar = NULL ;
dialogue = NULL ;
karaoke = NULL ;
peak = NULL ;
min = NULL ;
hasSel = false ;
diagUpdated = false ;
NeedCommit = false ;
loaded = false ;
2006-07-01 08:32:11 +02:00
temporary = false ;
2006-01-16 22:02:54 +01:00
blockUpdate = false ;
dontReadTimes = false ;
2006-02-21 22:33:15 +01:00
holding = false ;
2006-03-07 01:12:50 +01:00
draggingScale = false ;
2006-07-04 08:13:54 +02:00
scrubbing = false ;
2006-01-16 22:02:54 +01:00
Position = 0 ;
PositionSample = 0 ;
oldCurPos = 0 ;
scale = 1.0f ;
provider = NULL ;
2006-02-25 08:41:18 +01:00
player = NULL ;
2006-01-16 22:02:54 +01:00
video = display ;
hold = 0 ;
hasFocus = ( wxWindow : : FindFocus ( ) = = this ) ;
// Init
UpdateTimer . SetOwner ( this , Audio_Update_Timer ) ;
2006-03-06 01:45:24 +01:00
GetClientSize ( & w , & h ) ;
h - = 20 ;
2006-01-16 22:02:54 +01:00
SetSamplesPercent ( 50 , false ) ;
// Set cursor
//wxCursor cursor(wxCURSOR_BLANK);
//SetCursor(cursor);
//wxLog::SetActiveTarget(new wxLogWindow(NULL,_T("Log"),true,false));
}
//////////////
// Destructor
AudioDisplay : : ~ AudioDisplay ( ) {
2006-02-25 08:41:18 +01:00
if ( player ) player - > CloseStream ( ) ;
delete provider ;
delete player ;
delete origImage ;
delete spectrumDisplay ;
delete peak ;
delete min ;
2006-01-16 22:02:54 +01:00
}
/////////
// Reset
void AudioDisplay : : Reset ( ) {
hasSel = false ;
diagUpdated = false ;
NeedCommit = false ;
karaoke - > enabled = false ;
karaoke - > syllables . clear ( ) ;
box - > karaokeMode = false ;
box - > KaraokeButton - > SetValue ( false ) ;
dialogue = NULL ;
}
////////////////
// Update image
void AudioDisplay : : UpdateImage ( bool weak ) {
2006-07-04 23:59:30 +02:00
// Loaded?
if ( ! loaded | | ! provider ) return ;
2006-01-16 22:02:54 +01:00
// Prepare bitmap
2006-03-06 01:45:24 +01:00
int displayH = h + 20 ;
2006-01-16 22:02:54 +01:00
if ( origImage ) {
2006-03-06 01:45:24 +01:00
if ( origImage - > GetWidth ( ) ! = w | | origImage - > GetHeight ( ) ! = displayH ) {
2006-01-16 22:02:54 +01:00
delete origImage ;
origImage = NULL ;
}
}
bool draw_boundary_lines = Options . AsBool ( _T ( " Audio Draw Secondary Lines " ) ) ;
bool draw_selection_background = Options . AsBool ( _T ( " Audio Draw Selection Background " ) ) ;
// Invalid dimensions
2006-03-06 01:45:24 +01:00
if ( w = = 0 | | displayH = = 0 ) return ;
2006-01-16 22:02:54 +01:00
// New bitmap
2006-03-06 01:45:24 +01:00
if ( ! origImage ) origImage = new wxBitmap ( w , displayH , - 1 ) ;
2006-01-16 22:02:54 +01:00
// Is spectrum?
bool spectrum = false ;
if ( provider & & Options . AsBool ( _T ( " Audio Spectrum " ) ) ) {
spectrum = true ;
}
// Update samples
UpdateSamples ( ) ;
// Draw image to be displayed
wxMemoryDC dc ;
dc . SelectObject ( * origImage ) ;
dc . BeginDrawing ( ) ;
// Black background
dc . SetPen ( * wxTRANSPARENT_PEN ) ;
dc . SetBrush ( wxBrush ( Options . AsColour ( _T ( " Audio Background " ) ) ) ) ;
dc . DrawRectangle ( 0 , 0 , w , h ) ;
// Selection position
hasSel = false ;
hasKaraoke = karaoke - > enabled ;
selStart = 0 ;
selEnd = 0 ;
lineStart = 0 ;
lineEnd = 0 ;
selStartCap = 0 ;
selEndCap = 0 ;
if ( dialogue ) {
GetDialoguePos ( lineStart , lineEnd , false ) ;
hasSel = true ;
if ( hasKaraoke ) {
GetKaraokePos ( selStartCap , selEndCap , true ) ;
GetKaraokePos ( selStart , selEnd , false ) ;
}
else {
GetDialoguePos ( selStartCap , selEndCap , true ) ;
selStart = lineStart ;
selEnd = lineEnd ;
}
}
// Draw selection bg
if ( hasSel & & selStart < selEnd & & draw_selection_background ) {
if ( NeedCommit & & ! karaoke - > enabled ) dc . SetBrush ( wxBrush ( Options . AsColour ( _T ( " Audio Selection Background Modified " ) ) ) ) ;
else dc . SetBrush ( wxBrush ( Options . AsColour ( _T ( " Audio Selection Background " ) ) ) ) ;
dc . DrawRectangle ( selStart , 0 , selEnd - selStart , h ) ;
}
// Draw spectrum
if ( spectrum ) {
DrawSpectrum ( dc , weak ) ;
// Invert the selection, if any
if ( hasSel & & selStart < selEnd & & Options . AsBool ( _T ( " Audio Spectrum invert selection " ) ) ) {
dc . Blit ( selStart , 0 , selEnd - selStart , h , & dc , selStart , 0 , wxSRC_INVERT ) ;
}
}
// Draw seconds boundaries
if ( draw_boundary_lines ) {
__int64 start = Position * samples ;
2006-02-02 19:17:54 +01:00
int rate = provider - > GetSampleRate ( ) ;
2006-01-16 22:02:54 +01:00
int pixBounds = rate / samples ;
dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Seconds Boundaries " ) ) , 1 , wxDOT ) ) ;
if ( pixBounds > = 8 ) {
for ( int x = 0 ; x < w ; x + + ) {
if ( ( ( x * samples ) + start ) % rate < samples ) {
dc . DrawLine ( x , 0 , x , h ) ;
}
}
}
}
// Draw keyframes
2006-12-18 17:20:45 +01:00
if ( video - > KeyFramesLoaded ( ) & & draw_boundary_lines ) {
2006-12-18 05:53:40 +01:00
wxArrayInt KeyFrames = video - > GetKeyFrames ( ) ;
int nKeys = ( int ) KeyFrames . Count ( ) ;
2006-01-16 22:02:54 +01:00
dc . SetPen ( wxPen ( wxColour ( 255 , 0 , 255 ) , 1 ) ) ;
// Get min and max frames to care about
2006-02-24 17:45:10 +01:00
int minFrame = VFR_Output . GetFrameAtTime ( GetMSAtX ( 0 ) , true ) ;
int maxFrame = VFR_Output . GetFrameAtTime ( GetMSAtX ( w ) , true ) ;
2006-01-16 22:02:54 +01:00
// Scan list
for ( int i = 0 ; i < nKeys ; i + + ) {
2006-12-18 05:53:40 +01:00
int cur = KeyFrames [ i ] ;
2006-01-16 22:02:54 +01:00
if ( cur > = minFrame & & cur < = maxFrame ) {
2006-02-24 17:45:10 +01:00
int x = GetXAtMS ( VFR_Output . GetTimeAtFrame ( cur , true ) ) ;
2006-01-16 22:02:54 +01:00
dc . DrawLine ( x , 0 , x , h ) ;
}
else if ( cur > maxFrame ) break ;
}
}
// Waveform
if ( provider ) {
if ( ! spectrum ) DrawWaveform ( dc , weak ) ;
}
// Nothing
else {
dc . DrawLine ( 0 , h / 2 , w , h / 2 ) ;
}
// Draw previous line
int shadeType = Options . AsInt ( _T ( " Audio Inactive Lines Display Mode " ) ) ;
if ( shadeType = = 1 | | shadeType = = 2 ) {
dc . SetBrush ( wxBrush ( Options . AsColour ( _T ( " Audio Line boundary inactive line " ) ) ) ) ;
int selWidth = Options . AsInt ( _T ( " Audio Line boundaries Thickness " ) ) ;
AssDialogue * shade ;
int shadeX1 , shadeX2 ;
int shadeFrom , shadeTo ;
// Only previous
if ( shadeType = = 1 ) {
shadeFrom = this - > line_n - 1 ;
shadeTo = shadeFrom + 1 ;
}
// All
else {
shadeFrom = 0 ;
shadeTo = grid - > GetRows ( ) ;
}
for ( int j = shadeFrom ; j < shadeTo ; j + + ) {
if ( j = = line_n ) continue ;
shade = grid - > GetDialogue ( j ) ;
if ( shade ) {
// Get coordinates
shadeX1 = GetXAtMS ( shade - > Start . GetMS ( ) ) ;
shadeX2 = GetXAtMS ( shade - > End . GetMS ( ) ) ;
if ( shadeX2 < 0 | | shadeX1 > w ) continue ;
// Draw over waveform
if ( ! spectrum ) {
int x1 = MAX ( 0 , shadeX1 ) ;
int x2 = MIN ( w , shadeX2 ) ;
dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Waveform Inactive " ) ) ) ) ;
for ( __int64 i = x1 ; i < x2 ; i + + ) {
dc . DrawLine ( i , peak [ i ] , i , min [ i ] - 1 ) ;
}
}
// Draw boundaries
dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Line boundary inactive line " ) ) ) ) ;
dc . DrawRectangle ( shadeX1 - selWidth / 2 + 1 , 0 , selWidth , h ) ;
dc . DrawRectangle ( shadeX2 - selWidth / 2 + 1 , 0 , selWidth , h ) ;
}
}
}
if ( hasSel ) {
// Draw boundaries
int selWidth = Options . AsInt ( _T ( " Audio Line boundaries Thickness " ) ) ;
dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Line boundary start " ) ) ) ) ;
dc . SetBrush ( wxBrush ( Options . AsColour ( _T ( " Audio Line boundary start " ) ) ) ) ;
dc . DrawRectangle ( lineStart - selWidth / 2 + 1 , 0 , selWidth , h ) ;
dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Line boundary end " ) ) ) ) ;
dc . SetBrush ( wxBrush ( Options . AsColour ( _T ( " Audio Line boundary end " ) ) ) ) ;
dc . DrawRectangle ( lineEnd - selWidth / 2 + 1 , 0 , selWidth , h ) ;
// Draw karaoke
if ( hasKaraoke ) {
2006-02-20 08:12:01 +01:00
try {
// Prepare
wxPen curPen ( Options . AsColour ( _T ( " Audio Syllable boundaries " ) ) , 1 , wxDOT ) ;
dc . SetPen ( curPen ) ;
wxFont curFont ( 9 , wxFONTFAMILY_DEFAULT , wxFONTSTYLE_NORMAL , wxFONTWEIGHT_BOLD , false , _T ( " Verdana " ) , wxFONTENCODING_SYSTEM ) ;
dc . SetFont ( curFont ) ;
if ( ! spectrum ) dc . SetTextForeground ( Options . AsColour ( _T ( " Audio Syllable text " ) ) ) ;
else dc . SetTextForeground ( wxColour ( 255 , 255 , 255 ) ) ;
size_t karn = karaoke - > syllables . size ( ) ;
__int64 pos1 , pos2 ;
int len , curpos ;
wxCoord tw = 0 , th = 0 ;
KaraokeSyllable * curSyl ;
wxString temptext ;
// Draw syllables
for ( size_t i = 0 ; i < karn ; i + + ) {
2006-01-16 22:02:54 +01:00
curSyl = & karaoke - > syllables . at ( i ) ;
len = curSyl - > length * 10 ;
curpos = curSyl - > position * 10 ;
if ( len ! = - 1 ) {
pos1 = GetXAtMS ( curStartMS + curpos ) ;
pos2 = GetXAtMS ( curStartMS + len + curpos ) ;
dc . DrawLine ( pos2 , 0 , pos2 , h ) ;
temptext = curSyl - > contents ;
temptext . Trim ( true ) ;
temptext . Trim ( false ) ;
GetTextExtent ( temptext , & tw , & th , NULL , NULL , & curFont ) ;
dc . DrawText ( temptext , ( pos1 + pos2 - tw ) / 2 , h - th - 4 ) ;
}
}
2006-02-20 08:12:01 +01:00
}
catch ( . . . ) {
2006-01-16 22:02:54 +01:00
}
}
}
// Modified text
if ( NeedCommit ) {
dc . SetFont ( wxFont ( 9 , wxDEFAULT , wxFONTSTYLE_NORMAL , wxFONTWEIGHT_BOLD , false , _T ( " Verdana " ) ) ) ;
dc . SetTextForeground ( wxColour ( 255 , 0 , 0 ) ) ;
if ( selStart < = selEnd ) {
dc . DrawText ( _T ( " Modified " ) , 4 , 4 ) ;
}
else {
dc . DrawText ( _T ( " Negative time " ) , 4 , 4 ) ;
}
}
// Draw selection border
if ( hasFocus ) {
dc . SetPen ( * wxGREEN_PEN ) ;
dc . SetBrush ( * wxTRANSPARENT_BRUSH ) ;
dc . DrawRectangle ( 0 , 0 , w , h ) ;
}
2006-03-06 01:45:24 +01:00
// Draw timescale
dc . SetBrush ( wxSystemSettings : : GetColour ( wxSYS_COLOUR_BTNFACE ) ) ;
dc . SetPen ( * wxTRANSPARENT_PEN ) ;
dc . DrawRectangle ( 0 , h , w , 20 ) ;
dc . SetPen ( wxSystemSettings : : GetColour ( wxSYS_COLOUR_3DLIGHT ) ) ;
dc . DrawLine ( 0 , h , w , h ) ;
dc . SetPen ( wxSystemSettings : : GetColour ( wxSYS_COLOUR_3DHIGHLIGHT ) ) ;
dc . DrawLine ( 0 , h + 1 , w , h + 1 ) ;
dc . SetPen ( wxSystemSettings : : GetColour ( wxSYS_COLOUR_BTNTEXT ) ) ;
dc . SetTextForeground ( wxSystemSettings : : GetColour ( wxSYS_COLOUR_BTNTEXT ) ) ;
wxFont scaleFont ;
scaleFont . SetFaceName ( _T ( " Tahoma " ) ) ;
scaleFont . SetPointSize ( 8 ) ;
dc . SetFont ( scaleFont ) ;
// Timescale ticks
__int64 start = Position * samples ;
int rate = provider - > GetSampleRate ( ) ;
for ( int i = 1 ; i < 32 ; i * = 2 ) {
int pixBounds = rate / ( samples * 4 / i ) ;
if ( pixBounds > = 8 ) {
for ( int x = 0 ; x < w ; x + + ) {
__int64 pos = ( x * samples ) + start ;
// Second boundary
if ( pos % rate < samples ) {
dc . DrawLine ( x , h + 2 , x , h + 8 ) ;
// Draw text
wxCoord textW , textH ;
int hr = 0 ;
int m = 0 ;
int s = pos / rate ;
while ( s > = 3600 ) {
s - = 3600 ;
hr + + ;
}
while ( s > = 60 ) {
s - = 60 ;
m + + ;
}
wxString text ;
if ( hr ) text = wxString : : Format ( _T ( " %i:%02i:%02i " ) , hr , m , s ) ;
else if ( m ) text = wxString : : Format ( _T ( " %i:%02i " ) , m , s ) ;
else text = wxString : : Format ( _T ( " %i " ) , s ) ;
dc . GetTextExtent ( text , & textW , & textH , NULL , NULL , & scaleFont ) ;
dc . DrawText ( text , MAX ( 0 , x - textW / 2 ) + 1 , h + 8 ) ;
}
// Other
else if ( pos % ( rate / 4 * i ) < samples ) {
dc . DrawLine ( x , h + 2 , x , h + 5 ) ;
}
}
break ;
}
}
2006-01-16 22:02:54 +01:00
// Done
dc . EndDrawing ( ) ;
2006-02-02 19:24:58 +01:00
Refresh ( false ) ;
2006-01-16 22:02:54 +01:00
}
////////////
// Waveform
void AudioDisplay : : DrawWaveform ( wxDC & dc , bool weak ) {
// Prepare Waveform
if ( ! weak | | peak = = NULL | | min = = NULL ) {
if ( peak ) delete peak ;
if ( min ) delete min ;
peak = new int [ w ] ;
min = new int [ w ] ;
}
// Get waveform
if ( ! weak ) {
provider - > GetWaveForm ( min , peak , Position * samples , w , h , samples , scale ) ;
}
// Draw pre-selection
if ( ! hasSel ) selStartCap = w ;
dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Waveform " ) ) ) ) ;
for ( __int64 i = 0 ; i < selStartCap ; i + + ) {
dc . DrawLine ( i , peak [ i ] , i , min [ i ] - 1 ) ;
}
if ( hasSel ) {
// Draw selection
if ( Options . AsBool ( _T ( " Audio Draw Selection Background " ) ) ) {
if ( NeedCommit & & ! karaoke - > enabled ) dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Waveform Modified " ) ) ) ) ;
else dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Waveform Selected " ) ) ) ) ;
}
for ( __int64 i = selStartCap ; i < selEndCap ; i + + ) {
dc . DrawLine ( i , peak [ i ] , i , min [ i ] - 1 ) ;
}
// Draw post-selection
dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Waveform " ) ) ) ) ;
for ( __int64 i = selEndCap ; i < w ; i + + ) {
dc . DrawLine ( i , peak [ i ] , i , min [ i ] - 1 ) ;
}
}
}
static int spectrumColorMap [ 256 ] ;
static unsigned short spectrumColorMap16 [ 256 ] ;
static bool colorMapsGenerated = false ;
2006-08-27 21:54:51 +02:00
//////////////////////////////////////
// Spectrum analyser rendering thread
class SpectrumRendererThread : public wxThread {
public :
SpectrumRendererThread ( ) : wxThread ( wxTHREAD_JOINABLE ) {
if ( Create ( ) ! = wxTHREAD_NO_ERROR )
throw _T ( " Error creating Spectrum rendering thread. " ) ;
}
int * data ; // image data to write to (shared)
int window ; // 1 << Options.AsInt(_T("Audio Spectrum Window"))
int firstbar , lastbar ; // first and last vertical bar to draw
int w , h ; // width and height of canvas
int cutoff ; // cutoff frequency
float * base_in ; // audio sample data (shared)
int samples ; // number of samples per column
int depth ; // display bit depth
2006-11-23 22:43:45 +01:00
float scale ; // vertical scale of display, exponential, min=0, mid=1, max=8
2006-08-27 21:54:51 +02:00
protected :
wxThread : : ExitCode Entry ( ) {
// Pointers to image data
int * write_ptr = data ;
unsigned short * write_ptr16 = ( unsigned short * ) data ;
// FFT output data
2006-08-28 00:29:14 +02:00
float * out_r = new float [ window ] ; // real part
float * out_i = new float [ window ] ; // imaginary part
float * power = new float [ window ] ; // calculated signal power
2006-08-27 21:54:51 +02:00
// Prepare constants
const int halfwindow = window / 2 ;
2006-08-28 01:31:20 +02:00
//const int posThres = MAX(1,int(double(halfwindow-cutoff)/double(h)*0.5/scale + 0.5));
const int maxband = ( halfwindow - cutoff ) * 2 / 3 ;
2006-08-27 21:54:51 +02:00
const float mult = float ( h ) / float ( halfwindow - cutoff ) / 255.f ;
// Calculation loop
for ( int i = firstbar ; i < lastbar ; i + + ) {
__int64 curStart = i * samples - ( window / 2 ) ;
if ( curStart < 0 ) curStart = 0 ;
// Position input
float * in = base_in + curStart ;
// Perform the FFT
FFT fft ;
fft . Transform ( window , in , out_r , out_i ) ;
2006-08-28 00:29:14 +02:00
// Position pointer
write_ptr = data + i + h * w ;
write_ptr16 = ( ( unsigned short * ) data ) + ( i + h * w ) ;
2006-11-23 22:43:45 +01:00
// The maximum power output from the FFT
// Derived by maximising the result from the DFT function:
// f[u] = sum(x=0,N-1)[ f(x) * exp(-2 * pi * i * u * x) ]
// Where N is the number of samples transformed.
// = N * 2^(B-1) * exp(-2 * pi * i * u * x)
// Maximising by f(x) constant at maximum sample value.
// B is bit-depth of the samples, so 2^(B-1) is the maximum sample value.
// = N * 2^(B-1) * [ cos(-2*pi*u*x) + i sin(-2*pi*u*x) ]
// Expanding using Euler's formula.
// = N * 2^(B-1) * [ cos(2*pi*u*x) - i sin(2*pi*u*x) ]
// cos(-x) = cos(x) and sin(-x) = -sin(x)
// = N * 2^(B-1) * cos(2*pi*u*x) - N * 2^(B-1) * i sin(2*pi*u*x) [A]
// Expand the bracket.
// Now determine the maximum magnitude of [A], letting u be constant and x variable.
// | N * 2^(B-1) * cos(2*pi*u*x) - N * 2^(B-1) * i sin(2*pi*u*x) |
// = sqrt( [N * 2^(B-1) * cos(2*pi*u*x)]^2 + [N * 2^(B-1) * sin(2*pi*u*x)]^2 )
// = sqrt( N^2 * 4^(B-1) * cos^2(2*pi*u*x) + N^2 * 4^(B-1) * sin^2(2*pi*u*x) )
// = sqrt( N^2 * 4^(B-1) * [ cos^2(2*pi*u*x) + sin^2(2*pi*u*x) ] )
// = sqrt( N^2 * 4^(B-1) )
// It's known that sin^2(x) + cos^2(x) = 1.
// = N * 2^(B-1)
int maxpower = ( 1 < < ( 16 - 1 ) ) * 256 ;
2006-08-28 00:29:14 +02:00
2006-08-28 01:31:20 +02:00
// Calculate the signal power over frequency
2006-11-23 22:43:45 +01:00
#if 0
// Logarithmic scale
2006-08-28 01:31:20 +02:00
for ( int j = 0 ; j < window ; j + + ) {
float t = out_r [ j ] * out_r [ j ] + out_i [ j ] * out_i [ j ] ;
if ( t < 1 )
power [ j ] = 0 ;
else
power [ j ] = 10. * log10 ( t ) * 64 ; // try changing the constant 64 if playing with this
}
maxpower = 10 * log10 ( ( float ) maxpower ) ;
2006-11-23 22:43:45 +01:00
# elif 1
// "Compressed" scale
double onethirdmaxpower = maxpower / 3 , twothirdmaxpower = maxpower * 2 / 3 ;
2006-12-17 05:58:10 +01:00
double logoverscale = log ( maxpower * 8 * scale - twothirdmaxpower ) ;
2006-11-23 22:43:45 +01:00
for ( int j = 0 ; j < window ; j + + ) {
// First do a simple linear scale power calculation -- 8 gives a reasonable default scaling
power [ j ] = sqrt ( out_r [ j ] * out_r [ j ] + out_i [ j ] * out_i [ j ] ) * 8 * scale ;
if ( power [ j ] > maxpower * 2 / 3 ) {
double p = power [ j ] - twothirdmaxpower ;
2006-12-17 05:58:10 +01:00
p = log ( p ) * onethirdmaxpower / logoverscale ;
2006-11-23 22:43:45 +01:00
power [ j ] = p + twothirdmaxpower ;
}
}
2006-08-28 01:31:20 +02:00
# else
2006-11-23 22:43:45 +01:00
// Linear scale
2006-08-28 01:31:20 +02:00
for ( int j = 0 ; j < window ; j + + ) {
power [ j ] = sqrt ( out_r [ j ] * out_r [ j ] + out_i [ j ] * out_i [ j ] ) ;
}
# endif
2006-08-28 00:29:14 +02:00
# define WRITE_PIXEL \
if ( intensity > 255 ) intensity = 255 ; \
if ( intensity < 0 ) intensity = 0 ; \
if ( depth = = 32 ) { \
write_ptr - = w ; \
* write_ptr = spectrumColorMap [ intensity ] ; \
} \
else if ( depth = = 16 ) { \
write_ptr16 - = w ; \
* write_ptr16 = spectrumColorMap16 [ intensity ] ; \
}
// Decide which rendering algo to use
if ( halfwindow - cutoff > h ) {
// more than one frequency sample per pixel (vertically compress data)
// pick the largest value per pixel for display
// Iterate over pixels, picking a range of samples for each
for ( int j = 0 ; j < h ; j + + ) {
2006-08-28 01:31:20 +02:00
int sample1 = maxband * j / h + cutoff ;
int sample2 = maxband * ( j + 1 ) / h + cutoff ;
2006-08-28 00:29:14 +02:00
float maxval = 0 ;
for ( int samp = sample1 ; samp < = sample2 ; samp + + ) {
if ( power [ samp ] > maxval ) maxval = power [ samp ] ;
}
2006-11-23 22:43:45 +01:00
int intensity = int ( 256 * maxval / maxpower ) ;
2006-08-28 00:29:14 +02:00
WRITE_PIXEL
}
}
else {
// less than one frequency sample per pixel (vertically expand data)
// interpolate between pixels
// can also happen with exactly one sample per pixel, but how often is that?
// Iterate over pixels, picking the nearest power values
for ( int j = 0 ; j < h ; j + + ) {
2006-08-28 01:31:20 +02:00
float ideal = ( float ) ( j + 1. ) / h * maxband ;
2006-08-28 00:29:14 +02:00
float sample1 = power [ ( int ) floor ( ideal ) + cutoff ] ;
float sample2 = power [ ( int ) ceil ( ideal ) + cutoff ] ;
float frac = ideal - floor ( ideal ) ;
2006-11-23 22:43:45 +01:00
int intensity = int ( ( ( 1 - frac ) * sample1 + frac * sample2 ) / maxpower * 256 ) ;
2006-08-28 00:29:14 +02:00
WRITE_PIXEL
}
}
# undef WRITE_PIXEL
2006-08-27 21:54:51 +02:00
}
delete out_r ;
delete out_i ;
2006-08-28 00:29:14 +02:00
delete power ;
2006-08-27 21:54:51 +02:00
return 0 ;
}
} ;
2006-01-16 22:02:54 +01:00
//////////////////////////
// Draw spectrum analyzer
void AudioDisplay : : DrawSpectrum ( wxDC & finaldc , bool weak ) {
// Spectrum bitmap
if ( ! weak | | ! spectrumDisplay | | spectrumDisplay - > GetWidth ( ) ! = w | | spectrumDisplay - > GetHeight ( ) ! = h ) {
if ( spectrumDisplay ) delete spectrumDisplay ;
//spectrumDisplay = new wxBitmap(w,h);
weak = false ;
}
if ( ! weak ) {
// Generate colors
if ( ! colorMapsGenerated ) {
unsigned char r , g , b ;
for ( int i = 0 ; i < 256 ; i + + ) {
2006-08-27 21:54:51 +02:00
//hsv_to_rgb(255 - i, 255 - i * 3/10, 255*3/10 + i * 7/10, &r, &g, &b);
hsl_to_rgb ( 170 + i * 2 / 3 , 128 + i / 2 , i , & r , & g , & b ) ;
2006-01-16 22:02:54 +01:00
spectrumColorMap [ i ] = b | ( g < < 8 ) | ( r < < 16 ) ;
spectrumColorMap16 [ i ] = ( ( r > > 3 ) < < 11 ) | ( ( g > > 2 ) < < 5 ) | b > > 3 ;
}
colorMapsGenerated = true ;
}
int depth = wxDisplayDepth ( ) ;
// Prepare arrays
int cutOff = Options . AsInt ( _T ( " Audio Spectrum Cutoff " ) ) ;
int window = 1 < < Options . AsInt ( _T ( " Audio Spectrum Window " ) ) ;
int totalLen = w * samples + window ;
float * raw_float = new float [ totalLen ] ;
short * raw_int = new short [ totalLen ] ;
float * in = raw_float ;
// Fill input
__int64 start = Position * samples ;
provider - > GetAudio ( raw_int , start , totalLen ) ;
for ( int j = 0 ; j < totalLen ; j + + ) {
raw_float [ j ] = ( float ) raw_int [ j ] ;
}
delete raw_int ;
2006-08-27 21:54:51 +02:00
// For image data
int * data = new int [ w * h * depth / 32 ] ;
////// START OF PARALLELISED CODE //////
2006-11-11 02:47:35 +01:00
const int cpu_count = MAX ( wxThread : : GetCPUCount ( ) , 1 ) ;
2006-08-27 21:54:51 +02:00
std : : vector < SpectrumRendererThread * > threads ( cpu_count ) ;
for ( int i = 0 ; i < cpu_count ; i + + ) {
2006-11-23 22:43:45 +01:00
// Ugh, way too much data to copy in
2006-08-27 21:54:51 +02:00
threads [ i ] = new SpectrumRendererThread ( ) ;
threads [ i ] - > data = data ;
threads [ i ] - > window = window ;
threads [ i ] - > firstbar = i * w / cpu_count ;
threads [ i ] - > lastbar = ( i + 1 ) * w / cpu_count ;
threads [ i ] - > w = w ;
threads [ i ] - > h = h ;
threads [ i ] - > cutoff = cutOff ;
threads [ i ] - > base_in = raw_float ;
threads [ i ] - > samples = samples ;
threads [ i ] - > depth = depth ;
threads [ i ] - > scale = scale ;
threads [ i ] - > Run ( ) ;
}
// Threads started, wait for them to end
for ( int i = 0 ; i < cpu_count ; i + + ) {
threads [ i ] - > Wait ( ) ;
delete threads [ i ] ;
}
2006-01-16 22:02:54 +01:00
// Clear memory
delete raw_float ;
2006-11-23 22:43:45 +01:00
// Create image FIXME *BREAKS ON NON-WIN32* (see wx docs)
2006-01-16 22:02:54 +01:00
spectrumDisplay = new wxBitmap ( ( const char * ) data , w , h , depth ) ;
}
// Draw
wxMemoryDC dc ;
dc . SelectObject ( * spectrumDisplay ) ;
finaldc . Blit ( 0 , 0 , w , h , & dc , 0 , 0 ) ;
}
//////////////////////////
// Get selection position
void AudioDisplay : : GetDialoguePos ( __int64 & selStart , __int64 & selEnd , bool cap ) {
selStart = GetXAtMS ( curStartMS ) ;
selEnd = GetXAtMS ( curEndMS ) ;
if ( cap ) {
if ( selStart < 0 ) selStart = 0 ;
if ( selEnd < 0 ) selEnd = 0 ;
if ( selStart > = w ) selStart = w - 1 ;
if ( selEnd > = w ) selEnd = w - 1 ;
}
}
////////////////////////
// Get karaoke position
void AudioDisplay : : GetKaraokePos ( __int64 & karStart , __int64 & karEnd , bool cap ) {
2006-02-20 08:12:01 +01:00
try {
// Wrap around
2006-08-28 00:29:14 +02:00
int nsyls = ( int ) karaoke - > syllables . size ( ) ;
2006-02-20 08:12:01 +01:00
if ( karaoke - > curSyllable = = - 1 ) {
karaoke - > SetSyllable ( nsyls - 1 ) ;
}
if ( karaoke - > curSyllable > = nsyls ) karaoke - > curSyllable = nsyls - 1 ;
2006-01-16 22:02:54 +01:00
2006-02-20 08:12:01 +01:00
// Get positions
int pos = karaoke - > syllables . at ( karaoke - > curSyllable ) . position ;
int len = karaoke - > syllables . at ( karaoke - > curSyllable ) . length ;
karStart = GetXAtMS ( curStartMS + pos * 10 ) ;
karEnd = GetXAtMS ( curStartMS + pos * 10 + len * 10 ) ;
// Cap
if ( cap ) {
if ( karStart < 0 ) karStart = 0 ;
if ( karEnd < 0 ) karEnd = 0 ;
if ( karStart > = w ) karStart = w - 1 ;
if ( karEnd > = w ) karEnd = w - 1 ;
}
}
catch ( . . . ) {
2006-01-16 22:02:54 +01:00
}
}
//////////
// Update
void AudioDisplay : : Update ( ) {
if ( blockUpdate ) return ;
if ( loaded ) {
2006-02-02 19:24:58 +01:00
if ( Options . AsBool ( _T ( " Audio Autoscroll " ) ) )
MakeDialogueVisible ( ) ;
else
2006-01-16 22:02:54 +01:00
UpdateImage ( true ) ;
}
}
/////////////////////////
// Make dialogue visible
void AudioDisplay : : MakeDialogueVisible ( bool force ) {
// Variables
int temp1 = 0 , temp2 = 0 ;
GetTimesSelection ( temp1 , temp2 ) ;
int startPos = GetSampleAtMS ( temp1 ) ;
int endPos = GetSampleAtMS ( temp2 ) ;
int startX = GetXAtMS ( temp1 ) ;
int endX = GetXAtMS ( temp2 ) ;
if ( force | | startX < 50 | | endX > w - 50 ) {
UpdatePosition ( ( startPos + endPos - w * samples ) / 2 , true ) ;
}
// Update
UpdateImage ( ) ;
}
////////////////
// Set position
void AudioDisplay : : SetPosition ( int pos ) {
Position = pos ;
PositionSample = pos * samples ;
UpdateImage ( ) ;
}
///////////////////
// Update position
void AudioDisplay : : UpdatePosition ( int pos , bool IsSample ) {
// Safeguards
if ( IsSample ) pos / = samples ;
int len = provider - > GetNumSamples ( ) / samples ;
if ( pos < 0 ) pos = 0 ;
if ( pos > = len ) pos = len - 1 ;
// Set
Position = pos ;
PositionSample = pos * samples ;
UpdateScrollbar ( ) ;
}
/////////////////////////////
// Set samples in percentage
// Note: aka Horizontal Zoom
void AudioDisplay : : SetSamplesPercent ( int percent , bool update , float pivot ) {
// Calculate
if ( percent < 1 ) percent = 1 ;
if ( percent > 100 ) percent = 100 ;
if ( samplesPercent = = percent ) return ;
samplesPercent = percent ;
// Update
if ( update ) {
// Center scroll
int oldSamples = samples ;
2006-02-25 01:11:54 +01:00
UpdateSamples ( ) ;
2006-01-16 22:02:54 +01:00
PositionSample + = ( oldSamples - samples ) * w * pivot ;
if ( PositionSample < 0 ) PositionSample = 0 ;
// Update
2006-02-25 01:11:54 +01:00
UpdateSamples ( ) ;
2006-01-16 22:02:54 +01:00
UpdateScrollbar ( ) ;
UpdateImage ( ) ;
2006-02-25 01:11:54 +01:00
Refresh ( false ) ;
2006-01-16 22:02:54 +01:00
}
}
//////////////////
// Update samples
void AudioDisplay : : UpdateSamples ( ) {
// Set samples
2006-07-04 23:59:30 +02:00
if ( ! provider ) return ;
2006-02-02 19:17:54 +01:00
__int64 totalSamples = provider - > GetNumSamples ( ) ;
2006-01-16 22:02:54 +01:00
int total = totalSamples / w ;
int max = 5760000 / w ; // 2 minutes at 48 kHz maximum
if ( total > max ) total = max ;
int min = 8 ;
if ( total < min ) total = min ;
int range = total - min ;
samples = range * pow ( samplesPercent / 100.0 , 3 ) + min ;
// Set position
int length = w * samples ;
if ( PositionSample + length > totalSamples ) {
PositionSample = totalSamples - length ;
if ( PositionSample < 0 ) PositionSample = 0 ;
Position = PositionSample / samples ;
}
}
/////////////
// Set scale
void AudioDisplay : : SetScale ( float _scale ) {
if ( scale = = _scale ) return ;
scale = _scale ;
UpdateImage ( ) ;
}
//////////////////
// Load from file
2006-04-15 00:35:39 +02:00
void AudioDisplay : : SetFile ( wxString file , VideoProvider * vprovider ) {
2006-02-25 08:41:18 +01:00
// Unload
2006-02-20 22:32:58 +01:00
if ( file . IsEmpty ( ) ) {
2006-02-25 08:41:18 +01:00
if ( player ) player - > CloseStream ( ) ;
delete provider ;
delete player ;
2006-01-16 22:02:54 +01:00
provider = NULL ;
2006-02-25 08:41:18 +01:00
player = NULL ;
2006-01-16 22:02:54 +01:00
Reset ( ) ;
2006-02-02 19:17:54 +01:00
loaded = false ;
2006-07-04 23:59:30 +02:00
temporary = false ;
2006-01-16 22:02:54 +01:00
}
2006-02-25 08:41:18 +01:00
// Load
2006-01-16 22:02:54 +01:00
else {
SetFile ( _T ( " " ) ) ;
try {
2006-02-25 08:41:18 +01:00
// Get provider
2006-04-15 00:35:39 +02:00
provider = AudioProvider : : GetAudioProvider ( file , this , vprovider ) ;
2006-01-16 22:02:54 +01:00
2006-02-25 08:41:18 +01:00
// Get player
player = AudioPlayer : : GetAudioPlayer ( ) ;
player - > SetDisplayTimer ( & UpdateTimer ) ;
player - > SetProvider ( provider ) ;
player - > OpenStream ( ) ;
2006-02-02 19:17:54 +01:00
loaded = true ;
2006-01-16 22:02:54 +01:00
// Add to recent
Options . AddToRecentList ( file , _T ( " Recent aud " ) ) ;
2006-02-02 19:17:54 +01:00
// Update
UpdateImage ( ) ;
2006-01-16 22:02:54 +01:00
}
catch ( wxString & err ) {
wxMessageBox ( err , _T ( " Error loading audio " ) , wxICON_ERROR | wxOK ) ;
}
}
2006-02-02 19:17:54 +01:00
assert ( loaded = = ( provider ! = NULL ) ) ;
2006-01-16 22:02:54 +01:00
// Set default selection
int n = grid - > editBox - > linen ;
SetDialogue ( grid , grid - > GetDialogue ( n ) , n ) ;
}
///////////////////
// Load from video
void AudioDisplay : : SetFromVideo ( ) {
if ( video - > loaded ) {
wxString extension = video - > videoName . Right ( 4 ) ;
extension . LowerCase ( ) ;
if ( extension ! = _T ( " .d2v " ) )
2006-04-15 00:35:39 +02:00
SetFile ( video - > videoName , video - > provider ) ;
2006-01-16 22:02:54 +01:00
}
}
////////////////////
// Update scrollbar
void AudioDisplay : : UpdateScrollbar ( ) {
2006-07-04 23:59:30 +02:00
if ( ! provider ) return ;
2006-01-16 22:02:54 +01:00
int page = w / 12 ;
int len = provider - > GetNumSamples ( ) / samples / 12 ;
Position = PositionSample / samples ;
ScrollBar - > SetScrollbar ( Position / 12 , page , len , page * 0.7 , true ) ;
}
//////////////////////////////////////////////
// Gets the sample number at the x coordinate
__int64 AudioDisplay : : GetSampleAtX ( int x ) {
return ( x + Position ) * samples ;
}
/////////////////////////////////////////////////
// Gets the x coordinate corresponding to sample
int AudioDisplay : : GetXAtSample ( __int64 n ) {
return ( n / samples ) - Position ;
}
/////////////////
// Get MS from X
int AudioDisplay : : GetMSAtX ( __int64 x ) {
2006-02-02 19:17:54 +01:00
return ( PositionSample + ( x * samples ) ) * 1000 / provider - > GetSampleRate ( ) ;
2006-01-16 22:02:54 +01:00
}
/////////////////
// Get X from MS
int AudioDisplay : : GetXAtMS ( __int64 ms ) {
2006-02-02 19:17:54 +01:00
return ( ( ms * provider - > GetSampleRate ( ) / 1000 ) - PositionSample ) / samples ;
2006-01-16 22:02:54 +01:00
}
////////////////////
// Get MS At sample
int AudioDisplay : : GetMSAtSample ( __int64 x ) {
2006-02-02 19:17:54 +01:00
return x * 1000 / provider - > GetSampleRate ( ) ;
2006-01-16 22:02:54 +01:00
}
////////////////////
// Get Sample at MS
__int64 AudioDisplay : : GetSampleAtMS ( __int64 ms ) {
2006-02-02 19:17:54 +01:00
return ms * provider - > GetSampleRate ( ) / 1000 ;
2006-01-16 22:02:54 +01:00
}
////////
// Play
void AudioDisplay : : Play ( int start , int end ) {
// Check provider
2006-07-01 08:32:11 +02:00
if ( ! provider ) {
// Load temporary provider from video
if ( video - > loaded ) {
try {
// Get provider
provider = AudioProvider : : GetAudioProvider ( video - > videoName , this , video - > provider , 0 ) ;
// Get player
player = AudioPlayer : : GetAudioPlayer ( ) ;
player - > SetDisplayTimer ( & UpdateTimer ) ;
player - > SetProvider ( provider ) ;
player - > OpenStream ( ) ;
temporary = true ;
}
catch ( . . . ) {
return ;
}
}
if ( ! provider ) return ;
}
2006-01-16 22:02:54 +01:00
// Set defaults
__int64 num_samples = provider - > GetNumSamples ( ) ;
start = GetSampleAtMS ( start ) ;
if ( end ! = - 1 ) end = GetSampleAtMS ( end ) ;
else end = num_samples - 1 ;
// Sanity checking
if ( start < 0 ) start = 0 ;
if ( start > = num_samples ) start = num_samples - 1 ;
if ( end < 0 ) end = 0 ;
if ( end > = num_samples ) end = num_samples - 1 ;
if ( end < start ) end = start ;
// Call play
2006-02-25 08:41:18 +01:00
player - > Play ( start , end - start ) ;
2006-01-16 22:02:54 +01:00
}
////////
// Stop
void AudioDisplay : : Stop ( ) {
2006-02-25 08:41:18 +01:00
if ( ! player ) return ;
2006-01-16 22:02:54 +01:00
2006-02-25 08:41:18 +01:00
player - > Stop ( ) ;
2006-07-02 01:31:15 +02:00
if ( video & & video - > IsPlaying ) video - > Stop ( ) ;
2006-01-16 22:02:54 +01:00
}
///////////////////////////
// Get samples of dialogue
void AudioDisplay : : GetTimesDialogue ( int & start , int & end ) {
if ( ! dialogue ) {
start = 0 ;
end = 0 ;
return ;
}
start = dialogue - > Start . GetMS ( ) ;
end = dialogue - > End . GetMS ( ) ;
}
////////////////////////////
// Get samples of selection
void AudioDisplay : : GetTimesSelection ( int & start , int & end ) {
2006-02-20 08:12:01 +01:00
start = 0 ;
end = 0 ;
if ( ! dialogue ) return ;
2006-01-16 22:02:54 +01:00
2006-02-20 08:12:01 +01:00
try {
if ( karaoke - > enabled ) {
int pos = karaoke - > syllables . at ( karaoke - > curSyllable ) . position ;
int len = karaoke - > syllables . at ( karaoke - > curSyllable ) . length ;
start = curStartMS + pos * 10 ;
end = curStartMS + pos * 10 + len * 10 ;
}
else {
start = curStartMS ;
end = curEndMS ;
}
2006-01-16 22:02:54 +01:00
}
2006-02-20 08:12:01 +01:00
catch ( . . . ) { }
2006-01-16 22:02:54 +01:00
}
/////////////////////////////
// Set the current selection
void AudioDisplay : : SetSelection ( int start , int end ) {
curStartMS = start ;
curEndMS = end ;
Update ( ) ;
}
////////////////
// Set dialogue
void AudioDisplay : : SetDialogue ( SubtitlesGrid * _grid , AssDialogue * diag , int n ) {
// Actual parameters
if ( _grid ) {
// Set variables
grid = _grid ;
line_n = n ;
dialogue = diag ;
// Set flags
diagUpdated = false ;
NeedCommit = false ;
// Set times
if ( dialogue & & ! dontReadTimes ) {
curStartMS = dialogue - > Start . GetMS ( ) ;
curEndMS = dialogue - > End . GetMS ( ) ;
}
}
// Read karaoke data
if ( dialogue & & karaoke - > enabled ) {
NeedCommit = karaoke - > LoadFromDialogue ( dialogue ) ;
// Reset karaoke pos
2006-08-28 00:29:14 +02:00
if ( karaoke - > curSyllable = = - 1 ) karaoke - > SetSyllable ( ( int ) karaoke - > syllables . size ( ) - 1 ) ;
2006-01-16 22:02:54 +01:00
else karaoke - > SetSyllable ( 0 ) ;
}
// Update
Update ( ) ;
}
//////////////////
// Commit changes
void AudioDisplay : : CommitChanges ( ) {
2006-07-04 23:59:30 +02:00
// Loaded?
if ( ! loaded ) return ;
2006-01-27 04:18:26 +01:00
if ( ! Options . AsBool ( _T ( " Audio SSA Mode " ) ) & & ! box - > audioKaraoke - > splitting ) {
2006-01-16 22:02:54 +01:00
// Check if there's any need to commit
if ( ! NeedCommit ) return ;
// Check if selection is valid
if ( curEndMS < curStartMS ) {
wxMessageBox ( _T ( " Start time must be before end time! " ) , _T ( " Error commiting " ) , wxICON_ERROR ) ;
return ;
}
}
// Reset flags
diagUpdated = false ;
NeedCommit = false ;
// Update karaoke
int karSyl = 0 ;
2006-01-27 01:48:59 +01:00
bool wasKaraSplitting = false ;
2006-01-16 22:02:54 +01:00
if ( karaoke - > enabled ) {
2006-01-27 01:48:59 +01:00
wasKaraSplitting = box - > audioKaraoke - > splitting ;
2006-01-16 22:02:54 +01:00
karaoke - > Commit ( ) ;
karSyl = karaoke - > curSyllable ;
}
2006-02-20 23:32:20 +01:00
// Update dialogues
2006-01-16 22:02:54 +01:00
blockUpdate = true ;
2006-02-20 23:32:20 +01:00
wxArrayInt sel = grid - > GetSelection ( ) ;
2006-08-28 00:29:14 +02:00
int sels = ( int ) sel . Count ( ) ;
2006-02-20 23:32:20 +01:00
AssDialogue * curDiag ;
for ( int i = - 1 ; i < sels ; i + + ) {
if ( i = = - 1 ) curDiag = dialogue ;
else {
curDiag = grid - > GetDialogue ( sel [ i ] ) ;
if ( curDiag = = dialogue ) continue ;
}
curDiag - > Start . SetMS ( curStartMS ) ;
curDiag - > End . SetMS ( curEndMS ) ;
curDiag - > UpdateData ( ) ;
}
// Update grid
2006-01-16 22:02:54 +01:00
grid - > editBox - > Update ( ! karaoke - > enabled ) ;
grid - > ass - > FlagAsModified ( ) ;
grid - > CommitChanges ( ) ;
karaoke - > curSyllable = karSyl ;
blockUpdate = false ;
2006-01-27 01:48:59 +01:00
// If in SSA mode, select next line and "move timing forward" (unless the user was splitting karaoke)
if ( Options . AsBool ( _T ( " Audio SSA Mode " ) ) & & Options . AsBool ( _T ( " Audio SSA Next Line on Commit " ) ) & & ! wasKaraSplitting ) {
2006-12-18 21:13:23 +01:00
// Insert a line if it doesn't exist
int nrows = grid - > GetRows ( ) ;
if ( nrows = = line_n + 1 ) {
AssDialogue * def = new AssDialogue ;
def - > Start = grid - > GetDialogue ( line_n ) - > End ;
def - > End = grid - > GetDialogue ( line_n ) - > End ;
def - > End . SetMS ( def - > End . GetMS ( ) + 5000 ) ;
def - > Style = grid - > GetDialogue ( line_n ) - > Style ;
grid - > InsertLine ( def , line_n , true ) ;
}
// Go to next
2006-01-16 22:02:54 +01:00
dontReadTimes = true ;
Next ( ) ;
dontReadTimes = false ;
curStartMS = curEndMS ;
curEndMS = curStartMS + Options . AsInt ( _T ( " Timing Default Duration " ) ) ;
}
Update ( ) ;
}
////////////
// Add lead
void AudioDisplay : : AddLead ( bool in , bool out ) {
// Lead in
if ( in ) {
curStartMS - = Options . AsInt ( _T ( " Audio Lead in " ) ) ;
if ( curStartMS < 0 ) curStartMS = 0 ;
}
// Lead out
if ( out ) {
curEndMS + = Options . AsInt ( _T ( " Audio Lead out " ) ) ;
}
// Set changes
NeedCommit = true ;
if ( Options . AsBool ( _T ( " Audio Autocommit " ) ) ) CommitChanges ( ) ;
Update ( ) ;
}
///////////////
// Event table
BEGIN_EVENT_TABLE ( AudioDisplay , wxWindow )
EVT_MOUSE_EVENTS ( AudioDisplay : : OnMouseEvent )
EVT_PAINT ( AudioDisplay : : OnPaint )
EVT_SIZE ( AudioDisplay : : OnSize )
EVT_TIMER ( Audio_Update_Timer , AudioDisplay : : OnUpdateTimer )
EVT_KEY_DOWN ( AudioDisplay : : OnKeyDown )
EVT_SET_FOCUS ( AudioDisplay : : OnGetFocus )
EVT_KILL_FOCUS ( AudioDisplay : : OnLoseFocus )
END_EVENT_TABLE ( )
/////////
// Paint
void AudioDisplay : : OnPaint ( wxPaintEvent & event ) {
if ( w = = 0 | | h = = 0 ) return ;
wxPaintDC dc ( this ) ;
dc . BeginDrawing ( ) ;
dc . DrawBitmap ( * origImage , 0 , 0 ) ;
dc . EndDrawing ( ) ;
}
///////////////
// Mouse event
void AudioDisplay : : OnMouseEvent ( wxMouseEvent & event ) {
// Get x,y
__int64 x = event . GetX ( ) ;
__int64 y = event . GetY ( ) ;
bool karMode = karaoke - > enabled ;
bool shiftDown = event . m_shiftDown ;
bool ctrlDown = event . m_controlDown ;
2006-02-24 02:16:27 +01:00
// Leaving event
if ( event . Leaving ( ) ) {
event . Skip ( ) ;
return ;
}
2006-01-16 22:02:54 +01:00
// Is inside?
bool inside = false ;
2006-03-07 01:12:50 +01:00
bool onScale = false ;
if ( x > = 0 & & y > = 0 & & x < w ) {
if ( y < h ) {
inside = true ;
2006-01-16 22:02:54 +01:00
2006-03-07 01:12:50 +01:00
// Get focus
if ( wxWindow : : FindFocus ( ) ! = this & & Options . AsBool ( _T ( " Audio Autofocus " ) ) ) SetFocus ( ) ;
}
else if ( y < h + 20 ) onScale = true ;
2006-01-16 22:02:54 +01:00
}
2006-02-21 22:33:15 +01:00
// Click type
if ( event . ButtonDown ( wxMOUSE_BTN_LEFT ) & & ! holding ) {
holding = true ;
CaptureMouse ( ) ;
}
if ( ! event . ButtonIsDown ( wxMOUSE_BTN_LEFT ) & & holding ) {
holding = false ;
2006-07-04 08:13:54 +02:00
if ( HasCapture ( ) ) ReleaseMouse ( ) ;
}
// Stop scrubbing
2006-07-07 00:39:58 +02:00
bool scrubButton = false & & event . ButtonIsDown ( wxMOUSE_BTN_MIDDLE ) ;
2006-07-04 08:13:54 +02:00
if ( scrubbing & & ! scrubButton ) {
// Release mouse
scrubbing = false ;
if ( HasCapture ( ) ) ReleaseMouse ( ) ;
// Stop player
player - > Stop ( ) ;
player - > SetProvider ( provider ) ;
delete scrubProvider ;
}
// Start scrubbing
2006-07-04 10:25:54 +02:00
if ( ! scrubbing & & scrubButton & & provider - > GetChannels ( ) = = 1 ) {
2006-07-04 08:13:54 +02:00
// Get mouse
CaptureMouse ( ) ;
scrubbing = true ;
// Initialize provider
player - > Stop ( ) ;
scrubProvider = new StreamAudioProvider ( ) ;
scrubProvider - > SetParams ( provider - > GetChannels ( ) , provider - > GetSampleRate ( ) , provider - > GetBytesPerSample ( ) ) ;
player - > SetProvider ( scrubProvider ) ;
// Set variables
scrubLastPos = GetSampleAtX ( x ) ;
scrubTime = clock ( ) ;
2006-07-07 00:39:58 +02:00
scrubLastRate = provider - > GetSampleRate ( ) ;
2006-07-04 08:13:54 +02:00
}
// Scrub
if ( scrubbing & & scrubButton ) {
// Get current data
2006-07-07 00:39:58 +02:00
__int64 exactPos = MAX ( 0 , GetSampleAtX ( x ) ) ;
2006-07-04 08:13:54 +02:00
int curScrubTime = clock ( ) ;
int scrubDeltaTime = curScrubTime - scrubTime ;
2006-07-07 00:39:58 +02:00
bool invert = exactPos < scrubLastPos ;
__int64 curScrubPos = exactPos ;
if ( scrubDeltaTime > 0 ) {
// Get derived data
int rateChange = provider - > GetSampleRate ( ) / 20 ;
2006-07-08 00:48:26 +02:00
int curRate = MID ( int ( scrubLastRate - rateChange ) , abs ( int ( exactPos - scrubLastPos ) ) * CLOCKS_PER_SEC / scrubDeltaTime , int ( scrubLastRate + rateChange ) ) ;
2006-07-07 00:39:58 +02:00
if ( abs ( curRate - scrubLastRate ) < rateChange ) curRate = scrubLastRate ;
2006-07-08 00:48:26 +02:00
curScrubPos = scrubLastPos + ( curRate * scrubDeltaTime / CLOCKS_PER_SEC * ( invert ? - 1 : 1 ) ) ;
2006-07-07 00:39:58 +02:00
__int64 scrubDelta = curScrubPos - scrubLastPos ;
scrubLastRate = curRate ;
// Copy data to buffer
if ( scrubDelta ! = 0 ) {
// Create buffer
2006-07-08 00:48:26 +02:00
int bufSize = scrubDeltaTime * scrubProvider - > GetSampleRate ( ) / CLOCKS_PER_SEC ;
2006-07-07 00:39:58 +02:00
short * buf = new short [ bufSize ] ;
// Flag as inverted, if necessary
if ( invert ) scrubDelta = - scrubDelta ;
// Copy data from original provider to temp buffer
short * temp = new short [ scrubDelta ] ;
provider - > GetAudio ( temp , MIN ( curScrubPos , scrubLastPos ) , scrubDelta ) ;
// Scale
float scale = float ( double ( scrubDelta ) / double ( bufSize ) ) ;
float start , end ;
int istart , iend ;
float tempfinal ;
for ( int i = 0 ; i < bufSize ; i + + ) {
start = i * scale ;
end = ( i + 1 ) * scale ;
istart = ( int ) start ;
iend = MIN ( ( int ) end , scrubDelta - 1 ) ;
if ( istart = = iend ) tempfinal = temp [ istart ] * ( end - start ) ;
else {
tempfinal = temp [ istart ] * ( 1 + istart - start ) + temp [ iend ] * ( end - iend ) ;
for ( int j = istart + 1 ; j < iend ; j + + ) tempfinal + = temp [ i ] ;
}
buf [ i ] = tempfinal / scale ;
2006-07-04 10:25:54 +02:00
}
2006-07-07 00:39:58 +02:00
//int len = MIN(bufSize,scrubDelta);
//for (int i=0;i<len;i++) buf[i] = temp[i];
//for (int i=len;i<bufSize;i++) buf[i] = 0;
delete temp ;
// Invert
if ( invert ) {
short aux ;
for ( int i = 0 ; i < bufSize / 2 ; i + + ) {
aux = buf [ i ] ;
buf [ i ] = buf [ bufSize - i - 1 ] ;
buf [ bufSize - i - 1 ] = aux ;
}
2006-07-04 08:13:54 +02:00
}
2006-07-07 00:39:58 +02:00
// Send data to provider
scrubProvider - > Append ( buf , bufSize ) ;
2006-07-08 00:47:55 +02:00
if ( ! player - > IsPlaying ( ) ) player - > Play ( 0 , ~ 0ULL ) ;
2006-07-07 00:39:58 +02:00
delete buf ;
}
2006-07-04 08:13:54 +02:00
}
// Update last pos and time
scrubLastPos = curScrubPos ;
scrubTime = curScrubTime ;
// Return
return ;
2006-02-21 22:33:15 +01:00
}
2006-01-16 22:02:54 +01:00
// Mouse wheel
if ( event . GetWheelRotation ( ) ! = 0 ) {
// Zoom or scroll?
bool zoom = shiftDown ;
if ( Options . AsBool ( _T ( " Audio Wheel Default To Zoom " ) ) ) zoom = ! zoom ;
// Zoom
if ( zoom ) {
int step = - event . GetWheelRotation ( ) / event . GetWheelDelta ( ) ;
int value = box - > HorizontalZoom - > GetValue ( ) + step ;
box - > HorizontalZoom - > SetValue ( value ) ;
SetSamplesPercent ( value , true , float ( x ) / float ( w ) ) ;
}
// Scroll
else {
int step = event . GetWheelRotation ( ) * w / 360 ;
UpdatePosition ( Position + step , false ) ;
UpdateImage ( ) ;
}
}
// Cursor drawing
2006-02-25 08:41:18 +01:00
if ( ! player - > IsPlaying ( ) ) {
2006-01-16 22:02:54 +01:00
// Draw bg
wxClientDC dc ( this ) ;
dc . BeginDrawing ( ) ;
dc . DrawBitmap ( * origImage , 0 , 0 ) ;
if ( inside ) {
// Draw cursor
dc . SetLogicalFunction ( wxINVERT ) ;
dc . DrawLine ( x , 0 , x , h ) ;
// Time string
AssTime time ;
time . SetMS ( GetMSAtX ( x ) ) ;
wxString text = time . GetASSFormated ( ) ;
// Calculate metrics
wxFont font ( 10 , wxFONTFAMILY_DEFAULT , wxFONTSTYLE_NORMAL , wxFONTWEIGHT_BOLD , false , _T ( " Verdana " ) ) ;
dc . SetFont ( font ) ;
int tw , th ;
GetTextExtent ( text , & tw , & th , NULL , NULL , & font ) ;
// Set inversion
bool left = true ;
if ( x > w / 2 ) left = false ;
// Text coordinates
int dx ;
dx = x - tw / 2 ;
if ( dx < 4 ) dx = 4 ;
int max = w - tw - 4 ;
if ( dx > max ) dx = max ;
int dy = 4 ;
// Draw text
dc . SetTextForeground ( wxColour ( 64 , 64 , 64 ) ) ;
dc . DrawText ( text , dx + 1 , dy - 1 ) ;
dc . DrawText ( text , dx + 1 , dy + 1 ) ;
dc . DrawText ( text , dx - 1 , dy - 1 ) ;
dc . DrawText ( text , dx - 1 , dy + 1 ) ;
dc . SetTextForeground ( wxColour ( 255 , 255 , 255 ) ) ;
dc . DrawText ( text , dx , dy ) ;
}
// End drawing
dc . EndDrawing ( ) ;
}
2006-03-07 01:12:50 +01:00
// Scale dragging
2006-07-02 00:49:09 +02:00
if ( ( hold = = 0 & & onScale ) | | draggingScale ) {
2006-03-07 01:12:50 +01:00
if ( event . ButtonDown ( wxMOUSE_BTN_LEFT ) ) {
lastDragX = x ;
draggingScale = true ;
}
else if ( holding ) {
int delta = lastDragX - x ;
lastDragX = x ;
UpdatePosition ( Position + delta ) ;
UpdateImage ( ) ;
Refresh ( false ) ;
2006-07-02 00:49:09 +02:00
SetCursor ( wxNullCursor ) ;
return ;
2006-03-07 01:12:50 +01:00
}
else draggingScale = false ;
}
// Outside
2006-07-02 00:49:09 +02:00
if ( ! inside & & hold = = 0 ) return ;
2006-03-06 01:45:24 +01:00
2006-03-05 05:41:59 +01:00
// Left/middle click
if ( event . ButtonDown ( wxMOUSE_BTN_LEFT ) | | event . Button ( wxMOUSE_BTN_MIDDLE ) ) {
SetFocus ( ) ;
2006-01-16 22:02:54 +01:00
}
// Right click
if ( event . ButtonDown ( wxMOUSE_BTN_RIGHT ) ) {
2006-02-21 22:33:15 +01:00
SetFocus ( ) ;
2006-01-16 22:02:54 +01:00
if ( karaoke - > enabled ) {
int syl = GetSyllableAtX ( x ) ;
if ( syl ! = - 1 ) {
int start = karaoke - > syllables . at ( syl ) . position * 10 + dialogue - > Start . GetMS ( ) ;
int count = karaoke - > syllables . at ( syl ) . length * 10 ;
2006-02-25 08:41:18 +01:00
player - > Play ( GetSampleAtMS ( start ) , GetSampleAtMS ( count ) ) ;
2006-01-16 22:02:54 +01:00
}
}
}
bool defCursor = true ;
// Substation alpha mode
if ( Options . AsBool ( _T ( " Audio SSA Mode " ) ) & & ! karaoke - > enabled & & dialogue ) {
bool mod = false ;
// Set start
if ( event . ButtonDown ( wxMOUSE_BTN_LEFT ) ) {
curStartMS = GetMSAtX ( x ) ;
mod = true ;
}
// Set end
if ( event . ButtonDown ( wxMOUSE_BTN_RIGHT ) ) {
curEndMS = GetMSAtX ( x ) ;
mod = true ;
2006-02-25 08:41:18 +01:00
player - > SetEndPosition ( GetSampleAtX ( x ) ) ;
2006-01-16 22:02:54 +01:00
}
// Modified, commit changes
if ( mod ) {
// Swap if needed
if ( false & & curStartMS > curEndMS ) {
int aux = curStartMS ;
curStartMS = curEndMS ;
curEndMS = aux ;
}
// Commit
NeedCommit = true ;
2006-02-02 19:24:58 +01:00
if ( Options . AsBool ( _T ( " Audio SSA Allow Autocommit " ) ) & & Options . AsBool ( _T ( " Audio Autocommit " ) ) & & curStartMS < = curEndMS )
2006-01-16 22:02:54 +01:00
CommitChanges ( ) ;
2006-02-02 19:24:58 +01:00
else
2006-01-16 22:02:54 +01:00
UpdateImage ( true ) ;
}
}
// Standard mode
else {
// Moving around
if ( hasSel ) {
// Grab start/end
if ( hold = = 0 ) {
bool gotGrab = false ;
// Grab start
if ( ! karMode ) {
if ( abs64 ( x - selStart ) < 6 ) {
wxCursor cursor ( wxCURSOR_SIZEWE ) ;
SetCursor ( cursor ) ;
defCursor = false ;
if ( event . LeftIsDown ( ) ) {
hold = 1 ;
gotGrab = true ;
}
}
// Grab end
else if ( abs64 ( x - selEnd ) < 6 ) {
wxCursor cursor ( wxCURSOR_SIZEWE ) ;
SetCursor ( cursor ) ;
defCursor = false ;
if ( event . LeftIsDown ( ) ) {
hold = 2 ;
gotGrab = true ;
}
}
}
// Grabbing a syllable
if ( ! gotGrab & & karMode ) {
__int64 pos , len , curpos ;
KaraokeSyllable * curSyl ;
size_t karn = karaoke - > syllables . size ( ) ;
for ( size_t i = 0 ; i < karn ; i + + ) {
curSyl = & karaoke - > syllables . at ( i ) ;
len = curSyl - > length * 10 ;
curpos = curSyl - > position * 10 ;
if ( len ! = - 1 ) {
pos = GetXAtMS ( curStartMS + len + curpos ) ;
if ( abs64 ( x - pos ) < 4 ) {
wxCursor cursor ( wxCURSOR_SIZEWE ) ;
SetCursor ( cursor ) ;
defCursor = false ;
if ( event . LeftIsDown ( ) ) {
hold = 4 ;
2006-08-28 00:29:14 +02:00
holdSyl = ( int ) i ;
2006-01-16 22:02:54 +01:00
gotGrab = true ;
}
break ;
}
}
}
}
// Dragging nothing, time from scratch
if ( ! gotGrab ) {
if ( event . ButtonIsDown ( wxMOUSE_BTN_LEFT ) ) {
hold = 3 ;
lastX = x ;
gotGrab = true ;
}
}
}
// Drag start/end
if ( hold ! = 0 ) {
// Dragging
if ( event . ButtonIsDown ( wxMOUSE_BTN_LEFT ) ) {
bool updated = false ;
// Drag from nothing
if ( hold = = 3 ) {
if ( ! karMode ) {
if ( x ! = lastX ) {
selStart = x ;
selEnd = x ;
curEndMS = GetMSAtX ( selEnd ) ;
curStartMS = GetMSAtX ( selStart ) ;
hold = 2 ;
}
}
}
// Drag start
if ( hold = = 1 ) {
// Set new value
if ( x ! = selStart ) {
selStart = x ;
if ( selStart > selEnd ) {
int temp = selStart ;
selStart = selEnd ;
selEnd = temp ;
hold = 2 ;
curEndMS = GetMSAtX ( selEnd ) ;
}
curStartMS = GetMSAtX ( selStart ) ;
updated = true ;
diagUpdated = true ;
}
}
// Drag end
if ( hold = = 2 ) {
// Set new value
if ( x ! = selEnd ) {
selEnd = x ;
if ( selStart > selEnd ) {
int temp = selStart ;
selStart = selEnd ;
selEnd = temp ;
hold = 1 ;
curStartMS = GetMSAtX ( selStart ) ;
}
curEndMS = GetMSAtX ( selEnd ) ;
updated = true ;
diagUpdated = true ;
}
}
// Drag karaoke
if ( hold = = 4 ) {
// Set new value
int curpos , len , pos , nkar ;
KaraokeSyllable * curSyl = NULL , * nextSyl = NULL ;
curSyl = & karaoke - > syllables . at ( holdSyl ) ;
2006-08-28 00:29:14 +02:00
nkar = ( int ) karaoke - > syllables . size ( ) ;
2006-01-16 22:02:54 +01:00
if ( holdSyl < nkar - 1 ) {
nextSyl = & karaoke - > syllables . at ( holdSyl + 1 ) ;
}
curpos = curSyl - > position ;
len = curSyl - > length ;
pos = GetXAtMS ( curStartMS + ( len + curpos ) * 10 ) ;
if ( x ! = pos ) {
// Calculate delta in centiseconds
int delta = ( ( __int64 ) ( x - pos ) * samples * 100 ) / provider - > GetSampleRate ( ) ;
// Apply delta
int deltaMode = 0 ;
if ( shiftDown ) deltaMode = 1 ;
// else if (ctrlDown) deltaMode = 2;
bool result = karaoke - > SyllableDelta ( holdSyl , delta , deltaMode ) ;
if ( result ) {
updated = true ;
diagUpdated = true ;
}
}
}
// Update stuff
if ( updated ) {
2006-02-25 08:41:18 +01:00
player - > SetEndPosition ( GetSampleAtX ( selEnd ) ) ;
2006-01-16 22:02:54 +01:00
wxCursor cursor ( wxCURSOR_SIZEWE ) ;
SetCursor ( cursor ) ;
UpdateImage ( true ) ;
}
}
// Release
else {
// Commit changes
if ( diagUpdated ) {
diagUpdated = false ;
NeedCommit = true ;
2006-02-02 19:24:58 +01:00
if ( Options . AsBool ( _T ( " Audio Autocommit " ) ) & & curStartMS < = curEndMS )
2006-01-16 22:02:54 +01:00
CommitChanges ( ) ;
2006-02-02 19:24:58 +01:00
else
2006-01-16 22:02:54 +01:00
UpdateImage ( true ) ;
}
// Single click on nothing
else if ( hold = = 3 ) {
// Select syllable
if ( karaoke - > enabled ) {
int syl = GetSyllableAtX ( x ) ;
if ( syl ! = - 1 ) {
karaoke - > SetSyllable ( syl ) ;
UpdateImage ( true ) ;
}
}
}
// Update stuff
SetCursor ( wxNullCursor ) ;
hold = 0 ;
}
}
}
else {
hold = 0 ;
}
}
// Restore cursor
if ( defCursor ) SetCursor ( wxNullCursor ) ;
}
//////////////
// Size event
void AudioDisplay : : OnSize ( wxSizeEvent & event ) {
// Set size
GetClientSize ( & w , & h ) ;
2006-03-06 01:45:24 +01:00
h - = 20 ;
2006-01-16 22:02:54 +01:00
// Update image
UpdateImage ( ) ;
// Update scrollbar
UpdateScrollbar ( ) ;
}
///////////////
// Timer event
void AudioDisplay : : OnUpdateTimer ( wxTimerEvent & event ) {
// Get lock and check if it's OK
2006-02-25 08:41:18 +01:00
if ( player - > GetMutex ( ) ) {
wxMutexLocker locker ( * player - > GetMutex ( ) ) ;
2006-02-25 07:04:46 +01:00
if ( ! locker . IsOk ( ) ) return ;
}
2006-02-25 08:41:18 +01:00
if ( ! player - > IsPlaying ( ) ) return ;
2006-01-16 22:02:54 +01:00
// Get DCs
//wxMutexGuiEnter();
wxClientDC dc ( this ) ;
dc . BeginDrawing ( ) ;
// Draw cursor
int curpos = - 1 ;
2006-02-25 08:41:18 +01:00
if ( player - > IsPlaying ( ) ) {
2006-03-06 00:01:02 +01:00
__int64 curPos = player - > GetCurrentPosition ( ) ;
if ( curPos > player - > GetStartPosition ( ) & & curPos < player - > GetEndPosition ( ) ) {
// Scroll if needed
int posX = GetXAtSample ( curPos ) ;
2006-03-06 00:41:00 +01:00
bool fullDraw = false ;
2006-03-20 22:48:01 +01:00
bool centerLock = false ;
bool scrollToCursor = Options . AsBool ( _T ( " Audio lock scroll on cursor " ) ) ;
2006-03-06 00:41:00 +01:00
if ( centerLock ) {
int goTo = MAX ( 0 , curPos - w * samples / 2 ) ;
if ( goTo > = 0 ) {
UpdatePosition ( goTo , true ) ;
UpdateImage ( ) ;
fullDraw = true ;
}
}
else {
2006-03-20 22:48:01 +01:00
if ( scrollToCursor ) {
if ( posX < 80 | | posX > w - 80 ) {
int goTo = MAX ( 0 , curPos - 80 * samples ) ;
if ( goTo > = 0 ) {
UpdatePosition ( goTo , true ) ;
UpdateImage ( ) ;
fullDraw = true ;
}
2006-03-06 00:41:00 +01:00
}
}
2006-03-06 00:01:02 +01:00
}
// Draw cursor
wxMemoryDC src ;
curpos = GetXAtSample ( curPos ) ;
2006-03-06 00:41:00 +01:00
dc . SetPen ( wxPen ( Options . AsColour ( _T ( " Audio Play cursor " ) ) ) ) ;
src . SelectObject ( * origImage ) ;
if ( fullDraw ) {
//dc.Blit(0,0,w,h,&src,0,0);
dc . DrawLine ( curpos , 0 , curpos , h ) ;
//dc.Blit(0,0,curpos-10,h,&src,0,0);
//dc.Blit(curpos+10,0,w-curpos-10,h,&src,curpos+10,0);
}
else {
dc . Blit ( oldCurPos , 0 , 1 , h , & src , oldCurPos , 0 ) ;
dc . DrawLine ( curpos , 0 , curpos , h ) ;
}
2006-01-16 22:02:54 +01:00
}
2006-03-06 00:01:02 +01:00
else {
if ( curPos > player - > GetEndPosition ( ) + 8192 ) {
player - > Stop ( ) ;
}
wxMemoryDC src ;
src . SelectObject ( * origImage ) ;
dc . Blit ( oldCurPos , 0 , 1 , h , & src , oldCurPos , 0 ) ;
2006-01-16 22:02:54 +01:00
}
}
2006-03-06 00:01:02 +01:00
// Restore background
else {
wxMemoryDC src ;
src . SelectObject ( * origImage ) ;
dc . Blit ( oldCurPos , 0 , 1 , h , & src , oldCurPos , 0 ) ;
}
2006-01-16 22:02:54 +01:00
oldCurPos = curpos ;
// Done
dc . EndDrawing ( ) ;
//wxMutexGuiLeave();
}
////////////
// Key down
void AudioDisplay : : OnKeyDown ( wxKeyEvent & event ) {
int key = event . GetKeyCode ( ) ;
Hotkeys . SetPressed ( key , event . m_controlDown , event . m_altDown , event . m_shiftDown ) ;
// Accept
if ( Hotkeys . IsPressed ( _T ( " Audio Commit " ) ) ) {
CommitChanges ( ) ;
ChangeLine ( 1 ) ;
}
// Accept (SSA's "Grab times")
if ( Hotkeys . IsPressed ( _T ( " Audio Commit Alt " ) ) ) {
CommitChanges ( ) ;
}
// Accept (stay)
if ( Hotkeys . IsPressed ( _T ( " Audio Commit (Stay) " ) ) ) {
CommitChanges ( ) ;
}
// Previous
if ( Hotkeys . IsPressed ( _T ( " Audio Prev Line " ) ) | | Hotkeys . IsPressed ( _T ( " Audio Prev Line Alt " ) ) ) {
Prev ( ) ;
}
// Next
if ( Hotkeys . IsPressed ( _T ( " Audio Next Line " ) ) | | Hotkeys . IsPressed ( _T ( " Audio Next Line Alt " ) ) ) {
Next ( ) ;
}
// Play
if ( Hotkeys . IsPressed ( _T ( " Audio Play " ) ) | | Hotkeys . IsPressed ( _T ( " Audio Play Alt " ) ) ) {
2006-02-25 08:41:18 +01:00
if ( player - > IsPlaying ( ) ) Stop ( ) ;
2006-01-16 22:02:54 +01:00
else {
int start = 0 , end = 0 ;
GetTimesSelection ( start , end ) ;
Play ( start , end ) ;
}
}
// Increase length
if ( Hotkeys . IsPressed ( _T ( " Audio Karaoke Increase Len " ) ) ) {
if ( karaoke - > enabled ) {
bool result = karaoke - > SyllableDelta ( karaoke - > curSyllable , 1 , 0 ) ;
if ( result ) diagUpdated = true ;
}
}
// Increase length (shift)
if ( Hotkeys . IsPressed ( _T ( " Audio Karaoke Increase Len Shift " ) ) ) {
if ( karaoke - > enabled ) {
bool result = karaoke - > SyllableDelta ( karaoke - > curSyllable , 1 , 1 ) ;
if ( result ) diagUpdated = true ;
}
}
// Decrease length
if ( Hotkeys . IsPressed ( _T ( " Audio Karaoke Decrease Len " ) ) ) {
if ( karaoke - > enabled ) {
bool result = karaoke - > SyllableDelta ( karaoke - > curSyllable , - 1 , 0 ) ;
if ( result ) diagUpdated = true ;
}
}
// Decrease length (shift)
if ( Hotkeys . IsPressed ( _T ( " Audio Karaoke Decrease Len Shift " ) ) ) {
if ( karaoke - > enabled ) {
bool result = karaoke - > SyllableDelta ( karaoke - > curSyllable , - 1 , 1 ) ;
if ( result ) diagUpdated = true ;
}
}
// Move backwards
if ( Hotkeys . IsPressed ( _T ( " Audio Scroll Left " ) ) ) {
UpdatePosition ( Position - 128 , false ) ;
UpdateImage ( ) ;
}
// Move forward
if ( Hotkeys . IsPressed ( _T ( " Audio Scroll Right " ) ) ) {
UpdatePosition ( Position + 128 , false ) ;
UpdateImage ( ) ;
}
// Play first 500 ms
if ( Hotkeys . IsPressed ( _T ( " Audio Play First 500ms " ) ) ) {
int start = 0 , end = 0 ;
GetTimesSelection ( start , end ) ;
int e = start + 500 ;
if ( e > end ) e = end ;
Play ( start , e ) ;
}
// Play last 500 ms
if ( Hotkeys . IsPressed ( _T ( " Audio Play Last 500ms " ) ) ) {
int start = 0 , end = 0 ;
GetTimesSelection ( start , end ) ;
int s = end - 500 ;
if ( s < start ) s = start ;
Play ( s , end ) ;
}
// Play 500 ms before
if ( Hotkeys . IsPressed ( _T ( " Audio Play 500ms Before " ) ) ) {
int start = 0 , end = 0 ;
GetTimesSelection ( start , end ) ;
Play ( start - 500 , start ) ;
}
// Play 500 ms after
if ( Hotkeys . IsPressed ( _T ( " Audio Play 500ms After " ) ) ) {
int start = 0 , end = 0 ;
GetTimesSelection ( start , end ) ;
Play ( end , end + 500 ) ;
}
2006-07-01 08:37:46 +02:00
// Play to end of file
if ( Hotkeys . IsPressed ( _T ( " Audio Play To End " ) ) ) {
int start = 0 , end = 0 ;
GetTimesSelection ( start , end ) ;
Play ( start , - 1 ) ;
}
2006-01-16 22:02:54 +01:00
// Play original line
if ( Hotkeys . IsPressed ( _T ( " Audio Play Original Line " ) ) ) {
int start = 0 , end = 0 ;
GetTimesDialogue ( start , end ) ;
if ( Options . AsBool ( _T ( " Audio SSA Mode " ) ) ) {
SetSelection ( start , end ) ;
}
Play ( start , end ) ;
}
// Lead in
if ( Hotkeys . IsPressed ( _T ( " Audio Add Lead In " ) ) ) {
AddLead ( true , false ) ;
}
// Lead out
if ( Hotkeys . IsPressed ( _T ( " Audio Add Lead Out " ) ) ) {
AddLead ( false , true ) ;
}
// Update
if ( diagUpdated ) {
diagUpdated = false ;
NeedCommit = true ;
2006-02-02 19:24:58 +01:00
if ( ( Options . AsBool ( _T ( " Audio SSA Allow Autocommit " ) ) | | Options . AsBool ( _T ( " Audio SSA Mode " ) ) = = false ) & & Options . AsBool ( _T ( " Audio Autocommit " ) ) & & curStartMS < = curEndMS )
2006-01-16 22:02:54 +01:00
CommitChanges ( ) ;
2006-02-02 19:24:58 +01:00
else
2006-01-16 22:02:54 +01:00
UpdateImage ( true ) ;
}
}
///////////////
// Change line
void AudioDisplay : : ChangeLine ( int delta ) {
if ( dialogue ) {
// Get next line number and make sure it's within bounds
int next = line_n + delta ;
2006-02-20 08:12:01 +01:00
if ( next = = - 1 ) next = 0 ;
if ( next = = grid - > GetRows ( ) ) next = grid - > GetRows ( ) - 1 ;
2006-01-16 22:02:54 +01:00
// Set stuff
NeedCommit = false ;
dialogue = NULL ;
grid - > editBox - > SetToLine ( next ) ;
grid - > SelectRow ( next ) ;
2006-12-18 21:13:23 +01:00
grid - > MakeCellVisible ( next , 0 , true ) ;
2006-02-20 08:12:01 +01:00
if ( ! dialogue ) UpdateImage ( true ) ;
else UpdateImage ( false ) ;
2006-01-16 22:02:54 +01:00
line_n = next ;
}
}
////////
// Next
void AudioDisplay : : Next ( ) {
// Karaoke
if ( karaoke - > enabled ) {
2006-02-20 08:12:01 +01:00
int nextSyl = karaoke - > curSyllable + 1 ;
bool needsUpdate = true ;
2006-01-16 22:02:54 +01:00
// Last syllable; jump to next
2006-02-20 08:12:01 +01:00
if ( nextSyl > = ( signed int ) karaoke - > syllables . size ( ) ) {
// Already last?
if ( line_n = = grid - > GetRows ( ) - 1 ) return ;
2006-01-16 22:02:54 +01:00
if ( NeedCommit ) {
int result = wxMessageBox ( _ ( " Do you want to commit your changes? If you choose No, they will be discarded. " ) , _ ( " Commit? " ) , wxYES_NO | wxCANCEL | wxICON_QUESTION ) ;
//int result = wxNO;
if ( result = = wxYES ) {
CommitChanges ( ) ;
}
else if ( result = = wxCANCEL ) {
2006-08-28 00:29:14 +02:00
karaoke - > curSyllable = ( int ) karaoke - > syllables . size ( ) - 1 ;
2006-01-16 22:02:54 +01:00
return ;
}
}
2006-02-20 08:12:01 +01:00
nextSyl = 0 ;
2006-01-16 22:02:54 +01:00
karaoke - > curSyllable = 0 ;
ChangeLine ( 1 ) ;
2006-02-20 08:12:01 +01:00
needsUpdate = false ;
2006-01-16 22:02:54 +01:00
}
// Set syllable
2006-02-20 08:12:01 +01:00
karaoke - > SetSyllable ( nextSyl ) ;
if ( needsUpdate ) Update ( ) ;
2006-01-16 22:02:54 +01:00
int start = 0 , end = 0 ;
GetTimesSelection ( start , end ) ;
Play ( start , end ) ;
}
// Plain mode
else {
ChangeLine ( 1 ) ;
}
}
////////////
// Previous
void AudioDisplay : : Prev ( ) {
// Karaoke
if ( karaoke - > enabled ) {
2006-02-20 08:12:01 +01:00
int nextSyl = karaoke - > curSyllable - 1 ;
bool needsUpdate = true ;
2006-01-16 22:02:54 +01:00
// First syllable; jump line
2006-02-20 08:12:01 +01:00
if ( nextSyl < 0 ) {
// Already first?
if ( line_n = = 0 ) return ;
2006-01-16 22:02:54 +01:00
if ( NeedCommit ) {
int result = wxMessageBox ( _ ( " Do you want to commit your changes? If you choose No, they will be discarded. " ) , _ ( " Commit? " ) , wxYES_NO | wxCANCEL ) ;
if ( result = = wxYES ) {
CommitChanges ( ) ;
}
else if ( result = = wxCANCEL ) {
2006-02-19 07:05:15 +01:00
karaoke - > curSyllable = 0 ;
2006-01-16 22:02:54 +01:00
return ;
}
}
2006-02-20 08:12:01 +01:00
karaoke - > curSyllable = - 1 ;
2006-01-16 22:02:54 +01:00
ChangeLine ( - 1 ) ;
2006-02-20 08:12:01 +01:00
needsUpdate = false ;
2006-01-16 22:02:54 +01:00
}
// Set syllable
2006-02-20 08:12:01 +01:00
karaoke - > SetSyllable ( nextSyl ) ;
if ( needsUpdate ) Update ( ) ;
2006-01-16 22:02:54 +01:00
int start = 0 , end = 0 ;
GetTimesSelection ( start , end ) ;
Play ( start , end ) ;
}
// Plain mode
else {
ChangeLine ( - 1 ) ;
}
}
///////////////////////////////
// Gets syllable at x position
int AudioDisplay : : GetSyllableAtX ( int x ) {
if ( ! karaoke - > enabled ) return - 1 ;
int ms = GetMSAtX ( x ) ;
size_t syllables = karaoke - > syllables . size ( ) ; ;
int sylstart , sylend ;
// Find a matching syllable
for ( size_t i = 0 ; i < syllables ; i + + ) {
sylstart = karaoke - > syllables . at ( i ) . position * 10 + curStartMS ;
sylend = karaoke - > syllables . at ( i ) . length * 10 + sylstart ;
if ( ms > = sylstart & & ms < sylend ) {
2006-08-28 00:29:14 +02:00
return ( int ) i ;
2006-01-16 22:02:54 +01:00
}
}
return - 1 ;
}
////////////////
// Focus events
void AudioDisplay : : OnGetFocus ( wxFocusEvent & event ) {
if ( ! hasFocus ) {
hasFocus = true ;
UpdateImage ( true ) ;
}
}
void AudioDisplay : : OnLoseFocus ( wxFocusEvent & event ) {
2006-03-16 00:53:44 +01:00
if ( hasFocus & & loaded ) {
2006-01-16 22:02:54 +01:00
hasFocus = false ;
UpdateImage ( true ) ;
Refresh ( false ) ;
}
}