Solved Play small Audio files without gaps
-
Hi,
I need several small audio files to be played sequentially - but without gaps in between.
I am usingAudio { id: mediaPlayer playlist: Playlist { id: playlist PlaylistItem { source: "qrc:/snds/r1c1.wav"; } PlaylistItem { source: "qrc:/snds/r1c2.wav"; } PlaylistItem { source: "qrc:/snds/r1c3.wav"; } playbackMode: Playlist.Sequential } }
It does playback sequentially, but there's always a little gap (and some crackling) in between, that I do not get when I play the samples via Windows' "Media Player" playlist (so the samples are apparently ok).
I have not found any setting for intentional gaps that I could set to zero. Are there better methods to play audio sequences? If necessary, I'd happily sidestep to a C++ solution, too, of course.
I'd appreciate any hints or experiences on the matter!
-
@SeDi I tried it myself but I didnt notice any gaps between audiofiles. As soon as one of them finishes, it is passing to the other.
If there are some gaps, it should be about miliseconds. Do u want that time to be exactly 0 sec? -
@Yunus Thank you for your answer, yes, "exactly 0 s" ist crucial for my purpose. I try to implement a demonstration for Mozarts "Musikalisches Würfelspiel" (as described here) where a dice decides which of one of six possible next bars is played. So the bars have to be played seamlessly, like with no gap at all. When you use two "normal" tunes, you probably won't notice any gap between fadeout and intro.
I could make it a bit better with a chain of SoundEffects:
SoundEffect { id: bar1 source: "qrc:/snds/r1c1.wav"; onPlayingChanged: { if (!playing) { bar2.play() } } }
But it's still very audible. Any way to produce a seamless audio stream?
-
I have improved the situation a bit (not much) by using a chain of "SoundEffect" items as low latency option. Still, it was not really usable.
Fortunately, my samples all have the exact same length, so I could find a hack that gets me set for the moment, I am calling the samples with a Timer and I use an interval that is very slightly (but not too disturbingly) shorter than the actual sample duration.
Button { text: ("Play") onClicked: { timer.bar = 1 timer.start() bar1.play() } } SoundEffect { id: bar1 } SoundEffect { id: bar2 } SoundEffect { id: bar3 } SoundEffect { id: bar4 } SoundEffect { id: bar5 } SoundEffect { id: bar6 } SoundEffect { id: bar7 } SoundEffect { id: bar8 } SoundEffect { id: singlePlayBar } Timer { id: timer property int bar: 1 interval: 1475 // instead of 1500 onTriggered: { bar++ switch (bar) { case 1: bar1.play(); timer.restart(); break case 2: bar2.play(); timer.restart(); break case 3: bar3.play(); timer.restart(); break case 4: bar4.play(); timer.restart(); break case 5: bar5.play(); timer.restart(); break case 6: bar6.play(); timer.restart(); break case 7: bar7.play(); timer.restart(); break case 8: bar8.play(); timer.restart(); break } } }
Now you can actually get the idea from the audio, but there are still some crackling sounds from time to time.
Any ideas on how to concatenate wav-files into a seamless audio stream would be gratefully appreciated!
-
Do your samples have gaps/silence at the beginning or end of the file?
-
Perfectly valid question. Absolutely not. Extracted regions, directly from Soundforge. Triple checked this and rebuilt them anyway - to no avail...
-
@SeDi said in Play small Audio files without gaps:
to no avail...
Dang, I was hoping it was simple.
One thing you could do is use 2 Audio objects and have one play and have the other track progress of the played sound. Then start playing the next one in the other Audio object when it gets to a certain percentage of being done. Maybe even mess with volume and do a fade in fade out if that makes sense at all. I looked at Audio and it has the ms progress and total ms and volume control. So it may be doable. Otherwise I think you might need to build a custom C++ object. -
As I am dealing with a sequence of 8 bars of music, I am currently using 8 separate "SoundEffect" items that I trigger with a timer, because the gap was way too long (rythmically relevant) when triggering the respective next one with "onPlayingChanged".
The idea to use the duration and position (with a sufficiently small notifyInterval) is cool. I could actually take longer samples and let them crossfade into another. Tricky, but probably quite doable. I'll have to look into that. Thank you for that idea, @fcarney !
With "build a custom C++ object" you probably have something specific in mind, do you? I'd happily use C++ parts here, if that would be more suitable.
-
@SeDi said in Play small Audio files without gaps:
you probably have something specific in mind, do you?
Not really, I was just suggesting you might need to use C++ audio objects.
-
-
Thanks, I'll definitely have a look into that. Synthesis is currently not my aim, but as a music teacher I am definitely interested in general. But, perhaps, SuperCollider could be a better language for that.
I've built a small item that automatically fades itself in and out. It has further reduced the crackling while having no huge impact on attack, even before using longer samples with it. Not gone yet, but better.
import QtQuick 2.13 import QtMultimedia 5.13 Item { id: fadeSoundEffectItem property int fadeDuration: 40 Audio { id: playSound notifyInterval: 5 onPositionChanged: { if ((duration - position) <= fadeDuration && !fadeOutAnimation.running) { fadeOutAnimation.duration = duration - playSound.position fadeOutAnimation.start() } } } property alias source: playSound.source property real volume: 1 PropertyAnimation { id: fadeInAnimation target: playSound property: "volume" to: fadeSoundEffectItem.volume duration: fadeDuration easing.type: Easing.Linear } PropertyAnimation { id: fadeOutAnimation target: playSound property: "volume" to: 0 duration: duration - playSound.position easing.type: Easing.Linear } function fadeInAndPlay () { playSound.volume = 0; playSound.play() fadeInAnimation.start() } function play() { fadeInAndPlay() } }
Edit: fixed code
-
I'll set this to solved, because I will not explore this further. Probably, a buffered audio stream (perhaps with QAudioOutput) would yield the cleanest result but as the result from fading is sufficient for my needs, I'll leave it there for now.
Thanks for helping me!