Abfrage der Laufzeit entfernen und weiteres
Hallo,
bin jetzt etwas weiter mit dem Sound, allerdings funktioniert es noch nicht so richtig. Momentan sieht der Code folgendermaßen aus:
Ich vermute mal, dass das nicht optimal ist Ich habe das Problem, dass der Sound, wenn er nicht genau so lang bzw. kurz ist wie das Aufblinken, völlig falsch abgespielt wird. d.h. wenn ich den Sound nicht auf 0.1 Sekunden kürze, funktioniert die Wiedergabe nicht richtig. Und am Ende soll ein ANDERER Sound entsprechend des delays, also hier 5 Sekunden lang abgespielt werden.
bin jetzt etwas weiter mit dem Sound, allerdings funktioniert es noch nicht so richtig. Momentan sieht der Code folgendermaßen aus:
Code: Alles auswählen
import gpiozero
import time
import random
import pygame
from itertools import repeat, chain
pygame.init()
sound = pygame.mixer.Sound('/home/pi/Documents/test.wav')
def play_leds(leds):
on_time = 0.1 # Leuchtdauer der LED
delays = chain(repeat(on_time, 20 * len(leds) - 1), [5])
for delay in delays:
led = random.choice(leds)
led.on()
sound.play()
time.sleep(delay)
led.off()
def main():
leds = gpiozero.LEDBoard(17, 18, 27, 22, 23, 24, 25, 4, 12)
button = gpiozero.Button(16)
while True:
button.wait_for_press()
play_leds(leds)
if __name__ == '__main__':
main()
Moin Forum, kleines Update hierzu. Ich habe den Code erweitert, um insgesamt 5 verschiedene Sounds abzuspielen. Jetzt gibt es nur ein Problem. Obwohl die Sounds vorhanden sind, können sie nicht abgespielt werden. Hier mal der aktuelle Code:
Sobald das Skript gestartet wurde, und ich den Taster drücke, erscheint folgende Fehlermeldung:
pygame.error: Unable to open file '/home/pi/Documents/versuch5.mp3'
Wobei die Nummer hinter "versuch" immer anders ist, also z.B. versuch3, versuch2 usw. Die "glob" scheint also zu funktionieren, aber warum kann die MP3 nicht geöffnet werden?
Code: Alles auswählen
import gpiozero
import time
import random
import pygame.mixer
import glob
from itertools import repeat, chain
pygame.mixer.init()
soundfiles = glob.glob("/home/pi/Documents/*.mp3")
def play_leds(leds):
pygame.mixer.Sound(random.choice(soundfiles)).play()
on_time = 0.1 # Leuchtdauer der LED
delays = chain(repeat(on_time, 11 * len(leds) - 1), [5])
for delay in delays:
led = random.choice(leds)
led.on()
time.sleep(delay)
led.off()
def main():
leds = gpiozero.LEDBoard(17, 18, 27, 22, 23, 24, 25, 4, 12)
button = gpiozero.Button(16)
while True:
button.wait_for_press()
play_leds(leds)
if __name__ == '__main__':
main()
pygame.error: Unable to open file '/home/pi/Documents/versuch5.mp3'
Wobei die Nummer hinter "versuch" immer anders ist, also z.B. versuch3, versuch2 usw. Die "glob" scheint also zu funktionieren, aber warum kann die MP3 nicht geöffnet werden?
Update: Ich habe jetzt probeweise statt MP3 Dateien Wave Dateien verwendet (die selben MP3 in .wav) umgewandelt, und siehe da: Die Sounds werden tatsächlich OHNE Fehlermeldung abgespielt, auch zufällig. Aber warum klappt das mit MP3 nicht?
- __blackjack__
- User
- Beiträge: 13107
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Frank R.: Kann Pygame (unter Linux) überhaupt MP3? Ist ja ein nicht-freier Codec.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Habe eben mal nachgeschaut, pygame kann MP3 abspielen, aber der Code muss dann anders aussehen. Wenn man nur Sounds in Form von .ogg oder .wav Dateien abspielen möchte, sieht der Code so aus wie oben geschrieben. Wenn man aber MP3 Dateien abspielen will, muss es "pygame.mixer.music.play()" heißen, so habe ich das jedenfalls verstanden. Werde ich bei Gelegenheit mal testen.
Habe noch eine Frage: Ist es möglich, die Zufallswiedergabe der Sounds so zu coden, dass ein und derselbe Sound NICHT zweimal nacheinander abgespielt wird? Also z.B. test1.wav wird abgespielt, dann folgt zufällig test2.wav bis test5.wav, und erst nach diesem Durchlauf darf test1.wav wieder aufgerufen werden.
Klar ist das moeglich. Du musst eine Kopie der moeglichen Sounds machen, und bei jeder Auswahl (random.choice(copy_of_available_sounds)) den gewaehlten einfach entfernen. Sobald die Liste dann leer ist, erzeugst du wieder eine Kopie aller Moeglichkeiten.
So zB
Code: Alles auswählen
import time
import random
SONGS = ["a", "b", "c"]
def random_song_generator(songs):
while True:
selection = list(songs)
random.shuffle(selection)
yield from selection
def main():
rsg = random_song_generator(SONGS)
while True:
for _ in SONGS:
print(next(rsg))
print("-" * 20)
time.sleep(.2)
if __name__ == '__main__':
main()
Ok, aber wie binde ich diese Funktion in meinen Code ein? So wie ich das verstanden habe muss die Zeile "rsg = random_song_generator(SONGS)" , zusätzlich in "def main():" rein. Nur wie binde ich den Abschnitt "def random_song_generator(songs):" ein? Und was ist mit den pygame.mixer Angaben? Was kann/muss davon weg bzw. geändert werden?
Jetzt bin ich doch etwas verwirrt. play_leds hat doch bereits eine Zeile zur Soundwiedergabe, "pygame.mixer.Sound(random.choice(soundfiles)).play()", die aber so nicht mehr stimmen kann. Wenn ich das richtig verstanden habe, muss ja zwangsläufig "shuffle" verwendet werden, da nur so eine Wiederholung der selben Datei direkt nacheinander vermieden wird. Und welche while-true Schleife ist gemeint?
Du willst, dass ein Song nicht mehrfach gespielt wird, also muß die Funktion `play_leds` Wissen über ihren vorherigen Aufruf haben, das geht aber nicht. Daher muß dieses Wissen von außen kommen, über ein Argument.
Ich sehe in Deinem Code nur eine while-Schleife.
Ich sehe in Deinem Code nur eine while-Schleife.
Die Lösung tut übrigens nicht ganz das, was der Threadersteller gewünscht hat. Es kann noch immer dazu kommen, dass der selbe Song 2 Mal hintereinander gespielt wird. Nämlich dann, wenn er einmal einmal ans Ende der Liste gemischt wurde und bei dem nächsten Durchlauf an den Anfang. Bei dem Beispielcode mit 3 Elementen in der Liste kann man das sehr gut erkennen, weil es da relativ häufig auftritt. Natürlich wird die Wahrscheinlichkeit kleiner, je mehr Songs enthalten sind, trotzdem kann es vorkommen.
Bei Zufallswiedergaben von Liedern - oder zum Beispiel bei Fragen in einem Ratespiel - würde ich immer so vorgehen, dass ich mir die letzten x Songs / Fragen merke und eine neue ziehe, sollte die sich bereits in den letzten gespielten Elementen befinden.
Bei Zufallswiedergaben von Liedern - oder zum Beispiel bei Fragen in einem Ratespiel - würde ich immer so vorgehen, dass ich mir die letzten x Songs / Fragen merke und eine neue ziehe, sollte die sich bereits in den letzten gespielten Elementen befinden.
Code: Alles auswählen
import collections
import random
import time
SONGS = ["a", "b", "c", "d", "e", "f"]
class RandomSongGenerator():
def __init__(self, songs, no_repetition_before=None):
if no_repetition_before is None:
no_repetition_before = len(songs) // 2
if no_repetition_before >= len(songs):
raise Exception("Min. songs without repetition must be "
"less than all songs in list")
self.songs = songs
self.last_songs = collections.deque(maxlen=no_repetition_before)
def get_next_song(self):
while True:
current_songs = list(self.songs)
random.shuffle(current_songs)
while current_songs:
next_song = current_songs.pop(0)
if next_song not in self.last_songs:
self.last_songs.append(next_song)
yield next_song
else:
current_songs.append(next_song)
def main():
rsg = RandomSongGenerator(SONGS)
while True:
for _ in SONGS:
print(next(rsg.get_next_song()))
print("-" * 20)
time.sleep(.2)
if __name__ == '__main__':
main()
Ich habe den Generator mal entfernt, weil man sich den Zustand in der Instanz merken kann, und für dich der Aufruf mit next vielleicht etwas verwirrend ist.
Was genau ist denn jetzt noch unverständlich? Das Instanzieren einer Klasse mit Werten hast du doch bereits in deinem Code und das Aufrufen einer Funktion aus der Instanz doch auch.
Code: Alles auswählen
import collections
import random
import time
SONGS = ["a", "b", "c", "d", "e", "f"]
class RandomSongGenerator():
def __init__(self, songs, no_repetition_before=None):
if no_repetition_before is None:
no_repetition_before = len(songs) // 2
if no_repetition_before >= len(songs):
raise Exception("Min. songs without repetition must be "
"less than all songs in list")
self.songs = songs
self.last_songs = collections.deque(maxlen=no_repetition_before)
self.next_songs = []
def get_next_song(self):
if not self.next_songs:
self.next_songs = list(self.songs)
random.shuffle(self.next_songs)
while True:
next_song = self.next_songs.pop(0)
if next_song not in self.last_songs:
self.last_songs.append(next_song)
return next_song
else:
self.next_songs.append(next_song)
def main():
rsg = RandomSongGenerator(SONGS)
while True:
for _ in SONGS:
print(rsg.get_next_song())
print("-" * 20)
time.sleep(.2)
if __name__ == '__main__':
main()