Gammu internals  1.38.0
gsmring.c
Go to the documentation of this file.
1 /* (c) 2001-2004 by Marcin Wiacek */
2 /* Based on some work from Ralf Thelen (7110 ringtones) and others */
3 /* Based on some work (RTTL and SM) from Gnokii (www.gnokii.org)
4  * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot
5  * GNU GPL version 2 or later
6  */
7 /* Due to a problem in the source code management, the names of some of
8  * the authors have unfortunately been lost. We do not mean to belittle
9  * their efforts and hope they will contact us to see their names
10  * properly added to the Copyright notice above.
11  * Having published their contributions under the terms of the GNU
12  * General Public License (GPL) [version 2], the Copyright of these
13  * authors will remain respected by adhering to the license they chose
14  * to publish their code under.
15  */
16 
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <math.h>
21 #include <sys/stat.h>
22 #ifdef WIN32
23 # define WIN32_LEAN_AND_MEAN
24 # include <windows.h>
25 #endif
26 
27 #include <gammu-debug.h>
28 #include <gammu-unicode.h>
29 
30 #include "../misc/coding/coding.h"
31 #include "gsmring.h"
32 #include "../debug.h"
33 
37 #define chk_fwrite(data, size, count, file) \
38  if (fwrite(data, size, count, file) != count) goto fail;
39 
41 {
42  int freq = 0;
43 
44  /* Values according to the software from http://iki.fi/too/sw/xring/
45  * generated with:
46  * perl -e 'print int(4400 * (2 **($_/12)) + .5)/10, "\n" for(3..14)'
47  */
48  switch (Note.Note) {
49  case Note_C : freq = 52330; break;
50  case Note_Cis: freq = 55440; break;
51  case Note_D : freq = 58730; break;
52  case Note_Dis: freq = 62230; break;
53  case Note_E : freq = 65930; break;
54  case Note_F : freq = 69850; break;
55  case Note_Fis: freq = 74000; break;
56  case Note_G : freq = 78400; break;
57  case Note_Gis: freq = 83060; break;
58  case Note_A : freq = 88000; break;
59  case Note_Ais: freq = 93230; break;
60  case Note_H : freq = 98780; break;
61  case Note_Pause: break;
62  case Note_INVALID: break;
63  }
64  if (Note.Note != Note_Pause) {
65  switch (Note.Scale) {
66  case Scale_440 : freq = freq / 2; break;
67  case Scale_880 : break;
68  case Scale_1760: freq = freq * 2; break;
69  case Scale_3520: freq = freq * 4; break;
70  default : break;
71  }
72  }
73  return freq / 100;
74 }
75 
77 {
78  int duration = 1;
79 
80  switch (Note.Duration) {
81  case Duration_Full : duration = 128; break;
82  case Duration_1_2 : duration = 64; break;
83  case Duration_1_4 : duration = 32; break;
84  case Duration_1_8 : duration = 16; break;
85  case Duration_1_16 : duration = 8; break;
86  case Duration_1_32 : duration = 4; break;
87  case Duration_INVALID: break;
88  }
89  switch (Note.DurationSpec) {
90  case NoSpecialDuration : break;
91  case DottedNote : duration = duration * 3/2; break;
92  case DoubleDottedNote : duration = duration * 9/4; break;
93  case Length_2_3 : duration = duration * 2/3; break;
94  case DurationSpec_INVALID: break;
95  }
96  return duration;
97 }
98 
99 #ifndef PI
100 # define PI 3.141592654
101 #endif
102 
103 #define WAV_SAMPLE_RATE 44100
104 
106 {
107 
108  unsigned char WAV_Header[] = {
109  'R','I','F','F',
110  0x00,0x00,0x00,0x00, /* Length */
111  'W','A','V','E'};
112  unsigned char FMT_Header[] = {'f','m','t',' ',
113  0x10,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x44,0xac,
114  0x00,0x00,0x88,0x58,0x01,0x00,0x02,0x00,0x10,0x00};
115  unsigned char DATA_Header[] = {
116  'd','a','t','a',
117  0x00,0x00,0x00,0x00}; /* Length */
118  short DATA;
119  long wavfilesize;
120  GSM_RingNote *Note;
121  int i;
122  size_t j,length=0, duration;
123  double phase=0,phase_step;
124 
125  chk_fwrite(&WAV_Header, 1, sizeof(WAV_Header), file);
126  chk_fwrite(&FMT_Header, 1, sizeof(FMT_Header), file);
127  chk_fwrite(&DATA_Header, 1, sizeof(DATA_Header), file);
128 
129  for (i=0;i<ringtone->NoteTone.NrCommands;i++) {
130  if (ringtone->NoteTone.Commands[i].Type == RING_Note) {
131  Note = &ringtone->NoteTone.Commands[i].Note;
132 
133  phase_step = GSM_RingNoteGetFrequency(*Note);
134  phase_step *= WAV_SAMPLE_RATE * 1.5;
135 
136  duration = GSM_RingNoteGetFullDuration(*Note);
137  duration *= WAV_SAMPLE_RATE / 70;
138 
139  for (j = 0; j < duration; j++) {
140  DATA = ((int)(sin(phase*PI) * 50000));
141  chk_fwrite(&DATA, sizeof(short), 1, file);
142  phase = phase + phase_step;
143  length++;
144  }
145  }
146  }
147 
148  wavfilesize = sizeof(WAV_Header) + sizeof(FMT_Header) + sizeof(DATA_Header) + length*2;
149  WAV_Header[4] = ((unsigned char)wavfilesize % 256);
150  WAV_Header[5] = ((unsigned char)wavfilesize / 256);
151  WAV_Header[6] = ((unsigned char)wavfilesize / (256*256));
152  WAV_Header[7] = ((unsigned char)wavfilesize / (256*256*256));
153  wavfilesize = wavfilesize - 54;
154  DATA_Header[4] = ((unsigned char)wavfilesize % 256);
155  DATA_Header[5] = ((unsigned char)wavfilesize / 256);
156  DATA_Header[6] = ((unsigned char)wavfilesize / (256*256));
157  DATA_Header[7] = ((unsigned char)wavfilesize / (256*256*256));
158 
159  fseek( file, 0, SEEK_SET);
160  chk_fwrite(&WAV_Header, 1, sizeof(WAV_Header), file);
161  chk_fwrite(&FMT_Header, 1, sizeof(FMT_Header), file);
162  chk_fwrite(&DATA_Header, 1, sizeof(DATA_Header), file);
163 
164  return ERR_NONE;
165 fail:
166  return ERR_WRITING_FILE;
167 }
168 
169 static GSM_Error savebin(FILE *file, GSM_Ringtone *ringtone)
170 {
171  char nullchar=0x00;
172 
173  chk_fwrite(&nullchar,1,1,file);
174  chk_fwrite(&nullchar,1,1,file);
175  fprintf(file,"\x0C\x01\x2C");
176  fprintf(file,"%s",DecodeUnicodeString(ringtone->Name));
177  chk_fwrite(&nullchar,1,1,file);
178  chk_fwrite(&nullchar,1,1,file);
179  chk_fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file);
180  return ERR_NONE;
181 fail:
182  return ERR_WRITING_FILE;
183 }
184 
185 static GSM_Error savepuremidi(FILE *file, GSM_Ringtone *ringtone)
186 {
187  chk_fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file);
188  return ERR_NONE;
189 fail:
190  return ERR_WRITING_FILE;
191 }
192 
193 static GSM_Error savemmf(FILE *file, GSM_Ringtone *ringtone)
194 {
195  chk_fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file);
196  return ERR_NONE;
197 fail:
198  return ERR_WRITING_FILE;
199 }
200 
202 {
203  GSM_RingNoteScale DefNoteScale;
204  GSM_RingNoteDuration DefNoteDuration;
205 
206  GSM_RingNoteStyle DefNoteStyle=0;
207  int DefNoteTempo=0;
208 
209  gboolean started = FALSE, firstcomma = TRUE;
210  GSM_RingNote *Note;
211 
212  unsigned char buffer[15];
213  int i,j,k=0;
214 
215  /* Saves ringtone name */
216  fprintf(file,"%s:",DecodeUnicodeString(ringtone->Name));
217 
218  /* Find the most frequently used duration */
219  for (i=0;i<6;i++) buffer[i]=0;
220  for (i=0;i<ringtone->NoteTone.NrCommands;i++) {
221  if (ringtone->NoteTone.Commands[i].Type == RING_Note) {
222  Note = &ringtone->NoteTone.Commands[i].Note;
223  /* some durations need 2 bytes in file, some 1 */
224  /* Typecasting to silent GCC warning, Duration is usually unsigned */
225  if ((int)Note->Duration >= Duration_Full && Note->Duration <= Duration_1_8) {
226  buffer[Note->Duration/32]++;
227  }
228  if (Note->Duration >= Duration_1_16 && Note->Duration <= Duration_1_32) {
229  buffer[Note->Duration/32]+=2;
230  }
231  }
232  }
233  /* Now find the most frequently used */
234  j=0;
235  for (i=0;i<6;i++) {
236  if (buffer[i]>j) {
237  k=i;
238  j=buffer[i];
239  }
240  }
241  /* Finally convert the default duration */
242  DefNoteDuration = k * 32;
243  dbgprintf(NULL, "DefNoteDuration=%d\n", DefNoteDuration);
244  switch (DefNoteDuration) {
245  case Duration_INVALID: break;
246  case Duration_Full:fprintf(file,"d=1"); break;
247  case Duration_1_2 :fprintf(file,"d=2"); break;
248  case Duration_1_4 :fprintf(file,"d=4"); break;
249  case Duration_1_8 :fprintf(file,"d=8"); break;
250  case Duration_1_16:fprintf(file,"d=16");break;
251  case Duration_1_32:fprintf(file,"d=32");break;
252  }
253 
254  /* Find the most frequently used scale */
255  for (i=0;i<9;i++) buffer[i]=0;
256  for (i=0;i<ringtone->NoteTone.NrCommands;i++) {
257  if (ringtone->NoteTone.Commands[i].Type == RING_Note) {
258  Note = &ringtone->NoteTone.Commands[i].Note;
259  if (Note->Note!=Note_Pause &&
260  Note->Scale >= Scale_55 && Note->Scale <= Scale_14080) {
261  buffer[Note->Scale - 1]++;
262  }
263  }
264  }
265  j=0;
266  for (i=0;i<9;i++) {
267  if (buffer[i]>j) {
268  k = i;
269  j=buffer[i];
270  }
271  }
272  DefNoteScale = k + 1;
273  /* Save the default scale */
274  fprintf(file,",o=%i,",DefNoteScale);
275  dbgprintf(NULL, "DefNoteScale=%d\n", DefNoteScale);
276 
277  for (i=0;i<ringtone->NoteTone.NrCommands;i++) {
278  if (ringtone->NoteTone.Commands[i].Type != RING_Note) continue;
279 
280  Note = &ringtone->NoteTone.Commands[i].Note;
281 
282  /* Trick from PPM Edit */
283  if (Note->DurationSpec == DoubleDottedNote) {
284  switch (Note->Duration) {
285  case Duration_INVALID: break;
286  case Duration_Full:Note->Duration = Duration_Full;break;
287  case Duration_1_2 :Note->Duration = Duration_Full;break;
288  case Duration_1_4 :Note->Duration = Duration_1_2; break;
289  case Duration_1_8 :Note->Duration = Duration_1_4; break;
290  case Duration_1_16:Note->Duration = Duration_1_8; break;
291  case Duration_1_32:Note->Duration = Duration_1_16;break;
292  }
294  }
295 
296  if (!started) {
297  DefNoteTempo=Note->Tempo;
298  DefNoteStyle=Note->Style;
299  switch (Note->Style) {
300  case StaccatoStyle : fprintf(file,"s=S,"); break;
301  case NaturalStyle : fprintf(file,"s=N,"); break;
302  case ContinuousStyle : break;
303  case INVALIDStyle: break;
304  }
305  /* Save the default tempo */
306  fprintf(file,"b=%i:",DefNoteTempo);
307  dbgprintf(NULL, "DefNoteTempo=%d\n", DefNoteTempo);
308  started = TRUE;
309  firstcomma = TRUE;
310  }
311 
312  if (Note->Style!=DefNoteStyle) {
313  /* And a separator */
314  if (!firstcomma) fprintf(file,",");
315  firstcomma = FALSE;
316  DefNoteStyle=Note->Style;
317  switch (Note->Style) {
318  case StaccatoStyle : fprintf(file,"s=S"); break;
319  case NaturalStyle : fprintf(file,"s=N"); break;
320  case ContinuousStyle: fprintf(file,"s=C"); break;
321  case INVALIDStyle: break;
322  }
323  }
324  if (Note->Tempo!=DefNoteTempo) {
325  /* And a separator */
326  if (!firstcomma) fprintf(file,",");
327  firstcomma = FALSE;
328  DefNoteTempo=Note->Tempo;
329  fprintf(file,"b=%i",DefNoteTempo);
330  }
331  /* This note has a duration different than the default. We must save it */
332  if (Note->Duration!=DefNoteDuration) {
333  /* And a separator */
334  if (!firstcomma) fprintf(file,",");
335  firstcomma = FALSE;
336  switch (Note->Duration) {
337  case Duration_INVALID: break;
338  case Duration_Full:fprintf(file,"1"); break;
339  case Duration_1_2 :fprintf(file,"2"); break;
340  case Duration_1_4 :fprintf(file,"4"); break;
341  case Duration_1_8 :fprintf(file,"8"); break;
342  case Duration_1_16:fprintf(file,"16");break;
343  case Duration_1_32:fprintf(file,"32");break;
344  }
345  } else {
346  /* And a separator */
347  if (!firstcomma) fprintf(file,",");
348  firstcomma = FALSE;
349  }
350  /* Now save the actual note */
351  switch (Note->Note) {
352  case Note_C :fprintf(file,"c"); break;
353  case Note_Cis:fprintf(file,"c#"); break;
354  case Note_D :fprintf(file,"d"); break;
355  case Note_Dis:fprintf(file,"d#"); break;
356  case Note_E :fprintf(file,"e"); break;
357  case Note_F :fprintf(file,"f"); break;
358  case Note_Fis:fprintf(file,"f#"); break;
359  case Note_G :fprintf(file,"g"); break;
360  case Note_Gis:fprintf(file,"g#"); break;
361  case Note_A :fprintf(file,"a"); break;
362  case Note_Ais:fprintf(file,"a#"); break;
363  case Note_H :fprintf(file,"h"); break;
364  default :fprintf(file,"p"); break; /*Pause ?*/
365  }
366  switch (Note->DurationSpec) {
367  case DottedNote : fprintf(file,"."); break;
368  default : break;
369  }
370  if (Note->Note!=Note_Pause && Note->Scale != DefNoteScale) {
371  fprintf(file,"%i",Note->Scale);
372  }
373  }
374  return ERR_NONE;
375 }
376 
378 {
379  char Buffer[2000];
380  size_t i=2000;
381 
382  GSM_EncodeEMSSound(ringtone, Buffer, &i, GSM_Ring_IMelody12, TRUE);
383 
384  chk_fwrite(Buffer, 1, i, file);
385  return ERR_NONE;
386 fail:
387  return ERR_WRITING_FILE;
388 }
389 
390 static void WriteVarLen(unsigned char* midifile, size_t* current, long value)
391 {
392  long buffer;
393 
394  buffer = value & 0x7f;
395 
396  while (value >>= 7) {
397  buffer <<= 8;
398  buffer |= 0x80;
399  buffer += (value & 0x7f);
400  }
401 
402  while (1) {
403  midifile[(*current)++] = (unsigned char)buffer;
404  if (buffer & 0x80) {
405  buffer >>= 8;
406  } else {
407  break;
408  }
409  }
410 }
411 
412 /* FIXME: need adding tempo before each note and scale too ? */
414 {
415  int pause_time = 0, duration, i, note=0, length = 20;
416  size_t current = 26;
417  gboolean started = FALSE;
418  GSM_RingNote *Note;
419  unsigned char midifile[3000] = {
420  0x4D, 0x54, 0x68, 0x64, /* MThd */
421  0x00, 0x00, 0x00, 0x06, /* chunk length */
422  0x00, 0x00, /* format 0 */
423  0x00, 0x01, /* one track */
424  0x00, 0x20, /* 32 per quarter note */
425  0x4D, 0x54, 0x72, 0x6B, /* MTrk */
426  0x00, 0x00, 0x00, 0x00, /* chunk length */
427  0x00, 0xFF, 0x51, 0x03, /* tempo meta event */
428  0x00, 0x00, 0x00}; /* 3 bytes for us for a quarter note */
429 
430  for (i = 0; i < ringtone->NoteTone.NrCommands; i++) {
431  if (ringtone->NoteTone.Commands[i].Type == RING_Note) {
432  Note = &ringtone->NoteTone.Commands[i].Note;
433  if (!started) {
434  /* readmid does not read pauses at the beginning */
435  if (Note->Note != Note_Pause) {
436  /* FIXME: we need add tempo before each note or so... */
437  duration = 60000000/Note->Tempo;
438 
439  midifile[current++] = (unsigned char)(duration >> 16);
440  midifile[current++] = (unsigned char)(duration >> 8);
441  midifile[current++] = (unsigned char)duration;
442 
443  started = TRUE;
444  }
445  }
446  if (!started) continue;
447  duration = GSM_RingNoteGetFullDuration(*Note);
448  if (Note->Note == Note_Pause) {
449  pause_time += duration;
450  } else {
451  if (Note->Note >= Note_C && Note->Note <= Note_H) {
452  note = Note->Note/16 + 12 * Note->Scale - 1;
453  }
454 
455  WriteVarLen(midifile,&current,pause_time);
456  pause_time=0;
457  midifile[current++]=0x90; /* note on */
458  midifile[current++]=note;
459  midifile[current++]=0x64; /* forte */
460 
461  WriteVarLen(midifile,&current,duration);
462  midifile[current++]=0x80; /* note off */
463  midifile[current++]=note;
464  midifile[current++]=0x64;
465  }
466  }
467  }
468  midifile[current++] = 0x00;
469  midifile[current++] = 0xFF; /* track end */
470  midifile[current++] = 0x2F;
471  midifile[current++] = 0x00;
472  midifile[length++] = (current-22) >> 8;
473  midifile[length] = current-22;
474 
475  chk_fwrite(midifile,1,current,file);
476  return ERR_NONE;
477 fail:
478  return ERR_WRITING_FILE;
479 }
480 
482 {
483  char Buffer[2000];
484  size_t i=2000;
485 
486  GSM_EncodeNokiaRTTLRingtone(ringtone, Buffer, &i);
487 
488  chk_fwrite(Buffer, 1, i, file);
489  return ERR_NONE;
490 fail:
491  return ERR_WRITING_FILE;
492 }
493 
494 GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
495 {
496  FILE *file;
497  GSM_Error error = ERR_UNKNOWN;;
498 
499 
500  file = fopen(FileName, "wb");
501  if (file == NULL) return ERR_CANTOPENFILE;
502 
503  switch (ringtone->Format) {
504  case RING_NOTETONE:
505  if (strstr(FileName,".ott")) {
506  error = GSM_SaveRingtoneOtt(file,ringtone);
507  } else if (strstr(FileName,".rng")) {
508  error = GSM_SaveRingtoneOtt(file,ringtone);
509  } else if (strstr(FileName,".mid")) {
510  error = GSM_SaveRingtoneMidi(file,ringtone);
511  } else if (strstr(FileName,".imy")) {
512  error = GSM_SaveRingtoneIMelody(file,ringtone);
513  } else if (strstr(FileName,".ime")) {
514  error = GSM_SaveRingtoneIMelody(file,ringtone);
515  } else if (strstr(FileName,".wav")) {
516  error = GSM_SaveRingtoneWav(file,ringtone);
517  } else {
518  error = GSM_SaveRingtoneRttl(file, ringtone);
519  }
520  break;
521  case RING_NOKIABINARY:
522  error = savebin(file, ringtone);
523  break;
524  case RING_MIDI:
525  error = savepuremidi(file, ringtone);
526  break;
527  case RING_MMF:
528  error = savemmf(file, ringtone);
529  break;
530  }
531 
532  fclose(file);
533 
534  return error;
535 }
536 
537 static GSM_Error loadrttl(FILE *file, GSM_Ringtone *ringtone)
538 {
539  GSM_RingNoteScale DefNoteScale = Scale_880;
540  GSM_RingNoteDuration DefNoteDuration = Duration_1_4;
541  GSM_RingNoteStyle DefNoteStyle = NaturalStyle;
542  int DefNoteTempo = 63;
543  size_t i = 0;
544  size_t readbytes;
545 
546  char buffer[2000],Name[100];
547  GSM_RingNote *Note;
548 
549  readbytes = fread(buffer, 1, sizeof(buffer), file);
550 
551  ringtone->NoteTone.NrCommands = 0;
552 
553  /* -------------- name ---------------- */
554  while (buffer[i] != ':' && i < readbytes) {
555  if (buffer[i] == 0x00) return ERR_NONE;
556  i++;
557  }
558  if (i == 0) {
559  /* This is for RTTL ringtones without name. */
560  EncodeUnicode(ringtone->Name,"Gammu",5);
561  } else if (i >= readbytes) {
562  return ERR_FILENOTSUPPORTED;
563  } else {
564  memcpy(Name,buffer,i);
565  Name[i] = 0x00;
566  EncodeUnicode(ringtone->Name,Name,strlen(Name));
567  }
568  i++;
569 
570  /* --------- section with default ringtone settings ----------- */
571  while(1) {
572  if (i >= readbytes) {
573  return ERR_FILENOTSUPPORTED;
574  }
575  switch (buffer[i]) {
576  case ':':
577  break;
578  case 0x00:
579  return ERR_NONE;
580  case 'd': case 'D':
581  switch (atoi(buffer+i+2)) {
582  case 1: DefNoteDuration = Duration_Full; break;
583  case 2: DefNoteDuration = Duration_1_2 ; break;
584  case 4: DefNoteDuration = Duration_1_4 ; break;
585  case 8: DefNoteDuration = Duration_1_8 ; break;
586  case 16: DefNoteDuration = Duration_1_16; break;
587  case 32: DefNoteDuration = Duration_1_32; break;
588  }
589  break;
590  case 'o': case 'O':
591  switch (atoi(buffer+i+2)) {
592  case 4: DefNoteScale = Scale_440 ; break;
593  case 5: DefNoteScale = Scale_880 ; break;
594  case 6: DefNoteScale = Scale_1760; break;
595  case 7: DefNoteScale = Scale_3520; break;
596  }
597  break;
598  case 'b': case 'B':
599  DefNoteTempo=atoi(buffer+i+2);
600  dbgprintf(NULL, "Tempo = %i\n",DefNoteTempo);
601  break;
602  case 's': case 'S':
603  switch (buffer[i+1]) {
604  case 'C': case 'c': DefNoteStyle=ContinuousStyle; break;
605  case 'N': case 'n': DefNoteStyle=NaturalStyle; break;
606  case 'S': case 's': DefNoteStyle=StaccatoStyle; break;
607  }
608  switch (buffer[i+2]) {
609  case 'C': case 'c': DefNoteStyle=ContinuousStyle; break;
610  case 'N': case 'n': DefNoteStyle=NaturalStyle; break;
611  case 'S': case 's': DefNoteStyle=StaccatoStyle; break;
612  }
613  break;
614  }
615  while (buffer[i] != ':' && buffer[i] != ',') {
616  if (buffer[i] == 0x00) return ERR_NONE;
617  i++;
618  }
619  if (buffer[i] == ',') i++;
620  if (buffer[i] == ':') break;
621  }
622  dbgprintf(NULL, "DefNoteDuration=%d\n", DefNoteDuration);
623  dbgprintf(NULL, "DefNoteScale=%d\n", DefNoteScale);
624  i++;
625 
626  /* ------------------------- notes ------------------------------ */
627  while (buffer[i] != 0x00 && ringtone->NoteTone.NrCommands != GSM_MAX_RINGTONE_NOTES) {
628  switch(buffer[i]) {
629  case 'z': case 'Z':
630  switch (buffer[i+1]) {
631  case 'd':
632  ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableLED;
633  ringtone->NoteTone.NrCommands++;
634  break;
635  case 'D':
636  ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableLED;
637  ringtone->NoteTone.NrCommands++;
638  break;
639  case 'v':
641  ringtone->NoteTone.NrCommands++;
642  break;
643  case 'V':
644  ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableVibra;
645  ringtone->NoteTone.NrCommands++;
646  break;
647  case 'l':
649  ringtone->NoteTone.NrCommands++;
650  break;
651  case 'L':
652  ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableLight;
653  ringtone->NoteTone.NrCommands++;
654  }
655  break;
656  case 'o': case 'O':
657  switch (buffer[i+2]) {
658  case 4: DefNoteScale = Scale_440 ; break;
659  case 5: DefNoteScale = Scale_880 ; break;
660  case 6: DefNoteScale = Scale_1760; break;
661  case 7: DefNoteScale = Scale_3520; break;
662  }
663  break;
664  case 's': case 'S':
665  switch (buffer[i+1]) {
666  case 'C': case 'c': DefNoteStyle=ContinuousStyle; break;
667  case 'N': case 'n': DefNoteStyle=NaturalStyle; break;
668  case 'S': case 's': DefNoteStyle=StaccatoStyle; break;
669  }
670  switch (buffer[i+2]) {
671  case 'C': case 'c': DefNoteStyle=ContinuousStyle; break;
672  case 'N': case 'n': DefNoteStyle=NaturalStyle; break;
673  case 'S': case 's': DefNoteStyle=StaccatoStyle; break;
674  }
675  break;
676  default:
677  ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_Note;
678  Note = &ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Note;
679  Note->Style = DefNoteStyle;
680  Note->Tempo = DefNoteTempo;
681  Note->Scale = DefNoteScale;
682  Note->Duration = DefNoteDuration;
684  Note->Note = Note_Pause;
685 
686  /* Duration */
687  switch (atoi(buffer+i)) {
688  case 1: Note->Duration = Duration_Full ; break;
689  case 2: Note->Duration = Duration_1_2 ; break;
690  case 4: Note->Duration = Duration_1_4 ; break;
691  case 8: Note->Duration = Duration_1_8 ; break;
692  case 16: Note->Duration = Duration_1_16 ; break;
693  case 32: Note->Duration = Duration_1_32 ; break;
694  }
695  /* We skip all numbers from duration specification */
696  while(isdigit((int)buffer[i])) i++;
697 
698  /* Some files can have special duration here */
699  if (buffer[i]=='.') {
700  Note->DurationSpec = DottedNote;
701  i++;
702  }
703 
704  /* Note */
705  /* B or b is not in specs, but I decided to put it, because
706  * it's in some RTTL files. It's the same to H note */
707  switch (buffer[i]) {
708  case 'A': case 'a': Note->Note = Note_A; break;
709  case 'B': case 'b': Note->Note = Note_H; break;
710  case 'C': case 'c': Note->Note = Note_C; break;
711  case 'D': case 'd': Note->Note = Note_D; break;
712  case 'E': case 'e': Note->Note = Note_E; break;
713  case 'F': case 'f': Note->Note = Note_F; break;
714  case 'G': case 'g': Note->Note = Note_G; break;
715  case 'H': case 'h': Note->Note = Note_H; break;
716  }
717  i++;
718  if (i >= readbytes) break;
719 
720  if (buffer[i]=='#') {
721  switch (Note->Note) {
722  case Note_A : Note->Note = Note_Ais; break;
723  case Note_C : Note->Note = Note_Cis; break;
724  case Note_D : Note->Note = Note_Dis; break;
725  case Note_F : Note->Note = Note_Fis; break;
726  case Note_G : Note->Note = Note_Gis; break;
727  default : break;
728  }
729  i++;
730  if (i >= readbytes) break;
731  }
732 
733  /* Some files can have special duration here */
734  if (buffer[i]=='.') {
735  Note->DurationSpec = DottedNote;
736  i++;
737  if (i >= readbytes) break;
738  }
739 
740  /* Scale */
741  if (Note->Note!=Note_Pause && isdigit((int)buffer[i])) {
742  switch (atoi(buffer+i)) {
743  case 4: Note->Scale = Scale_440 ; break;
744  case 5: Note->Scale = Scale_880 ; break;
745  case 6: Note->Scale = Scale_1760; break;
746  case 7: Note->Scale = Scale_3520; break;
747  }
748  i++;
749  if (i >= readbytes) break;
750  }
751 
752  ringtone->NoteTone.NrCommands++;
753  break;
754  }
755  if (i >= readbytes) break;
756  while (buffer[i] != ',') {
757  if (buffer[i] == 0x00) return ERR_NONE;
758  i++;
759  if (i >= readbytes) break;
760  }
761  if (i >= readbytes) break;
762  if (buffer[i] == ',') i++;
763  if (i >= readbytes) {
764  return ERR_FILENOTSUPPORTED;
765  }
766  }
767 
768  return ERR_NONE;
769 }
770 
771 static GSM_Error loadott(FILE *file, GSM_Ringtone *ringtone)
772 {
773  char Buffer[2000];
774  int i;
775 
776  i = fread(Buffer, 1, 2000, file);
777 
778  return GSM_DecodeNokiaRTTLRingtone(ringtone, Buffer, i);
779 }
780 
781 static GSM_Error loadcommunicator(FILE *file, GSM_Ringtone *ringtone)
782 {
783  char Buffer[4000];
784  int bytes_read,j;
785 
786  bytes_read = fread(Buffer, 1, 4000, file);
787 
788  j=0;
789  while (TRUE) {
790  if (Buffer[j] ==0x00 && Buffer[j+1]==0x02 &&
791  Buffer[j+2]==0x4a && Buffer[j+3]==0x3a) break;
792  if (j==bytes_read-4) return ERR_UNKNOWN;
793  j++;
794  }
795  j++;
796 
797  return GSM_DecodeNokiaRTTLRingtone(ringtone, Buffer+j, bytes_read-j);
798 }
799 
800 static GSM_Error loadbin(FILE *file, GSM_Ringtone *ringtone)
801 {
802  int i;
803  unsigned char buffer[2000];
804 
805  dbgprintf(NULL, "loading binary\n");
806  ringtone->NokiaBinary.Length = fread(buffer, 1, 500, file);
807  i=5;
808  while (buffer[i]!=0x00) i++;
809  EncodeUnicode(ringtone->Name,buffer+5,i-5);
810  while (buffer[i]!=0x02 && buffer[i+1]!=0xFC && buffer[i+2]!=0x09) {
811  i++;
812  }
813  ringtone->NokiaBinary.Length=ringtone->NokiaBinary.Length-i;
814  memcpy(ringtone->NokiaBinary.Frame,buffer+i,ringtone->NokiaBinary.Length);
815  dbgprintf(NULL, "Length %ld name \"%s\"\n", (long)ringtone->NokiaBinary.Length,DecodeUnicodeString(ringtone->Name));
816  return ERR_NONE;
817 }
818 
819 static GSM_Error loadpuremidi(FILE *file, GSM_Ringtone *ringtone)
820 {
821  dbgprintf(NULL, "loading midi\n");
822  EncodeUnicode(ringtone->Name,"MIDI",4);
823  ringtone->NokiaBinary.Length = fread(ringtone->NokiaBinary.Frame,
824  1, sizeof(ringtone->NokiaBinary.Frame), file);
825  dbgprintf(NULL, "Length %ld name \"%s\"\n",(long)ringtone->NokiaBinary.Length,DecodeUnicodeString(ringtone->Name));
826  return ERR_NONE;
827 }
828 
829 static GSM_Error loadmmf(FILE *file, GSM_Ringtone *ringtone)
830 {
831  struct stat st;
832  char *buffer=NULL;
833  size_t length=0,readbytes=0;
834 
835  dbgprintf(NULL, "loading smaf file\n");
836  fstat(fileno(file), &st);
837  ringtone->BinaryTone.Length = length = st.st_size;
838  ringtone->BinaryTone.Buffer = buffer = (char *)malloc(length);
839  if (buffer == NULL)
840  return ERR_MOREMEMORY;
841  readbytes = fread(buffer, 1, length, file);
842  if (readbytes != length) {
843  dbgprintf(NULL, "Could not read whole file!\n");
844  return ERR_MOREMEMORY;
845  }
846 
847  dbgprintf(NULL, "Length %ld name \"%s\"\n", (long)length,
848  DecodeUnicodeString(ringtone->Name));
849 
850  return ERR_NONE;
851 }
852 
853 static GSM_Error loadre(FILE *file, GSM_Ringtone *ringtone)
854 {
855  unsigned char buffer[2000];
856 
857  ringtone->NokiaBinary.Length = fread(buffer, 1, 500, file);
858 
859  if (buffer[18]==0x00 && buffer[21]!=0x02) {
860  /* DCT3, Unicode subformat, 62xx & 7110 */
861  CopyUnicodeString(ringtone->Name,buffer+18);
862  ringtone->NokiaBinary.Length = ringtone->NokiaBinary.Length - (21+UnicodeLength(ringtone->Name)*2);
863  memcpy(ringtone->NokiaBinary.Frame,buffer+21+UnicodeLength(ringtone->Name)*2,ringtone->NokiaBinary.Length);
864  } else {
865  /* DCT3, normal subformat, 32xx/33xx/51xx/5210/5510/61xx/8xxx */
866  EncodeUnicode(ringtone->Name,buffer+17,buffer[16]);
867  ringtone->NokiaBinary.Length = ringtone->NokiaBinary.Length - (19+UnicodeLength(ringtone->Name));
868  memcpy(ringtone->NokiaBinary.Frame,buffer+19+UnicodeLength(ringtone->Name),ringtone->NokiaBinary.Length);
869  }
870  dbgprintf(NULL, "Name \"%s\"\n",DecodeUnicodeString(ringtone->Name));
871  return ERR_NONE;
872 }
873 
874 GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
875 {
876  FILE *file;
877  unsigned char buffer[300];
878  GSM_Error error = ERR_UNKNOWN;
879  size_t readbytes;
880  char *file_only_name;
881  size_t len;
882 
883  dbgprintf(NULL, "Loading ringtone %s\n",FileName);
884  file = fopen(FileName, "rb");
885  if (file == NULL) return ERR_CANTOPENFILE;
886 
887  file_only_name = strrchr(FileName, '/');
888  if (file_only_name == NULL) {
889  file_only_name = strrchr(FileName, '\\');
890  } else {
891  file_only_name++;
892  }
893  if (file_only_name == NULL) {
894  file_only_name = FileName;
895  } else {
896  file_only_name++;
897  }
898  len = strlen(file_only_name);
899  if (len > GSM_MAX_RINGTONE_NAME_LENGTH){
900  fclose(file);
901  return ERR_MOREMEMORY;
902  }
903 
904  EncodeUnicode(ringtone->Name, file_only_name, len);
905 
906  /* Read the header of the file. */
907  readbytes = fread(buffer, 1, 4, file);
908  if (ringtone->Format == 0x00 && readbytes == 4) {
909  ringtone->Format = RING_NOTETONE;
910  if (buffer[0]==0x00 && buffer[1]==0x00 &&
911  buffer[2]==0x0C && buffer[3]==0x01) {
912  ringtone->Format = RING_NOKIABINARY;
913  }
914  if (buffer[0]==0x00 && buffer[1]==0x00 &&
915  buffer[2]==0x00) {
916  ringtone->Format = RING_NOKIABINARY;
917  }
918  if (buffer[0]==0x4D && buffer[1]==0x54 &&
919  buffer[2]==0x68 && buffer[3]==0x64) {
920  ringtone->Format = RING_MIDI;
921  }
922  if (buffer[0]==0x4D && buffer[1]==0x4D &&
923  buffer[2]==0x4D && buffer[3]==0x44) {
924  ringtone->Format = RING_MMF;
925  }
926  if (buffer[0]=='R' && buffer[1]=='I' &&
927  buffer[2]=='F' && buffer[3]=='F') {
928  dbgprintf(NULL, "RIFF is not supported for loading!\n");
929  fclose(file);
930  return ERR_FILENOTSUPPORTED;
931  }
932  }
933  rewind(file);
934  switch (ringtone->Format) {
935  case RING_NOTETONE:
936  if (buffer[0]==0x02 && buffer[1]==0x4A) {
937  error=loadott(file,ringtone);
938  } else if (buffer[0]==0xC7 && buffer[1]==0x45) {
939  error=loadcommunicator(file,ringtone);
940  } else {
941  error=loadrttl(file,ringtone);
942  }
943  ringtone->NoteTone.AllNotesScale=FALSE;
944  break;
945  case RING_NOKIABINARY:
946  if (buffer[0]==0x00 && buffer[1]==0x00 &&
947  buffer[2]==0x0C && buffer[3]==0x01) {
948  error=loadbin(file,ringtone);
949  }
950  if (buffer[0]==0x00 && buffer[1]==0x00 &&
951  buffer[2]==0x00) {
952  error=loadre(file,ringtone);
953  }
954  break;
955  case RING_MIDI:
956  error = loadpuremidi(file,ringtone);
957  break;
958  case RING_MMF:
959  error = loadmmf(file,ringtone);
960  break;
961  default:
962  error = ERR_FILENOTSUPPORTED;
963  break;
964  }
965  fclose(file);
966  return error ;
967 }
968 
969 /* -------------------------- required with Nokia & RTTL ------------------- */
970 
971 /* Beats per Minute like written in Smart Messaging */
972 static int SM_BeatsPerMinute[] = {
973  25, 28, 31, 35, 40, 45, 50, 56, 63, 70,
974  80, 90, 100, 112, 125, 140, 160, 180, 200, 225,
975  250, 285, 320, 355, 400, 450, 500, 565, 635, 715,
976  800, 900
977 };
978 
979 int GSM_RTTLGetTempo(int Beats)
980 {
981  int i=0;
982 
983  while (Beats > SM_BeatsPerMinute[i] && SM_BeatsPerMinute[i] != 900) i++;
984 
985  return i<<3;
986 }
987 
988 /* This function packs the ringtone from the structure "ringtone" to
989  "package", where maxlength means length of package.
990  Function returns number of packed notes and change maxlength to
991  number of used chars in "package" */
992 unsigned char GSM_EncodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, size_t *maxlength)
993 {
994  unsigned char CommandLength = 0x02;
995  unsigned char Loop = 0x15; /* Infinite */
996 
997  unsigned char Buffer[200];
998  size_t StartBit=0, OldStartBit;
999  int StartBitHowManyCommands;
1000  int HowManyCommands = 0; /* How many instructions packed */
1001  int HowManyNotes = 0;
1002  int i;
1003  size_t j;
1004  gboolean started;
1005  GSM_RingNote *Note;
1006 
1007  GSM_RingNoteScale DefScale = 255;
1008  GSM_RingNoteStyle DefStyle = 255;
1009  int DefTempo = 255;
1010 
1011  AddBufferByte(package, &StartBit, CommandLength, 8);
1012  AddBufferByte(package, &StartBit, SM_Command_RingingToneProgramming, 7);
1013 
1014  /* According to specification we need have next part octet-aligned */
1015  BufferAlign(package, &StartBit);
1016 
1017  AddBufferByte(package, &StartBit, SM_Command_Sound, 7);
1018  AddBufferByte(package, &StartBit, SM_Song_BasicSongType, 3);
1019 
1020  /* Packing the name of the tune. */
1021  EncodeUnicodeSpecialNOKIAChars(Buffer, ringtone->Name, UnicodeLength(ringtone->Name));
1022  AddBufferByte(package, &StartBit, ((unsigned char)(UnicodeLength(Buffer)<<4)), 4);
1023  AddBuffer(package, &StartBit, DecodeUnicodeString(Buffer), 8*UnicodeLength(Buffer));
1024 
1025  /* Packing info about song pattern */
1026  AddBufferByte(package, &StartBit, 0x01, 8); /* one pattern */
1027  AddBufferByte(package, &StartBit, SM_InstructionID_PatternHeaderId, 3);
1028  AddBufferByte(package, &StartBit, SM_PatternID_A_part, 2);
1029  AddBufferByte(package, &StartBit, ((unsigned char)(Loop<<4)), 4);
1030 
1031  /* Later here will be HowManyCommands */
1032  StartBitHowManyCommands=StartBit;
1033  StartBit = StartBit + 8;
1034 
1035  started = FALSE;
1036  for (i=0; i<ringtone->NoteTone.NrCommands; i++) {
1037  if (ringtone->NoteTone.Commands[i].Type != RING_Note) {
1038  HowManyNotes++;
1039  continue;
1040  }
1041  Note = &ringtone->NoteTone.Commands[i].Note;
1042  if (!started) {
1043  /* First note can't be Pause - it makes problems
1044  * for example with PC Composer
1045  */
1046  if (Note->Note != Note_Pause) started = TRUE;
1047  }
1048  if (!started) {
1049  HowManyNotes++;
1050  continue;
1051  }
1052  OldStartBit = StartBit;
1053  /* we don't write Scale & Style info before "Pause" note - it saves place */
1054  if (Note->Note!=Note_Pause) {
1055  if (DefScale != Note->Scale || ringtone->NoteTone.AllNotesScale) {
1056  j = StartBit+5+8;
1057  BufferAlignNumber(&j);
1058  if ((j/8)>(*maxlength)) {
1059  StartBit = OldStartBit;
1060  break;
1061  }
1062  DefScale = Note->Scale;
1063  AddBufferByte(package, &StartBit, SM_InstructionID_ScaleInstructionId, 3);
1064  AddBufferByte(package, &StartBit, ((unsigned char)((DefScale-4)<<6)), 2);
1065  HowManyCommands++;
1066  }
1067  if (DefStyle != Note->Style) {
1068  j = StartBit+5+8;
1069  BufferAlignNumber(&j);
1070  if ((j/8)>(*maxlength)) {
1071  StartBit = OldStartBit;
1072  break;
1073  }
1074  DefStyle = Note->Style;
1075  AddBufferByte(package, &StartBit, SM_InstructionID_StyleInstructionId, 3);
1076  AddBufferByte(package, &StartBit, ((unsigned char)DefStyle), 2);
1077  HowManyCommands++;
1078  }
1079  }
1080  /* Beats per minute/tempo of the tune */
1081  if (DefTempo != GSM_RTTLGetTempo(Note->Tempo)) {
1082  j = StartBit+8+8;
1083  BufferAlignNumber(&j);
1084  if ((j/8)>(*maxlength)) {
1085  StartBit = OldStartBit;
1086  break;
1087  }
1088  DefTempo=GSM_RTTLGetTempo(Note->Tempo);
1089  /* Adding beats per minute (tempo) of the tune */
1090  AddBufferByte(package, &StartBit, SM_InstructionID_TempoInstructionId, 3);
1091  AddBufferByte(package, &StartBit, ((unsigned char)DefTempo), 5);
1092  HowManyCommands++;
1093  }
1094  j = StartBit+12+8;
1095  BufferAlignNumber(&j);
1096  if ((j/8)>(*maxlength)) {
1097  StartBit = OldStartBit;
1098  break;
1099  }
1100  /* Note */
1101  AddBufferByte(package, &StartBit, SM_InstructionID_NoteInstructionId, 3);
1102  AddBufferByte(package, &StartBit, ((unsigned char)Note->Note), 4);
1103  AddBufferByte(package, &StartBit, ((unsigned char)Note->Duration), 3);
1104  AddBufferByte(package, &StartBit, ((unsigned char)Note->DurationSpec), 2);
1105  HowManyCommands++;
1106  /* We are sure, we pack it for SMS or setting to phone, not for OTT file */
1107  if (*maxlength<1000) {
1108  /* Like Pc Composer say - before of phone limitations...*/
1109  if (HowManyNotes==130-1) break;
1110  }
1111  HowManyNotes++;
1112  }
1113 
1114  BufferAlign(package, &StartBit);
1115  AddBufferByte(package, &StartBit, SM_CommandEnd_CommandEnd, 8);
1116 
1117  OldStartBit = StartBit;
1118  StartBit = StartBitHowManyCommands;
1119  /* HowManyCommands */
1120  AddBufferByte(package, &StartBit, ((unsigned char)HowManyCommands), 8);
1121  StartBit = OldStartBit;
1122 
1123  *maxlength=StartBit/8;
1124 
1125  return(i);
1126 }
1127 
1128 GSM_Error GSM_DecodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, size_t maxlength UNUSED)
1129 {
1130  size_t StartBit=0;
1131  int l, q, i, spec, HowMany;
1132  char Buffer[100];
1133  GSM_RingNote *Note;
1134 
1135  /* Default ringtone parameters */
1136  GSM_RingNoteScale DefScale = Scale_880;
1137  GSM_RingNoteStyle DefStyle = NaturalStyle;
1138  int DefTempo = 63;
1139 
1140  ringtone->Format = RING_NOTETONE;
1141  ringtone->NoteTone.NrCommands = 0;
1142 
1143  GetBufferInt(package,&StartBit,&l,8);
1144  if (l != 0x02) {
1145  dbgprintf(NULL, "Not header\n");
1146  return ERR_NOTSUPPORTED;
1147  }
1148 
1149  GetBufferInt(package,&StartBit,&l,7);
1151  dbgprintf(NULL, "Not RingingToneProgramming\n");
1152  return ERR_NOTSUPPORTED;
1153  }
1154 
1155  /* According to specification we need have next part octet-aligned */
1156  BufferAlignNumber(&StartBit);
1157 
1158  GetBufferInt(package,&StartBit,&l,7);
1159  if (l != SM_Command_Sound) {
1160  dbgprintf(NULL, "Not Sound\n");
1161  return ERR_NOTSUPPORTED;
1162  }
1163 
1164  GetBufferInt(package,&StartBit,&l,3);
1165  if (l != SM_Song_BasicSongType) {
1166  dbgprintf(NULL, "Not BasicSongType\n");
1167  return ERR_NOTSUPPORTED;
1168  }
1169 
1170  /* Getting length of the tune name */
1171  GetBufferInt(package,&StartBit,&l,4);
1172  l=l>>4;
1173 
1174  /* Unpacking the name of the tune. */
1175  GetBuffer(package, &StartBit, Buffer, 8*l);
1176  Buffer[l]=0;
1177  EncodeUnicode(ringtone->Name,Buffer,strlen(Buffer));
1178  DecodeUnicodeSpecialNOKIAChars(Buffer, ringtone->Name, UnicodeLength(ringtone->Name));
1179  CopyUnicodeString(ringtone->Name,Buffer);
1180 
1181  GetBufferInt(package,&StartBit,&l,8);
1182  dbgprintf(NULL, "Number of song patterns: %i\n",l);
1183  /* we support only one song pattern */
1184  if (l!=1) return ERR_NOTSUPPORTED;
1185 
1186  GetBufferInt(package,&StartBit,&l,3);
1188  dbgprintf(NULL, "Not PatternHeaderId\n");
1189  return ERR_NOTSUPPORTED;
1190  }
1191 
1192  /* Pattern ID - we ignore it */
1193  StartBit+=2;
1194 
1195  GetBufferInt(package,&StartBit,&l,4);
1196  l=l>>4;
1197  dbgprintf(NULL, "Loop value: %i\n",l);
1198 
1199  HowMany=0;
1200  GetBufferInt(package, &StartBit, &HowMany, 8);
1201 
1202  for (i=0;i<HowMany;i++) {
1203  GetBufferInt(package,&StartBit,&q,3);
1204  switch (q) {
1206  StartBit+=4;
1207  break;
1209  GetBufferInt(package,&StartBit,&l,2);
1210  if (l>=NaturalStyle && l<=StaccatoStyle) DefStyle = l;
1211  break;
1213  GetBufferInt(package,&StartBit,&l,5);
1214  DefTempo=SM_BeatsPerMinute[l>>3];
1215  break;
1217  GetBufferInt(package,&StartBit,&l,2);
1218  DefScale=(l>>6)+4;
1219  break;
1221  Note = &ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Note;
1222  ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_Note;
1223 
1224  GetBufferInt(package,&StartBit,&l,4);
1225  Note->Note=Note_Pause;
1226  if (l >= Note_C && l <= Note_H) Note->Note = l;
1227 
1228  GetBufferInt(package,&StartBit,&l,3);
1229  if (l >= Duration_Full && l <= Duration_1_32) Note->Duration = l;
1230 
1231  GetBufferInt(package,&StartBit,&spec,2);
1232  if (spec >= NoSpecialDuration && spec <= Length_2_3) {
1233  Note->DurationSpec = spec;
1234  }
1235 
1236  Note->Scale = DefScale;
1237  Note->Style = DefStyle;
1238  Note->Tempo = DefTempo;
1239  if (ringtone->NoteTone.NrCommands==GSM_MAX_RINGTONE_NOTES) break;
1240  ringtone->NoteTone.NrCommands++;
1241  break;
1242  default:
1243  dbgprintf(NULL, "Unsupported block %i %i\n",q,i);
1244  return ERR_NOTSUPPORTED;
1245  }
1246  }
1247  return ERR_NONE;
1248 }
1249 
1250 static void RTTL2Binary(GSM_Ringtone *dest, GSM_Ringtone *src)
1251 {
1252  int current = 0, i, note, lastnote = 0, duration;
1253  GSM_RingNote *Note;
1254  unsigned char end[] = {0x40, 0x7D, 0x40, 0x5C, 0x0A, 0xFE, 0x40,
1255  0x20, 0x40, 0x7D, 0x40, 0x37, 0x0A, 0xFE,
1256  0x0A, 0x0A, 0x40, 0x32, 0x07, 0x0B};
1257 
1258  strcpy(dest->NokiaBinary.Frame+current,"\x02\xFC\x09"); current=current+3;
1259  dest->NokiaBinary.Frame[current++]=0x00;
1260 
1261 /* This command can be used to loop, where 0xLL = 0x01 - 0x10
1262  * 0x01=loop once [...] 0x10=loop infinite
1263  * Commented now
1264 
1265  dest->NokiaBinary.Frame[current++]=0x05;
1266  dest->NokiaBinary.Frame[current++]=0xLL;
1267  */
1268  strcpy(dest->NokiaBinary.Frame+current,"\x0A\x01"); current=current+2;
1269 
1270  for (i=0; i<src->NoteTone.NrCommands; i++) {
1271  if (src->NoteTone.Commands[i].Type != RING_Note) continue;
1272 
1273  Note = &src->NoteTone.Commands[i].Note;
1274  note = 64; /* Pause */
1275  if (Note->Note!=Note_Pause) {
1276  if (Note->Note >= Note_C && Note->Note <= Note_H) {
1277  note = 113 + Note->Note/16;
1278  }
1279  switch (Note->Scale) {
1280  case Scale_440 : break;
1281  case Scale_880 : note = note + 12; break;
1282  case Scale_1760: note = note + 24; break;
1283  case Scale_3520: note = note + 36; break;
1284  default : break;
1285  }
1286  }
1287 
1288  /* In 7110 we have 8 ms long sounds */
1289  duration = 60000 * GSM_RingNoteGetFullDuration(*Note) / Note->Tempo / 256;
1290 
1291  switch (Note->Style) {
1292  case StaccatoStyle:
1293  if (duration) {
1294  /* Note needs only one sound */
1295  dest->NokiaBinary.Frame[current++] = note;
1296  dest->NokiaBinary.Frame[current++] = 1;
1297  duration--;
1298  }
1299  note = 0x40; /* The rest is pause */
1300  case NaturalStyle:
1301  if (note != 0x40 && duration) {
1302  dest->NokiaBinary.Frame[current++] = 0x40;
1303  /* There is small pause between notes */
1304  dest->NokiaBinary.Frame[current++] = 1;
1305  duration--;
1306  }
1307  default:
1308  if (note != 0x40 && note == lastnote && duration) {
1309  dest->NokiaBinary.Frame[current++] = 0x40;
1310  /* There is small pause between same notes */
1311  dest->NokiaBinary.Frame[current++] = 1;
1312  duration--;
1313  }
1314  while (duration > 125) {
1315  dest->NokiaBinary.Frame[current++] = note;
1316  dest->NokiaBinary.Frame[current++] = 125;
1317  duration -= 125;
1318  }
1319  dest->NokiaBinary.Frame[current++] = note;
1320  dest->NokiaBinary.Frame[current++] = duration;
1321  }
1322  lastnote = note;
1323  }
1324  for (i = 0; i < (int)sizeof(end); i++) dest->NokiaBinary.Frame[current++] = end[i];
1325  dest->NokiaBinary.Length=current;
1326 }
1327 
1328 static void Binary2RTTL(GSM_Ringtone *dest, GSM_Ringtone *src)
1329 {
1330  size_t NrNotes = 0, i = 3, j, StartRepeat = 0, EndRepeat;
1331  int z, repeat = 0, accuracy;
1332  int Speed;
1333  unsigned char command,length=0;
1334  int NotesLen[500];
1335  GSM_RingNoteScale NotesScale[500];
1336  GSM_RingNoteNote Notes[500];
1337  int Lengths[6*4];
1338  GSM_RingNoteDurationSpec DurationSpec[6*4];
1339  GSM_RingNoteDuration Duration[6*4];
1340  gboolean foundlen;
1341  GSM_RingNote *Note;
1342 
1343  while (i<src->NokiaBinary.Length) {
1344  command = src->NokiaBinary.Frame[i];
1345  i++;
1346  if (command != 0x06 && command != 0x00 && command != 0x09) {
1347  length = src->NokiaBinary.Frame[i];
1348  i++;
1349  dbgprintf(NULL, "Block %02x %02x - ",length,command);
1350  } else dbgprintf(NULL, "Block %02x - ",command);
1351  if (command >= 114 && command <= 161) {
1352  dbgprintf(NULL, "note\n");
1353  if (command >= 114 && command <= 124) {
1354  NotesScale[NrNotes] = Scale_440; command -= 114;
1355  } else if (command >= 125 && command <= 137) {
1356  NotesScale[NrNotes] = Scale_880; command -= 126;
1357  } else if (command >= 138 && command <= 149) {
1358  NotesScale[NrNotes] = Scale_1760; command -= 138;
1359  } else if (command >= 150 && command <= 161) {
1360  NotesScale[NrNotes] = Scale_3520; command -= 150;
1361  } else {
1362  NotesScale[NrNotes] = Scale_440;
1363  }
1364  switch (command) {
1365  case 0 : Notes[NrNotes] = Note_C; break;
1366  case 1 : Notes[NrNotes] = Note_Cis; break;
1367  case 2 : Notes[NrNotes] = Note_D; break;
1368  case 3 : Notes[NrNotes] = Note_Dis; break;
1369  case 4 : Notes[NrNotes] = Note_E; break;
1370  case 5 : Notes[NrNotes] = Note_F; break;
1371  case 6 : Notes[NrNotes] = Note_Fis; break;
1372  case 7 : Notes[NrNotes] = Note_G; break;
1373  case 8 : Notes[NrNotes] = Note_Gis; break;
1374  case 9 : Notes[NrNotes] = Note_A; break;
1375  case 10 : Notes[NrNotes] = Note_Ais; break;
1376  case 11 : Notes[NrNotes] = Note_H; break;
1377  default : Notes[NrNotes] = Note_Pause; break;
1378  }
1379  if (NrNotes > 0 &&
1380  Notes[NrNotes - 1] == Notes[NrNotes] &&
1381  NotesScale[NrNotes - 1] == NotesScale[NrNotes]) {
1382  NotesLen[NrNotes - 1] += length;
1383  } else {
1384  NotesLen[NrNotes] = length;
1385  NrNotes++;
1386  }
1387  } else switch (command) {
1388  case 0x00:
1389  dbgprintf(NULL, "Unknown\n");
1390  break;
1391  case 0x05:
1392  dbgprintf(NULL, "repeat %i times\n",length);
1393  repeat = length;
1394  StartRepeat = NrNotes;
1395  break;
1396  case 0x06:
1397  dbgprintf(NULL, "end repeat\n");
1398  EndRepeat = NrNotes;
1399  for (z=0;z<repeat-1;z++) {
1400  for (j=StartRepeat;j<EndRepeat;j++) {
1401  Notes[NrNotes] = Notes[j];
1402  NotesScale[NrNotes] = NotesScale[j];
1403  NotesLen[NrNotes] = NotesLen[j];
1404  NrNotes++;
1405  dbgprintf(NULL, "Adding repeat note %i %i\n",Notes[j],NotesLen[j]);
1406  }
1407  }
1408  break;
1409  case 0x07:
1410  if (length == 0x0B) {
1411  dbgprintf(NULL, "Ringtone end\n");
1412  i = src->NokiaBinary.Length + 1;
1413  }
1414  break;
1415  case 0x09:
1416  dbgprintf(NULL, "Unknown\n");
1417  break;
1418  case 0x0A:
1419  if (length == 0x01) {
1420  dbgprintf(NULL, "Let's start our song\n");
1421  break;
1422  }
1423  if (length == 0x0A) {
1424  dbgprintf(NULL, "Ending joining note\n");
1425  break;
1426  }
1427  if (length == 0xFE) {
1428  dbgprintf(NULL, "Starting joining note\n");
1429  break;
1430  }
1431  break;
1432  case 0x40:
1433  dbgprintf(NULL, "Pause\n");
1434  Notes[NrNotes] = Note_Pause;
1435  if (NrNotes > 0 &&
1436  Notes[NrNotes - 1] == Notes[NrNotes]) {
1437  NotesLen[NrNotes - 1] += length;
1438  } else {
1439  NotesLen[NrNotes] = length;
1440  NotesScale[NrNotes] = 0;
1441  NrNotes++;
1442  }
1443  break;
1444  default:
1445  dbgprintf(NULL, "Unknown\n");
1446  }
1447  }
1448 
1449  while (NrNotes > 0 && Notes[NrNotes-1] == Note_Pause) {
1450  NrNotes--;
1451  }
1452 
1453  for (accuracy=1; accuracy<5; accuracy++) {
1454  i = 1;
1455  while (i < 1000) {
1456  Lengths[0] = 30000/i;
1457  for (j=0;j<5;j++) Lengths[j+1] = Lengths[j] / 2;
1458  for (j=0;j<6;j++) Lengths[6+j] = Lengths[j] * 3/2;
1459  for (j=0;j<6;j++) Lengths[12+j] = Lengths[j] * 9/4;
1460  for (j=0;j<6;j++) Lengths[18+j] = Lengths[j] * 2/3;
1461 
1462 #ifdef DEBUG
1463  dbgprintf(NULL, "Length matrix (%ld) : ", (long)i);
1464  for (j=0;j<6*4;j++) dbgprintf(NULL, "%i ",Lengths[j]);
1465  dbgprintf(NULL, "\n");
1466 #endif
1467  foundlen = FALSE;
1468 
1469  for (j=0;j<NrNotes;j++) {
1470  dbgprintf(NULL, "Comparing to %i\n",NotesLen[j]);
1471  foundlen = FALSE;
1472  for (z=0;z<6*4;z++) {
1473  if (NotesLen[j] - Lengths[z] > -accuracy &&
1474  NotesLen[j] - Lengths[z] < accuracy) {
1475  foundlen = TRUE;
1476  break;
1477  }
1478  }
1479  if (!foundlen) break;
1480  }
1481  if (foundlen) break;
1482  i++;
1483  }
1484 
1485  if (foundlen) {
1486  Speed = i;
1487  Duration[5] = Duration_1_32; Duration[4] = Duration_1_16;
1488  Duration[3] = Duration_1_8; Duration[2] = Duration_1_4;
1489  Duration[1] = Duration_1_2; Duration[0] = Duration_Full;
1490  for (i=0;i<6;i++) Duration[i] = Duration[i];
1491  for (i=0;i<6;i++) Duration[i+6] = Duration[i];
1492  for (i=0;i<6;i++) Duration[i+12] = Duration[i];
1493  for (i=0;i<6;i++) Duration[i+18] = Duration[i];
1494  for (i=0;i<6;i++) DurationSpec[i] = NoSpecialDuration;
1495  for (i=0;i<6;i++) DurationSpec[i+6] = DottedNote;
1496  for (i=0;i<6;i++) DurationSpec[i+12] = DoubleDottedNote;
1497  for (i=0;i<6;i++) DurationSpec[i+18] = Length_2_3;
1498 
1499  for (i=0;i<NrNotes;i++) {
1500  dest->NoteTone.Commands[i].Type = RING_Note;
1501  Note = &dest->NoteTone.Commands[i].Note;
1502  Note->Note = Notes[i];
1503  Note->Tempo = Speed;
1504  Note->Style = ContinuousStyle;
1505  if (Notes[i] != Note_Pause) Note->Scale = NotesScale[i];
1506  for (z=0;z<6*4;z++) {
1507  if (NotesLen[i] - Lengths[z] > -accuracy &&
1508  NotesLen[i] - Lengths[z] < accuracy) {
1509  Note->Duration = Duration[z];
1510  Note->DurationSpec = DurationSpec[z];
1511  /* Trick from PPM Edit */
1512  if (Note->DurationSpec == DoubleDottedNote) {
1513  switch (Note->Duration) {
1514  case Duration_INVALID: break;
1515  case Duration_Full:Note->Duration = Duration_Full;break;
1516  case Duration_1_2 :Note->Duration = Duration_Full;break;
1517  case Duration_1_4 :Note->Duration = Duration_1_2; break;
1518  case Duration_1_8 :Note->Duration = Duration_1_4; break;
1519  case Duration_1_16:Note->Duration = Duration_1_8; break;
1520  case Duration_1_32:Note->Duration = Duration_1_16;break;
1521  }
1523  }
1524  /* Here happy creation */
1525  if (Note->DurationSpec == Length_2_3) {
1527  }
1528 
1529  break;
1530  }
1531  }
1532  }
1533  dest->NoteTone.NrCommands = NrNotes;
1534  dbgprintf(NULL, "speed = %i\n",Speed);
1535  break;
1536  }
1537  }
1538 
1539  dest->NoteTone.AllNotesScale = FALSE;
1540  if (!foundlen) dest->NoteTone.NrCommands = 0;
1541 }
1542 
1544 {
1545  dest->Format = Format;
1546  CopyUnicodeString(dest->Name,src->Name);
1547  if (src->Format==RING_NOTETONE && Format==RING_NOKIABINARY) {
1548  RTTL2Binary(dest, src);
1549  return ERR_NONE;
1550  }
1551  if (src->Format==RING_NOKIABINARY && Format==RING_NOTETONE) {
1552  Binary2RTTL(dest, src);
1553  return ERR_NONE;
1554  }
1555  /* The same source and target format */
1556  if (src->Format==Format) {
1557  memcpy(dest,src,sizeof(GSM_Ringtone));
1558  return ERR_NONE;
1559  }
1560  return ERR_NOTIMPLEMENTED;
1561 }
1562 
1563 /* 0 = No header and footer, 0.5 = partial header and footer,
1564  * 1.0 = IMelody 1.0, 1.2 = IMelody 1.2 */
1565 unsigned char GSM_EncodeEMSSound(GSM_Ringtone *ringtone, unsigned char *package, size_t *maxlength, GSM_RingtoneVersion version, gboolean start)
1566 {
1567  int i, NrNotes = 0, Len, Max = *maxlength;
1568 
1569  GSM_RingNote *Note;
1570 
1571  GSM_RingNoteScale DefNoteScale;
1572  GSM_RingNoteStyle DefNoteStyle=0;
1573  int DefNoteTempo=0;
1574 
1575  gboolean started = FALSE, end;
1576 
1577  *maxlength = 0;
1578 
1579  if (start) {
1580  if (version != GSM_Ring_NoHeader)
1581  *maxlength+=sprintf(package,"BEGIN:IMELODY%c%c",13,10);
1582  if (version == GSM_Ring_IMelody10)
1583  *maxlength+=sprintf(package+(*maxlength),"VERSION:1.0%c%c",13,10);
1584  if (version == GSM_Ring_IMelody12)
1585  *maxlength+=sprintf(package+(*maxlength),"VERSION:1.2%c%c",13,10);
1586  if (version == GSM_Ring_IMelody12 || version == GSM_Ring_IMelody10)
1587  *maxlength+=sprintf(package+(*maxlength),"FORMAT:CLASS1.0%c%c",13,10);
1588  if (version == GSM_Ring_IMelody12)
1589  *maxlength+=sprintf(package+(*maxlength),"NAME:%s%c%c",DecodeUnicodeString(ringtone->Name),13,10);
1590  }
1591 
1592  DefNoteScale = Scale_880; /* by iMelody definition */
1593 
1594  for (i=0;i<ringtone->NoteTone.NrCommands;i++) {
1595  Len = *maxlength;
1596  if (ringtone->NoteTone.Commands[i].Type != RING_Note) continue;
1597 
1598  Note = &ringtone->NoteTone.Commands[i].Note;
1599  if (Note->Note == Note_Pause) continue;
1600 
1601  if (version == GSM_Ring_IMelody12 && start) {
1602  /* Save the default tempo */
1603  DefNoteTempo = Note->Tempo;
1604  Len+=sprintf(package+Len,"BEAT:%i%c%c",DefNoteTempo,13,10);
1605  dbgprintf(NULL, "DefNoteTempo=%d\n",DefNoteTempo);
1606 
1607  /* Save default style */
1608  DefNoteStyle = Note->Style;
1609  switch (DefNoteStyle) {
1610  case INVALIDStyle: break;
1611  case NaturalStyle :Len+=sprintf(package+Len,"STYLE:S0%c%c",13,10); break;
1612  case ContinuousStyle:Len+=sprintf(package+Len,"STYLE:S1%c%c",13,10); break;
1613  case StaccatoStyle :Len+=sprintf(package+Len,"STYLE:S2%c%c",13,10); break;
1614  }
1615  }
1616  Len+=sprintf(package+Len,"MELODY:");
1617  if (version != GSM_Ring_NoHeader) {
1618  /* 15 = Len of END:IMELODY... */
1619  if ((Len+15) > Max) { break; }
1620  } else {
1621  if (Len > Max) { break; }
1622  }
1623  *maxlength = Len;
1624  break;
1625  }
1626 
1627  for (i=0;i<ringtone->NoteTone.NrCommands;i++) {
1628  end = FALSE;
1629  Len = *maxlength;
1630  switch (ringtone->NoteTone.Commands[i].Type) {
1631  case RING_Note:
1632  Note = &ringtone->NoteTone.Commands[i].Note;
1633  if (!started && Note->Note != Note_Pause) started = TRUE;
1634  if (!started) break;
1635  if (Note->Note!=Note_Pause && Note->Scale != DefNoteScale) {
1636  Len+=sprintf(package+Len,"*%i",Note->Scale-1);
1637  }
1638  switch (Note->Note) {
1639  case Note_C :Len+=sprintf(package+Len,"c"); break;
1640  case Note_Cis :Len+=sprintf(package+Len,"#c");break;
1641  case Note_D :Len+=sprintf(package+Len,"d"); break;
1642  case Note_Dis :Len+=sprintf(package+Len,"#d");break;
1643  case Note_E :Len+=sprintf(package+Len,"e"); break;
1644  case Note_F :Len+=sprintf(package+Len,"f"); break;
1645  case Note_Fis :Len+=sprintf(package+Len,"#f");break;
1646  case Note_G :Len+=sprintf(package+Len,"g"); break;
1647  case Note_Gis :Len+=sprintf(package+Len,"#g");break;
1648  case Note_A :Len+=sprintf(package+Len,"a"); break;
1649  case Note_Ais :Len+=sprintf(package+Len,"#a");break;
1650  case Note_H :Len+=sprintf(package+Len,"b"); break;
1651  case Note_Pause :Len+=sprintf(package+Len,"r"); break;
1652  case Note_INVALID: break;
1653  }
1654  switch (Note->Duration) {
1655  case Duration_Full : package[Len++]='0'; break;
1656  case Duration_1_2 : package[Len++]='1'; break;
1657  case Duration_1_4 : package[Len++]='2'; break;
1658  case Duration_1_8 : package[Len++]='3'; break;
1659  case Duration_1_16 : package[Len++]='4'; break;
1660  case Duration_1_32 : package[Len++]='5'; break;
1661  default : break;
1662  }
1663  switch (Note->DurationSpec) {
1664  case DottedNote : package[Len++] = '.'; break;
1665  case DoubleDottedNote : package[Len++] = ':'; break;
1666  case Length_2_3 : package[Len++] = ';'; break;
1667  default : break;
1668  }
1669  if (version != 0) {
1670  /* 15 = Len of END:IMELODY... */
1671  if ((Len+15) > Max) { end = TRUE; break; }
1672  } else {
1673  if (Len > Max) { end = TRUE; break; }
1674  }
1675  *maxlength = Len;
1676  break;
1677  case RING_DisableLED:
1678  if ((Len + 6) > Max) { end = TRUE; break; }
1679  (*maxlength)+=sprintf(package+Len,"ledoff");
1680  break;
1681  case RING_EnableLED:
1682  if ((Len + 5) > Max) { end = TRUE; break; }
1683  (*maxlength)+=sprintf(package+Len,"ledon");
1684  break;
1685  case RING_DisableVibra:
1686  if ((Len + 7) > Max) { end = TRUE; break; }
1687  (*maxlength)+=sprintf(package+Len,"vibeoff");
1688  break;
1689  case RING_EnableVibra:
1690  if ((Len + 6) > Max) { end = TRUE; break; }
1691  (*maxlength)+=sprintf(package+Len,"vibeon");
1692  break;
1693  case RING_DisableLight:
1694  if ((Len + 7) > Max) { end = TRUE; break; }
1695  (*maxlength)+=sprintf(package+Len,"backoff");
1696  break;
1697  case RING_EnableLight:
1698  if ((Len + 6) > Max) { end = TRUE; break; }
1699  (*maxlength)+=sprintf(package+Len,"backon");
1700  break;
1701  default:
1702  break;
1703  }
1704  if (end) break;
1705  NrNotes ++;
1706  }
1707 
1708  if (version != 0) *maxlength+=sprintf(package+(*maxlength),"%c%cEND:IMELODY%c%c",13,10,13,10);
1709 
1710  return NrNotes;
1711 }
1712 
1713 const unsigned char *GSM_GetRingtoneName(const GSM_AllRingtonesInfo *Info, const int ID)
1714 {
1715  int i;
1716 
1717  for (i = 0; i < Info->Number; i++) {
1718  if (Info->Ringtone[i].ID == ID) {
1719  return Info->Ringtone[i].Name;
1720  }
1721  }
1722 
1723  return NULL;
1724 }
1725 
1726 /* How should editor hadle tabs in this file? Add editor commands here.
1727  * vim: noexpandtab sw=8 ts=8 sts=8:
1728  */
GSM_RingCommand Commands[GSM_MAX_RINGTONE_NOTES]
GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
Definition: gsmring.c:874
int GSM_RingNoteGetFrequency(GSM_RingNote Note)
Definition: gsmring.c:40
unsigned char Name[(GSM_MAX_RINGTONE_NAME_LENGTH+1) *2]
GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
Definition: gsmring.c:494
#define WAV_SAMPLE_RATE
Definition: gsmring.c:103
static GSM_Error loadott(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:771
#define PI
Definition: gsmring.c:100
GSM_RingNoteDurationSpec
GSM_Error GSM_SaveRingtoneMidi(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:413
#define SM_InstructionID_StyleInstructionId
Definition: gsmring.h:25
char * DecodeUnicodeString(const unsigned char *src)
Definition: coding.c:245
GSM_RingtoneFormat Format
#define SM_InstructionID_TempoInstructionId
Definition: gsmring.h:26
void CopyUnicodeString(unsigned char *Dest, const unsigned char *Source)
Definition: coding.c:1192
static GSM_Error loadcommunicator(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:781
static GSM_Error loadmmf(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:829
GSM_RingNoteDuration Duration
void AddBufferByte(unsigned char *Destination, size_t *CurrentBit, unsigned char Source, size_t BitsToProcess)
Definition: coding.c:1303
GSM_RingNoteNote Note
void BufferAlign(unsigned char *Destination, size_t *CurrentBit)
Definition: coding.c:1263
static GSM_Error loadbin(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:800
void GetBufferInt(unsigned char *Source, size_t *CurrentBit, int *integer, size_t BitsToProcess)
Definition: coding.c:1329
GSM_RingNoteScale Scale
GSM_RingtoneVersion
Definition: gsmring.h:31
static void RTTL2Binary(GSM_Ringtone *dest, GSM_Ringtone *src)
Definition: gsmring.c:1250
GSM_Error
Definition: gammu-error.h:23
#define GSM_MAX_RINGTONE_NAME_LENGTH
Definition: gammu-limits.h:232
GSM_RingCommandType Type
#define SM_InstructionID_NoteInstructionId
Definition: gsmring.h:23
GSM_RingNoteScale
size_t UnicodeLength(const unsigned char *str)
Definition: coding.c:186
GSM_RingNoteNote
#define SM_InstructionID_ScaleInstructionId
Definition: gsmring.h:24
unsigned char GSM_EncodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, size_t *maxlength)
Definition: gsmring.c:992
GSM_NoteRingtone NoteTone
void BufferAlignNumber(size_t *CurrentBit)
Definition: coding.c:1275
int GSM_RTTLGetTempo(int Beats)
Definition: gsmring.c:979
static GSM_Error loadrttl(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:537
static GSM_Error savemmf(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:193
#define SM_CommandEnd_CommandEnd
Definition: gsmring.h:9
static int SM_BeatsPerMinute[]
Definition: gsmring.c:972
#define SM_Command_RingingToneProgramming
Definition: gsmring.h:12
#define GSM_MAX_RINGTONE_NOTES
Definition: gammu-limits.h:225
int gboolean
Definition: gammu-types.h:23
GSM_Error GSM_SaveRingtoneRttl(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:201
void GetBuffer(unsigned char *Source, size_t *CurrentBit, unsigned char *Destination, size_t BitsToProcess)
Definition: coding.c:1311
void EncodeUnicode(unsigned char *dest, const char *src, size_t len)
Definition: coding.c:301
#define FALSE
Definition: gammu-types.h:25
static GSM_Error loadre(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:853
const unsigned char * GSM_GetRingtoneName(const GSM_AllRingtonesInfo *Info, const int ID)
Definition: gsmring.c:1713
GSM_RingNoteStyle Style
GSM_NokiaBinaryRingtone NokiaBinary
unsigned char Frame[50000]
unsigned char * Buffer
GSM_RingtoneInfo * Ringtone
GSM_RingNoteDurationSpec DurationSpec
int GSM_RingNoteGetFullDuration(GSM_RingNote Note)
Definition: gsmring.c:76
static GSM_Error loadpuremidi(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:819
static void Binary2RTTL(GSM_Ringtone *dest, GSM_Ringtone *src)
Definition: gsmring.c:1328
GSM_RingNoteStyle
GSM_RingtoneFormat
static GSM_Error savebin(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:169
GSM_Error GSM_DecodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, size_t maxlength UNUSED)
Definition: gsmring.c:1128
GSM_BinaryTone BinaryTone
void AddBuffer(unsigned char *Destination, size_t *CurrentBit, unsigned char *Source, size_t BitsToProcess)
Definition: coding.c:1286
void DecodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, size_t len)
Definition: coding.c:1401
#define dbgprintf
Definition: debug.h:72
void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, size_t len)
Definition: coding.c:1367
static GSM_Error savepuremidi(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:185
unsigned char Name[30 *2]
GSM_Error GSM_SaveRingtoneWav(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:105
static void WriteVarLen(unsigned char *midifile, size_t *current, long value)
Definition: gsmring.c:390
GSM_Error GSM_RingtoneConvert(GSM_Ringtone *dest, GSM_Ringtone *src, GSM_RingtoneFormat Format)
Definition: gsmring.c:1543
GSM_Error GSM_SaveRingtoneIMelody(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:377
#define TRUE
Definition: gammu-types.h:28
#define SM_InstructionID_VolumeInstructionId
Definition: gsmring.h:27
unsigned char GSM_EncodeEMSSound(GSM_Ringtone *ringtone, unsigned char *package, size_t *maxlength, GSM_RingtoneVersion version, gboolean start)
Definition: gsmring.c:1565
#define UNUSED
Definition: gammu-misc.h:105
GSM_RingNoteDuration
GSM_RingNote Note
#define SM_InstructionID_PatternHeaderId
Definition: gsmring.h:22
#define SM_Command_Sound
Definition: gsmring.h:13
#define SM_PatternID_A_part
Definition: gsmring.h:19
GSM_Error GSM_SaveRingtoneOtt(FILE *file, GSM_Ringtone *ringtone)
Definition: gsmring.c:481
#define chk_fwrite(data, size, count, file)
Definition: gsmring.c:37
#define SM_Song_BasicSongType
Definition: gsmring.h:16
gboolean AllNotesScale