[
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 60\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 7\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - pinned\n  - security\n  - help wanted\n# Label to use when marking an issue as stale\nstaleLabel: stale\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed if no further activity occurs. Thank you\n  for your contributions.\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n# Never stale pull requests\nonly: issues"
  },
  {
    "path": ".gitignore",
    "content": "CMakeLists.txt.user\nCMakeCache.txt\nCMakeFiles\nCMakeScripts\nTesting\nMakefile\ncmake_install.cmake\ninstall_manifest.txt\ncompile_commands.json\nCTestTestfile.cmake\n_deps\n\nbuild/\n\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.12)\n\n# initialize pico_sdk from GIT\n# (note this can come from environment, CMake cache etc)\n# set(PICO_SDK_FETCH_FROM_GIT on)\n\n# pico_sdk_import.cmake is a single file copied from this SDK\n# note: this must happen before project()\ninclude(pico_sdk_import.cmake)\n\nproject(pico_microphone)\n\n# initialize the Pico SDK\npico_sdk_init()\n\nadd_library(pico_pdm_microphone INTERFACE)\n\ntarget_sources(pico_pdm_microphone INTERFACE\n    ${CMAKE_CURRENT_LIST_DIR}/src/pdm_microphone.c\n    ${CMAKE_CURRENT_LIST_DIR}/src/OpenPDM2PCM/OpenPDMFilter.c\n)\n\ntarget_include_directories(pico_pdm_microphone INTERFACE\n    ${CMAKE_CURRENT_LIST_DIR}/src/include\n)\n\npico_generate_pio_header(pico_pdm_microphone ${CMAKE_CURRENT_LIST_DIR}/src/pdm_microphone.pio)\n\ntarget_link_libraries(pico_pdm_microphone INTERFACE pico_stdlib hardware_dma hardware_pio)\n\n\nadd_library(pico_analog_microphone INTERFACE)\n\ntarget_sources(pico_analog_microphone INTERFACE\n    ${CMAKE_CURRENT_LIST_DIR}/src/analog_microphone.c\n)\n\ntarget_include_directories(pico_analog_microphone INTERFACE\n    ${CMAKE_CURRENT_LIST_DIR}/src/include\n)\n\ntarget_link_libraries(pico_analog_microphone INTERFACE pico_stdlib hardware_adc hardware_dma)\n\nadd_subdirectory(\"examples/hello_analog_microphone\")\nadd_subdirectory(\"examples/hello_pdm_microphone\")\nadd_subdirectory(\"examples/usb_microphone\")\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# Microphone Library for Pico\n\nCapture audio from a microphone on your [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/) or any [RP2040](https://www.raspberrypi.org/products/rp2040/) based board. 🎤\n\n\n## Hardware\n\n * RP2040 board\n   * [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)\n * Microphones\n   * Analog\n     * [Electret Microphone Amplifier - MAX9814 with Auto Gain Control](https://www.adafruit.com/product/1713) \n   * PDM\n     * [Adafruit PDM MEMS Microphone Breakout](https://www.adafruit.com/product/3492)\n\n### Default Pinout\n\n#### Analog Microphone\n\n| Raspberry Pi Pico / RP2040 | Analog Microphone |\n| -------------------------- | ----------------- |\n| 3.3V | VCC |\n| GND | GND |\n| GPIO 26 | OUT |\n\n#### PDM Microphone\n\n| Raspberry Pi Pico / RP2040 | PDM Microphone |\n| -------------------------- | ----------------- |\n| 3.3V | VCC |\n| GND | GND |\n| GND | SEL |\n| GPIO 2 | DAT |\n| GPIO 3 | CLK |\n\nGPIO pins are configurable in examples or API.\n\n## Examples\n\nSee [examples](examples/) folder.\n\n\n## Cloning\n\n```sh\ngit clone https://github.com/ArmDeveloperEcosystem/microphone-library-for-pico.git \n```\n\n## Building\n\n1. [Set up the Pico C/C++ SDK](https://datasheets.raspberrypi.org/pico/getting-started-with-pico.pdf)\n2. Set `PICO_SDK_PATH`\n```sh\nexport PICO_SDK_PATH=/path/to/pico-sdk\n```\n3. Create `build` dir, run `cmake` and `make`:\n```\nmkdir build\ncd build\ncmake .. -DPICO_BOARD=pico\nmake\n```\n4. Copy example `.uf2` to Pico when in BOOT mode.\n\n## License\n\n[Apache-2.0 License](LICENSE)\n\n## Acknowledgements\n\nThis project was created on behalf of the [Arm Software Developers](https://developer.arm.com/) team, follow them on Twitter: [@ArmSoftwareDev](https://twitter.com/armsoftwaredev) and YouTube: [Arm Software Developers](https://www.youtube.com/channel/UCHUAckhCfRom2EHDGxwhfOg) for more resources!\n\nThe [OpenPDM2PCM](https://os.mbed.com/teams/ST/code/X_NUCLEO_CCA02M1//file/53f8b511f2a1/Middlewares/OpenPDM2PCM/) library is used to filter raw PDM data into PCM. The [TinyUSB](https://github.com/hathach/tinyusb) library is used in the `usb_microphone` example.\n\n---\n\nDisclaimer: This is not an official Arm product.\n"
  },
  {
    "path": "examples/hello_analog_microphone/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.12)\n\n# rest of your project\nadd_executable(hello_analog_microphone\n    main.c\n)\n\ntarget_link_libraries(hello_analog_microphone pico_analog_microphone)\n\n# enable usb output, disable uart output\npico_enable_stdio_usb(hello_analog_microphone 1)\npico_enable_stdio_uart(hello_analog_microphone 0)\n\n# create map/bin/hex/uf2 file in addition to ELF.\npico_add_extra_outputs(hello_analog_microphone)\n"
  },
  {
    "path": "examples/hello_analog_microphone/main.c",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n * \n * This examples captures data from an analog microphone using a sample\n * rate of 8 kHz and prints the sample values over the USB serial\n * connection.\n */\n\n#include <stdio.h>\n\n#include \"pico/stdlib.h\"\n#include \"pico/analog_microphone.h\"\n#include \"tusb.h\"\n\n// configuration\nconst struct analog_microphone_config config = {\n    // GPIO to use for input, must be ADC compatible (GPIO 26 - 28)\n    .gpio = 26,\n\n    // bias voltage of microphone in volts\n    .bias_voltage = 1.25,\n\n    // sample rate in Hz\n    .sample_rate = 8000,\n\n    // number of samples to buffer\n    .sample_buffer_size = 256,\n};\n\n// variables\nint16_t sample_buffer[256];\nvolatile int samples_read = 0;\n\nvoid on_analog_samples_ready()\n{\n    // callback from library when all the samples in the library\n    // internal sample buffer are ready for reading \n    samples_read = analog_microphone_read(sample_buffer, 256);\n}\n\nint main( void )\n{\n    // initialize stdio and wait for USB CDC connect\n    stdio_init_all();\n    while (!tud_cdc_connected()) {\n        tight_loop_contents();\n    }\n\n    printf(\"hello analog microphone\\n\");\n\n    // initialize the analog microphone\n    if (analog_microphone_init(&config) < 0) {\n        printf(\"analog microphone initialization failed!\\n\");\n        while (1) { tight_loop_contents(); }\n    }\n\n    // set callback that is called when all the samples in the library\n    // internal sample buffer are ready for reading\n    analog_microphone_set_samples_ready_handler(on_analog_samples_ready);\n    \n    // start capturing data from the analog microphone\n    if (analog_microphone_start() < 0) {\n        printf(\"PDM microphone start failed!\\n\");\n        while (1) { tight_loop_contents();  }\n    }\n\n    while (1) {\n        // wait for new samples\n        while (samples_read == 0) { tight_loop_contents(); }\n\n        // store and clear the samples read from the callback\n        int sample_count = samples_read;\n        samples_read = 0;\n        \n        // loop through any new collected samples\n        for (int i = 0; i < sample_count; i++) {\n            printf(\"%d\\n\", sample_buffer[i]);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/hello_pdm_microphone/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.12)\n\n# rest of your project\nadd_executable(hello_pdm_microphone\n    main.c\n)\n\ntarget_link_libraries(hello_pdm_microphone pico_pdm_microphone)\n\n# enable usb output, disable uart output\npico_enable_stdio_usb(hello_pdm_microphone 1)\npico_enable_stdio_uart(hello_pdm_microphone 0)\n\n# create map/bin/hex/uf2 file in addition to ELF.\npico_add_extra_outputs(hello_pdm_microphone)\n"
  },
  {
    "path": "examples/hello_pdm_microphone/main.c",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n * This examples captures data from a PDM microphone using a sample\n * rate of 8 kHz and prints the sample values over the USB serial\n * connection.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"pico/stdlib.h\"\n#include \"pico/pdm_microphone.h\"\n#include \"tusb.h\"\n\n// configuration\nconst struct pdm_microphone_config config = {\n    // GPIO pin for the PDM DAT signal\n    .gpio_data = 2,\n\n    // GPIO pin for the PDM CLK signal\n    .gpio_clk = 3,\n\n    // PIO instance to use\n    .pio = pio0,\n\n    // PIO State Machine instance to use\n    .pio_sm = 0,\n\n    // sample rate in Hz\n    .sample_rate = 8000,\n\n    // number of samples to buffer\n    .sample_buffer_size = 256,\n};\n\n// variables\nint16_t sample_buffer[256];\nvolatile int samples_read = 0;\n\nvoid on_pdm_samples_ready()\n{\n    // callback from library when all the samples in the library\n    // internal sample buffer are ready for reading \n    samples_read = pdm_microphone_read(sample_buffer, 256);\n}\n\nint main( void )\n{\n    // initialize stdio and wait for USB CDC connect\n    stdio_init_all();\n    while (!tud_cdc_connected()) {\n        tight_loop_contents();\n    }\n\n    printf(\"hello PDM microphone\\n\");\n\n    // initialize the PDM microphone\n    if (pdm_microphone_init(&config) < 0) {\n        printf(\"PDM microphone initialization failed!\\n\");\n        while (1) { tight_loop_contents(); }\n    }\n\n    // set callback that is called when all the samples in the library\n    // internal sample buffer are ready for reading\n    pdm_microphone_set_samples_ready_handler(on_pdm_samples_ready);\n    \n     // start capturing data from the PDM microphone\n    if (pdm_microphone_start() < 0) {\n        printf(\"PDM microphone start failed!\\n\");\n        while (1) { tight_loop_contents(); }\n    }\n\n    while (1) {\n        // wait for new samples\n        while (samples_read == 0) { tight_loop_contents(); }\n\n        // store and clear the samples read from the callback\n        int sample_count = samples_read;\n        samples_read = 0;\n        \n        // loop through any new collected samples\n        for (int i = 0; i < sample_count; i++) {\n            printf(\"%d\\n\", sample_buffer[i]);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/usb_microphone/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.12)\n\n# rest of your project\nadd_executable(usb_microphone\n    main.c\n    usb_descriptors.c\n    usb_microphone.c\n)\n\ntarget_include_directories(usb_microphone PRIVATE ${CMAKE_CURRENT_LIST_DIR})\n\ntarget_link_libraries(usb_microphone PRIVATE tinyusb_device tinyusb_board pico_pdm_microphone)\n\n# create map/bin/hex/uf2 file in addition to ELF.\npico_add_extra_outputs(usb_microphone)\n"
  },
  {
    "path": "examples/usb_microphone/main.c",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n * This examples creates a USB Microphone device using the TinyUSB\n * library and captures data from a PDM microphone using a sample\n * rate of 16 kHz, to be sent the to PC.\n * \n * The USB microphone code is based on the TinyUSB audio_test example.\n * \n * https://github.com/hathach/tinyusb/tree/master/examples/device/audio_test\n */\n\n#include \"pico/pdm_microphone.h\"\n\n#include \"usb_microphone.h\"\n\n// configuration\nconst struct pdm_microphone_config config = {\n  .gpio_data = 2,\n  .gpio_clk = 3,\n  .pio = pio0,\n  .pio_sm = 0,\n  .sample_rate = SAMPLE_RATE,\n  .sample_buffer_size = SAMPLE_BUFFER_SIZE,\n};\n\n// variables\nuint16_t sample_buffer[SAMPLE_BUFFER_SIZE];\n\n// callback functions\nvoid on_pdm_samples_ready();\nvoid on_usb_microphone_tx_ready();\n\nint main(void)\n{\n  // initialize and start the PDM microphone\n  pdm_microphone_init(&config);\n  pdm_microphone_set_samples_ready_handler(on_pdm_samples_ready);\n  pdm_microphone_start();\n\n  // initialize the USB microphone interface\n  usb_microphone_init();\n  usb_microphone_set_tx_ready_handler(on_usb_microphone_tx_ready);\n\n  while (1) {\n    // run the USB microphone task continuously\n    usb_microphone_task();\n  }\n\n  return 0;\n}\n\nvoid on_pdm_samples_ready()\n{\n  // Callback from library when all the samples in the library\n  // internal sample buffer are ready for reading.\n  //\n  // Read new samples into local buffer.\n  pdm_microphone_read(sample_buffer, SAMPLE_BUFFER_SIZE);\n}\n\nvoid on_usb_microphone_tx_ready()\n{\n  // Callback from TinyUSB library when all data is ready\n  // to be transmitted.\n  //\n  // Write local buffer to the USB microphone\n  usb_microphone_write(sample_buffer, sizeof(sample_buffer));\n}\n"
  },
  {
    "path": "examples/usb_microphone/tusb_config.h",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Ha Thach (tinyusb.org)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n */\n\n#ifndef _TUSB_CONFIG_H_\n#define _TUSB_CONFIG_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//--------------------------------------------------------------------\n// COMMON CONFIGURATION\n//--------------------------------------------------------------------\n\n// defined by compiler flags for flexibility\n#ifndef CFG_TUSB_MCU\n#error CFG_TUSB_MCU must be defined\n#endif\n\n#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX\n#define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)\n#else\n#define CFG_TUSB_RHPORT0_MODE       OPT_MODE_DEVICE\n#endif\n\n#ifndef CFG_TUSB_OS\n#define CFG_TUSB_OS                 OPT_OS_NONE\n#endif\n\n#ifndef CFG_TUSB_DEBUG\n#define CFG_TUSB_DEBUG              0\n#endif\n\n// CFG_TUSB_DEBUG is defined by compiler in DEBUG build\n// #define CFG_TUSB_DEBUG           0\n\n/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.\n * Tinyusb use follows macros to declare transferring memory so that they can be put\n * into those specific section.\n * e.g\n * - CFG_TUSB_MEM SECTION : __attribute__ (( section(\".usb_ram\") ))\n * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))\n */\n#ifndef CFG_TUSB_MEM_SECTION\n#define CFG_TUSB_MEM_SECTION\n#endif\n\n#ifndef CFG_TUSB_MEM_ALIGN\n#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))\n#endif\n\n//--------------------------------------------------------------------\n// DEVICE CONFIGURATION\n//--------------------------------------------------------------------\n\n#ifndef CFG_TUD_ENDPOINT0_SIZE\n#define CFG_TUD_ENDPOINT0_SIZE    64\n#endif\n\n//------------- CLASS -------------//\n#define CFG_TUD_CDC               0\n#define CFG_TUD_MSC               0\n#define CFG_TUD_HID               0\n#define CFG_TUD_MIDI              0\n#define CFG_TUD_AUDIO             1\n#define CFG_TUD_VENDOR            0\n\n//--------------------------------------------------------------------\n// AUDIO CLASS DRIVER CONFIGURATION\n//--------------------------------------------------------------------\n\n// Have a look into audio_device.h for all configurations\n\n#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN                                 TUD_AUDIO_MIC_ONE_CH_DESC_LEN\n#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT                                 1                                       // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)\n#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ                              64                                      // Size of control request buffer\n\n#define CFG_TUD_AUDIO_ENABLE_EP_IN                                    1\n#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX                    2                                       // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below\n#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX                            1                                       // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!\n#define CFG_TUD_AUDIO_EP_SZ_IN                                        (16 + 1) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX      // 16 Samples (16 kHz) x 2 Bytes/Sample x 1 Channel\n#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX                             CFG_TUD_AUDIO_EP_SZ_IN                  // Maximum EP IN size for all AS alternate settings used\n#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ                          CFG_TUD_AUDIO_EP_SZ_IN\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _TUSB_CONFIG_H_ */\n"
  },
  {
    "path": "examples/usb_microphone/usb_descriptors.c",
    "content": "/* \n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Ha Thach (tinyusb.org)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n */\n\n#include \"tusb.h\"\n\n/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.\n * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.\n *\n * Auto ProductID layout's Bitmap:\n *   [MSB]     AUDIO | MIDI | HID | MSC | CDC          [LSB]\n */\n#define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )\n#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \\\n    _PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )\n\n//--------------------------------------------------------------------+\n// Device Descriptors\n//--------------------------------------------------------------------+\ntusb_desc_device_t const desc_device =\n{\n    .bLength            = sizeof(tusb_desc_device_t),\n    .bDescriptorType    = TUSB_DESC_DEVICE,\n    .bcdUSB             = 0x0200,\n\n    // Use Interface Association Descriptor (IAD) for CDC\n    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)\n    .bDeviceClass       = TUSB_CLASS_MISC,\n    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,\n    .bDeviceProtocol    = MISC_PROTOCOL_IAD,\n    .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE,\n\n    .idVendor           = 0xCafe,\n    .idProduct          = USB_PID,\n    .bcdDevice          = 0x0100,\n\n    .iManufacturer      = 0x01,\n    .iProduct           = 0x02,\n    .iSerialNumber      = 0x03,\n\n    .bNumConfigurations = 0x01\n};\n\n// Invoked when received GET DEVICE DESCRIPTOR\n// Application return pointer to descriptor\nuint8_t const * tud_descriptor_device_cb(void)\n{\n  return (uint8_t const *) &desc_device;\n}\n\n//--------------------------------------------------------------------+\n// Configuration Descriptor\n//--------------------------------------------------------------------+\nenum\n{\n  ITF_NUM_AUDIO_CONTROL = 0,\n  ITF_NUM_AUDIO_STREAMING,\n  ITF_NUM_TOTAL\n};\n\n#define CONFIG_TOTAL_LEN    \t(TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN)\n\n#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX\n// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number\n// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...\n#define EPNUM_AUDIO   0x03\n#else\n#define EPNUM_AUDIO   0x01\n#endif\n\nuint8_t const desc_configuration[] =\n{\n    // Interface count, string index, total length, attribute, power in mA\n    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),\n\n    // Interface number, string index, EP Out & EP In address, EP size\n    TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN)\n};\n\n// Invoked when received GET CONFIGURATION DESCRIPTOR\n// Application return pointer to descriptor\n// Descriptor contents must exist long enough for transfer to complete\nuint8_t const * tud_descriptor_configuration_cb(uint8_t index)\n{\n  (void) index; // for multiple configurations\n  return desc_configuration;\n}\n\n//--------------------------------------------------------------------+\n// String Descriptors\n//--------------------------------------------------------------------+\n\n// array of pointer to string descriptors\nchar const* string_desc_arr [] =\n{\n    (const char[]) { 0x09, 0x04 }, \t// 0: is supported language is English (0x0409)\n    \"PaniRCorp\",                   \t// 1: Manufacturer\n    \"MicNode\",              \t\t// 2: Product\n    \"123456\",                      \t// 3: Serials, should use chip ID\n    \"UAC2\",                 \t \t// 4: Audio Interface\n};\n\nstatic uint16_t _desc_str[32];\n\n// Invoked when received GET STRING DESCRIPTOR request\n// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete\nuint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)\n{\n  (void) langid;\n\n  uint8_t chr_count;\n\n  if ( index == 0)\n  {\n    memcpy(&_desc_str[1], string_desc_arr[0], 2);\n    chr_count = 1;\n  }else\n  {\n    // Convert ASCII string into UTF-16\n\n    if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;\n\n    const char* str = string_desc_arr[index];\n\n    // Cap at max char\n    chr_count = strlen(str);\n    if ( chr_count > 31 ) chr_count = 31;\n\n    for(uint8_t i=0; i<chr_count; i++)\n    {\n      _desc_str[1+i] = str[i];\n    }\n  }\n\n  // first byte is length (including header), second byte is string type\n  _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);\n\n  return _desc_str;\n}\n"
  },
  {
    "path": "examples/usb_microphone/usb_microphone.c",
    "content": "/* \n * The MIT License (MIT)\n *\n * Copyright (c) 2020 Reinhard Panhuber\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n */\n\n#include \"usb_microphone.h\"\n\n// Audio controls\n// Current states\nbool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; \t\t\t\t\t\t// +1 for master channel 0\nuint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; \t\t\t\t\t// +1 for master channel 0\nuint32_t sampFreq;\nuint8_t clkValid;\n\n// Range states\naudio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; \t\t\t// Volume range state\naudio_control_range_4_n_t(1) sampleFreqRng; \t\t\t\t\t\t// Sample frequency range state\n\nstatic usb_microphone_tx_ready_handler_t usb_microphone_tx_ready_handler = NULL;\n\n/*------------- MAIN -------------*/\nvoid usb_microphone_init()\n{\n  tusb_init();\n\n  // Init values\n  sampFreq = SAMPLE_RATE;\n  clkValid = 1;\n\n  sampleFreqRng.wNumSubRanges = 1;\n  sampleFreqRng.subrange[0].bMin = SAMPLE_RATE;\n  sampleFreqRng.subrange[0].bMax = SAMPLE_RATE;\n  sampleFreqRng.subrange[0].bRes = 0;\n}\n\nvoid usb_microphone_set_tx_ready_handler(usb_microphone_tx_ready_handler_t handler)\n{\n  usb_microphone_tx_ready_handler = handler;\n}\n\nuint16_t usb_microphone_write(const void * data, uint16_t len)\n{\n  return tud_audio_write ((uint8_t *)data, len);\n}\n\nvoid usb_microphone_task()\n{\n  tud_task();\n}\n\n//--------------------------------------------------------------------+\n// Application Callback API Implementations\n//--------------------------------------------------------------------+\n\n// Invoked when audio class specific set request received for an EP\nbool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)\n{\n  (void) rhport;\n  (void) pBuff;\n\n  // We do not support any set range requests here, only current value requests\n  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);\n\n  // Page 91 in UAC2 specification\n  uint8_t channelNum = TU_U16_LOW(p_request->wValue);\n  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);\n  uint8_t ep = TU_U16_LOW(p_request->wIndex);\n\n  (void) channelNum; (void) ctrlSel; (void) ep;\n\n  return false; \t// Yet not implemented\n}\n\n// Invoked when audio class specific set request received for an interface\nbool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)\n{\n  (void) rhport;\n  (void) pBuff;\n\n  // We do not support any set range requests here, only current value requests\n  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);\n\n  // Page 91 in UAC2 specification\n  uint8_t channelNum = TU_U16_LOW(p_request->wValue);\n  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);\n  uint8_t itf = TU_U16_LOW(p_request->wIndex);\n\n  (void) channelNum; (void) ctrlSel; (void) itf;\n\n  return false; \t// Yet not implemented\n}\n\n// Invoked when audio class specific set request received for an entity\nbool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)\n{\n  (void) rhport;\n\n  // Page 91 in UAC2 specification\n  uint8_t channelNum = TU_U16_LOW(p_request->wValue);\n  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);\n  uint8_t itf = TU_U16_LOW(p_request->wIndex);\n  uint8_t entityID = TU_U16_HIGH(p_request->wIndex);\n\n  (void) itf;\n\n  // We do not support any set range requests here, only current value requests\n  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);\n\n  // If request is for our feature unit\n  if ( entityID == 2 )\n  {\n    switch ( ctrlSel )\n    {\n      case AUDIO_FU_CTRL_MUTE:\n        // Request uses format layout 1\n        TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));\n\n        mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur;\n\n        TU_LOG2(\"    Set Mute: %d of channel: %u\\r\\n\", mute[channelNum], channelNum);\n\n      return true;\n\n      case AUDIO_FU_CTRL_VOLUME:\n        // Request uses format layout 2\n        TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));\n\n        volume[channelNum] = ((audio_control_cur_2_t*) pBuff)->bCur;\n\n        TU_LOG2(\"    Set Volume: %d dB of channel: %u\\r\\n\", volume[channelNum], channelNum);\n\n     return true;\n\n        // Unknown/Unsupported control\n      default:\n        TU_BREAKPOINT();\n      return false;\n    }\n  }\n  return false;    // Yet not implemented\n}\n\n// Invoked when audio class specific get request received for an EP\nbool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request)\n{\n  (void) rhport;\n\n  // Page 91 in UAC2 specification\n  uint8_t channelNum = TU_U16_LOW(p_request->wValue);\n  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);\n  uint8_t ep = TU_U16_LOW(p_request->wIndex);\n\n  (void) channelNum; (void) ctrlSel; (void) ep;\n\n  //\treturn tud_control_xfer(rhport, p_request, &tmp, 1);\n\n  return false; \t// Yet not implemented\n}\n\n// Invoked when audio class specific get request received for an interface\nbool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)\n{\n  (void) rhport;\n\n  // Page 91 in UAC2 specification\n  uint8_t channelNum = TU_U16_LOW(p_request->wValue);\n  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);\n  uint8_t itf = TU_U16_LOW(p_request->wIndex);\n\n  (void) channelNum; (void) ctrlSel; (void) itf;\n\n  return false; \t// Yet not implemented\n}\n\n// Invoked when audio class specific get request received for an entity\nbool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request)\n{\n  (void) rhport;\n\n  // Page 91 in UAC2 specification\n  uint8_t channelNum = TU_U16_LOW(p_request->wValue);\n  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);\n  // uint8_t itf = TU_U16_LOW(p_request->wIndex); \t\t\t// Since we have only one audio function implemented, we do not need the itf value\n  uint8_t entityID = TU_U16_HIGH(p_request->wIndex);\n\n  // Input terminal (Microphone input)\n  if (entityID == 1)\n  {\n    switch (ctrlSel)\n    {\n      case AUDIO_TE_CTRL_CONNECTOR:;\n      // The terminal connector control only has a get request with only the CUR attribute.\n\n      audio_desc_channel_cluster_t ret;\n\n      // Those are dummy values for now\n      ret.bNrChannels = 1;\n      ret.bmChannelConfig = 0;\n      ret.iChannelNames = 0;\n\n      TU_LOG2(\"    Get terminal connector\\r\\n\");\n\n      return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));\n\n      // Unknown/Unsupported control selector\n      default: TU_BREAKPOINT(); return false;\n    }\n  }\n\n  // Feature unit\n  if (entityID == 2)\n  {\n    switch (ctrlSel)\n    {\n      case AUDIO_FU_CTRL_MUTE:\n\t// Audio control mute cur parameter block consists of only one byte - we thus can send it right away\n\t// There does not exist a range parameter block for mute\n\tTU_LOG2(\"    Get Mute of channel: %u\\r\\n\", channelNum);\n\treturn tud_control_xfer(rhport, p_request, &mute[channelNum], 1);\n\n      case AUDIO_FU_CTRL_VOLUME:\n\n\tswitch (p_request->bRequest)\n\t{\n\t  case AUDIO_CS_REQ_CUR:\n\t    TU_LOG2(\"    Get Volume of channel: %u\\r\\n\", channelNum);\n\t    return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));\n\t  case AUDIO_CS_REQ_RANGE:\n\t    TU_LOG2(\"    Get Volume range of channel: %u\\r\\n\", channelNum);\n\n\t    // Copy values - only for testing - better is version below\n\t    audio_control_range_2_n_t(1) ret;\n\n\t    ret.wNumSubRanges = 1;\n\t    ret.subrange[0].bMin = -90; \t// -90 dB\n\t    ret.subrange[0].bMax = 90;\t\t// +90 dB\n\t    ret.subrange[0].bRes = 1; \t\t// 1 dB steps\n\n\t    return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));\n\n\t    // Unknown/Unsupported control\n\t  default: TU_BREAKPOINT(); return false;\n\t}\n\n\t// Unknown/Unsupported control\n\t  default: TU_BREAKPOINT(); return false;\n    }\n  }\n\n  // Clock Source unit\n  if (entityID == 4)\n  {\n    switch (ctrlSel)\n    {\n      case AUDIO_CS_CTRL_SAM_FREQ:\n\n\t// channelNum is always zero in this case\n\n\tswitch (p_request->bRequest)\n\t{\n\t  case AUDIO_CS_REQ_CUR:\n\t    TU_LOG2(\"    Get Sample Freq.\\r\\n\");\n\t    return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));\n\t  case AUDIO_CS_REQ_RANGE:\n\t    TU_LOG2(\"    Get Sample Freq. range\\r\\n\");\n\t    return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));\n\n\t    // Unknown/Unsupported control\n\t  default: TU_BREAKPOINT(); return false;\n\t}\n\n\t  case AUDIO_CS_CTRL_CLK_VALID:\n\t    // Only cur attribute exists for this request\n\t    TU_LOG2(\"    Get Sample Freq. valid\\r\\n\");\n\t    return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));\n\n\t    // Unknown/Unsupported control\n\t  default: TU_BREAKPOINT(); return false;\n    }\n  }\n\n  TU_LOG2(\"  Unsupported entity: %d\\r\\n\", entityID);\n  return false; \t// Yet not implemented\n}\n\nbool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)\n{\n  (void) rhport;\n  (void) itf;\n  (void) ep_in;\n  (void) cur_alt_setting;\n\n  if (usb_microphone_tx_ready_handler)\n  {\n    usb_microphone_tx_ready_handler();\n  }\n\n  return true;\n}\n\nbool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)\n{\n  (void) rhport;\n  (void) n_bytes_copied;\n  (void) itf;\n  (void) ep_in;\n  (void) cur_alt_setting;\n\n  return true;\n}\n\nbool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request)\n{\n  (void) rhport;\n  (void) p_request;\n\n  return true;\n}\n"
  },
  {
    "path": "examples/usb_microphone/usb_microphone.h",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n */\n\n#ifndef _USB_MICROPHONE_H_\n#define _USB_MICROPHONE_H_\n\n#include \"tusb.h\"\n\n#ifndef SAMPLE_RATE\n#define SAMPLE_RATE ((CFG_TUD_AUDIO_EP_SZ_IN / 2) - 1) * 1000\n#endif\n\n#ifndef SAMPLE_BUFFER_SIZE\n#define SAMPLE_BUFFER_SIZE ((CFG_TUD_AUDIO_EP_SZ_IN/2) - 1)\n#endif\n\ntypedef void (*usb_microphone_tx_ready_handler_t)(void);\n\nvoid usb_microphone_init();\nvoid usb_microphone_set_tx_ready_handler(usb_microphone_tx_ready_handler_t handler);\nvoid usb_microphone_task();\nuint16_t usb_microphone_write(const void * data, uint16_t len);\n\n#endif\n"
  },
  {
    "path": "pico_sdk_import.cmake",
    "content": "# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake\n\n# This can be dropped into an external project to help locate this SDK\n# It should be include()ed prior to project()\n\nif (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))\n    set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})\n    message(\"Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')\")\nendif ()\n\nif (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))\n    set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})\n    message(\"Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')\")\nendif ()\n\nif (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))\n    set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})\n    message(\"Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')\")\nendif ()\n\nset(PICO_SDK_PATH \"${PICO_SDK_PATH}\" CACHE PATH \"Path to the Raspberry Pi Pico SDK\")\nset(PICO_SDK_FETCH_FROM_GIT \"${PICO_SDK_FETCH_FROM_GIT}\" CACHE BOOL \"Set to ON to fetch copy of SDK from git if not otherwise locatable\")\nset(PICO_SDK_FETCH_FROM_GIT_PATH \"${PICO_SDK_FETCH_FROM_GIT_PATH}\" CACHE FILEPATH \"location to download SDK\")\n\nif (NOT PICO_SDK_PATH)\n    if (PICO_SDK_FETCH_FROM_GIT)\n        include(FetchContent)\n        set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})\n        if (PICO_SDK_FETCH_FROM_GIT_PATH)\n            get_filename_component(FETCHCONTENT_BASE_DIR \"${PICO_SDK_FETCH_FROM_GIT_PATH}\" REALPATH BASE_DIR \"${CMAKE_SOURCE_DIR}\")\n        endif ()\n        FetchContent_Declare(\n                pico_sdk\n                GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk\n                GIT_TAG master\n        )\n        if (NOT pico_sdk)\n            message(\"Downloading Raspberry Pi Pico SDK\")\n            FetchContent_Populate(pico_sdk)\n            set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})\n        endif ()\n        set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})\n    else ()\n        message(FATAL_ERROR\n                \"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git.\"\n                )\n    endif ()\nendif ()\n\nget_filename_component(PICO_SDK_PATH \"${PICO_SDK_PATH}\" REALPATH BASE_DIR \"${CMAKE_BINARY_DIR}\")\nif (NOT EXISTS ${PICO_SDK_PATH})\n    message(FATAL_ERROR \"Directory '${PICO_SDK_PATH}' not found\")\nendif ()\n\nset(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)\nif (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})\n    message(FATAL_ERROR \"Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK\")\nendif ()\n\nset(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH \"Path to the Raspberry Pi Pico SDK\" FORCE)\n\ninclude(${PICO_SDK_INIT_CMAKE_FILE})\n"
  },
  {
    "path": "src/OpenPDM2PCM/LICENSE.txt",
    "content": " \n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n \n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n \n   1. Definitions.\n \n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n \n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n \n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n \n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n \n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n \n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n \n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n \n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n \n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n \n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n \n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n \n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n \n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n \n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n \n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n \n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n \n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n \n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n \n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n \n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n \n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n \n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n \n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n \n   END OF TERMS AND CONDITIONS\n \n   APPENDIX: How to apply the Apache License to your work.\n \n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n \n   Copyright [yyyy] [name of copyright owner]\n \n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n \n       http://www.apache.org/licenses/LICENSE-2.0\n \n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n \n            \nRepository toolbox\nImport into Mbed Studio\n Export to desktop IDE\nRepository details\nType:\t Library\nCreated:\t27 Apr 2017\nImports:\t 122\nForks:\t 1\nCommits:\t 27\nDependents:\t 4\nDependencies:\t 3\nFollowers:\t 387\nThe code in this repository is Apache licensed.\nComponents\n X-NUCLEO-CCA02M1 Digital MEMS Microphones Expansion Board.\n"
  },
  {
    "path": "src/OpenPDM2PCM/OpenPDMFilter.c",
    "content": "/**\n *******************************************************************************\n * @file    OpenPDMFilter.c\n * @author  CL\n * @version V1.0.0\n * @date    9-September-2015\n * @brief   Open PDM audio software decoding Library.   \n *          This Library is used to decode and reconstruct the audio signal\n *          produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx). \n *******************************************************************************\n * @attention\n *\n * <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************\n */\n \n \n/* Includes ------------------------------------------------------------------*/\n \n#include \"OpenPDMFilter.h\"\n \n \n/* Variables -----------------------------------------------------------------*/\n \nuint32_t div_const = 0;\nint64_t sub_const = 0;\nuint32_t sinc[DECIMATION_MAX * SINCN];\nuint32_t sinc1[DECIMATION_MAX];\nuint32_t sinc2[DECIMATION_MAX * 2];\nuint32_t coef[SINCN][DECIMATION_MAX];\n#ifdef USE_LUT\nint32_t lut[256][DECIMATION_MAX / 8][SINCN];\n#endif\n \n \n/* Functions -----------------------------------------------------------------*/\n \n#ifdef USE_LUT\nint32_t filter_table_mono_64(uint8_t *data, uint8_t sincn)\n{\n  return (int32_t)\n    lut[data[0]][0][sincn] +\n    lut[data[1]][1][sincn] +\n    lut[data[2]][2][sincn] +\n    lut[data[3]][3][sincn] +\n    lut[data[4]][4][sincn] +\n    lut[data[5]][5][sincn] +\n    lut[data[6]][6][sincn] +\n    lut[data[7]][7][sincn];\n}\nint32_t filter_table_stereo_64(uint8_t *data, uint8_t sincn)\n{\n  return (int32_t)\n    lut[data[0]][0][sincn] +\n    lut[data[2]][1][sincn] +\n    lut[data[4]][2][sincn] +\n    lut[data[6]][3][sincn] +\n    lut[data[8]][4][sincn] +\n    lut[data[10]][5][sincn] +\n    lut[data[12]][6][sincn] +\n    lut[data[14]][7][sincn];\n}\nint32_t filter_table_mono_128(uint8_t *data, uint8_t sincn)\n{\n  return (int32_t)\n    lut[data[0]][0][sincn] +\n    lut[data[1]][1][sincn] +\n    lut[data[2]][2][sincn] +\n    lut[data[3]][3][sincn] +\n    lut[data[4]][4][sincn] +\n    lut[data[5]][5][sincn] +\n    lut[data[6]][6][sincn] +\n    lut[data[7]][7][sincn] +\n    lut[data[8]][8][sincn] +\n    lut[data[9]][9][sincn] +\n    lut[data[10]][10][sincn] +\n    lut[data[11]][11][sincn] +\n    lut[data[12]][12][sincn] +\n    lut[data[13]][13][sincn] +\n    lut[data[14]][14][sincn] +\n    lut[data[15]][15][sincn];\n}\nint32_t filter_table_stereo_128(uint8_t *data, uint8_t sincn)\n{\n  return (int32_t)\n    lut[data[0]][0][sincn] +\n    lut[data[2]][1][sincn] +\n    lut[data[4]][2][sincn] +\n    lut[data[6]][3][sincn] +\n    lut[data[8]][4][sincn] +\n    lut[data[10]][5][sincn] +\n    lut[data[12]][6][sincn] +\n    lut[data[14]][7][sincn] +\n    lut[data[16]][8][sincn] +\n    lut[data[18]][9][sincn] +\n    lut[data[20]][10][sincn] +\n    lut[data[22]][11][sincn] +\n    lut[data[24]][12][sincn] +\n    lut[data[26]][13][sincn] +\n    lut[data[28]][14][sincn] +\n    lut[data[30]][15][sincn];\n}\nint32_t (* filter_tables_64[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_64, filter_table_stereo_64};\nint32_t (* filter_tables_128[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_128, filter_table_stereo_128};\n#else\nint32_t filter_table(uint8_t *data, uint8_t sincn, TPDMFilter_InitStruct *param)\n{\n  uint8_t c, i;\n  uint16_t data_index = 0;\n  uint32_t *coef_p = &coef[sincn][0];\n  int32_t F = 0;\n  uint8_t decimation = param->Decimation;\n  uint8_t channels = param->In_MicChannels;\n \n  for (i = 0; i < decimation; i += 8) {\n    c = data[data_index];\n    F += ((c >> 7)       ) * coef_p[i    ] +\n         ((c >> 6) & 0x01) * coef_p[i + 1] +\n         ((c >> 5) & 0x01) * coef_p[i + 2] +\n         ((c >> 4) & 0x01) * coef_p[i + 3] +\n         ((c >> 3) & 0x01) * coef_p[i + 4] +\n         ((c >> 2) & 0x01) * coef_p[i + 5] +\n         ((c >> 1) & 0x01) * coef_p[i + 6] +\n         ((c     ) & 0x01) * coef_p[i + 7];\n    data_index += channels;\n  }\n  return F;\n}\n#endif\n \nvoid convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen,\n              uint32_t Kernel[/* KernelLen */], unsigned short KernelLen,\n              uint32_t Result[/* SignalLen + KernelLen - 1 */])\n{\n  uint16_t n;\n \n  for (n = 0; n < SignalLen + KernelLen - 1; n++)\n  {\n    unsigned short kmin, kmax, k;\n    \n    Result[n] = 0;\n    \n    kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0;\n    kmax = (n < SignalLen - 1) ? n : SignalLen - 1;\n    \n    for (k = kmin; k <= kmax; k++) {\n      Result[n] += Signal[k] * Kernel[n - k];\n    }\n  }\n}\n \nvoid Open_PDM_Filter_Init(TPDMFilter_InitStruct *Param)\n{\n  uint16_t i, j;\n  int64_t sum = 0;\n \n  uint8_t decimation = Param->Decimation;\n \n  for (i = 0; i < SINCN; i++) {\n    Param->Coef[i] = 0;\n    Param->bit[i] = 0;\n  }\n  for (i = 0; i < decimation; i++) {\n    sinc1[i] = 1;\n  }\n \n  Param->OldOut = Param->OldIn = Param->OldZ = 0;\n  Param->LP_ALFA = (Param->LP_HZ != 0 ? (uint16_t) (Param->LP_HZ * 256 / (Param->LP_HZ + Param->Fs / (2 * 3.14159))) : 0);\n  Param->HP_ALFA = (Param->HP_HZ != 0 ? (uint16_t) (Param->Fs * 256 / (2 * 3.14159 * Param->HP_HZ + Param->Fs)) : 0);\n \n  Param->FilterLen = decimation * SINCN;       \n  sinc[0] = 0;\n  sinc[decimation * SINCN - 1] = 0;      \n  convolve(sinc1, decimation, sinc1, decimation, sinc2);\n  convolve(sinc2, decimation * 2 - 1, sinc1, decimation, &sinc[1]);     \n  for(j = 0; j < SINCN; j++) {\n    for (i = 0; i < decimation; i++) {\n      coef[j][i] = sinc[j * decimation + i];\n      sum += sinc[j * decimation + i];\n    }\n  }\n \n  sub_const = sum >> 1;\n  div_const = sub_const * Param->MaxVolume / 32768 / FILTER_GAIN;\n  div_const = (div_const == 0 ? 1 : div_const);\n \n#ifdef USE_LUT\n  /* Look-Up Table. */\n  uint16_t c, d, s;\n  for (s = 0; s < SINCN; s++)\n  {\n    uint32_t *coef_p = &coef[s][0];\n    for (c = 0; c < 256; c++)\n      for (d = 0; d < decimation / 8; d++)\n        lut[c][d][s] = ((c >> 7)       ) * coef_p[d * 8    ] +\n                       ((c >> 6) & 0x01) * coef_p[d * 8 + 1] +\n                       ((c >> 5) & 0x01) * coef_p[d * 8 + 2] +\n                       ((c >> 4) & 0x01) * coef_p[d * 8 + 3] +\n                       ((c >> 3) & 0x01) * coef_p[d * 8 + 4] +\n                       ((c >> 2) & 0x01) * coef_p[d * 8 + 5] +\n                       ((c >> 1) & 0x01) * coef_p[d * 8 + 6] +\n                       ((c     ) & 0x01) * coef_p[d * 8 + 7];\n  }\n#endif\n}\n \nvoid Open_PDM_Filter_64(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)\n{\n  uint8_t i, data_out_index;\n  uint8_t channels = Param->In_MicChannels;\n  uint8_t data_inc = ((DECIMATION_MAX >> 4) * channels);\n  int64_t Z, Z0, Z1, Z2;\n  int64_t OldOut, OldIn, OldZ;\n \n  OldOut = Param->OldOut;\n  OldIn = Param->OldIn;\n  OldZ = Param->OldZ;\n \n#ifdef USE_LUT\n  uint8_t j = channels - 1;\n#endif\n \n  for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) {\n#ifdef USE_LUT\n    Z0 = filter_tables_64[j](data, 0);\n    Z1 = filter_tables_64[j](data, 1);\n    Z2 = filter_tables_64[j](data, 2);\n#else\n    Z0 = filter_table(data, 0, Param);\n    Z1 = filter_table(data, 1, Param);\n    Z2 = filter_table(data, 2, Param);\n#endif\n \n    Z = Param->Coef[1] + Z2 - sub_const;\n    Param->Coef[1] = Param->Coef[0] + Z1;\n    Param->Coef[0] = Z0;\n \n    OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;\n    OldIn = Z;\n    OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;\n \n    Z = OldZ * volume;\n    Z = RoundDiv(Z, div_const);\n    Z = SaturaLH(Z, -32700, 32700);\n \n    dataOut[data_out_index] = Z;\n    data += data_inc;\n  }\n \n  Param->OldOut = OldOut;\n  Param->OldIn = OldIn;\n  Param->OldZ = OldZ;\n}\n \nvoid Open_PDM_Filter_128(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)\n{\n  uint8_t i, data_out_index;\n  uint8_t channels = Param->In_MicChannels;\n  uint8_t data_inc = ((DECIMATION_MAX >> 3) * channels);\n  int64_t Z, Z0, Z1, Z2;\n  int64_t OldOut, OldIn, OldZ;\n \n  OldOut = Param->OldOut;\n  OldIn = Param->OldIn;\n  OldZ = Param->OldZ;\n \n#ifdef USE_LUT\n  uint8_t j = channels - 1;\n#endif\n \n  for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) {\n#ifdef USE_LUT\n    Z0 = filter_tables_128[j](data, 0);\n    Z1 = filter_tables_128[j](data, 1);\n    Z2 = filter_tables_128[j](data, 2);\n#else\n    Z0 = filter_table(data, 0, Param);\n    Z1 = filter_table(data, 1, Param);\n    Z2 = filter_table(data, 2, Param);\n#endif\n \n    Z = Param->Coef[1] + Z2 - sub_const;\n    Param->Coef[1] = Param->Coef[0] + Z1;\n    Param->Coef[0] = Z0;\n \n    OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;\n    OldIn = Z;\n    OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;\n \n    Z = OldZ * volume;\n    Z = RoundDiv(Z, div_const);\n    Z = SaturaLH(Z, -32700, 32700);\n \n    dataOut[data_out_index] = Z;\n    data += data_inc;\n  }\n \n  Param->OldOut = OldOut;\n  Param->OldIn = OldIn;\n  Param->OldZ = OldZ;\n}\n \n"
  },
  {
    "path": "src/OpenPDM2PCM/OpenPDMFilter.h",
    "content": "/**\n *******************************************************************************\n * @file    OpenPDMFilter.h\n * @author  CL\n * @version V1.0.0\n * @date    9-September-2015\n * @brief   Header file for Open PDM audio software decoding Library.   \n *          This Library is used to decode and reconstruct the audio signal\n *          produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx). \n *******************************************************************************\n * @attention\n *\n * <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *******************************************************************************\n */\n \n \n/* Define to prevent recursive inclusion -------------------------------------*/\n \n#ifndef __OPENPDMFILTER_H\n#define __OPENPDMFILTER_H\n \n#ifdef __cplusplus\n  extern \"C\" {\n#endif\n \n \n/* Includes ------------------------------------------------------------------*/\n \n#include <stdint.h>\n \n \n/* Definitions ---------------------------------------------------------------*/\n \n/*\n * Enable to use a Look-Up Table to improve performances while using more FLASH\n * and RAM memory.\n * Note: Without Look-Up Table up to stereo@16KHz configuration is supported.\n */\n#define USE_LUT\n \n#define SINCN            3\n#define DECIMATION_MAX 128\n#ifdef PICO_BUILD\n#define FILTER_GAIN     Param->Gain\n#else\n#define FILTER_GAIN     16\n#endif\n \n#define HTONS(A) ((((uint16_t)(A) & 0xff00) >> 8) | \\\n                 (((uint16_t)(A) & 0x00ff) << 8))\n#define RoundDiv(a, b)    (((a)>0)?(((a)+(b)/2)/(b)):(((a)-(b)/2)/(b)))\n#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))\n \n \n/* Types ---------------------------------------------------------------------*/\n \ntypedef struct {\n  /* Public */\n  float LP_HZ;\n  float HP_HZ;\n  uint16_t Fs;\n  uint8_t In_MicChannels;\n  uint8_t Out_MicChannels;\n  uint8_t Decimation;\n  uint8_t MaxVolume;\n#ifdef PICO_BUILD\n  uint8_t Gain;\n#endif\n  /* Private */\n  uint32_t Coef[SINCN];\n  uint16_t FilterLen;\n  int64_t OldOut, OldIn, OldZ;\n  uint16_t LP_ALFA;\n  uint16_t HP_ALFA;\n  uint16_t bit[5];\n  uint16_t byte;\n} TPDMFilter_InitStruct;\n \n \n/* Exported functions ------------------------------------------------------- */\n \nvoid Open_PDM_Filter_Init(TPDMFilter_InitStruct *init_struct);\nvoid Open_PDM_Filter_64(uint8_t* data, uint16_t* data_out, uint16_t mic_gain, TPDMFilter_InitStruct *init_struct);\nvoid Open_PDM_Filter_128(uint8_t* data, uint16_t* data_out, uint16_t mic_gain, TPDMFilter_InitStruct *init_struct);\n \n#ifdef __cplusplus\n}\n#endif\n \n#endif // __OPENPDMFILTER_H\n \n/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/\n \n"
  },
  {
    "path": "src/analog_microphone.c",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"hardware/adc.h\"\n#include \"hardware/clocks.h\"\n#include \"hardware/dma.h\"\n#include \"hardware/irq.h\"\n\n#include \"pico/analog_microphone.h\"\n\n#define ANALOG_RAW_BUFFER_COUNT 2\n\nstatic struct {\n    struct analog_microphone_config config;\n    int dma_channel;\n    uint16_t* raw_buffer[ANALOG_RAW_BUFFER_COUNT];\n    volatile int raw_buffer_write_index;\n    volatile int raw_buffer_read_index;\n    uint buffer_size;\n    int16_t bias;\n    uint dma_irq;\n    analog_samples_ready_handler_t samples_ready_handler;\n} analog_mic;\n\nstatic void analog_dma_handler();\n\nint analog_microphone_init(const struct analog_microphone_config* config) {\n    memset(&analog_mic, 0x00, sizeof(analog_mic));\n    memcpy(&analog_mic.config, config, sizeof(analog_mic.config));\n\n    if (config->gpio < 26 || config->gpio > 29) {\n        return -1;\n    }\n\n    size_t raw_buffer_size = config->sample_buffer_size * sizeof(analog_mic.raw_buffer[0][0]);\n\n    analog_mic.buffer_size = config->sample_buffer_size;\n    analog_mic.bias = ((int16_t)((config->bias_voltage * 4095) / 3.3));\n\n    for (int i = 0; i < ANALOG_RAW_BUFFER_COUNT; i++) {\n        analog_mic.raw_buffer[i] = malloc(raw_buffer_size);\n        if (analog_mic.raw_buffer[i] == NULL) {\n            analog_microphone_deinit();\n\n            return -1;   \n        }\n    }\n\n    analog_mic.dma_channel = dma_claim_unused_channel(true);\n    if (analog_mic.dma_channel < 0) {\n        analog_microphone_deinit();\n\n        return -1;\n    }\n\n    float clk_div = (clock_get_hz(clk_adc) / (1.0 * config->sample_rate)) - 1;\n\n    dma_channel_config dma_channel_cfg = dma_channel_get_default_config(analog_mic.dma_channel);\n\n    channel_config_set_transfer_data_size(&dma_channel_cfg, DMA_SIZE_16);\n    channel_config_set_read_increment(&dma_channel_cfg, false);\n    channel_config_set_write_increment(&dma_channel_cfg, true);\n    channel_config_set_dreq(&dma_channel_cfg, DREQ_ADC);\n\n    analog_mic.dma_irq = DMA_IRQ_0;\n\n    dma_channel_configure(\n        analog_mic.dma_channel,\n        &dma_channel_cfg,\n        analog_mic.raw_buffer[0],\n        &adc_hw->fifo,\n        analog_mic.buffer_size,\n        false\n    );\n\n    adc_gpio_init(config->gpio);\n\n    adc_init();\n    adc_select_input(config->gpio - 26);\n    adc_fifo_setup(\n        true,    // Write each completed conversion to the sample FIFO\n        true,    // Enable DMA data request (DREQ)\n        1,       // DREQ (and IRQ) asserted when at least 1 sample present\n        false,   // We won't see the ERR bit because of 8 bit reads; disable.\n        false    // Don't shift each sample to 8 bits when pushing to FIFO\n    );\n\n    adc_set_clkdiv(clk_div);\n}\n\nvoid analog_microphone_deinit() {\n    for (int i = 0; i < ANALOG_RAW_BUFFER_COUNT; i++) {\n        if (analog_mic.raw_buffer[i]) {\n            free(analog_mic.raw_buffer[i]);\n\n            analog_mic.raw_buffer[i] = NULL;\n        }\n    }\n\n    if (analog_mic.dma_channel > -1) {\n        dma_channel_unclaim(analog_mic.dma_channel);\n\n        analog_mic.dma_channel = -1;\n    }\n}\n\nint analog_microphone_start() {\n    irq_set_enabled(analog_mic.dma_irq, true);\n    irq_set_exclusive_handler(analog_mic.dma_irq, analog_dma_handler);\n\n    if (analog_mic.dma_irq == DMA_IRQ_0) {\n        dma_channel_set_irq0_enabled(analog_mic.dma_channel, true);\n    } else if (analog_mic.dma_irq == DMA_IRQ_1) {\n        dma_channel_set_irq1_enabled(analog_mic.dma_channel, true);\n    } else {\n        return -1;\n    }\n\n    analog_mic.raw_buffer_write_index = 0;\n    analog_mic.raw_buffer_read_index = 0;\n\n    dma_channel_transfer_to_buffer_now(\n        analog_mic.dma_channel,\n        analog_mic.raw_buffer[0],\n        analog_mic.buffer_size\n    );\n\n    adc_run(true); // start running the adc\n}\n\nvoid analog_microphone_stop() {\n    adc_run(false); // stop running the adc\n\n    dma_channel_abort(analog_mic.dma_channel);\n\n    if (analog_mic.dma_irq == DMA_IRQ_0) {\n        dma_channel_set_irq0_enabled(analog_mic.dma_channel, false);\n    } else if (analog_mic.dma_irq == DMA_IRQ_1) {\n        dma_channel_set_irq1_enabled(analog_mic.dma_channel, false);\n    }\n\n    irq_set_enabled(analog_mic.dma_irq, false);\n}\n\nstatic void analog_dma_handler() {\n    // clear IRQ\n    if (analog_mic.dma_irq == DMA_IRQ_0) {\n        dma_hw->ints0 = (1u << analog_mic.dma_channel);\n    } else if (analog_mic.dma_irq == DMA_IRQ_1) {\n        dma_hw->ints1 = (1u << analog_mic.dma_channel);\n    }\n\n    // get the current buffer index\n    analog_mic.raw_buffer_read_index = analog_mic.raw_buffer_write_index;\n\n    // get the next capture index to send the dma to start\n    analog_mic.raw_buffer_write_index = (analog_mic.raw_buffer_write_index + 1) % ANALOG_RAW_BUFFER_COUNT;\n\n    // give the channel a new buffer to write to and re-trigger it\n    dma_channel_transfer_to_buffer_now(\n        analog_mic.dma_channel,\n        analog_mic.raw_buffer[analog_mic.raw_buffer_write_index],\n        analog_mic.buffer_size\n    );\n\n    if (analog_mic.samples_ready_handler) {\n        analog_mic.samples_ready_handler();\n    }\n}\n\nvoid analog_microphone_set_samples_ready_handler(analog_samples_ready_handler_t handler) {\n    analog_mic.samples_ready_handler = handler;\n}\n\nint analog_microphone_read(int16_t* buffer, size_t samples) {\n    if (samples > analog_mic.config.sample_buffer_size) {\n        samples = analog_mic.config.sample_buffer_size;\n    }\n\n    if (analog_mic.raw_buffer_write_index == analog_mic.raw_buffer_read_index) {\n        return 0;\n    }\n\n    uint16_t* in = analog_mic.raw_buffer[analog_mic.raw_buffer_read_index];\n    int16_t* out = buffer;\n    int16_t bias = analog_mic.bias;\n\n    analog_mic.raw_buffer_read_index++;\n\n    for (int i = 0; i < samples; i++) {\n        *out++ = *in++ - bias;\n    }\n\n    return samples;\n}\n"
  },
  {
    "path": "src/include/pico/analog_microphone.h",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n */\n\n#ifndef _PICO_ANALOG_MICROPHONE_H_\n#define _PICO_ANALOG_MICROPHONE_H_\n\ntypedef void (*analog_samples_ready_handler_t)(void);\n\nstruct analog_microphone_config {\n    uint gpio;\n    float bias_voltage;\n    uint sample_rate;\n    uint sample_buffer_size;\n};\n\nint analog_microphone_init(const struct analog_microphone_config* config);\nvoid analog_microphone_deinit();\n\nint analog_microphone_start();\nvoid analog_microphone_stop();\n\nvoid analog_microphone_set_samples_ready_handler(analog_samples_ready_handler_t handler);\n\nint analog_microphone_read(int16_t* buffer, size_t samples);\n\n#endif\n"
  },
  {
    "path": "src/include/pico/pdm_microphone.h",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n */\n\n#ifndef _PICO_PDM_MICROPHONE_H_\n#define _PICO_PDM_MICROPHONE_H_\n\n#include \"hardware/pio.h\"\n\ntypedef void (*pdm_samples_ready_handler_t)(void);\n\nstruct pdm_microphone_config {\n    uint gpio_data;\n    uint gpio_clk;\n    PIO pio;\n    uint pio_sm;\n    uint sample_rate;\n    uint sample_buffer_size;\n};\n\nint pdm_microphone_init(const struct pdm_microphone_config* config);\nvoid pdm_microphone_deinit();\n\nint pdm_microphone_start();\nvoid pdm_microphone_stop();\n\nvoid pdm_microphone_set_samples_ready_handler(pdm_samples_ready_handler_t handler);\nvoid pdm_microphone_set_filter_max_volume(uint8_t max_volume);\nvoid pdm_microphone_set_filter_gain(uint8_t gain);\nvoid pdm_microphone_set_filter_volume(uint16_t volume);\n\nint pdm_microphone_read(int16_t* buffer, size_t samples);\n\n#endif\n"
  },
  {
    "path": "src/pdm_microphone.c",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"hardware/clocks.h\"\n#include \"hardware/dma.h\"\n#include \"hardware/irq.h\"\n\n#include \"OpenPDM2PCM/OpenPDMFilter.h\"\n\n#include \"pdm_microphone.pio.h\"\n\n#include \"pico/pdm_microphone.h\"\n\n#define PDM_DECIMATION       64\n#define PDM_RAW_BUFFER_COUNT 2\n\nstatic struct {\n    struct pdm_microphone_config config;\n    int dma_channel;\n    uint8_t* raw_buffer[PDM_RAW_BUFFER_COUNT];\n    volatile int raw_buffer_write_index;\n    volatile int raw_buffer_read_index;\n    uint raw_buffer_size;\n    uint dma_irq;\n    TPDMFilter_InitStruct filter;\n    uint16_t filter_volume;\n    pdm_samples_ready_handler_t samples_ready_handler;\n} pdm_mic;\n\nstatic void pdm_dma_handler();\n\nint pdm_microphone_init(const struct pdm_microphone_config* config) {\n    memset(&pdm_mic, 0x00, sizeof(pdm_mic));\n    memcpy(&pdm_mic.config, config, sizeof(pdm_mic.config));\n\n    if (config->sample_buffer_size % (config->sample_rate / 1000)) {\n        return -1;\n    }\n\n    pdm_mic.raw_buffer_size = config->sample_buffer_size * (PDM_DECIMATION / 8);\n\n    for (int i = 0; i < PDM_RAW_BUFFER_COUNT; i++) {\n        pdm_mic.raw_buffer[i] = malloc(pdm_mic.raw_buffer_size);\n        if (pdm_mic.raw_buffer[i] == NULL) {\n            pdm_microphone_deinit();\n\n            return -1;   \n        }\n    }\n\n    pdm_mic.dma_channel = dma_claim_unused_channel(true);\n    if (pdm_mic.dma_channel < 0) {\n        pdm_microphone_deinit();\n\n        return -1;\n    }\n\n    uint pio_sm_offset = pio_add_program(config->pio, &pdm_microphone_data_program);\n\n    float clk_div = clock_get_hz(clk_sys) / (config->sample_rate * PDM_DECIMATION * 4.0);\n\n    pdm_microphone_data_init(\n        config->pio,\n        config->pio_sm,\n        pio_sm_offset,\n        clk_div,\n        config->gpio_data,\n        config->gpio_clk\n    );\n\n    dma_channel_config dma_channel_cfg = dma_channel_get_default_config(pdm_mic.dma_channel);\n\n    channel_config_set_transfer_data_size(&dma_channel_cfg, DMA_SIZE_8);\n    channel_config_set_read_increment(&dma_channel_cfg, false);\n    channel_config_set_write_increment(&dma_channel_cfg, true);\n    channel_config_set_dreq(&dma_channel_cfg, pio_get_dreq(config->pio, config->pio_sm, false));\n\n    pdm_mic.dma_irq = DMA_IRQ_0;\n\n    dma_channel_configure(\n        pdm_mic.dma_channel,\n        &dma_channel_cfg,\n        pdm_mic.raw_buffer[0],\n        &config->pio->rxf[config->pio_sm],\n        pdm_mic.raw_buffer_size,\n        false\n    );\n\n    pdm_mic.filter.Fs = config->sample_rate;\n    pdm_mic.filter.LP_HZ = config->sample_rate / 2;\n    pdm_mic.filter.HP_HZ = 10;\n    pdm_mic.filter.In_MicChannels = 1;\n    pdm_mic.filter.Out_MicChannels = 1;\n    pdm_mic.filter.Decimation = PDM_DECIMATION;\n    pdm_mic.filter.MaxVolume = 64;\n    pdm_mic.filter.Gain = 16;\n\n    pdm_mic.filter_volume = pdm_mic.filter.MaxVolume;\n}\n\nvoid pdm_microphone_deinit() {\n    for (int i = 0; i < PDM_RAW_BUFFER_COUNT; i++) {\n        if (pdm_mic.raw_buffer[i]) {\n            free(pdm_mic.raw_buffer[i]);\n\n            pdm_mic.raw_buffer[i] = NULL;\n        }\n    }\n\n    if (pdm_mic.dma_channel > -1) {\n        dma_channel_unclaim(pdm_mic.dma_channel);\n\n        pdm_mic.dma_channel = -1;\n    }\n}\n\nint pdm_microphone_start() {\n    irq_set_enabled(pdm_mic.dma_irq, true);\n    irq_set_exclusive_handler(pdm_mic.dma_irq, pdm_dma_handler);\n\n    if (pdm_mic.dma_irq == DMA_IRQ_0) {\n        dma_channel_set_irq0_enabled(pdm_mic.dma_channel, true);\n    } else if (pdm_mic.dma_irq == DMA_IRQ_1) {\n        dma_channel_set_irq1_enabled(pdm_mic.dma_channel, true);\n    } else {\n        return -1;\n    }\n\n    Open_PDM_Filter_Init(&pdm_mic.filter);\n\n    pio_sm_set_enabled(\n        pdm_mic.config.pio,\n        pdm_mic.config.pio_sm,\n        true\n    );\n\n    pdm_mic.raw_buffer_write_index = 0;\n    pdm_mic.raw_buffer_read_index = 0;\n\n    dma_channel_transfer_to_buffer_now(\n        pdm_mic.dma_channel,\n        pdm_mic.raw_buffer[0],\n        pdm_mic.raw_buffer_size\n    );\n\n    pio_sm_set_enabled(\n        pdm_mic.config.pio,\n        pdm_mic.config.pio_sm,\n        true\n    );\n}\n\nvoid pdm_microphone_stop() {\n    pio_sm_set_enabled(\n        pdm_mic.config.pio,\n        pdm_mic.config.pio_sm,\n        false\n    );\n\n    dma_channel_abort(pdm_mic.dma_channel);\n\n    if (pdm_mic.dma_irq == DMA_IRQ_0) {\n        dma_channel_set_irq0_enabled(pdm_mic.dma_channel, false);\n    } else if (pdm_mic.dma_irq == DMA_IRQ_1) {\n        dma_channel_set_irq1_enabled(pdm_mic.dma_channel, false);\n    }\n\n    irq_set_enabled(pdm_mic.dma_irq, false);\n}\n\nstatic void pdm_dma_handler() {\n    // clear IRQ\n    if (pdm_mic.dma_irq == DMA_IRQ_0) {\n        dma_hw->ints0 = (1u << pdm_mic.dma_channel);\n    } else if (pdm_mic.dma_irq == DMA_IRQ_1) {\n        dma_hw->ints1 = (1u << pdm_mic.dma_channel);\n    }\n\n    // get the current buffer index\n    pdm_mic.raw_buffer_read_index = pdm_mic.raw_buffer_write_index;\n\n    // get the next capture index to send the dma to start\n    pdm_mic.raw_buffer_write_index = (pdm_mic.raw_buffer_write_index + 1) % PDM_RAW_BUFFER_COUNT;\n\n    // give the channel a new buffer to write to and re-trigger it\n    dma_channel_transfer_to_buffer_now(\n        pdm_mic.dma_channel,\n        pdm_mic.raw_buffer[pdm_mic.raw_buffer_write_index],\n        pdm_mic.raw_buffer_size\n    );\n\n    if (pdm_mic.samples_ready_handler) {\n        pdm_mic.samples_ready_handler();\n    }\n}\n\nvoid pdm_microphone_set_samples_ready_handler(pdm_samples_ready_handler_t handler) {\n    pdm_mic.samples_ready_handler = handler;\n}\n\nvoid pdm_microphone_set_filter_max_volume(uint8_t max_volume) {\n    pdm_mic.filter.MaxVolume = max_volume;\n}\n\nvoid pdm_microphone_set_filter_gain(uint8_t gain) {\n    pdm_mic.filter.Gain = gain;\n}\n\nvoid pdm_microphone_set_filter_volume(uint16_t volume) {\n    pdm_mic.filter_volume = volume;\n}\n\nint pdm_microphone_read(int16_t* buffer, size_t samples) {\n    int filter_stride = (pdm_mic.filter.Fs / 1000);\n    samples = (samples / filter_stride) * filter_stride;\n\n    if (samples > pdm_mic.config.sample_buffer_size) {\n        samples = pdm_mic.config.sample_buffer_size;\n    }\n\n    if (pdm_mic.raw_buffer_write_index == pdm_mic.raw_buffer_read_index) {\n        return 0;\n    }\n\n    uint8_t* in = pdm_mic.raw_buffer[pdm_mic.raw_buffer_read_index];\n    int16_t* out = buffer;\n\n    pdm_mic.raw_buffer_read_index++;\n\n    for (int i = 0; i < samples; i += filter_stride) {\n#if PDM_DECIMATION == 64\n        Open_PDM_Filter_64(in, out, pdm_mic.filter_volume, &pdm_mic.filter);\n#elif PDM_DECIMATION == 128\n        Open_PDM_Filter_128(in, out, pdm_mic.filter_volume, &pdm_mic.filter);\n#else\n        #error \"Unsupported PDM_DECIMATION value!\"\n#endif\n\n        in += filter_stride * (PDM_DECIMATION / 8);\n        out += filter_stride;\n    }\n\n    return samples;\n}\n"
  },
  {
    "path": "src/pdm_microphone.pio",
    "content": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n * \n */\n\n.program pdm_microphone_data\n.side_set 1\n.wrap_target\n    nop side 0\n    in pins, 1 side 0\n    push iffull noblock side 1\n    nop side 1\n.wrap\n\n% c-sdk {\n\nstatic inline void pdm_microphone_data_init(PIO pio, uint sm, uint offset, float clk_div, uint data_pin, uint clk_pin) {\n    pio_sm_set_consecutive_pindirs(pio, sm, data_pin, 1, false);\n    pio_sm_set_consecutive_pindirs(pio, sm, clk_pin, 1, true);\n\n    pio_sm_config c = pdm_microphone_data_program_get_default_config(offset);\n    \n    sm_config_set_sideset_pins(&c, clk_pin);\n    sm_config_set_in_pins(&c, data_pin);\n\n    pio_gpio_init(pio, clk_pin);\n    pio_gpio_init(pio, data_pin);\n    \n    sm_config_set_in_shift(&c, false, false, 8);\n    sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);\n\n    sm_config_set_clkdiv(&c, clk_div);\n    \n    pio_sm_init(pio, sm, offset, &c);\n}\n%}\n"
  }
]