-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fc5c610
Showing
35 changed files
with
4,633 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
VLevel 0.3 INSTALL | ||
|
||
VLevel is distributed as source code. To build it, type "make". To | ||
install it, login as root (type "su") and type "make install". | ||
|
||
You can change where it is installed by editing Makefile before doing | ||
the above. | ||
|
||
I test VLevel on a Linux system, but it should build on any similar | ||
system. It should compile on Windows, but it won't be very useful | ||
until I write a Ruby script with a nice cross-platform GUI and SOX | ||
integration. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# This file is part of VLevel, a dynamic volume normalizer. | ||
# | ||
# Copyright 2003 Tom Felker <tcfelker@mtco.com> | ||
# | ||
# This library is free software; you can redistribute it and/or modify | ||
# it under the terms of the GNU Lesser General Public License as | ||
# published by the Free Software Foundation; either version 2.1 of the | ||
# License, or (at your option) any later version. | ||
# | ||
# This library is distributed in the hope that it will be useful, but | ||
# WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
# Lesser General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Lesser General Public | ||
# License along with this library; if not, write to the Free Software | ||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
# USA | ||
|
||
# User-editable options: | ||
|
||
# Change this to suit your preferences (maybe add -march=cputype) | ||
|
||
# This is what works fastest with GCC on my system | ||
# | ||
# I'd be interested to see how setting -DEXPECT impacts performance - | ||
# on my system, it makes it a bit worse. | ||
|
||
export CXXFLAGS = -Wall -O3 -fPIC -DPIC -g -march=pentium4 | ||
|
||
# On my system, ICC is quite a bit faster, with these options: | ||
#export CC=icc | ||
#export CXX=icc | ||
#export LD=icc | ||
#export CXXFLAGS = -fPIC -DPIC -g -O3 -rcd | ||
|
||
# This is where it will be installed | ||
export PREFIX = /usr/local/ | ||
export LADSPA_PATH = $(PREFIX)/lib/ladspa/ | ||
|
||
# End of user-editable options. | ||
|
||
|
||
# Note: this probably isn't the best way to have one makefile for | ||
# source in several directories. Someday I'll figure out automake. | ||
# Writing Makefiles always makes me feel like I'm reinventing the | ||
# wheel. | ||
|
||
# This is evil, but it makes implicit link rules use g++, not gcc | ||
export CC = $(CXX) | ||
|
||
.PHONY: all install clean | ||
|
||
all: | ||
make -C volumeleveler all | ||
make -C vlevel-bin all | ||
make -C vlevel-ladspa all | ||
|
||
install: all | ||
make -C volumeleveler install | ||
make -C vlevel-bin install | ||
make -C vlevel-ladspa install | ||
|
||
clean: | ||
make -C volumeleveler clean | ||
make -C vlevel-bin clean | ||
make -C vlevel-ladspa clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
VLevel 0.5 README | ||
|
||
What is VLevel? | ||
|
||
VLevel is a tool to amplify the soft parts of music so you don't | ||
have to fiddle with the volume control. It looks ahead a few | ||
seconds, so it can change the volume gradually without ever | ||
clipping. Because the volume is changed gradually, "dynamic | ||
contrast" is preserved. | ||
|
||
How do I install VLevel? | ||
|
||
See the file INSTALL. For the impatient: "sudo make install". | ||
|
||
How do I use VLevel? | ||
|
||
VLevel is a filter, meaning you pipe raw data to it, and it outputs | ||
the leveled data. For example: | ||
|
||
vlevel-bin < in.cdda > out.cdda | ||
|
||
There are options to control the length of the look-ahead buffer, | ||
the strength of the effect, and the maximum amplification, as well | ||
as the format of the raw data. Type "vlevel-bin --help" for | ||
details. | ||
|
||
VLevel also works as a LADSPA plugin. See http://www.ladspa.org for | ||
a lists of hosts that VLevel can plug into. | ||
|
||
What other features are planed? | ||
|
||
A Ruby cross-platform GUI drag-n-drop converter that uses SOX. | ||
|
||
Can I distribute VLevel? | ||
|
||
Please do. VLevel is licenced under the GPL, for more information, | ||
see the COPYING file. | ||
|
||
Where can I get more info? | ||
|
||
There is documentation in the docs directory. News, new versions, | ||
contact info, help, and more are available from the website: | ||
|
||
http://vlevel.sourceforge.net |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
More extensive testing, exotic channel config, feedback on other platforms | ||
|
||
Optimize for mono and stereo special cases | ||
- i tried this, and I couldn't do better than -O3 -march=pentium4 | ||
- someone else can try their hand, but beware. | ||
|
||
Cool FXRuby GUI with SOX | ||
|
||
Hopefully usable Winamp plugin before next version. Yay! | ||
|
||
Rememember: when updating version, change in docs, readme, and vlevel-bin.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
VLevel 0.3 notes.txt | ||
|
||
Channels | ||
|
||
VLevel abstracts audio into samples, each of which has as many | ||
values as there are channels, and most of the functions confusingly | ||
accept length in samples, but work on arrays of length (samples * | ||
values) doubles. | ||
|
||
You'd think this would be inneficient, but it's not. I tried | ||
changing the code to just work on arrays of double (which would only | ||
affect the lowest order bits, except for very short look-ahead), and | ||
it was actually a bit slower. | ||
|
||
I think the reason for this is that although when using channels, | ||
there is much more integer math and 2-iteration for loops, it means | ||
that the expensive slope calculation (not the whole search, but each | ||
slope = dy / dx) only has to be done half (1 / channels) as often. | ||
|
||
The moral is: channels aren't inneficient, don't waste your time | ||
abolishing them. Floating-point probably is, but fixed point may be | ||
even more ugly. | ||
|
||
The code currently allows for different functions to be called | ||
depending on the number of channels. For now, the generic code that | ||
works for any number of channels is fine, but speed optimization may | ||
be possible in the common mono and stereo cases. | ||
|
||
|
||
GCC Versions | ||
|
||
I discovered that while GCC 3.2 generates faster code than GCC 2.96, | ||
it's iostream implementation is slower by two orders of magnitude. | ||
I've changed the code to use FILE*, which is fast in either version, | ||
but that's ugly. I haven't tried other platforms or versions, but I | ||
see no reason they wouldn't work. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
VLevel 0.3 technical.txt | ||
|
||
This is an outline of how VLevel works, which will hopefully be useful | ||
to anyone who helps develop it. (And me in a month.) | ||
|
||
Code Layout | ||
|
||
The core of VLevel is the VolumeLeveler class. It contains the | ||
look-ahead buffer. It works on blocks of double-precision numbers, | ||
called values (value_t). Some number (channels) of values makes up | ||
a sample. Many of VolumeLeveler's functions take lengths in samples | ||
instead of values, so be careful. | ||
|
||
vlevel-bin drives the VolumeLeveler class, and also uses CommandLine | ||
to parse it's options. | ||
|
||
Soon, there will be a Ruby script using SOX that makes Ogg, FLAC, and wav | ||
files work with a nice drag-n-drop GUI. | ||
|
||
General Idea | ||
|
||
The intent is to make the quiet parts louder. This is done by | ||
computing the volume at each point, then scaling it as described in | ||
the Math section. The complex part is finding out what the volume | ||
is at each point (VolumeLeveler::avg_amp). It must vary smoothly so | ||
the volume changes aren't obvious, but it must always be above the | ||
peaks of the waveform, or clipping could occur. | ||
|
||
To do this, there is a fifo buffer. Imagine a graph of position | ||
vs. amplitude showing the contents of the buffer. A horizontal line | ||
is drawn across it, representing VolumeLeveler::avg_amp. From where | ||
avg_amp crosses the y-axis, a line is drawn with the maximum | ||
possible slope to intercept one of the amplitude points. This line | ||
which is as steep as possible, is the smooth line that avg_amp will | ||
follow. | ||
|
||
When the value at the head of the buffer is removed, it is scaled | ||
based on avg_amp. avg_amp is then incremented by the slope of the | ||
line. If we reach the point the line was drawn to (max_slope_pos), | ||
we search the fifo for the next point of highest slope. Otherwise, | ||
we only need to check the incoming sample to see if a line drawn to | ||
it has the highest slope. | ||
|
||
y y (a few samples later) | ||
|
||
^ ^ ^ | ||
| / max_slope | | ||
| / | | ||
| /s |s\---------- avg_amp | ||
| / s |s \ | ||
| / s |s \ max_slope | ||
| / s s |s s \ | ||
|--s-ss-s----avg_amp |s s \ | ||
| ss ss s s |s s ss | ||
|ssssssssss |ssssss | ||
+------------> x +---------> x | ||
|
||
Sorry for the ASCII art. The result is that the average amplitude | ||
(avg_amp) varies slowly and always stays above the amplitude of each | ||
sample. When the samples are removed, they are scaled based on the | ||
next section. | ||
|
||
Math | ||
|
||
Once we have avg_amp, each sample is scaled when it is output | ||
according to this: | ||
|
||
output_sample = sample * avg_amp ^ (-strength) | ||
|
||
This is derived as follows: | ||
|
||
First, we convert the amplitude of avg_amp to decibels (1 = 0dB): | ||
|
||
avg_amp_db = 10 * log10(avg_amp) | ||
|
||
avg_amp_db is less than zero. We want to scale it to be closer to | ||
zero, in such a way that if strength is 1, it will become zero, and | ||
if strength is 0 it will remain unchanged. | ||
|
||
ideal_amp_db = avg_amp_db * (1 - strength) | ||
ideal_amp_db = 10 * log10(avg_amp) * (1 - strength) | ||
|
||
Now we convert back to samples: | ||
|
||
ideal_amp = 10 ^ (ideal_amp_db / 10) | ||
ideal_amp = 10 ^ (log10(avg_amp) * (1 - strength)) | ||
ideal_amp = (10 ^ log10(avg_amp)) ^ (1 - strength) | ||
ideal_amp = avg_amp ^ (1 - strength) | ||
|
||
Now we find out what we should multiply the samples by to change | ||
their peak amplitude, avg_amp, to their ideal peak amplitude, | ||
ideal_amp: | ||
|
||
multiplier = ideal_amp / avg_amp | ||
multiplier = avg_amp ^ (1 - strength) / avg_amp | ||
multiplier = avg_amp ^ (-strength) | ||
|
||
And finally, we multiply the sample by the multiplier: | ||
|
||
output_sample = sample * multiplier | ||
output_sample = sample * avg_amp ^ (-strength) | ||
|
||
Undoing the effect | ||
|
||
If the original values for strength weren't too close to 1, you can | ||
undo the VLevel by giving the undo option. It works by changing | ||
strength as shown below. | ||
|
||
When we first leveled, we scaled the amplitudes like so: | ||
|
||
ideal_amp_db = avg_amp_db * (1 - strength) | ||
|
||
To get that back, we solve for avg_amp_db | ||
|
||
avg_amp_db = ideal_amp_db * 1 / (1 - strength) | ||
|
||
In this pass, however, the original avg_amp_db becomes ideal_amp_db, | ||
and the original (1 - strength) becomes 1 / (1 - strength). Now | ||
we skip ahead a bit: | ||
|
||
multiplier = avg_amp ^ (1 - strength) / avg_amp | ||
|
||
Substituting as explained above and continuing: | ||
|
||
multiplier = avg_amp ^ (1 / (1 - strength)) / avg_amp | ||
multiplier = avg_amp ^ ((1 / (1 - strength)) - 1) | ||
multiplier = avg_amp ^ (strength / (1 - strength)) | ||
|
||
But how do we get VLevel to do this? Well, we can give it any | ||
strength, and it does this: | ||
|
||
multiplier = avg_amp ^ -strength | ||
|
||
And we want it to do this: | ||
|
||
multiplier = avg_amp ^ (undo_strength / (1 - undo_strength)) | ||
|
||
So... | ||
|
||
-strength = undo_strength / (1 - undo_strength) | ||
strength = undo_strength / (undo_strength - 1) | ||
|
||
By choosing strength as above before starting VLevel, we can then | ||
undo the first VLevel, with no change to the main algorithm. | ||
|
||
To be totally precise, we'd also have to make a min_multiplier with | ||
a value of 1 / orig_max_multiplier, but that would be slow, and does | ||
anybody care if we drop the static anyway? | ||
|
||
It's not perfect, probably because avg_amp moves linearly, not | ||
logarithmically, so there are some rounding errors. Someday I might | ||
try changing that, but it's a big change. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
These are a few scripts I use to make VLeveling stuff easier. They | ||
mostly work on Ogg files, and use SOX. They are short and | ||
self-explanatory. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/bin/sh | ||
# uses vlevel to play .ogg files named on the command line | ||
|
||
ogg123 -d raw -f - "$@" | vlevel-bin | artscat |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/bin/sh | ||
|
||
sox -raw -r44100 -s -w -c2 $1 `basename $1 .raw`.wav |
Oops, something went wrong.