~ubuntu-branches/ubuntu/trusty/fldigi/trusty

« back to all changes in this revision

Viewing changes to src/mfsk/mfsk.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Joop Stakenborg
  • Date: 2008-11-17 19:40:43 UTC
  • mfrom: (1.1.6 upstream) (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20081117194043-sfe108e41ppsyhxr
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 
27
27
#include <config.h>
28
28
 
29
 
#include <stdlib.h>
30
 
#include <iostream>
 
29
#include <cstdlib>
 
30
#include <cstring>
 
31
#include <libgen.h>
31
32
 
32
33
#include "mfsk.h"
33
34
#include "modem.h"
 
35
#include "afcind.h"
 
36
 
34
37
#include "configuration.h"
35
38
#include "status.h"
36
39
#include "trx.h"
37
40
 
38
41
#include "ascii.h"
39
42
 
40
 
#include "File_Selector.h"
 
43
#include "fileselect.h"
41
44
 
42
45
#include "qrunner.h"
43
46
 
44
 
#define AFC_COUNT       32
45
 
 
46
47
using namespace std;
47
48
 
 
49
//=============================================================================
48
50
char mfskmsg[80];
49
 
char txclr_tooltip[24];
50
 
char txgry_tooltip[24];
 
51
//=============================================================================
 
52
 
 
53
#include "mfsk-pic.cxx"
51
54
 
52
55
void  mfsk::tx_init(SoundBase *sc)
53
56
{
54
57
        scard = sc;
55
58
        txstate = TX_STATE_PREAMBLE;
56
59
        bitstate = 0;
57
 
        counter = 0;
 
60
        
58
61
        videoText();
59
62
}
60
63
 
66
69
        met1 = 0.0;
67
70
        met2 = 0.0;
68
71
        counter = 0;
69
 
        for (int i = 0; i < 2 * symlen; i++)
 
72
        for (int i = 0; i < 2 * symlen; i++) {
70
73
                for (int j = 0; j < 32; j++)
71
74
                        (pipe[i].vector[j]).re = (pipe[i].vector[j]).im = 0.0;
 
75
        }
72
76
        reset_afc();
73
77
        s2n = 0.0;
74
78
        memset(picheader, ' ', PICHEADER - 1);
75
79
        picheader[PICHEADER -1] = 0;
76
80
        put_MODEstatus(mode);
 
81
        set_AFCrange (tonespacing / 10.0);
 
82
        syncfilter->reset();
 
83
        staticburst = false;
77
84
}
78
85
 
79
86
void mfsk::init()
80
87
{
81
88
        modem::init();
82
89
        rx_init();
83
 
        digiscope->mode(Digiscope::SCOPE);
 
90
        set_scope_mode(Digiscope::SCOPE);
 
91
// picture mode init
 
92
        setpicture_link(this);
 
93
        TXspp = txSPP;
 
94
        RXspp = 8;
 
95
}
 
96
 
 
97
void mfsk::shutdown()
 
98
{
84
99
}
85
100
 
86
101
mfsk::~mfsk()
87
102
{
 
103
        stopflag = true;
 
104
        if (picTxWin)
 
105
                picTxWin->hide();
 
106
        if (picRxWin)
 
107
                picRxWin->hide();
 
108
 
88
109
        if (bpfilt) delete bpfilt;
89
110
        if (rxinlv) delete rxinlv;
90
111
        if (txinlv) delete txinlv;
94
115
        if (pipe) delete [] pipe;
95
116
        if (hbfilt) delete hbfilt;
96
117
        if (binsfft) delete binsfft;
 
118
        for (int i = 0; i < SCOPESIZE; i++) {
 
119
                if (vidfilter[i]) delete vidfilter[i];
 
120
        }
 
121
        if (syncfilter) delete syncfilter;
97
122
}
98
123
 
99
124
mfsk::mfsk(trx_mode mfsk_mode) : modem()
100
125
{
 
126
        cap = CAP_AFC | CAP_REV;
 
127
 
101
128
        double bw, cf, flo, fhi;
102
129
        mode = mfsk_mode;
103
130
 
104
131
        switch (mode) {
105
 
 
 
132
                
106
133
        case MODE_MFSK8:
 
134
                samplerate = 8000;
107
135
                symlen =  1024;
108
136
                symbits =    5;
109
 
                basetone = 128;         /* 1000 Hz */
 
137
                basetone = 128;
 
138
                numtones = 32;
110
139
                break;
111
140
        case MODE_MFSK16:
 
141
                samplerate = 8000;
 
142
                symlen =  512;
 
143
                symbits =   4;
 
144
                basetone = 64;
 
145
                numtones = 16;
 
146
                cap |= CAP_IMG;
 
147
                break;
 
148
        case MODE_MFSK32:
 
149
                samplerate = 8000;
 
150
                symlen =  256;
 
151
                symbits =   4;
 
152
                basetone = 32;
 
153
                numtones = 16;
 
154
                cap |= CAP_IMG;
 
155
                break;
 
156
 
 
157
        case MODE_MFSK4:
 
158
                samplerate = 8000;
 
159
                symlen = 2048;
 
160
                symbits = 5;
 
161
                basetone = 256;
 
162
                numtones = 32;
 
163
                break;
 
164
        case MODE_MFSK31:
 
165
                samplerate = 8000;
 
166
                symlen =  256;
 
167
                symbits =   3;
 
168
                basetone = 32;
 
169
                numtones = 8;
 
170
                cap |= CAP_IMG;
 
171
                break;
 
172
        case MODE_MFSK64:
 
173
                samplerate = 8000;
 
174
                symlen =  128;
 
175
                symbits =    4;
 
176
                basetone = 16;
 
177
                numtones = 16;
 
178
                cap |= CAP_IMG;
 
179
                break;
 
180
        case MODE_MFSK11:
 
181
                samplerate = 11025;
 
182
                symlen =  1024;
 
183
                symbits =   4;
 
184
                basetone = 93;
 
185
                numtones = 16;
 
186
                cap |= CAP_IMG;
 
187
                break;
 
188
        case MODE_MFSK22:
 
189
                samplerate = 11025;
 
190
                symlen =  512;
 
191
                symbits =    4;
 
192
                basetone = 46;
 
193
                numtones = 16;
 
194
                cap |= CAP_IMG;
 
195
                break;
 
196
//
112
197
        default:
 
198
                samplerate = 8000;
113
199
                symlen =  512;
114
200
                symbits =   4;
115
 
                basetone = 64;          /* 1000 Hz */
 
201
                basetone = 64;
 
202
                numtones = 16;
116
203
        break;
117
204
        }
118
205
 
119
 
        numtones = 1 << symbits;
120
 
        tonespacing = (double) MFSKSampleRate / symlen;
 
206
        tonespacing = (double) samplerate / symlen;
 
207
        basefreq = 1.0 * samplerate * basetone / symlen;
121
208
 
122
 
        binsfft         = new sfft (symlen, basetone, basetone + numtones + 3);
 
209
        binsfft         = new sfft (symlen, basetone, basetone + numtones );
123
210
        hbfilt          = new C_FIR_filter();
124
211
        hbfilt->init_hilbert(37, 1);
125
 
        afcfilt         = new Cmovavg(AFC_COUNT);
 
212
 
 
213
        syncfilter = new Cmovavg(8);
 
214
        
 
215
        for (int i = 0; i < SCOPESIZE; i++)
 
216
                vidfilter[i] = new Cmovavg(16);
126
217
 
127
218
        pipe            = new rxpipe[ 2 * symlen ];
128
219
 
139
230
        rxinlv = new interleave (symbits, INTERLEAVE_REV);
140
231
 
141
232
        bw = (numtones - 1) * tonespacing;
142
 
        cf = 1000.0 + bw / 2.0;
 
233
        cf = basefreq + bw / 2.0;
143
234
 
144
 
        flo = (cf - bw) / MFSKSampleRate;
145
 
        fhi = (cf + bw) / MFSKSampleRate;
 
235
        flo = (cf - bw/2 - 2 * tonespacing) / samplerate;
 
236
        fhi = (cf + bw/2 + 2 * tonespacing) / samplerate;
146
237
 
147
238
        bpfilt = new C_FIR_filter();
148
239
        bpfilt->init_bandpass (127, 1, flo, fhi);
149
240
 
150
241
        scopedata.alloc(symlen * 2);
151
242
 
152
 
        samplerate = MFSKSampleRate;
153
243
        fragmentsize = symlen;
154
244
        bandwidth = (numtones - 1) * tonespacing;
155
245
        
156
 
        picRxWin = 0;
157
 
        picRxBox = 0;
158
 
        picRx = 0;
159
 
        picTxWin = 0;
160
 
        picTx = 0;
161
246
        startpic = false;
162
247
        abortxmt = false;
 
248
        stopflag = false;
 
249
 
163
250
        bitshreg = 0;
164
251
        bitstate = 0;
165
252
        phaseacc = 0;
167
254
        metric = 0;
168
255
        prev1symbol = prev2symbol = 0;
169
256
        symbolpair[0] = symbolpair[1] = 0;
170
 
 
 
257
        
 
258
// picTxWin and picRxWin are created once to support all instances of mfsk
 
259
        if (!picTxWin) createTxViewer();
 
260
        if (!picRxWin) {
 
261
                createRxViewer();
 
262
                activate_mfsk_image_item(true);
 
263
        }
171
264
        init();
172
 
}
173
265
 
174
 
void mfsk::shutdown()
175
 
{
176
 
        stopflag = true;
177
 
        if (picTxWin)
178
 
                picTxWin->hide();
179
266
}
180
267
 
181
268
 
217
304
                color = true;
218
305
                p++;
219
306
        }
220
 
 
 
307
        if (*p == ';') {
 
308
                if (picW == 0 || picH == 0 || picW > 4095 || picH > 4095)
 
309
                        return false;
 
310
                RXspp = 8;
 
311
                return true;
 
312
        }
 
313
        if (*p == 'p')
 
314
                p++;
 
315
        else
 
316
                return false;
 
317
        if (!*p) 
 
318
                return false;
 
319
        RXspp = 8;
 
320
        if (*p == '4') RXspp = 4;
 
321
        if (*p == '2') RXspp = 2;
 
322
        p++;
 
323
        if (!*p) 
 
324
                return false;
221
325
        if (*p != ';')
222
326
                return false;
223
 
 
224
327
        if (picW == 0 || picH == 0 || picW > 4095 || picH > 4095)
225
328
                return false;
226
 
 
227
329
        return true;
228
330
}
229
331
 
230
332
void mfsk::recvpic(complex z)
231
333
{
232
334
        int byte;
233
 
        picf += (prevz % z).arg() * samplerate / twopi;
 
335
        picf += (prevz % z).arg() * samplerate / TWOPI;
234
336
        prevz = z;
235
337
 
236
 
        if ((counter % SAMPLES_PER_PIXEL) == 0) {
237
 
                picf = 256 * (picf / SAMPLES_PER_PIXEL - 1000) / bandwidth;
 
338
        if (RXspp < 8 && progdefaults.slowcpu == true)
 
339
                return;
 
340
                
 
341
        if ((counter % RXspp) == 0) {
 
342
                picf = 256 * (picf / RXspp - basefreq) / bandwidth;
238
343
                byte = (int)CLAMP(picf, 0.0, 255.0);
239
344
                if (reverse)
240
345
                        byte = 255 - byte;
241
346
                
242
347
                if (color) {
243
348
                        pixelnbr = rgb + row + 3*col;
244
 
                        REQ(&mfsk::updateRxPic, this, byte, pixelnbr);
 
349
                        REQ(updateRxPic, byte, pixelnbr);
245
350
                        if (++col == picW) {
246
351
                                col = 0;
247
352
                                if (++rgb == 3) {
251
356
                        }
252
357
                } else {
253
358
                        for (int i = 0; i < 3; i++)
254
 
                                REQ(&mfsk::updateRxPic, this, byte, pixelnbr++);
 
359
                                REQ(updateRxPic, byte, pixelnbr++);
255
360
                }
256
361
                picf = 0.0;
257
362
 
258
363
                int n = picW * picH * 3;
259
 
                int s = snprintf(mfskmsg, sizeof(mfskmsg),
260
 
                                 "Recv picture: %04.1f%% done",
261
 
                                 (100.0f * pixelnbr) / n);
262
 
                print_time_left(n - pixelnbr, mfskmsg + s,
263
 
                                sizeof(mfskmsg) - s, ", ", " left");
264
 
                put_status(mfskmsg);
 
364
                if (pixelnbr % (picW * 3) == 0) {
 
365
                        int s = snprintf(mfskmsg, sizeof(mfskmsg),
 
366
                                         "Recv picture: %04.1f%% done",
 
367
                                         (100.0f * pixelnbr) / n);
 
368
                        print_time_left( (n - pixelnbr ) * 0.000125 * RXspp , 
 
369
                                        mfskmsg + s,
 
370
                                        sizeof(mfskmsg) - s, ", ", " left");
 
371
                        put_status(mfskmsg);
 
372
                }
265
373
        }
266
374
}
267
375
 
271
379
                return;
272
380
 
273
381
        if (check_picture_header(c) == true) {
274
 
                if (symbolbit == 4) {
275
 
                        rxstate = RX_STATE_PICTURE_START_1;
276
 
                }
277
 
                else {
278
 
                        rxstate = RX_STATE_PICTURE_START_2;
279
 
                }
280
 
                
281
 
                picturesize = SAMPLES_PER_PIXEL * picW * picH * (color ? 3 : 1);
282
 
                counter = 0;
283
 
                
284
 
                makeRxViewer(picW, picH);
 
382
// 44 nulls at 8 samples per pixel
 
383
// 88 nulls at 4 samples per pixel
 
384
// 176 nulls at 2 samples per pixel
 
385
                counter = 352; 
 
386
                if (symbolbit == symbits) counter += symlen;
 
387
                rxstate = RX_STATE_PICTURE_START;
 
388
                picturesize = RXspp * picW * picH * (color ? 3 : 1);
285
389
                pixelnbr = 0;
286
390
                col = 0;
287
391
                row = 0;
288
392
                rgb = 0;
289
 
 
290
393
                memset(picheader, ' ', PICHEADER - 1);
291
394
                picheader[PICHEADER -1] = 0;            
292
395
        }
293
 
 
294
396
        put_rx_char(c);
 
397
        
295
398
}
296
399
 
297
400
void mfsk::recvbit(int bit)
316
419
 
317
420
        symcounter = symcounter ? 0 : 1;
318
421
 
319
 
        /* MFSK16 doesn't need a vote */
320
 
        if (mode == MODE_MFSK16 && symcounter)
321
 
                return;
322
 
 
323
 
        if (symcounter) {
324
 
                if ((c = dec1->decode(symbolpair, &met)) == -1)
325
 
                        return;
326
 
 
327
 
                met1 = decayavg(met1, met, 32.0);
328
 
 
329
 
                if (met1 < met2)
330
 
                        return;
331
 
 
332
 
                metric = met1 / 2.5;
 
422
// only modes with odd number of symbits need a vote
 
423
        if (symbits == 5 || symbits == 3) { // could use symbits % 2 == 0
 
424
                if (symcounter) {
 
425
                        if ((c = dec1->decode(symbolpair, &met)) == -1)
 
426
                                return;
 
427
                        met1 = decayavg(met1, met, 32);
 
428
                        if (met1 < met2)
 
429
                                return;
 
430
                        metric = met1 / 2.0;
 
431
                } else {
 
432
                        if ((c = dec2->decode(symbolpair, &met)) == -1)
 
433
                                return;
 
434
                        met2 = decayavg(met2, met, 32);
 
435
                        if (met2 < met1)
 
436
                                return;
 
437
                        metric = met2 / 2.0;
 
438
                }
333
439
        } else {
 
440
                if (symcounter) return;
334
441
                if ((c = dec2->decode(symbolpair, &met)) == -1)
335
442
                        return;
336
 
 
337
 
                met2 = decayavg(met2, met, 32.0);
338
 
 
339
 
                if (met2 < met1)
340
 
                        return;
341
 
 
342
 
                metric = met2 / 2.5;
 
443
                met2 = decayavg(met2, met, 32);
 
444
                metric = met2 / 2.0;
343
445
        }
 
446
        
344
447
        display_metric(metric);
345
448
        
346
449
        if (progStatus.sqlonoff && metric < progStatus.sldrSquelchValue)
352
455
 
353
456
void mfsk::softdecode(complex *bins)
354
457
{
355
 
        double tone, sum, *b;
356
 
        unsigned char *symbols;
 
458
        double binmag, sum, b[symbits];
 
459
        unsigned char symbols[symbits];
357
460
        int i, j, k;
358
461
 
359
 
        b               = new double [symbits];
360
 
        symbols = new unsigned char[symbits];
361
 
 
362
462
        for (i = 0; i < symbits; i++)
363
463
                b[i] = 0.0;
364
464
 
373
473
                else
374
474
                        k = i;
375
475
 
376
 
                tone = bins[k].mag();
 
476
                binmag = bins[k].mag();
377
477
 
378
478
                for (k = 0; k < symbits; k++)
379
 
                        b[k] += (j & (1 << (symbits - k - 1))) ? tone : -tone;
 
479
                        b[k] += (j & (1 << (symbits - k - 1))) ? binmag : -binmag;
380
480
 
381
 
                sum += tone;
 
481
                sum += binmag;
382
482
        }
383
483
 
384
 
// shift to range 0...260 
 
484
// shift to range 0...255
385
485
        for (i = 0; i < symbits; i++)
386
 
                symbols[i] = (unsigned char)clamp(128.0 + (b[i] / sum * 128.0), 0, 260);
 
486
                if (staticburst)
 
487
                        symbols[i] = 0;  // puncturing
 
488
                else
 
489
                        symbols[i] = (unsigned char)clamp(128.0 + (b[i] / sum * 128.0), 0, 255);
387
490
 
388
491
        rxinlv->symbols(symbols);
389
492
 
391
494
                symbolbit = i + 1;
392
495
                decodesymbol(symbols[i]);
393
496
        }
394
 
        delete [] b;
395
 
        delete [] symbols;
396
497
}
397
498
 
398
499
complex mfsk::mixer(complex in, double f)
399
500
{
400
501
        complex z;
401
502
 
402
 
// Basetone is always 1000 Hz 
403
 
        f -= (1000.0 + bandwidth / 2);
 
503
// Basetone is a nominal 1000 Hz 
 
504
        f -= tonespacing * basetone + bandwidth / 2;    
 
505
        
404
506
        z = in * complex( cos(phaseacc), sin(phaseacc) );
405
507
 
406
 
        phaseacc -= twopi * f / samplerate;
407
 
        if (phaseacc > twopi) phaseacc -= twopi;
408
 
        if (phaseacc < -twopi) phaseacc += twopi;
 
508
        phaseacc -= TWOPI * f / samplerate;
 
509
        if (phaseacc > TWOPI) phaseacc -= TWOPI;
 
510
        if (phaseacc < -TWOPI) phaseacc += TWOPI;
409
511
        
410
512
        return z;
411
513
}
416
518
 
417
519
int mfsk::harddecode(complex *in)
418
520
{
419
 
        double x, max = 0.0;
 
521
        double x, max = 0.0, avg = 0.0;
420
522
        int i, symbol = 0;
 
523
        int burstcount = 0;
421
524
 
 
525
        for (int i = 0; i < numtones; i++)
 
526
                avg += in[i].mag();
 
527
        avg /= numtones;
 
528
                        
 
529
        if (avg < 1e-20) avg = 1e-20;
 
530
        
422
531
        for (i = 0; i < numtones; i++) {
423
532
                x = in[i].mag();
424
533
                if ( x > max) {
425
534
                        max = x;
426
535
                        symbol = i;
427
536
                }
 
537
                if (x > 2.0 * avg) burstcount++;
428
538
        }
 
539
 
 
540
        staticburst = (burstcount == numtones);
 
541
 
 
542
        if (!staticburst)
 
543
                afcmetric = 0.95*afcmetric + 0.05 * (2 * max / avg);
 
544
        else
 
545
                afcmetric = 0.0;
 
546
 
429
547
        return symbol;
430
548
}
431
549
 
432
550
void mfsk::update_syncscope()
433
551
{
434
552
        int j;
 
553
        int pipelen = 2 * symlen;
435
554
        memset(scopedata, 0, 2 * symlen * sizeof(double));
436
555
        if (!progStatus.sqlonoff || metric >= progStatus.sldrSquelchValue)
437
 
                for (int i = 0; i < 2 * symlen; i++) {
438
 
                        j = (i + pipeptr) % (2 * symlen);
439
 
                        scopedata[i] = (pipe[j].vector[prev1symbol]).mag();
 
556
                for (unsigned int i = 0; i < SCOPESIZE; i++) {
 
557
                        j = (pipeptr + i * pipelen / SCOPESIZE + 1) % (pipelen);
 
558
                        scopedata[i] = vidfilter[i]->run(pipe[j].vector[prev1symbol].mag());
440
559
                }
441
 
        set_scope(scopedata, 2 * symlen);
 
560
        set_scope(scopedata, SCOPESIZE);
 
561
 
442
562
        scopedata.next(); // change buffers
443
 
        snprintf(mfskmsg, sizeof(mfskmsg), "s/n %3.0f dB", 20.0 * log10(s2n) );
 
563
        snprintf(mfskmsg, sizeof(mfskmsg), "s/n %3.0f dB", 20.0 * log10(s2n));
444
564
        put_Status1(mfskmsg);
445
565
}
446
566
 
447
567
void mfsk::synchronize()
448
568
{
449
 
        int i, j, syn = -1;
 
569
        int i, j;
 
570
        double syn = -1;
450
571
        double val, max = 0.0;
451
572
 
452
573
        if (currsymbol == prev1symbol)
467
588
                j = (j + 1) % (2 * symlen);
468
589
        }
469
590
 
470
 
        synccounter += (int) floor((syn - symlen) / numtones + 0.5); //16.0 + 0.5);
 
591
        syn = syncfilter->run(syn);
 
592
 
 
593
        synccounter += (int) floor((syn - symlen) / numtones + 0.5);
 
594
        
 
595
        update_syncscope();
471
596
}
472
597
 
473
598
void mfsk::reset_afc() {
474
599
        freqerr = 0.0;
475
 
        for (int i = 0; i < AFC_COUNT; i++) afcfilt->run(0.0);
 
600
        syncfilter->reset();
476
601
        return;
477
602
}
478
603
 
480
605
{
481
606
        complex z;
482
607
        complex prevvector;
483
 
        double f;
 
608
        double f, f1;
 
609
        double ts = tonespacing / 4;
484
610
 
485
611
        if (sigsearch) {
486
612
                reset_afc();
487
613
                sigsearch = 0;
488
614
        }
489
615
        
 
616
        if (staticburst || !progStatus.afconoff)
 
617
                return;
 
618
        if (metric < progStatus.sldrSquelchValue)
 
619
                return;
 
620
        if (afcmetric < 3.0)
 
621
                return;
 
622
        if (currsymbol != prev1symbol)
 
623
                return;
 
624
//      if (prev1symbol != prev2symbol)
 
625
//              return;
 
626
        
490
627
        if (pipeptr == 0)
491
628
                prevvector = pipe[2*symlen - 1].vector[currsymbol];
492
629
        else
493
630
                prevvector = pipe[pipeptr - 1].vector[currsymbol];
494
 
        
495
631
        z = prevvector % currvector;
496
632
 
497
 
        f = z.arg() * samplerate / twopi;
498
 
        f -= (1000 + tonespacing * currsymbol);
 
633
        f = z.arg() * samplerate / TWOPI;
 
634
        
 
635
        f1 = tonespacing * (basetone + currsymbol);     
499
636
 
500
 
        if (progStatus.afconoff && (metric > progStatus.sldrSquelchValue || progStatus.sqlonoff == false)) {
501
 
                if (fabs(f) <= tonespacing / 2.0)
502
 
                        freqerr = afcfilt->run(f / numtones);
503
 
                set_freq(frequency + freqerr);
 
637
        if ( fabs(f1 - f) < ts) {
 
638
                freqerr = decayavg(freqerr, (f1 - f), 32);
 
639
                set_freq(frequency - freqerr);
 
640
                set_AFCind( freqerr );
504
641
        }
 
642
 
505
643
}
506
644
 
507
 
void mfsk::eval_s2n(complex c, complex n)
 
645
void mfsk::eval_s2n()
508
646
{
509
 
        sig = c.mag(); // signal + noise energy
510
 
        noise = n.mag() + 1e-10; // noise energy
511
 
 
512
 
        s2n = decayavg( s2n, fabs((sig - noise) / noise), 8);
 
647
        sig = pipe[pipeptr].vector[currsymbol].mag();
 
648
        noise = 0.0;
 
649
        for (int i = 0; i < numtones; i++) {
 
650
                if (i != currsymbol)
 
651
                        noise += pipe[pipeptr].vector[i].mag();
 
652
        }       
 
653
        if (noise > 0)
 
654
                s2n = decayavg ( s2n, sig / noise, 64 );
513
655
}
514
656
 
515
657
int mfsk::rx_process(const double *buf, int len)
521
663
// create analytic signal...
522
664
                z.re = z.im = *buf++;
523
665
                hbfilt->run ( z, z );
524
 
// shift in frequency to the base freq of 1000 hz
 
666
// shift in frequency to the base freq
525
667
                z = mixer(z, frequency);
526
668
// bandpass filter around the shifted center frequency
527
669
// with required bandwidth 
528
670
                bpfilt->run ( z, z );
529
671
                
530
 
                if (rxstate == RX_STATE_PICTURE_START_2) {
531
 
                        if (counter++ == 352) {
532
 
                                counter = 0;
533
 
                                rxstate = RX_STATE_PICTURE;
534
 
                        }
535
 
                        continue;
536
 
                }
537
 
                if (rxstate == RX_STATE_PICTURE_START_1) {
538
 
                        if (counter++ == 352 + symlen) {
539
 
                                counter = 0;
540
 
                                rxstate = RX_STATE_PICTURE;
541
 
                        }
542
 
                        continue;
543
 
                }
544
 
 
 
672
                if (rxstate == RX_STATE_PICTURE_START) {
 
673
                        if (--counter == 0) {
 
674
                                counter = picturesize;
 
675
                                rxstate = RX_STATE_PICTURE;
 
676
                                REQ( showRxViewer, picW, picH );
 
677
                        }
 
678
                        continue;
 
679
                }
545
680
                if (rxstate == RX_STATE_PICTURE) {
546
 
                        if (counter++ == picturesize) {
547
 
                                counter = 0;
 
681
                        if (--counter == 0) {
 
682
                                if (btnpicRxAbort) {
 
683
                                        FL_LOCK_E();
 
684
                                        btnpicRxAbort->hide();
 
685
                                        btnpicRxSave->show();
 
686
                                        FL_UNLOCK_E();
 
687
                                }
548
688
                                rxstate = RX_STATE_DATA;
549
 
                                // REQ_FLUSH();
550
689
                                put_status("");
 
690
#if USE_LIBPNG
 
691
                                string autosave_dir = HomeDir + "mfsk_pics/";
 
692
                                picRx->save_png(autosave_dir.c_str());
 
693
#else
 
694
#  if USE_LIBJPEG
551
695
                                string autosave_dir = HomeDir + "mfsk_pics/";
552
696
                                picRx->save_jpeg(autosave_dir.c_str());
 
697
#  endif
 
698
#endif
553
699
                        } else
554
700
                                recvpic(z);
555
701
                        continue;
561
707
// copy current vector to the pipe
562
708
                for (i = 0; i < numtones; i++)
563
709
                        pipe[pipeptr].vector[i] = bins[i];
564
 
 
 
710
                        
565
711
                if (--synccounter <= 0) {
 
712
                        
566
713
                        synccounter = symlen;
567
714
 
568
715
                        currsymbol = harddecode(bins);
569
716
                        currvector = bins[currsymbol];                  
 
717
                        softdecode(bins);
 
718
 
570
719
// frequency tracking 
571
 
                        afc();
572
 
                        eval_s2n(currvector, bins[numtones + 2]);
 
720
//                      afc();
 
721
//                      eval_s2n();
573
722
// decode symbol 
574
 
                        softdecode(bins);
 
723
//                      softdecode(bins);
 
724
 
575
725
// symbol sync 
576
726
                        synchronize();
577
 
// update the scope
578
 
                        update_syncscope();
 
727
 
 
728
// frequency tracking 
 
729
                        afc();
 
730
                        eval_s2n();
579
731
 
580
732
                        prev2symbol = prev1symbol;
581
733
                        prev2vector = prev1vector;
582
734
                        prev1symbol = currsymbol;
583
735
                        prev1vector = currvector;
 
736
//                      prevmaxval = maxval;
584
737
                }
585
738
                pipeptr = (pipeptr + 1) % (2 * symlen);
586
739
        }
601
754
        f = get_txfreq_woffset() - bandwidth / 2;
602
755
        
603
756
        sym = grayencode(sym & (numtones - 1));
604
 
//printf("%5d", sym);
605
757
        if (reverse)
606
758
                sym = (numtones - 1) - sym;
607
759
 
608
 
        phaseincr = twopi * (f + sym*tonespacing) / samplerate;
 
760
        phaseincr = TWOPI * (f + sym*tonespacing) / samplerate;
609
761
        
610
762
        for (int i = 0; i < symlen; i++) {
611
763
                outbuf[i] = cos(phaseacc);
612
764
                phaseacc -= phaseincr;
613
765
                if (phaseacc > M_PI)
614
 
                        phaseacc -= twopi;
 
766
                        phaseacc -= TWOPI;
615
767
                else if (phaseacc < M_PI)
616
 
                        phaseacc += twopi;
 
768
                        phaseacc += TWOPI;
617
769
        }
618
770
        ModulateXmtr(outbuf, symlen);
619
771
 
676
828
 
677
829
        for (i = 0; i < len; i++) {
678
830
                if (txstate == TX_STATE_PICTURE)
679
 
                        REQ(&mfsk::updateTxPic, this, data[i]);
 
831
                    REQ(updateTxPic, data[i]);
680
832
                if (reverse)
681
833
                        f = get_txfreq_woffset() - bandwidth * (data[i] - 128) / 256.0;
682
834
                else
683
835
                        f = get_txfreq_woffset() + bandwidth * (data[i] - 128) / 256.0;
684
836
                        
685
 
                for (j = 0; j < SAMPLES_PER_PIXEL; j++) {
 
837
                for (j = 0; j < TXspp; j++) {
686
838
                        *ptr++ = cos(phaseacc);
687
839
 
688
 
                        phaseacc += twopi * f / samplerate;
 
840
                        phaseacc += TWOPI * f / samplerate;
689
841
 
690
842
                        if (phaseacc > M_PI)
691
843
                                phaseacc -= 2.0 * M_PI;
692
844
                }
693
845
        }
694
846
 
695
 
        ModulateXmtr(outbuf, SAMPLES_PER_PIXEL * len);
 
847
        ModulateXmtr(outbuf, TXspp * len);
696
848
}
697
849
 
698
850
 
766
918
                        return -1;
767
919
 
768
920
                case TX_STATE_PICTURE_START:
769
 
                        memset(picprologue, 0, 44);
770
 
                        sendpic(picprologue, 44);
 
921
// 176 samples
 
922
                        memset(picprologue, 0, 44 * 8 / TXspp);
 
923
                        sendpic(picprologue, 44 * 8 / TXspp);
771
924
                        txstate = TX_STATE_PICTURE;
772
925
                        break;
773
926
        
781
934
                                        sendpic( &xmtpicbuff[i], blocklen);
782
935
                                else
783
936
                                        sendpic( &xmtpicbuff[i], xmtbytes - i);
 
937
                                if ( (100 * i / xmtbytes) % 2 == 0) {
 
938
                                        int n = snprintf(mfskmsg, sizeof(mfskmsg),
 
939
                                                         "Send picture: %04.1f%% done",
 
940
                                                         (100.0f * i) / xmtbytes);
 
941
                                        print_time_left((xmtbytes - i) * 0.000125 * TXspp, mfskmsg + n,
 
942
                                                        sizeof(mfskmsg) - n, ", ", " left");
 
943
                                        put_status(mfskmsg);
 
944
                                }
784
945
                                i += blocklen;
785
 
                                int n = snprintf(mfskmsg, sizeof(mfskmsg),
786
 
                                                 "Send picture: %04.1f%% done",
787
 
                                                 (100.0f * i) / xmtbytes);
788
 
                                print_time_left(xmtbytes - i, mfskmsg + n,
789
 
                                                sizeof(mfskmsg) - n, ", ", " left");
790
 
                                put_status(mfskmsg);
791
946
                        }
792
947
                        REQ_FLUSH();
793
948
 
795
950
                        put_status("Send picture: done");
796
951
                        FL_LOCK_E();
797
952
                        btnpicTxSendAbort->hide();
 
953
                        btnpicTxSPP->show();
798
954
                        btnpicTxSendColor->show();
799
955
                        btnpicTxSendGrey->show();
800
956
                        btnpicTxLoad->show();
801
957
                        btnpicTxClose->show();
802
958
                        abortxmt = false;
803
959
                        rxstate = RX_STATE_DATA;
804
 
                        counter = 0;
805
960
                        memset(picheader, ' ', PICHEADER - 1);
806
961
                        picheader[PICHEADER -1] = 0;
807
962
                        FL_UNLOCK_E();
811
966
        return 0;
812
967
}
813
968
 
814
 
 
815
 
 
816
 
void mfsk::updateRxPic(unsigned char data, int pos)
817
 
{
818
 
        picRx->pixel(data, pos);
819
 
}
820
 
 
821
 
void cb_picRxClose( Fl_Widget *w, void *who)
822
 
{
823
 
        mfsk *me = (mfsk *)who;
824
 
//      FL_LOCK();
825
 
        me->picRxWin->hide();
826
 
        me->rxstate = mfsk::RX_STATE_DATA;
827
 
        put_status("");
828
 
//      FL_UNLOCK();
829
 
}
830
 
 
831
 
void cb_picRxSave( Fl_Widget *w, void *who)
832
 
{
833
 
        mfsk *me = (mfsk *)who;
834
 
        char *fn = 
835
 
                File_Select("Save Image file?","*.{gif,jpg,png}", "", 0);
836
 
        if (!fn) return;
837
 
        me->picRx->save_jpeg(fn);
838
 
}
839
 
 
840
 
void mfsk::makeRxViewer(int W, int H)
841
 
{
842
 
        int winW, winH;
843
 
        int picX, picY;
844
 
        winW = W < 136 ? 140 : W + 4;
845
 
        winH = H + 34;
846
 
        picX = (winW - W) / 2;
847
 
        picY = 2;
848
 
        FL_LOCK_E();
849
 
        if (!picRxWin) {
850
 
                picRxWin = new Fl_Window(winW, winH);
851
 
                picRxWin->xclass(PACKAGE_NAME);
852
 
                picRx = new picture(picX, picY, W, H);
853
 
                btnpicRxSave = new Fl_Button(winW/2 - 65, H + 6, 60, 24,"Save");
854
 
                btnpicRxSave->callback(cb_picRxSave,this);
855
 
                btnpicRxClose = new Fl_Button(winW/2 + 5, H + 6, 60, 24, "Close");
856
 
                btnpicRxClose->callback(cb_picRxClose,this);
857
 
        } else {
858
 
                picRxWin->size(winW, winH);
859
 
                picRx->resize(picX, picY, W, H);
860
 
                btnpicRxSave->resize(winW/2 - 65, H + 6, 60, 24);
861
 
                btnpicRxClose->resize(winW/2 + 5, H + 6, 60, 24);
862
 
                picRx->clear();
863
 
        }
864
 
        picRxWin->show();
865
 
        FL_UNLOCK_E();
866
 
}
867
 
 
868
 
void mfsk::load_file(const char *n) {
869
 
        int W, H, D;
870
 
        unsigned char *img_data;
871
 
        
872
 
        if (TxImg) {
873
 
                TxImg->release();
874
 
                TxImg = 0L;
875
 
        }
876
 
        TxImg = Fl_Shared_Image::get(n);
877
 
        if (!TxImg)
878
 
                return;
879
 
        img_data = (unsigned char *)TxImg->data()[0];
880
 
        W = TxImg->w();
881
 
        H = TxImg->h();
882
 
        D = TxImg->d();
883
 
        if (xmtimg) delete [] xmtimg;
884
 
        xmtimg = new unsigned char [W * H * 3];
885
 
        if (D == 3)
886
 
                memcpy(xmtimg, img_data, W*H*3);
887
 
        else if (D == 4) {
888
 
                int i, j, k;
889
 
                for (i = 0; i < W*H; i++) {
890
 
                        j = i*3; k = i*4;
891
 
                        xmtimg[j] = img_data[k];
892
 
                        xmtimg[j+1] = img_data[k+1];
893
 
                        xmtimg[j+2] = img_data[k+2];
894
 
                }
895
 
        } else if (D == 1) {
896
 
                int i, j;
897
 
                for (i = 0; i < W*H; i++) {
898
 
                        j = i * 3;
899
 
                        xmtimg[j] = xmtimg[j+1] = xmtimg[j+2] = img_data[i];
900
 
                }
901
 
        } else
902
 
                return;
903
 
 
904
 
        TxViewerResize(W, H);
905
 
        
906
 
// load the picture widget with the rgb image
907
 
        FL_LOCK_D();
908
 
        picTx->video(xmtimg, W * H * 3);
909
 
        if (print_time_left(W * H * 3, txclr_tooltip, sizeof(txclr_tooltip), "Time needed: ") > 0)
910
 
                btnpicTxSendColor->tooltip(txclr_tooltip);
911
 
        btnpicTxSendColor->activate();
912
 
        if (print_time_left(W * H, txgry_tooltip, sizeof(txgry_tooltip), "Time needed: ") > 0)
913
 
                btnpicTxSendGrey->tooltip(txgry_tooltip);
914
 
        btnpicTxSendGrey->activate();
915
 
        FL_UNLOCK_D();
916
 
}
917
 
 
918
 
void mfsk::updateTxPic(unsigned char data)
919
 
{
920
 
        if (color) {
921
 
                pixelnbr = rgb + row + 3*col;
922
 
                picTx->pixel(data, pixelnbr);
923
 
                if (++col == TxImg->w()) {
924
 
                        col = 0;
925
 
                        if (++rgb == 3) {
926
 
                                rgb = 0;
927
 
                                row += 3 * TxImg->w();
928
 
                        }
929
 
                }
930
 
        } else {
931
 
                picTx->pixel( data, pixelnbr++ );
932
 
                picTx->pixel( data, pixelnbr++ );
933
 
                picTx->pixel( data, pixelnbr++ );
934
 
        }
935
 
}
936
 
 
937
 
void cb_picTxLoad(Fl_Widget *,void *who) {
938
 
        mfsk *TxWho = (mfsk *)who;
939
 
        char *fn = 
940
 
                File_Select("Image file?","*.{gif,jpg,png}", "", 0);
941
 
        if (!fn) return;
942
 
        TxWho->load_file(fn);
943
 
}
944
 
 
945
 
void cb_picTxClose( Fl_Widget *w, void *who)
946
 
{
947
 
        mfsk *me = (mfsk *)who;
948
 
        FL_LOCK_D();
949
 
        me->picTxWin->hide();
950
 
        FL_UNLOCK_D();
951
 
}
952
 
 
953
 
void cb_picTxSendColor( Fl_Widget *w, void *who)
954
 
{
955
 
        mfsk *my = (mfsk *)who;
956
 
        int W, H, rowstart;
957
 
        W = my->TxImg->w();
958
 
        H = my->TxImg->h();
959
 
        if (my->xmtpicbuff) delete [] my->xmtpicbuff;
960
 
        my->xmtpicbuff = new unsigned char [W*H*3];
961
 
        unsigned char *outbuf = my->xmtpicbuff;
962
 
        unsigned char *inbuf = my->xmtimg;
963
 
        int iy, ix, rgb;
964
 
        for (iy = 0; iy < H; iy++) {
965
 
                rowstart = iy * W * 3;
966
 
                for (rgb = 0; rgb < 3; rgb++)
967
 
                        for (ix = 0; ix < W; ix++)
968
 
                                outbuf[rowstart + rgb*W + ix] = inbuf[rowstart + rgb + ix*3];
969
 
        }
970
 
        snprintf(my->picheader, PICHEADER - 1, "\nSending Pic:%dx%dC;", W, H);
971
 
        my->xmtbytes = W * H * 3;
972
 
        my->color = true;
973
 
        my->rgb = 0;
974
 
        my->col = 0;
975
 
        my->row = 0;
976
 
        my->pixelnbr = 0;
977
 
        FL_LOCK_D();
978
 
        my->btnpicTxSendColor->hide();
979
 
        my->btnpicTxSendGrey->hide();
980
 
        my->btnpicTxLoad->hide();
981
 
        my->btnpicTxClose->hide();
982
 
        my->btnpicTxSendAbort->show();
983
 
        my->picTx->clear();
984
 
        FL_UNLOCK_D();
985
 
// start the transmission
986
 
        fl_lock(&trx_mutex);
987
 
        if (trx_state != STATE_TX)
988
 
                trx_state = STATE_TX;
989
 
        fl_unlock(&trx_mutex);
990
 
        wf->set_XmtRcvBtn(true);
991
 
        my->startpic = true;
992
 
}
993
 
 
994
 
void cb_picTxSendGrey( Fl_Widget *w, void *who)
995
 
{
996
 
        mfsk *my = (mfsk *)who;
997
 
        int W, H;
998
 
        W = my->TxImg->w();
999
 
        H = my->TxImg->h();
1000
 
        if (my->xmtpicbuff) delete [] my->xmtpicbuff;
1001
 
        my->xmtpicbuff = new unsigned char [W*H];
1002
 
        unsigned char *outbuf = my->xmtpicbuff;
1003
 
        unsigned char *inbuf = my->xmtimg;
1004
 
        for (int i = 0; i < W*H; i++)
1005
 
                outbuf[i] = ( 31 * inbuf[i*3] + 61 * inbuf[i*3 + 1] + 8 * inbuf[i*3 + 2])/100;
1006
 
        snprintf(my->picheader, PICHEADER - 1, "\nSending Pic:%dx%d;", W, H);
1007
 
        my->xmtbytes = W * H;
1008
 
        my->color = false;
1009
 
        my->col = 0;
1010
 
        my->row = 0;
1011
 
        my->pixelnbr = 0;
1012
 
        my->picTx->clear();
1013
 
        FL_LOCK_D();
1014
 
        my->btnpicTxSendColor->hide();
1015
 
        my->btnpicTxSendGrey->hide();
1016
 
        my->btnpicTxLoad->hide();
1017
 
        my->btnpicTxClose->hide();
1018
 
        my->btnpicTxSendAbort->show();
1019
 
        FL_UNLOCK_D();
1020
 
// start the transmission
1021
 
        fl_lock(&trx_mutex);
1022
 
        if (trx_state != STATE_TX)
1023
 
                trx_state = STATE_TX;
1024
 
        fl_unlock(&trx_mutex);
1025
 
        wf->set_XmtRcvBtn(true);
1026
 
        my->startpic = true;
1027
 
}
1028
 
 
1029
 
 
1030
 
void cb_picTxSendAbort( Fl_Widget *w, void *who)
1031
 
{
1032
 
        mfsk *my = (mfsk *)who;
1033
 
        my->abortxmt = true;
1034
 
// reload the picture widget with the rgb image
1035
 
        FL_LOCK_D();
1036
 
        my->picTx->video(my->xmtimg, my->TxImg->w() * my->TxImg->h() * 3);
1037
 
        FL_UNLOCK_D();
1038
 
}
1039
 
 
1040
 
void mfsk::TxViewerResize(int W, int H)
1041
 
{
1042
 
        int winW, winH;
1043
 
        int picX, picY;
1044
 
        winW = W < 246 ? 250 : W + 4;
1045
 
        winH = H < 180 ? 180 : H + 30;
1046
 
        picX = (winW - W) / 2;
1047
 
        picY =  (winH - 30 - H)/2;
1048
 
        FL_LOCK_D();
1049
 
        picTxWin->size(winW, winH);
1050
 
        picTx->resize(picX, picY, W, H);
1051
 
        picTx->clear();
1052
 
        btnpicTxSendColor->resize(winW/2 - 123, winH - 28, 60, 24);
1053
 
        btnpicTxSendGrey->resize(winW/2 - 61, winH - 28, 60, 24);
1054
 
        btnpicTxSendAbort->resize(winW/2 - 123, winH - 28, 122, 24);
1055
 
        btnpicTxLoad->resize(winW/2 + 1, winH - 28, 60, 24);
1056
 
        btnpicTxClose->resize(winW/2 + 63, winH - 28, 60, 24);
1057
 
        FL_UNLOCK_D();
1058
 
}
1059
 
 
1060
 
void mfsk::makeTxViewer(int W, int H)
1061
 
{
1062
 
        int winW, winH;
1063
 
        int picX, picY;
1064
 
        winW = W < 246 ? 250 : W + 4;
1065
 
        winH = H < 180 ? 180 : H + 30;
1066
 
        picX = (winW - W) / 2;
1067
 
        picY =  2;
1068
 
        FL_LOCK_D();
1069
 
        if (!picTxWin) {
1070
 
                picTxWin = new Fl_Window(winW, winH);
1071
 
                picTxWin->xclass(PACKAGE_NAME);
1072
 
                picTx = new picture (picX, picY, W, H);
1073
 
                btnpicTxSendColor = new Fl_Button(winW/2 - 123, winH - 28, 60, 24, "XmtClr");
1074
 
                btnpicTxSendColor->callback(cb_picTxSendColor, this);
1075
 
                btnpicTxSendGrey = new Fl_Button(winW/2 - 61, winH - 28, 60, 24, "XmtGry");
1076
 
                btnpicTxSendGrey->callback( cb_picTxSendGrey, this);
1077
 
                btnpicTxSendAbort = new Fl_Button(winW/2 - 123, winH - 28, 122, 24, "Abort Xmt");
1078
 
                btnpicTxSendAbort->callback(cb_picTxSendAbort, this);
1079
 
                btnpicTxLoad = new Fl_Button(winW/2 + 1, winH - 28, 60, 24, "Load");
1080
 
                btnpicTxLoad->callback(cb_picTxLoad, this);
1081
 
                btnpicTxClose = new Fl_Button(winW/2 + 63, winH - 28, 60, 24, "Close");
1082
 
                btnpicTxClose->callback(cb_picTxClose,this);
1083
 
                btnpicTxSendAbort->hide();
1084
 
                btnpicTxSendColor->deactivate();
1085
 
                btnpicTxSendGrey->deactivate();
1086
 
        } else {
1087
 
                picTxWin->size(winW, winH);
1088
 
                picTx->resize(picX, picY, W, H);
1089
 
                btnpicTxSendColor->resize(winW/2 - 123, winH - 28, 60, 24);
1090
 
                btnpicTxSendGrey->resize(winW/2 - 61, winH - 28, 60, 24);
1091
 
                btnpicTxSendAbort->resize(winW/2 - 123, winH - 28, 122, 24);
1092
 
                btnpicTxLoad->resize(winW/2 + 1, winH - 28, 60, 24);
1093
 
                btnpicTxClose->resize(winW/2 + 63, winH - 28, 60, 24);
1094
 
                btnpicTxSendColor->show();
1095
 
                btnpicTxSendGrey->show();
1096
 
                btnpicTxLoad->show();
1097
 
                btnpicTxClose->show();
1098
 
                btnpicTxSendAbort->hide();
1099
 
        }
1100
 
        picTxWin->show();
1101
 
        FL_UNLOCK_D();
1102
 
}
1103
 
 
1104
 
int mfsk::print_time_left(size_t bytes, char *str, size_t len,
1105
 
                          const char *prefix, const char *suffix)
1106
 
{
1107
 
        float time_sec = bytes * 0.001;
1108
 
        int time_min = (int)(time_sec / 60);
1109
 
        time_sec -= time_min * 60;
1110
 
 
1111
 
        if (time_min)
1112
 
                return snprintf(str, len, "%s%02dm%2.1fs%s",
1113
 
                                prefix, time_min, time_sec, suffix);
1114
 
        else
1115
 
                return snprintf(str, len, "%s%2.1fs%s", prefix, time_sec, suffix);
1116
 
}