|
| 1 | +"""Light theremin example using APDS9960 and the board buzzer. |
| 2 | +
|
| 3 | +Changes the buzzer pitch based on ambient light level. |
| 4 | +Move your hand up and down over the sensor to play it! |
| 5 | +""" |
| 6 | + |
| 7 | +from time import sleep_ms |
| 8 | + |
| 9 | +from apds9960 import uAPDS9960 as APDS9960 |
| 10 | +from machine import I2C, Pin |
| 11 | +from pyb import Timer |
| 12 | + |
| 13 | +# Calibration Constants |
| 14 | +# You may need to adjust MAX_LIGHT depending on your room's ambient lighting |
| 15 | +MIN_LIGHT = 45 |
| 16 | +MAX_LIGHT = 920 |
| 17 | + |
| 18 | +# Musical Frequency Range (Hz) - Auto-Tuned Pentatonic Scale |
| 19 | +PENTATONIC_NOTES = [ |
| 20 | + 131, 147, 165, 196, 220, # Octave 3 |
| 21 | + 262, 294, 330, 392, 440, # Octave 4 |
| 22 | + 523, 587, 659, 784, 880 # Octave 5 |
| 23 | +] |
| 24 | +TOTAL_NOTES = len(PENTATONIC_NOTES) |
| 25 | + |
| 26 | +# Hardware Initialization |
| 27 | +i2c = I2C(1) |
| 28 | +apds = APDS9960(i2c) |
| 29 | +apds.enable_light_sensor() |
| 30 | + |
| 31 | +# Hardware PWM on SPEAKER pin |
| 32 | +buzzer_tim = Timer(1, freq=1000) |
| 33 | +buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER")) |
| 34 | +buzzer_ch.pulse_width_percent(0) |
| 35 | + |
| 36 | +print("=======================") |
| 37 | +print(" Light Theremin ") |
| 38 | +print("=======================") |
| 39 | +print("Move your hand over the sensor.") |
| 40 | +print("Cover it completely to mute.") |
| 41 | +print("Press Ctrl+C to exit.") |
| 42 | + |
| 43 | +try: |
| 44 | + while True: |
| 45 | + light_level = apds.ambient_light() |
| 46 | + |
| 47 | + if light_level < MIN_LIGHT: |
| 48 | + buzzer_ch.pulse_width_percent(0) |
| 49 | + else: |
| 50 | + # Clamp the light reading to avoid exceeding the max frequency |
| 51 | + clamped_light = min(light_level, MAX_LIGHT) |
| 52 | + |
| 53 | + # Map the light range to an index in our note array (0 to 14) |
| 54 | + note_index = (clamped_light - MIN_LIGHT) * (TOTAL_NOTES - 1) // (MAX_LIGHT - MIN_LIGHT) |
| 55 | + print("Light Level: {}, Note Index: {}".format(light_level, note_index)) |
| 56 | + |
| 57 | + # Fetch the perfect harmonic frequency |
| 58 | + freq = PENTATONIC_NOTES[note_index] |
| 59 | + |
| 60 | + # Update the buzzer tone |
| 61 | + buzzer_tim.freq(freq) |
| 62 | + buzzer_ch.pulse_width_percent(50) |
| 63 | + |
| 64 | + sleep_ms(20) |
| 65 | + |
| 66 | +except KeyboardInterrupt: |
| 67 | + print("\nTheremin stopped.") |
| 68 | +finally: |
| 69 | + buzzer_ch.pulse_width_percent(0) |
0 commit comments