Add bugtracker to control file
[magread] / mslib.c
1 /*
2  * This file is part of mslib.
3  * mslib is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * mslib is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with nosebus.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 #include "mslib.h"
17
18 /* Data Create/Free functions */
19 msData *_ms_create() {
20         msData *ms;
21
22         ms = ( msData * ) calloc( sizeof( msData ), 1 );
23         if ( !ms )
24                 return NULL;
25         ms->peakThreshold = PEAK_THRESHOLD;
26         ms->peakOffset = PEAK_OFFSET;
27
28         return ms;
29 }
30
31 msData *ms_create( const short *pcmData, int pcmDataLen ) {
32         msData *ms;
33
34         ms = _ms_create();
35         if( !ms )
36                 return NULL;
37         
38         ms->pcmData = ( short * )pcmData;
39         ms->pcmDataLen = pcmDataLen;
40
41         return ms;
42 }
43
44 msData *ms_free( msData *ms ) {
45         if( !ms )
46                 return NULL;
47         
48         if( ms->peakList )
49                 llist_free( ms->peakList );
50         
51         if( ms->bitStream )
52                 free( ms->bitStream );
53         
54         if( ms->charStream )
55                 free( ms->charStream );
56
57         free( ms );
58
59         return NULL;
60 }
61
62 void ms_reinit( msData *ms ) {
63         if( !ms )
64                 return;
65
66         if( ms->peakList ) {
67                 llist_free( ms->peakList );
68                 ms->peakList = NULL;
69         }
70         
71         if( ms->bitStream ) {
72                 free( ms->bitStream );
73                 ms->bitStream = NULL;
74         }
75
76         if( ms->charStream ) {
77                 free( ms->charStream );
78                 ms->charStream = NULL;
79         }
80 }
81
82 /* Misc User Functions */
83 void ms_set_peakThreshold( msData *ms, int peakThreshold ) {
84         if( !ms )
85                 return;
86         ms->peakThreshold = peakThreshold;
87 }
88
89 void ms_set_peakOffset( msData *ms, int peakOffset ) {
90         if( !ms )
91                 return;
92         ms->peakOffset = peakOffset;
93 }
94
95 const char *ms_get_bitStream( msData *ms ) {
96         if( !ms )
97                 return NULL;
98         return ms->bitStream;
99 }
100
101 const char *ms_get_charStream( msData *ms ) {
102         if( !ms )
103                 return NULL;
104         return ms->charStream;
105 }
106
107
108 /* Finding Peaks */
109 int ms_range( int a, int b1, int b2 ) {
110         if( ( a >= b1 && a <= b2 ) || ( a >= b2 && a <= b1 ) )
111                 return 1;
112         return 0;
113 }
114
115 #define RANGE_OFFSET 2
116 void ms_peaks_find( msData *ms ) {
117         int i;
118         short *pcmData, *pcmDataOffset;
119         
120         if( ms == NULL || ( ms->pcmData == NULL ) )
121                 return;
122         
123         if( ms->peakList == NULL )
124                 ms->peakList = llist_init();
125         else
126                 llist_reinit( ms->peakList );
127
128         pcmData = ms->pcmData + RANGE_OFFSET;
129         pcmDataOffset = pcmData + ms->peakOffset;
130
131         for( i = ms->peakOffset + RANGE_OFFSET; i < ms->pcmDataLen; i++, pcmData++, pcmDataOffset++ ) {
132                 if( abs( *pcmData ) > ms->peakThreshold &&
133                         ms_range( *pcmData, *( pcmDataOffset - RANGE_OFFSET ), *( pcmDataOffset + RANGE_OFFSET ) ) ) {
134
135                         llist_append( ms->peakList, i, ms->pcmData[ i ] );
136                 }
137         }
138 }
139
140 void ms_peaks_find_walk( msData *ms ) {
141         int i;
142         short *pcmData;
143
144
145         if( ms == NULL || ( ms->pcmData == NULL ) )
146                 return;
147                 
148         if( ms->peakList == NULL )
149                 ms->peakList = llist_init();
150         else
151                 llist_reinit( ms->peakList );
152
153         for( i = 0, pcmData = ms->pcmData; i+1 < ms->pcmDataLen; i++, pcmData++ ) {
154                 if( abs( *pcmData ) > ms->peakThreshold ) {
155                         if( abs( pcmData[ 1 ] ) < abs( *pcmData ) ) {
156                                 llist_append( ms->peakList, i, *pcmData );
157                         }
158                 }
159         }
160 }
161
162
163 void ms_peaks_filter_group( msData *ms ) {
164         LList *trav;
165         LListH *groupList;
166         
167         int pos;//indicates pos/neg (not position)
168
169         if( !ms || ms->peakList->len < 2 )
170                 return;
171         
172         pos = ( ms->peakList->first->amp > 0 );
173
174         groupList = llist_init();
175         for( trav = ms->peakList->first; trav != NULL; trav = trav->next ) {
176
177                 if( ( trav->amp > 0 ) != pos ) {
178                         pos = !pos;
179                         _ms_peaks_filter_groupFind( ms, groupList );
180                 }
181                 
182                 llist_append( groupList, trav->idx, trav->amp );
183         }
184
185         if( groupList->len )
186                 _ms_peaks_filter_groupFind( ms, groupList );
187         
188         groupList = llist_free( groupList );
189 }
190
191
192
193 LListH *_ms_peaks_filter_groupFind( msData *ms, LListH *groupList ) {
194         LList *trav;
195         struct {
196                 int idx;
197                 short amp;
198         } bigPeak;
199
200         if( !ms || groupList == NULL || groupList->len < 2 )
201                 return NULL;
202         
203         bigPeak.idx = groupList->first->idx;
204         bigPeak.amp = abs( groupList->first->amp );
205
206         for( trav = groupList->first->next; trav != NULL; trav = trav->next ) {
207                 if( abs( trav->amp ) > bigPeak.amp ) {
208                         llist_remove_idx( ms->peakList, bigPeak.idx );
209                         bigPeak.idx = trav->idx;
210                         bigPeak.amp = abs( trav->amp );
211                 } else {
212                         llist_remove_idx( ms->peakList, trav->idx );
213                 }
214         }
215
216         llist_reinit( groupList );
217         return groupList;
218 }
219
220
221 /* Peak Decode functions */
222 char _ms_closer( int *oneClock, int dif ) {
223         int oneDif = abs( *oneClock - dif );
224         int zeroDif = abs( ( *oneClock * 2 ) - dif );
225         char bit;
226
227         if( oneDif < zeroDif ) {
228                 *oneClock = dif;
229                 bit = '1';
230         } else {
231                 *oneClock = dif / 2;
232                 bit = '0';
233         }
234
235         return bit;
236 }
237
238 void ms_decode_peaks( msData *ms ) {
239         LList *trav;
240         int clock, len;
241         int lastPeakidx;
242         char lastBit, curBit, bitStream[ MAX_BITSTREAM_LEN + 1 ];
243
244         if( !ms || ms->peakList == NULL || ms->peakList->len < 3 )
245                 return;
246
247         if( ms->bitStream ) {
248                 free( ms->bitStream );
249                 ms->bitStream = NULL;
250         }
251         
252         lastPeakidx = ms->peakList->first->next->idx;
253         clock = ( ms->peakList->first->next->next->idx - lastPeakidx ) / 2;
254
255         len = 0;
256         lastBit = '\0';
257
258         for( trav = ms->peakList->first->next; trav != NULL && len < MAX_BITSTREAM_LEN; trav = trav->next ) {
259                 curBit = _ms_closer( &clock, ( trav->idx - lastPeakidx ) );
260                 if( curBit == '0' ) {
261                         bitStream[ len++ ] = curBit;
262                 } else if( curBit == lastBit ) {
263                         bitStream[ len++ ] = curBit;
264                         curBit = '\0';
265                 }
266                 
267                 lastBit = curBit;
268                 lastPeakidx = trav->idx;
269         }
270
271         bitStream[ len ] = '\0';
272
273         ms->bitStream = ( char * ) malloc( sizeof( char ) * strlen( bitStream ) + 1 );
274         strcpy( ms->bitStream, bitStream );
275 }
276
277 /* String Reverse Function */
278 void strrev( char *str ) {
279         int f, l;
280         char tmp;
281
282         for( f = 0, l = strlen( str ) - 1; l > f; f++, l-- ) {
283                 tmp = str[ f ];
284                 str[ f ] = str[ l ];
285                 str[ l ] = tmp;
286         }
287 }
288
289 /* Bit Decode functions */
290 int ms_decode_typeDetect( msData *ms ) {
291         char *bitStream;
292         int loop = 2;
293
294         if( !ms || !ms->bitStream )
295                 return 1;
296
297
298         do {
299                 bitStream = strchr( ms->bitStream, '1' );
300                 if( bitStream == NULL )
301                         break;
302         
303                 if( !strncmp( bitStream, ABA_SS, ABA_CHAR_LEN ) ) {
304                         ms->dataType = ABA;
305                         return 0;
306                 } else if( !strncmp( bitStream, IATA_SS, IATA_CHAR_LEN ) ) {
307                         ms->dataType = IATA;
308                         return 0;
309                 }
310
311                 strrev( ms->bitStream );
312                 loop--;
313         } while( loop );
314
315
316         ms->dataType = UNKNOWN;
317         return 1;
318 }
319
320
321 int ms_decode_bits( msData *ms ) {
322         char *bitStream;
323         char charStream[ MAX_IATA_LEN + 1 ], curChar;
324         char LRC[ IATA_CHAR_LEN ] = { 0 };
325         int bitStreamLen, i, x, len, validSwipe;
326         int maxLen, charLen, badChars;
327
328         if( !ms || !ms->bitStream )
329                 return -1;
330
331         if( ms_decode_typeDetect( ms ) )
332                 return -1;
333
334         if( ms->dataType == ABA ) {
335                 maxLen = MAX_ABA_LEN;
336                 charLen = ABA_CHAR_LEN;
337         } else {
338                 maxLen = MAX_IATA_LEN;
339                 charLen = IATA_CHAR_LEN;
340         }
341
342         if( ms->charStream ) {
343                 free( ms->charStream );
344                 ms->charStream = NULL;
345         }
346
347         validSwipe = 0;
348
349         bitStream = strchr( ms->bitStream, '1' );
350         if( bitStream == NULL ) // if stream contains no 1s, it's bad, just quit
351                 return 1;
352         
353         bitStreamLen = strlen( bitStream );
354
355         /* Traverse the bitstream to decode all the bits into a charstream */
356         curChar = '\0';
357         badChars = 0;
358         for( i = 0, len = 0; ( i + charLen ) < bitStreamLen && len < maxLen && curChar != '?'; i += charLen, len++ ) {
359                 curChar = _ms_decode_bits_char( bitStream + i, LRC, ms->dataType );
360                 charStream[ len ] = curChar;
361                 if( curChar == BAD_CHAR )
362                         badChars++; // count the bad chars
363         }
364         charStream[ len ] = '\0';
365
366         /* Print warning about any detected bad characters */
367         if( badChars ) {
368                 fprintf( stderr, "ms_decode_bits(): Warning: %d chars failed parity check\n", badChars );
369                 validSwipe = 1;
370         }
371
372         ms->charStream = ( char * ) malloc( sizeof( char ) * strlen( charStream ) + 1 );
373         strcpy( ms->charStream, charStream );
374         if( !ms->charStream )
375                 return 1;
376         
377
378         /* Calculate the parity bit for the LRC */
379         LRC[ ( charLen - 1 ) ] = 1;
380         for( x = 0; x < ( charLen - 1 ); x++ ) {
381                 if( LRC[ x ] == 1 )
382                         LRC[ ( charLen - 1 ) ] = !LRC[ ( charLen - 1 ) ];
383                 LRC[ x ] += NUM_ASCII_OFFSET;
384         }
385         LRC[ ( charLen - 1 ) ] += NUM_ASCII_OFFSET;
386         
387         /* Verify the LRC */
388         if( strncmp( LRC, bitStream + i, charLen ) ) {
389                 fprintf( stderr, "ms_decode_bits(): Warning: LRC error decoding stream\n" );
390                 validSwipe = 1;
391         }
392
393         return validSwipe;
394 }
395
396 char _ms_decode_bits_char( char *bitStream, char *LRC, ms_dataType type ) {
397         int parity = 0, i;
398         char out;
399         int len; // char length not including parity
400         int offset; // offset to make it ASCII
401
402         if( type == ABA ) {
403                 len = ABA_CHAR_LEN - 1;
404                 offset = ABA_ASCII_OFFSET;
405         } else {
406                 len = IATA_CHAR_LEN - 1;
407                 offset = IATA_ASCII_OFFSET;
408         }
409
410         for( i = 0, out = 0; i < len; i++ ) {
411                 out |= ( bitStream[ i ] - NUM_ASCII_OFFSET ) << i; // using OR to assign the bits into the char
412                 if( bitStream[ i ] == '1' ) {
413                         LRC[ i ] = !LRC[ i ]; // flip the bit in the LRC for all 1 bits in the char
414                         parity++; // count the number of 1 bits for the parity bit
415                 }
416         }
417         out += offset;
418
419         if( ( parity & 1 ) == ( bitStream[ len ] - NUM_ASCII_OFFSET ) )
420                 out = BAD_CHAR; // return the error char if the calculated parity bit doesn't match the recorded one
421         
422         return out;
423 }
424
425
426 void ms_save( msData *ms, const char *filenamebase ) {
427         LList *trav;
428         FILE *output;
429         char filename[256];
430         int fnlen;
431
432         if( ms == NULL )
433                 return;
434
435         fnlen = strlen( filenamebase );
436         strncpy( filename, filenamebase, 256 );
437         
438         if( ms->peakList != NULL ) {
439                 strncpy( filename + fnlen, ".peaks", 256 - fnlen );
440
441                 output = fopen( filename, "w" );
442                 if( output == NULL )
443                         return;
444
445                 for( trav = ms->peakList->first; trav != NULL; trav = trav->next ) {
446                         fprintf( output, "%d %d\n", trav->idx, trav->amp );
447                 }
448
449                 fclose( output );
450         }
451
452         strncpy( filename + fnlen, ".pcm", 256 - fnlen );
453         output = fopen( filename, "w" );
454         if( output == NULL )
455                 return;
456
457         fwrite( ms->pcmData, sizeof( short ), ms->pcmDataLen, output );
458         
459         fclose( output );
460 }
461