At least the “sum and difference” part is easy (it’s about the only part that is)
Yeah, but only if the direct signal (with about 40 ms delay) and the demodulated signal can be properly synchronized.
The low-pass and band-pass filters, along with the equalization and compander section produce serious phase shifts. Even on the original device are 3 to 4 knobs to set up the turntable after each individual cartridge change. It is like solving an equation with 10 unknown variables. Ideally, we had both, a record from tim’s device and the digitally transferred channels from a quadrophonic turntable, e.g. a test disc.
Big question, why does Steve’s code snippet produce such a horrible sound?
Answer: Better ask, why does it produce sound at all?
The code does an AM demodulation, i.e. the message is coded in the instant amplitude of the 30000 Hz carrier.
CD-4 is modulated in “FM PM and SSB-FM” which is very nasty to demodulate.
Frequency modulation only squeezes and expands the wave-form horizontally, that’s why we shouldn’t hear anything after an AM demodulation.
The developers have now decided to adapt the FM-signal to the Main (what you hear on a stereo TT) signal’s amplitude, always about 19 dB below it (so called CLC - Carrier Level Control).
There’s additional noise and the groove in the other wall that modulates the carrier’s amplitude further.
FM-demodulation hinges on a signal of equal amplitude throughout. Hence, the first steps to retrieve the original message are:
- Highpass filter at 15500 Hz to get the carrier + side bands.
- Limit the carrier by hard-clipping.
(clip (mult 10000 carrier) 1)
- Bandpass the result between 20000 and 45000 Hz to remove the square wave harmonics.
- Actual demodulation with phase lock loop
The PLL from the last step is rather hard to implement because it uses a recursive approach.
I’ve now employed another method that firstly doesn’t need a limiter and secondly needs no lowpass update recursively.
It splits the signal into sine and cosine and keeps tracking the instant phase.
It works at the moment only for short periods because the result is gathered in a fixed array.
That’s the sound of the left channel from the sample Audio above:
I’ve also used an inverse RIAA to bring up the bass a bit. Unfortunately, CD-4 uses an own equalization curve + a expander for the noise reduction. I can’t read the response curves myself, thus…
By the way, the FM signal has only -31 to 36 dB, instead of -19 dB. I therefore assume that a normal stylus has been used.
The snippet first applies a narrow band pass filter at the carrier frequency.
The FM signal frequency has an average frequency equal to the carrier, but is modulated (by the message signal) so that the instantaneous frequency oscillates either side of the carrier frequency.
As the FM signal frequency moves through the narrow filter range, the amplitude will change such that maximum signal occurs when the FM signal frequency matches the filter’s centre frequency. In effect, the narrow pass band filter converts from FM to AM.
The resulting AM signal is then demodulated.
It’s primitive, but simple code and works as a proof of concept.
Excellent - are you doing that with FFT ?
Terrific, great progress
No, it doesn’t work with FFT, but it is related to it.
It is a Discreet Fourier transformation that returns for each sample a complex vector, tuned to the carrier frequency. It is basically what I’ve written in my PM.
(setf sig (highpass8 s 15500)) (defun dem (s cf) (let* ((ref-osc (osc (hz-to-step cf))) (ref-quad (osc (hz-to-step cf) 1 *table* 90)) (sn (lowpass8 (mult s ref-osc) 15500)) (cs (lowpass8 (mult s ref-quad) 15500 )) (out (make-array (truncate len))) (c-1 0) (s-1 1)) (dotimes (i (truncate len)) (let* ((c0 (snd-fetch cs)) (s0 (snd-fetch sn))) (setf (aref out i) (atan (+ (* s-1 c0) (* c-1 s0)) (- (* c-1 c0) (* s-1 s0)))) (psetq c-1 c0 s-1 (* -1 s0)))) (setf (aref out 0) 0) (snd-from-array 0 *sound-srate* out))) (setf sig (highpass8 (dem sig 30000) 50)) (mult (/ (peak sig ny:all)) sig)
C0/s0 is the current complex pair and c-1/s-1 is the conjugate of the past one. The atan function returns the instant phase for the pair.
This is normally very slow and therefore replaced with a lookup-table or a curve fitting function.
The code is not yet very refined, it should actually be implemented as object/class.
Please note: it works only with a mono track, stereo gives a nice visual C++ runtime error.
You lost me here:
Where did this equation come from?
(atan (+ (* s-1 c0) (* c-1 s0)) (- (* c-1 c0) (* s-1 s0))) (psetq c-1 c0 s-1 (* -1 s0))
This would probably be handled OO.
Well, the atan function works either with real or complex numbers (unfortunately the only nyquist function that can do this).
It returns a angle in radiants (from -pi to pi). the argument is essentially “real divided by imaginary”. The phase is not taken from the actual complex number but rather from the past number multiplied by the current one. All inside atan is a multiplication of two complex numbers.
The last line saves the current rex and imx and multiplies imx (the sine term) by -1, this gives the conjugate.
For example: You can take an FFT, multiply all imaginary numbers by -1 and you’ll get the conjugate. If you transform this back to the time domain, the whole sound will be reversed (in time).
I think I’ve confused the terms (although the output is essentially the same with a 90 deg phase shift).
It needs a lot simplification anyway.
OO > Object orientated.
Not pretty in Nyquist, but good for processing sounds sample by sample.
That was my intention anyway, at least if I have to use the ‘atan’ function.
However, later a lookup table could be great to perform several tasks at once.
I’ve also implemented the PLL variant - all object-oriented. However, the results are not yet convincing due to the lack of information about the fine tuning.
The only advantage, that I can see so far is the automatic carrier detection. But this could probably also included in the code above as a pre-processing step.
I forgot: There’s always a nasty click in the beginning. This is perhaps because of the high-order filters, which need some time to react. Hence it is better to put some dummy sound in front and cut it away in the end.
Yes I noticed
I wonder how accurate the specified frequency is? I guess it will be highly dependent on the quality and condition of the turntable. Also, how much the speed/frequency will drift over the course of a record.
The carrier frequency should be very accurate. The recording has been cut at 11.1 rpm and the carrier is therefore 10 kHz.
I am actually surprised how good the new algorithm extracts the upper signal. From your example code and from my earliest tries, I’ve expected less more than trash.
One has to keep in mind that the carrier has only -30 to -40 dB and could be therefore very susceptible to noise.
The original stylus is flat and has 4 times more surface contact than an elliptic one. That’s where most of the quality gets lost when using commonplace equipement, I fancy.
Without additional audio samples from Tim or whomever, the CD-4 demodulator project is at a dead end, I’m afraid.
I’d be interested to see your PLL code if you’re happy to post it.
That would be a shame, but you’ve come up with some interesting stuff on FM decoding and we may find other applications for that.
I can provide more samples from the same equipment and different discs if that’s what your requesting?
Unfortunately I don’t have access to a CD-4 decoder at this time to provide samples of it’s output.
Let me know what you require and I’ll do my best.
That would be great Tim.
There’s for one part the delay I am interested in. The base band is normally delayed by about 40 ms. This time is needed to demodulate the 30 kHz FM signal. The difference might best be seen at the very beginning of a recording.
Then, there’s the RIAA equalization that must be averaged from a longer piece of music.
I guess that the RIAA inversion is made for the lower band by your turntable automatically but not for the encoded signal of course.
The bad thing is that the expander section of the compander - which is essentially the noise reduction part - is the least known thing to me.
It seems to work in two defined bands, but threshold, ratio attack and release are mere guesswork for the time being.
Once the front and back are aligned, we will probably hear some “pumping” due to this and it should give us some clues.
In conclusion, we need some longer Audio (or a lot of short clips) for the spectrum averaging, some track transitions for the delay alignment, some longer lasting notes for the phase shift profile, in short all that is available.
I’ve last used a turntable 20 years ago, otherwise I’d purchased a CD-4 test disc. It would make things easier because some tracks have the exact same information stored in the front and back channel.
Maybe there are others out there who want to share some samples too (@Waxcylinder: Peter, wasn’t there never a quadrophonic phase in your life? ).
Since this is a educational project, clips of up to 30 sec shouldn’t violate any copyright (you know, I am not far from Berne…).
You can upload the samples here, use a public file sharing site or we (Tim, Steve and I) share my CD-4 drop box folder, whatever is the most convenient.
I considered it (briefly) but decided I was quite happy with my pair of electrostatic QUADS
Sorry for the delay getting you more samples; I have had a few technical problems but on the plus side I have now managed to capture at 192kHz.
I’ve uploaded to Dropbox six clips. They include the lead in at the beginning, lead out at the end and a transition between tracks around the middle point of two different disc’s.
The FLAC files are 192khz 24bit.
The WAV files are 192kHz 16bit.
Unfortunately I haven’t as yet heard from the chap in the USA who said he would provide clips from the calibration disc, needless to say I’ll upload them to Drop box as soon as I get them.
Hopefully this will enable you to make a bit more progress?
Sorry to dredge up such an old post, but I thought I could help out a bit, as I just got into 70s cd-4 in a small, but expensive, way. I’ve recorded the JVC calibration/test record 4DE-205-A for anyone still wishing to continue this audacity plugin. My recording equipment includes an Audio Technica AT14Sa phono cartridge, a Fisher MT-6320 turntable, a MIX MX750 mixer (used purely as a phono preamp), an M-Audio Delta 1010LT, and a Samson S-Direct Plus direct box. The recordings were done with the Delta 1010LT at 96000Hz, and 24-bit (as they’re the max for the Delta 1010LT). I’ve created two recordings, as I am unsure my first method has the necessary impedance bridging:
- Turntable->Mixer (Preamp)->2 RCA line inputs on the Delta 1010LT
- Turntable->Mixer (Preamp)->Direct Box (in Guitar Mode)->2 microphone inputs on the Delta 1010LT
The volume levels are slightly different for each recording. Also, the second recording has a higher right channel volume for some reason, although the levels were set equally in envy24control, etc.
I didn’t amplify the recordings to 0 dBFS, or delete the lead-ins or lead-outs. They are exactly as they were initially input, unedited but compressed to flac (from 96kHz, 24-bit wav).
In audacity, with Analyze->Plot Spectrum, I do see the “30Khz” tone in each recording, so although I’m not sure the frequency response is flat that high, there seems to be no equipment in either setup with a limiter for lowpass, etc. I was worried about the Samson S-Direct Plus (which states “10Hz - 20kHz”), and the MIX MX750 (which I can’t seem to find any manual or specs for).
Please excuse the clicking due to my not cleaning the record yet.
Here they are:
I probably won’t have google host these forever so don’t hesitate to download them as soon as you can. If someone (TimDog73?) would like, I approve of them being re-hosted for the long-term. By the way, I’m not that same “chap in the USA”, but I am one, and have also been an advocate for Free Software’s Four Freedoms as long as I can remember, and hope to help make CD-4 less expensive and more reliable for everyone.
Thanks a lot.
I’m curious how the demodulation will work for these files.
I have to analyse the plug-in as it doesn’t seem to be loadable in the newest Audacity version.
Thanks for your efforts, Robert.
I had no idea you could do this with Nyquist. I’m following this thread!