diff --git a/libs/microphone/micbuffer.ts b/libs/microphone/micbuffer.ts new file mode 100644 index 00000000000..8a14403133a --- /dev/null +++ b/libs/microphone/micbuffer.ts @@ -0,0 +1,22 @@ +namespace input { + //% shim=microphone::_readyEvent + function _readyEvent(): number { + return 0xffff + } + + //% shim=microphone::_pull + function _pull(): Buffer { + return null + } + + /** + * (beta) Run callback whenever new raw data from microphone is available. + */ + export function onSoundData(cb: (data: Buffer) => void) { + control.onEvent(DAL.DEVICE_ID_NOTIFY, _readyEvent(), () => { + const buf = _pull() + if (buf) + cb(buf) + }) + } +} \ No newline at end of file diff --git a/libs/microphone/microphonehw.cpp b/libs/microphone/microphonehw.cpp index 5d0a9cdd434..b9b517849d8 100644 --- a/libs/microphone/microphonehw.cpp +++ b/libs/microphone/microphonehw.cpp @@ -4,46 +4,63 @@ #include "pxt.h" #if MICROBIT_CODAL + #include "LevelDetector.h" #include "LevelDetectorSPL.h" #include "DataStream.h" -#ifndef MIC_DEVICE -// STM? -class DummyDataSource : public codal::DataSource { - public: - DummyDataSource() {} -}; -class PanicPDM { +namespace pxt { + +class TeeStream : public DataSink, public DataSource { public: - uint8_t level; - DummyDataSource source; - codal::DataStream output; + int evid; + DataSource &upstream; + DataStream output; + ManagedBuffer buffer; + bool pxtPending; - PanicPDM(Pin &sd, Pin &sck) : output(source) { target_panic(PANIC_MICROPHONE_MISSING); } - void enable() {} - void disable() {} -}; -#define MIC_DEVICE PanicPDM -#endif + TeeStream(int evid, DataSource &src) : evid(evid), upstream(src), output(*this) { + pxtPending = false; + output.setBlocking(false); + upstream.connect(*this); + } -#ifndef MIC_INIT -#define MIC_INIT \ - : microphone(*LOOKUP_PIN(MIC_DATA), *LOOKUP_PIN(MIC_CLOCK)) \ - , level(microphone.output, 95.0, 75.0, 9, 52, DEVICE_ID_MICROPHONE) -#endif + Buffer pxtBuffer() { + if (!pxtPending) + return nullptr; + pxtPending = false; + return mkBuffer(buffer.getBytes(), buffer.length()); + } -#ifndef MIC_ENABLE -#define MIC_ENABLE microphone.enable() -#endif + virtual ManagedBuffer pull() override { return buffer; } + virtual int getFormat() override { return upstream.getFormat(); } + virtual int setFormat(int format) override { return upstream.setFormat(format); } -namespace pxt { + virtual int pullRequest() override { + buffer = upstream.pull(); + pxtPending = buffer.length() > 0; + output.pullRequest(); + Event(DEVICE_ID_NOTIFY, evid); + return DEVICE_OK; + } +}; class WMicrophone { public: - MIC_DEVICE microphone; + NRF52ADCChannel *microphone; + StreamNormalizer normalizer; + TeeStream tee; LevelDetectorSPL level; - WMicrophone() MIC_INIT { MIC_ENABLE; } + WMicrophone() + : microphone(uBit.adc.getChannel(uBit.io.microphone)), + normalizer(microphone->output, 1.0f, true, DATASTREAM_FORMAT_UNKNOWN, 10), + tee(allocateNotifyEvent(), normalizer.output), + level(tee.output, 75.0, 60.0, 9, 52, DEVICE_ID_MICROPHONE) { + uBit.io.runmic.setDigitalValue(1); + uBit.io.runmic.setHighDrive(true); + microphone->setGain(7, 0); + DMESG("microphone: %d Hz", 1000000 / uBit.adc.getSamplePeriod()); + } }; SINGLETON(WMicrophone); @@ -53,4 +70,59 @@ codal::LevelDetectorSPL *getMicrophoneLevel() { } } // namespace pxt -#endif \ No newline at end of file + +#endif + +namespace microphone { + +//% +int _readyEvent() { +#if MICROBIT_CODAL + return getWMicrophone()->tee.evid; +#else + target_panic(PANIC_VARIANT_NOT_SUPPORTED); + return 0; +#endif +} + +//% +Buffer _pull() { +#if MICROBIT_CODAL + return getWMicrophone()->tee.pxtBuffer(); +#else + target_panic(PANIC_VARIANT_NOT_SUPPORTED); + return nullptr; +#endif +} + +} // namespace microphone + +namespace input { + +/** + * (beta) Return microphone sampling period in microseconds. + */ +//% +int soundSamplingPeriod() { +#if MICROBIT_CODAL + return uBit.adc.getSamplePeriod(); +#else + target_panic(PANIC_VARIANT_NOT_SUPPORTED); + return 0; +#endif +} + +/** + * (beta) Set microphone sampling period in microseconds. Typical range 20-200. + */ +//% +void setSoundSamplingPeriod(int us) { +#if MICROBIT_CODAL + if (us != uBit.adc.getSamplePeriod()) + uBit.adc.setSamplePeriod(us); +#else + target_panic(PANIC_VARIANT_NOT_SUPPORTED); +#endif +} + +} // namespace input diff --git a/libs/microphone/pxt.json b/libs/microphone/pxt.json index abfae4823a5..ace0677311c 100644 --- a/libs/microphone/pxt.json +++ b/libs/microphone/pxt.json @@ -1,6 +1,15 @@ { "additionalFilePath": "../../node_modules/pxt-common-packages/libs/microphone", + "files": [ + "README.md", + "microphone.cpp", + "microphonehw.cpp", + "micbuffer.ts", + "enums.d.ts", + "shims.d.ts", + "targetoverrides.ts" + ], "dependencies": { "core": "file:../core" } -} +} \ No newline at end of file diff --git a/libs/microphone/shims.d.ts b/libs/microphone/shims.d.ts index d189372914e..038d746770e 100644 --- a/libs/microphone/shims.d.ts +++ b/libs/microphone/shims.d.ts @@ -33,5 +33,19 @@ declare namespace input { //% group="micro:bit v2" threshold.defl=128 shim=input::setSoundThreshold function setSoundThreshold(sound: SoundThreshold, threshold?: int32): void; } +declare namespace input { + + /** + * Return microphone sampling period in microseconds. + */ + //% shim=input::soundSamplingPeriod + function soundSamplingPeriod(): int32; + + /** + * Set microphone sampling period in microseconds. Typical range 20-200. + */ + //% shim=input::setSoundSamplingPeriod + function setSoundSamplingPeriod(us: int32): void; +} // Auto-generated. Do not edit. Really.