2007-05-14 09:55:24 +00:00
|
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
|
<HTML>
|
|
|
|
|
|
|
|
<HEAD>
|
|
|
|
<TITLE>
|
|
|
|
libsndfile : Frequently Asked Questions.
|
|
|
|
</TITLE>
|
2004-01-21 07:46:34 +00:00
|
|
|
<META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT zip DOT com DOT au)">
|
|
|
|
<META NAME="Version" CONTENT="Version 1.0.6">
|
|
|
|
<!-- Another version at the bottom of the page. -->
|
2007-05-14 09:55:24 +00:00
|
|
|
<META NAME="Description" CONTENT="The libsndfile FAQ.">
|
|
|
|
<META NAME="Keywords" CONTENT="WAV AIFF AU libsndfile sound audio dsp Linux">
|
|
|
|
<LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
|
|
|
|
</HEAD>
|
|
|
|
|
2004-01-21 07:46:34 +00:00
|
|
|
<BODY TEXT="#FFFFFF" BGCOLOR="#000000" LINK="#5050FF" VLINK="#5050FF" ALINK="#FF00FF">
|
2007-05-14 09:55:24 +00:00
|
|
|
|
|
|
|
<H1><B>libsndfile : Frequently Asked Questions.</B></H1>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
<A HREF="#Q001">Q1 : On Linux, sf_open returns weird info about files. Why?</A><BR>
|
2007-05-14 09:55:24 +00:00
|
|
|
<A HREF="#Q002">Q2 : In version 0 the SF_INFO struct had a pcmbitwidth field
|
|
|
|
but version 1 does not. Why?</A><BR>
|
|
|
|
<A HREF="#Q003">Q3 : Compiling is really slow on MacOSX. Why?</A><BR>
|
|
|
|
<A HREF="#Q004">Q4 : When trying to compile libsndfile on Solaris I get a "bad
|
|
|
|
substitution" error during linking. What can I do to fix this?</A><BR>
|
|
|
|
<A HREF="#Q005">Q5 : Why doesn't libsndfile do interleaving/de-interleaving?</A><BR>
|
|
|
|
<A HREF="#Q006">Q6 : What's the best format for storing temporary files?</A><BR>
|
2004-01-21 07:46:34 +00:00
|
|
|
<A HREF="#Q007">Q7 : On Linux/Unix/MaxOSX, what's the best way of detecting the
|
2007-05-14 09:55:24 +00:00
|
|
|
presence of libsndfile?</A><BR>
|
2004-01-21 07:46:34 +00:00
|
|
|
<A HREF="#Q008">Q8 : How about adding the ability to write/read sound files to/from
|
2007-05-14 09:55:24 +00:00
|
|
|
memory buffers?</A><BR>
|
2004-01-21 07:46:34 +00:00
|
|
|
<A HREF="#Q009">Q9 : Reading a 16 bit PCM file as normalised floats and then
|
2007-05-14 09:55:24 +00:00
|
|
|
writing them back changes some sample values. Why?</A><BR>
|
2004-01-21 07:46:34 +00:00
|
|
|
<A HREF="#Q010">Q10 : I'm having problems with u-law encoded WAV files generated by
|
2007-05-14 09:55:24 +00:00
|
|
|
libsndfile in Winamp. Why?</A><BR>
|
2004-01-21 07:46:34 +00:00
|
|
|
<A HREF="#Q011">Q11 : What are samples? What are frames?</A><BR>
|
2007-05-14 09:55:24 +00:00
|
|
|
<HR>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
<A NAME="Q001"></A>
|
2004-01-21 07:46:34 +00:00
|
|
|
<H2><BR><B>Q1 : On Linux, sf_open returns weird info about files. Why?</B></H2>
|
2007-05-14 09:55:24 +00:00
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
This simple call to sf_open :
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
2004-01-21 07:46:34 +00:00
|
|
|
<PRE>
|
|
|
|
file = sf_open (filename, SFM_READ, &sfinfo) ;
|
|
|
|
|
|
|
|
printf ("srate : %d\n", sfinfo.samplerate) ;
|
|
|
|
printf ("frames : %d\n", sfinfo.frames) ;
|
|
|
|
printf ("channels : %d\n", sfinfo.channels) ;
|
|
|
|
printf ("format : %d\n", sfinfo.format) ;
|
|
|
|
printf ("sections : %d\n", sfinfo.sections);
|
|
|
|
printf ("seekable : %d\n", sfinfo.seekable) ;
|
|
|
|
</PRE>
|
2007-05-14 09:55:24 +00:00
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
returns this weird info:
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
2004-01-21 07:46:34 +00:00
|
|
|
<PRE>
|
|
|
|
srate : 0
|
|
|
|
frames : 1445760
|
|
|
|
channels : 44100
|
|
|
|
format : 2
|
|
|
|
sections : 65538
|
|
|
|
seekable : 1
|
|
|
|
|
|
|
|
</PRE>
|
|
|
|
<H2><B>Answer</B></H2>
|
2007-05-14 09:55:24 +00:00
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
This is only a problem on Linux and other 32 bit OSes (possibly 32 bit Solaris)
|
|
|
|
which require special compiler command line options to allow access to files
|
|
|
|
greater than 2 Gig in size.
|
|
|
|
<A HREF="pkgconfig.html">These instructions</A> should show you a way around this
|
|
|
|
problem.
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
2004-01-21 07:46:34 +00:00
|
|
|
|
2007-05-14 09:55:24 +00:00
|
|
|
<!-- ========================================================================= -->
|
|
|
|
<A NAME="Q002"></A>
|
|
|
|
<H2><BR><B>Q2 : In version 0 the SF_INFO struct had a pcmbitwidth field
|
|
|
|
but version 1 does not. Why?</B></H2>
|
|
|
|
<P>
|
|
|
|
This was dropped for a number of reasons:
|
|
|
|
</P>
|
|
|
|
<UL>
|
|
|
|
<LI> pcmbitwidth makes little sense on compressed or floating point formats
|
|
|
|
<LI> with the new API you really don't need to know it
|
|
|
|
</UL>
|
|
|
|
<P>
|
|
|
|
As documented
|
2004-01-21 07:46:34 +00:00
|
|
|
<A HREF="http://www.zip.com.au/~erikd/libsndfile/api.html#note1">here</A>
|
2007-05-14 09:55:24 +00:00
|
|
|
there is now a well defined behavior which ensures that no matter what the
|
|
|
|
bit width of the source file, the scaling always does something sensible.
|
|
|
|
This makes it safe to read 8, 16, 24 and 32 bit PCM files using sf_read_short()
|
|
|
|
and always have the optimal behavior.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
<A NAME="Q003"></A>
|
|
|
|
<H2><BR><B>Q3 : Compiling is really slow on MacOSX. Why?</B></H2>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
When you configure and compile libsndfile, it uses the Bourne shell for a number
|
2007-05-14 09:55:24 +00:00
|
|
|
of tasks (ie configure script and libtool).
|
2004-01-21 07:46:34 +00:00
|
|
|
However, Apple has decided to ship their system with a really crappy Bourne shell.
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
|
|
|
<P>
|
|
|
|
To fix this I suggest that you install the GNU Bash shell, rename /bin/sh to
|
|
|
|
/bin/sh.old and make a softlink from /bin/sh to the bash shell.
|
|
|
|
Bash is designed to behave as a Bourne shell when is is called as /bin/sh.
|
|
|
|
</P>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
When I did this on my iBook running MacOSX, compile times dropped from 13 minutes
|
2007-05-14 09:55:24 +00:00
|
|
|
to 3 minutes.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
<A NAME="Q004"></A>
|
|
|
|
<H2><BR><B>Q4 : When trying to compile libsndfile on Solaris I get a "bad
|
|
|
|
substitution" error on linking. Why?</B></H2>
|
|
|
|
<P>
|
|
|
|
It seems that the Solaris Bourne shell disagrees with GNU libtool.
|
|
|
|
</P>
|
|
|
|
<P>
|
|
|
|
To fix this I suggest that you install the GNU Bash shell, rename /bin/sh to
|
|
|
|
/bin/sh.old and make a softlink from /bin/sh to the bash shell.
|
|
|
|
Bash is designed to behave as a Bourne shell when is is called as /bin/sh.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
<A NAME="Q005"></A>
|
|
|
|
<H2><BR><B>Q5 : Why doesn't libsndfile do interleaving/de-interleaving?</B></H2>
|
|
|
|
<P>
|
|
|
|
This problem is bigger than it may seem at first.
|
|
|
|
</P>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
For a stereo file, it a pretty safe bet that a simple interleaving/de-interleaving
|
2007-05-14 09:55:24 +00:00
|
|
|
could satisfy most users.
|
2004-01-21 07:46:34 +00:00
|
|
|
However, for file with more than 2 channels this is unlikely to be the case.
|
|
|
|
If the user has a 4 channel file and want to play that file on a stereo output
|
|
|
|
sound card they either want the first two channels or they want some mixed combination
|
2007-05-14 09:55:24 +00:00
|
|
|
of the 4 channels.
|
|
|
|
</P>
|
|
|
|
<P>
|
|
|
|
When you add more channels, the combinations grow exponentially and it becomes
|
|
|
|
increasingly difficult to cover even a sensible subset of the possible combinations.
|
|
|
|
On top of that, coding any one style of interleaver/de-interleaver is trivial, while
|
|
|
|
coding one that can cover all combinations is far from trivial.
|
|
|
|
This means that this feature will not be added any time soon.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
<A NAME="Q006"></A>
|
|
|
|
<H2><BR><B>Q6 : What's the best format for storing temporary files?</B></H2>
|
|
|
|
|
|
|
|
<P>
|
|
|
|
When you want to store temporary data there are a number of requirements;
|
|
|
|
</P>
|
|
|
|
<UL>
|
|
|
|
<LI> A simple, easy to parse header.
|
|
|
|
<LI> The format must provide the fastest possible read and write rates (ie
|
|
|
|
avoid conversions and encoding/decoding).
|
|
|
|
<LI> The file format must be reasonably common and playable by most players.
|
|
|
|
<LI> Able to store data in either endian-ness.
|
|
|
|
</UL>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
The format which best means these requirements is AU, which allows data to be
|
|
|
|
stored in any one of short, int, float and double (among others).
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
For instance, if an application uses float data internally, it temporary files
|
2007-05-14 09:55:24 +00:00
|
|
|
should use a format of (SF_ENDIAN_CPU | SF_FORMAT_AU | SF_FORMAT_FLOAT) which
|
2004-01-21 07:46:34 +00:00
|
|
|
will store big endian float data in big endian CPUs and little float endian data
|
2007-05-14 09:55:24 +00:00
|
|
|
on little endian CPUs.
|
|
|
|
Reading and writing this format will not require any conversions or byte swapping
|
|
|
|
regardless of the host CPU.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
|
|
|
|
<A NAME="Q007"></A>
|
|
|
|
<H2><BR><B>Q7 : On Linux/Unix/MaxOSX, what's the best way of detecting the presence
|
|
|
|
of libsndfile using autoconf?</B></H2>
|
|
|
|
|
|
|
|
<P>
|
|
|
|
libsndfile uses the pkg-config (man pkg-config) method of registering itself with the
|
|
|
|
host system.
|
|
|
|
The best way of detecting its presence is using something like this in configure.ac
|
|
|
|
(or configure.in):
|
|
|
|
</P>
|
|
|
|
<PRE>
|
|
|
|
PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.2, ac_cv_sndfile=1, ac_cv_sndfile=0)
|
|
|
|
|
|
|
|
AC_DEFINE_UNQUOTED([HAVE_SNDFILE],${ac_cv_sndfile},
|
|
|
|
[Set to 1 if you have libsndfile.])
|
|
|
|
|
|
|
|
AC_SUBST(SNDFILE_CFLAGS)
|
|
|
|
AC_SUBST(SNDFILE_LIBS)
|
|
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
This will automatically set the <B>SNDFILE_CFLAGS</B> and <B>SNDFILE_LIBS</B>
|
|
|
|
variables which can be used in Makefile.am like this:
|
|
|
|
</P>
|
|
|
|
<PRE>
|
|
|
|
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
|
|
|
|
SNDFILE_LIBS = @SNDFILE_LIBS@
|
|
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
If you install libsndfile from source, you will probably need to set the
|
2004-01-21 07:46:34 +00:00
|
|
|
<B>PKG_CONFIG_PATH</B> environment variable's suggested at the end of the
|
2007-05-14 09:55:24 +00:00
|
|
|
libsndfile configure process. For instance on my system I get this:
|
|
|
|
</P>
|
|
|
|
<PRE>
|
|
|
|
-=-=-=-=-=-=-=-=-=-= Configuration Complete =-=-=-=-=-=-=-=-=-=-
|
|
|
|
|
|
|
|
Configuration summary :
|
|
|
|
|
|
|
|
Version : ..................... 1.0.5
|
|
|
|
Experimental code : ........... no
|
|
|
|
|
|
|
|
Tools :
|
|
|
|
|
|
|
|
Compiler is GCC : ............. yes
|
|
|
|
GCC major version : ........... 3
|
|
|
|
|
|
|
|
Installation directories :
|
|
|
|
|
|
|
|
Library directory : ........... /usr/local/lib
|
|
|
|
Program directory : ........... /usr/local/bin
|
|
|
|
Pkgconfig directory : ......... /usr/local/lib/pkgconfig
|
|
|
|
|
|
|
|
Compiling some other packages against libsndfile may require
|
|
|
|
the addition of "/usr/local/lib/pkgconfig" to the
|
|
|
|
PKG_CONFIG_PATH environment variable.
|
|
|
|
</PRE>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
|
|
|
|
<A NAME="Q008"></A>
|
2004-01-21 07:46:34 +00:00
|
|
|
<H2><BR><B>Q8 : How about adding the ability to write/read sound files to/from
|
|
|
|
memory buffers?</B></H2>
|
2007-05-14 09:55:24 +00:00
|
|
|
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
I have a had a number of requests like this over the last 18 months.
|
|
|
|
As yet, no-one has been able to justify why this is a good idea and why this
|
|
|
|
cannot be done a different way.
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
One example of different way is temporary files stored on a temporary file
|
|
|
|
systems (ie tmpfs on both Linux and Solaris).
|
|
|
|
These require no changes to libsndfile, no extra code in libsndfile, achieve
|
|
|
|
exactly what is required and work now.
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
|
|
|
|
<A NAME="Q009"></A>
|
2004-01-21 07:46:34 +00:00
|
|
|
<H2><BR><B>Q9 : Reading a 16 bit PCM file as normalised floats and then
|
2007-05-14 09:55:24 +00:00
|
|
|
writing them back changes some sample values. Why?</B></H2>
|
|
|
|
|
|
|
|
<P>
|
|
|
|
This is caused by the fact that the conversion from 16 bit short to float is
|
|
|
|
done by dividing by 32768 (0x8000 in hexadecimal) while the conversion from
|
|
|
|
float to 16 bit short is done by multiplying by 32767 (0x7FFF in hex).
|
2004-01-21 07:46:34 +00:00
|
|
|
So for instance, a value in a 16 bit PCM file of 20000, gets read as a floating
|
|
|
|
point number of 0.6103515625 (20000.0 / 0x8000).
|
2007-05-14 09:55:24 +00:00
|
|
|
Converting that back to a 16 bit short results in a value of 19999.3896484375
|
|
|
|
(0.6103515625 * 0x7FFF) which then gets rounded down to 19999.
|
|
|
|
</P>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
You will notice that for this particular case, the error is 1 in 20000 or
|
2007-05-14 09:55:24 +00:00
|
|
|
0.005%.
|
|
|
|
Interestingly, for values of less than 16369, dividing by 0x8000 followed
|
|
|
|
by multiplying by 0x7FFF and then rounding the result, gives back the
|
|
|
|
original value.
|
|
|
|
It turns out that as long as the host operating system supplies the 1999 ISO
|
2004-01-21 07:46:34 +00:00
|
|
|
C Standard functions <B>lrintf</B> and <B>lrint</B> (or a replacement has
|
2007-05-14 09:55:24 +00:00
|
|
|
been supplied) then the maximum possible error is 1 in 16369 or about 0.006%.
|
|
|
|
</P>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
Regardless of the size of the error, the reason why this is done is rather
|
2007-05-14 09:55:24 +00:00
|
|
|
subtle.
|
|
|
|
</P>
|
|
|
|
<P>
|
|
|
|
In a file containing 16 bit PCM samples, the values are restricted to the range
|
|
|
|
[-32768, 32767] while we want floating point values in the range [-1.0, 1.0].
|
2004-01-21 07:46:34 +00:00
|
|
|
The only way to do this conversion is to do a floating point divide by a value
|
|
|
|
0x8000.
|
2007-05-14 09:55:24 +00:00
|
|
|
Converting the other way, the only way to ensure that floating point values in
|
|
|
|
the range [-1.0, 1.0] are within the valid range allowed by a 16 bit short is
|
2004-01-21 07:46:34 +00:00
|
|
|
to multiply 0x7FFF.
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
|
|
|
<P>
|
|
|
|
Some people would say that this is a severe short-coming of libsndfile.
|
|
|
|
I would counter that anybody who is constantly converting back and forth
|
|
|
|
between 16 bit shorts and normalised floats is going to suffer other losses
|
|
|
|
in audio quality that they should also be concerned about.
|
|
|
|
</P>
|
|
|
|
<P>
|
|
|
|
The correct way to deal with this problem is to consider 16 bit short data as
|
|
|
|
a final destination format only, not as an intermediate storage format.
|
2004-01-21 07:46:34 +00:00
|
|
|
All intermediate data (ie which is going to be processed further) should be
|
|
|
|
stored in floating point format which is supported by all of the most common
|
2007-05-14 09:55:24 +00:00
|
|
|
file formats.
|
|
|
|
If floating point files are considered too large (2 times the size of a 16 bit
|
|
|
|
PCM file), it would also be possible to use 24 bit PCM as an intermediate
|
|
|
|
storage format (and which is also supported by most common file types).
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
|
2004-01-21 07:46:34 +00:00
|
|
|
<A NAME="Q010"></A>
|
|
|
|
<H2><BR><B>Q10 : I'm having problems with u-law encoded WAV files generated by
|
2007-05-14 09:55:24 +00:00
|
|
|
libsndfile in Winamp. Why?
|
|
|
|
</B></H2>
|
|
|
|
|
|
|
|
<P>
|
|
|
|
This is actually a Winamp problem.
|
|
|
|
The official Microsoft spec suggests that the 'fmt ' chunk should be 18 bytes.
|
|
|
|
Unfortunately at least one of Microsoft's own applications (Sound Recorder on
|
2004-01-21 07:46:34 +00:00
|
|
|
Win98 I believe), did not accept 18 bytes 'fmt ' chunks.
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
|
|
|
<P>
|
|
|
|
Michael Lee did some experimenting and found that:
|
|
|
|
</P>
|
|
|
|
<PRE>
|
2004-01-21 07:46:34 +00:00
|
|
|
I have checked that Windows Media Player 9, QuickTime Player 6.4,
|
2007-05-14 09:55:24 +00:00
|
|
|
RealOne Player 2.0 and GoldWave 5.06 can all play u-law files with
|
2004-01-21 07:46:34 +00:00
|
|
|
16-byte or 18-byte 'fmt ' chunk. Only Winamp (2.91) and foobar2000
|
2007-05-14 09:55:24 +00:00
|
|
|
are unable to play u-law files with 16-byte 'fmt ' chunk.
|
|
|
|
</PRE>
|
|
|
|
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
Even this is s very small sampling of all the players out there.
|
|
|
|
For that reason its probably not a good idea to change this now because there
|
2007-05-14 09:55:24 +00:00
|
|
|
is the risk of breaking something that currently works.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
|
2004-01-21 07:46:34 +00:00
|
|
|
<A NAME="Q011"></A>
|
|
|
|
<H2><BR><B>Q11 : What are samples? What are frames?
|
2007-05-14 09:55:24 +00:00
|
|
|
</B></H2>
|
|
|
|
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
For a sound file with only one channel, a frame is the same as a sample.
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
|
|
|
<P>
|
2004-01-21 07:46:34 +00:00
|
|
|
For multi channel sound files, a single frame contains a single sample for
|
2007-05-14 09:55:24 +00:00
|
|
|
each channel.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<!-- ========================================================================= -->
|
|
|
|
<HR>
|
|
|
|
<P>
|
|
|
|
The libsndfile home page is here :
|
2004-01-21 07:46:34 +00:00
|
|
|
<A HREF="http://www.zip.com.au/~erikd/libsndfile/">
|
|
|
|
http://www.zip.com.au/~erikd/libsndfile/</A>.
|
2007-05-14 09:55:24 +00:00
|
|
|
<BR>
|
2004-01-21 07:46:34 +00:00
|
|
|
Version : 1.0.6
|
2007-05-14 09:55:24 +00:00
|
|
|
</P>
|
|
|
|
|
|
|
|
</BODY>
|
|
|
|
</HTML>
|
2004-01-21 07:46:34 +00:00
|
|
|
|
|
|
|
<!--
|
|
|
|
Do not edit or modify anything in this comment block.
|
|
|
|
The arch-tag line is a file identity tag for the GNU Arch
|
|
|
|
revision control system.
|
|
|
|
|
|
|
|
arch-tag: 508f827d-b9a7-4a86-8c2f-d82321df91f7
|
|
|
|
-->
|