Bump to version 0.1.1
[magread] / audioinput.cpp
1 /*
2     This file is part of MagRead.
3
4     MagRead is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8
9     MagRead is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with MagRead.  If not, see <http://www.gnu.org/licenses/>.
16     
17     Written by Jeffrey Malone <ieatlint@tehinterweb.com>
18     http://blog.tehinterweb.com
19 */
20 #include "audioinput.h"
21
22 #include <QDebug>
23
24 #define BUF_SIZE 1024
25 //#define DEBUG
26
27 AudioInput::AudioInput(QObject *parent) : QThread(parent) {
28         paSpec.format = PA_SAMPLE_S16LE;
29         paSpec.channels = 1;
30         paSpec.rate = 48000;
31
32         paServer = NULL;
33         captureAudio = false;
34         silenceThresh = 750;
35
36         ms = 0;
37 }
38
39 AudioInput::~AudioInput() {
40         if( paServer )
41                 pa_simple_free( paServer );
42 }
43
44 void AudioInput::run() {
45         #ifdef DEBUG
46         qDebug() << "AudioInput::run() start";
47         #endif
48
49         paServer = pa_simple_new( NULL, "MagRead", PA_STREAM_RECORD, "source.hw0", "Recording", &paSpec, NULL, NULL, &paError );
50         if( !paServer ) {
51                 QString err = "Failed to open PulseAudio server:\n";
52                 err.append( pa_strerror( paError ) );
53                 emit error( err );
54                 return;
55         }
56
57         captureAudio = true;
58
59
60         qint16 pcmDataBlock[ BUF_SIZE ];
61         int i, silence = 0;
62         bool noise = false;
63         pcmData.clear();
64         while(  captureAudio ) {
65                 if( pa_simple_read( paServer, pcmDataBlock, ( sizeof( qint16 ) * BUF_SIZE ), &paError ) ) {
66                         QString err = "Failed to read a block of data:\n";
67                         err.append( pa_strerror( paError ) );
68                         emit error( err );
69                         captureAudio = false;
70                         noise = false;
71                 }
72
73                 for( i = 0; i < BUF_SIZE; i++ ) {
74                         if( qAbs( pcmDataBlock[ i ] ) > silenceThresh ) {
75                                 noise = true;
76                                 silence = 0;
77                         } else {
78                                 silence++;
79                         }
80                 }
81
82                 if( noise ) {
83                         pcmData.append( pcmDataBlock, BUF_SIZE );
84                 }
85
86                 if( noise && silence > 200 ) {
87                         captureAudio = false;
88                 } else if( noise && ( pcmData.count() / BUF_SIZE ) > 30 ) {
89                         /* Stream is too fucking long, we're clearing and restarting */
90                         pcmData.clear();
91                         silence = 0;
92                         noise = false;
93                 }
94         }
95
96         pa_simple_free( paServer );
97         paServer = NULL;
98
99         if( noise ) {
100                 processSwipe();
101         }
102         #ifdef DEBUG
103         qDebug() << "AudioInput::run() stop";
104         #endif
105 }
106
107 void AudioInput::stop() {
108         #ifdef DEBUG
109         qDebug() << "AudioInput::stop() ";
110         #endif
111         captureAudio = false;
112 }
113
114 void AudioInput::processSwipe() {
115         int retval;
116
117         #ifdef DEBUG
118         qDebug() << "AudioInput::processSwipe() start";
119         #endif
120
121         if( ms )
122                 ms_free( ms );
123
124         ms = ms_create( pcmData.data(), pcmData.count() );
125         #ifdef DEBUG
126         qDebug() << "AudioInput::processSwipe() 1";
127         #endif
128
129         //ms_peaks_find( ms );
130         ms_peaks_find_walk( ms );
131         ms_peaks_filter_group( ms );
132         #ifdef DEBUG
133         qDebug() << "AudioInput::processSwipe() 2";
134         #endif
135
136         ms_decode_peaks( ms );
137         #ifdef DEBUG
138         qDebug() << "AudioInput::processSwipe() 3";
139         #endif
140
141         retval = ( ms_decode_bits( ms ) == 0 ) ;
142
143         card.charStream = ms_get_charStream( ms );
144         if( !card.charStream.isEmpty() ) {
145                 card.encoding = ms->dataType;
146                 card.swipeValid = retval;
147
148                 emit cardRead( card );
149         }
150
151         run();
152 }
153