Exemplo n.º 1
0
class WinampApplication(displayio.Group):
    """
    WinampApplication

    Helper class that manages song playback and UI components.

    :param playlist_file: json file containing the playlist of songs
    :param skin_image: BMP image file for skin background
    :param skin_config_file: json file containing color values
    :param pyportal_titano: boolean value. True if using Titano, False otherwise.
    """

    STATE_PLAYING = 0
    STATE_PAUSED = 1

    # pylint: disable=too-many-statements,too-many-branches
    def __init__(
        self,
        playlist_file="playlist.json",
        skin_image="/base_240x320.bmp",
        skin_config_file="base_config.json",
        pyportal_titano=False,
    ):
        self.SKIN_IMAGE = skin_image
        self.SKIN_CONFIG_FILE = skin_config_file
        self.PLAYLIST_FILE = playlist_file

        # read the skin config data into variable
        f = open(self.SKIN_CONFIG_FILE, "r")
        self.CONFIG_DATA = json.loads(f.read())
        f.close()

        if self.PLAYLIST_FILE:
            try:
                # read the playlist data into variable
                f = open(self.PLAYLIST_FILE, "r")
                self.PLAYLIST = json.loads(f.read())
                f.close()
            except OSError:
                # file not found
                self.auto_find_tracks()
            except ValueError:
                # json parse error
                self.auto_find_tracks()
        else:
            # playlist file argument was None
            self.auto_find_tracks()

        if self.PLAYLIST:
            try:
                if len(self.PLAYLIST["playlist"]["files"]) == 0:
                    # valid playlist json data, but no tracks
                    self.auto_find_tracks()
            except KeyError:
                self.auto_find_tracks()

        # initialize clock display
        self.clock_display = ClockDisplay(
            text_color=self.CONFIG_DATA["time_color"])
        if not pyportal_titano:
            # standard PyPortal and pynt clock display location
            # and playlist display parameters
            self.clock_display.x = 44
            self.clock_display.y = 22
            _max_playlist_display_chars = 30
            _rows = 3
        else:
            # PyPortal Titano clock display location
            # and playlist display parameters
            self.clock_display.x = 65
            self.clock_display.y = 37
            _max_playlist_display_chars = 42
            _rows = 4

        # initialize playlist display
        self.playlist_display = PlaylistDisplay(
            text_color=self.CONFIG_DATA["text_color"],
            max_chars=_max_playlist_display_chars,
            rows=_rows,
        )
        if not pyportal_titano:
            # standard PyPortal and pynt playlist display location
            self.playlist_display.x = 13
            self.playlist_display.y = 234
        else:
            # PyPortal Titano playlist display location
            self.playlist_display.x = 20
            self.playlist_display.y = 354

        # set playlist into playlist display
        self.playlist_display.from_files_list(
            self.PLAYLIST["playlist"]["files"])
        self.playlist_display.current_track_number = 1

        # get name of current song
        self.current_song_file_name = self.PLAYLIST["playlist"]["files"][
            self.playlist_display.current_track_number - 1]

        if not pyportal_titano:
            # standard PyPortal and pynt max characters for track title
            _max_chars = 22
        else:
            # PyPortal Titano max characters for track title
            _max_chars = 29
        # initialize ScrollingLabel for track name
        self.current_song_lbl = scrolling_label.ScrollingLabel(
            terminalio.FONT,
            text=self.playlist_display.current_track_title,
            color=self.CONFIG_DATA["text_color"],
            max_characters=_max_chars,
        )
        self.current_song_lbl.anchor_point = (0, 0)
        if not pyportal_titano:
            # standard PyPortal and pynt track title location
            self.current_song_lbl.anchored_position = (98, 19)
        else:
            # PyPortal Titano track title location
            self.current_song_lbl.anchored_position = (130, 33)

        # Setup the skin image file as the bitmap data source
        self.background_bitmap = displayio.OnDiskBitmap(self.SKIN_IMAGE)

        # Create a TileGrid to hold the bitmap
        self.background_tilegrid = displayio.TileGrid(
            self.background_bitmap,
            pixel_shader=self.background_bitmap.pixel_shader)

        # initialize parent displayio.Group
        super().__init__()

        # Add the TileGrid to the Group
        self.append(self.background_tilegrid)

        # add other UI componenets
        self.append(self.current_song_lbl)
        self.append(self.clock_display)
        self.append(self.playlist_display)

        # Start playing first track
        self.current_song_file = open(self.current_song_file_name, "rb")
        self.decoder = MP3Decoder(self.current_song_file)
        self.audio = AudioOut(board.SPEAKER)
        self.audio.play(self.decoder)

        self.CURRENT_STATE = self.STATE_PLAYING

        # behavior variables.
        self._start_time = time.monotonic()
        self._cur_time = time.monotonic()
        self._pause_time = None
        self._pause_elapsed = 0
        self._prev_time = None
        self._seconds_elapsed = 0
        self._last_increment_time = 0

    def auto_find_tracks(self):
        """
        Initialize the song_list by searching for all MP3's within
        two layers of directories on the SDCard.

        e.g. It will find all of:
        /sd/Amazing Song.mp3
        /sd/[artist_name]/Amazing Song.mp3
        /sd/[artist_name]/[album_name]/Amazing Song.mp3

        but won't find:
        /sd/my_music/[artist_name]/[album_name]/Amazing Song.mp3

        :return: None
        """
        # list that holds all files in the root of SDCard
        _root_sd_all_files = os.listdir("/sd/")

        # list that will hold all directories in the root of the SDCard.
        _root_sd_dirs = []

        # list that will hold all subdirectories inside of root level directories
        _second_level_dirs = []

        # list that will hold all MP3 file songs that we find
        _song_list = []

        # loop over all files found on SDCard
        for _file in _root_sd_all_files:
            try:
                # Check if the current file is a directory
                os.listdir("/sd/{}".format(_file))

                # add it to a list to look at later
                _root_sd_dirs.append(_file)
            except OSError:
                # current file was not a directory, nothing to do.
                pass

            # if current file is an MP3 file
            if _file.endswith(".mp3"):
                # we found an MP3 file, add it to the list that will become our playlist
                _song_list.append("/sd/{}".format(_file))

        # loop over root level directories
        for _dir in _root_sd_dirs:
            # loop over all files inside of root level directory
            for _file in os.listdir("/sd/{}".format(_dir)):

                # check if current file is a directory
                try:
                    # if it is a directory, loop over all files inside of it
                    for _inner_file in os.listdir("/sd/{}/{}".format(
                            _dir, _file)):
                        # check if inner file is an MP3
                        if _inner_file.endswith(".mp3"):
                            # we found an MP3 file, add it to the list that will become our playlist
                            _song_list.append("/sd/{}/{}/{}".format(
                                _dir, _file, _inner_file))
                except OSError:
                    # current file is not a directory
                    pass
                # if the current file is an MP3 file
                if _file.endswith(".mp3"):
                    # we found an MP3 file, add it to the list that will become our playlist
                    _song_list.append("/sd/{}/{}".format(_dir, _file))

        # format the songs we found into the PLAYLIST data structure
        self.PLAYLIST = {"playlist": {"files": _song_list}}

        # print message to user letting them know we auto-generated the playlist
        print("Auto Generated Playlist from MP3's found on SDCard:")
        print(json.dumps(self.PLAYLIST))

    def update(self):
        """
        Must be called each iteration from the main loop.
        Responsible for updating all sub UI components and
        managing song playback

        :return: None
        """
        self._cur_time = time.monotonic()
        if self.CURRENT_STATE == self.STATE_PLAYING:
            # if it's time to increase the time on the ClockDisplay
            if self._cur_time >= self._last_increment_time + 1:
                # increase ClockDisplay by 1 second
                self._seconds_elapsed += 1
                self._last_increment_time = self._cur_time
                self.clock_display.seconds = int(self._seconds_elapsed)

        # update the track label (scrolling)
        self.current_song_lbl.update()

        if self.CURRENT_STATE == self.STATE_PLAYING:
            # if we are supposed to be playing but aren't
            # it means the track ended.
            if not self.audio.playing:
                # start the next track
                self.next_track()

        # store time for comparison later
        self._prev_time = self._cur_time

    def play_current_track(self):
        """
        Update the track label and begin playing the song for current
        track in the playlist.

        :return: None
        """
        # set the track title
        self.current_song_lbl.full_text = self.playlist_display.current_track_title

        # save start time in a variable
        self._start_time = self._cur_time

        # if previous song is still playing
        if self.audio.playing:
            # stop playing
            self.audio.stop()

        # close previous song file
        self.current_song_file.close()

        # open new song file
        self.current_song_file_name = self.PLAYLIST["playlist"]["files"][
            self.playlist_display.current_track_number - 1]
        self.current_song_file = open(self.current_song_file_name, "rb")
        self.decoder.file = self.current_song_file

        # play new song file
        self.audio.play(self.decoder)

        # if user paused the playback
        if self.CURRENT_STATE == self.STATE_PAUSED:
            # pause so it's loaded, and ready to resume
            self.audio.pause()

    def next_track(self):
        """
        Advance to the next track.
        :return: None
        """
        # reset ClockDisplay to 0
        self._seconds_elapsed = 0
        self.clock_display.seconds = int(self._seconds_elapsed)

        # increment current track number
        self.playlist_display.current_track_number += 1

        try:
            # start playing track
            self.play_current_track()
        except OSError as e:
            # file not found
            print("Error playing: {}".format(self.current_song_file_name))
            print(e)
            self.next_track()
            return

    def previous_track(self):
        """
        Go back to previous track.

        :return: None
        """
        # reset ClockDisplay to 0
        self._seconds_elapsed = 0
        self.clock_display.seconds = int(self._seconds_elapsed)

        # decrement current track number
        self.playlist_display.current_track_number -= 1

        try:
            # start playing track
            self.play_current_track()
        except OSError as e:
            # file not found
            print("Error playing: {}".format(self.current_song_file_name))
            print(e)
            self.previous_track()
            return

    def pause(self):
        """
        Stop playing song and wait until resume function.

        :return: None
        """
        if self.audio.playing:
            self.audio.pause()
        self.CURRENT_STATE = self.STATE_PAUSED

    def resume(self):
        """
        Resume playing song after having been paused.

        :return: None
        """
        self._last_increment_time = self._cur_time
        if self.audio.paused:
            self.audio.resume()
        self.CURRENT_STATE = self.STATE_PLAYING
    try:
        from audiopwmio import PWMAudioOut as AudioOut
    except ImportError:
        pass  # not always supported by every board!

FREQUENCY = 440  # 440 Hz middle 'A'
SAMPLERATE = 8000  # 8000 samples/second, recommended!

# Generate one period of sine wav.
length = SAMPLERATE // FREQUENCY
sine_wave = array.array("H", [0] * length)
for i in range(length):
    sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2**15) + 2**15)

# Enable the speaker
speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
speaker_enable.direction = digitalio.Direction.OUTPUT
speaker_enable.value = True

audio = AudioOut(board.SPEAKER)
sine_wave_sample = RawSample(sine_wave)

# A single sine wave sample is hundredths of a second long. If you set loop=False, it will play
# a single instance of the sample (a quick burst of sound) and then silence for the rest of the
# duration of the time.sleep(). If loop=True, it will play the single instance of the sample
# continuously for the duration of the time.sleep().
audio.play(sine_wave_sample,
           loop=True)  # Play the single sine_wave sample continuously...
time.sleep(1)  # for the duration of the sleep (in seconds)
audio.stop()  # and then stop.
Exemplo n.º 3
0
                new_mode = True
                switch_timer = 0

    if mode is "waiting":
        if new_mode is True:
            display.brightness = 0
            if USE_AUDIO is True:
                audio.stop()
            display.refresh()
            new_mode = False

    if mode is "laughing":
        if new_mode is True:
            display.brightness = 1.0
            if USE_AUDIO is True:
                audio.play(decoder, loop=True)
            display.refresh()
            new_mode = False

        # Make the skull laugh open/close once
        if USE_ANIMATION is True:
            if (time.monotonic() - last_frame_time) > LAUGHING_SPEED:
                current_frame = (current_frame + 1) % 4

                if current_frame is 0:
                    group.remove(skull_middle)
                    group.append(skull_close)
                elif current_frame is 1:
                    group.remove(skull_close)
                    group.append(skull_middle)
                elif current_frame is 2:
Exemplo n.º 4
0
            led.value = False
            time.sleep(0.1)
            led.value = True
            time.sleep(0.1)
            led.value = False

    while ble.connected or not ble_enabled.value:
        if not central.value:
            led.value = True
            print("Running")
            while True:
                i = random.randint(0, upper)
                if not buttons[i].value:
                    break

            audio.play(wave)
            if i == 0:
                print("Button 1")
                pixels.fill((0, 0, 255))
                if ble_enabled.value:
                    kl.write("Button 1")
            elif i == 1:
                print("Button 2")
                pixels.fill((0, 255, 0))
                if ble_enabled.value:
                    kl.write("Button 2")
            elif i == 2:
                print("Button 3")
                pixels.fill((255, 255, 255))
                if ble_enabled.value:
                    kl.write("Button 3")
Exemplo n.º 5
0

# make a sawtooth wave between +/- each value in volumes
# phase shifted so it starts and ends near midpoint
vol = 32767
sample_len = 10
waveraw = array.array("H", [
    midpoint +
    round(vol * sawtooth((idx + 0.5) / sample_len * twopi + math.pi))
    for idx in range(sample_len)
])

beep = RawSample(waveraw, sample_rate=sample_len * A4refhz)

# play something to get things inside audio libraries initialised
audio.play(beep, loop=True)
time.sleep(0.1)
audio.stop()
audio.play(beep)

# brightness 1.0 saves memory by removing need for a second buffer
# 10 is number of NeoPixels on CPX/CPB
numpixels = 10
pixels = neopixel.NeoPixel(board.NEOPIXEL, numpixels, brightness=1.0)

# B is right (usb at top)
button_right = digitalio.DigitalInOut(board.BUTTON_B)
button_right.switch_to_input(pull=digitalio.Pull.DOWN)


def wait_finger_off_and_random_delay():
Exemplo n.º 6
0
        from audiopwmio import PWMAudioOut as AudioOut
    except ImportError:
        pass  # not always supported by every board!

# The mp3 files on the sd card will be played in alphabetical order
mp3files = sorted("/sd/" + filename for filename in os.listdir("/sd")
                  if filename.lower().endswith("mp3"))

voodoo = [1, 2, 3]

# You have to specify some mp3 file when creating the decoder
mp3 = open(mp3files[0], "rb")
decoder = MP3Decoder(mp3)
audio = AudioOut(board.A0, right_channel=board.A1)

speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
speaker_enable.switch_to_output(True)

while True:
    for filename in mp3files:
        print("Playing", filename)

        # Updating the .file property of the existing decoder
        # helps avoid running out of memory (MemoryError exception)
        decoder.file = open(filename, "rb")
        audio.play(decoder)

        # This allows you to do other things while the audio plays!
        while audio.playing:
            time.sleep(1)
Exemplo n.º 7
0
              samples_signed=True)

wav_files = ("scanner-left-16k.wav", "scanner-right-16k.wav")

### Use same pins which would be used on a Feather M4 with real DACs
AUDIO_PIN_L = board.A0
AUDIO_PIN_R = board.A1
audio_out = AudioOut(AUDIO_PIN_L, right_channel=AUDIO_PIN_R)

wav_fh = [open(fn, "rb") for fn in wav_files]
wavs = [WaveFile(fh) for fh in wav_fh]

### Voice 0 behaves strangely
### https://github.com/adafruit/circuitpython/issues/3210
mixer.voice[0].level = 0.0
mixer.voice[1].level = 1.0
audio_out.play(mixer)

audio = mixer.voice[1]

uart = busio.UART(board.TX, board.RX, baudrate=115200)
rx_bytes = bytearray(1)

while True:
    if uart.readinto(rx_bytes) and rx_bytes[0]:
        try:
            wav_obj = wavs[rx_bytes[0] - 1]
            audio.play(wav_obj)
        except IndexError:
            print("No wav file for:", rx_bytes[0])
Exemplo n.º 8
0
except ImportError:
    from audioio import RawSample

try:
    from audioio import AudioOut
except ImportError:
    try:
        from audiopwmio import PWMAudioOut as AudioOut
    except ImportError:
        pass  # not always supported by every board!

button = digitalio.DigitalInOut(board.A1)
button.switch_to_input(pull=digitalio.Pull.UP)

tone_volume = 0.1  # Increase this to increase the volume of the tone.
frequency = 440  # Set this to the Hz of the tone you want to generate.
length = 8000 // frequency
sine_wave = array.array("H", [0] * length)
for i in range(length):
    sine_wave[i] = int(
        (1 + math.sin(math.pi * 2 * i / length)) * tone_volume * (2**15 - 1))

audio = AudioOut(board.A0)
sine_wave_sample = RawSample(sine_wave)

while True:
    if not button.value:
        audio.play(sine_wave_sample, loop=True)
        time.sleep(1)
        audio.stop()
                   pull=True)
event = keypad.Event()  # Single key event for re-use
keys.events.clear()

# Load all the WAV files from the pin_to_wave list, and one more for the
# mode selector, sharing a common buffer since only one is used at a time.
# Also, play a startup sound.
audio_buf = bytearray(1024)
waves = [
    WaveFile(open(sound_folder + "/" + x[1], "rb"), audio_buf)
    for x in pin_to_wave
]
active_sound = 0  # Index of waves[] to play when trigger is pressed
selector_wave = WaveFile(open(sound_folder + "/" + "click.wav", "rb"),
                         audio_buf)
audio.play(WaveFile(open(sound_folder + "/" + "startup.wav", "rb"), audio_buf))

# MAIN LOOP --------- repeat forever ----

while True:

    # Process the mode selector slider, check if moved into a new position.
    # This is currently just used to make click noises, it doesn't actually
    # change any "mode" in the operation of the prop, but it could if we
    # really wanted, with additional code (e.g. different sound sets).
    selector_pos = analog_in.value
    if not bounds[0] < selector_pos < bounds[1]:  # Moved out of mode range?
        # New mode, new bounds. +/-512 adds a little hysteresis to selection.
        mode = (selector_pos * (num_modes - 1) + 32768) // 65536
        bounds = (
            (mode * 65535 - 32768) // (num_modes - 1) - 512,
            cur_note = "{}{}".format(note_letter, octave)
            # add wave file to dictionary
            key = "{}{}".format(wave_type, cur_note)
            notes[key] = WaveFile(
                open("notes/{}/{}.wav".format(wave_type, cur_note), "rb"))

# main audio object
audio = AudioOut(left_channel=board.A0, right_channel=board.A1)
# mixer to allow pylyphonic playback
mixer = Mixer(voice_count=8,
              sample_rate=8000,
              channel_count=2,
              bits_per_sample=16,
              samples_signed=True)

audio.play(mixer)

# turn on the rainbow lights
for i, color in enumerate(colors):
    trellis.pixels[i, 0] = color
    trellis.pixels[i, 1] = color
    trellis.pixels[i, 2] = color

# list of keys pressed on the previous iteration
prev_pressed = []

# voice recycling variables
available_voices = [1, 2, 3, 4, 5, 6, 7]
# key to voice dictionary e.g. {... (1,2):4, (1,3):3,  ...}
used_voices = {}
try:
    from audioio import AudioOut
except ImportError:
    try:
        from audiopwmio import PWMAudioOut as AudioOut
    except ImportError:
        pass  # not always supported by every board!

FREQUENCY = 440  # 440 Hz middle 'A'
SAMPLERATE = 8000  # 8000 samples/second, recommended!

# Generate one period of sine wav.
length = SAMPLERATE // FREQUENCY
sine_wave = array.array("H", [0] * length)
for i in range(length):
    sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2**15) + 2**15)

# Enable the speaker
speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
speaker_enable.direction = digitalio.Direction.OUTPUT
speaker_enable.value = True

audio = AudioOut(board.SPEAKER)
sine_wave_sample = RawSample(sine_wave)

audio.play(sine_wave_sample,
           loop=True)  # Keep playing the sample over and over
time.sleep(1)  # until...
audio.stop()  # We tell the board to stop
Exemplo n.º 12
0
        channel = 2
    elif (scale == 3):
        noteIndex = notesG[note]
        channel = 3
    else:
        print("Invalid scale, must be 0-3")

    formattedNote = str(noteIndex)

    note = WaveFile(
        open(instrument + "/Marker #" + formattedNote + ".wav", "rb"))

    mixer.play(note, voice=channel)


a.play(mixer)
#print("audio setup done")
note = 0
'''
while True:
    print("play " + str(note))
    playNote("G", note);
    
    note += 1;
  
    if(note >= 9):
        note = 0;
        '''

i2c = I2C(SCL, SDA, frequency=100000, timeout=20000)
Exemplo n.º 13
0
try:
    from audiocore import WaveFile
except ImportError:
    from audioio import WaveFile

#check if the audio out is digital-to-analog, true analog voltage out,  or Pulse-Width-Modulated, pseudo-analog binary voltage out.
try:
    from audioio import AudioOut
except ImportError:
    try:
        from audiopwmio import PWMAudioOut as AudioOut
    except ImportError:
        print("NO audio out possible")
        pass  # not always supported by every board!

# CPX requires:
speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
speaker_enable.switch_to_output(value=True)

#more setup: open the file, load it into memory
wave_file = open("yikes.wav", "rb")
wave = WaveFile(wave_file)
audio = AudioOut(board.A0)

#loop
#a loop is too annoying to use with an audio file.
audio.play(wave) # start playing, non-blocking
# wait till finished
while audio.playing:
        pass
Exemplo n.º 14
0
stereo_dac = AudioOut(board.A0, right_channel=board.A1, quiescent_value=0)

frames = [locals()[f"frame_{i}"] for i in range(18)]
buffers = []
for c, points in enumerate(frames):
    print(f"Building frame {c}")
    print(f"Number of array cells {((len(points) - 1) * samples) * 2}")
    print(f"Num lines {len(points) - 1}")

    line_array = array("H", [0] * ((len(points) - 1) * samples * 2))

    i = 0
    for pt1, pt2 in pairwise(points):
        pt1 = int(pt1[0] * 65535 / 400), int(pt1[1] * 65535 / 400)
        pt2 = int(pt2[0] * 65535 / 400), int(pt2[1] * 65535 / 400)
        temp = sum(gen_line(pt1, pt2), ())

        for val in temp:
            line_array[i] = val
            i += 1
    buffers.append(
        RawSample(line_array, channel_count=2, sample_rate=1_000_000))

i = 0
while True:
    stereo_dac.play(buffers[i], loop=True)
    sleep(0.08)
    stereo_dac.stop()
    i = (i + 1) % len(buffers)