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.
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.
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/>.
18 /* Data Create/Free functions */
19 msData *_ms_create() {
22 ms = ( msData * ) calloc( sizeof( msData ), 1 );
25 ms->peakThreshold = PEAK_THRESHOLD;
26 ms->peakOffset = PEAK_OFFSET;
31 msData *ms_create( const short *pcmData, int pcmDataLen ) {
38 ms->pcmData = ( short * )pcmData;
39 ms->pcmDataLen = pcmDataLen;
44 msData *ms_free( msData *ms ) {
49 llist_free( ms->peakList );
52 free( ms->bitStream );
55 free( ms->charStream );
62 void ms_reinit( msData *ms ) {
67 llist_free( ms->peakList );
72 free( ms->bitStream );
76 if( ms->charStream ) {
77 free( ms->charStream );
78 ms->charStream = NULL;
82 /* Misc User Functions */
83 void ms_set_peakThreshold( msData *ms, int peakThreshold ) {
86 ms->peakThreshold = peakThreshold;
89 void ms_set_peakOffset( msData *ms, int peakOffset ) {
92 ms->peakOffset = peakOffset;
95 const char *ms_get_bitStream( msData *ms ) {
101 const char *ms_get_charStream( msData *ms ) {
104 return ms->charStream;
109 int ms_range( int a, int b1, int b2 ) {
110 if( ( a >= b1 && a <= b2 ) || ( a >= b2 && a <= b1 ) )
115 #define RANGE_OFFSET 2
116 void ms_peaks_find( msData *ms ) {
118 short *pcmData, *pcmDataOffset;
120 if( ms == NULL || ( ms->pcmData == NULL ) )
123 if( ms->peakList == NULL )
124 ms->peakList = llist_init();
126 llist_reinit( ms->peakList );
128 pcmData = ms->pcmData + RANGE_OFFSET;
129 pcmDataOffset = pcmData + ms->peakOffset;
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 ) ) ) {
135 llist_append( ms->peakList, i, ms->pcmData[ i ] );
140 void ms_peaks_find_walk( msData *ms ) {
145 if( ms == NULL || ( ms->pcmData == NULL ) )
148 if( ms->peakList == NULL )
149 ms->peakList = llist_init();
151 llist_reinit( ms->peakList );
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 );
163 void ms_peaks_filter_group( msData *ms ) {
167 int pos;//indicates pos/neg (not position)
169 if( !ms || ms->peakList->len < 2 )
172 pos = ( ms->peakList->first->amp > 0 );
174 groupList = llist_init();
175 for( trav = ms->peakList->first; trav != NULL; trav = trav->next ) {
177 if( ( trav->amp > 0 ) != pos ) {
179 _ms_peaks_filter_groupFind( ms, groupList );
182 llist_append( groupList, trav->idx, trav->amp );
186 _ms_peaks_filter_groupFind( ms, groupList );
188 groupList = llist_free( groupList );
193 LListH *_ms_peaks_filter_groupFind( msData *ms, LListH *groupList ) {
200 if( !ms || groupList == NULL || groupList->len < 2 )
203 bigPeak.idx = groupList->first->idx;
204 bigPeak.amp = abs( groupList->first->amp );
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 );
212 llist_remove_idx( ms->peakList, trav->idx );
216 llist_reinit( groupList );
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 );
227 if( oneDif < zeroDif ) {
238 void ms_decode_peaks( msData *ms ) {
242 char lastBit, curBit, bitStream[ MAX_BITSTREAM_LEN + 1 ];
244 if( !ms || ms->peakList == NULL || ms->peakList->len < 3 )
247 if( ms->bitStream ) {
248 free( ms->bitStream );
249 ms->bitStream = NULL;
252 lastPeakidx = ms->peakList->first->next->idx;
253 clock = ( ms->peakList->first->next->next->idx - lastPeakidx ) / 2;
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;
268 lastPeakidx = trav->idx;
271 bitStream[ len ] = '\0';
273 ms->bitStream = ( char * ) malloc( sizeof( char ) * strlen( bitStream ) + 1 );
274 strcpy( ms->bitStream, bitStream );
277 /* String Reverse Function */
278 void ms_strrev( char *str ) {
282 for( f = 0, l = strlen( str ) - 1; l > f; f++, l-- ) {
289 /* Bit Decode functions */
290 int ms_decode_typeDetect( msData *ms ) {
294 if( !ms || !ms->bitStream || strlen( ms->bitStream ) < 10 )
298 bitStream = strchr( ms->bitStream + 5, '1' );
299 if( bitStream == NULL )
302 if( !strncmp( bitStream, ABA_SS, ABA_CHAR_LEN ) && strncmp( bitStream, ABA_SS ABA_ES, ABA_CHAR_LEN * 2 ) ) {
305 } else if( !strncmp( bitStream, IATA_SS, IATA_CHAR_LEN ) && strncmp( bitStream,IATA_SS IATA_ES, IATA_CHAR_LEN * 2 ) ) {
310 ms_strrev( ms->bitStream );
314 ms->dataType = UNKNOWN;
319 int ms_decode_bits( msData *ms ) {
321 char charStream[ MAX_IATA_LEN + 1 ], curChar;
322 char LRC[ IATA_CHAR_LEN ] = { 0 };
323 int bitStreamLen, i, x, len, validSwipe;
324 int maxLen, charLen, badChars;
326 if( !ms || !ms->bitStream )
329 if( ms_decode_typeDetect( ms ) )
332 if( ms->dataType == ABA ) {
333 maxLen = MAX_ABA_LEN;
334 charLen = ABA_CHAR_LEN;
336 maxLen = MAX_IATA_LEN;
337 charLen = IATA_CHAR_LEN;
340 if( ms->charStream ) {
341 free( ms->charStream );
342 ms->charStream = NULL;
347 bitStream = strchr( ms->bitStream, '1' );
348 if( bitStream == NULL ) // if stream contains no 1s, it's bad, just quit
351 bitStreamLen = strlen( bitStream );
353 /* Traverse the bitstream to decode all the bits into a charstream */
356 for( i = 0, len = 0; ( i + charLen ) < bitStreamLen && len < maxLen && curChar != '?'; i += charLen, len++ ) {
357 curChar = _ms_decode_bits_char( bitStream + i, LRC, ms->dataType );
358 charStream[ len ] = curChar;
359 if( curChar == BAD_CHAR )
360 badChars++; // count the bad chars
362 charStream[ len ] = '\0';
364 /* Print warning about any detected bad characters */
366 fprintf( stderr, "ms_decode_bits(): Warning: %d chars failed parity check\n", badChars );
370 ms->charStream = ( char * ) malloc( sizeof( char ) * strlen( charStream ) + 1 );
371 strcpy( ms->charStream, charStream );
372 if( !ms->charStream )
376 /* Calculate the parity bit for the LRC */
377 LRC[ ( charLen - 1 ) ] = 1;
378 for( x = 0; x < ( charLen - 1 ); x++ ) {
380 LRC[ ( charLen - 1 ) ] = !LRC[ ( charLen - 1 ) ];
381 LRC[ x ] += NUM_ASCII_OFFSET;
383 LRC[ ( charLen - 1 ) ] += NUM_ASCII_OFFSET;
386 if( strncmp( LRC, bitStream + i, charLen ) ) {
387 fprintf( stderr, "ms_decode_bits(): Warning: LRC error decoding stream\n" );
394 char _ms_decode_bits_char( char *bitStream, char *LRC, ms_dataType type ) {
397 int len; // char length not including parity
398 int offset; // offset to make it ASCII
401 len = ABA_CHAR_LEN - 1;
402 offset = ABA_ASCII_OFFSET;
404 len = IATA_CHAR_LEN - 1;
405 offset = IATA_ASCII_OFFSET;
408 for( i = 0, out = 0; i < len; i++ ) {
409 out |= ( bitStream[ i ] - NUM_ASCII_OFFSET ) << i; // using OR to assign the bits into the char
410 if( bitStream[ i ] == '1' ) {
411 LRC[ i ] = !LRC[ i ]; // flip the bit in the LRC for all 1 bits in the char
412 parity++; // count the number of 1 bits for the parity bit
417 if( ( parity & 1 ) == ( bitStream[ len ] - NUM_ASCII_OFFSET ) )
418 out = BAD_CHAR; // return the error char if the calculated parity bit doesn't match the recorded one
424 void ms_save( msData *ms, const char *filenamebase ) {
433 fnlen = strlen( filenamebase );
434 strncpy( filename, filenamebase, 256 );
436 if( ms->peakList != NULL ) {
437 strncpy( filename + fnlen, ".peaks", 256 - fnlen );
439 output = fopen( filename, "w" );
443 for( trav = ms->peakList->first; trav != NULL; trav = trav->next ) {
444 fprintf( output, "%d %d\n", trav->idx, trav->amp );
450 strncpy( filename + fnlen, ".pcm", 256 - fnlen );
451 output = fopen( filename, "w" );
455 fwrite( ms->pcmData, sizeof( short ), ms->pcmDataLen, output );