X-Git-Url: http://git.jankratochvil.net/?p=gnokii.git;a=blobdiff_plain;f=common%2Fgsm-ringtones.c;fp=common%2Fgsm-ringtones.c;h=aa68378ed8a23e485946ea5593e75456f3d3169a;hp=f99883efd256e1dd28e7010ae7c660b12dd1221f;hb=a2dfc99dc499ea8600bf5178f8122125d7d7d557;hpb=1fdb423c0a2e33c1282bec25de66d9f40d56999b diff --git a/common/gsm-ringtones.c b/common/gsm-ringtones.c index f99883e..aa68378 100644 --- a/common/gsm-ringtones.c +++ b/common/gsm-ringtones.c @@ -1,620 +1,1023 @@ /* - $Id$ - G N O K I I A Linux/Unix toolset and driver for Nokia mobile phones. - Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml. - Released under the terms of the GNU GPL, see file COPYING for more details. This file provides support for ringtones. - $Log$ - Revision 1.1.1.1 2001/11/25 21:59:00 short - :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001 - - Revision 1.3 2001/11/08 16:34:19 pkot - Updates to work with new libsms - - Revision 1.2 2001/09/20 21:46:21 pkot - Locale cleanups (Pawel Kot) +*/ +#ifdef WIN32 + #include + #include "misc_win32.h" +#else + #include +#endif -*/ +#include "gsm-api.h" -#include "gsm-ringtones.h" -#include "misc.h" +GSM_Ringtone SMringtone; +GSM_BinRingtone ringtone; /* Beats-per-Minute Encoding */ int BeatsPerMinute[] = { - 25, - 28, - 31, - 35, - 40, - 45, - 50, - 56, - 63, - 70, - 80, - 90, - 100, - 112, - 125, - 140, - 160, - 180, - 200, - 225, - 250, - 285, - 320, - 355, - 400, - 450, - 500, - 565, - 635, - 715, - 800, - 900 + 25, 28, 31, 35, 40, 45, 50, 56, 63, 70, + 80, 90, 100, 112, 125, 140, 160, 180, 200, 225, + 250, 285, 320, 355, 400, 450, 500, 565, 635, 715, + 800, 900 +}; + +struct OneRingtone RingingTones[] = { + {"",0,0}, +/* 1 */ {"Uploaded #1",0,0}, /* 2 */ {"Ring ring",0,0}, +/* 3 */ {"Low",0,0}, /* 4 */ {"Fly",0,0}, +/* 5 */ {"Mosquito",0,0}, /* 6 */ {"Bee",0,0}, +/* 7 */ {"Intro",0,0}, /* 8 */ {"Etude",0,0}, +/* 9 */ {"Hunt",0,0}, /* 10 */ {"Going up",0,0}, +/* 11 */ {"City bird",0,0}, /* 12 */ {"Chase",0,0}, +/* 13 */ {"Scifi",0,0}, /* 14 */ {"Kick",0,0}, +/* 15 */ {"Do-mi-so",0,0}, /* 16 */ {"Robo N1X",0,0}, +/* 17 */ {"Dizzy",0,0}, /* 18 */ {"Playground",0,0}, +/* 19 */ {"That's it!",0,0}, /* 20 */ {"Grande valse",0,0}, +/* 21 */ {"Knock knock",0,0}, /* 22 */ {"Knock again",0,0}, +/* 23 */ {"Helan",0,0}, /* 24 */ {"Fuga",0,0}, +/* 25 */ {"Menuet",0,0}, /* 26 */ {"Ode to Joy",0,0}, +/* 27 */ {"Elise",0,0}, /* 28 */ {"Mozart 40",0,0}, +/* 29 */ {"Piano Concerto",0,0},/* 30 */ {"William Tell",0,0}, +/* 31 */ {"Badinerie",0,0}, /* 32 */ {"Polka",0,0}, +/* 33 */ {"Attraction",0,0}, /* 34 */ {"Polite",0,0}, +/* 35 */ {"Persuasion",0,0}, /* 36 */ {"Tick tick",0,0}, +/* 37 */ {"Samba",0,0}, /* 38 */ {"Orient",0,0}, +/* 39 */ {"Charleston",0,0}, /* 40 */ {"Songette",0,0}, +/* 41 */ {"Jumping",0,0}, /* 42 */ {"Lamb",0,0}, +/* 43 */ {"Marry",0,0}, /* 44 */ {"Tango",0,0}, +/* 45 */ {"Tangoed",0,0}, /* 46 */ {"Down",0,0}, +/* 47 */ {"Polska",0,0}, /* 48 */ {"WalzeBrilliant",0,0}, +/* 49 */ {"Cicada",0,0}, /* 50 */ {"Trio",0,0}, +/* 51 */ {"Circles",0,0}, /* 52 */ {"Nokia tune",0,0}, +/* 53 */ {"Sunny walks",0,0}, /* 54 */ {"Basic rock",0,0}, +/* 55 */ {"Reveille",0,0}, /* 56 */ {"Groovy Blue",0,0}, +/* 57 */ {"Brave Scotland",0,0},/* 58 */ {"Matilda",0,0}, +/* 59 */ {"Bumblebee",0,0}, /* 60 */ {"Hungarian",0,0}, +/* 61 */ {"Valkyrie",0,0}, /* 62 */ {"Bach #3",0,0}, +/* 63 */ {"Toreador",0,0}, /* 64 */ {"9th Symphony",0,0}, +/* 65 */ {"Uploaded #2",0,0}, /* 66 */ {"Uploaded #3",0,0}, +/* 67 */ {"Uploaded #4",0,0}, /* 68 */ {"Uploaded #5",0,0}, + {"",0,0} }; int OctetAlign(unsigned char *Dest, int CurrentBit) { - int i=0; + int i=0; - while((CurrentBit+i)%8) { - ClearBit(Dest, CurrentBit+i); - i++; - } + while((CurrentBit+i)%8) { + ClearBit(Dest, CurrentBit+i); + i++; + } - return CurrentBit+i; + return CurrentBit+i; } int OctetAlignNumber(int CurrentBit) { - int i=0; + int i=0; - while((CurrentBit+i)%8) { - i++; - } + while((CurrentBit+i)%8) { i++; } - return CurrentBit+i; + return CurrentBit+i; } int BitPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits) { - int i; - for (i=0; i is always - octet-aligned. */ - StartBit=OctetAlign(package, StartBit); - - StartBit=BitPackByte(package, StartBit, Sound, 7); - StartBit=BitPackByte(package, StartBit, BasicSongType, 3); - - /* Packing the name of the tune. */ - StartBit=BitPackByte(package, StartBit, strlen(ringtone->name)<<4, 4); - StartBit=BitPack(package, StartBit, ringtone->name, 8*strlen(ringtone->name)); - - /* Info about song pattern */ - StartBit=BitPackByte(package, StartBit, 0x01, 8); /* One song pattern */ - StartBit=BitPackByte(package, StartBit, PatternHeaderId, 3); - StartBit=BitPackByte(package, StartBit, A_part, 2); - StartBit=BitPackByte(package, StartBit, 0, 4); /* No loop value */ - - /* Info, how long is contents for SMS */ - HowLong=30+8*strlen(ringtone->name)+17+8+8+13; + int StartBit=0; + unsigned char CommandLength = 0x02; + unsigned char spec; + int oldscale=10, newscale=0, oldstyle=0, oldtempo=0; + int HowMany=0; /* How many instructions packed */ + int HowLong=0; /* How many bits packed */ + int StartNote=0, EndNote=0; /* First and last packed note from ringtone */ + + /* Default ringtone parameters */ + u8 DefNoteScale=2, DefNoteDuration=4; + int DefNoteTempo=63; + u8 DefNoteStyle=NaturalStyle; + + int buffer[6]; /* Used to find default ringtone parameters */ + int i,j,k=0,thisnote,thisnotelong; - /* Calculate the number of instructions in the tune. - Each Note contains Note and (sometimes) Scale. - Default Tempo and Style are instructions too. */ - HowMany=2; /* Default Tempo and Style */ - - for(i=0; iNrNotes; i++) { - - /* PC Composer 2.0.010 doesn't like, when we start ringtone from pause: - it displays that the format is invalid and - hangs, when you move mouse over place, where pause is */ - if (GSM_GetNote(ringtone->notes[i].note)==Note_Pause && oldscale==10) { - StartNote++; - } else { + /* Find the most frequently used duration and use this for the default */ + for (i=0;i<6;i++) buffer[i]=0; + for (i=0;iNrNotes;i++) { + switch (ringtone->notes[i].duration) { + case 192: buffer[0]++; break; + case 128: buffer[0]++; break; + case 96: buffer[1]++; break; + case 64: buffer[1]++; break; + case 48: buffer[2]++; break; + case 32: buffer[2]++; break; + case 24: buffer[3]++; break; + case 16: buffer[3]++; break; + case 12: buffer[4]++; break; + case 8: buffer[4]++; break; + case 6: buffer[5]++; break; + case 4: buffer[5]++; break; + } + } + + /* Now find the most frequently used */ + j=0; + for (i=0;i<6;i++) { + if (buffer[i]>j) { + k=i; + j=buffer[i]; + } + } + + /* Finally convert the default duration */ + switch (k) { + case 0: DefNoteDuration=128; break; + case 1: DefNoteDuration= 64; break; + case 2: DefNoteDuration= 32; break; + case 3: DefNoteDuration= 16; break; + case 4: DefNoteDuration= 8; break; + case 5: DefNoteDuration= 4; break; + default: DefNoteDuration= 16; break; + } + + /* Find the most frequently used scale and use this for the default */ + for (i=0;i<6;i++) buffer[i]=0; + for (i=0;iNrNotes;i++) { + if (ringtone->notes[i].note!=255) { + buffer[ringtone->notes[i].note/14]++; + } + } + j=0; + for (i=0;i<6;i++) { + if (buffer[i]>j) { + DefNoteScale=i; + j=buffer[i]; + } + } + + StartBit=BitPackByte(package, StartBit, CommandLength, 8); + StartBit=BitPackByte(package, StartBit, RingingToneProgramming, 7); + + /* The page 3-23 of the specs says that is always + octet-aligned. */ + StartBit=OctetAlign(package, StartBit); + + StartBit=BitPackByte(package, StartBit, Sound, 7); + StartBit=BitPackByte(package, StartBit, BasicSongType, 3); + + /* Set special chars in ringtone name */ + for (i=0;iname);i++) { + if (ringtone->name[i]=='~') ringtone->name[i]=1; //enables/disables blinking + if (ringtone->name[i]=='`') ringtone->name[i]=0; //hides rest ot contents + } + + /* Packing the name of the tune. */ + StartBit=BitPackByte(package, StartBit, strlen(ringtone->name)<<4, 4); + StartBit=BitPack(package, StartBit, ringtone->name, 8*strlen(ringtone->name)); + + /* Set special chars in ringtone name */ + for (i=0;iname);i++) { + if (ringtone->name[i]==1) ringtone->name[i]='~'; //enables/disables blinking + if (ringtone->name[i]==0) ringtone->name[i]='`'; //hides rest ot contents + } + + /* Info about song pattern */ + StartBit=BitPackByte(package, StartBit, 0x01, 8); /* One song pattern */ + StartBit=BitPackByte(package, StartBit, PatternHeaderId, 3); + StartBit=BitPackByte(package, StartBit, A_part, 2); + StartBit=BitPackByte(package, StartBit, ringtone->Loop<<4, 4); + + /* Info, how long is contents for SMS */ + HowLong=8+8+7+3+4+8*strlen(ringtone->name)+8+3+2+4+8+3+2+3+5; + + /* Calculating number of instructions in the tune. + Each Note contains Note and (sometimes) Scale. + Default Tempo and Style are instructions too. */ + HowMany=2; /* Default Tempo and Style */ + + /* Default style and tempo */ + DefNoteStyle=ringtone->notes[0].style; + DefNoteTempo=ringtone->notes[0].tempo; + oldstyle=DefNoteStyle; + oldtempo=DefNoteTempo; + + for(i=0; iNrNotes; i++) { + + /* PC Composer 2.0.010 doesn't like, when we start ringtone from pause: + displays, that format is invalid and + hangs, when you move mouse over place, where pause is */ + if (GSM_GetNote(ringtone->notes[i].note)==Note_Pause && oldscale==10) { + StartNote++; + } else { + + thisnote=0; + thisnotelong=0; + + /* we don't write Scale/Style info before "Pause" note - it saves place */ + if (GSM_GetNote(ringtone->notes[i].note)!=Note_Pause) { + + if (ringtone->allnotesscale || + oldscale!=(newscale=GSM_GetScale(ringtone->notes[i].note))) { + + /* We calculate, if we have space to add next scale instruction */ + if (((OctetAlignNumber(HowLong+5)+8)/8)<=(*maxlength)) { + oldscale=newscale; + HowLong+=5; + HowMany++; + thisnote++; + thisnotelong+=5; + } else { + break; + } + } + if (ringtone->notes[i].style!=oldstyle) { + /* We calculate, if we have space to add next style instruction */ + if (((OctetAlignNumber(HowLong+5)+8)/8)<=(*maxlength)) { + oldstyle=ringtone->notes[i].style; + HowLong+=5; + HowMany++; + thisnote++; + thisnotelong+=5; + } else { + HowLong=HowLong-thisnotelong; + HowMany=HowMany-thisnote; + break; + } + } + } - /* we don't write Scale info before "Pause" note - it saves space */ - if (GSM_GetNote(ringtone->notes[i].note)!=Note_Pause && - oldscale!=(newscale=GSM_GetScale(ringtone->notes[i].note))) { - - /* We calculate, if we have space to add next scale instruction */ - if (((HowLong+5)/8)<=(*maxlength-1)) { - oldscale=newscale; - HowMany++; - HowLong+=5; - } else { - break; - } - } + if (ringtone->notes[i].tempo!=oldtempo) { + /* We calculate, if we have space to add next tempo instruction */ + if (((OctetAlignNumber(HowLong+8)+8)/8)<=(*maxlength)) { + oldtempo=ringtone->notes[i].tempo; + HowLong+=8; + HowMany++; + thisnote++; + thisnotelong+=8; + } else { + HowLong=HowLong-thisnotelong; + HowMany=HowMany-thisnote; + break; + } + } - /* We calculate, if we have space to add next note instruction */ - if (((HowLong+12)/8)<=(*maxlength-1)) { - HowMany++; - EndNote++; - HowLong+=12; - } else { - break; - } - } - - /* If we are sure, we pack it for SMS or setting to phone, not for OTT file */ - if (*maxlength<1000) { - /* Pc Composer gives this as the phone limitation */ - if ((EndNote-StartNote)==GSM_MAX_RINGTONE_NOTES-1) break; - } - } - - StartBit=BitPackByte(package, StartBit, HowMany, 8); - - /* Style */ - StartBit=BitPackByte(package, StartBit, StyleInstructionId, 3); - StartBit=BitPackByte(package, StartBit, ContinuousStyle, 2); - - /* Beats per minute/tempo of the tune */ - StartBit=BitPackByte(package, StartBit, TempoInstructionId, 3); - StartBit=BitPackByte(package, StartBit, GetTempo(ringtone->tempo), 5); + /* We calculate, if we have space to add next note instruction */ + if (((OctetAlignNumber(HowLong+12)+8)/8)<=(*maxlength)) { + HowMany++; + EndNote++; + HowLong+=12; + } else { + HowLong=HowLong-thisnotelong; + HowMany=HowMany-thisnote; + break; + } + } + + /* We are sure, we pack it for SMS or setting to phone, not for OTT file */ + if (*maxlength<1000) { + /* Like Pc Composer say - before of phone limitations...*/ + if ((EndNote-StartNote)==FB61_MAX_RINGTONE_NOTES-1) break; + } + } + + StartBit=BitPackByte(package, StartBit, HowMany, 8); +#ifdef DEBUG +// fprintf(stdout,_("length of new pattern: %i %i\n"),HowMany,StartBit); +#endif + + /* Style */ + StartBit=BitPackByte(package, StartBit, StyleInstructionId, 3); + StartBit=BitPackByte(package, StartBit, DefNoteStyle, 2); + + /* Beats per minute/tempo of the tune */ + StartBit=BitPackByte(package, StartBit, TempoInstructionId, 3); + StartBit=BitPackByte(package, StartBit, GSM_GetTempo(DefNoteTempo), 5); +#ifdef DEBUG +// fprintf(stdout,_("def temp: %i %i\n"),GSM_GetTempo(DefNoteTempo),StartBit); +#endif + + /* Default scale */ + oldscale=10; + + /* Default style */ + oldstyle=DefNoteStyle; + + /* Default tempo */ + oldtempo=DefNoteTempo; + + /* Notes packing */ + for(i=StartNote; i<(EndNote+StartNote); i++) { + + /* we don't write Scale info before "Pause" note - it saves place */ + if (GSM_GetNote(ringtone->notes[i].note)!=Note_Pause) { + if (ringtone->allnotesscale || + oldscale!=(newscale=GSM_GetScale(ringtone->notes[i].note))) { +#ifdef DEBUG +// fprintf(stdout,_("Scale\n")); +#endif + oldscale=newscale; + StartBit=BitPackByte(package, StartBit, ScaleInstructionId, 3); + StartBit=BitPackByte(package, StartBit, GSM_GetScale(ringtone->notes[i].note), 2); + } + if (ringtone->notes[i].style!=oldstyle) { + /* Style */ + StartBit=BitPackByte(package, StartBit, StyleInstructionId, 3); + StartBit=BitPackByte(package, StartBit, ringtone->notes[i].style, 2); + oldstyle=ringtone->notes[i].style; + } + } + + if (ringtone->notes[i].tempo!=oldtempo) { + /* Beats per minute/tempo of the tune */ + StartBit=BitPackByte(package, StartBit, TempoInstructionId, 3); + StartBit=BitPackByte(package, StartBit, GSM_GetTempo(ringtone->notes[i].tempo), 5); + oldtempo=ringtone->notes[i].tempo; + } + + /* Note */ + StartBit=BitPackByte(package, StartBit, NoteInstructionId, 3); + StartBit=BitPackByte(package, StartBit, GSM_GetNote(ringtone->notes[i].note), 4); + StartBit=BitPackByte(package, StartBit, GSM_GetDuration(ringtone->notes[i].duration,&spec), 3); + StartBit=BitPackByte(package, StartBit, spec, 2); - /* Default scale */ - oldscale=10; +#ifdef DEBUG +// fprintf(stdout,_("note(%i): %i, scale: %i, duration: %i, spec: %i\n"),i,ringtone->notes[i].note,GSM_GetScale(ringtone->notes[i].note),GSM_GetDuration(ringtone->notes[i].duration,&spec),spec); +#endif - /* Notes packing */ - for(i=StartNote; i<(EndNote+StartNote); i++) { - - /* we don't write Scale info before "Pause" note - it saves place */ - if (GSM_GetNote(ringtone->notes[i].note)!=Note_Pause && - oldscale!=(newscale=GSM_GetScale(ringtone->notes[i].note))) { - oldscale=newscale; - StartBit=BitPackByte(package, StartBit, ScaleInstructionId, 3); - StartBit=BitPackByte(package, StartBit, GSM_GetScale(ringtone->notes[i].note), 2); - } - - /* Note */ - StartBit=BitPackByte(package, StartBit, NoteInstructionId, 3); - StartBit=BitPackByte(package, StartBit, GSM_GetNote(ringtone->notes[i].note), 4); - StartBit=BitPackByte(package, StartBit, GSM_GetDuration(ringtone->notes[i].duration,&spec), 3); - StartBit=BitPackByte(package, StartBit, spec, 2); - } + } - StartBit=OctetAlign(package, StartBit); + StartBit=OctetAlign(package, StartBit); - StartBit=BitPackByte(package, StartBit, CommandEnd, 8); + StartBit=BitPackByte(package, StartBit, CommandEnd, 8); - if (StartBit!=OctetAlignNumber(HowLong)) - dprintf("Error in PackRingtone - StartBit different to HowLong %d - %d)\n", StartBit,OctetAlignNumber(HowLong)); +#ifdef DEBUG + if (StartBit!=OctetAlignNumber(HowLong)+8) + fprintf(stdout,_("Error in PackRingtone - StartBit different to HowLong %d - %d)\n"),StartBit,OctetAlignNumber(HowLong)+8); +#endif - *maxlength=StartBit/8; + *maxlength=StartBit/8; - return(EndNote+StartNote); + return(EndNote+StartNote); } - int BitUnPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits) { - int i; + int i; - for (i=0; iallnotesscale=false; + + StartBit=BitUnPackInt(package,StartBit,&l,8); +#ifdef DEBUG + if (l!=0x02) + fprintf(stdout,_("Not header\n")); +#endif + if (l!=0x02) return GE_SUBFORMATNOTSUPPORTED; + + StartBit=BitUnPackInt(package,StartBit,&l,7); +#ifdef DEBUG + if (l!=RingingToneProgramming) + fprintf(stdout,_("Not RingingToneProgramming\n")); +#endif + if (l!=RingingToneProgramming) return GE_SUBFORMATNOTSUPPORTED; + + /* The page 3-23 of the specs says that is always + octet-aligned. */ + StartBit=OctetUnAlign(StartBit); + + StartBit=BitUnPackInt(package,StartBit,&l,7); +#ifdef DEBUG + if (l!=Sound) + fprintf(stdout,_("Not Sound\n")); +#endif + if (l!=Sound) return GE_SUBFORMATNOTSUPPORTED; + + StartBit=BitUnPackInt(package,StartBit,&l,3); +#ifdef DEBUG + if (l!=BasicSongType) + fprintf(stdout,_("Not BasicSongType\n")); +#endif + if (l!=BasicSongType) return GE_SUBFORMATNOTSUPPORTED; + + /* Getting length of the tune name */ + StartBit=BitUnPackInt(package,StartBit,&l,4); + l=l>>4; +#ifdef DEBUG +// fprintf(stdout,_("Length of name: %i\n"),l); +#endif + + /* Unpacking the name of the tune. */ + StartBit=BitUnPack(package, StartBit, ringtone->name, 8*l); + ringtone->name[l]=0; + + /* Set special chars in ringtone name */ + for (i=0;iname);i++) { + if (ringtone->name[i]==1) ringtone->name[i]='~'; //enables/disables blinking + if (ringtone->name[i]==0) ringtone->name[i]='`'; //hides rest ot contents + } + +#ifdef DEBUG +// fprintf(stdout,_("Name: %s\n"),ringtone->name); +#endif + + StartBit=BitUnPackInt(package,StartBit,&l,8); +#ifdef DEBUG +// fprintf(stdout,_("Number of song patterns: %i\n"),l); +#endif + if (l!=1) return GE_SUBFORMATNOTSUPPORTED; //we support only one song pattern + + StartBit=BitUnPackInt(package,StartBit,&l,3); +#ifdef DEBUG + if (l!=PatternHeaderId) + fprintf(stdout,_("Not PatternHeaderId\n")); +#endif + if (l!=PatternHeaderId) return GE_SUBFORMATNOTSUPPORTED; + + StartBit+=2; //Pattern ID - we ignore it + + StartBit=BitUnPackInt(package,StartBit,&l,4); + l=l>>4; +#ifdef DEBUG + fprintf(stdout,_("Loop value: %i\n"),l); +#endif + ringtone->Loop=l; + + HowMany=0; + StartBit=BitUnPackInt(package, StartBit, &HowMany, 8); +#ifdef DEBUG + fprintf(stdout,_("length of new pattern: %i %i\n"),HowMany,StartBit); +#endif + + ringtone->NrNotes=0; -/* The page 3-23 of the specs says that is always - octet-aligned. */ - StartBit = OctetUnAlign(StartBit); - - StartBit = BitUnPackInt(package, StartBit, &l, 7); - if (l != Sound) { - dprintf("Not Sound\n"); - return GE_SUBFORMATNOTSUPPORTED; + for (i=0;i>6); +#endif + switch (l) { + case StaccatoStyle : DefNoteStyle=StaccatoStyle; break; + case ContinuousStyle: DefNoteStyle=ContinuousStyle; break; + case NaturalStyle : DefNoteStyle=NaturalStyle; break; } + break; + case TempoInstructionId: + StartBit=BitUnPackInt(package,StartBit,&l,5); + l=l>>3; + DefNoteTempo=BeatsPerMinute[l]; +#ifdef DEBUG +// fprintf(stdout,_("Tempo %i\n"),l); +#endif + break; + case ScaleInstructionId: + StartBit=BitUnPackInt(package,StartBit,&l,2); + DefNoteScale=l>>6; +#ifdef DEBUG +// fprintf(stdout,_("scale: %i %i\n"),DefNoteScale,ringtone->NrNotes); +#endif + break; + case NoteInstructionId: + StartBit=BitUnPackInt(package,StartBit,&l,4); + + switch (l) { + case Note_C :ringtone->notes[ringtone->NrNotes].note=0;break; + case Note_Cis:ringtone->notes[ringtone->NrNotes].note=1;break; + case Note_D :ringtone->notes[ringtone->NrNotes].note=2;break; + case Note_Dis:ringtone->notes[ringtone->NrNotes].note=3;break; + case Note_E :ringtone->notes[ringtone->NrNotes].note=4;break; + case Note_F :ringtone->notes[ringtone->NrNotes].note=6;break; + case Note_Fis:ringtone->notes[ringtone->NrNotes].note=7;break; + case Note_G :ringtone->notes[ringtone->NrNotes].note=8;break; + case Note_Gis:ringtone->notes[ringtone->NrNotes].note=9;break; + case Note_A :ringtone->notes[ringtone->NrNotes].note=10;break; + case Note_Ais:ringtone->notes[ringtone->NrNotes].note=11;break; + case Note_H :ringtone->notes[ringtone->NrNotes].note=12;break; + default :ringtone->notes[ringtone->NrNotes].note=255;break; //Pause ? + } + + if (ringtone->notes[ringtone->NrNotes].note!=255) + ringtone->notes[ringtone->NrNotes].note=ringtone->notes[ringtone->NrNotes].note+DefNoteScale*14; + + StartBit=BitUnPackInt(package,StartBit,&l,3); + DefNoteDuration=l; + + StartBit=BitUnPackInt(package,StartBit,&spec,2); + + if (DefNoteDuration==Duration_Full && spec==DottedNote) + ringtone->notes[ringtone->NrNotes].duration=128*3/2; + if (DefNoteDuration==Duration_Full && spec==Length_2_3) + ringtone->notes[ringtone->NrNotes].duration=128*2/3; + if (DefNoteDuration==Duration_Full && spec==NoSpecialDuration) + ringtone->notes[ringtone->NrNotes].duration=128; + if (DefNoteDuration==Duration_1_2 && spec==DottedNote) + ringtone->notes[ringtone->NrNotes].duration=64*3/2; + if (DefNoteDuration==Duration_1_2 && spec==Length_2_3) + ringtone->notes[ringtone->NrNotes].duration=64*2/3; + if (DefNoteDuration==Duration_1_2 && spec==NoSpecialDuration) + ringtone->notes[ringtone->NrNotes].duration=64; + if (DefNoteDuration==Duration_1_4 && spec==DottedNote) + ringtone->notes[ringtone->NrNotes].duration=32*3/2; + if (DefNoteDuration==Duration_1_4 && spec==Length_2_3) + ringtone->notes[ringtone->NrNotes].duration=32*2/3; + if (DefNoteDuration==Duration_1_4 && spec==NoSpecialDuration) + ringtone->notes[ringtone->NrNotes].duration=32; + if (DefNoteDuration==Duration_1_8 && spec==DottedNote) + ringtone->notes[ringtone->NrNotes].duration=16*3/2; + if (DefNoteDuration==Duration_1_8 && spec==Length_2_3) + ringtone->notes[ringtone->NrNotes].duration=16*2/3; + if (DefNoteDuration==Duration_1_8 && spec==NoSpecialDuration) + ringtone->notes[ringtone->NrNotes].duration=16; + if (DefNoteDuration==Duration_1_16 && spec==DottedNote) + ringtone->notes[ringtone->NrNotes].duration=8*3/2; + if (DefNoteDuration==Duration_1_16 && spec==Length_2_3) + ringtone->notes[ringtone->NrNotes].duration=8*2/3; + if (DefNoteDuration==Duration_1_16 && spec==NoSpecialDuration) + ringtone->notes[ringtone->NrNotes].duration=8; + if (DefNoteDuration==Duration_1_32 && spec==DottedNote) + ringtone->notes[ringtone->NrNotes].duration=4*3/2; + if (DefNoteDuration==Duration_1_32 && spec==Length_2_3) + ringtone->notes[ringtone->NrNotes].duration=4*2/3; + if (DefNoteDuration==Duration_1_32 && spec==NoSpecialDuration) + ringtone->notes[ringtone->NrNotes].duration=4; + + ringtone->notes[ringtone->NrNotes].style=DefNoteStyle; + + ringtone->notes[ringtone->NrNotes].tempo=DefNoteTempo; + +#ifdef DEBUG +// fprintf(stdout,_("note(%i): %i, scale: %i, duration: %i, spec: %i\n"),ringtone->NrNotes,ringtone->notes[ringtone->NrNotes].note,DefNoteScale,DefNoteDuration,spec); +#endif + if (ringtone->NrNotes==FB61_MAX_RINGTONE_NOTES) break; + + ringtone->NrNotes++; + break; + default: +#ifdef DEBUG + fprintf(stdout,_("Unsupported block %i %i\n"),q,i); +#endif + return GE_SUBFORMATNOTSUPPORTED; + } + } + +#ifdef DEBUG +// printf("Number of notes=%d\n",ringtone->NrNotes); +#endif + + return GE_NONE; +} - StartBit = BitUnPackInt(package, StartBit, &l, 3); - if (l != BasicSongType) { - dprintf("Not BasicSongType\n"); - return GE_SUBFORMATNOTSUPPORTED; - } +GSM_Error GSM_ReadRingtone(GSM_SMSMessage *message, GSM_Ringtone *ringtone) +{ + if (message->UDHType==GSM_RingtoneUDH) { + return GSM_UnPackRingtone(ringtone, message->MessageText, message->Length); + } else return GE_SUBFORMATNOTSUPPORTED; +} + +int GSM_GetFrequency(int number) { + + int freq=0; -/* Getting length of the tune name */ - StartBit = BitUnPackInt(package, StartBit, &l, 4); - l = l >> 4; + /* Values according to the software from http://iki.fi/too/sw/xring/ + generated with: + perl -e 'print int(4400 * (2 **($_/12)) + .5)/10, "\n" for(3..14)' + */ + if (number!=255) { + freq=number%14; + switch (freq) { -/* Unpacking the name of the tune. */ - StartBit = BitUnPack(package, StartBit, ringtone->name, 8*l); - ringtone->name[l] = 0; + case 0: freq=523.3; break; // C + case 1: freq=554.4; break; // Cis - StartBit = BitUnPackInt(package, StartBit, &l, 8); - if (l != 1) return GE_SUBFORMATNOTSUPPORTED; //we support only one song pattern + case 2: freq=587.3; break; //D + case 3: freq=622.3; break; //Dis + + case 4: freq=659.3; break; //E - StartBit = BitUnPackInt(package, StartBit, &l, 3); - if (l != PatternHeaderId) { - dprintf("Not PatternHeaderId\n"); - return GE_SUBFORMATNOTSUPPORTED; - } + case 6: freq=698.5; break; //F + case 7: freq=740; break; //Fis - StartBit += 2; //Pattern ID - we ignore it + case 8: freq=784; break; //G + case 9: freq=830.6; break; //Gis - StartBit = BitUnPackInt(package, StartBit, &l, 4); + case 10: freq=880; break; //A + case 11: freq=932.3; break; //Ais - HowMany = 0; - StartBit = BitUnPackInt(package, StartBit, &HowMany, 8); + case 12: freq=987.8; break; //H + + default: freq=0; break; + } + } + else freq = 0; + + if ((number/14)!=0) freq=freq*(number/14); + else freq=freq/2; + + return freq; + +} + +/* Very fast hack. It should be written correctly ! */ +void GSM_PlayOneNote (GSM_RingtoneNote note) { + int Hz; + + Hz=GSM_GetFrequency(note.note); + + GSM->PlayTone(Hz,5); + + /* Is it correct ? Experimental values here */ + switch (note.style) { + case StaccatoStyle: + usleep (7500); + GSM->PlayTone(0,0); + usleep ((1500000/note.tempo*note.duration)-(7500)); + break; + case ContinuousStyle: + usleep (1500000/note.tempo*note.duration); + break; + case NaturalStyle: + usleep (1500000/note.tempo*note.duration-50); + GSM->PlayTone(0,0); + usleep (50); + break; + } +} + +void GSM_PlayRingtone (GSM_Ringtone *ringtone) { + + int i; + + for (i=0;iNrNotes;i++) { + GSM_PlayOneNote(ringtone->notes[i]); + } + + /* Disables buzzer */ + GSM->PlayTone(255*255,0); +} - scale = 0; - ringtone->NrNotes = 0; +/* Initializes one ringtone: first is number of ringtone in + RingingTones in gnokii.h, second its' code, last position in phone menu */ +void RT(int number, int code, int menu) { + RingingTones[number].code=code; + RingingTones[number].menu=menu; +} + +/* This function initializes structures with ringtones names adequate for + your phone model and firmware; if your phone is not now supported: + 1.set first ringtone in 1'st profile in your phone + 2.make ./gnokii --getprofile 1 + 3.read ringtone code + 4.see in gnokii.h, if ringtone name is gnokii.h in RingingTones (if not, add) + 5.put here RT(a,b,c), where a is number of name in RingingTones in gnokii.h, + b is its' code and c is number of ringtone in phone menu + 6.repeat steps 1-5 for all ringtones + 7.send me (Marcin-Wiacek@Topnet.PL) all RT and phone model */ +void PrepareRingingTones(char model[64], char rev[64]) { + + char rev2[64]; + int i; + bool doit; + + if (!RingingTones[0].code) { + if (!strcmp(model,"NSE-1")) //5110 + { + RT( 2,18, 1);RT( 3,19, 2);RT( 7,23, 3);RT( 5,21, 4);RT( 9,25, 5); + RT(20,48, 7);RT(11,27, 8);RT(33,59, 9);RT(35,62,10); + RT(46,60,11);RT(16,36,12);RT(17,37,13);RT(13,32,14);RT(14,34,15); + RT(19,43,16);RT(18,39,17);RT(24,50,18);RT(31,57,19);RT(28,54,20); + RT(30,56,21);RT(40,73,22);RT(39,72,23);RT(37,69,24); + RT(23,49,26);RT(38,71,27); RT(41,74,29); + + strcpy(rev2,"05.23"); //5.24 and higher + doit=false; + for(i=0;i<5;i++) + { + if (rev[i]rev2[i]) doit=true; + } + + if (doit) { + RT(22,47, 6);RT(47,58,25);RT(45,80,28);RT(43,75,30); + } else + { + RT(21,47, 6);RT(32,58,25);RT(44,80,28);RT(42,75,30); + } + RingingTones[0].menu=30; /* How many ringtones in phone */ + } + if (!strcmp(model,"NSM-1")) //6150 + { + RT( 2,18, 1);RT( 3,19, 2);RT( 7,23, 3);RT( 6,22, 4); + RT( 4,20, 5);RT( 5,21, 6);RT(15,35, 7);RT(12,30, 8); + RT( 9,25, 9);RT(20,47,10);RT( 8,24,11);RT(11,27,12); + RT(10,26,13);RT(34,60,14);RT(33,58,15);RT(35,61,16); + RT(16,36,17);RT(13,32,18);RT(19,43,19);RT(18,39,20); + RT(24,49,21);RT(31,56,22);RT(25,50,23);RT(27,52,24); + RT(26,51,25);RT(28,53,26);RT(29,54,27);RT(30,55,28); + RT(39,71,29);RT(37,68,30);RT(47,57,31);RT(23,48,32); + RT(38,70,33);RT(36,67,34);RT(41,73,35); + /*uploadable ringtone*/ + RT( 1,17,36); + RingingTones[0].menu=36; /* How many ringtones in phone */ + } + if (!strcmp(model,"NPE-3")) //6210 + { + RT(19,64, 1);RT( 2,65, 2);RT( 3,66, 3);RT(15,67, 4);RT( 6,68, 5); + RT(49,69, 6);RT(50,70, 7);RT( 7,71, 8);RT(35,72, 9);RT(33,73,10); + RT(18,74,11);RT( 5,75,12);RT(51,76,13);RT(52,77,14);RT(53,78,15); + RT(37,79,16);RT(54,80,17);RT(55,81,18);RT(56,82,19);RT(57,83,20); + RT(58,84,21);RT(59,85,22);RT(25,86,23);RT(27,87,24);RT(30,88,25); + RT(39,89,26);RT(24,90,27);RT( 8,91,28);RT(60,92,29);RT(61,93,30); + RT(31,94,31);RT(62,95,32);RT(63,96,33);RT(64,97,34);RT(48,98,35); + /* Uploadable ringtones */ + RT( 1,137,36);RT(65,138,37);RT(66,139,38);RT(67,140,39);RT(68,141,40); + + RingingTones[0].menu=40; /* How many ringtones in phone */ + } + RingingTones[0].code=true; + } +} + +/* returns names from code or number in menu */ +char *RingingToneName(int code, int menu) +{ + int index=1,i; + GSM_Error error; + + if (code==0) + { + while (strcmp(RingingTones[index].name,"")) { + if (RingingTones[index].menu==menu) break; + index++; + } + } else + { + while (strcmp(RingingTones[index].name,"")) { + if (RingingTones[index].code==code) break; + index++; + } + } + + if (!strncmp(RingingTones[index].name,"Uploaded ",9)) { + ringtone.location=atoi(&RingingTones[index].name[10]); + + error=GSM->GetBinRingtone(&ringtone); + + if (error==GE_NONE) return ringtone.name; + if (error==GE_UNKNOWNMODEL) { - for (i = 0; i < HowMany; i++) { - - StartBit = BitUnPackInt(package, StartBit, &q, 3); - switch (q) { - case VolumeInstructionId: - StartBit += 4; - break; - case StyleInstructionId: - StartBit = BitUnPackInt(package,StartBit,&l,2); - l = l >> 3; - break; - case TempoInstructionId: - StartBit = BitUnPackInt(package, StartBit, &l, 5); - l = l >> 3; - ringtone->tempo = BeatsPerMinute[l]; - break; - case ScaleInstructionId: - StartBit = BitUnPackInt(package, StartBit, &scale, 2); - scale = scale >> 6; - break; - case NoteInstructionId: - StartBit = BitUnPackInt(package, StartBit, &l, 4); - - switch (l) { - case Note_C :ringtone->notes[ringtone->NrNotes].note = 0; break; - case Note_Cis :ringtone->notes[ringtone->NrNotes].note = 1; break; - case Note_D :ringtone->notes[ringtone->NrNotes].note = 2; break; - case Note_Dis :ringtone->notes[ringtone->NrNotes].note = 3; break; - case Note_E :ringtone->notes[ringtone->NrNotes].note = 4; break; - case Note_F :ringtone->notes[ringtone->NrNotes].note = 6; break; - case Note_Fis :ringtone->notes[ringtone->NrNotes].note = 7; break; - case Note_G :ringtone->notes[ringtone->NrNotes].note = 8; break; - case Note_Gis :ringtone->notes[ringtone->NrNotes].note = 9; break; - case Note_A :ringtone->notes[ringtone->NrNotes].note = 10; break; - case Note_Ais :ringtone->notes[ringtone->NrNotes].note = 11; break; - case Note_H :ringtone->notes[ringtone->NrNotes].note = 12; break; - default :ringtone->notes[ringtone->NrNotes].note = 255; break; //Pause ? - } + /* In 33x we have normal "Smart Messaging" format */ + if (GetModelFeature (FN_RINGTONES)==F_RING_SM) { - if (ringtone->notes[ringtone->NrNotes].note != 255) - ringtone->notes[ringtone->NrNotes].note = ringtone->notes[ringtone->NrNotes].note + scale*14; - - StartBit = BitUnPackInt(package, StartBit, &duration, 3); - - StartBit = BitUnPackInt(package, StartBit, &spec, 2); - - if (duration==Duration_Full && spec==DottedNote) - ringtone->notes[ringtone->NrNotes].duration=128*3/2; - if (duration==Duration_Full && spec==Length_2_3) - ringtone->notes[ringtone->NrNotes].duration=128*2/3; - if (duration==Duration_Full && spec==NoSpecialDuration) - ringtone->notes[ringtone->NrNotes].duration=128; - if (duration==Duration_1_2 && spec==DottedNote) - ringtone->notes[ringtone->NrNotes].duration=64*3/2; - if (duration==Duration_1_2 && spec==Length_2_3) - ringtone->notes[ringtone->NrNotes].duration=64*2/3; - if (duration==Duration_1_2 && spec==NoSpecialDuration) - ringtone->notes[ringtone->NrNotes].duration=64; - if (duration==Duration_1_4 && spec==DottedNote) - ringtone->notes[ringtone->NrNotes].duration=32*3/2; - if (duration==Duration_1_4 && spec==Length_2_3) - ringtone->notes[ringtone->NrNotes].duration=32*2/3; - if (duration==Duration_1_4 && spec==NoSpecialDuration) - ringtone->notes[ringtone->NrNotes].duration=32; - if (duration==Duration_1_8 && spec==DottedNote) - ringtone->notes[ringtone->NrNotes].duration=16*3/2; - if (duration==Duration_1_8 && spec==Length_2_3) - ringtone->notes[ringtone->NrNotes].duration=16*2/3; - if (duration==Duration_1_8 && spec==NoSpecialDuration) - ringtone->notes[ringtone->NrNotes].duration=16; - if (duration==Duration_1_16 && spec==DottedNote) - ringtone->notes[ringtone->NrNotes].duration=8*3/2; - if (duration==Duration_1_16 && spec==Length_2_3) - ringtone->notes[ringtone->NrNotes].duration=8*2/3; - if (duration==Duration_1_16 && spec==NoSpecialDuration) - ringtone->notes[ringtone->NrNotes].duration=8; - if (duration==Duration_1_32 && spec==DottedNote) - ringtone->notes[ringtone->NrNotes].duration=4*3/2; - if (duration==Duration_1_32 && spec==Length_2_3) - ringtone->notes[ringtone->NrNotes].duration=4*2/3; - if (duration==Duration_1_32 && spec==NoSpecialDuration) - ringtone->notes[ringtone->NrNotes].duration=4; - - if (ringtone->NrNotes==MAX_RINGTONE_NOTES) break; + i=7; + if (ringtone.frame[9]==0x4a && ringtone.frame[10]==0x3a) i=8; + ringtone.frame[i]=0x02; - ringtone->NrNotes++; - break; - default: - dprintf("Unsupported block\n"); - return GE_SUBFORMATNOTSUPPORTED; - } - } + GSM_UnPackRingtone(&SMringtone, ringtone.frame+i, ringtone.length-i); - return GE_NONE; + return SMringtone.name; + } + } + } + + return RingingTones[index].name; } +/* returns code from number in menu */ +int RingingToneCode(int menu) +{ + int index=1; + + while ( RingingTones[index].menu!=menu) index++; -GSM_Error GSM_ReadRingtoneFromSMS(GSM_SMSMessage *message, GSM_Ringtone *ringtone) + return RingingTones[index].code; +} + +/* returns number in menu from code */ +int RingingToneMenu(int code) { - if (message->UDH[0].Type==SMS_Ringtone) { - return GSM_UnPackRingtone(ringtone, message->MessageText, message->Length); - } else return GE_SUBFORMATNOTSUPPORTED; + int index=1; + + while ( RingingTones[index].code!=code) index++; + + return RingingTones[index].menu; } +int NumberOfRingtones() +{ + return RingingTones[0].menu; +} -int GSM_SaveRingtoneToSMS(GSM_SMSMessage *message, GSM_Ringtone *ringtone) +int GSM_SaveRingtoneToSMS(GSM_MultiSMSMessage *SMS, + GSM_Ringtone *ringtone, bool profilestyle) { - int i, j = GSM_MAX_8BIT_SMS_LENGTH; - - char UserDataHeader[7]= { 0x06, /* User Data Header Length */ - 0x05, /* IEI: application port addressing scheme, 16 bit address */ - 0x04, /* IEDL (IED length ?) */ - 0x15, /* destination address: high byte */ - 0x81, /* destination address: low byte */ - 0x15, /* originator address: high byte */ - 0x81}; /* originator address: low byte */ - - /* Default settings for SMS message: - - no delivery report - - Class Message 1 - - no compression - - 8 bit data - - SMSC no. 1 - - validity 3 days - - set UserDataHeaderIndicator - */ - - message->Type = SMS_Sent; - - /* Data Coding Scheme */ - message->DCS.Type = SMS_GeneralDataCoding; - message->DCS.u.General.Class = 2; - message->DCS.u.General.Compressed = false; - message->DCS.u.General.Alphabet = SMS_8bit; - - message->MessageCenter.No = 1; - message->Validity.VPF = SMS_RelativeFormat; - message->Validity.u.Relative = 4320; /* 4320 minutes == 72 hours */ - message->ReplyViaSameSMSC = false; - - message->UDH_No = 1; - message->UDH[0].Type = SMS_Ringtone; + int i, j; + unsigned char MessageBuffer[GSM_MAX_SMS_8_BIT_LENGTH*4]; + unsigned char MessageBuffer2[GSM_MAX_SMS_8_BIT_LENGTH*4]; + int MessageLength; + GSM_UDH UDHType; - message->Length = j; - - memcpy(message->MessageText, UserDataHeader, 7); - i = GSM_PackRingtone(ringtone, message->MessageText + 7, &j); - - return i; + EncodeUDHHeader(MessageBuffer, GSM_RingtoneUDH); + MessageLength=GSM_MAX_SMS_8_BIT_LENGTH-(MessageBuffer[0]+1); + i=GSM_PackRingtone(ringtone, MessageBuffer, &MessageLength); + + if (i!=ringtone->NrNotes && profilestyle) + { + MessageLength=0; + MessageBuffer[MessageLength++]=0x30; //SM version. Here 3.0 + MessageBuffer[MessageLength++]=SM30_RINGTONE; //ID for ringtone + + MessageBuffer[MessageLength++]=0x01; //length hi.Later changed + MessageBuffer[MessageLength++]=0x00; //length lo.Later changed + + j=SM30_MAX_RINGTONE_FRAME_LENGTH; + i=GSM_PackRingtone(ringtone, MessageBuffer2, &j); + MessageLength=MessageLength+j; + memcpy(MessageBuffer+4,MessageBuffer2,j); + + MessageBuffer[2]=j/256; + MessageBuffer[3]=j%256; + + UDHType=GSM_ProfileUDH; + } else + UDHType=GSM_RingtoneUDH; + + GSM_MakeMultiPartSMS2(SMS,MessageBuffer,MessageLength, UDHType, GSM_Coding_Default); + + return i; }