You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
IoT-For-Beginners/translations/hu/6-consumer/lessons/1-speech-recognition/wio-terminal-audio.md

26 KiB

Hangrögzítés - Wio Terminal

Ebben a leckében kódot fogsz írni, hogy hangot rögzíts a Wio Terminal eszközön. A hangrögzítést a Wio Terminal tetején található egyik gomb fogja vezérelni.

Programozd az eszközt hangrögzítésre

A mikrofonról hangot C++ kóddal lehet rögzíteni. A Wio Terminal csak 192KB RAM-mal rendelkezik, ami nem elég több mint néhány másodpercnyi hang rögzítésére. Viszont van 4MB flash memóriája, amelyet használhatsz a rögzített hang tárolására.

A beépített mikrofon analóg jelet rögzít, amelyet digitális jellé alakít át, amit a Wio Terminal használni tud. Hangrögzítéskor az adatokat megfelelő időben kell rögzíteni - például 16KHz-es hang rögzítéséhez pontosan 16,000-szer másodpercenként kell mintát venni, egyenlő időközönként. Ahelyett, hogy a kódod végezné ezt, használhatod a közvetlen memória-hozzáférés vezérlőt (DMAC). Ez egy olyan áramkör, amely jelet tud rögzíteni és memóriába írni anélkül, hogy megszakítaná a processzoron futó kódot.

Olvass többet a DMA-ról a közvetlen memória-hozzáférés Wikipedia oldalán.

A mikrofonból érkező hang az ADC-n keresztül a DMAC-hoz jut. Ez egy pufferbe ír. Amikor ez a puffer megtelik, feldolgozásra kerül, és a DMAC egy második pufferbe ír

A DMAC képes hangot rögzíteni az ADC-től fix időközönként, például 16,000-szer másodpercenként 16KHz-es hang esetén. A rögzített adatokat egy előre lefoglalt memória pufferbe írja, és amikor ez megtelik, elérhetővé teszi a kódod számára feldolgozásra. A memória használata késleltetheti a hangrögzítést, de több puffert is beállíthatsz. A DMAC az 1-es pufferbe ír, majd amikor ez megtelik, értesíti a kódodat, hogy dolgozza fel az 1-es puffert, miközben a DMAC a 2-es pufferbe ír. Amikor a 2-es puffer megtelik, értesíti a kódodat, és visszatér az 1-es pufferbe íráshoz. Így, amíg minden puffert gyorsabban dolgozol fel, mint amennyi idő alatt megtelik, nem veszítesz adatot.

Miután minden puffer rögzítésre került, az flash memóriába írható. A flash memóriát meghatározott címekkel kell írni, megadva, hogy hova és mekkora méretben írjon, hasonlóan egy bájt tömb frissítéséhez a memóriában. A flash memóriának van granularitása, ami azt jelenti, hogy a törlési és írási műveletek nemcsak fix méretűek, hanem igazodniuk kell ehhez a mérethez. Például, ha a granularitás 4096 bájt, és törlést kérsz a 4200-as címen, akkor törölheti az összes adatot a 4096-tól 8192-ig terjedő címek között. Ez azt jelenti, hogy amikor a hangadatokat flash memóriába írod, megfelelő méretű darabokban kell írni.

Feladat - flash memória konfigurálása

  1. Hozz létre egy új Wio Terminal projektet a PlatformIO használatával. Nevezd el ezt a projektet smart-timer-nek. Adj hozzá kódot a setup függvényben a soros port konfigurálásához.

  2. Add hozzá a következő könyvtárfüggőségeket a platformio.ini fájlhoz, hogy hozzáférj a flash memóriához:

    lib_deps =
        seeed-studio/Seeed Arduino FS @ 2.1.1
        seeed-studio/Seeed Arduino SFUD @ 2.0.2
    
  3. Nyisd meg a main.cpp fájlt, és add hozzá a következő include direktívát a flash memória könyvtárhoz a fájl tetején:

    #include <sfud.h>
    #include <SPI.h>
    

    🎓 Az SFUD a Serial Flash Universal Driver rövidítése, amely egy könyvtár, amely minden flash memória chiphez használható.

  4. A setup függvényben add hozzá a következő kódot a flash tároló könyvtár beállításához:

    while (!(sfud_init() == SFUD_SUCCESS))
        ;
    
    sfud_qspi_fast_read_enable(sfud_get_device(SFUD_W25Q32_DEVICE_INDEX), 2);
    

    Ez addig ismétlődik, amíg az SFUD könyvtár inicializálódik, majd bekapcsolja a gyors olvasást. A beépített flash memória Queued Serial Peripheral Interface (QSPI) segítségével érhető el, amely egy olyan SPI vezérlő, amely minimális processzorhasználattal folyamatos hozzáférést biztosít egy soron keresztül. Ez gyorsabbá teszi a flash memóriába való olvasást és írást.

  5. Hozz létre egy új fájlt a src mappában flash_writer.h néven.

  6. Add hozzá a következőket a fájl tetejéhez:

    #pragma once
    
    #include <Arduino.h>
    #include <sfud.h>
    

    Ez néhány szükséges fejlécfájlt tartalmaz, beleértve az SFUD könyvtár fejlécfájlját a flash memóriával való interakcióhoz.

  7. Definiálj egy osztályt ebben az új fejlécfájlban FlashWriter néven:

    class FlashWriter
    {
    public:
    
    private:
    };
    
  8. A private szekcióban add hozzá a következő kódot:

    byte *_sfudBuffer;
    size_t _sfudBufferSize;
    size_t _sfudBufferPos;
    size_t _sfudBufferWritePos;
    
    const sfud_flash *_flash;
    

    Ez néhány mezőt definiál a pufferhez, amelyet az adatok flash memóriába írása előtt használnak. Van egy bájt tömb, _sfudBuffer, amelybe adatokat írnak, és amikor ez megtelik, az adatokat flash memóriába írják. Az _sfudBufferPos mező tárolja az aktuális helyet, ahová írni kell ebben a pufferben, az _sfudBufferWritePos pedig azt a helyet tárolja, ahová flash memóriába kell írni. _flash egy mutató a flash memóriára, amelybe írni kell - néhány mikrokontroller több flash memória chipet is tartalmaz.

  9. Add hozzá a következő metódust a public szekcióhoz az osztály inicializálásához:

    void init()
    {
        _flash = sfud_get_device_table() + 0;
        _sfudBufferSize = _flash->chip.erase_gran;
        _sfudBuffer = new byte[_sfudBufferSize];
        _sfudBufferPos = 0;
        _sfudBufferWritePos = 0;
    }
    

    Ez konfigurálja a Wio Terminal flash memóriáját írásra, és beállítja a puffereket a flash memória granularitása alapján. Ez egy init metódusban van, nem pedig egy konstruktorban, mivel ezt a flash memória beállítása után kell meghívni a setup függvényben.

  10. Add hozzá a következő kódot a public szekcióhoz:

    void writeSfudBuffer(byte b)
    {
        _sfudBuffer[_sfudBufferPos++] = b;
        if (_sfudBufferPos == _sfudBufferSize)
        {
            sfud_erase_write(_flash, _sfudBufferWritePos, _sfudBufferSize, _sfudBuffer);
            _sfudBufferWritePos += _sfudBufferSize;
            _sfudBufferPos = 0;
        }
    }
    
    void writeSfudBuffer(byte *b, size_t len)
    {
        for (size_t i = 0; i < len; ++i)
        {
            writeSfudBuffer(b[i]);
        }
    }
    
    void flushSfudBuffer()
    {
        if (_sfudBufferPos > 0)
        {
            sfud_erase_write(_flash, _sfudBufferWritePos, _sfudBufferSize, _sfudBuffer);
            _sfudBufferWritePos += _sfudBufferSize;
            _sfudBufferPos = 0;
        }
    }
    

    Ez a kód metódusokat definiál a bájtok flash tárolórendszerbe való írására. Ez úgy működik, hogy egy memóriapufferbe ír, amely megfelelő méretű a flash memóriához, és amikor ez megtelik, ezt írja a flash memóriába, törölve az adott helyen lévő meglévő adatokat. Van egy flushSfudBuffer is, amely egy nem teljes puffert ír, mivel a rögzített adatok nem lesznek pontosan a granularitás többszörösei, így az adatok végső része is írásra kerül.

    💁 Az adatok végső része további nem kívánt adatokat fog írni, de ez nem probléma, mivel csak a szükséges adatokat fogják olvasni.

Feladat - hangrögzítés beállítása

  1. Hozz létre egy új fájlt a src mappában config.h néven.

  2. Add hozzá a következőket a fájl tetejéhez:

    #pragma once
    
    #define RATE 16000
    #define SAMPLE_LENGTH_SECONDS 4
    #define SAMPLES RATE * SAMPLE_LENGTH_SECONDS
    #define BUFFER_SIZE (SAMPLES * 2) + 44
    #define ADC_BUF_LEN 1600
    

    Ez a kód néhány konstansot állít be a hangrögzítéshez.

    Konstans Érték Leírás
    RATE 16000 A hang mintavételi sebessége. 16,000 az 16KHz
    SAMPLE_LENGTH_SECONDS 4 A rögzítendő hang hossza. Ez 4 másodpercre van állítva. Ha hosszabb hangot szeretnél rögzíteni, növeld ezt az értéket.
    SAMPLES 64000 Az összes rögzítendő hangminta száma. A mintavételi sebesség * másodpercek száma
    BUFFER_SIZE 128044 A hangpuffer mérete a rögzítéshez. A hang WAV fájlként lesz rögzítve, amely 44 bájt fejlécet, majd 128,000 bájt hangadatot tartalmaz (minden minta 2 bájt)
    ADC_BUF_LEN 1600 A pufferek mérete, amelyeket a DMAC használ a hang rögzítéséhez

    💁 Ha úgy találod, hogy 4 másodperc túl rövid egy időzítő kéréséhez, növelheted a SAMPLE_LENGTH_SECONDS értéket, és az összes többi érték újraszámolódik.

  3. Hozz létre egy új fájlt a src mappában mic.h néven.

  4. Add hozzá a következőket a fájl tetejéhez:

    #pragma once
    
    #include <Arduino.h>
    
    #include "config.h"
    #include "flash_writer.h"
    

    Ez néhány szükséges fejlécfájlt tartalmaz, beleértve a config.h és FlashWriter fejlécfájlokat.

  5. Add hozzá a következőket, hogy definiálj egy Mic osztályt, amely képes a mikrofonról rögzíteni:

    class Mic
    {
    public:
        Mic()
        {
            _isRecording = false;
            _isRecordingReady = false;
        }
    
        void startRecording()
        {
            _isRecording = true;
            _isRecordingReady = false;
        }
    
        bool isRecording()
        {
            return _isRecording;
        }
    
        bool isRecordingReady()
        {
            return _isRecordingReady;
        }
    
    private:
        volatile bool _isRecording;
        volatile bool _isRecordingReady;
        FlashWriter _writer;
    };
    
    Mic mic;
    

    Ez az osztály jelenleg csak néhány mezőt tartalmaz, amelyek nyomon követik, hogy elkezdődött-e a rögzítés, és hogy a rögzítés készen áll-e a használatra. Amikor a DMAC be van állítva, folyamatosan ír memóriapufferekbe, így az _isRecording jelző határozza meg, hogy ezeket feldolgozni kell-e vagy sem. Az _isRecordingReady jelző akkor lesz beállítva, amikor a szükséges 4 másodpercnyi hang rögzítésre került. A _writer mező a hangadatok flash memóriába való mentésére szolgál.

    Ezután egy globális változó kerül deklarálásra a Mic osztály egy példányához.

  6. Add hozzá a következő kódot a Mic osztály private szekciójához:

    typedef struct
    {
        uint16_t btctrl;
        uint16_t btcnt;
        uint32_t srcaddr;
        uint32_t dstaddr;
        uint32_t descaddr;
    } dmacdescriptor;
    
    // Globals - DMA and ADC
    volatile dmacdescriptor _wrb[DMAC_CH_NUM] __attribute__((aligned(16)));
    dmacdescriptor _descriptor_section[DMAC_CH_NUM] __attribute__((aligned(16)));
    dmacdescriptor _descriptor __attribute__((aligned(16)));
    
    void configureDmaAdc()
    {
        // Configure DMA to sample from ADC at a regular interval (triggered by timer/counter)
        DMAC->BASEADDR.reg = (uint32_t)_descriptor_section;                    // Specify the location of the descriptors
        DMAC->WRBADDR.reg = (uint32_t)_wrb;                                    // Specify the location of the write back descriptors
        DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);           // Enable the DMAC peripheral
        DMAC->Channel[1].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(TC5_DMAC_ID_OVF) | // Set DMAC to trigger on TC5 timer overflow
                                        DMAC_CHCTRLA_TRIGACT_BURST;             // DMAC burst transfer
    
        _descriptor.descaddr = (uint32_t)&_descriptor_section[1];                    // Set up a circular descriptor
        _descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg;                           // Take the result from the ADC0 RESULT register
        _descriptor.dstaddr = (uint32_t)_adc_buf_0 + sizeof(uint16_t) * ADC_BUF_LEN; // Place it in the adc_buf_0 array
        _descriptor.btcnt = ADC_BUF_LEN;                                             // Beat count
        _descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD |                            // Beat size is HWORD (16-bits)
                                DMAC_BTCTRL_DSTINC |                                    // Increment the destination address
                                DMAC_BTCTRL_VALID |                                     // Descriptor is valid
                                DMAC_BTCTRL_BLOCKACT_SUSPEND;                           // Suspend DMAC channel 0 after block transfer
        memcpy(&_descriptor_section[0], &_descriptor, sizeof(_descriptor));          // Copy the descriptor to the descriptor section
    
        _descriptor.descaddr = (uint32_t)&_descriptor_section[0];                    // Set up a circular descriptor
        _descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg;                           // Take the result from the ADC0 RESULT register
        _descriptor.dstaddr = (uint32_t)_adc_buf_1 + sizeof(uint16_t) * ADC_BUF_LEN; // Place it in the adc_buf_1 array
        _descriptor.btcnt = ADC_BUF_LEN;                                             // Beat count
        _descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD |                            // Beat size is HWORD (16-bits)
                                DMAC_BTCTRL_DSTINC |                                    // Increment the destination address
                                DMAC_BTCTRL_VALID |                                     // Descriptor is valid
                                DMAC_BTCTRL_BLOCKACT_SUSPEND;                           // Suspend DMAC channel 0 after block transfer
        memcpy(&_descriptor_section[1], &_descriptor, sizeof(_descriptor));          // Copy the descriptor to the descriptor section
    
        // Configure NVIC
        NVIC_SetPriority(DMAC_1_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for DMAC1 to 0 (highest)
        NVIC_EnableIRQ(DMAC_1_IRQn);      // Connect DMAC1 to Nested Vector Interrupt Controller (NVIC)
    
        // Activate the suspend (SUSP) interrupt on DMAC channel 1
        DMAC->Channel[1].CHINTENSET.reg = DMAC_CHINTENSET_SUSP;
    
        // Configure ADC
        ADC1->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_AIN12_Val; // Set the analog input to ADC0/AIN2 (PB08 - A4 on Metro M4)
        while (ADC1->SYNCBUSY.bit.INPUTCTRL)
            ;                              // Wait for synchronization
        ADC1->SAMPCTRL.bit.SAMPLEN = 0x00; // Set max Sampling Time Length to half divided ADC clock pulse (2.66us)
        while (ADC1->SYNCBUSY.bit.SAMPCTRL)
            ;                                         // Wait for synchronization
        ADC1->CTRLA.reg = ADC_CTRLA_PRESCALER_DIV128; // Divide Clock ADC GCLK by 128 (48MHz/128 = 375kHz)
        ADC1->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT |    // Set ADC resolution to 12 bits
                            ADC_CTRLB_FREERUN;          // Set ADC to free run mode
        while (ADC1->SYNCBUSY.bit.CTRLB)
            ;                       // Wait for synchronization
        ADC1->CTRLA.bit.ENABLE = 1; // Enable the ADC
        while (ADC1->SYNCBUSY.bit.ENABLE)
            ;                       // Wait for synchronization
        ADC1->SWTRIG.bit.START = 1; // Initiate a software trigger to start an ADC conversion
        while (ADC1->SYNCBUSY.bit.SWTRIG)
            ; // Wait for synchronization
    
        // Enable DMA channel 1
        DMAC->Channel[1].CHCTRLA.bit.ENABLE = 1;
    
        // Configure Timer/Counter 5
        GCLK->PCHCTRL[TC5_GCLK_ID].reg = GCLK_PCHCTRL_CHEN |     // Enable peripheral channel for TC5
                                            GCLK_PCHCTRL_GEN_GCLK1; // Connect generic clock 0 at 48MHz
    
        TC5->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ; // Set TC5 to Match Frequency (MFRQ) mode
        TC5->COUNT16.CC[0].reg = 3000 - 1;            // Set the trigger to 16 kHz: (4Mhz / 16000) - 1
        while (TC5->COUNT16.SYNCBUSY.bit.CC0)
            ; // Wait for synchronization
    
        // Start Timer/Counter 5
        TC5->COUNT16.CTRLA.bit.ENABLE = 1; // Enable the TC5 timer
        while (TC5->COUNT16.SYNCBUSY.bit.ENABLE)
            ; // Wait for synchronization
    }
    
    uint16_t _adc_buf_0[ADC_BUF_LEN];
    uint16_t _adc_buf_1[ADC_BUF_LEN];
    

    Ez a kód definiál egy configureDmaAdc metódust, amely konfigurálja a DMAC-t, csatlakoztatva az ADC-hez, és beállítva, hogy két különböző váltakozó puffert töltsön ki, _adc_buf_0 és _adc_buf_1.

    💁 Az egyik hátránya a mikrokontroller fejlesztésnek a hardverrel való interakcióhoz szükséges kód összetettsége, mivel a kódod nagyon alacsony szinten fut, közvetlenül a hardverrel interakcióban. Ez a kód bonyolultabb, mint amit egy egykártyás számítógéphez vagy asztali számítógéphez írnál, mivel nincs operációs rendszer, amely segítene. Vannak elérhető könyvtárak, amelyek egyszerűsíthetik ezt, de még mindig sok a bonyolultság.

  7. Ez alatt add hozzá a következő kódot:

    // WAV files have a header. This struct defines that header
    struct wavFileHeader
    {
        char riff[4];         /* "RIFF"                                  */
        long flength;         /* file length in bytes                    */
        char wave[4];         /* "WAVE"                                  */
        char fmt[4];          /* "fmt "                                  */
        long chunk_size;      /* size of FMT chunk in bytes (usually 16) */
        short format_tag;     /* 1=PCM, 257=Mu-Law, 258=A-Law, 259=ADPCM */
        short num_chans;      /* 1=mono, 2=stereo                        */
        long srate;           /* Sampling rate in samples per second     */
        long bytes_per_sec;   /* bytes per second = srate*bytes_per_samp */
        short bytes_per_samp; /* 2=16-bit mono, 4=16-bit stereo          */
        short bits_per_samp;  /* Number of bits per sample               */
        char data[4];         /* "data"                                  */
        long dlength;         /* data length in bytes (filelength - 44)  */
    };
    
    void initBufferHeader()
    {
        wavFileHeader wavh;
    
        strncpy(wavh.riff, "RIFF", 4);
        strncpy(wavh.wave, "WAVE", 4);
        strncpy(wavh.fmt, "fmt ", 4);
        strncpy(wavh.data, "data", 4);
    
        wavh.chunk_size = 16;
        wavh.format_tag = 1; // PCM
        wavh.num_chans = 1;  // mono
        wavh.srate = RATE;
        wavh.bytes_per_sec = (RATE * 1 * 16 * 1) / 8;
        wavh.bytes_per_samp = 2;
        wavh.bits_per_samp = 16;
        wavh.dlength = RATE * 2 * 1 * 16 / 2;
        wavh.flength = wavh.dlength + 44;
    
        _writer.writeSfudBuffer((byte *)&wavh, 44);
    }
    

    Ez a kód definiálja a WAV fejlécet egy 44 bájtos memóriát foglaló struktúraként. Részleteket ír bele a hangfájl sebességéről, méretéről és csatornáinak számáról. Ez a fejléc ezután flash memóriába kerül.

  8. Ez alatt a kód alatt add hozzá a következőket, hogy deklarálj egy metódust, amelyet akkor hívnak meg, amikor a hangpufferek készen állnak a feldolgozásra:

    void audioCallback(uint16_t *buf, uint32_t buf_len)
    {
        static uint32_t idx = 44;
    
        if (_isRecording)
        {
            for (uint32_t i = 0; i < buf_len; i++)
            {
                int16_t audio_value = ((int16_t)buf[i] - 2048) * 16;
    
                _writer.writeSfudBuffer(audio_value & 0xFF);
                _writer.writeSfudBuffer((audio_value >> 8) & 0xFF);
            }
    
            idx += buf_len;
    
            if (idx >= BUFFER_SIZE)
            {
                _writer.flushSfudBuffer();
                idx = 44;
                _isRecording = false;
                _isRecordingReady = true;
            }
        }
    }
    

    A hangpufferek 16 bites egész számok tömbjei, amelyek az ADC-től származó hangot tartalmazzák. Az ADC 12 bites előjel nélküli értékeket (0-1023) ad vissza, így ezeket 16 bites előjeles értékekké kell konvertálni, majd 2 bájttá alakítani, hogy nyers bináris adatként tárolhatók legyenek.

    Ezeket a bájtokat a flash memória puffereibe írják. Az írás a 44-es indexnél kezdődik - ez az eltolás a WAV fájl fejlécének 44 bájtjától. Miután az összes szükséges bájt rögzítésre került a kívánt hanghosszhoz, a fennmaradó adatokat flash memóriába írják.

  9. A Mic osztály public szekciójában add hozzá a következő kódot:

    void dmaHandler()
    {
        static uint8_t count = 0;
    
        if (DMAC->Channel[1].CHINTFLAG.bit.SUSP)
        {
            DMAC->Channel[1].CHCTRLB.reg = DMAC_CHCTRLB_CMD_RESUME;
            DMAC->Channel[1].CHINTFLAG.bit.SUSP = 1;
    
            if (count)
            {
                audioCallback(_adc_buf_0, ADC_BUF_LEN);
            }
            else
            {
                audioCallback(_adc_buf_1, ADC_BUF_LEN);
            }
    
            count = (count + 1) % 2;
        }
    }
    

    Ez a kódot a DMAC hívja meg, hogy értesítse a kódodat a pufferek feldolgozásáról. Ellenőrzi, hogy van-e adat feldolgozásra, és meghívja az audioCallback metódust a megfelelő pufferrel.

  10. Az osztályon kívül, a Mic mic; deklaráció után add hozzá a következő kódot:

    void DMAC_1_Handler()
    {
        mic.dmaHandler();
    }
    

    A DMAC_1_Handler-t a DMAC hívja meg, amikor a pufferek készen állnak a feldolgozásra. Ez a függvény név alapján található meg, így csak léteznie kell, hogy meghívható legyen.

  11. Add hozzá a következő két metódust a Mic osztály public szekciójához:

    void init()
    {
        analogReference(AR_INTERNAL2V23);
    
        _writer.init();
    
        initBufferHeader();
        configureDmaAdc();
    }
    
    void reset()
    {
        _isRecordingReady = false;
        _isRecording = false;
    
        _writer.reset();
    
        initBufferHeader();
    }
    

    Az init metódus tartalmazza a Mic osztály inicializálásához szükséges kódot. Ez a metódus beállítja a Mic pin megfelelő feszültségét, beállítja a flash memória írót, megírja a WAV fájl fejlécét, és konfigurálja a DMAC-t. A reset metódus visszaállítja a flash memóriát, és újraírja a fejlécet, miután a hang rögzítésre került és felhasználásra került.

Feladat - hang rögzítése

  1. A main.cpp fájlban adj hozzá egy include direktívát a mic.h fejlécfájlhoz:

    #include "mic.h"
    
  2. A setup függvényben inicializáld a C gombot. A hangrögzítés akkor kezdődik, amikor ezt a gombot megnyomják, és 4 másodpercig folytatódik:

    pinMode(WIO_KEY_C, INPUT_PULLUP);
    
  3. Ez alatt inicializáld a mikrofont, majd írd ki a konzolra, hogy a hang rögzítésre kész:

    mic.init();
    
    Serial.println("Ready.");
    
  4. A loop függvény fölött definiálj egy függvényt a rögzített hang feldolgozására. Egyelőre ez nem csinál semmit, de később a leckében a beszéd szöveggé alakítására fogja küldeni:

    void processAudio()
    {
    
    }
    
  5. Add hozzá a következőket a loop függvényhez:

    void loop()
    {
        if (digitalRead(WIO_KEY_C) == LOW && !mic.isRecording())
        {
            Serial.println("Starting recording...");
            mic.startRecording();
        }
    
        if (!mic.isRecording() && mic.isRecordingReady())
        {
            Serial.println("Finished recording");
    
            processAudio();
    
            mic.reset();
        }
    }
    

    Ez a kód ellenőrzi a C gombot, és ha ezt megnyomják, és a rögzítés még nem kezdődött el, akkor a Mic osztály _isRecording mezője true értékre van állítva. Ez azt eredményezi, hogy a Mic osztály audioCallback metódusa hangot tárol, amíg 4 másodpercnyi hang rögzítésre nem kerül. Miután 4 másodpercnyi hang rögzítésre került, az _isRecording mező false értékre van állítva, és az _isRecordingReady mező true értékre van állítva. Ezután ezt ellenőrzi a loop függvény, és amikor igaz, meghívja a processAudio függvényt, majd visszaállítja a mic osztályt.

  6. Építsd meg ezt a kódot, töltsd fel a Wio Terminal eszközre, és teszteld a soros monitoron keresztül. Nyomd meg a C gombot (a bal oldalon található, legközelebb a bekapcsoló kapcsolóhoz), és beszélj. 4 másodpercnyi hang rögzítésre kerül.

    --- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
    --- More details at http://bit.ly/pio-monitor-filters
    --- Miniterm on /dev/cu.usbmodem1101  9600,8,N,1 ---
    --- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
    Ready.
    Starting recording...
    Finished recording
    

💁 Ezt a kódot megtalálhatod a code-record/wio-terminal mappában. 😀 Az audiofelvételi programod sikeres volt!


Felelősség kizárása:
Ez a dokumentum az AI fordítási szolgáltatás, a Co-op Translator segítségével lett lefordítva. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Kritikus információk esetén javasolt professzionális emberi fordítást igénybe venni. Nem vállalunk felelősséget semmilyen félreértésért vagy téves értelmezésért, amely a fordítás használatából eredhet.