mmsstv/ClockAdj.cpp

479 lines
14 KiB
C++
Raw Permalink Normal View History

2013-07-05 22:15:14 +02:00
//Copyright+LGPL
//-----------------------------------------------------------------------------------------------------------------------------------------------
// Copyright 2000-2013 Makoto Mori, Nobuyuki Oba
//-----------------------------------------------------------------------------------------------------------------------------------------------
// This file is part of MMSSTV.
// MMSSTV is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
// MMSSTV is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License along with MMTTY. If not, see
// <http://www.gnu.org/licenses/>.
//-----------------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "ClockAdj.h"
#include "Main.h"
//---------------------------------------------------------------------
#pragma resource "*.dfm"
//TClockAdjDlg *ClockAdjDlg;
static int s_Gain = 0x0108;
//---------------------------------------------------------------------
__fastcall TClockAdjDlg::TClockAdjDlg(TComponent* AOwner)
: TForm(AOwner)
{
FormStyle = ((TForm *)AOwner)->FormStyle;
Font->Name = ((TForm *)AOwner)->Font->Name;
Font->Charset = ((TForm *)AOwner)->Font->Charset;
EntryAlignControl();
pBitmap = new Graphics::TBitmap();
if( sys.m_Palette ) pBitmap->PixelFormat = pf16bit;
pBitmap->Width = PaintBox->Width;
pBitmap->Height = PaintBox->Height;
pDem = NULL;
pTick = NULL;
m_agcMax = 8192;
m_agcMin = 0;
m_agcSumMax = 8192 * AGCAVG;
m_Point = 0;
m_Samp = 11025;
m_rBase = 0;
m_MaxP = 0;
m_MaxD = 0;
}
//---------------------------------------------------------------------
__fastcall TClockAdjDlg::~TClockAdjDlg()
{
if( pTick != NULL ){
delete pTick;
pTick = NULL;
}
pDem = NULL;
pBitmap->Palette = NULL;
delete pBitmap;
pBitmap = NULL;
}
//---------------------------------------------------------------------------
// <20>T<EFBFBD>C<EFBFBD>Y<EFBFBD>ύX<CF8D>R<EFBFBD><52><EFBFBD>g<EFBFBD><67><EFBFBD>[<5B><><EFBFBD>̓o<CC93>^
void __fastcall TClockAdjDlg::EntryAlignControl(void)
{
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = ClientWidth-1;
rc.bottom = ClientHeight-1;
AlignList.EntryControl(OKBtn, &rc, OKBtn->Font);
AlignList.EntryControl(CancelBtn, &rc, CancelBtn->Font);
AlignList.EntryControl(Panel, &rc, NULL);
AlignList.EntryControl(TBGAIN, &rc, NULL);
AlignList.EntryControl(SBAGC, &rc, SBAGC->Font);
AlignList.EntryControl(MarkFreq, &rc, MarkFreq->Font);
AlignList.EntryControl(UDMark, &rc, NULL);
AlignList.EntryControl(Label2, &rc, Label2->Font);
AlignList.EntryControl(LPPM, &rc, LPPM->Font);
AlignList.EntryControl(EditClock, &rc, EditClock->Font);
AlignList.EntryControl(UDSamp, &rc, NULL);
AlignList.EntryControl(Label1, &rc, Label1->Font);
// int CX = ::GetSystemMetrics(SM_CXFULLSCREEN);
// int CY = ::GetSystemMetrics(SM_CYFULLSCREEN);
int CX = ::GetSystemMetrics(SM_CXSCREEN);
int CY = ::GetSystemMetrics(SM_CYSCREEN);
if( (CX < Width)||(CY < Height) ){
Top = 0;
Left = 0;
Width = CX;
Height = CY;
}
#if 0
else {
Top = 0;
Left = 0;
Width = 600;
Height = 400;
}
#endif
FormCenter(this, CX, CY);
if( Owner != NULL ){
WindowState = ((TForm *)Owner)->WindowState;
}
m_rBase = 0;
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::FormResize(TObject *Sender)
{
CWaitCursor tw;
AlignList.NewAlign(this);
if( pBitmap != NULL ){
delete pBitmap;
}
pBitmap = new Graphics::TBitmap();
if( sys.m_Palette ) pBitmap->PixelFormat = pf16bit;
pBitmap->Width = PaintBox->Width;
pBitmap->Height = PaintBox->Height;
TRect rc;
int XL = 0;
int XR = pBitmap->Width - 1;
int YT = 0;
int YB = pBitmap->Height - 1;
rc.Left = XL;
rc.Right = XR;
rc.Top = YT;
rc.Bottom = YB+1;
TCanvas *cp = pBitmap->Canvas;
cp->Brush->Color = clBlack;
cp->FillRect(rc);
m_CursorX = XR - 20;
cp->Font->Name = Font->Name;
cp->Font->Charset = Font->Charset;
cp->Font->Color = clWhite;
cp->Font->Size = 10;
int FH = cp->TextHeight("A");
int Y = 5;
if( MsgEng ){
Caption = "Calibrating the Sound Card with a Time Standard Broadcast Station";
// "Adjust Sampling Frequency using an off-air time signal";
// Caption = "Adjust Sampling freq. (Recive WWV tick sound on Mark freq.)";
CancelBtn->Caption = "Cancel";
cp->TextOut(10, Y, "1) Receive standard radio wave (e.g., WWV, BPM)."); Y+=FH;
cp->TextOut(10, Y, "2) Tune into the tick sound."); Y+=FH;
cp->TextOut(10, Y, "3) Continue listening to the sound for a while. You have a vertical line."); Y+=FH;
cp->TextOut(10, Y, "4) Click the lower point of the line."); Y+=FH;
cp->TextOut(10, Y, "5) Click the upper point of the line."); Y+=FH;
Y+=FH;
cp->TextOut(10, Y, "You could use FAX broadcasting instead of WWV or JJY, but be sure it has"); Y+=FH;
cp->TextOut(10, Y, "exact timing.");
}
else {
cp->TextOut(10, Y, "1.BPM<50><4D>AM<41>܂<EFBFBD><DC82><EFBFBD>SSB<53>Ŏ<EFBFBD><C58E>M<EFBFBD><4D><EFBFBD>A<EFBFBD><41><EFBFBD>̉<EFBFBD><CC89>ʂ̉<CA82><CC89>ɂ<EFBFBD><C982><EFBFBD>Tone<6E><65>1000Hz<48>܂<EFBFBD><DC82><EFBFBD>"); Y+=FH;
cp->TextOut(10, Y, " 1600Hz<48><7A><EFBFBD>ݒ肵<DD92>܂<EFBFBD>."); Y+=FH;
cp->TextOut(10, Y, "2.SSB<53>̏ꍇ<CC8F>͂P<CD82>b<EFBFBD>`<60>b<EFBFBD>N<EFBFBD><4E><EFBFBD><EFBFBD>Tone<6E>ɏd<C98F>Ȃ<EFBFBD><C882><EFBFBD>Ɏ<EFBFBD><C98E>M<EFBFBD><4D><EFBFBD>g<EFBFBD><67><EFBFBD>𒲐<EFBFBD><F092B290><EFBFBD><EFBFBD>܂<EFBFBD>."); Y+=FH;
cp->TextOut(10, Y, "3.<2E><><EFBFBD>΂炭<CE82><E782AD><EFBFBD>M<EFBFBD><4D><EFBFBD>ďc<C48F>܂<EFBFBD><DC82>͎΂߂̑ѐ<CC91><D190><EFBFBD><EFBFBD>\<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><EFBFBD>҂<EFBFBD><EFBFBD>܂<EFBFBD><EFBFBD>i<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j."); Y+=FH;
cp->TextOut(10, Y, "4.<2E>\<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѐ<EFBFBD><EFBFBD>̉<EFBFBD><EFBFBD>̒[<5B>_<EFBFBD><5F><EFBFBD>N<EFBFBD><4E><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>܂<EFBFBD>."); Y+=FH;
cp->TextOut(10, Y, "5.<2E>X<EFBFBD>ɓ<EFBFBD><C993><EFBFBD><EFBFBD>ѐ<EFBFBD><D190>̏<EFBFBD><CC8F>̒[<5B>_<EFBFBD><5F><EFBFBD>N<EFBFBD><4E><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD><EFBFBD><EFBFBD>ƃN<C683><4E><EFBFBD>b<EFBFBD>N<EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I<EFBFBD><49>"); Y+=FH;
cp->TextOut(10, Y, " <20>ݒ肳<DD92><E882B3><EFBFBD>܂<EFBFBD>.<2E>i2<69>_<EFBFBD>Ԃ̋<D482><CC8B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ق<EFBFBD><D982><EFBFBD><EFBFBD><EFBFBD><EFBFBD>m<EFBFBD>ł<EFBFBD><C582>j"); Y+=FH;
cp->TextOut(10, Y, "<EFBFBD>X<EFBFBD>΂<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɑ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><EFBFBD><EFBFBD>L<EFBFBD>̎葱<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>x<EFBFBD>J<EFBFBD><EFBFBD><EFBFBD>Ԃ<EFBFBD><EFBFBD>ĉ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>."); Y+=FH+FH;
cp->TextOut(10, Y, "BPM<EFBFBD>̑<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɁAJMH,JMG<4D>Ȃǂ<C882>FAX<41><58><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0.5<EFBFBD>b<EFBFBD><EFBFBD><EFBFBD>̃f<EFBFBD>b<EFBFBD>h<EFBFBD>Z<EFBFBD>N<EFBFBD>^<5E>𗘗p<F0979897><70><EFBFBD>Ă<EFBFBD>"); Y+=FH;
cp->TextOut(10, Y, "OK<EFBFBD>̂悤<EFBFBD>ł<EFBFBD>."); Y+=FH;
cp->TextOut(10, Y, "<EFBFBD><EFBFBD><EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>b<EFBFBD>N - <20><><EFBFBD><EFBFBD><EFBFBD>̊J<CC8A>n"); Y+=FH;
cp->TextOut(10, Y, "<EFBFBD>E<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>b<EFBFBD>N - <20><><EFBFBD><EFBFBD><EFBFBD>J<EFBFBD>[<5B>\<EFBFBD><EFBFBD><EFBFBD>ړ<EFBFBD>");
}
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::UpdateTB(void)
{
TBGAIN->Enabled = !SBAGC->Down;
LG->Font->Color = SBAGC->Down ? clGrayText : clBlack;
}
//---------------------------------------------------------------------
void __fastcall TClockAdjDlg::UpdatePPM(void)
{
double dd = ((m_Samp - SampBase) * 1000000.0 / SampBase);
char bf[64];
sprintf(bf, "%d ppm", int(dd+0.5));
LPPM->Caption = bf;
}
//---------------------------------------------------------------------
int __fastcall TClockAdjDlg::Execute(TSound *p, double &Samp)
{
pSound = p;
pDem = &p->SSTVDEM;
pTick = new CTICK;
pDem->pTick = pTick;
m_Samp = Samp;
pTick->m_Samp = int(Samp+0.5);
InitColorTable(clBlack, clWhite);
char bf[128];
sprintf(bf, "%.2lf", m_Samp);
EditClock->Text = bf;
pTick->Init();
pDem->m_Tick = 1;
m_DisEvent++;
UDMark->Position = 1000;
pDem->SetTickFreq(1000);
TBGAIN->Position = s_Gain & 0x00ff;
SBAGC->Down = s_Gain & 0xff00 ? 1 : 0;
UpdateTB();
m_DisEvent--;
UpdatePPM();
Mmsstv->PBoxG->Invalidate();
int r = ShowModal();
pDem->m_Tick = 0;
pDem->pTick = NULL;
InitColorTable(sys.m_ColorLow, sys.m_ColorHigh);
s_Gain = (s_Gain & 0x00ff) | (SBAGC->Down ? 0x0100 : 0);
delete pTick;
pTick = NULL;
pDem->SetTickFreq(0);
Mmsstv->PBoxG->Invalidate();
if( r == IDOK ){
Samp = m_Samp;
return TRUE;
}
else {
return FALSE;
}
}
//---------------------------------------------------------------------
void __fastcall TClockAdjDlg::TimerTimer(TObject *Sender)
{
if( pBitmap == NULL ) return;
if( pDem == NULL ) return;
if( pTick == NULL ) return;
int *p = pTick->GetData();
if( p == NULL ) return;
TCanvas *tp = pBitmap->Canvas;
int mx = -MAXINT;
int mi = MAXINT;
int x, xx, d;
double k1 = 16384.0/double(m_agcMax - m_agcMin);
double k2;
if( SBAGC->Down ){
k2 = 128.0 / 16384.0;
}
else {
k2 = (128.0 * (s_Gain & 0x00ff)) / (4096 * 16);
}
int ax = -1;
for( xx = 0; xx < pTick->m_Samp; xx++ ){
int xv = xx + m_rBase;
x = fmod(xv, m_Samp);
x = x * pBitmap->Width / m_Samp;
if( ax != x ){
ax = x;
if( !x ){
if( m_MaxD ){
tp->Pixels[m_MaxP][0] = clRed;
}
m_MaxD = 0;
m_MaxP = 0;
TRect rc;
rc.Left = 0;
rc.Right = pBitmap->Width - 1;
rc.Top = 0;
rc.Bottom = pBitmap->Height - 2;
TRect src(rc);
src.Bottom--;
rc.Top++;
tp->CopyRect(rc, tp, src);
}
d = p[xx];
if( m_MaxD < d ){
m_MaxD = d;
m_MaxP = x;
}
if( mx < d ) mx = d;
if( mi > d ) mi = d;
if( SBAGC->Down ){
d -= m_agcMin;
if( m_agcMax > 0 ) d = double(d) * k1;
}
d = double(d) * k2;
if( d >= 128 ) d = 127;
if( d <= 0 ) d = 0;
tp->Pixels[x][0] = TColor(ColorTable[127-d]);
}
}
m_rBase += pTick->m_Samp;
#if 0
for( x = 0; x < XR; x++){
xx = (x * pTick->m_Samp)/pBitmap->Width;
d = p[xx];
if( mx < d ) mx = d;
if( mi > d ) mi = d;
if( SBAGC->Down ){
d -= m_agcMin;
if( m_agcMax > 0 ) d = double(d) * k1;
}
d = double(d) * k2;
if( d >= 128 ) d = 127;
if( d <= 0 ) d = 0;
tp->Pixels[x][0] = TColor(ColorTable[127-d]);
}
#endif
m_agcSumMax -= m_agcMax;
m_agcSumMax += mx;
if( m_agcSumMax < (4096*AGCAVG) ) m_agcSumMax = (4096*AGCAVG);
m_agcMax = m_agcSumMax / AGCAVG;
m_agcMin = mi;
if( m_agcMin > 2048 ) m_agcMin = 2048;
m_PointY++;
PaintBox->Canvas->Draw(0, 0, (TGraphic*)pBitmap);
PaintCursor();
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::DrawMessage(LPCSTR p)
{
int xr = PaintBox->Canvas->TextWidth(p);
int xl = (PaintBox->Width - xr)/2;
xr += xl;
int FH = PaintBox->Canvas->TextHeight(p);
int VC = PaintBox->Height - FH;
PaintBox->Canvas->Pen->Color = clWhite;
PaintBox->Canvas->Brush->Color = clBlack;
PaintBox->Canvas->RoundRect(xl-10, VC-FH, xr+10, VC+FH, 10, 10);
PaintBox->Canvas->Font->Color = clWhite;
PaintBox->Canvas->TextOut(xl, VC-FH/2, p);
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::PaintCursor(void)
{
PaintBox->Canvas->Pen->Color = clLime;
PaintBox->Canvas->Pen->Style = psDot;
PaintBox->Canvas->MoveTo(m_CursorX, 0);
int rop = ::SetROP2(PaintBox->Canvas->Handle, R2_MASKPENNOT);
PaintBox->Canvas->LineTo(m_CursorX, pBitmap->Height - 1);
::SetROP2(PaintBox->Canvas->Handle, rop);
if( m_Point ){
PaintBox->Canvas->Pen->Color = clYellow;
PaintBox->Canvas->Pen->Style = psSolid;
PaintBox->Canvas->MoveTo(m_PointX, m_PointY);
::SetROP2(PaintBox->Canvas->Handle, R2_MASKPENNOT);
PaintBox->Canvas->LineTo(m_PointX2, m_PointY2);
::SetROP2(PaintBox->Canvas->Handle, rop);
char bf[256];
if( MsgEng ){
sprintf( bf, "OK : Left button, Cancel : Right button Clock=%.2lf", GetPointSamp());
}
else {
sprintf( bf, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD> : <20><><EFBFBD>{<7B>^<5E><>, <20><><EFBFBD>~ : <20>E<EFBFBD>{<7B>^<5E><> Clock=%.2lf", GetPointSamp());
}
DrawMessage(bf);
if( PaintBox->Cursor != crCross ) PaintBox->Cursor = crCross;
}
else {
if( PaintBox->Cursor != crDefault ) PaintBox->Cursor = crDefault;
}
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::PaintBoxPaint(TObject *Sender)
{
PaintBox->Canvas->Draw(0, 0, (TGraphic*)pBitmap);
PaintCursor();
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::PaintBoxMouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if( Button == mbLeft ){
if( m_Point ){
m_Point = 0;
if( m_PointY2 != m_PointY ){
m_Samp = GetPointSamp();
ModalResult = mrOk;
}
}
else {
m_PointX2 = m_PointX = X;
m_PointY2 = m_PointY = Y;
m_Point = 1;
}
}
else if( m_Point ){
m_Point = 0;
}
else {
m_CursorX = X;
}
PaintBox->Canvas->Draw(0, 0, (TGraphic*)pBitmap);
PaintCursor();
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::MarkFreqChange(TObject *Sender)
{
if( m_DisEvent ) return;
int dd;
if( sscanf(AnsiString(MarkFreq->Text).c_str(), "%lu", &dd ) == 1){ //ja7ude 0428
if( (dd >= 300) && (dd <= 2700) ){
m_DisEvent++;
UDMark->Position = SHORT(dd);
pDem->SetTickFreq(dd);
Mmsstv->PBoxG->Invalidate();
m_DisEvent--;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::TBGAINChange(TObject *Sender)
{
s_Gain = (s_Gain & 0xff00) | TBGAIN->Position;
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::UDMarkClick(TObject *Sender, TUDBtnType Button)
{
if( m_DisEvent ) return;
pDem->SetTickFreq(UDMark->Position);
Mmsstv->PBoxG->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::SBAGCClick(TObject *Sender)
{
UpdateTB();
}
//---------------------------------------------------------------------------
double __fastcall TClockAdjDlg::GetPointSamp(void)
{
if( m_PointY == m_PointY2 ) return m_Samp;
double d = (m_PointX2 - m_PointX);
d = d * m_Samp / pBitmap->Width;
d /= (m_PointY - m_PointY2);
d += m_Samp;
d = NormalSampFreq(d, 100);
return d;
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::PaintBoxMouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
if( m_Point ){
m_PointX2 = X;
m_PointY2 = Y;
PaintBox->Canvas->Draw(0, 0, (TGraphic*)pBitmap);
PaintCursor();
}
}
//---------------------------------------------------------------------------
void __fastcall TClockAdjDlg::UDSampClick(TObject *Sender,
TUDBtnType Button)
{
if( Button == btNext ){
m_Samp += 0.02;
}
else {
m_Samp -= 0.02;
}
m_Samp = NormalSampFreq(m_Samp, 50);
m_rBase += (1.0 - (m_Samp / pTick->m_Samp)) * pTick->m_Samp;
char bf[128];
sprintf(bf, "%.2lf", m_Samp);
EditClock->Text = bf;
UpdatePPM();
}
//---------------------------------------------------------------------------