am_imelody.cc
来自「Motorola synergy audio component」· CC 代码 · 共 983 行 · 第 1/2 页
CC
983 行
/* (c) Copyright Motorola 2001, All rights reserved.
Motorola Confidential Proprietary
Contains confidential proprietary information of Motorola, Inc.
Reverse engineering is prohibited.
The copyright notice does not imply publication.
DESCRIPTION:
This file contains all iMelody support in AM.
***************************** REVISION HISTORY ******************************
Date Author Reference Number
======== ======== ================
02-12-19 w13738 CR - LIBbb71564
Abnormal downloaded iMelody alert tone
Merge from T720
02-10-30 bof010 CR - LIBbb65108
Invalid format in stored melody (Port the fix from TALON)
02-20-02 w17860 CR - LIBbb18244
ATC - problems with playing tones created in Notes editor
Changed the second NextNonLfcrASCII function call in
ConvertNoteLength to take in ptr and not pitch.
01-03-18 ktang CR - CSGce90044
Implemented iMelody parsor
*/
/************** INCLUDES ******************************************************/
#include <SUAPI/suapi.h>
#include <audio/am_custom_tune.h>
#include <audio/AM_iMelody.H>
#include <string.h>
/************** LOCAL CONSTANTS ***********************************************/
/* The 8 values in the below array correpond to the indices to note types A, B, C,
E, F, G, and R in am_hw_phase_table defined in AM_HW_Primitive_Builder_tone.cc */
static const UINT8 PitchIndexTable[8] = {0, 2, 3, 5, 7, 8, 10, 12};
#define IMELODY_MAX_TEXT_LEN 75
const UINT8 IMELODY_MARKER_begin[] = "BEGIN:";
const UINT8 IMELODY_MARKER_version[] = "VERSION:";
const UINT8 IMELODY_MARKER_format[] = "FORMAT:";
const UINT8 IMELODY_MARKER_name[] = "NAME:";
const UINT8 IMELODY_MARKER_composer[] = "COMPOSER:";
const UINT8 IMELODY_MARKER_beat[] = "BEAT:";
const UINT8 IMELODY_MARKER_style[] = "STYLE:S";
const UINT8 IMELODY_MARKER_volume[] = "VOLUME:";
const UINT8 IMELODY_MARKER_melody[] = "MELODY:";
const UINT8 IMELODY_MARKER_end[] = "END:";
const UINT8 IMELODY_MARKER_endimelody[] = "END:IMELODY";
const UINT8 IMELODY_MARKER_default_header[] = \
"BEGIN:IMELODY\nVERSION:1.2\nFORMAT:CLASS1.0\n";
/************** GLOBAL DECLARATIONS ******************************************/
/************** FUNCTION DEFINITIONS ******************************************/
/* DESCRIPTION:
Constructor
INPUTS:
None
OUTPUTS:
None
IMPORTANT NOTES:
None
*/
AM_iMelody::AM_iMelody (void)
{
Reset();
octaveMethod = VERBOSE_OCTAVE;
}
AM_iMelody::AM_iMelody (IMELODY_OCTAVE_METHOD method)
{
Reset();
octaveMethod = method;
}
void
AM_iMelody::Reset()
{
head = NULL;
body = NULL;
tail = NULL;
wrt_ptr = NULL;
octave_ptr = NULL;
for (UINT8 i = 0; i < NUMBER_OF_FIELDS; i++)
{
TuneCharacters[i] = 0;
}
tuneDuration = 0;
}
/* DESCRIPTION:
Translates the user readable musical note stream to AM readable. The
AM readable format is specified in am_hw_primitive_builder_tone.h
INPUTS:
note_stream, pointer to the user readable musical note stream.
outputStream, pointer to the buffer where the parsed data is to be
written to.
outBuffByteSize, the byte length of the output buffer.
action, play the whole tune / the last note in the tune / or get the
duration of hte whole tune only.
OUTPUTS:
The duration of the whole tune in ms
IMPORTANT NOTES:
The input stream is assumed NULL terminated
*/
UINT8*
AM_iMelody::TuneTranslation (UINT8* inputStream, UINT8* outputStream,
UINT16 outBuffByteSize, AUD_CUSTOM_TYPE action)
{
UINT16 AM_note = AM_CUSTOM_INVALID_NOTE;
SetInput(inputStream);
SetOutput(outputStream, outBuffByteSize);
GetTuneInfoFromHeader(NULL);
/* The reason why to write a byte of UINT16 at a time is the passed in
buffer may start from an odd address */
while (tail > body)
{
if ((AM_note = NoteTranslation()) != AM_CUSTOM_INVALID_NOTE)
{
// The lower byte is duration field
UINT8 tmpDuration = (UINT8)(AM_note & 0x00FF);
*(--wrt_ptr) = tmpDuration;
/* Take the upper byte of UINT16 and write to the buffer; */
*(--wrt_ptr) = (UINT8)(AM_note >> 8);
TuneCharacters[NOTE_COUNT]++;
/* The time unit in am_hw_note_length_index_table is 125 us, shift it right by 3 for ms */
TuneCharacters[TUNE_DURATION] += AM_MUSIC_calc_DURATION(TuneCharacters[TEMPO], tmpDuration) >> 3;
if (action == PLAY_CUSTOM_NOTE)
{
/* this will terminate the backward note parsing */
tail = head;
}
}
}
if (TuneCharacters[NOTE_COUNT] == 0)
{
wrt_ptr = NULL;
}
return wrt_ptr;
}
/* DESCRIPTION:
Translates the user readable musical note to AM readable. The
AM readable format is specified in am_hw_primitive_builder_tone.h
INPUTS:
None
OUTPUTS:
The AM readable musical note
IMPORTANT NOTES:
None
*/
UINT16
AM_iMelody::NoteTranslation()
{
UINT8* pitch_ptr = tail;
UINT8* tmp_ptr;
UINT8 pitch;
UINT8 octave;
UINT16 note_len;
UINT16 AM_note = AM_CUSTOM_INVALID_NOTE;
/* Search backwards to look for the next pitch in the stream. */
do
{
--pitch_ptr;
}
while (!IsAPitch(*pitch_ptr) && pitch_ptr > body);
/* if there is such a note to be translated... */
if (IsAPitch(*pitch_ptr))
{
/* if no valid note length, i.e. > 0xff, skip the possible note */
if ((note_len = ConvertNoteLength(pitch_ptr)) < 0x100)
{
octave = GetOctave(pitch_ptr);
/* pass in the pitch field and modifier to get modified pitch */
/* octave is passed in since it may need to be changed too */
pitch = ConvertPitch(pitch_ptr, octave);
/* Due to the hardware frequency range constraint, only octaves */
/* 2 - 6 are returned. map 2 and 7 to 2; */
/* 3 and 8 to 3; */
/* 4 to 4; */
/* 0 and 5 to 5; and */
/* 1 and 6 to 6. */
octave = ((octave+3) % 5) + 2;
/* puts in the octave field */
AM_note = (((octave << NOTE_DEF_OCTAVE_SHIFT)
| (pitch << NOTE_DEF_PITCH_SHIFT)) << 8) +
note_len;
}
}
tail = pitch_ptr;
return AM_note;
}
/* DESCRIPTION:
Compares character
INPUTS:
a, character 1
b, character 2
OUTPUTS:
FALSE is equal, TRUE is not, follow C string lib convension
IMPORTANT NOTES:
If both values passed in are with the range of ASCII
'a' - 'z' or 'A' - 'Z', diff them case-insensitively
*/
BOOL
AM_iMelody::DiffInsensitive (UINT8 a, UINT8 b)
{
UINT8 a_other_case = a;
// if a is an upper case letter
// its lower case will be a_other_case
if ((a >= 'A') && (a <= 'Z'))
{
a_other_case += 0x20;
}
// if a is an low case letter
// its upper case will be a_other_case
else if ((a >= 'a') && (a <= 'z'))
{
a_other_case -= 0x20;
}
return ((a != b) && (a_other_case != b));
}
/* DESCRIPTION:
Searches the given field in the string within the range from start to
end (which points to the first uninterested character)
case insensitive.
INPUTS:
start, pointer to the begginning of the string to be searched
field, a supposedly shorter string to be looked for in another
string pointed by start.
end, pointer to the end of the string to be searched
OUTPUTS:
Pointer to the charater next to the found field string. If field string
is not found, it points to the same position end does.
IMPORTANT NOTES:
None
*/
UINT8*
AM_iMelody::SearchField(UINT8* start, const UINT8 field[], UINT8* end)
{
UINT8* ptr = start;
UINT8 upper_case = 0;
UINT8 lower_case = 0;
UINT8 indx = 0;
/* search until either of the strings is exhausted */
while ((field[indx] != NULL) && (ptr < end))
{
/* need to find the possible beginning of the field */
if (indx == 0)
{
/* find the firt character in the string */
while ((ptr < end) && DiffInsensitive(field[0], *ptr))
{
ptr++;
}
if (ptr < end)
{
ptr++;
indx++;
}
}
/* need to match the rest of the charaters. If any one is unmatched,
we need to go back to beginning of the 'field' research */
else if (DiffInsensitive(field[indx], *ptr))
{
ptr -= (indx - 1);
indx = 0;
}
/* if everything else */
else
{
indx++;
/* increment by 1, but make sure the next character */
/* is not LF or CR */
if ((ptr = NextNonLfcrASCII(end, ptr, 1)) == NULL)
{
ptr = end;
}
}
}
/* Upon exit from the while loop, ptr points to either start[indx], i.e.
the character in the searched string that is next to pattern 'field'
just found; or *end, i.e. the end of the searched string*/
return ptr;
}
/* DESCRIPTION:
Converts note length from iMeldoy defined values to AM defined.
INPUTS:
duration, iMeldoy defined duration value
modifier, iMeldoy defined duration modifier
OUTPUTS:
AM defined duration value
IMPORTANT NOTES:
In case of syntax error, a quarter is taken as default.
*/
UINT16
AM_iMelody::ConvertNoteLength (UINT8* pitch)
{
UINT16 NoteLen = 0xffff;
UINT8* ptr = NextNonLfcrASCII(tail, pitch, 1);
if (ptr != NULL)
{
if (*ptr >= '0' && *ptr <= '5')
{
NoteLen = *ptr - '0';
}
else if (*ptr == NULL)
{
NoteLen = 2;
}
}
if (NoteLen != 0xffff)
{
// convert from iMelody values to AM values, that
// musically is of the same duration.
NoteLen = 64 >> NoteLen;
ptr = NextNonLfcrASCII(tail, ptr, 1);
if (ptr != NULL)
{
switch (*ptr)
{
// dotted note, plus 1/2 of its length
case '.': NoteLen += NoteLen >> 1; break;
// double dotted note, plus 3/4 of its length
case ':': NoteLen += (NoteLen * 3) >> 2; break;
// plus 2/3 of its length
case ';': NoteLen += (NoteLen << 1) / 3; break;
default: break;
}
}
}
// convert to 0 based
return (NoteLen - 1);
}
/* DESCRIPTION:
Converts the iMelody defined pitch to AM octave value
INPUTS:
pitch, 'a', 'b', 'c', 'd', 'e', 'f', 'g', and 'r'
octave, reference to the octave
OUTPUTS:
AM pitch value
IMPORTANT NOTES:
The lowest pitch in the same ocatve is C, so octaves will need to be
incremented by 1 when *2#B (which is really *3C)i fhte octave to be
incremented is not already the highest; and decremented by 1 when
*2&C (which is really *1B) if octave to be decremented is not
already the lowest.
*/
UINT8
AM_iMelody::ConvertPitch (UINT8* pitch_ptr, UINT8& octave)
{
UINT8 modifier = 0;
UINT8 pitch = *pitch_ptr;
UINT8* ptr = NextNonLfcrASCII(body, pitch_ptr, -1);
if (ptr != NULL)
{
modifier = *ptr;
}
if (pitch == 'r')
{
// make all rest notes' octave 0's.
octave = 0;
pitch = 'h';
// sharp or flat rests are still rests
modifier = 0;
}
pitch = PitchIndexTable[pitch - 'a'];
switch (modifier)
{
case SHARP:
pitch = (pitch + 1) % NUMBER_OF_PITCHES;
/* SHARP B is equavilent to C (index == 3) of one octave higher */
/* increment octave only if it is not already the highest */
if (pitch == 3 && octave < HIGHEST_OCTAVE)
{
octave++;
}
break;
case FLAT:
pitch = (pitch + NUMBER_OF_PITCHES - 1) % NUMBER_OF_PITCHES;
/* FLAT C is equavilent to B (index == 2) of one octave lower */
/* decrement octave only if it is not already the lowest */
if (pitch == 2 && octave > LOWEST_OCTAVE)
{
octave--;
}
break;
}
return pitch;
}
/* DESCRIPTION:
Converts the iMelody defined octave to AM octave value, in verbose method
INPUTS:
pitch, pointer to the found pitch
OUTPUTS:
returns a pionter to the octave if found; NULL otherwise;
IMPORTANT NOTES:
None
*/
UINT8*
AM_iMelody::GetVerboseOctave(UINT8* pitch)
{
UINT8* ptr2;
UINT8* ptr = NextNonLfcrASCII(body, pitch, -1);
/* search up one more if this is pitch modifier */
if (ptr != NULL && (*ptr == SHARP || *ptr == FLAT))
{
ptr = NextNonLfcrASCII(body, ptr, -1);
}
/* if this is not within the octave range, it's garbage */
if (ptr != NULL && *ptr < LOWEST_OCTAVE && *ptr > HIGHEST_OCTAVE)
{
ptr = NULL;
}
/* if the next character is not octave marker, the */
/* one we are looking at is not a valid octave */
if (ptr != NULL &&
((ptr2 = NextNonLfcrASCII(body, ptr, -1)) == NULL ||
*ptr2 != OCTAVE_MARKER))
{
ptr = NULL;
}
return ptr;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?