5 A Linux/Unix toolset and driver for Nokia mobile phones.
7 Released under the terms of the GNU GPL, see file COPYING for more details.
9 This file provides support for ringtones.
15 #include "misc_win32.h"
22 GSM_Ringtone SMringtone;
23 GSM_BinRingtone ringtone;
25 /* Beats-per-Minute Encoding */
27 int BeatsPerMinute[] = {
28 25, 28, 31, 35, 40, 45, 50, 56, 63, 70,
29 80, 90, 100, 112, 125, 140, 160, 180, 200, 225,
30 250, 285, 320, 355, 400, 450, 500, 565, 635, 715,
34 struct OneRingtone RingingTones[] = {
36 /* 1 */ {"Uploaded #1",0,0}, /* 2 */ {"Ring ring",0,0},
37 /* 3 */ {"Low",0,0}, /* 4 */ {"Fly",0,0},
38 /* 5 */ {"Mosquito",0,0}, /* 6 */ {"Bee",0,0},
39 /* 7 */ {"Intro",0,0}, /* 8 */ {"Etude",0,0},
40 /* 9 */ {"Hunt",0,0}, /* 10 */ {"Going up",0,0},
41 /* 11 */ {"City bird",0,0}, /* 12 */ {"Chase",0,0},
42 /* 13 */ {"Scifi",0,0}, /* 14 */ {"Kick",0,0},
43 /* 15 */ {"Do-mi-so",0,0}, /* 16 */ {"Robo N1X",0,0},
44 /* 17 */ {"Dizzy",0,0}, /* 18 */ {"Playground",0,0},
45 /* 19 */ {"That's it!",0,0}, /* 20 */ {"Grande valse",0,0},
46 /* 21 */ {"Knock knock",0,0}, /* 22 */ {"Knock again",0,0},
47 /* 23 */ {"Helan",0,0}, /* 24 */ {"Fuga",0,0},
48 /* 25 */ {"Menuet",0,0}, /* 26 */ {"Ode to Joy",0,0},
49 /* 27 */ {"Elise",0,0}, /* 28 */ {"Mozart 40",0,0},
50 /* 29 */ {"Piano Concerto",0,0},/* 30 */ {"William Tell",0,0},
51 /* 31 */ {"Badinerie",0,0}, /* 32 */ {"Polka",0,0},
52 /* 33 */ {"Attraction",0,0}, /* 34 */ {"Polite",0,0},
53 /* 35 */ {"Persuasion",0,0}, /* 36 */ {"Tick tick",0,0},
54 /* 37 */ {"Samba",0,0}, /* 38 */ {"Orient",0,0},
55 /* 39 */ {"Charleston",0,0}, /* 40 */ {"Songette",0,0},
56 /* 41 */ {"Jumping",0,0}, /* 42 */ {"Lamb",0,0},
57 /* 43 */ {"Marry",0,0}, /* 44 */ {"Tango",0,0},
58 /* 45 */ {"Tangoed",0,0}, /* 46 */ {"Down",0,0},
59 /* 47 */ {"Polska",0,0}, /* 48 */ {"WalzeBrilliant",0,0},
60 /* 49 */ {"Cicada",0,0}, /* 50 */ {"Trio",0,0},
61 /* 51 */ {"Circles",0,0}, /* 52 */ {"Nokia tune",0,0},
62 /* 53 */ {"Sunny walks",0,0}, /* 54 */ {"Basic rock",0,0},
63 /* 55 */ {"Reveille",0,0}, /* 56 */ {"Groovy Blue",0,0},
64 /* 57 */ {"Brave Scotland",0,0},/* 58 */ {"Matilda",0,0},
65 /* 59 */ {"Bumblebee",0,0}, /* 60 */ {"Hungarian",0,0},
66 /* 61 */ {"Valkyrie",0,0}, /* 62 */ {"Bach #3",0,0},
67 /* 63 */ {"Toreador",0,0}, /* 64 */ {"9th Symphony",0,0},
68 /* 65 */ {"Uploaded #2",0,0}, /* 66 */ {"Uploaded #3",0,0},
69 /* 67 */ {"Uploaded #4",0,0}, /* 68 */ {"Uploaded #5",0,0},
73 int OctetAlign(unsigned char *Dest, int CurrentBit)
77 while((CurrentBit+i)%8) {
78 ClearBit(Dest, CurrentBit+i);
85 int OctetAlignNumber(int CurrentBit)
89 while((CurrentBit+i)%8) { i++; }
94 int BitPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits)
99 for (i=0; i<Bits; i++)
100 if (GetBit(Source, i)) SetBit(Dest, CurrentBit+i);
101 else ClearBit(Dest, CurrentBit+i);
103 return CurrentBit+Bits;
106 int GSM_GetTempo(int Beats) {
110 while ( i < sizeof(BeatsPerMinute)/sizeof(BeatsPerMinute[0])) {
112 if (Beats<=BeatsPerMinute[i]) break;
119 int BitPackByte(unsigned char *Dest, int CurrentBit, unsigned char Command, int Bits) {
121 unsigned char Byte[]={Command};
123 return BitPack(Dest, CurrentBit, Byte, Bits);
127 /* This is messy but saves using the math library! */
129 int GSM_GetDuration(int number, unsigned char *spec) {
135 case 128*3/2: duration=Duration_Full; *spec=DottedNote; break;
136 case 128*2/3: duration=Duration_Full; *spec=Length_2_3; break;
137 case 128 : duration=Duration_Full; *spec=NoSpecialDuration; break;
138 case 64*9/4 : duration=Duration_1_2; *spec=DoubleDottedNote; break;
139 case 64*3/2 : duration=Duration_1_2; *spec=DottedNote; break;
140 case 64*2/3 : duration=Duration_1_2; *spec=Length_2_3; break;
141 case 64 : duration=Duration_1_2; *spec=NoSpecialDuration; break;
142 case 32*9/4 : duration=Duration_1_4; *spec=DoubleDottedNote; break;
143 case 32*3/2 : duration=Duration_1_4; *spec=DottedNote; break;
144 case 32*2/3 : duration=Duration_1_4; *spec=Length_2_3; break;
145 case 32 : duration=Duration_1_4; *spec=NoSpecialDuration; break;
146 case 16*9/4 : duration=Duration_1_8; *spec=DoubleDottedNote; break;
147 case 16*3/2 : duration=Duration_1_8; *spec=DottedNote; break;
148 case 16*2/3 : duration=Duration_1_8; *spec=Length_2_3; break;
149 case 16 : duration=Duration_1_8; *spec=NoSpecialDuration; break;
150 case 8*9/4 : duration=Duration_1_16; *spec=DoubleDottedNote; break;
151 case 8*3/2 : duration=Duration_1_16; *spec=DottedNote; break;
152 case 8*2/3 : duration=Duration_1_16; *spec=Length_2_3; break;
153 case 8 : duration=Duration_1_16; *spec=NoSpecialDuration; break;
154 case 4*9/4 : duration=Duration_1_32; *spec=DoubleDottedNote; break;
155 case 4*3/2 : duration=Duration_1_32; *spec=DottedNote; break;
156 case 4*2/3 : duration=Duration_1_32; *spec=Length_2_3; break;
157 case 4 : duration=Duration_1_32; *spec=NoSpecialDuration; break;
164 int GSM_GetNote(int number) {
172 case 0: note=Note_C; break;
173 case 1: note=Note_Cis; break;
174 case 2: note=Note_D; break;
175 case 3: note=Note_Dis; break;
176 case 4: note=Note_E; break;
177 case 6: note=Note_F; break;
178 case 7: note=Note_Fis; break;
179 case 8: note=Note_G; break;
180 case 9: note=Note_Gis; break;
181 case 10: note=Note_A; break;
182 case 11: note=Note_Ais; break;
183 case 12: note=Note_H; break;
186 else note = Note_Pause;
192 int GSM_GetScale(int number) {
199 /* Ensure the scale is valid */
207 /* This function packs the ringtone from the structure "ringtone" to
208 "package", where maxlength means length of package.
209 Function returns number of packed notes and change maxlength to
210 number of used chars in "package" */
211 u8 GSM_PackRingtone(GSM_Ringtone *ringtone, unsigned char *package, int *maxlength)
214 unsigned char CommandLength = 0x02;
216 int oldscale=10, newscale=0, oldstyle=0, oldtempo=0;
217 int HowMany=0; /* How many instructions packed */
218 int HowLong=0; /* How many bits packed */
219 int StartNote=0, EndNote=0; /* First and last packed note from ringtone */
221 /* Default ringtone parameters */
222 u8 DefNoteScale=2, DefNoteDuration=4;
224 u8 DefNoteStyle=NaturalStyle;
226 int buffer[6];
\r /* Used to find default ringtone parameters */
227 int i,j,k=0,thisnote,thisnotelong;
\r
229 /* Find the most frequently used duration and use this for the default */
\r
230 \r for (i=0;i<6;i++) buffer[i]=0;
\r
231 for (i=0;i<ringtone->NrNotes;i++) {
\r
232 switch (ringtone->notes[i].duration) {
\r
233 case 192: buffer[0]++; break;
\r
234 case 128: buffer[0]++; break;
\r
235 case 96: buffer[1]++; break;
\r
236 case 64: buffer[1]++; break;
\r
237 case 48: buffer[2]++; break;
\r
238 case 32: buffer[2]++; break;
\r
239 case 24: buffer[3]++; break;
\r
240 case 16: buffer[3]++; break;
\r
241 case 12: buffer[4]++; break;
\r
242 case 8: buffer[4]++; break;
\r
243 case 6: buffer[5]++; break;
\r
244 case 4: buffer[5]++; break;
\r
248 /* Now find the most frequently used */
\r
250 for (i=0;i<6;i++) {
\r
257 /* Finally convert the default duration */
\r
259 case 0: DefNoteDuration=128; break;
\r
260 case 1: DefNoteDuration= 64; break;
\r
261 case 2: DefNoteDuration= 32; break;
\r
262 case 3: DefNoteDuration= 16; break;
\r
263 case 4: DefNoteDuration= 8; break;
\r
264 case 5: DefNoteDuration= 4; break;
\r
265 default: DefNoteDuration= 16; break;
\r
268 /* Find the most frequently used scale and use this for the default */
\r\r
269 for (i=0;i<6;i++) buffer[i]=0;
\r
270 for (i=0;i<ringtone->NrNotes;i++) {
\r
271 if (ringtone->notes[i].note!=255) {
\r
272 buffer[ringtone->notes[i].note/14]++;
\r
276 for (i=0;i<6;i++) {
\r
283 StartBit=BitPackByte(package, StartBit, CommandLength, 8);
284 StartBit=BitPackByte(package, StartBit, RingingToneProgramming, 7);
286 /* The page 3-23 of the specs says that <command-part> is always
288 StartBit=OctetAlign(package, StartBit);
290 StartBit=BitPackByte(package, StartBit, Sound, 7);
291 StartBit=BitPackByte(package, StartBit, BasicSongType, 3);
293 /* Set special chars in ringtone name */
294 for (i=0;i<strlen(ringtone->name);i++) {
295 if (ringtone->name[i]=='~') ringtone->name[i]=1; //enables/disables blinking
296 if (ringtone->name[i]=='`') ringtone->name[i]=0; //hides rest ot contents
299 /* Packing the name of the tune. */
300 StartBit=BitPackByte(package, StartBit, strlen(ringtone->name)<<4, 4);
301 StartBit=BitPack(package, StartBit, ringtone->name, 8*strlen(ringtone->name));
303 /* Set special chars in ringtone name */
304 for (i=0;i<strlen(ringtone->name);i++) {
305 if (ringtone->name[i]==1) ringtone->name[i]='~'; //enables/disables blinking
306 if (ringtone->name[i]==0) ringtone->name[i]='`'; //hides rest ot contents
309 /* Info about song pattern */
310 StartBit=BitPackByte(package, StartBit, 0x01, 8); /* One song pattern */
311 StartBit=BitPackByte(package, StartBit, PatternHeaderId, 3);
312 StartBit=BitPackByte(package, StartBit, A_part, 2);
313 StartBit=BitPackByte(package, StartBit, ringtone->Loop<<4, 4);
315 /* Info, how long is contents for SMS */
316 HowLong=8+8+7+3+4+8*strlen(ringtone->name)+8+3+2+4+8+3+2+3+5;
318 /* Calculating number of instructions in the tune.
319 Each Note contains Note and (sometimes) Scale.
320 Default Tempo and Style are instructions too. */
321 HowMany=2; /* Default Tempo and Style */
323 /* Default style and tempo */
324 DefNoteStyle=ringtone->notes[0].style;
325 DefNoteTempo=ringtone->notes[0].tempo;
326 oldstyle=DefNoteStyle;
327 oldtempo=DefNoteTempo;
329 for(i=0; i<ringtone->NrNotes; i++) {
331 /* PC Composer 2.0.010 doesn't like, when we start ringtone from pause:
332 displays, that format is invalid and
333 hangs, when you move mouse over place, where pause is */
334 if (GSM_GetNote(ringtone->notes[i].note)==Note_Pause && oldscale==10) {
341 /* we don't write Scale/Style info before "Pause" note - it saves place */
342 if (GSM_GetNote(ringtone->notes[i].note)!=Note_Pause) {
344 if (ringtone->allnotesscale ||
345 oldscale!=(newscale=GSM_GetScale(ringtone->notes[i].note))) {
347 /* We calculate, if we have space to add next scale instruction */
348 if (((OctetAlignNumber(HowLong+5)+8)/8)<=(*maxlength)) {
358 if (ringtone->notes[i].style!=oldstyle) {
359 /* We calculate, if we have space to add next style instruction */
360 if (((OctetAlignNumber(HowLong+5)+8)/8)<=(*maxlength)) {
361 oldstyle=ringtone->notes[i].style;
367 HowLong=HowLong-thisnotelong;
368 HowMany=HowMany-thisnote;
374 if (ringtone->notes[i].tempo!=oldtempo) {
375 /* We calculate, if we have space to add next tempo instruction */
376 if (((OctetAlignNumber(HowLong+8)+8)/8)<=(*maxlength)) {
377 oldtempo=ringtone->notes[i].tempo;
383 HowLong=HowLong-thisnotelong;
384 HowMany=HowMany-thisnote;
389 /* We calculate, if we have space to add next note instruction */
390 if (((OctetAlignNumber(HowLong+12)+8)/8)<=(*maxlength)) {
395 HowLong=HowLong-thisnotelong;
396 HowMany=HowMany-thisnote;
401 /* We are sure, we pack it for SMS or setting to phone, not for OTT file */
402 if (*maxlength<1000) {
403 /* Like Pc Composer say - before of phone limitations...*/
404 if ((EndNote-StartNote)==FB61_MAX_RINGTONE_NOTES-1) break;
408 StartBit=BitPackByte(package, StartBit, HowMany, 8);
410 // fprintf(stdout,_("length of new pattern: %i %i\n"),HowMany,StartBit);
414 StartBit=BitPackByte(package, StartBit, StyleInstructionId, 3);
415 StartBit=BitPackByte(package, StartBit, DefNoteStyle, 2);
417 /* Beats per minute/tempo of the tune */
418 StartBit=BitPackByte(package, StartBit, TempoInstructionId, 3);
419 StartBit=BitPackByte(package, StartBit, GSM_GetTempo(DefNoteTempo), 5);
421 // fprintf(stdout,_("def temp: %i %i\n"),GSM_GetTempo(DefNoteTempo),StartBit);
428 oldstyle=DefNoteStyle;
431 oldtempo=DefNoteTempo;
434 for(i=StartNote; i<(EndNote+StartNote); i++) {
436 /* we don't write Scale info before "Pause" note - it saves place */
437 if (GSM_GetNote(ringtone->notes[i].note)!=Note_Pause) {
438 if (ringtone->allnotesscale ||
439 oldscale!=(newscale=GSM_GetScale(ringtone->notes[i].note))) {
441 // fprintf(stdout,_("Scale\n"));
444 StartBit=BitPackByte(package, StartBit, ScaleInstructionId, 3);
445 StartBit=BitPackByte(package, StartBit, GSM_GetScale(ringtone->notes[i].note), 2);
447 if (ringtone->notes[i].style!=oldstyle) {
449 StartBit=BitPackByte(package, StartBit, StyleInstructionId, 3);
450 StartBit=BitPackByte(package, StartBit, ringtone->notes[i].style, 2);
451 oldstyle=ringtone->notes[i].style;
455 if (ringtone->notes[i].tempo!=oldtempo) {
456 /* Beats per minute/tempo of the tune */
457 StartBit=BitPackByte(package, StartBit, TempoInstructionId, 3);
458 StartBit=BitPackByte(package, StartBit, GSM_GetTempo(ringtone->notes[i].tempo), 5);
459 oldtempo=ringtone->notes[i].tempo;
463 StartBit=BitPackByte(package, StartBit, NoteInstructionId, 3);
464 StartBit=BitPackByte(package, StartBit, GSM_GetNote(ringtone->notes[i].note), 4);
465 StartBit=BitPackByte(package, StartBit, GSM_GetDuration(ringtone->notes[i].duration,&spec), 3);
466 StartBit=BitPackByte(package, StartBit, spec, 2);
469 // 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);
474 StartBit=OctetAlign(package, StartBit);
476 StartBit=BitPackByte(package, StartBit, CommandEnd, 8);
479 if (StartBit!=OctetAlignNumber(HowLong)+8)
480 fprintf(stdout,_("Error in PackRingtone - StartBit different to HowLong %d - %d)\n"),StartBit,OctetAlignNumber(HowLong)+8);
483 *maxlength=StartBit/8;
485 return(EndNote+StartNote);
488 int BitUnPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits)
492 for (i=0; i<Bits; i++)
493 if (GetBit(Dest, CurrentBit+i)) { SetBit(Source, i); }
494 else { ClearBit(Source, i); }
496 return CurrentBit+Bits;
499 int BitUnPackInt(unsigned char *Src, int CurrentBit, int *integer, int Bits) {
503 for (i=0; i<Bits; i++) {
504 if (GetBit(Src, CurrentBit+i)) l=l+z;
513 int OctetUnAlign(int CurrentBit)
517 while((CurrentBit+i)%8) i++;
522 /* TODO: better checking, if contents of ringtone is OK */
523 GSM_Error GSM_UnPackRingtone(GSM_Ringtone *ringtone, char *package, int maxlength)
530 /* Default ringtone parameters */
531 u8 DefNoteScale=2, DefNoteDuration=4;
533 u8 DefNoteStyle=NaturalStyle;
535 ringtone->allnotesscale=false;
537 StartBit=BitUnPackInt(package,StartBit,&l,8);
540 fprintf(stdout,_("Not header\n"));
542 if (l!=0x02) return GE_SUBFORMATNOTSUPPORTED;
544 StartBit=BitUnPackInt(package,StartBit,&l,7);
546 if (l!=RingingToneProgramming)
547 fprintf(stdout,_("Not RingingToneProgramming\n"));
549 if (l!=RingingToneProgramming) return GE_SUBFORMATNOTSUPPORTED;
551 /* The page 3-23 of the specs says that <command-part> is always
553 StartBit=OctetUnAlign(StartBit);
555 StartBit=BitUnPackInt(package,StartBit,&l,7);
558 fprintf(stdout,_("Not Sound\n"));
560 if (l!=Sound) return GE_SUBFORMATNOTSUPPORTED;
562 StartBit=BitUnPackInt(package,StartBit,&l,3);
564 if (l!=BasicSongType)
565 fprintf(stdout,_("Not BasicSongType\n"));
567 if (l!=BasicSongType) return GE_SUBFORMATNOTSUPPORTED;
569 /* Getting length of the tune name */
570 StartBit=BitUnPackInt(package,StartBit,&l,4);
573 // fprintf(stdout,_("Length of name: %i\n"),l);
576 /* Unpacking the name of the tune. */
577 StartBit=BitUnPack(package, StartBit, ringtone->name, 8*l);
580 /* Set special chars in ringtone name */
581 for (i=0;i<strlen(ringtone->name);i++) {
582 if (ringtone->name[i]==1) ringtone->name[i]='~'; //enables/disables blinking
583 if (ringtone->name[i]==0) ringtone->name[i]='`'; //hides rest ot contents
587 // fprintf(stdout,_("Name: %s\n"),ringtone->name);
590 StartBit=BitUnPackInt(package,StartBit,&l,8);
592 // fprintf(stdout,_("Number of song patterns: %i\n"),l);
594 if (l!=1) return GE_SUBFORMATNOTSUPPORTED; //we support only one song pattern
596 StartBit=BitUnPackInt(package,StartBit,&l,3);
598 if (l!=PatternHeaderId)
599 fprintf(stdout,_("Not PatternHeaderId\n"));
601 if (l!=PatternHeaderId) return GE_SUBFORMATNOTSUPPORTED;
603 StartBit+=2; //Pattern ID - we ignore it
605 StartBit=BitUnPackInt(package,StartBit,&l,4);
608 fprintf(stdout,_("Loop value: %i\n"),l);
613 StartBit=BitUnPackInt(package, StartBit, &HowMany, 8);
615 fprintf(stdout,_("length of new pattern: %i %i\n"),HowMany,StartBit);
620 for (i=0;i<HowMany;i++) {
622 StartBit=BitUnPackInt(package,StartBit,&q,3);
624 case VolumeInstructionId:
626 // fprintf(stdout,_("Volume\n"));
630 case StyleInstructionId:
631 StartBit=BitUnPackInt(package,StartBit,&l,2);
633 // fprintf(stdout,_("Style %i\n"),l>>6);
636 case StaccatoStyle : DefNoteStyle=StaccatoStyle; break;
637 case ContinuousStyle: DefNoteStyle=ContinuousStyle; break;
638 case NaturalStyle : DefNoteStyle=NaturalStyle; break;
641 case TempoInstructionId:
642 StartBit=BitUnPackInt(package,StartBit,&l,5);
644 DefNoteTempo=BeatsPerMinute[l];
646 // fprintf(stdout,_("Tempo %i\n"),l);
649 case ScaleInstructionId:
650 StartBit=BitUnPackInt(package,StartBit,&l,2);
653 // fprintf(stdout,_("scale: %i %i\n"),DefNoteScale,ringtone->NrNotes);
656 case NoteInstructionId:
657 StartBit=BitUnPackInt(package,StartBit,&l,4);
660 case Note_C :ringtone->notes[ringtone->NrNotes].note=0;break;
661 case Note_Cis:ringtone->notes[ringtone->NrNotes].note=1;break;
662 case Note_D :ringtone->notes[ringtone->NrNotes].note=2;break;
663 case Note_Dis:ringtone->notes[ringtone->NrNotes].note=3;break;
664 case Note_E :ringtone->notes[ringtone->NrNotes].note=4;break;
665 case Note_F :ringtone->notes[ringtone->NrNotes].note=6;break;
666 case Note_Fis:ringtone->notes[ringtone->NrNotes].note=7;break;
667 case Note_G :ringtone->notes[ringtone->NrNotes].note=8;break;
668 case Note_Gis:ringtone->notes[ringtone->NrNotes].note=9;break;
669 case Note_A :ringtone->notes[ringtone->NrNotes].note=10;break;
670 case Note_Ais:ringtone->notes[ringtone->NrNotes].note=11;break;
671 case Note_H :ringtone->notes[ringtone->NrNotes].note=12;break;
672 default :ringtone->notes[ringtone->NrNotes].note=255;break; //Pause ?
675 if (ringtone->notes[ringtone->NrNotes].note!=255)
676 ringtone->notes[ringtone->NrNotes].note=ringtone->notes[ringtone->NrNotes].note+DefNoteScale*14;
678 StartBit=BitUnPackInt(package,StartBit,&l,3);
681 StartBit=BitUnPackInt(package,StartBit,&spec,2);
683 if (DefNoteDuration==Duration_Full && spec==DottedNote)
684 ringtone->notes[ringtone->NrNotes].duration=128*3/2;
685 if (DefNoteDuration==Duration_Full && spec==Length_2_3)
686 ringtone->notes[ringtone->NrNotes].duration=128*2/3;
687 if (DefNoteDuration==Duration_Full && spec==NoSpecialDuration)
688 ringtone->notes[ringtone->NrNotes].duration=128;
689 if (DefNoteDuration==Duration_1_2 && spec==DottedNote)
690 ringtone->notes[ringtone->NrNotes].duration=64*3/2;
691 if (DefNoteDuration==Duration_1_2 && spec==Length_2_3)
692 ringtone->notes[ringtone->NrNotes].duration=64*2/3;
693 if (DefNoteDuration==Duration_1_2 && spec==NoSpecialDuration)
694 ringtone->notes[ringtone->NrNotes].duration=64;
695 if (DefNoteDuration==Duration_1_4 && spec==DottedNote)
696 ringtone->notes[ringtone->NrNotes].duration=32*3/2;
697 if (DefNoteDuration==Duration_1_4 && spec==Length_2_3)
698 ringtone->notes[ringtone->NrNotes].duration=32*2/3;
699 if (DefNoteDuration==Duration_1_4 && spec==NoSpecialDuration)
700 ringtone->notes[ringtone->NrNotes].duration=32;
701 if (DefNoteDuration==Duration_1_8 && spec==DottedNote)
702 ringtone->notes[ringtone->NrNotes].duration=16*3/2;
703 if (DefNoteDuration==Duration_1_8 && spec==Length_2_3)
704 ringtone->notes[ringtone->NrNotes].duration=16*2/3;
705 if (DefNoteDuration==Duration_1_8 && spec==NoSpecialDuration)
706 ringtone->notes[ringtone->NrNotes].duration=16;
707 if (DefNoteDuration==Duration_1_16 && spec==DottedNote)
708 ringtone->notes[ringtone->NrNotes].duration=8*3/2;
709 if (DefNoteDuration==Duration_1_16 && spec==Length_2_3)
710 ringtone->notes[ringtone->NrNotes].duration=8*2/3;
711 if (DefNoteDuration==Duration_1_16 && spec==NoSpecialDuration)
712 ringtone->notes[ringtone->NrNotes].duration=8;
713 if (DefNoteDuration==Duration_1_32 && spec==DottedNote)
714 ringtone->notes[ringtone->NrNotes].duration=4*3/2;
715 if (DefNoteDuration==Duration_1_32 && spec==Length_2_3)
716 ringtone->notes[ringtone->NrNotes].duration=4*2/3;
717 if (DefNoteDuration==Duration_1_32 && spec==NoSpecialDuration)
718 ringtone->notes[ringtone->NrNotes].duration=4;
720 ringtone->notes[ringtone->NrNotes].style=DefNoteStyle;
722 ringtone->notes[ringtone->NrNotes].tempo=DefNoteTempo;
725 // fprintf(stdout,_("note(%i): %i, scale: %i, duration: %i, spec: %i\n"),ringtone->NrNotes,ringtone->notes[ringtone->NrNotes].note,DefNoteScale,DefNoteDuration,spec);
727 if (ringtone->NrNotes==FB61_MAX_RINGTONE_NOTES) break;
733 fprintf(stdout,_("Unsupported block %i %i\n"),q,i);
735 return GE_SUBFORMATNOTSUPPORTED;
740 // printf("Number of notes=%d\n",ringtone->NrNotes);
746 GSM_Error GSM_ReadRingtone(GSM_SMSMessage *message, GSM_Ringtone *ringtone)
748 if (message->UDHType==GSM_RingtoneUDH) {
749 return GSM_UnPackRingtone(ringtone, message->MessageText, message->Length);
750 } else return GE_SUBFORMATNOTSUPPORTED;
753 int GSM_GetFrequency(int number) {
757 /* Values according to the software from http://iki.fi/too/sw/xring/
759 perl -e 'print int(4400 * (2 **($_/12)) + .5)/10, "\n" for(3..14)'
765 case 0: freq=523.3; break; // C
766 case 1: freq=554.4; break; // Cis
768 case 2: freq=587.3; break; //D
769 case 3: freq=622.3; break; //Dis
771 case 4: freq=659.3; break; //E
773 case 6: freq=698.5; break; //F
774 case 7: freq=740; break; //Fis
776 case 8: freq=784; break; //G
777 case 9: freq=830.6; break; //Gis
779 case 10: freq=880; break; //A
780 case 11: freq=932.3; break; //Ais
782 case 12: freq=987.8; break; //H
784 default: freq=0; break;
789 if ((number/14)!=0) freq=freq*(number/14);
796 /* Very fast hack. It should be written correctly ! */
797 void GSM_PlayOneNote (GSM_RingtoneNote note) {
800 Hz=GSM_GetFrequency(note.note);
804 /* Is it correct ? Experimental values here */
805 switch (note.style) {
809 usleep ((1500000/note.tempo*note.duration)-(7500));
811 case ContinuousStyle:
812 usleep (1500000/note.tempo*note.duration);
815 usleep (1500000/note.tempo*note.duration-50);
822 void GSM_PlayRingtone (GSM_Ringtone *ringtone) {
826 for (i=0;i<ringtone->NrNotes;i++) {
827 GSM_PlayOneNote(ringtone->notes[i]);
830 /* Disables buzzer */
831 GSM->PlayTone(255*255,0);
834 /* Initializes one ringtone: first is number of ringtone in
835 RingingTones in gnokii.h, second its' code, last position in phone menu */
836 void RT(int number, int code, int menu) {
837 RingingTones[number].code=code;
838 RingingTones[number].menu=menu;
841 /* This function initializes structures with ringtones names adequate for
842 your phone model and firmware; if your phone is not now supported:
843 1.set first ringtone in 1'st profile in your phone
844 2.make ./gnokii --getprofile 1
846 4.see in gnokii.h, if ringtone name is gnokii.h in RingingTones (if not, add)
847 5.put here RT(a,b,c), where a is number of name in RingingTones in gnokii.h,
848 b is its' code and c is number of ringtone in phone menu
849 6.repeat steps 1-5 for all ringtones
850 7.send me (Marcin-Wiacek@Topnet.PL) all RT and phone model */
851 void PrepareRingingTones(char model[64], char rev[64]) {
857 if (!RingingTones[0].code) {
858 if (!strcmp(model,"NSE-1")) //5110
860 RT( 2,18, 1);RT( 3,19, 2);RT( 7,23, 3);RT( 5,21, 4);RT( 9,25, 5);
861 RT(20,48, 7);RT(11,27, 8);RT(33,59, 9);RT(35,62,10);
862 RT(46,60,11);RT(16,36,12);RT(17,37,13);RT(13,32,14);RT(14,34,15);
863 RT(19,43,16);RT(18,39,17);RT(24,50,18);RT(31,57,19);RT(28,54,20);
864 RT(30,56,21);RT(40,73,22);RT(39,72,23);RT(37,69,24);
865 RT(23,49,26);RT(38,71,27); RT(41,74,29);
867 strcpy(rev2,"05.23"); //5.24 and higher
871 if (rev[i]<rev2[i]) break;
872 if (rev[i]>rev2[i]) doit=true;
876 RT(22,47, 6);RT(47,58,25);RT(45,80,28);RT(43,75,30);
879 RT(21,47, 6);RT(32,58,25);RT(44,80,28);RT(42,75,30);
881 RingingTones[0].menu=30; /* How many ringtones in phone */
883 if (!strcmp(model,"NSM-1")) //6150
885 RT( 2,18, 1);RT( 3,19, 2);RT( 7,23, 3);RT( 6,22, 4);
886 RT( 4,20, 5);RT( 5,21, 6);RT(15,35, 7);RT(12,30, 8);
887 RT( 9,25, 9);RT(20,47,10);RT( 8,24,11);RT(11,27,12);
888 RT(10,26,13);RT(34,60,14);RT(33,58,15);RT(35,61,16);
889 RT(16,36,17);RT(13,32,18);RT(19,43,19);RT(18,39,20);
890 RT(24,49,21);RT(31,56,22);RT(25,50,23);RT(27,52,24);
891 RT(26,51,25);RT(28,53,26);RT(29,54,27);RT(30,55,28);
892 RT(39,71,29);RT(37,68,30);RT(47,57,31);RT(23,48,32);
893 RT(38,70,33);RT(36,67,34);RT(41,73,35);
894 /*uploadable ringtone*/
896 RingingTones[0].menu=36; /* How many ringtones in phone */
898 if (!strcmp(model,"NPE-3")) //6210
900 RT(19,64, 1);RT( 2,65, 2);RT( 3,66, 3);RT(15,67, 4);RT( 6,68, 5);
901 RT(49,69, 6);RT(50,70, 7);RT( 7,71, 8);RT(35,72, 9);RT(33,73,10);
902 RT(18,74,11);RT( 5,75,12);RT(51,76,13);RT(52,77,14);RT(53,78,15);
903 RT(37,79,16);RT(54,80,17);RT(55,81,18);RT(56,82,19);RT(57,83,20);
904 RT(58,84,21);RT(59,85,22);RT(25,86,23);RT(27,87,24);RT(30,88,25);
905 RT(39,89,26);RT(24,90,27);RT( 8,91,28);RT(60,92,29);RT(61,93,30);
906 RT(31,94,31);RT(62,95,32);RT(63,96,33);RT(64,97,34);RT(48,98,35);
907 /* Uploadable ringtones */
908 RT( 1,137,36);RT(65,138,37);RT(66,139,38);RT(67,140,39);RT(68,141,40);
910 RingingTones[0].menu=40; /* How many ringtones in phone */
912 RingingTones[0].code=true;
916 /* returns names from code or number in menu */
917 char *RingingToneName(int code, int menu)
924 while (strcmp(RingingTones[index].name,"")) {
925 if (RingingTones[index].menu==menu) break;
930 while (strcmp(RingingTones[index].name,"")) {
931 if (RingingTones[index].code==code) break;
936 if (!strncmp(RingingTones[index].name,"Uploaded ",9)) {
937 ringtone.location=atoi(&RingingTones[index].name[10]);
939 error=GSM_GetPhoneRingtone(&ringtone,&SMringtone);
941 if (error==GE_NONE) {
942 if (GetModelFeature (FN_RINGTONES)==F_RING_SM) return SMringtone.name;
943 else return ringtone.name;
947 return RingingTones[index].name;
950 /* returns code from number in menu */
951 int RingingToneCode(int menu)
955 while ( RingingTones[index].menu!=menu) index++;
957 return RingingTones[index].code;
960 /* returns number in menu from code */
961 int RingingToneMenu(int code)
965 while ( RingingTones[index].code!=code) index++;
967 return RingingTones[index].menu;
970 int NumberOfRingtones()
972 return RingingTones[0].menu;
975 int GSM_SaveRingtoneToSMS(GSM_MultiSMSMessage *SMS,
976 GSM_Ringtone *ringtone, bool profilestyle)
979 unsigned char MessageBuffer[GSM_MAX_SMS_8_BIT_LENGTH*4];
980 unsigned char MessageBuffer2[GSM_MAX_SMS_8_BIT_LENGTH*4];
984 EncodeUDHHeader(MessageBuffer, GSM_RingtoneUDH);
985 MessageLength=GSM_MAX_SMS_8_BIT_LENGTH-(MessageBuffer[0]+1);
986 i=GSM_PackRingtone(ringtone, MessageBuffer, &MessageLength);
988 if (i!=ringtone->NrNotes && profilestyle)
991 MessageBuffer[MessageLength++]=0x30; //SM version. Here 3.0
992 MessageBuffer[MessageLength++]=SM30_RINGTONE; //ID for ringtone
994 MessageBuffer[MessageLength++]=0x01; //length hi.Later changed
995 MessageBuffer[MessageLength++]=0x00; //length lo.Later changed
997 j=SM30_MAX_RINGTONE_FRAME_LENGTH;
998 i=GSM_PackRingtone(ringtone, MessageBuffer2, &j);
999 MessageLength=MessageLength+j;
1000 memcpy(MessageBuffer+4,MessageBuffer2,j);
1002 MessageBuffer[2]=j/256;
1003 MessageBuffer[3]=j%256;
1005 UDHType=GSM_ProfileUDH;
1007 UDHType=GSM_RingtoneUDH;
1009 GSM_MakeMultiPartSMS2(SMS,MessageBuffer,MessageLength, UDHType, GSM_Coding_Default);
1014 GSM_Error GSM_GetPhoneRingtone(GSM_BinRingtone *ringtone,GSM_Ringtone *SMringtone)
1019 error=GSM->GetBinRingtone(ringtone);
1021 if (error==GE_UNKNOWNMODEL)
1023 /* In 3310,... we have normal "Smart Messaging" format */
1024 if (GetModelFeature (FN_RINGTONES)==F_RING_SM) {
1026 if (ringtone->frame[9]==0x4a && ringtone->frame[10]==0x3a) i=8;
1027 ringtone->frame[i]=0x02;
1029 GSM_UnPackRingtone(SMringtone, ringtone->frame+i, ringtone->length-i);