mmsstv/ClockAdj.cpp
2013-07-05 15:15:14 -05:00

479 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//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();
}
//---------------------------------------------------------------------------