📄 note.cpp
字号:
// Note.cpp: implementation of the Note class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "NokiaComposer.h"
#include "Note.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
IMPLEMENT_SERIAL(Note, CObject, SCHEMA_VERSION)
// +-------------------------------------------------------------
// |
// | Function : IsSeparator
// | Description :
// |
// | c :
// |
// +-------------------------------------------------------------
static bool IsSeparator(char c)
{
return c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == ',';
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::Note
// | Descripci髇 :
// |
// +-------------------------------------------------------------
Note::Note() :
tone_( ToneC ),
duration_( 8 ),
dot_( false ),
sharp_ ( false ),
octave_ (1)
{
AssertValid();
}
Note::Note(Tone tone, int duration, int octave, bool dot, bool sharp) :
tone_( tone ),
duration_( duration ),
dot_( dot ),
sharp_ ( sharp ),
octave_ ( octave )
{
AssertValid();
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note
// | Descripci髇 :
// |
// | other :
// |
// +-------------------------------------------------------------
Note::Note(const Note& other) :
tone_( other.tone_ ),
duration_( other.duration_ ),
dot_( other.dot_ ),
sharp_ ( other.sharp_ ),
octave_ ( other.octave_ )
{
AssertValid();
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::~Note
// | Descripci髇 :
// |
// +-------------------------------------------------------------
Note::~Note()
{
}
// +-------------------------------------------------------------
// |
// | Funci髇 : >>
// | Descripci髇 :
// |
// | ar :
// | &b :
// |
// +-------------------------------------------------------------
static CArchive& operator >>( CArchive& ar, bool &b )
{
int aux;
ar >> aux;
b = (aux != 0);
return ar;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : >>
// | Descripci髇 :
// |
// | ar :
// | &n :
// |
// +-------------------------------------------------------------
static CArchive& operator >>( CArchive& ar, Note::Tone &n )
{
int aux;
ar >> aux;
n = (Note::Tone) aux;
return ar;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::Serialize
// | Descripci髇 :
// |
// | &ar :
// |
// +-------------------------------------------------------------
void Note::Serialize(CArchive &ar)
{
if( ar.IsStoring() )
{
AssertValid();
ar << (int) dot_ ;
ar << duration_ ;
ar << octave_ ;
ar << sharp_ ;
ar << tone_ ;
}
else
{
ar >> dot_;
ar >> duration_ ;
ar >> octave_ ;
ar >> sharp_ ;
ar >> tone_ ;
AssertValid();
}
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::GetString
// | Descripci髇 :
// |
// +-------------------------------------------------------------
CString Note::GetString() const
{
AssertValid();
CString durationString;
CString toneString;
CString octaveString;
// duraci髇 (1,2,4,8,16,32)
durationString.Format("%d", duration_ );
// puntillo
if( dot_ )
durationString += ".";
// sostenido
if( sharp_ )
toneString += "#";
// nota (c,d,e,f,g,a,b)
switch( tone_ )
{
case Silence: toneString += "-"; break;
case ToneC: toneString += "c"; break;
case ToneD: toneString += "d"; break;
case ToneE: toneString += "e"; break;
case ToneF: toneString += "f"; break;
case ToneG: toneString += "g"; break;
case ToneA: toneString += "a"; break;
case ToneB: toneString += "b"; break;
}
if( tone_ != Silence )
{
// octava (1,2,3)
Assert( octave_ >= 1 && octave_ <= 3, "octava invalida");
octaveString.Format("%d", octave_ );
}
return durationString + toneString + octaveString;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::ParseString
// | Descripci髇 :
// |
// | string :
// |
// +-------------------------------------------------------------
const char* Note::ParseString(const char* string)
{
const int BUFSIZE = 100;
char buffer[BUFSIZE];
const char *p = string;
// ya no hay mas notas
if(*p == 0)
throw ParserException("no quedan notas", string);
// saltarse los espacios iniciales
while( IsSeparator(*p) )
p++;
// parse duration_
char *q = buffer;
while( isdigit( *p ) && (p - string) < BUFSIZE)
{
*q++ = *p++;
}
*q = 0;
duration_ = atoi( buffer );
if( duration_ == 0)
{
throw ParserException("duraci髇 inv醠ida", string);
}
sharp_ = false;
dot_ = false;
// has dot?
if( *p == '.' )
{
dot_ = true;
p++;
}
// is sharp?
if( *p == '#' )
{
sharp_ = true;
p++;
}
// get tone
switch( tolower(*p++) )
{
case 'c': tone_ = ToneC; break;
case 'd': tone_ = ToneD; break;
case 'e': tone_ = ToneE; break;
case 'f': tone_ = ToneF; break;
case 'g': tone_ = ToneG; break;
case 'a': tone_ = ToneA; break;
case 'b': tone_ = ToneB; break;
case '-':
case 'p': tone_ = Silence; break;
default:
throw ParserException( "nota invalida", string);
}
// is sharp?
if( *p == '#' )
{
sharp_ = true;
p++;
}
// get octave
if( tone_ != Silence )
{
if( ! isdigit( *p ))
throw ParserException("octava invalida", string);
octave_ = *p++ - '0';
}
// check if the new note is valid
const char* pError;
if(! IsValid(&pError) )
throw ParserException(pError, string);
// saltarse los espacios posteriores
if( ! IsSeparator(*p) && *p != 0 )
throw ParserException("no hay separaci髇 entre notas", string);
while( IsSeparator(*p) )
p++;
return p;
}
// +-------------------------------------------------------------
// |
// | Function : Note::GetMIDINote
// | Description :
// |
// | duration :
// | note :
// |
// +-------------------------------------------------------------
void Note::GetMIDINote(int& duration, int& note) const
{
AssertValid();
duration = 1024 / duration_;
note = 60 + ((octave_-1) * 12);
switch( tone_ )
{
case Silence: note = -1; break;
case ToneC: note += 0; break;
case ToneD: note += 2; break;
case ToneE: note += 4; break;
case ToneF: note += 5; break;
case ToneG: note += 7; break;
case ToneA: note += 9; break;
case ToneB: note += 11; break;
default:
Assert(0, "nota invalida");
}
if( sharp_ )
note += 1;
if( dot_ )
duration += duration / 2;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::AssertValid
// | Descripci髇 :
// |
// +-------------------------------------------------------------
void Note::AssertValid() const
{
const char* pError;
Assert( IsValid(&pError), (char*) pError);
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::CheckValid
// | Descripci髇 :
// |
// +-------------------------------------------------------------
bool Note::IsValid(const char** ppError) const
{
Assert( ppError != 0, "pError no puede ser nulo");
*ppError = 0;
// tone
if( tone_ < Silence || tone_ > ToneB)
{
*ppError = "invalid tone";
return false;
}
// duration
if( duration_ != 1 &&
duration_ != 2 &&
duration_ != 4 &&
duration_ != 8 &&
duration_ != 16 &&
duration_ != 32)
{
*ppError = "invalid duration";
return false;
}
// dot
if (dot_ && tone_ == Silence)
{
*ppError = "silences can not have dot";
return false;
}
// sharp
if( sharp_ && tone_ == Silence )
{
*ppError = "silences can not have sharp";
return false;
}
if( sharp_ && tone_ == ToneE)
{
*ppError = "Tone E can not have sharp";
return false;
}
if( sharp_ && tone_ == ToneB)
{
*ppError = "Tone B can not have sharp";
return false;
}
// octave
if( octave_ < 1 || octave_ > 3 )
{
*ppError = "invalid octave";
return false;
}
return true;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::OctaveUp
// | Descripci髇 :
// |
// +-------------------------------------------------------------
void Note::OctaveUp()
{
++octave_;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::OctaveDown
// | Descripci髇 :
// |
// +-------------------------------------------------------------
void Note::OctaveDown()
{
--octave_;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::SemitoneUp
// | Descripci髇 :
// |
// +-------------------------------------------------------------
void Note::SemitoneUp()
{
if( ! sharp_ )
{
sharp_ = true;
if( tone_ == Silence )
{
sharp_ = false;
}
else if( tone_ == ToneE )
{
tone_ = ToneF;
sharp_ = false;
}
else if( tone_ == ToneB )
{
tone_ = ToneC;
sharp_ = false;
++octave_;
}
}
else
{
sharp_ = false;
switch(tone_)
{
case ToneC: tone_ = ToneD; break;
case ToneD: tone_ = ToneE; break;
case ToneF: tone_ = ToneG; break;
case ToneG: tone_ = ToneA; break;
case ToneA: tone_ = ToneB; break;
default:
Assert(0, "invalid tone");
}
}
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::SemitoneDown
// | Descripci髇 :
// |
// +-------------------------------------------------------------
void Note::SemitoneDown()
{
if( sharp_ )
{
sharp_ = false;
}
else
{
switch(tone_)
{
case Silence: break;
case ToneC: tone_ = ToneB; --octave_; break;
case ToneD: tone_ = ToneC; sharp_ = true; break;
case ToneE: tone_ = ToneD; sharp_ = true; break;
case ToneF: tone_ = ToneE; break;
case ToneG: tone_ = ToneF; sharp_ = true; break;
case ToneA: tone_ = ToneG; sharp_ = true; break;
case ToneB: tone_ = ToneA; sharp_ = true; break;
default:
Assert(0, "invalid tone");
}
}
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::CanOctaveUp
// | Descripci髇 :
// |
// +-------------------------------------------------------------
bool Note::CanOctaveUp() const
{
return octave_ != 3;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::CanOctaveDown
// | Descripci髇 :
// |
// +-------------------------------------------------------------
bool Note::CanOctaveDown() const
{
return octave_ != 1;
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::CanSemitoneUp
// | Descripci髇 :
// |
// +-------------------------------------------------------------
bool Note::CanSemitoneUp() const
{
return (octave_ != 3 || tone_ != ToneB);
}
// +-------------------------------------------------------------
// |
// | Funci髇 : Note::CanSemitoneDown
// | Descripci髇 :
// |
// +-------------------------------------------------------------
bool Note::CanSemitoneDown() const
{
return (octave_ != 1 || tone_ != ToneC || sharp_ );
}
// +-------------------------------------------------------------
// |
// | Funci髇 : ParserException::ParserException
// | Descripci髇 :
// |
// | description :
// |
// +-------------------------------------------------------------
ParserException::ParserException( const char* description, const char* string ) :
description_(description)
{
nextNote_ = string;
// saltarse los espacios
while( IsSeparator(*nextNote_) && *nextNote_ != 0 )
++nextNote_;
// recuperar y saltarse la cadena de la nota erronea
while( ! IsSeparator(*nextNote_) && *nextNote_ != 0 )
noteString_ += *nextNote_++ ;
// nextNote_ se queda apuntando a la siguiente nota
}
// +-------------------------------------------------------------
// |
// | Funci髇 : ParserException::GetDescription
// | Descripci髇 :
// |
// +-------------------------------------------------------------
const CString& ParserException::GetDescription()
{
return description_;
}
// +-------------------------------------------------------------
// |
// | Function : ParserException::GetNoteString
// | Description :
// |
// +-------------------------------------------------------------
const CString& ParserException::GetNoteString()
{
return noteString_;
}
// +-------------------------------------------------------------
// |
// | Function : ParserException::GetNextNote
// | Description :
// |
// +-------------------------------------------------------------
const char* ParserException::GetNextNote()
{
return nextNote_;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -