Found in "gnokii-working" directory, some November-patches version
[gnokii.git] / common / gsm-ringtones.c
1 /*
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml.
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   This file provides support for ringtones.
14
15   $Log$
16   Revision 1.1.1.8  2002/04/03 00:07:57  short
17   Found in "gnokii-working" directory, some November-patches version
18
19   Revision 1.2  2001/09/20 21:46:21  pkot
20   Locale cleanups (Pawel Kot)
21
22
23 */
24
25 #include "gsm-ringtones.h"
26 #include "misc.h"
27
28 /* Beats-per-Minute Encoding */
29
30 int BeatsPerMinute[] = {
31         25,
32         28,
33         31,
34         35,
35         40,
36         45,
37         50,
38         56,
39         63,
40         70,
41         80,
42         90,
43         100,
44         112,
45         125,
46         140,
47         160,
48         180,
49         200,
50         225,
51         250,
52         285,
53         320,
54         355,
55         400,
56         450,
57         500,
58         565,
59         635,
60         715,
61         800,
62         900
63 };
64
65 int OctetAlign(unsigned char *Dest, int CurrentBit)
66 {
67         int i=0;
68
69         while((CurrentBit+i)%8) {
70                 ClearBit(Dest, CurrentBit+i);
71                 i++;
72         }
73
74         return CurrentBit+i;
75 }
76
77 int OctetAlignNumber(int CurrentBit)
78 {
79         int i=0;
80
81         while((CurrentBit+i)%8) {
82                 i++;
83         }
84
85         return CurrentBit+i;
86 }
87
88 int BitPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits)
89 {
90         int i;
91
92         for (i=0; i<Bits; i++)
93                 if (GetBit(Source, i))
94                         SetBit(Dest, CurrentBit+i);
95                 else
96                         ClearBit(Dest, CurrentBit+i);
97
98         return CurrentBit+Bits;
99 }
100
101 int GetTempo(int Beats)
102 {
103         int i=0;
104
105         while ( i < sizeof(BeatsPerMinute)/sizeof(BeatsPerMinute[0])) {
106
107                 if (Beats<=BeatsPerMinute[i])
108                         break;
109                 i++;
110         }
111
112         return i<<3;
113 }    
114
115 int BitPackByte(unsigned char *Dest, int CurrentBit, unsigned char Command, int Bits)
116 {
117         unsigned char Byte[]={Command};
118
119         return BitPack(Dest, CurrentBit, Byte, Bits);
120 }
121
122
123
124 /* This is messy but saves using the math library! */
125
126 int GSM_GetDuration(int number, unsigned char *spec)
127 {
128         int duration=0;
129
130         switch (number) {
131
132         case 128*3/2:
133                 duration=Duration_Full; *spec=DottedNote; break;  
134         case 128*2/3:
135                 duration=Duration_Full; *spec=Length_2_3; break;  
136         case 128:
137                 duration=Duration_Full; *spec=NoSpecialDuration; break;  
138         case 64*9/4:
139                 duration=Duration_1_2; *spec=DoubleDottedNote; break;    
140         case 64*3/2:
141                 duration=Duration_1_2; *spec=DottedNote; break;  
142         case 64*2/3:
143                 duration=Duration_1_2; *spec=Length_2_3; break;  
144         case 64:
145                 duration=Duration_1_2; *spec=NoSpecialDuration; break;  
146         case 32*9/4:
147                 duration=Duration_1_4; *spec=DoubleDottedNote; break;    
148         case 32*3/2:
149                 duration=Duration_1_4; *spec=DottedNote; break;  
150         case 32*2/3:
151                 duration=Duration_1_4; *spec=Length_2_3; break;  
152         case 32:
153                 duration=Duration_1_4; *spec=NoSpecialDuration; break;  
154         case 16*9/4:
155                 duration=Duration_1_8; *spec=DoubleDottedNote; break;    
156         case 16*3/2:
157                 duration=Duration_1_8; *spec=DottedNote; break;  
158         case 16*2/3:
159                 duration=Duration_1_8; *spec=Length_2_3; break;  
160         case 16:
161                 duration=Duration_1_8; *spec=NoSpecialDuration; break;  
162         case 8*9/4:
163                 duration=Duration_1_16; *spec=DoubleDottedNote; break;    
164         case 8*3/2:
165                 duration=Duration_1_16; *spec=DottedNote; break;  
166         case 8*2/3:
167                 duration=Duration_1_16; *spec=Length_2_3; break;  
168         case 8:
169                 duration=Duration_1_16; *spec=NoSpecialDuration; break;  
170         case 4*9/4:
171                 duration=Duration_1_32; *spec=DoubleDottedNote; break;    
172         case 4*3/2:
173                 duration=Duration_1_32; *spec=DottedNote; break;  
174         case 4*2/3:
175                 duration=Duration_1_32; *spec=Length_2_3; break;  
176         case 4:
177                 duration=Duration_1_32; *spec=NoSpecialDuration; break;  
178         }
179
180         return duration;
181 }
182
183
184 int GSM_GetNote(int number)
185 {
186         int note=0;
187  
188         if (number!=255) {
189                 note=number%14;
190                 switch (note) {
191
192                 case 0:
193                         note=Note_C; break;
194                 case 1:
195                         note=Note_Cis; break;
196                 case 2:
197                         note=Note_D; break;
198                 case 3:
199                         note=Note_Dis; break;
200                 case 4:
201                         note=Note_E; break;
202                 case 6:
203                         note=Note_F; break;
204                 case 7:
205                         note=Note_Fis; break;
206                 case 8:
207                         note=Note_G; break;
208                 case 9:
209                         note=Note_Gis; break;
210                 case 10:
211                         note=Note_A; break;
212                 case 11:
213                         note=Note_Ais; break;
214                 case 12:
215                         note=Note_H; break;
216                 }
217         }
218         else note = Note_Pause;
219
220         return note;
221
222 }
223
224 int GSM_GetScale(int number)
225 {
226         int scale=-1;
227
228         if (number!=255) {
229                 scale=number/14;
230
231                 /* Ensure the scale is valid */
232                 scale%=4;
233
234                 scale=scale<<6;
235         }
236         return scale;
237 }
238
239
240 /* This function packs the ringtone from the structure, so it can be set
241    or sent via sms to another phone.
242    Function returns number of packed notes and changes maxlength to
243    number of used chars in "package" */
244
245 u8 GSM_PackRingtone(GSM_Ringtone *ringtone, char *package, int *maxlength)
246 {
247         int StartBit=0;
248         int i;
249         unsigned char CommandLength = 0x02;
250         unsigned char spec;
251         int oldscale=10, newscale;
252         int HowMany=0, HowLong=0, StartNote=0, EndNote=0;
253
254         StartBit=BitPackByte(package, StartBit, CommandLength, 8);
255         StartBit=BitPackByte(package, StartBit, RingingToneProgramming, 7);
256
257         /* The page 3-23 of the specs says that <command-part> is always
258            octet-aligned. */
259         StartBit=OctetAlign(package, StartBit);
260
261         StartBit=BitPackByte(package, StartBit, Sound, 7);
262         StartBit=BitPackByte(package, StartBit, BasicSongType, 3);
263
264         /* Packing the name of the tune. */
265         StartBit=BitPackByte(package, StartBit, strlen(ringtone->name)<<4, 4);
266         StartBit=BitPack(package, StartBit, ringtone->name, 8*strlen(ringtone->name));
267
268         /* Info about song pattern */
269         StartBit=BitPackByte(package, StartBit, 0x01, 8); /* One song pattern */
270         StartBit=BitPackByte(package, StartBit, PatternHeaderId, 3);
271         StartBit=BitPackByte(package, StartBit, A_part, 2);
272         StartBit=BitPackByte(package, StartBit, 0, 4); /* No loop value */
273
274         /* Info, how long is contents for SMS */
275         HowLong=30+8*strlen(ringtone->name)+17+8+8+13;
276   
277         /* Calculate the number of instructions in the tune.
278            Each Note contains Note and (sometimes) Scale.
279            Default Tempo and Style are instructions too. */
280         HowMany=2; /* Default Tempo and Style */
281
282         for(i=0; i<ringtone->NrNotes; i++) {
283
284                 /* PC Composer 2.0.010 doesn't like, when we start ringtone from pause:
285                    it displays that the format is invalid and
286                    hangs, when you move mouse over place, where pause is */       
287                 if (GSM_GetNote(ringtone->notes[i].note)==Note_Pause && oldscale==10) {
288                         StartNote++;
289                 } else {
290       
291                         /* we don't write Scale info before "Pause" note - it saves space */
292                         if (GSM_GetNote(ringtone->notes[i].note)!=Note_Pause &&
293                             oldscale!=(newscale=GSM_GetScale(ringtone->notes[i].note))) {
294
295                                 /* We calculate, if we have space to add next scale instruction */
296                                 if (((HowLong+5)/8)<=(*maxlength-1)) {
297                                         oldscale=newscale;
298                                         HowMany++;
299                                         HowLong+=5;
300                                 } else {
301                                         break;
302                                 }
303                         }
304     
305                         /* We calculate, if we have space to add next note instruction */
306                         if (((HowLong+12)/8)<=(*maxlength-1)) {
307                                 HowMany++;
308                                 EndNote++;
309                                 HowLong+=12;
310                         } else {
311                                 break;
312                         }
313                 }
314
315                 /* If we are sure, we pack it for SMS or setting to phone, not for OTT file */    
316                 if (*maxlength<1000) {
317                         /* Pc Composer gives this as the phone limitation */
318                         if ((EndNote-StartNote)==GSM_MAX_RINGTONE_NOTES-1) break;
319                 }
320         }
321
322         StartBit=BitPackByte(package, StartBit, HowMany, 8);
323
324         /* Style */
325         StartBit=BitPackByte(package, StartBit, StyleInstructionId, 3);
326         StartBit=BitPackByte(package, StartBit, ContinuousStyle, 2);
327
328         /* Beats per minute/tempo of the tune */
329         StartBit=BitPackByte(package, StartBit, TempoInstructionId, 3);
330         StartBit=BitPackByte(package, StartBit, GetTempo(ringtone->tempo), 5);
331
332         /* Default scale */
333         oldscale=10;
334
335         /* Notes packing */
336         for(i=StartNote; i<(EndNote+StartNote); i++) {
337     
338                 /* we don't write Scale info before "Pause" note - it saves place */
339                 if (GSM_GetNote(ringtone->notes[i].note)!=Note_Pause &&
340                     oldscale!=(newscale=GSM_GetScale(ringtone->notes[i].note))) {
341                         oldscale=newscale;
342                         StartBit=BitPackByte(package, StartBit, ScaleInstructionId, 3);
343                         StartBit=BitPackByte(package, StartBit, GSM_GetScale(ringtone->notes[i].note), 2);
344                 }
345
346                 /* Note */
347                 StartBit=BitPackByte(package, StartBit, NoteInstructionId, 3);
348                 StartBit=BitPackByte(package, StartBit, GSM_GetNote(ringtone->notes[i].note), 4);
349                 StartBit=BitPackByte(package, StartBit, GSM_GetDuration(ringtone->notes[i].duration,&spec), 3);
350                 StartBit=BitPackByte(package, StartBit, spec, 2);
351         }
352
353         StartBit=OctetAlign(package, StartBit);
354
355         StartBit=BitPackByte(package, StartBit, CommandEnd, 8);
356   
357         if (StartBit!=OctetAlignNumber(HowLong))
358                 dprintf("Error in PackRingtone - StartBit different to HowLong %d - %d)\n", StartBit,OctetAlignNumber(HowLong));
359
360         *maxlength=StartBit/8;  
361
362         return(EndNote+StartNote);
363 }
364
365
366 int BitUnPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits)
367 {
368         int i;
369
370         for (i=0; i<Bits; i++)
371                 if (GetBit(Dest, CurrentBit+i)) {
372                         SetBit(Source, i);
373                 } else {
374                         ClearBit(Source, i);
375                 }
376
377         return CurrentBit+Bits;
378 }
379
380 int BitUnPackInt(unsigned char *Src, int CurrentBit, int *integer, int Bits)
381 {
382         int l=0,z=128,i;
383
384         for (i=0; i<Bits; i++) {
385                 if (GetBit(Src, CurrentBit+i)) l=l+z;
386                 z=z/2;
387         }
388
389         *integer=l;
390   
391         return CurrentBit+i;
392 }
393
394 int OctetUnAlign(int CurrentBit)
395 {
396         int i=0;
397
398         while((CurrentBit+i)%8) i++;
399
400         return CurrentBit+i;
401 }
402
403
404 /* TODO: better checking, if contents of ringtone is OK */
405
406 GSM_Error GSM_UnPackRingtone(GSM_Ringtone *ringtone, char *package, int maxlength)
407 {
408         int StartBit=0;
409         int spec,duration,scale;
410         int HowMany;
411         int l,q,i;
412
413         StartBit=BitUnPackInt(package,StartBit,&l,8);
414         if (l!=0x02) {
415                 dprintf("Not header\n");
416                 return GE_SUBFORMATNOTSUPPORTED;
417         }
418
419         StartBit=BitUnPackInt(package,StartBit,&l,7);    
420         if (l!=RingingToneProgramming) {
421                 dprintf("Not RingingToneProgramming\n");
422                 return GE_SUBFORMATNOTSUPPORTED;
423         }
424     
425 /* The page 3-23 of the specs says that <command-part> is always
426    octet-aligned. */
427         StartBit=OctetUnAlign(StartBit);
428
429         StartBit=BitUnPackInt(package,StartBit,&l,7);    
430         if (l!=Sound) {
431                 dprintf("Not Sound\n");
432                 return GE_SUBFORMATNOTSUPPORTED;
433         }
434
435         StartBit=BitUnPackInt(package,StartBit,&l,3);    
436         if (l!=BasicSongType) {
437                 dprintf("Not BasicSongType\n");
438                 return GE_SUBFORMATNOTSUPPORTED;
439         }
440
441 /* Getting length of the tune name */
442         StartBit=BitUnPackInt(package,StartBit,&l,4);
443         l=l>>4;
444
445 /* Unpacking the name of the tune. */
446         StartBit=BitUnPack(package, StartBit, ringtone->name, 8*l);
447         ringtone->name[l]=0;
448
449         StartBit=BitUnPackInt(package,StartBit,&l,8);    
450         if (l!=1) return GE_SUBFORMATNOTSUPPORTED; //we support only one song pattern
451
452         StartBit=BitUnPackInt(package,StartBit,&l,3);          
453         if (l!=PatternHeaderId) {
454                 dprintf("Not PatternHeaderId\n");
455                 return GE_SUBFORMATNOTSUPPORTED;
456         }
457
458         StartBit+=2; //Pattern ID - we ignore it
459
460         StartBit=BitUnPackInt(package,StartBit,&l,4);          
461     
462         HowMany=0;
463         StartBit=BitUnPackInt(package, StartBit, &HowMany, 8);
464
465         scale=0;
466         ringtone->NrNotes=0;
467     
468         for (i=0;i<HowMany;i++) {
469
470                 StartBit=BitUnPackInt(package,StartBit,&q,3);              
471                 switch (q) {
472                 case VolumeInstructionId:
473                         StartBit+=4;
474                         break;
475                 case StyleInstructionId:
476                         StartBit=BitUnPackInt(package,StartBit,&l,2);              
477                         l=l>>3;
478                         break;
479                 case TempoInstructionId:
480                         StartBit=BitUnPackInt(package,StartBit,&l,5);
481                         l=l>>3;
482                         ringtone->tempo=BeatsPerMinute[l];
483                         break;
484                 case ScaleInstructionId:
485                         StartBit=BitUnPackInt(package,StartBit,&scale,2);
486                         scale=scale>>6;
487                         break;
488                 case NoteInstructionId:
489                         StartBit=BitUnPackInt(package,StartBit,&l,4);    
490
491                         switch (l) {
492                         case Note_C  :ringtone->notes[ringtone->NrNotes].note=0;break;
493                         case Note_Cis:ringtone->notes[ringtone->NrNotes].note=1;break;
494                         case Note_D  :ringtone->notes[ringtone->NrNotes].note=2;break;
495                         case Note_Dis:ringtone->notes[ringtone->NrNotes].note=3;break;
496                         case Note_E  :ringtone->notes[ringtone->NrNotes].note=4;break;
497                         case Note_F  :ringtone->notes[ringtone->NrNotes].note=6;break;
498                         case Note_Fis:ringtone->notes[ringtone->NrNotes].note=7;break;
499                         case Note_G  :ringtone->notes[ringtone->NrNotes].note=8;break;
500                         case Note_Gis:ringtone->notes[ringtone->NrNotes].note=9;break;
501                         case Note_A  :ringtone->notes[ringtone->NrNotes].note=10;break;
502                         case Note_Ais:ringtone->notes[ringtone->NrNotes].note=11;break;
503                         case Note_H  :ringtone->notes[ringtone->NrNotes].note=12;break;
504                         default      :ringtone->notes[ringtone->NrNotes].note=255;break; //Pause ?
505                         }
506       
507                         if (ringtone->notes[ringtone->NrNotes].note!=255)
508                                 ringtone->notes[ringtone->NrNotes].note=ringtone->notes[ringtone->NrNotes].note+scale*14;
509
510                         StartBit=BitUnPackInt(package,StartBit,&duration,3);    
511
512                         StartBit=BitUnPackInt(package,StartBit,&spec,2);    
513
514                         if (duration==Duration_Full && spec==DottedNote)
515                                 ringtone->notes[ringtone->NrNotes].duration=128*3/2;
516                         if (duration==Duration_Full && spec==Length_2_3)
517                                 ringtone->notes[ringtone->NrNotes].duration=128*2/3;
518                         if (duration==Duration_Full && spec==NoSpecialDuration)
519                                 ringtone->notes[ringtone->NrNotes].duration=128;
520                         if (duration==Duration_1_2 && spec==DottedNote)
521                                 ringtone->notes[ringtone->NrNotes].duration=64*3/2;
522                         if (duration==Duration_1_2 && spec==Length_2_3)
523                                 ringtone->notes[ringtone->NrNotes].duration=64*2/3;
524                         if (duration==Duration_1_2 && spec==NoSpecialDuration)
525                                 ringtone->notes[ringtone->NrNotes].duration=64;
526                         if (duration==Duration_1_4 && spec==DottedNote)
527                                 ringtone->notes[ringtone->NrNotes].duration=32*3/2;
528                         if (duration==Duration_1_4 && spec==Length_2_3)
529                                 ringtone->notes[ringtone->NrNotes].duration=32*2/3;
530                         if (duration==Duration_1_4 && spec==NoSpecialDuration)
531                                 ringtone->notes[ringtone->NrNotes].duration=32;
532                         if (duration==Duration_1_8 && spec==DottedNote)
533                                 ringtone->notes[ringtone->NrNotes].duration=16*3/2;
534                         if (duration==Duration_1_8 && spec==Length_2_3)
535                                 ringtone->notes[ringtone->NrNotes].duration=16*2/3;
536                         if (duration==Duration_1_8 && spec==NoSpecialDuration)
537                                 ringtone->notes[ringtone->NrNotes].duration=16;
538                         if (duration==Duration_1_16 && spec==DottedNote)
539                                 ringtone->notes[ringtone->NrNotes].duration=8*3/2;
540                         if (duration==Duration_1_16 && spec==Length_2_3)
541                                 ringtone->notes[ringtone->NrNotes].duration=8*2/3;
542                         if (duration==Duration_1_16 && spec==NoSpecialDuration)
543                                 ringtone->notes[ringtone->NrNotes].duration=8;
544                         if (duration==Duration_1_32 && spec==DottedNote)
545                                 ringtone->notes[ringtone->NrNotes].duration=4*3/2;
546                         if (duration==Duration_1_32 && spec==Length_2_3)
547                                 ringtone->notes[ringtone->NrNotes].duration=4*2/3;
548                         if (duration==Duration_1_32 && spec==NoSpecialDuration)
549                                 ringtone->notes[ringtone->NrNotes].duration=4;
550
551                         if (ringtone->NrNotes==MAX_RINGTONE_NOTES) break;
552         
553                         ringtone->NrNotes++;
554                         break;
555                 default:
556                         dprintf("Unsupported block\n");
557                         return GE_SUBFORMATNOTSUPPORTED;
558                 } 
559         }
560
561         return GE_NONE;
562 }
563
564
565 #if 0 /* unused */
566 GSM_Error GSM_ReadRingtoneFromSMS(GSM_SMSMessage *message, GSM_Ringtone *ringtone)
567 {
568         if (message->UDHType==GSM_RingtoneUDH) {
569                 return GSM_UnPackRingtone(ringtone, message->MessageText, message->Length);
570         } else return GE_SUBFORMATNOTSUPPORTED;
571 }
572 #endif /* unused */
573
574 #if 0 /* unused */
575 int GSM_SaveRingtoneToSMS(GSM_SMSMessage *message, GSM_Ringtone *ringtone)
576 {  
577         int i, j=GSM_MAX_SMS_8_BIT_LENGTH;
578   
579         char UserDataHeader[7]= { 0x06,  /* User Data Header Length */
580                                   0x05,  /* IEI: application port addressing scheme, 16 bit address */
581                                   0x04,  /* IEDL (IED length ?) */
582                                   0x15,  /* destination address: high byte */
583                                   0x81,  /* destination address: low byte */
584                                   0x15,  /* originator address: high byte */
585                                   0x81}; /* originator address: low byte */
586
587         /* Default settings for SMS message:
588            - no delivery report
589            - Class Message 1
590            - no compression
591            - 8 bit data
592            - SMSC no. 1
593            - validity 3 days
594            - set UserDataHeaderIndicator
595         */
596
597         message->Type = GST_MO;
598         message->Class = 1;
599         message->Compression = false;
600         message->EightBit = true;
601         message->MessageCenter.No = 1;
602         message->Validity = 4320; /* 4320 minutes == 72 hours */
603         message->ReplyViaSameSMSC = false;
604
605         message->UDHType = GSM_RingtoneUDH;
606   
607         i=GSM_PackRingtone(ringtone, message->MessageText, &j);
608
609         message->Length=j;
610   
611         memcpy(message->UDH,UserDataHeader,7);
612   
613         return i;
614 }
615 #endif /* unused */