http://marcin-wiacek.fkn.pl/english/zips/mygnokii.tar.gz
[gnokii.git] / common / gsm-ringtones.c
index f99883e..aa68378 100644 (file)
 /*
 
-  $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 <windows.h>
+  #include "misc_win32.h"
+#else
+  #include <unistd.h>
+#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<Bits; i++)
-               if (GetBit(Source, i))
-                       SetBit(Dest, CurrentBit+i);
-               else
-                       ClearBit(Dest, CurrentBit+i);
+  int i;
 
-       return CurrentBit+Bits;
+  for (i=0; i<Bits; i++)
+    if (GetBit(Source, i))   SetBit(Dest, CurrentBit+i);
+                      else ClearBit(Dest, CurrentBit+i);
+
+  return CurrentBit+Bits;
 }
 
-int GetTempo(int Beats)
-{
-       int i=0;
+int GSM_GetTempo(int Beats) {
 
-       while ( i < sizeof(BeatsPerMinute)/sizeof(BeatsPerMinute[0])) {
+  int i=0;
 
-               if (Beats<=BeatsPerMinute[i])
-                       break;
-               i++;
-       }
+  while ( i < sizeof(BeatsPerMinute)/sizeof(BeatsPerMinute[0])) {
 
-       return i<<3;
+    if (Beats<=BeatsPerMinute[i]) break;
+    i++;
+  }
+
+  return i<<3;
 }    
 
-int BitPackByte(unsigned char *Dest, int CurrentBit, unsigned char Command, int Bits)
-{
-       unsigned char Byte[]={Command};
+int BitPackByte(unsigned char *Dest, int CurrentBit, unsigned char Command, int Bits) {
 
-       return BitPack(Dest, CurrentBit, Byte, Bits);
-}
+  unsigned char Byte[]={Command};
 
+  return BitPack(Dest, CurrentBit, Byte, Bits);
+}
 
 
 /* This is messy but saves using the math library! */
 
-int GSM_GetDuration(int number, unsigned char *spec)
-{
-       int duration=0;
-
-       switch (number) {
-
-       case 128*3/2:
-               duration=Duration_Full; *spec=DottedNote; break;  
-       case 128*2/3:
-               duration=Duration_Full; *spec=Length_2_3; break;  
-       case 128:
-               duration=Duration_Full; *spec=NoSpecialDuration; break;  
-       case 64*9/4:
-               duration=Duration_1_2; *spec=DoubleDottedNote; break;    
-       case 64*3/2:
-               duration=Duration_1_2; *spec=DottedNote; break;  
-       case 64*2/3:
-               duration=Duration_1_2; *spec=Length_2_3; break;  
-       case 64:
-               duration=Duration_1_2; *spec=NoSpecialDuration; break;  
-       case 32*9/4:
-               duration=Duration_1_4; *spec=DoubleDottedNote; break;    
-       case 32*3/2:
-               duration=Duration_1_4; *spec=DottedNote; break;  
-       case 32*2/3:
-               duration=Duration_1_4; *spec=Length_2_3; break;  
-       case 32:
-               duration=Duration_1_4; *spec=NoSpecialDuration; break;  
-       case 16*9/4:
-               duration=Duration_1_8; *spec=DoubleDottedNote; break;    
-       case 16*3/2:
-               duration=Duration_1_8; *spec=DottedNote; break;  
-       case 16*2/3:
-               duration=Duration_1_8; *spec=Length_2_3; break;  
-       case 16:
-               duration=Duration_1_8; *spec=NoSpecialDuration; break;  
-       case 8*9/4:
-               duration=Duration_1_16; *spec=DoubleDottedNote; break;    
-       case 8*3/2:
-               duration=Duration_1_16; *spec=DottedNote; break;  
-       case 8*2/3:
-               duration=Duration_1_16; *spec=Length_2_3; break;  
-       case 8:
-               duration=Duration_1_16; *spec=NoSpecialDuration; break;  
-       case 4*9/4:
-               duration=Duration_1_32; *spec=DoubleDottedNote; break;    
-       case 4*3/2:
-               duration=Duration_1_32; *spec=DottedNote; break;  
-       case 4*2/3:
-               duration=Duration_1_32; *spec=Length_2_3; break;  
-       case 4:
-               duration=Duration_1_32; *spec=NoSpecialDuration; break;  
-       }
-
-       return duration;
+int GSM_GetDuration(int number, unsigned char *spec) {
+
+  int duration=0;
+
+  switch (number) {
+
+  case 128*3/2: duration=Duration_Full; *spec=DottedNote;        break;  
+  case 128*2/3: duration=Duration_Full; *spec=Length_2_3;        break;  
+  case 128    : duration=Duration_Full; *spec=NoSpecialDuration; break;  
+  case 64*9/4 : duration=Duration_1_2;  *spec=DoubleDottedNote;  break;    
+  case 64*3/2 : duration=Duration_1_2;  *spec=DottedNote;        break;  
+  case 64*2/3 : duration=Duration_1_2;  *spec=Length_2_3;        break;  
+  case 64     : duration=Duration_1_2;  *spec=NoSpecialDuration; break;  
+  case 32*9/4 : duration=Duration_1_4;  *spec=DoubleDottedNote;  break;    
+  case 32*3/2 : duration=Duration_1_4;  *spec=DottedNote;        break;  
+  case 32*2/3 : duration=Duration_1_4;  *spec=Length_2_3;        break;  
+  case 32     : duration=Duration_1_4;  *spec=NoSpecialDuration; break;  
+  case 16*9/4 : duration=Duration_1_8;  *spec=DoubleDottedNote;  break;    
+  case 16*3/2 : duration=Duration_1_8;  *spec=DottedNote;        break;  
+  case 16*2/3 : duration=Duration_1_8;  *spec=Length_2_3;        break;  
+  case 16     : duration=Duration_1_8;  *spec=NoSpecialDuration; break;  
+  case 8*9/4  : duration=Duration_1_16; *spec=DoubleDottedNote;  break;    
+  case 8*3/2  : duration=Duration_1_16; *spec=DottedNote;        break;  
+  case 8*2/3  : duration=Duration_1_16; *spec=Length_2_3;        break;  
+  case 8      : duration=Duration_1_16; *spec=NoSpecialDuration; break;  
+  case 4*9/4  : duration=Duration_1_32; *spec=DoubleDottedNote;  break;    
+  case 4*3/2  : duration=Duration_1_32; *spec=DottedNote;        break;  
+  case 4*2/3  : duration=Duration_1_32; *spec=Length_2_3;        break;  
+  case 4      : duration=Duration_1_32; *spec=NoSpecialDuration; break;  
+  }
+
+  return duration;
 }
 
 
-int GSM_GetNote(int number)
-{
-       int note=0;
+int GSM_GetNote(int number) {
+  
+  int note=0;
  
-       if (number!=255) {
-               note=number%14;
-               switch (note) {
-
-               case 0:
-                       note=Note_C; break;
-               case 1:
-                       note=Note_Cis; break;
-               case 2:
-                       note=Note_D; break;
-               case 3:
-                       note=Note_Dis; break;
-               case 4:
-                       note=Note_E; break;
-               case 6:
-                       note=Note_F; break;
-               case 7:
-                       note=Note_Fis; break;
-               case 8:
-                       note=Note_G; break;
-               case 9:
-                       note=Note_Gis; break;
-               case 10:
-                       note=Note_A; break;
-               case 11:
-                       note=Note_Ais; break;
-               case 12:
-                       note=Note_H; break;
-               }
-       }
-       else note = Note_Pause;
-
-       return note;
+  if (number!=255) {
+    note=number%14;
+    switch (note) {
+
+    case  0: note=Note_C;   break;
+    case  1: note=Note_Cis; break;
+    case  2: note=Note_D;   break;
+    case  3: note=Note_Dis; break;
+    case  4: note=Note_E;   break;
+    case  6: note=Note_F;   break;
+    case  7: note=Note_Fis; break;
+    case  8: note=Note_G;   break;
+    case  9: note=Note_Gis; break;
+    case 10: note=Note_A;   break;
+    case 11: note=Note_Ais; break;
+    case 12: note=Note_H;   break;
+    }
+  }
+  else note = Note_Pause;
+
+  return note;
 
 }
 
-int GSM_GetScale(int number)
-{
-       int scale=-1;
+int GSM_GetScale(int number) {
 
-       if (number!=255) {
-               scale=number/14;
+  int scale=-1;
 
-               /* Ensure the scale is valid */
-               scale%=4;
+  if (number!=255) {
+    scale=number/14;
 
-               scale=scale<<6;
-       }
-       return scale;
-}
+    /* Ensure the scale is valid */
+    scale%=4;
 
+    scale=scale<<6;
+  }
+  return scale;
+}
 
-/* This function packs the ringtone from the structure, so it can be set
-   or sent via sms to another phone.
-   Function returns number of packed notes and changes maxlength to
+/* This function packs the ringtone from the structure "ringtone" to
+   "package", where maxlength means length of package.
+   Function returns number of packed notes and change maxlength to
    number of used chars in "package" */
-
-u8 GSM_PackRingtone(GSM_Ringtone *ringtone, char *package, int *maxlength)
+u8 GSM_PackRingtone(GSM_Ringtone *ringtone, unsigned char *package, int *maxlength)
 {
-       int StartBit=0;
-       int i;
-       unsigned char CommandLength = 0x02;
-       unsigned char spec;
-       int oldscale=10, newscale;
-       int HowMany=0, HowLong=0, StartNote=0, EndNote=0;
-
-       StartBit=BitPackByte(package, StartBit, CommandLength, 8);
-       StartBit=BitPackByte(package, StartBit, RingingToneProgramming, 7);
-
-       /* The page 3-23 of the specs says that <command-part> 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];\r              /* Used to find default ringtone parameters */
+  int i,j,k=0,thisnote,thisnotelong;\r
   
-       /* 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; i<ringtone->NrNotes; 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 */\r
\r for (i=0;i<6;i++) buffer[i]=0;\r
+  for (i=0;i<ringtone->NrNotes;i++) {\r
+    switch (ringtone->notes[i].duration) {\r
+      case 192: buffer[0]++; break;\r
+      case 128: buffer[0]++; break;\r
+      case  96:        buffer[1]++; break;\r
+      case  64: buffer[1]++; break;\r
+      case  48: buffer[2]++; break;\r
+      case  32: buffer[2]++; break;\r
+      case  24: buffer[3]++; break;\r
+      case  16: buffer[3]++; break;\r
+      case  12: buffer[4]++; break;\r
+      case   8: buffer[4]++; break;\r
+      case   6: buffer[5]++; break;\r
+      case   4: buffer[5]++; break;\r
+    }\r
+  }\r
+\r
+  /* Now find the most frequently used */\r
+  j=0;\r
+  for (i=0;i<6;i++) {\r
+    if (buffer[i]>j) {\r
+      k=i; \r
+      j=buffer[i];\r
+    }\r
+  }\r
+\r
+  /* Finally convert the default duration */\r
+  switch (k) {\r
+      case 0: DefNoteDuration=128; break;      \r
+      case 1: DefNoteDuration= 64; break;      \r
+      case 2: DefNoteDuration= 32; break;      \r
+      case 3: DefNoteDuration= 16; break;      \r
+      case 4: DefNoteDuration=  8; break;      \r
+      case 5: DefNoteDuration=  4; break;      \r
+     default: DefNoteDuration= 16; break;      \r
+  }  \r
+\r
+  /* Find the most frequently used scale and use this for the default */\r\r
+  for (i=0;i<6;i++) buffer[i]=0;\r
+  for (i=0;i<ringtone->NrNotes;i++) {\r
+    if (ringtone->notes[i].note!=255) {\r
+      buffer[ringtone->notes[i].note/14]++;\r
+    }\r
+  }\r
+  j=0;\r
+  for (i=0;i<6;i++) {\r
+    if (buffer[i]>j) {\r
+      DefNoteScale=i;\r
+      j=buffer[i];\r
+    }\r
+  }\r
+
+  StartBit=BitPackByte(package, StartBit, CommandLength, 8);
+  StartBit=BitPackByte(package, StartBit, RingingToneProgramming, 7);
+
+  /* The page 3-23 of the specs says that <command-part> 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;i<strlen(ringtone->name);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;i<strlen(ringtone->name);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; i<ringtone->NrNotes; 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; i<Bits; i++)
-               if (GetBit(Dest, CurrentBit+i)) {
-                       SetBit(Source, i);
-               } else {
-                       ClearBit(Source, i);
-               }
+  for (i=0; i<Bits; i++)
+    if (GetBit(Dest, CurrentBit+i)) {   SetBit(Source, i); }
+                               else { ClearBit(Source, i); }
 
-       return CurrentBit+Bits;
+  return CurrentBit+Bits;
 }
 
-int BitUnPackInt(unsigned char *Src, int CurrentBit, int *integer, int Bits)
-{
-       int l=0,z=128,i;
+int BitUnPackInt(unsigned char *Src, int CurrentBit, int *integer, int Bits) {
 
-       for (i=0; i<Bits; i++) {
-               if (GetBit(Src, CurrentBit+i)) l=l+z;
-               z=z/2;
-       }
+  int l=0,z=128,i;
 
-       *integer=l;
+  for (i=0; i<Bits; i++) {
+    if (GetBit(Src, CurrentBit+i)) l=l+z;
+    z=z/2;
+  }
+
+  *integer=l;
   
-       return CurrentBit+i;
+  return CurrentBit+i;
 }
 
 int OctetUnAlign(int CurrentBit)
 {
-       int i=0;
+  int i=0;
 
-       while((CurrentBit+i)%8) i++;
+  while((CurrentBit+i)%8) i++;
 
-       return CurrentBit+i;
+  return CurrentBit+i;
 }
 
-
 /* TODO: better checking, if contents of ringtone is OK */
-
 GSM_Error GSM_UnPackRingtone(GSM_Ringtone *ringtone, char *package, int maxlength)
 {
-       int StartBit = 0;
-       int spec, duration, scale;
-       int HowMany;
-       int l, q, i;
-
-       StartBit = BitUnPackInt(package, StartBit, &l, 8);
-       if (l != 0x02) {
-               dprintf("Not header\n");
-               return GE_SUBFORMATNOTSUPPORTED;
-       }
+  int StartBit=0;
+  int HowMany;
+  int l,q,i;
+  int spec;
 
-       StartBit = BitUnPackInt(package, StartBit, &l, 7);
-       if (l != RingingToneProgramming) {
-               dprintf("Not RingingToneProgramming\n");
-               return GE_SUBFORMATNOTSUPPORTED;
-       }
+  /* Default ringtone parameters */
+  u8 DefNoteScale=2, DefNoteDuration=4;
+  int DefNoteTempo=63;
+  u8 DefNoteStyle=NaturalStyle;
+
+  ringtone->allnotesscale=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 <command-part> 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;i<strlen(ringtone->name);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 <command-part> 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<HowMany;i++) {
+
+    StartBit=BitUnPackInt(package,StartBit,&q,3);              
+    switch (q) {
+      case VolumeInstructionId:
+#ifdef DEBUG
+//        fprintf(stdout,_("Volume\n"));
+#endif
+        StartBit+=4;
+        break;
+      case StyleInstructionId:
+        StartBit=BitUnPackInt(package,StartBit,&l,2);              
+#ifdef DEBUG
+//     fprintf(stdout,_("Style %i\n"),l>>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;i<ringtone->NrNotes;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]) break;
+       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;
 }