7 A Linux/Unix toolset and driver for Nokia mobile phones.
9 Copyright (C) 1999, 2000 Hugh Blemings & Pavel JanÃk ml.
11 Released under the terms of the GNU GPL, see file COPYING for more details.
13 This file provides support for ringtones.
16 Revision 1.1.1.8 2002/04/03 00:07:57 short
17 Found in "gnokii-working" directory, some November-patches version
19 Revision 1.2 2001/09/20 21:46:21 pkot
20 Locale cleanups (Pawel Kot)
25 #include "gsm-ringtones.h"
28 /* Beats-per-Minute Encoding */
30 int BeatsPerMinute[] = {
65 int OctetAlign(unsigned char *Dest, int CurrentBit)
69 while((CurrentBit+i)%8) {
70 ClearBit(Dest, CurrentBit+i);
77 int OctetAlignNumber(int CurrentBit)
81 while((CurrentBit+i)%8) {
88 int BitPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits)
92 for (i=0; i<Bits; i++)
93 if (GetBit(Source, i))
94 SetBit(Dest, CurrentBit+i);
96 ClearBit(Dest, CurrentBit+i);
98 return CurrentBit+Bits;
101 int GetTempo(int Beats)
105 while ( i < sizeof(BeatsPerMinute)/sizeof(BeatsPerMinute[0])) {
107 if (Beats<=BeatsPerMinute[i])
115 int BitPackByte(unsigned char *Dest, int CurrentBit, unsigned char Command, int Bits)
117 unsigned char Byte[]={Command};
119 return BitPack(Dest, CurrentBit, Byte, Bits);
124 /* This is messy but saves using the math library! */
126 int GSM_GetDuration(int number, unsigned char *spec)
133 duration=Duration_Full; *spec=DottedNote; break;
135 duration=Duration_Full; *spec=Length_2_3; break;
137 duration=Duration_Full; *spec=NoSpecialDuration; break;
139 duration=Duration_1_2; *spec=DoubleDottedNote; break;
141 duration=Duration_1_2; *spec=DottedNote; break;
143 duration=Duration_1_2; *spec=Length_2_3; break;
145 duration=Duration_1_2; *spec=NoSpecialDuration; break;
147 duration=Duration_1_4; *spec=DoubleDottedNote; break;
149 duration=Duration_1_4; *spec=DottedNote; break;
151 duration=Duration_1_4; *spec=Length_2_3; break;
153 duration=Duration_1_4; *spec=NoSpecialDuration; break;
155 duration=Duration_1_8; *spec=DoubleDottedNote; break;
157 duration=Duration_1_8; *spec=DottedNote; break;
159 duration=Duration_1_8; *spec=Length_2_3; break;
161 duration=Duration_1_8; *spec=NoSpecialDuration; break;
163 duration=Duration_1_16; *spec=DoubleDottedNote; break;
165 duration=Duration_1_16; *spec=DottedNote; break;
167 duration=Duration_1_16; *spec=Length_2_3; break;
169 duration=Duration_1_16; *spec=NoSpecialDuration; break;
171 duration=Duration_1_32; *spec=DoubleDottedNote; break;
173 duration=Duration_1_32; *spec=DottedNote; break;
175 duration=Duration_1_32; *spec=Length_2_3; break;
177 duration=Duration_1_32; *spec=NoSpecialDuration; break;
184 int GSM_GetNote(int number)
195 note=Note_Cis; break;
199 note=Note_Dis; break;
205 note=Note_Fis; break;
209 note=Note_Gis; break;
213 note=Note_Ais; break;
218 else note = Note_Pause;
224 int GSM_GetScale(int number)
231 /* Ensure the scale is valid */
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" */
245 u8 GSM_PackRingtone(GSM_Ringtone *ringtone, char *package, int *maxlength)
249 unsigned char CommandLength = 0x02;
251 int oldscale=10, newscale;
252 int HowMany=0, HowLong=0, StartNote=0, EndNote=0;
254 StartBit=BitPackByte(package, StartBit, CommandLength, 8);
255 StartBit=BitPackByte(package, StartBit, RingingToneProgramming, 7);
257 /* The page 3-23 of the specs says that <command-part> is always
259 StartBit=OctetAlign(package, StartBit);
261 StartBit=BitPackByte(package, StartBit, Sound, 7);
262 StartBit=BitPackByte(package, StartBit, BasicSongType, 3);
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));
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 */
274 /* Info, how long is contents for SMS */
275 HowLong=30+8*strlen(ringtone->name)+17+8+8+13;
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 */
282 for(i=0; i<ringtone->NrNotes; i++) {
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) {
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))) {
295 /* We calculate, if we have space to add next scale instruction */
296 if (((HowLong+5)/8)<=(*maxlength-1)) {
305 /* We calculate, if we have space to add next note instruction */
306 if (((HowLong+12)/8)<=(*maxlength-1)) {
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;
322 StartBit=BitPackByte(package, StartBit, HowMany, 8);
325 StartBit=BitPackByte(package, StartBit, StyleInstructionId, 3);
326 StartBit=BitPackByte(package, StartBit, ContinuousStyle, 2);
328 /* Beats per minute/tempo of the tune */
329 StartBit=BitPackByte(package, StartBit, TempoInstructionId, 3);
330 StartBit=BitPackByte(package, StartBit, GetTempo(ringtone->tempo), 5);
336 for(i=StartNote; i<(EndNote+StartNote); i++) {
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))) {
342 StartBit=BitPackByte(package, StartBit, ScaleInstructionId, 3);
343 StartBit=BitPackByte(package, StartBit, GSM_GetScale(ringtone->notes[i].note), 2);
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);
353 StartBit=OctetAlign(package, StartBit);
355 StartBit=BitPackByte(package, StartBit, CommandEnd, 8);
357 if (StartBit!=OctetAlignNumber(HowLong))
358 dprintf("Error in PackRingtone - StartBit different to HowLong %d - %d)\n", StartBit,OctetAlignNumber(HowLong));
360 *maxlength=StartBit/8;
362 return(EndNote+StartNote);
366 int BitUnPack(unsigned char *Dest, int CurrentBit, unsigned char *Source, int Bits)
370 for (i=0; i<Bits; i++)
371 if (GetBit(Dest, CurrentBit+i)) {
377 return CurrentBit+Bits;
380 int BitUnPackInt(unsigned char *Src, int CurrentBit, int *integer, int Bits)
384 for (i=0; i<Bits; i++) {
385 if (GetBit(Src, CurrentBit+i)) l=l+z;
394 int OctetUnAlign(int CurrentBit)
398 while((CurrentBit+i)%8) i++;
404 /* TODO: better checking, if contents of ringtone is OK */
406 GSM_Error GSM_UnPackRingtone(GSM_Ringtone *ringtone, char *package, int maxlength)
409 int spec,duration,scale;
413 StartBit=BitUnPackInt(package,StartBit,&l,8);
415 dprintf("Not header\n");
416 return GE_SUBFORMATNOTSUPPORTED;
419 StartBit=BitUnPackInt(package,StartBit,&l,7);
420 if (l!=RingingToneProgramming) {
421 dprintf("Not RingingToneProgramming\n");
422 return GE_SUBFORMATNOTSUPPORTED;
425 /* The page 3-23 of the specs says that <command-part> is always
427 StartBit=OctetUnAlign(StartBit);
429 StartBit=BitUnPackInt(package,StartBit,&l,7);
431 dprintf("Not Sound\n");
432 return GE_SUBFORMATNOTSUPPORTED;
435 StartBit=BitUnPackInt(package,StartBit,&l,3);
436 if (l!=BasicSongType) {
437 dprintf("Not BasicSongType\n");
438 return GE_SUBFORMATNOTSUPPORTED;
441 /* Getting length of the tune name */
442 StartBit=BitUnPackInt(package,StartBit,&l,4);
445 /* Unpacking the name of the tune. */
446 StartBit=BitUnPack(package, StartBit, ringtone->name, 8*l);
449 StartBit=BitUnPackInt(package,StartBit,&l,8);
450 if (l!=1) return GE_SUBFORMATNOTSUPPORTED; //we support only one song pattern
452 StartBit=BitUnPackInt(package,StartBit,&l,3);
453 if (l!=PatternHeaderId) {
454 dprintf("Not PatternHeaderId\n");
455 return GE_SUBFORMATNOTSUPPORTED;
458 StartBit+=2; //Pattern ID - we ignore it
460 StartBit=BitUnPackInt(package,StartBit,&l,4);
463 StartBit=BitUnPackInt(package, StartBit, &HowMany, 8);
468 for (i=0;i<HowMany;i++) {
470 StartBit=BitUnPackInt(package,StartBit,&q,3);
472 case VolumeInstructionId:
475 case StyleInstructionId:
476 StartBit=BitUnPackInt(package,StartBit,&l,2);
479 case TempoInstructionId:
480 StartBit=BitUnPackInt(package,StartBit,&l,5);
482 ringtone->tempo=BeatsPerMinute[l];
484 case ScaleInstructionId:
485 StartBit=BitUnPackInt(package,StartBit,&scale,2);
488 case NoteInstructionId:
489 StartBit=BitUnPackInt(package,StartBit,&l,4);
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 ?
507 if (ringtone->notes[ringtone->NrNotes].note!=255)
508 ringtone->notes[ringtone->NrNotes].note=ringtone->notes[ringtone->NrNotes].note+scale*14;
510 StartBit=BitUnPackInt(package,StartBit,&duration,3);
512 StartBit=BitUnPackInt(package,StartBit,&spec,2);
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;
551 if (ringtone->NrNotes==MAX_RINGTONE_NOTES) break;
556 dprintf("Unsupported block\n");
557 return GE_SUBFORMATNOTSUPPORTED;
566 GSM_Error GSM_ReadRingtoneFromSMS(GSM_SMSMessage *message, GSM_Ringtone *ringtone)
568 if (message->UDHType==GSM_RingtoneUDH) {
569 return GSM_UnPackRingtone(ringtone, message->MessageText, message->Length);
570 } else return GE_SUBFORMATNOTSUPPORTED;
575 int GSM_SaveRingtoneToSMS(GSM_SMSMessage *message, GSM_Ringtone *ringtone)
577 int i, j=GSM_MAX_SMS_8_BIT_LENGTH;
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 */
587 /* Default settings for SMS message:
594 - set UserDataHeaderIndicator
597 message->Type = GST_MO;
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;
605 message->UDHType = GSM_RingtoneUDH;
607 i=GSM_PackRingtone(ringtone, message->MessageText, &j);
611 memcpy(message->UDH,UserDataHeader,7);