78rpm EQ Curve Generator

Share your Audacity/Nyquist plug-ins here, or test drive the latest plug-ins submitted by Audacity users.

After testing a plug-in from this forum, please post feedback for the plug-in author.
Irish
Forum Crew
Posts: 550
Joined: Sat Sep 05, 2009 9:25 pm
Operating System: Please select

Re: 78rpm EQ Curve Generator

Post by Irish » Thu Jan 12, 2012 12:19 am

steve wrote:The formula in your code is the same as Formula 1.1.b after substituting t1, t2 and t3.
Yes, now I remember looking at that site, but I later mislaid the url.

I agree your re-arrangement looks a lot cleaner. It's just that when I'm writing code, I tend to spell everything out step-by-step, and it can end up a bit clunky.

POL
________________________________________FOR INSTANT HELP: (Click on Link below)
* * * * Tips * * * * Tutorials * * * * 1.3 Quick Start Guide * * * * Audacity 1.3 Manual * * * * Audacity wiki * * * *

steve
Site Admin
Posts: 81227
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: 78rpm EQ Curve Generator

Post by steve » Thu Jan 12, 2012 12:38 am

Irish wrote:when I'm writing code, I tend to spell everything out step-by-step, and it can end up a bit clunky.
I know what you mean - I tend to do the same myself, but I quite enjoy neatening it all up at the end, and I find it really helps if I ever need to come back to the code at a later date. Your code comments have been really helpful in showing what's going on.
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

steve
Site Admin
Posts: 81227
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: 78rpm EQ Curve Generator

Post by steve » Sat Jan 21, 2012 5:49 pm

@POL, continuing from our off forum discussion, some thoughts about streamlining the code:

--------------------------------------------------------------------

Once we're all happy that the plug-in is "release ready" I think that we can remove much of the "change log". This will help to bring the ;control data closer to the actual code, making it easier to follow.

As the license is GPL v2 we can add that in as a comment.

For the header data and comments I'd suggest trimming it down to something like this:

Code: Select all

;nyquist plug-in
;version 3
;type generate
;name "78rpm EQ Curve V2.7"
;info "EQ Curve Generator for playback equalisation of 78rpm records. (V2.7)nBy Paraic O'Lochlainn. Released under GPL v2.nnGenerates an EQ curve and writes it to an xml file for import into Effect > Equalization.nSee  http://wiki.audacityteam.org/wiki/78rpm_playback_curves for a list of EQ curves."

;; EQ Curve Generator - version 3 plug-in (requires Audacity 1.3.13 or later)
;; by Paraic O'Lochlainn 
;; Released under terms of the GNU General Public License version 2:
;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 
;;
;; Generates playback EQ curves, for 78rpm records, from "Bass Turnover" and "10kHz Gain Rolloff" parameters.
;; Writes the curve data to an xml file for use by Audacity's Equalization effect
;; Includes optional normalisation to 0dB at 1kHz.


;control mode "Select Function or Help" choice "Generate EQ Curve,Help: EQ Curves Part 1,Help: EQ Curves Part 2,Help: This Plug-in Part 1,Help: This Plug-in Part 2,Help: Cancelling RIAA EQ" 0
;control tofreq "Bass Turnover Frequency" real "Hz" 500.0 200.0 1000.0
;control tenkrolloff "10 kHz Gain Rolloff" real "dB" -13.656 -24.0 0.0
;control lfshelf "LF Shelving Frequencyn(50.0 safest - see Help)" real "Hz" 50.0 10.0 100.0
;control norm "Normalise to 0 dB at 1 kHz? " choice "Yes,No" 0
;control curname "Curve File Name" string "(max 30 char)" 78EQ
;control path "Valid File Output Foldern(default is Home directory)" string "" "Home directory"  

;; Note: the default input values generate the RIAA curve.
Is there any other info that needs to be included?

--------------------------------------------------------------------

Again to help bring the ;control lines and the actual code closer together, I think it would be useful to wrap the help screens in functions and move the down near the bottom of the code (out of the way). At the very bottom of the code could be the "mode" conditional - something like this:

Code: Select all

(defun help4 ()
  (format NIL
"Help text 4 ....."))

(defun help5 ()
  (format NIL
"Help text 5 ...."))


(case mode
  (0 (run))     ;Generate EQ
  (1 (help1))   ;Help: EQ Curves Part 1
  (2 (help2))   ;Help: EQ Curves Part 2
  (3 (help3))   ;Help: This Plug-in Part 1
  (4 (help4))   ;Help: This Plug-in Part 2
  (T (help5)))  ;Help: Cancelling RIAA EQ
The main body of the code would then be in the function (run) and all of the actual "doing" part of the code (other than this one simple conditional statement) would then be together.

--------------------------------------------------------------------

Looking at the user value checking:

Code: Select all

;; If Gain rolloff at 10kHz is empty, set it to zero 
;; Then if it is positive, make it negative 
(unless (numberp tenkrolloff)
(setq tenkrolloff 0.0)
)
(if (plusp tenkrolloff) 
(setq tenkrolloff (- tenkrolloff))
)
As "tenkrolloff" is supplied by the ;control

Code: Select all

;control tenkrolloff "10 kHz Gain Rolloff" real "dB" -13.656 -24.0 0.0
it must be a float, so checking that it is a number is redundant.
(note in old versions of Audacity the returned value could be a float or integer, but this plug-in requires 1.3.13 or later so it will always be a float).
All that this bit of code is actually doing is ensuring that "tenkrolloff" is negative, so we can do that with the single line:

Code: Select all

(setq tenkrolloff (- (abs tenkrolloff)))
The same for the other user entered parameters, so we can replace lines 211 to 238

Code: Select all

;; Check for "sensible" parameter values

;; If Gain rolloff at 10kHz is empty, set it to zero 
;; Then if it is positive, make it negative 
(unless (numberp tenkrolloff)
(setq tenkrolloff 0.0)
)
(if (plusp tenkrolloff) 
(setq tenkrolloff (- tenkrolloff))
)

;; If Bass Turnover frequency is empty, set it to zero.
;; Then if it is negative, make it positive 
(unless (numberp tofreq)
(setq tofreq 0.0)
)
(if (minusp tofreq) 
(setq tofreq (- tofreq))
)

;; If LF Shelving frequency is empty, set it to zero.
;; Then if it is negative, make it positive
(unless (numberp lfshelf)
(setq lfshelf 0.0)
)
(if (minusp lfshelf) 
(setq lfshelf (- lfshelf))
)
with:

Code: Select all

(setq tenkrolloff (- (abs tenkrolloff)))  ;10kHz must be negative
(setq tofreq (abs tofreq))                ;Bass Turnover must be positive
(setq lfshelf (abs lfshelf))              ;LF Shelving frequency must be positive.
--------------------------------------------------------------------

Here's quite a big one:
Rather than setting the values for each frequency as separate variables in the form of:

Code: Select all

(setq gain20 (- (gaincalc 20.0) normfactor))
(setq gain25 (- (gaincalc 25.0) normfactor))
(setq gain31_5 (- (gaincalc 31.5) normfactor))
...
...
we could have an association list in the form:

Code: Select all

((frequency1 . gain1)(frequency2 . gain2)(frequency3 . gain3)... )
As well as cutting down the number of lines of code considerably, the other advantage is that if ever anyone wanted to change the frequency values it would be much easier to do.

To do this, a list of frequency values could be created as:

Code: Select all

;;; Create list of frequencies
(setf glist (list
  20 25 31 40 50 63 80 100 125 160 200 250 315
  400 500 630 800 1000 1250 1600 2000 2500 3150
  4000 5000 6300 8000 10000 12500 16000 20000
  25000 31500 48000))
and then the gain values associated with each frequency like this:

Code: Select all

;; Calculate the gain at each frequency (34 in list)
(dotimes (i 34)
  (setf (nth i glist)
    (cons (nth i glist) (- (gaincalc (float (nth i glist))) normfactor))))
This could then be used to simplify the output strings by first creating the list of points as a single string

Code: Select all

;; point list for XML
(setq pointlist "") ;initialise string
(dotimes (i 34)
  (setq pointlist (strcat pointlist (format nil
  "tt<point f="~a" d="~a"/>n"
  (float (car(nth i glist)))
  (cdr(nth i glist))))))
and then adding the <equalizationeffect> and <curve> tags like this:

Code: Select all

;; Output results to xml file
(format fp 
  "<equalizationeffect>nt<curve name=~
  "~a">n~at</curve>n</equalizationeffect>"
  curname pointlist)
(close fp)
and for the screen dump:

Code: Select all

;; gain list for screen output
(setq screengain "") ;initialise string
(dotimes (i 17)
  (setq screengain (strcat screengain (format nil
  " ~a Hzt ~a dB   t ~a Hz       ~a dB~%"
  (car(nth i glist))
  (cdr(nth i glist))
  (car(nth (+ 17 i) glist))
  (cdr(nth (+ 17 i) glist))))))
The only slight drawback I can see with this method is that we need to round the 31.5 Hz to either 31 or 32 so that it does not mess up the formatting of the screen dump, though if that is considered to be a problem we could modify the screendump code so that it prints all values with a specified number of decimal places, for example, instead of

Code: Select all

(car(nth i glist))
we could have something like:

Code: Select all

(decimal (car(nth i glist)) 1)
where the function (decimal value places) is defined as:

Code: Select all

(defun decimal (val places)
  (let* ((places (format nil "~a" places))
        (ff (strcat "%#1." places "f")))
    (setq *float-format*  ff)
    (format nil "~a" val)))
I'm not sure if we really need to support float values for frequency. What do you think?

--------------------------------------------------------------------

The output path verification part of the code can be really useful for other plug-ins so I think that it would be good to separate this out as a function that can be reused in other plug-ins. I've not done this yet.

--------------------------------------------------------------------
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

Irish
Forum Crew
Posts: 550
Joined: Sat Sep 05, 2009 9:25 pm
Operating System: Please select

Re: 78rpm EQ Curve Generator

Post by Irish » Wed Jan 25, 2012 8:42 pm

Thanks, Steve,

Quite a bit to look at there - I'll get back to you when I've gone through it.

POL
________________________________________FOR INSTANT HELP: (Click on Link below)
* * * * Tips * * * * Tutorials * * * * 1.3 Quick Start Guide * * * * Audacity 1.3 Manual * * * * Audacity wiki * * * *

steve
Site Admin
Posts: 81227
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: 78rpm EQ Curve Generator

Post by steve » Wed Jan 25, 2012 9:07 pm

Don't waste too much time struggling to decipher my disjointed notes ;) .
Here's the suggestions in context.
78EQCurveGenV2-7_20120104.ny
(12.69 KiB) Downloaded 194 times
(I've still not done anything about putting the output path verification part of the code into a reusable function).
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

Irish
Forum Crew
Posts: 550
Joined: Sat Sep 05, 2009 9:25 pm
Operating System: Please select

Re: 78rpm EQ Curve Generator

Post by Irish » Mon Jan 30, 2012 12:22 am

Steve,

I've gone through your changes, and it all makes good sense. However, I noticed a couple of things when I did a bit of testing;

If the "10 kHz Rolloff" parameter is zero, or the input box is left blank, we get a "divide by zero" error, so the function "gencurve" has to be

Code: Select all

(if (= 0.0 tenkrolloff)
    (setq hfto 10000000.0)
    (setq hfto 
      (sqrt 
        (/ (sqrd 10000.0) 
          (- (power 10.0 (/ (- tenkrolloff) 10.0)) 1.0)))))
The formatting of the line which writes the input parameters to the screen came out wrong on my machine, (it didn't print a tab between the "10kHz Rolloff" value and the "LF Shelving" value) so I changed it from two lines

Code: Select all

10kHz Rollofft LF Shelvingn ~a Hz    t ~a dB   ~
t ~a Hznn Normalisation Factor ~a dBnn Freqt ~
to one line

Code: Select all

10kHz Rollofft LF Shelvingn ~a Hz    t ~a dB   t ~a Hznn Normalisation Factor ~a dBnn Freqt ~
which seems to work, though I'm not sure why.

One other question; in the mode selection code at the end, why 1, 2, 3, 4, T?

I'll do a bit more later and see if anything else breaks.

POL
________________________________________FOR INSTANT HELP: (Click on Link below)
* * * * Tips * * * * Tutorials * * * * 1.3 Quick Start Guide * * * * Audacity 1.3 Manual * * * * Audacity wiki * * * *

steve
Site Admin
Posts: 81227
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: 78rpm EQ Curve Generator

Post by steve » Mon Jan 30, 2012 5:51 pm

Irish wrote:If the "10 kHz Rolloff" parameter is zero
Good catch.
Irish wrote:it didn't print a tab between the "10kHz Rolloff" value and the "LF Shelving" value
Ah yes, I see what's happening there.
It was difficult for me to spot because the spacing looks a bit off anyway on my machine (different font and character spacing I presume).

The tilde (~) at the end of a line allows long lines of text to be split without creating a new line in the output. It also ignores any leading spaces on the next line, so:

Code: Select all

    (format nil "Hello world, Hello world, Hello world, ~
       Hello world, Hello world, Hello world, "
will print the same as:

Code: Select all

    (format nil "Hello world, Hello world, Hello world, ~
Hello world, Hello world, Hello world, "
and the same as:

Code: Select all

    (format nil "Hello world, Hello world, Hello world, Hello world, Hello world, Hello world, "
What I was not aware of was that tabs (t) are treated in the same way as spaces. In fact all leading white-space characters on the next line are ignored.
This is documented here: http://www.audacity-forum.de/download/e ... ef-121.htm
~<newline> - continue the 'format' string on the next line. This signals a line break in the format. The 'format' function will ignore all white-space [blanks, tabs, newlines]. This is useful when the 'format' string is longer than a program line. Note that the 'newline' character must immediately follow the tilde character.
If it looks better to split the line, this should work:

Code: Select all

10kHz Rollofft LF Shelvingn ~a Hz    t ~a dB   t ~a ~
Hznn Normalisation Factor ~a dBnn Freqt ~
or this:

Code: Select all

10kHz Rollofft LF Shelvingn ~a Hz    t ~a ~
dB   t ~a Hznn Normalisation Factor ~a dBnn Freqt ~
Irish wrote:in the mode selection code at the end, why 1, 2, 3, 4, T?
You mean the "T" rather than "5"?
It will work just the same with "5".
T represents 'true', as opposed to NIL , representing 'false'.
It's often convenient to end a "case" selection with "T" as a catch-all, especially while developing the code, as it ensures that you will never drop off the end of the list.
More about "case" here: http://www.audacity-forum.de/download/e ... ef-047.htm
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

steve
Site Admin
Posts: 81227
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: 78rpm EQ Curve Generator

Post by steve » Wed Feb 01, 2012 4:51 pm

Does this look right on Windows POL?

Code: Select all

      ;; Output results to screen
      (format NIL "EQ Curve:  ~a, written ton~a~an~ann Bass ~
        Turnovert 10kHz Rollofft LF Shelvingn ~a Hz    t~
        ~a dB   t ~a Hznn Normalisation Factor ~a dBnn Freqt ~
        Gaintt Freqt     Gainn~a"
        curname path filen errmessg tofreq tenkrolloff
        lfshelf normfactor screengain))))
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

Irish
Forum Crew
Posts: 550
Joined: Sat Sep 05, 2009 9:25 pm
Operating System: Please select

Re: 78rpm EQ Curve Generator

Post by Irish » Wed Feb 01, 2012 10:03 pm

Yes, that looks fine.

There's a question over the terminology of the LF Shelving Filter, but I'm in a rush now. I'll post later.

POL
________________________________________FOR INSTANT HELP: (Click on Link below)
* * * * Tips * * * * Tutorials * * * * 1.3 Quick Start Guide * * * * Audacity 1.3 Manual * * * * Audacity wiki * * * *

Irish
Forum Crew
Posts: 550
Joined: Sat Sep 05, 2009 9:25 pm
Operating System: Please select

Re: 78rpm EQ Curve Generator

Post by Irish » Thu Feb 02, 2012 12:04 am

As I was saying ...

I've come to realise that the term I used for the low frequency component, "LF Shelving Filter" is not strictly accurate, since it has a 6dB/octave rolloff, while a "Shelving" filter has a constant gain beyond the turnover frequency. The problen is that I'm not sure what to call it, since there doesn't seem to be a standard term for it, at least in the literature Ive read. It could maybe be called "Low Bass Turnover" or "Rumble Filter Turnover" since its purpose is to overcome low-frequency rumble by boosting the bass at around 50 to 100Hz when recording. Any other suggestions? Or should we leave it as it is?

POL
________________________________________FOR INSTANT HELP: (Click on Link below)
* * * * Tips * * * * Tutorials * * * * 1.3 Quick Start Guide * * * * Audacity 1.3 Manual * * * * Audacity wiki * * * *

Post Reply