U-Law Import is inverted

Windows 7 64-bit, Audacity 2.2.1

For the longest time I thought Audacity’s Mu-Law / μ-Law / U-Law (for search results) implementation was completely different from the mu-law companding used with old drum machines like the Drumulator and DMX, but I just realized it’s only because Audacity works with the data seemingly upside-down. If I take a mu-law EPROM dump, import it as unsigned 8-bit, invert it, export it as unsigned 8-bit so that all I’ve done is invert the values of the bytes, and then import that as U-Law then it works, aside from some spikes here and there that are probably related to near-zero or actually zero amplitude samples.

  • Top is straight from the EPROM, bottom is inverted bytes.

It’s like this with literally every u-law EPROM dump I’ve tried which come from a variety of drum machines ripped with potentially different hardware and software.

If you want to test this on your own machine you can get some EPROM dumps of the Oberheim DMX + DX from this page and E-mu Drumulator dumps from this page, from which the screenshot uses Alternate Set #1.

As far maintaining compatibility with older Audacity U-Law files, perhaps the Byte Order menu could be replaced with an inversion or some such menu with Legacy and Correct, for lack of a better word.

Also, slightly related but only in that it pertains to what I was doing with Audacity at the time, could unsigned 16-bit import / export be implemented? My current method involves importing mono signed 16-bit files as stereo signed 8-bit files to split the MSB and LSB and then exporting it as a raw stereo unsigned 8-bit, effectively creating a mono unsigned 16-bit file that I can more easily visually manipulate as the byte value is more closely related to the sample amplitude as illustrated in this ramp-turned-bitmap wherein top is unsigned, bottom is signed. The whole import /export process for it is convoluted and leaves my desktop a mess with temporary files.

I’m not sure what the exact form of the BIN files is, but it’s not standard ADPCM μ-law or A-law, and that’s why Audacity can’t decode the BIN files correctly.
I can tell that it is 24kHz sample rate, signed 8-bit data with some sort of compression, but further than that we would need the format specification.
I’ve had a quick search of Google, but not found a format spec for it, though I expect the information will be out there (somewhere…)

I found some information about the format here: http://electrongate.com/software/dwav.c

Here’s a way that you can convert those BIN files into WAV files in Audacity:

  1. Import RAW: Unsigned 8-bit, sample rate by experimentation (the drum machine would change this anyway according to the “tuning”), about 22050 should work for most.

  2. Apply this code using the Nyquist Prompt effect (http://manual.audacityteam.org/man/nyquist_prompt.html)

(setf ln (truncate len))
(setf ar (snd-fetch-array *track* ln ln))

(dotimes (i ln (snd-from-array 0 24000 ar))
  (setf (aref ar i) (* 127 (aref ar i)))  ; 8-bit value
    ((> (aref ar i) 0)
        (setf signbit 1))
        (setf signbit -1)
        (setf (aref ar i) (+ 127 (aref ar i)))))
  (if (/= (aref ar i) 127)
      (setf (aref ar i)
        (* signbit (exp (/ (aref ar i) 23.08)) (/ 255.0)))
      (setf (aref ar i) 0)))

From the same site, I found this page which includes:

  • WAV2DMX is a conversion program used to convert Windows WAV files to binary EPROM image files for use in digital drum machines, such as the Oberheim DMX or LinnDrum”
  • DWAV is a conversion program used to convert binary DMX EPROM image files to Windows WAV files.”
  • DMXWAV is a Windows-based conversion program used to convert binary DMX EPROM image files to Windows WAV files and vice-versa.”

It was the second one (DWAV) that included source code from which I could find the format details.
The only one I’ve tried is DWAV (I don’t like to run unknown software unless I can see the source code). It’s a bit buggy, creating WAV files that crashed Audacity (on Linux - it may be better on Windows).

The format isn’t µ-law, it’s u255law (an exponential 8-bit format).

And here’s a plug-in version:
u255law-decoder.ny (824 Bytes)
Note that you still have to import the BIN file as “unsigned 8-bit RAW”. This plug-in just decodes it.
The plug-in has a limit of 1 million samples at a time (should be more than adequate for DMX drum samples).
Installation instructions are here: https://wiki.audacityteam.org/wiki/Download_Nyquist_Plug-ins#install

It does turn it into a usable sound and it’s very close to DMXWAV’s output, but that’s actually an older and slightly flawed program. His newer program for converting to and from u-law for various drum machines is Promenade. Back in 2014 he corrected “a math error in conversion of bin to wav files” and DMXWAV + dwav.c is 12 years before that. I don’t immediately see anything about the source code being available though. However I imagine running a ramp of all 256 possible 8-bit values through Promenade and comparing it to the 256 resulting 16-bit values would expose any alterations in the decompanding process, which actually I’ve already done and attached as a ZIP.

Also what is u-law in the context of Audacity’s importer if not an exponential 8-bit format? In the machines these files were used in they had non-linear DACs that decompanded the files that were recorded to 8-bit with u-law companding, I can’t think of anything too different from this that would use u-law as well except maybe an analog signal in old phone systems? But Audacity still only imports u-Law as 8-bit. Seems like maybe the raw importer UI could use an overhaul, like bit-depth, byte-order, signed, companding, etc all in separate sections rather than a list of pre-determined combinations of them. Maybe even some more exotic bit-depths like 12, which I’ve ended up experiencing thanks to the Sequential Circuits Studio 440 drum machine. IIRC it was split like xxxxxxxx-xxxx|xxxx-xxxxxxxx It was genuinely surprising to see an actual 12-bit file rather than u-law’d 8-bit advertised as 12-bit.

Turns out on ElectronGate there’s a manual for the DAC the Oberheim DMX uses with tables for the ideal and nominal decoder outputs for u-law decoding, but I don’t know if it’s a good idea to use that as a reference for a generalized u-law decoder since I don’t know that all non-linear DACs using u-law decoders had these exact values, like the Linn LM-1 or LinnDrum, or Drumulator, or Drumtraks, etc, but it should be a good reference.

Also if you make changes the plugin, could you write one that goes the other way as well? I don’t immediately have a use for it but if there’s going to be a plugin to convert from something then there should be another to go back paired with it in order to be a more complete utility.
Promenade In and Out.zip (1.18 KB)

There’s a description on Wikipedia here: G.711 - Wikipedia

The implementation that Audacity uses is libsndfile.

As you can see from the very different results of Audacity’s μ-Law decoding, and the proper decoding of these BIN files, the algorithms are significantly different.

??? By default Audacity imports μ-Law files as 32-bit float, though of course the actual sample values have only 256 distinct values (because μ-Law has only 8 bits per sample).

Neither do I, and I doubt that many others will either. However, if anyone has a burning need for an encoder, it shouldn’t be too difficult for them to “reverse” the code of the decoder, and I’d be willing to help them.

I meant it imports data as 8-bits to a sample, not that the final imported data within Audacity is 8-bit. Don’t think it matters anymore, I don’t really remember my train of thought anyway.

I looked at it for a good while trying to figure out what math error he could have made and fixed in 2014, but I couldn’t come up with anything. However, I did open up Promenade with a hex editor so I could look for some clues and it looks like it just uses a lookup table for u255-law to 16-bit WAV and another for the reverse, which makes sense after giving the Am6070 a more thorough read since it splits the input into 8 ranges, and within those 16 linearly-spaced values, which is probably a tough equation to make compared to just using a 256 entry LUT, especially when the values are right there. Plus Promenade’s output seems in-line with 16 linearly-spaced values. Could be the math error was trying to do the conversion with a simplified curve, something to do with turning a 16-bit WAV into u255-law, or the math error was not using a LUT in the first place.

Now if it was just a simple adjustment to the equation from DMXWAV I could do that with the script you made, but I don’t know how I’d make a LUT Nyquist effect. I couldn’t even get it to do a simple equation for waveshaping the other day, all I’ve succeeded in so far is addition, subtraction, multiplication, and multiplication with a fraction since it seems you can’t use / with s. The “Promenade In and Out.zip” from earlier has a 16-bit WAV which should have every entry from the table, arranged from input values 0 to 255.

If you don’t want to do the heavy lifting of that and would rather give me the general framework I imagine I can use Audacity’s sample data export to get numbers Nyquist can use, and maybe a variable in the plugin to enable or disable interpolation of the LUT if it would end up interpolating the table’s values if an input doesn’t lead exactly to a number on the LUT. Suppose that’s quantize(s, 127) at the start?

There appears to be a couple of errors.

Regarding his "magic number “23.08”.
Unfortunately he didn’t explain where this came from, but it appears to be wrong.

This is his algorithm in pseudo code:

function getEncodedValue( val )
  if ( val is_positive )
     decoded = ( 32767 * exponent(value / 23.08) / 255.0 );
     decoded = ( -1 * 32767 * exponent(val / 23.08) / 255.0 );

  return toInteger( decoded );

The input value “val” is in the range 0 to 127 (binary 111 1111)
The signed 16 bit return value must be in the range -32768 to 32767
so exponent(val / magicNumber) / 255 must be in the range 0 to 1.

If val = 127, then we want: exponent(val / magicNumber) = 255
then (127 / magicNumber) = loge(255) = 5.541263545
gives: magicNumber = 127 / 5.541263545 = 22.918960444

Then if we look at the other extreme, when val = 0, whether we use magicNumber = 22.92 or 23.08 (or any other value)
exponent(0 / magicNumber) = exponent(0) = 1
which shows that the decoded value is never 0.
When input sample value is 0, the decoded value is:
32767 * exponent(0 / 23.08) / 255.0 ) =
32767 * 1 / 255 =

Taking the case of magicNumber = 23.08, out output values are in the range (+/-):
128.5 to **32767 * exponent(127/23.98) / 255

128.5** to 31524.28

In C programming language, casting (converting) a float to an integer truncates the fractional part, so the returned value is in the range:
+/- 128 to 3152
which is not the full signed 16-bit range -32768 to 32767 that we were hoping for.

A lookup table is one way to implement the algorithm. It would probably process a bit quicker than calculating each sample value, but considering that the files are typically only 2 to 4 kB, speed is not an issue for us. It ‘could’ be an issue in a program that converts the format on the fly when burning the EPROM, (so as to avoid waiting for the conversion during burning), though buffering the entire converted file would give even faster access.

When converting is both directions (encoding and decoding), it does have the advantages that:

  1. We can easily see that the output values are in the correct range (easy to spot the errors that were in DWAV)
  2. Easy to handle the special case when encoding of an input value = 0 (log(0) is undefined).

I presume that you are referring to “s” as a variable holding the audio from the selection. That is legacy syntax (deprecated) and should not be used in current code. It has been replaced by the global variable TRACK.

The “/” function in Nyquist is the same as in XLISP, it divides a list of numbers

The “MULT” function may be used with number or sounds Nyquist Functions
(if in doubt, refer to the manual)

If you want to, for example, divide the sound from the track by 2:

(mult *track* 0.5)

One way is to use and array.
With an array, you can look up values by their index position.

Here’s a simple example:

(setf lut (make-array 4)) ;make an array with 4 elements

;; Populate the array
(dotimes (index 4 (1+ index))
  (print index) ;print the index number
  ; Set the 'index' element to the square of the index number
  (setf (aref lut index) (* index index)))

(terpri) ;print an end of line

;; lookup some elements from the array.
;; Note that the first element is index 0
(print (aref lut 0))
(print (aref lut 3))
(print (aref lut 2))

The final line evaluates to “4”, so that’s the value that is returned to Audacity and displayed in a message box. The rest of the output can be seen in the debug window.
Debug output:



The “numbers” in the data dumps are 8-bit values, so whether you use Sample Data Export or a Hex editor on the BIN files, you will just get hex values in the range 00 to FF.

Without either a format specification or a reference file (such as a full-scale saw-tooth waveform) I don’t think it’s possible to work out the correct conversions.
I’ve not been able to find either a format specification or a reference file.

Wikipedia says the format is μ-law (Oberheim DMX - Wikipedia)
Paul White says the format is a-law (DMX Files FAQ)
The DWAV decoder by Paul White says the format is u255law (http://www.electrongate.com/software/dwav.c)

The “upside down” issue is because of how negative values are represented.
There are several different ways to represent binary negative numbers, for example:

  • Offset Binary (like “unsigned” numbers with zero taken as the half-way point)
  • 2’s compliment (Two's complement - Wikipedia)
  • 1’s compliment (Ones' complement - Wikipedia)
  • Sign Magnitude (the first 7 bits 000 0000 to 111 1111 represent the magnitude, and the MSB represents +ve or -ve)

These two tables compare some schemes with 4-bit numbers: Signed number representations - Wikipedia

Some clues about the format:

It is clearly some sort of logarithmic encoding (you can see that by looking at the waveforms, and u255law appears to be close even if not exact).

The minimum absolute hex value in the BIN files is (unsigned) 0x00
The maximum absolute hex value in the BIN files is (unsigned) 0xFF
The maximum negative value is (unsigned) 0x7F
Zero is (unsigned) 0x80

So it appears that positive values go from binary 1000 000 up to 1111 1111 and negative numbers from 0111 1111 down to 0000 0000.
In other words, it is signed magnitude (127 positive values including zero starting at Hex 80 = zero, and 127 negative values starting at hex 00)

This is highly unusual for a file format (which usually represent signed values as 2’s compliment), but the BIN files are not really a “file format”, they are just a dump from the hardware EPROM. It makes more sense in the context of hardware because then both the positive and negative parts of the waveform can be calculated in exactly the same way, and just flip the MSB for the negative part of the waveform.

A bit more information from a Google search:

μ-Law is a general companding algorithm with the formula:

y = F(x) = sign(x)*Vmax*(ln(1+(ux/Vmax)) / ln(1+u))
where -Vmax <= x <= Vmax
and u is the 'mu' of the law.

or as Wikipedia describes:

F(x) = sgn(x) * ( ln(1 + |x|) / ln(1 + u) )
where -1 <= y <= 1

where typical values of μ = 100 or 255.

ITU-T produced several standards that approximate μ-Law for telegraphy use, such as G.711.
The ITU-T standard for G.711 (and others), approximate the logarithmic curve with a series of straight lines that can be easily converted to and from lookup tables (which is an efficient way to encode / decode in hardware).

So μ255LAW is simply a version of the μ-Law algorithm where μ = 255, and the reason that the DX / DMX BIN dumps appear “upside down” is due to the method of signed number representation being different in the DX / DMX EPROM dumps from typical audio files.

Unfortunately we still don’t know if the BIN dumps are pure logarithmic μ-255Law, or one of the ITU-T standards, or something else. I guess we may never know for sure unless someone finds a Oberheim spec sheet.

Seems that Paul White found one (last item on the page: DMX and DX Downloads)

Maybe the conversion is seeing the “other” zero value and interpreting as maximum output instead? I would have to dig back through my source code and notes from the 90’s, but if memory serves there are two zeroes in this signed 8-bit system: 0x00 and 0x80. That looks like what’s going on in the capture in the very first post.

PS. Have a look at the DAC data sheet. That will tell you exactly what’s going on in these machines. It represents the exact implementation of the general case of u-law. The u-law theory is helpful but can lead you astray too.

PPS. If all you want to do is convert a u-law drum machine BIN file to WAV, then use R100Builder.

Hi, thank you
Maybe the spikes are inv(0) which is Inf, so maybe plotted as bigger than 1
Second, the table seems to solve the problem, has it been solved (or should I try myself?)
Kind regards, thank you