2012-05-21 12 views
10

मैं एक अजीब प्रोजेक्ट कर रहा हूं, और कुछ छोटे, सरल डेटाग्राम को ऑडियो में परिवर्तित करना चाहता हूं - उन्हें एक (भौतिक) रेडियो पर भेजना - फिर उन्हें किसी अन्य डिवाइस पर प्राप्त करने और डीकोड करने के लिए (सोचें - ऑडियो आउट जैक और जीएसएम/जीपीआरएस-प्रकार रेडियो के साथ एम्बेडेड डिवाइस)।एक अच्छी, सरल, मुलायम मॉडेम लाइब्रेरी के लिए स्रोत

(I में भौतिक, मौजूदा बाहरी रेडियो का उपयोग करने के लिए है)।

क्या किसी को भी इस परियोजना के लिए अच्छा, सरल सॉफ़्टवेयर मॉडेम लाइब्रेरी अच्छा लगता है? मैं डेटा दर के बारे में इतना चिंतित नहीं हूं, और कार्यक्षमता पर सादगी पसंद करूंगा। यहां तक ​​कि मूल 1200 बॉड मॉडेम की तरह कुछ शानदार होगा।

किसी भी सीखने के अनुभव और संभावित इमारत ब्लॉक को और अधिक व्यावहारिक रूप से व्यावहारिक रूप से देखते हुए।

+0

भेजने के पक्ष में किसी भी मूल स्वर जनरेटर के साथ शुरू करने जैसा लगता है। प्राप्त करने वाले पक्ष पर, आप शायद एक एफएफटी आधारित आवृत्ति डिटेक्टर चाहते हैं। वहां से, आप विभिन्न कस्टम प्रोटोकॉल के माध्यम से त्रुटि सुधार और बचाव के माध्यमों के बारे में जान सकते हैं। – bbum

+0

@bbum: यदि आप आवृत्ति को जानते हैं तो एफएफटी आवश्यक नहीं है। मुझे लगता है कि अपेक्षाकृत कम फ़िल्टर (एफआईआर) और कुछ तर्क ठीक काम करेंगे। –

+0

@ एलेक्स धन्यवाद! मैं स्वीकार करता हूं कि मेरा सिग्नल फ़िल्टरिंग कौशल पूरी तरह से कमी कर रहा है! मुझे उम्मीद है कि कोई इस सवाल पर एक अच्छा जवाब देगा क्योंकि मुझे सीखने में दिलचस्पी होगी (और यह एक स्वच्छ परियोजना की तरह लगता है!) – bbum

उत्तर

13

एक अभ्यास के रूप में मैंने एफएसके मॉड्यूलेशन का उपयोग करके एक साधारण वी.23-जैसे मॉडेम लागू किया है और 1200 बिट्स/सेकेंड की डेटा दर का समर्थन किया है (शुरुआत और स्टॉप बिट्स के कारण 960 बिट्स/दूसरा प्रभावी)।

मुझे यह देखने में उत्सुकता है कि यह आपके रेडियो के साथ काम करता है या नहीं। शोर, सिग्नल प्रतिबिंब और अपूर्ण डिमोड्यूलेशन सभी मॉडेम के प्रदर्शन को प्रभावित कर सकते हैं।

इस परियोजना को अपने प्रोजेक्ट में एकीकृत करने की कोशिश करने से पहले, पहले देखें कि यह आपके रेडियो से रिकॉर्ड किए गए ऑडियो के साथ काम करता है या नहीं।

कोड:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <limits.h> 
#include <math.h> 

#ifndef M_PI 
#define M_PI 3.14159265358979324 
#endif 

typedef unsigned char uchar, uint8; 
typedef signed char schar, int8; 
typedef unsigned short ushort, uint16; 
typedef short int16; 
typedef unsigned int uint; 
typedef unsigned long ulong; 
#if UINT_MAX >= 0xFFFFFFFF 
typedef int int32; 
typedef unsigned int uint32; 
#else 
typedef long int32; 
typedef unsigned long uint32; 
#endif 
typedef long long int64; 
typedef unsigned long long uint64; 

typedef struct 
{ 
    double x, y; 
} tComplex; 

tComplex complexAdd(const tComplex* a, const tComplex* b) 
{ 
    tComplex c; 
    c.x = a->x + b->x; 
    c.y = a->y + b->y; 
    return c; 
} 

tComplex complexMul(const tComplex* a, const tComplex* b) 
{ 
    tComplex c; 
    c.x = a->x * b->x - a->y * b->y; 
    c.y = a->x * b->y + a->y * b->x; 
    return c; 
} 

void dft(tComplex out[], const tComplex in[], size_t n, int direction) 
{ 
    size_t k, i; 
    for (k = 0; k < n; k++) 
    { 
    tComplex r = { 0, 0 }, e; 
    for (i = 0; i < n; i++) 
    { 
     e.x = cos(-2 * direction * M_PI/n * ((double)k - n/2) * ((double)i - n/2)); 
     e.y = sin(-2 * direction * M_PI/n * ((double)k - n/2) * ((double)i - n/2)); 
     e = complexMul(&e, &in[i]); 
     r = complexAdd(&r, &e); 
    } 
    out[k] = r; 
    } 
} 

#define FILTER_LENGTH 64 

typedef struct tTx 
{ 
    enum 
    { 
    stSendingOnes, 
    stSendingData 
    } State; 

    uint SampleRate; 
    uint OnesFreq; 
    uint ZeroesFreq; 
    uint BitRate; 

    uint32 SampleCnt; 
    uint BitSampleCnt; 
    uint Data; 
    uint DataLeft; 

    double Phase; 
    double PhaseIncrement; 

    uint (*pTxGetDataCallBack)(struct tTx*, uint8*); 
} tTx; 

void TxInit(tTx* pTx, 
      uint SampleRate, 
      uint (*pTxGetDataCallBack)(tTx*, uint8*)) 
{ 
    memset(pTx, 0, sizeof(*pTx)); 
    pTx->State = stSendingOnes; 
    pTx->SampleRate = SampleRate; 
    pTx->OnesFreq = 1300; 
    pTx->ZeroesFreq = 2100; 
    pTx->BitRate = 1200; 
    pTx->pTxGetDataCallBack = pTxGetDataCallBack; 

    pTx->SampleCnt = 0; 
    pTx->BitSampleCnt = pTx->SampleRate; 
    pTx->Data = 0; 
    pTx->DataLeft = 0; 
    pTx->Phase = 0.0; 
    pTx->PhaseIncrement = 2 * M_PI * pTx->OnesFreq/pTx->SampleRate; 
} 

int16 TxGetSample(tTx* pTx) 
{ 
    int16 sample; 

    if (pTx->State == stSendingOnes && 
     pTx->SampleCnt >= pTx->SampleRate) 
    { 
    // Sent 1 second worth of 1's, can now send data 
    pTx->State = stSendingData; 
    } 

    if (pTx->State == stSendingData && 
     pTx->BitSampleCnt >= pTx->SampleRate) 
    { 
    // Another data bit can now be sent 
    uint8 d; 

    pTx->BitSampleCnt -= pTx->SampleRate; 

    if (!pTx->DataLeft) 
    { 
     // Get the next data byte (if any) 
     if (pTx->pTxGetDataCallBack(pTx, &d) != 0) 
     { 
     pTx->Data = d & 0xFF; 
     pTx->Data |= 1 << 8; // insert the stop bit 
     pTx->Data <<= 1; // insert the start bit 
     pTx->DataLeft = 10; 
     } 
     else 
     { 
     pTx->Data = 0x3FF; // no data, send 10 1's 
     pTx->DataLeft = 10; 
     } 
    } 

    // Extract the next data bit to send 
    d = pTx->Data & 1; 
    pTx->Data >>= 1; 
    pTx->DataLeft--; 

    // Choose the appropriate frequency for 0 and 1 
    if (d) 
    { 
     pTx->PhaseIncrement = 2 * M_PI * pTx->OnesFreq/pTx->SampleRate; 
    } 
    else 
    { 
     pTx->PhaseIncrement = 2 * M_PI * pTx->ZeroesFreq/pTx->SampleRate; 
    } 
    } 

    // Generate the next sample, advance the generator's phase 
    sample = (int16)(16000 * cos(pTx->Phase)); 
    pTx->Phase += pTx->PhaseIncrement; 
    if (pTx->Phase >= 2 * M_PI) 
    { 
    pTx->Phase -= 2 * M_PI; 
    } 

    if (pTx->State == stSendingData) 
    { 
    pTx->BitSampleCnt += pTx->BitRate; 
    } 

    pTx->SampleCnt++; 

    return sample; 
} 

typedef struct tRx 
{ 
    enum 
    { 
    stCarrierLost, 
    stCarrierDetected, 
    stReceivingData 
    } State; 

    uint SampleRate; 
    uint OnesFreq; 
    uint ZeroesFreq; 
    uint MidFreq; 
    uint BitRate; 

    uint32 SampleCnt; 
    uint BitSampleCnt; 
    uint Data; 

    double Phase; 
    double PhaseIncrement; 

    tComplex Filter[FILTER_LENGTH]; 
    double Delay[FILTER_LENGTH]; 

    double LastAngle; 
    int LastDelta; 
    int32 Deltas; 

    int32 CarrierAngle; 
    int32 CarrierCnt; 

    double LongAvgPower; 
    double ShortAvgPower; 

    void (*pRxGetDataCallBack)(struct tRx*, uint8); 
} tRx; 

void RxInit(tRx* pRx, 
      uint SampleRate, 
      void (*pRxGetDataCallBack)(struct tRx*, uint8)) 
{ 
    tComplex tmp[FILTER_LENGTH]; 
    uint i; 

    memset(pRx, 0, sizeof(*pRx)); 
    pRx->State = stCarrierLost; 
    pRx->SampleRate = SampleRate; 
    pRx->OnesFreq = 1300; 
    pRx->ZeroesFreq = 2100; 
    pRx->MidFreq = (pRx->OnesFreq + pRx->ZeroesFreq)/2; 
    pRx->BitRate = 1200; 
    pRx->pRxGetDataCallBack = pRxGetDataCallBack; 

    pRx->SampleCnt = 0; 
    pRx->BitSampleCnt = 0; 
    pRx->Data = 0x3FF; 
    pRx->Phase = 0.0; 
    pRx->PhaseIncrement = 2 * M_PI * pRx->MidFreq/pRx->SampleRate; 
    pRx->LastAngle = 0.0; 
    pRx->LastDelta = 0; 
    pRx->Deltas = 0; 
    pRx->CarrierAngle = 0; 
    pRx->CarrierCnt = 0; 
    pRx->LongAvgPower = 0.0; 
    pRx->ShortAvgPower = 0.0; 

    for (i = 0; i < FILTER_LENGTH; i++) 
    { 
    pRx->Delay[i] = 0.0; 
    } 

    for (i = 0; i < FILTER_LENGTH; i++) 
    { 
    if (i == 0) // w < 0 (min w) 
    { 
     pRx->Filter[i].x = 0; 
     pRx->Filter[i].y = 0; 
    } 
    else if (i < FILTER_LENGTH/2) // w < 0 
    { 
     pRx->Filter[i].x = 0; 
     pRx->Filter[i].y = 0; 
    } 
    else if (i == FILTER_LENGTH/2) // w = 0 
    { 
     pRx->Filter[i].x = 0; 
     pRx->Filter[i].y = 0; 
    } 
    else if (i > FILTER_LENGTH/2) // w > 0 
    { 
     pRx->Filter[i].x = 0; 
     pRx->Filter[i].y = -1; 

     // Extra filter to combat channel noise 
     if (i - FILTER_LENGTH/2 < 875UL * FILTER_LENGTH/pRx->SampleRate || 
      i - FILTER_LENGTH/2 > (2350UL * FILTER_LENGTH + pRx->SampleRate - 1)/pRx->SampleRate) 
     { 
     pRx->Filter[i].y = 0; 
     } 
    } 
    } 

    memcpy(tmp, pRx->Filter, sizeof(tmp)); 
    dft(pRx->Filter, tmp, FILTER_LENGTH, -1); 
} 

#define RX_VERBOSE 0 
void RxGetSample(tRx* pRx, int16 Sample) 
{ 
    tComplex s = { 0.0, 0.0 }, ss; 
    double angle; 
    uint i; 
    int delta; 
    double pwr; 

    // Insert the sample into the delay line 
    memmove(&pRx->Delay[0], &pRx->Delay[1], sizeof(pRx->Delay) - sizeof(pRx->Delay[0])); 
    pRx->Delay[FILTER_LENGTH - 1] = Sample; 

    // Get the next analytic signal sample by applying Hilbert transform/filter 
    for (i = 0; i < FILTER_LENGTH; i++) 
    { 
    s.x += pRx->Delay[i] * pRx->Filter[FILTER_LENGTH - 1 - i].x; 
    s.y += pRx->Delay[i] * pRx->Filter[FILTER_LENGTH - 1 - i].y; 
    } 

    // Frequency shift by MidFreq down 
    ss.x = cos(-pRx->Phase); 
    ss.y = sin(-pRx->Phase); 
    s = complexMul(&s, &ss); 
    pRx->Phase += pRx->PhaseIncrement; 
    if (pRx->Phase >= 2 * M_PI) 
    { 
    pRx->Phase -= 2 * M_PI; 
    } 

    // Calculate signal power 
    pwr = (s.x * s.x + s.y * s.y)/32768/32768; 
    pRx->LongAvgPower *= 1 - pRx->BitRate/(pRx->SampleRate * 8.0 * 8); 
    pRx->LongAvgPower += pwr; 
    pRx->ShortAvgPower *= 1 - pRx->BitRate/(pRx->SampleRate * 8.0); 
    pRx->ShortAvgPower += pwr; 

#if 0 
    printf("LongAvgPower:%f ShortAvgPower:%f\n", pRx->LongAvgPower, pRx->ShortAvgPower); 
#endif 

    // Disconnect if the signal power changes abruptly. 
    if (pRx->State != stCarrierLost && 
     pRx->LongAvgPower > pRx->ShortAvgPower * 8 * 8) 
    { 
    // N.B. The receiver may have received a few extra (garbage) bytes 
    // while demodulating the abruptly changed signal. 
    // Prefixing data with its size or using a more advanced protocol 
    // may be a good solution to this little problem. 
    pRx->State = stCarrierLost; 
    pRx->BitSampleCnt = 0; 
    pRx->Data = 0x3FF; 
    pRx->Phase = 0.0; 
    pRx->LastAngle = 0.0; 
    pRx->LastDelta = 0; 
    pRx->Deltas = 0; 
    pRx->CarrierAngle = 0; 
    pRx->CarrierCnt = 0; 
    } 

    // Get the phase angle from the analytic signal sample 
    angle = (fpclassify(s.x) == FP_ZERO && fpclassify(s.y) == FP_ZERO) ? 
    0.0 : 180/M_PI * atan2(s.y, s.x); 
    // Calculate the phase angle change and force it to the -PI to +PI range 
    delta = (int)(360.5 + angle - pRx->LastAngle) % 360; 
    if (delta > 180) delta -= 360; 

    if (pRx->State == stCarrierLost) 
    { 
    // Accumulate the phase angle change to see if we're receiving 1's 
    pRx->CarrierAngle += delta; 
    pRx->CarrierCnt++; 

    // Check whether or not the phase corresponds to 1's 
    if (delta < 0) 
    { 
     if (pRx->CarrierCnt >= pRx->SampleRate/pRx->OnesFreq * 8) 
     { 
     double ph = (double)pRx->CarrierAngle/pRx->CarrierCnt; 
#if RX_VERBOSE 
     printf("ca:%5ld, cc:%4ld, ca/cc:%4ld\n", 
       (long)pRx->CarrierAngle, 
       (long)pRx->CarrierCnt, 
       (long)(pRx->CarrierAngle/pRx->CarrierCnt)); 
#endif 
     // Frequency tolerance is +/-16 Hz per the V.23 spec 
     if (ph < (pRx->OnesFreq - 17.0 - pRx->MidFreq) * 360.0/pRx->SampleRate || 
      ph > (pRx->OnesFreq + 17.0 - pRx->MidFreq) * 360.0/pRx->SampleRate) 
     { 
      goto BadCarrier; 
     } 
     } 
    } 
    else 
    { 
BadCarrier: 
     // Phase doesn't correspond to 1's 
     pRx->CarrierAngle = 0.0; 
     pRx->CarrierCnt = 0; 
    } 

    if (pRx->CarrierCnt >= pRx->SampleRate/2 + pRx->SampleRate/4) 
    { 
     // 0.75 seconds worth of 1's have been detected, ready to receive data 

     // Adjust MidFreq to compensate for the DAC and ADC sample rate difference 
     double f1 = (double)pRx->CarrierAngle/pRx->CarrierCnt/360 * pRx->SampleRate + pRx->MidFreq; 
     pRx->MidFreq = (uint)(pRx->MidFreq * f1/pRx->OnesFreq); 
     pRx->PhaseIncrement = 2 * M_PI * pRx->MidFreq/pRx->SampleRate; 
#if RX_VERBOSE 
     printf("f1:%u, new MidFreq:%u\n", (uint)f1, pRx->MidFreq); 
#endif 
     pRx->State = stCarrierDetected; 
    } 
    } 
    else 
    { 
    // Detect frequency changes (transitions between 0's and 1's) 
    int freqChange = ((int32)pRx->LastDelta * delta < 0 || pRx->LastDelta && !delta); 
    int reAddDelta = 0; 

#if RX_VERBOSE 
    printf("%6lu: delta:%4d freqChange:%d BitSampleCnt:%u\n", 
      (ulong)pRx->SampleCnt, 
      delta, 
      freqChange, 
      pRx->BitSampleCnt); 
#endif 

    // Synchronize with 1<->0 transitions 
    if (freqChange) 
    { 
     if (pRx->BitSampleCnt >= pRx->SampleRate/2) 
     { 
     pRx->BitSampleCnt = pRx->SampleRate; 
     pRx->Deltas -= delta; 
     reAddDelta = 1; 
     } 
     else 
     { 
     pRx->BitSampleCnt = 0; 
     pRx->Deltas = 0; 
     } 
    } 

    // Accumulate analytic signal phase angle changes 
    // (positive for 0, negative for 1) 
    pRx->Deltas += delta; 

    if (pRx->BitSampleCnt >= pRx->SampleRate) 
    { 
     // Another data bit has accumulated 
     pRx->BitSampleCnt -= pRx->SampleRate; 

#if RX_VERBOSE 
     printf("bit: %u\n", pRx->Deltas < 0); 
#endif 

     pRx->Data >>= 1; 
     pRx->Data |= (pRx->Deltas < 0) << 9; 
     pRx->Deltas = delta * reAddDelta; 

     if ((pRx->Data & 0x201) == 0x200) 
     { 
     // Start and stop bits have been detected 
     if (pRx->State == stCarrierDetected) 
     { 
      pRx->State = stReceivingData; 
     } 
     pRx->Data = (pRx->Data >> 1) & 0xFF; 
     pRx->pRxGetDataCallBack(pRx, (uint8)pRx->Data); 

#if RX_VERBOSE 
     printf("byte: 0x%02X ('%c')\n", 
       pRx->Data, 
       (pRx->Data >= 0x20 && pRx->Data <= 0x7F) ? pRx->Data : '?'); 
#endif 

     pRx->Data = 0x3FF; 
     } 
    } 

    pRx->BitSampleCnt += pRx->BitRate; 
    } 

    pRx->LastAngle = angle; 
    pRx->LastDelta = delta; 
    pRx->SampleCnt++; 
} 

typedef struct 
{ 
    tTx Tx; 
    FILE* DataFile; 
    int CountDown; 
} tTxTest; 

uint TxGetDataCallBack(tTx* pTx, uint8* pTxData) 
{ 
    tTxTest* pTxTest = (tTxTest*)pTx; 
    uchar c; 

    if (pTxTest->CountDown) 
    { 
    pTxTest->CountDown--; 
    return 0; 
    } 

    if (fread(&c, 1, 1, pTxTest->DataFile) != 1) 
    { 
    pTxTest->CountDown = 20; 
    return 0; 
    } 

    *pTxData = c; 
    return 1; 
} 

int testTx(uint SampleRate, 
      double NoiseLevel, 
      const char* DataFileName, 
      const char* AudioFileName) 
{ 
    FILE *fData = NULL, *fAudio = NULL; 
    int err = EXIT_FAILURE; 
    tTxTest txTest; 

    if ((fData = fopen(DataFileName, "rb")) == NULL) 
    { 
    printf("Can't open file \"%s\"\n", DataFileName); 
    goto Exit; 
    } 

    if ((fAudio = fopen(AudioFileName, "wb")) == NULL) 
    { 
    printf("Can't create file \"%s\"\n", AudioFileName); 
    goto Exit; 
    } 

    txTest.DataFile = fData; 
    txTest.CountDown = 0; 

    TxInit(&txTest.Tx, 
     SampleRate, 
     &TxGetDataCallBack); 

    do 
    { 
    int16 sample = TxGetSample(&txTest.Tx); 
    if (txTest.CountDown > 1 && txTest.CountDown <= 10) 
    { 
#if 0 // Enable this code to test disconnecting. 
     // Finish with silence. 
     sample = 0; 
#endif 
    } 
    sample += (rand() - (int)RAND_MAX/2) * NoiseLevel * 16000/(RAND_MAX/2); 
    fwrite(&sample, 1, sizeof(sample), fAudio); 
    } while (txTest.CountDown != 1); // Drain all data-containing samples 

    err = EXIT_SUCCESS; 

Exit: 

    if (fData != NULL) fclose(fData); 
    if (fAudio != NULL) fclose(fAudio); 

    return err; 
} 

typedef struct 
{ 
    tRx Rx; 
    FILE* DataFile; 
} tRxTest; 

void RxGetDataCallBack(tRx* pRx, uint8 RxData) 
{ 
    tRxTest* pRxTest = (tRxTest*)pRx; 
    uchar c = RxData; 
    fwrite(&c, 1, 1, pRxTest->DataFile); 
} 

int testRx(uint SampleRate, 
      const char* AudioFileName, 
      const char* DataFileName) 
{ 
    uint lastState; 
    FILE *fAudio = NULL, *fData = NULL; 
    int err = EXIT_FAILURE; 
    tRxTest rxTest; 

    if ((fAudio = fopen(AudioFileName, "rb")) == NULL) 
    { 
    printf("Can't open file \"%s\"\n", AudioFileName); 
    goto Exit; 
    } 

    if ((fData = fopen(DataFileName, "wb")) == NULL) 
    { 
    printf("Can't create file \"%s\"\n", DataFileName); 
    goto Exit; 
    } 

    rxTest.DataFile = fData; 

    RxInit(&rxTest.Rx, 
     SampleRate, 
     &RxGetDataCallBack); 

    for (;;) 
    { 
    int16 sample; 

    if (fread(&sample, 1, sizeof(sample), fAudio) != sizeof(sample)) 
    { 
     if (rxTest.Rx.State != stCarrierLost) goto NoCarrier; 
     break; 
    } 

    lastState = rxTest.Rx.State; 
    RxGetSample(&rxTest.Rx, sample); 

    if (rxTest.Rx.State != lastState && rxTest.Rx.State == stCarrierDetected) 
    { 
     printf("\nCONNECT %u\n\n", rxTest.Rx.BitRate); 
    } 

    if (rxTest.Rx.State != lastState && rxTest.Rx.State == stCarrierLost) 
    { 
NoCarrier: 
     printf("\n\nNO CARRIER\n"); 
     break; 
    } 
    } 

    err = EXIT_SUCCESS; 

Exit: 

    if (fAudio != NULL) fclose(fAudio); 
    if (fData != NULL) fclose(fData); 

    return err; 
} 

int main(int argc, char* argv[]) 
{ 
    uint sampleRate; 
    double noiseLevel; 

    if (argc < 2 || 
     !stricmp(argv[1], "-help") || 
     !stricmp(argv[1], "/help") || 
     !stricmp(argv[1], "-?") || 
     !stricmp(argv[1], "/?")) 
    { 
Usage: 
    printf("Usage:\n\n" 
      " %s tx <sample rate> <noise level> <data input file> <PCM output file>\n" 
      " %s rx <sample rate> <PCM input file> <data output file>\n", 
      argv[0], 
      argv[0]); 
    return 0; 
    } 

    if (!stricmp(argv[1], "tx") && 
     argc == 6 && 
     sscanf(argv[2], "%u", &sampleRate) == 1 && 
     sscanf(argv[3], "%lf", &noiseLevel) == 1) 
    { 
    return testTx(sampleRate, noiseLevel, argv[4], argv[5]); 
    } 
    else if (!stricmp(argv[1], "rx") && 
      argc == 5 && 
      sscanf(argv[2], "%u", &sampleRate) == 1) 
    { 
    return testRx(sampleRate, argv[3], argv[4]); 
    } 
    else 
    { 
    goto Usage; 
    } 
} 

विशिष्ट उपयोग:

modem.exe tx 8000 0.2 testin.txt test8000.pcm 
modem.exe rx 8000 test8000.pcm testout.txt 

जिसके परिणामस्वरूप testout.txt testin.txt लिए समान होना चाहिए।

+0

वाह! यह कोशिश करने के लिए तत्पर हैं !! :-) – Brad

+0

यह कैसा चल रहा है? –

+0

वेब पेज से कोड निर्यात करने का प्रयास करने में परेशानी हो रही है। क्या मैं कहीं फाइल के रूप में डाउनलोड कर सकता हूं? – Brad

2

एक वेब सर्च बहुत सारे शौकिया रेडियो बीपीएसके और आरटीटीई/एफएसके समाधानों को बदल देगी। इस कोड का अधिकांश पुराना धीमी सीपीयू के लिए लिखा गया था, इसलिए आईफोन पर बस ठीक चलना चाहिए। आप कोडेक में आईओएस ऑडियो आईओ के लिए ऑडियो क्यूई एपीआई या रिमोटियो ऑडियो यूनिट का उपयोग कर सकते हैं।

1

यदि आप अभी भी मुलायम मॉडेम की तलाश में हैं, तो आप libquiet या Quiet.js पर विचार कर सकते हैं। ये एक कम बिजली जीएमएसके मोड प्रदान करते हैं जो कि यदि आप ऑडियो केबल का उपयोग कर रहे हैं तो काफी सक्षम और साथ ही उच्च बिटरेट मोड भी हैं। शांत अपने मॉड्यूलेशन को करने के लिए मौजूदा एसडीआर लाइब्रेरी का उपयोग करता है ताकि आपको कुछ पूर्ण-विशेष रुप से प्रदर्शित किया जा सके।

संबंधित मुद्दे