Unwanted audio delay in Corona SDK - audio

I am currently making an extremely simple app where when an image is tapped, a sound plays and some text records the amount of clicks. However, I noticed some significant delay in the audio, where it would take half a second for the sound to play after the image is clicked. Does anyone have any ideas on why this might be the case?
local function btnTouch(event)
if event.phase == "began" then
media.playSound( "btnSnd.mp3" )
score = score + 1
btnText.text = score
return true
end
end
--code
imageBtn:addEventListener("touch", btnTouch)

The answer is probably that the sound needs to be loaded. Try and switch it to audio instead and preload it. Try and see if this gives you the desired result:
local buttonSendAudio = audio.loadSound( "btnSnd.mp3")
local function btnTouch(event)
if event.phase == "began" then
audio.play( buttonSendAudio )
score = score + 1
btnText.text = score
return true
end
end
--code
imageBtn:addEventListener("touch", btnTouch)
https://docs.coronalabs.com/daily/guide/media/audioSystem/index.html

Worth checking if sound has some silence stored in mp3.
Open it with any audio editor, see sound's waveform.

Related

Python SpeechRecognition Snowboy Integration Seems to be Broken

I am working at building a personal assistant in Python. It appears that the Python's SpeechRecognition library has built-in Snowboy recognition, but it appears to be broken. Here is my code. (Note that the problem is that the listen() function never returns).
import speech_recognition as sr
from SnowboyDependencies import snowboydecoder
def get_text():
with sr.Microphone(sample_rate = 48000) as source:
audio = r.listen(source, snowboy_configuration=("SnowboyDependencies", {hotword_path})) #PROBLEM HERE
try:
text = r.recognize_google(audio).lower()
except:
text = none
print("err")
return text
I did some digging in SpeechRecognition and I have found where the problem exists, but I am not sure how to fix it because I am not very familiar with the intricacies of the library. The issue is that sr.listen never returns. It appears the the Snowboy hotword detection is 100% working, because the program progresses past that point when I say my hotword. Here is the source code. I have added my own comments to try to describe the issue further. I added three comments and all of them are enclosed in a multi-line box of #s.
def listen(self, source, timeout=None, phrase_time_limit=None, snowboy_configuration=None):
"""
Records a single phrase from ``source`` (an ``AudioSource`` instance) into an ``AudioData`` instance, which it returns.
This is done by waiting until the audio has an energy above ``recognizer_instance.energy_threshold`` (the user has started speaking), and then recording until it encounters ``recognizer_instance.pause_threshold`` seconds of non-speaking or there is no more audio input. The ending silence is not included.
The ``timeout`` parameter is the maximum number of seconds that this will wait for a phrase to start before giving up and throwing an ``speech_recognition.WaitTimeoutError`` exception. If ``timeout`` is ``None``, there will be no wait timeout.
The ``phrase_time_limit`` parameter is the maximum number of seconds that this will allow a phrase to continue before stopping and returning the part of the phrase processed before the time limit was reached. The resulting audio will be the phrase cut off at the time limit. If ``phrase_timeout`` is ``None``, there will be no phrase time limit.
The ``snowboy_configuration`` parameter allows integration with `Snowboy <https://snowboy.kitt.ai/>`__, an offline, high-accuracy, power-efficient hotword recognition engine. When used, this function will pause until Snowboy detects a hotword, after which it will unpause. This parameter should either be ``None`` to turn off Snowboy support, or a tuple of the form ``(SNOWBOY_LOCATION, LIST_OF_HOT_WORD_FILES)``, where ``SNOWBOY_LOCATION`` is the path to the Snowboy root directory, and ``LIST_OF_HOT_WORD_FILES`` is a list of paths to Snowboy hotword configuration files (`*.pmdl` or `*.umdl` format).
This operation will always complete within ``timeout + phrase_timeout`` seconds if both are numbers, either by returning the audio data, or by raising a ``speech_recognition.WaitTimeoutError`` exception.
"""
assert isinstance(source, AudioSource), "Source must be an audio source"
assert source.stream is not None, "Audio source must be entered before listening, see documentation for ``AudioSource``; are you using ``source`` outside of a ``with`` statement?"
assert self.pause_threshold >= self.non_speaking_duration >= 0
if snowboy_configuration is not None:
assert os.path.isfile(os.path.join(snowboy_configuration[0], "snowboydetect.py")), "``snowboy_configuration[0]`` must be a Snowboy root directory containing ``snowboydetect.py``"
for hot_word_file in snowboy_configuration[1]:
assert os.path.isfile(hot_word_file), "``snowboy_configuration[1]`` must be a list of Snowboy hot word configuration files"
seconds_per_buffer = float(source.CHUNK) / source.SAMPLE_RATE
pause_buffer_count = int(math.ceil(self.pause_threshold / seconds_per_buffer)) # number of buffers of non-speaking audio during a phrase, before the phrase should be considered complete
phrase_buffer_count = int(math.ceil(self.phrase_threshold / seconds_per_buffer)) # minimum number of buffers of speaking audio before we consider the speaking audio a phrase
non_speaking_buffer_count = int(math.ceil(self.non_speaking_duration / seconds_per_buffer)) # maximum number of buffers of non-speaking audio to retain before and after a phrase
# read audio input for phrases until there is a phrase that is long enough
elapsed_time = 0 # number of seconds of audio read
buffer = b"" # an empty buffer means that the stream has ended and there is no data left to read
##################################################
######THE ISSIE IS THAT THIS LOOP NEVER EXITS#####
##################################################
while True:
frames = collections.deque()
if snowboy_configuration is None:
# store audio input until the phrase starts
while True:
# handle waiting too long for phrase by raising an exception
elapsed_time += seconds_per_buffer
if timeout and elapsed_time > timeout:
raise WaitTimeoutError("listening timed out while waiting for phrase to start")
buffer = source.stream.read(source.CHUNK)
if len(buffer) == 0: break # reached end of the stream
frames.append(buffer)
if len(frames) > non_speaking_buffer_count: # ensure we only keep the needed amount of non-speaking buffers
frames.popleft()
# detect whether speaking has started on audio input
energy = audioop.rms(buffer, source.SAMPLE_WIDTH) # energy of the audio signal
if energy > self.energy_threshold: break
# dynamically adjust the energy threshold using asymmetric weighted average
if self.dynamic_energy_threshold:
damping = self.dynamic_energy_adjustment_damping ** seconds_per_buffer # account for different chunk sizes and rates
target_energy = energy * self.dynamic_energy_ratio
self.energy_threshold = self.energy_threshold * damping + target_energy * (1 - damping)
else:
# read audio input until the hotword is said
#############################################################
########THIS IS WHERE THE HOTWORD DETECTION OCCURRS. HOTWORDS ARE DETECTED. I KNOW THIS BECAUSE THE PROGRAM PROGRESSES PAST THIS PART.
#############################################################
snowboy_location, snowboy_hot_word_files = snowboy_configuration
buffer, delta_time = self.snowboy_wait_for_hot_word(snowboy_location, snowboy_hot_word_files, source, timeout)
elapsed_time += delta_time
if len(buffer) == 0: break # reached end of the stream
frames.append(buffer)
# read audio input until the phrase ends
pause_count, phrase_count = 0, 0
phrase_start_time = elapsed_time
while True:
# handle phrase being too long by cutting off the audio
elapsed_time += seconds_per_buffer
if phrase_time_limit and elapsed_time - phrase_start_time > phrase_time_limit:
break
buffer = source.stream.read(source.CHUNK)
if len(buffer) == 0: break # reached end of the stream
frames.append(buffer)
phrase_count += 1
# check if speaking has stopped for longer than the pause threshold on the audio input
energy = audioop.rms(buffer, source.SAMPLE_WIDTH) # unit energy of the audio signal within the buffer
if energy > self.energy_threshold:
pause_count = 0
else:
pause_count += 1
if pause_count > pause_buffer_count: # end of the phrase
break
# check how long the detected phrase is, and retry listening if the phrase is too short
phrase_count -= pause_count # exclude the buffers for the pause before the phrase
####################################################################3
#######THE FOLLOWING CONDITION IS NEVER MET THEREFORE THE LOOP NEVER EXITS AND THE FUNCTION NEVER RETURNS################
############################################################################
if phrase_count >= phrase_buffer_count or len(buffer) == 0: break # phrase is long enough or we've reached the end of the stream, so stop listening
# obtain frame data
for i in range(pause_count - non_speaking_buffer_count): frames.pop() # remove extra non-speaking frames at the end
frame_data = b"".join(frames)
return AudioData(frame_data, source.SAMPLE_RATE, source.SAMPLE_WIDTH)
The issue is that the main while loop in listen() never exits. I am not sure why. Note that the SpeechRecognition module works flawlessly when I am not integrating snowboy. Also note that snowboy works flawlessly on its own.
I am also providing the speech_recognition.snowboy_wait_for_hot_word() method as the problem could be in here.
def snowboy_wait_for_hot_word(self, snowboy_location, snowboy_hot_word_files, source, timeout=None):
print("made it")
# load snowboy library (NOT THREAD SAFE)
sys.path.append(snowboy_location)
import snowboydetect
sys.path.pop()
detector = snowboydetect.SnowboyDetect(
resource_filename=os.path.join(snowboy_location, "resources", "common.res").encode(),
model_str=",".join(snowboy_hot_word_files).encode()
)
detector.SetAudioGain(1.0)
detector.SetSensitivity(",".join(["0.4"] * len(snowboy_hot_word_files)).encode())
snowboy_sample_rate = detector.SampleRate()
elapsed_time = 0
seconds_per_buffer = float(source.CHUNK) / source.SAMPLE_RATE
resampling_state = None
# buffers capable of holding 5 seconds of original and resampled audio
five_seconds_buffer_count = int(math.ceil(5 / seconds_per_buffer))
frames = collections.deque(maxlen=five_seconds_buffer_count)
resampled_frames = collections.deque(maxlen=five_seconds_buffer_count)
while True:
elapsed_time += seconds_per_buffer
if timeout and elapsed_time > timeout:
raise WaitTimeoutError("listening timed out while waiting for hotword to be said")
buffer = source.stream.read(source.CHUNK)
if len(buffer) == 0: break # reached end of the stream
frames.append(buffer)
# resample audio to the required sample rate
resampled_buffer, resampling_state = audioop.ratecv(buffer, source.SAMPLE_WIDTH, 1, source.SAMPLE_RATE, snowboy_sample_rate, resampling_state)
resampled_frames.append(resampled_buffer)
# run Snowboy on the resampled audio
snowboy_result = detector.RunDetection(b"".join(resampled_frames))
assert snowboy_result != -1, "Error initializing streams or reading audio data"
if snowboy_result > 0: break # wake word found
return b"".join(frames), elapsed_time
I am running python 3.7 on a Raspberry pi 3B+ running Raspbian Buster Lite (kernel 4.19.36). Please ask if I can provide any additional information.

How to wait until a sound file ends in vlc in Python 3.6

I have a question in vlc in python
import vlc
sound = vlc.MediaPlayer('sound.mp3')
sound.play()
# i wanna wait until the sound ends then do some code without
time.sleep()
import time, vlc
def Sound(sound):
vlc_instance = vlc.Instance()
player = vlc_instance.media_player_new()
media = vlc_instance.media_new(sound)
player.set_media(media)
player.play()
time.sleep(1.5)
duration = player.get_length() / 1000
time.sleep(duration)
After edit
That exactly what I wanted, thanks everyone for helping me ..
You can use the get_state method (see here: https://www.olivieraubert.net/vlc/python-ctypes/doc/) to check the state of the vlc player.
Something like
vlc_instance = vlc.Instance()
media = vlc_instance.media_new('sound.mp3')
player = vlc_instance.media_player_new()
player.set_media(media)
player.play()
print player.get_state()# Print player's state
for wait util end of vlc play sound, except your:
player.play()
time.sleep(1.5)
duration = player.get_length() / 1000
time.sleep(duration)
other possible (maybe more precise, but CPU costing) method is:
# your code ...
Ended = 6
current_state = player.get_state()
while current_state != Ended:
current_state = player.get_state()
# do sth you want
print("vlc play ended")
refer :
vlc.State definition
vlc.Instance
vlc.MediaPlayer - get_state
I.m.o. Flipbarak had it almost right. My version:
import vlc, time
vlc_instance = vlc.Instance()
song = 'D:\\mozart.mp3'
player = vlc_instance.media_player_new()
media = vlc_instance.media_new(song)
media.get_mrl()
player.set_media(media)
player.play()
playing = set([1])
time.sleep(1.5) # startup time.
duration = player.get_length() / 1000
mm, ss = divmod(duration, 60)
print "Current song is : ", song, "Length:", "%02d:%02d" % (mm,ss)
time_left = True
# the while loop checks every x seconds if the song is finished.
while time_left == True:
song_time = player.get_state()
print 'song time to go: %s' % song_time
if song_time not in playing:
time_left = False
time.sleep(1) # if 1, then delay is 1 second.
print 'Finished playing your song'
A slight alternative / method that i just tested and had good results (without needing to worry about the State.xxxx types.
This also allowed me to lower the overall wait/delay as i'm using TTS and found i would average 0.2 seconds before is_playing returns true
p = vlc.MediaPlayer(audio_url)
p.play()
while not p.is_playing():
time.sleep(0.0025)
while p.is_playing():
time.sleep(0.0025)
The above simply waits for the media to start playing and then for it to stop playing.
Note: I'm testing this via a URL / not a local file but was having the same issue and believe this will work the same.
Also fully aware its a slightly older and answered, but hopefully its of use to some.

Raw audio playback in Allegro 5

I'm writing a MOD player, trying to playback a sample using Allegro5 raw stream capabilities, I can't figure out the exact init parameters for the stream to play the loaded sample data from the mod file.
This is what I have:
xf::ModLoader ml;
ml.loadFromFile("C:\\Users\\bubu\\Downloads\\agress.mod");
// getSampleLength() returns # of data words
int sample_length = ml.getSampleLength(1) * 2;
const int8_t* sample_data = ml.getSampleData(1);
ALLEGRO_MIXER* mixer = al_get_default_mixer();
ALLEGRO_AUDIO_STREAM* stream = al_create_audio_stream(1, sample_length, 8363, ALLEGRO_AUDIO_DEPTH_INT8, ALLEGRO_CHANNEL_CONF_1);
al_attach_audio_stream_to_mixer(stream, mixer);
al_set_audio_stream_gain(stream, 0.7f);
al_set_audio_stream_playmode(stream, ALLEGRO_PLAYMODE_ONCE);
al_set_audio_stream_playing(stream, true);
al_set_audio_stream_fragment(stream, (void*)sample_data);
al_drain_audio_stream(stream);
First of all, freq param is hardcoded for the test (8363Hz), but, playing back at the specified frequency I don't get what I expect, and al_drain_audio_stream() gets stuck forever playing garbage in a loop...
Any help would be appreciated.
At the very least, you need to be calling al_get_audio_stream_fragment before you call al_set_audio_stream_fragment. Typically you'd feed these streams in a while loop, while responding to the ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT event. See the ex_saw example in the Allegro's source for some sample code: https://github.com/liballeg/allegro5/blob/master/examples/ex_saw.c

Can I use an ended sound file to transition to a new scene or refresh data in the same scene?

Lua novice asks:
How do I transition from this...
(a simple example to establish a how-to)...
visual = display.newImage( "redCircle.png", 50, 50 )
local music = audio.loadStream("sound1.mp3")
audio.play(music)
audio.stopWithDelay(60000/60)
to this, timed by the first sound file ending?
visual = display.newImage( "blueCircle.png", 50, 50 )
local music = audio.loadStream("sound2.mp3")
audio.play(music)
audio.stopWithDelay(60000/60)
Which api should I be experimenting with? I've looked at https://docs.coronalabs.com/api/index.html
What am I missing?
What you can do is create a function listener for the first audio file you can look more here: https://docs.coronalabs.com/api/library/audio/play.html Below is a sample code I can give you. Note that I did not use audio.stopWithDelay
--DECLARE LOCAL VARIABLES
local visual1
local visual2
local music1
local music2
--LOAD SOUNDS
music1 = audio.loadStream("sound1.mp3")
music2 = audio.loadStream("sound2.mp3")
local function soundIsFinished(event)
if (event.completed) then
--PLAY SECOND AUDIO AND HIDE/REMOVE VISUAL 1
visual1.isVisible = false
visual2.isVisible = true
audio.play(music2, {duration = 1000})
end
end
--DISPLAY VISUAL1 and play MUSIC1
visual1 = display.newImage("redCircle.png", 50,50)
--AUDIO WILL PLAY FOR 1 SECOND (60000/60) is 1 second
audio.play(music1, { duration=1000, onComplete=soundIsFinshed } )
-- HIDE VISUAL2 FIRST
visual2 = display.newImage("blueCircle.png", 50,50)
visual2.isVisible = false
Hope This helps.

love2d play a sound twice?

I have a problem with playing sounds.
The purpose is making a text to speech program that talks with my voice.
I recorded a lot of phonemes (.wav files with parts of speech) that need to play after each other in the right order.
each sound must play ONLY if the previous sound finished playing.
so if my program needs to say 'hello' then it does this:
**play("h.wav")
if "h.wav":isStopped() then:
play("e.wav")
if "e.wav":isStopped() then... etc ...**
For test purposes i want to play "a.wav" twice but the problem is that i only hear 'A' once...
if i play e.g. 'A' and then 'B', it works fine..
Any help would be mush appreciated!
This is the test code i currently have:
function love.load()
voice = {"a","b","e","f", ......}
for i in pairs(voice) do
voice[i] = love.audio.newSource("VOICE/" .. voice[i] .. ".wav", "static")
end
end
function love.keypressed(key)
if key == "a" then
voice[1]:play()
while voice[1]:isPlaying() do end
voice[1]:play()
while voice[1]:isPlaying() do end
end
end
Just a thought, what if you tried this:
if ( voice[ 1 ]:isPlaying() ) then
voice[ 1 ]:stop()
voice[ 1 ]:play()
end
I guess you could do that before playing any sound.
If you want to play the same sound twice simultaneously, you'll need to have multiple instances of the source.
SLAM, an audio manager library for Löve2D, handles this perfectly.
https://love2d.org/wiki/SLAM
Here's an example with SLAM that will play the same sound multiple times :
require("slam")
sounds = {
["testAudio"] = love.audio.newSource("testAudio.wav", "stream"),
}
for i = 1, 10 do
sounds["testAudio"]:play()
end
This way, any instance that's currently being played will not be stopped.

Resources