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