Closed rekinyz closed 4 years ago
No, the sound card volume can not be adjusted. This is as it should be. Single apps usually do not control sound card volume, but instead have a little volume control that changes the volume of their own audio.
In SoundCard, you can accomplish this simply by multiplying your audio data with a gain factor.
SoundCard does not control your system's sound card. It merely plays and records on it.
@bastibe sorry for reviving this old issue, but I can't figure out how to implement this without stutter. I read the sound data using soundfile library, then I feed the data into the play stream. To manipulate volume on the fly, I need to multiply the data with a gain value, but this just causes the stream to stutter.
Stuttering is usually a sign that you're taking too long to calculate, probably because you're doing things in an inefficient way, or using too short block sizes. Or maybe you mean something else by "stuttering". It's hard to tell from your description.
yes, I thought that was the case. I just don't know how to make go faster. I have the stream function in a separate thread and do the multiplication in the main thread when you change the volume. This is what my stream function looks like:
def _setup_stream(self):
global exitProgram
with self.speakers.player(self.samplerate, self.channels, 2000) as player:
while True:
if exitProgram.is_set() or self.close:
break
if self.playing:
data = self.playData[self.position : self.position + 2000]
self.position += 2000
if data.size == 0:
if self.endedCallback is not None:
self.endedCallback()
self.position = 0
self.playing = False
continue
player.play(data)
You should do the multiplication inside the audio thread, directly to the data
array:
data = self.currentLevel * self.playData[self.position : self.position + 2000]
I tried with a block size of 20000 and while that sounds a lot better, I can still hear clicks on a regular interval when the play function returns and I have to get new data, but that gives me an idea. Perhaps if I prepare the data to be played in another, second thread, I can get smooth playback 🤔
You should do the multiplication inside the audio thread, directly to the
data
array:data = self.currentLevel * self.playData[self.position : self.position + 2000]
wouldn't that just make it take even more compute time?
I cannot say upfront because I dont know how you are doing the multiplication on the main thread.
But this is the "standard" way of applying filters to an audio while playing
ah well, I just multiply the entire array and save to a variable, which the audio thread when it needs new audio data. I did it on the audio thread before, to just the slice, but since I got the stuttering, I thought it would be better to do on the main thread, so the audio thread wouldn't need to do any calculations
This can be one of several issues:
Perhaps the main thread is consuming too much CPU time, and doesn't leave enough headroom for the audio thread. Python can only run one thread at any one time, so threading only helps with latency, not throughput.
In this particular case, perhaps the multiplication takes too long when it is applied, thus stalling the audio thread during the multiplication, which causes the stutter.
Or perhaps the "stutter" is not actually an audio problem at all, but the effect of changing the volume too quickly. Any large change in volume will sound like a click if applied instantaneously. You'd need to ramp up the volume over a short time to make it sound smooth. (This is more easily done in the audio thread with a little state machine)
Useful block sizes are usually in the 1000-20000 range, i.e. higher than the default hardware block rate, but low enough to react somewhat quickly to UI events.
Hm, then I suspect it is the first issue, the main tread taking too much cpu time. The volume is applied only once to the entire dataset, so that can't be the issue. I wrote the application to support many audio streams at once. Perhaps that's where the issue lies?
Hard to tell from the outside. Heavily multithreaded code is not a good fit for Python, and real-time does not wait for stragglers.
there isn't a way to control the volume, in case someone want to implement voice dodge or somthing