Sound Object - Volume Operation

I have an application which uses the Sound class to play a sequence of WAV files needed for some test applications. The program is working quite nicely with one exception. The Volume property is not quite what I expected. The LR says that Sound.Volume controls the volume of sound, and the the range is from 0 to 100. I would expect (apparently incorrectly) that when it says “controls” it would be somewhat of a linear control (e.g. 25 -> 25% vol, 50 -> 50% vol, 100 -> 100% vol). From all my trials (and tribulations) the control appears to operate only from about 80 to 100; and not linear at all. Most of the real control of the volume resides between 90 and 100. Is that the way it’s supposed to be? Right now, I am going down the path of generating my own WAV files at different “volumes”, which is working ok. But I would like to understand how the control should be expected to operate. Tested this behavior on Windows 7 and Windows 8.

Thanks in advanced.

100% guesswork:

When dealing with sound intensity (volume) logarithmic scales are applied. So, we use decibels (a logarithmic scale) to express volume because our volume sensation and the intensity of the volume (the energy of the sound wave) are not linearly proportional.

So, you expect your volume property to affect linearly, and maybe it is actually varying linearly the intensity, but what you perceive is not a linear variation.

If this is the case, you need to correct the Volume property for our non-linear preception. Also, if this is the case, I would fill a feature request since the usability of the volume property as it is now would be very low, in my opinion.

Julen

Julien, thanks for your input. I am not guessing or perceiving anything. I measured this with an oscilloscope; and it does not match any sort of linear taper or logarithmic taper function I know off. I am just trying to figure out how was it meant to work/operate and if someone else had experienced this.

This is not like a new function/class. It certainly does not behave like any of the volume controls on the computer, so I am asking for some feedback on some more experienced user of this class or maybe a Xojo Engineer on what the expectation of that property should be.

I fully agree with you. But since this is my first foray on using this function, perhaps there are others out there with better ideas on how to improve its use (or use it properly).

Ok, could you try this please? (out of curiosity now):

sound.volume=50*log(MyVolumeValue)

Where MyVolumeValue is the value in the 0-100 volume scale you would like to set, if that scale behaved as you expected it (linearly).

Interesting, you are measuring the amplitude of the signal. Are you using a microphone or sending the signal directly to the oscilloscope?

I wonder if there is a linear proportionallity between the amplitude of the signal and the intensity (energy) of the sound wave?

I am very busy at work right now, but I will try to do the measurements myself some time next week. I am intrigued by this matter :).

Julen

It does make some difference, but doesn’t really address the issue. There is no usable range. Let me illustrate with an example. Below is some sample data using a 1kHz tone:

Sound.Volume / Output Audio Level (mVrms)
0 / 0
10 / 0
20 / 0
30 / 0
40 / 0
50 / 0
60 / 0
70 / 12
80 / 36
90 / 114
100 / 352

By comparison here is the same data using some declares (waveOutSetVolume from “winmm” library) to control the audio output.

Volume / Output Audio Level (mVrms)
0 / 0
10 / 35
20 / 71
30 / 106
40 / 141
50 / 176
60 / 211
70 / 247
80 / 282
90 / 317
100 / 352

Sorry for the gross table formatting, but at the moment I can’t access any file sharing site to post a graphic. But you can see, the latter set is as would be expected (and more important useable) and the former set is really not useable (at best is equivalent to 5-bit resolution - i.e. 32 discrete levels, and they are not even linear). It’s almost the same as just providing two states for the volume: on and off.

I am switching over to using the MoviePlayer which does seem to work as expected (except for the looping which does not seem to be working at the moment - trying to figure out why). But my question really is about the expected operation of the Sound Class. Maybe I am completely misreading its use in the LR.

Just using my ear, on mac it sounds linear.

The first graph looks like a geometric progression from 70 on, each about 3 times the previous. Maybe it’s erroneously trying to undo some scale.

The first set of data follows this equation: Output=0.00439EXP(0.112889Volume)

Your lower output values might be read as zero due to hardware limitations (the output values should be below 3 mVrms). This output is what I would expect, as this should provide a linear perception of the sound volume.

Julen

Very cool. How did you find that? Plugged it into Grapher and it’s a perfect fit.

I’m not familiar with EXP so I wrote it as

outmVrms = s * e ^ (f * volume)

then a little algebra to express volume as a function of output mVrms

ln(outmVrms / s) / f = volume

Then, instead of specifying mVrms which ranges up to 352, scale the input by 3.52 so it ranges 0-100.

ln(intendedVolume * 3.52 / s) / f = volume

finally, convert ln to logs, replace values and format for xojo.

#if TargetWindows then aSnd.Volume = log(intendedVolume * 801.822323) / (log(2.718282) * 0.112889) #else aSnd.Volume = intendedVolume #end

Assuming this is Windows only behavior, and that it is weird since the declares produce linear mVrms. (I don’t know what mVrms is btw :slight_smile: )

I got that expression from Excel, doing a regression. EXP is the same as e^ (also in Xojo).

Vrms is an average voltage of a wave shaped voltage signal (the one sent to the speakers). mV rms is the same, but in miliVolts instead of Volts.

Since the Log function in Xojo is the natural logarithm (usually expressed as Ln), you don’t need to convert the base of the logarithm (although it has no effect on the result as ln e equals 1). I have also used the original 0.00439 and 3.52 values for the sake of clarity:

#if TargetWindows then aSnd.Volume = log(intendedVolume/0.00439 * 3.52) / 0.112889 #else aSnd.Volume = intendedVolume #end

The LR is clear about the base of the logarithm, but to me the name of the function is misleading.

Julen

doh !

Many thanks for the explanations :slight_smile:

Julen / Will ,
Thanks for taking the time to look at this.

Same thing I used. It was nice to get a function that went with it, but the function itself made no difference (for my application). It follows no normal audio taper functions I have seen (and we have done many audio panels at work).

This snippet is cool conceptually, but it is doesn’t address the problem in real life (please take no offense); let me explain. This (similar equation to what you have) is what I started with, I mapped the sound function and made up an equation so I could attempt to gain some usefulness out of the function. But the Sound.Volume takes 100 discrete values. The discrete part is important. Once you apply the function you provided (and which is mathematically correct), only about a third of those values are actually meaningful. In other words, only values from about 70 to 100 are actually used, and the rest of the values are essentially thrown away. It would be awesome if Sound.Volume allowed fractional numbers between 70 and 100, but all you get is 30 values to control the volume (and they are not linear). That limits the real usefulness (and in no way matches the LR). Again, I am not trying to diminish what you have expressed there. I came to a very similar conclusion, but the usefulness of the function goes away since you can barely control the output. I mean you have some control, but very, very coarse.

Since Will says it plays ok (sounds linear) on the Mac (not a surprise), and if it did not you would be able to discern it (the ear+brain is a wonderful thing); I will assume the damn Windows implementation is broken (not a surprise I guess). I was hoping I was missing something obvious. The Sound object is probably not used much (in Windows), cause anyone trying to control the volume would’ve heard this I think.

As for how I was using this; I needed to play 4 nearly simultaneous tones and individually control their volumes. The Sound object seemed to be great for this (guess not). I have reconsidered my approach based on this Xojo limitation on the Windows implementation.

BTW, the declare to control the volume (in Windows) follows (credits to Barry Traver):
Soft Declare Function waveOutSetVolume Lib "winmm" ( devid as Integer, vol as Integer ) As Integer Dim outVolume As Integer Dim state As Integer // volume is 32bits, 16bits for left channel, and 16bits for right channel // intendedVolume is an integer value from 0 to 100 outVolume = intendedVolume * (&hFFFFFFFF / 100) state = waveOutSetVolume(0, outVolume)

Thank for the help. When I get a chance I will create a ticket and throw it into the Windows black hole for a rainy day.

No worries Langue, for me it was fun to give it a thought. Glad you solved your problem.

Maybe file a bug report?

Julen

<https://xojo.com/issue/39028>
Won’t hold my breath. It may be flagged as a “feature”. It has been this way since 2006 apparently (http://forums.realsoftware.com/viewtopic.php?t=7032). And since it is Windows, it may never get addressed. :wink: