-rw-r--r-- | gammu/emb/common/common.pro | 1 | ||||
-rw-r--r-- | gammu/emb/common/service/gsmring.c | 6 |
2 files changed, 6 insertions, 1 deletions
diff --git a/gammu/emb/common/common.pro b/gammu/emb/common/common.pro index 9342cb7..0e719ee 100644 --- a/gammu/emb/common/common.pro +++ b/gammu/emb/common/common.pro | |||
@@ -1,186 +1,187 @@ | |||
1 | ###################################################################### | 1 | ###################################################################### |
2 | # Automatically generated by qmake (1.07a) Fri Jul 30 22:13:34 2004 | 2 | # Automatically generated by qmake (1.07a) Fri Jul 30 22:13:34 2004 |
3 | ###################################################################### | 3 | ###################################################################### |
4 | 4 | ||
5 | TEMPLATE = lib | 5 | TEMPLATE = lib |
6 | DEPENDPATH += device \ | 6 | DEPENDPATH += device \ |
7 | misc \ | 7 | misc \ |
8 | phone \ | 8 | phone \ |
9 | protocol \ | 9 | protocol \ |
10 | service \ | 10 | service \ |
11 | device/bluetoth \ | 11 | device/bluetoth \ |
12 | device/irda \ | 12 | device/irda \ |
13 | device/serial \ | 13 | device/serial \ |
14 | misc/coding \ | 14 | misc/coding \ |
15 | phone/alcatel \ | 15 | phone/alcatel \ |
16 | phone/at \ | 16 | phone/at \ |
17 | phone/nokia \ | 17 | phone/nokia \ |
18 | phone/obex \ | 18 | phone/obex \ |
19 | phone/symbian \ | 19 | phone/symbian \ |
20 | protocol/alcatel \ | 20 | protocol/alcatel \ |
21 | protocol/at \ | 21 | protocol/at \ |
22 | protocol/nokia \ | 22 | protocol/nokia \ |
23 | protocol/obex \ | 23 | protocol/obex \ |
24 | protocol/symbian \ | 24 | protocol/symbian \ |
25 | service/backup \ | 25 | service/backup \ |
26 | service/sms \ | 26 | service/sms \ |
27 | phone/nokia/dct3 \ | 27 | phone/nokia/dct3 \ |
28 | phone/nokia/dct4 | 28 | phone/nokia/dct4 |
29 | INCLUDEPATH += . \ | 29 | INCLUDEPATH += . \ |
30 | misc/coding \ | 30 | misc/coding \ |
31 | misc \ | 31 | misc \ |
32 | device \ | 32 | device \ |
33 | phone/nokia/dct4 \ | 33 | phone/nokia/dct4 \ |
34 | phone/nokia/dct3 \ | 34 | phone/nokia/dct3 \ |
35 | phone/at \ | 35 | phone/at \ |
36 | phone/alcatel \ | 36 | phone/alcatel \ |
37 | phone/obex \ | 37 | phone/obex \ |
38 | phone/symbian \ | 38 | phone/symbian \ |
39 | protocol \ | 39 | protocol \ |
40 | protocol/nokia \ | 40 | protocol/nokia \ |
41 | protocol/at \ | 41 | protocol/at \ |
42 | protocol/alcatel \ | 42 | protocol/alcatel \ |
43 | protocol/obex \ | 43 | protocol/obex \ |
44 | protocol/symbian \ | 44 | protocol/symbian \ |
45 | device/serial \ | 45 | device/serial \ |
46 | device/irda \ | 46 | device/irda \ |
47 | device/bluetoth \ | 47 | device/bluetoth \ |
48 | service \ | 48 | service \ |
49 | service/sms \ | 49 | service/sms \ |
50 | service/backup \ | 50 | service/backup \ |
51 | phone/nokia \ | 51 | phone/nokia \ |
52 | phone | 52 | phone |
53 | 53 | ||
54 | # Input | 54 | # Input |
55 | HEADERS += config.h \ | 55 | HEADERS += config.h \ |
56 | gammu.h \ | 56 | gammu.h \ |
57 | gsmcomon.h \ | 57 | gsmcomon.h \ |
58 | gsmstate.h \ | 58 | gsmstate.h \ |
59 | device/devfunc.h \ | 59 | device/devfunc.h \ |
60 | misc/cfg.h \ | 60 | misc/cfg.h \ |
61 | misc/misc.h \ | 61 | misc/misc.h \ |
62 | phone/pfunc.h \ | 62 | phone/pfunc.h \ |
63 | protocol/protocol.h \ | 63 | protocol/protocol.h \ |
64 | service/gsmcal.h \ | 64 | service/gsmcal.h \ |
65 | service/gsmcall.h \ | 65 | service/gsmcall.h \ |
66 | service/gsmdata.h \ | 66 | service/gsmdata.h \ |
67 | service/gsmlogo.h \ | 67 | service/gsmlogo.h \ |
68 | service/gsmmisc.h \ | 68 | service/gsmmisc.h \ |
69 | service/gsmnet.h \ | 69 | service/gsmnet.h \ |
70 | service/gsmpbk.h \ | 70 | service/gsmpbk.h \ |
71 | service/gsmprof.h \ | 71 | service/gsmprof.h \ |
72 | service/gsmring.h \ | 72 | service/gsmring.h \ |
73 | device/bluetoth/affix.h \ | 73 | device/bluetoth/affix.h \ |
74 | device/bluetoth/blue_w32.h \ | 74 | device/bluetoth/blue_w32.h \ |
75 | device/bluetoth/bluetoth.h \ | 75 | device/bluetoth/bluetoth.h \ |
76 | device/bluetoth/bluez.h \ | 76 | device/bluetoth/bluez.h \ |
77 | device/irda/irda.h \ | 77 | device/irda/irda.h \ |
78 | device/irda/irda_unx.h \ | 78 | device/irda/irda_unx.h \ |
79 | device/irda/irda_w32.h \ | 79 | device/irda/irda_w32.h \ |
80 | device/serial/ser_djg.h \ | 80 | device/serial/ser_djg.h \ |
81 | device/serial/ser_unx.h \ | 81 | device/serial/ser_unx.h \ |
82 | device/serial/ser_w32.h \ | 82 | device/serial/ser_w32.h \ |
83 | misc/coding/coding.h \ | 83 | misc/coding/coding.h \ |
84 | misc/coding/md5.h \ | 84 | misc/coding/md5.h \ |
85 | phone/alcatel/alcatel.h \ | 85 | phone/alcatel/alcatel.h \ |
86 | phone/at/atgen.h \ | 86 | phone/at/atgen.h \ |
87 | phone/nokia/ncommon.h \ | 87 | phone/nokia/ncommon.h \ |
88 | phone/nokia/nfunc.h \ | 88 | phone/nokia/nfunc.h \ |
89 | phone/nokia/nfuncold.h \ | 89 | phone/nokia/nfuncold.h \ |
90 | phone/obex/obexgen.h \ | 90 | phone/obex/obexgen.h \ |
91 | phone/symbian/mroutgen.h \ | 91 | phone/symbian/mroutgen.h \ |
92 | protocol/alcatel/alcabus.h \ | 92 | protocol/alcatel/alcabus.h \ |
93 | protocol/at/at.h \ | 93 | protocol/at/at.h \ |
94 | protocol/nokia/fbus2.h \ | 94 | protocol/nokia/fbus2.h \ |
95 | protocol/nokia/mbus2.h \ | 95 | protocol/nokia/mbus2.h \ |
96 | protocol/nokia/phonet.h \ | 96 | protocol/nokia/phonet.h \ |
97 | protocol/obex/obex.h \ | 97 | protocol/obex/obex.h \ |
98 | protocol/symbian/mrouter.h \ | 98 | protocol/symbian/mrouter.h \ |
99 | service/backup/backgen.h \ | 99 | service/backup/backgen.h \ |
100 | service/backup/backics.h \ | 100 | service/backup/backics.h \ |
101 | service/backup/backldif.h \ | 101 | service/backup/backldif.h \ |
102 | service/backup/backlmb.h \ | 102 | service/backup/backlmb.h \ |
103 | service/backup/backtext.h \ | 103 | service/backup/backtext.h \ |
104 | service/backup/backvcf.h \ | 104 | service/backup/backvcf.h \ |
105 | service/backup/backvcs.h \ | 105 | service/backup/backvcs.h \ |
106 | service/backup/gsmback.h \ | 106 | service/backup/gsmback.h \ |
107 | service/sms/gsmems.h \ | 107 | service/sms/gsmems.h \ |
108 | service/sms/gsmmulti.h \ | 108 | service/sms/gsmmulti.h \ |
109 | service/sms/gsmsms.h \ | 109 | service/sms/gsmsms.h \ |
110 | phone/nokia/dct3/dct3comm.h \ | 110 | phone/nokia/dct3/dct3comm.h \ |
111 | phone/nokia/dct3/dct3func.h \ | 111 | phone/nokia/dct3/dct3func.h \ |
112 | phone/nokia/dct3/n6110.h \ | 112 | phone/nokia/dct3/n6110.h \ |
113 | phone/nokia/dct3/n7110.h \ | 113 | phone/nokia/dct3/n7110.h \ |
114 | phone/nokia/dct3/n9210.h \ | 114 | phone/nokia/dct3/n9210.h \ |
115 | phone/nokia/dct4/dct4func.h \ | 115 | phone/nokia/dct4/dct4func.h \ |
116 | phone/nokia/dct4/n3320.h \ | 116 | phone/nokia/dct4/n3320.h \ |
117 | phone/nokia/dct4/n3650.h \ | 117 | phone/nokia/dct4/n3650.h \ |
118 | phone/nokia/dct4/n6510.h | 118 | phone/nokia/dct4/n6510.h |
119 | SOURCES +=gsmcomon.c \ | 119 | SOURCES +=gsmcomon.c \ |
120 | gsmstate.c \ | 120 | gsmstate.c \ |
121 | misc/misc.c \ | 121 | misc/misc.c \ |
122 | misc/cfg.c \ | 122 | misc/cfg.c \ |
123 | misc/coding/coding.c \ | 123 | misc/coding/coding.c \ |
124 | misc/coding/md5.c \ | 124 | misc/coding/md5.c \ |
125 | service/sms/gsmsms.c \ | 125 | service/sms/gsmsms.c \ |
126 | service/sms/gsmems.c \ | 126 | service/sms/gsmems.c \ |
127 | service/sms/gsmmulti.c \ | 127 | service/sms/gsmmulti.c \ |
128 | service/gsmcal.c \ | 128 | service/gsmcal.c \ |
129 | service/gsmdata.c \ | 129 | service/gsmdata.c \ |
130 | service/gsmpbk.c \ | 130 | service/gsmpbk.c \ |
131 | service/gsmring.c \ | 131 | service/gsmring.c \ |
132 | service/gsmlogo.c \ | 132 | service/gsmlogo.c \ |
133 | service/gsmmisc.c \ | 133 | service/gsmmisc.c \ |
134 | service/gsmnet.c \ | 134 | service/gsmnet.c \ |
135 | service/backup/gsmback.c \ | 135 | service/backup/gsmback.c \ |
136 | service/backup/backldif.c \ | 136 | service/backup/backldif.c \ |
137 | service/backup/backlmb.c \ | 137 | service/backup/backlmb.c \ |
138 | service/backup/backtext.c \ | 138 | service/backup/backtext.c \ |
139 | service/backup/backvcs.c \ | 139 | service/backup/backvcs.c \ |
140 | service/backup/backvcf.c \ | 140 | service/backup/backvcf.c \ |
141 | service/backup/backics.c \ | 141 | service/backup/backics.c \ |
142 | device/bluetoth/affix.c \ | 142 | device/bluetoth/affix.c \ |
143 | device/bluetoth/bluez.c \ | 143 | device/bluetoth/bluez.c \ |
144 | device/bluetoth/blue_w32.c \ | 144 | device/bluetoth/blue_w32.c \ |
145 | device/bluetoth/bluetoth.c \ | 145 | device/bluetoth/bluetoth.c \ |
146 | device/serial/ser_djg.c \ | 146 | device/serial/ser_djg.c \ |
147 | device/irda/irda.c \ | 147 | device/irda/irda.c \ |
148 | device/devfunc.c \ | 148 | device/devfunc.c \ |
149 | protocol/at/at.c \ | 149 | protocol/at/at.c \ |
150 | protocol/alcatel/alcabus.c \ | 150 | protocol/alcatel/alcabus.c \ |
151 | protocol/nokia/mbus2.c \ | 151 | protocol/nokia/mbus2.c \ |
152 | protocol/nokia/fbus2.c \ | 152 | protocol/nokia/fbus2.c \ |
153 | protocol/nokia/phonet.c \ | 153 | protocol/nokia/phonet.c \ |
154 | protocol/obex/obex.c \ | 154 | protocol/obex/obex.c \ |
155 | protocol/symbian/mrouter.c \ | 155 | protocol/symbian/mrouter.c \ |
156 | phone/pfunc.c \ | 156 | phone/pfunc.c \ |
157 | phone/at/atgen.c \ | 157 | phone/at/atgen.c \ |
158 | phone/at/siemens.c \ | 158 | phone/at/siemens.c \ |
159 | phone/at/sonyeric.c \ | 159 | phone/at/sonyeric.c \ |
160 | phone/alcatel/alcatel.c \ | 160 | phone/alcatel/alcatel.c \ |
161 | phone/nokia/dct3/n6110.c \ | 161 | phone/nokia/dct3/n6110.c \ |
162 | phone/nokia/dct3/n7110.c \ | 162 | phone/nokia/dct3/n7110.c \ |
163 | phone/nokia/dct3/n9210.c \ | 163 | phone/nokia/dct3/n9210.c \ |
164 | phone/nokia/dct3/dct3func.c \ | 164 | phone/nokia/dct3/dct3func.c \ |
165 | phone/nokia/dct4/n3320.c \ | 165 | phone/nokia/dct4/n3320.c \ |
166 | phone/nokia/dct4/n3650.c \ | 166 | phone/nokia/dct4/n3650.c \ |
167 | phone/nokia/dct4/n6510.c \ | 167 | phone/nokia/dct4/n6510.c \ |
168 | phone/nokia/dct4/dct4func.c \ | 168 | phone/nokia/dct4/dct4func.c \ |
169 | phone/nokia/nauto.c \ | 169 | phone/nokia/nauto.c \ |
170 | phone/nokia/nfunc.c \ | 170 | phone/nokia/nfunc.c \ |
171 | phone/nokia/nfuncold.c \ | 171 | phone/nokia/nfuncold.c \ |
172 | phone/obex/obexgen.c \ | 172 | phone/obex/obexgen.c \ |
173 | phone/symbian/mroutgen.c | 173 | phone/symbian/mroutgen.c |
174 | 174 | ||
175 | DEFINES += DESKTOP_VERSION | ||
175 | TARGET = microgammu | 176 | TARGET = microgammu |
176 | CONFIG = warn_off release console | 177 | CONFIG = warn_off release console |
177 | DESTDIR = ../../../bin | 178 | DESTDIR = ../../../bin |
178 | OBJECTS_DIR = obj/unix | 179 | OBJECTS_DIR = obj/unix |
179 | MOC_DIR = moc/unix | 180 | MOC_DIR = moc/unix |
180 | 181 | ||
181 | unix: { | 182 | unix: { |
182 | SOURCES += device/serial/ser_unx.c | 183 | SOURCES += device/serial/ser_unx.c |
183 | } | 184 | } |
184 | win32:{ | 185 | win32:{ |
185 | SOURCES += device/serial/ser_w32.c | 186 | SOURCES += device/serial/ser_w32.c |
186 | } | 187 | } |
diff --git a/gammu/emb/common/service/gsmring.c b/gammu/emb/common/service/gsmring.c index f7f7082..7df46f1 100644 --- a/gammu/emb/common/service/gsmring.c +++ b/gammu/emb/common/service/gsmring.c | |||
@@ -1,1132 +1,1136 @@ | |||
1 | /* (c) 2001-2004 by Marcin Wiacek */ | 1 | /* (c) 2001-2004 by Marcin Wiacek */ |
2 | /* Based on some work from Ralf Thelen (7110 ringtones), | 2 | /* Based on some work from Ralf Thelen (7110 ringtones), |
3 | * Gnokii (RTTL and SM) and others | 3 | * Gnokii (RTTL and SM) and others |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
7 | #include <string.h> | 7 | #include <string.h> |
8 | #include <ctype.h> | 8 | #include <ctype.h> |
9 | #include <math.h> | 9 | #include <math.h> |
10 | #ifdef WIN32 | 10 | #ifdef WIN32 |
11 | # include <windows.h> | 11 | # include <windows.h> |
12 | #endif | 12 | #endif |
13 | 13 | ||
14 | #include "../gsmcomon.h" | 14 | #include "../gsmcomon.h" |
15 | #include "../misc/coding/coding.h" | 15 | #include "../misc/coding/coding.h" |
16 | #include "../gsmstate.h" | 16 | #include "../gsmstate.h" |
17 | #include "gsmring.h" | 17 | #include "gsmring.h" |
18 | #include "sms/gsmsms.h" | 18 | #include "sms/gsmsms.h" |
19 | 19 | ||
20 | int GSM_RingNoteGetFrequency(GSM_RingNote Note) | 20 | int GSM_RingNoteGetFrequency(GSM_RingNote Note) |
21 | { | 21 | { |
22 | double freq=0; | 22 | double freq=0; |
23 | 23 | ||
24 | /* Values according to the software from http://iki.fi/too/sw/xring/ | 24 | /* Values according to the software from http://iki.fi/too/sw/xring/ |
25 | * generated with: | 25 | * generated with: |
26 | * perl -e 'print int(4400 * (2 **($_/12)) + .5)/10, "\n" for(3..14)' | 26 | * perl -e 'print int(4400 * (2 **($_/12)) + .5)/10, "\n" for(3..14)' |
27 | */ | 27 | */ |
28 | switch (Note.Note) { | 28 | switch (Note.Note) { |
29 | case Note_C : freq = 523.3; break; | 29 | case Note_C : freq = 523.3; break; |
30 | case Note_Cis: freq = 554.4; break; | 30 | case Note_Cis: freq = 554.4; break; |
31 | case Note_D : freq = 587.3; break; | 31 | case Note_D : freq = 587.3; break; |
32 | case Note_Dis: freq = 622.3; break; | 32 | case Note_Dis: freq = 622.3; break; |
33 | case Note_E : freq = 659.3; break; | 33 | case Note_E : freq = 659.3; break; |
34 | case Note_F : freq = 698.5; break; | 34 | case Note_F : freq = 698.5; break; |
35 | case Note_Fis: freq = 740; break; | 35 | case Note_Fis: freq = 740; break; |
36 | case Note_G : freq = 784; break; | 36 | case Note_G : freq = 784; break; |
37 | case Note_Gis: freq = 830.6; break; | 37 | case Note_Gis: freq = 830.6; break; |
38 | case Note_A : freq = 880; break; | 38 | case Note_A : freq = 880; break; |
39 | case Note_Ais: freq = 932.3; break; | 39 | case Note_Ais: freq = 932.3; break; |
40 | case Note_H : freq = 987.8; break; | 40 | case Note_H : freq = 987.8; break; |
41 | case Note_Pause: break; | 41 | case Note_Pause: break; |
42 | } | 42 | } |
43 | switch (Note.Scale) { | 43 | switch (Note.Scale) { |
44 | case Scale_440 : freq = freq / 2; break; | 44 | case Scale_440 : freq = freq / 2; break; |
45 | case Scale_880 : break; | 45 | case Scale_880 : break; |
46 | case Scale_1760: freq = freq * 2; break; | 46 | case Scale_1760: freq = freq * 2; break; |
47 | case Scale_3520: freq = freq * 4; break; | 47 | case Scale_3520: freq = freq * 4; break; |
48 | default : break; | 48 | default : break; |
49 | } | 49 | } |
50 | return (int)freq; | 50 | return (int)freq; |
51 | } | 51 | } |
52 | 52 | ||
53 | int GSM_RingNoteGetFullDuration(GSM_RingNote Note) | 53 | int GSM_RingNoteGetFullDuration(GSM_RingNote Note) |
54 | { | 54 | { |
55 | int duration = 1; | 55 | int duration = 1; |
56 | 56 | ||
57 | switch (Note.Duration) { | 57 | switch (Note.Duration) { |
58 | case Duration_Full : duration = 128; break; | 58 | case Duration_Full : duration = 128; break; |
59 | case Duration_1_2 : duration = 64; break; | 59 | case Duration_1_2 : duration = 64; break; |
60 | case Duration_1_4 : duration = 32; break; | 60 | case Duration_1_4 : duration = 32; break; |
61 | case Duration_1_8 : duration = 16; break; | 61 | case Duration_1_8 : duration = 16; break; |
62 | case Duration_1_16 : duration = 8; break; | 62 | case Duration_1_16 : duration = 8; break; |
63 | case Duration_1_32 : duration = 4; break; | 63 | case Duration_1_32 : duration = 4; break; |
64 | } | 64 | } |
65 | switch (Note.DurationSpec) { | 65 | switch (Note.DurationSpec) { |
66 | case NoSpecialDuration : break; | 66 | case NoSpecialDuration : break; |
67 | case DottedNote : duration = duration * 3/2;break; | 67 | case DottedNote : duration = duration * 3/2;break; |
68 | case DoubleDottedNote : duration = duration * 9/4;break; | 68 | case DoubleDottedNote : duration = duration * 9/4;break; |
69 | case Length_2_3 : duration = duration * 2/3;break; | 69 | case Length_2_3 : duration = duration * 2/3;break; |
70 | } | 70 | } |
71 | return duration; | 71 | return duration; |
72 | } | 72 | } |
73 | 73 | ||
74 | #ifndef PI | 74 | #ifndef PI |
75 | # define PI 3.141592654 | 75 | # define PI 3.141592654 |
76 | #endif | 76 | #endif |
77 | 77 | ||
78 | #define WAV_SAMPLE_RATE 44100 | 78 | #define WAV_SAMPLE_RATE 44100 |
79 | 79 | ||
80 | GSM_Error savewav(FILE *file, GSM_Ringtone *ringtone) | 80 | GSM_Error savewav(FILE *file, GSM_Ringtone *ringtone) |
81 | { | 81 | { |
82 | unsigned char WAV_Header[] = { | 82 | unsigned char WAV_Header[] = { |
83 | 'R','I','F','F', | 83 | 'R','I','F','F', |
84 | 0x00,0x00,0x00,0x00,/* Length */ | 84 | 0x00,0x00,0x00,0x00,/* Length */ |
85 | 'W','A','V','E'}; | 85 | 'W','A','V','E'}; |
86 | unsigned char FMT_Header[] = {'f','m','t',' ', | 86 | unsigned char FMT_Header[] = {'f','m','t',' ', |
87 | 0x10,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x44,0xac, | 87 | 0x10,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x44,0xac, |
88 | 0x00,0x00,0x88,0x58,0x01,0x00,0x02,0x00,0x10,0x00}; | 88 | 0x00,0x00,0x88,0x58,0x01,0x00,0x02,0x00,0x10,0x00}; |
89 | unsigned char DATA_Header[] = { | 89 | unsigned char DATA_Header[] = { |
90 | 'd','a','t','a', | 90 | 'd','a','t','a', |
91 | 0x00,0x00,0x00,0x00};/* Length */ | 91 | 0x00,0x00,0x00,0x00};/* Length */ |
92 | short DATA_Buffer[60000]; | 92 | short DATA_Buffer[60000]; |
93 | long wavfilesize; | 93 | long wavfilesize; |
94 | GSM_RingNote *Note; | 94 | GSM_RingNote *Note; |
95 | long i,j,length=0; | 95 | long i,j,length=0; |
96 | double phase=0,phase_step; | 96 | double phase=0,phase_step; |
97 | 97 | ||
98 | fwrite(&WAV_Header, 1, sizeof(WAV_Header),file); | 98 | fwrite(&WAV_Header, 1, sizeof(WAV_Header),file); |
99 | fwrite(&FMT_Header, 1, sizeof(FMT_Header),file); | 99 | fwrite(&FMT_Header, 1, sizeof(FMT_Header),file); |
100 | fwrite(&DATA_Header, 1, sizeof(DATA_Header),file); | 100 | fwrite(&DATA_Header, 1, sizeof(DATA_Header),file); |
101 | 101 | ||
102 | for (i=0;i<ringtone->NoteTone.NrCommands;i++) { | 102 | for (i=0;i<ringtone->NoteTone.NrCommands;i++) { |
103 | if (ringtone->NoteTone.Commands[i].Type == RING_Note) { | 103 | if (ringtone->NoteTone.Commands[i].Type == RING_Note) { |
104 | Note = &ringtone->NoteTone.Commands[i].Note; | 104 | Note = &ringtone->NoteTone.Commands[i].Note; |
105 | phase_step = GSM_RingNoteGetFrequency(*Note)*WAV_SAMPLE_RATE*1.5; | 105 | phase_step = GSM_RingNoteGetFrequency(*Note)*WAV_SAMPLE_RATE*1.5; |
106 | for (j=0;j<((long)(GSM_RingNoteGetFullDuration(*Note)*WAV_SAMPLE_RATE/70));j++) { | 106 | for (j=0;j<((long)(GSM_RingNoteGetFullDuration(*Note)*WAV_SAMPLE_RATE/70));j++) { |
107 | /*DATA_Buffer[j] = ((int)(sin(phase*PI)*50000));*/ | 107 | #ifdef DESKTOP_VERSION |
108 | DATA_Buffer[j] = ((int)(sin(phase*PI)*50000)); | ||
109 | #else | ||
110 | // we have no sin on Zaurus | ||
108 | DATA_Buffer[j] = ((int)(0.5*50000)); | 111 | DATA_Buffer[j] = ((int)(0.5*50000)); |
112 | #endif | ||
109 | phase = phase + phase_step; | 113 | phase = phase + phase_step; |
110 | length++; | 114 | length++; |
111 | } | 115 | } |
112 | fwrite(&DATA_Buffer,sizeof(short),j,file); | 116 | fwrite(&DATA_Buffer,sizeof(short),j,file); |
113 | } | 117 | } |
114 | } | 118 | } |
115 | 119 | ||
116 | wavfilesize = sizeof(WAV_Header) + sizeof(FMT_Header) + sizeof(DATA_Header) + length*2; | 120 | wavfilesize = sizeof(WAV_Header) + sizeof(FMT_Header) + sizeof(DATA_Header) + length*2; |
117 | WAV_Header[4] = ((unsigned char)wavfilesize % 256); | 121 | WAV_Header[4] = ((unsigned char)wavfilesize % 256); |
118 | WAV_Header[5] = ((unsigned char)wavfilesize / 256); | 122 | WAV_Header[5] = ((unsigned char)wavfilesize / 256); |
119 | WAV_Header[6] = ((unsigned char)wavfilesize / (256*256)); | 123 | WAV_Header[6] = ((unsigned char)wavfilesize / (256*256)); |
120 | WAV_Header[7] = ((unsigned char)wavfilesize / (256*256*256)); | 124 | WAV_Header[7] = ((unsigned char)wavfilesize / (256*256*256)); |
121 | wavfilesize = wavfilesize - 54; | 125 | wavfilesize = wavfilesize - 54; |
122 | DATA_Header[4] = ((unsigned char)wavfilesize % 256); | 126 | DATA_Header[4] = ((unsigned char)wavfilesize % 256); |
123 | DATA_Header[5] = ((unsigned char)wavfilesize / 256); | 127 | DATA_Header[5] = ((unsigned char)wavfilesize / 256); |
124 | DATA_Header[6] = ((unsigned char)wavfilesize / (256*256)); | 128 | DATA_Header[6] = ((unsigned char)wavfilesize / (256*256)); |
125 | DATA_Header[7] = ((unsigned char)wavfilesize / (256*256*256)); | 129 | DATA_Header[7] = ((unsigned char)wavfilesize / (256*256*256)); |
126 | 130 | ||
127 | fseek( file, 0, SEEK_SET); | 131 | fseek( file, 0, SEEK_SET); |
128 | fwrite(&WAV_Header, 1, sizeof(WAV_Header),file); | 132 | fwrite(&WAV_Header, 1, sizeof(WAV_Header),file); |
129 | fwrite(&FMT_Header, 1, sizeof(FMT_Header),file); | 133 | fwrite(&FMT_Header, 1, sizeof(FMT_Header),file); |
130 | fwrite(&DATA_Header, 1, sizeof(DATA_Header),file); | 134 | fwrite(&DATA_Header, 1, sizeof(DATA_Header),file); |
131 | 135 | ||
132 | return ERR_NONE; | 136 | return ERR_NONE; |
133 | } | 137 | } |
134 | 138 | ||
135 | static GSM_Error savebin(FILE *file, GSM_Ringtone *ringtone) | 139 | static GSM_Error savebin(FILE *file, GSM_Ringtone *ringtone) |
136 | { | 140 | { |
137 | char nullchar=0x00; | 141 | char nullchar=0x00; |
138 | 142 | ||
139 | fwrite(&nullchar,1,1,file); | 143 | fwrite(&nullchar,1,1,file); |
140 | fwrite(&nullchar,1,1,file); | 144 | fwrite(&nullchar,1,1,file); |
141 | fprintf(file,"\x0C\x01\x2C"); | 145 | fprintf(file,"\x0C\x01\x2C"); |
142 | fprintf(file,"%s",DecodeUnicodeString(ringtone->Name)); | 146 | fprintf(file,"%s",DecodeUnicodeString(ringtone->Name)); |
143 | fwrite(&nullchar,1,1,file); | 147 | fwrite(&nullchar,1,1,file); |
144 | fwrite(&nullchar,1,1,file); | 148 | fwrite(&nullchar,1,1,file); |
145 | fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file); | 149 | fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file); |
146 | return ERR_NONE; | 150 | return ERR_NONE; |
147 | } | 151 | } |
148 | 152 | ||
149 | static GSM_Error savepuremidi(FILE *file, GSM_Ringtone *ringtone) | 153 | static GSM_Error savepuremidi(FILE *file, GSM_Ringtone *ringtone) |
150 | { | 154 | { |
151 | fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file); | 155 | fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file); |
152 | return ERR_NONE; | 156 | return ERR_NONE; |
153 | } | 157 | } |
154 | 158 | ||
155 | GSM_Error saverttl(FILE *file, GSM_Ringtone *ringtone) | 159 | GSM_Error saverttl(FILE *file, GSM_Ringtone *ringtone) |
156 | { | 160 | { |
157 | GSM_RingNoteScaleDefNoteScale; | 161 | GSM_RingNoteScaleDefNoteScale; |
158 | GSM_RingNoteDurationDefNoteDuration; | 162 | GSM_RingNoteDurationDefNoteDuration; |
159 | 163 | ||
160 | GSM_RingNoteStyleDefNoteStyle=0; | 164 | GSM_RingNoteStyleDefNoteStyle=0; |
161 | int DefNoteTempo=0; | 165 | int DefNoteTempo=0; |
162 | 166 | ||
163 | bool started = false, firstcomma = true; | 167 | bool started = false, firstcomma = true; |
164 | GSM_RingNote *Note; | 168 | GSM_RingNote *Note; |
165 | 169 | ||
166 | unsigned char buffer[15]; | 170 | unsigned char buffer[15]; |
167 | int i,j,k=0; | 171 | int i,j,k=0; |
168 | 172 | ||
169 | /* Saves ringtone name */ | 173 | /* Saves ringtone name */ |
170 | fprintf(file,"%s:",DecodeUnicodeString(ringtone->Name)); | 174 | fprintf(file,"%s:",DecodeUnicodeString(ringtone->Name)); |
171 | 175 | ||
172 | /* Find the most frequently used duration */ | 176 | /* Find the most frequently used duration */ |
173 | for (i=0;i<6;i++) buffer[i]=0; | 177 | for (i=0;i<6;i++) buffer[i]=0; |
174 | for (i=0;i<ringtone->NoteTone.NrCommands;i++) { | 178 | for (i=0;i<ringtone->NoteTone.NrCommands;i++) { |
175 | if (ringtone->NoteTone.Commands[i].Type == RING_Note) { | 179 | if (ringtone->NoteTone.Commands[i].Type == RING_Note) { |
176 | Note = &ringtone->NoteTone.Commands[i].Note; | 180 | Note = &ringtone->NoteTone.Commands[i].Note; |
177 | /* some durations need 2 bytes in file, some 1 */ | 181 | /* some durations need 2 bytes in file, some 1 */ |
178 | if (Note->Duration >= Duration_Full && Note->Duration <= Duration_1_8) { | 182 | if (Note->Duration >= Duration_Full && Note->Duration <= Duration_1_8) { |
179 | buffer[Note->Duration/32]++; | 183 | buffer[Note->Duration/32]++; |
180 | } | 184 | } |
181 | if (Note->Duration >= Duration_1_16 && Note->Duration <= Duration_1_32) { | 185 | if (Note->Duration >= Duration_1_16 && Note->Duration <= Duration_1_32) { |
182 | buffer[Note->Duration/32]+=2; | 186 | buffer[Note->Duration/32]+=2; |
183 | } | 187 | } |
184 | } | 188 | } |
185 | } | 189 | } |
186 | /* Now find the most frequently used */ | 190 | /* Now find the most frequently used */ |
187 | j=0; | 191 | j=0; |
188 | for (i=0;i<6;i++) { | 192 | for (i=0;i<6;i++) { |
189 | if (buffer[i]>j) { | 193 | if (buffer[i]>j) { |
190 | k=i; | 194 | k=i; |
191 | j=buffer[i]; | 195 | j=buffer[i]; |
192 | } | 196 | } |
193 | } | 197 | } |
194 | /* Finally convert the default duration */ | 198 | /* Finally convert the default duration */ |
195 | DefNoteDuration = k * 32; | 199 | DefNoteDuration = k * 32; |
196 | dbgprintf("DefNoteDuration=%d\n", DefNoteDuration); | 200 | dbgprintf("DefNoteDuration=%d\n", DefNoteDuration); |
197 | switch (DefNoteDuration) { | 201 | switch (DefNoteDuration) { |
198 | case Duration_Full:fprintf(file,"d=1"); break; | 202 | case Duration_Full:fprintf(file,"d=1"); break; |
199 | case Duration_1_2 :fprintf(file,"d=2"); break; | 203 | case Duration_1_2 :fprintf(file,"d=2"); break; |
200 | case Duration_1_4 :fprintf(file,"d=4"); break; | 204 | case Duration_1_4 :fprintf(file,"d=4"); break; |
201 | case Duration_1_8 :fprintf(file,"d=8"); break; | 205 | case Duration_1_8 :fprintf(file,"d=8"); break; |
202 | case Duration_1_16:fprintf(file,"d=16");break; | 206 | case Duration_1_16:fprintf(file,"d=16");break; |
203 | case Duration_1_32:fprintf(file,"d=32");break; | 207 | case Duration_1_32:fprintf(file,"d=32");break; |
204 | } | 208 | } |
205 | 209 | ||
206 | /* Find the most frequently used scale */ | 210 | /* Find the most frequently used scale */ |
207 | for (i=0;i<9;i++) buffer[i]=0; | 211 | for (i=0;i<9;i++) buffer[i]=0; |
208 | for (i=0;i<ringtone->NoteTone.NrCommands;i++) { | 212 | for (i=0;i<ringtone->NoteTone.NrCommands;i++) { |
209 | if (ringtone->NoteTone.Commands[i].Type == RING_Note) { | 213 | if (ringtone->NoteTone.Commands[i].Type == RING_Note) { |
210 | Note = &ringtone->NoteTone.Commands[i].Note; | 214 | Note = &ringtone->NoteTone.Commands[i].Note; |
211 | if (Note->Note!=Note_Pause && | 215 | if (Note->Note!=Note_Pause && |
212 | Note->Scale >= Scale_55 && Note->Scale <= Scale_14080) { | 216 | Note->Scale >= Scale_55 && Note->Scale <= Scale_14080) { |
213 | buffer[Note->Scale - 1]++; | 217 | buffer[Note->Scale - 1]++; |
214 | } | 218 | } |
215 | } | 219 | } |
216 | } | 220 | } |
217 | j=0; | 221 | j=0; |
218 | for (i=0;i<9;i++) { | 222 | for (i=0;i<9;i++) { |
219 | if (buffer[i]>j) { | 223 | if (buffer[i]>j) { |
220 | k = i; | 224 | k = i; |
221 | j=buffer[i]; | 225 | j=buffer[i]; |
222 | } | 226 | } |
223 | } | 227 | } |
224 | DefNoteScale = k + 1; | 228 | DefNoteScale = k + 1; |
225 | /* Save the default scale */ | 229 | /* Save the default scale */ |
226 | fprintf(file,",o=%i,",DefNoteScale); | 230 | fprintf(file,",o=%i,",DefNoteScale); |
227 | dbgprintf("DefNoteScale=%d\n", DefNoteScale); | 231 | dbgprintf("DefNoteScale=%d\n", DefNoteScale); |
228 | 232 | ||
229 | for (i=0;i<ringtone->NoteTone.NrCommands;i++) { | 233 | for (i=0;i<ringtone->NoteTone.NrCommands;i++) { |
230 | if (ringtone->NoteTone.Commands[i].Type != RING_Note) continue; | 234 | if (ringtone->NoteTone.Commands[i].Type != RING_Note) continue; |
231 | 235 | ||
232 | Note = &ringtone->NoteTone.Commands[i].Note; | 236 | Note = &ringtone->NoteTone.Commands[i].Note; |
233 | 237 | ||
234 | /* Trick from PPM Edit */ | 238 | /* Trick from PPM Edit */ |
235 | if (Note->DurationSpec == DoubleDottedNote) { | 239 | if (Note->DurationSpec == DoubleDottedNote) { |
236 | switch (Note->Duration) { | 240 | switch (Note->Duration) { |
237 | case Duration_Full:Note->Duration = Duration_Full;break; | 241 | case Duration_Full:Note->Duration = Duration_Full;break; |
238 | case Duration_1_2 :Note->Duration = Duration_Full;break; | 242 | case Duration_1_2 :Note->Duration = Duration_Full;break; |
239 | case Duration_1_4 :Note->Duration = Duration_1_2; break; | 243 | case Duration_1_4 :Note->Duration = Duration_1_2; break; |
240 | case Duration_1_8 :Note->Duration = Duration_1_4; break; | 244 | case Duration_1_8 :Note->Duration = Duration_1_4; break; |
241 | case Duration_1_16:Note->Duration = Duration_1_8; break; | 245 | case Duration_1_16:Note->Duration = Duration_1_8; break; |
242 | case Duration_1_32:Note->Duration = Duration_1_16;break; | 246 | case Duration_1_32:Note->Duration = Duration_1_16;break; |
243 | } | 247 | } |
244 | Note->DurationSpec = NoSpecialDuration; | 248 | Note->DurationSpec = NoSpecialDuration; |
245 | } | 249 | } |
246 | 250 | ||
247 | if (!started) { | 251 | if (!started) { |
248 | DefNoteTempo=Note->Tempo; | 252 | DefNoteTempo=Note->Tempo; |
249 | DefNoteStyle=Note->Style; | 253 | DefNoteStyle=Note->Style; |
250 | switch (Note->Style) { | 254 | switch (Note->Style) { |
251 | case StaccatoStyle: fprintf(file,"s=S,"); break; | 255 | case StaccatoStyle: fprintf(file,"s=S,"); break; |
252 | case NaturalStyle : fprintf(file,"s=N,"); break; | 256 | case NaturalStyle : fprintf(file,"s=N,"); break; |
253 | case ContinuousStyle : break; | 257 | case ContinuousStyle : break; |
254 | } | 258 | } |
255 | /* Save the default tempo */ | 259 | /* Save the default tempo */ |
256 | fprintf(file,"b=%i:",DefNoteTempo); | 260 | fprintf(file,"b=%i:",DefNoteTempo); |
257 | dbgprintf("DefNoteTempo=%d\n", DefNoteTempo); | 261 | dbgprintf("DefNoteTempo=%d\n", DefNoteTempo); |
258 | started = true; | 262 | started = true; |
259 | firstcomma = true; | 263 | firstcomma = true; |
260 | } | 264 | } |
261 | 265 | ||
262 | if (!started) continue; | 266 | if (!started) continue; |
263 | 267 | ||
264 | if (Note->Style!=DefNoteStyle) { | 268 | if (Note->Style!=DefNoteStyle) { |
265 | /* And a separator */ | 269 | /* And a separator */ |
266 | if (!firstcomma) fprintf(file,","); | 270 | if (!firstcomma) fprintf(file,","); |
267 | firstcomma = false; | 271 | firstcomma = false; |
268 | DefNoteStyle=Note->Style; | 272 | DefNoteStyle=Note->Style; |
269 | switch (Note->Style) { | 273 | switch (Note->Style) { |
270 | case StaccatoStyle : fprintf(file,"s=S"); break; | 274 | case StaccatoStyle : fprintf(file,"s=S"); break; |
271 | case NaturalStyle : fprintf(file,"s=N"); break; | 275 | case NaturalStyle : fprintf(file,"s=N"); break; |
272 | case ContinuousStyle: fprintf(file,"s=C"); break; | 276 | case ContinuousStyle: fprintf(file,"s=C"); break; |
273 | } | 277 | } |
274 | } | 278 | } |
275 | if (Note->Tempo!=DefNoteTempo) { | 279 | if (Note->Tempo!=DefNoteTempo) { |
276 | /* And a separator */ | 280 | /* And a separator */ |
277 | if (!firstcomma) fprintf(file,","); | 281 | if (!firstcomma) fprintf(file,","); |
278 | firstcomma = false; | 282 | firstcomma = false; |
279 | DefNoteTempo=Note->Tempo; | 283 | DefNoteTempo=Note->Tempo; |
280 | fprintf(file,"b=%i",DefNoteTempo); | 284 | fprintf(file,"b=%i",DefNoteTempo); |
281 | } | 285 | } |
282 | /* This note has a duration different than the default. We must save it */ | 286 | /* This note has a duration different than the default. We must save it */ |
283 | if (Note->Duration!=DefNoteDuration) { | 287 | if (Note->Duration!=DefNoteDuration) { |
284 | /* And a separator */ | 288 | /* And a separator */ |
285 | if (!firstcomma) fprintf(file,","); | 289 | if (!firstcomma) fprintf(file,","); |
286 | firstcomma = false; | 290 | firstcomma = false; |
287 | switch (Note->Duration) { | 291 | switch (Note->Duration) { |
288 | case Duration_Full:fprintf(file,"1"); break; | 292 | case Duration_Full:fprintf(file,"1"); break; |
289 | case Duration_1_2 :fprintf(file,"2"); break; | 293 | case Duration_1_2 :fprintf(file,"2"); break; |
290 | case Duration_1_4 :fprintf(file,"4"); break; | 294 | case Duration_1_4 :fprintf(file,"4"); break; |
291 | case Duration_1_8 :fprintf(file,"8"); break; | 295 | case Duration_1_8 :fprintf(file,"8"); break; |
292 | case Duration_1_16:fprintf(file,"16");break; | 296 | case Duration_1_16:fprintf(file,"16");break; |
293 | case Duration_1_32:fprintf(file,"32");break; | 297 | case Duration_1_32:fprintf(file,"32");break; |
294 | } | 298 | } |
295 | } else { | 299 | } else { |
296 | /* And a separator */ | 300 | /* And a separator */ |
297 | if (!firstcomma) fprintf(file,","); | 301 | if (!firstcomma) fprintf(file,","); |
298 | firstcomma = false; | 302 | firstcomma = false; |
299 | } | 303 | } |
300 | /* Now save the actual note */ | 304 | /* Now save the actual note */ |
301 | switch (Note->Note) { | 305 | switch (Note->Note) { |
302 | case Note_C :fprintf(file,"c");break; | 306 | case Note_C :fprintf(file,"c");break; |
303 | case Note_Cis:fprintf(file,"c#");break; | 307 | case Note_Cis:fprintf(file,"c#");break; |
304 | case Note_D :fprintf(file,"d");break; | 308 | case Note_D :fprintf(file,"d");break; |
305 | case Note_Dis:fprintf(file,"d#");break; | 309 | case Note_Dis:fprintf(file,"d#");break; |
306 | case Note_E :fprintf(file,"e");break; | 310 | case Note_E :fprintf(file,"e");break; |
307 | case Note_F :fprintf(file,"f");break; | 311 | case Note_F :fprintf(file,"f");break; |
308 | case Note_Fis:fprintf(file,"f#");break; | 312 | case Note_Fis:fprintf(file,"f#");break; |
309 | case Note_G :fprintf(file,"g");break; | 313 | case Note_G :fprintf(file,"g");break; |
310 | case Note_Gis:fprintf(file,"g#");break; | 314 | case Note_Gis:fprintf(file,"g#");break; |
311 | case Note_A :fprintf(file,"a");break; | 315 | case Note_A :fprintf(file,"a");break; |
312 | case Note_Ais:fprintf(file,"a#");break; | 316 | case Note_Ais:fprintf(file,"a#");break; |
313 | case Note_H :fprintf(file,"h");break; | 317 | case Note_H :fprintf(file,"h");break; |
314 | default :fprintf(file,"p");break; /*Pause ?*/ | 318 | default :fprintf(file,"p");break; /*Pause ?*/ |
315 | } | 319 | } |
316 | switch (Note->DurationSpec) { | 320 | switch (Note->DurationSpec) { |
317 | case DottedNote : fprintf(file,".");break; | 321 | case DottedNote : fprintf(file,".");break; |
318 | default : break; | 322 | default : break; |
319 | } | 323 | } |
320 | if (Note->Note!=Note_Pause && Note->Scale != DefNoteScale) { | 324 | if (Note->Note!=Note_Pause && Note->Scale != DefNoteScale) { |
321 | fprintf(file,"%i",Note->Scale); | 325 | fprintf(file,"%i",Note->Scale); |
322 | } | 326 | } |
323 | } | 327 | } |
324 | return ERR_NONE; | 328 | return ERR_NONE; |
325 | } | 329 | } |
326 | 330 | ||
327 | void saveimelody(FILE *file, GSM_Ringtone *ringtone) | 331 | void saveimelody(FILE *file, GSM_Ringtone *ringtone) |
328 | { | 332 | { |
329 | char Buffer[2000]; | 333 | char Buffer[2000]; |
330 | int i=2000; | 334 | int i=2000; |
331 | 335 | ||
332 | GSM_EncodeEMSSound(*ringtone, Buffer, &i, (float)1.2, true); | 336 | GSM_EncodeEMSSound(*ringtone, Buffer, &i, (float)1.2, true); |
333 | 337 | ||
334 | fwrite(Buffer, 1, i, file); | 338 | fwrite(Buffer, 1, i, file); |
335 | } | 339 | } |
336 | 340 | ||
337 | #ifndef ENABLE_LGPL | 341 | #ifndef ENABLE_LGPL |
338 | 342 | ||
339 | static void WriteVarLen(unsigned char* midifile, int* current, long value) | 343 | static void WriteVarLen(unsigned char* midifile, int* current, long value) |
340 | { | 344 | { |
341 | long buffer; | 345 | long buffer; |
342 | 346 | ||
343 | buffer = value & 0x7f; | 347 | buffer = value & 0x7f; |
344 | 348 | ||
345 | while (value >>= 7) { | 349 | while (value >>= 7) { |
346 | buffer <<= 8; | 350 | buffer <<= 8; |
347 | buffer |= 0x80; | 351 | buffer |= 0x80; |
348 | buffer += (value & 0x7f); | 352 | buffer += (value & 0x7f); |
349 | } | 353 | } |
350 | 354 | ||
351 | while (1) { | 355 | while (1) { |
352 | midifile[(*current)++] = (unsigned char)buffer; | 356 | midifile[(*current)++] = (unsigned char)buffer; |
353 | if (buffer & 0x80) { | 357 | if (buffer & 0x80) { |
354 | buffer >>= 8; | 358 | buffer >>= 8; |
355 | } else { | 359 | } else { |
356 | break; | 360 | break; |
357 | } | 361 | } |
358 | } | 362 | } |
359 | } | 363 | } |
360 | 364 | ||
361 | #define singlepauses | 365 | #define singlepauses |
362 | 366 | ||
363 | /* FIXME: need adding tempo before each note and scale too ? */ | 367 | /* FIXME: need adding tempo before each note and scale too ? */ |
364 | void savemid(FILE* file, GSM_Ringtone *ringtone) | 368 | void savemid(FILE* file, GSM_Ringtone *ringtone) |
365 | { | 369 | { |
366 | int pause = 0, current = 26, duration, i, note=0, length = 20; | 370 | int pause = 0, current = 26, duration, i, note=0, length = 20; |
367 | bool started = false; | 371 | bool started = false; |
368 | GSM_RingNote *Note; | 372 | GSM_RingNote *Note; |
369 | unsigned char midifile[3000] = { | 373 | unsigned char midifile[3000] = { |
370 | 0x4D, 0x54, 0x68, 0x64, // MThd | 374 | 0x4D, 0x54, 0x68, 0x64, // MThd |
371 | 0x00, 0x00, 0x00, 0x06, // chunk length | 375 | 0x00, 0x00, 0x00, 0x06, // chunk length |
372 | 0x00, 0x00, // format 0 | 376 | 0x00, 0x00, // format 0 |
373 | 0x00, 0x01, // one track | 377 | 0x00, 0x01, // one track |
374 | 0x00, 0x20, // 32 per quarter note | 378 | 0x00, 0x20, // 32 per quarter note |
375 | 0x4D, 0x54, 0x72, 0x6B, // MTrk | 379 | 0x4D, 0x54, 0x72, 0x6B, // MTrk |
376 | 0x00, 0x00, 0x00, 0x00, // chunk length | 380 | 0x00, 0x00, 0x00, 0x00, // chunk length |
377 | 0x00, 0xFF, 0x51, 0x03, // tempo meta event | 381 | 0x00, 0xFF, 0x51, 0x03, // tempo meta event |
378 | 0x00, 0x00, 0x00}; // 3 bytes for us for a quarter note | 382 | 0x00, 0x00, 0x00}; // 3 bytes for us for a quarter note |
379 | 383 | ||
380 | for (i = 0; i < ringtone->NoteTone.NrCommands; i++) { | 384 | for (i = 0; i < ringtone->NoteTone.NrCommands; i++) { |
381 | if (ringtone->NoteTone.Commands[i].Type == RING_Note) { | 385 | if (ringtone->NoteTone.Commands[i].Type == RING_Note) { |
382 | Note = &ringtone->NoteTone.Commands[i].Note; | 386 | Note = &ringtone->NoteTone.Commands[i].Note; |
383 | if (!started) { | 387 | if (!started) { |
384 | /* readmid does not read pauses at the beginning */ | 388 | /* readmid does not read pauses at the beginning */ |
385 | if (Note->Note != Note_Pause) { | 389 | if (Note->Note != Note_Pause) { |
386 | /* FIXME: we need add tempo before each note or so... */ | 390 | /* FIXME: we need add tempo before each note or so... */ |
387 | long duration=60000000/Note->Tempo; | 391 | long duration=60000000/Note->Tempo; |
388 | 392 | ||
389 | midifile[current++] = (unsigned char)(duration >> 16); | 393 | midifile[current++] = (unsigned char)(duration >> 16); |
390 | midifile[current++] = (unsigned char)(duration >> 8); | 394 | midifile[current++] = (unsigned char)(duration >> 8); |
391 | midifile[current++] = (unsigned char)duration; | 395 | midifile[current++] = (unsigned char)duration; |
392 | 396 | ||
393 | started = true; | 397 | started = true; |
394 | } | 398 | } |
395 | } | 399 | } |
396 | if (!started) continue; | 400 | if (!started) continue; |
397 | duration = GSM_RingNoteGetFullDuration(*Note); | 401 | duration = GSM_RingNoteGetFullDuration(*Note); |
398 | if (Note->Note == Note_Pause) { | 402 | if (Note->Note == Note_Pause) { |
399 | pause += duration; | 403 | pause += duration; |
400 | #ifdef singlepauses | 404 | #ifdef singlepauses |
401 | WriteVarLen(midifile,¤t,pause); | 405 | WriteVarLen(midifile,¤t,pause); |
402 | pause=0; | 406 | pause=0; |
403 | midifile[current++]=0x00; // pause | 407 | midifile[current++]=0x00; // pause |
404 | midifile[current++]=0x00; | 408 | midifile[current++]=0x00; |
405 | #endif | 409 | #endif |
406 | } else { | 410 | } else { |
407 | if (Note->Note >= Note_C && Note->Note <= Note_H) { | 411 | if (Note->Note >= Note_C && Note->Note <= Note_H) { |
408 | note = Note->Note/16 + 12 * Note->Scale - 1; | 412 | note = Note->Note/16 + 12 * Note->Scale - 1; |
409 | } | 413 | } |
410 | 414 | ||
411 | WriteVarLen(midifile,¤t,pause); | 415 | WriteVarLen(midifile,¤t,pause); |
412 | pause=0; | 416 | pause=0; |
413 | midifile[current++]=0x90; // note on | 417 | midifile[current++]=0x90; // note on |
414 | midifile[current++]=note; | 418 | midifile[current++]=note; |
415 | midifile[current++]=0x64; // forte | 419 | midifile[current++]=0x64; // forte |
416 | 420 | ||
417 | WriteVarLen(midifile,¤t,duration); | 421 | WriteVarLen(midifile,¤t,duration); |
418 | midifile[current++]=0x80; // note off | 422 | midifile[current++]=0x80; // note off |
419 | midifile[current++]=note; | 423 | midifile[current++]=note; |
420 | midifile[current++]=0x64; | 424 | midifile[current++]=0x64; |
421 | } | 425 | } |
422 | } | 426 | } |
423 | } | 427 | } |
424 | if (pause) { | 428 | if (pause) { |
425 | WriteVarLen(midifile,¤t,pause); | 429 | WriteVarLen(midifile,¤t,pause); |
426 | midifile[current++]=0x00; // pause | 430 | midifile[current++]=0x00; // pause |
427 | midifile[current++]=0x00; // | 431 | midifile[current++]=0x00; // |
428 | } | 432 | } |
429 | midifile[current++] = 0x00; | 433 | midifile[current++] = 0x00; |
430 | midifile[current++] = 0xFF; // track end | 434 | midifile[current++] = 0xFF; // track end |
431 | midifile[current++] = 0x2F; | 435 | midifile[current++] = 0x2F; |
432 | midifile[current++] = 0x00; | 436 | midifile[current++] = 0x00; |
433 | midifile[length++] = (current-22) >> 8; | 437 | midifile[length++] = (current-22) >> 8; |
434 | midifile[length++] = current-22; | 438 | midifile[length++] = current-22; |
435 | 439 | ||
436 | fwrite(midifile,1,current,file); | 440 | fwrite(midifile,1,current,file); |
437 | } | 441 | } |
438 | 442 | ||
439 | #endif | 443 | #endif |
440 | 444 | ||
441 | void saveott(FILE *file, GSM_Ringtone *ringtone) | 445 | void saveott(FILE *file, GSM_Ringtone *ringtone) |
442 | { | 446 | { |
443 | char Buffer[2000]; | 447 | char Buffer[2000]; |
444 | int i=2000; | 448 | int i=2000; |
445 | 449 | ||
446 | GSM_EncodeNokiaRTTLRingtone(*ringtone, Buffer, &i); | 450 | GSM_EncodeNokiaRTTLRingtone(*ringtone, Buffer, &i); |
447 | 451 | ||
448 | fwrite(Buffer, 1, i, file); | 452 | fwrite(Buffer, 1, i, file); |
449 | } | 453 | } |
450 | 454 | ||
451 | GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone) | 455 | GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone) |
452 | { | 456 | { |
453 | FILE *file; | 457 | FILE *file; |
454 | 458 | ||
455 | file = fopen(FileName, "wb"); | 459 | file = fopen(FileName, "wb"); |
456 | if (file == NULL) return ERR_CANTOPENFILE; | 460 | if (file == NULL) return ERR_CANTOPENFILE; |
457 | 461 | ||
458 | switch (ringtone->Format) { | 462 | switch (ringtone->Format) { |
459 | case RING_NOTETONE: | 463 | case RING_NOTETONE: |
460 | if (strstr(FileName,".ott")) { | 464 | if (strstr(FileName,".ott")) { |
461 | saveott(file,ringtone); | 465 | saveott(file,ringtone); |
462 | #ifndef ENABLE_LGPL | 466 | #ifndef ENABLE_LGPL |
463 | } else if (strstr(FileName,".mid")) { | 467 | } else if (strstr(FileName,".mid")) { |
464 | savemid(file,ringtone); | 468 | savemid(file,ringtone); |
465 | #endif | 469 | #endif |
466 | } else if (strstr(FileName,".rng")) { | 470 | } else if (strstr(FileName,".rng")) { |
467 | saveott(file,ringtone); | 471 | saveott(file,ringtone); |
468 | } else if (strstr(FileName,".imy")) { | 472 | } else if (strstr(FileName,".imy")) { |
469 | saveimelody(file,ringtone); | 473 | saveimelody(file,ringtone); |
470 | } else if (strstr(FileName,".ime")) { | 474 | } else if (strstr(FileName,".ime")) { |
471 | saveimelody(file,ringtone); | 475 | saveimelody(file,ringtone); |
472 | } else if (strstr(FileName,".wav")) { | 476 | } else if (strstr(FileName,".wav")) { |
473 | savewav(file,ringtone); | 477 | savewav(file,ringtone); |
474 | } else { | 478 | } else { |
475 | saverttl(file, ringtone); | 479 | saverttl(file, ringtone); |
476 | } | 480 | } |
477 | break; | 481 | break; |
478 | case RING_NOKIABINARY: | 482 | case RING_NOKIABINARY: |
479 | savebin(file, ringtone); | 483 | savebin(file, ringtone); |
480 | break; | 484 | break; |
481 | case RING_MIDI: | 485 | case RING_MIDI: |
482 | savepuremidi(file, ringtone); | 486 | savepuremidi(file, ringtone); |
483 | break; | 487 | break; |
484 | } | 488 | } |
485 | 489 | ||
486 | fclose(file); | 490 | fclose(file); |
487 | 491 | ||
488 | return ERR_NONE; | 492 | return ERR_NONE; |
489 | } | 493 | } |
490 | 494 | ||
491 | static GSM_Error loadrttl(FILE *file, GSM_Ringtone *ringtone) | 495 | static GSM_Error loadrttl(FILE *file, GSM_Ringtone *ringtone) |
492 | { | 496 | { |
493 | GSM_RingNoteScale DefNoteScale= Scale_880; | 497 | GSM_RingNoteScale DefNoteScale= Scale_880; |
494 | GSM_RingNoteDuration DefNoteDuration= Duration_1_4; | 498 | GSM_RingNoteDuration DefNoteDuration= Duration_1_4; |
495 | GSM_RingNoteStyle DefNoteStyle= NaturalStyle; | 499 | GSM_RingNoteStyle DefNoteStyle= NaturalStyle; |
496 | int DefNoteTempo= 63, i=0; | 500 | int DefNoteTempo= 63, i=0; |
497 | 501 | ||
498 | unsigned char buffer[2000],Name[100]; | 502 | unsigned char buffer[2000],Name[100]; |
499 | GSM_RingNote *Note; | 503 | GSM_RingNote *Note; |
500 | 504 | ||
501 | fread(buffer, 2000, 1, file); | 505 | fread(buffer, 2000, 1, file); |
502 | 506 | ||
503 | ringtone->NoteTone.NrCommands = 0; | 507 | ringtone->NoteTone.NrCommands = 0; |
504 | 508 | ||
505 | /* -------------- name ---------------- */ | 509 | /* -------------- name ---------------- */ |
506 | while (buffer[i] != ':') { | 510 | while (buffer[i] != ':') { |
507 | if (buffer[i] == 0x00) return ERR_NONE; | 511 | if (buffer[i] == 0x00) return ERR_NONE; |
508 | i++; | 512 | i++; |
509 | } | 513 | } |
510 | if (i == 0) { | 514 | if (i == 0) { |
511 | /* This is for RTTL ringtones without name. */ | 515 | /* This is for RTTL ringtones without name. */ |
512 | EncodeUnicode(ringtone->Name,"Gammu",5); | 516 | EncodeUnicode(ringtone->Name,"Gammu",5); |
513 | } else { | 517 | } else { |
514 | memcpy(Name,buffer,i); | 518 | memcpy(Name,buffer,i); |
515 | Name[i] = 0x00; | 519 | Name[i] = 0x00; |
516 | EncodeUnicode(ringtone->Name,Name,strlen(Name)); | 520 | EncodeUnicode(ringtone->Name,Name,strlen(Name)); |
517 | } | 521 | } |
518 | i++; | 522 | i++; |
519 | 523 | ||
520 | /* --------- section with default ringtone settings ----------- */ | 524 | /* --------- section with default ringtone settings ----------- */ |
521 | while(1) { | 525 | while(1) { |
522 | switch (buffer[i]) { | 526 | switch (buffer[i]) { |
523 | case ':': | 527 | case ':': |
524 | break; | 528 | break; |
525 | case 0x00: | 529 | case 0x00: |
526 | return ERR_NONE; | 530 | return ERR_NONE; |
527 | case 'd': case 'D': | 531 | case 'd': case 'D': |
528 | switch (atoi(buffer+i+2)) { | 532 | switch (atoi(buffer+i+2)) { |
529 | case 1: DefNoteDuration = Duration_Full; break; | 533 | case 1: DefNoteDuration = Duration_Full; break; |
530 | case 2: DefNoteDuration = Duration_1_2 ; break; | 534 | case 2: DefNoteDuration = Duration_1_2 ; break; |
531 | case 4: DefNoteDuration = Duration_1_4 ; break; | 535 | case 4: DefNoteDuration = Duration_1_4 ; break; |
532 | case 8: DefNoteDuration = Duration_1_8 ; break; | 536 | case 8: DefNoteDuration = Duration_1_8 ; break; |
533 | case 16: DefNoteDuration = Duration_1_16; break; | 537 | case 16: DefNoteDuration = Duration_1_16; break; |
534 | case 32: DefNoteDuration = Duration_1_32; break; | 538 | case 32: DefNoteDuration = Duration_1_32; break; |
535 | } | 539 | } |
536 | break; | 540 | break; |
537 | case 'o': case 'O': | 541 | case 'o': case 'O': |
538 | switch (atoi(buffer+i+2)) { | 542 | switch (atoi(buffer+i+2)) { |
539 | case 4: DefNoteScale = Scale_440 ; break; | 543 | case 4: DefNoteScale = Scale_440 ; break; |
540 | case 5: DefNoteScale = Scale_880 ; break; | 544 | case 5: DefNoteScale = Scale_880 ; break; |
541 | case 6: DefNoteScale = Scale_1760; break; | 545 | case 6: DefNoteScale = Scale_1760; break; |
542 | case 7: DefNoteScale = Scale_3520; break; | 546 | case 7: DefNoteScale = Scale_3520; break; |
543 | } | 547 | } |
544 | break; | 548 | break; |
545 | case 'b': case 'B': | 549 | case 'b': case 'B': |
546 | DefNoteTempo=atoi(buffer+i+2); | 550 | DefNoteTempo=atoi(buffer+i+2); |
547 | dbgprintf("Tempo = %i\n",DefNoteTempo); | 551 | dbgprintf("Tempo = %i\n",DefNoteTempo); |
548 | break; | 552 | break; |
549 | case 's': case 'S': | 553 | case 's': case 'S': |
550 | switch (buffer[i+1]) { | 554 | switch (buffer[i+1]) { |
551 | case 'C': case 'c': DefNoteStyle=ContinuousStyle;break; | 555 | case 'C': case 'c': DefNoteStyle=ContinuousStyle;break; |
552 | case 'N': case 'n': DefNoteStyle=NaturalStyle; break; | 556 | case 'N': case 'n': DefNoteStyle=NaturalStyle; break; |
553 | case 'S': case 's': DefNoteStyle=StaccatoStyle; break; | 557 | case 'S': case 's': DefNoteStyle=StaccatoStyle; break; |
554 | } | 558 | } |
555 | switch (buffer[i+2]) { | 559 | switch (buffer[i+2]) { |
556 | case 'C': case 'c': DefNoteStyle=ContinuousStyle;break; | 560 | case 'C': case 'c': DefNoteStyle=ContinuousStyle;break; |
557 | case 'N': case 'n': DefNoteStyle=NaturalStyle; break; | 561 | case 'N': case 'n': DefNoteStyle=NaturalStyle; break; |
558 | case 'S': case 's': DefNoteStyle=StaccatoStyle; break; | 562 | case 'S': case 's': DefNoteStyle=StaccatoStyle; break; |
559 | } | 563 | } |
560 | break; | 564 | break; |
561 | } | 565 | } |
562 | while (buffer[i] != ':' && buffer[i] != ',') { | 566 | while (buffer[i] != ':' && buffer[i] != ',') { |
563 | if (buffer[i] == 0x00) return ERR_NONE; | 567 | if (buffer[i] == 0x00) return ERR_NONE; |
564 | i++; | 568 | i++; |
565 | } | 569 | } |
566 | if (buffer[i] == ',') i++; | 570 | if (buffer[i] == ',') i++; |
567 | if (buffer[i] == ':') break; | 571 | if (buffer[i] == ':') break; |
568 | } | 572 | } |
569 | dbgprintf("DefNoteDuration=%d\n", DefNoteDuration); | 573 | dbgprintf("DefNoteDuration=%d\n", DefNoteDuration); |
570 | dbgprintf("DefNoteScale=%d\n", DefNoteScale); | 574 | dbgprintf("DefNoteScale=%d\n", DefNoteScale); |
571 | i++; | 575 | i++; |
572 | 576 | ||
573 | /* ------------------------- notes ------------------------------ */ | 577 | /* ------------------------- notes ------------------------------ */ |
574 | while (buffer[i] != 0x00 && ringtone->NoteTone.NrCommands != MAX_RINGTONE_NOTES) { | 578 | while (buffer[i] != 0x00 && ringtone->NoteTone.NrCommands != MAX_RINGTONE_NOTES) { |
575 | switch(buffer[i]) { | 579 | switch(buffer[i]) { |
576 | case 'z': case 'Z': | 580 | case 'z': case 'Z': |
577 | switch (buffer[i+1]) { | 581 | switch (buffer[i+1]) { |
578 | case 'd': | 582 | case 'd': |
579 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableLED; | 583 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableLED; |
580 | ringtone->NoteTone.NrCommands++; | 584 | ringtone->NoteTone.NrCommands++; |
581 | break; | 585 | break; |
582 | case 'D': | 586 | case 'D': |
583 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableLED; | 587 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableLED; |
584 | ringtone->NoteTone.NrCommands++; | 588 | ringtone->NoteTone.NrCommands++; |
585 | break; | 589 | break; |
586 | case 'v': | 590 | case 'v': |
587 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableVibra; | 591 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableVibra; |
588 | ringtone->NoteTone.NrCommands++; | 592 | ringtone->NoteTone.NrCommands++; |
589 | break; | 593 | break; |
590 | case 'V': | 594 | case 'V': |
591 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableVibra; | 595 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableVibra; |
592 | ringtone->NoteTone.NrCommands++; | 596 | ringtone->NoteTone.NrCommands++; |
593 | break; | 597 | break; |
594 | case 'l': | 598 | case 'l': |
595 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableLight; | 599 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableLight; |
596 | ringtone->NoteTone.NrCommands++; | 600 | ringtone->NoteTone.NrCommands++; |
597 | break; | 601 | break; |
598 | case 'L': | 602 | case 'L': |
599 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableLight; | 603 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableLight; |
600 | ringtone->NoteTone.NrCommands++; | 604 | ringtone->NoteTone.NrCommands++; |
601 | } | 605 | } |
602 | break; | 606 | break; |
603 | case 'o': case 'O': | 607 | case 'o': case 'O': |
604 | switch (buffer[i+2]) { | 608 | switch (buffer[i+2]) { |
605 | case 4: DefNoteScale = Scale_440 ; break; | 609 | case 4: DefNoteScale = Scale_440 ; break; |
606 | case 5: DefNoteScale = Scale_880 ; break; | 610 | case 5: DefNoteScale = Scale_880 ; break; |
607 | case 6: DefNoteScale = Scale_1760; break; | 611 | case 6: DefNoteScale = Scale_1760; break; |
608 | case 7: DefNoteScale = Scale_3520; break; | 612 | case 7: DefNoteScale = Scale_3520; break; |
609 | } | 613 | } |
610 | break; | 614 | break; |
611 | case 's': case 'S': | 615 | case 's': case 'S': |
612 | switch (buffer[i+1]) { | 616 | switch (buffer[i+1]) { |
613 | case 'C': case 'c': DefNoteStyle=ContinuousStyle;break; | 617 | case 'C': case 'c': DefNoteStyle=ContinuousStyle;break; |
614 | case 'N': case 'n': DefNoteStyle=NaturalStyle; break; | 618 | case 'N': case 'n': DefNoteStyle=NaturalStyle; break; |
615 | case 'S': case 's': DefNoteStyle=StaccatoStyle; break; | 619 | case 'S': case 's': DefNoteStyle=StaccatoStyle; break; |
616 | } | 620 | } |
617 | switch (buffer[i+2]) { | 621 | switch (buffer[i+2]) { |
618 | case 'C': case 'c': DefNoteStyle=ContinuousStyle;break; | 622 | case 'C': case 'c': DefNoteStyle=ContinuousStyle;break; |
619 | case 'N': case 'n': DefNoteStyle=NaturalStyle; break; | 623 | case 'N': case 'n': DefNoteStyle=NaturalStyle; break; |
620 | case 'S': case 's': DefNoteStyle=StaccatoStyle; break; | 624 | case 'S': case 's': DefNoteStyle=StaccatoStyle; break; |
621 | } | 625 | } |
622 | break; | 626 | break; |
623 | default: | 627 | default: |
624 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_Note; | 628 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_Note; |
625 | Note = &ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Note; | 629 | Note = &ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Note; |
626 | Note->Style = DefNoteStyle; | 630 | Note->Style = DefNoteStyle; |
627 | Note->Tempo = DefNoteTempo; | 631 | Note->Tempo = DefNoteTempo; |
628 | Note->Scale = DefNoteScale; | 632 | Note->Scale = DefNoteScale; |
629 | Note->Duration = DefNoteDuration; | 633 | Note->Duration = DefNoteDuration; |
630 | Note->DurationSpec = NoSpecialDuration; | 634 | Note->DurationSpec = NoSpecialDuration; |
631 | Note->Note = Note_Pause; | 635 | Note->Note = Note_Pause; |
632 | 636 | ||
633 | /* Duration */ | 637 | /* Duration */ |
634 | switch (atoi(buffer+i)) { | 638 | switch (atoi(buffer+i)) { |
635 | case 1: Note->Duration = Duration_Full ; break; | 639 | case 1: Note->Duration = Duration_Full ; break; |
636 | case 2: Note->Duration = Duration_1_2 ; break; | 640 | case 2: Note->Duration = Duration_1_2 ; break; |
637 | case 4: Note->Duration = Duration_1_4 ; break; | 641 | case 4: Note->Duration = Duration_1_4 ; break; |
638 | case 8: Note->Duration = Duration_1_8 ; break; | 642 | case 8: Note->Duration = Duration_1_8 ; break; |
639 | case 16: Note->Duration = Duration_1_16 ; break; | 643 | case 16: Note->Duration = Duration_1_16 ; break; |
640 | case 32: Note->Duration = Duration_1_32 ; break; | 644 | case 32: Note->Duration = Duration_1_32 ; break; |
641 | } | 645 | } |
642 | /* We skip all numbers from duration specification */ | 646 | /* We skip all numbers from duration specification */ |
643 | while(isdigit(buffer[i])) i++; | 647 | while(isdigit(buffer[i])) i++; |
644 | 648 | ||
645 | /* Some files can have special duration here */ | 649 | /* Some files can have special duration here */ |
646 | if (buffer[i]=='.') { | 650 | if (buffer[i]=='.') { |
647 | Note->DurationSpec = DottedNote; | 651 | Note->DurationSpec = DottedNote; |
648 | i++; | 652 | i++; |
649 | } | 653 | } |
650 | 654 | ||
651 | /* Note */ | 655 | /* Note */ |
652 | /* B or b is not in specs, but I decided to put it, because | 656 | /* B or b is not in specs, but I decided to put it, because |
653 | * it's in some RTTL files. It's the same to H note */ | 657 | * it's in some RTTL files. It's the same to H note */ |
654 | switch (buffer[i]) { | 658 | switch (buffer[i]) { |
655 | case 'A': case 'a': Note->Note = Note_A; break; | 659 | case 'A': case 'a': Note->Note = Note_A; break; |
656 | case 'B': case 'b': Note->Note = Note_H; break; | 660 | case 'B': case 'b': Note->Note = Note_H; break; |
657 | case 'C': case 'c': Note->Note = Note_C; break; | 661 | case 'C': case 'c': Note->Note = Note_C; break; |
658 | case 'D': case 'd': Note->Note = Note_D; break; | 662 | case 'D': case 'd': Note->Note = Note_D; break; |
659 | case 'E': case 'e': Note->Note = Note_E; break; | 663 | case 'E': case 'e': Note->Note = Note_E; break; |
660 | case 'F': case 'f': Note->Note = Note_F; break; | 664 | case 'F': case 'f': Note->Note = Note_F; break; |
661 | case 'G': case 'g': Note->Note = Note_G; break; | 665 | case 'G': case 'g': Note->Note = Note_G; break; |
662 | case 'H': case 'h': Note->Note = Note_H; break; | 666 | case 'H': case 'h': Note->Note = Note_H; break; |
663 | } | 667 | } |
664 | i++; | 668 | i++; |
665 | 669 | ||
666 | if (buffer[i]=='#') { | 670 | if (buffer[i]=='#') { |
667 | switch (Note->Note) { | 671 | switch (Note->Note) { |
668 | case Note_A : Note->Note = Note_Ais; break; | 672 | case Note_A : Note->Note = Note_Ais; break; |
669 | case Note_C : Note->Note = Note_Cis; break; | 673 | case Note_C : Note->Note = Note_Cis; break; |
670 | case Note_D : Note->Note = Note_Dis; break; | 674 | case Note_D : Note->Note = Note_Dis; break; |
671 | case Note_F : Note->Note = Note_Fis; break; | 675 | case Note_F : Note->Note = Note_Fis; break; |
672 | case Note_G : Note->Note = Note_Gis; break; | 676 | case Note_G : Note->Note = Note_Gis; break; |
673 | default : break; | 677 | default : break; |
674 | } | 678 | } |
675 | i++; | 679 | i++; |
676 | } | 680 | } |
677 | 681 | ||
678 | /* Some files can have special duration here */ | 682 | /* Some files can have special duration here */ |
679 | if (buffer[i]=='.') { | 683 | if (buffer[i]=='.') { |
680 | Note->DurationSpec = DottedNote; | 684 | Note->DurationSpec = DottedNote; |
681 | i++; | 685 | i++; |
682 | } | 686 | } |
683 | 687 | ||
684 | /* Scale */ | 688 | /* Scale */ |
685 | if (Note->Note!=Note_Pause && isdigit(buffer[i])) { | 689 | if (Note->Note!=Note_Pause && isdigit(buffer[i])) { |
686 | switch (atoi(buffer+i)) { | 690 | switch (atoi(buffer+i)) { |
687 | case 4: Note->Scale = Scale_440 ; break; | 691 | case 4: Note->Scale = Scale_440 ; break; |
688 | case 5: Note->Scale = Scale_880 ; break; | 692 | case 5: Note->Scale = Scale_880 ; break; |
689 | case 6: Note->Scale = Scale_1760; break; | 693 | case 6: Note->Scale = Scale_1760; break; |
690 | case 7: Note->Scale = Scale_3520; break; | 694 | case 7: Note->Scale = Scale_3520; break; |
691 | } | 695 | } |
692 | i++; | 696 | i++; |
693 | } | 697 | } |
694 | 698 | ||
695 | ringtone->NoteTone.NrCommands++; | 699 | ringtone->NoteTone.NrCommands++; |
696 | break; | 700 | break; |
697 | } | 701 | } |
698 | while (buffer[i] != ',') { | 702 | while (buffer[i] != ',') { |
699 | if (buffer[i] == 0x00) return ERR_NONE; | 703 | if (buffer[i] == 0x00) return ERR_NONE; |
700 | i++; | 704 | i++; |
701 | } | 705 | } |
702 | if (buffer[i] == ',') i++; | 706 | if (buffer[i] == ',') i++; |
703 | } | 707 | } |
704 | 708 | ||
705 | return ERR_NONE; | 709 | return ERR_NONE; |
706 | } | 710 | } |
707 | 711 | ||
708 | static GSM_Error loadott(FILE *file, GSM_Ringtone *ringtone) | 712 | static GSM_Error loadott(FILE *file, GSM_Ringtone *ringtone) |
709 | { | 713 | { |
710 | char Buffer[2000]; | 714 | char Buffer[2000]; |
711 | int i; | 715 | int i; |
712 | 716 | ||
713 | i=fread(Buffer, 1, 2000, file); | 717 | i=fread(Buffer, 1, 2000, file); |
714 | 718 | ||
715 | return GSM_DecodeNokiaRTTLRingtone(ringtone, Buffer, i); | 719 | return GSM_DecodeNokiaRTTLRingtone(ringtone, Buffer, i); |
716 | } | 720 | } |
717 | 721 | ||
718 | static GSM_Error loadcommunicator(FILE *file, GSM_Ringtone *ringtone) | 722 | static GSM_Error loadcommunicator(FILE *file, GSM_Ringtone *ringtone) |
719 | { | 723 | { |
720 | char Buffer[4000]; | 724 | char Buffer[4000]; |
721 | int i,j; | 725 | int i,j; |
722 | 726 | ||
723 | i=fread(Buffer, 1, 4000, file); | 727 | i=fread(Buffer, 1, 4000, file); |
724 | 728 | ||
725 | i=0;j=0; | 729 | i=0;j=0; |
726 | while (true) { | 730 | while (true) { |
727 | if (Buffer[j] ==0x00 && Buffer[j+1]==0x02 && | 731 | if (Buffer[j] ==0x00 && Buffer[j+1]==0x02 && |
728 | Buffer[j+2]==0x4a && Buffer[j+3]==0x3a) break; | 732 | Buffer[j+2]==0x4a && Buffer[j+3]==0x3a) break; |
729 | if (j==i-4) return ERR_UNKNOWN; | 733 | if (j==i-4) return ERR_UNKNOWN; |
730 | j++; | 734 | j++; |
731 | } | 735 | } |
732 | j++; | 736 | j++; |
733 | 737 | ||
734 | return GSM_DecodeNokiaRTTLRingtone(ringtone, Buffer+j, i-j); | 738 | return GSM_DecodeNokiaRTTLRingtone(ringtone, Buffer+j, i-j); |
735 | } | 739 | } |
736 | 740 | ||
737 | static GSM_Error loadbin(FILE *file, GSM_Ringtone *ringtone) | 741 | static GSM_Error loadbin(FILE *file, GSM_Ringtone *ringtone) |
738 | { | 742 | { |
739 | int i; | 743 | int i; |
740 | unsigned charbuffer[2000]; | 744 | unsigned charbuffer[2000]; |
741 | 745 | ||
742 | dbgprintf("loading binary\n"); | 746 | dbgprintf("loading binary\n"); |
743 | ringtone->NokiaBinary.Length=fread(buffer, 1, 500, file); | 747 | ringtone->NokiaBinary.Length=fread(buffer, 1, 500, file); |
744 | i=5; | 748 | i=5; |
745 | while (buffer[i]!=0x00) i++; | 749 | while (buffer[i]!=0x00) i++; |
746 | EncodeUnicode(ringtone->Name,buffer+5,i-5); | 750 | EncodeUnicode(ringtone->Name,buffer+5,i-5); |
747 | while (buffer[i]!=0x02 && buffer[i+1]!=0xFC && buffer[i+2]!=0x09) { | 751 | while (buffer[i]!=0x02 && buffer[i+1]!=0xFC && buffer[i+2]!=0x09) { |
748 | i++; | 752 | i++; |
749 | } | 753 | } |
750 | ringtone->NokiaBinary.Length=ringtone->NokiaBinary.Length-i; | 754 | ringtone->NokiaBinary.Length=ringtone->NokiaBinary.Length-i; |
751 | memcpy(ringtone->NokiaBinary.Frame,buffer+i,ringtone->NokiaBinary.Length); | 755 | memcpy(ringtone->NokiaBinary.Frame,buffer+i,ringtone->NokiaBinary.Length); |
752 | dbgprintf("Length %i name \"%s\"\n",ringtone->NokiaBinary.Length,DecodeUnicodeString(ringtone->Name)); | 756 | dbgprintf("Length %i name \"%s\"\n",ringtone->NokiaBinary.Length,DecodeUnicodeString(ringtone->Name)); |
753 | return ERR_NONE; | 757 | return ERR_NONE; |
754 | } | 758 | } |
755 | 759 | ||
756 | static GSM_Error loadpuremidi(FILE *file, GSM_Ringtone *ringtone) | 760 | static GSM_Error loadpuremidi(FILE *file, GSM_Ringtone *ringtone) |
757 | { | 761 | { |
758 | unsigned char buffer[30000]; | 762 | unsigned char buffer[30000]; |
759 | 763 | ||
760 | dbgprintf("loading midi\n"); | 764 | dbgprintf("loading midi\n"); |
761 | EncodeUnicode(ringtone->Name,"MIDI",4); | 765 | EncodeUnicode(ringtone->Name,"MIDI",4); |
762 | ringtone->NokiaBinary.Length=fread(buffer, 1, 30000, file); | 766 | ringtone->NokiaBinary.Length=fread(buffer, 1, 30000, file); |
763 | memcpy(ringtone->NokiaBinary.Frame,buffer,ringtone->NokiaBinary.Length); | 767 | memcpy(ringtone->NokiaBinary.Frame,buffer,ringtone->NokiaBinary.Length); |
764 | dbgprintf("Length %i name \"%s\"\n",ringtone->NokiaBinary.Length,DecodeUnicodeString(ringtone->Name)); | 768 | dbgprintf("Length %i name \"%s\"\n",ringtone->NokiaBinary.Length,DecodeUnicodeString(ringtone->Name)); |
765 | return ERR_NONE; | 769 | return ERR_NONE; |
766 | } | 770 | } |
767 | 771 | ||
768 | static GSM_Error loadre(FILE *file, GSM_Ringtone *ringtone) | 772 | static GSM_Error loadre(FILE *file, GSM_Ringtone *ringtone) |
769 | { | 773 | { |
770 | unsigned char buffer[2000]; | 774 | unsigned char buffer[2000]; |
771 | 775 | ||
772 | ringtone->NokiaBinary.Length=fread(buffer, 1, 500, file); | 776 | ringtone->NokiaBinary.Length=fread(buffer, 1, 500, file); |
773 | 777 | ||
774 | if (buffer[18]==0x00 && buffer[21]!=0x02) { | 778 | if (buffer[18]==0x00 && buffer[21]!=0x02) { |
775 | /* DCT3, Unicode subformat, 62xx & 7110 */ | 779 | /* DCT3, Unicode subformat, 62xx & 7110 */ |
776 | CopyUnicodeString(ringtone->Name,buffer+18); | 780 | CopyUnicodeString(ringtone->Name,buffer+18); |
777 | ringtone->NokiaBinary.Length = ringtone->NokiaBinary.Length - (21+UnicodeLength(ringtone->Name)*2); | 781 | ringtone->NokiaBinary.Length = ringtone->NokiaBinary.Length - (21+UnicodeLength(ringtone->Name)*2); |
778 | memcpy(ringtone->NokiaBinary.Frame,buffer+21+UnicodeLength(ringtone->Name)*2,ringtone->NokiaBinary.Length); | 782 | memcpy(ringtone->NokiaBinary.Frame,buffer+21+UnicodeLength(ringtone->Name)*2,ringtone->NokiaBinary.Length); |
779 | } else { | 783 | } else { |
780 | /* DCT3, normal subformat, 32xx/33xx/51xx/5210/5510/61xx/8xxx */ | 784 | /* DCT3, normal subformat, 32xx/33xx/51xx/5210/5510/61xx/8xxx */ |
781 | EncodeUnicode(ringtone->Name,buffer+17,buffer[16]); | 785 | EncodeUnicode(ringtone->Name,buffer+17,buffer[16]); |
782 | ringtone->NokiaBinary.Length = ringtone->NokiaBinary.Length - (19+UnicodeLength(ringtone->Name)); | 786 | ringtone->NokiaBinary.Length = ringtone->NokiaBinary.Length - (19+UnicodeLength(ringtone->Name)); |
783 | memcpy(ringtone->NokiaBinary.Frame,buffer+19+UnicodeLength(ringtone->Name),ringtone->NokiaBinary.Length); | 787 | memcpy(ringtone->NokiaBinary.Frame,buffer+19+UnicodeLength(ringtone->Name),ringtone->NokiaBinary.Length); |
784 | } | 788 | } |
785 | dbgprintf("Name \"%s\"\n",DecodeUnicodeString(ringtone->Name)); | 789 | dbgprintf("Name \"%s\"\n",DecodeUnicodeString(ringtone->Name)); |
786 | return ERR_NONE; | 790 | return ERR_NONE; |
787 | } | 791 | } |
788 | 792 | ||
789 | GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone) | 793 | GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone) |
790 | { | 794 | { |
791 | FILE *file; | 795 | FILE *file; |
792 | unsigned charbuffer[300]; | 796 | unsigned charbuffer[300]; |
793 | GSM_Errorerror = ERR_UNKNOWN; | 797 | GSM_Errorerror = ERR_UNKNOWN; |
794 | 798 | ||
795 | dbgprintf("Loading ringtone %s\n",FileName); | 799 | dbgprintf("Loading ringtone %s\n",FileName); |
796 | file = fopen(FileName, "rb"); | 800 | file = fopen(FileName, "rb"); |
797 | if (file == NULL) return ERR_CANTOPENFILE; | 801 | if (file == NULL) return ERR_CANTOPENFILE; |
798 | 802 | ||
799 | /* Read the header of the file. */ | 803 | /* Read the header of the file. */ |
800 | fread(buffer, 1, 4, file); | 804 | fread(buffer, 1, 4, file); |
801 | if (ringtone->Format == 0x00) { | 805 | if (ringtone->Format == 0x00) { |
802 | ringtone->Format = RING_NOTETONE; | 806 | ringtone->Format = RING_NOTETONE; |
803 | if (buffer[0]==0x00 && buffer[1]==0x00 && | 807 | if (buffer[0]==0x00 && buffer[1]==0x00 && |
804 | buffer[2]==0x0C && buffer[3]==0x01) { | 808 | buffer[2]==0x0C && buffer[3]==0x01) { |
805 | ringtone->Format = RING_NOKIABINARY; | 809 | ringtone->Format = RING_NOKIABINARY; |
806 | } | 810 | } |
807 | if (buffer[0]==0x00 && buffer[1]==0x00 && | 811 | if (buffer[0]==0x00 && buffer[1]==0x00 && |
808 | buffer[2]==0x00) { | 812 | buffer[2]==0x00) { |
809 | ringtone->Format = RING_NOKIABINARY; | 813 | ringtone->Format = RING_NOKIABINARY; |
810 | } | 814 | } |
811 | if (buffer[0]==0x4D && buffer[1]==0x54 && | 815 | if (buffer[0]==0x4D && buffer[1]==0x54 && |
812 | buffer[2]==0x68 && buffer[3]==0x64) { | 816 | buffer[2]==0x68 && buffer[3]==0x64) { |
813 | ringtone->Format = RING_MIDI; | 817 | ringtone->Format = RING_MIDI; |
814 | } | 818 | } |
815 | } | 819 | } |
816 | rewind(file); | 820 | rewind(file); |
817 | switch (ringtone->Format) { | 821 | switch (ringtone->Format) { |
818 | case RING_NOTETONE: | 822 | case RING_NOTETONE: |
819 | if (buffer[0]==0x02 && buffer[1]==0x4A) { | 823 | if (buffer[0]==0x02 && buffer[1]==0x4A) { |
820 | error=loadott(file,ringtone); | 824 | error=loadott(file,ringtone); |
821 | } else if (buffer[0]==0xC7 && buffer[1]==0x45) { | 825 | } else if (buffer[0]==0xC7 && buffer[1]==0x45) { |
822 | error=loadcommunicator(file,ringtone); | 826 | error=loadcommunicator(file,ringtone); |
823 | } else { | 827 | } else { |
824 | error=loadrttl(file,ringtone); | 828 | error=loadrttl(file,ringtone); |
825 | } | 829 | } |
826 | ringtone->NoteTone.AllNotesScale=false; | 830 | ringtone->NoteTone.AllNotesScale=false; |
827 | break; | 831 | break; |
828 | case RING_NOKIABINARY: | 832 | case RING_NOKIABINARY: |
829 | if (buffer[0]==0x00 && buffer[1]==0x00 && | 833 | if (buffer[0]==0x00 && buffer[1]==0x00 && |
830 | buffer[2]==0x0C && buffer[3]==0x01) { | 834 | buffer[2]==0x0C && buffer[3]==0x01) { |
831 | error=loadbin(file,ringtone); | 835 | error=loadbin(file,ringtone); |
832 | } | 836 | } |
833 | if (buffer[0]==0x00 && buffer[1]==0x00 && | 837 | if (buffer[0]==0x00 && buffer[1]==0x00 && |
834 | buffer[2]==0x00) { | 838 | buffer[2]==0x00) { |
835 | error=loadre(file,ringtone); | 839 | error=loadre(file,ringtone); |
836 | } | 840 | } |
837 | break; | 841 | break; |
838 | case RING_MIDI: | 842 | case RING_MIDI: |
839 | EncodeUnicode(ringtone->Name,FileName,strlen(FileName)); | 843 | EncodeUnicode(ringtone->Name,FileName,strlen(FileName)); |
840 | error = loadpuremidi(file,ringtone); | 844 | error = loadpuremidi(file,ringtone); |
841 | } | 845 | } |
842 | fclose(file); | 846 | fclose(file); |
843 | return(error); | 847 | return(error); |
844 | } | 848 | } |
845 | 849 | ||
846 | /* -------------------------- required with Nokia & RTTL ------------------- */ | 850 | /* -------------------------- required with Nokia & RTTL ------------------- */ |
847 | 851 | ||
848 | /* Beats per Minute like written in Smart Messaging */ | 852 | /* Beats per Minute like written in Smart Messaging */ |
849 | static int SM_BeatsPerMinute[] = { | 853 | static int SM_BeatsPerMinute[] = { |
850 | 25, 28, 31, 35, 40, 45, 50, 56, 63,70, | 854 | 25, 28, 31, 35, 40, 45, 50, 56, 63,70, |
851 | 80, 90, 100, 112, 125, 140, 160, 180, 200,225, | 855 | 80, 90, 100, 112, 125, 140, 160, 180, 200,225, |
852 | 250, 285, 320, 355, 400, 450, 500, 565, 635,715, | 856 | 250, 285, 320, 355, 400, 450, 500, 565, 635,715, |
853 | 800,900 | 857 | 800,900 |
854 | }; | 858 | }; |
855 | 859 | ||
856 | int GSM_RTTLGetTempo(int Beats) | 860 | int GSM_RTTLGetTempo(int Beats) |
857 | { | 861 | { |
858 | int i=0; | 862 | int i=0; |
859 | 863 | ||
860 | while (Beats > SM_BeatsPerMinute[i] && SM_BeatsPerMinute[i] != 900) i++; | 864 | while (Beats > SM_BeatsPerMinute[i] && SM_BeatsPerMinute[i] != 900) i++; |
861 | 865 | ||
862 | return i<<3; | 866 | return i<<3; |
863 | } | 867 | } |
864 | 868 | ||
865 | /* This function packs the ringtone from the structure "ringtone" to | 869 | /* This function packs the ringtone from the structure "ringtone" to |
866 | "package", where maxlength means length of package. | 870 | "package", where maxlength means length of package. |
867 | Function returns number of packed notes and change maxlength to | 871 | Function returns number of packed notes and change maxlength to |
868 | number of used chars in "package" */ | 872 | number of used chars in "package" */ |
869 | unsigned char GSM_EncodeNokiaRTTLRingtone(GSM_Ringtone ringtone, unsigned char *package, int *maxlength) | 873 | unsigned char GSM_EncodeNokiaRTTLRingtone(GSM_Ringtone ringtone, unsigned char *package, int *maxlength) |
870 | { | 874 | { |
871 | unsigned char CommandLength = 0x02; | 875 | unsigned char CommandLength = 0x02; |
872 | unsigned char Loop = 0x15;/* Infinite */ | 876 | unsigned char Loop = 0x15;/* Infinite */ |
873 | 877 | ||
874 | unsigned char Buffer[200]; | 878 | unsigned char Buffer[200]; |
875 | int StartBit=0, OldStartBit; | 879 | int StartBit=0, OldStartBit; |
876 | int StartBitHowManyCommands; | 880 | int StartBitHowManyCommands; |
877 | int HowManyCommands = 0;/* How many instructions packed */ | 881 | int HowManyCommands = 0;/* How many instructions packed */ |
878 | int HowManyNotes= 0; | 882 | int HowManyNotes= 0; |
879 | int i,j; | 883 | int i,j; |
880 | bool started; | 884 | bool started; |
881 | GSM_RingNote *Note; | 885 | GSM_RingNote *Note; |
882 | 886 | ||
883 | GSM_RingNoteScale DefScale = 255; | 887 | GSM_RingNoteScale DefScale = 255; |
884 | GSM_RingNoteStyle DefStyle = 255; | 888 | GSM_RingNoteStyle DefStyle = 255; |
885 | int DefTempo = 255; | 889 | int DefTempo = 255; |
886 | 890 | ||
887 | AddBufferByte(package, &StartBit, CommandLength, 8); | 891 | AddBufferByte(package, &StartBit, CommandLength, 8); |
888 | AddBufferByte(package, &StartBit, SM_Command_RingingToneProgramming, 7); | 892 | AddBufferByte(package, &StartBit, SM_Command_RingingToneProgramming, 7); |
889 | 893 | ||
890 | /* According to specification we need have next part octet-aligned */ | 894 | /* According to specification we need have next part octet-aligned */ |
891 | BufferAlign(package, &StartBit); | 895 | BufferAlign(package, &StartBit); |
892 | 896 | ||
893 | AddBufferByte(package, &StartBit, SM_Command_Sound, 7); | 897 | AddBufferByte(package, &StartBit, SM_Command_Sound, 7); |
894 | AddBufferByte(package, &StartBit, SM_Song_BasicSongType, 3); | 898 | AddBufferByte(package, &StartBit, SM_Song_BasicSongType, 3); |
895 | 899 | ||
896 | /* Packing the name of the tune. */ | 900 | /* Packing the name of the tune. */ |
897 | EncodeUnicodeSpecialNOKIAChars(Buffer, ringtone.Name, UnicodeLength(ringtone.Name)); | 901 | EncodeUnicodeSpecialNOKIAChars(Buffer, ringtone.Name, UnicodeLength(ringtone.Name)); |
898 | AddBufferByte(package, &StartBit, ((unsigned char)(UnicodeLength(Buffer)<<4)), 4); | 902 | AddBufferByte(package, &StartBit, ((unsigned char)(UnicodeLength(Buffer)<<4)), 4); |
899 | AddBuffer(package, &StartBit, DecodeUnicodeString(Buffer), 8*UnicodeLength(Buffer)); | 903 | AddBuffer(package, &StartBit, DecodeUnicodeString(Buffer), 8*UnicodeLength(Buffer)); |
900 | 904 | ||
901 | /* Packing info about song pattern */ | 905 | /* Packing info about song pattern */ |
902 | AddBufferByte(package, &StartBit, 0x01, 8); //one pattern | 906 | AddBufferByte(package, &StartBit, 0x01, 8); //one pattern |
903 | AddBufferByte(package, &StartBit, SM_InstructionID_PatternHeaderId, 3); | 907 | AddBufferByte(package, &StartBit, SM_InstructionID_PatternHeaderId, 3); |
904 | AddBufferByte(package, &StartBit, SM_PatternID_A_part, 2); | 908 | AddBufferByte(package, &StartBit, SM_PatternID_A_part, 2); |
905 | AddBufferByte(package, &StartBit, ((unsigned char)(Loop<<4)), 4); | 909 | AddBufferByte(package, &StartBit, ((unsigned char)(Loop<<4)), 4); |
906 | 910 | ||
907 | /* Later here will be HowManyCommands */ | 911 | /* Later here will be HowManyCommands */ |
908 | StartBitHowManyCommands=StartBit; | 912 | StartBitHowManyCommands=StartBit; |
909 | StartBit = StartBit + 8; | 913 | StartBit = StartBit + 8; |
910 | 914 | ||
911 | started = false; | 915 | started = false; |
912 | for (i=0; i<ringtone.NoteTone.NrCommands; i++) { | 916 | for (i=0; i<ringtone.NoteTone.NrCommands; i++) { |
913 | if (ringtone.NoteTone.Commands[i].Type != RING_Note) { | 917 | if (ringtone.NoteTone.Commands[i].Type != RING_Note) { |
914 | HowManyNotes++; | 918 | HowManyNotes++; |
915 | continue; | 919 | continue; |
916 | } | 920 | } |
917 | Note = &ringtone.NoteTone.Commands[i].Note; | 921 | Note = &ringtone.NoteTone.Commands[i].Note; |
918 | if (!started) { | 922 | if (!started) { |
919 | /* First note can't be Pause - it makes problems | 923 | /* First note can't be Pause - it makes problems |
920 | * for example with PC Composer | 924 | * for example with PC Composer |
921 | */ | 925 | */ |
922 | if (Note->Note != Note_Pause) started = true; | 926 | if (Note->Note != Note_Pause) started = true; |
923 | } | 927 | } |
924 | if (!started) { | 928 | if (!started) { |
925 | HowManyNotes++; | 929 | HowManyNotes++; |
926 | continue; | 930 | continue; |
927 | } | 931 | } |
928 | OldStartBit = StartBit; | 932 | OldStartBit = StartBit; |
929 | /* we don't write Scale & Style info before "Pause" note - it saves place */ | 933 | /* we don't write Scale & Style info before "Pause" note - it saves place */ |
930 | if (Note->Note!=Note_Pause) { | 934 | if (Note->Note!=Note_Pause) { |
931 | if (DefScale != Note->Scale || ringtone.NoteTone.AllNotesScale) { | 935 | if (DefScale != Note->Scale || ringtone.NoteTone.AllNotesScale) { |
932 | j = StartBit+5+8; | 936 | j = StartBit+5+8; |
933 | BufferAlignNumber(&j); | 937 | BufferAlignNumber(&j); |
934 | if ((j/8)>(*maxlength)) { | 938 | if ((j/8)>(*maxlength)) { |
935 | StartBit = OldStartBit; | 939 | StartBit = OldStartBit; |
936 | break; | 940 | break; |
937 | } | 941 | } |
938 | DefScale = Note->Scale; | 942 | DefScale = Note->Scale; |
939 | AddBufferByte(package, &StartBit, SM_InstructionID_ScaleInstructionId, 3); | 943 | AddBufferByte(package, &StartBit, SM_InstructionID_ScaleInstructionId, 3); |
940 | AddBufferByte(package, &StartBit, ((unsigned char)((DefScale-4)<<6)), 2); | 944 | AddBufferByte(package, &StartBit, ((unsigned char)((DefScale-4)<<6)), 2); |
941 | HowManyCommands++; | 945 | HowManyCommands++; |
942 | } | 946 | } |
943 | if (DefStyle != Note->Style) { | 947 | if (DefStyle != Note->Style) { |
944 | j = StartBit+5+8; | 948 | j = StartBit+5+8; |
945 | BufferAlignNumber(&j); | 949 | BufferAlignNumber(&j); |
946 | if ((j/8)>(*maxlength)) { | 950 | if ((j/8)>(*maxlength)) { |
947 | StartBit = OldStartBit; | 951 | StartBit = OldStartBit; |
948 | break; | 952 | break; |
949 | } | 953 | } |
950 | DefStyle = Note->Style; | 954 | DefStyle = Note->Style; |
951 | AddBufferByte(package, &StartBit, SM_InstructionID_StyleInstructionId, 3); | 955 | AddBufferByte(package, &StartBit, SM_InstructionID_StyleInstructionId, 3); |
952 | AddBufferByte(package, &StartBit, ((unsigned char)DefStyle), 2); | 956 | AddBufferByte(package, &StartBit, ((unsigned char)DefStyle), 2); |
953 | HowManyCommands++; | 957 | HowManyCommands++; |
954 | } | 958 | } |
955 | } | 959 | } |
956 | /* Beats per minute/tempo of the tune */ | 960 | /* Beats per minute/tempo of the tune */ |
957 | if (DefTempo != GSM_RTTLGetTempo(Note->Tempo)) { | 961 | if (DefTempo != GSM_RTTLGetTempo(Note->Tempo)) { |
958 | j = StartBit+8+8; | 962 | j = StartBit+8+8; |
959 | BufferAlignNumber(&j); | 963 | BufferAlignNumber(&j); |
960 | if ((j/8)>(*maxlength)) { | 964 | if ((j/8)>(*maxlength)) { |
961 | StartBit = OldStartBit; | 965 | StartBit = OldStartBit; |
962 | break; | 966 | break; |
963 | } | 967 | } |
964 | DefTempo=GSM_RTTLGetTempo(Note->Tempo); | 968 | DefTempo=GSM_RTTLGetTempo(Note->Tempo); |
965 | /* Adding beats per minute (tempo) of the tune */ | 969 | /* Adding beats per minute (tempo) of the tune */ |
966 | AddBufferByte(package, &StartBit, SM_InstructionID_TempoInstructionId, 3); | 970 | AddBufferByte(package, &StartBit, SM_InstructionID_TempoInstructionId, 3); |
967 | AddBufferByte(package, &StartBit, ((unsigned char)DefTempo), 5); | 971 | AddBufferByte(package, &StartBit, ((unsigned char)DefTempo), 5); |
968 | HowManyCommands++; | 972 | HowManyCommands++; |
969 | } | 973 | } |
970 | j = StartBit+12+8; | 974 | j = StartBit+12+8; |
971 | BufferAlignNumber(&j); | 975 | BufferAlignNumber(&j); |
972 | if ((j/8)>(*maxlength)) { | 976 | if ((j/8)>(*maxlength)) { |
973 | StartBit = OldStartBit; | 977 | StartBit = OldStartBit; |
974 | break; | 978 | break; |
975 | } | 979 | } |
976 | /* Note */ | 980 | /* Note */ |
977 | AddBufferByte(package, &StartBit, SM_InstructionID_NoteInstructionId, 3); | 981 | AddBufferByte(package, &StartBit, SM_InstructionID_NoteInstructionId, 3); |
978 | AddBufferByte(package, &StartBit, ((unsigned char)Note->Note), 4); | 982 | AddBufferByte(package, &StartBit, ((unsigned char)Note->Note), 4); |
979 | AddBufferByte(package, &StartBit, ((unsigned char)Note->Duration), 3); | 983 | AddBufferByte(package, &StartBit, ((unsigned char)Note->Duration), 3); |
980 | AddBufferByte(package, &StartBit, ((unsigned char)Note->DurationSpec), 2); | 984 | AddBufferByte(package, &StartBit, ((unsigned char)Note->DurationSpec), 2); |
981 | HowManyCommands++; | 985 | HowManyCommands++; |
982 | /* We are sure, we pack it for SMS or setting to phone, not for OTT file */ | 986 | /* We are sure, we pack it for SMS or setting to phone, not for OTT file */ |
983 | if (*maxlength<1000) { | 987 | if (*maxlength<1000) { |
984 | /* Like Pc Composer say - before of phone limitations...*/ | 988 | /* Like Pc Composer say - before of phone limitations...*/ |
985 | if (HowManyNotes==130-1) break; | 989 | if (HowManyNotes==130-1) break; |
986 | } | 990 | } |
987 | HowManyNotes++; | 991 | HowManyNotes++; |
988 | } | 992 | } |
989 | 993 | ||
990 | BufferAlign(package, &StartBit); | 994 | BufferAlign(package, &StartBit); |
991 | AddBufferByte(package, &StartBit, SM_CommandEnd_CommandEnd, 8); | 995 | AddBufferByte(package, &StartBit, SM_CommandEnd_CommandEnd, 8); |
992 | 996 | ||
993 | OldStartBit = StartBit; | 997 | OldStartBit = StartBit; |
994 | StartBit = StartBitHowManyCommands; | 998 | StartBit = StartBitHowManyCommands; |
995 | /* HowManyCommands */ | 999 | /* HowManyCommands */ |
996 | AddBufferByte(package, &StartBit, ((unsigned char)HowManyCommands), 8); | 1000 | AddBufferByte(package, &StartBit, ((unsigned char)HowManyCommands), 8); |
997 | StartBit = OldStartBit; | 1001 | StartBit = OldStartBit; |
998 | 1002 | ||
999 | *maxlength=StartBit/8; | 1003 | *maxlength=StartBit/8; |
1000 | 1004 | ||
1001 | return(i); | 1005 | return(i); |
1002 | } | 1006 | } |
1003 | 1007 | ||
1004 | GSM_Error GSM_DecodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, int maxlength) | 1008 | GSM_Error GSM_DecodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, int maxlength) |
1005 | { | 1009 | { |
1006 | int StartBit=0, HowMany, l, q, i, spec; | 1010 | int StartBit=0, HowMany, l, q, i, spec; |
1007 | char Buffer[100]; | 1011 | char Buffer[100]; |
1008 | GSM_RingNote *Note; | 1012 | GSM_RingNote *Note; |
1009 | 1013 | ||
1010 | /* Default ringtone parameters */ | 1014 | /* Default ringtone parameters */ |
1011 | GSM_RingNoteScale DefScale= Scale_880; | 1015 | GSM_RingNoteScale DefScale= Scale_880; |
1012 | GSM_RingNoteStyle DefStyle = NaturalStyle; | 1016 | GSM_RingNoteStyle DefStyle = NaturalStyle; |
1013 | int DefTempo= 63; | 1017 | int DefTempo= 63; |
1014 | 1018 | ||
1015 | ringtone->Format = RING_NOTETONE; | 1019 | ringtone->Format = RING_NOTETONE; |
1016 | ringtone->NoteTone.NrCommands = 0; | 1020 | ringtone->NoteTone.NrCommands = 0; |
1017 | 1021 | ||
1018 | GetBufferInt(package,&StartBit,&l,8); | 1022 | GetBufferInt(package,&StartBit,&l,8); |
1019 | if (l!=0x02) { | 1023 | if (l!=0x02) { |
1020 | dbgprintf("Not header\n"); | 1024 | dbgprintf("Not header\n"); |
1021 | return ERR_NOTSUPPORTED; | 1025 | return ERR_NOTSUPPORTED; |
1022 | } | 1026 | } |
1023 | 1027 | ||
1024 | GetBufferInt(package,&StartBit,&l,7); | 1028 | GetBufferInt(package,&StartBit,&l,7); |
1025 | if (l!=SM_Command_RingingToneProgramming) { | 1029 | if (l!=SM_Command_RingingToneProgramming) { |
1026 | dbgprintf("Not RingingToneProgramming\n"); | 1030 | dbgprintf("Not RingingToneProgramming\n"); |
1027 | return ERR_NOTSUPPORTED; | 1031 | return ERR_NOTSUPPORTED; |
1028 | } | 1032 | } |
1029 | 1033 | ||
1030 | /* According to specification we need have next part octet-aligned */ | 1034 | /* According to specification we need have next part octet-aligned */ |
1031 | BufferAlignNumber(&StartBit); | 1035 | BufferAlignNumber(&StartBit); |
1032 | 1036 | ||
1033 | GetBufferInt(package,&StartBit,&l,7); | 1037 | GetBufferInt(package,&StartBit,&l,7); |
1034 | if (l!=SM_Command_Sound) { | 1038 | if (l!=SM_Command_Sound) { |
1035 | dbgprintf("Not Sound\n"); | 1039 | dbgprintf("Not Sound\n"); |
1036 | return ERR_NOTSUPPORTED; | 1040 | return ERR_NOTSUPPORTED; |
1037 | } | 1041 | } |
1038 | 1042 | ||
1039 | GetBufferInt(package,&StartBit,&l,3); | 1043 | GetBufferInt(package,&StartBit,&l,3); |
1040 | if (l!=SM_Song_BasicSongType) { | 1044 | if (l!=SM_Song_BasicSongType) { |
1041 | dbgprintf("Not BasicSongType\n"); | 1045 | dbgprintf("Not BasicSongType\n"); |
1042 | return ERR_NOTSUPPORTED; | 1046 | return ERR_NOTSUPPORTED; |
1043 | } | 1047 | } |
1044 | 1048 | ||
1045 | /* Getting length of the tune name */ | 1049 | /* Getting length of the tune name */ |
1046 | GetBufferInt(package,&StartBit,&l,4); | 1050 | GetBufferInt(package,&StartBit,&l,4); |
1047 | l=l>>4; | 1051 | l=l>>4; |
1048 | 1052 | ||
1049 | /* Unpacking the name of the tune. */ | 1053 | /* Unpacking the name of the tune. */ |
1050 | GetBuffer(package, &StartBit, Buffer, 8*l); | 1054 | GetBuffer(package, &StartBit, Buffer, 8*l); |
1051 | Buffer[l]=0; | 1055 | Buffer[l]=0; |
1052 | EncodeUnicode(ringtone->Name,Buffer,strlen(Buffer)); | 1056 | EncodeUnicode(ringtone->Name,Buffer,strlen(Buffer)); |
1053 | DecodeUnicodeSpecialNOKIAChars(Buffer, ringtone->Name, UnicodeLength(ringtone->Name)); | 1057 | DecodeUnicodeSpecialNOKIAChars(Buffer, ringtone->Name, UnicodeLength(ringtone->Name)); |
1054 | CopyUnicodeString(ringtone->Name,Buffer); | 1058 | CopyUnicodeString(ringtone->Name,Buffer); |
1055 | 1059 | ||
1056 | GetBufferInt(package,&StartBit,&l,8); | 1060 | GetBufferInt(package,&StartBit,&l,8); |
1057 | dbgprintf("Number of song patterns: %i\n",l); | 1061 | dbgprintf("Number of song patterns: %i\n",l); |
1058 | /* we support only one song pattern */ | 1062 | /* we support only one song pattern */ |
1059 | if (l!=1) return ERR_NOTSUPPORTED; | 1063 | if (l!=1) return ERR_NOTSUPPORTED; |
1060 | 1064 | ||
1061 | GetBufferInt(package,&StartBit,&l,3); | 1065 | GetBufferInt(package,&StartBit,&l,3); |
1062 | if (l!=SM_InstructionID_PatternHeaderId) { | 1066 | if (l!=SM_InstructionID_PatternHeaderId) { |
1063 | dbgprintf("Not PatternHeaderId\n"); | 1067 | dbgprintf("Not PatternHeaderId\n"); |
1064 | return ERR_NOTSUPPORTED; | 1068 | return ERR_NOTSUPPORTED; |
1065 | } | 1069 | } |
1066 | 1070 | ||
1067 | /* Pattern ID - we ignore it */ | 1071 | /* Pattern ID - we ignore it */ |
1068 | StartBit+=2; | 1072 | StartBit+=2; |
1069 | 1073 | ||
1070 | GetBufferInt(package,&StartBit,&l,4); | 1074 | GetBufferInt(package,&StartBit,&l,4); |
1071 | l=l>>4; | 1075 | l=l>>4; |
1072 | dbgprintf("Loop value: %i\n",l); | 1076 | dbgprintf("Loop value: %i\n",l); |
1073 | 1077 | ||
1074 | HowMany=0; | 1078 | HowMany=0; |
1075 | GetBufferInt(package, &StartBit, &HowMany, 8); | 1079 | GetBufferInt(package, &StartBit, &HowMany, 8); |
1076 | 1080 | ||
1077 | for (i=0;i<HowMany;i++) { | 1081 | for (i=0;i<HowMany;i++) { |
1078 | GetBufferInt(package,&StartBit,&q,3); | 1082 | GetBufferInt(package,&StartBit,&q,3); |
1079 | switch (q) { | 1083 | switch (q) { |
1080 | case SM_InstructionID_VolumeInstructionId: | 1084 | case SM_InstructionID_VolumeInstructionId: |
1081 | StartBit+=4; | 1085 | StartBit+=4; |
1082 | break; | 1086 | break; |
1083 | case SM_InstructionID_StyleInstructionId: | 1087 | case SM_InstructionID_StyleInstructionId: |
1084 | GetBufferInt(package,&StartBit,&l,2); | 1088 | GetBufferInt(package,&StartBit,&l,2); |
1085 | if (l>=NaturalStyle && l<=StaccatoStyle) DefStyle = l; | 1089 | if (l>=NaturalStyle && l<=StaccatoStyle) DefStyle = l; |
1086 | break; | 1090 | break; |
1087 | case SM_InstructionID_TempoInstructionId: | 1091 | case SM_InstructionID_TempoInstructionId: |
1088 | GetBufferInt(package,&StartBit,&l,5); | 1092 | GetBufferInt(package,&StartBit,&l,5); |
1089 | DefTempo=SM_BeatsPerMinute[l>>3]; | 1093 | DefTempo=SM_BeatsPerMinute[l>>3]; |
1090 | break; | 1094 | break; |
1091 | case SM_InstructionID_ScaleInstructionId: | 1095 | case SM_InstructionID_ScaleInstructionId: |
1092 | GetBufferInt(package,&StartBit,&l,2); | 1096 | GetBufferInt(package,&StartBit,&l,2); |
1093 | DefScale=(l>>6)+4; | 1097 | DefScale=(l>>6)+4; |
1094 | break; | 1098 | break; |
1095 | case SM_InstructionID_NoteInstructionId: | 1099 | case SM_InstructionID_NoteInstructionId: |
1096 | Note = &ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Note; | 1100 | Note = &ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Note; |
1097 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_Note; | 1101 | ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_Note; |
1098 | 1102 | ||
1099 | GetBufferInt(package,&StartBit,&l,4); | 1103 | GetBufferInt(package,&StartBit,&l,4); |
1100 | Note->Note=Note_Pause; | 1104 | Note->Note=Note_Pause; |
1101 | if (l >= Note_C && l <= Note_H) Note->Note = l; | 1105 | if (l >= Note_C && l <= Note_H) Note->Note = l; |
1102 | 1106 | ||
1103 | GetBufferInt(package,&StartBit,&l,3); | 1107 | GetBufferInt(package,&StartBit,&l,3); |
1104 | if (l >= Duration_Full && l <= Duration_1_32) Note->Duration = l; | 1108 | if (l >= Duration_Full && l <= Duration_1_32) Note->Duration = l; |
1105 | 1109 | ||
1106 | GetBufferInt(package,&StartBit,&spec,2); | 1110 | GetBufferInt(package,&StartBit,&spec,2); |
1107 | if (spec >= NoSpecialDuration && spec <= Length_2_3) { | 1111 | if (spec >= NoSpecialDuration && spec <= Length_2_3) { |
1108 | Note->DurationSpec = spec; | 1112 | Note->DurationSpec = spec; |
1109 | } | 1113 | } |
1110 | 1114 | ||
1111 | Note->Scale = DefScale; | 1115 | Note->Scale = DefScale; |
1112 | Note->Style = DefStyle; | 1116 | Note->Style = DefStyle; |
1113 | Note->Tempo = DefTempo; | 1117 | Note->Tempo = DefTempo; |
1114 | if (ringtone->NoteTone.NrCommands==MAX_RINGTONE_NOTES) break; | 1118 | if (ringtone->NoteTone.NrCommands==MAX_RINGTONE_NOTES) break; |
1115 | ringtone->NoteTone.NrCommands++; | 1119 | ringtone->NoteTone.NrCommands++; |
1116 | break; | 1120 | break; |
1117 | default: | 1121 | default: |
1118 | dbgprintf("Unsupported block %i %i\n",q,i); | 1122 | dbgprintf("Unsupported block %i %i\n",q,i); |
1119 | return ERR_NOTSUPPORTED; | 1123 | return ERR_NOTSUPPORTED; |
1120 | } | 1124 | } |
1121 | } | 1125 | } |
1122 | return ERR_NONE; | 1126 | return ERR_NONE; |
1123 | } | 1127 | } |
1124 | 1128 | ||
1125 | static void RTTL2Binary(GSM_Ringtone *dest, GSM_Ringtone *src) | 1129 | static void RTTL2Binary(GSM_Ringtone *dest, GSM_Ringtone *src) |
1126 | { | 1130 | { |
1127 | int current = 0, i, note, lastnote = 0, duration; | 1131 | int current = 0, i, note, lastnote = 0, duration; |
1128 | GSM_RingNote *Note; | 1132 | GSM_RingNote *Note; |
1129 | unsigned char end[] = {0x40, 0x7D, 0x40, 0x5C, 0x0A, 0xFE, 0x40, | 1133 | unsigned char end[] = {0x40, 0x7D, 0x40, 0x5C, 0x0A, 0xFE, 0x40, |
1130 | 0x20, 0x40, 0x7D, 0x40, 0x37, 0x0A, 0xFE, | 1134 | 0x20, 0x40, 0x7D, 0x40, 0x37, 0x0A, 0xFE, |
1131 | 0x0A, 0x0A, 0x40, 0x32, 0x07, 0x0B}; | 1135 | 0x0A, 0x0A, 0x40, 0x32, 0x07, 0x0B}; |
1132 | 1136 | ||