Update of /cvsroot/audacity/audacity-src/src
In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv6575
Added Files:
Tag: Audacity_UmixIt
Lyrics.cpp Lyrics.h LyricsWindow.cpp LyricsWindow.h
Log Message:
Lyrics Window
--- NEW FILE: LyricsWindow.h ---
/**********************************************************************
Audacity: A Digital Audio Editor
LyricsWindow.h
Vaughan Johnson
Dominic Mazzoni
**********************************************************************/
#ifndef __AUDACITY_LYRICS_WINDOW__
#define __AUDACITY_LYRICS_WINDOW__
#include <wx/frame.h>
class AudacityProject;
class Lyrics;
class LyricsWindow : public wxFrame {
public:
LyricsWindow(AudacityProject* parent);
~LyricsWindow();
Lyrics *GetLyricsPanel() {
return mLyricsPanel;
}
private:
void OnCloseWindow(wxCloseEvent & WXUNUSED(event));
//void OnFontSizeBtn(wxCommandEvent & event);
AudacityProject *mProject;
Lyrics *mLyricsPanel;
public:
DECLARE_EVENT_TABLE()
};
#endif
--- NEW FILE: Lyrics.h ---
/**********************************************************************
Audacity: A Digital Audio Editor
Lyrics.h
Dominic Mazzoni
**********************************************************************/
#ifndef __AUDACITY_LYRICS__
#define __AUDACITY_LYRICS__
#include "Audacity.h"
#include <wx/dynarray.h>
#include <wx/panel.h>
#define LYRICS_DEFAULT_WIDTH 440
#define LYRICS_DEFAULT_HEIGHT 330
class wxHtmlWindow;
struct Syllable {
double t;
wxString text;
wxString textWithSpace;
int char0;
int char1;
int width;
int leftX;
int x;
};
WX_DECLARE_OBJARRAY(Syllable, SyllableArray);
class Lyrics : public wxPanel
{
DECLARE_DYNAMIC_CLASS(Lyrics)
public:
Lyrics(wxWindow* parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
~Lyrics();
void Clear();
void Add(double t, wxString syllable);
void Finish(double finalT);
void Update(double t, bool bForce = false);
//
// Event handlers
//
void OnKeyEvent(wxKeyEvent & event);
void OnPaint(wxPaintEvent &evt);
void OnSize(wxSizeEvent &evt);
void OnMouse(wxMouseEvent &evt);
void HandlePaint(wxDC &dc);
void HandleLayout();
private:
void SetFont(wxDC *dc);
void Measure(wxDC *dc);
int FindSyllable(double t);
void GetKaraokePosition(double t,
int *outX, double *outY);
int mWidth;
int mHeight;
double mT;
int mKaraokeHeight;
int mCurrentSyllable;
SyllableArray mSyllables;
wxString mText;
int mTextHeight;
wxHtmlWindow *mHtml;
bool mMeasurementsDone;
DECLARE_EVENT_TABLE()
};
#endif // __AUDACITY_LYRICS__
// Indentation settings for Vim and Emacs.
// Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
//
--- NEW FILE: Lyrics.cpp ---
/**********************************************************************
Audacity: A Digital Audio Editor
Lyrics.cpp
Dominic Mazzoni
Vaughan Johnson
**********************************************************************/
#include <math.h>
#include <wx/defs.h>
#include <wx/dcmemory.h>
#include <wx/html/htmlwin.h>
#include "Lyrics.h"
#include "Project.h" // for GetActiveProject in OnKeyEvent
#include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(SyllableArray);
BEGIN_EVENT_TABLE(Lyrics, wxPanel)
EVT_CHAR(Lyrics::OnKeyEvent)
EVT_PAINT(Lyrics::OnPaint)
EVT_SIZE(Lyrics::OnSize)
END_EVENT_TABLE()
IMPLEMENT_CLASS(Lyrics, wxPanel)
Lyrics::Lyrics(wxWindow* parent, wxWindowID id,
const wxPoint& pos /*= wxDefaultPosition*/,
const wxSize& size /*= wxDefaultSize*/):
wxPanel(parent, id, pos, size),
mWidth(size.x), mHeight(size.y)
{
mHtml = new wxHtmlWindow(this, -1,
wxDefaultPosition, wxDefaultSize);
Clear();
Finish(0.0);
mT = 0.0;
}
Lyrics::~Lyrics()
{
}
void Lyrics::Clear()
{
mSyllables.Clear();
mText = "";
// Add two dummy syllables at the beginning
mSyllables.Add(Syllable());
mSyllables[0].t = -2.0;
mSyllables.Add(Syllable());
mSyllables[1].t = -1.0;
}
void Lyrics::Add(double t, wxString syllable)
{
int i = mSyllables.GetCount();
if (mSyllables[i-1].t == t) {
// We can't have two syllables with the same time, so append
// this to the end of the previous one if they're at the
// same time.
mSyllables[i-1].text += syllable;
mSyllables[i-1].textWithSpace += syllable;
mSyllables[i-1].char1 += syllable.Length();
return;
}
mSyllables.Add(Syllable());
mSyllables[i].t = t;
mSyllables[i].text = syllable;
// Put a space between syllables unless the previous one
// ended in a hyphen
if (i > 0 && mSyllables[i-1].text.Length() > 0 &&
mSyllables[i-1].text.Right(1)!="-") {
mSyllables[i].textWithSpace = " " + syllable;
mText += " ";
}
else {
mSyllables[i].textWithSpace = syllable;
}
mSyllables[i].char0 = mText.Length();
mText += syllable;
mSyllables[i].char1 = mText.Length();
}
void Lyrics::Finish(double finalT)
{
// Add two dummy syllables at the end
int i = mSyllables.GetCount();
mSyllables.Add(Syllable());
mSyllables[i].t = finalT + 1;
mSyllables.Add(Syllable());
mSyllables[i+1].t = finalT + 2;
mSyllables.Add(Syllable());
mSyllables[i+2].t = finalT + 3;
// Mark measurements as invalid
mMeasurementsDone = false;
mCurrentSyllable = 0;
}
#define DEFAULT_FONT_POINTSIZE 12
int gKaraokeFontPointSize = DEFAULT_FONT_POINTSIZE;
void Lyrics::SetFont(wxDC *dc)
{
dc->SetFont(wxFont(gKaraokeFontPointSize, wxSWISS, wxNORMAL, wxNORMAL));
}
void Lyrics::Measure(wxDC *dc)
{
SetFont(dc);
int width = 0, height = 0;
int x = 0;
unsigned int i;
for(i=0; i<mSyllables.GetCount(); i++) {
if (i < 2 || i >= mSyllables.GetCount()-2) {
dc->GetTextExtent("DUMMY", &width, &height); // Get the correct height
even if we're at i=0.
width = 0;
}
else {
dc->GetTextExtent(mSyllables[i].textWithSpace, &width, &height);
}
mSyllables[i].width = width + 30;
mSyllables[i].leftX = x;
mSyllables[i].x = x + width/2;
x += mSyllables[i].width;
}
mTextHeight = height;
mMeasurementsDone = true;
}
// Binary-search for the syllable with the largest time not greater than t
int Lyrics::FindSyllable(double t)
{
int i1, i2;
i1 = 0;
i2 = mSyllables.GetCount();
while (i2 > i1+1) {
int pmid = (i1+i2)/2;
if (mSyllables[pmid].t > t)
i2 = pmid;
else
i1 = pmid;
}
if (i1 < 2)
i1 = 2;
if (i1 > mSyllables.GetCount() - 3)
i1 = mSyllables.GetCount() - 3;
return i1;
}
// Given the current time t, returns the x/y position of the scrolling
// karaoke display. For some syllable i, when t==mSyllables[i].t,
// it will return mSyllables[i].x for outX and 0 for outY.
// In-between words, outX is interpolated using smooth acceleration
// between the two neighboring words, and y is a positive number indicating
// the bouncing ball height
void Lyrics::GetKaraokePosition(double t,
int *outX, double *outY)
{
*outX = 0;
*outY = 0;
if (t < mSyllables[2].t || t > mSyllables[mSyllables.GetCount()-3].t)
return;
int i0, i1, i2, i3;
int x0, x1, x2, x3;
double t0, t1, t2, t3;
i1 = FindSyllable(t);
i2 = i1 + 1;
// Because we've padded the syllables with two dummies at the beginning
// and end, we know that i0...i3 will always exist. Also, we've made
// sure that we don't ever have two of the same time, so t2>t1 strictly.
//
// t
// \/
// time: t0 t1 t2 t3
// pos: x0 x1 x2 x3
// index: i0 i1 i2 i3
// vel: vel1 vel2
i0 = i1 - 1;
i3 = i2 + 1;
x0 = mSyllables[i0].x;
x1 = mSyllables[i1].x;
x2 = mSyllables[i2].x;
x3 = mSyllables[i3].x;
t0 = mSyllables[i0].t;
t1 = mSyllables[i1].t;
t2 = mSyllables[i2].t;
t3 = mSyllables[i3].t;
double linear_vel0 = (x1 - x0) / (t1 - t0);
double linear_vel1 = (x2 - x1) / (t2 - t1);
double linear_vel2 = (x3 - x2) / (t3 - t2);
// average velocities
double v1 = (linear_vel0 + linear_vel1) / 2;
double v2 = (linear_vel1 + linear_vel2) / 2;
// Solve a cubic equation f(t) = at^3 + bt^2 + ct + d
// which gives the position x as a function of
// (t - t1), by constraining f(0), f'(0), f(t2-t1), f'(t2-t1)
double delta_t = t2 - t1;
double delta_x = x2 - x1;
v1 *= delta_t;
v2 *= delta_t;
double a = v1 + v2 - 2*delta_x;
double b = 3*delta_x - 2*v1 - v2;
double c = v1;
double d = x1;
t = (t - t1) / (t2 - t1);
double xx = a*t*t*t + b*t*t + c*t + d;
*outX = (int)xx;
// The y position is a simple cosine curve; the max height is a
// function of the time.
double height = t2 - t1 > 4.0? 1.0: sqrt((t2-t1)/4.0);
#ifdef _WIN32
#define M_PI 3.1415926535897932385
#endif
*outY = height * sin(M_PI * t);
}
void Lyrics::Update(double t, bool bForce /* = false */)
{
mT = t;
wxRect karaokeRect(0, 0, mWidth, mKaraokeHeight);
this->Refresh(false, &karaokeRect);
int i = FindSyllable(t);
if (!bForce && (i == mCurrentSyllable))
return;
wxString htmlText;
if (!bForce && (i < 0 || i >= mSyllables.GetCount()))
htmlText = mText;
else {
// Size the whole htmlText.
// Map nFontRelativeSize into -2 to +4, in increments of
DEFAULT_FONT_POINTSIZE/2
int nFontRelativeSize = (int)((float)(2 * gKaraokeFontPointSize) /
(float)DEFAULT_FONT_POINTSIZE);
nFontRelativeSize = ((nFontRelativeSize > 6) ? 6 : nFontRelativeSize) - 2;
wxString strFontRelativeSizeStart = "";
wxString strFontRelativeSizeEnd = "";
/* This works for <small>, but on Windows, the <big> acts like <small>!
So instead, use a relative size in a <font> tag.
switch (nFontRelativeSize) {
case -2: strFontRelativeSizeStart = "<small><small>";
strFontRelativeSizeEnd = "</small></small>"; break;
case -1: strFontRelativeSizeStart = "<small>";
strFontRelativeSizeEnd = "</small>"; break;
default:
strFontRelativeSizeStart = "";
strFontRelativeSizeEnd = "";
for (int i = 0; i < nFontRelativeSize; i++) {
strFontRelativeSizeStart += "<big>";
strFontRelativeSizeEnd += "</big>";
}
}
*/
if (nFontRelativeSize != 0) {
strFontRelativeSizeStart =
wxString::Format("<font size=\"%s%d\">", (nFontRelativeSize > 0) ?
"+" : "", nFontRelativeSize);
strFontRelativeSizeEnd = "</font>";
}
htmlText =
strFontRelativeSizeStart +
mText.Left(mSyllables[i].char0) +
"<font color=\"#ee0066\">" +
mText.Mid(mSyllables[i].char0,
mSyllables[i].char1-mSyllables[i].char0) +
"</font>" +
mText.Mid(mSyllables[i].char1) +
strFontRelativeSizeEnd;
}
htmlText.Replace("_", "<br>"); // Convert '_' to newline.
mHtml->SetPage(htmlText);
mHtml->Refresh(false);
mCurrentSyllable = i;
}
void Lyrics::OnKeyEvent(wxKeyEvent & event)
{
GetActiveProject()->HandleKeyDown(event);
}
void Lyrics::OnPaint(wxPaintEvent &evt)
{
wxPaintDC dc(this);
if (!mMeasurementsDone)
Measure(&dc);
#ifdef __WXMAC__
// Mac OS X automatically double-buffers the screen for you,
// so our bitmap is unneccessary
HandlePaint(dc);
#else
wxBitmap bitmap(mWidth, mKaraokeHeight);
wxMemoryDC memDC;
memDC.SelectObject(bitmap);
HandlePaint(memDC);
dc.Blit(0, 0, mWidth, mKaraokeHeight, &memDC, 0, 0, wxCOPY, FALSE);
#endif
}
void Lyrics::OnSize(wxSizeEvent &evt)
{
GetClientSize(&mWidth, &mHeight);
mKaraokeHeight = mHeight / 4;
mHtml->SetSize(0, mKaraokeHeight, mWidth, mHeight - mKaraokeHeight);
gKaraokeFontPointSize = (int)((float)(DEFAULT_FONT_POINTSIZE * mHeight) /
(float)LYRICS_DEFAULT_HEIGHT);
// Usually don't get the size window we want, usually less than
// LYRICS_DEFAULT_HEIGHT, so bump it a little.
gKaraokeFontPointSize += 2;
this->Update(mT, true);
wxPaintEvent ignore;
mMeasurementsDone = false;
this->OnPaint(ignore);
}
void Lyrics::HandlePaint(wxDC &dc)
{
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(0, 0, mWidth, mKaraokeHeight);
int ctr = mWidth / 2;
int x;
double y;
GetKaraokePosition(mT, &x, &y);
dc.SetTextForeground(wxColour(238, 0, 102));
bool changedColor = false;
SetFont(&dc);
unsigned int i;
wxCoord yTextTop = mKaraokeHeight - mTextHeight - 2;
for(i=0; i<mSyllables.GetCount(); i++) {
if (mSyllables[i].x + mSyllables[i].width < (x - ctr))
continue;
if (mSyllables[i].x > x + ctr)
continue;
if (!changedColor && mSyllables[i].x >= x) {
dc.SetTextForeground(*wxBLACK);
changedColor = true;
}
dc.DrawText(mSyllables[i].text,
mSyllables[i].leftX + ctr - x,
yTextTop);
}
int bounceTop = 10;
int bounceHeight = yTextTop - bounceTop;
int yi = (int)(yTextTop - 4 - (y * bounceHeight));
if (mT >= 0.0) {
int ballRadius = (int)(mTextHeight / 3.0);
wxRect ball(ctr - ballRadius, yi - ballRadius, 2 * ballRadius, 2 *
ballRadius);
dc.SetBrush(wxBrush(wxColour(238, 0, 102), wxSOLID));
dc.DrawEllipse(ball);
}
}
// Indentation settings for Vim and Emacs.
// Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
//
--- NEW FILE: LyricsWindow.cpp ---
/**********************************************************************
Audacity: A Digital Audio Editor
LyricsWindow.cpp
Vaughan Johnson
Dominic Mazzoni
**********************************************************************/
#include "LyricsWindow.h"
#include "Lyrics.h"
#include "Project.h"
//enum {
// LyricsWindowCtlID = 1000,
// FontSizeBtnID
//};
BEGIN_EVENT_TABLE(LyricsWindow, wxFrame)
EVT_CLOSE(LyricsWindow::OnCloseWindow)
//EVT_BUTTON(FontSizeBtnID, LyricsWindow::OnFontSizeBtn)
END_EVENT_TABLE()
const wxSize gSize = wxSize(LYRICS_DEFAULT_WIDTH, LYRICS_DEFAULT_HEIGHT);
LyricsWindow::LyricsWindow(AudacityProject *parent):
wxFrame(parent, -1, _("Audacity Lyrics"), wxDefaultPosition, gSize,
wxDEFAULT_FRAME_STYLE | ((parent == NULL) ? 0x0 :
wxFRAME_FLOAT_ON_PARENT))
{
mProject = parent;
mLyricsPanel = new Lyrics(this, -1, wxPoint(0, 0), gSize);
// loads either the XPM or the windows resource, depending on the platform
#if !defined(__WXMAC__) && !defined(__WXX11__)
#ifdef __WXMSW__
wxIcon ic(wxICON(AudacityLogo));
#else
wxIcon ic(wxICON(AudacityLogo48x48));
#endif
SetIcon(ic);
#endif
}
LyricsWindow::~LyricsWindow()
{}
void LyricsWindow::OnCloseWindow(wxCloseEvent & WXUNUSED(event))
{
this->Hide();
}
//void LyricsWindow::OnFontSizeBtn(wxCommandEvent & event)
//{
// // this->UpdateDisplay();
//}
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Audacity-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/audacity-cvs